agent-transport-system 0.7.95 → 0.7.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ats.js CHANGED
@@ -31,7 +31,7 @@ import { Box, Container, Editor, Key, ProcessTerminal, TUI, Text, getEditorKeybi
31
31
  import { ReadStream, WriteStream } from "node:tty";
32
32
 
33
33
  //#region package.json
34
- var version = "0.7.95";
34
+ var version = "0.7.96";
35
35
  var package_default = {
36
36
  $schema: "https://www.schemastore.org/package.json",
37
37
  name: "agent-transport-system",
@@ -82581,6 +82581,16 @@ function toErrorMessage$7(error) {
82581
82581
  //#endregion
82582
82582
  //#region src/space/web-url.ts
82583
82583
  function buildSpaceWebUrl(baseUrl, spaceId, options) {
82584
+ const url = new URL(resolveGatewayWebOrigin(baseUrl));
82585
+ const surface = options?.surface ?? "public";
82586
+ url.pathname = surface === "app" ? `/app/spaces/${encodeURIComponent(spaceId)}` : `/spaces/${encodeURIComponent(spaceId)}`;
82587
+ url.search = "";
82588
+ const profileId = normalizeOptionalText$5(options?.profileId);
82589
+ if (surface === "app" && profileId) url.searchParams.set("profileId", profileId);
82590
+ url.hash = "";
82591
+ return url.toString();
82592
+ }
82593
+ function resolveGatewayWebOrigin(baseUrl) {
82584
82594
  const url = new URL(baseUrl);
82585
82595
  if (isLoopbackHostname$2(url.hostname) && url.port === "8080") url.port = "3000";
82586
82596
  if (url.hostname === "gateway.ats.sh") {
@@ -82588,13 +82598,10 @@ function buildSpaceWebUrl(baseUrl, spaceId, options) {
82588
82598
  url.port = "";
82589
82599
  url.protocol = "https:";
82590
82600
  }
82591
- const surface = options?.surface ?? "public";
82592
- url.pathname = surface === "app" ? `/app/spaces/${encodeURIComponent(spaceId)}` : `/spaces/${encodeURIComponent(spaceId)}`;
82601
+ url.pathname = "";
82593
82602
  url.search = "";
82594
- const profileId = normalizeOptionalText$5(options?.profileId);
82595
- if (surface === "app" && profileId) url.searchParams.set("profileId", profileId);
82596
82603
  url.hash = "";
82597
- return url.toString();
82604
+ return url.origin;
82598
82605
  }
82599
82606
  function isLoopbackHostname$2(hostname) {
82600
82607
  return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
@@ -97785,6 +97792,69 @@ function requireValidSetupBootstrapWrite(input) {
97785
97792
  return parsed.data;
97786
97793
  }
97787
97794
 
97795
+ //#endregion
97796
+ //#region src/guides/local-agents-guide-url.ts
97797
+ const LOCAL_AGENTS_GUIDE_PATH = "/guides/local-agents";
97798
+ const LOCAL_AGENTS_GUIDE_AGENT_NAMES = "Codex, Claude Code, or OpenCode";
97799
+ function buildLocalAgentsGuideUrl(baseUrl) {
97800
+ const url = new URL(resolveGatewayWebOrigin(baseUrl));
97801
+ url.pathname = LOCAL_AGENTS_GUIDE_PATH;
97802
+ url.search = "";
97803
+ url.hash = "";
97804
+ return url.toString();
97805
+ }
97806
+ function buildNoLocalAgentsNoticeLines(input) {
97807
+ return [
97808
+ `ATS did not find ${LOCAL_AGENTS_GUIDE_AGENT_NAMES} on this computer.`,
97809
+ "Install and sign in to one of them if you want this computer to run local agents from ATS.",
97810
+ `Guide: ${input.guideUrl}`
97811
+ ];
97812
+ }
97813
+ function appendLocalAgentsGuideUrl(input) {
97814
+ return `${input.message} Install guide: ${input.guideUrl}`;
97815
+ }
97816
+ async function confirmContinueWithoutLocalAgents(input) {
97817
+ return await runInteractivePrompt({
97818
+ initialState: { guideUrl: input.guideUrl },
97819
+ fallbackResult: "continue",
97820
+ renderLines: renderLocalAgentsGuidePromptLines,
97821
+ handleKeypress: handleLocalAgentsGuidePromptKeypress
97822
+ }, input.streams);
97823
+ }
97824
+ function renderLocalAgentsGuidePromptLines(state, status) {
97825
+ if (status === "submitted") return ["Continuing setup without local agents."];
97826
+ if (status === "cancelled") return ["Setup cancelled."];
97827
+ return [...buildNoLocalAgentsNoticeLines({ guideUrl: state.guideUrl }), "Continue setting up the ATS service without any local agents? [Y/n]"];
97828
+ }
97829
+ function handleLocalAgentsGuidePromptKeypress(input) {
97830
+ if (input.key.name === "return" || input.key.name === "enter") return {
97831
+ type: "result",
97832
+ status: "submitted",
97833
+ result: "continue",
97834
+ state: input.state
97835
+ };
97836
+ const value = String(input.str ?? "").trim().toLowerCase();
97837
+ if (value === "y") return {
97838
+ type: "result",
97839
+ status: "submitted",
97840
+ result: "continue",
97841
+ state: input.state
97842
+ };
97843
+ if (value === "n" || input.key.name === "escape") return {
97844
+ type: "result",
97845
+ status: "cancelled",
97846
+ result: "cancelled",
97847
+ state: input.state
97848
+ };
97849
+ if (input.key.ctrl && input.key.name === "c") return {
97850
+ type: "result",
97851
+ status: "cancelled",
97852
+ result: "cancelled",
97853
+ state: input.state
97854
+ };
97855
+ return { type: "ignore" };
97856
+ }
97857
+
97788
97858
  //#endregion
97789
97859
  //#region src/local-service/reporting/selected-agent-controller-reporting.ts
97790
97860
  function resolveSelectedAgentControllerReadiness(input) {
@@ -97895,6 +97965,64 @@ function normalizeId(value) {
97895
97965
  return value.trim();
97896
97966
  }
97897
97967
 
97968
+ //#endregion
97969
+ //#region src/ui/controlling-terminal.ts
97970
+ const CONTROLLING_TERMINAL_PATH = "/dev/tty";
97971
+ function hasUsableProcessTerminal() {
97972
+ return process$1.stdin.isTTY === true && process$1.stdout.isTTY === true && typeof process$1.stdin.setRawMode === "function";
97973
+ }
97974
+ function closeFdSafely(fd) {
97975
+ if (fd === null) return;
97976
+ try {
97977
+ closeSync(fd);
97978
+ } catch {}
97979
+ }
97980
+ function resolveControllingTerminalSession() {
97981
+ if (hasUsableProcessTerminal()) return {
97982
+ streams: {
97983
+ input: process$1.stdin,
97984
+ output: process$1.stdout
97985
+ },
97986
+ close: () => void 0
97987
+ };
97988
+ if (process$1.platform === "win32") return null;
97989
+ let readFd = null;
97990
+ let writeFd = null;
97991
+ let input = null;
97992
+ let output = null;
97993
+ try {
97994
+ readFd = openSync(CONTROLLING_TERMINAL_PATH, "r");
97995
+ input = new ReadStream(readFd);
97996
+ readFd = null;
97997
+ writeFd = openSync(CONTROLLING_TERMINAL_PATH, "w");
97998
+ output = new WriteStream(writeFd);
97999
+ writeFd = null;
98000
+ if (input.isTTY !== true || output.isTTY !== true || typeof input.setRawMode !== "function") {
98001
+ input.destroy();
98002
+ output.destroy();
98003
+ return null;
98004
+ }
98005
+ const ttyInput = input;
98006
+ const ttyOutput = output;
98007
+ return {
98008
+ streams: {
98009
+ input: ttyInput,
98010
+ output: ttyOutput
98011
+ },
98012
+ close: () => {
98013
+ ttyInput.destroy();
98014
+ ttyOutput.destroy();
98015
+ }
98016
+ };
98017
+ } catch {
98018
+ if (input) input.destroy();
98019
+ else closeFdSafely(readFd);
98020
+ if (output) output.destroy();
98021
+ else closeFdSafely(writeFd);
98022
+ return null;
98023
+ }
98024
+ }
98025
+
97898
98026
  //#endregion
97899
98027
  //#region src/ui/setup-progress.ts
97900
98028
  function createSetupProgressReporter(input) {
@@ -98525,64 +98653,6 @@ async function writeConnectedComputerEnrollmentToServiceContract(input) {
98525
98653
  });
98526
98654
  }
98527
98655
 
98528
- //#endregion
98529
- //#region src/ui/controlling-terminal.ts
98530
- const CONTROLLING_TERMINAL_PATH = "/dev/tty";
98531
- function hasUsableProcessTerminal() {
98532
- return process$1.stdin.isTTY === true && process$1.stdout.isTTY === true && typeof process$1.stdin.setRawMode === "function";
98533
- }
98534
- function closeFdSafely(fd) {
98535
- if (fd === null) return;
98536
- try {
98537
- closeSync(fd);
98538
- } catch {}
98539
- }
98540
- function resolveControllingTerminalSession() {
98541
- if (hasUsableProcessTerminal()) return {
98542
- streams: {
98543
- input: process$1.stdin,
98544
- output: process$1.stdout
98545
- },
98546
- close: () => void 0
98547
- };
98548
- if (process$1.platform === "win32") return null;
98549
- let readFd = null;
98550
- let writeFd = null;
98551
- let input = null;
98552
- let output = null;
98553
- try {
98554
- readFd = openSync(CONTROLLING_TERMINAL_PATH, "r");
98555
- input = new ReadStream(readFd);
98556
- readFd = null;
98557
- writeFd = openSync(CONTROLLING_TERMINAL_PATH, "w");
98558
- output = new WriteStream(writeFd);
98559
- writeFd = null;
98560
- if (input.isTTY !== true || output.isTTY !== true || typeof input.setRawMode !== "function") {
98561
- input.destroy();
98562
- output.destroy();
98563
- return null;
98564
- }
98565
- const ttyInput = input;
98566
- const ttyOutput = output;
98567
- return {
98568
- streams: {
98569
- input: ttyInput,
98570
- output: ttyOutput
98571
- },
98572
- close: () => {
98573
- ttyInput.destroy();
98574
- ttyOutput.destroy();
98575
- }
98576
- };
98577
- } catch {
98578
- if (input) input.destroy();
98579
- else closeFdSafely(readFd);
98580
- if (output) output.destroy();
98581
- else closeFdSafely(writeFd);
98582
- return null;
98583
- }
98584
- }
98585
-
98586
98656
  //#endregion
98587
98657
  //#region src/commands/prepare-session-executor.ts
98588
98658
  const PREPARE_TOKEN_HEADER = "x-ats-prepare-token";
@@ -98720,12 +98790,15 @@ async function runPrepareSessionExecutorOnce(input) {
98720
98790
  }
98721
98791
  async function resolveAgentSelection(input) {
98722
98792
  if (input.input.localAgentSelection) {
98793
+ const guideUrl = buildLocalAgentsGuideUrl(input.input.gatewayUrl);
98723
98794
  const localAgentIds = resolveTerminalSelectedLocalAgentIds({
98795
+ guideUrl,
98724
98796
  selection: input.input.localAgentSelection,
98725
98797
  snapshot: input.snapshot
98726
98798
  });
98727
98799
  if (hasAgentSelectionBeenSaved(input.snapshot) && haveSameLocalAgentIds(input.snapshot.selectedLocalAgentIds, localAgentIds)) return input.snapshot;
98728
98800
  return await writeTerminalAgentSelection({
98801
+ ...localAgentIds.length === 0 && input.input.localAgentSelection.mode !== "none" ? { emptySelectionGuideUrl: guideUrl } : {},
98729
98802
  input: input.input,
98730
98803
  localAgentIds,
98731
98804
  stream: input.stream,
@@ -98748,10 +98821,7 @@ const PROMPT_LOCAL_AGENT_SELECTION_MESSAGE = "Choose the local agents to connect
98748
98821
  async function resolveTerminalInteractiveLocalAgentSelection(input) {
98749
98822
  const selectableEntries = resolveSelectableLocalAgentCatalogEntries(input.snapshot);
98750
98823
  if (selectableEntries.length === 0) {
98751
- emitPrepareProgressLine(input.input, {
98752
- state: "success",
98753
- text: "No supported local agents found. Setup will continue without local agents."
98754
- });
98824
+ await confirmZeroLocalAgentPrepareSessionIfNeeded({ input: input.input });
98755
98825
  return [];
98756
98826
  }
98757
98827
  const allSelectableIds = selectableEntries.map((entry) => entry.agentId);
@@ -98783,6 +98853,35 @@ async function resolveTerminalInteractiveLocalAgentSelection(input) {
98783
98853
  terminal.close();
98784
98854
  }
98785
98855
  }
98856
+ async function confirmZeroLocalAgentPrepareSessionIfNeeded(input) {
98857
+ const guideUrl = buildLocalAgentsGuideUrl(input.input.gatewayUrl);
98858
+ const terminal = input.input.runtime.resolvedView === "human" ? resolveControllingTerminalSession() : null;
98859
+ if (!terminal) {
98860
+ emitPrepareNoLocalAgentsNotice({
98861
+ guideUrl,
98862
+ input: input.input
98863
+ });
98864
+ return;
98865
+ }
98866
+ try {
98867
+ if (await confirmContinueWithoutLocalAgents({
98868
+ guideUrl,
98869
+ streams: terminal.streams
98870
+ }) === "continue") return;
98871
+ emitHumanStatus(input.input, "Setup cancelled", ["Install an agent CLI, then re-run the setup command from ATS Web.", `Guide: ${guideUrl}`]);
98872
+ throw new Error("ATS setup was cancelled before choosing local agents.");
98873
+ } finally {
98874
+ terminal.close();
98875
+ }
98876
+ }
98877
+ function emitPrepareNoLocalAgentsNotice(input) {
98878
+ const [summary, ...details] = buildNoLocalAgentsNoticeLines({ guideUrl: input.guideUrl });
98879
+ emitPrepareProgressLine(input.input, {
98880
+ state: "success",
98881
+ text: summary ? `${summary} Setup will continue without local agents.` : "Setup will continue without local agents."
98882
+ });
98883
+ for (const detail of details) emitPrepareProgressDetail(input.input, detail);
98884
+ }
98786
98885
  function resolveSelectableLocalAgentCatalogEntries(snapshot) {
98787
98886
  return (snapshot.localAgentCatalog?.entries ?? []).filter((entry) => entry.selectable);
98788
98887
  }
@@ -98796,10 +98895,17 @@ function resolveTerminalSelectedLocalAgentIds(input) {
98796
98895
  const missingIds = selectedIds.filter((agentId) => !selectableById.has(agentId));
98797
98896
  if (missingIds.length > 0) {
98798
98897
  const selectableIds = [...selectableById.keys()];
98799
- throw new Error([`ATS cannot select local agent ${missingIds.join(", ")} for setup.`, selectableIds.length > 0 ? `Selectable local agents: ${selectableIds.join(", ")}.` : "No selectable local agents were found on this computer."].join(" "));
98898
+ throw new Error([`ATS cannot select local agent ${missingIds.join(", ")} for setup.`, selectableIds.length > 0 ? `Selectable local agents: ${selectableIds.join(", ")}.` : formatNoSelectableLocalAgentsFound(input.guideUrl)].join(" "));
98800
98899
  }
98801
98900
  return selectedIds;
98802
98901
  }
98902
+ function formatNoSelectableLocalAgentsFound(guideUrl) {
98903
+ const message = "No selectable local agents were found on this computer.";
98904
+ return guideUrl ? appendLocalAgentsGuideUrl({
98905
+ guideUrl,
98906
+ message
98907
+ }) : message;
98908
+ }
98803
98909
  function assertCompletedPrepareSessionMatchesTerminalSelection(input) {
98804
98910
  const localAgentIds = resolveTerminalSelectedLocalAgentIds(input);
98805
98911
  if (haveSameLocalAgentIds(input.snapshot.selectedLocalAgentIds, localAgentIds)) return;
@@ -98819,13 +98925,20 @@ async function writeTerminalAgentSelection(input) {
98819
98925
  });
98820
98926
  emitPrepareProgressLine(input.input, {
98821
98927
  state: "success",
98822
- text: input.localAgentIds.length === 0 ? "Selected: no local agents" : `Selected: ${formatSelectedLocalAgentNames({
98928
+ text: input.localAgentIds.length === 0 ? formatSelectedNoLocalAgents(input.emptySelectionGuideUrl) : `Selected: ${formatSelectedLocalAgentNames({
98823
98929
  localAgentIds: input.localAgentIds,
98824
98930
  snapshot: selectedSnapshot
98825
98931
  })}`
98826
98932
  });
98827
98933
  return selectedSnapshot;
98828
98934
  }
98935
+ function formatSelectedNoLocalAgents(guideUrl) {
98936
+ const message = "Selected: no local agents";
98937
+ return guideUrl ? appendLocalAgentsGuideUrl({
98938
+ guideUrl,
98939
+ message
98940
+ }) : message;
98941
+ }
98829
98942
  async function reportLocalAgentCatalogForSelection(input) {
98830
98943
  const connectionEpoch = requireConnectionEpoch(input.snapshot);
98831
98944
  emitHumanSection(input.input, "Local agents");
@@ -100502,11 +100615,21 @@ async function runSetupUnlocked(input) {
100502
100615
  readiness: initialReadiness,
100503
100616
  view: runtime.resolvedView
100504
100617
  });
100618
+ const localAgentsGuideUrl = buildLocalAgentsGuideUrl(gatewayUrl);
100505
100619
  const selectedLocalAgentIds = resolveSetupLocalAgentIds({
100620
+ guideUrl: localAgentsGuideUrl,
100506
100621
  localAgent: input.localAgent,
100507
100622
  localAgents: input.localAgents,
100508
100623
  readiness: initialReadiness
100509
100624
  });
100625
+ await confirmZeroLocalAgentSetupIfNeeded({
100626
+ explicitSelection: hasExplicitLocalAgentSelection(input),
100627
+ guideUrl: localAgentsGuideUrl,
100628
+ localAgentsMode: input.localAgents,
100629
+ presenter,
100630
+ runtime,
100631
+ selectedLocalAgentIds
100632
+ });
100510
100633
  if (selectedLocalAgentIds.length > 0) assertStartLocalAgentsEnableCompleted(await runWithSetupSpinner({
100511
100634
  code: "setup.progress.local_agents.enabling",
100512
100635
  message: setupCopy.cliProgressConnectingLocalAgents,
@@ -100648,12 +100771,79 @@ function resolveSetupLocalAgentIds(input) {
100648
100771
  const missingIds = localAgentIds.filter((agentId) => !selectableById.has(agentId));
100649
100772
  if (missingIds.length > 0) {
100650
100773
  const selectableIds = [...selectableById.keys()];
100651
- throw new Error([`ATS cannot set up local agent ${missingIds.join(", ")} on this computer.`, selectableIds.length > 0 ? `Available local agents: ${selectableIds.join(", ")}.` : "No available local agents were found on this computer."].join(" "));
100774
+ throw new Error([`ATS cannot set up local agent ${missingIds.join(", ")} on this computer.`, selectableIds.length > 0 ? `Available local agents: ${selectableIds.join(", ")}.` : formatNoAvailableLocalAgentsFound(input.guideUrl)].join(" "));
100652
100775
  }
100653
100776
  return localAgentIds;
100654
100777
  }
100655
100778
  return [...selectableById.keys()].sort((left, right) => left.localeCompare(right));
100656
100779
  }
100780
+ async function confirmZeroLocalAgentSetupIfNeeded(input) {
100781
+ if (input.selectedLocalAgentIds.length > 0 || normalizeOptionalString$1(input.localAgentsMode) === "none") return;
100782
+ if (input.explicitSelection) {
100783
+ emitSetupNoLocalAgentsWarning(input);
100784
+ return;
100785
+ }
100786
+ const terminal = input.runtime.resolvedView === "human" ? resolveControllingTerminalSession() : null;
100787
+ if (!terminal) {
100788
+ emitSetupNoLocalAgentsWarning(input);
100789
+ return;
100790
+ }
100791
+ try {
100792
+ if (await confirmContinueWithoutLocalAgents({
100793
+ guideUrl: input.guideUrl,
100794
+ streams: terminal.streams
100795
+ }) === "continue") return;
100796
+ emitSetupNoLocalAgentsCancelled(input);
100797
+ throw new Error("ATS setup was cancelled before choosing local agents.");
100798
+ } finally {
100799
+ terminal.close();
100800
+ }
100801
+ }
100802
+ function emitSetupNoLocalAgentsWarning(input) {
100803
+ const lines = buildNoLocalAgentsNoticeLines({ guideUrl: input.guideUrl });
100804
+ if (input.runtime.resolvedView === "human") {
100805
+ renderInfoCard({
100806
+ presenter: input.presenter,
100807
+ title: "No Local Agents Found",
100808
+ codePrefix: "setup.local_agents.none",
100809
+ rows: lines.map((line) => ({
100810
+ label: "",
100811
+ value: line
100812
+ })),
100813
+ sanitize: true,
100814
+ minContentWidth: 56
100815
+ });
100816
+ return;
100817
+ }
100818
+ for (const [index, line] of lines.entries()) input.presenter.line({
100819
+ code: `setup.local_agents.none.${index + 1}`,
100820
+ text: line
100821
+ });
100822
+ }
100823
+ function emitSetupNoLocalAgentsCancelled(input) {
100824
+ if (input.runtime.resolvedView !== "human") return;
100825
+ renderInfoCard({
100826
+ presenter: input.presenter,
100827
+ title: "Setup Cancelled",
100828
+ codePrefix: "setup.local_agents.cancelled",
100829
+ rows: [{
100830
+ label: "",
100831
+ value: "Install an agent CLI, then re-run the setup command from ATS Web."
100832
+ }, {
100833
+ label: "",
100834
+ value: `Guide: ${input.guideUrl}`
100835
+ }],
100836
+ sanitize: true,
100837
+ minContentWidth: 56
100838
+ });
100839
+ }
100840
+ function formatNoAvailableLocalAgentsFound(guideUrl) {
100841
+ const message = "No available local agents were found on this computer.";
100842
+ return guideUrl ? appendLocalAgentsGuideUrl({
100843
+ guideUrl,
100844
+ message
100845
+ }) : message;
100846
+ }
100657
100847
  function assertStartLocalAgentsEnableCompleted(result) {
100658
100848
  if (result.status !== "completed") throw new Error("ATS setup cannot continue until selected local agents are available on this computer.");
100659
100849
  const blockingError = result.summary.errors[0] ?? null;
@@ -100736,6 +100926,7 @@ async function resolveDelegatedSetupCompletionFacts(input) {
100736
100926
  selectedLocalAgentIds: []
100737
100927
  };
100738
100928
  const selectedLocalAgentIds = sessionSelectedLocalAgentIds ? [...sessionSelectedLocalAgentIds] : resolveSetupLocalAgentIds({
100929
+ guideUrl: buildLocalAgentsGuideUrl(input.gatewayUrl),
100739
100930
  localAgent: input.setupInput.localAgent,
100740
100931
  localAgents: input.setupInput.localAgents,
100741
100932
  readiness: await collectStartLocalReadiness({ auth: {
@@ -100822,6 +101013,7 @@ function emitSetupComplete(input) {
100822
101013
  if (input.view === "human") {
100823
101014
  const setupCopy = getSetupFlowCopy("setup");
100824
101015
  const serviceGuidance = buildSetupServiceGuidance({ cliCommandPrefix });
101016
+ const localAgentsGuideUrl = buildLocalAgentsGuideUrl(input.gatewayUrl);
100825
101017
  renderInfoCard({
100826
101018
  presenter: input.presenter,
100827
101019
  title: setupCopy.cliCompletionTitle,
@@ -100829,13 +101021,30 @@ function emitSetupComplete(input) {
100829
101021
  compact: true,
100830
101022
  minContentWidth: 44,
100831
101023
  sanitize: true,
100832
- rows: [{
100833
- label: "Agents",
100834
- value: formatSetupCompleteLocalAgents(input.selectedLocalAgentIds)
100835
- }, ...input.bootstrap.status === "completed" ? [] : [{
100836
- label: "Space",
100837
- value: formatSetupBootstrapHumanSummary(input.bootstrap)
100838
- }]]
101024
+ rows: [
101025
+ {
101026
+ label: "Agents",
101027
+ value: formatSetupCompleteLocalAgents({
101028
+ guideUrl: localAgentsGuideUrl,
101029
+ selectedLocalAgentIds: input.selectedLocalAgentIds
101030
+ })
101031
+ },
101032
+ ...input.selectedLocalAgentIds.length === 0 ? [{
101033
+ label: "Install guide",
101034
+ value: localAgentsGuideUrl
101035
+ }] : [],
101036
+ ...input.bootstrap.status === "completed" ? [] : [{
101037
+ label: "Space",
101038
+ value: formatSetupBootstrapHumanSummary(input.bootstrap)
101039
+ }]
101040
+ ]
101041
+ });
101042
+ if (input.selectedLocalAgentIds.length === 0) input.presenter.line({
101043
+ code: "setup.complete.local_agents.guide",
101044
+ text: `Open guide: ${formatTerminalHyperlink({
101045
+ label: "Local agent install guide",
101046
+ url: localAgentsGuideUrl
101047
+ })} (${localAgentsGuideUrl})`
100839
101048
  });
100840
101049
  renderSetupServiceGuidanceCard({
100841
101050
  atsServiceRuntimeIdentity: input.atsServiceRuntimeIdentity,
@@ -100992,9 +101201,9 @@ async function finalizeLocalComponentsSetupSnapshot() {
100992
101201
  await writeInstalledLocalComponentsSnapshot({ source: "setup" });
100993
101202
  return await resolveLocalComponentsStatus();
100994
101203
  }
100995
- function formatSetupCompleteLocalAgents(selectedLocalAgentIds) {
100996
- if (selectedLocalAgentIds.length === 0) return "No local agents selected";
100997
- return `${selectedLocalAgentIds.length} detected: ${selectedLocalAgentIds.join(", ")}`;
101204
+ function formatSetupCompleteLocalAgents(input) {
101205
+ if (input.selectedLocalAgentIds.length === 0) return `No local agents connected. Install one from the guide: ${input.guideUrl}`;
101206
+ return `${input.selectedLocalAgentIds.length} detected: ${input.selectedLocalAgentIds.join(", ")}`;
100998
101207
  }
100999
101208
  function formatSetupCompleteSpaceSetupHint(input) {
101000
101209
  if (input.bootstrap.status === "completed") return `${input.bootstrap.welcomingSpace.outcome === "reused" ? "Reused" : "Created"} ${input.bootstrap.welcomingSpace.name}`;