codiedev 0.9.11 → 0.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/utils.js +46 -20
  2. package/package.json +1 -1
package/dist/utils.js CHANGED
@@ -285,40 +285,49 @@ function resolveCaptureDir(transcriptContent, workspaceRoot) {
285
285
  // used (work done directly in the repo).
286
286
  function resolveCaptureDirs(transcriptContent, workspaceRoot) {
287
287
  const rootGitDir = resolveGitDir(workspaceRoot);
288
- // Collect EVERY filesystem path the session referenced, in order — not just
289
- // the session cwd. An agent can touch a worktree without cd-ing into it:
290
- // - `git -C <path> ...` (operate on a worktree by path)
291
- // - editing a file inside it ("file_path": "<worktree>/src/x.ts")
292
- // Catching all of these is what makes worktree detection robust.
288
+ // Collect the folders the session WROTE to (not merely referenced), in order:
289
+ // - the session cwd
290
+ // - `git -C <path>` of MUTATING git commands (commit/push/add/...) — NOT
291
+ // read-only ones (log/status/diff), which would falsely credit a worktree
292
+ // the session only inspected
293
+ // - the dir of files edited via Edit/Write/NotebookEdit — NOT Read/Grep/Glob
294
+ // Reading/inspecting another worktree must not attribute its PRs to this
295
+ // session (that also corrupts the even cost-split).
293
296
  const candidates = [];
294
297
  const add = (p) => {
295
298
  if (!p)
296
299
  return;
297
300
  candidates.push(path.isAbsolute(p) ? p : path.resolve(workspaceRoot, p));
298
301
  };
299
- const gitCRe = /git\s+(?:[^\s]+\s+)*?-C\s+(?:"([^"]+)"|'([^']+)'|(\S+))/g;
300
- const filePathRe = /"file_path"\s*:\s*"((?:[^"\\]|\\.)+)"/g;
301
302
  for (const line of transcriptContent.split("\n")) {
302
303
  if (!line.trim())
303
304
  continue;
305
+ let entry;
304
306
  try {
305
- const entry = JSON.parse(line);
306
- if (typeof entry?.cwd === "string" && entry.cwd)
307
- add(entry.cwd);
307
+ entry = JSON.parse(line);
308
308
  }
309
309
  catch {
310
- // non-JSON / partial line — still scan the raw text below
310
+ // partial/non-JSON line — best-effort: only mutating git -C, never files.
311
+ for (const d of mutatingGitCDirs(line))
312
+ add(d);
313
+ continue;
311
314
  }
312
- let m;
313
- gitCRe.lastIndex = 0;
314
- while ((m = gitCRe.exec(line)))
315
- add(m[1] ?? m[2] ?? m[3]);
316
- filePathRe.lastIndex = 0;
317
- while ((m = filePathRe.exec(line))) {
318
- try {
319
- add(path.dirname(JSON.parse(`"${m[1]}"`)));
315
+ if (typeof entry?.cwd === "string" && entry.cwd)
316
+ add(entry.cwd);
317
+ const content = entry?.message?.content;
318
+ if (!Array.isArray(content))
319
+ continue;
320
+ for (const b of content) {
321
+ if (b?.type !== "tool_use")
322
+ continue;
323
+ if (b.name === "Bash" && typeof b.input?.command === "string") {
324
+ for (const d of mutatingGitCDirs(b.input.command))
325
+ add(d);
326
+ }
327
+ else if ((b.name === "Edit" || b.name === "Write" || b.name === "NotebookEdit") &&
328
+ typeof (b.input?.file_path ?? b.input?.notebook_path) === "string") {
329
+ add(path.dirname(b.input.file_path ?? b.input.notebook_path));
320
330
  }
321
- catch { /* skip */ }
322
331
  }
323
332
  }
324
333
  // Walk most-recent first; one entry per distinct worktree gitdir (a worktree's
@@ -338,6 +347,23 @@ function resolveCaptureDirs(transcriptContent, workspaceRoot) {
338
347
  }
339
348
  return out.length > 0 ? out : [workspaceRoot];
340
349
  }
350
+ // Extract the `-C <path>` targets of MUTATING git commands in a shell string.
351
+ // Splits on command separators and only takes a sub-command's -C path when that
352
+ // sub-command runs a state-changing git verb — so `git -C x log` is ignored but
353
+ // `git -C x commit`/`push`/`add` count.
354
+ const MUTATING_GIT = /\b(?:commit|push|add|checkout|switch|merge|rebase|reset|restore|rm|mv|stash|apply|cherry-pick|am|tag|worktree)\b/;
355
+ function mutatingGitCDirs(command) {
356
+ const out = [];
357
+ for (const sub of command.split(/&&|\|\||;|\n/)) {
358
+ if (!/\bgit\b/.test(sub) || !MUTATING_GIT.test(sub))
359
+ continue;
360
+ const re = /-C\s+(?:"([^"]+)"|'([^']+)'|(\S+))/g;
361
+ let m;
362
+ while ((m = re.exec(sub)))
363
+ out.push(m[1] ?? m[2] ?? m[3]);
364
+ }
365
+ return out;
366
+ }
341
367
  // A linked worktree's gitdir (`.git/worktrees/<name>`) holds a `gitdir` file
342
368
  // pointing at the worktree's own `.git` file; its parent is the worktree root.
343
369
  function worktreeRootFromGitDir(gitDir) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.11",
3
+ "version": "0.9.12",
4
4
  "description": "Connect Claude Code, Codex, Cursor, or VS Code Copilot to Codiedev for org-wide session capture and artifact collaboration",
5
5
  "bin": {
6
6
  "codiedev": "dist/cli.js",