chat-recall 0.5.3 → 0.5.5

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/dist/cli.js CHANGED
@@ -6278,6 +6278,24 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
6278
6278
  }
6279
6279
  const filesToParse = hasSubagentsDir(sessionPath) ? [sessionPath, ...getSubagentPaths(sessionPath)] : [sessionPath];
6280
6280
  let userCount = 0;
6281
+ const seenPrompts = /* @__PURE__ */ new Set();
6282
+ const recordPrompt = (raw, line, dedupe = false) => {
6283
+ if (userCount >= maxMessages)
6284
+ return;
6285
+ const withoutReminders = raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
6286
+ if (!withoutReminders.trim() || withoutReminders.trim().length <= 10)
6287
+ return;
6288
+ const cleanedText = stripInjectedBanners(withoutReminders).trim();
6289
+ if (cleanedText.length < 10)
6290
+ return;
6291
+ if (dedupe && seenPrompts.has(cleanedText))
6292
+ return;
6293
+ seenPrompts.add(cleanedText);
6294
+ content.userMessages.push({ text: cleanedText, lineNumber: line, contentType: "user" });
6295
+ userCount++;
6296
+ if (!content.firstPrompt)
6297
+ content.firstPrompt = cleanedText.slice(0, 1e3);
6298
+ };
6281
6299
  let assistantCount = 0;
6282
6300
  let toolCount = 0;
6283
6301
  let lineNum = 0;
@@ -6356,19 +6374,11 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
6356
6374
  text = textParts.join("\n");
6357
6375
  }
6358
6376
  }
6359
- if (text && !text.includes("<system-reminder>") && text.trim().length > 10) {
6360
- const cleanedText = stripInjectedBanners(text).trim();
6361
- if (cleanedText.length < 10)
6362
- continue;
6363
- content.userMessages.push({
6364
- text: cleanedText,
6365
- lineNumber: lineNum,
6366
- contentType: "user"
6367
- });
6368
- userCount++;
6369
- if (!content.firstPrompt) {
6370
- content.firstPrompt = cleanedText.slice(0, 1e3);
6371
- }
6377
+ if (text)
6378
+ recordPrompt(text, lineNum);
6379
+ } else if (msgType === "queue-operation") {
6380
+ if (obj.operation === "enqueue" && typeof obj.content === "string") {
6381
+ recordPrompt(obj.content, lineNum, true);
6372
6382
  }
6373
6383
  } else if (msgType === "assistant") {
6374
6384
  const msg = obj.message;
@@ -9539,23 +9549,24 @@ var init_codex2 = __esm({
9539
9549
  return null;
9540
9550
  }
9541
9551
  /**
9542
- * Stream a Codex JSONL rollout into canonical events. Codex separates:
9543
- * - event_msg + payload.type='user_message' → user
9544
- * - response_item + payload.type='message' → assistant_text
9545
- * - response_item + payload.type='function_call' → tool_use
9546
- * - response_item + payload.type='function_call_output' → tool_result
9547
- *
9548
- * Filters Codex's wrapper-bearing user messages (environment_context etc.).
9549
- *
9550
- * **Subagent fan-out:** Codex orchestrates work via `spawn_agent` calls
9551
- * that produce sibling rollout files in the same YYYY/MM/DD directory.
9552
- * Sub-agent rollouts carry `payload.source.subagent.thread_spawn` linking
9553
- * back to the parent. The actual file edits often happen inside those
9554
- * subagent rollouts — without folding their events into the parent's
9555
- * stream, replay/scan would see the parent as edit-free. We append every
9556
- * subagent rollout's events here so the generic engine sees one unified
9557
- * stream per user-facing session.
9558
- */
9552
+ * Stream a Codex JSONL rollout into canonical events. Codex separates:
9553
+ * - event_msg + payload.type='user_message' → user
9554
+ * - response_item + payload.type='message' → user OR assistant_text,
9555
+ * by payload.role
9556
+ * - response_item + payload.type='function_call' → tool_use
9557
+ * - response_item + payload.type='function_call_output' → tool_result
9558
+ *
9559
+ * Filters Codex's wrapper-bearing user messages (environment_context etc.).
9560
+ *
9561
+ * **Subagent fan-out:** Codex orchestrates work via `spawn_agent` calls
9562
+ * that produce sibling rollout files in the same YYYY/MM/DD directory.
9563
+ * Sub-agent rollouts carry `payload.source.subagent.thread_spawn` linking
9564
+ * back to the parent. The actual file edits often happen inside those
9565
+ * subagent rollouts — without folding their events into the parent's
9566
+ * stream, replay/scan would see the parent as edit-free. We append every
9567
+ * subagent rollout's events here so the generic engine sees one unified
9568
+ * stream per user-facing session.
9569
+ */
9559
9570
  readEvents(rawId) {
9560
9571
  const located = findCodexSessionFile(this.toRawId(rawId));
9561
9572
  if (!located)
@@ -9625,6 +9636,11 @@ var init_codex2 = __esm({
9625
9636
  if (text && !isCodexInjectedWrapper2(text)) {
9626
9637
  events.push({ kind: "user", ts, tsIso, line: lineNum, text });
9627
9638
  }
9639
+ } else if (obj.type === "response_item" && payload.type === "message" && payload.role === "user") {
9640
+ const text = flattenContent(payload.content).trim();
9641
+ if (text && !isCodexInjectedWrapper2(text)) {
9642
+ events.push({ kind: "user", ts, tsIso, line: lineNum, text });
9643
+ }
9628
9644
  } else if (obj.type === "response_item" && payload.type === "message" && payload.role === "assistant") {
9629
9645
  const text = flattenContent(payload.content).trim();
9630
9646
  if (text)
@@ -11087,6 +11103,9 @@ var init_first_prompt = __esm({
11087
11103
  // ../engine/dist/core/backends/claude.js
11088
11104
  import { existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as readFileSync9, statSync as statSync11, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
11089
11105
  import { join as join14, basename as basename11 } from "path";
11106
+ function stripReminders(text) {
11107
+ return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
11108
+ }
11090
11109
  function parseExitCode(text) {
11091
11110
  const m = text.match(/(?:^|\n)\s*(?:exit\s+code|returncode|exit\s+status|exit)\s*[:=]\s*(\d+)\b/i);
11092
11111
  return m ? Number(m[1]) : void 0;
@@ -11395,6 +11414,15 @@ var init_claude2 = __esm({
11395
11414
  }
11396
11415
  const tsIso = typeof obj.timestamp === "string" ? obj.timestamp : void 0;
11397
11416
  const ts = tsIso ? Date.parse(tsIso) || mtime : mtime;
11417
+ if (obj.type === "queue-operation") {
11418
+ if (obj.operation === "enqueue" && typeof obj.content === "string") {
11419
+ const queued = stripReminders(obj.content);
11420
+ if (queued && !queued.startsWith("<task-notification")) {
11421
+ events.push({ kind: "user", ts, tsIso, line: lineNum, text: queued });
11422
+ }
11423
+ }
11424
+ continue;
11425
+ }
11398
11426
  if (obj.type === "user") {
11399
11427
  const msg = obj.message;
11400
11428
  const content = msg?.content;
@@ -11428,9 +11456,9 @@ var init_claude2 = __esm({
11428
11456
  }
11429
11457
  }
11430
11458
  }
11431
- if (text && !text.includes("<system-reminder>")) {
11432
- events.push({ kind: "user", ts, tsIso, line: lineNum, text });
11433
- }
11459
+ const spoken = stripReminders(text);
11460
+ if (spoken)
11461
+ events.push({ kind: "user", ts, tsIso, line: lineNum, text: spoken });
11434
11462
  for (const tr of toolResults) {
11435
11463
  events.push({
11436
11464
  kind: "tool_result",
@@ -17641,7 +17669,9 @@ var init_extractor_version = __esm({
17641
17669
  "use strict";
17642
17670
  BASE_EXTRACTOR_VERSION = 2;
17643
17671
  TOOL_EXTRACTOR_BUMP = {
17644
- agy: 2
17672
+ agy: 2,
17673
+ claude: 1,
17674
+ codex: 1
17645
17675
  };
17646
17676
  EXTRACTOR_VERSION = BASE_EXTRACTOR_VERSION;
17647
17677
  }
@@ -17971,7 +18001,7 @@ var init_http = __esm({
17971
18001
  CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
17972
18002
  } catch {
17973
18003
  try {
17974
- if (true) CLI_VERSION = "0.5.3";
18004
+ if (true) CLI_VERSION = "0.5.5";
17975
18005
  } catch {
17976
18006
  }
17977
18007
  }
@@ -18610,6 +18640,17 @@ async function syncToTarget(cred, opts = {}) {
18610
18640
  if (res.status === 401 || res.status === 403) {
18611
18641
  throw new Error(`server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base2}`);
18612
18642
  }
18643
+ if (res.status === 402) {
18644
+ let detail = text;
18645
+ try {
18646
+ const body2 = JSON.parse(text);
18647
+ detail = body2.error ?? text;
18648
+ if (body2.resetsAt) detail += ` (resets ${new Date(body2.resetsAt).toISOString().slice(0, 10)})`;
18649
+ if (body2.upgradeUrl) detail += ` \u2014 ${body2.upgradeUrl}`;
18650
+ } catch {
18651
+ }
18652
+ throw new Error(`sync paused by the server: ${detail}`);
18653
+ }
18613
18654
  if (!retryable) throw new Error(`sync failed: HTTP ${res.status} ${text}`);
18614
18655
  if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
18615
18656
  const retryAfterS = Number(res.headers.get("retry-after"));
@@ -19494,7 +19535,7 @@ var init_sync_client = __esm({
19494
19535
  ownVersion = JSON.parse(readFileSync33(join40(dir, "../package.json"), "utf-8")).version || ownVersion;
19495
19536
  } catch {
19496
19537
  try {
19497
- if (true) ownVersion = "0.5.3";
19538
+ if (true) ownVersion = "0.5.5";
19498
19539
  } catch {
19499
19540
  }
19500
19541
  }
@@ -21073,6 +21114,14 @@ async function collectCode(opts) {
21073
21114
  agentPrompt: manifestPrompt(v.violation_type ?? "", file, v.line ?? null, v.description ?? "")
21074
21115
  });
21075
21116
  }
21117
+ {
21118
+ const before = findings.length;
21119
+ const own = findings.filter((f) => !f.file || !isGenerated(f.file));
21120
+ if (own.length !== before) {
21121
+ findings.splice(0, before, ...own);
21122
+ log6(`dropped ${before - own.length} finding(s) in vendored/generated files`);
21123
+ }
21124
+ }
21076
21125
  const godSet = new Set((coup?.god_modules ?? []).map((m) => rel(m.file)));
21077
21126
  const cloneSet = /* @__PURE__ */ new Set();
21078
21127
  for (const g of clones?.groups ?? [])
@@ -21158,7 +21207,9 @@ async function collectCode(opts) {
21158
21207
  }
21159
21208
  for (const g of clones?.groups ?? []) {
21160
21209
  if ((g.count ?? 0) >= 3 || (g.lines ?? 0) >= 12) {
21161
- const fns = (g.functions ?? []).filter((x) => x && typeof x === "object");
21210
+ const fns = (g.functions ?? []).filter((x) => x && typeof x === "object").filter((x) => !isGenerated(rel(x.file)));
21211
+ if (fns.length < 2)
21212
+ continue;
21162
21213
  const names = [...new Set(fns.map((x) => x.name))];
21163
21214
  const locs = fns.map((x) => rel(x.file)).slice(0, 5);
21164
21215
  pushAction((g.lines ?? 0) * (g.count ?? 0) >= 150 ? 1 : 2, "duplication", `${names.join(", ")} copy-pasted ${g.count}\xD7 (${g.lines} lines each)`, "Extract one shared implementation and replace the copies.", locs.map((f) => ({ file: f })), clonePrompt(names, g.lines ?? 0, g.count ?? 0, locs));
@@ -21177,10 +21228,14 @@ async function collectCode(opts) {
21177
21228
  }
21178
21229
  for (const m of (coup?.god_modules ?? []).slice(0, 5)) {
21179
21230
  const file = rel(m.file);
21231
+ if (isGenerated(file))
21232
+ continue;
21180
21233
  pushAction(2, "modularity", `God module ${file} (fan-in ${m.fan_in}, fan-out ${m.fan_out})`, "Split into cohesive sub-modules; introduce interfaces to cut fan-out.", [{ file }], couplingPrompt(file, m.fan_in ?? 0, m.fan_out ?? 0, Math.round((m.instability ?? 0) * 100) / 100));
21181
21234
  }
21182
21235
  for (const c of (cyc?.cycles ?? []).slice(0, 5)) {
21183
- const chain = (c.files ?? []).map(rel);
21236
+ const chain = (c.files ?? []).map(rel).filter((f) => !isGenerated(f));
21237
+ if (chain.length < 2)
21238
+ continue;
21184
21239
  pushAction(2, "architecture", `Circular dependency (${chain.length} files)`, "Break the cycle: extract the shared type/interface into a separate module.", chain.slice(0, 4).map((f) => ({ file: f })), cyclePrompt(chain.slice(0, 6)));
21185
21240
  }
21186
21241
  for (const h of hotspotsAll.slice(0, 5)) {
@@ -21319,7 +21374,31 @@ var init_collector = __esm({
21319
21374
  "migration_parity",
21320
21375
  "manifest_compliance"
21321
21376
  ];
21322
- GENERATED = ["generated/", ".pb.go", ".gen.", "_pb2.py", "/gen/", ".g.dart", "/node_modules/", "/vendor/", ".lock"];
21377
+ GENERATED = [
21378
+ "generated/",
21379
+ "__generated__/",
21380
+ ".pb.go",
21381
+ ".gen.",
21382
+ "_pb2.py",
21383
+ "/gen/",
21384
+ ".g.dart",
21385
+ "/node_modules/",
21386
+ "/vendor/",
21387
+ "/third_party/",
21388
+ "/site-packages/",
21389
+ ".lock",
21390
+ "/dist/",
21391
+ "/build/",
21392
+ "/out/",
21393
+ "/target/",
21394
+ "/.next/",
21395
+ "/coverage/",
21396
+ ".min.js",
21397
+ ".min.css",
21398
+ ".bundle.js",
21399
+ "-bundle.js",
21400
+ ".map"
21401
+ ];
21323
21402
  CF_RE = /\b(if|for|while|switch|case|catch|elif|when|loop|&&|\|\||\?)\b|\?/g;
21324
21403
  DEPTH = 2;
21325
21404
  MCP_OUT_MAX_BYTES = 64 * 1024 * 1024;
@@ -22313,7 +22392,7 @@ var init_intent_drain = __esm({
22313
22392
  ownVersion2 = JSON.parse(readFileSync41(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
22314
22393
  } catch {
22315
22394
  try {
22316
- if (true) ownVersion2 = "0.5.3";
22395
+ if (true) ownVersion2 = "0.5.5";
22317
22396
  } catch {
22318
22397
  }
22319
22398
  }
@@ -23826,6 +23905,8 @@ var DEFAULT_ALLOW = [
23826
23905
  "recall_tasks",
23827
23906
  "recall_task_create",
23828
23907
  "recall_task_update",
23908
+ "recall_task_comment",
23909
+ "recall_help",
23829
23910
  "recall_smart_resume",
23830
23911
  "recall_project_context",
23831
23912
  "recall_weekly_digest",