heyspex 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +14 -0
- package/README.md +21 -0
- package/bin/hs.mjs +1089 -104
- package/bin/spexcode.mjs +262 -0
- package/dev-factory/engine/worktree.mjs +740 -0
- package/dev-factory/lib/code-repo-root.mjs +67 -0
- package/dev-factory/lib/context-budget.mjs +84 -0
- package/dev-factory/lib/epic-detect.mjs +190 -0
- package/dev-factory/lib/fleet-queue-file.mjs +846 -0
- package/dev-factory/lib/fleet-queue.mjs +426 -0
- package/dev-factory/lib/fleet-state.mjs +14 -18
- package/dev-factory/lib/model-catalog.mjs +338 -0
- package/dev-factory/lib/seat-context.mjs +199 -0
- package/dev-factory/lib/spec-io.mjs +93 -0
- package/dev-factory/lib/sufficiency-score.mjs +8 -2
- package/dev-factory/lib/worktree-allocator.mjs +744 -0
- package/dev-factory/model-catalog.json +222 -0
- package/dist/cli/hs-check.mjs +1127 -103
- package/dist/cli/hs-claim.mjs +981 -63
- package/dist/cli/hs-connect.mjs +10059 -1729
- package/dist/cli/hs-defer.mjs +5507 -3072
- package/dist/cli/hs-dev.mjs +576 -0
- package/dist/cli/hs-env.mjs +416 -302
- package/dist/cli/hs-index-rebuild.mjs +7334 -0
- package/dist/cli/hs-index-reconcile.mjs +8138 -0
- package/dist/cli/hs-init.mjs +2840 -149
- package/dist/cli/hs-install.mjs +7214 -594
- package/dist/cli/hs-join.mjs +10640 -2421
- package/dist/cli/hs-vault-pull.mjs +8157 -6370
- package/dist/cli/hs-vault-push.mjs +6433 -0
- package/dist/cli/hs-vault.mjs +4029 -1555
- package/dist/cli/hs-workspace.mjs +2702 -538
- package/dist/cli-templates/customer-vault/specs/entity-model.md +594 -601
- package/dist/cli-templates/customer-vault/specs/protocols/canonical-frontmatter-templates.md +110 -177
- package/dist/cli-templates/customer-vault/specs/protocols/destructive-action-checklist.md +122 -0
- package/dist/cli-templates/customer-vault/specs/protocols/memory-protocol.md +13 -15
- package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +91 -0
- package/dist/cli-templates/customer-vault/specs/protocols/spec-hierarchy.md +150 -168
- package/dist/cli-templates/customer-vault/specs/protocols/spec-summary-authoring.md +83 -0
- package/dist/cli-templates/harness-commands/claude/hs-auto.md +36 -0
- package/dist/cli-templates/harness-commands/claude/hs-backfill.md +28 -0
- package/dist/cli-templates/harness-commands/claude/hs-capture.md +62 -0
- package/dist/cli-templates/harness-commands/claude/hs-defer.md +29 -0
- package/dist/cli-templates/harness-commands/claude/hs-dev.md +20 -0
- package/dist/cli-templates/harness-commands/claude/hs-doctor.md +32 -0
- package/dist/cli-templates/harness-commands/claude/hs-ground.md +30 -0
- package/dist/cli-templates/harness-commands/claude/hs-handoff.md +33 -0
- package/dist/cli-templates/harness-commands/claude/hs-log.md +27 -0
- package/dist/cli-templates/harness-commands/claude/hs-next.md +29 -0
- package/dist/cli-templates/harness-commands/claude/hs-promote.md +70 -0
- package/dist/cli-templates/harness-commands/claude/hs-push.md +35 -0
- package/dist/cli-templates/harness-commands/claude/hs-qc.md +27 -0
- package/dist/cli-templates/harness-commands/claude/hs-res.md +63 -0
- package/dist/cli-templates/harness-commands/claude/hs-resolve.md +23 -0
- package/dist/cli-templates/harness-commands/claude/hs-review.md +23 -0
- package/dist/cli-templates/harness-commands/claude/hs-view.md +28 -0
- package/dist/cli-templates/harness-commands/claude/kill-ports.md +32 -0
- package/dist/cli-templates/harness-commands/claude/prototype.md +91 -0
- package/dist/cli-templates/harness-commands/cursor/hs-auto.md +40 -0
- package/dist/cli-templates/harness-commands/cursor/hs-backfill.md +31 -0
- package/dist/cli-templates/harness-commands/cursor/hs-capture.md +65 -0
- package/dist/cli-templates/harness-commands/cursor/hs-defer.md +32 -0
- package/dist/cli-templates/harness-commands/cursor/hs-dev.md +24 -0
- package/dist/cli-templates/harness-commands/cursor/hs-doctor.md +36 -0
- package/dist/cli-templates/harness-commands/cursor/hs-ground.md +33 -0
- package/dist/cli-templates/harness-commands/cursor/hs-handoff.md +37 -0
- package/dist/cli-templates/harness-commands/cursor/hs-log.md +31 -0
- package/dist/cli-templates/harness-commands/cursor/hs-next.md +32 -0
- package/dist/cli-templates/harness-commands/cursor/hs-promote.md +73 -0
- package/dist/cli-templates/harness-commands/cursor/hs-push.md +38 -0
- package/dist/cli-templates/harness-commands/cursor/hs-qc.md +30 -0
- package/dist/cli-templates/harness-commands/cursor/hs-res.md +67 -0
- package/dist/cli-templates/harness-commands/cursor/hs-resolve.md +26 -0
- package/dist/cli-templates/harness-commands/cursor/hs-review.md +26 -0
- package/dist/cli-templates/harness-commands/cursor/hs-view.md +32 -0
- package/dist/cli-templates/harness-commands/cursor/kill-ports.md +35 -0
- package/dist/cli-templates/harness-commands/cursor/prototype.md +95 -0
- package/docs/copilot-plugin-install.md +162 -0
- package/docs/driving-heyspex-from-copilot.md +165 -0
- package/docs/mcp-client-config.md +259 -6
- package/package.json +249 -124
- package/plugins/heyspex/.claude-plugin/plugin.json +12 -0
- package/plugins/heyspex/.cursor-plugin/plugin.json +15 -0
- package/plugins/heyspex/.mcp.json +12 -0
- package/plugins/heyspex/README.md +309 -0
- package/plugins/heyspex/bin/launch-mcp.mjs +95 -0
- package/plugins/heyspex/bin/run-hook.mjs +80 -0
- package/plugins/heyspex/hooks/cursor-hooks.json +308 -0
- package/plugins/heyspex/hooks/hooks.json +418 -0
- package/plugins/heyspex/mcp.json +13 -0
- package/scripts/check-mcp-freshness.mjs +17 -9
- package/scripts/claude-hooks/_env-vault-events.mjs +68 -0
- package/scripts/claude-hooks/_guardrail-events.mjs +96 -0
- package/scripts/claude-hooks/_guardrail-loader.mjs +494 -0
- package/scripts/claude-hooks/_intent-classifier-router.mjs +456 -0
- package/scripts/claude-hooks/_intent-classifier-semantic.mjs +356 -0
- package/scripts/claude-hooks/_run.mjs +413 -0
- package/scripts/claude-hooks/_transcript-text.mjs +60 -0
- package/scripts/claude-hooks/_vault-retrieval.mjs +322 -0
- package/scripts/claude-hooks/agent-spawn-delegation-gate.mjs +133 -0
- package/scripts/claude-hooks/capture-execution-gate.mjs +51 -0
- package/scripts/claude-hooks/capture-workflow-gate.mjs +11 -0
- package/scripts/claude-hooks/check-auto-memory-budget.mjs +396 -0
- package/scripts/claude-hooks/check-claude-md-budget.mjs +327 -0
- package/scripts/claude-hooks/check-mcp-freshness-hook.mjs +14 -0
- package/scripts/claude-hooks/claim-before-code-gate.mjs +11 -0
- package/scripts/claude-hooks/claim-liveness-shared.mjs +577 -0
- package/scripts/claude-hooks/close-terminal-on-ship.mjs +64 -0
- package/scripts/claude-hooks/coo-denylist-gate.mjs +11 -0
- package/scripts/claude-hooks/coo-guard-check.mjs +11 -0
- package/scripts/claude-hooks/deep-research-cost-gate.mjs +11 -0
- package/scripts/claude-hooks/dev-server-task-reminder.mjs +15 -0
- package/scripts/claude-hooks/diagnose-capture-reminder.mjs +11 -0
- package/scripts/claude-hooks/directive-obligation-gate.mjs +11 -0
- package/scripts/claude-hooks/emit-claim-status.mjs +41 -0
- package/scripts/claude-hooks/enforce-session-sequence.mjs +11 -0
- package/scripts/claude-hooks/enforce-vault-naming.mjs +11 -0
- package/scripts/claude-hooks/env-vault-guard.mjs +11 -0
- package/scripts/claude-hooks/epic-milestone-phrasing-gate.mjs +11 -0
- package/scripts/claude-hooks/git-identity-guard.mjs +11 -0
- package/scripts/claude-hooks/git-reflog-audit.mjs +15 -0
- package/scripts/claude-hooks/git-stash-gate.mjs +11 -0
- package/scripts/claude-hooks/guard-auto-memory-writes.mjs +137 -0
- package/scripts/claude-hooks/id-display-format-gate.mjs +11 -0
- package/scripts/claude-hooks/inject-communication-style.mjs +86 -0
- package/scripts/claude-hooks/inject-coo-seat.mjs +78 -0
- package/scripts/claude-hooks/inject-dev-server-awareness.mjs +11 -0
- package/scripts/claude-hooks/inject-doctrine.mjs +13 -0
- package/scripts/claude-hooks/inject-vault-context.mjs +14 -0
- package/scripts/claude-hooks/intent-classifier-trigger.mjs +279 -0
- package/scripts/claude-hooks/log-session-activity.mjs +341 -0
- package/scripts/claude-hooks/naughty-list-gate.mjs +11 -0
- package/scripts/claude-hooks/notify-status-flip.mjs +72 -0
- package/scripts/claude-hooks/plan-exit-ingest-gate.mjs +170 -0
- package/scripts/claude-hooks/plan-ingest-close-reminder.mjs +66 -0
- package/scripts/claude-hooks/plan-review-gate.mjs +11 -0
- package/scripts/claude-hooks/preflight-reminder.mjs +262 -0
- package/scripts/claude-hooks/protected-action-intent.mjs +221 -0
- package/scripts/claude-hooks/research-method-guard.mjs +398 -0
- package/scripts/claude-hooks/research-protocol-gate.mjs +11 -0
- package/scripts/claude-hooks/session-end.mjs +451 -0
- package/scripts/claude-hooks/settings-write-gate.mjs +11 -0
- package/scripts/claude-hooks/settlement-check-gate.mjs +39 -0
- package/scripts/claude-hooks/status-flip-detect.mjs +17 -0
- package/scripts/claude-hooks/terminal-close-shared.mjs +426 -0
- package/scripts/claude-hooks/terminal-close-watcher.mjs +122 -0
- package/scripts/claude-hooks/vault-mirror-catchup.mjs +11 -0
- package/scripts/claude-hooks/vault-write-tier-guard.mjs +11 -0
- package/scripts/claude-hooks/wip-checkpoint.mjs +302 -0
- package/scripts/cursor-hooks/manifest.mjs +281 -0
- package/scripts/dev-server-status.mjs +34 -13
- package/scripts/dev-server-stop.mjs +313 -0
- package/scripts/heyspex-mode.mjs +288 -0
- package/scripts/hs-auto-resolve.mjs +240 -0
- package/scripts/hs-auto-source.mjs +398 -0
- package/scripts/hs-auto.mjs +134 -0
- package/scripts/hs-capture-cli.mjs +326 -0
- package/scripts/hs-classifier.mjs +136 -0
- package/scripts/hs-companion.mjs +88 -0
- package/scripts/hs-gateway.mjs +115 -0
- package/scripts/hs-mode.mjs +125 -0
- package/scripts/hs-next.mjs +441 -0
- package/scripts/hs-settings.mjs +338 -0
- package/scripts/hs-view.mjs +496 -0
- package/scripts/hs-worktree.mjs +201 -0
- package/scripts/install-claude-code-hooks.mjs +272 -0
- package/scripts/install-cursor-hooks.mjs +471 -0
- package/scripts/lib/agent-env-markers.mjs +38 -0
- package/scripts/lib/console-url-resolver.mjs +199 -61
- package/scripts/lib/customer-kit.mjs +1203 -0
- package/scripts/lib/dev-mode.mjs +249 -32
- package/scripts/lib/directive-obligations.mjs +349 -0
- package/scripts/lib/heyspex-home.mjs +72 -0
- package/scripts/lib/hook-dispositions.mjs +210 -0
- package/scripts/lib/hook-vault-header.mjs +30 -0
- package/scripts/lib/hs-command.mjs +277 -0
- package/scripts/lib/hs-companion-settings.mjs +472 -0
- package/scripts/lib/hs-source-branch.mjs +196 -0
- package/scripts/lib/hs-source-commit.mjs +59 -5
- package/scripts/lib/hs-source-identity.mjs +526 -0
- package/scripts/lib/hs-source-log.mjs +13 -22
- package/scripts/lib/hs-source-preflight.mjs +18 -4
- package/scripts/lib/hs-source-push.mjs +386 -307
- package/scripts/lib/hs-worktree-args.mjs +115 -0
- package/scripts/lib/shared-path-helpers.mjs +134 -0
- package/scripts/lib/standalone-doctor.mjs +540 -3
- package/scripts/lib/subagent-git-lock.mjs +109 -0
- package/scripts/lib/template-pin.mjs +34 -0
- package/scripts/lib/window-placement.mjs +109 -0
- package/scripts/provenance-lib.mjs +91 -0
- package/scripts/stamp-provenance-on-edit.mjs +222 -0
- package/scripts/wip-ledger-health.mjs +653 -0
- package/spexharness/doctrine/baseline/SPEXCODE-DOCTRINE.baseline.json +29 -0
- package/spexharness/src/adapters/audit.mjs +197 -0
- package/spexharness/src/adapters/claude-code.mjs +449 -0
- package/spexharness/src/adapters/copilot.mjs +236 -0
- package/spexharness/src/adapters/detect-harness.mjs +34 -0
- package/spexharness/src/chat/tui/ansi.mjs +448 -0
- package/spexharness/src/chat/tui/palette.mjs +22 -0
- package/spexharness/src/chat/tui/select.mjs +208 -0
- package/spexharness/src/config-root.mjs +54 -0
- package/spexharness/src/context-budget.mjs +141 -0
- package/spexharness/src/dev-server-control.mjs +389 -0
- package/spexharness/src/doctrine/behaviour.mjs +371 -0
- package/spexharness/src/doctrine/corpus.mjs +733 -0
- package/spexharness/src/doctrine/inject.mjs +338 -0
- package/spexharness/src/doctrine/merge.mjs +184 -0
- package/spexharness/src/doctrine/sources.mjs +252 -0
- package/spexharness/src/doctrine/synthesize.mjs +401 -0
- package/spexharness/src/doctrine/vault-source.mjs +574 -0
- package/spexharness/src/doctrine/writer.mjs +176 -0
- package/spexharness/src/events.mjs +84 -0
- package/spexharness/src/gates/_shell-write-targets.mjs +77 -0
- package/spexharness/src/gates/capture-workflow-gate.mjs +202 -0
- package/spexharness/src/gates/claim-before-code-gate.decide.mjs +33 -0
- package/spexharness/src/gates/claim-before-code-gate.mjs +129 -0
- package/spexharness/src/gates/deep-research-cost-gate.mjs +275 -0
- package/spexharness/src/gates/diagnose-capture-reminder.mjs +112 -0
- package/spexharness/src/gates/directive-obligation-gate.decide.mjs +132 -0
- package/spexharness/src/gates/directive-obligation-gate.mjs +183 -0
- package/spexharness/src/gates/enforce-session-sequence.mjs +895 -0
- package/spexharness/src/gates/enforce-vault-naming.mjs +215 -0
- package/spexharness/src/gates/epic-milestone-phrasing-gate.mjs +233 -0
- package/spexharness/src/gates/git-identity-guard.decide.mjs +436 -0
- package/spexharness/src/gates/git-identity-guard.mjs +61 -0
- package/spexharness/src/gates/git-reflog-audit.mjs +151 -0
- package/spexharness/src/gates/git-stash-gate.decide.mjs +361 -0
- package/spexharness/src/gates/git-stash-gate.mjs +159 -0
- package/spexharness/src/gates/id-display-format-gate.mjs +190 -0
- package/spexharness/src/gates/inject-doctrine-gate.mjs +89 -0
- package/spexharness/src/gates/inject-vault-context.mjs +239 -0
- package/spexharness/src/gates/naughty-list-gate.mjs +213 -0
- package/spexharness/src/gates/plan-review-gate.mjs +233 -0
- package/spexharness/src/gates/preflight-reminder-gate.mjs +265 -0
- package/spexharness/src/gates/research-protocol-gate.mjs +175 -0
- package/spexharness/src/gates/settings-write-gate.decide.mjs +96 -0
- package/spexharness/src/gates/settings-write-gate.mjs +104 -0
- package/spexharness/src/gates/vault-mirror-catchup.mjs +124 -0
- package/spexharness/src/gates/vault-write-tier-guard.decide.mjs +125 -0
- package/spexharness/src/gates/vault-write-tier-guard.mjs +42 -0
- package/spexharness/src/git-reflog-audit.mjs +294 -0
- package/spexharness/src/intent-classifier.mjs +196 -0
- package/spexharness/src/intent-directive.mjs +626 -0
- package/spexharness/src/profile/learn.mjs +551 -0
- package/spexharness/src/profile/proposals.mjs +357 -0
- package/spexharness/src/profile/vault-inclusion.mjs +386 -0
- package/spexharness/src/redact.mjs +151 -0
- package/spexharness/src/rule-table.mjs +849 -0
- package/spexharness/src/seat-context.mjs +122 -0
- package/spexharness/src/session-bootstrap.mjs +512 -0
- package/spexharness/src/session-record.mjs +815 -0
- package/spexharness/src/token-inventory.mjs +207 -0
- package/vendor/heyspex-mcp/account-switch.mjs +96 -0
- package/vendor/heyspex-mcp/alignment-gate.mjs +315 -1
- package/vendor/heyspex-mcp/blocker-resolver.mjs +37 -2
- package/vendor/heyspex-mcp/breakdown-ladder.mjs +119 -4
- package/vendor/heyspex-mcp/breakdown-source.mjs +271 -0
- package/vendor/heyspex-mcp/breakdown-writer.mjs +23 -3
- package/vendor/heyspex-mcp/capture-buffer-patches.mjs +77 -8
- package/vendor/heyspex-mcp/capture-channel.mjs +55 -5
- package/vendor/heyspex-mcp/capture-console-client.mjs +117 -3
- package/vendor/heyspex-mcp/capture-focus.mjs +1061 -31
- package/vendor/heyspex-mcp/capture-outbox.mjs +15 -5
- package/vendor/heyspex-mcp/capture-sources.mjs +195 -0
- package/vendor/heyspex-mcp/capture-tools.mjs +1264 -0
- package/vendor/heyspex-mcp/claim-tools.mjs +1147 -0
- package/vendor/heyspex-mcp/cli-verbs.mjs +2074 -0
- package/vendor/heyspex-mcp/cli.mjs +207 -15524
- package/vendor/heyspex-mcp/close-branch-report.mjs +102 -0
- package/vendor/heyspex-mcp/cloud-tool-surface.mjs +128 -0
- package/vendor/heyspex-mcp/cloud-vault-writes.mjs +602 -0
- package/vendor/heyspex-mcp/config-seed.yaml +15 -0
- package/vendor/heyspex-mcp/config-settings.mjs +290 -7
- package/vendor/heyspex-mcp/console-fetch.mjs +822 -17
- package/vendor/heyspex-mcp/console-transport.mjs +172 -0
- package/vendor/heyspex-mcp/credentials.mjs +585 -0
- package/vendor/heyspex-mcp/defer-spec.mjs +44 -4
- package/vendor/heyspex-mcp/deferred-reclaim.mjs +29 -3
- package/vendor/heyspex-mcp/design-handlers.mjs +31 -0
- package/vendor/heyspex-mcp/design-tools.mjs +4 -1
- package/vendor/heyspex-mcp/dev-factory-bridge.mjs +4 -4
- package/vendor/heyspex-mcp/dev-mode-core.mjs +45 -0
- package/vendor/heyspex-mcp/dev-tools.mjs +131 -0
- package/vendor/heyspex-mcp/diagnose-handlers.mjs +54 -0
- package/vendor/heyspex-mcp/events-tools.mjs +207 -0
- package/vendor/heyspex-mcp/filing-tools.mjs +723 -0
- package/vendor/heyspex-mcp/fleet-handlers.mjs +37 -0
- package/vendor/heyspex-mcp/fleet-queue-tools.mjs +71 -15
- package/vendor/heyspex-mcp/focus-tools.mjs +190 -0
- package/vendor/heyspex-mcp/folder-trust-store.mjs +60 -0
- package/vendor/heyspex-mcp/http-transport.mjs +302 -0
- package/vendor/heyspex-mcp/list-tools.mjs +257 -0
- package/vendor/heyspex-mcp/login-handoff.mjs +15 -1
- package/vendor/heyspex-mcp/mcp-config.mjs +107 -0
- package/vendor/heyspex-mcp/memory-tools.mjs +523 -0
- package/vendor/heyspex-mcp/mvp-mode.mjs +53 -6
- package/vendor/heyspex-mcp/obligation-backstop.mjs +103 -0
- package/vendor/heyspex-mcp/occupied-keys.mjs +142 -0
- package/vendor/heyspex-mcp/on-deck-brief.mjs +3377 -0
- package/vendor/heyspex-mcp/on-deck-scheduler.mjs +1708 -0
- package/vendor/heyspex-mcp/package-root.mjs +32 -0
- package/vendor/heyspex-mcp/peer-presence.mjs +8 -1
- package/vendor/heyspex-mcp/plan-ground.mjs +621 -652
- package/vendor/heyspex-mcp/plan-push.mjs +908 -22
- package/vendor/heyspex-mcp/plan-review.mjs +124 -30
- package/vendor/heyspex-mcp/preflight-gate.mjs +0 -0
- package/vendor/heyspex-mcp/procedure-handlers.mjs +327 -0
- package/vendor/heyspex-mcp/procedure-tools.mjs +1181 -970
- package/vendor/heyspex-mcp/promote-capture.mjs +388 -69
- package/vendor/heyspex-mcp/promote-diagnose.mjs +74 -0
- package/vendor/heyspex-mcp/promote-research-to-diagnose.mjs +9 -2
- package/vendor/heyspex-mcp/promote-research.mjs +666 -53
- package/vendor/heyspex-mcp/promotion-helpers.mjs +251 -0
- package/vendor/heyspex-mcp/prompts.mjs +1460 -0
- package/vendor/heyspex-mcp/read-path.mjs +191 -15
- package/vendor/heyspex-mcp/receipt-shape.mjs +146 -0
- package/vendor/heyspex-mcp/recipe-handlers.mjs +117 -0
- package/vendor/heyspex-mcp/regen-tasks.mjs +210 -3
- package/vendor/heyspex-mcp/register-spec.mjs +266 -54
- package/vendor/heyspex-mcp/request-context.mjs +83 -0
- package/vendor/heyspex-mcp/research-focus.mjs +207 -4
- package/vendor/heyspex-mcp/research-handlers.mjs +625 -0
- package/vendor/heyspex-mcp/research-tools.mjs +4 -4
- package/vendor/heyspex-mcp/response-budget.mjs +348 -0
- package/vendor/heyspex-mcp/review-focus.mjs +25 -1
- package/vendor/heyspex-mcp/roadmap-default.mjs +70 -0
- package/vendor/heyspex-mcp/search-specs.mjs +280 -0
- package/vendor/heyspex-mcp/seat-block-ledger.mjs +113 -0
- package/vendor/heyspex-mcp/seat-identity.mjs +2 -6
- package/vendor/heyspex-mcp/session-owner.mjs +109 -0
- package/vendor/heyspex-mcp/session-tools.mjs +162 -0
- package/vendor/heyspex-mcp/settings-registry.mjs +232 -0
- package/vendor/heyspex-mcp/settings-tools.mjs +85 -12
- package/vendor/heyspex-mcp/spec-edit-tools.mjs +453 -0
- package/vendor/heyspex-mcp/spec-id-lib.mjs +93 -17
- package/vendor/heyspex-mcp/split-research.mjs +304 -56
- package/vendor/heyspex-mcp/stdio-rpc.mjs +22 -0
- package/vendor/heyspex-mcp/submit-for-review.mjs +150 -7
- package/vendor/heyspex-mcp/summary-contract.mjs +105 -0
- package/vendor/heyspex-mcp/summary-write-tools.mjs +228 -0
- package/vendor/heyspex-mcp/symptom-query.mjs +146 -0
- package/vendor/heyspex-mcp/test-helpers.mjs +123 -1
- package/vendor/heyspex-mcp/tool-catalog.mjs +2819 -0
- package/vendor/heyspex-mcp/tool-dispatch.mjs +657 -0
- package/vendor/heyspex-mcp/tool-helpers.mjs +325 -0
- package/vendor/heyspex-mcp/validate-linkage.mjs +414 -27
- package/vendor/heyspex-mcp/vault-io.mjs +720 -0
- package/vendor/heyspex-mcp/vault-less-endpoints.mjs +52 -0
- package/vendor/heyspex-mcp/vault-resolve.mjs +554 -68
- package/vendor/heyspex-mcp/verify-reproduction.mjs +270 -30
- package/vendor/heyspex-mcp/whoami.mjs +92 -0
- package/vendor/heyspex-mcp/write-outbox.mjs +512 -0
package/scripts/lib/dev-mode.mjs
CHANGED
|
@@ -19,6 +19,15 @@
|
|
|
19
19
|
* (~/.heyspex/dev-mode.json) → cloud admin setting (account_settings.dev_mode,
|
|
20
20
|
* injected by the caller — this module never talks to Neon) → default prod.
|
|
21
21
|
*
|
|
22
|
+
* ONE HOME ([[HS-R0YM-WW9R-TASK-publish-the-routing-fact-table-test]], routing
|
|
23
|
+
* fact G in `spex-console/src/lib/cli/routing-facts.ts`): the cloud
|
|
24
|
+
* `account_settings.dev_mode` row is the home of the mode. `dev-mode.json` is a
|
|
25
|
+
* machine-local CACHE of it (owner decision: kept as a cache, not deleted),
|
|
26
|
+
* validated by the `hs doctor` `mode-override` row, which names the file's
|
|
27
|
+
* writer and date and fails when it disagrees with a known cloud setting.
|
|
28
|
+
* Both implementations are held to the one precedence table in
|
|
29
|
+
* `./dev-mode.fixtures.mjs`.
|
|
30
|
+
*
|
|
22
31
|
* MACHINE-LOCAL RECORD — CROSS-COMPONENT CONTRACT (the Windows Companion
|
|
23
32
|
* reads the same file; keep the shape exactly this):
|
|
24
33
|
* ~/.heyspex/dev-mode.json
|
|
@@ -28,19 +37,29 @@
|
|
|
28
37
|
* Env overrides:
|
|
29
38
|
* HEYSPEX_DEV_MODE = prod | dev | local | cloud (local/cloud imply dev)
|
|
30
39
|
* HEYSPEX_DEV_RELIANCE = local | cloud (refines HEYSPEX_DEV_MODE=dev)
|
|
40
|
+
* `HEYSPEX_DEV_MODE=dev` with no reliance still resolves local, but the
|
|
41
|
+
* envelope reports `sources.reliance: "assumed-local"` — never silently.
|
|
42
|
+
*
|
|
43
|
+
* Any active switch (env or file) is reported as ONE structured object by
|
|
44
|
+
* `modeOverrideOf(resolved)` — `hs dev --json`, `hs doctor --json` and the MCP
|
|
45
|
+
* `heyspex_dev_mode` all carry it as `mode_override`
|
|
46
|
+
* ([[HS-EVVI-WW9R-TASK-show-any-dev-mode-override-in-hs-dev]]).
|
|
31
47
|
*
|
|
32
48
|
* Zero deps beyond node builtins (same rule as console-url-resolver.mjs).
|
|
33
49
|
*/
|
|
50
|
+
import { heyspexHome } from './heyspex-home.mjs';
|
|
34
51
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
35
52
|
import { homedir } from 'node:os';
|
|
36
53
|
import { join } from 'node:path';
|
|
37
54
|
|
|
55
|
+
import { assertNotRealHomeUnderTest, readBearer } from '../../vendor/heyspex-mcp/credentials.mjs';
|
|
56
|
+
|
|
38
57
|
export const CLOUD_CONSOLE_URL = 'https://app.heyspex.com';
|
|
39
58
|
export const LOCAL_CONSOLE_URL = 'http://localhost:3000';
|
|
40
59
|
export const DEV_MODE_FILENAME = 'dev-mode.json';
|
|
41
60
|
|
|
42
61
|
/** Absolute path of the machine-local record. */
|
|
43
|
-
export function devModeFilePath(homeDir =
|
|
62
|
+
export function devModeFilePath(homeDir = heyspexHome()) {
|
|
44
63
|
return join(homeDir, '.heyspex', DEV_MODE_FILENAME);
|
|
45
64
|
}
|
|
46
65
|
|
|
@@ -70,14 +89,19 @@ export function deriveSemantics(mode, reliance) {
|
|
|
70
89
|
};
|
|
71
90
|
}
|
|
72
91
|
|
|
92
|
+
/** Default file reader — injectable so tests never touch the real HOME. */
|
|
93
|
+
const defaultReadFile = (p) => readFileSync(p, 'utf8');
|
|
94
|
+
|
|
73
95
|
/**
|
|
74
96
|
* Read + validate ~/.heyspex/dev-mode.json. Never throws:
|
|
75
97
|
* returns { record, parseError } — record null when missing/invalid.
|
|
98
|
+
* `readFile` is an injectable seam (same shape as the TS twin's) so the
|
|
99
|
+
* parity test can feed both implementations the SAME in-memory fixture.
|
|
76
100
|
*/
|
|
77
|
-
export function readLocalDevModeRecord({ homeDir =
|
|
101
|
+
export function readLocalDevModeRecord({ homeDir = heyspexHome(), readFile = defaultReadFile } = {}) {
|
|
78
102
|
let raw;
|
|
79
103
|
try {
|
|
80
|
-
raw =
|
|
104
|
+
raw = readFile(devModeFilePath(homeDir));
|
|
81
105
|
} catch {
|
|
82
106
|
return { record: null, parseError: null }; // absent — not an error
|
|
83
107
|
}
|
|
@@ -112,10 +136,11 @@ export function readLocalDevModeRecord({ homeDir = homedir() } = {}) {
|
|
|
112
136
|
*/
|
|
113
137
|
export function resolveDevMode({
|
|
114
138
|
env = process.env,
|
|
115
|
-
homeDir =
|
|
139
|
+
homeDir = heyspexHome(),
|
|
140
|
+
readFile = defaultReadFile,
|
|
116
141
|
cloudSetting = undefined,
|
|
117
142
|
} = {}) {
|
|
118
|
-
const local = readLocalDevModeRecord({ homeDir });
|
|
143
|
+
const local = readLocalDevModeRecord({ homeDir, readFile });
|
|
119
144
|
const cloudKnown = cloudSetting !== undefined;
|
|
120
145
|
const cloudValue =
|
|
121
146
|
cloudKnown && cloudSetting
|
|
@@ -128,11 +153,19 @@ export function resolveDevMode({
|
|
|
128
153
|
let mode;
|
|
129
154
|
let reliance;
|
|
130
155
|
let source;
|
|
156
|
+
// Where the RELIANCE came from. Equals `source` except in one case:
|
|
157
|
+
// `HEYSPEX_DEV_MODE=dev` with no `HEYSPEX_DEV_RELIANCE` used to mean local
|
|
158
|
+
// silently; it still means local, but the envelope now says the reliance
|
|
159
|
+
// was ASSUMED ([[HS-EVVI-WW9R-TASK-show-any-dev-mode-override-in-hs-dev]]
|
|
160
|
+
// AC1, invariant 10 — no hidden mode switch).
|
|
161
|
+
let relianceSource;
|
|
131
162
|
const envParsed = normalizeMode(env.HEYSPEX_DEV_MODE);
|
|
132
163
|
if (envParsed) {
|
|
133
164
|
mode = envParsed.mode;
|
|
134
|
-
|
|
165
|
+
const envReliance = envParsed.reliance ?? normalizeReliance(env.HEYSPEX_DEV_RELIANCE);
|
|
166
|
+
reliance = envReliance ?? 'local';
|
|
135
167
|
source = 'env';
|
|
168
|
+
relianceSource = envReliance ? 'env' : 'assumed-local';
|
|
136
169
|
} else if (local.record) {
|
|
137
170
|
mode = local.record.mode;
|
|
138
171
|
reliance = local.record.reliance;
|
|
@@ -167,7 +200,7 @@ export function resolveDevMode({
|
|
|
167
200
|
vaultWriteMode: semantics.vaultWriteMode,
|
|
168
201
|
sources: {
|
|
169
202
|
mode: source,
|
|
170
|
-
reliance: source,
|
|
203
|
+
reliance: relianceSource ?? source,
|
|
171
204
|
consoleUrl:
|
|
172
205
|
source === 'local-override' && local.record?.console_url ? 'local-override' : 'derived',
|
|
173
206
|
readTier: 'derived',
|
|
@@ -183,6 +216,131 @@ export function resolveDevMode({
|
|
|
183
216
|
};
|
|
184
217
|
}
|
|
185
218
|
|
|
219
|
+
/** The `source` values {@link modeOverrideOf} can report. */
|
|
220
|
+
export const MODE_OVERRIDE_SOURCE_ENV = 'env';
|
|
221
|
+
export const MODE_OVERRIDE_SOURCE_FILE = 'dev-mode.json';
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* The one structured answer to "is a mode switch active on this machine?" —
|
|
225
|
+
* what `hs dev --json`, `hs doctor --json` and `heyspex_dev_mode` all report
|
|
226
|
+
* as `mode_override` ([[HS-EVVI-WW9R-TASK-show-any-dev-mode-override-in-hs-dev]]
|
|
227
|
+
* AC1/AC2; epic [[HS-P1AW-WW9R-EPIC-identity-threading-and-the-end-of-the]]
|
|
228
|
+
* criterion 4). Pure: reads only the resolved envelope, never the file.
|
|
229
|
+
*
|
|
230
|
+
* null — nothing overrides the cloud/default
|
|
231
|
+
* { source: "env", written_at: null, written_by: "HEYSPEX_DEV_MODE", disagrees_with_cloud }
|
|
232
|
+
* { source: "dev-mode.json", written_at: <ISO>, written_by: <record.source>, disagrees_with_cloud }
|
|
233
|
+
*
|
|
234
|
+
* `written_at` / `written_by` are the record's `updated_at` / `source` (the
|
|
235
|
+
* cross-component file contract keeps its own key names; the Companion reads
|
|
236
|
+
* that file). `disagrees_with_cloud` is only ever true when the cloud setting
|
|
237
|
+
* is KNOWN and differs — an unreachable cloud is never a disagreement.
|
|
238
|
+
*/
|
|
239
|
+
export function modeOverrideOf(resolved) {
|
|
240
|
+
if (!resolved) return null;
|
|
241
|
+
const cloud = resolved.cloudSetting?.value ?? null;
|
|
242
|
+
if (resolved.sources?.mode === 'env') {
|
|
243
|
+
const disagrees =
|
|
244
|
+
cloud !== null &&
|
|
245
|
+
(cloud.mode !== resolved.mode ||
|
|
246
|
+
(resolved.mode === 'dev' && cloud.reliance !== resolved.reliance));
|
|
247
|
+
return {
|
|
248
|
+
source: MODE_OVERRIDE_SOURCE_ENV,
|
|
249
|
+
written_at: null,
|
|
250
|
+
written_by: 'HEYSPEX_DEV_MODE',
|
|
251
|
+
disagrees_with_cloud: disagrees,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (resolved.localOverride?.present) {
|
|
255
|
+
const record = resolved.localOverride.record;
|
|
256
|
+
return {
|
|
257
|
+
source: MODE_OVERRIDE_SOURCE_FILE,
|
|
258
|
+
written_at: record?.updated_at ?? null,
|
|
259
|
+
written_by: record?.source ?? null,
|
|
260
|
+
disagrees_with_cloud: resolved.localOverride.staleAgainstCloud === true,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** `prod` / `dev+local` / `dev+cloud` — the label doctor and hs dev print. */
|
|
267
|
+
export function describeModeLabel(resolved) {
|
|
268
|
+
return `${resolved.mode}${resolved.mode === 'dev' ? `+${resolved.reliance}` : ''}`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* The `hs doctor` row for {@link modeOverrideOf} (row id `mode-override`).
|
|
273
|
+
* Pure — the caller resolves ONCE and passes the envelope in; this never
|
|
274
|
+
* re-reads the file. Shape matches every other doctor row
|
|
275
|
+
* (`{ id, label, status, detail, human? }`) plus the structured
|
|
276
|
+
* `mode_override` so `--json` carries the same object `hs dev --json` does.
|
|
277
|
+
*
|
|
278
|
+
* ok no override; or one that pins prod (the default) and does not
|
|
279
|
+
* disagree with a known cloud setting — the file is then just a
|
|
280
|
+
* cache of the normal mode, and the detail still names its date and
|
|
281
|
+
* writer so nothing on disk stays invisible.
|
|
282
|
+
* warn an override puts this machine in dev mode (cloud setting unknown
|
|
283
|
+
* or agreeing) — names the file, date and writer, repair `hs dev prod`.
|
|
284
|
+
* fail the override DISAGREES with a known cloud setting — same repair.
|
|
285
|
+
*
|
|
286
|
+
* `repairCommand` is rendered by the caller (`hsCommand('dev prod')`) so the
|
|
287
|
+
* advice is in the form THIS machine can run.
|
|
288
|
+
*/
|
|
289
|
+
export function modeOverrideDoctorRow(resolved, { recordPath, repairCommand = 'hs dev prod' } = {}) {
|
|
290
|
+
const id = 'mode-override';
|
|
291
|
+
const label = 'Dev-mode override (env / ~/.heyspex/dev-mode.json)';
|
|
292
|
+
const override = modeOverrideOf(resolved);
|
|
293
|
+
const modeLabel = describeModeLabel(resolved);
|
|
294
|
+
if (!override) {
|
|
295
|
+
return {
|
|
296
|
+
id,
|
|
297
|
+
label,
|
|
298
|
+
status: 'ok',
|
|
299
|
+
detail: `none — ${modeLabel} from ${resolved.sources.mode}`,
|
|
300
|
+
mode_override: null,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const where =
|
|
304
|
+
override.source === MODE_OVERRIDE_SOURCE_ENV
|
|
305
|
+
? `HEYSPEX_DEV_MODE env override`
|
|
306
|
+
: `${recordPath ?? devModeFilePath()}`;
|
|
307
|
+
const stamp =
|
|
308
|
+
override.source === MODE_OVERRIDE_SOURCE_ENV
|
|
309
|
+
? ''
|
|
310
|
+
: ` (written ${override.written_at ?? 'unknown date'} by ${override.written_by ?? 'unknown writer'})`;
|
|
311
|
+
const cloud = resolved.cloudSetting?.value;
|
|
312
|
+
const cloudLabel = cloud ? describeModeLabel({ mode: cloud.mode, reliance: cloud.reliance }) : null;
|
|
313
|
+
const repair = `Run \`${repairCommand}\` to put this machine back on the cloud console, or set the mode on purpose with \`${repairCommand.replace(/\bdev prod$/, 'dev <mode>')}\`.`;
|
|
314
|
+
|
|
315
|
+
if (override.disagrees_with_cloud) {
|
|
316
|
+
return {
|
|
317
|
+
id,
|
|
318
|
+
label,
|
|
319
|
+
status: 'fail',
|
|
320
|
+
detail: `${modeLabel} from ${where}${stamp} — DISAGREES with the cloud setting (${cloudLabel})`,
|
|
321
|
+
human: repair,
|
|
322
|
+
mode_override: override,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (resolved.mode === 'dev') {
|
|
326
|
+
return {
|
|
327
|
+
id,
|
|
328
|
+
label,
|
|
329
|
+
status: 'warn',
|
|
330
|
+
detail: `${modeLabel} from ${where}${stamp}${cloudLabel ? ` — matches the cloud setting (${cloudLabel})` : ' — cloud setting not checked (offline)'}`,
|
|
331
|
+
human: repair,
|
|
332
|
+
mode_override: override,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
id,
|
|
337
|
+
label,
|
|
338
|
+
status: 'ok',
|
|
339
|
+
detail: `${where}${stamp} pins ${modeLabel} — the default, nothing overridden`,
|
|
340
|
+
mode_override: override,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
186
344
|
/**
|
|
187
345
|
* Upsert top-level `key: value` lines in ~/.heyspex/credentials.yaml without a
|
|
188
346
|
* full YAML round-trip (same targeted approach as the vendor MCP `pair`
|
|
@@ -192,8 +350,11 @@ export function resolveDevMode({
|
|
|
192
350
|
*/
|
|
193
351
|
export function upsertCredentialsYamlKeys(homeDir, updates) {
|
|
194
352
|
const dir = join(homeDir, '.heyspex');
|
|
195
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
196
353
|
const filePath = join(dir, 'credentials.yaml');
|
|
354
|
+
// The real-home guard the credentials and registry writers carry: under a
|
|
355
|
+
// test runner, refuse to touch the REAL ~/.heyspex (checked before mkdir).
|
|
356
|
+
assertNotRealHomeUnderTest(filePath);
|
|
357
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
197
358
|
let content = '';
|
|
198
359
|
try {
|
|
199
360
|
content = readFileSync(filePath, 'utf8');
|
|
@@ -214,14 +375,57 @@ export function upsertCredentialsYamlKeys(homeDir, updates) {
|
|
|
214
375
|
return filePath;
|
|
215
376
|
}
|
|
216
377
|
|
|
217
|
-
/**
|
|
218
|
-
|
|
378
|
+
/**
|
|
379
|
+
* The bearer for cloud calls — `HEYSPEX_MCP_TOKEN` env, then `mcp_token:` in
|
|
380
|
+
* credentials.yaml — via the ONE shared reader
|
|
381
|
+
* (`vendor/heyspex-mcp/credentials.mjs`,
|
|
382
|
+
* [[HS-HL0D-WW9R-TASK-share-one-bearer-reader-and-one-console]]). Kept under
|
|
383
|
+
* its historical name for the hook scripts that import it; the precedence is
|
|
384
|
+
* the shared module's, never re-implemented here.
|
|
385
|
+
*/
|
|
386
|
+
export function readCredentialsMcpToken({ env = process.env, homeDir = heyspexHome() } = {}) {
|
|
387
|
+
return readBearer({ env, homeDir }).token;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Run `fn(signal)` under a request timeout that is ALWAYS cleared and can
|
|
392
|
+
* never fire after the request has settled.
|
|
393
|
+
*
|
|
394
|
+
* Why not `AbortSignal.timeout(ms)`: that signal owns a timer nothing can
|
|
395
|
+
* cancel — it stays armed for the whole window even once the response has
|
|
396
|
+
* resolved, so a late abort can land on an already-settled request. Here the
|
|
397
|
+
* controller is ours: the timer is cleared in `finally` (rule 1 of
|
|
398
|
+
* [[HS-SWW3-Z9WP-DIAG-hs-dev-crashes-with-a-libuv-assertion]]) and `unref`'d
|
|
399
|
+
* so it can never hold the event loop open on its own.
|
|
400
|
+
*/
|
|
401
|
+
async function withRequestTimeout(timeoutMs, fn) {
|
|
402
|
+
const controller = new AbortController();
|
|
403
|
+
const state = { timedOut: false };
|
|
404
|
+
const timer = setTimeout(() => {
|
|
405
|
+
state.timedOut = true;
|
|
406
|
+
controller.abort();
|
|
407
|
+
}, timeoutMs);
|
|
408
|
+
timer.unref?.();
|
|
409
|
+
try {
|
|
410
|
+
return await fn(controller.signal);
|
|
411
|
+
} catch (err) {
|
|
412
|
+
if (state.timedOut) throw new Error(`timed out after ${timeoutMs}ms`);
|
|
413
|
+
throw err;
|
|
414
|
+
} finally {
|
|
415
|
+
clearTimeout(timer);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Release a response we are not going to read. An undrained body keeps its
|
|
421
|
+
* socket half-read in the keep-alive pool; cancelling hands it back so the
|
|
422
|
+
* process can tear down cleanly. Never throws (the body may already be gone).
|
|
423
|
+
*/
|
|
424
|
+
async function discardResponseBody(res) {
|
|
219
425
|
try {
|
|
220
|
-
|
|
221
|
-
const match = raw.match(/^mcp_token:\s*["']?([^"'\r\n#]+)/m);
|
|
222
|
-
return match?.[1]?.trim() || null;
|
|
426
|
+
await res?.body?.cancel();
|
|
223
427
|
} catch {
|
|
224
|
-
|
|
428
|
+
/* already consumed, closed, or bodyless — nothing to release */
|
|
225
429
|
}
|
|
226
430
|
}
|
|
227
431
|
|
|
@@ -229,17 +433,22 @@ export function readCredentialsMcpToken({ homeDir = homedir() } = {}) {
|
|
|
229
433
|
export async function fetchCloudDevMode({
|
|
230
434
|
consoleUrl,
|
|
231
435
|
fetchImpl = fetch,
|
|
232
|
-
homeDir =
|
|
436
|
+
homeDir = heyspexHome(),
|
|
233
437
|
timeoutMs = 4000,
|
|
234
438
|
} = {}) {
|
|
235
439
|
if (!consoleUrl) return { ok: false, setting: undefined, error: 'no console url' };
|
|
236
440
|
try {
|
|
237
441
|
const token = readCredentialsMcpToken({ homeDir });
|
|
238
|
-
const res = await
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
442
|
+
const res = await withRequestTimeout(timeoutMs, (signal) =>
|
|
443
|
+
fetchImpl(`${consoleUrl.replace(/\/+$/, '')}/api/admin/dev-mode`, {
|
|
444
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
445
|
+
signal,
|
|
446
|
+
}),
|
|
447
|
+
);
|
|
448
|
+
if (!res.ok) {
|
|
449
|
+
await discardResponseBody(res);
|
|
450
|
+
return { ok: false, setting: undefined, error: `HTTP ${res.status}` };
|
|
451
|
+
}
|
|
243
452
|
const body = await res.json();
|
|
244
453
|
return { ok: true, setting: body?.cloud ?? null, error: null };
|
|
245
454
|
} catch (err) {
|
|
@@ -280,7 +489,7 @@ export class DevModeNotAdminError extends Error {
|
|
|
280
489
|
export async function applyDevMode(
|
|
281
490
|
target,
|
|
282
491
|
{
|
|
283
|
-
homeDir =
|
|
492
|
+
homeDir = heyspexHome(),
|
|
284
493
|
fetchImpl = fetch,
|
|
285
494
|
source = 'cli',
|
|
286
495
|
now = () => new Date().toISOString(),
|
|
@@ -297,18 +506,24 @@ export async function applyDevMode(
|
|
|
297
506
|
parsed.reliance ?? normalizeReliance(target?.reliance) ?? 'local';
|
|
298
507
|
const mode = parsed.mode;
|
|
299
508
|
const semantics = deriveSemantics(mode, reliance);
|
|
509
|
+
// Under a test runner, refuse a real-home target BEFORE the cloud precheck
|
|
510
|
+
// or any write (the same guard the credentials and registry writers carry).
|
|
511
|
+
assertNotRealHomeUnderTest(devModeFilePath(homeDir));
|
|
300
512
|
|
|
513
|
+
// Timer-safe on purpose — never `AbortSignal.timeout` here
|
|
514
|
+
// ([[HS-SWW3-Z9WP-DIAG-hs-dev-crashes-with-a-libuv-assertion]]).
|
|
301
515
|
async function postCloud(token) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
516
|
+
return withRequestTimeout(5000, (signal) =>
|
|
517
|
+
fetchImpl(`${semantics.consoleUrl}/api/admin/dev-mode`, {
|
|
518
|
+
method: 'POST',
|
|
519
|
+
headers: {
|
|
520
|
+
'content-type': 'application/json',
|
|
521
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
522
|
+
},
|
|
523
|
+
body: JSON.stringify({ mode, reliance: semantics.reliance, source }),
|
|
524
|
+
signal,
|
|
525
|
+
}),
|
|
526
|
+
);
|
|
312
527
|
}
|
|
313
528
|
|
|
314
529
|
// 0. Authorization precheck — see the doc comment above.
|
|
@@ -318,6 +533,7 @@ export async function applyDevMode(
|
|
|
318
533
|
if (token) {
|
|
319
534
|
try {
|
|
320
535
|
const res = await postCloud(token);
|
|
536
|
+
await discardResponseBody(res);
|
|
321
537
|
if (res.status === 403) throw new DevModeNotAdminError();
|
|
322
538
|
cloud = { attempted: true, updated: res.ok, error: res.ok ? null : `HTTP ${res.status}` };
|
|
323
539
|
} catch (err) {
|
|
@@ -336,8 +552,8 @@ export async function applyDevMode(
|
|
|
336
552
|
source,
|
|
337
553
|
};
|
|
338
554
|
const dir = join(homeDir, '.heyspex');
|
|
339
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
340
555
|
const recordPath = devModeFilePath(homeDir);
|
|
556
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
341
557
|
writeFileSync(recordPath, `${JSON.stringify(record, null, 2)}\n`, 'utf8');
|
|
342
558
|
|
|
343
559
|
// 2. credentials.yaml console_url (rung 2 of the shared resolver).
|
|
@@ -354,6 +570,7 @@ export async function applyDevMode(
|
|
|
354
570
|
const res = await postCloud(token);
|
|
355
571
|
if (res.ok) cloud.updated = true;
|
|
356
572
|
else cloud.error = `HTTP ${res.status}`;
|
|
573
|
+
await discardResponseBody(res);
|
|
357
574
|
} catch (err) {
|
|
358
575
|
cloud.error = String(err?.message ?? err);
|
|
359
576
|
}
|