chat-recall 0.5.28 → 0.5.30

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/mcp.js CHANGED
@@ -4604,9 +4604,9 @@ function doResolve(realPath) {
4604
4604
  const bot = resolveBotWorktree(realPath);
4605
4605
  if (bot)
4606
4606
  return bot;
4607
- const git = resolveGit(realPath);
4608
- if (git)
4609
- return git;
4607
+ const git2 = resolveGit(realPath);
4608
+ if (git2)
4609
+ return git2;
4610
4610
  const ws = resolveAutoWorkspace(realPath, cfg.autoWorkspaceMinRepos ?? DEFAULT_AUTO_WORKSPACE_MIN_REPOS);
4611
4611
  if (ws)
4612
4612
  return ws;
@@ -4675,9 +4675,9 @@ function resolveGit(realPath) {
4675
4675
  const toplevel = findGitToplevel(realPath);
4676
4676
  if (!toplevel)
4677
4677
  return null;
4678
- const remote = getGitRemote(toplevel);
4679
- if (remote) {
4680
- const parsed = parseGitRemote(remote);
4678
+ const probe = getGitRemote(toplevel);
4679
+ if (probe.kind === "remote") {
4680
+ const parsed = parseGitRemote(probe.url);
4681
4681
  if (parsed) {
4682
4682
  return {
4683
4683
  id: `git:${parsed.host}/${parsed.owner}/${parsed.repo}`,
@@ -4686,6 +4686,9 @@ function resolveGit(realPath) {
4686
4686
  };
4687
4687
  }
4688
4688
  }
4689
+ if (probe.kind === "failed") {
4690
+ console.error(`[project] could not read git remotes in ${toplevel} \u2014 filing it as a local-only repo for now, which is probably wrong: ${probe.reason}`);
4691
+ }
4689
4692
  const hash = createHash("sha1").update(toplevel).digest("hex").slice(0, 12);
4690
4693
  return {
4691
4694
  id: `git-local:${hash}`,
@@ -4704,23 +4707,39 @@ function findGitToplevel(realPath) {
4704
4707
  }
4705
4708
  return null;
4706
4709
  }
4710
+ function git(toplevel, args) {
4711
+ return execSync(`git ${args}`, {
4712
+ cwd: toplevel,
4713
+ stdio: ["ignore", "pipe", "ignore"],
4714
+ encoding: "utf-8",
4715
+ timeout: GIT_TIMEOUT_MS
4716
+ });
4717
+ }
4718
+ function probeGitRemote(toplevel) {
4719
+ let names;
4720
+ try {
4721
+ names = git(toplevel, "remote").split("\n").map((n) => n.trim()).filter(Boolean);
4722
+ } catch (err) {
4723
+ return { kind: "failed", reason: err instanceof Error ? err.message : String(err) };
4724
+ }
4725
+ if (names.length === 0)
4726
+ return { kind: "none" };
4727
+ const pick = names.includes("origin") ? "origin" : names[0];
4728
+ try {
4729
+ const url = git(toplevel, `remote get-url ${pick}`).trim();
4730
+ return url ? { kind: "remote", url } : { kind: "none" };
4731
+ } catch (err) {
4732
+ return { kind: "failed", reason: err instanceof Error ? err.message : String(err) };
4733
+ }
4734
+ }
4707
4735
  function getGitRemote(toplevel) {
4708
4736
  const cached = gitCache.get(toplevel);
4709
4737
  if (cached)
4710
- return cached.remote;
4711
- let remote = null;
4712
- try {
4713
- remote = execSync("git remote get-url origin", {
4714
- cwd: toplevel,
4715
- stdio: ["ignore", "pipe", "ignore"],
4716
- encoding: "utf-8",
4717
- timeout: 2e3
4718
- }).trim() || null;
4719
- } catch {
4720
- remote = null;
4721
- }
4722
- gitCache.set(toplevel, { remote });
4723
- return remote;
4738
+ return cached;
4739
+ const probe = probeGitRemote(toplevel);
4740
+ if (probe.kind !== "failed")
4741
+ gitCache.set(toplevel, probe);
4742
+ return probe;
4724
4743
  }
4725
4744
  function parseGitRemote(url) {
4726
4745
  const trimmed = url.trim().replace(/\.git$/, "");
@@ -4850,7 +4869,7 @@ function globToRegex(glob) {
4850
4869
  function escapeRe(s) {
4851
4870
  return s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
4852
4871
  }
4853
- var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, cachedConfig, AUTO_WORKSPACE_MAX_DEPTH;
4872
+ var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
4854
4873
  var init_project_resolver = __esm({
4855
4874
  "../engine/dist/core/project-resolver.js"() {
4856
4875
  "use strict";
@@ -4861,6 +4880,7 @@ var init_project_resolver = __esm({
4861
4880
  gitCache = /* @__PURE__ */ new Map();
4862
4881
  workspaceCache = /* @__PURE__ */ new Map();
4863
4882
  cachedConfig = null;
4883
+ GIT_TIMEOUT_MS = 1e4;
4864
4884
  AUTO_WORKSPACE_MAX_DEPTH = 2;
4865
4885
  }
4866
4886
  });
@@ -7793,7 +7813,7 @@ async function archiveRawSession(store2, sessionId) {
7793
7813
  return await store2.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
7794
7814
  }
7795
7815
  function detectForkPredecessor(sessionPath) {
7796
- const { readFileSync: readFileSync44, readdirSync: readdirSync34 } = requireFs();
7816
+ const { readFileSync: readFileSync44, readdirSync: readdirSync35 } = requireFs();
7797
7817
  const { dirname: dirname20, join: join53, basename: basename25 } = requirePath();
7798
7818
  let text;
7799
7819
  try {
@@ -7823,7 +7843,7 @@ function detectForkPredecessor(sessionPath) {
7823
7843
  const self = basename25(sessionPath);
7824
7844
  let entries;
7825
7845
  try {
7826
- entries = readdirSync34(dir);
7846
+ entries = readdirSync35(dir);
7827
7847
  } catch {
7828
7848
  return null;
7829
7849
  }
@@ -20633,7 +20653,7 @@ var init_http = __esm({
20633
20653
  CLI_VERSION = JSON.parse(readFileSync37(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
20634
20654
  } catch {
20635
20655
  try {
20636
- if (true) CLI_VERSION = "0.5.28";
20656
+ if (true) CLI_VERSION = "0.5.30";
20637
20657
  } catch {
20638
20658
  }
20639
20659
  }
@@ -21145,7 +21165,7 @@ var init_telemetry = __esm({
21145
21165
  init_sync_client();
21146
21166
  cliVersion2 = () => {
21147
21167
  try {
21148
- return true ? "0.5.28" : "dev";
21168
+ return true ? "0.5.30" : "dev";
21149
21169
  } catch {
21150
21170
  return "dev";
21151
21171
  }
@@ -21303,12 +21323,13 @@ __export(auto_update_exports, {
21303
21323
  planAutoUpdate: () => planAutoUpdate,
21304
21324
  runAutoUpdate: () => runAutoUpdate,
21305
21325
  runningPrefix: () => runningPrefix,
21326
+ sweepStaleStaging: () => sweepStaleStaging,
21306
21327
  tarballUrl: () => tarballUrl
21307
21328
  });
21308
21329
  import { execSync as execSync4 } from "node:child_process";
21309
21330
  import { readFileSync as readFileSync38 } from "node:fs";
21310
21331
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21311
- import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3 } from "node:fs";
21332
+ import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync32, statSync as statSync41 } from "node:fs";
21312
21333
  import { join as join48, dirname as dirname18, sep as sep3 } from "node:path";
21313
21334
  import { tmpdir as tmpdir2 } from "node:os";
21314
21335
  import { createHash as createHash13 } from "node:crypto";
@@ -21347,6 +21368,31 @@ function planAutoUpdate(base, caps, ownVersion2, flag) {
21347
21368
  if (compareVersions(rel.version, ownVersion2) <= 0) return { update: false, reason: `already current (own ${ownVersion2} >= server ${rel.version})` };
21348
21369
  return { update: true, reason: `server ${rel.version} > own ${ownVersion2}`, url: tarballUrl(base), sha256: rel.sha256, from: ownVersion2, to: rel.version };
21349
21370
  }
21371
+ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
21372
+ const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
21373
+ const COLD_MS = 60 * 60 * 1e3;
21374
+ let removed = 0;
21375
+ let entries;
21376
+ try {
21377
+ entries = readdirSync32(root);
21378
+ } catch {
21379
+ return 0;
21380
+ }
21381
+ for (const name of entries) {
21382
+ if (!MKDTEMP_SUFFIX.test(name)) continue;
21383
+ const dir = join48(root, name);
21384
+ try {
21385
+ const st = statSync41(dir);
21386
+ if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
21387
+ const inside = readdirSync32(dir);
21388
+ if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
21389
+ rmSync5(dir, { recursive: true, force: true });
21390
+ removed++;
21391
+ } catch {
21392
+ }
21393
+ }
21394
+ return removed;
21395
+ }
21350
21396
  async function executeAutoUpdate(plan, deps) {
21351
21397
  if (!plan.update || !plan.url || !plan.sha256) return { updated: false, reason: plan.reason };
21352
21398
  let buf;
@@ -21358,13 +21404,21 @@ async function executeAutoUpdate(plan, deps) {
21358
21404
  const got = createHash13("sha256").update(buf).digest("hex");
21359
21405
  if (got !== plan.sha256) return { updated: false, reason: `checksum mismatch (expected ${plan.sha256.slice(0, 12)}\u2026, got ${got.slice(0, 12)}\u2026) \u2014 NOT installing` };
21360
21406
  const dir = mkdtempSync3(join48(tmpdir2(), "cr-update-"));
21407
+ const discardStaging = () => {
21408
+ try {
21409
+ rmSync5(dir, { recursive: true, force: true });
21410
+ } catch {
21411
+ }
21412
+ };
21361
21413
  const tgz = join48(dir, "chat-recall.tgz");
21362
21414
  writeFileSync9(tgz, buf);
21363
21415
  try {
21364
21416
  deps.install(tgz);
21365
21417
  } catch (e) {
21418
+ discardStaging();
21366
21419
  return { updated: false, reason: `install failed: ${e instanceof Error ? e.message : e}` };
21367
21420
  }
21421
+ discardStaging();
21368
21422
  const landed = (deps.verify ?? installedVersion)();
21369
21423
  if (landed && plan.to && compareVersions(landed, plan.to) < 0) {
21370
21424
  return {
@@ -21471,7 +21525,7 @@ __export(sync_client_exports, {
21471
21525
  syncSessions: () => syncSessions
21472
21526
  });
21473
21527
  import { join as join49, dirname as dirname19, basename as basename23 } from "node:path";
21474
- import { readFileSync as readFileSync39, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync4, rmSync as rmSync5, chmodSync as chmodSync5, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as statSync41 } from "node:fs";
21528
+ import { readFileSync as readFileSync39, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync5, unlinkSync as unlinkSync3, readdirSync as readdirSync33, statSync as statSync42 } from "node:fs";
21475
21529
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
21476
21530
  import { createHash as createHash14 } from "node:crypto";
21477
21531
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -21843,7 +21897,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
21843
21897
  let reaped = 0;
21844
21898
  let names;
21845
21899
  try {
21846
- names = readdirSync32(dir);
21900
+ names = readdirSync33(dir);
21847
21901
  } catch {
21848
21902
  return 0;
21849
21903
  }
@@ -21851,8 +21905,8 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
21851
21905
  if (!name.startsWith("cr-batchscan-")) continue;
21852
21906
  const p = join49(dir, name);
21853
21907
  try {
21854
- if (now - statSync41(p).mtimeMs < maxAgeMs) continue;
21855
- rmSync5(p, { recursive: true, force: true });
21908
+ if (now - statSync42(p).mtimeMs < maxAgeMs) continue;
21909
+ rmSync6(p, { recursive: true, force: true });
21856
21910
  reaped++;
21857
21911
  } catch {
21858
21912
  }
@@ -21884,7 +21938,7 @@ function batchScanExternal(items, opts = {}) {
21884
21938
  slices++;
21885
21939
  }
21886
21940
  try {
21887
- rmSync5(scanDir, { recursive: true, force: true });
21941
+ rmSync6(scanDir, { recursive: true, force: true });
21888
21942
  } catch {
21889
21943
  }
21890
21944
  safeToId = /* @__PURE__ */ new Map();
@@ -21909,7 +21963,7 @@ function batchScanExternal(items, opts = {}) {
21909
21963
  flushSlice();
21910
21964
  } finally {
21911
21965
  try {
21912
- rmSync5(scanDir, { recursive: true, force: true });
21966
+ rmSync6(scanDir, { recursive: true, force: true });
21913
21967
  } catch {
21914
21968
  }
21915
21969
  }
@@ -22042,9 +22096,10 @@ async function syncToTargetInScope(cred, opts = {}) {
22042
22096
  setServerIngestConcurrency(base, Math.floor(adv));
22043
22097
  }
22044
22098
  if (body2.cli && body2.cli.version) {
22045
- const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
22099
+ const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
22046
22100
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
22047
22101
  const plan = planAutoUpdate2(base, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
22102
+ sweepStaleStaging2();
22048
22103
  if (plan.update) {
22049
22104
  void runAutoUpdate2(base, authHeaders, ownVersion).catch(() => {
22050
22105
  });
@@ -22170,9 +22225,10 @@ async function syncToTargetInScope(cred, opts = {}) {
22170
22225
  if (!res.ok) throw new Error(`append sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
22171
22226
  const body = await res.json().catch(() => ({}));
22172
22227
  if (body.cli && body.cli.version) {
22173
- const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
22228
+ const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
22174
22229
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
22175
22230
  const plan = planAutoUpdate2(base, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
22231
+ sweepStaleStaging2();
22176
22232
  if (plan.update) {
22177
22233
  void runAutoUpdate2(base, authHeaders, ownVersion).catch(() => {
22178
22234
  });
@@ -22974,7 +23030,7 @@ var init_sync_client = __esm({
22974
23030
  ownVersion = JSON.parse(readFileSync39(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
22975
23031
  } catch {
22976
23032
  try {
22977
- if (true) ownVersion = "0.5.28";
23033
+ if (true) ownVersion = "0.5.30";
22978
23034
  } catch {
22979
23035
  }
22980
23036
  }
@@ -23163,7 +23219,7 @@ __export(install_skills_exports, {
23163
23219
  skillsSourceDir: () => skillsSourceDir,
23164
23220
  uninstallSkills: () => uninstallSkills
23165
23221
  });
23166
- import { readdirSync as readdirSync33, existsSync as existsSync47, mkdirSync as mkdirSync12, rmSync as rmSync6, cpSync, writeFileSync as writeFileSync12, readFileSync as readFileSync42, statSync as statSync42, realpathSync as realpathSync4 } from "fs";
23222
+ import { readdirSync as readdirSync34, existsSync as existsSync47, mkdirSync as mkdirSync12, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync12, readFileSync as readFileSync42, statSync as statSync43, realpathSync as realpathSync4 } from "fs";
23167
23223
  import { createHash as createHash15 } from "crypto";
23168
23224
  import { join as join51, basename as basename24 } from "path";
23169
23225
  function skillsSourceDir() {
@@ -23189,7 +23245,7 @@ function skillsFingerprint() {
23189
23245
  }
23190
23246
  function filesUnder(dir, prefix = "") {
23191
23247
  const out = [];
23192
- for (const e of readdirSync33(dir, { withFileTypes: true })) {
23248
+ for (const e of readdirSync34(dir, { withFileTypes: true })) {
23193
23249
  if (e.name === MARKER) continue;
23194
23250
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
23195
23251
  if (e.isDirectory()) out.push(...filesUnder(join51(dir, e.name), rel));
@@ -23203,7 +23259,7 @@ function skillStamp() {
23203
23259
  function bundledSkillNames() {
23204
23260
  const src = skillsSourceDir();
23205
23261
  if (!existsSync47(src)) return [];
23206
- return readdirSync33(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync47(join51(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
23262
+ return readdirSync34(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync47(join51(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
23207
23263
  }
23208
23264
  function realPathOrSelf(p) {
23209
23265
  try {
@@ -23276,7 +23332,7 @@ function installSkills(opts = {}) {
23276
23332
  continue;
23277
23333
  }
23278
23334
  mkdirSync12(t.dir, { recursive: true });
23279
- rmSync6(dest, { recursive: true, force: true });
23335
+ rmSync7(dest, { recursive: true, force: true });
23280
23336
  cpSync(join51(src, name), dest, { recursive: true });
23281
23337
  writeFileSync12(join51(dest, MARKER), `${stamp}
23282
23338
  `);
@@ -23295,11 +23351,11 @@ function uninstallSkills() {
23295
23351
  perTarget.push({ id: t.id, label: t.label, removed });
23296
23352
  continue;
23297
23353
  }
23298
- for (const entry of readdirSync33(t.dir, { withFileTypes: true })) {
23354
+ for (const entry of readdirSync34(t.dir, { withFileTypes: true })) {
23299
23355
  if (!entry.isDirectory()) continue;
23300
23356
  const dir = join51(t.dir, entry.name);
23301
23357
  if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
23302
- rmSync6(dir, { recursive: true, force: true });
23358
+ rmSync7(dir, { recursive: true, force: true });
23303
23359
  removed.push(entry.name);
23304
23360
  }
23305
23361
  }
@@ -23373,7 +23429,7 @@ __export(service_installer_exports, {
23373
23429
  uninstallService: () => uninstallService
23374
23430
  });
23375
23431
  import { execSync as execSync5 } from "child_process";
23376
- import { existsSync as existsSync48, mkdirSync as mkdirSync13, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "fs";
23432
+ import { existsSync as existsSync48, mkdirSync as mkdirSync13, rmSync as rmSync8, writeFileSync as writeFileSync13 } from "fs";
23377
23433
  import { homedir as homedir17 } from "os";
23378
23434
  import { join as join52 } from "path";
23379
23435
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -23529,7 +23585,7 @@ function uninstallService() {
23529
23585
  }
23530
23586
  const unitPath = join52(homedir17(), ".config", "systemd", "user", "chat-recall-watch.service");
23531
23587
  if (existsSync48(unitPath)) {
23532
- rmSync7(unitPath, { force: true });
23588
+ rmSync8(unitPath, { force: true });
23533
23589
  removed = true;
23534
23590
  }
23535
23591
  try {
@@ -23546,7 +23602,7 @@ function uninstallService() {
23546
23602
  }
23547
23603
  let removed = false;
23548
23604
  if (existsSync48(plistPath)) {
23549
- rmSync7(plistPath, { force: true });
23605
+ rmSync8(plistPath, { force: true });
23550
23606
  removed = true;
23551
23607
  }
23552
23608
  return removed;
@@ -24369,7 +24425,8 @@ var RecallTaskUpdateSchema = z.object({
24369
24425
  id: z.string().describe("Task id (t_\u2026)"),
24370
24426
  status: z.enum(TASK_STATUS_SETTABLE).optional().describe("'done' needs linked_session_id \u2014 the session that did the work. 'closed' means the card no longer applies (its finding went away, or it duplicates another) and needs closed_reason. If it was never a real problem, do not close it: tell the user, because rejecting is their call."),
24371
24427
  closed_reason: z.string().optional().describe("Why the card no longer applies. REQUIRED with status 'closed'."),
24372
- commits: z.array(z.string()).optional().describe("The commit sha(s) that fixed this, in THIS card's repository. REQUIRED with status 'done' \u2014 a session link alone proved the wrong thing once: a card closed with a real session attached showed 74 commits belonging to a DIFFERENT repository."),
24428
+ diff: z.string().optional().describe("THE CHANGE YOU MADE for this card, as a unified diff (`git diff`, or the patch you applied). REQUIRED with status 'done' unless you pass commits. You are the only one who knows it: the board cannot reconstruct shell-driven edits, and its commit scan only sees repositories this session tool-touched."),
24429
+ commits: z.array(z.string()).optional().describe("The commit sha(s) carrying that change, if you committed it. Pass them with the diff when you have both \u2014 the diff is what a reader sees, the sha is what makes it checkable."),
24373
24430
  files: z.array(z.string()).optional().describe("Files those commits changed. PASS THESE: without them the card cannot narrow the session's diff to this card, and shows no changes at all rather than another repository's."),
24374
24431
  summary: z.string().optional().describe("One line on what changed (optional)."),
24375
24432
  assignee: z.string().optional().describe("Reassign to this user id (sub); empty string unassigns"),
@@ -24394,7 +24451,8 @@ var RecallTaskPolicySchema = z.object({
24394
24451
  categories: z.array(z.string()).optional().describe('Only file these finding/action categories (e.g. ["security","clone"]). Pass an empty array for all of them.'),
24395
24452
  excluded_projects: z.array(z.string()).optional().describe("Projects that never file a card \u2014 replaces the whole list. Use exclude_project/include_project to change one."),
24396
24453
  exclude_project: z.string().optional().describe('Add ONE project to the never-file list. For "do not put work on my board for this repo" \u2014 a client codebase, an archive, a mirror.'),
24397
- include_project: z.string().optional().describe("Remove ONE project from the never-file list.")
24454
+ include_project: z.string().optional().describe("Remove ONE project from the never-file list."),
24455
+ project: z.string().optional().describe('Apply max_pri and categories to THIS PROJECT ONLY, leaving every other repo on the global setting. For "only security in the client repo, everything in mine".')
24398
24456
  });
24399
24457
  var RecallTaskCommentSchema = z.object({
24400
24458
  task_id: z.string().describe("Task id (t_\u2026) from recall_tasks"),
@@ -25189,11 +25247,23 @@ WORKFLOW \u2014 do this whenever the user asks you to work on a task from the bo
25189
25247
  server cannot see it). This is REQUIRED \u2014 claiming without it is refused,
25190
25248
  because "in progress" with nothing behind it cannot be asked about. The card
25191
25249
  then shows that session's changes as they land, not only after the commit.
25192
- 2. When you finish, set status 'done' AND pass commits \u2014 the sha(s) in this
25193
- card's repository that fixed it. Without them the close is refused. Pass
25194
- the FILES too: they are what lets the card show the exact change, because a
25195
- session's diff covers every repository it touched and only the file list can
25196
- narrow it to this card.
25250
+ 2. When you finish, set status 'done' AND RECORD WHAT YOU CHANGED: pass the diff
25251
+ (unified \u2014 what git diff printed for this fix) and the commits if you
25252
+ committed it. The close is refused without one of them. Do not expect the
25253
+ board to work it out \u2014 it cannot see edits made through a shell, and its
25254
+ commit scan only searches repositories this session already tool-touched.
25255
+ The diff you paste is what the next person reads on the card.
25256
+
25257
+ STAY INSIDE THE CARD'S PROJECT. A card names one project; fix it there and
25258
+ nowhere else. If the real fix needs a change in another repository, say so and
25259
+ leave the card open rather than reaching across \u2014 the person who filed this board
25260
+ did not ask you to touch a second codebase, and a diff spanning repositories
25261
+ cannot be reviewed as one change.
25262
+
25263
+ TELL THE USER WHAT YOU ARE DOING. Say that you are taking tasks off the
25264
+ chat-recall board, name the ones you picked, and say when each is done and what
25265
+ changed. A card closing on its own, with no word to the person whose board it is,
25266
+ is how this board stopped being trusted the first time.
25197
25267
 
25198
25268
  THE THREE ENDINGS ARE NOT THE SAME:
25199
25269
  - 'done' \u2014 you fixed it. Needs linked_session_id; refused without one.
@@ -25211,7 +25281,8 @@ nobody had done.`,
25211
25281
  id: { type: "string", description: "Task id (t_\u2026)" },
25212
25282
  status: { type: "string", enum: [...TASK_STATUS_SETTABLE], description: "Set the card's state. 'done' needs linked_session_id; 'closed' needs closed_reason. There is no 'rejected' here on purpose: rejecting is the user's verdict, not yours." },
25213
25283
  closed_reason: { type: "string", description: "Why the card no longer applies. REQUIRED with status 'closed'." },
25214
- commits: { type: "array", items: { type: "string" }, description: "Commit sha(s) in THIS card's repository that fixed it. REQUIRED with status 'done'." },
25284
+ diff: { type: "string", description: "THE CHANGE YOU MADE for this card, as a unified diff. REQUIRED with status 'done' unless you pass commits \u2014 the board cannot reconstruct shell-driven edits, so this is the only reliable record." },
25285
+ commits: { type: "array", items: { type: "string" }, description: "Commit sha(s) carrying that change, if you committed it." },
25215
25286
  files: { type: "array", items: { type: "string" }, description: "Files those commits changed. PASS THESE: the card scopes the session's diff by them, and without them it can show no changes rather than risk showing another repository's." },
25216
25287
  summary: { type: "string", description: "One line on what changed (optional)." },
25217
25288
  assignee: { type: "string", description: "Reassign to this user id (sub)" },
@@ -25244,6 +25315,8 @@ without editing the task itself. Pass the task id (t_\u2026) from recall_tasks.`
25244
25315
  ceiling how many auto-filed cards may be open at once
25245
25316
  max_per_run cap on new cards per run
25246
25317
  categories only file these categories (e.g. ["security"]); [] means all
25318
+ project apply max_pri/categories to THAT REPOSITORY ONLY \u2014 one floor
25319
+ across every repo forces the strictest one on all of them
25247
25320
  exclude_project / include_project
25248
25321
  a repository that never files a card \u2014 a client's codebase, an
25249
25322
  archive, a mirror. Indexed and searchable as before; simply never
@@ -25260,6 +25333,7 @@ explains a quiet board: at the ceiling, filing pauses until cards close.`,
25260
25333
  ceiling: { type: "number", description: "How many auto-filed cards may be OPEN at once." },
25261
25334
  max_per_run: { type: "number", description: "Cap on NEW cards per run." },
25262
25335
  categories: { type: "array", items: { type: "string" }, description: "Only file these categories; [] means all." },
25336
+ project: { type: "string", description: "Apply max_pri/categories to THIS project only, leaving other repos on the global setting." },
25263
25337
  excluded_projects: { type: "array", items: { type: "string" }, description: "Replace the never-file list." },
25264
25338
  exclude_project: { type: "string", description: "Add ONE project to the never-file list." },
25265
25339
  include_project: { type: "string", description: "Remove ONE project from the never-file list." }
@@ -26984,11 +27058,16 @@ ${howTo}` }] };
26984
27058
  patch.linkedSessionId = params.linked_session_id;
26985
27059
  if (params.closed_reason !== void 0)
26986
27060
  patch.closedReason = params.closed_reason;
26987
- if (params.commits?.length) {
26988
- patch.doneEvidence = { commits: params.commits, files: params.files, summary: params.summary };
27061
+ if (params.commits?.length || params.diff) {
27062
+ patch.doneEvidence = {
27063
+ diff: params.diff,
27064
+ commits: params.commits,
27065
+ files: params.files,
27066
+ summary: params.summary
27067
+ };
26989
27068
  }
26990
- if (params.status === "done" && !params.commits?.length) {
26991
- return { content: [{ type: "text", text: "Closing as 'done' needs the commit sha(s) that fixed it, in this card's repository \u2014 pass commits. Commit the fix first if you have not. If the card no longer applies, use status 'closed' with closed_reason; if it was never a real problem, leave it open and tell the user, because rejecting is their call." }] };
27069
+ if (params.status === "done" && !params.commits?.length && !params.diff) {
27070
+ return { content: [{ type: "text", text: "Closing as 'done' needs the change that fixed it: pass `diff` \u2014 the unified diff of what you changed for this card \u2014 and `commits` if you committed it. Nothing else can supply it: the board cannot see shell-driven edits, and its commit scan only searches repositories this session tool-touched. If the card no longer applies, use status 'closed' with closed_reason; if it was never a real problem, leave it open and tell the user, because rejecting is their call." }] };
26992
27071
  }
26993
27072
  if (params.status === "closed" && !(params.closed_reason ?? "").trim()) {
26994
27073
  return { content: [{ type: "text", text: "closed_reason is required when closing a task. Say why the card no longer applies (its finding stopped being reported, or it duplicates another card). If you FIXED it, use status 'done' with linked_session_id instead; if it was never a real problem, leave it open and tell the user, because rejecting it is their call." }] };
@@ -27012,14 +27091,23 @@ ${howTo}` }] };
27012
27091
  const patch = {};
27013
27092
  if (params.enabled !== void 0)
27014
27093
  patch.enabled = params.enabled;
27015
- if (params.max_pri !== void 0)
27016
- patch.maxPri = params.max_pri;
27094
+ if (params.project) {
27095
+ const over = {};
27096
+ if (params.max_pri !== void 0)
27097
+ over.maxPri = params.max_pri;
27098
+ if (params.categories !== void 0)
27099
+ over.categories = params.categories;
27100
+ patch.perProject = { [params.project]: Object.keys(over).length ? over : null };
27101
+ } else {
27102
+ if (params.max_pri !== void 0)
27103
+ patch.maxPri = params.max_pri;
27104
+ if (params.categories !== void 0)
27105
+ patch.categories = params.categories;
27106
+ }
27017
27107
  if (params.ceiling !== void 0)
27018
27108
  patch.ceiling = params.ceiling;
27019
27109
  if (params.max_per_run !== void 0)
27020
27110
  patch.maxPerRun = params.max_per_run;
27021
- if (params.categories !== void 0)
27022
- patch.categories = params.categories;
27023
27111
  if (params.excluded_projects !== void 0)
27024
27112
  patch.excludedProjects = params.excluded_projects;
27025
27113
  const cur = await remoteGetQS("/api/tasks/policy", {});
@@ -1 +1 @@
1
- {"version":3,"file":"sync-client.d.ts","sourceRoot":"","sources":["../src/sync-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-client.d.ts","sourceRoot":"","sources":["../src/sync-client.ts"],"names":[],"mappings":"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"}
@@ -1097,9 +1097,10 @@ async function syncToTargetInScope(cred, opts = {}) {
1097
1097
  setServerIngestConcurrency(base, Math.floor(adv));
1098
1098
  }
1099
1099
  if (body.cli && body.cli.version) {
1100
- const { planAutoUpdate, runAutoUpdate } = await import('./auto-update.js');
1100
+ const { planAutoUpdate, runAutoUpdate, sweepStaleStaging } = await import('./auto-update.js');
1101
1101
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
1102
1102
  const plan = planAutoUpdate(base, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
1103
+ sweepStaleStaging();
1103
1104
  if (plan.update) {
1104
1105
  void runAutoUpdate(base, authHeaders, ownVersion).catch(() => { });
1105
1106
  }
@@ -1308,9 +1309,10 @@ async function syncToTargetInScope(cred, opts = {}) {
1308
1309
  throw new Error(`append sync failed: HTTP ${res.status} ${await res.text().catch(() => '')}`);
1309
1310
  const body = await res.json().catch(() => ({}));
1310
1311
  if (body.cli && body.cli.version) {
1311
- const { planAutoUpdate, runAutoUpdate } = await import('./auto-update.js');
1312
+ const { planAutoUpdate, runAutoUpdate, sweepStaleStaging } = await import('./auto-update.js');
1312
1313
  const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
1313
1314
  const plan = planAutoUpdate(base, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
1315
+ sweepStaleStaging();
1314
1316
  if (plan.update) {
1315
1317
  void runAutoUpdate(base, authHeaders, ownVersion).catch(() => { });
1316
1318
  }