@tekmidian/pai 0.14.2 → 0.16.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/dist/{auto-route-CLYcToZ5.mjs → auto-route-CdvjEWs5.mjs} +4 -4
- package/dist/{auto-route-CLYcToZ5.mjs.map → auto-route-CdvjEWs5.mjs.map} +1 -1
- package/dist/{kg-extraction-C8DEUHTS.mjs → checkpoint-block-Bl0HD3U2.mjs} +442 -13
- package/dist/checkpoint-block-Bl0HD3U2.mjs.map +1 -0
- package/dist/cli/index.mjs +14 -12
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.d.mts.map +1 -1
- package/dist/cli/program.mjs +31 -16
- package/dist/cli/program.mjs.map +1 -1
- package/dist/{clusters-BYPw7vfW.mjs → clusters-CKWDwcMX.mjs} +2 -2
- package/dist/{clusters-BYPw7vfW.mjs.map → clusters-CKWDwcMX.mjs.map} +1 -1
- package/dist/{config-C8m-tPhP.mjs → config-DGOfoGfm.mjs} +1 -1
- package/dist/config-DGOfoGfm.mjs.map +1 -0
- package/dist/daemon/index.mjs +18 -16
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/{daemon-COSvHTNu.mjs → daemon-1rKbN-fd.mjs} +31 -30
- package/dist/{daemon-COSvHTNu.mjs.map → daemon-1rKbN-fd.mjs.map} +1 -1
- package/dist/daemon-mcp/index.mjs +24 -2
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/db-BtuN768f.mjs +206 -0
- package/dist/db-BtuN768f.mjs.map +1 -0
- package/dist/{db-CmYbAVCD.mjs → db-CYmBWcjh.mjs} +1 -1
- package/dist/{db-CmYbAVCD.mjs.map → db-CYmBWcjh.mjs.map} +1 -1
- package/dist/{detect-KjycLtXM.mjs → detect-Bf2z-oKB.mjs} +1 -1
- package/dist/{detect-KjycLtXM.mjs.map → detect-Bf2z-oKB.mjs.map} +1 -1
- package/dist/{detector-ZiOhHszd.mjs → detector-rq9JGTmS.mjs} +2 -2
- package/dist/{detector-ZiOhHszd.mjs.map → detector-rq9JGTmS.mjs.map} +1 -1
- package/dist/{embeddings-BJPOcbik.mjs → embeddings-DGRAPAYb.mjs} +1 -1
- package/dist/{embeddings-BJPOcbik.mjs.map → embeddings-DGRAPAYb.mjs.map} +1 -1
- package/dist/{factory-Q88X1bAN.mjs → factory-HcQsQqh0.mjs} +8 -5
- package/dist/{factory-Q88X1bAN.mjs.map → factory-HcQsQqh0.mjs.map} +1 -1
- package/dist/{helpers-IjZkXBhj.mjs → helpers-crDEr6S2.mjs} +1 -1
- package/dist/{helpers-IjZkXBhj.mjs.map → helpers-crDEr6S2.mjs.map} +1 -1
- package/dist/hooks/capture-all-events.mjs.map +1 -1
- package/dist/hooks/capture-session-summary.mjs.map +1 -1
- package/dist/hooks/capture-tool-output.mjs.map +1 -1
- package/dist/hooks/cleanup-session-files.mjs.map +1 -1
- package/dist/hooks/context-compression-hook.mjs +304 -48
- package/dist/hooks/context-compression-hook.mjs.map +4 -4
- package/dist/hooks/initialize-session.mjs.map +1 -1
- package/dist/hooks/inject-observations.mjs.map +1 -1
- package/dist/hooks/load-core-context.mjs.map +1 -1
- package/dist/hooks/load-project-context.mjs.map +1 -1
- package/dist/hooks/observe.mjs.map +1 -1
- package/dist/hooks/post-compact-inject.mjs.map +1 -1
- package/dist/hooks/security-validator.mjs.map +1 -1
- package/dist/hooks/session-commands.mjs.map +1 -1
- package/dist/hooks/stop-hook.mjs +299 -43
- package/dist/hooks/stop-hook.mjs.map +4 -4
- package/dist/hooks/subagent-stop-hook.mjs.map +1 -1
- package/dist/hooks/sync-todo-to-md.mjs.map +1 -1
- package/dist/hooks/update-tab-on-action.mjs.map +1 -1
- package/dist/hooks/update-tab-titles.mjs.map +1 -1
- package/dist/hooks/whisper-rules.mjs.map +1 -1
- package/dist/index.d.mts +0 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +10 -9
- package/dist/indexer-AEcT8wHf.mjs +1 -0
- package/dist/{indexer-backend-Cm5RS7y0.mjs → indexer-backend-BQZXoarl.mjs} +3 -3
- package/dist/{indexer-backend-Cm5RS7y0.mjs.map → indexer-backend-BQZXoarl.mjs.map} +1 -1
- package/dist/{ipc-client-CoyUHPod.mjs → ipc-client-vO2GV325.mjs} +1 -1
- package/dist/{ipc-client-CoyUHPod.mjs.map → ipc-client-vO2GV325.mjs.map} +1 -1
- package/dist/{kg-entity-LXblD7LZ.mjs → kg-entity-DbOMPdF9.mjs} +1 -1
- package/dist/{kg-entity-LXblD7LZ.mjs.map → kg-entity-DbOMPdF9.mjs.map} +1 -1
- package/dist/{latent-ideas-RyC6eyqI.mjs → latent-ideas-C6IFFT0-.mjs} +4 -4
- package/dist/{latent-ideas-RyC6eyqI.mjs.map → latent-ideas-C6IFFT0-.mjs.map} +1 -1
- package/dist/{main-resolver-uFxNiDy7.mjs → main-resolver-DimnS2qP.mjs} +22 -22
- package/dist/{main-resolver-uFxNiDy7.mjs.map → main-resolver-DimnS2qP.mjs.map} +1 -1
- package/dist/{migrate-B02wDDgS.mjs → migrate-fLD6rAdO.mjs} +2 -2
- package/dist/{migrate-B02wDDgS.mjs.map → migrate-fLD6rAdO.mjs.map} +1 -1
- package/dist/{neighborhood-CklGIB8r.mjs → neighborhood-CzRNG2Oy.mjs} +2 -2
- package/dist/{neighborhood-CklGIB8r.mjs.map → neighborhood-CzRNG2Oy.mjs.map} +1 -1
- package/dist/{note-context-qvZlVXVO.mjs → note-context-CrfMbr4R.mjs} +1 -1
- package/dist/{note-context-qvZlVXVO.mjs.map → note-context-CrfMbr4R.mjs.map} +1 -1
- package/dist/{pai-marker-HVBwwBW-.mjs → pai-marker-B20KqhA8.mjs} +44 -2
- package/dist/pai-marker-B20KqhA8.mjs.map +1 -0
- package/dist/{pick-gne3kOJG.mjs → pick-B3zEYjin.mjs} +2316 -483
- package/dist/pick-B3zEYjin.mjs.map +1 -0
- package/dist/{postgres-B451Hnkm.mjs → postgres-zjKqPl4X.mjs} +2 -2
- package/dist/{postgres-B451Hnkm.mjs.map → postgres-zjKqPl4X.mjs.map} +1 -1
- package/dist/{query-feedback-fapbqRgh.mjs → query-feedback-BoY8_Dbb.mjs} +1 -1
- package/dist/{query-feedback-fapbqRgh.mjs.map → query-feedback-BoY8_Dbb.mjs.map} +1 -1
- package/dist/{reranker-C08R99zn.mjs → reranker-CMNZcfVx.mjs} +1 -1
- package/dist/{reranker-C08R99zn.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
- package/dist/{search-HcdKtMla.mjs → search-i2nlQ-JM.mjs} +3 -3
- package/dist/{search-HcdKtMla.mjs.map → search-i2nlQ-JM.mjs.map} +1 -1
- package/dist/skills/End/SKILL.md +78 -0
- package/dist/skills/Pause/SKILL.md +77 -0
- package/dist/skills/Tasks/SKILL.md +22 -0
- package/dist/{sqlite-DQpY1Esi.mjs → sqlite-ChSCYwiC.mjs} +3 -3
- package/dist/{sqlite-DQpY1Esi.mjs.map → sqlite-ChSCYwiC.mjs.map} +1 -1
- package/dist/{state-BIlxNRUn.mjs → state-BXIdbxDs.mjs} +1 -1
- package/dist/{state-BIlxNRUn.mjs.map → state-BXIdbxDs.mjs.map} +1 -1
- package/dist/{stop-words-BwplsQ3z.mjs → stop-words-BaMEGVeY.mjs} +1 -1
- package/dist/{stop-words-BwplsQ3z.mjs.map → stop-words-BaMEGVeY.mjs.map} +1 -1
- package/dist/{sync-uPR4g438.mjs → sync-CmBKOL3K.mjs} +6 -205
- package/dist/sync-CmBKOL3K.mjs.map +1 -0
- package/dist/{themes-Cg8oG9Ra.mjs → themes-nvRM8v84.mjs} +3 -3
- package/dist/{themes-Cg8oG9Ra.mjs.map → themes-nvRM8v84.mjs.map} +1 -1
- package/dist/{tools-Op3C2Nm6.mjs → tools-CznjzfYz.mjs} +26 -26
- package/dist/{tools-Op3C2Nm6.mjs.map → tools-CznjzfYz.mjs.map} +1 -1
- package/dist/{trace-CLK-NPkb.mjs → trace-B8oz1ok0.mjs} +1 -1
- package/dist/{trace-CLK-NPkb.mjs.map → trace-B8oz1ok0.mjs.map} +1 -1
- package/dist/{utils-CqqgB0dH.mjs → utils-BAxjW3j8.mjs} +1 -1
- package/dist/{utils-CqqgB0dH.mjs.map → utils-BAxjW3j8.mjs.map} +1 -1
- package/dist/{vault-indexer-Dn_BccVK.mjs → vault-indexer-DrttVeEk.mjs} +2 -2
- package/dist/{vault-indexer-Dn_BccVK.mjs.map → vault-indexer-DrttVeEk.mjs.map} +1 -1
- package/dist/{work-queue-worker-BwouhVkb.mjs → work-queue-worker-BPXLkEik.mjs} +47 -30
- package/dist/work-queue-worker-BPXLkEik.mjs.map +1 -0
- package/dist/{zettelkasten-NwBD1NsT.mjs → zettelkasten-CTlt1dGv.mjs} +4 -4
- package/dist/{zettelkasten-NwBD1NsT.mjs.map → zettelkasten-CTlt1dGv.mjs.map} +1 -1
- package/docs/commands/README.md +17 -0
- package/docs/commands/backup.md +1 -1
- package/docs/commands/clear-names.md +1 -1
- package/docs/commands/daemon.md +1 -1
- package/docs/commands/db.md +1 -1
- package/docs/commands/end.md +4 -1
- package/docs/commands/help.md +1 -1
- package/docs/commands/kg.md +1 -1
- package/docs/commands/mcp.md +1 -1
- package/docs/commands/memory.md +1 -1
- package/docs/commands/notify.md +1 -1
- package/docs/commands/observation.md +1 -1
- package/docs/commands/obsidian.md +1 -1
- package/docs/commands/pause.md +4 -1
- package/docs/commands/project.md +1 -1
- package/docs/commands/projects.md +1 -1
- package/docs/commands/registry.md +18 -1
- package/docs/commands/restore.md +1 -1
- package/docs/commands/session.md +271 -0
- package/docs/commands/sessions.md +1 -1
- package/docs/commands/setup.md +1 -1
- package/docs/commands/shell-init.md +1 -1
- package/docs/commands/skill.md +1 -1
- package/docs/commands/task.md +2 -1
- package/docs/commands/topic.md +1 -1
- package/docs/commands/update.md +1 -1
- package/docs/commands/zettel.md +1 -1
- package/package.json +1 -1
- package/scripts/build-hooks.mjs +32 -3
- package/src/hooks/ts/lib/project-utils/todo.test.ts +132 -0
- package/src/hooks/ts/lib/project-utils/todo.ts +60 -34
- package/dist/config-C8m-tPhP.mjs.map +0 -1
- package/dist/kg-extraction-C8DEUHTS.mjs.map +0 -1
- package/dist/pai-marker-HVBwwBW-.mjs.map +0 -1
- package/dist/pick-gne3kOJG.mjs.map +0 -1
- package/dist/sync-uPR4g438.mjs.map +0 -1
- package/dist/work-queue-worker-BwouhVkb.mjs.map +0 -1
package/dist/hooks/stop-hook.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/hooks/ts/stop/stop-hook.ts
|
|
4
|
-
import { readFileSync as
|
|
5
|
-
import { join as
|
|
4
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync7, unlinkSync } from "fs";
|
|
5
|
+
import { join as join7, basename as basename3, dirname } from "path";
|
|
6
6
|
import { connect } from "net";
|
|
7
7
|
import { randomUUID } from "crypto";
|
|
8
8
|
|
|
@@ -387,13 +387,260 @@ ${summary || "Session completed."}`
|
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
// src/hooks/ts/lib/project-utils/todo.ts
|
|
390
|
-
import { existsSync as
|
|
391
|
-
import { join as
|
|
390
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
391
|
+
import { join as join6 } from "path";
|
|
392
|
+
|
|
393
|
+
// src/session/checkpoint-block.ts
|
|
394
|
+
import {
|
|
395
|
+
existsSync as existsSync5,
|
|
396
|
+
readFileSync as readFileSync4,
|
|
397
|
+
writeFileSync as writeFileSync2,
|
|
398
|
+
readdirSync as readdirSync3,
|
|
399
|
+
renameSync as renameSync3,
|
|
400
|
+
mkdirSync as mkdirSync3,
|
|
401
|
+
realpathSync
|
|
402
|
+
} from "node:fs";
|
|
403
|
+
import { join as join5 } from "node:path";
|
|
404
|
+
var TODO_LOCATIONS = [
|
|
405
|
+
"Notes/TODO.md",
|
|
406
|
+
".claude/Notes/TODO.md",
|
|
407
|
+
"tasks/todo.md",
|
|
408
|
+
"TODO.md"
|
|
409
|
+
];
|
|
410
|
+
var MARKER_OPEN = "<!-- pai:checkpoint";
|
|
411
|
+
var MARKER_CLOSE = "<!-- /pai:checkpoint -->";
|
|
412
|
+
var CONTINUE_HEADING = "## Continue";
|
|
413
|
+
function findProjectTodo(rootPath) {
|
|
414
|
+
for (const rel of TODO_LOCATIONS) {
|
|
415
|
+
const full = join5(rootPath, rel);
|
|
416
|
+
if (existsSync5(full)) {
|
|
417
|
+
try {
|
|
418
|
+
return { path: full, content: readFileSync4(full, "utf8") };
|
|
419
|
+
} catch {
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
function resolveTodoTarget(rootPath, opts = {}) {
|
|
426
|
+
const found = findProjectTodo(rootPath);
|
|
427
|
+
if (found) return found;
|
|
428
|
+
const notesDir = join5(rootPath, "Notes");
|
|
429
|
+
if (opts.create !== false) {
|
|
430
|
+
try {
|
|
431
|
+
if (!existsSync5(notesDir)) mkdirSync3(notesDir, { recursive: true });
|
|
432
|
+
} catch {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return { path: join5(notesDir, "TODO.md"), content: "" };
|
|
437
|
+
}
|
|
438
|
+
function parseMarker(line) {
|
|
439
|
+
const trimmed = line.trim();
|
|
440
|
+
if (!trimmed.startsWith(MARKER_OPEN)) return null;
|
|
441
|
+
const attrs = {};
|
|
442
|
+
for (const m of trimmed.matchAll(/([a-zA-Z][\w-]*)="([^"]*)"/g)) {
|
|
443
|
+
attrs[m[1]] = m[2];
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
authored: attrs.authored === "model" ? "model" : "auto",
|
|
447
|
+
session: attrs.session || void 0,
|
|
448
|
+
sessionId: attrs["session-id"] || void 0,
|
|
449
|
+
ts: attrs.ts || void 0
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
var BOILERPLATE_PATTERNS = [
|
|
453
|
+
/^##\s+Continue$/,
|
|
454
|
+
/^<!--\s*\/?pai:checkpoint/,
|
|
455
|
+
/^>\s*\*\*Last session:\*\*/,
|
|
456
|
+
/^>\s*\*\*Paused at:\*\*/,
|
|
457
|
+
/^>\s*Working directory:/,
|
|
458
|
+
/^>\s*Resume with:/,
|
|
459
|
+
/^>\s*_No checkpoint body was recorded/,
|
|
460
|
+
/^>?\s*$/,
|
|
461
|
+
/^-{3,}$/
|
|
462
|
+
];
|
|
463
|
+
function isBoilerplateOnly(lines) {
|
|
464
|
+
return lines.every((line) => {
|
|
465
|
+
const t = line.trim();
|
|
466
|
+
return BOILERPLATE_PATTERNS.some((re) => re.test(t));
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
function extractSectionContent(lines) {
|
|
470
|
+
const kept = [];
|
|
471
|
+
for (const line of lines) {
|
|
472
|
+
const t = line.trim();
|
|
473
|
+
if (BOILERPLATE_PATTERNS.some((re) => re.test(t))) continue;
|
|
474
|
+
kept.push(line);
|
|
475
|
+
}
|
|
476
|
+
return kept.join("\n").trim();
|
|
477
|
+
}
|
|
478
|
+
function locateContinue(content) {
|
|
479
|
+
const lines = content.split("\n");
|
|
480
|
+
const startIdx = lines.findIndex((l) => l.trim() === CONTINUE_HEADING);
|
|
481
|
+
if (startIdx === -1) return null;
|
|
482
|
+
let meta = null;
|
|
483
|
+
let markerIdx = -1;
|
|
484
|
+
for (let i = startIdx + 1; i < Math.min(startIdx + 6, lines.length); i++) {
|
|
485
|
+
const parsed = parseMarker(lines[i]);
|
|
486
|
+
if (parsed) {
|
|
487
|
+
meta = parsed;
|
|
488
|
+
markerIdx = i;
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
if (lines[i].trim() !== "") break;
|
|
492
|
+
}
|
|
493
|
+
let endIdx = lines.length;
|
|
494
|
+
if (markerIdx !== -1) {
|
|
495
|
+
const closeIdx = lines.findIndex(
|
|
496
|
+
(l, i) => i > markerIdx && l.trim() === MARKER_CLOSE
|
|
497
|
+
);
|
|
498
|
+
if (closeIdx !== -1) {
|
|
499
|
+
endIdx = closeIdx + 1;
|
|
500
|
+
} else {
|
|
501
|
+
endIdx = heuristicEnd(lines, startIdx);
|
|
502
|
+
}
|
|
503
|
+
} else {
|
|
504
|
+
endIdx = heuristicEnd(lines, startIdx);
|
|
505
|
+
}
|
|
506
|
+
let trailingEnd = endIdx;
|
|
507
|
+
while (trailingEnd < lines.length && lines[trailingEnd].trim() === "") {
|
|
508
|
+
trailingEnd += 1;
|
|
509
|
+
}
|
|
510
|
+
if (trailingEnd < lines.length && lines[trailingEnd].trim() === "---") {
|
|
511
|
+
trailingEnd += 1;
|
|
512
|
+
} else {
|
|
513
|
+
trailingEnd = endIdx;
|
|
514
|
+
}
|
|
515
|
+
return {
|
|
516
|
+
startIdx,
|
|
517
|
+
endIdx: trailingEnd,
|
|
518
|
+
meta,
|
|
519
|
+
lines: lines.slice(startIdx, trailingEnd)
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function heuristicEnd(lines, startIdx) {
|
|
523
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
524
|
+
const trimmed = lines[i].trim();
|
|
525
|
+
if (trimmed === "---" || /^##(?!#)/.test(trimmed) && trimmed !== CONTINUE_HEADING) {
|
|
526
|
+
return i;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return lines.length;
|
|
530
|
+
}
|
|
531
|
+
function stripContinue(content) {
|
|
532
|
+
const found = locateContinue(content);
|
|
533
|
+
if (!found) return content;
|
|
534
|
+
const lines = content.split("\n");
|
|
535
|
+
const before = lines.slice(0, found.startIdx);
|
|
536
|
+
const after = lines.slice(found.endIdx);
|
|
537
|
+
while (after.length > 0 && after[0].trim() === "") after.shift();
|
|
538
|
+
return [...before, ...after].join("\n");
|
|
539
|
+
}
|
|
540
|
+
function escapeAttr(value) {
|
|
541
|
+
return value.replace(/"/g, "'");
|
|
542
|
+
}
|
|
543
|
+
function buildContinueBlock(opts) {
|
|
544
|
+
const ts = opts.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
545
|
+
const attrs = [
|
|
546
|
+
`authored="${opts.authored}"`,
|
|
547
|
+
`session="${escapeAttr(opts.sessionLine)}"`,
|
|
548
|
+
opts.sessionId ? `session-id="${escapeAttr(opts.sessionId)}"` : null,
|
|
549
|
+
`ts="${ts}"`
|
|
550
|
+
].filter(Boolean).join(" ");
|
|
551
|
+
const header = [
|
|
552
|
+
`> **Last session:** ${opts.sessionLine}`,
|
|
553
|
+
`> **Paused at:** ${ts}`,
|
|
554
|
+
">",
|
|
555
|
+
`> Working directory: ${opts.cwd}`
|
|
556
|
+
];
|
|
557
|
+
if (opts.sessionId) {
|
|
558
|
+
header.push(">", `> Resume with: \`claude --resume ${opts.sessionId}\``);
|
|
559
|
+
}
|
|
560
|
+
const body = (opts.body ?? "").trim();
|
|
561
|
+
const parts = [
|
|
562
|
+
CONTINUE_HEADING,
|
|
563
|
+
"",
|
|
564
|
+
`${MARKER_OPEN} ${attrs} -->`,
|
|
565
|
+
"",
|
|
566
|
+
...header
|
|
567
|
+
];
|
|
568
|
+
if (body) {
|
|
569
|
+
parts.push("", body);
|
|
570
|
+
} else {
|
|
571
|
+
parts.push(
|
|
572
|
+
">",
|
|
573
|
+
"> _No checkpoint body was recorded \u2014 see the latest session note._"
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
parts.push("", MARKER_CLOSE, "", "---", "");
|
|
577
|
+
return parts.join("\n");
|
|
578
|
+
}
|
|
579
|
+
function applyContinue(opts) {
|
|
580
|
+
const target = resolveTodoTarget(opts.rootPath, { create: !opts.dryRun });
|
|
581
|
+
if (!target) {
|
|
582
|
+
return {
|
|
583
|
+
action: "failed",
|
|
584
|
+
path: null,
|
|
585
|
+
block: buildContinueBlock(opts),
|
|
586
|
+
error: "Could not resolve or create a TODO.md target"
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const existing = locateContinue(target.content);
|
|
590
|
+
let carriedForward = false;
|
|
591
|
+
let effectiveBody = opts.body;
|
|
592
|
+
if (opts.authored === "auto" && existing) {
|
|
593
|
+
if (existing.meta?.authored === "model" && existing.meta.session === opts.sessionLine) {
|
|
594
|
+
return {
|
|
595
|
+
action: "preserved",
|
|
596
|
+
path: target.path,
|
|
597
|
+
block: buildContinueBlock(opts),
|
|
598
|
+
preservedMeta: existing.meta
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
if (!existing.meta && !isBoilerplateOnly(existing.lines)) {
|
|
602
|
+
const salvaged = extractSectionContent(existing.lines);
|
|
603
|
+
if (salvaged) {
|
|
604
|
+
effectiveBody = [
|
|
605
|
+
"_Carried forward from the previous checkpoint (author unknown \u2014 this",
|
|
606
|
+
"block predates checkpoint authorship markers):_",
|
|
607
|
+
"",
|
|
608
|
+
salvaged
|
|
609
|
+
].join("\n");
|
|
610
|
+
carriedForward = true;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const block = buildContinueBlock({ ...opts, body: effectiveBody });
|
|
615
|
+
if (opts.dryRun) {
|
|
616
|
+
return { action: "written", path: target.path, block, carriedForward };
|
|
617
|
+
}
|
|
618
|
+
const newContent = block + stripContinue(target.content).trimStart();
|
|
619
|
+
const tmpPath = `${target.path}.continue.tmp`;
|
|
620
|
+
try {
|
|
621
|
+
writeFileSync2(tmpPath, newContent, "utf8");
|
|
622
|
+
renameSync3(tmpPath, target.path);
|
|
623
|
+
} catch (err) {
|
|
624
|
+
try {
|
|
625
|
+
if (existsSync5(tmpPath)) renameSync3(tmpPath, `${tmpPath}.dead`);
|
|
626
|
+
} catch {
|
|
627
|
+
}
|
|
628
|
+
return {
|
|
629
|
+
action: "failed",
|
|
630
|
+
path: target.path,
|
|
631
|
+
block,
|
|
632
|
+
error: String(err)
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
return { action: "written", path: target.path, block, carriedForward };
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/hooks/ts/lib/project-utils/todo.ts
|
|
392
639
|
function ensureTodoMd(cwd) {
|
|
393
640
|
const todoPath = findTodoPath(cwd);
|
|
394
|
-
if (!
|
|
395
|
-
const parentDir =
|
|
396
|
-
if (!
|
|
641
|
+
if (!existsSync6(todoPath)) {
|
|
642
|
+
const parentDir = join6(todoPath, "..");
|
|
643
|
+
if (!existsSync6(parentDir)) mkdirSync4(parentDir, { recursive: true });
|
|
397
644
|
const content = `# TODO
|
|
398
645
|
|
|
399
646
|
## Current Session
|
|
@@ -408,43 +655,52 @@ function ensureTodoMd(cwd) {
|
|
|
408
655
|
|
|
409
656
|
*Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}*
|
|
410
657
|
`;
|
|
411
|
-
|
|
658
|
+
writeFileSync3(todoPath, content);
|
|
412
659
|
console.error(`Created TODO.md: ${todoPath}`);
|
|
413
660
|
}
|
|
414
661
|
return todoPath;
|
|
415
662
|
}
|
|
416
663
|
function updateTodoContinue(cwd, noteFilename, state, tokenDisplay) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
664
|
+
ensureTodoMd(cwd);
|
|
665
|
+
const result = applyContinue({
|
|
666
|
+
rootPath: cwd,
|
|
667
|
+
authored: "auto",
|
|
668
|
+
// The hooks identify a session by its note filename; `pai pause` resolves
|
|
669
|
+
// the same string from the registry (and falls back to this filename when
|
|
670
|
+
// the registry has no session row). They must agree, because this string
|
|
671
|
+
// is the key that decides whether an authored checkpoint belongs to the
|
|
672
|
+
// current session and must be preserved.
|
|
673
|
+
sessionLine: noteFilename.replace(/\.md$/, ""),
|
|
674
|
+
cwd,
|
|
675
|
+
body: state?.trim() || void 0
|
|
676
|
+
});
|
|
677
|
+
if (result.action === "preserved") {
|
|
678
|
+
console.error(
|
|
679
|
+
"TODO.md ## Continue left intact \u2014 authored checkpoint for this session"
|
|
680
|
+
);
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
if (result.action === "failed") {
|
|
684
|
+
console.error(`TODO.md ## Continue update failed: ${result.error}`);
|
|
685
|
+
return;
|
|
438
686
|
}
|
|
439
|
-
|
|
440
|
-
|
|
687
|
+
try {
|
|
688
|
+
const todoPath = result.path;
|
|
689
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
690
|
+
let content = readFileSync5(todoPath, "utf-8");
|
|
691
|
+
content = content.replace(/(\n---\s*)*(\n\*Last updated:.*\*\s*)+$/g, "");
|
|
692
|
+
content = content.trimEnd() + `
|
|
441
693
|
|
|
442
694
|
---
|
|
443
695
|
|
|
444
696
|
*Last updated: ${now}*
|
|
445
697
|
`;
|
|
446
|
-
|
|
447
|
-
|
|
698
|
+
writeFileSync3(todoPath, content);
|
|
699
|
+
} catch {
|
|
700
|
+
}
|
|
701
|
+
console.error(
|
|
702
|
+
result.carriedForward ? "TODO.md ## Continue section updated (previous content carried forward)" : "TODO.md ## Continue section updated"
|
|
703
|
+
);
|
|
448
704
|
}
|
|
449
705
|
|
|
450
706
|
// src/hooks/ts/stop/stop-hook.ts
|
|
@@ -458,7 +714,7 @@ var AUTO_SAVE_INTERVAL = (() => {
|
|
|
458
714
|
}
|
|
459
715
|
return 15;
|
|
460
716
|
})();
|
|
461
|
-
var SESSION_STATE_DIR =
|
|
717
|
+
var SESSION_STATE_DIR = join7(
|
|
462
718
|
process.env.HOME ?? "/tmp",
|
|
463
719
|
".config",
|
|
464
720
|
"pai",
|
|
@@ -466,9 +722,9 @@ var SESSION_STATE_DIR = join6(
|
|
|
466
722
|
);
|
|
467
723
|
function readSessionState(sessionId) {
|
|
468
724
|
try {
|
|
469
|
-
const stateFile =
|
|
470
|
-
if (!
|
|
471
|
-
const raw =
|
|
725
|
+
const stateFile = join7(SESSION_STATE_DIR, `${sessionId}.json`);
|
|
726
|
+
if (!existsSync7(stateFile)) return { humanMessageCount: 0 };
|
|
727
|
+
const raw = readFileSync6(stateFile, "utf-8");
|
|
472
728
|
const parsed = JSON.parse(raw);
|
|
473
729
|
return {
|
|
474
730
|
humanMessageCount: typeof parsed.humanMessageCount === "number" ? parsed.humanMessageCount : 0
|
|
@@ -479,17 +735,17 @@ function readSessionState(sessionId) {
|
|
|
479
735
|
}
|
|
480
736
|
function writeSessionState(sessionId, state) {
|
|
481
737
|
try {
|
|
482
|
-
|
|
483
|
-
const stateFile =
|
|
484
|
-
|
|
738
|
+
mkdirSync5(SESSION_STATE_DIR, { recursive: true });
|
|
739
|
+
const stateFile = join7(SESSION_STATE_DIR, `${sessionId}.json`);
|
|
740
|
+
writeFileSync4(stateFile, JSON.stringify(state, null, 2), "utf-8");
|
|
485
741
|
} catch (e) {
|
|
486
742
|
console.error(`STOP-HOOK: Could not write session state: ${e}`);
|
|
487
743
|
}
|
|
488
744
|
}
|
|
489
745
|
function deleteSessionState(sessionId) {
|
|
490
746
|
try {
|
|
491
|
-
const stateFile =
|
|
492
|
-
if (
|
|
747
|
+
const stateFile = join7(SESSION_STATE_DIR, `${sessionId}.json`);
|
|
748
|
+
if (existsSync7(stateFile)) {
|
|
493
749
|
unlinkSync(stateFile);
|
|
494
750
|
}
|
|
495
751
|
} catch {
|
|
@@ -996,7 +1252,7 @@ STOP-HOOK TRIGGERED AT ${timestamp}`);
|
|
|
996
1252
|
}
|
|
997
1253
|
let transcript;
|
|
998
1254
|
try {
|
|
999
|
-
transcript =
|
|
1255
|
+
transcript = readFileSync6(transcriptPath, "utf-8");
|
|
1000
1256
|
debug(`Transcript loaded: ${transcript.split("\n").length} lines`);
|
|
1001
1257
|
} catch (e) {
|
|
1002
1258
|
console.error(`Error reading transcript: ${e}`);
|