@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.
- package/package.json +3 -3
- package/resources/deploy/eai-app-template/producer-pin.json +5 -5
- package/resources/deploy/eai-app-template/tests/source-unknown-deployment-evidence.test.mjs +2141 -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 +4 -4
- 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,567 @@
|
|
|
1
|
+
/** Native adapter primitives. They create real Git worktree isolation and
|
|
2
|
+
* require a ledger authority record before a host integration can start work. */
|
|
3
|
+
import { execFile, spawn } from 'node:child_process';
|
|
4
|
+
import { mkdtemp, mkdir, open, readFile, readdir, realpath } from 'node:fs/promises';
|
|
5
|
+
import { constants } from 'node:fs';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { promisify } from 'node:util';
|
|
9
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
10
|
+
import { capabilityReceiptHash, verifyCapabilityReceipt } from './gofer-host-capability.mjs';
|
|
11
|
+
import { codexIsolatedPermissionArgs, verifyLocalIsolationReport } from './gofer-local-isolation.mjs';
|
|
12
|
+
|
|
13
|
+
const execFileAsync = promisify(execFile);
|
|
14
|
+
const text = value => typeof value === 'string' && value.trim().length > 0;
|
|
15
|
+
const QUALIFIED_LOCAL_ISOLATION = 'git-worktree+local-os-sandbox';
|
|
16
|
+
function processGroupAlive(processGroupId) {
|
|
17
|
+
try { process.kill(-processGroupId, 0); return true; }
|
|
18
|
+
catch (error) { return error?.code !== 'ESRCH'; }
|
|
19
|
+
}
|
|
20
|
+
const sameScope = (left, right) => Array.isArray(left) && Array.isArray(right) &&
|
|
21
|
+
left.length === right.length && left.every((value, index) => value === right[index]);
|
|
22
|
+
const gitEnvironment = Object.fromEntries(Object.entries(process.env).filter(([key]) =>
|
|
23
|
+
!['GIT_DIR', 'GIT_WORK_TREE', 'GIT_INDEX_FILE', 'GIT_COMMON_DIR'].includes(key)));
|
|
24
|
+
|
|
25
|
+
async function git(directory, args) {
|
|
26
|
+
return execFileAsync('git', ['-C', directory, ...args], { encoding: 'utf8', env: gitEnvironment });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function safeScope(scope) {
|
|
30
|
+
return text(scope) && !/(^\/|\\|\0|(^|\/)\.\.?(?:\/|$))/.test(scope);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function boundedCollector(limit = 1024 * 1024) {
|
|
34
|
+
let value = '';
|
|
35
|
+
return {
|
|
36
|
+
add(chunk) { value = `${value}${chunk}`.slice(-limit); },
|
|
37
|
+
value: () => value,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function tokenUsage(value) {
|
|
42
|
+
if (!value || typeof value !== 'object') return null;
|
|
43
|
+
const inputTokens = value.input_tokens ?? value.inputTokens;
|
|
44
|
+
const cachedInputTokens = value.cached_input_tokens ?? value.cachedInputTokens ?? 0;
|
|
45
|
+
const outputTokens = value.output_tokens ?? value.outputTokens;
|
|
46
|
+
if (![inputTokens, cachedInputTokens, outputTokens].every(item => Number.isInteger(item) && item >= 0)) return null;
|
|
47
|
+
return Object.freeze({ inputTokens, cachedInputTokens, outputTokens });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function extractTokenUsage(jsonl) {
|
|
51
|
+
const findings = [];
|
|
52
|
+
const visit = value => {
|
|
53
|
+
if (!value || typeof value !== 'object') return;
|
|
54
|
+
const direct = tokenUsage(value);
|
|
55
|
+
if (direct) findings.push(direct);
|
|
56
|
+
for (const item of Object.values(value)) visit(item);
|
|
57
|
+
};
|
|
58
|
+
for (const line of jsonl.split(/\r?\n/)) {
|
|
59
|
+
try { visit(JSON.parse(line)); } catch { /* Non-JSON host diagnostics are not usage evidence. */ }
|
|
60
|
+
}
|
|
61
|
+
return findings.at(-1) ?? null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The Codex host profile: what differs between hosts is only how a host is
|
|
65
|
+
* launched, how its sandbox is described, and how its result is read. The
|
|
66
|
+
* process-group evidence, Git baseline and scope checks are shared. */
|
|
67
|
+
export const CODEX_HOST = Object.freeze({
|
|
68
|
+
name: 'codex',
|
|
69
|
+
sandboxPolicy: workspace => codexIsolatedPermissionArgs(workspace),
|
|
70
|
+
buildArgs: ({ sandboxPolicy, outputPath, modelId, prompt }) => ['--ask-for-approval', 'never', 'exec',
|
|
71
|
+
'--ignore-user-config', ...sandboxPolicy.config.flatMap(value => ['-c', value]),
|
|
72
|
+
'--json', '--output-last-message', outputPath, '--model', modelId, prompt],
|
|
73
|
+
finalMessage: ({ outputPath }) => readFile(outputPath, 'utf8').catch(() => ''),
|
|
74
|
+
extractUsage: stdoutText => extractTokenUsage(stdoutText),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Start a real local host process in a pre-created isolated worktree. This
|
|
79
|
+
* primitive deliberately has no fallback host or cloud mode. Its receipt is
|
|
80
|
+
* only available after the child has exited, so a cancellation cannot be
|
|
81
|
+
* reported as confirmed while the host still owns the worktree.
|
|
82
|
+
*/
|
|
83
|
+
export async function startLocalHostInvocation({ host, isolatedWorkspace, prompt, modelId,
|
|
84
|
+
capabilityReceiptHash, allowedWriteScope, command, spawnProcess = spawn,
|
|
85
|
+
receiptDirectory = tmpdir(), evidenceDirectory, objectiveRevision, leaseId,
|
|
86
|
+
worktreeReceipt, expectedHead, signalProcessGroup = (pid, signal) => process.kill(-pid, signal),
|
|
87
|
+
usageReporting = false, hostOptions = {} } = {}) {
|
|
88
|
+
if (!/^[a-z]{3,16}$/.test(host?.name ?? '') || typeof host.sandboxPolicy !== 'function' ||
|
|
89
|
+
typeof host.buildArgs !== 'function' || typeof host.finalMessage !== 'function' ||
|
|
90
|
+
typeof host.extractUsage !== 'function') throw new Error('INVALID_NATIVE_HOST');
|
|
91
|
+
if (!text(isolatedWorkspace) || !text(prompt) || !text(modelId) || !text(capabilityReceiptHash) ||
|
|
92
|
+
!Array.isArray(allowedWriteScope) || !allowedWriteScope.length ||
|
|
93
|
+
allowedWriteScope.some(scope => !safeScope(scope)) || !text(command) ||
|
|
94
|
+
(evidenceDirectory && (![objectiveRevision, leaseId, worktreeReceipt].every(text)))) throw new Error('INVALID_NATIVE_REQUEST');
|
|
95
|
+
const workspace = await realpath(isolatedWorkspace);
|
|
96
|
+
const sandboxPolicy = host.sandboxPolicy(workspace, hostOptions);
|
|
97
|
+
if (!sandboxPolicy) throw new Error('LOCAL_SANDBOX_REQUIRED');
|
|
98
|
+
const outputRoot = await realpath(receiptDirectory);
|
|
99
|
+
// A clean file-status result does not reveal a commit or a new branch made
|
|
100
|
+
// by the worker. Capture both HEAD and shared refs before native execution.
|
|
101
|
+
const gitBaseline = await Promise.all([
|
|
102
|
+
git(workspace, ['rev-parse', 'HEAD']),
|
|
103
|
+
git(workspace, ['for-each-ref', '--format=%(refname) %(objectname)']),
|
|
104
|
+
]).then(([head, refs]) => ({ head: head.stdout.trim(), refs: refs.stdout })).catch(() => null);
|
|
105
|
+
if (expectedHead && gitBaseline?.head !== expectedHead) throw new Error('NATIVE_GIT_BASELINE_MISMATCH');
|
|
106
|
+
let evidenceRoot;
|
|
107
|
+
if (evidenceDirectory) {
|
|
108
|
+
if (process.platform === 'win32') throw new Error('NATIVE_PROCESS_GROUP_UNAVAILABLE');
|
|
109
|
+
const requested = path.join(await realpath(path.dirname(path.resolve(evidenceDirectory))),
|
|
110
|
+
path.basename(evidenceDirectory));
|
|
111
|
+
const requestedRelative = path.relative(workspace, requested);
|
|
112
|
+
if (requestedRelative === '' || (!requestedRelative.startsWith('..') && !path.isAbsolute(requestedRelative))) {
|
|
113
|
+
throw new Error('NATIVE_EVIDENCE_INSIDE_WORKTREE');
|
|
114
|
+
}
|
|
115
|
+
await mkdir(evidenceDirectory, { recursive: true, mode: 0o700 });
|
|
116
|
+
evidenceRoot = await realpath(evidenceDirectory);
|
|
117
|
+
const relative = path.relative(workspace, evidenceRoot);
|
|
118
|
+
if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) {
|
|
119
|
+
throw new Error('NATIVE_EVIDENCE_INSIDE_WORKTREE');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const outputPath = path.join(outputRoot, `gofer-${host.name}-${randomUUID()}.md`);
|
|
123
|
+
const args = host.buildArgs({ sandboxPolicy, outputPath, modelId, prompt, allowedWriteScope,
|
|
124
|
+
workspace, hostOptions });
|
|
125
|
+
const stdout = boundedCollector();
|
|
126
|
+
const stderr = boundedCollector();
|
|
127
|
+
let child;
|
|
128
|
+
let exit = null;
|
|
129
|
+
let cancelRequested = false;
|
|
130
|
+
let fatal = null;
|
|
131
|
+
let completion;
|
|
132
|
+
const invocationId = `${host.name}-${randomUUID()}`;
|
|
133
|
+
const evidencePath = evidenceRoot ? path.join(evidenceRoot, `native-worker-${invocationId}.jsonl`) : null;
|
|
134
|
+
const receiptFor = async () => {
|
|
135
|
+
const message = await host.finalMessage({ outputPath, stdout: stdout.value() });
|
|
136
|
+
return createHash('sha256').update(JSON.stringify({ invocationId, capabilityReceiptHash, modelId,
|
|
137
|
+
allowedWriteScope, exit, stdout: stdout.value(), stderr: stderr.value(), message })).digest('hex');
|
|
138
|
+
};
|
|
139
|
+
// A host may write a per-task policy file before it starts.
|
|
140
|
+
await host.beforeStart?.({ workspace, sandboxPolicy, hostOptions });
|
|
141
|
+
try {
|
|
142
|
+
child = spawnProcess(command, args, { cwd: workspace, shell: false, detached: Boolean(evidenceRoot),
|
|
143
|
+
stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true,
|
|
144
|
+
...(typeof host.env === 'function' ? { env: host.env(process.env) } : {}) });
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new Error(`NATIVE_HOST_START_FAILED:${error.message}`);
|
|
147
|
+
}
|
|
148
|
+
if (!child || typeof child.once !== 'function' || typeof child.kill !== 'function') throw new Error('NATIVE_HOST_START_FAILED');
|
|
149
|
+
if (evidencePath && (!Number.isSafeInteger(child.pid) || child.pid <= 0)) {
|
|
150
|
+
child.kill('SIGTERM');
|
|
151
|
+
throw new Error('NATIVE_PROCESS_ID_REQUIRED');
|
|
152
|
+
}
|
|
153
|
+
const startEvidence = evidencePath ? (async () => {
|
|
154
|
+
const file = await open(evidencePath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o600);
|
|
155
|
+
try {
|
|
156
|
+
await file.writeFile(`${JSON.stringify({ schemaVersion: 1, event: 'started', invocationId,
|
|
157
|
+
objectiveRevision, leaseId, worktreeReceipt, capabilityReceiptHash, modelId,
|
|
158
|
+
isolatedWorkspace: workspace, pid: child.pid, processGroupId: child.pid,
|
|
159
|
+
at: new Date().toISOString() })}\n`);
|
|
160
|
+
await file.sync();
|
|
161
|
+
} finally { await file.close(); }
|
|
162
|
+
})() : Promise.resolve();
|
|
163
|
+
child.stdout?.on('data', chunk => stdout.add(chunk));
|
|
164
|
+
child.stderr?.on('data', chunk => {
|
|
165
|
+
stderr.add(chunk);
|
|
166
|
+
// A sandbox that fails to apply must never be allowed to run unsandboxed.
|
|
167
|
+
if (!fatal && host.fatalStderr?.test(String(chunk))) {
|
|
168
|
+
fatal = 'NATIVE_HOST_SANDBOX_NOT_APPLIED';
|
|
169
|
+
// A single group signal can miss a child that was starting at that moment,
|
|
170
|
+
// so keep killing until the group is empty.
|
|
171
|
+
(async () => {
|
|
172
|
+
for (let attempt = 0; attempt < 30; attempt++) {
|
|
173
|
+
try { if (evidencePath) signalProcessGroup(child.pid, 'SIGKILL'); else child.kill('SIGKILL'); } catch { /* already gone */ }
|
|
174
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
175
|
+
if (evidencePath ? !processGroupAlive(child.pid) : exit !== null) return;
|
|
176
|
+
}
|
|
177
|
+
})();
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
completion = new Promise((resolve, reject) => {
|
|
181
|
+
child.once('error', error => reject(new Error(`NATIVE_HOST_START_FAILED:${error.message}`)));
|
|
182
|
+
child.once('close', async (code, signal) => {
|
|
183
|
+
exit = { code, signal };
|
|
184
|
+
// The host has stopped: remove anything it needed from the worktree.
|
|
185
|
+
try { await host.cleanup?.({ workspace, sandboxPolicy, hostOptions }); } catch { /* reported by the scope check */ }
|
|
186
|
+
try {
|
|
187
|
+
await startEvidence;
|
|
188
|
+
if (evidencePath) {
|
|
189
|
+
const file = await open(evidencePath, constants.O_WRONLY | constants.O_APPEND | constants.O_NOFOLLOW);
|
|
190
|
+
try {
|
|
191
|
+
await file.writeFile(`${JSON.stringify({ schemaVersion: 1, event: 'stopped', invocationId,
|
|
192
|
+
pid: child.pid, processGroupId: child.pid, cancelled: cancelRequested, exit, receipt: await receiptFor(),
|
|
193
|
+
at: new Date().toISOString() })}\n`);
|
|
194
|
+
await file.sync();
|
|
195
|
+
} finally { await file.close(); }
|
|
196
|
+
}
|
|
197
|
+
resolve();
|
|
198
|
+
} catch (error) { reject(error); }
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
await startEvidence.catch(error => {
|
|
202
|
+
if (evidencePath) signalProcessGroup(child.pid, 'SIGTERM');
|
|
203
|
+
else child.kill('SIGTERM');
|
|
204
|
+
throw new Error(`NATIVE_EVIDENCE_UNAVAILABLE:${error.message}`);
|
|
205
|
+
});
|
|
206
|
+
return Object.freeze({
|
|
207
|
+
invocationId,
|
|
208
|
+
evidencePath,
|
|
209
|
+
async cancel() {
|
|
210
|
+
if (exit !== null) throw new Error('CANCELLATION_ALREADY_EXITED');
|
|
211
|
+
cancelRequested = true;
|
|
212
|
+
if (exit === null) {
|
|
213
|
+
try {
|
|
214
|
+
if (evidencePath) signalProcessGroup(child.pid, 'SIGTERM');
|
|
215
|
+
else if (child.kill('SIGTERM') === false) throw new Error('CANCELLATION_DELIVERY_REQUIRED');
|
|
216
|
+
} catch { throw new Error('CANCELLATION_DELIVERY_REQUIRED'); }
|
|
217
|
+
}
|
|
218
|
+
await completion;
|
|
219
|
+
if (evidencePath) {
|
|
220
|
+
for (let attempt = 0; attempt < 20 && processGroupAlive(child.pid); attempt++) {
|
|
221
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
222
|
+
}
|
|
223
|
+
if (processGroupAlive(child.pid)) throw new Error('CANCELLATION_CONFIRMATION_REQUIRED');
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
async inspect() {
|
|
227
|
+
if (exit === null) return { invocationId, cancelled: false, receipt: null, state: 'running' };
|
|
228
|
+
await completion;
|
|
229
|
+
if (evidencePath && processGroupAlive(child.pid)) {
|
|
230
|
+
return { invocationId, cancelled: false, receipt: null, state: 'unresolved' };
|
|
231
|
+
}
|
|
232
|
+
return { invocationId, cancelled: cancelRequested, receipt: await receiptFor(), state: 'exited', exit: { ...exit } };
|
|
233
|
+
},
|
|
234
|
+
async wait() {
|
|
235
|
+
await completion;
|
|
236
|
+
const receipt = await receiptFor();
|
|
237
|
+
if (cancelRequested) {
|
|
238
|
+
if (evidencePath && processGroupAlive(child.pid)) throw new Error('CANCELLATION_CONFIRMATION_REQUIRED');
|
|
239
|
+
return { invocationId, capabilityReceiptHash, receipt, cancelled: true };
|
|
240
|
+
}
|
|
241
|
+
if (fatal) throw new Error(fatal);
|
|
242
|
+
if (exit?.code !== 0) throw new Error(`NATIVE_HOST_EXIT:${exit?.code ?? 'signal'}`);
|
|
243
|
+
host.assertSuccess?.(stdout.value(), stderr.value());
|
|
244
|
+
if (!gitBaseline) throw new Error('NATIVE_GIT_BASELINE_REQUIRED');
|
|
245
|
+
const [head, refs] = await Promise.all([
|
|
246
|
+
git(workspace, ['rev-parse', 'HEAD']),
|
|
247
|
+
git(workspace, ['for-each-ref', '--format=%(refname) %(objectname)']),
|
|
248
|
+
]);
|
|
249
|
+
if (head.stdout.trim() !== gitBaseline.head || refs.stdout !== gitBaseline.refs) {
|
|
250
|
+
throw new Error('NATIVE_UNAUTHORIZED_GIT_CHANGE');
|
|
251
|
+
}
|
|
252
|
+
await host.afterExit?.({ workspace, sandboxPolicy, hostOptions });
|
|
253
|
+
const status = await git(workspace, ['-c', 'status.renames=false', 'status', '--porcelain=v1', '-z',
|
|
254
|
+
'--untracked-files=all', '--ignored=matching']);
|
|
255
|
+
const entries = status.stdout.split('\0').filter(Boolean);
|
|
256
|
+
if (entries.some(entry => entry.length < 4 || entry[2] !== ' ')) throw new Error('NATIVE_STATUS_UNAVAILABLE');
|
|
257
|
+
const changedFiles = [...new Set(entries.map(entry => entry.slice(3)))];
|
|
258
|
+
if (changedFiles.some(file => !allowedWriteScope.some(scope => file === scope.replace(/\/$/, '') || file.startsWith(`${scope.replace(/\/$/, '')}/`)))) {
|
|
259
|
+
throw new Error('NATIVE_SCOPE_VIOLATION');
|
|
260
|
+
}
|
|
261
|
+
return Object.freeze({ invocationId, capabilityReceiptHash, receipt, changedFiles,
|
|
262
|
+
outputPath, isolation: QUALIFIED_LOCAL_ISOLATION,
|
|
263
|
+
usage: usageReporting ? host.extractUsage(stdout.value()) : undefined });
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Start a real local Codex process. Kept as the stable entry point. */
|
|
269
|
+
export function startLocalCodexInvocation(options = {}) {
|
|
270
|
+
return startLocalHostInvocation({ ...options, host: CODEX_HOST, command: options.command ?? 'codex' });
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** A missing, incomplete, or still-running process never becomes a stop proof. */
|
|
274
|
+
export async function inspectNativeWorkerEvidence({ evidenceDirectory, revision, journalHash,
|
|
275
|
+
authorizations, probeProcess = processGroupId => {
|
|
276
|
+
if (process.platform === 'win32') return true;
|
|
277
|
+
return processGroupAlive(processGroupId);
|
|
278
|
+
} } = {}) {
|
|
279
|
+
const denied = { allStopped: false, revision, journalHash, receipt: null };
|
|
280
|
+
if (![evidenceDirectory, revision, journalHash].every(text) || !Array.isArray(authorizations) ||
|
|
281
|
+
!authorizations.length || typeof probeProcess !== 'function') return denied;
|
|
282
|
+
let root;
|
|
283
|
+
try { root = await realpath(evidenceDirectory); } catch { return denied; }
|
|
284
|
+
const names = await readdir(root);
|
|
285
|
+
if (names.length > 1000 || names.some(name => !/^native-worker-(?:codex|claude|grok)-[0-9a-f-]+\.jsonl$/.test(name))) return denied;
|
|
286
|
+
const records = [];
|
|
287
|
+
for (const name of names) {
|
|
288
|
+
const file = await open(path.join(root, name), constants.O_RDONLY | constants.O_NOFOLLOW).catch(() => null);
|
|
289
|
+
if (!file) return denied;
|
|
290
|
+
let raw;
|
|
291
|
+
try {
|
|
292
|
+
const stat = await file.stat();
|
|
293
|
+
if (!stat.isFile() || stat.size > 65536) return denied;
|
|
294
|
+
raw = await file.readFile('utf8');
|
|
295
|
+
} finally { await file.close(); }
|
|
296
|
+
if (!raw.endsWith('\n')) return denied;
|
|
297
|
+
let events;
|
|
298
|
+
try { events = raw.trimEnd().split('\n').map(line => JSON.parse(line)); }
|
|
299
|
+
catch { return denied; }
|
|
300
|
+
if (events.length !== 2 || events[0]?.schemaVersion !== 1 || events[0].event !== 'started' ||
|
|
301
|
+
events[1]?.schemaVersion !== 1 || events[1].event !== 'stopped' ||
|
|
302
|
+
events[0].invocationId !== events[1].invocationId ||
|
|
303
|
+
events[0].pid !== events[1].pid || !Number.isSafeInteger(events[0].pid) || events[0].pid <= 0 ||
|
|
304
|
+
events[0].processGroupId !== events[0].pid || events[1].processGroupId !== events[0].pid ||
|
|
305
|
+
!text(events[1].receipt) || events[0].objectiveRevision !== revision) return denied;
|
|
306
|
+
if (await probeProcess(events[0].processGroupId) !== false) return denied;
|
|
307
|
+
records.push({ started: events[0], stopped: events[1] });
|
|
308
|
+
}
|
|
309
|
+
if (!records.length || authorizations.some(authority =>
|
|
310
|
+
!text(authority?.leaseId) || !text(authority?.worktreeReceipt) ||
|
|
311
|
+
records.filter(record => record.started.leaseId === authority.leaseId &&
|
|
312
|
+
record.started.capabilityReceiptHash === authority.capabilityReceiptHash &&
|
|
313
|
+
record.started.worktreeReceipt === authority.worktreeReceipt &&
|
|
314
|
+
(!authority.isolatedWorkspace || record.started.isolatedWorkspace === authority.isolatedWorkspace)).length !== 1)) return denied;
|
|
315
|
+
const receipt = `worker-stop:${createHash('sha256').update(JSON.stringify({ revision, journalHash,
|
|
316
|
+
records: records.map(record => ({ invocationId: record.started.invocationId,
|
|
317
|
+
leaseId: record.started.leaseId, pid: record.started.pid,
|
|
318
|
+
cancelled: record.stopped.cancelled, receipt: record.stopped.receipt }))
|
|
319
|
+
.sort((left, right) => left.invocationId.localeCompare(right.invocationId)) })).digest('hex')}`;
|
|
320
|
+
return { allStopped: true, revision, journalHash, receipt, workerCount: records.length,
|
|
321
|
+
cancelledLeases: records.filter(record => record.stopped.cancelled === true).map(record => record.started.leaseId) };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** Bind benchmark capture to the controller-owned worker evidence directory.
|
|
325
|
+
* Workers cannot choose the directory or declare their own stopped state. */
|
|
326
|
+
export function createNativeBenchmarkCaptureVerifier({ evidenceDirectory } = {}) {
|
|
327
|
+
if (!text(evidenceDirectory) || !path.isAbsolute(evidenceDirectory)) {
|
|
328
|
+
throw new Error('BENCHMARK_CAPTURE_EVIDENCE_REQUIRED');
|
|
329
|
+
}
|
|
330
|
+
return request => inspectNativeWorkerEvidence({ evidenceDirectory,
|
|
331
|
+
revision: request?.revision, journalHash: request?.journalHash,
|
|
332
|
+
authorizations: request?.runs?.map(run => ({ leaseId: run.leaseId,
|
|
333
|
+
capabilityReceiptHash: run.capabilityReceiptHash,
|
|
334
|
+
worktreeReceipt: run.worktreeReceipt,
|
|
335
|
+
isolatedWorkspace: run.isolatedWorkspace })) });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Adapt the verified graph's `execute` seam to a real Codex invocation. The
|
|
340
|
+
* caller supplies the durable ledger assertion; this adapter refuses to run
|
|
341
|
+
* if it cannot reproduce the graph's just-issued authority receipt. This
|
|
342
|
+
* prevents a caller from substituting a safe-looking local launcher after
|
|
343
|
+
* the graph has authorised a different task, scope, lease, or approval.
|
|
344
|
+
*/
|
|
345
|
+
export function createLedgerBoundCodexExecutor({ isolatedWorkspace, worktreeReceipt, expectedHead, capabilityReceipt, capabilityPublicKey,
|
|
346
|
+
requiredCapabilities, assertLedger, promptForRequest, start = startLocalCodexInvocation } = {}) {
|
|
347
|
+
if (!text(isolatedWorkspace) || !text(worktreeReceipt) || !capabilityReceipt || !capabilityPublicKey ||
|
|
348
|
+
typeof assertLedger !== 'function' || typeof promptForRequest !== 'function' || typeof start !== 'function') {
|
|
349
|
+
throw new Error('NATIVE_EXECUTOR_CONFIGURATION_REQUIRED');
|
|
350
|
+
}
|
|
351
|
+
return Object.freeze({
|
|
352
|
+
worktreeReceipt,
|
|
353
|
+
async execute(request) {
|
|
354
|
+
if (!request || !text(request.revision) || !text(request.taskId) || !text(request.ledgerAuthorityReceipt) ||
|
|
355
|
+
!text(request.selectedModel) || !Array.isArray(request.allowedEditScope) ||
|
|
356
|
+
request.worktreeReceipt !== worktreeReceipt) throw new Error('LEDGER_AUTHORITY_REQUIRED');
|
|
357
|
+
const prompt = await promptForRequest(Object.freeze({ ...request }));
|
|
358
|
+
if (!text(prompt)) throw new Error('NATIVE_PROMPT_REQUIRED');
|
|
359
|
+
return invokeLedgerBoundNative({
|
|
360
|
+
request: {
|
|
361
|
+
objectiveRevision: request.revision,
|
|
362
|
+
allowedWriteScope: request.allowedEditScope,
|
|
363
|
+
leaseId: request.leaseId,
|
|
364
|
+
budgetReservation: request.budgetReservation,
|
|
365
|
+
approvalReceipt: request.approvalReceipt,
|
|
366
|
+
worktreeReceipt,
|
|
367
|
+
usageReporting: request.usageReporting === true,
|
|
368
|
+
},
|
|
369
|
+
capabilityReceipt,
|
|
370
|
+
capabilityPublicKey,
|
|
371
|
+
requiredCapabilities,
|
|
372
|
+
assertLedger: async nativeRequest => {
|
|
373
|
+
const authority = await assertLedger(Object.freeze({ ...request, ...nativeRequest }));
|
|
374
|
+
if (authority?.receipt !== request.ledgerAuthorityReceipt) throw new Error('LEDGER_AUTHORITY_REQUIRED');
|
|
375
|
+
return authority;
|
|
376
|
+
},
|
|
377
|
+
start: nativeRequest => start({ isolatedWorkspace, expectedHead, prompt, modelId: request.selectedModel,
|
|
378
|
+
allowedWriteScope: request.allowedEditScope, ...nativeRequest }),
|
|
379
|
+
signal: request.signal,
|
|
380
|
+
});
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export async function createVerifiedWorktree({ workspaceRoot, host, localIsolation, baseRef = 'HEAD', temporaryRoot = tmpdir() } = {}) {
|
|
386
|
+
if (!text(workspaceRoot) || !text(baseRef) || baseRef.startsWith('-')) throw new Error('INVALID_ISOLATION_REQUEST');
|
|
387
|
+
if (typeof localIsolation !== 'function') throw new Error('LOCAL_SANDBOX_REQUIRED');
|
|
388
|
+
const workspace = await realpath(workspaceRoot);
|
|
389
|
+
const temporary = await realpath(temporaryRoot);
|
|
390
|
+
const relativeTemporary = path.relative(workspace, temporary);
|
|
391
|
+
if (relativeTemporary === '' || (!relativeTemporary.startsWith('..') && !path.isAbsolute(relativeTemporary))) {
|
|
392
|
+
throw new Error('ISOLATION_ROOT_INSIDE_WORKSPACE');
|
|
393
|
+
}
|
|
394
|
+
const repository = (await git(workspace, ['rev-parse', '--is-inside-work-tree'])).stdout.trim();
|
|
395
|
+
if (repository !== 'true') throw new Error('WORKSPACE_IS_NOT_GIT');
|
|
396
|
+
const destination = await mkdtemp(path.join(temporary, 'gofer-isolated-worktree-'));
|
|
397
|
+
try {
|
|
398
|
+
await git(workspace, ['worktree', 'add', '--detach', destination, baseRef]);
|
|
399
|
+
const isolated = await realpath(destination);
|
|
400
|
+
if (isolated === workspace) throw new Error('ISOLATION_PATH_REUSED');
|
|
401
|
+
const [head, expected] = await Promise.all([
|
|
402
|
+
git(isolated, ['rev-parse', 'HEAD']), git(workspace, ['rev-parse', baseRef]),
|
|
403
|
+
]);
|
|
404
|
+
if (head.stdout.trim() !== expected.stdout.trim()) throw new Error('ISOLATION_REVISION_MISMATCH');
|
|
405
|
+
const report = await localIsolation(Object.freeze({ host, workspaceRoot: isolated }));
|
|
406
|
+
if (!verifyLocalIsolationReport(report, { host, workspaceRoot: isolated }) ||
|
|
407
|
+
!text(report.nativeExecutable) || !path.isAbsolute(report.nativeExecutable)) {
|
|
408
|
+
throw new Error('LOCAL_SANDBOX_REQUIRED');
|
|
409
|
+
}
|
|
410
|
+
const status = await git(isolated, ['status', '--porcelain=v1', '--untracked-files=all', '--ignored=matching']);
|
|
411
|
+
if (status.stdout.trim() !== '') throw new Error('ISOLATION_PREFLIGHT_CHANGED_WORKTREE');
|
|
412
|
+
const receipt = worktreeReceipt(workspace, isolated, head.stdout.trim());
|
|
413
|
+
return Object.freeze({ isolationClass: 'git-worktree+local-os-sandbox', workspace, isolatedWorkspace: isolated,
|
|
414
|
+
nativeExecutable: report.nativeExecutable, revision: head.stdout.trim(), receipt });
|
|
415
|
+
} catch (error) {
|
|
416
|
+
await git(workspace, ['worktree', 'remove', '--force', destination]).catch(() => {});
|
|
417
|
+
throw error;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function worktreeReceipt(workspace, isolated, revision) {
|
|
422
|
+
return `git-worktree:${createHash('sha256').update(JSON.stringify({ workspace, isolated, revision })).digest('hex')}`;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Recheck a worktree before it is named in a cancellation reconciliation. */
|
|
426
|
+
export async function inspectVerifiedWorktree({ workspaceRoot, isolatedWorkspace, revision, receipt, requireClean = false } = {}) {
|
|
427
|
+
if (![workspaceRoot, isolatedWorkspace, revision, receipt].every(text)) return { valid: false };
|
|
428
|
+
const workspace = await realpath(workspaceRoot);
|
|
429
|
+
const isolated = await realpath(isolatedWorkspace);
|
|
430
|
+
if (workspace === isolated || worktreeReceipt(workspace, isolated, revision) !== receipt) return { valid: false };
|
|
431
|
+
const [head, listed, status] = await Promise.all([
|
|
432
|
+
git(isolated, ['rev-parse', 'HEAD']),
|
|
433
|
+
git(workspace, ['worktree', 'list', '--porcelain']),
|
|
434
|
+
git(isolated, ['status', '--porcelain=v1', '--untracked-files=all', '--ignored=matching']),
|
|
435
|
+
]);
|
|
436
|
+
const comparablePath = value => process.platform === 'win32'
|
|
437
|
+
? path.normalize(value.trim()).toLowerCase() : path.normalize(value.trim());
|
|
438
|
+
const registered = [...listed.stdout.matchAll(/^worktree (.+)$/gm)]
|
|
439
|
+
.some(match => comparablePath(match[1]) === comparablePath(isolated));
|
|
440
|
+
const clean = status.stdout.trim() === '';
|
|
441
|
+
if (!registered || head.stdout.trim() !== revision || (requireClean && !clean)) return { valid: false };
|
|
442
|
+
return Object.freeze({ valid: true, receipt, revision, isolatedWorkspace: isolated, clean,
|
|
443
|
+
statusHash: createHash('sha256').update(status.stdout).digest('hex') });
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/** Remove only a matching, clean task worktree after its controller has closed. */
|
|
447
|
+
export async function disposeVerifiedWorktree({ workspaceRoot, isolatedWorkspace, revision, receipt } = {}) {
|
|
448
|
+
const inspection = await inspectVerifiedWorktree({ workspaceRoot, isolatedWorkspace,
|
|
449
|
+
revision, receipt, requireClean: true });
|
|
450
|
+
if (!inspection.valid) throw new Error('WORKTREE_DISPOSAL_REQUIRES_CLEAN_VERIFIED_STATE');
|
|
451
|
+
await git(workspaceRoot, ['worktree', 'remove', isolatedWorkspace]);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** Bind ledger cancellation authority to independently inspected local state. */
|
|
455
|
+
export function createNativeCancellationVerifier({ workspaceRoot, abandonedWorkspace,
|
|
456
|
+
replacementWorkspace, worktreeRevision, evidenceDirectory, inspectInputRevision } = {}) {
|
|
457
|
+
if (![workspaceRoot, abandonedWorkspace, replacementWorkspace, worktreeRevision, evidenceDirectory].every(text) ||
|
|
458
|
+
typeof inspectInputRevision !== 'function') throw new Error('NATIVE_CANCELLATION_VERIFIER_CONFIGURATION_REQUIRED');
|
|
459
|
+
return async request => {
|
|
460
|
+
const denied = { valid: false };
|
|
461
|
+
if (![request?.taskId, request?.revision, request?.leaseId, request?.journalHash,
|
|
462
|
+
request?.workerStopReceipt, request?.abandonedWorktreeReceipt,
|
|
463
|
+
request?.replacementWorktreeReceipt, request?.capabilityReceiptHash,
|
|
464
|
+
request?.inputRevision].every(text)) return denied;
|
|
465
|
+
try {
|
|
466
|
+
const [oldWorktree, newWorktree, evidenceRoot] = await Promise.all([
|
|
467
|
+
inspectVerifiedWorktree({ workspaceRoot, isolatedWorkspace: abandonedWorkspace,
|
|
468
|
+
revision: worktreeRevision, receipt: request.abandonedWorktreeReceipt }),
|
|
469
|
+
inspectVerifiedWorktree({ workspaceRoot, isolatedWorkspace: replacementWorkspace,
|
|
470
|
+
revision: worktreeRevision, receipt: request.replacementWorktreeReceipt, requireClean: true }),
|
|
471
|
+
realpath(evidenceDirectory),
|
|
472
|
+
]);
|
|
473
|
+
if (!oldWorktree.valid || !newWorktree.valid ||
|
|
474
|
+
oldWorktree.isolatedWorkspace === newWorktree.isolatedWorkspace ||
|
|
475
|
+
oldWorktree.receipt === newWorktree.receipt) return denied;
|
|
476
|
+
for (const worktree of [oldWorktree, newWorktree]) {
|
|
477
|
+
const relative = path.relative(worktree.isolatedWorkspace, evidenceRoot);
|
|
478
|
+
if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return denied;
|
|
479
|
+
}
|
|
480
|
+
const workers = await inspectNativeWorkerEvidence({ evidenceDirectory: evidenceRoot,
|
|
481
|
+
revision: request.revision, journalHash: request.journalHash,
|
|
482
|
+
authorizations: [{ leaseId: request.leaseId,
|
|
483
|
+
capabilityReceiptHash: request.capabilityReceiptHash,
|
|
484
|
+
worktreeReceipt: request.abandonedWorktreeReceipt,
|
|
485
|
+
isolatedWorkspace: oldWorktree.isolatedWorkspace }] });
|
|
486
|
+
if (!workers.allStopped || workers.receipt !== request.workerStopReceipt ||
|
|
487
|
+
!workers.cancelledLeases.includes(request.leaseId)) return denied;
|
|
488
|
+
const currentInput = await inspectInputRevision(Object.freeze({ taskId: request.taskId,
|
|
489
|
+
revision: request.revision, isolatedWorkspace: newWorktree.isolatedWorkspace,
|
|
490
|
+
worktreeReceipt: newWorktree.receipt }));
|
|
491
|
+
if (currentInput !== request.inputRevision) return denied;
|
|
492
|
+
return { ...request, valid: true };
|
|
493
|
+
} catch { return denied; }
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Execute only after a ledger service binds the exact objective revision,
|
|
499
|
+
* scope, receipt hash, lease, budget and approval state. Cancellation must be
|
|
500
|
+
* delivered and independently confirmed before an aborted invocation returns.
|
|
501
|
+
*/
|
|
502
|
+
export async function invokeLedgerBoundNative({ request, capabilityReceipt, capabilityPublicKey,
|
|
503
|
+
requiredCapabilities, assertLedger, start, signal } = {}) {
|
|
504
|
+
if (!request || !capabilityReceipt || typeof assertLedger !== 'function' || typeof start !== 'function' ||
|
|
505
|
+
!text(request.objectiveRevision) || !Array.isArray(request.allowedWriteScope) || !text(request.leaseId) ||
|
|
506
|
+
!text(request.budgetReservation) || !text(request.approvalReceipt)) throw new Error('LEDGER_AUTHORITY_REQUIRED');
|
|
507
|
+
if (capabilityReceipt?.isolationClass !== QUALIFIED_LOCAL_ISOLATION ||
|
|
508
|
+
!verifyCapabilityReceipt(capabilityReceipt, { publicKey: capabilityPublicKey,
|
|
509
|
+
host: 'codex', requiredCapabilities })) {
|
|
510
|
+
throw new Error('CAPABILITY_RECEIPT_REQUIRED');
|
|
511
|
+
}
|
|
512
|
+
const receiptHash = capabilityReceiptHash(capabilityReceipt);
|
|
513
|
+
const authority = await assertLedger({ ...request, capabilityReceiptHash: receiptHash });
|
|
514
|
+
if (authority?.allowed !== true || authority.objectiveRevision !== request.objectiveRevision ||
|
|
515
|
+
authority.capabilityReceiptHash !== receiptHash || authority.leaseId !== request.leaseId ||
|
|
516
|
+
authority.budgetReservation !== request.budgetReservation || authority.approvalReceipt !== request.approvalReceipt ||
|
|
517
|
+
authority.worktreeReceipt !== request.worktreeReceipt ||
|
|
518
|
+
!sameScope(authority.allowedWriteScope, request.allowedWriteScope) ||
|
|
519
|
+
authority.isolation !== capabilityReceipt.isolationClass) {
|
|
520
|
+
throw new Error('LEDGER_AUTHORITY_REQUIRED');
|
|
521
|
+
}
|
|
522
|
+
const invocation = await start(Object.freeze({ ...request, capabilityReceiptHash: receiptHash }));
|
|
523
|
+
if (!text(invocation?.invocationId) || typeof invocation.wait !== 'function' || typeof invocation.cancel !== 'function' ||
|
|
524
|
+
typeof invocation.inspect !== 'function') {
|
|
525
|
+
if (typeof invocation?.cancel === 'function') await invocation.cancel();
|
|
526
|
+
if (typeof invocation?.inspect === 'function') {
|
|
527
|
+
const state = await invocation.inspect();
|
|
528
|
+
if (state?.invocationId !== invocation.invocationId || state?.cancelled !== true || !text(state?.receipt)) {
|
|
529
|
+
throw new Error('CANCELLATION_CONFIRMATION_REQUIRED');
|
|
530
|
+
}
|
|
531
|
+
} else if (invocation) {
|
|
532
|
+
throw new Error('CANCELLATION_CONFIRMATION_REQUIRED');
|
|
533
|
+
}
|
|
534
|
+
throw new Error('NATIVE_INVOCATION_REQUIRED');
|
|
535
|
+
}
|
|
536
|
+
let cancelPromise;
|
|
537
|
+
const cancel = () => {
|
|
538
|
+
if (!cancelPromise) {
|
|
539
|
+
cancelPromise = (async () => {
|
|
540
|
+
await invocation.cancel();
|
|
541
|
+
const state = await invocation.inspect();
|
|
542
|
+
if (state?.invocationId !== invocation.invocationId || state?.cancelled !== true || !text(state?.receipt)) {
|
|
543
|
+
throw new Error('CANCELLATION_CONFIRMATION_REQUIRED');
|
|
544
|
+
}
|
|
545
|
+
})();
|
|
546
|
+
}
|
|
547
|
+
return cancelPromise;
|
|
548
|
+
};
|
|
549
|
+
if (signal?.aborted) await cancel();
|
|
550
|
+
const listener = () => { cancel().catch(() => {}); };
|
|
551
|
+
signal?.addEventListener('abort', listener, { once: true });
|
|
552
|
+
try {
|
|
553
|
+
const result = await invocation.wait();
|
|
554
|
+
if (signal?.aborted) await cancel();
|
|
555
|
+
if (cancelPromise) {
|
|
556
|
+
await cancelPromise;
|
|
557
|
+
throw new Error('NATIVE_INVOCATION_CANCELLED');
|
|
558
|
+
}
|
|
559
|
+
if (result?.invocationId !== invocation.invocationId || result?.capabilityReceiptHash !== receiptHash || !text(result?.receipt)) {
|
|
560
|
+
throw new Error('NATIVE_INVOCATION_UNVERIFIED');
|
|
561
|
+
}
|
|
562
|
+
return Object.freeze({ ...result, capabilityReceiptHash: receiptHash, isolation: authority.isolation });
|
|
563
|
+
} finally {
|
|
564
|
+
signal?.removeEventListener('abort', listener);
|
|
565
|
+
if (cancelPromise) await cancelPromise;
|
|
566
|
+
}
|
|
567
|
+
}
|