@open-agent-toolkit/cli 0.1.12 → 0.1.14

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 (45) hide show
  1. package/assets/agents/oat-reviewer.md +54 -10
  2. package/assets/docs/workflows/projects/reviews.md +21 -2
  3. package/assets/docs/workflows/skills/index.md +2 -0
  4. package/assets/public-package-versions.json +4 -4
  5. package/assets/skills/oat-project-review-provide-remote/SKILL.md +354 -0
  6. package/assets/skills/oat-project-review-receive/SKILL.md +7 -10
  7. package/assets/skills/oat-project-review-receive-remote/SKILL.md +4 -4
  8. package/assets/skills/oat-review-provide-remote/SKILL.md +273 -0
  9. package/assets/skills/oat-review-receive/SKILL.md +6 -6
  10. package/assets/skills/oat-review-receive-remote/SKILL.md +5 -5
  11. package/dist/commands/init/tools/shared/skill-manifest.d.ts +2 -2
  12. package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
  13. package/dist/commands/init/tools/shared/skill-manifest.js +2 -0
  14. package/dist/config/json.d.ts +2 -0
  15. package/dist/config/json.d.ts.map +1 -0
  16. package/dist/config/json.js +29 -0
  17. package/dist/config/oat-config.d.ts.map +1 -1
  18. package/dist/config/oat-config.js +4 -3
  19. package/dist/config/sync-config.d.ts.map +1 -1
  20. package/dist/config/sync-config.js +2 -1
  21. package/dist/review-remote/body-builder.d.ts +79 -0
  22. package/dist/review-remote/body-builder.d.ts.map +1 -0
  23. package/dist/review-remote/body-builder.js +103 -0
  24. package/dist/review-remote/capability-probe.d.ts +61 -0
  25. package/dist/review-remote/capability-probe.d.ts.map +1 -0
  26. package/dist/review-remote/capability-probe.js +87 -0
  27. package/dist/review-remote/line-mapper.d.ts +81 -0
  28. package/dist/review-remote/line-mapper.d.ts.map +1 -0
  29. package/dist/review-remote/line-mapper.js +165 -0
  30. package/dist/review-remote/marker-parser.d.ts +44 -0
  31. package/dist/review-remote/marker-parser.d.ts.map +1 -0
  32. package/dist/review-remote/marker-parser.js +97 -0
  33. package/dist/review-remote/narrowing.d.ts +81 -0
  34. package/dist/review-remote/narrowing.d.ts.map +1 -0
  35. package/dist/review-remote/narrowing.js +90 -0
  36. package/dist/review-remote/project-resolver.d.ts +46 -0
  37. package/dist/review-remote/project-resolver.d.ts.map +1 -0
  38. package/dist/review-remote/project-resolver.js +60 -0
  39. package/dist/review-remote/reviewer-dispatch.d.ts +108 -0
  40. package/dist/review-remote/reviewer-dispatch.d.ts.map +1 -0
  41. package/dist/review-remote/reviewer-dispatch.js +153 -0
  42. package/dist/review-remote/worktree.d.ts +62 -0
  43. package/dist/review-remote/worktree.d.ts.map +1 -0
  44. package/dist/review-remote/worktree.js +117 -0
  45. package/package.json +3 -2
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Ephemeral worktree lifecycle helper (see design.md → Data Flow step 2).
3
+ *
4
+ * The provide-remote skills review a PR without mutating the caller's working
5
+ * tree. They acquire an ephemeral, repo-scoped worktree, run `gh pr checkout`
6
+ * INSIDE it (that step lives in the skill, not here), review, then tear the
7
+ * worktree down. This helper owns only the create/run/release lifecycle:
8
+ *
9
+ * - `acquireWorktree({ repoRoot })` — `mktemp -d` an ephemeral path OUTSIDE
10
+ * `repoRoot`, then `git -C "$repoRoot" worktree add --detach <path> HEAD`.
11
+ * The `-C "$repoRoot"` flag is load-bearing: it lets the command run even
12
+ * when the caller's CWD is not inside the repository (a thin remote-review
13
+ * machine invoking the skill from a home directory). `HEAD` is a
14
+ * placeholder ref the skill overwrites with `gh pr checkout <N>`.
15
+ * - `runInWorktree(handle, cb)` — invoke `cb(worktreePath)`. The helper does
16
+ * NOT chdir the host process; it passes the path so callers run repo-scoped
17
+ * git / `cd "$path" && gh pr checkout` in a subshell. This keeps the
18
+ * caller's CWD unchanged (verified by tests).
19
+ * - `releaseWorktree(handle)` — `git -C "$repoRoot" worktree remove --force`
20
+ * then remove the temp directory. Idempotent and safe even if the worktree
21
+ * never populated, so callers run it in a `finally`.
22
+ *
23
+ * Design Open Question resolution: `oat-worktree-bootstrap-auto` reuse was
24
+ * considered but the helper is hand-rolled per the design fallback. The plan's
25
+ * mechanics (repo-scoped git invocation, ephemeral path outside repo root,
26
+ * force-removal teardown) are implemented directly here; the helper stays
27
+ * agnostic to PR checkout so it has no dependency on the bootstrap contract.
28
+ */
29
+ import { execFile as execFileCallback } from 'node:child_process';
30
+ import { mkdtempSync, rmSync } from 'node:fs';
31
+ import { tmpdir } from 'node:os';
32
+ import { join } from 'node:path';
33
+ import { promisify } from 'node:util';
34
+ const execFile = promisify(execFileCallback);
35
+ /**
36
+ * Create an ephemeral, detached worktree outside the repo root and register it
37
+ * with git. The path is created via `mktemp`-style `mkdtempSync` under the
38
+ * system temp dir, so it is guaranteed to be outside `repoRoot`.
39
+ */
40
+ export async function acquireWorktree(options) {
41
+ const { repoRoot } = options;
42
+ // Ephemeral path under the OS temp dir — outside repoRoot by construction.
43
+ const worktreePath = mkdtempSync(join(tmpdir(), 'oat-review-wt-'));
44
+ // `git worktree add` requires the target path to NOT already exist, so remove
45
+ // the placeholder mkdtemp directory and let git create it fresh.
46
+ rmSync(worktreePath, { recursive: true, force: true });
47
+ try {
48
+ await execFile('git', [
49
+ '-C',
50
+ repoRoot,
51
+ 'worktree',
52
+ 'add',
53
+ '--detach',
54
+ worktreePath,
55
+ 'HEAD',
56
+ ]);
57
+ }
58
+ catch (error) {
59
+ // `git worktree add` can fail after partially creating the target dir
60
+ // and/or registering `.git/worktrees/<name>` metadata. Because we throw
61
+ // without returning a handle, the caller's `finally { releaseWorktree }`
62
+ // never runs — so clean up the partial worktree here before rethrowing.
63
+ // Best-effort: prune dangling worktree metadata, then remove the temp dir.
64
+ try {
65
+ await execFile('git', ['-C', repoRoot, 'worktree', 'prune']);
66
+ }
67
+ catch {
68
+ // Best-effort; ignore (e.g. repoRoot is not a git repo).
69
+ }
70
+ rmSync(worktreePath, { recursive: true, force: true });
71
+ throw error;
72
+ }
73
+ return { repoRoot, worktreePath, released: false };
74
+ }
75
+ /**
76
+ * Run a callback "inside" the worktree. The callback receives the worktree
77
+ * path; the helper does not change the host process's working directory, so
78
+ * callers must scope filesystem / git operations to that path themselves
79
+ * (e.g., `git -C <path> …` or `cd <path> && gh pr checkout` in a subshell).
80
+ */
81
+ export async function runInWorktree(handle, callback) {
82
+ return callback(handle.worktreePath);
83
+ }
84
+ /**
85
+ * Remove the git worktree (force) and clean up the temp directory. Idempotent:
86
+ * a second call is a no-op, and a failed `git worktree remove` (e.g., the
87
+ * worktree never populated, or was already pruned) does not prevent the temp
88
+ * directory cleanup. Safe to call in a `finally`.
89
+ */
90
+ export async function releaseWorktree(handle) {
91
+ if (handle.released) {
92
+ return;
93
+ }
94
+ handle.released = true;
95
+ try {
96
+ await execFile('git', [
97
+ '-C',
98
+ handle.repoRoot,
99
+ 'worktree',
100
+ 'remove',
101
+ '--force',
102
+ handle.worktreePath,
103
+ ]);
104
+ }
105
+ catch {
106
+ // `worktree remove` can fail if the worktree was never populated or was
107
+ // already removed. That is non-fatal — proceed to temp cleanup so we never
108
+ // leak the directory, then prune stale worktree metadata best-effort.
109
+ try {
110
+ await execFile('git', ['-C', handle.repoRoot, 'worktree', 'prune']);
111
+ }
112
+ catch {
113
+ // Best-effort; ignore.
114
+ }
115
+ }
116
+ rmSync(handle.worktreePath, { recursive: true, force: true });
117
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-agent-toolkit/cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "private": false,
5
5
  "description": "Open Agent Toolkit CLI",
6
6
  "homepage": "https://github.com/voxmedia/open-agent-toolkit/tree/main/packages/cli",
@@ -30,10 +30,11 @@
30
30
  "@inquirer/prompts": "^8.2.0",
31
31
  "chalk": "^5.6.2",
32
32
  "commander": "^12.1.0",
33
+ "jsonc-parser": "3.2.1",
33
34
  "ora": "^9.0.0",
34
35
  "yaml": "2.8.2",
35
36
  "zod": "^3.25.76",
36
- "@open-agent-toolkit/control-plane": "0.1.12"
37
+ "@open-agent-toolkit/control-plane": "0.1.14"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/node": "^22.10.0",