@xdxer/dingtalk-agent 0.1.4-beta.8 → 0.1.4

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 (254) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/README.en.md +167 -0
  3. package/README.md +101 -248
  4. package/dist/bin/dingtalk-agent.js +1255 -25
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/actions.js +98 -14
  7. package/dist/src/actions.js.map +1 -1
  8. package/dist/src/agent-audit.js +1385 -0
  9. package/dist/src/agent-audit.js.map +1 -0
  10. package/dist/src/agent-bindings.js +132 -0
  11. package/dist/src/agent-bindings.js.map +1 -0
  12. package/dist/src/agent-definition.js +182 -0
  13. package/dist/src/agent-definition.js.map +1 -0
  14. package/dist/src/agent-enhance.js +711 -0
  15. package/dist/src/agent-enhance.js.map +1 -0
  16. package/dist/src/agent-platform.js +299 -0
  17. package/dist/src/agent-platform.js.map +1 -0
  18. package/dist/src/bootstrap.js +125 -17
  19. package/dist/src/bootstrap.js.map +1 -1
  20. package/dist/src/config.js +1 -7
  21. package/dist/src/config.js.map +1 -1
  22. package/dist/src/development-workspace.js +755 -0
  23. package/dist/src/development-workspace.js.map +1 -0
  24. package/dist/src/doctor.js +74 -15
  25. package/dist/src/doctor.js.map +1 -1
  26. package/dist/src/dws.js +145 -0
  27. package/dist/src/dws.js.map +1 -1
  28. package/dist/src/eval-evidence.js +193 -0
  29. package/dist/src/eval-evidence.js.map +1 -0
  30. package/dist/src/host-detect.js +146 -0
  31. package/dist/src/host-detect.js.map +1 -0
  32. package/dist/src/instruction-path.js +270 -0
  33. package/dist/src/instruction-path.js.map +1 -0
  34. package/dist/src/invocation.js +36 -0
  35. package/dist/src/invocation.js.map +1 -0
  36. package/dist/src/lab.js +679 -0
  37. package/dist/src/lab.js.map +1 -0
  38. package/dist/src/lease.js +100 -0
  39. package/dist/src/lease.js.map +1 -0
  40. package/dist/src/map.js +157 -0
  41. package/dist/src/map.js.map +1 -0
  42. package/dist/src/memory/candidates.js +451 -0
  43. package/dist/src/memory/candidates.js.map +1 -0
  44. package/dist/src/memory/completion-evidence.js +536 -0
  45. package/dist/src/memory/completion-evidence.js.map +1 -0
  46. package/dist/src/memory/operational.js +263 -0
  47. package/dist/src/memory/operational.js.map +1 -0
  48. package/dist/src/memory/remote-state.js +478 -0
  49. package/dist/src/memory/remote-state.js.map +1 -0
  50. package/dist/src/memory/task-checkpoints.js +204 -0
  51. package/dist/src/memory/task-checkpoints.js.map +1 -0
  52. package/dist/src/multica-deploy.js +1538 -0
  53. package/dist/src/multica-deploy.js.map +1 -0
  54. package/dist/src/multica-provider.js +685 -0
  55. package/dist/src/multica-provider.js.map +1 -0
  56. package/dist/src/opencode-evals.js +1547 -0
  57. package/dist/src/opencode-evals.js.map +1 -0
  58. package/dist/src/opencode-isolation.js +124 -0
  59. package/dist/src/opencode-isolation.js.map +1 -0
  60. package/dist/src/opencode-provider.js +532 -0
  61. package/dist/src/opencode-provider.js.map +1 -0
  62. package/dist/src/opencode-workspace.js +208 -0
  63. package/dist/src/opencode-workspace.js.map +1 -0
  64. package/dist/src/perception.js +225 -0
  65. package/dist/src/perception.js.map +1 -0
  66. package/dist/src/personal-event-evals.js +595 -0
  67. package/dist/src/personal-event-evals.js.map +1 -0
  68. package/dist/src/promotion.js +786 -0
  69. package/dist/src/promotion.js.map +1 -0
  70. package/dist/src/remote-semantic-state-live-evals.js +888 -0
  71. package/dist/src/remote-semantic-state-live-evals.js.map +1 -0
  72. package/dist/src/remote-semantic-state-worker.js +38 -0
  73. package/dist/src/remote-semantic-state-worker.js.map +1 -0
  74. package/dist/src/remote-state-evals.js +502 -0
  75. package/dist/src/remote-state-evals.js.map +1 -0
  76. package/dist/src/response-gate.js +51 -0
  77. package/dist/src/response-gate.js.map +1 -0
  78. package/dist/src/robot-evals.js +771 -0
  79. package/dist/src/robot-evals.js.map +1 -0
  80. package/dist/src/sessions.js +66 -105
  81. package/dist/src/sessions.js.map +1 -1
  82. package/dist/src/setup.js +6 -5
  83. package/dist/src/setup.js.map +1 -1
  84. package/dist/src/skill-manager.js +162 -24
  85. package/dist/src/skill-manager.js.map +1 -1
  86. package/dist/src/skills.js +2 -1
  87. package/dist/src/skills.js.map +1 -1
  88. package/dist/src/storage-evals.js +26 -0
  89. package/dist/src/storage-evals.js.map +1 -0
  90. package/dist/src/types.js.map +1 -1
  91. package/dist/src/upgrade.js +23 -27
  92. package/dist/src/upgrade.js.map +1 -1
  93. package/dist/src/version.js +73 -0
  94. package/dist/src/version.js.map +1 -0
  95. package/dist/src/waits.js +5 -1
  96. package/dist/src/waits.js.map +1 -1
  97. package/dist/src/workspace.js +28 -3
  98. package/dist/src/workspace.js.map +1 -1
  99. package/docs/INSTALLATION.md +50 -3
  100. package/docs/SECOND-AGENT-ACCEPTANCE.md +62 -0
  101. package/docs/architecture/agent-memory-topology.png +0 -0
  102. package/docs/architecture/agent-memory-topology.svg +132 -0
  103. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  104. package/docs/architecture/general-agent-kernel-topology.svg +149 -0
  105. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  106. package/docs/architecture/provider-bound-development-workspace.svg +141 -0
  107. package/docs/architecture/task-completion-gate.png +0 -0
  108. package/docs/architecture/task-completion-gate.svg +191 -0
  109. package/docs/assets/agent-delivery-lifecycle.svg +103 -0
  110. package/docs/schemas/agent-audit-load-evidence.schema.json +14 -0
  111. package/docs/schemas/agent-audit.schema.json +92 -0
  112. package/docs/schemas/agent-bindings.schema.json +54 -0
  113. package/docs/schemas/agent-definition.schema.json +78 -0
  114. package/docs/schemas/agent-enhancement-plan.schema.json +88 -0
  115. package/docs/schemas/agent-enhancement-receipt.schema.json +37 -0
  116. package/docs/schemas/agent-platform.schema.json +13 -0
  117. package/docs/schemas/enriched-invocation.schema.json +46 -0
  118. package/docs/schemas/eval-candidate-plan.schema.json +28 -0
  119. package/docs/schemas/eval-candidate-result.schema.json +20 -0
  120. package/docs/schemas/eval-candidate.schema.json +30 -0
  121. package/docs/schemas/invocation.schema.json +19 -0
  122. package/docs/schemas/memory-candidate-proposal.schema.json +18 -0
  123. package/docs/schemas/memory-candidate.schema.json +76 -0
  124. package/docs/schemas/memory-publish-target.schema.json +25 -0
  125. package/docs/schemas/multica-deployment-list.schema.json +29 -0
  126. package/docs/schemas/multica-deployment-operation.schema.json +51 -0
  127. package/docs/schemas/multica-deployment-plan.schema.json +70 -0
  128. package/docs/schemas/multica-deployment-receipt.schema.json +87 -0
  129. package/docs/schemas/multica-deployment-status.schema.json +23 -0
  130. package/docs/schemas/multica-workspace-inspection.schema.json +77 -0
  131. package/docs/schemas/multica-workspace-plan.schema.json +68 -0
  132. package/docs/schemas/multica-workspace-resource-list.schema.json +27 -0
  133. package/docs/schemas/multica-workspace-status.schema.json +34 -0
  134. package/docs/schemas/observation.schema.json +21 -0
  135. package/docs/schemas/operational-memory-provider.schema.json +36 -0
  136. package/docs/schemas/operational-memory-record.schema.json +24 -0
  137. package/docs/schemas/perception-input.schema.json +56 -0
  138. package/docs/schemas/project.schema.json +115 -0
  139. package/docs/schemas/promotion-list.schema.json +36 -0
  140. package/docs/schemas/promotion-plan.schema.json +60 -0
  141. package/docs/schemas/promotion-policy.schema.json +29 -0
  142. package/docs/schemas/promotion-receipt.schema.json +43 -0
  143. package/docs/schemas/promotion-status.schema.json +23 -0
  144. package/docs/schemas/release-readiness.schema.json +66 -0
  145. package/docs/schemas/remote-semantic-state-live-eval.schema.json +60 -0
  146. package/docs/schemas/remote-semantic-state-manifest.schema.json +79 -0
  147. package/docs/schemas/remote-semantic-state-provider.schema.json +98 -0
  148. package/docs/schemas/response-gate.schema.json +20 -0
  149. package/docs/schemas/task-checkpoint.schema.json +71 -0
  150. package/docs/schemas/task-completion-evidence.schema.json +154 -0
  151. package/docs/schemas/workspace-doctor.schema.json +56 -0
  152. package/docs/schemas/workspace-state.schema.json +39 -0
  153. package/evals/README.md +17 -0
  154. package/evals/baselines/2026-07-16/opencode-basic-010-completion-summary.json +123 -0
  155. package/evals/baselines/2026-07-16/opencode-basic-skill-required-summary.json +69 -0
  156. package/evals/baselines/2026-07-16/opencode-multi-surface-summary.json +63 -0
  157. package/evals/baselines/2026-07-16/remote-state-live-summary.json +70 -0
  158. package/evals/baselines/2026-07-17/agent-enhance-opencode-dogfood-summary.json +98 -0
  159. package/evals/baselines/2026-07-17/personal-event-live-readiness-summary.json +68 -0
  160. package/examples/agents/fde-coach/AGENTS.md +26 -0
  161. package/examples/agents/fde-coach/MEMORY.md +3 -0
  162. package/examples/agents/fde-coach/fields/default/field.json +24 -0
  163. package/examples/agents/fde-coach/knowledge/INDEX.md +4 -0
  164. package/examples/agents/fde-coach/skills/fde-coach/SKILL.md +13 -0
  165. package/examples/agents/release-manager/AGENTS.md +26 -0
  166. package/examples/agents/release-manager/MEMORY.md +3 -0
  167. package/examples/agents/release-manager/fields/default/field.json +24 -0
  168. package/examples/agents/release-manager/knowledge/INDEX.md +4 -0
  169. package/examples/agents/release-manager/skills/release-manager/SKILL.md +13 -0
  170. package/lab/README.md +109 -0
  171. package/lab/agent-eval/catalog.json +91 -0
  172. package/lab/agent-eval/classic-failures.json +177 -0
  173. package/lab/agent-eval/completion-gate-regression.json +99 -0
  174. package/lab/agent-eval/personal-event-live.example.json +94 -0
  175. package/lab/agent-eval/remote-semantic-state-live.example.json +70 -0
  176. package/lab/agent-eval/remote-semantic-state-provider.fixture.json +47 -0
  177. package/lab/agent-eval/remote-state-workspace/AGENTS.md +8 -0
  178. package/lab/agent-eval/remote-state-workspace/opencode.json +7 -0
  179. package/lab/agent-eval/remote-state-workspace/skills/remote-state-operator/SKILL.md +13 -0
  180. package/lab/agent-eval/remote-state.example.json +31 -0
  181. package/lab/agent-eval/workspace/AGENTS.md +7 -0
  182. package/lab/agent-eval/workspace/MEMORY.md +4 -0
  183. package/lab/agent-eval/workspace/artifacts/pending-review.md +3 -0
  184. package/lab/agent-eval/workspace/knowledge/INDEX.md +4 -0
  185. package/lab/agent-eval/workspace/opencode.json +20 -0
  186. package/lab/manifest.example.json +27 -0
  187. package/lab/manifest.personal-event.example.json +27 -0
  188. package/lab/project-workspace/README.md +11 -0
  189. package/lab/project-workspace/fake-multica-provider.mjs +277 -0
  190. package/lab/project-workspace/multica-deploy.fixture.json +29 -0
  191. package/lab/project-workspace/multica-readonly.fixture.json +69 -0
  192. package/lab/project-workspace/observation.fixture.json +14 -0
  193. package/lab/project-workspace/opencode-provider-suite.json +65 -0
  194. package/lab/project-workspace/project.fixture.json +44 -0
  195. package/lab/project-workspace/promotion-policy.fixture.json +15 -0
  196. package/lab/robot-eval/pool.example.json +30 -0
  197. package/lab/robot-eval/suite.json +123 -0
  198. package/lab/robot-eval/workspace/AGENTS.md +21 -0
  199. package/lab/robot-eval/workspace/MEMORY.md +3 -0
  200. package/lab/robot-eval/workspace/knowledge/INDEX.md +5 -0
  201. package/lab/robot-eval/workspace/opencode.json +22 -0
  202. package/lab/schemas/agent-eval-catalog.schema.json +47 -0
  203. package/lab/schemas/lab-manifest.schema.json +70 -0
  204. package/lab/schemas/personal-event-eval.schema.json +91 -0
  205. package/lab/schemas/remote-state-eval.schema.json +66 -0
  206. package/lab/schemas/robot-eval-suite.schema.json +184 -0
  207. package/lab/schemas/robot-pool.schema.json +56 -0
  208. package/package.json +28 -9
  209. package/skills/README.md +23 -0
  210. package/skills/core/dingtalk-agent-compose/SKILL.md +151 -0
  211. package/skills/core/dingtalk-agent-compose/assets/AGENTS.template.md +35 -0
  212. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +13 -0
  213. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.local.template.json +13 -0
  214. package/skills/core/dingtalk-agent-compose/assets/hosts/opencode/opencode.template.json +12 -0
  215. package/skills/core/dingtalk-agent-compose/assets/role-skill.template.md +32 -0
  216. package/skills/core/dingtalk-agent-compose/evals/evals.json +129 -0
  217. package/skills/core/dingtalk-agent-compose/references/agent-definition-contract.md +55 -0
  218. package/skills/core/dingtalk-agent-compose/references/host-loading-contract.md +58 -0
  219. package/skills/core/dingtalk-agent-compose/references/hosts/claude-code.md +48 -0
  220. package/skills/core/dingtalk-agent-compose/references/hosts/opencode.md +77 -0
  221. package/skills/core/dingtalk-agent-compose/references/storage-routing.md +20 -0
  222. package/skills/core/dingtalk-agent-eval/SKILL.md +140 -0
  223. package/skills/core/dingtalk-agent-eval/assets/eval-catalog.template.json +18 -0
  224. package/skills/core/dingtalk-agent-eval/evals/evals.json +83 -0
  225. package/skills/core/dingtalk-agent-eval/references/eval-topology.md +48 -0
  226. package/skills/core/dingtalk-agent-eval/references/evidence-contract.md +52 -0
  227. package/skills/core/dingtalk-agent-eval/references/failure-to-case.md +35 -0
  228. package/skills/core/dingtalk-agent-eval/references/interactive-debug-channels.md +93 -0
  229. package/skills/core/dingtalk-agent-eval/references/local-connector-smoke.md +75 -0
  230. package/skills/core/dingtalk-agent-eval/references/scenario-taxonomy.md +25 -0
  231. package/skills/core/dingtalk-agent-eval/references/storage-modes.md +75 -0
  232. package/skills/core/dingtalk-basic-behavior/SKILL.md +87 -0
  233. package/skills/core/dingtalk-basic-behavior/assets/memory-candidate-proposal.json +10 -0
  234. package/skills/{dingtalk-basic-behavior/assets/task-checkpoint.md → core/dingtalk-basic-behavior/assets/task-checkpoint.json} +2 -21
  235. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/action-contract.md +2 -0
  236. package/skills/core/dingtalk-basic-behavior/references/memory-and-evolution.md +53 -0
  237. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +28 -0
  238. package/skills/core/dingtalk-basic-behavior/references/risk-authority-and-privacy.md +62 -0
  239. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/task-lifecycle.md +47 -10
  240. package/skills/core/dingtalk-basic-behavior/references/truth-and-recovery.md +65 -0
  241. package/skills/platforms/deap/PLATFORM.md +3 -0
  242. package/skills/platforms/deap/README.md +3 -0
  243. package/skills/platforms/multica-dingtalk/PLATFORM.md +40 -0
  244. package/skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica/SKILL.md +40 -0
  245. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/SKILL.md +60 -0
  246. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/multica-deployment-contract.md +49 -0
  247. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/promotion-observation-contract.md +49 -0
  248. package/skills/platforms/multica-dingtalk/multica-external/SKILL.md +282 -0
  249. package/skills/platforms/multica-dingtalk/multica-external/scripts/bootstrap.sh +78 -0
  250. package/skills/platforms/multica-dingtalk/multica-external/scripts/multica_ext.py +1180 -0
  251. package/skills/dingtalk-basic-behavior/SKILL.md +0 -86
  252. package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +0 -27
  253. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/event-to-behavior.md +0 -0
  254. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/runtime-modes.md +0 -0
@@ -0,0 +1,282 @@
1
+ ---
2
+ name: multica-external
3
+ description: External Python wrapper defining the full developer chain for delivering an agent on the Multica (DingTalk-FDE fork) platform — workspace bootstrap, runtime/agent provisioning, skill assembly (push/pull), DingTalk robot & account binding, execution-trace observability, cron scheduling (autopilot), and health checks. Use when provisioning, operating, debugging, or observing a Multica-managed agent from the command line with only an endpoint and a token.
4
+ metadata:
5
+ version: "0.1.0"
6
+ ---
7
+
8
+ # Multica FDE External Skill
9
+
10
+ This skill is the **Multica adapter** of the Managed Agent Platform developer
11
+ chain: everything a developer needs to take an agent from nothing to a
12
+ customer-facing DingTalk bot, then observe, schedule, and health-check it.
13
+ Multica may be only one of several managed platforms; this skill defines
14
+ exactly which capabilities the Multica backend provides and wraps each one as
15
+ a script command. An external orchestrator can fetch this skill (see
16
+ *Skill logistics*) and execute its scripts.
17
+
18
+ Deliberately **decoupled from the Go CLI**: nothing patches `multica`;
19
+ everything is plain HTTPS against the server. Only two inputs are needed —
20
+ **server URL** and **token** — both reusable from the CLI's stored config.
21
+
22
+ - Script: `scripts/multica_ext.py` — single file, stdlib only, Python >= 3.9.
23
+ - Proxy-immune: the script ignores `HTTP(S)_PROXY` env vars by design (unlike
24
+ curl or the Go CLI), so an exported shell proxy cannot break pre/intranet
25
+ endpoints.
26
+ - All commands print JSON to stdout (status notes on stderr) — pipe to `jq`.
27
+ - Global flags may appear before or after the command.
28
+
29
+ ## Credentials
30
+
31
+ Resolution order (first hit wins):
32
+
33
+ 1. Flags: `--server-url`, `--token`, `--workspace <slug|uuid>`
34
+ 2. Env: `MULTICA_SERVER_URL`, `MULTICA_TOKEN`, `MULTICA_WORKSPACE_ID`
35
+ 3. `--profile <name>` → `~/.multica/profiles/<name>/config.json`
36
+ 4. `~/.multica/config.json` (keys: `server_url`, `workspace_id`, `token`)
37
+
38
+ The token is a `mul_` personal access token or login JWT; mint PATs with
39
+ `POST /api/tokens`.
40
+
41
+ ```bash
42
+ PY=".agents/skills/multica-external/scripts/multica_ext.py"
43
+ python3 $PY --help
44
+ python3 $PY whoami --profile pre-fde
45
+ ```
46
+
47
+ ## The developer chain
48
+
49
+ ### 1 — Provision: workspace, runtime, agent
50
+
51
+ ```bash
52
+ python3 $PY workspace-init --profile pre-fde --name "FDE 团队" --slug fde-team \
53
+ --repo https://code.example.com/org/repo.git --complete-onboarding
54
+ python3 $PY runtime-create-fc --workspace fde-team --template-id <id> # cloud FC-E2B runtime
55
+ python3 $PY agent-create --workspace fde-team --name "FDE 教练" \
56
+ --instructions "..." --model claude-sonnet-5 # sole runtime auto-picked
57
+ ```
58
+
59
+ `workspace-init` is idempotent (409 → reuse when you are a member); repos
60
+ merge, never clobber; repo registration needs owner/admin. Slugs:
61
+ `^[a-z0-9]+(-[a-z0-9]+)*$`, reserved list enforced. An agent needs a runtime:
62
+ FC-E2B cloud (`runtime-create-fc`, requires server-side FC-E2B enablement) or
63
+ a local daemon. `runtime-templates` lists templates; when `--template-id` is
64
+ omitted and exactly one exists it is auto-picked.
65
+
66
+ ### 2 — Define & assemble: where the agent comes from, what skills it has
67
+
68
+ - `agent-source --agent <uuid>` — which git repo backs the agent (the
69
+ per-agent `agent_sources` link: `github` or `managed_git`; `null` = not
70
+ git-backed). `agent-source-sync` re-syncs github-sourced agents
71
+ (`managed_git` refuses with 409 by design — updated by the platform).
72
+ - Skills: `skill-list`, `skill-get`, `skill-push --dir <path>`
73
+ (local directory → workspace, `--on-conflict overwrite` replaces content
74
+ AND files wholesale), `skill-pull --skill <id-or-name> --dest <dir>`
75
+ (workspace → local directory). Assign skills to an agent with the Go CLI
76
+ (`multica agent skills add`) or `PUT /api/agents/{id}/skills`.
77
+ - Gap to know: there is no API to bind an *arbitrary* git URL to an agent;
78
+ per-agent git links are created only by the GitHub publish flow or the
79
+ managed FDE provision flow. Workspace-level repos (`workspace-repos`) and
80
+ the two flows above are the supported paths.
81
+
82
+ ### 3 — Deliver: bind the agent to a customer-facing DingTalk bot
83
+
84
+ The binding is a **channel installation** (one robot app per agent), not a
85
+ Skill object. AppKey/AppSecret are `client_id`/`client_secret` on the wire;
86
+ the secret is encrypted at rest (`MULTICA_DINGTALK_SECRET_KEY`) and never
87
+ returned. Inbound messages use DingTalk Stream Mode — no public webhook
88
+ registration needed.
89
+
90
+ ```bash
91
+ # Self-service: inject an existing robot app's credentials (owner/admin)
92
+ python3 $PY dingtalk-bind --agent <uuid> --client-id <AppKey> --client-secret-stdin < secret.txt
93
+ # Or scan-to-create: DingTalk mints the app, server captures credentials
94
+ python3 $PY dingtalk-begin --agent <uuid> --wait
95
+ python3 $PY dingtalk-list ; python3 $PY dingtalk-revoke --installation <uuid>
96
+ # Personal-account binding family (dingtalk_account):
97
+ python3 $PY dingtalk-account-begin --agent <uuid> # prints QR URL
98
+ python3 $PY dingtalk-account-list ; python3 $PY dingtalk-account-unbind --installation <uuid>
99
+ ```
100
+
101
+ Bind and unbind always come in pairs: robot `dingtalk-bind`/`dingtalk-begin`
102
+ ↔ `dingtalk-revoke`; account `dingtalk-account-begin` ↔
103
+ `dingtalk-account-unbind`. `dingtalk-account-begin` returns the binding link
104
+ (`qr_code_url`) directly — hand it to the counterpart to scan; check the
105
+ result with `dingtalk-account-list` (`dws_identity` carries the bound
106
+ account's org/display name).
107
+
108
+ Server rules: one robot per agent; re-binding the same `client_id` **moves**
109
+ the installation; cross-workspace `client_id` reuse → 409. Error map for
110
+ `dingtalk-bind`: **502** "dingtalk credentials check failed" = wrong
111
+ AppKey/AppSecret; **409** = ownership/agent conflict; **404** = agent not in
112
+ this workspace; `configured: false` in `dingtalk-list` = server lacks the
113
+ secret key. Deletes are audit-kept (`status: revoked`).
114
+
115
+ ### 4 — Observe: the agent's working and reasoning process
116
+
117
+ The full step-by-step trace (reasoning text, every tool call with input JSON,
118
+ every tool result, errors) is **persisted forever** in `task_messages` and
119
+ retrievable by REST — no backend changes needed:
120
+
121
+ ```bash
122
+ python3 $PY agent-tasks --agent <uuid> # run history (status, error, failure_reason, kind)
123
+ python3 $PY task-trace --task <uuid> --text # full reasoning/tool trace, human-readable
124
+ python3 $PY task-trace --task <uuid> --follow --text # live: polls until the task ends
125
+ python3 $PY issue-tasks --issue FDE-1 # all runs for an issue (uuid or identifier)
126
+ python3 $PY issue-timeline --issue FDE-1 # comments + activity log merged (status changes, task_completed...)
127
+ python3 $PY issue-usage --issue FDE-1 # aggregated token usage
128
+ python3 $PY task-snapshot # workspace-wide: active tasks + each agent's latest outcome
129
+ ```
130
+
131
+ Chat surfaces are REST-pollable too (`/api/chat/sessions/...` — session
132
+ messages, `pending-task`); realtime push is WebSocket `/ws` only (no SSE),
133
+ but a poll-only client fully reconstructs any past run from `task-trace`.
134
+
135
+ ### 5 — Schedule: cron automations (autopilot)
136
+
137
+ ```bash
138
+ python3 $PY autopilot-create --title "每日巡检" --agent <uuid> \
139
+ --description "<the prompt for each run>" --cron "0 9 * * 1-5" --timezone Asia/Shanghai
140
+ python3 $PY autopilot-trigger --autopilot <uuid> # run once, now
141
+ python3 $PY autopilot-runs --autopilot <uuid> # history: status, linked issue/task
142
+ python3 $PY autopilot-set-status --autopilot <uuid> --status paused # pause / active
143
+ python3 $PY autopilot-list ; python3 $PY autopilot-get --autopilot <uuid>
144
+ ```
145
+
146
+ Cron is standard 5-field (no seconds, no `@daily`), IANA timezone (default
147
+ UTC in the API; this script defaults `Asia/Shanghai`). `create_issue` mode
148
+ creates an issue per run (title template supports `{{date}}`) and enqueues an
149
+ agent task; `run_only` enqueues a task with no issue. Runs are idempotent per
150
+ (trigger, planned time); missed fires collapse to the latest, >5 min late is
151
+ skipped. Webhook triggers also exist (`POST /api/autopilots/{id}/triggers`
152
+ with `kind: webhook`).
153
+
154
+ ### 6 — Check: doctor report
155
+
156
+ ```bash
157
+ python3 $PY agent-check --agent <uuid>
158
+ ```
159
+
160
+ Composite JSON report: agent status/archived, runtime health (online /
161
+ unstable = offline but seen <5 min ago / offline / missing), active tasks +
162
+ last outcome (with `failure_reason`), recent failure count, DingTalk robot +
163
+ account binding state, plus a `checks[]` verdict list; `healthy` = no `fail`
164
+ (warns don't fail the check).
165
+
166
+ ### 7 — Basics: issues, comments, chat, members, tokens
167
+
168
+ Everyday Multica operations so an orchestrator needs nothing but this script:
169
+
170
+ ```bash
171
+ python3 $PY issue-create --title "..." --assignee-agent <uuid> # assigning an agent triggers a run
172
+ python3 $PY issue-get --issue FDE-1 ; python3 $PY issue-list --open-only --assignee <uuid>
173
+ python3 $PY issue-update --issue FDE-1 --status done
174
+ python3 $PY comment-add --issue FDE-1 --content "..." # "/note " prefix suppresses agent triggering
175
+ python3 $PY comment-list --issue FDE-1 --recent 10
176
+ python3 $PY chat-send --agent <uuid> --content "你好" --wait # direct conversation — the no-DingTalk e2e test path
177
+ python3 $PY member-list ; python3 $PY member-invite --email a@b.c --role member
178
+ python3 $PY token-create --name ci-bot --expires-days 90 # plaintext token shown once
179
+ ```
180
+
181
+ `chat-send` creates a session when `--session` is omitted and with `--wait`
182
+ polls `pending-task` until the assistant reply lands — the fastest way to
183
+ smoke-test a freshly provisioned agent before binding any channel.
184
+
185
+ ## Skill logistics: how skills move (the three planes)
186
+
187
+ - **Up (local → workspace):** `skill-push --dir` (this script);
188
+ `multica skill import --url|--file` (URL / `.skill`/`.zip` archive);
189
+ or the runtime *local-skills* API — the daemon scans the machine's
190
+ home-level skill dirs (`~/.claude/skills`, `~/.codex/skills`, the
191
+ cross-tool universal root `~/.agents/skills`, Claude plugin roots, etc.;
192
+ a "skill" = a directory with `SKILL.md`) and the workspace can list and
193
+ import them (`POST /api/runtimes/{id}/local-skills[/import]`, owner-only
194
+ for import).
195
+ - **Store:** workspace DB (`content` = SKILL.md, `files[]` = supporting
196
+ files; `SKILL.md` is a reserved file path).
197
+ - **Down (workspace → local):** automatic — the daemon materializes assigned
198
+ skills into each task's exec env (per-provider dirs, e.g.
199
+ `.claude/skills`, ephemeral, task-scoped). Manual/persistent — the Go CLI
200
+ has **no** download command; `skill-pull` (this script) is the downlink:
201
+ it writes `SKILL.md` + files into a local directory, byte-identical to
202
+ what was pushed. An external orchestrator can therefore
203
+ `skill-pull --skill multica-external --dest <dir>` and execute the
204
+ scripts it receives.
205
+
206
+ ## Command → API map
207
+
208
+ | Command | API |
209
+ | --- | --- |
210
+ | `whoami` | `GET /api/me` |
211
+ | `workspace-list` / `workspace-create` / `workspace-init` | `GET`/`POST /api/workspaces` (+ `PUT /api/workspaces/{id}`, `POST /api/me/onboarding/complete`) |
212
+ | `workspace-repos` | `GET`/`PUT /api/workspaces/{id}` (`repos` JSONB) |
213
+ | `runtime-list` / `runtime-templates` / `runtime-create-fc` | `GET /api/runtimes`, `GET`/`POST /api/runtimes/fc-e2b(/templates)` |
214
+ | `agent-list` / `agent-get` / `agent-create` | `GET`/`POST /api/agents` |
215
+ | `agent-source` / `agent-source-sync` | `GET /api/agents/{id}/source`, `POST .../source/sync` |
216
+ | `agent-tasks` | `GET /api/agents/{id}/tasks` |
217
+ | `task-trace` | `GET /api/tasks/{taskId}/messages?since=` (+ `GET /api/agent-task-snapshot` for follow-stop) |
218
+ | `issue-tasks` / `issue-timeline` / `issue-usage` | `GET /api/issues/{id}/task-runs` / `/timeline` / `/usage` |
219
+ | `task-snapshot` | `GET /api/agent-task-snapshot` |
220
+ | `autopilot-*` | `GET`/`POST`/`PATCH /api/autopilots`, `POST .../trigger`, `GET .../runs`, `POST .../triggers` |
221
+ | `agent-check` | composite of agents/runtimes/snapshot/tasks/dingtalk endpoints |
222
+ | `dingtalk-bind` / `dingtalk-begin` | `POST /api/workspaces/{id}/dingtalk/install/manual` / `install/begin` + status poll |
223
+ | `dingtalk-list` / `dingtalk-revoke` | `GET`/`DELETE .../dingtalk/installations` |
224
+ | `dingtalk-account-*` | `POST`/`GET`/`DELETE .../dingtalk/account-bindings` |
225
+ | `skill-list` / `skill-get` / `skill-pull` / `skill-push` | `GET /api/skills(/{id})`, `POST /api/skills`, `PUT /api/skills/{id}` |
226
+ | `issue-create` / `issue-get` / `issue-list` / `issue-update` | `POST`/`GET`/`PUT /api/issues(/{id})` |
227
+ | `comment-add` / `comment-list` | `POST`/`GET /api/issues/{id}/comments` |
228
+ | `chat-send` | `POST /api/chat/sessions(/{id}/messages)` + `GET .../pending-task` + `GET .../messages` |
229
+ | `member-list` / `member-invite` | `GET`/`POST /api/workspaces/{id}/members` |
230
+ | `token-create` | `POST /api/tokens` |
231
+
232
+ Auth: `Authorization: Bearer <token>`; workspace-scoped generic routes use
233
+ the `X-Workspace-ID` header, `/api/workspaces/{id}/...` routes take the UUID
234
+ in the path. No cookies, no CSRF.
235
+
236
+ ## Distribution
237
+
238
+ This directory is self-contained (SKILL.md + scripts):
239
+
240
+ - Import into any Multica workspace: `multica skill import` from a URL or
241
+ `.skill`/`.zip` archive, or `skill-push` from this script. Files land in
242
+ agent envs without the exec bit — always invoke via
243
+ `python3 .../multica_ext.py` / `sh .../bootstrap.sh`, never `./x`.
244
+ - Or vendor into a dedicated git repo later; nothing depends on this
245
+ monorepo.
246
+
247
+ ### Bootstrap: getting this skill onto a fresh machine
248
+
249
+ The workspace itself is the registry — no extra storage needed. `skill-pull`
250
+ lives inside the skill, so the first fetch uses `scripts/bootstrap.sh`
251
+ (copy it from a runbook, teammate, or this repo):
252
+
253
+ ```bash
254
+ # Path A — authenticated multica CLI (no pull command needed: skill get
255
+ # outputs everything; bootstrap just writes it to disk):
256
+ sh bootstrap.sh --profile pre-fde --workspace-id <uuid> [--dest <dir>]
257
+
258
+ # Path B — no CLI at all, just endpoint + token (+ curl, python3):
259
+ MULTICA_SERVER_URL=... MULTICA_TOKEN=... MULTICA_WORKSPACE_ID=... \
260
+ sh bootstrap.sh --curl [--dest <dir>]
261
+ ```
262
+
263
+ Both paths produce a byte-identical copy of what `skill-push` uploaded, and
264
+ bootstrap.sh ships inside the bundle, so a pulled copy can bootstrap the
265
+ next machine. After bootstrap, stay current with
266
+ `python3 scripts/multica_ext.py skill-pull --skill multica-external --dest . --force`.
267
+
268
+ Equivalent one-liner where bootstrap.sh is unavailable:
269
+
270
+ ```bash
271
+ multica skill get <skill-id> --output json | python3 -c '
272
+ import json,sys,pathlib
273
+ sk=json.load(sys.stdin); d=pathlib.Path(sk["name"]); d.mkdir(exist_ok=True)
274
+ (d/"SKILL.md").write_text(sk.get("content") or "")
275
+ for f in sk.get("files") or []:
276
+ p=d/f["path"]; p.parent.mkdir(parents=True,exist_ok=True); p.write_text(f.get("content") or "")'
277
+ ```
278
+
279
+ OSS (or any object store) is an optional *anonymous* channel — useful only
280
+ when the target machine has no Multica credentials yet. It needs a publish
281
+ step on every update and bucket/ACL management, so prefer the
282
+ workspace-as-registry paths above when a token exists.
@@ -0,0 +1,78 @@
1
+ #!/bin/sh
2
+ # Bootstrap: fetch the multica-external skill from a Multica workspace
3
+ # onto this machine. Solves the chicken-and-egg problem (skill-pull lives
4
+ # inside the skill) using only tools already present: the multica CLI, or
5
+ # curl with endpoint+token. python3 is required either way (the skill's
6
+ # script needs it too).
7
+ #
8
+ # Path A (default) — authenticated multica CLI:
9
+ # sh bootstrap.sh [--profile <name>] [--workspace-id <uuid>] [--dest <dir>]
10
+ # Path B — no CLI, just endpoint + token:
11
+ # MULTICA_SERVER_URL=... MULTICA_TOKEN=... MULTICA_WORKSPACE_ID=... \
12
+ # sh bootstrap.sh --curl [--dest <dir>]
13
+ #
14
+ # curl runs with --noproxy '*' so an exported shell proxy cannot break
15
+ # intranet/pre endpoints (the Go CLI needs proxies unset by the caller).
16
+ set -eu
17
+
18
+ SKILL_NAME="multica-external"
19
+ DEST=""
20
+ PROFILE=""
21
+ WS_ID=""
22
+ MODE="cli"
23
+
24
+ while [ $# -gt 0 ]; do
25
+ case "$1" in
26
+ --profile) PROFILE="$2"; shift 2 ;;
27
+ --workspace-id) WS_ID="$2"; shift 2 ;;
28
+ --dest) DEST="$2"; shift 2 ;;
29
+ --name) SKILL_NAME="$2"; shift 2 ;;
30
+ --curl) MODE="curl"; shift ;;
31
+ *) echo "unknown argument: $1" >&2; exit 1 ;;
32
+ esac
33
+ done
34
+
35
+ RESOLVE='
36
+ import json, sys
37
+ name = sys.argv[1]
38
+ ids = [s.get("id") for s in json.load(sys.stdin) if isinstance(s, dict) and s.get("name") == name]
39
+ print(ids[0] if ids else "", end="")
40
+ '
41
+
42
+ UNPACK='
43
+ import json, sys, pathlib
44
+ sk = json.load(sys.stdin)
45
+ dest = sys.argv[1] if len(sys.argv) > 1 and sys.argv[1] else sk["name"]
46
+ d = pathlib.Path(dest)
47
+ d.mkdir(parents=True, exist_ok=True)
48
+ (d / "SKILL.md").write_text(sk.get("content") or "", encoding="utf-8")
49
+ count = 1
50
+ for f in sk.get("files") or []:
51
+ rel = f.get("path") or ""
52
+ parts = pathlib.Path(rel).parts
53
+ if not parts or pathlib.Path(rel).is_absolute() or ".." in parts or rel == "SKILL.md":
54
+ continue
55
+ p = d / rel
56
+ p.parent.mkdir(parents=True, exist_ok=True)
57
+ p.write_text(f.get("content") or "", encoding="utf-8")
58
+ count += 1
59
+ print("pulled %d file(s) -> %s" % (count, d.resolve()))
60
+ '
61
+
62
+ if [ "$MODE" = "cli" ]; then
63
+ CLI="multica"
64
+ [ -n "$PROFILE" ] && CLI="$CLI --profile $PROFILE"
65
+ [ -n "$WS_ID" ] && CLI="$CLI --workspace-id $WS_ID"
66
+ SID=$($CLI skill list --output json | python3 -c "$RESOLVE" "$SKILL_NAME")
67
+ [ -n "$SID" ] || { echo "skill \"$SKILL_NAME\" not found in the workspace" >&2; exit 1; }
68
+ $CLI skill get "$SID" --output json | python3 -c "$UNPACK" "$DEST"
69
+ else
70
+ : "${MULTICA_SERVER_URL:?set MULTICA_SERVER_URL}"
71
+ : "${MULTICA_TOKEN:?set MULTICA_TOKEN}"
72
+ : "${MULTICA_WORKSPACE_ID:?set MULTICA_WORKSPACE_ID}"
73
+ AUTH="Authorization: Bearer $MULTICA_TOKEN"
74
+ WS="X-Workspace-ID: $MULTICA_WORKSPACE_ID"
75
+ SID=$(curl -fsS --noproxy '*' -H "$AUTH" -H "$WS" "$MULTICA_SERVER_URL/api/skills" | python3 -c "$RESOLVE" "$SKILL_NAME")
76
+ [ -n "$SID" ] || { echo "skill \"$SKILL_NAME\" not found in the workspace" >&2; exit 1; }
77
+ curl -fsS --noproxy '*' -H "$AUTH" -H "$WS" "$MULTICA_SERVER_URL/api/skills/$SID" | python3 -c "$UNPACK" "$DEST"
78
+ fi