minimal-agent 0.12.0 → 0.14.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 (472) hide show
  1. package/README.md +6 -5
  2. package/package.json +62 -5
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +204 -185
  16. package/plugins/workflow-runner/src/index.ts +249 -224
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +404 -467
  28. package/plugins/workflow-runner/src/runner.ts +491 -535
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +172 -152
  54. package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -105
  58. package/plugins/workflow-runner/src/types.ts +155 -520
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +542 -469
  68. package/plugins/workflow-runner/src/workflowState.ts +639 -589
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/skill-creator/scripts/run_eval.py +3 -2
  92. package/skills/ui-design/SKILL.md +5 -2
  93. package/skills/ui-design/references/layout-composition.md +1 -1
  94. package/skills/workflow-creator/SKILL.md +344 -0
  95. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  96. package/skills/workflow-creator/references/api.md +216 -0
  97. package/skills/workflow-creator/references/migration.md +103 -0
  98. package/skills/workflow-creator/references/patterns.md +779 -0
  99. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  100. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  101. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  102. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  103. package/src/advisor/advisorCoordinator.js +503 -0
  104. package/src/advisor/advisorCoordinator.ts +657 -0
  105. package/src/cli/configMenu.tsx +0 -1
  106. package/src/cli/print.js +44 -6
  107. package/src/cli/print.ts +73 -4
  108. package/src/cli/streamJson.js +5 -6
  109. package/src/cli/streamJson.ts +8 -4
  110. package/src/cli/wizards/advisorWizard.js +4 -2
  111. package/src/cli/wizards/advisorWizard.tsx +8 -2
  112. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  113. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  114. package/src/collaboration/taskFlow.js +115 -0
  115. package/src/collaboration/taskFlow.ts +169 -0
  116. package/src/config/configDefaults.js +41 -1
  117. package/src/config/configDefaults.ts +43 -1
  118. package/src/config/configDiagnostics.ts +2 -2
  119. package/src/config/configFile.js +40 -9
  120. package/src/config/configFile.ts +60 -11
  121. package/src/config/configService.js +443 -74
  122. package/src/config/configService.ts +723 -142
  123. package/src/config/numericLimits.js +22 -0
  124. package/src/config/numericLimits.ts +24 -0
  125. package/src/config.js +1 -0
  126. package/src/config.ts +3 -2
  127. package/src/context/budgetPlan.js +1 -1
  128. package/src/context/budgetPlan.ts +1 -1
  129. package/src/context/compact.js +7 -2
  130. package/src/context/compact.ts +9 -2
  131. package/src/context/microCompactLite.js +212 -13
  132. package/src/context/microCompactLite.ts +261 -12
  133. package/src/context/sessionRegistry.js +8 -1
  134. package/src/context/sessionRegistry.ts +18 -5
  135. package/src/context/toolResultArchive.js +72 -0
  136. package/src/context/toolResultArchive.ts +95 -0
  137. package/src/goal/errors.js +8 -0
  138. package/src/goal/errors.ts +18 -0
  139. package/src/goal/goalRuntime.js +344 -0
  140. package/src/goal/goalRuntime.ts +466 -0
  141. package/src/goal/goalStore.js +200 -0
  142. package/src/goal/goalStore.ts +219 -0
  143. package/src/goal/index.js +4 -0
  144. package/src/goal/index.ts +4 -0
  145. package/src/goal/statusMapping.js +71 -0
  146. package/src/goal/statusMapping.ts +95 -0
  147. package/src/goal/types.js +7 -0
  148. package/src/goal/types.ts +179 -0
  149. package/src/goal/workflowController.js +306 -0
  150. package/src/goal/workflowController.ts +360 -0
  151. package/src/harness/evidenceLedger.js +2 -0
  152. package/src/harness/evidenceLedger.ts +1 -0
  153. package/src/harness/stallGuard.js +9 -3
  154. package/src/harness/stallGuard.ts +7 -3
  155. package/src/images/imageResolver.js +161 -0
  156. package/src/images/imageResolver.ts +189 -0
  157. package/src/infra/verification.js +56 -20
  158. package/src/infra/verification.ts +87 -20
  159. package/src/llm/client.js +79 -21
  160. package/src/llm/client.ts +182 -35
  161. package/src/llm/gatewayClient.js +201 -0
  162. package/src/llm/gatewayClient.ts +299 -0
  163. package/src/llm/messageProvenance.js +46 -0
  164. package/src/llm/messageProvenance.ts +58 -0
  165. package/src/llm/modelProvider.js +1 -0
  166. package/src/llm/modelProvider.ts +22 -0
  167. package/src/llm/providers/anthropicFormat.js +108 -1
  168. package/src/llm/providers/anthropicFormat.ts +115 -4
  169. package/src/llm/providers/openaiFormat.js +9 -0
  170. package/src/llm/providers/openaiFormat.ts +12 -3
  171. package/src/loop.js +319 -54
  172. package/src/loop.ts +373 -57
  173. package/src/main.js +4 -1
  174. package/src/main.tsx +4 -1
  175. package/src/managedExecution/index.js +2 -0
  176. package/src/managedExecution/index.ts +2 -0
  177. package/src/managedExecution/registry.js +15 -0
  178. package/src/managedExecution/registry.ts +20 -0
  179. package/src/managedExecution/types.js +1 -0
  180. package/src/managedExecution/types.ts +86 -0
  181. package/src/modelRef.js +9 -0
  182. package/src/modelRef.ts +31 -0
  183. package/src/multimodal.js +14 -28
  184. package/src/multimodal.ts +17 -33
  185. package/src/net/lanDiscovery.js +65 -0
  186. package/src/net/lanDiscovery.ts +82 -0
  187. package/src/plugin-sdk.js +28 -3
  188. package/src/plugin-sdk.ts +39 -6
  189. package/src/plugins/pluginApi.ts +16 -1
  190. package/src/plugins/pluginLoader.js +4 -0
  191. package/src/plugins/pluginLoader.ts +6 -0
  192. package/src/plugins/pluginRunner.js +152 -9
  193. package/src/plugins/pluginRunner.ts +186 -8
  194. package/src/plugins/slashFallback.js +113 -0
  195. package/src/plugins/slashFallback.ts +137 -0
  196. package/src/prompts/policyRegistry.js +15 -8
  197. package/src/prompts/policyRegistry.ts +18 -8
  198. package/src/prompts/promptAssembly.js +103 -12
  199. package/src/prompts/promptAssembly.ts +114 -12
  200. package/src/prompts/skillList.js +21 -3
  201. package/src/prompts/skillList.ts +27 -2
  202. package/src/prompts/stableSystemPrompt.js +18 -0
  203. package/src/prompts/stableSystemPrompt.ts +33 -0
  204. package/src/runtime/agentRuntimeContext.js +8 -2
  205. package/src/runtime/agentRuntimeContext.ts +17 -4
  206. package/src/session/runAgentTurn.js +78 -12
  207. package/src/session/runAgentTurn.ts +105 -23
  208. package/src/session/runTurn.js +10 -9
  209. package/src/session/runTurn.ts +17 -8
  210. package/src/session/sessionState.ts +2 -0
  211. package/src/team/auth.js +186 -0
  212. package/src/team/auth.ts +298 -0
  213. package/src/team/cli.js +105 -0
  214. package/src/team/cli.ts +122 -0
  215. package/src/team/onlineToolContract.js +64 -0
  216. package/src/team/onlineToolContract.ts +109 -0
  217. package/src/team/toolPolicy.js +36 -0
  218. package/src/team/toolPolicy.ts +75 -0
  219. package/src/tools/advisor/advisor.js +148 -37
  220. package/src/tools/advisor/advisor.ts +161 -38
  221. package/src/tools/advisor/advisorDecision.js +71 -0
  222. package/src/tools/advisor/advisorDecision.ts +85 -0
  223. package/src/tools/agent/agent.js +18 -5
  224. package/src/tools/agent/agent.ts +21 -7
  225. package/src/tools/agent/agentControl.js +246 -0
  226. package/src/tools/agent/agentControl.ts +284 -0
  227. package/src/tools/agent/agentTaskService.js +40 -1
  228. package/src/tools/agent/agentTaskService.ts +44 -1
  229. package/src/tools/agent/agentTypes.js +14 -2
  230. package/src/tools/agent/agentTypes.ts +15 -2
  231. package/src/tools/applypatch/applyPatch.js +362 -0
  232. package/src/tools/applypatch/applyPatch.ts +428 -0
  233. package/src/tools/bash/bash.js +70 -18
  234. package/src/tools/bash/bash.ts +75 -20
  235. package/src/tools/capabilities.js +10 -5
  236. package/src/tools/capabilities.ts +10 -5
  237. package/src/tools/computeruse/computerIntent.js +32 -0
  238. package/src/tools/computeruse/computerIntent.ts +46 -0
  239. package/src/tools/computeruse/telemetryLog.js +12 -0
  240. package/src/tools/computeruse/telemetryLog.ts +16 -0
  241. package/src/tools/computeruse/vision/telemetry.js +1 -0
  242. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  243. package/src/tools/effectiveToolSet.js +4 -0
  244. package/src/tools/effectiveToolSet.ts +4 -0
  245. package/src/tools/index.js +21 -2
  246. package/src/tools/index.ts +33 -2
  247. package/src/tools/powershell/powershell.js +18 -1
  248. package/src/tools/powershell/powershell.ts +18 -2
  249. package/src/tools/presentresult/presentresult.js +6 -15
  250. package/src/tools/presentresult/presentresult.ts +6 -15
  251. package/src/tools/read/read.js +69 -11
  252. package/src/tools/read/read.ts +70 -11
  253. package/src/tools/shared/fileUtils.js +1 -2
  254. package/src/tools/shared/fileUtils.ts +1 -2
  255. package/src/tools/shared/permanentDeleteGuard.js +34 -3
  256. package/src/tools/shared/permanentDeleteGuard.ts +43 -6
  257. package/src/tools/shared/toolOutputStore.js +23 -1
  258. package/src/tools/shared/toolOutputStore.ts +22 -1
  259. package/src/tools/skill/skill.js +9 -3
  260. package/src/tools/skill/skill.ts +8 -4
  261. package/src/tools/toolPromptGuides.js +117 -0
  262. package/src/tools/toolPromptGuides.ts +137 -0
  263. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  264. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  265. package/src/tools/webbrowser/browser.js +27 -11
  266. package/src/tools/webbrowser/browser.ts +68 -24
  267. package/src/tools/webbrowser/browserAutomation.js +329 -0
  268. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  269. package/src/tools/webbrowser/browserAxState.js +97 -0
  270. package/src/tools/webbrowser/browserAxState.ts +142 -0
  271. package/src/tools/webbrowser/browserBatch.js +1578 -0
  272. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  273. package/src/tools/webbrowser/browserCdp.js +208 -0
  274. package/src/tools/webbrowser/browserCdp.ts +255 -0
  275. package/src/tools/webbrowser/browserConditions.js +24 -0
  276. package/src/tools/webbrowser/browserConditions.ts +45 -0
  277. package/src/tools/webbrowser/browserContent.js +281 -0
  278. package/src/tools/webbrowser/browserContent.ts +438 -0
  279. package/src/tools/webbrowser/browserControl.js +131 -30
  280. package/src/tools/webbrowser/browserControl.ts +210 -50
  281. package/src/tools/webbrowser/browserDaemon.js +22 -14
  282. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  283. package/src/tools/webbrowser/browserFrames.js +47 -0
  284. package/src/tools/webbrowser/browserFrames.ts +54 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  286. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  287. package/src/tools/webbrowser/browserLocator.js +140 -0
  288. package/src/tools/webbrowser/browserLocator.ts +194 -0
  289. package/src/tools/webbrowser/browserOutcome.js +10 -17
  290. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  291. package/src/tools/webbrowser/browserRecovery.js +58 -0
  292. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  293. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  294. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  295. package/src/tools/webbrowser/browserService.js +28 -2
  296. package/src/tools/webbrowser/browserService.ts +49 -9
  297. package/src/tools/webbrowser/browserStream.js +132 -33
  298. package/src/tools/webbrowser/browserStream.ts +224 -50
  299. package/src/tools/webbrowser/browserTabs.js +48 -15
  300. package/src/tools/webbrowser/browserTabs.ts +178 -96
  301. package/src/tools/webbrowser/webbrowser.js +683 -144
  302. package/src/tools/webbrowser/webbrowser.ts +979 -236
  303. package/src/tools/webfetch/preapproved.js +0 -2
  304. package/src/tools/webfetch/preapproved.ts +0 -2
  305. package/src/tools/websearch/websearch.js +129 -8
  306. package/src/tools/websearch/websearch.ts +138 -6
  307. package/src/types.ts +450 -42
  308. package/src/ui/App.js +377 -58
  309. package/src/ui/App.tsx +576 -111
  310. package/src/ui/LiveArea.js +14 -8
  311. package/src/ui/LiveArea.tsx +14 -10
  312. package/src/ui/MessageList.js +63 -20
  313. package/src/ui/MessageList.tsx +101 -16
  314. package/src/ui/ModelPicker.js +7 -4
  315. package/src/ui/ModelPicker.tsx +55 -8
  316. package/src/ui/hooks/useChat.js +152 -163
  317. package/src/ui/hooks/useChat.ts +396 -334
  318. package/src/ui/loginCommand.js +56 -0
  319. package/src/ui/loginCommand.ts +63 -0
  320. package/src/ui/toolProgress.js +41 -0
  321. package/src/ui/toolProgress.ts +44 -0
  322. package/src/web/browserBridge.js +20 -2
  323. package/src/web/browserBridge.ts +20 -2
  324. package/src/web/protocol.ts +1897 -194
  325. package/workflows/adaptive-research/workflow.mjs +86 -0
  326. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  327. package/workflows/e2e-llm/workflow.mjs +52 -0
  328. package/workflows/e2e-smoke/workflow.mjs +59 -0
  329. package/workflows/e2e-vision-schema/README.md +48 -0
  330. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  331. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  332. package/workflows/file-census/README.md +14 -0
  333. package/workflows/file-census/scripts/.gitkeep +2 -0
  334. package/workflows/file-census/workflow.mjs +110 -0
  335. package/workflows/goal/README.md +166 -0
  336. package/workflows/goal/prompts/audit.md +57 -0
  337. package/workflows/goal/prompts/contract.md +56 -0
  338. package/workflows/goal/prompts/iterate.md +37 -0
  339. package/workflows/goal/workflow.mjs +501 -0
  340. package/workflows/illustrate/README.md +90 -0
  341. package/workflows/illustrate/assets/engines.json +20 -0
  342. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  343. package/workflows/illustrate/assets/extract-bing.js +33 -0
  344. package/workflows/illustrate/assets/extract-google.js +31 -0
  345. package/workflows/illustrate/workflow.mjs +301 -0
  346. package/workflows/plan/workflow.mjs +389 -0
  347. package/workflows/question-crops/README.md +35 -0
  348. package/workflows/question-crops/prompts/inventory.md +23 -0
  349. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  350. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  351. package/workflows/question-crops/workflow.mjs +172 -0
  352. package/workflows/ralph-loop/workflow.mjs +162 -0
  353. package/workflows/research/DESIGN.md +449 -0
  354. package/workflows/research/README.md +74 -0
  355. package/workflows/research/prompts/s0-goal.md +43 -0
  356. package/workflows/research/prompts/s1-early-exit.md +22 -0
  357. package/workflows/research/prompts/s1-map.md +58 -0
  358. package/workflows/research/prompts/s2-options.md +53 -0
  359. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  360. package/workflows/research/prompts/s4-verify.md +74 -0
  361. package/workflows/research/prompts/s5-synthesis.md +81 -0
  362. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  363. package/workflows/research/prompts/s6-package.md +32 -0
  364. package/workflows/research/scripts/build-report.mjs +98 -0
  365. package/workflows/research/workflow.mjs +288 -0
  366. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  367. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  368. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  369. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  370. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  371. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  372. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  373. package/workflows/wrong-question-docx/README.md +55 -0
  374. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  375. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  376. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  377. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  378. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  379. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  380. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  381. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  382. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  383. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  384. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  385. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  386. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  387. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  388. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  389. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  390. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  391. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  392. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  393. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  394. package/plugins/workflow-runner/src/expressions.js +0 -618
  395. package/plugins/workflow-runner/src/expressions.ts +0 -622
  396. package/plugins/workflow-runner/src/loader.js +0 -573
  397. package/plugins/workflow-runner/src/loader.ts +0 -721
  398. package/plugins/workflow-runner/src/multimodal.js +0 -38
  399. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  400. package/plugins/workflow-runner/src/recovery.js +0 -119
  401. package/plugins/workflow-runner/src/recovery.ts +0 -149
  402. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  403. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  404. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
  405. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
  406. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  407. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  408. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  409. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  410. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  411. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  412. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  413. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  414. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
  415. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
  416. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
  417. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
  418. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  419. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  420. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  421. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  422. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  423. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  424. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
  425. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  426. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  427. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
  428. package/plugins/workflow-runner/test/expressions.test.ts +0 -397
  429. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  430. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  431. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  432. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  433. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  434. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  435. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  436. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  437. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  438. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  439. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
  440. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  441. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  442. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
  443. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -199
  468. package/workflows/schema.json +0 -176
  469. package/workflows/webppt.yaml +0 -496
  470. package/workflows/wechat-reading-shots.yaml +0 -315
  471. package/workflows/word.yaml +0 -720
  472. package/workflows/youtube-shorts.yaml +0 -202
@@ -0,0 +1,224 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/journal.ts —— 断点续跑账本
4
+ * ------------------------------------------------------------
5
+ * 代码编排里没有「步骤索引」可以定位断点 —— 控制流是 JS 决定的,同一个脚本
6
+ * 两次运行经过的分支可能都不一样。所以断点按**车道内序号 + 内容指纹**记账:
7
+ * 每次 agent/llm/skill/tool/verify/ask 调用记一行 jsonl,resume 时按序重放,
8
+ * 某条车道上首个指纹失配处转实跑并作废该车道其后全部记录。
9
+ *
10
+ * ------------------------------------------------------------
11
+ * ⚠️ **车道(lane)解决的是并发下的定位错乱**(这是实测过的降级,不是假想):
12
+ *
13
+ * 序号原本在**拿到并发闸之后**才自增,于是扇出超过并发上限(8)时,第 9 项的
14
+ * 序号取决于前 8 项谁先返回 —— 也就是取决于 LLM 延迟。同一个脚本两次运行的
15
+ * 序号分配可能完全不同 → 首个失配 → 后面全部实跑,**resume 静默失效**。
16
+ * N ≤ 8 的用例恒绿,所以这个坑不写针对性测试就看不见。
17
+ *
18
+ * 修法不是改成内容寻址(那会把下面那条安全属性静默换掉),而是给每条并发链
19
+ * 一个**确定性的车道名**,车道内序号严格按该链的执行顺序自增 —— 链本身是串行的,
20
+ * 所以顺序确定。车道名由 `pipeline()` 按 (嵌套路径, 项下标) 生成,与调度无关。
21
+ *
22
+ * ------------------------------------------------------------
23
+ * ⚠️ **为什么不是纯内容寻址**(有人会想「按 fp 查表不就顺序无关了」):
24
+ *
25
+ * run 1: agent 产出 plan v1 → agent('审查 out/plan.md') 得 R2
26
+ * run 2: 第一步实跑产出 plan v2 → 那句审查的 fp **一模一样**(路径是常量,
27
+ * 内容在磁盘上)→ 命中缓存 → 拿到的是对 v1 的审查
28
+ *
29
+ * 失配即作废其后记录,正是为了挡住这个。内容寻址挡不住,且是**静默错误**。
30
+ *
31
+ * ------------------------------------------------------------
32
+ * ⚠️ **必须现在就认下的语义降级**(别等第一次真实 resume 才发现):
33
+ *
34
+ * 指纹按**内容**算(kind + 参数)。而 `agent()` 的 prompt 常常是用上一次调用的
35
+ * 产出拼出来的,`runQuery` 又非确定性 —— 于是**重放边界之后的第一次实跑一旦
36
+ * 产出不同,同车道其后所有调用的指纹全部失配、余下部分整体作废**。
37
+ * 代价与 Claude Code 官方文档写明的那条一致("every agent that started after
38
+ * that one runs again"),接受。
39
+ *
40
+ * 这也是 `scriptGuard` 禁 `Date.now()`/`Math.random()`/无参 `new Date()` 的原因 ——
41
+ * 脚本里任何不确定性都会让指纹在重放时必然失配,等于 resume 直接失效。
42
+ *
43
+ * ------------------------------------------------------------
44
+ * V2 不重放旧执行器留下的账本。每条记录都绑定引擎 API、bundle hash 与根运行,
45
+ * 只有同一份工作流依赖图产生的调用才能快进。
46
+ * ============================================================
47
+ */
48
+ import { createHash } from 'node:crypto';
49
+ import { appendFile, mkdir, readFile } from 'node:fs/promises';
50
+ import { dirname } from 'node:path';
51
+ /** 主车道名。脚本顶层的串行调用都走它。 */
52
+ export const MAIN_LANE = 'main';
53
+ /** 计算一次调用的内容指纹。 */
54
+ export function fingerprint(kind, args) {
55
+ // JSON.stringify 的键序依赖对象构造顺序,同一份逻辑参数可能序列化成两种字符串。
56
+ // 排序后再序列化,让指纹只取决于内容本身。
57
+ const stable = stableStringify(args);
58
+ return createHash('sha256')
59
+ .update(`${kind} ${stable}`)
60
+ .digest('hex')
61
+ .slice(0, 16);
62
+ }
63
+ function stableStringify(v) {
64
+ if (v === null || typeof v !== 'object')
65
+ return JSON.stringify(v) ?? 'null';
66
+ if (Array.isArray(v))
67
+ return `[${v.map(stableStringify).join(',')}]`;
68
+ const keys = Object.keys(v).sort();
69
+ return `{${keys
70
+ .map((k) => `${JSON.stringify(k)}:${stableStringify(v[k])}`)
71
+ .join(',')}}`;
72
+ }
73
+ export class Journal {
74
+ identity;
75
+ path;
76
+ /** 上次运行留下的记录,按 `lane#idx` 索引。 */
77
+ loaded = new Map();
78
+ /** 各车道的游标与分叉状态。 */
79
+ lanes = new Map();
80
+ /** 写入序号(跨车道全局单调,仅用于展示与 backoff)。 */
81
+ writeSeq = 0;
82
+ /** 实际命中重放的次数 —— 测试要断言这个**具体数字**。 */
83
+ replayed = 0;
84
+ /** 本次运行是否真跑过至少一次(`replaying` 据此判定,见下)。 */
85
+ liveRan = false;
86
+ constructor(path, identity) {
87
+ this.identity = identity;
88
+ this.path = path;
89
+ }
90
+ /**
91
+ * 读入上次的账本。
92
+ *
93
+ * @param backoff 额外丢弃末尾 N 条(承接 legacy 的 `self_heal.backoff`)——
94
+ * 最后一次成功调用可能留下了未完成的副作用,宁可重做。
95
+ * 按**写入顺序**丢弃,与车道无关。
96
+ */
97
+ async load(backoff = 0) {
98
+ this.loaded.clear();
99
+ let parsed = [];
100
+ try {
101
+ const raw = await readFile(this.path, 'utf8');
102
+ for (const line of raw.split('\n')) {
103
+ if (line.trim() === '')
104
+ continue;
105
+ try {
106
+ const entry = JSON.parse(line);
107
+ if (entry.apiVersion !== 2 ||
108
+ entry.bundleHash !== this.identity.bundleHash) {
109
+ // V1 或另一份依赖图留下的记录不能混入当前恢复链。rootRunId 只用于
110
+ // 追踪原始执行树;恢复天然会获得新的 rootRunId,不能据此拒绝重放。
111
+ parsed = [];
112
+ break;
113
+ }
114
+ parsed.push(entry);
115
+ }
116
+ catch {
117
+ // 单行坏掉(上次被 kill 在写盘中间)→ 从这里截断,前面的仍然可用。
118
+ break;
119
+ }
120
+ }
121
+ }
122
+ catch {
123
+ return; // 没有账本 = 全新运行
124
+ }
125
+ if (backoff > 0)
126
+ parsed = parsed.slice(0, -backoff);
127
+ for (const e of parsed) {
128
+ this.loaded.set(`${e.lane ?? MAIN_LANE}#${e.idx ?? e.seq - 1}`, e);
129
+ }
130
+ this.writeSeq = parsed.length;
131
+ }
132
+ /** 本次已重放的调用数。 */
133
+ get replayedCount() {
134
+ return this.replayed;
135
+ }
136
+ /** 上次账本里的记录数。 */
137
+ get loadedCount() {
138
+ return this.loaded.size;
139
+ }
140
+ /**
141
+ * 本次运行是否还**一次实跑都没发生**(即:到此为止全是快进)。
142
+ *
143
+ * 给**不进账本**的调用判断「这一段是不是在重放」用。典型是 `echo()`:它写进
144
+ * `ctx.history`,而 resume 时 history 是从会话文件加载的、**上一轮的 echo 已经在
145
+ * 里面了** —— 快进段再 push 一次就成了重复消息。进账本的调用不需要这个判断,
146
+ * `step()` 在重放时压根不执行 `run()`。
147
+ *
148
+ * ⚠️ 判据是「有没有实跑过」而**不是**「游标有没有走到账本末尾」:车道化之后
149
+ * 序号不再跨车道单调,「走到哪了」在并发下没有意义,而「还没干过真活」在
150
+ * 任何调度下都成立。
151
+ */
152
+ get replaying() {
153
+ return this.loaded.size > 0 && !this.liveRan;
154
+ }
155
+ /** 下一个写入序号(进度展示用,不改变任何状态)。 */
156
+ get nextSeq() {
157
+ return this.writeSeq + 1;
158
+ }
159
+ laneState(lane) {
160
+ let st = this.lanes.get(lane);
161
+ if (!st) {
162
+ st = { next: 0, diverged: false };
163
+ this.lanes.set(lane, st);
164
+ }
165
+ return st;
166
+ }
167
+ /** 某条车道是否已分叉(`pipeline` 用它把子车道的分叉向上传播)。 */
168
+ laneDiverged(lane) {
169
+ return this.laneState(lane).diverged;
170
+ }
171
+ /**
172
+ * 手工把一条车道标记为已分叉。
173
+ *
174
+ * `pipeline()` 在子链抛错、或任一子车道分叉时用它污染主车道 —— 下游串行步骤
175
+ * 依赖扇出的聚合结果,上游变了就不能再拿旧结果冒充。
176
+ */
177
+ markDiverged(lane) {
178
+ this.laneState(lane).diverged = true;
179
+ }
180
+ /**
181
+ * 走一次调用:命中重放就直接返回缓存结果,否则执行 `run` 并记账。
182
+ *
183
+ * 这是**唯一**的记账入口 —— 所有需要恢复的 `wf` 能力都必须经过它,否则 resume 时
184
+ * 车道内序号会对不上(少记一次,该车道后面全错位)。
185
+ */
186
+ async step(kind, args, run, lane = MAIN_LANE) {
187
+ const st = this.laneState(lane);
188
+ const idx = st.next++;
189
+ const fp = fingerprint(kind, args);
190
+ if (!st.diverged) {
191
+ const prev = this.loaded.get(`${lane}#${idx}`);
192
+ if (prev && prev.fp === fp) {
193
+ this.replayed++;
194
+ return prev.result;
195
+ }
196
+ // 该车道首个失配:其后的记录一律作废(控制流可能已经走了另一条分支)。
197
+ st.diverged = true;
198
+ }
199
+ // 在 await 之前翻 —— `replaying` 是给同步的 echo() 看的,晚翻会漏判。
200
+ this.liveRan = true;
201
+ const result = await run();
202
+ await this.append({
203
+ apiVersion: 2,
204
+ bundleHash: this.identity.bundleHash,
205
+ rootRunId: this.identity.rootRunId,
206
+ seq: ++this.writeSeq,
207
+ lane,
208
+ idx,
209
+ kind,
210
+ fp,
211
+ result,
212
+ });
213
+ return result;
214
+ }
215
+ async append(entry) {
216
+ try {
217
+ await mkdir(dirname(this.path), { recursive: true });
218
+ await appendFile(this.path, `${JSON.stringify(entry)}\n`, 'utf8');
219
+ }
220
+ catch {
221
+ // 账本写失败不该让任务本身挂掉 —— 代价只是下次 resume 少续一点。
222
+ }
223
+ }
224
+ }
@@ -0,0 +1,274 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/journal.ts —— 断点续跑账本
4
+ * ------------------------------------------------------------
5
+ * 代码编排里没有「步骤索引」可以定位断点 —— 控制流是 JS 决定的,同一个脚本
6
+ * 两次运行经过的分支可能都不一样。所以断点按**车道内序号 + 内容指纹**记账:
7
+ * 每次 agent/llm/skill/tool/verify/ask 调用记一行 jsonl,resume 时按序重放,
8
+ * 某条车道上首个指纹失配处转实跑并作废该车道其后全部记录。
9
+ *
10
+ * ------------------------------------------------------------
11
+ * ⚠️ **车道(lane)解决的是并发下的定位错乱**(这是实测过的降级,不是假想):
12
+ *
13
+ * 序号原本在**拿到并发闸之后**才自增,于是扇出超过并发上限(8)时,第 9 项的
14
+ * 序号取决于前 8 项谁先返回 —— 也就是取决于 LLM 延迟。同一个脚本两次运行的
15
+ * 序号分配可能完全不同 → 首个失配 → 后面全部实跑,**resume 静默失效**。
16
+ * N ≤ 8 的用例恒绿,所以这个坑不写针对性测试就看不见。
17
+ *
18
+ * 修法不是改成内容寻址(那会把下面那条安全属性静默换掉),而是给每条并发链
19
+ * 一个**确定性的车道名**,车道内序号严格按该链的执行顺序自增 —— 链本身是串行的,
20
+ * 所以顺序确定。车道名由 `pipeline()` 按 (嵌套路径, 项下标) 生成,与调度无关。
21
+ *
22
+ * ------------------------------------------------------------
23
+ * ⚠️ **为什么不是纯内容寻址**(有人会想「按 fp 查表不就顺序无关了」):
24
+ *
25
+ * run 1: agent 产出 plan v1 → agent('审查 out/plan.md') 得 R2
26
+ * run 2: 第一步实跑产出 plan v2 → 那句审查的 fp **一模一样**(路径是常量,
27
+ * 内容在磁盘上)→ 命中缓存 → 拿到的是对 v1 的审查
28
+ *
29
+ * 失配即作废其后记录,正是为了挡住这个。内容寻址挡不住,且是**静默错误**。
30
+ *
31
+ * ------------------------------------------------------------
32
+ * ⚠️ **必须现在就认下的语义降级**(别等第一次真实 resume 才发现):
33
+ *
34
+ * 指纹按**内容**算(kind + 参数)。而 `agent()` 的 prompt 常常是用上一次调用的
35
+ * 产出拼出来的,`runQuery` 又非确定性 —— 于是**重放边界之后的第一次实跑一旦
36
+ * 产出不同,同车道其后所有调用的指纹全部失配、余下部分整体作废**。
37
+ * 代价与 Claude Code 官方文档写明的那条一致("every agent that started after
38
+ * that one runs again"),接受。
39
+ *
40
+ * 这也是 `scriptGuard` 禁 `Date.now()`/`Math.random()`/无参 `new Date()` 的原因 ——
41
+ * 脚本里任何不确定性都会让指纹在重放时必然失配,等于 resume 直接失效。
42
+ *
43
+ * ------------------------------------------------------------
44
+ * V2 不重放旧执行器留下的账本。每条记录都绑定引擎 API、bundle hash 与根运行,
45
+ * 只有同一份工作流依赖图产生的调用才能快进。
46
+ * ============================================================
47
+ */
48
+
49
+ import { createHash } from 'node:crypto';
50
+ import { appendFile, mkdir, readFile } from 'node:fs/promises';
51
+ import { dirname } from 'node:path';
52
+
53
+ /** 主车道名。脚本顶层的串行调用都走它。 */
54
+ export const MAIN_LANE = 'main';
55
+
56
+ /** 账本里一条已完成调用的记录。 */
57
+ export interface JournalEntry {
58
+ apiVersion: 2;
59
+ bundleHash: string;
60
+ rootRunId: string;
61
+ /** 写入顺序(1-based)。并发下它**不代表**逻辑顺序,只用于展示与 backoff。 */
62
+ seq: number;
63
+ /** 车道名;v1 记录没有这个字段,载入时按 'main' 解释。 */
64
+ lane?: string;
65
+ /** 车道内序号(0-based);v1 记录没有,载入时按 `seq - 1` 解释。 */
66
+ idx?: number;
67
+ /** 调用类别:agent / llm / skill / tool / verify / ask …… */
68
+ kind: string;
69
+ /** 内容指纹:sha256(kind + 归一化参数) 前 16 位。 */
70
+ fp: string;
71
+ /** 该次调用的返回值(JSON 可序列化)。 */
72
+ result: unknown;
73
+ }
74
+
75
+ export interface JournalIdentity {
76
+ bundleHash: string;
77
+ rootRunId: string;
78
+ }
79
+
80
+ /** 计算一次调用的内容指纹。 */
81
+ export function fingerprint(kind: string, args: unknown): string {
82
+ // JSON.stringify 的键序依赖对象构造顺序,同一份逻辑参数可能序列化成两种字符串。
83
+ // 排序后再序列化,让指纹只取决于内容本身。
84
+ const stable = stableStringify(args);
85
+ return createHash('sha256')
86
+ .update(`${kind} ${stable}`)
87
+ .digest('hex')
88
+ .slice(0, 16);
89
+ }
90
+
91
+ function stableStringify(v: unknown): string {
92
+ if (v === null || typeof v !== 'object') return JSON.stringify(v) ?? 'null';
93
+ if (Array.isArray(v)) return `[${v.map(stableStringify).join(',')}]`;
94
+ const keys = Object.keys(v as Record<string, unknown>).sort();
95
+ return `{${keys
96
+ .map(
97
+ (k) =>
98
+ `${JSON.stringify(k)}:${stableStringify((v as Record<string, unknown>)[k])}`,
99
+ )
100
+ .join(',')}}`;
101
+ }
102
+
103
+ interface LaneState {
104
+ /** 该车道下一次调用的序号(0-based)。 */
105
+ next: number;
106
+ /** 该车道是否已失配转实跑。 */
107
+ diverged: boolean;
108
+ }
109
+
110
+ export class Journal {
111
+ private readonly path: string;
112
+ /** 上次运行留下的记录,按 `lane#idx` 索引。 */
113
+ private loaded = new Map<string, JournalEntry>();
114
+ /** 各车道的游标与分叉状态。 */
115
+ private lanes = new Map<string, LaneState>();
116
+ /** 写入序号(跨车道全局单调,仅用于展示与 backoff)。 */
117
+ private writeSeq = 0;
118
+ /** 实际命中重放的次数 —— 测试要断言这个**具体数字**。 */
119
+ private replayed = 0;
120
+ /** 本次运行是否真跑过至少一次(`replaying` 据此判定,见下)。 */
121
+ private liveRan = false;
122
+
123
+ constructor(path: string, private readonly identity: JournalIdentity) {
124
+ this.path = path;
125
+ }
126
+
127
+ /**
128
+ * 读入上次的账本。
129
+ *
130
+ * @param backoff 额外丢弃末尾 N 条(承接 legacy 的 `self_heal.backoff`)——
131
+ * 最后一次成功调用可能留下了未完成的副作用,宁可重做。
132
+ * 按**写入顺序**丢弃,与车道无关。
133
+ */
134
+ async load(backoff = 0): Promise<void> {
135
+ this.loaded.clear();
136
+ let parsed: JournalEntry[] = [];
137
+ try {
138
+ const raw = await readFile(this.path, 'utf8');
139
+ for (const line of raw.split('\n')) {
140
+ if (line.trim() === '') continue;
141
+ try {
142
+ const entry = JSON.parse(line) as Partial<JournalEntry>;
143
+ if (
144
+ entry.apiVersion !== 2 ||
145
+ entry.bundleHash !== this.identity.bundleHash
146
+ ) {
147
+ // V1 或另一份依赖图留下的记录不能混入当前恢复链。rootRunId 只用于
148
+ // 追踪原始执行树;恢复天然会获得新的 rootRunId,不能据此拒绝重放。
149
+ parsed = [];
150
+ break;
151
+ }
152
+ parsed.push(entry as JournalEntry);
153
+ } catch {
154
+ // 单行坏掉(上次被 kill 在写盘中间)→ 从这里截断,前面的仍然可用。
155
+ break;
156
+ }
157
+ }
158
+ } catch {
159
+ return; // 没有账本 = 全新运行
160
+ }
161
+ if (backoff > 0) parsed = parsed.slice(0, -backoff);
162
+ for (const e of parsed) {
163
+ this.loaded.set(`${e.lane ?? MAIN_LANE}#${e.idx ?? e.seq - 1}`, e);
164
+ }
165
+ this.writeSeq = parsed.length;
166
+ }
167
+
168
+ /** 本次已重放的调用数。 */
169
+ get replayedCount(): number {
170
+ return this.replayed;
171
+ }
172
+
173
+ /** 上次账本里的记录数。 */
174
+ get loadedCount(): number {
175
+ return this.loaded.size;
176
+ }
177
+
178
+ /**
179
+ * 本次运行是否还**一次实跑都没发生**(即:到此为止全是快进)。
180
+ *
181
+ * 给**不进账本**的调用判断「这一段是不是在重放」用。典型是 `echo()`:它写进
182
+ * `ctx.history`,而 resume 时 history 是从会话文件加载的、**上一轮的 echo 已经在
183
+ * 里面了** —— 快进段再 push 一次就成了重复消息。进账本的调用不需要这个判断,
184
+ * `step()` 在重放时压根不执行 `run()`。
185
+ *
186
+ * ⚠️ 判据是「有没有实跑过」而**不是**「游标有没有走到账本末尾」:车道化之后
187
+ * 序号不再跨车道单调,「走到哪了」在并发下没有意义,而「还没干过真活」在
188
+ * 任何调度下都成立。
189
+ */
190
+ get replaying(): boolean {
191
+ return this.loaded.size > 0 && !this.liveRan;
192
+ }
193
+
194
+ /** 下一个写入序号(进度展示用,不改变任何状态)。 */
195
+ get nextSeq(): number {
196
+ return this.writeSeq + 1;
197
+ }
198
+
199
+ private laneState(lane: string): LaneState {
200
+ let st = this.lanes.get(lane);
201
+ if (!st) {
202
+ st = { next: 0, diverged: false };
203
+ this.lanes.set(lane, st);
204
+ }
205
+ return st;
206
+ }
207
+
208
+ /** 某条车道是否已分叉(`pipeline` 用它把子车道的分叉向上传播)。 */
209
+ laneDiverged(lane: string): boolean {
210
+ return this.laneState(lane).diverged;
211
+ }
212
+
213
+ /**
214
+ * 手工把一条车道标记为已分叉。
215
+ *
216
+ * `pipeline()` 在子链抛错、或任一子车道分叉时用它污染主车道 —— 下游串行步骤
217
+ * 依赖扇出的聚合结果,上游变了就不能再拿旧结果冒充。
218
+ */
219
+ markDiverged(lane: string): void {
220
+ this.laneState(lane).diverged = true;
221
+ }
222
+
223
+ /**
224
+ * 走一次调用:命中重放就直接返回缓存结果,否则执行 `run` 并记账。
225
+ *
226
+ * 这是**唯一**的记账入口 —— 所有需要恢复的 `wf` 能力都必须经过它,否则 resume 时
227
+ * 车道内序号会对不上(少记一次,该车道后面全错位)。
228
+ */
229
+ async step<T>(
230
+ kind: string,
231
+ args: unknown,
232
+ run: () => Promise<T>,
233
+ lane: string = MAIN_LANE,
234
+ ): Promise<T> {
235
+ const st = this.laneState(lane);
236
+ const idx = st.next++;
237
+ const fp = fingerprint(kind, args);
238
+
239
+ if (!st.diverged) {
240
+ const prev = this.loaded.get(`${lane}#${idx}`);
241
+ if (prev && prev.fp === fp) {
242
+ this.replayed++;
243
+ return prev.result as T;
244
+ }
245
+ // 该车道首个失配:其后的记录一律作废(控制流可能已经走了另一条分支)。
246
+ st.diverged = true;
247
+ }
248
+
249
+ // 在 await 之前翻 —— `replaying` 是给同步的 echo() 看的,晚翻会漏判。
250
+ this.liveRan = true;
251
+ const result = await run();
252
+ await this.append({
253
+ apiVersion: 2,
254
+ bundleHash: this.identity.bundleHash,
255
+ rootRunId: this.identity.rootRunId,
256
+ seq: ++this.writeSeq,
257
+ lane,
258
+ idx,
259
+ kind,
260
+ fp,
261
+ result,
262
+ });
263
+ return result;
264
+ }
265
+
266
+ private async append(entry: JournalEntry): Promise<void> {
267
+ try {
268
+ await mkdir(dirname(this.path), { recursive: true });
269
+ await appendFile(this.path, `${JSON.stringify(entry)}\n`, 'utf8');
270
+ } catch {
271
+ // 账本写失败不该让任务本身挂掉 —— 代价只是下次 resume 少续一点。
272
+ }
273
+ }
274
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/jsonSchema.ts —— JSON Schema 子集校验
4
+ * ------------------------------------------------------------
5
+ * 为什么手写而不是引 ajv:
6
+ * ① 工作流的结构化输出契约采用可序列化的 JSON Schema 子集,便于参与 journal
7
+ * 指纹并跨 provider 使用。
8
+ * ② 校验结果要**回喂给模型做修复**,所以错误消息比规范覆盖度重要得多 ——
9
+ * 「`branches[2].score` 应为 number,实际是 string」比一句
10
+ * `must be number` 有用,而通用库的默认文案偏向后者。
11
+ * ③ 项目一贯取向:能用基本类型说清就不引第三方(见 CLAUDE.md 设计原则)。
12
+ *
13
+ * 支持的关键字:type(含数组联合)/ properties / required / items /
14
+ * enum / additionalProperties:false / minItems / maxItems / minimum / maximum /
15
+ * nullable。**不支持**的关键字一律**忽略**(宽松),不报错 —— 校验器的职责是
16
+ * 挡住畸形输出,不是当规范警察;误伤一个合法产出的代价比放过一个边角约束大。
17
+ * ============================================================
18
+ */
19
+ function typeOf(v) {
20
+ if (v === null)
21
+ return 'null';
22
+ if (Array.isArray(v))
23
+ return 'array';
24
+ if (Number.isInteger(v))
25
+ return 'integer';
26
+ return typeof v;
27
+ }
28
+ /** `integer` 也满足 `number`;其余按 typeof 对齐。 */
29
+ function typeMatches(want, v) {
30
+ const actual = typeOf(v);
31
+ if (want === actual)
32
+ return true;
33
+ if (want === 'number')
34
+ return actual === 'integer' || actual === 'number';
35
+ if (want === 'integer')
36
+ return actual === 'integer';
37
+ return false;
38
+ }
39
+ function describe(v) {
40
+ const t = typeOf(v);
41
+ if (t === 'string')
42
+ return `string(${JSON.stringify(String(v)).slice(0, 40)})`;
43
+ if (t === 'array')
44
+ return `array(长度 ${v.length})`;
45
+ if (t === 'object')
46
+ return `object(键 ${Object.keys(v).join('/')})`;
47
+ return `${t}(${String(v)})`;
48
+ }
49
+ function walk(value, schema, path, out) {
50
+ if (!schema || typeof schema !== 'object')
51
+ return;
52
+ if (value === null && schema.nullable === true)
53
+ return;
54
+ if (schema.enum && Array.isArray(schema.enum)) {
55
+ if (!schema.enum.some((e) => e === value)) {
56
+ out.push({
57
+ path,
58
+ message: `应为 [${schema.enum.map((e) => JSON.stringify(e)).join(', ')}] 之一,实际是 ${describe(value)}`,
59
+ });
60
+ return;
61
+ }
62
+ }
63
+ if (schema.type !== undefined) {
64
+ const wants = Array.isArray(schema.type) ? schema.type : [schema.type];
65
+ if (!wants.some((w) => typeMatches(w, value))) {
66
+ out.push({
67
+ path,
68
+ message: `应为 ${wants.join(' 或 ')},实际是 ${describe(value)}`,
69
+ });
70
+ return; // 类型都不对,再查下去只会刷屏
71
+ }
72
+ }
73
+ const t = typeOf(value);
74
+ if (t === 'object') {
75
+ const obj = value;
76
+ for (const key of schema.required ?? []) {
77
+ if (!(key in obj)) {
78
+ out.push({ path: path ? `${path}.${key}` : key, message: '缺少必填字段' });
79
+ }
80
+ }
81
+ if (schema.properties) {
82
+ for (const [key, sub] of Object.entries(schema.properties)) {
83
+ if (key in obj)
84
+ walk(obj[key], sub, path ? `${path}.${key}` : key, out);
85
+ }
86
+ if (schema.additionalProperties === false) {
87
+ for (const key of Object.keys(obj)) {
88
+ if (!(key in schema.properties)) {
89
+ out.push({
90
+ path: path ? `${path}.${key}` : key,
91
+ message: '不允许的额外字段',
92
+ });
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ if (t === 'array') {
99
+ const arr = value;
100
+ if (typeof schema.minItems === 'number' && arr.length < schema.minItems) {
101
+ out.push({ path, message: `至少要 ${schema.minItems} 项,实际 ${arr.length} 项` });
102
+ }
103
+ if (typeof schema.maxItems === 'number' && arr.length > schema.maxItems) {
104
+ out.push({ path, message: `最多 ${schema.maxItems} 项,实际 ${arr.length} 项` });
105
+ }
106
+ if (schema.items) {
107
+ arr.forEach((el, i) => walk(el, schema.items, `${path}[${i}]`, out));
108
+ }
109
+ }
110
+ if (t === 'number' || t === 'integer') {
111
+ const n = value;
112
+ if (typeof schema.minimum === 'number' && n < schema.minimum) {
113
+ out.push({ path, message: `不得小于 ${schema.minimum},实际 ${n}` });
114
+ }
115
+ if (typeof schema.maximum === 'number' && n > schema.maximum) {
116
+ out.push({ path, message: `不得大于 ${schema.maximum},实际 ${n}` });
117
+ }
118
+ }
119
+ }
120
+ /** 校验一个值。返回空数组 = 通过。 */
121
+ export function validateAgainstSchema(value, schema) {
122
+ const out = [];
123
+ walk(value, schema, '', out);
124
+ return out;
125
+ }
126
+ /** 把违规列表渲染成给**模型**看的修复指令(不是给人看的报错)。 */
127
+ export function renderViolations(violations) {
128
+ return violations
129
+ .slice(0, 20)
130
+ .map((v) => ` · ${v.path || '(根)'}:${v.message}`)
131
+ .join('\n');
132
+ }