diff --git a/feishu-export-design/CODEX_CLEAN_TASK_CHAIN.md b/feishu-export-design/CODEX_CLEAN_TASK_CHAIN.md new file mode 100644 index 0000000..4dfb058 --- /dev/null +++ b/feishu-export-design/CODEX_CLEAN_TASK_CHAIN.md @@ -0,0 +1,740 @@ +# Codex Clean Task Chain: GitLink CLI Feishu Export + +## Goal + +Add a safe `feishu` shortcut module to `gitlink-cli`. + +This task only implements: + +```text +GitLink workflow JSON + -> Feishu card preview + -> Feishu bot send with explicit --send + -> weekly report + -> Bitable schema + -> Bitable-ready records + -> Agent Skill +``` + +## Boundaries + +Do not implement: + +```text +Feishu tasks +Feishu approval +callback server +button callbacks +GitLink remote writes +GitLink comments +Issue closure +code merge actions +direct GitLink webhook creation +real Bitable OpenAPI writes +Feishu Base creation +Feishu table creation +Feishu view creation +open_id person mapping +``` + +## Hard Rules + +```text +1. Target repository: gitlink-cli. +2. Language: Go. +3. Do not add Ruby, Rails, Python, or Node services. +4. First implementation consumes local workflow JSON only. +5. Default behavior is local preview. +6. Real Feishu bot sending requires explicit --send. +7. If --send and --dry-run are both set, return an error. +8. Tests must use local fixtures or mock HTTP servers. +9. Tests must not depend on a real Feishu tenant, bot, token, or webhook. +10. Logs and errors must not print full webhook URLs or secrets. +11. Do not add non-engineering packaging language to code, docs, comments, or reports. +``` + +## Phase 0: Repository Scan + +### Objective + +Scan the current codebase and record implementation anchors. + +### Read + +```text +cmd/root.go +shortcuts/register.go +shortcuts/common/runner.go +shortcuts/common/types.go +shortcuts/workflow/workflow.go +shortcuts/workflow/repo_report.go +shortcuts/workflow/pr_summary.go +shortcuts/workflow/render.go +shortcuts/workflow/testdata/ +internal/output/ +skills/ +docs/ +examples/ +go.mod +Makefile +.github/ +``` + +### Create + +```text +reports/FEISHU_IMPLEMENTATION_SCAN.md +``` + +### Required Content + +```text +Repository anchors +Reusable workflow data and renderers +Reusable output behavior +Shortcut registration pattern +Test fixtures +Current test baseline +Implementation landing points +``` + +### Verification + +```bash +go test ./shortcuts/workflow +go test ./shortcuts +``` + +Use this when the default Go proxy is unavailable: + +```powershell +$env:GOPROXY='https://goproxy.cn,direct' +``` + +## Phase 1: Feishu Command Skeleton + +### Objective + +Add a `feishu` shortcut group with five commands. All commands must compile and support `--help`. No command sends network traffic by default. + +### Add + +```text +shortcuts/feishu/ + feishu.go + options.go + redact.go + output.go +``` + +### Register + +Update: + +```text +shortcuts/register.go +``` + +Add: + +```text +feishu -> feishu.Shortcuts() +``` + +Description: + +```text +Export GitLink workflow data to Feishu cards and Bitable-ready records +``` + +### Commands + +```bash +gitlink-cli feishu +bot-test +gitlink-cli feishu +notify +gitlink-cli feishu +weekly-report +gitlink-cli feishu +bitable-schema +gitlink-cli feishu +bitable-records +``` + +Do not add: + +```text ++sync-bitable ++approval-create ++sync-tasks ++serve ++webhook-create +``` + +### Shared Flags + +```text +--owner +--repo +--since +--include issues,prs,contributors,health +--format json|table|markdown +--lang zh-CN|en-US +--dry-run +--from-workflow-json +``` + +### Bot Flags + +```text +--webhook-url +--secret +--send +``` + +### Bitable Preview Flags + +```text +--tables issues,prs,contributors,reports +``` + +### Environment Variables + +Read only: + +```text +FEISHU_WEBHOOK_URL +FEISHU_WEBHOOK_SECRET +``` + +Do not read in this task: + +```text +FEISHU_TENANT_ACCESS_TOKEN +FEISHU_APP_ID +FEISHU_APP_SECRET +FEISHU_BASE_APP_TOKEN +FEISHU_ISSUE_TABLE_ID +FEISHU_PR_TABLE_ID +FEISHU_CONTRIBUTOR_TABLE_ID +FEISHU_REPORT_TABLE_ID +``` + +### Verification + +```bash +gofmt -w shortcuts/feishu +go test ./shortcuts/feishu +go test ./shortcuts +``` + +Check help: + +```bash +go run . feishu --help +go run . feishu +bot-test --help +go run . feishu +notify --help +go run . feishu +weekly-report --help +go run . feishu +bitable-schema --help +go run . feishu +bitable-records --help +``` + +## Phase 2: Options and Redaction + +### Objective + +Implement safe option loading, validation, and redaction. + +### Files + +```text +shortcuts/feishu/options.go +shortcuts/feishu/redact.go +shortcuts/feishu/options_test.go +shortcuts/feishu/redact_test.go +``` + +### Options + +```go +type Options struct { + Owner string + Repo string + Since string + Include []string + Format string + Lang string + DryRun bool + Send bool + FromWorkflowJSON string + + WebhookURL string + WebhookSecret string + + Tables []string +} +``` + +### Functions + +```go +func LoadOptions(ctx *common.RuntimeContext) (Options, error) +func ValidateCommonOptions(opts Options) error +func ValidateBotOptions(opts Options) error +func ValidateWorkflowJSONOptions(opts Options) error +func ValidateBitableRecordOptions(opts Options) error +func NormalizeInclude(value string) ([]string, error) +func NormalizeTables(value string) ([]string, error) +func ValidateSendMode(opts Options) error +``` + +### Send Mode + +```text +Default: preview only. +--send: send Feishu bot message. +--send + --dry-run: error. +--send without webhook URL: error. +No --send: no HTTP request. +``` + +### Redaction + +```go +func MaskSecret(value string) string +func MaskWebhookURL(value string) string +func MaskToken(value string) string +func MaskError(err error) string +``` + +Rules: + +```text +secret -> *** +token -> *** +webhook URL -> scheme + host + final 4 path characters +empty string -> "" +short sensitive string -> *** +``` + +### Verification + +```bash +gofmt -w shortcuts/feishu +go test ./shortcuts/feishu +``` + +## Phase 3: Bot Signature + +### Objective + +Implement Feishu custom bot signing. + +### Files + +```text +shortcuts/feishu/signer.go +shortcuts/feishu/signer_test.go +``` + +### Functions + +```go +func BuildBotSign(timestamp int64, secret string) (string, error) +func BuildBotEnvelope(card map[string]any, secret string, now time.Time) (map[string]any, error) +``` + +### Behavior + +```text +Empty secret: no timestamp/sign. +Non-empty secret: add timestamp/sign. +Timestamp: Unix seconds. +Errors must not include secret. +Tests use fixed timestamps. +``` + +## Phase 4: Card Builders + +### Objective + +Build Feishu interactive card JSON without network calls. + +### Files + +```text +shortcuts/feishu/model.go +shortcuts/feishu/card.go +shortcuts/feishu/card_test.go +``` + +### Models + +```go +type ProjectActivity struct { + Repository string + Period string + IssueSummary SummaryBlock + PullRequestSummary SummaryBlock + ContributorSummary SummaryBlock + HealthSummary SummaryBlock + Risks []string + Recommendations []string +} + +type SummaryBlock struct { + Title string + Count int + Items []string +} + +type WeeklyReport struct { + Repository string + Period string + NewIssues int + ClosedIssues int + NewPullRequests int + MergedPullRequests int + ActiveContributors int + Risks []string + Recommendations []string + Markdown string +} +``` + +### Functions + +```go +func BuildBotTestCard(lang string) map[string]any +func BuildProjectActivityCard(activity ProjectActivity, lang string) map[string]any +func BuildWeeklyReportCard(report WeeklyReport, lang string) map[string]any +``` + +### Requirements + +```text +Use interactive card. +Support zh-CN and en-US text. +Handle empty data. +Do not include secrets or webhook URLs. +``` + +## Phase 5: Bot Webhook Client + +### Objective + +Send Feishu bot payloads through an injectable HTTP client. + +### Files + +```text +shortcuts/feishu/client.go +shortcuts/feishu/client_test.go +``` + +### API + +```go +type Client struct { + HTTPClient *http.Client +} + +func NewClient(httpClient *http.Client) *Client +func (c *Client) SendBotMessage(ctx context.Context, webhookURL string, payload any) error +``` + +### Behavior + +```text +POST JSON. +2xx means success. +Non-2xx returns redacted error. +Limit response body read size. +Network errors are redacted. +Never print full webhook URL. +``` + +### Tests + +Use `httptest.Server` for: + +```text +200 +400 +429 +500 +network error +redaction +``` + +Do not implement Bitable OpenAPI client in this phase. + +## Phase 6: Bot Test Command + +### Objective + +Preview or explicitly send a test card. + +### Commands + +Preview: + +```bash +go run . feishu +bot-test --format json +``` + +Send: + +```bash +go run . feishu +bot-test --webhook-url "$FEISHU_WEBHOOK_URL" --secret "$FEISHU_WEBHOOK_SECRET" --send +``` + +### Behavior + +```text +Default preview. +Preview prints JSON. +--send sends through mockable client. +--send requires webhook URL. +Output shows only redacted target. +No GitLink data read. +No GitLink write. +``` + +## Phase 7: Workflow JSON Mapper + +### Objective + +Read local workflow JSON and map it into Feishu models. + +### Files + +```text +shortcuts/feishu/mapper.go +shortcuts/feishu/mapper_test.go +shortcuts/feishu/testdata/ + repo_report.json + pr_summary.json + health.json +``` + +### Functions + +```go +func LoadWorkflowJSON(path string) (map[string]any, error) +func MapWorkflowToProjectActivity(data map[string]any, opts Options) (ProjectActivity, error) +func MapWorkflowToWeeklyReport(data map[string]any, opts Options) (WeeklyReport, error) +``` + +### Rules + +```text +Support workflow +repo-report JSON first. +Missing fields must not panic. +Unknown fields are ignored. +Do not duplicate workflow analysis logic. +Do not call GitLink remote APIs. +Do not change existing workflow behavior. +``` + +## Phase 8: Notify Command + +### Objective + +Create a project activity card from workflow JSON. + +### Commands + +Preview: + +```bash +go run . feishu +notify --from-workflow-json report.json --include issues,prs,contributors,health --format json +``` + +Send: + +```bash +go run . feishu +notify --from-workflow-json report.json --webhook-url "$FEISHU_WEBHOOK_URL" --secret "$FEISHU_WEBHOOK_SECRET" --send +``` + +### Behavior + +```text +Requires --from-workflow-json. +Uses include filter. +Default output is JSON preview. +--send sends a card. +No GitLink write. +``` + +## Phase 9: Weekly Report Command + +### Objective + +Create a weekly report from workflow JSON. + +### Commands + +```bash +go run . feishu +weekly-report --from-workflow-json report.json --format markdown +go run . feishu +weekly-report --from-workflow-json report.json --format json +go run . feishu +weekly-report --from-workflow-json report.json --webhook-url "$FEISHU_WEBHOOK_URL" --secret "$FEISHU_WEBHOOK_SECRET" --send +``` + +### Behavior + +```text +Default output is markdown. +JSON output returns structured WeeklyReport. +--send sends a Feishu card after local report generation. +No GitLink write. +``` + +## Phase 10: Bitable Schema + +### Objective + +Generate recommended Bitable schema. Do not connect to Feishu OpenAPI. + +### Files + +```text +shortcuts/feishu/schema.go +shortcuts/feishu/schema_test.go +``` + +### Command + +```bash +go run . feishu +bitable-schema --tables issues,prs,contributors,reports --format markdown +go run . feishu +bitable-schema --tables issues,prs,contributors,reports --format json +``` + +### Tables + +```text +Issues +Pull Requests +Contributors +Weekly Reports +``` + +### Rules + +```text +Do not create Base. +Do not create tables. +Do not create fields. +Do not create views. +Do not call Feishu OpenAPI. +``` + +## Phase 11: Bitable Records + +### Objective + +Generate Bitable-ready records from workflow JSON. Output only. + +### Files + +```text +shortcuts/feishu/bitable.go +shortcuts/feishu/bitable_test.go +``` + +### Command + +```bash +go run . feishu +bitable-records --from-workflow-json report.json --tables issues,prs,contributors,reports --format json +``` + +### Rules + +```text +Requires --from-workflow-json. +Only outputs records. +Does not read app token. +Does not read table IDs. +Does not call Feishu OpenAPI. +Does not create, update, or upsert. +``` + +## Phase 12: Skill and Docs + +### Add + +```text +skills/gitlink-feishu/SKILL.md +docs/feishu-integration.md +docs/feishu-security.md +docs/feishu-bitable-schema.md +examples/feishu/ + bot-test.md + notify.md + weekly-report.md + bitable-schema.md + bitable-records.md +``` + +### Content Rules + +```text +Describe engineering usage only. +Default to preview examples. +Show --send only for bot cards. +State that Bitable output is local-only in this task. +Do not include non-engineering packaging language. +``` + +## Phase 13: Final Verification + +### Commands + +```bash +gofmt -w shortcuts/feishu +go test ./shortcuts/feishu +go test ./shortcuts/workflow +go test ./shortcuts +``` + +If dependencies are already available or a temporary proxy is set: + +```bash +go test ./... +``` + +### Completion Report + +Create: + +```text +reports/FEISHU_TASK_COMPLETION.md +``` + +Include: + +```text +implemented commands +changed files +preview behavior +explicit send behavior +mock test coverage +redaction checks +test results +excluded capabilities +``` + +## Final Acceptance + +```text +feishu --help works. ++bot-test previews JSON. ++bot-test --send is covered by mock HTTP tests. ++notify reads workflow JSON and previews card JSON. ++notify --send is covered by mock HTTP tests. ++weekly-report reads workflow JSON and outputs markdown/json. ++bitable-schema outputs markdown/json. ++bitable-records outputs records JSON. +No output leaks full webhook URL or secret. +No Feishu send happens without --send. +No GitLink remote write exists. +No real Bitable write exists. +Targeted tests pass. +``` + diff --git a/feishu-export-design/EVALUATION.md b/feishu-export-design/EVALUATION.md new file mode 100644 index 0000000..50aa181 --- /dev/null +++ b/feishu-export-design/EVALUATION.md @@ -0,0 +1,97 @@ +# Feishu Export Design Evaluation + +## Current Baseline + +Working directory: + +```text +E:\GitLinkCLI-Competition\gitlink-cli-feishu-clean +``` + +Branch and base: + +```text +feat/feishu-export-clean +origin/master ef7a2c6 +``` + +Baseline tests: + +```powershell +$env:GOPROXY='https://goproxy.cn,direct'; go test ./... +``` + +Result: passed. + +The first default `go test ./...` attempt failed only because `proxy.golang.org` was unreachable for new dependencies. With a temporary Go proxy override, the latest master baseline is clean. + +## Judgment + +The v2 task chain is substantially better than the earlier version and is close to executable. It correctly narrows the feature into a safe one-way export module: + +```text +workflow JSON -> local preview +workflow JSON -> Feishu bot card +workflow JSON -> weekly report +workflow JSON -> Bitable schema +workflow JSON -> Bitable-ready records +``` + +The remaining design adjustments are: + +1. Keep the first implementation limited to local workflow JSON input. +2. Use `--send` as the only real Feishu bot send switch. +3. Use `prs` in flags and table keys, while displaying `Pull Requests` to users. +4. Replace any `sync-bitable` wording with `bitable-records`. +5. Do not implement real Bitable OpenAPI writes in this task. +6. Keep `doctor` out of the first implementation unless the other commands already exist. + +## What Is Complete + +The v2 task chain is complete enough for: + +- Command skeleton design. +- Safety options and redaction design. +- Feishu bot card and signature design. +- Mocked webhook client design. +- Workflow JSON mapping design. +- Local weekly report generation. +- Bitable schema generation. +- Bitable-ready record generation. +- Agent Skill and documentation outline. + +## What Is Not Closed Yet + +The following should not be implemented in the first pass: + +- Real Bitable record creation. +- Real Bitable record update. +- Bitable unique-key lookup through Feishu OpenAPI. +- Tenant token acquisition. +- Token cache behavior. +- Feishu Base/table/view creation. +- Any GitLink remote write. + +These require a separate authentication and data consistency design. + +## Practical Utility + +The design is useful in a real CLI workflow: + +1. A user generates a workflow report with the existing `workflow +repo-report` command. +2. The new `feishu` command consumes that JSON file. +3. The user previews a card, weekly report, schema, or records locally. +4. Only when `--send` is explicit does the CLI send a Feishu bot message. + +This produces a small, testable feature that is useful without requiring Feishu enterprise app credentials. + +## Implementation Scope Rating + +```text +Direction: strong +Safety boundary: strong +Repository fit: strong +First implementation size: acceptable after removing real Bitable writes +Direct executability: good after using the clean task chain in this directory +``` + diff --git a/feishu-export-design/TECHNICAL_PLAN.md b/feishu-export-design/TECHNICAL_PLAN.md new file mode 100644 index 0000000..7c1daa1 --- /dev/null +++ b/feishu-export-design/TECHNICAL_PLAN.md @@ -0,0 +1,303 @@ +# Feishu Export Technical Plan + +## Latest Master Anchors + +Current command registration: + +```text +shortcuts/register.go +``` + +Add imports: + +```go +github.com/gitlink-org/gitlink-cli/shortcuts/feishu +``` + +Add group: + +```go +"feishu": feishu.Shortcuts(), +``` + +Add description: + +```go +"feishu": "Export GitLink workflow data to Feishu cards and Bitable-ready records", +``` + +Shortcut mounting: + +```text +shortcuts/common/runner.go +``` + +Important behavior: + +- Boolean flags are read from Cobra as strings in `RuntimeContext.Args`. +- A bool flag with default `true` cannot tell whether the user explicitly set it. Therefore `--send` should be the positive action flag, and `--dry-run` should remain a preview indicator. +- If implementation must detect explicit `--dry-run`, it needs a command-specific Cobra command instead of the generic shortcut runner. Avoid that for the first implementation. + +## Send Flag Decision + +Use this rule: + +```text +--send=false or omitted: preview only. +--send=true and dry-run=false: send. +--send=true and dry-run=true: error. +``` + +Since generic shortcut flags cannot detect whether `--dry-run` was explicitly passed, set `--dry-run` default to `false` in Feishu commands and treat preview as `!Send`. This avoids a default conflict where `--send` would always collide with default `--dry-run=true`. + +Effective mode: + +```go +Preview := !opts.Send +``` + +Validation: + +```go +if opts.Send && opts.DryRun { + return error +} +if opts.Send && opts.WebhookURL == "" { + return error +} +``` + +User-facing meaning: + +```text +No --send: preview. +--dry-run: preview and forbid send. +--send: real bot send. +--send --dry-run: invalid. +``` + +## Output Strategy + +Do not extend `internal/output` in the first implementation. + +Reason: + +- Global output supports `json`, `yaml`, and generic `table`. +- Workflow uses local renderers for markdown. +- Feishu needs markdown for weekly reports and schema docs. + +Implement local Feishu render helpers: + +```go +func renderJSON(w io.Writer, value any) error +func renderMarkdown(w io.Writer, value any) error +func renderTable(w io.Writer, value any) error +func normalizeFormat(format string, defaultFormat string) string +``` + +Default formats: + +```text ++bot-test: json ++notify: json ++weekly-report: markdown ++bitable-schema: markdown ++bitable-records: json +``` + +## Workflow JSON Input + +First implementation only supports local JSON files. + +Expected source: + +```bash +gitlink-cli workflow +repo-report --owner --repo --format json > report.json +``` + +Mapping should accept both shapes if found: + +1. Raw `RepoReportResult`. +2. Envelope-like object with `data`. + +Fields to use: + +```text +repository +health.health_score +health.risk_level +issue_summary.total +issue_summary.high_risk +issue_summary.missing_info +pr_summary.total +pr_summary.high_risk +pr_summary.review_focus +recommendations +risk_level +report_score +source +``` + +Do not import unexported workflow readers. Use JSON mapping to avoid changing workflow internals. + +## Feishu Signature + +Use Feishu custom bot signing: + +```text +string_to_sign = timestamp + "\n" + secret +sign = base64(hmac_sha256(string_to_sign, secret)) +``` + +Implementation notes: + +- `timestamp` is Unix seconds and serialized as a string. +- Empty secret means no timestamp/sign. +- Tests use fixed timestamp. +- Errors must be redacted. + +## Feishu Card Shape + +Use custom bot interactive card payload: + +```json +{ + "msg_type": "interactive", + "card": { + "header": { + "title": { + "tag": "plain_text", + "content": "GitLink Project Activity" + } + }, + "elements": [] + } +} +``` + +Envelope with signature: + +```json +{ + "timestamp": "1710000000", + "sign": "redacted in logs", + "msg_type": "interactive", + "card": {} +} +``` + +## HTTP Client + +Use package-local client: + +```go +type Client struct { + HTTPClient *http.Client +} +``` + +Use `httptest.Server` for all tests. + +Do not use `internal/client.Client` for Feishu because it appends GitLink `.json` suffixes and injects GitLink auth. + +## Naming + +CLI flags: + +```text +prs +--include issues,prs,contributors,health +--tables issues,prs,contributors,reports +``` + +User-facing labels: + +```text +Pull Requests +``` + +Internal model names: + +```text +PullRequestSummary +NewPullRequests +MergedPullRequests +``` + +Do not use `pulls` in new user-facing flags. + +## Bitable Scope + +First implementation: + +```text ++bitable-schema ++bitable-records +``` + +No Feishu OpenAPI calls. + +No environment variables for app tokens or table IDs. + +No tenant token. + +No create/update/upsert. + +The records command outputs local JSON only: + +```go +type BitableRecordsOutput struct { + Repository string `json:"repository"` + Tables []BitableTableRecords `json:"tables"` +} + +type BitableTableRecords struct { + Table string `json:"table"` + Records []BitableRecord `json:"records"` +} + +type BitableRecord struct { + UniqueKey string `json:"unique_key"` + Fields map[string]any `json:"fields"` +} +``` + +## Tests To Add + +```text +shortcuts/feishu/options_test.go +shortcuts/feishu/redact_test.go +shortcuts/feishu/signer_test.go +shortcuts/feishu/card_test.go +shortcuts/feishu/client_test.go +shortcuts/feishu/mapper_test.go +shortcuts/feishu/schema_test.go +shortcuts/feishu/bitable_test.go +shortcuts/feishu/commands_test.go +``` + +Minimum assertions: + +```text +No --send means no HTTP. +--send means HTTP in mock tests. +--send --dry-run errors. +Missing webhook URL with --send errors. +Errors redact webhook URL and secret. +Workflow JSON can be loaded from fixture. +Missing fields do not panic. +Weekly report markdown is stable. +Bitable schema JSON is parseable. +Bitable records JSON is parseable. +``` + +## Baseline Verification + +Current latest master passes with: + +```powershell +$env:GOPROXY='https://goproxy.cn,direct'; go test ./... +``` + +Keep this as the baseline before implementation. +