From 1af54e015adea6653d9a69f639b6269282f3187a Mon Sep 17 00:00:00 2001 From: whzy <2402686765@qq.com> Date: Mon, 15 Jun 2026 22:03:52 +0800 Subject: [PATCH] chore: harden feishu export delivery --- docs/feishu-bitable-schema.md | 68 +++++++++ docs/feishu-integration.md | 133 +++++++++++------- docs/feishu-security.md | 75 ++++++++++ examples/feishu/README.md | 40 ++++-- .../OFFICIAL_DOCS_ALIGNMENT.md | 7 +- feishu-export-design/TECHNICAL_PLAN.md | 12 +- reports/FEISHU_TASK_COMPLETION.md | 22 ++- .../FEISHU_TEST_ENTERPRISE_SMOKE_20260615.md | 116 +++++++++++++++ shortcuts/feishu/feishu.go | 2 +- shortcuts/feishu/feishu_test.go | 26 ++++ shortcuts/feishu/workflow_input.go | 33 +++++ skills/gitlink-feishu/SKILL.md | 95 +++++++++---- 12 files changed, 531 insertions(+), 98 deletions(-) create mode 100644 docs/feishu-bitable-schema.md create mode 100644 docs/feishu-security.md create mode 100644 reports/FEISHU_TEST_ENTERPRISE_SMOKE_20260615.md diff --git a/docs/feishu-bitable-schema.md b/docs/feishu-bitable-schema.md new file mode 100644 index 0000000..29584c3 --- /dev/null +++ b/docs/feishu-bitable-schema.md @@ -0,0 +1,68 @@ +# Feishu Bitable Dry-Run Schema + +`gitlink-cli feishu` currently generates Bitable schema and records locally. + +It does not call Feishu Bitable OpenAPI. + +## Commands + +```bash +gitlink-cli feishu +bitable-schema --format markdown +gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json +``` + +## Tables + +Default tables: + +```text +issues +prs +contributors +reports +``` + +## Record Semantics + +Records are summary records derived from `workflow +repo-report` JSON. + +They are not one row per GitLink issue or one row per GitLink pull request. + +Current behavior: + +```text +reports: one summary row per repo report +issues: summary buckets by issue type and priority +prs: summary buckets by change type and risk +contributors: reserved schema; records are empty unless workflow JSON later includes contributor details +``` + +## Real Write Boundary + +Not implemented: + +```text +Bitable OpenAPI create +Bitable OpenAPI batch create +Bitable update +Bitable upsert +Base creation +table creation +view creation +field creation +person/open_id mapping +``` + +Real Bitable writes require a separate design for: + +```text +app authentication +table IDs +record unique keys +search-before-update +pagination +partial failure handling +rate limits +permission diagnostics +``` + diff --git a/docs/feishu-integration.md b/docs/feishu-integration.md index c6b4f4b..6e9a914 100644 --- a/docs/feishu-integration.md +++ b/docs/feishu-integration.md @@ -1,27 +1,39 @@ # Feishu Integration -`gitlink-cli feishu` exports local GitLink workflow JSON to Feishu collaboration surfaces. +`gitlink-cli feishu` exports local GitLink workflow JSON to Feishu. -The commands are intentionally one-way: +The stable command path is intentionally narrow: ```text workflow JSON -> local preview -workflow JSON -> Feishu bot card -workflow JSON -> Feishu DocX / Wiki report -workflow JSON -> Bitable-ready dry-run records +workflow JSON -> Feishu custom bot card +workflow JSON -> weekly report +workflow JSON -> Bitable schema / records dry-run ``` +## Stable Commands + +```text +gitlink-cli feishu +bot-test +gitlink-cli feishu +notify +gitlink-cli feishu +weekly-report +gitlink-cli feishu +bitable-schema +gitlink-cli feishu +bitable-records +``` + +`feishu +doc-export` exists as an experimental command. It uses Feishu self-built app OpenAPI and is not part of the clean first-path workflow. + ## Safety Model -Default behavior is local preview. +- Default behavior is local preview. +- Real Feishu bot delivery requires `--send`. +- `--send` and `--dry-run` cannot be used together. +- Webhook URLs are redacted in command output. +- Secrets and tokens are never intentionally printed. +- The stable commands do not write to GitLink resources. +- Bitable commands are dry-run only and do not call Bitable OpenAPI. -Network operations require `--send`. - -`--send` and `--dry-run` cannot be used together. - -The implementation does not write to GitLink resources, does not close issues, does not comment on PRs, and does not merge code. - -## Custom Bot +## Custom Bot Setup Use a Feishu custom group bot for notification cards. @@ -32,26 +44,41 @@ $env:FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/..." $env:FEISHU_WEBHOOK_SECRET="optional signing secret" ``` -Preview: +Preview a test card: ```bash gitlink-cli feishu +bot-test --format json ``` -Send: +Send a test card: ```bash gitlink-cli feishu +bot-test --send --format table ``` -Send a workflow report card: +## Workflow Report Card + +Generate workflow JSON: ```bash gitlink-cli workflow +repo-report --owner Gitlink --repo gitlink-cli --format json > report.json +``` + +On Windows PowerShell, redirected files may be written with UTF-16 encoding. `feishu` workflow JSON readers accept UTF-8 and UTF-16 BOM files so the redirected output above can be consumed directly. + +Preview a card: + +```bash +gitlink-cli feishu +notify --from-workflow-json report.json --format json +``` + +Send a card: + +```bash gitlink-cli feishu +notify --from-workflow-json report.json --send --format table ``` -Send a card with a DocX or Wiki link: +Send a card with an existing Feishu document or Wiki link: ```bash gitlink-cli feishu +notify \ @@ -61,9 +88,39 @@ gitlink-cli feishu +notify \ --format table ``` -## DocX / Wiki Export +## Weekly Report -Use a Feishu self-built app for document export. +Render markdown: + +```bash +gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown +``` + +Send a weekly summary card: + +```bash +gitlink-cli feishu +weekly-report --from-workflow-json report.json --send --format table +``` + +## Bitable Dry Run + +Generate recommended table schemas: + +```bash +gitlink-cli feishu +bitable-schema --format markdown +``` + +Generate Bitable-ready records: + +```bash +gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json +``` + +These records are summary records derived from workflow repo-report JSON. They are not a per-issue or per-PR synchronization. + +## Experimental DocX / Wiki Export + +`feishu +doc-export` is experimental because it uses Feishu self-built app credentials and writes to DocX / Wiki through OpenAPI. Environment: @@ -81,7 +138,7 @@ gitlink-cli feishu +doc-export \ --format markdown ``` -Append report blocks to a Wiki-backed DocX: +Write to DocX / Wiki: ```bash gitlink-cli feishu +doc-export \ @@ -91,40 +148,10 @@ gitlink-cli feishu +doc-export \ --format table ``` -Create a new DocX in a folder: - -```bash -gitlink-cli feishu +doc-export \ - --from-workflow-json report.json \ - --folder-token "" \ - --title "GitLink workflow report" \ - --send \ - --format table -``` - Required Feishu setup: ```text -1. The self-built app must have DocX / Drive application scopes. -2. The app permission version must be published and approved. -3. The target Wiki / DocX / folder must grant the app write permission. +1. The self-built app must have approved DocX / Drive scopes. +2. The target Wiki / DocX / folder must grant the app write permission. +3. If Feishu returns 1770032: forBidden, credentials are valid but the app cannot write the target document. ``` - -If Feishu returns `1770032: forBidden`, the token is valid but the app cannot write to the target document. Grant the app access to that Wiki/DocX page or use a folder where the app can create documents. - -## Bitable Dry Run - -Generate recommended table schemas: - -```bash -gitlink-cli feishu +bitable-schema --format markdown -``` - -Generate Bitable-ready records: - -```bash -gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json -``` - -These commands do not call Bitable OpenAPI and do not create, update, or upsert records. - diff --git a/docs/feishu-security.md b/docs/feishu-security.md new file mode 100644 index 0000000..6ac40f5 --- /dev/null +++ b/docs/feishu-security.md @@ -0,0 +1,75 @@ +# Feishu Security Notes + +## Default Behavior + +All Feishu shortcut commands default to local preview. + +Real network writes require `--send`. + +`--send` and `--dry-run` cannot be used together. + +## Secrets + +Supported environment variables: + +```text +FEISHU_WEBHOOK_URL +FEISHU_WEBHOOK_SECRET +FEISHU_APP_ID experimental doc-export only +FEISHU_APP_SECRET experimental doc-export only +``` + +Do not commit real webhook URLs, app secrets, access tokens, Base app tokens, table IDs, or document tokens. + +Command output redacts webhook URLs. Tests use fake webhook IDs. + +## Stable Surface + +The stable surface uses Feishu custom bot webhooks: + +```text +feishu +bot-test +feishu +notify +feishu +weekly-report +``` + +These commands can send Feishu cards, but they do not read or write Feishu documents, tables, users, or groups. + +## Dry-Run Surface + +The Bitable commands are local only: + +```text +feishu +bitable-schema +feishu +bitable-records +``` + +They do not call Feishu OpenAPI and cannot create, update, or upsert Bitable records. + +## Experimental Surface + +`feishu +doc-export` is experimental. It uses: + +```text +app_id +app_secret +tenant_access_token +Wiki OpenAPI +DocX OpenAPI +``` + +It should not be treated as part of the stable clean export path. If used, grant the self-built app only the minimum required document permissions. + +## Non-Goals + +```text +BotBuilder integration +Feishu Robot Assistant workflows +automatic Feishu permission changes +GitLink remote writes +GitLink comments +Issue closure +merge actions +real Bitable writes +``` + diff --git a/examples/feishu/README.md b/examples/feishu/README.md index 132e698..941fc2e 100644 --- a/examples/feishu/README.md +++ b/examples/feishu/README.md @@ -1,24 +1,48 @@ # Feishu Export Examples -## 1. Generate Workflow JSON +## Stable Workflow + +### 1. Generate Workflow JSON ```bash gitlink-cli workflow +repo-report --owner Gitlink --repo gitlink-cli --format json > report.json ``` -## 2. Preview Notification Card +### 2. Preview Notification Card ```bash gitlink-cli feishu +notify --from-workflow-json report.json --format json ``` -## 3. Send Notification Card +### 3. Send Notification Card ```bash gitlink-cli feishu +notify --from-workflow-json report.json --send --format table ``` -## 4. Preview Wiki Export +### 4. Render Weekly Report + +```bash +gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown +``` + +### 5. Generate Bitable Schema + +```bash +gitlink-cli feishu +bitable-schema --format markdown +``` + +### 6. Generate Bitable Records + +```bash +gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json +``` + +## Experimental DocX / Wiki Export + +`+doc-export` is available for Feishu self-built app experiments. It is not part of the stable clean export path. + +Preview: ```bash gitlink-cli feishu +doc-export \ @@ -27,7 +51,7 @@ gitlink-cli feishu +doc-export \ --format markdown ``` -## 5. Export To Wiki +Write: ```bash gitlink-cli feishu +doc-export \ @@ -37,9 +61,3 @@ gitlink-cli feishu +doc-export \ --format table ``` -## 6. Generate Bitable Records - -```bash -gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json -``` - diff --git a/feishu-export-design/OFFICIAL_DOCS_ALIGNMENT.md b/feishu-export-design/OFFICIAL_DOCS_ALIGNMENT.md index 69b7af7..17504fc 100644 --- a/feishu-export-design/OFFICIAL_DOCS_ALIGNMENT.md +++ b/feishu-export-design/OFFICIAL_DOCS_ALIGNMENT.md @@ -266,7 +266,8 @@ But it is incomplete for a "Feishu collaboration export" feature because it does Required design adjustment: ```text -Add doc-export with DocX/Wiki support as the first Open Platform custom-app integration. -Keep real Bitable writes after doc-export. -Keep custom bot as the low-friction smoke test path. +Keep custom bot as the low-friction stable smoke test path. +Keep Bitable as dry-run in the stable path. +Treat doc-export with DocX/Wiki support as experimental because it uses self-built app OpenAPI and document write permissions. +Keep real Bitable writes out of scope. ``` diff --git a/feishu-export-design/TECHNICAL_PLAN.md b/feishu-export-design/TECHNICAL_PLAN.md index 3969196..3904876 100644 --- a/feishu-export-design/TECHNICAL_PLAN.md +++ b/feishu-export-design/TECHNICAL_PLAN.md @@ -266,7 +266,7 @@ type BitableRecord struct { Official Feishu Open Platform docs show that cloud document integration belongs to the self-built app flow, not the custom bot flow. -Add this after the custom bot MVP: +Experimental command: ```text feishu +doc-export @@ -310,13 +310,19 @@ Implementation notes: - Mock all HTTP tests. - Do not implement document sharing or permission changes in the first doc export pass. -Recommended product flow: +Stable product flow: + +```text +workflow +repo-report -> feishu +weekly-report -> feishu +notify --doc-url -> feishu +bitable-records +``` + +Experimental product flow: ```text workflow +repo-report -> feishu +doc-export --wiki-url -> feishu +notify --doc-url -> feishu +bitable-records ``` -This should land before any real Bitable write because DocX export has clearer value and simpler consistency semantics than Bitable upsert. +DocX export should remain clearly marked as experimental until tenant permissions, scopes, and document-write behavior are stable. ## Tests To Add diff --git a/reports/FEISHU_TASK_COMPLETION.md b/reports/FEISHU_TASK_COMPLETION.md index b4f0f69..8c46bb9 100644 --- a/reports/FEISHU_TASK_COMPLETION.md +++ b/reports/FEISHU_TASK_COMPLETION.md @@ -30,7 +30,7 @@ gitlink-cli feishu +bitable-records - Added project activity card generation from workflow JSON. - Added weekly report rendering from workflow JSON. - Added `--doc-url` support for notification cards. -- Added `feishu +doc-export` for Feishu DocX / Wiki export. +- Added experimental `feishu +doc-export` for Feishu DocX / Wiki export. - Added self-built app tenant token acquisition. - Added Wiki node resolution. - Added DocX block creation client. @@ -109,6 +109,20 @@ Design now treats Feishu Knowledge Base / Wiki pages as a project showcase and r workflow JSON -> DocX/Wiki report -> bot card with doc URL -> Bitable dry-run records ``` +After scope review, DocX / Wiki export is explicitly experimental and not part of the stable clean workflow. + +Stable path: + +```text +workflow JSON -> bot card / weekly report / Bitable dry-run records +``` + +Experimental path: + +```text +workflow JSON -> DocX/Wiki export through self-built app OpenAPI +``` + ## Tests Commands run: @@ -147,9 +161,13 @@ document permission modification DocX content write ``` +Note: experimental `doc-export` can attempt DocX block writes when explicitly invoked with `--send`, but it remains outside the stable clean export path. + ## Next Engineering Step -Complete the Feishu document permission setup and rerun: +For stable delivery, continue validating custom bot delivery, weekly reports, and Bitable dry-run output. + +For experimental DocX/Wiki export, complete the Feishu document permission setup and rerun: ```text gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url --send --format table diff --git a/reports/FEISHU_TEST_ENTERPRISE_SMOKE_20260615.md b/reports/FEISHU_TEST_ENTERPRISE_SMOKE_20260615.md new file mode 100644 index 0000000..581bf7c --- /dev/null +++ b/reports/FEISHU_TEST_ENTERPRISE_SMOKE_20260615.md @@ -0,0 +1,116 @@ +# Feishu Test Enterprise Smoke Report + +Date: 2026-06-15 + +Branch: + +```text +feat/feishu-export-clean +``` + +## Scope + +This smoke run validates the stable Feishu export path in a real Feishu test enterprise. + +Stable path: + +```text +bot-test +notify +weekly-report +bitable-schema +bitable-records +``` + +Experimental path: + +```text +doc-export +``` + +Secrets, full webhook URLs, app secrets, and real Wiki tokens are not recorded in this report. + +## Local Verification + +Commands: + +```bash +gofmt -w shortcuts/feishu +git diff --check +go test ./shortcuts/feishu ./shortcuts ./... +``` + +Result: + +```text +passed +``` + +## Windows JSON Encoding Check + +The smoke run generated workflow JSON through Windows PowerShell redirection. + +Initial result before fix: + +```text +parse workflow JSON: invalid character 'ΓΏ' looking for beginning of value +``` + +Fix: + +```text +workflow JSON reader now accepts UTF-8 BOM, UTF-16LE BOM, and UTF-16BE BOM. +``` + +Post-fix result: + +```text +workflow JSON generated by PowerShell redirection is accepted. +``` + +## Real Feishu Bot Smoke + +| Step | Result | Notes | +| --- | --- | --- | +| bot-test preview | pass | local preview | +| bot-test send | pass | HTTP 200 / Feishu code 0 | +| notify preview | pass | local preview | +| notify send | pass | HTTP 200 / Feishu code 0 | +| notify send with doc URL | pass | HTTP 200 / Feishu code 0 | +| weekly-report markdown | pass | markdown rendered | +| weekly-report send | pass | HTTP 200 / Feishu code 0 | + +## Bitable Dry-Run Smoke + +| Step | Result | Notes | +| --- | --- | --- | +| bitable-schema json | pass | JSON schema generated | +| bitable-schema markdown | pass | Markdown schema generated | +| bitable-records json | pass | dry-run records generated | +| bitable-records table | pass | reports/issues/prs records summarized; contributors reserved | + +## Experimental Doc Export Smoke + +| Step | Result | Notes | +| --- | --- | --- | +| doc-export preview | pass | target resolved as Wiki append preview | +| doc-export send | expected failure | Feishu returned HTTP 403 / code 1770032 / forBidden | + +Interpretation: + +```text +The self-built app credentials can get tenant_access_token and resolve the Wiki node, but the app cannot write blocks to the target Wiki-backed DocX page yet. +``` + +Required Feishu-side action: + +```text +Grant the self-built app approved DocX/Drive scopes and write access to the target Wiki/DocX page or use a writable folder token. +``` + +## Conclusion + +Stable Feishu export path is working in the test enterprise. + +`doc-export` remains experimental and permission-blocked for real writes. + diff --git a/shortcuts/feishu/feishu.go b/shortcuts/feishu/feishu.go index 920504d..4b242b9 100644 --- a/shortcuts/feishu/feishu.go +++ b/shortcuts/feishu/feishu.go @@ -76,7 +76,7 @@ func newWeeklyReportShortcut() *common.Shortcut { func newDocExportShortcut() *common.Shortcut { return &common.Shortcut{ Name: "doc-export", - Description: "Preview or export a workflow report to Feishu DocX or Wiki", + Description: "Experimental: preview or export a workflow report to Feishu DocX or Wiki", Flags: []common.Flag{ {Name: "from-workflow-json", Usage: "Read workflow repo report JSON from a file", Required: true}, {Name: "title", Usage: "Document title"}, diff --git a/shortcuts/feishu/feishu_test.go b/shortcuts/feishu/feishu_test.go index 54a33d9..8e8829b 100644 --- a/shortcuts/feishu/feishu_test.go +++ b/shortcuts/feishu/feishu_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net/http" "net/http/httptest" + "os" "path/filepath" "strings" "testing" @@ -120,6 +121,31 @@ func TestReadWorkflowReportSupportsInputFixture(t *testing.T) { } } +func TestReadWorkflowReportSupportsPowerShellUTF16Redirect(t *testing.T) { + raw, err := os.ReadFile(filepath.Join("..", "workflow", "testdata", "repo_report.json")) + if err != nil { + t.Fatalf("read fixture: %v", err) + } + utf16Data := []byte{0xFF, 0xFE} + for _, r := range string(raw) { + if r > 0xFFFF { + t.Fatalf("fixture contains non-BMP rune %q", r) + } + utf16Data = append(utf16Data, byte(r), byte(r>>8)) + } + path := filepath.Join(t.TempDir(), "report.json") + if err := os.WriteFile(path, utf16Data, 0600); err != nil { + t.Fatalf("write UTF-16 fixture: %v", err) + } + report, err := readWorkflowReport(path, "en") + if err != nil { + t.Fatalf("readWorkflowReport returned error: %v", err) + } + if report.Repository != "Gitlink/gitlink-cli" { + t.Fatalf("Repository = %q", report.Repository) + } +} + func TestBitableSchemaAndRecords(t *testing.T) { report, err := readWorkflowReport(filepath.Join("..", "workflow", "testdata", "repo_report.json"), "en") if err != nil { diff --git a/shortcuts/feishu/workflow_input.go b/shortcuts/feishu/workflow_input.go index 60553a9..5c67320 100644 --- a/shortcuts/feishu/workflow_input.go +++ b/shortcuts/feishu/workflow_input.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "strings" + "unicode/utf16" "github.com/gitlink-org/gitlink-cli/shortcuts/workflow" ) @@ -14,6 +15,10 @@ func readWorkflowReport(path string, lang string) (workflow.RepoReportResult, er if err != nil { return workflow.RepoReportResult{}, fmt.Errorf("read workflow JSON: %w", err) } + data, err = normalizeJSONBytes(data) + if err != nil { + return workflow.RepoReportResult{}, err + } data, err = unwrapWorkflowJSON(data) if err != nil { return workflow.RepoReportResult{}, err @@ -32,6 +37,34 @@ func readWorkflowReport(path string, lang string) (workflow.RepoReportResult, er return workflow.RepoReportResult{}, fmt.Errorf("parse workflow JSON: expected workflow RepoReportResult or RepoReportInput") } +func normalizeJSONBytes(data []byte) ([]byte, error) { + if len(data) >= 3 && data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF { + return data[3:], nil + } + if len(data) >= 2 && data[0] == 0xFF && data[1] == 0xFE { + return decodeUTF16(data[2:], true) + } + if len(data) >= 2 && data[0] == 0xFE && data[1] == 0xFF { + return decodeUTF16(data[2:], false) + } + return data, nil +} + +func decodeUTF16(data []byte, littleEndian bool) ([]byte, error) { + if len(data)%2 != 0 { + return nil, fmt.Errorf("parse workflow JSON: invalid UTF-16 byte length") + } + words := make([]uint16, 0, len(data)/2) + for i := 0; i < len(data); i += 2 { + if littleEndian { + words = append(words, uint16(data[i])|uint16(data[i+1])<<8) + } else { + words = append(words, uint16(data[i])<<8|uint16(data[i+1])) + } + } + return []byte(string(utf16.Decode(words))), nil +} + func unwrapWorkflowJSON(data []byte) ([]byte, error) { var raw map[string]json.RawMessage if err := json.Unmarshal(data, &raw); err != nil { diff --git a/skills/gitlink-feishu/SKILL.md b/skills/gitlink-feishu/SKILL.md index ba0f60c..81efc03 100644 --- a/skills/gitlink-feishu/SKILL.md +++ b/skills/gitlink-feishu/SKILL.md @@ -1,7 +1,7 @@ --- name: gitlink-feishu version: 1.0.0 -description: "Export GitLink workflow JSON to Feishu bot cards, DocX/Wiki reports, and Bitable-ready dry-run records." +description: "Export GitLink workflow JSON to Feishu custom bot cards, weekly reports, and Bitable-ready dry-run records." metadata: requires: bins: ["gitlink-cli"] @@ -10,47 +10,58 @@ metadata: # gitlink-feishu -Use this skill when a user needs to send or export GitLink workflow analysis to Feishu. +Use this skill when a user needs to export GitLink workflow analysis into Feishu. -## Rules +## Purpose -- Prefer local preview first. -- Use `--send` only when the user explicitly wants a Feishu network write. -- Never use BotBuilder or Robot Assistant workflows. -- Do not write to GitLink resources. -- Do not print webhook URLs, app secrets, or access tokens. -- Use `+bitable-records` for dry-run output only; do not claim that Bitable has been written. +Stable path: -## Workflow +```text +workflow JSON -> Feishu bot card / weekly report / Bitable dry-run records +``` -Generate workflow JSON: +Experimental path: + +```text +workflow JSON -> Feishu DocX / Wiki export +``` + +## Inputs + +Workflow JSON should usually come from: ```bash gitlink-cli workflow +repo-report --owner --repo --format json > report.json ``` -Preview a Feishu card: +## Safety Rules + +- Preview first. +- Use `--send` only when the user explicitly wants a Feishu network write. +- Never use BotBuilder or Robot Assistant workflows. +- Do not write to GitLink resources. +- Do not print webhook URLs, app secrets, access tokens, or table tokens. +- Treat `+bitable-schema` and `+bitable-records` as local dry-run commands only. +- Treat `+doc-export` as experimental because it uses self-built app OpenAPI and document write permissions. + +## Preview Flow + +Preview a card: ```bash gitlink-cli feishu +notify --from-workflow-json report.json --format json ``` -Send a Feishu card: +Render a weekly report: ```bash -gitlink-cli feishu +notify --from-workflow-json report.json --send --format table +gitlink-cli feishu +weekly-report --from-workflow-json report.json --format markdown ``` -Preview a document export: +Generate Bitable schemas: ```bash -gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "" --format markdown -``` - -Export to DocX or Wiki: - -```bash -gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "" --send --format table +gitlink-cli feishu +bitable-schema --format markdown ``` Generate Bitable-ready records: @@ -59,7 +70,7 @@ Generate Bitable-ready records: gitlink-cli feishu +bitable-records --from-workflow-json report.json --format json ``` -## Feishu Setup +## Send Flow Custom bot commands need: @@ -68,12 +79,46 @@ FEISHU_WEBHOOK_URL FEISHU_WEBHOOK_SECRET optional ``` -DocX/Wiki export needs: +Send a card: + +```bash +gitlink-cli feishu +notify --from-workflow-json report.json --send --format table +``` + +Send a weekly report card: + +```bash +gitlink-cli feishu +weekly-report --from-workflow-json report.json --send --format table +``` + +## Experimental Doc Export + +DocX / Wiki export needs: ```text FEISHU_APP_ID FEISHU_APP_SECRET ``` -The self-built app must also have permission to write the target DocX/Wiki page or folder. +Preview only: + +```bash +gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "" --format markdown +``` + +Write to Feishu: + +```bash +gitlink-cli feishu +doc-export --from-workflow-json report.json --wiki-url "" --send --format table +``` + +If Feishu returns `1770032: forBidden`, the app token is valid but the app cannot write to the target DocX/Wiki page or folder. + +## Non-Goals + +- No GitLink remote writes. +- No GitLink comments, issue closure, merge, or webhook creation. +- No Bitable real writes in the stable path. +- No BotBuilder integration. +- No automatic Feishu permission changes.