@orquentra/codebuddy 2.6.0 → 2.7.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.
Files changed (117) hide show
  1. package/CLAUDE_CODEX.md +6 -4
  2. package/WORKFLOW.md +5 -5
  3. package/dist/{chunk-U4HAJLIB.js → chunk-3QGW53GD.js} +16 -3
  4. package/dist/chunk-3QGW53GD.js.map +1 -0
  5. package/dist/{chunk-L5AYZC3F.js → chunk-5EDGAZQN.js} +438 -68
  6. package/dist/chunk-5EDGAZQN.js.map +1 -0
  7. package/dist/chunk-5UH3BEQR.js +32 -0
  8. package/dist/chunk-5UH3BEQR.js.map +1 -0
  9. package/dist/{chunk-JFDRBPYF.js → chunk-6JCKMIQY.js} +2 -2
  10. package/dist/{chunk-UN57FKQX.js → chunk-AK2UAE32.js} +152 -862
  11. package/dist/chunk-AK2UAE32.js.map +1 -0
  12. package/dist/{chunk-GDJH7XJC.js → chunk-AL6VBTNA.js} +77 -3
  13. package/dist/chunk-AL6VBTNA.js.map +1 -0
  14. package/dist/{chunk-WHZSVY2L.js → chunk-AQHPEJR6.js} +94 -23
  15. package/dist/chunk-AQHPEJR6.js.map +1 -0
  16. package/dist/{chunk-PCE4STAY.js → chunk-BQM7FJ7D.js} +6 -6
  17. package/dist/chunk-BQM7FJ7D.js.map +1 -0
  18. package/dist/{chunk-XBJQKCLU.js → chunk-CAEPHLHC.js} +13 -9
  19. package/dist/chunk-CAEPHLHC.js.map +1 -0
  20. package/dist/chunk-CG5B3LYG.js +66 -0
  21. package/dist/chunk-CG5B3LYG.js.map +1 -0
  22. package/dist/chunk-CSRD5OQA.js +79 -0
  23. package/dist/chunk-CSRD5OQA.js.map +1 -0
  24. package/dist/{chunk-IHQM2ZDV.js → chunk-DFV2SK6C.js} +1 -1
  25. package/dist/{chunk-IHQM2ZDV.js.map → chunk-DFV2SK6C.js.map} +1 -1
  26. package/dist/chunk-EEUFU7KV.js +1634 -0
  27. package/dist/chunk-EEUFU7KV.js.map +1 -0
  28. package/dist/{chunk-UFZD3JAA.js → chunk-ESZXCZIN.js} +3 -3
  29. package/dist/{chunk-PYLH4MH5.js → chunk-FJOTP632.js} +1 -1
  30. package/dist/{chunk-SYWJG5NA.js → chunk-GKNYMNFM.js} +17 -7
  31. package/dist/{chunk-SYWJG5NA.js.map → chunk-GKNYMNFM.js.map} +1 -1
  32. package/dist/{chunk-JPHJBCZB.js → chunk-HPOR6YXA.js} +3 -2
  33. package/dist/chunk-HPOR6YXA.js.map +1 -0
  34. package/dist/chunk-JUAFCLRB.js +1014 -0
  35. package/dist/chunk-JUAFCLRB.js.map +1 -0
  36. package/dist/{chunk-776EQXDV.js → chunk-KNR2P2UY.js} +110 -83
  37. package/dist/chunk-KNR2P2UY.js.map +1 -0
  38. package/dist/{chunk-N34XHWBA.js → chunk-LCSBL5TT.js} +24 -11
  39. package/dist/chunk-LCSBL5TT.js.map +1 -0
  40. package/dist/{chunk-QDBDYCM2.js → chunk-MSUAVR3R.js} +76 -11
  41. package/dist/chunk-MSUAVR3R.js.map +1 -0
  42. package/dist/{chunk-6MKEIDX5.js → chunk-SFMIMLXR.js} +2 -2
  43. package/dist/chunk-TGFTKWOR.js +16 -0
  44. package/dist/chunk-TGFTKWOR.js.map +1 -0
  45. package/dist/chunk-TUR6YKEE.js +55 -0
  46. package/dist/chunk-TUR6YKEE.js.map +1 -0
  47. package/dist/chunk-Y7D7PUBE.js +321 -0
  48. package/dist/chunk-Y7D7PUBE.js.map +1 -0
  49. package/dist/{chunk-VAKBJV26.js → chunk-YJIA2MFL.js} +918 -2238
  50. package/dist/chunk-YJIA2MFL.js.map +1 -0
  51. package/dist/cli/index.js +14 -3
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/{cloud-7WM3YLI4.js → cloud-LXZUR3U2.js} +3 -3
  54. package/dist/{codebuddy-DM-i0Fu5.d.ts → codebuddy-DO7ZhoWn.d.ts} +37 -3
  55. package/dist/config-GEZFLXK6.js +12 -0
  56. package/dist/docker-autostart-KDME7TVC.js +12 -0
  57. package/dist/index.d.ts +48 -3
  58. package/dist/index.js +32 -25
  59. package/dist/langgraph/index.d.ts +1 -1
  60. package/dist/lean-command-CWJAVQ5G.js +18 -0
  61. package/dist/local-ST4WMRCG.js +17 -0
  62. package/dist/{main-HFHLGID4.js → main-AHNGHC4L.js} +327 -329
  63. package/dist/main-AHNGHC4L.js.map +1 -0
  64. package/dist/{memory-4RGVLPKG.js → memory-TGHVTBME.js} +9 -8
  65. package/dist/memory-TGHVTBME.js.map +1 -0
  66. package/dist/operations-7BTAAUHF.js +26 -0
  67. package/dist/postgres-docker-QQZQ2ABK.js +16 -0
  68. package/dist/pretool-command-3SXQSMAO.js +13 -0
  69. package/dist/{rerank-3P3C2UHN.js → rerank-IQAEWLQR.js} +6 -5
  70. package/dist/rerank-IQAEWLQR.js.map +1 -0
  71. package/dist/runtime-E7JQZ2BZ.js +46 -0
  72. package/dist/runtime-E7JQZ2BZ.js.map +1 -0
  73. package/dist/stdio-HOV4P3DQ.js +12 -0
  74. package/dist/stdio-HOV4P3DQ.js.map +1 -0
  75. package/dist/summaries-XV3JGGCC.js +20 -0
  76. package/dist/summaries-XV3JGGCC.js.map +1 -0
  77. package/dist/{zvec-MAPSJQSR.js → zvec-KP4KNB7Y.js} +10 -3
  78. package/dist/zvec-KP4KNB7Y.js.map +1 -0
  79. package/package.json +7 -10
  80. package/src/db/migrations/0006_fact_idempotency_key.sql +2 -0
  81. package/src/db/migrations/meta/0006_snapshot.json +1258 -0
  82. package/src/db/migrations/meta/_journal.json +7 -0
  83. package/dist/chunk-776EQXDV.js.map +0 -1
  84. package/dist/chunk-GDJH7XJC.js.map +0 -1
  85. package/dist/chunk-JPHJBCZB.js.map +0 -1
  86. package/dist/chunk-L5AYZC3F.js.map +0 -1
  87. package/dist/chunk-N34XHWBA.js.map +0 -1
  88. package/dist/chunk-PCE4STAY.js.map +0 -1
  89. package/dist/chunk-PQK3GKZH.js +0 -98
  90. package/dist/chunk-PQK3GKZH.js.map +0 -1
  91. package/dist/chunk-QDBDYCM2.js.map +0 -1
  92. package/dist/chunk-U4HAJLIB.js.map +0 -1
  93. package/dist/chunk-UN57FKQX.js.map +0 -1
  94. package/dist/chunk-VAKBJV26.js.map +0 -1
  95. package/dist/chunk-WHZSVY2L.js.map +0 -1
  96. package/dist/chunk-XBJQKCLU.js.map +0 -1
  97. package/dist/config-KFEHLV6W.js +0 -11
  98. package/dist/lean-command-C5YPFKHP.js +0 -15
  99. package/dist/local-OTOY56B4.js +0 -13
  100. package/dist/main-HFHLGID4.js.map +0 -1
  101. package/dist/memory-4RGVLPKG.js.map +0 -1
  102. package/dist/operations-LOBAQRLO.js +0 -24
  103. package/dist/pretool-command-MQQ2UNQM.js +0 -10
  104. package/dist/rerank-3P3C2UHN.js.map +0 -1
  105. package/dist/summaries-ZBV5IN7Y.js +0 -18
  106. /package/dist/{chunk-JFDRBPYF.js.map → chunk-6JCKMIQY.js.map} +0 -0
  107. /package/dist/{chunk-UFZD3JAA.js.map → chunk-ESZXCZIN.js.map} +0 -0
  108. /package/dist/{chunk-PYLH4MH5.js.map → chunk-FJOTP632.js.map} +0 -0
  109. /package/dist/{chunk-6MKEIDX5.js.map → chunk-SFMIMLXR.js.map} +0 -0
  110. /package/dist/{cloud-7WM3YLI4.js.map → cloud-LXZUR3U2.js.map} +0 -0
  111. /package/dist/{config-KFEHLV6W.js.map → config-GEZFLXK6.js.map} +0 -0
  112. /package/dist/{lean-command-C5YPFKHP.js.map → docker-autostart-KDME7TVC.js.map} +0 -0
  113. /package/dist/{local-OTOY56B4.js.map → lean-command-CWJAVQ5G.js.map} +0 -0
  114. /package/dist/{operations-LOBAQRLO.js.map → local-ST4WMRCG.js.map} +0 -0
  115. /package/dist/{pretool-command-MQQ2UNQM.js.map → operations-7BTAAUHF.js.map} +0 -0
  116. /package/dist/{summaries-ZBV5IN7Y.js.map → postgres-docker-QQZQ2ABK.js.map} +0 -0
  117. /package/dist/{zvec-MAPSJQSR.js.map → pretool-command-3SXQSMAO.js.map} +0 -0
@@ -0,0 +1,79 @@
1
+ // src/cli/commands/postgres-docker.ts
2
+ import { spawn } from "child_process";
3
+ import { existsSync } from "fs";
4
+ import { dirname, resolve } from "path";
5
+ import { fileURLToPath } from "url";
6
+ function resolveBundledComposeFile(from = dirname(fileURLToPath(import.meta.url))) {
7
+ const candidates = [];
8
+ for (let dir = from; ; dir = dirname(dir)) {
9
+ candidates.push(resolve(dir, "docker-compose.yml"));
10
+ if (dirname(dir) === dir) break;
11
+ }
12
+ candidates.push(resolve(process.cwd(), "docker-compose.yml"));
13
+ for (const candidate of candidates) {
14
+ if (existsSync(candidate)) return candidate;
15
+ }
16
+ throw new Error(`Could not locate docker-compose.yml. Looked in:
17
+ ${candidates.join("\n ")}`);
18
+ }
19
+ async function runDockerCompose(args, options = {}) {
20
+ const spawnImpl = options.spawnImpl ?? spawn;
21
+ const composeFile = resolveBundledComposeFile();
22
+ const project = ["-p", "codebuddy"];
23
+ const attempts = [
24
+ { kind: "v2", bin: "docker", args: ["compose", ...project, "-f", composeFile, ...args] },
25
+ { kind: "v1", bin: "docker-compose", args: [...project, "-f", composeFile, ...args] }
26
+ ];
27
+ let lastSpawnError = null;
28
+ for (const attempt of attempts) {
29
+ try {
30
+ return await spawnOnce(spawnImpl, attempt);
31
+ } catch (error) {
32
+ const err = error;
33
+ if (err.code !== "ENOENT") throw err;
34
+ lastSpawnError = err;
35
+ }
36
+ }
37
+ throw new Error(
38
+ `Could not find docker. Install Docker Desktop (or docker-compose v1) and ensure it is on your PATH. (${lastSpawnError?.message ?? "spawn ENOENT"})`
39
+ );
40
+ }
41
+ function spawnOnce(spawnImpl, attempt) {
42
+ return new Promise((resolvePromise, rejectPromise) => {
43
+ const child = spawnImpl(attempt.bin, attempt.args, {
44
+ stdio: ["ignore", "pipe", "pipe"]
45
+ });
46
+ let stdout = "";
47
+ let stderr = "";
48
+ child.stdout?.on("data", (chunk) => {
49
+ stdout += String(chunk);
50
+ });
51
+ child.stderr?.on("data", (chunk) => {
52
+ stderr += String(chunk);
53
+ });
54
+ child.on("error", (error) => {
55
+ rejectPromise(error);
56
+ });
57
+ child.on("close", (code) => {
58
+ resolvePromise({ code: code ?? 0, stdout, stderr });
59
+ });
60
+ });
61
+ }
62
+ async function postgresUp(options) {
63
+ return runDockerCompose(["up", "-d"], options ?? {});
64
+ }
65
+ async function postgresDown(options) {
66
+ return runDockerCompose(["down"], options ?? {});
67
+ }
68
+ async function postgresStatus(options) {
69
+ return runDockerCompose(["ps"], options ?? {});
70
+ }
71
+
72
+ export {
73
+ resolveBundledComposeFile,
74
+ runDockerCompose,
75
+ postgresUp,
76
+ postgresDown,
77
+ postgresStatus
78
+ };
79
+ //# sourceMappingURL=chunk-CSRD5OQA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/postgres-docker.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nexport type ComposeCommand =\n | { kind: \"v2\"; bin: \"docker\"; args: string[] }\n | { kind: \"v1\"; bin: \"docker-compose\"; args: string[] };\n\nexport function resolveBundledComposeFile(from = dirname(fileURLToPath(import.meta.url))): string {\n // tsup code-splits, so this module may run from dist/, dist/<chunk>.js or\n // src/cli/commands/; fixed `..` counts break on one of them. Walk up to the\n // nearest docker-compose.yml so the package's bundled file wins over a\n // stray one in the user's cwd.\n const candidates: string[] = [];\n for (let dir = from; ; dir = dirname(dir)) {\n candidates.push(resolve(dir, \"docker-compose.yml\"));\n if (dirname(dir) === dir) break;\n }\n candidates.push(resolve(process.cwd(), \"docker-compose.yml\"));\n for (const candidate of candidates) {\n if (existsSync(candidate)) return candidate;\n }\n throw new Error(`Could not locate docker-compose.yml. Looked in:\\n ${candidates.join(\"\\n \")}`);\n}\n\nexport type DockerComposeResult = {\n code: number;\n stdout: string;\n stderr: string;\n};\n\nexport type RunDockerComposeOptions = {\n /** Override spawn for tests. */\n spawnImpl?: typeof spawn;\n};\n\n/**\n * Try `docker compose` (v2 — bundled with Docker Desktop) first, then fall back\n * to the legacy standalone `docker-compose` (v1) for older installs.\n */\nexport async function runDockerCompose(\n args: string[],\n options: RunDockerComposeOptions = {},\n): Promise<DockerComposeResult> {\n const spawnImpl = options.spawnImpl ?? spawn;\n const composeFile = resolveBundledComposeFile();\n // A fixed project name: compose otherwise names the project (and its data\n // volume, `codebuddy_codebuddy-postgres-data`) after the folder holding the\n // compose file, so another install location would get an empty database.\n const project = [\"-p\", \"codebuddy\"];\n const attempts: ComposeCommand[] = [\n { kind: \"v2\", bin: \"docker\", args: [\"compose\", ...project, \"-f\", composeFile, ...args] },\n { kind: \"v1\", bin: \"docker-compose\", args: [...project, \"-f\", composeFile, ...args] },\n ];\n\n let lastSpawnError: NodeJS.ErrnoException | null = null;\n\n for (const attempt of attempts) {\n try {\n return await spawnOnce(spawnImpl, attempt);\n } catch (error) {\n const err = error as NodeJS.ErrnoException;\n // ENOENT means the binary isn't on PATH — try the next candidate.\n // Any other error is propagated immediately.\n if (err.code !== \"ENOENT\") throw err;\n lastSpawnError = err;\n }\n }\n\n throw new Error(\n `Could not find docker. Install Docker Desktop (or docker-compose v1) and ensure it is on your PATH. (${lastSpawnError?.message ?? \"spawn ENOENT\"})`,\n );\n}\n\nfunction spawnOnce(spawnImpl: typeof spawn, attempt: ComposeCommand): Promise<DockerComposeResult> {\n return new Promise((resolvePromise, rejectPromise) => {\n const child = spawnImpl(attempt.bin, attempt.args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.on(\"data\", (chunk) => {\n stdout += String(chunk);\n });\n child.stderr?.on(\"data\", (chunk) => {\n stderr += String(chunk);\n });\n child.on(\"error\", (error) => {\n rejectPromise(error);\n });\n child.on(\"close\", (code) => {\n resolvePromise({ code: code ?? 0, stdout, stderr });\n });\n });\n}\n\nexport async function postgresUp(options?: RunDockerComposeOptions): Promise<DockerComposeResult> {\n return runDockerCompose([\"up\", \"-d\"], options ?? {});\n}\n\nexport async function postgresDown(\n options?: RunDockerComposeOptions,\n): Promise<DockerComposeResult> {\n return runDockerCompose([\"down\"], options ?? {});\n}\n\nexport async function postgresStatus(\n options?: RunDockerComposeOptions,\n): Promise<DockerComposeResult> {\n return runDockerCompose([\"ps\"], options ?? {});\n}\n"],"mappings":";AAAA,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,SAAS,eAAe;AACjC,SAAS,qBAAqB;AAMvB,SAAS,0BAA0B,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAW;AAKhG,QAAM,aAAuB,CAAC;AAC9B,WAAS,MAAM,QAAQ,MAAM,QAAQ,GAAG,GAAG;AACzC,eAAW,KAAK,QAAQ,KAAK,oBAAoB,CAAC;AAClD,QAAI,QAAQ,GAAG,MAAM,IAAK;AAAA,EAC5B;AACA,aAAW,KAAK,QAAQ,QAAQ,IAAI,GAAG,oBAAoB,CAAC;AAC5D,aAAW,aAAa,YAAY;AAClC,QAAI,WAAW,SAAS,EAAG,QAAO;AAAA,EACpC;AACA,QAAM,IAAI,MAAM;AAAA,IAAsD,WAAW,KAAK,MAAM,CAAC,EAAE;AACjG;AAiBA,eAAsB,iBACpB,MACA,UAAmC,CAAC,GACN;AAC9B,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,cAAc,0BAA0B;AAI9C,QAAM,UAAU,CAAC,MAAM,WAAW;AAClC,QAAM,WAA6B;AAAA,IACjC,EAAE,MAAM,MAAM,KAAK,UAAU,MAAM,CAAC,WAAW,GAAG,SAAS,MAAM,aAAa,GAAG,IAAI,EAAE;AAAA,IACvF,EAAE,MAAM,MAAM,KAAK,kBAAkB,MAAM,CAAC,GAAG,SAAS,MAAM,aAAa,GAAG,IAAI,EAAE;AAAA,EACtF;AAEA,MAAI,iBAA+C;AAEnD,aAAW,WAAW,UAAU;AAC9B,QAAI;AACF,aAAO,MAAM,UAAU,WAAW,OAAO;AAAA,IAC3C,SAAS,OAAO;AACd,YAAM,MAAM;AAGZ,UAAI,IAAI,SAAS,SAAU,OAAM;AACjC,uBAAiB;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR,wGAAwG,gBAAgB,WAAW,cAAc;AAAA,EACnJ;AACF;AAEA,SAAS,UAAU,WAAyB,SAAuD;AACjG,SAAO,IAAI,QAAQ,CAAC,gBAAgB,kBAAkB;AACpD,UAAM,QAAQ,UAAU,QAAQ,KAAK,QAAQ,MAAM;AAAA,MACjD,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,IAClC,CAAC;AACD,QAAI,SAAS;AACb,QAAI,SAAS;AACb,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,gBAAU,OAAO,KAAK;AAAA,IACxB,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,gBAAU,OAAO,KAAK;AAAA,IACxB,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,UAAU;AAC3B,oBAAc,KAAK;AAAA,IACrB,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,qBAAe,EAAE,MAAM,QAAQ,GAAG,QAAQ,OAAO,CAAC;AAAA,IACpD,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,WAAW,SAAiE;AAChG,SAAO,iBAAiB,CAAC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC;AACrD;AAEA,eAAsB,aACpB,SAC8B;AAC9B,SAAO,iBAAiB,CAAC,MAAM,GAAG,WAAW,CAAC,CAAC;AACjD;AAEA,eAAsB,eACpB,SAC8B;AAC9B,SAAO,iBAAiB,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC;AAC/C;","names":[]}
@@ -16,4 +16,4 @@ export {
16
16
  MEMORY_CLASSES,
17
17
  memoryCandidateSchema
18
18
  };
19
- //# sourceMappingURL=chunk-IHQM2ZDV.js.map
19
+ //# sourceMappingURL=chunk-DFV2SK6C.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/memory-extract/types.ts"],"sourcesContent":["/**\n * Automatic memory extraction model (Proposal 04 Phase 04.4). After a coding\n * turn, CodeBuddy turns a short summary into structured memory *candidates*,\n * classifies each, and — only when confidence and safety allow — saves durable\n * Markdown. Everything else is routed to a reviewable queue or dropped. The\n * guiding rule: prefer a false negative (missed memory) over a false durable\n * fact. Junk memory poisons recall, so capture is deliberately conservative.\n */\n\nimport { z } from \"zod\";\nimport type { IncidentSeverity } from \"../core/memory-file-store.js\";\n\n/** How a candidate is classified. `ignored` is chatter we deliberately drop. */\nexport const MEMORY_CLASSES = [\"fact\", \"decision\", \"incident\", \"note\", \"ignored\"] as const;\nexport type MemoryClass = (typeof MEMORY_CLASSES)[number];\n\n/** What ultimately happened to a candidate. */\nexport type CandidateOutcome = \"saved\" | \"queued\" | \"ignored\";\n\n/**\n * A single extracted memory candidate, before gating. `content` is the human\n * sentence; the subject/predicate/object triple mirrors the durable fact\n * schema so an approved candidate maps cleanly onto `MemoryFileStore`.\n */\nexport type MemoryCandidate = {\n class: MemoryClass;\n content: string;\n subject: string;\n predicate: string;\n object: string;\n confidence: number;\n paths: string[];\n severity: IncidentSeverity | null;\n};\n\n/** Zod schema used to validate extractor (esp. LLM) output strictly. */\nexport const memoryCandidateSchema = z.object({\n class: z.enum(MEMORY_CLASSES),\n content: z.string().min(1),\n subject: z.string().min(1),\n predicate: z.string().min(1),\n object: z.string().min(1),\n confidence: z.number().min(0).max(1),\n paths: z.array(z.string().min(1)).default([]),\n severity: z.enum([\"low\", \"medium\", \"high\", \"critical\"]).nullable().default(null),\n});\n\nexport type ExtractionInput = {\n summary: string;\n namespace: string;\n changedFiles?: string[];\n planId?: string;\n taskType?: string;\n agentId?: string;\n sessionId?: string;\n commitSha?: string;\n verification?: string[];\n /** Standing rules the user stated this turn (`extractUserRules`). */\n userRules?: string[];\n /** User sentences withdrawing an earlier rule. */\n revokedRules?: string[];\n /** A turn without edits that still produced findings: record a handoff anyway. */\n investigation?: boolean;\n /** false: skip extraction from `summary` (only user rules, procedures and the handoff). */\n extract?: boolean;\n};\n\n/** A candidate paired with the gating decision made about it. */\nexport type CandidateDecision = {\n candidate: MemoryCandidate;\n outcome: CandidateOutcome;\n reason: string;\n /** Present when the outcome is `saved` (fact id) or `queued` (review id). */\n ref?: string;\n sensitive: boolean;\n sensitiveReasons: string[];\n};\n\nexport type AfterTurnResult = {\n saved: CandidateDecision[];\n queuedForReview: CandidateDecision[];\n ignored: CandidateDecision[];\n /** One line per decision, for explainability. */\n reasons: string[];\n extractor: \"deterministic\" | \"llm\";\n /** Worklog entry recorded for this turn, or null when the turn changed nothing. */\n worklogId: string | null;\n};\n"],"mappings":";AASA,SAAS,SAAS;AAIX,IAAM,iBAAiB,CAAC,QAAQ,YAAY,YAAY,QAAQ,SAAS;AAuBzE,IAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,KAAK,cAAc;AAAA,EAC5B,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EACnC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC5C,UAAU,EAAE,KAAK,CAAC,OAAO,UAAU,QAAQ,UAAU,CAAC,EAAE,SAAS,EAAE,QAAQ,IAAI;AACjF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/memory-extract/types.ts"],"sourcesContent":["/**\n * Automatic memory extraction model (Proposal 04 Phase 04.4). After a coding\n * turn, CodeBuddy turns a short summary into structured memory *candidates*,\n * classifies each, and — only when confidence and safety allow — saves durable\n * Markdown. Everything else is routed to a reviewable queue or dropped. The\n * guiding rule: prefer a false negative (missed memory) over a false durable\n * fact. Junk memory poisons recall, so capture is deliberately conservative.\n */\n\nimport { z } from \"zod\";\nimport type { IncidentSeverity } from \"../core/memory-file-store.js\";\n\n/** How a candidate is classified. `ignored` is chatter we deliberately drop. */\nexport const MEMORY_CLASSES = [\"fact\", \"decision\", \"incident\", \"note\", \"ignored\"] as const;\nexport type MemoryClass = (typeof MEMORY_CLASSES)[number];\n\n/** What ultimately happened to a candidate. */\nexport type CandidateOutcome = \"saved\" | \"queued\" | \"ignored\";\n\n/**\n * A single extracted memory candidate, before gating. `content` is the human\n * sentence; the subject/predicate/object triple mirrors the durable fact\n * schema so an approved candidate maps cleanly onto `MemoryFileStore`.\n */\nexport type MemoryCandidate = {\n class: MemoryClass;\n content: string;\n subject: string;\n predicate: string;\n object: string;\n confidence: number;\n paths: string[];\n severity: IncidentSeverity | null;\n};\n\n/** Zod schema used to validate extractor (esp. LLM) output strictly. */\nexport const memoryCandidateSchema = z.object({\n class: z.enum(MEMORY_CLASSES),\n content: z.string().min(1),\n subject: z.string().min(1),\n predicate: z.string().min(1),\n object: z.string().min(1),\n confidence: z.number().min(0).max(1),\n paths: z.array(z.string().min(1)).default([]),\n severity: z.enum([\"low\", \"medium\", \"high\", \"critical\"]).nullable().default(null),\n});\n\nexport type ExtractionInput = {\n summary: string;\n namespace: string;\n changedFiles?: string[];\n planId?: string;\n taskType?: string;\n agentId?: string;\n sessionId?: string;\n commitSha?: string;\n verification?: string[];\n /** Standing rules the user stated this turn (`extractUserRules`). */\n userRules?: string[];\n /** Durable-looking user statements that are not explicit rules: queued for review. */\n userPolicies?: string[];\n /** User sentences withdrawing an earlier rule. */\n revokedRules?: string[];\n /** A turn without edits that still produced findings: record a handoff anyway. */\n investigation?: boolean;\n /** false: skip extraction from `summary` (only user rules, procedures and the handoff). */\n extract?: boolean;\n};\n\n/** A candidate paired with the gating decision made about it. */\nexport type CandidateDecision = {\n candidate: MemoryCandidate;\n outcome: CandidateOutcome;\n reason: string;\n /** Present when the outcome is `saved` (fact id) or `queued` (review id). */\n ref?: string;\n sensitive: boolean;\n sensitiveReasons: string[];\n};\n\nexport type AfterTurnResult = {\n saved: CandidateDecision[];\n queuedForReview: CandidateDecision[];\n ignored: CandidateDecision[];\n /** One line per decision, for explainability. */\n reasons: string[];\n extractor: \"deterministic\" | \"llm\";\n /** Worklog entry recorded for this turn, or null when the turn changed nothing. */\n worklogId: string | null;\n};\n"],"mappings":";AASA,SAAS,SAAS;AAIX,IAAM,iBAAiB,CAAC,QAAQ,YAAY,YAAY,QAAQ,SAAS;AAuBzE,IAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,KAAK,cAAc;AAAA,EAC5B,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACzB,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC3B,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACxB,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EACnC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC5C,UAAU,EAAE,KAAK,CAAC,OAAO,UAAU,QAAQ,UAAU,CAAC,EAAE,SAAS,EAAE,QAAQ,IAAI;AACjF,CAAC;","names":[]}