heyspex 0.2.2 → 0.2.4
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 +2 -1
- package/README.md +11 -0
- package/bin/hs-vault-binding.mjs +157 -0
- package/bin/hs.mjs +83 -79
- 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 +200 -177
- package/docs/driving-heyspex-from-copilot.md +174 -165
- package/docs/mcp-client-config.md +93 -25
- package/package.json +257 -250
- package/plugins/heyspex/.claude-plugin/plugin.json +13 -12
- package/plugins/heyspex/.cursor-plugin/plugin.json +16 -15
- package/plugins/heyspex/.mcp.json +3 -4
- package/plugins/heyspex/README.md +323 -312
- package/plugins/heyspex/assets/heyspex-glyph-128.png +0 -0
- package/plugins/heyspex/assets/heyspex-glyph-256.png +0 -0
- package/plugins/heyspex/assets/heyspex-glyph.svg +12 -0
- 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 +1073 -0
- package/scripts/copilot-statusline.mjs +130 -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 +152 -36
- 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/http-transport.mjs +6 -1
- package/vendor/heyspex-mcp/mcp-config.mjs +4 -2
- package/vendor/heyspex-mcp/server-identity.mjs +13 -0
- 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 +63 -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
package/dist/cli/hs-connect.mjs
CHANGED
|
@@ -154,9 +154,9 @@ function resolveBearer({ envToken, credentialsText, accountId, legacyAccountId }
|
|
|
154
154
|
if (entry?.mcp_token) return { token: entry.mcp_token, source: "credentials-file" };
|
|
155
155
|
return { token: null, source: null };
|
|
156
156
|
}
|
|
157
|
-
function readTextOrNull(read,
|
|
157
|
+
function readTextOrNull(read, path9) {
|
|
158
158
|
try {
|
|
159
|
-
const raw = read(
|
|
159
|
+
const raw = read(path9);
|
|
160
160
|
return typeof raw === "string" ? raw : null;
|
|
161
161
|
} catch {
|
|
162
162
|
return null;
|
|
@@ -260,6 +260,11 @@ function readLocalDevModeRecord({ homeDir = heyspexHome(), readFile: readFile2 =
|
|
|
260
260
|
return { record: null, parseError: `unparseable dev-mode.json: ${String(err?.message ?? err)}` };
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
|
+
function overrideCloudCheck(source, cloudKnown, staleAgainstCloud) {
|
|
264
|
+
if (source !== "local-override") return "not-applicable";
|
|
265
|
+
if (!cloudKnown) return "unverified";
|
|
266
|
+
return staleAgainstCloud ? "stale" : "in-sync";
|
|
267
|
+
}
|
|
263
268
|
function resolveDevMode({
|
|
264
269
|
env = process.env,
|
|
265
270
|
homeDir = heyspexHome(),
|
|
@@ -299,6 +304,7 @@ function resolveDevMode({
|
|
|
299
304
|
const semantics = deriveSemantics(mode, reliance);
|
|
300
305
|
const consoleUrl = source === "local-override" && local.record?.console_url ? local.record.console_url.replace(/\/+$/, "") : semantics.consoleUrl;
|
|
301
306
|
const staleAgainstCloud = source === "local-override" && cloudValue !== null && (cloudValue.mode !== mode || mode === "dev" && cloudValue.reliance !== semantics.reliance);
|
|
307
|
+
const cloudCheck = overrideCloudCheck(source, cloudKnown, staleAgainstCloud);
|
|
302
308
|
return {
|
|
303
309
|
mode,
|
|
304
310
|
reliance: semantics.reliance,
|
|
@@ -316,7 +322,8 @@ function resolveDevMode({
|
|
|
316
322
|
present: local.record !== null,
|
|
317
323
|
record: local.record,
|
|
318
324
|
parseError: local.parseError,
|
|
319
|
-
staleAgainstCloud
|
|
325
|
+
staleAgainstCloud,
|
|
326
|
+
cloudCheck
|
|
320
327
|
},
|
|
321
328
|
cloudSetting: { known: cloudKnown, value: cloudValue }
|
|
322
329
|
};
|
|
@@ -996,19 +1003,19 @@ var require_gray_matter = __commonJS({
|
|
|
996
1003
|
});
|
|
997
1004
|
|
|
998
1005
|
// spex-console/bin/hs-connect.ts
|
|
999
|
-
import { spawnSync as
|
|
1006
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
1000
1007
|
import {
|
|
1001
|
-
copyFileSync,
|
|
1002
|
-
existsSync as
|
|
1003
|
-
mkdirSync as
|
|
1008
|
+
copyFileSync as copyFileSync2,
|
|
1009
|
+
existsSync as existsSync9,
|
|
1010
|
+
mkdirSync as mkdirSync7,
|
|
1004
1011
|
readdirSync as readdirSync3,
|
|
1005
|
-
readFileSync as
|
|
1006
|
-
statSync,
|
|
1007
|
-
writeFileSync as
|
|
1012
|
+
readFileSync as readFileSync14,
|
|
1013
|
+
statSync as statSync5,
|
|
1014
|
+
writeFileSync as writeFileSync7
|
|
1008
1015
|
} from "node:fs";
|
|
1009
|
-
import
|
|
1016
|
+
import path8 from "node:path";
|
|
1010
1017
|
import process4 from "node:process";
|
|
1011
|
-
import { fileURLToPath as
|
|
1018
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
1012
1019
|
|
|
1013
1020
|
// scripts/lib/console-url-resolver.mjs
|
|
1014
1021
|
init_heyspex_home();
|
|
@@ -1116,7 +1123,9 @@ function resolveConsoleUrl({
|
|
|
1116
1123
|
}
|
|
1117
1124
|
|
|
1118
1125
|
// scripts/lib/shared-path-helpers.mjs
|
|
1126
|
+
import { realpathSync } from "node:fs";
|
|
1119
1127
|
import { isAbsolute, resolve as resolve2, sep } from "node:path";
|
|
1128
|
+
import { fileURLToPath } from "node:url";
|
|
1120
1129
|
function resolveCodeRoot({
|
|
1121
1130
|
explicit,
|
|
1122
1131
|
packageRoot: packageRoot2,
|
|
@@ -1239,10 +1248,10 @@ function classifyHttpFailureReason(res) {
|
|
|
1239
1248
|
if (res.status === 401) return "unauthorized";
|
|
1240
1249
|
return "server-error";
|
|
1241
1250
|
}
|
|
1242
|
-
async function cloudHttpRequest(http, method,
|
|
1243
|
-
const scopeHeaders = http.scope ? http.scope.headersFor(method,
|
|
1251
|
+
async function cloudHttpRequest(http, method, path9, body) {
|
|
1252
|
+
const scopeHeaders = http.scope ? http.scope.headersFor(method, path9) : {};
|
|
1244
1253
|
try {
|
|
1245
|
-
const res = await http.fetchImpl(`${http.consoleUrl}${
|
|
1254
|
+
const res = await http.fetchImpl(`${http.consoleUrl}${path9}`, {
|
|
1246
1255
|
method,
|
|
1247
1256
|
headers: {
|
|
1248
1257
|
"content-type": "application/json",
|
|
@@ -3014,12 +3023,12 @@ var SUSPENSION_ELAPSED_FACTOR = 3;
|
|
|
3014
3023
|
var SUSPENSION_MIN_OVERSHOOT_MS = 5e3;
|
|
3015
3024
|
var MAX_SUSPENSION_RETRIES = 2;
|
|
3016
3025
|
function withTimeout(promise, ms, label) {
|
|
3017
|
-
return new Promise((
|
|
3026
|
+
return new Promise((resolve6, reject) => {
|
|
3018
3027
|
const timer = setTimeout(() => reject(new NeonProbeTimeoutError(label, ms)), ms);
|
|
3019
3028
|
promise.then(
|
|
3020
3029
|
(value) => {
|
|
3021
3030
|
clearTimeout(timer);
|
|
3022
|
-
|
|
3031
|
+
resolve6(value);
|
|
3023
3032
|
},
|
|
3024
3033
|
(err) => {
|
|
3025
3034
|
clearTimeout(timer);
|
|
@@ -3038,7 +3047,7 @@ var NeonProbeTimeoutError = class _NeonProbeTimeoutError extends Error {
|
|
|
3038
3047
|
}
|
|
3039
3048
|
};
|
|
3040
3049
|
function sleep(ms) {
|
|
3041
|
-
return new Promise((
|
|
3050
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
3042
3051
|
}
|
|
3043
3052
|
function emitProbeFailure(options2, failure) {
|
|
3044
3053
|
try {
|
|
@@ -4032,7 +4041,7 @@ import { createHash } from "node:crypto";
|
|
|
4032
4041
|
import fs from "node:fs";
|
|
4033
4042
|
import path2 from "node:path";
|
|
4034
4043
|
import os2 from "node:os";
|
|
4035
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4044
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
|
|
4036
4045
|
|
|
4037
4046
|
// scripts/lib/hook-dispositions.mjs
|
|
4038
4047
|
var HOSTS = Object.freeze(["claude-code", "cursor", "copilot"]);
|
|
@@ -4380,8 +4389,16 @@ var LAUNCHER_TEMPLATE = [
|
|
|
4380
4389
|
"// 4. node_modules/heyspex up from $__ENV__, $CLAUDE_PROJECT_DIR, $CURSOR_PROJECT_DIR, cwd",
|
|
4381
4390
|
"// 5. <npm root -g>/heyspex a global install, last resort",
|
|
4382
4391
|
"// Nothing found -> one stderr line and exit 0 (fail-open, like the shim itself).",
|
|
4392
|
+
"//",
|
|
4393
|
+
"// The same resolution starts the package's other entrypoints, so no committed",
|
|
4394
|
+
"// file names node_modules/heyspex directly and a repo with no node_modules of",
|
|
4395
|
+
"// its own still works off a global install:",
|
|
4396
|
+
"// --mcp the stdio MCP server (.mcp.json, .cursor/mcp.json)",
|
|
4397
|
+
"// --statusline the Claude Code status line (statusLine.command)",
|
|
4398
|
+
"// --resolve print the package root, exit 0; exit 1 when none (hs doctor)",
|
|
4383
4399
|
"import { spawnSync } from 'node:child_process';",
|
|
4384
|
-
"import { existsSync } from 'node:fs';",
|
|
4400
|
+
"import { existsSync, readdirSync, readFileSync, realpathSync } from 'node:fs';",
|
|
4401
|
+
"import { homedir } from 'node:os';",
|
|
4385
4402
|
"import { dirname, resolve } from 'node:path';",
|
|
4386
4403
|
"import { fileURLToPath, pathToFileURL } from 'node:url';",
|
|
4387
4404
|
"",
|
|
@@ -4391,6 +4408,7 @@ var LAUNCHER_TEMPLATE = [
|
|
|
4391
4408
|
"const text = (v) => (typeof v === 'string' && v.trim() ? v.trim() : null);",
|
|
4392
4409
|
"const hasShim = (root) => Boolean(root) && existsSync(resolve(root, ...SHIM));",
|
|
4393
4410
|
"",
|
|
4411
|
+
"__YIELD__",
|
|
4394
4412
|
"function packageUpFrom(start) {",
|
|
4395
4413
|
" let dir = resolve(start);",
|
|
4396
4414
|
" for (;;) {",
|
|
@@ -4425,31 +4443,109 @@ var LAUNCHER_TEMPLATE = [
|
|
|
4425
4443
|
" if (hasShim(global)) root = global;",
|
|
4426
4444
|
"}",
|
|
4427
4445
|
"",
|
|
4446
|
+
"const ENTRYPOINTS = {",
|
|
4447
|
+
" '--mcp': 'vendor/heyspex-mcp/cli.mjs',",
|
|
4448
|
+
" '--statusline': 'scripts/claude-statusline/statusline-command.mjs',",
|
|
4449
|
+
"};",
|
|
4450
|
+
"const mode = process.argv[2];",
|
|
4451
|
+
"const entry = Object.hasOwn(ENTRYPOINTS, mode) ? ENTRYPOINTS[mode] : null;",
|
|
4452
|
+
"",
|
|
4428
4453
|
"if (!root) {",
|
|
4454
|
+
" const what = entry || mode === '--resolve' ? mode : 'hook ' + (mode ?? '?');",
|
|
4429
4455
|
" process.stderr.write(",
|
|
4430
|
-
" '[heyspex]
|
|
4431
|
-
` '(run "npm install heyspex" in this repo, or set HEYSPEX_PLATFORM_ROOT).
|
|
4432
|
-
" 'HEYSPEX_PLATFORM_ROOT, HEYSPEX_MCP_ENTRY, node_modules/heyspex up from ' + starts.join(', ') + ', and npm root -g.\\n',",
|
|
4456
|
+
" '[heyspex] ' + what + ' skipped: no heyspex package found ' +",
|
|
4457
|
+
` '(run "npm install heyspex" or "npm link heyspex" in this repo, install it globally, or set HEYSPEX_PLATFORM_ROOT). ' +`,
|
|
4458
|
+
" 'Looked for __SHIM__ under HEYSPEX_PLATFORM_ROOT, HEYSPEX_MCP_ENTRY, node_modules/heyspex up from ' + starts.join(', ') + ', and npm root -g.\\n',",
|
|
4433
4459
|
" );",
|
|
4460
|
+
" // Hooks and the status line fail open; the MCP server and --resolve fail",
|
|
4461
|
+
" // loudly, so the client and hs doctor both see it.",
|
|
4462
|
+
" process.exit(mode === '--mcp' || mode === '--resolve' ? 1 : 0);",
|
|
4463
|
+
"}",
|
|
4464
|
+
"if (mode === '--resolve') {",
|
|
4465
|
+
" process.stdout.write(root + '\\n');",
|
|
4434
4466
|
" process.exit(0);",
|
|
4435
4467
|
"}",
|
|
4436
4468
|
"",
|
|
4437
4469
|
"// argv is already [node, <this file>, <hook>, ...args] -- the shape the shim",
|
|
4438
|
-
'// reads; the
|
|
4439
|
-
"//
|
|
4440
|
-
"
|
|
4441
|
-
"
|
|
4470
|
+
'// reads; the target replaces this file so a script guarded by "am I main?"',
|
|
4471
|
+
"// runs exactly as if it had been invoked directly. Real path, so that guard",
|
|
4472
|
+
"// still matches when node_modules/heyspex is an npm link or a junction (node",
|
|
4473
|
+
"// realpaths import.meta.url but leaves argv[1] alone).",
|
|
4474
|
+
"let target = resolve(root, ...(entry ? entry.split('/') : SHIM));",
|
|
4475
|
+
"try {",
|
|
4476
|
+
" target = realpathSync(target);",
|
|
4477
|
+
"} catch {",
|
|
4478
|
+
" // keep the resolved path",
|
|
4479
|
+
"}",
|
|
4480
|
+
"if (entry) process.argv.splice(2, 1);",
|
|
4481
|
+
"process.argv[1] = target;",
|
|
4442
4482
|
"try {",
|
|
4443
|
-
" await import(pathToFileURL(
|
|
4483
|
+
" await import(pathToFileURL(target).href);",
|
|
4444
4484
|
"} catch (err) {",
|
|
4445
|
-
" process.stderr.write('[heyspex] hook ' + (process.argv[2] ?? '?') + ' skipped: ' + (err && err.message ? err.message : err) + '\\n');",
|
|
4485
|
+
" process.stderr.write('[heyspex] ' + (entry ? mode : 'hook ' + (process.argv[2] ?? '?')) + ' skipped: ' + (err && err.message ? err.message : err) + '\\n');",
|
|
4486
|
+
" // Hooks and the status line fail open; the MCP server fails loudly.",
|
|
4487
|
+
" if (mode === '--mcp') process.exit(1);",
|
|
4446
4488
|
" process.exit(0);",
|
|
4447
4489
|
"}",
|
|
4448
4490
|
""
|
|
4449
4491
|
].join("\n");
|
|
4492
|
+
var LAUNCHER_YIELD_MARKER = "// yields-to-plugin: v1";
|
|
4493
|
+
var LAUNCHER_YIELD_BLOCK = [
|
|
4494
|
+
LAUNCHER_YIELD_MARKER + " -- one source of hooks: when the heyspex plugin is enabled on this machine",
|
|
4495
|
+
"// its own launcher (plugins/heyspex/bin/run-hook.mjs, which never calls this file) already runs every",
|
|
4496
|
+
"// hook, so this committed row exits 0 silently before resolving anything and each hook fires ONCE.",
|
|
4497
|
+
"// HEYSPEX_REPO_HOOKS=1 never yield (the repo rows are the chosen source);",
|
|
4498
|
+
`// enabledPlugins["heyspex@..."] === false in ~/.claude/settings.json or this repo's .claude/`,
|
|
4499
|
+
"// settings[.local].json: plugin off here, the row runs;",
|
|
4500
|
+
"// plugin evidence (what `hs doctor` hook-double-fire reads): a heyspex@... key in",
|
|
4501
|
+
"// ~/.claude/plugins/installed_plugins.json, enabledPlugins naming heyspex with a non-false",
|
|
4502
|
+
"// value, or a heyspex directory under ~/.copilot/installed-plugins | ~/.copilot/plugins.",
|
|
4503
|
+
"function readJson(file) {",
|
|
4504
|
+
" try { return JSON.parse(readFileSync(file, 'utf8')); } catch { return undefined; }",
|
|
4505
|
+
"}",
|
|
4506
|
+
"function listDir(dir) {",
|
|
4507
|
+
" try { return readdirSync(dir); } catch { return []; }",
|
|
4508
|
+
"}",
|
|
4509
|
+
"function pluginTakesThisHook() {",
|
|
4510
|
+
" const flag = text(env.HEYSPEX_REPO_HOOKS);",
|
|
4511
|
+
" if (flag && flag !== '0' && flag.toLowerCase() !== 'false') return false;",
|
|
4512
|
+
" const home = homedir();",
|
|
4513
|
+
" const repo = resolve(here, '..', '..');",
|
|
4514
|
+
" const isHeyspex = (k) => /^heyspex(@|$)/i.test(k);",
|
|
4515
|
+
" let enabled = false;",
|
|
4516
|
+
" for (const f of [resolve(home, '.claude', 'settings.json'), resolve(repo, '.claude', 'settings.json'), resolve(repo, '.claude', 'settings.local.json')]) {",
|
|
4517
|
+
" const settings = readJson(f);",
|
|
4518
|
+
" const ep = settings && typeof settings === 'object' ? settings.enabledPlugins : null;",
|
|
4519
|
+
" if (!ep || typeof ep !== 'object') continue;",
|
|
4520
|
+
" for (const [k, v] of Object.entries(ep)) {",
|
|
4521
|
+
" if (!isHeyspex(k)) continue;",
|
|
4522
|
+
" if (v === false) return false;",
|
|
4523
|
+
" enabled = true;",
|
|
4524
|
+
" }",
|
|
4525
|
+
" }",
|
|
4526
|
+
" if (enabled) return true;",
|
|
4527
|
+
" const installed = readJson(resolve(home, '.claude', 'plugins', 'installed_plugins.json'));",
|
|
4528
|
+
" if (installed && typeof installed === 'object' && Object.keys(installed.plugins && typeof installed.plugins === 'object' ? installed.plugins : installed).some(isHeyspex)) return true;",
|
|
4529
|
+
" for (const sub of ['installed-plugins', 'plugins']) {",
|
|
4530
|
+
" const dir = resolve(home, '.copilot', sub);",
|
|
4531
|
+
" const names = listDir(dir);",
|
|
4532
|
+
" if (names.some((n) => /heyspex/i.test(n))) return true;",
|
|
4533
|
+
" if (names.some((n) => listDir(resolve(dir, n)).some((m) => /heyspex/i.test(m)))) return true;",
|
|
4534
|
+
" }",
|
|
4535
|
+
" return false;",
|
|
4536
|
+
"}",
|
|
4537
|
+
"// Only a HOOK EVENT yields: --mcp / --statusline / --resolve and an agent-run",
|
|
4538
|
+
"// `<script> --directive <key>` fetch are not hook events the plugin could run in",
|
|
4539
|
+
"// our place, so they always go on to the package below.",
|
|
4540
|
+
"const yieldMode = process.argv[2];",
|
|
4541
|
+
"const notAHookEvent = ['--mcp', '--statusline', '--resolve'].includes(yieldMode) || process.argv.includes('--directive');",
|
|
4542
|
+
"if (!notAHookEvent && pluginTakesThisHook()) process.exit(0);",
|
|
4543
|
+
"",
|
|
4544
|
+
""
|
|
4545
|
+
].join("\n");
|
|
4450
4546
|
function renderCustomerLauncher(surface = "claude") {
|
|
4451
4547
|
const l = CUSTOMER_LAUNCHERS[surface];
|
|
4452
|
-
return LAUNCHER_TEMPLATE.replace(
|
|
4548
|
+
return LAUNCHER_TEMPLATE.replace("__YIELD__\n", surface === "claude" ? LAUNCHER_YIELD_BLOCK : "").replace(
|
|
4453
4549
|
/__(REGISTRY|ENV|LAUNCHER|SHIM)__/g,
|
|
4454
4550
|
(_m, token) => token === "REGISTRY" ? l.registry : token === "ENV" ? l.projectDirEnv : token === "LAUNCHER" ? l.rel.join("/") : l.shim
|
|
4455
4551
|
);
|
|
@@ -4675,25 +4771,33 @@ var MARKER_RE = /\n<!-- heyspex-kit: managed by hs install \(sha256:([0-9a-f]{16
|
|
|
4675
4771
|
function shortHash(text2) {
|
|
4676
4772
|
return createHash("sha256").update(text2, "utf8").digest("hex").slice(0, 16);
|
|
4677
4773
|
}
|
|
4774
|
+
function normalizeEol(text2) {
|
|
4775
|
+
return text2 === null || text2 === void 0 ? text2 : String(text2).replace(/\r\n/g, "\n");
|
|
4776
|
+
}
|
|
4678
4777
|
function renderKitCommand(content, platformRoot) {
|
|
4679
|
-
const body = `${rewritePlatformPaths(content, platformRoot).replace(/\s+$/, "")}
|
|
4778
|
+
const body = `${rewritePlatformPaths(normalizeEol(content), platformRoot).replace(/\s+$/, "")}
|
|
4680
4779
|
`;
|
|
4681
4780
|
return `${body}
|
|
4682
4781
|
<!-- heyspex-kit: managed by hs install (sha256:${shortHash(body)}). Edit freely: once edited, hs install leaves this file alone. -->
|
|
4683
4782
|
`;
|
|
4684
4783
|
}
|
|
4685
4784
|
function kitFileState(content) {
|
|
4686
|
-
const
|
|
4785
|
+
const text2 = normalizeEol(String(content));
|
|
4786
|
+
const m = text2.match(MARKER_RE);
|
|
4687
4787
|
if (!m) return "unmanaged";
|
|
4688
|
-
const body =
|
|
4689
|
-
|
|
4690
|
-
|
|
4788
|
+
const body = `${text2.slice(0, m.index).replace(/\n$/, "")}
|
|
4789
|
+
`;
|
|
4790
|
+
if (shortHash(body) === m[1]) return "managed";
|
|
4791
|
+
if (shortHash(`${body.slice(0, -1).replace(/\n/g, "\r\n")}
|
|
4792
|
+
`) === m[1]) return "managed";
|
|
4793
|
+
return "customized";
|
|
4691
4794
|
}
|
|
4692
4795
|
function planKitFileWrite({ existing, rendered, raw, force }) {
|
|
4693
4796
|
if (existing === null || existing === void 0) return { write: true, reason: "missing" };
|
|
4694
|
-
|
|
4695
|
-
if (
|
|
4696
|
-
if (
|
|
4797
|
+
const have = normalizeEol(existing);
|
|
4798
|
+
if (have === normalizeEol(rendered)) return { write: false, reason: "unchanged" };
|
|
4799
|
+
if (kitFileState(have) === "managed") return { write: true, reason: "update" };
|
|
4800
|
+
if (have === normalizeEol(raw)) return { write: true, reason: "legacy-copy" };
|
|
4697
4801
|
return force ? { write: true, reason: "forced" } : { write: false, reason: "customized" };
|
|
4698
4802
|
}
|
|
4699
4803
|
function listKitCommandFiles(platformRoot, deps, opts = {}) {
|
|
@@ -4737,14 +4841,14 @@ var fsDeps = {
|
|
|
4737
4841
|
function invokedDirectly(importMetaUrl, selfBasename, argv1 = process.argv[1]) {
|
|
4738
4842
|
try {
|
|
4739
4843
|
if (!argv1) return false;
|
|
4740
|
-
const self =
|
|
4844
|
+
const self = fileURLToPath2(importMetaUrl);
|
|
4741
4845
|
if (path2.basename(self) !== selfBasename) return false;
|
|
4742
4846
|
return pathToFileURL(path2.resolve(argv1)).href === pathToFileURL(self).href;
|
|
4743
4847
|
} catch {
|
|
4744
4848
|
return false;
|
|
4745
4849
|
}
|
|
4746
4850
|
}
|
|
4747
|
-
var SELF =
|
|
4851
|
+
var SELF = fileURLToPath2(import.meta.url);
|
|
4748
4852
|
if (invokedDirectly(import.meta.url, "customer-kit.mjs")) {
|
|
4749
4853
|
const platformRoot = path2.resolve(path2.dirname(SELF), "..", "..");
|
|
4750
4854
|
const target = path2.join(platformRoot, "plugins", "heyspex", "hooks", "hooks.json");
|
|
@@ -4790,6 +4894,11 @@ import { join as join6 } from "node:path";
|
|
|
4790
4894
|
init_credentials();
|
|
4791
4895
|
var CLOUD_CONSOLE_URL2 = "https://app.heyspex.com";
|
|
4792
4896
|
var LOCAL_CONSOLE_URL2 = "http://localhost:3000";
|
|
4897
|
+
function overrideCloudCheck2(source, cloudKnown, staleAgainstCloud) {
|
|
4898
|
+
if (source !== "local-override") return "not-applicable";
|
|
4899
|
+
if (!cloudKnown) return "unverified";
|
|
4900
|
+
return staleAgainstCloud ? "stale" : "in-sync";
|
|
4901
|
+
}
|
|
4793
4902
|
function normalizeMode2(raw) {
|
|
4794
4903
|
const v = String(raw ?? "").trim().toLowerCase();
|
|
4795
4904
|
if (v === "prod" || v === "production") return { mode: "prod", reliance: "cloud" };
|
|
@@ -4897,6 +5006,7 @@ function resolveDevMode2({
|
|
|
4897
5006
|
const semantics = deriveSemantics2(mode, reliance);
|
|
4898
5007
|
const consoleUrl = source === "local-override" && local.record?.console_url ? local.record.console_url.replace(/\/+$/, "") : semantics.consoleUrl;
|
|
4899
5008
|
const staleAgainstCloud = source === "local-override" && cloudValue !== null && (cloudValue.mode !== mode || mode === "dev" && cloudValue.reliance !== semantics.reliance);
|
|
5009
|
+
const cloudCheck = overrideCloudCheck2(source, cloudKnown, staleAgainstCloud);
|
|
4900
5010
|
return {
|
|
4901
5011
|
mode,
|
|
4902
5012
|
reliance: semantics.reliance,
|
|
@@ -4914,7 +5024,8 @@ function resolveDevMode2({
|
|
|
4914
5024
|
present: local.record !== null,
|
|
4915
5025
|
record: local.record,
|
|
4916
5026
|
parseError: local.parseError,
|
|
4917
|
-
staleAgainstCloud
|
|
5027
|
+
staleAgainstCloud,
|
|
5028
|
+
cloudCheck
|
|
4918
5029
|
},
|
|
4919
5030
|
cloudSetting: { known: cloudKnown, value: cloudValue }
|
|
4920
5031
|
};
|
|
@@ -4950,16 +5061,16 @@ init_credentials();
|
|
|
4950
5061
|
import { randomUUID } from "node:crypto";
|
|
4951
5062
|
|
|
4952
5063
|
// spex-console/src/lib/cli/control-shared.ts
|
|
4953
|
-
import
|
|
5064
|
+
import path4 from "node:path";
|
|
4954
5065
|
|
|
4955
5066
|
// scripts/lib/hs-command.mjs
|
|
4956
5067
|
import { existsSync as existsSync2 } from "node:fs";
|
|
4957
5068
|
import { delimiter, dirname as dirname3, join as join7 } from "node:path";
|
|
4958
|
-
import { fileURLToPath as
|
|
5069
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
4959
5070
|
var HS_BIN_NAME = "hs";
|
|
4960
5071
|
var HS_DISPATCHER_PATH = (() => {
|
|
4961
5072
|
try {
|
|
4962
|
-
const here = dirname3(
|
|
5073
|
+
const here = dirname3(fileURLToPath3(import.meta.url));
|
|
4963
5074
|
return join7(dirname3(dirname3(here)), "bin", "hs.mjs");
|
|
4964
5075
|
} catch {
|
|
4965
5076
|
return null;
|
|
@@ -4973,8 +5084,8 @@ var HS_DISPATCHER_PREFIX = HS_DISPATCHER_PATH ? `node ${shellQuote(HS_DISPATCHER
|
|
|
4973
5084
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
4974
5085
|
init_heyspex_home();
|
|
4975
5086
|
init_credentials();
|
|
4976
|
-
import { readFileSync as
|
|
4977
|
-
import { homedir as
|
|
5087
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
5088
|
+
import { homedir as homedir9 } from "node:os";
|
|
4978
5089
|
import { join as join10 } from "node:path";
|
|
4979
5090
|
|
|
4980
5091
|
// vendor/heyspex-mcp/vault-less-endpoints.mjs
|
|
@@ -4987,14 +5098,14 @@ var VAULT_LESS_ENDPOINTS = Object.freeze([
|
|
|
4987
5098
|
"GET /api/workspaces",
|
|
4988
5099
|
"* /api/admin/dev-mode"
|
|
4989
5100
|
]);
|
|
4990
|
-
function pathnameOf(
|
|
4991
|
-
const raw = String(
|
|
5101
|
+
function pathnameOf(path9) {
|
|
5102
|
+
const raw = String(path9 ?? "").split("?")[0].split("#")[0];
|
|
4992
5103
|
const noTrailing = raw.length > 1 ? raw.replace(/\/+$/, "") : raw;
|
|
4993
5104
|
return noTrailing || "/";
|
|
4994
5105
|
}
|
|
4995
|
-
function isVaultLessEndpoint(method,
|
|
5106
|
+
function isVaultLessEndpoint(method, path9) {
|
|
4996
5107
|
const m = String(method || "GET").toUpperCase();
|
|
4997
|
-
const pathname = pathnameOf(
|
|
5108
|
+
const pathname = pathnameOf(path9);
|
|
4998
5109
|
return VAULT_LESS_ENDPOINTS.some((row2) => {
|
|
4999
5110
|
const [rowMethod, rowPath] = row2.split(" ");
|
|
5000
5111
|
return rowPath === pathname && (rowMethod === "*" || rowMethod === m);
|
|
@@ -5015,9 +5126,30 @@ import { basename, join as join8, isAbsolute as isAbsolute2 } from "node:path";
|
|
|
5015
5126
|
|
|
5016
5127
|
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
5017
5128
|
init_heyspex_home();
|
|
5018
|
-
import { existsSync as
|
|
5019
|
-
import { homedir as
|
|
5020
|
-
|
|
5129
|
+
import { existsSync as existsSync5, readFileSync as readFileSync10, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
5130
|
+
import { homedir as homedir8, tmpdir } from "node:os";
|
|
5131
|
+
|
|
5132
|
+
// vendor/heyspex-mcp/usable-dir-env.mjs
|
|
5133
|
+
import { statSync } from "node:fs";
|
|
5134
|
+
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
5135
|
+
|
|
5136
|
+
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
5137
|
+
import { basename as basename2, dirname as dirname4, join as join9, resolve as resolve4 } from "node:path";
|
|
5138
|
+
|
|
5139
|
+
// vendor/heyspex-mcp/vault-binding.mjs
|
|
5140
|
+
import {
|
|
5141
|
+
copyFileSync,
|
|
5142
|
+
existsSync as existsSync4,
|
|
5143
|
+
mkdirSync as mkdirSync6,
|
|
5144
|
+
readFileSync as readFileSync9,
|
|
5145
|
+
realpathSync as realpathSync2,
|
|
5146
|
+
renameSync as renameSync4,
|
|
5147
|
+
statSync as statSync2,
|
|
5148
|
+
unlinkSync,
|
|
5149
|
+
writeFileSync as writeFileSync6
|
|
5150
|
+
} from "node:fs";
|
|
5151
|
+
import { homedir as homedir7 } from "node:os";
|
|
5152
|
+
import path3 from "node:path";
|
|
5021
5153
|
|
|
5022
5154
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
5023
5155
|
var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMATCH", "VAULT_NOT_REGISTERED"]);
|
|
@@ -5119,11 +5251,11 @@ function readPairedBearer(opts = {}) {
|
|
|
5119
5251
|
function readPairedToken(opts = {}) {
|
|
5120
5252
|
return readPairedBearer(opts).token ?? void 0;
|
|
5121
5253
|
}
|
|
5122
|
-
function scopeHeadersFor(scope, method,
|
|
5254
|
+
function scopeHeadersFor(scope, method, path9) {
|
|
5123
5255
|
if (scope === "none") {
|
|
5124
|
-
if (!isVaultLessEndpoint(method,
|
|
5256
|
+
if (!isVaultLessEndpoint(method, path9)) {
|
|
5125
5257
|
throw new Error(
|
|
5126
|
-
`controlRequest: scope "none" is only allowed for the vault-less endpoints (${VAULT_LESS_ENDPOINTS.join(", ")}); ${method.toUpperCase()} ${
|
|
5258
|
+
`controlRequest: scope "none" is only allowed for the vault-less endpoints (${VAULT_LESS_ENDPOINTS.join(", ")}); ${method.toUpperCase()} ${path9} is vault-scoped and must name { accountId, vaultId }.`
|
|
5127
5259
|
);
|
|
5128
5260
|
}
|
|
5129
5261
|
return {};
|
|
@@ -5134,7 +5266,7 @@ function cloudRequestScope(scope) {
|
|
|
5134
5266
|
const named = { accountId: scope.accountId, vaultId: scope.vaultId };
|
|
5135
5267
|
return {
|
|
5136
5268
|
...named,
|
|
5137
|
-
headersFor: (method,
|
|
5269
|
+
headersFor: (method, path9) => isVaultLessEndpoint(method, path9) ? {} : scopeHeadersFor(named, method, path9)
|
|
5138
5270
|
};
|
|
5139
5271
|
}
|
|
5140
5272
|
function withCloudScope(deps, accountId, vaultId) {
|
|
@@ -5381,12 +5513,15 @@ var HELP = [
|
|
|
5381
5513
|
"(spex-console/src/lib/cli/template-manifest.ts) \u2014 universal docs",
|
|
5382
5514
|
"copied verbatim, template-shape docs written as author-prompt skeletons \u2014",
|
|
5383
5515
|
"plus a generated CLAUDE.md, the kept-principles index, and the template_version",
|
|
5384
|
-
"pin; with --git, one initial `git init` + commit.
|
|
5385
|
-
"holds heyspex.yaml
|
|
5386
|
-
"
|
|
5387
|
-
"
|
|
5388
|
-
"
|
|
5389
|
-
"
|
|
5516
|
+
"pin; with --git, one initial `git init` + commit. On an EXISTING vault (<dir>",
|
|
5517
|
+
"holds heyspex.yaml with a vault_id) it is a REFRESH \u2014 the repair `hs doctor`'s",
|
|
5518
|
+
"vault-template row names: only missing shipped files are added, template_version",
|
|
5519
|
+
"is written/updated in heyspex.yaml (every other byte and the vault_id kept),",
|
|
5520
|
+
"nothing existing is ever overwritten (an existing CLAUDE.md gets a",
|
|
5521
|
+
"CLAUDE.md.template beside it), the result lists each manifest row as created or",
|
|
5522
|
+
"kept, and a second run writes nothing. <dir> may be any path (a satellite repo",
|
|
5523
|
+
"names its vault, e.g. `hs init --customer-vault ../my-specs`). Refuses only a",
|
|
5524
|
+
"non-empty <dir> that has no heyspex.yaml. See init.customer-vault.ts.",
|
|
5390
5525
|
"",
|
|
5391
5526
|
"Flags:",
|
|
5392
5527
|
" --console-url <url> console_url value (default: the mode-aware console --",
|
|
@@ -5650,9 +5785,9 @@ function detectMarkerAttachment(repoRoot, deps) {
|
|
|
5650
5785
|
function readPinnedVaultRoot(repoRoot, deps) {
|
|
5651
5786
|
const pins = [];
|
|
5652
5787
|
for (const rel of SATELLITE_MANIFEST_RELS) {
|
|
5653
|
-
const
|
|
5654
|
-
if (!deps.fileExists(
|
|
5655
|
-
const raw = deps.readFile(
|
|
5788
|
+
const path9 = deps.joinPath(repoRoot, ...rel);
|
|
5789
|
+
if (!deps.fileExists(path9)) continue;
|
|
5790
|
+
const raw = deps.readFile(path9);
|
|
5656
5791
|
if (!raw) continue;
|
|
5657
5792
|
let value;
|
|
5658
5793
|
try {
|
|
@@ -5736,7 +5871,7 @@ function checkHarnessCommandDrift(repoRoot, deps) {
|
|
|
5736
5871
|
const installedContent = deps.fileExists(installedPath) ? deps.readFile(installedPath) : null;
|
|
5737
5872
|
if (installedContent === null) {
|
|
5738
5873
|
out.missingFiles.push(`${label}/${f.file}`);
|
|
5739
|
-
} else if (installedContent !== f.content) {
|
|
5874
|
+
} else if (normalizeEol(installedContent) !== normalizeEol(f.content)) {
|
|
5740
5875
|
out.staleFiles.push(`${label}/${f.file}`);
|
|
5741
5876
|
}
|
|
5742
5877
|
}
|
|
@@ -5756,8 +5891,8 @@ function row(id, label, present, detail) {
|
|
|
5756
5891
|
...detail ? { detail } : {}
|
|
5757
5892
|
};
|
|
5758
5893
|
}
|
|
5759
|
-
function readIfExists(deps,
|
|
5760
|
-
return deps.fileExists(
|
|
5894
|
+
function readIfExists(deps, path9) {
|
|
5895
|
+
return deps.fileExists(path9) ? deps.readFile(path9) : null;
|
|
5761
5896
|
}
|
|
5762
5897
|
var PRE_COMMIT_HOOK_MARKER = "run-pre-commit-checks.mjs";
|
|
5763
5898
|
function hasHeyspexMcpEntry(raw) {
|
|
@@ -6067,12 +6202,12 @@ function runConnectChecks(repoRoot, deps, opts = {}) {
|
|
|
6067
6202
|
};
|
|
6068
6203
|
}
|
|
6069
6204
|
var CLOUD_READ_TIMEOUT_MS = 8e3;
|
|
6070
|
-
async function cloudGet(http, token,
|
|
6205
|
+
async function cloudGet(http, token, path9) {
|
|
6071
6206
|
const controller = new AbortController();
|
|
6072
6207
|
const timer = setTimeout(() => controller.abort(), CLOUD_READ_TIMEOUT_MS);
|
|
6073
6208
|
timer.unref?.();
|
|
6074
6209
|
try {
|
|
6075
|
-
const res = await http.fetch(`${http.consoleUrl.replace(/\/+$/, "")}${
|
|
6210
|
+
const res = await http.fetch(`${http.consoleUrl.replace(/\/+$/, "")}${path9}`, {
|
|
6076
6211
|
method: "GET",
|
|
6077
6212
|
headers: token ? { authorization: `Bearer ${token}` } : {},
|
|
6078
6213
|
signal: controller.signal
|
|
@@ -6090,7 +6225,7 @@ async function cloudGet(http, token, path7) {
|
|
|
6090
6225
|
clearTimeout(timer);
|
|
6091
6226
|
}
|
|
6092
6227
|
}
|
|
6093
|
-
function readFailure(read,
|
|
6228
|
+
function readFailure(read, path9, http) {
|
|
6094
6229
|
if (read === null) {
|
|
6095
6230
|
return {
|
|
6096
6231
|
cause: "no sign-in token on this machine, so the console was not asked",
|
|
@@ -6106,9 +6241,9 @@ function readFailure(read, path7, http) {
|
|
|
6106
6241
|
};
|
|
6107
6242
|
}
|
|
6108
6243
|
if (read.status === 401) {
|
|
6109
|
-
return { cause: `GET ${
|
|
6244
|
+
return { cause: `GET ${path9} answered HTTP 401 (the sign-in was refused)`, repair: "hs login" };
|
|
6110
6245
|
}
|
|
6111
|
-
return { cause: `GET ${
|
|
6246
|
+
return { cause: `GET ${path9} answered HTTP ${read.status}`, repair: retry };
|
|
6112
6247
|
}
|
|
6113
6248
|
var str2 = (v) => typeof v === "string" && v ? v : null;
|
|
6114
6249
|
function cloudRow(id, fields) {
|
|
@@ -6296,7 +6431,13 @@ async function defaultCheckMcpBuild(deps, opts) {
|
|
|
6296
6431
|
}
|
|
6297
6432
|
}
|
|
6298
6433
|
var shortFp = (fp) => fp ? fp.slice(0, 12) : null;
|
|
6299
|
-
function hookScriptPath(command, repoRoot) {
|
|
6434
|
+
function hookScriptPath(command, repoRoot, joinPath) {
|
|
6435
|
+
const bootstrap = /^\s*node\s+-e\s+"[^"]*\/\/([^"\s]+)"/.exec(command);
|
|
6436
|
+
if (bootstrap) {
|
|
6437
|
+
const rel = bootstrap[1].replace(/^\/+/, "");
|
|
6438
|
+
if (rel === "bin/run-hook.mjs") return null;
|
|
6439
|
+
return joinPath(repoRoot, ...rel.split("/"));
|
|
6440
|
+
}
|
|
6300
6441
|
const m = /^\s*node\s+(?:"([^"]+)"|(\S+))/.exec(command);
|
|
6301
6442
|
const raw = m?.[1] ?? m?.[2];
|
|
6302
6443
|
if (!raw) return null;
|
|
@@ -6330,7 +6471,7 @@ function hooksRow(repoRoot, deps) {
|
|
|
6330
6471
|
const list = Array.isArray(group?.hooks) ? group.hooks : [];
|
|
6331
6472
|
for (const h of list) {
|
|
6332
6473
|
if (typeof h?.command !== "string" || ourHookTail(h.command) === null) continue;
|
|
6333
|
-
const script = hookScriptPath(h.command, repoRoot);
|
|
6474
|
+
const script = hookScriptPath(h.command, repoRoot, deps.joinPath);
|
|
6334
6475
|
if (script) scripts.add(script);
|
|
6335
6476
|
}
|
|
6336
6477
|
}
|
|
@@ -6370,7 +6511,7 @@ async function mcpBuildRow(vaultSubject, deps) {
|
|
|
6370
6511
|
);
|
|
6371
6512
|
}
|
|
6372
6513
|
async function readCloudView(http, tokens) {
|
|
6373
|
-
const get = (token,
|
|
6514
|
+
const get = (token, path9) => http && token ? cloudGet(http, token, path9) : Promise.resolve(null);
|
|
6374
6515
|
const [session, vaults2, workspaces2, devMode] = await Promise.all([
|
|
6375
6516
|
get(tokens.current, "/api/mcp/session"),
|
|
6376
6517
|
get(tokens.repo, "/api/vaults?include_archived=true"),
|
|
@@ -6381,9 +6522,9 @@ async function readCloudView(http, tokens) {
|
|
|
6381
6522
|
cause: "no console URL configured for this machine",
|
|
6382
6523
|
repair: "hs login"
|
|
6383
6524
|
};
|
|
6384
|
-
const fail = (read,
|
|
6385
|
-
const shapeFailure = (
|
|
6386
|
-
cause: `GET ${
|
|
6525
|
+
const fail = (read, path9) => http ? readFailure(read, path9, http) : noConsole;
|
|
6526
|
+
const shapeFailure = (path9, what) => ({
|
|
6527
|
+
cause: `GET ${path9} answered without ${what}`,
|
|
6387
6528
|
repair: `retry \`hs connect --check\` once ${http?.consoleUrl ?? "the console"} answers`
|
|
6388
6529
|
});
|
|
6389
6530
|
const sessionBody = session?.ok ? session.json : null;
|
|
@@ -6691,7 +6832,7 @@ function writeProjectContract(ctx, options2 = {}) {
|
|
|
6691
6832
|
}
|
|
6692
6833
|
|
|
6693
6834
|
// spex-console/src/lib/cli/init.customer-vault.ts
|
|
6694
|
-
import { basename as
|
|
6835
|
+
import { basename as basename3 } from "node:path";
|
|
6695
6836
|
|
|
6696
6837
|
// spex-console/src/lib/cli/template-manifest.sources.mjs
|
|
6697
6838
|
var UNIVERSAL_TEMPLATE_ROWS = [
|
|
@@ -7176,41 +7317,42 @@ var SCAFFOLD_FOLDERS = [
|
|
|
7176
7317
|
"checks",
|
|
7177
7318
|
"events"
|
|
7178
7319
|
];
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
if (deps.isDirectory) return deps.isDirectory(path7);
|
|
7182
|
-
try {
|
|
7183
|
-
const kids = deps.readdir(path7);
|
|
7184
|
-
return kids.length > 0 || !name.includes(".");
|
|
7185
|
-
} catch {
|
|
7186
|
-
return false;
|
|
7187
|
-
}
|
|
7320
|
+
function defaultVaultName(targetDir) {
|
|
7321
|
+
return basename3(targetDir) || targetDir;
|
|
7188
7322
|
}
|
|
7189
|
-
function
|
|
7190
|
-
const
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
if (isDir(deps, childAbs, name)) walk(childAbs, childRel);
|
|
7196
|
-
else if (!PLACEHOLDER_FILES.has(name) && name.endsWith(".md") && !manifestDests.has(childRel))
|
|
7197
|
-
out.push(childRel);
|
|
7198
|
-
}
|
|
7199
|
-
};
|
|
7200
|
-
const specsRoot = deps.joinPath(targetDir, "specs");
|
|
7201
|
-
if (deps.exists(specsRoot)) walk(specsRoot, "specs");
|
|
7202
|
-
return out;
|
|
7323
|
+
function readTemplateVersionPin(yamlText) {
|
|
7324
|
+
const m = yamlText.match(/^template_version:[ \t]*(.*?)[ \t]*$/m);
|
|
7325
|
+
if (!m) return null;
|
|
7326
|
+
const raw = m[1].trim();
|
|
7327
|
+
const unquoted = raw.replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
|
|
7328
|
+
return unquoted.length > 0 ? unquoted : null;
|
|
7203
7329
|
}
|
|
7204
|
-
function
|
|
7205
|
-
|
|
7330
|
+
function stampTemplateVersion(content, version) {
|
|
7331
|
+
if (readTemplateVersionPin(content) === version) return content;
|
|
7332
|
+
const eol = content.includes("\r\n") ? "\r\n" : "\n";
|
|
7333
|
+
const line = `template_version: ${version}`;
|
|
7334
|
+
if (/^template_version:[^\r\n]*$/m.test(content)) {
|
|
7335
|
+
return content.replace(/^template_version:[^\r\n]*$/m, line);
|
|
7336
|
+
}
|
|
7337
|
+
const body = content.replace(/(?:\r?\n)+$/, "");
|
|
7338
|
+
return body.length === 0 ? `${line}${eol}` : `${body}${eol}${line}${eol}`;
|
|
7339
|
+
}
|
|
7340
|
+
function parentDirOf(deps, targetDir, dest) {
|
|
7341
|
+
const segments = dest.split("/");
|
|
7342
|
+
if (segments.length < 2) return null;
|
|
7343
|
+
return deps.joinPath(targetDir, ...segments.slice(0, -1));
|
|
7206
7344
|
}
|
|
7207
7345
|
function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
7208
7346
|
const { targetDir } = args;
|
|
7209
7347
|
const written = [];
|
|
7210
7348
|
const filter = options2.manifestFilter ?? (() => true);
|
|
7211
7349
|
const rows = TEMPLATE_MANIFEST.filter(filter);
|
|
7350
|
+
const heyspexYamlPath = deps.joinPath(targetDir, "heyspex.yaml");
|
|
7351
|
+
const markerPresent = deps.exists(targetDir) && deps.exists(heyspexYamlPath);
|
|
7352
|
+
const existingYaml = markerPresent ? deps.readFile?.(heyspexYamlPath) ?? null : null;
|
|
7353
|
+
const existingVaultId = existingYaml ? parseVaultId(existingYaml) : null;
|
|
7354
|
+
const mode = markerPresent && existingVaultId ? "refresh" : "scaffold";
|
|
7212
7355
|
if (deps.exists(targetDir)) {
|
|
7213
|
-
const markerPresent = deps.exists(deps.joinPath(targetDir, "heyspex.yaml"));
|
|
7214
7356
|
if (!markerPresent && deps.readdir(targetDir).length > 0) {
|
|
7215
7357
|
return {
|
|
7216
7358
|
code: EXIT.INVALID_ARG,
|
|
@@ -7220,43 +7362,43 @@ function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
|
7220
7362
|
written: []
|
|
7221
7363
|
};
|
|
7222
7364
|
}
|
|
7223
|
-
if (markerPresent) {
|
|
7224
|
-
const manifestDests = new Set(TEMPLATE_MANIFEST.map((r) => r.dest));
|
|
7225
|
-
const managed = findManagedSpecs(deps, targetDir, manifestDests);
|
|
7226
|
-
if (managed.length > 0) {
|
|
7227
|
-
return {
|
|
7228
|
-
code: EXIT.INVALID_ARG,
|
|
7229
|
-
message: `${targetDir}/specs already holds managed spec(s) (${managed.slice(0, 3).join(", ")}${managed.length > 3 ? ", ..." : ""}) \u2014 customer-vault init refuses to write over an existing vault.`,
|
|
7230
|
-
payload: { ok: false, error: "specs_not_empty", path: targetDir, specs: managed },
|
|
7231
|
-
isError: true,
|
|
7232
|
-
written: []
|
|
7233
|
-
};
|
|
7234
|
-
}
|
|
7235
|
-
}
|
|
7236
7365
|
} else {
|
|
7237
7366
|
deps.mkdirRecursive(targetDir);
|
|
7238
7367
|
}
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7368
|
+
if (mode === "scaffold") {
|
|
7369
|
+
const specsRoot = deps.joinPath(targetDir, "specs");
|
|
7370
|
+
deps.mkdirRecursive(specsRoot);
|
|
7371
|
+
for (const folder of SCAFFOLD_FOLDERS) {
|
|
7372
|
+
deps.mkdirRecursive(deps.joinPath(specsRoot, folder));
|
|
7373
|
+
}
|
|
7243
7374
|
}
|
|
7244
|
-
const heyspexYamlPath = deps.joinPath(targetDir, "heyspex.yaml");
|
|
7245
7375
|
let vaultId;
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
vaultId =
|
|
7376
|
+
let pin;
|
|
7377
|
+
if (markerPresent) {
|
|
7378
|
+
vaultId = existingVaultId ?? "";
|
|
7379
|
+
const stamped = existingYaml === null ? null : stampTemplateVersion(existingYaml, TEMPLATE_VERSION);
|
|
7380
|
+
if (stamped !== null && stamped !== existingYaml) {
|
|
7381
|
+
deps.writeFile(heyspexYamlPath, stamped);
|
|
7382
|
+
written.push(heyspexYamlPath);
|
|
7383
|
+
pin = "written";
|
|
7384
|
+
} else {
|
|
7385
|
+
pin = "kept";
|
|
7386
|
+
}
|
|
7249
7387
|
} else {
|
|
7250
7388
|
vaultId = mintVaultId();
|
|
7251
7389
|
deps.writeFile(
|
|
7252
7390
|
heyspexYamlPath,
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7391
|
+
stampTemplateVersion(
|
|
7392
|
+
renderHeyspexYaml({
|
|
7393
|
+
consoleUrl: options2.consoleUrl ?? DEFAULT_CONSOLE_URL2,
|
|
7394
|
+
vaultRoot: "specs/",
|
|
7395
|
+
vaultId
|
|
7396
|
+
}),
|
|
7397
|
+
TEMPLATE_VERSION
|
|
7398
|
+
)
|
|
7258
7399
|
);
|
|
7259
7400
|
written.push(heyspexYamlPath);
|
|
7401
|
+
pin = "written";
|
|
7260
7402
|
}
|
|
7261
7403
|
const readConfigSeed = deps.readConfigSeed;
|
|
7262
7404
|
const configSeed = seedConfigYaml(
|
|
@@ -7272,6 +7414,10 @@ function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
|
7272
7414
|
rowResults.push({ dest: row2.dest, action: "kept" });
|
|
7273
7415
|
continue;
|
|
7274
7416
|
}
|
|
7417
|
+
if (mode === "refresh") {
|
|
7418
|
+
const parent = parentDirOf(deps, targetDir, row2.dest);
|
|
7419
|
+
if (parent && !deps.exists(parent)) deps.mkdirRecursive(parent);
|
|
7420
|
+
}
|
|
7275
7421
|
if (row2.classification === "universal-template") {
|
|
7276
7422
|
const srcAbs = deps.joinPath(deps.platformRoot, ...row2.source.split("/"));
|
|
7277
7423
|
deps.copyFile(srcAbs, destAbs);
|
|
@@ -7291,24 +7437,41 @@ function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
|
7291
7437
|
targetDir,
|
|
7292
7438
|
vaultName: options2.vaultName ?? defaultVaultName(targetDir),
|
|
7293
7439
|
templateVersion: TEMPLATE_VERSION,
|
|
7440
|
+
mode,
|
|
7294
7441
|
manifestRows: rows,
|
|
7295
7442
|
rows: rowResults,
|
|
7296
7443
|
deps,
|
|
7297
|
-
recordWrite: (
|
|
7298
|
-
written.push(
|
|
7444
|
+
recordWrite: (path9) => {
|
|
7445
|
+
written.push(path9);
|
|
7299
7446
|
}
|
|
7300
7447
|
};
|
|
7301
7448
|
for (const hook of options2.afterScaffold) hook(ctx);
|
|
7302
7449
|
}
|
|
7303
7450
|
const createdCount = rowResults.filter((r) => r.action === "created").length;
|
|
7304
7451
|
const keptCount = rowResults.length - createdCount;
|
|
7452
|
+
const added = rowResults.filter((r) => r.action === "created").map((r) => r.dest);
|
|
7453
|
+
let message2;
|
|
7454
|
+
if (mode === "refresh") {
|
|
7455
|
+
const parts = [];
|
|
7456
|
+
if (added.length > 0)
|
|
7457
|
+
parts.push(`added ${added.length} missing template file(s): ${added.join(", ")}`);
|
|
7458
|
+
if (pin === "written")
|
|
7459
|
+
parts.push(`pinned template_version: ${TEMPLATE_VERSION} in heyspex.yaml`);
|
|
7460
|
+
const hookWrites = written.length - added.length - (pin === "written" ? 1 : 0);
|
|
7461
|
+
if (hookWrites > 0) parts.push(`${hookWrites} other file(s) written`);
|
|
7462
|
+
message2 = parts.length > 0 ? `Refreshed customer vault at ${targetDir}: ${parts.join("; ")} (${keptCount} existing file(s) kept untouched).` : `Customer vault at ${targetDir} is already current (template v${TEMPLATE_VERSION}, ${keptCount} file(s) kept) \u2014 nothing written.`;
|
|
7463
|
+
} else {
|
|
7464
|
+
message2 = `Initialized customer vault at ${targetDir} (${written.length} files written, ${createdCount} manifest rows created, ${keptCount} kept, template v${TEMPLATE_VERSION}).`;
|
|
7465
|
+
}
|
|
7305
7466
|
return {
|
|
7306
7467
|
code: EXIT.OK,
|
|
7307
|
-
message:
|
|
7468
|
+
message: message2,
|
|
7308
7469
|
payload: {
|
|
7309
7470
|
ok: true,
|
|
7471
|
+
mode,
|
|
7310
7472
|
targetDir,
|
|
7311
7473
|
templateVersion: TEMPLATE_VERSION,
|
|
7474
|
+
templatePin: pin,
|
|
7312
7475
|
vaultId,
|
|
7313
7476
|
written,
|
|
7314
7477
|
rows: rowResults,
|
|
@@ -7350,14 +7513,14 @@ function templatePinHook() {
|
|
|
7350
7513
|
}
|
|
7351
7514
|
|
|
7352
7515
|
// spex-console/src/lib/cli/principle-selection.ts
|
|
7353
|
-
import { basename as
|
|
7516
|
+
import { basename as basename4 } from "node:path";
|
|
7354
7517
|
var PRINCIPLES_INDEX_DEST = "specs/principles-index.md";
|
|
7355
7518
|
function principleKey(row2) {
|
|
7356
|
-
const base =
|
|
7519
|
+
const base = basename4(row2.dest, ".md");
|
|
7357
7520
|
return base.startsWith("principle-") ? base.slice("principle-".length) : base;
|
|
7358
7521
|
}
|
|
7359
7522
|
function principleWikilink(row2) {
|
|
7360
|
-
return
|
|
7523
|
+
return basename4(row2.dest, ".md");
|
|
7361
7524
|
}
|
|
7362
7525
|
function parsePrinciplesFlag(value, rows) {
|
|
7363
7526
|
const principleRows = rows.filter((row2) => row2.group === "principle");
|
|
@@ -7423,13 +7586,13 @@ function applyCustomerTemplate(args) {
|
|
|
7423
7586
|
templateVersion: ctx.templateVersion
|
|
7424
7587
|
});
|
|
7425
7588
|
for (const file of contractFiles) {
|
|
7426
|
-
const
|
|
7427
|
-
if (force && ctx.deps.exists(
|
|
7428
|
-
if (ctx.deps.readFile?.(
|
|
7589
|
+
const path9 = ctx.deps.joinPath(ctx.targetDir, file);
|
|
7590
|
+
if (force && ctx.deps.exists(path9)) {
|
|
7591
|
+
if (ctx.deps.readFile?.(path9) === content) {
|
|
7429
7592
|
contracts.push({ file, action: "unchanged" });
|
|
7430
7593
|
} else {
|
|
7431
|
-
ctx.deps.writeFile(
|
|
7432
|
-
ctx.recordWrite(
|
|
7594
|
+
ctx.deps.writeFile(path9, content);
|
|
7595
|
+
ctx.recordWrite(path9);
|
|
7433
7596
|
contracts.push({ file, action: "overwritten" });
|
|
7434
7597
|
}
|
|
7435
7598
|
continue;
|
|
@@ -7468,12 +7631,17 @@ function applyCustomerTemplate(args) {
|
|
|
7468
7631
|
}
|
|
7469
7632
|
|
|
7470
7633
|
// spex-console/src/lib/cli/install.ts
|
|
7471
|
-
import { isAbsolute as
|
|
7634
|
+
import { isAbsolute as isAbsolute4, resolve as resolveNodePath2 } from "node:path";
|
|
7635
|
+
|
|
7636
|
+
// spex-console/src/lib/vault-resolve/index.ts
|
|
7637
|
+
import { existsSync as existsSync6, readFileSync as readFileSync12, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
|
|
7638
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
7639
|
+
import path5 from "node:path";
|
|
7472
7640
|
|
|
7473
7641
|
// scripts/install-cursor-hooks.mjs
|
|
7474
7642
|
import fs2 from "node:fs";
|
|
7475
|
-
import
|
|
7476
|
-
import { fileURLToPath as
|
|
7643
|
+
import path6 from "node:path";
|
|
7644
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
7477
7645
|
|
|
7478
7646
|
// scripts/cursor-hooks/manifest.mjs
|
|
7479
7647
|
var SHIM = "scripts/cursor-hooks/_run.mjs";
|
|
@@ -7617,9 +7785,9 @@ function timeoutFor(entry) {
|
|
|
7617
7785
|
}
|
|
7618
7786
|
|
|
7619
7787
|
// scripts/install-cursor-hooks.mjs
|
|
7620
|
-
var PLATFORM_ROOT =
|
|
7621
|
-
var REPO_ROOT = process.env.HS_SETUP_TARGET?.trim() ?
|
|
7622
|
-
var SETTINGS_PATH =
|
|
7788
|
+
var PLATFORM_ROOT = path6.resolve(path6.dirname(fileURLToPath4(import.meta.url)), "..");
|
|
7789
|
+
var REPO_ROOT = process.env.HS_SETUP_TARGET?.trim() ? path6.resolve(process.env.HS_SETUP_TARGET.trim()) : PLATFORM_ROOT;
|
|
7790
|
+
var SETTINGS_PATH = path6.join(REPO_ROOT, ".cursor", "hooks.json");
|
|
7623
7791
|
function cursorKitFor(targetRoot, platformRoot = PLATFORM_ROOT) {
|
|
7624
7792
|
const customer = !samePlatformPath(targetRoot, platformRoot);
|
|
7625
7793
|
return {
|
|
@@ -7631,7 +7799,7 @@ function cursorKitFor(targetRoot, platformRoot = PLATFORM_ROOT) {
|
|
|
7631
7799
|
}
|
|
7632
7800
|
var KIT = cursorKitFor(REPO_ROOT);
|
|
7633
7801
|
var ACTIVE_HOOKS = KIT.hooks;
|
|
7634
|
-
var LAUNCHER_PATH =
|
|
7802
|
+
var LAUNCHER_PATH = path6.join(REPO_ROOT, ...CUSTOMER_LAUNCHERS.cursor.rel);
|
|
7635
7803
|
var LEGACY_MARKER = "scripts/claude-hooks/";
|
|
7636
7804
|
function readSettings() {
|
|
7637
7805
|
try {
|
|
@@ -7650,7 +7818,7 @@ function readSettings() {
|
|
|
7650
7818
|
return { version: 1, hooks: {} };
|
|
7651
7819
|
}
|
|
7652
7820
|
function writeSettings(settings) {
|
|
7653
|
-
fs2.mkdirSync(
|
|
7821
|
+
fs2.mkdirSync(path6.dirname(SETTINGS_PATH), { recursive: true });
|
|
7654
7822
|
fs2.writeFileSync(SETTINGS_PATH, `${JSON.stringify(settings, null, 2)}
|
|
7655
7823
|
`, "utf8");
|
|
7656
7824
|
}
|
|
@@ -7685,7 +7853,7 @@ function sameEntry(raw, entry, render = KIT.commandFor) {
|
|
|
7685
7853
|
const want = desiredEntry(entry, render);
|
|
7686
7854
|
return commandOf(raw) === want.command && raw.timeout === want.timeout && (raw.matcher ?? void 0) === (want.matcher ?? void 0);
|
|
7687
7855
|
}
|
|
7688
|
-
var PLUGIN_HOOKS_PATH =
|
|
7856
|
+
var PLUGIN_HOOKS_PATH = path6.join(REPO_ROOT, "plugins", "heyspex", "hooks", "cursor-hooks.json");
|
|
7689
7857
|
function pluginHooksDocument() {
|
|
7690
7858
|
const hooks = {};
|
|
7691
7859
|
for (const entry of HOOKS) {
|
|
@@ -7715,7 +7883,7 @@ function syncPluginHooks() {
|
|
|
7715
7883
|
have = null;
|
|
7716
7884
|
}
|
|
7717
7885
|
if (have === want) return false;
|
|
7718
|
-
fs2.mkdirSync(
|
|
7886
|
+
fs2.mkdirSync(path6.dirname(PLUGIN_HOOKS_PATH), { recursive: true });
|
|
7719
7887
|
fs2.writeFileSync(PLUGIN_HOOKS_PATH, want, "utf8");
|
|
7720
7888
|
return true;
|
|
7721
7889
|
}
|
|
@@ -7788,7 +7956,7 @@ function install({ json = false } = {}) {
|
|
|
7788
7956
|
if (KIT.customer) {
|
|
7789
7957
|
const plan = launcherPlan();
|
|
7790
7958
|
if (plan.write) {
|
|
7791
|
-
fs2.mkdirSync(
|
|
7959
|
+
fs2.mkdirSync(path6.dirname(LAUNCHER_PATH), { recursive: true });
|
|
7792
7960
|
fs2.writeFileSync(LAUNCHER_PATH, plan.text, "utf8");
|
|
7793
7961
|
launcherWritten = true;
|
|
7794
7962
|
}
|
|
@@ -7815,10 +7983,10 @@ function install({ json = false } = {}) {
|
|
|
7815
7983
|
return;
|
|
7816
7984
|
}
|
|
7817
7985
|
if (pluginChanged) {
|
|
7818
|
-
console.log(`install-cursor-hooks: regenerated ${
|
|
7986
|
+
console.log(`install-cursor-hooks: regenerated ${path6.relative(REPO_ROOT, PLUGIN_HOOKS_PATH)}`);
|
|
7819
7987
|
}
|
|
7820
7988
|
if (launcherWritten) {
|
|
7821
|
-
console.log(`install-cursor-hooks: wrote ${
|
|
7989
|
+
console.log(`install-cursor-hooks: wrote ${path6.relative(REPO_ROOT, LAUNCHER_PATH)} (resolves node_modules/heyspex)`);
|
|
7822
7990
|
}
|
|
7823
7991
|
if (!settingsChanged) {
|
|
7824
7992
|
console.log(`install-cursor-hooks: already installed (${ACTIVE_HOOKS.length} hooks, no changes).`);
|
|
@@ -7829,7 +7997,7 @@ function install({ json = false } = {}) {
|
|
|
7829
7997
|
if (repaired.length) parts.push(`repaired ${repaired.length}`);
|
|
7830
7998
|
if (removed.length) parts.push(`removed ${removed.length}`);
|
|
7831
7999
|
console.log(
|
|
7832
|
-
`install-cursor-hooks: ${parts.join("; ")} \u2192 ${
|
|
8000
|
+
`install-cursor-hooks: ${parts.join("; ")} \u2192 ${path6.relative(REPO_ROOT, SETTINGS_PATH)} (${ACTIVE_HOOKS.length} hooks registered)`
|
|
7833
8001
|
);
|
|
7834
8002
|
for (const line of removed) console.log(` - ${line}`);
|
|
7835
8003
|
console.log(
|
|
@@ -8078,8 +8246,8 @@ function formatReceipt(receipt) {
|
|
|
8078
8246
|
// spex-console/src/lib/cli/receipt-readback.ts
|
|
8079
8247
|
var RECEIPT_CLOUD_READS = 3;
|
|
8080
8248
|
var RECEIPT_REREAD_DELAY_MS = 1e3;
|
|
8081
|
-
var realSleep = (ms) => new Promise((
|
|
8082
|
-
setTimeout(
|
|
8249
|
+
var realSleep = (ms) => new Promise((resolve6) => {
|
|
8250
|
+
setTimeout(resolve6, ms);
|
|
8083
8251
|
});
|
|
8084
8252
|
function message(err) {
|
|
8085
8253
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -8117,11 +8285,11 @@ function readLocalReceiptSide(subject, registryOpts = {}) {
|
|
|
8117
8285
|
return unreadSide(`registry.json could not be read: ${message(err)}`);
|
|
8118
8286
|
}
|
|
8119
8287
|
}
|
|
8120
|
-
async function readList(http,
|
|
8121
|
-
const res = await cloudHttpRequest(http, "GET",
|
|
8288
|
+
async function readList(http, path9, key) {
|
|
8289
|
+
const res = await cloudHttpRequest(http, "GET", path9);
|
|
8122
8290
|
const rows = res.json?.[key];
|
|
8123
8291
|
if (!res.ok || !Array.isArray(rows)) {
|
|
8124
|
-
return { reason: `GET ${
|
|
8292
|
+
return { reason: `GET ${path9.split("?")[0]} answered HTTP ${res.status}` };
|
|
8125
8293
|
}
|
|
8126
8294
|
return { rows: rows.filter((r) => Boolean(r) && typeof r === "object") };
|
|
8127
8295
|
}
|
|
@@ -8196,7 +8364,7 @@ async function readReceiptSides(subject, deps) {
|
|
|
8196
8364
|
var import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
8197
8365
|
import { createHash as createHash2 } from "node:crypto";
|
|
8198
8366
|
import { promises as fs3 } from "node:fs";
|
|
8199
|
-
import
|
|
8367
|
+
import path7 from "node:path";
|
|
8200
8368
|
|
|
8201
8369
|
// spex-console/src/lib/vault-id.ts
|
|
8202
8370
|
var FILE_KEY_RE = /^(?=[0-9]*[A-Z])[A-Z0-9]{4,}$/;
|
|
@@ -8778,8 +8946,8 @@ async function indexTemplateToCloud(args) {
|
|
|
8778
8946
|
const res = await cloudHttpRequest(args.http, "GET", REINDEX_PATH);
|
|
8779
8947
|
return { status: res.status, json: res.json };
|
|
8780
8948
|
},
|
|
8781
|
-
post: async (
|
|
8782
|
-
const res = await cloudHttpRequest(args.http, "POST",
|
|
8949
|
+
post: async (path9, body) => {
|
|
8950
|
+
const res = await cloudHttpRequest(args.http, "POST", path9, body);
|
|
8783
8951
|
return { status: res.status, json: res.json };
|
|
8784
8952
|
}
|
|
8785
8953
|
});
|
|
@@ -8825,39 +8993,58 @@ async function indexTemplateToCloud(args) {
|
|
|
8825
8993
|
// spex-console/src/lib/cli/install.ts
|
|
8826
8994
|
var MCP_REL = ["vendor", "heyspex-mcp", "cli.mjs"];
|
|
8827
8995
|
var PORTABLE_MCP_CLI = Object.freeze({
|
|
8996
|
+
claude: `\${CLAUDE_PROJECT_DIR:-.}/${CUSTOMER_LAUNCHERS.claude.rel.join("/")}`,
|
|
8997
|
+
cursor: `\${workspaceFolder}/${CUSTOMER_LAUNCHERS.cursor.rel.join("/")}`
|
|
8998
|
+
});
|
|
8999
|
+
var LEGACY_PORTABLE_MCP_CLI = Object.freeze({
|
|
8828
9000
|
claude: `\${CLAUDE_PROJECT_DIR:-.}/${PORTABLE_PACKAGE_DIR}/${MCP_REL.join("/")}`,
|
|
8829
9001
|
cursor: `\${workspaceFolder}/${PORTABLE_PACKAGE_DIR}/${MCP_REL.join("/")}`
|
|
8830
9002
|
});
|
|
9003
|
+
var LAUNCHER_MCP_FLAG = "--mcp";
|
|
9004
|
+
function mcpServerArgs(cliPath) {
|
|
9005
|
+
return /[\\/]heyspex[\\/]run-hook\.mjs$/.test(cliPath) ? [cliPath, LAUNCHER_MCP_FLAG] : [cliPath];
|
|
9006
|
+
}
|
|
9007
|
+
function repairLegacyMcpManifest(manifest, surface) {
|
|
9008
|
+
const servers = manifest?.mcpServers;
|
|
9009
|
+
const entry = servers && typeof servers === "object" ? servers.heyspex : void 0;
|
|
9010
|
+
if (!entry || !Array.isArray(entry.args) || entry.args[0] !== LEGACY_PORTABLE_MCP_CLI[surface]) {
|
|
9011
|
+
return false;
|
|
9012
|
+
}
|
|
9013
|
+
entry.args = mcpServerArgs(PORTABLE_MCP_CLI[surface]);
|
|
9014
|
+
return true;
|
|
9015
|
+
}
|
|
8831
9016
|
function mcpCliArgFor(surface, platformRoot, targetDir, joinPath) {
|
|
8832
9017
|
return samePlatformPath(targetDir, platformRoot) ? mcpCliPath(platformRoot, joinPath) : PORTABLE_MCP_CLI[surface];
|
|
8833
9018
|
}
|
|
8834
9019
|
function mcpCliPath(platformRoot, joinPath) {
|
|
8835
9020
|
return joinPath(platformRoot, ...MCP_REL);
|
|
8836
9021
|
}
|
|
8837
|
-
function renderCursorMcpJson(cliAbsPath, attachedVaultRoot) {
|
|
9022
|
+
function renderCursorMcpJson(cliAbsPath, attachedVaultRoot, opts = {}) {
|
|
9023
|
+
const pin = vaultRootPin(attachedVaultRoot, "${workspaceFolder}", opts);
|
|
8838
9024
|
return {
|
|
8839
9025
|
mcpServers: {
|
|
8840
9026
|
heyspex: {
|
|
8841
9027
|
type: "stdio",
|
|
8842
9028
|
command: "node",
|
|
8843
|
-
args:
|
|
8844
|
-
env: {
|
|
8845
|
-
HEYSPEX_VAULT_ROOT: attachedVaultRoot ?? "${workspaceFolder}"
|
|
8846
|
-
}
|
|
9029
|
+
args: mcpServerArgs(cliAbsPath),
|
|
9030
|
+
...pin ? { env: { HEYSPEX_VAULT_ROOT: pin } } : {}
|
|
8847
9031
|
}
|
|
8848
9032
|
}
|
|
8849
9033
|
};
|
|
8850
9034
|
}
|
|
8851
|
-
function
|
|
9035
|
+
function vaultRootPin(attachedVaultRoot, placeholder, opts = {}) {
|
|
9036
|
+
if (attachedVaultRoot) return attachedVaultRoot;
|
|
9037
|
+
return opts.targetIsVault === false ? null : placeholder;
|
|
9038
|
+
}
|
|
9039
|
+
function renderClaudeMcpJson(cliAbsPath, attachedVaultRoot, opts = {}) {
|
|
9040
|
+
const pin = vaultRootPin(attachedVaultRoot, "${CLAUDE_PROJECT_DIR:-.}", opts);
|
|
8852
9041
|
return {
|
|
8853
9042
|
mcpServers: {
|
|
8854
9043
|
heyspex: {
|
|
8855
9044
|
type: "stdio",
|
|
8856
9045
|
command: "node",
|
|
8857
|
-
args:
|
|
8858
|
-
env: {
|
|
8859
|
-
HEYSPEX_VAULT_ROOT: attachedVaultRoot ?? "${CLAUDE_PROJECT_DIR:-.}"
|
|
8860
|
-
}
|
|
9046
|
+
args: mcpServerArgs(cliAbsPath),
|
|
9047
|
+
...pin ? { env: { HEYSPEX_VAULT_ROOT: pin } } : {}
|
|
8861
9048
|
}
|
|
8862
9049
|
}
|
|
8863
9050
|
};
|
|
@@ -9135,7 +9322,6 @@ var WRITE_TARGET_KIND = {
|
|
|
9135
9322
|
claudeMcp: "claude_mcp",
|
|
9136
9323
|
claudeMd: "claude_md",
|
|
9137
9324
|
agentsMd: "agents_md",
|
|
9138
|
-
statuslineVendor: "statusline_vendor",
|
|
9139
9325
|
gitignore: "gitignore",
|
|
9140
9326
|
claudeMdTemplate: "claude_md_template",
|
|
9141
9327
|
agentsMdTemplate: "agents_md_template"
|
|
@@ -9192,12 +9378,6 @@ var INSTALL_WRITE_TARGETS = [
|
|
|
9192
9378
|
path: (targetDir, joinPath) => joinPath(targetDir, "AGENTS.md.template"),
|
|
9193
9379
|
appliesTo: (args, opts) => Boolean(args.registerVault) && !opts.attached && opts.installContract
|
|
9194
9380
|
},
|
|
9195
|
-
{
|
|
9196
|
-
kind: WRITE_TARGET_KIND.statuslineVendor,
|
|
9197
|
-
rel: "scripts/claude-statusline",
|
|
9198
|
-
path: (targetDir, joinPath) => joinPath(targetDir, "scripts", "claude-statusline"),
|
|
9199
|
-
appliesTo: (args) => (args.statusline ?? true) && args.claude
|
|
9200
|
-
},
|
|
9201
9381
|
{
|
|
9202
9382
|
kind: WRITE_TARGET_KIND.gitignore,
|
|
9203
9383
|
rel: ".gitignore",
|
|
@@ -9330,7 +9510,7 @@ var INSTALL_HELP = [
|
|
|
9330
9510
|
|
|
9331
9511
|
// spex-console/src/lib/cli/install-identity.ts
|
|
9332
9512
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
9333
|
-
import { existsSync as
|
|
9513
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
9334
9514
|
import { join as join11 } from "node:path";
|
|
9335
9515
|
import { createInterface } from "node:readline/promises";
|
|
9336
9516
|
init_credentials();
|
|
@@ -9338,7 +9518,7 @@ init_credentials();
|
|
|
9338
9518
|
// vendor/heyspex-mcp/whoami.mjs
|
|
9339
9519
|
init_heyspex_home();
|
|
9340
9520
|
init_credentials();
|
|
9341
|
-
import { homedir as
|
|
9521
|
+
import { homedir as homedir10 } from "node:os";
|
|
9342
9522
|
var SESSION_PATH = "/api/mcp/session";
|
|
9343
9523
|
async function probeCredentialIdentity({ consoleUrl, token, fetchImpl = fetch } = {}) {
|
|
9344
9524
|
if (!token) return { kind: "no_credential" };
|
|
@@ -9622,7 +9802,7 @@ function isInteractiveTerminal() {
|
|
|
9622
9802
|
}
|
|
9623
9803
|
function defaultIdentityGateIo(opts) {
|
|
9624
9804
|
const consoleUrl = opts.consoleUrl.trim().replace(/\/+$/, "");
|
|
9625
|
-
const loginCli = [opts.platformRoot, resolveCodeRoot({})].filter((r) => Boolean(r && r.trim())).map((r) => join11(r, "vendor", "heyspex-mcp", "cli.mjs")).find((p) =>
|
|
9805
|
+
const loginCli = [opts.platformRoot, resolveCodeRoot({})].filter((r) => Boolean(r && r.trim())).map((r) => join11(r, "vendor", "heyspex-mcp", "cli.mjs")).find((p) => existsSync7(p));
|
|
9626
9806
|
return {
|
|
9627
9807
|
consoleUrl,
|
|
9628
9808
|
interactive: opts.interactive ?? isInteractiveTerminal(),
|
|
@@ -10036,9 +10216,9 @@ function detachedSatelliteWarning(repoRoot, gitRemote, registryBefore, deps) {
|
|
|
10036
10216
|
reasons.push(`${wiredManifests.join(" + ")} already declares the heyspex MCP server`);
|
|
10037
10217
|
}
|
|
10038
10218
|
const contractFiles = ["CLAUDE.md", "AGENTS.md"].filter((name) => {
|
|
10039
|
-
const
|
|
10040
|
-
if (!deps.fileExists(
|
|
10041
|
-
const content = deps.readFile(
|
|
10219
|
+
const path9 = deps.joinPath(repoRoot, name);
|
|
10220
|
+
if (!deps.fileExists(path9)) return false;
|
|
10221
|
+
const content = deps.readFile(path9);
|
|
10042
10222
|
return content !== null && HEYSPEX_CONTRACT_MARKERS.some((m) => content.includes(m));
|
|
10043
10223
|
});
|
|
10044
10224
|
if (contractFiles.length > 0) {
|
|
@@ -10857,7 +11037,32 @@ async function runConnectFullRun(args, deps) {
|
|
|
10857
11037
|
const mcpConfirmedBy = "read .mcp.json + .cursor/mcp.json";
|
|
10858
11038
|
const claudeMissing = !deps.fileExists(claudeMcpPath);
|
|
10859
11039
|
const cursorMissing = !deps.fileExists(cursorMcpPath);
|
|
10860
|
-
|
|
11040
|
+
const repairedLegacy = [];
|
|
11041
|
+
for (const [file, surface, missing] of [
|
|
11042
|
+
[claudeMcpPath, "claude", claudeMissing],
|
|
11043
|
+
[cursorMcpPath, "cursor", cursorMissing]
|
|
11044
|
+
]) {
|
|
11045
|
+
if (missing || samePlatformPath(repoRoot, platformRoot)) continue;
|
|
11046
|
+
let parsed = null;
|
|
11047
|
+
try {
|
|
11048
|
+
parsed = JSON.parse(deps.readFile(file) ?? "");
|
|
11049
|
+
} catch {
|
|
11050
|
+
continue;
|
|
11051
|
+
}
|
|
11052
|
+
if (!repairLegacyMcpManifest(parsed, surface)) continue;
|
|
11053
|
+
if (!args.dryRun) deps.writeFile(file, `${JSON.stringify(parsed, null, 2)}
|
|
11054
|
+
`);
|
|
11055
|
+
repairedLegacy.push(file);
|
|
11056
|
+
}
|
|
11057
|
+
if (repairedLegacy.length > 0 && !claudeMissing && !cursorMissing) {
|
|
11058
|
+
steps.push({
|
|
11059
|
+
id: "mcp_entry",
|
|
11060
|
+
label,
|
|
11061
|
+
status: "run",
|
|
11062
|
+
detail: `${args.dryRun ? "would repoint" : "repointed"} ${repairedLegacy.join(", ")} at the committed launcher (${PORTABLE_MCP_CLI.claude})`,
|
|
11063
|
+
confirmed_by: mcpConfirmedBy
|
|
11064
|
+
});
|
|
11065
|
+
} else if (!claudeMissing && !cursorMissing) {
|
|
10861
11066
|
steps.push({
|
|
10862
11067
|
id: "mcp_entry",
|
|
10863
11068
|
label,
|
|
@@ -10880,12 +11085,14 @@ async function runConnectFullRun(args, deps) {
|
|
|
10880
11085
|
try {
|
|
10881
11086
|
const claudeCli = mcpCliArgFor("claude", platformRoot, repoRoot, deps.joinPath);
|
|
10882
11087
|
const cursorCli = mcpCliArgFor("cursor", platformRoot, repoRoot, deps.joinPath);
|
|
10883
|
-
const
|
|
11088
|
+
const markerRel = satellite?.viaMarker ? satellite.vaultPath : void 0;
|
|
11089
|
+
const claudePin = markerRel ? "${CLAUDE_PROJECT_DIR:-.}/" + markerRel : satellite?.vaultRootAbs;
|
|
11090
|
+
const cursorPin = markerRel ? "${workspaceFolder}/" + markerRel : satellite?.vaultRootAbs;
|
|
10884
11091
|
const written = [];
|
|
10885
11092
|
if (claudeMissing) {
|
|
10886
11093
|
deps.writeFile(
|
|
10887
11094
|
claudeMcpPath,
|
|
10888
|
-
`${JSON.stringify(renderClaudeMcpJson(claudeCli,
|
|
11095
|
+
`${JSON.stringify(renderClaudeMcpJson(claudeCli, claudePin), null, 2)}
|
|
10889
11096
|
`
|
|
10890
11097
|
);
|
|
10891
11098
|
written.push(claudeMcpPath);
|
|
@@ -10894,7 +11101,7 @@ async function runConnectFullRun(args, deps) {
|
|
|
10894
11101
|
deps.mkdir(deps.joinPath(repoRoot, ".cursor"));
|
|
10895
11102
|
deps.writeFile(
|
|
10896
11103
|
cursorMcpPath,
|
|
10897
|
-
`${JSON.stringify(renderCursorMcpJson(cursorCli,
|
|
11104
|
+
`${JSON.stringify(renderCursorMcpJson(cursorCli, cursorPin), null, 2)}
|
|
10898
11105
|
`
|
|
10899
11106
|
);
|
|
10900
11107
|
written.push(cursorMcpPath);
|
|
@@ -11279,11 +11486,11 @@ function resolveDoctorCommand(repoRoot, platformRoot, deps) {
|
|
|
11279
11486
|
const hs = deps.joinPath(platformRoot, "bin", "hs.mjs");
|
|
11280
11487
|
return deps.fileExists(hs) ? { args: [hs, "doctor", "--json"], confirmedBy: "hs doctor --json" } : null;
|
|
11281
11488
|
}
|
|
11282
|
-
function assertMarker(content,
|
|
11283
|
-
if (content === null) throw new Error(`${
|
|
11489
|
+
function assertMarker(content, path9, vaultId, accountId) {
|
|
11490
|
+
if (content === null) throw new Error(`${path9} could not be read back after the write`);
|
|
11284
11491
|
const back = parseVaultId(content);
|
|
11285
11492
|
if (vaultId && back !== vaultId) {
|
|
11286
|
-
throw new Error(`${
|
|
11493
|
+
throw new Error(`${path9} reads back vault_id ${back ?? "(none)"}, not ${vaultId}`);
|
|
11287
11494
|
}
|
|
11288
11495
|
}
|
|
11289
11496
|
var MIRRORED_SKILL_DIRS = [
|
|
@@ -11437,7 +11644,7 @@ async function runFixHarnessCommands(args, deps) {
|
|
|
11437
11644
|
continue;
|
|
11438
11645
|
}
|
|
11439
11646
|
const existingContent = deps.fileExists(installedPath) ? deps.readFile(installedPath) : null;
|
|
11440
|
-
if (existingContent === f.content) {
|
|
11647
|
+
if (existingContent !== null && normalizeEol(existingContent) === normalizeEol(f.content)) {
|
|
11441
11648
|
unchangedCount += 1;
|
|
11442
11649
|
continue;
|
|
11443
11650
|
}
|
|
@@ -11624,6 +11831,104 @@ var HELP3 = [
|
|
|
11624
11831
|
"Exit codes: 0 ok \xB7 1 usage \xB7 10 not-found \xB7 11 bad-arg \xB7 12 console-unreachable \xB7 13 write-failed"
|
|
11625
11832
|
].join("\n");
|
|
11626
11833
|
|
|
11834
|
+
// spex-console/src/lib/cli/generated-file-eol.ts
|
|
11835
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
11836
|
+
import { existsSync as existsSync8, readFileSync as readFileSync13 } from "node:fs";
|
|
11837
|
+
import { dirname as dirname6, relative, resolve as resolve5 } from "node:path";
|
|
11838
|
+
function dominantEol(text2) {
|
|
11839
|
+
const crlf = (text2.match(/\r\n/g) ?? []).length;
|
|
11840
|
+
const lf = (text2.match(/\n/g) ?? []).length - crlf;
|
|
11841
|
+
if (crlf === 0 && lf === 0) return null;
|
|
11842
|
+
return crlf > lf ? "\r\n" : "\n";
|
|
11843
|
+
}
|
|
11844
|
+
function applyEol(text2, eol) {
|
|
11845
|
+
const lf = text2.replace(/\r\n/g, "\n");
|
|
11846
|
+
return eol === "\n" ? lf : lf.replace(/\n/g, "\r\n");
|
|
11847
|
+
}
|
|
11848
|
+
function defaultRunGit(args, cwd) {
|
|
11849
|
+
try {
|
|
11850
|
+
const res = spawnSync3("git", args, {
|
|
11851
|
+
cwd,
|
|
11852
|
+
encoding: "utf8",
|
|
11853
|
+
windowsHide: true,
|
|
11854
|
+
timeout: 1e4
|
|
11855
|
+
});
|
|
11856
|
+
if (res.status !== 0) return null;
|
|
11857
|
+
return String(res.stdout ?? "").trim();
|
|
11858
|
+
} catch {
|
|
11859
|
+
return null;
|
|
11860
|
+
}
|
|
11861
|
+
}
|
|
11862
|
+
function defaultReadFile4(path9) {
|
|
11863
|
+
try {
|
|
11864
|
+
return readFileSync13(path9, "utf8");
|
|
11865
|
+
} catch {
|
|
11866
|
+
return null;
|
|
11867
|
+
}
|
|
11868
|
+
}
|
|
11869
|
+
function existingAncestor(path9) {
|
|
11870
|
+
let dir = dirname6(resolve5(path9));
|
|
11871
|
+
for (; ; ) {
|
|
11872
|
+
if (existsSync8(dir)) return dir;
|
|
11873
|
+
const parent = dirname6(dir);
|
|
11874
|
+
if (parent === dir) return dir;
|
|
11875
|
+
dir = parent;
|
|
11876
|
+
}
|
|
11877
|
+
}
|
|
11878
|
+
function createGeneratedFileEol(opts) {
|
|
11879
|
+
const readFile2 = opts.readFile ?? defaultReadFile4;
|
|
11880
|
+
const runGit = opts.runGit ?? defaultRunGit;
|
|
11881
|
+
const platform = opts.platform ?? process.platform;
|
|
11882
|
+
const attrCache = /* @__PURE__ */ new Map();
|
|
11883
|
+
let configEol;
|
|
11884
|
+
const configDefault = () => {
|
|
11885
|
+
if (configEol !== void 0) return configEol;
|
|
11886
|
+
if (runGit(["rev-parse", "--is-inside-work-tree"], opts.repoRoot) !== "true") {
|
|
11887
|
+
configEol = null;
|
|
11888
|
+
return configEol;
|
|
11889
|
+
}
|
|
11890
|
+
const get = (key) => runGit(["config", "--get", key], opts.repoRoot);
|
|
11891
|
+
const coreEol = (get("core.eol") ?? "").toLowerCase();
|
|
11892
|
+
if (coreEol === "crlf") configEol = "\r\n";
|
|
11893
|
+
else if (coreEol === "lf") configEol = "\n";
|
|
11894
|
+
else if (platform === "win32" && (get("core.autocrlf") ?? "").toLowerCase() === "true")
|
|
11895
|
+
configEol = "\r\n";
|
|
11896
|
+
else configEol = null;
|
|
11897
|
+
return configEol;
|
|
11898
|
+
};
|
|
11899
|
+
const attrEol = (path9) => {
|
|
11900
|
+
const abs = resolve5(path9);
|
|
11901
|
+
const cwd = existingAncestor(abs);
|
|
11902
|
+
const rel = relative(cwd, abs).replace(/\\/g, "/") || ".";
|
|
11903
|
+
const key = `${cwd}\0${rel}`;
|
|
11904
|
+
let out = attrCache.get(key);
|
|
11905
|
+
if (out === void 0) {
|
|
11906
|
+
out = runGit(["check-attr", "eol", "--", rel], cwd) ?? "";
|
|
11907
|
+
attrCache.set(key, out);
|
|
11908
|
+
}
|
|
11909
|
+
const m = out.match(/:\s*eol:\s*(\S+)\s*$/);
|
|
11910
|
+
const value = (m?.[1] ?? "").toLowerCase();
|
|
11911
|
+
if (value === "crlf") return "\r\n";
|
|
11912
|
+
if (value === "lf") return "\n";
|
|
11913
|
+
return null;
|
|
11914
|
+
};
|
|
11915
|
+
const eolFor = (path9, existing) => {
|
|
11916
|
+
const current = existing === void 0 ? readFile2(path9) : existing;
|
|
11917
|
+
if (current !== null) {
|
|
11918
|
+
const have = dominantEol(current);
|
|
11919
|
+
if (have) return have;
|
|
11920
|
+
}
|
|
11921
|
+
return attrEol(path9) ?? configDefault() ?? "\n";
|
|
11922
|
+
};
|
|
11923
|
+
return {
|
|
11924
|
+
eolFor,
|
|
11925
|
+
convert: (path9, content, existing) => {
|
|
11926
|
+
if (!content.includes("\n")) return content;
|
|
11927
|
+
return applyEol(content, eolFor(path9, existing));
|
|
11928
|
+
}
|
|
11929
|
+
};
|
|
11930
|
+
}
|
|
11931
|
+
|
|
11627
11932
|
// spex-console/bin/run-entry.ts
|
|
11628
11933
|
import process3 from "node:process";
|
|
11629
11934
|
var BinExit = class extends Error {
|
|
@@ -11655,7 +11960,7 @@ function runEntry(name, main2, options2 = {}) {
|
|
|
11655
11960
|
// spex-console/bin/hs-connect.ts
|
|
11656
11961
|
function readFile(p) {
|
|
11657
11962
|
try {
|
|
11658
|
-
return
|
|
11963
|
+
return readFileSync14(p, "utf8");
|
|
11659
11964
|
} catch {
|
|
11660
11965
|
return null;
|
|
11661
11966
|
}
|
|
@@ -11667,13 +11972,13 @@ function listDir(p) {
|
|
|
11667
11972
|
return [];
|
|
11668
11973
|
}
|
|
11669
11974
|
}
|
|
11670
|
-
var packageRoot =
|
|
11975
|
+
var packageRoot = path8.resolve(path8.dirname(fileURLToPath5(import.meta.url)), "..", "..");
|
|
11671
11976
|
var satelliteWalkDeps = {
|
|
11672
|
-
fileExists: (p) =>
|
|
11977
|
+
fileExists: (p) => existsSync9(p),
|
|
11673
11978
|
readFile,
|
|
11674
|
-
joinPath: (...segments) =>
|
|
11675
|
-
parentDir: (p) =>
|
|
11676
|
-
resolveDir: (p) =>
|
|
11979
|
+
joinPath: (...segments) => path8.join(...segments),
|
|
11980
|
+
parentDir: (p) => path8.dirname(p),
|
|
11981
|
+
resolveDir: (p) => path8.resolve(p)
|
|
11677
11982
|
};
|
|
11678
11983
|
async function main() {
|
|
11679
11984
|
const identityArgv = extractIdentityFlags(process4.argv.slice(3));
|
|
@@ -11698,7 +12003,7 @@ async function main() {
|
|
|
11698
12003
|
}
|
|
11699
12004
|
const cwd = resolveConnectCwd(process4.env, process4.cwd());
|
|
11700
12005
|
const satelliteRepoRoot = findSatelliteRepoRoot(cwd, satelliteWalkDeps);
|
|
11701
|
-
const repoRoot = satelliteRepoRoot ?? (process4.env.HS_VAULT_ROOT ?
|
|
12006
|
+
const repoRoot = satelliteRepoRoot ?? (process4.env.HS_VAULT_ROOT ? path8.resolve(process4.env.HS_VAULT_ROOT) : cwd);
|
|
11702
12007
|
const platformRoot = resolveCodeRoot({
|
|
11703
12008
|
// The two install-specific overrides outrank HS_PKG_ROOT here, so they
|
|
11704
12009
|
// ride in as `explicit`; the rest of the ladder (HS_PKG_ROOT, then the
|
|
@@ -11709,7 +12014,7 @@ async function main() {
|
|
|
11709
12014
|
const consoleUrl = resolveSpexConsoleUrl(repoRoot, readFile);
|
|
11710
12015
|
if (parsed.args.sub === "run" && !parsed.args.dryRun) {
|
|
11711
12016
|
const gate = await runIdentityGate(
|
|
11712
|
-
defaultIdentityGateIo({ consoleUrl, platformRoot:
|
|
12017
|
+
defaultIdentityGateIo({ consoleUrl, platformRoot: path8.resolve(platformRoot) }),
|
|
11713
12018
|
identityArgv.flags,
|
|
11714
12019
|
"hs connect"
|
|
11715
12020
|
);
|
|
@@ -11722,28 +12027,29 @@ async function main() {
|
|
|
11722
12027
|
return;
|
|
11723
12028
|
}
|
|
11724
12029
|
}
|
|
12030
|
+
const eol = createGeneratedFileEol({ repoRoot });
|
|
11725
12031
|
const result = await runConnect(parsed.args, {
|
|
11726
12032
|
repoRoot,
|
|
11727
12033
|
cwd,
|
|
11728
|
-
platformRoot:
|
|
11729
|
-
fileExists: (p) =>
|
|
12034
|
+
platformRoot: path8.resolve(platformRoot),
|
|
12035
|
+
fileExists: (p) => existsSync9(p),
|
|
11730
12036
|
readFile,
|
|
11731
12037
|
listDir,
|
|
11732
|
-
writeFile: (p, c) =>
|
|
11733
|
-
mkdir: (p) =>
|
|
11734
|
-
copyFile: (src, dest) =>
|
|
12038
|
+
writeFile: (p, c) => writeFileSync7(p, eol.convert(p, c), "utf8"),
|
|
12039
|
+
mkdir: (p) => mkdirSync7(p, { recursive: true }),
|
|
12040
|
+
copyFile: (src, dest) => copyFileSync2(src, dest),
|
|
11735
12041
|
isDirectory: (p) => {
|
|
11736
12042
|
try {
|
|
11737
|
-
return
|
|
12043
|
+
return statSync5(p).isDirectory();
|
|
11738
12044
|
} catch {
|
|
11739
12045
|
return false;
|
|
11740
12046
|
}
|
|
11741
12047
|
},
|
|
11742
|
-
joinPath: (...s) =>
|
|
11743
|
-
basename: (p) =>
|
|
12048
|
+
joinPath: (...s) => path8.join(...s),
|
|
12049
|
+
basename: (p) => path8.basename(p),
|
|
11744
12050
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
11745
12051
|
spawn: (command, args, opts) => {
|
|
11746
|
-
const res =
|
|
12052
|
+
const res = spawnSync4(command, args, {
|
|
11747
12053
|
cwd: opts?.cwd,
|
|
11748
12054
|
...opts?.env ? { env: mergeChildEnv(process4.env, opts.env) } : {},
|
|
11749
12055
|
encoding: "utf8",
|