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
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* hs settings — CLI face of the HeySpex settings capability.
|
|
4
|
+
* Dispatched from bin/hs.mjs. Delegates to the ONE settings core
|
|
5
|
+
* (vendor/heyspex-mcp/config-settings.mjs) per the three-faces principle
|
|
6
|
+
* ([[capability-three-faces-no-per-capability-slash]]).
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* hs settings list [prefix] [--json]
|
|
10
|
+
* hs settings get <dotted.key> [--json]
|
|
11
|
+
* hs settings set <dotted.key> <value> [--json] [--confirmed-by-user]
|
|
12
|
+
*
|
|
13
|
+
* WRITE-PERMISSION GUARDRAIL (agent-settings-protocol, owner directive
|
|
14
|
+
* 2026-07-11): settings writes require explicit user permission. A human typing
|
|
15
|
+
* `hs settings set` in their own terminal IS the permission. But when this CLI
|
|
16
|
+
* runs inside an agent harness (Claude Code sets CLAUDECODE=1 / CLAUDE_AGENT for
|
|
17
|
+
* its shell tool), the write is agent-initiated: it is refused unless
|
|
18
|
+
* `--confirmed-by-user` is passed, and that flag may ONLY be passed after the
|
|
19
|
+
* user explicitly approved the exact change in the conversation. This holds
|
|
20
|
+
* regardless of agent_behaviors.ask_forgiveness_not_permission — that switch
|
|
21
|
+
* governs behaviors, never its own controls. All writes are audited to
|
|
22
|
+
* .heyspex/settings-history.jsonl.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import fs from 'node:fs';
|
|
26
|
+
import path from 'node:path';
|
|
27
|
+
import process from 'node:process';
|
|
28
|
+
import { pathToFileURL } from 'node:url';
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
listConfigLeaves,
|
|
32
|
+
getEffectiveSetting,
|
|
33
|
+
setConfigLeaf,
|
|
34
|
+
validateSettingKey,
|
|
35
|
+
} from '../vendor/heyspex-mcp/config-settings.mjs';
|
|
36
|
+
import {
|
|
37
|
+
SETTINGS_REGISTRY,
|
|
38
|
+
getSettingEntry,
|
|
39
|
+
isKnownSetting,
|
|
40
|
+
} from '../vendor/heyspex-mcp/settings-registry.mjs';
|
|
41
|
+
import { getActiveConfig } from '../vendor/heyspex-mcp/vault-resolve.mjs';
|
|
42
|
+
|
|
43
|
+
const HELP = `hs settings — read/change HeySpex workflow settings (.heyspex/config.yaml at the VAULT root)
|
|
44
|
+
|
|
45
|
+
Usage:
|
|
46
|
+
hs settings list [prefix] [--json] List all scalar settings (optionally under a dotted prefix)
|
|
47
|
+
hs settings get <dotted.key> [--json] Read one setting (e.g. agent_behaviors.capture_on_idea.enabled)
|
|
48
|
+
hs settings set <dotted.key> <value> Change one setting (value: string | number | true | false | null)
|
|
49
|
+
[--confirmed-by-user] [--json]
|
|
50
|
+
|
|
51
|
+
The settings file lives at <vault root>/.heyspex/config.yaml (ADR-0009). If it is
|
|
52
|
+
missing, \`hs settings set\` creates it from the shipped seed template first and
|
|
53
|
+
then applies the change (reads never create it) — \`hs init\` seeds the same file.
|
|
54
|
+
|
|
55
|
+
Write permission (agent-settings-protocol):
|
|
56
|
+
A human running \`hs settings set\` directly is inherently permissioned. Inside an
|
|
57
|
+
agent harness (CLAUDECODE / CLAUDE_AGENT env present) the write is refused unless
|
|
58
|
+
--confirmed-by-user is passed — and an agent may pass it ONLY after the user
|
|
59
|
+
explicitly approved the exact change. Writes are audited to
|
|
60
|
+
.heyspex/settings-history.jsonl. Agents should prefer the MCP tool
|
|
61
|
+
heyspex_settings_set (two-step confirm).
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The vault root this face reads/writes. `bin/hs.mjs` always forwards
|
|
66
|
+
* `HS_VAULT_ROOT`; the last fallback (this script run directly) asks the shared
|
|
67
|
+
* vault resolver — NEVER this code checkout. Since the 2026-08-31 repo split the
|
|
68
|
+
* vault is a sibling repo, so falling back to `scripts/..` silently read/wrote a
|
|
69
|
+
* `.heyspex/config.yaml` the console and MCP never look at
|
|
70
|
+
* ([[HS-4C76-9W86-DIAG-heyspex-config-yaml-has-no-single-home]]).
|
|
71
|
+
*/
|
|
72
|
+
function vaultRoot() {
|
|
73
|
+
return process.env.HS_VAULT_ROOT || process.env.HEYSPEX_VAULT_ROOT || getActiveConfig().repoRootAbs;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isAgentHarness() {
|
|
77
|
+
return Boolean(
|
|
78
|
+
process.env.CLAUDECODE ||
|
|
79
|
+
process.env.CLAUDE_AGENT ||
|
|
80
|
+
process.env.CLAUDE_CODE_SESSION_ID ||
|
|
81
|
+
process.env.CURSOR_AGENT,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* True when `root` is the HeySpex platform vault rather than a
|
|
87
|
+
* customer-provisioned one. `hs init --customer-vault` unconditionally stamps
|
|
88
|
+
* `template_version: <…>` into the scaffolded vault's `heyspex.yaml`
|
|
89
|
+
* (`spex-console/src/lib/cli/init-git-finalize.ts` `gitFinalizeHook` /
|
|
90
|
+
* `ensureTemplateVersionLine`) — the platform vault's own marker never
|
|
91
|
+
* carries that field. That stamp is the one on-disk, offline-readable signal
|
|
92
|
+
* that distinguishes the two without a network/account lookup (the MCP/CLI
|
|
93
|
+
* process is standalone, per `vendor/heyspex-mcp/vault-resolve.mjs`'s module
|
|
94
|
+
* doc). A vault with no `heyspex.yaml` at all (e.g. this code checkout run
|
|
95
|
+
* directly, with no vault marker) is treated as platform — it is not a
|
|
96
|
+
* customer scaffold. Registry-declared admin-only entries (e.g.
|
|
97
|
+
* `close_out.run_command_drift_doctor`) are hidden from `hs settings list`
|
|
98
|
+
* everywhere `template_version` is present ([[HS-5MNS-15XI-TASK]] AC4).
|
|
99
|
+
*/
|
|
100
|
+
export function isHeyspexPlatformVault(root) {
|
|
101
|
+
let raw;
|
|
102
|
+
try {
|
|
103
|
+
raw = fs.readFileSync(path.join(root, 'heyspex.yaml'), 'utf8');
|
|
104
|
+
} catch {
|
|
105
|
+
return true; // no marker at all — not a customer scaffold
|
|
106
|
+
}
|
|
107
|
+
return !/^template_version:\s*\S+/m.test(raw);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** How a value's `source` reads in a one-line human sentence. */
|
|
111
|
+
function describeSource(source) {
|
|
112
|
+
if (source === 'file') return 'settings file';
|
|
113
|
+
if (source === 'registry_default') return 'shipped default';
|
|
114
|
+
return 'absent';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Build the `hs settings list` result: every registry entry this vault ships
|
|
119
|
+
* (admin-only entries dropped in a non-platform vault), each carrying its
|
|
120
|
+
* effective value/source plus its shipped default and description, followed
|
|
121
|
+
* by any keys the settings file has that the registry does not declare
|
|
122
|
+
* (marked `unrecognised: true`) — the freeform namespaces the registry has
|
|
123
|
+
* not been taught yet (`agent_behaviors.*`, `mvp_mode.*`, …) land here too,
|
|
124
|
+
* unchanged from their pre-registry values.
|
|
125
|
+
* ([[HS-5MNS-15XI-TASK-show-every-declared-setting-in-the]])
|
|
126
|
+
*
|
|
127
|
+
* @param {string} root
|
|
128
|
+
* @param {string} [prefix] - optional dotted-key prefix filter
|
|
129
|
+
* @returns {{ declared: object[], unrecognised: object[] }}
|
|
130
|
+
*/
|
|
131
|
+
export function buildListEntries(root, prefix, options = {}) {
|
|
132
|
+
const trimmedPrefix = (prefix ?? '').trim();
|
|
133
|
+
const matchesPrefix = (key) =>
|
|
134
|
+
!trimmedPrefix || key === trimmedPrefix || key.startsWith(trimmedPrefix + '.');
|
|
135
|
+
const platform = isHeyspexPlatformVault(root);
|
|
136
|
+
|
|
137
|
+
const declared = [];
|
|
138
|
+
for (const entry of SETTINGS_REGISTRY) {
|
|
139
|
+
if (entry.adminOnly && !platform) continue;
|
|
140
|
+
if (!matchesPrefix(entry.key)) continue;
|
|
141
|
+
const effective = getEffectiveSetting(root, entry.key, options);
|
|
142
|
+
declared.push({
|
|
143
|
+
key: entry.key,
|
|
144
|
+
value: effective.value,
|
|
145
|
+
source: effective.source,
|
|
146
|
+
default: entry.default,
|
|
147
|
+
type: entry.type,
|
|
148
|
+
description: entry.description,
|
|
149
|
+
cliFlag: entry.cliFlag,
|
|
150
|
+
adminOnly: entry.adminOnly,
|
|
151
|
+
enforced: entry.enforced,
|
|
152
|
+
...(entry.type === 'enum' ? { values: entry.values } : {}),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const unrecognised = listConfigLeaves(root, options)
|
|
157
|
+
.filter((leaf) => !isKnownSetting(leaf.key))
|
|
158
|
+
.filter((leaf) => matchesPrefix(leaf.key))
|
|
159
|
+
.map((leaf) => ({ key: leaf.key, value: leaf.value, unrecognised: true }));
|
|
160
|
+
|
|
161
|
+
return { declared, unrecognised };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Build the `hs settings get <key>` result: the effective value (file value
|
|
166
|
+
* when present, else the registry's shipped default), which of the two it
|
|
167
|
+
* came from, and — for a name the registry does not declare AND that has no
|
|
168
|
+
* value in the file either — an explicit "not declared" report instead of a
|
|
169
|
+
* silent empty value. ([[HS-7W0S-15XI-TASK-return-the-effective-value-from-the]])
|
|
170
|
+
*
|
|
171
|
+
* @param {string} root
|
|
172
|
+
* @param {string} key
|
|
173
|
+
* @returns {object}
|
|
174
|
+
*/
|
|
175
|
+
export function resolveGet(root, key, options = {}) {
|
|
176
|
+
const effective = getEffectiveSetting(root, key, options);
|
|
177
|
+
if (effective.source === 'absent') {
|
|
178
|
+
return { ok: true, key, found: false, known: false, value: null, source: 'absent' };
|
|
179
|
+
}
|
|
180
|
+
const entry = getSettingEntry(key);
|
|
181
|
+
return {
|
|
182
|
+
ok: true,
|
|
183
|
+
key,
|
|
184
|
+
found: effective.found,
|
|
185
|
+
known: Boolean(entry),
|
|
186
|
+
value: effective.value,
|
|
187
|
+
source: effective.source,
|
|
188
|
+
...(entry ? { default: entry.default, description: entry.description } : {}),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Render `resolveGet`'s result as the plain-text `hs settings get` body. */
|
|
193
|
+
function renderGetText(result) {
|
|
194
|
+
if (result.source === 'absent') {
|
|
195
|
+
return `${result.key} is not set and is not declared in the settings registry (no shipped default to fall back to)\n`;
|
|
196
|
+
}
|
|
197
|
+
return `${result.key} = ${JSON.stringify(result.value)} [${describeSource(result.source)}]\n`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Render `buildListEntries`'s result as the plain-text `hs settings list` body. */
|
|
201
|
+
function renderListText({ declared, unrecognised }) {
|
|
202
|
+
const lines = [];
|
|
203
|
+
for (const row of declared) {
|
|
204
|
+
lines.push(`${row.key} = ${JSON.stringify(row.value)} [${describeSource(row.source)}]`);
|
|
205
|
+
lines.push(` ${row.description}`);
|
|
206
|
+
}
|
|
207
|
+
if (unrecognised.length) {
|
|
208
|
+
if (declared.length) lines.push('');
|
|
209
|
+
lines.push('Unrecognised (not declared in the settings registry):');
|
|
210
|
+
for (const row of unrecognised) {
|
|
211
|
+
lines.push(` ${row.key} = ${JSON.stringify(row.value)}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (!declared.length && !unrecognised.length) return 'no settings found\n';
|
|
215
|
+
return lines.join('\n') + '\n';
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function parseValueToken(token) {
|
|
219
|
+
if (token === undefined) return undefined;
|
|
220
|
+
if (token === 'null') return null;
|
|
221
|
+
if (token === 'true') return true;
|
|
222
|
+
if (token === 'false') return false;
|
|
223
|
+
if (/^-?\d+(\.\d+)?$/.test(token)) return Number(token);
|
|
224
|
+
return token;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function out(obj, asJson, plain) {
|
|
228
|
+
if (asJson) process.stdout.write(JSON.stringify(obj, null, 2) + '\n');
|
|
229
|
+
else process.stdout.write(plain);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function main(argv) {
|
|
233
|
+
// bin/hs.mjs forwards the full argv (leading `settings` token included).
|
|
234
|
+
const args = argv[0] === 'settings' ? argv.slice(1) : argv.slice();
|
|
235
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
236
|
+
process.stdout.write(HELP);
|
|
237
|
+
process.exit(args.length === 0 ? 2 : 0);
|
|
238
|
+
}
|
|
239
|
+
const asJson = args.includes('--json');
|
|
240
|
+
const confirmedByUser = args.includes('--confirmed-by-user');
|
|
241
|
+
const positional = args.filter((a) => !a.startsWith('--'));
|
|
242
|
+
const [verb, keyArg, ...valueTokens] = positional;
|
|
243
|
+
const root = vaultRoot();
|
|
244
|
+
|
|
245
|
+
if (verb === 'list') {
|
|
246
|
+
const prefix = keyArg?.trim() || '';
|
|
247
|
+
const { declared, unrecognised } = buildListEntries(root, prefix);
|
|
248
|
+
out(
|
|
249
|
+
{ ok: true, count: declared.length + unrecognised.length, declared, unrecognised },
|
|
250
|
+
asJson,
|
|
251
|
+
renderListText({ declared, unrecognised }),
|
|
252
|
+
);
|
|
253
|
+
process.exit(0);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (verb === 'get') {
|
|
257
|
+
const check = validateSettingKey(keyArg ?? '');
|
|
258
|
+
if (!check.ok) {
|
|
259
|
+
process.stderr.write(`hs settings get: ${check.reason}\n`);
|
|
260
|
+
process.exit(2);
|
|
261
|
+
}
|
|
262
|
+
const result = resolveGet(root, keyArg);
|
|
263
|
+
out(result, asJson, renderGetText(result));
|
|
264
|
+
process.exit(0);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (verb === 'set') {
|
|
268
|
+
const check = validateSettingKey(keyArg ?? '');
|
|
269
|
+
if (!check.ok) {
|
|
270
|
+
process.stderr.write(`hs settings set: ${check.reason}\n`);
|
|
271
|
+
process.exit(2);
|
|
272
|
+
}
|
|
273
|
+
if (valueTokens.length === 0) {
|
|
274
|
+
process.stderr.write('hs settings set: missing <value> (string | number | true | false | null)\n');
|
|
275
|
+
process.exit(2);
|
|
276
|
+
}
|
|
277
|
+
const value = parseValueToken(valueTokens.join(' '));
|
|
278
|
+
|
|
279
|
+
if (isAgentHarness() && !confirmedByUser) {
|
|
280
|
+
const msg =
|
|
281
|
+
`hs settings set: REFUSED — this shell is running inside an agent harness, and settings writes ` +
|
|
282
|
+
`require explicit user permission (agent-settings-protocol; independent of ` +
|
|
283
|
+
`ask_forgiveness_not_permission). Show the user the exact change and, only after they approve, ` +
|
|
284
|
+
`re-run with --confirmed-by-user (or use the MCP tool heyspex_settings_set, which has a ` +
|
|
285
|
+
`built-in confirm step).\n`;
|
|
286
|
+
process.stderr.write(msg);
|
|
287
|
+
process.exit(3);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const actor = isAgentHarness() ? 'agent (CLI, user-confirmed)' : 'human (CLI)';
|
|
291
|
+
const result = setConfigLeaf(root, keyArg, value, { actor, face: 'cli' });
|
|
292
|
+
if (!result.ok) {
|
|
293
|
+
process.stderr.write(`hs settings set: ${result.error} — ${result.message}\n`);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
// HS-4C76 fix 3: the core seeds a missing config.yaml from the template on
|
|
297
|
+
// the first write instead of refusing — say so, since the user may not have
|
|
298
|
+
// known the file was absent (it is git-tracked at the vault root).
|
|
299
|
+
if (result.seeded === true) {
|
|
300
|
+
process.stderr.write(
|
|
301
|
+
`hs settings set: note — ${path.join(root, '.heyspex', 'config.yaml')} did not exist and was created from ` +
|
|
302
|
+
`the seed template before applying this change. Commit it with the vault (ADR-0009).\n`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
// The CLI face shares the core with heyspex_settings_set, so it inherits the
|
|
306
|
+
// measured `audited` flag ([[HS-IOJW-5YDH-DIAG]] sweep). A settings write with
|
|
307
|
+
// no audit row is a partial, and must not print as a clean success.
|
|
308
|
+
if (result.audited !== true) {
|
|
309
|
+
process.stderr.write(
|
|
310
|
+
`hs settings set: WARNING — the value was applied to .heyspex/config.yaml but the audit append to ` +
|
|
311
|
+
`.heyspex/settings-history.jsonl FAILED. The change is live and UNAUDITED; check that file is writable.\n`,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
out(
|
|
315
|
+
{ ok: true, ...result },
|
|
316
|
+
asJson,
|
|
317
|
+
`${keyArg}: ${JSON.stringify(result.previous)} → ${JSON.stringify(result.value)}${result.created ? ' (created)' : ''}${result.seeded === true ? ' (config.yaml seeded from template)' : ''}${result.audited === true ? '' : ' (UNAUDITED — audit append failed)'}\n`,
|
|
318
|
+
);
|
|
319
|
+
process.exit(0);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
process.stderr.write(`hs settings: unknown subcommand \`${verb ?? ''}\` (expected: list | get | set)\n${HELP}`);
|
|
323
|
+
process.exit(2);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Only auto-run when executed directly (`node scripts/hs-settings.mjs …` or via
|
|
327
|
+
// bin/hs.mjs's spawn) — not when a test imports this module for its exported
|
|
328
|
+
// helpers (buildListEntries, isHeyspexPlatformVault, …).
|
|
329
|
+
const isMain = (() => {
|
|
330
|
+
try {
|
|
331
|
+
return import.meta.url === pathToFileURL(process.argv[1] ?? '').href;
|
|
332
|
+
} catch {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
})();
|
|
336
|
+
if (isMain) {
|
|
337
|
+
main(process.argv.slice(2));
|
|
338
|
+
}
|