@enterpriseai/cli 3.19.0 → 3.19.1

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 (362) hide show
  1. package/package.json +1 -1
  2. package/resources/gofer/.gofer-version +4 -357
  3. package/resources/gofer/agents-skills/eai/SKILL.md +365 -0
  4. package/resources/gofer/agents-skills/eai-update/SKILL.md +56 -0
  5. package/resources/gofer/agents-skills/gofer-documentation/SKILL.md +93 -0
  6. package/resources/gofer/bash-scripts/create-new-feature.sh +3 -1
  7. package/resources/gofer/bash-scripts/sync-implementation-status.sh +4 -3
  8. package/resources/gofer/bash-scripts/update-agent-context.sh +7 -8
  9. package/resources/gofer/bash-scripts/validate-artifact.sh +10 -6
  10. package/resources/gofer/bash-scripts/verify-object-type-routing-workspace.sh +184 -0
  11. package/resources/gofer/claude-commands/eai-update.md +46 -0
  12. package/resources/gofer/claude-commands/eai.md +355 -0
  13. package/resources/gofer/claude-skills/eai/SKILL.md +365 -0
  14. package/resources/gofer/claude-skills/eai-update/SKILL.md +56 -0
  15. package/resources/gofer/claude-skills/gofer-documentation/SKILL.md +93 -0
  16. package/resources/gofer/commands/0_gofer_start.md +440 -99
  17. package/resources/gofer/commands/0a_problem_validation.md +187 -27
  18. package/resources/gofer/commands/10_gofer_cloud.md +183 -23
  19. package/resources/gofer/commands/1_gofer_research.md +239 -30
  20. package/resources/gofer/commands/2_gofer_specify.md +239 -35
  21. package/resources/gofer/commands/3_gofer_plan.md +259 -43
  22. package/resources/gofer/commands/4_gofer_tasks.md +401 -81
  23. package/resources/gofer/commands/5_gofer_implement.md +375 -84
  24. package/resources/gofer/commands/6_gofer_validate.md +284 -53
  25. package/resources/gofer/commands/7_gofer_save.md +187 -26
  26. package/resources/gofer/commands/7a_stakeholder_comms.md +183 -23
  27. package/resources/gofer/commands/8_gofer_branding.md +183 -23
  28. package/resources/gofer/commands/9_gofer_tests.md +212 -23
  29. package/resources/gofer/commands/gofer_bootstrap_workspace.md +121 -8
  30. package/resources/gofer/commands/gofer_check_workspace.md +123 -8
  31. package/resources/gofer/commands/gofer_constitution.md +183 -23
  32. package/resources/gofer/commands/gofer_diagnose.md +183 -23
  33. package/resources/gofer/commands/gofer_eai_first_run.md +254 -25
  34. package/resources/gofer/commands/gofer_hydrate.md +183 -23
  35. package/resources/gofer/commands/gofer_personality.md +117 -6
  36. package/resources/gofer/commands/gofer_plan.md +117 -6
  37. package/resources/gofer/commands/gofer_side.md +117 -6
  38. package/resources/gofer/commands/gofer_spec_summary.md +183 -23
  39. package/resources/gofer/commands/gofer_tdd.md +183 -23
  40. package/resources/gofer/commands/gofer_vocabulary.md +185 -25
  41. package/resources/gofer/commands/gofer_zoom_out.md +183 -23
  42. package/resources/gofer/config/typesafe-learning-review.json +16 -0
  43. package/resources/gofer/config/typesafe-semantic-review.json +9 -0
  44. package/resources/gofer/copilot-instructions/gofer-cost.instructions.md +15 -6
  45. package/resources/gofer/copilot-instructions/typescript.instructions.md +1 -1
  46. package/resources/gofer/copilot-prompts/eai-update.prompt.md +58 -0
  47. package/resources/gofer/copilot-prompts/eai.prompt.md +367 -0
  48. package/resources/gofer/gemini/commands/gofer/eai-update.md +22 -0
  49. package/resources/gofer/gemini/commands/gofer/eai-update.toml +2 -0
  50. package/resources/gofer/gemini/commands/gofer/eai.md +357 -0
  51. package/resources/gofer/gemini/commands/gofer/eai.toml +2 -0
  52. package/resources/gofer/gemini/commands/gofer/manifest.json +3 -27
  53. package/resources/gofer/gemini/extension.json +4 -4
  54. package/resources/gofer/github-agents/eai.agent.md +83 -0
  55. package/resources/gofer/github-agents/gofer-business.agent.md +73 -4
  56. package/resources/gofer/github-agents/gofer-implement.agent.md +71 -2
  57. package/resources/gofer/github-agents/gofer-plan.agent.md +72 -2
  58. package/resources/gofer/github-agents/gofer-research.agent.md +72 -2
  59. package/resources/gofer/github-agents/gofer-validate.agent.md +72 -2
  60. package/resources/gofer/github-skills/eai/SKILL.md +365 -0
  61. package/resources/gofer/github-skills/eai-update/SKILL.md +56 -0
  62. package/resources/gofer/github-skills/gofer-documentation/SKILL.md +93 -0
  63. package/resources/gofer/grok-skills/eai/SKILL.md +267 -14
  64. package/resources/gofer/grok-skills/eai-update/SKILL.md +56 -0
  65. package/resources/gofer/hook-scripts/user-prompt-submit.mjs +58 -13
  66. package/resources/gofer/instruction-templates/base/agents-base.md +8 -4
  67. package/resources/gofer/instruction-templates/gofer/gofer-claude.md +7 -5
  68. package/resources/gofer/instruction-templates/gofer/gofer-copilot.md +10 -8
  69. package/resources/gofer/memory/constitution.md +9 -7
  70. package/resources/gofer/memory/gofer-model-policy.yaml +23 -1
  71. package/resources/gofer/memory/lessons.md +0 -31
  72. package/resources/gofer/node-scripts/canonical-descriptions.mjs +1 -1
  73. package/resources/gofer/node-scripts/check-version-alignment.mjs +4 -7
  74. package/resources/gofer/node-scripts/delivery-lineage-corpus.mjs +156 -0
  75. package/resources/gofer/node-scripts/generate-commands.mjs +1073 -265
  76. package/resources/gofer/node-scripts/gofer-acceptance-check.mjs +143 -0
  77. package/resources/gofer/node-scripts/gofer-agent-catalog.mjs +271 -0
  78. package/resources/gofer/node-scripts/gofer-benchmark-executor.mjs +123 -0
  79. package/resources/gofer/node-scripts/gofer-benchmark-sign.mjs +62 -0
  80. package/resources/gofer/node-scripts/gofer-benchmark-signer.mjs +89 -0
  81. package/resources/gofer/node-scripts/gofer-benchmark.mjs +76 -0
  82. package/resources/gofer/node-scripts/gofer-blocker-control.mjs +274 -0
  83. package/resources/gofer/node-scripts/gofer-claude-adapter.mjs +154 -0
  84. package/resources/gofer/node-scripts/gofer-closed-loop-audit.mjs +19 -2
  85. package/resources/gofer/node-scripts/gofer-delivery-check.mjs +121 -0
  86. package/resources/gofer/node-scripts/gofer-encrypted-key.mjs +58 -0
  87. package/resources/gofer/node-scripts/gofer-execution-metrics.mjs +477 -0
  88. package/resources/gofer/node-scripts/gofer-execution-recovery.mjs +334 -0
  89. package/resources/gofer/node-scripts/gofer-grok-adapter.mjs +184 -0
  90. package/resources/gofer/node-scripts/gofer-heldout-corpus.mjs +73 -0
  91. package/resources/gofer/node-scripts/gofer-heldout-snapshot.mjs +286 -0
  92. package/resources/gofer/node-scripts/gofer-heldout-verifier.mjs +211 -0
  93. package/resources/gofer/node-scripts/gofer-host-capability.mjs +335 -0
  94. package/resources/gofer/node-scripts/gofer-independent-reviewer.mjs +130 -0
  95. package/resources/gofer/node-scripts/gofer-live-routing.mjs +109 -0
  96. package/resources/gofer/node-scripts/gofer-local-capability-issuer.mjs +71 -0
  97. package/resources/gofer/node-scripts/gofer-local-isolation.mjs +175 -0
  98. package/resources/gofer/node-scripts/gofer-local-settings-cleanup.mjs +388 -0
  99. package/resources/gofer/node-scripts/gofer-loop-audit.mjs +54 -3
  100. package/resources/gofer/node-scripts/gofer-native-adapter.mjs +567 -0
  101. package/resources/gofer/node-scripts/gofer-native-benchmark-dispatch.mjs +145 -0
  102. package/resources/gofer/node-scripts/gofer-native-runtime.mjs +169 -0
  103. package/resources/gofer/node-scripts/gofer-pre-edit-check.mjs +204 -0
  104. package/resources/gofer/node-scripts/gofer-priority-check.mjs +214 -0
  105. package/resources/gofer/node-scripts/gofer-response-check.mjs +56 -0
  106. package/resources/gofer/node-scripts/gofer-reviewed-learning.mjs +1232 -0
  107. package/resources/gofer/node-scripts/gofer-run-verified-task.mjs +330 -0
  108. package/resources/gofer/node-scripts/gofer-runtime-ledger.mjs +289 -0
  109. package/resources/gofer/node-scripts/gofer-semantic-drift.mjs +584 -0
  110. package/resources/gofer/node-scripts/gofer-surface-update.mjs +1178 -0
  111. package/resources/gofer/node-scripts/gofer-trust-bootstrap.mjs +77 -0
  112. package/resources/gofer/node-scripts/gofer-trusted-benchmark.mjs +102 -0
  113. package/resources/gofer/node-scripts/gofer-trusted-evaluator.mjs +274 -0
  114. package/resources/gofer/node-scripts/gofer-tty-prompt.mjs +34 -0
  115. package/resources/gofer/node-scripts/gofer-typesafe-credentials.mjs +435 -0
  116. package/resources/gofer/node-scripts/gofer-ui-preview.mjs +1212 -0
  117. package/resources/gofer/node-scripts/gofer-verified-execution.mjs +484 -0
  118. package/resources/gofer/node-scripts/gofer-verifier-key-ceremony.mjs +101 -0
  119. package/resources/gofer/node-scripts/gofer-worktree-layout.mjs +32 -0
  120. package/resources/gofer/node-scripts/object-type-routing-phase-bundle.mjs +360 -0
  121. package/resources/gofer/node-scripts/package-agent-plugin.mjs +574 -82
  122. package/resources/gofer/node-scripts/parse-stage-command.mjs +1 -1
  123. package/resources/gofer/node-scripts/render-delivery-lineage.mjs +178 -0
  124. package/resources/gofer/node-scripts/sync-extension-resources.mjs +78 -2
  125. package/resources/gofer/node-scripts/validate-object-type-identifiers.mjs +767 -0
  126. package/resources/gofer/node-scripts/validate-object-type-routing-workspace.mjs +1325 -0
  127. package/resources/gofer/node-scripts/validate-v4-resource-contract.d.mts +44 -0
  128. package/resources/gofer/node-scripts/validate-v4-resource-contract.mjs +957 -0
  129. package/resources/gofer/node-scripts/workspace-bootstrap-lib.mjs +685 -116
  130. package/resources/gofer/references/agent-catalog.json +126 -0
  131. package/resources/gofer/references/blocker-mediation.md +156 -0
  132. package/resources/gofer/references/business-updates-and-goal-checks.md +109 -0
  133. package/resources/gofer/references/delivery-lineage.md +48 -0
  134. package/resources/gofer/references/mvp-capability-validation.md +102 -0
  135. package/resources/gofer/references/platform/README.md +1 -1
  136. package/resources/gofer/references/platform/eai-app-template.md +15 -13
  137. package/resources/gofer/references/platform/eai-auth-access.md +104 -0
  138. package/resources/gofer/references/platform/eai-config-driven-ui.md +5 -5
  139. package/resources/gofer/references/platform/eai-error-catalog.yaml +77 -19
  140. package/resources/gofer/references/platform/eai-repo-contract.md +61 -23
  141. package/resources/gofer/references/platform/eai-service-patterns.md +102 -105
  142. package/resources/gofer/references/platform/eai.md +44 -8
  143. package/resources/gofer/references/platform/vertical-template.md +10 -9
  144. package/resources/gofer/references/priority-outcome-protection.md +152 -0
  145. package/resources/gofer/references/verified-agent-execution.md +179 -0
  146. package/resources/gofer/schemas/gofer-learning-trace-v1.json +70 -0
  147. package/resources/gofer/specify-commands/0_gofer_start.md +440 -99
  148. package/resources/gofer/specify-commands/0a_problem_validation.md +187 -27
  149. package/resources/gofer/specify-commands/10_gofer_cloud.md +183 -23
  150. package/resources/gofer/specify-commands/1_gofer_research.md +239 -30
  151. package/resources/gofer/specify-commands/2_gofer_specify.md +239 -35
  152. package/resources/gofer/specify-commands/3_gofer_plan.md +259 -43
  153. package/resources/gofer/specify-commands/4_gofer_tasks.md +401 -81
  154. package/resources/gofer/specify-commands/5_gofer_implement.md +375 -84
  155. package/resources/gofer/specify-commands/6_gofer_validate.md +284 -53
  156. package/resources/gofer/specify-commands/7_gofer_save.md +187 -26
  157. package/resources/gofer/specify-commands/7a_stakeholder_comms.md +183 -23
  158. package/resources/gofer/specify-commands/8_gofer_branding.md +183 -23
  159. package/resources/gofer/specify-commands/9_gofer_tests.md +212 -23
  160. package/resources/gofer/specify-commands/gofer_bootstrap_workspace.md +121 -8
  161. package/resources/gofer/specify-commands/gofer_check_workspace.md +123 -8
  162. package/resources/gofer/specify-commands/gofer_constitution.md +183 -23
  163. package/resources/gofer/specify-commands/gofer_diagnose.md +183 -23
  164. package/resources/gofer/specify-commands/gofer_eai_first_run.md +254 -25
  165. package/resources/gofer/specify-commands/gofer_hydrate.md +183 -23
  166. package/resources/gofer/specify-commands/gofer_personality.md +117 -6
  167. package/resources/gofer/specify-commands/gofer_plan.md +117 -6
  168. package/resources/gofer/specify-commands/gofer_side.md +117 -6
  169. package/resources/gofer/specify-commands/gofer_spec_summary.md +183 -23
  170. package/resources/gofer/specify-commands/gofer_tdd.md +183 -23
  171. package/resources/gofer/specify-commands/gofer_vocabulary.md +185 -25
  172. package/resources/gofer/specify-commands/gofer_zoom_out.md +183 -23
  173. package/resources/gofer/specify-config/object-type-routing.json +24 -0
  174. package/resources/gofer/specify-config/typesafe-learning-review.json +16 -0
  175. package/resources/gofer/specify-config/typesafe-semantic-review.json +9 -0
  176. package/resources/gofer/system-skills/eai/SKILL.md +365 -0
  177. package/resources/gofer/system-skills/eai-update/SKILL.md +56 -0
  178. package/resources/gofer/system-skills/gofer-documentation/SKILL.md +93 -0
  179. package/resources/gofer/templates/build-map-template.md +64 -0
  180. package/resources/gofer/templates/business-scenarios-template.json +14 -0
  181. package/resources/gofer/templates/ciso-security-summary-template.md +3 -3
  182. package/resources/gofer/templates/context-bundle-template.md +4 -3
  183. package/resources/gofer/templates/contract-pack-template.md +8 -8
  184. package/resources/gofer/templates/cto-architecture-summary-template.md +3 -3
  185. package/resources/gofer/templates/delivery-lineage-template.json +8 -0
  186. package/resources/gofer/templates/eai-preflight-template.md +109 -68
  187. package/resources/gofer/templates/goal-ledger-template.json +1 -1
  188. package/resources/gofer/templates/gofer-model-policy.yaml +28 -6
  189. package/resources/gofer/templates/loop-contract-template.json +3 -1
  190. package/resources/gofer/templates/plan-template.md +8 -7
  191. package/resources/gofer/templates/priority-plan-template.json +29 -0
  192. package/resources/gofer/templates/proposal-review-template.md +6 -3
  193. package/resources/gofer/templates/release-capability-ledger-template.md +24 -0
  194. package/resources/gofer/templates/research-template.md +7 -6
  195. package/resources/gofer/templates/spec-summary-template.md +1 -1
  196. package/resources/gofer/templates/spec-template.md +45 -6
  197. package/resources/gofer/templates/tasks-template.md +12 -3
  198. package/resources/gofer/templates/ui-preview-brief-template.md +55 -5
  199. package/resources/gofer/templates/ui-review-log-template.md +21 -3
  200. package/resources/gofer/templates/ui-show-and-tell-template.md +46 -0
  201. package/resources/gofer/templates/visuals/capability-heatmap-template.md +2 -2
  202. package/resources/gofer/templates/working-backwards-prfaq-template.md +9 -8
  203. package/resources/linked-sources.json +2 -2
  204. package/resources/gofer/agents-skills/0_gofer_start/SKILL.md +0 -1287
  205. package/resources/gofer/agents-skills/0a_problem_validation/SKILL.md +0 -429
  206. package/resources/gofer/agents-skills/10_gofer_cloud/SKILL.md +0 -635
  207. package/resources/gofer/agents-skills/1_gofer_research/SKILL.md +0 -1159
  208. package/resources/gofer/agents-skills/2_gofer_specify/SKILL.md +0 -860
  209. package/resources/gofer/agents-skills/3_gofer_plan/SKILL.md +0 -899
  210. package/resources/gofer/agents-skills/4_gofer_tasks/SKILL.md +0 -760
  211. package/resources/gofer/agents-skills/5_gofer_implement/SKILL.md +0 -944
  212. package/resources/gofer/agents-skills/6_gofer_validate/SKILL.md +0 -2302
  213. package/resources/gofer/agents-skills/7_gofer_save/SKILL.md +0 -423
  214. package/resources/gofer/agents-skills/7a_stakeholder_comms/SKILL.md +0 -508
  215. package/resources/gofer/agents-skills/8_gofer_branding/SKILL.md +0 -315
  216. package/resources/gofer/agents-skills/9_gofer_tests/SKILL.md +0 -558
  217. package/resources/gofer/agents-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  218. package/resources/gofer/agents-skills/gofer_check_workspace/SKILL.md +0 -119
  219. package/resources/gofer/agents-skills/gofer_constitution/SKILL.md +0 -612
  220. package/resources/gofer/agents-skills/gofer_diagnose/SKILL.md +0 -114
  221. package/resources/gofer/agents-skills/gofer_eai_first_run/SKILL.md +0 -397
  222. package/resources/gofer/agents-skills/gofer_hydrate/SKILL.md +0 -561
  223. package/resources/gofer/agents-skills/gofer_personality/SKILL.md +0 -44
  224. package/resources/gofer/agents-skills/gofer_plan/SKILL.md +0 -40
  225. package/resources/gofer/agents-skills/gofer_side/SKILL.md +0 -45
  226. package/resources/gofer/agents-skills/gofer_spec_summary/SKILL.md +0 -112
  227. package/resources/gofer/agents-skills/gofer_tdd/SKILL.md +0 -112
  228. package/resources/gofer/agents-skills/gofer_vocabulary/SKILL.md +0 -112
  229. package/resources/gofer/agents-skills/gofer_zoom_out/SKILL.md +0 -112
  230. package/resources/gofer/claude-commands/0_gofer_start.md +0 -1282
  231. package/resources/gofer/claude-commands/0a_problem_validation.md +0 -424
  232. package/resources/gofer/claude-commands/10_gofer_cloud.md +0 -630
  233. package/resources/gofer/claude-commands/1_gofer_research.md +0 -1154
  234. package/resources/gofer/claude-commands/2_gofer_specify.md +0 -855
  235. package/resources/gofer/claude-commands/3_gofer_plan.md +0 -894
  236. package/resources/gofer/claude-commands/4_gofer_tasks.md +0 -755
  237. package/resources/gofer/claude-commands/5_gofer_implement.md +0 -939
  238. package/resources/gofer/claude-commands/6_gofer_validate.md +0 -2297
  239. package/resources/gofer/claude-commands/7_gofer_save.md +0 -418
  240. package/resources/gofer/claude-commands/7a_stakeholder_comms.md +0 -503
  241. package/resources/gofer/claude-commands/8_gofer_branding.md +0 -310
  242. package/resources/gofer/claude-commands/9_gofer_tests.md +0 -553
  243. package/resources/gofer/claude-commands/gofer_bootstrap_workspace.md +0 -143
  244. package/resources/gofer/claude-commands/gofer_check_workspace.md +0 -114
  245. package/resources/gofer/claude-commands/gofer_constitution.md +0 -607
  246. package/resources/gofer/claude-commands/gofer_diagnose.md +0 -109
  247. package/resources/gofer/claude-commands/gofer_eai_first_run.md +0 -392
  248. package/resources/gofer/claude-commands/gofer_hydrate.md +0 -556
  249. package/resources/gofer/claude-commands/gofer_personality.md +0 -39
  250. package/resources/gofer/claude-commands/gofer_plan.md +0 -35
  251. package/resources/gofer/claude-commands/gofer_side.md +0 -40
  252. package/resources/gofer/claude-commands/gofer_spec_summary.md +0 -107
  253. package/resources/gofer/claude-commands/gofer_tdd.md +0 -107
  254. package/resources/gofer/claude-commands/gofer_vocabulary.md +0 -107
  255. package/resources/gofer/claude-commands/gofer_zoom_out.md +0 -107
  256. package/resources/gofer/claude-skills/eai-gofer/SKILL.md +0 -56
  257. package/resources/gofer/copilot-prompts/0_gofer_start.prompt.md +0 -1308
  258. package/resources/gofer/copilot-prompts/0a_problem_validation.prompt.md +0 -429
  259. package/resources/gofer/copilot-prompts/10_gofer_cloud.prompt.md +0 -644
  260. package/resources/gofer/copilot-prompts/1_gofer_research.prompt.md +0 -1177
  261. package/resources/gofer/copilot-prompts/2_gofer_specify.prompt.md +0 -878
  262. package/resources/gofer/copilot-prompts/3_gofer_plan.prompt.md +0 -917
  263. package/resources/gofer/copilot-prompts/4_gofer_tasks.prompt.md +0 -778
  264. package/resources/gofer/copilot-prompts/5_gofer_implement.prompt.md +0 -962
  265. package/resources/gofer/copilot-prompts/6_gofer_validate.prompt.md +0 -2310
  266. package/resources/gofer/copilot-prompts/7_gofer_save.prompt.md +0 -433
  267. package/resources/gofer/copilot-prompts/7a_stakeholder_comms.prompt.md +0 -516
  268. package/resources/gofer/copilot-prompts/8_gofer_branding.prompt.md +0 -323
  269. package/resources/gofer/copilot-prompts/9_gofer_tests.prompt.md +0 -566
  270. package/resources/gofer/copilot-prompts/gofer_bootstrap_workspace.prompt.md +0 -161
  271. package/resources/gofer/copilot-prompts/gofer_check_workspace.prompt.md +0 -132
  272. package/resources/gofer/copilot-prompts/gofer_constitution.prompt.md +0 -621
  273. package/resources/gofer/copilot-prompts/gofer_diagnose.prompt.md +0 -127
  274. package/resources/gofer/copilot-prompts/gofer_eai_first_run.prompt.md +0 -410
  275. package/resources/gofer/copilot-prompts/gofer_hydrate.prompt.md +0 -571
  276. package/resources/gofer/copilot-prompts/gofer_personality.prompt.md +0 -57
  277. package/resources/gofer/copilot-prompts/gofer_plan.prompt.md +0 -53
  278. package/resources/gofer/copilot-prompts/gofer_side.prompt.md +0 -58
  279. package/resources/gofer/copilot-prompts/gofer_spec_summary.prompt.md +0 -125
  280. package/resources/gofer/copilot-prompts/gofer_tdd.prompt.md +0 -125
  281. package/resources/gofer/copilot-prompts/gofer_vocabulary.prompt.md +0 -125
  282. package/resources/gofer/copilot-prompts/gofer_zoom_out.prompt.md +0 -125
  283. package/resources/gofer/gemini/commands/gofer/0_gofer_start.md +0 -1282
  284. package/resources/gofer/gemini/commands/gofer/0_gofer_start.toml +0 -2
  285. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.md +0 -424
  286. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.toml +0 -2
  287. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.md +0 -630
  288. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.toml +0 -2
  289. package/resources/gofer/gemini/commands/gofer/1_gofer_research.md +0 -1154
  290. package/resources/gofer/gemini/commands/gofer/1_gofer_research.toml +0 -2
  291. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.md +0 -855
  292. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.toml +0 -2
  293. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.md +0 -894
  294. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.toml +0 -2
  295. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.md +0 -755
  296. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.toml +0 -2
  297. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.md +0 -939
  298. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.toml +0 -2
  299. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.md +0 -2297
  300. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.toml +0 -2
  301. package/resources/gofer/gemini/commands/gofer/7_gofer_save.md +0 -418
  302. package/resources/gofer/gemini/commands/gofer/7_gofer_save.toml +0 -2
  303. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.md +0 -503
  304. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.toml +0 -2
  305. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.md +0 -310
  306. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.toml +0 -2
  307. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.md +0 -553
  308. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.toml +0 -2
  309. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.md +0 -143
  310. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.toml +0 -2
  311. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.md +0 -114
  312. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.toml +0 -2
  313. package/resources/gofer/gemini/commands/gofer/gofer_constitution.md +0 -607
  314. package/resources/gofer/gemini/commands/gofer/gofer_constitution.toml +0 -2
  315. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.md +0 -109
  316. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.toml +0 -2
  317. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.md +0 -392
  318. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.toml +0 -2
  319. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.md +0 -556
  320. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.toml +0 -2
  321. package/resources/gofer/gemini/commands/gofer/gofer_personality.md +0 -39
  322. package/resources/gofer/gemini/commands/gofer/gofer_personality.toml +0 -2
  323. package/resources/gofer/gemini/commands/gofer/gofer_plan.md +0 -35
  324. package/resources/gofer/gemini/commands/gofer/gofer_plan.toml +0 -2
  325. package/resources/gofer/gemini/commands/gofer/gofer_side.md +0 -40
  326. package/resources/gofer/gemini/commands/gofer/gofer_side.toml +0 -2
  327. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.md +0 -107
  328. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.toml +0 -2
  329. package/resources/gofer/gemini/commands/gofer/gofer_tdd.md +0 -107
  330. package/resources/gofer/gemini/commands/gofer/gofer_tdd.toml +0 -2
  331. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.md +0 -107
  332. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.toml +0 -2
  333. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.md +0 -107
  334. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.toml +0 -2
  335. package/resources/gofer/github-skills/eai-gofer/SKILL.md +0 -56
  336. package/resources/gofer/system-skills/0_gofer_start/SKILL.md +0 -1287
  337. package/resources/gofer/system-skills/0a_problem_validation/SKILL.md +0 -429
  338. package/resources/gofer/system-skills/10_gofer_cloud/SKILL.md +0 -635
  339. package/resources/gofer/system-skills/1_gofer_research/SKILL.md +0 -1159
  340. package/resources/gofer/system-skills/2_gofer_specify/SKILL.md +0 -860
  341. package/resources/gofer/system-skills/3_gofer_plan/SKILL.md +0 -899
  342. package/resources/gofer/system-skills/4_gofer_tasks/SKILL.md +0 -760
  343. package/resources/gofer/system-skills/5_gofer_implement/SKILL.md +0 -944
  344. package/resources/gofer/system-skills/6_gofer_validate/SKILL.md +0 -2302
  345. package/resources/gofer/system-skills/7_gofer_save/SKILL.md +0 -423
  346. package/resources/gofer/system-skills/7a_stakeholder_comms/SKILL.md +0 -508
  347. package/resources/gofer/system-skills/8_gofer_branding/SKILL.md +0 -315
  348. package/resources/gofer/system-skills/9_gofer_tests/SKILL.md +0 -558
  349. package/resources/gofer/system-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  350. package/resources/gofer/system-skills/gofer_check_workspace/SKILL.md +0 -119
  351. package/resources/gofer/system-skills/gofer_constitution/SKILL.md +0 -612
  352. package/resources/gofer/system-skills/gofer_diagnose/SKILL.md +0 -114
  353. package/resources/gofer/system-skills/gofer_eai_first_run/SKILL.md +0 -397
  354. package/resources/gofer/system-skills/gofer_hydrate/SKILL.md +0 -561
  355. package/resources/gofer/system-skills/gofer_personality/SKILL.md +0 -44
  356. package/resources/gofer/system-skills/gofer_plan/SKILL.md +0 -40
  357. package/resources/gofer/system-skills/gofer_side/SKILL.md +0 -45
  358. package/resources/gofer/system-skills/gofer_spec_summary/SKILL.md +0 -112
  359. package/resources/gofer/system-skills/gofer_tdd/SKILL.md +0 -112
  360. package/resources/gofer/system-skills/gofer_vocabulary/SKILL.md +0 -112
  361. package/resources/gofer/system-skills/gofer_zoom_out/SKILL.md +0 -112
  362. 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
+ }