agentel 0.2.6 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +260 -79
- package/docs/code-reference.md +130 -42
- package/docs/history-source-handling.md +685 -153
- package/docs/release.md +35 -8
- package/npm-shrinkwrap.json +478 -0
- package/package.json +20 -4
- package/scripts/postinstall.js +156 -0
- package/src/archive.js +1342 -50
- package/src/canonical-events.js +346 -35
- package/src/cli.js +8835 -843
- package/src/collector.js +42 -4
- package/src/config.js +26 -4
- package/src/diffs.js +156 -0
- package/src/doctor.js +48 -5
- package/src/importers/claude.js +51 -4
- package/src/importers/copilot.js +385 -0
- package/src/importers/cursor-recovery.js +22 -0
- package/src/importers/factory.js +396 -0
- package/src/importers/gemini.js +41 -1
- package/src/importers/grok.js +367 -0
- package/src/importers/pi.js +422 -0
- package/src/importers/providers.js +64 -5
- package/src/importers.js +6429 -747
- package/src/mcp.js +1 -0
- package/src/memory-sources.js +671 -0
- package/src/memory-store.js +0 -0
- package/src/parser-versions.js +13 -0
- package/src/pricing.js +84 -0
- package/src/search.js +641 -215
- package/src/session-store.js +405 -0
- package/src/source-watch.js +293 -0
- package/src/sources.js +60 -11
- package/src/supervisor.js +197 -9
- package/src/sync.js +6 -0
- package/src/unavailable-sources.js +358 -0
- package/src/web-export-instructions.js +6 -4
package/src/sources.js
CHANGED
|
@@ -15,7 +15,7 @@ const SOURCE_GROUPS = [
|
|
|
15
15
|
sources: [
|
|
16
16
|
{ source: "claude", provider: "claude_code", label: "Claude Code CLI" },
|
|
17
17
|
{ source: "claude-code-desktop", provider: "claude_desktop", sourceType: "claude-code-desktop-metadata", label: "Claude Code Desktop" },
|
|
18
|
-
{ source: "claude-
|
|
18
|
+
{ source: "claude-cowork", provider: "claude_desktop", sourceType: "claude-workspace-desktop", label: "Claude Cowork" },
|
|
19
19
|
{ source: "claude-web", provider: "claude_web", label: "Claude.ai" },
|
|
20
20
|
{ source: "claude-sdk", provider: "claude_sdk", label: "Claude SDK jobs" }
|
|
21
21
|
]
|
|
@@ -24,19 +24,42 @@ const SOURCE_GROUPS = [
|
|
|
24
24
|
group: "Google",
|
|
25
25
|
sources: [
|
|
26
26
|
{ source: "gemini-cli", provider: "gemini_cli", label: "Gemini CLI" },
|
|
27
|
-
{ source: "antigravity", provider: "antigravity", label: "Antigravity" }
|
|
27
|
+
{ source: "antigravity-cli", provider: "antigravity_cli", sourceType: "antigravity-cli-transcript-log", label: "Antigravity CLI" },
|
|
28
|
+
{ source: "antigravity", provider: "antigravity", label: "Antigravity 2.0" },
|
|
29
|
+
{ source: "antigravity-ide", provider: "antigravity_ide", sourceType: "antigravity-ide-transcript-log", label: "Antigravity IDE" }
|
|
28
30
|
]
|
|
29
31
|
},
|
|
30
32
|
{
|
|
31
33
|
group: "Cognition",
|
|
32
34
|
sources: [
|
|
33
|
-
{ source: "devin-cli", provider: "devin", sourceType: "devin-cli-history", label: "Devin CLI" }
|
|
35
|
+
{ source: "devin-cli", provider: "devin", sourceType: "devin-cli-history", label: "Devin CLI" },
|
|
36
|
+
{ source: "devin-desktop", provider: "devin", sourceType: "devin-desktop-acp-events", label: "Devin Desktop" },
|
|
37
|
+
{ source: "windsurf", provider: "windsurf", sourceType: "windsurf-cascade-brain", label: "Windsurf" }
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
group: "GitHub",
|
|
42
|
+
sources: [
|
|
43
|
+
{ source: "copilot-cli", provider: "copilot", sourceType: "copilot-cli-history", label: "GitHub Copilot CLI" }
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
group: "Factory",
|
|
48
|
+
sources: [
|
|
49
|
+
{ source: "factory", provider: "factory", sourceType: "factory-droid-history", label: "Factory Droid" }
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
group: "xAI",
|
|
54
|
+
sources: [
|
|
55
|
+
{ source: "grok-build", provider: "grok", sourceType: "grok-build-history", label: "Grok Build" }
|
|
34
56
|
]
|
|
35
57
|
},
|
|
36
58
|
{
|
|
37
59
|
group: "Other",
|
|
38
60
|
sources: [
|
|
39
61
|
{ source: "cursor", provider: "cursor", label: "Cursor" },
|
|
62
|
+
{ source: "pi", provider: "pi", sourceType: "pi-cli-history", label: "pi" },
|
|
40
63
|
{ source: "cline", provider: "cline", sourceType: "cline-task-history", label: "Cline" },
|
|
41
64
|
{ source: "opencode-cli", provider: "opencode", sourceType: "opencode-cli-history", label: "OpenCode CLI" },
|
|
42
65
|
{ source: "opencode-desktop", provider: "opencode", sourceType: "opencode-desktop-history", label: "OpenCode Desktop" },
|
|
@@ -46,23 +69,28 @@ const SOURCE_GROUPS = [
|
|
|
46
69
|
}
|
|
47
70
|
];
|
|
48
71
|
|
|
49
|
-
const DISABLED_IMPORT_SOURCES = new Set(
|
|
72
|
+
const DISABLED_IMPORT_SOURCES = new Set();
|
|
50
73
|
|
|
51
|
-
const DISABLED_IMPORT_SOURCE_MESSAGES = {
|
|
52
|
-
windsurf:
|
|
53
|
-
"Windsurf import is disabled because current Cascade transcripts are encrypted binary stores. agentlog can detect those sessions, but cannot archive readable conversation text yet."
|
|
54
|
-
};
|
|
74
|
+
const DISABLED_IMPORT_SOURCE_MESSAGES = {};
|
|
55
75
|
|
|
56
76
|
const IMPORT_SOURCE_ORDER = [
|
|
57
77
|
"codex-cli",
|
|
58
78
|
"codex-desktop",
|
|
59
79
|
"claude",
|
|
60
80
|
"claude-code-desktop",
|
|
61
|
-
"claude-
|
|
81
|
+
"claude-cowork",
|
|
62
82
|
"gemini-cli",
|
|
83
|
+
"antigravity-cli",
|
|
63
84
|
"antigravity",
|
|
85
|
+
"antigravity-ide",
|
|
64
86
|
"devin-cli",
|
|
87
|
+
"devin-desktop",
|
|
88
|
+
"windsurf",
|
|
89
|
+
"copilot-cli",
|
|
90
|
+
"factory",
|
|
91
|
+
"grok-build",
|
|
65
92
|
"cursor",
|
|
93
|
+
"pi",
|
|
66
94
|
"cline",
|
|
67
95
|
"opencode-cli",
|
|
68
96
|
"opencode-desktop",
|
|
@@ -70,17 +98,38 @@ const IMPORT_SOURCE_ORDER = [
|
|
|
70
98
|
"aider"
|
|
71
99
|
];
|
|
72
100
|
|
|
101
|
+
const IMPORT_SOURCE_ALIASES = {
|
|
102
|
+
"claude-workspace": "claude-cowork",
|
|
103
|
+
claude_workspace: "claude-cowork",
|
|
104
|
+
claude_cowork: "claude-cowork"
|
|
105
|
+
};
|
|
106
|
+
|
|
73
107
|
const HISTORY_PROVIDER_OPTIONS = SOURCE_GROUPS.flatMap((group) => group.sources);
|
|
74
108
|
|
|
109
|
+
function canonicalImportSource(source) {
|
|
110
|
+
const value = String(source || "").trim();
|
|
111
|
+
return IMPORT_SOURCE_ALIASES[value] || value;
|
|
112
|
+
}
|
|
113
|
+
|
|
75
114
|
function enabledImportSources(sources) {
|
|
76
|
-
|
|
115
|
+
const seen = new Set();
|
|
116
|
+
const result = [];
|
|
117
|
+
for (const rawSource of sources || []) {
|
|
118
|
+
const source = canonicalImportSource(rawSource);
|
|
119
|
+
if (!source || seen.has(source) || DISABLED_IMPORT_SOURCES.has(source)) continue;
|
|
120
|
+
seen.add(source);
|
|
121
|
+
result.push(source);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
77
124
|
}
|
|
78
125
|
|
|
79
126
|
function sourceLabel(source) {
|
|
80
|
-
|
|
127
|
+
const canonical = canonicalImportSource(source);
|
|
128
|
+
return HISTORY_PROVIDER_OPTIONS.find((item) => item.source === canonical)?.label || { opencode: "OpenCode" }[canonical] || canonical;
|
|
81
129
|
}
|
|
82
130
|
|
|
83
131
|
module.exports = {
|
|
132
|
+
canonicalImportSource,
|
|
84
133
|
DISABLED_IMPORT_SOURCE_MESSAGES,
|
|
85
134
|
DISABLED_IMPORT_SOURCES,
|
|
86
135
|
HISTORY_PROVIDER_OPTIONS,
|
package/src/supervisor.js
CHANGED
|
@@ -6,12 +6,101 @@ const { spawn } = require("child_process");
|
|
|
6
6
|
const { ensureBaseDirs, paths, readJson, writeJson } = require("./paths");
|
|
7
7
|
const { effectiveImportSources, loadConfig } = require("./config");
|
|
8
8
|
const { startCollector } = require("./collector");
|
|
9
|
+
const { startSourceWatchers } = require("./source-watch");
|
|
9
10
|
const { hasRemoteTarget } = require("./sync");
|
|
10
11
|
|
|
11
12
|
let tickRunning = false;
|
|
12
13
|
const CHILD_MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
|
|
13
14
|
const CHILD_TIMEOUT_MS = 10 * 60 * 1000;
|
|
14
15
|
const CHILD_KILL_GRACE_MS = 2000;
|
|
16
|
+
// Backoff so an idle machine doesn't spawn import/index children every 30s
|
|
17
|
+
// forever: after a few empty imports a source drops to a slower cadence and
|
|
18
|
+
// snaps back to every tick as soon as an import finds activity. Failing
|
|
19
|
+
// sources back off exponentially so a permanently broken source doesn't
|
|
20
|
+
// burn a child process (and a log line) per tick.
|
|
21
|
+
const SOURCE_IDLE_TICKS_BEFORE_BACKOFF = 4;
|
|
22
|
+
const SOURCE_IDLE_INTERVAL_MS = 5 * 60 * 1000;
|
|
23
|
+
const SOURCE_ERROR_BACKOFF_MIN_MS = 60 * 1000;
|
|
24
|
+
const SOURCE_ERROR_BACKOFF_MAX_MS = 30 * 60 * 1000;
|
|
25
|
+
// Sources covered by filesystem watchers don't need the fast poll at all:
|
|
26
|
+
// events mark them pending (imported on the next tick, triggered
|
|
27
|
+
// immediately), and this heartbeat poll only backstops dropped events —
|
|
28
|
+
// fs.watch loses events under load and emits nothing on network volumes.
|
|
29
|
+
const WATCHED_SOURCE_HEARTBEAT_MS = 15 * 60 * 1000;
|
|
30
|
+
const INDEX_MIN_INTERVAL_MS = 10 * 60 * 1000;
|
|
31
|
+
// Memory files change rarely and the backup is a stat+hash sweep, so a
|
|
32
|
+
// moderate cadence keeps provider memories continuously archived without
|
|
33
|
+
// meaningful cost.
|
|
34
|
+
const MEMORY_BACKUP_INTERVAL_MS = 15 * 60 * 1000;
|
|
35
|
+
|
|
36
|
+
// Per-run tick state. Owned by runSupervisorForeground so direct tick()
|
|
37
|
+
// callers (tests, one-shot runs) always start fresh.
|
|
38
|
+
function createTickState() {
|
|
39
|
+
return {
|
|
40
|
+
sources: new Map(),
|
|
41
|
+
lastIndexAt: 0,
|
|
42
|
+
indexDirty: true,
|
|
43
|
+
lastMemoryBackupAt: 0,
|
|
44
|
+
pendingSources: new Set(),
|
|
45
|
+
tickAgain: false,
|
|
46
|
+
watch: null
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function sourceTickStateFor(state, source) {
|
|
51
|
+
let sourceState = state.sources.get(source);
|
|
52
|
+
if (!sourceState) {
|
|
53
|
+
sourceState = { nextEligibleAt: 0, idleTicks: 0, failures: 0, idleLogged: false };
|
|
54
|
+
state.sources.set(source, sourceState);
|
|
55
|
+
}
|
|
56
|
+
return sourceState;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Returns true when the source just transitioned into idle backoff (so the
|
|
60
|
+
// caller can log the transition once instead of every tick).
|
|
61
|
+
function applySourceImportOutcome(sourceState, activity, now) {
|
|
62
|
+
sourceState.failures = 0;
|
|
63
|
+
if (activity > 0) {
|
|
64
|
+
sourceState.idleTicks = 0;
|
|
65
|
+
sourceState.nextEligibleAt = 0;
|
|
66
|
+
sourceState.idleLogged = false;
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
sourceState.idleTicks += 1;
|
|
70
|
+
if (sourceState.idleTicks < SOURCE_IDLE_TICKS_BEFORE_BACKOFF) return false;
|
|
71
|
+
sourceState.nextEligibleAt = now + SOURCE_IDLE_INTERVAL_MS;
|
|
72
|
+
const firstTime = !sourceState.idleLogged;
|
|
73
|
+
sourceState.idleLogged = true;
|
|
74
|
+
return firstTime;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Watched sources skip idle backoff entirely: filesystem events snap them
|
|
78
|
+
// back via pendingSources, so after any import they rest until the heartbeat.
|
|
79
|
+
function applyWatchedSourceImportOutcome(sourceState, now) {
|
|
80
|
+
sourceState.failures = 0;
|
|
81
|
+
sourceState.idleTicks = 0;
|
|
82
|
+
sourceState.idleLogged = false;
|
|
83
|
+
sourceState.nextEligibleAt = now + WATCHED_SOURCE_HEARTBEAT_MS;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Pending filesystem activity bypasses idle/heartbeat scheduling but not
|
|
87
|
+
// error backoff, so a chatty source that fails to import doesn't retry on
|
|
88
|
+
// every coalesce window.
|
|
89
|
+
function sourceEligibleForImport(sourceState, pending, now) {
|
|
90
|
+
if (now >= sourceState.nextEligibleAt) return true;
|
|
91
|
+
return pending && sourceState.failures === 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Returns the backoff delay in ms applied after a failed import.
|
|
95
|
+
function applySourceImportFailure(sourceState, now) {
|
|
96
|
+
sourceState.failures += 1;
|
|
97
|
+
const backoffMs = Math.min(
|
|
98
|
+
SOURCE_ERROR_BACKOFF_MAX_MS,
|
|
99
|
+
SOURCE_ERROR_BACKOFF_MIN_MS * 2 ** (sourceState.failures - 1)
|
|
100
|
+
);
|
|
101
|
+
sourceState.nextEligibleAt = now + backoffMs;
|
|
102
|
+
return backoffMs;
|
|
103
|
+
}
|
|
15
104
|
|
|
16
105
|
function startSupervisorDetached(env = process.env) {
|
|
17
106
|
const p = paths(env);
|
|
@@ -37,57 +126,134 @@ async function runSupervisorForeground(env = process.env) {
|
|
|
37
126
|
});
|
|
38
127
|
if (collector) log(`collector listening on ${loadConfig(env).collector.otlpEndpoint}`, env);
|
|
39
128
|
|
|
129
|
+
const tickState = createTickState();
|
|
130
|
+
|
|
40
131
|
let stopping = false;
|
|
41
132
|
const stop = () => {
|
|
42
133
|
if (stopping) return;
|
|
43
134
|
stopping = true;
|
|
44
135
|
log("supervisor stopping", env);
|
|
136
|
+
if (tickState.watch) tickState.watch.close();
|
|
45
137
|
removeSupervisorPidIfOwned(process.pid, env);
|
|
46
138
|
process.exit(0);
|
|
47
139
|
};
|
|
48
140
|
process.on("SIGTERM", stop);
|
|
49
141
|
process.on("SIGINT", stop);
|
|
50
142
|
|
|
51
|
-
|
|
143
|
+
const runTick = () => {
|
|
144
|
+
if (stopping) return;
|
|
145
|
+
tick(env, tickState)
|
|
146
|
+
.catch((error) => log(`tick failed: ${error.message}`, env))
|
|
147
|
+
.finally(() => {
|
|
148
|
+
// Sources marked dirty while a tick ran get picked up right away
|
|
149
|
+
// instead of waiting for the interval.
|
|
150
|
+
if (tickState.tickAgain && !stopping) {
|
|
151
|
+
tickState.tickAgain = false;
|
|
152
|
+
runTick();
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const sources = effectiveImportSources(loadConfig(env));
|
|
159
|
+
tickState.watch = startSourceWatchers(
|
|
160
|
+
Array.isArray(sources) && sources.length ? sources : [],
|
|
161
|
+
env,
|
|
162
|
+
(source) => {
|
|
163
|
+
tickState.pendingSources.add(source);
|
|
164
|
+
if (tickRunning) {
|
|
165
|
+
tickState.tickAgain = true;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
runTick();
|
|
169
|
+
},
|
|
170
|
+
{ onLog: (message) => log(message, env) }
|
|
171
|
+
);
|
|
172
|
+
const active = tickState.watch.activeWatchCount();
|
|
173
|
+
if (active) log(`watching ${active} source root(s) for changes`, env);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
log(`source watch disabled: ${error.message}`, env);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
await tick(env, tickState);
|
|
179
|
+
if (tickState.tickAgain) {
|
|
180
|
+
tickState.tickAgain = false;
|
|
181
|
+
runTick();
|
|
182
|
+
}
|
|
52
183
|
const timer = setInterval(() => {
|
|
53
184
|
if (tickRunning) {
|
|
54
185
|
log("tick skipped: previous tick still running", env);
|
|
55
186
|
return;
|
|
56
187
|
}
|
|
57
|
-
|
|
188
|
+
runTick();
|
|
58
189
|
}, 30 * 1000);
|
|
59
190
|
|
|
60
191
|
await new Promise(() => {});
|
|
61
192
|
}
|
|
62
193
|
|
|
63
|
-
async function tick(env) {
|
|
194
|
+
async function tick(env, state = createTickState()) {
|
|
64
195
|
tickRunning = true;
|
|
65
196
|
try {
|
|
197
|
+
const now = Date.now();
|
|
66
198
|
try {
|
|
67
199
|
const cfg = loadConfig(env);
|
|
68
200
|
const sources = effectiveImportSources(cfg);
|
|
69
201
|
const importSources = Array.isArray(sources) && sources.length ? sources : ["all"];
|
|
70
202
|
for (const source of importSources) {
|
|
203
|
+
const sourceState = sourceTickStateFor(state, source);
|
|
204
|
+
const pending = state.pendingSources.has(source);
|
|
205
|
+
if (!sourceEligibleForImport(sourceState, pending, now)) continue;
|
|
206
|
+
state.pendingSources.delete(source);
|
|
71
207
|
try {
|
|
72
208
|
const imports = await importSourceInChild(source, cfg, env);
|
|
209
|
+
let activity = 0;
|
|
73
210
|
for (const result of imports) {
|
|
211
|
+
activity += (Number(result.imported) || 0) + (Number(result.pruned) || 0);
|
|
74
212
|
const summary = supervisorImportResultLog(result, source);
|
|
75
213
|
if (summary) log(summary, env);
|
|
76
214
|
if (result.errors?.length) log(`${result.provider} import errors from ${source}: ${result.errors.length}`, env);
|
|
77
215
|
}
|
|
216
|
+
if (activity > 0) state.indexDirty = true;
|
|
217
|
+
if (state.watch && state.watch.isWatched(source)) {
|
|
218
|
+
applyWatchedSourceImportOutcome(sourceState, now);
|
|
219
|
+
} else if (applySourceImportOutcome(sourceState, activity, now)) {
|
|
220
|
+
log(`${source} import idle: slowing to ${formatDuration(SOURCE_IDLE_INTERVAL_MS)} cadence until new activity`, env);
|
|
221
|
+
}
|
|
78
222
|
} catch (error) {
|
|
79
|
-
|
|
223
|
+
const backoffMs = applySourceImportFailure(sourceState, now);
|
|
224
|
+
log(`${source} history import skipped: ${error.message} (retrying in ${formatDuration(backoffMs)})`, env);
|
|
80
225
|
}
|
|
81
226
|
}
|
|
82
227
|
} catch (error) {
|
|
83
228
|
log(`history import skipped: ${error.message}`, env);
|
|
84
229
|
}
|
|
85
230
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
231
|
+
if (state.indexDirty || now - state.lastIndexAt >= INDEX_MIN_INTERVAL_MS) {
|
|
232
|
+
try {
|
|
233
|
+
const result = await reindexInChild(env);
|
|
234
|
+
if (result.index?.docCount != null) log(`index ready (${result.index.docCount} chunk(s))`, env);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
log(`index skipped: ${error.message}`, env);
|
|
237
|
+
} finally {
|
|
238
|
+
// Advance the clock even on failure so a persistent indexing error
|
|
239
|
+
// backs off to INDEX_MIN_INTERVAL_MS instead of retrying every tick.
|
|
240
|
+
state.lastIndexAt = now;
|
|
241
|
+
state.indexDirty = false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (now - state.lastMemoryBackupAt >= MEMORY_BACKUP_INTERVAL_MS) {
|
|
246
|
+
try {
|
|
247
|
+
const summaries = await memoryBackupInChild(env);
|
|
248
|
+
const changed = summaries.reduce((sum, item) => sum + (Number(item.changed) || 0), 0);
|
|
249
|
+
if (changed > 0) log(`memory backup captured ${changed} change(s)`, env);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
log(`memory backup skipped: ${error.message}`, env);
|
|
252
|
+
} finally {
|
|
253
|
+
// Advance even on failure so a persistent error backs off to the
|
|
254
|
+
// backup interval instead of retrying every tick.
|
|
255
|
+
state.lastMemoryBackupAt = now;
|
|
256
|
+
}
|
|
91
257
|
}
|
|
92
258
|
|
|
93
259
|
try {
|
|
@@ -124,6 +290,22 @@ try {
|
|
|
124
290
|
return runJsonChild(script, env, `${source} import`, title);
|
|
125
291
|
}
|
|
126
292
|
|
|
293
|
+
function memoryBackupInChild(env = process.env) {
|
|
294
|
+
const title = childProcessTitle("memory-backup");
|
|
295
|
+
const script = `
|
|
296
|
+
process.title = ${JSON.stringify(title)};
|
|
297
|
+
(async () => {
|
|
298
|
+
const { collectMemoryBackup } = require(${JSON.stringify(path.join(__dirname, "memory-sources"))});
|
|
299
|
+
const summaries = await collectMemoryBackup(process.env);
|
|
300
|
+
process.stdout.write(JSON.stringify(summaries));
|
|
301
|
+
})().catch((error) => {
|
|
302
|
+
console.error(error && error.message ? error.message : String(error));
|
|
303
|
+
process.exit(1);
|
|
304
|
+
});
|
|
305
|
+
`;
|
|
306
|
+
return runJsonChild(script, env, "memory backup", title);
|
|
307
|
+
}
|
|
308
|
+
|
|
127
309
|
function reindexInChild(env = process.env) {
|
|
128
310
|
const title = childProcessTitle("index");
|
|
129
311
|
const script = `
|
|
@@ -350,6 +532,11 @@ function log(message, env = process.env) {
|
|
|
350
532
|
}
|
|
351
533
|
|
|
352
534
|
module.exports = {
|
|
535
|
+
applySourceImportFailure,
|
|
536
|
+
applySourceImportOutcome,
|
|
537
|
+
applyWatchedSourceImportOutcome,
|
|
538
|
+
createTickState,
|
|
539
|
+
sourceEligibleForImport,
|
|
353
540
|
runSupervisorForeground,
|
|
354
541
|
startSupervisorDetached,
|
|
355
542
|
stopSupervisor,
|
|
@@ -359,6 +546,7 @@ module.exports = {
|
|
|
359
546
|
removeSupervisorPidIfOwned,
|
|
360
547
|
shouldRunScheduledSync,
|
|
361
548
|
importSourceInChild,
|
|
549
|
+
memoryBackupInChild,
|
|
362
550
|
reindexInChild,
|
|
363
551
|
runJsonChild,
|
|
364
552
|
syncInChild,
|
package/src/sync.js
CHANGED
|
@@ -526,6 +526,7 @@ function listLocalArchiveObjects(env = process.env, prefix = "agentlog") {
|
|
|
526
526
|
const stat = safeStat(file);
|
|
527
527
|
if (!stat || !stat.isFile()) return;
|
|
528
528
|
const relative = path.relative(root, file).split(path.sep).join("/");
|
|
529
|
+
if (!syncableArchiveObject(relative)) return;
|
|
529
530
|
const key = [normalizePrefix(prefix), relative].filter(Boolean).join("/");
|
|
530
531
|
objects.push({
|
|
531
532
|
file,
|
|
@@ -538,6 +539,11 @@ function listLocalArchiveObjects(env = process.env, prefix = "agentlog") {
|
|
|
538
539
|
return objects.sort((a, b) => a.key.localeCompare(b.key));
|
|
539
540
|
}
|
|
540
541
|
|
|
542
|
+
function syncableArchiveObject(relative) {
|
|
543
|
+
const key = String(relative || "").replace(/\\/g, "/");
|
|
544
|
+
return !key.startsWith("indexes/");
|
|
545
|
+
}
|
|
546
|
+
|
|
541
547
|
function listDirectoryObjects(root) {
|
|
542
548
|
const objects = [];
|
|
543
549
|
walk(root, (file) => {
|