@askexenow/exe-os 0.9.61 → 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/deploy/stack-manifests/v0.9.json +62 -13
- package/dist/bin/backfill-conversations.js +210 -2
- package/dist/bin/backfill-responses.js +210 -2
- package/dist/bin/backfill-vectors.js +47 -2
- package/dist/bin/cleanup-stale-review-tasks.js +210 -2
- package/dist/bin/cli.js +488 -25
- package/dist/bin/exe-agent-config.js +2 -2
- package/dist/bin/exe-agent.js +2 -2
- package/dist/bin/exe-assign.js +210 -2
- package/dist/bin/exe-boot.js +47 -2
- package/dist/bin/exe-call.js +2 -2
- package/dist/bin/exe-cloud.js +2 -2
- package/dist/bin/exe-dispatch.js +210 -2
- package/dist/bin/exe-doctor.js +2691 -1212
- package/dist/bin/exe-export-behaviors.js +210 -2
- package/dist/bin/exe-forget.js +264 -2
- package/dist/bin/exe-gateway.js +210 -2
- package/dist/bin/exe-heartbeat.js +212 -4
- package/dist/bin/exe-kill.js +210 -2
- package/dist/bin/exe-launch-agent.js +210 -2
- package/dist/bin/exe-link.js +47 -2
- package/dist/bin/exe-new-employee.js +113 -3
- package/dist/bin/exe-pending-messages.js +210 -2
- package/dist/bin/exe-pending-notifications.js +210 -2
- package/dist/bin/exe-pending-reviews.js +210 -2
- package/dist/bin/exe-rename.js +210 -2
- package/dist/bin/exe-review.js +210 -2
- package/dist/bin/exe-search.js +234 -3
- package/dist/bin/exe-session-cleanup.js +210 -2
- package/dist/bin/exe-settings.js +2 -2
- package/dist/bin/exe-start-codex.js +322 -4
- package/dist/bin/exe-start-opencode.js +336 -4
- package/dist/bin/exe-status.js +210 -2
- package/dist/bin/exe-team.js +210 -2
- package/dist/bin/git-sweep.js +210 -2
- package/dist/bin/graph-backfill.js +210 -2
- package/dist/bin/graph-export.js +210 -2
- package/dist/bin/install.js +113 -3
- package/dist/bin/intercom-check.js +210 -2
- package/dist/bin/scan-tasks.js +210 -2
- package/dist/bin/setup.js +47 -2
- package/dist/bin/shard-migrate.js +210 -2
- package/dist/bin/stack-update.js +158 -13
- package/dist/bin/update.js +2 -2
- package/dist/gateway/index.js +210 -2
- package/dist/hooks/bug-report-worker.js +321 -44
- package/dist/hooks/codex-stop-task-finalizer.js +210 -2
- package/dist/hooks/commit-complete.js +210 -2
- package/dist/hooks/error-recall.js +234 -3
- package/dist/hooks/exe-heartbeat-hook.js +2 -2
- package/dist/hooks/ingest-worker.js +2 -2
- package/dist/hooks/ingest.js +210 -2
- package/dist/hooks/instructions-loaded.js +210 -2
- package/dist/hooks/notification.js +210 -2
- package/dist/hooks/post-compact.js +210 -2
- package/dist/hooks/post-tool-combined.js +234 -3
- package/dist/hooks/pre-compact.js +446 -111
- package/dist/hooks/pre-tool-use.js +210 -2
- package/dist/hooks/prompt-submit.js +234 -3
- package/dist/hooks/session-end.js +347 -124
- package/dist/hooks/session-start.js +236 -5
- package/dist/hooks/stop.js +210 -2
- package/dist/hooks/subagent-stop.js +210 -2
- package/dist/hooks/summary-worker.js +171 -74
- package/dist/index.js +210 -2
- package/dist/lib/agent-config.js +2 -2
- package/dist/lib/cloud-sync.js +47 -2
- package/dist/lib/config.js +2 -2
- package/dist/lib/consolidation.js +2 -2
- package/dist/lib/database.js +47 -2
- package/dist/lib/db-daemon-client.js +2 -2
- package/dist/lib/db.js +47 -2
- package/dist/lib/device-registry.js +47 -2
- package/dist/lib/embedder.js +2 -2
- package/dist/lib/employee-templates.js +2 -2
- package/dist/lib/employees.js +2 -2
- package/dist/lib/exe-daemon-client.js +2 -2
- package/dist/lib/exe-daemon.js +592 -10
- package/dist/lib/hybrid-search.js +234 -3
- package/dist/lib/identity.js +2 -2
- package/dist/lib/license.js +2 -2
- package/dist/lib/messaging.js +2 -2
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +47 -2
- package/dist/lib/skill-learning.js +2 -2
- package/dist/lib/store.js +210 -2
- package/dist/lib/task-router.js +2 -2
- package/dist/lib/tasks.js +2 -2
- package/dist/lib/tmux-routing.js +2 -2
- package/dist/lib/token-spend.js +2 -2
- package/dist/mcp/server.js +608 -10
- package/dist/mcp/tools/complete-reminder.js +2 -2
- package/dist/mcp/tools/create-reminder.js +2 -2
- package/dist/mcp/tools/create-task.js +2 -2
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +2 -2
- package/dist/mcp/tools/list-tasks.js +2 -2
- package/dist/mcp/tools/send-message.js +2 -2
- package/dist/mcp/tools/update-task.js +2 -2
- package/dist/runtime/index.js +210 -2
- package/dist/tui/App.js +210 -2
- package/package.json +3 -2
- package/stack.release.json +23 -7
package/dist/bin/cli.js
CHANGED
|
@@ -258,8 +258,8 @@ var init_config = __esm({
|
|
|
258
258
|
rerankerAutoTrigger: {
|
|
259
259
|
enabled: true,
|
|
260
260
|
broadQueryMinCardinality: 5e4,
|
|
261
|
-
fetchTopK:
|
|
262
|
-
returnTopK:
|
|
261
|
+
fetchTopK: 200,
|
|
262
|
+
returnTopK: 20
|
|
263
263
|
}
|
|
264
264
|
},
|
|
265
265
|
graphRagEnabled: true,
|
|
@@ -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",
|
|
@@ -4561,6 +4671,51 @@ async function ensureSchema() {
|
|
|
4561
4671
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
4562
4672
|
END;
|
|
4563
4673
|
`);
|
|
4674
|
+
await client.executeMultiple(`
|
|
4675
|
+
CREATE TABLE IF NOT EXISTS memory_cards (
|
|
4676
|
+
id TEXT PRIMARY KEY,
|
|
4677
|
+
memory_id TEXT NOT NULL,
|
|
4678
|
+
agent_id TEXT NOT NULL,
|
|
4679
|
+
session_id TEXT NOT NULL,
|
|
4680
|
+
project_name TEXT,
|
|
4681
|
+
timestamp TEXT NOT NULL,
|
|
4682
|
+
card_type TEXT NOT NULL,
|
|
4683
|
+
subject TEXT,
|
|
4684
|
+
predicate TEXT,
|
|
4685
|
+
object TEXT,
|
|
4686
|
+
content TEXT NOT NULL,
|
|
4687
|
+
source_ref TEXT,
|
|
4688
|
+
confidence REAL DEFAULT 0.6,
|
|
4689
|
+
active INTEGER DEFAULT 1,
|
|
4690
|
+
created_at TEXT NOT NULL
|
|
4691
|
+
);
|
|
4692
|
+
|
|
4693
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_agent
|
|
4694
|
+
ON memory_cards(agent_id, active, timestamp);
|
|
4695
|
+
|
|
4696
|
+
CREATE INDEX IF NOT EXISTS idx_memory_cards_memory
|
|
4697
|
+
ON memory_cards(memory_id);
|
|
4698
|
+
|
|
4699
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_cards_fts
|
|
4700
|
+
USING fts5(content, subject, predicate, object, content='memory_cards', content_rowid='rowid');
|
|
4701
|
+
|
|
4702
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ai AFTER INSERT ON memory_cards BEGIN
|
|
4703
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
4704
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
4705
|
+
END;
|
|
4706
|
+
|
|
4707
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_ad AFTER DELETE ON memory_cards BEGIN
|
|
4708
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
4709
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
4710
|
+
END;
|
|
4711
|
+
|
|
4712
|
+
CREATE TRIGGER IF NOT EXISTS memory_cards_fts_au AFTER UPDATE ON memory_cards BEGIN
|
|
4713
|
+
INSERT INTO memory_cards_fts(memory_cards_fts, rowid, content, subject, predicate, object)
|
|
4714
|
+
VALUES('delete', old.rowid, old.content, old.subject, old.predicate, old.object);
|
|
4715
|
+
INSERT INTO memory_cards_fts(rowid, content, subject, predicate, object)
|
|
4716
|
+
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
4717
|
+
END;
|
|
4718
|
+
`);
|
|
4564
4719
|
try {
|
|
4565
4720
|
await client.execute({
|
|
4566
4721
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -7941,6 +8096,164 @@ ${p.content}`).join("\n\n");
|
|
|
7941
8096
|
}
|
|
7942
8097
|
});
|
|
7943
8098
|
|
|
8099
|
+
// src/lib/memory-cards.ts
|
|
8100
|
+
var memory_cards_exports = {};
|
|
8101
|
+
__export(memory_cards_exports, {
|
|
8102
|
+
extractMemoryCards: () => extractMemoryCards,
|
|
8103
|
+
insertMemoryCardsForBatch: () => insertMemoryCardsForBatch,
|
|
8104
|
+
searchMemoryCards: () => searchMemoryCards
|
|
8105
|
+
});
|
|
8106
|
+
import { createHash as createHash3 } from "crypto";
|
|
8107
|
+
function stableId(memoryId, type, content) {
|
|
8108
|
+
return createHash3("sha256").update(`${memoryId}:${type}:${content}`).digest("hex").slice(0, 32);
|
|
8109
|
+
}
|
|
8110
|
+
function cleanText(text) {
|
|
8111
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
8112
|
+
}
|
|
8113
|
+
function splitSentences(text) {
|
|
8114
|
+
return cleanText(text).split(/(?<=[.!?])\s+|\n+/).map((s) => s.trim()).filter((s) => s.length >= 24 && s.length <= MAX_SENTENCE_CHARS);
|
|
8115
|
+
}
|
|
8116
|
+
function inferCardType(sentence, toolName) {
|
|
8117
|
+
const lower = sentence.toLowerCase();
|
|
8118
|
+
if (toolName === "store_decision" || /\b(decided|decision|adr|approved|rejected)\b/.test(lower)) return "decision";
|
|
8119
|
+
if (/\b(prefers|preference|likes|dislikes|wants|doesn't want|does not want)\b/.test(lower)) return "preference";
|
|
8120
|
+
if (/\b(changed|updated|replaced|now|no longer|instead|supersedes)\b/.test(lower)) return "belief_update";
|
|
8121
|
+
if (toolName && ["Read", "Write", "Edit", "Bash"].includes(toolName)) return "code";
|
|
8122
|
+
if (/\b(meeting|deadline|shipped|launched|completed|failed|blocked|assigned|created)\b/.test(lower)) return "event";
|
|
8123
|
+
return "fact";
|
|
8124
|
+
}
|
|
8125
|
+
function extractSubject(sentence, agentId) {
|
|
8126
|
+
const explicit = sentence.match(/\b([A-Z][a-zA-Z0-9_-]{2,}(?:\s+[A-Z][a-zA-Z0-9_-]{2,})?)\b/);
|
|
8127
|
+
return explicit?.[1] ?? agentId;
|
|
8128
|
+
}
|
|
8129
|
+
function predicateFor(type) {
|
|
8130
|
+
switch (type) {
|
|
8131
|
+
case "preference":
|
|
8132
|
+
return "prefers";
|
|
8133
|
+
case "belief_update":
|
|
8134
|
+
return "updated";
|
|
8135
|
+
case "decision":
|
|
8136
|
+
return "decided";
|
|
8137
|
+
case "event":
|
|
8138
|
+
return "happened";
|
|
8139
|
+
case "code":
|
|
8140
|
+
return "implemented";
|
|
8141
|
+
default:
|
|
8142
|
+
return "states";
|
|
8143
|
+
}
|
|
8144
|
+
}
|
|
8145
|
+
function extractMemoryCards(row) {
|
|
8146
|
+
const sentences = splitSentences(row.raw_text);
|
|
8147
|
+
const cards = [];
|
|
8148
|
+
for (const sentence of sentences) {
|
|
8149
|
+
const type = inferCardType(sentence, row.tool_name);
|
|
8150
|
+
const subject = extractSubject(sentence, row.agent_id);
|
|
8151
|
+
const content = sentence.length > MAX_SENTENCE_CHARS ? `${sentence.slice(0, MAX_SENTENCE_CHARS - 1)}\u2026` : sentence;
|
|
8152
|
+
cards.push({
|
|
8153
|
+
id: stableId(row.id, type, content),
|
|
8154
|
+
memory_id: row.id,
|
|
8155
|
+
agent_id: row.agent_id,
|
|
8156
|
+
session_id: row.session_id,
|
|
8157
|
+
project_name: row.project_name ?? null,
|
|
8158
|
+
timestamp: row.timestamp,
|
|
8159
|
+
card_type: type,
|
|
8160
|
+
subject,
|
|
8161
|
+
predicate: predicateFor(type),
|
|
8162
|
+
object: content,
|
|
8163
|
+
content,
|
|
8164
|
+
source_ref: row.id,
|
|
8165
|
+
confidence: type === "fact" ? 0.55 : 0.65
|
|
8166
|
+
});
|
|
8167
|
+
if (cards.length >= MAX_CARDS_PER_MEMORY) break;
|
|
8168
|
+
}
|
|
8169
|
+
return cards;
|
|
8170
|
+
}
|
|
8171
|
+
async function insertMemoryCardsForBatch(rows) {
|
|
8172
|
+
const cards = rows.flatMap(extractMemoryCards);
|
|
8173
|
+
if (cards.length === 0) return 0;
|
|
8174
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8175
|
+
const client = getClient();
|
|
8176
|
+
const stmts = cards.map((card) => ({
|
|
8177
|
+
sql: `INSERT OR IGNORE INTO memory_cards
|
|
8178
|
+
(id, memory_id, agent_id, session_id, project_name, timestamp, card_type,
|
|
8179
|
+
subject, predicate, object, content, source_ref, confidence, active, created_at)
|
|
8180
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)`,
|
|
8181
|
+
args: [
|
|
8182
|
+
card.id,
|
|
8183
|
+
card.memory_id,
|
|
8184
|
+
card.agent_id,
|
|
8185
|
+
card.session_id,
|
|
8186
|
+
card.project_name,
|
|
8187
|
+
card.timestamp,
|
|
8188
|
+
card.card_type,
|
|
8189
|
+
card.subject,
|
|
8190
|
+
card.predicate,
|
|
8191
|
+
card.object,
|
|
8192
|
+
card.content,
|
|
8193
|
+
card.source_ref,
|
|
8194
|
+
card.confidence,
|
|
8195
|
+
now
|
|
8196
|
+
]
|
|
8197
|
+
}));
|
|
8198
|
+
await client.batch(stmts, "write");
|
|
8199
|
+
return cards.length;
|
|
8200
|
+
}
|
|
8201
|
+
function buildMatchExpr(queryText) {
|
|
8202
|
+
const terms = queryText.toLowerCase().split(/\s+/).filter((t) => t.length >= 3).map((t) => t.replace(/[^a-z0-9_]/g, "")).filter((t) => t.length >= 3).slice(0, 12);
|
|
8203
|
+
if (terms.length === 0) return null;
|
|
8204
|
+
return terms.map((t) => `${t}*`).join(terms.length >= 3 ? " AND " : " OR ");
|
|
8205
|
+
}
|
|
8206
|
+
async function searchMemoryCards(queryText, agentId, options) {
|
|
8207
|
+
const limit = options?.limit ?? 10;
|
|
8208
|
+
const matchExpr = buildMatchExpr(queryText);
|
|
8209
|
+
if (!matchExpr) return [];
|
|
8210
|
+
let sql = `SELECT c.id, c.memory_id, c.agent_id, c.session_id, c.project_name,
|
|
8211
|
+
c.timestamp, c.card_type, c.content, c.source_ref, c.confidence
|
|
8212
|
+
FROM memory_cards c
|
|
8213
|
+
JOIN memory_cards_fts fts ON c.rowid = fts.rowid
|
|
8214
|
+
WHERE memory_cards_fts MATCH ?
|
|
8215
|
+
AND c.agent_id = ?
|
|
8216
|
+
AND COALESCE(c.active, 1) = 1`;
|
|
8217
|
+
const args2 = [matchExpr, agentId];
|
|
8218
|
+
if (options?.projectName) {
|
|
8219
|
+
sql += ` AND c.project_name = ?`;
|
|
8220
|
+
args2.push(options.projectName);
|
|
8221
|
+
}
|
|
8222
|
+
if (options?.since) {
|
|
8223
|
+
sql += ` AND c.timestamp >= ?`;
|
|
8224
|
+
args2.push(options.since);
|
|
8225
|
+
}
|
|
8226
|
+
sql += ` ORDER BY rank LIMIT ?`;
|
|
8227
|
+
args2.push(limit);
|
|
8228
|
+
const result = await getClient().execute({ sql, args: args2 });
|
|
8229
|
+
return result.rows.map((row) => ({
|
|
8230
|
+
id: `card:${String(row.id)}`,
|
|
8231
|
+
agent_id: String(row.agent_id),
|
|
8232
|
+
agent_role: "memory_card",
|
|
8233
|
+
session_id: String(row.session_id),
|
|
8234
|
+
timestamp: String(row.timestamp),
|
|
8235
|
+
tool_name: `memory_card:${String(row.card_type)}`,
|
|
8236
|
+
project_name: row.project_name == null ? "" : String(row.project_name),
|
|
8237
|
+
has_error: false,
|
|
8238
|
+
raw_text: `[${String(row.card_type)}] ${String(row.content)}
|
|
8239
|
+
Source memory: ${String(row.source_ref ?? row.memory_id)}`,
|
|
8240
|
+
vector: [],
|
|
8241
|
+
importance: 6,
|
|
8242
|
+
status: "active",
|
|
8243
|
+
confidence: Number(row.confidence ?? 0.6),
|
|
8244
|
+
last_accessed: String(row.timestamp)
|
|
8245
|
+
}));
|
|
8246
|
+
}
|
|
8247
|
+
var MAX_CARDS_PER_MEMORY, MAX_SENTENCE_CHARS;
|
|
8248
|
+
var init_memory_cards = __esm({
|
|
8249
|
+
"src/lib/memory-cards.ts"() {
|
|
8250
|
+
"use strict";
|
|
8251
|
+
init_database();
|
|
8252
|
+
MAX_CARDS_PER_MEMORY = 6;
|
|
8253
|
+
MAX_SENTENCE_CHARS = 360;
|
|
8254
|
+
}
|
|
8255
|
+
});
|
|
8256
|
+
|
|
7944
8257
|
// src/lib/store.ts
|
|
7945
8258
|
var store_exports = {};
|
|
7946
8259
|
__export(store_exports, {
|
|
@@ -8279,6 +8592,11 @@ async function flushBatch() {
|
|
|
8279
8592
|
const globalClient = getClient();
|
|
8280
8593
|
const globalStmts = batch.map(buildStmt);
|
|
8281
8594
|
await globalClient.batch(globalStmts, "write");
|
|
8595
|
+
try {
|
|
8596
|
+
const { insertMemoryCardsForBatch: insertMemoryCardsForBatch2 } = await Promise.resolve().then(() => (init_memory_cards(), memory_cards_exports));
|
|
8597
|
+
await insertMemoryCardsForBatch2(batch);
|
|
8598
|
+
} catch {
|
|
8599
|
+
}
|
|
8282
8600
|
schedulePostWriteMemoryHygiene(batch.map((row) => row.id));
|
|
8283
8601
|
_pendingRecords.splice(0, batch.length);
|
|
8284
8602
|
try {
|
|
@@ -9537,7 +9855,7 @@ __export(identity_exports, {
|
|
|
9537
9855
|
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
9538
9856
|
import { readdirSync as readdirSync4 } from "fs";
|
|
9539
9857
|
import path17 from "path";
|
|
9540
|
-
import { createHash as
|
|
9858
|
+
import { createHash as createHash4 } from "crypto";
|
|
9541
9859
|
function ensureDir() {
|
|
9542
9860
|
if (!existsSync16(IDENTITY_DIR2)) {
|
|
9543
9861
|
mkdirSync9(IDENTITY_DIR2, { recursive: true });
|
|
@@ -9584,7 +9902,7 @@ function parseFrontmatter(raw) {
|
|
|
9584
9902
|
};
|
|
9585
9903
|
}
|
|
9586
9904
|
function contentHash(content) {
|
|
9587
|
-
return
|
|
9905
|
+
return createHash4("sha256").update(content).digest("hex").slice(0, 16);
|
|
9588
9906
|
}
|
|
9589
9907
|
function getIdentity(agentId) {
|
|
9590
9908
|
const filePath = identityPath(agentId);
|
|
@@ -15004,7 +15322,7 @@ var init_exe_rename = __esm({
|
|
|
15004
15322
|
// src/lib/model-downloader.ts
|
|
15005
15323
|
import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync26, unlinkSync as unlinkSync12, renameSync as renameSync6 } from "fs";
|
|
15006
15324
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
15007
|
-
import { createHash as
|
|
15325
|
+
import { createHash as createHash5 } from "crypto";
|
|
15008
15326
|
import path32 from "path";
|
|
15009
15327
|
async function downloadModel(opts) {
|
|
15010
15328
|
const { destDir, onProgress, fetchFn = globalThis.fetch } = opts;
|
|
@@ -15032,7 +15350,7 @@ async function downloadModel(opts) {
|
|
|
15032
15350
|
throw new Error(`Download failed: HTTP ${response.status}`);
|
|
15033
15351
|
}
|
|
15034
15352
|
const contentLength = Number(response.headers.get("content-length") ?? EXPECTED_SIZE);
|
|
15035
|
-
const hash =
|
|
15353
|
+
const hash = createHash5("sha256");
|
|
15036
15354
|
const fileStream = createWriteStream(tmpPath);
|
|
15037
15355
|
const reader = response.body.getReader();
|
|
15038
15356
|
try {
|
|
@@ -15076,7 +15394,7 @@ Download attempt ${attempt} failed, retrying...
|
|
|
15076
15394
|
}
|
|
15077
15395
|
async function fileHash(filePath) {
|
|
15078
15396
|
return new Promise((resolve, reject) => {
|
|
15079
|
-
const hash =
|
|
15397
|
+
const hash = createHash5("sha256");
|
|
15080
15398
|
const stream = createReadStream2(filePath);
|
|
15081
15399
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
15082
15400
|
stream.on("end", () => resolve(hash.digest("hex")));
|
|
@@ -16898,12 +17216,64 @@ var init_update = __esm({
|
|
|
16898
17216
|
|
|
16899
17217
|
// src/lib/stack-update.ts
|
|
16900
17218
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
16901
|
-
import {
|
|
17219
|
+
import { createVerify, verify as verifySignature } from "crypto";
|
|
17220
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readdirSync as readdirSync10, readFileSync as readFileSync25, renameSync as renameSync7, writeFileSync as writeFileSync20 } from "fs";
|
|
16902
17221
|
import http from "http";
|
|
16903
17222
|
import https from "https";
|
|
16904
17223
|
import path37 from "path";
|
|
16905
|
-
function
|
|
16906
|
-
|
|
17224
|
+
function isSignedEnvelope(value) {
|
|
17225
|
+
return !!value && typeof value === "object" && "manifest" in value && "signature" in value;
|
|
17226
|
+
}
|
|
17227
|
+
function canonicalizeStackManifest(manifest) {
|
|
17228
|
+
const clone = JSON.parse(JSON.stringify(manifest));
|
|
17229
|
+
delete clone.signature;
|
|
17230
|
+
return stableJson(clone);
|
|
17231
|
+
}
|
|
17232
|
+
function verifyStackManifestSignature(manifest, publicKeyPem) {
|
|
17233
|
+
const signature = manifest.signature;
|
|
17234
|
+
if (!signature) throw new Error("Stack manifest signature required but missing");
|
|
17235
|
+
const payload = Buffer.from(canonicalizeStackManifest(manifest));
|
|
17236
|
+
const sig = Buffer.from(signature.signature, "base64");
|
|
17237
|
+
let ok = false;
|
|
17238
|
+
if (signature.alg === "ed25519") {
|
|
17239
|
+
ok = verifySignature(null, payload, publicKeyPem, sig);
|
|
17240
|
+
} else if (signature.alg === "rsa-sha256") {
|
|
17241
|
+
const verifier = createVerify("RSA-SHA256");
|
|
17242
|
+
verifier.update(payload);
|
|
17243
|
+
verifier.end();
|
|
17244
|
+
ok = verifier.verify(publicKeyPem, sig);
|
|
17245
|
+
} else {
|
|
17246
|
+
throw new Error(`Unsupported stack manifest signature alg: ${signature.alg}`);
|
|
17247
|
+
}
|
|
17248
|
+
if (!ok) throw new Error("Stack manifest signature verification failed");
|
|
17249
|
+
}
|
|
17250
|
+
function stableJson(value) {
|
|
17251
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
17252
|
+
if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
|
|
17253
|
+
const obj = value;
|
|
17254
|
+
return `{${Object.keys(obj).sort().map((key) => `${JSON.stringify(key)}:${stableJson(obj[key])}`).join(",")}}`;
|
|
17255
|
+
}
|
|
17256
|
+
function findLatestBackupEnvFile(envFile) {
|
|
17257
|
+
const backupDir = path37.join(path37.dirname(envFile), ".exe-stack-backups");
|
|
17258
|
+
if (!existsSync30(backupDir)) return null;
|
|
17259
|
+
const backups = readdirSync10(backupDir).filter((name) => name.startsWith("env-") && name.endsWith(".bak")).sort();
|
|
17260
|
+
const latest = backups.at(-1);
|
|
17261
|
+
return latest ? path37.join(backupDir, latest) : null;
|
|
17262
|
+
}
|
|
17263
|
+
async function rollbackStackUpdate(options) {
|
|
17264
|
+
const exec2 = options.exec ?? defaultExec;
|
|
17265
|
+
const backupEnvFile = options.lockFile && existsSync30(options.lockFile) ? JSON.parse(readFileSync25(options.lockFile, "utf8")).backupEnvFile : void 0;
|
|
17266
|
+
const rollbackEnv = backupEnvFile && existsSync30(backupEnvFile) ? backupEnvFile : findLatestBackupEnvFile(options.envFile);
|
|
17267
|
+
if (!rollbackEnv) throw new Error(`No stack backup env found beside ${options.envFile}`);
|
|
17268
|
+
writeFileSync20(options.envFile, readFileSync25(rollbackEnv), { mode: 384 });
|
|
17269
|
+
const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
|
|
17270
|
+
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
17271
|
+
return { status: "rolled_back", targetVersion: "previous", changes: [], backupEnvFile: rollbackEnv, lockFile: options.lockFile ?? path37.join(path37.dirname(options.envFile), ".exe-stack-lock.json") };
|
|
17272
|
+
}
|
|
17273
|
+
function parseStackManifest(raw, publicKey) {
|
|
17274
|
+
const parsedRaw = JSON.parse(raw);
|
|
17275
|
+
const parsed = isSignedEnvelope(parsedRaw) ? { ...parsedRaw.manifest, signature: parsedRaw.signature } : parsedRaw;
|
|
17276
|
+
if (publicKey) verifyStackManifestSignature(parsed, publicKey);
|
|
16907
17277
|
if (parsed.schemaVersion !== 1) throw new Error("Unsupported stack manifest schemaVersion");
|
|
16908
17278
|
if (!parsed.latest || !parsed.stacks || typeof parsed.stacks !== "object") {
|
|
16909
17279
|
throw new Error("Invalid stack manifest: latest and stacks are required");
|
|
@@ -16921,9 +17291,13 @@ function parseStackManifest(raw) {
|
|
|
16921
17291
|
}
|
|
16922
17292
|
return parsed;
|
|
16923
17293
|
}
|
|
16924
|
-
async function loadStackManifest(ref, fetchText = defaultFetchText) {
|
|
16925
|
-
if (/^https?:\/\//.test(ref)) return parseStackManifest(await
|
|
16926
|
-
return parseStackManifest(readFileSync25(ref, "utf8"));
|
|
17294
|
+
async function loadStackManifest(ref, fetchText = defaultFetchText, publicKey, authToken) {
|
|
17295
|
+
if (/^https?:\/\//.test(ref)) return parseStackManifest(await fetchTextWithAuth(ref, fetchText, authToken), publicKey);
|
|
17296
|
+
return parseStackManifest(readFileSync25(ref, "utf8"), publicKey);
|
|
17297
|
+
}
|
|
17298
|
+
async function fetchTextWithAuth(ref, fetchText, authToken) {
|
|
17299
|
+
if (!authToken || fetchText !== defaultFetchText) return fetchText(ref);
|
|
17300
|
+
return defaultFetchText(ref, authToken);
|
|
16927
17301
|
}
|
|
16928
17302
|
function parseEnv(raw) {
|
|
16929
17303
|
const env = /* @__PURE__ */ new Map();
|
|
@@ -16989,14 +17363,17 @@ Re-run with --allow-breaking ${missing.map((c) => c.id).join(",")}`
|
|
|
16989
17363
|
async function runStackUpdate(options) {
|
|
16990
17364
|
const exec2 = options.exec ?? defaultExec;
|
|
16991
17365
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
16992
|
-
|
|
17366
|
+
if (options.rollback) return rollbackStackUpdate(options);
|
|
17367
|
+
const manifest = await loadStackManifest(options.manifestRef, options.fetchText, options.manifestPublicKey, options.manifestAuthToken);
|
|
16993
17368
|
const envRaw = readFileSync25(options.envFile, "utf8");
|
|
16994
17369
|
const plan = createStackUpdatePlan(manifest, envRaw, options.targetVersion);
|
|
16995
17370
|
assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
|
|
16996
17371
|
const lockFile = options.lockFile ?? path37.join(path37.dirname(options.envFile), ".exe-stack-lock.json");
|
|
17372
|
+
const previousVersion = readCurrentStackVersion(lockFile);
|
|
16997
17373
|
if (options.dryRun || plan.changes.length === 0) {
|
|
16998
17374
|
return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
|
|
16999
17375
|
}
|
|
17376
|
+
await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
|
|
17000
17377
|
const backupDir = path37.join(path37.dirname(options.envFile), ".exe-stack-backups");
|
|
17001
17378
|
mkdirSync19(backupDir, { recursive: true });
|
|
17002
17379
|
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
@@ -17012,7 +17389,8 @@ async function runStackUpdate(options) {
|
|
|
17012
17389
|
exec2("docker", [...composeArgs, "pull"]);
|
|
17013
17390
|
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
17014
17391
|
await verifyReleaseHealth(plan.release, options.healthRetries ?? 12, options.healthDelayMs ?? 5e3);
|
|
17015
|
-
writeFileSync20(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, updatedAt: now().toISOString(), services: plan.release.services }, null, 2) + "\n");
|
|
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 });
|
|
17016
17394
|
return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile };
|
|
17017
17395
|
} catch (err) {
|
|
17018
17396
|
writeFileSync20(options.envFile, envRaw, { mode: 384 });
|
|
@@ -17021,9 +17399,37 @@ async function runStackUpdate(options) {
|
|
|
17021
17399
|
} catch {
|
|
17022
17400
|
}
|
|
17023
17401
|
const reason = err instanceof Error ? err.message : String(err);
|
|
17402
|
+
await postDeployAudit(options, "failed", plan.targetVersion, previousVersion, reason, { rollbackAttempted: true });
|
|
17024
17403
|
throw new Error(`Stack update failed and rollback was attempted: ${reason}`);
|
|
17025
17404
|
}
|
|
17026
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
|
+
}
|
|
17027
17433
|
async function verifyReleaseHealth(release, retries, delayMs) {
|
|
17028
17434
|
for (const [serviceName, service] of Object.entries(release.services)) {
|
|
17029
17435
|
if (!service.healthUrl) continue;
|
|
@@ -17060,20 +17466,43 @@ function httpStatus(urlString) {
|
|
|
17060
17466
|
function defaultExec(cmd, args2, opts) {
|
|
17061
17467
|
execFileSync3(cmd, args2, { stdio: "inherit", cwd: opts?.cwd });
|
|
17062
17468
|
}
|
|
17063
|
-
async function defaultFetchText(ref) {
|
|
17064
|
-
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
|
+
});
|
|
17065
17473
|
if (!res.ok) throw new Error(`Failed to fetch ${ref}: HTTP ${res.status}`);
|
|
17066
17474
|
return res.text();
|
|
17067
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
|
+
}
|
|
17068
17487
|
function defaultStackPaths() {
|
|
17069
17488
|
const cwdCompose = path37.resolve("docker-compose.yml");
|
|
17070
17489
|
const cwdEnv = path37.resolve(".env");
|
|
17071
17490
|
return {
|
|
17072
17491
|
composeFile: process.env.EXE_STACK_COMPOSE_FILE || (existsSync30(cwdCompose) ? cwdCompose : "/opt/exe-stack/docker-compose.yml"),
|
|
17073
17492
|
envFile: process.env.EXE_STACK_ENV_FILE || (existsSync30(cwdEnv) ? cwdEnv : "/opt/exe-stack/.env"),
|
|
17074
|
-
manifestRef: process.env.EXE_STACK_MANIFEST || "https://
|
|
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()
|
|
17075
17497
|
};
|
|
17076
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
|
+
}
|
|
17077
17506
|
var init_stack_update = __esm({
|
|
17078
17507
|
"src/lib/stack-update.ts"() {
|
|
17079
17508
|
"use strict";
|
|
@@ -17092,8 +17521,14 @@ function parseArgs4(args2) {
|
|
|
17092
17521
|
manifestRef: defaults.manifestRef,
|
|
17093
17522
|
composeFile: defaults.composeFile,
|
|
17094
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,
|
|
17095
17529
|
dryRun: false,
|
|
17096
17530
|
check: false,
|
|
17531
|
+
rollback: false,
|
|
17097
17532
|
yes: false,
|
|
17098
17533
|
allowedBreakingChangeIds: []
|
|
17099
17534
|
};
|
|
@@ -17109,6 +17544,18 @@ function parseArgs4(args2) {
|
|
|
17109
17544
|
else if (arg === "--env-file") opts.envFile = next();
|
|
17110
17545
|
else if (arg.startsWith("--env-file=")) opts.envFile = arg.split("=").slice(1).join("=");
|
|
17111
17546
|
else if (arg === "--lock-file") opts.lockFile = next();
|
|
17547
|
+
else if (arg === "--public-key") opts.manifestPublicKey = readFileSync26(next(), "utf8");
|
|
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("=");
|
|
17558
|
+
else if (arg === "--rollback") opts.rollback = true;
|
|
17112
17559
|
else if (arg === "--dry-run") opts.dryRun = true;
|
|
17113
17560
|
else if (arg === "--check") opts.check = true;
|
|
17114
17561
|
else if (arg === "--yes" || arg === "-y") opts.yes = true;
|
|
@@ -17130,13 +17577,20 @@ Usage:
|
|
|
17130
17577
|
exe-os stack-update [--manifest <path-or-url>] [--target <version>] [--yes]
|
|
17131
17578
|
|
|
17132
17579
|
Options:
|
|
17133
|
-
--manifest <ref> Stack manifest JSON path or URL (default:
|
|
17580
|
+
--manifest <ref> Stack manifest JSON path or URL (default: update.askexe.com)
|
|
17134
17581
|
--target <version> Stack version to install (default: manifest.latest)
|
|
17135
17582
|
--compose-file <path> docker-compose.yml path (default: ./docker-compose.yml or /opt/exe-stack/docker-compose.yml)
|
|
17136
17583
|
--env-file <path> .env path (default: ./.env or /opt/exe-stack/.env)
|
|
17137
17584
|
--lock-file <path> Lock file path (default: beside .env)
|
|
17138
17585
|
--check Print available changes only
|
|
17139
17586
|
--dry-run Plan only; do not run Docker
|
|
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
|
|
17593
|
+
--rollback Restore latest backed-up .env and restart stack
|
|
17140
17594
|
--allow-breaking <ids> Confirm breaking changes, comma-separated
|
|
17141
17595
|
-y, --yes Non-interactive confirmation
|
|
17142
17596
|
`);
|
|
@@ -17164,7 +17618,16 @@ function printBreaking(changes) {
|
|
|
17164
17618
|
}
|
|
17165
17619
|
async function main3() {
|
|
17166
17620
|
const opts = parseArgs4(process.argv.slice(2));
|
|
17167
|
-
|
|
17621
|
+
if (opts.rollback) {
|
|
17622
|
+
if (!opts.yes) {
|
|
17623
|
+
console.error("Refusing to rollback without --yes.");
|
|
17624
|
+
process.exit(2);
|
|
17625
|
+
}
|
|
17626
|
+
const result2 = await runStackUpdate(opts);
|
|
17627
|
+
console.log(`\u2705 Stack rollback attempted using backup: ${result2.backupEnvFile ?? "latest backup"}`);
|
|
17628
|
+
return;
|
|
17629
|
+
}
|
|
17630
|
+
const manifest = await loadStackManifest(opts.manifestRef, void 0, opts.manifestPublicKey, opts.manifestAuthToken);
|
|
17168
17631
|
const envRaw = readFileSync26(opts.envFile, "utf8");
|
|
17169
17632
|
const plan = createStackUpdatePlan(manifest, envRaw, opts.targetVersion);
|
|
17170
17633
|
console.log(`Exe OS stack target: ${plan.targetVersion}`);
|
|
@@ -32104,7 +32567,7 @@ var init_mcp_diagnostics = __esm({
|
|
|
32104
32567
|
});
|
|
32105
32568
|
|
|
32106
32569
|
// src/bin/cli.ts
|
|
32107
|
-
import { existsSync as existsSync35, readFileSync as readFileSync30, writeFileSync as writeFileSync21, readdirSync as
|
|
32570
|
+
import { existsSync as existsSync35, readFileSync as readFileSync30, writeFileSync as writeFileSync21, readdirSync as readdirSync11, rmSync } from "fs";
|
|
32108
32571
|
import path49 from "path";
|
|
32109
32572
|
import os22 from "os";
|
|
32110
32573
|
var args = process.argv.slice(2);
|
|
@@ -32553,7 +33016,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
32553
33016
|
if (existsSync35(skillsDir)) {
|
|
32554
33017
|
let skillCount = 0;
|
|
32555
33018
|
try {
|
|
32556
|
-
const entries =
|
|
33019
|
+
const entries = readdirSync11(skillsDir);
|
|
32557
33020
|
for (const entry of entries) {
|
|
32558
33021
|
if (entry.startsWith("exe")) {
|
|
32559
33022
|
const fullPath = path49.join(skillsDir, entry);
|
|
@@ -32586,7 +33049,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
32586
33049
|
if (existsSync35(agentsDir)) {
|
|
32587
33050
|
let agentCount = 0;
|
|
32588
33051
|
try {
|
|
32589
|
-
const entries =
|
|
33052
|
+
const entries = readdirSync11(agentsDir).filter((f) => f.endsWith(".md"));
|
|
32590
33053
|
let knownNames = /* @__PURE__ */ new Set();
|
|
32591
33054
|
const rosterPath = path49.join(exeOsDir, "exe-employees.json");
|
|
32592
33055
|
if (existsSync35(rosterPath)) {
|
|
@@ -32614,7 +33077,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
32614
33077
|
if (existsSync35(projectsDir)) {
|
|
32615
33078
|
let projectCount = 0;
|
|
32616
33079
|
try {
|
|
32617
|
-
const projects =
|
|
33080
|
+
const projects = readdirSync11(projectsDir);
|
|
32618
33081
|
for (const proj of projects) {
|
|
32619
33082
|
const projSettings = path49.join(projectsDir, proj, "settings.json");
|
|
32620
33083
|
if (!existsSync35(projSettings)) continue;
|