@tekmidian/pai 0.5.7 → 0.6.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 (137) hide show
  1. package/ARCHITECTURE.md +72 -1
  2. package/README.md +87 -1
  3. package/dist/{auto-route-BG6I_4B1.mjs → auto-route-C-DrW6BL.mjs} +3 -3
  4. package/dist/{auto-route-BG6I_4B1.mjs.map → auto-route-C-DrW6BL.mjs.map} +1 -1
  5. package/dist/cli/index.mjs +1482 -1628
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/clusters-JIDQW65f.mjs +201 -0
  8. package/dist/clusters-JIDQW65f.mjs.map +1 -0
  9. package/dist/{config-Cf92lGX_.mjs → config-BuhHWyOK.mjs} +21 -6
  10. package/dist/config-BuhHWyOK.mjs.map +1 -0
  11. package/dist/daemon/index.mjs +11 -8
  12. package/dist/daemon/index.mjs.map +1 -1
  13. package/dist/{daemon-2ND5WO2j.mjs → daemon-D3hYb5_C.mjs} +669 -218
  14. package/dist/daemon-D3hYb5_C.mjs.map +1 -0
  15. package/dist/daemon-mcp/index.mjs +4597 -4
  16. package/dist/daemon-mcp/index.mjs.map +1 -1
  17. package/dist/db-DdUperSl.mjs +110 -0
  18. package/dist/db-DdUperSl.mjs.map +1 -0
  19. package/dist/{detect-BU3Nx_2L.mjs → detect-CdaA48EI.mjs} +1 -1
  20. package/dist/{detect-BU3Nx_2L.mjs.map → detect-CdaA48EI.mjs.map} +1 -1
  21. package/dist/{detector-Bp-2SM3x.mjs → detector-jGBuYQJM.mjs} +2 -2
  22. package/dist/{detector-Bp-2SM3x.mjs.map → detector-jGBuYQJM.mjs.map} +1 -1
  23. package/dist/{factory-Bzcy70G9.mjs → factory-Ygqe_bVZ.mjs} +7 -5
  24. package/dist/{factory-Bzcy70G9.mjs.map → factory-Ygqe_bVZ.mjs.map} +1 -1
  25. package/dist/helpers-BEST-4Gx.mjs +420 -0
  26. package/dist/helpers-BEST-4Gx.mjs.map +1 -0
  27. package/dist/hooks/capture-all-events.mjs +2 -2
  28. package/dist/hooks/capture-all-events.mjs.map +3 -3
  29. package/dist/hooks/capture-session-summary.mjs +38 -0
  30. package/dist/hooks/capture-session-summary.mjs.map +3 -3
  31. package/dist/hooks/cleanup-session-files.mjs +6 -12
  32. package/dist/hooks/cleanup-session-files.mjs.map +4 -4
  33. package/dist/hooks/context-compression-hook.mjs +93 -104
  34. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  35. package/dist/hooks/initialize-session.mjs +14 -11
  36. package/dist/hooks/initialize-session.mjs.map +4 -4
  37. package/dist/hooks/inject-observations.mjs +220 -0
  38. package/dist/hooks/inject-observations.mjs.map +7 -0
  39. package/dist/hooks/load-core-context.mjs +2 -2
  40. package/dist/hooks/load-core-context.mjs.map +3 -3
  41. package/dist/hooks/load-project-context.mjs +90 -91
  42. package/dist/hooks/load-project-context.mjs.map +4 -4
  43. package/dist/hooks/observe.mjs +354 -0
  44. package/dist/hooks/observe.mjs.map +7 -0
  45. package/dist/hooks/stop-hook.mjs +94 -107
  46. package/dist/hooks/stop-hook.mjs.map +4 -4
  47. package/dist/hooks/sync-todo-to-md.mjs +31 -33
  48. package/dist/hooks/sync-todo-to-md.mjs.map +4 -4
  49. package/dist/index.d.mts +30 -7
  50. package/dist/index.d.mts.map +1 -1
  51. package/dist/index.mjs +5 -8
  52. package/dist/indexer-D53l5d1U.mjs +1 -0
  53. package/dist/{indexer-backend-CIMXedqk.mjs → indexer-backend-jcJFsmB4.mjs} +37 -127
  54. package/dist/indexer-backend-jcJFsmB4.mjs.map +1 -0
  55. package/dist/{ipc-client-Bjg_a1dc.mjs → ipc-client-CoyUHPod.mjs} +2 -7
  56. package/dist/{ipc-client-Bjg_a1dc.mjs.map → ipc-client-CoyUHPod.mjs.map} +1 -1
  57. package/dist/latent-ideas-bTJo6Omd.mjs +191 -0
  58. package/dist/latent-ideas-bTJo6Omd.mjs.map +1 -0
  59. package/dist/neighborhood-BYYbEkUJ.mjs +135 -0
  60. package/dist/neighborhood-BYYbEkUJ.mjs.map +1 -0
  61. package/dist/note-context-BK24bX8Y.mjs +126 -0
  62. package/dist/note-context-BK24bX8Y.mjs.map +1 -0
  63. package/dist/postgres-CKf-EDtS.mjs +846 -0
  64. package/dist/postgres-CKf-EDtS.mjs.map +1 -0
  65. package/dist/{reranker-D7bRAHi6.mjs → reranker-CMNZcfVx.mjs} +1 -1
  66. package/dist/{reranker-D7bRAHi6.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
  67. package/dist/{search-_oHfguA5.mjs → search-DC1qhkKn.mjs} +2 -58
  68. package/dist/search-DC1qhkKn.mjs.map +1 -0
  69. package/dist/{sqlite-WWBq7_2C.mjs → sqlite-l-s9xPjY.mjs} +160 -3
  70. package/dist/sqlite-l-s9xPjY.mjs.map +1 -0
  71. package/dist/state-C6_vqz7w.mjs +102 -0
  72. package/dist/state-C6_vqz7w.mjs.map +1 -0
  73. package/dist/stop-words-BaMEGVeY.mjs +326 -0
  74. package/dist/stop-words-BaMEGVeY.mjs.map +1 -0
  75. package/dist/{indexer-CMPOiY1r.mjs → sync-BOsnEj2-.mjs} +14 -216
  76. package/dist/sync-BOsnEj2-.mjs.map +1 -0
  77. package/dist/themes-BvYF0W8T.mjs +148 -0
  78. package/dist/themes-BvYF0W8T.mjs.map +1 -0
  79. package/dist/{tools-DV_lsiCc.mjs → tools-DcaJlYDN.mjs} +162 -273
  80. package/dist/tools-DcaJlYDN.mjs.map +1 -0
  81. package/dist/trace-CRx9lPuc.mjs +137 -0
  82. package/dist/trace-CRx9lPuc.mjs.map +1 -0
  83. package/dist/{vault-indexer-k-kUlaZ-.mjs → vault-indexer-Bi2cRmn7.mjs} +134 -132
  84. package/dist/vault-indexer-Bi2cRmn7.mjs.map +1 -0
  85. package/dist/zettelkasten-cdajbnPr.mjs +708 -0
  86. package/dist/zettelkasten-cdajbnPr.mjs.map +1 -0
  87. package/package.json +1 -2
  88. package/src/hooks/ts/lib/project-utils/index.ts +50 -0
  89. package/src/hooks/ts/lib/project-utils/notify.ts +75 -0
  90. package/src/hooks/ts/lib/project-utils/paths.ts +218 -0
  91. package/src/hooks/ts/lib/project-utils/session-notes.ts +363 -0
  92. package/src/hooks/ts/lib/project-utils/todo.ts +178 -0
  93. package/src/hooks/ts/lib/project-utils/tokens.ts +39 -0
  94. package/src/hooks/ts/lib/project-utils.ts +40 -1018
  95. package/src/hooks/ts/post-tool-use/observe.ts +327 -0
  96. package/src/hooks/ts/session-end/capture-session-summary.ts +41 -0
  97. package/src/hooks/ts/session-start/inject-observations.ts +254 -0
  98. package/dist/chunker-CbnBe0s0.mjs +0 -191
  99. package/dist/chunker-CbnBe0s0.mjs.map +0 -1
  100. package/dist/config-Cf92lGX_.mjs.map +0 -1
  101. package/dist/daemon-2ND5WO2j.mjs.map +0 -1
  102. package/dist/db-Dp8VXIMR.mjs +0 -212
  103. package/dist/db-Dp8VXIMR.mjs.map +0 -1
  104. package/dist/indexer-CMPOiY1r.mjs.map +0 -1
  105. package/dist/indexer-backend-CIMXedqk.mjs.map +0 -1
  106. package/dist/mcp/index.d.mts +0 -1
  107. package/dist/mcp/index.mjs +0 -500
  108. package/dist/mcp/index.mjs.map +0 -1
  109. package/dist/postgres-FXrHDPcE.mjs +0 -358
  110. package/dist/postgres-FXrHDPcE.mjs.map +0 -1
  111. package/dist/schemas-BFIgGntb.mjs +0 -3405
  112. package/dist/schemas-BFIgGntb.mjs.map +0 -1
  113. package/dist/search-_oHfguA5.mjs.map +0 -1
  114. package/dist/sqlite-WWBq7_2C.mjs.map +0 -1
  115. package/dist/tools-DV_lsiCc.mjs.map +0 -1
  116. package/dist/vault-indexer-k-kUlaZ-.mjs.map +0 -1
  117. package/dist/zettelkasten-e-a4rW_6.mjs +0 -901
  118. package/dist/zettelkasten-e-a4rW_6.mjs.map +0 -1
  119. package/templates/README.md +0 -181
  120. package/templates/skills/CORE/Aesthetic.md +0 -333
  121. package/templates/skills/CORE/CONSTITUTION.md +0 -1502
  122. package/templates/skills/CORE/HistorySystem.md +0 -427
  123. package/templates/skills/CORE/HookSystem.md +0 -1082
  124. package/templates/skills/CORE/Prompting.md +0 -509
  125. package/templates/skills/CORE/ProsodyAgentTemplate.md +0 -53
  126. package/templates/skills/CORE/ProsodyGuide.md +0 -416
  127. package/templates/skills/CORE/SKILL.md +0 -741
  128. package/templates/skills/CORE/SkillSystem.md +0 -213
  129. package/templates/skills/CORE/TerminalTabs.md +0 -119
  130. package/templates/skills/CORE/VOICE.md +0 -106
  131. package/templates/skills/createskill-skill.template.md +0 -78
  132. package/templates/skills/history-system.template.md +0 -371
  133. package/templates/skills/hook-system.template.md +0 -913
  134. package/templates/skills/sessions-skill.template.md +0 -102
  135. package/templates/skills/skill-system.template.md +0 -214
  136. package/templates/skills/terminal-tabs.template.md +0 -120
  137. package/templates/templates.md +0 -20
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/hooks/ts/pre-compact/context-compression-hook.ts
4
- import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
5
- import { basename as basename2, dirname, join as join3 } from "path";
4
+ import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
5
+ import { basename as basename3, dirname, join as join6 } from "path";
6
6
  import { tmpdir } from "os";
7
7
 
8
- // src/hooks/ts/lib/project-utils.ts
9
- import { existsSync as existsSync2, mkdirSync, readdirSync, readFileSync as readFileSync2, writeFileSync, renameSync } from "fs";
8
+ // src/hooks/ts/lib/project-utils/paths.ts
9
+ import { existsSync as existsSync2, mkdirSync, readdirSync, renameSync } from "fs";
10
10
  import { join as join2, basename } from "path";
11
- import { homedir as homedir2 } from "os";
12
11
 
13
12
  // src/hooks/ts/lib/pai-paths.ts
14
13
  import { homedir } from "os";
@@ -68,7 +67,8 @@ function validatePAIStructure() {
68
67
  }
69
68
  validatePAIStructure();
70
69
 
71
- // src/hooks/ts/lib/project-utils.ts
70
+ // src/hooks/ts/lib/project-utils/paths.ts
71
+ var PROJECTS_DIR = join2(PAI_DIR, "projects");
72
72
  var PROBE_CWD_PATTERNS = [
73
73
  "/CodexBar/ClaudeProbe",
74
74
  "/ClaudeProbe"
@@ -77,7 +77,6 @@ function isProbeSession(cwd) {
77
77
  const dir = cwd || process.cwd();
78
78
  return PROBE_CWD_PATTERNS.some((pattern) => dir.includes(pattern));
79
79
  }
80
- var PROJECTS_DIR = join2(PAI_DIR, "projects");
81
80
  function encodePath(path) {
82
81
  return path.replace(/\//g, "-").replace(/\./g, "-").replace(/ /g, "-");
83
82
  }
@@ -105,10 +104,27 @@ function findNotesDir(cwd) {
105
104
  }
106
105
  return { path: getNotesDir(cwd), isLocal: false };
107
106
  }
107
+ function findTodoPath(cwd) {
108
+ const localPaths = [
109
+ join2(cwd, "TODO.md"),
110
+ join2(cwd, "notes", "TODO.md"),
111
+ join2(cwd, "Notes", "TODO.md"),
112
+ join2(cwd, ".claude", "TODO.md")
113
+ ];
114
+ for (const path of localPaths) {
115
+ if (existsSync2(path)) return path;
116
+ }
117
+ return join2(getNotesDir(cwd), "TODO.md");
118
+ }
119
+
120
+ // src/hooks/ts/lib/project-utils/notify.ts
121
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
122
+ import { join as join3 } from "path";
123
+ import { homedir as homedir2 } from "os";
108
124
  function isWhatsAppEnabled() {
109
125
  try {
110
- const settingsPath = join2(homedir2(), ".claude", "settings.json");
111
- if (!existsSync2(settingsPath)) return false;
126
+ const settingsPath = join3(homedir2(), ".claude", "settings.json");
127
+ if (!existsSync3(settingsPath)) return false;
112
128
  const settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
113
129
  const enabled = settings.enabledMcpjsonServers || [];
114
130
  return enabled.includes("aibroker") || enabled.includes("whazaa") || enabled.includes("telex");
@@ -152,22 +168,24 @@ async function sendNtfyNotification(message, retries = 2) {
152
168
  console.error("ntfy.sh notification failed after all retries");
153
169
  return false;
154
170
  }
171
+
172
+ // src/hooks/ts/lib/project-utils/session-notes.ts
173
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync3, writeFileSync, renameSync as renameSync2 } from "fs";
174
+ import { join as join4, basename as basename2 } from "path";
155
175
  function getMonthDir(notesDir) {
156
176
  const now = /* @__PURE__ */ new Date();
157
177
  const year = String(now.getFullYear());
158
178
  const month = String(now.getMonth() + 1).padStart(2, "0");
159
- const monthDir = join2(notesDir, year, month);
160
- if (!existsSync2(monthDir)) {
161
- mkdirSync(monthDir, { recursive: true });
179
+ const monthDir = join4(notesDir, year, month);
180
+ if (!existsSync4(monthDir)) {
181
+ mkdirSync2(monthDir, { recursive: true });
162
182
  }
163
183
  return monthDir;
164
184
  }
165
185
  function getNextNoteNumber(notesDir) {
166
186
  const monthDir = getMonthDir(notesDir);
167
- const files = readdirSync(monthDir).filter((f) => f.match(/^\d{3,4}[\s_-]/)).filter((f) => f.endsWith(".md")).sort();
168
- if (files.length === 0) {
169
- return "0001";
170
- }
187
+ const files = readdirSync2(monthDir).filter((f) => f.match(/^\d{3,4}[\s_-]/)).filter((f) => f.endsWith(".md")).sort();
188
+ if (files.length === 0) return "0001";
171
189
  let maxNumber = 0;
172
190
  for (const file of files) {
173
191
  const digitMatch = file.match(/^(\d+)/);
@@ -179,29 +197,27 @@ function getNextNoteNumber(notesDir) {
179
197
  return String(maxNumber + 1).padStart(4, "0");
180
198
  }
181
199
  function getCurrentNotePath(notesDir) {
182
- if (!existsSync2(notesDir)) {
183
- return null;
184
- }
200
+ if (!existsSync4(notesDir)) return null;
185
201
  const findLatestIn = (dir) => {
186
- if (!existsSync2(dir)) return null;
187
- const files = readdirSync(dir).filter((f) => f.match(/^\d{3,4}[\s_-].*\.md$/)).sort((a, b) => {
202
+ if (!existsSync4(dir)) return null;
203
+ const files = readdirSync2(dir).filter((f) => f.match(/^\d{3,4}[\s_-].*\.md$/)).sort((a, b) => {
188
204
  const numA = parseInt(a.match(/^(\d+)/)?.[1] || "0", 10);
189
205
  const numB = parseInt(b.match(/^(\d+)/)?.[1] || "0", 10);
190
206
  return numA - numB;
191
207
  });
192
208
  if (files.length === 0) return null;
193
- return join2(dir, files[files.length - 1]);
209
+ return join4(dir, files[files.length - 1]);
194
210
  };
195
211
  const now = /* @__PURE__ */ new Date();
196
212
  const year = String(now.getFullYear());
197
213
  const month = String(now.getMonth() + 1).padStart(2, "0");
198
- const currentMonthDir = join2(notesDir, year, month);
214
+ const currentMonthDir = join4(notesDir, year, month);
199
215
  const found = findLatestIn(currentMonthDir);
200
216
  if (found) return found;
201
217
  const prevDate = new Date(now.getFullYear(), now.getMonth() - 1, 1);
202
218
  const prevYear = String(prevDate.getFullYear());
203
219
  const prevMonth = String(prevDate.getMonth() + 1).padStart(2, "0");
204
- const prevMonthDir = join2(notesDir, prevYear, prevMonth);
220
+ const prevMonthDir = join4(notesDir, prevYear, prevMonth);
205
221
  const prevFound = findLatestIn(prevMonthDir);
206
222
  if (prevFound) return prevFound;
207
223
  return findLatestIn(notesDir);
@@ -209,10 +225,9 @@ function getCurrentNotePath(notesDir) {
209
225
  function createSessionNote(notesDir, description) {
210
226
  const noteNumber = getNextNoteNumber(notesDir);
211
227
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
212
- const safeDescription = "New Session";
213
228
  const monthDir = getMonthDir(notesDir);
214
- const filename = `${noteNumber} - ${date} - ${safeDescription}.md`;
215
- const filepath = join2(monthDir, filename);
229
+ const filename = `${noteNumber} - ${date} - New Session.md`;
230
+ const filepath = join4(monthDir, filename);
216
231
  const content = `# Session ${noteNumber}: ${description}
217
232
 
218
233
  **Date:** ${date}
@@ -239,14 +254,12 @@ function createSessionNote(notesDir, description) {
239
254
  return filepath;
240
255
  }
241
256
  function appendCheckpoint(notePath, checkpoint) {
242
- if (!existsSync2(notePath)) {
257
+ if (!existsSync4(notePath)) {
243
258
  console.error(`Note file not found, recreating: ${notePath}`);
244
259
  try {
245
- const parentDir = join2(notePath, "..");
246
- if (!existsSync2(parentDir)) {
247
- mkdirSync(parentDir, { recursive: true });
248
- }
249
- const noteFilename = basename(notePath);
260
+ const parentDir = join4(notePath, "..");
261
+ if (!existsSync4(parentDir)) mkdirSync2(parentDir, { recursive: true });
262
+ const noteFilename = basename2(notePath);
250
263
  const numberMatch = noteFilename.match(/^(\d+)/);
251
264
  const noteNumber = numberMatch ? numberMatch[1] : "0000";
252
265
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
@@ -278,7 +291,7 @@ function appendCheckpoint(notePath, checkpoint) {
278
291
  return;
279
292
  }
280
293
  }
281
- const content = readFileSync2(notePath, "utf-8");
294
+ const content = readFileSync3(notePath, "utf-8");
282
295
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
283
296
  const checkpointText = `
284
297
  ### Checkpoint ${timestamp}
@@ -286,28 +299,21 @@ function appendCheckpoint(notePath, checkpoint) {
286
299
  ${checkpoint}
287
300
  `;
288
301
  const nextStepsIndex = content.indexOf("## Next Steps");
289
- let newContent;
290
- if (nextStepsIndex !== -1) {
291
- newContent = content.substring(0, nextStepsIndex) + checkpointText + content.substring(nextStepsIndex);
292
- } else {
293
- newContent = content + checkpointText;
294
- }
302
+ const newContent = nextStepsIndex !== -1 ? content.substring(0, nextStepsIndex) + checkpointText + content.substring(nextStepsIndex) : content + checkpointText;
295
303
  writeFileSync(notePath, newContent);
296
- console.error(`Checkpoint added to: ${basename(notePath)}`);
304
+ console.error(`Checkpoint added to: ${basename2(notePath)}`);
297
305
  }
298
306
  function addWorkToSessionNote(notePath, workItems, sectionTitle) {
299
- if (!existsSync2(notePath)) {
307
+ if (!existsSync4(notePath)) {
300
308
  console.error(`Note file not found: ${notePath}`);
301
309
  return;
302
310
  }
303
- let content = readFileSync2(notePath, "utf-8");
311
+ let content = readFileSync3(notePath, "utf-8");
304
312
  let workText = "";
305
- if (sectionTitle) {
306
- workText += `
313
+ if (sectionTitle) workText += `
307
314
  ### ${sectionTitle}
308
315
 
309
316
  `;
310
- }
311
317
  for (const item of workItems) {
312
318
  const checkbox = item.completed !== false ? "[x]" : "[ ]";
313
319
  workText += `- ${checkbox} **${item.title}**
@@ -330,30 +336,24 @@ function addWorkToSessionNote(notePath, workItems, sectionTitle) {
330
336
  }
331
337
  }
332
338
  writeFileSync(notePath, content);
333
- console.error(`Added ${workItems.length} work item(s) to: ${basename(notePath)}`);
339
+ console.error(`Added ${workItems.length} work item(s) to: ${basename2(notePath)}`);
334
340
  }
335
341
  function renameSessionNote(notePath, meaningfulName) {
336
- if (!meaningfulName || !existsSync2(notePath)) {
337
- return notePath;
338
- }
339
- const dir = join2(notePath, "..");
340
- const oldFilename = basename(notePath);
342
+ if (!meaningfulName || !existsSync4(notePath)) return notePath;
343
+ const dir = join4(notePath, "..");
344
+ const oldFilename = basename2(notePath);
341
345
  const correctMatch = oldFilename.match(/^(\d{3,4}) - (\d{4}-\d{2}-\d{2}) - .*\.md$/);
342
346
  const legacyMatch = oldFilename.match(/^(\d{3,4})_(\d{4}-\d{2}-\d{2})_.*\.md$/);
343
347
  const match = correctMatch || legacyMatch;
344
- if (!match) {
345
- return notePath;
346
- }
348
+ if (!match) return notePath;
347
349
  const [, noteNumber, date] = match;
348
350
  const titleCaseName = meaningfulName.split(/[\s_-]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ").trim();
349
351
  const paddedNumber = noteNumber.padStart(4, "0");
350
352
  const newFilename = `${paddedNumber} - ${date} - ${titleCaseName}.md`;
351
- const newPath = join2(dir, newFilename);
352
- if (newFilename === oldFilename) {
353
- return notePath;
354
- }
353
+ const newPath = join4(dir, newFilename);
354
+ if (newFilename === oldFilename) return notePath;
355
355
  try {
356
- renameSync(notePath, newPath);
356
+ renameSync2(notePath, newPath);
357
357
  console.error(`Renamed note: ${oldFilename} \u2192 ${newFilename}`);
358
358
  return newPath;
359
359
  } catch (error) {
@@ -361,12 +361,13 @@ function renameSessionNote(notePath, meaningfulName) {
361
361
  return notePath;
362
362
  }
363
363
  }
364
+
365
+ // src/hooks/ts/lib/project-utils/tokens.ts
366
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
364
367
  function calculateSessionTokens(jsonlPath) {
365
- if (!existsSync2(jsonlPath)) {
366
- return 0;
367
- }
368
+ if (!existsSync5(jsonlPath)) return 0;
368
369
  try {
369
- const content = readFileSync2(jsonlPath, "utf-8");
370
+ const content = readFileSync4(jsonlPath, "utf-8");
370
371
  const lines = content.trim().split("\n");
371
372
  let totalTokens = 0;
372
373
  for (const line of lines) {
@@ -388,27 +389,15 @@ function calculateSessionTokens(jsonlPath) {
388
389
  return 0;
389
390
  }
390
391
  }
391
- function findTodoPath(cwd) {
392
- const localPaths = [
393
- join2(cwd, "TODO.md"),
394
- join2(cwd, "notes", "TODO.md"),
395
- join2(cwd, "Notes", "TODO.md"),
396
- join2(cwd, ".claude", "TODO.md")
397
- ];
398
- for (const path of localPaths) {
399
- if (existsSync2(path)) {
400
- return path;
401
- }
402
- }
403
- return join2(getNotesDir(cwd), "TODO.md");
404
- }
392
+
393
+ // src/hooks/ts/lib/project-utils/todo.ts
394
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
395
+ import { join as join5 } from "path";
405
396
  function ensureTodoMd(cwd) {
406
397
  const todoPath = findTodoPath(cwd);
407
- if (!existsSync2(todoPath)) {
408
- const parentDir = join2(todoPath, "..");
409
- if (!existsSync2(parentDir)) {
410
- mkdirSync(parentDir, { recursive: true });
411
- }
398
+ if (!existsSync6(todoPath)) {
399
+ const parentDir = join5(todoPath, "..");
400
+ if (!existsSync6(parentDir)) mkdirSync3(parentDir, { recursive: true });
412
401
  const content = `# TODO
413
402
 
414
403
  ## Current Session
@@ -423,14 +412,14 @@ function ensureTodoMd(cwd) {
423
412
 
424
413
  *Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}*
425
414
  `;
426
- writeFileSync(todoPath, content);
415
+ writeFileSync2(todoPath, content);
427
416
  console.error(`Created TODO.md: ${todoPath}`);
428
417
  }
429
418
  return todoPath;
430
419
  }
431
420
  function updateTodoContinue(cwd, noteFilename, state, tokenDisplay) {
432
421
  const todoPath = ensureTodoMd(cwd);
433
- let content = readFileSync2(todoPath, "utf-8");
422
+ let content = readFileSync5(todoPath, "utf-8");
434
423
  content = content.replace(/## Continue\n[\s\S]*?\n---\n+/, "");
435
424
  const now = (/* @__PURE__ */ new Date()).toISOString();
436
425
  const stateLines = state ? state.split("\n").filter((l) => l.trim()).slice(0, 10).map((l) => `> ${l}`).join("\n") : `> Working directory: ${cwd}. Check the latest session note for details.`;
@@ -458,7 +447,7 @@ ${stateLines}
458
447
 
459
448
  *Last updated: ${now}*
460
449
  `;
461
- writeFileSync(todoPath, content);
450
+ writeFileSync2(todoPath, content);
462
451
  console.error("TODO.md ## Continue section updated");
463
452
  }
464
453
 
@@ -477,7 +466,7 @@ function contentToText(content) {
477
466
  }
478
467
  function getTranscriptStats(transcriptPath) {
479
468
  try {
480
- const content = readFileSync3(transcriptPath, "utf-8");
469
+ const content = readFileSync6(transcriptPath, "utf-8");
481
470
  const lines = content.trim().split("\n");
482
471
  let userMessages = 0;
483
472
  let assistantMessages = 0;
@@ -506,7 +495,7 @@ function parseTranscript(transcriptPath) {
506
495
  workItems: []
507
496
  };
508
497
  try {
509
- const raw = readFileSync3(transcriptPath, "utf-8");
498
+ const raw = readFileSync6(transcriptPath, "utf-8");
510
499
  const lines = raw.trim().split("\n");
511
500
  const seenSummaries = /* @__PURE__ */ new Set();
512
501
  for (const line of lines) {
@@ -623,7 +612,7 @@ function deriveTitle(data) {
623
612
  }
624
613
  if (!title && data.filesModified.length > 0) {
625
614
  const basenames = data.filesModified.slice(-5).map((f) => {
626
- const b = basename2(f);
615
+ const b = basename3(f);
627
616
  return b.replace(/\.[^.]+$/, "");
628
617
  });
629
618
  const unique = [...new Set(basenames)];
@@ -634,9 +623,9 @@ function deriveTitle(data) {
634
623
  var CUMULATIVE_STATE_FILE = ".compact-state.json";
635
624
  function loadCumulativeState(notesDir) {
636
625
  try {
637
- const filePath = join3(notesDir, CUMULATIVE_STATE_FILE);
638
- if (!existsSync3(filePath)) return null;
639
- const raw = JSON.parse(readFileSync3(filePath, "utf-8"));
626
+ const filePath = join6(notesDir, CUMULATIVE_STATE_FILE);
627
+ if (!existsSync7(filePath)) return null;
628
+ const raw = JSON.parse(readFileSync6(filePath, "utf-8"));
640
629
  return {
641
630
  userMessages: raw.userMessages || [],
642
631
  summaries: raw.summaries || [],
@@ -668,8 +657,8 @@ function mergeTranscriptData(accumulated, current) {
668
657
  }
669
658
  function saveCumulativeState(notesDir, data, notePath) {
670
659
  try {
671
- const filePath = join3(notesDir, CUMULATIVE_STATE_FILE);
672
- writeFileSync2(filePath, JSON.stringify({
660
+ const filePath = join6(notesDir, CUMULATIVE_STATE_FILE);
661
+ writeFileSync3(filePath, JSON.stringify({
673
662
  ...data,
674
663
  notePath,
675
664
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
@@ -710,9 +699,9 @@ async function main() {
710
699
  const data = parseTranscript(hookInput.transcript_path);
711
700
  let notesInfo;
712
701
  try {
713
- notesInfo = hookInput.cwd ? findNotesDir(hookInput.cwd) : { path: join3(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
702
+ notesInfo = hookInput.cwd ? findNotesDir(hookInput.cwd) : { path: join6(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
714
703
  } catch {
715
- notesInfo = { path: join3(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
704
+ notesInfo = { path: join6(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
716
705
  }
717
706
  const accumulated = loadCumulativeState(notesInfo.path);
718
707
  const merged = mergeTranscriptData(accumulated, data);
@@ -728,9 +717,9 @@ async function main() {
728
717
  notePath = createSessionNote(notesInfo.path, "Recovered Session");
729
718
  } else {
730
719
  try {
731
- const noteContent = readFileSync3(notePath, "utf-8");
720
+ const noteContent = readFileSync6(notePath, "utf-8");
732
721
  if (noteContent.includes("**Status:** Completed") || noteContent.includes("**Completed:**")) {
733
- console.error(`Latest note is completed (${basename2(notePath)}) \u2014 creating new one`);
722
+ console.error(`Latest note is completed (${basename3(notePath)}) \u2014 creating new one`);
734
723
  notePath = createSessionNote(notesInfo.path, "Continued Session");
735
724
  }
736
725
  } catch {
@@ -749,26 +738,26 @@ ${state}` : `Context compression triggered at ~${tokenDisplay} tokens with ${sta
749
738
  const newPath = renameSessionNote(notePath, title);
750
739
  if (newPath !== notePath) {
751
740
  try {
752
- let noteContent = readFileSync3(newPath, "utf-8");
741
+ let noteContent = readFileSync6(newPath, "utf-8");
753
742
  noteContent = noteContent.replace(
754
743
  /^(# Session \d+:)\s*.*$/m,
755
744
  `$1 ${title}`
756
745
  );
757
- writeFileSync2(newPath, noteContent);
746
+ writeFileSync3(newPath, noteContent);
758
747
  console.error(`Updated note H1 to match rename`);
759
748
  } catch {
760
749
  }
761
750
  notePath = newPath;
762
751
  }
763
752
  }
764
- console.error(`Rich checkpoint saved: ${basename2(notePath)}`);
753
+ console.error(`Rich checkpoint saved: ${basename3(notePath)}`);
765
754
  } catch (noteError) {
766
755
  console.error(`Could not save checkpoint: ${noteError}`);
767
756
  }
768
757
  saveCumulativeState(notesInfo.path, merged, notePath);
769
758
  if (hookInput.cwd && notePath) {
770
759
  try {
771
- const noteFilename = basename2(notePath);
760
+ const noteFilename = basename3(notePath);
772
761
  updateTodoContinue(hookInput.cwd, noteFilename, state, tokenDisplay);
773
762
  console.error("TODO.md ## Continue section updated");
774
763
  } catch (todoError) {
@@ -795,8 +784,8 @@ rename it based on actual work done and add a rich summary.` : "";
795
784
  "</system-reminder>"
796
785
  ].join("\n");
797
786
  try {
798
- const stateFile = join3(tmpdir(), `pai-compact-state-${hookInput.session_id}.txt`);
799
- writeFileSync2(stateFile, injection, "utf-8");
787
+ const stateFile = join6(tmpdir(), `pai-compact-state-${hookInput.session_id}.txt`);
788
+ writeFileSync3(stateFile, injection, "utf-8");
800
789
  console.error(`Session state saved to ${stateFile} (${injection.length} chars)`);
801
790
  } catch (err) {
802
791
  console.error(`Failed to save state file: ${err}`);