chat-recall 0.5.28 → 0.5.29

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
  });
@@ -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.29";
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.29" : "dev";
21149
21169
  } catch {
21150
21170
  return "dev";
21151
21171
  }
@@ -22974,7 +22994,7 @@ var init_sync_client = __esm({
22974
22994
  ownVersion = JSON.parse(readFileSync39(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
22975
22995
  } catch {
22976
22996
  try {
22977
- if (true) ownVersion = "0.5.28";
22997
+ if (true) ownVersion = "0.5.29";
22978
22998
  } catch {
22979
22999
  }
22980
23000
  }
@@ -24369,7 +24389,8 @@ var RecallTaskUpdateSchema = z.object({
24369
24389
  id: z.string().describe("Task id (t_\u2026)"),
24370
24390
  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
24391
  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."),
24392
+ 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."),
24393
+ 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
24394
  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
24395
  summary: z.string().optional().describe("One line on what changed (optional)."),
24375
24396
  assignee: z.string().optional().describe("Reassign to this user id (sub); empty string unassigns"),
@@ -24394,7 +24415,8 @@ var RecallTaskPolicySchema = z.object({
24394
24415
  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
24416
  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
24417
  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.")
24418
+ include_project: z.string().optional().describe("Remove ONE project from the never-file list."),
24419
+ 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
24420
  });
24399
24421
  var RecallTaskCommentSchema = z.object({
24400
24422
  task_id: z.string().describe("Task id (t_\u2026) from recall_tasks"),
@@ -25189,11 +25211,23 @@ WORKFLOW \u2014 do this whenever the user asks you to work on a task from the bo
25189
25211
  server cannot see it). This is REQUIRED \u2014 claiming without it is refused,
25190
25212
  because "in progress" with nothing behind it cannot be asked about. The card
25191
25213
  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.
25214
+ 2. When you finish, set status 'done' AND RECORD WHAT YOU CHANGED: pass the diff
25215
+ (unified \u2014 what git diff printed for this fix) and the commits if you
25216
+ committed it. The close is refused without one of them. Do not expect the
25217
+ board to work it out \u2014 it cannot see edits made through a shell, and its
25218
+ commit scan only searches repositories this session already tool-touched.
25219
+ The diff you paste is what the next person reads on the card.
25220
+
25221
+ STAY INSIDE THE CARD'S PROJECT. A card names one project; fix it there and
25222
+ nowhere else. If the real fix needs a change in another repository, say so and
25223
+ leave the card open rather than reaching across \u2014 the person who filed this board
25224
+ did not ask you to touch a second codebase, and a diff spanning repositories
25225
+ cannot be reviewed as one change.
25226
+
25227
+ TELL THE USER WHAT YOU ARE DOING. Say that you are taking tasks off the
25228
+ chat-recall board, name the ones you picked, and say when each is done and what
25229
+ changed. A card closing on its own, with no word to the person whose board it is,
25230
+ is how this board stopped being trusted the first time.
25197
25231
 
25198
25232
  THE THREE ENDINGS ARE NOT THE SAME:
25199
25233
  - 'done' \u2014 you fixed it. Needs linked_session_id; refused without one.
@@ -25211,7 +25245,8 @@ nobody had done.`,
25211
25245
  id: { type: "string", description: "Task id (t_\u2026)" },
25212
25246
  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
25247
  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'." },
25248
+ 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." },
25249
+ commits: { type: "array", items: { type: "string" }, description: "Commit sha(s) carrying that change, if you committed it." },
25215
25250
  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
25251
  summary: { type: "string", description: "One line on what changed (optional)." },
25217
25252
  assignee: { type: "string", description: "Reassign to this user id (sub)" },
@@ -25244,6 +25279,8 @@ without editing the task itself. Pass the task id (t_\u2026) from recall_tasks.`
25244
25279
  ceiling how many auto-filed cards may be open at once
25245
25280
  max_per_run cap on new cards per run
25246
25281
  categories only file these categories (e.g. ["security"]); [] means all
25282
+ project apply max_pri/categories to THAT REPOSITORY ONLY \u2014 one floor
25283
+ across every repo forces the strictest one on all of them
25247
25284
  exclude_project / include_project
25248
25285
  a repository that never files a card \u2014 a client's codebase, an
25249
25286
  archive, a mirror. Indexed and searchable as before; simply never
@@ -25260,6 +25297,7 @@ explains a quiet board: at the ceiling, filing pauses until cards close.`,
25260
25297
  ceiling: { type: "number", description: "How many auto-filed cards may be OPEN at once." },
25261
25298
  max_per_run: { type: "number", description: "Cap on NEW cards per run." },
25262
25299
  categories: { type: "array", items: { type: "string" }, description: "Only file these categories; [] means all." },
25300
+ project: { type: "string", description: "Apply max_pri/categories to THIS project only, leaving other repos on the global setting." },
25263
25301
  excluded_projects: { type: "array", items: { type: "string" }, description: "Replace the never-file list." },
25264
25302
  exclude_project: { type: "string", description: "Add ONE project to the never-file list." },
25265
25303
  include_project: { type: "string", description: "Remove ONE project from the never-file list." }
@@ -26984,11 +27022,16 @@ ${howTo}` }] };
26984
27022
  patch.linkedSessionId = params.linked_session_id;
26985
27023
  if (params.closed_reason !== void 0)
26986
27024
  patch.closedReason = params.closed_reason;
26987
- if (params.commits?.length) {
26988
- patch.doneEvidence = { commits: params.commits, files: params.files, summary: params.summary };
27025
+ if (params.commits?.length || params.diff) {
27026
+ patch.doneEvidence = {
27027
+ diff: params.diff,
27028
+ commits: params.commits,
27029
+ files: params.files,
27030
+ summary: params.summary
27031
+ };
26989
27032
  }
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." }] };
27033
+ if (params.status === "done" && !params.commits?.length && !params.diff) {
27034
+ 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
27035
  }
26993
27036
  if (params.status === "closed" && !(params.closed_reason ?? "").trim()) {
26994
27037
  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 +27055,23 @@ ${howTo}` }] };
27012
27055
  const patch = {};
27013
27056
  if (params.enabled !== void 0)
27014
27057
  patch.enabled = params.enabled;
27015
- if (params.max_pri !== void 0)
27016
- patch.maxPri = params.max_pri;
27058
+ if (params.project) {
27059
+ const over = {};
27060
+ if (params.max_pri !== void 0)
27061
+ over.maxPri = params.max_pri;
27062
+ if (params.categories !== void 0)
27063
+ over.categories = params.categories;
27064
+ patch.perProject = { [params.project]: Object.keys(over).length ? over : null };
27065
+ } else {
27066
+ if (params.max_pri !== void 0)
27067
+ patch.maxPri = params.max_pri;
27068
+ if (params.categories !== void 0)
27069
+ patch.categories = params.categories;
27070
+ }
27017
27071
  if (params.ceiling !== void 0)
27018
27072
  patch.ceiling = params.ceiling;
27019
27073
  if (params.max_per_run !== void 0)
27020
27074
  patch.maxPerRun = params.max_per_run;
27021
- if (params.categories !== void 0)
27022
- patch.categories = params.categories;
27023
27075
  if (params.excluded_projects !== void 0)
27024
27076
  patch.excludedProjects = params.excluded_projects;
27025
27077
  const cur = await remoteGetQS("/api/tasks/policy", {});
package/dist/watch.js CHANGED
@@ -14102,9 +14102,9 @@ function doResolve(realPath) {
14102
14102
  const bot = resolveBotWorktree(realPath);
14103
14103
  if (bot)
14104
14104
  return bot;
14105
- const git = resolveGit(realPath);
14106
- if (git)
14107
- return git;
14105
+ const git2 = resolveGit(realPath);
14106
+ if (git2)
14107
+ return git2;
14108
14108
  const ws = resolveAutoWorkspace(realPath, cfg.autoWorkspaceMinRepos ?? DEFAULT_AUTO_WORKSPACE_MIN_REPOS);
14109
14109
  if (ws)
14110
14110
  return ws;
@@ -14173,9 +14173,9 @@ function resolveGit(realPath) {
14173
14173
  const toplevel = findGitToplevel(realPath);
14174
14174
  if (!toplevel)
14175
14175
  return null;
14176
- const remote = getGitRemote(toplevel);
14177
- if (remote) {
14178
- const parsed = parseGitRemote(remote);
14176
+ const probe = getGitRemote(toplevel);
14177
+ if (probe.kind === "remote") {
14178
+ const parsed = parseGitRemote(probe.url);
14179
14179
  if (parsed) {
14180
14180
  return {
14181
14181
  id: `git:${parsed.host}/${parsed.owner}/${parsed.repo}`,
@@ -14184,6 +14184,9 @@ function resolveGit(realPath) {
14184
14184
  };
14185
14185
  }
14186
14186
  }
14187
+ if (probe.kind === "failed") {
14188
+ 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}`);
14189
+ }
14187
14190
  const hash = createHash7("sha1").update(toplevel).digest("hex").slice(0, 12);
14188
14191
  return {
14189
14192
  id: `git-local:${hash}`,
@@ -14202,23 +14205,39 @@ function findGitToplevel(realPath) {
14202
14205
  }
14203
14206
  return null;
14204
14207
  }
14208
+ function git(toplevel, args) {
14209
+ return execSync(`git ${args}`, {
14210
+ cwd: toplevel,
14211
+ stdio: ["ignore", "pipe", "ignore"],
14212
+ encoding: "utf-8",
14213
+ timeout: GIT_TIMEOUT_MS
14214
+ });
14215
+ }
14216
+ function probeGitRemote(toplevel) {
14217
+ let names;
14218
+ try {
14219
+ names = git(toplevel, "remote").split("\n").map((n) => n.trim()).filter(Boolean);
14220
+ } catch (err) {
14221
+ return { kind: "failed", reason: err instanceof Error ? err.message : String(err) };
14222
+ }
14223
+ if (names.length === 0)
14224
+ return { kind: "none" };
14225
+ const pick = names.includes("origin") ? "origin" : names[0];
14226
+ try {
14227
+ const url = git(toplevel, `remote get-url ${pick}`).trim();
14228
+ return url ? { kind: "remote", url } : { kind: "none" };
14229
+ } catch (err) {
14230
+ return { kind: "failed", reason: err instanceof Error ? err.message : String(err) };
14231
+ }
14232
+ }
14205
14233
  function getGitRemote(toplevel) {
14206
14234
  const cached = gitCache.get(toplevel);
14207
14235
  if (cached)
14208
- return cached.remote;
14209
- let remote = null;
14210
- try {
14211
- remote = execSync("git remote get-url origin", {
14212
- cwd: toplevel,
14213
- stdio: ["ignore", "pipe", "ignore"],
14214
- encoding: "utf-8",
14215
- timeout: 2e3
14216
- }).trim() || null;
14217
- } catch {
14218
- remote = null;
14219
- }
14220
- gitCache.set(toplevel, { remote });
14221
- return remote;
14236
+ return cached;
14237
+ const probe = probeGitRemote(toplevel);
14238
+ if (probe.kind !== "failed")
14239
+ gitCache.set(toplevel, probe);
14240
+ return probe;
14222
14241
  }
14223
14242
  function parseGitRemote(url) {
14224
14243
  const trimmed = url.trim().replace(/\.git$/, "");
@@ -14348,7 +14367,7 @@ function globToRegex(glob) {
14348
14367
  function escapeRe(s) {
14349
14368
  return s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
14350
14369
  }
14351
- var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, cachedConfig, AUTO_WORKSPACE_MAX_DEPTH;
14370
+ var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
14352
14371
  var init_project_resolver = __esm({
14353
14372
  "../engine/dist/core/project-resolver.js"() {
14354
14373
  "use strict";
@@ -14359,6 +14378,7 @@ var init_project_resolver = __esm({
14359
14378
  gitCache = /* @__PURE__ */ new Map();
14360
14379
  workspaceCache = /* @__PURE__ */ new Map();
14361
14380
  cachedConfig = null;
14381
+ GIT_TIMEOUT_MS = 1e4;
14362
14382
  AUTO_WORKSPACE_MAX_DEPTH = 2;
14363
14383
  }
14364
14384
  });
@@ -19213,7 +19233,7 @@ var init_http = __esm({
19213
19233
  CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19214
19234
  } catch {
19215
19235
  try {
19216
- if (true) CLI_VERSION = "0.5.28";
19236
+ if (true) CLI_VERSION = "0.5.29";
19217
19237
  } catch {
19218
19238
  }
19219
19239
  }
@@ -19721,7 +19741,7 @@ var init_telemetry = __esm({
19721
19741
  init_sync_client();
19722
19742
  cliVersion = () => {
19723
19743
  try {
19724
- return true ? "0.5.28" : "dev";
19744
+ return true ? "0.5.29" : "dev";
19725
19745
  } catch {
19726
19746
  return "dev";
19727
19747
  }
@@ -21586,7 +21606,7 @@ var init_sync_client = __esm({
21586
21606
  ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
21587
21607
  } catch {
21588
21608
  try {
21589
- if (true) ownVersion = "0.5.28";
21609
+ if (true) ownVersion = "0.5.29";
21590
21610
  } catch {
21591
21611
  }
21592
21612
  }
@@ -24374,7 +24394,7 @@ try {
24374
24394
  ownVersion2 = JSON.parse(readFileSync41(join50(dir, "../package.json"), "utf-8")).version || ownVersion2;
24375
24395
  } catch {
24376
24396
  try {
24377
- if (true) ownVersion2 = "0.5.28";
24397
+ if (true) ownVersion2 = "0.5.29";
24378
24398
  } catch {
24379
24399
  }
24380
24400
  }
@@ -24718,7 +24738,7 @@ async function runCollectorMigration(opts) {
24718
24738
  init_sync_ledger();
24719
24739
  init_collector_health();
24720
24740
  import { existsSync as existsSync50, readFileSync as readFileSync46 } from "fs";
24721
- var CLI_VERSION3 = true ? "0.5.28" : "0.0.0";
24741
+ var CLI_VERSION3 = true ? "0.5.29" : "0.0.0";
24722
24742
  var DEBOUNCE_MS = 5e3;
24723
24743
  var CLAUDE_DIR = claudeBackend.projectsDir();
24724
24744
  var PLANS_DIR = claudeBackend.plansDir();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chat-recall",
3
- "version": "0.5.28",
3
+ "version": "0.5.29",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/munhq/chat-recall.git"
@@ -59,12 +59,25 @@ diary conclusions, and cost. Accepts a path, a name substring, or a project id
59
59
 
60
60
  ## Tasks and team (shared, not personal notes)
61
61
 
62
+ **Working the board out loud.** When you take work from here, say so: that you are
63
+ pulling tasks from the chat-recall board, which ones you picked, and — as each one
64
+ lands — that it is done and what changed. The board is the user's, and a card that
65
+ claims and closes itself with no word to them is how it stopped being trusted the
66
+ first time. `recall_tasks detail:true` gives you the brief, the locations and the
67
+ agent prompt for each card, so "what can I pick up" is one call.
68
+
69
+
62
70
  - `mcp__chat-recall__recall_tasks` — the shared task board: status, assignee,
63
71
  project. This is the answer to "what are my open tasks".
64
72
  - `mcp__chat-recall__recall_task_create` — create a task, optionally assigned to
65
73
  a teammate and attached to a project. Returns the new task id.
66
74
  - `mcp__chat-recall__recall_task_update` — change status, reassign, rename or
67
75
  comment. Takes the `t_…` id from `recall_tasks`.
76
+ - **`done` needs the CHANGE.** Pass `diff` — the unified diff of what you changed
77
+ for that card — and `commits` if you committed it. Nothing else can supply it:
78
+ the board cannot see edits made through a shell, and its commit scan only
79
+ searches repositories the session already touched with file tools. The diff you
80
+ record is what the person reads on the card.
68
81
  - **`done` needs the session that did the work.** Pass your own session id;
69
82
  without one the update is refused. A card asserts a problem in the code, so
70
83
  closing it asserts the code changed, and the board shows the files and commits
@@ -73,6 +86,10 @@ diary conclusions, and cost. Accepts a path, a name substring, or a project id
73
86
  - Cards filed from findings also close THEMSELVES once a re-index stops
74
87
  reporting the finding, so fixing the code and re-indexing is usually enough.
75
88
  Attach your session anyway: the closure keeps its evidence.
89
+ - **Stay inside the card's project.** A card names one repository; fix it there
90
+ and nowhere else. If the real fix needs a change in another repo, say so and
91
+ leave the card open — the API refuses evidence whose file paths climb out of
92
+ the project, and a diff spanning repositories cannot be reviewed as one change.
76
93
  - Filing is capped — at most 10 new cards per run and 50 open at once. A board
77
94
  at the ceiling files nothing until cards close; the backlog stays visible in
78
95
  the ranked findings view.