elepha 0.1.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.
Files changed (290) hide show
  1. package/LICENSE.md +375 -0
  2. package/README.md +135 -0
  3. package/bin/elepha.js +2 -0
  4. package/dist/adapters/base.js +600 -0
  5. package/dist/adapters/base.js.map +1 -0
  6. package/dist/adapters/claude-code.js +260 -0
  7. package/dist/adapters/claude-code.js.map +1 -0
  8. package/dist/adapters/codex.js +499 -0
  9. package/dist/adapters/codex.js.map +1 -0
  10. package/dist/adapters/discriminators.js +39 -0
  11. package/dist/adapters/discriminators.js.map +1 -0
  12. package/dist/adapters/index.js +6 -0
  13. package/dist/adapters/index.js.map +1 -0
  14. package/dist/adapters/internal-command.js +3 -0
  15. package/dist/adapters/internal-command.js.map +1 -0
  16. package/dist/cli/backup-wizard.js +97 -0
  17. package/dist/cli/backup-wizard.js.map +1 -0
  18. package/dist/cli/capture-service.js +80 -0
  19. package/dist/cli/capture-service.js.map +1 -0
  20. package/dist/cli/commands/backfills.js +336 -0
  21. package/dist/cli/commands/backfills.js.map +1 -0
  22. package/dist/cli/commands/backup.js +234 -0
  23. package/dist/cli/commands/backup.js.map +1 -0
  24. package/dist/cli/commands/config.js +66 -0
  25. package/dist/cli/commands/config.js.map +1 -0
  26. package/dist/cli/commands/consent.js +237 -0
  27. package/dist/cli/commands/consent.js.map +1 -0
  28. package/dist/cli/commands/daemon-control.js +76 -0
  29. package/dist/cli/commands/daemon-control.js.map +1 -0
  30. package/dist/cli/commands/doctor.js +31 -0
  31. package/dist/cli/commands/doctor.js.map +1 -0
  32. package/dist/cli/commands/hook.js +24 -0
  33. package/dist/cli/commands/hook.js.map +1 -0
  34. package/dist/cli/commands/import.js +611 -0
  35. package/dist/cli/commands/import.js.map +1 -0
  36. package/dist/cli/commands/init.js +19 -0
  37. package/dist/cli/commands/init.js.map +1 -0
  38. package/dist/cli/commands/inspect.js +54 -0
  39. package/dist/cli/commands/inspect.js.map +1 -0
  40. package/dist/cli/commands/install.js +49 -0
  41. package/dist/cli/commands/install.js.map +1 -0
  42. package/dist/cli/commands/internal.js +16 -0
  43. package/dist/cli/commands/internal.js.map +1 -0
  44. package/dist/cli/commands/mcp.js +12 -0
  45. package/dist/cli/commands/mcp.js.map +1 -0
  46. package/dist/cli/commands/projects.js +26 -0
  47. package/dist/cli/commands/projects.js.map +1 -0
  48. package/dist/cli/commands/purge.js +216 -0
  49. package/dist/cli/commands/purge.js.map +1 -0
  50. package/dist/cli/commands/reingest.js +80 -0
  51. package/dist/cli/commands/reingest.js.map +1 -0
  52. package/dist/cli/commands/rekey.js +58 -0
  53. package/dist/cli/commands/rekey.js.map +1 -0
  54. package/dist/cli/commands/restore.js +376 -0
  55. package/dist/cli/commands/restore.js.map +1 -0
  56. package/dist/cli/commands/rollup.js +130 -0
  57. package/dist/cli/commands/rollup.js.map +1 -0
  58. package/dist/cli/commands/sanitize.js +72 -0
  59. package/dist/cli/commands/sanitize.js.map +1 -0
  60. package/dist/cli/commands/segment.js +153 -0
  61. package/dist/cli/commands/segment.js.map +1 -0
  62. package/dist/cli/commands/self-update.js +26 -0
  63. package/dist/cli/commands/self-update.js.map +1 -0
  64. package/dist/cli/commands/start.js +53 -0
  65. package/dist/cli/commands/start.js.map +1 -0
  66. package/dist/cli/commands/stats.js +42 -0
  67. package/dist/cli/commands/stats.js.map +1 -0
  68. package/dist/cli/commands/status.js +73 -0
  69. package/dist/cli/commands/status.js.map +1 -0
  70. package/dist/cli/commands/uninstall.js +23 -0
  71. package/dist/cli/commands/uninstall.js.map +1 -0
  72. package/dist/cli/config-wizard.js +104 -0
  73. package/dist/cli/config-wizard.js.map +1 -0
  74. package/dist/cli/destructive-op.js +32 -0
  75. package/dist/cli/destructive-op.js.map +1 -0
  76. package/dist/cli/import-wizard.js +89 -0
  77. package/dist/cli/import-wizard.js.map +1 -0
  78. package/dist/cli/index.js +74 -0
  79. package/dist/cli/index.js.map +1 -0
  80. package/dist/cli/init-wizard.js +80 -0
  81. package/dist/cli/init-wizard.js.map +1 -0
  82. package/dist/cli/init.js +159 -0
  83. package/dist/cli/init.js.map +1 -0
  84. package/dist/cli/launcher-probe.js +71 -0
  85. package/dist/cli/launcher-probe.js.map +1 -0
  86. package/dist/cli/project-path.js +16 -0
  87. package/dist/cli/project-path.js.map +1 -0
  88. package/dist/cli/purge-wizard.js +200 -0
  89. package/dist/cli/purge-wizard.js.map +1 -0
  90. package/dist/cli/restore-wizard.js +101 -0
  91. package/dist/cli/restore-wizard.js.map +1 -0
  92. package/dist/cli/shared.js +128 -0
  93. package/dist/cli/shared.js.map +1 -0
  94. package/dist/cli/status.js +22 -0
  95. package/dist/cli/status.js.map +1 -0
  96. package/dist/cli/wordmark.js +15 -0
  97. package/dist/cli/wordmark.js.map +1 -0
  98. package/dist/config/constants.js +115 -0
  99. package/dist/config/constants.js.map +1 -0
  100. package/dist/config/env.js +168 -0
  101. package/dist/config/env.js.map +1 -0
  102. package/dist/config/memory-config.js +63 -0
  103. package/dist/config/memory-config.js.map +1 -0
  104. package/dist/config/paths.js +343 -0
  105. package/dist/config/paths.js.map +1 -0
  106. package/dist/config/settings.js +132 -0
  107. package/dist/config/settings.js.map +1 -0
  108. package/dist/config/version.js +12 -0
  109. package/dist/config/version.js.map +1 -0
  110. package/dist/daemon/failure-window.js +38 -0
  111. package/dist/daemon/failure-window.js.map +1 -0
  112. package/dist/daemon/heartbeat.js +40 -0
  113. package/dist/daemon/heartbeat.js.map +1 -0
  114. package/dist/daemon/index.js +873 -0
  115. package/dist/daemon/index.js.map +1 -0
  116. package/dist/daemon/log-rotation.js +27 -0
  117. package/dist/daemon/log-rotation.js.map +1 -0
  118. package/dist/daemon/readability-guard.js +89 -0
  119. package/dist/daemon/readability-guard.js.map +1 -0
  120. package/dist/daemon/rollup-service.js +239 -0
  121. package/dist/daemon/rollup-service.js.map +1 -0
  122. package/dist/daemon/update-check.js +87 -0
  123. package/dist/daemon/update-check.js.map +1 -0
  124. package/dist/daemon/work-queue.js +28 -0
  125. package/dist/daemon/work-queue.js.map +1 -0
  126. package/dist/discovery/session-projects.js +242 -0
  127. package/dist/discovery/session-projects.js.map +1 -0
  128. package/dist/hooks/codex-trust.js +80 -0
  129. package/dist/hooks/codex-trust.js.map +1 -0
  130. package/dist/hooks/common.js +81 -0
  131. package/dist/hooks/common.js.map +1 -0
  132. package/dist/hooks/hook-log.js +38 -0
  133. package/dist/hooks/hook-log.js.map +1 -0
  134. package/dist/hooks/installer.js +200 -0
  135. package/dist/hooks/installer.js.map +1 -0
  136. package/dist/hooks/session-start.js +321 -0
  137. package/dist/hooks/session-start.js.map +1 -0
  138. package/dist/hooks/user-prompt-submit.js +248 -0
  139. package/dist/hooks/user-prompt-submit.js.map +1 -0
  140. package/dist/install/binary.js +72 -0
  141. package/dist/install/binary.js.map +1 -0
  142. package/dist/install/config-file.js +119 -0
  143. package/dist/install/config-file.js.map +1 -0
  144. package/dist/install/daemon-health.js +48 -0
  145. package/dist/install/daemon-health.js.map +1 -0
  146. package/dist/install/daemon-service.js +309 -0
  147. package/dist/install/daemon-service.js.map +1 -0
  148. package/dist/install/doctor.js +180 -0
  149. package/dist/install/doctor.js.map +1 -0
  150. package/dist/install/health-checks.js +90 -0
  151. package/dist/install/health-checks.js.map +1 -0
  152. package/dist/install/installer.js +411 -0
  153. package/dist/install/installer.js.map +1 -0
  154. package/dist/install/launchd-backend.js +261 -0
  155. package/dist/install/launchd-backend.js.map +1 -0
  156. package/dist/install/launcher.js +224 -0
  157. package/dist/install/launcher.js.map +1 -0
  158. package/dist/install/markers.js +14 -0
  159. package/dist/install/markers.js.map +1 -0
  160. package/dist/install/platform.js +29 -0
  161. package/dist/install/platform.js.map +1 -0
  162. package/dist/install/present-tools.js +16 -0
  163. package/dist/install/present-tools.js.map +1 -0
  164. package/dist/install/self-update.js +120 -0
  165. package/dist/install/self-update.js.map +1 -0
  166. package/dist/install/service-backend.js +36 -0
  167. package/dist/install/service-backend.js.map +1 -0
  168. package/dist/install/service-manifest.js +36 -0
  169. package/dist/install/service-manifest.js.map +1 -0
  170. package/dist/install/status.js +58 -0
  171. package/dist/install/status.js.map +1 -0
  172. package/dist/install/systemd-backend.js +225 -0
  173. package/dist/install/systemd-backend.js.map +1 -0
  174. package/dist/markers.js +5 -0
  175. package/dist/markers.js.map +1 -0
  176. package/dist/mcp/installer.js +131 -0
  177. package/dist/mcp/installer.js.map +1 -0
  178. package/dist/mcp/server.js +81 -0
  179. package/dist/mcp/server.js.map +1 -0
  180. package/dist/mcp/tools/get-context.js +3 -0
  181. package/dist/mcp/tools/get-context.js.map +1 -0
  182. package/dist/mcp/tools/list-projects.js +3 -0
  183. package/dist/mcp/tools/list-projects.js.map +1 -0
  184. package/dist/mcp/tools/save-memory.js +3 -0
  185. package/dist/mcp/tools/save-memory.js.map +1 -0
  186. package/dist/mcp/tools.js +288 -0
  187. package/dist/mcp/tools.js.map +1 -0
  188. package/dist/rendering/raw-turn-renderer.js +85 -0
  189. package/dist/rendering/raw-turn-renderer.js.map +1 -0
  190. package/dist/security/file-permissions.js +15 -0
  191. package/dist/security/file-permissions.js.map +1 -0
  192. package/dist/security/provider-transcript.js +74 -0
  193. package/dist/security/provider-transcript.js.map +1 -0
  194. package/dist/security/sanitize.js +210 -0
  195. package/dist/security/sanitize.js.map +1 -0
  196. package/dist/security/self-ingestion.js +47 -0
  197. package/dist/security/self-ingestion.js.map +1 -0
  198. package/dist/security/sentinel.js +19 -0
  199. package/dist/security/sentinel.js.map +1 -0
  200. package/dist/security/subprocess-allowlist.js +421 -0
  201. package/dist/security/subprocess-allowlist.js.map +1 -0
  202. package/dist/serving/instructions.js +33 -0
  203. package/dist/serving/instructions.js.map +1 -0
  204. package/dist/serving/lexical-recall.js +249 -0
  205. package/dist/serving/lexical-recall.js.map +1 -0
  206. package/dist/serving/session-reader.js +302 -0
  207. package/dist/serving/session-reader.js.map +1 -0
  208. package/dist/storage/backfill-runner.js +34 -0
  209. package/dist/storage/backfill-runner.js.map +1 -0
  210. package/dist/storage/backup.js +46 -0
  211. package/dist/storage/backup.js.map +1 -0
  212. package/dist/storage/candidate-validator.js +77 -0
  213. package/dist/storage/candidate-validator.js.map +1 -0
  214. package/dist/storage/consent-store.js +198 -0
  215. package/dist/storage/consent-store.js.map +1 -0
  216. package/dist/storage/custom-title-backfill.js +68 -0
  217. package/dist/storage/custom-title-backfill.js.map +1 -0
  218. package/dist/storage/db.js +312 -0
  219. package/dist/storage/db.js.map +1 -0
  220. package/dist/storage/external-agent-import-purge.js +182 -0
  221. package/dist/storage/external-agent-import-purge.js.map +1 -0
  222. package/dist/storage/first-prompt-search-backfill.js +76 -0
  223. package/dist/storage/first-prompt-search-backfill.js.map +1 -0
  224. package/dist/storage/first-prompt-search.js +7 -0
  225. package/dist/storage/first-prompt-search.js.map +1 -0
  226. package/dist/storage/injection-store.js +37 -0
  227. package/dist/storage/injection-store.js.map +1 -0
  228. package/dist/storage/memory-store.js +428 -0
  229. package/dist/storage/memory-store.js.map +1 -0
  230. package/dist/storage/project-resolver.js +294 -0
  231. package/dist/storage/project-resolver.js.map +1 -0
  232. package/dist/storage/project-store.js +104 -0
  233. package/dist/storage/project-store.js.map +1 -0
  234. package/dist/storage/rendered-chars-backfill.js +85 -0
  235. package/dist/storage/rendered-chars-backfill.js.map +1 -0
  236. package/dist/storage/resegmentation.js +582 -0
  237. package/dist/storage/resegmentation.js.map +1 -0
  238. package/dist/storage/rollup-store.js +246 -0
  239. package/dist/storage/rollup-store.js.map +1 -0
  240. package/dist/storage/root-commit-backfill.js +32 -0
  241. package/dist/storage/root-commit-backfill.js.map +1 -0
  242. package/dist/storage/sanitize-backfill.js +184 -0
  243. package/dist/storage/sanitize-backfill.js.map +1 -0
  244. package/dist/storage/segmentation.js +87 -0
  245. package/dist/storage/segmentation.js.map +1 -0
  246. package/dist/storage/session-fields-backfill.js +196 -0
  247. package/dist/storage/session-fields-backfill.js.map +1 -0
  248. package/dist/storage/session-read-model.js +130 -0
  249. package/dist/storage/session-read-model.js.map +1 -0
  250. package/dist/storage/session-store.js +200 -0
  251. package/dist/storage/session-store.js.map +1 -0
  252. package/dist/storage/session-title-backfill.js +75 -0
  253. package/dist/storage/session-title-backfill.js.map +1 -0
  254. package/dist/storage/session-title.js +71 -0
  255. package/dist/storage/session-title.js.map +1 -0
  256. package/dist/storage/shown-session-list-store.js +33 -0
  257. package/dist/storage/shown-session-list-store.js.map +1 -0
  258. package/dist/storage/stats.js +30 -0
  259. package/dist/storage/stats.js.map +1 -0
  260. package/dist/storage/turn-store.js +202 -0
  261. package/dist/storage/turn-store.js.map +1 -0
  262. package/dist/storage/ulid.js +17 -0
  263. package/dist/storage/ulid.js.map +1 -0
  264. package/dist/summarizer/anthropic-call.js +76 -0
  265. package/dist/summarizer/anthropic-call.js.map +1 -0
  266. package/dist/summarizer/call-log.js +120 -0
  267. package/dist/summarizer/call-log.js.map +1 -0
  268. package/dist/summarizer/haiku-provider.js +136 -0
  269. package/dist/summarizer/haiku-provider.js.map +1 -0
  270. package/dist/summarizer/pricing.js +8 -0
  271. package/dist/summarizer/pricing.js.map +1 -0
  272. package/dist/summarizer/prompt-cache.js +6 -0
  273. package/dist/summarizer/prompt-cache.js.map +1 -0
  274. package/dist/summarizer/prompt.js +47 -0
  275. package/dist/summarizer/prompt.js.map +1 -0
  276. package/dist/summarizer/provider-config.js +25 -0
  277. package/dist/summarizer/provider-config.js.map +1 -0
  278. package/dist/summarizer/rollup-prompt.js +225 -0
  279. package/dist/summarizer/rollup-prompt.js.map +1 -0
  280. package/dist/summarizer/rollup-provider.js +224 -0
  281. package/dist/summarizer/rollup-provider.js.map +1 -0
  282. package/dist/types/index.js +10 -0
  283. package/dist/types/index.js.map +1 -0
  284. package/dist/util/error.js +5 -0
  285. package/dist/util/error.js.map +1 -0
  286. package/dist/util/fs.js +97 -0
  287. package/dist/util/fs.js.map +1 -0
  288. package/dist/util/relative-time.js +12 -0
  289. package/dist/util/relative-time.js.map +1 -0
  290. package/package.json +81 -0
@@ -0,0 +1,58 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { gitRevParseShowToplevel } from '../../security/subprocess-allowlist.js';
3
+ import { backupDatabaseAndReport } from '../../storage/backup.js';
4
+ import { defaultDbPath, openDb } from '../../storage/db.js';
5
+ import { MemoryStore } from '../../storage/memory-store.js';
6
+ import { refuseIfDaemonRunning } from '../shared.js';
7
+ export function registerRekey(program) {
8
+ program
9
+ .command('rekey-projects', { hidden: true })
10
+ .description('Consolidate project rows by stable repository identity. Dry-run by default.')
11
+ .option('--apply', 'actually perform the merge (default is a dry run that only prints the mapping)')
12
+ .action((opts) => {
13
+ const dbPath = defaultDbPath();
14
+ const store = new MemoryStore(openDb());
15
+ const resolveGitRoot = (p) => {
16
+ if (!p || !existsSync(p)) {
17
+ return null;
18
+ }
19
+ return gitRevParseShowToplevel(p);
20
+ };
21
+ const before = store.listProjects().length;
22
+ let plans = store.planRekeyProjectsByIdentity(resolveGitRoot);
23
+ if (plans.length === 0) {
24
+ console.log('No project rows need consolidating.');
25
+ return;
26
+ }
27
+ if (opts.apply) {
28
+ if (refuseIfDaemonRunning('rekey-projects --apply')) {
29
+ return;
30
+ }
31
+ // Re-keying deletes only now-redundant project rows, but it still
32
+ // moves foreign keys and must leave a full recoverable snapshot.
33
+ if (existsSync(dbPath)) {
34
+ backupDatabaseAndReport(store.database, dbPath, reportBackupWithoutLeadingNewline);
35
+ }
36
+ plans = store.rekeyProjectsByIdentity(resolveGitRoot);
37
+ }
38
+ console.log(opts.apply ? '=== PROJECT RE-KEY APPLIED ===\n' : '=== PROJECT RE-KEY DRY RUN (nothing written) ===\n');
39
+ for (const plan of plans) {
40
+ console.log(`git_root: ${plan.gitRoot ?? '(unresolved)'}`);
41
+ console.log(` canonical -> [${plan.canonical.id}] ${plan.gitRoot ?? plan.canonical.path}`);
42
+ for (const m of plan.merged) {
43
+ console.log(` merged <- [${m.id}] ${m.path}`);
44
+ }
45
+ console.log('');
46
+ }
47
+ const mergedCount = plans.reduce((sum, p) => sum + p.merged.length, 0);
48
+ const verb = opts.apply ? 'merged' : 'would merge';
49
+ console.log(`${plans.length} group(s), ${verb} ${mergedCount} row(s): ${before} -> ${before - mergedCount} project rows`);
50
+ if (!opts.apply) {
51
+ console.log('\nRe-run with --apply to perform the merge.');
52
+ }
53
+ });
54
+ }
55
+ function reportBackupWithoutLeadingNewline(message) {
56
+ console.log(message.startsWith('\n') ? message.slice(1) : message);
57
+ }
58
+ //# sourceMappingURL=rekey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rekey.js","sourceRoot":"","sources":["../../../src/cli/commands/rekey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,376 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { createReadStream, existsSync, mkdtempSync, rmdirSync, unlinkSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import path from 'node:path';
5
+ import Database from 'better-sqlite3';
6
+ import { PRIVATE_FILE_MODE } from '../../config/constants.js';
7
+ import { daemonHealth as currentDaemonHealth } from '../../install/health-checks.js';
8
+ import { writeBackup } from '../../storage/backup.js';
9
+ import { validateCandidateSemantics } from '../../storage/candidate-validator.js';
10
+ import { defaultDbPath, openDb } from '../../storage/db.js';
11
+ import { errorMessage } from '../../util/error.js';
12
+ import { atomicCopyPrivateFile } from '../../util/fs.js';
13
+ import { runRestoreWizard } from '../restore-wizard.js';
14
+ import { confirmYesNo } from '../shared.js';
15
+ export const REQUIRED_RESTORE_TABLES = [
16
+ 'projects',
17
+ 'sessions',
18
+ 'memories',
19
+ 'session_rollups',
20
+ 'consent_roots',
21
+ 'injections',
22
+ 'purged_transcripts',
23
+ ];
24
+ const TOMBSTONE_TABLES = [
25
+ { table: 'purged_transcripts', timestampColumn: 'purged_at' },
26
+ { table: 'incognito_transcripts', timestampColumn: 'tombstoned_at' },
27
+ ];
28
+ class RestoreApplyError extends Error {
29
+ snapshotPath;
30
+ constructor(snapshotPath, cause) {
31
+ super(`Restore failed after saving the pre-restore snapshot to ${snapshotPath}: ${errorMessage(cause)}`);
32
+ this.snapshotPath = snapshotPath;
33
+ }
34
+ }
35
+ function quoteTable(table) {
36
+ return `"${table}"`;
37
+ }
38
+ function candidateCounts(db) {
39
+ return Object.fromEntries(REQUIRED_RESTORE_TABLES.map((table) => [
40
+ table,
41
+ Number(db.prepare(`SELECT COUNT(*) AS count FROM ${quoteTable(table)}`).get().count),
42
+ ]));
43
+ }
44
+ function missingRequiredTables(db) {
45
+ const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => row.name));
46
+ return REQUIRED_RESTORE_TABLES.filter((table) => !tables.has(table));
47
+ }
48
+ function tableColumns(db, table) {
49
+ return new Map(db.prepare(`PRAGMA table_info(${quoteTable(table)})`).all().map((column) => [column.name, column.type]));
50
+ }
51
+ function schemaDifferences(candidate, canonical) {
52
+ const errors = [];
53
+ for (const table of REQUIRED_RESTORE_TABLES) {
54
+ const candidateColumns = tableColumns(candidate, table);
55
+ const canonicalColumns = tableColumns(canonical, table);
56
+ const missing = [...canonicalColumns.keys()].filter((column) => !candidateColumns.has(column));
57
+ const extra = [...candidateColumns.keys()].filter((column) => !canonicalColumns.has(column));
58
+ const typeMismatches = [...canonicalColumns].filter(([column, type]) => candidateColumns.has(column) && candidateColumns.get(column) !== type);
59
+ if (missing.length > 0) {
60
+ errors.push(`${table}: missing column(s): ${missing.join(', ')}`);
61
+ }
62
+ if (extra.length > 0) {
63
+ errors.push(`${table}: unexpected column(s): ${extra.join(', ')}`);
64
+ }
65
+ for (const [column, type] of typeMismatches) {
66
+ errors.push(`${table}: ${column} has type ${candidateColumns.get(column)}, expected ${type}`);
67
+ }
68
+ }
69
+ return errors;
70
+ }
71
+ function removeTemporaryDatabase(dbPath, directory) {
72
+ let cleanupError;
73
+ for (const file of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
74
+ try {
75
+ unlinkSync(file);
76
+ }
77
+ catch (error) {
78
+ if (error.code !== 'ENOENT' && cleanupError === undefined) {
79
+ cleanupError = error;
80
+ }
81
+ }
82
+ }
83
+ try {
84
+ rmdirSync(directory);
85
+ }
86
+ catch (error) {
87
+ if (error.code !== 'ENOENT' && cleanupError === undefined) {
88
+ cleanupError = error;
89
+ }
90
+ }
91
+ if (cleanupError !== undefined) {
92
+ throw cleanupError;
93
+ }
94
+ }
95
+ /** Opens the staged backup so accepted older backups receive the same idempotent migrations as the active database. */
96
+ function verifyStagedSchema(stagedPath) {
97
+ let staged;
98
+ let canonical;
99
+ try {
100
+ staged = openDb(stagedPath);
101
+ canonical = openDb(':memory:');
102
+ const errors = schemaDifferences(staged, canonical);
103
+ if (errors.length > 0) {
104
+ throw new Error(`Backup schema does not match the current elepha schema after migration: ${errors.join('; ')}`);
105
+ }
106
+ const semanticViolations = validateCandidateSemantics(staged, ['sessions', 'memories', 'session_rollups', 'consent_roots']);
107
+ if (semanticViolations.length > 0) {
108
+ throw new Error(`Backup is semantically invalid: ${semanticViolations.join('; ')}`);
109
+ }
110
+ }
111
+ finally {
112
+ canonical?.close();
113
+ staged?.close();
114
+ }
115
+ }
116
+ function verifyDatabase(db, expectedCounts) {
117
+ const missing = missingRequiredTables(db);
118
+ const errors = missing.length > 0 ? [`missing required table(s): ${missing.join(', ')}`] : [];
119
+ if (missing.length > 0) {
120
+ return errors;
121
+ }
122
+ const integrity = db.pragma('integrity_check');
123
+ if (integrity.length !== 1 || integrity[0]?.integrity_check !== 'ok') {
124
+ errors.push(`integrity_check failed: ${integrity.map((row) => row.integrity_check).join('; ')}`);
125
+ }
126
+ const foreignKeys = db.pragma('foreign_key_check');
127
+ if (foreignKeys.length > 0) {
128
+ errors.push(`foreign_key_check found ${foreignKeys.length} violation(s)`);
129
+ }
130
+ const actualCounts = candidateCounts(db);
131
+ for (const table of REQUIRED_RESTORE_TABLES) {
132
+ if (actualCounts[table] !== expectedCounts[table]) {
133
+ errors.push(`${table} row count is ${actualCounts[table]}, expected ${expectedCounts[table]}`);
134
+ }
135
+ }
136
+ return errors;
137
+ }
138
+ function inspectCandidate(stagedPath, candidatePath) {
139
+ let candidate;
140
+ let counts;
141
+ let validationError;
142
+ try {
143
+ candidate = new Database(stagedPath, { readonly: true, fileMustExist: true });
144
+ const missing = missingRequiredTables(candidate);
145
+ if (missing.length > 0) {
146
+ validationError = `Backup is incomplete (missing required table(s): ${missing.join(', ')}). Project exports cannot be restored; use the future elepha import command instead.`;
147
+ }
148
+ else {
149
+ counts = candidateCounts(candidate);
150
+ const errors = verifyDatabase(candidate, counts);
151
+ if (errors.length > 0) {
152
+ validationError = `Backup failed validation: ${errors.join('; ')}`;
153
+ }
154
+ }
155
+ }
156
+ catch (error) {
157
+ throw new Error(`Not a valid SQLite backup at ${candidatePath}: ${errorMessage(error)}`);
158
+ }
159
+ finally {
160
+ candidate?.close();
161
+ }
162
+ if (validationError !== undefined) {
163
+ throw new Error(validationError);
164
+ }
165
+ if (counts === undefined) {
166
+ throw new Error(`Not a valid SQLite backup at ${candidatePath}.`);
167
+ }
168
+ verifyStagedSchema(stagedPath);
169
+ return counts;
170
+ }
171
+ async function sha256File(filePath) {
172
+ const hash = createHash('sha256');
173
+ for await (const chunk of createReadStream(filePath)) {
174
+ hash.update(chunk);
175
+ }
176
+ return hash.digest('hex');
177
+ }
178
+ function printPreview(dbPath, candidatePath, counts, tombstones) {
179
+ console.log(`Restore preview: ${candidatePath}`);
180
+ console.log(`Active database: ${dbPath}`);
181
+ console.log('Candidate rows (the active database will become):');
182
+ for (const table of REQUIRED_RESTORE_TABLES) {
183
+ console.log(` ${table}: ${counts[table]}`);
184
+ }
185
+ console.log(`Carried tombstones: purged_transcripts: ${tombstones.purged_transcripts.length}, incognito_transcripts: ${tombstones.incognito_transcripts.length}`);
186
+ }
187
+ function checkpointActiveDatabase(dbPath) {
188
+ const db = new Database(dbPath);
189
+ db.pragma('wal_checkpoint(TRUNCATE)');
190
+ return db;
191
+ }
192
+ function activeTranscriptTombstones(dbPath) {
193
+ const tombstones = { purged_transcripts: [], incognito_transcripts: [] };
194
+ if (!existsSync(dbPath)) {
195
+ return tombstones;
196
+ }
197
+ const active = new Database(dbPath, { readonly: true, fileMustExist: true });
198
+ try {
199
+ for (const { table } of TOMBSTONE_TABLES) {
200
+ const exists = active.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(table);
201
+ if (exists !== undefined) {
202
+ tombstones[table] = active.prepare(`SELECT tool, native_id FROM ${table}`).all();
203
+ }
204
+ }
205
+ return tombstones;
206
+ }
207
+ finally {
208
+ active.close();
209
+ }
210
+ }
211
+ function unionTranscriptTombstones(dbPath, tombstones) {
212
+ const restored = openDb(dbPath);
213
+ try {
214
+ const recordedAt = new Date().toISOString();
215
+ restored.transaction(() => {
216
+ for (const { table, timestampColumn } of TOMBSTONE_TABLES) {
217
+ const insert = restored.prepare(`INSERT OR IGNORE INTO ${table} (tool, native_id, ${timestampColumn}) VALUES (?, ?, ?)`);
218
+ for (const transcript of tombstones[table]) {
219
+ insert.run(transcript.tool, transcript.native_id, recordedAt);
220
+ }
221
+ }
222
+ })();
223
+ const checkpoint = restored.pragma('wal_checkpoint(TRUNCATE)');
224
+ if (checkpoint[0]?.busy !== 0) {
225
+ throw new Error('Could not checkpoint preserved transcript tombstones.');
226
+ }
227
+ }
228
+ finally {
229
+ restored.close();
230
+ }
231
+ }
232
+ function removeStaleSidecars(dbPath) {
233
+ for (const sidecar of [`${dbPath}-wal`, `${dbPath}-shm`]) {
234
+ try {
235
+ unlinkSync(sidecar);
236
+ }
237
+ catch (error) {
238
+ if (error.code !== 'ENOENT') {
239
+ throw error;
240
+ }
241
+ }
242
+ }
243
+ }
244
+ function verifyRestoredDatabase(dbPath, expectedCounts) {
245
+ const restored = new Database(dbPath, { readonly: true, fileMustExist: true });
246
+ try {
247
+ const errors = verifyDatabase(restored, expectedCounts);
248
+ if (errors.length > 0) {
249
+ throw new Error(errors.join('; '));
250
+ }
251
+ }
252
+ finally {
253
+ restored.close();
254
+ }
255
+ }
256
+ /** Validates an external SQLite file then replaces the active database; it cannot use runDestructiveOp because the apply is an atomic file replacement, not a SQL transaction. */
257
+ export async function runRestoreOperation(candidatePath, runtime = {}) {
258
+ const dbPath = runtime.dbPath ?? defaultDbPath();
259
+ if (!existsSync(candidatePath)) {
260
+ throw new Error(`Backup file not found: ${candidatePath}`);
261
+ }
262
+ const stagedDirectory = mkdtempSync(path.join(tmpdir(), 'elepha-restore-'));
263
+ const stagedPath = path.join(stagedDirectory, 'candidate.db');
264
+ try {
265
+ atomicCopyPrivateFile(candidatePath, stagedPath, PRIVATE_FILE_MODE);
266
+ const counts = inspectCandidate(stagedPath, candidatePath);
267
+ const stagedHash = await sha256File(stagedPath);
268
+ const health = (runtime.daemonHealth ?? currentDaemonHealth)();
269
+ if (health.healthy) {
270
+ throw new Error(`Refusing restore while the daemon is running (${health.state}). Run elepha pause first.`);
271
+ }
272
+ if (health.state.startsWith('STUCK')) {
273
+ console.error(`Daemon appears stuck (${health.state}); proceeding — it is not writing.`);
274
+ }
275
+ const tombstones = activeTranscriptTombstones(dbPath);
276
+ printPreview(dbPath, candidatePath, counts, tombstones);
277
+ if (runtime.confirm && !(await runtime.confirm())) {
278
+ return { cancelled: true };
279
+ }
280
+ if (!existsSync(dbPath)) {
281
+ throw new Error(`No active elepha database exists at ${dbPath}; nothing can be snapshotted before restore.`);
282
+ }
283
+ const active = checkpointActiveDatabase(dbPath);
284
+ let snapshotPath;
285
+ try {
286
+ snapshotPath = (runtime.writeBackup ?? writeBackup)(active, dbPath);
287
+ }
288
+ finally {
289
+ active.close();
290
+ }
291
+ try {
292
+ atomicCopyPrivateFile(stagedPath, dbPath, PRIVATE_FILE_MODE);
293
+ }
294
+ catch (error) {
295
+ throw new RestoreApplyError(snapshotPath, error);
296
+ }
297
+ try {
298
+ const installedHash = await sha256File(dbPath);
299
+ if (installedHash !== stagedHash) {
300
+ //noinspection ExceptionCaughtLocallyJS
301
+ throw new Error('Installed database hash does not match the validated backup.');
302
+ }
303
+ removeStaleSidecars(dbPath);
304
+ verifyRestoredDatabase(dbPath, counts);
305
+ unionTranscriptTombstones(dbPath, tombstones);
306
+ // Read-only verification can create fresh empty WAL bookkeeping files;
307
+ // remove them too so no sidecar from before the replacement can survive.
308
+ removeStaleSidecars(dbPath);
309
+ }
310
+ catch (restoreError) {
311
+ try {
312
+ atomicCopyPrivateFile(snapshotPath, dbPath, PRIVATE_FILE_MODE);
313
+ removeStaleSidecars(dbPath);
314
+ }
315
+ catch (rollbackError) {
316
+ throw new RestoreApplyError(snapshotPath, new Error(`Rollback failed: ${errorMessage(rollbackError)}. Original restore error: ${errorMessage(restoreError)}`));
317
+ }
318
+ throw new Error(`Restore failed and the previous database was rolled back from ${snapshotPath}: ${errorMessage(restoreError)}`);
319
+ }
320
+ console.log(`Restored ${dbPath} from ${candidatePath}. Pre-restore snapshot: ${snapshotPath}`);
321
+ return { cancelled: false, snapshotPath };
322
+ }
323
+ finally {
324
+ removeTemporaryDatabase(stagedPath, stagedDirectory);
325
+ }
326
+ }
327
+ async function confirmRestore() {
328
+ return confirmYesNo('Replace the current elepha database with this backup? A snapshot is saved first. [y/N] ');
329
+ }
330
+ function reportRestoreError(error) {
331
+ console.error(errorMessage(error));
332
+ process.exitCode = 1;
333
+ }
334
+ /** Registers full-database restore. Project exports are deliberately reserved for the future import command. */
335
+ export function registerRestore(program) {
336
+ program
337
+ .command('restore [file]')
338
+ .description('Replace the local elepha database from a full elepha backup')
339
+ .option('--skip-confirmation', 'restore without an interactive confirmation')
340
+ .action(async (file, opts) => {
341
+ const restore = (candidate, confirm) => runRestoreOperation(candidate, { dbPath: defaultDbPath(), confirm });
342
+ if (file === undefined) {
343
+ if (!process.stdin.isTTY) {
344
+ console.error('Specify a backup file when not running interactively.');
345
+ process.exitCode = 1;
346
+ return;
347
+ }
348
+ try {
349
+ process.exitCode = await runRestoreWizard({
350
+ restore: (candidate, confirm) => restore(candidate, confirm),
351
+ });
352
+ }
353
+ catch (error) {
354
+ reportRestoreError(error);
355
+ }
356
+ return;
357
+ }
358
+ const confirm = opts.skipConfirmation
359
+ ? undefined
360
+ : process.stdin.isTTY
361
+ ? confirmRestore
362
+ : async () => {
363
+ throw new Error('Refusing to restore without a TTY confirmation. Re-run interactively or use --skip-confirmation.');
364
+ };
365
+ try {
366
+ const result = await restore(path.resolve(file), confirm);
367
+ if (result.cancelled) {
368
+ console.log('Cancelled — no changes were made.');
369
+ }
370
+ }
371
+ catch (error) {
372
+ reportRestoreError(error);
373
+ }
374
+ });
375
+ }
376
+ //# sourceMappingURL=restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../src/cli/commands/restore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { stat as statFile } from 'node:fs/promises';
2
+ import { ClaudeCodeAdapter } from '../../adapters/claude-code.js';
3
+ import { CodexAdapter } from '../../adapters/codex.js';
4
+ import { CHARS_PER_TOKEN } from '../../config/constants.js';
5
+ import { isReadableProviderSource } from '../../config/paths.js';
6
+ import { RollupService } from '../../daemon/rollup-service.js';
7
+ import { daemonHealth } from '../../install/health-checks.js';
8
+ import { openDb } from '../../storage/db.js';
9
+ import { MemoryStore } from '../../storage/memory-store.js';
10
+ import { ROLLUP_VERSION, RollupStore } from '../../storage/rollup-store.js';
11
+ import { SummarizerCallLog } from '../../summarizer/call-log.js';
12
+ import { estimateCostUsd } from '../../summarizer/pricing.js';
13
+ import { createConfiguredSynthesisProviders } from '../../summarizer/provider-config.js';
14
+ const REBUILD_PREVIEW_OUTPUT_TOKENS_PER_SESSION = 512;
15
+ export function registerRollup(program) {
16
+ program
17
+ .command('rollup', { hidden: true })
18
+ .description('Compute session rollups for sessions that do not have an up-to-date one. Safe to re-run: incremental and idempotent.')
19
+ .option('--all', 'include sessions whose transcript is still active (default: only sessions idle past the close threshold)')
20
+ .option('--rebuild', 'rebuild every rollup written by an older rollup_version, including finalized ones. Without this, only open sessions are visited, so a version bump silently misses every final rollup.')
21
+ .option('--apply', 'run a --rebuild after showing its estimated cost')
22
+ .option('--limit <n>', 'stop after N sessions', '0')
23
+ .action(async (opts) => {
24
+ let store;
25
+ let candidates;
26
+ // A multi-batch rebuild reprocesses a session from scratch across
27
+ // several model calls; the live daemon's own idle-sweep or
28
+ // new-turn-triggered rollupSession call can land on the same session
29
+ // in between those batches and move the watermark out from under it.
30
+ // The watermark guard then correctly refuses the rebuild's next
31
+ // write, but only after that batch's API call has already been
32
+ // paid for. Refusing outright beats racing (the incident this guards
33
+ // against: 9 of 10 sessions aborted this way in one run, $1.66 spent
34
+ // for no progress).
35
+ if (opts.rebuild) {
36
+ const rebuildStore = new MemoryStore(openDb());
37
+ store = rebuildStore;
38
+ candidates = rebuildStore.listSessionsForRollupRebuild(ROLLUP_VERSION);
39
+ if (!opts.apply) {
40
+ const inputTokens = candidates.reduce((sum, session) => sum +
41
+ (session.rendered_chars === null
42
+ ? rebuildStore.listMemoriesForSession(session.id).length
43
+ : Math.ceil(session.rendered_chars / CHARS_PER_TOKEN)), 0);
44
+ const outputTokens = candidates.length * REBUILD_PREVIEW_OUTPUT_TOKENS_PER_SESSION;
45
+ console.log(`Preview: ${candidates.length} session(s) would be rebuilt whose rollup predates v${ROLLUP_VERSION}.`);
46
+ console.log(`ESTIMATED cost: $${estimateCostUsd(inputTokens, outputTokens).toFixed(4)} (${inputTokens} input / ${outputTokens} output tokens).`);
47
+ console.log('Re-run with --rebuild --apply to make API calls.');
48
+ return;
49
+ }
50
+ const { state, healthy } = daemonHealth();
51
+ if (healthy) {
52
+ console.error(`Refusing to run --rebuild while the daemon is live (${state}).`);
53
+ console.error('Run `elepha pause`, then re-run `elepha rollup --rebuild --apply`, and finish with `elepha resume`.');
54
+ process.exitCode = 1;
55
+ return;
56
+ }
57
+ }
58
+ const providers = createConfiguredSynthesisProviders();
59
+ if (!providers) {
60
+ console.error('No synthesis provider configured. Set ANTHROPIC_API_KEY before running rollup.');
61
+ process.exitCode = 1;
62
+ return;
63
+ }
64
+ const activeStore = store ?? new MemoryStore(openDb());
65
+ const rollups = new RollupStore(activeStore.database);
66
+ const callLog = new SummarizerCallLog();
67
+ const service = new RollupService({
68
+ store: activeStore,
69
+ rollups,
70
+ provider: providers.rollupMerge,
71
+ log: (msg) => console.log(msg),
72
+ });
73
+ const adapters = { 'claude-code': new ClaudeCodeAdapter(), codex: new CodexAdapter() };
74
+ const limit = Number(opts.limit) || 0;
75
+ const runStart = new Date().toISOString();
76
+ let completed = 0;
77
+ let aborted = 0;
78
+ let skipped = 0;
79
+ // --rebuild widens the set to every stale-version rollup. The default
80
+ // sweep deliberately skips `final` rollups, which is correct for
81
+ // idle-close and wrong for a version bump.
82
+ const sessions = candidates ?? activeStore.listOpenSessions();
83
+ if (opts.rebuild) {
84
+ console.log(`Rebuilding ${sessions.length} session(s) whose rollup predates v${ROLLUP_VERSION}.`);
85
+ }
86
+ for (const session of sessions) {
87
+ if (limit && completed + aborted >= limit) {
88
+ break;
89
+ }
90
+ const adapter = adapters[session.tool];
91
+ if (!isReadableProviderSource(session.tool, session.source_path)) {
92
+ continue;
93
+ }
94
+ const stat = await statFile(session.source_path).catch(() => undefined);
95
+ const idle = stat ? service.isIdle(stat.mtimeMs) : true;
96
+ if (!opts.all && !idle) {
97
+ skipped++;
98
+ continue;
99
+ }
100
+ const classification = await adapter.classifySession(session.source_path);
101
+ const parentId = classification.parentNativeId
102
+ ? (activeStore.findSession(session.tool, classification.parentNativeId)?.id ?? null)
103
+ : null;
104
+ const outcome = await service.rollupSession(session, classification.kind, parentId, idle ? 'final' : 'live');
105
+ // wrote-but-not-complete is not success: it's a partially-applied
106
+ // rebuild that got interrupted, and reporting it as "done" is
107
+ // exactly the false-success line that hid the concurrency bug.
108
+ if (outcome.complete) {
109
+ if (outcome.wrote) {
110
+ completed++;
111
+ }
112
+ }
113
+ else {
114
+ aborted++;
115
+ }
116
+ }
117
+ const entries = callLog.readEntriesSince(runStart);
118
+ const inTok = entries.reduce((s, e) => s + (e.inputTokens ?? 0), 0);
119
+ const outTok = entries.reduce((s, e) => s + (e.outputTokens ?? 0), 0);
120
+ console.log(`\nRolled up ${completed} session(s); ${skipped} still active (use --all to include).`);
121
+ if (aborted > 0) {
122
+ console.log(`${aborted} session(s) ABORTED mid-rebuild (see "watermark moved" / "failed at batch" above) - re-run to retry them.`);
123
+ }
124
+ console.log(`API calls: ${entries.length} — tokens ${inTok} in / ${outTok} out — est. cost $${estimateCostUsd(inTok, outTok).toFixed(4)}`);
125
+ if (aborted > 0) {
126
+ process.exitCode = 1;
127
+ }
128
+ });
129
+ }
130
+ //# sourceMappingURL=rollup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollup.js","sourceRoot":"","sources":["../../../src/cli/commands/rollup.ts"],"names":[],"mappings":"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"}