@askexenow/exe-os 0.9.66 → 0.9.67
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 +54 -5
- package/dist/bin/age-ontology-load.js +61 -0
- package/dist/bin/agentic-ontology-backfill.js +4708 -0
- package/dist/bin/agentic-reflection-backfill.js +4144 -0
- package/dist/bin/{exe-link.js → agentic-semantic-label.js} +1523 -2275
- package/dist/bin/backfill-conversations.js +506 -20
- package/dist/bin/backfill-responses.js +506 -20
- package/dist/bin/backfill-vectors.js +233 -20
- package/dist/bin/bulk-sync-postgres.js +4876 -0
- package/dist/bin/cleanup-stale-review-tasks.js +507 -21
- package/dist/bin/cli.js +2450 -1530
- package/dist/bin/exe-assign.js +506 -20
- package/dist/bin/exe-boot.js +410 -60
- package/dist/bin/exe-cloud.js +795 -105
- package/dist/bin/exe-dispatch.js +516 -22
- package/dist/bin/exe-doctor.js +587 -30
- package/dist/bin/exe-export-behaviors.js +518 -24
- package/dist/bin/exe-forget.js +507 -21
- package/dist/bin/exe-gateway.js +571 -25
- package/dist/bin/exe-heartbeat.js +518 -24
- package/dist/bin/exe-kill.js +507 -21
- package/dist/bin/exe-launch-agent.js +2312 -1069
- package/dist/bin/exe-new-employee.js +197 -165
- package/dist/bin/exe-pending-messages.js +507 -21
- package/dist/bin/exe-pending-notifications.js +507 -21
- package/dist/bin/exe-pending-reviews.js +507 -21
- package/dist/bin/exe-rename.js +507 -21
- package/dist/bin/exe-review.js +507 -21
- package/dist/bin/exe-search.js +518 -24
- package/dist/bin/exe-session-cleanup.js +516 -22
- package/dist/bin/exe-settings.js +4 -0
- package/dist/bin/exe-start-codex.js +682 -143
- package/dist/bin/exe-start-opencode.js +627 -79
- package/dist/bin/exe-status.js +507 -21
- package/dist/bin/exe-team.js +507 -21
- package/dist/bin/git-sweep.js +516 -22
- package/dist/bin/graph-backfill.js +558 -21
- package/dist/bin/graph-export.js +507 -21
- package/dist/bin/graph-layer-benchmark.js +109 -0
- package/dist/bin/install.js +305 -288
- package/dist/bin/intercom-check.js +516 -22
- package/dist/bin/postgres-agentic-reflection-backfill.js +187 -0
- package/dist/bin/postgres-agentic-semantic-backfill.js +237 -0
- package/dist/bin/scan-tasks.js +516 -22
- package/dist/bin/setup.js +412 -62
- package/dist/bin/shard-migrate.js +506 -20
- package/dist/gateway/index.js +569 -23
- package/dist/hooks/bug-report-worker.js +519 -25
- package/dist/hooks/codex-stop-task-finalizer.js +516 -22
- package/dist/hooks/commit-complete.js +516 -22
- package/dist/hooks/error-recall.js +518 -24
- package/dist/hooks/ingest.js +516 -22
- package/dist/hooks/instructions-loaded.js +507 -21
- package/dist/hooks/notification.js +507 -21
- package/dist/hooks/post-compact.js +507 -21
- package/dist/hooks/post-tool-combined.js +519 -25
- package/dist/hooks/pre-compact.js +516 -22
- package/dist/hooks/pre-tool-use.js +507 -21
- package/dist/hooks/prompt-submit.js +519 -25
- package/dist/hooks/session-end.js +516 -22
- package/dist/hooks/session-start.js +520 -26
- package/dist/hooks/stop.js +517 -23
- package/dist/hooks/subagent-stop.js +507 -21
- package/dist/hooks/summary-worker.js +411 -61
- package/dist/index.js +569 -23
- package/dist/lib/cloud-sync.js +391 -53
- package/dist/lib/config.js +13 -1
- package/dist/lib/consolidation.js +1 -1
- package/dist/lib/database.js +124 -0
- package/dist/lib/db.js +124 -0
- package/dist/lib/device-registry.js +124 -0
- package/dist/lib/embedder.js +13 -1
- package/dist/lib/exe-daemon.js +2184 -561
- package/dist/lib/hybrid-search.js +518 -24
- package/dist/lib/identity.js +3 -0
- package/dist/lib/keychain.js +178 -22
- package/dist/lib/messaging.js +3 -0
- package/dist/lib/reminders.js +3 -0
- package/dist/lib/schedules.js +233 -20
- package/dist/lib/skill-learning.js +16 -1
- package/dist/lib/store.js +506 -20
- package/dist/lib/tasks.js +16 -1
- package/dist/lib/tmux-routing.js +16 -1
- package/dist/lib/token-spend.js +3 -0
- package/dist/mcp/server.js +1757 -428
- package/dist/mcp/tools/complete-reminder.js +3 -0
- package/dist/mcp/tools/create-reminder.js +3 -0
- package/dist/mcp/tools/create-task.js +16 -1
- package/dist/mcp/tools/deactivate-behavior.js +3 -0
- package/dist/mcp/tools/list-reminders.js +3 -0
- package/dist/mcp/tools/list-tasks.js +3 -0
- package/dist/mcp/tools/send-message.js +3 -0
- package/dist/mcp/tools/update-task.js +16 -1
- package/dist/runtime/index.js +516 -22
- package/dist/tui/App.js +594 -29
- package/package.json +8 -5
- package/src/commands/exe/cloud.md +6 -10
- package/stack.release.json +3 -3
- package/src/commands/exe/link.md +0 -18
package/dist/lib/cloud-sync.js
CHANGED
|
@@ -1471,6 +1471,9 @@ function getClient() {
|
|
|
1471
1471
|
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
1472
1472
|
return _daemonClient;
|
|
1473
1473
|
}
|
|
1474
|
+
if (!_resilientClient) {
|
|
1475
|
+
return _adapterClient;
|
|
1476
|
+
}
|
|
1474
1477
|
return _resilientClient;
|
|
1475
1478
|
}
|
|
1476
1479
|
async function initDaemonClient() {
|
|
@@ -2503,6 +2506,127 @@ async function ensureSchema() {
|
|
|
2503
2506
|
VALUES (new.rowid, new.content, new.subject, new.predicate, new.object);
|
|
2504
2507
|
END;
|
|
2505
2508
|
`);
|
|
2509
|
+
await client.executeMultiple(`
|
|
2510
|
+
CREATE TABLE IF NOT EXISTS agent_sessions (
|
|
2511
|
+
id TEXT PRIMARY KEY,
|
|
2512
|
+
agent_id TEXT NOT NULL,
|
|
2513
|
+
project_name TEXT,
|
|
2514
|
+
started_at TEXT NOT NULL,
|
|
2515
|
+
last_event_at TEXT NOT NULL,
|
|
2516
|
+
event_count INTEGER NOT NULL DEFAULT 0,
|
|
2517
|
+
properties TEXT DEFAULT '{}'
|
|
2518
|
+
);
|
|
2519
|
+
|
|
2520
|
+
CREATE INDEX IF NOT EXISTS idx_agent_sessions_agent_time
|
|
2521
|
+
ON agent_sessions(agent_id, started_at);
|
|
2522
|
+
|
|
2523
|
+
CREATE TABLE IF NOT EXISTS agent_goals (
|
|
2524
|
+
id TEXT PRIMARY KEY,
|
|
2525
|
+
statement TEXT NOT NULL,
|
|
2526
|
+
owner_agent_id TEXT,
|
|
2527
|
+
project_name TEXT,
|
|
2528
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
2529
|
+
priority INTEGER NOT NULL DEFAULT 5,
|
|
2530
|
+
success_criteria TEXT,
|
|
2531
|
+
parent_goal_id TEXT,
|
|
2532
|
+
due_at TEXT,
|
|
2533
|
+
achieved_at TEXT,
|
|
2534
|
+
supersedes_id TEXT,
|
|
2535
|
+
created_at TEXT NOT NULL,
|
|
2536
|
+
updated_at TEXT NOT NULL,
|
|
2537
|
+
source_memory_id TEXT
|
|
2538
|
+
);
|
|
2539
|
+
|
|
2540
|
+
CREATE INDEX IF NOT EXISTS idx_agent_goals_project_status
|
|
2541
|
+
ON agent_goals(project_name, status, priority);
|
|
2542
|
+
|
|
2543
|
+
CREATE TABLE IF NOT EXISTS agent_events (
|
|
2544
|
+
id TEXT PRIMARY KEY,
|
|
2545
|
+
event_type TEXT NOT NULL,
|
|
2546
|
+
occurred_at TEXT NOT NULL,
|
|
2547
|
+
sequence_index INTEGER NOT NULL,
|
|
2548
|
+
actor_agent_id TEXT,
|
|
2549
|
+
agent_role TEXT,
|
|
2550
|
+
project_name TEXT,
|
|
2551
|
+
session_id TEXT,
|
|
2552
|
+
task_id TEXT,
|
|
2553
|
+
goal_id TEXT,
|
|
2554
|
+
parent_event_id TEXT,
|
|
2555
|
+
intention TEXT,
|
|
2556
|
+
outcome TEXT,
|
|
2557
|
+
evidence_memory_id TEXT,
|
|
2558
|
+
impact TEXT,
|
|
2559
|
+
payload TEXT DEFAULT '{}',
|
|
2560
|
+
created_at TEXT NOT NULL
|
|
2561
|
+
);
|
|
2562
|
+
|
|
2563
|
+
CREATE INDEX IF NOT EXISTS idx_agent_events_time
|
|
2564
|
+
ON agent_events(occurred_at, sequence_index);
|
|
2565
|
+
|
|
2566
|
+
CREATE INDEX IF NOT EXISTS idx_agent_events_session_seq
|
|
2567
|
+
ON agent_events(session_id, sequence_index);
|
|
2568
|
+
|
|
2569
|
+
CREATE INDEX IF NOT EXISTS idx_agent_events_goal_time
|
|
2570
|
+
ON agent_events(goal_id, occurred_at);
|
|
2571
|
+
|
|
2572
|
+
CREATE INDEX IF NOT EXISTS idx_agent_events_memory
|
|
2573
|
+
ON agent_events(evidence_memory_id);
|
|
2574
|
+
|
|
2575
|
+
CREATE TABLE IF NOT EXISTS agent_goal_links (
|
|
2576
|
+
id TEXT PRIMARY KEY,
|
|
2577
|
+
goal_id TEXT NOT NULL,
|
|
2578
|
+
link_type TEXT NOT NULL,
|
|
2579
|
+
target_id TEXT NOT NULL,
|
|
2580
|
+
target_type TEXT NOT NULL,
|
|
2581
|
+
created_at TEXT NOT NULL
|
|
2582
|
+
);
|
|
2583
|
+
|
|
2584
|
+
CREATE INDEX IF NOT EXISTS idx_agent_goal_links_goal
|
|
2585
|
+
ON agent_goal_links(goal_id, target_type);
|
|
2586
|
+
|
|
2587
|
+
CREATE TABLE IF NOT EXISTS agent_semantic_labels (
|
|
2588
|
+
id TEXT PRIMARY KEY,
|
|
2589
|
+
source_memory_id TEXT NOT NULL,
|
|
2590
|
+
event_id TEXT,
|
|
2591
|
+
labeler TEXT NOT NULL,
|
|
2592
|
+
schema_version INTEGER NOT NULL DEFAULT 1,
|
|
2593
|
+
confidence REAL NOT NULL DEFAULT 0,
|
|
2594
|
+
labels TEXT NOT NULL,
|
|
2595
|
+
created_at TEXT NOT NULL,
|
|
2596
|
+
updated_at TEXT NOT NULL
|
|
2597
|
+
);
|
|
2598
|
+
|
|
2599
|
+
CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_memory
|
|
2600
|
+
ON agent_semantic_labels(source_memory_id, labeler);
|
|
2601
|
+
|
|
2602
|
+
CREATE INDEX IF NOT EXISTS idx_agent_semantic_labels_event
|
|
2603
|
+
ON agent_semantic_labels(event_id);
|
|
2604
|
+
|
|
2605
|
+
CREATE TABLE IF NOT EXISTS agent_reflection_checkpoints (
|
|
2606
|
+
id TEXT PRIMARY KEY,
|
|
2607
|
+
project_name TEXT,
|
|
2608
|
+
session_id TEXT,
|
|
2609
|
+
window_start_at TEXT NOT NULL,
|
|
2610
|
+
window_end_at TEXT NOT NULL,
|
|
2611
|
+
event_count INTEGER NOT NULL DEFAULT 0,
|
|
2612
|
+
goal_count INTEGER NOT NULL DEFAULT 0,
|
|
2613
|
+
success_count INTEGER NOT NULL DEFAULT 0,
|
|
2614
|
+
failure_count INTEGER NOT NULL DEFAULT 0,
|
|
2615
|
+
risk_count INTEGER NOT NULL DEFAULT 0,
|
|
2616
|
+
summary TEXT NOT NULL,
|
|
2617
|
+
learnings TEXT NOT NULL DEFAULT '[]',
|
|
2618
|
+
next_actions TEXT NOT NULL DEFAULT '[]',
|
|
2619
|
+
evidence_event_ids TEXT NOT NULL DEFAULT '[]',
|
|
2620
|
+
confidence REAL NOT NULL DEFAULT 0,
|
|
2621
|
+
created_at TEXT NOT NULL
|
|
2622
|
+
);
|
|
2623
|
+
|
|
2624
|
+
CREATE INDEX IF NOT EXISTS idx_agent_reflection_project_time
|
|
2625
|
+
ON agent_reflection_checkpoints(project_name, window_end_at);
|
|
2626
|
+
|
|
2627
|
+
CREATE INDEX IF NOT EXISTS idx_agent_reflection_session_time
|
|
2628
|
+
ON agent_reflection_checkpoints(session_id, window_end_at);
|
|
2629
|
+
`);
|
|
2506
2630
|
try {
|
|
2507
2631
|
await client.execute({
|
|
2508
2632
|
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
@@ -2881,12 +3005,13 @@ var keychain_exports = {};
|
|
|
2881
3005
|
__export(keychain_exports, {
|
|
2882
3006
|
deleteMasterKey: () => deleteMasterKey,
|
|
2883
3007
|
exportMnemonic: () => exportMnemonic,
|
|
3008
|
+
getKeyStorageInfo: () => getKeyStorageInfo,
|
|
2884
3009
|
getMasterKey: () => getMasterKey,
|
|
2885
3010
|
importMnemonic: () => importMnemonic,
|
|
2886
3011
|
setMasterKey: () => setMasterKey
|
|
2887
3012
|
});
|
|
2888
3013
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2889
|
-
import { existsSync as existsSync8 } from "fs";
|
|
3014
|
+
import { existsSync as existsSync8, statSync as statSync2 } from "fs";
|
|
2890
3015
|
import { execSync as execSync2 } from "child_process";
|
|
2891
3016
|
import path8 from "path";
|
|
2892
3017
|
import os6 from "os";
|
|
@@ -2896,29 +3021,65 @@ function getKeyDir() {
|
|
|
2896
3021
|
function getKeyPath() {
|
|
2897
3022
|
return path8.join(getKeyDir(), "master.key");
|
|
2898
3023
|
}
|
|
2899
|
-
function
|
|
3024
|
+
function nativeKeychainAllowed() {
|
|
3025
|
+
return process.env.EXE_OS_DISABLE_NATIVE_KEYCHAIN !== "1";
|
|
3026
|
+
}
|
|
3027
|
+
function linuxSecretAvailable() {
|
|
3028
|
+
if (!nativeKeychainAllowed()) return false;
|
|
3029
|
+
if (process.platform !== "linux") return false;
|
|
3030
|
+
if (linuxSecretAvailability !== null) return linuxSecretAvailability;
|
|
3031
|
+
try {
|
|
3032
|
+
execSync2("command -v secret-tool >/dev/null 2>&1", { timeout: 1e3 });
|
|
3033
|
+
} catch {
|
|
3034
|
+
linuxSecretAvailability = false;
|
|
3035
|
+
return false;
|
|
3036
|
+
}
|
|
3037
|
+
try {
|
|
3038
|
+
execSync2("secret-tool search --all exe-os probe >/dev/null 2>&1", { timeout: 1e3 });
|
|
3039
|
+
linuxSecretAvailability = true;
|
|
3040
|
+
} catch {
|
|
3041
|
+
linuxSecretAvailability = false;
|
|
3042
|
+
}
|
|
3043
|
+
return linuxSecretAvailability;
|
|
3044
|
+
}
|
|
3045
|
+
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
3046
|
+
if (process.platform !== "linux") return false;
|
|
3047
|
+
try {
|
|
3048
|
+
const uid = typeof os6.userInfo().uid === "number" ? os6.userInfo().uid : -1;
|
|
3049
|
+
const st = statSync2(keyPath);
|
|
3050
|
+
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
3051
|
+
if (uid === 0) return true;
|
|
3052
|
+
const exeOsDir = process.env.EXE_OS_DIR;
|
|
3053
|
+
return Boolean(exeOsDir && path8.resolve(keyPath).startsWith(path8.resolve(exeOsDir) + path8.sep));
|
|
3054
|
+
} catch {
|
|
3055
|
+
return false;
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
function macKeychainGet(service = SERVICE) {
|
|
3059
|
+
if (!nativeKeychainAllowed()) return null;
|
|
2900
3060
|
if (process.platform !== "darwin") return null;
|
|
2901
3061
|
try {
|
|
2902
3062
|
return execSync2(
|
|
2903
|
-
`security find-generic-password -s "${
|
|
3063
|
+
`security find-generic-password -s "${service}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
2904
3064
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
2905
3065
|
).trim();
|
|
2906
3066
|
} catch {
|
|
2907
3067
|
return null;
|
|
2908
3068
|
}
|
|
2909
3069
|
}
|
|
2910
|
-
function macKeychainSet(value) {
|
|
3070
|
+
function macKeychainSet(value, service = SERVICE) {
|
|
3071
|
+
if (!nativeKeychainAllowed()) return false;
|
|
2911
3072
|
if (process.platform !== "darwin") return false;
|
|
2912
3073
|
try {
|
|
2913
3074
|
try {
|
|
2914
3075
|
execSync2(
|
|
2915
|
-
`security delete-generic-password -s "${
|
|
3076
|
+
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
2916
3077
|
{ timeout: 5e3 }
|
|
2917
3078
|
);
|
|
2918
3079
|
} catch {
|
|
2919
3080
|
}
|
|
2920
3081
|
execSync2(
|
|
2921
|
-
`security add-generic-password -s "${
|
|
3082
|
+
`security add-generic-password -s "${service}" -a "${ACCOUNT}" -w "${value}"`,
|
|
2922
3083
|
{ timeout: 5e3 }
|
|
2923
3084
|
);
|
|
2924
3085
|
return true;
|
|
@@ -2926,11 +3087,12 @@ function macKeychainSet(value) {
|
|
|
2926
3087
|
return false;
|
|
2927
3088
|
}
|
|
2928
3089
|
}
|
|
2929
|
-
function macKeychainDelete() {
|
|
3090
|
+
function macKeychainDelete(service = SERVICE) {
|
|
3091
|
+
if (!nativeKeychainAllowed()) return false;
|
|
2930
3092
|
if (process.platform !== "darwin") return false;
|
|
2931
3093
|
try {
|
|
2932
3094
|
execSync2(
|
|
2933
|
-
`security delete-generic-password -s "${
|
|
3095
|
+
`security delete-generic-password -s "${service}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
2934
3096
|
{ timeout: 5e3 }
|
|
2935
3097
|
);
|
|
2936
3098
|
return true;
|
|
@@ -2938,22 +3100,22 @@ function macKeychainDelete() {
|
|
|
2938
3100
|
return false;
|
|
2939
3101
|
}
|
|
2940
3102
|
}
|
|
2941
|
-
function linuxSecretGet() {
|
|
2942
|
-
if (
|
|
3103
|
+
function linuxSecretGet(service = SERVICE) {
|
|
3104
|
+
if (!linuxSecretAvailable()) return null;
|
|
2943
3105
|
try {
|
|
2944
3106
|
return execSync2(
|
|
2945
|
-
`secret-tool lookup service "${
|
|
3107
|
+
`secret-tool lookup service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2946
3108
|
{ encoding: "utf-8", timeout: 5e3 }
|
|
2947
3109
|
).trim();
|
|
2948
3110
|
} catch {
|
|
2949
3111
|
return null;
|
|
2950
3112
|
}
|
|
2951
3113
|
}
|
|
2952
|
-
function linuxSecretSet(value) {
|
|
2953
|
-
if (
|
|
3114
|
+
function linuxSecretSet(value, service = SERVICE) {
|
|
3115
|
+
if (!linuxSecretAvailable()) return false;
|
|
2954
3116
|
try {
|
|
2955
3117
|
execSync2(
|
|
2956
|
-
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${
|
|
3118
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2957
3119
|
{ timeout: 5e3 }
|
|
2958
3120
|
);
|
|
2959
3121
|
return true;
|
|
@@ -2961,11 +3123,12 @@ function linuxSecretSet(value) {
|
|
|
2961
3123
|
return false;
|
|
2962
3124
|
}
|
|
2963
3125
|
}
|
|
2964
|
-
function linuxSecretDelete() {
|
|
3126
|
+
function linuxSecretDelete(service = SERVICE) {
|
|
3127
|
+
if (!nativeKeychainAllowed()) return false;
|
|
2965
3128
|
if (process.platform !== "linux") return false;
|
|
2966
3129
|
try {
|
|
2967
3130
|
execSync2(
|
|
2968
|
-
`secret-tool clear service "${
|
|
3131
|
+
`secret-tool clear service "${service}" account "${ACCOUNT}" 2>/dev/null`,
|
|
2969
3132
|
{ timeout: 5e3 }
|
|
2970
3133
|
);
|
|
2971
3134
|
return true;
|
|
@@ -2974,6 +3137,7 @@ function linuxSecretDelete() {
|
|
|
2974
3137
|
}
|
|
2975
3138
|
}
|
|
2976
3139
|
async function tryKeytar() {
|
|
3140
|
+
if (!nativeKeychainAllowed()) return null;
|
|
2977
3141
|
try {
|
|
2978
3142
|
return await import("keytar");
|
|
2979
3143
|
} catch {
|
|
@@ -3047,7 +3211,19 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
3047
3211
|
return "plaintext";
|
|
3048
3212
|
}
|
|
3049
3213
|
async function getMasterKey() {
|
|
3050
|
-
|
|
3214
|
+
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
3215
|
+
if (!nativeValue) {
|
|
3216
|
+
const legacyValue = macKeychainGet(LEGACY_SERVICE) ?? linuxSecretGet(LEGACY_SERVICE);
|
|
3217
|
+
if (legacyValue) {
|
|
3218
|
+
const migrated = macKeychainSet(legacyValue) || linuxSecretSet(legacyValue);
|
|
3219
|
+
if (migrated) {
|
|
3220
|
+
macKeychainDelete(LEGACY_SERVICE);
|
|
3221
|
+
linuxSecretDelete(LEGACY_SERVICE);
|
|
3222
|
+
process.stderr.write("[keychain] Migrated keychain service from exe-mem to exe-os.\n");
|
|
3223
|
+
}
|
|
3224
|
+
nativeValue = legacyValue;
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3051
3227
|
if (nativeValue) {
|
|
3052
3228
|
return Buffer.from(nativeValue, "base64");
|
|
3053
3229
|
}
|
|
@@ -3055,12 +3231,17 @@ async function getMasterKey() {
|
|
|
3055
3231
|
if (keytar) {
|
|
3056
3232
|
try {
|
|
3057
3233
|
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
3058
|
-
|
|
3059
|
-
|
|
3234
|
+
const legacyKeytarValue = keytarValue ?? await keytar.getPassword(LEGACY_SERVICE, ACCOUNT);
|
|
3235
|
+
if (legacyKeytarValue) {
|
|
3236
|
+
const migrated = macKeychainSet(legacyKeytarValue) || linuxSecretSet(legacyKeytarValue);
|
|
3060
3237
|
if (migrated) {
|
|
3061
3238
|
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
3239
|
+
try {
|
|
3240
|
+
await keytar.deletePassword(LEGACY_SERVICE, ACCOUNT);
|
|
3241
|
+
} catch {
|
|
3242
|
+
}
|
|
3062
3243
|
}
|
|
3063
|
-
return Buffer.from(
|
|
3244
|
+
return Buffer.from(legacyKeytarValue, "base64");
|
|
3064
3245
|
}
|
|
3065
3246
|
} catch {
|
|
3066
3247
|
}
|
|
@@ -3085,7 +3266,7 @@ async function getMasterKey() {
|
|
|
3085
3266
|
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
3086
3267
|
if (!decrypted) {
|
|
3087
3268
|
process.stderr.write(
|
|
3088
|
-
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os
|
|
3269
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase during setup: exe-os setup\n"
|
|
3089
3270
|
);
|
|
3090
3271
|
return null;
|
|
3091
3272
|
}
|
|
@@ -3094,6 +3275,9 @@ async function getMasterKey() {
|
|
|
3094
3275
|
b64Value = content;
|
|
3095
3276
|
}
|
|
3096
3277
|
const key = Buffer.from(b64Value, "base64");
|
|
3278
|
+
if (!content.startsWith(ENCRYPTED_PREFIX) && isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
3279
|
+
return key;
|
|
3280
|
+
}
|
|
3097
3281
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
3098
3282
|
if (migrated) {
|
|
3099
3283
|
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
@@ -3121,6 +3305,97 @@ async function getMasterKey() {
|
|
|
3121
3305
|
return null;
|
|
3122
3306
|
}
|
|
3123
3307
|
}
|
|
3308
|
+
async function getKeyStorageInfo() {
|
|
3309
|
+
if (macKeychainGet()) {
|
|
3310
|
+
return {
|
|
3311
|
+
kind: "macos-keychain",
|
|
3312
|
+
secure: true,
|
|
3313
|
+
note: "stored in macOS Keychain via built-in security CLI"
|
|
3314
|
+
};
|
|
3315
|
+
}
|
|
3316
|
+
if (macKeychainGet(LEGACY_SERVICE)) {
|
|
3317
|
+
return {
|
|
3318
|
+
kind: "macos-keychain",
|
|
3319
|
+
secure: true,
|
|
3320
|
+
note: "stored in legacy macOS Keychain service exe-mem; next key read migrates it to exe-os"
|
|
3321
|
+
};
|
|
3322
|
+
}
|
|
3323
|
+
if (linuxSecretGet()) {
|
|
3324
|
+
return {
|
|
3325
|
+
kind: "linux-secret-service",
|
|
3326
|
+
secure: true,
|
|
3327
|
+
note: "stored in Linux Secret Service via secret-tool"
|
|
3328
|
+
};
|
|
3329
|
+
}
|
|
3330
|
+
if (linuxSecretGet(LEGACY_SERVICE)) {
|
|
3331
|
+
return {
|
|
3332
|
+
kind: "linux-secret-service",
|
|
3333
|
+
secure: true,
|
|
3334
|
+
note: "stored in legacy Linux Secret Service service exe-mem; next key read migrates it to exe-os"
|
|
3335
|
+
};
|
|
3336
|
+
}
|
|
3337
|
+
const keytar = await tryKeytar();
|
|
3338
|
+
if (keytar) {
|
|
3339
|
+
try {
|
|
3340
|
+
if (await keytar.getPassword(SERVICE, ACCOUNT)) {
|
|
3341
|
+
return {
|
|
3342
|
+
kind: "legacy-keytar",
|
|
3343
|
+
secure: true,
|
|
3344
|
+
note: "stored in legacy keytar backend; will migrate to native keychain when possible"
|
|
3345
|
+
};
|
|
3346
|
+
}
|
|
3347
|
+
if (await keytar.getPassword(LEGACY_SERVICE, ACCOUNT)) {
|
|
3348
|
+
return {
|
|
3349
|
+
kind: "legacy-keytar",
|
|
3350
|
+
secure: true,
|
|
3351
|
+
note: "stored in legacy keytar service exe-mem; will migrate to native exe-os keychain when possible"
|
|
3352
|
+
};
|
|
3353
|
+
}
|
|
3354
|
+
} catch {
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
const keyPath = getKeyPath();
|
|
3358
|
+
if (!existsSync8(keyPath)) {
|
|
3359
|
+
return {
|
|
3360
|
+
kind: "missing",
|
|
3361
|
+
secure: false,
|
|
3362
|
+
path: keyPath,
|
|
3363
|
+
note: "no key found in OS keychain, legacy keytar, or file fallback"
|
|
3364
|
+
};
|
|
3365
|
+
}
|
|
3366
|
+
try {
|
|
3367
|
+
const content = (await readFile3(keyPath, "utf-8")).trim();
|
|
3368
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
3369
|
+
return {
|
|
3370
|
+
kind: "encrypted-file",
|
|
3371
|
+
secure: true,
|
|
3372
|
+
path: keyPath,
|
|
3373
|
+
note: "stored in machine-bound encrypted file fallback"
|
|
3374
|
+
};
|
|
3375
|
+
}
|
|
3376
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
3377
|
+
return {
|
|
3378
|
+
kind: "server-secret-file",
|
|
3379
|
+
secure: true,
|
|
3380
|
+
path: keyPath,
|
|
3381
|
+
note: "stored as root-only trusted server secret file"
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
return {
|
|
3385
|
+
kind: "plaintext-file",
|
|
3386
|
+
secure: false,
|
|
3387
|
+
path: keyPath,
|
|
3388
|
+
note: "stored in legacy plaintext file; reading it will migrate or encrypt it"
|
|
3389
|
+
};
|
|
3390
|
+
} catch {
|
|
3391
|
+
return {
|
|
3392
|
+
kind: "missing",
|
|
3393
|
+
secure: false,
|
|
3394
|
+
path: keyPath,
|
|
3395
|
+
note: "key file exists but could not be read"
|
|
3396
|
+
};
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3124
3399
|
async function setMasterKey(key) {
|
|
3125
3400
|
const b64 = key.toString("base64");
|
|
3126
3401
|
if (macKeychainSet(b64) || linuxSecretSet(b64)) {
|
|
@@ -3146,10 +3421,13 @@ async function setMasterKey(key) {
|
|
|
3146
3421
|
async function deleteMasterKey() {
|
|
3147
3422
|
macKeychainDelete();
|
|
3148
3423
|
linuxSecretDelete();
|
|
3424
|
+
macKeychainDelete(LEGACY_SERVICE);
|
|
3425
|
+
linuxSecretDelete(LEGACY_SERVICE);
|
|
3149
3426
|
const keytar = await tryKeytar();
|
|
3150
3427
|
if (keytar) {
|
|
3151
3428
|
try {
|
|
3152
3429
|
await keytar.deletePassword(SERVICE, ACCOUNT);
|
|
3430
|
+
await keytar.deletePassword(LEGACY_SERVICE, ACCOUNT);
|
|
3153
3431
|
} catch {
|
|
3154
3432
|
}
|
|
3155
3433
|
}
|
|
@@ -3187,12 +3465,14 @@ async function importMnemonic(mnemonic) {
|
|
|
3187
3465
|
const entropy = mnemonicToEntropy(trimmed);
|
|
3188
3466
|
return Buffer.from(entropy, "hex");
|
|
3189
3467
|
}
|
|
3190
|
-
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
3468
|
+
var SERVICE, LEGACY_SERVICE, ACCOUNT, linuxSecretAvailability, ENCRYPTED_PREFIX;
|
|
3191
3469
|
var init_keychain = __esm({
|
|
3192
3470
|
"src/lib/keychain.ts"() {
|
|
3193
3471
|
"use strict";
|
|
3194
|
-
SERVICE = "exe-
|
|
3472
|
+
SERVICE = "exe-os";
|
|
3473
|
+
LEGACY_SERVICE = "exe-mem";
|
|
3195
3474
|
ACCOUNT = "master-key";
|
|
3475
|
+
linuxSecretAvailability = null;
|
|
3196
3476
|
ENCRYPTED_PREFIX = "enc:";
|
|
3197
3477
|
}
|
|
3198
3478
|
});
|
|
@@ -3208,7 +3488,7 @@ __export(db_backup_exports, {
|
|
|
3208
3488
|
listBackups: () => listBackups,
|
|
3209
3489
|
rotateBackups: () => rotateBackups
|
|
3210
3490
|
});
|
|
3211
|
-
import { copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync4, readdirSync, unlinkSync as unlinkSync4, statSync as
|
|
3491
|
+
import { copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync4, readdirSync, unlinkSync as unlinkSync4, statSync as statSync3 } from "fs";
|
|
3212
3492
|
import path9 from "path";
|
|
3213
3493
|
function findActiveDb() {
|
|
3214
3494
|
for (const name of DB_NAMES) {
|
|
@@ -3252,7 +3532,7 @@ function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
|
3252
3532
|
if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
|
|
3253
3533
|
const filePath = path9.join(BACKUP_DIR, file);
|
|
3254
3534
|
try {
|
|
3255
|
-
const stat =
|
|
3535
|
+
const stat = statSync3(filePath);
|
|
3256
3536
|
if (stat.mtimeMs < cutoff) {
|
|
3257
3537
|
unlinkSync4(filePath);
|
|
3258
3538
|
deleted++;
|
|
@@ -3270,7 +3550,7 @@ function listBackups() {
|
|
|
3270
3550
|
const files = readdirSync(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
|
|
3271
3551
|
return files.map((name) => {
|
|
3272
3552
|
const p = path9.join(BACKUP_DIR, name);
|
|
3273
|
-
const stat =
|
|
3553
|
+
const stat = statSync3(p);
|
|
3274
3554
|
return { path: p, name, size: stat.size, date: stat.mtime };
|
|
3275
3555
|
}).sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
3276
3556
|
} catch {
|
|
@@ -3302,7 +3582,7 @@ var init_db_backup = __esm({
|
|
|
3302
3582
|
|
|
3303
3583
|
// src/lib/cloud-sync.ts
|
|
3304
3584
|
init_database();
|
|
3305
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync10, readdirSync as readdirSync2, mkdirSync as mkdirSync5, appendFileSync, unlinkSync as unlinkSync5, openSync as openSync2, closeSync as closeSync2, statSync as
|
|
3585
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync10, readdirSync as readdirSync2, mkdirSync as mkdirSync5, appendFileSync, unlinkSync as unlinkSync5, openSync as openSync2, closeSync as closeSync2, statSync as statSync4 } from "fs";
|
|
3306
3586
|
import crypto3 from "crypto";
|
|
3307
3587
|
import path10 from "path";
|
|
3308
3588
|
import { homedir as homedir2 } from "os";
|
|
@@ -3457,18 +3737,36 @@ function loadPgClient() {
|
|
|
3457
3737
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
3458
3738
|
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
3459
3739
|
if (explicitPath) {
|
|
3460
|
-
const
|
|
3461
|
-
const
|
|
3462
|
-
if (!
|
|
3463
|
-
return new
|
|
3740
|
+
const mod = await import(pathToFileURL3(explicitPath).href);
|
|
3741
|
+
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
3742
|
+
if (!Ctor) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
3743
|
+
return new Ctor();
|
|
3464
3744
|
}
|
|
3465
3745
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path10.join(homedir2(), "exe-db");
|
|
3466
|
-
const
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3746
|
+
const packagePath = path10.join(exeDbRoot, "package.json");
|
|
3747
|
+
if (existsSync10(packagePath)) {
|
|
3748
|
+
const req = createRequire3(packagePath);
|
|
3749
|
+
const entry = req.resolve("@prisma/client");
|
|
3750
|
+
const mod = await import(pathToFileURL3(entry).href);
|
|
3751
|
+
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
3752
|
+
if (!Ctor) throw new Error("No PrismaClient");
|
|
3753
|
+
return new Ctor();
|
|
3754
|
+
}
|
|
3755
|
+
const { Pool } = await import("pg");
|
|
3756
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
3757
|
+
return {
|
|
3758
|
+
async $queryRawUnsafe(query, ...values) {
|
|
3759
|
+
const result = await pool.query(query, values);
|
|
3760
|
+
return result.rows;
|
|
3761
|
+
},
|
|
3762
|
+
async $executeRawUnsafe(query, ...values) {
|
|
3763
|
+
const result = await pool.query(query, values);
|
|
3764
|
+
return result.rowCount ?? 0;
|
|
3765
|
+
},
|
|
3766
|
+
async $disconnect() {
|
|
3767
|
+
await pool.end();
|
|
3768
|
+
}
|
|
3769
|
+
};
|
|
3472
3770
|
})().catch(() => {
|
|
3473
3771
|
_pgFailed = true;
|
|
3474
3772
|
_pgPromise = null;
|
|
@@ -3489,7 +3787,7 @@ async function pushToPostgres(records) {
|
|
|
3489
3787
|
let inserted = 0;
|
|
3490
3788
|
for (const rec of records) {
|
|
3491
3789
|
try {
|
|
3492
|
-
await prisma.$executeRawUnsafe(
|
|
3790
|
+
const changed = await prisma.$executeRawUnsafe(
|
|
3493
3791
|
`INSERT INTO raw.raw_events (id, source, source_id, event_type, payload, metadata, timestamp)
|
|
3494
3792
|
VALUES (gen_random_uuid(), 'cloud_sync', $1, 'memory', $2::jsonb, $3::jsonb, $4)
|
|
3495
3793
|
ON CONFLICT (source, source_id, event_type) DO NOTHING`,
|
|
@@ -3498,7 +3796,7 @@ async function pushToPostgres(records) {
|
|
|
3498
3796
|
JSON.stringify({ agent_id: rec.agent_id, project_name: rec.project_name, tool_name: rec.tool_name }),
|
|
3499
3797
|
rec.timestamp ? new Date(String(rec.timestamp)) : /* @__PURE__ */ new Date()
|
|
3500
3798
|
);
|
|
3501
|
-
inserted
|
|
3799
|
+
inserted += Number(changed ?? 0);
|
|
3502
3800
|
} catch {
|
|
3503
3801
|
}
|
|
3504
3802
|
}
|
|
@@ -3603,6 +3901,23 @@ async function cloudPush(records, maxVersion, config) {
|
|
|
3603
3901
|
return false;
|
|
3604
3902
|
}
|
|
3605
3903
|
}
|
|
3904
|
+
async function cloudResetMemoryBlobs(config) {
|
|
3905
|
+
assertSecureEndpoint(config.endpoint);
|
|
3906
|
+
const resp = await fetchWithRetry(`${config.endpoint}/sync/reset-memory`, {
|
|
3907
|
+
method: "POST",
|
|
3908
|
+
headers: {
|
|
3909
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
3910
|
+
"Content-Type": "application/json",
|
|
3911
|
+
"X-Device-Id": loadDeviceId()
|
|
3912
|
+
},
|
|
3913
|
+
body: JSON.stringify({ confirm: "LOCAL DB IS SOURCE OF TRUTH" })
|
|
3914
|
+
});
|
|
3915
|
+
if (!resp.ok) {
|
|
3916
|
+
throw new Error(`cloud reset failed: HTTP ${resp.status}`);
|
|
3917
|
+
}
|
|
3918
|
+
const data = await resp.json();
|
|
3919
|
+
return { deleted: Number(data.deleted ?? 0), freedBytes: Number(data.freed_bytes ?? 0) };
|
|
3920
|
+
}
|
|
3606
3921
|
async function cloudPull(sinceVersion, config) {
|
|
3607
3922
|
assertSecureEndpoint(config.endpoint);
|
|
3608
3923
|
try {
|
|
@@ -3622,41 +3937,62 @@ async function cloudPull(sinceVersion, config) {
|
|
|
3622
3937
|
if (!response.ok) return { records: [], maxVersion: sinceVersion };
|
|
3623
3938
|
const data = await response.json();
|
|
3624
3939
|
const allRecords = [];
|
|
3625
|
-
|
|
3940
|
+
let maxReadableVersion = sinceVersion;
|
|
3941
|
+
let skippedBlobs = 0;
|
|
3942
|
+
for (const { version, blob } of data.blobs ?? []) {
|
|
3626
3943
|
try {
|
|
3627
3944
|
const compressed = decryptSyncBlob(blob);
|
|
3628
3945
|
const json = decompress(compressed).toString("utf8");
|
|
3629
3946
|
const records = JSON.parse(json);
|
|
3630
3947
|
allRecords.push(...records);
|
|
3948
|
+
const recordMax = records.reduce((max, rec) => {
|
|
3949
|
+
const v = Number(rec.version ?? 0);
|
|
3950
|
+
return Number.isFinite(v) ? Math.max(max, v) : max;
|
|
3951
|
+
}, 0);
|
|
3952
|
+
const blobVersion = Number(version ?? 0);
|
|
3953
|
+
maxReadableVersion = Math.max(
|
|
3954
|
+
maxReadableVersion,
|
|
3955
|
+
Number.isFinite(blobVersion) ? blobVersion : 0,
|
|
3956
|
+
recordMax
|
|
3957
|
+
);
|
|
3631
3958
|
} catch {
|
|
3959
|
+
skippedBlobs++;
|
|
3632
3960
|
continue;
|
|
3633
3961
|
}
|
|
3634
3962
|
}
|
|
3635
|
-
|
|
3963
|
+
if (skippedBlobs > 0) {
|
|
3964
|
+
logError(`[cloud-sync] PULL skipped ${skippedBlobs} undecryptable blob(s); pull cursor advanced only to last readable version ${maxReadableVersion}`);
|
|
3965
|
+
}
|
|
3966
|
+
return { records: allRecords, maxVersion: maxReadableVersion };
|
|
3636
3967
|
} catch (err) {
|
|
3637
3968
|
logError(`[cloud-sync] PULL FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
3638
3969
|
return { records: [], maxVersion: sinceVersion };
|
|
3639
3970
|
}
|
|
3640
3971
|
}
|
|
3641
|
-
var
|
|
3642
|
-
async function
|
|
3972
|
+
var CLOUD_REUPLOAD_REQUIRED_MESSAGE = "Cloud sync is blocked because this device rotated its memory encryption key. Run `exe-os cloud reupload` first to re-upload the cloud backup with the new key.";
|
|
3973
|
+
async function getCloudReuploadRequired(client = getClient()) {
|
|
3643
3974
|
try {
|
|
3644
3975
|
await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
|
|
3645
|
-
const
|
|
3646
|
-
return String(
|
|
3976
|
+
const result = await client.execute("SELECT key, value FROM sync_meta WHERE key IN ('cloud_reupload_required', 'cloud_relink_required')");
|
|
3977
|
+
return result.rows.some((row) => String(row.value ?? "") === "1");
|
|
3647
3978
|
} catch {
|
|
3648
3979
|
return false;
|
|
3649
3980
|
}
|
|
3650
3981
|
}
|
|
3651
|
-
async function
|
|
3982
|
+
async function clearCloudReuploadRequired(client = getClient()) {
|
|
3652
3983
|
await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
|
|
3984
|
+
await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reupload_required', '0')");
|
|
3653
3985
|
await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_relink_required', '0')");
|
|
3654
3986
|
await client.execute({
|
|
3655
|
-
sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('
|
|
3987
|
+
sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reuploaded_at', ?)",
|
|
3656
3988
|
args: [(/* @__PURE__ */ new Date()).toISOString()]
|
|
3657
3989
|
});
|
|
3658
3990
|
await client.execute("DELETE FROM sync_meta WHERE key IN ('last_cloud_pull_version', 'last_cloud_push_version')");
|
|
3659
3991
|
}
|
|
3992
|
+
async function markCloudReuploadRequired(client = getClient()) {
|
|
3993
|
+
await client.execute("CREATE TABLE IF NOT EXISTS sync_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)");
|
|
3994
|
+
await client.execute("INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('cloud_reupload_required', '1')");
|
|
3995
|
+
}
|
|
3660
3996
|
async function cloudSync(config) {
|
|
3661
3997
|
if (!isSyncCryptoInitialized()) {
|
|
3662
3998
|
try {
|
|
@@ -3678,10 +4014,10 @@ async function cloudSync(config) {
|
|
|
3678
4014
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
3679
4015
|
}
|
|
3680
4016
|
try {
|
|
3681
|
-
if (await
|
|
4017
|
+
if (await getCloudReuploadRequired(client)) throw new Error(CLOUD_REUPLOAD_REQUIRED_MESSAGE);
|
|
3682
4018
|
} catch (err) {
|
|
3683
4019
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3684
|
-
if (msg.includes("
|
|
4020
|
+
if (msg === CLOUD_REUPLOAD_REQUIRED_MESSAGE || msg.includes("key rotation")) throw err;
|
|
3685
4021
|
}
|
|
3686
4022
|
try {
|
|
3687
4023
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
@@ -3939,7 +4275,7 @@ async function cloudSync(config) {
|
|
|
3939
4275
|
const { getLatestBackup: getLatestBackup2 } = await Promise.resolve().then(() => (init_db_backup(), db_backup_exports));
|
|
3940
4276
|
const latestBackup = getLatestBackup2();
|
|
3941
4277
|
if (latestBackup) {
|
|
3942
|
-
const backupSize =
|
|
4278
|
+
const backupSize = statSync4(latestBackup).size;
|
|
3943
4279
|
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
3944
4280
|
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
3945
4281
|
const backupData = readFileSync7(latestBackup);
|
|
@@ -4612,10 +4948,10 @@ async function cloudPullDocuments(config) {
|
|
|
4612
4948
|
return { pulled };
|
|
4613
4949
|
}
|
|
4614
4950
|
export {
|
|
4615
|
-
|
|
4951
|
+
CLOUD_REUPLOAD_REQUIRED_MESSAGE,
|
|
4616
4952
|
assertSecureEndpoint,
|
|
4617
4953
|
buildRosterBlob,
|
|
4618
|
-
|
|
4954
|
+
clearCloudReuploadRequired,
|
|
4619
4955
|
cloudPull,
|
|
4620
4956
|
cloudPullBehaviors,
|
|
4621
4957
|
cloudPullBlob,
|
|
@@ -4634,8 +4970,10 @@ export {
|
|
|
4634
4970
|
cloudPushGraphRAG,
|
|
4635
4971
|
cloudPushRoster,
|
|
4636
4972
|
cloudPushTasks,
|
|
4973
|
+
cloudResetMemoryBlobs,
|
|
4637
4974
|
cloudSync,
|
|
4638
|
-
|
|
4975
|
+
getCloudReuploadRequired,
|
|
4976
|
+
markCloudReuploadRequired,
|
|
4639
4977
|
mergeConfig,
|
|
4640
4978
|
mergeRosterFromRemote,
|
|
4641
4979
|
pushToPostgres,
|