@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
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-95iHPtFO.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/storage/factory.ts
|
|
4
|
+
var factory_exports = /* @__PURE__ */ __exportAll({ createStorageBackend: () => createStorageBackend });
|
|
5
|
+
/** Backoff schedule (ms) for the bounded CLI retry path. */
|
|
6
|
+
const CLI_RETRY_DELAYS_MS = [
|
|
7
|
+
500,
|
|
8
|
+
1e3,
|
|
9
|
+
2e3
|
|
10
|
+
];
|
|
11
|
+
/** Backoff cap (ms) for the daemon's infinite retry path. */
|
|
12
|
+
const DAEMON_RETRY_CAP_MS = 15e3;
|
|
13
|
+
/**
|
|
14
|
+
* Create and return the configured StorageBackend.
|
|
15
|
+
*
|
|
16
|
+
* Auto-behaviour:
|
|
17
|
+
* - storageBackend = "sqlite" → SQLiteBackend always
|
|
18
|
+
* - storageBackend = "postgres" → PostgresBackend (retried; never falls back)
|
|
19
|
+
*/
|
|
20
|
+
async function createStorageBackend(config, opts = {}) {
|
|
21
|
+
if (config.storageBackend === "postgres") return await connectPostgres(config, opts.waitForPostgres ?? false);
|
|
22
|
+
return createSQLiteBackend();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Attempt a single Postgres connection (ensure DB + test). Returns the live
|
|
26
|
+
* backend on success, or an error string describing why it failed.
|
|
27
|
+
*/
|
|
28
|
+
async function attemptPostgres(config) {
|
|
29
|
+
const { PostgresBackend } = await import("./postgres-BJxiqtqg.mjs");
|
|
30
|
+
const pgConfig = config.postgres ?? {};
|
|
31
|
+
let backend = null;
|
|
32
|
+
try {
|
|
33
|
+
await PostgresBackend.ensureDatabase(pgConfig);
|
|
34
|
+
backend = new PostgresBackend(pgConfig);
|
|
35
|
+
const err = await backend.testConnection();
|
|
36
|
+
if (err) {
|
|
37
|
+
await backend.close().catch(() => {});
|
|
38
|
+
return { error: err };
|
|
39
|
+
}
|
|
40
|
+
return { backend };
|
|
41
|
+
} catch (e) {
|
|
42
|
+
if (backend) await backend.close().catch(() => {});
|
|
43
|
+
return { error: e instanceof Error ? e.message : String(e) };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function connectPostgres(config, waitForever) {
|
|
47
|
+
let attempt = 0;
|
|
48
|
+
let lastError = "unknown error";
|
|
49
|
+
while (true) {
|
|
50
|
+
attempt++;
|
|
51
|
+
const result = await attemptPostgres(config);
|
|
52
|
+
if ("backend" in result) {
|
|
53
|
+
if (attempt > 1) process.stderr.write(`[pai-daemon] Connected to PostgreSQL backend (after ${attempt} attempts).\n`);
|
|
54
|
+
else process.stderr.write("[pai-daemon] Connected to PostgreSQL backend.\n");
|
|
55
|
+
return result.backend;
|
|
56
|
+
}
|
|
57
|
+
lastError = result.error;
|
|
58
|
+
if (!waitForever && attempt > CLI_RETRY_DELAYS_MS.length) throw new Error(`Postgres backend unreachable after ${attempt} attempts: ${lastError}. Is Docker Desktop / Postgres running? Refusing to fall back to SQLite (would split the corpus). Start Postgres and retry.`);
|
|
59
|
+
const delayMs = waitForever ? Math.min(DAEMON_RETRY_CAP_MS, 1e3 * 2 ** Math.min(attempt - 1, 4)) : CLI_RETRY_DELAYS_MS[attempt - 1];
|
|
60
|
+
process.stderr.write(`[pai-daemon] Postgres unavailable (${lastError}). Retry ${attempt}${waitForever ? "" : `/${CLI_RETRY_DELAYS_MS.length + 1}`} in ${delayMs}ms...\n`);
|
|
61
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function createSQLiteBackend() {
|
|
65
|
+
const { openFederation } = await import("./db-CYmBWcjh.mjs").then((n) => n.t);
|
|
66
|
+
const { SQLiteBackend } = await import("./sqlite-Nw8ZW5Rj.mjs");
|
|
67
|
+
return new SQLiteBackend(openFederation());
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { factory_exports as n, createStorageBackend as t };
|
|
72
|
+
//# sourceMappingURL=factory-PDXQdkLO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory-PDXQdkLO.mjs","names":[],"sources":["../src/storage/factory.ts"],"sourcesContent":["/**\n * Storage backend factory.\n *\n * Reads the daemon config and returns the appropriate StorageBackend.\n *\n * When Postgres is the configured backend we NEVER silently fall back to\n * SQLite — doing so would split the corpus across two databases. Instead:\n * - Daemon (waitForPostgres: true) retries Postgres forever with capped\n * backoff until it comes up (handles the boot race where launchd starts\n * the daemon before Docker Desktop / Postgres is ready).\n * - CLI / one-shot callers (default) retry a few times, then throw a clear\n * error rather than returning a wrong/empty SQLite database.\n */\n\nimport type { PaiDaemonConfig } from \"../daemon/config.js\";\nimport type { StorageBackend } from \"./interface.js\";\n\nexport interface StorageBackendOptions {\n /**\n * When true, retry Postgres indefinitely instead of giving up. Used by the\n * long-lived daemon so a not-yet-ready Postgres at boot is tolerated.\n * Defaults to false (one-shot CLI behaviour: bounded retries, then throw).\n */\n waitForPostgres?: boolean;\n}\n\n/** Backoff schedule (ms) for the bounded CLI retry path. */\nconst CLI_RETRY_DELAYS_MS = [500, 1_000, 2_000];\n\n/** Backoff cap (ms) for the daemon's infinite retry path. */\nconst DAEMON_RETRY_CAP_MS = 15_000;\n\n/**\n * Create and return the configured StorageBackend.\n *\n * Auto-behaviour:\n * - storageBackend = \"sqlite\" → SQLiteBackend always\n * - storageBackend = \"postgres\" → PostgresBackend (retried; never falls back)\n */\nexport async function createStorageBackend(\n config: PaiDaemonConfig,\n opts: StorageBackendOptions = {}\n): Promise<StorageBackend> {\n if (config.storageBackend === \"postgres\") {\n return await connectPostgres(config, opts.waitForPostgres ?? false);\n }\n\n // Default: SQLite\n return createSQLiteBackend();\n}\n\n/**\n * Attempt a single Postgres connection (ensure DB + test). Returns the live\n * backend on success, or an error string describing why it failed.\n */\nasync function attemptPostgres(\n config: PaiDaemonConfig\n): Promise<{ backend: StorageBackend } | { error: string }> {\n const { PostgresBackend } = await import(\"./postgres.js\");\n const pgConfig = config.postgres ?? {};\n\n let backend: InstanceType<typeof PostgresBackend> | null = null;\n try {\n // Ensure the per-user database exists and has the schema applied.\n await PostgresBackend.ensureDatabase(pgConfig);\n\n backend = new PostgresBackend(pgConfig);\n const err = await backend.testConnection();\n if (err) {\n await backend.close().catch(() => {});\n return { error: err };\n }\n return { backend };\n } catch (e) {\n if (backend) await backend.close().catch(() => {});\n return { error: e instanceof Error ? e.message : String(e) };\n }\n}\n\nasync function connectPostgres(\n config: PaiDaemonConfig,\n waitForever: boolean\n): Promise<StorageBackend> {\n let attempt = 0;\n let lastError = \"unknown error\";\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n attempt++;\n const result = await attemptPostgres(config);\n if (\"backend\" in result) {\n if (attempt > 1) {\n process.stderr.write(\n `[pai-daemon] Connected to PostgreSQL backend (after ${attempt} attempts).\\n`\n );\n } else {\n process.stderr.write(\"[pai-daemon] Connected to PostgreSQL backend.\\n\");\n }\n return result.backend;\n }\n\n lastError = result.error;\n\n if (!waitForever && attempt > CLI_RETRY_DELAYS_MS.length) {\n // Bounded CLI path exhausted — fail loudly, never silently use SQLite.\n throw new Error(\n `Postgres backend unreachable after ${attempt} attempts: ${lastError}. ` +\n `Is Docker Desktop / Postgres running? Refusing to fall back to SQLite ` +\n `(would split the corpus). Start Postgres and retry.`\n );\n }\n\n const delayMs = waitForever\n ? Math.min(DAEMON_RETRY_CAP_MS, 1_000 * 2 ** Math.min(attempt - 1, 4))\n : CLI_RETRY_DELAYS_MS[attempt - 1];\n\n process.stderr.write(\n `[pai-daemon] Postgres unavailable (${lastError}). ` +\n `Retry ${attempt}${waitForever ? \"\" : `/${CLI_RETRY_DELAYS_MS.length + 1}`} ` +\n `in ${delayMs}ms...\\n`\n );\n await new Promise((r) => setTimeout(r, delayMs));\n }\n}\n\nasync function createSQLiteBackend(): Promise<StorageBackend> {\n const { openFederation } = await import(\"../memory/db.js\");\n const { SQLiteBackend } = await import(\"./sqlite.js\");\n const db = openFederation();\n return new SQLiteBackend(db);\n}\n"],"mappings":";;;;;AA2BA,MAAM,sBAAsB;CAAC;CAAK;CAAO;CAAM;;AAG/C,MAAM,sBAAsB;;;;;;;;AAS5B,eAAsB,qBACpB,QACA,OAA8B,EAAE,EACP;AACzB,KAAI,OAAO,mBAAmB,WAC5B,QAAO,MAAM,gBAAgB,QAAQ,KAAK,mBAAmB,MAAM;AAIrE,QAAO,qBAAqB;;;;;;AAO9B,eAAe,gBACb,QAC0D;CAC1D,MAAM,EAAE,oBAAoB,MAAM,OAAO;CACzC,MAAM,WAAW,OAAO,YAAY,EAAE;CAEtC,IAAI,UAAuD;AAC3D,KAAI;AAEF,QAAM,gBAAgB,eAAe,SAAS;AAE9C,YAAU,IAAI,gBAAgB,SAAS;EACvC,MAAM,MAAM,MAAM,QAAQ,gBAAgB;AAC1C,MAAI,KAAK;AACP,SAAM,QAAQ,OAAO,CAAC,YAAY,GAAG;AACrC,UAAO,EAAE,OAAO,KAAK;;AAEvB,SAAO,EAAE,SAAS;UACX,GAAG;AACV,MAAI,QAAS,OAAM,QAAQ,OAAO,CAAC,YAAY,GAAG;AAClD,SAAO,EAAE,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,EAAE;;;AAIhE,eAAe,gBACb,QACA,aACyB;CACzB,IAAI,UAAU;CACd,IAAI,YAAY;AAGhB,QAAO,MAAM;AACX;EACA,MAAM,SAAS,MAAM,gBAAgB,OAAO;AAC5C,MAAI,aAAa,QAAQ;AACvB,OAAI,UAAU,EACZ,SAAQ,OAAO,MACb,uDAAuD,QAAQ,eAChE;OAED,SAAQ,OAAO,MAAM,kDAAkD;AAEzE,UAAO,OAAO;;AAGhB,cAAY,OAAO;AAEnB,MAAI,CAAC,eAAe,UAAU,oBAAoB,OAEhD,OAAM,IAAI,MACR,sCAAsC,QAAQ,aAAa,UAAU,6HAGtE;EAGH,MAAM,UAAU,cACZ,KAAK,IAAI,qBAAqB,MAAQ,KAAK,KAAK,IAAI,UAAU,GAAG,EAAE,CAAC,GACpE,oBAAoB,UAAU;AAElC,UAAQ,OAAO,MACb,sCAAsC,UAAU,WACrC,UAAU,cAAc,KAAK,IAAI,oBAAoB,SAAS,IAAI,MACrE,QAAQ,SACjB;AACD,QAAM,IAAI,SAAS,MAAM,WAAW,GAAG,QAAQ,CAAC;;;AAIpD,eAAe,sBAA+C;CAC5D,MAAM,EAAE,mBAAmB,MAAM,OAAO;CACxC,MAAM,EAAE,kBAAkB,MAAM,OAAO;AAEvC,QAAO,IAAI,cADA,gBAAgB,CACC"}
|
|
@@ -490,13 +490,13 @@ var BOILERPLATE_PATTERNS = [
|
|
|
490
490
|
/^>\s*Working directory:/,
|
|
491
491
|
/^>\s*Resume with:/,
|
|
492
492
|
/^>\s*_No checkpoint body was recorded/,
|
|
493
|
-
/^>?\s*$/,
|
|
494
493
|
/^-{3,}$/
|
|
495
494
|
];
|
|
495
|
+
var BLANK_LINE = /^>?\s*$/;
|
|
496
496
|
function isBoilerplateOnly(lines) {
|
|
497
497
|
return lines.every((line) => {
|
|
498
498
|
const t = line.trim();
|
|
499
|
-
return BOILERPLATE_PATTERNS.some((re) => re.test(t));
|
|
499
|
+
return BLANK_LINE.test(t) || BOILERPLATE_PATTERNS.some((re) => re.test(t));
|
|
500
500
|
});
|
|
501
501
|
}
|
|
502
502
|
function extractSectionContent(lines) {
|
|
@@ -506,7 +506,25 @@ function extractSectionContent(lines) {
|
|
|
506
506
|
if (BOILERPLATE_PATTERNS.some((re) => re.test(t))) continue;
|
|
507
507
|
kept.push(line);
|
|
508
508
|
}
|
|
509
|
-
return kept.join("\n")
|
|
509
|
+
return trimBlankEdges(collapseBlankRuns(kept)).join("\n");
|
|
510
|
+
}
|
|
511
|
+
function trimBlankEdges(lines) {
|
|
512
|
+
let start = 0;
|
|
513
|
+
let end = lines.length;
|
|
514
|
+
while (start < end && BLANK_LINE.test(lines[start].trim())) start += 1;
|
|
515
|
+
while (end > start && BLANK_LINE.test(lines[end - 1].trim())) end -= 1;
|
|
516
|
+
return lines.slice(start, end);
|
|
517
|
+
}
|
|
518
|
+
function collapseBlankRuns(lines) {
|
|
519
|
+
const out = [];
|
|
520
|
+
let lastWasBlank = false;
|
|
521
|
+
for (const line of lines) {
|
|
522
|
+
const isBlank = BLANK_LINE.test(line.trim());
|
|
523
|
+
if (isBlank && lastWasBlank) continue;
|
|
524
|
+
out.push(line);
|
|
525
|
+
lastWasBlank = isBlank;
|
|
526
|
+
}
|
|
527
|
+
return out;
|
|
510
528
|
}
|
|
511
529
|
function locateContinue(content) {
|
|
512
530
|
const lines = content.split("\n");
|
|
@@ -609,6 +627,12 @@ function buildContinueBlock(opts) {
|
|
|
609
627
|
parts.push("", MARKER_CLOSE, "", "---", "");
|
|
610
628
|
return parts.join("\n");
|
|
611
629
|
}
|
|
630
|
+
function isSameSession(meta, opts) {
|
|
631
|
+
if (meta.sessionId && opts.sessionId) {
|
|
632
|
+
return meta.sessionId === opts.sessionId;
|
|
633
|
+
}
|
|
634
|
+
return meta.session === opts.sessionLine;
|
|
635
|
+
}
|
|
612
636
|
function applyContinue(opts) {
|
|
613
637
|
const target = resolveTodoTarget(opts.rootPath, { create: !opts.dryRun });
|
|
614
638
|
if (!target) {
|
|
@@ -623,7 +647,7 @@ function applyContinue(opts) {
|
|
|
623
647
|
let carriedForward = false;
|
|
624
648
|
let effectiveBody = opts.body;
|
|
625
649
|
if (opts.authored === "auto" && existing) {
|
|
626
|
-
if (existing.meta?.authored === "model" && existing.meta
|
|
650
|
+
if (existing.meta?.authored === "model" && isSameSession(existing.meta, opts)) {
|
|
627
651
|
return {
|
|
628
652
|
action: "preserved",
|
|
629
653
|
path: target.path,
|
|
@@ -631,6 +655,14 @@ function applyContinue(opts) {
|
|
|
631
655
|
preservedMeta: existing.meta
|
|
632
656
|
};
|
|
633
657
|
}
|
|
658
|
+
if (existing.meta && !(opts.body ?? "").trim() && !isBoilerplateOnly(existing.lines)) {
|
|
659
|
+
return {
|
|
660
|
+
action: "preserved",
|
|
661
|
+
path: target.path,
|
|
662
|
+
block: buildContinueBlock(opts),
|
|
663
|
+
preservedMeta: existing.meta ?? void 0
|
|
664
|
+
};
|
|
665
|
+
}
|
|
634
666
|
if (!existing.meta && !isBoilerplateOnly(existing.lines)) {
|
|
635
667
|
const salvaged = extractSectionContent(existing.lines);
|
|
636
668
|
if (salvaged) {
|