claude-code-infinite 1.0.20 → 1.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +165 -30
  2. package/dist/auto-update-runner.d.ts +52 -0
  3. package/dist/auto-update-runner.d.ts.map +1 -0
  4. package/dist/auto-update-runner.js +307 -0
  5. package/dist/auto-update-runner.js.map +1 -0
  6. package/dist/auto-update-setup.d.ts +38 -0
  7. package/dist/auto-update-setup.d.ts.map +1 -0
  8. package/dist/auto-update-setup.js +72 -0
  9. package/dist/auto-update-setup.js.map +1 -0
  10. package/dist/auto-update.d.ts +170 -0
  11. package/dist/auto-update.d.ts.map +1 -0
  12. package/dist/auto-update.js +401 -0
  13. package/dist/auto-update.js.map +1 -0
  14. package/dist/claude-env.d.ts +14 -1
  15. package/dist/claude-env.d.ts.map +1 -1
  16. package/dist/claude-env.js +17 -1
  17. package/dist/claude-env.js.map +1 -1
  18. package/dist/cli-lifecycle.d.ts +4 -0
  19. package/dist/cli-lifecycle.d.ts.map +1 -1
  20. package/dist/cli-lifecycle.js +18 -0
  21. package/dist/cli-lifecycle.js.map +1 -1
  22. package/dist/cli-main.js +139 -19
  23. package/dist/cli-main.js.map +1 -1
  24. package/dist/config.d.ts +4 -0
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js.map +1 -1
  27. package/dist/count-tokens.d.ts +38 -3
  28. package/dist/count-tokens.d.ts.map +1 -1
  29. package/dist/count-tokens.js +94 -19
  30. package/dist/count-tokens.js.map +1 -1
  31. package/dist/diagnostics-schema.d.ts +44 -0
  32. package/dist/diagnostics-schema.d.ts.map +1 -0
  33. package/dist/diagnostics-schema.js +162 -0
  34. package/dist/diagnostics-schema.js.map +1 -0
  35. package/dist/diagnostics.d.ts +116 -0
  36. package/dist/diagnostics.d.ts.map +1 -0
  37. package/dist/diagnostics.js +316 -0
  38. package/dist/diagnostics.js.map +1 -0
  39. package/dist/first-tree.d.ts +11 -0
  40. package/dist/first-tree.d.ts.map +1 -0
  41. package/dist/first-tree.js +45 -0
  42. package/dist/first-tree.js.map +1 -0
  43. package/dist/hooks.d.ts +37 -0
  44. package/dist/hooks.d.ts.map +1 -1
  45. package/dist/hooks.js +69 -9
  46. package/dist/hooks.js.map +1 -1
  47. package/dist/memtree-finder.d.ts +11 -0
  48. package/dist/memtree-finder.d.ts.map +1 -1
  49. package/dist/memtree-finder.js +18 -0
  50. package/dist/memtree-finder.js.map +1 -1
  51. package/dist/memtree-links.d.ts +2 -0
  52. package/dist/memtree-links.d.ts.map +1 -1
  53. package/dist/memtree-links.js +4 -0
  54. package/dist/memtree-links.js.map +1 -1
  55. package/dist/memtree-mcp-config.d.ts.map +1 -1
  56. package/dist/memtree-mcp-config.js +4 -2
  57. package/dist/memtree-mcp-config.js.map +1 -1
  58. package/dist/memtree-mcp.d.ts +24 -4
  59. package/dist/memtree-mcp.d.ts.map +1 -1
  60. package/dist/memtree-mcp.js +47 -14
  61. package/dist/memtree-mcp.js.map +1 -1
  62. package/dist/memtree-tools.d.ts +17 -1
  63. package/dist/memtree-tools.d.ts.map +1 -1
  64. package/dist/memtree-tools.js +50 -2
  65. package/dist/memtree-tools.js.map +1 -1
  66. package/dist/memtree.d.ts +17 -1
  67. package/dist/memtree.d.ts.map +1 -1
  68. package/dist/memtree.js +62 -19
  69. package/dist/memtree.js.map +1 -1
  70. package/dist/notices.d.ts +6 -1
  71. package/dist/notices.d.ts.map +1 -1
  72. package/dist/notices.js +13 -1
  73. package/dist/notices.js.map +1 -1
  74. package/dist/prefix-store.js +3 -0
  75. package/dist/prefix-store.js.map +1 -1
  76. package/dist/proxy.d.ts +45 -3
  77. package/dist/proxy.d.ts.map +1 -1
  78. package/dist/proxy.js +193 -54
  79. package/dist/proxy.js.map +1 -1
  80. package/dist/reqlog.d.ts +27 -1
  81. package/dist/reqlog.d.ts.map +1 -1
  82. package/dist/reqlog.js.map +1 -1
  83. package/dist/request-sizing.d.ts +21 -2
  84. package/dist/request-sizing.d.ts.map +1 -1
  85. package/dist/request-sizing.js +60 -7
  86. package/dist/request-sizing.js.map +1 -1
  87. package/dist/resume-hint.d.ts +25 -0
  88. package/dist/resume-hint.d.ts.map +1 -0
  89. package/dist/resume-hint.js +36 -0
  90. package/dist/resume-hint.js.map +1 -0
  91. package/dist/token-estimate.d.ts +35 -0
  92. package/dist/token-estimate.d.ts.map +1 -0
  93. package/dist/token-estimate.js +97 -0
  94. package/dist/token-estimate.js.map +1 -0
  95. package/dist/update-check.d.ts +4 -3
  96. package/dist/update-check.d.ts.map +1 -1
  97. package/dist/update-check.js +4 -3
  98. package/dist/update-check.js.map +1 -1
  99. package/dist/update-lock.d.ts +68 -0
  100. package/dist/update-lock.d.ts.map +1 -0
  101. package/dist/update-lock.js +176 -0
  102. package/dist/update-lock.js.map +1 -0
  103. package/package.json +3 -3
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Client diagnostics: why a session stalls, without ever sending its content
3
+ * (polychat plans/2026-10-16_PLAN_ccc_client_diagnostics.md).
4
+ *
5
+ * What is sent: ccc / Claude Code / Node versions, install method, OS and arch,
6
+ * terminal type, locale, and lifecycle and error events made of enums, status
7
+ * codes, sizes and timings (diagnostics-schema.ts is the allowlist; polychat
8
+ * enforces it again). Never prompts, paths, hostnames, usernames, env values,
9
+ * keys or error message text.
10
+ *
11
+ * Hard constraints, like reqlog.ts: never throw and never block. Events go into
12
+ * a capped in-memory queue; batches are POSTed fire-and-forget (every
13
+ * FLUSH_INTERVAL_MS, after the sign-in prompt, and at shutdown under a short
14
+ * bound); a failed POST drops its batch.
15
+ *
16
+ * Off with CCC_NO_DIAGNOSTICS=1, `"diagnostics": false` in the config,
17
+ * DO_NOT_TRACK=1, or Claude Code's DISABLE_TELEMETRY /
18
+ * CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC.
19
+ */
20
+ import { randomUUID } from "node:crypto";
21
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
22
+ import * as os from "node:os";
23
+ import { join } from "node:path";
24
+ import { DIAGNOSTICS_SCHEMA, TERMINALS, TURN_TYPES, errnoName, errorClassName, sanitizeContext, sanitizeEvent, threePartVersion, } from "./diagnostics-schema.js";
25
+ export const DIAGNOSTICS_PATH = "/v1/ccc/diagnostics";
26
+ export const INSTALL_ID_FILE = "install_id";
27
+ export const FLUSH_INTERVAL_MS = 30_000;
28
+ export const MAX_QUEUE = 200;
29
+ export const BATCH_SIZE = 50;
30
+ export const SEND_TIMEOUT_MS = 3_000;
31
+ export const SHUTDOWN_FLUSH_MS = 1_000;
32
+ /** Repeats of one error kind (event + status) reported per process. */
33
+ export const MAX_REPEATS = 5;
34
+ const OPT_OUT_ENV = [
35
+ "CCC_NO_DIAGNOSTICS", "DO_NOT_TRACK", "DISABLE_TELEMETRY",
36
+ "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC",
37
+ ];
38
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
39
+ /** False when any opt-out is set. */
40
+ export function diagnosticsEnabled(env, config) {
41
+ if (config.diagnostics === false)
42
+ return false;
43
+ return !OPT_OUT_ENV.some((name) => envFlagSet(env[name]));
44
+ }
45
+ export class Diagnostics {
46
+ opts;
47
+ enabled;
48
+ /** True when this launch created the install id (the machine's first run). */
49
+ firstRun;
50
+ /** Events dropped because the queue was full. */
51
+ dropped = 0;
52
+ installId;
53
+ queue = [];
54
+ inFlight = new Set();
55
+ repeats = new Map();
56
+ context = {};
57
+ apiKey;
58
+ timer;
59
+ constructor(opts) {
60
+ this.opts = opts;
61
+ const env = opts.env ?? process.env;
62
+ let enabled = diagnosticsEnabled(env, opts.config ?? {});
63
+ const install = enabled ? readOrCreateInstallId(opts.configDir) : null;
64
+ if (install === null)
65
+ enabled = false;
66
+ this.enabled = enabled;
67
+ this.installId = install?.id ?? null;
68
+ this.firstRun = install?.created === true;
69
+ this.apiKey = opts.apiKey;
70
+ if (enabled)
71
+ this.context = sanitizeContext(environmentContext(env, opts.clientVersion));
72
+ }
73
+ setApiKey(apiKey) {
74
+ this.apiKey = apiKey;
75
+ }
76
+ /** Add context fields (allowlisted; later values win). */
77
+ setContext(fields) {
78
+ if (!this.enabled)
79
+ return;
80
+ try {
81
+ this.context = { ...this.context, ...sanitizeContext(fields) };
82
+ }
83
+ catch {
84
+ // Never break the caller.
85
+ }
86
+ }
87
+ record(name, fields = {}) {
88
+ if (!this.enabled)
89
+ return;
90
+ try {
91
+ const event = sanitizeEvent(name, fields, this.now());
92
+ if (event === null)
93
+ return;
94
+ if (this.queue.length >= (this.opts.maxQueue ?? MAX_QUEUE)) {
95
+ this.dropped++;
96
+ return;
97
+ }
98
+ this.queue.push(event);
99
+ }
100
+ catch {
101
+ // Never break the caller.
102
+ }
103
+ }
104
+ /** Like record, but at most MAX_REPEATS times per `key` in this process. */
105
+ recordLimited(key, name, fields = {}) {
106
+ const seen = this.repeats.get(key) ?? 0;
107
+ if (seen >= MAX_REPEATS)
108
+ return;
109
+ this.repeats.set(key, seen + 1);
110
+ this.record(name, fields);
111
+ }
112
+ /** Flush every FLUSH_INTERVAL_MS without keeping the process alive. */
113
+ start() {
114
+ if (!this.enabled || this.timer)
115
+ return;
116
+ this.timer = setInterval(() => this.flushNow(), this.opts.flushIntervalMs ?? FLUSH_INTERVAL_MS);
117
+ this.timer.unref();
118
+ }
119
+ /** Send what is queued now; fire-and-forget. */
120
+ flushNow() {
121
+ if (!this.enabled)
122
+ return;
123
+ while (this.queue.length > 0) {
124
+ this.track(this.send(this.queue.splice(0, BATCH_SIZE)));
125
+ }
126
+ }
127
+ /** Shutdown: send what is queued and wait for in-flight sends, at most `timeoutMs`. */
128
+ async flush(timeoutMs = SHUTDOWN_FLUSH_MS) {
129
+ if (this.timer)
130
+ clearInterval(this.timer);
131
+ this.timer = undefined;
132
+ this.flushNow();
133
+ if (this.inFlight.size === 0)
134
+ return;
135
+ let timer;
136
+ await Promise.race([
137
+ Promise.allSettled([...this.inFlight]),
138
+ new Promise((resolve) => {
139
+ timer = setTimeout(resolve, timeoutMs);
140
+ }),
141
+ ]);
142
+ if (timer)
143
+ clearTimeout(timer);
144
+ }
145
+ /** The exact JSON body a batch of these events is sent as (tests read it). */
146
+ batchBody(events) {
147
+ return JSON.stringify({
148
+ schema: DIAGNOSTICS_SCHEMA, install_id: this.installId, context: this.context, events,
149
+ });
150
+ }
151
+ async send(events) {
152
+ try {
153
+ const doFetch = this.opts.fetchImpl ?? fetch;
154
+ await doFetch(`${this.opts.baseUrl.replace(/\/$/, "")}${DIAGNOSTICS_PATH}`, {
155
+ method: "POST",
156
+ headers: this.headers(),
157
+ body: this.batchBody(events),
158
+ signal: AbortSignal.timeout(SEND_TIMEOUT_MS),
159
+ });
160
+ }
161
+ catch {
162
+ // Dropped: diagnostics never retry or surface errors.
163
+ }
164
+ }
165
+ headers() {
166
+ return {
167
+ "content-type": "application/json",
168
+ "x-client": this.opts.clientName,
169
+ "x-client-version": this.opts.clientVersion,
170
+ ...(this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {}),
171
+ };
172
+ }
173
+ track(sending) {
174
+ this.inFlight.add(sending);
175
+ void sending.finally(() => this.inFlight.delete(sending));
176
+ }
177
+ now() {
178
+ return (this.opts.now ?? Date.now)();
179
+ }
180
+ }
181
+ /**
182
+ * Tee for the request log: every record still goes to `inner` unchanged, and a
183
+ * few named numeric/enum fields of some records become diagnostics events.
184
+ * Records are never copied: they can hold content (client.systemHead, URLs).
185
+ */
186
+ export class DiagnosticsRequestSink {
187
+ inner;
188
+ diagnostics;
189
+ firstRequest = false;
190
+ firstTurn = false;
191
+ constructor(inner, diagnostics) {
192
+ this.inner = inner;
193
+ this.diagnostics = diagnostics;
194
+ }
195
+ log(record) {
196
+ this.inner?.log(record);
197
+ try {
198
+ this.observe(record);
199
+ }
200
+ catch {
201
+ // Diagnostics never break the request log.
202
+ }
203
+ }
204
+ observe(record) {
205
+ if (record.kind === "messages")
206
+ this.observeMessages(record);
207
+ else if (record.kind === "memtree")
208
+ this.observeMemtree(record);
209
+ }
210
+ observeMessages(rec) {
211
+ if (rec.turnType === "foreign")
212
+ return;
213
+ const ccVersion = threePartVersion(rec.client?.ccVersion);
214
+ if (ccVersion)
215
+ this.diagnostics.setContext({ cc_version: ccVersion });
216
+ const fields = {
217
+ status: rec.upstreamStatus, turn_type: turnType(rec.turnType), ttfb_ms: rec.ttfbMs,
218
+ total_ms: rec.totalMs, request_kb: kb(rec.requestBytes),
219
+ };
220
+ if (!this.firstRequest) {
221
+ this.firstRequest = true;
222
+ this.diagnostics.record("first_request", fields);
223
+ }
224
+ if (!this.firstTurn && rec.client?.turnOrigin === "human") {
225
+ this.firstTurn = true;
226
+ this.diagnostics.record("first_turn", fields);
227
+ }
228
+ this.observeMessageErrors(rec, fields);
229
+ }
230
+ observeMessageErrors(rec, fields) {
231
+ const status = rec.upstreamStatus;
232
+ if (typeof status === "number" && status >= 400) {
233
+ this.diagnostics.recordLimited(`upstream:${status}`, "upstream_error", fields);
234
+ }
235
+ if (rec.compress?.timedOut) {
236
+ this.diagnostics.recordLimited("compress_timeout", "compress_timeout", { ms: rec.compress.ms, request_kb: kb(rec.requestBytes) });
237
+ }
238
+ }
239
+ observeMemtree(rec) {
240
+ if (rec.ok)
241
+ return;
242
+ this.diagnostics.recordLimited(`memtree:${rec.status ?? "none"}`, "memtree_error", {
243
+ status: rec.status, index_only: rec.indexOnly, ms: rec.ms, request_kb: kb(rec.requestBytes),
244
+ });
245
+ }
246
+ }
247
+ /** Record a launcher error by code only: Node's errno and class name, never its message. */
248
+ export function recordError(diagnostics, code, err) {
249
+ const e = err;
250
+ diagnostics.record("error", {
251
+ code,
252
+ errno: errnoName(e?.code),
253
+ error_name: errorClassName(e?.name),
254
+ });
255
+ }
256
+ /** The install id, created (0600) on first use; null when it cannot be read or written. */
257
+ export function readOrCreateInstallId(configDir) {
258
+ const file = join(configDir, INSTALL_ID_FILE);
259
+ try {
260
+ const existing = readFileSync(file, "utf-8").trim();
261
+ if (UUID_RE.test(existing))
262
+ return { id: existing, created: false };
263
+ }
264
+ catch {
265
+ // Missing: create it below.
266
+ }
267
+ try {
268
+ mkdirSync(configDir, { recursive: true, mode: 0o700 });
269
+ const id = randomUUID();
270
+ writeFileSync(file, `${id}\n`, { mode: 0o600 });
271
+ chmodSync(file, 0o600);
272
+ return { id, created: true };
273
+ }
274
+ catch {
275
+ return null;
276
+ }
277
+ }
278
+ /** Environment context; every value is mapped onto an allowlisted shape. */
279
+ export function environmentContext(env, cccVersion) {
280
+ return {
281
+ ccc_version: threePartVersion(cccVersion),
282
+ node: threePartVersion(process.versions.node),
283
+ os: process.platform,
284
+ os_release: /^\d{1,4}(?:\.\d{1,6}){0,2}/.exec(os.release())?.[0],
285
+ arch: process.arch,
286
+ terminal: terminalName(env),
287
+ locale: localeName(),
288
+ wsl: process.platform === "linux" && (env.WSL_DISTRO_NAME !== undefined || env.WSL_INTEROP !== undefined),
289
+ };
290
+ }
291
+ export function terminalName(env) {
292
+ const raw = env.TERM_PROGRAM;
293
+ if (!raw)
294
+ return env.WT_SESSION ? "Windows_Terminal" : "none";
295
+ const known = TERMINALS.find((t) => t.toLowerCase() === raw.toLowerCase());
296
+ return known ?? "other";
297
+ }
298
+ export function localeName() {
299
+ try {
300
+ const locale = Intl.DateTimeFormat().resolvedOptions().locale;
301
+ return /^[a-z]{2,3}(?:-[A-Z][a-z]{3})?(?:-(?:[A-Z]{2}|\d{3}))?$/.test(locale) ? locale : "other";
302
+ }
303
+ catch {
304
+ return "other";
305
+ }
306
+ }
307
+ function turnType(value) {
308
+ return TURN_TYPES.includes(value) ? value : "other";
309
+ }
310
+ function kb(bytes) {
311
+ return typeof bytes === "number" ? Math.round(bytes / 1024) : undefined;
312
+ }
313
+ function envFlagSet(value) {
314
+ return value !== undefined && /^(1|true|yes|on)$/i.test(value.trim());
315
+ }
316
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { FirstTreeIntro } from "./hooks.js";
2
+ import type { MemtreeLinkStore } from "./memtree-links.js";
3
+ export declare const FIRST_TREE_MARKER_FILE = "first-tree-shown.json";
4
+ export declare class FirstTreeMarker implements FirstTreeIntro {
5
+ private readonly linkStore?;
6
+ readonly filePath: string;
7
+ constructor(linkStore?: Pick<MemtreeLinkStore, "hasOtherSession"> | undefined, filePath?: string);
8
+ isFirstEver(sessionId: string | undefined): boolean;
9
+ markShown(_sessionId: string | undefined): void;
10
+ }
11
+ //# sourceMappingURL=first-tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-tree.d.ts","sourceRoot":"","sources":["../src/first-tree.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAE9D,qBAAa,eAAgB,YAAW,cAAc;IAElD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM;gBADR,SAAS,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,YAAA,EAC7D,QAAQ,GAAE,MAA0D;IAG/E,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO;IASnD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;CAUhD"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Whether the user has ever been shown a MemTree, so the first tree they ever
3
+ * see can say what to do with it (FIRST_EVER_HINT). A marker file in the ccc
4
+ * config dir records that it was shown. A user who had trees before this
5
+ * notice existed has pages in memtree-links.json for other sessions, and so
6
+ * counts as having seen one.
7
+ *
8
+ * Every failure reads as "not the first": the hint is a nicety, and showing it
9
+ * twice is worse than never.
10
+ */
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+ import { getConfigDir } from "./config.js";
14
+ export const FIRST_TREE_MARKER_FILE = "first-tree-shown.json";
15
+ export class FirstTreeMarker {
16
+ linkStore;
17
+ filePath;
18
+ constructor(linkStore, filePath = path.join(getConfigDir(), FIRST_TREE_MARKER_FILE)) {
19
+ this.linkStore = linkStore;
20
+ this.filePath = filePath;
21
+ }
22
+ isFirstEver(sessionId) {
23
+ try {
24
+ if (fs.existsSync(this.filePath))
25
+ return false;
26
+ return !this.linkStore?.hasOtherSession(sessionId);
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ markShown(_sessionId) {
33
+ try {
34
+ if (fs.existsSync(this.filePath))
35
+ return;
36
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
37
+ const shownAt = new Date().toISOString();
38
+ fs.writeFileSync(this.filePath, JSON.stringify({ shownAt }), { mode: 0o600, flag: "wx" });
39
+ }
40
+ catch {
41
+ // Another ccc wrote it first, or the dir is read-only: either way, done.
42
+ }
43
+ }
44
+ }
45
+ //# sourceMappingURL=first-tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-tree.js","sourceRoot":"","sources":["../src/first-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,MAAM,CAAC,MAAM,sBAAsB,GAAG,uBAAuB,CAAC;AAE9D,MAAM,OAAO,eAAe;IAEP;IACR;IAFX,YACmB,SAAqD,EAC7D,WAAmB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,sBAAsB,CAAC;QAD5D,cAAS,GAAT,SAAS,CAA4C;QAC7D,aAAQ,GAAR,QAAQ,CAA4D;IAC5E,CAAC;IAEJ,WAAW,CAAC,SAA6B;QACvC,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,SAAS,CAAC,UAA8B;QACtC,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACzC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/D,MAAM,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACzC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5F,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;QAC3E,CAAC;IACH,CAAC;CACF"}
package/dist/hooks.d.ts CHANGED
@@ -12,6 +12,17 @@ export declare const MESSAGE_DISPLAY_MIN_VERSION = "2.1.166";
12
12
  export declare const TRAILER_LABEL = "\u2022 MemTree \u00B7";
13
13
  /** Label on a line that carries a MemTree page link. */
14
14
  export declare const LINK_LABEL = "\u2022 MemTree";
15
+ /** What the link is, said next to the label when a tree is news. */
16
+ export declare const LINK_DESCRIPTION = "this session's memory map";
17
+ /**
18
+ * The one-time notice for a session's first tree: set apart from the routine
19
+ * link (leaf, bold) and saying in one line why it is worth opening. Kept short
20
+ * enough to fit 80 columns after Claude Code's "Stop says: " label.
21
+ */
22
+ export declare const FIRST_TREE_TITLE = "\uD83C\uDF3F First MemTree ready";
23
+ export declare const FIRST_TREE_VALUE = "a searchable map of this session so far";
24
+ /** Added under the first tree a user ever sees: what to do with it. */
25
+ export declare const FIRST_EVER_HINT = "Open it, or paste the link to any agent to give it this session's context";
15
26
  /**
16
27
  * Closes every URL line. Terminal linkifiers run a bare URL into whatever is
17
28
  * drawn right after it when the row joins the next one: a URL that ended a
@@ -73,6 +84,15 @@ export interface SuccessLink {
73
84
  */
74
85
  note?: string;
75
86
  }
87
+ /**
88
+ * Introduces the first tree of each session (see FIRST_TREE_TITLE). Answers
89
+ * whether this is the user's first tree ever, and hears when the intro was
90
+ * shown. Failures never break a hook.
91
+ */
92
+ export interface FirstTreeIntro {
93
+ isFirstEver(sessionId: string | undefined): boolean;
94
+ markShown(sessionId: string | undefined): void;
95
+ }
76
96
  /**
77
97
  * Where the trailer (`• MemTree · <link>`) is shown: under every finished
78
98
  * assistant message (with Stop as the fallback for a turn that rendered no
@@ -154,6 +174,7 @@ export declare class NoticeDeliveryQueue {
154
174
  private readonly delivered;
155
175
  private trailer;
156
176
  private trailerPlacement;
177
+ private firstTreeIntro;
157
178
  /** Key of the last trailer shown; a different key is announced as new. */
158
179
  constructor(ttlMs?: number, now?: () => number, color?: boolean);
159
180
  /** Replace stale delivery state when a new main human prompt is submitted. */
@@ -180,6 +201,11 @@ export declare class NoticeDeliveryQueue {
180
201
  * link is always at the bottom of the screen.
181
202
  */
182
203
  setTrailer(resolve: LinkResolver | null, placement?: TrailerPlacement): void;
204
+ /**
205
+ * Announce the first link a session shows with the one-time first-tree
206
+ * notice instead of the routine trailer. Off (null) by default.
207
+ */
208
+ setFirstTreeIntro(intro: FirstTreeIntro | null): void;
183
209
  queuePrefix(text: NoticeText, onDelivered?: () => void, promptId?: string): void;
184
210
  queueSuffix(text: NoticeText, onDelivered?: () => void, promptId?: string): void;
185
211
  /**
@@ -205,6 +231,8 @@ export declare class NoticeDeliveryQueue {
205
231
  * does not repeat the same link.
206
232
  */
207
233
  private renderSuccess;
234
+ /** No link has been shown for this session yet, and the first-tree intro is on. */
235
+ private isFirstLink;
208
236
  /** The session's current link, shown or not. Resolver failures never break a hook. */
209
237
  private currentLink;
210
238
  /** The link if its key changed since last shown, without marking it. Resolver failures never break a hook. */
@@ -216,6 +244,15 @@ export declare class NoticeDeliveryQueue {
216
244
  * marks the key as seen. Resolver failures never break a hook.
217
245
  */
218
246
  private renderTrailer;
247
+ /** A link that is news: green label, then what it is (dim). */
248
+ private newLinkLabel;
249
+ /**
250
+ * The session's first tree: bold leaf title, the value in one line, the
251
+ * URL below; for the user's first tree ever, one dim line on what to do.
252
+ */
253
+ private firstTreeNotice;
254
+ /** Call the first-tree intro; a throwing one never breaks a hook. */
255
+ private askIntro;
219
256
  /** The link notice with its note dim. */
220
257
  private linkNotice;
221
258
  private styleDim;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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"}
package/dist/hooks.js CHANGED
@@ -15,6 +15,17 @@ export const MESSAGE_DISPLAY_MIN_VERSION = "2.1.166";
15
15
  export const TRAILER_LABEL = "• MemTree ·";
16
16
  /** Label on a line that carries a MemTree page link. */
17
17
  export const LINK_LABEL = "• MemTree";
18
+ /** What the link is, said next to the label when a tree is news. */
19
+ export const LINK_DESCRIPTION = "this session's memory map";
20
+ /**
21
+ * The one-time notice for a session's first tree: set apart from the routine
22
+ * link (leaf, bold) and saying in one line why it is worth opening. Kept short
23
+ * enough to fit 80 columns after Claude Code's "Stop says: " label.
24
+ */
25
+ export const FIRST_TREE_TITLE = "🌿 First MemTree ready";
26
+ export const FIRST_TREE_VALUE = "a searchable map of this session so far";
27
+ /** Added under the first tree a user ever sees: what to do with it. */
28
+ export const FIRST_EVER_HINT = "Open it, or paste the link to any agent to give it this session's context";
18
29
  /**
19
30
  * Closes every URL line. Terminal linkifiers run a bare URL into whatever is
20
31
  * drawn right after it when the row joins the next one: a URL that ended a
@@ -42,6 +53,7 @@ const ANSI_GREEN = "\x1b[32m";
42
53
  const ANSI_YELLOW = "\x1b[33m";
43
54
  const ANSI_DEFAULT_FOREGROUND = "\x1b[39m";
44
55
  const ANSI_DIM = "\x1b[2m";
56
+ const ANSI_BOLD = "\x1b[1m";
45
57
  const ANSI_NORMAL_INTENSITY = "\x1b[22m";
46
58
  const STARTUP_NOTICE_FILE = "startup-notice.json";
47
59
  const RESUME_RELAY_FILE = "resume-link.mjs";
@@ -156,6 +168,7 @@ export class NoticeDeliveryQueue {
156
168
  delivered = new Map();
157
169
  trailer = null;
158
170
  trailerPlacement = "message";
171
+ firstTreeIntro = null;
159
172
  /** Key of the last trailer shown; a different key is announced as new. */
160
173
  constructor(ttlMs = DEFAULT_NOTICE_TTL_MS, now = Date.now, color = terminalSupportsColor()) {
161
174
  this.ttlMs = ttlMs;
@@ -184,7 +197,7 @@ export class NoticeDeliveryQueue {
184
197
  this.deliveryFor(sessionId).trailer = link.key;
185
198
  this.deliveryFor(sessionId).trailerUrl = link.link;
186
199
  this.deliveryFor(sessionId).link = link.key;
187
- return this.linkNotice(this.styleSuccess(LINK_LABEL), link);
200
+ return this.linkNotice(this.newLinkLabel(), link);
188
201
  }
189
202
  /** Whether the next success line would carry a link not shown before. */
190
203
  linkPending(sessionId) {
@@ -200,6 +213,13 @@ export class NoticeDeliveryQueue {
200
213
  this.trailer = resolve;
201
214
  this.trailerPlacement = placement;
202
215
  }
216
+ /**
217
+ * Announce the first link a session shows with the one-time first-tree
218
+ * notice instead of the routine trailer. Off (null) by default.
219
+ */
220
+ setFirstTreeIntro(intro) {
221
+ this.firstTreeIntro = intro;
222
+ }
203
223
  queuePrefix(text, onDelivered, promptId) {
204
224
  this.pending = {
205
225
  createdAt: this.now(),
@@ -339,11 +359,22 @@ export class NoticeDeliveryQueue {
339
359
  const link = this.currentLink(sessionId);
340
360
  if (link === undefined)
341
361
  return this.styleSuccess(text);
342
- this.deliveryFor(sessionId).link = link.key;
343
- this.deliveryFor(sessionId).successPage = noticePageIdentity(link.link);
344
- this.deliveryFor(sessionId).trailer = link.key;
345
- this.deliveryFor(sessionId).trailerUrl = link.link;
346
- return `${this.styleSuccess(text)}\n${urlLine(link.link)}`;
362
+ // The session's first link may arrive with a compression: introduce it here,
363
+ // since marking it delivered below keeps the trailer from ever doing so.
364
+ const first = this.isFirstLink(sessionId);
365
+ const delivered = this.deliveryFor(sessionId);
366
+ delivered.link = link.key;
367
+ delivered.successPage = noticePageIdentity(link.link);
368
+ delivered.trailer = link.key;
369
+ delivered.trailerUrl = link.link;
370
+ const below = first ? this.firstTreeNotice(link.link, sessionId) : urlLine(link.link);
371
+ return `${this.styleSuccess(text)}\n${below}`;
372
+ }
373
+ /** No link has been shown for this session yet, and the first-tree intro is on. */
374
+ isFirstLink(sessionId) {
375
+ const delivered = this.deliveryFor(sessionId);
376
+ return this.firstTreeIntro !== null && delivered.trailer === undefined &&
377
+ delivered.link === undefined && delivered.trailerUrl === undefined;
347
378
  }
348
379
  /** The session's current link, shown or not. Resolver failures never break a hook. */
349
380
  currentLink(sessionId) {
@@ -395,11 +426,40 @@ export class NoticeDeliveryQueue {
395
426
  // "turn": one line per user turn, and only when the index changed.
396
427
  if (this.trailerPlacement === "turn" && !isNew)
397
428
  return undefined;
398
- this.deliveryFor(sessionId).trailer = link.key;
399
- this.deliveryFor(sessionId).trailerUrl = link.link;
400
- const label = isNew ? this.styleSuccess(LINK_LABEL) : this.styleDim(LINK_LABEL);
429
+ const first = this.isFirstLink(sessionId);
430
+ delivered.trailer = link.key;
431
+ delivered.trailerUrl = link.link;
432
+ if (first)
433
+ return this.firstTreeNotice(link.link, sessionId);
434
+ const label = isNew ? this.newLinkLabel() : this.styleDim(LINK_LABEL);
401
435
  return this.linkNotice(label, link);
402
436
  }
437
+ /** A link that is news: green label, then what it is (dim). */
438
+ newLinkLabel() {
439
+ return `${this.styleSuccess(LINK_LABEL)} · ${this.styleDim(LINK_DESCRIPTION)}`;
440
+ }
441
+ /**
442
+ * The session's first tree: bold leaf title, the value in one line, the
443
+ * URL below; for the user's first tree ever, one dim line on what to do.
444
+ */
445
+ firstTreeNotice(url, sessionId) {
446
+ const title = this.color
447
+ ? `${ANSI_BOLD}${this.styleSuccess(FIRST_TREE_TITLE)}${ANSI_NORMAL_INTENSITY}`
448
+ : FIRST_TREE_TITLE;
449
+ const notice = linkLines(title, url, FIRST_TREE_VALUE);
450
+ const firstEver = this.askIntro((intro) => intro.isFirstEver(sessionId)) === true;
451
+ this.askIntro((intro) => intro.markShown(sessionId));
452
+ return firstEver ? `${notice}\n ${this.styleDim(FIRST_EVER_HINT)}` : notice;
453
+ }
454
+ /** Call the first-tree intro; a throwing one never breaks a hook. */
455
+ askIntro(call) {
456
+ try {
457
+ return this.firstTreeIntro ? call(this.firstTreeIntro) : undefined;
458
+ }
459
+ catch {
460
+ return undefined;
461
+ }
462
+ }
403
463
  /** The link notice with its note dim. */
404
464
  linkNotice(label, link) {
405
465
  return linkLines(label, link.link, link.note && this.styleDim(link.note));