@stigmer/runner 3.15.0 → 3.15.2-dev.20260913223433

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 (518) hide show
  1. package/README.md +2 -4
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/__test-utils__/execution-record-fixture.d.ts +14 -0
  4. package/dist/__test-utils__/execution-record-fixture.js +4 -0
  5. package/dist/__test-utils__/execution-record-fixture.js.map +1 -1
  6. package/dist/__test-utils__/file-review-projection.d.ts +40 -0
  7. package/dist/__test-utils__/file-review-projection.js +136 -0
  8. package/dist/__test-utils__/file-review-projection.js.map +1 -0
  9. package/dist/__test-utils__/harness-contract/types.d.ts +23 -1
  10. package/dist/__test-utils__/harness-contract/types.js +15 -0
  11. package/dist/__test-utils__/harness-contract/types.js.map +1 -1
  12. package/dist/__test-utils__/hermetic-activity.d.ts +44 -12
  13. package/dist/__test-utils__/hermetic-activity.js +52 -14
  14. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  15. package/dist/__test-utils__/model-registry-fixture.d.ts +32 -7
  16. package/dist/__test-utils__/model-registry-fixture.js +31 -7
  17. package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
  18. package/dist/__test-utils__/turn-input-fixture.d.ts +1 -1
  19. package/dist/__test-utils__/turn-input-fixture.js +1 -1
  20. package/dist/__test-utils__/turn-input-fixture.js.map +1 -1
  21. package/dist/activities/call-agent.js +2 -2
  22. package/dist/activities/call-agent.js.map +1 -1
  23. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +45 -3
  24. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
  25. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +0 -9
  26. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +2 -41
  27. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  28. package/dist/activities/execute-cursor/adapter.d.ts +7 -5
  29. package/dist/activities/execute-cursor/adapter.js +7 -5
  30. package/dist/activities/execute-cursor/adapter.js.map +1 -1
  31. package/dist/activities/execute-cursor/approval-policy.d.ts +5 -2
  32. package/dist/activities/execute-cursor/approval-policy.js +5 -2
  33. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  34. package/dist/activities/execute-cursor/approval-state.d.ts +16 -8
  35. package/dist/activities/execute-cursor/approval-state.js +6 -3
  36. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  37. package/dist/activities/execute-cursor/cas-observations.d.ts +14 -2
  38. package/dist/activities/execute-cursor/cas-observations.js +19 -2
  39. package/dist/activities/execute-cursor/cas-observations.js.map +1 -1
  40. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +8 -4
  41. package/dist/activities/execute-cursor/cursor-capabilities.js +21 -4
  42. package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -1
  43. package/dist/activities/execute-cursor/message-translator.d.ts +12 -20
  44. package/dist/activities/execute-cursor/message-translator.js +19 -32
  45. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  46. package/dist/activities/execute-cursor/prompt-builder.d.ts +48 -58
  47. package/dist/activities/execute-cursor/prompt-builder.js +76 -95
  48. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  49. package/dist/activities/execute-cursor/turn-boundary.d.ts +27 -55
  50. package/dist/activities/execute-cursor/turn-boundary.js +30 -90
  51. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  52. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  53. package/dist/activities/execute-cursor/turn-settle.js +37 -49
  54. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  55. package/dist/activities/execute-cursor/turn-setup.d.ts +16 -24
  56. package/dist/activities/execute-cursor/turn-setup.js +29 -59
  57. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  58. package/dist/activities/execute-cursor/turn-stream.d.ts +3 -8
  59. package/dist/activities/execute-cursor/turn-stream.js +9 -22
  60. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  61. package/dist/activities/execute-cursor/turn.js +5 -1
  62. package/dist/activities/execute-cursor/turn.js.map +1 -1
  63. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +93 -0
  64. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +348 -0
  65. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js.map +1 -0
  66. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +170 -0
  67. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +225 -0
  68. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -0
  69. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.d.ts +24 -0
  70. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +41 -0
  71. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -0
  72. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +54 -0
  73. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +72 -0
  74. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -0
  75. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +187 -23
  76. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +238 -27
  77. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  78. package/dist/activities/execute-deep-agent/adapter.d.ts +41 -0
  79. package/dist/activities/execute-deep-agent/adapter.js +78 -0
  80. package/dist/activities/execute-deep-agent/adapter.js.map +1 -0
  81. package/dist/activities/execute-deep-agent/cas-capture-observer.d.ts +8 -0
  82. package/dist/activities/execute-deep-agent/cas-capture-observer.js +9 -0
  83. package/dist/activities/execute-deep-agent/cas-capture-observer.js.map +1 -1
  84. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +31 -0
  85. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +40 -0
  86. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js.map +1 -0
  87. package/dist/activities/execute-deep-agent/execution-state.d.ts +4 -11
  88. package/dist/activities/execute-deep-agent/execution-state.js +4 -12
  89. package/dist/activities/execute-deep-agent/execution-state.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/hitl.d.ts +49 -47
  91. package/dist/activities/execute-deep-agent/hitl.js +77 -103
  92. package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
  93. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +51 -23
  94. package/dist/activities/execute-deep-agent/prompt-builder.js +115 -76
  95. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  96. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +18 -32
  97. package/dist/activities/execute-deep-agent/status-builder-shared.js +10 -65
  98. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -1
  99. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +10 -8
  100. package/dist/activities/execute-deep-agent/streaming-side-effects.js +12 -14
  101. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  102. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +36 -13
  103. package/dist/activities/execute-deep-agent/subagent-tracker.js +76 -39
  104. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +1 -1
  105. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +25 -28
  106. package/dist/activities/execute-deep-agent/subagent-transformer.js +29 -82
  107. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  108. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -2
  109. package/dist/activities/execute-deep-agent/subagent-wiring.js +2 -2
  110. package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/turn-settle.d.ts +42 -0
  112. package/dist/activities/execute-deep-agent/turn-settle.js +146 -0
  113. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -0
  114. package/dist/activities/execute-deep-agent/turn-setup.d.ts +212 -0
  115. package/dist/activities/execute-deep-agent/turn-setup.js +430 -0
  116. package/dist/activities/execute-deep-agent/turn-setup.js.map +1 -0
  117. package/dist/activities/execute-deep-agent/turn-stream.d.ts +97 -0
  118. package/dist/activities/execute-deep-agent/turn-stream.js +242 -0
  119. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -0
  120. package/dist/activities/execute-deep-agent/turn.d.ts +42 -0
  121. package/dist/activities/execute-deep-agent/turn.js +116 -0
  122. package/dist/activities/execute-deep-agent/turn.js.map +1 -0
  123. package/dist/activities/execute-deep-agent/v3-event-recorder.d.ts +6 -5
  124. package/dist/activities/execute-deep-agent/v3-event-recorder.js +6 -5
  125. package/dist/activities/execute-deep-agent/v3-event-recorder.js.map +1 -1
  126. package/dist/activities/execute-deep-agent/v3-events.d.ts +1 -1
  127. package/dist/activities/execute-deep-agent/v3-events.js +1 -1
  128. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +60 -17
  129. package/dist/activities/execute-deep-agent/v3-status-builder.js +72 -57
  130. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
  131. package/dist/harness/approval-decisions.d.ts +61 -0
  132. package/dist/harness/approval-decisions.js +102 -0
  133. package/dist/harness/approval-decisions.js.map +1 -0
  134. package/dist/harness/capabilities.d.ts +16 -5
  135. package/dist/harness/capabilities.js +9 -0
  136. package/dist/harness/capabilities.js.map +1 -1
  137. package/dist/harness/capture.d.ts +144 -0
  138. package/dist/harness/capture.js +219 -0
  139. package/dist/harness/capture.js.map +1 -0
  140. package/dist/harness/persist-chokepoint.d.ts +19 -4
  141. package/dist/harness/persist-chokepoint.js +17 -4
  142. package/dist/harness/persist-chokepoint.js.map +1 -1
  143. package/dist/harness/run-turn.js +115 -29
  144. package/dist/harness/run-turn.js.map +1 -1
  145. package/dist/harness/terminal-table.d.ts +40 -11
  146. package/dist/harness/terminal-table.js +58 -19
  147. package/dist/harness/terminal-table.js.map +1 -1
  148. package/dist/harness/turn-context.d.ts +141 -76
  149. package/dist/harness/turn-context.js +194 -99
  150. package/dist/harness/turn-context.js.map +1 -1
  151. package/dist/harness/types.d.ts +65 -12
  152. package/dist/harness/types.js +8 -2
  153. package/dist/harness/types.js.map +1 -1
  154. package/dist/harness-adapters.d.ts +12 -8
  155. package/dist/harness-adapters.js +17 -9
  156. package/dist/harness-adapters.js.map +1 -1
  157. package/dist/middleware/approval-gate.d.ts +1 -1
  158. package/dist/middleware/approval-gate.js +1 -1
  159. package/dist/middleware/approval-gate.js.map +1 -1
  160. package/dist/middleware/cost-advisory.d.ts +39 -0
  161. package/dist/middleware/{cost-cap.js → cost-advisory.js} +37 -55
  162. package/dist/middleware/cost-advisory.js.map +1 -0
  163. package/dist/middleware/index.d.ts +23 -12
  164. package/dist/middleware/index.js +26 -18
  165. package/dist/middleware/index.js.map +1 -1
  166. package/dist/middleware/types.d.ts +3 -2
  167. package/dist/runner-manager.js +1 -5
  168. package/dist/runner-manager.js.map +1 -1
  169. package/dist/runner.js +1 -5
  170. package/dist/runner.js.map +1 -1
  171. package/dist/shared/attachment-resolver.d.ts +41 -18
  172. package/dist/shared/attachment-resolver.js +178 -46
  173. package/dist/shared/attachment-resolver.js.map +1 -1
  174. package/dist/shared/attachment-zip.d.ts +85 -0
  175. package/dist/shared/attachment-zip.js +185 -0
  176. package/dist/shared/attachment-zip.js.map +1 -0
  177. package/dist/shared/connect-backfill.js +5 -4
  178. package/dist/shared/connect-backfill.js.map +1 -1
  179. package/dist/shared/cost-guard.d.ts +3 -3
  180. package/dist/shared/cost-guard.js +3 -3
  181. package/dist/shared/execution-status-writer.d.ts +5 -5
  182. package/dist/shared/execution-status-writer.js +5 -5
  183. package/dist/shared/extract-structured-output.d.ts +8 -7
  184. package/dist/shared/extract-structured-output.js +8 -7
  185. package/dist/shared/extract-structured-output.js.map +1 -1
  186. package/dist/shared/filereview/cas-progress.d.ts +1 -18
  187. package/dist/shared/filereview/cas-progress.js +4 -0
  188. package/dist/shared/filereview/cas-progress.js.map +1 -1
  189. package/dist/shared/filereview/cas-touched.d.ts +56 -0
  190. package/dist/shared/filereview/cas-touched.js +63 -0
  191. package/dist/shared/filereview/cas-touched.js.map +1 -0
  192. package/dist/shared/filereview/index.d.ts +2 -1
  193. package/dist/shared/filereview/index.js +2 -1
  194. package/dist/shared/filereview/index.js.map +1 -1
  195. package/dist/shared/mcp-resolver.d.ts +4 -5
  196. package/dist/shared/mcp-resolver.js +4 -5
  197. package/dist/shared/mcp-resolver.js.map +1 -1
  198. package/dist/shared/persist-decision.d.ts +3 -4
  199. package/dist/shared/persist-decision.js +3 -4
  200. package/dist/shared/persist-decision.js.map +1 -1
  201. package/dist/shared/plan-mode-permissions.d.ts +2 -2
  202. package/dist/shared/plan-mode-permissions.js +2 -2
  203. package/dist/shared/plan-mode-prompt.d.ts +1 -1
  204. package/dist/shared/plan-mode-prompt.js +1 -1
  205. package/dist/shared/prompt-sections.d.ts +163 -0
  206. package/dist/shared/prompt-sections.js +164 -0
  207. package/dist/shared/prompt-sections.js.map +1 -0
  208. package/dist/shared/skill-resolver.d.ts +4 -2
  209. package/dist/shared/skill-resolver.js +4 -2
  210. package/dist/shared/skill-resolver.js.map +1 -1
  211. package/dist/shared/tool-rounds.d.ts +32 -0
  212. package/dist/shared/tool-rounds.js +43 -0
  213. package/dist/shared/tool-rounds.js.map +1 -1
  214. package/dist/shared/tool-row.d.ts +34 -0
  215. package/dist/shared/tool-row.js +52 -0
  216. package/dist/shared/tool-row.js.map +1 -1
  217. package/dist/shared/workspace/session-provision.d.ts +3 -3
  218. package/dist/shared/workspace/session-provision.js +3 -3
  219. package/dist/shared/workspace/stigmer-link.d.ts +3 -3
  220. package/dist/shared/workspace/stigmer-link.js +3 -3
  221. package/dist/shared/workspace/writeback-coordinator.d.ts +15 -22
  222. package/dist/shared/workspace/writeback-coordinator.js +16 -53
  223. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  224. package/dist/tools/index.d.ts +1 -1
  225. package/dist/tools/index.js +1 -1
  226. package/package.json +4 -4
  227. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +1 -0
  228. package/src/__test-utils__/execution-record-fixture.ts +18 -2
  229. package/src/__test-utils__/file-review-projection.ts +156 -0
  230. package/src/__test-utils__/git-workspace-fixture.ts +58 -0
  231. package/src/__test-utils__/harness-boot-order-child.ts +7 -2
  232. package/src/__test-utils__/harness-contract/contract.ts +33 -20
  233. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  234. package/src/__test-utils__/harness-contract/runtime-contract.ts +328 -10
  235. package/src/__test-utils__/harness-contract/scripted-adapter.ts +38 -6
  236. package/src/__test-utils__/harness-contract/types.ts +27 -3
  237. package/src/__test-utils__/hermetic-activity.ts +52 -14
  238. package/src/__test-utils__/model-registry-fixture.ts +32 -7
  239. package/src/__test-utils__/module-specifiers.ts +24 -0
  240. package/src/__test-utils__/turn-input-fixture.ts +2 -2
  241. package/src/__tests__/harness-boot-order.test.ts +9 -2
  242. package/src/activities/call-agent.ts +2 -2
  243. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +47 -3
  244. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +2 -48
  245. package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +1 -1
  246. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +6 -1
  247. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +52 -27
  248. package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +25 -0
  249. package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.everything.prompt.md +166 -0
  250. package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.plan-mode.prompt.md +186 -0
  251. package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.recovery.prompt.md +191 -0
  252. package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.reinvocation.prompt.md +13 -0
  253. package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.prefixed.prompt.md +32 -0
  254. package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.raw.prompt.md +1 -0
  255. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -2
  256. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +4 -0
  257. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +24 -4
  258. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +6 -5
  259. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +9 -0
  260. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +11 -8
  261. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +229 -0
  262. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +3 -3
  263. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +2 -2
  264. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +78 -234
  265. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +1 -26
  266. package/src/activities/execute-cursor/adapter.ts +7 -5
  267. package/src/activities/execute-cursor/approval-policy.ts +5 -2
  268. package/src/activities/execute-cursor/approval-state.ts +16 -8
  269. package/src/activities/execute-cursor/cas-observations.ts +20 -2
  270. package/src/activities/execute-cursor/cursor-capabilities.ts +24 -5
  271. package/src/activities/execute-cursor/message-translator.ts +29 -41
  272. package/src/activities/execute-cursor/prompt-builder.ts +99 -157
  273. package/src/activities/execute-cursor/turn-boundary.ts +34 -140
  274. package/src/activities/execute-cursor/turn-settle.ts +37 -51
  275. package/src/activities/execute-cursor/turn-setup.ts +30 -70
  276. package/src/activities/execute-cursor/turn-stream.ts +8 -31
  277. package/src/activities/execute-cursor/turn.ts +5 -1
  278. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +391 -0
  279. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +313 -0
  280. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +48 -0
  281. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +85 -0
  282. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +383 -36
  283. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +76 -0
  284. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +47 -0
  285. package/src/activities/execute-deep-agent/__tests__/adapter.test.ts +80 -0
  286. package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +1 -1
  287. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -2
  288. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -3
  289. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.build-from-plan.prompt.md +172 -0
  290. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.everything.prompt.md +167 -0
  291. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md +36 -0
  292. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.plan-mode.prompt.md +178 -0
  293. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.skills-below-threshold.prompt.md +158 -0
  294. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +210 -0
  295. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +74 -0
  296. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +104 -0
  297. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +78 -0
  298. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +138 -0
  299. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +68 -0
  300. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +154 -0
  301. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +116 -0
  302. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +69 -0
  303. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +67 -0
  304. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/plain-turn.status.json +47 -0
  305. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +68 -0
  306. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +280 -0
  307. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +77 -0
  308. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
  309. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +99 -0
  310. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +109 -0
  311. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +76 -0
  312. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.text-fallback.status.json +51 -0
  313. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tier2.status.json +51 -0
  314. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tool-strategy.status.json +56 -0
  315. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +90 -0
  316. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +70 -0
  317. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +71 -0
  318. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +144 -0
  319. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +184 -0
  320. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +203 -0
  321. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +170 -0
  322. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +175 -0
  323. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +206 -0
  324. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +142 -0
  325. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +126 -0
  326. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +139 -0
  327. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +122 -0
  328. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +236 -0
  329. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +161 -0
  330. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +157 -0
  331. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +152 -0
  332. package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +50 -122
  333. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +8 -6
  334. package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +2 -2
  335. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +35 -35
  336. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +247 -0
  337. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +329 -0
  338. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +1 -20
  339. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +78 -0
  340. package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +1 -1
  341. package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +2 -2
  342. package/src/activities/execute-deep-agent/__tests__/subagent-tracker.test.ts +57 -31
  343. package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +19 -79
  344. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +15 -15
  345. package/src/activities/execute-deep-agent/__tests__/summarization-verification.test.ts +1 -1
  346. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +391 -0
  347. package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +343 -38
  348. package/src/activities/execute-deep-agent/__tests__/vision-input.test.ts +5 -5
  349. package/src/activities/execute-deep-agent/adapter.ts +94 -0
  350. package/src/activities/execute-deep-agent/cas-capture-observer.ts +11 -0
  351. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +43 -0
  352. package/src/activities/execute-deep-agent/execution-state.ts +4 -13
  353. package/src/activities/execute-deep-agent/hitl.ts +100 -123
  354. package/src/activities/execute-deep-agent/prompt-builder.ts +141 -115
  355. package/src/activities/execute-deep-agent/status-builder-shared.ts +21 -84
  356. package/src/activities/execute-deep-agent/streaming-side-effects.ts +13 -19
  357. package/src/activities/execute-deep-agent/subagent-tracker.ts +77 -42
  358. package/src/activities/execute-deep-agent/subagent-transformer.ts +46 -105
  359. package/src/activities/execute-deep-agent/subagent-wiring.ts +5 -4
  360. package/src/activities/execute-deep-agent/turn-settle.ts +164 -0
  361. package/src/activities/execute-deep-agent/turn-setup.ts +541 -0
  362. package/src/activities/execute-deep-agent/turn-stream.ts +313 -0
  363. package/src/activities/execute-deep-agent/turn.ts +131 -0
  364. package/src/activities/execute-deep-agent/v3-event-recorder.ts +6 -5
  365. package/src/activities/execute-deep-agent/v3-events.ts +1 -1
  366. package/src/activities/execute-deep-agent/v3-status-builder.ts +84 -63
  367. package/src/harness/__tests__/approval-decisions.test.ts +116 -0
  368. package/src/harness/__tests__/capture.test.ts +268 -0
  369. package/src/harness/__tests__/mount-skills.test.ts +169 -0
  370. package/src/harness/__tests__/persist-chokepoint.test.ts +38 -2
  371. package/src/harness/__tests__/run-turn-deterministic.test.ts +94 -0
  372. package/src/harness/__tests__/run-turn.test.ts +39 -23
  373. package/src/harness/__tests__/turn-attachments-vision.test.ts +80 -0
  374. package/src/harness/__tests__/turn-context.test.ts +73 -26
  375. package/src/harness/approval-decisions.ts +104 -0
  376. package/src/harness/capabilities.ts +16 -5
  377. package/src/harness/capture.ts +301 -0
  378. package/src/harness/persist-chokepoint.ts +24 -4
  379. package/src/harness/run-turn.ts +120 -29
  380. package/src/harness/terminal-table.ts +61 -20
  381. package/src/harness/turn-context.ts +208 -111
  382. package/src/harness/types.ts +66 -12
  383. package/src/harness-adapters.ts +17 -9
  384. package/src/middleware/__tests__/approval-gate.test.ts +1 -1
  385. package/src/middleware/__tests__/cost-advisory.test.ts +113 -0
  386. package/src/middleware/approval-gate.ts +2 -2
  387. package/src/middleware/{cost-cap.ts → cost-advisory.ts} +40 -70
  388. package/src/middleware/index.ts +29 -29
  389. package/src/middleware/types.ts +3 -2
  390. package/src/runner-manager.ts +0 -8
  391. package/src/runner.ts +0 -8
  392. package/src/shared/__tests__/attachment-naming.test.ts +6 -19
  393. package/src/shared/__tests__/attachment-resolver.test.ts +158 -8
  394. package/src/shared/__tests__/attachment-zip.test.ts +236 -0
  395. package/src/shared/__tests__/bedrock-adapter.test.ts +1 -1
  396. package/src/shared/__tests__/blueprint-resolver.test.ts +43 -0
  397. package/src/shared/__tests__/cost-guard.test.ts +3 -3
  398. package/src/shared/__tests__/prompt-sections.test.ts +167 -0
  399. package/src/shared/__tests__/secret-leak-scan.test.ts +2 -2
  400. package/src/{activities/execute-deep-agent → shared}/__tests__/stamp-flowed-rows.test.ts +33 -10
  401. package/src/shared/__tests__/vertex-adapter.test.ts +1 -1
  402. package/src/shared/attachment-resolver.ts +218 -55
  403. package/src/shared/attachment-zip.ts +281 -0
  404. package/src/shared/connect-backfill.ts +9 -11
  405. package/src/shared/cost-guard.ts +3 -3
  406. package/src/shared/execution-status-writer.ts +5 -5
  407. package/src/shared/extract-structured-output.ts +8 -7
  408. package/src/shared/filereview/__tests__/capture.test.ts +86 -4
  409. package/src/shared/filereview/__tests__/cas-progress.test.ts +2 -1
  410. package/src/shared/filereview/cas-progress.ts +5 -19
  411. package/src/shared/filereview/cas-touched.ts +89 -0
  412. package/src/shared/filereview/index.ts +4 -2
  413. package/src/shared/mcp-resolver.ts +4 -5
  414. package/src/shared/persist-decision.ts +3 -4
  415. package/src/shared/plan-mode-permissions.ts +2 -2
  416. package/src/shared/plan-mode-prompt.ts +1 -1
  417. package/src/shared/prompt-sections.ts +256 -0
  418. package/src/shared/skill-resolver.ts +4 -2
  419. package/src/shared/tool-rounds.ts +48 -0
  420. package/src/shared/tool-row.ts +61 -0
  421. package/src/shared/workspace/__tests__/stigmer-link.test.ts +7 -22
  422. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +20 -61
  423. package/src/shared/workspace/session-provision.ts +3 -3
  424. package/src/shared/workspace/stigmer-link.ts +3 -3
  425. package/src/shared/workspace/writeback-coordinator.ts +16 -64
  426. package/src/tools/index.ts +1 -1
  427. package/dist/activities/execute-cursor/capture-flow.d.ts +0 -142
  428. package/dist/activities/execute-cursor/capture-flow.js +0 -285
  429. package/dist/activities/execute-cursor/capture-flow.js.map +0 -1
  430. package/dist/activities/execute-cursor/command-provenance.d.ts +0 -48
  431. package/dist/activities/execute-cursor/command-provenance.js +0 -38
  432. package/dist/activities/execute-cursor/command-provenance.js.map +0 -1
  433. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +0 -134
  434. package/dist/activities/execute-deep-agent/attachment-injector.js +0 -386
  435. package/dist/activities/execute-deep-agent/attachment-injector.js.map +0 -1
  436. package/dist/activities/execute-deep-agent/command-provenance.d.ts +0 -61
  437. package/dist/activities/execute-deep-agent/command-provenance.js +0 -72
  438. package/dist/activities/execute-deep-agent/command-provenance.js.map +0 -1
  439. package/dist/activities/execute-deep-agent/environment.d.ts +0 -24
  440. package/dist/activities/execute-deep-agent/environment.js +0 -58
  441. package/dist/activities/execute-deep-agent/environment.js.map +0 -1
  442. package/dist/activities/execute-deep-agent/event-recorder.d.ts +0 -21
  443. package/dist/activities/execute-deep-agent/event-recorder.js +0 -67
  444. package/dist/activities/execute-deep-agent/event-recorder.js.map +0 -1
  445. package/dist/activities/execute-deep-agent/index.d.ts +0 -15
  446. package/dist/activities/execute-deep-agent/index.js +0 -918
  447. package/dist/activities/execute-deep-agent/index.js.map +0 -1
  448. package/dist/activities/execute-deep-agent/mcp-gate.d.ts +0 -28
  449. package/dist/activities/execute-deep-agent/mcp-gate.js +0 -22
  450. package/dist/activities/execute-deep-agent/mcp-gate.js.map +0 -1
  451. package/dist/activities/execute-deep-agent/post-stream.d.ts +0 -23
  452. package/dist/activities/execute-deep-agent/post-stream.js +0 -71
  453. package/dist/activities/execute-deep-agent/post-stream.js.map +0 -1
  454. package/dist/activities/execute-deep-agent/setup.d.ts +0 -136
  455. package/dist/activities/execute-deep-agent/setup.js +0 -767
  456. package/dist/activities/execute-deep-agent/setup.js.map +0 -1
  457. package/dist/activities/execute-deep-agent/stamp-flowed-rows.d.ts +0 -36
  458. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js +0 -56
  459. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js.map +0 -1
  460. package/dist/activities/execute-deep-agent/status-builder.d.ts +0 -93
  461. package/dist/activities/execute-deep-agent/status-builder.js +0 -365
  462. package/dist/activities/execute-deep-agent/status-builder.js.map +0 -1
  463. package/dist/activities/execute-deep-agent/streaming-terminal.d.ts +0 -21
  464. package/dist/activities/execute-deep-agent/streaming-terminal.js +0 -80
  465. package/dist/activities/execute-deep-agent/streaming-terminal.js.map +0 -1
  466. package/dist/activities/execute-deep-agent/streaming-v3.d.ts +0 -13
  467. package/dist/activities/execute-deep-agent/streaming-v3.js +0 -174
  468. package/dist/activities/execute-deep-agent/streaming-v3.js.map +0 -1
  469. package/dist/activities/execute-deep-agent/streaming.d.ts +0 -81
  470. package/dist/activities/execute-deep-agent/streaming.js +0 -160
  471. package/dist/activities/execute-deep-agent/streaming.js.map +0 -1
  472. package/dist/middleware/cost-cap.d.ts +0 -22
  473. package/dist/middleware/cost-cap.js.map +0 -1
  474. package/dist/middleware/graceful-stop.d.ts +0 -17
  475. package/dist/middleware/graceful-stop.js +0 -63
  476. package/dist/middleware/graceful-stop.js.map +0 -1
  477. package/dist/shared/skill-writer.d.ts +0 -75
  478. package/dist/shared/skill-writer.js +0 -207
  479. package/dist/shared/skill-writer.js.map +0 -1
  480. package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +0 -1032
  481. package/src/activities/execute-cursor/__tests__/command-provenance.test.ts +0 -240
  482. package/src/activities/execute-cursor/__tests__/progress-substrate.test.ts +0 -169
  483. package/src/activities/execute-cursor/capture-flow.ts +0 -379
  484. package/src/activities/execute-cursor/command-provenance.ts +0 -73
  485. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +0 -1161
  486. package/src/activities/execute-deep-agent/__tests__/command-provenance.test.ts +0 -252
  487. package/src/activities/execute-deep-agent/__tests__/environment.test.ts +0 -108
  488. package/src/activities/execute-deep-agent/__tests__/event-recorder.test.ts +0 -150
  489. package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +0 -226
  490. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +0 -318
  491. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +0 -351
  492. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +0 -293
  493. package/src/activities/execute-deep-agent/__tests__/index.test.ts +0 -99
  494. package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +0 -44
  495. package/src/activities/execute-deep-agent/__tests__/post-stream.test.ts +0 -112
  496. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +0 -358
  497. package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +0 -1933
  498. package/src/activities/execute-deep-agent/__tests__/streaming-terminal.test.ts +0 -40
  499. package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +0 -597
  500. package/src/activities/execute-deep-agent/__tests__/streaming.test.ts +0 -508
  501. package/src/activities/execute-deep-agent/attachment-injector.ts +0 -627
  502. package/src/activities/execute-deep-agent/command-provenance.ts +0 -102
  503. package/src/activities/execute-deep-agent/environment.ts +0 -76
  504. package/src/activities/execute-deep-agent/event-recorder.ts +0 -95
  505. package/src/activities/execute-deep-agent/index.ts +0 -1072
  506. package/src/activities/execute-deep-agent/mcp-gate.ts +0 -37
  507. package/src/activities/execute-deep-agent/post-stream.ts +0 -109
  508. package/src/activities/execute-deep-agent/setup.ts +0 -1081
  509. package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +0 -64
  510. package/src/activities/execute-deep-agent/status-builder.ts +0 -481
  511. package/src/activities/execute-deep-agent/streaming-terminal.ts +0 -106
  512. package/src/activities/execute-deep-agent/streaming-v3.ts +0 -277
  513. package/src/activities/execute-deep-agent/streaming.ts +0 -313
  514. package/src/middleware/__tests__/cost-cap.test.ts +0 -192
  515. package/src/middleware/__tests__/graceful-stop.test.ts +0 -105
  516. package/src/middleware/graceful-stop.ts +0 -86
  517. package/src/shared/__tests__/skill-writer.test.ts +0 -372
  518. package/src/shared/skill-writer.ts +0 -266
@@ -1,372 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
- import { mkdtempSync, readFileSync, existsSync, rmSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { tmpdir } from "node:os";
5
- import { ConnectError, Code } from "@connectrpc/connect";
6
- import {
7
- mergeSkillRefs,
8
- fetchSkillsByRefs,
9
- mountSkills,
10
- generatePromptSection,
11
- generateAlsoAvailableSection,
12
- } from "../skill-writer.js";
13
- import type { Skill } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
14
- import type { ApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
15
- import { buildZip } from "@stigmer/zip-structure/testing";
16
-
17
- // ─── Helpers ─────────────────────────────────────────────────────────────
18
-
19
- function makeSkill(overrides: {
20
- id?: string;
21
- name?: string;
22
- slug?: string;
23
- org?: string;
24
- description?: string;
25
- skillMd?: string;
26
- artifactStorageKey?: string;
27
- versionHash?: string;
28
- } = {}): Skill {
29
- return {
30
- metadata: {
31
- id: overrides.id ?? "skill-id-1",
32
- name: overrides.name ?? overrides.slug ?? "test-skill",
33
- slug: overrides.slug ?? "test-skill",
34
- org: overrides.org ?? "test-org",
35
- },
36
- spec: {
37
- name: overrides.name ?? "test-skill",
38
- description: overrides.description ?? "A test skill",
39
- skillMd: overrides.skillMd ?? "# Test Skill\n\nDoes testing.",
40
- tag: "",
41
- },
42
- status: {
43
- artifactStorageKey: overrides.artifactStorageKey ?? "",
44
- versionHash: overrides.versionHash ?? "abc123",
45
- state: "active",
46
- },
47
- } as any;
48
- }
49
-
50
- function makeRef(slug: string, org = "test-org"): ApiResourceReference {
51
- return { slug, org, kind: 43 } as any;
52
- }
53
-
54
- /** A server that predates the transfer lane (#675) answers the mint RPC
55
- * with UNIMPLEMENTED, pinning these tests to the unary fallback. */
56
- function makeMockClient(overrides: Record<string, unknown> = {}) {
57
- return {
58
- getSkillByReference: vi.fn().mockImplementation((ref: any) =>
59
- Promise.resolve(makeSkill({ slug: ref.slug, name: ref.slug })),
60
- ),
61
- getSkillArtifact: vi.fn().mockResolvedValue({ artifact: new Uint8Array(0) }),
62
- getSkillArtifactDownloadUrl: vi.fn().mockRejectedValue(
63
- new ConnectError("unimplemented", Code.Unimplemented),
64
- ),
65
- ...overrides,
66
- } as any;
67
- }
68
-
69
- // ─── mergeSkillRefs ──────────────────────────────────────────────────────
70
-
71
- describe("mergeSkillRefs", () => {
72
- it("returns empty for no refs", () => {
73
- expect(mergeSkillRefs([], [])).toEqual([]);
74
- });
75
-
76
- it("returns agent refs when no session refs", () => {
77
- const refs = [makeRef("skill-a"), makeRef("skill-b")];
78
- const result = mergeSkillRefs(refs, []);
79
- expect(result).toHaveLength(2);
80
- expect(result.map(r => r.slug)).toEqual(["skill-a", "skill-b"]);
81
- });
82
-
83
- it("deduplicates by slug with session winning", () => {
84
- const agentRefs = [makeRef("skill-a", "org1")];
85
- const sessionRefs = [makeRef("skill-a", "org2")];
86
- const result = mergeSkillRefs(agentRefs, sessionRefs);
87
- expect(result).toHaveLength(1);
88
- expect(result[0].org).toBe("org2");
89
- });
90
-
91
- it("unions unique skills from both sources", () => {
92
- const agentRefs = [makeRef("skill-a")];
93
- const sessionRefs = [makeRef("skill-b")];
94
- const result = mergeSkillRefs(agentRefs, sessionRefs);
95
- expect(result).toHaveLength(2);
96
- });
97
- });
98
-
99
- // ─── fetchSkillsByRefs ───────────────────────────────────────────────────
100
-
101
- describe("fetchSkillsByRefs", () => {
102
- it("returns empty for no refs", async () => {
103
- const client = makeMockClient();
104
- const result = await fetchSkillsByRefs(client, []);
105
- expect(result).toEqual([]);
106
- expect(client.getSkillByReference).not.toHaveBeenCalled();
107
- });
108
-
109
- it("fetches all skills by reference", async () => {
110
- const client = makeMockClient();
111
- const refs = [makeRef("skill-a"), makeRef("skill-b")];
112
- const result = await fetchSkillsByRefs(client, refs);
113
- expect(result).toHaveLength(2);
114
- expect(client.getSkillByReference).toHaveBeenCalledTimes(2);
115
- });
116
-
117
- it("skips failed fetches gracefully", async () => {
118
- const client = makeMockClient({
119
- getSkillByReference: vi.fn()
120
- .mockResolvedValueOnce(makeSkill({ name: "good", slug: "good" }))
121
- .mockRejectedValueOnce(new Error("Not found")),
122
- });
123
- const refs = [makeRef("good"), makeRef("bad")];
124
- const result = await fetchSkillsByRefs(client, refs);
125
- expect(result).toHaveLength(1);
126
- expect(result[0].spec!.name).toBe("good");
127
- });
128
- });
129
-
130
- // ─── mountSkills ─────────────────────────────────────────────────────────
131
-
132
- describe("mountSkills", () => {
133
- let platformDir: string;
134
-
135
- beforeEach(() => {
136
- platformDir = mkdtempSync(join(tmpdir(), "skill-writer-platform-"));
137
- });
138
-
139
- afterEach(() => {
140
- rmSync(platformDir, { recursive: true, force: true });
141
- });
142
-
143
- it("writes SKILL.md and returns agent-visible paths keyed by skill id", async () => {
144
- const client = makeMockClient();
145
- const skills = [makeSkill({ name: "calculator", skillMd: "# Calculator\n\nAdds numbers." })];
146
- const result = await mountSkills(client, skills, platformDir);
147
-
148
- expect(result.paths.get("skill-id-1")).toBe(".stigmer/skills/calculator");
149
- expect(readFileSync(join(platformDir, "skills", "calculator", "SKILL.md"), "utf-8"))
150
- .toBe("# Calculator\n\nAdds numbers.");
151
- });
152
-
153
- it("extracts artifact files alongside SKILL.md", async () => {
154
- const artifact = buildZip([
155
- { name: "SKILL.md", content: "# Stale zip copy" },
156
- { name: "references/schema.md", content: "schema" },
157
- ]);
158
- const client = makeMockClient({
159
- getSkillArtifact: vi.fn().mockResolvedValue({ artifact }),
160
- });
161
- const skills = [makeSkill({
162
- name: "db-skill",
163
- skillMd: "# Authoritative",
164
- artifactStorageKey: "artifacts/db.zip",
165
- })];
166
- await mountSkills(client, skills, platformDir);
167
-
168
- const skillDir = join(platformDir, "skills", "db-skill");
169
- expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toBe("# Authoritative");
170
- expect(readFileSync(join(skillDir, "references", "schema.md"), "utf-8")).toBe("schema");
171
- });
172
-
173
- it("handles multiple skills", async () => {
174
- const client = makeMockClient();
175
- const skills = [
176
- makeSkill({ id: "id-1", name: "skill-a", skillMd: "# A" }),
177
- makeSkill({ id: "id-2", name: "skill-b", skillMd: "# B" }),
178
- ];
179
- const result = await mountSkills(client, skills, platformDir);
180
- expect(result.paths.size).toBe(2);
181
- expect(result.paths.get("id-1")).toBe(".stigmer/skills/skill-a");
182
- expect(result.paths.get("id-2")).toBe(".stigmer/skills/skill-b");
183
- expect(existsSync(join(platformDir, "skills", "skill-a", "SKILL.md"))).toBe(true);
184
- expect(existsSync(join(platformDir, "skills", "skill-b", "SKILL.md"))).toBe(true);
185
- });
186
-
187
- it("skips the artifact download when the mounted hash matches (cache hit)", async () => {
188
- const artifact = buildZip([{ name: "references/guide.md", content: "guide" }]);
189
- const client = makeMockClient({
190
- getSkillArtifact: vi.fn().mockResolvedValue({ artifact }),
191
- });
192
- const skill = makeSkill({
193
- name: "cached-skill",
194
- artifactStorageKey: "artifacts/cached.zip",
195
- versionHash: "hash-v1",
196
- });
197
-
198
- await mountSkills(client, [skill], platformDir);
199
- expect(client.getSkillArtifact).toHaveBeenCalledTimes(1);
200
-
201
- // Second execution of the same session: same hash, no transfer.
202
- const second = await mountSkills(client, [skill], platformDir);
203
- expect(client.getSkillArtifact).toHaveBeenCalledTimes(1);
204
- expect(second.paths.get("skill-id-1")).toBe(".stigmer/skills/cached-skill");
205
- expect(readFileSync(
206
- join(platformDir, "skills", "cached-skill", "references", "guide.md"), "utf-8",
207
- )).toBe("guide");
208
- });
209
-
210
- it("remounts on version change and clears stale files from the old mount", async () => {
211
- const artifactV1 = buildZip([{ name: "references/removed-in-v2.md", content: "old" }]);
212
- const artifactV2 = buildZip([{ name: "references/new-in-v2.md", content: "new" }]);
213
- const client = makeMockClient({
214
- getSkillArtifact: vi.fn()
215
- .mockResolvedValueOnce({ artifact: artifactV1 })
216
- .mockResolvedValueOnce({ artifact: artifactV2 }),
217
- });
218
-
219
- await mountSkills(client, [makeSkill({
220
- name: "evolving-skill",
221
- skillMd: "# V1",
222
- artifactStorageKey: "artifacts/v1.zip",
223
- versionHash: "hash-v1",
224
- })], platformDir);
225
-
226
- await mountSkills(client, [makeSkill({
227
- name: "evolving-skill",
228
- skillMd: "# V2",
229
- artifactStorageKey: "artifacts/v2.zip",
230
- versionHash: "hash-v2",
231
- })], platformDir);
232
-
233
- const skillDir = join(platformDir, "skills", "evolving-skill");
234
- expect(client.getSkillArtifact).toHaveBeenCalledTimes(2);
235
- expect(readFileSync(join(skillDir, "SKILL.md"), "utf-8")).toBe("# V2");
236
- expect(readFileSync(join(skillDir, "references", "new-in-v2.md"), "utf-8")).toBe("new");
237
- // The v1-only file must not linger in the v2 mount (the stale-file leak).
238
- expect(existsSync(join(skillDir, "references", "removed-in-v2.md"))).toBe(false);
239
- });
240
-
241
- it("does not cache a degraded SKILL.md-only mount — the next execution retries", async () => {
242
- const artifact = buildZip([{ name: "references/late.md", content: "finally" }]);
243
- const client = makeMockClient({
244
- getSkillArtifact: vi.fn()
245
- .mockRejectedValueOnce(new Error("Network timeout"))
246
- .mockResolvedValueOnce({ artifact }),
247
- });
248
- const skill = makeSkill({
249
- name: "retry-skill",
250
- artifactStorageKey: "artifacts/retry.zip",
251
- versionHash: "hash-v1",
252
- });
253
-
254
- // First pass degrades to SKILL.md only — never throws.
255
- const first = await mountSkills(client, [skill], platformDir);
256
- const skillDir = join(platformDir, "skills", "retry-skill");
257
- expect(first.paths.get("skill-id-1")).toBe(".stigmer/skills/retry-skill");
258
- expect(existsSync(join(skillDir, "SKILL.md"))).toBe(true);
259
- expect(existsSync(join(skillDir, "references"))).toBe(false);
260
-
261
- // Second pass retries and completes the mount.
262
- await mountSkills(client, [skill], platformDir);
263
- expect(client.getSkillArtifact).toHaveBeenCalledTimes(2);
264
- expect(readFileSync(join(skillDir, "references", "late.md"), "utf-8")).toBe("finally");
265
-
266
- // Third pass is a cache hit.
267
- await mountSkills(client, [skill], platformDir);
268
- expect(client.getSkillArtifact).toHaveBeenCalledTimes(2);
269
- });
270
-
271
- it("mounts only the first claimant when two skills resolve to the same directory", async () => {
272
- const client = makeMockClient();
273
- const skills = [
274
- makeSkill({ id: "id-1", org: "org-a", slug: "shared-a", name: "shared-name", skillMd: "# First" }),
275
- makeSkill({ id: "id-2", org: "org-b", slug: "shared-b", name: "shared-name", skillMd: "# Second" }),
276
- ];
277
- const result = await mountSkills(client, skills, platformDir);
278
-
279
- // Both ids resolve to the (single) directory; the first claimant's content wins.
280
- expect(result.paths.get("id-1")).toBe(".stigmer/skills/shared-name");
281
- expect(result.paths.get("id-2")).toBe(".stigmer/skills/shared-name");
282
- expect(readFileSync(join(platformDir, "skills", "shared-name", "SKILL.md"), "utf-8"))
283
- .toBe("# First");
284
- });
285
-
286
- it("skips skills with no skillMd content", async () => {
287
- const client = makeMockClient();
288
- const skill = makeSkill({ name: "broken", skillMd: "" });
289
- (skill as any).spec.skillMd = "";
290
- const result = await mountSkills(client, [skill], platformDir);
291
-
292
- // The path entry exists (naming is total) but nothing was mounted.
293
- expect(result.paths.get("skill-id-1")).toBe(".stigmer/skills/broken");
294
- expect(existsSync(join(platformDir, "skills", "broken"))).toBe(false);
295
- });
296
- });
297
-
298
- // ─── generatePromptSection ───────────────────────────────────────────────
299
-
300
- describe("generatePromptSection", () => {
301
- it("returns empty string for no skills", () => {
302
- expect(generatePromptSection([], new Map())).toBe("");
303
- });
304
-
305
- it("generates progressive disclosure format", () => {
306
- const skills = [makeSkill({ name: "calculator", description: "Arithmetic operations" })];
307
- const paths = new Map([["skill-id-1", ".stigmer/skills/calculator"]]);
308
- const section = generatePromptSection(skills, paths);
309
-
310
- expect(section).toContain("## Skills");
311
- expect(section).toContain("### calculator");
312
- expect(section).toContain("**Description**: Arithmetic operations");
313
- expect(section).toContain("**Location**: `.stigmer/skills/calculator/`");
314
- expect(section).toContain("**Activate**: `read .stigmer/skills/calculator/SKILL.md`");
315
- });
316
-
317
- it("includes activation protocol instructions", () => {
318
- const skills = [makeSkill()];
319
- const paths = new Map([["skill-id-1", ".stigmer/skills/test-skill"]]);
320
- const section = generatePromptSection(skills, paths);
321
-
322
- expect(section).toContain("Activation protocol");
323
- expect(section).toContain("read its SKILL.md");
324
- });
325
-
326
- it("handles multiple skills", () => {
327
- const skills = [
328
- makeSkill({ id: "id-1", name: "skill-a", description: "Desc A" }),
329
- makeSkill({ id: "id-2", name: "skill-b", description: "Desc B" }),
330
- ];
331
- const paths = new Map([
332
- ["id-1", ".stigmer/skills/skill-a"],
333
- ["id-2", ".stigmer/skills/skill-b"],
334
- ]);
335
- const section = generatePromptSection(skills, paths);
336
-
337
- expect(section).toContain("### skill-a");
338
- expect(section).toContain("### skill-b");
339
- expect(section).toContain("Desc A");
340
- expect(section).toContain("Desc B");
341
- });
342
-
343
- it("falls back to (no description) when empty", () => {
344
- const skills = [makeSkill({ description: "" })];
345
- (skills[0] as any).spec.description = "";
346
- const paths = new Map([["skill-id-1", ".stigmer/skills/test-skill"]]);
347
- const section = generatePromptSection(skills, paths);
348
- expect(section).toContain("(no description)");
349
- });
350
- });
351
-
352
- // ─── generateAlsoAvailableSection ────────────────────────────────────────
353
-
354
- describe("generateAlsoAvailableSection", () => {
355
- it("returns empty for no excluded names", () => {
356
- expect(generateAlsoAvailableSection([])).toBe("");
357
- });
358
-
359
- it("lists excluded skills with backtick formatting", () => {
360
- const section = generateAlsoAvailableSection(["alpha", "beta", "gamma"]);
361
- expect(section).toContain("### Also Available");
362
- expect(section).toContain("`alpha`");
363
- expect(section).toContain("`beta`");
364
- expect(section).toContain("`gamma`");
365
- });
366
-
367
- it("includes activation instructions", () => {
368
- const section = generateAlsoAvailableSection(["some-skill"]);
369
- expect(section).toContain(".stigmer/skills/<name>/SKILL.md");
370
- expect(section).toContain("relevant to your task");
371
- });
372
- });
@@ -1,266 +0,0 @@
1
- /**
2
- * Skill mounting and prompt generation for the deep-agent execution path.
3
- *
4
- * Follows the Agent Skills specification progressive disclosure model:
5
- *
6
- * 1. Metadata (startup) — skill name + description injected into
7
- * the system prompt so the agent knows which skills are available.
8
- * 2. Instructions (activation) — the agent reads SKILL.md from the
9
- * filesystem when it decides to activate a skill.
10
- * 3. Resources (on demand) — scripts, references, and assets are
11
- * loaded by the agent only when required.
12
- *
13
- * Skills physically live in the session's platform directory
14
- * (`{platformDir}/skills/{name}/` — the SAME location the Cursor harness
15
- * mounts into), and the agent sees them as `.stigmer/skills/{name}/`
16
- * through the per-turn workspace symlink (see workspace/stigmer-link.ts).
17
- * Returned paths are the agent-visible `.stigmer/…` form.
18
- *
19
- * Mounts are cached by the skill's content-addressed version hash via the
20
- * shared skill-mount mechanics (issue #337, mirroring the Cursor harness's
21
- * #672 fix): metadata is fetched every execution — a pushed skill update
22
- * still lands on the very next message — but an unchanged skill skips the
23
- * artifact download and rewrite entirely.
24
- */
25
-
26
- import { join } from "node:path";
27
- import type { Skill } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
28
- import type { ApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
29
- import type { StigmerClient } from "../client/stigmer-client.js";
30
- import {
31
- SKILLS_SUBDIR,
32
- mountIsFresh,
33
- downloadArtifact,
34
- writeSkillMount,
35
- } from "./skill-mount.js";
36
- import { STIGMER_LOCAL_STATE_DIR } from "./workspace/stigmer-link.js";
37
-
38
- /** Agent-visible base of the skills tree (via the workspace `.stigmer` symlink). */
39
- const SKILLS_RELATIVE_BASE = `${STIGMER_LOCAL_STATE_DIR}/${SKILLS_SUBDIR}`;
40
-
41
- // ─── Types ───────────────────────────────────────────────────────────────
42
-
43
- export interface SkillPathMap {
44
- /** Map from skill metadata ID to workspace-relative directory path. */
45
- readonly paths: ReadonlyMap<string, string>;
46
- }
47
-
48
- // ─── Fetch ───────────────────────────────────────────────────────────────
49
-
50
- /**
51
- * Merge skill refs from agent and session specs (union, dedup by slug,
52
- * session wins on collision).
53
- */
54
- export function mergeSkillRefs(
55
- agentRefs: readonly ApiResourceReference[],
56
- sessionRefs: readonly ApiResourceReference[],
57
- ): ApiResourceReference[] {
58
- const bySlug = new Map<string, ApiResourceReference>();
59
- for (const ref of agentRefs) {
60
- if (ref.slug) bySlug.set(ref.slug, ref);
61
- }
62
- for (const ref of sessionRefs) {
63
- if (ref.slug) bySlug.set(ref.slug, ref);
64
- }
65
- return [...bySlug.values()];
66
- }
67
-
68
- /**
69
- * Fetch all skills by their ApiResourceReference. Failures for individual
70
- * skills are logged and skipped (non-fatal).
71
- */
72
- export async function fetchSkillsByRefs(
73
- client: StigmerClient,
74
- refs: readonly ApiResourceReference[],
75
- ): Promise<Skill[]> {
76
- if (refs.length === 0) return [];
77
-
78
- const results: Skill[] = [];
79
- const fetches = refs.map(async (ref) => {
80
- try {
81
- return await client.getSkillByReference(ref);
82
- } catch (err) {
83
- console.warn(
84
- `[skill-writer] Failed to fetch skill ${ref.org}/${ref.slug}: ` +
85
- `${err instanceof Error ? err.message : String(err)}`,
86
- );
87
- return null;
88
- }
89
- });
90
-
91
- const settled = await Promise.all(fetches);
92
- for (const skill of settled) {
93
- if (skill) results.push(skill);
94
- }
95
- return results;
96
- }
97
-
98
- // ─── Mount ───────────────────────────────────────────────────────────────
99
-
100
- /**
101
- * Mount skills into the session's platform directory, downloading each
102
- * skill's artifact only on a version-hash cache miss (see skill-mount.ts
103
- * for the marker mechanics). Returns a map of skill-id -> agent-visible
104
- * directory path.
105
- *
106
- * The returned map is a NAMING function, not a success record: every skill
107
- * gets its path entry so prompt generation stays total, while mount
108
- * failures degrade that one skill (loud log, no throw) — one broken skill
109
- * must never kill the run.
110
- *
111
- * Skills mount in parallel (each owns an independent directory), EXCEPT
112
- * when two skills resolve to the same directory name (same `spec.name`
113
- * from different orgs): concurrent remove-and-rewrite passes on one
114
- * directory would corrupt the mount, so only the first claimant mounts and
115
- * the collision is logged loudly. (The sequential code this replaced
116
- * silently let the last writer win — no better, just quieter.)
117
- */
118
- export async function mountSkills(
119
- client: StigmerClient,
120
- skills: readonly Skill[],
121
- platformDir: string,
122
- ): Promise<SkillPathMap> {
123
- const paths = new Map<string, string>();
124
- const claims = new Map<string, Skill>();
125
-
126
- for (const skill of skills) {
127
- const name = skill.spec?.name || skill.metadata?.slug || "unknown";
128
- const skillId = skill.metadata?.id ?? name;
129
- paths.set(skillId, `${SKILLS_RELATIVE_BASE}/${name}`);
130
-
131
- // Impossible through the push pipeline (push.go hard-fails a ZIP
132
- // without an extractable SKILL.md and always populates spec.skill_md),
133
- // so an empty skillMd means a broken resource — skip, same as Cursor.
134
- if (!skill.spec?.skillMd) {
135
- console.warn(
136
- `[skill-writer] skill ${name} (${skillId}) has no skillMd content — skipping mount`,
137
- );
138
- continue;
139
- }
140
-
141
- const prev = claims.get(name);
142
- if (prev) {
143
- console.warn(
144
- `[skill-writer] mount directory collision on '${name}': ` +
145
- `${prev.metadata?.org}/${prev.metadata?.slug} already claims it, ` +
146
- `skipping ${skill.metadata?.org}/${skill.metadata?.slug}`,
147
- );
148
- continue;
149
- }
150
- claims.set(name, skill);
151
- }
152
-
153
- await Promise.all([...claims.entries()].map(async ([name, skill]) => {
154
- const skillDir = join(platformDir, SKILLS_SUBDIR, name);
155
- try {
156
- const versionHash = skill.status?.versionHash ?? "";
157
- const wantsArtifact = Boolean(skill.status?.artifactStorageKey);
158
-
159
- if (versionHash !== "" && (await mountIsFresh(skillDir, versionHash, wantsArtifact))) {
160
- console.log(
161
- `[skill-writer] mount cache hit: ${name} (version ${versionHash.slice(0, 12)}) — skipping artifact transfer`,
162
- );
163
- return;
164
- }
165
-
166
- let artifactBytes: Uint8Array | undefined;
167
- if (wantsArtifact) {
168
- try {
169
- artifactBytes = await downloadArtifact(client, skill.status!.artifactStorageKey);
170
- } catch (err) {
171
- // Deliberate degradation, but LOUD (#675): the run still gets
172
- // SKILL.md, and the marker records artifactMounted=false so the
173
- // next execution retries the download.
174
- console.error(
175
- `[skill-writer] artifact download FAILED for ${name} ` +
176
- `(key=${skill.status!.artifactStorageKey}) — mounting SKILL.md WITHOUT the skill's ` +
177
- `supporting files (scripts/references will be missing): ${err instanceof Error ? err.message : err}`,
178
- );
179
- }
180
- }
181
-
182
- await writeSkillMount(skill, skillDir, artifactBytes);
183
- console.log(`[skill-writer] wrote skill mount: ${name}`);
184
- } catch (err) {
185
- console.warn(
186
- `[skill-writer] failed to mount skill ${name}: ${err instanceof Error ? err.message : err}`,
187
- );
188
- }
189
- }));
190
-
191
- return { paths };
192
- }
193
-
194
- // ─── Prompt generation ───────────────────────────────────────────────────
195
-
196
- /**
197
- * Generate the system prompt section following the Agent Skills spec
198
- * progressive disclosure model.
199
- *
200
- * Only metadata (name + description + location) is injected. The agent
201
- * reads SKILL.md on demand via filesystem tools.
202
- */
203
- export function generatePromptSection(
204
- skills: readonly Skill[],
205
- skillPaths: ReadonlyMap<string, string>,
206
- ): string {
207
- if (skills.length === 0) return "";
208
-
209
- const lines: string[] = [
210
- "",
211
- "",
212
- "## Skills",
213
- "",
214
- "You have access to the following skills. Each skill provides specialized " +
215
- "knowledge or capabilities.",
216
- "",
217
- "**Activation protocol**: To use a skill, read its SKILL.md file " +
218
- "using the `read` tool. The SKILL.md contains detailed instructions, " +
219
- "available tools, and usage examples.",
220
- "",
221
- "**Usage pattern**:",
222
- "",
223
- "1. Review the skill description below to determine relevance",
224
- "2. Read `{location}/SKILL.md` for full instructions",
225
- "3. Follow the skill's documented operations:",
226
- "",
227
- "`read {location}/references/schema.md`",
228
- '`execute("python3 {location}/scripts/run.py")`',
229
- "",
230
- ];
231
-
232
- for (const skill of skills) {
233
- const name = skill.spec?.name || skill.metadata?.slug || "unknown";
234
- const skillId = skill.metadata?.id ?? name;
235
- const skillDir = skillPaths.get(skillId) ?? `${SKILLS_RELATIVE_BASE}/${name}`;
236
- const description = skill.spec?.description || "(no description)";
237
-
238
- lines.push(`### ${name}`);
239
- lines.push(`**Description**: ${description}`);
240
- lines.push(`**Location**: \`${skillDir}/\``);
241
- lines.push(`**Activate**: \`read ${skillDir}/SKILL.md\``);
242
- lines.push("");
243
- }
244
-
245
- return lines.join("\n");
246
- }
247
-
248
- /**
249
- * Generate a brief note listing skills excluded by relevance filtering.
250
- *
251
- * The agent can still request these skills by name if it determines
252
- * they are needed mid-conversation.
253
- */
254
- export function generateAlsoAvailableSection(
255
- excludedNames: readonly string[],
256
- ): string {
257
- if (excludedNames.length === 0) return "";
258
-
259
- const namesStr = excludedNames.map(n => `\`${n}\``).join(", ");
260
- return (
261
- "\n### Also Available\n\n" +
262
- `These skills are installed but were not highlighted above: ${namesStr}. ` +
263
- "If you determine one of them is relevant to your task, " +
264
- "read its SKILL.md at `.stigmer/skills/<name>/SKILL.md` to activate it.\n"
265
- );
266
- }