auto-mode 0.13.0 → 0.14.0

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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { D as string, E as strictObject, T as number, _ as splitCommandWords, a as resolveSessionScopePath, b as DEFAULT_SCOPE_SOURCES, c as findCheckout, f as loadRepositoryContext, g as splitShellCommand, h as toRepositorySlug, i as resolveStateDir, m as loadPolicy, n as parseActionRequest, o as loadSessionScope, p as loadCheckoutRemotes, r as classifyAction, s as EMPTY_SESSION_SCOPE, t as renderVerdict, x as loadConfig, y as DEFAULT_DENIAL_BUDGET } from "./render-verdict-De8aTmg-.js";
2
+ import { D as string, E as strictObject, T as number, _ as splitCommandWords, a as resolveSessionScopePath, b as DEFAULT_SCOPE_SOURCES, c as findCheckout, f as loadRepositoryContext, g as splitShellCommand, h as toRepositorySlug, i as resolveStateDir, m as loadPolicy, n as parseActionRequest, o as loadSessionScope, p as loadCheckoutRemotes, r as classifyAction, s as EMPTY_SESSION_SCOPE, t as renderVerdict, x as loadConfig, y as DEFAULT_DENIAL_BUDGET } from "./render-verdict-QLyj-g7d.js";
3
3
  import { appendFile, mkdir, open, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
4
4
  import { dirname, isAbsolute, join, normalize } from "node:path";
5
5
  import { homedir } from "node:os";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { C as resolveConfigPath, S as resolveApiKey, d as parseModelVerdict, l as classifyLocally, m as loadPolicy, n as parseActionRequest, r as classifyAction, t as renderVerdict, u as classifyWithModel, v as DEFAULT_CONFIG, w as PRESETS, x as loadConfig } from "./render-verdict-De8aTmg-.js";
1
+ import { C as resolveConfigPath, S as resolveApiKey, d as parseModelVerdict, l as classifyLocally, m as loadPolicy, n as parseActionRequest, r as classifyAction, t as renderVerdict, u as classifyWithModel, v as DEFAULT_CONFIG, w as PRESETS, x as loadConfig } from "./render-verdict-QLyj-g7d.js";
2
2
  export { DEFAULT_CONFIG, PRESETS, classifyAction, classifyLocally, classifyWithModel, loadConfig, loadPolicy, parseActionRequest, parseModelVerdict, renderVerdict, resolveApiKey, resolveConfigPath };
@@ -5654,7 +5654,8 @@ const DEFAULT_DENIAL_BUDGET = {
5654
5654
  };
5655
5655
  const DEFAULT_SCOPE_SOURCES = {
5656
5656
  cwd: { kind: "cwd" },
5657
- session: { kind: "session" }
5657
+ session: { kind: "session" },
5658
+ atc: { kind: "atc" }
5658
5659
  };
5659
5660
  const DEFAULT_CONFIG = {
5660
5661
  provider: DEFAULT_PROVIDER,
@@ -7837,6 +7838,106 @@ const DEFAULT_NAMES = /* @__PURE__ */ new Set([
7837
7838
  "develop"
7838
7839
  ]);
7839
7840
  //#endregion
7841
+ //#region src/scope/build-atc-scope-facts.ts
7842
+ function buildAtcScopeFacts(record, isInRepository) {
7843
+ const scope = record.scope;
7844
+ const checkouts = [scope.workspace, ...scope.worktrees];
7845
+ return {
7846
+ worktrees: checkouts.map((checkout) => checkout.path),
7847
+ branches: [...checkouts.flatMap((checkout) => checkout.branch !== null && isInRepository(checkout.path) ? [checkout.branch] : []), ...scope.branches.flatMap((branch) => isInRepository(branch.repo ?? scope.workspace.path) ? [branch.name] : [])],
7848
+ pullRequests: scope.pullRequests.flatMap((pull) => {
7849
+ const repository = toRepositorySlug(`https://${findHost(pull.url)}/${pull.repo}`);
7850
+ return pull.branch === null || repository === null ? [] : [{
7851
+ number: pull.number,
7852
+ head: pull.branch,
7853
+ repository
7854
+ }];
7855
+ }),
7856
+ pathGlobs: []
7857
+ };
7858
+ }
7859
+ function findHost(url) {
7860
+ return (url === void 0 ? null : URL.parse(url)?.host) ?? "github.com";
7861
+ }
7862
+ //#endregion
7863
+ //#region src/scope/load-atc-session-record.ts
7864
+ const name$1 = string().min(1);
7865
+ const path = name$1.refine(isAbsolute, "an absolute path");
7866
+ const checkoutSchema = object({
7867
+ path,
7868
+ branch: name$1.nullable()
7869
+ }).readonly();
7870
+ const branchSchema$1 = object({
7871
+ name: name$1,
7872
+ repo: path.optional()
7873
+ }).readonly();
7874
+ const pullRequestSchema$1 = object({
7875
+ repo: name$1,
7876
+ number: number().int().positive(),
7877
+ url: name$1.optional(),
7878
+ branch: name$1.nullable()
7879
+ }).readonly();
7880
+ const scopeSchema = object({
7881
+ workspace: checkoutSchema,
7882
+ worktrees: array(checkoutSchema).readonly(),
7883
+ branches: array(branchSchema$1).readonly(),
7884
+ pullRequests: array(pullRequestSchema$1).readonly()
7885
+ }).readonly();
7886
+ const recordSchema = object({
7887
+ format: literal("atc.session-record"),
7888
+ version: literal(1),
7889
+ session: name$1,
7890
+ scope: scopeSchema
7891
+ }).readonly();
7892
+ async function loadAtcSessionRecord(location, sessionID) {
7893
+ if (location === void 0 || location === "") return { kind: "absent" };
7894
+ if (!isAbsolute(location)) return {
7895
+ kind: "malformed",
7896
+ diagnostic: `atc session record path is not absolute: ${location}`
7897
+ };
7898
+ let raw;
7899
+ try {
7900
+ raw = await readFile(location, "utf8");
7901
+ } catch (error) {
7902
+ return isMissing(error) ? { kind: "absent" } : {
7903
+ kind: "malformed",
7904
+ diagnostic: `atc session record unreadable: ${location}`
7905
+ };
7906
+ }
7907
+ let parsed;
7908
+ try {
7909
+ parsed = JSON.parse(raw);
7910
+ } catch {
7911
+ return {
7912
+ kind: "malformed",
7913
+ diagnostic: `atc session record is not JSON: ${location}`
7914
+ };
7915
+ }
7916
+ const result = recordSchema.safeParse(parsed);
7917
+ if (!result.success) {
7918
+ const [issue] = result.error.issues;
7919
+ return {
7920
+ kind: "malformed",
7921
+ diagnostic: `atc session record ignored: ${issue === void 0 ? "record" : issue.path.join(".") || "record"} does not match version 1: ${location}`
7922
+ };
7923
+ }
7924
+ if (sessionID === void 0 || sessionID === "") return {
7925
+ kind: "malformed",
7926
+ diagnostic: `atc session record has no session to match: ${location}`
7927
+ };
7928
+ if (result.data.session !== sessionID) return {
7929
+ kind: "malformed",
7930
+ diagnostic: `atc session record belongs to another session: ${location}`
7931
+ };
7932
+ return {
7933
+ kind: "record",
7934
+ record: result.data
7935
+ };
7936
+ }
7937
+ function isMissing(error) {
7938
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
7939
+ }
7940
+ //#endregion
7840
7941
  //#region src/scope/types.ts
7841
7942
  const EMPTY_SCOPE_FACTS = {
7842
7943
  worktrees: [],
@@ -7902,7 +8003,23 @@ function pickScopeSourceReader(source) {
7902
8003
  });
7903
8004
  };
7904
8005
  if (source.kind === "globs") return () => Promise.resolve(buildFacts({ pathGlobs: source.paths ?? [] }));
7905
- return () => Promise.resolve(EMPTY_SCOPE_FACTS);
8006
+ return async (context) => {
8007
+ const loaded = await loadAtcSessionRecord(context.atcRecordPath, context.atcSessionID);
8008
+ if (loaded.kind === "malformed") process.stderr.write(`auto-mode: ${loaded.diagnostic}\n`);
8009
+ if (loaded.kind !== "record") return EMPTY_SCOPE_FACTS;
8010
+ const scope = loaded.record.scope;
8011
+ const paths = /* @__PURE__ */ new Set([
8012
+ scope.workspace.path,
8013
+ ...scope.worktrees.map((worktree) => worktree.path),
8014
+ ...scope.branches.map((branch) => branch.repo ?? scope.workspace.path)
8015
+ ]);
8016
+ const entries = await Promise.all([...paths].map((path) => findCommonDirEntry(path)));
8017
+ const commonDirs = new Map(entries);
8018
+ return buildAtcScopeFacts(loaded.record, (path) => context.commonDir !== null && commonDirs.get(path) === context.commonDir);
8019
+ };
8020
+ }
8021
+ async function findCommonDirEntry(path) {
8022
+ return [path, (await findCheckout(path))?.commonDir ?? null];
7906
8023
  }
7907
8024
  function buildFacts(facts) {
7908
8025
  return {
@@ -7922,7 +8039,9 @@ async function loadTaskScope(request, sources) {
7922
8039
  worktree: checkout?.worktree ?? cwd,
7923
8040
  commonDir: checkout?.commonDir ?? null,
7924
8041
  branch,
7925
- stateDir: request.stateDir
8042
+ stateDir: request.stateDir,
8043
+ atcRecordPath: process.env["ATC_SESSION_RECORD"],
8044
+ atcSessionID: process.env["ATC_SESSION_ID"]
7926
8045
  };
7927
8046
  const [remotes, ...facts] = await Promise.all([checkout === null ? [] : loadCheckoutRemotes(checkout.commonDir), ...Object.values(sources).map((source) => pickScopeSourceReader(source)(sourceContext))]);
7928
8047
  return buildTaskScope({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auto-mode",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
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",