@xdxer/dingtalk-agent 0.1.4-beta.0 → 0.1.4-beta.10
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.
- package/CHANGELOG.md +50 -0
- package/README.en.md +397 -0
- package/README.md +497 -46
- package/dist/bin/dingtalk-agent.js +1162 -340
- package/dist/bin/dingtalk-agent.js.map +1 -1
- package/dist/src/actions.js +98 -14
- package/dist/src/actions.js.map +1 -1
- package/dist/src/agent-audit.js +460 -0
- package/dist/src/agent-audit.js.map +1 -0
- package/dist/src/agent-bindings.js +132 -0
- package/dist/src/agent-bindings.js.map +1 -0
- package/dist/src/agent-definition.js +182 -0
- package/dist/src/agent-definition.js.map +1 -0
- package/dist/src/agent-enhance.js +678 -0
- package/dist/src/agent-enhance.js.map +1 -0
- package/dist/src/bootstrap.js +125 -17
- package/dist/src/bootstrap.js.map +1 -1
- package/dist/src/config.js +1 -7
- package/dist/src/config.js.map +1 -1
- package/dist/src/development-workspace.js +729 -0
- package/dist/src/development-workspace.js.map +1 -0
- package/dist/src/doctor.js +20 -9
- package/dist/src/doctor.js.map +1 -1
- package/dist/src/dws.js +145 -0
- package/dist/src/dws.js.map +1 -1
- package/dist/src/eval-evidence.js +193 -0
- package/dist/src/eval-evidence.js.map +1 -0
- package/dist/src/init.js +1 -1
- package/dist/src/init.js.map +1 -1
- package/dist/src/invocation.js +36 -0
- package/dist/src/invocation.js.map +1 -0
- package/dist/src/lab.js +679 -0
- package/dist/src/lab.js.map +1 -0
- package/dist/src/lease.js +100 -0
- package/dist/src/lease.js.map +1 -0
- package/dist/src/memory/candidates.js +451 -0
- package/dist/src/memory/candidates.js.map +1 -0
- package/dist/src/memory/completion-evidence.js +536 -0
- package/dist/src/memory/completion-evidence.js.map +1 -0
- package/dist/src/memory/operational.js +263 -0
- package/dist/src/memory/operational.js.map +1 -0
- package/dist/src/memory/remote-state.js +478 -0
- package/dist/src/memory/remote-state.js.map +1 -0
- package/dist/src/memory/task-checkpoints.js +204 -0
- package/dist/src/memory/task-checkpoints.js.map +1 -0
- package/dist/src/multica-deploy.js +1480 -0
- package/dist/src/multica-deploy.js.map +1 -0
- package/dist/src/multica-provider.js +685 -0
- package/dist/src/multica-provider.js.map +1 -0
- package/dist/src/opencode-evals.js +1062 -0
- package/dist/src/opencode-evals.js.map +1 -0
- package/dist/src/opencode-provider.js +531 -0
- package/dist/src/opencode-provider.js.map +1 -0
- package/dist/src/opencode-workspace.js +197 -0
- package/dist/src/opencode-workspace.js.map +1 -0
- package/dist/src/perception.js +225 -0
- package/dist/src/perception.js.map +1 -0
- package/dist/src/personal-event-evals.js +595 -0
- package/dist/src/personal-event-evals.js.map +1 -0
- package/dist/src/promotion.js +786 -0
- package/dist/src/promotion.js.map +1 -0
- package/dist/src/remote-semantic-state-live-evals.js +888 -0
- package/dist/src/remote-semantic-state-live-evals.js.map +1 -0
- package/dist/src/remote-semantic-state-worker.js +38 -0
- package/dist/src/remote-semantic-state-worker.js.map +1 -0
- package/dist/src/remote-state-evals.js +501 -0
- package/dist/src/remote-state-evals.js.map +1 -0
- package/dist/src/response-gate.js +51 -0
- package/dist/src/response-gate.js.map +1 -0
- package/dist/src/robot-evals.js +770 -0
- package/dist/src/robot-evals.js.map +1 -0
- package/dist/src/sessions.js +66 -105
- package/dist/src/sessions.js.map +1 -1
- package/dist/src/setup.js +10 -9
- package/dist/src/setup.js.map +1 -1
- package/dist/src/skill-manager.js +102 -203
- package/dist/src/skill-manager.js.map +1 -1
- package/dist/src/skills.js.map +1 -1
- package/dist/src/storage-evals.js +26 -0
- package/dist/src/storage-evals.js.map +1 -0
- package/dist/src/types.js.map +1 -1
- package/dist/src/upgrade.js +137 -0
- package/dist/src/upgrade.js.map +1 -0
- package/dist/src/waits.js +5 -1
- package/dist/src/waits.js.map +1 -1
- package/dist/src/workspace.js +28 -3
- package/dist/src/workspace.js.map +1 -1
- package/docs/INSTALLATION.md +118 -13
- package/docs/SECOND-AGENT-ACCEPTANCE.md +62 -0
- package/docs/architecture/agent-memory-topology.png +0 -0
- package/docs/architecture/agent-memory-topology.svg +132 -0
- package/docs/architecture/general-agent-kernel-topology.png +0 -0
- package/docs/architecture/general-agent-kernel-topology.svg +149 -0
- package/docs/architecture/provider-bound-development-workspace.png +0 -0
- package/docs/architecture/provider-bound-development-workspace.svg +141 -0
- package/docs/architecture/task-completion-gate.png +0 -0
- package/docs/architecture/task-completion-gate.svg +191 -0
- package/docs/schemas/agent-audit-load-evidence.schema.json +14 -0
- package/docs/schemas/agent-audit.schema.json +92 -0
- package/docs/schemas/agent-bindings.schema.json +54 -0
- package/docs/schemas/agent-definition.schema.json +78 -0
- package/docs/schemas/agent-enhancement-plan.schema.json +88 -0
- package/docs/schemas/agent-enhancement-receipt.schema.json +37 -0
- package/docs/schemas/enriched-invocation.schema.json +46 -0
- package/docs/schemas/eval-candidate-plan.schema.json +28 -0
- package/docs/schemas/eval-candidate-result.schema.json +20 -0
- package/docs/schemas/eval-candidate.schema.json +30 -0
- package/docs/schemas/invocation.schema.json +19 -0
- package/docs/schemas/memory-candidate-proposal.schema.json +18 -0
- package/docs/schemas/memory-candidate.schema.json +76 -0
- package/docs/schemas/memory-publish-target.schema.json +25 -0
- package/docs/schemas/multica-deployment-list.schema.json +29 -0
- package/docs/schemas/multica-deployment-operation.schema.json +51 -0
- package/docs/schemas/multica-deployment-plan.schema.json +70 -0
- package/docs/schemas/multica-deployment-receipt.schema.json +87 -0
- package/docs/schemas/multica-deployment-status.schema.json +23 -0
- package/docs/schemas/multica-workspace-inspection.schema.json +77 -0
- package/docs/schemas/multica-workspace-plan.schema.json +68 -0
- package/docs/schemas/multica-workspace-resource-list.schema.json +27 -0
- package/docs/schemas/multica-workspace-status.schema.json +34 -0
- package/docs/schemas/observation.schema.json +21 -0
- package/docs/schemas/operational-memory-provider.schema.json +36 -0
- package/docs/schemas/operational-memory-record.schema.json +24 -0
- package/docs/schemas/perception-input.schema.json +56 -0
- package/docs/schemas/project.schema.json +112 -0
- package/docs/schemas/promotion-list.schema.json +36 -0
- package/docs/schemas/promotion-plan.schema.json +60 -0
- package/docs/schemas/promotion-policy.schema.json +29 -0
- package/docs/schemas/promotion-receipt.schema.json +43 -0
- package/docs/schemas/promotion-status.schema.json +23 -0
- package/docs/schemas/release-readiness.schema.json +65 -0
- package/docs/schemas/remote-semantic-state-live-eval.schema.json +60 -0
- package/docs/schemas/remote-semantic-state-manifest.schema.json +79 -0
- package/docs/schemas/remote-semantic-state-provider.schema.json +98 -0
- package/docs/schemas/response-gate.schema.json +20 -0
- package/docs/schemas/task-checkpoint.schema.json +71 -0
- package/docs/schemas/task-completion-evidence.schema.json +154 -0
- package/docs/schemas/workspace-doctor.schema.json +56 -0
- package/docs/schemas/workspace-state.schema.json +39 -0
- package/evals/baselines/2026-07-16/opencode-basic-010-completion-summary.json +123 -0
- package/evals/baselines/2026-07-16/opencode-basic-skill-required-summary.json +69 -0
- package/evals/baselines/2026-07-16/opencode-multi-surface-summary.json +63 -0
- package/evals/baselines/2026-07-16/remote-state-live-summary.json +70 -0
- package/evals/baselines/2026-07-17/agent-enhance-opencode-dogfood-summary.json +98 -0
- package/evals/baselines/2026-07-17/personal-event-live-readiness-summary.json +68 -0
- package/examples/agents/fde-coach/AGENTS.md +26 -0
- package/examples/agents/fde-coach/MEMORY.md +3 -0
- package/examples/agents/fde-coach/fields/default/field.json +24 -0
- package/examples/agents/fde-coach/knowledge/INDEX.md +4 -0
- package/examples/agents/fde-coach/skills/fde-coach/SKILL.md +13 -0
- package/examples/agents/release-manager/AGENTS.md +26 -0
- package/examples/agents/release-manager/MEMORY.md +3 -0
- package/examples/agents/release-manager/fields/default/field.json +24 -0
- package/examples/agents/release-manager/knowledge/INDEX.md +4 -0
- package/examples/agents/release-manager/skills/release-manager/SKILL.md +13 -0
- package/lab/README.md +109 -0
- package/lab/agent-eval/catalog.json +91 -0
- package/lab/agent-eval/classic-failures.json +177 -0
- package/lab/agent-eval/completion-gate-regression.json +99 -0
- package/lab/agent-eval/personal-event-live.example.json +94 -0
- package/lab/agent-eval/remote-semantic-state-live.example.json +70 -0
- package/lab/agent-eval/remote-semantic-state-provider.fixture.json +47 -0
- package/lab/agent-eval/remote-state-workspace/AGENTS.md +8 -0
- package/lab/agent-eval/remote-state-workspace/opencode.json +7 -0
- package/lab/agent-eval/remote-state-workspace/skills/remote-state-operator/SKILL.md +13 -0
- package/lab/agent-eval/remote-state.example.json +31 -0
- package/lab/agent-eval/workspace/AGENTS.md +7 -0
- package/lab/agent-eval/workspace/MEMORY.md +4 -0
- package/lab/agent-eval/workspace/artifacts/pending-review.md +3 -0
- package/lab/agent-eval/workspace/knowledge/INDEX.md +4 -0
- package/lab/agent-eval/workspace/opencode.json +20 -0
- package/lab/manifest.example.json +27 -0
- package/lab/manifest.personal-event.example.json +27 -0
- package/lab/project-workspace/README.md +11 -0
- package/lab/project-workspace/fake-multica-provider.mjs +266 -0
- package/lab/project-workspace/multica-deploy.fixture.json +29 -0
- package/lab/project-workspace/multica-readonly.fixture.json +69 -0
- package/lab/project-workspace/observation.fixture.json +14 -0
- package/lab/project-workspace/opencode-provider-suite.json +65 -0
- package/lab/project-workspace/project.fixture.json +44 -0
- package/lab/project-workspace/promotion-policy.fixture.json +15 -0
- package/lab/robot-eval/pool.example.json +30 -0
- package/lab/robot-eval/suite.json +123 -0
- package/lab/robot-eval/workspace/AGENTS.md +21 -0
- package/lab/robot-eval/workspace/MEMORY.md +3 -0
- package/lab/robot-eval/workspace/knowledge/INDEX.md +5 -0
- package/lab/robot-eval/workspace/opencode.json +22 -0
- package/lab/schemas/agent-eval-catalog.schema.json +47 -0
- package/lab/schemas/lab-manifest.schema.json +70 -0
- package/lab/schemas/personal-event-eval.schema.json +91 -0
- package/lab/schemas/remote-state-eval.schema.json +66 -0
- package/lab/schemas/robot-eval-suite.schema.json +184 -0
- package/lab/schemas/robot-pool.schema.json +56 -0
- package/package.json +26 -14
- package/skills/dingtalk-agent-boot-multica/SKILL.md +40 -0
- package/skills/dingtalk-agent-compose/SKILL.md +110 -0
- package/skills/dingtalk-agent-compose/assets/AGENTS.template.md +26 -0
- package/skills/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +13 -0
- package/skills/dingtalk-agent-compose/assets/agent.bindings.local.template.json +13 -0
- package/skills/dingtalk-agent-compose/assets/opencode.template.json +12 -0
- package/skills/dingtalk-agent-compose/assets/role-skill.template.md +24 -0
- package/skills/dingtalk-agent-compose/evals/evals.json +94 -0
- package/skills/dingtalk-agent-compose/references/agent-definition-contract.md +55 -0
- package/skills/dingtalk-agent-compose/references/opencode-host-contract.md +65 -0
- package/skills/dingtalk-agent-compose/references/storage-routing.md +20 -0
- package/skills/dingtalk-agent-deploy/SKILL.md +60 -0
- package/skills/dingtalk-agent-deploy/references/multica-deployment-contract.md +49 -0
- package/skills/dingtalk-agent-deploy/references/promotion-observation-contract.md +49 -0
- package/skills/dingtalk-agent-eval/SKILL.md +116 -0
- package/skills/dingtalk-agent-eval/assets/eval-catalog.template.json +18 -0
- package/skills/dingtalk-agent-eval/evals/evals.json +61 -0
- package/skills/dingtalk-agent-eval/references/eval-topology.md +34 -0
- package/skills/dingtalk-agent-eval/references/evidence-contract.md +31 -0
- package/skills/dingtalk-agent-eval/references/scenario-taxonomy.md +25 -0
- package/skills/dingtalk-agent-eval/references/storage-modes.md +75 -0
- package/skills/dingtalk-basic-behavior/SKILL.md +63 -3
- package/skills/dingtalk-basic-behavior/assets/memory-candidate-proposal.json +10 -0
- package/skills/dingtalk-basic-behavior/assets/{task-checkpoint.md → task-checkpoint.json} +2 -21
- package/skills/dingtalk-basic-behavior/references/action-contract.md +2 -0
- package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +15 -1
- package/skills/dingtalk-basic-behavior/references/perception-and-gates.md +28 -0
- package/skills/dingtalk-basic-behavior/references/task-lifecycle.md +32 -7
- package/dist/src/boot.js +0 -70
- package/dist/src/boot.js.map +0 -1
- package/dist/src/duty.js +0 -74
- package/dist/src/duty.js.map +0 -1
- package/dist/src/kb.js +0 -240
- package/dist/src/kb.js.map +0 -1
- package/dist/src/runs.js +0 -79
- package/dist/src/runs.js.map +0 -1
- package/docs/ARCHITECTURE.md +0 -217
- package/docs/MINIMAL-WORKSPACE-V1.md +0 -172
- package/docs/OPEN-SOURCE-REFERENCES.md +0 -107
- package/docs/SELF-TEST.md +0 -252
- package/docs//345/206/205/347/275/221/345/256/236/347/233/270.md +0 -77
- package/evals/baselines/2026-07-14/behavior-summary.json +0 -28
- package/evals/baselines/2026-07-14/contract-summary.json +0 -18
- package/evals/baselines/2026-07-14/live-canary-summary.json +0 -25
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/SKILL.md +0 -72
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/action-contract.md +0 -31
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/event-to-behavior.md +0 -22
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/memory-and-evolution.md +0 -25
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/runtime-modes.md +0 -34
- package/evals/baselines/2026-07-15/task-lifecycle-summary.json +0 -50
- package/evals/evals.json +0 -316
- package/evals/fixtures/dm-ambiguous-send.json +0 -4
- package/evals/fixtures/dm-blocked.json +0 -4
- package/evals/fixtures/dm-clear.json +0 -4
- package/evals/fixtures/dm-discussion.json +0 -4
- package/evals/fixtures/dm-doc-write-no-tool.json +0 -4
- package/evals/fixtures/dm-long-task-ack.json +0 -4
- package/evals/fixtures/dm-nonblocking-gap.json +0 -4
- package/evals/fixtures/dm-structured-task.json +0 -4
- package/evals/fixtures/group.json +0 -10
- package/evals/fixtures/mentioned.json +0 -3
- package/evals/run-contract-evals.mjs +0 -1106
- package/evals/run-shadow-evals.mjs +0 -267
- package/evals/runners/README.md +0 -66
- package/evals/runners/claude-shadow.mjs +0 -533
- package/evals/schemas/action-request.schema.json +0 -77
- package/evals/shadow-evals.json +0 -133
- package/skills/AGENTS.md +0 -104
- package/skills//344/273/273/345/212/241.md +0 -48
- package/skills//345/237/272/347/241/200/350/241/214/344/270/272.md +0 -44
- package/skills//345/277/203/350/267/263.md +0 -79
- package/skills//346/266/210/346/201/257.md +0 -50
- package/skills//347/237/245/350/257/206.md +0 -55
- package/skills//350/257/204/346/265/213.md +0 -62
- package/skills//351/222/211/351/222/211.md +0 -64
- package/templates/ontology/index.md +0 -24
- package/templates/ontology/self/access.md +0 -38
- package/templates/ontology/self/role-spec.md +0 -34
- package/templates/ontology/self/workspace.md +0 -41
package/dist/src/kb.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"kb.js","sourceRoot":"","sources":["../../src/kb.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,uEAAuE;AACvE,mBAAmB;AACnB,uEAAuE;AACvE,EAAE;AACF,uDAAuD;AACvD,kDAAkD;AAClD,oDAAoD;AACpD,oDAAoD;AACpD,gDAAgD;AAChD,sEAAsE;AACtE,EAAE;AACF,+CAA+C;AAC/C,EAAE;AACF,uEAAuE;AACvE,mBAAmB;AACnB,uEAAuE;AACvE,EAAE;AACF,uCAAuC;AACvC,kCAAkC;AAClC,EAAE;AACF,sDAAsD;AACtD,6DAA6D;AAC7D,EAAE;AACF,kDAAkD;AAClD,gCAAgC;AAEhC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAE/B,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,EAAE,QAAQ,GAAG,UAAU,CAAA;AACnD,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,EAAE,IAAI,GAAG,MAAM,EAAE,IAAI,GAAG,MAAM,CAAA;AAExD,wDAAwD;AACxD,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAA;AAE7B,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAMrG,MAAM,UAAW,SAAQ,KAAK;IAC5B,QAAQ,GAAG,CAAC,CAAA;CACb;AAED,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,CAAC;IAC3B,IAAI,CAAC,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC5C,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAmB,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACxD,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC1B,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAA;IAChF,MAAM,IAAI,KAAK,CACb,WAAW,CAAC,IAAI;QAChB,WAAW;QACX,8DAA8D;QAC9D,0CAA0C;QAC1C,wDAAwD,CAAC,CAAA;AAC7D,CAAC;AAED,mDAAmD;AACnD,SAAS,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE;IAClC,MAAM,GAAG,GAAiB,EAAE,CAAA;IAC5B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,MAAM,CAAA;QACzC,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAAC,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,SAAQ;QAAC,CAAC;QACxF,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,KAAK,QAAQ;YAAE,SAAQ,CAAM,YAAY;QAC3E,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC;YAC7D,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,CAAA;IAC7C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE;IAC/C,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;IAC5E,IAAI,MAAM;QAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IACzC,MAAM,GAAG,GAAiB,EAAE,CAAA;IAC5B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,MAAM,CAAA;QACzC,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QACnG,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC;YAC7D,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,CAAA;IAC7C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,GAAG,KAAK;IAC1C,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;IACzC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,IAAI,aAAa,CAAC,CAAC;QAAC,OAAM;IAAC,CAAC;IAE/E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;IACjC,MAAM,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IACzD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,IAAI,EAAE,CAAC,IAAI,qCAAqC;YAChD,0CAA0C,CAAC,CAAA;IAC/C,CAAC;IACD,EAAE,CAAC,MAAM,KAAK,EAAE,CAAA;IAChB,IAAI,MAAM,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,CAAA;IAC3B,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QACzB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,KAAK,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAAC,OAAO,EAAE,CAAC;YAAC,SAAQ;QAAC,CAAC;QACvF,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC3B,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1C,kCAAkC;QAClC,aAAa,CAAC,CAAC,EACb,gDAAgD;YAChD,gBAAgB,GAAG,kBAAkB,GAAG,EAAE,WAAW,EAAE,EAAE,CAAC,CAAA;QAC5D,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAA;QAC/B,MAAM,EAAE,CAAA;IACV,CAAC;IACD,EAAE,CAAC,SAAS,GAAG,GAAG,EAAE,CAAA;IACpB,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,WAAW,OAAO,IAAI,CAAC,CAAA;AAChF,CAAC;AAED,sDAAsD;AACtD,SAAS,SAAS,CAAC,GAAG,EAAE,IAAI,GAAG,GAAG;IAChC,MAAM,GAAG,GAAgB,EAAE,CAAA;IAC3B,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;QAC3B,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YAAC,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YAAC,SAAQ;QAAC,CAAC;QAClE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;IAC3E,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,GAAG,KAAK;IAC1C,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;IACzC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,8CAA8C;YAC9C,gCAAgC,CAAC,CAAA;IACnD,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;IAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAA;IAExD,EAAE,CAAC,MAAM,KAAK,EAAE,CAAA;IAChB,MAAM,KAAK,GAAwC,EAAE,CAAA;IACrD,IAAI,MAAM,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAA;IAE7B,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QACvC,IAAI,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAA;QACtE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;YAC1D,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,eAAe,CAAC,CAAA;YACnD,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAA;YACtD,MAAM,EAAE,CAAC;YAAC,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;YAAC,SAAQ;QACpD,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;YAAC,SAAS,EAAE,CAAC;YAAC,SAAQ;QAAC,CAAC;QAErD,8BAA8B;QAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,CAAA;QACvC,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YAAC,SAAQ;QAAC,CAAC;QAExF,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACxB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,gCAAgC,CAAC,CAAA;QAC5D,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5C,MAAM,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,EAAE,CAAC,CAAA;IAC1C,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,4BAA4B,KAAK,CAAC,MAAM,MAAM,CAAC,CAAA;QAC3D,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,aAAa,GAAG,EAAE,CAAC,CAAA;QAC7E,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAA;QAClD,OAAO,CAAC,GAAG,CAAC,0CAA0C,EAAE,CAAC,IAAI,UAAU,CAAC,CAAA;QACxE,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,CAAA;IAClC,CAAC;IACD,EAAE,CAAC,SAAS,GAAG,GAAG,EAAE,CAAA;IACpB,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,WAAW,SAAS,IAAI,CAAC,CAAA;AAClF,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,KAAK,CAAC,EAAE;IACtB,IAAI,EAAE,CAAC,GAAG,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAA;IACzD,IAAI,CAAC,EAAE,CAAC,SAAS;QAAE,OAAO,IAAI,CAAA;IAC9B,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,CAAA;IAC5D,OAAO,GAAG,GAAG,WAAW,CAAA;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,GAAG,EAAE;IAC5C,MAAM,IAAI,GAAgB,EAAE,CAAA;IAC5B,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;QACvE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC/B,IAAI,KAAK,CAAC,EAAE,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;QACnC,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;QACvF,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAA;YAChG,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;QACtE,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,kBAAkB,WAAW,aAAa,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACzE,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;QAC5C,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAA;IAChD,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAC1B,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAA;QACjE,OAAO,EAAE,CAAA;IACX,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,KAAK,CAAC,CAAA;IACnC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QACvC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;IACvF,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;IAC/C,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["// 知识库挂载与同步(TypeScript source)。\n//\n// ════════════════════════════════════════════════════════════════════\n// 【核心判断】所有权决定真值方向。\n// ════════════════════════════════════════════════════════════════════\n//\n// owned(我的本体) external(别人维护的)\n// 真值在 **Git**(本地) **钉钉**(远端)\n// 同步方向 push 本地 → 钉钉 pull 钉钉 → 本地\n// 为什么 给人看(人机同源) 给我 grep(快、能看上下文)\n// 冲突了 远端被人改过 → **停** 远端赢,本地缓存可丢弃\n// 落在 ontology/(入 Git) .cache/kb/<name>/(gitignore)\n//\n// 这就是「Git 内核 × 钉钉暴露层」:**Git 是常量层,钉钉是可替换的暴露层。**\n//\n// ════════════════════════════════════════════════════════════════════\n// 【三个硬约束】—— 全是踩出来的\n// ════════════════════════════════════════════════════════════════════\n//\n// 1. **绝不双向自动 merge。** 一个方向是真值,另一个是投影。\n// 自动合并两个都在变的东西 = 灾难,而且是【静默】灾难。\n//\n// 2. **重排版不是漂移。** 判据是「剥掉 markdown 符号后的文字流」,不是行级 diff。\n// 用行级 diff → 每次 sync 都误报 → **你就会开始无脑 --force,真漂移也一起覆盖掉。**\n//\n// 3. **缓存不新鲜就不许用(fail-closed)。** external KB 是快照。\n// **拿着过期快照回答,比说「我不知道」危险得多。**\n\nimport { mkdirSync, writeFileSync, readFileSync, existsSync, statSync } from 'node:fs'\nimport { readdirSync } from 'node:fs'\nimport { join, dirname, relative, basename } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport * as dws from './dws.js'\n\nexport const OWNED = 'owned', EXTERNAL = 'external'\nexport const PULL = 'pull', PUSH = 'push', NONE = 'none'\n\n/** external 缓存超过这么久就算过期。过期 → kb search 会警告并要求先 sync。 */\nexport const STALE_HOURS = 24\n\nconst now = () => new Date(Date.now() + 8 * 3600e3).toISOString().replace('Z', '+08:00').slice(0, 19)\n\ninterface RemoteItem { rel: string; nid: string; mtime: string | number }\ninterface LocalItem { path: string; rel: string }\ninterface SearchHit { kb: string; file: string; ctx: string }\n\nclass DriftError extends Error {\n exitCode = 1\n}\n\n/** dingtalk:doc:<folderId> · dingtalk:wiki:<spaceId> · local:<path> */\nexport function parseSource(s): { kind: 'doc' | 'wiki' | 'local'; id: string } {\n let m = /^dingtalk:(doc|wiki):(.+)$/.exec(s)\n if (m) return { kind: m[1] as 'doc' | 'wiki', id: m[2] }\n m = /^local:(.+)$/.exec(s)\n if (m) return { kind: 'local', id: m[1].replace(/^~/, process.env.HOME || '~') }\n throw new Error(\n `挂载源写错了: ${s}\\n` +\n ` 支持三种:\\n` +\n ` dingtalk:doc:<folderId> 文档文件夹(最常见 —— 很多组织根本没建\"知识库\")\\n` +\n ` dingtalk:wiki:<spaceId> 钉钉知识库空间\\n` +\n ` local:<路径> 本地目录(只读挂载,比如另一个仓库的 wiki/)`)\n}\n\n// ════════════════ pull:钉钉 → 本地缓存 ════════════════\nfunction walkDoc(folder, prefix = ''): RemoteItem[] {\n const out: RemoteItem[] = []\n for (const n of dws.nodes(dws.run(['doc', 'list', '--folder', folder, '--page-size', '50']))) {\n const name = n.name || '', nid = n.nodeId\n if (n.nodeType === 'folder') { out.push(...walkDoc(nid, join(prefix, name))); continue }\n if (n.contentType && n.contentType !== 'ALIDOC') continue // 二进制附件不是知识\n out.push({ rel: join(prefix, name.endsWith('.md') ? name : `${name}.md`),\n nid, mtime: n.updateTime || 0 })\n }\n return out\n}\n\nfunction walkWiki(space, folder = '', prefix = ''): RemoteItem[] {\n const args = ['wiki', 'node', 'list', '--workspace', space, '--limit', '50']\n if (folder) args.push('--folder', folder)\n const out: RemoteItem[] = []\n for (const n of dws.nodes(dws.run(args))) {\n const name = n.name || '', nid = n.nodeId\n if (n.nodeType === 'folder' || n.hasChildren) out.push(...walkWiki(space, nid, join(prefix, name)))\n out.push({ rel: join(prefix, name.endsWith('.md') ? name : `${name}.md`),\n nid, mtime: n.updateTime || 0 })\n }\n return out\n}\n\n/** 钉钉 → 本地缓存。**远端赢**(external 的真值在远端)。增量靠 updateTime。 */\nexport function pull(kb, root, force = false) {\n const { kind, id } = parseSource(kb.from)\n if (kind === 'local') { console.log(` local ${kb.name} 就在本地,不用同步`); return }\n\n const dest = join(root, kb.local)\n const items = kind === 'doc' ? walkDoc(id) : walkWiki(id)\n if (!items.length) {\n throw new Error(\n `「${kb.name}」远端一个节点都没有 —— **不许当成【这个知识库是空的】。**\\n` +\n ` 可能是: ID 写错 / 没权限 / 它真的空。先用 dws 手工确认再说。`)\n }\n kb._state ??= {}\n let pulled = 0, skipped = 0\n for (const { rel, nid, mtime } of items) {\n const p = join(dest, rel)\n if (!force && kb._state[nid]?.mtime === mtime && existsSync(p)) { skipped++; continue }\n const md = dws.readDoc(nid)\n mkdirSync(dirname(p), { recursive: true })\n // 头三行钉住来源 —— **没有指针的知识,用的时候不敢信。**\n writeFileSync(p,\n `<!-- 来自钉钉 · 只读缓存 · 不要在这里改,改了下次 sync 会被覆盖 -->\\n` +\n `<!-- nodeId: ${nid} -->\\n<!-- 拉取: ${now()} -->\\n\\n${md}`)\n kb._state[nid] = { rel, mtime }\n pulled++\n }\n kb._syncedAt = now()\n console.log(` pull ${kb.name.padEnd(14)} 拉了 ${pulled} 篇 · 没变 ${skipped} 篇`)\n}\n\n// ════════════════ push:本地 → 钉钉(人机同源)════════════════\nfunction walkLocal(dir, base = dir): LocalItem[] {\n const out: LocalItem[] = []\n for (const e of readdirSync(dir, { withFileTypes: true })) {\n const p = join(dir, e.name)\n if (e.isDirectory()) { out.push(...walkLocal(p, base)); continue }\n if (e.name.endsWith('.md')) out.push({ path: p, rel: relative(base, p) })\n }\n return out\n}\n\n/**\n * 本地 → 钉钉。**Git 赢**(owned 的真值在 Git)。\n *\n * ⚠️ **推之前先查漂移** —— 远端被人改过就【停下来问】,绝不盲覆盖。\n * 人在钉钉里改了东西,说明他有话要说。**盲覆盖 = 把人的意见删了。**\n */\nexport function push(kb, root, force = false) {\n const { kind, id } = parseSource(kb.from)\n if (kind !== 'doc') {\n throw new Error('push 目前只支持 dingtalk:doc:<folderId>(文档文件夹)。\\n' +\n ' 知识库空间的写入面还没验过 —— **不许假装支持。**')\n }\n const src = join(root, kb.local)\n if (!existsSync(src)) throw new Error(`本地目录不存在: ${src}`)\n\n kb._state ??= {}\n const drift: Array<{ rel: string; nid: string }> = []\n let pushed = 0, unchanged = 0\n\n for (const { path, rel } of walkLocal(src)) {\n const body = readFileSync(path, 'utf8')\n let nid = Object.keys(kb._state).find((k) => kb._state[k].rel === rel)\n if (!nid) {\n nid = String(dws.createDoc(id, basename(rel), path) || '')\n if (!nid) throw new Error(`创建 ${rel} 后没有返回 nodeId`)\n kb._state[nid] = { rel, pushedWords: dws.words(body) }\n pushed++; console.log(` + 新建 ${rel}`); continue\n }\n const remote = dws.readDoc(nid)\n if (dws.same(remote, body)) { unchanged++; continue }\n\n // 远端 ≠ 我上次推上去的 → **有人在钉钉里改过**\n const last = kb._state[nid].pushedWords\n if (last && dws.words(remote) !== last && !force) { drift.push({ rel, nid }); continue }\n\n dws.updateDoc(nid, path)\n if (!dws.same(dws.readDoc(nid), body)) {\n throw new Error(`推了 ${rel} 但回读不一致 —— **写操作报错≠失败,回读定成败。**`)\n }\n kb._state[nid].pushedWords = dws.words(body)\n pushed++; console.log(` ↑ 更新 ${rel}`)\n }\n\n if (drift.length) {\n console.log(`\\n ⚠️ **远端被人改过**,默认拒绝覆盖(${drift.length} 篇):`)\n for (const { rel, nid } of drift) console.log(` ${rel} nodeId=${nid}`)\n console.log(` 人在钉钉里改了东西,说明他有话要说。**先去看一眼**,别盲覆盖。`)\n console.log(` 确认要覆盖: dingtalk-agent kb sync --name ${kb.name} --force`)\n throw new DriftError('有漂移,拒绝覆盖')\n }\n kb._syncedAt = now()\n console.log(` push ${kb.name.padEnd(14)} 推了 ${pushed} 篇 · 一致 ${unchanged} 篇`)\n}\n\n// ════════════════ search:跨所有挂载点 ════════════════\nexport function stale(kb) {\n if (kb.own !== EXTERNAL || kb.sync === NONE) return false\n if (!kb._syncedAt) return true\n const age = (Date.now() - Date.parse(kb._syncedAt)) / 3600e3\n return age > STALE_HOURS\n}\n\n/**\n * 跨所有挂载的 KB 搜。**本地 grep 为主** —— 快、确定、能看到上下文。\n *\n * fail-closed:不新鲜的缓存会【警告】。\n * **拿着过期快照回答,比说「我不知道」危险得多。**\n */\nexport function search(cfg, root, kw, top = 20) {\n const hits: SearchHit[] = []\n const warned: string[] = []\n for (const kb of cfg.kb || []) {\n const base = kb.local.startsWith('/') ? kb.local : join(root, kb.local)\n if (!existsSync(base)) continue\n if (stale(kb)) warned.push(kb.name)\n const r = spawnSync('grep', ['-ril', '--include=*.md', kw, base], { encoding: 'utf8' })\n for (const p of (r.stdout || '').split('\\n').filter(Boolean)) {\n const ctx = spawnSync('grep', ['-i', '-n', '-m', '2', kw, p], { encoding: 'utf8' }).stdout || ''\n hits.push({ kb: kb.name, file: relative(root, p), ctx: ctx.trim() })\n }\n }\n\n if (warned.length) {\n console.log(`⚠️ 这些知识库的缓存【超过 ${STALE_HOURS} 小时没同步】了: ${warned.join('、')}`)\n console.log(` **拿着过期快照回答,比说「我不知道」危险得多。**`)\n console.log(` 先跑: dingtalk-agent kb sync\\n`)\n }\n if (!hits.length) {\n console.log(`没搜到「${kw}」。`)\n console.log(`**搜不到就说搜不到 —— 不要编。** 挂了哪些库: dingtalk-agent kb list`)\n return []\n }\n console.log(`命中 ${hits.length} 处:`)\n for (const h of hits.slice(0, top)) {\n console.log(`\\n── [${h.kb}] ${h.file}`)\n for (const l of h.ctx.split('\\n').slice(0, 2)) console.log(` ${l.slice(0, 110)}`)\n }\n console.log(`\\n**别只看这几行就作答** —— 打开命中的那一页读完再说。`)\n return hits\n}\n"]}
|
package/dist/src/runs.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// 留痕与集中进化 —— runs/YYYY-MM-DD.md,一天一档 jsonl(TypeScript source)。
|
|
2
|
-
//
|
|
3
|
-
// 每行钉住【三个硬 ID】—— 出问题才反查得到:
|
|
4
|
-
// issue → 平台派单 id,翻得出整个运行过程
|
|
5
|
-
// conv → 会话 id,**filter 得出整条对话流(这就是训练素材)**
|
|
6
|
-
// msg → 触发消息 id,定位到那一句
|
|
7
|
-
// **缺了这三个,记录就只是一堆"我做了什么",出了问题什么也追不到。**
|
|
8
|
-
//
|
|
9
|
-
// r = 【引擎层】成败(跑通没有)
|
|
10
|
-
// fb = 【用户层】成败(主人认不认)
|
|
11
|
-
// **两者必须分开** —— 引擎跑通 ≠ 答对 ≠ 主人满意。
|
|
12
|
-
// 只看 r,你会看到一片绿,然后什么也进化不了。
|
|
13
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'node:fs';
|
|
14
|
-
import { join } from 'node:path';
|
|
15
|
-
export const FB_OK = '认可', FB_MORE = '追问', FB_FIX = '纠正';
|
|
16
|
-
const MARKER = 'AGENT_RUN_LOG_V1';
|
|
17
|
-
const cst = (d = new Date()) => new Date(d.getTime() + 8 * 3600e3);
|
|
18
|
-
export const today = () => cst().toISOString().slice(0, 10);
|
|
19
|
-
export const now = () => cst().toISOString().replace('Z', '+08:00').slice(0, 19);
|
|
20
|
-
export const todayZero = () => today() + 'T00:00:00+08:00';
|
|
21
|
-
/** 【今晚跑过没有】= 数据水位 ≥ 今天 00:00。纯【数据派生】——
|
|
22
|
-
* 不记状态、不建标记文件、不看会话记忆。重启/换实例/漏拍都不受影响。 */
|
|
23
|
-
export const ranTonight = (wm) => Boolean(wm) && String(wm) >= todayZero();
|
|
24
|
-
const file = (root, day) => join(root, 'runs', `${day}.md`);
|
|
25
|
-
export function read(root, day) {
|
|
26
|
-
const p = file(root, day);
|
|
27
|
-
if (!existsSync(p))
|
|
28
|
-
return [];
|
|
29
|
-
const out = [];
|
|
30
|
-
for (const line of readFileSync(p, 'utf8').split('\n')) {
|
|
31
|
-
const s = line.trim();
|
|
32
|
-
if (!s.startsWith('{'))
|
|
33
|
-
continue;
|
|
34
|
-
try {
|
|
35
|
-
out.push(JSON.parse(s));
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
console.error(` ⚠️ 运行记录有坏行,跳过但【不当成空】: ${s.slice(0, 60)}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return out;
|
|
42
|
-
}
|
|
43
|
-
export function write(root, day, rows) {
|
|
44
|
-
mkdirSync(join(root, 'runs'), { recursive: true });
|
|
45
|
-
const body = rows.map((r) => JSON.stringify(r)).join('\n');
|
|
46
|
-
writeFileSync(file(root, day), `${MARKER} · ${day}\n\n\`\`\`jsonl\n${body}\n\`\`\`\n`);
|
|
47
|
-
}
|
|
48
|
-
/** 追加一行 + 回读校验。**写了没落上 = 这次没发生过,要说出来。** */
|
|
49
|
-
export function append(root, row) {
|
|
50
|
-
const day = today();
|
|
51
|
-
const rows = read(root, day);
|
|
52
|
-
rows.push(row);
|
|
53
|
-
write(root, day, rows);
|
|
54
|
-
const ok = read(root, day).some((r) => r.t === row.t && r.did === row.did);
|
|
55
|
-
if (!ok)
|
|
56
|
-
console.error(' ⚠️ 运行记录写后回读不到 —— 动作照常,但【留痕失败】');
|
|
57
|
-
return ok ? row.t : '';
|
|
58
|
-
}
|
|
59
|
-
export function scan(root, days = 1) {
|
|
60
|
-
const out = [];
|
|
61
|
-
for (let i = 0; i < Math.max(1, days); i++) {
|
|
62
|
-
const d = new Date(Date.now() - i * 86400e3);
|
|
63
|
-
const day = cst(d).toISOString().slice(0, 10);
|
|
64
|
-
for (const r of read(root, day))
|
|
65
|
-
out.push({ ...r, _day: day });
|
|
66
|
-
}
|
|
67
|
-
return out.sort((a, b) => (a._day + a.t).localeCompare(b._day + b.t));
|
|
68
|
-
}
|
|
69
|
-
export function logq(root, { did, kind = '问答', secs = 0, r = 'pass', ev = '', ch = '钉钉单聊', asked = '', issue = '', conv = '', msg = '' }) {
|
|
70
|
-
const row = {
|
|
71
|
-
t: now().slice(11, 19), ch, kind, did: String(did).slice(0, 300), secs: +secs, r,
|
|
72
|
-
};
|
|
73
|
-
for (const [k, v] of [['asked', asked], ['issue', issue], ['conv', conv], ['msg', msg], ['ev', ev]]) {
|
|
74
|
-
if (v)
|
|
75
|
-
row[k] = String(v).slice(0, 600);
|
|
76
|
-
}
|
|
77
|
-
return append(root, row);
|
|
78
|
-
}
|
|
79
|
-
//# sourceMappingURL=runs.js.map
|
package/dist/src/runs.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/runs.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,2BAA2B;AAC3B,8BAA8B;AAC9B,8CAA8C;AAC9C,2BAA2B;AAC3B,uCAAuC;AACvC,EAAE;AACF,qBAAqB;AACrB,sBAAsB;AACtB,kCAAkC;AAClC,0BAA0B;AAC1B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,EAAE,OAAO,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;AACxD,MAAM,MAAM,GAAG,kBAAkB,CAAA;AAoBjC,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,CAAA;AAClE,MAAM,CAAC,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAC3D,MAAM,CAAC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAChF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,iBAAiB,CAAA;AAE1D;yCACyC;AACzC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,IAAI,SAAS,EAAE,CAAA;AAE1E,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,KAAK,CAAC,CAAA;AAE3D,MAAM,UAAU,IAAI,CAAC,IAAI,EAAE,GAAG;IAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IACzB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,CAAA;IAC7B,MAAM,GAAG,GAAmB,EAAE,CAAA;IAC9B,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QACrB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QAChC,IAAI,CAAC;YAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAiB,CAAC,CAAA;QAAC,CAAC;QAC/C,MAAM,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAA;QAAC,CAAC;IACtE,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,IAAoB;IACnD,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC1D,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG,MAAM,MAAM,GAAG,oBAAoB,IAAI,YAAY,CAAC,CAAA;AACxF,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,MAAM,CAAC,IAAI,EAAE,GAAiB;IAC5C,MAAM,GAAG,GAAG,KAAK,EAAE,CAAA;IACnB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACd,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IACtB,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAA;IAC1E,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACzD,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC;IACjC,MAAM,GAAG,GAAmB,EAAE,CAAA;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,CAAA;QAC5C,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QAC7C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACvE,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,EAAE,GAAG,EAAE,EAChD,EAAE,GAAG,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE;IACpF,MAAM,GAAG,GAAiB;QACxB,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;KACjF,CAAA;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;QACpG,IAAI,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;AAC1B,CAAC","sourcesContent":["// 留痕与集中进化 —— runs/YYYY-MM-DD.md,一天一档 jsonl(TypeScript source)。\n//\n// 每行钉住【三个硬 ID】—— 出问题才反查得到:\n// issue → 平台派单 id,翻得出整个运行过程\n// conv → 会话 id,**filter 得出整条对话流(这就是训练素材)**\n// msg → 触发消息 id,定位到那一句\n// **缺了这三个,记录就只是一堆\"我做了什么\",出了问题什么也追不到。**\n//\n// r = 【引擎层】成败(跑通没有)\n// fb = 【用户层】成败(主人认不认)\n// **两者必须分开** —— 引擎跑通 ≠ 答对 ≠ 主人满意。\n// 只看 r,你会看到一片绿,然后什么也进化不了。\nimport { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport const FB_OK = '认可', FB_MORE = '追问', FB_FIX = '纠正'\nconst MARKER = 'AGENT_RUN_LOG_V1'\n\nexport interface RunLogRecord {\n t: string\n did: string\n r: string\n _day?: string\n asked?: string\n kind?: string\n secs?: number\n ev?: string\n ch?: string\n issue?: string\n conv?: string\n msg?: string\n fb?: string\n fbt?: string\n [key: string]: unknown\n}\n\nconst cst = (d = new Date()) => new Date(d.getTime() + 8 * 3600e3)\nexport const today = () => cst().toISOString().slice(0, 10)\nexport const now = () => cst().toISOString().replace('Z', '+08:00').slice(0, 19)\nexport const todayZero = () => today() + 'T00:00:00+08:00'\n\n/** 【今晚跑过没有】= 数据水位 ≥ 今天 00:00。纯【数据派生】——\n * 不记状态、不建标记文件、不看会话记忆。重启/换实例/漏拍都不受影响。 */\nexport const ranTonight = (wm) => Boolean(wm) && String(wm) >= todayZero()\n\nconst file = (root, day) => join(root, 'runs', `${day}.md`)\n\nexport function read(root, day): RunLogRecord[] {\n const p = file(root, day)\n if (!existsSync(p)) return []\n const out: RunLogRecord[] = []\n for (const line of readFileSync(p, 'utf8').split('\\n')) {\n const s = line.trim()\n if (!s.startsWith('{')) continue\n try { out.push(JSON.parse(s) as RunLogRecord) }\n catch { console.error(` ⚠️ 运行记录有坏行,跳过但【不当成空】: ${s.slice(0, 60)}`) }\n }\n return out\n}\n\nexport function write(root, day, rows: RunLogRecord[]) {\n mkdirSync(join(root, 'runs'), { recursive: true })\n const body = rows.map((r) => JSON.stringify(r)).join('\\n')\n writeFileSync(file(root, day), `${MARKER} · ${day}\\n\\n\\`\\`\\`jsonl\\n${body}\\n\\`\\`\\`\\n`)\n}\n\n/** 追加一行 + 回读校验。**写了没落上 = 这次没发生过,要说出来。** */\nexport function append(root, row: RunLogRecord) {\n const day = today()\n const rows = read(root, day)\n rows.push(row)\n write(root, day, rows)\n const ok = read(root, day).some((r) => r.t === row.t && r.did === row.did)\n if (!ok) console.error(' ⚠️ 运行记录写后回读不到 —— 动作照常,但【留痕失败】')\n return ok ? row.t : ''\n}\n\nexport function scan(root, days = 1): RunLogRecord[] {\n const out: RunLogRecord[] = []\n for (let i = 0; i < Math.max(1, days); i++) {\n const d = new Date(Date.now() - i * 86400e3)\n const day = cst(d).toISOString().slice(0, 10)\n for (const r of read(root, day)) out.push({ ...r, _day: day })\n }\n return out.sort((a, b) => (a._day + a.t).localeCompare(b._day + b.t))\n}\n\nexport function logq(root, { did, kind = '问答', secs = 0, r = 'pass', ev = '',\n ch = '钉钉单聊', asked = '', issue = '', conv = '', msg = '' }): string {\n const row: RunLogRecord = {\n t: now().slice(11, 19), ch, kind, did: String(did).slice(0, 300), secs: +secs, r,\n }\n for (const [k, v] of [['asked', asked], ['issue', issue], ['conv', conv], ['msg', msg], ['ev', ev]]) {\n if (v) row[k] = String(v).slice(0, 600)\n }\n return append(root, row)\n}\n"]}
|
package/docs/ARCHITECTURE.md
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
# dingtalk-agent:Skill-first 代码与运行架构
|
|
2
|
-
|
|
3
|
-
## 一句话结论
|
|
4
|
-
|
|
5
|
-
主入口是“外部 Agent 会话 + 全局 Basic Behavior Skill”;Workspace/Storage 是按需上下文,Prepared Run 是需要强可靠性时才启用的宿主模式,`listen` 只是其中一个可替换 Driver。
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
```mermaid
|
|
10
|
-
flowchart TB
|
|
11
|
-
USER["钉钉协作事项 / 用户请求"] --> HOST["Claude Code / Codex / Agent Host"]
|
|
12
|
-
SKILL["全局 Basic Behavior\n何时说、问、静默"] --> HOST
|
|
13
|
-
HOST --> BOOT["bootstrap\n按需发现上下文"]
|
|
14
|
-
BOOT --> LOCAL["local-dir\n挂载 Markdown"]
|
|
15
|
-
BOOT --> REMOTE["dingtalk-doc\nDWS 拉取只读快照"]
|
|
16
|
-
HOST --> ROLE["岗位 / Workflow Skill\nFDE、周报、事故处理"]
|
|
17
|
-
HOST --> MODE{"有可信 Event?"}
|
|
18
|
-
MODE -- "否" --> DIRECT["Direct / Mounted Session\n按需使用 DWS"]
|
|
19
|
-
MODE -- "是" --> RUNTIME["Prepared Run Runtime\nSession / Run / Wait / Gate"]
|
|
20
|
-
RUNTIME --> ACTION["ack / reply / ask / silence"]
|
|
21
|
-
ACTION --> DWS["DWS 产品能力"]
|
|
22
|
-
DIRECT --> DWS
|
|
23
|
-
DRIVER["可选 Driver\n云端 / DWS listen / fixture"] -. "标准 Event" .-> RUNTIME
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Why:一个普通 Claude Code Session 已经有模型、工具和生命周期。再要求它先启动一个以 `listen` 为中心的运行时,会让基础行为依赖部署形态。真正可迁移的是 Skill;CLI 只在需要硬边界的地方介入。
|
|
27
|
-
|
|
28
|
-
## 四层职责
|
|
29
|
-
|
|
30
|
-
| 层 | 回答的问题 | 不负责什么 |
|
|
31
|
-
|---|---|---|
|
|
32
|
-
| Agent Definition / Storage | 我是谁、服务谁、长期内容放哪 | 不决定单次消息是否可外发 |
|
|
33
|
-
| Basic Behavior Skill | 何时响应、如何追问、何时沉默、记什么 | 不猜 API 参数和收件人 ID |
|
|
34
|
-
| Role / Workflow Skill | FDE 评价、周报、事故处理等业务方法 | 不扩大基础权限 |
|
|
35
|
-
| CLI + DWS | CLI 固定事务边界;DWS 调具体产品能力 | CLI 不复制整个 DWS 命令面 |
|
|
36
|
-
|
|
37
|
-
动作是否进入 `dingtalk-agent` 的判断标准:是否需要冻结作用域、身份、权限、幂等键、回读、状态迁移或跨产品组合。若都不需要,继续直接使用 DWS。
|
|
38
|
-
|
|
39
|
-
## 三种运行模式
|
|
40
|
-
|
|
41
|
-
### 1. Direct Session
|
|
42
|
-
|
|
43
|
-
没有 `CONTEXT.md`,也没有 Workspace manifest。全局 Skill 仍然生效;Agent 使用当前用户请求与宿主显式提供的上下文,不自动 init、不假造钉钉目标。
|
|
44
|
-
|
|
45
|
-
### 2. Mounted Session
|
|
46
|
-
|
|
47
|
-
通过 `bootstrap` 发现或拉取身份、记忆和知识:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
dingtalk-agent bootstrap --json
|
|
51
|
-
dingtalk-agent bootstrap --storage local-dir:/workspace --json
|
|
52
|
-
dingtalk-agent bootstrap --storage 'dingtalk-doc:<node-or-url>' --json
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
本地目录不复制;远端文档先用 `doc info` probe,只有 `ALIDOC/adoc` 才用 `doc read` 拉为隐藏只读快照。
|
|
56
|
-
|
|
57
|
-
### 3. Prepared Run
|
|
58
|
-
|
|
59
|
-
上游提供可信事件 envelope 后,运行时冻结目标、身份、Field、Skill 和动作预算。此时 Agent 只能通过 typed Broker 或四个 `act` 动作产生消息副作用。
|
|
60
|
-
|
|
61
|
-
```text
|
|
62
|
-
Driver → normalizeEvent → Session → Run → Agent → Action Gate → DWS → Receipt
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
它适合真实数字员工的自动运行,不是每个交互式 Agent Session 的强制前置。
|
|
66
|
-
|
|
67
|
-
## 新任务如何承接
|
|
68
|
-
|
|
69
|
-
这里借鉴 Claude Tag 的公开行为,但不复制任何逆向 Prompt。关键不是“每次先向人提问”,而是先在内部形成任务合同,再把真正阻塞的未知量交还给人:
|
|
70
|
-
|
|
71
|
-
```text
|
|
72
|
-
感知消息
|
|
73
|
-
→ 区分讨论 / 派活
|
|
74
|
-
→ UNDERSTAND(目标、交付物、范围、完成条件、权限)
|
|
75
|
-
→ CLARIFY(先查上下文;阻塞才问一个问题)
|
|
76
|
-
→ PLAN(复杂任务才建 checklist)
|
|
77
|
-
→ EXECUTE(在里程碑、方向改变、等待时更新)
|
|
78
|
-
→ VERIFY(工具结果 + 必要回读)
|
|
79
|
-
→ COMPLETE(结果、证据、遗留项、下一责任人)
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Why:如果把“先澄清”实现成固定追问,信息完整的任务也会被打断;如果完全不澄清,Agent 又会在对象、权限或完成条件不明时擅自执行。真正的分界是缺口是否阻塞安全执行。
|
|
83
|
-
|
|
84
|
-
Claude Tag 官方的线程模型与本项目高度一致:一个 thread 是一项工作的 session;长任务使用 checklist;结果回到原 thread;空闲后沙箱释放,新回复到来时重建沙箱继续。因此持久化的是显式 checkpoint 和外部成果,不是 JavaScript/LLM 隐藏栈。
|
|
85
|
-
|
|
86
|
-
## 机器 Setup 与 Workspace Init 为什么分开
|
|
87
|
-
|
|
88
|
-
机器首次使用从不会依赖全局 PATH 的入口开始:
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
npx --yes @xdxer/dingtalk-agent@beta setup
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
`setup` 只处理用户级 CLI、PATH、DWS 健康/认证和全局 Skill;它不初始化当前代码仓库。普通 Session 随后直接 `bootstrap`,只有需要长期 Workspace 或 Prepared Run 时才 `init`。三者分开,避免把“机器缺命令”“Agent 缺行为”和“当前目录需要持久状态”混成一个不可恢复的大初始化。
|
|
95
|
-
|
|
96
|
-
## Workspace 初始化为什么是可选的
|
|
97
|
-
|
|
98
|
-
全局安装一次:
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
dingtalk-agent skill install
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
物理结构:
|
|
105
|
-
|
|
106
|
-
```text
|
|
107
|
-
~/.agents/skills/dingtalk-basic-behavior/ canonical copy
|
|
108
|
-
~/.claude/skills/dingtalk-basic-behavior relative symlink
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
canonical 不链接 npm/node_modules,避免包升级、卸载或 npx cache 清理造成断链。安装有 ownership marker、内容 hash 和原子 staging;陌生同名目录不覆盖,本地修改不静默丢弃。
|
|
112
|
-
|
|
113
|
-
`dingtalk-agent init` 只在需要持久 Workspace/Prepared Run 时执行一次。它会创建最小 manifest、默认 Markdown 和机器策略,不再写项目的 `AGENTS.md`、`CLAUDE.md`、`.gitignore`、Ontology,也不复制 Skill。contextId 可省略,由目录名稳定派生。
|
|
114
|
-
|
|
115
|
-
## Storage 与 Context
|
|
116
|
-
|
|
117
|
-
公开 Provider:
|
|
118
|
-
|
|
119
|
-
```text
|
|
120
|
-
local-dir:<path> 直接挂载已有目录
|
|
121
|
-
local-md:<path> Workspace manifest 的单文件挂载
|
|
122
|
-
dingtalk-doc:<node-or-url> DWS 拉取在线文档快照
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
`contextId` 只保留为 Prepared Run 的兼容字段,不是普通 Session 必须理解或传入的参数。`bootstrap` 用 Storage canonical identity 派生内部 `scopeId`。
|
|
126
|
-
|
|
127
|
-
语义内容与控制状态必须隔离:
|
|
128
|
-
|
|
129
|
-
| 可放 Markdown / 钉钉文档 | 必须留在宿主 state store |
|
|
130
|
-
|---|---|
|
|
131
|
-
| 身份、长期记忆、知识、Skill 候选、业务 task checkpoint | EventIndex、Wait、锁、generation、幂等键、Action intent/receipt |
|
|
132
|
-
|
|
133
|
-
Why:Markdown 没有可靠 CAS;请求超时也不能证明写失败,不能承担并发控制。
|
|
134
|
-
|
|
135
|
-
Task checkpoint 只在跨 Run、等待依赖、已经产生副作用、需要接手或用户要求跟踪时创建。Prepared Run 使用 `$DTA_SESSION/memory/task.md`;Mounted Session 只写显式配置的本地 state root;远端可映射到一项任务一篇钉钉文档,但当前 `dingtalk-doc` bootstrap 仍只读,写入必须经过授权的 DWS/typed provider 并回读。
|
|
136
|
-
|
|
137
|
-
## Prepared Run 的四个公开对象
|
|
138
|
-
|
|
139
|
-
| 对象 | 生命周期 | 物理形态 | 作用 |
|
|
140
|
-
|---|---|---|---|
|
|
141
|
-
| Workspace | 长期、可选 | 一个目录或远端语义挂载 | 身份、内容、Field 和 Skill 清单 |
|
|
142
|
-
| Session | 一件事 | `.dingtalk-agent/sessions/.../<sessionId>` | 工作记忆、Skill 绑定、跨消息延续 |
|
|
143
|
-
| Run | 一次信号 | `Session/runs/<runId>` | 冻结输入;每次可启动新沙箱 |
|
|
144
|
-
| Action | 一次效果 | intent + attempt + receipt | `ack/reply/ask/silence` |
|
|
145
|
-
|
|
146
|
-
可选的 Task checkpoint 是 Session 的业务投影,不是第五个运行时控制对象。P0 直接令 `taskId = sessionId`;只有真实失败证明 Markdown checkpoint 不够可靠时,才考虑增加 provider-neutral 的 `task show/checkpoint` 两个命令。
|
|
147
|
-
|
|
148
|
-
Wait、Event Journal、dispatch outbox 和 reply target 是宿主内部实现,不要求 Agent 学习。
|
|
149
|
-
|
|
150
|
-
## 与异步进程模型的对应
|
|
151
|
-
|
|
152
|
-
| 进程隐喻 | 实体 |
|
|
153
|
-
|---|---|
|
|
154
|
-
| Heap | Field/Workspace 的身份、知识、Skill |
|
|
155
|
-
| Stack | Session working memory 与事项状态 |
|
|
156
|
-
| 一次函数调用 | Run |
|
|
157
|
-
| syscall | Action |
|
|
158
|
-
| await continuation | 宿主内部 Wait |
|
|
159
|
-
| interrupt | 新事件、心跳、显式取消 |
|
|
160
|
-
|
|
161
|
-
`ask` 后当前 Run 结束,沙箱释放;匹配事件产生新 Run,并回到原 Session。系统恢复业务 checkpoint,不序列化 JavaScript native stack。
|
|
162
|
-
|
|
163
|
-
## TypeScript 模块边界
|
|
164
|
-
|
|
165
|
-
```mermaid
|
|
166
|
-
flowchart TB
|
|
167
|
-
CLI["bin/dingtalk-agent.ts\ncomposition root"] --> SM["skill-manager.ts\n全局安装与漂移保护"]
|
|
168
|
-
CLI --> BS["bootstrap.ts\nStorage 水合"]
|
|
169
|
-
CLI --> DRIVER["driver.ts\n可选事件入口"]
|
|
170
|
-
DRIVER --> EVENTS["events.ts\nnormalize"]
|
|
171
|
-
EVENTS --> SESSIONS["sessions.ts\nSession / Run / dispatch"]
|
|
172
|
-
SESSIONS --> WORKSPACE["workspace.ts\nmanifest / mounts"]
|
|
173
|
-
SESSIONS --> SKILLS["skills.ts\nlocal → global → bundled resolver"]
|
|
174
|
-
SESSIONS --> WAITS["waits.ts\ncontinuation"]
|
|
175
|
-
CLI --> ACTIONS["actions.ts\nAction Gate"]
|
|
176
|
-
ACTIONS --> DWS["dws.ts\ntyped platform adapter"]
|
|
177
|
-
BS --> DWS
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Skill resolver 的优先级:
|
|
181
|
-
|
|
182
|
-
```text
|
|
183
|
-
Workspace override → ~/.agents/skills → Claude/legacy exposure → npm bundled
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
创建 Session 后立即冻结 Skill manifest;同一事项不会因全局 Skill 升级而中途变规则,新 Session 才使用新版本。
|
|
187
|
-
|
|
188
|
-
## FDE 教练实例
|
|
189
|
-
|
|
190
|
-
| 基础框架 | FDE 教练 |
|
|
191
|
-
|---|---|
|
|
192
|
-
| 全局 Basic Behavior | 先判断被 @/DM/普通群聊的响应资格 |
|
|
193
|
-
| Workspace/Storage | 菲迪身份、评价原则、学员资料 |
|
|
194
|
-
| Role Skill | 生成评价、等待确认、调整、发布的方法 |
|
|
195
|
-
| Session | “给张三本轮评价并等确认”这一件事 |
|
|
196
|
-
| Run | 每条新信号唤醒的一次沙箱 |
|
|
197
|
-
| Action | 收到、回复、追问、沉默 |
|
|
198
|
-
|
|
199
|
-
FDE 的评价模板和发布流程不进入全局 Basic Behavior;否则任何钉钉员工都会被污染成教练。
|
|
200
|
-
|
|
201
|
-
## 当前明确不做
|
|
202
|
-
|
|
203
|
-
- 不把 `listen` 作为 Agent 主进程;
|
|
204
|
-
- 不自动 init 任意代码仓库;
|
|
205
|
-
- 不复制整个 DWS 成另一套 CLI;
|
|
206
|
-
- 不把钉钉文档当锁或事务数据库;
|
|
207
|
-
- 不序列化语言运行时栈;
|
|
208
|
-
- 不允许在线 Run 自动扩大身份、权限或启用 Skill。
|
|
209
|
-
|
|
210
|
-
## 验收
|
|
211
|
-
|
|
212
|
-
```bash
|
|
213
|
-
npm run typecheck
|
|
214
|
-
npm run eval:contract
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
28 个确定性场景覆盖三条主链:setup/PATH/DWS/多客户端发现、Skill-first 安装/水合,以及 Prepared Run 的 Session、Wait、幂等、目标与回执。
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
# Skill-first / Optional Workspace 决策记录
|
|
2
|
-
|
|
3
|
-
- 日期:2026-07-15
|
|
4
|
-
- 状态:v1 已实现
|
|
5
|
-
- 范围:钉钉数字员工 Basic Behavior 蓝本
|
|
6
|
-
|
|
7
|
-
## 决策
|
|
8
|
-
|
|
9
|
-
### 1. 全局 Skill 是主入口
|
|
10
|
-
|
|
11
|
-
一次执行:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
dingtalk-agent skill install
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
之后每个 Claude Code/Codex Session 都能先应用 Basic Behavior。Workspace 不再承担“让 Skill 被发现”的职责。
|
|
18
|
-
|
|
19
|
-
Why:行为范式应该跟 Agent Host 走;一个工作目录可能是已有代码仓库、临时沙箱或远端挂载,不能要求它们都先脚手架化。
|
|
20
|
-
|
|
21
|
-
### 2. init 是一次性、可选且幂等
|
|
22
|
-
|
|
23
|
-
只有需要长期身份/记忆挂载或 Prepared Run runtime 时才执行:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
dingtalk-agent init
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
- `contextId` 可省略,由目录名稳定派生;
|
|
30
|
-
- 已存在时只检查,不重新绑定;
|
|
31
|
-
- 不写 `AGENTS.md`、`CLAUDE.md`、`.gitignore`、Ontology;
|
|
32
|
-
- 不复制 Skill;
|
|
33
|
-
- 只补齐 Workspace manifest、默认内容和 Prepared Run 所需的机器策略。
|
|
34
|
-
|
|
35
|
-
### 3. bootstrap 是每个 Session 的轻量准备动作
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
dingtalk-agent bootstrap --json
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
它只做发现和水合:
|
|
42
|
-
|
|
43
|
-
- 本地 `local-dir` 直接返回现有文件路径;
|
|
44
|
-
- 远端 `dingtalk-doc` 先 probe,再通过 DWS 拉成隐藏只读快照;
|
|
45
|
-
- 无内容时返回空 mounts,不自动 init;
|
|
46
|
-
- 不要求 Context ID。
|
|
47
|
-
|
|
48
|
-
### 4. Storage 介质和运行状态分离
|
|
49
|
-
|
|
50
|
-
语义 Storage:
|
|
51
|
-
|
|
52
|
-
```text
|
|
53
|
-
local-dir:<path>
|
|
54
|
-
local-md:<path>
|
|
55
|
-
dingtalk-doc:<node-or-url>
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
控制 State:
|
|
59
|
-
|
|
60
|
-
```text
|
|
61
|
-
EventIndex / Session / Run / Wait / Lock / Receipt
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
语义 Storage 可以是 Markdown 或钉钉文档;控制 State 必须由本地隐藏目录或未来的宿主数据库承担。原因是文档没有可靠 CAS,不能做并发协调。
|
|
65
|
-
|
|
66
|
-
### 5. Context ID 从 public requirement 降为 runtime compatibility
|
|
67
|
-
|
|
68
|
-
普通 Session 由 Storage canonical identity 派生内部 `scopeId`。Prepared Run 继续在历史记录和 dispatch 中保留 `contextId`,避免破坏现有 controller,但调用者不必在 init 时显式定制。
|
|
69
|
-
|
|
70
|
-
### 6. listen 是可选 Driver
|
|
71
|
-
|
|
72
|
-
云端事件源、本地 DWS、fixture 或 Agent Host 都可以驱动同一标准 Event:
|
|
73
|
-
|
|
74
|
-
```text
|
|
75
|
-
Driver → normalizeEvent → Session → Run → Action
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
`listen` 仍保留用于开发联调,但从主帮助和默认上手路径移出。
|
|
79
|
-
|
|
80
|
-
## Workspace 合同
|
|
81
|
-
|
|
82
|
-
显式 init 后的最小 manifest:
|
|
83
|
-
|
|
84
|
-
```json
|
|
85
|
-
{
|
|
86
|
-
"$schema": "dingtalk-agent/workspace@1",
|
|
87
|
-
"id": "fde-coach",
|
|
88
|
-
"contextId": "fde-coach",
|
|
89
|
-
"fieldId": "default",
|
|
90
|
-
"dws": { "profile": "", "expectedUserId": "" },
|
|
91
|
-
"skills": ["dingtalk-basic-behavior"],
|
|
92
|
-
"mounts": {
|
|
93
|
-
"profile": "local-md:WORKSPACE.md",
|
|
94
|
-
"memory": "local-md:MEMORY.md",
|
|
95
|
-
"knowledge": "local-md:knowledge/INDEX.md",
|
|
96
|
-
"skills": "local-dir:skills"
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
`skills[]` 声明逻辑名称,不再声明强耦合物理路径。解析顺序:Workspace override → canonical global → client exposure → npm bundled。新 Session 冻结解析结果。
|
|
102
|
-
|
|
103
|
-
## 两条执行路径
|
|
104
|
-
|
|
105
|
-
### 普通 Agent Session
|
|
106
|
-
|
|
107
|
-
```text
|
|
108
|
-
全局 Skill
|
|
109
|
-
→ 判断 Direct / Mounted
|
|
110
|
-
→ bootstrap 按需读 Storage
|
|
111
|
-
→ Role/Workflow Skill
|
|
112
|
-
→ 未包装产品能力按需使用 DWS
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
没有可信事件目标时,不能调用 Prepared Run 的 `act reply/ask`,也不能从正文猜钉钉 ID。
|
|
116
|
-
|
|
117
|
-
### Prepared Run
|
|
118
|
-
|
|
119
|
-
```text
|
|
120
|
-
可信 Event
|
|
121
|
-
→ normalize
|
|
122
|
-
→ Workspace / Field
|
|
123
|
-
→ Session-bound Skill snapshot
|
|
124
|
-
→ Run
|
|
125
|
-
→ ack / reply / ask / silence
|
|
126
|
-
→ Action Gate / DWS / Receipt
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
这一条链继续保留去重、outbox、Wait、generation 和目标防篡改;简化 public 入口不等于删除可靠性。
|
|
130
|
-
|
|
131
|
-
## CLI 行为边界
|
|
132
|
-
|
|
133
|
-
P0 只保留四个消息原语:
|
|
134
|
-
|
|
135
|
-
```text
|
|
136
|
-
ack 看到了且需要时间,不代表接单
|
|
137
|
-
reply 向 origin 交付结果
|
|
138
|
-
ask 问一个真正阻塞的问题并等待
|
|
139
|
-
silence 有意识地不打扰并留回执
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
下一组最值得增加的是带 source/scope 的 `memory propose/commit`,而不是 `doc write`、`todo create` 这类 DWS 别名。
|
|
143
|
-
|
|
144
|
-
新增 CLI 原子动作必须至少满足一项:
|
|
145
|
-
|
|
146
|
-
- 需要固定作用域或收件人;
|
|
147
|
-
- 需要权限/审批;
|
|
148
|
-
- 需要幂等键与不盲重试;
|
|
149
|
-
- 需要写后回读;
|
|
150
|
-
- 需要状态迁移;
|
|
151
|
-
- 需要跨产品组合。
|
|
152
|
-
|
|
153
|
-
## FDE 教练映射
|
|
154
|
-
|
|
155
|
-
| 框架 | FDE |
|
|
156
|
-
|---|---|
|
|
157
|
-
| Basic Behavior | 如何面对 @、DM、普通群聊、确认和停止 |
|
|
158
|
-
| Storage | 菲迪身份、评价原则、学员资料 |
|
|
159
|
-
| Role Skill | 生成评价 → 等确认 → 调整 → 发布 |
|
|
160
|
-
| Session | 针对某学员的一次评价事项 |
|
|
161
|
-
| Run | 每条事件的一次唤醒 |
|
|
162
|
-
| Wait | 等学员/教练确认 |
|
|
163
|
-
|
|
164
|
-
## 验收
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
dingtalk-agent skill status
|
|
168
|
-
dingtalk-agent bootstrap --json
|
|
169
|
-
npm run eval:contract
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
合同集当前包含 26 个场景,覆盖无 Workspace 全局安装与生命周期、无 init 本地/远端水合、远端类型闸门、Direct Session 外发闸门,以及可选/幂等 init。
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# 开源蓝本的差异、共同点与迁移决策
|
|
2
|
-
|
|
3
|
-
调研基于 2026-07-14 各仓库当前源码。结论不是 fork 某一个项目,而是 clean-room 组合:这些项目分别擅长社交行为、记忆、运行内核、人格或 Skill 包装,没有一个同时解决钉钉真实事件、DWS 权限和员工行为。
|
|
4
|
-
|
|
5
|
-
## 哪份提示词最值得参考
|
|
6
|
-
|
|
7
|
-
- **行为事实的第一基线**:Claude Tag 官方的 [How it works](https://claude.com/docs/claude-tag/concepts/how-it-works) 与 [Good habits](https://claude.com/docs/claude-tag/users/good-habits)。官方没有公开完整 system prompt,但明确了 thread=session、sandbox 可丢弃、长任务 checklist、原 thread 交付、definition of done 和 durable artifact。
|
|
8
|
-
- **只选一份“完整开源同事 Prompt”基线**:[`open-tag/src/daemon/prompt.ts`](https://github.com/fancyboi999/open-tag/blob/main/src/daemon/prompt.ts)。它覆盖原频道/线程回复、task claim、避免重复汇报、freshness hold、私密范围、长任务提醒、睡眠/唤醒和压缩前记忆。
|
|
9
|
-
- **最接近中文 IM 数字同事、最便于迁移内容**:AWS 样例的 [`prompts.py`](https://github.com/aws-samples/sample-claude-tag-in-lark/blob/main/larkclaudetag/app/larktag/prompts.py)。它对“当前消息与背景分离、工具成功后才能宣称完成、两阶段遗忘、定时任务确认、文件交付”写得最具体。
|
|
10
|
-
- **最好的单一事件剧本**:用户提供的 [Claude Tag onboarding gist](https://gist.github.com/coco98/c8ef8e2f02b1ef82dea0cd0e95283b97)。它只描述 `agent.joined` 一次 wake,不是完整系统提示词。
|
|
11
|
-
|
|
12
|
-
所以不会复制一段“万能 Prompt”:官方资料约束真实产品行为,`open-tag` 提供社交协议,gist 提供事件剧本写法,AWS 提供工具诚实性与记忆规则;目标、权限、幂等和回执全部下沉到 CLI/宿主。
|
|
13
|
-
|
|
14
|
-
## 核心差异
|
|
15
|
-
|
|
16
|
-
| 项目 | 核心抽象 | 强项 | 不能直接照搬 | 本项目迁移 |
|
|
17
|
-
|---|---|---|---|---|
|
|
18
|
-
| [Claude Tag 官方行为](https://claude.com/docs/claude-tag/concepts/how-it-works) | 一个 thread 一个 working session;每次活跃期构建 sandbox | 五步生命周期、可编辑 checklist、原 thread steer/交付、显式 definition of done、sandbox 与 durable state 分离 | 没有公开完整 Prompt 或运行源码;Slack 的 thread/权限模型不能直接等同钉钉 | Session/Run 映射、任务承接协议、checkpoint 与长期记忆分离 |
|
|
19
|
-
| [AWS Claude Tag in Lark](https://github.com/aws-samples/sample-claude-tag-in-lark) | 一个群一个共享上下文;薄 webhook + AgentCore runtime | 可运行的飞书链路;按群记忆、显式/自动记忆、两阶段遗忘、Skill、定时任务、旁听 | 仓库明确是 sample;Agent 使用 `bypassPermissions`;全局 Skill 当场生效不符合强治理 | 当前消息/背景分离、工具结果诚实、记忆分层、候选式进化 |
|
|
20
|
-
| [Anil Open Claude Tag](https://github.com/Anil-matcha/open-claude-tag) | `(workspace_id, channel_id)` 一个 Agent;`CHANNEL.md + MEMORY.md + skills + tools.toml` | Workspace 文件结构、共享频道上下文、记忆整理 turn | 当前 README 中多项记忆/Skill/ambient 能力仍在 roadmap;进程内锁和直接工具循环不足以做可靠运行内核 | Workspace 目录、按需 Skill、记忆 curation 思路,不以其 roadmap 当现成功能 |
|
|
21
|
-
| [TagIt](https://github.com/liliang-cn/tagit) | IM → daemon/queue → coding agent → Git worktree | CLI、事件存储、lease、恢复/重放、worktree、策略 broker、多 Agent 执行 | 本质是代码任务编排,不是通用社交员工;部分危险信号是事后文本分类;不迁移其高权限默认 | durable inbox/outbox、Run 管理、执行闸门和沙箱思想 |
|
|
22
|
-
| [open-tag](https://github.com/fancyboi999/open-tag) | 自建完整协作平台;持久 Agent workspace + wake/sleep + channels/DM/tasks | 最完整的同事协议、task claim、freshness hold、原线程汇报、prepare→human commit | 它替代 Slack/钉钉,而本项目必须适配真实钉钉;prompt 暴露通用消息 target,不适合作为 DWS 安全边界 | 社交协议、任务状态、忙时通知、freshness 再判断;目标改由宿主冻结 |
|
|
23
|
-
| [ElizaOS](https://github.com/elizaOS/eliza/blob/develop/packages/core/src/schemas/character.ts) | Character + room/world + action/provider | `bio/messageExamples/postExamples/style/topics` 人格建模;结构化 should-respond/action | Character 不能承担 ACL、目标、幂等和审批 | Identity/Voice/Examples 层,可作为 Field 的人格插件 |
|
|
24
|
-
| [Agent Skills](https://agentskills.io/specification) | `SKILL.md + scripts/references/assets` | 便携能力包、渐进披露、跨 Agent 复用 | 不定义事件、Session、记忆、权限或 Receipt | 标准 Skill 目录;Session 绑定 snapshot/hash,每个 Run 使用其投影 |
|
|
25
|
-
|
|
26
|
-
需要特别注意:此前所说 `CHANNEL.md + MEMORY.md + tools.toml` 指的是
|
|
27
|
-
[`Anil-matcha/open-claude-tag`](https://github.com/Anil-matcha/open-claude-tag),不要与其它同名仓库混淆。
|
|
28
|
-
|
|
29
|
-
## gist 里真正可迁移的内容
|
|
30
|
-
|
|
31
|
-
该 gist 的结构是 `<wake reason="dispatch">` + `<channel …>` + 带 `trust="principal"` 的系统消息。最有价值的不是具体英文文案,而是:
|
|
32
|
-
|
|
33
|
-
1. **信号与正文分层**:可信 wake 元数据决定当前是什么事件,普通消息不能升级权限。
|
|
34
|
-
2. **先分类协作场域**:PERSONAL / TEAM / BROADCAST 对应不同 response eligibility;广播场域默认安静。
|
|
35
|
-
3. **动作序列与预算显式化**:先做什么、最多读几次、错误是否重试、何时退出都写进事件合同。
|
|
36
|
-
4. **建议必须有证据**:主动提出的 pickup 要指向真的看过且仍未关闭的工作,不虚构待办或 permalink。
|
|
37
|
-
5. **offer 不等于 commitment**:先说“我可以接”,获得授权后才承诺执行。
|
|
38
|
-
6. **观察不等于插话**:默认在后台,只有被点名或配置的主动信号才发言。
|
|
39
|
-
|
|
40
|
-
不能迁移的是“TEAM/PERSONAL 永远发三条消息”。它是 onboarding 的产品剧本,放到普通钉钉消息会制造噪声。gist 也没有证明事件持久化、Session、身份核验、工具审批、幂等、送达回读或 Skill 发布治理。
|
|
41
|
-
|
|
42
|
-
## 新任务协议的来源组合
|
|
43
|
-
|
|
44
|
-
```text
|
|
45
|
-
UNDERSTAND / PLAN / checklist / original-thread delivery
|
|
46
|
-
← Claude Tag 官方公开生命周期
|
|
47
|
-
|
|
48
|
-
当前消息与背景分离 / 工具成功后才宣称完成
|
|
49
|
-
← AWS Lark sample prompts.py
|
|
50
|
-
|
|
51
|
-
task claim / freshness hold / 阶段更新 / 人工验收
|
|
52
|
-
← open-tag prompt.ts
|
|
53
|
-
|
|
54
|
-
Field 分类 / offer 不等于 commitment / 工具预算
|
|
55
|
-
← onboarding gist(仅作为未验证的逆向样本)
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
最终落成 `UNDERSTAND → CLARIFY → PLAN → EXECUTE → WAIT → VERIFY → COMPLETE`。其中 CLARIFY 是内部缺口判断,不是固定先问人;简单任务直接完成,多步或跨 Run 的任务才建立 checklist/checkpoint。
|
|
59
|
-
|
|
60
|
-
## 所有有效实现的共同点
|
|
61
|
-
|
|
62
|
-
1. 稳定作用域绑定频道、房间或 workspace,不绑定一次模型会话。
|
|
63
|
-
2. “感知到”与“应该发言”分离,先做 response eligibility。
|
|
64
|
-
3. 回复回到原频道/线程/DM,并区分确认、进度和结果。
|
|
65
|
-
4. 当前运行可以短暂,事件、任务、记忆、Skill 和审计必须外部持久化。
|
|
66
|
-
5. 上下文分层加载:身份/政策 → 当前事件 → 当前线程/任务 → 记忆 → 相关 Skill。
|
|
67
|
-
6. 记忆选择性写入并带作用域;旁听不等于自动记忆,更不等于自动插话。
|
|
68
|
-
7. 长任务需要队列、lease、恢复、重放、提醒和审计。
|
|
69
|
-
8. ID、ACL、审批、预算、幂等、外发和 Receipt 应由宿主强制,而不是要求模型“自觉”。
|
|
70
|
-
9. 新 Skill 先做 candidate,经评测和审批再发布;不能在当前 Run 热改规则。
|
|
71
|
-
10. 多个事件级行为合同,比一个超长 System Prompt 更可靠。
|
|
72
|
-
|
|
73
|
-
## dingtalk-agent 与它们的本质差异
|
|
74
|
-
|
|
75
|
-
```text
|
|
76
|
-
它们常见的抽象:一个频道 = 一个长期 Agent / 模型会话
|
|
77
|
-
|
|
78
|
-
dingtalk-agent:
|
|
79
|
-
Workspace(稳定 Context / 权限 / 知识 / 人格边界)
|
|
80
|
-
└── Session(同一件事,tenant + conversation + causal key)
|
|
81
|
-
└── Run(一次信号,可启动一次可丢弃沙箱)
|
|
82
|
-
└── ActionRequest(无 target)
|
|
83
|
-
└── Host Gate + DWS + Receipt
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
P0 中 Workspace 与 Field 一对一,可以对应一个群、一个 DM、一个项目或一组明确 selector,但不强制等于频道。Session 也不等于 conversation:同一个钉钉群里可以同时有多件事。沙箱只是一次 Run 的执行尝试,长期记忆和权限不放在里面。
|
|
87
|
-
|
|
88
|
-
最终组合是:
|
|
89
|
-
|
|
90
|
-
```text
|
|
91
|
-
Behavior Contract
|
|
92
|
-
= open-tag 社交协议
|
|
93
|
-
+ gist 事件剧本
|
|
94
|
-
+ AWS 工具诚实性/记忆规则
|
|
95
|
-
+ ElizaOS 人格与结构化响应
|
|
96
|
-
|
|
97
|
-
Runtime Kernel
|
|
98
|
-
= Workspace / Session / Run / Action
|
|
99
|
-
+ 宿主私有 Event Journal / Continuation / Receipt
|
|
100
|
-
+ TagIt 的队列、恢复、重放思想
|
|
101
|
-
+ open-tag 的 freshness hold 与 prepare/commit
|
|
102
|
-
|
|
103
|
-
Capability Package
|
|
104
|
-
= Agent Skills 规范
|
|
105
|
-
+ Session 级 Skill snapshot/hash + Run 投影
|
|
106
|
-
+ candidate → eval → approval → publish
|
|
107
|
-
```
|