@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.
- package/ARCHITECTURE.md +72 -1
- package/README.md +87 -1
- package/dist/{auto-route-BG6I_4B1.mjs → auto-route-C-DrW6BL.mjs} +3 -3
- package/dist/{auto-route-BG6I_4B1.mjs.map → auto-route-C-DrW6BL.mjs.map} +1 -1
- package/dist/cli/index.mjs +1482 -1628
- package/dist/cli/index.mjs.map +1 -1
- package/dist/clusters-JIDQW65f.mjs +201 -0
- package/dist/clusters-JIDQW65f.mjs.map +1 -0
- package/dist/{config-Cf92lGX_.mjs → config-BuhHWyOK.mjs} +21 -6
- package/dist/config-BuhHWyOK.mjs.map +1 -0
- package/dist/daemon/index.mjs +11 -8
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/{daemon-2ND5WO2j.mjs → daemon-D3hYb5_C.mjs} +669 -218
- package/dist/daemon-D3hYb5_C.mjs.map +1 -0
- package/dist/daemon-mcp/index.mjs +4597 -4
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/db-DdUperSl.mjs +110 -0
- package/dist/db-DdUperSl.mjs.map +1 -0
- package/dist/{detect-BU3Nx_2L.mjs → detect-CdaA48EI.mjs} +1 -1
- package/dist/{detect-BU3Nx_2L.mjs.map → detect-CdaA48EI.mjs.map} +1 -1
- package/dist/{detector-Bp-2SM3x.mjs → detector-jGBuYQJM.mjs} +2 -2
- package/dist/{detector-Bp-2SM3x.mjs.map → detector-jGBuYQJM.mjs.map} +1 -1
- package/dist/{factory-Bzcy70G9.mjs → factory-Ygqe_bVZ.mjs} +7 -5
- package/dist/{factory-Bzcy70G9.mjs.map → factory-Ygqe_bVZ.mjs.map} +1 -1
- package/dist/helpers-BEST-4Gx.mjs +420 -0
- package/dist/helpers-BEST-4Gx.mjs.map +1 -0
- package/dist/hooks/capture-all-events.mjs +2 -2
- package/dist/hooks/capture-all-events.mjs.map +3 -3
- package/dist/hooks/capture-session-summary.mjs +38 -0
- package/dist/hooks/capture-session-summary.mjs.map +3 -3
- package/dist/hooks/cleanup-session-files.mjs +6 -12
- package/dist/hooks/cleanup-session-files.mjs.map +4 -4
- package/dist/hooks/context-compression-hook.mjs +93 -104
- package/dist/hooks/context-compression-hook.mjs.map +4 -4
- package/dist/hooks/initialize-session.mjs +14 -11
- package/dist/hooks/initialize-session.mjs.map +4 -4
- package/dist/hooks/inject-observations.mjs +220 -0
- package/dist/hooks/inject-observations.mjs.map +7 -0
- package/dist/hooks/load-core-context.mjs +2 -2
- package/dist/hooks/load-core-context.mjs.map +3 -3
- package/dist/hooks/load-project-context.mjs +90 -91
- package/dist/hooks/load-project-context.mjs.map +4 -4
- package/dist/hooks/observe.mjs +354 -0
- package/dist/hooks/observe.mjs.map +7 -0
- package/dist/hooks/stop-hook.mjs +94 -107
- package/dist/hooks/stop-hook.mjs.map +4 -4
- package/dist/hooks/sync-todo-to-md.mjs +31 -33
- package/dist/hooks/sync-todo-to-md.mjs.map +4 -4
- package/dist/index.d.mts +30 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -8
- package/dist/indexer-D53l5d1U.mjs +1 -0
- package/dist/{indexer-backend-CIMXedqk.mjs → indexer-backend-jcJFsmB4.mjs} +37 -127
- package/dist/indexer-backend-jcJFsmB4.mjs.map +1 -0
- package/dist/{ipc-client-Bjg_a1dc.mjs → ipc-client-CoyUHPod.mjs} +2 -7
- package/dist/{ipc-client-Bjg_a1dc.mjs.map → ipc-client-CoyUHPod.mjs.map} +1 -1
- package/dist/latent-ideas-bTJo6Omd.mjs +191 -0
- package/dist/latent-ideas-bTJo6Omd.mjs.map +1 -0
- package/dist/neighborhood-BYYbEkUJ.mjs +135 -0
- package/dist/neighborhood-BYYbEkUJ.mjs.map +1 -0
- package/dist/note-context-BK24bX8Y.mjs +126 -0
- package/dist/note-context-BK24bX8Y.mjs.map +1 -0
- package/dist/postgres-CKf-EDtS.mjs +846 -0
- package/dist/postgres-CKf-EDtS.mjs.map +1 -0
- package/dist/{reranker-D7bRAHi6.mjs → reranker-CMNZcfVx.mjs} +1 -1
- package/dist/{reranker-D7bRAHi6.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
- package/dist/{search-_oHfguA5.mjs → search-DC1qhkKn.mjs} +2 -58
- package/dist/search-DC1qhkKn.mjs.map +1 -0
- package/dist/{sqlite-WWBq7_2C.mjs → sqlite-l-s9xPjY.mjs} +160 -3
- package/dist/sqlite-l-s9xPjY.mjs.map +1 -0
- package/dist/state-C6_vqz7w.mjs +102 -0
- package/dist/state-C6_vqz7w.mjs.map +1 -0
- package/dist/stop-words-BaMEGVeY.mjs +326 -0
- package/dist/stop-words-BaMEGVeY.mjs.map +1 -0
- package/dist/{indexer-CMPOiY1r.mjs → sync-BOsnEj2-.mjs} +14 -216
- package/dist/sync-BOsnEj2-.mjs.map +1 -0
- package/dist/themes-BvYF0W8T.mjs +148 -0
- package/dist/themes-BvYF0W8T.mjs.map +1 -0
- package/dist/{tools-DV_lsiCc.mjs → tools-DcaJlYDN.mjs} +162 -273
- package/dist/tools-DcaJlYDN.mjs.map +1 -0
- package/dist/trace-CRx9lPuc.mjs +137 -0
- package/dist/trace-CRx9lPuc.mjs.map +1 -0
- package/dist/{vault-indexer-k-kUlaZ-.mjs → vault-indexer-Bi2cRmn7.mjs} +134 -132
- package/dist/vault-indexer-Bi2cRmn7.mjs.map +1 -0
- package/dist/zettelkasten-cdajbnPr.mjs +708 -0
- package/dist/zettelkasten-cdajbnPr.mjs.map +1 -0
- package/package.json +1 -2
- package/src/hooks/ts/lib/project-utils/index.ts +50 -0
- package/src/hooks/ts/lib/project-utils/notify.ts +75 -0
- package/src/hooks/ts/lib/project-utils/paths.ts +218 -0
- package/src/hooks/ts/lib/project-utils/session-notes.ts +363 -0
- package/src/hooks/ts/lib/project-utils/todo.ts +178 -0
- package/src/hooks/ts/lib/project-utils/tokens.ts +39 -0
- package/src/hooks/ts/lib/project-utils.ts +40 -1018
- package/src/hooks/ts/post-tool-use/observe.ts +327 -0
- package/src/hooks/ts/session-end/capture-session-summary.ts +41 -0
- package/src/hooks/ts/session-start/inject-observations.ts +254 -0
- package/dist/chunker-CbnBe0s0.mjs +0 -191
- package/dist/chunker-CbnBe0s0.mjs.map +0 -1
- package/dist/config-Cf92lGX_.mjs.map +0 -1
- package/dist/daemon-2ND5WO2j.mjs.map +0 -1
- package/dist/db-Dp8VXIMR.mjs +0 -212
- package/dist/db-Dp8VXIMR.mjs.map +0 -1
- package/dist/indexer-CMPOiY1r.mjs.map +0 -1
- package/dist/indexer-backend-CIMXedqk.mjs.map +0 -1
- package/dist/mcp/index.d.mts +0 -1
- package/dist/mcp/index.mjs +0 -500
- package/dist/mcp/index.mjs.map +0 -1
- package/dist/postgres-FXrHDPcE.mjs +0 -358
- package/dist/postgres-FXrHDPcE.mjs.map +0 -1
- package/dist/schemas-BFIgGntb.mjs +0 -3405
- package/dist/schemas-BFIgGntb.mjs.map +0 -1
- package/dist/search-_oHfguA5.mjs.map +0 -1
- package/dist/sqlite-WWBq7_2C.mjs.map +0 -1
- package/dist/tools-DV_lsiCc.mjs.map +0 -1
- package/dist/vault-indexer-k-kUlaZ-.mjs.map +0 -1
- package/dist/zettelkasten-e-a4rW_6.mjs +0 -901
- package/dist/zettelkasten-e-a4rW_6.mjs.map +0 -1
- package/templates/README.md +0 -181
- package/templates/skills/CORE/Aesthetic.md +0 -333
- package/templates/skills/CORE/CONSTITUTION.md +0 -1502
- package/templates/skills/CORE/HistorySystem.md +0 -427
- package/templates/skills/CORE/HookSystem.md +0 -1082
- package/templates/skills/CORE/Prompting.md +0 -509
- package/templates/skills/CORE/ProsodyAgentTemplate.md +0 -53
- package/templates/skills/CORE/ProsodyGuide.md +0 -416
- package/templates/skills/CORE/SKILL.md +0 -741
- package/templates/skills/CORE/SkillSystem.md +0 -213
- package/templates/skills/CORE/TerminalTabs.md +0 -119
- package/templates/skills/CORE/VOICE.md +0 -106
- package/templates/skills/createskill-skill.template.md +0 -78
- package/templates/skills/history-system.template.md +0 -371
- package/templates/skills/hook-system.template.md +0 -913
- package/templates/skills/sessions-skill.template.md +0 -102
- package/templates/skills/skill-system.template.md +0 -214
- package/templates/skills/terminal-tabs.template.md +0 -120
- package/templates/templates.md +0 -20
package/dist/hooks/stop-hook.mjs
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/hooks/ts/stop/stop-hook.ts
|
|
4
|
-
import { readFileSync as
|
|
5
|
-
import { basename as
|
|
4
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
5
|
+
import { basename as basename3, dirname } from "path";
|
|
6
6
|
|
|
7
|
-
// src/hooks/ts/lib/project-utils.ts
|
|
8
|
-
import { existsSync as existsSync2, mkdirSync, readdirSync,
|
|
7
|
+
// src/hooks/ts/lib/project-utils/paths.ts
|
|
8
|
+
import { existsSync as existsSync2, mkdirSync, readdirSync, renameSync } from "fs";
|
|
9
9
|
import { join as join2, basename } from "path";
|
|
10
|
-
import { homedir as homedir2 } from "os";
|
|
11
10
|
|
|
12
11
|
// src/hooks/ts/lib/pai-paths.ts
|
|
13
12
|
import { homedir } from "os";
|
|
@@ -67,7 +66,8 @@ function validatePAIStructure() {
|
|
|
67
66
|
}
|
|
68
67
|
validatePAIStructure();
|
|
69
68
|
|
|
70
|
-
// src/hooks/ts/lib/project-utils.ts
|
|
69
|
+
// src/hooks/ts/lib/project-utils/paths.ts
|
|
70
|
+
var PROJECTS_DIR = join2(PAI_DIR, "projects");
|
|
71
71
|
var PROBE_CWD_PATTERNS = [
|
|
72
72
|
"/CodexBar/ClaudeProbe",
|
|
73
73
|
"/ClaudeProbe"
|
|
@@ -76,7 +76,6 @@ function isProbeSession(cwd) {
|
|
|
76
76
|
const dir = cwd || process.cwd();
|
|
77
77
|
return PROBE_CWD_PATTERNS.some((pattern) => dir.includes(pattern));
|
|
78
78
|
}
|
|
79
|
-
var PROJECTS_DIR = join2(PAI_DIR, "projects");
|
|
80
79
|
function encodePath(path) {
|
|
81
80
|
return path.replace(/\//g, "-").replace(/\./g, "-").replace(/ /g, "-");
|
|
82
81
|
}
|
|
@@ -107,10 +106,55 @@ function findNotesDir(cwd) {
|
|
|
107
106
|
function getSessionsDirFromProjectDir(projectDir) {
|
|
108
107
|
return join2(projectDir, "sessions");
|
|
109
108
|
}
|
|
109
|
+
function ensureSessionsDirFromProjectDir(projectDir) {
|
|
110
|
+
const sessionsDir = getSessionsDirFromProjectDir(projectDir);
|
|
111
|
+
if (!existsSync2(sessionsDir)) {
|
|
112
|
+
mkdirSync(sessionsDir, { recursive: true });
|
|
113
|
+
console.error(`Created sessions directory: ${sessionsDir}`);
|
|
114
|
+
}
|
|
115
|
+
return sessionsDir;
|
|
116
|
+
}
|
|
117
|
+
function moveSessionFilesToSessionsDir(projectDir, excludeFile, silent = false) {
|
|
118
|
+
const sessionsDir = ensureSessionsDirFromProjectDir(projectDir);
|
|
119
|
+
if (!existsSync2(projectDir)) return 0;
|
|
120
|
+
const files = readdirSync(projectDir);
|
|
121
|
+
let movedCount = 0;
|
|
122
|
+
for (const file of files) {
|
|
123
|
+
if (file.endsWith(".jsonl") && file !== excludeFile) {
|
|
124
|
+
const sourcePath = join2(projectDir, file);
|
|
125
|
+
const destPath = join2(sessionsDir, file);
|
|
126
|
+
try {
|
|
127
|
+
renameSync(sourcePath, destPath);
|
|
128
|
+
if (!silent) console.error(`Moved ${file} \u2192 sessions/`);
|
|
129
|
+
movedCount++;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (!silent) console.error(`Could not move ${file}: ${error}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return movedCount;
|
|
136
|
+
}
|
|
137
|
+
function findTodoPath(cwd) {
|
|
138
|
+
const localPaths = [
|
|
139
|
+
join2(cwd, "TODO.md"),
|
|
140
|
+
join2(cwd, "notes", "TODO.md"),
|
|
141
|
+
join2(cwd, "Notes", "TODO.md"),
|
|
142
|
+
join2(cwd, ".claude", "TODO.md")
|
|
143
|
+
];
|
|
144
|
+
for (const path of localPaths) {
|
|
145
|
+
if (existsSync2(path)) return path;
|
|
146
|
+
}
|
|
147
|
+
return join2(getNotesDir(cwd), "TODO.md");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/hooks/ts/lib/project-utils/notify.ts
|
|
151
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
152
|
+
import { join as join3 } from "path";
|
|
153
|
+
import { homedir as homedir2 } from "os";
|
|
110
154
|
function isWhatsAppEnabled() {
|
|
111
155
|
try {
|
|
112
|
-
const settingsPath =
|
|
113
|
-
if (!
|
|
156
|
+
const settingsPath = join3(homedir2(), ".claude", "settings.json");
|
|
157
|
+
if (!existsSync3(settingsPath)) return false;
|
|
114
158
|
const settings = JSON.parse(readFileSync2(settingsPath, "utf-8"));
|
|
115
159
|
const enabled = settings.enabledMcpjsonServers || [];
|
|
116
160
|
return enabled.includes("aibroker") || enabled.includes("whazaa") || enabled.includes("telex");
|
|
@@ -154,81 +198,47 @@ async function sendNtfyNotification(message, retries = 2) {
|
|
|
154
198
|
console.error("ntfy.sh notification failed after all retries");
|
|
155
199
|
return false;
|
|
156
200
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
console.error(`Created sessions directory: ${sessionsDir}`);
|
|
162
|
-
}
|
|
163
|
-
return sessionsDir;
|
|
164
|
-
}
|
|
165
|
-
function moveSessionFilesToSessionsDir(projectDir, excludeFile, silent = false) {
|
|
166
|
-
const sessionsDir = ensureSessionsDirFromProjectDir(projectDir);
|
|
167
|
-
if (!existsSync2(projectDir)) {
|
|
168
|
-
return 0;
|
|
169
|
-
}
|
|
170
|
-
const files = readdirSync(projectDir);
|
|
171
|
-
let movedCount = 0;
|
|
172
|
-
for (const file of files) {
|
|
173
|
-
if (file.endsWith(".jsonl") && file !== excludeFile) {
|
|
174
|
-
const sourcePath = join2(projectDir, file);
|
|
175
|
-
const destPath = join2(sessionsDir, file);
|
|
176
|
-
try {
|
|
177
|
-
renameSync(sourcePath, destPath);
|
|
178
|
-
if (!silent) {
|
|
179
|
-
console.error(`Moved ${file} \u2192 sessions/`);
|
|
180
|
-
}
|
|
181
|
-
movedCount++;
|
|
182
|
-
} catch (error) {
|
|
183
|
-
if (!silent) {
|
|
184
|
-
console.error(`Could not move ${file}: ${error}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return movedCount;
|
|
190
|
-
}
|
|
201
|
+
|
|
202
|
+
// src/hooks/ts/lib/project-utils/session-notes.ts
|
|
203
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync3, writeFileSync, renameSync as renameSync2 } from "fs";
|
|
204
|
+
import { join as join4, basename as basename2 } from "path";
|
|
191
205
|
function getCurrentNotePath(notesDir) {
|
|
192
|
-
if (!
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
206
|
+
if (!existsSync4(notesDir)) return null;
|
|
195
207
|
const findLatestIn = (dir) => {
|
|
196
|
-
if (!
|
|
197
|
-
const files =
|
|
208
|
+
if (!existsSync4(dir)) return null;
|
|
209
|
+
const files = readdirSync2(dir).filter((f) => f.match(/^\d{3,4}[\s_-].*\.md$/)).sort((a, b) => {
|
|
198
210
|
const numA = parseInt(a.match(/^(\d+)/)?.[1] || "0", 10);
|
|
199
211
|
const numB = parseInt(b.match(/^(\d+)/)?.[1] || "0", 10);
|
|
200
212
|
return numA - numB;
|
|
201
213
|
});
|
|
202
214
|
if (files.length === 0) return null;
|
|
203
|
-
return
|
|
215
|
+
return join4(dir, files[files.length - 1]);
|
|
204
216
|
};
|
|
205
217
|
const now = /* @__PURE__ */ new Date();
|
|
206
218
|
const year = String(now.getFullYear());
|
|
207
219
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
208
|
-
const currentMonthDir =
|
|
220
|
+
const currentMonthDir = join4(notesDir, year, month);
|
|
209
221
|
const found = findLatestIn(currentMonthDir);
|
|
210
222
|
if (found) return found;
|
|
211
223
|
const prevDate = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
212
224
|
const prevYear = String(prevDate.getFullYear());
|
|
213
225
|
const prevMonth = String(prevDate.getMonth() + 1).padStart(2, "0");
|
|
214
|
-
const prevMonthDir =
|
|
226
|
+
const prevMonthDir = join4(notesDir, prevYear, prevMonth);
|
|
215
227
|
const prevFound = findLatestIn(prevMonthDir);
|
|
216
228
|
if (prevFound) return prevFound;
|
|
217
229
|
return findLatestIn(notesDir);
|
|
218
230
|
}
|
|
219
231
|
function addWorkToSessionNote(notePath, workItems, sectionTitle) {
|
|
220
|
-
if (!
|
|
232
|
+
if (!existsSync4(notePath)) {
|
|
221
233
|
console.error(`Note file not found: ${notePath}`);
|
|
222
234
|
return;
|
|
223
235
|
}
|
|
224
|
-
let content =
|
|
236
|
+
let content = readFileSync3(notePath, "utf-8");
|
|
225
237
|
let workText = "";
|
|
226
|
-
if (sectionTitle)
|
|
227
|
-
workText += `
|
|
238
|
+
if (sectionTitle) workText += `
|
|
228
239
|
### ${sectionTitle}
|
|
229
240
|
|
|
230
241
|
`;
|
|
231
|
-
}
|
|
232
242
|
for (const item of workItems) {
|
|
233
243
|
const checkbox = item.completed !== false ? "[x]" : "[ ]";
|
|
234
244
|
workText += `- ${checkbox} **${item.title}**
|
|
@@ -251,7 +261,7 @@ function addWorkToSessionNote(notePath, workItems, sectionTitle) {
|
|
|
251
261
|
}
|
|
252
262
|
}
|
|
253
263
|
writeFileSync(notePath, content);
|
|
254
|
-
console.error(`Added ${workItems.length} work item(s) to: ${
|
|
264
|
+
console.error(`Added ${workItems.length} work item(s) to: ${basename2(notePath)}`);
|
|
255
265
|
}
|
|
256
266
|
function sanitizeForFilename(str) {
|
|
257
267
|
return str.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").substring(0, 50);
|
|
@@ -275,40 +285,30 @@ function extractMeaningfulName(noteContent, summary) {
|
|
|
275
285
|
}
|
|
276
286
|
}
|
|
277
287
|
const numberedItems = workDoneSection.match(/^\d+\.\s+\*\*([^*]+)\*\*/m);
|
|
278
|
-
if (numberedItems)
|
|
279
|
-
return sanitizeForFilename(numberedItems[1]);
|
|
280
|
-
}
|
|
288
|
+
if (numberedItems) return sanitizeForFilename(numberedItems[1]);
|
|
281
289
|
}
|
|
282
290
|
if (summary && summary.length > 5 && summary !== "Session completed.") {
|
|
283
291
|
const cleanSummary = summary.replace(/[^\w\s-]/g, " ").trim().split(/\s+/).slice(0, 5).join(" ");
|
|
284
|
-
if (cleanSummary.length > 3)
|
|
285
|
-
return sanitizeForFilename(cleanSummary);
|
|
286
|
-
}
|
|
292
|
+
if (cleanSummary.length > 3) return sanitizeForFilename(cleanSummary);
|
|
287
293
|
}
|
|
288
294
|
return "";
|
|
289
295
|
}
|
|
290
296
|
function renameSessionNote(notePath, meaningfulName) {
|
|
291
|
-
if (!meaningfulName || !
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const dir = join2(notePath, "..");
|
|
295
|
-
const oldFilename = basename(notePath);
|
|
297
|
+
if (!meaningfulName || !existsSync4(notePath)) return notePath;
|
|
298
|
+
const dir = join4(notePath, "..");
|
|
299
|
+
const oldFilename = basename2(notePath);
|
|
296
300
|
const correctMatch = oldFilename.match(/^(\d{3,4}) - (\d{4}-\d{2}-\d{2}) - .*\.md$/);
|
|
297
301
|
const legacyMatch = oldFilename.match(/^(\d{3,4})_(\d{4}-\d{2}-\d{2})_.*\.md$/);
|
|
298
302
|
const match = correctMatch || legacyMatch;
|
|
299
|
-
if (!match)
|
|
300
|
-
return notePath;
|
|
301
|
-
}
|
|
303
|
+
if (!match) return notePath;
|
|
302
304
|
const [, noteNumber, date] = match;
|
|
303
305
|
const titleCaseName = meaningfulName.split(/[\s_-]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ").trim();
|
|
304
306
|
const paddedNumber = noteNumber.padStart(4, "0");
|
|
305
307
|
const newFilename = `${paddedNumber} - ${date} - ${titleCaseName}.md`;
|
|
306
|
-
const newPath =
|
|
307
|
-
if (newFilename === oldFilename)
|
|
308
|
-
return notePath;
|
|
309
|
-
}
|
|
308
|
+
const newPath = join4(dir, newFilename);
|
|
309
|
+
if (newFilename === oldFilename) return notePath;
|
|
310
310
|
try {
|
|
311
|
-
|
|
311
|
+
renameSync2(notePath, newPath);
|
|
312
312
|
console.error(`Renamed note: ${oldFilename} \u2192 ${newFilename}`);
|
|
313
313
|
return newPath;
|
|
314
314
|
} catch (error) {
|
|
@@ -317,13 +317,13 @@ function renameSessionNote(notePath, meaningfulName) {
|
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
function finalizeSessionNote(notePath, summary) {
|
|
320
|
-
if (!
|
|
320
|
+
if (!existsSync4(notePath)) {
|
|
321
321
|
console.error(`Note file not found: ${notePath}`);
|
|
322
322
|
return notePath;
|
|
323
323
|
}
|
|
324
|
-
let content =
|
|
324
|
+
let content = readFileSync3(notePath, "utf-8");
|
|
325
325
|
if (content.includes("**Status:** Completed")) {
|
|
326
|
-
console.error(`Note already finalized: ${
|
|
326
|
+
console.error(`Note already finalized: ${basename2(notePath)}`);
|
|
327
327
|
return notePath;
|
|
328
328
|
}
|
|
329
329
|
content = content.replace("**Status:** In Progress", "**Status:** Completed");
|
|
@@ -348,35 +348,22 @@ ${summary || "Session completed."}`
|
|
|
348
348
|
);
|
|
349
349
|
}
|
|
350
350
|
writeFileSync(notePath, content);
|
|
351
|
-
console.error(`Session note finalized: ${
|
|
351
|
+
console.error(`Session note finalized: ${basename2(notePath)}`);
|
|
352
352
|
const meaningfulName = extractMeaningfulName(content, summary);
|
|
353
353
|
if (meaningfulName) {
|
|
354
|
-
|
|
355
|
-
return newPath;
|
|
354
|
+
return renameSessionNote(notePath, meaningfulName);
|
|
356
355
|
}
|
|
357
356
|
return notePath;
|
|
358
357
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
join2(cwd, "Notes", "TODO.md"),
|
|
364
|
-
join2(cwd, ".claude", "TODO.md")
|
|
365
|
-
];
|
|
366
|
-
for (const path of localPaths) {
|
|
367
|
-
if (existsSync2(path)) {
|
|
368
|
-
return path;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return join2(getNotesDir(cwd), "TODO.md");
|
|
372
|
-
}
|
|
358
|
+
|
|
359
|
+
// src/hooks/ts/lib/project-utils/todo.ts
|
|
360
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
361
|
+
import { join as join5 } from "path";
|
|
373
362
|
function ensureTodoMd(cwd) {
|
|
374
363
|
const todoPath = findTodoPath(cwd);
|
|
375
|
-
if (!
|
|
376
|
-
const parentDir =
|
|
377
|
-
if (!
|
|
378
|
-
mkdirSync(parentDir, { recursive: true });
|
|
379
|
-
}
|
|
364
|
+
if (!existsSync5(todoPath)) {
|
|
365
|
+
const parentDir = join5(todoPath, "..");
|
|
366
|
+
if (!existsSync5(parentDir)) mkdirSync3(parentDir, { recursive: true });
|
|
380
367
|
const content = `# TODO
|
|
381
368
|
|
|
382
369
|
## Current Session
|
|
@@ -391,14 +378,14 @@ function ensureTodoMd(cwd) {
|
|
|
391
378
|
|
|
392
379
|
*Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}*
|
|
393
380
|
`;
|
|
394
|
-
|
|
381
|
+
writeFileSync2(todoPath, content);
|
|
395
382
|
console.error(`Created TODO.md: ${todoPath}`);
|
|
396
383
|
}
|
|
397
384
|
return todoPath;
|
|
398
385
|
}
|
|
399
386
|
function updateTodoContinue(cwd, noteFilename, state, tokenDisplay) {
|
|
400
387
|
const todoPath = ensureTodoMd(cwd);
|
|
401
|
-
let content =
|
|
388
|
+
let content = readFileSync4(todoPath, "utf-8");
|
|
402
389
|
content = content.replace(/## Continue\n[\s\S]*?\n---\n+/, "");
|
|
403
390
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
404
391
|
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.`;
|
|
@@ -426,7 +413,7 @@ ${stateLines}
|
|
|
426
413
|
|
|
427
414
|
*Last updated: ${now}*
|
|
428
415
|
`;
|
|
429
|
-
|
|
416
|
+
writeFileSync2(todoPath, content);
|
|
430
417
|
console.error("TODO.md ## Continue section updated");
|
|
431
418
|
}
|
|
432
419
|
|
|
@@ -578,7 +565,7 @@ STOP-HOOK TRIGGERED AT ${timestamp}`);
|
|
|
578
565
|
}
|
|
579
566
|
let transcript;
|
|
580
567
|
try {
|
|
581
|
-
transcript =
|
|
568
|
+
transcript = readFileSync5(transcriptPath, "utf-8");
|
|
582
569
|
console.error(`Transcript loaded: ${transcript.split("\n").length} lines`);
|
|
583
570
|
} catch (e) {
|
|
584
571
|
console.error(`Error reading transcript: ${e}`);
|
|
@@ -681,7 +668,7 @@ STOP-HOOK TRIGGERED AT ${timestamp}`);
|
|
|
681
668
|
}
|
|
682
669
|
const summary = message || "Session completed.";
|
|
683
670
|
finalizeSessionNote(currentNotePath, summary);
|
|
684
|
-
console.error(`Session note finalized: ${
|
|
671
|
+
console.error(`Session note finalized: ${basename3(currentNotePath)}`);
|
|
685
672
|
try {
|
|
686
673
|
const stateLines = [];
|
|
687
674
|
stateLines.push(`Working directory: ${cwd}`);
|
|
@@ -697,7 +684,7 @@ STOP-HOOK TRIGGERED AT ${timestamp}`);
|
|
|
697
684
|
stateLines.push(`Last completed: ${message}`);
|
|
698
685
|
}
|
|
699
686
|
const state = stateLines.join("\n");
|
|
700
|
-
updateTodoContinue(cwd,
|
|
687
|
+
updateTodoContinue(cwd, basename3(currentNotePath), state, "session-end");
|
|
701
688
|
} catch (todoError) {
|
|
702
689
|
console.error(`Could not update TODO.md: ${todoError}`);
|
|
703
690
|
}
|