auto-mode 3.1.3 → 3.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { C as pickJudgeLane, E as updateJSONFile, S as CLI_LIMITS, T as resolveXDGDir, _ as readCheckout, a as resolveSessionScopePath, b as loadConfig, c as splitGitCommand, d as loadCheckoutFacts, f as writeActionDiagnostic, g as isUnresolvedWord, h as resolveShellPath, i as classifyAction, l as loadPolicy, m as collectShellCommands, n as readRuntime, o as loadSessionScope, p as toRepositorySlug, s as EMPTY_SESSION_SCOPE, t as parseActionRequest, u as resolveShippedPolicyDir, v as readGitEntry, w as M, x as runCapped, y as DEFAULT_SCOPE_SOURCES } from "./parse-action-request-Czvdr5DS.js";
3
- import { a as literal, d as string, i as discriminatedUnion, r as boolean, s as number, u as strictObject } from "./schemas-B80Yxv6m.js";
2
+ import { C as pickJudgeLane, E as updateJSONFile, S as CLI_LIMITS, T as resolveXDGDir, _ as readCheckout, a as resolveSessionScopePath, b as loadConfig, c as splitGitCommand, d as loadCheckoutFacts, f as writeActionDiagnostic, g as isUnresolvedWord, h as resolveShellPath, i as classifyAction, l as loadPolicy, m as collectShellCommands, n as readRuntime, o as loadSessionScope, p as toRepositorySlug, s as EMPTY_SESSION_SCOPE, t as parseActionRequest, u as resolveShippedPolicyDir, v as readGitEntry, w as M, x as runCapped, y as DEFAULT_SCOPE_SOURCES } from "./parse-action-request-DlsgKqiF.js";
3
+ import { a as literal, d as string, i as discriminatedUnion, l as record, p as unknown, r as boolean, s as number, u as strictObject } from "./schemas-B80Yxv6m.js";
4
4
  import { createHash, randomUUID } from "node:crypto";
5
5
  import { chmod, mkdir, open, readFile, realpath, stat } from "node:fs/promises";
6
6
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
@@ -2665,13 +2665,15 @@ function startDetachedProcess(file, args, env) {
2665
2665
  }
2666
2666
  //#endregion
2667
2667
  //#region src/judge/judge-server-response-schema.ts
2668
+ const modelUsageSchema = record(string(), unknown());
2668
2669
  const judgeServerResponseSchema = discriminatedUnion("kind", [strictObject({
2669
2670
  kind: literal("reply"),
2670
2671
  text: string(),
2671
2672
  model: string(),
2672
2673
  safetyStops: number().nullable(),
2673
2674
  fallback: boolean(),
2674
- warm: boolean().nullable()
2675
+ warm: boolean().nullable(),
2676
+ modelUsage: modelUsageSchema.nullable()
2675
2677
  }), strictObject({
2676
2678
  kind: literal("failure"),
2677
2679
  aborted: boolean(),
@@ -3283,7 +3285,7 @@ async function runJudgeServer(io, socketPath) {
3283
3285
  io.stderr.write(`auto-mode: judge-server needs a socket path\n\n${USAGE}`);
3284
3286
  return 2;
3285
3287
  }
3286
- await (await (await import("./start-judge-server-CDYdRR4I.js")).startJudgeServer({
3288
+ await (await (await import("./start-judge-server-BaeD4mmu.js")).startJudgeServer({
3287
3289
  socketPath,
3288
3290
  env: io.runtime.host.env,
3289
3291
  idleMs: JUDGE_IDLE_MS
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ interface JudgeMessageReply {
20
20
  readonly safetyStops: number | null;
21
21
  readonly fallback: boolean;
22
22
  readonly warm: boolean | null;
23
+ readonly modelUsage: Readonly<Record<string, unknown>> | null;
23
24
  }
24
25
  interface JudgeSession {
25
26
  readonly review: (model: string, request: Readonly<ModelRequest>, signal: Readonly<AbortSignal>) => Promise<JudgeMessageReply>;
@@ -30,6 +31,7 @@ interface JudgeDiagnostics {
30
31
  readonly status: JudgeStatus;
31
32
  readonly failureReason: JudgeFailure | null;
32
33
  readonly overturnBasis: OverturnBasis | null;
34
+ readonly overturnReason: string | null;
33
35
  readonly model: string;
34
36
  readonly answeringModel: string | null;
35
37
  readonly safetyStops: number | null;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { b as loadConfig$1, i as classifyAction$1, n as readRuntime, r as readHostEnvironment, t as parseActionRequest } from "./parse-action-request-Czvdr5DS.js";
1
+ import { b as loadConfig$1, i as classifyAction$1, n as readRuntime, r as readHostEnvironment, t as parseActionRequest } from "./parse-action-request-DlsgKqiF.js";
2
2
  //#region src/index.ts
3
3
  function classifyAction(request, config, options = {}) {
4
4
  return classifyAction$1(request, config, {
@@ -3091,7 +3091,7 @@ async function writeActionDiagnostic(payload, entry, host, warnings) {
3091
3091
  const agentKey = agentID === null ? payload.sessionID : `${payload.sessionID}\0${agentID}`;
3092
3092
  const isReviewed = entry.judge !== void 0 || entry.grant !== void 0;
3093
3093
  const record = {
3094
- schemaVersion: 7,
3094
+ schemaVersion: 8,
3095
3095
  time: (/* @__PURE__ */ new Date()).toISOString(),
3096
3096
  invocationID: entry.invocationID,
3097
3097
  sessionHash: toHash(payload.sessionID),
@@ -3103,8 +3103,8 @@ async function writeActionDiagnostic(payload, entry, host, warnings) {
3103
3103
  denials: entry.denials ?? null,
3104
3104
  escalation: entry.escalation ?? false,
3105
3105
  diagnostics: entry.diagnostics ?? null,
3106
- judge: entry.judge ?? null,
3107
- grant: entry.grant ?? null,
3106
+ judge: entry.judge === void 0 ? null : buildLoggedReview(entry.judge),
3107
+ grant: entry.grant === void 0 ? null : buildLoggedReview(entry.grant),
3108
3108
  action: isReviewed ? buildLoggedAction(payload) : null
3109
3109
  };
3110
3110
  try {
@@ -3120,6 +3120,17 @@ async function writeActionDiagnostic(payload, entry, host, warnings) {
3120
3120
  function toHash(value) {
3121
3121
  return createHash("sha256").update(value).digest("hex").slice(0, 16);
3122
3122
  }
3123
+ function buildLoggedReview(review) {
3124
+ if (review.overturnReason === null) return review;
3125
+ const reason = buildSecretFreeText(review.overturnReason, () => "[secret]");
3126
+ return {
3127
+ ...review,
3128
+ overturnReason: findSecret({
3129
+ text: reason,
3130
+ path: null
3131
+ }) === null ? reason : null
3132
+ };
3133
+ }
3123
3134
  const LOGGED_INPUT_MAX_CHARS = 2e3;
3124
3135
  function buildLoggedAction(payload) {
3125
3136
  const redacted = buildSecretFreeValue(payload.toolInput);
@@ -3149,6 +3160,25 @@ function hasSecret(value) {
3149
3160
  return false;
3150
3161
  }
3151
3162
  //#endregion
3163
+ //#region src/diagnostics/write-judge-usage.ts
3164
+ async function writeJudgeUsage(usage, host, warnings) {
3165
+ const path = host.env["AUTO_MODE_DEBUG_PATH"];
3166
+ if (path === void 0 || path === "") return;
3167
+ const line = {
3168
+ time: (/* @__PURE__ */ new Date()).toISOString(),
3169
+ ...usage
3170
+ };
3171
+ try {
3172
+ await mkdir(dirname(path), {
3173
+ recursive: true,
3174
+ mode: 448
3175
+ });
3176
+ await appendFile(path, `${JSON.stringify(line)}\n`, { mode: 384 });
3177
+ } catch {
3178
+ warnings.write("auto-mode: judge debug line unavailable\n");
3179
+ }
3180
+ }
3181
+ //#endregion
3152
3182
  //#region src/git/build-repository-context.ts
3153
3183
  function buildRepositoryContext(facts) {
3154
3184
  if (facts.head === null) return null;
@@ -3571,18 +3601,24 @@ function buildJudgedVerdict(rule, basis, reply, options) {
3571
3601
  if (reply === null || reply.kind === "unreadable") return {
3572
3602
  verdict: template,
3573
3603
  status: "failed",
3574
- overturnBasis: null
3604
+ overturnBasis: null,
3605
+ overturnReason: null
3575
3606
  };
3576
3607
  if (reply.kind === "overturn") {
3577
3608
  const clearsHardRule = reply.basis === "misread" && options.misreadClears === true;
3578
- return rule.tier === "hard" && !clearsHardRule || reply.basis === "misread" && options.overturns === "consent" || reply.basis === "consent" && !options.hasUserMessage ? {
3609
+ const isHeld = rule.tier === "hard" && !clearsHardRule || reply.basis === "misread" && options.overturns === "consent" || reply.basis === "consent" && !options.hasUserMessage;
3610
+ const overturn = {
3611
+ overturnBasis: reply.basis,
3612
+ overturnReason: formatJudgeText(buildSecretFreeText(reply.reason, () => "[secret]"))
3613
+ };
3614
+ return isHeld ? {
3579
3615
  verdict: template,
3580
3616
  status: "held",
3581
- overturnBasis: reply.basis
3617
+ ...overturn
3582
3618
  } : {
3583
3619
  verdict: { kind: "allow" },
3584
3620
  status: "overturned",
3585
- overturnBasis: reply.basis
3621
+ ...overturn
3586
3622
  };
3587
3623
  }
3588
3624
  return {
@@ -3592,7 +3628,8 @@ function buildJudgedVerdict(rule, basis, reply, options) {
3592
3628
  reason: `The reviewer confirmed the ${rule.name} deny: ${formatJudgeText(reply.reason)}`
3593
3629
  },
3594
3630
  status: "confirmed",
3595
- overturnBasis: null
3631
+ overturnBasis: null,
3632
+ overturnReason: null
3596
3633
  };
3597
3634
  }
3598
3635
  function formatJudgeText(text) {
@@ -3808,7 +3845,7 @@ function sendJudgeMessage(provider, request, transport, signal) {
3808
3845
  }
3809
3846
  async function sendToAgentSDK(provider, request, transport, signal) {
3810
3847
  if (transport.session !== void 0) return transport.session.review(provider.model, request, signal);
3811
- const session = (await import("./start-judge-session-C0eRJFlg.js")).startJudgeSession(transport.env);
3848
+ const session = (await import("./start-judge-session-B65PMvQ6.js")).startJudgeSession(transport.env);
3812
3849
  try {
3813
3850
  return await session.review(provider.model, request, signal);
3814
3851
  } finally {
@@ -3822,7 +3859,8 @@ async function sendToMessagesAPI(provider, request, transport, signal) {
3822
3859
  model: provider.model,
3823
3860
  safetyStops: null,
3824
3861
  fallback: false,
3825
- warm: null
3862
+ warm: null,
3863
+ modelUsage: null
3826
3864
  };
3827
3865
  }
3828
3866
  //#endregion
@@ -3872,6 +3910,11 @@ async function classifyWithJudge(payload, evidence, judge, options) {
3872
3910
  throw error;
3873
3911
  });
3874
3912
  replies = parseJudgeReplies(answered.text, evidence.map((entry) => entry.rule.name));
3913
+ if (answered.modelUsage !== null) await options.onUsage?.({
3914
+ model: judge.model,
3915
+ answeringModel: answered.model,
3916
+ modelUsage: answered.modelUsage
3917
+ });
3875
3918
  failure = null;
3876
3919
  } catch {}
3877
3920
  const elapsedMs = Math.round(performance.now() - start);
@@ -3890,6 +3933,7 @@ async function classifyWithJudge(payload, evidence, judge, options) {
3890
3933
  status: verdict.status,
3891
3934
  failureReason: failure ?? (reply?.kind === "unreadable" ? "unreadable" : null),
3892
3935
  overturnBasis: verdict.overturnBasis,
3936
+ overturnReason: verdict.overturnReason,
3893
3937
  model: judge.model,
3894
3938
  answeringModel: answered?.model ?? null,
3895
3939
  safetyStops: answered?.safetyStops ?? null,
@@ -6241,7 +6285,8 @@ async function classifyWithGrant(ctx, decided) {
6241
6285
  const judged = await classifyWithJudge(ctx.request, evidence, judge, {
6242
6286
  ...ctx.options,
6243
6287
  rulesPath: ctx.config.rulesPath,
6244
- overturns: ctx.config.judgeOverturns ?? "any"
6288
+ overturns: ctx.config.judgeOverturns ?? "any",
6289
+ onUsage: (usage) => writeJudgeUsage(usage, ctx.options.runtime.host, ctx.options.stderr)
6245
6290
  });
6246
6291
  const granted = grant === null ? null : judged[0] ?? null;
6247
6292
  const reviewed = denied === null ? null : judged.at(-1) ?? null;
@@ -1,5 +1,5 @@
1
1
  import { d as string, s as number, u as strictObject } from "./schemas-B80Yxv6m.js";
2
- import { t as startJudgeSession } from "./start-judge-session-vhUxe9-V.js";
2
+ import { t as startJudgeSession } from "./start-judge-session-C_k8lacU.js";
3
3
  import { randomBytes } from "node:crypto";
4
4
  import { chmod, mkdir, rename, rm, stat } from "node:fs/promises";
5
5
  import { dirname, join } from "node:path";
@@ -0,0 +1 @@
1
+ export { t as startJudgeSession } from "./start-judge-session-C_k8lacU.js";
@@ -1,4 +1,4 @@
1
- import { c as object, d as string, l as record, s as number } from "./schemas-B80Yxv6m.js";
1
+ import { c as object, d as string, l as record, p as unknown, s as number } from "./schemas-B80Yxv6m.js";
2
2
  import { createRequire } from "node:module";
3
3
  import ut, { delimiter, isAbsolute, join } from "node:path";
4
4
  import { spawn } from "node:child_process";
@@ -39277,7 +39277,7 @@ function startJudgeSession(env) {
39277
39277
  current.reviews += 1;
39278
39278
  if (turn.sessionFallback) stop();
39279
39279
  else current.cleared = sendClear(current.send, current.stop);
39280
- return buildReply(turn.result, turn.fallbacks, model, warm);
39280
+ return buildReply(turn, model, warm);
39281
39281
  } catch (error) {
39282
39282
  if (signal.aborted) throw new DOMException("Judge review aborted", "AbortError");
39283
39283
  throw error;
@@ -39343,13 +39343,18 @@ function startLiveProcess(model, system, key, env) {
39343
39343
  waiter.sessionFallback ||= message.scope !== "local";
39344
39344
  return;
39345
39345
  }
39346
+ if (message.type === "assistant" && message.parent_tool_use_id === null && message.error === void 0) {
39347
+ waiter.replyModel = message.message.model;
39348
+ return;
39349
+ }
39346
39350
  if (message.type === "result") {
39347
39351
  const done = waiter;
39348
39352
  waiter = null;
39349
39353
  done.resolve({
39350
39354
  result: message,
39351
39355
  fallbacks: done.fallbacks,
39352
- sessionFallback: done.sessionFallback
39356
+ sessionFallback: done.sessionFallback,
39357
+ replyModel: done.replyModel
39353
39358
  });
39354
39359
  }
39355
39360
  };
@@ -39371,7 +39376,8 @@ function startLiveProcess(model, system, key, env) {
39371
39376
  resolve,
39372
39377
  reject,
39373
39378
  fallbacks: 0,
39374
- sessionFallback: false
39379
+ sessionFallback: false,
39380
+ replyModel: null
39375
39381
  };
39376
39382
  input.push(text);
39377
39383
  })
@@ -39445,23 +39451,22 @@ async function sendClear(send, stop) {
39445
39451
  }
39446
39452
  }
39447
39453
  const MODEL_USAGE = record(string(), object({ outputTokens: number() }));
39454
+ const RAW_MODEL_USAGE = record(string(), unknown());
39448
39455
  const SAFETY_STOPS = object({ safety_stops: number() });
39449
- function buildReply(result, fallbacks, requested, warm) {
39456
+ function buildReply(turn, requested, warm) {
39457
+ const result = turn.result;
39450
39458
  if (result.subtype !== "success" || result.is_error) throw new Error(`the judge turn ended in ${result.subtype}`);
39451
39459
  const usage = MODEL_USAGE.safeParse(result.modelUsage).data;
39452
39460
  const stops = SAFETY_STOPS.safeParse(result).data?.safety_stops;
39453
39461
  return {
39454
39462
  text: result.result,
39455
- model: pickAnsweringModel(usage, requested),
39463
+ model: turn.replyModel ?? requested,
39456
39464
  safetyStops: stops ?? null,
39457
- fallback: fallbacks > 0 || isFallbackReply(usage, stops),
39458
- warm
39465
+ fallback: turn.fallbacks > 0 || isFallbackReply(usage, stops),
39466
+ warm,
39467
+ modelUsage: RAW_MODEL_USAGE.safeParse(result.modelUsage).data ?? null
39459
39468
  };
39460
39469
  }
39461
- function pickAnsweringModel(usage, requested) {
39462
- const [top] = Object.entries(usage ?? {}).filter(([, entry]) => entry.outputTokens > 0).toSorted(([, left], [, right]) => right.outputTokens - left.outputTokens);
39463
- return top === void 0 ? requested : top[0];
39464
- }
39465
39470
  function isFallbackReply(usage, stops) {
39466
39471
  if (stops !== void 0) return stops > 0;
39467
39472
  const entries = Object.values(usage ?? {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auto-mode",
3
- "version": "3.1.3",
3
+ "version": "3.1.4",
4
4
  "description": "A permission classifier library and Claude Code mod, so agents that are not Claude can run unattended",
5
5
  "keywords": [
6
6
  "agent",
@@ -1 +0,0 @@
1
- export { t as startJudgeSession } from "./start-judge-session-vhUxe9-V.js";