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.
- package/README.md +165 -30
- package/dist/auto-update-runner.d.ts +52 -0
- package/dist/auto-update-runner.d.ts.map +1 -0
- package/dist/auto-update-runner.js +307 -0
- package/dist/auto-update-runner.js.map +1 -0
- package/dist/auto-update-setup.d.ts +38 -0
- package/dist/auto-update-setup.d.ts.map +1 -0
- package/dist/auto-update-setup.js +72 -0
- package/dist/auto-update-setup.js.map +1 -0
- package/dist/auto-update.d.ts +170 -0
- package/dist/auto-update.d.ts.map +1 -0
- package/dist/auto-update.js +401 -0
- package/dist/auto-update.js.map +1 -0
- package/dist/claude-env.d.ts +14 -1
- package/dist/claude-env.d.ts.map +1 -1
- package/dist/claude-env.js +17 -1
- package/dist/claude-env.js.map +1 -1
- package/dist/cli-lifecycle.d.ts +4 -0
- package/dist/cli-lifecycle.d.ts.map +1 -1
- package/dist/cli-lifecycle.js +18 -0
- package/dist/cli-lifecycle.js.map +1 -1
- package/dist/cli-main.js +139 -19
- package/dist/cli-main.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/count-tokens.d.ts +38 -3
- package/dist/count-tokens.d.ts.map +1 -1
- package/dist/count-tokens.js +94 -19
- package/dist/count-tokens.js.map +1 -1
- package/dist/diagnostics-schema.d.ts +44 -0
- package/dist/diagnostics-schema.d.ts.map +1 -0
- package/dist/diagnostics-schema.js +162 -0
- package/dist/diagnostics-schema.js.map +1 -0
- package/dist/diagnostics.d.ts +116 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +316 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/first-tree.d.ts +11 -0
- package/dist/first-tree.d.ts.map +1 -0
- package/dist/first-tree.js +45 -0
- package/dist/first-tree.js.map +1 -0
- package/dist/hooks.d.ts +37 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +69 -9
- package/dist/hooks.js.map +1 -1
- package/dist/memtree-finder.d.ts +11 -0
- package/dist/memtree-finder.d.ts.map +1 -1
- package/dist/memtree-finder.js +18 -0
- package/dist/memtree-finder.js.map +1 -1
- package/dist/memtree-links.d.ts +2 -0
- package/dist/memtree-links.d.ts.map +1 -1
- package/dist/memtree-links.js +4 -0
- package/dist/memtree-links.js.map +1 -1
- package/dist/memtree-mcp-config.d.ts.map +1 -1
- package/dist/memtree-mcp-config.js +4 -2
- package/dist/memtree-mcp-config.js.map +1 -1
- package/dist/memtree-mcp.d.ts +24 -4
- package/dist/memtree-mcp.d.ts.map +1 -1
- package/dist/memtree-mcp.js +47 -14
- package/dist/memtree-mcp.js.map +1 -1
- package/dist/memtree-tools.d.ts +17 -1
- package/dist/memtree-tools.d.ts.map +1 -1
- package/dist/memtree-tools.js +50 -2
- package/dist/memtree-tools.js.map +1 -1
- package/dist/memtree.d.ts +17 -1
- package/dist/memtree.d.ts.map +1 -1
- package/dist/memtree.js +62 -19
- package/dist/memtree.js.map +1 -1
- package/dist/notices.d.ts +6 -1
- package/dist/notices.d.ts.map +1 -1
- package/dist/notices.js +13 -1
- package/dist/notices.js.map +1 -1
- package/dist/prefix-store.js +3 -0
- package/dist/prefix-store.js.map +1 -1
- package/dist/proxy.d.ts +45 -3
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +193 -54
- package/dist/proxy.js.map +1 -1
- package/dist/reqlog.d.ts +27 -1
- package/dist/reqlog.d.ts.map +1 -1
- package/dist/reqlog.js.map +1 -1
- package/dist/request-sizing.d.ts +21 -2
- package/dist/request-sizing.d.ts.map +1 -1
- package/dist/request-sizing.js +60 -7
- package/dist/request-sizing.js.map +1 -1
- package/dist/resume-hint.d.ts +25 -0
- package/dist/resume-hint.d.ts.map +1 -0
- package/dist/resume-hint.js +36 -0
- package/dist/resume-hint.js.map +1 -0
- package/dist/token-estimate.d.ts +35 -0
- package/dist/token-estimate.d.ts.map +1 -0
- package/dist/token-estimate.js +97 -0
- package/dist/token-estimate.js.map +1 -0
- package/dist/update-check.d.ts +4 -3
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js +4 -3
- package/dist/update-check.js.map +1 -1
- package/dist/update-lock.d.ts +68 -0
- package/dist/update-lock.d.ts.map +1 -0
- package/dist/update-lock.js +176 -0
- package/dist/update-lock.js.map +1 -0
- 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;
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,eAAO,MAAM,2BAA2B,YAAY,CAAC;AACrD,8EAA8E;AAC9E,eAAO,MAAM,aAAa,0BAAgB,CAAC;AAC3C,wDAAwD;AACxD,eAAO,MAAM,UAAU,mBAAc,CAAC;
|
|
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.
|
|
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
|
-
|
|
343
|
-
|
|
344
|
-
this.
|
|
345
|
-
this.deliveryFor(sessionId)
|
|
346
|
-
|
|
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.
|
|
399
|
-
|
|
400
|
-
|
|
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));
|