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,236 @@
|
|
|
1
|
+
// spexharness/src/adapters/copilot.mjs
|
|
2
|
+
//
|
|
3
|
+
// GitHub Copilot CLI front for the shared hook gates ([[HS-20SW-DRSM-DIAG-heyspex-capture-on-idea-and-workflow]];
|
|
4
|
+
// contract: GitHub Docs "Hooks configuration" + "CLI plugin reference", fetched 2026-10-16;
|
|
5
|
+
// [[HS-0GBS-CTF8-RES-copilot-plugin-parity-with-the-spexcode]]). Pure functions, no I/O.
|
|
6
|
+
//
|
|
7
|
+
// What Copilot does that Claude Code does not:
|
|
8
|
+
// INPUT two shapes. camelCase config events `{ sessionId, timestamp, cwd, toolName, toolArgs }` and the
|
|
9
|
+
// PascalCase shape `.claude/settings.json` rows receive `{ hook_event_name, session_id, timestamp,
|
|
10
|
+
// cwd, tool_name, tool_input }` (tool names already mapped to Claude's: bash/powershell -> Bash,
|
|
11
|
+
// create -> Write, edit/apply_patch -> Edit, view -> Read, task -> Agent). No `transcript_path`.
|
|
12
|
+
// OUTPUT ONE top-level JSON object on stdout: `{ permissionDecision: allow|deny|ask, permissionDecisionReason }`.
|
|
13
|
+
// It does NOT read `hookSpecificOutput`. Unparseable stdout is ignored.
|
|
14
|
+
// EXIT 0 -> stdout parsed. 2 -> always deny (stderr reason lost). ANY other non-zero -> deny ("hook
|
|
15
|
+
// errored"). Timeout -> fail open. So a Copilot hook prints its deny as JSON and exits 0, never 2.
|
|
16
|
+
//
|
|
17
|
+
// This module maps both directions; ./detect-harness.mjs decides WHEN it applies.
|
|
18
|
+
|
|
19
|
+
// HeySpex MCP tool names arrive in several spellings depending on the Copilot host (the payload spelling is not
|
|
20
|
+
// documented; [[HS-0GBS-CTF8-RES-copilot-plugin-parity-with-the-spexcode]] residual gap). Every spelling below maps
|
|
21
|
+
// to the Claude-side `mcp__heyspex__<tool>` the gates and `.claude/settings.json` matchers already use:
|
|
22
|
+
// mcp__heyspex__heyspex_x mcp__plugin_heyspex_heyspex__heyspex_x heyspex/heyspex_x heyspex.heyspex_x heyspex_x
|
|
23
|
+
const HEYSPEX_MCP_NAME = /^(?:mcp__plugin_heyspex_heyspex__|mcp__heyspex__|heyspex[/.:])?(heyspex_[A-Za-z0-9_]+)$/;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {unknown} name
|
|
27
|
+
* @returns {{ name: string, suffix: string } | null} null when `name` is not a HeySpex MCP tool in a known spelling
|
|
28
|
+
*/
|
|
29
|
+
export function normalizeMcpToolName(name) {
|
|
30
|
+
if (typeof name !== 'string') return null;
|
|
31
|
+
const m = HEYSPEX_MCP_NAME.exec(name.trim());
|
|
32
|
+
return m ? { name: `mcp__heyspex__${m[1]}`, suffix: m[1] } : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const COPILOT_TOOL_TO_CLAUDE = {
|
|
36
|
+
bash: 'Bash',
|
|
37
|
+
powershell: 'PowerShell',
|
|
38
|
+
create: 'Write',
|
|
39
|
+
edit: 'Edit',
|
|
40
|
+
apply_patch: 'Edit',
|
|
41
|
+
view: 'Read',
|
|
42
|
+
task: 'Agent',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function parseArgs(value) {
|
|
46
|
+
if (value && typeof value === 'object') return value;
|
|
47
|
+
if (typeof value !== 'string' || !value.trim()) return {};
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(value);
|
|
50
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
51
|
+
} catch {
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Either Copilot payload shape -> the Claude-shaped payload every hook already reads. Never throws; a payload
|
|
58
|
+
* that is already Claude-shaped passes through with its `hook_event_name`, and unknown fields stay untouched.
|
|
59
|
+
* @param {unknown} payload
|
|
60
|
+
* @returns {Record<string, unknown>}
|
|
61
|
+
*/
|
|
62
|
+
export function normalizeCopilotPayload(payload) {
|
|
63
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return {};
|
|
64
|
+
const p = /** @type {Record<string, any>} */ (payload);
|
|
65
|
+
const out = { ...p };
|
|
66
|
+
if (out.session_id === undefined && typeof p.sessionId === 'string') out.session_id = p.sessionId;
|
|
67
|
+
if (out.tool_name === undefined && typeof p.toolName === 'string') {
|
|
68
|
+
out.tool_name = COPILOT_TOOL_TO_CLAUDE[p.toolName] ?? p.toolName;
|
|
69
|
+
}
|
|
70
|
+
if (out.tool_input === undefined && p.toolArgs !== undefined) {
|
|
71
|
+
const args = { ...parseArgs(p.toolArgs) };
|
|
72
|
+
if (args.file_path === undefined && typeof args.path === 'string') args.file_path = args.path;
|
|
73
|
+
out.tool_input = args;
|
|
74
|
+
}
|
|
75
|
+
if (typeof out.tool_name === 'string') {
|
|
76
|
+
const mcp = normalizeMcpToolName(out.tool_name);
|
|
77
|
+
if (mcp) {
|
|
78
|
+
if (mcp.name !== out.tool_name && out.tool_name_original === undefined) out.tool_name_original = out.tool_name;
|
|
79
|
+
out.tool_name = mcp.name;
|
|
80
|
+
out.tool_name_suffix = mcp.suffix;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (out.tool_response === undefined && p.toolResult !== undefined) out.tool_response = p.toolResult;
|
|
84
|
+
if (typeof out.hook_event_name !== 'string') {
|
|
85
|
+
if (out.tool_response !== undefined) out.hook_event_name = 'PostToolUse';
|
|
86
|
+
else if (out.tool_name !== undefined) out.hook_event_name = 'PreToolUse';
|
|
87
|
+
else if (typeof p.prompt === 'string') out.hook_event_name = 'UserPromptSubmit';
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const body = (decision, reason) => JSON.stringify({ permissionDecision: decision, permissionDecisionReason: reason });
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* A gate decision (decide.mjs shape) -> what a Copilot hook process emits. A deny is ALWAYS exit 0 with the
|
|
96
|
+
* JSON on stdout (exit 2 would lose the reason). `allow`, `inject` and warn-only rewrites print nothing on
|
|
97
|
+
* stdout (Copilot has no additionalContext channel for tool hooks).
|
|
98
|
+
* @param {{ id?: string, event?: unknown }} _gate
|
|
99
|
+
* @param {{ point?: string }} engineEvent
|
|
100
|
+
* @param {{ decision?: string, reason?: string, rewrite?: { ask?: boolean, warn?: boolean } }} decision
|
|
101
|
+
* @returns {{ exitCode: 0, stdout: string, stderr: string }}
|
|
102
|
+
*/
|
|
103
|
+
export function toCopilotResponse(_gate, engineEvent, decision) {
|
|
104
|
+
const kind = decision?.decision ?? 'allow';
|
|
105
|
+
const reason = String(decision?.reason ?? 'Denied by a HeySpex hook.');
|
|
106
|
+
if (kind === 'deny') {
|
|
107
|
+
const o = { permissionDecision: 'deny', permissionDecisionReason: reason };
|
|
108
|
+
// a Stop-time deny is a re-drive: carry the Claude stop shape too so either reader acts on it
|
|
109
|
+
if (engineEvent?.point === 'stop') Object.assign(o, { decision: 'block', reason });
|
|
110
|
+
return { exitCode: 0, stdout: JSON.stringify(o), stderr: '' };
|
|
111
|
+
}
|
|
112
|
+
if (kind === 'rewrite' && decision.rewrite?.ask) return { exitCode: 0, stdout: body('ask', reason), stderr: '' };
|
|
113
|
+
if (kind === 'rewrite' && decision.rewrite?.warn) {
|
|
114
|
+
return { exitCode: 0, stdout: '', stderr: reason.endsWith('\n') ? reason : `${reason}\n` };
|
|
115
|
+
}
|
|
116
|
+
return { exitCode: 0, stdout: '', stderr: '' };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Rewrite a Claude-dialect stdout blob (`{"hookSpecificOutput":{"permissionDecision":...}}`) into Copilot's
|
|
121
|
+
* top-level object. Anything else (already top-level, Stop `{decision:"block"}`, additionalContext, plain
|
|
122
|
+
* text) is returned unchanged. Used by the shared runner for hand-written hooks that print Claude JSON.
|
|
123
|
+
* @param {string} text
|
|
124
|
+
* @returns {string}
|
|
125
|
+
*/
|
|
126
|
+
export function rewriteStdoutForCopilot(text) {
|
|
127
|
+
try {
|
|
128
|
+
const o = JSON.parse(text);
|
|
129
|
+
const h = o?.hookSpecificOutput;
|
|
130
|
+
if (h && typeof h.permissionDecision === 'string') {
|
|
131
|
+
return body(h.permissionDecision, h.permissionDecisionReason ?? 'Denied by a HeySpex hook.');
|
|
132
|
+
}
|
|
133
|
+
} catch {
|
|
134
|
+
/* not JSON: pass through */
|
|
135
|
+
}
|
|
136
|
+
return text;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A hand-written hook that decided "deny" the legacy way (exit 2, reason on stderr) -> the Copilot JSON deny.
|
|
141
|
+
* @param {string} stderrText
|
|
142
|
+
* @returns {string}
|
|
143
|
+
*/
|
|
144
|
+
export function denyFromLegacyExit(stderrText) {
|
|
145
|
+
const reason = String(stderrText ?? '').replace(/\r/g, '').trim() || 'Denied by a HeySpex hook.';
|
|
146
|
+
return body('deny', reason);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* VS Code's Local harness ignores hook matchers, so the runner re-applies them. True when ANY matcher admits the
|
|
151
|
+
* tool (an empty / `*` / `.*` matcher admits everything; an invalid regex fails open to "admit"). Matchers are
|
|
152
|
+
* Claude Code's: a regex that must match the WHOLE tool name.
|
|
153
|
+
* @param {string[]} matchers
|
|
154
|
+
* @param {string[]} toolNames every spelling of the tool (normalized first, original after)
|
|
155
|
+
* @returns {boolean}
|
|
156
|
+
*/
|
|
157
|
+
export function toolMatchesAnyMatcher(matchers, toolNames) {
|
|
158
|
+
if (!Array.isArray(matchers) || matchers.length === 0) return true;
|
|
159
|
+
const names = toolNames.filter((n) => typeof n === 'string' && n);
|
|
160
|
+
for (const m of matchers) {
|
|
161
|
+
if (typeof m !== 'string' || m === '' || m === '*' || m === '**') return true;
|
|
162
|
+
try {
|
|
163
|
+
const re = new RegExp(`^(?:${m})$`);
|
|
164
|
+
if (names.some((n) => re.test(n))) return true;
|
|
165
|
+
} catch {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** All spellings a gate matcher might name for this (normalized) payload's tool. */
|
|
173
|
+
export function toolNameCandidates(payload) {
|
|
174
|
+
const names = [];
|
|
175
|
+
const add = (n) => { if (typeof n === 'string' && n && !names.includes(n)) names.push(n); };
|
|
176
|
+
add(payload?.tool_name);
|
|
177
|
+
add(payload?.tool_name_original);
|
|
178
|
+
if (typeof payload?.tool_name_suffix === 'string') add(`mcp__plugin_heyspex_heyspex__${payload.tool_name_suffix}`);
|
|
179
|
+
return names;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const CONTEXT_EVENTS = new Set(['SessionStart', 'PostToolUse', 'SubagentStart']);
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The ONE place the runner decides what a Copilot hook process may print. Guarantees: the result is '' or a
|
|
186
|
+
* single valid JSON object. Non-JSON output is dropped (Copilot ignores unparseable stdout anyway). Claude's
|
|
187
|
+
* `hookSpecificOutput` permission form becomes the top-level form. Copilot drops command-hook output on
|
|
188
|
+
* `UserPromptSubmit`, so a context-only result there prints nothing (a permission / block result still prints).
|
|
189
|
+
* For events that DO accept context (sessionStart, postToolUse, subagentStart) the Claude
|
|
190
|
+
* `hookSpecificOutput.additionalContext` is mirrored to the top-level `additionalContext` Copilot documents.
|
|
191
|
+
* @param {string} text raw buffered stdout
|
|
192
|
+
* @param {string} [eventName] normalized hook_event_name
|
|
193
|
+
* @returns {string}
|
|
194
|
+
*/
|
|
195
|
+
export function finalizeCopilotStdout(text, eventName) {
|
|
196
|
+
let o;
|
|
197
|
+
try {
|
|
198
|
+
o = JSON.parse(rewriteStdoutForCopilot(String(text ?? '')));
|
|
199
|
+
} catch {
|
|
200
|
+
return '';
|
|
201
|
+
}
|
|
202
|
+
if (!o || typeof o !== 'object' || Array.isArray(o)) return '';
|
|
203
|
+
const decided = typeof o.permissionDecision === 'string' || o.decision === 'block';
|
|
204
|
+
if (eventName === 'UserPromptSubmit' && !decided) return '';
|
|
205
|
+
const ctx = o.hookSpecificOutput?.additionalContext;
|
|
206
|
+
if (typeof ctx === 'string' && o.additionalContext === undefined && CONTEXT_EVENTS.has(String(eventName))) {
|
|
207
|
+
o = { ...o, additionalContext: ctx };
|
|
208
|
+
}
|
|
209
|
+
return JSON.stringify(o);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Append `extra` to a finished Copilot stdout blob's additionalContext (creating the object when stdout is
|
|
214
|
+
* empty). A permission decision is never touched. Returns the new stdout.
|
|
215
|
+
* @param {string} finalText '' or one JSON object
|
|
216
|
+
* @param {string} extra
|
|
217
|
+
* @returns {string}
|
|
218
|
+
*/
|
|
219
|
+
export function mergeAdditionalContext(finalText, extra) {
|
|
220
|
+
if (!extra) return finalText;
|
|
221
|
+
let o = {};
|
|
222
|
+
if (finalText) {
|
|
223
|
+
try { o = JSON.parse(finalText); } catch { return finalText; }
|
|
224
|
+
if (!o || typeof o !== 'object' || Array.isArray(o)) return finalText;
|
|
225
|
+
}
|
|
226
|
+
if (typeof o.permissionDecision === 'string') return finalText;
|
|
227
|
+
const prev = typeof o.additionalContext === 'string' ? o.additionalContext : o.hookSpecificOutput?.additionalContext;
|
|
228
|
+
const merged = typeof prev === 'string' && prev ? `${prev}
|
|
229
|
+
|
|
230
|
+
${extra}` : extra;
|
|
231
|
+
o.additionalContext = merged;
|
|
232
|
+
if (o.hookSpecificOutput && typeof o.hookSpecificOutput === 'object') {
|
|
233
|
+
o.hookSpecificOutput = { ...o.hookSpecificOutput, additionalContext: merged };
|
|
234
|
+
}
|
|
235
|
+
return JSON.stringify(o);
|
|
236
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// spexharness/src/adapters/detect-harness.mjs
|
|
2
|
+
//
|
|
3
|
+
// Which agent harness is invoking this hook? ([[HS-20SW-DRSM-DIAG-heyspex-capture-on-idea-and-workflow]] Copilot
|
|
4
|
+
// compatibility; contract: GitHub Docs "Hooks configuration", fetched 2026-10-16.) GitHub Copilot CLI runs the
|
|
5
|
+
// hooks registered in `.claude/settings.json` too, but it speaks a different output dialect (ONE top-level
|
|
6
|
+
// `{permissionDecision, permissionDecisionReason}` object, not `hookSpecificOutput`) and treats every
|
|
7
|
+
// non-zero exit as a deny, so the shared runner must know when it is talking to Copilot.
|
|
8
|
+
//
|
|
9
|
+
// DETECTION IS POSITIVE-SIGNATURE ONLY - never "session_id missing". Pure: payload + env in, a string out.
|
|
10
|
+
// - explicit override HEYSPEX_HARNESS = copilot | claude-code | cursor (wins)
|
|
11
|
+
// - 'copilot' the payload carries `timestamp` (absent from Claude Code payloads) AND no Cursor marker; or it
|
|
12
|
+
// is the camelCase config shape ({ sessionId, toolName, toolArgs } with no snake_case twins).
|
|
13
|
+
// - 'cursor' `conversation_id` / `workspace_roots` / `cursor_version` present.
|
|
14
|
+
// - 'claude-code' a `hook_event_name` + `session_id` payload with none of the above.
|
|
15
|
+
// - 'unknown' anything else (including a non-object payload). Callers treat unknown like claude-code.
|
|
16
|
+
|
|
17
|
+
const OVERRIDES = new Set(['copilot', 'claude-code', 'cursor']);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {unknown} payload parsed hook stdin (or null)
|
|
21
|
+
* @param {Record<string, string | undefined>} [env]
|
|
22
|
+
* @returns {'claude-code' | 'copilot' | 'cursor' | 'unknown'}
|
|
23
|
+
*/
|
|
24
|
+
export function detectHarness(payload, env = process.env) {
|
|
25
|
+
const forced = String(env?.HEYSPEX_HARNESS ?? '').trim().toLowerCase();
|
|
26
|
+
if (OVERRIDES.has(forced)) return forced;
|
|
27
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return 'unknown';
|
|
28
|
+
const p = /** @type {Record<string, unknown>} */ (payload);
|
|
29
|
+
if ('conversation_id' in p || 'workspace_roots' in p || 'cursor_version' in p) return 'cursor';
|
|
30
|
+
const camel = ('toolName' in p || 'toolArgs' in p) && !('tool_name' in p);
|
|
31
|
+
if ('timestamp' in p || camel) return 'copilot';
|
|
32
|
+
if (typeof p.hook_event_name === 'string' && typeof p.session_id === 'string') return 'claude-code';
|
|
33
|
+
return 'unknown';
|
|
34
|
+
}
|