@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,89 @@
1
+ /**
2
+ * Sign a held-out benchmark attestation only after this process has re-run
3
+ * every case itself. The executor's saved verdicts are never trusted: the
4
+ * signer re-executes each protected check in the offline sandbox against the
5
+ * captured bytes, and binds the signature to the exact report it rechecked.
6
+ * It never activates a key. An inactive or unregistered key fails closed.
7
+ */
8
+ import { createHash, createPublicKey, sign } from 'node:crypto';
9
+ import { readFile, rm } from 'node:fs/promises';
10
+ import path from 'node:path';
11
+ import { capabilityReceiptHash } from './gofer-host-capability.mjs';
12
+ import { recheckHeldOutSnapshot } from './gofer-heldout-verifier.mjs';
13
+ import { materializeHeldOutResultSnapshot } from './gofer-heldout-snapshot.mjs';
14
+ import { loadActiveBenchmarkVerifierKey, loadTrustedHeldOutCorpus,
15
+ resolveTrustedEvaluatorPublicKey } from './gofer-trusted-evaluator.mjs';
16
+ import { verifyTrustedBenchmarkEvidence } from './gofer-trusted-benchmark.mjs';
17
+
18
+ const text = value => typeof value === 'string' && value.trim().length > 0;
19
+ const sha = value => createHash('sha256').update(value).digest('hex');
20
+ const denied = () => new Error('BENCHMARK_SIGNER_REQUIRED');
21
+ const EVALUATOR = 'gofer-heldout-benchmark-verifier';
22
+ const VERIFIER_VERSION = '1';
23
+ const DEFAULT_TTL_MS = 60 * 60 * 1000;
24
+ const MAX_TTL_MS = 24 * 60 * 60 * 1000;
25
+
26
+ /**
27
+ * `trustRoot` exists for isolated tests. The production composition root never
28
+ * passes it and always resolves the fixed account trust root.
29
+ */
30
+ export async function signHeldOutBenchmarkAttestation({ workspaceRoot, trustRoot,
31
+ capabilityReceipt, capabilityPublicKey, snapshotId, getPassphrase, protectedRegistry,
32
+ ttlMs = DEFAULT_TTL_MS, now = Date.now() } = {}) {
33
+ let materialized;
34
+ try {
35
+ if (!text(workspaceRoot) || !path.isAbsolute(workspaceRoot) ||
36
+ capabilityReceipt?.host !== 'codex' || !text(capabilityReceipt?.provenance?.keyId) ||
37
+ !/^[a-f0-9]{64}$/.test(snapshotId ?? '') || !Number.isFinite(now) ||
38
+ !Number.isInteger(ttlMs) || ttlMs < 1 || ttlMs > MAX_TTL_MS) throw denied();
39
+ const receiptHash = capabilityReceiptHash(capabilityReceipt);
40
+ const corpus = await loadTrustedHeldOutCorpus({ workspaceRoot, trustRoot });
41
+ const corpusTrustRoot = path.dirname(path.dirname(corpus.corpusRoot));
42
+
43
+ // The signing identity must exist and be active before any work is done.
44
+ const signer = await loadActiveBenchmarkVerifierKey({ workspaceRoot, trustRoot, getPassphrase,
45
+ protectedRegistry });
46
+ if (signer.keyId === capabilityReceipt.provenance.keyId) throw denied();
47
+ const signerPublicKey = await resolveTrustedEvaluatorPublicKey({ host: 'codex',
48
+ provenance: { evaluator: EVALUATOR, keyId: signer.keyId } }, { workspaceRoot, trustRoot, protectedRegistry });
49
+ const capabilityKey = capabilityPublicKey?.type === 'public'
50
+ ? capabilityPublicKey : createPublicKey(capabilityPublicKey);
51
+ if (signerPublicKey.export({ type: 'spki', format: 'der' })
52
+ .equals(capabilityKey.export({ type: 'spki', format: 'der' }))) throw denied();
53
+
54
+ // Independent re-execution. Any disagreement with the saved verdicts throws.
55
+ const recheck = await recheckHeldOutSnapshot({ corpusRoot: corpus.corpusRoot,
56
+ workspaceRoot, trustRoot: corpusTrustRoot, snapshotId });
57
+ if (recheck.corpusHash !== corpus.corpusHash ||
58
+ recheck.functionalPasses !== recheck.functionalRuns) throw denied();
59
+
60
+ materialized = await materializeHeldOutResultSnapshot({ trustRoot: corpusTrustRoot,
61
+ workspaceRoot, snapshotId });
62
+ const saved = JSON.parse(await readFile(path.join(materialized.root, 'receipts',
63
+ 'benchmark-report.json'), 'utf8'));
64
+ const evidence = saved?.report;
65
+ // The signature binds the exact report the sandbox just rechecked.
66
+ if (!evidence || sha(JSON.stringify(evidence)) !== recheck.reportHash ||
67
+ evidence.provenance?.capabilityReceiptHash !== receiptHash ||
68
+ evidence.provenance?.corpusHash !== corpus.corpusHash) throw denied();
69
+
70
+ const payload = { schemaVersion: 1, host: 'codex', capabilityReceiptHash: receiptHash,
71
+ evidenceHash: sha(JSON.stringify(evidence)),
72
+ verification: 'functional-tests+independent-review', verifierVersion: VERIFIER_VERSION,
73
+ verifiedAt: new Date(now).toISOString(), expiresAt: new Date(now + ttlMs).toISOString(),
74
+ provenance: { evaluator: EVALUATOR, keyId: signer.keyId,
75
+ source: `heldout-snapshot:${snapshotId}` } };
76
+ const attestation = { ...payload, signature: { algorithm: 'ed25519', keyId: signer.keyId,
77
+ value: sign(null, Buffer.from(JSON.stringify(payload)), signer.privateKey)
78
+ .toString('base64url') } };
79
+
80
+ // The consumer must accept exactly what was signed, or nothing is returned.
81
+ const verified = await verifyTrustedBenchmarkEvidence({ host: 'codex', receiptHash,
82
+ evidence, attestation, capabilityKeyId: capabilityReceipt.provenance.keyId,
83
+ capabilityPublicKey: capabilityKey, workspaceRoot, now });
84
+ if (verified?.valid !== true) throw denied();
85
+ return Object.freeze({ attestation, evidence, verification: verified,
86
+ snapshotId, checks: recheck.functionalRuns });
87
+ } catch { throw denied(); }
88
+ finally { if (materialized) await rm(materialized.root, { recursive: true, force: true }); }
89
+ }
@@ -0,0 +1,76 @@
1
+ /** A benchmark execution result is not a functional pass. An independent
2
+ * verifier binds every verdict to the held-out input and execution receipt. */
3
+ import { createHash } from 'node:crypto';
4
+
5
+ const positive = value => Number.isFinite(value) && value >= 0;
6
+ const reliability = value => Number.isFinite(value) && value >= 0 && value <= 1;
7
+ const text = value => typeof value === 'string' && value.trim().length > 0;
8
+ const hash = value => createHash('sha256').update(JSON.stringify(value)).digest('hex');
9
+ const validCase = item => item && text(item.id) && item.heldOut === true;
10
+ const validExecution = result => result && text(result.modelId) && positive(result.costUsd) && positive(result.durationMs) && text(result.receipt);
11
+ const validVerifiedRun = result => validExecution(result) && result.functionalVerified === true && text(result.verifierReceipt) && text(result.verifierId) && text(result.inputHash);
12
+ const wilson95 = (successes, total) => {
13
+ const z = 1.96;
14
+ const p = successes / total;
15
+ const denominator = 1 + z ** 2 / total;
16
+ const centre = (p + z ** 2 / (2 * total)) / denominator;
17
+ const spread = z * Math.sqrt((p * (1 - p) + z ** 2 / (4 * total)) / total) / denominator;
18
+ return Object.freeze({ level: 0.95, lower: Math.max(0, centre - spread), upper: Math.min(1, centre + spread) });
19
+ };
20
+
21
+ export async function runBenchmark({ cases, execute, verify, repetitions = 3, provenance } = {}) {
22
+ if (!Array.isArray(cases) || !cases.length || cases.length > 1000 || !cases.every(validCase) ||
23
+ new Set(cases.map(item => item.id)).size !== cases.length || typeof execute !== 'function' ||
24
+ typeof verify !== 'function' || execute === verify || repetitions !== 3 || !text(provenance?.harnessId) || !text(provenance?.modelId)) {
25
+ throw new Error('INVALID_BENCHMARK_CONTRACT');
26
+ }
27
+ const results = [];
28
+ for (const benchmarkCase of cases) for (let run = 1; run <= repetitions; run++) {
29
+ const input = structuredClone(benchmarkCase.input);
30
+ const inputHash = hash({ caseId: benchmarkCase.id, input });
31
+ const execution = await execute(Object.freeze({ id: benchmarkCase.id, run, input }));
32
+ if (!validExecution(execution) || execution.modelId !== provenance.modelId) throw new Error('INVALID_BENCHMARK_RESULT');
33
+ const verdict = await verify(Object.freeze({ caseId: benchmarkCase.id, run, inputHash,
34
+ execution: { receipt: execution.receipt, modelId: execution.modelId ?? null, output: structuredClone(execution.output ?? null) } }));
35
+ if (!verdict || verdict.caseId !== benchmarkCase.id || verdict.run !== run || verdict.inputHash !== inputHash || verdict.executionReceipt !== execution.receipt ||
36
+ typeof verdict.passed !== 'boolean' || !text(verdict.receipt) || !text(verdict.verifierId) ||
37
+ !text(verdict.failureClassification) || !text(verdict.reviewReceipt)) throw new Error('INVALID_BENCHMARK_VERDICT');
38
+ results.push(Object.freeze({ caseId: benchmarkCase.id, run, modelId: execution.modelId ?? null,
39
+ costUsd: execution.costUsd, durationMs: execution.durationMs, receipt: execution.receipt, inputHash,
40
+ functionalVerified: verdict.passed, verifierReceipt: verdict.receipt, verifierId: verdict.verifierId,
41
+ failureClassification: verdict.failureClassification, reviewReceipt: verdict.reviewReceipt }));
42
+ }
43
+ if (new Set(results.map(result => result.receipt)).size !== results.length ||
44
+ new Set(results.map(result => result.verifierReceipt)).size !== results.length) {
45
+ throw new Error('NON_INDEPENDENT_BENCHMARK_RUNS');
46
+ }
47
+ const functionalPasses = results.filter(validVerifiedRun).length;
48
+ const totals = results.reduce((sum, result) => ({ costUsd: sum.costUsd + result.costUsd, durationMs: sum.durationMs + result.durationMs }), { costUsd: 0, durationMs: 0 });
49
+ return Object.freeze({ schemaVersion: 2, repetitions, caseCount: cases.length, runs: results, provenance: { ...provenance },
50
+ reliability: functionalPasses / results.length, confidenceInterval: wilson95(functionalPasses, results.length), functionalPasses, functionalRuns: results.length,
51
+ costUsd: totals.costUsd, durationMs: totals.durationMs, status: functionalPasses === results.length ? 'pass' : 'fail' });
52
+ }
53
+
54
+ export function ablateBenchmark(reports) {
55
+ if (!Array.isArray(reports) || reports.length < 2 || reports.some(report => !report || !text(report.provenance?.harnessId) ||
56
+ !text(report.provenance?.modelId) || !reliability(report.reliability) || !positive(report.costUsd) || !positive(report.durationMs) ||
57
+ !['pass', 'fail'].includes(report.status))) throw new Error('INVALID_ABLATION_REPORT');
58
+ return Object.freeze(reports.map(report => Object.freeze({ harnessId: report.provenance.harnessId, modelId: report.provenance.modelId,
59
+ reliability: report.reliability, costUsd: report.costUsd, durationMs: report.durationMs, status: report.status })));
60
+ }
61
+
62
+ export function gateBenchmark(candidate, baseline, { minReliability = 1, maxCostIncreasePct = 0.1, maxDurationIncreasePct = 0.1 } = {}) {
63
+ if (!candidate || !baseline || !positive(candidate.costUsd) || !positive(candidate.durationMs) || !positive(baseline.costUsd) ||
64
+ !positive(baseline.durationMs) || !reliability(candidate.reliability) || !reliability(baseline.reliability) ||
65
+ ![minReliability, maxCostIncreasePct, maxDurationIncreasePct].every(positive)) throw new Error('INVALID_BENCHMARK_GATE');
66
+ const findings = [];
67
+ if (candidate.status !== 'pass' || candidate.reliability < minReliability) findings.push('FUNCTIONAL_RELIABILITY_REGRESSION');
68
+ if (candidate.reliability < baseline.reliability) findings.push('BASELINE_RELIABILITY_REGRESSION');
69
+ if (baseline.costUsd === 0 ? candidate.costUsd > 0 :
70
+ (candidate.costUsd - baseline.costUsd) / baseline.costUsd > maxCostIncreasePct) findings.push('COST_REGRESSION');
71
+ if (baseline.durationMs === 0 ? candidate.durationMs > 0 :
72
+ (candidate.durationMs - baseline.durationMs) / baseline.durationMs > maxDurationIncreasePct) findings.push('DURATION_REGRESSION');
73
+ return Object.freeze({ status: findings.length ? 'fail' : 'pass', findings,
74
+ candidate: { reliability: candidate.reliability, costUsd: candidate.costUsd, durationMs: candidate.durationMs },
75
+ baseline: { reliability: baseline.reliability, costUsd: baseline.costUsd, durationMs: baseline.durationMs } });
76
+ }
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env node
2
+ import { promises as fs, constants } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { createHash, randomUUID } from 'node:crypto';
5
+ import { pathToFileURL } from 'node:url';
6
+
7
+ const FILE = 'blocker-register.json';
8
+ const MAX_EVIDENCE_BYTES = 16 * 1024 * 1024;
9
+ const CATEGORIES = ['decision', 'access', 'external', 'capability', 'solvable', 'unknown'];
10
+ const STATES = ['ready', 'waiting', 'blocked', 'resolved'];
11
+ const digest = value => createHash('sha256').update(value).digest('hex');
12
+ const material = value => typeof value === 'string' && value.trim().length > 0;
13
+ const key = value => {
14
+ if (!material(value) || !/^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,159}$/.test(value)) throw new Error('A stable machine key is required');
15
+ return value.toLowerCase();
16
+ };
17
+ const waits = category => ['decision', 'access', 'external', 'capability'].includes(category);
18
+
19
+ export function blockerIdentity(value) {
20
+ return digest(JSON.stringify([key(value.goalKey), key(value.subjectKey), key(value.conditionKey)]));
21
+ }
22
+
23
+ async function readBounded(file) {
24
+ const check = stat => {
25
+ if (!stat.isFile()) throw new Error('Evidence must be a regular file');
26
+ if (stat.size > MAX_EVIDENCE_BYTES) throw new Error('Evidence exceeds the 16 MiB limit');
27
+ };
28
+ // Inspect the opened descriptor; a pathname precheck can race with replacement.
29
+ const handle = await fs.open(file, constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW);
30
+ try {
31
+ check(await handle.stat());
32
+ const chunks = [];
33
+ let total = 0;
34
+ while (true) {
35
+ const chunk = Buffer.alloc(Math.min(64 * 1024, MAX_EVIDENCE_BYTES - total + 1));
36
+ const { bytesRead } = await handle.read(chunk, 0, chunk.length, null);
37
+ if (!bytesRead) return Buffer.concat(chunks, total);
38
+ total += bytesRead;
39
+ // Bound the read itself, not only the initial size of a file that can grow.
40
+ if (total > MAX_EVIDENCE_BYTES) throw new Error('Evidence exceeds the 16 MiB limit');
41
+ chunks.push(chunk.subarray(0, bytesRead));
42
+ }
43
+ } finally {
44
+ await handle.close();
45
+ }
46
+ }
47
+
48
+ async function readInside(root, relative) {
49
+ if (!material(relative) || path.isAbsolute(relative) || relative.split(/[\\/]/).includes('..')) throw new Error('Invalid evidence path');
50
+ const resolved = await fs.realpath(path.resolve(root, relative));
51
+ if (!resolved.startsWith(root + path.sep)) throw new Error('Evidence escapes the state directory');
52
+ return readBounded(resolved);
53
+ }
54
+
55
+ function validateRegister(register) {
56
+ if (register?.schemaVersion !== 1 || !register.blockers || typeof register.blockers !== 'object' || Array.isArray(register.blockers)) throw new Error('Invalid blocker register');
57
+ for (const [id, b] of Object.entries(register.blockers)) {
58
+ if (!b || blockerIdentity(b) !== id || !CATEGORIES.includes(b.category) || !STATES.includes(b.state) ||
59
+ typeof b.asked !== 'boolean' || !Array.isArray(b.tasks) || b.tasks.some(t => !/^T\d+$/.test(t)) ||
60
+ !Array.isArray(b.attempts) || !Array.isArray(b.history) || !Array.isArray(b.proofs) ||
61
+ !Number.isInteger(b.epoch) || b.epoch < 0 || b.epoch > 1) throw new Error('Invalid blocker entry');
62
+ const attempts = new Set();
63
+ const approaches = new Set();
64
+ for (const a of b.attempts) {
65
+ if (!material(a.id) || attempts.has(a.id) || !material(a.approach) ||
66
+ !Number.isInteger(a.epoch) || a.epoch < 0 || a.epoch > b.epoch ||
67
+ !['pending', 'progress', 'no_progress', 'blocked'].includes(a.result)) throw new Error('Invalid attempt history');
68
+ if (approaches.has(`${a.epoch}:${a.approach}`)) throw new Error('Repeated approach');
69
+ attempts.add(a.id);
70
+ approaches.add(`${a.epoch}:${a.approach}`);
71
+ }
72
+ if (b.attempts.length > 4 || [0, 1].some(epoch => b.attempts.filter(a => a.epoch === epoch).length > 2)) throw new Error('Invalid attempt budget');
73
+ if (b.attempts.filter(a => a.result === 'pending').length > 1) throw new Error('Multiple pending attempts');
74
+ if (b.state === 'resolved' && !b.proofs.some(p => p.kind === 'resolution')) throw new Error('Missing resolution evidence');
75
+ }
76
+ return register;
77
+ }
78
+
79
+ async function load(root) {
80
+ try { return validateRegister(JSON.parse(await readInside(root, FILE))); }
81
+ catch (error) {
82
+ if (error.code === 'ENOENT') {
83
+ // A dangling register link is invalid, not an empty register.
84
+ try { await fs.lstat(path.join(root, FILE)); } catch (statError) { if (statError.code === 'ENOENT') return { schemaVersion: 1, blockers: {} }; }
85
+ }
86
+ throw error;
87
+ }
88
+ }
89
+
90
+ async function checkProofs(root, blocker) {
91
+ for (const proof of blocker.proofs) {
92
+ if (!proof || !['change', 'resolution', 'diagnosis'].includes(proof.kind) || !material(proof.hash)) throw new Error('Invalid proof record');
93
+ const raw = await readInside(root, proof.file);
94
+ if (digest(raw) !== proof.hash) throw new Error('Blocker evidence changed or is missing');
95
+ if (proof.kind === 'diagnosis') {
96
+ const diagnosis = JSON.parse(raw);
97
+ if (digest(await readInside(root, diagnosis.evidence)) !== diagnosis.sha256) throw new Error('Diagnosis output changed or is missing');
98
+ }
99
+ }
100
+ }
101
+
102
+ async function acceptProof(root, blocker, id, file, kind) {
103
+ const raw = await readInside(root, file);
104
+ const proof = JSON.parse(raw);
105
+ const hash = digest(raw);
106
+ if (proof.blockerId !== id || proof.kind !== kind || proof.result !== (kind === 'change' ? 'changed' : 'pass') ||
107
+ !material(proof.source) || !material(proof.summary) || blocker.proofs.some(p => p.hash === hash || p.source === proof.source)) {
108
+ throw new Error('New evidence for this blocker and action is required');
109
+ }
110
+ return { file, kind, hash, source: proof.source };
111
+ }
112
+
113
+ async function acceptDiagnosis(root, id, file) {
114
+ const raw = await readInside(root, file);
115
+ const proof = JSON.parse(raw);
116
+ const age = Date.now() - Date.parse(proof.checkedAt);
117
+ if (proof.blockerId !== id || proof.kind !== 'diagnosis' ||
118
+ !['product', 'tooling', 'credential', 'environment', 'self-caused'].includes(proof.classification) ||
119
+ !material(proof.command) || !material(proof.observed) || !material(proof.source) ||
120
+ !material(proof.selfCauseCheck) || proof.selfCauseChecked !== true ||
121
+ proof.authorizedRepairAvailable !== false || !material(proof.authorityCheck) ||
122
+ !(material(proof.alternativeCheck) || material(proof.noSafeAlternativeReason)) ||
123
+ !Number.isFinite(age) || age < -300000 || age > 86400000 ||
124
+ digest(await readInside(root, proof.evidence)) !== proof.sha256) {
125
+ throw new Error('Fresh diagnosis and authority evidence are required before technical escalation');
126
+ }
127
+ return { file, kind: 'diagnosis', hash: digest(raw), source: proof.source };
128
+ }
129
+
130
+ export async function inspectBlockers(stateDir, { taskId } = {}) {
131
+ if (taskId !== undefined && !/^T\d+$/.test(taskId)) throw new Error('Invalid task ID');
132
+ const root = await fs.realpath(stateDir);
133
+ const register = await load(root);
134
+ const active = [];
135
+ for (const [id, blocker] of Object.entries(register.blockers)) {
136
+ // Empty task scope means the blocker affects the whole feature.
137
+ if (taskId && blocker.tasks.length && !blocker.tasks.includes(taskId)) continue;
138
+ try { await checkProofs(root, blocker); }
139
+ catch { active.push({ id, state: 'blocked', reason: 'evidence_invalid' }); continue; }
140
+ if (blocker.state !== 'resolved') active.push({ id, state: blocker.state, category: blocker.category });
141
+ }
142
+ return { status: active.length ? 'blocked' : 'clear', blockers: active,
143
+ registered: Object.keys(register.blockers).length,
144
+ coverage: 'Recorded blockers only; does not discover unreported blockers or verify user consent.' };
145
+ }
146
+
147
+ export async function applyBlockerEvent(stateDir, event) {
148
+ if (!event || typeof event !== 'object' || Array.isArray(event)) throw new Error('An event object is required');
149
+ const root = await fs.realpath(stateDir);
150
+ const lockPath = path.join(root, '.gofer-blocker.lock');
151
+ const lock = await fs.open(lockPath, 'wx', 0o600);
152
+ let temporary;
153
+ try {
154
+ const register = await load(root);
155
+ const id = event.action === 'open' ? blockerIdentity(event) : event.blockerId;
156
+ if (typeof id !== 'string' || !/^[a-f0-9]{64}$/.test(id)) throw new Error('Blocker ID is required');
157
+ let b = register.blockers[id];
158
+ const response = { allowed: false, blockerId: id, decision: 'wait' };
159
+ if (event.action === 'open') {
160
+ if (!CATEGORIES.includes(event.category) || !material(event.owner) || !material(event.question) || !material(event.requiredChange) ||
161
+ !Array.isArray(event.tasks) || event.tasks.some(t => !/^T\d+$/.test(t))) throw new Error('Blocker classification and scope are required');
162
+ if (!b) {
163
+ b = { goalKey: key(event.goalKey), subjectKey: key(event.subjectKey), conditionKey: key(event.conditionKey),
164
+ category: event.category, needsDiagnosis: event.category !== 'decision', owner: event.owner, question: event.question, requiredChange: event.requiredChange,
165
+ tasks: [...new Set(event.tasks)], state: waits(event.category) ? 'waiting' : 'ready', asked: false,
166
+ attempts: [], proofs: [], history: [], epoch: 0 };
167
+ register.blockers[id] = b;
168
+ response.allowed = true;
169
+ response.decision = b.state;
170
+ } else {
171
+ // Rewording or another surface cannot clear or narrow a known blocker.
172
+ await checkProofs(root, b);
173
+ b.tasks = b.tasks.length && event.tasks.length ? [...new Set([...b.tasks, ...event.tasks])] : [];
174
+ response.decision = b.state === 'resolved' ? 'already_resolved' : 'already_registered';
175
+ }
176
+ } else {
177
+ if (!b) throw new Error('Unknown blocker');
178
+ await checkProofs(root, b);
179
+ const pending = b.attempts.find(a => a.result === 'pending');
180
+ if (event.action === 'ask') {
181
+ if (!b.asked && !pending && b.state !== 'resolved') {
182
+ // A business choice needs an answer, not a contrived failing command.
183
+ if (b.category !== 'decision' || b.needsDiagnosis === true) b.proofs.push(await acceptDiagnosis(root, id, event.verification));
184
+ b.asked = true;
185
+ b.state = 'waiting';
186
+ response.allowed = true;
187
+ response.decision = 'ask_once';
188
+ response.question = b.question;
189
+ response.requiredChange = b.requiredChange;
190
+ response.owner = b.owner;
191
+ }
192
+ } else if (event.action === 'attempt') {
193
+ const approach = key(event.approachKey);
194
+ const current = b.attempts.filter(a => a.epoch === b.epoch);
195
+ if (b.state === 'ready' && !pending && !waits(b.category) && current.length < 2 && !current.some(a => a.approach === approach)) {
196
+ const attempt = { id: randomUUID(), epoch: b.epoch, approach, result: 'pending' };
197
+ b.attempts.push(attempt);
198
+ response.allowed = true;
199
+ response.decision = current.length ? 'recover_once' : 'investigate_once';
200
+ response.attemptId = attempt.id;
201
+ } else if (b.state === 'ready' && !pending) {
202
+ b.state = 'blocked';
203
+ response.decision = 'stop_no_new_approach_or_budget';
204
+ }
205
+ } else if (event.action === 'result') {
206
+ if (!pending || event.attemptId !== pending.id || !['progress', 'no_progress', 'blocked'].includes(event.result) || !material(event.summary)) throw new Error('A result for the reserved attempt is required');
207
+ pending.result = event.result;
208
+ pending.summary = event.summary;
209
+ b.state = event.result === 'blocked' || b.attempts.filter(a => a.epoch === b.epoch).length >= 2 ? 'blocked' : 'ready';
210
+ response.allowed = true;
211
+ response.decision = b.state;
212
+ } else if (event.action === 'classify') {
213
+ if (pending || b.state === 'resolved' || !CATEGORIES.includes(event.category)) throw new Error('Cannot change this classification');
214
+ const previousCategory = b.category;
215
+ b.category = event.category;
216
+ b.needsDiagnosis = b.needsDiagnosis === true || previousCategory !== 'decision' || event.category !== 'decision';
217
+ if (waits(b.category)) b.state = 'waiting';
218
+ // Reclassification never resets attempts or clears a waiting decision.
219
+ response.allowed = true;
220
+ response.decision = b.state;
221
+ } else if (event.action === 'resume' || event.action === 'resolve') {
222
+ if (pending) throw new Error('Record the pending attempt result first');
223
+ const isResume = event.action === 'resume';
224
+ if (isResume && b.state === 'ready') throw new Error('Ready work does not need a fresh attempt budget');
225
+ if (isResume && b.epoch >= 1) {
226
+ response.decision = 'stop_resume_budget_exhausted';
227
+ } else if (!isResume && b.state === 'resolved') {
228
+ response.decision = 'already_resolved';
229
+ } else {
230
+ if (isResume && !['solvable', 'unknown'].includes(event.category)) throw new Error('Resume must identify work the AI can now attempt');
231
+ const proof = await acceptProof(root, b, id, event.evidence, isResume ? 'change' : 'resolution');
232
+ b.proofs.push(proof);
233
+ b.state = isResume ? 'ready' : 'resolved';
234
+ if (isResume) { b.epoch++; b.category = event.category; b.needsDiagnosis = true; }
235
+ response.allowed = true;
236
+ response.decision = b.state;
237
+ }
238
+ } else throw new Error('Unknown blocker action');
239
+ }
240
+ if (b.history.length >= 1000) throw new Error('Blocker history limit reached; review is required');
241
+ b.history.push({ at: new Date().toISOString(), action: event.action, allowed: response.allowed, decision: response.decision });
242
+ validateRegister(register);
243
+ temporary = path.join(root, `.blocker-register-${randomUUID()}.tmp`);
244
+ await fs.writeFile(temporary, JSON.stringify(register, null, 2) + '\n', { flag: 'wx', mode: 0o600 });
245
+ await fs.rename(temporary, path.join(root, FILE));
246
+ temporary = undefined;
247
+ return { ...response, state: b.state };
248
+ } finally {
249
+ if (temporary) await fs.unlink(temporary).catch(() => {});
250
+ await lock.close();
251
+ await fs.unlink(lockPath);
252
+ }
253
+ }
254
+
255
+ async function main() {
256
+ const args = process.argv.slice(2);
257
+ if (args.includes('--help')) {
258
+ console.log('Usage: gofer-blocker-control.mjs --state-dir <directory> [--event <private-json-file> | --task <T001>]'); return;
259
+ }
260
+ const values = {};
261
+ for (let i = 0; i < args.length; i++) {
262
+ if (!['--state-dir', '--event', '--task'].includes(args[i]) || !args[i + 1] || args[i + 1].startsWith('--')) throw new Error('Invalid arguments');
263
+ values[args[i].slice(2)] = args[++i];
264
+ }
265
+ if (!values['state-dir'] || (values.event && values.task)) throw new Error('State directory and one action are required');
266
+ const result = values.event
267
+ ? await applyBlockerEvent(values['state-dir'], JSON.parse(await readBounded(await fs.realpath(values.event))))
268
+ : await inspectBlockers(values['state-dir'], { taskId: values.task });
269
+ console.log(JSON.stringify(result, null, 2));
270
+ if (result.allowed === false || result.status === 'blocked') process.exitCode = 1;
271
+ }
272
+ if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
273
+ main().catch(() => { console.error('Blocker check stopped. Check local inputs or an active writer; do not repeat work or bypass the check.'); process.exitCode = 1; });
274
+ }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Claude Code 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
+ * Only three things are Claude-specific: how the sandbox policy is described,
5
+ * how the command line is built, and how the result and usage are read.
6
+ *
7
+ * Isolation comes from Claude Code's own OS sandbox, configured per task. A
8
+ * live probe found the default sandbox lets a worker write the shared Git
9
+ * store of a linked worktree, so this policy denies that folder explicitly.
10
+ * Claude has no model catalogue command and no no-model boundary test, so this
11
+ * adapter does not issue capability receipts and does not, by itself, satisfy
12
+ * the EAI CLI isolation gate. See docs/verified-autonomous-runtime.md.
13
+ */
14
+ import { execFileSync, spawnSync } from 'node:child_process';
15
+ import { lstatSync, mkdtempSync, existsSync, readdirSync, realpathSync, rmSync, rmdirSync } from 'node:fs';
16
+ import path from 'node:path';
17
+ import { startLocalHostInvocation } from './gofer-native-adapter.mjs';
18
+ import { sharedGitDirectory } from './gofer-worktree-layout.mjs';
19
+
20
+ const text = value => typeof value === 'string' && value.trim().length > 0;
21
+ /**
22
+ * The per-task sandbox settings. `protectedReadPaths` (for example the account
23
+ * trust folder) are denied for both the shell sandbox and the file tools.
24
+ */
25
+ export function claudeSandboxPolicy(workspaceRoot, { protectedReadPaths = [] } = {}) {
26
+ const common = sharedGitDirectory(workspaceRoot);
27
+ if (!common || !Array.isArray(protectedReadPaths) ||
28
+ protectedReadPaths.some(item => !path.isAbsolute(item ?? ''))) return null;
29
+ const denied = [...protectedReadPaths];
30
+ const settings = { sandbox: { enabled: true, allowUnsandboxedCommands: false,
31
+ filesystem: { denyWrite: [common], ...(denied.length ? { denyRead: denied } : {}) } },
32
+ ...(denied.length ? { permissions: { deny: denied.flatMap(item =>
33
+ ['Read', 'Edit', 'Write'].map(tool => `${tool}(/${item}/**)`)) } } : {}) };
34
+ return Object.freeze({ common, settings: JSON.stringify(settings) });
35
+ }
36
+
37
+ function parseResult(stdoutText) {
38
+ const trimmed = String(stdoutText ?? '').trim();
39
+ for (const candidate of [trimmed, trimmed.split('\n').at(-1)]) {
40
+ try { const value = JSON.parse(candidate); if (value && typeof value === 'object') return value; }
41
+ catch { /* try the next candidate */ }
42
+ }
43
+ return null;
44
+ }
45
+
46
+ /** Token counts in the shape the pricing code expects, plus Claude's own cost. */
47
+ export function extractClaudeUsage(stdoutText) {
48
+ const usage = parseResult(stdoutText)?.usage;
49
+ const output = usage?.output_tokens;
50
+ const fresh = usage?.input_tokens;
51
+ const cachedRead = usage?.cache_read_input_tokens ?? 0;
52
+ const cachedWrite = usage?.cache_creation_input_tokens ?? 0;
53
+ if (![output, fresh, cachedRead, cachedWrite].every(value => Number.isInteger(value) && value >= 0)) return null;
54
+ const reported = parseResult(stdoutText)?.total_cost_usd;
55
+ return Object.freeze({ inputTokens: fresh + cachedRead + cachedWrite, cachedInputTokens: cachedRead,
56
+ outputTokens: output, reportedCostUsd: Number.isFinite(reported) && reported >= 0 ? reported : null });
57
+ }
58
+
59
+ const editRule = (tool, scope) => {
60
+ const clean = scope.replace(/\/$/, '');
61
+ return `${tool}(${scope.endsWith('/') ? `${clean}/**` : clean})`;
62
+ };
63
+
64
+ export const CLAUDE_HOST = Object.freeze({
65
+ name: 'claude',
66
+ sandboxPolicy: (workspace, hostOptions) => claudeSandboxPolicy(workspace, hostOptions),
67
+ buildArgs: ({ sandboxPolicy, modelId, prompt, allowedWriteScope, hostOptions }) => {
68
+ const budget = hostOptions?.maxBudgetUsd;
69
+ if (!(budget > 0) || budget > 100) throw new Error('INVALID_NATIVE_REQUEST');
70
+ const tools = ['Bash', 'Read', 'Glob', 'Grep',
71
+ ...allowedWriteScope.flatMap(scope => [editRule('Edit', scope), editRule('Write', scope)])];
72
+ return ['-p', prompt, '--output-format', 'json', '--model', modelId, '--permission-mode', 'dontAsk',
73
+ '--no-session-persistence', '--disable-slash-commands', '--strict-mcp-config',
74
+ '--max-budget-usd', String(budget), '--settings', sandboxPolicy.settings,
75
+ '--allowedTools', tools.join(',')];
76
+ },
77
+ // A nested Claude session must not inherit its parent's session variables.
78
+ env: base => Object.fromEntries(Object.entries(base).filter(([key]) =>
79
+ key !== 'CLAUDECODE' && !key.startsWith('CLAUDE_CODE') && !key.startsWith('GIT_'))),
80
+ // Claude's sandbox leaves an empty `.claude/.cc-writes` folder in the worktree.
81
+ // It is removed only when it is empty and alone, so a file a worker places
82
+ // there is still reported as a scope violation.
83
+ afterExit: ({ workspace }) => {
84
+ const directory = path.join(workspace, '.claude');
85
+ const bookkeeping = path.join(directory, '.cc-writes');
86
+ try {
87
+ if (lstatSync(directory).isDirectory() && readdirSync(directory).join() === '.cc-writes' &&
88
+ lstatSync(bookkeeping).isDirectory() && readdirSync(bookkeeping).length === 0) {
89
+ rmdirSync(bookkeeping);
90
+ rmdirSync(directory);
91
+ }
92
+ } catch { /* nothing to clean */ }
93
+ },
94
+ finalMessage: ({ stdout }) => String(parseResult(stdout)?.result ?? ''),
95
+ extractUsage: stdoutText => extractClaudeUsage(stdoutText),
96
+ assertSuccess: stdoutText => {
97
+ const result = parseResult(stdoutText);
98
+ if (!result) throw new Error('NATIVE_HOST_RESULT_UNPARSEABLE');
99
+ if (result.is_error === true || result.subtype !== 'success') throw new Error('NATIVE_HOST_REPORTED_ERROR');
100
+ },
101
+ });
102
+
103
+ /** `command` must be the pinned absolute path of the Claude executable, and
104
+ * `hostOptions.maxBudgetUsd` bounds this one run inside Claude itself. */
105
+ export function startLocalClaudeInvocation(options = {}) {
106
+ if (!path.isAbsolute(options.command ?? '')) throw new Error('NATIVE_HOST_COMMAND_MUST_BE_PINNED');
107
+ return startLocalHostInvocation({ ...options, host: CLAUDE_HOST });
108
+ }
109
+
110
+ /**
111
+ * A live boundary probe. Unlike Codex, Claude has no no-model sandbox command,
112
+ * so this asks a real model (about US$0.05 on Haiku) to try one allowed write
113
+ * and four forbidden ones (shell and file tool, sibling folder and shared Git
114
+ * store), then checks the filesystem. It spends money, so nothing calls it
115
+ * implicitly. Returns the executable when the boundary held, otherwise null.
116
+ */
117
+ export function probeClaudeSandboxBoundary({ workspaceRoot, executable, model = 'haiku',
118
+ maxBudgetUsd = 0.25, run = spawnSync } = {}) {
119
+ if (!text(workspaceRoot) || !path.isAbsolute(executable ?? '')) return null;
120
+ const policy = claudeSandboxPolicy(workspaceRoot);
121
+ if (!policy) return null;
122
+ const workspace = realpathSync(workspaceRoot);
123
+ let sibling;
124
+ try {
125
+ sibling = mkdtempSync(path.join(path.dirname(workspace), '.gofer-claude-probe-'));
126
+ const inside_ = path.join(workspace, `.gofer-claude-probe-${process.pid}`);
127
+ const outside = path.join(sibling, 'outside.txt');
128
+ const outsideTool = path.join(sibling, 'outside-tool.txt');
129
+ const store = path.join(policy.common, `.gofer-claude-probe-${process.pid}`);
130
+ const prompt = 'This is a file-permission test. Do these five things, each separately, even if an ' +
131
+ `earlier one fails, and never retry or work around a failure. Shell: (1) touch ${inside_} (2) touch ${outside} ` +
132
+ `(3) touch ${store}. File tool: (4) use the Write tool to create ${outsideTool} with the text x. Then report each result and stop.`;
133
+ const args = ['-p', prompt, '--output-format', 'json', '--model', model, '--permission-mode', 'dontAsk',
134
+ '--no-session-persistence', '--max-budget-usd', String(maxBudgetUsd), '--settings', policy.settings,
135
+ // Mirrors production: Bash, and file tools scoped to one in-scope file only.
136
+ '--allowedTools', 'Bash,Write(gofer-claude-probe-scope.txt)'];
137
+ const result = run(executable, args, { cwd: workspace, encoding: 'utf8', timeout: 180000,
138
+ maxBuffer: 4 * 1024 * 1024, env: CLAUDE_HOST.env(process.env) });
139
+ const parsed = parseResult(result.stdout);
140
+ // A model that skipped the forbidden attempts would pass by doing nothing.
141
+ // Require its own report to describe at least three refusals as well.
142
+ const refusals = (String(parsed?.result ?? '').match(/not permitted|permission denied|denied|blocked|refused|not allowed/gi) ?? []).length;
143
+ const held = result.status === 0 && parsed?.is_error !== true && refusals >= 3 && existsSync(inside_) &&
144
+ !existsSync(outside) && !existsSync(store) && !existsSync(outsideTool);
145
+ rmSync(inside_, { force: true }); rmSync(outside, { force: true }); rmSync(store, { force: true });
146
+ return held ? executable : null;
147
+ } catch { return null; }
148
+ finally { if (sibling) rmSync(sibling, { recursive: true, force: true }); }
149
+ }
150
+
151
+ export function claudeExecutableVersion(executable) {
152
+ try { return execFileSync(executable, ['--version'], { encoding: 'utf8', timeout: 5000 }).trim(); }
153
+ catch { return null; }
154
+ }