@kylecheng3146/agent-ops 0.2.0 → 0.2.1

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.
@@ -318,6 +318,7 @@ export async function runReviewCommand(options) {
318
318
  return notRunEnvelope({
319
319
  ...resultBase,
320
320
  status: "NOT_RUN", reason: preflight.reason,
321
+ taskId: context.taskId,
321
322
  scope
322
323
  });
323
324
  }
@@ -229,7 +229,7 @@ export async function runHookProcess(argv, io, cliVersion, dependencies = {}) {
229
229
  return 0;
230
230
  }
231
231
  try {
232
- const root = dependencies.root ?? process.cwd();
232
+ let root = dependencies.root ?? process.cwd();
233
233
  const harnessId = harness;
234
234
  const hookEvent = event;
235
235
  if (process.env.AGENT_OPS_DISABLE === "1") {
@@ -247,6 +247,21 @@ export async function runHookProcess(argv, io, cliVersion, dependencies = {}) {
247
247
  }
248
248
  const rawInput = await readStdin(io.stdin);
249
249
  const parsedInput = withInjectedSession(harnessId, parseInput(rawInput));
250
+ if (dependencies.root === undefined) {
251
+ const inputRoot = typeof parsedInput === "object" &&
252
+ parsedInput !== null &&
253
+ Array.isArray(parsedInput.workspacePaths) &&
254
+ typeof parsedInput.workspacePaths[0] === "string"
255
+ ? parsedInput.workspacePaths[0]
256
+ : typeof parsedInput === "object" &&
257
+ parsedInput !== null &&
258
+ typeof parsedInput.projectRoot === "string"
259
+ ? parsedInput.projectRoot
260
+ : undefined;
261
+ if (inputRoot !== undefined) {
262
+ root = inputRoot;
263
+ }
264
+ }
250
265
  const configOutcome = await hookConfigOutcome(root, dependencies.loadConfig);
251
266
  if (configOutcome.kind === "invalid") {
252
267
  if (completionGateInstalled) {
@@ -3,6 +3,16 @@ import { safeTaskText } from "../task/render.js";
3
3
  function safe(value) {
4
4
  return safeTaskText(redactSecrets(value));
5
5
  }
6
+ /**
7
+ * NOT_RUN reasons that mean the task's verification evidence, not the reviewer,
8
+ * stopped the run: every one of them is cleared by producing fresh evidence.
9
+ */
10
+ const VERIFICATION_EVIDENCE_REASONS = new Set([
11
+ "stale-verification",
12
+ "missing-verification-evidence",
13
+ "unreadable-verification-evidence",
14
+ "verification-not-passed"
15
+ ]);
6
16
  function lineList(values) {
7
17
  return values.length === 0 ? ["- none"] : values.map((value) => `- ${safe(value)}`);
8
18
  }
@@ -51,6 +61,26 @@ export function renderReviewResult(result) {
51
61
  result.attempts?.some((attempt) => attempt.reason === "login-required")) {
52
62
  lines.push("Run: agent-ops doctor --check-auth to verify target authentication.");
53
63
  }
64
+ // Evidence is pinned to the source it was produced from, so any edit to a
65
+ // changed file after the verifier ran — a doc rewritten by a later step
66
+ // counts — voids it. Without the next command the caller reads
67
+ // "stale-verification" as a review failure and retries review instead.
68
+ if (result.reason === "stale-verification") {
69
+ lines.push("The source changed after this evidence was recorded, so it no longer " +
70
+ "describes the worktree under review.");
71
+ }
72
+ const verifyCommand = `agent-ops verify --task ${result.taskId ?? "<task-id>"}`;
73
+ if (result.reason === "verification-not-passed") {
74
+ // No review invitation: the verifier failed, and review is refused until
75
+ // a passing run replaces that evidence. Naming review here is what sent
76
+ // the caller back to the command that had just refused them.
77
+ lines.push("The recorded verification did not pass. Fix what failed, then run: " +
78
+ `${verifyCommand}. Re-running review cannot turn a failing verifier ` +
79
+ "into a PASS.");
80
+ }
81
+ else if (VERIFICATION_EVIDENCE_REASONS.has(result.reason ?? "")) {
82
+ lines.push(`Run: ${verifyCommand}, then run this review again.`);
83
+ }
54
84
  if (result.reason === "host-sandboxed") {
55
85
  lines.push("No target ran: the sandbox around this process blocks the network a " +
56
86
  "reviewer needs. Run agent-ops review outside the sandbox, or grant " +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kylecheng3146/agent-ops",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Evidence-driven development loops for agy, Codex, Claude Code, and opencode",
5
5
  "type": "module",
6
6
  "license": "MIT",