@a2f0/agent-tool 0.1.10 → 0.1.11
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/README.md +54 -0
- package/package.json +1 -1
- package/skills/cross-agent-review/SKILL.md +7 -0
- package/skills/ship-pr/SKILL.md +12 -0
- package/skills/update-dependencies/SKILL.md +9 -0
- package/src/cli.ts +7 -1
- package/src/commands/logFile.ts +11 -0
- package/src/commands/output.ts +62 -0
- package/src/commands/run.ts +93 -0
- package/src/index.ts +1 -1
- package/src/review/diagnostics.ts +24 -0
- package/src/review/solicitClaudeCodeReview.ts +4 -3
- package/src/review/solicitCodexReview.ts +7 -14
- package/src/review/solicitOpencodeReview.ts +5 -15
- package/src/skills/bundled.ts +3 -3
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@ version management, and portable skills for Claude Code, Codex, and OpenCode.
|
|
|
11
11
|
`bun.lock` in sync.
|
|
12
12
|
- **Share skills**: install the same workflow instructions where each harness
|
|
13
13
|
discovers them, and check them in CI.
|
|
14
|
+
- **Compact output**: run noisy commands with full private logs and bounded
|
|
15
|
+
diagnostics, keeping routine output out of an agent's context.
|
|
14
16
|
|
|
15
17
|
## Install
|
|
16
18
|
|
|
@@ -95,6 +97,8 @@ agent-tool skills install --apply
|
|
|
95
97
|
|
|
96
98
|
| Command | Behavior |
|
|
97
99
|
| --- | --- |
|
|
100
|
+
| `run [--label text] [--max-bytes N] [--tail-lines N] -- <command> [args...]` | Run with full local logs and compact results; preserve exit status |
|
|
101
|
+
| `logs <file> [--max-bytes N] [--tail-lines N]` | Inspect a bounded, terminal-safe tail of a local file |
|
|
98
102
|
| `review claude\|codex\|opencode [effort] [--base ref]` | Review committed HEAD using a pinned raw-file snapshot |
|
|
99
103
|
| `pr open [title]` | Open a same-repository PR; body from stdin; branch already pushed |
|
|
100
104
|
| `pr merge <subject-or-empty> <head-oid> <base-branch>` | Check CI and synchronously squash the reviewed HEAD |
|
|
@@ -119,6 +123,56 @@ A successful review exit means a complete review was returned, ending in a
|
|
|
119
123
|
command does not repair, push, or merge; the shipping skills coordinate that
|
|
120
124
|
work.
|
|
121
125
|
|
|
126
|
+
### Compact command output
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
agent-tool run --label tests -- bun test
|
|
130
|
+
agent-tool run --label build -- npm run build
|
|
131
|
+
agent-tool run --label checks -- sh -c 'npm run lint && npm test'
|
|
132
|
+
agent-tool logs /path/from/receipt/output.log --max-bytes 8192 --tail-lines 80
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`run` executes the argv after `--` directly, without a shell, in the current
|
|
136
|
+
directory (or `--repo`), with inherited environment and stdin. Use an explicit
|
|
137
|
+
shell only when the command needs shell syntax. The child receives regular files
|
|
138
|
+
for stdout and stderr, so interactive/TTY programs should run directly. This
|
|
139
|
+
works outside Git and does not depend on project policy or a package manager.
|
|
140
|
+
Use it for finite commands; long-running servers need their own lifecycle.
|
|
141
|
+
|
|
142
|
+
Both streams go directly to one private log: even gigabytes of output do not
|
|
143
|
+
accumulate in the runner's memory. On completion, stdout contains one JSON
|
|
144
|
+
receipt with `status`, `exitCode`, `signal`, `durationMs`, `outputBytes`, and
|
|
145
|
+
`log` (plus an optional label of at most 120 characters). Command arguments and
|
|
146
|
+
environment are not copied to the receipt. A success emits no log content;
|
|
147
|
+
failure adds a terminal-control-stripped tail on stderr. The default tail is at
|
|
148
|
+
most 4096 bytes and 40 lines, with explicit limits up to 65536 bytes and 1000
|
|
149
|
+
lines. Limits bound the excerpt after decoding too, including one huge line or
|
|
150
|
+
invalid UTF-8; receipt metadata is additional. A command's numeric status is
|
|
151
|
+
preserved, missing executables return 127, and other launch failures return 126.
|
|
152
|
+
On macOS/Linux, SIGINT, SIGTERM, and SIGHUP are forwarded to the child process
|
|
153
|
+
group, with SIGKILL escalation after five seconds; the runner then terminates by
|
|
154
|
+
the original signal. Children that create a separate session escape that group;
|
|
155
|
+
SIGKILL of the runner cannot be intercepted. The command is not a sandbox.
|
|
156
|
+
|
|
157
|
+
Logs live in unique `agent-tool-run-*` directories under the system temporary
|
|
158
|
+
directory, with mode 0700 directories and 0600 files. They are retained until you
|
|
159
|
+
remove the specific directory reported by the receipt or the OS cleans temporary
|
|
160
|
+
files. Remove task logs after investigation; long or repeated commands can use
|
|
161
|
+
substantial disk space. There is no automatic age sweep or disk quota. Logs are
|
|
162
|
+
complete, raw, and may contain secrets; terminal cleanup is not secret redaction.
|
|
163
|
+
`logs` reads any explicitly supplied regular local file, including symlink targets;
|
|
164
|
+
it does not authenticate a file as an agent-tool artifact.
|
|
165
|
+
|
|
166
|
+
Use bounded log inspection or scoped searches for a failure, required warnings,
|
|
167
|
+
coverage, timing assertions, or build artifacts; do not reread successful suite
|
|
168
|
+
logs wholesale. Success means the command exited zero, not that its logs contain
|
|
169
|
+
no warnings. Keep structured output and decisions visible: run `review`,
|
|
170
|
+
`versions prepare`, audit reports, and infrastructure plan guards directly.
|
|
171
|
+
Review commands retain full reviewer stderr in separate private
|
|
172
|
+
`agent-tool-review-log-*` directories and show bounded stderr on failure, while
|
|
173
|
+
always displaying the final findings and verdict. Empty reviewer logs are removed.
|
|
174
|
+
The bundled shipping, review, and dependency skills use this distinction.
|
|
175
|
+
|
|
122
176
|
## Configuration
|
|
123
177
|
|
|
124
178
|
`agent-tool init` creates `agent-tool.json` and never overwrites an existing
|
package/package.json
CHANGED
|
@@ -14,6 +14,13 @@ Select a reviewer different from the coordinating agent when possible. Honor a
|
|
|
14
14
|
requested reviewer or effort; otherwise use an available independent reviewer.
|
|
15
15
|
Run `agent-tool doctor` if CLI compatibility is uncertain.
|
|
16
16
|
|
|
17
|
+
Run noisy validation or repair checks through
|
|
18
|
+
`agent-tool run --label <check> -- <command> [args...]`. Read its bounded failure
|
|
19
|
+
tail and use `agent-tool logs <log>` or a targeted search for more evidence.
|
|
20
|
+
Keep `agent-tool review` direct: it retains reviewer stderr in a private local
|
|
21
|
+
log and displays the complete final review. Never hide, truncate, or substitute
|
|
22
|
+
a command success receipt for findings and the final verdict.
|
|
23
|
+
|
|
17
24
|
Review committed changes with `agent-tool review claude`, `agent-tool review codex`,
|
|
18
25
|
or `agent-tool review opencode`. Optional effort is `low`, `medium`, `high`,
|
|
19
26
|
`xhigh`, or `max`. For a local or non-GitHub repository, add `--base <commit-or-ref>`.
|
package/skills/ship-pr/SKILL.md
CHANGED
|
@@ -11,6 +11,18 @@ concerns. Shipping authorizes this workflow within the user's stated scope.
|
|
|
11
11
|
Preserve unrelated edits and honor requested stopping points such as open-PR
|
|
12
12
|
only, report-only review, or keeping the feature branch.
|
|
13
13
|
|
|
14
|
+
Use `agent-tool run --label <check> -- <command> [args...]` for noisy setup,
|
|
15
|
+
validation, builds, and hook-running Git commands. It preserves exit status and
|
|
16
|
+
complete private logs, prints one success receipt, and shows a bounded failure
|
|
17
|
+
tail. Inspect more with `agent-tool logs <log> --max-bytes 8192 --tail-lines 80`
|
|
18
|
+
or a targeted search; never dump an entire suite log or pipe checks into `tail`.
|
|
19
|
+
The receipt proves process completion, not absence of warnings: inspect required
|
|
20
|
+
warning, coverage, timing, or artifact evidence before accepting a check. Keep
|
|
21
|
+
machine-readable receipts and review findings visible by running `versions
|
|
22
|
+
prepare`, `review`, and other commands whose output drives a decision directly.
|
|
23
|
+
Prefer documented compact test reporters when they preserve required evidence;
|
|
24
|
+
do not reduce test scope, skip checks, silence warnings, or mask failures.
|
|
25
|
+
|
|
14
26
|
1. Finish the requested change on a feature branch. Create it with
|
|
15
27
|
`git switch --no-track -c <branch>`; settings such as
|
|
16
28
|
`branch.autosetupmerge=always` otherwise make it track a local branch.
|
|
@@ -14,6 +14,15 @@ changing global tools; use existing user authorization and `ship-pr` when shippi
|
|
|
14
14
|
is requested. Default dependency-update merge subject: `chore: update dependencies`,
|
|
15
15
|
subject to repository title policy and any explicit user subject.
|
|
16
16
|
|
|
17
|
+
Run noisy installs, checks, tests, and builds with
|
|
18
|
+
`agent-tool run --label <check> -- <command> [args...]` to retain full private
|
|
19
|
+
logs and return the original status with compact output. Inspect bounded excerpts
|
|
20
|
+
using `agent-tool logs <log>` and targeted searches for warnings and evidence;
|
|
21
|
+
a successful receipt does not establish a warning-free upgrade. Keep structured
|
|
22
|
+
audit/plan results, deployment previews, and review findings directly visible
|
|
23
|
+
when they drive a safety decision. Do not dump full suite logs into context,
|
|
24
|
+
silence warnings at their source, or change check scope to reduce output.
|
|
25
|
+
|
|
17
26
|
## Safety before execution
|
|
18
27
|
|
|
19
28
|
**Always dry-run before any infrastructure apply or deployment. Never destroy,
|
package/src/cli.ts
CHANGED
|
@@ -14,11 +14,15 @@ import { resolveVersionConflicts } from "./version/resolveVersionConflicts";
|
|
|
14
14
|
import { openPr } from "./pr/openPr";
|
|
15
15
|
import { squashMerge } from "./pr/squashMerge";
|
|
16
16
|
import metadata from "../package.json";
|
|
17
|
+
import { runCommand } from "./commands/run";
|
|
18
|
+
import { inspectLog } from "./commands/output";
|
|
17
19
|
|
|
18
20
|
export const HELP = `agent-tool ${metadata.version}
|
|
19
21
|
|
|
20
22
|
Usage: agent-tool [--repo <directory>] [--config <file>] <command>
|
|
21
23
|
|
|
24
|
+
run [--label text] [--max-bytes N] [--tail-lines N] -- <command> [args...]
|
|
25
|
+
logs <file> [--max-bytes N] [--tail-lines N] Bounded local log tail
|
|
22
26
|
review <claude|codex|opencode> [effort] [--base <local-ref>]
|
|
23
27
|
pr open [title] Body from stdin; branch already pushed
|
|
24
28
|
pr merge <subject-or-empty> <head-oid> <base-branch>
|
|
@@ -45,7 +49,7 @@ function gitRoot(): string {
|
|
|
45
49
|
return execFileSync("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
export function main(argv = process.argv.slice(2)): number {
|
|
52
|
+
export function main(argv = process.argv.slice(2)): number | Promise<number> {
|
|
49
53
|
const args = [...argv];
|
|
50
54
|
while (args[0] === "--repo" || args[0] === "--config") {
|
|
51
55
|
const flag = args.shift()!;
|
|
@@ -60,6 +64,8 @@ export function main(argv = process.argv.slice(2)): number {
|
|
|
60
64
|
writeSync(1, HELP); return 0;
|
|
61
65
|
}
|
|
62
66
|
if (command === "--version") { usage(args.length === 0, "Unexpected version arguments."); writeSync(1, `${metadata.version}\n`); return 0; }
|
|
67
|
+
if (command === "run") return runCommand(args);
|
|
68
|
+
if (command === "logs") return inspectLog(args);
|
|
63
69
|
if (command === "dependencies") {
|
|
64
70
|
usage(args.length === 2 && args[0] === "check-terraform-plan", "Usage: agent-tool dependencies check-terraform-plan <json-file>");
|
|
65
71
|
const source = readFileSync(args[1], "utf8");
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { chmodSync, mkdtempSync, openSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
export function createLog(prefix = "agent-tool-run-"): { directory: string; log: string; fd: number } {
|
|
6
|
+
const directory = mkdtempSync(path.join(tmpdir(), prefix));
|
|
7
|
+
chmodSync(directory, 0o700);
|
|
8
|
+
const log = path.join(directory, "output.log");
|
|
9
|
+
const fd = openSync(log, "wx", 0o600);
|
|
10
|
+
return { directory, log, fd };
|
|
11
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { closeSync, constants, fstatSync, openSync, readSync, writeSync } from "node:fs";
|
|
2
|
+
import { stripVTControlCharacters } from "node:util";
|
|
3
|
+
|
|
4
|
+
export interface OutputLimits { maxBytes: number; tailLines: number }
|
|
5
|
+
export const DEFAULT_LIMITS: OutputLimits = { maxBytes: 4096, tailLines: 40 };
|
|
6
|
+
|
|
7
|
+
export function outputLimit(flag: string, value: string | undefined): number {
|
|
8
|
+
const maximum = flag === "--max-bytes" ? 65536 : 1000;
|
|
9
|
+
if (!value || !/^\d+$/.test(value) || Number(value) < 1 || Number(value) > maximum) {
|
|
10
|
+
throw new Error(`${flag} requires an integer from 1 to ${maximum}.`);
|
|
11
|
+
}
|
|
12
|
+
return Number(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function plainText(value: string): string {
|
|
16
|
+
return stripVTControlCharacters(value).replace(/\r\n/g, "\n").replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, "");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Read at most maxBytes, including when the last line is gigabytes long. */
|
|
20
|
+
export function logTail(file: string, limits: OutputLimits): { text: string; bytes: number; truncated: boolean } {
|
|
21
|
+
const fd = openSync(file, constants.O_RDONLY | constants.O_NONBLOCK);
|
|
22
|
+
try {
|
|
23
|
+
const stat = fstatSync(fd);
|
|
24
|
+
if (!stat.isFile()) throw new Error("Log inspection requires a regular file.");
|
|
25
|
+
const buffer = Buffer.alloc(Math.min(stat.size, limits.maxBytes));
|
|
26
|
+
const size = readSync(fd, buffer, 0, buffer.length, Math.max(0, stat.size - buffer.length));
|
|
27
|
+
let text = plainText(buffer.subarray(0, size).toString("utf8"));
|
|
28
|
+
const lines = text.replace(/\n$/, "").split("\n");
|
|
29
|
+
let truncated = stat.size > size || lines.length > limits.tailLines;
|
|
30
|
+
text = lines.slice(-limits.tailLines).join("\n");
|
|
31
|
+
// Invalid UTF-8 can expand to replacement characters; enforce the byte cap
|
|
32
|
+
// after decoding and terminal-control removal as well.
|
|
33
|
+
const encoded = Buffer.from(text);
|
|
34
|
+
if (encoded.length > limits.maxBytes) {
|
|
35
|
+
truncated = true;
|
|
36
|
+
let offset = encoded.length - limits.maxBytes;
|
|
37
|
+
while ((encoded[offset] & 0xc0) === 0x80) offset++;
|
|
38
|
+
text = encoded.subarray(offset).toString("utf8");
|
|
39
|
+
}
|
|
40
|
+
return { text, bytes: stat.size, truncated };
|
|
41
|
+
} finally { closeSync(fd); }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function printLogTail(file: string, limits: OutputLimits, fd = 1): void {
|
|
45
|
+
const tail = logTail(file, limits);
|
|
46
|
+
writeSync(fd, `${JSON.stringify({ log: file, outputBytes: tail.bytes, truncated: tail.truncated })}\n`);
|
|
47
|
+
if (tail.text) writeSync(fd, `${tail.text}\n`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function inspectLog(args: string[]): number {
|
|
51
|
+
const file = args.shift();
|
|
52
|
+
if (!file || file.startsWith("--")) throw new Error("Usage: agent-tool logs <file> [--max-bytes N] [--tail-lines N]");
|
|
53
|
+
const limits = { ...DEFAULT_LIMITS };
|
|
54
|
+
while (args.length) {
|
|
55
|
+
const flag = args.shift();
|
|
56
|
+
if (flag === "--max-bytes") limits.maxBytes = outputLimit(flag, args.shift());
|
|
57
|
+
else if (flag === "--tail-lines") limits.tailLines = outputLimit(flag, args.shift());
|
|
58
|
+
else throw new Error(`Unknown logs argument '${flag}'.`);
|
|
59
|
+
}
|
|
60
|
+
printLogTail(file, limits);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { closeSync, fstatSync, writeSync } from "node:fs";
|
|
3
|
+
import { constants } from "node:os";
|
|
4
|
+
import { DEFAULT_LIMITS, outputLimit, plainText, printLogTail } from "./output";
|
|
5
|
+
import { createLog } from "./logFile";
|
|
6
|
+
|
|
7
|
+
const FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"] as const;
|
|
8
|
+
|
|
9
|
+
/** Run directly into a private file: child output never accumulates in memory. */
|
|
10
|
+
export async function runCommand(args: string[]): Promise<number> {
|
|
11
|
+
const limits = { ...DEFAULT_LIMITS };
|
|
12
|
+
let label: string | undefined;
|
|
13
|
+
while (args[0] !== "--" && args.length) {
|
|
14
|
+
const flag = args.shift();
|
|
15
|
+
if (flag === "--max-bytes") limits.maxBytes = outputLimit(flag, args.shift());
|
|
16
|
+
else if (flag === "--tail-lines") limits.tailLines = outputLimit(flag, args.shift());
|
|
17
|
+
else if (flag === "--label") {
|
|
18
|
+
label = args.shift();
|
|
19
|
+
if (!label || label.length > 120) throw new Error("--label requires 1 to 120 characters.");
|
|
20
|
+
label = plainText(label);
|
|
21
|
+
} else throw new Error(`Unknown run argument '${flag}'.`);
|
|
22
|
+
}
|
|
23
|
+
if (args.shift() !== "--" || !args[0]) throw new Error("Usage: agent-tool run [--label text] [--max-bytes N] [--tail-lines N] -- <command> [args...]");
|
|
24
|
+
const { log, fd } = createLog();
|
|
25
|
+
const started = performance.now();
|
|
26
|
+
let interrupted: NodeJS.Signals | null = null;
|
|
27
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
28
|
+
let cancelDeadline = Infinity;
|
|
29
|
+
const handlers = new Map<NodeJS.Signals, () => void>();
|
|
30
|
+
const grouped = process.platform !== "win32";
|
|
31
|
+
let status: number | null = null;
|
|
32
|
+
let signal: NodeJS.Signals | null = null;
|
|
33
|
+
try {
|
|
34
|
+
const child = spawn(args[0], args.slice(1), {
|
|
35
|
+
stdio: ["inherit", fd, fd], detached: grouped, env: process.env,
|
|
36
|
+
});
|
|
37
|
+
const forward = (value: NodeJS.Signals) => {
|
|
38
|
+
if (!child.pid) return;
|
|
39
|
+
try {
|
|
40
|
+
if (grouped) process.kill(-child.pid, value);
|
|
41
|
+
else child.kill(value);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if ((error as NodeJS.ErrnoException).code !== "ESRCH") throw error;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
for (const value of FORWARDED_SIGNALS) {
|
|
47
|
+
const handler = () => {
|
|
48
|
+
interrupted ??= value;
|
|
49
|
+
cancelDeadline = Math.min(cancelDeadline, performance.now() + 5000);
|
|
50
|
+
forward(value);
|
|
51
|
+
// A child may ignore cancellation; do not leave its process group behind.
|
|
52
|
+
timer ??= setTimeout(() => forward("SIGKILL"), 5000);
|
|
53
|
+
};
|
|
54
|
+
handlers.set(value, handler);
|
|
55
|
+
process.on(value, handler);
|
|
56
|
+
}
|
|
57
|
+
const result = await new Promise<{ status: number | null; signal: NodeJS.Signals | null }>(resolve => {
|
|
58
|
+
child.once("error", (error: NodeJS.ErrnoException) => {
|
|
59
|
+
writeSync(fd, `Unable to start command: ${error.message}\n`);
|
|
60
|
+
resolve({ status: error.code === "ENOENT" ? 127 : 126, signal: null });
|
|
61
|
+
});
|
|
62
|
+
child.once("close", (code, childSignal) => resolve({ status: code, signal: childSignal }));
|
|
63
|
+
});
|
|
64
|
+
status = result.status;
|
|
65
|
+
signal = interrupted ?? result.signal;
|
|
66
|
+
if (interrupted) {
|
|
67
|
+
// The direct child can exit before its descendants finish cleanup. Keep
|
|
68
|
+
// the original grace period for the remaining process group as well.
|
|
69
|
+
while (grouped && child.pid && performance.now() < cancelDeadline) {
|
|
70
|
+
try { process.kill(-child.pid, 0); }
|
|
71
|
+
catch (error) {
|
|
72
|
+
if ((error as NodeJS.ErrnoException).code === "ESRCH") break;
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, 25));
|
|
76
|
+
}
|
|
77
|
+
forward("SIGKILL");
|
|
78
|
+
}
|
|
79
|
+
const exitCode = signal ? 128 + (constants.signals[signal] ?? 0) : status ?? 1;
|
|
80
|
+
writeSync(1, `${JSON.stringify({ status: exitCode === 0 ? "passed" : "failed", ...(label ? { label } : {}), exitCode, signal, durationMs: Math.round(performance.now() - started), outputBytes: fstatSync(fd).size, log })}\n`);
|
|
81
|
+
if (exitCode !== 0) printLogTail(log, limits, 2);
|
|
82
|
+
} finally {
|
|
83
|
+
if (timer) clearTimeout(timer);
|
|
84
|
+
for (const [value, handler] of handlers) process.removeListener(value, handler);
|
|
85
|
+
closeSync(fd);
|
|
86
|
+
}
|
|
87
|
+
// Preserve signal termination for calling shells/supervisors, after the receipt.
|
|
88
|
+
if (signal) {
|
|
89
|
+
process.kill(process.pid, signal);
|
|
90
|
+
return 128 + (constants.signals[signal] ?? 0);
|
|
91
|
+
}
|
|
92
|
+
return status ?? 1;
|
|
93
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { closeSync, fstatSync, rmSync, writeSync } from "node:fs";
|
|
2
|
+
import { createLog } from "../commands/logFile";
|
|
3
|
+
import { DEFAULT_LIMITS, printLogTail } from "../commands/output";
|
|
4
|
+
|
|
5
|
+
/** Reviewer stderr is a transcript, not the review. Keep it off the model's
|
|
6
|
+
* context while retaining complete local evidence and bounded failure details. */
|
|
7
|
+
export function withReviewDiagnostics<T extends { status: number | null; error?: Error }>(
|
|
8
|
+
reviewer: string, run: (fd: number) => T,
|
|
9
|
+
): T {
|
|
10
|
+
const { directory, log, fd } = createLog("agent-tool-review-log-");
|
|
11
|
+
try {
|
|
12
|
+
const result = run(fd);
|
|
13
|
+
const outputBytes = fstatSync(fd).size;
|
|
14
|
+
if (outputBytes > 0) {
|
|
15
|
+
writeSync(2, `${JSON.stringify({ reviewer, outputBytes, log })}\n`);
|
|
16
|
+
if (result.status !== 0 || result.error) printLogTail(log, DEFAULT_LIMITS, 2);
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
} finally {
|
|
20
|
+
const empty = fstatSync(fd).size === 0;
|
|
21
|
+
closeSync(fd);
|
|
22
|
+
if (empty) rmSync(directory, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "./reviewEffort";
|
|
17
17
|
import { buildReviewPrompt, CLAUDE_ACCESS_NOTE } from "./reviewPrompt";
|
|
18
18
|
import { type ReviewerEnv, relayReviewWithRetry } from "./runReview";
|
|
19
|
+
import { withReviewDiagnostics } from "./diagnostics";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Tools the reviewer gets. Read-only, and deliberately not empty: the diff alone
|
|
@@ -91,11 +92,11 @@ export function spawnClaudeReview(
|
|
|
91
92
|
// Captured rather than inherited: a review has to be read to be judged, and
|
|
92
93
|
// `claude` exits 0 whether it reviewed the diff or merely said it would.
|
|
93
94
|
// `--print` emits the review in one final block, so nothing streams anyway.
|
|
94
|
-
const result = spawnSync(
|
|
95
|
+
const result = withReviewDiagnostics("claude", fd => spawnSync(
|
|
95
96
|
executable,
|
|
96
97
|
buildClaudeReviewArgs(effort, snapshotRoot, loadConfig().review.claudeModel),
|
|
97
98
|
{
|
|
98
|
-
stdio: ["pipe", "pipe",
|
|
99
|
+
stdio: ["pipe", "pipe", fd],
|
|
99
100
|
input: prompt,
|
|
100
101
|
encoding: "utf8",
|
|
101
102
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
@@ -105,7 +106,7 @@ export function spawnClaudeReview(
|
|
|
105
106
|
// the one the runtime snapshotted at startup.
|
|
106
107
|
env,
|
|
107
108
|
},
|
|
108
|
-
);
|
|
109
|
+
));
|
|
109
110
|
return {
|
|
110
111
|
exitCode: spawnExitCode("claude", result),
|
|
111
112
|
review: result.stdout ?? "",
|
|
@@ -22,9 +22,7 @@ import {
|
|
|
22
22
|
} from "./reviewEffort";
|
|
23
23
|
import { buildReviewPrompt, CODEX_ACCESS_NOTE } from "./reviewPrompt";
|
|
24
24
|
import { type ReviewerEnv, relayReviewWithRetry } from "./runReview";
|
|
25
|
-
|
|
26
|
-
/** How much transcript tail to relay when a codex attempt fails outright. */
|
|
27
|
-
const TRANSCRIPT_TAIL_CHARS = 2000;
|
|
25
|
+
import { withReviewDiagnostics } from "./diagnostics";
|
|
28
26
|
|
|
29
27
|
/**
|
|
30
28
|
* Build the `codex exec` argv. `exec`, not `review`: `codex review` writes its
|
|
@@ -120,8 +118,9 @@ function readLastMessage(lastMessageFile: string): string {
|
|
|
120
118
|
* codex prints its session transcript — including a verbatim echo of the
|
|
121
119
|
* prompt and diff — to stderr and the final message to stdout, and inheriting
|
|
122
120
|
* either would bury the verdict in noise (the exact failure this replaces).
|
|
123
|
-
*
|
|
124
|
-
*
|
|
121
|
+
* Stdout is captured and stderr is retained in a private file; on a failed
|
|
122
|
+
* launch its bounded tail is relayed so the error is still diagnosable.
|
|
123
|
+
* Degenerate exit-0 output is retried once via
|
|
125
124
|
* the shared gate, same as the Claude path.
|
|
126
125
|
*/
|
|
127
126
|
export function spawnCodexReview(
|
|
@@ -144,7 +143,7 @@ export function spawnCodexReview(
|
|
|
144
143
|
// never be read as the previous attempt's stale message.
|
|
145
144
|
attempt += 1;
|
|
146
145
|
const lastMessageFile = path.join(outDir, `review-${attempt}.md`);
|
|
147
|
-
const result = spawnSync(
|
|
146
|
+
const result = withReviewDiagnostics("codex", fd => spawnSync(
|
|
148
147
|
codexExecutable,
|
|
149
148
|
buildCodexReviewArgs(
|
|
150
149
|
effort,
|
|
@@ -154,7 +153,7 @@ export function spawnCodexReview(
|
|
|
154
153
|
loadConfig().review.codexModel,
|
|
155
154
|
),
|
|
156
155
|
{
|
|
157
|
-
stdio: ["pipe", "pipe",
|
|
156
|
+
stdio: ["pipe", "pipe", fd],
|
|
158
157
|
input: prompt,
|
|
159
158
|
encoding: "utf8",
|
|
160
159
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
@@ -164,14 +163,8 @@ export function spawnCodexReview(
|
|
|
164
163
|
cwd: outDir,
|
|
165
164
|
env,
|
|
166
165
|
},
|
|
167
|
-
);
|
|
166
|
+
));
|
|
168
167
|
const exitCode = spawnExitCode("codex", result);
|
|
169
|
-
const transcript = result.stderr ?? "";
|
|
170
|
-
if (exitCode !== 0 && transcript.length > 0) {
|
|
171
|
-
process.stderr.write(
|
|
172
|
-
`codex transcript (tail):\n${transcript.slice(-TRANSCRIPT_TAIL_CHARS)}\n`,
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
168
|
return { exitCode, review: readLastMessage(lastMessageFile) };
|
|
176
169
|
});
|
|
177
170
|
} finally {
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "./reviewEffort";
|
|
19
19
|
import { buildReviewPrompt, OPENCODE_ACCESS_NOTE } from "./reviewPrompt";
|
|
20
20
|
import { type ReviewerEnv, relayReviewWithRetry } from "./runReview";
|
|
21
|
+
import { withReviewDiagnostics } from "./diagnostics";
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* The model every opencode review runs under. Pinned so the review never
|
|
@@ -125,11 +126,6 @@ export function buildOpencodeReviewArgs(variant: string, model = OPENCODE_MODEL)
|
|
|
125
126
|
];
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
/**
|
|
129
|
-
* How much stderr tail to relay when an opencode attempt fails outright.
|
|
130
|
-
*/
|
|
131
|
-
const TRANSCRIPT_TAIL_CHARS = 2000;
|
|
132
|
-
|
|
133
129
|
/**
|
|
134
130
|
* Run `opencode run` over an already-built review prompt and relay whatever it
|
|
135
131
|
* prints to stdout — the final message alone, since run mode keeps its TUI
|
|
@@ -137,7 +133,7 @@ const TRANSCRIPT_TAIL_CHARS = 2000;
|
|
|
137
133
|
* Claude and Codex paths: a nonzero CLI exit is returned as-is, and an exit-0
|
|
138
134
|
* run without a verdict-signed review is retried once before failing.
|
|
139
135
|
*
|
|
140
|
-
*
|
|
136
|
+
* Stdout is captured and stderr is retained in a private file: opencode prints its session transcript — tool
|
|
141
137
|
* call echo, progress lines, and the like — to stderr, and inheriting it
|
|
142
138
|
* would bury the review under noise on every run. On a failed launch the
|
|
143
139
|
* stderr tail is relayed so the error is still diagnosable (the Codex path
|
|
@@ -169,11 +165,11 @@ export function spawnOpencodeReview(
|
|
|
169
165
|
const outDir = mkdtempSync(path.join(tmpdir(), "agent-tool-opencode-"));
|
|
170
166
|
try {
|
|
171
167
|
return relayReviewWithRetry("opencode", () => {
|
|
172
|
-
const result = spawnSync(
|
|
168
|
+
const result = withReviewDiagnostics("opencode", fd => spawnSync(
|
|
173
169
|
executable,
|
|
174
170
|
buildOpencodeReviewArgs(resolveOpencodeVariant(effort, loadConfig().review.opencodeVariants), model),
|
|
175
171
|
{
|
|
176
|
-
stdio: ["pipe", "pipe",
|
|
172
|
+
stdio: ["pipe", "pipe", fd],
|
|
177
173
|
input: prompt,
|
|
178
174
|
encoding: "utf8",
|
|
179
175
|
maxBuffer: MAX_BUFFER_BYTES,
|
|
@@ -187,14 +183,8 @@ export function spawnOpencodeReview(
|
|
|
187
183
|
OPENCODE_CONFIG_DIR: outDir,
|
|
188
184
|
},
|
|
189
185
|
},
|
|
190
|
-
);
|
|
186
|
+
));
|
|
191
187
|
const exitCode = spawnExitCode("opencode", result);
|
|
192
|
-
const transcript = result.stderr ?? "";
|
|
193
|
-
if (exitCode !== 0 && transcript.length > 0) {
|
|
194
|
-
process.stderr.write(
|
|
195
|
-
`opencode transcript (tail):\n${transcript.slice(-TRANSCRIPT_TAIL_CHARS)}\n`,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
188
|
return {
|
|
199
189
|
exitCode,
|
|
200
190
|
review: result.stdout ?? "",
|
package/src/skills/bundled.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// Generated by scripts/bundle-skills.ts; edit skills/*/SKILL.md.
|
|
2
2
|
export const BUNDLED_SKILLS: Readonly<Record<string, string>> = {
|
|
3
|
-
"cross-agent-review": "---\nname: cross-agent-review\ndescription: Review committed branch changes with an independent Claude Code, Codex, or OpenCode reviewer, and repair actionable findings when requested.\n---\n\n# Cross-Agent Review\n\nUse the installed `agent-tool` executable. Read the repository's development and\nreview policy and `agent-tool.json` when present. Keep project validation commands\nand release rules in the repository; do not assume Bun, a workspace layout, or\nparticular CI job names.\n\nSelect a reviewer different from the coordinating agent when possible. Honor a\nrequested reviewer or effort; otherwise use an available independent reviewer.\nRun `agent-tool doctor` if CLI compatibility is uncertain.\n\nReview committed changes with `agent-tool review claude`, `agent-tool review codex`,\nor `agent-tool review opencode`. Optional effort is `low`, `medium`, `high`,\n`xhigh`, or `max`. For a local or non-GitHub repository, add `--base <commit-or-ref>`.\nFor a coordinated GitHub review, pin the fetched base using\n`AGENT_TOOL_REVIEW_BASE_REF`, the base branch name such as `main` (not a\nremote-tracking ref like `origin/main`), and `AGENT_TOOL_REVIEW_BASE_OID`, its\nfetched commit. Fetch from the repository that owns the PR, which can differ\nfrom the checkout's origin.\n\nRecord the exact base and HEAD before reviewing. The tool reviews raw committed\nfiles and excludes worktree edits. A zero exit means a complete review was\nreturned; it does not mean the findings are non-blocking. Read the final\n`VERDICT: BLOCKER|MAJOR|MINOR|SUGGESTION|CLEAN` and the findings. A reviewer\nthat labels findings `[P0]` through `[P3]` uses the same scale: `[P0]` and\n`[P1]` are BLOCKER and MAJOR, `[P2]` and `[P3]` are MINOR and SUGGESTION.\n\nIf a CLI is unavailable, out of credits, or returns an unusable review, try another\navailable reviewer and disclose the fallback. Do not silently convert a failed\nreview into CLEAN or call an in-session review independent.\n\nFor report-only requests, report findings without changing files or history.\nWhen repairs are authorized, address actionable BLOCKER and MAJOR findings,\nvalidate with the repository's relevant checks, commit the repairs, and review\nthe new HEAD. Continue while meaningful progress is possible; report an impasse\nwhen progress requires a material user decision. A repaired commit is unreviewed\nuntil the next review completes. Preserve unrelated work.\n\nBefore reporting success, confirm HEAD still matches the reviewed commit and\nthat an existing PR points to that same commit. If the base moved, refresh it and\nreview again before shipping. Report reviewer, exact base and head IDs, verdict,\nremaining findings, validation, and any repairs performed. This skill does not\nauthorize pushing, opening a PR, or merging unless the user requested that work.\n",
|
|
3
|
+
"cross-agent-review": "---\nname: cross-agent-review\ndescription: Review committed branch changes with an independent Claude Code, Codex, or OpenCode reviewer, and repair actionable findings when requested.\n---\n\n# Cross-Agent Review\n\nUse the installed `agent-tool` executable. Read the repository's development and\nreview policy and `agent-tool.json` when present. Keep project validation commands\nand release rules in the repository; do not assume Bun, a workspace layout, or\nparticular CI job names.\n\nSelect a reviewer different from the coordinating agent when possible. Honor a\nrequested reviewer or effort; otherwise use an available independent reviewer.\nRun `agent-tool doctor` if CLI compatibility is uncertain.\n\nRun noisy validation or repair checks through\n`agent-tool run --label <check> -- <command> [args...]`. Read its bounded failure\ntail and use `agent-tool logs <log>` or a targeted search for more evidence.\nKeep `agent-tool review` direct: it retains reviewer stderr in a private local\nlog and displays the complete final review. Never hide, truncate, or substitute\na command success receipt for findings and the final verdict.\n\nReview committed changes with `agent-tool review claude`, `agent-tool review codex`,\nor `agent-tool review opencode`. Optional effort is `low`, `medium`, `high`,\n`xhigh`, or `max`. For a local or non-GitHub repository, add `--base <commit-or-ref>`.\nFor a coordinated GitHub review, pin the fetched base using\n`AGENT_TOOL_REVIEW_BASE_REF`, the base branch name such as `main` (not a\nremote-tracking ref like `origin/main`), and `AGENT_TOOL_REVIEW_BASE_OID`, its\nfetched commit. Fetch from the repository that owns the PR, which can differ\nfrom the checkout's origin.\n\nRecord the exact base and HEAD before reviewing. The tool reviews raw committed\nfiles and excludes worktree edits. A zero exit means a complete review was\nreturned; it does not mean the findings are non-blocking. Read the final\n`VERDICT: BLOCKER|MAJOR|MINOR|SUGGESTION|CLEAN` and the findings. A reviewer\nthat labels findings `[P0]` through `[P3]` uses the same scale: `[P0]` and\n`[P1]` are BLOCKER and MAJOR, `[P2]` and `[P3]` are MINOR and SUGGESTION.\n\nIf a CLI is unavailable, out of credits, or returns an unusable review, try another\navailable reviewer and disclose the fallback. Do not silently convert a failed\nreview into CLEAN or call an in-session review independent.\n\nFor report-only requests, report findings without changing files or history.\nWhen repairs are authorized, address actionable BLOCKER and MAJOR findings,\nvalidate with the repository's relevant checks, commit the repairs, and review\nthe new HEAD. Continue while meaningful progress is possible; report an impasse\nwhen progress requires a material user decision. A repaired commit is unreviewed\nuntil the next review completes. Preserve unrelated work.\n\nBefore reporting success, confirm HEAD still matches the reviewed commit and\nthat an existing PR points to that same commit. If the base moved, refresh it and\nreview again before shipping. Report reviewer, exact base and head IDs, verdict,\nremaining findings, validation, and any repairs performed. This skill does not\nauthorize pushing, opening a PR, or merging unless the user requested that work.\n",
|
|
4
4
|
"open-pr": "---\nname: open-pr\ndescription: Open a GitHub pull request for the current feature branch with a validated title and a reviewable description.\n---\n\n# Open PR\n\nUse the installed `agent-tool`. Follow repository policy for validation, commits,\nand branch naming. Resolve the repository and default branch with Git and `gh`;\ndo not assume the branch is named main. Preserve unrelated work and finish\nrequested changes and appropriate checks before publishing them.\n\nEnsure the intended commit is on a feature branch and push it through the\nrepository's normal push workflow, naming the PR repository's remote and branch\nexplicitly, as in `git push -u origin HEAD`; a bare push follows whatever\nupstream the branch tracks, which may be a local branch. Respect existing push\nauthorization; do not bypass hooks. If the user only requested a draft\ndescription, prepare that text without publishing a PR.\n\nWrite a title that satisfies the data-only `agent-tool.json` subject policy.\nDescribe the concrete resulting behavior and relevant validation. Put multiline\nbody text in a temporary file, then run:\n\n```sh\nagent-tool pr open 'feat: describe the change' < /path/to/pr-body.txt\n```\n\nOmitting the title uses the latest commit subject. The tool refuses duplicate\nopen PRs and requires the branch to be pushed at its local HEAD. It does not\npush for you. Resolve a fork's head/base identities explicitly if the repository\nuses fork PRs; the initial open helper supports same-repository branches.\n\nReport the created PR link and any remaining validation or review work.\n",
|
|
5
5
|
"reset": "---\nname: reset\ndescription: Return a clean checkout to its updated default branch after confirmed shipping or an explicit checkout cleanup request.\n---\n\n# Reset\n\nThis is checkout cleanup, not a destructive Git reset. Read repository guidance\nfor setup and hooks. Determine the default branch through the repository's\nremote metadata rather than assuming main.\n\nCheck worktree and index first. Preserve user edits; if they prevent switching,\nreport the condition instead of discarding or automatically stashing them. For\npost-merge cleanup, confirm the PR is MERGED before removing a feature branch.\n\nFetch the default branch, switch to it, and update by fast-forward only. A\ndiverged default branch requires inspection rather than forced replacement.\nDelete a merged feature branch only within the requested cleanup scope and\nafter verifying its exact commit is the shipped commit; squash merging does not\nmake Git ancestry-based branch deletion proof of shipping. Honor keep-branch.\n\nRun only the hook installer or dependency setup documented by this repository\nwhen the updated checkout requires it. Do not assume a package manager or copy\nsetup commands from another project. Report final branch, commit, and any\nunfinished cleanup.\n",
|
|
6
|
-
"ship-pr": "---\nname: ship-pr\ndescription: Complete an authorized commit, independent review, repair, PR, CI, and squash-merge workflow for a GitHub repository.\n---\n\n# Ship PR\n\nUse the installed `agent-tool`. Read repository guidance and policy first;\nvalidation, versioning, package management, and hook installation remain project\nconcerns. Shipping authorizes this workflow within the user's stated scope.\nPreserve unrelated edits and honor requested stopping points such as open-PR\nonly, report-only review, or keeping the feature branch.\n\n1. Finish the requested change on a feature branch. Create it with\n `git switch --no-track -c <branch>`; settings such as\n `branch.autosetupmerge=always` otherwise make it track a local branch.\n Validate it with appropriate project checks and commit only the intended\n files.\n2. Determine the current PR's base repository and branch, or the repository's\n default branch when no PR exists. Fetch and pin its exact base. Integrate it\n using the repository's normal workflow, resolving conflicts without losing\n user work. If project policy versions packages, prepare versions against the\n pinned base after every integration or repair and before each review, using\n the project's commands or `agent-tool versions prepare <base-oid>`, which\n commits bumped manifests and the refreshed lockfile.\n `agent-tool versions resolve-conflicts` resolves conflicts confined to\n version fields. Review the resulting committed HEAD with an independent\n reviewer using the bundled cross-agent-review skill. Repair blocking findings\n and review every changed HEAD again. Review failure blocks shipping.\n3. Push the reviewed HEAD through normal hooks, then verify the pushed SHA still\n equals the reviewed SHA. If a hook changed content or HEAD, review that result.\n Open the PR using the open-pr skill, or update the existing PR as needed.\n4. Allow any configured review bots time to respond, then fetch unresolved PR\n review threads. Follow repository policy for feedback: fix valid findings,\n reply in the original threads, and resolve only fully addressed comments.\n Validate, commit, push, and independently review every feedback or CI repair.\n Wait for CI, recheck the live base, PR base branch, and local and remote heads.\n A changed base requires integration, validation, and another review. When\n versions are managed, `agent-tool versions check <base-oid>` must pass for the\n live base. Use the squash-merge skill to merge the exact reviewed HEAD.\n5. After confirmed MERGED, honor keep-branch; otherwise use the reset skill to\n return to the updated default branch and apply any documented project setup.\n6. When the project deploys the merged branch, verify the deployment for the\n merge commit and run its documented live checks. Report deployment failures\n separately from a successful merge; follow project policy for repairs.\n\nNever infer a clean review from process success alone or carry a review across\ncontent changes. Do not weaken configured CI policy to get a merge through.\nIf a step fails, preserve useful intermediate work and report the concrete\nremaining issue. Report PR link, merged commit, review verdict, validation, and\nfinal checkout state.\n",
|
|
6
|
+
"ship-pr": "---\nname: ship-pr\ndescription: Complete an authorized commit, independent review, repair, PR, CI, and squash-merge workflow for a GitHub repository.\n---\n\n# Ship PR\n\nUse the installed `agent-tool`. Read repository guidance and policy first;\nvalidation, versioning, package management, and hook installation remain project\nconcerns. Shipping authorizes this workflow within the user's stated scope.\nPreserve unrelated edits and honor requested stopping points such as open-PR\nonly, report-only review, or keeping the feature branch.\n\nUse `agent-tool run --label <check> -- <command> [args...]` for noisy setup,\nvalidation, builds, and hook-running Git commands. It preserves exit status and\ncomplete private logs, prints one success receipt, and shows a bounded failure\ntail. Inspect more with `agent-tool logs <log> --max-bytes 8192 --tail-lines 80`\nor a targeted search; never dump an entire suite log or pipe checks into `tail`.\nThe receipt proves process completion, not absence of warnings: inspect required\nwarning, coverage, timing, or artifact evidence before accepting a check. Keep\nmachine-readable receipts and review findings visible by running `versions\nprepare`, `review`, and other commands whose output drives a decision directly.\nPrefer documented compact test reporters when they preserve required evidence;\ndo not reduce test scope, skip checks, silence warnings, or mask failures.\n\n1. Finish the requested change on a feature branch. Create it with\n `git switch --no-track -c <branch>`; settings such as\n `branch.autosetupmerge=always` otherwise make it track a local branch.\n Validate it with appropriate project checks and commit only the intended\n files.\n2. Determine the current PR's base repository and branch, or the repository's\n default branch when no PR exists. Fetch and pin its exact base. Integrate it\n using the repository's normal workflow, resolving conflicts without losing\n user work. If project policy versions packages, prepare versions against the\n pinned base after every integration or repair and before each review, using\n the project's commands or `agent-tool versions prepare <base-oid>`, which\n commits bumped manifests and the refreshed lockfile.\n `agent-tool versions resolve-conflicts` resolves conflicts confined to\n version fields. Review the resulting committed HEAD with an independent\n reviewer using the bundled cross-agent-review skill. Repair blocking findings\n and review every changed HEAD again. Review failure blocks shipping.\n3. Push the reviewed HEAD through normal hooks, then verify the pushed SHA still\n equals the reviewed SHA. If a hook changed content or HEAD, review that result.\n Open the PR using the open-pr skill, or update the existing PR as needed.\n4. Allow any configured review bots time to respond, then fetch unresolved PR\n review threads. Follow repository policy for feedback: fix valid findings,\n reply in the original threads, and resolve only fully addressed comments.\n Validate, commit, push, and independently review every feedback or CI repair.\n Wait for CI, recheck the live base, PR base branch, and local and remote heads.\n A changed base requires integration, validation, and another review. When\n versions are managed, `agent-tool versions check <base-oid>` must pass for the\n live base. Use the squash-merge skill to merge the exact reviewed HEAD.\n5. After confirmed MERGED, honor keep-branch; otherwise use the reset skill to\n return to the updated default branch and apply any documented project setup.\n6. When the project deploys the merged branch, verify the deployment for the\n merge commit and run its documented live checks. Report deployment failures\n separately from a successful merge; follow project policy for repairs.\n\nNever infer a clean review from process success alone or carry a review across\ncontent changes. Do not weaken configured CI policy to get a merge through.\nIf a step fails, preserve useful intermediate work and report the concrete\nremaining issue. Report PR link, merged commit, review verdict, validation, and\nfinal checkout state.\n",
|
|
7
7
|
"squash-merge": "---\nname: squash-merge\ndescription: Squash-merge a reviewed GitHub pull request while binding the mutation to the reviewed commit and checking CI.\n---\n\n# Squash Merge\n\nUse the installed `agent-tool` and repository merge policy. Merge only within\nthe user's authorized scope. Have the exact reviewed HEAD, base commit, and base\nbranch available, and read the verdict and unresolved findings. BLOCKER or MAJOR\nfindings require repair and a new review before merging.\nFollow the repository's review-bot policy and require all actionable blocking\nreview feedback to be addressed before merging.\n\nWait for required checks using `gh pr checks --watch --fail-fast`. Refresh the\nPR and live base from the repository that owns the PR. Confirm local HEAD and PR\nHEAD both equal the reviewed commit, the base branch is unchanged, the live base\nstill equals the reviewed base, and that base is an ancestor of reviewed HEAD.\nIf any identity changed, refresh, validate, and review again.\n\nUse a title that satisfies `agent-tool.json` and pass both reviewed HEAD and\nbase branch:\n\n```sh\nagent-tool pr merge 'feat: describe the change' <reviewed-head-oid> <base-branch>\n```\n\nThe helper enforces HEAD atomically through GitHub's `expectedHeadOid`, checks\nCI, rejects queued or automatic merges, and creates a subject-only squash with\nthe PR reference. GitHub has no atomic expected-base argument in this mutation;\nrepository branch protection must enforce any required base freshness. With\n`merge.requireStrictBaseFreshness`, the helper refuses to merge unless an\nactive strict status ruleset that the actor cannot bypass protects the base. Do\nnot retarget the PR concurrently with merging.\n\nConfirm GitHub reports MERGED before any cleanup. A failed or uncertain mutation\nis not evidence of a merge. Preserve the branch on failure. After a confirmed\nmerge, perform checkout cleanup only when requested or as part of an authorized\nshipping workflow. Report the PR and merge result.\n",
|
|
8
|
-
"update-dependencies": "---\nname: update-dependencies\ndescription: Update a repository's dependency manifests, lockfiles, runtimes, tools, and CI pins with upstream migrations, compatibility checks, and non-destructive infrastructure previews.\n---\n\n# Update Dependencies\n\nUse the repository's package managers and installed `agent-tool`. Read `AGENTS.md`,\nREADME, linked setup/release documents, and repository-owned upgrade skills before\nediting. Follow their hooks, version policy, checks, and requested stopping point.\nUpdate applicable dependencies throughout the repository, including workspaces\nand examples. This skill does not authorize deploying, merging, publishing, or\nchanging global tools; use existing user authorization and `ship-pr` when shipping\nis requested. Default dependency-update merge subject: `chore: update dependencies`,\nsubject to repository title policy and any explicit user subject.\n\n## Safety before execution\n\n**Always dry-run before any infrastructure apply or deployment. Never destroy,\nreplace, or recreate a resource during an upgrade.** This includes Terraform,\nOpenTofu, Wrangler, Ansible, other infrastructure tools, and effects triggered by\ninstallation, tests, hooks, Git push, opening a PR, CI, or merging. Greenfield\nprojects and approval to ship do not waive this rule.\n\nBefore running project commands or pushing, trace their scripts, hooks, workflow\ntriggers, reusable workflows, and deployment commands. A dry-run flag alone is\ninsufficient: inspect tasks, provisioners, plugins, external programs, and actions\nthat can mutate despite preview mode. Avoid such a preview unless its effects\nare proven read-only. Do not run destroy/delete, taint/replace, state removal,\nbackend migration, forced database reset, or an automatic \"repair\" that bypasses\nthe rule. Do not hide destruction with targeting, disabled refresh, ignored\nchanges, new resource identities, or weakened policy.\n\nPreview with the proposed versions and complete configuration for each affected\nenvironment, using its real backend/workspace/account, variables, inventory, and\nresource identities. An empty local state, mocked credentials, validate-only run,\nor bundle build cannot establish safety for production. Check the current baseline\nas well when needed to distinguish existing drift from the upgrade. Keep state,\nbinary plans, JSON plans, and secret-bearing diffs out of Git and public reports.\n\nIf a preview proposes deletion or replacement, fails, is incomplete, omits\naffected resources, or cannot establish safety, skip that dependency and its\ncoupled migrations. Restore only this task's edits to the affected compatibility\ngroup, retain independent safe upgrades, and record the reason and affected\nresources. Never apply to find out. A preview is not deployment authorization.\n\nBefore an authorized apply/deploy, verify the exact validated commit, toolchain,\nconfiguration, environment, and current state still match the preview. Re-preview\nafter relevant changes or drift. CI must enforce the same order and stop on an\nunsafe preview before mutation; a successful local preview does not excuse an\nunguarded push- or merge-triggered deployment. Establish a narrowly scoped guard\nwhen authorized and reviewable, or hold the affected upgrade before triggering\nthat workflow. Do not disable protections to ship. A plan must be inspected before\nthe operation; inspecting deployment logs afterward is too late.\nAn unsafe workflow triggered on every branch push also blocks pushing otherwise\nindependent upgrades until that trigger has a proven safe guard.\n\n### Terraform and OpenTofu\n\nRead core, provider, and module upgrade guides, including intermediate major\nmigrations. Regenerate provider locks with the pinned CLI, preserving supported\nplatform hashes. Backend initialization/migration is also subject to the safety\ngate. Inspect external data programs and provisioners before planning.\n\nUse a full refreshed saved plan with locking and the real variables, for example\n`terraform plan -input=false -out=<private-plan>`; if using `-detailed-exitcode`,\n0 and 2 are success, 1 is failure. Inspect `terraform show -json <private-plan>`.\nRun `agent-tool dependencies check-terraform-plan <private-plan.json>` to check\nsupported JSON resource actions. It fails for every action containing `delete`,\nincluding both replacement orders, unknown actions, incomplete/deferred plans,\nfailed checks, or opaque provider action invocations. It prints actions and\ndiagnostics without resource attribute values; it does not prove that a plan is\nfresh, comprehensive, authentic, or that provider code has no hidden effects.\nOlder/unsupported plan formats that cannot establish completeness are skipped.\nOpenTofu currently omits `complete` in its JSON format and is rejected by this\nhelper; report that limitation rather than adding a synthetic completeness flag.\nAlso inspect resource identity, drift, warnings, provider semantics, and any\neffects outside resource actions. For an authorized apply, consume the exact\napproved saved plan, not an uninspected newly generated plan.\n\nSource: [Terraform JSON plan format](https://developer.hashicorp.com/terraform/internals/json-format).\n\n### Wrangler and other deployment tools\n\nUse the proposed pinned Wrangler for `wrangler deploy --dry-run` with the same\nbuild/configuration/environment used by deployment. This checks bundling, not a\ncomplete remote resource plan. Separately verify account, worker name, routes,\nbindings and resource IDs against the existing deployment and read migration\nsemantics. Review Durable Object deleted/renamed classes, D1 schema/data\nmigrations, storage resources, queues, containers, and deployment integrations.\nNever infer \"no destruction\" from a successful bundle. Resource removals,\nreplacement, or unprovable remote effects skip the affected group. Apply the\nequivalent preview and identity checks to other tools rather than assuming they\nshare Terraform's guarantees.\n\nDo not assume `wrangler d1 migrations list --remote` is read-only. The\nimplementation inspected for this skill initializes migration tracking with\n`CREATE TABLE IF NOT EXISTS`; verify the pinned Wrangler version before using\nthe command. Verify database identity and compare migration files with the\ndatabase's configured migration tracking table through audited read-only\nqueries. A missing table, pending migration, or unverifiable schema/data\neffects hold the affected upgrade/deployment group. Never initialize schema\nmerely to establish preview safety.\n\nWrangler runs a custom `build.command` again during deployment. Use supported\nconfiguration referencing the same validated artifacts for both preview and\ndeployment, preventing another unvalidated build before upload. Bind the\nartifacts, configuration, and pinned tool to the authorized commit, and recheck\ntheir identities before upload and after relevant changes. Hold the affected\ngroup if the pinned Wrangler cannot upload the validated output without\nrebuilding it, or if the upload cannot be proven to match the preview.\n\nSources: [Wrangler command documentation](https://developers.cloudflare.com/workers/wrangler/commands/),\n[D1 migration listing implementation](https://github.com/cloudflare/workers-sdk/blob/e3d186776fcc2e4b5cc4cfd7155591778a375957/packages/wrangler/src/d1/migrations/list.ts),\n[migration table initialization](https://github.com/cloudflare/workers-sdk/blob/e3d186776fcc2e4b5cc4cfd7155591778a375957/packages/wrangler/src/d1/migrations/helpers.ts),\nand [Wrangler custom builds](https://developers.cloudflare.com/workers/wrangler/custom-builds/).\n\n### Ansible\n\nCheck controller Python, ansible-core, collections/roles, and target Python support\ntogether; read porting guides. Inspect all tasks and invoked scripts before\n`ansible-playbook --check --diff` with the real inventory and variables.\n`check_mode: false` forces mutation even with `--check`; unsupported modules and\nconditions based on registered results can omit effects. Inspect deletion,\nrecreation, service/data reset, and package removal semantics beyond the diff.\nSkipped or opaque tasks are a safety gap, not a clean preview. Redact diffs.\n\nSource: [Ansible check mode limits](https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_checkmode.html).\n\n## Inventory and choose compatible targets\n\nRecord each dependency source, current resolved version, latest stable candidate,\nselected target, compatibility constraints, upstream migration links, and checks.\nQuery authoritative registries, official releases, support matrices, and migration\nguides at execution time; do not treat remembered versions or prereleases as\nlatest stable. Inspect runtime requirements, peer dependencies, ABI/API changes,\nplatform availability, maintained release lines, and changed defaults, including\nsecurity, privacy/telemetry, data retention, and postinstall/native behavior.\nCheck transitive dependencies' peer/runtime constraints as well as direct ones. Unsupported\nor unpublished targets stay pinned with an explanation.\n\nInventory manifests, locks, tool configuration, CI/reusable actions, containers,\nscripts, deployment files, and executable documentation. Search duplicate version\npins and aliases, not just filenames; exclude vendored/generated snapshots unless\nthe repository owns their update process. Examples of sources to inspect:\n\n| Ecosystem | Sources and compatibility group |\n| --- | --- |\n| JavaScript/TypeScript | All package.json dependency fields, overrides/resolutions, workspace catalogs, packageManager/engines, npm/Bun/pnpm/Yarn locks, Node/Bun pins, compiler and lint/build/test plugins |\n| Toolchains | mise.toml/.mise.toml, mise.lock, .tool-versions, runtime version files, tool URLs/checksums, CI pins and container images; include every tool declared by mise, not just mise itself |\n| Python/Ansible | pyproject/requirements, uv/Poetry/pip locks, Python pins, ansible-core, collection/role requirements, lint plugins and managed host constraints |\n| Ruby/iOS | .ruby-version, Gemfile/lock, Bundler, CocoaPods, Podfile/lock, podspecs, Swift packages and Xcode/iOS deployment requirements |\n| Infrastructure | Terraform/OpenTofu CLI constraints, provider locks/constraints, module versions/Git refs, Wrangler and Cloudflare integration dependencies |\n| CI/system/native | Actions/reusable workflow refs, Docker tags/digests, OS images/packages, Rust/Cargo toolchain and locks, Go modules, Gradle/AGP/Kotlin/JDK and other repository-specific manifests |\n\nBuild connected compatibility groups before editing. Select the newest supported\ncombination, which can be older than an individual package's latest. Upgrade the\nframework first or keep its compatible toolchain pinned; do not force peer\nresolution, drop compatibility checks, or add blanket overrides to make installs\npass. Preserve source pin policy (exact version, digest, full Git SHA) and resolve\nimmutable pins from verified upstream releases. Preserve intentional runtime\nminimums unless migration requires changing the support contract.\n\nFor React Native, use its version-specific upgrade guide/template diffs and\nrepository upgrade skills. Couple React and its renderer, native modules,\nMetro/Babel, CLI, codegen, Hermes/New Architecture, CocoaPods/Bundler/Ruby,\nXcode/iOS deployment targets, and Android Gradle/AGP/Kotlin/JDK/SDK/NDK. For Expo,\nuse the chosen SDK's supported React Native/dependency matrix and its dependency\nchecks. Do not independently update framework-managed pods or generated native\nfiles; use the framework's regeneration workflow and prove iOS/Android builds.\nPermissive peer ranges alone do not prove native renderer or toolchain compatibility;\ncheck the framework's actual supported versions and native implementation.\nAn unavailable native toolchain is a reported validation limit; do not claim the\ngroup verified. See [React Native upgrading](https://reactnative.dev/docs/upgrading).\n\nCheck developer tools' own dependencies too: a compiler release without its old\nprogrammatic API may break test/lint runners that import it even when `tsc` passes.\nAction runtime upgrades can require newer self-hosted runners; preserve workflow\npermissions, action inputs/outputs, caching, artifact semantics, and job names.\n\nCheck current advisories with read-only ecosystem audits against the baseline and\nproposed lockfiles, using the repository's configured registry/advisory sources.\nDo not send private dependency metadata to an unconfigured or unauthorized service;\nreport the resulting coverage limit. Cover direct and resolved transitive dependencies,\nincluding native/platform-specific binaries. Latest direct packages can still\npin vulnerable transitive versions. Trace each finding to its owning dependency,\nverify affected versions, runtime conditions, and remediation in the maintainer's\nadvisory and fixed release. When the owner's range permits a fixed version, use a\ntargeted refresh with the lockfile's owning manager and preserve unrelated\nresolutions; otherwise prefer a supported owner upgrade.\nIf the owner still pins a vulnerable version, a narrowly scoped security patch\noverride may be used only with API/ABI/runtime compatibility evidence and focused\nregression checks of the actual affected integration. Document its rationale and\nremoval condition; a passing install or bundle alone is insufficient. Do not run\nblind audit fixes or use blanket overrides to bypass compatibility constraints.\nReport unresolved advisories and unavailable audit coverage accurately; current\ndirect pins or a partial clean audit do not\nestablish that the whole dependency graph is safe.\n\n## Migrate and validate\n\nCapture relevant baseline checks and warnings first, after screening their side\neffects. Update one compatibility group at a time. Read the upstream instructions\nfor every breaking step; implement required source/config/schema migrations and\nremoved API replacements. Use the manager that owns each lockfile, on the selected\nruntime, and inspect the resulting diff. Refresh transitive dependencies through\ntheir owning direct dependency; do not hand-edit integrity hashes or lock entries.\nReview intentional patches, overrides, and pins before removal; retain them until\nupstream fixes and regression checks demonstrate they are unnecessary.\nAvoid unrelated global installations or environment changes. Use task-local or\nrepository-scoped tools for testing changed runtime pins.\nFor published packages, also validate tarballs and consumer installs with their\ndocumented supported package managers, including manifest/override syntax and\nruntime requirements. A successful owning-manager install does not prove that\npublished metadata works for those consumers.\n\nRun the repository's setup/hooks, frozen installs, lint, typechecks, tests, builds,\npackage/platform smoke checks, and relevant safe integration previews. Resolve\nupgrade-related deprecation warnings at their source. Do not suppress warnings,\nweaken tests, or disable checks; report remaining upstream/pre-existing warnings\nwith evidence and keep a target pinned when migration cannot be completed.\nAdd focused regression coverage when a migration changes behavior; avoid tests\nthat merely assert version strings. Re-run checks after repairs. Report checks\nblocked by missing credentials, platforms, or external services accurately.\nRe-audit the final resolved graph after migrations and repairs.\n\nConfirm every inventory row is upgraded, already current, intentionally constrained,\nor skipped with a concrete reason. Do not present an unresolved group as complete.\nWhen upgrading agent-tool itself, install its managed skills with the same harness\nscope and commit the ownership manifest; never edit generated managed skill copies.\n\nWhen changes depend on another repository's release, ship the producer first and\nconfirm publishing and registry availability before pinning the consumer; include\nits exact version/commit and API migration notes. Independent groups may proceed.\nUse the installed `ship-pr` for authorized shipping and independently review every\nchanged HEAD. Check deployment safety again before its push/open/merge operations.\n\n## Report\n\nKeep a compact ledger of old/selected versions, completed migrations, validation\nand warning results, preview environment/commit/tool versions and safe action\nsummary, and every skipped/constrained dependency with the reason. Include baseline\nand final audit results, security overrides with their rationale and removal\ncondition, unresolved advisories, and audit coverage limits. For shipping,\ninclude branch, reviewed commit/verdict, PR, merge, publish/deploy result, and final\ncheckout state. For a repository sweep, keep one entry per repository, including\nunready or unchanged checkouts. Do not publish credentials, state, or plan contents.\n"
|
|
8
|
+
"update-dependencies": "---\nname: update-dependencies\ndescription: Update a repository's dependency manifests, lockfiles, runtimes, tools, and CI pins with upstream migrations, compatibility checks, and non-destructive infrastructure previews.\n---\n\n# Update Dependencies\n\nUse the repository's package managers and installed `agent-tool`. Read `AGENTS.md`,\nREADME, linked setup/release documents, and repository-owned upgrade skills before\nediting. Follow their hooks, version policy, checks, and requested stopping point.\nUpdate applicable dependencies throughout the repository, including workspaces\nand examples. This skill does not authorize deploying, merging, publishing, or\nchanging global tools; use existing user authorization and `ship-pr` when shipping\nis requested. Default dependency-update merge subject: `chore: update dependencies`,\nsubject to repository title policy and any explicit user subject.\n\nRun noisy installs, checks, tests, and builds with\n`agent-tool run --label <check> -- <command> [args...]` to retain full private\nlogs and return the original status with compact output. Inspect bounded excerpts\nusing `agent-tool logs <log>` and targeted searches for warnings and evidence;\na successful receipt does not establish a warning-free upgrade. Keep structured\naudit/plan results, deployment previews, and review findings directly visible\nwhen they drive a safety decision. Do not dump full suite logs into context,\nsilence warnings at their source, or change check scope to reduce output.\n\n## Safety before execution\n\n**Always dry-run before any infrastructure apply or deployment. Never destroy,\nreplace, or recreate a resource during an upgrade.** This includes Terraform,\nOpenTofu, Wrangler, Ansible, other infrastructure tools, and effects triggered by\ninstallation, tests, hooks, Git push, opening a PR, CI, or merging. Greenfield\nprojects and approval to ship do not waive this rule.\n\nBefore running project commands or pushing, trace their scripts, hooks, workflow\ntriggers, reusable workflows, and deployment commands. A dry-run flag alone is\ninsufficient: inspect tasks, provisioners, plugins, external programs, and actions\nthat can mutate despite preview mode. Avoid such a preview unless its effects\nare proven read-only. Do not run destroy/delete, taint/replace, state removal,\nbackend migration, forced database reset, or an automatic \"repair\" that bypasses\nthe rule. Do not hide destruction with targeting, disabled refresh, ignored\nchanges, new resource identities, or weakened policy.\n\nPreview with the proposed versions and complete configuration for each affected\nenvironment, using its real backend/workspace/account, variables, inventory, and\nresource identities. An empty local state, mocked credentials, validate-only run,\nor bundle build cannot establish safety for production. Check the current baseline\nas well when needed to distinguish existing drift from the upgrade. Keep state,\nbinary plans, JSON plans, and secret-bearing diffs out of Git and public reports.\n\nIf a preview proposes deletion or replacement, fails, is incomplete, omits\naffected resources, or cannot establish safety, skip that dependency and its\ncoupled migrations. Restore only this task's edits to the affected compatibility\ngroup, retain independent safe upgrades, and record the reason and affected\nresources. Never apply to find out. A preview is not deployment authorization.\n\nBefore an authorized apply/deploy, verify the exact validated commit, toolchain,\nconfiguration, environment, and current state still match the preview. Re-preview\nafter relevant changes or drift. CI must enforce the same order and stop on an\nunsafe preview before mutation; a successful local preview does not excuse an\nunguarded push- or merge-triggered deployment. Establish a narrowly scoped guard\nwhen authorized and reviewable, or hold the affected upgrade before triggering\nthat workflow. Do not disable protections to ship. A plan must be inspected before\nthe operation; inspecting deployment logs afterward is too late.\nAn unsafe workflow triggered on every branch push also blocks pushing otherwise\nindependent upgrades until that trigger has a proven safe guard.\n\n### Terraform and OpenTofu\n\nRead core, provider, and module upgrade guides, including intermediate major\nmigrations. Regenerate provider locks with the pinned CLI, preserving supported\nplatform hashes. Backend initialization/migration is also subject to the safety\ngate. Inspect external data programs and provisioners before planning.\n\nUse a full refreshed saved plan with locking and the real variables, for example\n`terraform plan -input=false -out=<private-plan>`; if using `-detailed-exitcode`,\n0 and 2 are success, 1 is failure. Inspect `terraform show -json <private-plan>`.\nRun `agent-tool dependencies check-terraform-plan <private-plan.json>` to check\nsupported JSON resource actions. It fails for every action containing `delete`,\nincluding both replacement orders, unknown actions, incomplete/deferred plans,\nfailed checks, or opaque provider action invocations. It prints actions and\ndiagnostics without resource attribute values; it does not prove that a plan is\nfresh, comprehensive, authentic, or that provider code has no hidden effects.\nOlder/unsupported plan formats that cannot establish completeness are skipped.\nOpenTofu currently omits `complete` in its JSON format and is rejected by this\nhelper; report that limitation rather than adding a synthetic completeness flag.\nAlso inspect resource identity, drift, warnings, provider semantics, and any\neffects outside resource actions. For an authorized apply, consume the exact\napproved saved plan, not an uninspected newly generated plan.\n\nSource: [Terraform JSON plan format](https://developer.hashicorp.com/terraform/internals/json-format).\n\n### Wrangler and other deployment tools\n\nUse the proposed pinned Wrangler for `wrangler deploy --dry-run` with the same\nbuild/configuration/environment used by deployment. This checks bundling, not a\ncomplete remote resource plan. Separately verify account, worker name, routes,\nbindings and resource IDs against the existing deployment and read migration\nsemantics. Review Durable Object deleted/renamed classes, D1 schema/data\nmigrations, storage resources, queues, containers, and deployment integrations.\nNever infer \"no destruction\" from a successful bundle. Resource removals,\nreplacement, or unprovable remote effects skip the affected group. Apply the\nequivalent preview and identity checks to other tools rather than assuming they\nshare Terraform's guarantees.\n\nDo not assume `wrangler d1 migrations list --remote` is read-only. The\nimplementation inspected for this skill initializes migration tracking with\n`CREATE TABLE IF NOT EXISTS`; verify the pinned Wrangler version before using\nthe command. Verify database identity and compare migration files with the\ndatabase's configured migration tracking table through audited read-only\nqueries. A missing table, pending migration, or unverifiable schema/data\neffects hold the affected upgrade/deployment group. Never initialize schema\nmerely to establish preview safety.\n\nWrangler runs a custom `build.command` again during deployment. Use supported\nconfiguration referencing the same validated artifacts for both preview and\ndeployment, preventing another unvalidated build before upload. Bind the\nartifacts, configuration, and pinned tool to the authorized commit, and recheck\ntheir identities before upload and after relevant changes. Hold the affected\ngroup if the pinned Wrangler cannot upload the validated output without\nrebuilding it, or if the upload cannot be proven to match the preview.\n\nSources: [Wrangler command documentation](https://developers.cloudflare.com/workers/wrangler/commands/),\n[D1 migration listing implementation](https://github.com/cloudflare/workers-sdk/blob/e3d186776fcc2e4b5cc4cfd7155591778a375957/packages/wrangler/src/d1/migrations/list.ts),\n[migration table initialization](https://github.com/cloudflare/workers-sdk/blob/e3d186776fcc2e4b5cc4cfd7155591778a375957/packages/wrangler/src/d1/migrations/helpers.ts),\nand [Wrangler custom builds](https://developers.cloudflare.com/workers/wrangler/custom-builds/).\n\n### Ansible\n\nCheck controller Python, ansible-core, collections/roles, and target Python support\ntogether; read porting guides. Inspect all tasks and invoked scripts before\n`ansible-playbook --check --diff` with the real inventory and variables.\n`check_mode: false` forces mutation even with `--check`; unsupported modules and\nconditions based on registered results can omit effects. Inspect deletion,\nrecreation, service/data reset, and package removal semantics beyond the diff.\nSkipped or opaque tasks are a safety gap, not a clean preview. Redact diffs.\n\nSource: [Ansible check mode limits](https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_checkmode.html).\n\n## Inventory and choose compatible targets\n\nRecord each dependency source, current resolved version, latest stable candidate,\nselected target, compatibility constraints, upstream migration links, and checks.\nQuery authoritative registries, official releases, support matrices, and migration\nguides at execution time; do not treat remembered versions or prereleases as\nlatest stable. Inspect runtime requirements, peer dependencies, ABI/API changes,\nplatform availability, maintained release lines, and changed defaults, including\nsecurity, privacy/telemetry, data retention, and postinstall/native behavior.\nCheck transitive dependencies' peer/runtime constraints as well as direct ones. Unsupported\nor unpublished targets stay pinned with an explanation.\n\nInventory manifests, locks, tool configuration, CI/reusable actions, containers,\nscripts, deployment files, and executable documentation. Search duplicate version\npins and aliases, not just filenames; exclude vendored/generated snapshots unless\nthe repository owns their update process. Examples of sources to inspect:\n\n| Ecosystem | Sources and compatibility group |\n| --- | --- |\n| JavaScript/TypeScript | All package.json dependency fields, overrides/resolutions, workspace catalogs, packageManager/engines, npm/Bun/pnpm/Yarn locks, Node/Bun pins, compiler and lint/build/test plugins |\n| Toolchains | mise.toml/.mise.toml, mise.lock, .tool-versions, runtime version files, tool URLs/checksums, CI pins and container images; include every tool declared by mise, not just mise itself |\n| Python/Ansible | pyproject/requirements, uv/Poetry/pip locks, Python pins, ansible-core, collection/role requirements, lint plugins and managed host constraints |\n| Ruby/iOS | .ruby-version, Gemfile/lock, Bundler, CocoaPods, Podfile/lock, podspecs, Swift packages and Xcode/iOS deployment requirements |\n| Infrastructure | Terraform/OpenTofu CLI constraints, provider locks/constraints, module versions/Git refs, Wrangler and Cloudflare integration dependencies |\n| CI/system/native | Actions/reusable workflow refs, Docker tags/digests, OS images/packages, Rust/Cargo toolchain and locks, Go modules, Gradle/AGP/Kotlin/JDK and other repository-specific manifests |\n\nBuild connected compatibility groups before editing. Select the newest supported\ncombination, which can be older than an individual package's latest. Upgrade the\nframework first or keep its compatible toolchain pinned; do not force peer\nresolution, drop compatibility checks, or add blanket overrides to make installs\npass. Preserve source pin policy (exact version, digest, full Git SHA) and resolve\nimmutable pins from verified upstream releases. Preserve intentional runtime\nminimums unless migration requires changing the support contract.\n\nFor React Native, use its version-specific upgrade guide/template diffs and\nrepository upgrade skills. Couple React and its renderer, native modules,\nMetro/Babel, CLI, codegen, Hermes/New Architecture, CocoaPods/Bundler/Ruby,\nXcode/iOS deployment targets, and Android Gradle/AGP/Kotlin/JDK/SDK/NDK. For Expo,\nuse the chosen SDK's supported React Native/dependency matrix and its dependency\nchecks. Do not independently update framework-managed pods or generated native\nfiles; use the framework's regeneration workflow and prove iOS/Android builds.\nPermissive peer ranges alone do not prove native renderer or toolchain compatibility;\ncheck the framework's actual supported versions and native implementation.\nAn unavailable native toolchain is a reported validation limit; do not claim the\ngroup verified. See [React Native upgrading](https://reactnative.dev/docs/upgrading).\n\nCheck developer tools' own dependencies too: a compiler release without its old\nprogrammatic API may break test/lint runners that import it even when `tsc` passes.\nAction runtime upgrades can require newer self-hosted runners; preserve workflow\npermissions, action inputs/outputs, caching, artifact semantics, and job names.\n\nCheck current advisories with read-only ecosystem audits against the baseline and\nproposed lockfiles, using the repository's configured registry/advisory sources.\nDo not send private dependency metadata to an unconfigured or unauthorized service;\nreport the resulting coverage limit. Cover direct and resolved transitive dependencies,\nincluding native/platform-specific binaries. Latest direct packages can still\npin vulnerable transitive versions. Trace each finding to its owning dependency,\nverify affected versions, runtime conditions, and remediation in the maintainer's\nadvisory and fixed release. When the owner's range permits a fixed version, use a\ntargeted refresh with the lockfile's owning manager and preserve unrelated\nresolutions; otherwise prefer a supported owner upgrade.\nIf the owner still pins a vulnerable version, a narrowly scoped security patch\noverride may be used only with API/ABI/runtime compatibility evidence and focused\nregression checks of the actual affected integration. Document its rationale and\nremoval condition; a passing install or bundle alone is insufficient. Do not run\nblind audit fixes or use blanket overrides to bypass compatibility constraints.\nReport unresolved advisories and unavailable audit coverage accurately; current\ndirect pins or a partial clean audit do not\nestablish that the whole dependency graph is safe.\n\n## Migrate and validate\n\nCapture relevant baseline checks and warnings first, after screening their side\neffects. Update one compatibility group at a time. Read the upstream instructions\nfor every breaking step; implement required source/config/schema migrations and\nremoved API replacements. Use the manager that owns each lockfile, on the selected\nruntime, and inspect the resulting diff. Refresh transitive dependencies through\ntheir owning direct dependency; do not hand-edit integrity hashes or lock entries.\nReview intentional patches, overrides, and pins before removal; retain them until\nupstream fixes and regression checks demonstrate they are unnecessary.\nAvoid unrelated global installations or environment changes. Use task-local or\nrepository-scoped tools for testing changed runtime pins.\nFor published packages, also validate tarballs and consumer installs with their\ndocumented supported package managers, including manifest/override syntax and\nruntime requirements. A successful owning-manager install does not prove that\npublished metadata works for those consumers.\n\nRun the repository's setup/hooks, frozen installs, lint, typechecks, tests, builds,\npackage/platform smoke checks, and relevant safe integration previews. Resolve\nupgrade-related deprecation warnings at their source. Do not suppress warnings,\nweaken tests, or disable checks; report remaining upstream/pre-existing warnings\nwith evidence and keep a target pinned when migration cannot be completed.\nAdd focused regression coverage when a migration changes behavior; avoid tests\nthat merely assert version strings. Re-run checks after repairs. Report checks\nblocked by missing credentials, platforms, or external services accurately.\nRe-audit the final resolved graph after migrations and repairs.\n\nConfirm every inventory row is upgraded, already current, intentionally constrained,\nor skipped with a concrete reason. Do not present an unresolved group as complete.\nWhen upgrading agent-tool itself, install its managed skills with the same harness\nscope and commit the ownership manifest; never edit generated managed skill copies.\n\nWhen changes depend on another repository's release, ship the producer first and\nconfirm publishing and registry availability before pinning the consumer; include\nits exact version/commit and API migration notes. Independent groups may proceed.\nUse the installed `ship-pr` for authorized shipping and independently review every\nchanged HEAD. Check deployment safety again before its push/open/merge operations.\n\n## Report\n\nKeep a compact ledger of old/selected versions, completed migrations, validation\nand warning results, preview environment/commit/tool versions and safe action\nsummary, and every skipped/constrained dependency with the reason. Include baseline\nand final audit results, security overrides with their rationale and removal\ncondition, unresolved advisories, and audit coverage limits. For shipping,\ninclude branch, reviewed commit/verdict, PR, merge, publish/deploy result, and final\ncheckout state. For a repository sweep, keep one entry per repository, including\nunready or unchanged checkouts. Do not publish credentials, state, or plan contents.\n"
|
|
9
9
|
};
|