heyspex 0.2.2 → 0.2.3
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/README.md +10 -0
- package/bin/hs-vault-binding.mjs +157 -0
- package/bin/hs.mjs +81 -77
- package/bin/spexcode.mjs +91 -0
- package/dev-factory/engine/worktree.mjs +36 -7
- package/dev-factory/lib/epic-detect.mjs +2 -2
- package/dev-factory/lib/fleet-readiness.mjs +3 -5
- package/dev-factory/lib/fleet-state.mjs +2 -2
- package/dev-factory/lib/sufficiency-score.mjs +3 -5
- package/dist/cli/hs-check.mjs +76 -46
- package/dist/cli/hs-claim.mjs +63 -33
- package/dist/cli/hs-connect.mjs +520 -214
- package/dist/cli/hs-defer.mjs +161 -19
- package/dist/cli/hs-dev.mjs +11 -5
- package/dist/cli/hs-env.mjs +187 -161
- package/dist/cli/hs-index-rebuild.mjs +123 -78
- package/dist/cli/hs-index-reconcile.mjs +203 -107
- package/dist/cli/hs-init.mjs +426 -179
- package/dist/cli/hs-install.mjs +759 -437
- package/dist/cli/hs-join.mjs +590 -383
- package/dist/cli/hs-vault-pull.mjs +359 -254
- package/dist/cli/hs-vault-push.mjs +151 -113
- package/dist/cli/hs-vault.mjs +271 -104
- package/dist/cli/hs-workspace.mjs +90 -57
- package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +178 -91
- package/docs/copilot-plugin-install.md +189 -177
- package/docs/driving-heyspex-from-copilot.md +174 -165
- package/docs/mcp-client-config.md +93 -25
- package/package.json +255 -250
- package/plugins/heyspex/.mcp.json +3 -4
- package/plugins/heyspex/README.md +323 -312
- package/plugins/heyspex/bin/launch-mcp.mjs +21 -7
- package/plugins/heyspex/mcp.json +12 -13
- package/scripts/check-mcp-freshness.mjs +6 -4
- package/scripts/claude-hooks/_intent-classifier-router.mjs +518 -456
- package/scripts/claude-hooks/intent-classifier-trigger.mjs +305 -279
- package/scripts/claude-hooks/research-method-guard.mjs +2 -2
- package/scripts/claude-hooks/wip-checkpoint.mjs +33 -9
- package/scripts/claude-statusline/fonts/HeySpexIcons.ttf +0 -0
- package/scripts/claude-statusline/statusline-command.mjs +1058 -0
- package/scripts/dev-server-status.mjs +3 -2
- package/scripts/dev-server-stop.mjs +3 -2
- package/scripts/hs-capture-cli.mjs +2 -2
- package/scripts/hs-settings.mjs +2 -2
- package/scripts/hs-view.mjs +3 -2
- package/scripts/install-copilot-hooks.mjs +64 -34
- package/scripts/lib/copilot-cli.mjs +108 -0
- package/scripts/lib/customer-kit.mjs +223 -30
- package/scripts/lib/dev-mode.mjs +28 -2
- package/scripts/lib/shared-path-helpers.mjs +32 -0
- package/scripts/lib/standalone-doctor.mjs +131 -32
- package/scripts/wip-ledger-health.mjs +3 -2
- package/spexharness/src/gates/vault-mirror-catchup.mjs +113 -24
- package/spexharness/src/gates/vault-mirror-catchup.runner.mjs +52 -0
- package/spexharness/src/intent-directive.mjs +839 -626
- package/spexharness/src/rule-table.mjs +1 -1
- package/vendor/heyspex-mcp/cli-verbs.mjs +16 -2
- package/vendor/heyspex-mcp/cli.mjs +20 -4
- package/vendor/heyspex-mcp/console-fetch.mjs +15 -3
- package/vendor/heyspex-mcp/dev-tools.mjs +11 -4
- package/vendor/heyspex-mcp/events-tools.mjs +1 -1
- package/vendor/heyspex-mcp/factory-run-status.mjs +42 -0
- package/vendor/heyspex-mcp/mcp-config.mjs +4 -2
- package/vendor/heyspex-mcp/spec-edit-tools.mjs +26 -1
- package/vendor/heyspex-mcp/test-helpers.mjs +5 -2
- package/vendor/heyspex-mcp/tool-catalog.mjs +12 -0
- package/vendor/heyspex-mcp/tool-dispatch.mjs +59 -23
- package/vendor/heyspex-mcp/usable-dir-env.mjs +82 -0
- package/vendor/heyspex-mcp/vault-binding.mjs +839 -0
- package/vendor/heyspex-mcp/vault-resolve.mjs +353 -245
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
import fs from 'node:fs';
|
|
49
49
|
import path from 'node:path';
|
|
50
50
|
import { fileURLToPath } from 'node:url';
|
|
51
|
-
import { getActiveConfig } from '../../vendor/heyspex-mcp/vault-resolve.mjs';
|
|
51
|
+
import { getActiveConfig, isResolvedVault } from '../../vendor/heyspex-mcp/vault-resolve.mjs';
|
|
52
52
|
import { hookVaultHeaders } from '../lib/hook-vault-header.mjs';
|
|
53
53
|
import { resolveConsoleUrl as resolveConsoleUrlShared } from '../lib/console-url-resolver.mjs';
|
|
54
54
|
import { readCredentialsMcpToken, resolveDevMode } from '../lib/dev-mode.mjs';
|
|
@@ -68,26 +68,48 @@ function repoRoot() {
|
|
|
68
68
|
// code checkout. Reading repoRoot() here previewed a frozen pre-split snapshot to
|
|
69
69
|
// every new session — the HS-OR8H repo-split "quiet window OPEN" notice kept
|
|
70
70
|
// re-appearing for days after the window closed, because the live ledger had moved
|
|
71
|
-
// and this copy never advanced. Resolve the vault first; fall back to the
|
|
72
|
-
// so a pre-split or standalone checkout still previews its own ledger.
|
|
71
|
+
// and this copy never advanced. Resolve the vault first; fall back to the session's
|
|
72
|
+
// own project so a pre-split or standalone checkout still previews its own ledger.
|
|
73
73
|
function vaultRoot() {
|
|
74
74
|
try {
|
|
75
|
-
|
|
75
|
+
const resolved = getActiveConfig();
|
|
76
|
+
return isResolvedVault(resolved) ? resolved.repoRootAbs ?? null : null;
|
|
76
77
|
} catch {
|
|
77
|
-
return null; // registry unreadable — the
|
|
78
|
+
return null; // registry unreadable — the project base still applies
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
//
|
|
82
|
+
// The session's project — NOT this script's location. In a satellite repo the hook
|
|
83
|
+
// runs out of the `heyspex` package (node_modules/heyspex, often an npm link to the
|
|
84
|
+
// platform checkout), so repoRoot() is the PLATFORM's tree and its ledger belongs to
|
|
85
|
+
// somebody else's sessions: a satellite once previewed the platform checkout's
|
|
86
|
+
// `HS-EPIC-FILLER-20` (a leaked wip-state.prune.test.ts fixture) as its own WIP.
|
|
87
|
+
function projectDir() {
|
|
88
|
+
const fromEnv = process.env.CLAUDE_PROJECT_DIR;
|
|
89
|
+
return path.resolve(typeof fromEnv === 'string' && fromEnv.trim() ? fromEnv.trim() : process.cwd());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Ledger roots in precedence order: bound vault first, the session's project second.
|
|
93
|
+
// The package's own checkout is never a root unless it IS the project.
|
|
82
94
|
function ledgerRoots() {
|
|
83
95
|
const roots = [];
|
|
84
96
|
const vault = vaultRoot();
|
|
85
|
-
if (vault) roots.push(vault);
|
|
86
|
-
const
|
|
87
|
-
if (!roots.includes(
|
|
97
|
+
if (vault) roots.push(path.resolve(vault));
|
|
98
|
+
const project = projectDir();
|
|
99
|
+
if (!roots.includes(project)) roots.push(project);
|
|
88
100
|
return roots;
|
|
89
101
|
}
|
|
90
102
|
|
|
103
|
+
// Defense in depth against test fixtures that escaped into a real ledger (the
|
|
104
|
+
// wip-state*.test.ts suites write ids like HS-EPIC-FILLER-07, HS-EPIC-OLD34,
|
|
105
|
+
// HS-EPIC-BUD-PROTECT under vault id `vault-test`). Real ids are server-minted
|
|
106
|
+
// file keys; a SessionStart preview must never present one of these as the
|
|
107
|
+
// prior session's hand-off.
|
|
108
|
+
const FIXTURE_ID_RE = /^HS-EPIC-(?:FILLER-\d+|OLD\d+|BUD-[A-Z0-9-]+|CLAIMED-BUD|TRIGGER(?:-[A-Z0-9-]+)?)$/;
|
|
109
|
+
function isFixtureLedgerEntry(epicId) {
|
|
110
|
+
return typeof epicId === 'string' && FIXTURE_ID_RE.test(epicId);
|
|
111
|
+
}
|
|
112
|
+
|
|
91
113
|
async function readStdinJson() {
|
|
92
114
|
if (process.stdin.isTTY) return null;
|
|
93
115
|
return new Promise((resolve) => {
|
|
@@ -152,6 +174,7 @@ function mostRecentLedgerEntry() {
|
|
|
152
174
|
let best = null;
|
|
153
175
|
for (const [epicId, entry] of Object.entries(parsed)) {
|
|
154
176
|
if (!entry || typeof entry !== 'object') continue;
|
|
177
|
+
if (isFixtureLedgerEntry(epicId)) continue;
|
|
155
178
|
const updatedAt = typeof entry.updatedAt === 'string' ? entry.updatedAt : '';
|
|
156
179
|
if (!best || updatedAt > best.updatedAt) {
|
|
157
180
|
best = { epicId, updatedAt, entry };
|
|
@@ -228,6 +251,7 @@ async function fetchCloudLedgerEntry(root) {
|
|
|
228
251
|
let best = null;
|
|
229
252
|
for (const [specId, entry] of Object.entries(wipState)) {
|
|
230
253
|
if (!entry || typeof entry !== 'object') continue;
|
|
254
|
+
if (isFixtureLedgerEntry(specId)) continue;
|
|
231
255
|
const updatedAt = typeof entry.updatedAt === 'string' ? entry.updatedAt : '';
|
|
232
256
|
if (!best || updatedAt > best.updatedAt) {
|
|
233
257
|
best = { epicId: specId, updatedAt, entry };
|
|
Binary file
|