@entelligentsia/forgecli 1.0.3 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +2 -1
  3. package/dist/CHANGELOG-forge-plugin.md +100 -0
  4. package/dist/CHANGELOG-pi.md +94 -0
  5. package/dist/extensions/forgecli/forge-artifact-tool.js +27 -4
  6. package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
  7. package/dist/extensions/forgecli/forge-tools.js +2 -2
  8. package/dist/extensions/forgecli/forge-tools.js.map +1 -1
  9. package/dist/extensions/forgecli/subagent/phase-guard.js +15 -5
  10. package/dist/extensions/forgecli/subagent/phase-guard.js.map +1 -1
  11. package/dist/extensions/forgecli/subagent/phase-summary-map.d.ts +1 -0
  12. package/dist/extensions/forgecli/subagent/phase-summary-map.js +17 -0
  13. package/dist/extensions/forgecli/subagent/phase-summary-map.js.map +1 -1
  14. package/dist/forge-payload/.base-pack/workflows/_fragments/store-cli-verbs.md +18 -3
  15. package/dist/forge-payload/.base-pack/workflows/architect_approve.md +4 -5
  16. package/dist/forge-payload/.base-pack/workflows/collator_agent.md +1 -1
  17. package/dist/forge-payload/.base-pack/workflows/commit_task.md +2 -3
  18. package/dist/forge-payload/.base-pack/workflows/implement_plan.md +3 -2
  19. package/dist/forge-payload/.base-pack/workflows/orchestrate_task.md +41 -47
  20. package/dist/forge-payload/.base-pack/workflows/triage.md +2 -2
  21. package/dist/forge-payload/.base-pack/workflows/validate_task.md +2 -3
  22. package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
  23. package/dist/forge-payload/.schemas/_defs/locator.schema.json +13 -0
  24. package/dist/forge-payload/.schemas/bug.schema.json +1 -0
  25. package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
  26. package/dist/forge-payload/.schemas/migrations.json +63 -0
  27. package/dist/forge-payload/.schemas/sprint.schema.json +1 -0
  28. package/dist/forge-payload/.schemas/task.schema.json +1 -0
  29. package/dist/forge-payload/integrity.json +3 -3
  30. package/dist/forge-payload/meta/workflows/_fragments/store-cli-verbs.md +18 -3
  31. package/dist/forge-payload/meta/workflows/meta-approve.md +4 -5
  32. package/dist/forge-payload/meta/workflows/meta-bug-triage.md +2 -2
  33. package/dist/forge-payload/meta/workflows/meta-collate.md +1 -1
  34. package/dist/forge-payload/meta/workflows/meta-commit.md +2 -3
  35. package/dist/forge-payload/meta/workflows/meta-implement.md +3 -2
  36. package/dist/forge-payload/meta/workflows/meta-orchestrate.md +41 -47
  37. package/dist/forge-payload/meta/workflows/meta-validate.md +2 -3
  38. package/dist/forge-payload/schemas/_defs/locator.schema.json +13 -0
  39. package/dist/forge-payload/schemas/bug.schema.json +1 -0
  40. package/dist/forge-payload/schemas/enum-catalog.json +2 -2
  41. package/dist/forge-payload/schemas/sprint.schema.json +1 -0
  42. package/dist/forge-payload/schemas/structure-manifest.json +3 -2
  43. package/dist/forge-payload/schemas/task.schema.json +1 -0
  44. package/dist/forge-payload/tools/artifact-store.cjs +242 -0
  45. package/dist/forge-payload/tools/artifact.cjs +60 -120
  46. package/dist/forge-payload/tools/lib/artifact-kinds.cjs +95 -0
  47. package/dist/forge-payload/tools/lib/store-nlp.cjs +6 -0
  48. package/dist/forge-payload/tools/lib/store-query-exec.cjs +39 -5
  49. package/dist/forge-payload/tools/lib/suggest.cjs +2 -1
  50. package/dist/forge-payload/tools/preflight-gate.cjs +55 -5
  51. package/dist/forge-payload/tools/store-cli.cjs +50 -15
  52. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts +5 -2
  53. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  54. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
  55. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  56. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  57. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
  58. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
  59. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
  60. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +19 -24
  61. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
  62. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +1 -0
  63. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
  64. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
  65. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
  66. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +22 -8
  67. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  68. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
  69. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  70. package/node_modules/@earendil-works/pi-ai/README.md +1 -1
  71. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +374 -122
  72. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  73. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +424 -232
  74. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
  75. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts +1 -1
  76. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
  77. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +38 -2
  78. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  79. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  80. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +21 -12
  81. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
  82. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  83. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +6 -10
  84. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  85. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.d.ts.map +1 -1
  86. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
  87. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js.map +1 -1
  88. package/node_modules/@earendil-works/pi-ai/dist/providers/google.d.ts.map +1 -1
  89. package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
  90. package/node_modules/@earendil-works/pi-ai/dist/providers/google.js.map +1 -1
  91. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.d.ts.map +1 -1
  92. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +3 -4
  93. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js.map +1 -1
  94. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.d.ts.map +1 -1
  95. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
  96. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js.map +1 -1
  97. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  98. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +159 -78
  99. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  100. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  101. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +16 -11
  102. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
  103. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.d.ts.map +1 -1
  104. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +4 -1
  105. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  106. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  107. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +6 -10
  108. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
  109. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  110. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
  111. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
  112. package/node_modules/@earendil-works/pi-ai/dist/stream.d.ts.map +1 -1
  113. package/node_modules/@earendil-works/pi-ai/dist/stream.js +14 -2
  114. package/node_modules/@earendil-works/pi-ai/dist/stream.js.map +1 -1
  115. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +14 -4
  116. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  117. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  118. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts +6 -0
  119. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.d.ts.map +1 -0
  120. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
  121. package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js.map +1 -0
  122. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts +9 -7
  123. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.d.ts.map +1 -1
  124. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
  125. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js.map +1 -1
  126. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  127. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
  128. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  129. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts +1 -1
  130. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
  131. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
  132. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js.map +1 -1
  133. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts +10 -1
  134. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  135. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
  136. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js.map +1 -1
  137. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  138. package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +94 -0
  139. package/node_modules/@earendil-works/pi-coding-agent/README.md +9 -0
  140. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts +3 -0
  141. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  142. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +27 -0
  143. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js.map +1 -1
  144. package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
  145. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +15 -2
  146. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
  147. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts +1 -0
  148. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.d.ts.map +1 -1
  149. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -0
  150. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js.map +1 -1
  151. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +5 -1
  152. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  153. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +28 -4
  154. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  155. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  156. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
  157. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  158. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -1
  159. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  160. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +8 -2
  161. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  162. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts +7 -5
  163. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  164. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  165. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  166. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +65 -13
  167. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  168. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  169. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
  170. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  171. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts +9 -1
  172. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
  173. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +134 -11
  174. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
  175. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts +2 -0
  176. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  177. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +10 -6
  178. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js.map +1 -1
  179. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts +6 -7
  180. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
  181. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +75 -28
  182. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js.map +1 -1
  183. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts +2 -0
  184. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  185. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +14 -9
  186. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  187. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  188. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +0 -3
  189. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  190. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  191. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +7 -10
  192. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  193. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  194. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  195. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  196. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  197. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  198. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -7
  199. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  200. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  201. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +6 -7
  202. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  203. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts +5 -2
  204. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  205. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js +17 -1
  206. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  207. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  208. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +5 -6
  209. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  210. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts +2 -0
  211. package/node_modules/@earendil-works/pi-coding-agent/dist/index.d.ts.map +1 -1
  212. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -0
  213. package/node_modules/@earendil-works/pi-coding-agent/dist/index.js.map +1 -1
  214. package/node_modules/@earendil-works/pi-coding-agent/dist/main.d.ts.map +1 -1
  215. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +69 -16
  216. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js.map +1 -1
  217. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.d.ts.map +1 -1
  218. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +118 -1
  219. package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js.map +1 -1
  220. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts +1 -3
  221. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  222. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +2 -4
  223. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  224. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  225. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
  226. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  227. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
  228. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  229. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +59 -6
  230. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  231. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  232. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
  233. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  234. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  235. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +3 -1
  236. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  237. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -0
  238. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  239. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  240. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts +4 -0
  241. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.d.ts.map +1 -0
  242. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js +13 -0
  243. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js.map +1 -0
  244. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts +3 -0
  245. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.d.ts.map +1 -0
  246. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js +7 -0
  247. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js.map +1 -0
  248. package/node_modules/@earendil-works/pi-coding-agent/docs/custom-provider.md +13 -10
  249. package/node_modules/@earendil-works/pi-coding-agent/docs/development.md +1 -1
  250. package/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +12 -6
  251. package/node_modules/@earendil-works/pi-coding-agent/docs/models.md +25 -12
  252. package/node_modules/@earendil-works/pi-coding-agent/docs/providers.md +13 -5
  253. package/node_modules/@earendil-works/pi-coding-agent/docs/quickstart.md +1 -0
  254. package/node_modules/@earendil-works/pi-coding-agent/docs/rpc.md +2 -1
  255. package/node_modules/@earendil-works/pi-coding-agent/docs/sdk.md +6 -0
  256. package/node_modules/@earendil-works/pi-coding-agent/docs/session-format.md +1 -1
  257. package/node_modules/@earendil-works/pi-coding-agent/docs/sessions.md +8 -0
  258. package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +7 -3
  259. package/node_modules/@earendil-works/pi-coding-agent/docs/terminal-setup.md +2 -0
  260. package/node_modules/@earendil-works/pi-coding-agent/docs/tui.md +2 -2
  261. package/node_modules/@earendil-works/pi-coding-agent/docs/usage.md +9 -0
  262. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/README.md +1 -0
  263. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/index.ts +1 -1
  264. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
  265. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/index.ts +54 -3
  266. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  267. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/git-merge-and-resolve.ts +115 -0
  268. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/input-transform-streaming.ts +39 -0
  269. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
  270. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
  271. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +443 -61
  272. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
  273. package/node_modules/@earendil-works/pi-tui/README.md +2 -2
  274. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  275. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +24 -83
  276. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  277. package/node_modules/@earendil-works/pi-tui/dist/components/input.d.ts.map +1 -1
  278. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +7 -55
  279. package/node_modules/@earendil-works/pi-tui/dist/components/input.js.map +1 -1
  280. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts +7 -1
  281. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.d.ts.map +1 -1
  282. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
  283. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js.map +1 -1
  284. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
  285. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  286. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  287. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts +1 -1
  288. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.d.ts.map +1 -1
  289. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
  290. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js.map +1 -1
  291. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts +33 -10
  292. package/node_modules/@earendil-works/pi-tui/dist/terminal.d.ts.map +1 -1
  293. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +172 -37
  294. package/node_modules/@earendil-works/pi-tui/dist/terminal.js.map +1 -1
  295. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts +6 -1
  296. package/node_modules/@earendil-works/pi-tui/dist/utils.d.ts.map +1 -1
  297. package/node_modules/@earendil-works/pi-tui/dist/utils.js +27 -15
  298. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
  299. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts +25 -0
  300. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.d.ts.map +1 -0
  301. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
  302. package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js.map +1 -0
  303. package/node_modules/@earendil-works/pi-tui/package.json +2 -2
  304. package/node_modules/@entelligentsia/forge-compress/LICENSE +21 -0
  305. package/node_modules/@entelligentsia/forge-compress/README.md +85 -0
  306. package/node_modules/@mariozechner/clipboard/Cargo.toml +3 -3
  307. package/node_modules/@mariozechner/clipboard/index.d.ts +34 -20
  308. package/node_modules/@mariozechner/clipboard/index.js +546 -257
  309. package/node_modules/@mariozechner/clipboard/package.json +5 -6
  310. package/node_modules/@mariozechner/clipboard/package.json.prepack-backup +14 -14
  311. package/node_modules/@mariozechner/clipboard/src/lib.rs +4 -9
  312. package/node_modules/@mariozechner/clipboard-linux-x64-gnu/clipboard.linux-x64-gnu.node +0 -0
  313. package/node_modules/@mariozechner/clipboard-linux-x64-gnu/package.json +2 -2
  314. package/package.json +7 -7
  315. package/dist/forge-payload/.base-pack/commands/quiz-agent.md +0 -6
  316. package/dist/forge-payload/.base-pack/commands/retrospective.md +0 -6
  317. package/dist/forge-payload/.base-pack/commands/sprint-intake.md +0 -6
  318. package/dist/forge-payload/.base-pack/commands/sprint-plan.md +0 -6
  319. package/dist/forge-payload/commands/calibrate.md +0 -10
  320. package/dist/forge-payload/commands/materialize.md +0 -119
  321. package/dist/forge-payload/commands/migrate.md +0 -12
  322. package/dist/forge-payload/commands/quiz-agent.md +0 -6
  323. package/dist/forge-payload/commands/regenerate.md +0 -6
  324. package/dist/forge-payload/commands/store-query.md +0 -6
  325. package/dist/forge-payload/commands/store-repair.md +0 -6
  326. package/dist/forge-payload/commands/update-tools.md +0 -10
  327. package/dist/forge-payload/meta/templates/meta-retrospective.md +0 -28
  328. package/dist/forge-payload/tools/prompts/sprint-plan-prompt.md +0 -70
  329. package/dist/forge-payload/tools/schemas/task-list.schema.json +0 -53
  330. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts +0 -4
  331. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.d.ts.map +0 -1
  332. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js +0 -3
  333. package/node_modules/@earendil-works/pi-agent-core/dist/harness/execution-env.js.map +0 -1
  334. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts +0 -20
  335. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.d.ts.map +0 -1
  336. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js +0 -92
  337. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/jsonl.js.map +0 -1
  338. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts +0 -18
  339. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.d.ts.map +0 -1
  340. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js +0 -42
  341. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/memory.js.map +0 -1
  342. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts +0 -10
  343. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.d.ts.map +0 -1
  344. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js +0 -31
  345. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/repo/shared.js.map +0 -1
  346. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts +0 -30
  347. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.d.ts.map +0 -1
  348. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js +0 -170
  349. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/jsonl.js.map +0 -1
  350. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts +0 -26
  351. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.d.ts.map +0 -1
  352. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js +0 -90
  353. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/storage/memory.js.map +0 -1
  354. package/node_modules/@mariozechner/clipboard-linux-x64-musl/README.md +0 -3
  355. package/node_modules/@mariozechner/clipboard-linux-x64-musl/clipboard.linux-x64-musl.node +0 -0
  356. package/node_modules/@mariozechner/clipboard-linux-x64-musl/package.json +0 -25
@@ -566,28 +566,32 @@ for each task in dependency_sorted(tasks):
566
566
  /compact
567
567
  continue
568
568
 
569
- # --- Review phase: detect verdict via parse-verdict.cjs (see Verdict Detection below) ---
570
- # The CLI returns exit 0/1/2 for approved/revision/unknown. Never pattern-match
571
- # the **Verdict:** line manually — the closed vocabulary lives in the tool.
569
+ # --- Review phase: detect verdict via read-verdict.cjs (see Verdict Detection below) ---
570
+ # Verdicts come from the STORE record (phase summaries / task.status), NOT from a
571
+ # markdown review artifact — the orchestrator never constructs an artifact path.
572
+ # stdout is one of: approved | revision | n/a | unknown. Never pattern-match a
573
+ # **Verdict:** line — the closed vocabulary lives in the tool.
572
574
  verdict_result = run_bash(
573
- f'node "$FORGE_ROOT/tools/parse-verdict.cjs" {review_artifact_path(phase, task)}'
575
+ f'node "$FORGE_ROOT/tools/read-verdict.cjs" --phase {phase.role} --task {task_id}'
574
576
  )
575
- if verdict_result.exit_code == 0:
577
+ verdict_token = verdict_result.stdout.strip()
578
+ if verdict_token == "approved":
576
579
  verdict = "Approved"
577
- elif verdict_result.exit_code == 1:
580
+ elif verdict_token == "revision":
578
581
  verdict = "Revision Required"
579
582
  else:
580
- # exit 2: malformed, missing verdict line, or missing artifact. Never guess.
583
+ # "n/a" / "unknown" (no verdict recorded) or exit 2 (record not found / bad args).
584
+ # Never guess.
581
585
  print(f" ⚠ {task_id} {phase.role} — verdict_malformed, escalating\n")
582
586
  emit_event(task, phase, action="verdict_malformed",
583
- notes=f"parse-verdict exit={verdict_result.exit_code}")
587
+ notes=f"read-verdict stdout='{verdict_token}' exit={verdict_result.exit_code}")
584
588
  # ---- ESCALATION (mandatory hard stop — do NOT continue) ----
585
589
  run_bash(f'node "$FORGE_ROOT/tools/store-cli.cjs" update-status task {task_id} status escalated')
586
590
  emit_event(task, phase, eventId=event_id, iteration=iteration,
587
591
  action="escalated", verdict="escalated",
588
- notes="verdict_malformed: review artifact missing or verdict line unparseable")
589
- print(f" ⚠ Task {task_id} escalated: verdict_malformed — review artifact missing or verdict line unparseable\n")
590
- print(f" Review artifact: {review_artifact_path(phase, task)}\n")
592
+ notes="verdict_malformed: no verdict recorded in the phase summary / record")
593
+ print(f" ⚠ Task {task_id} escalated: verdict_malformed — no verdict recorded for {phase.role}\n")
594
+ print(f" Inspect with: node \"$FORGE_ROOT/tools/read-verdict.cjs\" --phase {phase.role} --task {task_id}\n")
591
595
  print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
592
596
  break
593
597
 
@@ -609,7 +613,7 @@ for each task in dependency_sorted(tasks):
609
613
  action="escalated", verdict="escalated",
610
614
  notes="max iterations reached")
611
615
  print(f" ⚠ Task {task_id} escalated: max iterations reached\n")
612
- print(f" Review artifact: {review_artifact_path(phase, task)}\n")
616
+ print(f" Inspect with: node \"$FORGE_ROOT/tools/read-verdict.cjs\" --phase {phase.role} --task {task_id}\n")
613
617
  print(f" Resume with: /{phase.command} {task_id} after addressing the issues.\n")
614
618
  break
615
619
  break # stop processing this task
@@ -621,7 +625,7 @@ for each task in dependency_sorted(tasks):
621
625
  print(f"[checkpoint] task={task_id} sprint={sprint_id} phase_index={i} iterations={iteration_counts}")
622
626
  /compact
623
627
 
624
- # No `else:` branch needed — parse-verdict.cjs already exhausts the
628
+ # No `else:` branch needed — read-verdict.cjs already exhausts the
625
629
  # possibilities (approved | revision | verdict_malformed), and the
626
630
  # malformed case is handled above before this if/elif chain.
627
631
  ```
@@ -681,45 +685,35 @@ Examples:
681
685
  ## Verdict Detection
682
686
 
683
687
  After each review phase completes, the orchestrator MUST read the verdict
684
- before branching. Do not infer the verdict from conversation context alone
685
- always read the artifact.
688
+ before branching. Do not infer the verdict from conversation context alone, and
689
+ **never construct or read a markdown artifact path** to find it — the verdict
690
+ lives in the **store record** (the phase summary written by `set-summary`, or
691
+ `task.status` for the approve phase).
686
692
 
687
- | Phase role | Artifact to read | Verdict field |
688
- |---------------|---------------------------------------------------------------------------|------------------------------|
689
- | `review-plan` | `{engineering}/sprints/{sprintDir}/{taskDir}/PLAN_REVIEW.md` | Line matching `**Verdict:**` |
690
- | `review-code` | `{engineering}/sprints/{sprintDir}/{taskDir}/CODE_REVIEW.md` | Line matching `**Verdict:**` |
691
- | `validate` | `{engineering}/sprints/{sprintDir}/{taskDir}/VALIDATION_REPORT.md` | Line matching `**Verdict:**` |
692
-
693
- The verdict line format is:
694
-
695
- ```
696
- **Verdict:** Approved
697
- ```
698
- or
699
- ```
700
- **Verdict:** Revision Required
701
- ```
702
-
703
- **Parse the verdict via `parse-verdict.cjs`** — do NOT pattern-match the
704
- line manually. The tool enforces a closed verdict vocabulary so typos, case
705
- drift, and reviewer prose cannot cause silent misclassification:
693
+ **Read the verdict via `read-verdict.cjs`** addressed by entity ID and phase
694
+ role, never by file path. The tool sources the verdict from the record and
695
+ enforces a closed vocabulary so typos, case drift, and reviewer prose cannot
696
+ cause silent misclassification:
706
697
 
707
698
  ```
708
699
  FORGE_ROOT = resolve_forge_root()
709
- result = run_bash(f'node "$FORGE_ROOT/tools/parse-verdict.cjs" {artifact_path}')
710
- # exit 0 → approved (stdout "approved")
711
- # exit 1 → revision (stdout "revision")
712
- # exit 2 unknown/malformed/missing (stdout "unknown")
700
+ result = run_bash(f'node "$FORGE_ROOT/tools/read-verdict.cjs" --phase {phase.role} --task {task_id}')
701
+ # stdout "approved" → approved
702
+ # stdout "revision" → revision
703
+ # stdout "n/a" | "unknown" → no verdict recorded (treat as malformed; do NOT guess)
704
+ # exit 2 → record not found / invalid args (treat as malformed)
713
705
  ```
714
706
 
715
- Recognised values (case-insensitive):
707
+ Branch on the **stdout token** (exit 1 bundles both `revision` and the
708
+ no-verdict cases, so the token is authoritative). Recognised verdict values:
716
709
 
717
- - **approved** — `Approved`, `Approve`, `[Approved]`
718
- - **revision** — `Revision Required`, `Revision`, `Needs Revision`, `Changes Requested`
710
+ - **approved** — written as `verdict: "approved"` in the phase summary (or `task.status == approved` for the approve phase).
711
+ - **revision** — `verdict: "revision"`.
719
712
 
720
- Anything else — including free-form prose, missing bold markers, a missing
721
- verdict line, or a missing artifact yields exit 2. Do NOT treat unknown
722
- as approved or revision; halt the loop and escalate via `verdict_malformed`.
713
+ Anything else — `n/a`, `unknown`, a missing summary, or a missing record —
714
+ must NOT be treated as approved or revision; halt the loop and escalate via
715
+ `verdict_malformed`. (In bug mode pass `--bug {bug_id}`; `read-verdict.cjs`
716
+ applies the bug-specific phase→summary map.)
723
717
 
724
718
  ## Escalation Procedure
725
719
 
@@ -755,8 +749,8 @@ Grammar (one directive per line):
755
749
  `in [v1, v2, ...]`. Fields are dotted paths against the store record, e.g.
756
750
  `task.status`.
757
751
  - `forbid <field> <op> <value>` — predicate must NOT hold.
758
- - `after <phase> = <approved|revision>` — predecessor phase's review artifact
759
- must carry the stated verdict (parsed by `parse-verdict.cjs`).
752
+ - `after <phase> = <approved|revision>` — predecessor phase's stored verdict
753
+ must match (read from the record by `read-verdict.cjs`, not from markdown).
760
754
 
761
755
  ```gates phase=plan
762
756
  forbid task.status == committed
@@ -854,7 +848,7 @@ is a violation of the Iron Laws.
854
848
  - Subagent empty/crash/timeout response: retry once with simplified prompt
855
849
  (strip summary and architecture blocks). Escalate on second failure.
856
850
  See Subagent Response Validation in the Execution Algorithm.
857
- - Subagent non-zero exit code (not parse-verdict): same as above — retry
851
+ - Subagent non-zero exit code (not read-verdict): same as above — retry
858
852
  once, escalate on second failure. The crash reason is captured in the
859
853
  escalation event notes.
860
854
  - Verdict malformed or missing: escalate to human immediately. Never guess.
@@ -115,10 +115,9 @@ The Supervisor performs a final validation of the implementation against the acc
115
115
  "artifact_ref":"VALIDATION_REPORT.md"
116
116
  }
117
117
  ```
118
- - Call:
118
+ - Call (the sidecar path is auto-resolved from the task record's `path` — never pass it):
119
119
  ```
120
- node "$FORGE_ROOT/tools/store-cli.cjs" set-summary {task_id} validation \
121
- engineering/sprints/{sprint}/{task}/VALIDATION-SUMMARY.json
120
+ node "$FORGE_ROOT/tools/store-cli.cjs" set-summary {task_id} validation
122
121
  ```
123
122
  - If set-summary exits non-zero, fix the sidecar JSON and retry. Do not proceed without a valid summary.
124
123
  ```
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "forge/_defs/locator.schema.json",
4
+ "title": "ArtifactLocator",
5
+ "description": "Backend-agnostic artifact locator (ADR doc/decisions/artifact-resolution-abstraction.md, issue #111 Phase 3). Single-sourced under _defs/ and $ref'd from task/bug/sprint schemas. `record.path` remains the required back-compat alias during migration; `locator` is the forward-looking form so a non-fs backend (s3/cms/db) is a drop-in. `ref` is an opaque, backend-specific reference (a URI is a fine encoding): fs → 'engineering/sprints/<dir>/<task>/', s3 → 's3://bucket/key', cms → 'cms://collection/<id>', db → 'blob:<uuid>'.",
6
+ "type": "object",
7
+ "required": ["backend", "ref"],
8
+ "properties": {
9
+ "backend": { "type": "string", "description": "Storage backend identifier — e.g. fs, s3, gcs, azure, cms, db." },
10
+ "ref": { "type": "string", "description": "Opaque backend-specific reference (URI-encodable)." }
11
+ },
12
+ "additionalProperties": false
13
+ }
@@ -11,6 +11,7 @@
11
11
  "severity": { "type": "string", "enum": ["critical", "major", "minor"] },
12
12
  "status": { "type": "string", "enum": ["reported", "triaged", "in-progress", "fixed"] },
13
13
  "path": { "type": "string" },
14
+ "locator": { "$ref": "_defs/locator.schema.json" },
14
15
  "rootCauseCategory": {
15
16
  "type": "string",
16
17
  "enum": ["validation", "auth", "business-rule", "data-integrity", "race-condition", "integration", "configuration", "regression"]
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.0.2",
3
- "generated": "2026-05-28",
2
+ "version": "1.0.10",
3
+ "generated": "2026-05-31",
4
4
  "note": "Authoritative enum catalog. Source: build-enum-catalog.cjs. Regenerate via node forge/tools/build-manifest.cjs.",
5
5
  "enums": {
6
6
  "task.status": [
@@ -20,6 +20,7 @@
20
20
  "createdAt": { "type": "string", "format": "date-time" },
21
21
  "completedAt": { "type": "string", "format": "date-time" },
22
22
  "path": { "type": "string" },
23
+ "locator": { "$ref": "_defs/locator.schema.json" },
23
24
  "humanEstimates": { "type": "object" },
24
25
  "features": { "type": "array", "items": { "type": "string" } }
25
26
  },
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.0.2",
3
- "generatedAt": "2026-05-28T05:59:32.606Z",
2
+ "version": "1.0.10",
3
+ "generatedAt": "2026-05-31T03:19:45.318Z",
4
4
  "generatedByTool": "build-manifest.cjs",
5
5
  "namespaces": {
6
6
  "personas": {
@@ -110,6 +110,7 @@
110
110
  "logicalKey": "schemas",
111
111
  "dir": ".forge/schemas",
112
112
  "files": [
113
+ "_defs/locator.schema.json",
113
114
  "_defs/phaseSummary.schema.json",
114
115
  "bug.schema.json",
115
116
  "collation-state.schema.json",
@@ -19,6 +19,7 @@
19
19
  ]
20
20
  },
21
21
  "path": { "type": "string" },
22
+ "locator": { "$ref": "_defs/locator.schema.json" },
22
23
  "estimate": { "type": "string", "enum": ["S", "M", "L", "XL"] },
23
24
  "dependencies": { "type": "array", "items": { "type": "string" } },
24
25
  "knowledgeUpdates": { "type": "array" },
@@ -0,0 +1,242 @@
1
+ 'use strict';
2
+
3
+ // ── ArtifactStore — backend-agnostic artifact provider ───────────────────────
4
+ //
5
+ // Mirrors the store.cjs `Store`/`FSImpl` pattern (ADR
6
+ // `doc/decisions/artifact-resolution-abstraction.md`, issue #111 Phase 3):
7
+ // a backend-agnostic facade delegating to a swappable, SYNCHRONOUS impl,
8
+ // default-wired to the filesystem, impl exported for substitution.
9
+ //
10
+ // class ArtifactStore { read|write|exists|url|list|delete(handle) → impl }
11
+ // class FsArtifactImpl { engineering/ files }
12
+ // module.exports = new ArtifactStore(new FsArtifactImpl())
13
+ // module.exports.FsArtifactImpl = FsArtifactImpl // swap for S3Impl / CmsImpl / DbBlobImpl
14
+ //
15
+ // A `handle` is the logical address (entityType, entityId, artifactKind) — never
16
+ // a path. The fs impl resolves it from the store record's `path` (the locator)
17
+ // plus the canonical kind registry, so callers never construct paths.
18
+ //
19
+ // SYNC CONSTRAINT (load-bearing): in-process callers (store-cli.cjs,
20
+ // preflight-gate.cjs, collate.cjs) invoke this without `await`, so every method
21
+ // is synchronous — same constraint that blocks the store's async InstantDbImpl
22
+ // (see doc/decisions/instantdb-store-backend.md). A future remote impl must
23
+ // either stay sync or be reached only through the forge-cli subprocess surface.
24
+
25
+ const fs = require('fs');
26
+ const path = require('path');
27
+ const { execFileSync } = require('child_process');
28
+ const { resolveArtifactFilename } = require('./lib/artifact-kinds.cjs');
29
+
30
+ // ── Locator helpers ({ backend, ref }) ───────────────────────────────────────
31
+
32
+ // Derive the backend-agnostic locator from a store record. Prefers an explicit
33
+ // `record.locator`; otherwise treats the legacy `record.path` as an fs locator
34
+ // (the back-compat alias maintained during migration).
35
+ function toLocator(record) {
36
+ if (record && record.locator && record.locator.backend) return record.locator;
37
+ if (record && typeof record.path === 'string' && record.path.length > 0) {
38
+ return { backend: 'fs', ref: record.path };
39
+ }
40
+ return null;
41
+ }
42
+
43
+ // For an fs locator ref, return the entity *directory* (strip a trailing filename).
44
+ function fsRefToDir(ref) {
45
+ const norm = String(ref).replace(/\\/g, '/').replace(/\/+$/, '');
46
+ return /\.[a-zA-Z0-9]+$/.test(norm) ? norm.replace(/\/[^/]*$/, '') : norm;
47
+ }
48
+
49
+ // ── Default dir resolution (store record path) ───────────────────────────────
50
+ // Reads a record's `path` via store-cli (out-of-process) so this module has no
51
+ // hard dependency on store internals. Returns the entity directory or null.
52
+ function readStorePath(entity, entityId, toolDir, projectRoot) {
53
+ const cliPath = path.join(toolDir, 'store-cli.cjs');
54
+ try {
55
+ const result = execFileSync('node', [cliPath, 'read', entity, entityId, '--json'], {
56
+ cwd: projectRoot, encoding: 'utf8', timeout: 10_000,
57
+ });
58
+ const record = JSON.parse(result);
59
+ const loc = toLocator(record);
60
+ if (loc && loc.backend === 'fs') return fsRefToDir(loc.ref);
61
+ } catch (_) { /* store unavailable / record not found — fall through */ }
62
+ return null;
63
+ }
64
+
65
+ // Resolve entity directory from the store record's path, falling back to
66
+ // ID-only construction. (Moved verbatim from artifact.cjs; re-exported there.)
67
+ function resolveEntityDir(entity, entityId, engineeringPath, toolDir, projectRoot) {
68
+ switch (entity) {
69
+ case 'bug': {
70
+ const storePath = readStorePath('bug', entityId, toolDir, projectRoot);
71
+ if (storePath) return storePath;
72
+ return path.join(engineeringPath, 'bugs', entityId);
73
+ }
74
+ case 'sprint': {
75
+ const storePath = readStorePath('sprint', entityId, toolDir, projectRoot);
76
+ if (storePath) return storePath;
77
+ return path.join(engineeringPath, 'sprints', entityId);
78
+ }
79
+ case 'task': {
80
+ const storePath = readStorePath('task', entityId, toolDir, projectRoot);
81
+ if (storePath) return storePath;
82
+ const match = entityId.match(/^(.+-S\d+)-T\d+$/);
83
+ if (!match) return null;
84
+ const sprintId = match[1];
85
+ const sprintPath = readStorePath('sprint', sprintId, toolDir, projectRoot);
86
+ if (sprintPath) return path.join(sprintPath, entityId);
87
+ return path.join(engineeringPath, 'sprints', sprintId, entityId);
88
+ }
89
+ default:
90
+ return null;
91
+ }
92
+ }
93
+
94
+ // ── Facade ───────────────────────────────────────────────────────────────────
95
+
96
+ class ArtifactStore {
97
+ // The constructor impl is the default backend (`fs`). Additional backends are
98
+ // added with register(name, impl) — Phase 4. Each call routes to the impl for
99
+ // the handle's `backend` (default 'fs'), so adding a backend requires
100
+ // implementing the method surface only — no call-site or prompt changes.
101
+ constructor(impl) {
102
+ this.impl = impl; // default (fs) backend
103
+ this._backends = new Map([['fs', impl]]);
104
+ }
105
+
106
+ // Register an additional backend impl (e.g. an S3/CMS/DB provider). Returns
107
+ // `this` for chaining; re-registering the same name replaces the impl.
108
+ register(backend, impl) {
109
+ this._backends.set(backend, impl);
110
+ return this;
111
+ }
112
+
113
+ _implFor(handle) {
114
+ const backend = (handle && handle.backend) || 'fs';
115
+ const impl = this._backends.get(backend);
116
+ if (!impl) {
117
+ throw new Error(
118
+ `No ArtifactStore backend registered for "${backend}". ` +
119
+ `Registered: ${[...this._backends.keys()].join(', ')}. ` +
120
+ `Add one with artifactStore.register("${backend}", impl).`
121
+ );
122
+ }
123
+ return impl;
124
+ }
125
+
126
+ read(handle) { return this._implFor(handle).read(handle); }
127
+ write(handle, content) { return this._implFor(handle).write(handle, content); }
128
+ exists(handle) { return this._implFor(handle).exists(handle); }
129
+ url(handle) { return this._implFor(handle).url(handle); }
130
+ list(handle) { return this._implFor(handle).list(handle); }
131
+ delete(handle) { return this._implFor(handle).delete(handle); }
132
+ }
133
+
134
+ // ── Filesystem impl ───────────────────────────────────────────────────────────
135
+
136
+ class FsArtifactImpl {
137
+ // opts: { projectRoot, engineeringPath, toolDir, resolveDir }
138
+ // resolveDir(entity, entityId) → dir (relative to projectRoot) | null.
139
+ // Injectable for testing; defaults to the store-record resolver above.
140
+ constructor(opts = {}) {
141
+ this.projectRoot = opts.projectRoot || process.cwd();
142
+ this.engineeringPath = opts.engineeringPath || 'engineering';
143
+ this.toolDir = opts.toolDir || __dirname;
144
+ this._resolveDir = opts.resolveDir
145
+ || ((entity, entityId) => resolveEntityDir(entity, entityId, this.engineeringPath, this.toolDir, this.projectRoot));
146
+ }
147
+
148
+ _absDir(handle) {
149
+ const dir = this._resolveDir(handle.entity, handle.entityId);
150
+ if (!dir) {
151
+ throw new Error(
152
+ `Cannot resolve ${handle.entity} directory for "${handle.entityId}". ` +
153
+ `Expected ID pattern: task=PREFIX-SNN-TNN, bug=PREFIX-BNN[-slug], sprint=PREFIX-SNN.`
154
+ );
155
+ }
156
+ return path.resolve(this.projectRoot, dir);
157
+ }
158
+
159
+ _absFile(handle) {
160
+ return path.join(this._absDir(handle), resolveArtifactFilename(handle.entity, handle.kind));
161
+ }
162
+
163
+ read(handle) {
164
+ const file = this._absFile(handle);
165
+ if (!fs.existsSync(file)) {
166
+ const err = new Error(`Artifact not found: ${path.relative(this.projectRoot, file)}`);
167
+ err.code = 'ENOENT';
168
+ throw err;
169
+ }
170
+ return fs.readFileSync(file, 'utf8');
171
+ }
172
+
173
+ write(handle, content) {
174
+ const dir = this._absDir(handle);
175
+ fs.mkdirSync(dir, { recursive: true });
176
+ const file = path.join(dir, resolveArtifactFilename(handle.entity, handle.kind));
177
+ fs.writeFileSync(file, content, 'utf8');
178
+ return { bytes: Buffer.byteLength(content, 'utf8'), ref: path.relative(this.projectRoot, file) };
179
+ }
180
+
181
+ exists(handle) {
182
+ try { return fs.existsSync(this._absFile(handle)); }
183
+ catch (_) { return false; }
184
+ }
185
+
186
+ url(handle) {
187
+ return 'file://' + this._absFile(handle);
188
+ }
189
+
190
+ // Entity-level listing: handle without `kind`. Returns existing filenames.
191
+ list(handle) {
192
+ const dir = this._absDir(handle);
193
+ if (!fs.existsSync(dir)) return [];
194
+ return fs.readdirSync(dir).filter((f) => f.endsWith('.md') || f.endsWith('.json'));
195
+ }
196
+
197
+ delete(handle) {
198
+ const file = this._absFile(handle);
199
+ if (fs.existsSync(file)) { fs.unlinkSync(file); return true; }
200
+ return false;
201
+ }
202
+ }
203
+
204
+ // ── Reference non-fs backend (Phase 4) ───────────────────────────────────────
205
+ //
206
+ // A complete, synchronous, in-memory implementation of the ArtifactStore method
207
+ // surface. It exists as the canonical *reference* for adding a backend: a real
208
+ // S3/CMS/DB provider implements these same six methods and is wired with
209
+ // `artifactStore.register('<backend>', new XxxArtifactImpl(...))` — no prompt or
210
+ // call-site changes. (A networked impl is sync-bound for in-process callers per
211
+ // the ADR; it is reachable async-internally only through the forge-cli
212
+ // subprocess surface. This in-memory impl is fully functional and dependency-free.)
213
+ class MemArtifactImpl {
214
+ constructor() { this.files = new Map(); }
215
+ _key(h) { return `${h.entity}/${h.entityId}/${resolveArtifactFilename(h.entity, h.kind)}`; }
216
+ read(handle) {
217
+ const k = this._key(handle);
218
+ if (!this.files.has(k)) { const e = new Error(`Artifact not found: mem:${k}`); e.code = 'ENOENT'; throw e; }
219
+ return this.files.get(k);
220
+ }
221
+ write(handle, content) {
222
+ const k = this._key(handle);
223
+ this.files.set(k, content);
224
+ return { bytes: Buffer.byteLength(content, 'utf8'), ref: `mem:${k}` };
225
+ }
226
+ exists(handle) { return this.files.has(this._key(handle)); }
227
+ url(handle) { return `mem://${this._key(handle)}`; }
228
+ list(handle) {
229
+ const prefix = `${handle.entity}/${handle.entityId}/`;
230
+ return [...this.files.keys()].filter((k) => k.startsWith(prefix)).map((k) => k.slice(prefix.length));
231
+ }
232
+ delete(handle) { return this.files.delete(this._key(handle)); }
233
+ }
234
+
235
+ module.exports = new ArtifactStore(new FsArtifactImpl());
236
+ module.exports.ArtifactStore = ArtifactStore;
237
+ module.exports.FsArtifactImpl = FsArtifactImpl;
238
+ module.exports.MemArtifactImpl = MemArtifactImpl;
239
+ module.exports.toLocator = toLocator;
240
+ module.exports.fsRefToDir = fsRefToDir;
241
+ module.exports.resolveEntityDir = resolveEntityDir;
242
+ module.exports.readStorePath = readStorePath;