@shgroup/dsh-serenity-hooks 1.73.0 → 1.75.0

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 (48) hide show
  1. package/README.md +18 -12
  2. package/dsh.plugin.json +2 -2
  3. package/lib/accounts-BHQbakUh.js +33 -0
  4. package/lib/{ccc-CZUOq3NY.js → ccc-CyYJL4F2.js} +9 -9
  5. package/lib/{ccc-roots-BhoA7G-0.js → ccc-roots-BVxn97dY.js} +4 -4
  6. package/lib/client.js +116 -1
  7. package/lib/cro/core.d.ts +11 -1
  8. package/lib/cro/log.d.ts +54 -4
  9. package/lib/guard/seam.d.ts +4 -4
  10. package/lib/host/effect.d.ts +1 -1
  11. package/lib/im/bridge.d.ts +3 -3
  12. package/lib/im/endpoint.d.ts +2 -2
  13. package/lib/im/guard.d.ts +1 -1
  14. package/lib/im/hook.d.ts +1 -1
  15. package/lib/im/inbound-event.d.ts +6 -6
  16. package/lib/im/route.d.ts +25 -3
  17. package/lib/index.d.ts +5 -5
  18. package/lib/index.js +680 -295
  19. package/lib/kernel/ccc-roots.d.ts +4 -4
  20. package/lib/kernel/ccc.d.ts +20 -19
  21. package/lib/kernel/ports.d.ts +1 -1
  22. package/lib/{message-source-ChyVfev9.js → message-source-JhN-qyfn.js} +2 -2
  23. package/lib/patches/opencode-provider.d.ts +1 -1
  24. package/lib/{profile-BIQ2widI.js → profile-Cz4oBXlI.js} +197 -65
  25. package/lib/{route-ItCgAsnz.js → route-COOFLTpU.js} +44 -6
  26. package/lib/seams/guards.d.ts +14 -14
  27. package/lib/seams/keeper.d.ts +1 -1
  28. package/lib/seams/lifecycle.d.ts +2 -2
  29. package/lib/{settings-UcwIPJhM.js → settings-CII0Y597.js} +40 -26
  30. package/lib/surface/faces.d.ts +1 -1
  31. package/lib/surface/http.d.ts +1 -1
  32. package/lib/surface/settings.d.ts +7 -7
  33. package/lib/surface/text.d.ts +3 -3
  34. package/lib/tools/config-docs.d.ts +71 -0
  35. package/lib/tools/container-admin.d.ts +24 -12
  36. package/lib/tools/msm/service.d.ts +18 -0
  37. package/lib/tools/trajectory-constraint-admin.d.ts +30 -0
  38. package/lib/trajectory/carrier.d.ts +1 -1
  39. package/lib/trajectory/core.d.ts +11 -1
  40. package/lib/trajectory/policy/files.d.ts +75 -0
  41. package/lib/trajectory/policy/profile.d.ts +41 -36
  42. package/lib/trajectory/policy/rules.d.ts +33 -20
  43. package/lib/trajectory/policy/window.d.ts +13 -13
  44. package/lib/trajectory/prompt.d.ts +12 -12
  45. package/lib/trajectory/rebuild.d.ts +2 -2
  46. package/lib/trajectory/session.d.ts +49 -49
  47. package/package.json +2 -2
  48. package/lib/tools/skiff-admin.d.ts +0 -30
@@ -7,7 +7,25 @@
7
7
  import type { JsonValue } from '../../kernel/json.js';
8
8
  type MsmAction = 'list' | 'exec' | 'register' | 'deregister' | 'check' | 'guide' | 'ccc-config' | 'catalog';
9
9
  export declare const MSM_ACTIONS: readonly MsmAction[];
10
+ /**
11
+ * ACC 能力目录(需求④ S142 用户拍板:"acc 配置各自做 guide 越来越多,整合成目录式使用指南")。
12
+ * 目录在前、详情各归各——**单一真相源**:本目录只索引"去哪个工具/子命令看详情",不复制详情
13
+ * (避免 container_admin/weixin-doctor 等 guide 全文重复 → 多真相源 → 失同步)。
14
+ * 后续新增功能只需在此加一行(低熵可演进)。
15
+ *
16
+ * 🔴 **2026-10-19 v1.75.0 起导出**:它是 `container_admin config docs catalog` 那一章的正文。
17
+ * `msm catalog` 动作**降为指针**(只指路,不再返回本常量)—— 否则同一份正文会有两个入口,
18
+ * 而"两个入口返回同一份内容"正是本目录自己反对的形态。
19
+ */
20
+ export declare const ACC_CATALOG = "\u2550\u2550\u2550 ACC Usage Catalog \u2550\u2550\u2550\nDirectory of ACC capabilities \u2014 each area lists where to go for details (guides live with their feature; this catalog only points).\n\n \u2460 \u8F68\u8FF9\u672C\u4F53 \u2192 cognitive_trajectory\uFF08list/show/create/use + rebuild \u8D85\u9650\u91CD\u5EFA + send-now \u5373\u65F6\u6295\u9012 + send-later \u672A\u6765\u4E00\u6B21\u6027\u5524\u9192\n + cro-guide CRO \u7F16\u5199\u6307\u5357\uFF09\n \u539F logbook \u5DF2\u5E76\u5165\uFF08v1.33 \u7528\u6237\u88C1\u51B3\uFF1A\u5E9F\u9664 logbook \u8BCD\uFF09\uFF1Bclose/archive \u5220\uFF08\u5F52\u6863\u8D70 container_fs mv\uFF09\uFF0C\n health/qa/summary \u5206\u522B\u5E76\u5165 use / list\uFF0Chook-develop-guide \u5E76\u8FDB container_admin msm guide\n \u2461 \u8BA4\u77E5\u8D28\u91CF\u6846\u67B6 \u2192 praxis\uFF08eap/neat/cce/ontology \u56DB\u5408\u4E00\u2014\u2014\u53EF\u5B9E\u8DF5\u7406\u8BBA\u6CE8\u5165\uFF0Csection \u6E10\u8FDB\u62AB\u9732\uFF0C\u65E0\u53C2\u5373\u76EE\u5F55\uFF09\n ontology\uFF08v1.52 D121\uFF1A\u672C\u4F53\u5DE5\u7A0B**\u5F15\u64CE**\u2014\u2014init/check/explain/verify/review/compliance\uFF1B\n \u4E0E praxis ontology \u7684\u5206\u5DE5 = \u90A3\u4E2A\u662F**\u65B9\u6CD5\u6587\u672C**\u3001\u8FD9\u4E2A\u662F**\u80FD\u8DD1\u7684\u90A3\u4E2A**\uFF09\n \u2462 \u5DE5\u5177\u4E0E\u6267\u884C \u2192 container_fs\uFF08\u5BB9\u5668\u6587\u4EF6\u7CFB\u7EDF 15 \u5B50\u547D\u4EE4\uFF09/ container_git\uFF08git\uFF09/ dashboard\uFF08health \u542B\u6CE8\u518C\u8868\u68C0\u67E5/time/wait\uFF09\n acc_msm \u5DF2\u5E76\u5165 msm\uFF08\u6267\u884C+\u53D1\u73B0\uFF09\u4E0E container_admin\uFF08\u7BA1\u7406\uFF09\u2014\u2014msm(\"<name>\", [\"<args>\"])\uFF1Binspect=true \u67E5\u7528\u6CD5\n cheap-worker\uFF08\u6742\u5DE5 agent \u7F16\u6392\u2014\u2014guide \u5B50\u547D\u4EE4\uFF1Acheap-worker guide\uFF09\n \u4E13\u5C5E\u5DE5\u5177\uFF08**\u9ED8\u8BA4\u5BF9\u6240\u6709 CCC \u9690\u85CF**\uFF0C\u53EA\u6709\u5728\u81EA\u5DF1 exclusiveTools \u91CC\u70B9\u540D\u7684 CCC \u53EF\u89C1\uFF09\u2192 acc-diag\uFF08\u8FD0\u884C\u6001\u8BCA\u65AD\uFF09\n \u2463 \u8F68\u8FF9\u7EA6\u675F\u4E0E\u5BF9\u5916\u9762 \u2192 container_admin config\uFF08\u8F68\u8FF9\u7EA6\u675F\u56DB\u52A8\u4F5C guide/validate/apply/list\u2014\u2014**\u539F role \u57DF\u5DF2\u5E76\u5165 config**\uFF0C\u65E7\u540D\u4F5C\u8FC7\u6E21\u522B\u540D\u4ECD\u53EF\u7528\uFF1B\u8BF4\u660E\u7C7B\u914D\u7F6E\u8D70**\u4E24\u5C42\u83DC\u5355** config docs \u76EE\u5F55 \uFF0F config docs <\u7AE0\u8282> \u8BE6\u60C5\uFF09\n \u5916\u90E8\u7A0B\u5E8F\u5316\u63A5\u5165\u7528\u5B98\u65B9 dsh --profile acp\n \uFF0B \u73B0\u6210 ACP \u5BA2\u6237\u7AEF\uFF1B\u672C\u63D2\u4EF6\u4E0D\u63D0\u4F9B ACP \u9762\n \u2464 \u81EA\u4E3B\u4E0E\u63A5\u5165 \u2192 cognitive_trajectory send-now\uFF08\u8DE8\u8F68\u8FF9\u7684**\u5373\u65F6**\u9012\u9001\uFF0C**\u4E0D\u6392\u961F**\uFF1Alive \u76EE\u6807\u5728\u8DD1\u5C31\u5F53\u573A\u6CE8\u5165\u5F53\u524D\u8F6E\u3001\u7A7A\u95F2\u5219\u7ACB\u5373\u8D77\u8F6E\uFF1B\u975E live \u51B7\u8F7D\u5165\u2014\u2014\u7B49\u6548\u4E8E\u76F4\u63A5 wake\uFF1B**\u6709\u540C\u6B65\u56DE\u6267**\uFF09\n cognitive_trajectory send-later\uFF08\u8DE8\u8F68\u8FF9\u7684\"\u672A\u6765\u65F6\u523B + \u4E00\u6761 message\"\uFF1Bfire-and-forget\uFF0C\u65E0\u56DE\u6267\u65E0\u56DE\u6536\uFF09\n weixin \u5FAE\u4FE1\u6865\uFF08\u914D\u7F6E/\u626B\u7801/\u8DEF\u7531/\u6D88\u606F hook\u2014\u2014CCC \u4FA7 weixin-doctor MSM\uFF1Amsm(\"weixin-doctor\", [\"guide\"])\uFF09\n \u2465 CCC \u914D\u7F6E\u603B\u89C8 \u2192 container_admin config docs config\uFF08\u6309\u7AE0\u8BE6\u60C5\u2014\u20149 \u6BB5\u5168\u8868\uFF09\n \u6216 container_admin msm ccc-config\uFF08\u540C\u4E00\u4EFD\u6B63\u6587\u7684\u65E7\u5165\u53E3\uFF0C\u4FDD\u7559\uFF09\n \u2466 \u6CE8\u518C\u8868\u4E0E\u5B89\u5168 \u2192 mech-registry.json \u7531 container_admin msm register/deregister \u7BA1\u7406\uFF08\u5199\u4FDD\u62A4\u2014\u2014\u4E0D\u53EF\u76F4\u63A5\u7F16\u8F91\uFF09\n dashboard health \u8F93\u51FA registry \u5B8C\u6574\u6027\u68C0\u67E5\uFF1B\u635F\u574F\u6062\u590D\u6307\u5F15\u89C1 health registry.issues\n CCC \u7EA7\u5F00\u5173\uFF1AexclusiveTools\uFF08\u58F0\u660E\u4E13\u5C5E\u5DE5\u5177\uFF09/ safeMode.blacklist\uFF08\u5199\u8DEF\u5F84\u9ED1\u540D\u5355\uFF09\n / safeMode.hiddenTools\uFF08**\u5B89\u5168\u6A21\u5F0F\u5F00\u542F\u671F\u95F4**\u989D\u5916\u9690\u85CF\u7684\u5DE5\u5177\uFF0Cv1.51.4\uFF09\n CCC \u7EA7 skill \u4F9B\u7ED9\uFF1AcognitiveTrajectory.skills\uFF08v1.44.0\u2014\u2014**\u672C CCC \u6BCF\u6761\u8F68\u8FF9\u90FD\u5E26**\uFF0C\u542B \u8F68\u8FF9\u7EA6\u675F\u4F1A\u8BDD\uFF1B\u4E0E\u8F68\u8FF9\u81EA\u5DF1\u7684 frontmatter \u58F0\u660E\u53D6\u5E76\u96C6\uFF09\n\n\u6BCF\u533A\uFF1A\u4E00\u53E5\u8BDD\u5B9A\u4F4D + \u8BE6\u7EC6\u5165\u53E3\uFF08\u5DE5\u5177\u540D / guide \u5B50\u547D\u4EE4\uFF09\u3002\u8BE6\u60C5\u6C38\u8FDC\u4EE5\u5BF9\u5E94\u5DE5\u5177\u7684 guide/ccc-config \u4E3A\u5355\u4E00\u771F\u76F8\u6E90\u3002\n";
10
21
  export declare const MSM_GUIDE = "MSM Development Manual (Mech & Semi-Mech framework)\n\n## What it is\nMSM = the executable-unit layer. Mech is pure TS with zero LLM reasoning; Semi-Mech is a TS framework + LLM decision points.\nMSM is ACC's deterministic executable-unit layer \u2014 all shell/exec operations go through MSM and cannot be bypassed.\n\n## Registering a new MSM (container_admin msm register)\n1. Write the script under <skill>/scripts/ (runnable via tsx; must include a main() CLI guard with an import.meta.url check)\n2. container_admin msm register --domain msm --action register <name> --skill <s> --path <script path relative to root> --category <mech|semi-mech> --description <desc>\n3. Auto-writes mech-registry.json (preserving the original format) + git commit (commits only the registry file)\n4. Validation: path must be inside root, script must exist, name must be globally unique\n\n## flag schema (v1)\nflags is a new-style object array for parameter validation and path-escape guarding:\n [{\"name\":\"output\",\"type\":\"string\",\"description\":\"output path\"},\n {\"name\":\"target\",\"type\":\"path\",\"description\":\"operation target (type:path enables in-root validation + symlink defense)\"},\n {\"name\":\"force\",\"type\":\"boolean\",\"description\":\"force mode\",\"default\":false}]\n- {name, type} format \u2014 new style, type:\"path\" enables the path-escape guard\n- {flag, description} format \u2014 old style, CLI flag description string\n- On registration, flags are passed via container_admin msm register --flags '<json>'\n\n## Script conventions\n- Top-of-file documentation: purpose / usage / exit codes\n- Exit codes: 0 success / 1 user / 2 system / 3 operator (per ACC protocol classification)\n- main() CLI guard (DC-M2): the script must start with\n if (import.meta.url === `file://${process.argv[1]}`) { main() }\n or an equivalent isMain / require.main === check \u2014 so vitest imports never trigger top-level code\n- A paired .test.ts or .spec.ts (DC-M1, vitest)\n- Business subprocess environment: SERENITY_ROOT / SERENITY_CCC / SERENITY_VERSION injected\n\n## Interaction & confirmation conventions (no blocking confirmation)\n- MSMs run in **user-less subprocesses** (spawn/execFile, 600s timeout) \u2014 **never** use\n readline / prompt / process.stdin etc. to block waiting for user input (it would hang until killed by the timeout)\n- When a second confirmation is needed: **directly return the confirmation request** (list the operation to perform and its impact + how to retry with the confirmation flag),\n returning a non-zero exit code (or an explicit hint)\n- After the agent confirms, **re-invoke the MSM with the confirmation flag** (e.g. --confirm / --yes / --force) to retry\n- Standard mode (two-phase):\n 1. First call: destructive/confirmation-requiring operation detected and no confirmation flag present \u2192 output the confirmation request (list operation/impact/rollback),\n exit non-zero (e.g. 1 user), **perform no changes**\n 2. After the agent evaluates, re-invoke: with the confirmation flag \u2192 execute and output the result\n- Applies to: delete/overwrite/push/batch operations and other irreversible or wide-impact operations\n- Anti-example (forbidden): readline waiting for user input, process.stdin.on('data') blocking waits\n (MSMs have no stdin interaction channel \u2014 they hang until the 600s timeout)\n\n## Quality checks (container_admin msm check, DC-M1~M4)\nDC-M1 has .test.ts/.spec.ts; DC-M2 has a main() guard (function main( / isMain / require.main === / import.meta.url);\nDC-M3 bidirectional: scripts unregistered + registry references missing scripts; DC-M4 path-type flags marked type:\"path\"\n\n## Self-description (protocol flags, first argument only)\nmsm(\"<name>\", [\"--list\"]) \u2014 list all MSMs\nmsm(\"<name>\", [\"--schema\", \"<n>\"]) \u2014 view a specific MSM's parameter schema\nmsm(\"<name>\", [\"--format=json\"]) \u2014 JSON output mode (remaining args passed through losslessly)\n";
22
+ /**
23
+ * CCC 配置参考(对齐 osp ccc-config action)。
24
+ *
25
+ * 🔴 **2026-10-19 起导出**:`container_admin config docs config` 的两层菜单把它作为
26
+ * 「config」章正文返回。**不另写一份**——同一段说明有第二份副本就会漂(本轨反复踩过)。
27
+ */
28
+ export declare const CCC_CONFIG_REFERENCE = "\u2550\u2550\u2550 CCC Configuration Reference \u2550\u2550\u2550\n\nCCC-level features are configured in .opencode/serenity.json.\nBelow are all available configuration sections.\n\n\u2500\u2500 1. cheap-worker.models \u2500\u2500\ncheap-worker\uFF08\u6742\u5DE5\uFF09\u5DE5\u5177\u53EF\u7528\u6A21\u578B\u767D\u540D\u5355\uFF08provider/model \u5217\u8868\uFF09\uFF1B\u672A\u914D\u7F6E\u65F6 cheap-worker \u62A5\u9519\u8981\u6C42\u914D\u7F6E\u3002\n\u7F3A\u7701\u6A21\u578B = models[0]\uFF08\u53EF\u7528 cheap-worker.defaultModel \u6307\u5B9A\uFF0C\u5FC5\u987B \u2208 models\uFF09\u3002\n**CCC \u5E94\u628A\u8BE5\u767D\u540D\u5355\u6307\u5411\u4F4E\u6210\u672C\u6A21\u578B**\u2014\u2014cheap-worker \u662F\u6279\u91CF\u6267\u884C\u901A\u9053\u3002\n\uD83D\uDD34 \u6A21\u578B**\u4E0D\u53EF\u7531\u8C03\u7528\u65B9\u6307\u5B9A**\uFF08\u5DE5\u5177\u65E0 model \u53C2\u6570\uFF09\u21D2 \u672C\u767D\u540D\u5355\u662F\u6A21\u578B\u9009\u62E9\u7684\u552F\u4E00\u6765\u6E90\u3002\n\n Behaviour\uFF082026-10-14\uFF1Abackground \u6A21\u5F0F\u5DF2\u5220\u9664\uFF0C\u53EA\u5269\u524D\u53F0\u59D4\u6D3E\uFF09:\n cheap-worker(task, [label])\uFF1A\u4E00\u6B21\u524D\u53F0\u59D4\u6D3E\uFF08\u5BBF\u4E3B\u59D4\u6D3E\u670D\u52A1 ctx.subagents.start(\"spawn\") +\n agentOptions \u6CE8\u5165\u6A21\u578B\uFF09\u2014\u2014\u4E0D\u5FAA\u73AF\u3001\u4E0D\u6821\u9A8C\u5B8C\u6210\u7801\u3001\u4E0D\u5199\u8FDB\u5EA6\u6587\u4EF6\uFF1B\u8FD4\u56DE\u5B50 agent \u6700\u7EC8\u6587\u672C\u3002\n cheap-worker(jobs=[{task,label?},...])\uFF1A\u5E76\u884C\u6247\u51FA\uFF0C\u4E0A\u9650 10\uFF08\u786C\u7F16\u7801\uFF09\uFF0C\u7ED3\u679C\u4FDD\u6301\u4F20\u5165\u987A\u5E8F\u3002\n \u21D2 **\u65E0 background \u6A21\u5F0F\u3001\u65E0\u8FDB\u5EA6\u6587\u4EF6\u3001\u65E0\u7EED\u8DD1**\uFF08owner 2026-10-14 \u4EE4\u300C\u5220\u9664\u540E\u53F0\u8FD0\u884C\u80FD\u529B\u300D\uFF09\u3002\n\n Old key\uFF08\u517C\u5BB9\uFF09:\n \u8BFB\u4E0D\u5230 \"cheap-worker\" \u65F6**\u56DE\u843D\u5230\u65E7\u952E \"handyman\"**\uFF08\u540C\u5F62\u72B6\uFF1Amodels / defaultModel\uFF09\u3002\n \u65E7\u952E\u91CC\u7684 \"maxRounds\"\uFF0F\"maxParallel\" \u5DF2\u968F background \u9000\u573A\uFF0C\u7559\u7740\u65E0\u5BB3\u4F46\u4E0D\u518D\u751F\u6548\u3002\n\n Config:\n { \"cheap-worker\": { \"models\": [\"provider/model-name\"] } }\n\n Example:\n { \"cheap-worker\": { \"models\": [\"minimax-cn-coding-plan/MiniMax-M3\"], \"defaultModel\": \"minimax-cn-coding-plan/MiniMax-M3\" } }\n\n\u2500\u2500 2. sessionKeeper.threshold / sessionKeeper.sessionMdMaxKB \u2500\u2500\ncognitive-trajectory-assistant\uFF08COGNITIVE-TRAJECTORY-ASSISTANT \u00B7 CHECKPOINT\uFF09\u63D0\u9192\u673A\u5236\u7684\u79EF\u5206\u9608\u503C\uFF08\u975E headless \u4E3B agent\uFF09\u3002\n\u6309\u5DE5\u5177\u8C03\u7528\u52A0\u6743 + \u8017\u65F6\u8BA1\u5206\uFF1B\u8FBE\u5230\u9608\u503C\u6CE8\u5165\u63D0\u9192\uFF0C\u8981\u6C42\u6A21\u578B\u56DE\u590D ACK \u7801\u3002\n\n Config:\n { \"sessionKeeper\": { \"threshold\": 150, \"sessionMdMaxKB\": 200 } }\n\n \u8BA1\u5206\uFF1Awrite/edit = 3\uFF0Ctask = 10\uFF0Cread/grep/glob/msm \u7B49 = 1\uFF0C\u65F6\u95F4 = 1/\u5206\u949F\n \u9ED8\u8BA4\uFF1A150\n\n \u25B8 sessionMdMaxKB\uFF08v1.31.1 \u65B0\u589E\uFF0Cv1.31.2 \u7F3A\u7701 100\u2192200\uFF09\uFF1A**\u6D3B\u8DC3 SESSION.md \u4F53\u79EF\u4E0A\u9650\uFF08KB\uFF0C\u7F3A\u7701 200\uFF1B0 = \u5173\u95ED\uFF09**\u3002\n \u8D85\u8FC7 \u2192 \u6CE8\u5165 [COGNITIVE-TRAJECTORY-ASSISTANT \u00B7 LOGBOOK COMPACTION] \u63D0\u9192\uFF1A\u6682\u505C\u5F53\u524D\u5DE5\u4F5C \u2192\n \u52A0\u8F7D eap\uFF08praxis eap\uFF09\u2192 \u6309 EAP \u5206\u5C42\u9AA8\u67B6\u91CD\u5199 SESSION.md\u3002\u56DB\u6761\u539F\u5219\uFF08ACC \u5185\u5D4C\uFF0C\u968F\u63D0\u9192\u7ED9\u51FA\uFF09\uFF1A\n \u2460 \u4FDD\u7559 EAP \u5206\u5C42\u9AA8\u67B6\uFF08\u4E0D\u538B\u6210\u65F6\u95F4\u6D41\u6C34\u8D26\uFF09\u2461 \u5185\u5BB9\u53EF\u5916\u79FB\u5230 references \u6587\u4EF6\n \uFF08AGENT_SESSIONS/<\u4F1A\u8BDD>/references/*.md\uFF0CSESSION.md \u7559\u94FE\u63A5\uFF09\u2462 \u5141\u8BB8\u6574\u5408/\u5220\u9664\u4E0D\u91CD\u8981\u4E8B\u9879\n \uFF08\u88AB\u53D6\u4EE3\u7684\u51B3\u7B56\u3001\u5DF2\u89E3\u51B3\u95EE\u9898\u3001\u4E2D\u95F4\u6001\uFF09\u2463 \u81EA\u4E3B\u88C1\u91CF\u6743\u5145\u5206\u5141\u8BB8\uFF08\u552F\u4E00\u786C\u8981\u6C42 = \u9AA8\u67B6 +\n \u672A\u51B3\u9879/\u51B3\u7B56\u7406\u7531/\u4E0B\u4E00\u6B65\u4ECD\u53EF\u91CD\u5EFA\uFF09\u3002\u8D85\u9650\u6BCF\u8F6E\u63D0\u9192\uFF1B\u8FDE\u7EED 3 \u8F6E\u672A\u91CD\u5199 \u2192 \u5347\u7EA7\u5F3A\u5236\u8BED\u6C14\uFF1B\n \u6587\u4EF6\u56DE\u5230\u9650\u5185 \u2192 \u81EA\u52A8\u505C\u6B62\uFF08\u81EA\u6108\uFF09\u3002\u8F68\u8FF9\u63D0\u9192**\u4E0D\u673A\u68B0\u963B\u65AD\u5DE5\u4F5C**\uFF08\u4E0E rebuild \u63D0\u9192\u540C\u65CF\uFF09\u3002\n\n\u2500\u2500 3. localstore.gitTrack \u2500\u2500\nlocalstore.json \u7684 git \u7B56\u7565\uFF1Aallow \u53EF\u63D0\u4EA4 / deny \u7981\u63D0\u4EA4\uFF08\u9ED8\u8BA4 deny\uFF09\u3002\ndeny \u65F6\u5199\u5165\u81EA\u52A8\u786E\u4FDD .gitignore \u542B\u8BE5\u6587\u4EF6\uFF08\u7269\u7406\u4FDD\u8BC1\uFF09\uFF0Ccontainer_git commit \u4F1A\u68C0\u67E5\u62D2\u7EDD\u3002\n\n Config:\n { \"localstore\": { \"gitTrack\": \"allow\" } }\n\n\u2500\u2500 4. hooks.autoRestoreSession \u2500\u2500\n\u4F1A\u8BDD\u81EA\u52A8\u6062\u590D\uFF08\u9ED8\u8BA4 true\uFF1B\u53D7 events \u95E8\u63A7\u2014\u2014\u4EC5\u6839\u4F1A\u8BDD + \u5DF2\u6709\u5BF9\u8BDD\u5386\u53F2\u624D\u6062\u590D\uFF09\u3002\n\n Config:\n { \"hooks\": { \"autoRestoreSession\": false } }\n\n\u2500\u2500 5. safeMode\uFF08\u9ED1\u540D\u5355 \uFF0B \u5F00\u542F\u671F\u95F4\u9690\u85CF\u7684\u5DE5\u5177\uFF09\u2500\u2500\nsafe-mode \u7531 WebUI \u5F00\u5173\u63A7\u5236\uFF08\u5199 .serenity-safe-on \u6807\u8BB0\uFF09\uFF1B\u9ED1\u540D\u5355\u8DEF\u5F84\u53D7 guards seam \u62E6\u622A\u3002\n\n \u25B8 blacklist\uFF1A\u5199\u8DEF\u5F84\u9ED1\u540D\u5355\uFF08\u540C\u4E0B Config\uFF09\u3002\n \u25B8 hiddenTools\uFF08v1.51.4\uFF0Cowner 2026-10-09 \u4EE4\uFF09\uFF1A**\u4EC5\u5728\u5B89\u5168\u6A21\u5F0F\u5F00\u542F\u671F\u95F4**\u989D\u5916\u4ECE\u6A21\u578B\u5DE5\u5177\n \u6E05\u5355\u9690\u85CF\u7684\u5DE5\u5177\uFF08ACC \u57FA\u7840\u8868\u6052\u9690 bash\uFF09\u3002\u6253\u5F00 safe-mode \u751F\u6548\u3001**\u5173\u6389\u5373\u5168\u90E8\u6062\u590D**\uFF1B\n \u6539\u672C\u952E**\u70ED\u751F\u6548**\uFF08\u4E0B\u4E00\u4E2A pre-step \u91CD\u7B97\uFF0C\u65E0\u9700\u91CD\u542F\uFF09\u3002\u58F0\u660E\u5728 CCC\uFF08D23\uFF09\u2014\u2014ACC \u4EE3\u7801\u91CC\n \u4E0D\u51FA\u73B0\u4EFB\u4F55\u5177\u4F53\u5DE5\u5177\u540D\u3002\n \u26A0\uFE0F \u5199\u4E00\u4E2A**\u672C CCC \u672A\u6CE8\u518C**\u7684\u540D\u5B57\u4F1A\u8BA9**\u6574\u6B21 restrict \u5931\u8D25**\uFF08DSH \u5951\u7EA6\u9010\u5B57\uFF1A\"unknown\n names \u2026 fail\"\uFF09\u21D2 \u6B64\u65F6**\u9000\u5316\u4E3A\u53EA\u9690\u85CF\u57FA\u7840\u8868**\u5E76\u5728\u65E5\u5FD7\u54CD\u4EAE\u62A5\u9519\uFF08\u7EDD\u4E0D\u56E0\u4E00\u4E2A\u9519\u540D\u4E22\u6389\n safe-mode \u7684\u6838\u5FC3\u9690\u85CF\uFF09\u3002\u8BCA\u65AD\uFF1A`AGENT_SESSIONS/.restrict-diag.json` \u7684 `denyByKey`\u3002\n \u26A0\uFE0F \u9690\u85CF = **\u4ECE schema \u79FB\u9664**\uFF08agent \u6839\u672C\u770B\u4E0D\u5230\u8BE5\u5DE5\u5177\uFF09\u21D2 \u522B\u628A skill/\u6587\u6863\u8FD8\u5728\u6559\u7684\u5DE5\u5177\u5199\u8FDB\u6765\u3002\n\n Config:\n { \"safeMode\": { \"blacklist\": [\".secrets/\"], \"hiddenTools\": [\"workflow\", \"job_kill\"] } }\n\n\u2500\u2500 6. \u8F68\u8FF9\u7EA6\u675F.roles\uFF08F4 \u8BA4\u77E5\u5B50\u96C6\u89D2\u8272\uFF09\u2500\u2500\n\u8F68\u8FF9\u7EA6\u675F\u89D2\u8272 = \u5168\u77E5\u5168\u80FD cognitive trajectory \u7684\u4EFB\u610F\u5B50\u96C6\uFF08CCC \u5B9A\u4E49\uFF09\u3002\u6BCF\u89D2\u8272\u72EC\u7ACB\u6A21\u578B + \u53CC\u767D\u540D\u5355\n\uFF08MSM \u767D\u540D\u5355 msms[] \u4E0E\u975E MSM \u5DE5\u5177\u767D\u540D\u5355 tools[]\uFF0C\u767D\u540D\u5355\u5916\u5168\u9690\u85CF\uFF1Bskill \u52A0\u8F7D\u6052\u53EF\u7528\uFF09\u3002\ncognitive trajectory \u7EAA\u5F8B\u5B50\u96C6\uFF08session/keeper/rebuild \u53C2\u4E0E\u9879\uFF09\u9ED8\u8BA4\u5168\u5173 = \u5B8C\u5168\u72EC\u7ACB\u3002\nsystemPrompt \u5185\u8054 \u6216 systemPromptFile\uFF08.md \u5F15\u7528\uFF0C\u63A8\u8350\uFF09\u2014\u2014\u89D2\u8272\u4F1A\u8BDD\u7684\u5B8C\u6574\u4EBA\u683C/\u8FB9\u754C\u63D0\u793A\u8BCD\u3002\nvalidate \u6821\u9A8C / apply \u751F\u6548 / list \u67E5\u770B\uFF1Acontainer_admin config <guide|validate|apply|list>\uFF08\u539F role \u57DF\u5DF2\u5E76\u5165 config\uFF0C\u65E7\u540D\u4F5C\u8FC7\u6E21\u522B\u540D\u4ECD\u53EF\u7528\uFF09\u3002\n\n Config:\n { \"\u8F68\u8FF9\u7EA6\u675F\": { \"roles\": {\n \"qa\": {\n \"model\": \"provider/model\",\n \"msms\": [\"web-search\", \"vlm-describe\"],\n \"tools\": [\"read\", \"grep\", \"glob\"],\n \"systemPromptFile\": \".opencode/skiff/qa.md\"\n } } } }\n\n\u2500\u2500 7. cognitive_trajectory\uFF08\u8F68\u8FF9 + \u5524\u9192\u6CE8\u518C\u8868\uFF0CD58\uFF09\u2500\u2500\nCCC \u7684\u4E00\u6761 cognitive trajectory = \u6301\u4E45\u8EAB\u4F53\uFF08SESSION.md\uFF09+ \u65F6\u95F4\u8F74\uFF08AGENT_SESSIONS/ \u76EE\u5F55 + \u5524\u9192\u6CE8\u518C\u8868\uFF09\u3002\n\u4E00\u4E2A CCC \u5185\u53EF\u591A\u6761\u5E76\u884C\uFF1B\u6761\u76EE\u5168\u90E8\u7531\u4EBA\u7C7B/agent \u663E\u5F0F\u767B\u8BB0\u3002\n\u26A0\uFE0F ACC \u4E0D\u518D\u63D0\u4F9B**\u5468\u671F\u81EA\u5524\u9192**\uFF08\u539F autopilot\uFF0C2026-09-15 \u6574\u6BB5\u9000\u573A\uFF1A\u673A\u5236/\u65F6\u949F/container_admin autopilot\n\u57DF/\u9762\u677F\u533A\u5757\u4E00\u5E76\u5220\u9664\uFF09\u3002\u81EA\u4E3B\u5DE1\u822A\u6539\u7531 CCC \u81EA\u5DF1\u9A71\u52A8\uFF08home-serenity \u4FA7 msm autopilot-round \u6BCF\u8F6E\u81EA\u6392\u4E0B\u4E00\u8F6E\uFF0C\n\u771F\u76F8\u6E90 = S151 SESSION.md \u00A71/\u00A71b/\u00A71c\uFF09\u3002**\u672C\u8F6E\u7684 cognitiveTrajectory.autopilot \u914D\u7F6E\u6BB5\u4FDD\u7559**\uFF08\u89C1\u4E0B\u8868\uFF09\u2014\u2014\n\u5B83\u73B0\u7531 **CCC \u4FA7\u811A\u672C**\u8BFB\u53D6\uFF0CACC \u4E0D\u518D\u6D88\u8D39\u8BE5\u6BB5\u3002\n\u5524\u9192\u6CE8\u518C\u8868\uFF08cognitive_trajectory send-later\uFF09\uFF1A\u5524\u9192 = \u672A\u6765\u65F6\u523B + \u4E00\u6761 message\uFF0C\u53EF\u5524\u9192\u81EA\u5DF1\u6216\u522B\u7684 cognitive trajectory\uFF1B\n\u843D\u70B9 AGENT_SESSIONS/wake-registry.json\uFF0C\u4E2D\u5FC3\u8C03\u5EA6\u5668\u5230\u70B9\u6295\u9012\uFF08fire-and-forget\uFF1B\u65E0\u56DE\u6267\u3001\u65E0\u56DE\u6536\uFF09\u3002\n\u8FD0\u884C\u6001\u8BCA\u65AD\uFF08ACC \u8D1F\u8D23\u4EBA\u4E13\u7528\uFF09\uFF1Aacc-diag\uFF08\u2460 live \u8FD0\u884C\u6001 / \u2460b \u5524\u9192\u65F6\u949F / \u2462 \u5524\u9192\u6CE8\u518C\u8868\uFF09\u3002\n\n\u25B8 cognitiveTrajectory.skills\uFF08v1.44.0\uFF0C**CCC \u7EA7 skill \u4F9B\u7ED9**\uFF1Bowner \u4EE4 2026-09-20\u300C\u8981\u6C42\u5B9E\u73B0\u6211\u7684\u8BC9\u6C42\u2026\u2026\n \u6CE8\u5165\u662F\u52A8\u6001\u6CE8\u5165\u5C31\u884C\uFF1Bcreate \u5148\u4E0D\u89E6\u53D1\u5427\uFF1B**\u8F68\u8FF9\u7EA6\u675F\u4E5F\u652F\u6301**\u300D\uFF09\uFF1A\n **\u672C CCC \u7684\u6BCF\u6761\u8F68\u8FF9\u90FD\u5E26\u8FD9\u4E9B skill**\u2014\u2014\u58F0\u660E\u7684 skill \u5168\u6587\u5728\u8BE5\u8F68\u8FF9**\u88AB\u7ED1\u5B9A\u671F\u95F4**\u6CE8\u5165\u7CFB\u7EDF\u63D0\u793A\u8BCD\n \uFF08**\u52A8\u6001\u6CE8\u5165**\uFF1A\u6BCF\u8BF7\u6C42\u91CD\u65B0\u6C42\u503C\u3001\u4E0D\u7F13\u5B58 \u21D2 \u6539\u914D\u7F6E\u6216\u6539 frontmatter **\u5373\u65F6\u751F\u6548**\uFF0C\u65E0\u9700\u91CD\u65B0 use\u3001\u65E0\u9700\u91CD\u542F\uFF09\u3002\n \u4E24\u6761\u58F0\u660E\u6765\u6E90**\u5E76\u96C6**\uFF08\u4E0D\u662F\u4E8C\u9009\u4E00\uFF09\uFF1A\u672C\u952E **cognitiveTrajectory.skills**\uFF08\u5BB9\u5668\u7ED9\u7684\u5E95\u5EA7\uFF0C**\u5728\u524D**\uFF09\n \uFF0B \u8F68\u8FF9\u81EA\u5DF1 SESSION.md \u9876\u90E8 frontmatter \u7684 skills:\uFF08\u8FD9\u6761\u8F68\u8FF9\u989D\u5916\u7684\uFF0C**\u8FFD\u52A0**\uFF1B\u540C\u540D\u53BB\u91CD\uFF09\u3002\n \u2705 **\u542B \u8F68\u8FF9\u7EA6\u675F\u89D2\u8272\u4F1A\u8BDD**\uFF08\u65C1\u8DEF\u7684\u662F ACC \u8EAB\u4EFD\u4E0E\u7EAA\u5F8B\uFF1Bskill \u662F\"\u5DE5\u4F5C\u8D44\u6599\"\uFF0C\u7167\u7ED9\uFF09\u3002\n \u5B88\u536B\uFF1A\u540D\u5B57\u5148\u8FC7\u5B89\u5168\u6821\u9A8C\u624D\u7528\u4E8E\u62FC\u8DEF\u5F84\uFF08\u9632\u7A7F\u8D8A\uFF09\uFF5C**\u5408\u5E76\u540E**\u7EDF\u4E00 32 KB \u4E0A\u9650\u622A\u65AD\uFF5C\u627E\u4E0D\u5230\u54CD\u4EAE\u5199 [\u7F3A\u5931]\u3002\n \u26A0\uFE0F \u4E0E create **\u65E0\u5173**\uFF08create \u523B\u610F\u4E0D\u593A\u7ED1\u5B9A\uFF0CU6\uFF09\u21D2 \u6CE8\u5165\u7684\u95E8\u662F\"**\u5B58\u5728\u7ED1\u5B9A**\"\uFF08cognitive_trajectory use\uFF09\u3002\n \u5931\u8D25\u8BED\u4E49\uFF1A\u672A\u914D\u7F6E / \u5B57\u6BB5\u7F3A\u5931 / \u914D\u7F6E\u635F\u574F \u21D2 **\u7A7A\u6570\u7EC4**\uFF08= \u65E0 CCC \u7EA7\u4F9B\u7ED9\uFF1B\u8F68\u8FF9\u7EA7\u58F0\u660E\u7167\u65E7\u751F\u6548\uFF09\u3002\n \u5F52\u5C5E\uFF08D23\uFF09\uFF1A**\u673A\u5236\u5728 ACC**\uFF08\u8BFB\u53D6 + \u5408\u5E76 + \u6CE8\u5165 + \u5B88\u536B\uFF09\uFF0C**\u58F0\u660E\u5728 CCC**\uFF08\u672C\u952E\uFF09\u3002\n\n Config:\n { \"cognitiveTrajectory\": {\n \"skills\": [\"acc-session\", \"cce\"], // v1.44.0\uFF1A\u672C CCC \u7684\u6BCF\u6761\u8F68\u8FF9\u90FD\u5E26\uFF08\u542B \u8F68\u8FF9\u7EA6\u675F\u4F1A\u8BDD\uFF09\n \"autopilot\": { // \u539F autopilotTrajectory \u6BB5\uFF0C\u5B57\u6BB5\u4E0D\u53D8\uFF08\u65E7\u952E\u4ECD\u56DE\u9000\u8BFB\uFF09\n \"enabled\": true,\n \"intervalHours\": 2,\n \"session\": \"S151\",\n \"biasProvider\": \"autopilot-bias.ts\",\n \"topPrompt\": \"\u672C\u8F68\u8FF9\u6838\u5FC3\u76EE\u6807/\u7EAA\u5F8B/\u8D28\u91CF\u8981\u6C42\uFF08CCC \u81EA\u586B\uFF0C\u9632\u6F02\u79FB\uFF09\",\n \"avoidWakeHours\": { \"start\": 8, \"end\": 18 }\n } } }\n\n\u2500\u2500 8. weixin\uFF08\u5FAE\u4FE1\u6865 F4c-3\uFF0C\u542B\u6D88\u606F\u8BB0\u5F55 hook\uFF09\u2500\u2500\nCCC \u7EA7\u5FAE\u4FE1\u4E2A\u4EBA\u53F7\u63A5\u5165\uFF08iLink \u534F\u8BAE\uFF09\uFF1Adsh \u4E00\u8FDB\u7A0B\u591A CCC\uFF0C\u6BCF CCC \u72EC\u7ACB\u5BF9\u63A5\u5FAE\u4FE1\u6865\u3002\n\u8D26\u53F7/\u8DEF\u7531/\u5F00\u5173\u5728\u6B64\u6587\u4EF6\uFF1B**bot_token \u51ED\u636E\u5728 CCC localstore credential scope**\n\uFF08\u626B\u7801\u7ED1\u5B9A\u540E\u81EA\u52A8\u5199\u5165\uFF0C\u6C38\u4E0D\u8FDB git \u660E\u6587\u9762\uFF09\u3002\n\u8DEF\u7531 user \u2192 role\uFF1Aexact \u4F18\u5148\uFF0C* \u901A\u914D\u515C\u5E95\uFF1Brole \u5FC5\u987B \u2208 \u8BE5 CCC \u8F68\u8FF9\u7EA6\u675F.roles\u3002\n\u9762\u677F\uFF08WebUI \u8BBE\u7F6E \u2192 \u5FAE\u4FE1\u6865\uFF09\u53EF\u626B\u7801\u7ED1\u5B9A/\u79FB\u9664\u8D26\u53F7/\u7F16\u8F91\u8DEF\u7531\uFF1Bmsm(\"weixin-doctor\", [\"status\"|\"diag\"|\"verify\"|\"guide\"]) \u6392\u67E5 + \u5927\u800C\u5168\u6307\u5357\u3002\u51ED\u636E\u4E3B\u52A8\u67E5\u770B\uFF1Alocalstore get WEIXIN_<ACCOUNT>_TOKEN\u3002\n \u25B8 \u4E3B\u52A8\u53D1\u9001\uFF08v1.31.0\uFF1A**ACC \u5DE5\u5177 im-bridge**\uFF09\uFF1A\u8C03\n im-bridge({channel:\"weixin\", action:\"send\", user:\"<\u522B\u540D|id>\", text:\"<\u6587\u672C>\"}) \u7ED9\u7528\u6237\u53D1\u6D88\u606F\u2014\u2014\n **\u5DE5\u5177\u53EA\u80FD\u64CD\u4F5C\u672C\u4F1A\u8BDD CCC**\uFF08\u65E0 ccc \u53C2\u6570\uFF0C\u9632\u8BEF\u53D1\u4ED6\u5BB9\u5668\uFF09\u2192 weixin-bridge.sendProactiveText \u2192\n \u6210\u529F\u540E\u89E6\u53D1 outgoing hook\uFF08source=\"proactive\"\uFF09\u3002\u6587\u4EF6\u7528 action:\"send-file\" + file:\"<CCC \u5185\u8DEF\u5F84>\"\n \uFF08\u9003\u9038/\u7F3A\u5931/\u8D85 20MB \u62D2\u7EDD\uFF09+ \u53EF\u9009 caption\u3002**\u53EF\u89C1\u6027**\uFF1A\u672C CCC \u914D\u7F6E\u4E86 IM \u901A\u9053\n \uFF08weixin.enabled=true\uFF09\u624D\u51FA\u73B0\u5728\u6A21\u578B\u5DE5\u5177\u6E05\u5355\u91CC\uFF1B\u672A\u914D\u7F6E \u2192 \u7531 guards \u9010 agent\n tools.restrict({deny:['im-bridge']}) \u79FB\u9664\uFF08\u4E0D\u662F\"\u770B\u5F97\u5230\u4F46\u88AB\u62D2\"\uFF09\u3002\u8F68\u8FF9\u7EA6\u675F\u89D2\u8272\u53E6\u9700\u5728\n roles.<role>.tools \u767D\u540D\u5355\u5217\u51FA im-bridge\u3002\n \u5386\u53F2\uFF08v1.30.9~v1.30.x\uFF09\uFF1ACCC \u4FA7 MSM weixin-send\uFF08\u8D70 loopback HTTP \u5165\u53E3 3082\uFF09\u2014\u2014\n v1.31.0 \u5DF2\u9000\u5F79\uFF08\u811A\u672C\u5220\u9664 + \u6CE8\u518C\u8868\u6CE8\u9500\uFF09\uFF1B3082 \u5165\u53E3\u4FDD\u7559\u7ED9**\u975E agent \u8C03\u7528\u8005**\u3002\n\n \u25B8 weixin.autoReplyWithLastMessage\uFF08v1.30.10\uFF0C\u5173\u95ED\u6865\u7684\u81EA\u52A8\u8F93\u51FA\uFF09\uFF1A\n \u7F3A\u7701 true = \u73B0\u72B6\uFF1A\u6865\u5728 agent \u4E00\u8F6E\u7ED3\u675F\u540E\u628A**\u6700\u7EC8 assistant \u6587\u672C**\u81EA\u52A8\u56DE\u53D1\u7528\u6237\uFF08source=\"reply\"\uFF09\u3002\n \u663E\u5F0F false = \u5173\u95ED\uFF1A\u6865**\u4E0D\u518D\u8F6C\u53D1\u6700\u7EC8\u6587\u672C**\uFF0C\u8F93\u51FA\u6743\u4EA4\u7ED9 agent\u2014\u2014\u6BCF\u8F6E\u5728\u7528\u6237\u6D88\u606F**\u672B\u5C3E**\u8FFD\u52A0\n **\u673A\u5236\u6807\u8BB0** [serenity:weixin-manual-output] + \u4E00\u884C\u5DF2\u586B\u597D\u53C2\u6570\u7684 im-bridge \u8C03\u7528\n \uFF08\u8D26\u53F7/\u7528\u6237 id\uFF09\uFF0Cagent \u81EA\u5DF1\u51B3\u5B9A\u53D1\u4EC0\u4E48\u3001\u53D1\u51E0\u6761\uFF08\u5168\u90E8\u8BB0 source=\"proactive\"\uFF09\u3002\n **ACC \u53EA\u7ED9\u673A\u5236\u4E0E\u6570\u636E\uFF0C\u7EAA\u5F8B\u63AA\u8F9E\u5F52 CCC**\uFF08v1.30.16\uFF09\uFF1A\u600E\u4E48\u5199/\u5FC5\u987B\u600E\u4E48\u505A/\u540E\u679C\u662F\u4EC0\u4E48\u5199\u5728\n CCC \u89D2\u8272\u63D0\u793A\u8BCD\u6587\u4EF6\u91CC\uFF08\u5982 .opencode/skiff/<role>.md\uFF09\uFF0C\u53EF\u70ED\u6539\uFF08v1.30.15 \u8D77\u89D2\u8272\u63D0\u793A\u8BCD\u70ED\u91CD\u8F7D\uFF09\u3002\n \u673A\u68B0\u95F8\u95E8\uFF08v1.30.16\uFF09\uFF1A\u672C\u8F6E turn \u7ED3\u675F\u4ECD\u672A\u6210\u529F\u8C03\u7528 im-bridge\uFF08send / send-file\uFF1B\u517C\u5BB9\u65E7\n msm(\"weixin-send\") \u5F62\u6001\uFF09\u2192 agent \u88AB\u6253\u56DE\uFF08\u22642 \u6B21\uFF0C\u63D0\u793A = \u6807\u8BB0 + \u4E8B\u5B9E\uFF09\uFF1B\u8FBE\u4E0A\u9650\u653E\u5F03\u5E76\u54CD\u4EAE\u544A\u8B66\u3002\n \u5931\u8D25\u8C03\u7528\u4E0D\u7B97\u5DF2\u9001\u8FBE\u3002\n \u8BED\u4E49\u8FB9\u754C\uFF08\u7528\u6237\u62CD\u677F\uFF09\uFF1A\u53EA\u5173\u6700\u7EC8\u6587\u672C\uFF1B\u7CFB\u7EDF\u7C7B\u6D88\u606F\uFF08\u65B0\u5BF9\u8BDD\u901A\u77E5 / \u8BED\u97F3\u65E0\u6CD5\u89E3\u6790\u63D0\u793A\uFF09\u4FDD\u7559\uFF1B\n typing \u6307\u793A\u4E0E incoming hook \u4E0D\u53D7\u5F71\u54CD\u3002\n\n \u25B8 weixin.fallbackOnNoSend\uFF08v1.30.17\uFF0C\u624B\u52A8\u6A21\u5F0F\u7684**\u515C\u5E95**\uFF1B\u7F3A\u7701 false\uFF09\uFF1A\n \u4EC5\u5728 autoReplyWithLastMessage=false \u65F6\u751F\u6548\u3002true \u2192 \u4E00\u8F6E\u7ED3\u675F\u65F6\u82E5 agent **\u4E00\u6B21\u90FD\u6CA1\u6210\u529F**\n \u8C03\u7528\u8F93\u51FA\u5DE5\u5177\uFF08\u95F8\u95E8\u6253\u56DE\u7528\u5C3D\uFF09\uFF0C\u6865\u628A\u8BE5\u8F6E\u6700\u7EC8\u6587\u672C\u8F6C\u53D1\u7ED9\u7528\u6237\uFF08\u8BB0\u5F55 source=\"reply-fallback\"\uFF0C\n \u65E5\u5FD7\u7559\u54CD\u4EAE\u544A\u8B66\uFF09\u2014\u2014\u4FDD\u8BC1\"\u4E0D\u4E22\u6D88\u606F\"\u3002agent \u81EA\u5DF1\u53D1\u8FC7 \u2192 \u4E0D\u515C\u5E95\uFF08\u8F93\u51FA\u6743\u4ECD\u5728 agent\uFF09\u3002\n \u4E3A\u4EC0\u4E48\u9700\u8981\uFF08\u5B9E\u8BC1\uFF09\uFF1Av1.30.16 \u95F8\u95E8\u4F1A\u6253\u56DE \u22642 \u6B21\uFF0C\u4F46\u5B9E\u6D4B\u67D0\u6A21\u578B\u5728**\u5BD2\u6684\u7C7B\u6D88\u606F**\u4E0A\u8FDE\u7EED 4 \u8F6E\u3001\n \u8DE8 3 \u7248 CCC \u63D0\u793A\u8BCD\u4ECD\u4E0D\u8C03\u5DE5\u5177 \u2192 \u6253\u56DE\u7528\u5C3D\u540E\u7528\u6237\u4EC0\u4E48\u90FD\u6536\u4E0D\u5230\uFF1B\u63D0\u793A\u8BCD\u4E0E\u95F8\u95E8\u5747\u5DF2\u6392\u9664\u3002\n \u4EE3\u4EF7\uFF08\u663E\u5F0F\uFF09\uFF1A\u89D2\u8272\u5931\u53BB\"\u6545\u610F\u9759\u9ED8\"\u80FD\u529B\uFF08\u5B83\u603B\u4F1A\u4EA7\u51FA\u4E00\u6BB5\u6700\u7EC8\u6587\u672C\uFF09\u2192 \u9700\u4E25\u683C\u9759\u9ED8\u7684\u89D2\u8272\u4FDD\u6301\u7F3A\u7701\u3002\n \u4E09\u6001\uFF1A\u2460 autoReplyWithLastMessage=true\uFF08\u7F3A\u7701\uFF09\u6865\u603B\u662F\u56DE\u53D1\uFF1B\u2461 =false + fallbackOnNoSend=true\n = agent \u4F18\u5148\u3001\u6865\u515C\u5E95\uFF08\u63A8\u8350\uFF09\uFF1B\u2462 \u4E24\u8005\u7686 false\uFF08\u7F3A\u7701\uFF09= \u4E25\u683C\u9759\u9ED8\uFF08v1.30.10 \u8BED\u4E49\uFF09\u3002\n \u26A0\uFE0F \u515C\u5E95\u53EA\u5728**\u95F8\u95E8\u88C5\u914D\u6210\u529F**\u65F6\u751F\u6548\uFF08\u672A\u88C5\u914D\u5219\u65E0\u6CD5\u5224\u5B9A\u662F\u5426\u53D1\u9001\u8FC7 \u2192 \u4E0D\u5192\u91CD\u590D\u53D1\u9001\u98CE\u9669\uFF09\u3002\n\n Config:\n { \"weixin\": {\n \"enabled\": true,\n \"hook\": \"scripts/weixin-message-hook.ts\",\n \"autoReplyWithLastMessage\": true,\n \"fallbackOnNoSend\": false,\n \"accounts\": [{ \"accountId\": \"wechat-1\", \"name\": \"\u5BB6\u5EAD\u52A9\u624B\", \"enabled\": true }],\n \"routes\": [{ \"user\": \"*\", \"role\": \"my-role\" }]\n } }\n\n \u25B8 weixin.hook\uFF08\u6D88\u606F\u8BB0\u5F55 hook\uFF0Cv1.27.13\uFF09\uFF1A\n \u5FAE\u4FE1\u6865\u6BCF\u6536/\u53D1\u4E00\u6761\u6D88\u606F\u89E6\u53D1\u4E00\u6B21 CCC \u81EA\u5199\u811A\u672C\uFF0C\u7531 CCC \u81EA\u884C\u6301\u4E45\u5316\u4FDD\u5B58\uFF08\u5B58\u54EA/\u5B58\u6210\u4EC0\u4E48\n /\u662F\u5426\u5165\u5E93\u5168\u5F52 CCC\u2014\u2014ACC \u4E0D\u7ED1\u5B9A\u5B58\u50A8\uFF09\u3002\u672A\u914D\u7F6E hook \u2192 \u96F6\u53D8\u5316\uFF08\u4E0D\u89E6\u53D1\uFF09\u3002\n\n \u89E6\u53D1\uFF08\u53CC\u5411\uFF09\uFF1A\n incoming = \u7528\u6237 \u2192 bot\uFF1A\u8DEF\u7531\u547D\u4E2D\u540E\u3001\u5A92\u4F53\u843D\u76D8\u540E\u89E6\u53D1\uFF08\u6587\u672C\u542B\u8BED\u97F3\u8F6C\u5199\uFF1B\u5A92\u4F53\u5E26\u843D\u76D8 relPath\uFF09\n outgoing = bot \u2192 \u7528\u6237\uFF1A\u53D1\u9001\u6210\u529F\u540E\u89E6\u53D1\uFF08reply = \u7528\u6237\u5B9E\u9645\u6536\u5230\u7684\u7EAF\u6587\u672C\uFF0C\u5DF2\u5265\u79BB think\uFF09\n \u00B7 source=\"reply\"\uFF08\u7F3A\u7701\uFF09= \u56DE\u590D\u7528\u6237\u6D88\u606F\uFF1Bsource=\"proactive\"\uFF08v1.30.9\uFF09= bot \u4E3B\u52A8\u53D1\u8D77\n \uFF08CCC \u7ECF im-bridge \u5DE5\u5177\uFF08v1.31.0\uFF1B\u65E7 weixin-send MSM \u5DF2\u9000\u5F79\uFF09\u2192 sendProactiveText\uFF09\uFF1B\n source=\"reply-fallback\"\uFF08v1.30.17\uFF09= \u624B\u52A8\u6A21\u5F0F\u4E0B agent \u672C\u8F6E\u672A\u53D1\u9001 \u2192 \u6865\u515C\u5E95\u8F6C\u53D1\u6700\u7EC8\u6587\u672C\n \u00B7 file\uFF08\u4EC5 send-file \u8865\u8BB0\uFF09\uFF1A{ \"name\": \"\u62A5\u544A.pdf\", \"size\": 12345, \"caption\": \"\u53EF\u9009\" }\n\n \u811A\u672C\u7EA6\u5B9A\uFF08\u4E8B\u4EF6 JSON \u5355\u884C\u7ECF stdin \u4F20\u5165\uFF1Bbun \u4F18\u5148 node \u515C\u5E95\uFF09\uFF1A\n #!/usr/bin/env bun \u6216 node script.js \u2014\u2014 \u8BFB process.stdin \u6574\u6BB5 JSON.parse\n const ev = JSON.parse(await new Response(process.stdin).text())\n ev.event === 'incoming' | 'outgoing'\n\n \u4E8B\u4EF6 schema\uFF08**\u4E0D\u542B\u4EFB\u4F55\u4F1A\u8BDD\u51ED\u636E**\u2014\u2014context_token/bot_token/token/aes_key \u5747\u4E0D\u51FA\u73B0\uFF09\uFF1A\n { \"event\": \"incoming\", \"ts\": 1788359941488, \"cccRoot\": \"/path/ccc\",\n \"accountId\": \"wechat-1\", \"userId\": \"u1@im.wechat\",\n \"sessionId\": \"skiff-weixin-xxx\", \"role\": \"my-role\",\n \"message\": { \"text\": \"\u4F60\u597D\", \"media\": [{ \"kind\": \"image\", \"relPath\": \"_tmp/weixin-inbound/<hash>/img_x.jpg\" }] } }\n { \"event\": \"outgoing\", \"ts\": ..., \"cccRoot\": ..., \"accountId\": ...,\n \"userId\": ..., \"sessionId\": ..., \"role\": ...,\n \"reply\": \"\u5DF2\u8BB0\u5F55\uFF08\u7EAF\u6587\u672C\uFF09\", \"source\": \"reply\" | \"proactive\" | \"reply-fallback\" }\n\n \u793A\u4F8B\u811A\u672C\uFF08\u8FFD\u52A0\u5230\u6309\u65E5\u6587\u4EF6\u2014\u2014\u6301\u4E45\u5316\u5F52 CCC \u81EA\u9009\uFF1A\u6587\u4EF6/DB/\u8FDC\u7AEF\u5747\u53EF\uFF09\uFF1A\n const fs = require('node:fs'); const p = '/path/ccc/AGENT_SESSIONS/_weixin-log.jsonl';\n fs.appendFileSync(p, JSON.stringify(ev) + '\\n');\n\n \u6267\u884C\u8BED\u4E49\uFF08\u65C1\u8DEF\u5BB9\u5FCD\uFF09\uFF1A\u5F02\u6B65 fire-and-forget + 15s \u8D85\u65F6 kill + \u5931\u8D25\u4EC5\u65E5\u5FD7\u2014\u2014\n \u5FAE\u4FE1\u6865\u6D88\u606F\u5904\u7406/\u56DE\u590D\u4E0D\u53D7 hook \u5F71\u54CD\uFF1B\u811A\u672C\u987B\u5728 CCC \u6839\u5185\uFF08\u8DEF\u5F84\u9003\u9038\u62D2\u7EDD\uFF09\u3002\n \u5A92\u4F53 relPath \u6307\u5411 _tmp/weixin-inbound/\uFF08\u4E34\u65F6\u76EE\u5F55\uFF09\u2014\u2014\u9700\u6301\u4E45\u4FDD\u5B58\u5A92\u4F53\u6587\u4EF6\u8BF7\u81EA\u884C copy\u3002\n\n\u2500\u2500 9. exclusiveTools\uFF08\u4E13\u5C5E\u5DE5\u5177\u58F0\u660E\uFF0Cv1.33\uFF09\u2500\u2500\n**ACC \u6CE8\u518C\u4F46\u9ED8\u8BA4\u5BF9\u6240\u6709 CCC \u9690\u85CF**\u7684\u5DE5\u5177\uFF0C\u53EA\u6709\u5728\u81EA\u5DF1\u8FD9\u91CC**\u70B9\u540D**\u7684 CCC \u53EF\u89C1\u3002\n\u8FD9\u662F\u901A\u7528\u673A\u5236\uFF08\u4EFB\u4F55\u5DE5\u5177\u540D\u7686\u53EF\uFF09\uFF0C\u5224\u636E\u7531 CCC \u58F0\u660E\u2014\u2014ACC \u4EE3\u7801\u91CC\u4E0D\u51FA\u73B0\u4EFB\u4F55\u5177\u4F53 CCC \u7684\u540D\u5B57\u3002\n\u5F53\u524D\u4E13\u5C5E\u5DE5\u5177\uFF1Aacc-diag\uFF08\u8FD0\u884C\u6001\u8BCA\u65AD\u2014\u2014live \u4F1A\u8BDD / agent \u5B9A\u4F4D / \u5524\u9192\u6CE8\u518C\u8868 / \u5524\u8D77\u6761\u4EF6\u94FE\uFF09\u3002\n\n \u25B8 \u53EF\u89C1\u6027\u8BED\u4E49\uFF1A\u672A\u58F0\u660E \u21D2 \u7531 guards \u9010 agent tools.restrict({deny:[tool]}) \u4ECE**\u6A21\u578B\u5DE5\u5177\u6E05\u5355\u79FB\u9664**\n \uFF08\u4E0D\u662F\"\u770B\u5F97\u5230\u4F46\u88AB\u62D2\"\uFF09\u3002\u914D\u7F6E\u70ED\u66F4\u65B0\uFF1A\u6539\u672C\u6587\u4EF6\u5373\u65F6\u751F\u6548\uFF08\u65E0\u9700\u91CD\u542F\uFF09\u3002\n \u25B8 \u5931\u8D25\u65B9\u5411 **fail-closed**\uFF1A\u672A\u914D\u7F6E / \u5B57\u6BB5\u7F3A\u5931 / \u914D\u7F6E\u635F\u574F\uFF08JSON \u574F\uFF09\u21D2 \u4E00\u5F8B\u6309\"\u672A\u58F0\u660E\"\u5904\u7406\n \uFF08\u4E13\u5C5E\u5DE5\u5177\u4FDD\u6301\u9690\u85CF\uFF1B\u914D\u7F6E\u635F\u574F\u672C\u8EAB\u53E6\u6709\u54CD\u4EAE\u544A\u8B66\uFF09\u3002\u4E0E im-bridge \u76F8\u53CD\u2014\u2014\u9690\u85CF\u4E00\u4E2A**\u5DF2\u5728\u4F7F\u7528**\n \u7684\u901A\u9053\u624D\u4F1A\u9759\u9ED8\u635F\u5BB3\u80FD\u529B\uFF0C\u800C\u4E13\u5C5E\u5DE5\u5177\u7684\u9ED8\u8BA4\u6001\u672C\u5C31\u662F\u9690\u85CF\u3002\n \u25B8 \u914D\u7F6E\u635F\u574F\u7684\u54CD\u4EAE\u544A\u8B66\u53EA\u51FA\u73B0\u4E00\u6B21\uFF08\u6BCF\u8DEF\u5F84\uFF09\uFF0Cdashboard health \u540C\u6837\u80FD\u770B\u5230\u3002\n\n Config:\n { \"exclusiveTools\": [\"acc-diag\"] }\n";
11
29
  interface MsmFlag {
12
30
  name: string;
13
31
  type?: string;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * trajectory-constraint-admin.ts — 轨迹约束面逻辑层(公开入口 = `container_admin` 的 `role` 域)
3
+ *
4
+ * 三动作分工(用户拍板 2026-08-28,2026-10-19 重做后语义不变):guide 定义教程 /
5
+ * validate 校验 / list 摘要 / apply 显式应用确认。
6
+ *
7
+ * ## 🔴 2026-10-19 重做后,本文件的**数据源变了**
8
+ *
9
+ * 旧:读 `.opencode/serenity.json` 的 `轨迹约束.roles`(容器级配置表)。
10
+ * 新:读**轨迹目录里的 `trajectory-constraint.json`**(owner:「目录下拥有 `trajectory-constraint.json` 的认知轨迹自动是一个 轨迹约束」)。
11
+ * ⇒ `constraintCount` 的语义 = **本 CCC 有几条 轨迹约束轨迹**;"角色名"这个概念没有了,只有**轨迹编码**。
12
+ *
13
+ * 归属(D23)不变:ACC 提供机制(教程 + 校验 + 列表),**约束内容归 CCC**(写进 `trajectory-constraint.json`)。
14
+ */
15
+ import type { JsonValue } from '../kernel/json.js';
16
+ /** 轨迹约束 定义教程:概念 / `trajectory.json` schema / 双白名单 / 轨迹纪律 / 微信路由 */
17
+ export declare const TRAJECTORY_CONSTRAINT_GUIDE: string;
18
+ /** 校验当前 CCC 的 轨迹约束面:msms 均已注册 / model ∈ cheap-worker.models / 提示词非空 */
19
+ export declare function validateTrajectoryConstraint(root: string): JsonValue;
20
+ /** 列出当前 CCC 的轨迹约束(编码 / 模型 / msms / tools / 纪律摘要 / 提示词来源) */
21
+ export declare function listTrajectoryConstraintSummary(root: string): JsonValue;
22
+ /**
23
+ * 应用当前 轨迹约束 配置(S142 用户:改了 json 应该有个生效机制)。
24
+ *
25
+ * 语义:约束面是**每轮实时读取**的 ⇒ apply 不是"推送",而是**显式校验 + 应用确认**:
26
+ * ① 校验合法(复用 validate:msms 注册 / model 白名单 / 提示词非空)
27
+ * ② 非法 → 报告问题清单,不应用(提示修复后重跑 apply)
28
+ * ③ 合法 → 应用确认:绑定 CCC + 轨迹清单 + 说明(下一轮即生效)
29
+ */
30
+ export declare function applyTrajectoryConstraint(root: string): JsonValue;
@@ -11,7 +11,7 @@
11
11
  * 而本模块回答的是**关于载体的问题**(它空闲了/它被销毁了/会话先没了)。
12
12
  * 三个结算条件(见下)里有两条与"空闲"无关 —— 名字取窄了会误导调用方以为只需等 idle。
13
13
  *
14
- * 为什么单独成模块:`askSkiff`(问答)与 `cheap-worker`(杂工循环)都要"等这一轮做完",
14
+ * 为什么单独成模块:`askTrajectory`(问答)与 `cheap-worker`(杂工循环)都要"等这一轮做完",
15
15
  * 此前各自复制了一份只监听 `agent/status → idle` 的实现。该实现有一个静默挂死:
16
16
  * **agent 先被销毁(会话关闭/进程回收/显式 dispose)就永远不会再发 idle 事件**,
17
17
  * 等待方 Promise 永不结算 → 问答/杂工永久卡住(宿主的 disposal 语义:
@@ -32,7 +32,7 @@
32
32
  *
33
33
  * ⚠️ 由此产生一条**必须成立**的配套:`readAllSessions` **跳过 `_` 前缀目录**。
34
34
  * 否则归档后的轨迹会继续出现在清单里,"归档"就不是归档了(历史 bug:`_weixin-logs` /
35
- * `_skiff-logs` / `_corpus` 曾被当成轨迹列出来)。
35
+ * `_轨迹约束-logs` / `_corpus` 曾被当成轨迹列出来)。
36
36
  */
37
37
  /**
38
38
  * `cognitive_trajectory` 工具的动作集合(v1.33,S142 §32 用户裁决后的收敛结果)。
@@ -162,6 +162,16 @@ export declare function isValidUid(uid: string): boolean;
162
162
  * 🔴 **形态非法的文件按"没设定"处理,而不是报错**:解析侧出现在**每一次** `findSession` 里
163
163
  * (show/use/archive/send-now/send-later 全走它),在那里抛错会让一个坏文件**炸掉整条轨迹的所有操作**
164
164
  * —— 惩罚远大于问题本身。而写入侧已退役 ⇒ 坏文件只可能来自外部手改,更不该连坐。
165
+ *
166
+ * ## 🆕 2026-10-19 owner 裁 Q2:**声明文件里的 `uid` 优先,独立文件回落**
167
+ *
168
+ * 收拢后这个旧标识住在 `<轨迹目录>/trajectory.json` 的 `uid` 字段里(它属"声明",
169
+ * 与约束面/机器绑定同源)。判据(**两代并读,不硬切**):
170
+ * **声明面里有合法 `uid` ⇒ 用它;否则回落 `TRAJECTORY-UID` 文件**。
171
+ *
172
+ * ⚠️ **为什么字段名是 `uid` 而不是方案书里写的 `code`**:`code` 在本仓已有一个**更窄的含义**
173
+ * —— 目录名里那个固定位置的轨迹编码(`parseTrajectoryCode`)。同一个词在一个 JSON 里表示两件事,
174
+ * 正是本轨反复抓的那类"名字会撒谎"。⇒ 旧标识就叫 `uid`(它本来就是 UID,见 `UID_FILENAME`)。
165
175
  */
166
176
  export declare function readTrajectoryUid(sessionPath: string): string | null;
167
177
  /**
@@ -0,0 +1,75 @@
1
+ /**
2
+ * trajectory/policy/files.ts — **轨迹级文件的文件名族**(owner 2026-10-19 裁 Q2:短名 `trajectory.json`)
3
+ *
4
+ * ## 这一层解决什么(白话)
5
+ *
6
+ * 一条轨迹目录里,ACC 自己产的文件原先有**四个名字各异的文件**:
7
+ * `trajectory-constraint.json`(约束面)/`TRAJECTORY-UID`(只读遗留的旧标识)/
8
+ * `cro-host-binding`(一行机器名)/`cro-wake-log.json`(CRO 流水)。
9
+ * 后两个里,**「声明」性质的那两个现在并进一个 JSON**(流水不并 —— 见 `cro/log.ts` 的理由)。
10
+ *
11
+ * ⇒ 收拢后的形态:
12
+ *
13
+ * ```text
14
+ * <轨迹目录>/
15
+ * SESSION.md ← 轨迹的身体(不动)
16
+ * PROMPT.md ← 章程(不动)
17
+ * continuous-re-occurrence.ts← CRO 程序(不动)
18
+ * trajectory.json ← 🆕 声明面:约束 + 旧标识(code) + cro.host
19
+ * cro-wake-log.log ← CRO 流水(高频追加,**刻意不并入**)
20
+ * ```
21
+ *
22
+ * ## 🔴 为什么不硬切(本容器已两次栽在"上游改名、下游写死旧名")
23
+ *
24
+ * 读取侧认**族**:`trajectory.json`(新)→ `trajectory-constraint.json`(v1.74 名)→
25
+ * `skiff.json`(v1.71 名)。**任一存在即成立**。上游再改名只往族里加一项,不再单点写死。
26
+ *
27
+ * 🔴 **`cro-host-binding` 必须两代并读,这一条是有行为后果的**
28
+ * (理由逐字保留在 `cro/core.ts` 的 `resolveCroHostBinding` 头注):
29
+ * 绑定声明要**跟着轨迹走到第二台机器**,在那里被判成「绑给了别人」而**正确地不跑**。
30
+ * 若硬切改名,第二台机器读到的是**「没绑」** —— **表面结果相同,但判据退化**
31
+ * (失去"明确绑给别人"的可诊断性)⇒ 只能两代并读。
32
+ *
33
+ * ## 归属(D23)
34
+ * 本模块只管**机制**(文件叫什么、按什么顺序找、怎么读);**内容归 CCC**
35
+ * (JSON 里填什么:模型 / 白名单 / 提示词路径 / 机器名)。
36
+ *
37
+ * ## 边界与铁律
38
+ * 本模块**零本地依赖**(只用 `node:fs` / `node:path`)⇒ 谁 import 它都不会成环。
39
+ * 每个读取函数**永不抛**:文件不存在 / 坏 JSON ⇒ `null`,由调用方各自决定降级方式。
40
+ */
41
+ /**
42
+ * 收拢后的**新**文件名(owner 裁 Q2「短名」)。
43
+ *
44
+ * 🔴 **为什么要改名**:它装的不止"约束"了(还有 `code` 与 `cro.host`)
45
+ * ⇒ 留着旧名会让**名字本身就是错名**(D151 同族:界面/文档里的名字会随内容演进而撒谎)。
46
+ */
47
+ export declare const TRAJECTORY_FILENAME = "trajectory.json";
48
+ /**
49
+ * **判据族**:任一存在 ⇒ 这条轨迹有声明面(= 旧模型说的"它是一个轨迹约束")。
50
+ *
51
+ * ⚠️ **顺序即优先级**(第一个找到的胜过后面的):新名优先,两个旧名按代际倒序。
52
+ * ⚠️ **准入面宽于约束面是有意的**:约束文件缺失的轨迹仍需要能被当作轨迹处理。
53
+ */
54
+ export declare const TRAJECTORY_FILENAME_FAMILY: readonly ["trajectory.json", "trajectory-constraint.json", "skiff.json"];
55
+ /** 旧名的单独导出(调用方要单独判断"这是不是旧档"时用;顺序同上、不含新名) */
56
+ export declare const TRAJECTORY_LEGACY_FILENAMES: ("trajectory.json" | "trajectory-constraint.json" | "skiff.json")[];
57
+ /**
58
+ * 在一条轨迹目录里找**声明文件**(族内第一个存在的)。
59
+ *
60
+ * @param trajectoryDir 轨迹目录绝对路径
61
+ * @returns 命中的文件绝对路径;族内一个都不存在 ⇒ `null`(= 普通轨迹,**常态不是错误**)
62
+ */
63
+ export declare function findTrajectoryFile(trajectoryDir: string): string | null;
64
+ /**
65
+ * 读一条轨迹目录里的声明文件,解析成对象(**永不抛**)。
66
+ *
67
+ * @returns `{ file, data }`:`file` 是命中的文件名(族内哪个),`data` 是解析后的对象;
68
+ * **族内无文件 ⇒ `null`**;**坏 JSON / 顶层非对象 ⇒ `{ file, data: null, error }`**
69
+ * —— 这三种情形调用方的降级方式各不相同(普通轨迹 / 告警后按普通轨迹),故分开给。
70
+ */
71
+ export declare function readTrajectoryFile(trajectoryDir: string): {
72
+ file: string;
73
+ data: Record<string, unknown> | null;
74
+ error: string | null;
75
+ } | null;
@@ -1,53 +1,58 @@
1
1
  /**
2
- * trajectory/policy/profile.ts — **skiff 的唯一判据**:目录下有 `skiff.json` 的认知轨迹(零 DSH 依赖,可独立单测)
2
+ * trajectory/policy/profile.ts — **轨迹约束的唯一判据**:目录下有 `trajectory-constraint.json` 的认知轨迹(零 DSH 依赖,可独立单测)
3
3
  *
4
4
  * ## 🔴 owner 2026-10-19 重做令(逐字,本文件存在的全部理由)
5
5
  *
6
- * > 「skiff 复杂的约束和提示词体系都干掉,改为这样的实现:
7
- * > **skiff 本身是认知轨迹的一个特殊情况,即目录下拥有 `skiff.json` 的认知轨迹自动是一个 skiff**
8
- * > (json 里配置上个版本就有的各种约束),**会话跑在认知轨迹上且发现 `skiff.json`,则运行时实现各类约束**」
6
+ * > 「轨迹约束 复杂的约束和提示词体系都干掉,改为这样的实现:
7
+ * > **轨迹约束本身是认知轨迹的一个特殊情况,即目录下拥有 `trajectory-constraint.json` 的认知轨迹自动是一个 轨迹约束**
8
+ * > (json 里配置上个版本就有的各种约束),**会话跑在认知轨迹上且发现 `trajectory-constraint.json`,则运行时实现各类约束**」
9
9
  *
10
10
  * ## 旧模型 → 新模型(**一条判据取代四条**)
11
11
  *
12
12
  * | 项 | 旧 | 新 |
13
13
  * |---|---|---|
14
- * | skiff 是什么 | `serenity.json` 的 `skiff.roles.<name>` 一条配置 | **轨迹目录里有 `skiff.json`** |
15
- * | 怎么认出 skiff 会话 | dsh sessionId 前缀 `skiff-` | **它绑定的轨迹有 `skiff.json`** |
16
- * | 工作台从哪来 | `ensureSkiffSession` 另建一个 SESSION | **就是该轨迹自己的 SESSION.md** |
14
+ * | 轨迹约束是什么 | `serenity.json` 的 `轨迹约束.roles.<name>` 一条配置 | **轨迹目录里有 `trajectory-constraint.json`** |
15
+ * | 怎么认出 轨迹约束会话 | dsh sessionId 前缀 `轨迹约束-` | **它绑定的轨迹有 `trajectory-constraint.json`** |
16
+ * | 工作台从哪来 | `ensureTrajectorySession` 另建一个 SESSION | **就是该轨迹自己的 SESSION.md** |
17
17
  * | 身份 | 角色名 | **轨迹编码**(`trajectory/core.ts` 的 `parseTrajectoryCode`) |
18
18
  *
19
19
  * ⇒ 收益(owner:「理解难度大幅下降」的实际内容):四个各自会漂的机制收敛为**一条文件存在性判据**。
20
- * 删掉 `skiff.json` ⇒ 该轨迹**当场**退化为普通轨迹(工具面、提示词、keeper 全部恢复默认)。
20
+ * 删掉 `trajectory-constraint.json` ⇒ 该轨迹**当场**退化为普通轨迹(工具面、提示词、keeper 全部恢复默认)。
21
21
  *
22
22
  * ## 归属(D23)
23
23
  * **机制在 ACC**(文件叫什么、怎么读、怎么判、缺省值、如何施加约束);
24
- * **内容在 CCC**(`skiff.json` 里填什么:模型、白名单、提示词路径)。
25
- * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 skiff 段(该段已退役)。
24
+ * **内容在 CCC**(`trajectory-constraint.json` 里填什么:模型、白名单、提示词路径)。
25
+ * ⇒ ACC 代码里**不出现任何具体角色名**,也不读 `serenity.json` 的 轨迹约束段(该段已退役)。
26
26
  *
27
- * ## S12(2026-10-19,轨迹中心重构):此前位于 `role/skiff/` 下(该目录已随本重构消失)
27
+ * ## S12(2026-10-19,轨迹中心重构):此前位于 `role/轨迹约束/` 下(该目录已随本重构消失)
28
28
  *
29
29
  * 落点 = `trajectory/policy/`。判据(判读表 §3.1):本文件判的是**某条轨迹的约束面**,
30
30
  * 主语是轨迹 ⇒ 它一直就是轨迹切面,只是旧目录把它挂在"角色"这个**平行概念**下。
31
- * ⚠️ **文件名 `profile` 与 `skiff.json` / `SkiffProfile` 等符号名一律不动**:
31
+ * ⚠️ **文件名 `profile` 与 `trajectory-constraint.json` / `TrajectoryConstraint` 等符号名一律不动**:
32
32
  * 那是有具体指称的东西(一个固定文件名 + 它的解析结果),不是组织单位。
33
33
  */
34
- /** `skiff.json` 的固定文件名(**判据就是它存在**——不是目录名前缀,也不是配置里的一行) */
35
- export declare const SKIFF_PROFILE_FILENAME = "skiff.json";
36
34
  /**
37
- * 一个 skiff 轨迹的**完整约束面**(= 旧 `skiff.roles.<name>` 那套,整体搬进轨迹目录)。
35
+ * 🆕 **声明文件的文件名**(2026-10-19 owner 裁 Q2:短名 `trajectory.json`)。
36
+ *
37
+ * ⚠️ **判据不是"这个名字在不在"**,而是**族内任一存在**(`TRAJECTORY_FILENAME_FAMILY`)。
38
+ * 这个名字只是**写入目标**与**提示文案里该印的那个**。
39
+ */
40
+ export declare const TRAJECTORY_CONSTRAINT_FILENAME = "trajectory.json";
41
+ /**
42
+ * 一个 轨迹约束轨迹的**完整约束面**(= 旧 `轨迹约束.roles.<name>` 那套,整体搬进轨迹目录)。
38
43
  *
39
44
  * ⚠️ 与旧配置的**一处有意语义翻转**(R↓,别当成"顺手改默认值"):
40
- * `cognitiveTrajectory.*` 在旧模型里**缺省全 false**("skiff 完全独立"),理由是
41
- * **它的工作台是外挂的**(`ensureSkiffSession` 另建一个 SESSION,不由轨迹承载)。
45
+ * `cognitiveTrajectory.*` 在旧模型里**缺省全 false**("轨迹约束 完全独立"),理由是
46
+ * **它的工作台是外挂的**(`ensureTrajectorySession` 另建一个 SESSION,不由轨迹承载)。
42
47
  * 新模型里**工作台就是它自己的 SESSION.md** ⇒ 全 false 会让它拿不到自己的身体
43
48
  * ⇒ **缺省翻成 true**。这不是偏好问题,是两个模型的结构差。
44
49
  */
45
- export interface SkiffProfile {
50
+ export interface TrajectoryConstraint {
46
51
  /** 该约束面所属轨迹的目录名(`YYYY-MM-DD--<code>[--<desc>]`) */
47
52
  dirName: string;
48
53
  /** 轨迹编码(= 唯一标识;见 `parseTrajectoryCode`) */
49
54
  code: string;
50
- /** `skiff.json` 的绝对路径 */
55
+ /** `trajectory-constraint.json` 的绝对路径 */
51
56
  path: string;
52
57
  /** 模型(`provider/model`);缺省回退 `cheap-worker.defaultModel` */
53
58
  model?: string;
@@ -67,26 +72,26 @@ export interface SkiffProfile {
67
72
  systemPromptFile?: string;
68
73
  }
69
74
  /**
70
- * 读一个目录下的 `skiff.json`(**纯读,不施加约束**)。
75
+ * 读一个目录下的 `trajectory-constraint.json`(**纯读,不施加约束**)。
71
76
  *
72
77
  * @param trajectoryDir 轨迹目录绝对路径
73
78
  * @param root CCC 根(仅用于 `systemPromptFile` 的逃逸拒绝)
74
- * @returns 归一后的约束面;**无该文件 → `null`(= 这不是 skiff,常态,不是错误)**
79
+ * @returns 归一后的约束面;**无该文件 → `null`(= 这不是 轨迹约束,常态,不是错误)**
75
80
  *
76
81
  * ⚠️ **形态容错**:数组元素非字符串 → 丢弃该项(不整份作废);`cognitiveTrajectory`
77
82
  * 缺项 → 各自取 **true**(见 R↓);`model` 空白 → undefined(回退缺省)。
78
- * 坏 JSON ⇒ 告警 + `null`(**按"不是 skiff"处理**:宁可让它退回普通轨迹,也不要带着
83
+ * 坏 JSON ⇒ 告警 + `null`(**按"不是 轨迹约束"处理**:宁可让它退回普通轨迹,也不要带着
79
84
  * 半份读不懂的权限面运行)。
80
85
  */
81
- export declare function readSkiffProfileAt(trajectoryDir: string, root: string): SkiffProfile | null;
86
+ export declare function readTrajectoryConstraintAt(trajectoryDir: string, root: string): TrajectoryConstraint | null;
82
87
  /**
83
- * 按**轨迹编码**解析 skiff 约束面(`list`/`admin`/调试页/路由解析用)。
88
+ * 按**轨迹编码**解析 轨迹约束面(`list`/`admin`/调试页/路由解析用)。
84
89
  *
85
- * @returns 约束面;轨迹不存在 / 无 `skiff.json` → `null`
90
+ * @returns 约束面;轨迹不存在 / 无 `trajectory-constraint.json` → `null`
86
91
  */
87
- export declare function readSkiffProfileByCode(root: string, code: string): SkiffProfile | null;
88
- /** 扫全部活跃轨迹,返回全部 skiff。**顺序按目录名**(确定性,便于对读)。 */
89
- export declare function listSkiffProfiles(root: string): SkiffProfile[];
92
+ export declare function readTrajectoryConstraintByCode(root: string, code: string): TrajectoryConstraint | null;
93
+ /** 扫全部活跃轨迹,返回全部 轨迹约束。**顺序按目录名**(确定性,便于对读)。 */
94
+ export declare function listTrajectoryConstraints(root: string): TrajectoryConstraint[];
90
95
  /**
91
96
  * 编码 → 轨迹目录名(活跃轨迹内)。找不到 → `null`。
92
97
  *
@@ -96,27 +101,27 @@ export declare function listSkiffProfiles(root: string): SkiffProfile[];
96
101
  */
97
102
  export declare function findDirNameByCode(root: string, code: string): string | null;
98
103
  /**
99
- * **会话级**判据(J2):这个 dsh 会话是不是 skiff 会话 —— 唯一入口。
104
+ * **会话级**判据(J2):这个 dsh 会话是不是 轨迹约束会话 —— 唯一入口。
100
105
  *
101
- * 判据 = **它绑定的轨迹有 `skiff.json`**(不是 sessionId 前缀,也不是配置里有没有角色)。
106
+ * 判据 = **它绑定的轨迹有 `trajectory-constraint.json`**(不是 sessionId 前缀,也不是配置里有没有角色)。
102
107
  *
103
108
  * ## 为什么"绑定的轨迹"从两个来源取(R↓,一个失败模式)
104
109
  * ① **持久绑定**(`readLastBound`,宿主存储域/`.bindings.json`)—— 权威,跨重启成立;
105
110
  * ② **内存注册表**(`trajectory/policy/window`)—— 覆盖绑定的**窗口期**(轨迹刚定、bound 还没落盘)。
106
- * ⇒ 只取 ① 会在建会话的第一轮判成"不是 skiff"(工具面不收窄,模型看见不该有的工具);
107
- * 只取 ② 会在进程重启后全判成"不是"(skiff 失去约束,**权限面静默放开**)。
111
+ * ⇒ 只取 ① 会在建会话的第一轮判成"不是 轨迹约束"(工具面不收窄,模型看见不该有的工具);
112
+ * 只取 ② 会在进程重启后全判成"不是"(轨迹约束 失去约束,**权限面静默放开**)。
108
113
  * ⇒ **两来源并取**,都不中才 `null`。
109
114
  *
110
115
  * @param root CCC 根
111
116
  * @param sessionId dsh 会话 id
112
117
  * @param boundDirName 调用方已解析的绑定目录名(可选;给了就省一次读绑定)
113
- * @returns 约束面;不是 skiff 会话 → `null`
118
+ * @returns 约束面;不是 轨迹约束会话 → `null`
114
119
  */
115
- export declare function skiffProfileForSession(root: string, sessionId: string | undefined, boundDirName?: string | null): SkiffProfile | null;
120
+ export declare function trajectoryConstraintForSession(root: string, sessionId: string | undefined, boundDirName?: string | null): TrajectoryConstraint | null;
116
121
  /**
117
- * 该 dsh 会话**是不是** skiff 会话(布尔形态的 `skiffProfileForSession`)。
122
+ * 该 dsh 会话**是不是** 轨迹约束会话(布尔形态的 `trajectoryConstraintForSession`)。
118
123
  *
119
124
  * 存在的理由:调用点很多只要一个"是/不是"(seams 的旁路判定),
120
125
  * 让它们各自写 `!== null` 会把判据散开;**判据只能有一个入口**。
121
126
  */
122
- export declare function isSkiffSession(root: string, sessionId: string | undefined): boolean;
127
+ export declare function isTrajectoryConstrained(root: string, sessionId: string | undefined): boolean;
@@ -5,35 +5,35 @@
5
5
  *
6
6
  * | 模块 | 管什么 |
7
7
  * |---|---|
8
- * | `./profile.ts` | **判据 + 读盘**("这是不是 skiff"、"约束面是什么") |
8
+ * | `./profile.ts` | **判据 + 读盘**("这是不是 轨迹约束"、"约束面是什么") |
9
9
  * | `./rules.ts`(本文件) | **从约束面派生出的纯函数**(白名单集合、提示词读取器、基础提示词文本) |
10
10
  * | `../session-create.ts` | 会话创建/复用、提问、守门查询 |
11
11
  *
12
- * ⇒ 本文件**不再读 `serenity.json`**:`skiff.roles` 整段已退役(owner 2026-10-19 重做)。
13
- * 它只接收一个已解析好的 `SkiffProfile`,因此**不涉及任何 IO**(除提示词文件,那是刻意懒读的)。
12
+ * ⇒ 本文件**不再读 `serenity.json`**:`轨迹约束.roles` 整段已退役(owner 2026-10-19 重做)。
13
+ * 它只接收一个已解析好的 `TrajectoryConstraint`,因此**不涉及任何 IO**(除提示词文件,那是刻意懒读的)。
14
14
  *
15
15
  * ## S12(2026-10-19,轨迹中心重构)
16
16
  *
17
- * 原名 `role/skiff/config.ts`。改名理由(框架 §6.3「角色不是一个概念,是一段历史」):
17
+ * 原名 `role/轨迹约束/config.ts`。改名理由(框架 §6.3「角色不是一个概念,是一段历史」):
18
18
  * 它派生的是**某条轨迹的约束面**,与"配置读取"无关(本文件零配置读取,见上一段)
19
19
  * ⇒ `config` 这个名字描述的是**它曾经的样子**,`rules` 描述它**现在做的事**。
20
20
  */
21
- import type { SkiffProfile } from './profile.js';
21
+ import type { TrajectoryConstraint } from './profile.js';
22
22
  /** 白名单推导 ────────────────────────────────────────────────────────────── */
23
23
  /** 提示词来源提示串(`apply` 回执与面板共用;避免两处措辞漂) */
24
- export declare const SKIFF_PROFILE_HINT = "systemPromptFile hot-reloads by mtime; the rest of skiff.json is re-read every turn";
24
+ export declare const TRAJECTORY_CONSTRAINT_HINT = "systemPromptFile hot-reloads by mtime; the rest of trajectory-constraint.json is re-read every turn";
25
25
  /**
26
- * 该 skiff 会话**可见**的工具面(tools ∪ `msm`)。
26
+ * 该 轨迹约束会话**可见**的工具面(tools ∪ `msm`)。
27
27
  *
28
- * 🔴 `msm` 为什么自动加入:`msms` 非空意味着这个 skiff **有 MSM 通道**,
28
+ * 🔴 `msm` 为什么自动加入:`msms` 非空意味着这个 轨迹约束 **有 MSM 通道**,
29
29
  * 而 MSM 的唯一合法调用入口是 `msm` 工具(单入口纪律)——不给它 `msm` 就等于
30
30
  * 声明了一堆调不动的能力。⚠️ 这是**并集**,不是覆盖:`tools` 里显式写的照旧生效。
31
31
  */
32
- export declare function profileToolWhitelist(profile: SkiffProfile | null | undefined): Set<string>;
33
- /** 该 skiff 会话可 exec 的 MSM 白名单(`msm` 工具内部再过滤;独立于工具白名单) */
34
- export declare function profileMsmWhitelist(profile: SkiffProfile | null | undefined): Set<string>;
35
- /** 轨迹纪律参与项(`profile` 缺省已在 `readSkiffProfileAt` 归一为全 true) */
36
- export declare function profileCognitiveTrajectory(profile: SkiffProfile | null | undefined): {
32
+ export declare function profileToolWhitelist(profile: TrajectoryConstraint | null | undefined): Set<string>;
33
+ /** 该 轨迹约束会话可 exec 的 MSM 白名单(`msm` 工具内部再过滤;独立于工具白名单) */
34
+ export declare function profileMsmWhitelist(profile: TrajectoryConstraint | null | undefined): Set<string>;
35
+ /** 轨迹纪律参与项(`profile` 缺省已在 `readTrajectoryConstraintAt` 归一为全 true) */
36
+ export declare function constraintCognitiveTrajectory(profile: TrajectoryConstraint | null | undefined): {
37
37
  session: boolean;
38
38
  keeper: boolean;
39
39
  rebuild: boolean;
@@ -46,9 +46,22 @@ export declare function profileCognitiveTrajectory(profile: SkiffProfile | null
46
46
  *
47
47
  * ⚠️ 热路径**不用**它(那会用每次工具调用去读盘)——热路径用 `createProfilePromptReader`。
48
48
  */
49
- export declare function resolveProfileSystemPrompt(root: string, profile: SkiffProfile | null | undefined): string;
50
- /** 提示词来源(`list`/`validate` 展示用) */
51
- export declare function profileSystemPromptSource(profile: SkiffProfile | null | undefined): 'file' | 'inline' | 'none';
49
+ export declare function resolveConstraintSystemPrompt(root: string, profile: TrajectoryConstraint | null | undefined): string;
50
+ /**
51
+ * 提示词来源(`list`/`validate` 展示用)。
52
+ *
53
+ * 🔴 **2026-10-19 修(T4 的漏网面)**:v1.72.0 起提示词有两代来源——**新形态**
54
+ * 是轨迹目录里的 `PROMPT.md`(`trajectory/prompt.ts`,**优先**),旧形态才是
55
+ * `systemPromptFile` / `systemPrompt`。本函数原先只认旧形态 ⇒ 两条只写了 `PROMPT.md`
56
+ * 的轨迹在 `container_admin config list` 里恒显示 `promptSource: 'none'`。
57
+ *
58
+ * 那是**读数器过时**,不是配置缺失:`validate` 侧早已按两条来源判(见
59
+ * `trajectory-constraint-admin.ts` 的 `hasTrajectoryPromptOrLegacy`),而 `list` 侧漏了。
60
+ * ⇒ 返 **四种**值,把"有章程但来源是新形态"这一格单独说出来。
61
+ *
62
+ * @param hasPromptFile 该轨迹目录下**是否真有** `PROMPT.md`(调用方查,本函数不做 IO)
63
+ */
64
+ export declare function constraintSystemPromptSource(profile: TrajectoryConstraint | null | undefined, hasPromptFile?: boolean): 'trajectory-file' | 'file' | 'inline' | 'none';
52
65
  /**
53
66
  * 提示词**读取器**(长期热更新;改文件即生效,无需重启)。
54
67
  *
@@ -62,9 +75,9 @@ export declare function profileSystemPromptSource(profile: SkiffProfile | null |
62
75
  * @param root CCC 根
63
76
  * @param profile 约束面
64
77
  */
65
- export declare function createProfilePromptReader(root: string, profile: SkiffProfile | null | undefined): () => string;
78
+ export declare function createProfilePromptReader(root: string, profile: TrajectoryConstraint | null | undefined): () => string;
66
79
  /**
67
- * skiff 基础提示词(dsp 只给这部分;CCC 的 `systemPrompt` 段由调用方拼接)。
80
+ * 轨迹约束 基础提示词(dsp 只给这部分;CCC 的 `systemPrompt` 段由调用方拼接)。
68
81
  *
69
82
  * ## 🔴 为什么**不再枚举**清单(owner 2026-10-19 令)
70
83
  *
@@ -80,6 +93,6 @@ export declare function createProfilePromptReader(root: string, profile: SkiffPr
80
93
  *
81
94
  * ⇒ 现在只声明**边界与发现路径**,不抄内容:清单在哪,怎么取,越界会怎样。
82
95
  *
83
- * @param code 轨迹编码(skiff 的身份 —— 不是"角色名",那个概念已退役)
96
+ * @param code 轨迹编码(轨迹约束的身份 —— 不是"角色名",那个概念已退役)
84
97
  */
85
- export declare function buildSkiffBasePrompt(code: string): string;
98
+ export declare function buildTrajectoryBasePrompt(code: string): string;
@@ -4,11 +4,11 @@
4
4
  * ## 它现在只做一件事:**把「会话」映到「轨迹」**
5
5
  *
6
6
  * 旧形态存的是 `{role, ccc}`(角色名)。owner 2026-10-19 重做后 **角色名不再存在**——
7
- * skiff 的身份是**轨迹编码**,约束面住在该轨迹的 `skiff.json` 里(见 `./profile.ts`)。
7
+ * 轨迹约束的身份是**轨迹编码**,约束面住在该轨迹的 `trajectory-constraint.json` 里(见 `./profile.ts`)。
8
8
  * ⇒ 本表退化为一张**会话 → 轨迹目录名**的内存映射,供**同步**热路径(guards / system-prompt)查询;
9
9
  * 权威来源仍是持久绑定(`trajectory/bound.ts` 的 `readLastBound`)。
10
10
  *
11
- * ## S12(2026-10-19,轨迹中心重构):原名 `role/skiff/registry.ts`
11
+ * ## S12(2026-10-19,轨迹中心重构):原名 `role/轨迹约束/registry.ts`
12
12
  *
13
13
  * 改名理由:它**不是**一张"注册表"(注册表的语义是权威名单),它是**权威来源之外的一个窗口**——
14
14
  * 覆盖「轨迹已定、绑定还没落盘」那一段(见下方「为什么还需要这张内存表」)。
@@ -16,32 +16,32 @@
16
16
  *
17
17
  * ## 为什么还需要这张内存表(R↓,一个窗口期)
18
18
  *
19
- * 持久绑定是**异步落盘**的(宿主存储域写入)。会话刚建立、`skiff.json` 已生效、绑定的记录
20
- * 还没落盘的那一段,`readLastBound` 返回 null ⇒ 若只认持久绑定,**第一轮会被判成"不是 skiff"**
19
+ * 持久绑定是**异步落盘**的(宿主存储域写入)。会话刚建立、`trajectory-constraint.json` 已生效、绑定的记录
20
+ * 还没落盘的那一段,`readLastBound` 返回 null ⇒ 若只认持久绑定,**第一轮会被判成"不是 轨迹约束"**
21
21
  * ⇒ 工具面不收窄(模型看见并会去试它不该有的工具)。
22
- * ⇒ 两个来源并取(见 `profile.ts` 的 `skiffProfileForSession`),**都不中才判"不是"**。
22
+ * ⇒ 两个来源并取(见 `profile.ts` 的 `trajectoryConstraintForSession`),**都不中才判"不是"**。
23
23
  *
24
24
  * ## 生命周期
25
25
  * 进程内存态:连接/会话关闭时解绑(`lifecycle.ts`),进程重启自然清空
26
26
  * (此时持久绑定已落盘 ⇒ 由它接管,**不会因为内存空而失去约束**)。
27
27
  */
28
28
  /** 注册表值:该 dsh 会话承载哪条轨迹(`trajectoryDirName` 为空串 = 已登记但还没定轨迹) */
29
- interface SkiffSessionBinding {
30
- /** 轨迹目录名(`YYYY-MM-DD--<code>[--<desc>]`)——**skiff 身份的唯一载体** */
29
+ interface TrajectorySessionBinding {
30
+ /** 轨迹目录名(`YYYY-MM-DD--<code>[--<desc>]`)——**轨迹身份的唯一载体** */
31
31
  trajectoryDirName: string;
32
32
  /** CCC 根(多 CCC 时防止串味:同 sessionId 复用必须同 (轨迹, CCC)) */
33
33
  ccc: string;
34
34
  }
35
35
  /** 登记/更新一个会话 → 轨迹的映射 */
36
- export declare function registerSkiffSession(sessionId: string, trajectoryDirName: string, ccc: string): void;
36
+ export declare function registerTrajectorySession(sessionId: string, trajectoryDirName: string, ccc: string): void;
37
37
  /** 解绑(会话销毁 / 轨迹失效 ⇒ 换身份) */
38
- export declare function unregisterSkiffSession(sessionId: string): void;
38
+ export declare function unregisterTrajectorySession(sessionId: string): void;
39
39
  /** 查会话承载的轨迹目录名(无 → null);`guards`/`system-prompt` 的同步热路径用 */
40
- export declare function skiffTrajectoryDirNameFor(sessionId: string): string | null;
40
+ export declare function trajectoryDirNameForSession(sessionId: string): string | null;
41
41
  /** 查会话的完整绑定(轨迹 + CCC;无 → null)——追问延续时校验 (轨迹, CCC) 未串味 */
42
- export declare function skiffSessionInfo(sessionId: string): SkiffSessionBinding | null;
42
+ export declare function trajectorySessionInfo(sessionId: string): TrajectorySessionBinding | null;
43
43
  /** 测试/诊断:注册表快照 */
44
- export declare function skiffSessionSnapshot(): ReadonlyMap<string, SkiffSessionBinding>;
44
+ export declare function trajectorySessionSnapshot(): ReadonlyMap<string, TrajectorySessionBinding>;
45
45
  /** 测试:清空(进程级状态,用例间必须复位) */
46
- export declare function resetSkiffSessions(): void;
46
+ export declare function resetTrajectorySessions(): void;
47
47
  export {};