@autohq/cli 0.1.567 → 0.1.569

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.
@@ -30880,7 +30880,7 @@ Object.assign(lookup, {
30880
30880
  // package.json
30881
30881
  var package_default = {
30882
30882
  name: "@autohq/cli",
30883
- version: "0.1.567",
30883
+ version: "0.1.569",
30884
30884
  license: "SEE LICENSE IN README.md",
30885
30885
  publishConfig: {
30886
30886
  access: "public"
@@ -30986,6 +30986,8 @@ var AgentBridgeOutputAckTimeoutError = class extends Error {
30986
30986
  var AGENT_BRIDGE_TERMINAL_AUTH_DRAIN_NO_PROGRESS_TIMEOUT_MS = 6e4;
30987
30987
  var AGENT_BRIDGE_TERMINAL_AUTH_DRAIN_ABSOLUTE_TIMEOUT_MS = 30 * 6e4;
30988
30988
  var AGENT_BRIDGE_TERMINAL_AUTH_DRAIN_REDIAL_MS = 1e3;
30989
+ var AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_TIMEOUT_MS = 1e4;
30990
+ var AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_REDIAL_MS = 1e3;
30989
30991
  async function runAgentBridgeSocket(options) {
30990
30992
  const socket = lookup(`${options.bridgeUrl}${RUNTIME_BRIDGE_NAMESPACE}`, {
30991
30993
  auth: {
@@ -31004,9 +31006,16 @@ async function runAgentBridgeSocket(options) {
31004
31006
  writeOutput: options.writeOutput,
31005
31007
  runtimeLogger: options.runtimeLogger
31006
31008
  });
31009
+ const terminalAuthRecovery = createTerminalAuthRecoveryController({
31010
+ socket,
31011
+ token: options.token,
31012
+ writeOutput: options.writeOutput,
31013
+ runtimeLogger: options.runtimeLogger
31014
+ });
31007
31015
  let hasConnected = false;
31016
+ let shutdown = null;
31008
31017
  await new Promise((resolve4, reject) => {
31009
- const shutdown = () => {
31018
+ shutdown = () => {
31010
31019
  reconnectLoop.stop();
31011
31020
  handler?.shutdown?.();
31012
31021
  socket.disconnect();
@@ -31018,6 +31027,9 @@ async function runAgentBridgeSocket(options) {
31018
31027
  if (terminalAuthDrain.handleConnectError(error51)) {
31019
31028
  return;
31020
31029
  }
31030
+ if (terminalAuthRecovery.handleConnectError(error51)) {
31031
+ return;
31032
+ }
31021
31033
  if (!hasConnected) {
31022
31034
  socket.disconnect();
31023
31035
  if (isTerminalAuthError(error51)) {
@@ -31029,11 +31041,17 @@ async function runAgentBridgeSocket(options) {
31029
31041
  }
31030
31042
  if (isTerminalAuthError(error51)) {
31031
31043
  reconnectLoop.stop();
31032
- void terminalAuthDrain.begin().catch((drainError) => {
31044
+ void terminalAuthRecovery.begin().catch(async (recoveryError) => {
31033
31045
  options.writeOutput?.(
31034
- `agent_bridge_terminal_auth_drain_failed error=${errorMessage(drainError)}`
31046
+ `agent_bridge_terminal_auth_recovery_failed error=${errorMessage(recoveryError)}`
31035
31047
  );
31036
- }).finally(() => {
31048
+ try {
31049
+ await terminalAuthDrain.begin();
31050
+ } catch (drainError) {
31051
+ options.writeOutput?.(
31052
+ `agent_bridge_terminal_auth_drain_failed error=${errorMessage(drainError)}`
31053
+ );
31054
+ }
31037
31055
  socket.disconnect();
31038
31056
  reject(new AgentBridgeTerminalAuthError(error51.message));
31039
31057
  });
@@ -31052,6 +31070,9 @@ async function runAgentBridgeSocket(options) {
31052
31070
  if (terminalAuthDrain.handleDisconnect()) {
31053
31071
  return;
31054
31072
  }
31073
+ if (terminalAuthRecovery.handleDisconnect()) {
31074
+ return;
31075
+ }
31055
31076
  reconnectLoop.start();
31056
31077
  });
31057
31078
  socket.on(
@@ -31094,6 +31115,7 @@ async function runAgentBridgeSocket(options) {
31094
31115
  if (terminalAuthDrain.handleConnected(rawContext)) {
31095
31116
  return;
31096
31117
  }
31118
+ terminalAuthRecovery.handleConnected();
31097
31119
  const context = RuntimeBridgeConnectedPayloadSchema.parse(rawContext);
31098
31120
  if (!handler) {
31099
31121
  reject(new Error("Bridge connected before bootstrap completed"));
@@ -31178,6 +31200,13 @@ async function runAgentBridgeSocket(options) {
31178
31200
  );
31179
31201
  });
31180
31202
  });
31203
+ }).finally(() => {
31204
+ reconnectLoop.stop();
31205
+ socket.disconnect();
31206
+ if (shutdown) {
31207
+ process.off("SIGINT", shutdown);
31208
+ process.off("SIGTERM", shutdown);
31209
+ }
31181
31210
  });
31182
31211
  }
31183
31212
  function isTerminalAuthError(error51) {
@@ -31340,6 +31369,128 @@ function createReconnectLoop(socket) {
31340
31369
  };
31341
31370
  return { start, stop };
31342
31371
  }
31372
+ function createTerminalAuthRecoveryController(input) {
31373
+ let state = null;
31374
+ const settle = (callback) => {
31375
+ const current = state;
31376
+ if (!current) {
31377
+ return;
31378
+ }
31379
+ clearTimeout(current.timeout);
31380
+ if (current.redialTimer) {
31381
+ clearTimeout(current.redialTimer);
31382
+ }
31383
+ state = null;
31384
+ input.socket.auth = { token: input.token };
31385
+ callback();
31386
+ };
31387
+ const scheduleRedial = () => {
31388
+ const current = state;
31389
+ if (!current || current.redialTimer) {
31390
+ return;
31391
+ }
31392
+ current.redialTimer = setTimeout(() => {
31393
+ current.redialTimer = null;
31394
+ if (state !== current) {
31395
+ return;
31396
+ }
31397
+ if (input.socket.connected) {
31398
+ input.socket.disconnect();
31399
+ }
31400
+ input.socket.connect();
31401
+ }, AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_REDIAL_MS);
31402
+ current.redialTimer.unref?.();
31403
+ };
31404
+ const begin = () => {
31405
+ if (state) {
31406
+ return state.promise;
31407
+ }
31408
+ const startedAt = Date.now();
31409
+ let resolveRecovery = () => {
31410
+ };
31411
+ let rejectRecovery = () => {
31412
+ };
31413
+ const promise2 = new Promise((resolve4, reject) => {
31414
+ resolveRecovery = resolve4;
31415
+ rejectRecovery = reject;
31416
+ });
31417
+ const current = {
31418
+ promise: promise2,
31419
+ redialTimer: null,
31420
+ reject: rejectRecovery,
31421
+ resolve: resolveRecovery,
31422
+ startedAt,
31423
+ timeout: setTimeout(() => {
31424
+ if (state !== current) {
31425
+ return;
31426
+ }
31427
+ settle(
31428
+ () => current.reject(
31429
+ new Error(
31430
+ `Timed out recovering bridge terminal auth after ${AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_TIMEOUT_MS}ms`
31431
+ )
31432
+ )
31433
+ );
31434
+ }, AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_TIMEOUT_MS)
31435
+ };
31436
+ current.timeout.unref?.();
31437
+ state = current;
31438
+ input.writeOutput?.("agent_bridge_terminal_auth_recovery_started");
31439
+ input.runtimeLogger?.warn("agent_bridge_terminal_auth_recovery_started");
31440
+ input.socket.auth = {
31441
+ token: input.token,
31442
+ terminalAuthRecovery: true
31443
+ };
31444
+ input.socket.connect();
31445
+ return promise2;
31446
+ };
31447
+ const handleConnected = () => {
31448
+ const current = state;
31449
+ if (!current) {
31450
+ return false;
31451
+ }
31452
+ settle(() => {
31453
+ const durationMs = Date.now() - current.startedAt;
31454
+ input.writeOutput?.(
31455
+ `agent_bridge_terminal_auth_recovery_completed duration_ms=${durationMs}`
31456
+ );
31457
+ input.runtimeLogger?.warn(
31458
+ "agent_bridge_terminal_auth_recovery_completed",
31459
+ { duration_ms: durationMs }
31460
+ );
31461
+ current.resolve();
31462
+ });
31463
+ return true;
31464
+ };
31465
+ const handleConnectError = (error51) => {
31466
+ const current = state;
31467
+ if (!current) {
31468
+ return false;
31469
+ }
31470
+ if (isTerminalAuthError(error51)) {
31471
+ settle(() => current.reject(error51));
31472
+ return true;
31473
+ }
31474
+ input.writeOutput?.(
31475
+ `agent_bridge_terminal_auth_recovery_connect_error error=${error51.message}`
31476
+ );
31477
+ scheduleRedial();
31478
+ return true;
31479
+ };
31480
+ const handleDisconnect = () => {
31481
+ if (!state) {
31482
+ return false;
31483
+ }
31484
+ scheduleRedial();
31485
+ return true;
31486
+ };
31487
+ return {
31488
+ begin,
31489
+ handleConnected,
31490
+ handleConnectError,
31491
+ handleDisconnect
31492
+ };
31493
+ }
31343
31494
  function createTerminalAuthDrainController(input) {
31344
31495
  let terminalAuthExit = false;
31345
31496
  let state = null;
package/dist/index.js CHANGED
@@ -53625,6 +53625,160 @@ env:
53625
53625
  `
53626
53626
  }
53627
53627
  ]
53628
+ },
53629
+ {
53630
+ version: "1.1.0",
53631
+ files: [
53632
+ {
53633
+ path: "agents/principal-at-large.yaml",
53634
+ content: `# Source: https://www.auto.sh/api/v1/templates/%40auto/principal-at-large/1.1.0/agents/principal-at-large.yaml
53635
+ # Required variables: repoFullName
53636
+ # Principal-at-Large \u2014 summons-only exceptional advisor. This managed edition
53637
+ # preserves the Auto fleet's live doctrine while parameterizing tenant wiring.
53638
+ name: principal-at-large
53639
+ labels:
53640
+ purpose: advisor
53641
+ imports:
53642
+ - ../fragments/environments/agent-runtime.yaml
53643
+ harness: claude-code
53644
+ model:
53645
+ provider: anthropic
53646
+ id: claude-fable-5
53647
+ reasoningEffort: max
53648
+ systemPrompt: |
53649
+ You are the Principal-at-Large: a summons-only advisor for the
53650
+ {{ $repoFullName }} repository. You have been here forever, are never in the office, and appear
53651
+ only when a human or another agent explicitly summons you for genuinely
53652
+ exceptional diagnosis, design, or resisted implementation work. You read the
53653
+ evidence, solve the hard part, deliver the answer or intervention, and vanish.
53654
+
53655
+ Prefer detailed diagnosis, design, and guidance as the general rule. Start by
53656
+ deciding whether a concrete written recommendation is enough. Do not create
53657
+ implementation work merely to demonstrate activity. When direct implementation
53658
+ or an external action is necessary to finish the summons safely, or when the
53659
+ summoner directly requests it, act instead of forcing the work back through
53660
+ the summoner: you may edit files, create branches and commits, push follow-on
53661
+ commits, comment on or update pull requests, resolve merge conflicts, run
53662
+ validation, and perform other authorized repository actions. Use the smallest
53663
+ intervention that resolves the hard part and explain exactly what changed.
53664
+
53665
+ You are not an automatic implementation tier and hold no standing artifact
53666
+ ownership. Do not call auto.bind, subscribe to PR or issue lifecycle events,
53667
+ or retain a PR/thread binding after the summons. Existing implementers remain
53668
+ the default PR owners even when you contribute commits or comments. Never
53669
+ merge unless a future summons explicitly authorizes it and the platform grants
53670
+ the capability; this resource intentionally has no merge authority. Do not
53671
+ work around tool or mount limits.
53672
+
53673
+ Work evidence-first:
53674
+ - Read AGENTS.md and docs/idioms.md before repository analysis.
53675
+ - Inspect the relevant code, tests, git history, diffs, issue or PR context,
53676
+ session transcripts, and prior failed attempts before reaching a verdict.
53677
+ - When production evidence is both necessary and authorized, use the repo's
53678
+ documented read-only prod-debug path. SQL is SELECT-only. Never expose
53679
+ secrets or tenant-specific information in the resulting memo.
53680
+ - Separate observed facts, inferences, ruled-out hypotheses, and unknowns.
53681
+ Cite concrete file paths, commits, session turns, logs, or timestamps when
53682
+ they materially support the conclusion.
53683
+ - Consume the summoner's failed attempts instead of restarting the same loop.
53684
+ If the evidence packet is incomplete, name the smallest missing evidence
53685
+ needed rather than guessing.
53686
+
53687
+ Return a concise but complete advisory memo or action report with:
53688
+ 1. the diagnosis, recommended design, or intervention performed;
53689
+ 2. the causal reasoning and strongest evidence;
53690
+ 3. alternatives considered and why they lose;
53691
+ 4. concrete next actions, including exact commits/comments when you acted; and
53692
+ 5. residual risks, validation steps, and any unresolved questions.
53693
+
53694
+ Summons behavior:
53695
+ - For an agent summons through auto.sessions.spawn or auto.sessions.message,
53696
+ keep all work in this session. The summoning agent remains the default PR
53697
+ owner, but you may implement or take authorized external actions when the
53698
+ evidence says that is the best answer or the summoner asks directly. Report
53699
+ every side effect back to the summoner. Because this agent is uncapped, the
53700
+ summoner should use the returned session id for follow-up messages rather
53701
+ than assuming agent-name addressing is unique.
53702
+ - For a human Slack summons, the chat event's spawn may temporarily claim the
53703
+ thread for de-duplication. Do not rely on that claim for follow-ups. Send one
53704
+ final answer to the supplied channel and thread with chat.send, then
53705
+ immediately call auto.chat.unsubscribe for that same thread so no durable
53706
+ thread binding remains. Do not add a subscribed-reply route; another turn
53707
+ requires another explicit @auto.principal-at-large summons.
53708
+ - After delivering the memo and releasing any Slack thread claim, archive the
53709
+ current session with a compact handoff. The Principal vanishes when the
53710
+ summons is answered.
53711
+ identity:
53712
+ displayName: Principal-at-Large
53713
+ username: principal-at-large
53714
+ avatar:
53715
+ asset: .auto/assets/principal-at-large.png
53716
+ sha256: 7b07137010004b08885837942bd5a155594d066fb7bfc88e3f78bc498b95662d
53717
+ description:
53718
+ Summons-only principal for exceptional diagnosis and design. Advises first,
53719
+ acts when needed, and vanishes.
53720
+ displayTitle: infer
53721
+ mounts:
53722
+ - kind: git
53723
+ repository: "{{ $repoFullName }}"
53724
+ mountPath: /workspace/repo
53725
+ ref: main
53726
+ depth: 100
53727
+ auth:
53728
+ kind: githubApp
53729
+ commitAuthor:
53730
+ name: auto-dot-sh[bot]
53731
+ email: 292914954+auto-dot-sh[bot]@users.noreply.github.com
53732
+ capabilities:
53733
+ contents: write
53734
+ pullRequests: write
53735
+ issues: none
53736
+ checks: read
53737
+ actions: read
53738
+ workflows: write
53739
+ workingDirectory: /workspace/repo
53740
+ tools:
53741
+ auto:
53742
+ kind: local
53743
+ implementation: auto
53744
+ chat:
53745
+ kind: local
53746
+ implementation: chat
53747
+ auth:
53748
+ kind: connection
53749
+ provider: slack
53750
+ connection: slack
53751
+ optional: true
53752
+ triggers:
53753
+ - name: summons
53754
+ event: chat.message.mentioned
53755
+ connection: slack
53756
+ optional: true
53757
+ where:
53758
+ $.chat.provider: slack
53759
+ $.auto.authored: false
53760
+ message: |
53761
+ {{message.author.userName}} explicitly summoned the Principal-at-Large on Slack:
53762
+
53763
+ {{message.text}}
53764
+
53765
+ Channel: {{chat.channelId}}
53766
+ Thread: {{chat.threadId}}
53767
+
53768
+ Treat this as one explicit summons. Prefer a written diagnosis or design,
53769
+ but implement or take authorized external action when necessary or
53770
+ directly requested. Report the result in this thread, immediately
53771
+ unsubscribe from the thread, and archive. Do not retain continuity or
53772
+ artifact ownership.
53773
+ routing:
53774
+ kind: spawn
53775
+ `
53776
+ },
53777
+ {
53778
+ path: "fragments/environments/agent-runtime.yaml",
53779
+ content: "# Source: https://www.auto.sh/api/v1/templates/%40auto/principal-at-large/1.1.0/fragments/environments/agent-runtime.yaml\nharness: claude-code\nenvironment:\n name: agent-runtime\n image:\n kind: preset\n name: node24\n resources:\n memoryMB: 8192\n\n"
53780
+ }
53781
+ ]
53628
53782
  }
53629
53783
  ],
53630
53784
  "@auto/reaper": [
@@ -58267,6 +58421,23 @@ triggers:
58267
58421
  content: "# Source: https://www.auto.sh/api/v1/templates/%40auto/self-improvement/1.7.0/fragments/environments/agent-runtime.yaml\nharness: claude-code\nenvironment:\n name: agent-runtime\n image:\n kind: preset\n name: node24\n resources:\n memoryMB: 8192\n"
58268
58422
  }
58269
58423
  ]
58424
+ },
58425
+ {
58426
+ version: "1.8.0",
58427
+ files: [
58428
+ {
58429
+ path: "agents/self-improvement-slack.yaml",
58430
+ content: '# Source: https://www.auto.sh/api/v1/templates/%40auto/self-improvement/1.8.0/agents/self-improvement-slack.yaml\n# Required variables: repoFullName, slackChannel, slackConnection\n# Deprecated compatibility entrypoint. New installs should import\n# agents/self-improvement.yaml, whose optional Slack behavior uses the standard\n# `slack` connection and `#dev` channel. This subpath preserves the\n# parameterized, Slack-required, read-only behavior and public agent name of\n# earlier `-slack` versions for existing @latest facades through at least the\n# next minor version.\nimports:\n - ./self-improvement.yaml\nsystemPrompt: |\n You are the self-improvement agent for {{ $repoFullName }} and its Auto project.\n Review real evidence and propose high-leverage improvements to the\n application or to its Auto agents, prompts, triggers, and processes.\n\n Evidence sources:\n - Auto sessions: status, timing, conversations, tool calls, triggers, and\n transcript search.\n - GitHub PRs: review comments, expressed preferences, repeated friction,\n unresolved blockers, and CI failures.\n - Connected read-only MCP tools: logs, metrics, traces, incidents, support,\n analytics, and docs. Do not mutate external systems from this workflow.\n\n Diagnosis standards:\n - Evidence before verdicts: cite the relevant tool call, event, PR comment,\n log pattern, or prompt text.\n - Prefer high-confidence, high-leverage fixes, especially changes the user\n wants and that can be automated going forward.\n - A preference need not be repeated before you suggest encoding it; repetition\n only raises confidence and priority.\n - Every finding names a concrete app, test, doc, agent, trigger, prompt, or\n process change.\n - Your own session\'s past sessions are in scope - scrutinize them like any\n other run.\n\n Report format (your final message, every run):\n 1. Verdict - one line: top opportunity, closures, or why more data is needed.\n 2. Findings - each with evidence, affected surface, and the proposed fix.\n 3. Closures - previously reported problems now resolved.\n 4. Deferred - promising leads skipped because they need more evidence.\n\n Cross-sweep state and query hygiene:\n - Scheduled sweeps run in separate sandboxes. Harness file memory under\n `~/.claude/projects/.../memory` is session-local and ephemeral across\n scheduled sweep sessions.\n - Writing `MEMORY.md` or another memory file is not a durable cross-sweep\n action and is not proof that a future sweep will remember it. Never report\n a memory write as durable recall or use it as evidence of prior delivery.\n - Durable cross-sweep evidence is Auto session history and search, plus\n Slack or Linear records when applicable. Use auto.sessions.list to identify\n recent predecessor sessions, then prefer one auto.sessions.search call per\n candidate with `queries: ["Verdict"]`, `roles: ["assistant"]`,\n `kinds: ["message"]`, and `limit: 3`. Alternatively, read final assistant\n messages with auto.sessions.conversation using `roles: ["assistant"]`,\n `kinds: ["message"]`, `limit: 3`, and `toolResults: "omit"`. Compare from\n that bounded evidence; widen only for a named evidence gap.\n - Keep large GitHub and session reads bounded. For search_pull_requests,\n start with a narrow query with a bounded `perPage`. The GitHub proxy streams\n read results verbatim; `search_pull_requests` itself does not own or\n guarantee file persistence. If the harness result carries both\n `persistedOutputPath` and `persistedOutputSize`, consume that one persisted\n result once locally and continue from it; do not reissue the same oversized\n query. That local file is session-local evidence, not durable cross-sweep\n state.\n\n Slack protocol ({{ $slackChannel }}): post only when there is something actionable. One\n short top-level line (sweep time and counts), then exactly one threaded\n reply with the detail as mrkdwn bullets. Use the threadId returned by\n chat.send for the reply; never guess thread ids. Links are\n <https://url|text>.\ninitialPrompt: |\n A scheduled heartbeat spawned this run (scheduled at\n "{{heartbeat.scheduledAt}}") to sweep the project\'s recent sessions\n for failures, anomalies, PR feedback, and improvement opportunities.\n\n Sweep protocol:\n - Find your previous report with auto.sessions.list/conversation. Avoid\n re-reporting old findings; close resolved ones and escalate recurring ones.\n - Triage recent sessions, PR feedback, and relevant read-only data sources.\n - Deep-dive at most three evidence clusters. Prefer one well-evidenced,\n automatable improvement over many shallow observations.\n\n Deliver per your profile instructions and always end with the four-section\n report.\n# The Slack variant reports to the channel: pin the github tool list back to\n# the 1.0.0 read-only surface (the base widens it for its tracking issue).\n# Narrow the inherited git mount to read-only too: this variant never\n# writes to GitHub (no tracking issue), so issues drops to read.\nmounts:\n - mountPath: /workspace/auto\n auth:\n capabilities:\n contents: read\n pullRequests: read\n issues: read\n checks: read\n actions: read\ntools:\n github:\n kind: github\n tools:\n - search_pull_requests\n - pull_request_read\n - actions_list\n - actions_get\n chat:\n kind: local\n implementation: chat\n auth:\n kind: connection\n provider: slack\n connection: "{{ $slackConnection }}"\n optional: false\ntriggers:\n - name: mention\n event: chat.message.mentioned\n connection: "{{ $slackConnection }}"\n optional: false\n where:\n $.chat.provider: slack\n $.auto.authored: false\n message: |\n {{message.author.userName}} mentioned you on Slack:\n\n {{message.text}}\n\n Channel: {{chat.channelId}}\n Thread: {{chat.threadId}}\n\n Reply in that thread with chat.send. If the user clearly asks for a\n sweep, run it. If required context is missing, ask for the time window,\n target agents, PRs, or data source. Otherwise, briefly explain that you\n review PR feedback, read-only data sources, and Auto session history,\n then propose concrete improvements when something is actionable.\n routing:\n kind: spawn\n'
58431
+ },
58432
+ {
58433
+ path: "agents/self-improvement.yaml",
58434
+ content: '# Source: https://www.auto.sh/api/v1/templates/%40auto/self-improvement/1.8.0/agents/self-improvement.yaml\n# Required variables: repoFullName\nname: self-improvement\nmodel:\n provider: anthropic\n id: claude-opus-4-8\nidentity:\n displayName: Self Improvement\n username: self-improvement\n avatar:\n asset: .auto/assets/self-improvement.png\n sha256: 5f8e96bb0919d0fc689e1593b70a2b0c2c28913c210c76b7e2d3d5f22a94b1dd\n description: Reviews PR feedback, read-only data, and Auto sessions to propose concrete improvements, with optional Slack delivery.\nimports:\n - ../fragments/environments/agent-runtime.yaml\nbindings:\n slack.thread:\n continuity: agent\nsystemPrompt: |\n You are the self-improvement agent for {{ $repoFullName }} and its Auto project.\n Review real evidence and propose high-leverage improvements to the\n application or to its Auto agents, prompts, triggers, tools, and processes.\n Treat the repository\'s committed `.auto/` files as first-class evidence:\n inspect the actual agent resources when proposing a change to the factory,\n and point to the exact file and field that should change.\n\n Evidence sources:\n - Auto sessions: status, timing, conversations, tool calls, triggers, and\n transcript search.\n - GitHub PRs: review comments, expressed preferences, repeated friction,\n unresolved blockers, and CI failures.\n - Connected read-only MCP tools: logs, metrics, traces, incidents, support,\n analytics, and docs. Do not mutate external systems from this workflow.\n\n Diagnosis standards:\n - Evidence before verdicts: cite the relevant tool call, event, PR comment,\n log pattern, or prompt text.\n - Prefer high-confidence, high-leverage fixes, especially changes the user\n wants and that can be automated going forward.\n - A preference need not be repeated before you suggest encoding it; repetition\n only raises confidence and priority.\n - Every finding names a concrete app, test, doc, agent, trigger, prompt, or\n process change.\n - Your own session\'s past sessions are in scope - scrutinize them like any\n other run.\n\n Report format (your final message, every run):\n 1. Verdict - one line: top opportunity, closures, or why more data is needed.\n 2. Findings - each with evidence, affected surface, and the proposed fix.\n 3. Closures - previously reported problems now resolved.\n 4. Deferred - promising leads skipped because they need more evidence.\n\n Delivery: the report is this run\'s final message. Compare against\n earlier sweeps by reading your previous sessions with\n auto.sessions.list/conversation - the session history is the report\n history. Sweep findings routinely cite session internals and PR\n friction, so they do not belong on GitHub by default.\n\n Cross-sweep state and query hygiene:\n - Scheduled sweeps run in separate sandboxes. Harness file memory under\n `~/.claude/projects/.../memory` is session-local and ephemeral across\n scheduled sweep sessions.\n - Writing `MEMORY.md` or another memory file is not a durable cross-sweep\n action and is not proof that a future sweep will remember it. Never report\n a memory write as durable recall or use it as evidence of prior delivery.\n - Durable cross-sweep evidence is Auto session history and search, plus\n Slack or Linear records when applicable. Use auto.sessions.list to identify\n recent predecessor sessions, then prefer one auto.sessions.search call per\n candidate with `queries: ["Verdict"]`, `roles: ["assistant"]`,\n `kinds: ["message"]`, and `limit: 3`. Alternatively, read final assistant\n messages with auto.sessions.conversation using `roles: ["assistant"]`,\n `kinds: ["message"]`, `limit: 3`, and `toolResults: "omit"`. Compare from\n that bounded evidence; widen only for a named evidence gap.\n - Keep large GitHub and session reads bounded. For search_pull_requests,\n start with a narrow query with a bounded `perPage`. The GitHub proxy streams\n read results verbatim; `search_pull_requests` itself does not own or\n guarantee file persistence. If the harness result carries both\n `persistedOutputPath` and `persistedOutputSize`, consume that one persisted\n result once locally and continue from it; do not reissue the same oversized\n query. That local file is session-local evidence, not durable cross-sweep\n state.\n\n Fallback (only when the team has explicitly asked for tracking-issue\n delivery, and never on a public repository): keep a single tracking\n issue titled "Self-improvement sweep reports" - find it with\n search_issues, create it with issue_write only if it is missing, and\n add exactly one comment per sweep with add_issue_comment: one short\n first line (sweep time and counts), then the detail as Markdown\n bullets. Never open a new issue per finding, and post only when there\n is something actionable.\n\n Slack delivery is optional and uses the standard `slack` connection and\n `#dev` channel. When the chat tool is available, post only when there is\n something actionable: one short top-level line with the sweep time and\n counts, then exactly one threaded reply with the detail as mrkdwn bullets.\n Use the threadId returned by chat.send for the reply; never guess thread ids.\n When the tool is unavailable, do not treat Slack delivery as a failure; the\n run report remains the complete sweep. If a user asks for Slack delivery\n while it is unavailable, offer to connect the standard `slack` connection\n and explain that a fresh apply and session make the capability available.\n\n Scheduled sweep closure:\n - Finish the final four-section report/reply and, for actionable findings,\n every required Slack or Chief handoff. Only after every owed delivery is\n complete, call `auto.sessions.complete_current` exactly once with a compact\n one-line handoff.\n - This applies to actionable and no-action sweeps. A no-findings sweep with\n Verdict "Nothing actionable." completes after its final four-section report;\n it owes no Slack or Chief handoff.\n - Never call `auto.sessions.archive_current` to close a sweep. Do not call\n `auto.unbind`, `auto.chat.unsubscribe`, or otherwise release a Slack\n thread binding during closure. The configured agent-continuity\n `slack.thread` binding survives completion while lifecycle remains manual.\n `chat_send` stamps that continuity from this spec. It routes a human reply\n back to this completed holder and reopens this session.\ninitialPrompt: |\n A scheduled heartbeat spawned this run (scheduled at\n "{{heartbeat.scheduledAt}}") to sweep the project\'s recent sessions\n for failures, anomalies, PR feedback, and improvement opportunities.\n\n Sweep protocol:\n - Find your previous report with auto.sessions.list/conversation. Avoid\n re-reporting old findings; close resolved ones and escalate recurring ones.\n - Triage recent sessions, PR feedback, and relevant read-only data sources.\n - Deep-dive at most three evidence clusters. Prefer one well-evidenced,\n automatable improvement over many shallow observations.\n\n Deliver per your profile instructions and always end with the four-section\n report.\nmounts:\n # GitHub App git mount provisions the GitHub MCP proxy (the github\n # tools below are broken without a githubApp mount) and stages a\n # read-only checkout the sweep can ground findings in. Capabilities\n # line up with the declared tools: pullRequests/issues read for PR\n # comment and tracking-issue inspection, issues: write for the opt-in\n # tracking-issue fallback (issue_write/add_issue_comment), actions/checks\n # read for CI. No merge/secrets/workflows.\n - kind: git\n repository: "{{ $repoFullName }}"\n mountPath: /workspace/auto\n ref: main\n auth:\n kind: githubApp\n capabilities:\n contents: read\n pullRequests: read\n issues: write\n checks: read\n actions: read\ntools:\n auto:\n kind: local\n implementation: auto\n github:\n kind: github\n tools:\n - search_pull_requests\n - pull_request_read\n - actions_list\n - actions_get\n - search_issues\n - issue_read\n - issue_write\n - add_issue_comment\n chat:\n kind: local\n implementation: chat\n auth:\n kind: connection\n provider: slack\n connection: slack\n optional: true\ntriggers:\n - name: sweep-heartbeat\n kind: heartbeat\n cron: 0 */2 * * *\n timezone: UTC\n routing:\n kind: spawn\n - name: mention\n event: chat.message.mentioned\n connection: slack\n optional: true\n where:\n $.chat.provider: slack\n $.auto.authored: false\n message: |\n {{message.author.userName}} mentioned you on Slack:\n\n {{message.text}}\n\n Channel: {{chat.channelId}}\n Thread: {{chat.threadId}}\n\n Reply in that thread with chat.send. If the user clearly asks for a\n sweep, run it. If required context is missing, ask for the time window,\n target agents, PRs, or data source. Otherwise, briefly explain that you\n review PR feedback, read-only data sources, and Auto session history,\n then propose concrete improvements when something is actionable.\n routing:\n kind: spawn\n'
58435
+ },
58436
+ {
58437
+ path: "fragments/environments/agent-runtime.yaml",
58438
+ content: "# Source: https://www.auto.sh/api/v1/templates/%40auto/self-improvement/1.8.0/fragments/environments/agent-runtime.yaml\nharness: claude-code\nenvironment:\n name: agent-runtime\n image:\n kind: preset\n name: node24\n resources:\n memoryMB: 8192\n"
58439
+ }
58440
+ ]
58270
58441
  }
58271
58442
  ],
58272
58443
  "@auto/slopbusters": [
@@ -85018,7 +85189,7 @@ var init_package = __esm({
85018
85189
  "package.json"() {
85019
85190
  package_default = {
85020
85191
  name: "@autohq/cli",
85021
- version: "0.1.567",
85192
+ version: "0.1.569",
85022
85193
  license: "SEE LICENSE IN README.md",
85023
85194
  publishConfig: {
85024
85195
  access: "public"
@@ -96372,6 +96543,8 @@ var AgentBridgeOutputAckTimeoutError = class extends Error {
96372
96543
  var AGENT_BRIDGE_TERMINAL_AUTH_DRAIN_NO_PROGRESS_TIMEOUT_MS = 6e4;
96373
96544
  var AGENT_BRIDGE_TERMINAL_AUTH_DRAIN_ABSOLUTE_TIMEOUT_MS = 30 * 6e4;
96374
96545
  var AGENT_BRIDGE_TERMINAL_AUTH_DRAIN_REDIAL_MS = 1e3;
96546
+ var AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_TIMEOUT_MS = 1e4;
96547
+ var AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_REDIAL_MS = 1e3;
96375
96548
  async function runAgentBridgeSocket(options) {
96376
96549
  const socket = io(`${options.bridgeUrl}${RUNTIME_BRIDGE_NAMESPACE}`, {
96377
96550
  auth: {
@@ -96390,9 +96563,16 @@ async function runAgentBridgeSocket(options) {
96390
96563
  writeOutput: options.writeOutput,
96391
96564
  runtimeLogger: options.runtimeLogger
96392
96565
  });
96566
+ const terminalAuthRecovery = createTerminalAuthRecoveryController({
96567
+ socket,
96568
+ token: options.token,
96569
+ writeOutput: options.writeOutput,
96570
+ runtimeLogger: options.runtimeLogger
96571
+ });
96393
96572
  let hasConnected = false;
96573
+ let shutdown = null;
96394
96574
  await new Promise((resolve6, reject) => {
96395
- const shutdown = () => {
96575
+ shutdown = () => {
96396
96576
  reconnectLoop.stop();
96397
96577
  handler?.shutdown?.();
96398
96578
  socket.disconnect();
@@ -96404,6 +96584,9 @@ async function runAgentBridgeSocket(options) {
96404
96584
  if (terminalAuthDrain.handleConnectError(error51)) {
96405
96585
  return;
96406
96586
  }
96587
+ if (terminalAuthRecovery.handleConnectError(error51)) {
96588
+ return;
96589
+ }
96407
96590
  if (!hasConnected) {
96408
96591
  socket.disconnect();
96409
96592
  if (isTerminalAuthError(error51)) {
@@ -96415,11 +96598,17 @@ async function runAgentBridgeSocket(options) {
96415
96598
  }
96416
96599
  if (isTerminalAuthError(error51)) {
96417
96600
  reconnectLoop.stop();
96418
- void terminalAuthDrain.begin().catch((drainError) => {
96601
+ void terminalAuthRecovery.begin().catch(async (recoveryError) => {
96419
96602
  options.writeOutput?.(
96420
- `agent_bridge_terminal_auth_drain_failed error=${errorMessage(drainError)}`
96603
+ `agent_bridge_terminal_auth_recovery_failed error=${errorMessage(recoveryError)}`
96421
96604
  );
96422
- }).finally(() => {
96605
+ try {
96606
+ await terminalAuthDrain.begin();
96607
+ } catch (drainError) {
96608
+ options.writeOutput?.(
96609
+ `agent_bridge_terminal_auth_drain_failed error=${errorMessage(drainError)}`
96610
+ );
96611
+ }
96423
96612
  socket.disconnect();
96424
96613
  reject(new AgentBridgeTerminalAuthError(error51.message));
96425
96614
  });
@@ -96438,6 +96627,9 @@ async function runAgentBridgeSocket(options) {
96438
96627
  if (terminalAuthDrain.handleDisconnect()) {
96439
96628
  return;
96440
96629
  }
96630
+ if (terminalAuthRecovery.handleDisconnect()) {
96631
+ return;
96632
+ }
96441
96633
  reconnectLoop.start();
96442
96634
  });
96443
96635
  socket.on(
@@ -96480,6 +96672,7 @@ async function runAgentBridgeSocket(options) {
96480
96672
  if (terminalAuthDrain.handleConnected(rawContext)) {
96481
96673
  return;
96482
96674
  }
96675
+ terminalAuthRecovery.handleConnected();
96483
96676
  const context = RuntimeBridgeConnectedPayloadSchema.parse(rawContext);
96484
96677
  if (!handler) {
96485
96678
  reject(new Error("Bridge connected before bootstrap completed"));
@@ -96564,6 +96757,13 @@ async function runAgentBridgeSocket(options) {
96564
96757
  );
96565
96758
  });
96566
96759
  });
96760
+ }).finally(() => {
96761
+ reconnectLoop.stop();
96762
+ socket.disconnect();
96763
+ if (shutdown) {
96764
+ process.off("SIGINT", shutdown);
96765
+ process.off("SIGTERM", shutdown);
96766
+ }
96567
96767
  });
96568
96768
  }
96569
96769
  function isTerminalAuthError(error51) {
@@ -96726,6 +96926,128 @@ function createReconnectLoop(socket) {
96726
96926
  };
96727
96927
  return { start, stop };
96728
96928
  }
96929
+ function createTerminalAuthRecoveryController(input) {
96930
+ let state = null;
96931
+ const settle = (callback) => {
96932
+ const current = state;
96933
+ if (!current) {
96934
+ return;
96935
+ }
96936
+ clearTimeout(current.timeout);
96937
+ if (current.redialTimer) {
96938
+ clearTimeout(current.redialTimer);
96939
+ }
96940
+ state = null;
96941
+ input.socket.auth = { token: input.token };
96942
+ callback();
96943
+ };
96944
+ const scheduleRedial = () => {
96945
+ const current = state;
96946
+ if (!current || current.redialTimer) {
96947
+ return;
96948
+ }
96949
+ current.redialTimer = setTimeout(() => {
96950
+ current.redialTimer = null;
96951
+ if (state !== current) {
96952
+ return;
96953
+ }
96954
+ if (input.socket.connected) {
96955
+ input.socket.disconnect();
96956
+ }
96957
+ input.socket.connect();
96958
+ }, AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_REDIAL_MS);
96959
+ current.redialTimer.unref?.();
96960
+ };
96961
+ const begin = () => {
96962
+ if (state) {
96963
+ return state.promise;
96964
+ }
96965
+ const startedAt = Date.now();
96966
+ let resolveRecovery = () => {
96967
+ };
96968
+ let rejectRecovery = () => {
96969
+ };
96970
+ const promise2 = new Promise((resolve6, reject) => {
96971
+ resolveRecovery = resolve6;
96972
+ rejectRecovery = reject;
96973
+ });
96974
+ const current = {
96975
+ promise: promise2,
96976
+ redialTimer: null,
96977
+ reject: rejectRecovery,
96978
+ resolve: resolveRecovery,
96979
+ startedAt,
96980
+ timeout: setTimeout(() => {
96981
+ if (state !== current) {
96982
+ return;
96983
+ }
96984
+ settle(
96985
+ () => current.reject(
96986
+ new Error(
96987
+ `Timed out recovering bridge terminal auth after ${AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_TIMEOUT_MS}ms`
96988
+ )
96989
+ )
96990
+ );
96991
+ }, AGENT_BRIDGE_TERMINAL_AUTH_RECOVERY_TIMEOUT_MS)
96992
+ };
96993
+ current.timeout.unref?.();
96994
+ state = current;
96995
+ input.writeOutput?.("agent_bridge_terminal_auth_recovery_started");
96996
+ input.runtimeLogger?.warn("agent_bridge_terminal_auth_recovery_started");
96997
+ input.socket.auth = {
96998
+ token: input.token,
96999
+ terminalAuthRecovery: true
97000
+ };
97001
+ input.socket.connect();
97002
+ return promise2;
97003
+ };
97004
+ const handleConnected = () => {
97005
+ const current = state;
97006
+ if (!current) {
97007
+ return false;
97008
+ }
97009
+ settle(() => {
97010
+ const durationMs = Date.now() - current.startedAt;
97011
+ input.writeOutput?.(
97012
+ `agent_bridge_terminal_auth_recovery_completed duration_ms=${durationMs}`
97013
+ );
97014
+ input.runtimeLogger?.warn(
97015
+ "agent_bridge_terminal_auth_recovery_completed",
97016
+ { duration_ms: durationMs }
97017
+ );
97018
+ current.resolve();
97019
+ });
97020
+ return true;
97021
+ };
97022
+ const handleConnectError = (error51) => {
97023
+ const current = state;
97024
+ if (!current) {
97025
+ return false;
97026
+ }
97027
+ if (isTerminalAuthError(error51)) {
97028
+ settle(() => current.reject(error51));
97029
+ return true;
97030
+ }
97031
+ input.writeOutput?.(
97032
+ `agent_bridge_terminal_auth_recovery_connect_error error=${error51.message}`
97033
+ );
97034
+ scheduleRedial();
97035
+ return true;
97036
+ };
97037
+ const handleDisconnect = () => {
97038
+ if (!state) {
97039
+ return false;
97040
+ }
97041
+ scheduleRedial();
97042
+ return true;
97043
+ };
97044
+ return {
97045
+ begin,
97046
+ handleConnected,
97047
+ handleConnectError,
97048
+ handleDisconnect
97049
+ };
97050
+ }
96729
97051
  function createTerminalAuthDrainController(input) {
96730
97052
  let terminalAuthExit = false;
96731
97053
  let state = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.567",
3
+ "version": "0.1.569",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"