@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.
- package/package.json +1 -1
- package/resources/gofer/.gofer-version +4 -357
- package/resources/gofer/agents-skills/eai/SKILL.md +365 -0
- package/resources/gofer/agents-skills/eai-update/SKILL.md +56 -0
- package/resources/gofer/agents-skills/gofer-documentation/SKILL.md +93 -0
- package/resources/gofer/bash-scripts/create-new-feature.sh +3 -1
- package/resources/gofer/bash-scripts/sync-implementation-status.sh +4 -3
- package/resources/gofer/bash-scripts/update-agent-context.sh +7 -8
- package/resources/gofer/bash-scripts/validate-artifact.sh +10 -6
- package/resources/gofer/bash-scripts/verify-object-type-routing-workspace.sh +184 -0
- package/resources/gofer/claude-commands/eai-update.md +46 -0
- package/resources/gofer/claude-commands/eai.md +355 -0
- package/resources/gofer/claude-skills/eai/SKILL.md +365 -0
- package/resources/gofer/claude-skills/eai-update/SKILL.md +56 -0
- package/resources/gofer/claude-skills/gofer-documentation/SKILL.md +93 -0
- package/resources/gofer/commands/0_gofer_start.md +440 -99
- package/resources/gofer/commands/0a_problem_validation.md +187 -27
- package/resources/gofer/commands/10_gofer_cloud.md +183 -23
- package/resources/gofer/commands/1_gofer_research.md +239 -30
- package/resources/gofer/commands/2_gofer_specify.md +239 -35
- package/resources/gofer/commands/3_gofer_plan.md +259 -43
- package/resources/gofer/commands/4_gofer_tasks.md +401 -81
- package/resources/gofer/commands/5_gofer_implement.md +375 -84
- package/resources/gofer/commands/6_gofer_validate.md +284 -53
- package/resources/gofer/commands/7_gofer_save.md +187 -26
- package/resources/gofer/commands/7a_stakeholder_comms.md +183 -23
- package/resources/gofer/commands/8_gofer_branding.md +183 -23
- package/resources/gofer/commands/9_gofer_tests.md +212 -23
- package/resources/gofer/commands/gofer_bootstrap_workspace.md +121 -8
- package/resources/gofer/commands/gofer_check_workspace.md +123 -8
- package/resources/gofer/commands/gofer_constitution.md +183 -23
- package/resources/gofer/commands/gofer_diagnose.md +183 -23
- package/resources/gofer/commands/gofer_eai_first_run.md +254 -25
- package/resources/gofer/commands/gofer_hydrate.md +183 -23
- package/resources/gofer/commands/gofer_personality.md +117 -6
- package/resources/gofer/commands/gofer_plan.md +117 -6
- package/resources/gofer/commands/gofer_side.md +117 -6
- package/resources/gofer/commands/gofer_spec_summary.md +183 -23
- package/resources/gofer/commands/gofer_tdd.md +183 -23
- package/resources/gofer/commands/gofer_vocabulary.md +185 -25
- package/resources/gofer/commands/gofer_zoom_out.md +183 -23
- package/resources/gofer/config/typesafe-learning-review.json +16 -0
- package/resources/gofer/config/typesafe-semantic-review.json +9 -0
- package/resources/gofer/copilot-instructions/gofer-cost.instructions.md +15 -6
- package/resources/gofer/copilot-instructions/typescript.instructions.md +1 -1
- package/resources/gofer/copilot-prompts/eai-update.prompt.md +58 -0
- package/resources/gofer/copilot-prompts/eai.prompt.md +367 -0
- package/resources/gofer/gemini/commands/gofer/eai-update.md +22 -0
- package/resources/gofer/gemini/commands/gofer/eai-update.toml +2 -0
- package/resources/gofer/gemini/commands/gofer/eai.md +357 -0
- package/resources/gofer/gemini/commands/gofer/eai.toml +2 -0
- package/resources/gofer/gemini/commands/gofer/manifest.json +3 -27
- package/resources/gofer/gemini/extension.json +4 -4
- package/resources/gofer/github-agents/eai.agent.md +83 -0
- package/resources/gofer/github-agents/gofer-business.agent.md +73 -4
- package/resources/gofer/github-agents/gofer-implement.agent.md +71 -2
- package/resources/gofer/github-agents/gofer-plan.agent.md +72 -2
- package/resources/gofer/github-agents/gofer-research.agent.md +72 -2
- package/resources/gofer/github-agents/gofer-validate.agent.md +72 -2
- package/resources/gofer/github-skills/eai/SKILL.md +365 -0
- package/resources/gofer/github-skills/eai-update/SKILL.md +56 -0
- package/resources/gofer/github-skills/gofer-documentation/SKILL.md +93 -0
- package/resources/gofer/grok-skills/eai/SKILL.md +267 -14
- package/resources/gofer/grok-skills/eai-update/SKILL.md +56 -0
- package/resources/gofer/hook-scripts/user-prompt-submit.mjs +58 -13
- package/resources/gofer/instruction-templates/base/agents-base.md +8 -4
- package/resources/gofer/instruction-templates/gofer/gofer-claude.md +7 -5
- package/resources/gofer/instruction-templates/gofer/gofer-copilot.md +10 -8
- package/resources/gofer/memory/constitution.md +9 -7
- package/resources/gofer/memory/gofer-model-policy.yaml +23 -1
- package/resources/gofer/memory/lessons.md +0 -31
- package/resources/gofer/node-scripts/canonical-descriptions.mjs +1 -1
- package/resources/gofer/node-scripts/check-version-alignment.mjs +4 -7
- package/resources/gofer/node-scripts/delivery-lineage-corpus.mjs +156 -0
- package/resources/gofer/node-scripts/generate-commands.mjs +1073 -265
- package/resources/gofer/node-scripts/gofer-acceptance-check.mjs +143 -0
- package/resources/gofer/node-scripts/gofer-agent-catalog.mjs +271 -0
- package/resources/gofer/node-scripts/gofer-benchmark-executor.mjs +123 -0
- package/resources/gofer/node-scripts/gofer-benchmark-sign.mjs +62 -0
- package/resources/gofer/node-scripts/gofer-benchmark-signer.mjs +89 -0
- package/resources/gofer/node-scripts/gofer-benchmark.mjs +76 -0
- package/resources/gofer/node-scripts/gofer-blocker-control.mjs +274 -0
- package/resources/gofer/node-scripts/gofer-claude-adapter.mjs +154 -0
- package/resources/gofer/node-scripts/gofer-closed-loop-audit.mjs +19 -2
- package/resources/gofer/node-scripts/gofer-delivery-check.mjs +121 -0
- package/resources/gofer/node-scripts/gofer-encrypted-key.mjs +58 -0
- package/resources/gofer/node-scripts/gofer-execution-metrics.mjs +477 -0
- package/resources/gofer/node-scripts/gofer-execution-recovery.mjs +334 -0
- package/resources/gofer/node-scripts/gofer-grok-adapter.mjs +184 -0
- package/resources/gofer/node-scripts/gofer-heldout-corpus.mjs +73 -0
- package/resources/gofer/node-scripts/gofer-heldout-snapshot.mjs +286 -0
- package/resources/gofer/node-scripts/gofer-heldout-verifier.mjs +211 -0
- package/resources/gofer/node-scripts/gofer-host-capability.mjs +335 -0
- package/resources/gofer/node-scripts/gofer-independent-reviewer.mjs +130 -0
- package/resources/gofer/node-scripts/gofer-live-routing.mjs +109 -0
- package/resources/gofer/node-scripts/gofer-local-capability-issuer.mjs +71 -0
- package/resources/gofer/node-scripts/gofer-local-isolation.mjs +175 -0
- package/resources/gofer/node-scripts/gofer-local-settings-cleanup.mjs +388 -0
- package/resources/gofer/node-scripts/gofer-loop-audit.mjs +54 -3
- package/resources/gofer/node-scripts/gofer-native-adapter.mjs +567 -0
- package/resources/gofer/node-scripts/gofer-native-benchmark-dispatch.mjs +145 -0
- package/resources/gofer/node-scripts/gofer-native-runtime.mjs +169 -0
- package/resources/gofer/node-scripts/gofer-pre-edit-check.mjs +204 -0
- package/resources/gofer/node-scripts/gofer-priority-check.mjs +214 -0
- package/resources/gofer/node-scripts/gofer-response-check.mjs +56 -0
- package/resources/gofer/node-scripts/gofer-reviewed-learning.mjs +1232 -0
- package/resources/gofer/node-scripts/gofer-run-verified-task.mjs +330 -0
- package/resources/gofer/node-scripts/gofer-runtime-ledger.mjs +289 -0
- package/resources/gofer/node-scripts/gofer-semantic-drift.mjs +584 -0
- package/resources/gofer/node-scripts/gofer-surface-update.mjs +1178 -0
- package/resources/gofer/node-scripts/gofer-trust-bootstrap.mjs +77 -0
- package/resources/gofer/node-scripts/gofer-trusted-benchmark.mjs +102 -0
- package/resources/gofer/node-scripts/gofer-trusted-evaluator.mjs +274 -0
- package/resources/gofer/node-scripts/gofer-tty-prompt.mjs +34 -0
- package/resources/gofer/node-scripts/gofer-typesafe-credentials.mjs +435 -0
- package/resources/gofer/node-scripts/gofer-ui-preview.mjs +1212 -0
- package/resources/gofer/node-scripts/gofer-verified-execution.mjs +484 -0
- package/resources/gofer/node-scripts/gofer-verifier-key-ceremony.mjs +101 -0
- package/resources/gofer/node-scripts/gofer-worktree-layout.mjs +32 -0
- package/resources/gofer/node-scripts/object-type-routing-phase-bundle.mjs +360 -0
- package/resources/gofer/node-scripts/package-agent-plugin.mjs +574 -82
- package/resources/gofer/node-scripts/parse-stage-command.mjs +1 -1
- package/resources/gofer/node-scripts/render-delivery-lineage.mjs +178 -0
- package/resources/gofer/node-scripts/sync-extension-resources.mjs +78 -2
- package/resources/gofer/node-scripts/validate-object-type-identifiers.mjs +767 -0
- package/resources/gofer/node-scripts/validate-object-type-routing-workspace.mjs +1325 -0
- package/resources/gofer/node-scripts/validate-v4-resource-contract.d.mts +44 -0
- package/resources/gofer/node-scripts/validate-v4-resource-contract.mjs +957 -0
- package/resources/gofer/node-scripts/workspace-bootstrap-lib.mjs +685 -116
- package/resources/gofer/references/agent-catalog.json +126 -0
- package/resources/gofer/references/blocker-mediation.md +156 -0
- package/resources/gofer/references/business-updates-and-goal-checks.md +109 -0
- package/resources/gofer/references/delivery-lineage.md +48 -0
- package/resources/gofer/references/mvp-capability-validation.md +102 -0
- package/resources/gofer/references/platform/README.md +1 -1
- package/resources/gofer/references/platform/eai-app-template.md +15 -13
- package/resources/gofer/references/platform/eai-auth-access.md +104 -0
- package/resources/gofer/references/platform/eai-config-driven-ui.md +5 -5
- package/resources/gofer/references/platform/eai-error-catalog.yaml +77 -19
- package/resources/gofer/references/platform/eai-repo-contract.md +61 -23
- package/resources/gofer/references/platform/eai-service-patterns.md +102 -105
- package/resources/gofer/references/platform/eai.md +44 -8
- package/resources/gofer/references/platform/vertical-template.md +10 -9
- package/resources/gofer/references/priority-outcome-protection.md +152 -0
- package/resources/gofer/references/verified-agent-execution.md +179 -0
- package/resources/gofer/schemas/gofer-learning-trace-v1.json +70 -0
- package/resources/gofer/specify-commands/0_gofer_start.md +440 -99
- package/resources/gofer/specify-commands/0a_problem_validation.md +187 -27
- package/resources/gofer/specify-commands/10_gofer_cloud.md +183 -23
- package/resources/gofer/specify-commands/1_gofer_research.md +239 -30
- package/resources/gofer/specify-commands/2_gofer_specify.md +239 -35
- package/resources/gofer/specify-commands/3_gofer_plan.md +259 -43
- package/resources/gofer/specify-commands/4_gofer_tasks.md +401 -81
- package/resources/gofer/specify-commands/5_gofer_implement.md +375 -84
- package/resources/gofer/specify-commands/6_gofer_validate.md +284 -53
- package/resources/gofer/specify-commands/7_gofer_save.md +187 -26
- package/resources/gofer/specify-commands/7a_stakeholder_comms.md +183 -23
- package/resources/gofer/specify-commands/8_gofer_branding.md +183 -23
- package/resources/gofer/specify-commands/9_gofer_tests.md +212 -23
- package/resources/gofer/specify-commands/gofer_bootstrap_workspace.md +121 -8
- package/resources/gofer/specify-commands/gofer_check_workspace.md +123 -8
- package/resources/gofer/specify-commands/gofer_constitution.md +183 -23
- package/resources/gofer/specify-commands/gofer_diagnose.md +183 -23
- package/resources/gofer/specify-commands/gofer_eai_first_run.md +254 -25
- package/resources/gofer/specify-commands/gofer_hydrate.md +183 -23
- package/resources/gofer/specify-commands/gofer_personality.md +117 -6
- package/resources/gofer/specify-commands/gofer_plan.md +117 -6
- package/resources/gofer/specify-commands/gofer_side.md +117 -6
- package/resources/gofer/specify-commands/gofer_spec_summary.md +183 -23
- package/resources/gofer/specify-commands/gofer_tdd.md +183 -23
- package/resources/gofer/specify-commands/gofer_vocabulary.md +185 -25
- package/resources/gofer/specify-commands/gofer_zoom_out.md +183 -23
- package/resources/gofer/specify-config/object-type-routing.json +24 -0
- package/resources/gofer/specify-config/typesafe-learning-review.json +16 -0
- package/resources/gofer/specify-config/typesafe-semantic-review.json +9 -0
- package/resources/gofer/system-skills/eai/SKILL.md +365 -0
- package/resources/gofer/system-skills/eai-update/SKILL.md +56 -0
- package/resources/gofer/system-skills/gofer-documentation/SKILL.md +93 -0
- package/resources/gofer/templates/build-map-template.md +64 -0
- package/resources/gofer/templates/business-scenarios-template.json +14 -0
- package/resources/gofer/templates/ciso-security-summary-template.md +3 -3
- package/resources/gofer/templates/context-bundle-template.md +4 -3
- package/resources/gofer/templates/contract-pack-template.md +8 -8
- package/resources/gofer/templates/cto-architecture-summary-template.md +3 -3
- package/resources/gofer/templates/delivery-lineage-template.json +8 -0
- package/resources/gofer/templates/eai-preflight-template.md +109 -68
- package/resources/gofer/templates/goal-ledger-template.json +1 -1
- package/resources/gofer/templates/gofer-model-policy.yaml +28 -6
- package/resources/gofer/templates/loop-contract-template.json +3 -1
- package/resources/gofer/templates/plan-template.md +8 -7
- package/resources/gofer/templates/priority-plan-template.json +29 -0
- package/resources/gofer/templates/proposal-review-template.md +6 -3
- package/resources/gofer/templates/release-capability-ledger-template.md +24 -0
- package/resources/gofer/templates/research-template.md +7 -6
- package/resources/gofer/templates/spec-summary-template.md +1 -1
- package/resources/gofer/templates/spec-template.md +45 -6
- package/resources/gofer/templates/tasks-template.md +12 -3
- package/resources/gofer/templates/ui-preview-brief-template.md +55 -5
- package/resources/gofer/templates/ui-review-log-template.md +21 -3
- package/resources/gofer/templates/ui-show-and-tell-template.md +46 -0
- package/resources/gofer/templates/visuals/capability-heatmap-template.md +2 -2
- package/resources/gofer/templates/working-backwards-prfaq-template.md +9 -8
- package/resources/linked-sources.json +2 -2
- package/resources/gofer/agents-skills/0_gofer_start/SKILL.md +0 -1287
- package/resources/gofer/agents-skills/0a_problem_validation/SKILL.md +0 -429
- package/resources/gofer/agents-skills/10_gofer_cloud/SKILL.md +0 -635
- package/resources/gofer/agents-skills/1_gofer_research/SKILL.md +0 -1159
- package/resources/gofer/agents-skills/2_gofer_specify/SKILL.md +0 -860
- package/resources/gofer/agents-skills/3_gofer_plan/SKILL.md +0 -899
- package/resources/gofer/agents-skills/4_gofer_tasks/SKILL.md +0 -760
- package/resources/gofer/agents-skills/5_gofer_implement/SKILL.md +0 -944
- package/resources/gofer/agents-skills/6_gofer_validate/SKILL.md +0 -2302
- package/resources/gofer/agents-skills/7_gofer_save/SKILL.md +0 -423
- package/resources/gofer/agents-skills/7a_stakeholder_comms/SKILL.md +0 -508
- package/resources/gofer/agents-skills/8_gofer_branding/SKILL.md +0 -315
- package/resources/gofer/agents-skills/9_gofer_tests/SKILL.md +0 -558
- package/resources/gofer/agents-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
- package/resources/gofer/agents-skills/gofer_check_workspace/SKILL.md +0 -119
- package/resources/gofer/agents-skills/gofer_constitution/SKILL.md +0 -612
- package/resources/gofer/agents-skills/gofer_diagnose/SKILL.md +0 -114
- package/resources/gofer/agents-skills/gofer_eai_first_run/SKILL.md +0 -397
- package/resources/gofer/agents-skills/gofer_hydrate/SKILL.md +0 -561
- package/resources/gofer/agents-skills/gofer_personality/SKILL.md +0 -44
- package/resources/gofer/agents-skills/gofer_plan/SKILL.md +0 -40
- package/resources/gofer/agents-skills/gofer_side/SKILL.md +0 -45
- package/resources/gofer/agents-skills/gofer_spec_summary/SKILL.md +0 -112
- package/resources/gofer/agents-skills/gofer_tdd/SKILL.md +0 -112
- package/resources/gofer/agents-skills/gofer_vocabulary/SKILL.md +0 -112
- package/resources/gofer/agents-skills/gofer_zoom_out/SKILL.md +0 -112
- package/resources/gofer/claude-commands/0_gofer_start.md +0 -1282
- package/resources/gofer/claude-commands/0a_problem_validation.md +0 -424
- package/resources/gofer/claude-commands/10_gofer_cloud.md +0 -630
- package/resources/gofer/claude-commands/1_gofer_research.md +0 -1154
- package/resources/gofer/claude-commands/2_gofer_specify.md +0 -855
- package/resources/gofer/claude-commands/3_gofer_plan.md +0 -894
- package/resources/gofer/claude-commands/4_gofer_tasks.md +0 -755
- package/resources/gofer/claude-commands/5_gofer_implement.md +0 -939
- package/resources/gofer/claude-commands/6_gofer_validate.md +0 -2297
- package/resources/gofer/claude-commands/7_gofer_save.md +0 -418
- package/resources/gofer/claude-commands/7a_stakeholder_comms.md +0 -503
- package/resources/gofer/claude-commands/8_gofer_branding.md +0 -310
- package/resources/gofer/claude-commands/9_gofer_tests.md +0 -553
- package/resources/gofer/claude-commands/gofer_bootstrap_workspace.md +0 -143
- package/resources/gofer/claude-commands/gofer_check_workspace.md +0 -114
- package/resources/gofer/claude-commands/gofer_constitution.md +0 -607
- package/resources/gofer/claude-commands/gofer_diagnose.md +0 -109
- package/resources/gofer/claude-commands/gofer_eai_first_run.md +0 -392
- package/resources/gofer/claude-commands/gofer_hydrate.md +0 -556
- package/resources/gofer/claude-commands/gofer_personality.md +0 -39
- package/resources/gofer/claude-commands/gofer_plan.md +0 -35
- package/resources/gofer/claude-commands/gofer_side.md +0 -40
- package/resources/gofer/claude-commands/gofer_spec_summary.md +0 -107
- package/resources/gofer/claude-commands/gofer_tdd.md +0 -107
- package/resources/gofer/claude-commands/gofer_vocabulary.md +0 -107
- package/resources/gofer/claude-commands/gofer_zoom_out.md +0 -107
- package/resources/gofer/claude-skills/eai-gofer/SKILL.md +0 -56
- package/resources/gofer/copilot-prompts/0_gofer_start.prompt.md +0 -1308
- package/resources/gofer/copilot-prompts/0a_problem_validation.prompt.md +0 -429
- package/resources/gofer/copilot-prompts/10_gofer_cloud.prompt.md +0 -644
- package/resources/gofer/copilot-prompts/1_gofer_research.prompt.md +0 -1177
- package/resources/gofer/copilot-prompts/2_gofer_specify.prompt.md +0 -878
- package/resources/gofer/copilot-prompts/3_gofer_plan.prompt.md +0 -917
- package/resources/gofer/copilot-prompts/4_gofer_tasks.prompt.md +0 -778
- package/resources/gofer/copilot-prompts/5_gofer_implement.prompt.md +0 -962
- package/resources/gofer/copilot-prompts/6_gofer_validate.prompt.md +0 -2310
- package/resources/gofer/copilot-prompts/7_gofer_save.prompt.md +0 -433
- package/resources/gofer/copilot-prompts/7a_stakeholder_comms.prompt.md +0 -516
- package/resources/gofer/copilot-prompts/8_gofer_branding.prompt.md +0 -323
- package/resources/gofer/copilot-prompts/9_gofer_tests.prompt.md +0 -566
- package/resources/gofer/copilot-prompts/gofer_bootstrap_workspace.prompt.md +0 -161
- package/resources/gofer/copilot-prompts/gofer_check_workspace.prompt.md +0 -132
- package/resources/gofer/copilot-prompts/gofer_constitution.prompt.md +0 -621
- package/resources/gofer/copilot-prompts/gofer_diagnose.prompt.md +0 -127
- package/resources/gofer/copilot-prompts/gofer_eai_first_run.prompt.md +0 -410
- package/resources/gofer/copilot-prompts/gofer_hydrate.prompt.md +0 -571
- package/resources/gofer/copilot-prompts/gofer_personality.prompt.md +0 -57
- package/resources/gofer/copilot-prompts/gofer_plan.prompt.md +0 -53
- package/resources/gofer/copilot-prompts/gofer_side.prompt.md +0 -58
- package/resources/gofer/copilot-prompts/gofer_spec_summary.prompt.md +0 -125
- package/resources/gofer/copilot-prompts/gofer_tdd.prompt.md +0 -125
- package/resources/gofer/copilot-prompts/gofer_vocabulary.prompt.md +0 -125
- package/resources/gofer/copilot-prompts/gofer_zoom_out.prompt.md +0 -125
- package/resources/gofer/gemini/commands/gofer/0_gofer_start.md +0 -1282
- package/resources/gofer/gemini/commands/gofer/0_gofer_start.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/0a_problem_validation.md +0 -424
- package/resources/gofer/gemini/commands/gofer/0a_problem_validation.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.md +0 -630
- package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/1_gofer_research.md +0 -1154
- package/resources/gofer/gemini/commands/gofer/1_gofer_research.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/2_gofer_specify.md +0 -855
- package/resources/gofer/gemini/commands/gofer/2_gofer_specify.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/3_gofer_plan.md +0 -894
- package/resources/gofer/gemini/commands/gofer/3_gofer_plan.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.md +0 -755
- package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/5_gofer_implement.md +0 -939
- package/resources/gofer/gemini/commands/gofer/5_gofer_implement.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/6_gofer_validate.md +0 -2297
- package/resources/gofer/gemini/commands/gofer/6_gofer_validate.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/7_gofer_save.md +0 -418
- package/resources/gofer/gemini/commands/gofer/7_gofer_save.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.md +0 -503
- package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/8_gofer_branding.md +0 -310
- package/resources/gofer/gemini/commands/gofer/8_gofer_branding.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/9_gofer_tests.md +0 -553
- package/resources/gofer/gemini/commands/gofer/9_gofer_tests.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.md +0 -143
- package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.md +0 -114
- package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_constitution.md +0 -607
- package/resources/gofer/gemini/commands/gofer/gofer_constitution.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_diagnose.md +0 -109
- package/resources/gofer/gemini/commands/gofer/gofer_diagnose.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.md +0 -392
- package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_hydrate.md +0 -556
- package/resources/gofer/gemini/commands/gofer/gofer_hydrate.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_personality.md +0 -39
- package/resources/gofer/gemini/commands/gofer/gofer_personality.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_plan.md +0 -35
- package/resources/gofer/gemini/commands/gofer/gofer_plan.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_side.md +0 -40
- package/resources/gofer/gemini/commands/gofer/gofer_side.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.md +0 -107
- package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_tdd.md +0 -107
- package/resources/gofer/gemini/commands/gofer/gofer_tdd.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.md +0 -107
- package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.toml +0 -2
- package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.md +0 -107
- package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.toml +0 -2
- package/resources/gofer/github-skills/eai-gofer/SKILL.md +0 -56
- package/resources/gofer/system-skills/0_gofer_start/SKILL.md +0 -1287
- package/resources/gofer/system-skills/0a_problem_validation/SKILL.md +0 -429
- package/resources/gofer/system-skills/10_gofer_cloud/SKILL.md +0 -635
- package/resources/gofer/system-skills/1_gofer_research/SKILL.md +0 -1159
- package/resources/gofer/system-skills/2_gofer_specify/SKILL.md +0 -860
- package/resources/gofer/system-skills/3_gofer_plan/SKILL.md +0 -899
- package/resources/gofer/system-skills/4_gofer_tasks/SKILL.md +0 -760
- package/resources/gofer/system-skills/5_gofer_implement/SKILL.md +0 -944
- package/resources/gofer/system-skills/6_gofer_validate/SKILL.md +0 -2302
- package/resources/gofer/system-skills/7_gofer_save/SKILL.md +0 -423
- package/resources/gofer/system-skills/7a_stakeholder_comms/SKILL.md +0 -508
- package/resources/gofer/system-skills/8_gofer_branding/SKILL.md +0 -315
- package/resources/gofer/system-skills/9_gofer_tests/SKILL.md +0 -558
- package/resources/gofer/system-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
- package/resources/gofer/system-skills/gofer_check_workspace/SKILL.md +0 -119
- package/resources/gofer/system-skills/gofer_constitution/SKILL.md +0 -612
- package/resources/gofer/system-skills/gofer_diagnose/SKILL.md +0 -114
- package/resources/gofer/system-skills/gofer_eai_first_run/SKILL.md +0 -397
- package/resources/gofer/system-skills/gofer_hydrate/SKILL.md +0 -561
- package/resources/gofer/system-skills/gofer_personality/SKILL.md +0 -44
- package/resources/gofer/system-skills/gofer_plan/SKILL.md +0 -40
- package/resources/gofer/system-skills/gofer_side/SKILL.md +0 -45
- package/resources/gofer/system-skills/gofer_spec_summary/SKILL.md +0 -112
- package/resources/gofer/system-skills/gofer_tdd/SKILL.md +0 -112
- package/resources/gofer/system-skills/gofer_vocabulary/SKILL.md +0 -112
- package/resources/gofer/system-skills/gofer_zoom_out/SKILL.md +0 -112
- package/resources/gofer/templates/ui-approval-template.md +0 -32
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native dispatch for held-out benchmark cases. Each case runs through the same
|
|
3
|
+
* ledger-bound Codex executor as production tasks: reserve, lease, authorize,
|
|
4
|
+
* native authorize, local OS sandbox, scope and git checks.
|
|
5
|
+
*
|
|
6
|
+
* A benchmark cannot use the normal routing gate, because that gate needs the
|
|
7
|
+
* benchmark result these runs produce. Authority here comes from a dedicated
|
|
8
|
+
* ledger, an explicit user approval receipt, a fixed model, and a hard spend
|
|
9
|
+
* cap. The bootstrap benchmark receipt used here cannot satisfy
|
|
10
|
+
* `verifyTrustedBenchmarkEvidence`, so it never becomes routing authority.
|
|
11
|
+
*/
|
|
12
|
+
import { execFile } from 'node:child_process';
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
import { cp, mkdtemp, readdir, realpath, rm } from 'node:fs/promises';
|
|
15
|
+
import os from 'node:os';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
import { promisify } from 'node:util';
|
|
18
|
+
import { capabilityReceiptHash } from './gofer-host-capability.mjs';
|
|
19
|
+
import { createLedgerBoundCodexExecutor, startLocalCodexInvocation } from './gofer-native-adapter.mjs';
|
|
20
|
+
import { createRuntimeLedger } from './gofer-runtime-ledger.mjs';
|
|
21
|
+
|
|
22
|
+
const run = promisify(execFile);
|
|
23
|
+
const text = value => typeof value === 'string' && value.trim().length > 0;
|
|
24
|
+
const rate = value => Number.isFinite(value) && value >= 0;
|
|
25
|
+
const sha = value => createHash('sha256').update(value).digest('hex');
|
|
26
|
+
const denied = code => new Error(code);
|
|
27
|
+
const ISOLATION = 'git-worktree+local-os-sandbox';
|
|
28
|
+
const gitEnvironment = Object.fromEntries(Object.entries(process.env)
|
|
29
|
+
.filter(([key]) => !key.startsWith('GIT_') || key.startsWith('GIT_CONFIG_')));
|
|
30
|
+
|
|
31
|
+
async function git(directory, args) {
|
|
32
|
+
return run('git', ['-C', directory, '-c', 'user.name=gofer-benchmark',
|
|
33
|
+
'-c', 'user.email=benchmark@gofer.invalid', '-c', 'commit.gpgsign=false', ...args],
|
|
34
|
+
{ encoding: 'utf8', env: gitEnvironment, timeout: 30000 });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** List-price cost from reported token usage. Cached input is charged at its
|
|
38
|
+
* own rate only when one is given; otherwise at the full input rate. */
|
|
39
|
+
export function priceUsage(usage, rateCard) {
|
|
40
|
+
if (![usage?.inputTokens, usage?.cachedInputTokens, usage?.outputTokens]
|
|
41
|
+
.every(value => Number.isInteger(value) && value >= 0) ||
|
|
42
|
+
usage.cachedInputTokens > usage.inputTokens ||
|
|
43
|
+
!rate(rateCard?.inputUsdPerMillion) || !rate(rateCard?.outputUsdPerMillion) ||
|
|
44
|
+
(rateCard.cachedInputUsdPerMillion !== undefined && !rate(rateCard.cachedInputUsdPerMillion))) {
|
|
45
|
+
throw denied('BENCHMARK_USAGE_REQUIRED');
|
|
46
|
+
}
|
|
47
|
+
const cachedRate = rateCard.cachedInputUsdPerMillion ?? rateCard.inputUsdPerMillion;
|
|
48
|
+
const uncached = usage.inputTokens - usage.cachedInputTokens;
|
|
49
|
+
return (uncached * rateCard.inputUsdPerMillion + usage.cachedInputTokens * cachedRate +
|
|
50
|
+
usage.outputTokens * rateCard.outputUsdPerMillion) / 1_000_000;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** One cap shared by every dispatcher of a benchmark, workers and reviewers. */
|
|
54
|
+
export function createSpendCap(maxTotalCostUsd) {
|
|
55
|
+
if (!(maxTotalCostUsd > 0)) throw denied('NATIVE_BENCHMARK_DISPATCH_REQUIRED');
|
|
56
|
+
return { spentUsd: 0, maxTotalCostUsd };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `command` must be the pinned, absolute native executable, never a PATH
|
|
61
|
+
* lookup. `maxRunCostUsd` bounds one run; `maxTotalCostUsd` bounds the whole
|
|
62
|
+
* benchmark and is checked before every launch. A run that cannot be metered,
|
|
63
|
+
* or that times out, is charged at `maxRunCostUsd` so the cap cannot be beaten.
|
|
64
|
+
*/
|
|
65
|
+
export async function createNativeBenchmarkDispatch({ ledgerPath, capabilityReceipt,
|
|
66
|
+
capabilityPublicKey, requiredCapabilities, modelId, approvalReceipt, command, rateCard,
|
|
67
|
+
maxRunCostUsd, spend, taskPrefix = 'benchmark', scratchRoot = os.tmpdir(), timeoutMs = 600_000,
|
|
68
|
+
start = startLocalCodexInvocation, createLedger = createRuntimeLedger } = {}) {
|
|
69
|
+
if (!text(ledgerPath) || !path.isAbsolute(ledgerPath) || !text(modelId) ||
|
|
70
|
+
!text(approvalReceipt) || !text(command) || !path.isAbsolute(command) ||
|
|
71
|
+
capabilityReceipt?.host !== 'codex' || capabilityReceipt.isolationClass !== ISOLATION ||
|
|
72
|
+
!Array.isArray(capabilityReceipt.models) || !capabilityReceipt.models.some(model => model?.id === modelId) ||
|
|
73
|
+
!capabilityPublicKey || !rate(rateCard?.inputUsdPerMillion) ||
|
|
74
|
+
!rate(rateCard?.outputUsdPerMillion) || !(maxRunCostUsd > 0) ||
|
|
75
|
+
!(spend?.maxTotalCostUsd >= maxRunCostUsd) || !/^[a-z]{3,16}$/.test(taskPrefix) ||
|
|
76
|
+
!text(scratchRoot) || !path.isAbsolute(scratchRoot) || !Number.isFinite(spend.spentUsd) || !Number.isInteger(timeoutMs) || timeoutMs < 1 ||
|
|
77
|
+
typeof start !== 'function') throw denied('NATIVE_BENCHMARK_DISPATCH_REQUIRED');
|
|
78
|
+
const ledger = await createLedger({ ledgerPath });
|
|
79
|
+
const receiptHash = capabilityReceiptHash(capabilityReceipt);
|
|
80
|
+
|
|
81
|
+
return async function dispatchCase({ caseId, run: runNumber, prompt, allowedWriteScope, worktree }) {
|
|
82
|
+
if (!text(caseId) || !Number.isInteger(runNumber) || !text(prompt) || !text(worktree) ||
|
|
83
|
+
!path.isAbsolute(worktree) || !Array.isArray(allowedWriteScope) ||
|
|
84
|
+
!allowedWriteScope.length) throw denied('NATIVE_BENCHMARK_DISPATCH_REQUIRED');
|
|
85
|
+
// Checked before any process starts, so the cap cannot be exceeded.
|
|
86
|
+
if (spend.spentUsd + maxRunCostUsd > spend.maxTotalCostUsd) throw denied('BENCHMARK_SPEND_CAP_REACHED');
|
|
87
|
+
|
|
88
|
+
// The qualified sandbox needs a linked worktree whose shared git store lies
|
|
89
|
+
// outside the workspace. Build a scratch base repository from the prepared
|
|
90
|
+
// files, then check the case out into `worktree` as a linked worktree.
|
|
91
|
+
const base = await realpath(await mkdtemp(path.join(scratchRoot, 'gofer-benchmark-base-')));
|
|
92
|
+
try {
|
|
93
|
+
await cp(worktree, base, { recursive: true });
|
|
94
|
+
await git(base, ['init', '-q', '-b', 'main']);
|
|
95
|
+
await git(base, ['add', '-A']);
|
|
96
|
+
await git(base, ['commit', '-q', '-m', 'baseline']);
|
|
97
|
+
const head = (await git(base, ['rev-parse', 'HEAD'])).stdout.trim();
|
|
98
|
+
for (const name of await readdir(worktree)) {
|
|
99
|
+
await rm(path.join(worktree, name), { recursive: true, force: true });
|
|
100
|
+
}
|
|
101
|
+
await git(base, ['worktree', 'add', '-q', '--detach', worktree, head]);
|
|
102
|
+
|
|
103
|
+
const worktreeReceipt = sha(JSON.stringify({ worktree, head }));
|
|
104
|
+
const taskId = `${taskPrefix}:${caseId}:${runNumber}`;
|
|
105
|
+
const task = { taskId, revision: head, attempt: 1, dependencies: [],
|
|
106
|
+
worktreeReceipt, allowedEditScope: [...allowedWriteScope],
|
|
107
|
+
requiredChecks: ['protected-verify'], capabilityReceiptHash: receiptHash,
|
|
108
|
+
approvalReceipt, selectedModel: modelId,
|
|
109
|
+
benchmarkReceipt: `bootstrap-${taskPrefix}:${sha(approvalReceipt).slice(0, 24)}` };
|
|
110
|
+
const reserved = await ledger.reserve(task);
|
|
111
|
+
const leased = reserved?.allowed === true ? await ledger.lease(task) : null;
|
|
112
|
+
if (leased?.allowed !== true) throw denied('NATIVE_BENCHMARK_LEDGER_DENIED');
|
|
113
|
+
const authority = await ledger.authorize({ ...task, leaseId: leased.leaseId,
|
|
114
|
+
budgetReservation: leased.budgetReservation });
|
|
115
|
+
if (authority?.allowed !== true) throw denied('NATIVE_BENCHMARK_LEDGER_DENIED');
|
|
116
|
+
|
|
117
|
+
let launched = false;
|
|
118
|
+
const executor = createLedgerBoundCodexExecutor({ isolatedWorkspace: worktree,
|
|
119
|
+
worktreeReceipt, expectedHead: head, capabilityReceipt, capabilityPublicKey,
|
|
120
|
+
requiredCapabilities, assertLedger: request => ledger.authorizeNative(request),
|
|
121
|
+
promptForRequest: () => prompt,
|
|
122
|
+
start: request => { launched = true; return start({ ...request, command }); } });
|
|
123
|
+
const startedAt = Date.now();
|
|
124
|
+
let result;
|
|
125
|
+
try {
|
|
126
|
+
result = await executor.execute({ revision: head, taskId, attempt: 1, dependencies: [],
|
|
127
|
+
ledgerAuthorityReceipt: authority.receipt, selectedModel: modelId,
|
|
128
|
+
allowedEditScope: [...allowedWriteScope], worktreeReceipt, leaseId: leased.leaseId,
|
|
129
|
+
budgetReservation: leased.budgetReservation, approvalReceipt, usageReporting: true,
|
|
130
|
+
signal: AbortSignal.timeout(timeoutMs) });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// An unmetered or interrupted run is charged in full.
|
|
133
|
+
if (launched) spend.spentUsd += maxRunCostUsd;
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
let costUsd;
|
|
137
|
+
try { costUsd = priceUsage(result.usage, rateCard); }
|
|
138
|
+
catch (error) { spend.spentUsd += maxRunCostUsd; throw error; }
|
|
139
|
+
spend.spentUsd += costUsd;
|
|
140
|
+
if (costUsd > maxRunCostUsd) throw denied('BENCHMARK_RUN_COST_EXCEEDED');
|
|
141
|
+
return { modelId, costUsd, durationMs: Date.now() - startedAt, isolation: result.isolation,
|
|
142
|
+
receipt: result.receipt };
|
|
143
|
+
} finally { await rm(base, { recursive: true, force: true }); }
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production composition root for verified local native execution. It does
|
|
3
|
+
* not manufacture authority: callers must provide one durable ledger that
|
|
4
|
+
* governs both graph dispatch and the host launch.
|
|
5
|
+
*/
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { lstat, realpath } from 'node:fs/promises';
|
|
8
|
+
import { createVerifiedWorktree, inspectVerifiedWorktree, disposeVerifiedWorktree, createLedgerBoundCodexExecutor, startLocalCodexInvocation,
|
|
9
|
+
inspectNativeWorkerEvidence, createNativeCancellationVerifier, createNativeBenchmarkCaptureVerifier } from './gofer-native-adapter.mjs';
|
|
10
|
+
import { createRuntimeLedger } from './gofer-runtime-ledger.mjs';
|
|
11
|
+
import { captureConfiguredHeldOutResultSnapshot } from './gofer-heldout-snapshot.mjs';
|
|
12
|
+
import { reconcileCancelledExecution } from './gofer-execution-recovery.mjs';
|
|
13
|
+
import { runVerifiedGraph } from './gofer-verified-execution.mjs';
|
|
14
|
+
import { inspectEaiLocalIsolation } from './gofer-local-isolation.mjs';
|
|
15
|
+
import { verifyCapabilityReceipt } from './gofer-host-capability.mjs';
|
|
16
|
+
import { resolveTrustedEvaluatorPublicKey } from './gofer-trusted-evaluator.mjs';
|
|
17
|
+
import { verifyTrustedBenchmarkEvidence } from './gofer-trusted-benchmark.mjs';
|
|
18
|
+
|
|
19
|
+
const text = value => typeof value === 'string' && value.trim().length > 0;
|
|
20
|
+
const inside = (parent, child) => {
|
|
21
|
+
const relative = path.relative(parent, child);
|
|
22
|
+
return relative === '' || (relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export async function createVerifiedNativeRuntime({ workspaceRoot, host = 'codex',
|
|
26
|
+
localIsolation = inspectEaiLocalIsolation,
|
|
27
|
+
capabilityReceipt, requiredCapabilities, ledger,
|
|
28
|
+
promptForRequest, adapter, baseRef } = {}) {
|
|
29
|
+
if (!text(workspaceRoot) || host !== 'codex' || typeof localIsolation !== 'function' ||
|
|
30
|
+
capabilityReceipt?.host !== host ||
|
|
31
|
+
typeof ledger?.authorize !== 'function' || typeof ledger?.authorizeCommit !== 'function' ||
|
|
32
|
+
typeof ledger?.authorizeNative !== 'function' || typeof promptForRequest !== 'function' ||
|
|
33
|
+
typeof adapter?.bindWorkspace !== 'function') {
|
|
34
|
+
throw new Error('VERIFIED_NATIVE_RUNTIME_CONFIGURATION_REQUIRED');
|
|
35
|
+
}
|
|
36
|
+
const capabilityPublicKey = await resolveTrustedEvaluatorPublicKey(capabilityReceipt, { workspaceRoot });
|
|
37
|
+
if (!verifyCapabilityReceipt(capabilityReceipt, { publicKey: capabilityPublicKey,
|
|
38
|
+
host, requiredCapabilities })) throw new Error('TRUSTED_CAPABILITY_RECEIPT_REQUIRED');
|
|
39
|
+
const isolation = await createVerifiedWorktree({ workspaceRoot, host, localIsolation, baseRef });
|
|
40
|
+
let boundAdapter;
|
|
41
|
+
try {
|
|
42
|
+
boundAdapter = await adapter.bindWorkspace(Object.freeze({ workspaceRoot: isolation.isolatedWorkspace,
|
|
43
|
+
worktreeReceipt: isolation.receipt }));
|
|
44
|
+
if (boundAdapter?.workspaceRoot !== isolation.isolatedWorkspace ||
|
|
45
|
+
['reserve', 'lease', 'inputRevision', 'check', 'verified'].some(method =>
|
|
46
|
+
typeof boundAdapter?.[method] !== 'function')) throw new Error('NATIVE_ADAPTER_WORKSPACE_BINDING_REQUIRED');
|
|
47
|
+
} catch (error) {
|
|
48
|
+
await disposeVerifiedWorktree({ workspaceRoot: isolation.workspace,
|
|
49
|
+
isolatedWorkspace: isolation.isolatedWorkspace, revision: isolation.revision,
|
|
50
|
+
receipt: isolation.receipt }).catch(() => {});
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
let lifecycle = 'idle';
|
|
54
|
+
return Object.freeze({
|
|
55
|
+
isolation,
|
|
56
|
+
async dispose() {
|
|
57
|
+
if (lifecycle === 'disposed') return;
|
|
58
|
+
if (lifecycle !== 'idle' && lifecycle !== 'verified') {
|
|
59
|
+
throw new Error('NATIVE_RUNTIME_REQUIRES_RECOVERY_BEFORE_DISPOSAL');
|
|
60
|
+
}
|
|
61
|
+
const prior = lifecycle;
|
|
62
|
+
lifecycle = 'disposing';
|
|
63
|
+
try {
|
|
64
|
+
await disposeVerifiedWorktree({ workspaceRoot: isolation.workspace,
|
|
65
|
+
isolatedWorkspace: isolation.isolatedWorkspace, revision: isolation.revision,
|
|
66
|
+
receipt: isolation.receipt });
|
|
67
|
+
lifecycle = 'disposed';
|
|
68
|
+
} catch (error) {
|
|
69
|
+
lifecycle = prior;
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
async run({ featureDir, checks, benchmarkEvidence, benchmarkAttestation, advisoryConstraints,
|
|
74
|
+
approvalReceipt, maxCalls, maxConcurrent, deadlineMs, signal, recovery } = {}) {
|
|
75
|
+
if (lifecycle !== 'idle') throw new Error('NATIVE_RUNTIME_NOT_AVAILABLE');
|
|
76
|
+
lifecycle = 'running';
|
|
77
|
+
let graphStarted = false;
|
|
78
|
+
try {
|
|
79
|
+
if (!text(featureDir)) throw new Error('NATIVE_EVIDENCE_DIRECTORY_REQUIRED');
|
|
80
|
+
const controllerRoot = await realpath(featureDir);
|
|
81
|
+
if (!inside(isolation.workspace, controllerRoot) || inside(isolation.isolatedWorkspace, controllerRoot)) {
|
|
82
|
+
throw new Error('NATIVE_CONTROL_PLANE_OUTSIDE_SOURCE_WORKSPACE');
|
|
83
|
+
}
|
|
84
|
+
const worktree = await inspectVerifiedWorktree({ workspaceRoot: isolation.workspace,
|
|
85
|
+
isolatedWorkspace: isolation.isolatedWorkspace, revision: isolation.revision,
|
|
86
|
+
receipt: isolation.receipt, requireClean: true });
|
|
87
|
+
if (!worktree.valid) throw new Error('NATIVE_WORKTREE_NOT_CLEAN');
|
|
88
|
+
// The trusted journal stays outside the worker sandbox. The bound
|
|
89
|
+
// adapter performs input reads, checks, and commits in the task worktree.
|
|
90
|
+
const evidenceDirectory = path.join(controllerRoot, '.native-worker-evidence');
|
|
91
|
+
const executor = createLedgerBoundCodexExecutor({ isolatedWorkspace: isolation.isolatedWorkspace,
|
|
92
|
+
worktreeReceipt: isolation.receipt, expectedHead: isolation.revision,
|
|
93
|
+
capabilityReceipt, capabilityPublicKey, requiredCapabilities,
|
|
94
|
+
assertLedger: request => ledger.authorizeNative(request), promptForRequest,
|
|
95
|
+
start: request => startLocalCodexInvocation({ ...request,
|
|
96
|
+
command: isolation.nativeExecutable, evidenceDirectory }) });
|
|
97
|
+
const trustedAdapter = Object.freeze({ ...boundAdapter, worktreeReceipt: isolation.receipt,
|
|
98
|
+
execute: executor.execute });
|
|
99
|
+
const trustedRecovery = recovery ? { ...recovery,
|
|
100
|
+
inspectWorkers: request => inspectNativeWorkerEvidence({ ...request, evidenceDirectory }) } : undefined;
|
|
101
|
+
graphStarted = true;
|
|
102
|
+
const verifyBenchmark = request => verifyTrustedBenchmarkEvidence({ ...request,
|
|
103
|
+
attestation: benchmarkAttestation, capabilityKeyId: capabilityReceipt.provenance.keyId,
|
|
104
|
+
capabilityPublicKey,
|
|
105
|
+
workspaceRoot: isolation.workspace });
|
|
106
|
+
const result = await runVerifiedGraph({ featureDir: controllerRoot, workspaceRoot: isolation.isolatedWorkspace,
|
|
107
|
+
checks, adapter: trustedAdapter,
|
|
108
|
+
ledger, capabilityReceipt, capabilityPublicKey, requiredCapabilities, benchmarkEvidence, verifyBenchmark,
|
|
109
|
+
advisoryConstraints, approvalReceipt, maxCalls, maxConcurrent, deadlineMs, signal, recovery: trustedRecovery });
|
|
110
|
+
lifecycle = result.status === 'verified' && result.adapterCallsSettled ? 'verified' : 'recovery-required';
|
|
111
|
+
return result;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
lifecycle = graphStarted ? 'recovery-required' : 'idle';
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Reopen the dispatch ledger with native cancellation proof after a controller restart. */
|
|
121
|
+
export async function reconcileVerifiedNativeCancellation({ featureDir, ledgerPath, workspaceRoot,
|
|
122
|
+
abandonedWorkspace, replacementWorkspace, worktreeRevision, replacementWorktreeReceipt,
|
|
123
|
+
inputRevision, inspectInputRevision, verifyReceipt, timeoutMs } = {}) {
|
|
124
|
+
if (![featureDir, ledgerPath, workspaceRoot, abandonedWorkspace, replacementWorkspace,
|
|
125
|
+
worktreeRevision, replacementWorktreeReceipt, inputRevision].every(text) ||
|
|
126
|
+
!path.isAbsolute(ledgerPath) || typeof inspectInputRevision !== 'function' ||
|
|
127
|
+
typeof verifyReceipt !== 'function') throw new Error('NATIVE_RECOVERY_CONFIGURATION_REQUIRED');
|
|
128
|
+
const evidenceDirectory = path.join(featureDir, '.native-worker-evidence');
|
|
129
|
+
const verifyCancellation = createNativeCancellationVerifier({ workspaceRoot,
|
|
130
|
+
abandonedWorkspace, replacementWorkspace, worktreeRevision,
|
|
131
|
+
evidenceDirectory, inspectInputRevision });
|
|
132
|
+
const ledger = await createRuntimeLedger({ ledgerPath, verifyCancellation });
|
|
133
|
+
return reconcileCancelledExecution({ featureDir, workspaceRoot, abandonedWorkspace,
|
|
134
|
+
replacementWorkspace, worktreeRevision, replacementWorktreeReceipt, inputRevision,
|
|
135
|
+
ledger, verifyReceipt, timeoutMs,
|
|
136
|
+
inspectWorkers: request => inspectNativeWorkerEvidence({ ...request, evidenceDirectory }) });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Reopen the dispatch ledger from the controller's source-side feature root.
|
|
140
|
+
* Capture stays unavailable until that same ledger proves all native runs and
|
|
141
|
+
* the controller-owned process evidence proves that every worker has stopped. */
|
|
142
|
+
export async function openVerifiedNativeBenchmarkCapture({ featureDir, ledgerPath, workspaceRoot } = {}) {
|
|
143
|
+
if (![featureDir, ledgerPath, workspaceRoot].every(text) ||
|
|
144
|
+
![featureDir, ledgerPath, workspaceRoot].every(path.isAbsolute)) {
|
|
145
|
+
throw new Error('NATIVE_BENCHMARK_CAPTURE_CONFIGURATION_REQUIRED');
|
|
146
|
+
}
|
|
147
|
+
const [workspace, controllerRoot, ledgerParent] = await Promise.all([
|
|
148
|
+
realpath(workspaceRoot), realpath(featureDir), realpath(path.dirname(ledgerPath)),
|
|
149
|
+
]);
|
|
150
|
+
if (!inside(workspace, controllerRoot) || controllerRoot === workspace ||
|
|
151
|
+
!inside(controllerRoot, ledgerParent)) {
|
|
152
|
+
throw new Error('NATIVE_BENCHMARK_CAPTURE_CONTROL_PLANE_REQUIRED');
|
|
153
|
+
}
|
|
154
|
+
const ledgerFile = path.join(ledgerParent, path.basename(ledgerPath));
|
|
155
|
+
const info = await lstat(ledgerFile);
|
|
156
|
+
if (!info.isFile() || info.nlink !== 1 ||
|
|
157
|
+
(typeof process.getuid === 'function' && info.uid !== process.getuid()) ||
|
|
158
|
+
(info.mode & 0o077) !== 0) {
|
|
159
|
+
throw new Error('NATIVE_BENCHMARK_CAPTURE_LEDGER_REQUIRED');
|
|
160
|
+
}
|
|
161
|
+
const evidenceDirectory = path.join(controllerRoot, '.native-worker-evidence');
|
|
162
|
+
const ledger = await createRuntimeLedger({ ledgerPath: ledgerFile,
|
|
163
|
+
verifyBenchmarkCapture: createNativeBenchmarkCaptureVerifier({ evidenceDirectory }) });
|
|
164
|
+
return Object.freeze({
|
|
165
|
+
authorizeCapture: request => ledger.authorizeBenchmarkCapture(request),
|
|
166
|
+
capture: captureAuthorization => captureConfiguredHeldOutResultSnapshot({ workspaceRoot: workspace,
|
|
167
|
+
ledger, captureAuthorization }),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { constants } from 'node:fs';
|
|
4
|
+
import { lstat, open, realpath } from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import { pathToFileURL } from 'node:url';
|
|
8
|
+
import { reviewPriority } from './gofer-priority-check.mjs';
|
|
9
|
+
import { runSemanticReview } from './gofer-semantic-drift.mjs';
|
|
10
|
+
|
|
11
|
+
const MAX_DOCUMENT_BYTES = 4 * 1024 * 1024;
|
|
12
|
+
const MAX_CONTEXT_FILE_BYTES = 16 * 1024;
|
|
13
|
+
const NO_FOLLOW = process.platform === 'win32' ? 0 : (constants.O_NOFOLLOW ?? 0);
|
|
14
|
+
const PLACEHOLDER_MARKERS = [
|
|
15
|
+
'[FEATURE NAME]',
|
|
16
|
+
'[###-feature-name]',
|
|
17
|
+
'[specific capability',
|
|
18
|
+
'[domain-specific',
|
|
19
|
+
'[REMOVE IF UNUSED]',
|
|
20
|
+
'ACTION REQUIRED',
|
|
21
|
+
'NEEDS CLARIFICATION',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function isInside(parent, target) {
|
|
25
|
+
const relative = path.relative(parent, target);
|
|
26
|
+
return relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function assertNoSymlinkPath(root, target) {
|
|
30
|
+
const relative = path.relative(root, target);
|
|
31
|
+
if (!isInside(root, target)) throw new Error('Feature or context path must remain inside its workspace.');
|
|
32
|
+
let current = root;
|
|
33
|
+
for (const component of relative.split(path.sep).filter(Boolean)) {
|
|
34
|
+
current = path.join(current, component);
|
|
35
|
+
const info = await lstat(current).catch((error) => {
|
|
36
|
+
if (error?.code === 'ENOENT') return null;
|
|
37
|
+
throw error;
|
|
38
|
+
});
|
|
39
|
+
if (info?.isSymbolicLink()) throw new Error('Feature and context paths must not pass through symbolic links.');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function sameFileIdentity(left, right) {
|
|
44
|
+
return left.dev !== undefined && left.ino !== undefined &&
|
|
45
|
+
right.dev !== undefined && right.ino !== undefined &&
|
|
46
|
+
left.dev === right.dev && left.ino === right.ino;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function safeFile(root, target, limit = MAX_DOCUMENT_BYTES, openFile = open) {
|
|
50
|
+
await assertNoSymlinkPath(root, target);
|
|
51
|
+
const handle = await openFile(target, constants.O_RDONLY | NO_FOLLOW);
|
|
52
|
+
try {
|
|
53
|
+
const opened = await handle.stat();
|
|
54
|
+
if (!opened.isFile() || opened.size > limit) {
|
|
55
|
+
throw new Error('A required feature file is missing, not regular, or too large.');
|
|
56
|
+
}
|
|
57
|
+
// Recheck the resolved path after opening, then compare it with the open
|
|
58
|
+
// file identity. Reads come from the validated handle, not the path, so a
|
|
59
|
+
// swap between lstat and open cannot redirect content outside the workspace.
|
|
60
|
+
await assertNoSymlinkPath(root, target);
|
|
61
|
+
const current = await lstat(target);
|
|
62
|
+
if (current.isSymbolicLink() || !sameFileIdentity(opened, current)) {
|
|
63
|
+
throw new Error('A required feature file changed while it was being opened.');
|
|
64
|
+
}
|
|
65
|
+
return await handle.readFile({ encoding: 'utf8' });
|
|
66
|
+
} finally {
|
|
67
|
+
await handle.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function hasTemplateMarker(content) {
|
|
72
|
+
return PLACEHOLDER_MARKERS.some((marker) => content.includes(marker));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function parseArgs(argv) {
|
|
76
|
+
const options = { workspace: process.cwd(), featureDir: '', task: '', changedFiles: [], jevChatReadiness: false, chatContextFile: '' };
|
|
77
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
78
|
+
const flag = argv[index];
|
|
79
|
+
if (flag === '--workspace') options.workspace = argv[++index] || '';
|
|
80
|
+
else if (flag === '--feature-dir') options.featureDir = argv[++index] || '';
|
|
81
|
+
else if (flag === '--task') options.task = argv[++index] || '';
|
|
82
|
+
else if (flag === '--changed-file') options.changedFiles.push(argv[++index] || '');
|
|
83
|
+
else if (flag === '--jev-chat-readiness') options.jevChatReadiness = true;
|
|
84
|
+
else if (flag === '--chat-context-file') options.chatContextFile = argv[++index] || '';
|
|
85
|
+
else throw new Error(`Unknown argument: ${flag}`);
|
|
86
|
+
}
|
|
87
|
+
if (!options.workspace || !options.featureDir || !options.task || !options.changedFiles.length) {
|
|
88
|
+
throw new Error('--workspace, --feature-dir, --task, and at least one --changed-file are required.');
|
|
89
|
+
}
|
|
90
|
+
if (options.jevChatReadiness !== Boolean(options.chatContextFile)) {
|
|
91
|
+
throw new Error('--jev-chat-readiness requires --chat-context-file, and the context file is only valid with that option.');
|
|
92
|
+
}
|
|
93
|
+
return options;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function checkPreEdit(options, { semanticReview = runSemanticReview, openFile = open } = {}) {
|
|
97
|
+
const workspace = await realpath(path.resolve(options.workspace));
|
|
98
|
+
const featureDir = path.resolve(workspace, options.featureDir);
|
|
99
|
+
await assertNoSymlinkPath(workspace, featureDir);
|
|
100
|
+
const featureInfo = await lstat(featureDir).catch(() => null);
|
|
101
|
+
if (!featureInfo?.isDirectory()) return { status: 'blocked', findings: ['FEATURE_DIRECTORY_MISSING'] };
|
|
102
|
+
|
|
103
|
+
const findings = [];
|
|
104
|
+
const contents = {};
|
|
105
|
+
for (const file of ['goal-ledger.json', 'spec.md', 'plan.md', 'tasks.md']) {
|
|
106
|
+
try {
|
|
107
|
+
contents[file] = await safeFile(workspace, path.join(featureDir, file), MAX_DOCUMENT_BYTES, openFile);
|
|
108
|
+
if (!contents[file].trim()) findings.push(`EMPTY_FILE:${file}`);
|
|
109
|
+
else if (hasTemplateMarker(contents[file])) findings.push(`TEMPLATE_FILE:${file}`);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
findings.push(error?.code === 'ENOENT' ? `MISSING_FILE:${file}` : `INVALID_FILE:${file}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const ledger = JSON.parse(contents['goal-ledger.json'] || 'null');
|
|
116
|
+
if (!Array.isArray(ledger?.goals) || ledger.goals.length === 0 || !ledger.goals.some((goal) => typeof goal.goal === 'string' && goal.goal.trim())) {
|
|
117
|
+
findings.push('GOAL_LEDGER_HAS_NO_GOAL');
|
|
118
|
+
}
|
|
119
|
+
} catch { findings.push('GOAL_LEDGER_INVALID'); }
|
|
120
|
+
|
|
121
|
+
if (findings.length) return { status: 'blocked', findings, task: options.task };
|
|
122
|
+
|
|
123
|
+
const priority = await reviewPriority(featureDir, {
|
|
124
|
+
task: options.task,
|
|
125
|
+
changedFiles: options.changedFiles,
|
|
126
|
+
workspaceRoot: workspace,
|
|
127
|
+
});
|
|
128
|
+
if (priority.status !== 'pass') {
|
|
129
|
+
return { status: 'blocked', findings: priority.findings, task: options.task, nextTask: priority.nextTask };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!options.jevChatReadiness) {
|
|
133
|
+
return { status: 'ready', findings: [], task: options.task, jev: { selected: false } };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const contextFile = options.chatContextFile;
|
|
137
|
+
if (path.isAbsolute(contextFile) || contextFile.split(/[\\/]/).some((part) => part === '..' || part === '.')) {
|
|
138
|
+
return { status: 'blocked', findings: ['CHAT_CONTEXT_PATH_INVALID'], task: options.task };
|
|
139
|
+
}
|
|
140
|
+
const contextPath = path.resolve(featureDir, contextFile);
|
|
141
|
+
let contextInfo;
|
|
142
|
+
try {
|
|
143
|
+
await assertNoSymlinkPath(featureDir, contextPath);
|
|
144
|
+
contextInfo = await lstat(contextPath);
|
|
145
|
+
} catch {
|
|
146
|
+
return { status: 'blocked', findings: ['CHAT_CONTEXT_FILE_MISSING_OR_INVALID'], task: options.task };
|
|
147
|
+
}
|
|
148
|
+
if (!contextInfo.isFile()) return { status: 'blocked', findings: ['CHAT_CONTEXT_FILE_MISSING_OR_INVALID'], task: options.task };
|
|
149
|
+
if (contextInfo.size > MAX_CONTEXT_FILE_BYTES) {
|
|
150
|
+
return {
|
|
151
|
+
status: 'blocked',
|
|
152
|
+
findings: ['CHAT_CONTEXT_TOO_LARGE'],
|
|
153
|
+
task: options.task,
|
|
154
|
+
chatContext: { actualBytes: contextInfo.size, maximumBytes: MAX_CONTEXT_FILE_BYTES },
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
let chatContext;
|
|
158
|
+
try {
|
|
159
|
+
chatContext = await safeFile(featureDir, contextPath, MAX_CONTEXT_FILE_BYTES, openFile);
|
|
160
|
+
} catch {
|
|
161
|
+
return { status: 'blocked', findings: ['CHAT_CONTEXT_FILE_MISSING_OR_INVALID'], task: options.task };
|
|
162
|
+
}
|
|
163
|
+
if (!chatContext.trim()) return { status: 'blocked', findings: ['CHAT_CONTEXT_EMPTY'], task: options.task };
|
|
164
|
+
|
|
165
|
+
let jev;
|
|
166
|
+
try {
|
|
167
|
+
jev = await semanticReview({
|
|
168
|
+
workspace,
|
|
169
|
+
featureDir,
|
|
170
|
+
event: 'chat_readiness',
|
|
171
|
+
chatContext,
|
|
172
|
+
onDemand: true,
|
|
173
|
+
});
|
|
174
|
+
} catch {
|
|
175
|
+
return { status: 'blocked', findings: ['JEV_CHAT_READINESS_UNAVAILABLE'], task: options.task, jev: { selected: true, status: 'unavailable' } };
|
|
176
|
+
}
|
|
177
|
+
const safeReason = typeof jev.reason === 'string' && /^[a-z0-9_]{1,80}$/.test(jev.reason) ? jev.reason : undefined;
|
|
178
|
+
const jevSummary = {
|
|
179
|
+
selected: true,
|
|
180
|
+
status: jev.status,
|
|
181
|
+
...(Number.isFinite(jev.confidence) ? { confidence: jev.confidence } : {}),
|
|
182
|
+
...(safeReason ? { reason: safeReason } : {}),
|
|
183
|
+
};
|
|
184
|
+
return jev.status === 'aligned'
|
|
185
|
+
? { status: 'ready', findings: [], task: options.task, jev: jevSummary }
|
|
186
|
+
: { status: 'blocked', findings: [`JEV_CHAT_READINESS_${String(jev.status || 'unavailable').toUpperCase()}`], task: options.task, jev: jevSummary };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function main() {
|
|
190
|
+
if (process.argv.includes('--help')) {
|
|
191
|
+
console.log('Usage: gofer-pre-edit-check.mjs --workspace <repo> --feature-dir <path> --task T001 --changed-file <path> [--changed-file <path> [--jev-chat-readiness --chat-context-file <feature-relative-path>]]');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const result = await checkPreEdit(parseArgs(process.argv.slice(2)));
|
|
195
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
196
|
+
if (result.status !== 'ready') process.exitCode = 1;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
200
|
+
main().catch((error) => {
|
|
201
|
+
process.stderr.write(`${error.message}\n`);
|
|
202
|
+
process.exitCode = 1;
|
|
203
|
+
});
|
|
204
|
+
}
|