@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,435 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { constants } from 'fs';
|
|
4
|
+
import { promises as fs } from 'fs';
|
|
5
|
+
import { execFile, spawn } from 'child_process';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import process from 'process';
|
|
8
|
+
import { promisify } from 'util';
|
|
9
|
+
|
|
10
|
+
const SECRET_RELATIVE_PATH = path.join('.specify', 'secrets', 'typesafe.env');
|
|
11
|
+
const POLICY_RELATIVE_PATHS = [
|
|
12
|
+
path.join('.specify', 'config', 'typesafe-semantic-review.json'),
|
|
13
|
+
path.join('.specify', 'config', 'typesafe-learning-review.json'),
|
|
14
|
+
];
|
|
15
|
+
const KEYCHAIN_SERVICE = 'com.enterpriseai.gofer.jev';
|
|
16
|
+
const KEYCHAIN_ACCOUNT = 'shared-api-key';
|
|
17
|
+
const execFileAsync = promisify(execFile);
|
|
18
|
+
|
|
19
|
+
export function parseArgs(argv) {
|
|
20
|
+
const action = argv.find((value) => value === '--connect' || value === '--disconnect' || value === '--status');
|
|
21
|
+
const scopeIndex = argv.indexOf('--scope');
|
|
22
|
+
const scope = scopeIndex === -1 ? (process.platform === 'darwin' ? 'shared' : 'project') : argv[scopeIndex + 1];
|
|
23
|
+
const expectedLength = scopeIndex === -1 ? 1 : 3;
|
|
24
|
+
if (!action || argv.length !== expectedLength || !['project', 'shared'].includes(scope)) {
|
|
25
|
+
throw new Error('Usage: --connect | --disconnect | --status [--scope project|shared]');
|
|
26
|
+
}
|
|
27
|
+
if (action === '--status' && scopeIndex !== -1) {
|
|
28
|
+
throw new Error('--status reports the effective credential and does not accept --scope.');
|
|
29
|
+
}
|
|
30
|
+
return { action: action.slice(2), scope };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const macOSKeychain = {
|
|
34
|
+
async has() {
|
|
35
|
+
if (process.platform !== 'darwin') return false;
|
|
36
|
+
try {
|
|
37
|
+
await execFileAsync('/usr/bin/security', [
|
|
38
|
+
'find-generic-password', '-a', KEYCHAIN_ACCOUNT, '-s', KEYCHAIN_SERVICE,
|
|
39
|
+
], { encoding: 'utf8', maxBuffer: 64 * 1024 });
|
|
40
|
+
return true;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error?.code === 44 || error?.stderr?.includes('could not be found')) return false;
|
|
43
|
+
throw new Error('Gofer could not check the shared Jev credential in macOS Keychain.');
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
async read() {
|
|
47
|
+
if (process.platform !== 'darwin') return '';
|
|
48
|
+
try {
|
|
49
|
+
const { stdout } = await execFileAsync('/usr/bin/security', [
|
|
50
|
+
'find-generic-password', '-a', KEYCHAIN_ACCOUNT, '-s', KEYCHAIN_SERVICE, '-w',
|
|
51
|
+
], { encoding: 'utf8', maxBuffer: 64 * 1024 });
|
|
52
|
+
return String(stdout).trim();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error?.code === 44 || error?.stderr?.includes('could not be found')) return '';
|
|
55
|
+
throw new Error('Gofer could not read the shared Jev credential from macOS Keychain.');
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
async write(key) {
|
|
59
|
+
if (process.platform !== 'darwin') throw new Error('Shared Jev credentials require macOS Keychain.');
|
|
60
|
+
const encoded = Buffer.from(String(key), 'utf8').toString('hex');
|
|
61
|
+
const child = spawn('/usr/bin/security', ['-i'], { stdio: ['pipe', 'ignore', 'pipe'] });
|
|
62
|
+
let stderr = '';
|
|
63
|
+
child.stderr.on('data', (chunk) => {
|
|
64
|
+
if (stderr.length < 64 * 1024) stderr += chunk.toString('utf8');
|
|
65
|
+
});
|
|
66
|
+
child.stdin.end(
|
|
67
|
+
`add-generic-password -a "${KEYCHAIN_ACCOUNT}" -s "${KEYCHAIN_SERVICE}" ` +
|
|
68
|
+
`-l "EAI Gofer Jev API key" -U -X ${encoded}\n`
|
|
69
|
+
);
|
|
70
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
71
|
+
child.once('error', reject);
|
|
72
|
+
child.once('exit', (code) => resolve(code));
|
|
73
|
+
});
|
|
74
|
+
if (exitCode !== 0 || stderr.includes('SecKeychainItem')) {
|
|
75
|
+
throw new Error('macOS Keychain did not save the shared Jev credential.');
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
async remove() {
|
|
79
|
+
if (process.platform !== 'darwin') return false;
|
|
80
|
+
try {
|
|
81
|
+
await execFileAsync('/usr/bin/security', [
|
|
82
|
+
'delete-generic-password', '-a', KEYCHAIN_ACCOUNT, '-s', KEYCHAIN_SERVICE,
|
|
83
|
+
]);
|
|
84
|
+
return true;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (error?.code === 44 || error?.stderr?.includes('could not be found')) return false;
|
|
87
|
+
throw new Error('Gofer could not remove the shared Jev credential from macOS Keychain.');
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// A lexical check alone does not stop a symlinked intermediate directory
|
|
93
|
+
// (e.g. .specify/secrets) from redirecting the confined path outside the
|
|
94
|
+
// workspace. Walk every component from the workspace root and reject any
|
|
95
|
+
// that is a symlink, matching gofer-surface-update.mjs's existing check.
|
|
96
|
+
async function assertNoSymlinkComponents(root, relativeTarget) {
|
|
97
|
+
const components = relativeTarget.split(path.sep).filter(Boolean);
|
|
98
|
+
let currentPath = root;
|
|
99
|
+
for (const component of components) {
|
|
100
|
+
currentPath = path.join(currentPath, component);
|
|
101
|
+
try {
|
|
102
|
+
const status = await fs.lstat(currentPath);
|
|
103
|
+
if (status.isSymbolicLink()) {
|
|
104
|
+
throw new Error('Gofer credential path must not pass through a symbolic link.');
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (error?.code === 'ENOENT') return;
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// assertNoSymlinkComponents only walks descendants of root; it never checks
|
|
114
|
+
// root itself. A caller-supplied workspace that is a symlink (or missing, or
|
|
115
|
+
// not a directory) would otherwise sail through every confinement check
|
|
116
|
+
// below it. Matches workspace-bootstrap-lib.mjs's assertSafeWorkspaceRoot.
|
|
117
|
+
async function assertSafeWorkspaceRoot(workspaceRoot) {
|
|
118
|
+
const resolvedRoot = path.resolve(workspaceRoot);
|
|
119
|
+
const rootStat = await fs.lstat(resolvedRoot).catch((error) => {
|
|
120
|
+
if (error?.code === 'ENOENT') return null;
|
|
121
|
+
throw error;
|
|
122
|
+
});
|
|
123
|
+
if (!rootStat) throw new Error('Gofer workspace root does not exist.');
|
|
124
|
+
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
|
125
|
+
throw new Error('Gofer workspace root must be a real directory, not a symbolic link.');
|
|
126
|
+
}
|
|
127
|
+
return resolvedRoot;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function confinedPath(workspace, relativePath) {
|
|
131
|
+
const root = await assertSafeWorkspaceRoot(workspace);
|
|
132
|
+
const target = path.resolve(root, relativePath);
|
|
133
|
+
const relative = path.relative(root, target);
|
|
134
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
|
|
135
|
+
throw new Error('Gofer credential path must remain inside the workspace.');
|
|
136
|
+
}
|
|
137
|
+
await assertNoSymlinkComponents(root, relative);
|
|
138
|
+
return target;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function existingFile(target) {
|
|
142
|
+
try {
|
|
143
|
+
const stat = await fs.lstat(target);
|
|
144
|
+
if (stat.isSymbolicLink() || !stat.isFile()) throw new Error('Gofer credential path must be a regular file.');
|
|
145
|
+
return true;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (error?.code === 'ENOENT') return false;
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// O_NOFOLLOW is unavailable on Windows; the bitwise OR silently contributes
|
|
153
|
+
// nothing there rather than erroring. lstat detects a symlink or junction
|
|
154
|
+
// cross-platform (including Windows) and is the actual protection;
|
|
155
|
+
// O_NOFOLLOW only closes the small remaining gap between that check and the
|
|
156
|
+
// open, on platforms that support it.
|
|
157
|
+
const noFollowFlag = process.platform === 'win32' ? 0 : constants.O_NOFOLLOW;
|
|
158
|
+
function sameIdentity(left, right) {
|
|
159
|
+
if (left.dev === undefined || left.ino === undefined ||
|
|
160
|
+
right.dev === undefined || right.ino === undefined) return true;
|
|
161
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function withVerifiedParent(target, action) {
|
|
165
|
+
const parent = path.dirname(target);
|
|
166
|
+
const parentHandle = await fs.open(parent,
|
|
167
|
+
constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | noFollowFlag);
|
|
168
|
+
const openedParent = await parentHandle.stat();
|
|
169
|
+
try {
|
|
170
|
+
const currentParent = await fs.lstat(parent);
|
|
171
|
+
if (!openedParent.isDirectory() || currentParent.isSymbolicLink() ||
|
|
172
|
+
!sameIdentity(openedParent, currentParent)) {
|
|
173
|
+
throw new Error('Gofer credential parent directory changed during access.');
|
|
174
|
+
}
|
|
175
|
+
const result = await action();
|
|
176
|
+
const parentAfter = await fs.lstat(parent);
|
|
177
|
+
if (parentAfter.isSymbolicLink() || !sameIdentity(openedParent, parentAfter)) {
|
|
178
|
+
throw new Error('Gofer credential parent directory changed during access.');
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
} finally {
|
|
182
|
+
await parentHandle.close();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function assertNotSymlink(target) {
|
|
187
|
+
const info = await fs.lstat(target).catch((error) => {
|
|
188
|
+
if (error?.code === 'ENOENT') return null;
|
|
189
|
+
throw error;
|
|
190
|
+
});
|
|
191
|
+
if (info?.isSymbolicLink()) throw new Error('Gofer credential path must not be a symbolic link.');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// The static confinement check happens before the caller ever opens the file;
|
|
195
|
+
// a same-account process could still swap a symlink in between. The lstat
|
|
196
|
+
// check immediately before opening, plus O_NOFOLLOW where available, closes
|
|
197
|
+
// that window instead of merely trusting the earlier confinedPath check.
|
|
198
|
+
async function readNoFollow(target) {
|
|
199
|
+
return withVerifiedParent(target, async () => {
|
|
200
|
+
await assertNotSymlink(target);
|
|
201
|
+
const handle = await fs.open(target, constants.O_RDONLY | noFollowFlag);
|
|
202
|
+
try {
|
|
203
|
+
const opened = await handle.stat();
|
|
204
|
+
const current = await fs.lstat(target);
|
|
205
|
+
if (!opened.isFile() || current.isSymbolicLink() || !sameIdentity(opened, current)) {
|
|
206
|
+
throw new Error('Gofer credential path must be a stable regular file.');
|
|
207
|
+
}
|
|
208
|
+
return await handle.readFile('utf8');
|
|
209
|
+
} finally { await handle.close(); }
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function writeNoFollow(target, content, mode) {
|
|
214
|
+
return withVerifiedParent(target, async () => {
|
|
215
|
+
await assertNotSymlink(target);
|
|
216
|
+
const handle = await fs.open(target,
|
|
217
|
+
constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | noFollowFlag, mode);
|
|
218
|
+
try {
|
|
219
|
+
const opened = await handle.stat();
|
|
220
|
+
const current = await fs.lstat(target);
|
|
221
|
+
if (!opened.isFile() || current.isSymbolicLink() || !sameIdentity(opened, current)) {
|
|
222
|
+
throw new Error('Gofer credential path must be a stable regular file.');
|
|
223
|
+
}
|
|
224
|
+
await handle.writeFile(content);
|
|
225
|
+
await handle.sync();
|
|
226
|
+
} finally { await handle.close(); }
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function unlinkNoFollow(target) {
|
|
231
|
+
return withVerifiedParent(target, async () => {
|
|
232
|
+
const before = await fs.lstat(target);
|
|
233
|
+
if (before.isSymbolicLink() || !before.isFile()) {
|
|
234
|
+
throw new Error('Gofer credential path must be a regular file.');
|
|
235
|
+
}
|
|
236
|
+
await fs.unlink(target);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function ensurePrivateParent(target) {
|
|
241
|
+
const parent = path.dirname(target);
|
|
242
|
+
const grandparent = path.dirname(parent);
|
|
243
|
+
const grandparentHandle = await fs.open(grandparent,
|
|
244
|
+
constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | noFollowFlag);
|
|
245
|
+
const openedGrandparent = await grandparentHandle.stat();
|
|
246
|
+
try {
|
|
247
|
+
const currentGrandparent = await fs.lstat(grandparent);
|
|
248
|
+
if (!openedGrandparent.isDirectory() || currentGrandparent.isSymbolicLink() ||
|
|
249
|
+
!sameIdentity(openedGrandparent, currentGrandparent)) {
|
|
250
|
+
throw new Error('Gofer credential parent directory changed during setup.');
|
|
251
|
+
}
|
|
252
|
+
await fs.mkdir(parent, { mode: 0o700 }).catch((error) => {
|
|
253
|
+
if (error?.code !== 'EEXIST') throw error;
|
|
254
|
+
});
|
|
255
|
+
const parentHandle = await fs.open(parent,
|
|
256
|
+
constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | noFollowFlag);
|
|
257
|
+
try {
|
|
258
|
+
const openedParent = await parentHandle.stat();
|
|
259
|
+
const [parentCurrent, grandparentAfter] = await Promise.all([
|
|
260
|
+
fs.lstat(parent),
|
|
261
|
+
fs.lstat(grandparent),
|
|
262
|
+
]);
|
|
263
|
+
if (!openedParent.isDirectory() || parentCurrent.isSymbolicLink() ||
|
|
264
|
+
!sameIdentity(openedParent, parentCurrent) || grandparentAfter.isSymbolicLink() ||
|
|
265
|
+
!sameIdentity(openedGrandparent, grandparentAfter)) {
|
|
266
|
+
throw new Error('Gofer credential parent directory changed during setup.');
|
|
267
|
+
}
|
|
268
|
+
await parentHandle.chmod(0o700);
|
|
269
|
+
} finally {
|
|
270
|
+
await parentHandle.close();
|
|
271
|
+
}
|
|
272
|
+
} finally {
|
|
273
|
+
await grandparentHandle.close();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async function readSecretFile(secretPath) {
|
|
278
|
+
if (!(await existingFile(secretPath))) return '';
|
|
279
|
+
const match = (await readNoFollow(secretPath)).match(/^TYPESAFE_API_KEY=([^\r\n]+)$/m);
|
|
280
|
+
return match?.[1]?.trim() || '';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function writePolicyEnabled(workspace, enabled) {
|
|
284
|
+
for (const relativePath of POLICY_RELATIVE_PATHS) {
|
|
285
|
+
const policyPath = await confinedPath(workspace, relativePath);
|
|
286
|
+
// Older Gofer workspaces have only the semantic-review policy. Keep
|
|
287
|
+
// connect/disconnect compatible until workspace bootstrap adds the
|
|
288
|
+
// reviewed-learning policy.
|
|
289
|
+
if (!(await existingFile(policyPath))) continue;
|
|
290
|
+
const current = JSON.parse(await readNoFollow(policyPath));
|
|
291
|
+
current.enabled = enabled;
|
|
292
|
+
await writeNoFollow(policyPath, `${JSON.stringify(current, null, 2)}\n`, 0o600);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function promptForKey() {
|
|
297
|
+
if (!process.stdin.isTTY) throw new Error('Set TYPESAFE_API_KEY, then run --connect from an interactive terminal.');
|
|
298
|
+
process.stdout.write('TypeSafe API key: ');
|
|
299
|
+
const key = await new Promise((resolve, reject) => {
|
|
300
|
+
let value = '';
|
|
301
|
+
process.stdin.setRawMode(true);
|
|
302
|
+
process.stdin.resume();
|
|
303
|
+
process.stdin.on('data', (chunk) => {
|
|
304
|
+
const character = chunk.toString('utf8');
|
|
305
|
+
if (character === '\r' || character === '\n') {
|
|
306
|
+
process.stdin.setRawMode(false);
|
|
307
|
+
process.stdin.pause();
|
|
308
|
+
process.stdout.write('\n');
|
|
309
|
+
resolve(value);
|
|
310
|
+
} else if (character === '\u0003') {
|
|
311
|
+
process.stdin.setRawMode(false);
|
|
312
|
+
reject(new Error('Credential setup cancelled.'));
|
|
313
|
+
} else if (character === '\u007f') {
|
|
314
|
+
value = value.slice(0, -1);
|
|
315
|
+
} else {
|
|
316
|
+
value += character;
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
return String(key).trim();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export async function credentialStatus({ workspace = process.cwd(), env = process.env, keychain = macOSKeychain } = {}) {
|
|
324
|
+
const { source } = await resolveApiKey({ workspace, env, keychain });
|
|
325
|
+
return {
|
|
326
|
+
configured: source !== 'none',
|
|
327
|
+
source,
|
|
328
|
+
secretPath: source === 'project_secret_file' ? SECRET_RELATIVE_PATH : null,
|
|
329
|
+
sharedAcrossLocalWorkspaces: source === 'macos_keychain',
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export async function resolveApiKey({ workspace = process.cwd(), env = process.env, keychain = macOSKeychain } = {}) {
|
|
334
|
+
const environmentKey = String(env.TYPESAFE_API_KEY || '').trim();
|
|
335
|
+
if (environmentKey) return { apiKey: environmentKey, source: 'environment' };
|
|
336
|
+
const fileKey = await readSecretFile(await confinedPath(workspace, SECRET_RELATIVE_PATH));
|
|
337
|
+
if (fileKey) return { apiKey: fileKey, source: 'project_secret_file' };
|
|
338
|
+
if (env.GOFER_DISABLE_SHARED_CREDENTIALS !== '1') {
|
|
339
|
+
const sharedKey = String(await keychain.read()).trim();
|
|
340
|
+
if (sharedKey) return { apiKey: sharedKey, source: 'macos_keychain' };
|
|
341
|
+
}
|
|
342
|
+
return { apiKey: '', source: 'none' };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export async function sharedCredentialConfigured({ keychain = macOSKeychain } = {}) {
|
|
346
|
+
return keychain.has();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export async function requestTypeSafeEvaluation({ workspace, env = process.env, fetchImpl = globalThis.fetch, policy, projection, rubric, keychain = macOSKeychain }) {
|
|
350
|
+
const { apiKey, source } = await resolveApiKey({ workspace, env, keychain });
|
|
351
|
+
if (!apiKey) return { status: 'not_configured', networkCalled: false };
|
|
352
|
+
let response;
|
|
353
|
+
try {
|
|
354
|
+
response = await fetchImpl(policy.endpoint, {
|
|
355
|
+
method: 'POST',
|
|
356
|
+
headers: { authorization: `Bearer ${apiKey}`, 'content-type': 'application/json' },
|
|
357
|
+
signal: AbortSignal.timeout(policy.timeoutMs),
|
|
358
|
+
body: JSON.stringify({ model: policy.model, state: JSON.stringify(projection), questions: rubric }),
|
|
359
|
+
});
|
|
360
|
+
} catch (error) {
|
|
361
|
+
return {
|
|
362
|
+
status: 'unavailable',
|
|
363
|
+
networkCalled: true,
|
|
364
|
+
reason: ['AbortError', 'TimeoutError'].includes(error?.name) ? 'timeout' : 'network_error',
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
if (!response.ok) return { status: 'unavailable', networkCalled: true, httpStatus: response.status };
|
|
368
|
+
try {
|
|
369
|
+
if (!response.body?.getReader) throw new Error('response body is not streamable');
|
|
370
|
+
const reader = response.body.getReader();
|
|
371
|
+
const chunks = [];
|
|
372
|
+
let bytes = 0;
|
|
373
|
+
while (true) {
|
|
374
|
+
const { done, value } = await reader.read();
|
|
375
|
+
if (done) break;
|
|
376
|
+
bytes += value.byteLength;
|
|
377
|
+
if (bytes > 2 * 1024 * 1024) {
|
|
378
|
+
await reader.cancel('response too large');
|
|
379
|
+
throw new Error('response too large');
|
|
380
|
+
}
|
|
381
|
+
chunks.push(Buffer.from(value));
|
|
382
|
+
}
|
|
383
|
+
const raw = Buffer.concat(chunks, bytes).toString('utf8');
|
|
384
|
+
return { status: 'received', networkCalled: true, credentialSource: source, payload: JSON.parse(raw) };
|
|
385
|
+
} catch {
|
|
386
|
+
return { status: 'unavailable', networkCalled: true, reason: 'invalid_response' };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export async function connect({ workspace = process.cwd(), key } = {}) {
|
|
391
|
+
const secretPath = await confinedPath(workspace, SECRET_RELATIVE_PATH);
|
|
392
|
+
const resolvedKey = String(key || process.env.TYPESAFE_API_KEY || '').trim() || await promptForKey();
|
|
393
|
+
if (!resolvedKey) throw new Error('TypeSafe API key cannot be empty.');
|
|
394
|
+
await ensurePrivateParent(secretPath);
|
|
395
|
+
if (await existingFile(secretPath)) await fs.chmod(secretPath, 0o600);
|
|
396
|
+
await writeNoFollow(secretPath, `TYPESAFE_API_KEY=${resolvedKey}\n`, 0o600);
|
|
397
|
+
await fs.chmod(secretPath, 0o600);
|
|
398
|
+
await writePolicyEnabled(workspace, true);
|
|
399
|
+
return { configured: true, source: process.env.TYPESAFE_API_KEY ? 'environment' : 'project_secret_file', secretPath: SECRET_RELATIVE_PATH };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export async function connectShared({ workspace = process.cwd(), key, keychain = macOSKeychain } = {}) {
|
|
403
|
+
await assertSafeWorkspaceRoot(workspace);
|
|
404
|
+
const resolvedKey = String(key || process.env.TYPESAFE_API_KEY || '').trim() || await promptForKey();
|
|
405
|
+
if (!resolvedKey) throw new Error('TypeSafe API key cannot be empty.');
|
|
406
|
+
await keychain.write(resolvedKey);
|
|
407
|
+
const stored = String(await keychain.read()).trim();
|
|
408
|
+
if (!stored) throw new Error('macOS Keychain saved no Jev credential.');
|
|
409
|
+
return { configured: true, source: 'macos_keychain', secretPath: null, sharedAcrossLocalWorkspaces: true };
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export async function disconnect({ workspace = process.cwd() } = {}) {
|
|
413
|
+
const secretPath = await confinedPath(workspace, SECRET_RELATIVE_PATH);
|
|
414
|
+
const existed = await existingFile(secretPath);
|
|
415
|
+
if (existed) await unlinkNoFollow(secretPath);
|
|
416
|
+
await writePolicyEnabled(workspace, false);
|
|
417
|
+
return { removedProjectSecret: existed, environmentStillConfigured: Boolean(process.env.TYPESAFE_API_KEY), secretPath: SECRET_RELATIVE_PATH };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export async function disconnectShared({ workspace = process.cwd(), keychain = macOSKeychain } = {}) {
|
|
421
|
+
await assertSafeWorkspaceRoot(workspace);
|
|
422
|
+
const removed = await keychain.remove();
|
|
423
|
+
return { removedSharedCredential: removed, source: 'macos_keychain', sharedAcrossLocalWorkspaces: false };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async function main() {
|
|
427
|
+
const { action, scope } = parseArgs(process.argv.slice(2));
|
|
428
|
+
const result = action === 'status' ? await credentialStatus()
|
|
429
|
+
: action === 'connect' && scope === 'shared' ? await connectShared()
|
|
430
|
+
: action === 'disconnect' && scope === 'shared' ? await disconnectShared()
|
|
431
|
+
: action === 'connect' ? await connect() : await disconnect();
|
|
432
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (import.meta.url === `file://${process.argv[1]}`) main().catch((error) => { process.stderr.write(`${error.message}\n`); process.exitCode = 1; });
|