@askexenow/exe-os 0.9.62 → 0.9.63
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/dist/bin/cli.js +195 -8
- package/dist/bin/exe-doctor.js +2645 -1211
- package/dist/bin/exe-new-employee.js +111 -1
- package/dist/bin/exe-start-codex.js +111 -1
- package/dist/bin/exe-start-opencode.js +125 -1
- package/dist/bin/install.js +111 -1
- package/dist/bin/stack-update.js +84 -7
- package/dist/hooks/bug-report-worker.js +111 -42
- package/dist/hooks/pre-compact.js +236 -109
- package/dist/hooks/session-end.js +137 -122
- package/dist/hooks/summary-worker.js +124 -72
- package/dist/lib/exe-daemon.js +356 -5
- package/dist/mcp/server.js +372 -5
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -820,7 +820,7 @@ function isLegacySplitPostToolCommand(command) {
|
|
|
820
820
|
function textHasLegacySplitPostToolHook(text) {
|
|
821
821
|
return [EXE_HOOK_FILES.ingest, EXE_HOOK_FILES.errorRecall, EXE_HOOK_FILES.ingestWorker].some((file) => text.includes(file));
|
|
822
822
|
}
|
|
823
|
-
var EXE_HOOK_FILES, EXE_HOOKS, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS;
|
|
823
|
+
var EXE_HOOK_FILES, EXE_HOOKS, EXE_HOOK_MANIFEST, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS;
|
|
824
824
|
var init_runtime_hook_manifest = __esm({
|
|
825
825
|
"src/adapters/runtime-hook-manifest.ts"() {
|
|
826
826
|
"use strict";
|
|
@@ -844,6 +844,116 @@ var init_runtime_hook_manifest = __esm({
|
|
|
844
844
|
notification: "dist/hooks/notification.js",
|
|
845
845
|
instructionsLoaded: "dist/hooks/instructions-loaded.js"
|
|
846
846
|
};
|
|
847
|
+
EXE_HOOK_MANIFEST = [
|
|
848
|
+
{
|
|
849
|
+
key: "postToolCombined",
|
|
850
|
+
event: "PostToolUse",
|
|
851
|
+
commandMarker: EXE_HOOKS.postToolCombined,
|
|
852
|
+
owner: "exe-os",
|
|
853
|
+
purpose: "Single PostToolUse entrypoint for ingestion, error recall, summaries, and bug detection.",
|
|
854
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
855
|
+
checkpointRole: "none"
|
|
856
|
+
},
|
|
857
|
+
{
|
|
858
|
+
key: "sessionStart",
|
|
859
|
+
event: "SessionStart",
|
|
860
|
+
commandMarker: EXE_HOOKS.sessionStart,
|
|
861
|
+
owner: "exe-os",
|
|
862
|
+
purpose: "Loads agent identity, procedures, and boot context.",
|
|
863
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
864
|
+
checkpointRole: "none"
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
key: "promptSubmit",
|
|
868
|
+
event: "UserPromptSubmit",
|
|
869
|
+
commandMarker: EXE_HOOKS.promptSubmit,
|
|
870
|
+
owner: "exe-os",
|
|
871
|
+
purpose: "Injects current tasks, pending reviews, and local context before each prompt.",
|
|
872
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
873
|
+
checkpointRole: "none"
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
key: "heartbeat",
|
|
877
|
+
event: "UserPromptSubmit",
|
|
878
|
+
commandMarker: EXE_HOOKS.heartbeat,
|
|
879
|
+
owner: "exe-os",
|
|
880
|
+
purpose: "Lightweight heartbeat/status sidecar for Claude Code sessions.",
|
|
881
|
+
runtimes: ["claude"],
|
|
882
|
+
checkpointRole: "none"
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
key: "stop",
|
|
886
|
+
event: "Stop",
|
|
887
|
+
commandMarker: EXE_HOOKS.stop,
|
|
888
|
+
owner: "exe-os",
|
|
889
|
+
purpose: "Finalizes task state, capacity signals, and emergency checkpointing.",
|
|
890
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
891
|
+
checkpointRole: "capacity_checkpoint"
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
key: "preToolUse",
|
|
895
|
+
event: "PreToolUse",
|
|
896
|
+
commandMarker: EXE_HOOKS.preToolUse,
|
|
897
|
+
owner: "exe-os",
|
|
898
|
+
purpose: "Preflight guardrails before shell/tool execution.",
|
|
899
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
900
|
+
checkpointRole: "none"
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
key: "subagentStop",
|
|
904
|
+
event: "SubagentStop",
|
|
905
|
+
commandMarker: EXE_HOOKS.subagentStop,
|
|
906
|
+
owner: "exe-os",
|
|
907
|
+
purpose: "Captures subagent completion context.",
|
|
908
|
+
runtimes: ["claude"],
|
|
909
|
+
checkpointRole: "none"
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
key: "preCompact",
|
|
913
|
+
event: "PreCompact",
|
|
914
|
+
commandMarker: EXE_HOOKS.preCompact,
|
|
915
|
+
owner: "exe-os",
|
|
916
|
+
purpose: "Writes active-task snapshot and compaction recovery context.",
|
|
917
|
+
runtimes: ["claude"],
|
|
918
|
+
checkpointRole: "recovery_context"
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
key: "postCompact",
|
|
922
|
+
event: "PostCompact",
|
|
923
|
+
commandMarker: EXE_HOOKS.postCompact,
|
|
924
|
+
owner: "exe-os",
|
|
925
|
+
purpose: "Rehydrates recovery context after compaction.",
|
|
926
|
+
runtimes: ["claude"],
|
|
927
|
+
checkpointRole: "recovery_context"
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
key: "sessionEnd",
|
|
931
|
+
event: "SessionEnd",
|
|
932
|
+
commandMarker: EXE_HOOKS.sessionEnd,
|
|
933
|
+
owner: "exe-os",
|
|
934
|
+
purpose: "Stores session-end checkpoint and triages orphaned in-progress tasks.",
|
|
935
|
+
runtimes: ["claude"],
|
|
936
|
+
checkpointRole: "session_summary"
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
key: "notification",
|
|
940
|
+
event: "Notification",
|
|
941
|
+
commandMarker: EXE_HOOKS.notification,
|
|
942
|
+
owner: "exe-os",
|
|
943
|
+
purpose: "Captures runtime notifications and nudges.",
|
|
944
|
+
runtimes: ["claude"],
|
|
945
|
+
checkpointRole: "none"
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
key: "instructionsLoaded",
|
|
949
|
+
event: "InstructionsLoaded",
|
|
950
|
+
commandMarker: EXE_HOOKS.instructionsLoaded,
|
|
951
|
+
owner: "exe-os",
|
|
952
|
+
purpose: "Applies runtime instruction post-processing.",
|
|
953
|
+
runtimes: ["claude"],
|
|
954
|
+
checkpointRole: "none"
|
|
955
|
+
}
|
|
956
|
+
];
|
|
847
957
|
LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS = [
|
|
848
958
|
"dist/hooks/ingest.js",
|
|
849
959
|
"dist/hooks/error-recall.js",
|
|
@@ -17181,10 +17291,14 @@ function parseStackManifest(raw, publicKey) {
|
|
|
17181
17291
|
}
|
|
17182
17292
|
return parsed;
|
|
17183
17293
|
}
|
|
17184
|
-
async function loadStackManifest(ref, fetchText = defaultFetchText, publicKey) {
|
|
17185
|
-
if (/^https?:\/\//.test(ref)) return parseStackManifest(await
|
|
17294
|
+
async function loadStackManifest(ref, fetchText = defaultFetchText, publicKey, authToken) {
|
|
17295
|
+
if (/^https?:\/\//.test(ref)) return parseStackManifest(await fetchTextWithAuth(ref, fetchText, authToken), publicKey);
|
|
17186
17296
|
return parseStackManifest(readFileSync25(ref, "utf8"), publicKey);
|
|
17187
17297
|
}
|
|
17298
|
+
async function fetchTextWithAuth(ref, fetchText, authToken) {
|
|
17299
|
+
if (!authToken || fetchText !== defaultFetchText) return fetchText(ref);
|
|
17300
|
+
return defaultFetchText(ref, authToken);
|
|
17301
|
+
}
|
|
17188
17302
|
function parseEnv(raw) {
|
|
17189
17303
|
const env = /* @__PURE__ */ new Map();
|
|
17190
17304
|
for (const line of raw.split(/\r?\n/)) {
|
|
@@ -17250,14 +17364,16 @@ async function runStackUpdate(options) {
|
|
|
17250
17364
|
const exec2 = options.exec ?? defaultExec;
|
|
17251
17365
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
17252
17366
|
if (options.rollback) return rollbackStackUpdate(options);
|
|
17253
|
-
const manifest = await loadStackManifest(options.manifestRef, options.fetchText, options.manifestPublicKey);
|
|
17367
|
+
const manifest = await loadStackManifest(options.manifestRef, options.fetchText, options.manifestPublicKey, options.manifestAuthToken);
|
|
17254
17368
|
const envRaw = readFileSync25(options.envFile, "utf8");
|
|
17255
17369
|
const plan = createStackUpdatePlan(manifest, envRaw, options.targetVersion);
|
|
17256
17370
|
assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
|
|
17257
17371
|
const lockFile = options.lockFile ?? path37.join(path37.dirname(options.envFile), ".exe-stack-lock.json");
|
|
17372
|
+
const previousVersion = readCurrentStackVersion(lockFile);
|
|
17258
17373
|
if (options.dryRun || plan.changes.length === 0) {
|
|
17259
17374
|
return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
|
|
17260
17375
|
}
|
|
17376
|
+
await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
|
|
17261
17377
|
const backupDir = path37.join(path37.dirname(options.envFile), ".exe-stack-backups");
|
|
17262
17378
|
mkdirSync19(backupDir, { recursive: true });
|
|
17263
17379
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
@@ -17274,6 +17390,7 @@ async function runStackUpdate(options) {
|
|
|
17274
17390
|
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
17275
17391
|
await verifyReleaseHealth(plan.release, options.healthRetries ?? 12, options.healthDelayMs ?? 5e3);
|
|
17276
17392
|
writeFileSync20(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, updatedAt: now().toISOString(), backupEnvFile, services: plan.release.services }, null, 2) + "\n");
|
|
17393
|
+
await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
|
|
17277
17394
|
return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile };
|
|
17278
17395
|
} catch (err) {
|
|
17279
17396
|
writeFileSync20(options.envFile, envRaw, { mode: 384 });
|
|
@@ -17282,9 +17399,37 @@ async function runStackUpdate(options) {
|
|
|
17282
17399
|
} catch {
|
|
17283
17400
|
}
|
|
17284
17401
|
const reason = err instanceof Error ? err.message : String(err);
|
|
17402
|
+
await postDeployAudit(options, "failed", plan.targetVersion, previousVersion, reason, { rollbackAttempted: true });
|
|
17285
17403
|
throw new Error(`Stack update failed and rollback was attempted: ${reason}`);
|
|
17286
17404
|
}
|
|
17287
17405
|
}
|
|
17406
|
+
function readCurrentStackVersion(lockFile) {
|
|
17407
|
+
if (!existsSync30(lockFile)) return void 0;
|
|
17408
|
+
try {
|
|
17409
|
+
const parsed = JSON.parse(readFileSync25(lockFile, "utf8"));
|
|
17410
|
+
return parsed.stackVersion;
|
|
17411
|
+
} catch {
|
|
17412
|
+
return void 0;
|
|
17413
|
+
}
|
|
17414
|
+
}
|
|
17415
|
+
async function postDeployAudit(options, status, stackVersion, previousVersion, error, metadata) {
|
|
17416
|
+
if (!options.auditUrl) return;
|
|
17417
|
+
const postJson = options.postJson ?? defaultPostJson;
|
|
17418
|
+
try {
|
|
17419
|
+
await postJson(options.auditUrl, {
|
|
17420
|
+
stackVersion,
|
|
17421
|
+
previousVersion,
|
|
17422
|
+
status,
|
|
17423
|
+
error,
|
|
17424
|
+
metadata,
|
|
17425
|
+
deviceId: options.deviceId,
|
|
17426
|
+
licenseKey: options.licenseKey
|
|
17427
|
+
}, options.manifestAuthToken);
|
|
17428
|
+
} catch (err) {
|
|
17429
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
17430
|
+
console.warn(`[stack-update] deploy audit failed: ${reason}`);
|
|
17431
|
+
}
|
|
17432
|
+
}
|
|
17288
17433
|
async function verifyReleaseHealth(release, retries, delayMs) {
|
|
17289
17434
|
for (const [serviceName, service] of Object.entries(release.services)) {
|
|
17290
17435
|
if (!service.healthUrl) continue;
|
|
@@ -17321,20 +17466,43 @@ function httpStatus(urlString) {
|
|
|
17321
17466
|
function defaultExec(cmd, args2, opts) {
|
|
17322
17467
|
execFileSync3(cmd, args2, { stdio: "inherit", cwd: opts?.cwd });
|
|
17323
17468
|
}
|
|
17324
|
-
async function defaultFetchText(ref) {
|
|
17325
|
-
const res = await fetch(ref
|
|
17469
|
+
async function defaultFetchText(ref, authToken) {
|
|
17470
|
+
const res = await fetch(ref, {
|
|
17471
|
+
headers: authToken ? { authorization: `Bearer ${authToken}` } : void 0
|
|
17472
|
+
});
|
|
17326
17473
|
if (!res.ok) throw new Error(`Failed to fetch ${ref}: HTTP ${res.status}`);
|
|
17327
17474
|
return res.text();
|
|
17328
17475
|
}
|
|
17476
|
+
async function defaultPostJson(url, body, authToken) {
|
|
17477
|
+
const res = await fetch(url, {
|
|
17478
|
+
method: "POST",
|
|
17479
|
+
headers: {
|
|
17480
|
+
"content-type": "application/json",
|
|
17481
|
+
...authToken ? { authorization: `Bearer ${authToken}` } : {}
|
|
17482
|
+
},
|
|
17483
|
+
body: JSON.stringify(body)
|
|
17484
|
+
});
|
|
17485
|
+
if (!res.ok) throw new Error(`Failed to POST ${url}: HTTP ${res.status}`);
|
|
17486
|
+
}
|
|
17329
17487
|
function defaultStackPaths() {
|
|
17330
17488
|
const cwdCompose = path37.resolve("docker-compose.yml");
|
|
17331
17489
|
const cwdEnv = path37.resolve(".env");
|
|
17332
17490
|
return {
|
|
17333
17491
|
composeFile: process.env.EXE_STACK_COMPOSE_FILE || (existsSync30(cwdCompose) ? cwdCompose : "/opt/exe-stack/docker-compose.yml"),
|
|
17334
17492
|
envFile: process.env.EXE_STACK_ENV_FILE || (existsSync30(cwdEnv) ? cwdEnv : "/opt/exe-stack/.env"),
|
|
17335
|
-
manifestRef: process.env.EXE_STACK_MANIFEST || "https://update.askexe.com/stack-manifest.json"
|
|
17493
|
+
manifestRef: process.env.EXE_STACK_MANIFEST || "https://update.askexe.com/stack-manifest.json",
|
|
17494
|
+
auditUrl: process.env.EXE_STACK_AUDIT_URL || "https://update.askexe.com/v1/deploy-audits",
|
|
17495
|
+
manifestAuthToken: process.env.EXE_STACK_UPDATE_TOKEN,
|
|
17496
|
+
manifestPublicKey: loadDefaultPublicKey()
|
|
17336
17497
|
};
|
|
17337
17498
|
}
|
|
17499
|
+
function loadDefaultPublicKey() {
|
|
17500
|
+
if (process.env.EXE_STACK_PUBLIC_KEY) return process.env.EXE_STACK_PUBLIC_KEY;
|
|
17501
|
+
if (process.env.EXE_STACK_PUBLIC_KEY_FILE && existsSync30(process.env.EXE_STACK_PUBLIC_KEY_FILE)) {
|
|
17502
|
+
return readFileSync25(process.env.EXE_STACK_PUBLIC_KEY_FILE, "utf8");
|
|
17503
|
+
}
|
|
17504
|
+
return void 0;
|
|
17505
|
+
}
|
|
17338
17506
|
var init_stack_update = __esm({
|
|
17339
17507
|
"src/lib/stack-update.ts"() {
|
|
17340
17508
|
"use strict";
|
|
@@ -17353,6 +17521,11 @@ function parseArgs4(args2) {
|
|
|
17353
17521
|
manifestRef: defaults.manifestRef,
|
|
17354
17522
|
composeFile: defaults.composeFile,
|
|
17355
17523
|
envFile: defaults.envFile,
|
|
17524
|
+
auditUrl: defaults.auditUrl,
|
|
17525
|
+
manifestAuthToken: defaults.manifestAuthToken,
|
|
17526
|
+
manifestPublicKey: defaults.manifestPublicKey,
|
|
17527
|
+
deviceId: process.env.EXE_DEVICE_ID,
|
|
17528
|
+
licenseKey: process.env.EXE_LICENSE_KEY,
|
|
17356
17529
|
dryRun: false,
|
|
17357
17530
|
check: false,
|
|
17358
17531
|
rollback: false,
|
|
@@ -17373,6 +17546,15 @@ function parseArgs4(args2) {
|
|
|
17373
17546
|
else if (arg === "--lock-file") opts.lockFile = next();
|
|
17374
17547
|
else if (arg === "--public-key") opts.manifestPublicKey = readFileSync26(next(), "utf8");
|
|
17375
17548
|
else if (arg.startsWith("--public-key=")) opts.manifestPublicKey = readFileSync26(arg.split("=").slice(1).join("="), "utf8");
|
|
17549
|
+
else if (arg === "--auth-token") opts.manifestAuthToken = next();
|
|
17550
|
+
else if (arg.startsWith("--auth-token=")) opts.manifestAuthToken = arg.split("=").slice(1).join("=");
|
|
17551
|
+
else if (arg === "--auth-token-env") opts.manifestAuthToken = process.env[next()] ?? "";
|
|
17552
|
+
else if (arg === "--audit-url") opts.auditUrl = next();
|
|
17553
|
+
else if (arg.startsWith("--audit-url=")) opts.auditUrl = arg.split("=").slice(1).join("=");
|
|
17554
|
+
else if (arg === "--device-id") opts.deviceId = next();
|
|
17555
|
+
else if (arg.startsWith("--device-id=")) opts.deviceId = arg.split("=").slice(1).join("=");
|
|
17556
|
+
else if (arg === "--license-key") opts.licenseKey = next();
|
|
17557
|
+
else if (arg.startsWith("--license-key=")) opts.licenseKey = arg.split("=").slice(1).join("=");
|
|
17376
17558
|
else if (arg === "--rollback") opts.rollback = true;
|
|
17377
17559
|
else if (arg === "--dry-run") opts.dryRun = true;
|
|
17378
17560
|
else if (arg === "--check") opts.check = true;
|
|
@@ -17403,6 +17585,11 @@ Options:
|
|
|
17403
17585
|
--check Print available changes only
|
|
17404
17586
|
--dry-run Plan only; do not run Docker
|
|
17405
17587
|
--public-key <path> PEM public key for signed manifest verification
|
|
17588
|
+
--auth-token <token> Bearer token for private update manifest/audit API
|
|
17589
|
+
--auth-token-env <name> Read bearer token from an environment variable
|
|
17590
|
+
--audit-url <url> Deploy-audit endpoint (default: EXE_STACK_AUDIT_URL/update.askexe.com)
|
|
17591
|
+
--device-id <id> Device ID to include in deploy audit
|
|
17592
|
+
--license-key <key> License key to include in deploy audit
|
|
17406
17593
|
--rollback Restore latest backed-up .env and restart stack
|
|
17407
17594
|
--allow-breaking <ids> Confirm breaking changes, comma-separated
|
|
17408
17595
|
-y, --yes Non-interactive confirmation
|
|
@@ -17440,7 +17627,7 @@ async function main3() {
|
|
|
17440
17627
|
console.log(`\u2705 Stack rollback attempted using backup: ${result2.backupEnvFile ?? "latest backup"}`);
|
|
17441
17628
|
return;
|
|
17442
17629
|
}
|
|
17443
|
-
const manifest = await loadStackManifest(opts.manifestRef, void 0, opts.manifestPublicKey);
|
|
17630
|
+
const manifest = await loadStackManifest(opts.manifestRef, void 0, opts.manifestPublicKey, opts.manifestAuthToken);
|
|
17444
17631
|
const envRaw = readFileSync26(opts.envFile, "utf8");
|
|
17445
17632
|
const plan = createStackUpdatePlan(manifest, envRaw, opts.targetVersion);
|
|
17446
17633
|
console.log(`Exe OS stack target: ${plan.targetVersion}`);
|