heyspex 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/bin/hs-vault-binding.mjs +157 -0
- package/bin/hs.mjs +99 -81
- package/bin/spexcode.mjs +91 -0
- package/dev-factory/engine/worktree.mjs +36 -7
- package/dev-factory/lib/epic-detect.mjs +2 -2
- package/dev-factory/lib/fleet-readiness.mjs +3 -5
- package/dev-factory/lib/fleet-state.mjs +2 -2
- package/dev-factory/lib/sufficiency-score.mjs +3 -5
- package/dist/cli/hs-check.mjs +76 -46
- package/dist/cli/hs-claim.mjs +63 -33
- package/dist/cli/hs-connect.mjs +520 -214
- package/dist/cli/hs-defer.mjs +161 -19
- package/dist/cli/hs-dev.mjs +11 -5
- package/dist/cli/hs-env.mjs +187 -161
- package/dist/cli/hs-index-rebuild.mjs +123 -78
- package/dist/cli/hs-index-reconcile.mjs +203 -107
- package/dist/cli/hs-init.mjs +426 -179
- package/dist/cli/hs-install.mjs +759 -437
- package/dist/cli/hs-join.mjs +590 -383
- package/dist/cli/hs-vault-pull.mjs +359 -254
- package/dist/cli/hs-vault-push.mjs +151 -113
- package/dist/cli/hs-vault.mjs +271 -104
- package/dist/cli/hs-workspace.mjs +90 -57
- package/dist/cli-templates/customer-vault/specs/protocols/session-close-protocol.md +178 -91
- package/docs/copilot-plugin-install.md +189 -162
- package/docs/driving-heyspex-from-copilot.md +174 -165
- package/docs/mcp-client-config.md +93 -25
- package/package.json +255 -249
- package/plugins/heyspex/.mcp.json +3 -4
- package/plugins/heyspex/README.md +323 -309
- package/plugins/heyspex/bin/launch-mcp.mjs +21 -7
- package/plugins/heyspex/mcp.json +12 -13
- package/scripts/check-mcp-freshness.mjs +6 -4
- package/scripts/claude-hooks/_intent-classifier-router.mjs +518 -456
- package/scripts/claude-hooks/intent-classifier-trigger.mjs +305 -279
- package/scripts/claude-hooks/research-method-guard.mjs +2 -2
- package/scripts/claude-hooks/wip-checkpoint.mjs +33 -9
- package/scripts/claude-statusline/fonts/HeySpexIcons.ttf +0 -0
- package/scripts/claude-statusline/statusline-command.mjs +1058 -0
- package/scripts/dev-server-status.mjs +3 -2
- package/scripts/dev-server-stop.mjs +3 -2
- package/scripts/hs-capture-cli.mjs +2 -2
- package/scripts/hs-settings.mjs +2 -2
- package/scripts/hs-view.mjs +3 -2
- package/scripts/install-copilot-hooks.mjs +318 -0
- package/scripts/lib/copilot-cli.mjs +108 -0
- package/scripts/lib/customer-kit.mjs +223 -30
- package/scripts/lib/dev-mode.mjs +28 -2
- package/scripts/lib/shared-path-helpers.mjs +32 -0
- package/scripts/lib/standalone-doctor.mjs +131 -32
- package/scripts/wip-ledger-health.mjs +3 -2
- package/spexharness/src/gates/vault-mirror-catchup.mjs +113 -24
- package/spexharness/src/gates/vault-mirror-catchup.runner.mjs +52 -0
- package/spexharness/src/intent-directive.mjs +839 -626
- package/spexharness/src/rule-table.mjs +1 -1
- package/vendor/heyspex-mcp/cli-verbs.mjs +16 -2
- package/vendor/heyspex-mcp/cli.mjs +20 -4
- package/vendor/heyspex-mcp/console-fetch.mjs +15 -3
- package/vendor/heyspex-mcp/dev-tools.mjs +11 -4
- package/vendor/heyspex-mcp/events-tools.mjs +1 -1
- package/vendor/heyspex-mcp/factory-run-status.mjs +42 -0
- package/vendor/heyspex-mcp/mcp-config.mjs +4 -2
- package/vendor/heyspex-mcp/spec-edit-tools.mjs +26 -1
- package/vendor/heyspex-mcp/test-helpers.mjs +5 -2
- package/vendor/heyspex-mcp/tool-catalog.mjs +12 -0
- package/vendor/heyspex-mcp/tool-dispatch.mjs +59 -23
- package/vendor/heyspex-mcp/usable-dir-env.mjs +82 -0
- package/vendor/heyspex-mcp/vault-binding.mjs +839 -0
- package/vendor/heyspex-mcp/vault-resolve.mjs +353 -245
package/dist/cli/hs-claim.mjs
CHANGED
|
@@ -124,9 +124,9 @@ function resolveBearer({ envToken, credentialsText, accountId, legacyAccountId }
|
|
|
124
124
|
if (entry?.mcp_token) return { token: entry.mcp_token, source: "credentials-file" };
|
|
125
125
|
return { token: null, source: null };
|
|
126
126
|
}
|
|
127
|
-
function readTextOrNull(read,
|
|
127
|
+
function readTextOrNull(read, path3) {
|
|
128
128
|
try {
|
|
129
|
-
const raw = read(
|
|
129
|
+
const raw = read(path3);
|
|
130
130
|
return typeof raw === "string" ? raw : null;
|
|
131
131
|
} catch {
|
|
132
132
|
return null;
|
|
@@ -169,8 +169,8 @@ var init_credentials = __esm({
|
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
// scripts/lib/dev-mode.mjs
|
|
172
|
-
import { mkdirSync as
|
|
173
|
-
import { homedir as
|
|
172
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
173
|
+
import { homedir as homedir8 } from "node:os";
|
|
174
174
|
import { join as join8 } from "node:path";
|
|
175
175
|
function devModeFilePath(homeDir = heyspexHome()) {
|
|
176
176
|
return join8(homeDir, ".heyspex", DEV_MODE_FILENAME);
|
|
@@ -225,6 +225,11 @@ function readLocalDevModeRecord({ homeDir = heyspexHome(), readFile = defaultRea
|
|
|
225
225
|
return { record: null, parseError: `unparseable dev-mode.json: ${String(err?.message ?? err)}` };
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
|
+
function overrideCloudCheck(source, cloudKnown, staleAgainstCloud) {
|
|
229
|
+
if (source !== "local-override") return "not-applicable";
|
|
230
|
+
if (!cloudKnown) return "unverified";
|
|
231
|
+
return staleAgainstCloud ? "stale" : "in-sync";
|
|
232
|
+
}
|
|
228
233
|
function resolveDevMode({
|
|
229
234
|
env = process.env,
|
|
230
235
|
homeDir = heyspexHome(),
|
|
@@ -264,6 +269,7 @@ function resolveDevMode({
|
|
|
264
269
|
const semantics = deriveSemantics(mode, reliance);
|
|
265
270
|
const consoleUrl = source === "local-override" && local.record?.console_url ? local.record.console_url.replace(/\/+$/, "") : semantics.consoleUrl;
|
|
266
271
|
const staleAgainstCloud = source === "local-override" && cloudValue !== null && (cloudValue.mode !== mode || mode === "dev" && cloudValue.reliance !== semantics.reliance);
|
|
272
|
+
const cloudCheck = overrideCloudCheck(source, cloudKnown, staleAgainstCloud);
|
|
267
273
|
return {
|
|
268
274
|
mode,
|
|
269
275
|
reliance: semantics.reliance,
|
|
@@ -281,7 +287,8 @@ function resolveDevMode({
|
|
|
281
287
|
present: local.record !== null,
|
|
282
288
|
record: local.record,
|
|
283
289
|
parseError: local.parseError,
|
|
284
|
-
staleAgainstCloud
|
|
290
|
+
staleAgainstCloud,
|
|
291
|
+
cloudCheck
|
|
285
292
|
},
|
|
286
293
|
cloudSetting: { known: cloudKnown, value: cloudValue }
|
|
287
294
|
};
|
|
@@ -295,12 +302,12 @@ var init_dev_mode = __esm({
|
|
|
295
302
|
CLOUD_CONSOLE_URL = "https://app.heyspex.com";
|
|
296
303
|
LOCAL_CONSOLE_URL = "http://localhost:3000";
|
|
297
304
|
DEV_MODE_FILENAME = "dev-mode.json";
|
|
298
|
-
defaultReadFile = (p) =>
|
|
305
|
+
defaultReadFile = (p) => readFileSync8(p, "utf8");
|
|
299
306
|
}
|
|
300
307
|
});
|
|
301
308
|
|
|
302
309
|
// spex-console/bin/hs-claim.ts
|
|
303
|
-
import { readFileSync as
|
|
310
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
304
311
|
import process3 from "node:process";
|
|
305
312
|
|
|
306
313
|
// spex-console/src/lib/work-stages.ts
|
|
@@ -344,7 +351,7 @@ function resolveAgentIdentity(argAgent, argSession) {
|
|
|
344
351
|
}
|
|
345
352
|
|
|
346
353
|
// spex-console/src/lib/cli/control-shared.ts
|
|
347
|
-
import
|
|
354
|
+
import path2 from "node:path";
|
|
348
355
|
|
|
349
356
|
// scripts/lib/hs-command.mjs
|
|
350
357
|
import { existsSync } from "node:fs";
|
|
@@ -434,8 +441,8 @@ function hsCommand(args = "", options = {}) {
|
|
|
434
441
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
435
442
|
init_heyspex_home();
|
|
436
443
|
init_credentials();
|
|
437
|
-
import { readFileSync as
|
|
438
|
-
import { homedir as
|
|
444
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
445
|
+
import { homedir as homedir6 } from "node:os";
|
|
439
446
|
import { join as join6 } from "node:path";
|
|
440
447
|
|
|
441
448
|
// vendor/heyspex-mcp/session-owner.mjs
|
|
@@ -460,14 +467,14 @@ var VAULT_LESS_ENDPOINTS = Object.freeze([
|
|
|
460
467
|
"GET /api/workspaces",
|
|
461
468
|
"* /api/admin/dev-mode"
|
|
462
469
|
]);
|
|
463
|
-
function pathnameOf(
|
|
464
|
-
const raw = String(
|
|
470
|
+
function pathnameOf(path3) {
|
|
471
|
+
const raw = String(path3 ?? "").split("?")[0].split("#")[0];
|
|
465
472
|
const noTrailing = raw.length > 1 ? raw.replace(/\/+$/, "") : raw;
|
|
466
473
|
return noTrailing || "/";
|
|
467
474
|
}
|
|
468
|
-
function isVaultLessEndpoint(method,
|
|
475
|
+
function isVaultLessEndpoint(method, path3) {
|
|
469
476
|
const m = String(method || "GET").toUpperCase();
|
|
470
|
-
const pathname = pathnameOf(
|
|
477
|
+
const pathname = pathnameOf(path3);
|
|
471
478
|
return VAULT_LESS_ENDPOINTS.some((row) => {
|
|
472
479
|
const [rowMethod, rowPath] = row.split(" ");
|
|
473
480
|
return rowPath === pathname && (rowMethod === "*" || rowMethod === m);
|
|
@@ -487,13 +494,36 @@ import {
|
|
|
487
494
|
import { basename, join as join4, isAbsolute as isAbsolute2 } from "node:path";
|
|
488
495
|
|
|
489
496
|
// scripts/lib/shared-path-helpers.mjs
|
|
497
|
+
import { realpathSync } from "node:fs";
|
|
490
498
|
import { isAbsolute, resolve as resolve2, sep } from "node:path";
|
|
499
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
491
500
|
|
|
492
501
|
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
493
502
|
init_heyspex_home();
|
|
494
|
-
import { existsSync as
|
|
495
|
-
import { homedir as
|
|
496
|
-
|
|
503
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
|
|
504
|
+
import { homedir as homedir5, tmpdir } from "node:os";
|
|
505
|
+
|
|
506
|
+
// vendor/heyspex-mcp/usable-dir-env.mjs
|
|
507
|
+
import { statSync } from "node:fs";
|
|
508
|
+
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
509
|
+
|
|
510
|
+
// vendor/heyspex-mcp/vault-resolve.mjs
|
|
511
|
+
import { basename as basename2, dirname as dirname3, join as join5, resolve as resolve3 } from "node:path";
|
|
512
|
+
|
|
513
|
+
// vendor/heyspex-mcp/vault-binding.mjs
|
|
514
|
+
import {
|
|
515
|
+
copyFileSync,
|
|
516
|
+
existsSync as existsSync3,
|
|
517
|
+
mkdirSync as mkdirSync3,
|
|
518
|
+
readFileSync as readFileSync4,
|
|
519
|
+
realpathSync as realpathSync2,
|
|
520
|
+
renameSync as renameSync3,
|
|
521
|
+
statSync as statSync2,
|
|
522
|
+
unlinkSync,
|
|
523
|
+
writeFileSync as writeFileSync3
|
|
524
|
+
} from "node:fs";
|
|
525
|
+
import { homedir as homedir4 } from "node:os";
|
|
526
|
+
import path from "node:path";
|
|
497
527
|
|
|
498
528
|
// vendor/heyspex-mcp/console-fetch.mjs
|
|
499
529
|
var VAULT_NOT_REGISTERED = "VAULT_NOT_REGISTERED";
|
|
@@ -525,7 +555,7 @@ function isCloudVaultId(value) {
|
|
|
525
555
|
var MARKER_VAULT_ID_RE = /^vault_id:[ \t]*["']?([^"'\r\n#]+)/m;
|
|
526
556
|
function readMarkerVaultId(repoRootAbs, { readFile } = {}) {
|
|
527
557
|
if (typeof repoRootAbs !== "string" || !repoRootAbs.trim()) return null;
|
|
528
|
-
const read = readFile ?? ((p) =>
|
|
558
|
+
const read = readFile ?? ((p) => readFileSync6(p, "utf8"));
|
|
529
559
|
try {
|
|
530
560
|
const raw = read(join6(repoRootAbs, "heyspex.yaml"));
|
|
531
561
|
const value = String(raw ?? "").match(MARKER_VAULT_ID_RE)?.[1]?.trim() ?? "";
|
|
@@ -547,17 +577,17 @@ var SCOPE_REFUSAL_CODES = Object.freeze(["VAULT_SCOPE_MISMATCH", "ACCOUNT_MISMAT
|
|
|
547
577
|
init_credentials();
|
|
548
578
|
|
|
549
579
|
// spex-console/src/lib/vault-registry/registry-file.ts
|
|
550
|
-
import { existsSync as
|
|
580
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync4, writeFileSync as writeFileSync4 } from "node:fs";
|
|
551
581
|
import { dirname as dirname4, join as join7, resolve as resolve4 } from "node:path";
|
|
552
582
|
|
|
553
583
|
// spex-console/src/lib/heyspex-home.ts
|
|
554
|
-
import { homedir as
|
|
584
|
+
import { homedir as homedir7 } from "node:os";
|
|
555
585
|
function heyspexHome2(env = process.env) {
|
|
556
586
|
const override = env?.HEYSPEX_HOME;
|
|
557
587
|
if (typeof override === "string" && override.trim().length > 0) {
|
|
558
588
|
return override.trim();
|
|
559
589
|
}
|
|
560
|
-
return
|
|
590
|
+
return homedir7();
|
|
561
591
|
}
|
|
562
592
|
|
|
563
593
|
// spex-console/src/lib/vault-registry/types.ts
|
|
@@ -679,9 +709,9 @@ function parseVaultRegistryFile(json) {
|
|
|
679
709
|
}
|
|
680
710
|
function readRegistryJson(opts) {
|
|
681
711
|
const filePath = vaultRegistryFilePath(opts);
|
|
682
|
-
if (!
|
|
712
|
+
if (!existsSync5(filePath)) return { kind: "missing" };
|
|
683
713
|
try {
|
|
684
|
-
const raw =
|
|
714
|
+
const raw = readFileSync7(filePath, "utf8");
|
|
685
715
|
const json = JSON.parse(raw);
|
|
686
716
|
if (registryFileSchemaOf(json) === null) return { kind: "unreadable" };
|
|
687
717
|
return { kind: "ok", raw, json };
|
|
@@ -816,11 +846,11 @@ function bearerHeaderFor(consoleUrl, opts = {}) {
|
|
|
816
846
|
return {};
|
|
817
847
|
}
|
|
818
848
|
}
|
|
819
|
-
function scopeHeadersFor(scope, method,
|
|
849
|
+
function scopeHeadersFor(scope, method, path3) {
|
|
820
850
|
if (scope === "none") {
|
|
821
|
-
if (!isVaultLessEndpoint(method,
|
|
851
|
+
if (!isVaultLessEndpoint(method, path3)) {
|
|
822
852
|
throw new Error(
|
|
823
|
-
`controlRequest: scope "none" is only allowed for the vault-less endpoints (${VAULT_LESS_ENDPOINTS.join(", ")}); ${method.toUpperCase()} ${
|
|
853
|
+
`controlRequest: scope "none" is only allowed for the vault-less endpoints (${VAULT_LESS_ENDPOINTS.join(", ")}); ${method.toUpperCase()} ${path3} is vault-scoped and must name { accountId, vaultId }.`
|
|
824
854
|
);
|
|
825
855
|
}
|
|
826
856
|
return {};
|
|
@@ -914,7 +944,7 @@ function parseTtl(token) {
|
|
|
914
944
|
return { value: n };
|
|
915
945
|
}
|
|
916
946
|
function normalizeRoot(p) {
|
|
917
|
-
return
|
|
947
|
+
return path2.resolve(p).replace(/[\\/]+/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
918
948
|
}
|
|
919
949
|
function resolveControlScope(input) {
|
|
920
950
|
const target = normalizeRoot(input.vaultRoot);
|
|
@@ -1184,8 +1214,8 @@ ${lines}`,
|
|
|
1184
1214
|
return writeFailed(res2.status, res2.body);
|
|
1185
1215
|
}
|
|
1186
1216
|
const releaser = resolveAgentIdentity(args.agent, args.session).agent;
|
|
1187
|
-
const
|
|
1188
|
-
const res = await controlRequest(deps, { method: "DELETE", path:
|
|
1217
|
+
const path3 = `/api/control/active-claims/${encodeURIComponent(args.specId)}?agent=${encodeURIComponent(releaser)}`;
|
|
1218
|
+
const res = await controlRequest(deps, { method: "DELETE", path: path3 });
|
|
1189
1219
|
if (!res.ok) return res.error;
|
|
1190
1220
|
if (res.status === 200) {
|
|
1191
1221
|
return {
|
|
@@ -1245,8 +1275,8 @@ var HELP = [
|
|
|
1245
1275
|
// scripts/lib/console-url-resolver.mjs
|
|
1246
1276
|
init_heyspex_home();
|
|
1247
1277
|
init_dev_mode();
|
|
1248
|
-
import { readFileSync as
|
|
1249
|
-
import { homedir as
|
|
1278
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
1279
|
+
import { homedir as homedir9 } from "node:os";
|
|
1250
1280
|
import { join as join9 } from "node:path";
|
|
1251
1281
|
var DEFAULT_CONSOLE_URL = LOCAL_CONSOLE_URL;
|
|
1252
1282
|
function trimTrailingSlash(url) {
|
|
@@ -1284,7 +1314,7 @@ function readCredentialsConsoleUrl({ homeDir = heyspexHome(), readFile = default
|
|
|
1284
1314
|
}
|
|
1285
1315
|
}
|
|
1286
1316
|
function defaultReadFile2(p) {
|
|
1287
|
-
return
|
|
1317
|
+
return readFileSync9(p, "utf8");
|
|
1288
1318
|
}
|
|
1289
1319
|
function readDiscoveryFileConsoleUrl(repoRoot, { readDiscovery: readDiscovery2 = defaultReadFile2 } = {}) {
|
|
1290
1320
|
if (!repoRoot) return null;
|
|
@@ -1411,7 +1441,7 @@ function runEntry(name, main2, options = {}) {
|
|
|
1411
1441
|
// spex-console/bin/hs-claim.ts
|
|
1412
1442
|
function readDiscovery(p) {
|
|
1413
1443
|
try {
|
|
1414
|
-
return
|
|
1444
|
+
return readFileSync10(p, "utf-8");
|
|
1415
1445
|
} catch {
|
|
1416
1446
|
return null;
|
|
1417
1447
|
}
|