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-init.mjs
CHANGED
|
@@ -51,9 +51,9 @@ var init_heyspex_home = __esm({
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
// vendor/heyspex-mcp/credentials.mjs
|
|
54
|
-
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
54
|
+
import { mkdirSync, readFileSync as readFileSync2, renameSync, writeFileSync } from "node:fs";
|
|
55
55
|
import os, { homedir as homedir2 } from "node:os";
|
|
56
|
-
import { dirname, join, resolve as
|
|
56
|
+
import { dirname as dirname2, join, resolve as resolve3 } from "node:path";
|
|
57
57
|
var init_credentials = __esm({
|
|
58
58
|
"vendor/heyspex-mcp/credentials.mjs"() {
|
|
59
59
|
"use strict";
|
|
@@ -62,7 +62,7 @@ var init_credentials = __esm({
|
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
// scripts/lib/dev-mode.mjs
|
|
65
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
65
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
66
66
|
import { homedir as homedir3 } from "node:os";
|
|
67
67
|
import { join as join2 } from "node:path";
|
|
68
68
|
function devModeFilePath(homeDir = heyspexHome()) {
|
|
@@ -90,7 +90,7 @@ function deriveSemantics(mode, reliance) {
|
|
|
90
90
|
vaultWriteMode: local ? "local" : "cloud"
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
function readLocalDevModeRecord({ homeDir = heyspexHome(), readFile =
|
|
93
|
+
function readLocalDevModeRecord({ homeDir = heyspexHome(), readFile = defaultReadFile2 } = {}) {
|
|
94
94
|
let raw;
|
|
95
95
|
try {
|
|
96
96
|
raw = readFile(devModeFilePath(homeDir));
|
|
@@ -118,10 +118,15 @@ function readLocalDevModeRecord({ homeDir = heyspexHome(), readFile = defaultRea
|
|
|
118
118
|
return { record: null, parseError: `unparseable dev-mode.json: ${String(err?.message ?? err)}` };
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
+
function overrideCloudCheck(source, cloudKnown, staleAgainstCloud) {
|
|
122
|
+
if (source !== "local-override") return "not-applicable";
|
|
123
|
+
if (!cloudKnown) return "unverified";
|
|
124
|
+
return staleAgainstCloud ? "stale" : "in-sync";
|
|
125
|
+
}
|
|
121
126
|
function resolveDevMode({
|
|
122
127
|
env = process.env,
|
|
123
128
|
homeDir = heyspexHome(),
|
|
124
|
-
readFile =
|
|
129
|
+
readFile = defaultReadFile2,
|
|
125
130
|
cloudSetting = void 0
|
|
126
131
|
} = {}) {
|
|
127
132
|
const local = readLocalDevModeRecord({ homeDir, readFile });
|
|
@@ -157,6 +162,7 @@ function resolveDevMode({
|
|
|
157
162
|
const semantics = deriveSemantics(mode, reliance);
|
|
158
163
|
const consoleUrl = source === "local-override" && local.record?.console_url ? local.record.console_url.replace(/\/+$/, "") : semantics.consoleUrl;
|
|
159
164
|
const staleAgainstCloud = source === "local-override" && cloudValue !== null && (cloudValue.mode !== mode || mode === "dev" && cloudValue.reliance !== semantics.reliance);
|
|
165
|
+
const cloudCheck = overrideCloudCheck(source, cloudKnown, staleAgainstCloud);
|
|
160
166
|
return {
|
|
161
167
|
mode,
|
|
162
168
|
reliance: semantics.reliance,
|
|
@@ -174,12 +180,13 @@ function resolveDevMode({
|
|
|
174
180
|
present: local.record !== null,
|
|
175
181
|
record: local.record,
|
|
176
182
|
parseError: local.parseError,
|
|
177
|
-
staleAgainstCloud
|
|
183
|
+
staleAgainstCloud,
|
|
184
|
+
cloudCheck
|
|
178
185
|
},
|
|
179
186
|
cloudSetting: { known: cloudKnown, value: cloudValue }
|
|
180
187
|
};
|
|
181
188
|
}
|
|
182
|
-
var CLOUD_CONSOLE_URL, LOCAL_CONSOLE_URL, DEV_MODE_FILENAME,
|
|
189
|
+
var CLOUD_CONSOLE_URL, LOCAL_CONSOLE_URL, DEV_MODE_FILENAME, defaultReadFile2;
|
|
183
190
|
var init_dev_mode = __esm({
|
|
184
191
|
"scripts/lib/dev-mode.mjs"() {
|
|
185
192
|
"use strict";
|
|
@@ -188,7 +195,7 @@ var init_dev_mode = __esm({
|
|
|
188
195
|
CLOUD_CONSOLE_URL = "https://app.heyspex.com";
|
|
189
196
|
LOCAL_CONSOLE_URL = "http://localhost:3000";
|
|
190
197
|
DEV_MODE_FILENAME = "dev-mode.json";
|
|
191
|
-
|
|
198
|
+
defaultReadFile2 = (p) => readFileSync3(p, "utf8");
|
|
192
199
|
}
|
|
193
200
|
});
|
|
194
201
|
|
|
@@ -855,21 +862,23 @@ var require_gray_matter = __commonJS({
|
|
|
855
862
|
|
|
856
863
|
// spex-console/bin/hs-init.ts
|
|
857
864
|
import {
|
|
858
|
-
copyFileSync,
|
|
859
|
-
existsSync as
|
|
860
|
-
mkdirSync as
|
|
865
|
+
copyFileSync as copyFileSync2,
|
|
866
|
+
existsSync as existsSync8,
|
|
867
|
+
mkdirSync as mkdirSync7,
|
|
861
868
|
readdirSync as readdirSync2,
|
|
862
|
-
readFileSync as
|
|
863
|
-
statSync,
|
|
864
|
-
writeFileSync as
|
|
869
|
+
readFileSync as readFileSync14,
|
|
870
|
+
statSync as statSync5,
|
|
871
|
+
writeFileSync as writeFileSync7
|
|
865
872
|
} from "node:fs";
|
|
866
|
-
import { dirname as
|
|
873
|
+
import { dirname as dirname7, join as join11, resolve as resolve6 } from "node:path";
|
|
867
874
|
import process4 from "node:process";
|
|
868
875
|
import { createInterface } from "node:readline/promises";
|
|
869
|
-
import { fileURLToPath as
|
|
876
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
870
877
|
|
|
871
878
|
// scripts/lib/shared-path-helpers.mjs
|
|
879
|
+
import { realpathSync } from "node:fs";
|
|
872
880
|
import { isAbsolute, resolve, sep } from "node:path";
|
|
881
|
+
import { fileURLToPath } from "node:url";
|
|
873
882
|
function resolveCodeRoot({
|
|
874
883
|
explicit,
|
|
875
884
|
packageRoot,
|
|
@@ -967,17 +976,118 @@ function writeProjectContract(ctx, options2 = {}) {
|
|
|
967
976
|
}
|
|
968
977
|
function customerClaudeMdHook(notify) {
|
|
969
978
|
return (ctx) => {
|
|
979
|
+
if (ctx.mode === "refresh" && ctx.deps.exists(ctx.deps.joinPath(ctx.targetDir, "CLAUDE.md"))) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
970
982
|
writeProjectContract(ctx, { notify });
|
|
971
983
|
};
|
|
972
984
|
}
|
|
973
985
|
|
|
986
|
+
// spex-console/src/lib/cli/generated-file-eol.ts
|
|
987
|
+
import { spawnSync } from "node:child_process";
|
|
988
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
989
|
+
import { dirname, relative, resolve as resolve2 } from "node:path";
|
|
990
|
+
function dominantEol(text) {
|
|
991
|
+
const crlf = (text.match(/\r\n/g) ?? []).length;
|
|
992
|
+
const lf = (text.match(/\n/g) ?? []).length - crlf;
|
|
993
|
+
if (crlf === 0 && lf === 0) return null;
|
|
994
|
+
return crlf > lf ? "\r\n" : "\n";
|
|
995
|
+
}
|
|
996
|
+
function applyEol(text, eol) {
|
|
997
|
+
const lf = text.replace(/\r\n/g, "\n");
|
|
998
|
+
return eol === "\n" ? lf : lf.replace(/\n/g, "\r\n");
|
|
999
|
+
}
|
|
1000
|
+
function defaultRunGit(args, cwd) {
|
|
1001
|
+
try {
|
|
1002
|
+
const res = spawnSync("git", args, {
|
|
1003
|
+
cwd,
|
|
1004
|
+
encoding: "utf8",
|
|
1005
|
+
windowsHide: true,
|
|
1006
|
+
timeout: 1e4
|
|
1007
|
+
});
|
|
1008
|
+
if (res.status !== 0) return null;
|
|
1009
|
+
return String(res.stdout ?? "").trim();
|
|
1010
|
+
} catch {
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
function defaultReadFile(path7) {
|
|
1015
|
+
try {
|
|
1016
|
+
return readFileSync(path7, "utf8");
|
|
1017
|
+
} catch {
|
|
1018
|
+
return null;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
function existingAncestor(path7) {
|
|
1022
|
+
let dir = dirname(resolve2(path7));
|
|
1023
|
+
for (; ; ) {
|
|
1024
|
+
if (existsSync(dir)) return dir;
|
|
1025
|
+
const parent = dirname(dir);
|
|
1026
|
+
if (parent === dir) return dir;
|
|
1027
|
+
dir = parent;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
function createGeneratedFileEol(opts) {
|
|
1031
|
+
const readFile = opts.readFile ?? defaultReadFile;
|
|
1032
|
+
const runGit = opts.runGit ?? defaultRunGit;
|
|
1033
|
+
const platform = opts.platform ?? process.platform;
|
|
1034
|
+
const attrCache = /* @__PURE__ */ new Map();
|
|
1035
|
+
let configEol;
|
|
1036
|
+
const configDefault = () => {
|
|
1037
|
+
if (configEol !== void 0) return configEol;
|
|
1038
|
+
if (runGit(["rev-parse", "--is-inside-work-tree"], opts.repoRoot) !== "true") {
|
|
1039
|
+
configEol = null;
|
|
1040
|
+
return configEol;
|
|
1041
|
+
}
|
|
1042
|
+
const get = (key) => runGit(["config", "--get", key], opts.repoRoot);
|
|
1043
|
+
const coreEol = (get("core.eol") ?? "").toLowerCase();
|
|
1044
|
+
if (coreEol === "crlf") configEol = "\r\n";
|
|
1045
|
+
else if (coreEol === "lf") configEol = "\n";
|
|
1046
|
+
else if (platform === "win32" && (get("core.autocrlf") ?? "").toLowerCase() === "true")
|
|
1047
|
+
configEol = "\r\n";
|
|
1048
|
+
else configEol = null;
|
|
1049
|
+
return configEol;
|
|
1050
|
+
};
|
|
1051
|
+
const attrEol = (path7) => {
|
|
1052
|
+
const abs = resolve2(path7);
|
|
1053
|
+
const cwd = existingAncestor(abs);
|
|
1054
|
+
const rel = relative(cwd, abs).replace(/\\/g, "/") || ".";
|
|
1055
|
+
const key = `${cwd}\0${rel}`;
|
|
1056
|
+
let out = attrCache.get(key);
|
|
1057
|
+
if (out === void 0) {
|
|
1058
|
+
out = runGit(["check-attr", "eol", "--", rel], cwd) ?? "";
|
|
1059
|
+
attrCache.set(key, out);
|
|
1060
|
+
}
|
|
1061
|
+
const m = out.match(/:\s*eol:\s*(\S+)\s*$/);
|
|
1062
|
+
const value = (m?.[1] ?? "").toLowerCase();
|
|
1063
|
+
if (value === "crlf") return "\r\n";
|
|
1064
|
+
if (value === "lf") return "\n";
|
|
1065
|
+
return null;
|
|
1066
|
+
};
|
|
1067
|
+
const eolFor = (path7, existing) => {
|
|
1068
|
+
const current = existing === void 0 ? readFile(path7) : existing;
|
|
1069
|
+
if (current !== null) {
|
|
1070
|
+
const have = dominantEol(current);
|
|
1071
|
+
if (have) return have;
|
|
1072
|
+
}
|
|
1073
|
+
return attrEol(path7) ?? configDefault() ?? "\n";
|
|
1074
|
+
};
|
|
1075
|
+
return {
|
|
1076
|
+
eolFor,
|
|
1077
|
+
convert: (path7, content, existing) => {
|
|
1078
|
+
if (!content.includes("\n")) return content;
|
|
1079
|
+
return applyEol(content, eolFor(path7, existing));
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
|
|
974
1084
|
// spex-console/src/lib/cli/init.ts
|
|
975
1085
|
import { randomUUID } from "node:crypto";
|
|
976
1086
|
|
|
977
1087
|
// scripts/lib/console-url-resolver.mjs
|
|
978
1088
|
init_heyspex_home();
|
|
979
1089
|
init_dev_mode();
|
|
980
|
-
import { readFileSync as
|
|
1090
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
981
1091
|
import { homedir as homedir4 } from "node:os";
|
|
982
1092
|
import { join as join3 } from "node:path";
|
|
983
1093
|
var DEFAULT_CONSOLE_URL = LOCAL_CONSOLE_URL;
|
|
@@ -1005,7 +1115,7 @@ function warnStaleLoopbackCredentialsOnce(credentialsUrl, derivedUrl, { log }) {
|
|
|
1005
1115
|
} catch {
|
|
1006
1116
|
}
|
|
1007
1117
|
}
|
|
1008
|
-
function readCredentialsConsoleUrl({ homeDir = heyspexHome(), readFile =
|
|
1118
|
+
function readCredentialsConsoleUrl({ homeDir = heyspexHome(), readFile = defaultReadFile3 } = {}) {
|
|
1009
1119
|
try {
|
|
1010
1120
|
const raw = readFile(join3(homeDir, ".heyspex", "credentials.yaml"));
|
|
1011
1121
|
const match = String(raw ?? "").match(/^console_url:\s*["']?([^"'\r\n#]+)/m);
|
|
@@ -1015,10 +1125,10 @@ function readCredentialsConsoleUrl({ homeDir = heyspexHome(), readFile = default
|
|
|
1015
1125
|
return null;
|
|
1016
1126
|
}
|
|
1017
1127
|
}
|
|
1018
|
-
function
|
|
1019
|
-
return
|
|
1128
|
+
function defaultReadFile3(p) {
|
|
1129
|
+
return readFileSync4(p, "utf8");
|
|
1020
1130
|
}
|
|
1021
|
-
function readDiscoveryFileConsoleUrl(repoRoot, { readDiscovery =
|
|
1131
|
+
function readDiscoveryFileConsoleUrl(repoRoot, { readDiscovery = defaultReadFile3 } = {}) {
|
|
1022
1132
|
if (!repoRoot) return null;
|
|
1023
1133
|
try {
|
|
1024
1134
|
const discovery = String(readDiscovery(join3(repoRoot, ".heyspex", "console-url")) ?? "").trim();
|
|
@@ -1053,8 +1163,8 @@ function resolveConsoleUrl({
|
|
|
1053
1163
|
strict = false,
|
|
1054
1164
|
devMode,
|
|
1055
1165
|
log = (line) => process.stderr.write(line),
|
|
1056
|
-
readFile =
|
|
1057
|
-
readDiscovery =
|
|
1166
|
+
readFile = defaultReadFile3,
|
|
1167
|
+
readDiscovery = defaultReadFile3
|
|
1058
1168
|
} = {}) {
|
|
1059
1169
|
const envUrl = env.HEYSPEX_CONSOLE_URL?.trim();
|
|
1060
1170
|
if (envUrl) return trimTrailingSlash(envUrl);
|
|
@@ -1080,17 +1190,17 @@ function resolveConsoleUrl({
|
|
|
1080
1190
|
}
|
|
1081
1191
|
|
|
1082
1192
|
// spex-console/src/lib/cli/control-shared.ts
|
|
1083
|
-
import
|
|
1193
|
+
import path2 from "node:path";
|
|
1084
1194
|
|
|
1085
1195
|
// scripts/lib/hs-command.mjs
|
|
1086
|
-
import { existsSync } from "node:fs";
|
|
1087
|
-
import { delimiter, dirname as
|
|
1088
|
-
import { fileURLToPath } from "node:url";
|
|
1196
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
1197
|
+
import { delimiter, dirname as dirname3, join as join4 } from "node:path";
|
|
1198
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1089
1199
|
var HS_BIN_NAME = "hs";
|
|
1090
1200
|
var HS_DISPATCHER_PATH = (() => {
|
|
1091
1201
|
try {
|
|
1092
|
-
const here =
|
|
1093
|
-
return join4(
|
|
1202
|
+
const here = dirname3(fileURLToPath2(import.meta.url));
|
|
1203
|
+
return join4(dirname3(dirname3(here)), "bin", "hs.mjs");
|
|
1094
1204
|
} catch {
|
|
1095
1205
|
return null;
|
|
1096
1206
|
}
|
|
@@ -1103,14 +1213,14 @@ var HS_DISPATCHER_PREFIX = HS_DISPATCHER_PATH ? `node ${shellQuote(HS_DISPATCHER
|
|
|
1103
1213
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
1104
1214
|
init_heyspex_home();
|
|
1105
1215
|
init_credentials();
|
|
1106
|
-
import { readFileSync as
|
|
1107
|
-
import { homedir as
|
|
1216
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
1217
|
+
import { homedir as homedir8 } from "node:os";
|
|
1108
1218
|
import { join as join8 } from "node:path";
|
|
1109
1219
|
|
|
1110
1220
|
// vendor/heyspex-mcp/session-owner.mjs
|
|
1111
1221
|
init_heyspex_home();
|
|
1112
1222
|
init_credentials();
|
|
1113
|
-
import { readFileSync as
|
|
1223
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
1114
1224
|
import { homedir as homedir5 } from "node:os";
|
|
1115
1225
|
import { join as join5 } from "node:path";
|
|
1116
1226
|
|
|
@@ -1128,10 +1238,10 @@ var VAULT_LESS_ENDPOINTS = Object.freeze([
|
|
|
1128
1238
|
// vendor/heyspex-mcp/write-outbox.mjs
|
|
1129
1239
|
import {
|
|
1130
1240
|
readdirSync,
|
|
1131
|
-
readFileSync as
|
|
1241
|
+
readFileSync as readFileSync6,
|
|
1132
1242
|
writeFileSync as writeFileSync3,
|
|
1133
1243
|
mkdirSync as mkdirSync3,
|
|
1134
|
-
existsSync as
|
|
1244
|
+
existsSync as existsSync3,
|
|
1135
1245
|
renameSync as renameSync2,
|
|
1136
1246
|
rmSync
|
|
1137
1247
|
} from "node:fs";
|
|
@@ -1139,9 +1249,30 @@ import { basename, join as join6, isAbsolute as isAbsolute2 } from "node:path";
|
|
|
1139
1249
|
|
|
1140
1250
|
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
1141
1251
|
init_heyspex_home();
|
|
1142
|
-
import { existsSync as
|
|
1143
|
-
import { homedir as
|
|
1144
|
-
|
|
1252
|
+
import { existsSync as existsSync5, readFileSync as readFileSync8, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
1253
|
+
import { homedir as homedir7, tmpdir } from "node:os";
|
|
1254
|
+
|
|
1255
|
+
// vendor/heyspex-mcp/usable-dir-env.mjs
|
|
1256
|
+
import { statSync } from "node:fs";
|
|
1257
|
+
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
1258
|
+
|
|
1259
|
+
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
1260
|
+
import { basename as basename2, dirname as dirname4, join as join7, resolve as resolve4 } from "node:path";
|
|
1261
|
+
|
|
1262
|
+
// vendor/heyspex-mcp/vault-binding.mjs
|
|
1263
|
+
import {
|
|
1264
|
+
copyFileSync,
|
|
1265
|
+
existsSync as existsSync4,
|
|
1266
|
+
mkdirSync as mkdirSync4,
|
|
1267
|
+
readFileSync as readFileSync7,
|
|
1268
|
+
realpathSync as realpathSync2,
|
|
1269
|
+
renameSync as renameSync3,
|
|
1270
|
+
statSync as statSync2,
|
|
1271
|
+
unlinkSync,
|
|
1272
|
+
writeFileSync as writeFileSync4
|
|
1273
|
+
} from "node:fs";
|
|
1274
|
+
import { homedir as homedir6 } from "node:os";
|
|
1275
|
+
import path from "node:path";
|
|
1145
1276
|
|
|
1146
1277
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
1147
1278
|
var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMATCH", "VAULT_NOT_REGISTERED"]);
|
|
@@ -1150,11 +1281,11 @@ var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMAT
|
|
|
1150
1281
|
init_credentials();
|
|
1151
1282
|
|
|
1152
1283
|
// spex-console/src/lib/vault-registry/registry-file.ts
|
|
1153
|
-
import { existsSync as
|
|
1154
|
-
import { dirname as
|
|
1284
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync10, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
1285
|
+
import { dirname as dirname5, join as join9, resolve as resolve5 } from "node:path";
|
|
1155
1286
|
|
|
1156
1287
|
// spex-console/src/lib/heyspex-home.ts
|
|
1157
|
-
import { homedir as
|
|
1288
|
+
import { homedir as homedir9 } from "node:os";
|
|
1158
1289
|
|
|
1159
1290
|
// spex-console/src/lib/cli/control-shared.ts
|
|
1160
1291
|
var EXIT = {
|
|
@@ -1547,12 +1678,15 @@ var HELP = [
|
|
|
1547
1678
|
"(spex-console/src/lib/cli/template-manifest.ts) \u2014 universal docs",
|
|
1548
1679
|
"copied verbatim, template-shape docs written as author-prompt skeletons \u2014",
|
|
1549
1680
|
"plus a generated CLAUDE.md, the kept-principles index, and the template_version",
|
|
1550
|
-
"pin; with --git, one initial `git init` + commit.
|
|
1551
|
-
"holds heyspex.yaml
|
|
1552
|
-
"
|
|
1553
|
-
"
|
|
1554
|
-
"
|
|
1555
|
-
"
|
|
1681
|
+
"pin; with --git, one initial `git init` + commit. On an EXISTING vault (<dir>",
|
|
1682
|
+
"holds heyspex.yaml with a vault_id) it is a REFRESH \u2014 the repair `hs doctor`'s",
|
|
1683
|
+
"vault-template row names: only missing shipped files are added, template_version",
|
|
1684
|
+
"is written/updated in heyspex.yaml (every other byte and the vault_id kept),",
|
|
1685
|
+
"nothing existing is ever overwritten (an existing CLAUDE.md gets a",
|
|
1686
|
+
"CLAUDE.md.template beside it), the result lists each manifest row as created or",
|
|
1687
|
+
"kept, and a second run writes nothing. <dir> may be any path (a satellite repo",
|
|
1688
|
+
"names its vault, e.g. `hs init --customer-vault ../my-specs`). Refuses only a",
|
|
1689
|
+
"non-empty <dir> that has no heyspex.yaml. See init.customer-vault.ts.",
|
|
1556
1690
|
"",
|
|
1557
1691
|
"Flags:",
|
|
1558
1692
|
" --console-url <url> console_url value (default: the mode-aware console --",
|
|
@@ -1575,7 +1709,7 @@ var HELP = [
|
|
|
1575
1709
|
].join("\n");
|
|
1576
1710
|
|
|
1577
1711
|
// spex-console/src/lib/cli/init.customer-vault.ts
|
|
1578
|
-
import { basename as
|
|
1712
|
+
import { basename as basename3 } from "node:path";
|
|
1579
1713
|
|
|
1580
1714
|
// spex-console/src/lib/cli/template-manifest.sources.mjs
|
|
1581
1715
|
var UNIVERSAL_TEMPLATE_ROWS = [
|
|
@@ -2060,41 +2194,42 @@ var SCAFFOLD_FOLDERS = [
|
|
|
2060
2194
|
"checks",
|
|
2061
2195
|
"events"
|
|
2062
2196
|
];
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
if (deps.isDirectory) return deps.isDirectory(path5);
|
|
2066
|
-
try {
|
|
2067
|
-
const kids = deps.readdir(path5);
|
|
2068
|
-
return kids.length > 0 || !name.includes(".");
|
|
2069
|
-
} catch {
|
|
2070
|
-
return false;
|
|
2071
|
-
}
|
|
2197
|
+
function defaultVaultName(targetDir) {
|
|
2198
|
+
return basename3(targetDir) || targetDir;
|
|
2072
2199
|
}
|
|
2073
|
-
function
|
|
2074
|
-
const
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
if (isDir(deps, childAbs, name)) walk(childAbs, childRel);
|
|
2080
|
-
else if (!PLACEHOLDER_FILES.has(name) && name.endsWith(".md") && !manifestDests.has(childRel))
|
|
2081
|
-
out.push(childRel);
|
|
2082
|
-
}
|
|
2083
|
-
};
|
|
2084
|
-
const specsRoot = deps.joinPath(targetDir, "specs");
|
|
2085
|
-
if (deps.exists(specsRoot)) walk(specsRoot, "specs");
|
|
2086
|
-
return out;
|
|
2200
|
+
function readTemplateVersionPin(yamlText) {
|
|
2201
|
+
const m = yamlText.match(/^template_version:[ \t]*(.*?)[ \t]*$/m);
|
|
2202
|
+
if (!m) return null;
|
|
2203
|
+
const raw = m[1].trim();
|
|
2204
|
+
const unquoted = raw.replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1");
|
|
2205
|
+
return unquoted.length > 0 ? unquoted : null;
|
|
2087
2206
|
}
|
|
2088
|
-
function
|
|
2089
|
-
|
|
2207
|
+
function stampTemplateVersion(content, version) {
|
|
2208
|
+
if (readTemplateVersionPin(content) === version) return content;
|
|
2209
|
+
const eol = content.includes("\r\n") ? "\r\n" : "\n";
|
|
2210
|
+
const line = `template_version: ${version}`;
|
|
2211
|
+
if (/^template_version:[^\r\n]*$/m.test(content)) {
|
|
2212
|
+
return content.replace(/^template_version:[^\r\n]*$/m, line);
|
|
2213
|
+
}
|
|
2214
|
+
const body = content.replace(/(?:\r?\n)+$/, "");
|
|
2215
|
+
return body.length === 0 ? `${line}${eol}` : `${body}${eol}${line}${eol}`;
|
|
2216
|
+
}
|
|
2217
|
+
function parentDirOf(deps, targetDir, dest) {
|
|
2218
|
+
const segments = dest.split("/");
|
|
2219
|
+
if (segments.length < 2) return null;
|
|
2220
|
+
return deps.joinPath(targetDir, ...segments.slice(0, -1));
|
|
2090
2221
|
}
|
|
2091
2222
|
function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
2092
2223
|
const { targetDir } = args;
|
|
2093
2224
|
const written = [];
|
|
2094
2225
|
const filter = options2.manifestFilter ?? (() => true);
|
|
2095
2226
|
const rows = TEMPLATE_MANIFEST.filter(filter);
|
|
2227
|
+
const heyspexYamlPath = deps.joinPath(targetDir, "heyspex.yaml");
|
|
2228
|
+
const markerPresent = deps.exists(targetDir) && deps.exists(heyspexYamlPath);
|
|
2229
|
+
const existingYaml = markerPresent ? deps.readFile?.(heyspexYamlPath) ?? null : null;
|
|
2230
|
+
const existingVaultId = existingYaml ? parseVaultId(existingYaml) : null;
|
|
2231
|
+
const mode = markerPresent && existingVaultId ? "refresh" : "scaffold";
|
|
2096
2232
|
if (deps.exists(targetDir)) {
|
|
2097
|
-
const markerPresent = deps.exists(deps.joinPath(targetDir, "heyspex.yaml"));
|
|
2098
2233
|
if (!markerPresent && deps.readdir(targetDir).length > 0) {
|
|
2099
2234
|
return {
|
|
2100
2235
|
code: EXIT.INVALID_ARG,
|
|
@@ -2104,43 +2239,43 @@ function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
|
2104
2239
|
written: []
|
|
2105
2240
|
};
|
|
2106
2241
|
}
|
|
2107
|
-
if (markerPresent) {
|
|
2108
|
-
const manifestDests = new Set(TEMPLATE_MANIFEST.map((r) => r.dest));
|
|
2109
|
-
const managed = findManagedSpecs(deps, targetDir, manifestDests);
|
|
2110
|
-
if (managed.length > 0) {
|
|
2111
|
-
return {
|
|
2112
|
-
code: EXIT.INVALID_ARG,
|
|
2113
|
-
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.`,
|
|
2114
|
-
payload: { ok: false, error: "specs_not_empty", path: targetDir, specs: managed },
|
|
2115
|
-
isError: true,
|
|
2116
|
-
written: []
|
|
2117
|
-
};
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
2242
|
} else {
|
|
2121
2243
|
deps.mkdirRecursive(targetDir);
|
|
2122
2244
|
}
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2245
|
+
if (mode === "scaffold") {
|
|
2246
|
+
const specsRoot = deps.joinPath(targetDir, "specs");
|
|
2247
|
+
deps.mkdirRecursive(specsRoot);
|
|
2248
|
+
for (const folder of SCAFFOLD_FOLDERS) {
|
|
2249
|
+
deps.mkdirRecursive(deps.joinPath(specsRoot, folder));
|
|
2250
|
+
}
|
|
2127
2251
|
}
|
|
2128
|
-
const heyspexYamlPath = deps.joinPath(targetDir, "heyspex.yaml");
|
|
2129
2252
|
let vaultId;
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
vaultId =
|
|
2253
|
+
let pin;
|
|
2254
|
+
if (markerPresent) {
|
|
2255
|
+
vaultId = existingVaultId ?? "";
|
|
2256
|
+
const stamped = existingYaml === null ? null : stampTemplateVersion(existingYaml, TEMPLATE_VERSION);
|
|
2257
|
+
if (stamped !== null && stamped !== existingYaml) {
|
|
2258
|
+
deps.writeFile(heyspexYamlPath, stamped);
|
|
2259
|
+
written.push(heyspexYamlPath);
|
|
2260
|
+
pin = "written";
|
|
2261
|
+
} else {
|
|
2262
|
+
pin = "kept";
|
|
2263
|
+
}
|
|
2133
2264
|
} else {
|
|
2134
2265
|
vaultId = mintVaultId();
|
|
2135
2266
|
deps.writeFile(
|
|
2136
2267
|
heyspexYamlPath,
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2268
|
+
stampTemplateVersion(
|
|
2269
|
+
renderHeyspexYaml({
|
|
2270
|
+
consoleUrl: options2.consoleUrl ?? DEFAULT_CONSOLE_URL2,
|
|
2271
|
+
vaultRoot: "specs/",
|
|
2272
|
+
vaultId
|
|
2273
|
+
}),
|
|
2274
|
+
TEMPLATE_VERSION
|
|
2275
|
+
)
|
|
2142
2276
|
);
|
|
2143
2277
|
written.push(heyspexYamlPath);
|
|
2278
|
+
pin = "written";
|
|
2144
2279
|
}
|
|
2145
2280
|
const readConfigSeed2 = deps.readConfigSeed;
|
|
2146
2281
|
const configSeed = seedConfigYaml(
|
|
@@ -2156,6 +2291,10 @@ function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
|
2156
2291
|
rowResults.push({ dest: row.dest, action: "kept" });
|
|
2157
2292
|
continue;
|
|
2158
2293
|
}
|
|
2294
|
+
if (mode === "refresh") {
|
|
2295
|
+
const parent = parentDirOf(deps, targetDir, row.dest);
|
|
2296
|
+
if (parent && !deps.exists(parent)) deps.mkdirRecursive(parent);
|
|
2297
|
+
}
|
|
2159
2298
|
if (row.classification === "universal-template") {
|
|
2160
2299
|
const srcAbs = deps.joinPath(deps.platformRoot, ...row.source.split("/"));
|
|
2161
2300
|
deps.copyFile(srcAbs, destAbs);
|
|
@@ -2175,24 +2314,41 @@ function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
|
2175
2314
|
targetDir,
|
|
2176
2315
|
vaultName: options2.vaultName ?? defaultVaultName(targetDir),
|
|
2177
2316
|
templateVersion: TEMPLATE_VERSION,
|
|
2317
|
+
mode,
|
|
2178
2318
|
manifestRows: rows,
|
|
2179
2319
|
rows: rowResults,
|
|
2180
2320
|
deps,
|
|
2181
|
-
recordWrite: (
|
|
2182
|
-
written.push(
|
|
2321
|
+
recordWrite: (path7) => {
|
|
2322
|
+
written.push(path7);
|
|
2183
2323
|
}
|
|
2184
2324
|
};
|
|
2185
2325
|
for (const hook of options2.afterScaffold) hook(ctx);
|
|
2186
2326
|
}
|
|
2187
2327
|
const createdCount = rowResults.filter((r) => r.action === "created").length;
|
|
2188
2328
|
const keptCount = rowResults.length - createdCount;
|
|
2329
|
+
const added = rowResults.filter((r) => r.action === "created").map((r) => r.dest);
|
|
2330
|
+
let message;
|
|
2331
|
+
if (mode === "refresh") {
|
|
2332
|
+
const parts = [];
|
|
2333
|
+
if (added.length > 0)
|
|
2334
|
+
parts.push(`added ${added.length} missing template file(s): ${added.join(", ")}`);
|
|
2335
|
+
if (pin === "written")
|
|
2336
|
+
parts.push(`pinned template_version: ${TEMPLATE_VERSION} in heyspex.yaml`);
|
|
2337
|
+
const hookWrites = written.length - added.length - (pin === "written" ? 1 : 0);
|
|
2338
|
+
if (hookWrites > 0) parts.push(`${hookWrites} other file(s) written`);
|
|
2339
|
+
message = 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.`;
|
|
2340
|
+
} else {
|
|
2341
|
+
message = `Initialized customer vault at ${targetDir} (${written.length} files written, ${createdCount} manifest rows created, ${keptCount} kept, template v${TEMPLATE_VERSION}).`;
|
|
2342
|
+
}
|
|
2189
2343
|
return {
|
|
2190
2344
|
code: EXIT.OK,
|
|
2191
|
-
message
|
|
2345
|
+
message,
|
|
2192
2346
|
payload: {
|
|
2193
2347
|
ok: true,
|
|
2348
|
+
mode,
|
|
2194
2349
|
targetDir,
|
|
2195
2350
|
templateVersion: TEMPLATE_VERSION,
|
|
2351
|
+
templatePin: pin,
|
|
2196
2352
|
vaultId,
|
|
2197
2353
|
written,
|
|
2198
2354
|
rows: rowResults,
|
|
@@ -2205,10 +2361,10 @@ function runCustomerVaultInit(args, deps, options2 = {}) {
|
|
|
2205
2361
|
}
|
|
2206
2362
|
|
|
2207
2363
|
// spex-console/src/lib/cli/init-git-finalize.ts
|
|
2208
|
-
import { spawnSync } from "node:child_process";
|
|
2364
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
2209
2365
|
var nodeGitRunner = {
|
|
2210
2366
|
run(args, cwd) {
|
|
2211
|
-
const result =
|
|
2367
|
+
const result = spawnSync2("git", args, { cwd, encoding: "utf8" });
|
|
2212
2368
|
return {
|
|
2213
2369
|
ok: result.error === void 0 && result.status === 0,
|
|
2214
2370
|
stdout: result.stdout ?? "",
|
|
@@ -2271,12 +2427,21 @@ function gitFinalizeHook(runner, notify) {
|
|
|
2271
2427
|
}
|
|
2272
2428
|
|
|
2273
2429
|
// spex-console/src/lib/cli/install.ts
|
|
2274
|
-
import { isAbsolute as
|
|
2430
|
+
import { isAbsolute as isAbsolute4, resolve as resolveNodePath2 } from "node:path";
|
|
2431
|
+
|
|
2432
|
+
// spex-console/src/lib/vault-resolve/index.ts
|
|
2433
|
+
import { existsSync as existsSync7, readFileSync as readFileSync11, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
|
|
2434
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
2435
|
+
import path3 from "node:path";
|
|
2436
|
+
|
|
2437
|
+
// spex-console/src/lib/cli/satellite.ts
|
|
2438
|
+
import { resolve as resolveNodePath } from "node:path";
|
|
2439
|
+
import process2 from "node:process";
|
|
2275
2440
|
|
|
2276
2441
|
// scripts/install-cursor-hooks.mjs
|
|
2277
2442
|
import fs2 from "node:fs";
|
|
2278
|
-
import
|
|
2279
|
-
import { fileURLToPath as
|
|
2443
|
+
import path5 from "node:path";
|
|
2444
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
2280
2445
|
|
|
2281
2446
|
// scripts/cursor-hooks/manifest.mjs
|
|
2282
2447
|
var SHIM = "scripts/cursor-hooks/_run.mjs";
|
|
@@ -2422,9 +2587,9 @@ function timeoutFor(entry) {
|
|
|
2422
2587
|
// scripts/lib/customer-kit.mjs
|
|
2423
2588
|
import { createHash } from "node:crypto";
|
|
2424
2589
|
import fs from "node:fs";
|
|
2425
|
-
import
|
|
2590
|
+
import path4 from "node:path";
|
|
2426
2591
|
import os2 from "node:os";
|
|
2427
|
-
import { fileURLToPath as
|
|
2592
|
+
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
|
|
2428
2593
|
|
|
2429
2594
|
// scripts/lib/hook-dispositions.mjs
|
|
2430
2595
|
var HOSTS = Object.freeze(["claude-code", "cursor", "copilot"]);
|
|
@@ -2691,7 +2856,7 @@ function toPosixPath(p) {
|
|
|
2691
2856
|
function samePlatformPath(a, b) {
|
|
2692
2857
|
if (!a || !b) return false;
|
|
2693
2858
|
const norm = (p) => {
|
|
2694
|
-
const s = toPosixPath(
|
|
2859
|
+
const s = toPosixPath(path4.resolve(p));
|
|
2695
2860
|
return process.platform === "win32" ? s.toLowerCase() : s;
|
|
2696
2861
|
};
|
|
2697
2862
|
return norm(a) === norm(b);
|
|
@@ -2764,8 +2929,16 @@ var LAUNCHER_TEMPLATE = [
|
|
|
2764
2929
|
"// 4. node_modules/heyspex up from $__ENV__, $CLAUDE_PROJECT_DIR, $CURSOR_PROJECT_DIR, cwd",
|
|
2765
2930
|
"// 5. <npm root -g>/heyspex a global install, last resort",
|
|
2766
2931
|
"// Nothing found -> one stderr line and exit 0 (fail-open, like the shim itself).",
|
|
2932
|
+
"//",
|
|
2933
|
+
"// The same resolution starts the package's other entrypoints, so no committed",
|
|
2934
|
+
"// file names node_modules/heyspex directly and a repo with no node_modules of",
|
|
2935
|
+
"// its own still works off a global install:",
|
|
2936
|
+
"// --mcp the stdio MCP server (.mcp.json, .cursor/mcp.json)",
|
|
2937
|
+
"// --statusline the Claude Code status line (statusLine.command)",
|
|
2938
|
+
"// --resolve print the package root, exit 0; exit 1 when none (hs doctor)",
|
|
2767
2939
|
"import { spawnSync } from 'node:child_process';",
|
|
2768
|
-
"import { existsSync } from 'node:fs';",
|
|
2940
|
+
"import { existsSync, readdirSync, readFileSync, realpathSync } from 'node:fs';",
|
|
2941
|
+
"import { homedir } from 'node:os';",
|
|
2769
2942
|
"import { dirname, resolve } from 'node:path';",
|
|
2770
2943
|
"import { fileURLToPath, pathToFileURL } from 'node:url';",
|
|
2771
2944
|
"",
|
|
@@ -2775,6 +2948,7 @@ var LAUNCHER_TEMPLATE = [
|
|
|
2775
2948
|
"const text = (v) => (typeof v === 'string' && v.trim() ? v.trim() : null);",
|
|
2776
2949
|
"const hasShim = (root) => Boolean(root) && existsSync(resolve(root, ...SHIM));",
|
|
2777
2950
|
"",
|
|
2951
|
+
"__YIELD__",
|
|
2778
2952
|
"function packageUpFrom(start) {",
|
|
2779
2953
|
" let dir = resolve(start);",
|
|
2780
2954
|
" for (;;) {",
|
|
@@ -2809,31 +2983,109 @@ var LAUNCHER_TEMPLATE = [
|
|
|
2809
2983
|
" if (hasShim(global)) root = global;",
|
|
2810
2984
|
"}",
|
|
2811
2985
|
"",
|
|
2986
|
+
"const ENTRYPOINTS = {",
|
|
2987
|
+
" '--mcp': 'vendor/heyspex-mcp/cli.mjs',",
|
|
2988
|
+
" '--statusline': 'scripts/claude-statusline/statusline-command.mjs',",
|
|
2989
|
+
"};",
|
|
2990
|
+
"const mode = process.argv[2];",
|
|
2991
|
+
"const entry = Object.hasOwn(ENTRYPOINTS, mode) ? ENTRYPOINTS[mode] : null;",
|
|
2992
|
+
"",
|
|
2812
2993
|
"if (!root) {",
|
|
2994
|
+
" const what = entry || mode === '--resolve' ? mode : 'hook ' + (mode ?? '?');",
|
|
2813
2995
|
" process.stderr.write(",
|
|
2814
|
-
" '[heyspex]
|
|
2815
|
-
` '(run "npm install heyspex" in this repo, or set HEYSPEX_PLATFORM_ROOT).
|
|
2816
|
-
" 'HEYSPEX_PLATFORM_ROOT, HEYSPEX_MCP_ENTRY, node_modules/heyspex up from ' + starts.join(', ') + ', and npm root -g.\\n',",
|
|
2996
|
+
" '[heyspex] ' + what + ' skipped: no heyspex package found ' +",
|
|
2997
|
+
` '(run "npm install heyspex" or "npm link heyspex" in this repo, install it globally, or set HEYSPEX_PLATFORM_ROOT). ' +`,
|
|
2998
|
+
" 'Looked for __SHIM__ under HEYSPEX_PLATFORM_ROOT, HEYSPEX_MCP_ENTRY, node_modules/heyspex up from ' + starts.join(', ') + ', and npm root -g.\\n',",
|
|
2817
2999
|
" );",
|
|
3000
|
+
" // Hooks and the status line fail open; the MCP server and --resolve fail",
|
|
3001
|
+
" // loudly, so the client and hs doctor both see it.",
|
|
3002
|
+
" process.exit(mode === '--mcp' || mode === '--resolve' ? 1 : 0);",
|
|
3003
|
+
"}",
|
|
3004
|
+
"if (mode === '--resolve') {",
|
|
3005
|
+
" process.stdout.write(root + '\\n');",
|
|
2818
3006
|
" process.exit(0);",
|
|
2819
3007
|
"}",
|
|
2820
3008
|
"",
|
|
2821
3009
|
"// argv is already [node, <this file>, <hook>, ...args] -- the shape the shim",
|
|
2822
|
-
'// reads; the
|
|
2823
|
-
"//
|
|
2824
|
-
"
|
|
2825
|
-
"
|
|
3010
|
+
'// reads; the target replaces this file so a script guarded by "am I main?"',
|
|
3011
|
+
"// runs exactly as if it had been invoked directly. Real path, so that guard",
|
|
3012
|
+
"// still matches when node_modules/heyspex is an npm link or a junction (node",
|
|
3013
|
+
"// realpaths import.meta.url but leaves argv[1] alone).",
|
|
3014
|
+
"let target = resolve(root, ...(entry ? entry.split('/') : SHIM));",
|
|
3015
|
+
"try {",
|
|
3016
|
+
" target = realpathSync(target);",
|
|
3017
|
+
"} catch {",
|
|
3018
|
+
" // keep the resolved path",
|
|
3019
|
+
"}",
|
|
3020
|
+
"if (entry) process.argv.splice(2, 1);",
|
|
3021
|
+
"process.argv[1] = target;",
|
|
2826
3022
|
"try {",
|
|
2827
|
-
" await import(pathToFileURL(
|
|
3023
|
+
" await import(pathToFileURL(target).href);",
|
|
2828
3024
|
"} catch (err) {",
|
|
2829
|
-
" process.stderr.write('[heyspex] hook ' + (process.argv[2] ?? '?') + ' skipped: ' + (err && err.message ? err.message : err) + '\\n');",
|
|
3025
|
+
" process.stderr.write('[heyspex] ' + (entry ? mode : 'hook ' + (process.argv[2] ?? '?')) + ' skipped: ' + (err && err.message ? err.message : err) + '\\n');",
|
|
3026
|
+
" // Hooks and the status line fail open; the MCP server fails loudly.",
|
|
3027
|
+
" if (mode === '--mcp') process.exit(1);",
|
|
2830
3028
|
" process.exit(0);",
|
|
2831
3029
|
"}",
|
|
2832
3030
|
""
|
|
2833
3031
|
].join("\n");
|
|
3032
|
+
var LAUNCHER_YIELD_MARKER = "// yields-to-plugin: v1";
|
|
3033
|
+
var LAUNCHER_YIELD_BLOCK = [
|
|
3034
|
+
LAUNCHER_YIELD_MARKER + " -- one source of hooks: when the heyspex plugin is enabled on this machine",
|
|
3035
|
+
"// its own launcher (plugins/heyspex/bin/run-hook.mjs, which never calls this file) already runs every",
|
|
3036
|
+
"// hook, so this committed row exits 0 silently before resolving anything and each hook fires ONCE.",
|
|
3037
|
+
"// HEYSPEX_REPO_HOOKS=1 never yield (the repo rows are the chosen source);",
|
|
3038
|
+
`// enabledPlugins["heyspex@..."] === false in ~/.claude/settings.json or this repo's .claude/`,
|
|
3039
|
+
"// settings[.local].json: plugin off here, the row runs;",
|
|
3040
|
+
"// plugin evidence (what `hs doctor` hook-double-fire reads): a heyspex@... key in",
|
|
3041
|
+
"// ~/.claude/plugins/installed_plugins.json, enabledPlugins naming heyspex with a non-false",
|
|
3042
|
+
"// value, or a heyspex directory under ~/.copilot/installed-plugins | ~/.copilot/plugins.",
|
|
3043
|
+
"function readJson(file) {",
|
|
3044
|
+
" try { return JSON.parse(readFileSync(file, 'utf8')); } catch { return undefined; }",
|
|
3045
|
+
"}",
|
|
3046
|
+
"function listDir(dir) {",
|
|
3047
|
+
" try { return readdirSync(dir); } catch { return []; }",
|
|
3048
|
+
"}",
|
|
3049
|
+
"function pluginTakesThisHook() {",
|
|
3050
|
+
" const flag = text(env.HEYSPEX_REPO_HOOKS);",
|
|
3051
|
+
" if (flag && flag !== '0' && flag.toLowerCase() !== 'false') return false;",
|
|
3052
|
+
" const home = homedir();",
|
|
3053
|
+
" const repo = resolve(here, '..', '..');",
|
|
3054
|
+
" const isHeyspex = (k) => /^heyspex(@|$)/i.test(k);",
|
|
3055
|
+
" let enabled = false;",
|
|
3056
|
+
" for (const f of [resolve(home, '.claude', 'settings.json'), resolve(repo, '.claude', 'settings.json'), resolve(repo, '.claude', 'settings.local.json')]) {",
|
|
3057
|
+
" const settings = readJson(f);",
|
|
3058
|
+
" const ep = settings && typeof settings === 'object' ? settings.enabledPlugins : null;",
|
|
3059
|
+
" if (!ep || typeof ep !== 'object') continue;",
|
|
3060
|
+
" for (const [k, v] of Object.entries(ep)) {",
|
|
3061
|
+
" if (!isHeyspex(k)) continue;",
|
|
3062
|
+
" if (v === false) return false;",
|
|
3063
|
+
" enabled = true;",
|
|
3064
|
+
" }",
|
|
3065
|
+
" }",
|
|
3066
|
+
" if (enabled) return true;",
|
|
3067
|
+
" const installed = readJson(resolve(home, '.claude', 'plugins', 'installed_plugins.json'));",
|
|
3068
|
+
" if (installed && typeof installed === 'object' && Object.keys(installed.plugins && typeof installed.plugins === 'object' ? installed.plugins : installed).some(isHeyspex)) return true;",
|
|
3069
|
+
" for (const sub of ['installed-plugins', 'plugins']) {",
|
|
3070
|
+
" const dir = resolve(home, '.copilot', sub);",
|
|
3071
|
+
" const names = listDir(dir);",
|
|
3072
|
+
" if (names.some((n) => /heyspex/i.test(n))) return true;",
|
|
3073
|
+
" if (names.some((n) => listDir(resolve(dir, n)).some((m) => /heyspex/i.test(m)))) return true;",
|
|
3074
|
+
" }",
|
|
3075
|
+
" return false;",
|
|
3076
|
+
"}",
|
|
3077
|
+
"// Only a HOOK EVENT yields: --mcp / --statusline / --resolve and an agent-run",
|
|
3078
|
+
"// `<script> --directive <key>` fetch are not hook events the plugin could run in",
|
|
3079
|
+
"// our place, so they always go on to the package below.",
|
|
3080
|
+
"const yieldMode = process.argv[2];",
|
|
3081
|
+
"const notAHookEvent = ['--mcp', '--statusline', '--resolve'].includes(yieldMode) || process.argv.includes('--directive');",
|
|
3082
|
+
"if (!notAHookEvent && pluginTakesThisHook()) process.exit(0);",
|
|
3083
|
+
"",
|
|
3084
|
+
""
|
|
3085
|
+
].join("\n");
|
|
2834
3086
|
function renderCustomerLauncher(surface = "claude") {
|
|
2835
3087
|
const l = CUSTOMER_LAUNCHERS[surface];
|
|
2836
|
-
return LAUNCHER_TEMPLATE.replace(
|
|
3088
|
+
return LAUNCHER_TEMPLATE.replace("__YIELD__\n", surface === "claude" ? LAUNCHER_YIELD_BLOCK : "").replace(
|
|
2837
3089
|
/__(REGISTRY|ENV|LAUNCHER|SHIM)__/g,
|
|
2838
3090
|
(_m, token) => token === "REGISTRY" ? l.registry : token === "ENV" ? l.projectDirEnv : token === "LAUNCHER" ? l.rel.join("/") : l.shim
|
|
2839
3091
|
);
|
|
@@ -2965,7 +3217,7 @@ var SCRIPT_VERBS = Object.freeze({
|
|
|
2965
3217
|
});
|
|
2966
3218
|
var PORTABLE_PACKAGE_DIR = "node_modules/heyspex";
|
|
2967
3219
|
var fsDeps = {
|
|
2968
|
-
joinPath: (...s) =>
|
|
3220
|
+
joinPath: (...s) => path4.join(...s),
|
|
2969
3221
|
readFile: (p) => {
|
|
2970
3222
|
try {
|
|
2971
3223
|
return fs.readFileSync(p, "utf8");
|
|
@@ -2984,22 +3236,22 @@ var fsDeps = {
|
|
|
2984
3236
|
function invokedDirectly(importMetaUrl, selfBasename, argv1 = process.argv[1]) {
|
|
2985
3237
|
try {
|
|
2986
3238
|
if (!argv1) return false;
|
|
2987
|
-
const self =
|
|
2988
|
-
if (
|
|
2989
|
-
return pathToFileURL(
|
|
3239
|
+
const self = fileURLToPath3(importMetaUrl);
|
|
3240
|
+
if (path4.basename(self) !== selfBasename) return false;
|
|
3241
|
+
return pathToFileURL(path4.resolve(argv1)).href === pathToFileURL(self).href;
|
|
2990
3242
|
} catch {
|
|
2991
3243
|
return false;
|
|
2992
3244
|
}
|
|
2993
3245
|
}
|
|
2994
|
-
var SELF =
|
|
3246
|
+
var SELF = fileURLToPath3(import.meta.url);
|
|
2995
3247
|
if (invokedDirectly(import.meta.url, "customer-kit.mjs")) {
|
|
2996
|
-
const platformRoot =
|
|
2997
|
-
const target =
|
|
3248
|
+
const platformRoot = path4.resolve(path4.dirname(SELF), "..", "..");
|
|
3249
|
+
const target = path4.join(platformRoot, "plugins", "heyspex", "hooks", "hooks.json");
|
|
2998
3250
|
const want = renderPluginHooksText();
|
|
2999
3251
|
const same = (fsDeps.readFile(target) ?? "").replace(/\r\n/g, "\n") === want;
|
|
3000
3252
|
if (process.argv.includes("--write-plugin-hooks")) {
|
|
3001
3253
|
if (!same) fs.writeFileSync(target, want, "utf8");
|
|
3002
|
-
console.log(`customer-kit: ${same ? "unchanged" : "wrote"} ${
|
|
3254
|
+
console.log(`customer-kit: ${same ? "unchanged" : "wrote"} ${path4.relative(platformRoot, target)}`);
|
|
3003
3255
|
} else if (process.argv.includes("--check-plugin-hooks")) {
|
|
3004
3256
|
if (!same) {
|
|
3005
3257
|
console.error("customer-kit: plugins/heyspex/hooks/hooks.json is stale \u2014 run `node scripts/lib/customer-kit.mjs --write-plugin-hooks`");
|
|
@@ -3007,15 +3259,15 @@ if (invokedDirectly(import.meta.url, "customer-kit.mjs")) {
|
|
|
3007
3259
|
}
|
|
3008
3260
|
console.log("customer-kit: plugins/heyspex/hooks/hooks.json up to date");
|
|
3009
3261
|
} else if (process.argv.includes("--write-github-hooks") || process.argv.includes("--check-github-hooks")) {
|
|
3010
|
-
const ghTarget =
|
|
3262
|
+
const ghTarget = path4.join(platformRoot, ".github", "hooks", "heyspex.json");
|
|
3011
3263
|
const ghWant = renderGithubHooksText();
|
|
3012
3264
|
const ghSame = (fsDeps.readFile(ghTarget) ?? "").replace(/\r\n/g, "\n") === ghWant;
|
|
3013
3265
|
if (process.argv.includes("--write-github-hooks")) {
|
|
3014
3266
|
if (!ghSame) {
|
|
3015
|
-
fs.mkdirSync(
|
|
3267
|
+
fs.mkdirSync(path4.dirname(ghTarget), { recursive: true });
|
|
3016
3268
|
fs.writeFileSync(ghTarget, ghWant, "utf8");
|
|
3017
3269
|
}
|
|
3018
|
-
console.log(`customer-kit: ${ghSame ? "unchanged" : "wrote"} ${
|
|
3270
|
+
console.log(`customer-kit: ${ghSame ? "unchanged" : "wrote"} ${path4.relative(platformRoot, ghTarget).replace(/\\/g, "/")}`);
|
|
3019
3271
|
} else if (!ghSame) {
|
|
3020
3272
|
console.error("customer-kit: .github/hooks/heyspex.json is stale - run `node scripts/lib/customer-kit.mjs --write-github-hooks`");
|
|
3021
3273
|
process.exit(1);
|
|
@@ -3028,9 +3280,9 @@ if (invokedDirectly(import.meta.url, "customer-kit.mjs")) {
|
|
|
3028
3280
|
}
|
|
3029
3281
|
|
|
3030
3282
|
// scripts/install-cursor-hooks.mjs
|
|
3031
|
-
var PLATFORM_ROOT =
|
|
3032
|
-
var REPO_ROOT = process.env.HS_SETUP_TARGET?.trim() ?
|
|
3033
|
-
var SETTINGS_PATH =
|
|
3283
|
+
var PLATFORM_ROOT = path5.resolve(path5.dirname(fileURLToPath4(import.meta.url)), "..");
|
|
3284
|
+
var REPO_ROOT = process.env.HS_SETUP_TARGET?.trim() ? path5.resolve(process.env.HS_SETUP_TARGET.trim()) : PLATFORM_ROOT;
|
|
3285
|
+
var SETTINGS_PATH = path5.join(REPO_ROOT, ".cursor", "hooks.json");
|
|
3034
3286
|
function cursorKitFor(targetRoot, platformRoot = PLATFORM_ROOT) {
|
|
3035
3287
|
const customer = !samePlatformPath(targetRoot, platformRoot);
|
|
3036
3288
|
return {
|
|
@@ -3042,7 +3294,7 @@ function cursorKitFor(targetRoot, platformRoot = PLATFORM_ROOT) {
|
|
|
3042
3294
|
}
|
|
3043
3295
|
var KIT = cursorKitFor(REPO_ROOT);
|
|
3044
3296
|
var ACTIVE_HOOKS = KIT.hooks;
|
|
3045
|
-
var LAUNCHER_PATH =
|
|
3297
|
+
var LAUNCHER_PATH = path5.join(REPO_ROOT, ...CUSTOMER_LAUNCHERS.cursor.rel);
|
|
3046
3298
|
var LEGACY_MARKER = "scripts/claude-hooks/";
|
|
3047
3299
|
function readSettings() {
|
|
3048
3300
|
try {
|
|
@@ -3061,7 +3313,7 @@ function readSettings() {
|
|
|
3061
3313
|
return { version: 1, hooks: {} };
|
|
3062
3314
|
}
|
|
3063
3315
|
function writeSettings(settings) {
|
|
3064
|
-
fs2.mkdirSync(
|
|
3316
|
+
fs2.mkdirSync(path5.dirname(SETTINGS_PATH), { recursive: true });
|
|
3065
3317
|
fs2.writeFileSync(SETTINGS_PATH, `${JSON.stringify(settings, null, 2)}
|
|
3066
3318
|
`, "utf8");
|
|
3067
3319
|
}
|
|
@@ -3096,7 +3348,7 @@ function sameEntry(raw, entry, render = KIT.commandFor) {
|
|
|
3096
3348
|
const want = desiredEntry(entry, render);
|
|
3097
3349
|
return commandOf(raw) === want.command && raw.timeout === want.timeout && (raw.matcher ?? void 0) === (want.matcher ?? void 0);
|
|
3098
3350
|
}
|
|
3099
|
-
var PLUGIN_HOOKS_PATH =
|
|
3351
|
+
var PLUGIN_HOOKS_PATH = path5.join(REPO_ROOT, "plugins", "heyspex", "hooks", "cursor-hooks.json");
|
|
3100
3352
|
function pluginHooksDocument() {
|
|
3101
3353
|
const hooks = {};
|
|
3102
3354
|
for (const entry of HOOKS) {
|
|
@@ -3126,7 +3378,7 @@ function syncPluginHooks() {
|
|
|
3126
3378
|
have = null;
|
|
3127
3379
|
}
|
|
3128
3380
|
if (have === want) return false;
|
|
3129
|
-
fs2.mkdirSync(
|
|
3381
|
+
fs2.mkdirSync(path5.dirname(PLUGIN_HOOKS_PATH), { recursive: true });
|
|
3130
3382
|
fs2.writeFileSync(PLUGIN_HOOKS_PATH, want, "utf8");
|
|
3131
3383
|
return true;
|
|
3132
3384
|
}
|
|
@@ -3199,7 +3451,7 @@ function install({ json = false } = {}) {
|
|
|
3199
3451
|
if (KIT.customer) {
|
|
3200
3452
|
const plan = launcherPlan();
|
|
3201
3453
|
if (plan.write) {
|
|
3202
|
-
fs2.mkdirSync(
|
|
3454
|
+
fs2.mkdirSync(path5.dirname(LAUNCHER_PATH), { recursive: true });
|
|
3203
3455
|
fs2.writeFileSync(LAUNCHER_PATH, plan.text, "utf8");
|
|
3204
3456
|
launcherWritten = true;
|
|
3205
3457
|
}
|
|
@@ -3226,10 +3478,10 @@ function install({ json = false } = {}) {
|
|
|
3226
3478
|
return;
|
|
3227
3479
|
}
|
|
3228
3480
|
if (pluginChanged) {
|
|
3229
|
-
console.log(`install-cursor-hooks: regenerated ${
|
|
3481
|
+
console.log(`install-cursor-hooks: regenerated ${path5.relative(REPO_ROOT, PLUGIN_HOOKS_PATH)}`);
|
|
3230
3482
|
}
|
|
3231
3483
|
if (launcherWritten) {
|
|
3232
|
-
console.log(`install-cursor-hooks: wrote ${
|
|
3484
|
+
console.log(`install-cursor-hooks: wrote ${path5.relative(REPO_ROOT, LAUNCHER_PATH)} (resolves node_modules/heyspex)`);
|
|
3233
3485
|
}
|
|
3234
3486
|
if (!settingsChanged) {
|
|
3235
3487
|
console.log(`install-cursor-hooks: already installed (${ACTIVE_HOOKS.length} hooks, no changes).`);
|
|
@@ -3240,7 +3492,7 @@ function install({ json = false } = {}) {
|
|
|
3240
3492
|
if (repaired.length) parts.push(`repaired ${repaired.length}`);
|
|
3241
3493
|
if (removed.length) parts.push(`removed ${removed.length}`);
|
|
3242
3494
|
console.log(
|
|
3243
|
-
`install-cursor-hooks: ${parts.join("; ")} \u2192 ${
|
|
3495
|
+
`install-cursor-hooks: ${parts.join("; ")} \u2192 ${path5.relative(REPO_ROOT, SETTINGS_PATH)} (${ACTIVE_HOOKS.length} hooks registered)`
|
|
3244
3496
|
);
|
|
3245
3497
|
for (const line of removed) console.log(` - ${line}`);
|
|
3246
3498
|
console.log(
|
|
@@ -3342,30 +3594,26 @@ if (invokedDirectly(import.meta.url, "install-cursor-hooks.mjs")) {
|
|
|
3342
3594
|
init_credentials();
|
|
3343
3595
|
|
|
3344
3596
|
// spex-console/src/lib/cli/connect-checks.ts
|
|
3345
|
-
import { dirname as
|
|
3597
|
+
import { dirname as dirname6 } from "node:path";
|
|
3346
3598
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
3347
3599
|
|
|
3348
3600
|
// spex-console/src/lib/dev-mode.ts
|
|
3349
|
-
import { mkdirSync as
|
|
3601
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "node:fs";
|
|
3350
3602
|
import { join as join10 } from "node:path";
|
|
3351
3603
|
init_credentials();
|
|
3352
3604
|
|
|
3353
3605
|
// spex-console/src/lib/cli/connect-checks.ts
|
|
3354
3606
|
init_credentials();
|
|
3355
3607
|
|
|
3356
|
-
// spex-console/src/lib/cli/satellite.ts
|
|
3357
|
-
import { resolve as resolveNodePath } from "node:path";
|
|
3358
|
-
import process2 from "node:process";
|
|
3359
|
-
|
|
3360
3608
|
// spex-console/src/lib/cli/principle-selection.ts
|
|
3361
|
-
import { basename as
|
|
3609
|
+
import { basename as basename4 } from "node:path";
|
|
3362
3610
|
var PRINCIPLES_INDEX_DEST = "specs/principles-index.md";
|
|
3363
3611
|
function principleKey(row) {
|
|
3364
|
-
const base =
|
|
3612
|
+
const base = basename4(row.dest, ".md");
|
|
3365
3613
|
return base.startsWith("principle-") ? base.slice("principle-".length) : base;
|
|
3366
3614
|
}
|
|
3367
3615
|
function principleWikilink(row) {
|
|
3368
|
-
return
|
|
3616
|
+
return basename4(row.dest, ".md");
|
|
3369
3617
|
}
|
|
3370
3618
|
function parsePrinciplesFlag(value, rows) {
|
|
3371
3619
|
const principleRows = rows.filter((row) => row.group === "principle");
|
|
@@ -3441,24 +3689,28 @@ var ALL_FIELDS = [
|
|
|
3441
3689
|
];
|
|
3442
3690
|
|
|
3443
3691
|
// spex-console/src/lib/cli/vault-workspace-shared.ts
|
|
3444
|
-
import { readFileSync as
|
|
3692
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
3445
3693
|
|
|
3446
3694
|
// spex-console/src/lib/indexer/parser.ts
|
|
3447
3695
|
var import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
3448
3696
|
import { createHash as createHash2 } from "node:crypto";
|
|
3449
3697
|
import { promises as fs3 } from "node:fs";
|
|
3450
|
-
import
|
|
3698
|
+
import path6 from "node:path";
|
|
3451
3699
|
|
|
3452
3700
|
// spex-console/src/lib/cli/install.ts
|
|
3453
3701
|
var MCP_REL = ["vendor", "heyspex-mcp", "cli.mjs"];
|
|
3454
3702
|
var PORTABLE_MCP_CLI = Object.freeze({
|
|
3703
|
+
claude: `\${CLAUDE_PROJECT_DIR:-.}/${CUSTOMER_LAUNCHERS.claude.rel.join("/")}`,
|
|
3704
|
+
cursor: `\${workspaceFolder}/${CUSTOMER_LAUNCHERS.cursor.rel.join("/")}`
|
|
3705
|
+
});
|
|
3706
|
+
var LEGACY_PORTABLE_MCP_CLI = Object.freeze({
|
|
3455
3707
|
claude: `\${CLAUDE_PROJECT_DIR:-.}/${PORTABLE_PACKAGE_DIR}/${MCP_REL.join("/")}`,
|
|
3456
3708
|
cursor: `\${workspaceFolder}/${PORTABLE_PACKAGE_DIR}/${MCP_REL.join("/")}`
|
|
3457
3709
|
});
|
|
3458
3710
|
function resolveCallerPath(p, env, fallbackCwd) {
|
|
3459
3711
|
const trimmed = p?.trim() ?? "";
|
|
3460
3712
|
if (!trimmed) return "";
|
|
3461
|
-
if (
|
|
3713
|
+
if (isAbsolute4(trimmed)) return trimmed;
|
|
3462
3714
|
const base = env.HS_INVOKED_CWD?.trim() || fallbackCwd;
|
|
3463
3715
|
return resolveNodePath2(base, trimmed);
|
|
3464
3716
|
}
|
|
@@ -3473,7 +3725,6 @@ var WRITE_TARGET_KIND = {
|
|
|
3473
3725
|
claudeMcp: "claude_mcp",
|
|
3474
3726
|
claudeMd: "claude_md",
|
|
3475
3727
|
agentsMd: "agents_md",
|
|
3476
|
-
statuslineVendor: "statusline_vendor",
|
|
3477
3728
|
gitignore: "gitignore",
|
|
3478
3729
|
claudeMdTemplate: "claude_md_template",
|
|
3479
3730
|
agentsMdTemplate: "agents_md_template"
|
|
@@ -3530,12 +3781,6 @@ var INSTALL_WRITE_TARGETS = [
|
|
|
3530
3781
|
path: (targetDir, joinPath) => joinPath(targetDir, "AGENTS.md.template"),
|
|
3531
3782
|
appliesTo: (args, opts) => Boolean(args.registerVault) && !opts.attached && opts.installContract
|
|
3532
3783
|
},
|
|
3533
|
-
{
|
|
3534
|
-
kind: WRITE_TARGET_KIND.statuslineVendor,
|
|
3535
|
-
rel: "scripts/claude-statusline",
|
|
3536
|
-
path: (targetDir, joinPath) => joinPath(targetDir, "scripts", "claude-statusline"),
|
|
3537
|
-
appliesTo: (args) => (args.statusline ?? true) && args.claude
|
|
3538
|
-
},
|
|
3539
3784
|
{
|
|
3540
3785
|
kind: WRITE_TARGET_KIND.gitignore,
|
|
3541
3786
|
rel: ".gitignore",
|
|
@@ -3696,13 +3941,13 @@ function runEntry(name, main2, options2 = {}) {
|
|
|
3696
3941
|
|
|
3697
3942
|
// spex-console/bin/hs-init.ts
|
|
3698
3943
|
var INTERACTIVE = process4.stdin.isTTY === true;
|
|
3699
|
-
var PKG_ROOT =
|
|
3700
|
-
resolveCodeRoot({ packageRoot:
|
|
3944
|
+
var PKG_ROOT = resolve6(
|
|
3945
|
+
resolveCodeRoot({ packageRoot: resolve6(dirname7(fileURLToPath5(import.meta.url)), "..", "..") })
|
|
3701
3946
|
);
|
|
3702
3947
|
var CONFIG_SEED_PATH = join11(PKG_ROOT, "vendor", "heyspex-mcp", "config-seed.yaml");
|
|
3703
3948
|
function readConfigSeed() {
|
|
3704
3949
|
try {
|
|
3705
|
-
return
|
|
3950
|
+
return readFileSync14(CONFIG_SEED_PATH, "utf8");
|
|
3706
3951
|
} catch {
|
|
3707
3952
|
process4.stderr.write(
|
|
3708
3953
|
`hs init: warning \u2014 config seed template not found at ${CONFIG_SEED_PATH}; .heyspex/config.yaml was not seeded (run \`hs settings set <key> <value>\` to create it).
|
|
@@ -3736,7 +3981,7 @@ async function resolvePrincipleSelection(principlesFlag) {
|
|
|
3736
3981
|
return parsePrinciplesFlag(void 0, TEMPLATE_MANIFEST);
|
|
3737
3982
|
}
|
|
3738
3983
|
async function main() {
|
|
3739
|
-
const repoRoot = process4.env.HS_VAULT_ROOT ?
|
|
3984
|
+
const repoRoot = process4.env.HS_VAULT_ROOT ? resolve6(process4.env.HS_VAULT_ROOT) : process4.cwd();
|
|
3740
3985
|
const parsed = parseInitArgs(process4.argv.slice(3));
|
|
3741
3986
|
if (parsed.help) {
|
|
3742
3987
|
process4.stdout.write(`${HELP}
|
|
@@ -3752,28 +3997,29 @@ async function main() {
|
|
|
3752
3997
|
}
|
|
3753
3998
|
const args = parsed.args;
|
|
3754
3999
|
if (args.customerVaultDir) {
|
|
3755
|
-
const here =
|
|
3756
|
-
const platformRoot =
|
|
3757
|
-
const targetDir =
|
|
4000
|
+
const here = dirname7(fileURLToPath5(import.meta.url));
|
|
4001
|
+
const platformRoot = resolve6(here, "..", "..");
|
|
4002
|
+
const targetDir = resolve6(resolveCallerPath(args.customerVaultDir, process4.env, process4.cwd()));
|
|
4003
|
+
const eol = createGeneratedFileEol({ repoRoot: targetDir });
|
|
3758
4004
|
const deps = {
|
|
3759
4005
|
platformRoot,
|
|
3760
|
-
exists: (p) =>
|
|
4006
|
+
exists: (p) => existsSync8(p),
|
|
3761
4007
|
readdir: (p) => readdirSync2(p),
|
|
3762
4008
|
mkdirRecursive: (p) => {
|
|
3763
|
-
|
|
4009
|
+
mkdirSync7(p, { recursive: true });
|
|
3764
4010
|
},
|
|
3765
|
-
writeFile: (p, c) =>
|
|
3766
|
-
copyFile: (src, dest) =>
|
|
4011
|
+
writeFile: (p, c) => writeFileSync7(p, eol.convert(p, c), "utf8"),
|
|
4012
|
+
copyFile: (src, dest) => copyFileSync2(src, dest),
|
|
3767
4013
|
joinPath: (...s) => join11(...s),
|
|
3768
4014
|
readConfigSeed,
|
|
3769
4015
|
readFile: (p) => {
|
|
3770
4016
|
try {
|
|
3771
|
-
return
|
|
4017
|
+
return readFileSync14(p, "utf8");
|
|
3772
4018
|
} catch {
|
|
3773
4019
|
return null;
|
|
3774
4020
|
}
|
|
3775
4021
|
},
|
|
3776
|
-
isDirectory: (p) =>
|
|
4022
|
+
isDirectory: (p) => statSync5(p).isDirectory()
|
|
3777
4023
|
};
|
|
3778
4024
|
const principlesResult = await resolvePrincipleSelection(args.principles);
|
|
3779
4025
|
if (!principlesResult.ok) {
|
|
@@ -3811,20 +4057,21 @@ async function main() {
|
|
|
3811
4057
|
process4.exitCode = result2.code;
|
|
3812
4058
|
return;
|
|
3813
4059
|
}
|
|
4060
|
+
const repoEol = createGeneratedFileEol({ repoRoot });
|
|
3814
4061
|
const result = runInit(args, {
|
|
3815
4062
|
repoRoot,
|
|
3816
|
-
fileExists: (p) =>
|
|
4063
|
+
fileExists: (p) => existsSync8(p),
|
|
3817
4064
|
readFile: (p) => {
|
|
3818
4065
|
try {
|
|
3819
|
-
return
|
|
4066
|
+
return readFileSync14(p, "utf8");
|
|
3820
4067
|
} catch {
|
|
3821
4068
|
return null;
|
|
3822
4069
|
}
|
|
3823
4070
|
},
|
|
3824
|
-
writeFile: (p, c) =>
|
|
4071
|
+
writeFile: (p, c) => writeFileSync7(p, repoEol.convert(p, c), "utf8"),
|
|
3825
4072
|
joinPath: (...s) => join11(...s),
|
|
3826
4073
|
mkdirRecursive: (p) => {
|
|
3827
|
-
|
|
4074
|
+
mkdirSync7(p, { recursive: true });
|
|
3828
4075
|
},
|
|
3829
4076
|
readConfigSeed
|
|
3830
4077
|
});
|