@thinkingai/ae-cli 6.1.17 → 6.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +2 -0
  2. package/README.zh.md +6 -0
  3. package/dist/{auth-77BUFLGC.js → auth-QPEVVBKT.js} +20 -15
  4. package/dist/auth-UMJAA72O.js +15 -0
  5. package/dist/{capability-72DTW5M2.js → capability-ASI62I4A.js} +53 -15
  6. package/dist/{chunk-UW5UN47B.js → chunk-533JK3YX.js} +2 -0
  7. package/dist/{chunk-UOUS37JQ.js → chunk-6QK7SYYY.js} +5 -4
  8. package/dist/{chunk-TUKQZTMI.js → chunk-7K24F7T2.js} +2 -0
  9. package/dist/{chunk-OO6XR6LK.js → chunk-AMBFK2K3.js} +2 -0
  10. package/dist/{sync-DAVKYVMW.js → chunk-B5HMQAOM.js} +31 -540
  11. package/dist/{chunk-VR3LCBHW.js → chunk-DKEXH6Q5.js} +6 -5
  12. package/dist/{chunk-VTWMIC5L.js → chunk-E2JKXMVO.js} +2 -0
  13. package/dist/{chunk-LYVNONC4.js → chunk-FR2EDAQM.js} +36 -0
  14. package/dist/{chunk-ILIU36SU.js → chunk-GJXRF7Y6.js} +6 -5
  15. package/dist/{chunk-DWO43OIB.js → chunk-JQ3ENZZH.js} +2 -0
  16. package/dist/chunk-JYMGHGCE.js +191 -0
  17. package/dist/{chunk-GT46FPXN.js → chunk-KEWVSO64.js} +18 -8
  18. package/dist/chunk-KZ6ZHF5J.js +294 -0
  19. package/dist/chunk-O6K2ODUE.js +318 -0
  20. package/dist/chunk-QL6R6TSK.js +25215 -0
  21. package/dist/{chunk-4SGZG4XY.js → chunk-RWXIXOZG.js} +28 -13
  22. package/dist/{chunk-YA6SMTXG.js → chunk-S5PONFBM.js} +5 -4
  23. package/dist/{chunk-4NN5IWVN.js → chunk-T6OSFQZD.js} +2 -0
  24. package/dist/{chunk-PTE56QPL.js → chunk-TKHSULJT.js} +6 -0
  25. package/dist/{chunk-6EIJSNBD.js → chunk-Y74WTIKJ.js} +2 -0
  26. package/dist/{client-TKG4WBHN.js → client-N7NGZUNI.js} +6 -4
  27. package/dist/{community-report-client-FI4LNVYS.js → community-report-client-6OL6GBQW.js} +3 -3
  28. package/dist/{config-RE6CMGPK.js → config-XNMACCKX.js} +10 -8
  29. package/dist/{data-integration-XQYB4X4F.js → data-integration-4NZGZ45E.js} +2502 -272
  30. package/dist/index.js +137 -1245
  31. package/dist/{local-data-upload-client-BWHSUQQK.js → local-data-upload-client-EFHDLXFG.js} +3 -3
  32. package/dist/{memory-YK33G4T7.js → memory-HBJQ2GC5.js} +8 -7
  33. package/dist/{metadata-UILXHBWF.js → metadata-62EWBEIG.js} +12 -11
  34. package/dist/{model-NR3JHFSJ.js → model-BHLJ2QMT.js} +10 -9
  35. package/dist/personal-semantic-preference-JBVMAI7L.js +240 -0
  36. package/dist/project-semantic-BQ4MPUS5.js +1115 -0
  37. package/dist/sync-MUWPRM5I.js +522 -0
  38. package/dist/{te-agent-4BKBODMF.js → te-agent-WQZTMEK4.js} +12 -10
  39. package/dist/{te-analysis-O6DCO6BS.js → te-analysis-MNCG65LU.js} +534 -48
  40. package/dist/{te-community-HLC43QKH.js → te-community-BNE6KREL.js} +8 -7
  41. package/dist/{te-dataops-EJP56W3K.js → te-dataops-TXLKM2W6.js} +469 -68
  42. package/dist/{te-engage-FGBGQ4IY.js → te-engage-TPKLRVTL.js} +84 -10
  43. package/dist/{te-experiment-SO5MPDMJ.js → te-experiment-6BYKTCY7.js} +303 -12
  44. package/dist/{te-kb-SQCLHG6X.js → te-kb-BUD6N3NI.js} +312 -25
  45. package/dist/{te-system-YARIK4S5.js → te-system-44LZJDTQ.js} +573 -37
  46. package/dist/{te-team-EFKWYKMK.js → te-team-XMP47YXE.js} +10 -7
  47. package/dist/{update-OGPSZM5A.js → update-UODFOZ4P.js} +9 -7
  48. package/package.json +18 -9
  49. package/skills/ae-agent/SKILL.md +3 -4
  50. package/skills/ae-agent/references/edit-skill.md +3 -0
  51. package/skills/ae-agent/references/get-skill-content.md +1 -1
  52. package/skills/ae-agent/references/rescan-skills.md +15 -13
  53. package/skills/ae-agent/references/upload-skill.md +7 -4
  54. package/skills/ae-analysis/SKILL.md +45 -4
  55. package/skills/ae-analysis/metadata_resolution.md +38 -4
  56. package/skills/ae-analysis/references/analysis_data_retrieval.md +29 -0
  57. package/skills/ae-analysis/references/analysis_gateway_assets.md +1 -1
  58. package/skills/ae-analysis/references/asset_authentication_export.md +22 -0
  59. package/skills/ae-analysis/references/asset_authentication_list.md +18 -14
  60. package/skills/ae-analysis/references/asset_authentication_update.md +29 -14
  61. package/skills/ae-analysis/references/audience_models.md +18 -0
  62. package/skills/ae-analysis/references/command_index.md +19 -11
  63. package/skills/ae-analysis/references/dashboard_get.md +18 -1
  64. package/skills/ae-analysis/references/dashboard_update.md +3 -0
  65. package/skills/ae-analysis/references/personal_semantic_preference_add.md +23 -0
  66. package/skills/ae-analysis/references/personal_semantic_preference_delete.md +17 -0
  67. package/skills/ae-analysis/references/personal_semantic_preference_get.md +19 -0
  68. package/skills/ae-analysis/references/personal_semantic_preference_list.md +21 -0
  69. package/skills/ae-analysis/references/personal_semantic_preference_update.md +19 -0
  70. package/skills/ae-analysis/references/project_timezone_update.md +13 -4
  71. package/skills/ae-analysis/references/property_create.md +2 -0
  72. package/skills/ae-analysis/references/super_metadata_batch_create.md +2 -0
  73. package/skills/ae-analysis/references/user_cluster_models.md +2 -0
  74. package/skills/ae-analysis/references/user_cluster_update.md +8 -4
  75. package/skills/ae-analysis/references/user_tag_create.md +7 -1
  76. package/skills/ae-analysis/references/user_tag_models.md +8 -2
  77. package/skills/ae-data-integration/SKILL.md +24 -4
  78. package/skills/ae-data-integration/references/custom-layer.md +93 -0
  79. package/skills/ae-data-integration/references/error-handling.md +145 -0
  80. package/skills/ae-data-integration/references/handoff.md +77 -18
  81. package/skills/ae-data-integration/references/local-analysis.md +1 -1
  82. package/skills/ae-data-integration/references/reuse.md +9 -5
  83. package/skills/ae-data-integration/references/sink-upload.md +1 -1
  84. package/skills/ae-data-integration/references/source-inspect.md +35 -13
  85. package/skills/ae-data-integration/references/tracking-plan.md +7 -5
  86. package/skills/ae-data-integration/references/transform.md +12 -10
  87. package/skills/ae-data-integration/references/ue-mapping.md +33 -11
  88. package/skills/ae-data-integration/references/ue-routing.md +23 -0
  89. package/skills/ae-dataops/SKILL.md +11 -1
  90. package/skills/ae-dataops/references/dataops-backfill.md +135 -0
  91. package/skills/ae-engage/SKILL.md +5 -0
  92. package/skills/ae-engage/references/build-task-save-guide.md +14 -1
  93. package/skills/ae-engage/references/save-flow.md +37 -1
  94. package/skills/ae-engage/references/save-task.md +88 -0
  95. package/skills/ae-experiment/SKILL.md +14 -4
  96. package/skills/ae-experiment/references/manage_feature_whitelist.md +66 -0
  97. package/skills/ae-experiment/references/manage_guardrail_metrics.md +26 -0
  98. package/skills/ae-experiment/references/save_experiment.md +1 -1
  99. package/skills/ae-experiment/references/save_metric.md +20 -8
  100. package/skills/ae-kb/SKILL.md +121 -10
  101. package/skills/ae-project-semantic/SKILL.md +193 -0
  102. package/skills/ae-project-semantic/references/query-routing-v5.md +165 -0
  103. package/skills/ae-project-semantic/references/recommendation-quality.md +68 -0
  104. package/skills/ae-system/SKILL.md +28 -30
  105. package/skills/ae-system/references/channel-management.md +303 -0
  106. package/dist/auth-2WTQOP77.js +0 -14
  107. package/dist/capability-PJHNI4GJ.js +0 -315
  108. package/dist/chunk-4KVPKXFX.js +0 -98
  109. package/dist/chunk-C4MGVGJW.js +0 -13
  110. package/dist/chunk-P3FGXJTU.js +0 -349
  111. package/dist/chunk-QGM4M3NI.js +0 -37
  112. package/dist/chunk-RGKJGKT7.js +0 -71
  113. package/dist/chunk-SAU3QFIQ.js +0 -556
  114. package/dist/chunk-VPKZ7I72.js +0 -509
  115. package/dist/chunk-ZZUOD757.js +0 -598
  116. package/dist/memory-CHRU2F7W.js +0 -893
  117. package/dist/metadata-XXR34N5P.js +0 -339
  118. package/dist/model-K3KLWIW6.js +0 -139
  119. package/dist/sync-FCKOVWWS.js +0 -10261
  120. package/dist/te-agent-HLW4VTQK.js +0 -3893
  121. package/dist/te-analysis-ZMNGOVNW.js +0 -8958
  122. package/dist/te-community-6HPBWJUZ.js +0 -1859
  123. package/dist/te-dataops-HDRUXY4K.js +0 -2208
  124. package/dist/te-engage-RAK5PESW.js +0 -4898
  125. package/dist/te-experiment-VZF7BT6G.js +0 -770
  126. package/dist/te-system-Z77IKZFN.js +0 -2213
@@ -0,0 +1,68 @@
1
+ # Project Semantic Recommendation Quality
2
+
3
+ ## Business Goal
4
+
5
+ The Agent should turn a certified project snapshot into a small, reviewable L2 semantic system. The output should help future analysis interpret business terms, choose the right dashboards/reports, and apply project-wide rules consistently.
6
+
7
+ It should not produce a checklist of assets to approve one by one.
8
+
9
+ ## Extraction Method
10
+
11
+ 1. Start with `manifest.json`, `.asset-package.json`, and all catalog files. Published semantics and active candidates form the duplicate/update exclusion set. Disabled semantics form a strict suppression set and must not be recreated by the scan. Rejected candidates require a documented material change before reconsideration.
12
+ 2. Treat `indexes/work-units.jsonl` as the primary investigation queue. Follow its recent-90-day usage order, but rotate across distinct evidence-backed business themes before adding more candidates for a dominant theme.
13
+ 3. Start with authenticated, active dashboards and reports as primary evidence. When the user explicitly approved a broader export scope, preserve each asset's authentication and selection provenance. Unauthenticated dashboards/reports may support discovery only when corroborated by definitions, work-unit relationships, usage, or notes, and any resulting claim must carry a lower confidence boundary. Events, properties, metrics, notes, and background text are supporting evidence only. Open `details/normalized/**` and `details/raw/**` through `detail_locator` only for assets that may support a candidate.
14
+ 4. Use normalized key fields to establish definition families. Display names, descriptions, and notes remain available as interpretation evidence, but differences in those fields alone must not split a family. Discover semantic families with cross-domain questions: business object/state, analysis subject and grain, formula and denominator, inclusion/exclusion, time roles, units and normalization, asset-selection priority, applicability and exceptions. These are inspection dimensions, not topic names.
15
+ 5. Name L2 topic domains only after the evidence families are understood. Use the project's own natural business language; do not start from a fixed industry taxonomy or known test-package themes.
16
+ 6. For every cluster, ask what reusable project meaning it implies:
17
+ - business concept: a named business object or state;
18
+ - business rule: inclusion/exclusion logic;
19
+ - asset semantics: default asset set for a question type;
20
+ - calculation convention: denominator, numerator, window, attribution, currency, deduplication.
21
+ 7. Create candidates only when the semantic is reusable across future questions and changes Agent behavior.
22
+ 8. Return a successful empty recommendation when published or active semantics already cover every supported behavior change.
23
+ 9. Apply [`query-routing-v5.md`](query-routing-v5.md) after evidence-family discovery. Prefer reusable query routing, recall shortcuts, and evidence-bounded analysis paths over standalone formula or state descriptions.
24
+
25
+ ## Reject These Candidates
26
+
27
+ - One candidate per asset.
28
+ - Candidate title merely copies an event/property/report name.
29
+ - Candidate title is an L1 metadata object, for example an event, property, metric, tag, or field name.
30
+ - Candidate has fewer than two related evidence assets unless one asset is a high-authority certified dashboard/report with detailed notes.
31
+ - Candidate claims a calculation rule not present in asset names, descriptions, definitions, notes, or inspected reports.
32
+ - Candidate mixes unrelated lifecycle domains to raise evidence count.
33
+ - Candidate treats an unauthenticated asset as a certified or authoritative project default without corroboration and an explicit confidence limit.
34
+ - Candidate is a duplicate of a published or disabled semantic by title, alias, or equivalent behavior.
35
+ - Candidate is a generic lifecycle template that ignores the project domain discovered in the snapshot.
36
+ - Candidate only restates one formula, threshold, state, event, property, report, dashboard, or asset name.
37
+ - Candidate is a broad topic summary with no asset-choice branch, stop condition, or wrong-asset exclusion.
38
+
39
+ ## Candidate Shape
40
+
41
+ Each topic group should explain why the assets belong together. Each candidate should include:
42
+
43
+ - `candidate_kind`: `QUERY_ROUTING`, `RECALL_SHORTCUT`, or `ANALYSIS_PLAYBOOK`;
44
+ - `semantic_type`;
45
+ - `title`;
46
+ - `summary`;
47
+ - `content` with definition, scope, usage, and exclusions;
48
+ - `keywords`;
49
+ - `resource_refs` with asset type, id/name, display name, and description when available;
50
+ - `work_unit_coverage` for the snapshot work units it covers;
51
+ - `recommendation_reason`;
52
+ - `evidence` with source titles and excerpts.
53
+ - the V5 route fields required for its candidate kind, including branches, exclusions, stop/fallback behavior, asset roles, evidence strength, and problem-frame ids.
54
+
55
+ The candidate body must read as governed business knowledge, not as an asset inventory. Use this review order:
56
+
57
+ 1. **Business definition**: what the concept, rule, or convention means in this project.
58
+ 2. **Applicable questions**: which future questions should activate it.
59
+ 3. **Decision or calculation rule**: the concrete inclusion, exclusion, grain, denominator, time-window, or asset-selection rule proven by evidence.
60
+ 4. **Agent usage rule**: how the Agent changes interpretation or execution after adopting it.
61
+ 5. **Boundaries and exceptions**: what must not be inferred, merged, or substituted.
62
+ 6. **Evidence assets**: keep dashboards/reports in `resource_refs` and evidence sections; do not make their names the semantic body.
63
+
64
+ Reject a batch when multiple candidates differ only by asset names or counts while reusing the same definition, usage, and exclusion prose. A recommendation reason must name the business claim supported by the evidence, not merely state that dashboards/reports were bound.
65
+
66
+ ## Evaluation Packages
67
+
68
+ Evaluate the unchanged protocol on at least two unrelated asset packages when tuning recommendation quality. Do not add project names, asset IDs, expected titles, expected domains, or expected counts to the skill or CLI code after seeing a test result. A sparse governed package should trigger explicit, sequential consent before re-exporting `collaborative` and then `all_visible`; a sparse broad package should still produce fewer candidates or explicit insufficiency warnings rather than generic filler.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: ae-system
3
- version: 1.1.0
4
- description: "AE Agent system administration CLI for root and agent administrators. Use when the user asks to manage Agent members, sandboxes and shared tools, company model visibility/defaults/pricing, usage statistics and exports, cost quotas, balance alerts, or IM channels. Must use ae-cli system commands, discover real IDs before writes, and never attempt to bypass a permission denial."
3
+ version: 1.2.0
4
+ description: "AE Agent system administration CLI for root and agent administrators. Use when the user asks to manage Agent members, sandboxes and shared tools, company model visibility/defaults/pricing, usage statistics and exports, cost quotas, balance alerts, IM channels, channel routing, WhatsApp Web linking, or Feishu user bindings. Must use ae-cli system commands, discover real IDs before writes, and never attempt to bypass a permission denial."
5
5
  ---
6
6
 
7
7
  # ae-system
@@ -10,12 +10,13 @@ Use the `system` domain for Agent system administration:
10
10
 
11
11
  ```bash
12
12
  ae-cli system +<command> [options]
13
+ ae-cli system <resource> <action> [options]
13
14
  ```
14
15
 
15
16
  ## Mandatory Rules
16
17
 
17
18
  - These commands are only for users whose Agent role is `root` or `agent_admin`.
18
- - The te-agent `/api/admin/**` endpoint is the final authorization boundary. A member receives a permission error (HTTP 403). Do not retry login or attempt a different endpoint after a 403.
19
+ - The te-agent `/api/admin/**` and `/api/cli/channel/v1/**` endpoints are the final authorization boundaries. A member receives a permission error (HTTP 403). Do not retry login or attempt a different endpoint after a 403.
19
20
  - Run `ae-cli auth login --host <host>` before using this domain. System administration requires a user access-token session; sandbox identity headers are not an authorization substitute.
20
21
  - `+npm-install` is the exception that must also run inside a Linux te-agent sandbox because it packages the installed Linux files. It still requires the logged-in user to be `root` or `agent_admin`.
21
22
  - Discover real IDs with a list command before any update or delete. Never guess a user, sandbox, model, quota rule, or channel ID.
@@ -353,41 +354,38 @@ Rules:
353
354
 
354
355
  ### Channels
355
356
 
357
+ For channel setup, routing, WhatsApp Web linking, or Feishu user binding, read [references/channel-management.md](references/channel-management.md) before taking action. It defines the two confirmation phases and the `ae-cli` plus Feishu OpenAPI MCP workflow.
358
+
356
359
  | Command | Risk | Purpose |
357
360
  | --- | --- | --- |
358
- | `+list-channels` | read | List Feishu, Lark, and Slack channels. |
361
+ | `+list-channels` | read | List all configured channels. |
362
+ | `channel get` | read | Read one channel, its verification state, and endpoints. |
359
363
  | `+create-channel` | write | Create one channel. |
360
364
  | `+update-channel` | write | Update channel settings, credentials, model, prompt, or enabled state. |
361
365
  | `+remove-channel` | high-risk-write | Delete a channel, unbind users, and stop its connection. |
362
-
363
- Always use `@file` for channel payloads when they contain credentials:
366
+ | `channel verify` | write | Verify credentials and discover endpoints. |
367
+ | `channel routing get` | read | Read one endpoint's group message routing. |
368
+ | `channel routing set` | write | Replace one endpoint's group message routing. |
369
+ | `channel whatsapp-web status` | read | Read a WhatsApp Web link state and QR data. |
370
+ | `channel whatsapp-web start` | write | Start or resume WhatsApp Web QR linking. |
371
+ | `channel whatsapp-web unlink` | high-risk-write | Unlink WhatsApp Web and remove stored credentials. |
372
+ | `channel binding list` | read | List channel user bindings. |
373
+ | `channel binding bind-feishu` | write | Bind one Feishu user. |
374
+ | `+bind-feishu-users` | write | Bind 1-100 Feishu users and optionally assign Agents. |
375
+ | `channel binding unbind` | high-risk-write | Delete one channel user binding. |
376
+ | `channel binding set-agent` | write | Set or clear one binding's private-chat default Agent. |
377
+
378
+ Use canonical snake_case request fields. The four original commands also accept their legacy camelCase JSON fields for compatibility. Always use `@file` for credentials and batch rosters:
364
379
 
365
380
  ```bash
366
381
  ae-cli system +create-channel --channel @channel.json
367
382
  ae-cli system +update-channel --id <channel-id> --channel @channel-update.json
383
+ ae-cli system +bind-feishu-users \
384
+ --channel-id <channel-id> \
385
+ --endpoint-id <endpoint-id> \
386
+ --bindings @bindings.json
368
387
  ```
369
388
 
370
- Create schema:
371
-
372
- ```json
373
- {
374
- "name": "Required display name",
375
- "type": "feishu",
376
- "config": {
377
- "appId": "Feishu/Lark",
378
- "appSecret": "Feishu/Lark",
379
- "botToken": "Slack",
380
- "appToken": "Slack",
381
- "clientId": "optional",
382
- "clientSecret": "optional"
383
- },
384
- "model": "optional Model.id or modelId::scope",
385
- "systemPrompt": "optional"
386
- }
387
- ```
388
-
389
- Update accepts a partial object with `name`, `config`, `model`, `systemPrompt`, `enabled`, or `unbindUsers`. Channel type is immutable after creation. Dry-run replaces secret values with `***`.
390
-
391
389
  ## Permission Errors
392
390
 
393
391
  A permission response looks like:
@@ -412,9 +410,9 @@ An authenticated `root` or `agent_admin` is still scoped to their own company. T
412
410
 
413
411
  ## Transport Status
414
412
 
415
- This is a Transitional L2 domain backed by te-agent `/api/admin/**`.
413
+ This is a Transitional domain backed by te-agent `/api/admin/**` and `/api/cli/channel/v1/**`.
416
414
 
417
- - Maintainer: te-agent admin routes and `src/commands/te-system/**`.
418
- - Migration target: system Capability Gateway.
415
+ - Maintainer: te-agent admin/channel-management routes and `src/commands/te-system/**`.
416
+ - Migration target: system and channel Capability Gateways.
419
417
  - Review date: 2026-10-24.
420
418
  - Exit condition: migrate after equivalent gateway schema, auth, risk, dry-run, and output contracts are stable.
@@ -0,0 +1,303 @@
1
+ # Channel Management
2
+
3
+ Use this workflow for channel configuration, group routing, WhatsApp Web linking, and Feishu user bindings. All channel endpoints require an authenticated `root` or `agent_admin` and enforce company isolation.
4
+
5
+ ## Scope
6
+
7
+ Channel configuration supports `feishu`, `lark`, `slack`, `discord`, `dingtalk`, `wecom`, `mattermost`, `google_chat`, and `whatsapp`. Administrator-driven user binding is available only for `feishu`.
8
+
9
+ The default Feishu binding is group-routing ready. It requires a verified `endpoint_id` for the channel and a `union_id` for every user. Use `--private-only` only after the user explicitly accepts private-chat-only behavior; never downgrade silently when either value is unavailable.
10
+
11
+ ## Two Confirmation Phases
12
+
13
+ Treat channel configuration and personnel binding as separate writes:
14
+
15
+ 1. **Channel configuration phase**: discover current state, prepare channel configuration and routing, run every applicable `ae-cli ... --dry-run`, show the redacted target/effect, and obtain one explicit confirmation before executing this phase.
16
+ 2. **Personnel binding phase**: resolve the final roster and IDs, inspect each person's sandbox readiness, validate the complete binding batch and every required sandbox write with `--dry-run`, show counts, endpoint, private-only state, Agent assignments, sandbox creates, and sandbox enables, then obtain explicit confirmation before each planned write set. A roster containing only existing Agent members needs one final binding-and-sandbox confirmation.
17
+
18
+ A confirmation for phase 1 does not authorize phase 2. A confirmation for one roster does not authorize a changed roster.
19
+
20
+ ## Phase 1: Configure a Channel
21
+
22
+ Start from current state:
23
+
24
+ ```bash
25
+ ae-cli system +list-channels
26
+ ae-cli system channel get --id <channel-id>
27
+ ```
28
+
29
+ Create JSON uses snake_case. The original `+create-channel` and `+update-channel` commands also accept legacy camelCase fields, but new files should not use them.
30
+
31
+ ```json
32
+ {
33
+ "name": "Support Bot",
34
+ "type": "feishu",
35
+ "config": {
36
+ "app_id": "<app-id>",
37
+ "app_secret": "<app-secret>"
38
+ },
39
+ "model": "<optional-model-id>",
40
+ "system_prompt": "<optional-system-prompt>",
41
+ "enabled": false
42
+ }
43
+ ```
44
+
45
+ Run the dry-run before the phase-1 confirmation. Credential values are replaced with `***`:
46
+
47
+ ```bash
48
+ ae-cli --dry-run system +create-channel --channel @channel.json
49
+ ae-cli system +create-channel --channel @channel.json
50
+ ```
51
+
52
+ Type-specific configuration:
53
+
54
+ | Type | Required config | Conditional config |
55
+ | --- | --- | --- |
56
+ | `feishu`, `lark` | `app_id`, `app_secret` | — |
57
+ | `slack` | `bot_token`, `app_token` | `client_id`, `client_secret` when used by the deployment |
58
+ | `discord` | `bot_token` | `client_id`, `client_secret` when used by the deployment |
59
+ | `dingtalk` | `client_id`, `client_secret`, `corp_id` | `interaction_card_template_id` |
60
+ | `wecom` | `bot_id`, `bot_secret` | If `oauth_enabled=true`: `corp_id`, `corp_secret`, `agent_id` |
61
+ | `mattermost` | `server_url`, `bot_token` | If `oauth_enabled=true`: `client_id`, `client_secret` |
62
+ | `google_chat` | `service_account_json` | `workspace_addon_service_account_email`; if `oauth_enabled=true`: `client_id`, `client_secret` |
63
+ | `whatsapp` | no manual config | Credentials are created by the QR lifecycle |
64
+
65
+ Update accepts a partial object containing `name`, `type`, `config`, `model`, `system_prompt`, `enabled`, or `unbind_users`. If `type` is present it must equal the channel's existing type. Omitting a secret or passing an empty string preserves the stored value; it does not clear the secret.
66
+
67
+ For every non-WhatsApp channel, verify credentials before depending on endpoints:
68
+
69
+ ```bash
70
+ ae-cli --dry-run system channel verify --id <channel-id>
71
+ ae-cli system channel verify --id <channel-id>
72
+ ae-cli system channel get --id <channel-id>
73
+ ```
74
+
75
+ Treat configuration persistence and runtime startup as separate outcomes. An HTTP 200 may still contain `runtime_status="error"`; report that the configuration was saved without claiming the bot is online. When Google Chat creation returns its one-time `webhook_url`, ask the operator to save it immediately in an approved secret store and never copy it into logs or repository files.
76
+
77
+ For WhatsApp, create the channel without config, enable it with `+update-channel`, then start linking. Poll only until the returned `expires_at` (and never longer than two minutes) for `linked`, `needs_relink`, `failed`, or `expired`:
78
+
79
+ ```bash
80
+ ae-cli --dry-run system +update-channel --id <channel-id> --channel '{"enabled":true}'
81
+ ae-cli system +update-channel --id <channel-id> --channel '{"enabled":true}'
82
+ ae-cli --dry-run system channel whatsapp-web start --id <channel-id>
83
+ ae-cli system channel whatsapp-web start --id <channel-id>
84
+ ae-cli system channel whatsapp-web status --id <channel-id>
85
+ ```
86
+
87
+ Show `qr_data_url` to the user for scanning. Do not call `channel verify` for WhatsApp. Before unlinking, disable the channel with `+update-channel`, then call `channel whatsapp-web unlink`; the unlink command requires its own high-risk CLI confirmation and still stays inside phase 1.
88
+
89
+ ```bash
90
+ ae-cli --dry-run system +update-channel --id <channel-id> --channel '{"enabled":false}'
91
+ ae-cli system +update-channel --id <channel-id> --channel '{"enabled":false}'
92
+ ae-cli --dry-run system channel whatsapp-web unlink --id <channel-id>
93
+ ae-cli system channel whatsapp-web unlink --id <channel-id>
94
+ ```
95
+
96
+ ## Group Routing
97
+
98
+ Use a verified endpoint ID from `channel verify` or `channel get`:
99
+
100
+ ```bash
101
+ ae-cli system channel routing get --endpoint-id <endpoint-id>
102
+ ae-cli --dry-run system channel routing set \
103
+ --endpoint-id <endpoint-id> \
104
+ --routing @routing.json
105
+ ```
106
+
107
+ `routing.json` replaces the full routing configuration:
108
+
109
+ ```json
110
+ {
111
+ "status": "enabled",
112
+ "default_handler": { "kind": "agent", "id": "<agent-id>" },
113
+ "targets": [
114
+ {
115
+ "handler_kind": "team",
116
+ "handler_id": "<team-id>",
117
+ "slug": "billing",
118
+ "keywords": ["invoice", "refund"],
119
+ "sort_order": 10,
120
+ "enabled": true
121
+ }
122
+ ]
123
+ }
124
+ ```
125
+
126
+ `status` is `enabled | disabled`, `default_handler` is an Agent/Team handler or `null`, and `targets` contains at most 19 entries. The server validates handler ownership, duplicate handlers/slugs, and keyword conflicts.
127
+
128
+ ## Phase 2: Resolve and Bind Feishu Users
129
+
130
+ ### Feishu binding transport contract
131
+
132
+ Both the single-user and batch CLI flows use the same binding endpoint:
133
+
134
+ | Operation | Method and path | CLI mapping |
135
+ | --- | --- | --- |
136
+ | Bind one Feishu identity to one channel | PUT `/api/cli/channel/v1/bindings/feishu` | `channel binding bind-feishu` sends one request. |
137
+ | Bind 1-100 Feishu identities to one channel | PUT `/api/cli/channel/v1/bindings/feishu` | `+bind-feishu-users` validates the full roster, then sends one binding PUT per person. |
138
+ | Set the private-chat default Agent after binding | PUT `/api/cli/channel/v1/bindings/{binding_id}/agent` | `channel binding set-agent`; the batch command calls it after each successful binding when an Agent is selected. |
139
+
140
+ The Feishu binding request body is a strict, flat JSON object:
141
+
142
+ | Field | Required | Binding meaning |
143
+ | --- | --- | --- |
144
+ | `channel_id` | yes | `channel_id` identifies the one target Feishu channel for the request. The channel must belong to the current company and be enabled. |
145
+ | `te_user_id` | yes | The selected AE Agent member's `openId`; this is the member being associated with the channel identity. |
146
+ | `open_id` | yes | The person's Feishu `open_id` under the same Feishu application configured by the target channel. |
147
+ | `union_id` | group-ready only | The person's stable Feishu identity for group routing. Supply it together with `endpoint_id`; omit both only for explicitly approved private-chat-only binding. |
148
+ | `endpoint_id` | group-ready only | `endpoint_id` must identify a verified endpoint that belongs to the same `channel_id`. Supply it together with `union_id`. |
149
+
150
+ ```json
151
+ {
152
+ "channel_id": "channel-sales",
153
+ "te_user_id": "agent-member-open-id-alice",
154
+ "open_id": "ou_alice",
155
+ "union_id": "on_alice",
156
+ "endpoint_id": "endpoint-sales-verified"
157
+ }
158
+ ```
159
+
160
+ The binding response returns:
161
+
162
+ | Field | Meaning |
163
+ | --- | --- |
164
+ | `binding_id` | The channel-user binding ID used for later Agent assignment or maintenance. |
165
+ | `channel_id` | The target channel confirmed by the server. |
166
+ | `te_user_id` | The AE Agent member associated with the channel identity. |
167
+ | `open_id` | The Feishu application-scoped identity stored on the binding. |
168
+ | `group_routing_ready` | Whether this binding is ready for group routing. |
169
+ | `agent_id` | The current private-chat default Agent, or no value when system-default resolution applies. |
170
+ | `endpoint_id` | The associated endpoint when the binding is group-routing ready. |
171
+
172
+ `agent_id` is not part of this request body. After the binding response returns `binding_id`, set or clear the private-chat default Agent through `PUT /api/cli/channel/v1/bindings/{binding_id}/agent`. `default_agent_id` and `private_only` are also CLI orchestration fields, not fields accepted by the Feishu binding endpoint.
173
+
174
+ One `+bind-feishu-users` invocation has one top-level `--channel-id` and one shared `--endpoint-id`; every entry in `bindings.json` is bound to that channel. Run separate confirmed batches for different channels. Do not put `channel_id` or `endpoint_id` inside individual roster entries.
175
+
176
+ Common contract mistakes:
177
+
178
+ | Mistake | Required correction |
179
+ | --- | --- |
180
+ | Reusing an `open_id` resolved under another Feishu application | Resolve the person again with the application configured by the target channel. |
181
+ | Pairing the target channel with an endpoint from another channel | Select a verified endpoint returned by `channel get` or `channel verify` for the same `channel_id`. |
182
+ | Sending `agent_id`, `default_agent_id`, or `private_only` to the Feishu binding endpoint | Keep them in CLI orchestration; assign the Agent through the binding-specific Agent endpoint. |
183
+ | Mixing users for multiple channels in one batch roster | Split the work by channel, dry-run every final roster, and confirm each batch separately. |
184
+
185
+ 1. The current session must have the Feishu OpenAPI MCP mounted. Before resolving identities, verify all of these prerequisites:
186
+
187
+ - The MCP and the target channel use the same App ID and App Secret. Read the channel's `config.app_id` with `ae-cli system channel get --id <channel-id>` and compare it with the MCP application configuration. When the App Secret or MCP configuration is masked, obtain explicit confirmation from the configuration owner instead of assuming a match. Feishu `open_id` is application-scoped.
188
+ - The Feishu application has the `contact:user.id:readonly` permission.
189
+ - The MCP exposes the `contact.v3.users.batchGetId` tool.
190
+
191
+ Stop when any prerequisite is missing or cannot be verified. Resolve people by exact corporate email address or mobile number; `contact.v3.users.batchGetId` does not resolve names, so ask for an email address or mobile number when only a name is provided.
192
+
193
+ 2. Call `contact.v3.users.batchGetId` with `user_id_type=open_id`. Put exact emails in `data.emails` or exact mobile numbers in `data.mobiles`:
194
+
195
+ ```json
196
+ {
197
+ "params": { "user_id_type": "open_id" },
198
+ "data": { "emails": ["alice@example.com", "bob@example.com"] }
199
+ }
200
+ ```
201
+
202
+ Map each returned `user_list[].user_id` to the matching returned email or mobile number as that person's Feishu `open_id`. A zero-result lookup, missing input, duplicate input, or response that cannot be mapped one-to-one is unresolved. Stop, show the unresolved inputs, and obtain corrected exact identifiers; never choose the first result or infer a person from ordering.
203
+
204
+ 3. Repeat `contact.v3.users.batchGetId` for the same exact emails or mobile numbers with `user_id_type=union_id`; reuse the corresponding `data.emails` or `data.mobiles` roster from step 2 unchanged.
205
+
206
+ Map each returned `user_list[].user_id` to the same person as that person's Feishu `union_id`. Require the `open_id` and `union_id` lookup results to cover the same uniquely identified roster. If the Feishu OpenAPI MCP cannot return a `union_id`, stop. Ask whether the user explicitly accepts `--private-only`; do not infer that choice.
207
+
208
+ 4. Fetch Agent members and match each selected person to exactly one Agent member by confirmed login/display identity. Use that member's `openId` as `te_user_id`; do not use its database `userId`, and do not assume the app-scoped Feishu `open_id` equals the AE member `openId`:
209
+
210
+ ```bash
211
+ ae-cli system +list-members --status enabled --all true
212
+ ```
213
+
214
+ If a selected person is not yet an Agent member, use `+list-member-candidates` to resolve the exact candidate. When member addition is required, phase 2 has a prerequisite member-add confirmation and a final binding-and-sandbox confirmation. Dry-run and confirm `+add-members`, execute it, then refetch members before preparing the final binding and sandbox plan. Keep `--create-sandbox` false or omit it in this workflow; sandbox creation and verification happen explicitly after a successful channel binding. The member-add confirmation does not authorize the later binding or sandbox writes.
215
+ 5. Build `bindings.json` using only snake_case:
216
+
217
+ ```json
218
+ [
219
+ {
220
+ "te_user_id": "<agent-member-open-id>",
221
+ "open_id": "<feishu-open-id>",
222
+ "union_id": "<feishu-union-id>",
223
+ "agent_id": "<optional-per-user-agent-id>"
224
+ }
225
+ ]
226
+ ```
227
+
228
+ `--default-agent-id` applies when an item omits `agent_id`; an item's `agent_id` overrides the default. Omit both to leave the private-chat default Agent unchanged.
229
+
230
+ 6. Inspect sandbox capacity and current ownership before building the phase-2 plan:
231
+
232
+ ```bash
233
+ ae-cli system +get-sandbox-config
234
+ ae-cli system +list-sandboxes
235
+ ```
236
+
237
+ For sandbox operations, map each selected Agent member's database `userId` to `items[].boundUsers[].userId`; never use the member's `openId`, Feishu `open_id`, or Feishu `union_id`. A channel-bound person's sandbox is ready when exactly one returned sandbox contains that `userId` and has `enabled === true`. Container `runningState` is a separate lifecycle state and does not trigger `+start-sandbox` in this workflow.
238
+
239
+ - For members with no sandbox, prepare one dry-run containing their database user IDs:
240
+
241
+ ```bash
242
+ ae-cli --dry-run system +batch-create-sandboxes \
243
+ --user-ids '["<member-database-user-id>"]'
244
+ ```
245
+
246
+ - For each existing sandbox with `enabled === false`, prepare its enable dry-run:
247
+
248
+ ```bash
249
+ ae-cli --dry-run system +set-sandbox-enabled \
250
+ --id <sandbox-id> \
251
+ --enabled true
252
+ ```
253
+
254
+ Calculate the planned quota use from `+get-sandbox-config`: required create seats equal the number of members with no sandbox, and required active seats equal that number plus the number of existing disabled sandboxes to enable. Require `sandboxQuota.cluster.remaining` to cover required create seats and `sandboxQuota.active.remaining` to cover required active seats. Treat a missing or non-numeric quota value as unverified rather than assuming capacity; `sandboxActiveSeatsLimit` is the limit, not the remaining count.
255
+
256
+ Sandbox preflight protects sandbox writes without becoming a gate on channel binding. When sandbox management is disabled, verified capacity cannot cover the plan, quota values are unverified, a person maps to multiple sandboxes, or ownership cannot be matched exactly, mark the affected person as `sandbox_readiness_blocked` and show the reason in the phase-2 plan. Require confirmation that the channel binding may succeed while the sandbox remains not ready, and do not issue an unsafe sandbox write. A sandbox preflight failure does not cancel a confirmed channel binding.
257
+
258
+ The phase-2 confirmation also authorizes the listed sandbox readiness writes. If the roster, target user IDs, sandbox IDs, required actions, or limits change, regenerate every affected dry-run and obtain a new confirmation.
259
+
260
+ 7. Validate the whole 1-100 item binding batch and show the complete phase-2 plan before asking for confirmation:
261
+
262
+ ```bash
263
+ ae-cli --dry-run system +bind-feishu-users \
264
+ --channel-id <channel-id> \
265
+ --endpoint-id <verified-endpoint-id> \
266
+ --bindings @bindings.json \
267
+ --default-agent-id <optional-agent-id>
268
+ ```
269
+
270
+ For an explicitly approved private-chat-only batch, omit every `union_id` and `--endpoint-id`, then add `--private-only true`.
271
+
272
+ 8. After phase-2 confirmation, execute the same binding command without `--dry-run`. The command validates the whole batch before the first request, then processes users sequentially. An item-level validation or conflict failure does not stop later users and no automatic rollback is attempted; a final 401 or any 403 stops the batch because authentication or authorization is no longer valid. Inspect `succeeded`, `failed`, and every result's `stage` (`binding` or `agent_assignment`). Retry only failed items with a new file; the Feishu binding PUT is idempotent.
273
+
274
+ 9. Only users whose channel binding succeeded proceed to sandbox readiness. A result with `binding_id` and `stage: "agent_assignment"` still proceeds to sandbox readiness. The channel binding exists, so report the Agent-assignment failure separately. Refetch `+list-sandboxes` after binding, then apply the confirmed plan against the refreshed state:
275
+
276
+ - If preflight marked the person as `sandbox_readiness_blocked`, preserve the successful binding, report `channel_bound_sandbox_not_ready`, and wait for a new safe dry-run and confirmation before any later sandbox write.
277
+ - If the exact user's sandbox is already `enabled === true`, make no write.
278
+ - If the confirmed existing sandbox is still present with `enabled === false`, execute its prepared `+set-sandbox-enabled --enabled true` command.
279
+ - If the confirmed user still has no sandbox, execute the prepared `+batch-create-sandboxes` command. The create call must return a successful result and a `sandboxId` for that database `userId`.
280
+ - Refetch after creation. The batch-create contract creates an enabled personal sandbox and binds it to the requested database `userId`. If the new sandbox instead has `enabled === false`, run a fresh `+set-sandbox-enabled` dry-run and obtain supplemental explicit confirmation for the returned `sandboxId` before enabling it.
281
+ - If the refreshed ownership or sandbox ID conflicts with the confirmed plan, stop that person's sandbox action and request a new dry-run and confirmation.
282
+
283
+ Inspect every create or enable result. A final 401 or any 403 stops remaining sandbox writes. A quota, validation, conflict, or other item failure does not undo earlier bindings or prevent independent confirmed users from being processed. Record and report that person as `channel_bound_sandbox_not_ready`. Do not roll back a successful channel binding when sandbox preparation fails.
284
+
285
+ 10. Read back the final channel and sandbox state:
286
+
287
+ ```bash
288
+ ae-cli system channel binding list --channel-id <channel-id>
289
+ ae-cli system +list-sandboxes
290
+ ```
291
+
292
+ For every successful channel binding, verify that exactly one sandbox contains the Agent member's database `userId` in `boundUsers[].userId` and returns `enabled === true`. Report separate counts and identities for `channel_bound_sandbox_ready`, `channel_bound_sandbox_not_ready`, and `channel_binding_failed`; do not collapse partial readiness into overall success.
293
+
294
+ For one-off maintenance, use `channel binding bind-feishu`, `channel binding set-agent`, and `channel binding unbind` with the same dry-run, confirmation, and read-back rules. Clear a binding's private-chat Agent and restore system-default resolution with `channel binding set-agent --binding-id <binding-id> --clear`.
295
+
296
+ ## Transport Status
297
+
298
+ Transition status: transitional
299
+ Owning module: te-agent channel management
300
+ Current transport: signed REST at `/api/cli/channel/v1/**`
301
+ Gateway target: channel Capability Gateway
302
+ Review after: 2026-10-24
303
+ Exit condition: migrate when equivalent schemas, authorization, risk, dry-run, batch orchestration, and output contracts are stable.
@@ -1,14 +0,0 @@
1
- import {
2
- getToken,
3
- invalidateAccessTokenForRetry,
4
- resolveHost,
5
- validateToken
6
- } from "./chunk-ZZUOD757.js";
7
- import "./chunk-LYVNONC4.js";
8
- import "./chunk-QGM4M3NI.js";
9
- export {
10
- getToken,
11
- invalidateAccessTokenForRetry,
12
- resolveHost,
13
- validateToken
14
- };