@lossless-claude/lcm 0.5.0 → 0.7.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 (182) hide show
  1. package/.claude-plugin/commands/lcm-compact.md +10 -0
  2. package/.claude-plugin/commands/lcm-curate.md +16 -6
  3. package/.claude-plugin/commands/lcm-diagnose.md +10 -0
  4. package/.claude-plugin/commands/lcm-doctor.md +1 -1
  5. package/.claude-plugin/commands/lcm-dogfood.md +1 -1
  6. package/.claude-plugin/commands/lcm-import.md +10 -0
  7. package/.claude-plugin/commands/lcm-promote.md +10 -0
  8. package/.claude-plugin/commands/lcm-sensitive.md +10 -0
  9. package/.claude-plugin/commands/lcm-stats.md +1 -1
  10. package/.claude-plugin/commands/lcm-status.md +10 -0
  11. package/.claude-plugin/hooks/README.md +1 -1
  12. package/.claude-plugin/marketplace.json +1 -1
  13. package/.claude-plugin/plugin.json +14 -2
  14. package/.claude-plugin/skills/lcm-context/SKILL.md +10 -0
  15. package/.claude-plugin/skills/lcm-dogfood/SKILL.md +1 -1
  16. package/.claude-plugin/skills/lcm-dogfood/references/checks.md +1 -1
  17. package/README.md +2 -2
  18. package/dist/bin/lcm.js +828 -474
  19. package/dist/bin/lcm.js.map +1 -1
  20. package/dist/installer/install.d.ts +6 -5
  21. package/dist/installer/install.js +116 -108
  22. package/dist/installer/install.js.map +1 -1
  23. package/dist/src/batch-compact.d.ts +7 -1
  24. package/dist/src/batch-compact.js +80 -6
  25. package/dist/src/batch-compact.js.map +1 -1
  26. package/dist/src/bootstrap.d.ts +24 -0
  27. package/dist/src/bootstrap.js +76 -0
  28. package/dist/src/bootstrap.js.map +1 -0
  29. package/dist/src/cli/pipeline-runner.d.ts +47 -0
  30. package/dist/src/cli/pipeline-runner.js +106 -0
  31. package/dist/src/cli/pipeline-runner.js.map +1 -0
  32. package/dist/src/cli/pipeline-step.d.ts +20 -0
  33. package/dist/src/cli/pipeline-step.js +6 -0
  34. package/dist/src/cli/pipeline-step.js.map +1 -0
  35. package/dist/src/cli/progress-state.d.ts +61 -0
  36. package/dist/src/cli/progress-state.js +16 -0
  37. package/dist/src/cli/progress-state.js.map +1 -0
  38. package/dist/src/cli/render-frame.d.ts +26 -0
  39. package/dist/src/cli/render-frame.js +153 -0
  40. package/dist/src/cli/render-frame.js.map +1 -0
  41. package/dist/src/cli/render-summary.d.ts +8 -0
  42. package/dist/src/cli/render-summary.js +79 -0
  43. package/dist/src/cli/render-summary.js.map +1 -0
  44. package/dist/src/cli-help.js +15 -9
  45. package/dist/src/cli-help.js.map +1 -1
  46. package/dist/src/codex-transcript.d.ts +50 -0
  47. package/dist/src/codex-transcript.js +207 -0
  48. package/dist/src/codex-transcript.js.map +1 -0
  49. package/dist/src/daemon/auth.d.ts +2 -0
  50. package/dist/src/daemon/auth.js +40 -0
  51. package/dist/src/daemon/auth.js.map +1 -0
  52. package/dist/src/daemon/client.d.ts +5 -1
  53. package/dist/src/daemon/client.js +21 -2
  54. package/dist/src/daemon/client.js.map +1 -1
  55. package/dist/src/daemon/config.d.ts +15 -0
  56. package/dist/src/daemon/config.js +33 -8
  57. package/dist/src/daemon/config.js.map +1 -1
  58. package/dist/src/daemon/content-fence.d.ts +7 -0
  59. package/dist/src/daemon/content-fence.js +14 -0
  60. package/dist/src/daemon/content-fence.js.map +1 -0
  61. package/dist/src/daemon/lifecycle.js +5 -0
  62. package/dist/src/daemon/lifecycle.js.map +1 -1
  63. package/dist/src/daemon/orientation.d.ts +1 -0
  64. package/dist/src/daemon/orientation.js +35 -6
  65. package/dist/src/daemon/orientation.js.map +1 -1
  66. package/dist/src/daemon/project.d.ts +1 -0
  67. package/dist/src/daemon/project.js +95 -3
  68. package/dist/src/daemon/project.js.map +1 -1
  69. package/dist/src/daemon/routes/compact.js +41 -10
  70. package/dist/src/daemon/routes/compact.js.map +1 -1
  71. package/dist/src/daemon/routes/describe.js +12 -1
  72. package/dist/src/daemon/routes/describe.js.map +1 -1
  73. package/dist/src/daemon/routes/expand.js +12 -1
  74. package/dist/src/daemon/routes/expand.js.map +1 -1
  75. package/dist/src/daemon/routes/grep.js +11 -2
  76. package/dist/src/daemon/routes/grep.js.map +1 -1
  77. package/dist/src/daemon/routes/ingest.js +36 -8
  78. package/dist/src/daemon/routes/ingest.js.map +1 -1
  79. package/dist/src/daemon/routes/promote-events.d.ts +3 -0
  80. package/dist/src/daemon/routes/promote-events.js +180 -0
  81. package/dist/src/daemon/routes/promote-events.js.map +1 -0
  82. package/dist/src/daemon/routes/promote.js +18 -3
  83. package/dist/src/daemon/routes/promote.js.map +1 -1
  84. package/dist/src/daemon/routes/prompt-search.js +11 -2
  85. package/dist/src/daemon/routes/prompt-search.js.map +1 -1
  86. package/dist/src/daemon/routes/recent.js +11 -2
  87. package/dist/src/daemon/routes/recent.js.map +1 -1
  88. package/dist/src/daemon/routes/restore.js +117 -69
  89. package/dist/src/daemon/routes/restore.js.map +1 -1
  90. package/dist/src/daemon/routes/search.js +12 -1
  91. package/dist/src/daemon/routes/search.js.map +1 -1
  92. package/dist/src/daemon/routes/session-complete.d.ts +2 -0
  93. package/dist/src/daemon/routes/session-complete.js +36 -0
  94. package/dist/src/daemon/routes/session-complete.js.map +1 -0
  95. package/dist/src/daemon/routes/status.js +77 -64
  96. package/dist/src/daemon/routes/status.js.map +1 -1
  97. package/dist/src/daemon/routes/store.d.ts +2 -1
  98. package/dist/src/daemon/routes/store.js +42 -8
  99. package/dist/src/daemon/routes/store.js.map +1 -1
  100. package/dist/src/daemon/safe-error.d.ts +5 -0
  101. package/dist/src/daemon/safe-error.js +15 -0
  102. package/dist/src/daemon/safe-error.js.map +1 -0
  103. package/dist/src/daemon/server.d.ts +3 -1
  104. package/dist/src/daemon/server.js +37 -17
  105. package/dist/src/daemon/server.js.map +1 -1
  106. package/dist/src/daemon/validate-cwd.d.ts +5 -0
  107. package/dist/src/daemon/validate-cwd.js +38 -0
  108. package/dist/src/daemon/validate-cwd.js.map +1 -0
  109. package/dist/src/daemon/version.d.ts +10 -0
  110. package/dist/src/daemon/version.js +31 -0
  111. package/dist/src/daemon/version.js.map +1 -0
  112. package/dist/src/db/events-path.d.ts +2 -0
  113. package/dist/src/db/events-path.js +11 -0
  114. package/dist/src/db/events-path.js.map +1 -0
  115. package/dist/src/db/events-stats.d.ts +29 -0
  116. package/dist/src/db/events-stats.js +107 -0
  117. package/dist/src/db/events-stats.js.map +1 -0
  118. package/dist/src/db/migration.js +8 -0
  119. package/dist/src/db/migration.js.map +1 -1
  120. package/dist/src/diagnose.js +14 -1
  121. package/dist/src/diagnose.js.map +1 -1
  122. package/dist/src/doctor/doctor.d.ts +1 -1
  123. package/dist/src/doctor/doctor.js +184 -15
  124. package/dist/src/doctor/doctor.js.map +1 -1
  125. package/dist/src/hooks/auto-heal.js +24 -1
  126. package/dist/src/hooks/auto-heal.js.map +1 -1
  127. package/dist/src/hooks/compact.js +7 -0
  128. package/dist/src/hooks/compact.js.map +1 -1
  129. package/dist/src/hooks/dispatch.d.ts +1 -1
  130. package/dist/src/hooks/dispatch.js +19 -1
  131. package/dist/src/hooks/dispatch.js.map +1 -1
  132. package/dist/src/hooks/events-db.d.ts +41 -0
  133. package/dist/src/hooks/events-db.js +190 -0
  134. package/dist/src/hooks/events-db.js.map +1 -0
  135. package/dist/src/hooks/extractors.d.ts +17 -0
  136. package/dist/src/hooks/extractors.js +198 -0
  137. package/dist/src/hooks/extractors.js.map +1 -0
  138. package/dist/src/hooks/hook-errors.d.ts +14 -0
  139. package/dist/src/hooks/hook-errors.js +56 -0
  140. package/dist/src/hooks/hook-errors.js.map +1 -0
  141. package/dist/src/hooks/post-tool.d.ts +4 -0
  142. package/dist/src/hooks/post-tool.js +43 -0
  143. package/dist/src/hooks/post-tool.js.map +1 -0
  144. package/dist/src/hooks/restore.js +31 -1
  145. package/dist/src/hooks/restore.js.map +1 -1
  146. package/dist/src/hooks/session-end.d.ts +3 -0
  147. package/dist/src/hooks/session-end.js +68 -5
  148. package/dist/src/hooks/session-end.js.map +1 -1
  149. package/dist/src/hooks/session-snapshot.d.ts +12 -0
  150. package/dist/src/hooks/session-snapshot.js +100 -0
  151. package/dist/src/hooks/session-snapshot.js.map +1 -0
  152. package/dist/src/hooks/user-prompt.js +44 -5
  153. package/dist/src/hooks/user-prompt.js.map +1 -1
  154. package/dist/src/import-summary.d.ts +4 -0
  155. package/dist/src/import-summary.js +34 -0
  156. package/dist/src/import-summary.js.map +1 -0
  157. package/dist/src/import.d.ts +11 -1
  158. package/dist/src/import.js +218 -88
  159. package/dist/src/import.js.map +1 -1
  160. package/dist/src/installer/settings.d.ts +5 -0
  161. package/dist/src/installer/settings.js +74 -0
  162. package/dist/src/installer/settings.js.map +1 -0
  163. package/dist/src/mcp/server.d.ts +15 -0
  164. package/dist/src/mcp/server.js +83 -6
  165. package/dist/src/mcp/server.js.map +1 -1
  166. package/dist/src/promotion/detector.js +19 -5
  167. package/dist/src/promotion/detector.js.map +1 -1
  168. package/dist/src/scrub.js +26 -0
  169. package/dist/src/scrub.js.map +1 -1
  170. package/dist/src/stats.d.ts +4 -0
  171. package/dist/src/stats.js +23 -0
  172. package/dist/src/stats.js.map +1 -1
  173. package/dist/src/store/conversation-store.js +2 -1
  174. package/dist/src/store/conversation-store.js.map +1 -1
  175. package/dist/src/store/regex-safety.d.ts +1 -0
  176. package/dist/src/store/regex-safety.js +22 -0
  177. package/dist/src/store/regex-safety.js.map +1 -0
  178. package/dist/src/store/summary-store.js +2 -1
  179. package/dist/src/store/summary-store.js.map +1 -1
  180. package/docs/passive-learning.md +138 -0
  181. package/lcm.mjs +20 -1
  182. package/package.json +5 -2
@@ -35,6 +35,60 @@ export function fireCompactRequest(port, body) {
35
35
  req.write(json);
36
36
  req.end();
37
37
  }
38
+ export function firePromoteRequest(port, body) {
39
+ const json = JSON.stringify(body);
40
+ const req = request({
41
+ hostname: "127.0.0.1",
42
+ port,
43
+ path: "/promote",
44
+ method: "POST",
45
+ headers: {
46
+ "Content-Type": "application/json",
47
+ "Content-Length": Buffer.byteLength(json),
48
+ },
49
+ });
50
+ req.on("socket", (socket) => {
51
+ req.on("finish", () => socket.unref());
52
+ });
53
+ req.on("error", () => { });
54
+ req.write(json);
55
+ req.end();
56
+ }
57
+ export function firePromoteEventsRequest(port, body) {
58
+ const json = JSON.stringify(body);
59
+ const req = request({
60
+ hostname: "127.0.0.1",
61
+ port,
62
+ path: "/promote-events",
63
+ method: "POST",
64
+ headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(json) },
65
+ });
66
+ req.on("socket", (socket) => {
67
+ req.on("finish", () => socket.unref());
68
+ });
69
+ req.on("error", () => { }); // non-fatal
70
+ req.write(json);
71
+ req.end();
72
+ }
73
+ export function fireSessionCompleteRequest(port, body) {
74
+ const json = JSON.stringify(body);
75
+ const req = request({
76
+ hostname: "127.0.0.1",
77
+ port,
78
+ path: "/session-complete",
79
+ method: "POST",
80
+ headers: {
81
+ "Content-Type": "application/json",
82
+ "Content-Length": Buffer.byteLength(json),
83
+ },
84
+ });
85
+ req.on("socket", (socket) => {
86
+ req.on("finish", () => socket.unref());
87
+ });
88
+ req.on("error", () => { });
89
+ req.write(json);
90
+ req.end();
91
+ }
38
92
  export async function handleSessionEnd(stdin, client, port) {
39
93
  const daemonPort = port ?? 3737;
40
94
  const pidFilePath = join(homedir(), ".lossless-claude", "daemon.pid");
@@ -48,13 +102,10 @@ export async function handleSessionEnd(stdin, client, port) {
48
102
  try {
49
103
  const input = JSON.parse(stdin || "{}");
50
104
  const ingestResult = await client.post("/ingest", input);
51
- // Auto-compact if conversation exceeds threshold
52
105
  const configPath = join(homedir(), ".lossless-claude", "config.json");
53
106
  const config = loadDaemonConfig(configPath);
54
- const threshold = config.compaction.autoCompactMinTokens;
55
- if (threshold > 0 &&
56
- typeof ingestResult.totalTokens === "number" &&
57
- ingestResult.totalTokens >= threshold) {
107
+ const disableCompact = config.hooks?.disableAutoCompact ?? false;
108
+ if (!disableCompact) {
58
109
  // Fire-and-forget via unreffed http.request — does not block the event loop.
59
110
  // The daemon receives and compacts independently after the hook process exits.
60
111
  fireCompactRequest(daemonPort, {
@@ -64,6 +115,18 @@ export async function handleSessionEnd(stdin, client, port) {
64
115
  client: "claude",
65
116
  });
66
117
  }
118
+ // Always promote
119
+ firePromoteRequest(daemonPort, { cwd: input.cwd });
120
+ // Promote events for passive learning
121
+ firePromoteEventsRequest(daemonPort, { cwd: input.cwd });
122
+ // Record session completion in manifest.
123
+ // Note: ingestResult.ingested is the delta (new messages this call), not the total.
124
+ // We pass it as-is since we don't have the total without an extra DB query.
125
+ fireSessionCompleteRequest(daemonPort, {
126
+ session_id: input.session_id,
127
+ cwd: input.cwd,
128
+ message_count: ingestResult.ingested ?? 0,
129
+ });
67
130
  return { exitCode: 0, stdout: "" };
68
131
  }
69
132
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"session-end.js","sourceRoot":"","sources":["../../../src/hooks/session-end.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,IAA6B;IAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,OAAO,CAAC;QAClB,QAAQ,EAAE,WAAW;QACrB,IAAI;QACJ,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;SAC1C;KACF,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;QAC1B,sEAAsE;QACtE,6EAA6E;QAC7E,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAE,MAAoC,CAAC,KAAK,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,YAAY;IACvC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChB,GAAG,CAAC,GAAG,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,MAAoB,EACpB,IAAa;IAEb,MAAM,UAAU,GAAG,IAAI,IAAI,IAAI,CAAC;IAChC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC;IACtE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,CAAC;QACvC,IAAI,EAAE,UAAU;QAChB,WAAW;QACX,cAAc,EAAE,IAAI;KACrB,CAAC,CAAC;IACH,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;QACxC,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,IAAI,CAGnC,SAAS,EAAE,KAAK,CAAC,CAAC;QAErB,iDAAiD;QACjD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,EAAE,aAAa,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC;QAEzD,IACE,SAAS,GAAG,CAAC;YACb,OAAO,YAAY,CAAC,WAAW,KAAK,QAAQ;YAC5C,YAAY,CAAC,WAAW,IAAI,SAAS,EACrC,CAAC;YACD,6EAA6E;YAC7E,+EAA+E;YAC/E,kBAAkB,CAAC,UAAU,EAAE;gBAC7B,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,WAAW,EAAE,IAAI;gBACjB,MAAM,EAAE,QAAQ;aACjB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"session-end.js","sourceRoot":"","sources":["../../../src/hooks/session-end.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface SnapshotDeps {
2
+ statSync: (path: string) => {
3
+ mtimeMs: number;
4
+ } | null;
5
+ writeFileSync: (path: string, data: string) => void;
6
+ snapshotIntervalSec: number;
7
+ post: (path: string, body: Record<string, unknown>) => Promise<unknown>;
8
+ }
9
+ export declare function handleSessionSnapshot(stdin: string, deps?: Partial<SnapshotDeps>): Promise<{
10
+ exitCode: number;
11
+ stdout: string;
12
+ }>;
@@ -0,0 +1,100 @@
1
+ import { statSync, writeFileSync, mkdirSync, chmodSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ function defaultStatSync(path) {
5
+ try {
6
+ return statSync(path);
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ }
12
+ export async function handleSessionSnapshot(stdin, deps) {
13
+ try {
14
+ const input = JSON.parse(stdin || "{}");
15
+ const { session_id, cwd, transcript_path } = input;
16
+ if (!session_id || !cwd || !transcript_path) {
17
+ return { exitCode: 0, stdout: "" };
18
+ }
19
+ const safeSessionId = session_id.replace(/[^a-zA-Z0-9_-]/g, "_");
20
+ const cursorDir = join(homedir(), ".lossless-claude", "tmp");
21
+ mkdirSync(cursorDir, { recursive: true, mode: 0o700 });
22
+ const cursorPath = join(cursorDir, `snap-${safeSessionId}.json`);
23
+ const _statSync = deps?.statSync ?? defaultStatSync;
24
+ let intervalSec = deps?.snapshotIntervalSec;
25
+ if (intervalSec === undefined) {
26
+ const { loadDaemonConfig } = await import("../daemon/config.js");
27
+ const { homedir } = await import("node:os");
28
+ const config = loadDaemonConfig(join(homedir(), ".lossless-claude", "config.json"));
29
+ intervalSec = config.hooks?.snapshotIntervalSec ?? 60;
30
+ }
31
+ // Throttle: stat cursor mtime, skip if within interval
32
+ let stat = null;
33
+ try {
34
+ stat = _statSync(cursorPath);
35
+ }
36
+ catch {
37
+ // No cursor file — treat as expired
38
+ }
39
+ if (stat && (Date.now() - stat.mtimeMs) < intervalSec * 1000) {
40
+ return { exitCode: 0, stdout: "" };
41
+ }
42
+ // POST to /ingest — daemon handles delta via storedCount
43
+ const _post = deps?.post;
44
+ if (_post) {
45
+ await _post("/ingest", { session_id, cwd, transcript_path });
46
+ }
47
+ else {
48
+ const { loadDaemonConfig } = await import("../daemon/config.js");
49
+ const { readFileSync: _readFileSync } = await import("node:fs");
50
+ const { homedir: _homedir } = await import("node:os");
51
+ const config = loadDaemonConfig(join(_homedir(), ".lossless-claude", "config.json"));
52
+ const port = config.daemon?.port ?? 3737;
53
+ const baseUrl = `http://127.0.0.1:${port}`;
54
+ // Read token from token file if available (silent fallback if not found)
55
+ let token = null;
56
+ try {
57
+ const tokenPath = join(_homedir(), ".lossless-claude", "daemon.token");
58
+ const raw = _readFileSync(tokenPath, "utf-8").trim();
59
+ token = raw || null;
60
+ }
61
+ catch {
62
+ // Token file not found — auth not yet set up, proceed without it
63
+ }
64
+ const headers = { "Content-Type": "application/json" };
65
+ if (token) {
66
+ headers["Authorization"] = `Bearer ${token}`;
67
+ }
68
+ await fetch(`${baseUrl}/ingest`, {
69
+ method: "POST",
70
+ headers,
71
+ body: JSON.stringify({ session_id, cwd, transcript_path }),
72
+ signal: AbortSignal.timeout(5000),
73
+ });
74
+ }
75
+ // Touch cursor file
76
+ const _writeFileSync = deps?.writeFileSync ?? writeFileSync;
77
+ _writeFileSync(cursorPath, JSON.stringify({ ts: Date.now() }));
78
+ try {
79
+ chmodSync(cursorPath, 0o600);
80
+ }
81
+ catch { /* non-fatal */ }
82
+ // Best-effort promote-events flush
83
+ try {
84
+ const { loadDaemonConfig: _loadConfig } = await import("../daemon/config.js");
85
+ const { homedir: _homedir2 } = await import("node:os");
86
+ const _config = _loadConfig(join(_homedir2(), ".lossless-claude", "config.json"));
87
+ const port = _config.daemon?.port ?? 3737;
88
+ const { firePromoteEventsRequest } = await import("./session-end.js");
89
+ firePromoteEventsRequest(port, { cwd: input.cwd });
90
+ }
91
+ catch {
92
+ // Best-effort only
93
+ }
94
+ return { exitCode: 0, stdout: "" };
95
+ }
96
+ catch {
97
+ return { exitCode: 0, stdout: "" };
98
+ }
99
+ }
100
+ //# sourceMappingURL=session-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-snapshot.js","sourceRoot":"","sources":["../../../src/hooks/session-snapshot.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,55 @@
1
1
  import { ensureDaemon } from "../daemon/lifecycle.js";
2
2
  import { join } from "node:path";
3
3
  import { homedir } from "node:os";
4
+ import { safeLogError } from "./hook-errors.js";
5
+ const LEARNING_INSTRUCTION = `<learning-instruction>
6
+ When you recognize a durable insight, call lcm_store immediately:
7
+ - decision: architectural/design choice with trade-offs
8
+ - preference: user working style or tool preference
9
+ - root-cause: bug cause that took effort to uncover
10
+ - pattern: codebase convention not documented elsewhere
11
+ - gotcha: non-obvious pitfall or footgun
12
+ - solution: non-trivial fix worth remembering
13
+ - workflow: multi-step process that works
14
+
15
+ Usage: lcm_store(text: "concise insight with why", tags: ["category:decision"])
16
+ </learning-instruction>`;
4
17
  export async function handleUserPromptSubmit(stdin, client, port) {
5
18
  const daemonPort = port ?? 3737;
6
19
  const pidFilePath = join(homedir(), ".lossless-claude", "daemon.pid");
7
20
  const { connected } = await ensureDaemon({ port: daemonPort, pidFilePath, spawnTimeoutMs: 5000 });
8
21
  if (!connected)
9
- return { exitCode: 0, stdout: "" };
22
+ return { exitCode: 0, stdout: LEARNING_INSTRUCTION };
10
23
  try {
11
24
  const input = JSON.parse(stdin || "{}");
12
25
  if (!input.prompt || typeof input.prompt !== "string" || !input.prompt.trim()) {
13
- return { exitCode: 0, stdout: "" };
26
+ return { exitCode: 0, stdout: LEARNING_INSTRUCTION };
27
+ }
28
+ // Sidecar event extraction — must happen before prompt-search, must never throw
29
+ try {
30
+ const { extractUserPromptEvents } = await import("./extractors.js");
31
+ const { EventsDb } = await import("./events-db.js");
32
+ const { eventsDbPath } = await import("../db/events-path.js");
33
+ const prompt = String(input.prompt ?? "");
34
+ const events = extractUserPromptEvents(prompt);
35
+ if (events.length > 0 && input.session_id && typeof input.session_id === "string") {
36
+ const cwd = input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
37
+ const db = new EventsDb(eventsDbPath(cwd));
38
+ try {
39
+ for (const event of events) {
40
+ db.insertEvent(input.session_id, event, "UserPromptSubmit");
41
+ }
42
+ }
43
+ finally {
44
+ db.close();
45
+ }
46
+ }
47
+ }
48
+ catch (e) {
49
+ safeLogError("UserPromptSubmit", e, {
50
+ cwd: input.cwd ?? process.env.CLAUDE_PROJECT_DIR,
51
+ sessionId: input.session_id,
52
+ });
14
53
  }
15
54
  const result = await client.post("/prompt-search", {
16
55
  query: input.prompt,
@@ -18,14 +57,14 @@ export async function handleUserPromptSubmit(stdin, client, port) {
18
57
  session_id: input.session_id,
19
58
  });
20
59
  if (!result.hints || result.hints.length === 0) {
21
- return { exitCode: 0, stdout: "" };
60
+ return { exitCode: 0, stdout: LEARNING_INSTRUCTION };
22
61
  }
23
62
  const snippets = result.hints.map((h) => `- ${h}`).join("\n");
24
63
  const hint = `<memory-context>\nRelevant context from previous sessions (use lcm_expand for details):\n${snippets}\n</memory-context>`;
25
- return { exitCode: 0, stdout: hint };
64
+ return { exitCode: 0, stdout: `${hint}\n${LEARNING_INSTRUCTION}` };
26
65
  }
27
66
  catch {
28
- return { exitCode: 0, stdout: "" };
67
+ return { exitCode: 0, stdout: LEARNING_INSTRUCTION };
29
68
  }
30
69
  }
31
70
  //# sourceMappingURL=user-prompt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-prompt.js","sourceRoot":"","sources":["../../../src/hooks/user-prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAMlC,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAAa,EACb,MAAoB,EACpB,IAAa;IAEb,MAAM,UAAU,GAAG,IAAI,IAAI,IAAI,CAAC;IAChC,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC;IACtE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAClG,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAEnD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAC9E,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACrC,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAuB,gBAAgB,EAAE;YACvE,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,UAAU,EAAE,KAAK,CAAC,UAAU;SAC7B,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACrC,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9D,MAAM,IAAI,GAAG,4FAA4F,QAAQ,qBAAqB,CAAC;QACvI,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"user-prompt.js","sourceRoot":"","sources":["../../../src/hooks/user-prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ImportResult } from "./import.js";
2
+ export declare function printImportSummary(result: ImportResult, opts?: {
3
+ replay?: boolean;
4
+ }): void;
@@ -0,0 +1,34 @@
1
+ import { formatNumber, formatRatio } from "./stats.js";
2
+ export function printImportSummary(result, opts = {}) {
3
+ const sessionsProcessed = result.imported + result.skippedEmpty + result.failed;
4
+ const tokenSuffix = result.totalTokens > 0 ? `, ${formatNumber(result.totalTokens)} tokens` : "";
5
+ console.log(` ${result.imported} sessions imported (${result.totalMessages} messages${tokenSuffix})`);
6
+ if (result.skippedEmpty > 0)
7
+ console.log(` ${result.skippedEmpty} skipped (empty transcript)`);
8
+ if (result.failed > 0)
9
+ console.log(` ${result.failed} failed`);
10
+ if (opts.replay) {
11
+ console.log(" [replay] Sessions compacted sequentially with threaded context.");
12
+ }
13
+ // Show compression summary when tokens were ingested
14
+ if (result.totalTokens > 0) {
15
+ const border = "\u2500".repeat(41);
16
+ console.log();
17
+ console.log(` ${border}`);
18
+ const rows = [
19
+ ["Sessions processed", String(sessionsProcessed)],
20
+ ["Tokens ingested", formatNumber(result.totalTokens)],
21
+ ];
22
+ if (opts.replay && result.totalTokens > result.tokensAfter) {
23
+ const ratio = formatRatio(result.totalTokens, result.tokensAfter);
24
+ const freed = result.totalTokens - result.tokensAfter;
25
+ rows.push(["Tokens after", formatNumber(result.tokensAfter)], ["Compression ratio", `${ratio}\u00d7`], ["Tokens freed", formatNumber(freed)]);
26
+ }
27
+ const labelWidth = Math.max(...rows.map(([l]) => l.length));
28
+ for (const [label, value] of rows) {
29
+ console.log(` ${label.padEnd(labelWidth)} : ${value}`);
30
+ }
31
+ console.log(` ${border}`);
32
+ }
33
+ }
34
+ //# sourceMappingURL=import-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-summary.js","sourceRoot":"","sources":["../../src/import-summary.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvD,MAAM,UAAU,kBAAkB,CAChC,MAAoB,EACpB,OAA6B,EAAE;IAE/B,MAAM,iBAAiB,GAAG,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;IAChF,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IACjG,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,QAAQ,uBAAuB,MAAM,CAAC,aAAa,YAAY,WAAW,GAAG,CAAC,CAAC;IACvG,IAAI,MAAM,CAAC,YAAY,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,YAAY,6BAA6B,CAAC,CAAC;IAChG,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;IAEhE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;IACnF,CAAC;IAED,qDAAqD;IACrD,IAAI,MAAM,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;QAE3B,MAAM,IAAI,GAAuB;YAC/B,CAAC,oBAAoB,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC;YACjD,CAAC,iBAAiB,EAAE,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;SACtD,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;YAClE,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;YACtD,IAAI,CAAC,IAAI,CACP,CAAC,cAAc,EAAE,YAAY,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EAClD,CAAC,mBAAmB,EAAE,GAAG,KAAK,QAAQ,CAAC,EACvC,CAAC,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CACtC,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5D,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"}
@@ -1,20 +1,30 @@
1
1
  import type { DaemonClient } from "./daemon/client.js";
2
+ import type { ProgressState } from "./cli/progress-state.js";
3
+ export type ImportProvider = "claude" | "codex" | "all";
2
4
  interface ImportOptions {
3
5
  all?: boolean;
4
6
  verbose?: boolean;
5
7
  dryRun?: boolean;
6
8
  cwd?: string;
7
9
  replay?: boolean;
10
+ /** Which transcript provider to import from (default: "claude") */
11
+ provider?: ImportProvider;
12
+ /** Called with state patches as each session is processed — used by the ninja renderer */
13
+ onProgress?: (patch: Partial<ProgressState>) => void;
8
14
  /** Override ~/.claude/projects path — used in tests only */
9
15
  _claudeProjectsDir?: string;
10
16
  /** Override ~/.lossless-claude path — used in tests only */
11
17
  _lcmDir?: string;
18
+ /** Override ~/.codex path — used in tests only */
19
+ _codexDir?: string;
12
20
  }
13
- interface ImportResult {
21
+ export interface ImportResult {
14
22
  imported: number;
15
23
  skippedEmpty: number;
16
24
  failed: number;
17
25
  totalMessages: number;
26
+ totalTokens: number;
27
+ tokensAfter: number;
18
28
  }
19
29
  export declare function cwdToProjectHash(cwd: string): string;
20
30
  export declare function findSessionFiles(projectDir: string): {