@tekmidian/pai 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/dist/auto-route-DkIRampF.mjs +86 -0
- package/dist/auto-route-DkIRampF.mjs.map +1 -0
- package/dist/checkpoint-block-Bl0HD3U2.mjs.map +1 -1
- package/dist/checkpoint-block-C05sK_HK.mjs +1056 -0
- package/dist/checkpoint-block-C05sK_HK.mjs.map +1 -0
- package/dist/checkpoint-block-CUCG10Uh.mjs +1022 -0
- package/dist/checkpoint-block-CUCG10Uh.mjs.map +1 -0
- package/dist/checkpoint-block-D5IyLLTr.mjs +1062 -0
- package/dist/checkpoint-block-D5IyLLTr.mjs.map +1 -0
- package/dist/cli/index.mjs +6 -6
- package/dist/cli/program.mjs +7 -7
- package/dist/cli/program.mjs.map +1 -1
- package/dist/daemon/index.mjs +9 -9
- package/dist/daemon-9AL6Pwh-.mjs +1581 -0
- package/dist/daemon-9AL6Pwh-.mjs.map +1 -0
- package/dist/daemon-Bbk-_rV6.mjs +1581 -0
- package/dist/daemon-Bbk-_rV6.mjs.map +1 -0
- package/dist/daemon-BvcaMk4g.mjs +1581 -0
- package/dist/daemon-BvcaMk4g.mjs.map +1 -0
- package/dist/daemon-CTDEfwcq.mjs +1576 -0
- package/dist/daemon-CTDEfwcq.mjs.map +1 -0
- package/dist/daemon-ClbfaF60.mjs +1576 -0
- package/dist/daemon-ClbfaF60.mjs.map +1 -0
- package/dist/daemon-DDQNDgYF.mjs +1576 -0
- package/dist/daemon-DDQNDgYF.mjs.map +1 -0
- package/dist/daemon-DU8yDWlQ.mjs +1576 -0
- package/dist/daemon-DU8yDWlQ.mjs.map +1 -0
- package/dist/daemon-NJr4iSW3.mjs +1576 -0
- package/dist/daemon-NJr4iSW3.mjs.map +1 -0
- package/dist/detector-Bwzm3E_x.mjs +74 -0
- package/dist/detector-Bwzm3E_x.mjs.map +1 -0
- package/dist/embeddings-Bn86ssxR.mjs +119 -0
- package/dist/embeddings-Bn86ssxR.mjs.map +1 -0
- package/dist/factory-0-57Ac-7.mjs +72 -0
- package/dist/factory-0-57Ac-7.mjs.map +1 -0
- package/dist/factory-PDXQdkLO.mjs +72 -0
- package/dist/factory-PDXQdkLO.mjs.map +1 -0
- package/dist/hooks/context-compression-hook.mjs +36 -4
- package/dist/hooks/context-compression-hook.mjs.map +3 -3
- package/dist/hooks/load-project-context.mjs +188 -6
- package/dist/hooks/load-project-context.mjs.map +4 -4
- package/dist/hooks/stop-hook.mjs +36 -4
- package/dist/hooks/stop-hook.mjs.map +3 -3
- package/dist/index.mjs +3 -3
- package/dist/indexer-backend-BmaS2VcD.mjs +299 -0
- package/dist/indexer-backend-BmaS2VcD.mjs.map +1 -0
- package/dist/indexer-backend-COrJ5rjS.mjs +299 -0
- package/dist/indexer-backend-COrJ5rjS.mjs.map +1 -0
- package/dist/indexer-backend-NwD7TBGh.mjs +301 -0
- package/dist/indexer-backend-NwD7TBGh.mjs.map +1 -0
- package/dist/latent-ideas-BwM3WdBp.mjs +191 -0
- package/dist/latent-ideas-BwM3WdBp.mjs.map +1 -0
- package/dist/neighborhood-DZY0wkpE.mjs +135 -0
- package/dist/neighborhood-DZY0wkpE.mjs.map +1 -0
- package/dist/pick-B0q5cy79.mjs +11785 -0
- package/dist/pick-B0q5cy79.mjs.map +1 -0
- package/dist/pick-BHE9_iA0.mjs +11947 -0
- package/dist/pick-BHE9_iA0.mjs.map +1 -0
- package/dist/pick-BaTjoNqM.mjs +11544 -0
- package/dist/pick-BaTjoNqM.mjs.map +1 -0
- package/dist/pick-C6JbZfN4.mjs +11893 -0
- package/dist/pick-C6JbZfN4.mjs.map +1 -0
- package/dist/pick-CK-bJyjp.mjs +11883 -0
- package/dist/pick-CK-bJyjp.mjs.map +1 -0
- package/dist/pick-CLBkGHyI.mjs +11826 -0
- package/dist/pick-CLBkGHyI.mjs.map +1 -0
- package/dist/pick-CTOif21h.mjs +11544 -0
- package/dist/pick-CTOif21h.mjs.map +1 -0
- package/dist/pick-Ck2cdQgD.mjs +11893 -0
- package/dist/pick-Ck2cdQgD.mjs.map +1 -0
- package/dist/pick-Cr4nJzHA.mjs +11914 -0
- package/dist/pick-Cr4nJzHA.mjs.map +1 -0
- package/dist/pick-D4dFfKAu.mjs +11893 -0
- package/dist/pick-D4dFfKAu.mjs.map +1 -0
- package/dist/pick-D7-lYiGX.mjs +11543 -0
- package/dist/pick-D7-lYiGX.mjs.map +1 -0
- package/dist/pick-DMjCY0np.mjs +11875 -0
- package/dist/pick-DMjCY0np.mjs.map +1 -0
- package/dist/pick-DbX4OrCP.mjs +11543 -0
- package/dist/pick-DbX4OrCP.mjs.map +1 -0
- package/dist/pick-iCiPjlnC.mjs +11893 -0
- package/dist/pick-iCiPjlnC.mjs.map +1 -0
- package/dist/pick-sF9GnQUS.mjs +11893 -0
- package/dist/pick-sF9GnQUS.mjs.map +1 -0
- package/dist/pick-yHKUrnfG.mjs +11793 -0
- package/dist/pick-yHKUrnfG.mjs.map +1 -0
- package/dist/postgres-BJxiqtqg.mjs +891 -0
- package/dist/postgres-BJxiqtqg.mjs.map +1 -0
- package/dist/search-CpTv1I24.mjs +298 -0
- package/dist/search-CpTv1I24.mjs.map +1 -0
- package/dist/skills/Pause/SKILL.md +11 -4
- package/dist/sqlite-CZ0LFili.mjs +271 -0
- package/dist/sqlite-CZ0LFili.mjs.map +1 -0
- package/dist/sqlite-Nw8ZW5Rj.mjs +271 -0
- package/dist/sqlite-Nw8ZW5Rj.mjs.map +1 -0
- package/dist/sync--BoxBBok.mjs +310 -0
- package/dist/sync--BoxBBok.mjs.map +1 -0
- package/dist/themes-BBOlGXAg.mjs +148 -0
- package/dist/themes-BBOlGXAg.mjs.map +1 -0
- package/dist/tools-B6BmaAvz.mjs +1939 -0
- package/dist/tools-B6BmaAvz.mjs.map +1 -0
- package/dist/tools-CAIY8TAb.mjs +1939 -0
- package/dist/tools-CAIY8TAb.mjs.map +1 -0
- package/dist/work-queue-worker-BoHIH70K.mjs +1856 -0
- package/dist/work-queue-worker-BoHIH70K.mjs.map +1 -0
- package/dist/work-queue-worker-CZGcQoLw.mjs +1856 -0
- package/dist/work-queue-worker-CZGcQoLw.mjs.map +1 -0
- package/dist/work-queue-worker-D05Ze9e9.mjs +1856 -0
- package/dist/work-queue-worker-D05Ze9e9.mjs.map +1 -0
- package/dist/work-queue-worker-DdXFINfH.mjs +1856 -0
- package/dist/work-queue-worker-DdXFINfH.mjs.map +1 -0
- package/dist/zettelkasten-D0N_A_OE.mjs +1063 -0
- package/dist/zettelkasten-D0N_A_OE.mjs.map +1 -0
- package/docs/commands/README.md +2 -1
- package/docs/commands/pause.md +1 -1
- package/docs/commands/session.md +27 -3
- package/package.json +1 -1
- package/plugins/context-preservation/hooks/hooks.json +12 -1
- package/scripts/build-hooks.mjs +1 -0
- package/src/hooks/session-autosave.sh +69 -0
- package/src/hooks/session-stop.sh +32 -1
- package/src/hooks/ts/session-start/load-project-context.ts +44 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/hooks/ts/session-start/load-project-context.ts
|
|
4
|
-
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync } from "fs";
|
|
4
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
5
5
|
import { join as join6, basename as basename4, dirname, resolve as resolve2 } from "path";
|
|
6
6
|
import { homedir as homedir4 } from "os";
|
|
7
7
|
import { execSync } from "child_process";
|
|
8
8
|
|
|
9
9
|
// src/memory/wakeup.ts
|
|
10
|
-
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
10
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
11
11
|
import { join, basename } from "node:path";
|
|
12
12
|
import { homedir } from "node:os";
|
|
13
13
|
var L1_TOKEN_BUDGET = 800;
|
|
@@ -68,10 +68,26 @@ function findSessionNotes(notesDir) {
|
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
scanDir(notesDir);
|
|
71
|
+
const dateOf = (p) => basename(p).match(/(\d{4}-\d{2}-\d{2})/)?.[1] ?? "";
|
|
72
|
+
const numberOf = (p) => parseInt(basename(p).match(/^(\d+)/)?.[1] ?? "0", 10);
|
|
73
|
+
const mtimeOf = (p) => {
|
|
74
|
+
try {
|
|
75
|
+
return statSync(p).mtimeMs;
|
|
76
|
+
} catch {
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
71
80
|
result.sort((a, b) => {
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
81
|
+
const dateA = dateOf(a);
|
|
82
|
+
const dateB = dateOf(b);
|
|
83
|
+
if (dateA !== dateB) {
|
|
84
|
+
if (!dateA) return 1;
|
|
85
|
+
if (!dateB) return -1;
|
|
86
|
+
return dateB.localeCompare(dateA);
|
|
87
|
+
}
|
|
88
|
+
const byNumber = numberOf(b) - numberOf(a);
|
|
89
|
+
if (byNumber !== 0) return byNumber;
|
|
90
|
+
return mtimeOf(b) - mtimeOf(a);
|
|
75
91
|
});
|
|
76
92
|
return result;
|
|
77
93
|
}
|
|
@@ -161,6 +177,141 @@ ${essentialStory}`);
|
|
|
161
177
|
return parts.join("\n\n");
|
|
162
178
|
}
|
|
163
179
|
|
|
180
|
+
// src/session/checkpoint-block.ts
|
|
181
|
+
var MARKER_OPEN = "<!-- pai:checkpoint";
|
|
182
|
+
var MARKER_CLOSE = "<!-- /pai:checkpoint -->";
|
|
183
|
+
var CONTINUE_HEADING = "## Continue";
|
|
184
|
+
function parseMarker(line) {
|
|
185
|
+
const trimmed = line.trim();
|
|
186
|
+
if (!trimmed.startsWith(MARKER_OPEN)) return null;
|
|
187
|
+
const attrs = {};
|
|
188
|
+
for (const m of trimmed.matchAll(/([a-zA-Z][\w-]*)="([^"]*)"/g)) {
|
|
189
|
+
attrs[m[1]] = m[2];
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
authored: attrs.authored === "model" ? "model" : "auto",
|
|
193
|
+
session: attrs.session || void 0,
|
|
194
|
+
sessionId: attrs["session-id"] || void 0,
|
|
195
|
+
ts: attrs.ts || void 0
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
var BOILERPLATE_PATTERNS = [
|
|
199
|
+
/^##\s+Continue$/,
|
|
200
|
+
/^<!--\s*\/?pai:checkpoint/,
|
|
201
|
+
/^>\s*\*\*Last session:\*\*/,
|
|
202
|
+
/^>\s*\*\*Paused at:\*\*/,
|
|
203
|
+
/^>\s*Working directory:/,
|
|
204
|
+
/^>\s*Resume with:/,
|
|
205
|
+
/^>\s*_No checkpoint body was recorded/,
|
|
206
|
+
/^-{3,}$/
|
|
207
|
+
];
|
|
208
|
+
var BLANK_LINE = /^>?\s*$/;
|
|
209
|
+
function extractSectionContent(lines) {
|
|
210
|
+
const kept = [];
|
|
211
|
+
for (const line of lines) {
|
|
212
|
+
const t = line.trim();
|
|
213
|
+
if (BOILERPLATE_PATTERNS.some((re) => re.test(t))) continue;
|
|
214
|
+
kept.push(line);
|
|
215
|
+
}
|
|
216
|
+
return trimBlankEdges(collapseBlankRuns(kept)).join("\n");
|
|
217
|
+
}
|
|
218
|
+
function trimBlankEdges(lines) {
|
|
219
|
+
let start = 0;
|
|
220
|
+
let end = lines.length;
|
|
221
|
+
while (start < end && BLANK_LINE.test(lines[start].trim())) start += 1;
|
|
222
|
+
while (end > start && BLANK_LINE.test(lines[end - 1].trim())) end -= 1;
|
|
223
|
+
return lines.slice(start, end);
|
|
224
|
+
}
|
|
225
|
+
function collapseBlankRuns(lines) {
|
|
226
|
+
const out = [];
|
|
227
|
+
let lastWasBlank = false;
|
|
228
|
+
for (const line of lines) {
|
|
229
|
+
const isBlank = BLANK_LINE.test(line.trim());
|
|
230
|
+
if (isBlank && lastWasBlank) continue;
|
|
231
|
+
out.push(line);
|
|
232
|
+
lastWasBlank = isBlank;
|
|
233
|
+
}
|
|
234
|
+
return out;
|
|
235
|
+
}
|
|
236
|
+
function locateContinue(content) {
|
|
237
|
+
const lines = content.split("\n");
|
|
238
|
+
const startIdx = lines.findIndex((l) => l.trim() === CONTINUE_HEADING);
|
|
239
|
+
if (startIdx === -1) return null;
|
|
240
|
+
let meta = null;
|
|
241
|
+
let markerIdx = -1;
|
|
242
|
+
for (let i = startIdx + 1; i < Math.min(startIdx + 6, lines.length); i++) {
|
|
243
|
+
const parsed = parseMarker(lines[i]);
|
|
244
|
+
if (parsed) {
|
|
245
|
+
meta = parsed;
|
|
246
|
+
markerIdx = i;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
if (lines[i].trim() !== "") break;
|
|
250
|
+
}
|
|
251
|
+
let endIdx = lines.length;
|
|
252
|
+
if (markerIdx !== -1) {
|
|
253
|
+
const closeIdx = lines.findIndex(
|
|
254
|
+
(l, i) => i > markerIdx && l.trim() === MARKER_CLOSE
|
|
255
|
+
);
|
|
256
|
+
if (closeIdx !== -1) {
|
|
257
|
+
endIdx = closeIdx + 1;
|
|
258
|
+
} else {
|
|
259
|
+
endIdx = heuristicEnd(lines, startIdx);
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
endIdx = heuristicEnd(lines, startIdx);
|
|
263
|
+
}
|
|
264
|
+
let trailingEnd = endIdx;
|
|
265
|
+
while (trailingEnd < lines.length && lines[trailingEnd].trim() === "") {
|
|
266
|
+
trailingEnd += 1;
|
|
267
|
+
}
|
|
268
|
+
if (trailingEnd < lines.length && lines[trailingEnd].trim() === "---") {
|
|
269
|
+
trailingEnd += 1;
|
|
270
|
+
} else {
|
|
271
|
+
trailingEnd = endIdx;
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
startIdx,
|
|
275
|
+
endIdx: trailingEnd,
|
|
276
|
+
meta,
|
|
277
|
+
lines: lines.slice(startIdx, trailingEnd)
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
function heuristicEnd(lines, startIdx) {
|
|
281
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
282
|
+
const trimmed = lines[i].trim();
|
|
283
|
+
if (trimmed === "---" || /^##(?!#)/.test(trimmed) && trimmed !== CONTINUE_HEADING) {
|
|
284
|
+
return i;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return lines.length;
|
|
288
|
+
}
|
|
289
|
+
function readContinueCheckpoint(content) {
|
|
290
|
+
const found = locateContinue(content);
|
|
291
|
+
if (!found) return null;
|
|
292
|
+
const body = found.meta ? extractMarkedBody(found.lines) : extractSectionContent(found.lines);
|
|
293
|
+
if (!body) return null;
|
|
294
|
+
return { meta: found.meta, body, raw: found.lines.join("\n") };
|
|
295
|
+
}
|
|
296
|
+
function extractMarkedBody(lines) {
|
|
297
|
+
const markerIdx = lines.findIndex((l) => parseMarker(l) !== null);
|
|
298
|
+
if (markerIdx === -1) return extractSectionContent(lines);
|
|
299
|
+
const closeIdx = lines.findIndex(
|
|
300
|
+
(l, i) => i > markerIdx && l.trim() === MARKER_CLOSE
|
|
301
|
+
);
|
|
302
|
+
if (closeIdx === -1) return extractSectionContent(lines);
|
|
303
|
+
let bodyStart = markerIdx + 1;
|
|
304
|
+
while (bodyStart < closeIdx) {
|
|
305
|
+
const t = lines[bodyStart].trim();
|
|
306
|
+
if (BLANK_LINE.test(t) || t.startsWith(">")) {
|
|
307
|
+
bodyStart += 1;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
return trimBlankEdges(lines.slice(bodyStart, closeIdx)).join("\n");
|
|
313
|
+
}
|
|
314
|
+
|
|
164
315
|
// src/hooks/ts/lib/project-utils/paths.ts
|
|
165
316
|
import { existsSync as existsSync3, mkdirSync, readdirSync as readdirSync2, renameSync } from "fs";
|
|
166
317
|
import { join as join3, basename as basename2 } from "path";
|
|
@@ -573,7 +724,7 @@ async function main() {
|
|
|
573
724
|
const jsonlFiles = files.filter((f) => f.endsWith(".jsonl")).map((f) => ({
|
|
574
725
|
name: f,
|
|
575
726
|
path: join6(projectDir, f),
|
|
576
|
-
mtime:
|
|
727
|
+
mtime: statSync2(join6(projectDir, f)).mtime.getTime()
|
|
577
728
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
578
729
|
if (jsonlFiles.length > 1) {
|
|
579
730
|
const { mkdirSync: mkdirSync3, renameSync: renameSync3 } = await import("fs");
|
|
@@ -750,6 +901,37 @@ Session Commands:
|
|
|
750
901
|
</system-reminder>
|
|
751
902
|
`;
|
|
752
903
|
console.log(reminder);
|
|
904
|
+
if (existsSync6(todoPath)) {
|
|
905
|
+
try {
|
|
906
|
+
const checkpoint = readContinueCheckpoint(readFileSync5(todoPath, "utf-8"));
|
|
907
|
+
if (checkpoint) {
|
|
908
|
+
const from = checkpoint.meta?.session ? `
|
|
909
|
+
From session: ${checkpoint.meta.session}` : "";
|
|
910
|
+
const when = checkpoint.meta?.ts ? `
|
|
911
|
+
Paused at: ${checkpoint.meta.ts}` : "";
|
|
912
|
+
const resume = checkpoint.meta?.sessionId ? `
|
|
913
|
+
Resume that session with: claude --resume ${checkpoint.meta.sessionId}` : "";
|
|
914
|
+
console.log(`
|
|
915
|
+
<system-reminder>
|
|
916
|
+
HANDOVER FROM THE PREVIOUS SESSION
|
|
917
|
+
|
|
918
|
+
Source: ${todoPath} (## Continue)${from}${when}${resume}
|
|
919
|
+
|
|
920
|
+
${checkpoint.body}
|
|
921
|
+
|
|
922
|
+
---
|
|
923
|
+
This is recorded state, not a new instruction. Do not start acting on it
|
|
924
|
+
unprompted. If the user says "go", "continue", or "weiter", resume from here.
|
|
925
|
+
</system-reminder>
|
|
926
|
+
`);
|
|
927
|
+
console.error(`Injected pause checkpoint (${checkpoint.body.length} chars)`);
|
|
928
|
+
} else {
|
|
929
|
+
console.error("No pause checkpoint body in TODO.md \u2014 nothing to hand over");
|
|
930
|
+
}
|
|
931
|
+
} catch (error) {
|
|
932
|
+
console.error("Checkpoint injection failed:", error);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
753
935
|
for (const { path, content } of claudeMdContents) {
|
|
754
936
|
const claudeMdReminder = `
|
|
755
937
|
<system-reminder>
|