heyspex 0.2.1 → 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 +99 -81
- 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 -162
- package/docs/driving-heyspex-from-copilot.md +174 -165
- package/docs/mcp-client-config.md +93 -25
- package/package.json +255 -249
- package/plugins/heyspex/.mcp.json +3 -4
- package/plugins/heyspex/README.md +323 -309
- 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 +318 -0
- 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
|
@@ -34,6 +34,8 @@ import { spawnSync } from "node:child_process";
|
|
|
34
34
|
import { join, resolve, dirname } from "node:path";
|
|
35
35
|
import { fileURLToPath } from "node:url";
|
|
36
36
|
import { tmpdir } from "node:os";
|
|
37
|
+
import { toRunnerRelativePath } from "../lib/runner-path.mjs";
|
|
38
|
+
import { isNoTestFilesOutput } from "../lib/dispatch-guard.mjs";
|
|
37
39
|
|
|
38
40
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
39
41
|
|
|
@@ -97,13 +99,24 @@ export function runTsc(ctx, worktree) {
|
|
|
97
99
|
return { count: (out.match(/error TS\d+/g) || []).length, status: r.status, output: out.trim().slice(0, 1200), timedOut: r.error?.code === "ETIMEDOUT" };
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
/**
|
|
102
|
+
/** The vitest filter for `testRel` as seen from vitest's cwd (<worktree>/<spex>). Callers pass
|
|
103
|
+
* the test REPO-relative ("spex-console/src/x.test.ts", same convention as task.target) or
|
|
104
|
+
* already spex-relative ("src/x.test.ts"); vitest only matches the latter from its cwd —
|
|
105
|
+
* the repo-relative form printed "No test files found" and was misread as a red baseline
|
|
106
|
+
* (HS-7BYJ, 2026-10-15). */
|
|
107
|
+
export function vitestFilter(ctx, worktree, testRel) {
|
|
108
|
+
return toRunnerRelativePath(testRel, { cwdRel: ctx.spex, roots: [worktree, ctx.repo] });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Run a scoped vitest file in <worktree>/<spex>. Returns { pass, output, timedOut, cwd, filter }. */
|
|
101
112
|
export function runVitest(ctx, worktree, testRel) {
|
|
102
|
-
const
|
|
103
|
-
|
|
113
|
+
const cwd = join(worktree, ctx.spex);
|
|
114
|
+
const filter = vitestFilter(ctx, worktree, testRel);
|
|
115
|
+
const r = spawnSync(`npx --no-install vitest run ${filter}`, {
|
|
116
|
+
cwd, shell: true, encoding: "utf8", timeout: ctx.testTimeout,
|
|
104
117
|
});
|
|
105
118
|
const out = ((r.stdout || "") + (r.stderr || ""));
|
|
106
|
-
return { pass: r.status === 0 && !r.error, output: out.trim().slice(-1200), timedOut: r.error?.code === "ETIMEDOUT" };
|
|
119
|
+
return { pass: r.status === 0 && !r.error, output: out.trim().slice(-1200), timedOut: r.error?.code === "ETIMEDOUT", cwd, filter };
|
|
107
120
|
}
|
|
108
121
|
|
|
109
122
|
// HS-AY5K: the deterministic gate used to run EVERY test file through scoped
|
|
@@ -191,7 +204,10 @@ export function runPlainSelfTestScript(ctx, worktree, testRel) {
|
|
|
191
204
|
* runGate and baselineTest both call through, so the routing rule lives in exactly
|
|
192
205
|
* one place. Order matters: node:test and the plain-self-test conventions are both
|
|
193
206
|
* narrow, cheap-to-check positives; vitest is the default fallback for everything else. */
|
|
194
|
-
function runScopedTest(ctx, worktree,
|
|
207
|
+
function runScopedTest(ctx, worktree, testPath) {
|
|
208
|
+
// Root-relative for the node runners (cwd = worktree root); an absolute or backslashed
|
|
209
|
+
// path is re-rooted here, and runVitest re-relativizes it to its own spex cwd.
|
|
210
|
+
const testRel = toRunnerRelativePath(testPath, { cwdRel: "", roots: [worktree, ctx.repo] });
|
|
195
211
|
const abs = join(worktree, testRel);
|
|
196
212
|
if (isNodeTestFile(abs)) return runNodeTest(ctx, worktree, testRel);
|
|
197
213
|
if (isPlainSelfTestScript(abs)) return runPlainSelfTestScript(ctx, worktree, testRel);
|
|
@@ -290,7 +306,8 @@ export function runLanguageGate(ctx, worktree, task, code, { buildCmd, testCmd,
|
|
|
290
306
|
// relative against `worktree`; vitest resolves it spex-relative against
|
|
291
307
|
// `worktree/ctx.spex`) — a NEW-FILE test could land under either once the builder
|
|
292
308
|
// creates it.
|
|
293
|
-
function testExistsAtBaseline(ctx, worktree,
|
|
309
|
+
function testExistsAtBaseline(ctx, worktree, testPath) {
|
|
310
|
+
const testRel = toRunnerRelativePath(testPath, { cwdRel: "", roots: [worktree, ctx.repo] });
|
|
294
311
|
return existsSync(join(worktree, testRel)) || existsSync(join(worktree, ctx.spex, testRel));
|
|
295
312
|
}
|
|
296
313
|
|
|
@@ -302,7 +319,19 @@ export function baselineTest(ctx, worktree, testRel) {
|
|
|
302
319
|
output: `test file does not exist at baseline (${testRel}) — expected NEW-FILE condition, not a gate/environment fault`,
|
|
303
320
|
};
|
|
304
321
|
}
|
|
305
|
-
|
|
322
|
+
const r = runScopedTest(ctx, worktree, testRel);
|
|
323
|
+
// The file EXISTS (checked above), so a runner that still reports "No test files found"
|
|
324
|
+
// is a path/filter mismatch between the caller and the runner's cwd — never a silent
|
|
325
|
+
// environment fault. Name the cwd and the filter so the fix is obvious (HS-7BYJ).
|
|
326
|
+
if (!r.pass && isNoTestFilesOutput(r.output)) {
|
|
327
|
+
return {
|
|
328
|
+
...r,
|
|
329
|
+
runnerPathMismatch: true,
|
|
330
|
+
output: `runner found no test files although ${testRel} exists — runner cwd: ${r.cwd ?? worktree}, filter: ${r.filter ?? testRel}. `
|
|
331
|
+
+ `The test path is not relative to the runner's cwd (or the runner's include globs exclude it); fix the path convention, not the code.\n${r.output}`,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
return r;
|
|
306
335
|
}
|
|
307
336
|
|
|
308
337
|
// HS-L9BX: `setupWorktree` builds the gate's worktree from `git worktree add --detach
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* exact -EPIC-suffix regression that motivated the module.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import {
|
|
29
|
+
import { isMainModule } from "../../scripts/lib/shared-path-helpers.mjs";
|
|
30
30
|
|
|
31
31
|
const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
32
32
|
|
|
@@ -185,6 +185,6 @@ function runSelfTest() {
|
|
|
185
185
|
return ok ? 0 : 1;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
if (
|
|
188
|
+
if (isMainModule(import.meta.url)) {
|
|
189
189
|
if (process.argv.includes("--self-test")) process.exit(runSelfTest());
|
|
190
190
|
}
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
import { loadFleetState } from "./fleet-state.mjs";
|
|
15
15
|
import { readFileSync } from "node:fs";
|
|
16
16
|
import path from "node:path";
|
|
17
|
-
import { fileURLToPath
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { isMainModule } from "../../scripts/lib/shared-path-helpers.mjs";
|
|
18
19
|
|
|
19
20
|
export const DEFAULT_FLEET_FRESHNESS_MS = 15 * 60 * 1000; // 15 minutes
|
|
20
21
|
|
|
@@ -266,9 +267,6 @@ function runSelfTest() {
|
|
|
266
267
|
return ok ? 0 : 1;
|
|
267
268
|
}
|
|
268
269
|
|
|
269
|
-
if (
|
|
270
|
-
process.argv[1] &&
|
|
271
|
-
pathToFileURL(process.argv[1]).href === import.meta.url
|
|
272
|
-
) {
|
|
270
|
+
if (isMainModule(import.meta.url)) {
|
|
273
271
|
if (process.argv.includes("--self-test")) process.exit(runSelfTest());
|
|
274
272
|
}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync } from "node:fs";
|
|
32
32
|
import { join } from "node:path";
|
|
33
|
-
import {
|
|
33
|
+
import { isMainModule } from "../../scripts/lib/shared-path-helpers.mjs";
|
|
34
34
|
import { tmpdir } from "node:os";
|
|
35
35
|
import { codeRepoRoot } from "./code-repo-root.mjs";
|
|
36
36
|
import { OLLAMA } from "./model-catalog.mjs";
|
|
@@ -232,7 +232,7 @@ function runSelfTest() {
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
// ── Main ─────────────────────────────────────────────────────────────────────────
|
|
235
|
-
if (
|
|
235
|
+
if (isMainModule(import.meta.url)) {
|
|
236
236
|
if (process.argv.includes("--self-test")) process.exit(runSelfTest());
|
|
237
237
|
console.log([
|
|
238
238
|
"lib/fleet-state.mjs — per-machine runtime state sidecar (.heyspex/fleet-state.json).",
|
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
* `node dev-factory/lib/sufficiency-score.mjs --self-test`).
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
|
-
import { fileURLToPath
|
|
45
|
+
import { fileURLToPath } from "node:url";
|
|
46
|
+
import { isMainModule } from "../../scripts/lib/shared-path-helpers.mjs";
|
|
46
47
|
import { readFileSync, existsSync } from "node:fs";
|
|
47
48
|
import { join, dirname } from "node:path";
|
|
48
49
|
|
|
@@ -439,9 +440,6 @@ function runSelfTest() {
|
|
|
439
440
|
return ok ? 0 : 1;
|
|
440
441
|
}
|
|
441
442
|
|
|
442
|
-
if (
|
|
443
|
-
process.argv[1] &&
|
|
444
|
-
pathToFileURL(process.argv[1]).href === import.meta.url
|
|
445
|
-
) {
|
|
443
|
+
if (isMainModule(import.meta.url)) {
|
|
446
444
|
if (process.argv.includes("--self-test")) process.exit(runSelfTest());
|
|
447
445
|
}
|
package/dist/cli/hs-check.mjs
CHANGED
|
@@ -124,9 +124,9 @@ function resolveBearer({ envToken, credentialsText, accountId, legacyAccountId }
|
|
|
124
124
|
if (entry?.mcp_token) return { token: entry.mcp_token, source: "credentials-file" };
|
|
125
125
|
return { token: null, source: null };
|
|
126
126
|
}
|
|
127
|
-
function readTextOrNull(read,
|
|
127
|
+
function readTextOrNull(read, path4) {
|
|
128
128
|
try {
|
|
129
|
-
const raw = read(
|
|
129
|
+
const raw = read(path4);
|
|
130
130
|
return typeof raw === "string" ? raw : null;
|
|
131
131
|
} catch {
|
|
132
132
|
return null;
|
|
@@ -169,8 +169,8 @@ var init_credentials = __esm({
|
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
// scripts/lib/dev-mode.mjs
|
|
172
|
-
import { mkdirSync as
|
|
173
|
-
import { homedir as
|
|
172
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
173
|
+
import { homedir as homedir8 } from "node:os";
|
|
174
174
|
import { join as join8 } from "node:path";
|
|
175
175
|
function devModeFilePath(homeDir = heyspexHome()) {
|
|
176
176
|
return join8(homeDir, ".heyspex", DEV_MODE_FILENAME);
|
|
@@ -225,6 +225,11 @@ function readLocalDevModeRecord({ homeDir = heyspexHome(), readFile = defaultRea
|
|
|
225
225
|
return { record: null, parseError: `unparseable dev-mode.json: ${String(err?.message ?? err)}` };
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
|
+
function overrideCloudCheck(source, cloudKnown, staleAgainstCloud) {
|
|
229
|
+
if (source !== "local-override") return "not-applicable";
|
|
230
|
+
if (!cloudKnown) return "unverified";
|
|
231
|
+
return staleAgainstCloud ? "stale" : "in-sync";
|
|
232
|
+
}
|
|
228
233
|
function resolveDevMode({
|
|
229
234
|
env = process.env,
|
|
230
235
|
homeDir = heyspexHome(),
|
|
@@ -264,6 +269,7 @@ function resolveDevMode({
|
|
|
264
269
|
const semantics = deriveSemantics(mode, reliance);
|
|
265
270
|
const consoleUrl = source === "local-override" && local.record?.console_url ? local.record.console_url.replace(/\/+$/, "") : semantics.consoleUrl;
|
|
266
271
|
const staleAgainstCloud = source === "local-override" && cloudValue !== null && (cloudValue.mode !== mode || mode === "dev" && cloudValue.reliance !== semantics.reliance);
|
|
272
|
+
const cloudCheck = overrideCloudCheck(source, cloudKnown, staleAgainstCloud);
|
|
267
273
|
return {
|
|
268
274
|
mode,
|
|
269
275
|
reliance: semantics.reliance,
|
|
@@ -281,7 +287,8 @@ function resolveDevMode({
|
|
|
281
287
|
present: local.record !== null,
|
|
282
288
|
record: local.record,
|
|
283
289
|
parseError: local.parseError,
|
|
284
|
-
staleAgainstCloud
|
|
290
|
+
staleAgainstCloud,
|
|
291
|
+
cloudCheck
|
|
285
292
|
},
|
|
286
293
|
cloudSetting: { known: cloudKnown, value: cloudValue }
|
|
287
294
|
};
|
|
@@ -295,18 +302,20 @@ var init_dev_mode = __esm({
|
|
|
295
302
|
CLOUD_CONSOLE_URL = "https://app.heyspex.com";
|
|
296
303
|
LOCAL_CONSOLE_URL = "http://localhost:3000";
|
|
297
304
|
DEV_MODE_FILENAME = "dev-mode.json";
|
|
298
|
-
defaultReadFile = (p) =>
|
|
305
|
+
defaultReadFile = (p) => readFileSync8(p, "utf8");
|
|
299
306
|
}
|
|
300
307
|
});
|
|
301
308
|
|
|
302
309
|
// spex-console/bin/hs-check.ts
|
|
303
310
|
import { spawn, spawnSync } from "node:child_process";
|
|
304
|
-
import { existsSync as
|
|
305
|
-
import
|
|
311
|
+
import { existsSync as existsSync6, readFileSync as readFileSync10 } from "node:fs";
|
|
312
|
+
import path3 from "node:path";
|
|
306
313
|
import process3 from "node:process";
|
|
307
314
|
|
|
308
315
|
// scripts/lib/shared-path-helpers.mjs
|
|
316
|
+
import { realpathSync } from "node:fs";
|
|
309
317
|
import { isAbsolute, resolve, sep } from "node:path";
|
|
318
|
+
import { fileURLToPath } from "node:url";
|
|
310
319
|
function resolveCodeRoot({
|
|
311
320
|
explicit,
|
|
312
321
|
packageRoot,
|
|
@@ -751,16 +760,16 @@ var HELP = [
|
|
|
751
760
|
].join("\n");
|
|
752
761
|
|
|
753
762
|
// spex-console/src/lib/cli/control-shared.ts
|
|
754
|
-
import
|
|
763
|
+
import path2 from "node:path";
|
|
755
764
|
|
|
756
765
|
// scripts/lib/hs-command.mjs
|
|
757
766
|
import { existsSync } from "node:fs";
|
|
758
767
|
import { delimiter, dirname, join } from "node:path";
|
|
759
|
-
import { fileURLToPath } from "node:url";
|
|
768
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
760
769
|
var HS_BIN_NAME = "hs";
|
|
761
770
|
var HS_DISPATCHER_PATH = (() => {
|
|
762
771
|
try {
|
|
763
|
-
const here = dirname(
|
|
772
|
+
const here = dirname(fileURLToPath2(import.meta.url));
|
|
764
773
|
return join(dirname(dirname(here)), "bin", "hs.mjs");
|
|
765
774
|
} catch {
|
|
766
775
|
return null;
|
|
@@ -841,8 +850,8 @@ function hsCommand(args = "", options = {}) {
|
|
|
841
850
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
842
851
|
init_heyspex_home();
|
|
843
852
|
init_credentials();
|
|
844
|
-
import { readFileSync as
|
|
845
|
-
import { homedir as
|
|
853
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
854
|
+
import { homedir as homedir6 } from "node:os";
|
|
846
855
|
import { join as join6 } from "node:path";
|
|
847
856
|
|
|
848
857
|
// vendor/heyspex-mcp/session-owner.mjs
|
|
@@ -867,14 +876,14 @@ var VAULT_LESS_ENDPOINTS = Object.freeze([
|
|
|
867
876
|
"GET /api/workspaces",
|
|
868
877
|
"* /api/admin/dev-mode"
|
|
869
878
|
]);
|
|
870
|
-
function pathnameOf(
|
|
871
|
-
const raw = String(
|
|
879
|
+
function pathnameOf(path4) {
|
|
880
|
+
const raw = String(path4 ?? "").split("?")[0].split("#")[0];
|
|
872
881
|
const noTrailing = raw.length > 1 ? raw.replace(/\/+$/, "") : raw;
|
|
873
882
|
return noTrailing || "/";
|
|
874
883
|
}
|
|
875
|
-
function isVaultLessEndpoint(method,
|
|
884
|
+
function isVaultLessEndpoint(method, path4) {
|
|
876
885
|
const m = String(method || "GET").toUpperCase();
|
|
877
|
-
const pathname = pathnameOf(
|
|
886
|
+
const pathname = pathnameOf(path4);
|
|
878
887
|
return VAULT_LESS_ENDPOINTS.some((row) => {
|
|
879
888
|
const [rowMethod, rowPath] = row.split(" ");
|
|
880
889
|
return rowPath === pathname && (rowMethod === "*" || rowMethod === m);
|
|
@@ -895,9 +904,30 @@ import { basename, join as join4, isAbsolute as isAbsolute2 } from "node:path";
|
|
|
895
904
|
|
|
896
905
|
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
897
906
|
init_heyspex_home();
|
|
898
|
-
import { existsSync as
|
|
899
|
-
import { homedir as
|
|
900
|
-
|
|
907
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
908
|
+
import { homedir as homedir5, tmpdir } from "node:os";
|
|
909
|
+
|
|
910
|
+
// vendor/heyspex-mcp/usable-dir-env.mjs
|
|
911
|
+
import { statSync } from "node:fs";
|
|
912
|
+
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
913
|
+
|
|
914
|
+
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
915
|
+
import { basename as basename2, dirname as dirname3, join as join5, resolve as resolve3 } from "node:path";
|
|
916
|
+
|
|
917
|
+
// vendor/heyspex-mcp/vault-binding.mjs
|
|
918
|
+
import {
|
|
919
|
+
copyFileSync,
|
|
920
|
+
existsSync as existsSync3,
|
|
921
|
+
mkdirSync as mkdirSync3,
|
|
922
|
+
readFileSync as readFileSync4,
|
|
923
|
+
realpathSync as realpathSync2,
|
|
924
|
+
renameSync as renameSync3,
|
|
925
|
+
statSync as statSync2,
|
|
926
|
+
unlinkSync,
|
|
927
|
+
writeFileSync as writeFileSync3
|
|
928
|
+
} from "node:fs";
|
|
929
|
+
import { homedir as homedir4 } from "node:os";
|
|
930
|
+
import path from "node:path";
|
|
901
931
|
|
|
902
932
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
903
933
|
var VAULT_NOT_REGISTERED = "VAULT_NOT_REGISTERED";
|
|
@@ -929,7 +959,7 @@ function isCloudVaultId(value) {
|
|
|
929
959
|
var MARKER_VAULT_ID_RE = /^vault_id:[ \t]*["']?([^"'\r\n#]+)/m;
|
|
930
960
|
function readMarkerVaultId(repoRootAbs, { readFile } = {}) {
|
|
931
961
|
if (typeof repoRootAbs !== "string" || !repoRootAbs.trim()) return null;
|
|
932
|
-
const read = readFile ?? ((p) =>
|
|
962
|
+
const read = readFile ?? ((p) => readFileSync6(p, "utf8"));
|
|
933
963
|
try {
|
|
934
964
|
const raw = read(join6(repoRootAbs, "heyspex.yaml"));
|
|
935
965
|
const value = String(raw ?? "").match(MARKER_VAULT_ID_RE)?.[1]?.trim() ?? "";
|
|
@@ -951,17 +981,17 @@ var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMAT
|
|
|
951
981
|
init_credentials();
|
|
952
982
|
|
|
953
983
|
// spex-console/src/lib/vault-registry/registry-file.ts
|
|
954
|
-
import { existsSync as
|
|
984
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
955
985
|
import { dirname as dirname4, join as join7, resolve as resolve4 } from "node:path";
|
|
956
986
|
|
|
957
987
|
// spex-console/src/lib/heyspex-home.ts
|
|
958
|
-
import { homedir as
|
|
988
|
+
import { homedir as homedir7 } from "node:os";
|
|
959
989
|
function heyspexHome2(env = process.env) {
|
|
960
990
|
const override = env?.HEYSPEX_HOME;
|
|
961
991
|
if (typeof override === "string" && override.trim().length > 0) {
|
|
962
992
|
return override.trim();
|
|
963
993
|
}
|
|
964
|
-
return
|
|
994
|
+
return homedir7();
|
|
965
995
|
}
|
|
966
996
|
|
|
967
997
|
// spex-console/src/lib/vault-registry/types.ts
|
|
@@ -1083,9 +1113,9 @@ function parseVaultRegistryFile(json) {
|
|
|
1083
1113
|
}
|
|
1084
1114
|
function readRegistryJson(opts) {
|
|
1085
1115
|
const filePath = vaultRegistryFilePath(opts);
|
|
1086
|
-
if (!
|
|
1116
|
+
if (!existsSync5(filePath)) return { kind: "missing" };
|
|
1087
1117
|
try {
|
|
1088
|
-
const raw =
|
|
1118
|
+
const raw = readFileSync7(filePath, "utf8");
|
|
1089
1119
|
const json = JSON.parse(raw);
|
|
1090
1120
|
if (registryFileSchemaOf(json) === null) return { kind: "unreadable" };
|
|
1091
1121
|
return { kind: "ok", raw, json };
|
|
@@ -1220,11 +1250,11 @@ function bearerHeaderFor(consoleUrl, opts = {}) {
|
|
|
1220
1250
|
return {};
|
|
1221
1251
|
}
|
|
1222
1252
|
}
|
|
1223
|
-
function scopeHeadersFor(scope, method,
|
|
1253
|
+
function scopeHeadersFor(scope, method, path4) {
|
|
1224
1254
|
if (scope === "none") {
|
|
1225
|
-
if (!isVaultLessEndpoint(method,
|
|
1255
|
+
if (!isVaultLessEndpoint(method, path4)) {
|
|
1226
1256
|
throw new Error(
|
|
1227
|
-
`controlRequest: scope "none" is only allowed for the vault-less endpoints (${VAULT_LESS_ENDPOINTS.join(", ")}); ${method.toUpperCase()} ${
|
|
1257
|
+
`controlRequest: scope "none" is only allowed for the vault-less endpoints (${VAULT_LESS_ENDPOINTS.join(", ")}); ${method.toUpperCase()} ${path4} is vault-scoped and must name { accountId, vaultId }.`
|
|
1228
1258
|
);
|
|
1229
1259
|
}
|
|
1230
1260
|
return {};
|
|
@@ -1293,7 +1323,7 @@ async function controlRequest(deps, req) {
|
|
|
1293
1323
|
return { ok: true, status: res.status, body: parsed };
|
|
1294
1324
|
}
|
|
1295
1325
|
function normalizeRoot(p) {
|
|
1296
|
-
return
|
|
1326
|
+
return path2.resolve(p).replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
1297
1327
|
}
|
|
1298
1328
|
function resolveControlScope(input) {
|
|
1299
1329
|
const target = normalizeRoot(input.vaultRoot);
|
|
@@ -1362,8 +1392,8 @@ function resolveControlScopeFromMachine(vaultRoot, opts = {}) {
|
|
|
1362
1392
|
// scripts/lib/console-url-resolver.mjs
|
|
1363
1393
|
init_heyspex_home();
|
|
1364
1394
|
init_dev_mode();
|
|
1365
|
-
import { readFileSync as
|
|
1366
|
-
import { homedir as
|
|
1395
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
1396
|
+
import { homedir as homedir9 } from "node:os";
|
|
1367
1397
|
import { join as join9 } from "node:path";
|
|
1368
1398
|
var DEFAULT_CONSOLE_URL = LOCAL_CONSOLE_URL;
|
|
1369
1399
|
function trimTrailingSlash(url) {
|
|
@@ -1401,7 +1431,7 @@ function readCredentialsConsoleUrl({ homeDir = heyspexHome(), readFile = default
|
|
|
1401
1431
|
}
|
|
1402
1432
|
}
|
|
1403
1433
|
function defaultReadFile2(p) {
|
|
1404
|
-
return
|
|
1434
|
+
return readFileSync9(p, "utf8");
|
|
1405
1435
|
}
|
|
1406
1436
|
function readDiscoveryFileConsoleUrl(repoRoot, { readDiscovery = defaultReadFile2 } = {}) {
|
|
1407
1437
|
if (!repoRoot) return null;
|
|
@@ -1527,14 +1557,14 @@ function runEntry(name, main2, options = {}) {
|
|
|
1527
1557
|
|
|
1528
1558
|
// spex-console/bin/hs-check.ts
|
|
1529
1559
|
function manifestForSpecId(vaultRoot, specId) {
|
|
1530
|
-
return
|
|
1560
|
+
return path3.join(vaultRoot, "specs", "checks", `${specId}.checks.json`);
|
|
1531
1561
|
}
|
|
1532
1562
|
function resolveManifestPath(target, vaultRoot, invokedCwd) {
|
|
1533
|
-
const literal =
|
|
1534
|
-
if (
|
|
1563
|
+
const literal = path3.resolve(invokedCwd, target);
|
|
1564
|
+
if (existsSync6(literal)) return literal;
|
|
1535
1565
|
if (target.endsWith(".json")) return null;
|
|
1536
1566
|
const byId = manifestForSpecId(vaultRoot, target);
|
|
1537
|
-
return
|
|
1567
|
+
return existsSync6(byId) ? byId : null;
|
|
1538
1568
|
}
|
|
1539
1569
|
function countTscErrors(output) {
|
|
1540
1570
|
const matches = output.match(/error TS\d+/g);
|
|
@@ -1548,12 +1578,12 @@ function resolveWindowsPosixShell() {
|
|
|
1548
1578
|
"C:\\Program Files\\Git\\bin\\bash.exe"
|
|
1549
1579
|
].filter((c) => typeof c === "string" && c.length > 0);
|
|
1550
1580
|
for (const candidate of candidates) {
|
|
1551
|
-
if (
|
|
1581
|
+
if (existsSync6(candidate)) return cachedPosixShell = candidate;
|
|
1552
1582
|
}
|
|
1553
1583
|
const where = spawnSync("where", ["bash"], { encoding: "utf8", windowsHide: true });
|
|
1554
1584
|
if (where.status === 0 && where.stdout) {
|
|
1555
1585
|
const hit = where.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).find((line) => !/\\system32\\/i.test(line));
|
|
1556
|
-
if (hit &&
|
|
1586
|
+
if (hit && existsSync6(hit)) return cachedPosixShell = hit;
|
|
1557
1587
|
}
|
|
1558
1588
|
return cachedPosixShell = null;
|
|
1559
1589
|
}
|
|
@@ -1610,7 +1640,7 @@ function makeRunCheck(vaultRoot, codeRoot) {
|
|
|
1610
1640
|
return async (check) => {
|
|
1611
1641
|
const cwds = resolveCheckCwds(check, {
|
|
1612
1642
|
repoRoot: codeRoot,
|
|
1613
|
-
consoleRoot:
|
|
1643
|
+
consoleRoot: path3.join(codeRoot, "spex-console"),
|
|
1614
1644
|
vaultRoot
|
|
1615
1645
|
});
|
|
1616
1646
|
let lastFailure = null;
|
|
@@ -1641,8 +1671,8 @@ async function main() {
|
|
|
1641
1671
|
}
|
|
1642
1672
|
if (process3.argv[3] === "judge") {
|
|
1643
1673
|
const pkgRoot = resolveCodeRoot({ vaultRoot });
|
|
1644
|
-
const judgeScript =
|
|
1645
|
-
if (!
|
|
1674
|
+
const judgeScript = path3.join(pkgRoot, "dev-factory", "judge.mjs");
|
|
1675
|
+
if (!existsSync6(judgeScript)) {
|
|
1646
1676
|
process3.stderr.write(
|
|
1647
1677
|
`hs check judge: script not found at ${judgeScript} (source checkout only \u2014 not available in a published install).
|
|
1648
1678
|
`
|
|
@@ -1678,13 +1708,13 @@ async function main() {
|
|
|
1678
1708
|
if (!manifestPath) {
|
|
1679
1709
|
process3.stderr.write(
|
|
1680
1710
|
`hs check: no manifest for "${args.target}".
|
|
1681
|
-
Pass a manifest path, or create ${
|
|
1711
|
+
Pass a manifest path, or create ${path3.join("specs", "checks", `${args.target}.checks.json`)} under the vault root.
|
|
1682
1712
|
`
|
|
1683
1713
|
);
|
|
1684
1714
|
process3.exitCode = EXIT.NOT_FOUND;
|
|
1685
1715
|
return;
|
|
1686
1716
|
}
|
|
1687
|
-
const { manifest, error } = parseChecksManifest(
|
|
1717
|
+
const { manifest, error } = parseChecksManifest(readFileSync10(manifestPath, "utf-8"));
|
|
1688
1718
|
if (error) {
|
|
1689
1719
|
process3.stderr.write(`hs check: ${manifestPath}: ${error}
|
|
1690
1720
|
`);
|
|
@@ -1716,7 +1746,7 @@ async function main() {
|
|
|
1716
1746
|
process3.exitCode = reportExitCode(report);
|
|
1717
1747
|
}
|
|
1718
1748
|
async function reportVerdict(target, report, vaultRoot, unattended = false) {
|
|
1719
|
-
if (
|
|
1749
|
+
if (existsSync6(target) || target.endsWith(".json")) {
|
|
1720
1750
|
process3.stderr.write(
|
|
1721
1751
|
"hs check: --report needs a spec-id target (to identify the claim), not a manifest path.\n"
|
|
1722
1752
|
);
|
|
@@ -1724,7 +1754,7 @@ async function reportVerdict(target, report, vaultRoot, unattended = false) {
|
|
|
1724
1754
|
}
|
|
1725
1755
|
const consoleUrl = resolveSpexConsoleUrl(vaultRoot, (p) => {
|
|
1726
1756
|
try {
|
|
1727
|
-
return
|
|
1757
|
+
return readFileSync10(p, "utf-8");
|
|
1728
1758
|
} catch {
|
|
1729
1759
|
return null;
|
|
1730
1760
|
}
|