agent-yes 1.261.1 → 1.262.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.
Files changed (26) hide show
  1. package/dist/{SUPPORTED_CLIS-CUP5ABMb.js → SUPPORTED_CLIS-BFLGbQmm.js} +3 -3
  2. package/dist/{SUPPORTED_CLIS-DGlkS83_.js → SUPPORTED_CLIS-CjKxvhlh.js} +2 -2
  3. package/dist/{agentShare-tL6j9Em4.js → agentShare-LEETLOm1.js} +2 -2
  4. package/dist/{callback-JJh1_Zzp.js → callback-CB3UjryF.js} +3 -3
  5. package/dist/{callback-BfJqf5hh.js → callback-lqCCgSy1.js} +2 -2
  6. package/dist/cli.js +5 -5
  7. package/dist/index.js +2 -2
  8. package/dist/{notifyDaemon-C1HL2AKc.js → notifyDaemon-P6Q7Eo_B.js} +2 -2
  9. package/dist/{rustBinary-BBzI-0gG.js → rustBinary-_qRGhAa5.js} +2 -2
  10. package/dist/{schedule-DCR7zeRi.js → schedule-ChAdx2h6.js} +4 -4
  11. package/dist/{serve-DCPbGttS.js → serve-DhtgWGZB.js} +185 -16
  12. package/dist/{setup-DO75Uqec.js → setup-BlJRaODn.js} +2 -2
  13. package/dist/{subcommands-C5qaj8cS.js → subcommands-D6O9uRvN.js} +1 -1
  14. package/dist/{subcommands-BSdA19Nv.js → subcommands-Zk3brdKt.js} +13 -13
  15. package/dist/{terminal-CXIqdFAy.js → terminal-BVWhnQUf.js} +2 -2
  16. package/dist/trayApp-C6U7Hghi.js +5 -0
  17. package/dist/{trayApp-DO9sPIPo.js → trayApp-DtThjl0_.js} +2 -2
  18. package/dist/{ts-BeFjrOhc.js → ts-BqaOPFCQ.js} +2 -2
  19. package/dist/{versionChecker-d15cc3u7.js → versionChecker-D-WLKAN6.js} +2 -2
  20. package/dist/{widget-BFpPQNzh.js → widget-CJyd9t8k.js} +3 -3
  21. package/dist/{ws-C7dDiQPE.js → ws-Vy3mBjNm.js} +2 -2
  22. package/dist/{ws-xrWDKWNS.js → ws-mG4yeZu8.js} +3 -3
  23. package/lab/ui/index.html +108 -2
  24. package/package.json +1 -1
  25. package/ts/serve.ts +216 -3
  26. package/dist/trayApp-CpnLyvEB.js +0 -5
@@ -1,11 +1,11 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-d15cc3u7.js";
3
- import "./ts-BeFjrOhc.js";
2
+ import "./versionChecker-D-WLKAN6.js";
3
+ import "./ts-BqaOPFCQ.js";
4
4
  import "./todoAutomation-BQRW614S.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-pwp7Vb7o.js";
7
7
  import "./pidStore-DfSm1jog.js";
8
8
  import "./messageLog-BYFwioFY.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DGlkS83_.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CjKxvhlh.js";
10
10
 
11
11
  export { SUPPORTED_CLIS };
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-BeFjrOhc.js";
1
+ import { t as CLIS_CONFIG } from "./ts-BqaOPFCQ.js";
2
2
 
3
3
  //#region ts/SUPPORTED_CLIS.ts
4
4
  const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
5
5
 
6
6
  //#endregion
7
7
  export { SUPPORTED_CLIS as t };
8
- //# sourceMappingURL=SUPPORTED_CLIS-DGlkS83_.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-CjKxvhlh.js.map
@@ -3,7 +3,7 @@ import "./globalPidIndex-pwp7Vb7o.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-CUMZC53I.js";
5
5
  import "./configShared-DtHMBCl7.js";
6
- import { I as resolveOne } from "./subcommands-BSdA19Nv.js";
6
+ import { I as resolveOne } from "./subcommands-Zk3brdKt.js";
7
7
  import "./webrtcLink-CS4D-3G1.js";
8
8
  import "./remotes-Cn-wszbK.js";
9
9
  import { a as startShare } from "./share-B-e_9WBx.js";
@@ -229,4 +229,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
229
229
 
230
230
  //#endregion
231
231
  export { createScopedShare, listShares, revokeAllShares, revokeShare };
232
- //# sourceMappingURL=agentShare-tL6j9Em4.js.map
232
+ //# sourceMappingURL=agentShare-LEETLOm1.js.map
@@ -1,5 +1,5 @@
1
1
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
2
- import { I as resolveOne } from "./subcommands-BSdA19Nv.js";
2
+ import { I as resolveOne } from "./subcommands-Zk3brdKt.js";
3
3
  import { a as mintCapability, o as parseExpires } from "./callbackCore-Cg3Ye0ZS.js";
4
4
  import { randomBytes } from "node:crypto";
5
5
  import { chmodSync, readFileSync, renameSync, writeFileSync } from "node:fs";
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
72
72
  if (flag) return flag;
73
73
  if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
74
74
  try {
75
- const { resolveLocalServeUrl } = await import("./serve-DCPbGttS.js");
75
+ const { resolveLocalServeUrl } = await import("./serve-DhtgWGZB.js");
76
76
  const url = await resolveLocalServeUrl();
77
77
  if (url) return url;
78
78
  } catch {}
@@ -187,4 +187,4 @@ async function cmdCallback(rest) {
187
187
 
188
188
  //#endregion
189
189
  export { loadOrCreateCallbackSecret as i, isCallbackRevoked as n, loadCallbackSecretReadOnly as r, cmdCallback as t };
190
- //# sourceMappingURL=callback-JJh1_Zzp.js.map
190
+ //# sourceMappingURL=callback-CB3UjryF.js.map
@@ -3,10 +3,10 @@ import "./globalPidIndex-pwp7Vb7o.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-CUMZC53I.js";
5
5
  import "./configShared-DtHMBCl7.js";
6
- import "./subcommands-BSdA19Nv.js";
6
+ import "./subcommands-Zk3brdKt.js";
7
7
  import "./webrtcLink-CS4D-3G1.js";
8
8
  import "./remotes-Cn-wszbK.js";
9
9
  import "./callbackCore-Cg3Ye0ZS.js";
10
- import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-JJh1_Zzp.js";
10
+ import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-CB3UjryF.js";
11
11
 
12
12
  export { cmdCallback };
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bun
2
2
  import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
3
3
  import { n as logger } from "./logger-CDIsZ-Pp.js";
4
- import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-d15cc3u7.js";
5
- import { r as getRustBinary } from "./rustBinary-BBzI-0gG.js";
4
+ import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-D-WLKAN6.js";
5
+ import { r as getRustBinary } from "./rustBinary-_qRGhAa5.js";
6
6
  import { argv } from "process";
7
7
  import { spawn } from "child_process";
8
8
  import ms from "ms";
@@ -295,7 +295,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
295
295
  const rawArg = process.argv[2];
296
296
  const managerCommands = !invokedCliName(process.argv);
297
297
  const isHelpFlag = rawArg === "-h" || rawArg === "--help";
298
- const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken } = await import("./subcommands-C5qaj8cS.js");
298
+ const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken } = await import("./subcommands-D6O9uRvN.js");
299
299
  if (isHelpFlag && process.argv.length === 3) {
300
300
  await cmdHelp(managerCommands);
301
301
  process.exit(0);
@@ -305,7 +305,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
305
305
  process.exit(code ?? 0);
306
306
  }
307
307
  {
308
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-CUP5ABMb.js");
308
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-BFLGbQmm.js");
309
309
  if (isUnknownManagerToken(rawArg, managerCommands, SUPPORTED_CLIS)) {
310
310
  process.stderr.write(`ay: unknown subcommand or CLI '${rawArg}'.\n See 'ay help' for subcommands. To run an agent, name a CLI:\n 'ay <cli> …' (e.g. 'ay claude …') or 'ay --cli <cli> …'.\n`);
311
311
  process.exit(1);
@@ -356,7 +356,7 @@ if (config.useRust) {
356
356
  }
357
357
  }
358
358
  if (rustBinary) {
359
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-CUP5ABMb.js");
359
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-BFLGbQmm.js");
360
360
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
361
361
  if (config.verbose) {
362
362
  console.log(`[rust] Using binary: ${rustBinary}`);
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-d15cc3u7.js";
3
- import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-BeFjrOhc.js";
2
+ import "./versionChecker-D-WLKAN6.js";
3
+ import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-BqaOPFCQ.js";
4
4
  import { _ as isKnownKind, a as renderTree, b as statesOf, c as monitorHint, d as openStore, f as DONE_STATE, g as initialState, h as canTransition, i as renderDigest, l as CycleError, m as ORPHANED_STATE, o as unblockedTasks, p as LIFECYCLES, r as openBlockers, s as describeBlock, t as reconcileTodos, u as TodoStore, v as nextStates, x as removeControlCharacters, y as requiredGate } from "./todoAutomation-BQRW614S.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-pwp7Vb7o.js";
@@ -3,7 +3,7 @@ import "./globalPidIndex-pwp7Vb7o.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-CUMZC53I.js";
5
5
  import "./configShared-DtHMBCl7.js";
6
- import { $ as liveWatchers, J as appendEvent, N as renderLogTailLines, Q as listInboxParents, X as hostId, Y as gcInboxes, et as readInbox, it as notifyDir, l as deriveLiveState, nt as daemonLockDir, rt as daemonLockOwnerPath, tt as shouldStealLock, v as isPidAlive, w as listRecords } from "./subcommands-BSdA19Nv.js";
6
+ import { $ as liveWatchers, J as appendEvent, N as renderLogTailLines, Q as listInboxParents, X as hostId, Y as gcInboxes, et as readInbox, it as notifyDir, l as deriveLiveState, nt as daemonLockDir, rt as daemonLockOwnerPath, tt as shouldStealLock, v as isPidAlive, w as listRecords } from "./subcommands-Zk3brdKt.js";
7
7
  import "./webrtcLink-CS4D-3G1.js";
8
8
  import "./remotes-Cn-wszbK.js";
9
9
  import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
@@ -836,4 +836,4 @@ async function ensureDaemon() {
836
836
 
837
837
  //#endregion
838
838
  export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
839
- //# sourceMappingURL=notifyDaemon-C1HL2AKc.js.map
839
+ //# sourceMappingURL=notifyDaemon-P6Q7Eo_B.js.map
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-d15cc3u7.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-D-WLKAN6.js";
2
2
  import { execFileSync } from "child_process";
3
3
  import { existsSync, mkdirSync, unlinkSync } from "fs";
4
4
  import { chmod, copyFile } from "fs/promises";
@@ -243,4 +243,4 @@ async function getRustBinary(options = {}) {
243
243
 
244
244
  //#endregion
245
245
  export { findTrayLauncher as n, getRustBinary as r, findSpawnHiddenLauncher as t };
246
- //# sourceMappingURL=rustBinary-BBzI-0gG.js.map
246
+ //# sourceMappingURL=rustBinary-_qRGhAa5.js.map
@@ -1,12 +1,12 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-d15cc3u7.js";
3
- import "./ts-BeFjrOhc.js";
2
+ import "./versionChecker-D-WLKAN6.js";
3
+ import "./ts-BqaOPFCQ.js";
4
4
  import "./todoAutomation-BQRW614S.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-pwp7Vb7o.js";
7
7
  import "./pidStore-DfSm1jog.js";
8
8
  import "./messageLog-BYFwioFY.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DGlkS83_.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CjKxvhlh.js";
10
10
  import { f as resolveSpawnCwd } from "./workspaceConfig-Bxuk_MOq.js";
11
11
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-vhOBffJ3.js";
12
12
  import { createHash } from "node:crypto";
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
153
153
 
154
154
  //#endregion
155
155
  export { cmdSchedule };
156
- //# sourceMappingURL=schedule-DCR7zeRi.js.map
156
+ //# sourceMappingURL=schedule-ChAdx2h6.js.map
@@ -1,7 +1,7 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-d15cc3u7.js";
3
- import { t as findSpawnHiddenLauncher } from "./rustBinary-BBzI-0gG.js";
4
- import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-BeFjrOhc.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-D-WLKAN6.js";
3
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-_qRGhAa5.js";
4
+ import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-BqaOPFCQ.js";
5
5
  import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
6
6
  import { x as removeControlCharacters } from "./todoAutomation-BQRW614S.js";
7
7
  import "./JsonlStore-CPGIR0Wy.js";
@@ -11,17 +11,17 @@ import { r as recordInbox } from "./messageLog-BYFwioFY.js";
11
11
  import { t as pgidForWrapper } from "./reaper-C4BvNylH.js";
12
12
  import "./e2e-CUMZC53I.js";
13
13
  import "./configShared-DtHMBCl7.js";
14
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DGlkS83_.js";
15
- import { A as readPtysize, F as renderRawLogLines, I as resolveOne, M as recentReadEdges, N as renderLogTailLines, O as readLogForRender, P as renderRawLog, S as isUserTyping, V as snapshotStatus, Z as isTransientLockMkdirError, at as TYPING_BADGE, d as extractBadges, j as recentMessageEdges, k as readNotes, m as extractTaskCounts, p as extractNeedsInput, q as writeToIpc, s as controlCodeFromName, u as deriveLiveStatus, w as listRecords } from "./subcommands-BSdA19Nv.js";
14
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CjKxvhlh.js";
15
+ import { A as readPtysize, F as renderRawLogLines, I as resolveOne, M as recentReadEdges, N as renderLogTailLines, O as readLogForRender, P as renderRawLog, S as isUserTyping, V as snapshotStatus, Z as isTransientLockMkdirError, at as TYPING_BADGE, d as extractBadges, j as recentMessageEdges, k as readNotes, m as extractTaskCounts, p as extractNeedsInput, q as writeToIpc, s as controlCodeFromName, u as deriveLiveStatus, w as listRecords } from "./subcommands-Zk3brdKt.js";
16
16
  import "./webrtcLink-CS4D-3G1.js";
17
17
  import "./remotes-Cn-wszbK.js";
18
18
  import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-Cg3Ye0ZS.js";
19
- import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-JJh1_Zzp.js";
19
+ import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-CB3UjryF.js";
20
20
  import { a as getProvisionRoot, d as isProvisionAllowed, f as resolveSpawnCwd, i as getProvisionHook, l as hasProvisionHook, o as getSpawnHook, t as allowsSkipPermissions, u as hasSpawnHook } from "./workspaceConfig-Bxuk_MOq.js";
21
21
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-vhOBffJ3.js";
22
- import { i as importProvisionModule } from "./ws-C7dDiQPE.js";
22
+ import { i as importProvisionModule } from "./ws-Vy3mBjNm.js";
23
23
  import { r as spawnRejectionReason } from "./spawnGate-D-68B907.js";
24
- import { i as launchTray } from "./trayApp-DO9sPIPo.js";
24
+ import { i as launchTray } from "./trayApp-DtThjl0_.js";
25
25
  import yargs from "yargs";
26
26
  import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "fs/promises";
27
27
  import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
@@ -675,6 +675,33 @@ function originOwnerRepo(cwd) {
675
675
  return null;
676
676
  }
677
677
  }
678
+ async function runCapture(argv, opts) {
679
+ try {
680
+ const child = Bun.spawn(argv, {
681
+ cwd: opts?.cwd,
682
+ env: freshAgentEnv(),
683
+ stdin: "ignore",
684
+ stdout: "pipe",
685
+ stderr: "pipe"
686
+ });
687
+ const timeoutMs = opts?.timeoutMs ?? 15e3;
688
+ const code = await Promise.race([child.exited, new Promise((r) => setTimeout(() => r(124), timeoutMs))]);
689
+ if (code === 124) child.kill();
690
+ const [stdout, stderr] = await Promise.all([new Response(child.stdout).text(), new Response(child.stderr).text()]);
691
+ return {
692
+ ok: code === 0,
693
+ stdout,
694
+ stderr
695
+ };
696
+ } catch (e) {
697
+ return {
698
+ ok: false,
699
+ stdout: "",
700
+ stderr: e.message
701
+ };
702
+ }
703
+ }
704
+ let ghRepoListMemo = null;
678
705
  async function runProvisionHook(cwd, koho) {
679
706
  const hook = getProvisionHook();
680
707
  if (!hook) return { ran: false };
@@ -2368,7 +2395,7 @@ Options:
2368
2395
  }
2369
2396
  });
2370
2397
  if (req.method === "GET" && p === "/api/ws") {
2371
- const ws = await import("./ws-xrWDKWNS.js");
2398
+ const ws = await import("./ws-mG4yeZu8.js");
2372
2399
  try {
2373
2400
  await ws.loadProvision();
2374
2401
  } catch (e) {
@@ -2388,7 +2415,7 @@ Options:
2388
2415
  if (req.method === "GET" && p === "/api/ws/status") {
2389
2416
  const dirRaw = url.searchParams.get("path");
2390
2417
  if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
2391
- const ws = await import("./ws-xrWDKWNS.js");
2418
+ const ws = await import("./ws-mG4yeZu8.js");
2392
2419
  let prov;
2393
2420
  try {
2394
2421
  prov = await ws.loadProvision();
@@ -2409,6 +2436,147 @@ Options:
2409
2436
  return new Response(`git status failed: ${e.message}`, { status: 502 });
2410
2437
  }
2411
2438
  }
2439
+ if (req.method === "GET" && p === "/api/ws/repos") {
2440
+ const ws = await import("./ws-mG4yeZu8.js");
2441
+ try {
2442
+ await ws.loadProvision();
2443
+ } catch (e) {
2444
+ return new Response(e.message, { status: 501 });
2445
+ }
2446
+ let wsRoot;
2447
+ let workspaces;
2448
+ try {
2449
+ ({wsRoot, workspaces} = await ws.collectWorkspaces());
2450
+ } catch (e) {
2451
+ return new Response(`workspace walk failed: ${e.message}`, { status: 500 });
2452
+ }
2453
+ const byRepo = /* @__PURE__ */ new Map();
2454
+ for (const w of workspaces) {
2455
+ const key = `${w.owner}/${w.repo}`;
2456
+ const entry = byRepo.get(key) ?? {
2457
+ owner: w.owner,
2458
+ repo: w.repo,
2459
+ local: true,
2460
+ branches: []
2461
+ };
2462
+ entry.branches.push({
2463
+ name: w.branch,
2464
+ path: w.path
2465
+ });
2466
+ byRepo.set(key, entry);
2467
+ }
2468
+ const gh = { ok: false };
2469
+ let ghRepos = [];
2470
+ const memo = ghRepoListMemo;
2471
+ if (memo && performance.now() - memo.t < 6e4) {
2472
+ gh.ok = memo.ok;
2473
+ if (memo.error) gh.error = memo.error;
2474
+ ghRepos = memo.repos;
2475
+ } else {
2476
+ const r = await runCapture([
2477
+ "gh",
2478
+ "repo",
2479
+ "list",
2480
+ "--limit",
2481
+ "200",
2482
+ "--json",
2483
+ "nameWithOwner"
2484
+ ], { timeoutMs: 1e4 });
2485
+ if (r.ok) try {
2486
+ ghRepos = JSON.parse(r.stdout).map((x) => x.nameWithOwner);
2487
+ gh.ok = true;
2488
+ } catch {
2489
+ gh.error = "gh returned unparseable JSON";
2490
+ }
2491
+ else gh.error = (r.stderr.trim() || "gh unavailable").slice(0, 200);
2492
+ ghRepoListMemo = {
2493
+ t: performance.now(),
2494
+ ok: gh.ok,
2495
+ repos: ghRepos,
2496
+ error: gh.error
2497
+ };
2498
+ }
2499
+ for (const nameWithOwner of ghRepos) {
2500
+ const [owner, repo] = nameWithOwner.split("/");
2501
+ if (owner && repo && !byRepo.has(nameWithOwner)) byRepo.set(nameWithOwner, {
2502
+ owner,
2503
+ repo,
2504
+ local: false,
2505
+ branches: []
2506
+ });
2507
+ }
2508
+ const repos = [...byRepo.values()].sort((a, b) => a.local !== b.local ? a.local ? -1 : 1 : `${a.owner}/${a.repo}`.localeCompare(`${b.owner}/${b.repo}`));
2509
+ return Response.json({
2510
+ schema: ws.WS_JSON_SCHEMA,
2511
+ wsRoot,
2512
+ repos,
2513
+ gh
2514
+ });
2515
+ }
2516
+ if (req.method === "GET" && p === "/api/ws/branches") {
2517
+ const repoParam = url.searchParams.get("repo") ?? "";
2518
+ const m = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/.exec(repoParam);
2519
+ if (!m || m[1] === "." || m[1] === ".." || m[2] === "." || m[2] === "..") return new Response("missing/invalid ?repo=<owner>/<repo>", { status: 400 });
2520
+ const [, owner, repo] = m;
2521
+ const ws = await import("./ws-mG4yeZu8.js");
2522
+ let prov;
2523
+ try {
2524
+ prov = await ws.loadProvision();
2525
+ } catch (e) {
2526
+ return new Response(e.message, { status: 501 });
2527
+ }
2528
+ const wsRoot = prov.resolveWsRoot(getProvisionRoot());
2529
+ const localByBranch = /* @__PURE__ */ new Map();
2530
+ try {
2531
+ for (const w of await ws.walkWorkspaces(wsRoot)) if (w.owner === owner && w.repo === repo) localByBranch.set(w.branch, w.path);
2532
+ } catch {}
2533
+ let remote = [];
2534
+ let source = "";
2535
+ let error;
2536
+ const anchor = localByBranch.values().next().value;
2537
+ if (anchor) {
2538
+ const r = await runCapture([
2539
+ "git",
2540
+ "-C",
2541
+ anchor,
2542
+ "ls-remote",
2543
+ "--heads",
2544
+ "origin"
2545
+ ]);
2546
+ if (r.ok) {
2547
+ remote = [...r.stdout.matchAll(/\trefs\/heads\/(.+)/g)].map((x) => x[1].trim());
2548
+ source = "ls-remote";
2549
+ } else error = (r.stderr.trim() || "git ls-remote failed").slice(0, 200);
2550
+ }
2551
+ if (!source) {
2552
+ const r = await runCapture([
2553
+ "gh",
2554
+ "api",
2555
+ `repos/${owner}/${repo}/branches`,
2556
+ "--paginate",
2557
+ "--jq",
2558
+ ".[].name"
2559
+ ]);
2560
+ if (r.ok) {
2561
+ remote = r.stdout.split("\n").map((s) => s.trim()).filter(Boolean);
2562
+ source = "gh";
2563
+ error = void 0;
2564
+ } else if (!error) error = (r.stderr.trim() || "gh unavailable").slice(0, 200);
2565
+ }
2566
+ const branches = [...new Set([...remote, ...localByBranch.keys()])].sort((a, b) => a.localeCompare(b)).map((name) => ({
2567
+ name,
2568
+ remote: remote.includes(name),
2569
+ provisioned: localByBranch.has(name),
2570
+ ...localByBranch.has(name) ? { path: localByBranch.get(name) } : {}
2571
+ }));
2572
+ return Response.json({
2573
+ schema: ws.WS_JSON_SCHEMA,
2574
+ repo: `${owner}/${repo}`,
2575
+ source: source || "local-only",
2576
+ branches,
2577
+ ...error ? { error } : {}
2578
+ });
2579
+ }
2412
2580
  if (req.method === "GET" && p === "/api/notes") {
2413
2581
  const notes = await readNotes();
2414
2582
  return Response.json(Object.fromEntries(notes));
@@ -3034,10 +3202,11 @@ Options:
3034
3202
  try {
3035
3203
  const wsRoot = getProvisionRoot();
3036
3204
  result = await prov.provision(spec, wsRoot ? { wsRoot } : void 0);
3205
+ if (!result?.ok && body.create === true && result?.reason === "branch-not-found" && typeof prov.createBranch === "function") result = await prov.createBranch(spec, wsRoot ? { wsRoot } : void 0);
3037
3206
  } catch (e) {
3038
3207
  return new Response(`provision failed: ${e.message}`, { status: 502 });
3039
3208
  }
3040
- if (!result?.ok) return new Response(result?.error ?? "provision failed", { status: 502 });
3209
+ if (!result?.ok) return new Response((result?.error ?? "provision failed") + (result?.reason === "branch-not-found" && body.create !== true ? "\n(branch missing on the remote — retry with create:true to branch off the default)" : ""), { status: 502 });
3041
3210
  cwd = result.folder;
3042
3211
  provisioned = {
3043
3212
  action: result.action,
@@ -3145,7 +3314,7 @@ Options:
3145
3314
  const perm = body.perm ?? "r";
3146
3315
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
3147
3316
  try {
3148
- const { createScopedShare } = await import("./agentShare-tL6j9Em4.js");
3317
+ const { createScopedShare } = await import("./agentShare-LEETLOm1.js");
3149
3318
  const share = await createScopedShare({
3150
3319
  agent: body.agent,
3151
3320
  perm,
@@ -3160,12 +3329,12 @@ Options:
3160
3329
  }
3161
3330
  }
3162
3331
  if (req.method === "GET" && p === "/api/shares") {
3163
- const { listShares } = await import("./agentShare-tL6j9Em4.js");
3332
+ const { listShares } = await import("./agentShare-LEETLOm1.js");
3164
3333
  return Response.json(listShares());
3165
3334
  }
3166
3335
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
3167
3336
  if (req.method === "DELETE" && revokeM) {
3168
- const { revokeShare } = await import("./agentShare-tL6j9Em4.js");
3337
+ const { revokeShare } = await import("./agentShare-LEETLOm1.js");
3169
3338
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
3170
3339
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
3171
3340
  }
@@ -3467,7 +3636,7 @@ Options:
3467
3636
  const shutdown = (resolve) => {
3468
3637
  if (heartbeat) clearInterval(heartbeat);
3469
3638
  closeShare?.();
3470
- import("./agentShare-tL6j9Em4.js").then((m) => m.revokeAllShares()).catch(() => {});
3639
+ import("./agentShare-LEETLOm1.js").then((m) => m.revokeAllShares()).catch(() => {});
3471
3640
  server?.stop();
3472
3641
  Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
3473
3642
  };
@@ -3480,4 +3649,4 @@ Options:
3480
3649
 
3481
3650
  //#endregion
3482
3651
  export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
3483
- //# sourceMappingURL=serve-DCPbGttS.js.map
3652
+ //# sourceMappingURL=serve-DhtgWGZB.js.map
@@ -40,7 +40,7 @@ async function cmdSetup(rest) {
40
40
  } catch {}
41
41
  if (noShare) return 0;
42
42
  process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
43
- const { cmdServe } = await import("./serve-DCPbGttS.js");
43
+ const { cmdServe } = await import("./serve-DhtgWGZB.js");
44
44
  return cmdServe([
45
45
  "install",
46
46
  "--share",
@@ -50,4 +50,4 @@ async function cmdSetup(rest) {
50
50
 
51
51
  //#endregion
52
52
  export { cmdSetup };
53
- //# sourceMappingURL=setup-DO75Uqec.js.map
53
+ //# sourceMappingURL=setup-BlJRaODn.js.map
@@ -3,7 +3,7 @@ import "./globalPidIndex-pwp7Vb7o.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-CUMZC53I.js";
5
5
  import "./configShared-DtHMBCl7.js";
6
- import { A as readPtysize, B as runSubcommand, C as lastStdinAt, D as readAgentPtysize, E as menuSelectKeys, F as renderRawLogLines, G as waitForLogQuiet, H as stdinActivityPath, I as resolveOne, K as writeKeysPaced, L as resolveReadWindow, M as recentReadEdges, N as renderLogTailLines, O as readLogForRender, P as renderRawLog, R as resolveResumeArgs, S as isUserTyping, T as matchKeyword, U as stopTipForCli, V as snapshotStatus, W as submitAndConfirm, _ as isExitRequest, a as backoffWhileTyping, b as isSubcommand, c as cursorAbs, d as extractBadges, f as extractMenu, g as isAgentStuck, h as finalizedLines, i as TYPING_WINDOW_MS, j as recentMessageEdges, k as readNotes, l as deriveLiveState, m as extractTaskCounts, n as MAX_RENDER_BYTES, o as cmdHelp, p as extractNeedsInput, q as writeToIpc, r as READ_PAGE_DEFAULT, s as controlCodeFromName, t as GRACEFUL_EXIT_COMMANDS, u as deriveLiveStatus, v as isPidAlive, w as listRecords, x as isUnknownManagerToken, y as isSlashCommand, z as restartHintLines } from "./subcommands-BSdA19Nv.js";
6
+ import { A as readPtysize, B as runSubcommand, C as lastStdinAt, D as readAgentPtysize, E as menuSelectKeys, F as renderRawLogLines, G as waitForLogQuiet, H as stdinActivityPath, I as resolveOne, K as writeKeysPaced, L as resolveReadWindow, M as recentReadEdges, N as renderLogTailLines, O as readLogForRender, P as renderRawLog, R as resolveResumeArgs, S as isUserTyping, T as matchKeyword, U as stopTipForCli, V as snapshotStatus, W as submitAndConfirm, _ as isExitRequest, a as backoffWhileTyping, b as isSubcommand, c as cursorAbs, d as extractBadges, f as extractMenu, g as isAgentStuck, h as finalizedLines, i as TYPING_WINDOW_MS, j as recentMessageEdges, k as readNotes, l as deriveLiveState, m as extractTaskCounts, n as MAX_RENDER_BYTES, o as cmdHelp, p as extractNeedsInput, q as writeToIpc, r as READ_PAGE_DEFAULT, s as controlCodeFromName, t as GRACEFUL_EXIT_COMMANDS, u as deriveLiveStatus, v as isPidAlive, w as listRecords, x as isUnknownManagerToken, y as isSlashCommand, z as restartHintLines } from "./subcommands-Zk3brdKt.js";
7
7
  import "./webrtcLink-CS4D-3G1.js";
8
8
  import "./remotes-Cn-wszbK.js";
9
9
 
@@ -1402,35 +1402,35 @@ async function runSubcommand(argv) {
1402
1402
  return cmdCh(rest);
1403
1403
  }
1404
1404
  case "term": {
1405
- const { cmdTerm } = await import("./terminal-CXIqdFAy.js");
1405
+ const { cmdTerm } = await import("./terminal-BVWhnQUf.js");
1406
1406
  return cmdTerm(rest);
1407
1407
  }
1408
1408
  case "widget": {
1409
- const { cmdWidget } = await import("./widget-BFpPQNzh.js");
1409
+ const { cmdWidget } = await import("./widget-CJyd9t8k.js");
1410
1410
  return cmdWidget(rest);
1411
1411
  }
1412
1412
  case "mint": {
1413
- const { cmdMint } = await import("./widget-BFpPQNzh.js");
1413
+ const { cmdMint } = await import("./widget-CJyd9t8k.js");
1414
1414
  return cmdMint(rest);
1415
1415
  }
1416
1416
  case "serve": {
1417
- const { cmdServe } = await import("./serve-DCPbGttS.js");
1417
+ const { cmdServe } = await import("./serve-DhtgWGZB.js");
1418
1418
  return cmdServe(rest);
1419
1419
  }
1420
1420
  case "tray": {
1421
- const { cmdTray } = await import("./trayApp-CpnLyvEB.js");
1421
+ const { cmdTray } = await import("./trayApp-C6U7Hghi.js");
1422
1422
  return cmdTray(rest);
1423
1423
  }
1424
1424
  case "setup": {
1425
- const { cmdSetup } = await import("./setup-DO75Uqec.js");
1425
+ const { cmdSetup } = await import("./setup-BlJRaODn.js");
1426
1426
  return cmdSetup(rest);
1427
1427
  }
1428
1428
  case "ws": {
1429
- const { cmdWs } = await import("./ws-xrWDKWNS.js");
1429
+ const { cmdWs } = await import("./ws-mG4yeZu8.js");
1430
1430
  return cmdWs(rest);
1431
1431
  }
1432
1432
  case "schedule": {
1433
- const { cmdSchedule } = await import("./schedule-DCR7zeRi.js");
1433
+ const { cmdSchedule } = await import("./schedule-ChAdx2h6.js");
1434
1434
  return cmdSchedule(rest);
1435
1435
  }
1436
1436
  case "remote": {
@@ -1442,7 +1442,7 @@ async function runSubcommand(argv) {
1442
1442
  return cmdExpose(rest);
1443
1443
  }
1444
1444
  case "callback": {
1445
- const { cmdCallback } = await import("./callback-BfJqf5hh.js");
1445
+ const { cmdCallback } = await import("./callback-lqCCgSy1.js");
1446
1446
  return cmdCallback(rest);
1447
1447
  }
1448
1448
  case "reap":
@@ -3956,7 +3956,7 @@ async function cmdAttach(rest) {
3956
3956
  const winsizeDir = path.join(ayHome, "winsize");
3957
3957
  await mkdir(winsizeDir, { recursive: true });
3958
3958
  const winsizePath = path.join(winsizeDir, String(record.pid));
3959
- const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-DCPbGttS.js");
3959
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-DhtgWGZB.js");
3960
3960
  const daemonBase = await resolveDaemonHttpBase().catch(() => null);
3961
3961
  const daemonToken = daemonBase ? await loadTokenReadOnly().catch(() => null) ?? "" : "";
3962
3962
  const capViewer = `attach:${process.pid}`;
@@ -4666,7 +4666,7 @@ async function cmdNotify(rest) {
4666
4666
  }
4667
4667
  const ensure = async () => {
4668
4668
  if (!argv["ensure-daemon"]) return;
4669
- const { ensureDaemon } = await import("./notifyDaemon-C1HL2AKc.js");
4669
+ const { ensureDaemon } = await import("./notifyDaemon-P6Q7Eo_B.js");
4670
4670
  await ensureDaemon().catch(() => null);
4671
4671
  };
4672
4672
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4740,7 +4740,7 @@ async function cmdNotifyCursor(args) {
4740
4740
  }
4741
4741
  async function cmdNotifyd(rest) {
4742
4742
  const sub = rest[0] ?? "status";
4743
- const daemon = await import("./notifyDaemon-C1HL2AKc.js");
4743
+ const daemon = await import("./notifyDaemon-P6Q7Eo_B.js");
4744
4744
  switch (sub) {
4745
4745
  case "run": return daemon.runDaemon();
4746
4746
  case "once": return daemon.runDaemon({ once: true });
@@ -4767,4 +4767,4 @@ async function cmdNotifyd(rest) {
4767
4767
 
4768
4768
  //#endregion
4769
4769
  export { liveWatchers as $, readPtysize as A, runSubcommand as B, lastStdinAt as C, readAgentPtysize as D, menuSelectKeys as E, renderRawLogLines as F, waitForLogQuiet as G, stdinActivityPath as H, resolveOne as I, appendEvent as J, writeKeysPaced as K, resolveReadWindow as L, recentReadEdges as M, renderLogTailLines as N, readLogForRender as O, renderRawLog as P, listInboxParents as Q, resolveResumeArgs as R, isUserTyping as S, matchKeyword as T, stopTipForCli as U, snapshotStatus as V, submitAndConfirm as W, hostId as X, gcInboxes as Y, isTransientLockMkdirError as Z, isExitRequest as _, backoffWhileTyping as a, TYPING_BADGE as at, isSubcommand as b, cursorAbs as c, extractBadges as d, readInbox as et, extractMenu as f, isAgentStuck as g, finalizedLines as h, TYPING_WINDOW_MS as i, notifyDir as it, recentMessageEdges as j, readNotes as k, deriveLiveState as l, extractTaskCounts as m, MAX_RENDER_BYTES as n, daemonLockDir as nt, cmdHelp as o, extractNeedsInput as p, writeToIpc as q, READ_PAGE_DEFAULT as r, daemonLockOwnerPath as rt, controlCodeFromName as s, GRACEFUL_EXIT_COMMANDS as t, shouldStealLock as tt, deriveLiveStatus as u, isPidAlive as v, listRecords as w, isUnknownManagerToken as x, isSlashCommand as y, restartHintLines as z };
4770
- //# sourceMappingURL=subcommands-BSdA19Nv.js.map
4770
+ //# sourceMappingURL=subcommands-Zk3brdKt.js.map
@@ -98,7 +98,7 @@ async function cmdTermMint(args) {
98
98
  if (flags.ro && flags.interactive) throw new Error("--ro and --interactive are mutually exclusive");
99
99
  const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
100
100
  const canSend = flags.interactive === true;
101
- const { mintScopedTermToken } = await import("./serve-DCPbGttS.js");
101
+ const { mintScopedTermToken } = await import("./serve-DhtgWGZB.js");
102
102
  const r = await mintScopedTermToken(pid, {
103
103
  ttlSec,
104
104
  canSend
@@ -135,4 +135,4 @@ async function cmdTerm(args) {
135
135
 
136
136
  //#endregion
137
137
  export { cmdTerm };
138
- //# sourceMappingURL=terminal-CXIqdFAy.js.map
138
+ //# sourceMappingURL=terminal-BVWhnQUf.js.map
@@ -0,0 +1,5 @@
1
+ import "./versionChecker-D-WLKAN6.js";
2
+ import "./rustBinary-_qRGhAa5.js";
3
+ import { a as trayHiddenMarker, i as launchTray, n as hasDesktop, r as isTrayHidden, t as cmdTray } from "./trayApp-DtThjl0_.js";
4
+
5
+ export { cmdTray };
@@ -1,4 +1,4 @@
1
- import { n as findTrayLauncher } from "./rustBinary-BBzI-0gG.js";
1
+ import { n as findTrayLauncher } from "./rustBinary-_qRGhAa5.js";
2
2
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
3
3
  import { existsSync } from "node:fs";
4
4
  import path from "node:path";
@@ -97,4 +97,4 @@ async function cmdTray(args) {
97
97
 
98
98
  //#endregion
99
99
  export { trayHiddenMarker as a, launchTray as i, hasDesktop as n, isTrayHidden as r, cmdTray as t };
100
- //# sourceMappingURL=trayApp-DO9sPIPo.js.map
100
+ //# sourceMappingURL=trayApp-DtThjl0_.js.map
@@ -1,6 +1,6 @@
1
1
  import { n as __esmMin, r as __exportAll } from "./chunk-cZBX9HZv.js";
2
2
  import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
3
- import { r as getInstalledPackage } from "./versionChecker-d15cc3u7.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-D-WLKAN6.js";
4
4
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
5
5
  import { d as openStore, p as LIFECYCLES, x as removeControlCharacters } from "./todoAutomation-BQRW614S.js";
6
6
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-DBoONoM-.js";
@@ -2181,4 +2181,4 @@ function sleep(ms) {
2181
2181
 
2182
2182
  //#endregion
2183
2183
  export { hasTodoStore as a, permissionBadge as c, answerAsk as i, AgentContext as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t, CLAUDE_SESSION_PIN_ENV as u };
2184
- //# sourceMappingURL=ts-BeFjrOhc.js.map
2184
+ //# sourceMappingURL=ts-BqaOPFCQ.js.map
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
7
7
 
8
8
  //#region package.json
9
9
  var name = "agent-yes";
10
- var version = "1.261.1";
10
+ var version = "1.262.0";
11
11
 
12
12
  //#endregion
13
13
  //#region ts/versionChecker.ts
@@ -215,4 +215,4 @@ async function displayVersion() {
215
215
 
216
216
  //#endregion
217
217
  export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
218
- //# sourceMappingURL=versionChecker-d15cc3u7.js.map
218
+ //# sourceMappingURL=versionChecker-D-WLKAN6.js.map
@@ -28,7 +28,7 @@ function parseFlags(args, known) {
28
28
  }
29
29
  /** Resolve the local daemon base URL + token (flags override discovery). */
30
30
  async function daemonTarget(flags) {
31
- const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-DCPbGttS.js");
31
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-DhtgWGZB.js");
32
32
  const base = typeof flags.base === "string" ? flags.base : await resolveDaemonHttpBase();
33
33
  if (!base) throw new Error("no running ay serve daemon found — start `ay serve` or pass --base <url> (e.g. http://127.0.0.1:PORT)");
34
34
  const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
@@ -186,7 +186,7 @@ async function cmdMint(args) {
186
186
  const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
187
187
  if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
188
188
  const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
189
- const { mintScopedTermToken } = await import("./serve-DCPbGttS.js");
189
+ const { mintScopedTermToken } = await import("./serve-DhtgWGZB.js");
190
190
  const r = await mintScopedTermToken(target, {
191
191
  ttlSec,
192
192
  caps
@@ -202,4 +202,4 @@ async function cmdMint(args) {
202
202
 
203
203
  //#endregion
204
204
  export { cmdMint, cmdWidget };
205
- //# sourceMappingURL=widget-BFpPQNzh.js.map
205
+ //# sourceMappingURL=widget-CJyd9t8k.js.map
@@ -1,4 +1,4 @@
1
- import { w as listRecords } from "./subcommands-BSdA19Nv.js";
1
+ import { w as listRecords } from "./subcommands-Zk3brdKt.js";
2
2
  import { a as getProvisionRoot } from "./workspaceConfig-Bxuk_MOq.js";
3
3
  import { existsSync } from "fs";
4
4
  import { lstat, opendir } from "fs/promises";
@@ -426,4 +426,4 @@ async function cmdWs(args) {
426
426
 
427
427
  //#endregion
428
428
  export { isPathInside as a, walkWorkspaces as c, importProvisionModule as i, workspaceStatus as l, cmdWs as n, loadProvision as o, collectWorkspaces as r, resolveOperand as s, WS_JSON_SCHEMA as t };
429
- //# sourceMappingURL=ws-C7dDiQPE.js.map
429
+ //# sourceMappingURL=ws-Vy3mBjNm.js.map
@@ -3,9 +3,9 @@ import "./globalPidIndex-pwp7Vb7o.js";
3
3
  import "./messageLog-BYFwioFY.js";
4
4
  import "./e2e-CUMZC53I.js";
5
5
  import "./configShared-DtHMBCl7.js";
6
- import "./subcommands-BSdA19Nv.js";
6
+ import "./subcommands-Zk3brdKt.js";
7
7
  import "./webrtcLink-CS4D-3G1.js";
8
8
  import "./remotes-Cn-wszbK.js";
9
- import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-C7dDiQPE.js";
9
+ import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-Vy3mBjNm.js";
10
10
 
11
- export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
11
+ export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, walkWorkspaces, workspaceStatus };
package/lab/ui/index.html CHANGED
@@ -7982,6 +7982,7 @@ my.translate = async (text, lang) => {
7982
7982
  const res = await target.tx.post("/api/spawn", {
7983
7983
  cli: spec.cli || "claude",
7984
7984
  from: spec.from || undefined,
7985
+ create: spec.create || undefined,
7985
7986
  fork: spec.fork || undefined,
7986
7987
  cwd: spec.cwd || undefined,
7987
7988
  prompt: spec.prompt || undefined,
@@ -8105,6 +8106,8 @@ my.translate = async (text, lang) => {
8105
8106
  ${hostRow}
8106
8107
  <div class="nfield"><label>Working dir</label><input id="nf-cwd" list="nf-cwd-list" value="${esc(cwd)}" placeholder="(host default — ignored when Spawn from is set)" spellcheck="false" autocapitalize="off" /><datalist id="nf-cwd-list">${cwdOptions(target ? target.id : "")}</datalist></div>
8107
8108
  <div class="nfield"><label>CLI</label><select id="nf-cli">${cliOptions(null, preferredCli)}</select></div>
8109
+ <div class="nfield"><label>Provision repo — optional</label><select id="nf-repo"><option value="" selected>(none — use working dir or spawn-from)</option></select></div>
8110
+ <div class="nfield" id="nf-branch-row" style="display:none"><label>Branch</label><input id="nf-branch" list="nf-branch-list" placeholder="(repo default) — pick one, or type a new name to create it" spellcheck="false" autocapitalize="off" /><datalist id="nf-branch-list"></datalist><div class="lhint" id="nf-branch-hint" style="display:none"></div></div>
8108
8111
  <div class="nfield"><label>Spawn from — optional</label><input id="nf-from" placeholder="github URL / owner/repo@branch — provisions a worktree" spellcheck="false" autocapitalize="off" /></div>
8109
8112
  <div class="nfield"><label>Prompt — optional</label><textarea id="nf-prompt" rows="3" placeholder="initial message to send the agent…"></textarea></div>
8110
8113
  <div class="lrow">
@@ -8122,8 +8125,95 @@ my.translate = async (text, lang) => {
8122
8125
  const dl = $("nf-cwd-list");
8123
8126
  if (dl) dl.innerHTML = cwdOptions(ev.target.value);
8124
8127
  showHook(sources.get(ev.target.value));
8128
+ loadRepoPicker(sources.get(ev.target.value));
8129
+ });
8130
+ $("nf-repo")?.addEventListener("change", () => {
8131
+ const repo = $("nf-repo").value;
8132
+ const row = $("nf-branch-row");
8133
+ if (row) row.style.display = repo ? "" : "none";
8134
+ if (repo) loadBranchPicker(spawnTarget($("newform").dataset.room), repo);
8135
+ else nfRemoteBranches = null;
8136
+ });
8137
+ $("nf-branch-row")?.addEventListener("input", (ev) => {
8138
+ if (ev.target.id === "nf-branch") updateBranchHint();
8125
8139
  });
8126
8140
  showHook(target);
8141
+ loadRepoPicker(target);
8142
+ }
8143
+
8144
+ // ---- provisioning picker (repo → branch) for the New-agent form -------
8145
+ // Data comes from the target host's /api/ws/repos and /api/ws/branches.
8146
+ // Both are best-effort on the server (gh may be unauthenticated); here a
8147
+ // fetch failure just leaves the pickers empty — the free-text "Spawn
8148
+ // from" field still works.
8149
+ let nfRemoteBranches = null; // Set of remote branch names for the picked repo
8150
+ function loadRepoPicker(target) {
8151
+ const selEl = $("nf-repo");
8152
+ if (!selEl || !target?.tx?.fetchJSON) return;
8153
+ const forId = target.id;
8154
+ target.tx
8155
+ .fetchJSON("/api/ws/repos")
8156
+ .then((d) => {
8157
+ // a slow answer for a host the user switched away from must not
8158
+ // paint the new host's repo list (same guard as showHook)
8159
+ if ($("newform").dataset.room !== forId) return;
8160
+ const cur = selEl.value;
8161
+ const repos = (d && d.repos) || [];
8162
+ selEl.innerHTML =
8163
+ `<option value="">(none — use working dir or spawn-from)</option>` +
8164
+ repos
8165
+ .map((r) => {
8166
+ const full = `${r.owner}/${r.repo}`;
8167
+ return `<option value="${esc(full)}"${full === cur ? " selected" : ""}>${esc(full)}${r.local ? "" : " (gh)"}</option>`;
8168
+ })
8169
+ .join("");
8170
+ })
8171
+ .catch(() => {});
8172
+ }
8173
+ function loadBranchPicker(target, repo) {
8174
+ const dl = $("nf-branch-list");
8175
+ const hint = $("nf-branch-hint");
8176
+ nfRemoteBranches = null;
8177
+ if (dl) dl.innerHTML = "";
8178
+ if (hint) {
8179
+ hint.textContent = "fetching branches…";
8180
+ hint.style.display = "";
8181
+ }
8182
+ if (!target?.tx?.fetchJSON) return;
8183
+ const want = repo;
8184
+ target.tx
8185
+ .fetchJSON("/api/ws/branches?repo=" + encodeURIComponent(repo))
8186
+ .then((d) => {
8187
+ if ($("nf-repo")?.value !== want) return; // user picked another repo meanwhile
8188
+ const branches = (d && d.branches) || [];
8189
+ nfRemoteBranches = new Set(branches.filter((b) => b.remote).map((b) => b.name));
8190
+ if (dl)
8191
+ dl.innerHTML = branches
8192
+ .map(
8193
+ (b) =>
8194
+ `<option value="${esc(b.name)}">${b.provisioned ? "provisioned" : b.remote ? "remote" : "local"}</option>`,
8195
+ )
8196
+ .join("");
8197
+ updateBranchHint(d && d.error);
8198
+ })
8199
+ .catch(() => {
8200
+ if (hint) hint.textContent = "branch list unavailable — type a branch name";
8201
+ });
8202
+ }
8203
+ function updateBranchHint(fetchError) {
8204
+ const hint = $("nf-branch-hint");
8205
+ if (!hint) return;
8206
+ const br = ($("nf-branch")?.value || "").trim();
8207
+ if (nfRemoteBranches == null) {
8208
+ if (fetchError) hint.textContent = `branch list unavailable (${fetchError})`;
8209
+ return;
8210
+ }
8211
+ if (br && !nfRemoteBranches.has(br)) {
8212
+ hint.textContent = `“${br}” is not on the remote — a new branch will be created off the default`;
8213
+ } else {
8214
+ hint.textContent = `${nfRemoteBranches.size} remote branches — empty = repo default; a new name creates a branch`;
8215
+ }
8216
+ hint.style.display = "";
8127
8217
  }
8128
8218
 
8129
8219
  // Surface whether the target host runs a spawn hook (a trusted local command
@@ -8168,10 +8258,26 @@ my.translate = async (text, lang) => {
8168
8258
  try {
8169
8259
  localStorage.setItem(LAST_CLI_KEY, cli);
8170
8260
  } catch {}
8261
+ // The repo/branch pickers win over the free-text "Spawn from" field:
8262
+ // picked repo [+ branch] → a `from` spec; a branch name that isn't on
8263
+ // the remote asks the server to create it (create:true, ws new --create).
8264
+ let from = $("nf-from")?.value.trim() || "";
8265
+ let create = false;
8266
+ const pickedRepo = $("nf-repo")?.value || "";
8267
+ if (pickedRepo) {
8268
+ const br = ($("nf-branch")?.value || "").trim();
8269
+ from = br ? `${pickedRepo}@${br}` : pickedRepo;
8270
+ // Unknown remote list (fetch failed) → still send create: the server
8271
+ // only uses it after the branch turns out missing, so it's harmless
8272
+ // for existing branches and saves an un-actionable 502 for new ones.
8273
+ create = !!(br && (!nfRemoteBranches || !nfRemoteBranches.has(br)));
8274
+ }
8171
8275
  const spec = {
8172
8276
  cli,
8173
- from: $("nf-from")?.value.trim() || "",
8174
- cwd: $("nf-cwd").value.trim(),
8277
+ from,
8278
+ create,
8279
+ // a provision spec decides the cwd server-side — don't send a stale one
8280
+ cwd: from ? "" : $("nf-cwd").value.trim(),
8175
8281
  prompt: $("nf-prompt").value,
8176
8282
  };
8177
8283
  const room = $("newform").dataset.room || undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.261.1",
3
+ "version": "1.262.0",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "ai",
package/ts/serve.ts CHANGED
@@ -532,6 +532,43 @@ function originOwnerRepo(cwd: string): { owner: string; repo: string } | null {
532
532
  }
533
533
  }
534
534
 
535
+ // Run a host command and capture its output — used by the /api/ws/repos and
536
+ // /api/ws/branches listing endpoints (git ls-remote / gh). Runs under the
537
+ // recovered login-shell env (freshAgentEnv) because the oxmgr/launchd daemon's
538
+ // raw PATH lacks Homebrew/bun, so `git`/`gh` would otherwise be missing — the
539
+ // same reason runProvisionHook does this. Never throws; a timeout kills the
540
+ // child and reports ok:false.
541
+ async function runCapture(
542
+ argv: string[],
543
+ opts?: { cwd?: string; timeoutMs?: number },
544
+ ): Promise<{ ok: boolean; stdout: string; stderr: string }> {
545
+ try {
546
+ const child = Bun.spawn(argv, {
547
+ cwd: opts?.cwd,
548
+ env: freshAgentEnv(),
549
+ stdin: "ignore",
550
+ stdout: "pipe",
551
+ stderr: "pipe",
552
+ });
553
+ const timeoutMs = opts?.timeoutMs ?? 15_000;
554
+ const code = await Promise.race([
555
+ child.exited,
556
+ new Promise<number>((r) => setTimeout(() => r(124), timeoutMs)),
557
+ ]);
558
+ if (code === 124) child.kill();
559
+ const [stdout, stderr] = await Promise.all([
560
+ new Response(child.stdout).text(),
561
+ new Response(child.stderr).text(),
562
+ ]);
563
+ return { ok: code === 0, stdout, stderr };
564
+ } catch (e) {
565
+ return { ok: false, stdout: "", stderr: (e as Error).message };
566
+ }
567
+ }
568
+
569
+ // 60s memo for /api/ws/repos' gh side (see the endpoint for why).
570
+ let ghRepoListMemo: { t: number; ok: boolean; repos: string[]; error?: string } | null = null;
571
+
535
572
  type ProvisionHookResult =
536
573
  | { ran: false }
537
574
  | { ran: true; ok: boolean; code: number | null; detail: string };
@@ -3062,6 +3099,159 @@ export async function cmdServe(rest: string[]): Promise<number> {
3062
3099
  }
3063
3100
  }
3064
3101
 
3102
+ // GET /api/ws/repos — the repos this host can provision from: every
3103
+ // owner/repo already present under the workspace layout (with its
3104
+ // provisioned branches), plus — best-effort — the repos `gh repo list` can
3105
+ // see with this host's auth. gh being missing/unauthenticated must never
3106
+ // fail the endpoint (two-account gh setups break routinely); the UI gets
3107
+ // `gh.ok=false` + a short reason and still renders the local repos.
3108
+ if (req.method === "GET" && p === "/api/ws/repos") {
3109
+ const ws = await import("./ws.ts");
3110
+ try {
3111
+ await ws.loadProvision();
3112
+ } catch (e) {
3113
+ return new Response((e as Error).message, { status: 501 });
3114
+ }
3115
+ let wsRoot: string;
3116
+ let workspaces: Awaited<ReturnType<typeof ws.collectWorkspaces>>["workspaces"];
3117
+ try {
3118
+ ({ wsRoot, workspaces } = await ws.collectWorkspaces());
3119
+ } catch (e) {
3120
+ return new Response(`workspace walk failed: ${(e as Error).message}`, { status: 500 });
3121
+ }
3122
+ const byRepo = new Map<
3123
+ string,
3124
+ { owner: string; repo: string; local: boolean; branches: { name: string; path: string }[] }
3125
+ >();
3126
+ for (const w of workspaces) {
3127
+ const key = `${w.owner}/${w.repo}`;
3128
+ const entry = byRepo.get(key) ?? { owner: w.owner, repo: w.repo, local: true, branches: [] };
3129
+ entry.branches.push({ name: w.branch, path: w.path });
3130
+ byRepo.set(key, entry);
3131
+ }
3132
+ // gh repo list is slow (network + up to 10s timeout) and the UI hits this
3133
+ // endpoint on every form open / host switch — memoize the gh side briefly.
3134
+ const gh: { ok: boolean; error?: string } = { ok: false };
3135
+ let ghRepos: string[] = [];
3136
+ const memo = ghRepoListMemo;
3137
+ if (memo && performance.now() - memo.t < 60_000) {
3138
+ gh.ok = memo.ok;
3139
+ if (memo.error) gh.error = memo.error;
3140
+ ghRepos = memo.repos;
3141
+ } else {
3142
+ const r = await runCapture(
3143
+ ["gh", "repo", "list", "--limit", "200", "--json", "nameWithOwner"],
3144
+ { timeoutMs: 10_000 },
3145
+ );
3146
+ if (r.ok) {
3147
+ try {
3148
+ ghRepos = (JSON.parse(r.stdout) as { nameWithOwner: string }[]).map(
3149
+ (x) => x.nameWithOwner,
3150
+ );
3151
+ gh.ok = true;
3152
+ } catch {
3153
+ gh.error = "gh returned unparseable JSON";
3154
+ }
3155
+ } else {
3156
+ gh.error = (r.stderr.trim() || "gh unavailable").slice(0, 200);
3157
+ }
3158
+ ghRepoListMemo = { t: performance.now(), ok: gh.ok, repos: ghRepos, error: gh.error };
3159
+ }
3160
+ for (const nameWithOwner of ghRepos) {
3161
+ const [owner, repo] = nameWithOwner.split("/");
3162
+ if (owner && repo && !byRepo.has(nameWithOwner))
3163
+ byRepo.set(nameWithOwner, { owner, repo, local: false, branches: [] });
3164
+ }
3165
+ const repos = [...byRepo.values()].sort((a, b) =>
3166
+ // provisioned repos first, then alphabetical — the picker's natural order
3167
+ a.local !== b.local
3168
+ ? a.local
3169
+ ? -1
3170
+ : 1
3171
+ : `${a.owner}/${a.repo}`.localeCompare(`${b.owner}/${b.repo}`),
3172
+ );
3173
+ return Response.json({ schema: ws.WS_JSON_SCHEMA, wsRoot, repos, gh });
3174
+ }
3175
+
3176
+ // GET /api/ws/branches?repo=<owner>/<repo> — the branches a provision of
3177
+ // that repo could target. Remote branches come from `git ls-remote --heads
3178
+ // origin` run inside an existing local checkout (uses that checkout's
3179
+ // credentials), falling back to `gh api .../branches` when the repo has no
3180
+ // local checkout yet. Local-only branches (provisioned but never pushed)
3181
+ // are merged in. The repo param is strictly validated and passed as argv —
3182
+ // these endpoints are reachable with just a share token.
3183
+ if (req.method === "GET" && p === "/api/ws/branches") {
3184
+ const repoParam = url.searchParams.get("repo") ?? "";
3185
+ const m = /^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/.exec(repoParam);
3186
+ // "." / ".." pass the charset but would traverse the `gh api repos/…` URL
3187
+ if (!m || m[1] === "." || m[1] === ".." || m[2] === "." || m[2] === "..")
3188
+ return new Response("missing/invalid ?repo=<owner>/<repo>", { status: 400 });
3189
+ const [, owner, repo] = m as unknown as [string, string, string];
3190
+ const ws = await import("./ws.ts");
3191
+ let prov: Awaited<ReturnType<typeof ws.loadProvision>>;
3192
+ try {
3193
+ prov = await ws.loadProvision();
3194
+ } catch (e) {
3195
+ return new Response((e as Error).message, { status: 501 });
3196
+ }
3197
+ const wsRoot = prov.resolveWsRoot(getProvisionRoot());
3198
+ // Provisioned local checkouts of this repo (branch → path).
3199
+ const localByBranch = new Map<string, string>();
3200
+ try {
3201
+ for (const w of await ws.walkWorkspaces(wsRoot)) {
3202
+ if (w.owner === owner && w.repo === repo) localByBranch.set(w.branch, w.path);
3203
+ }
3204
+ } catch {
3205
+ /* no local checkouts is fine */
3206
+ }
3207
+ let remote: string[] = [];
3208
+ let source = "";
3209
+ let error: string | undefined;
3210
+ const anchor = localByBranch.values().next().value as string | undefined;
3211
+ if (anchor) {
3212
+ const r = await runCapture(["git", "-C", anchor, "ls-remote", "--heads", "origin"]);
3213
+ if (r.ok) {
3214
+ remote = [...r.stdout.matchAll(/\trefs\/heads\/(.+)/g)].map((x) => x[1]!.trim());
3215
+ source = "ls-remote";
3216
+ } else {
3217
+ error = (r.stderr.trim() || "git ls-remote failed").slice(0, 200);
3218
+ }
3219
+ }
3220
+ if (!source) {
3221
+ const r = await runCapture([
3222
+ "gh",
3223
+ "api",
3224
+ `repos/${owner}/${repo}/branches`,
3225
+ "--paginate",
3226
+ "--jq",
3227
+ ".[].name",
3228
+ ]);
3229
+ if (r.ok) {
3230
+ remote = r.stdout.split("\n").map((s) => s.trim()).filter(Boolean);
3231
+ source = "gh";
3232
+ error = undefined;
3233
+ } else if (!error) {
3234
+ error = (r.stderr.trim() || "gh unavailable").slice(0, 200);
3235
+ }
3236
+ }
3237
+ const names = [...new Set([...remote, ...localByBranch.keys()])].sort((a, b) =>
3238
+ a.localeCompare(b),
3239
+ );
3240
+ const branches = names.map((name) => ({
3241
+ name,
3242
+ remote: remote.includes(name),
3243
+ provisioned: localByBranch.has(name),
3244
+ ...(localByBranch.has(name) ? { path: localByBranch.get(name)! } : {}),
3245
+ }));
3246
+ return Response.json({
3247
+ schema: ws.WS_JSON_SCHEMA,
3248
+ repo: `${owner}/${repo}`,
3249
+ source: source || "local-only",
3250
+ branches,
3251
+ ...(error ? { error } : {}),
3252
+ });
3253
+ }
3254
+
3065
3255
  // GET /api/notes
3066
3256
  if (req.method === "GET" && p === "/api/notes") {
3067
3257
  const notes = await readNotes();
@@ -3833,6 +4023,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
3833
4023
  from?: string;
3834
4024
  prompt?: string;
3835
4025
  yes?: boolean;
4026
+ create?: boolean;
3836
4027
  fork?: { fromCwd?: string; branch?: string };
3837
4028
  };
3838
4029
  try {
@@ -3978,7 +4169,11 @@ export async function cmdServe(rest: string[]): Promise<number> {
3978
4169
  provision: (
3979
4170
  spec: Spec,
3980
4171
  opts?: { wsRoot?: string },
3981
- ) => Promise<{ ok: boolean; folder: string; action: string; error?: string }>;
4172
+ ) => Promise<{ ok: boolean; folder: string; action: string; error?: string; reason?: string }>;
4173
+ createBranch?: (
4174
+ spec: Spec,
4175
+ opts?: { wsRoot?: string },
4176
+ ) => Promise<{ ok: boolean; folder: string; action: string; error?: string; reason?: string }>;
3982
4177
  };
3983
4178
  try {
3984
4179
  prov = (await importProvisionModule()) as typeof prov;
@@ -4029,14 +4224,32 @@ export async function cmdServe(rest: string[]): Promise<number> {
4029
4224
  { status: 403 },
4030
4225
  );
4031
4226
  }
4032
- let result: { ok: boolean; folder: string; action: string; error?: string };
4227
+ let result: { ok: boolean; folder: string; action: string; error?: string; reason?: string };
4033
4228
  try {
4034
4229
  const wsRoot = getProvisionRoot();
4035
4230
  result = await prov.provision(spec, wsRoot ? { wsRoot } : undefined);
4231
+ // `create:true` = the "ay ws new --create" semantics: when the branch
4232
+ // doesn't exist on the remote, branch it off the default locally.
4233
+ // Runs INSIDE the hook/allowlist gate above — same repo, same risk.
4234
+ if (
4235
+ !result?.ok &&
4236
+ body.create === true &&
4237
+ result?.reason === "branch-not-found" &&
4238
+ typeof prov.createBranch === "function"
4239
+ ) {
4240
+ result = await prov.createBranch(spec, wsRoot ? { wsRoot } : undefined);
4241
+ }
4036
4242
  } catch (e) {
4037
4243
  return new Response(`provision failed: ${(e as Error).message}`, { status: 502 });
4038
4244
  }
4039
- if (!result?.ok) return new Response(result?.error ?? "provision failed", { status: 502 });
4245
+ if (!result?.ok)
4246
+ return new Response(
4247
+ (result?.error ?? "provision failed") +
4248
+ (result?.reason === "branch-not-found" && body.create !== true
4249
+ ? "\n(branch missing on the remote — retry with create:true to branch off the default)"
4250
+ : ""),
4251
+ { status: 502 },
4252
+ );
4040
4253
  cwd = result.folder;
4041
4254
  provisioned = { action: result.action, folder: result.folder };
4042
4255
  } else {
@@ -1,5 +0,0 @@
1
- import "./versionChecker-d15cc3u7.js";
2
- import "./rustBinary-BBzI-0gG.js";
3
- import { a as trayHiddenMarker, i as launchTray, n as hasDesktop, r as isTrayHidden, t as cmdTray } from "./trayApp-DO9sPIPo.js";
4
-
5
- export { cmdTray };