@tznthou/ccrecall 0.7.2 → 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,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":"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"}
@@ -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,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;CACb,GACA,aAAa,CAqCf;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAkJnE"}
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)) {
@@ -211,14 +223,50 @@ export function recallContextHandler(db, memoryService, args) {
211
223
  }
212
224
  export function recallSaveHandler(db, args) {
213
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
+ }
214
261
  const id = db.saveMemory({
215
262
  sessionId: args.sessionId ?? null,
216
- messageId: args.messageId ?? null,
263
+ messageId,
217
264
  content: args.content,
218
265
  type: args.type,
219
266
  confidence: args.confidence ?? 1,
220
267
  projectId: args.projectId ?? null,
221
268
  key: args.key ?? null,
269
+ origin: args.origin,
222
270
  });
223
271
  // Auto topic extraction — Phase 3 Tier 0 needs memory_topics to exist.
224
272
  // Resolve projectId the same way saveMemory does (session-backed →
@@ -242,7 +290,7 @@ export function recallSaveHandler(db, args) {
242
290
  console.warn('[recall_save] topic extraction failed:', err instanceof Error ? err.message : String(err));
243
291
  }
244
292
  }
245
- return textResult(`Saved memory #${id} (type: ${args.type})`);
293
+ return textResult(`Saved memory #${id} (type: ${args.type})${provenanceNote}`);
246
294
  }
247
295
  catch (err) {
248
296
  return textError('Error saving memory', err);
@@ -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":"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"}
@@ -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
+ }
@@ -13,11 +13,14 @@ import fs from 'node:fs'
13
13
  import path from 'node:path'
14
14
  import os from 'node:os'
15
15
  import { resolveProjectId } from './lib/project-id.mjs'
16
+ import { ensureCcrecallDir, secureCcrecallFile, CCRECALL_FILE_MODE } from './lib/secure-dir.mjs'
16
17
 
17
18
  const PORT = Number(process.env.CCRECALL_PORT ?? 7749)
18
19
  const HOST = '127.0.0.1'
19
20
  const TIMEOUT_MS = 2000
20
21
  const MEMORY_LIMIT = 5
22
+ // Legacy strategy only. /memory/query treats an absent maxTokens as "no budget
23
+ // at all" and would emit whole memories, so this one still has to be sent.
21
24
  const MAX_TOKENS = 300
22
25
  // A key longer than this is not rendered at all rather than truncated: a clipped
23
26
  // key is a handle that silently resolves to nothing. Observed keys run to 52
@@ -82,11 +85,16 @@ async function queryLegacy(query, projectId) {
82
85
  }
83
86
 
84
87
  async function queryStartupV1(query, projectId, sessionId) {
88
+ // No maxTokens: the daemon owns budget policy, same as the prompt hook. It
89
+ // prices the rendered line — prefix, confidence suffix, [key: …] handle,
90
+ // header and footer — and this file is the thing being priced, so it cannot
91
+ // be the one naming the number. It also means an upgrade to the service
92
+ // changes the budget without rewriting a hook already installed in the
93
+ // user's settings.json.
85
94
  const params = new URLSearchParams({
86
95
  project: projectId,
87
96
  q: query,
88
97
  limit: String(MEMORY_LIMIT),
89
- maxTokens: String(MAX_TOKENS),
90
98
  })
91
99
  if (sessionId) params.set('sessionId', sessionId)
92
100
  const result = await httpGet(`/memory/startup?${params.toString()}`)
@@ -101,8 +109,17 @@ async function queryStartupV1(query, projectId, sessionId) {
101
109
  function writeTelemetry(record) {
102
110
  if (TELEMETRY_OFF) return
103
111
  try {
104
- fs.mkdirSync(path.dirname(TELEMETRY_PATH), { recursive: true })
105
- fs.appendFileSync(TELEMETRY_PATH, JSON.stringify(record) + '\n', 'utf8')
112
+ // #95: this hook runs on every session start, which made it the creator
113
+ // that in practice decided ~/.ccrecall's mode — 0755 on the dogfood
114
+ // machine. secureCcrecallFile also repairs a log already sitting at 0644,
115
+ // which appendFileSync's own `mode` option would not: that applies only
116
+ // when the file is created.
117
+ ensureCcrecallDir(path.dirname(TELEMETRY_PATH))
118
+ fs.appendFileSync(TELEMETRY_PATH, JSON.stringify(record) + '\n', {
119
+ encoding: 'utf8',
120
+ mode: CCRECALL_FILE_MODE,
121
+ })
122
+ secureCcrecallFile(TELEMETRY_PATH)
106
123
  } catch (err) {
107
124
  console.error(`[ccRecall] telemetry write failed: ${err.message}`)
108
125
  }