@chendpoc/pi-memory 0.1.11 → 0.1.13
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 +88 -16
- package/dist/cache/memoryCaches.d.ts +32 -0
- package/dist/cache/memoryCaches.d.ts.map +1 -0
- package/dist/cache/memoryCaches.js +59 -0
- package/dist/cache/memoryCaches.js.map +1 -0
- package/dist/cli.js +123 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +37 -1
- package/dist/config.js.map +1 -1
- package/dist/consolidation/enqueue.d.ts +33 -0
- package/dist/consolidation/enqueue.d.ts.map +1 -0
- package/dist/consolidation/enqueue.js +145 -0
- package/dist/consolidation/enqueue.js.map +1 -0
- package/dist/consolidation/index.d.ts +19 -0
- package/dist/consolidation/index.d.ts.map +1 -0
- package/dist/consolidation/index.js +15 -0
- package/dist/consolidation/index.js.map +1 -0
- package/dist/consolidation/lock.d.ts +5 -0
- package/dist/consolidation/lock.d.ts.map +1 -0
- package/dist/consolidation/lock.js +33 -0
- package/dist/consolidation/lock.js.map +1 -0
- package/dist/consolidation/log.d.ts +8 -0
- package/dist/consolidation/log.d.ts.map +1 -0
- package/dist/consolidation/log.js +32 -0
- package/dist/consolidation/log.js.map +1 -0
- package/dist/consolidation/memoryIndex.d.ts +18 -0
- package/dist/consolidation/memoryIndex.d.ts.map +1 -0
- package/dist/consolidation/memoryIndex.js +100 -0
- package/dist/consolidation/memoryIndex.js.map +1 -0
- package/dist/consolidation/phase2/runPhase2.d.ts +23 -0
- package/dist/consolidation/phase2/runPhase2.d.ts.map +1 -0
- package/dist/consolidation/phase2/runPhase2.js +196 -0
- package/dist/consolidation/phase2/runPhase2.js.map +1 -0
- package/dist/consolidation/scheduler/launchd.d.ts +5 -0
- package/dist/consolidation/scheduler/launchd.d.ts.map +1 -0
- package/dist/consolidation/scheduler/launchd.js +54 -0
- package/dist/consolidation/scheduler/launchd.js.map +1 -0
- package/dist/consolidation/scheduler/runConsolidate.d.ts +26 -0
- package/dist/consolidation/scheduler/runConsolidate.d.ts.map +1 -0
- package/dist/consolidation/scheduler/runConsolidate.js +83 -0
- package/dist/consolidation/scheduler/runConsolidate.js.map +1 -0
- package/dist/consolidation/scheduler/setupSchedule.d.ts +3 -0
- package/dist/consolidation/scheduler/setupSchedule.d.ts.map +1 -0
- package/dist/consolidation/scheduler/setupSchedule.js +79 -0
- package/dist/consolidation/scheduler/setupSchedule.js.map +1 -0
- package/dist/consolidation/scheduler/systemd.d.ts +9 -0
- package/dist/consolidation/scheduler/systemd.d.ts.map +1 -0
- package/dist/consolidation/scheduler/systemd.js +57 -0
- package/dist/consolidation/scheduler/systemd.js.map +1 -0
- package/dist/consolidation/scheduler/types.d.ts +24 -0
- package/dist/consolidation/scheduler/types.d.ts.map +1 -0
- package/dist/consolidation/scheduler/types.js +2 -0
- package/dist/consolidation/scheduler/types.js.map +1 -0
- package/dist/consolidation/scope.d.ts +12 -0
- package/dist/consolidation/scope.d.ts.map +1 -0
- package/dist/consolidation/scope.js +51 -0
- package/dist/consolidation/scope.js.map +1 -0
- package/dist/consolidation/stage1/deltaExtract.d.ts +3 -0
- package/dist/consolidation/stage1/deltaExtract.d.ts.map +1 -0
- package/dist/consolidation/stage1/deltaExtract.js +19 -0
- package/dist/consolidation/stage1/deltaExtract.js.map +1 -0
- package/dist/consolidation/stage1/drainQueue.d.ts +21 -0
- package/dist/consolidation/stage1/drainQueue.d.ts.map +1 -0
- package/dist/consolidation/stage1/drainQueue.js +113 -0
- package/dist/consolidation/stage1/drainQueue.js.map +1 -0
- package/dist/consolidation/stage1/extractSession.d.ts +6 -0
- package/dist/consolidation/stage1/extractSession.d.ts.map +1 -0
- package/dist/consolidation/stage1/extractSession.js +47 -0
- package/dist/consolidation/stage1/extractSession.js.map +1 -0
- package/dist/consolidation/stage1/store.d.ts +45 -0
- package/dist/consolidation/stage1/store.d.ts.map +1 -0
- package/dist/consolidation/stage1/store.js +297 -0
- package/dist/consolidation/stage1/store.js.map +1 -0
- package/dist/consolidation/types.d.ts +49 -0
- package/dist/consolidation/types.d.ts.map +1 -0
- package/dist/consolidation/types.js +2 -0
- package/dist/consolidation/types.js.map +1 -0
- package/dist/fallback/llmRerank.d.ts.map +1 -1
- package/dist/fallback/llmRerank.js +9 -1
- package/dist/fallback/llmRerank.js.map +1 -1
- package/dist/fallback/sessionIndex.d.ts.map +1 -1
- package/dist/fallback/sessionIndex.js +15 -63
- package/dist/fallback/sessionIndex.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/local/graphQuery.d.ts +10 -0
- package/dist/local/graphQuery.d.ts.map +1 -1
- package/dist/local/graphQuery.js +25 -0
- package/dist/local/graphQuery.js.map +1 -1
- package/dist/pi-extension.d.ts.map +1 -1
- package/dist/pi-extension.js +356 -22
- package/dist/pi-extension.js.map +1 -1
- package/dist/preflight/detectIntents.d.ts.map +1 -1
- package/dist/preflight/detectIntents.js +7 -0
- package/dist/preflight/detectIntents.js.map +1 -1
- package/dist/preflight/hook.d.ts +18 -0
- package/dist/preflight/hook.d.ts.map +1 -1
- package/dist/preflight/hook.js +52 -7
- package/dist/preflight/hook.js.map +1 -1
- package/dist/preflight/render.d.ts +16 -2
- package/dist/preflight/render.d.ts.map +1 -1
- package/dist/preflight/render.js +24 -4
- package/dist/preflight/render.js.map +1 -1
- package/dist/service.d.ts +16 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +57 -0
- package/dist/service.js.map +1 -1
- package/dist/session/activeBranch.d.ts +17 -0
- package/dist/session/activeBranch.d.ts.map +1 -0
- package/dist/session/activeBranch.js +251 -0
- package/dist/session/activeBranch.js.map +1 -0
- package/dist/settings.d.ts +5 -2
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +18 -1
- package/dist/settings.js.map +1 -1
- package/dist/tools/memoryAppend.d.ts +14 -4
- package/dist/tools/memoryAppend.d.ts.map +1 -1
- package/dist/tools/memoryAppend.js +46 -7
- package/dist/tools/memoryAppend.js.map +1 -1
- package/dist/tools/memoryRecall.d.ts +2 -2
- package/dist/tools/memoryRecall.d.ts.map +1 -1
- package/dist/tools/memoryRecall.js +35 -9
- package/dist/tools/memoryRecall.js.map +1 -1
- package/dist/trainer/extractFacts.d.ts +1 -1
- package/dist/trainer/index.d.ts +1 -1
- package/dist/trainer/index.d.ts.map +1 -1
- package/dist/trainer/index.js +1 -1
- package/dist/trainer/index.js.map +1 -1
- package/dist/trainer/scheduler.d.ts +2 -0
- package/dist/trainer/scheduler.d.ts.map +1 -1
- package/dist/trainer/scheduler.js +1 -0
- package/dist/trainer/scheduler.js.map +1 -1
- package/dist/trainer/sessionLoader.d.ts +3 -0
- package/dist/trainer/sessionLoader.d.ts.map +1 -1
- package/dist/trainer/sessionLoader.js +37 -74
- package/dist/trainer/sessionLoader.js.map +1 -1
- package/package.json +17 -4
- package/src/cache/memoryCaches.ts +72 -0
- package/src/cli.ts +144 -0
- package/src/config.ts +89 -1
- package/src/consolidation/enqueue.ts +205 -0
- package/src/consolidation/index.ts +90 -0
- package/src/consolidation/lock.ts +41 -0
- package/src/consolidation/log.ts +43 -0
- package/src/consolidation/memoryIndex.ts +127 -0
- package/src/consolidation/phase2/runPhase2.ts +255 -0
- package/src/consolidation/scheduler/launchd.ts +62 -0
- package/src/consolidation/scheduler/runConsolidate.ts +115 -0
- package/src/consolidation/scheduler/setupSchedule.ts +106 -0
- package/src/consolidation/scheduler/systemd.ts +78 -0
- package/src/consolidation/scheduler/types.ts +27 -0
- package/src/consolidation/scope.ts +58 -0
- package/src/consolidation/stage1/deltaExtract.ts +29 -0
- package/src/consolidation/stage1/drainQueue.ts +143 -0
- package/src/consolidation/stage1/extractSession.ts +58 -0
- package/src/consolidation/stage1/store.ts +411 -0
- package/src/consolidation/types.ts +52 -0
- package/src/fallback/llmRerank.ts +8 -1
- package/src/fallback/sessionIndex.ts +14 -51
- package/src/index.ts +8 -0
- package/src/local/graphQuery.ts +24 -0
- package/src/pi-extension.ts +393 -28
- package/src/preflight/detectIntents.ts +6 -0
- package/src/preflight/hook.ts +84 -7
- package/src/preflight/render.ts +35 -3
- package/src/service.ts +57 -0
- package/src/session/activeBranch.ts +294 -0
- package/src/settings.ts +37 -2
- package/src/tools/memoryAppend.ts +60 -7
- package/src/tools/memoryRecall.ts +33 -9
- package/src/trainer/index.ts +1 -1
- package/src/trainer/scheduler.ts +3 -0
- package/src/trainer/sessionLoader.ts +38 -87
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const SCOPE_RE = /<!--\s*scope:([^>\s]+)\s*-->/;
|
|
5
|
+
export function projectHash(input) {
|
|
6
|
+
return createHash("sha256").update(input).digest("hex").slice(0, 12);
|
|
7
|
+
}
|
|
8
|
+
export function projectScope(projectHashValue) {
|
|
9
|
+
return projectHashValue ? `project:${projectHashValue}` : "global";
|
|
10
|
+
}
|
|
11
|
+
export function parseScopeComment(line) {
|
|
12
|
+
const raw = line.match(SCOPE_RE)?.[1]?.trim();
|
|
13
|
+
if (!raw)
|
|
14
|
+
return null;
|
|
15
|
+
if (raw === "global")
|
|
16
|
+
return "global";
|
|
17
|
+
if (/^project:[a-f0-9]{12}$/i.test(raw))
|
|
18
|
+
return raw;
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
export function lineMatchesScope(line, allowedScopes) {
|
|
22
|
+
if (!allowedScopes || allowedScopes.length === 0)
|
|
23
|
+
return true;
|
|
24
|
+
const scope = parseScopeComment(line);
|
|
25
|
+
if (!scope)
|
|
26
|
+
return true;
|
|
27
|
+
return allowedScopes.includes(scope);
|
|
28
|
+
}
|
|
29
|
+
export function findGitRoot(startDir) {
|
|
30
|
+
if (!startDir)
|
|
31
|
+
return null;
|
|
32
|
+
let current = path.resolve(startDir);
|
|
33
|
+
for (;;) {
|
|
34
|
+
if (fs.existsSync(path.join(current, ".git")))
|
|
35
|
+
return current;
|
|
36
|
+
const parent = path.dirname(current);
|
|
37
|
+
if (parent === current)
|
|
38
|
+
return null;
|
|
39
|
+
current = parent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function scopeForCwd(cwd) {
|
|
43
|
+
const gitRoot = findGitRoot(cwd);
|
|
44
|
+
const hash = gitRoot ? projectHash(gitRoot) : null;
|
|
45
|
+
return {
|
|
46
|
+
gitRoot,
|
|
47
|
+
projectHash: hash,
|
|
48
|
+
scopes: hash ? ["global", `project:${hash}`] : ["global"],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/consolidation/scope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,QAAQ,GAAG,8BAA8B,CAAC;AAEhD,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,gBAA2C;IACtE,OAAO,gBAAgB,CAAC,CAAC,CAAC,WAAW,gBAAgB,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC9C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACtC,IAAI,yBAAyB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,GAAkB,CAAC;IACnE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,aAAiD;IAEjD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9D,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAmC;IAC7D,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrC,SAAS,CAAC;QACR,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,IAAI,CAAC;QACpC,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAA8B;IAKxD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,OAAO;QACL,OAAO;QACP,WAAW,EAAE,IAAI;QACjB,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;KAC1D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deltaExtract.d.ts","sourceRoot":"","sources":["../../../src/consolidation/stage1/deltaExtract.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAQlE,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,WAAW,EAAE,EAC1B,UAAU,EAAE,WAAW,EAAE,GACxB,WAAW,EAAE,CAef"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
function turnHash(turn) {
|
|
3
|
+
return createHash("sha256")
|
|
4
|
+
.update(`${turn.role}\0${turn.content}`)
|
|
5
|
+
.digest("hex");
|
|
6
|
+
}
|
|
7
|
+
export function computeDeltaTurns(parentTurns, childTurns) {
|
|
8
|
+
let forkIndex = 0;
|
|
9
|
+
for (; forkIndex < parentTurns.length && forkIndex < childTurns.length; forkIndex++) {
|
|
10
|
+
if (turnHash(parentTurns[forkIndex]) !== turnHash(childTurns[forkIndex])) {
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return childTurns.slice(forkIndex).map((turn, idx) => ({
|
|
15
|
+
...turn,
|
|
16
|
+
turnIndex: idx,
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=deltaExtract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deltaExtract.js","sourceRoot":"","sources":["../../../src/consolidation/stage1/deltaExtract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,SAAS,QAAQ,CAAC,IAAiB;IACjC,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;SACvC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,WAA0B,EAC1B,UAAyB;IAEzB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAEE,SAAS,GAAG,WAAW,CAAC,MAAM,IAAI,SAAS,GAAG,UAAU,CAAC,MAAM,EAC/D,SAAS,EAAE,EACX,CAAC;QACD,IAAI,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAE,CAAC,KAAK,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAE,CAAC,EAAE,CAAC;YAC3E,MAAM;QACR,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACrD,GAAG,IAAI;QACP,SAAS,EAAE,GAAG;KACf,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ConsolidationStore } from "./store.js";
|
|
2
|
+
export interface DrainQueueOptions {
|
|
3
|
+
limit?: number;
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
now?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DrainQueueReport {
|
|
8
|
+
sessionsProcessed: number;
|
|
9
|
+
sessionsSkipped: number;
|
|
10
|
+
sessionsFailed: number;
|
|
11
|
+
stage1NewRows: number;
|
|
12
|
+
dryRun: boolean;
|
|
13
|
+
details: Array<{
|
|
14
|
+
session_id: string;
|
|
15
|
+
status: "processed" | "skipped" | "failed";
|
|
16
|
+
reason?: string;
|
|
17
|
+
delta_turns?: number;
|
|
18
|
+
}>;
|
|
19
|
+
}
|
|
20
|
+
export declare function drainQueue(store: ConsolidationStore, opts?: DrainQueueOptions): Promise<DrainQueueReport>;
|
|
21
|
+
//# sourceMappingURL=drainQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drainQueue.d.ts","sourceRoot":"","sources":["../../../src/consolidation/stage1/drainQueue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAMrD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,KAAK,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;QAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ;AA+CD,wBAAsB,UAAU,CAC9B,KAAK,EAAE,kBAAkB,EACzB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAoE3B"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { computeDeltaTurns } from "./deltaExtract.js";
|
|
2
|
+
import { extractSessionToStage1 } from "./extractSession.js";
|
|
3
|
+
import { loadSessionFile } from "../../trainer/sessionLoader.js";
|
|
4
|
+
function topoSortPending(sessions) {
|
|
5
|
+
const byId = new Map(sessions.map((session) => [session.session_id, session]));
|
|
6
|
+
const visited = new Set();
|
|
7
|
+
const visiting = new Set();
|
|
8
|
+
const out = [];
|
|
9
|
+
function visit(session) {
|
|
10
|
+
if (visited.has(session.session_id))
|
|
11
|
+
return;
|
|
12
|
+
if (visiting.has(session.session_id)) {
|
|
13
|
+
out.push(session);
|
|
14
|
+
visited.add(session.session_id);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
visiting.add(session.session_id);
|
|
18
|
+
const parent = session.parent_session_id
|
|
19
|
+
? byId.get(session.parent_session_id)
|
|
20
|
+
: undefined;
|
|
21
|
+
if (parent)
|
|
22
|
+
visit(parent);
|
|
23
|
+
visiting.delete(session.session_id);
|
|
24
|
+
visited.add(session.session_id);
|
|
25
|
+
out.push(session);
|
|
26
|
+
}
|
|
27
|
+
for (const session of sessions)
|
|
28
|
+
visit(session);
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
async function loadTurns(filePath) {
|
|
32
|
+
const session = await loadSessionFile(filePath);
|
|
33
|
+
return session?.turns ?? null;
|
|
34
|
+
}
|
|
35
|
+
async function turnsForExtraction(pending) {
|
|
36
|
+
const childTurns = await loadTurns(pending.session_file);
|
|
37
|
+
if (!childTurns)
|
|
38
|
+
return null;
|
|
39
|
+
if (!pending.parent_session_file) {
|
|
40
|
+
return { turns: childTurns, delta: false };
|
|
41
|
+
}
|
|
42
|
+
const parentTurns = await loadTurns(pending.parent_session_file).catch(() => null);
|
|
43
|
+
if (!parentTurns)
|
|
44
|
+
return { turns: childTurns, delta: false };
|
|
45
|
+
return { turns: computeDeltaTurns(parentTurns, childTurns), delta: true };
|
|
46
|
+
}
|
|
47
|
+
export async function drainQueue(store, opts = {}) {
|
|
48
|
+
const dryRun = opts.dryRun ?? false;
|
|
49
|
+
const pending = topoSortPending(store.listPendingSessions(opts.limit ?? 100));
|
|
50
|
+
const report = {
|
|
51
|
+
sessionsProcessed: 0,
|
|
52
|
+
sessionsSkipped: 0,
|
|
53
|
+
sessionsFailed: 0,
|
|
54
|
+
stage1NewRows: 0,
|
|
55
|
+
dryRun,
|
|
56
|
+
details: [],
|
|
57
|
+
};
|
|
58
|
+
for (const session of pending) {
|
|
59
|
+
try {
|
|
60
|
+
const loaded = await turnsForExtraction(session);
|
|
61
|
+
if (!loaded) {
|
|
62
|
+
report.sessionsSkipped++;
|
|
63
|
+
report.details.push({
|
|
64
|
+
session_id: session.session_id,
|
|
65
|
+
status: "skipped",
|
|
66
|
+
reason: "session_unreadable",
|
|
67
|
+
});
|
|
68
|
+
if (!dryRun)
|
|
69
|
+
store.setPendingSessionStatus(session.session_id, "skipped");
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (loaded.delta && loaded.turns.length === 0) {
|
|
73
|
+
report.sessionsSkipped++;
|
|
74
|
+
report.details.push({
|
|
75
|
+
session_id: session.session_id,
|
|
76
|
+
status: "skipped",
|
|
77
|
+
reason: "clone_no_delta",
|
|
78
|
+
delta_turns: 0,
|
|
79
|
+
});
|
|
80
|
+
if (!dryRun)
|
|
81
|
+
store.setPendingSessionStatus(session.session_id, "skipped");
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const output = await extractSessionToStage1(session, loaded.turns, {
|
|
85
|
+
now: opts.now,
|
|
86
|
+
});
|
|
87
|
+
report.sessionsProcessed++;
|
|
88
|
+
report.stage1NewRows++;
|
|
89
|
+
report.details.push({
|
|
90
|
+
session_id: session.session_id,
|
|
91
|
+
status: "processed",
|
|
92
|
+
delta_turns: loaded.turns.length,
|
|
93
|
+
});
|
|
94
|
+
if (!dryRun) {
|
|
95
|
+
store.upsertStage1Output(output);
|
|
96
|
+
store.setPendingSessionStatus(session.session_id, output.status === "skipped" ? "skipped" : "done");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
report.sessionsFailed++;
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
report.details.push({
|
|
103
|
+
session_id: session.session_id,
|
|
104
|
+
status: "failed",
|
|
105
|
+
reason: message,
|
|
106
|
+
});
|
|
107
|
+
if (!dryRun)
|
|
108
|
+
store.setPendingSessionStatus(session.session_id, "failed", message);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return report;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=drainQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drainQueue.js","sourceRoot":"","sources":["../../../src/consolidation/stage1/drainQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PendingSession, Stage1Output } from "../types.js";
|
|
2
|
+
import type { SessionTurn } from "../../trainer/sessionLoader.js";
|
|
3
|
+
export declare function extractSessionToStage1(pending: PendingSession, turns: SessionTurn[], opts?: {
|
|
4
|
+
now?: string;
|
|
5
|
+
}): Promise<Stage1Output>;
|
|
6
|
+
//# sourceMappingURL=extractSession.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractSession.d.ts","sourceRoot":"","sources":["../../../src/consolidation/stage1/extractSession.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AA4BlE,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,WAAW,EAAE,EACpB,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1B,OAAO,CAAC,YAAY,CAAC,CAqBvB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { projectScope } from "../scope.js";
|
|
3
|
+
const OPERATING_SIGNAL_RE = /\b(prefer|preference|always|default|remember|convention|build command|test command)\b|(?:偏好|默认|以后|记住|约定|构建|测试命令)/i;
|
|
4
|
+
function cleanLine(text) {
|
|
5
|
+
return text.replace(/\s+/g, " ").trim();
|
|
6
|
+
}
|
|
7
|
+
function summarizeTurns(turns, max = 4) {
|
|
8
|
+
return turns
|
|
9
|
+
.filter((turn) => turn.role === "user" || turn.role === "assistant")
|
|
10
|
+
.slice(0, max)
|
|
11
|
+
.map((turn) => `- ${turn.role}: ${cleanLine(turn.content).slice(0, 240)}`)
|
|
12
|
+
.join("\n");
|
|
13
|
+
}
|
|
14
|
+
function extractOperatingLines(turns) {
|
|
15
|
+
const lines = [];
|
|
16
|
+
for (const turn of turns) {
|
|
17
|
+
if (turn.role !== "user")
|
|
18
|
+
continue;
|
|
19
|
+
const text = cleanLine(turn.content);
|
|
20
|
+
if (!OPERATING_SIGNAL_RE.test(text))
|
|
21
|
+
continue;
|
|
22
|
+
lines.push(`- ${text}`);
|
|
23
|
+
}
|
|
24
|
+
return lines.join("\n");
|
|
25
|
+
}
|
|
26
|
+
export async function extractSessionToStage1(pending, turns, opts = {}) {
|
|
27
|
+
const generatedAt = opts.now ?? new Date().toISOString();
|
|
28
|
+
const stat = await fs.stat(pending.session_file);
|
|
29
|
+
const rawMemory = extractOperatingLines(turns);
|
|
30
|
+
const rolloutSummary = summarizeTurns(turns);
|
|
31
|
+
const hasOutput = rawMemory.trim() || rolloutSummary.trim();
|
|
32
|
+
return {
|
|
33
|
+
session_id: pending.session_id,
|
|
34
|
+
session_file: pending.session_file,
|
|
35
|
+
source_mtime_ms: Math.trunc(stat.mtimeMs),
|
|
36
|
+
generated_at: generatedAt,
|
|
37
|
+
raw_memory: rawMemory.trim(),
|
|
38
|
+
rollout_summary: rolloutSummary.trim(),
|
|
39
|
+
scope: projectScope(pending.project_hash),
|
|
40
|
+
status: hasOutput ? "done" : "skipped",
|
|
41
|
+
selected_for_phase2: false,
|
|
42
|
+
usage_count: 0,
|
|
43
|
+
last_usage: generatedAt,
|
|
44
|
+
error_message: null,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=extractSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractSession.js","sourceRoot":"","sources":["../../../src/consolidation/stage1/extractSession.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,mBAAmB,GACvB,mHAAmH,CAAC;AAEtH,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,cAAc,CAAC,KAAoB,EAAE,GAAG,GAAG,CAAC;IACnD,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;SACnE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;SACb,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;SACzE,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAoB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,SAAS;QACnC,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,OAAuB,EACvB,KAAoB,EACpB,OAAyB,EAAE;IAE3B,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACzD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACjD,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,cAAc,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,cAAc,CAAC,IAAI,EAAE,CAAC;IAE5D,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;QACzC,YAAY,EAAE,WAAW;QACzB,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE;QAC5B,eAAe,EAAE,cAAc,CAAC,IAAI,EAAE;QACtC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC;QACzC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QACtC,mBAAmB,EAAE,KAAK;QAC1B,WAAW,EAAE,CAAC;QACd,UAAU,EAAE,WAAW;QACvB,aAAa,EAAE,IAAI;KACpB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { PendingSession, Stage1Output, ConsolidationStatus } from "../types.js";
|
|
2
|
+
export interface SqliteDatabase {
|
|
3
|
+
pragma(sql: string): unknown;
|
|
4
|
+
exec(sql: string): void;
|
|
5
|
+
prepare(sql: string): {
|
|
6
|
+
run(...args: unknown[]): unknown;
|
|
7
|
+
get(...args: unknown[]): unknown;
|
|
8
|
+
all(...args: unknown[]): unknown[];
|
|
9
|
+
};
|
|
10
|
+
transaction<T>(fn: () => T): () => T;
|
|
11
|
+
close(): void;
|
|
12
|
+
}
|
|
13
|
+
export interface ConsolidationStore {
|
|
14
|
+
upsertPendingSession(session: Omit<PendingSession, "created_at" | "updated_at"> & {
|
|
15
|
+
created_at: string;
|
|
16
|
+
updated_at: string;
|
|
17
|
+
}): PendingSession;
|
|
18
|
+
upsertStage1Output(output: Stage1Output): void;
|
|
19
|
+
getPendingSession(sessionId: string): PendingSession | null;
|
|
20
|
+
listPendingSessions(limit?: number): PendingSession[];
|
|
21
|
+
setPendingSessionStatus(sessionId: string, status: ConsolidationStatus, errorMessage?: string | null, updatedAt?: string): void;
|
|
22
|
+
getStage1Output(sessionId: string): Stage1Output | null;
|
|
23
|
+
listUnselectedStage1(limit: number): Stage1Output[];
|
|
24
|
+
listStage1OlderThan(cutoffIso: string, limit?: number): Stage1Output[];
|
|
25
|
+
markStage1Selected(sessionIds: string[]): void;
|
|
26
|
+
incrementStage1Usage(sessionId: string, usedAt?: string): void;
|
|
27
|
+
countPendingSessions(): number;
|
|
28
|
+
getConsolidationStatusCounts(): {
|
|
29
|
+
pending: number;
|
|
30
|
+
processing: number;
|
|
31
|
+
done: number;
|
|
32
|
+
skipped: number;
|
|
33
|
+
failed: number;
|
|
34
|
+
};
|
|
35
|
+
getStage1Count(): number;
|
|
36
|
+
getLastGeneratedAt(): string | null;
|
|
37
|
+
getLastUpdatedAt(): string | null;
|
|
38
|
+
close(): void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Lazy-open a sqlite database and ensure the consolidation schema exists.
|
|
42
|
+
* Returns null when better-sqlite3 is unavailable and no injected DB is provided.
|
|
43
|
+
*/
|
|
44
|
+
export declare function openConsolidationStore(dbPath: string, injectedDb?: SqliteDatabase): ConsolidationStore | null;
|
|
45
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/consolidation/stage1/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QACpB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACjC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACjC,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;KACpC,CAAC;IACF,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;IACrC,KAAK,IAAI,IAAI,CAAC;CACf;AA6GD,MAAM,WAAW,kBAAkB;IACjC,oBAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,GAAG,YAAY,CAAC,GAAG;QAChF,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,cAAc,CAAC;IACnB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC/C,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAC;IAC5D,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE,CAAC;IACtD,uBAAuB,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,mBAAmB,EAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CAAC;IACR,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;IACxD,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;IACpD,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;IACvE,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/C,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,oBAAoB,IAAI,MAAM,CAAC;IAC/B,4BAA4B,IAAI;QAC9B,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,cAAc,IAAI,MAAM,CAAC;IACzB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAAC;IACpC,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAAC;IAClC,KAAK,IAAI,IAAI,CAAC;CACf;AAsED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,cAAc,GAC1B,kBAAkB,GAAG,IAAI,CA+K3B"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
function loadSqlite() {
|
|
3
|
+
try {
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
const mod = require("better-sqlite3");
|
|
6
|
+
return mod;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const SCHEMA_VERSION = 1;
|
|
13
|
+
const SCHEMA_SQL = `
|
|
14
|
+
CREATE TABLE IF NOT EXISTS pending_sessions (
|
|
15
|
+
session_id TEXT PRIMARY KEY,
|
|
16
|
+
session_file TEXT NOT NULL,
|
|
17
|
+
cwd TEXT NOT NULL,
|
|
18
|
+
git_root TEXT,
|
|
19
|
+
project_hash TEXT,
|
|
20
|
+
parent_session_id TEXT,
|
|
21
|
+
parent_session_file TEXT,
|
|
22
|
+
user_turn_count INTEGER NOT NULL,
|
|
23
|
+
ended_at TEXT NOT NULL,
|
|
24
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'processing', 'done', 'skipped', 'failed')),
|
|
25
|
+
error_message TEXT,
|
|
26
|
+
created_at TEXT NOT NULL,
|
|
27
|
+
updated_at TEXT NOT NULL
|
|
28
|
+
);
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_pending_sessions_status ON pending_sessions(status);
|
|
30
|
+
CREATE TABLE IF NOT EXISTS stage1_outputs (
|
|
31
|
+
session_id TEXT PRIMARY KEY,
|
|
32
|
+
session_file TEXT NOT NULL,
|
|
33
|
+
source_mtime_ms INTEGER NOT NULL,
|
|
34
|
+
generated_at TEXT NOT NULL,
|
|
35
|
+
raw_memory TEXT NOT NULL,
|
|
36
|
+
rollout_summary TEXT NOT NULL,
|
|
37
|
+
scope TEXT NOT NULL,
|
|
38
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'processing', 'done', 'skipped', 'failed')),
|
|
39
|
+
selected_for_phase2 INTEGER NOT NULL DEFAULT 0,
|
|
40
|
+
usage_count INTEGER NOT NULL DEFAULT 0,
|
|
41
|
+
last_usage TEXT,
|
|
42
|
+
error_message TEXT
|
|
43
|
+
);
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_stage1_outputs_status ON stage1_outputs(status);
|
|
45
|
+
`;
|
|
46
|
+
const UPSERT_PENDING_SQL = `
|
|
47
|
+
INSERT INTO pending_sessions (
|
|
48
|
+
session_id,
|
|
49
|
+
session_file,
|
|
50
|
+
cwd,
|
|
51
|
+
git_root,
|
|
52
|
+
project_hash,
|
|
53
|
+
parent_session_id,
|
|
54
|
+
parent_session_file,
|
|
55
|
+
user_turn_count,
|
|
56
|
+
ended_at,
|
|
57
|
+
status,
|
|
58
|
+
error_message,
|
|
59
|
+
created_at,
|
|
60
|
+
updated_at
|
|
61
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
62
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
63
|
+
session_file = excluded.session_file,
|
|
64
|
+
cwd = excluded.cwd,
|
|
65
|
+
git_root = excluded.git_root,
|
|
66
|
+
project_hash = excluded.project_hash,
|
|
67
|
+
parent_session_id = excluded.parent_session_id,
|
|
68
|
+
parent_session_file = excluded.parent_session_file,
|
|
69
|
+
user_turn_count = excluded.user_turn_count,
|
|
70
|
+
ended_at = excluded.ended_at,
|
|
71
|
+
status = excluded.status,
|
|
72
|
+
error_message = excluded.error_message,
|
|
73
|
+
updated_at = excluded.updated_at;
|
|
74
|
+
`;
|
|
75
|
+
const UPSERT_STAGE1_SQL = `
|
|
76
|
+
INSERT INTO stage1_outputs (
|
|
77
|
+
session_id,
|
|
78
|
+
session_file,
|
|
79
|
+
source_mtime_ms,
|
|
80
|
+
generated_at,
|
|
81
|
+
raw_memory,
|
|
82
|
+
rollout_summary,
|
|
83
|
+
scope,
|
|
84
|
+
status,
|
|
85
|
+
selected_for_phase2,
|
|
86
|
+
usage_count,
|
|
87
|
+
last_usage,
|
|
88
|
+
error_message
|
|
89
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
90
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
91
|
+
session_file = excluded.session_file,
|
|
92
|
+
source_mtime_ms = excluded.source_mtime_ms,
|
|
93
|
+
generated_at = excluded.generated_at,
|
|
94
|
+
raw_memory = excluded.raw_memory,
|
|
95
|
+
rollout_summary = excluded.rollout_summary,
|
|
96
|
+
scope = excluded.scope,
|
|
97
|
+
status = excluded.status,
|
|
98
|
+
selected_for_phase2 = excluded.selected_for_phase2,
|
|
99
|
+
usage_count = excluded.usage_count,
|
|
100
|
+
last_usage = excluded.last_usage,
|
|
101
|
+
error_message = excluded.error_message;
|
|
102
|
+
`;
|
|
103
|
+
function toIsoTimestamp(value = new Date()) {
|
|
104
|
+
const dt = typeof value === "string" ? new Date(value) : value;
|
|
105
|
+
return dt.toISOString();
|
|
106
|
+
}
|
|
107
|
+
function getUserVersion(db) {
|
|
108
|
+
const raw = db.pragma("user_version");
|
|
109
|
+
if (Array.isArray(raw) && raw[0] && typeof raw[0] === "object" && "user_version" in raw[0]) {
|
|
110
|
+
return Number(raw[0].user_version);
|
|
111
|
+
}
|
|
112
|
+
if (typeof raw === "number")
|
|
113
|
+
return raw;
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
function setUserVersion(db, version) {
|
|
117
|
+
db.pragma(`user_version = ${version}`);
|
|
118
|
+
}
|
|
119
|
+
function normalizeSessionRow(row) {
|
|
120
|
+
if (!row)
|
|
121
|
+
return null;
|
|
122
|
+
return {
|
|
123
|
+
session_id: String(row.session_id ?? ""),
|
|
124
|
+
session_file: String(row.session_file ?? ""),
|
|
125
|
+
cwd: String(row.cwd ?? ""),
|
|
126
|
+
git_root: row.git_root == null ? null : String(row.git_root),
|
|
127
|
+
project_hash: row.project_hash == null ? null : String(row.project_hash),
|
|
128
|
+
parent_session_id: row.parent_session_id == null ? null : String(row.parent_session_id),
|
|
129
|
+
parent_session_file: row.parent_session_file == null ? null : String(row.parent_session_file),
|
|
130
|
+
user_turn_count: Number(row.user_turn_count ?? 0),
|
|
131
|
+
ended_at: String(row.ended_at ?? ""),
|
|
132
|
+
status: String(row.status ?? "pending"),
|
|
133
|
+
error_message: row.error_message == null ? null : String(row.error_message),
|
|
134
|
+
created_at: String(row.created_at ?? ""),
|
|
135
|
+
updated_at: String(row.updated_at ?? ""),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function normalizeStage1Row(row) {
|
|
139
|
+
if (!row)
|
|
140
|
+
return null;
|
|
141
|
+
return {
|
|
142
|
+
session_id: String(row.session_id ?? ""),
|
|
143
|
+
session_file: String(row.session_file ?? ""),
|
|
144
|
+
source_mtime_ms: toNumber(row.source_mtime_ms, 0),
|
|
145
|
+
generated_at: String(row.generated_at ?? ""),
|
|
146
|
+
raw_memory: String(row.raw_memory ?? ""),
|
|
147
|
+
rollout_summary: String(row.rollout_summary ?? ""),
|
|
148
|
+
scope: String(row.scope ?? "global"),
|
|
149
|
+
status: String(row.status ?? "pending"),
|
|
150
|
+
selected_for_phase2: Number(row.selected_for_phase2 ?? 0) === 1,
|
|
151
|
+
usage_count: toNumber(row.usage_count, 0),
|
|
152
|
+
last_usage: row.last_usage == null ? null : String(row.last_usage),
|
|
153
|
+
error_message: row.error_message == null ? null : String(row.error_message),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function toBoolInt(value) {
|
|
157
|
+
return value ? 1 : 0;
|
|
158
|
+
}
|
|
159
|
+
function toNumber(value, fallback = 0) {
|
|
160
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
161
|
+
return value;
|
|
162
|
+
if (typeof value === "string") {
|
|
163
|
+
const parsed = Number(value);
|
|
164
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
165
|
+
}
|
|
166
|
+
return fallback;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Lazy-open a sqlite database and ensure the consolidation schema exists.
|
|
170
|
+
* Returns null when better-sqlite3 is unavailable and no injected DB is provided.
|
|
171
|
+
*/
|
|
172
|
+
export function openConsolidationStore(dbPath, injectedDb) {
|
|
173
|
+
let db;
|
|
174
|
+
if (injectedDb) {
|
|
175
|
+
db = injectedDb;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const Sqlite = loadSqlite();
|
|
179
|
+
if (!Sqlite)
|
|
180
|
+
return null;
|
|
181
|
+
db = new Sqlite(dbPath);
|
|
182
|
+
}
|
|
183
|
+
db.pragma("journal_mode = WAL");
|
|
184
|
+
const current = getUserVersion(db);
|
|
185
|
+
if (current !== SCHEMA_VERSION) {
|
|
186
|
+
db.exec(SCHEMA_SQL);
|
|
187
|
+
setUserVersion(db, SCHEMA_VERSION);
|
|
188
|
+
}
|
|
189
|
+
const upsertPendingStmt = db.prepare(UPSERT_PENDING_SQL);
|
|
190
|
+
const upsertStage1Stmt = db.prepare(UPSERT_STAGE1_SQL);
|
|
191
|
+
const selectPendingByIdStmt = db.prepare("SELECT * FROM pending_sessions WHERE session_id = ?");
|
|
192
|
+
const listPendingStmt = db.prepare("SELECT * FROM pending_sessions WHERE status IN ('pending', 'failed') ORDER BY ended_at ASC LIMIT ?");
|
|
193
|
+
const updatePendingStatusStmt = db.prepare("UPDATE pending_sessions SET status = ?, error_message = ?, updated_at = ? WHERE session_id = ?");
|
|
194
|
+
const selectStage1ByIdStmt = db.prepare("SELECT * FROM stage1_outputs WHERE session_id = ?");
|
|
195
|
+
const listUnselectedStage1Stmt = db.prepare("SELECT * FROM stage1_outputs WHERE selected_for_phase2 = 0 AND status = 'done' ORDER BY generated_at DESC LIMIT ?");
|
|
196
|
+
const listStage1OlderThanStmt = db.prepare("SELECT * FROM stage1_outputs WHERE last_usage IS NOT NULL AND last_usage < ? ORDER BY last_usage ASC LIMIT ?");
|
|
197
|
+
const markStage1SelectedStmt = db.prepare("UPDATE stage1_outputs SET selected_for_phase2 = 1 WHERE session_id = ?");
|
|
198
|
+
const incrementStage1UsageStmt = db.prepare("UPDATE stage1_outputs SET usage_count = usage_count + 1, last_usage = ? WHERE session_id = ?");
|
|
199
|
+
const countPendingAllStmt = db.prepare("SELECT COUNT(*) AS count FROM pending_sessions");
|
|
200
|
+
const countPendingByStatusStmt = db.prepare("SELECT status, COUNT(*) AS count FROM pending_sessions GROUP BY status");
|
|
201
|
+
const countStage1Stmt = db.prepare("SELECT COUNT(*) AS count FROM stage1_outputs");
|
|
202
|
+
const lastGeneratedStmt = db.prepare("SELECT MAX(generated_at) AS generated_at FROM stage1_outputs");
|
|
203
|
+
const lastUpdatedStmt = db.prepare("SELECT MAX(updated_at) AS updated_at FROM pending_sessions");
|
|
204
|
+
return {
|
|
205
|
+
upsertPendingSession(session) {
|
|
206
|
+
const now = toIsoTimestamp(session.updated_at);
|
|
207
|
+
const payload = {
|
|
208
|
+
...session,
|
|
209
|
+
created_at: session.created_at ?? now,
|
|
210
|
+
updated_at: now,
|
|
211
|
+
};
|
|
212
|
+
upsertPendingStmt.run(payload.session_id, payload.session_file, payload.cwd, payload.git_root, payload.project_hash, payload.parent_session_id, payload.parent_session_file, payload.user_turn_count, payload.ended_at, payload.status, payload.error_message, payload.created_at, payload.updated_at);
|
|
213
|
+
return payload;
|
|
214
|
+
},
|
|
215
|
+
upsertStage1Output(output) {
|
|
216
|
+
upsertStage1Stmt.run(output.session_id, output.session_file, output.source_mtime_ms, output.generated_at, output.raw_memory, output.rollout_summary, output.scope, output.status, toBoolInt(output.selected_for_phase2), output.usage_count, output.last_usage, output.error_message);
|
|
217
|
+
},
|
|
218
|
+
getPendingSession(sessionId) {
|
|
219
|
+
return normalizeSessionRow(selectPendingByIdStmt.get(sessionId));
|
|
220
|
+
},
|
|
221
|
+
listPendingSessions(limit = 100) {
|
|
222
|
+
const rows = listPendingStmt.all(limit);
|
|
223
|
+
return rows
|
|
224
|
+
.map((row) => normalizeSessionRow(row))
|
|
225
|
+
.filter((row) => row != null);
|
|
226
|
+
},
|
|
227
|
+
setPendingSessionStatus(sessionId, status, errorMessage = null, updatedAt = new Date().toISOString()) {
|
|
228
|
+
updatePendingStatusStmt.run(status, errorMessage, updatedAt, sessionId);
|
|
229
|
+
},
|
|
230
|
+
getStage1Output(sessionId) {
|
|
231
|
+
return normalizeStage1Row(selectStage1ByIdStmt.get(sessionId));
|
|
232
|
+
},
|
|
233
|
+
listUnselectedStage1(limit) {
|
|
234
|
+
const rows = listUnselectedStage1Stmt.all(limit);
|
|
235
|
+
return rows
|
|
236
|
+
.map((row) => normalizeStage1Row(row))
|
|
237
|
+
.filter((row) => row != null);
|
|
238
|
+
},
|
|
239
|
+
listStage1OlderThan(cutoffIso, limit = 100) {
|
|
240
|
+
const rows = listStage1OlderThanStmt.all(cutoffIso, limit);
|
|
241
|
+
return rows
|
|
242
|
+
.map((row) => normalizeStage1Row(row))
|
|
243
|
+
.filter((row) => row != null);
|
|
244
|
+
},
|
|
245
|
+
markStage1Selected(sessionIds) {
|
|
246
|
+
const tx = db.transaction(() => {
|
|
247
|
+
for (const sessionId of sessionIds)
|
|
248
|
+
markStage1SelectedStmt.run(sessionId);
|
|
249
|
+
});
|
|
250
|
+
tx();
|
|
251
|
+
},
|
|
252
|
+
incrementStage1Usage(sessionId, usedAt = new Date().toISOString()) {
|
|
253
|
+
incrementStage1UsageStmt.run(usedAt, sessionId);
|
|
254
|
+
},
|
|
255
|
+
countPendingSessions() {
|
|
256
|
+
const row = countPendingAllStmt.get();
|
|
257
|
+
return toNumber(row?.count, 0);
|
|
258
|
+
},
|
|
259
|
+
getConsolidationStatusCounts() {
|
|
260
|
+
const rows = countPendingByStatusStmt.all();
|
|
261
|
+
const counts = {
|
|
262
|
+
pending: 0,
|
|
263
|
+
processing: 0,
|
|
264
|
+
done: 0,
|
|
265
|
+
skipped: 0,
|
|
266
|
+
failed: 0,
|
|
267
|
+
};
|
|
268
|
+
for (const row of rows) {
|
|
269
|
+
const status = row.status;
|
|
270
|
+
if (status in counts) {
|
|
271
|
+
counts[status] = toNumber(row.count, 0);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return counts;
|
|
275
|
+
},
|
|
276
|
+
getStage1Count() {
|
|
277
|
+
const row = countStage1Stmt.get();
|
|
278
|
+
return toNumber(row?.count, 0);
|
|
279
|
+
},
|
|
280
|
+
getLastGeneratedAt() {
|
|
281
|
+
const row = lastGeneratedStmt.get();
|
|
282
|
+
if (!row?.generated_at)
|
|
283
|
+
return null;
|
|
284
|
+
return String(row.generated_at);
|
|
285
|
+
},
|
|
286
|
+
getLastUpdatedAt() {
|
|
287
|
+
const row = lastUpdatedStmt.get();
|
|
288
|
+
if (!row?.updated_at)
|
|
289
|
+
return null;
|
|
290
|
+
return String(row.updated_at);
|
|
291
|
+
},
|
|
292
|
+
close() {
|
|
293
|
+
db.close();
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=store.js.map
|