@enterpriseai/cli 3.19.0 → 3.19.2

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 (364) hide show
  1. package/package.json +3 -3
  2. package/resources/deploy/eai-app-template/producer-pin.json +5 -5
  3. package/resources/deploy/eai-app-template/tests/source-unknown-deployment-evidence.test.mjs +2141 -1
  4. package/resources/gofer/.gofer-version +4 -357
  5. package/resources/gofer/agents-skills/eai/SKILL.md +365 -0
  6. package/resources/gofer/agents-skills/eai-update/SKILL.md +56 -0
  7. package/resources/gofer/agents-skills/gofer-documentation/SKILL.md +93 -0
  8. package/resources/gofer/bash-scripts/create-new-feature.sh +3 -1
  9. package/resources/gofer/bash-scripts/sync-implementation-status.sh +4 -3
  10. package/resources/gofer/bash-scripts/update-agent-context.sh +7 -8
  11. package/resources/gofer/bash-scripts/validate-artifact.sh +10 -6
  12. package/resources/gofer/bash-scripts/verify-object-type-routing-workspace.sh +184 -0
  13. package/resources/gofer/claude-commands/eai-update.md +46 -0
  14. package/resources/gofer/claude-commands/eai.md +355 -0
  15. package/resources/gofer/claude-skills/eai/SKILL.md +365 -0
  16. package/resources/gofer/claude-skills/eai-update/SKILL.md +56 -0
  17. package/resources/gofer/claude-skills/gofer-documentation/SKILL.md +93 -0
  18. package/resources/gofer/commands/0_gofer_start.md +440 -99
  19. package/resources/gofer/commands/0a_problem_validation.md +187 -27
  20. package/resources/gofer/commands/10_gofer_cloud.md +183 -23
  21. package/resources/gofer/commands/1_gofer_research.md +239 -30
  22. package/resources/gofer/commands/2_gofer_specify.md +239 -35
  23. package/resources/gofer/commands/3_gofer_plan.md +259 -43
  24. package/resources/gofer/commands/4_gofer_tasks.md +401 -81
  25. package/resources/gofer/commands/5_gofer_implement.md +375 -84
  26. package/resources/gofer/commands/6_gofer_validate.md +284 -53
  27. package/resources/gofer/commands/7_gofer_save.md +187 -26
  28. package/resources/gofer/commands/7a_stakeholder_comms.md +183 -23
  29. package/resources/gofer/commands/8_gofer_branding.md +183 -23
  30. package/resources/gofer/commands/9_gofer_tests.md +212 -23
  31. package/resources/gofer/commands/gofer_bootstrap_workspace.md +121 -8
  32. package/resources/gofer/commands/gofer_check_workspace.md +123 -8
  33. package/resources/gofer/commands/gofer_constitution.md +183 -23
  34. package/resources/gofer/commands/gofer_diagnose.md +183 -23
  35. package/resources/gofer/commands/gofer_eai_first_run.md +254 -25
  36. package/resources/gofer/commands/gofer_hydrate.md +183 -23
  37. package/resources/gofer/commands/gofer_personality.md +117 -6
  38. package/resources/gofer/commands/gofer_plan.md +117 -6
  39. package/resources/gofer/commands/gofer_side.md +117 -6
  40. package/resources/gofer/commands/gofer_spec_summary.md +183 -23
  41. package/resources/gofer/commands/gofer_tdd.md +183 -23
  42. package/resources/gofer/commands/gofer_vocabulary.md +185 -25
  43. package/resources/gofer/commands/gofer_zoom_out.md +183 -23
  44. package/resources/gofer/config/typesafe-learning-review.json +16 -0
  45. package/resources/gofer/config/typesafe-semantic-review.json +9 -0
  46. package/resources/gofer/copilot-instructions/gofer-cost.instructions.md +15 -6
  47. package/resources/gofer/copilot-instructions/typescript.instructions.md +1 -1
  48. package/resources/gofer/copilot-prompts/eai-update.prompt.md +58 -0
  49. package/resources/gofer/copilot-prompts/eai.prompt.md +367 -0
  50. package/resources/gofer/gemini/commands/gofer/eai-update.md +22 -0
  51. package/resources/gofer/gemini/commands/gofer/eai-update.toml +2 -0
  52. package/resources/gofer/gemini/commands/gofer/eai.md +357 -0
  53. package/resources/gofer/gemini/commands/gofer/eai.toml +2 -0
  54. package/resources/gofer/gemini/commands/gofer/manifest.json +3 -27
  55. package/resources/gofer/gemini/extension.json +4 -4
  56. package/resources/gofer/github-agents/eai.agent.md +83 -0
  57. package/resources/gofer/github-agents/gofer-business.agent.md +73 -4
  58. package/resources/gofer/github-agents/gofer-implement.agent.md +71 -2
  59. package/resources/gofer/github-agents/gofer-plan.agent.md +72 -2
  60. package/resources/gofer/github-agents/gofer-research.agent.md +72 -2
  61. package/resources/gofer/github-agents/gofer-validate.agent.md +72 -2
  62. package/resources/gofer/github-skills/eai/SKILL.md +365 -0
  63. package/resources/gofer/github-skills/eai-update/SKILL.md +56 -0
  64. package/resources/gofer/github-skills/gofer-documentation/SKILL.md +93 -0
  65. package/resources/gofer/grok-skills/eai/SKILL.md +267 -14
  66. package/resources/gofer/grok-skills/eai-update/SKILL.md +56 -0
  67. package/resources/gofer/hook-scripts/user-prompt-submit.mjs +58 -13
  68. package/resources/gofer/instruction-templates/base/agents-base.md +8 -4
  69. package/resources/gofer/instruction-templates/gofer/gofer-claude.md +7 -5
  70. package/resources/gofer/instruction-templates/gofer/gofer-copilot.md +10 -8
  71. package/resources/gofer/memory/constitution.md +9 -7
  72. package/resources/gofer/memory/gofer-model-policy.yaml +23 -1
  73. package/resources/gofer/memory/lessons.md +0 -31
  74. package/resources/gofer/node-scripts/canonical-descriptions.mjs +1 -1
  75. package/resources/gofer/node-scripts/check-version-alignment.mjs +4 -7
  76. package/resources/gofer/node-scripts/delivery-lineage-corpus.mjs +156 -0
  77. package/resources/gofer/node-scripts/generate-commands.mjs +1073 -265
  78. package/resources/gofer/node-scripts/gofer-acceptance-check.mjs +143 -0
  79. package/resources/gofer/node-scripts/gofer-agent-catalog.mjs +271 -0
  80. package/resources/gofer/node-scripts/gofer-benchmark-executor.mjs +123 -0
  81. package/resources/gofer/node-scripts/gofer-benchmark-sign.mjs +62 -0
  82. package/resources/gofer/node-scripts/gofer-benchmark-signer.mjs +89 -0
  83. package/resources/gofer/node-scripts/gofer-benchmark.mjs +76 -0
  84. package/resources/gofer/node-scripts/gofer-blocker-control.mjs +274 -0
  85. package/resources/gofer/node-scripts/gofer-claude-adapter.mjs +154 -0
  86. package/resources/gofer/node-scripts/gofer-closed-loop-audit.mjs +19 -2
  87. package/resources/gofer/node-scripts/gofer-delivery-check.mjs +121 -0
  88. package/resources/gofer/node-scripts/gofer-encrypted-key.mjs +58 -0
  89. package/resources/gofer/node-scripts/gofer-execution-metrics.mjs +477 -0
  90. package/resources/gofer/node-scripts/gofer-execution-recovery.mjs +334 -0
  91. package/resources/gofer/node-scripts/gofer-grok-adapter.mjs +184 -0
  92. package/resources/gofer/node-scripts/gofer-heldout-corpus.mjs +73 -0
  93. package/resources/gofer/node-scripts/gofer-heldout-snapshot.mjs +286 -0
  94. package/resources/gofer/node-scripts/gofer-heldout-verifier.mjs +211 -0
  95. package/resources/gofer/node-scripts/gofer-host-capability.mjs +335 -0
  96. package/resources/gofer/node-scripts/gofer-independent-reviewer.mjs +130 -0
  97. package/resources/gofer/node-scripts/gofer-live-routing.mjs +109 -0
  98. package/resources/gofer/node-scripts/gofer-local-capability-issuer.mjs +71 -0
  99. package/resources/gofer/node-scripts/gofer-local-isolation.mjs +175 -0
  100. package/resources/gofer/node-scripts/gofer-local-settings-cleanup.mjs +388 -0
  101. package/resources/gofer/node-scripts/gofer-loop-audit.mjs +54 -3
  102. package/resources/gofer/node-scripts/gofer-native-adapter.mjs +567 -0
  103. package/resources/gofer/node-scripts/gofer-native-benchmark-dispatch.mjs +145 -0
  104. package/resources/gofer/node-scripts/gofer-native-runtime.mjs +169 -0
  105. package/resources/gofer/node-scripts/gofer-pre-edit-check.mjs +204 -0
  106. package/resources/gofer/node-scripts/gofer-priority-check.mjs +214 -0
  107. package/resources/gofer/node-scripts/gofer-response-check.mjs +56 -0
  108. package/resources/gofer/node-scripts/gofer-reviewed-learning.mjs +1232 -0
  109. package/resources/gofer/node-scripts/gofer-run-verified-task.mjs +330 -0
  110. package/resources/gofer/node-scripts/gofer-runtime-ledger.mjs +289 -0
  111. package/resources/gofer/node-scripts/gofer-semantic-drift.mjs +584 -0
  112. package/resources/gofer/node-scripts/gofer-surface-update.mjs +1178 -0
  113. package/resources/gofer/node-scripts/gofer-trust-bootstrap.mjs +77 -0
  114. package/resources/gofer/node-scripts/gofer-trusted-benchmark.mjs +102 -0
  115. package/resources/gofer/node-scripts/gofer-trusted-evaluator.mjs +274 -0
  116. package/resources/gofer/node-scripts/gofer-tty-prompt.mjs +34 -0
  117. package/resources/gofer/node-scripts/gofer-typesafe-credentials.mjs +435 -0
  118. package/resources/gofer/node-scripts/gofer-ui-preview.mjs +1212 -0
  119. package/resources/gofer/node-scripts/gofer-verified-execution.mjs +484 -0
  120. package/resources/gofer/node-scripts/gofer-verifier-key-ceremony.mjs +101 -0
  121. package/resources/gofer/node-scripts/gofer-worktree-layout.mjs +32 -0
  122. package/resources/gofer/node-scripts/object-type-routing-phase-bundle.mjs +360 -0
  123. package/resources/gofer/node-scripts/package-agent-plugin.mjs +574 -82
  124. package/resources/gofer/node-scripts/parse-stage-command.mjs +1 -1
  125. package/resources/gofer/node-scripts/render-delivery-lineage.mjs +178 -0
  126. package/resources/gofer/node-scripts/sync-extension-resources.mjs +78 -2
  127. package/resources/gofer/node-scripts/validate-object-type-identifiers.mjs +767 -0
  128. package/resources/gofer/node-scripts/validate-object-type-routing-workspace.mjs +1325 -0
  129. package/resources/gofer/node-scripts/validate-v4-resource-contract.d.mts +44 -0
  130. package/resources/gofer/node-scripts/validate-v4-resource-contract.mjs +957 -0
  131. package/resources/gofer/node-scripts/workspace-bootstrap-lib.mjs +685 -116
  132. package/resources/gofer/references/agent-catalog.json +126 -0
  133. package/resources/gofer/references/blocker-mediation.md +156 -0
  134. package/resources/gofer/references/business-updates-and-goal-checks.md +109 -0
  135. package/resources/gofer/references/delivery-lineage.md +48 -0
  136. package/resources/gofer/references/mvp-capability-validation.md +102 -0
  137. package/resources/gofer/references/platform/README.md +1 -1
  138. package/resources/gofer/references/platform/eai-app-template.md +15 -13
  139. package/resources/gofer/references/platform/eai-auth-access.md +104 -0
  140. package/resources/gofer/references/platform/eai-config-driven-ui.md +5 -5
  141. package/resources/gofer/references/platform/eai-error-catalog.yaml +77 -19
  142. package/resources/gofer/references/platform/eai-repo-contract.md +61 -23
  143. package/resources/gofer/references/platform/eai-service-patterns.md +102 -105
  144. package/resources/gofer/references/platform/eai.md +44 -8
  145. package/resources/gofer/references/platform/vertical-template.md +10 -9
  146. package/resources/gofer/references/priority-outcome-protection.md +152 -0
  147. package/resources/gofer/references/verified-agent-execution.md +179 -0
  148. package/resources/gofer/schemas/gofer-learning-trace-v1.json +70 -0
  149. package/resources/gofer/specify-commands/0_gofer_start.md +440 -99
  150. package/resources/gofer/specify-commands/0a_problem_validation.md +187 -27
  151. package/resources/gofer/specify-commands/10_gofer_cloud.md +183 -23
  152. package/resources/gofer/specify-commands/1_gofer_research.md +239 -30
  153. package/resources/gofer/specify-commands/2_gofer_specify.md +239 -35
  154. package/resources/gofer/specify-commands/3_gofer_plan.md +259 -43
  155. package/resources/gofer/specify-commands/4_gofer_tasks.md +401 -81
  156. package/resources/gofer/specify-commands/5_gofer_implement.md +375 -84
  157. package/resources/gofer/specify-commands/6_gofer_validate.md +284 -53
  158. package/resources/gofer/specify-commands/7_gofer_save.md +187 -26
  159. package/resources/gofer/specify-commands/7a_stakeholder_comms.md +183 -23
  160. package/resources/gofer/specify-commands/8_gofer_branding.md +183 -23
  161. package/resources/gofer/specify-commands/9_gofer_tests.md +212 -23
  162. package/resources/gofer/specify-commands/gofer_bootstrap_workspace.md +121 -8
  163. package/resources/gofer/specify-commands/gofer_check_workspace.md +123 -8
  164. package/resources/gofer/specify-commands/gofer_constitution.md +183 -23
  165. package/resources/gofer/specify-commands/gofer_diagnose.md +183 -23
  166. package/resources/gofer/specify-commands/gofer_eai_first_run.md +254 -25
  167. package/resources/gofer/specify-commands/gofer_hydrate.md +183 -23
  168. package/resources/gofer/specify-commands/gofer_personality.md +117 -6
  169. package/resources/gofer/specify-commands/gofer_plan.md +117 -6
  170. package/resources/gofer/specify-commands/gofer_side.md +117 -6
  171. package/resources/gofer/specify-commands/gofer_spec_summary.md +183 -23
  172. package/resources/gofer/specify-commands/gofer_tdd.md +183 -23
  173. package/resources/gofer/specify-commands/gofer_vocabulary.md +185 -25
  174. package/resources/gofer/specify-commands/gofer_zoom_out.md +183 -23
  175. package/resources/gofer/specify-config/object-type-routing.json +24 -0
  176. package/resources/gofer/specify-config/typesafe-learning-review.json +16 -0
  177. package/resources/gofer/specify-config/typesafe-semantic-review.json +9 -0
  178. package/resources/gofer/system-skills/eai/SKILL.md +365 -0
  179. package/resources/gofer/system-skills/eai-update/SKILL.md +56 -0
  180. package/resources/gofer/system-skills/gofer-documentation/SKILL.md +93 -0
  181. package/resources/gofer/templates/build-map-template.md +64 -0
  182. package/resources/gofer/templates/business-scenarios-template.json +14 -0
  183. package/resources/gofer/templates/ciso-security-summary-template.md +3 -3
  184. package/resources/gofer/templates/context-bundle-template.md +4 -3
  185. package/resources/gofer/templates/contract-pack-template.md +8 -8
  186. package/resources/gofer/templates/cto-architecture-summary-template.md +3 -3
  187. package/resources/gofer/templates/delivery-lineage-template.json +8 -0
  188. package/resources/gofer/templates/eai-preflight-template.md +109 -68
  189. package/resources/gofer/templates/goal-ledger-template.json +1 -1
  190. package/resources/gofer/templates/gofer-model-policy.yaml +28 -6
  191. package/resources/gofer/templates/loop-contract-template.json +3 -1
  192. package/resources/gofer/templates/plan-template.md +8 -7
  193. package/resources/gofer/templates/priority-plan-template.json +29 -0
  194. package/resources/gofer/templates/proposal-review-template.md +6 -3
  195. package/resources/gofer/templates/release-capability-ledger-template.md +24 -0
  196. package/resources/gofer/templates/research-template.md +7 -6
  197. package/resources/gofer/templates/spec-summary-template.md +1 -1
  198. package/resources/gofer/templates/spec-template.md +45 -6
  199. package/resources/gofer/templates/tasks-template.md +12 -3
  200. package/resources/gofer/templates/ui-preview-brief-template.md +55 -5
  201. package/resources/gofer/templates/ui-review-log-template.md +21 -3
  202. package/resources/gofer/templates/ui-show-and-tell-template.md +46 -0
  203. package/resources/gofer/templates/visuals/capability-heatmap-template.md +2 -2
  204. package/resources/gofer/templates/working-backwards-prfaq-template.md +9 -8
  205. package/resources/linked-sources.json +4 -4
  206. package/resources/gofer/agents-skills/0_gofer_start/SKILL.md +0 -1287
  207. package/resources/gofer/agents-skills/0a_problem_validation/SKILL.md +0 -429
  208. package/resources/gofer/agents-skills/10_gofer_cloud/SKILL.md +0 -635
  209. package/resources/gofer/agents-skills/1_gofer_research/SKILL.md +0 -1159
  210. package/resources/gofer/agents-skills/2_gofer_specify/SKILL.md +0 -860
  211. package/resources/gofer/agents-skills/3_gofer_plan/SKILL.md +0 -899
  212. package/resources/gofer/agents-skills/4_gofer_tasks/SKILL.md +0 -760
  213. package/resources/gofer/agents-skills/5_gofer_implement/SKILL.md +0 -944
  214. package/resources/gofer/agents-skills/6_gofer_validate/SKILL.md +0 -2302
  215. package/resources/gofer/agents-skills/7_gofer_save/SKILL.md +0 -423
  216. package/resources/gofer/agents-skills/7a_stakeholder_comms/SKILL.md +0 -508
  217. package/resources/gofer/agents-skills/8_gofer_branding/SKILL.md +0 -315
  218. package/resources/gofer/agents-skills/9_gofer_tests/SKILL.md +0 -558
  219. package/resources/gofer/agents-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  220. package/resources/gofer/agents-skills/gofer_check_workspace/SKILL.md +0 -119
  221. package/resources/gofer/agents-skills/gofer_constitution/SKILL.md +0 -612
  222. package/resources/gofer/agents-skills/gofer_diagnose/SKILL.md +0 -114
  223. package/resources/gofer/agents-skills/gofer_eai_first_run/SKILL.md +0 -397
  224. package/resources/gofer/agents-skills/gofer_hydrate/SKILL.md +0 -561
  225. package/resources/gofer/agents-skills/gofer_personality/SKILL.md +0 -44
  226. package/resources/gofer/agents-skills/gofer_plan/SKILL.md +0 -40
  227. package/resources/gofer/agents-skills/gofer_side/SKILL.md +0 -45
  228. package/resources/gofer/agents-skills/gofer_spec_summary/SKILL.md +0 -112
  229. package/resources/gofer/agents-skills/gofer_tdd/SKILL.md +0 -112
  230. package/resources/gofer/agents-skills/gofer_vocabulary/SKILL.md +0 -112
  231. package/resources/gofer/agents-skills/gofer_zoom_out/SKILL.md +0 -112
  232. package/resources/gofer/claude-commands/0_gofer_start.md +0 -1282
  233. package/resources/gofer/claude-commands/0a_problem_validation.md +0 -424
  234. package/resources/gofer/claude-commands/10_gofer_cloud.md +0 -630
  235. package/resources/gofer/claude-commands/1_gofer_research.md +0 -1154
  236. package/resources/gofer/claude-commands/2_gofer_specify.md +0 -855
  237. package/resources/gofer/claude-commands/3_gofer_plan.md +0 -894
  238. package/resources/gofer/claude-commands/4_gofer_tasks.md +0 -755
  239. package/resources/gofer/claude-commands/5_gofer_implement.md +0 -939
  240. package/resources/gofer/claude-commands/6_gofer_validate.md +0 -2297
  241. package/resources/gofer/claude-commands/7_gofer_save.md +0 -418
  242. package/resources/gofer/claude-commands/7a_stakeholder_comms.md +0 -503
  243. package/resources/gofer/claude-commands/8_gofer_branding.md +0 -310
  244. package/resources/gofer/claude-commands/9_gofer_tests.md +0 -553
  245. package/resources/gofer/claude-commands/gofer_bootstrap_workspace.md +0 -143
  246. package/resources/gofer/claude-commands/gofer_check_workspace.md +0 -114
  247. package/resources/gofer/claude-commands/gofer_constitution.md +0 -607
  248. package/resources/gofer/claude-commands/gofer_diagnose.md +0 -109
  249. package/resources/gofer/claude-commands/gofer_eai_first_run.md +0 -392
  250. package/resources/gofer/claude-commands/gofer_hydrate.md +0 -556
  251. package/resources/gofer/claude-commands/gofer_personality.md +0 -39
  252. package/resources/gofer/claude-commands/gofer_plan.md +0 -35
  253. package/resources/gofer/claude-commands/gofer_side.md +0 -40
  254. package/resources/gofer/claude-commands/gofer_spec_summary.md +0 -107
  255. package/resources/gofer/claude-commands/gofer_tdd.md +0 -107
  256. package/resources/gofer/claude-commands/gofer_vocabulary.md +0 -107
  257. package/resources/gofer/claude-commands/gofer_zoom_out.md +0 -107
  258. package/resources/gofer/claude-skills/eai-gofer/SKILL.md +0 -56
  259. package/resources/gofer/copilot-prompts/0_gofer_start.prompt.md +0 -1308
  260. package/resources/gofer/copilot-prompts/0a_problem_validation.prompt.md +0 -429
  261. package/resources/gofer/copilot-prompts/10_gofer_cloud.prompt.md +0 -644
  262. package/resources/gofer/copilot-prompts/1_gofer_research.prompt.md +0 -1177
  263. package/resources/gofer/copilot-prompts/2_gofer_specify.prompt.md +0 -878
  264. package/resources/gofer/copilot-prompts/3_gofer_plan.prompt.md +0 -917
  265. package/resources/gofer/copilot-prompts/4_gofer_tasks.prompt.md +0 -778
  266. package/resources/gofer/copilot-prompts/5_gofer_implement.prompt.md +0 -962
  267. package/resources/gofer/copilot-prompts/6_gofer_validate.prompt.md +0 -2310
  268. package/resources/gofer/copilot-prompts/7_gofer_save.prompt.md +0 -433
  269. package/resources/gofer/copilot-prompts/7a_stakeholder_comms.prompt.md +0 -516
  270. package/resources/gofer/copilot-prompts/8_gofer_branding.prompt.md +0 -323
  271. package/resources/gofer/copilot-prompts/9_gofer_tests.prompt.md +0 -566
  272. package/resources/gofer/copilot-prompts/gofer_bootstrap_workspace.prompt.md +0 -161
  273. package/resources/gofer/copilot-prompts/gofer_check_workspace.prompt.md +0 -132
  274. package/resources/gofer/copilot-prompts/gofer_constitution.prompt.md +0 -621
  275. package/resources/gofer/copilot-prompts/gofer_diagnose.prompt.md +0 -127
  276. package/resources/gofer/copilot-prompts/gofer_eai_first_run.prompt.md +0 -410
  277. package/resources/gofer/copilot-prompts/gofer_hydrate.prompt.md +0 -571
  278. package/resources/gofer/copilot-prompts/gofer_personality.prompt.md +0 -57
  279. package/resources/gofer/copilot-prompts/gofer_plan.prompt.md +0 -53
  280. package/resources/gofer/copilot-prompts/gofer_side.prompt.md +0 -58
  281. package/resources/gofer/copilot-prompts/gofer_spec_summary.prompt.md +0 -125
  282. package/resources/gofer/copilot-prompts/gofer_tdd.prompt.md +0 -125
  283. package/resources/gofer/copilot-prompts/gofer_vocabulary.prompt.md +0 -125
  284. package/resources/gofer/copilot-prompts/gofer_zoom_out.prompt.md +0 -125
  285. package/resources/gofer/gemini/commands/gofer/0_gofer_start.md +0 -1282
  286. package/resources/gofer/gemini/commands/gofer/0_gofer_start.toml +0 -2
  287. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.md +0 -424
  288. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.toml +0 -2
  289. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.md +0 -630
  290. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.toml +0 -2
  291. package/resources/gofer/gemini/commands/gofer/1_gofer_research.md +0 -1154
  292. package/resources/gofer/gemini/commands/gofer/1_gofer_research.toml +0 -2
  293. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.md +0 -855
  294. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.toml +0 -2
  295. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.md +0 -894
  296. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.toml +0 -2
  297. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.md +0 -755
  298. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.toml +0 -2
  299. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.md +0 -939
  300. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.toml +0 -2
  301. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.md +0 -2297
  302. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.toml +0 -2
  303. package/resources/gofer/gemini/commands/gofer/7_gofer_save.md +0 -418
  304. package/resources/gofer/gemini/commands/gofer/7_gofer_save.toml +0 -2
  305. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.md +0 -503
  306. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.toml +0 -2
  307. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.md +0 -310
  308. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.toml +0 -2
  309. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.md +0 -553
  310. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.toml +0 -2
  311. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.md +0 -143
  312. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.toml +0 -2
  313. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.md +0 -114
  314. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.toml +0 -2
  315. package/resources/gofer/gemini/commands/gofer/gofer_constitution.md +0 -607
  316. package/resources/gofer/gemini/commands/gofer/gofer_constitution.toml +0 -2
  317. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.md +0 -109
  318. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.toml +0 -2
  319. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.md +0 -392
  320. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.toml +0 -2
  321. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.md +0 -556
  322. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.toml +0 -2
  323. package/resources/gofer/gemini/commands/gofer/gofer_personality.md +0 -39
  324. package/resources/gofer/gemini/commands/gofer/gofer_personality.toml +0 -2
  325. package/resources/gofer/gemini/commands/gofer/gofer_plan.md +0 -35
  326. package/resources/gofer/gemini/commands/gofer/gofer_plan.toml +0 -2
  327. package/resources/gofer/gemini/commands/gofer/gofer_side.md +0 -40
  328. package/resources/gofer/gemini/commands/gofer/gofer_side.toml +0 -2
  329. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.md +0 -107
  330. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.toml +0 -2
  331. package/resources/gofer/gemini/commands/gofer/gofer_tdd.md +0 -107
  332. package/resources/gofer/gemini/commands/gofer/gofer_tdd.toml +0 -2
  333. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.md +0 -107
  334. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.toml +0 -2
  335. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.md +0 -107
  336. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.toml +0 -2
  337. package/resources/gofer/github-skills/eai-gofer/SKILL.md +0 -56
  338. package/resources/gofer/system-skills/0_gofer_start/SKILL.md +0 -1287
  339. package/resources/gofer/system-skills/0a_problem_validation/SKILL.md +0 -429
  340. package/resources/gofer/system-skills/10_gofer_cloud/SKILL.md +0 -635
  341. package/resources/gofer/system-skills/1_gofer_research/SKILL.md +0 -1159
  342. package/resources/gofer/system-skills/2_gofer_specify/SKILL.md +0 -860
  343. package/resources/gofer/system-skills/3_gofer_plan/SKILL.md +0 -899
  344. package/resources/gofer/system-skills/4_gofer_tasks/SKILL.md +0 -760
  345. package/resources/gofer/system-skills/5_gofer_implement/SKILL.md +0 -944
  346. package/resources/gofer/system-skills/6_gofer_validate/SKILL.md +0 -2302
  347. package/resources/gofer/system-skills/7_gofer_save/SKILL.md +0 -423
  348. package/resources/gofer/system-skills/7a_stakeholder_comms/SKILL.md +0 -508
  349. package/resources/gofer/system-skills/8_gofer_branding/SKILL.md +0 -315
  350. package/resources/gofer/system-skills/9_gofer_tests/SKILL.md +0 -558
  351. package/resources/gofer/system-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  352. package/resources/gofer/system-skills/gofer_check_workspace/SKILL.md +0 -119
  353. package/resources/gofer/system-skills/gofer_constitution/SKILL.md +0 -612
  354. package/resources/gofer/system-skills/gofer_diagnose/SKILL.md +0 -114
  355. package/resources/gofer/system-skills/gofer_eai_first_run/SKILL.md +0 -397
  356. package/resources/gofer/system-skills/gofer_hydrate/SKILL.md +0 -561
  357. package/resources/gofer/system-skills/gofer_personality/SKILL.md +0 -44
  358. package/resources/gofer/system-skills/gofer_plan/SKILL.md +0 -40
  359. package/resources/gofer/system-skills/gofer_side/SKILL.md +0 -45
  360. package/resources/gofer/system-skills/gofer_spec_summary/SKILL.md +0 -112
  361. package/resources/gofer/system-skills/gofer_tdd/SKILL.md +0 -112
  362. package/resources/gofer/system-skills/gofer_vocabulary/SKILL.md +0 -112
  363. package/resources/gofer/system-skills/gofer_zoom_out/SKILL.md +0 -112
  364. package/resources/gofer/templates/ui-approval-template.md +0 -32
@@ -0,0 +1,334 @@
1
+ import { open, realpath, unlink } from 'node:fs/promises';
2
+ import { constants } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { createHash } from 'node:crypto';
5
+ import { executionRevision } from './gofer-verified-execution.mjs';
6
+
7
+ const LIMIT = 8 * 1024 * 1024;
8
+ const taskId = value => typeof value === 'string' && /^T\d+$/.test(value);
9
+ const text = value => typeof value === 'string' && value.length > 0;
10
+
11
+ async function readJournal(root) {
12
+ const file = await open(path.join(root, 'verified-execution.jsonl'), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
13
+ try {
14
+ const stat = await file.stat();
15
+ if (!stat.isFile() || stat.size > LIMIT) throw new Error('INVALID_RECOVERY_JOURNAL');
16
+ const chunks = [];
17
+ let total = 0;
18
+ while (true) {
19
+ const buffer = Buffer.alloc(Math.min(65536, LIMIT - total + 1));
20
+ const { bytesRead } = await file.read(buffer);
21
+ if (!bytesRead) break;
22
+ total += bytesRead;
23
+ if (total > LIMIT) throw new Error('RECOVERY_JOURNAL_LIMIT');
24
+ chunks.push(buffer.subarray(0, bytesRead));
25
+ }
26
+ return Buffer.concat(chunks).toString('utf8');
27
+ } finally { await file.close(); }
28
+ }
29
+
30
+ /** Read-only reconciliation. This never clears a journal or replays a side effect. */
31
+ export async function inspectExecutionRecovery({ featureDir, verifyReceipt, verifyCancellation, inspectWorkers, inspectLedger, timeoutMs = 2000 }) {
32
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 10000) throw new Error('INVALID_INSPECTION_LIMIT');
33
+ let inspectionDeadline = Date.now() + timeoutMs;
34
+ let inspectionTimedOut = false;
35
+ const bounded = async callback => {
36
+ if (inspectionTimedOut || Date.now() >= inspectionDeadline) throw new Error('INSPECTION_TIMEOUT');
37
+ let timer;
38
+ try { return await Promise.race([
39
+ Promise.resolve().then(() => { if (inspectionTimedOut || Date.now() >= inspectionDeadline) throw new Error('INSPECTION_TIMEOUT'); return callback(); }),
40
+ new Promise((_, reject) => { timer = setTimeout(() => { inspectionTimedOut = true; reject(new Error('INSPECTION_TIMEOUT')); }, Math.max(0, inspectionDeadline - Date.now())); }),
41
+ ]); } finally { clearTimeout(timer); }
42
+ };
43
+ const root = await realpath(featureDir);
44
+ const raw = await readJournal(root);
45
+ const journalHash = createHash('sha256').update(raw).digest('hex');
46
+ const report = { status: 'blocked', journalHash, resumeAllowed: false, replayAllowed: false,
47
+ reusableTasks: [], restartableTasks: [], verifiedInputs: {}, uncertainTasks: [], callsConsumed: 0, attemptsConsumed: {}, reasons: [],
48
+ coverage: 'Read-only reconciliation; trusted receipt and worker inspection are required. No automatic replay.' };
49
+ const reasons = report.reasons;
50
+ if (!raw.endsWith('\n')) { reasons.push('TRUNCATED_JOURNAL'); return report; }
51
+ let events;
52
+ try { events = raw.trimEnd().split('\n').map(line => JSON.parse(line)); }
53
+ catch { reasons.push('INVALID_JOURNAL_JSON'); return report; }
54
+ const first = events[0];
55
+ if (events.length > 50000 || first?.event !== 'started' || first.schemaVersion !== 1 ||
56
+ !text(first.revision) || !Number.isSafeInteger(first.maxCalls) || first.maxCalls <= 0 ||
57
+ !Number.isFinite(first.deadlineMs) || !Number.isInteger(first.maxConcurrent) || first.maxConcurrent < 1 || first.maxConcurrent > 8 ||
58
+ !Number.isSafeInteger(first.maxIterations) || first.maxIterations < 1 || !first.requiredChecks ||
59
+ typeof first.requiredChecks !== 'object' || Array.isArray(first.requiredChecks) ||
60
+ !Object.keys(first.requiredChecks).length || Object.keys(first.requiredChecks).length > 1000 || Object.entries(first.requiredChecks).some(([task, checks]) =>
61
+ !taskId(task) || !Array.isArray(checks) || !checks.length || checks.length > 256 || checks.some(c => !text(c)) || new Set(checks).size !== checks.length)) {
62
+ reasons.push('INVALID_RUN_HEADER'); return report;
63
+ }
64
+ inspectionDeadline = Math.min(inspectionDeadline, first.deadlineMs);
65
+ report.run = { revision: first.revision, maxCalls: first.maxCalls, maxConcurrent: first.maxConcurrent,
66
+ maxIterations: first.maxIterations, deadlineMs: first.deadlineMs, requiredChecks: first.requiredChecks,
67
+ capabilityReceiptHash: first.capabilityReceiptHash, selectedModel: first.selectedModel,
68
+ benchmarkReceipt: first.benchmarkReceipt, approvalReceipt: first.approvalReceipt };
69
+ if (await executionRevision(root) !== first.revision) reasons.push('STALE_DIRECTION');
70
+ if (Date.now() >= first.deadlineMs) reasons.push('DEADLINE_EXHAUSTED');
71
+ const uncertain = new Set();
72
+ const receipts = new Map();
73
+ const latestChecks = new Map();
74
+ const authorizations = [];
75
+ const commits = [];
76
+ const authorizedTasks = new Map();
77
+ const commitAuthorities = new Map();
78
+ const cancellations = new Map();
79
+ const active = new Set();
80
+ const methods = new Set(['reserve', 'lease', 'execute', 'inputRevision', 'check', 'verified']);
81
+ const known = new Set(['started', 'resumed', 'attempt_reserved', 'call_reserved', 'lease_granted', 'ledger_authorized', 'check', 'commit_authorized', 'verified', 'repair_required', 'blocked', 'cancelled', 'cancel_reconciled', 'stale', 'finished']);
82
+ let finished = false;
83
+ for (const [index, event] of events.entries()) {
84
+ if (!event || event.schemaVersion !== 1 || event.revision !== first.revision || !known.has(event.event) ||
85
+ (index > 0 && event.event === 'started') || (finished && !['resumed', 'cancel_reconciled'].includes(event.event)) ||
86
+ (!['started', 'finished', 'resumed'].includes(event.event) && !taskId(event.task))) {
87
+ reasons.push('INVALID_JOURNAL_SEQUENCE'); break;
88
+ }
89
+ if (event.event === 'resumed') {
90
+ const prefix = events.slice(0, index).map(record => `${JSON.stringify(record)}\n`).join('');
91
+ const expectedHash = createHash('sha256').update(prefix).digest('hex');
92
+ if (!receipts.size && !cancellations.size || event.previousJournalHash !== expectedHash ||
93
+ event.callsConsumed !== report.callsConsumed ||
94
+ JSON.stringify(event.attemptsConsumed) !== JSON.stringify(report.attemptsConsumed) ||
95
+ [...uncertain].some(task => !receipts.has(task) && !cancellations.has(task))) {
96
+ reasons.push('INVALID_RESUME_HISTORY'); break;
97
+ }
98
+ finished = false;
99
+ continue;
100
+ }
101
+ if (event.event === 'cancel_reconciled') {
102
+ const prefix = events.slice(0, index).map(record => `${JSON.stringify(record)}\n`).join('');
103
+ const expectedHash = createHash('sha256').update(prefix).digest('hex');
104
+ const prior = authorizedTasks.get(event.task);
105
+ const cancelled = events.slice(0, index).reverse().find(record => record.task === event.task && record.event === 'cancelled');
106
+ if (!prior || !cancelled || receipts.has(event.task) || cancellations.has(event.task) ||
107
+ event.journalHash !== expectedHash || event.attempt !== report.attemptsConsumed[event.task] ||
108
+ event.leaseId !== prior.leaseId || event.abandonedWorktreeReceipt !== prior.worktreeReceipt ||
109
+ !text(event.replacementWorktreeReceipt) || event.replacementWorktreeReceipt === event.abandonedWorktreeReceipt ||
110
+ !text(event.workerStopReceipt) || !text(event.receipt) || !text(event.inputRevision)) {
111
+ reasons.push('INVALID_CANCELLATION_RECONCILIATION'); break;
112
+ }
113
+ cancellations.set(event.task, event);
114
+ continue;
115
+ }
116
+ const verifiedRead = receipts.has(event.task) && event.event === 'call_reserved' && event.method === 'inputRevision';
117
+ if (event.task && !verifiedRead) uncertain.add(event.task);
118
+ if (event.task && (!Object.hasOwn(first.requiredChecks, event.task) || (receipts.has(event.task) && !verifiedRead))) {
119
+ receipts.delete(event.task); reasons.push('INVALID_LATE_OR_UNKNOWN_TASK'); break;
120
+ }
121
+ if (event.event === 'attempt_reserved') {
122
+ const expected = (report.attemptsConsumed[event.task] || 0) + 1;
123
+ if (event.attempt !== expected || expected > first.maxIterations) { reasons.push('INVALID_ATTEMPT_HISTORY'); break; }
124
+ report.attemptsConsumed[event.task] = expected;
125
+ latestChecks.set(event.task, new Map());
126
+ active.delete(event.task);
127
+ }
128
+ if (event.event === 'call_reserved') {
129
+ if (event.call !== report.callsConsumed + 1 || !methods.has(event.method) ||
130
+ event.call > first.maxCalls) { reasons.push('INVALID_CALL_HISTORY'); break; }
131
+ report.callsConsumed = event.call;
132
+ if (!report.attemptsConsumed[event.task]) { reasons.push('INVALID_CALL_WITHOUT_ATTEMPT'); break; }
133
+ if (event.method === 'execute') active.add(event.task);
134
+ if (active.size > first.maxConcurrent) { reasons.push('INVALID_CONCURRENCY_HISTORY'); break; }
135
+ }
136
+ if (event.event === 'lease_granted' && (!report.attemptsConsumed[event.task] || !text(event.leaseId) || !text(event.expiresAt))) {
137
+ reasons.push('INVALID_LEASE_HISTORY'); break;
138
+ }
139
+ if (event.event === 'ledger_authorized') {
140
+ if (!report.attemptsConsumed[event.task] || !text(event.leaseId) || !text(event.receipt) ||
141
+ !text(event.capabilityReceiptHash)) { reasons.push('INVALID_LEDGER_AUTHORIZATION'); break; }
142
+ authorizations.push({ taskId: event.task, leaseId: event.leaseId, receipt: event.receipt,
143
+ capabilityReceiptHash: event.capabilityReceiptHash, worktreeReceipt: event.worktreeReceipt });
144
+ authorizedTasks.set(event.task, event);
145
+ }
146
+ if (event.event === 'check') {
147
+ if (!active.has(event.task) || event.attempt !== report.attemptsConsumed[event.task] ||
148
+ !first.requiredChecks[event.task].includes(event.check)) { reasons.push('INVALID_CHECK_HISTORY'); break; }
149
+ latestChecks.get(event.task).set(event.check, event);
150
+ }
151
+ if (event.event === 'verified') {
152
+ if (!active.has(event.task) || !text(event.inputRevision) || !text(event.receipt) || receipts.has(event.task) ||
153
+ !authorizedTasks.has(event.task) || commitAuthorities.get(event.task)?.inputRevision !== event.inputRevision ||
154
+ first.requiredChecks[event.task].some(check => {
155
+ const proof = latestChecks.get(event.task)?.get(check);
156
+ return proof?.passed !== true || proof.inputRevision !== event.inputRevision || !text(proof.receipt);
157
+ })) {
158
+ reasons.push('INVALID_VERIFICATION_RECORD'); break;
159
+ }
160
+ receipts.set(event.task, event);
161
+ active.delete(event.task);
162
+ }
163
+ if (event.event === 'commit_authorized') {
164
+ const authority = authorizedTasks.get(event.task);
165
+ if (!active.has(event.task) || !authority || !text(event.leaseId) ||
166
+ !text(event.receipt) || !text(event.inputRevision) ||
167
+ !text(event.capabilityReceiptHash) ||
168
+ event.attempt !== authority.attempt || event.leaseId !== authority.leaseId ||
169
+ event.capabilityReceiptHash !== authority.capabilityReceiptHash ||
170
+ commitAuthorities.get(event.task)?.attempt === event.attempt ||
171
+ first.requiredChecks[event.task].some(check => {
172
+ const proof = latestChecks.get(event.task)?.get(check);
173
+ return proof?.passed !== true || proof.inputRevision !== event.inputRevision || !text(proof.receipt);
174
+ })) {
175
+ reasons.push('INVALID_COMMIT_AUTHORIZATION'); break;
176
+ }
177
+ commits.push({ taskId: event.task, leaseId: event.leaseId, receipt: event.receipt,
178
+ inputRevision: event.inputRevision, capabilityReceiptHash: event.capabilityReceiptHash });
179
+ commitAuthorities.set(event.task, event);
180
+ }
181
+ if (['blocked', 'cancelled', 'stale', 'repair_required'].includes(event.event)) active.delete(event.task);
182
+ if (event.event === 'finished') {
183
+ finished = true;
184
+ if (event.adapterCallsSettled === false) reasons.push('ADAPTER_CALLS_NOT_SETTLED');
185
+ }
186
+ }
187
+ if (report.callsConsumed >= first.maxCalls) reasons.push('CALL_LIMIT_EXHAUSTED');
188
+ if (reasons.some(reason => /^(INVALID|STALE)/.test(reason))) {
189
+ report.uncertainTasks = [...uncertain]; return report;
190
+ }
191
+ if (uncertain.size === 1 && events.at(-1)?.event === 'finished' && events.at(-1)?.adapterCallsSettled === true) {
192
+ const task = [...uncertain][0];
193
+ const authority = authorizedTasks.get(task);
194
+ const cancelled = events.findLast(event => event.task === task && event.event === 'cancelled');
195
+ if (authority && cancelled && !cancellations.has(task) && !receipts.has(task) &&
196
+ authority.attempt === report.attemptsConsumed[task] && text(authority.worktreeReceipt) &&
197
+ text(authority.budgetReservation) && !commits.some(item => item.taskId === task && item.leaseId === authority.leaseId)) {
198
+ report.pendingCancellation = { taskId: task, revision: first.revision, attempt: authority.attempt,
199
+ leaseId: authority.leaseId, abandonedWorktreeReceipt: authority.worktreeReceipt,
200
+ budgetReservation: authority.budgetReservation, capabilityReceiptHash: authority.capabilityReceiptHash,
201
+ approvalReceipt: first.approvalReceipt };
202
+ }
203
+ }
204
+ // A journal proves recorded actions, not whether a local or remote worker is gone.
205
+ if (typeof inspectWorkers !== 'function') reasons.push('WORKER_INSPECTION_REQUIRED');
206
+ else {
207
+ try {
208
+ const workers = await bounded(() => inspectWorkers({ revision: first.revision, journalHash,
209
+ authorizations: structuredClone(authorizations) }));
210
+ if (workers?.allStopped !== true || workers.revision !== first.revision ||
211
+ workers.journalHash !== journalHash || !text(workers.receipt)) reasons.push('WORKERS_NOT_RECONCILED');
212
+ else report.workerStopReceipt = workers.receipt;
213
+ } catch { reasons.push('WORKER_INSPECTION_FAILED'); }
214
+ }
215
+ if (typeof verifyReceipt !== 'function') reasons.push('RECEIPT_VERIFIER_REQUIRED');
216
+ if (cancellations.size && typeof verifyCancellation !== 'function') reasons.push('CANCELLATION_VERIFIER_REQUIRED');
217
+ if (typeof inspectLedger !== 'function') reasons.push('LEDGER_INSPECTION_REQUIRED');
218
+ else {
219
+ try {
220
+ const result = await bounded(() => inspectLedger({ revision: first.revision, journalHash,
221
+ authorizations: structuredClone(authorizations), commits: structuredClone(commits) }));
222
+ if (result?.allowed !== true || result.revision !== first.revision || result.journalHash !== journalHash) {
223
+ reasons.push('LEDGER_NOT_RECONCILED');
224
+ }
225
+ } catch { reasons.push('LEDGER_INSPECTION_FAILED'); }
226
+ }
227
+ if (!reasons.length) {
228
+ for (const [task, event] of receipts) {
229
+ if (inspectionTimedOut || Date.now() >= inspectionDeadline) { reasons.push('INSPECTION_DEADLINE_EXHAUSTED'); break; }
230
+ try {
231
+ const result = await bounded(() => verifyReceipt({ taskId: task, revision: first.revision,
232
+ inputRevision: event.inputRevision, receipt: event.receipt, journalHash }));
233
+ if (result?.valid !== true || result.taskId !== task || result.revision !== first.revision ||
234
+ result.inputRevision !== event.inputRevision || result.receipt !== event.receipt || result.journalHash !== journalHash) throw new Error('UNVERIFIED');
235
+ report.reusableTasks.push(task); uncertain.delete(task);
236
+ report.verifiedInputs[task] = event.inputRevision;
237
+ } catch { reasons.push(`RECEIPT_NOT_VERIFIED:${task}`); }
238
+ }
239
+ }
240
+ if (!reasons.length) {
241
+ for (const [task, event] of cancellations) {
242
+ if (inspectionTimedOut || Date.now() >= inspectionDeadline) { reasons.push('INSPECTION_DEADLINE_EXHAUSTED'); break; }
243
+ try {
244
+ const request = { taskId: task, revision: first.revision, leaseId: event.leaseId,
245
+ attempt: event.attempt, journalHash: event.journalHash, receipt: event.receipt,
246
+ workerStopReceipt: event.workerStopReceipt, abandonedWorktreeReceipt: event.abandonedWorktreeReceipt,
247
+ replacementWorktreeReceipt: event.replacementWorktreeReceipt, inputRevision: event.inputRevision };
248
+ const result = await bounded(() => verifyCancellation(structuredClone(request)));
249
+ if (result?.valid !== true || Object.entries(request).some(([key, value]) => result[key] !== value)) throw new Error('UNVERIFIED');
250
+ report.restartableTasks.push(task);
251
+ uncertain.delete(task);
252
+ report.replacementWorktreeReceipt = event.replacementWorktreeReceipt;
253
+ } catch { reasons.push(`CANCELLATION_NOT_VERIFIED:${task}`); }
254
+ }
255
+ }
256
+ // Detect new journal events or direction changes during asynchronous proof inspection.
257
+ const directionStillMatches = await executionRevision(root) === first.revision;
258
+ if (!directionStillMatches || createHash('sha256').update(await readJournal(root)).digest('hex') !== journalHash) {
259
+ reasons.push('RECOVERY_INPUT_CHANGED');
260
+ for (const task of report.reusableTasks) uncertain.add(task);
261
+ report.reusableTasks = [];
262
+ report.restartableTasks = [];
263
+ report.verifiedInputs = {};
264
+ }
265
+ if (inspectionTimedOut || Date.now() >= inspectionDeadline) {
266
+ reasons.push('INSPECTION_DEADLINE_EXHAUSTED');
267
+ for (const task of report.reusableTasks) uncertain.add(task);
268
+ report.reusableTasks = [];
269
+ report.restartableTasks = [];
270
+ report.verifiedInputs = {};
271
+ }
272
+ report.uncertainTasks = [...uncertain];
273
+ if (uncertain.size) reasons.push('SIDE_EFFECT_RECONCILIATION_REQUIRED');
274
+ if (!reasons.length) {
275
+ report.status = 'reconciled';
276
+ report.resumeAllowed = report.reusableTasks.length > 0 || report.restartableTasks.length > 0;
277
+ }
278
+ return report;
279
+ }
280
+
281
+ /** Retire one cancelled lease and journal a fresh-worktree restart boundary. */
282
+ export async function reconcileCancelledExecution({ featureDir, workspaceRoot, abandonedWorkspace,
283
+ replacementWorkspace, worktreeRevision, replacementWorktreeReceipt, inputRevision,
284
+ ledger, inspectWorkers, verifyReceipt, timeoutMs = 2000 } = {}) {
285
+ if (!ledger || typeof ledger.reconcileCancelledLease !== 'function' ||
286
+ typeof ledger.readCancellation !== 'function' || typeof ledger.inspectRecovery !== 'function' ||
287
+ ![workspaceRoot, abandonedWorkspace,
288
+ replacementWorkspace, worktreeRevision, replacementWorktreeReceipt, inputRevision].every(text)) {
289
+ throw new Error('CANCELLATION_RECONCILIATION_INPUT_REQUIRED');
290
+ }
291
+ const root = await realpath(featureDir);
292
+ const lock = await open(path.join(root, 'verified-execution.resume.lock'), 'wx', 0o600)
293
+ .catch(() => { throw new Error('RESUME_LOCKED'); });
294
+ try {
295
+ const report = await inspectExecutionRecovery({ featureDir: root, inspectWorkers,
296
+ inspectLedger: request => ledger.inspectRecovery(request),
297
+ verifyReceipt, timeoutMs });
298
+ if (report.status !== 'blocked' || !report.pendingCancellation ||
299
+ report.reasons.length !== 1 || report.reasons[0] !== 'SIDE_EFFECT_RECONCILIATION_REQUIRED' ||
300
+ !text(report.workerStopReceipt) || report.attemptsConsumed[report.pendingCancellation.taskId] >= report.run.maxIterations) {
301
+ throw new Error('CANCELLATION_RECONCILIATION_REQUIRED');
302
+ }
303
+ const { inspectVerifiedWorktree } = await import('./gofer-native-adapter.mjs');
304
+ const [oldWorktree, replacementWorktree] = await Promise.all([
305
+ inspectVerifiedWorktree({ workspaceRoot, isolatedWorkspace: abandonedWorkspace,
306
+ revision: worktreeRevision, receipt: report.pendingCancellation.abandonedWorktreeReceipt }),
307
+ inspectVerifiedWorktree({ workspaceRoot, isolatedWorkspace: replacementWorkspace,
308
+ revision: worktreeRevision, receipt: replacementWorktreeReceipt, requireClean: true }),
309
+ ]);
310
+ if (oldWorktree.valid !== true || replacementWorktree.valid !== true ||
311
+ oldWorktree.isolatedWorkspace === replacementWorktree.isolatedWorkspace ||
312
+ oldWorktree.receipt === replacementWorktree.receipt) throw new Error('REPLACEMENT_WORKTREE_UNVERIFIED');
313
+ const request = { ...report.pendingCancellation, journalHash: report.journalHash,
314
+ workerStopReceipt: report.workerStopReceipt, replacementWorktreeReceipt, inputRevision };
315
+ const existing = await ledger.readCancellation(request);
316
+ const result = existing.found === true && JSON.stringify(existing.request) === JSON.stringify(request)
317
+ ? { allowed: true, receipt: existing.receipt }
318
+ : await ledger.reconcileCancelledLease(request);
319
+ if (result?.allowed !== true || !text(result.receipt)) throw new Error('LEDGER_CANCELLATION_DENIED');
320
+ if (createHash('sha256').update(await readJournal(root)).digest('hex') !== report.journalHash) {
321
+ throw new Error('RECOVERY_INPUT_CHANGED');
322
+ }
323
+ const event = { schemaVersion: 1, revision: report.run.revision, event: 'cancel_reconciled',
324
+ task: request.taskId, attempt: request.attempt, leaseId: request.leaseId,
325
+ journalHash: request.journalHash, workerStopReceipt: request.workerStopReceipt,
326
+ abandonedWorktreeReceipt: request.abandonedWorktreeReceipt,
327
+ replacementWorktreeReceipt: request.replacementWorktreeReceipt,
328
+ inputRevision: request.inputRevision, receipt: result.receipt };
329
+ const file = await open(path.join(root, 'verified-execution.jsonl'), constants.O_WRONLY | constants.O_APPEND | constants.O_NOFOLLOW);
330
+ try { await file.writeFile(`${JSON.stringify(event)}\n`); await file.sync(); } finally { await file.close(); }
331
+ return { reconciled: true, taskId: request.taskId, receipt: result.receipt,
332
+ replacementWorktreeReceipt, journalHash: request.journalHash };
333
+ } finally { await lock.close(); await unlink(path.join(root, 'verified-execution.resume.lock')).catch(() => {}); }
334
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Grok Build host profile for the shared native launcher. It reuses the same
3
+ * process-group evidence, Git baseline and scope checks as the Codex launcher.
4
+ *
5
+ * Isolation is Grok's own OS sandbox (Seatbelt on macOS), driven by a per-task
6
+ * profile. What live tests found, and what this adapter therefore does:
7
+ *
8
+ * - Grok's built-in `strict` profile still allows writes to the OS temp
9
+ * folder, where Gofer worktrees normally live. This adapter denies the
10
+ * temp folders and so REFUSES a worktree or shared Git store inside them.
11
+ * Keep Grok worktrees under another root, for example under your home folder.
12
+ * - An unknown profile, or one that cannot be applied, only prints a warning
13
+ * and runs UNSANDBOXED. The adapter kills the process the moment that
14
+ * warning appears and rejects the run. Unknown profile keys are silently
15
+ * ignored, so only `extends` and `deny`, which were verified live, are used.
16
+ * - The profile name is random per run, and the profile file is written into
17
+ * the worktree before start and removed after exit.
18
+ * - A worker can READ `~/.grok/auth.json`. It cannot be hidden, because Grok
19
+ * itself cannot start without it. It cannot WRITE anywhere in `~/.grok`.
20
+ *
21
+ * Grok has no spend flag, so cost is bounded by `--max-turns` here and by the
22
+ * caller's spend cap. There is no model catalogue use and no capability
23
+ * receipt in this adapter, and the EAI CLI does not qualify Grok, so this does
24
+ * not by itself pass the EAI isolation gate. See docs/verified-autonomous-runtime.md.
25
+ */
26
+ import { execFileSync, spawnSync } from 'node:child_process';
27
+ import { randomUUID } from 'node:crypto';
28
+ import { constants, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, closeSync,
29
+ realpathSync, rmSync, rmdirSync, writeFileSync } from 'node:fs';
30
+ import os from 'node:os';
31
+ import path from 'node:path';
32
+ import { startLocalHostInvocation } from './gofer-native-adapter.mjs';
33
+ import { insideDirectory, sharedGitDirectory } from './gofer-worktree-layout.mjs';
34
+
35
+ const text = value => typeof value === 'string' && value.trim().length > 0;
36
+ const TEMPORARY_ROOTS = Object.freeze(['/tmp', '/private/tmp', '/var/tmp', '/private/var/tmp',
37
+ '/var/folders', '/private/var/folders']);
38
+ const PROFILE_FILE = path.join('.grok', 'sandbox.toml');
39
+
40
+ /**
41
+ * The per-task profile, or null when the layout cannot be protected. Only paths
42
+ * that exist are listed: Grok cannot apply a profile that names a missing path.
43
+ * `temporaryRoots` exists for isolated tests; production never passes it.
44
+ */
45
+ export function grokSandboxPolicy(workspaceRoot, { temporaryRoots = TEMPORARY_ROOTS } = {}) {
46
+ const common = sharedGitDirectory(workspaceRoot);
47
+ if (!common || !Array.isArray(temporaryRoots)) return null;
48
+ let workspace;
49
+ try { workspace = realpathSync(workspaceRoot); } catch { return null; }
50
+ const denied = [...new Set(temporaryRoots.filter(root => path.isAbsolute(root ?? '') && existsSync(root)))];
51
+ const resolved = denied.flatMap(root => { try { return [root, realpathSync(root)]; } catch { return [root]; } });
52
+ // The temp folders are denied, so a worktree inside them would be denied too.
53
+ if (resolved.some(root => insideDirectory(root, workspace) || insideDirectory(root, common))) return null;
54
+ // Never overwrite a project's own sandbox file, tracked or not.
55
+ try { lstatSync(path.join(workspace, PROFILE_FILE)); return null; } catch { /* absent, as required */ }
56
+ const profileName = `gofer-${randomUUID().replace(/-/g, '').slice(0, 16)}`;
57
+ const toml = `[profiles.${profileName}]\nextends = "strict"\ndeny = ${JSON.stringify(denied)}\n`;
58
+ return Object.freeze({ profileName, toml, common, workspace, denied: Object.freeze(denied) });
59
+ }
60
+
61
+ function parseResult(stdoutText) {
62
+ const trimmed = String(stdoutText ?? '').trim();
63
+ for (const candidate of [trimmed, trimmed.split('\n').at(-1)]) {
64
+ try { const value = JSON.parse(candidate); if (value && typeof value === 'object') return value; }
65
+ catch { /* try the next candidate */ }
66
+ }
67
+ return null;
68
+ }
69
+
70
+ /** Token counts in the shape the pricing code expects, plus Grok's own cost.
71
+ * Grok's `input_tokens` excludes cache reads, as Claude's does. */
72
+ export function extractGrokUsage(stdoutText) {
73
+ const result = parseResult(stdoutText);
74
+ const usage = result?.usage;
75
+ const output = usage?.output_tokens;
76
+ const fresh = usage?.input_tokens;
77
+ const cachedRead = usage?.cache_read_input_tokens ?? 0;
78
+ const cachedWrite = usage?.cache_creation_input_tokens ?? 0;
79
+ if (![output, fresh, cachedRead, cachedWrite].every(value => Number.isInteger(value) && value >= 0)) return null;
80
+ const reported = result.total_cost_usd;
81
+ return Object.freeze({ inputTokens: fresh + cachedRead + cachedWrite, cachedInputTokens: cachedRead,
82
+ outputTokens: output, reportedCostUsd: Number.isFinite(reported) && reported >= 0 ? reported : null });
83
+ }
84
+
85
+ const SANDBOX_FAILURE = /sandbox could not be applied/i;
86
+
87
+ export const GROK_HOST = Object.freeze({
88
+ name: 'grok',
89
+ sandboxPolicy: (workspace, hostOptions) => grokSandboxPolicy(workspace, hostOptions),
90
+ buildArgs: ({ sandboxPolicy, modelId, prompt, workspace, hostOptions }) => {
91
+ const turns = hostOptions?.maxTurns;
92
+ if (!Number.isInteger(turns) || turns < 1 || turns > 200) throw new Error('INVALID_NATIVE_REQUEST');
93
+ return ['-p', prompt, '--cwd', workspace, '--output-format', 'json', '--model', modelId, '--always-approve',
94
+ '--sandbox', sandboxPolicy.profileName, '--max-turns', String(turns), '--no-subagents', '--disable-web-search'];
95
+ },
96
+ // The parent's sandbox variables must not be able to weaken this run.
97
+ env: base => Object.fromEntries(Object.entries(base).filter(([key]) =>
98
+ !key.startsWith('GROK_SANDBOX') && !key.startsWith('GIT_'))),
99
+ fatalStderr: SANDBOX_FAILURE,
100
+ // `wx`: fail closed if the file appeared since the policy was made.
101
+ beforeStart: ({ workspace, sandboxPolicy }) => {
102
+ mkdirSync(path.join(workspace, '.grok'), { recursive: true, mode: 0o700 });
103
+ const descriptor = openSync(path.join(workspace, PROFILE_FILE), constants.O_WRONLY | constants.O_CREAT |
104
+ constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
105
+ try { writeFileSync(descriptor, sandboxPolicy.toml); } finally { closeSync(descriptor); }
106
+ },
107
+ cleanup: ({ workspace }) => {
108
+ const file = path.join(workspace, PROFILE_FILE);
109
+ try { if (lstatSync(file).isFile()) rmSync(file, { force: true }); } catch { /* nothing to remove */ }
110
+ try { rmdirSync(path.join(workspace, '.grok')); } catch { /* not empty or absent: left for the scope check */ }
111
+ },
112
+ finalMessage: ({ stdout }) => String(parseResult(stdout)?.text ?? ''),
113
+ extractUsage: stdoutText => extractGrokUsage(stdoutText),
114
+ assertSuccess: (stdoutText, stderrText) => {
115
+ if (SANDBOX_FAILURE.test(String(stderrText ?? ''))) throw new Error('NATIVE_HOST_SANDBOX_NOT_APPLIED');
116
+ const result = parseResult(stdoutText);
117
+ if (!result) throw new Error('NATIVE_HOST_RESULT_UNPARSEABLE');
118
+ if (result.is_error === true || result.stopReason !== 'end_turn') throw new Error('NATIVE_HOST_REPORTED_ERROR');
119
+ },
120
+ });
121
+
122
+ /** `command` must be the pinned absolute path of the Grok executable, and
123
+ * `hostOptions.maxTurns` bounds this run. Grok has no spend flag. */
124
+ export function startLocalGrokInvocation(options = {}) {
125
+ if (!path.isAbsolute(options.command ?? '')) throw new Error('NATIVE_HOST_COMMAND_MUST_BE_PINNED');
126
+ return startLocalHostInvocation({ ...options, host: GROK_HOST });
127
+ }
128
+
129
+ /**
130
+ * A live boundary probe. Grok has no no-model sandbox command, so this asks a
131
+ * real model (about US$0.01) to try one allowed write and four forbidden ones:
132
+ * a sibling folder, the shared Git store, the OS temp folder, and Grok's own
133
+ * home. It then checks the disk and requires Grok's own report to describe the
134
+ * refusals. It spends money, so nothing calls it implicitly. Returns the
135
+ * executable when the boundary held.
136
+ */
137
+ export function probeGrokSandboxBoundary({ workspaceRoot, executable, model = 'grok-4.5', maxTurns = 8,
138
+ run = spawnSync, temporaryRoots } = {}) {
139
+ if (!text(workspaceRoot) || !path.isAbsolute(executable ?? '')) return null;
140
+ const policy = grokSandboxPolicy(workspaceRoot, temporaryRoots ? { temporaryRoots } : undefined);
141
+ if (!policy) return null;
142
+ const grokHome = path.join(os.homedir(), '.grok');
143
+ let sibling;
144
+ const created = [];
145
+ try {
146
+ sibling = mkdtempSync(path.join(path.dirname(policy.workspace), '.gofer-grok-probe-'));
147
+ const targets = {
148
+ inside: path.join(policy.workspace, `.gofer-grok-probe-${process.pid}`),
149
+ sibling: path.join(sibling, 'outside.txt'),
150
+ store: path.join(policy.common, `.gofer-grok-probe-${process.pid}`),
151
+ temp: path.join(os.tmpdir(), `.gofer-grok-probe-${process.pid}`),
152
+ home: path.join(grokHome, `.gofer-grok-probe-${process.pid}`),
153
+ };
154
+ created.push(...Object.values(targets));
155
+ const prompt = 'This is a file-permission test. Use your shell tool to run exactly these five commands, one at a ' +
156
+ `time, even if an earlier one fails, and never retry or work around a failure: (1) touch ${targets.inside} ` +
157
+ `(2) touch ${targets.sibling} (3) touch ${targets.store} (4) touch ${targets.temp} (5) touch ${targets.home}. ` +
158
+ 'Report each exit code and the error text, then stop.';
159
+ const args = GROK_HOST.buildArgs({ sandboxPolicy: policy, modelId: model, prompt, workspace: policy.workspace,
160
+ hostOptions: { maxTurns } });
161
+ GROK_HOST.beforeStart({ workspace: policy.workspace, sandboxPolicy: policy });
162
+ let result;
163
+ try {
164
+ result = run(executable, args, { cwd: policy.workspace, encoding: 'utf8', timeout: 240000,
165
+ maxBuffer: 8 * 1024 * 1024, env: GROK_HOST.env(process.env) });
166
+ } finally { GROK_HOST.cleanup({ workspace: policy.workspace }); }
167
+ const parsed = parseResult(result.stdout);
168
+ const refusals = (String(parsed?.text ?? '').match(/not permitted|permission denied|denied|blocked|refused|not allowed/gi) ?? []).length;
169
+ const held = result.status === 0 && !SANDBOX_FAILURE.test(String(result.stderr ?? '')) &&
170
+ parsed?.stopReason === 'end_turn' && refusals >= 4 && existsSync(targets.inside) &&
171
+ ['sibling', 'store', 'temp', 'home'].every(key => !existsSync(targets[key]));
172
+ return held ? executable : null;
173
+ } catch { return null; }
174
+ finally {
175
+ for (const file of created) rmSync(file, { force: true });
176
+ if (sibling) rmSync(sibling, { recursive: true, force: true });
177
+ }
178
+ }
179
+
180
+ export function grokExecutableVersion(executable) {
181
+ try { return execFileSync(executable, ['--version'], { encoding: 'utf8', timeout: 5000 }).trim(); }
182
+ catch { return null; }
183
+ }
184
+
@@ -0,0 +1,73 @@
1
+ /** Load a private, integrity-pinned benchmark corpus without copying its cases
2
+ * into Gofer's distributable source tree. */
3
+ import { createHash } from 'node:crypto';
4
+ import { constants } from 'node:fs';
5
+ import { open, realpath } from 'node:fs/promises';
6
+ import path from 'node:path';
7
+
8
+ const text = value => typeof value === 'string' && value.trim().length > 0;
9
+ const CATEGORIES = new Set(['bug-fix', 'refactor', 'cross-service-contract', 'security-sensitive']);
10
+ const digest = value => createHash('sha256').update(value).digest('hex');
11
+
12
+ function within(root, target) {
13
+ const relative = path.relative(root, target);
14
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
15
+ }
16
+
17
+ /**
18
+ * The manifest is a private controller input. Each case references one JSON
19
+ * input file and pins its SHA-256. The loader rejects a corpus located inside
20
+ * the released workspace, traversal paths, duplicate identifiers, incomplete
21
+ * category coverage, and any changed case content.
22
+ */
23
+ export async function loadHeldOutCorpus({ corpusRoot, workspaceRoot } = {}) {
24
+ if (!text(corpusRoot) || !text(workspaceRoot) || !path.isAbsolute(corpusRoot) || !path.isAbsolute(workspaceRoot)) {
25
+ throw new Error('HELDOUT_CORPUS_PATH_REQUIRED');
26
+ }
27
+ const [root, workspace] = await Promise.all([realpath(corpusRoot), realpath(workspaceRoot)]);
28
+ if (within(workspace, root) || within(root, workspace)) {
29
+ throw new Error('HELDOUT_CORPUS_MUST_BE_EXTERNAL');
30
+ }
31
+ const manifestPath = path.join(root, 'manifest.json');
32
+ let manifestText;
33
+ try {
34
+ const file = await open(manifestPath, constants.O_RDONLY | constants.O_NOFOLLOW);
35
+ try {
36
+ const info = await file.stat();
37
+ if (!info.isFile() || info.size < 2 || info.size > 65536) throw new Error('INVALID_HELDOUT_MANIFEST');
38
+ manifestText = await file.readFile('utf8');
39
+ } finally { await file.close(); }
40
+ } catch { throw new Error('INVALID_HELDOUT_MANIFEST'); }
41
+ const manifest = JSON.parse(manifestText);
42
+ if (manifest?.schemaVersion !== 1 || !Array.isArray(manifest.cases) || manifest.cases.length < 4 ||
43
+ new Set(manifest.cases.map(item => item?.id)).size !== manifest.cases.length) throw new Error('INVALID_HELDOUT_MANIFEST');
44
+ const categories = new Set();
45
+ const cases = [];
46
+ for (const item of manifest.cases) {
47
+ if (!text(item?.id) || !CATEGORIES.has(item?.category) || !text(item?.inputFile) ||
48
+ item.inputFile === '.' || item.inputFile === '..' || /[\\/]/.test(item.inputFile) ||
49
+ !/^[a-f0-9]{64}$/i.test(item?.inputSha256 ?? '')) throw new Error('INVALID_HELDOUT_MANIFEST');
50
+ const inputPath = path.resolve(root, item.inputFile);
51
+ if (!within(root, inputPath) || !within(root, await realpath(inputPath))) {
52
+ throw new Error('INVALID_HELDOUT_MANIFEST');
53
+ }
54
+ let input;
55
+ try {
56
+ // A direct case file cannot become a symlink between validation and open.
57
+ const file = await open(inputPath, constants.O_RDONLY | constants.O_NOFOLLOW);
58
+ try {
59
+ const info = await file.stat();
60
+ if (!info.isFile() || info.size < 1 || info.size > 1024 * 1024) throw new Error('INVALID_HELDOUT_MANIFEST');
61
+ input = await file.readFile('utf8');
62
+ } finally { await file.close(); }
63
+ if (!within(root, await realpath(inputPath))) throw new Error('INVALID_HELDOUT_MANIFEST');
64
+ } catch { throw new Error('INVALID_HELDOUT_MANIFEST'); }
65
+ if (digest(input) !== item.inputSha256) throw new Error('HELDOUT_INPUT_INTEGRITY_REQUIRED');
66
+ categories.add(item.category);
67
+ cases.push(Object.freeze({ id: item.id, heldOut: true, category: item.category, input: JSON.parse(input) }));
68
+ }
69
+ if (categories.size !== CATEGORIES.size || [...CATEGORIES].some(category => !categories.has(category))) {
70
+ throw new Error('HELDOUT_CATEGORY_COVERAGE_REQUIRED');
71
+ }
72
+ return Object.freeze({ schemaVersion: 1, corpusHash: digest(JSON.stringify(manifest)), cases: Object.freeze(cases) });
73
+ }