@autohq/cli 0.1.134 → 0.1.135

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.
@@ -26273,7 +26273,7 @@ Object.assign(lookup, {
26273
26273
  // package.json
26274
26274
  var package_default = {
26275
26275
  name: "@autohq/cli",
26276
- version: "0.1.134",
26276
+ version: "0.1.135",
26277
26277
  license: "SEE LICENSE IN README.md",
26278
26278
  publishConfig: {
26279
26279
  access: "public"
package/dist/index.js CHANGED
@@ -334,8 +334,8 @@ async function createOAuthLoopbackCallback(input) {
334
334
  });
335
335
  let resolveResult;
336
336
  let rejectResult;
337
- const result = new Promise((resolve2, reject) => {
338
- resolveResult = resolve2;
337
+ const result = new Promise((resolve3, reject) => {
338
+ resolveResult = resolve3;
339
339
  rejectResult = reject;
340
340
  });
341
341
  const server = createServer((request, response) => {
@@ -595,14 +595,14 @@ async function listenOnPreferredPort(server, port) {
595
595
  }
596
596
  }
597
597
  async function listen(server, port) {
598
- await new Promise((resolve2, reject) => {
598
+ await new Promise((resolve3, reject) => {
599
599
  const onError = (error51) => {
600
600
  server.off("listening", onListening);
601
601
  reject(error51);
602
602
  };
603
603
  const onListening = () => {
604
604
  server.off("error", onError);
605
- resolve2();
605
+ resolve3();
606
606
  };
607
607
  server.once("error", onError);
608
608
  server.once("listening", onListening);
@@ -873,7 +873,7 @@ function persistLogin(config2, input) {
873
873
  }
874
874
  }
875
875
  async function sleep(ms) {
876
- await new Promise((resolve2) => setTimeout(resolve2, ms));
876
+ await new Promise((resolve3) => setTimeout(resolve3, ms));
877
877
  }
878
878
  var init_login = __esm({
879
879
  "src/commands/auth/login.ts"() {
@@ -21208,7 +21208,7 @@ var init_package = __esm({
21208
21208
  "package.json"() {
21209
21209
  package_default = {
21210
21210
  name: "@autohq/cli",
21211
- version: "0.1.134",
21211
+ version: "0.1.135",
21212
21212
  license: "SEE LICENSE IN README.md",
21213
21213
  publishConfig: {
21214
21214
  access: "public"
@@ -21375,14 +21375,8 @@ var init_assets = __esm({
21375
21375
  }
21376
21376
  });
21377
21377
 
21378
- // src/commands/apply/files.ts
21379
- import { createHash as createHash3 } from "crypto";
21380
- import {
21381
- readFileSync as readFileSync3,
21382
- readdirSync as readdirSync2,
21383
- realpathSync,
21384
- statSync
21385
- } from "fs";
21378
+ // src/commands/agents/authoring.ts
21379
+ import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync } from "fs";
21386
21380
  import {
21387
21381
  basename as basename2,
21388
21382
  dirname as dirname4,
@@ -21391,7 +21385,436 @@ import {
21391
21385
  join as join3,
21392
21386
  resolve
21393
21387
  } from "path";
21394
- import { parseAllDocuments as parseYamlDocuments } from "yaml";
21388
+ import { parseAllDocuments as parseYamlDocuments, stringify } from "yaml";
21389
+ function compileAgentFile(path2) {
21390
+ const context = { graph: /* @__PURE__ */ new Map(), removals: [] };
21391
+ const document = readSingleDocument(path2);
21392
+ const compiled = normalizeAgentDocument(
21393
+ compileAgentDocument(document, path2, [], context)
21394
+ );
21395
+ const parsed = ProjectApplyResourceSchema.safeParse(compiled);
21396
+ if (!parsed.success) {
21397
+ throw new Error(`Invalid compiled agent ${path2}: ${parsed.error.message}`);
21398
+ }
21399
+ if (parsed.data.kind !== RESOURCE_KIND_SESSION) {
21400
+ throw new Error(
21401
+ `Invalid compiled agent ${path2}: expected kind "agent", got "${parsed.data.kind}"`
21402
+ );
21403
+ }
21404
+ return {
21405
+ resource: parsed.data,
21406
+ graph: [...context.graph.values()],
21407
+ removals: context.removals
21408
+ };
21409
+ }
21410
+ function compileAgentDocumentValue(document, path2) {
21411
+ const context = { graph: /* @__PURE__ */ new Map(), removals: [] };
21412
+ const compiled = normalizeAgentDocument(
21413
+ compileAgentDocument(document, path2, [], context)
21414
+ );
21415
+ const parsed = ProjectApplyResourceSchema.safeParse(compiled);
21416
+ if (!parsed.success) {
21417
+ throw new Error(`Invalid compiled agent ${path2}: ${parsed.error.message}`);
21418
+ }
21419
+ if (parsed.data.kind !== RESOURCE_KIND_SESSION) {
21420
+ throw new Error(
21421
+ `Invalid compiled agent ${path2}: expected kind "agent", got "${parsed.data.kind}"`
21422
+ );
21423
+ }
21424
+ return {
21425
+ resource: parsed.data,
21426
+ graph: [...context.graph.values()],
21427
+ removals: context.removals
21428
+ };
21429
+ }
21430
+ function renderCompiledAgentYaml(result) {
21431
+ return stringify(result.resource).trimEnd();
21432
+ }
21433
+ function renderAgentExplain(result) {
21434
+ const lines = [
21435
+ `agent ${result.resource.metadata.name}`,
21436
+ `files ${result.graph.length}`
21437
+ ];
21438
+ for (const node of result.graph) {
21439
+ lines.push(node.path);
21440
+ for (const imported of node.imports) {
21441
+ lines.push(` imports ${imported}`);
21442
+ }
21443
+ }
21444
+ if (result.removals.length > 0) {
21445
+ lines.push("removals");
21446
+ for (const removal of result.removals) {
21447
+ lines.push(
21448
+ ` ${removal.target}: ${removal.names.join(", ")} (${removal.path})`
21449
+ );
21450
+ }
21451
+ }
21452
+ return lines.join("\n");
21453
+ }
21454
+ function readLocalAgentAuthoringStatuses(input) {
21455
+ const agentsDirectory = join3(
21456
+ input?.directory ?? join3(process.cwd(), ".auto"),
21457
+ "agents"
21458
+ );
21459
+ let entries;
21460
+ try {
21461
+ entries = readdirSync2(agentsDirectory).filter(
21462
+ (entry) => AGENT_FILE_EXTENSIONS.includes(
21463
+ extname(
21464
+ entry
21465
+ ).toLowerCase()
21466
+ )
21467
+ ).sort((left, right) => left.localeCompare(right));
21468
+ } catch {
21469
+ return [];
21470
+ }
21471
+ return entries.map((entry) => {
21472
+ const path2 = join3(agentsDirectory, entry);
21473
+ const fallbackName = basename2(entry, extname(entry));
21474
+ try {
21475
+ const result = compileAgentFile(path2);
21476
+ return {
21477
+ name: result.resource.metadata.name,
21478
+ path: path2,
21479
+ ok: true,
21480
+ imports: importedEdgeCount(result.graph),
21481
+ removals: result.removals.reduce(
21482
+ (count, removal) => count + removal.names.length,
21483
+ 0
21484
+ )
21485
+ };
21486
+ } catch (error51) {
21487
+ return {
21488
+ name: fallbackName,
21489
+ path: path2,
21490
+ ok: false,
21491
+ imports: 0,
21492
+ removals: 0,
21493
+ error: error51 instanceof Error ? error51.message : String(error51)
21494
+ };
21495
+ }
21496
+ });
21497
+ }
21498
+ function importedAgentAuthoringPaths(paths) {
21499
+ const imported = /* @__PURE__ */ new Set();
21500
+ for (const path2 of paths) {
21501
+ for (const document of readDocuments(path2)) {
21502
+ discoverImports(document, path2, [], imported);
21503
+ }
21504
+ }
21505
+ return imported;
21506
+ }
21507
+ function resolveAgentAuthoringPath(input) {
21508
+ const candidate = resolve(input.agent);
21509
+ if (isAgentFile(candidate)) {
21510
+ return candidate;
21511
+ }
21512
+ const agentsDirectory = join3(
21513
+ input.directory ?? join3(process.cwd(), ".auto"),
21514
+ "agents"
21515
+ );
21516
+ for (const extension of AGENT_FILE_EXTENSIONS) {
21517
+ const path2 = join3(agentsDirectory, `${input.agent}${extension}`);
21518
+ if (isAgentFile(path2)) {
21519
+ return path2;
21520
+ }
21521
+ }
21522
+ throw new Error(
21523
+ `Agent authoring file not found for "${input.agent}" under ${agentsDirectory}`
21524
+ );
21525
+ }
21526
+ function discoverImports(document, path2, stack, imported) {
21527
+ const resolvedPath = resolve(path2);
21528
+ if (stack.includes(resolvedPath)) {
21529
+ throw new Error(
21530
+ `Agent import cycle detected: ${[...stack, resolvedPath].join(" -> ")}`
21531
+ );
21532
+ }
21533
+ if (!isRecord2(document)) {
21534
+ return;
21535
+ }
21536
+ for (const importPath of importPaths(document)) {
21537
+ const resolvedImport = resolveImportPath(importPath, resolvedPath);
21538
+ imported.add(resolvedImport);
21539
+ discoverImports(
21540
+ readSingleDocument(resolvedImport),
21541
+ resolvedImport,
21542
+ [...stack, resolvedPath],
21543
+ imported
21544
+ );
21545
+ }
21546
+ }
21547
+ function compileAgentDocument(document, path2, stack, context) {
21548
+ const resolvedPath = resolve(path2);
21549
+ if (stack.includes(resolvedPath)) {
21550
+ throw new Error(
21551
+ `Agent import cycle detected: ${[...stack, resolvedPath].join(" -> ")}`
21552
+ );
21553
+ }
21554
+ if (!isRecord2(document)) {
21555
+ throw new Error(`Invalid agent authoring file ${path2}: expected object`);
21556
+ }
21557
+ const imports = importPaths(document).map(
21558
+ (importPath) => resolveImportPath(importPath, resolvedPath)
21559
+ );
21560
+ context.graph.set(resolvedPath, { path: resolvedPath, imports });
21561
+ let merged = {};
21562
+ for (const imported of imports) {
21563
+ const importedDocument = readSingleDocument(imported);
21564
+ merged = mergeValues2(
21565
+ merged,
21566
+ compileAgentDocument(
21567
+ importedDocument,
21568
+ imported,
21569
+ [...stack, resolvedPath],
21570
+ context
21571
+ ),
21572
+ []
21573
+ );
21574
+ }
21575
+ const removals = removalDirectives(document, resolvedPath);
21576
+ for (const removal of removals) {
21577
+ merged = applyRemoval(merged, removal);
21578
+ context.removals.push(removal);
21579
+ }
21580
+ return mergeValues2(merged, sanitizedAgentDocument(document), []);
21581
+ }
21582
+ function readSingleDocument(path2) {
21583
+ const documents = readDocuments(path2);
21584
+ if (documents.length !== 1) {
21585
+ throw new Error(
21586
+ `Agent authoring file ${path2} must contain exactly one document`
21587
+ );
21588
+ }
21589
+ return documents[0];
21590
+ }
21591
+ function readDocuments(path2) {
21592
+ const source = readFileSync3(path2, "utf8");
21593
+ return parseYamlDocuments(source).filter((document) => document.contents !== null).map((document) => document.toJSON());
21594
+ }
21595
+ function importPaths(document) {
21596
+ const value = document.imports ?? document.import;
21597
+ if (value === void 0) {
21598
+ return [];
21599
+ }
21600
+ const values = Array.isArray(value) ? value : [value];
21601
+ return values.map((item) => {
21602
+ if (typeof item !== "string" || item.trim().length === 0) {
21603
+ throw new Error("Agent imports must be non-empty string paths");
21604
+ }
21605
+ return item.trim();
21606
+ });
21607
+ }
21608
+ function resolveImportPath(importPath, importerPath) {
21609
+ if (isAbsolute(importPath) || /^[A-Za-z]+:\/\//.test(importPath)) {
21610
+ throw new Error(`Agent import must be a relative path: ${importPath}`);
21611
+ }
21612
+ const resolved = resolve(dirname4(importerPath), importPath);
21613
+ if (!isAgentFile(resolved)) {
21614
+ throw new Error(
21615
+ `Agent import not found: ${importPath} from ${importerPath}`
21616
+ );
21617
+ }
21618
+ return resolved;
21619
+ }
21620
+ function sanitizedAgentDocument(document) {
21621
+ const next = { ...document };
21622
+ delete next.import;
21623
+ delete next.imports;
21624
+ delete next.remove;
21625
+ if (isRecord2(next.spec) && "remove" in next.spec) {
21626
+ const spec = { ...next.spec };
21627
+ delete spec.remove;
21628
+ next.spec = spec;
21629
+ }
21630
+ return next;
21631
+ }
21632
+ function normalizeAgentDocument(document) {
21633
+ if (!isRecord2(document) || "kind" in document) {
21634
+ return document;
21635
+ }
21636
+ return { ...document, kind: RESOURCE_KIND_SESSION };
21637
+ }
21638
+ function removalDirectives(document, path2) {
21639
+ const raw = mergeValues2(
21640
+ isRecord2(document.remove) ? document.remove : {},
21641
+ isRecord2(document.spec) && isRecord2(document.spec.remove) ? document.spec.remove : {},
21642
+ []
21643
+ );
21644
+ if (!isRecord2(raw)) {
21645
+ return [];
21646
+ }
21647
+ const directives = [];
21648
+ for (const [target, value] of Object.entries(raw)) {
21649
+ const names = stringList(value, `remove.${target}`);
21650
+ if (names.length > 0) {
21651
+ directives.push({ path: path2, target, names });
21652
+ }
21653
+ }
21654
+ return directives;
21655
+ }
21656
+ function stringList(value, label) {
21657
+ const values = Array.isArray(value) ? value : [value];
21658
+ return values.map((item) => {
21659
+ if (typeof item !== "string" || item.trim().length === 0) {
21660
+ throw new Error(`${label} entries must be non-empty strings`);
21661
+ }
21662
+ return item.trim();
21663
+ });
21664
+ }
21665
+ function applyRemoval(value, removal) {
21666
+ if (!isRecord2(value)) {
21667
+ return value;
21668
+ }
21669
+ const next = structuredClone(value);
21670
+ if (!isRecord2(next.spec)) {
21671
+ return next;
21672
+ }
21673
+ const spec = { ...next.spec };
21674
+ next.spec = spec;
21675
+ switch (removal.target) {
21676
+ case "tools":
21677
+ case "env": {
21678
+ if (!isRecord2(spec[removal.target])) {
21679
+ return next;
21680
+ }
21681
+ const collection = {
21682
+ ...spec[removal.target]
21683
+ };
21684
+ for (const name of removal.names) {
21685
+ delete collection[name];
21686
+ }
21687
+ spec[removal.target] = collection;
21688
+ return next;
21689
+ }
21690
+ case "mounts":
21691
+ case "triggers": {
21692
+ const value2 = spec[removal.target];
21693
+ if (!Array.isArray(value2)) {
21694
+ return next;
21695
+ }
21696
+ const collection = value2;
21697
+ spec[removal.target] = collection.filter(
21698
+ (item) => !removal.names.includes(
21699
+ collectionItemKey(removal.target, item) ?? ""
21700
+ )
21701
+ );
21702
+ return next;
21703
+ }
21704
+ default:
21705
+ throw new Error(
21706
+ `Unsupported agent remove target "${removal.target}"; supported targets are tools, env, mounts, triggers`
21707
+ );
21708
+ }
21709
+ }
21710
+ function mergeValues2(base, override, path2) {
21711
+ if (override === void 0) {
21712
+ return base;
21713
+ }
21714
+ if (Array.isArray(base) && Array.isArray(override)) {
21715
+ return mergeArrays(base, override, path2);
21716
+ }
21717
+ if (isRecord2(base) && isRecord2(override)) {
21718
+ const merged = { ...base };
21719
+ for (const [key, value] of Object.entries(override)) {
21720
+ merged[key] = mergeValues2(merged[key], value, [...path2, key]);
21721
+ }
21722
+ return merged;
21723
+ }
21724
+ return override;
21725
+ }
21726
+ function mergeArrays(base, override, path2) {
21727
+ const pathKey = path2.join(".");
21728
+ if (pathKey !== "spec.mounts" && pathKey !== "spec.triggers") {
21729
+ return [...base, ...override];
21730
+ }
21731
+ const merged = [...base];
21732
+ const indexByKey = /* @__PURE__ */ new Map();
21733
+ for (const [index, item] of merged.entries()) {
21734
+ const key = collectionItemKey(path2.at(-1) ?? "", item);
21735
+ if (key) {
21736
+ indexByKey.set(key, index);
21737
+ }
21738
+ }
21739
+ for (const item of override) {
21740
+ const key = collectionItemKey(path2.at(-1) ?? "", item);
21741
+ if (key && indexByKey.has(key)) {
21742
+ merged[indexByKey.get(key) ?? 0] = mergeValues2(
21743
+ merged[indexByKey.get(key) ?? 0],
21744
+ item,
21745
+ path2
21746
+ );
21747
+ continue;
21748
+ }
21749
+ if (key) {
21750
+ indexByKey.set(key, merged.length);
21751
+ }
21752
+ merged.push(item);
21753
+ }
21754
+ return merged;
21755
+ }
21756
+ function collectionItemKey(collection, item) {
21757
+ if (!isRecord2(item)) {
21758
+ return void 0;
21759
+ }
21760
+ if (typeof item.name === "string") {
21761
+ return item.name;
21762
+ }
21763
+ if (collection === "mounts" && typeof item.mountPath === "string") {
21764
+ return item.mountPath;
21765
+ }
21766
+ if (collection === "triggers") {
21767
+ if (typeof item.event === "string") {
21768
+ return item.event;
21769
+ }
21770
+ if (Array.isArray(item.events)) {
21771
+ return item.events.filter((event) => typeof event === "string").join(",");
21772
+ }
21773
+ if (typeof item.cron === "string") {
21774
+ return `cron:${item.cron}:${typeof item.timezone === "string" ? item.timezone : ""}`;
21775
+ }
21776
+ }
21777
+ return void 0;
21778
+ }
21779
+ function importedEdgeCount(graph) {
21780
+ return graph.reduce((count, node) => count + node.imports.length, 0);
21781
+ }
21782
+ function isAgentFile(path2) {
21783
+ try {
21784
+ return statSync(path2).isFile();
21785
+ } catch {
21786
+ return false;
21787
+ }
21788
+ }
21789
+ function isRecord2(value) {
21790
+ return typeof value === "object" && value !== null && !Array.isArray(value);
21791
+ }
21792
+ var AGENT_FILE_EXTENSIONS;
21793
+ var init_authoring = __esm({
21794
+ "src/commands/agents/authoring.ts"() {
21795
+ "use strict";
21796
+ init_src();
21797
+ AGENT_FILE_EXTENSIONS = [".yaml", ".yml", ".json"];
21798
+ }
21799
+ });
21800
+
21801
+ // src/commands/apply/files.ts
21802
+ import { createHash as createHash3 } from "crypto";
21803
+ import {
21804
+ readFileSync as readFileSync4,
21805
+ readdirSync as readdirSync3,
21806
+ realpathSync,
21807
+ statSync as statSync2
21808
+ } from "fs";
21809
+ import {
21810
+ basename as basename3,
21811
+ dirname as dirname5,
21812
+ extname as extname2,
21813
+ isAbsolute as isAbsolute2,
21814
+ join as join4,
21815
+ resolve as resolve2
21816
+ } from "path";
21817
+ import { parseAllDocuments as parseYamlDocuments2 } from "yaml";
21395
21818
  function readProjectApplyRequest(options) {
21396
21819
  if (options.file && options.directory) {
21397
21820
  throw new Error("Cannot use --file with --directory.");
@@ -21404,7 +21827,7 @@ function readProjectApplyRequest(options) {
21404
21827
  );
21405
21828
  return { ...request, assets: assets2 };
21406
21829
  }
21407
- const directory = options.directory ?? join3(process.cwd(), ".auto");
21830
+ const directory = options.directory ?? join4(process.cwd(), ".auto");
21408
21831
  const files = applyFiles(directory);
21409
21832
  if (files.length === 0) {
21410
21833
  throw new Error(`No resource files found in ${directory}`);
@@ -21456,24 +21879,30 @@ function mcpOAuthSessionToolConnectionsFromAppliedResources(resources) {
21456
21879
  function applyFiles(root) {
21457
21880
  const files = [];
21458
21881
  for (const kind of PROJECT_RESOURCE_APPLY_ORDER) {
21882
+ const kindFiles = [];
21459
21883
  for (const directory of applyDirectories(kind)) {
21460
- const path2 = join3(root, directory);
21884
+ const path2 = join4(root, directory);
21461
21885
  let entries;
21462
21886
  try {
21463
- entries = readdirSync2(path2, { withFileTypes: true });
21887
+ entries = readdirSync3(path2, { withFileTypes: true });
21464
21888
  } catch {
21465
21889
  continue;
21466
21890
  }
21467
- files.push(
21468
- ...resourceApplyFiles(path2, entries).map((file2) => ({
21469
- kind,
21470
- path: file2
21471
- }))
21472
- );
21891
+ kindFiles.push(...resourceApplyFiles(path2, entries));
21473
21892
  }
21893
+ const importedFiles = kind === RESOURCE_KIND_SESSION ? importedAgentAuthoringPaths(kindFiles) : /* @__PURE__ */ new Set();
21894
+ const appliedFiles = kind === RESOURCE_KIND_SESSION ? kindFiles.filter(
21895
+ (path2) => !importedFiles.has(resolve2(path2)) && !isSharedAgentAuthoringFile(root, path2)
21896
+ ) : kindFiles;
21897
+ files.push(...appliedFiles.map((path2) => ({ kind, path: path2 })));
21474
21898
  }
21475
21899
  return files;
21476
21900
  }
21901
+ function isSharedAgentAuthoringFile(root, path2) {
21902
+ const agentsSharedRoot = resolve2(root, "agents", "shared");
21903
+ const resolvedPath = resolve2(path2);
21904
+ return resolvedPath.startsWith(`${agentsSharedRoot}/`);
21905
+ }
21477
21906
  function mcpOAuthSessionToolConnectionsFromSessionTools(input) {
21478
21907
  return Object.entries(input.tools).flatMap(([alias, tool]) => {
21479
21908
  if (tool.kind !== "mcp_remote" || tool.disabled || tool.auth.kind !== "mcp_oauth") {
@@ -21489,10 +21918,10 @@ function mcpOAuthSessionToolConnectionsFromSessionTools(input) {
21489
21918
  });
21490
21919
  }
21491
21920
  function readApplyDocumentFile(path2) {
21492
- const source = readFileSync3(path2, "utf8");
21921
+ const source = readFileSync4(path2, "utf8");
21493
21922
  let documents;
21494
21923
  try {
21495
- documents = parseYamlDocuments(source).filter((document) => document.contents !== null).map((document) => document.toJSON());
21924
+ documents = parseYamlDocuments2(source).filter((document) => document.contents !== null).map((document) => document.toJSON());
21496
21925
  } catch (error51) {
21497
21926
  throw new Error(
21498
21927
  `Invalid apply file: ${error51 instanceof Error ? error51.message : String(error51)}`
@@ -21511,12 +21940,15 @@ function readApplyDocumentFile(path2) {
21511
21940
  delete: [],
21512
21941
  dryRun: false,
21513
21942
  prune: false,
21514
- resources: documents.map(readApplyDocument),
21943
+ resources: documents.map((document) => readApplyDocument(document, path2)),
21515
21944
  assets: {}
21516
21945
  };
21517
21946
  }
21518
- function readApplyDocument(document) {
21947
+ function readApplyDocument(document, path2) {
21519
21948
  const candidate = applyCandidate(document);
21949
+ if (candidate.kind === RESOURCE_KIND_SESSION) {
21950
+ return compileAgentDocumentValue(document, path2).resource;
21951
+ }
21520
21952
  const parsed = APPLY_SCHEMAS[candidate.kind].safeParse(candidate.value);
21521
21953
  if (!parsed.success) {
21522
21954
  throw new Error(
@@ -21541,7 +21973,7 @@ function readApplyAssets(resources, projectRoot) {
21541
21973
  resourceName: target.resourceName,
21542
21974
  projectRoot
21543
21975
  });
21544
- const bytes = readFileSync3(resolvedPath);
21976
+ const bytes = readFileSync4(resolvedPath);
21545
21977
  const dimensionsProblem = avatarAssetDimensionsProblem(bytes);
21546
21978
  if (dimensionsProblem) {
21547
21979
  throw new Error(
@@ -21550,7 +21982,7 @@ function readApplyAssets(resources, projectRoot) {
21550
21982
  }
21551
21983
  assets[target.asset] = {
21552
21984
  sha256: createHash3("sha256").update(bytes).digest("hex"),
21553
- contentType: extname(resolvedPath).toLowerCase() === ".png" ? "image/png" : "image/jpeg",
21985
+ contentType: extname2(resolvedPath).toLowerCase() === ".png" ? "image/png" : "image/jpeg",
21554
21986
  dataBase64: bytes.toString("base64")
21555
21987
  };
21556
21988
  }
@@ -21568,7 +22000,7 @@ function avatarAssetTarget(resource) {
21568
22000
  return void 0;
21569
22001
  }
21570
22002
  function validateSessionAvatarAsset(input) {
21571
- if (isAbsolute(input.asset)) {
22003
+ if (isAbsolute2(input.asset)) {
21572
22004
  throw new Error(
21573
22005
  `Invalid identity avatar asset for "${input.resourceName}": asset path must be relative`
21574
22006
  );
@@ -21580,10 +22012,10 @@ function validateSessionAvatarAsset(input) {
21580
22012
  );
21581
22013
  }
21582
22014
  const projectRoot = realpathSync(input.projectRoot);
21583
- const assetPath = resolve(projectRoot, input.asset);
22015
+ const assetPath = resolve2(projectRoot, input.asset);
21584
22016
  let assetsRoot;
21585
22017
  try {
21586
- assetsRoot = realpathSync(resolve(projectRoot, ".auto", "assets"));
22018
+ assetsRoot = realpathSync(resolve2(projectRoot, ".auto", "assets"));
21587
22019
  } catch {
21588
22020
  throw new Error(
21589
22021
  `Invalid identity avatar asset for "${input.resourceName}": .auto/assets directory does not exist`
@@ -21593,7 +22025,7 @@ function validateSessionAvatarAsset(input) {
21593
22025
  let stat;
21594
22026
  try {
21595
22027
  resolvedAssetPath = realpathSync(assetPath);
21596
- stat = statSync(resolvedAssetPath);
22028
+ stat = statSync2(resolvedAssetPath);
21597
22029
  } catch {
21598
22030
  throw new Error(
21599
22031
  `Invalid identity avatar asset for "${input.resourceName}": ${input.asset} does not exist`
@@ -21614,7 +22046,7 @@ function validateSessionAvatarAsset(input) {
21614
22046
  `Invalid identity avatar asset for "${input.resourceName}": asset must be ${MAX_AVATAR_ASSET_BYTES} bytes or smaller`
21615
22047
  );
21616
22048
  }
21617
- const extension = extname(resolvedAssetPath).toLowerCase();
22049
+ const extension = extname2(resolvedAssetPath).toLowerCase();
21618
22050
  if (!ALLOWED_AVATAR_EXTENSIONS.has(extension)) {
21619
22051
  throw new Error(
21620
22052
  `Invalid identity avatar asset for "${input.resourceName}": asset must be a PNG or JPEG image`
@@ -21623,16 +22055,16 @@ function validateSessionAvatarAsset(input) {
21623
22055
  return resolvedAssetPath;
21624
22056
  }
21625
22057
  function applyProjectRoot(directory) {
21626
- const resolved = resolve(directory);
21627
- return basename2(resolved) === ".auto" ? dirname4(resolved) : resolved;
22058
+ const resolved = resolve2(directory);
22059
+ return basename3(resolved) === ".auto" ? dirname5(resolved) : resolved;
21628
22060
  }
21629
22061
  function applyFileProjectRoot(file2) {
21630
- let dir = dirname4(resolve(file2));
22062
+ let dir = dirname5(resolve2(file2));
21631
22063
  while (true) {
21632
- if (basename2(dir) === ".auto") {
21633
- return dirname4(dir);
22064
+ if (basename3(dir) === ".auto") {
22065
+ return dirname5(dir);
21634
22066
  }
21635
- const parent = dirname4(dir);
22067
+ const parent = dirname5(dir);
21636
22068
  if (parent === dir) {
21637
22069
  return process.cwd();
21638
22070
  }
@@ -21643,7 +22075,7 @@ function isInside(path2, parent) {
21643
22075
  return path2.startsWith(`${parent}/`);
21644
22076
  }
21645
22077
  function applyCandidate(document) {
21646
- if (!isRecord2(document) || !("kind" in document)) {
22078
+ if (!isRecord3(document) || !("kind" in document)) {
21647
22079
  return { kind: RESOURCE_KIND_SESSION, value: document };
21648
22080
  }
21649
22081
  if (document.kind === LEGACY_RESOURCE_KIND_SESSION) {
@@ -21675,16 +22107,16 @@ function applyDirectories(kind) {
21675
22107
  function primaryApplyDirectory(kind) {
21676
22108
  return APPLY_DIRECTORIES[kind];
21677
22109
  }
21678
- function isRecord2(value) {
22110
+ function isRecord3(value) {
21679
22111
  return typeof value === "object" && value !== null && !Array.isArray(value);
21680
22112
  }
21681
22113
  function resourceApplyFiles(directory, entries) {
21682
22114
  const files = [];
21683
22115
  for (const entry of entries) {
21684
- const path2 = join3(directory, entry.name);
22116
+ const path2 = join4(directory, entry.name);
21685
22117
  if (entry.isDirectory()) {
21686
22118
  files.push(
21687
- ...resourceApplyFiles(path2, readdirSync2(path2, { withFileTypes: true }))
22119
+ ...resourceApplyFiles(path2, readdirSync3(path2, { withFileTypes: true }))
21688
22120
  );
21689
22121
  continue;
21690
22122
  }
@@ -21699,6 +22131,7 @@ var init_files = __esm({
21699
22131
  "src/commands/apply/files.ts"() {
21700
22132
  "use strict";
21701
22133
  init_src();
22134
+ init_authoring();
21702
22135
  APPLY_DIRECTORIES = {
21703
22136
  environment: "environments",
21704
22137
  identity: "identities",
@@ -22083,10 +22516,10 @@ var init_resources3 = __esm({
22083
22516
 
22084
22517
  // src/commands/edit/actions.ts
22085
22518
  import { spawn as spawn2 } from "child_process";
22086
- import { mkdtempSync, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
22519
+ import { mkdtempSync, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
22087
22520
  import { tmpdir } from "os";
22088
- import { join as join4 } from "path";
22089
- import { parseAllDocuments as parseYamlDocuments2, stringify as stringify2 } from "yaml";
22521
+ import { join as join5 } from "path";
22522
+ import { parseAllDocuments as parseYamlDocuments3, stringify as stringify3 } from "yaml";
22090
22523
  async function editResource(input) {
22091
22524
  const reference = parseProjectResourceReference(input.resource);
22092
22525
  const editor = resolveEditor({
@@ -22098,15 +22531,15 @@ async function editResource(input) {
22098
22531
  apiBaseUrl: input.commandOptions.apiBaseUrl
22099
22532
  });
22100
22533
  const document = editableResourceDocument(reference.kind, current);
22101
- const source = `${stringify2(document).trimEnd()}
22534
+ const source = `${stringify3(document).trimEnd()}
22102
22535
  `;
22103
- const tempRoot = mkdtempSync(join4(tmpdir(), "auto-edit-"));
22104
- const filePath = join4(tempRoot, `${reference.kind}-${reference.name}.yaml`);
22536
+ const tempRoot = mkdtempSync(join5(tmpdir(), "auto-edit-"));
22537
+ const filePath = join5(tempRoot, `${reference.kind}-${reference.name}.yaml`);
22105
22538
  writeFileSync3(filePath, source, "utf8");
22106
22539
  let removeTempFile = false;
22107
22540
  try {
22108
22541
  await runEditor(editor, filePath);
22109
- const editedSource = readFileSync4(filePath, "utf8");
22542
+ const editedSource = readFileSync5(filePath, "utf8");
22110
22543
  if (editedSource === source) {
22111
22544
  input.writeOutput("No changes; skipped apply.");
22112
22545
  removeTempFile = true;
@@ -22153,7 +22586,7 @@ function resolveEditor(input) {
22153
22586
  return input.env.VISUAL?.trim() || input.env.EDITOR?.trim() || "vi";
22154
22587
  }
22155
22588
  async function runEditor(editor, filePath) {
22156
- await new Promise((resolve2, reject) => {
22589
+ await new Promise((resolve3, reject) => {
22157
22590
  const child = spawn2(editor, [filePath], {
22158
22591
  shell: true,
22159
22592
  stdio: "inherit"
@@ -22165,7 +22598,7 @@ async function runEditor(editor, filePath) {
22165
22598
  });
22166
22599
  child.on("close", (code, signal) => {
22167
22600
  if (code === 0) {
22168
- resolve2();
22601
+ resolve3();
22169
22602
  return;
22170
22603
  }
22171
22604
  if (signal) {
@@ -22177,10 +22610,10 @@ async function runEditor(editor, filePath) {
22177
22610
  });
22178
22611
  }
22179
22612
  function readEditedResource(filePath, expected) {
22180
- const source = readFileSync4(filePath, "utf8");
22613
+ const source = readFileSync5(filePath, "utf8");
22181
22614
  let documents;
22182
22615
  try {
22183
- documents = parseYamlDocuments2(source).filter((document) => document.contents !== null).map((document) => document.toJSON());
22616
+ documents = parseYamlDocuments3(source).filter((document) => document.contents !== null).map((document) => document.toJSON());
22184
22617
  } catch (error51) {
22185
22618
  throw new Error(
22186
22619
  `Invalid edited resource: ${error51 instanceof Error ? error51.message : String(error51)}`
@@ -24106,13 +24539,13 @@ function sleep2(ms, signal) {
24106
24539
  if (signal.aborted) {
24107
24540
  return Promise.resolve();
24108
24541
  }
24109
- return new Promise((resolve2) => {
24110
- const timeout = setTimeout(resolve2, ms);
24542
+ return new Promise((resolve3) => {
24543
+ const timeout = setTimeout(resolve3, ms);
24111
24544
  signal.addEventListener(
24112
24545
  "abort",
24113
24546
  () => {
24114
24547
  clearTimeout(timeout);
24115
- resolve2();
24548
+ resolve3();
24116
24549
  },
24117
24550
  { once: true }
24118
24551
  );
@@ -25300,20 +25733,25 @@ var init_RunsView = __esm({
25300
25733
  // src/tui/SessionsView.tsx
25301
25734
  import { Box as Box11, Text as Text12, useStdout as useStdout6 } from "ink";
25302
25735
  import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
25303
- function SessionsView({ sessions, selectedIndex, error: error51 }) {
25736
+ function SessionsView({
25737
+ sessions,
25738
+ selectedIndex,
25739
+ error: error51,
25740
+ authoringStatuses
25741
+ }) {
25304
25742
  const { stdout } = useStdout6();
25305
25743
  const termWidth = stdout?.columns ?? 120;
25306
25744
  const numCols = 4;
25307
25745
  const gapTotal = (numCols - 1) * TABLE_GAP;
25308
25746
  const descriptionWidth = Math.max(
25309
25747
  24,
25310
- termWidth - TABLE_PADDING_X * 2 - COL_NAME2 - COL_RUNS - COL_UPDATED2 - gapTotal
25748
+ termWidth - TABLE_PADDING_X * 2 - COL_NAME2 - COL_AUTHORING - COL_UPDATED2 - gapTotal
25311
25749
  );
25312
25750
  return /* @__PURE__ */ jsxs10(Box11, { flexDirection: "column", flexGrow: 1, children: [
25313
25751
  /* @__PURE__ */ jsxs10(Box11, { paddingX: TABLE_PADDING_X, paddingBottom: 1, gap: TABLE_GAP, children: [
25314
25752
  /* @__PURE__ */ jsx12(HeaderCell, { width: COL_NAME2, children: "NAME\u2191" }),
25315
- /* @__PURE__ */ jsx12(HeaderCell, { width: descriptionWidth, children: "DESCRIPTION" }),
25316
- /* @__PURE__ */ jsx12(HeaderCell, { width: COL_RUNS, justifyContent: "flex-end", children: "RUNS" }),
25753
+ /* @__PURE__ */ jsx12(HeaderCell, { width: descriptionWidth, children: "CONFIG" }),
25754
+ /* @__PURE__ */ jsx12(HeaderCell, { width: COL_AUTHORING, justifyContent: "flex-end", children: "AUTHORING" }),
25317
25755
  /* @__PURE__ */ jsx12(HeaderCell, { width: COL_UPDATED2, justifyContent: "flex-end", children: "UPDATED" })
25318
25756
  ] }),
25319
25757
  error51 ? /* @__PURE__ */ jsx12(Box11, { paddingX: 2, children: /* @__PURE__ */ jsxs10(Text12, { color: "red", children: [
@@ -25325,7 +25763,9 @@ function SessionsView({ sessions, selectedIndex, error: error51 }) {
25325
25763
  ] }) }) : sessions.map((session, i) => {
25326
25764
  const isSelected = i === selectedIndex;
25327
25765
  const updated = relativeTime3(session.metadata.updatedAt);
25328
- const runCount = session.status.runCount.toString();
25766
+ const authoring = sessionAuthoringLabel(
25767
+ authoringStatuses?.get(session.metadata.name)
25768
+ );
25329
25769
  return /* @__PURE__ */ jsxs10(TableRow, { selected: isSelected, children: [
25330
25770
  /* @__PURE__ */ jsx12(
25331
25771
  TableCell,
@@ -25344,17 +25784,17 @@ function SessionsView({ sessions, selectedIndex, error: error51 }) {
25344
25784
  width: descriptionWidth,
25345
25785
  selected: isSelected,
25346
25786
  dim: !isSelected,
25347
- children: "<todo fill in>"
25787
+ children: sessionConfigLabel(session)
25348
25788
  }
25349
25789
  ),
25350
25790
  /* @__PURE__ */ jsx12(
25351
25791
  TableCell,
25352
25792
  {
25353
- width: COL_RUNS,
25793
+ width: COL_AUTHORING,
25354
25794
  selected: isSelected,
25355
25795
  dim: !isSelected,
25356
25796
  justifyContent: "flex-end",
25357
- children: runCount
25797
+ children: authoring
25358
25798
  }
25359
25799
  ),
25360
25800
  /* @__PURE__ */ jsx12(
@@ -25371,6 +25811,26 @@ function SessionsView({ sessions, selectedIndex, error: error51 }) {
25371
25811
  })
25372
25812
  ] });
25373
25813
  }
25814
+ function sessionConfigLabel(session) {
25815
+ const pieces = [
25816
+ session.spec.harness,
25817
+ session.spec.environment ? `env:${session.spec.environment}` : void 0,
25818
+ `${session.status.runCount} runs`
25819
+ ].filter(Boolean);
25820
+ return pieces.join(" ");
25821
+ }
25822
+ function sessionAuthoringLabel(status) {
25823
+ if (!status) {
25824
+ return "remote";
25825
+ }
25826
+ if (!status.ok) {
25827
+ return "error";
25828
+ }
25829
+ if (status.imports === 0 && status.removals === 0) {
25830
+ return "local ok";
25831
+ }
25832
+ return `ok i${status.imports}/r${status.removals}`;
25833
+ }
25374
25834
  function relativeTime3(dateStr) {
25375
25835
  const ms = Date.now() - new Date(dateStr).getTime();
25376
25836
  const s = Math.floor(ms / 1e3);
@@ -25382,12 +25842,12 @@ function relativeTime3(dateStr) {
25382
25842
  const d = Math.floor(h / 24);
25383
25843
  return `${d}d ago`;
25384
25844
  }
25385
- var COL_RUNS, COL_UPDATED2, COL_NAME2;
25845
+ var COL_AUTHORING, COL_UPDATED2, COL_NAME2;
25386
25846
  var init_SessionsView = __esm({
25387
25847
  "src/tui/SessionsView.tsx"() {
25388
25848
  "use strict";
25389
25849
  init_Table();
25390
- COL_RUNS = 6;
25850
+ COL_AUTHORING = 16;
25391
25851
  COL_UPDATED2 = 10;
25392
25852
  COL_NAME2 = 28;
25393
25853
  }
@@ -25395,7 +25855,7 @@ var init_SessionsView = __esm({
25395
25855
 
25396
25856
  // src/tui/SpecInspector.tsx
25397
25857
  import { Box as Box12, Text as Text13 } from "ink";
25398
- import { stringify as stringify4 } from "yaml";
25858
+ import { stringify as stringify6 } from "yaml";
25399
25859
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
25400
25860
  function SpecInspector({
25401
25861
  kind,
@@ -25426,7 +25886,7 @@ function specLineCount(spec) {
25426
25886
  return yamlLines(spec).length;
25427
25887
  }
25428
25888
  function yamlLines(spec) {
25429
- return stringify4(spec).trimEnd().split("\n");
25889
+ return stringify6(spec).trimEnd().split("\n");
25430
25890
  }
25431
25891
  function YamlLine({ line }) {
25432
25892
  const match = /^(\s*)([^:#][^:]*:)(.*)$/.exec(line);
@@ -25513,6 +25973,15 @@ function selectedNamedResourceForSection(input) {
25513
25973
  return null;
25514
25974
  }
25515
25975
  }
25976
+ function agentAuthoringHeaderLabel(status) {
25977
+ if (!status.ok) {
25978
+ return "error";
25979
+ }
25980
+ if (status.imports === 0 && status.removals === 0) {
25981
+ return "local ok";
25982
+ }
25983
+ return `local ok, ${status.imports} imports, ${status.removals} removals`;
25984
+ }
25516
25985
  function editableResourceForSelection(input) {
25517
25986
  if (!isApplyResourceSection(input.activeSection)) {
25518
25987
  return null;
@@ -25571,6 +26040,15 @@ function HomeView({ apiUrl, notice, returnToSession }) {
25571
26040
  const [serviceAccountNameInput, setServiceAccountNameInput] = useState3("");
25572
26041
  const [inspectedResource, setInspectedResource] = useState3(null);
25573
26042
  const [inspectScrollOffset, setInspectScrollOffset] = useState3(0);
26043
+ const localAgentAuthoringStatuses = useMemo3(
26044
+ () => new Map(
26045
+ readLocalAgentAuthoringStatuses().map((status) => [
26046
+ status.name,
26047
+ status
26048
+ ])
26049
+ ),
26050
+ []
26051
+ );
25574
26052
  const activeSelectionIds = client.getActiveSelection();
25575
26053
  const {
25576
26054
  data: sessions = [],
@@ -25673,6 +26151,7 @@ function HomeView({ apiUrl, notice, returnToSession }) {
25673
26151
  const selectedConnectionProvider = providerRows2(connectionProviders)[connectionProviderIndex];
25674
26152
  const selectedServiceAccount = serviceAccounts[serviceAccountIndex];
25675
26153
  const selectedSession = sessions[sessionIndex];
26154
+ const selectedAgentAuthoringStatus = selectedSession ? localAgentAuthoringStatuses.get(selectedSession.metadata.name) : void 0;
25676
26155
  const selectedEnvironment = environments[environmentIndex];
25677
26156
  const selectedIdentity = identities[identityIndex];
25678
26157
  const selectedInspectableResource = useMemo3(() => {
@@ -26620,6 +27099,14 @@ function HomeView({ apiUrl, notice, returnToSession }) {
26620
27099
  activeProject && /* @__PURE__ */ jsx14(KV, { label: "Project", value: activeProject.projectName }),
26621
27100
  activeProject && /* @__PURE__ */ jsx14(KV, { label: "Role", value: activeProject.role }),
26622
27101
  selectedSession && /* @__PURE__ */ jsx14(KV, { label: "Agent", value: selectedSession.metadata.name }),
27102
+ selectedAgentAuthoringStatus && /* @__PURE__ */ jsx14(
27103
+ KV,
27104
+ {
27105
+ label: "Authoring",
27106
+ value: agentAuthoringHeaderLabel(selectedAgentAuthoringStatus),
27107
+ color: selectedAgentAuthoringStatus.ok ? void 0 : "red"
27108
+ }
27109
+ ),
26623
27110
  runError && /* @__PURE__ */ jsx14(KV, { label: "Error", value: runError, color: "red" }),
26624
27111
  isRunMutationPending && /* @__PURE__ */ jsx14(
26625
27112
  KV,
@@ -26768,7 +27255,8 @@ function HomeView({ apiUrl, notice, returnToSession }) {
26768
27255
  {
26769
27256
  sessions,
26770
27257
  selectedIndex: sessionIndex,
26771
- error: sessionsErrorMessage
27258
+ error: sessionsErrorMessage,
27259
+ authoringStatuses: localAgentAuthoringStatuses
26772
27260
  }
26773
27261
  ) : activeSection === "serviceAccounts" ? isServiceAccountsLoading ? /* @__PURE__ */ jsx14(Box13, { padding: 2, children: /* @__PURE__ */ jsx14(Spinner, { label: "loading service accounts\u2026" }) }) : /* @__PURE__ */ jsxs12(Box13, { flexDirection: "column", flexGrow: 1, children: [
26774
27262
  serviceAccountInputMode === "create" && /* @__PURE__ */ jsxs12(Box13, { paddingX: 2, gap: 1, children: [
@@ -27087,6 +27575,7 @@ var init_HomeView = __esm({
27087
27575
  "src/tui/HomeView.tsx"() {
27088
27576
  "use strict";
27089
27577
  init_src();
27578
+ init_authoring();
27090
27579
  init_login();
27091
27580
  init_base_url();
27092
27581
  init_browser();
@@ -27794,8 +28283,8 @@ async function startGitCredentialRelay(input) {
27794
28283
  update: (next) => {
27795
28284
  target = { url: next.url, accessToken: next.accessToken };
27796
28285
  },
27797
- close: () => new Promise((resolve2) => {
27798
- server.close(() => resolve2());
28286
+ close: () => new Promise((resolve3) => {
28287
+ server.close(() => resolve3());
27799
28288
  })
27800
28289
  };
27801
28290
  }
@@ -28218,12 +28707,12 @@ async function runAgentBridgeSocket(options) {
28218
28707
  let handler = null;
28219
28708
  const reconnectLoop = createReconnectLoop(socket);
28220
28709
  let hasConnected = false;
28221
- await new Promise((resolve2, reject) => {
28710
+ await new Promise((resolve3, reject) => {
28222
28711
  const shutdown = () => {
28223
28712
  reconnectLoop.stop();
28224
28713
  handler?.shutdown?.();
28225
28714
  socket.disconnect();
28226
- resolve2();
28715
+ resolve3();
28227
28716
  };
28228
28717
  process.once("SIGINT", shutdown);
28229
28718
  process.once("SIGTERM", shutdown);
@@ -28406,7 +28895,7 @@ function createRuntimeBridgeBootstrapListener(input) {
28406
28895
  };
28407
28896
  }
28408
28897
  function emitOutputWithAck(socket, output) {
28409
- return new Promise((resolve2, reject) => {
28898
+ return new Promise((resolve3, reject) => {
28410
28899
  socket.timeout(5e3).emit(
28411
28900
  RUNTIME_BRIDGE_OUTPUT_EVENT,
28412
28901
  output,
@@ -28426,7 +28915,7 @@ function emitOutputWithAck(socket, output) {
28426
28915
  );
28427
28916
  return;
28428
28917
  }
28429
- resolve2(ack.data);
28918
+ resolve3(ack.data);
28430
28919
  }
28431
28920
  );
28432
28921
  });
@@ -29169,8 +29658,8 @@ var AsyncMessageQueue = class {
29169
29658
  if (this.closed) {
29170
29659
  return Promise.resolve({ done: true, value: void 0 });
29171
29660
  }
29172
- return new Promise((resolve2) => {
29173
- this.waiters.push(resolve2);
29661
+ return new Promise((resolve3) => {
29662
+ this.waiters.push(resolve3);
29174
29663
  });
29175
29664
  }
29176
29665
  };
@@ -29434,13 +29923,13 @@ var ClaudeCodeCommandHandler = class {
29434
29923
  this.input.writeOutput?.(
29435
29924
  `agent_bridge_question_pending tool_use_id=${toolUseId}`
29436
29925
  );
29437
- return new Promise((resolve2) => {
29438
- this.pendingQuestions.set(toolUseId, { input: toolInput, resolve: resolve2 });
29926
+ return new Promise((resolve3) => {
29927
+ this.pendingQuestions.set(toolUseId, { input: toolInput, resolve: resolve3 });
29439
29928
  options.signal.addEventListener(
29440
29929
  "abort",
29441
29930
  () => {
29442
29931
  if (this.pendingQuestions.delete(toolUseId)) {
29443
- resolve2({
29932
+ resolve3({
29444
29933
  behavior: "deny",
29445
29934
  message: "The question was cancelled before the user answered",
29446
29935
  toolUseID: toolUseId
@@ -30089,7 +30578,7 @@ async function activeGrantIds(input) {
30089
30578
  );
30090
30579
  }
30091
30580
  async function waitForNewGrant(input, knownGrantIds) {
30092
- const sleep3 = input.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
30581
+ const sleep3 = input.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
30093
30582
  const now3 = input.now ?? Date.now;
30094
30583
  const deadline = now3() + (input.pollTimeoutMs ?? POLL_TIMEOUT_MS);
30095
30584
  while (now3() < deadline) {
@@ -30786,13 +31275,13 @@ function registerDeleteCommands(program, context) {
30786
31275
 
30787
31276
  // src/commands/describe/actions.ts
30788
31277
  init_resources3();
30789
- import { stringify } from "yaml";
31278
+ import { stringify as stringify2 } from "yaml";
30790
31279
  async function inspectResource(input) {
30791
31280
  const request = parseProjectResourceReference(input.resource);
30792
31281
  const resource = await requireProjectResource(input.client, request, {
30793
31282
  apiBaseUrl: input.commandOptions.apiBaseUrl
30794
31283
  });
30795
- input.writeOutput(stringify(resource.spec).trimEnd());
31284
+ input.writeOutput(stringify2(resource.spec).trimEnd());
30796
31285
  }
30797
31286
 
30798
31287
  // src/commands/describe/commands.ts
@@ -31469,13 +31958,13 @@ function delay(ms, signal) {
31469
31958
  if (signal.aborted) {
31470
31959
  return Promise.resolve();
31471
31960
  }
31472
- return new Promise((resolve2) => {
31473
- const timeout = setTimeout(resolve2, ms);
31961
+ return new Promise((resolve3) => {
31962
+ const timeout = setTimeout(resolve3, ms);
31474
31963
  signal.addEventListener(
31475
31964
  "abort",
31476
31965
  () => {
31477
31966
  clearTimeout(timeout);
31478
- resolve2();
31967
+ resolve3();
31479
31968
  },
31480
31969
  { once: true }
31481
31970
  );
@@ -31500,11 +31989,11 @@ function pollUntilFailed(input) {
31500
31989
  input.abort?.addEventListener("abort", cancel, { once: true });
31501
31990
  const done = (async () => {
31502
31991
  while (!cancelled) {
31503
- await new Promise((resolve2) => {
31504
- sleepResolve = resolve2;
31992
+ await new Promise((resolve3) => {
31993
+ sleepResolve = resolve3;
31505
31994
  activeSleep = setTimeout(() => {
31506
31995
  activeSleep = void 0;
31507
- resolve2();
31996
+ resolve3();
31508
31997
  }, interval);
31509
31998
  });
31510
31999
  if (cancelled) {
@@ -31841,7 +32330,7 @@ function delay2(ms) {
31841
32330
  if (ms <= 0) {
31842
32331
  return Promise.resolve();
31843
32332
  }
31844
- return new Promise((resolve2) => setTimeout(resolve2, ms));
32333
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
31845
32334
  }
31846
32335
  function createDiagnosticCollector(limit) {
31847
32336
  const events = [];
@@ -32239,9 +32728,9 @@ function entryPreview(event, full) {
32239
32728
  case "text":
32240
32729
  return part.text;
32241
32730
  case "tool_call":
32242
- return `${part.name} ${stringify3(part.input)}`;
32731
+ return `${part.name} ${stringify4(part.input)}`;
32243
32732
  case "tool_result":
32244
- return stringify3(part.output);
32733
+ return stringify4(part.output);
32245
32734
  case "question":
32246
32735
  return part.questions.map((question) => question.question).join(" ");
32247
32736
  default:
@@ -32252,9 +32741,9 @@ function entryPreview(event, full) {
32252
32741
  return full ? joined : clip(joined);
32253
32742
  }
32254
32743
  function preview(value) {
32255
- return clip(singleLine(stringify3(value)));
32744
+ return clip(singleLine(stringify4(value)));
32256
32745
  }
32257
- function stringify3(value) {
32746
+ function stringify4(value) {
32258
32747
  return typeof value === "string" ? value : JSON.stringify(value);
32259
32748
  }
32260
32749
  function singleLine(text) {
@@ -32699,12 +33188,57 @@ function withApiBaseUrl2(context, commandOptions) {
32699
33188
  };
32700
33189
  }
32701
33190
 
33191
+ // src/commands/agents/actions.ts
33192
+ init_authoring();
33193
+ import { stringify as stringify5 } from "yaml";
33194
+ function renderAgent(input) {
33195
+ const result = compileAgent(input);
33196
+ input.writeOutput(renderCompiledAgentYaml(result));
33197
+ }
33198
+ function compileAgent(input) {
33199
+ const path2 = resolveAgentAuthoringPath({
33200
+ agent: input.agent,
33201
+ directory: input.options.directory
33202
+ });
33203
+ return compileAgentFile(path2);
33204
+ }
33205
+ function compileAgentCommand(input) {
33206
+ const result = compileAgent(input);
33207
+ input.writeOutput(
33208
+ input.options.json ? JSON.stringify(result.resource) : stringify5(result.resource).trimEnd()
33209
+ );
33210
+ }
33211
+ function explainAgent(input) {
33212
+ const result = compileAgent(input);
33213
+ input.writeOutput(
33214
+ input.options.json ? JSON.stringify(result) : renderAgentExplain(result)
33215
+ );
33216
+ }
33217
+ function statusAgents(input) {
33218
+ const statuses = readLocalAgentAuthoringStatuses({
33219
+ directory: input.options.directory
33220
+ });
33221
+ if (input.options.json) {
33222
+ input.writeOutput(JSON.stringify(statuses));
33223
+ return;
33224
+ }
33225
+ if (statuses.length === 0) {
33226
+ input.writeOutput("No local agent authoring files found.");
33227
+ return;
33228
+ }
33229
+ for (const status of statuses) {
33230
+ const state = status.ok ? "ok" : "error";
33231
+ const suffix = status.ok ? `imports=${status.imports} removals=${status.removals}` : status.error;
33232
+ input.writeOutput(`${state} ${status.name} ${suffix}`);
33233
+ }
33234
+ }
33235
+
32702
33236
  // src/commands/sessions/connect.ts
32703
33237
  init_resources2();
32704
33238
  init_browser();
32705
33239
  import { existsSync as existsSync3, mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync4 } from "fs";
32706
33240
  import { homedir as homedir3, tmpdir as tmpdir2 } from "os";
32707
- import { join as join5 } from "path";
33241
+ import { join as join6 } from "path";
32708
33242
  var POLL_INTERVAL_MS2 = 2e3;
32709
33243
  var POLL_TIMEOUT_MS2 = 5 * 6e4;
32710
33244
  var SLACK_APPS_URL = "https://api.slack.com/apps";
@@ -32756,7 +33290,7 @@ async function connectSessionPresence2(input) {
32756
33290
  );
32757
33291
  return;
32758
33292
  }
32759
- const sleep3 = input.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
33293
+ const sleep3 = input.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms)));
32760
33294
  const openBrowser2 = input.openBrowser ?? openBrowser;
32761
33295
  const now3 = input.now ?? Date.now;
32762
33296
  const pollIntervalMs = input.pollIntervalMs ?? POLL_INTERVAL_MS2;
@@ -32875,7 +33409,7 @@ async function promptForIconUploads(input, options) {
32875
33409
  }
32876
33410
  }
32877
33411
  function stagedLocationLabel(stagedPath) {
32878
- return stagedPath.startsWith(`${join5(homedir3(), "Downloads")}/`) ? "Downloads" : "the printed path";
33412
+ return stagedPath.startsWith(`${join6(homedir3(), "Downloads")}/`) ? "Downloads" : "the printed path";
32879
33413
  }
32880
33414
  async function stageAvatarImage(input) {
32881
33415
  try {
@@ -32887,9 +33421,9 @@ async function stageAvatarImage(input) {
32887
33421
  }
32888
33422
  const contentType = response.headers.get("content-type") ?? "";
32889
33423
  const extension = contentType.includes("jpeg") ? ".jpg" : ".png";
32890
- const downloads = join5(homedir3(), "Downloads");
32891
- const directory = existsSync3(downloads) ? downloads : mkdtempSync2(join5(tmpdir2(), "auto-avatar-"));
32892
- const path2 = join5(directory, `${input.session}-avatar${extension}`);
33424
+ const downloads = join6(homedir3(), "Downloads");
33425
+ const directory = existsSync3(downloads) ? downloads : mkdtempSync2(join6(tmpdir2(), "auto-avatar-"));
33426
+ const path2 = join6(directory, `${input.session}-avatar${extension}`);
32893
33427
  writeFileSync4(path2, Buffer.from(await response.arrayBuffer()));
32894
33428
  return path2;
32895
33429
  } catch {
@@ -32985,6 +33519,45 @@ function registerSessionCommands(program, context) {
32985
33519
  });
32986
33520
  });
32987
33521
  const sessions = program.command("agents").alias("sessions").description("Manage Agent resources.");
33522
+ sessions.command("render").description("Render a local Agent authoring file after imports/removals.").argument("<agent>", "agent name or path").option(
33523
+ "--directory <directory>",
33524
+ "directory containing Auto resource files"
33525
+ ).action((agent, commandOptions) => {
33526
+ renderAgent({
33527
+ agent,
33528
+ options: commandOptions,
33529
+ writeOutput: context.writeOutput
33530
+ });
33531
+ });
33532
+ sessions.command("compile").description("Compile a local Agent authoring file into an apply resource.").argument("<agent>", "agent name or path").option(
33533
+ "--directory <directory>",
33534
+ "directory containing Auto resource files"
33535
+ ).option("--json", "print the compiled resource as JSON").action((agent, commandOptions) => {
33536
+ compileAgentCommand({
33537
+ agent,
33538
+ options: commandOptions,
33539
+ writeOutput: context.writeOutput
33540
+ });
33541
+ });
33542
+ sessions.command("explain").description("Explain a local Agent authoring file's import graph.").argument("<agent>", "agent name or path").option(
33543
+ "--directory <directory>",
33544
+ "directory containing Auto resource files"
33545
+ ).option("--json", "print the import graph as JSON").action((agent, commandOptions) => {
33546
+ explainAgent({
33547
+ agent,
33548
+ options: commandOptions,
33549
+ writeOutput: context.writeOutput
33550
+ });
33551
+ });
33552
+ sessions.command("status").description("Validate local Agent authoring files.").option(
33553
+ "--directory <directory>",
33554
+ "directory containing Auto resource files"
33555
+ ).option("--json", "print local authoring status as JSON").action((commandOptions) => {
33556
+ statusAgents({
33557
+ options: commandOptions,
33558
+ writeOutput: context.writeOutput
33559
+ });
33560
+ });
32988
33561
  sessions.command("connect").description(
32989
33562
  "Connect an agent's provider presence (e.g. install its Slack agent app)."
32990
33563
  ).argument("<session>", "agent resource name").option("--manual", "print authorization URLs without opening a browser").option(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.134",
3
+ "version": "0.1.135",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"