@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24

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 (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -1,248 +1,585 @@
1
+ /**
2
+ * 账本 CLI(ADR-15 事务化状态基座的操作面;D3 决策:仓内极简命令,恢复语义
3
+ * 已与驱动器解耦,随时可换 loopx tick):
4
+ * migrate [root] one-shot 迁移:旧 JSON/JSONL → 账本 events
5
+ * (导入前自动快照到 gotry-state/pre-ledger-backup/)
6
+ * export [root] local-only:账本 → 旧文件名视图(红线 6:可见可导出;单向,不回流)
7
+ * log [root] [--limit N] 事件账本尾部(append-only 审计面)
8
+ * stats [root] 各面计数
9
+ * rebuild [root] [toSeq] DROP 投影 → fold 重放(可截到 toSeq;账本/投影
10
+ * 永不分叉的可验证性)
11
+ * rewind [root] <seq> = rebuild toSeq(投影回到历史时点;events 不动,
12
+ * rebuild 无参即回到最新)
13
+ * forget [root] wish|companion|motivation <id>
14
+ * 物理硬删该主体全部事件 + 审计一行 + 重建投影
15
+ * (红线 6「可删除」;D5 默认物理删)
16
+ * tick [root] local-only:回收全部 pending 工单(durable 恢复语义)
17
+ * whatif [root] <dest.db> local-only:VACUUM INTO 整库分叉副本(管理员 snapshot;
18
+ * 不是租户 export,不触正本)
19
+ * pw-list [root] pending_writes 清单
20
+ * pw-request [root] <idemKey> <seam> <payloadJson> 登记待确认外部写(L2)
21
+ * pw-confirm [root] <idemKey> <receipt> 具名 seam 确认(L3,携 receipt)
22
+ * pw-compensate [root] <idemKey> <note> saga 补偿
23
+ * repair-plan [root] [--mapping <file>] [--format text|json]
24
+ * 只读 inventory + dry-run tenant 修复计划(#254):
25
+ * 正本零写(只在临时副本上读),无显式证据映射的
26
+ * 事件一律原地保留;真实 apply 在单独 owner gate 后
27
+ * repair-apply [root] --mapping <file> --plan-digest <hex>
28
+ * --i-authorize-apply [--format text|json] [--receipt-out <file>]
29
+ * 授权 apply(#254):写前 backup + CAS 搬移 + 投影重建
30
+ * repair-rollback [root] --backup <dir> --i-authorize-rollback
31
+ * 用校验过的 backup 还原正本(#254)
32
+ *
33
+ * 选项(可放在命令前或命令后,也可夹在位置参数之间):
34
+ * --state-root <root> 显式 state root;省略时按命令沿用位置参数 root 或默认 '.'。
35
+ * --tenant <tenant> 账本租户 scope(默认 local);这是范围参数,不是认证/授权。
36
+ * --limit <N> 仅 log 支持;N 必须是正整数。
37
+ * --mapping <file> repair-plan / repair-apply;人工确认的证据映射 JSON 数组。
38
+ * --format text|json repair-plan / repair-apply;默认 text。
39
+ * --plan-digest <hex> 仅 repair-apply;必须与重算计划 digest 一致。
40
+ * --i-authorize-apply 仅 repair-apply;显式授权写路径(布尔旗标)。
41
+ * --backup <dir> 仅 repair-rollback;校验过的 backup 目录。
42
+ * --i-authorize-rollback 仅 repair-rollback;显式授权还原(布尔旗标)。
43
+ * --receipt-out <file> 仅 repair-apply;写出脱敏回执 JSON。
44
+ *
45
+ * root 默认 '.';运行:cd ts && npx tsx scripts/state-cli.ts <cmd> ...
46
+ */
1
47
  import { mkdirSync, renameSync, writeFileSync } from 'node:fs';
2
48
  import { dirname, join } from 'node:path';
3
- import { ensureLedger, openLedgerIfExists } from '../src/state-ledger.js';
49
+ import { ensureLedger, ledgerDbPath, ledgerExists, openLedgerIfExists } from '../src/state-ledger.js';
50
+ import { formatRepairPlan, loadEvidenceMappingFile, planLedgerRepair } from '../src/ledger-repair-plan.js';
51
+ import { applyLedgerRepair, formatRepairApplyResult, restoreRepairBackup, } from '../src/ledger-repair-apply.js';
4
52
  import { collectDeepPlanning, makeJournaledSolvePort, settleAsyncTicket } from '../src/loop.js';
5
53
  import { solveUnified } from '../src/unified.js';
6
- const [cmd, ...rest] = process.argv.slice(2);
7
- function rootOf(args) {
8
- const i = args.indexOf('--state-root');
9
- if (i >= 0 && args[i + 1]) return args[i + 1];
10
- const first = args.find((a)=>!a.startsWith('--') && !/^[\d]+$/.test(a));
11
- return first ?? '.';
54
+ const HELP = `用法: npx tsx scripts/state-cli.ts [--state-root <root>] [--tenant <tenant>] <cmd> [args...]
55
+ 命令:
56
+ migrate [root]
57
+ export [root] # local-only:导出共享 legacy 文件名视图
58
+ log [root] [--limit N]
59
+ stats [root]
60
+ rebuild [root] [toSeq]
61
+ rewind [root] <seq>
62
+ forget [root] wish|companion|motivation <id>
63
+ tick [root] # local-only:回收本地 pending 工单
64
+ whatif [root] <dest.db> # local-only:整库管理员 snapshot,不是租户 export
65
+ pw-list [root]
66
+ pw-request [root] <idemKey> <seam> <payloadJson>
67
+ pw-confirm [root] <idemKey> <receipt>
68
+ pw-compensate [root] <idemKey> <note>
69
+ repair-plan [root] [--mapping <file>] [--format text|json] # 只读 dry-run,零写
70
+ repair-apply [root] --mapping <file> --plan-digest <hex> --i-authorize-apply [--receipt-out <file>]
71
+ repair-rollback [root] --backup <dir> --i-authorize-rollback
72
+ 选项:
73
+ --state-root <root> 显式 state root;保留位置参数 root 用法
74
+ --tenant <tenant> 默认 local;仅是账本 scope,不是认证/授权
75
+ --limit <N> 仅 log 支持,N 为正整数
76
+ --mapping <file> repair-plan/repair-apply,人工确认的证据映射 JSON 数组
77
+ --format text|json repair-plan/repair-apply,默认 text
78
+ --plan-digest <hex> 仅 repair-apply
79
+ --i-authorize-apply 仅 repair-apply(布尔旗标)
80
+ --backup <dir> 仅 repair-rollback
81
+ --i-authorize-rollback 仅 repair-rollback(布尔旗标)
82
+ --receipt-out <file> 仅 repair-apply
83
+ 边界:tick/export/whatif 只支持 --tenant local;非 local 会在创建目录、打开账本、求解或写文件前拒绝。
84
+ repair-plan 全程只读:不建库、不迁移 schema、不改任何 ledger/projection。
85
+ db/-wal/-shm 在复制或读取期间若有变化会 fail-closed;请对静默或不可变副本重试。
86
+ repair-apply/repair-rollback 是显式授权写路径;无旗标或 digest 不匹配则零写失败。
87
+ 提示:root 路径若像数字/负数或以 '-' 开头,请用 --state-root <root> 明示。`;
88
+ const COMMANDS = new Set([
89
+ 'migrate',
90
+ 'export',
91
+ 'log',
92
+ 'stats',
93
+ 'rebuild',
94
+ 'rewind',
95
+ 'forget',
96
+ 'tick',
97
+ 'whatif',
98
+ 'pw-list',
99
+ 'pw-request',
100
+ 'pw-confirm',
101
+ 'pw-compensate',
102
+ 'repair-plan',
103
+ 'repair-apply',
104
+ 'repair-rollback',
105
+ ]);
106
+ const OPTION_NAMES = new Set([
107
+ '--state-root',
108
+ '--tenant',
109
+ '--limit',
110
+ '--mapping',
111
+ '--format',
112
+ '--plan-digest',
113
+ '--backup',
114
+ '--receipt-out',
115
+ ]);
116
+ const FLAG_NAMES = new Set(['--i-authorize-apply', '--i-authorize-rollback']);
117
+ const LOCAL_ONLY_COMMANDS = new Set(['export', 'tick', 'whatif']);
118
+ const SUBJECTS = new Set(['wish', 'companion', 'motivation']);
119
+ function usageError(message) {
120
+ console.error(message);
121
+ console.error(HELP);
122
+ process.exit(1);
12
123
  }
13
- function tenantOf(args) {
14
- const i = args.indexOf('--tenant');
15
- return i >= 0 && args[i + 1] ? args[i + 1] : 'local';
124
+ function isOptionName(token) {
125
+ return OPTION_NAMES.has(token);
16
126
  }
17
- function arg(name, fallback) {
18
- const i = process.argv.indexOf(name);
19
- return i >= 0 ? process.argv[i + 1] : fallback;
127
+ function isFlagName(token) {
128
+ return FLAG_NAMES.has(token);
129
+ }
130
+ function parsePositiveInteger(raw, label) {
131
+ if (!/^\d+$/.test(raw))
132
+ usageError(`${label} 必须是正整数:${raw}`);
133
+ const n = Number(raw);
134
+ if (!Number.isSafeInteger(n) || n <= 0)
135
+ usageError(`${label} 必须是正整数:${raw}`);
136
+ return n;
137
+ }
138
+ function parseSequence(raw, label) {
139
+ if (!/^\d+$/.test(raw))
140
+ usageError(`${label} 必须是非负整数:${raw}`);
141
+ const n = Number(raw);
142
+ if (!Number.isSafeInteger(n))
143
+ usageError(`${label} 超出安全整数范围:${raw}`);
144
+ return n;
145
+ }
146
+ function looksLikeNumeric(raw) {
147
+ return /^[+-]?(?:\d|\.\d)/.test(raw);
148
+ }
149
+ function rootAndArgs(cmd, positional, explicitRoot) {
150
+ if (explicitRoot !== undefined)
151
+ return { root: explicitRoot, args: positional };
152
+ switch (cmd) {
153
+ case 'migrate':
154
+ case 'export':
155
+ case 'log':
156
+ case 'stats':
157
+ case 'tick':
158
+ case 'pw-list':
159
+ case 'repair-plan':
160
+ case 'repair-apply':
161
+ case 'repair-rollback': {
162
+ if (positional.length > 1)
163
+ usageError(`${cmd} 只接受一个可选 root 位置参数`);
164
+ return { root: positional[0] ?? '.', args: [] };
165
+ }
166
+ case 'rebuild':
167
+ case 'rewind': {
168
+ const rootIndex = positional.findIndex(p => !looksLikeNumeric(p));
169
+ if (rootIndex < 0)
170
+ return { root: '.', args: positional };
171
+ const root = positional[rootIndex];
172
+ return { root, args: positional.filter((_, i) => i !== rootIndex) };
173
+ }
174
+ case 'forget':
175
+ case 'whatif':
176
+ case 'pw-request':
177
+ case 'pw-confirm':
178
+ case 'pw-compensate': {
179
+ if (positional.length === 0)
180
+ return { root: '.', args: [] };
181
+ return { root: positional[0], args: positional.slice(1) };
182
+ }
183
+ default:
184
+ return { root: '.', args: positional };
185
+ }
186
+ }
187
+ function validateArgs(cmd, args, opts) {
188
+ if (opts.limitRaw !== undefined && cmd !== 'log')
189
+ usageError(`${cmd} 不支持 --limit`);
190
+ if (opts.mappingRaw !== undefined && cmd !== 'repair-plan' && cmd !== 'repair-apply') {
191
+ usageError(`${cmd} 不支持 --mapping`);
192
+ }
193
+ if (opts.formatRaw !== undefined && cmd !== 'repair-plan' && cmd !== 'repair-apply') {
194
+ usageError(`${cmd} 不支持 --format`);
195
+ }
196
+ if (opts.planDigest !== undefined && cmd !== 'repair-apply')
197
+ usageError(`${cmd} 不支持 --plan-digest`);
198
+ if (opts.backup !== undefined && cmd !== 'repair-rollback')
199
+ usageError(`${cmd} 不支持 --backup`);
200
+ if (opts.receiptOut !== undefined && cmd !== 'repair-apply')
201
+ usageError(`${cmd} 不支持 --receipt-out`);
202
+ if (opts.authorizeApply && cmd !== 'repair-apply')
203
+ usageError(`${cmd} 不支持 --i-authorize-apply`);
204
+ if (opts.authorizeRollback && cmd !== 'repair-rollback')
205
+ usageError(`${cmd} 不支持 --i-authorize-rollback`);
206
+ const limit = opts.limitRaw === undefined ? 20 : parsePositiveInteger(opts.limitRaw, '--limit');
207
+ if (opts.formatRaw !== undefined && opts.formatRaw !== 'text' && opts.formatRaw !== 'json') {
208
+ usageError(`--format 只支持 text|json:${opts.formatRaw}`);
209
+ }
210
+ const format = opts.formatRaw === 'json' ? 'json' : 'text';
211
+ switch (cmd) {
212
+ case 'migrate':
213
+ case 'export':
214
+ case 'log':
215
+ case 'stats':
216
+ case 'tick':
217
+ case 'pw-list':
218
+ case 'repair-plan':
219
+ case 'repair-apply':
220
+ case 'repair-rollback':
221
+ if (args.length !== 0)
222
+ usageError(`${cmd} 不接受额外位置参数:${args.join(' ')}`);
223
+ break;
224
+ case 'rebuild':
225
+ if (args.length > 1)
226
+ usageError('rebuild 最多接受一个 toSeq');
227
+ if (args[0] !== undefined)
228
+ parseSequence(args[0], 'toSeq');
229
+ break;
230
+ case 'rewind':
231
+ if (args.length !== 1)
232
+ usageError('rewind 需要且只接受一个 seq');
233
+ parseSequence(args[0], 'seq');
234
+ break;
235
+ case 'forget':
236
+ if (args.length !== 2)
237
+ usageError('forget 需要 subject 与 id;省略 root 时请用 --state-root . 明示');
238
+ if (!SUBJECTS.has(args[0]))
239
+ usageError(`未知主体 ${args[0]}(wish|companion|motivation)`);
240
+ break;
241
+ case 'whatif':
242
+ if (args.length !== 1)
243
+ usageError('whatif 需要 dest.db;省略 root 时请用 --state-root . 明示');
244
+ break;
245
+ case 'pw-request':
246
+ if (args.length !== 3)
247
+ usageError('pw-request 需要 idemKey、seam 与 payloadJson;省略 root 时请用 --state-root . 明示');
248
+ break;
249
+ case 'pw-confirm':
250
+ if (args.length !== 2)
251
+ usageError('pw-confirm 需要 idemKey 与 receipt;省略 root 时请用 --state-root . 明示');
252
+ break;
253
+ case 'pw-compensate':
254
+ if (args.length !== 2)
255
+ usageError('pw-compensate 需要 idemKey 与 note;省略 root 时请用 --state-root . 明示');
256
+ break;
257
+ }
258
+ if (cmd === 'repair-apply') {
259
+ if (opts.mappingRaw === undefined)
260
+ usageError('repair-apply 需要 --mapping <file>');
261
+ if (opts.planDigest === undefined)
262
+ usageError('repair-apply 需要 --plan-digest <hex>');
263
+ if (!opts.authorizeApply)
264
+ usageError('repair-apply 需要显式 --i-authorize-apply');
265
+ }
266
+ if (cmd === 'repair-rollback') {
267
+ if (opts.backup === undefined)
268
+ usageError('repair-rollback 需要 --backup <dir>');
269
+ if (!opts.authorizeRollback)
270
+ usageError('repair-rollback 需要显式 --i-authorize-rollback');
271
+ }
272
+ return { limit, format };
273
+ }
274
+ function parseCli(argv) {
275
+ let cmd;
276
+ const positional = [];
277
+ const options = new Map();
278
+ const flags = new Set();
279
+ for (let i = 0; i < argv.length; i++) {
280
+ const token = argv[i];
281
+ if (token.startsWith('--')) {
282
+ if (isFlagName(token)) {
283
+ if (flags.has(token))
284
+ usageError(`重复选项 ${token}`);
285
+ flags.add(token);
286
+ continue;
287
+ }
288
+ if (!isOptionName(token))
289
+ usageError(`未知选项 ${token}`);
290
+ if (options.has(token))
291
+ usageError(`重复选项 ${token}`);
292
+ const value = argv[i + 1];
293
+ if (value === undefined || value === '' || value.startsWith('--'))
294
+ usageError(`${token} 缺少值`);
295
+ options.set(token, value);
296
+ i++;
297
+ continue;
298
+ }
299
+ if (token.startsWith('-') && !looksLikeNumeric(token))
300
+ usageError(`未知选项 ${token}`);
301
+ if (cmd === undefined)
302
+ cmd = token;
303
+ else
304
+ positional.push(token);
305
+ }
306
+ if (cmd === undefined)
307
+ usageError('缺少命令');
308
+ if (!COMMANDS.has(cmd)) {
309
+ return {
310
+ cmd, root: '.', tenant: 'local', limit: 20, format: 'text',
311
+ authorizeApply: false, authorizeRollback: false, positional,
312
+ };
313
+ }
314
+ const tenant = options.get('--tenant') ?? 'local';
315
+ if (tenant.trim() === '')
316
+ usageError('--tenant 缺少值');
317
+ const explicitRoot = options.get('--state-root');
318
+ if (explicitRoot !== undefined && explicitRoot.trim() === '')
319
+ usageError('--state-root 缺少值');
320
+ const { root, args } = rootAndArgs(cmd, positional, explicitRoot);
321
+ const authorizeApply = flags.has('--i-authorize-apply');
322
+ const authorizeRollback = flags.has('--i-authorize-rollback');
323
+ const { limit, format } = validateArgs(cmd, args, {
324
+ limitRaw: options.get('--limit'),
325
+ mappingRaw: options.get('--mapping'),
326
+ formatRaw: options.get('--format'),
327
+ planDigest: options.get('--plan-digest'),
328
+ backup: options.get('--backup'),
329
+ receiptOut: options.get('--receipt-out'),
330
+ authorizeApply,
331
+ authorizeRollback,
332
+ });
333
+ if (LOCAL_ONLY_COMMANDS.has(cmd) && tenant !== 'local') {
334
+ usageError(`${cmd} 仅支持 --tenant local;该命令未实现租户隔离,已在创建目录、打开账本、求解或写文件前拒绝。`);
335
+ }
336
+ return {
337
+ cmd,
338
+ root,
339
+ tenant,
340
+ limit,
341
+ mapping: options.get('--mapping'),
342
+ format,
343
+ planDigest: options.get('--plan-digest'),
344
+ backup: options.get('--backup'),
345
+ receiptOut: options.get('--receipt-out'),
346
+ authorizeApply,
347
+ authorizeRollback,
348
+ positional: args,
349
+ };
20
350
  }
21
351
  function atomicWrite(path, text) {
22
352
  const tmp = `${path}.tmp`;
23
353
  writeFileSync(tmp, text, 'utf-8');
24
354
  renameSync(tmp, path);
25
355
  }
26
- const HELP = '用法见文件头注释(npx tsx scripts/state-cli.ts <cmd> [root] ...)';
27
- switch(cmd){
28
- case 'migrate':
29
- {
30
- const root = rootOf(rest);
31
- const tenant = tenantOf(rest);
32
- const before = openLedgerIfExists(root, tenant)?.countEvents() ?? 0;
33
- const ledger = ensureLedger(root, tenant);
34
- const backupDir = join(root, 'gotry-state', 'pre-ledger-backup');
35
- console.log(`账本就绪:${ledger.dbPath}(events ${before} → ${ledger.countEvents()};存在旧文件时已快照至 ${backupDir}/)`);
356
+ const parsed = parseCli(process.argv.slice(2));
357
+ const { cmd, root, tenant } = parsed;
358
+ switch (cmd) {
359
+ case 'migrate': {
360
+ const before = openLedgerIfExists(root, tenant)?.countEvents() ?? 0;
361
+ const ledger = ensureLedger(root, tenant);
362
+ const backupDir = join(root, 'gotry-state', 'pre-ledger-backup');
363
+ console.log(`账本就绪:${ledger.dbPath}(events ${before} → ${ledger.countEvents()};存在旧文件时已快照至 ${backupDir}/)`);
364
+ break;
365
+ }
366
+ case 'export': {
367
+ const ledger = ensureLedger(root, tenant);
368
+ const dir = join(root === '.' ? process.cwd() : root, 'gotry-state');
369
+ mkdirSync(dir, { recursive: true });
370
+ const motivation = ledger.readMotivation();
371
+ if (motivation)
372
+ atomicWrite(join(dir, 'motivation-profile.json'), JSON.stringify(motivation, null, 2));
373
+ const pool = ledger.readWishPool();
374
+ if (pool.length)
375
+ atomicWrite(join(dir, 'wish-pool.json'), JSON.stringify(pool, null, 2));
376
+ const companions = ledger.readCompanions();
377
+ if (companions.length)
378
+ atomicWrite(join(dir, 'companions.json'), JSON.stringify(companions, null, 2));
379
+ const utility = ledger.readUtilityEvents();
380
+ if (utility.length)
381
+ atomicWrite(join(dir, 'memory-utility.jsonl'), utility.map(e => JSON.stringify(e)).join('\n') + '\n');
382
+ const trips = ledger.readTrips();
383
+ if (trips.length)
384
+ atomicWrite(join(dir, 'trips.jsonl'), trips.map(e => JSON.stringify(e)).join('\n') + '\n');
385
+ console.log(`视图已导出(单向,DB→文件;红线 6):${dir}/`);
386
+ break;
387
+ }
388
+ case 'log': {
389
+ const ledger = openLedgerIfExists(root, tenant);
390
+ if (!ledger) {
391
+ console.log('(无账本——未迁移 root,旧文件形态)');
36
392
  break;
37
393
  }
38
- case 'export':
39
- {
40
- const root = rootOf(rest);
41
- const tenant = tenantOf(rest);
42
- const ledger = ensureLedger(root, tenant);
43
- const dir = join(root === '.' ? process.cwd() : root, 'gotry-state');
44
- mkdirSync(dir, {
45
- recursive: true
46
- });
47
- const motivation = ledger.readMotivation();
48
- if (motivation) atomicWrite(join(dir, 'motivation-profile.json'), JSON.stringify(motivation, null, 2));
49
- const pool = ledger.readWishPool();
50
- if (pool.length) atomicWrite(join(dir, 'wish-pool.json'), JSON.stringify(pool, null, 2));
51
- const companions = ledger.readCompanions();
52
- if (companions.length) atomicWrite(join(dir, 'companions.json'), JSON.stringify(companions, null, 2));
53
- const utility = ledger.readUtilityEvents();
54
- if (utility.length) atomicWrite(join(dir, 'memory-utility.jsonl'), utility.map((e)=>JSON.stringify(e)).join('\n') + '\n');
55
- const trips = ledger.readTrips();
56
- if (trips.length) atomicWrite(join(dir, 'trips.jsonl'), trips.map((e)=>JSON.stringify(e)).join('\n') + '\n');
57
- console.log(`视图已导出(单向,DB→文件;红线 6):${dir}/`);
58
- break;
394
+ for (const e of ledger.readEvents(undefined, parsed.limit)) {
395
+ console.log(`${String(e.seq).padStart(5)} ${e.ts} ${e.actor.padEnd(28)} ${e.kind.padEnd(24)} ${e.subject_id}${e.idem_key ? ` #${e.idem_key}` : ''}`);
59
396
  }
60
- case 'log':
61
- {
62
- const root = rootOf(rest);
63
- const tenant = tenantOf(rest);
64
- const limit = Number(arg('--limit', '20'));
65
- const ledger = openLedgerIfExists(root, tenant);
66
- if (!ledger) {
67
- console.log('(无账本——未迁移 root,旧文件形态)');
68
- break;
69
- }
70
- for (const e of ledger.readEvents(undefined, limit)){
71
- console.log(`${String(e.seq).padStart(5)} ${e.ts} ${e.actor.padEnd(28)} ${e.kind.padEnd(24)} ${e.subject_id}${e.idem_key ? ` #${e.idem_key}` : ''}`);
72
- }
73
- break;
74
- }
75
- case 'stats':
76
- {
77
- const root = rootOf(rest);
78
- const tenant = tenantOf(rest);
79
- const ledger = openLedgerIfExists(root, tenant);
80
- if (!ledger) {
81
- console.log('(无账本——未迁移 root)');
82
- break;
83
- }
84
- console.log(`events=${ledger.countEvents()} wishes=${ledger.readWishPool().length} companions=${ledger.readCompanions().length} trips=${ledger.readTrips().length} utility=${ledger.readUtilityEvents().length} pendingRuns=${ledger.pendingWorkflowRuns().length} pendingWrites=${ledger.listPendingWrites().length}`);
397
+ break;
398
+ }
399
+ case 'stats': {
400
+ const ledger = openLedgerIfExists(root, tenant);
401
+ if (!ledger) {
402
+ console.log('(无账本——未迁移 root)');
85
403
  break;
86
404
  }
405
+ console.log(`events=${ledger.countEvents()} wishes=${ledger.readWishPool().length} companions=${ledger.readCompanions().length} trips=${ledger.readTrips().length} utility=${ledger.readUtilityEvents().length} pendingRuns=${ledger.pendingWorkflowRuns().length} pendingWrites=${ledger.listPendingWrites().length}`);
406
+ break;
407
+ }
87
408
  case 'rebuild':
88
- case 'rewind':
89
- {
90
- const root = rootOf(rest);
91
- const tenant = tenantOf(rest);
92
- const ledger = openLedgerIfExists(root, tenant);
93
- if (!ledger) {
94
- console.error('无账本');
95
- process.exit(1);
96
- }
97
- const toSeqRaw = rest.find((a)=>/^\d+$/.test(a));
98
- const r = ledger.rebuildProjections(toSeqRaw ? Number(toSeqRaw) : undefined);
99
- console.log(`fold 重建完成${toSeqRaw ? `(至 seq ${toSeqRaw};rebuild 无参即回最新)` : '(全量)'}:重放 ${r.events} 事件 → 愿望 ${r.wishes} / 同行人 ${r.companions}`);
100
- break;
409
+ case 'rewind': {
410
+ const ledger = openLedgerIfExists(root, tenant);
411
+ if (!ledger) {
412
+ console.error('无账本');
413
+ process.exit(1);
101
414
  }
102
- case 'forget':
103
- {
104
- const root = rootOf(rest);
105
- const tenant = tenantOf(rest);
106
- const ledger = openLedgerIfExists(root, tenant);
107
- if (!ledger) {
108
- console.error('无账本');
109
- process.exit(1);
110
- }
111
- const subject = rest.find((a)=>!a.startsWith('--') && a !== root);
112
- const id = rest[rest.indexOf(subject) + 1];
113
- if (!subject || id === undefined) {
114
- console.error(HELP);
115
- process.exit(1);
116
- }
117
- const map = {
118
- wish: {
119
- kinds: [
120
- 'wish.imported',
121
- 'wish.added',
122
- 'wish.updated',
123
- 'memory_utility.event'
124
- ],
125
- subjectId: id
126
- },
127
- companion: {
128
- kinds: [
129
- 'companion.imported',
130
- 'companion.saved'
131
- ],
132
- subjectId: id
133
- },
134
- motivation: {
135
- kinds: [
136
- 'motivation.imported',
137
- 'motivation.patch'
138
- ],
139
- subjectId: 'motivation'
140
- }
141
- };
142
- const spec = map[subject];
143
- if (!spec) {
144
- console.error(`未知主体 ${subject}(wish|companion|motivation)`);
145
- process.exit(1);
146
- }
147
- const r = ledger.forgetSubject([
148
- spec
149
- ]);
150
- console.log(`已物理硬删 ${r.deleted} 条事件并重建投影(审计一行留痕;红线 6「可删除」)`);
151
- break;
415
+ const toSeqRaw = parsed.positional[0];
416
+ const toSeq = toSeqRaw === undefined ? undefined : parseSequence(toSeqRaw, 'seq');
417
+ const r = ledger.rebuildProjections(toSeq);
418
+ console.log(`fold 重建完成${toSeqRaw ? `(至 seq ${toSeqRaw};rebuild 无参即回最新)` : '(全量)'}:重放 ${r.events} 事件 → 愿望 ${r.wishes} / 同行人 ${r.companions}`);
419
+ break;
420
+ }
421
+ case 'forget': {
422
+ const ledger = openLedgerIfExists(root, tenant);
423
+ if (!ledger) {
424
+ console.error('无账本');
425
+ process.exit(1);
152
426
  }
153
- case 'tick':
154
- {
155
- const root = rootOf(rest);
156
- const tenant = tenantOf(rest);
157
- const ledger = openLedgerIfExists(root, tenant);
158
- if (!ledger) {
159
- console.log('(无账本,无待办)');
160
- break;
161
- }
162
- const pending = ledger.pendingWorkflowRuns();
163
- if (pending.length === 0) {
164
- console.log('(无 pending 工单)');
165
- break;
166
- }
167
- for (const p of pending){
168
- const run = ledger.getWorkflowRun(p.id);
169
- const ticket = JSON.parse(run.ticket_json);
170
- const state = JSON.parse(run.state_json);
171
- const solve = makeJournaledSolvePort(ledger, p.id, solveUnified);
172
- const { reply } = await collectDeepPlanning(state, ticket, solve);
173
- await settleAsyncTicket(p.id, reply, root);
174
- console.log(`工单 ${p.id} 已回收(durable 恢复语义:done 步骤零重执行)`);
175
- }
427
+ const [subject, id] = parsed.positional;
428
+ const map = {
429
+ wish: { kinds: ['wish.imported', 'wish.added', 'wish.updated', 'memory_utility.event'], subjectId: id },
430
+ companion: { kinds: ['companion.imported', 'companion.saved'], subjectId: id },
431
+ motivation: { kinds: ['motivation.imported', 'motivation.patch'], subjectId: 'motivation' },
432
+ };
433
+ const spec = map[subject];
434
+ if (!spec) {
435
+ console.error(`未知主体 ${subject}(wish|companion|motivation)`);
436
+ process.exit(1);
437
+ }
438
+ const r = ledger.forgetSubject([spec]);
439
+ console.log(`已物理硬删 ${r.deleted} 条事件并重建投影(审计一行留痕;红线 6「可删除」)`);
440
+ break;
441
+ }
442
+ case 'tick': {
443
+ const ledger = openLedgerIfExists(root, tenant);
444
+ if (!ledger) {
445
+ console.log('(无账本,无待办)');
176
446
  break;
177
447
  }
178
- case 'whatif':
179
- {
180
- const root = rootOf(rest);
181
- const tenant = tenantOf(rest);
182
- const ledger = openLedgerIfExists(root, tenant);
183
- if (!ledger) {
184
- console.error('无账本');
185
- process.exit(1);
186
- }
187
- const dest = rest.find((a)=>a !== root && !a.startsWith('--'));
188
- if (!dest) {
189
- console.error(HELP);
190
- process.exit(1);
191
- }
192
- mkdirSync(dirname(dest), {
193
- recursive: true
194
- });
195
- ledger.forkWhatIf(dest);
196
- console.log(`what-if 分叉已生成:${dest}(预演在副本,正本零改动)`);
448
+ const pending = ledger.pendingWorkflowRuns();
449
+ if (pending.length === 0) {
450
+ console.log('(无 pending 工单)');
197
451
  break;
198
452
  }
199
- case 'pw-list':
200
- {
201
- const root = rootOf(rest);
202
- const tenant = tenantOf(rest);
203
- const ledger = openLedgerIfExists(root, tenant);
204
- if (!ledger) {
205
- console.log('(无账本)');
206
- break;
207
- }
208
- for (const w of ledger.listPendingWrites()){
209
- console.log(`${w.status.padEnd(12)} ${w.idem_key} seam=${w.seam}${w.receipt ? ` receipt=${w.receipt}` : ''}`);
210
- }
453
+ for (const p of pending) {
454
+ const run = ledger.getWorkflowRun(p.id);
455
+ const ticket = JSON.parse(run.ticket_json);
456
+ const state = JSON.parse(run.state_json);
457
+ const solve = makeJournaledSolvePort(ledger, p.id, solveUnified);
458
+ const { reply } = await collectDeepPlanning(state, ticket, solve);
459
+ await settleAsyncTicket(p.id, reply, root);
460
+ console.log(`工单 ${p.id} 已回收(durable 恢复语义:done 步骤零重执行)`);
461
+ }
462
+ break;
463
+ }
464
+ case 'whatif': {
465
+ const ledger = openLedgerIfExists(root, tenant);
466
+ if (!ledger) {
467
+ console.error('无账本');
468
+ process.exit(1);
469
+ }
470
+ const dest = parsed.positional[0];
471
+ mkdirSync(dirname(dest), { recursive: true });
472
+ ledger.forkWhatIf(dest);
473
+ console.log(`what-if 分叉已生成:${dest}(预演在副本,正本零改动)`);
474
+ break;
475
+ }
476
+ case 'pw-list': {
477
+ const ledger = openLedgerIfExists(root, tenant);
478
+ if (!ledger) {
479
+ console.log('(无账本)');
211
480
  break;
212
481
  }
482
+ for (const w of ledger.listPendingWrites()) {
483
+ console.log(`${w.status.padEnd(12)} ${w.idem_key} seam=${w.seam}${w.receipt ? ` receipt=${w.receipt}` : ''}`);
484
+ }
485
+ break;
486
+ }
213
487
  case 'pw-request':
214
488
  case 'pw-confirm':
215
- case 'pw-compensate':
216
- {
217
- const root = rootOf(rest);
218
- const tenant = tenantOf(rest);
219
- const ledger = ensureLedger(root, tenant);
220
- const positional = rest.filter((a)=>a !== root && !a.startsWith('--'));
221
- if (positional.length < (cmd === 'pw-request' ? 3 : 2)) {
222
- console.error(HELP);
223
- process.exit(1);
489
+ case 'pw-compensate': {
490
+ const ledger = ensureLedger(root, tenant);
491
+ const positional = parsed.positional;
492
+ if (cmd === 'pw-request') {
493
+ const r = ledger.requestPendingWrite({ idemKey: positional[0], seam: positional[1], payload: JSON.parse(positional[2]) });
494
+ console.log(`登记:${JSON.stringify(r)}(L2:只登记不执行)`);
495
+ }
496
+ else if (cmd === 'pw-confirm') {
497
+ const r = ledger.confirmPendingWrite(positional[0], positional[1]);
498
+ console.log(`确认:${JSON.stringify(r)}`);
499
+ }
500
+ else {
501
+ const r = ledger.compensatePendingWrite(positional[0], positional[1]);
502
+ console.log(`补偿:${JSON.stringify(r)}`);
503
+ }
504
+ break;
505
+ }
506
+ case 'repair-plan': {
507
+ // 全程只读:不用 ensureLedger/openLedgerIfExists(它们会建库、迁移 v1 schema、
508
+ // 重建投影);planLedgerRepair 把 db 复制到临时目录再只读读取,正本一次都不打开。
509
+ if (!ledgerExists(root)) {
510
+ console.error(`无账本(未迁移 root):${ledgerDbPath(root)}`);
511
+ process.exit(1);
512
+ }
513
+ let mappings;
514
+ if (parsed.mapping !== undefined) {
515
+ try {
516
+ mappings = loadEvidenceMappingFile(parsed.mapping);
224
517
  }
225
- if (cmd === 'pw-request') {
226
- const r = ledger.requestPendingWrite({
227
- idemKey: positional[0],
228
- seam: positional[1],
229
- payload: JSON.parse(positional[2])
230
- });
231
- console.log(`登记:${JSON.stringify(r)}(L2:只登记不执行)`);
232
- } else if (cmd === 'pw-confirm') {
233
- const r = ledger.confirmPendingWrite(positional[0], positional[1]);
234
- console.log(`确认:${JSON.stringify(r)}`);
235
- } else {
236
- const r = ledger.compensatePendingWrite(positional[0], positional[1]);
237
- console.log(`补偿:${JSON.stringify(r)}`);
518
+ catch (e) {
519
+ // fail-closed:映射不可读/非法 JSON 一律拒绝,绝不退化成「无映射照跑」
520
+ console.error(e instanceof Error ? e.message : String(e));
521
+ process.exit(1);
238
522
  }
239
- break;
240
523
  }
524
+ try {
525
+ const plan = planLedgerRepair({ stateRoot: root, sourceTenant: tenant, mappings });
526
+ console.log(parsed.format === 'json' ? JSON.stringify(plan, null, 2) : formatRepairPlan(plan));
527
+ }
528
+ catch (e) {
529
+ // source db/WAL/SHM changed during the read: never present a mixed-time plan.
530
+ console.error(e instanceof Error ? e.message : String(e));
531
+ process.exit(1);
532
+ }
533
+ break;
534
+ }
535
+ case 'repair-apply': {
536
+ if (!ledgerExists(root)) {
537
+ console.error(`无账本(未迁移 root):${ledgerDbPath(root)}`);
538
+ process.exit(1);
539
+ }
540
+ let mappings;
541
+ try {
542
+ mappings = loadEvidenceMappingFile(parsed.mapping);
543
+ }
544
+ catch (e) {
545
+ console.error(e instanceof Error ? e.message : String(e));
546
+ process.exit(1);
547
+ }
548
+ try {
549
+ const result = applyLedgerRepair({
550
+ stateRoot: root,
551
+ sourceTenant: tenant,
552
+ mappings,
553
+ planDigest: parsed.planDigest,
554
+ authorizeApply: true,
555
+ receiptOut: parsed.receiptOut,
556
+ });
557
+ console.log(parsed.format === 'json' ? JSON.stringify(result, null, 2) : formatRepairApplyResult(result));
558
+ }
559
+ catch (e) {
560
+ console.error(e instanceof Error ? e.message : String(e));
561
+ process.exit(1);
562
+ }
563
+ break;
564
+ }
565
+ case 'repair-rollback': {
566
+ try {
567
+ const r = restoreRepairBackup({
568
+ stateRoot: root,
569
+ backupDir: parsed.backup,
570
+ authorizeRollback: true,
571
+ });
572
+ console.log(`已从校验过的 backup 还原:${r.restoredFrom}`);
573
+ console.log(`plan-digest=${r.manifest.planDigest} mapping-sha256=${r.manifest.mappingSha256}`);
574
+ }
575
+ catch (e) {
576
+ console.error(e instanceof Error ? e.message : String(e));
577
+ process.exit(1);
578
+ }
579
+ break;
580
+ }
241
581
  default:
242
582
  console.error(cmd ? `未知命令 ${cmd}` : HELP);
243
583
  console.error(HELP);
244
584
  process.exit(1);
245
585
  }
246
-
247
-
248
- //# sourceURL=ts/scripts/state-cli.ts