@tznthou/ccrecall 0.7.1 → 0.8.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.
@@ -0,0 +1,7 @@
1
+ export declare const CCRECALL_DIR_MODE = 448;
2
+ export declare const CCRECALL_FILE_MODE = 384;
3
+ /** Create a ccRecall directory 0700, and repair one we already own. */
4
+ export declare function ensureCcrecallDir(dir: string): void;
5
+ /** Hold a ccRecall file at 0600, whoever chose its location. */
6
+ export declare function secureCcrecallFile(file: string): void;
7
+ //# sourceMappingURL=secure-dir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-dir.d.ts","sourceRoot":"","sources":["../../src/core/secure-dir.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,iBAAiB,MAAQ,CAAA;AACtC,eAAO,MAAM,kBAAkB,MAAQ,CAAA;AAWvC,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAkBnD;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAWrD"}
@@ -0,0 +1,64 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ //
3
+ // #95: ~/.ccrecall holds the database — every memory, every session title — and
4
+ // telemetry whose rows carry `cwd`: the account name and every project name
5
+ // worked on. Four call sites create that directory; whichever ran first decided
6
+ // its mode, and three of them passed none. On a `umask 022` machine that is
7
+ // 0755, and under the `umask 002` that several distributions default to, 0775 —
8
+ // a directory another local user can write into.
9
+ //
10
+ // ⚠️ There is a second copy of this logic in hooks/lib/secure-dir.mjs. The hooks
11
+ // ship as standalone .mjs installed via npm and are never bundled through the
12
+ // TypeScript build, so they cannot import this file. The two are kept in step
13
+ // by tests/ccrecall-dir-permissions.test.ts, which imports both and asserts
14
+ // they agree — the same arrangement src/core/project-id.ts has with
15
+ // hooks/lib/project-id.mjs.
16
+ import { mkdirSync, chmodSync } from 'node:fs';
17
+ import os from 'node:os';
18
+ import path from 'node:path';
19
+ export const CCRECALL_DIR_MODE = 0o700;
20
+ export const CCRECALL_FILE_MODE = 0o600;
21
+ /** Resolved per call, never at module load: tests move $HOME, and a value
22
+ * frozen at import time would answer "is this ours?" about the real home
23
+ * directory no matter where the caller was pointed. */
24
+ function isOurs(dir) {
25
+ const root = path.join(os.homedir(), '.ccrecall');
26
+ const resolved = path.resolve(dir);
27
+ return resolved === root || resolved.startsWith(root + path.sep);
28
+ }
29
+ /** Create a ccRecall directory 0700, and repair one we already own. */
30
+ export function ensureCcrecallDir(dir) {
31
+ mkdirSync(dir, { recursive: true, mode: CCRECALL_DIR_MODE });
32
+ // mkdirSync leaves an existing directory's mode alone, so without this every
33
+ // install predating the fix keeps whatever its first creator gave it. The
34
+ // repair is limited to a path we know is ours because PR #94 did it to a
35
+ // configurable one: with a relative CCRECALL_EXTRACT_LOG the parent is the
36
+ // working directory, and a user's project directory went 0755 -> 0700 in
37
+ // testing. That attempt was reverted twice. A creator may choose the mode of
38
+ // a directory it makes; it may not re-mode a directory that was already
39
+ // there and belongs to someone else.
40
+ if (isOurs(dir)) {
41
+ try {
42
+ chmodSync(dir, CCRECALL_DIR_MODE);
43
+ }
44
+ catch {
45
+ // Raced away, or owned by another user. Nothing safe left to do, and the
46
+ // caller's real work must not fail over a mode.
47
+ }
48
+ }
49
+ }
50
+ /** Hold a ccRecall file at 0600, whoever chose its location. */
51
+ export function secureCcrecallFile(file) {
52
+ // Unconditional, unlike the directory above: a user-chosen *location* does
53
+ // not make the file someone else's — ccRecall wrote it either way. This is
54
+ // what the shell wrapper has done since #94, and it is what repairs the logs
55
+ // that are already 0644 on existing installs, since `mode` on appendFileSync
56
+ // only applies when the file is created.
57
+ try {
58
+ chmodSync(file, CCRECALL_FILE_MODE);
59
+ }
60
+ catch {
61
+ // Not there yet, or not ours. Telemetry must never break a caller.
62
+ }
63
+ }
64
+ //# sourceMappingURL=secure-dir.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-dir.js","sourceRoot":"","sources":["../../src/core/secure-dir.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,gFAAgF;AAChF,4EAA4E;AAC5E,gFAAgF;AAChF,iDAAiD;AACjD,EAAE;AACF,iFAAiF;AACjF,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,oEAAoE;AACpE,4BAA4B;AAC5B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,CAAA;AACtC,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAA;AAEvC;;wDAEwD;AACxD,SAAS,MAAM,CAAC,GAAW;IACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAClC,OAAO,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;AAClE,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAA;IAC5D,6EAA6E;IAC7E,0EAA0E;IAC1E,yEAAyE;IACzE,2EAA2E;IAC3E,yEAAyE;IACzE,6EAA6E;IAC7E,wEAAwE;IACxE,qCAAqC;IACrC,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,SAAS,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAA;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;YACzE,gDAAgD;QAClD,CAAC;IACH,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,2EAA2E;IAC3E,2EAA2E;IAC3E,6EAA6E;IAC7E,6EAA6E;IAC7E,yCAAyC;IACzC,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAA;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;IACrE,CAAC;AACH,CAAC"}
@@ -1,8 +1,19 @@
1
1
  /**
2
2
  * Token budget primitives for recall output (Issue #12).
3
- * Implementation of the "<300 tokens" contract documented in tutorial.md.
3
+ * Implementation of the injection budget contract documented in tutorial.md.
4
+ * The number lives in DEFAULT_MAX_TOKENS below, not in this sentence: stating
5
+ * it twice is how the file came to say "<300 tokens" three lines above the
6
+ * constant that reads 400.
4
7
  */
5
- export declare const DEFAULT_MAX_TOKENS = 300;
8
+ /** Total output budget for one SessionStart injection.
9
+ *
10
+ * Raised from 300 on 2026-09-11 alongside honest accounting. The old number
11
+ * was not a smaller budget, it was a wrong one: measured against the real hook
12
+ * with a corpus-shaped payload, a "300 token" injection emitted 363 because
13
+ * only `content` was priced. 400 keeps the same five rows reaching the reader
14
+ * now that the prefix, confidence suffix, [key: …] handle, header and footer
15
+ * are all counted. It buys no extra content — it stops the contract lying. */
16
+ export declare const DEFAULT_MAX_TOKENS = 400;
6
17
  export declare const DEFAULT_PER_ROW_CHAR_CAP = 150;
7
18
  /**
8
19
  * Conservative token estimate without a real tokenizer.
@@ -25,6 +36,28 @@ export interface BudgetResult<R extends BudgetRow> {
25
36
  usedTokens: number;
26
37
  truncated: boolean;
27
38
  }
39
+ /** What a row costs once the hook has rendered it — prefix, suffixes and all.
40
+ * Receives the clipped content so the caller never re-derives the clipping. */
41
+ export type RowCostFn<R extends BudgetRow> = (clipped: string, row: R) => number;
42
+ export interface BudgetOptions<R extends BudgetRow> {
43
+ /** Price of a rendered row. Defaults to the content alone, which is what the
44
+ * budget did before it learned about the decoration around it. */
45
+ costOf?: RowCostFn<R>;
46
+ /** Fixed output the caller will add regardless of how many rows survive —
47
+ * a header, a footer. Charged up front, and included in `usedTokens`, so
48
+ * the reported number is the size of the whole emission. */
49
+ reservedTokens?: number;
50
+ /** When the first row will not fit, trim it to what remains instead of
51
+ * emitting nothing. Off by default: this changes what callers receive.
52
+ *
53
+ * Exists because honest accounting makes "nothing fits" common on the
54
+ * mid-conversation path, where one CJK memory costs one token per character
55
+ * and alone exceeds the budget. Silence there is indistinguishable from
56
+ * "no relevant memory", so the failure was invisible. Trimming keeps the
57
+ * contract intact — the budget is never exceeded — while still saying
58
+ * something. */
59
+ minimumOneRow?: boolean;
60
+ }
28
61
  /**
29
62
  * Apply a token budget to a list of row-like objects with a `content` field.
30
63
  * Per-row content is truncated to perRowCharCap (ellipsis-aware), cumulative
@@ -34,5 +67,28 @@ export interface BudgetResult<R extends BudgetRow> {
34
67
  * Callers should touch/log only `emitted` ids — dropped rows never reached
35
68
  * the client.
36
69
  */
37
- export declare function applyRowBudget<R extends BudgetRow>(rows: R[], maxTokens?: number, perRowCharCap?: number): BudgetResult<R>;
70
+ export declare function applyRowBudget<R extends BudgetRow>(rows: R[], maxTokens?: number, perRowCharCap?: number, options?: BudgetOptions<R>): BudgetResult<R>;
71
+ /** A key longer than this is dropped by both hooks rather than truncated, so
72
+ * it costs nothing. Mirrors MAX_KEY_CHARS in both hook files. */
73
+ export declare const MAX_KEY_CHARS = 60;
74
+ /** Header, blank lines and footer the startup hook wraps around the rows.
75
+ * Sized against the longest footer variant (the one carrying the corpus
76
+ * count), so the reservation cannot come up short as the corpus grows. */
77
+ export declare const STARTUP_CHROME_TOKENS = 52;
78
+ /** Same for the mid-conversation hook, whose footer is a single short line. */
79
+ export declare const PROMPT_CHROME_TOKENS = 31;
80
+ /** Only the fields the hooks render alongside the content. Deliberately not
81
+ * extending BudgetRow: these functions receive the clipped text as their first
82
+ * argument and must never read `row.content`, which is the unclipped original. */
83
+ interface DecoratedRow {
84
+ confidence?: number;
85
+ key?: string | null;
86
+ }
87
+ /** Cost of one startup line: `- <content>[ (conf N.NN)][ [key: …]]` plus the
88
+ * newline joining it to the previous line. */
89
+ export declare function startupLineCost(clipped: string, row: DecoratedRow): number;
90
+ /** Cost of one mid-conversation line. No confidence suffix — that hook does
91
+ * not render one. */
92
+ export declare function promptLineCost(clipped: string, row: DecoratedRow): number;
93
+ export {};
38
94
  //# sourceMappingURL=token-budget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-budget.d.ts","sourceRoot":"","sources":["../../src/core/token-budget.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,wBAAwB,MAAM,CAAA;AAI3C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQtD;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,SAAS;IAC/C,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,SAAS,EAChD,IAAI,EAAE,CAAC,EAAE,EACT,SAAS,GAAE,MAA2B,EACtC,aAAa,GAAE,MAAiC,GAC/C,YAAY,CAAC,CAAC,CAAC,CAqBjB"}
1
+ {"version":3,"file":"token-budget.d.ts","sourceRoot":"","sources":["../../src/core/token-budget.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH;;;;;;;+EAO+E;AAC/E,eAAO,MAAM,kBAAkB,MAAM,CAAA;AACrC,eAAO,MAAM,wBAAwB,MAAM,CAAA;AAI3C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQtD;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,SAAS;IAC/C,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,OAAO,CAAA;CACnB;AAED;gFACgF;AAChF,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,SAAS,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,KAAK,MAAM,CAAA;AAEhF,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,SAAS;IAChD;uEACmE;IACnE,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAA;IACrB;;iEAE6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;qBAQiB;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAoBD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,SAAS,EAChD,IAAI,EAAE,CAAC,EAAE,EACT,SAAS,GAAE,MAA2B,EACtC,aAAa,GAAE,MAAiC,EAChD,OAAO,GAAE,aAAa,CAAC,CAAC,CAAM,GAC7B,YAAY,CAAC,CAAC,CAAC,CAmCjB;AAUD;kEACkE;AAClE,eAAO,MAAM,aAAa,KAAK,CAAA;AAE/B;;2EAE2E;AAC3E,eAAO,MAAM,qBAAqB,KAAK,CAAA;AAEvC,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC;;mFAEmF;AACnF,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAMD;+CAC+C;AAC/C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAK1E;AAED;sBACsB;AACtB,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAEzE"}
@@ -1,9 +1,20 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
3
  * Token budget primitives for recall output (Issue #12).
4
- * Implementation of the "<300 tokens" contract documented in tutorial.md.
4
+ * Implementation of the injection budget contract documented in tutorial.md.
5
+ * The number lives in DEFAULT_MAX_TOKENS below, not in this sentence: stating
6
+ * it twice is how the file came to say "<300 tokens" three lines above the
7
+ * constant that reads 400.
5
8
  */
6
- export const DEFAULT_MAX_TOKENS = 300;
9
+ /** Total output budget for one SessionStart injection.
10
+ *
11
+ * Raised from 300 on 2026-09-11 alongside honest accounting. The old number
12
+ * was not a smaller budget, it was a wrong one: measured against the real hook
13
+ * with a corpus-shaped payload, a "300 token" injection emitted 363 because
14
+ * only `content` was priced. 400 keeps the same five rows reaching the reader
15
+ * now that the prefix, confidence suffix, [key: …] handle, header and footer
16
+ * are all counted. It buys no extra content — it stops the contract lying. */
17
+ export const DEFAULT_MAX_TOKENS = 400;
7
18
  export const DEFAULT_PER_ROW_CHAR_CAP = 150;
8
19
  const CJK_REGEX = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
9
20
  /**
@@ -38,6 +49,25 @@ export function truncateToChars(text, maxChars) {
38
49
  return ELLIPSIS;
39
50
  return chars.slice(0, maxChars - 1).join('') + ELLIPSIS;
40
51
  }
52
+ /** Number of code points of `text` that fit in `budget` tokens.
53
+ *
54
+ * Walks from the front accumulating real cost rather than dividing by an
55
+ * average: the two scripts price an order of magnitude apart (CJK 1.0,
56
+ * Latin 0.3), so an average is wrong for any mixed string and silently
57
+ * overshoots on the CJK-heavy ones this exists to serve. */
58
+ function charsWithin(text, budget) {
59
+ if (budget <= 0)
60
+ return 0;
61
+ let used = 0;
62
+ let count = 0;
63
+ for (const ch of text) {
64
+ used += CJK_REGEX.test(ch) ? 1 : 0.3;
65
+ if (Math.ceil(used) > budget)
66
+ break;
67
+ count++;
68
+ }
69
+ return count;
70
+ }
41
71
  /**
42
72
  * Apply a token budget to a list of row-like objects with a `content` field.
43
73
  * Per-row content is truncated to perRowCharCap (ellipsis-aware), cumulative
@@ -47,27 +77,101 @@ export function truncateToChars(text, maxChars) {
47
77
  * Callers should touch/log only `emitted` ids — dropped rows never reached
48
78
  * the client.
49
79
  */
50
- export function applyRowBudget(rows, maxTokens = DEFAULT_MAX_TOKENS, perRowCharCap = DEFAULT_PER_ROW_CHAR_CAP) {
80
+ export function applyRowBudget(rows, maxTokens = DEFAULT_MAX_TOKENS, perRowCharCap = DEFAULT_PER_ROW_CHAR_CAP, options = {}) {
81
+ const costOf = options.costOf ?? ((clipped) => approximateTokens(clipped));
82
+ const reserved = options.reservedTokens ?? 0;
51
83
  const emitted = [];
52
- let used = 0;
84
+ let used = reserved;
53
85
  let truncated = false;
54
86
  for (let i = 0; i < rows.length; i++) {
55
87
  const row = rows[i];
56
88
  const clipped = truncateToChars(row.content, perRowCharCap);
57
89
  if (clipped !== row.content)
58
90
  truncated = true;
59
- const cost = approximateTokens(clipped);
91
+ const cost = costOf(clipped, row);
60
92
  if (used + cost > maxTokens) {
61
- return {
62
- emitted,
63
- droppedCount: rows.length - i,
64
- usedTokens: used,
65
- truncated,
66
- };
93
+ // The floor applies only to the first row: once something has been
94
+ // emitted, silence is no longer the failure mode this guards against.
95
+ if (options.minimumOneRow && emitted.length === 0) {
96
+ const trimmed = trimToBudget(clipped, row, maxTokens - used, costOf, perRowCharCap);
97
+ if (trimmed !== null) {
98
+ emitted.push({ ...row, content: trimmed });
99
+ return {
100
+ emitted,
101
+ droppedCount: rows.length - 1,
102
+ usedTokens: used + costOf(trimmed, row),
103
+ truncated: true,
104
+ };
105
+ }
106
+ }
107
+ return { emitted, droppedCount: rows.length - i, usedTokens: used, truncated };
67
108
  }
68
109
  emitted.push({ ...row, content: clipped });
69
110
  used += cost;
70
111
  }
71
112
  return { emitted, droppedCount: 0, usedTokens: used, truncated };
72
113
  }
114
+ // ── What the hooks actually render ──────────────────────────────────────────
115
+ //
116
+ // These mirror `formatStartupV1` in hooks/session-start.mjs and `formatRecall`
117
+ // in hooks/user-prompt-submit.mjs. Two copies of a format is how they drift
118
+ // apart, so tests/token-budget-honesty.test.ts spawns the real hooks and
119
+ // asserts the prediction against their actual stdout. Change a hook's
120
+ // rendering and that test fails — which is the point.
121
+ /** A key longer than this is dropped by both hooks rather than truncated, so
122
+ * it costs nothing. Mirrors MAX_KEY_CHARS in both hook files. */
123
+ export const MAX_KEY_CHARS = 60;
124
+ /** Header, blank lines and footer the startup hook wraps around the rows.
125
+ * Sized against the longest footer variant (the one carrying the corpus
126
+ * count), so the reservation cannot come up short as the corpus grows. */
127
+ export const STARTUP_CHROME_TOKENS = 52;
128
+ /** Same for the mid-conversation hook, whose footer is a single short line. */
129
+ export const PROMPT_CHROME_TOKENS = 31;
130
+ function handleFor(row) {
131
+ return row.key && row.key.length <= MAX_KEY_CHARS ? ` [key: ${row.key}]` : '';
132
+ }
133
+ /** Cost of one startup line: `- <content>[ (conf N.NN)][ [key: …]]` plus the
134
+ * newline joining it to the previous line. */
135
+ export function startupLineCost(clipped, row) {
136
+ const conf = row.confidence != null && row.confidence !== 1
137
+ ? ` (conf ${Number(row.confidence).toFixed(2)})`
138
+ : '';
139
+ return approximateTokens(`- ${clipped}${conf}${handleFor(row)}`) + 1;
140
+ }
141
+ /** Cost of one mid-conversation line. No confidence suffix — that hook does
142
+ * not render one. */
143
+ export function promptLineCost(clipped, row) {
144
+ return approximateTokens(`- ${clipped}${handleFor(row)}`) + 1;
145
+ }
146
+ /** Longest prefix of `clipped` whose *rendered* cost fits `budget`, or null if
147
+ * even a minimal one does not.
148
+ *
149
+ * Budgets against the rendered cost, not the content's own: the decoration is
150
+ * charged per row whether the content is 150 characters or 5, so trimming
151
+ * against the raw length would overshoot by exactly the amount this change
152
+ * exists to stop hiding. Returns null rather than an empty string — an empty
153
+ * bullet costs the reader a line and tells them nothing. */
154
+ function trimToBudget(clipped, row, budget, costOf, perRowCharCap) {
155
+ if (budget <= 0)
156
+ return null;
157
+ const overhead = costOf('', row);
158
+ let chars = Math.min(charsWithin(clipped, budget - overhead), perRowCharCap);
159
+ // charsWithin works off raw content cost; the ellipsis truncateToChars adds
160
+ // and any rounding in costOf can still push it over. Walk down until it fits
161
+ // rather than trusting the estimate.
162
+ //
163
+ // Stops at MIN_TRIMMED_CHARS rather than 1: truncateToChars(text, 1) returns
164
+ // the ellipsis alone, and a bullet reading "- …" costs the reader a line to
165
+ // learn nothing. Below the floor there is no row worth emitting.
166
+ while (chars >= MIN_TRIMMED_CHARS) {
167
+ const candidate = truncateToChars(clipped, chars);
168
+ if (costOf(candidate, row) <= budget)
169
+ return candidate;
170
+ chars--;
171
+ }
172
+ return null;
173
+ }
174
+ /** Shortest trimmed row worth emitting. Under this the line is an ellipsis and
175
+ * a word or two — it occupies a slot and conveys nothing. */
176
+ const MIN_TRIMMED_CHARS = 12;
73
177
  //# sourceMappingURL=token-budget.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"token-budget.js","sourceRoot":"","sources":["../../src/core/token-budget.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;GAGG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAA;AACrC,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAA;AAE3C,MAAM,SAAS,GAAG,0EAA0E,CAAA;AAE5F;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,GAAG,GAAG,CAAC,CAAA;IACX,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,GAAG,EAAE,CAAA;;YACxB,KAAK,EAAE,CAAA;IACd,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC,CAAA;AACrC,CAAC;AAED,MAAM,QAAQ,GAAG,GAAG,CAAA;AAEpB;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAgB;IAC5D,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAA;IACzC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAA;IACnC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAA;AACzD,CAAC;AAaD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAS,EACT,YAAoB,kBAAkB,EACtC,gBAAwB,wBAAwB;IAEhD,MAAM,OAAO,GAAQ,EAAE,CAAA;IACvB,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;QAC3D,IAAI,OAAO,KAAK,GAAG,CAAC,OAAO;YAAE,SAAS,GAAG,IAAI,CAAA;QAC7C,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;QACvC,IAAI,IAAI,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO;gBACP,YAAY,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC;gBAC7B,UAAU,EAAE,IAAI;gBAChB,SAAS;aACV,CAAA;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,EAAO,CAAC,CAAA;QAC/C,IAAI,IAAI,IAAI,CAAA;IACd,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;AAClE,CAAC"}
1
+ {"version":3,"file":"token-budget.js","sourceRoot":"","sources":["../../src/core/token-budget.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;;;GAMG;AAEH;;;;;;;+EAO+E;AAC/E,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAA;AACrC,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAA;AAE3C,MAAM,SAAS,GAAG,0EAA0E,CAAA;AAE5F;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,GAAG,GAAG,CAAC,CAAA;IACX,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,GAAG,EAAE,CAAA;;YACxB,KAAK,EAAE,CAAA;IACd,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC,CAAA;AACrC,CAAC;AAED,MAAM,QAAQ,GAAG,GAAG,CAAA;AAEpB;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,QAAgB;IAC5D,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAA;IACzC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAA;IACnC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAA;AACzD,CAAC;AAqCD;;;;;6DAK6D;AAC7D,SAAS,WAAW,CAAC,IAAY,EAAE,MAAc;IAC/C,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACzB,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QACpC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,MAAM;YAAE,MAAK;QACnC,KAAK,EAAE,CAAA;IACT,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAS,EACT,YAAoB,kBAAkB,EACtC,gBAAwB,wBAAwB,EAChD,UAA4B,EAAE;IAE9B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAA;IAClF,MAAM,QAAQ,GAAG,OAAO,CAAC,cAAc,IAAI,CAAC,CAAA;IAC5C,MAAM,OAAO,GAAQ,EAAE,CAAA;IACvB,IAAI,IAAI,GAAG,QAAQ,CAAA;IACnB,IAAI,SAAS,GAAG,KAAK,CAAA;IAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;QAC3D,IAAI,OAAO,KAAK,GAAG,CAAC,OAAO;YAAE,SAAS,GAAG,IAAI,CAAA;QAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QAEjC,IAAI,IAAI,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC;YAC5B,mEAAmE;YACnE,sEAAsE;YACtE,IAAI,OAAO,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClD,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,CAAA;gBACnF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACrB,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,EAAO,CAAC,CAAA;oBAC/C,OAAO;wBACL,OAAO;wBACP,YAAY,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC;wBAC7B,UAAU,EAAE,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC;wBACvC,SAAS,EAAE,IAAI;qBAChB,CAAA;gBACH,CAAC;YACH,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;QAChF,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,OAAO,EAAO,CAAC,CAAA;QAC/C,IAAI,IAAI,IAAI,CAAA;IACd,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;AAClE,CAAC;AAED,+EAA+E;AAC/E,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,yEAAyE;AACzE,sEAAsE;AACtE,sDAAsD;AAEtD;kEACkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAA;AAE/B;;2EAE2E;AAC3E,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAA;AAEvC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAA;AAUtC,SAAS,SAAS,CAAC,GAAiB;IAClC,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;AAC/E,CAAC;AAED;+CAC+C;AAC/C,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,GAAiB;IAChE,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,IAAI,IAAI,IAAI,GAAG,CAAC,UAAU,KAAK,CAAC;QACzD,CAAC,CAAC,UAAU,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;QAChD,CAAC,CAAC,EAAE,CAAA;IACN,OAAO,iBAAiB,CAAC,KAAK,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;AACtE,CAAC;AAED;sBACsB;AACtB,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,GAAiB;IAC/D,OAAO,iBAAiB,CAAC,KAAK,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;AAC/D,CAAC;AAED;;;;;;;6DAO6D;AAC7D,SAAS,YAAY,CACnB,OAAe,EACf,GAAM,EACN,MAAc,EACd,MAAoB,EACpB,aAAqB;IAErB,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;IAChC,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAA;IAC5E,4EAA4E;IAC5E,6EAA6E;IAC7E,qCAAqC;IACrC,EAAE;IACF,6EAA6E;IAC7E,4EAA4E;IAC5E,iEAAiE;IACjE,OAAO,KAAK,IAAI,iBAAiB,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QACjD,IAAI,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,MAAM;YAAE,OAAO,SAAS,CAAA;QACtD,KAAK,EAAE,CAAA;IACT,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;8DAC8D;AAC9D,MAAM,iBAAiB,GAAG,EAAE,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { Database } from '../core/database.js';
2
+ import type { Database, MemoryOrigin } from '../core/database.js';
3
3
  import { MemoryService } from '../core/memory-service.js';
4
4
  import type { Memory, MemoryType, KnowledgeDepth } from '../core/types.js';
5
5
  type McpTextResult = {
@@ -41,6 +41,7 @@ export declare function recallSaveHandler(db: Database, args: {
41
41
  confidence?: number;
42
42
  projectId?: string | null;
43
43
  key?: string;
44
+ origin?: MemoryOrigin;
44
45
  }): McpTextResult;
45
46
  export declare function registerTools(server: McpServer, db: Database): void;
46
47
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAiB1E,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9C,OAAO,CAAC,EAAE,IAAI,CAAA;CACf,CAAA;AAmDD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAA2B,GACrC,eAAe,CAMjB;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,EACZ,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,aAAa,CAsBf;AAgBD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,cAAc,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EAAE,EACxB,iBAAiB,EAAE,MAAM,EAAE,EAC3B,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,EACjC,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,GAAE,MAA2B,GACrC,eAAe,CAmDjB;AAiBD,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,EACZ,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF,aAAa,CA2Df;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,UAAU,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,GACA,aAAa,CAqCf;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CA4InE"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAiB1E,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9C,OAAO,CAAC,EAAE,IAAI,CAAA;CACf,CAAA;AAmDD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAA2B,GACrC,eAAe,CAMjB;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,EACZ,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7E,aAAa,CAsBf;AA+BD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,cAAc,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EAAE,EACxB,iBAAiB,EAAE,MAAM,EAAE,EAC3B,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,EACjC,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,GAAE,MAA2B,GACrC,eAAe,CAmDjB;AAiBD,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,EACZ,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF,aAAa,CA+Df;AAED,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,UAAU,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB,GACA,aAAa,CA2Ef;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAkJnE"}
package/dist/mcp/tools.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  import * as z from 'zod';
3
+ import { normaliseMessageUuid } from '../core/database.js';
3
4
  import { MemoryService } from '../core/memory-service.js';
4
5
  import { deriveDepth } from '../core/types.js';
5
6
  import { normalizeTopicKey, extractTopicsFromContent } from '../core/topic-extractor.js';
@@ -83,10 +84,21 @@ const recallSaveInput = {
83
84
  content: z.string().min(1).describe('Memory content — the fact or insight to remember'),
84
85
  type: z.enum(MEMORY_TYPES).describe('Memory category'),
85
86
  sessionId: z.string().nullable().optional().describe('Origin session ID (optional)'),
86
- messageId: z.string().nullable().optional().describe('Origin message ID (optional)'),
87
+ messageId: z.string().nullable().optional().describe('The uuid of the single message this memory came from. Post-session ' +
88
+ 'extraction reads it from the transcript header (`--- human [<uuid>] ---`). ' +
89
+ 'Checked against the messages of the session named in sessionId: a uuid ' +
90
+ 'that session does not hold is dropped and the memory is saved without it, ' +
91
+ 'so omit this rather than guess. Storing a citation does not assert that ' +
92
+ 'the cited message proves the memory — it records where it came from.'),
87
93
  confidence: z.number().min(0).max(1).optional().describe('Confidence 0-1 (default 1)'),
88
94
  projectId: z.string().nullable().optional().describe('Project ID for scoped queries. Session-backed memories derive this from sessions.project_id automatically. Omit projectId for knowledge reusable across all projects.'),
89
95
  key: z.string().min(1).max(100).optional().describe('Stable hyphenated slug for dedup (e.g. "sqlite-wal-truncate-checkpoint"). Same (projectId, key) updates instead of creating a duplicate.'),
96
+ origin: z.enum(['explicit', 'agent-inferred']).optional().describe('Who is writing. Leave unset (defaults to "explicit") whenever a human is in ' +
97
+ 'the conversation — including when you decide on your own that something is ' +
98
+ 'worth saving mid-session. Set "agent-inferred" ONLY from the automated ' +
99
+ 'post-session extraction pass, which reads a finished transcript with nobody ' +
100
+ 'watching. The difference is enforced: an agent-inferred save will not ' +
101
+ 'overwrite an existing explicit memory under the same key.'),
90
102
  };
91
103
  export function formatContextResult(clusters, unmatchedKeywords, fallbackMemories, keywords, maxTokens = DEFAULT_MAX_TOKENS) {
92
104
  if (clusters.length === 0 && (!fallbackMemories || fallbackMemories.length === 0)) {
@@ -174,8 +186,12 @@ export function recallContextHandler(db, memoryService, args) {
174
186
  memories,
175
187
  });
176
188
  }
177
- // FTS fallback if no topic matched — per-keyword union (queryMemories quotes every
178
- // token into a phrase, so "foo OR bar" collapses to a phrase query, not a boolean OR)
189
+ // FTS fallback if no topic matched — per-keyword union in caller order.
190
+ // queryMemories now OR-joins its own terms, so a single combined call would
191
+ // also return matches; the loop is kept because it preserves each keyword's
192
+ // own ranking instead of letting one global BM25 sort reorder everything.
193
+ // This is keyword *priority*, not fair coverage: the aggregate limit can be
194
+ // exhausted by the first keyword alone, leaving later keywords unqueried.
179
195
  let fallback = null;
180
196
  if (clusters.length === 0 && args.keywords.length > 0) {
181
197
  const seen = new Set();
@@ -207,14 +223,50 @@ export function recallContextHandler(db, memoryService, args) {
207
223
  }
208
224
  export function recallSaveHandler(db, args) {
209
225
  try {
226
+ // Q1 (2026-09-11): a citation is stored only if this session really holds
227
+ // that message. The model is a small one copying a 36-char hex string out
228
+ // of a 200KB transcript, so the failure to design against is not refusal
229
+ // but a plausible-looking wrong value — `message_id` reads as evidence,
230
+ // and evidence that can be invented is worse than an empty column.
231
+ //
232
+ // Verification failure drops the citation and keeps the memory: provenance
233
+ // is additive, never a gate on content. The note back to the caller says
234
+ // so explicitly, because an extraction run has a hard turn budget
235
+ // (--max-turns 5) and a retry loop would cost saves it has not made yet.
236
+ let messageId = null;
237
+ let provenanceNote = '';
238
+ const citedMessageId = normaliseMessageUuid(args.messageId);
239
+ if (citedMessageId !== null) {
240
+ if (db.hasMessageUuid(citedMessageId, args.sessionId ?? null)) {
241
+ messageId = citedMessageId;
242
+ }
243
+ else {
244
+ // Where this trace actually lands (measured 2026-09-11): NOT in the
245
+ // extraction wrapper's extract.log.jsonl. Claude Code does not forward
246
+ // an MCP server's stderr to its own — it captures it into a per-project
247
+ // MCP log, on macOS ~/Library/Caches/claude-cli-nodejs/<projectId>/
248
+ // mcp-logs-ccrecall/<ts>.jsonl, one entry per line prefixed
249
+ // `Server stderr:`. Measured against the banner every launch prints:
250
+ // 0 of 590 wrapper runs captured it, while the MCP log holds it every
251
+ // time. Look in the wrong file and a dropped citation reads as
252
+ // byte-identical to a model that never cited anything — the same
253
+ // silent-miss shape #75 took months to notice.
254
+ console.warn('[recall_save] messageId failed verification (unknown uuid, or a message ' +
255
+ 'from a different session) — provenance dropped, memory saved');
256
+ provenanceNote =
257
+ ' — the supplied messageId is not a message of this session and was dropped; ' +
258
+ 'the memory itself is saved, so do not retry';
259
+ }
260
+ }
210
261
  const id = db.saveMemory({
211
262
  sessionId: args.sessionId ?? null,
212
- messageId: args.messageId ?? null,
263
+ messageId,
213
264
  content: args.content,
214
265
  type: args.type,
215
266
  confidence: args.confidence ?? 1,
216
267
  projectId: args.projectId ?? null,
217
268
  key: args.key ?? null,
269
+ origin: args.origin,
218
270
  });
219
271
  // Auto topic extraction — Phase 3 Tier 0 needs memory_topics to exist.
220
272
  // Resolve projectId the same way saveMemory does (session-backed →
@@ -238,7 +290,7 @@ export function recallSaveHandler(db, args) {
238
290
  console.warn('[recall_save] topic extraction failed:', err instanceof Error ? err.message : String(err));
239
291
  }
240
292
  }
241
- return textResult(`Saved memory #${id} (type: ${args.type})`);
293
+ return textResult(`Saved memory #${id} (type: ${args.type})${provenanceNote}`);
242
294
  }
243
295
  catch (err) {
244
296
  return textError('Error saving memory', err);
@@ -280,13 +332,19 @@ export function registerTools(server, db) {
280
332
  '- Before concluding "X does not work" or "we should do Y instead"',
281
333
  '',
282
334
  'HOW TO PHRASE THE QUERY:',
283
- '- Give MORE terms rather than fewer. The index is trigram-based and',
284
- ' ranked by BM25, which discriminates by how many query terms a',
285
- ' document matches — a broad OR query ranks better than a narrow one.',
286
- ' Do not use AND; it collapses the result set.',
287
- '- Use English technical terms. Memory content is predominantly',
288
- ' English and the tokenizer is trigram, so CJK queries return nothing.',
289
- ' Translate the concept before searching.',
335
+ '- Give MORE terms rather than fewer. Terms are OR-joined, so extra',
336
+ ' terms widen recall rather than narrowing it, and BM25 ranks by how',
337
+ ' many terms a document matches — a broad query beats a narrow one.',
338
+ '- Do not type AND / OR / NEAR yourself. Every term is quoted as a',
339
+ ' literal to block operator injection, so an operator you type is',
340
+ ' just one more meaningless search word.',
341
+ '- Each term needs 3+ characters. The trigram tokenizer cannot index',
342
+ ' anything shorter, in ANY language — `UI` and `DB` fail exactly as',
343
+ ' `記憶` does. CJK is not excluded: 3-character terms match fine.',
344
+ ' (An all-short query falls back to a substring scan that ANDs the',
345
+ ' terms, so keep those queries to one or two terms.)',
346
+ '- Prefer English technical terms — memory content is predominantly',
347
+ ' English, so an English query simply has more to match.',
290
348
  '- Search the GENERAL name of a pattern, not this project\'s own names.',
291
349
  ' Project nouns pull local results to the top and bury the rest.',
292
350
  '',
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACxF,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AAEnE,sEAAsE;AACtE,sEAAsE;AACtE,MAAM,sBAAsB,GAAG,EAAE,CAAA;AAEjC,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAU,CAAA;AAOrG,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;AACvD,CAAC;AAED,SAAS,SAAS,CAAC,MAAc,EAAE,GAAY;IAC7C,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC5D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,GAAG,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC3F,CAAC;AAED,MAAM,gBAAgB,GAAG;IACvB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;IAC3E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CACnC,gFAAgF;QAChF,+EAA+E;QAC/E,wEAAwE;QACxE,uEAAuE;QACvE,uDAAuD,CACxD;IACD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IAClG,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAClE,kDAAkD,kBAAkB,6FAA6F,CAClK;CACF,CAAA;AAED,SAAS,gBAAgB,CAAC,CAAS;IACjC,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IAC3E,OAAO,MAAM,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,eAAe,CAAC,CAAC,CAAC,OAAO,EAAE,wBAAwB,CAAC,EAAE,CAAA;AACvF,CAAC;AAED,SAAS,gBAAgB,CACvB,QAAkB,EAClB,MAAc;IAEd,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QAC1C,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACpC,IAAI,IAAI,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;YACzB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;QAC5E,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAChB,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC7B,IAAI,IAAI,IAAI,CAAA;IACd,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;AAC1D,CAAC;AAOD,MAAM,UAAU,cAAc,CAC5B,QAAkB,EAClB,KAAa,EACb,YAAoB,kBAAkB;IAEtC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,0BAA0B,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAA;IAC7F,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,sBAAsB,CAAC,CAAA;IACpE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;IAC7E,IAAI,OAAO,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,OAAO,2BAA2B,CAAC,CAAA;IACxE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,EAAY,EACZ,aAA4B,EAC5B,IAA8E;IAE9E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAA;IAC9B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QACpE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QACjF,kEAAkE;QAClE,sEAAsE;QACtE,wDAAwD;QACxD,aAAa,CAAC,KAAK,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;QAC/C,qEAAqE;QACrE,0EAA0E;QAC1E,qBAAqB,CAAC;YACpB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,UAAU,CAAC,MAAM;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;SAClC,CAAC,CAAA;QACF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,SAAS,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAA;IAClD,CAAC;AACH,CAAC;AAED,MAAM,eAAe,GAAG;IACtB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,kDAAkD,CAAC;IACvF,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IACtD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IACpF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAClD,qEAAqE;QACrE,6EAA6E;QAC7E,yEAAyE;QACzE,4EAA4E;QAC5E,0EAA0E;QAC1E,sEAAsE,CACvE;IACD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;IACtF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAClD,uKAAuK,CACxK;IACD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CACjD,0IAA0I,CAC3I;IACD,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAChE,8EAA8E;QAC9E,6EAA6E;QAC7E,yEAAyE;QACzE,8EAA8E;QAC9E,wEAAwE;QACxE,2DAA2D,CAC5D;CACF,CAAA;AASD,MAAM,UAAU,mBAAmB,CACjC,QAAwB,EACxB,iBAA2B,EAC3B,gBAAiC,EACjC,QAAkB,EAClB,YAAoB,kBAAkB;IAEtC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,gBAAgB,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAClF,OAAO,EAAE,IAAI,EAAE,6BAA6B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAA;IACrF,CAAC;IACD,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,sBAAsB,CAAC,CAAA;IAC/D,MAAM,UAAU,GAAG,4BAA4B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;IACpE,SAAS,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAC1C,MAAM,KAAK,GAAa,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IACxC,MAAM,UAAU,GAAa,EAAE,CAAA;IAC/B,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,YAAY,YAAY,CAAA;QACrF,MAAM,UAAU,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAA;QACnD,IAAI,SAAS,GAAG,UAAU,EAAE,CAAC;YAC3B,YAAY,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAA;YACjC,SAAQ;QACV,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QACzB,SAAS,IAAI,UAAU,CAAA;QACvB,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QACxC,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;YACtD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;YAC3B,SAAS,IAAI,MAAM,CAAC,UAAU,CAAA;YAC9B,YAAY,IAAI,MAAM,CAAC,OAAO,CAAA;YAC9B,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChB,CAAC;IACD,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,kCAAkC,CAAA;QACnD,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;QAC9C,IAAI,SAAS,GAAG,UAAU,EAAE,CAAC;YAC3B,YAAY,IAAI,gBAAgB,CAAC,MAAM,CAAA;QACzC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACpB,MAAM,MAAM,GAAG,gBAAgB,CAAC,gBAAgB,EAAE,SAAS,GAAG,UAAU,CAAC,CAAA;YACzE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;YAC3B,YAAY,IAAI,MAAM,CAAC,OAAO,CAAA;YAC9B,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;YACnC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAChB,CAAC;IACH,CAAC;IACD,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,SAAS,YAAY,2BAA2B,CAAC,CAAA;IAC9D,CAAC;IACD,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,wBAAwB,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACrE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,CAAA;AACzD,CAAC;AAED,MAAM,kBAAkB,GAAG;IACzB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CACnC,gFAAgF;QAChF,+EAA+E;QAC/E,wEAAwE;QACxE,uEAAuE;QACvE,uDAAuD,CACxD;IACD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,uDAAuD,CAAC;IAC7G,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;IAC1G,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAClE,kDAAkD,kBAAkB,6FAA6F,CAClK;CACF,CAAA;AAED,MAAM,UAAU,oBAAoB,CAClC,EAAY,EACZ,aAA4B,EAC5B,IAAyF;IAEzF,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAA;QACzC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ;aAC7B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;aACjD,MAAM,CAAC,CAAC,CAAC,EAAqC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,CAAA;QAEnE,MAAM,QAAQ,GAAmB,EAAE,CAAA;QACnC,MAAM,SAAS,GAAa,EAAE,CAAA;QAE9B,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,UAAU,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;YAC9C,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACnB,SAAQ;YACV,CAAC;YACD,MAAM,QAAQ,GAAG,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,CAAA;YAC3E,QAAQ,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,GAAG;gBACV,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC;gBACtC,YAAY,EAAE,KAAK,CAAC,YAAY;gBAChC,QAAQ;aACT,CAAC,CAAA;QACJ,CAAC;QAED,wEAAwE;QACxE,4EAA4E;QAC5E,4EAA4E;QAC5E,0EAA0E;QAC1E,4EAA4E;QAC5E,0EAA0E;QAC1E,IAAI,QAAQ,GAAoB,IAAI,CAAA;QACpC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;YAC9B,MAAM,UAAU,GAAa,EAAE,CAAA;YAC/B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC/B,IAAI,UAAU,CAAC,MAAM,IAAI,WAAW;oBAAE,MAAK;gBAC3C,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;gBACjE,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;oBACxB,IAAI,UAAU,CAAC,MAAM,IAAI,WAAW;wBAAE,MAAK;oBAC3C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;wBACpB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;wBACd,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;oBACpB,CAAC;gBACH,CAAC;YACH,CAAC;YACD,QAAQ,GAAG,UAAU,CAAA;QACvB,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,mBAAmB,CAC9C,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,SAAS,CACf,CAAA;QACD,kEAAkE;QAClE,0CAA0C;QAC1C,aAAa,CAAC,KAAK,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACjD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,SAAS,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAA;IACjD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,EAAY,EACZ,IASC;IAED,IAAI,CAAC;QACH,0EAA0E;QAC1E,0EAA0E;QAC1E,yEAAyE;QACzE,wEAAwE;QACxE,mEAAmE;QACnE,EAAE;QACF,2EAA2E;QAC3E,yEAAyE;QACzE,kEAAkE;QAClE,yEAAyE;QACzE,IAAI,SAAS,GAAkB,IAAI,CAAA;QACnC,IAAI,cAAc,GAAG,EAAE,CAAA;QACvB,MAAM,cAAc,GAAG,oBAAoB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC3D,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;YAC5B,IAAI,EAAE,CAAC,cAAc,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,EAAE,CAAC;gBAC9D,SAAS,GAAG,cAAc,CAAA;YAC5B,CAAC;iBAAM,CAAC;gBACN,oEAAoE;gBACpE,uEAAuE;gBACvE,wEAAwE;gBACxE,oEAAoE;gBACpE,4DAA4D;gBAC5D,qEAAqE;gBACrE,sEAAsE;gBACtE,+DAA+D;gBAC/D,iEAAiE;gBACjE,+CAA+C;gBAC/C,OAAO,CAAC,IAAI,CACV,0EAA0E;oBAC1E,8DAA8D,CAC/D,CAAA;gBACD,cAAc;oBACZ,8EAA8E;wBAC9E,6CAA6C,CAAA;YACjD,CAAC;QACH,CAAC;QAED,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;YACjC,SAAS;YACT,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC;YAChC,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;YACjC,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAA;QAEF,uEAAuE;QACvE,mEAAmE;QACnE,kEAAkE;QAClE,MAAM,SAAS,GAAG,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACxD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,IAAI,iBAAiB,GAAkB,IAAI,CAAC,SAAS,IAAI,IAAI,CAAA;YAC7D,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,IAAI,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;gBAC9C,IAAI,IAAI;oBAAE,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAA;YAC9C,CAAC;YACD,MAAM,cAAc,GAAG,iBAAiB,IAAI,EAAE,CAAA;YAC9C,IAAI,CAAC;gBACH,EAAE,CAAC,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,CAAC,CAAA;gBAClD,IAAI,cAAc,EAAE,CAAC;oBACnB,EAAE,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAA;gBACxC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,wCAAwC,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;YAC1G,CAAC;QACH,CAAC;QAED,OAAO,UAAU,CAAC,iBAAiB,EAAE,WAAW,IAAI,CAAC,IAAI,IAAI,cAAc,EAAE,CAAC,CAAA;IAChF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,SAAS,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAA;IAC9C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAiB,EAAE,EAAY;IAC3D,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,EAAE,CAAC,CAAA;IAC3C,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE;YACX,8DAA8D;YAC9D,EAAE;YACF,oEAAoE;YACpE,kEAAkE;YAClE,+DAA+D;YAC/D,4DAA4D;YAC5D,EAAE;YACF,wDAAwD;YACxD,uEAAuE;YACvE,wEAAwE;YACxE,wEAAwE;YACxE,yEAAyE;YACzE,oEAAoE;YACpE,EAAE;YACF,gBAAgB;YAChB,qEAAqE;YACrE,4DAA4D;YAC5D,+DAA+D;YAC/D,gCAAgC;YAChC,mDAAmD;YACnD,mEAAmE;YACnE,mCAAmC;YACnC,EAAE;YACF,uEAAuE;YACvE,oEAAoE;YACpE,yBAAyB;YACzB,uEAAuE;YACvE,qEAAqE;YACrE,mEAAmE;YACnE,EAAE;YACF,0BAA0B;YAC1B,oEAAoE;YACpE,sEAAsE;YACtE,qEAAqE;YACrE,mEAAmE;YACnE,mEAAmE;YACnE,0CAA0C;YAC1C,qEAAqE;YACrE,qEAAqE;YACrE,iEAAiE;YACjE,oEAAoE;YACpE,sDAAsD;YACtD,oEAAoE;YACpE,0DAA0D;YAC1D,wEAAwE;YACxE,kEAAkE;YAClE,EAAE;YACF,wEAAwE;SACzE,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE,gBAAgB;QAC7B,0EAA0E;QAC1E,yEAAyE;QACzE,wEAAwE;QACxE,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE;KAC5D,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,CAC5D,CAAA;IAED,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EAAE;YACX,2EAA2E;YAC3E,EAAE;YACF,mEAAmE;YACnE,qEAAqE;YACrE,qDAAqD;YACrD,EAAE;YACF,gBAAgB;YAChB,mEAAmE;YACnE,uCAAuC;YACvC,kEAAkE;YAClE,uDAAuD;YACvD,EAAE;YACF,kBAAkB;YAClB,sEAAsE;YACtE,uEAAuE;YACvE,0BAA0B;YAC1B,EAAE;YACF,uFAAuF;SACxF,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE,kBAAkB;QAC/B,0EAA0E;QAC1E,qEAAqE;QACrE,qDAAqD;QACrD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE;KAC5D,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,CAC9D,CAAA;IAED,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE;YACX,qEAAqE;YACrE,qDAAqD;YACrD,EAAE;YACF,eAAe;YACf,mEAAmE;YACnE,+DAA+D;YAC/D,kDAAkD;YAClD,oDAAoD;YACpD,4CAA4C;YAC5C,yEAAyE;YACzE,EAAE;YACF,oEAAoE;YACpE,mEAAmE;YACnE,mDAAmD;YACnD,EAAE;YACF,6DAA6D;YAC7D,kEAAkE;YAClE,sCAAsC;YACtC,oEAAoE;YACpE,mEAAmE;YACnE,gDAAgD;YAChD,wDAAwD;YACxD,EAAE;YACF,2DAA2D;YAC3D,4DAA4D;YAC5D,4EAA4E;YAC5E,EAAE;YACF,oEAAoE;YACpE,QAAQ;YACR,4CAA4C;YAC5C,kCAAkC;YAClC,wCAAwC;YACxC,gDAAgD;YAChD,0CAA0C;YAC1C,6EAA6E;YAC7E,EAAE;YACF,2CAA2C;SAC5C,CAAC,IAAI,CAAC,IAAI,CAAC;QACZ,WAAW,EAAE,eAAe;QAC5B,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE;KAC5D,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,CAC5C,CAAA;AACH,CAAC"}
@@ -0,0 +1,52 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ //
3
+ // #95: mode for the directory and files under ~/.ccrecall.
4
+ //
5
+ // ⚠️ Deliberately a second copy of src/core/secure-dir.ts. The hooks ship as
6
+ // standalone .mjs installed via npm and are never bundled through the
7
+ // TypeScript build, so importing the compiled module is not an option — the
8
+ // same reason hooks/lib/project-id.mjs exists beside src/core/project-id.ts.
9
+ // tests/ccrecall-dir-permissions.test.ts imports both and asserts they agree,
10
+ // which is what keeps them from drifting apart.
11
+ import { mkdirSync, chmodSync } from 'node:fs'
12
+ import os from 'node:os'
13
+ import path from 'node:path'
14
+
15
+ export const CCRECALL_DIR_MODE = 0o700
16
+ export const CCRECALL_FILE_MODE = 0o600
17
+
18
+ /** Resolved per call, never at module load: tests move $HOME, and a frozen
19
+ * value would answer about the real home directory instead. */
20
+ function isOurs(dir) {
21
+ const root = path.join(os.homedir(), '.ccrecall')
22
+ const resolved = path.resolve(dir)
23
+ return resolved === root || resolved.startsWith(root + path.sep)
24
+ }
25
+
26
+ /** Create a ccRecall directory 0700, and repair one we already own. */
27
+ export function ensureCcrecallDir(dir) {
28
+ mkdirSync(dir, { recursive: true, mode: CCRECALL_DIR_MODE })
29
+ // Existing directories keep their mode through mkdirSync, so the repair is
30
+ // what reaches installs that predate this. Limited to paths we own: PR #94
31
+ // re-moded a user's project directory by doing this to a configurable path
32
+ // and was reverted twice.
33
+ if (isOurs(dir)) {
34
+ try {
35
+ chmodSync(dir, CCRECALL_DIR_MODE)
36
+ } catch {
37
+ // Raced away or owned by another user; a mode must never fail the hook.
38
+ }
39
+ }
40
+ }
41
+
42
+ /** Hold a ccRecall file at 0600, whoever chose its location. */
43
+ export function secureCcrecallFile(file) {
44
+ // Unconditional: a user-chosen location does not make the file someone
45
+ // else's. Also the only thing that repairs a log already at 0644, since the
46
+ // `mode` option applies solely when a file is created.
47
+ try {
48
+ chmodSync(file, CCRECALL_FILE_MODE)
49
+ } catch {
50
+ // Not there yet, or not ours.
51
+ }
52
+ }