agent-transport-system 0.3.1 → 0.3.2

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
@@ -24,11 +24,11 @@ import wrapAnsi from "wrap-ansi";
24
24
  import { Box, Container, Editor, Key, ProcessTerminal, TUI, Text, getEditorKeybindings, matchesKey } from "@mariozechner/pi-tui";
25
25
 
26
26
  //#region package.json
27
- var version$1 = "0.3.1";
27
+ var version$1 = "0.3.2";
28
28
  var package_default = {
29
29
  name: "agent-transport-system",
30
30
  version: version$1,
31
- atsReleaseDate: "2026-03-12",
31
+ atsReleaseDate: "2026-04-16",
32
32
  description: "Agent Transport System CLI - https://ats.sh",
33
33
  license: "MIT",
34
34
  type: "module",
@@ -4319,7 +4319,7 @@ const daemonRouteObservationSummarySchema = strictObject({
4319
4319
  });
4320
4320
 
4321
4321
  //#endregion
4322
- //#region ../../packages/schemas/dist/entry-brief-LY-buFs9.js
4322
+ //#region ../../packages/schemas/dist/entry-brief-B2jV7t7E.js
4323
4323
  const providerConversationExternalImportCapabilitySchema = _enum(["unsupported", "by_ref_id"]);
4324
4324
  const providerConversationResumeCapabilitySchema = _enum(["unsupported", "by_ref_id"]);
4325
4325
  const providerConversationDiscoverCapabilitySchema = literal("unsupported");
@@ -6576,6 +6576,7 @@ const REPLY_READINESS_REASON_CODE_VALUES = [
6576
6576
  "runtime.adapter.unsupported",
6577
6577
  "controller.bootstrap.failed",
6578
6578
  "controller.gateway.unhealthy",
6579
+ "local_agents.none_needed",
6579
6580
  "route.offline",
6580
6581
  "route.not_registered"
6581
6582
  ];
@@ -11423,6 +11424,10 @@ function buildSkillsSharedNotes(context) {
11423
11424
  //#endregion
11424
11425
  //#region src/command-entry-checks/command-check-requirements.ts
11425
11426
  const SKIP_ALL_CHECKS = {
11427
+ disclaimer: {
11428
+ mode: "skip",
11429
+ stage: "before-entry"
11430
+ },
11426
11431
  cliUpdate: {
11427
11432
  mode: "skip",
11428
11433
  stage: "before-entry"
@@ -11452,6 +11457,10 @@ const OPTIONAL_CLI_UPDATE = { cliUpdate: {
11452
11457
  mode: "optional",
11453
11458
  stage: "before-entry"
11454
11459
  } };
11460
+ const REQUIRED_DISCLAIMER = { disclaimer: {
11461
+ mode: "required",
11462
+ stage: "before-entry"
11463
+ } };
11455
11464
  const AUTO_FIX_LOCAL_RUNTIME = { localRuntimeState: {
11456
11465
  mode: "auto-fix",
11457
11466
  stage: "before-entry"
@@ -11480,10 +11489,6 @@ const STATUS_ONLY_SELECTED_PROFILE = { selectedProfile: {
11480
11489
  mode: "status-only",
11481
11490
  stage: "status-only"
11482
11491
  } };
11483
- const OPTIONAL_SERVICE_AFTER_PROFILE = { service: {
11484
- mode: "optional",
11485
- stage: "after-profile"
11486
- } };
11487
11492
  const STATUS_ONLY_SERVICE = { service: {
11488
11493
  mode: "status-only",
11489
11494
  stage: "status-only"
@@ -11494,77 +11499,77 @@ function buildCommandChecks(...parts) {
11494
11499
  const COMMAND_CHECK_REQUIREMENTS = Object.freeze({
11495
11500
  root: buildCommandChecks(OPTIONAL_CLI_UPDATE),
11496
11501
  view: buildCommandChecks(OPTIONAL_CLI_UPDATE),
11497
- start: buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11498
- "repair.local-state": buildCommandChecks(),
11499
- uninstall: buildCommandChecks(),
11500
- reset: buildCommandChecks(),
11501
- upgrade: buildCommandChecks(),
11502
- "auth.menu": buildCommandChecks(),
11503
- "auth.status": buildCommandChecks(),
11504
- "auth.login": buildCommandChecks(),
11505
- "auth.logout": buildCommandChecks(),
11506
- "skills.menu": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11507
- "skills.install": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11508
- "skills.uninstall": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11509
- "skills.list": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11510
- "skills.check": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11511
- "skills.update": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11512
- "agents.menu": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11513
- "agents.detect": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11514
- "agents.list": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11515
- "agents.manage": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11516
- "agents.enable": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11517
- "agents.repair": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11518
- "agents.disable": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11519
- "agents.show": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11520
- "agents.custom.list": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11521
- "agents.custom.add": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11522
- "agents.custom.update": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11523
- "agents.custom.remove": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11524
- "agents.config": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11525
- "service.menu": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11526
- "service.run": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11527
- "service.status": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11528
- "service.snapshot": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11529
- "service.interrupt": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11530
- "service.cancel": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11531
- "service.trace": buildCommandChecks(OPTIONAL_CLI_UPDATE, REQUIRED_SIGN_IN, REQUIRED_SELECTED_PROFILE),
11532
- "service.install": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11533
- "service.uninstall": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11534
- "service.reinstall": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11535
- "service.stop": buildCommandChecks(OPTIONAL_CLI_UPDATE),
11536
- "space.menu": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11537
- "space.create": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE, OPTIONAL_SERVICE_AFTER_PROFILE),
11538
- "space.delete": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11539
- "space.conversation.bind": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11540
- "space.conversation.clear": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11541
- "space.conversation.status": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11542
- "space.join": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE, OPTIONAL_SERVICE_AFTER_PROFILE),
11543
- "space.add-members": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11544
- "space.remove-members": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11545
- "space.watch": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE, OPTIONAL_SERVICE_AFTER_PROFILE),
11546
- "space.send": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11547
- "space.history": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11548
- "space.contract": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11549
- "space.contract.set": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11550
- "space.status": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11551
- "space.updates": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11552
- "space.result": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11553
- "space.list": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11554
- "space.password": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11555
- "space.guide": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11556
- "space.guide.set": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11557
- "space.guide.clear": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11558
- doctor: buildCommandChecks(OPTIONAL_CLI_UPDATE, OPTIONAL_SIGN_IN, STATUS_ONLY_SERVICE),
11559
- whoami: buildCommandChecks(OPTIONAL_CLI_UPDATE),
11560
- "profile.menu": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11561
- "profile.create": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11562
- "profile.list": buildCommandChecks(OPTIONAL_CLI_UPDATE, REQUIRED_SIGN_IN),
11563
- "profile.ready": buildCommandChecks(OPTIONAL_CLI_UPDATE, STATUS_ONLY_SIGN_IN, STATUS_ONLY_SELECTED_PROFILE),
11564
- "profile.set": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11565
- "profile.show": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11566
- "profile.update": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11567
- "profile.delete": buildCommandChecks(OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN)
11502
+ start: buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11503
+ "repair.local-state": buildCommandChecks(REQUIRED_DISCLAIMER),
11504
+ uninstall: buildCommandChecks(REQUIRED_DISCLAIMER),
11505
+ reset: buildCommandChecks(REQUIRED_DISCLAIMER),
11506
+ upgrade: buildCommandChecks(REQUIRED_DISCLAIMER),
11507
+ "auth.menu": buildCommandChecks(REQUIRED_DISCLAIMER),
11508
+ "auth.status": buildCommandChecks(REQUIRED_DISCLAIMER),
11509
+ "auth.login": buildCommandChecks(REQUIRED_DISCLAIMER),
11510
+ "auth.logout": buildCommandChecks(REQUIRED_DISCLAIMER),
11511
+ "skills.menu": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11512
+ "skills.install": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11513
+ "skills.uninstall": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11514
+ "skills.list": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11515
+ "skills.check": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11516
+ "skills.update": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11517
+ "agents.menu": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11518
+ "agents.detect": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11519
+ "agents.list": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11520
+ "agents.manage": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11521
+ "agents.enable": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11522
+ "agents.repair": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11523
+ "agents.disable": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11524
+ "agents.show": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11525
+ "agents.custom.list": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11526
+ "agents.custom.add": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11527
+ "agents.custom.update": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11528
+ "agents.custom.remove": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11529
+ "agents.config": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11530
+ "service.menu": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11531
+ "service.run": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11532
+ "service.status": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11533
+ "service.snapshot": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11534
+ "service.interrupt": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11535
+ "service.cancel": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME),
11536
+ "service.trace": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, REQUIRED_SIGN_IN, REQUIRED_SELECTED_PROFILE),
11537
+ "service.install": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11538
+ "service.uninstall": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11539
+ "service.reinstall": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11540
+ "service.stop": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11541
+ "space.menu": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11542
+ "space.create": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11543
+ "space.delete": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11544
+ "space.conversation.bind": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11545
+ "space.conversation.clear": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11546
+ "space.conversation.status": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11547
+ "space.join": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11548
+ "space.add-members": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11549
+ "space.remove-members": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11550
+ "space.watch": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11551
+ "space.send": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11552
+ "space.history": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11553
+ "space.contract": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11554
+ "space.contract.set": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11555
+ "space.status": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11556
+ "space.updates": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11557
+ "space.result": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11558
+ "space.list": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11559
+ "space.password": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11560
+ "space.guide": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11561
+ "space.guide.set": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11562
+ "space.guide.clear": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN, CONFIRM_SELECTED_PROFILE),
11563
+ doctor: buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, OPTIONAL_SIGN_IN, STATUS_ONLY_SERVICE),
11564
+ whoami: buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE),
11565
+ "profile.menu": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11566
+ "profile.create": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11567
+ "profile.list": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, REQUIRED_SIGN_IN),
11568
+ "profile.ready": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, STATUS_ONLY_SIGN_IN, STATUS_ONLY_SELECTED_PROFILE),
11569
+ "profile.set": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11570
+ "profile.show": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11571
+ "profile.update": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN),
11572
+ "profile.delete": buildCommandChecks(REQUIRED_DISCLAIMER, OPTIONAL_CLI_UPDATE, AUTO_FIX_LOCAL_RUNTIME, REQUIRED_SIGN_IN)
11568
11573
  });
11569
11574
  function getCommandCheckRequirements(entryName) {
11570
11575
  return COMMAND_CHECK_REQUIREMENTS[entryName];
@@ -14670,6 +14675,9 @@ async function getConfiguredDaemonDispatchLimits() {
14670
14675
  async function getConfiguredOnboardingConfig() {
14671
14676
  return (await readRuntimeConfig())?.onboarding ?? null;
14672
14677
  }
14678
+ async function getConfiguredOnboardingDisclaimerAcceptedAt() {
14679
+ return (await getConfiguredOnboardingConfig())?.disclaimerAcceptedAt ?? null;
14680
+ }
14673
14681
  async function getConfiguredStartV1OnboardingState() {
14674
14682
  return (await getConfiguredOnboardingConfig())?.startV1 ?? null;
14675
14683
  }
@@ -14734,10 +14742,23 @@ async function updateConfiguredDeviceRuntimeState(updater) {
14734
14742
  async function updateConfiguredStartV1OnboardingState(updater) {
14735
14743
  await withRuntimeConfigLock(async () => {
14736
14744
  const previous = await readRuntimeConfig();
14737
- const previousStartV1 = previous?.onboarding?.startV1 ?? null;
14745
+ const previousOnboarding = previous?.onboarding ?? null;
14746
+ const previousStartV1 = previousOnboarding?.startV1 ?? null;
14738
14747
  const nextStartV1 = updater(previousStartV1);
14739
14748
  if (JSON.stringify(previousStartV1) === JSON.stringify(nextStartV1)) return;
14740
- await writeRuntimeConfig(buildNextConfig(previous, { onboarding: nextStartV1 ? { startV1: nextStartV1 } : null }));
14749
+ await writeRuntimeConfig(buildNextConfig(previous, { onboarding: nextStartV1 || previousOnboarding?.disclaimerAcceptedAt ? {
14750
+ ...previousOnboarding?.disclaimerAcceptedAt ? { disclaimerAcceptedAt: previousOnboarding.disclaimerAcceptedAt } : {},
14751
+ ...nextStartV1 ? { startV1: nextStartV1 } : {}
14752
+ } : null }));
14753
+ });
14754
+ }
14755
+ async function updateConfiguredOnboardingConfig(updater) {
14756
+ await withRuntimeConfigLock(async () => {
14757
+ const previous = await readRuntimeConfig();
14758
+ const previousOnboarding = previous?.onboarding ?? null;
14759
+ const nextOnboarding = updater(previousOnboarding);
14760
+ if (JSON.stringify(previousOnboarding) === JSON.stringify(nextOnboarding)) return;
14761
+ await writeRuntimeConfig(buildNextConfig(previous, { onboarding: nextOnboarding }));
14741
14762
  });
14742
14763
  }
14743
14764
  function buildNextConfig(previous, overrides) {
@@ -14867,9 +14888,14 @@ function parseRuntimeDeviceRuntimeStateObject(value) {
14867
14888
  }
14868
14889
  function parseRuntimeOnboardingConfig(value) {
14869
14890
  if (!value || typeof value !== "object") return;
14870
- const startV1 = parseRuntimeStartV1OnboardingState(value.startV1);
14871
- if (!startV1) return;
14872
- return { startV1 };
14891
+ const obj = value;
14892
+ const disclaimerAcceptedAt = toTrimmedStringOrUndefined(obj.disclaimerAcceptedAt);
14893
+ const startV1 = parseRuntimeStartV1OnboardingState(obj.startV1);
14894
+ if (!(disclaimerAcceptedAt || startV1)) return;
14895
+ return {
14896
+ ...disclaimerAcceptedAt ? { disclaimerAcceptedAt } : {},
14897
+ ...startV1 ? { startV1 } : {}
14898
+ };
14873
14899
  }
14874
14900
  function parseRuntimeStartV1OnboardingState(value) {
14875
14901
  if (!value || typeof value !== "object") return;
@@ -16611,8 +16637,77 @@ function createPresenter(context) {
16611
16637
 
16612
16638
  //#endregion
16613
16639
  //#region src/system/daemon-install-attention.ts
16640
+ const DAEMON_INSTALL_DECISION_CHOICE = {
16641
+ install: "install",
16642
+ notNow: "not_now"
16643
+ };
16614
16644
  const DAEMON_INSTALL_COMMAND = "ats service install";
16615
16645
  const DAEMON_UPGRADE_COMMAND = "ats upgrade";
16646
+ const DAEMON_DECISION_RECOMMENDED_HINT = "Recommended";
16647
+ const DAEMON_INSTALL_DECISION_COPY = {
16648
+ missing: {
16649
+ question: "ATS Service is missing. Install it now?",
16650
+ explanation: "Without it, local agents on this device can't reply from Space.",
16651
+ primaryLabel: "Yes, install it for me",
16652
+ deferred: "ATS Service is still missing. Local agents on this device can't reply from Space until you install it later with `ats service install`.",
16653
+ failed: "ATS Service could not be installed. Local agents on this device still can't reply from Space. Run `ats service install`."
16654
+ },
16655
+ outdated: {
16656
+ question: "ATS Service needs an update. Fix it now?",
16657
+ explanation: "Until ATS fixes it, local agents on this device may not be able to reply from Space.",
16658
+ primaryLabel: "Yes, fix it for me",
16659
+ deferred: "ATS Service still needs an update. Local agents on this device may not be able to reply from Space until ATS fixes it. Run `ats service install` later.",
16660
+ failed: "ATS Service was not updated. Local agents on this device may not be able to reply from Space. Run `ats service install`."
16661
+ }
16662
+ };
16663
+ function buildDaemonInstallDecisionPromptConfig(input) {
16664
+ const copy = DAEMON_INSTALL_DECISION_COPY[input.kind];
16665
+ const detailLine = input.kind === "outdated" && typeof input.installedVersion === "string" && typeof input.expectedVersion === "string" ? `Installed v${input.installedVersion}, expected v${input.expectedVersion}.` : null;
16666
+ return {
16667
+ message: [
16668
+ copy.question,
16669
+ copy.explanation,
16670
+ detailLine
16671
+ ].filter((line) => typeof line === "string" && line.length > 0).join("\n"),
16672
+ initialValue: DAEMON_INSTALL_DECISION_CHOICE.install,
16673
+ options: [{
16674
+ value: DAEMON_INSTALL_DECISION_CHOICE.install,
16675
+ label: copy.primaryLabel,
16676
+ hint: DAEMON_DECISION_RECOMMENDED_HINT
16677
+ }, {
16678
+ value: DAEMON_INSTALL_DECISION_CHOICE.notNow,
16679
+ label: "Not now"
16680
+ }]
16681
+ };
16682
+ }
16683
+ async function promptForDaemonInstallDecision(input) {
16684
+ const choice = await select(buildDaemonInstallDecisionPromptConfig(input));
16685
+ if (isCancel(choice)) return "cancelled";
16686
+ return choice === DAEMON_INSTALL_DECISION_CHOICE.install ? DAEMON_INSTALL_DECISION_CHOICE.install : DAEMON_INSTALL_DECISION_CHOICE.notNow;
16687
+ }
16688
+ async function runDaemonInstallDecisionPrompt(input) {
16689
+ const decision = await promptForDaemonInstallDecision({
16690
+ kind: input.kind,
16691
+ installedVersion: input.installedVersion,
16692
+ expectedVersion: input.expectedVersion
16693
+ });
16694
+ if (decision === DAEMON_INSTALL_DECISION_CHOICE.install) try {
16695
+ await input.installService();
16696
+ return "install";
16697
+ } catch {
16698
+ await input.emitLine(formatDaemonInstallFailedMessage(input.kind));
16699
+ return "failed";
16700
+ }
16701
+ if (decision === "cancelled") return "cancelled";
16702
+ await input.emitLine(formatDaemonInstallDeferredMessage(input.kind));
16703
+ return decision;
16704
+ }
16705
+ function formatDaemonInstallDeferredMessage(kind) {
16706
+ return formatInlineAtsCliCommands(DAEMON_INSTALL_DECISION_COPY[kind].deferred);
16707
+ }
16708
+ function formatDaemonInstallFailedMessage(kind) {
16709
+ return formatInlineAtsCliCommands(DAEMON_INSTALL_DECISION_COPY[kind].failed);
16710
+ }
16616
16711
  function formatDaemonServiceMissingRecommendation() {
16617
16712
  return "ATS Service is not installed yet. Local agents on this device can't reply from Space until it is installed.";
16618
16713
  }
@@ -19712,6 +19807,12 @@ function getStepOrderIndex$1(stepId) {
19712
19807
  if (index === -1) throw new Error(`unknown start session step "${stepId}"`);
19713
19808
  return index;
19714
19809
  }
19810
+ function resolveServiceParticipationRequirement(input) {
19811
+ if (input.humanOnlyParticipation) return "not_needed";
19812
+ if (input.explicitSelectedLocalAgents) return input.selectedAgentProfilesHaveRunnableLocalSetup ? "offer_service_gate" : "agent_setup_needed";
19813
+ if (input.deviceLocalDemand === "keep_running") return "offer_service_gate";
19814
+ return "not_needed";
19815
+ }
19715
19816
  function buildDaemonRouteObservationPresentation$1(observation) {
19716
19817
  if (observation.status === "online") return {
19717
19818
  detail: "ATS server can see an active daemon route for this profile.",
@@ -19774,6 +19875,7 @@ function formatStartReplyReadinessReason(reasonCode) {
19774
19875
  case "runtime.adapter.unsupported": return "This agent setup can't reply from this device";
19775
19876
  case "controller.bootstrap.failed": return "ATS couldn't finish setting up OpenClaw on this device";
19776
19877
  case "controller.gateway.unhealthy": return "OpenClaw is not ready on this device yet";
19878
+ case "local_agents.none_needed": return "This device does not need ATS Service until you choose local agents to bring into a space";
19777
19879
  case "route.offline": return "ATS server can't currently see an active daemon route for this profile";
19778
19880
  case "route.not_registered": return "ATS is still setting up replies for this profile on this device";
19779
19881
  default: return reasonCode ? "ATS can't confirm reply status yet" : null;
@@ -26911,6 +27013,7 @@ function emitStructuredReconcileEvidence(eventName, payload) {
26911
27013
 
26912
27014
  //#endregion
26913
27015
  //#region src/system/device-runtime-state-sync.ts
27016
+ const NO_LOCAL_AGENTS_NEED_ATS_SERVICE_REASON = "No local agents on this device need ATS Service right now";
26914
27017
  async function syncDeviceRuntimeStateProjection(input) {
26915
27018
  const mode = input?.mode ?? "check";
26916
27019
  const currentControllers = await readCurrentControllers();
@@ -26950,7 +27053,7 @@ async function syncDeviceRuntimeStateProjection(input) {
26950
27053
  disabledControllerIds: [],
26951
27054
  repairRequiredControllerIds: [],
26952
27055
  repairedControllerIds: [],
26953
- reason: "no bound agent controller requires local projection"
27056
+ reason: NO_LOCAL_AGENTS_NEED_ATS_SERVICE_REASON
26954
27057
  });
26955
27058
  const gap = resolveProjectionGap({
26956
27059
  currentControllers,
@@ -28039,7 +28142,7 @@ function normalizeOptionalString$14(value) {
28039
28142
  }
28040
28143
  function resolveZeroLocalValueReason(projection) {
28041
28144
  if (!projection) return "no wakeable local agent routes are available";
28042
- if (projection.status === "ok" && projection.projectedControllerIds.length === 0) return "no bound agent controller currently needs local projection";
28145
+ if (projection.status === "ok" && projection.projectedControllerIds.length === 0) return NO_LOCAL_AGENTS_NEED_ATS_SERVICE_REASON;
28043
28146
  if (projection.status === "degraded") return "projected local controllers are not currently wakeable";
28044
28147
  return "no wakeable local agent routes are available";
28045
28148
  }
@@ -28472,13 +28575,17 @@ function resolveDeviceReplyReadinessFromRuntimeProjection(runtimeProjection) {
28472
28575
  return null;
28473
28576
  }
28474
28577
  function createRouteNotRegisteredReplyReadinessStatus(input) {
28578
+ const projectionWithoutLocalDemand = input.localDemand?.projection ?? input.runtimeProjection;
28475
28579
  return createDeviceReplyReadinessStatus({
28476
- reasonCode: "route.not_registered",
28477
- reasonText: normalizeReplyReadinessReason(input.localDemand?.reason ?? input.runtimeProjection?.reason) ?? "ATS is still setting up replies on this device",
28478
- replyReadiness: input.runtimeProjection?.status === "skipped" ? "unknown" : "blocked",
28580
+ reasonCode: input.runtimeProjection?.status === "skipped" || hasNoProjectedLocalControllers(projectionWithoutLocalDemand) ? "local_agents.none_needed" : "route.not_registered",
28581
+ reasonText: normalizeOptionalText$17(input.localDemand?.reason ?? input.runtimeProjection?.reason) ?? "ATS is still setting up replies on this device",
28582
+ replyReadiness: input.runtimeProjection?.status === "skipped" || hasNoProjectedLocalControllers(projectionWithoutLocalDemand) ? "unknown" : "blocked",
28479
28583
  wakeableRouteCount: 0
28480
28584
  });
28481
28585
  }
28586
+ function hasNoProjectedLocalControllers(projection) {
28587
+ return projection?.status === "ok" && projection.projectedControllerIds.length === 0;
28588
+ }
28482
28589
  function createDeviceReplyReadinessStatus(input) {
28483
28590
  return {
28484
28591
  reasonCodes: sortReplyReadinessReasonCodes(input.reasonCode ? [input.reasonCode] : []),
@@ -28531,6 +28638,7 @@ function describeReplyReadinessReason(reasonCode) {
28531
28638
  case "runtime.adapter.unsupported": return "the local agent controller setup is not supported";
28532
28639
  case "controller.bootstrap.failed": return "ATS couldn't finish setting up the local OpenClaw agent for this profile";
28533
28640
  case "controller.gateway.unhealthy": return "the local OpenClaw Gateway is not healthy on this device";
28641
+ case "local_agents.none_needed": return "no local agents on this device need ATS Service right now";
28534
28642
  case "route.offline": return "ATS server can't currently see an active daemon route for this profile";
28535
28643
  case "route.not_registered": return "ATS is still setting up replies for this profile on this device";
28536
28644
  default: return "ATS can't confirm local reply readiness yet";
@@ -30889,7 +30997,7 @@ const COMMAND_ENTRY_COPY_BY_NAME = Object.freeze({
30889
30997
  signInAction: "creating a space",
30890
30998
  profileAction: "creating a space",
30891
30999
  cliUpdateAction: "creating a space",
30892
- serviceAction: "creating a space"
31000
+ serviceAction: null
30893
31001
  },
30894
31002
  "space.delete": {
30895
31003
  signInAction: "deleting a space",
@@ -30919,7 +31027,7 @@ const COMMAND_ENTRY_COPY_BY_NAME = Object.freeze({
30919
31027
  signInAction: "joining a space",
30920
31028
  profileAction: "joining a space",
30921
31029
  cliUpdateAction: "joining a space",
30922
- serviceAction: "joining a space"
31030
+ serviceAction: null
30923
31031
  },
30924
31032
  "space.add-members": {
30925
31033
  signInAction: "adding members to a space",
@@ -30937,7 +31045,7 @@ const COMMAND_ENTRY_COPY_BY_NAME = Object.freeze({
30937
31045
  signInAction: "watching a space",
30938
31046
  profileAction: "watching a space",
30939
31047
  cliUpdateAction: "watching a space",
30940
- serviceAction: "watching a space"
31048
+ serviceAction: null
30941
31049
  },
30942
31050
  "space.send": {
30943
31051
  signInAction: "sending a message",
@@ -31346,6 +31454,82 @@ async function runCliUpdateCheck(input) {
31346
31454
  };
31347
31455
  }
31348
31456
 
31457
+ //#endregion
31458
+ //#region src/onboarding/disclaimer.ts
31459
+ const ATS_ACCEPT_DISCLAIMER_ENV = "ATS_ACCEPT_DISCLAIMER";
31460
+ const ATS_ONBOARDING_DISCLAIMER_ACCEPT = "__onboarding_disclaimer_accept__";
31461
+ const ATS_ONBOARDING_DISCLAIMER_DECLINE = "__onboarding_disclaimer_decline__";
31462
+ const ATS_ONBOARDING_DISCLAIMER_TEXT = "ATSD is experimental and changes rapidly. Breaking changes may occur. You are fully responsible for data security and sensitive information handling. Use ATSD only in trusted environments.";
31463
+ async function runOnboardingDisclaimerGate(input) {
31464
+ if (await getConfiguredOnboardingDisclaimerAcceptedAt().catch(() => null)) return true;
31465
+ if (shouldBypassDisclaimerWithEnv()) {
31466
+ await persistOnboardingDisclaimerAccepted();
31467
+ return true;
31468
+ }
31469
+ if (input.runtime.resolvedView === "agent") {
31470
+ input.presenter.data({
31471
+ code: input.codePrefix,
31472
+ payload: {
31473
+ acceptedAt: null,
31474
+ text: ATS_ONBOARDING_DISCLAIMER_TEXT,
31475
+ mode: "agent_notice",
31476
+ requiresConfirmation: false
31477
+ }
31478
+ });
31479
+ await persistOnboardingDisclaimerAccepted();
31480
+ return true;
31481
+ }
31482
+ note(`⚠️ ${ATS_ONBOARDING_DISCLAIMER_TEXT}`, "Disclaimer");
31483
+ if (!input.interactive) {
31484
+ input.presenter.line({
31485
+ code: `${input.codePrefix}.auto_continue`,
31486
+ text: "Non-interactive session: disclaimer displayed and ATS continues."
31487
+ });
31488
+ await persistOnboardingDisclaimerAccepted();
31489
+ return true;
31490
+ }
31491
+ const decision = await select({
31492
+ message: "Do you accept and continue?",
31493
+ options: [{
31494
+ value: ATS_ONBOARDING_DISCLAIMER_ACCEPT,
31495
+ label: "Yes, continue"
31496
+ }, {
31497
+ value: ATS_ONBOARDING_DISCLAIMER_DECLINE,
31498
+ label: "No, exit"
31499
+ }],
31500
+ initialValue: ATS_ONBOARDING_DISCLAIMER_ACCEPT
31501
+ });
31502
+ if (isCancel(decision) || decision === ATS_ONBOARDING_DISCLAIMER_DECLINE) {
31503
+ cancel("Cancelled.");
31504
+ return false;
31505
+ }
31506
+ await persistOnboardingDisclaimerAccepted();
31507
+ return true;
31508
+ }
31509
+ function shouldBypassDisclaimerWithEnv() {
31510
+ return String(process.env[ATS_ACCEPT_DISCLAIMER_ENV] ?? "").trim() === "1";
31511
+ }
31512
+ async function persistOnboardingDisclaimerAccepted() {
31513
+ const acceptedAt = (/* @__PURE__ */ new Date()).toISOString();
31514
+ await updateConfiguredOnboardingConfig((current) => ({
31515
+ ...current ?? {},
31516
+ disclaimerAcceptedAt: acceptedAt
31517
+ }));
31518
+ }
31519
+
31520
+ //#endregion
31521
+ //#region src/command-entry-checks/check-disclaimer.ts
31522
+ async function runDisclaimerCheck(input) {
31523
+ if (input.requirement.mode === "skip") return { status: "continue" };
31524
+ if (await runOnboardingDisclaimerGate({
31525
+ runtime: input.context.runtime,
31526
+ presenter: input.context.presenter,
31527
+ interactive: input.context.allowPrompt,
31528
+ codePrefix: "command.entry.disclaimer"
31529
+ })) return { status: "continue" };
31530
+ return { status: "cancelled" };
31531
+ }
31532
+
31349
31533
  //#endregion
31350
31534
  //#region src/config/storage-version.ts
31351
31535
  const STORAGE_VERSION_SCHEMA = "ats-local-state-v1";
@@ -46783,7 +46967,7 @@ function resolveServiceParticipationReadiness(input) {
46783
46967
  };
46784
46968
  }
46785
46969
  if (reasonCodes.includes("service.not_installed")) {
46786
- const nextSteps = formatAtsCliCommands(["ats service install", "ats service run --mode foreground"]);
46970
+ const nextSteps = formatAtsCliCommands(["ats service install", "ats service run"]);
46787
46971
  return {
46788
46972
  serviceReadiness: "not_installed",
46789
46973
  summaryText: "Not installed",
@@ -46794,7 +46978,7 @@ function resolveServiceParticipationReadiness(input) {
46794
46978
  };
46795
46979
  }
46796
46980
  if (reasonCodes.includes("service.not_running")) {
46797
- const nextSteps = [formatAtsCliCommand("ats service run --mode foreground")];
46981
+ const nextSteps = [formatAtsCliCommand("ats service run")];
46798
46982
  return {
46799
46983
  serviceReadiness: "not_running",
46800
46984
  summaryText: "Not running",
@@ -46812,6 +46996,21 @@ function resolveServiceParticipationReadiness(input) {
46812
46996
  nextSteps: [],
46813
46997
  runtimeHeadline
46814
46998
  };
46999
+ if (reasonCodes.includes("local_agents.none_needed")) {
47000
+ const nextSteps = formatAtsCliCommands([
47001
+ "ats start",
47002
+ "ats service install",
47003
+ "ats service run"
47004
+ ]);
47005
+ return {
47006
+ serviceReadiness: "unknown",
47007
+ summaryText: "Not needed yet",
47008
+ detailText: input.deviceReplyReadiness.reasonText,
47009
+ nextStepSummary: "If you later choose local agents to bring into a space, rerun `ats start` or enable ATS Service directly.",
47010
+ nextSteps,
47011
+ runtimeHeadline
47012
+ };
47013
+ }
46815
47014
  const nextSteps = [formatAtsCliCommand("ats service status")];
46816
47015
  return {
46817
47016
  serviceReadiness: "unknown",
@@ -50851,7 +51050,7 @@ function mapLocalControllerStatusReason(reason) {
50851
51050
  const projectedControllersDisabledReason = "one or more projected controllers are disabled locally";
50852
51051
  if (reason.includes("already exists")) return "setup is already prepared";
50853
51052
  if (reason.includes("authentication is not valid")) return "sign in required";
50854
- if (reason.includes("no bound agent controller requires local projection")) return "no local agent is configured for this device";
51053
+ if (reason.includes(NO_LOCAL_AGENTS_NEED_ATS_SERVICE_REASON)) return "no local agent is configured for this device";
50855
51054
  if (reason.includes(missingOrDisabledReason)) return "some local agents are missing or turned off";
50856
51055
  if (reason.includes("is missing for one or more bound controllers")) return "some local agents are missing";
50857
51056
  if (reason.includes(projectedControllersDisabledReason)) return "some local agent entries are disabled";
@@ -51057,6 +51256,177 @@ async function ensureDaemonVersionForCliStartup(input) {
51057
51256
  };
51058
51257
  }
51059
51258
 
51259
+ //#endregion
51260
+ //#region src/system/daemon-service-participation-gate.ts
51261
+ function shouldRequireDaemonServiceParticipation(localDemand) {
51262
+ return localDemand?.decision === "keep_running";
51263
+ }
51264
+ async function resolveDaemonServiceParticipationStatus(input) {
51265
+ const expectedVersion = input?.expectedVersion ?? resolveCurrentDaemonExpectedVersion();
51266
+ const inventory = await inspectDaemonServiceInventory({ expectedVersion });
51267
+ if (!(inventory.installStatus.installed && inventory.installStatus.state)) return {
51268
+ kind: "missing",
51269
+ expectedVersion
51270
+ };
51271
+ const installedVersion = inventory.installStatus.state.daemonVersion;
51272
+ if (installedVersion !== expectedVersion) return {
51273
+ kind: "outdated",
51274
+ expectedVersion,
51275
+ installedVersion
51276
+ };
51277
+ const repairAnomalies = inventory.anomalies.filter((anomaly) => DAEMON_SERVICE_REPAIR_ANOMALIES.has(anomaly.code));
51278
+ if (repairAnomalies.length > 0) return {
51279
+ kind: "needs_repair",
51280
+ expectedVersion,
51281
+ installedVersion,
51282
+ runtimeStatus: inventory.runtimeStatus.status,
51283
+ detail: repairAnomalies[0]?.message ?? "ATS found conflicting local service state on this device.",
51284
+ anomalyCodes: repairAnomalies.map((anomaly) => anomaly.code)
51285
+ };
51286
+ if (inventory.runtimeStatus.status !== "running") return {
51287
+ kind: "not_running",
51288
+ expectedVersion,
51289
+ installedVersion,
51290
+ runtimeStatus: inventory.runtimeStatus.status
51291
+ };
51292
+ return {
51293
+ kind: "ready",
51294
+ expectedVersion,
51295
+ installedVersion,
51296
+ runtimeStatus: inventory.runtimeStatus.status
51297
+ };
51298
+ }
51299
+ async function runDaemonServiceParticipationGate(input) {
51300
+ if (!shouldRunDaemonServiceParticipationGate(input)) return { status: "aligned" };
51301
+ const initialStatus = await resolveDaemonServiceParticipationStatus();
51302
+ if (initialStatus.kind === "ready") return { status: "aligned" };
51303
+ const codePrefix = resolveDaemonServiceParticipationCodePrefix(input.intent);
51304
+ const installStageResult = await runDaemonServiceParticipationInstallStage({
51305
+ input,
51306
+ codePrefix,
51307
+ status: initialStatus
51308
+ });
51309
+ if (installStageResult.result) return installStageResult.result;
51310
+ return await runDaemonServiceParticipationActionStage({
51311
+ input,
51312
+ codePrefix,
51313
+ status: installStageResult.status
51314
+ });
51315
+ }
51316
+ function shouldRunDaemonServiceParticipationGate(input) {
51317
+ return input.resolvedView === "human" && input.allowPrompt && (input.forcePrompt === true || shouldRequireDaemonServiceParticipation(input.localDemand));
51318
+ }
51319
+ async function runDaemonServiceParticipationInstallStage(input) {
51320
+ if (input.status.kind !== "missing" && input.status.kind !== "outdated") return { status: input.status };
51321
+ const installResult = await runDaemonInstallDecisionPrompt({
51322
+ kind: input.status.kind,
51323
+ ...input.status.kind === "outdated" ? { installedVersion: input.status.installedVersion } : {},
51324
+ expectedVersion: input.status.expectedVersion,
51325
+ emitLine: (text) => {
51326
+ input.input.presenter.line({
51327
+ code: `${input.codePrefix}.install`,
51328
+ text
51329
+ });
51330
+ },
51331
+ installService: async () => {
51332
+ await runDaemonInstall({ view: input.input.view }, { suppressHumanOutput: shouldSuppressHumanInstallOutput(input.input.intent) });
51333
+ }
51334
+ });
51335
+ if (installResult === "cancelled") return {
51336
+ status: input.status,
51337
+ result: { status: "cancelled" }
51338
+ };
51339
+ if (installResult === "failed") return {
51340
+ status: input.status,
51341
+ result: { status: "needs_attention" }
51342
+ };
51343
+ if (installResult === "not_now" || !shouldStartAfterDaemonInstall(input.input.intent)) return {
51344
+ status: input.status,
51345
+ result: { status: "declined" }
51346
+ };
51347
+ const refreshedStatus = await resolveDaemonServiceParticipationStatus();
51348
+ if (refreshedStatus.kind === "ready") return {
51349
+ status: refreshedStatus,
51350
+ result: { status: "aligned" }
51351
+ };
51352
+ if (refreshedStatus.kind === "missing" || refreshedStatus.kind === "outdated") {
51353
+ renderDaemonStartNeedsAttention({
51354
+ presenter: input.input.presenter,
51355
+ codePrefix: input.codePrefix,
51356
+ summary: refreshedStatus.kind === "missing" ? formatDaemonInstallFailedMessage("missing") : formatDaemonInstallFailedMessage("outdated")
51357
+ });
51358
+ return {
51359
+ status: refreshedStatus,
51360
+ result: { status: "needs_attention" }
51361
+ };
51362
+ }
51363
+ return { status: refreshedStatus };
51364
+ }
51365
+ async function runDaemonServiceParticipationActionStage(input) {
51366
+ if (input.status.kind === "needs_repair") return mapDaemonBackgroundStartResult(await runDaemonBackgroundStartForDecision({ view: input.input.view }), {
51367
+ presenter: input.input.presenter,
51368
+ codePrefix: input.codePrefix
51369
+ });
51370
+ if (input.status.kind !== "not_running") return { status: "aligned" };
51371
+ return mapDaemonBackgroundStartResult(await runDaemonStartDecisionPrompt({ startService: async () => await runDaemonBackgroundStartForDecision({ view: input.input.view }) }), {
51372
+ presenter: input.input.presenter,
51373
+ codePrefix: input.codePrefix
51374
+ });
51375
+ }
51376
+ function resolveDaemonServiceParticipationCodePrefix(intent) {
51377
+ switch (intent) {
51378
+ case "start": return "start.service";
51379
+ case "space_create_join": return "space.create_join.service";
51380
+ case "space_join": return "space.join.service";
51381
+ case "space_add_members": return "space.add_members.service";
51382
+ default: throw new Error(`Unknown daemon service participation intent: ${intent}`);
51383
+ }
51384
+ }
51385
+ function shouldStartAfterDaemonInstall(_intent) {
51386
+ return true;
51387
+ }
51388
+ function shouldSuppressHumanInstallOutput(intent) {
51389
+ return intent !== "start";
51390
+ }
51391
+ function mapDaemonBackgroundStartResult(result, input) {
51392
+ if (result === "started" || result === "deferred_with_card") return { status: "aligned" };
51393
+ if (result === "cancelled") return { status: "cancelled" };
51394
+ if (result === "not_now") {
51395
+ renderDaemonStartDeferred({
51396
+ presenter: input.presenter,
51397
+ codePrefix: input.codePrefix
51398
+ });
51399
+ return { status: "declined" };
51400
+ }
51401
+ if (result === "failed") {
51402
+ renderDaemonStartNeedsAttention({
51403
+ presenter: input.presenter,
51404
+ codePrefix: input.codePrefix,
51405
+ summary: "ATS could not finish starting ATS Service."
51406
+ });
51407
+ return { status: "needs_attention" };
51408
+ }
51409
+ return { status: "needs_attention" };
51410
+ }
51411
+ function renderDaemonStartDeferred(input) {
51412
+ const card = buildDaemonStartDeferredCard();
51413
+ renderInfoCard({
51414
+ presenter: input.presenter,
51415
+ title: card.title,
51416
+ codePrefix: `${input.codePrefix}.deferred`,
51417
+ rows: card.rows
51418
+ });
51419
+ }
51420
+ function renderDaemonStartNeedsAttention(input) {
51421
+ const card = buildDaemonStartNeedsAttentionCard({ summary: input.summary });
51422
+ renderInfoCard({
51423
+ presenter: input.presenter,
51424
+ title: card.title,
51425
+ codePrefix: `${input.codePrefix}.failed`,
51426
+ rows: card.rows
51427
+ });
51428
+ }
51429
+
51060
51430
  //#endregion
51061
51431
  //#region src/command-entry-checks/check-service.ts
51062
51432
  const FIX_SERVICE = "__command_entry_fix_service__";
@@ -51069,10 +51439,9 @@ async function runServiceCheck(input) {
51069
51439
  shouldAutoRepair: input.requirement.mode !== "status-only",
51070
51440
  view: input.context.runtime.resolvedView
51071
51441
  });
51072
- const shouldSuppressStandaloneHumanServiceCard = shouldDeferHumanServiceCardToJoinQuickCheck(input.context);
51073
51442
  if (serviceStatus.kind === "ready") return { status: "continue" };
51074
51443
  if (input.requirement.mode === "status-only") {
51075
- if (!shouldSuppressStandaloneHumanServiceCard) emitServiceStatus({
51444
+ emitServiceStatus({
51076
51445
  context: input.context,
51077
51446
  serviceStatus,
51078
51447
  blocking: false
@@ -51080,22 +51449,21 @@ async function runServiceCheck(input) {
51080
51449
  return { status: "continue" };
51081
51450
  }
51082
51451
  if (input.context.runtime.resolvedView !== "human" || !input.context.allowPrompt) {
51083
- if (!shouldSuppressStandaloneHumanServiceCard) emitServiceStatus({
51452
+ emitServiceStatus({
51084
51453
  context: input.context,
51085
51454
  serviceStatus,
51086
51455
  blocking: false
51087
51456
  });
51088
51457
  return { status: "continue" };
51089
51458
  }
51090
- if (serviceStatus.kind === "repair_blocked" || serviceStatus.kind === "repair_failed") {
51091
- if (!shouldSuppressStandaloneHumanServiceCard) emitServiceStatus({
51459
+ if (serviceStatus.kind === "needs_repair" || serviceStatus.kind === "repair_blocked" || serviceStatus.kind === "repair_failed") {
51460
+ emitServiceStatus({
51092
51461
  context: input.context,
51093
51462
  serviceStatus,
51094
51463
  blocking: false
51095
51464
  });
51096
51465
  return { status: "continue" };
51097
51466
  }
51098
- if (shouldSuppressStandaloneHumanServiceCard) return { status: "continue" };
51099
51467
  const copy = getCommandEntryCopy(input.context.entryName);
51100
51468
  showHumanCheckCard({
51101
51469
  presenter: input.context.presenter,
@@ -51130,12 +51498,21 @@ async function runServiceCheck(input) {
51130
51498
  if (!await fixServiceStatus(serviceStatus)) return { status: "continue" };
51131
51499
  return { status: "continue" };
51132
51500
  }
51133
- function shouldDeferHumanServiceCardToJoinQuickCheck(context) {
51134
- return context.entryName === "space.join" && context.runtime.resolvedView === "human";
51135
- }
51136
51501
  async function resolveServiceStatus(input) {
51137
51502
  const expectedVersion = resolveCurrentDaemonExpectedVersion();
51138
- const currentStatus = await readCurrentServiceStatus(expectedVersion);
51503
+ const currentStatus = await resolveDaemonServiceParticipationStatus({ expectedVersion }).catch((error) => {
51504
+ warnServiceCheckIssue("resolveDaemonServiceParticipationStatus failed", {
51505
+ error,
51506
+ expectedVersion,
51507
+ view: input.view
51508
+ });
51509
+ return {
51510
+ kind: "not_running",
51511
+ expectedVersion,
51512
+ installedVersion: null,
51513
+ runtimeStatus: null
51514
+ };
51515
+ });
51139
51516
  if (currentStatus.kind === "ready") return currentStatus;
51140
51517
  if (input.shouldAutoRepair) {
51141
51518
  const preflight = await runDaemonStartupPreflight({
@@ -51158,27 +51535,19 @@ async function resolveServiceStatus(input) {
51158
51535
  detail: buildStartupPreflightAttentionDetail(preflight)
51159
51536
  };
51160
51537
  }
51161
- return await readCurrentServiceStatus(expectedVersion);
51162
- }
51163
- async function readCurrentServiceStatus(expectedVersion) {
51164
- const daemonStatus = await getDaemonStatus();
51165
- if (!(daemonStatus.installed && daemonStatus.state)) return { kind: "missing" };
51166
- if (daemonStatus.state.daemonVersion !== expectedVersion) return {
51167
- kind: "outdated",
51168
- installedVersion: daemonStatus.state.daemonVersion
51169
- };
51170
- const runtime = await readCurrentDaemonRuntimeContext({ status: daemonStatus }).catch((error) => {
51171
- warnServiceCheckIssue("readCurrentDaemonRuntimeContext failed", {
51172
- daemonStatus,
51173
- error
51538
+ return await resolveDaemonServiceParticipationStatus({ expectedVersion }).catch((error) => {
51539
+ warnServiceCheckIssue("resolveDaemonServiceParticipationStatus failed", {
51540
+ error,
51541
+ expectedVersion,
51542
+ view: input.view
51174
51543
  });
51175
- return null;
51544
+ return {
51545
+ kind: "not_running",
51546
+ expectedVersion,
51547
+ installedVersion: null,
51548
+ runtimeStatus: null
51549
+ };
51176
51550
  });
51177
- if (!runtime || runtime.effectiveRuntimeStatus !== "running") return {
51178
- kind: "not_running",
51179
- runtimeStatus: runtime?.runtimeStatus ?? null
51180
- };
51181
- return { kind: "ready" };
51182
51551
  }
51183
51552
  async function fixServiceStatus(serviceStatus) {
51184
51553
  const expectedVersion = resolveCurrentDaemonExpectedVersion();
@@ -51199,6 +51568,7 @@ async function fixServiceStatus(serviceStatus) {
51199
51568
  return true;
51200
51569
  }
51201
51570
  if (serviceStatus.kind === "not_running") return await runDaemonBackgroundStartForDecision({ view: "human" }) === "started";
51571
+ if (serviceStatus.kind === "needs_repair") return await runDaemonBackgroundStartForDecision({ view: "human" }) === "started";
51202
51572
  if (serviceStatus.kind === "repair_blocked" || serviceStatus.kind === "repair_failed") {
51203
51573
  await runDaemonStatusSafely();
51204
51574
  return false;
@@ -51248,6 +51618,7 @@ function emitServiceStatus(input) {
51248
51618
  function buildServiceStatusText(serviceStatus) {
51249
51619
  if (serviceStatus.kind === "missing") return "ATS Service is not installed on this device.";
51250
51620
  if (serviceStatus.kind === "outdated") return `ATS Service is on ${serviceStatus.installedVersion}. ${resolveCurrentDaemonExpectedVersion()} is needed.`;
51621
+ if (serviceStatus.kind === "needs_repair") return "ATS Service needs cleanup before local agents on this device can reply from Space.";
51251
51622
  if (serviceStatus.kind === "repair_blocked") return "ATS Service needs manual repair before ATS can align it automatically.";
51252
51623
  if (serviceStatus.kind === "repair_failed") return "ATS tried to repair ATS Service automatically, but the service still needs attention.";
51253
51624
  return "ATS Service is installed but not running.";
@@ -51255,17 +51626,19 @@ function buildServiceStatusText(serviceStatus) {
51255
51626
  function buildServiceNextText(serviceStatus, action) {
51256
51627
  if (serviceStatus.kind === "missing") return action ? `Install ATS Service now, or continue ${action} without it.` : "Install ATS Service now, or continue without it.";
51257
51628
  if (serviceStatus.kind === "outdated") return "Update ATS Service now to match the current ATS CLI.";
51629
+ if (serviceStatus.kind === "needs_repair") return "Repair ATS Service now so local agents on this device can reply from Space again.";
51258
51630
  if (serviceStatus.kind === "repair_blocked" || serviceStatus.kind === "repair_failed") return "Run `ats service status` first. If ATS still says the service needs repair, run `ats service reinstall`.";
51259
51631
  return action ? `Start ATS Service now, or continue ${action} without it.` : "Start ATS Service now, or continue without it.";
51260
51632
  }
51261
51633
  function buildServiceFixLabel(serviceStatus) {
51262
51634
  if (serviceStatus.kind === "missing") return "Install ATS Service now (Recommended)";
51263
51635
  if (serviceStatus.kind === "outdated") return "Update ATS Service now (Recommended)";
51636
+ if (serviceStatus.kind === "needs_repair") return "Repair ATS Service now (Recommended)";
51264
51637
  if (serviceStatus.kind === "repair_blocked" || serviceStatus.kind === "repair_failed") return "Open ATS Service diagnostics (Recommended)";
51265
51638
  return "Start ATS Service now (Recommended)";
51266
51639
  }
51267
51640
  function buildServiceAgentNextSteps(serviceStatus) {
51268
- if (serviceStatus.kind === "repair_blocked" || serviceStatus.kind === "repair_failed") return formatAtsCliCommands(["ats service status", "ats service reinstall"]);
51641
+ if (serviceStatus.kind === "needs_repair" || serviceStatus.kind === "repair_blocked" || serviceStatus.kind === "repair_failed") return formatAtsCliCommands(["ats service status", "ats service reinstall"]);
51269
51642
  return formatAtsCliCommands(["ats service install", "ats service run"]);
51270
51643
  }
51271
51644
  function buildStartupPreflightAttentionDetail(preflight) {
@@ -54683,6 +55056,7 @@ async function runSkillsCheck(input) {
54683
55056
  //#endregion
54684
55057
  //#region src/command-entry-checks/run-command-entry-flow.ts
54685
55058
  const CHECK_RUNNERS = {
55059
+ disclaimer: runDisclaimerCheck,
54686
55060
  cliUpdate: runCliUpdateCheck,
54687
55061
  signIn: runSignInCheck,
54688
55062
  selectedProfile: runSelectedProfileCheck,
@@ -54697,6 +55071,7 @@ const CHECK_STAGES = [
54697
55071
  "status-only"
54698
55072
  ];
54699
55073
  const CHECK_ORDER = [
55074
+ "disclaimer",
54700
55075
  "cliUpdate",
54701
55076
  "localRuntimeState",
54702
55077
  "signIn",
@@ -60578,6 +60953,7 @@ function buildServiceReplyReadinessGuidance(input) {
60578
60953
  }
60579
60954
  function buildReplyReadinessGuidanceSummary(reasonCode) {
60580
60955
  switch (reasonCode) {
60956
+ case "local_agents.none_needed": return "This device does not need ATS Service until you choose local agents to bring into a space.";
60581
60957
  case "profile.inactive": return "Choose an active agent profile first.";
60582
60958
  case "profile.unbound": return "This profile is not connected to an agent yet.";
60583
60959
  case "controller.binding.disabled": return "This profile's agent is turned off.";
@@ -60606,6 +60982,11 @@ function buildReplyReadinessNextSteps(input) {
60606
60982
  controllerRef
60607
60983
  }) ?? controllerRef ?? "<agent-id>";
60608
60984
  switch (input.reasonCode) {
60985
+ case "local_agents.none_needed": return [
60986
+ formatAtsCliCommand("ats start"),
60987
+ formatAtsCliCommand("ats service install"),
60988
+ formatAtsCliCommand("ats service run")
60989
+ ];
60609
60990
  case "profile.inactive": return [formatAtsCliCommand("ats profile list"), formatAtsCliCommand("ats profile set <agent-profile-id>")];
60610
60991
  case "profile.unbound": return [formatAtsCliCommand(`ats profile update ${profileId} --controller-kind builtin --controller-ref ${controllerRef ?? "<controller-ref>"} --controller-enabled true`), formatAtsCliCommand(`ats space join <space-id> --profile ${profileId}`)];
60611
60992
  case "controller.binding.disabled": return [formatAtsCliCommand(`ats profile update ${profileId} --controller-enabled true`)];
@@ -62628,19 +63009,6 @@ function normalizeOptionalString$5(value) {
62628
63009
 
62629
63010
  //#endregion
62630
63011
  //#region src/start-foundation/selectors.ts
62631
- const BACKGROUND_HELPER_REASON_CODES = new Set([
62632
- "background_helper.not_installed",
62633
- "background_helper.installed_outdated",
62634
- "background_helper.not_running",
62635
- "background_helper.stale",
62636
- "background_helper.unknown"
62637
- ]);
62638
- function isCliStartBackgroundHelperReasonCode(reasonCode) {
62639
- return BACKGROUND_HELPER_REASON_CODES.has(reasonCode);
62640
- }
62641
- function isCliStartBackgroundHelperSignal(signal) {
62642
- return signal.actionId === "device_check" && isCliStartBackgroundHelperReasonCode(signal.reasonCode);
62643
- }
62644
63012
  function findCliStartSelectedProfileReadinessEntry(input) {
62645
63013
  return input.foundation.foundationState.readModel.profileReadiness.find((entry) => entry.profileId === input.profileId) ?? null;
62646
63014
  }
@@ -62650,8 +63018,13 @@ function readCliStartDeviceProjection(foundation) {
62650
63018
  function isCliStartNextActionBlocked(foundation) {
62651
63019
  return foundation.foundationState.decision.status === "blocking";
62652
63020
  }
62653
- function hasCliStartBackgroundHelperBlockingOrAttentionSignal(foundation) {
62654
- return [...foundation.foundationState.decision.blocking, ...foundation.foundationState.decision.attention].some(isCliStartBackgroundHelperSignal);
63021
+ function hasCliStartSelectedLocalAgents(foundation) {
63022
+ return foundation.foundationState.readModel.session.value?.agentSelection.mode === "selected_agents";
63023
+ }
63024
+ function readCliStartSelectedLocalAgentIds(foundation) {
63025
+ const agentSelection = foundation.foundationState.readModel.session.value?.agentSelection;
63026
+ if (!agentSelection || agentSelection.mode !== "selected_agents") return [];
63027
+ return agentSelection.selectedAgentIds;
62655
63028
  }
62656
63029
 
62657
63030
  //#endregion
@@ -62945,12 +63318,6 @@ function collectStartLocalBackgroundHelperReadiness() {
62945
63318
  async function resolveStartLocalBackgroundHelperDemand(input) {
62946
63319
  return await resolveDaemonLocalServiceDemand(input);
62947
63320
  }
62948
- async function runStartLocalBackgroundHelperInstall(input) {
62949
- await runDaemonInstall({ view: input.view });
62950
- }
62951
- async function runStartLocalBackgroundHelperBackgroundStart(input) {
62952
- return await runDaemonBackgroundStartForDecision({ view: input.view });
62953
- }
62954
63321
 
62955
63322
  //#endregion
62956
63323
  //#region src/start-local/skills-local.ts
@@ -62993,49 +63360,13 @@ async function collectStartLocalReadiness(input) {
62993
63360
 
62994
63361
  //#endregion
62995
63362
  //#region src/commands/start-auth-and-readiness.ts
62996
- const START_DISCLAIMER_ACCEPT = "__start_disclaimer_accept__";
62997
- const START_DISCLAIMER_DECLINE = "__start_disclaimer_decline__";
62998
- const START_V1_DISCLAIMER_VERSION = "start-v1-2026-03-02";
62999
- const START_V1_DISCLAIMER_TEXT = "ATSD is experimental and changes rapidly. Breaking changes may occur. You are fully responsible for data security and sensitive information handling. Use ATSD only in trusted environments.";
63000
63363
  async function runStartDisclaimerStep(input) {
63001
- if ((await getConfiguredStartV1OnboardingState().catch(() => null))?.disclaimerAcceptedVersion === START_V1_DISCLAIMER_VERSION) return true;
63002
- if (input.runtime.resolvedView === "agent") {
63003
- input.presenter.data({
63004
- code: "start.disclaimer",
63005
- payload: {
63006
- version: START_V1_DISCLAIMER_VERSION,
63007
- text: START_V1_DISCLAIMER_TEXT,
63008
- mode: "agent_notice",
63009
- requiresConfirmation: false
63010
- }
63011
- });
63012
- return true;
63013
- }
63014
- note(`⚠️ ${START_V1_DISCLAIMER_TEXT}`, "Disclaimer");
63015
- if (!input.interactive) {
63016
- input.presenter.line({
63017
- code: "start.disclaimer.auto_continue",
63018
- text: "Non-interactive session: disclaimer displayed and onboarding continues."
63019
- });
63020
- return true;
63021
- }
63022
- const decision = await select({
63023
- message: "Do you accept and continue?",
63024
- options: [{
63025
- value: START_DISCLAIMER_ACCEPT,
63026
- label: "Yes, continue"
63027
- }, {
63028
- value: START_DISCLAIMER_DECLINE,
63029
- label: "No, exit"
63030
- }],
63031
- initialValue: START_DISCLAIMER_ACCEPT
63364
+ return await runOnboardingDisclaimerGate({
63365
+ runtime: input.runtime,
63366
+ presenter: input.presenter,
63367
+ interactive: input.interactive,
63368
+ codePrefix: "start.disclaimer"
63032
63369
  });
63033
- if (isCancel(decision) || decision === START_DISCLAIMER_DECLINE) {
63034
- cancel("Cancelled.");
63035
- return false;
63036
- }
63037
- await persistStartDisclaimerAccepted();
63038
- return true;
63039
63370
  }
63040
63371
  async function markStartV1Completed() {
63041
63372
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -63122,12 +63453,6 @@ function formatReadinessLine(input) {
63122
63453
  if (!input.detail) return line;
63123
63454
  return `${line} ${pc.dim(input.detail)}`;
63124
63455
  }
63125
- async function persistStartDisclaimerAccepted() {
63126
- await updateConfiguredStartV1OnboardingState((current) => ({
63127
- ...current ?? {},
63128
- disclaimerAcceptedVersion: START_V1_DISCLAIMER_VERSION
63129
- }));
63130
- }
63131
63456
  function evaluateStartAuthentication(input) {
63132
63457
  return evaluateCommandAuthentication({ gatewayUrl: input.gatewayUrl });
63133
63458
  }
@@ -64292,10 +64617,14 @@ function resolveStartBackgroundHelperShellState(input) {
64292
64617
  runtimeStatus: input.readiness.service.runtime?.status ?? "unknown"
64293
64618
  };
64294
64619
  }
64295
- function resolveStartServiceRecommendation(input) {
64296
- if (input.backgroundHelper.status === "installed_outdated") return "recommended";
64297
- if (input.backgroundHelper.status === "installed_current") return input.localDemand?.decision === "keep_running" ? "recommended" : "optional";
64298
- return hasCliStartBackgroundHelperBlockingOrAttentionSignal(input.foundation) ? "recommended" : "optional";
64620
+ function haveRunnableSelectedLocalAgentSetup(input) {
64621
+ const selectedAgentIds = readCliStartSelectedLocalAgentIds(input.foundation);
64622
+ if (selectedAgentIds.length === 0) return false;
64623
+ const candidateById = new Map(input.readiness.agents.candidates.map((candidate) => [candidate.agentId, candidate]));
64624
+ return selectedAgentIds.every((selectedAgentId) => {
64625
+ const candidate = candidateById.get(selectedAgentId);
64626
+ return candidate?.enabled === true && candidate.selectable === true;
64627
+ });
64299
64628
  }
64300
64629
  function emitStartServiceNonInteractiveLine(input) {
64301
64630
  const text = input.backgroundHelper.status === "installed_current" ? formatInlineAtsCliCommands("⚠️ ATS Service: Installed and up to date, but not currently running. Start it manually with `ats service run`.") : formatInlineAtsCliCommands(input.backgroundHelper.status === "not_installed" ? `⚠️ ATS Service: ${formatDaemonServiceMissingStatus()} ${formatDaemonServiceMissingAction()}` : `⚠️ ATS Service: ${formatDaemonServiceOutdatedStatus({
@@ -64307,78 +64636,47 @@ function emitStartServiceNonInteractiveLine(input) {
64307
64636
  text
64308
64637
  });
64309
64638
  }
64310
- function emitStartServiceSkippedLine(input) {
64311
- const text = resolveStartServiceSkippedText(input);
64312
- input.presenter.line({
64313
- code: "start.service.skipped",
64314
- text: formatInlineAtsCliCommands(text)
64639
+
64640
+ //#endregion
64641
+ //#region src/system/service-participation-policy.ts
64642
+ function resolveCliServiceParticipationRequirement(input) {
64643
+ return resolveServiceParticipationRequirement({
64644
+ intent: input.intent,
64645
+ humanOnlyParticipation: input.humanOnlyParticipation,
64646
+ explicitSelectedLocalAgents: input.explicitSelectedLocalAgents,
64647
+ selectedAgentProfilesHaveRunnableLocalSetup: input.selectedAgentProfilesHaveRunnableLocalSetup,
64648
+ deviceLocalDemand: mapDaemonLocalServiceDemandToSharedValue(input.localDemand)
64315
64649
  });
64316
64650
  }
64317
- function renderStartServiceDeferredCard(input) {
64318
- const card = buildDaemonStartDeferredCard();
64319
- renderInfoCard({
64320
- presenter: input.presenter,
64321
- title: card.title,
64322
- codePrefix: "start.service.deferred",
64323
- rows: card.rows
64324
- });
64651
+ function isExplicitLocalAgentProfile(profile) {
64652
+ return profile.profileKind === "agent";
64325
64653
  }
64326
- function renderStartServiceFailureCard(input) {
64327
- const card = buildDaemonStartNeedsAttentionCard({ summary: "ATS could not finish starting ATS Service." });
64328
- renderInfoCard({
64329
- presenter: input.presenter,
64330
- title: card.title,
64331
- codePrefix: "start.service.failed",
64332
- rows: card.rows
64654
+ function hasRunnableLocalAgentSetup(profile) {
64655
+ return hasRunnableLocalAgentParticipationCandidate({
64656
+ profileKind: profile.profileKind === "agent" ? "agent" : "human",
64657
+ controllerRef: profile.controllerBinding?.controllerRef,
64658
+ controllerEnabled: profile.controllerBinding?.controllerEnabled
64333
64659
  });
64334
64660
  }
64335
- async function promptForStartServiceInstallDecision(input) {
64336
- const actionLabel = input.kind === "outdated" ? "Update ATS Service now" : "Install ATS Service now";
64337
- const statusLine = input.kind === "outdated" ? formatDaemonServiceOutdatedStatus({
64338
- installedVersion: input.installedVersion,
64339
- expectedVersion: input.expectedVersion
64340
- }) : formatDaemonServiceMissingStatus();
64341
- const explanation = input.recommendation === "recommended" ? "ATS Service lets local agents on this device reply from Space, so we recommend it for this setup." : "You can keep going without ATS Service, but local agents on this device won't be able to reply from Space.";
64342
- const detailLine = input.kind === "outdated" && input.installedVersion ? `Installed v${input.installedVersion}, expected v${input.expectedVersion}.` : null;
64343
- const decision = await select({
64344
- message: [
64345
- input.kind === "outdated" ? "ATS Service needs an update. Fix it now?" : "ATS Service is missing. Install it now?",
64346
- explanation,
64347
- `Current status: ${statusLine}`,
64348
- detailLine
64349
- ].filter((line) => typeof line === "string" && line.length > 0).join("\n"),
64350
- initialValue: "fix_now",
64351
- options: [{
64352
- value: "fix_now",
64353
- label: actionLabel,
64354
- hint: input.recommendation === "recommended" ? "Recommended" : "Optional"
64355
- }, {
64356
- value: "not_now",
64357
- label: "Not now"
64358
- }]
64359
- });
64360
- if (isCancel(decision)) return "cancelled";
64361
- return decision === "fix_now" ? "fix_now" : "not_now";
64661
+ function hasAnyExplicitLocalAgentCandidates(candidates) {
64662
+ return candidates.some((candidate) => candidate.profileKind === "agent");
64362
64663
  }
64363
- function resolveStartServiceSkippedText(input) {
64364
- if (input.outcome === "failed_install") return input.backgroundHelper.status === "installed_outdated" ? "ATS Service was not updated. Local agents on this device may not be able to reply from Space. Run `ats service install`." : "ATS Service could not be installed. Local agents on this device still can't reply from Space. Run `ats service install`.";
64365
- return input.backgroundHelper.status === "installed_outdated" ? "ATS Service still needs an update. Local agents on this device may not be able to reply from Space until ATS fixes it. Run `ats service install` later." : "ATS Service is still missing. Local agents on this device can't reply from Space until you install it later with `ats service install`.";
64664
+ function haveAllExplicitLocalAgentCandidatesRunnable(candidates) {
64665
+ const agentCandidates = candidates.filter((candidate) => candidate.profileKind === "agent");
64666
+ if (agentCandidates.length === 0) return false;
64667
+ return agentCandidates.every((candidate) => hasRunnableLocalAgentParticipationCandidate(candidate));
64366
64668
  }
64367
- async function promptForStartServiceStartDecision(input) {
64368
- const decision = await select({
64369
- message: ["ATS Service is not running. Start it now?", input.recommendation === "recommended" ? "ATS Service lets local agents on this device reply from Space, so we recommend it for this setup." : "You can keep going without ATS Service, but local agents on this device won't be able to reply from Space."].join("\n"),
64370
- initialValue: "fix_now",
64371
- options: [{
64372
- value: "fix_now",
64373
- label: "Start ATS Service now",
64374
- hint: input.recommendation === "recommended" ? "Recommended" : "Optional"
64375
- }, {
64376
- value: "not_now",
64377
- label: "Not now"
64378
- }]
64379
- });
64380
- if (isCancel(decision)) return "cancelled";
64381
- return decision === "fix_now" ? "fix_now" : "not_now";
64669
+ function hasRunnableLocalAgentParticipationCandidate(candidate) {
64670
+ if (candidate.profileKind !== "agent") return false;
64671
+ return candidate.controllerEnabled === true && typeof candidate.controllerRef === "string" && candidate.controllerRef.trim().length > 0;
64672
+ }
64673
+ function mapDaemonLocalServiceDemandToSharedValue(localDemand) {
64674
+ switch (localDemand?.decision) {
64675
+ case "keep_running":
64676
+ case "allow_auto_stop":
64677
+ case "indeterminate": return localDemand.decision;
64678
+ default: return "indeterminate";
64679
+ }
64382
64680
  }
64383
64681
 
64384
64682
  //#endregion
@@ -64388,6 +64686,7 @@ async function runStartServiceStep(input) {
64388
64686
  foundation: input.foundation,
64389
64687
  readiness: input.readiness
64390
64688
  });
64689
+ const selectedLocalAgentsRequireService = hasCliStartSelectedLocalAgents(input.foundation);
64391
64690
  const payload = buildStartServicePayload({
64392
64691
  readiness: input.readiness,
64393
64692
  backgroundHelper
@@ -64399,15 +64698,7 @@ async function runStartServiceStep(input) {
64399
64698
  });
64400
64699
  return "continue";
64401
64700
  }
64402
- if (backgroundHelper.status === "installed_current") return await runInstalledCurrentStartServiceStep({
64403
- ...input,
64404
- backgroundHelper
64405
- });
64406
- const recommendation = resolveStartServiceRecommendation({
64407
- backgroundHelper,
64408
- foundation: input.foundation,
64409
- localDemand: null
64410
- });
64701
+ if (backgroundHelper.status === "installed_current" && backgroundHelper.runtimeStatus === "running") return "continue";
64411
64702
  if (!input.interactive) {
64412
64703
  emitStartServiceNonInteractiveLine({
64413
64704
  presenter: input.presenter,
@@ -64415,78 +64706,46 @@ async function runStartServiceStep(input) {
64415
64706
  });
64416
64707
  return "continue";
64417
64708
  }
64418
- const decision = await promptForStartServiceInstallDecision({
64419
- kind: backgroundHelper.status === "installed_outdated" ? "outdated" : "missing",
64420
- installedVersion: backgroundHelper.installedVersion ?? void 0,
64421
- expectedVersion: backgroundHelper.expectedVersion,
64422
- recommendation
64709
+ const localDemand = await resolveStartLocalBackgroundHelperDemand({ ownerUserId: input.ownerUserId }).catch(() => null);
64710
+ const currentProfileIsExplicitLocalAgent = isExplicitLocalAgentProfile(input.profile);
64711
+ const selectedLocalAgentsHaveRunnableLocalSetup = !selectedLocalAgentsRequireService || haveRunnableSelectedLocalAgentSetup({
64712
+ foundation: input.foundation,
64713
+ readiness: input.readiness
64423
64714
  });
64424
- if (decision === "cancelled") {
64425
- cancel("Cancelled.");
64426
- return "cancelled";
64427
- }
64428
- if (decision === "fix_now") {
64429
- try {
64430
- await runStartLocalBackgroundHelperInstall({ view: input.view });
64431
- } catch {
64432
- emitStartServiceSkippedLine({
64433
- presenter: input.presenter,
64434
- backgroundHelper,
64435
- outcome: "failed_install"
64436
- });
64437
- return "needs_attention";
64438
- }
64439
- return "continue";
64440
- }
64441
- emitStartServiceSkippedLine({
64442
- presenter: input.presenter,
64443
- backgroundHelper,
64444
- outcome: "not_fixed"
64715
+ const currentProfileHasRunnableLocalSetup = !currentProfileIsExplicitLocalAgent || hasRunnableLocalAgentSetup(input.profile);
64716
+ const serviceRequirement = resolveCliServiceParticipationRequirement({
64717
+ intent: "start",
64718
+ humanOnlyParticipation: !(selectedLocalAgentsRequireService || currentProfileIsExplicitLocalAgent) && localDemand?.decision !== "keep_running",
64719
+ explicitSelectedLocalAgents: selectedLocalAgentsRequireService || currentProfileIsExplicitLocalAgent,
64720
+ selectedAgentProfilesHaveRunnableLocalSetup: selectedLocalAgentsHaveRunnableLocalSetup && currentProfileHasRunnableLocalSetup,
64721
+ localDemand
64445
64722
  });
64446
- return "continue";
64447
- }
64448
- async function runInstalledCurrentStartServiceStep(input) {
64449
- const localDemand = input.runtime.resolvedView === "human" && input.interactive ? await resolveStartLocalBackgroundHelperDemand({ ownerUserId: input.ownerUserId }).catch(() => null) : null;
64450
- if (input.backgroundHelper.runtimeStatus === "running") return "continue";
64451
- if (localDemand && localDemand.decision !== "keep_running") return "continue";
64452
- if (!input.interactive) {
64453
- emitStartServiceNonInteractiveLine({
64454
- presenter: input.presenter,
64455
- backgroundHelper: input.backgroundHelper
64723
+ if (serviceRequirement === "not_needed") return "continue";
64724
+ if (serviceRequirement === "agent_setup_needed") {
64725
+ input.presenter.line({
64726
+ code: "start.service.agent_setup_needed",
64727
+ text: `Finish local agent setup before you bring this profile into a space. Use \`ats profile ready --profile ${input.profile.atsProfileId}\` or rerun \`ats start\`.`
64456
64728
  });
64457
64729
  return "continue";
64458
64730
  }
64459
- return await handleInstalledCurrentStartServiceDecision({
64731
+ const gateResult = await runDaemonServiceParticipationGate({
64732
+ intent: "start",
64460
64733
  presenter: input.presenter,
64461
- recommendation: resolveStartServiceRecommendation({
64462
- backgroundHelper: input.backgroundHelper,
64463
- foundation: input.foundation,
64464
- localDemand
64465
- }),
64734
+ resolvedView: input.runtime.resolvedView,
64735
+ allowPrompt: input.interactive,
64736
+ localDemand,
64737
+ forcePrompt: selectedLocalAgentsRequireService || currentProfileIsExplicitLocalAgent,
64466
64738
  view: input.view
64467
64739
  });
64468
- }
64469
- async function handleInstalledCurrentStartServiceDecision(input) {
64470
- const decision = await promptForStartServiceStartDecision({ recommendation: input.recommendation });
64471
- if (decision === "cancelled") {
64472
- cancel("Cancelled.");
64473
- return "cancelled";
64474
- }
64475
- if (decision === "not_now") {
64476
- renderStartServiceDeferredCard({ presenter: input.presenter });
64477
- return "continue";
64478
- }
64479
- const startResult = await runStartLocalBackgroundHelperBackgroundStart({ view: input.view }).catch(() => "failed");
64480
- if (startResult === "cancelled") {
64740
+ if (gateResult.status === "cancelled") {
64481
64741
  cancel("Cancelled.");
64482
64742
  return "cancelled";
64483
64743
  }
64484
- if (startResult === "deferred_with_card") return "continue";
64485
- if (startResult === "failed") {
64486
- renderStartServiceFailureCard({ presenter: input.presenter });
64487
- return "needs_attention";
64488
- }
64489
- if (startResult === "failed_with_card") return "needs_attention";
64744
+ if (gateResult.status === "needs_attention") return "needs_attention";
64745
+ if (gateResult.status === "declined") input.presenter.line({
64746
+ code: "start.service.declined",
64747
+ text: "ATS will continue without wakeable local agent participation on this device. To enable background replies later, rerun `ats start` or use `ats service install` and `ats service run`."
64748
+ });
64490
64749
  return "continue";
64491
64750
  }
64492
64751
 
@@ -71960,6 +72219,11 @@ async function emitSpaceCommandPreflight(input) {
71960
72219
  },
71961
72220
  serviceRepairGuidance: resolveSpacePreflightRepairGuidance({ serviceParticipationReadiness })
71962
72221
  };
72222
+ if (!shouldEmitSpaceCommandPreflightOutput(input.emitOutput)) return {
72223
+ deviceReplyReadiness: replyReadinessSnapshot.deviceReplyReadiness,
72224
+ payload,
72225
+ serviceParticipationReadiness
72226
+ };
71963
72227
  if (input.resolvedView === "human") {
71964
72228
  const authLabel = buildHumanPreflightAuthLabel(payload.auth);
71965
72229
  const agentReplyReadinessLabel = payload.agentReplyReadiness && input.profile.profileKind === "agent" && shouldSurfaceSenderReplyReadinessInPreflightHeadline(input.command) ? formatReplyReadinessSummary(payload.agentReplyReadiness) : null;
@@ -71971,7 +72235,8 @@ async function emitSpaceCommandPreflight(input) {
71971
72235
  profileName: payload.profile.profileName,
71972
72236
  agentReplyReadinessLabel,
71973
72237
  guidance: payload.serviceRepairGuidance,
71974
- serviceParticipationReadiness
72238
+ serviceParticipationReadiness,
72239
+ humanServiceGuidanceMode: input.humanServiceGuidanceMode ?? "show"
71975
72240
  });
71976
72241
  return {
71977
72242
  deviceReplyReadiness: replyReadinessSnapshot.deviceReplyReadiness,
@@ -72029,7 +72294,8 @@ function emitHumanSpaceCommandPreflight(input) {
72029
72294
  emitSpacePreflightRepairGuidance({
72030
72295
  presenter: input.presenter,
72031
72296
  command: input.command,
72032
- guidance: input.guidance
72297
+ guidance: input.guidance,
72298
+ mode: input.humanServiceGuidanceMode
72033
72299
  });
72034
72300
  return;
72035
72301
  }
@@ -72040,7 +72306,8 @@ function emitHumanSpaceCommandPreflight(input) {
72040
72306
  emitSpacePreflightRepairGuidance({
72041
72307
  presenter: input.presenter,
72042
72308
  command: input.command,
72043
- guidance: input.guidance
72309
+ guidance: input.guidance,
72310
+ mode: input.humanServiceGuidanceMode
72044
72311
  });
72045
72312
  }
72046
72313
  function shouldSurfaceSenderReplyReadinessInPreflightHeadline(command) {
@@ -72108,7 +72375,7 @@ function toSpacePreflightAgentReplyReadiness(input) {
72108
72375
  };
72109
72376
  }
72110
72377
  function emitSpacePreflightRepairGuidance(input) {
72111
- if (!input.guidance) return;
72378
+ if (!input.guidance || input.mode === "suppress") return;
72112
72379
  input.presenter.line({
72113
72380
  code: `space.${input.command}.preflight.next_step`,
72114
72381
  text: `Next step: ${input.guidance.summary}`,
@@ -72118,6 +72385,9 @@ function emitSpacePreflightRepairGuidance(input) {
72118
72385
  }
72119
72386
  });
72120
72387
  }
72388
+ function shouldEmitSpaceCommandPreflightOutput(emitOutput) {
72389
+ return emitOutput !== false;
72390
+ }
72121
72391
  function emitSpaceFailureNextStep(input) {
72122
72392
  const guidance = resolveSpaceFailureGuidance(input.error);
72123
72393
  if (!guidance) return;
@@ -79347,10 +79617,6 @@ function emitSpaceJoinLockBlocked(input) {
79347
79617
 
79348
79618
  //#endregion
79349
79619
  //#region src/space/join-entry.ts
79350
- const NOT_INSTALLED_DAEMON_STATUS = {
79351
- installed: false,
79352
- state: null
79353
- };
79354
79620
  const LOCAL_SERVICE_ONLY_JOIN_BLOCK_REASON_CODES = new Set([
79355
79621
  "service.drifted",
79356
79622
  "service.not_installed",
@@ -79458,99 +79724,67 @@ async function prepareSpaceJoinServiceState(input) {
79458
79724
  };
79459
79725
  }
79460
79726
  async function assertSpaceJoinTargetPreflightReady(input) {
79727
+ const serviceRequirement = input.resolvedView === "human" ? resolveCliServiceParticipationRequirement({
79728
+ intent: input.serviceIntent ?? "space_join",
79729
+ humanOnlyParticipation: !isExplicitLocalAgentProfile(input.atsProfile) && input.localDemand?.decision !== "keep_running",
79730
+ explicitSelectedLocalAgents: isExplicitLocalAgentProfile(input.atsProfile),
79731
+ selectedAgentProfilesHaveRunnableLocalSetup: hasRunnableLocalAgentSetup(input.atsProfile),
79732
+ localDemand: input.localDemand ?? null
79733
+ }) : "not_needed";
79734
+ if (serviceRequirement === "agent_setup_needed") {
79735
+ input.presenter.line({
79736
+ code: "space.join.agent_setup_needed",
79737
+ text: `Finish local agent setup before you bring this profile into a space. Use \`ats profile ready --profile ${input.atsProfile.atsProfileId}\` or rerun \`ats start\`.`
79738
+ });
79739
+ return "cancelled";
79740
+ }
79741
+ const shouldManageServiceParticipation = serviceRequirement === "offer_service_gate";
79461
79742
  const runPreflight = async () => await emitSpaceCommandPreflight({
79462
79743
  presenter: input.presenter,
79463
79744
  command: "join",
79464
79745
  profile: input.atsProfile,
79465
79746
  baseUrl: input.baseUrl,
79466
- resolvedView: input.resolvedView
79467
- });
79468
- let preflight = await runPreflight();
79469
- const blockingLocalServiceOutcome = await maybeHandleBlockingLocalServiceAttentionBeforeSpaceJoin({
79470
- localDemand: input.localDemand ?? null,
79471
- preflight,
79472
- presenter: input.presenter,
79473
79747
  resolvedView: input.resolvedView,
79474
- view: input.view
79748
+ humanServiceGuidanceMode: shouldManageServiceParticipation || serviceRequirement === "not_needed" ? "suppress" : "show"
79475
79749
  });
79476
- if (blockingLocalServiceOutcome === "recovered") preflight = await runPreflight();
79477
- if (preflight.deviceReplyReadiness.replyReadiness === "blocked") {
79478
- if (blockingLocalServiceOutcome === "continue_without_service" || blockingLocalServiceOutcome === "recovered" && isBlockingLocalServiceJoinAttention(preflight)) return;
79479
- if (await maybeOfferDaemonStartBeforeSpaceJoin({
79480
- localDemand: input.localDemand ?? null,
79750
+ let preflight = await runPreflight();
79751
+ if (shouldManageServiceParticipation) {
79752
+ const gateResult = await runDaemonServiceParticipationGate({
79753
+ intent: input.serviceIntent ?? "space_join",
79481
79754
  presenter: input.presenter,
79755
+ resolvedView: input.resolvedView,
79756
+ allowPrompt: input.allowPrompt ?? true,
79757
+ localDemand: input.localDemand ?? null,
79482
79758
  view: input.view
79483
- })) preflight = await runPreflight();
79484
- if (preflight.deviceReplyReadiness.replyReadiness === "blocked") throw new Error(preflight.deviceReplyReadiness.reasonText);
79485
- return;
79486
- }
79487
- if (blockingLocalServiceOutcome !== "not_applicable") return;
79488
- await maybeOfferDaemonStartBeforeSpaceJoin({
79489
- localDemand: input.localDemand ?? null,
79490
- presenter: input.presenter,
79491
- view: input.view
79492
- });
79493
- }
79494
- async function maybeHandleBlockingLocalServiceAttentionBeforeSpaceJoin(input) {
79495
- if (input.resolvedView !== "human" || !isBlockingLocalServiceJoinAttention(input.preflight)) return "not_applicable";
79496
- if (input.preflight.deviceReplyReadiness.reasonCodes.includes("service.drifted")) return await maybeOfferDaemonRepairBeforeSpaceJoin({
79497
- localDemand: input.localDemand ?? null,
79498
- view: input.view
79499
- }) ? "recovered" : "continue_without_service";
79500
- return await maybeOfferDaemonStartBeforeSpaceJoin({
79501
- localDemand: input.localDemand ?? null,
79502
- presenter: input.presenter,
79503
- view: input.view
79504
- }) ? "recovered" : "continue_without_service";
79505
- }
79506
- function isBlockingLocalServiceJoinAttention(preflight) {
79507
- const { deviceReplyReadiness } = preflight;
79508
- return deviceReplyReadiness.replyReadiness === "blocked" && deviceReplyReadiness.reasonCodes.length > 0 && deviceReplyReadiness.reasonCodes.every((reasonCode) => LOCAL_SERVICE_ONLY_JOIN_BLOCK_REASON_CODES.has(reasonCode));
79509
- }
79510
- async function maybeOfferDaemonRepairBeforeSpaceJoin(input) {
79511
- if (!isHumanInteractiveJoinRuntime(await resolveRuntimeContext({ view: input.view }))) return false;
79512
- if (input.localDemand?.decision !== "keep_running") return false;
79513
- return await runDaemonBackgroundStartForDecision({ view: input.view }) === "started";
79514
- }
79515
- async function maybeOfferDaemonStartBeforeSpaceJoin(input) {
79516
- const runtime = await resolveRuntimeContext({ view: input.view });
79517
- if (runtime.resolvedView !== "human" || !canUseInteractivePrompts(runtime)) return false;
79518
- if (input.localDemand?.decision !== "keep_running") return false;
79519
- const daemonStatus = await getDaemonStatus().catch(() => NOT_INSTALLED_DAEMON_STATUS);
79520
- if (!daemonStatus.installed) return false;
79521
- const runtimeState = await resolveDaemonRuntimeState(daemonStatus);
79522
- if (!runtimeState) return false;
79523
- const { serviceManagerStatus } = await resolveDaemonServiceManagerForRuntimeState({
79524
- runtimeState,
79525
- status: daemonStatus
79526
- });
79527
- if (!shouldOfferDaemonStartDecision(getEffectiveDaemonRuntimeStatus({
79528
- runtimeState,
79529
- serviceManagerStatus
79530
- }))) return false;
79531
- const decision = await runDaemonStartDecisionPrompt({ startService: async () => await runDaemonBackgroundStartForDecision({ view: input.view }) });
79532
- if (decision === "not_now") {
79533
- const card = buildDaemonStartDeferredCard();
79534
- renderInfoCard({
79759
+ });
79760
+ if (gateResult.status === "cancelled") return "cancelled";
79761
+ preflight = await emitSpaceCommandPreflight({
79535
79762
  presenter: input.presenter,
79536
- title: card.title,
79537
- codePrefix: "space.join.service.deferred",
79538
- rows: card.rows
79763
+ command: "join",
79764
+ profile: input.atsProfile,
79765
+ baseUrl: input.baseUrl,
79766
+ resolvedView: input.resolvedView,
79767
+ humanServiceGuidanceMode: "suppress",
79768
+ emitOutput: false
79769
+ });
79770
+ if (gateResult.status === "declined") input.presenter.line({
79771
+ code: "space.join.service.declined",
79772
+ text: "ATS will continue joining this space without wakeable local agent participation on this device. To enable background replies later, rerun `ats start` or use `ats service install` and `ats service run`."
79539
79773
  });
79540
- return false;
79541
79774
  }
79542
- if (decision === "cancelled" || decision === "deferred_with_card") return false;
79543
- if (decision === "failed") {
79544
- const card = buildDaemonStartNeedsAttentionCard({ summary: "ATS could not finish starting ATS Service." });
79545
- renderInfoCard({
79546
- presenter: input.presenter,
79547
- title: card.title,
79548
- codePrefix: "space.join.service.failed",
79549
- rows: card.rows
79775
+ if (preflight.deviceReplyReadiness.replyReadiness === "blocked" && (shouldManageServiceParticipation || serviceRequirement === "not_needed") && isBlockingLocalServiceJoinAttention(preflight)) {
79776
+ if (serviceRequirement === "not_needed") input.presenter.line({
79777
+ code: "space.join.service.not_needed",
79778
+ text: "ATS will keep joining this space without wakeable local agent participation on this device. If you decide to bring local agents later, rerun `ats start` or use `ats service install` and `ats service run`."
79550
79779
  });
79551
- return false;
79780
+ return "continue";
79552
79781
  }
79553
- return decision === "started";
79782
+ if (preflight.deviceReplyReadiness.replyReadiness === "blocked") throw new Error(preflight.deviceReplyReadiness.reasonText);
79783
+ return "continue";
79784
+ }
79785
+ function isBlockingLocalServiceJoinAttention(preflight) {
79786
+ const { deviceReplyReadiness } = preflight;
79787
+ return deviceReplyReadiness.replyReadiness === "blocked" && deviceReplyReadiness.reasonCodes.length > 0 && deviceReplyReadiness.reasonCodes.every((reasonCode) => LOCAL_SERVICE_ONLY_JOIN_BLOCK_REASON_CODES.has(reasonCode));
79554
79788
  }
79555
79789
  function buildJoinTargetMissingMessage(input) {
79556
79790
  return formatMessage(input.resolvedView, "space.target.missing", { command: "join" });
@@ -79902,7 +80136,8 @@ function normalizeSpaceJoinMembershipCandidate(value) {
79902
80136
  ownerProfileName: normalizeOptionalString$2(candidate.ownerProfileName),
79903
80137
  ownerUserId: normalizeOptionalString$2(candidate.ownerUserId),
79904
80138
  ownerName: normalizeOptionalString$2(candidate.ownerName),
79905
- controllerRef: normalizeOptionalString$2(candidate.controllerRef)
80139
+ controllerRef: normalizeOptionalString$2(candidate.controllerRef),
80140
+ controllerEnabled: candidate.controllerEnabled === true
79906
80141
  };
79907
80142
  }
79908
80143
  function resolveSpaceJoinMembershipProfileKind(value) {
@@ -79920,6 +80155,7 @@ function buildLocallyCreatedPendingSpaceJoinMembershipCandidate(profile) {
79920
80155
  ownerUserId: profile.ownerUserId,
79921
80156
  ownerName: typeof profile.ownerName === "string" ? profile.ownerName : null,
79922
80157
  controllerRef: profile.controllerBinding?.controllerRef ?? null,
80158
+ controllerEnabled: profile.controllerBinding?.controllerEnabled === true,
79923
80159
  alreadyJoined: false,
79924
80160
  needsActivation: false
79925
80161
  };
@@ -80131,6 +80367,12 @@ async function applySelectedSpaceAddMembersBeforeJoin(input, dependencies) {
80131
80367
  });
80132
80368
  }
80133
80369
  if (confirmedCandidates.candidates.length === 0) return "completed";
80370
+ if (await dependencies.prepareSpaceMemberCandidatesLocalParticipation({
80371
+ actorProfile: input.actorProfile,
80372
+ candidates: confirmedCandidates.candidates,
80373
+ presenter: input.presenter,
80374
+ resolvedView: input.resolvedView
80375
+ }) === "cancelled") return input.cancelResult;
80134
80376
  const result = await dependencies.applySpaceAddMembers({
80135
80377
  actorProfile: input.actorProfile,
80136
80378
  candidates: confirmedCandidates.candidates,
@@ -80659,6 +80901,7 @@ function buildPostCreateJoinRequest(input) {
80659
80901
  ...typeof input.postCreateJoin?.mentionAlias === "string" ? { mentionAlias: input.postCreateJoin.mentionAlias } : {},
80660
80902
  ...typeof input.postCreateJoin?.rawStream === "boolean" ? { rawStream: input.postCreateJoin.rawStream } : {},
80661
80903
  ...typeof input.postCreateJoin?.skipBringProfilesPrompt === "boolean" ? { skipBringProfilesPrompt: input.postCreateJoin.skipBringProfilesPrompt } : {},
80904
+ serviceIntent: input.postCreateJoin?.serviceIntent ?? "space_create_join",
80662
80905
  entryChecksHandled: true
80663
80906
  };
80664
80907
  }
@@ -80688,7 +80931,8 @@ async function runSpaceCreate(input) {
80688
80931
  command: "create",
80689
80932
  profile: atsProfile,
80690
80933
  baseUrl,
80691
- resolvedView: contextRuntime.resolvedView
80934
+ resolvedView: contextRuntime.resolvedView,
80935
+ humanServiceGuidanceMode: isHumanInteractiveSpaceRuntime(contextRuntime) ? "suppress" : "show"
80692
80936
  });
80693
80937
  await ensureSpaceCreateAuthReady({ baseUrl });
80694
80938
  const createInput = await resolveSpaceCreateInput({
@@ -81788,6 +82032,17 @@ async function runSpaceAddMembersForTarget(input) {
81788
82032
  selectedProfileIds
81789
82033
  });
81790
82034
  if (selectedCandidates.length === 0) return { status: "completed" };
82035
+ if (await ensureSpaceMemberCandidatesLocalParticipationReady({
82036
+ atsProfile: input.atsProfile,
82037
+ candidates: selectedCandidates,
82038
+ presenter: input.presenter,
82039
+ resolvedView: input.runtime.resolvedView,
82040
+ allowPrompt: input.allowPrompt,
82041
+ view: input.view
82042
+ }) === "cancelled") return input.allowBackToCaller ? {
82043
+ status: "repeat_target",
82044
+ authenticatedGatewayUrl
82045
+ } : { status: "cancelled" };
81791
82046
  const result = await applySpaceAddMembers({
81792
82047
  actorProfile: input.atsProfile,
81793
82048
  candidates: selectedCandidates,
@@ -81894,6 +82149,46 @@ async function runSpaceRemoveMembersForTarget(input) {
81894
82149
  function resolveSelectedSpaceMemberCandidates(input) {
81895
82150
  return input.selectedProfileIds.map((profileId) => input.candidates.find((candidate) => candidate.profileId === profileId)).filter((candidate) => Boolean(candidate));
81896
82151
  }
82152
+ async function ensureSpaceMemberCandidatesLocalParticipationReady(input) {
82153
+ const explicitSelectedLocalAgents = hasAnyExplicitLocalAgentCandidates(input.candidates);
82154
+ const serviceRequirement = resolveCliServiceParticipationRequirement({
82155
+ intent: "space_add_members",
82156
+ humanOnlyParticipation: !explicitSelectedLocalAgents,
82157
+ explicitSelectedLocalAgents,
82158
+ selectedAgentProfilesHaveRunnableLocalSetup: haveAllExplicitLocalAgentCandidatesRunnable(input.candidates),
82159
+ localDemand: input.resolvedView === "human" ? await resolveDaemonLocalServiceDemand({ ownerUserId: input.atsProfile.ownerUserId }).catch(() => null) : null
82160
+ });
82161
+ if (serviceRequirement === "not_needed") return "continue";
82162
+ if (serviceRequirement === "agent_setup_needed") {
82163
+ input.presenter.line({
82164
+ code: "space.add_members.agent_setup_needed",
82165
+ text: "At least one selected agent profile is not set up on this device yet. Finish agent setup first, then retry. Use `ats start` or `ats profile ready --profile <agent-profile-id>`."
82166
+ });
82167
+ return "cancelled";
82168
+ }
82169
+ if (!(input.resolvedView === "human" && input.allowPrompt)) {
82170
+ input.presenter.line({
82171
+ code: "space.add_members.service.deferred",
82172
+ text: "ATS will continue without wakeable local agent participation on this device. To enable background replies later, rerun `ats start` or use `ats service install` and `ats service run`."
82173
+ });
82174
+ return "continue";
82175
+ }
82176
+ const gateResult = await runDaemonServiceParticipationGate({
82177
+ intent: "space_add_members",
82178
+ presenter: input.presenter,
82179
+ resolvedView: input.resolvedView,
82180
+ allowPrompt: input.allowPrompt,
82181
+ localDemand: await resolveDaemonLocalServiceDemand({ ownerUserId: input.atsProfile.ownerUserId }).catch(() => null),
82182
+ forcePrompt: explicitSelectedLocalAgents,
82183
+ view: input.view
82184
+ });
82185
+ if (gateResult.status === "cancelled") return "cancelled";
82186
+ if (gateResult.status !== "aligned") input.presenter.line({
82187
+ code: "space.add_members.service.declined",
82188
+ text: "ATS will continue adding these profiles without wakeable local agent participation on this device. To enable background replies later, rerun `ats start` or use `ats service install` and `ats service run`."
82189
+ });
82190
+ return "continue";
82191
+ }
81897
82192
  async function runSpaceJoin(input) {
81898
82193
  let failureRuntime = null;
81899
82194
  let failurePresenter = null;
@@ -81934,7 +82229,8 @@ async function runSpaceJoin(input) {
81934
82229
  role: input.role,
81935
82230
  roleInstructions: input.roleInstructions,
81936
82231
  mentionAlias: input.mentionAlias,
81937
- rawStream: input.rawStream === true
82232
+ rawStream: input.rawStream === true,
82233
+ serviceIntent: input.serviceIntent ?? "space_join"
81938
82234
  });
81939
82235
  } catch (error) {
81940
82236
  const runtime = failureRuntime ?? await resolveRuntimeContext({
@@ -81981,7 +82277,8 @@ async function runSpaceJoinTargetLoop(input) {
81981
82277
  rawStream: input.rawStream,
81982
82278
  skipBringProfilesPrompt: input.skipBringProfilesPrompt,
81983
82279
  output: input.output,
81984
- view: input.view
82280
+ view: input.view,
82281
+ serviceIntent: "space_create_join"
81985
82282
  }
81986
82283
  });
81987
82284
  }
@@ -81993,14 +82290,16 @@ async function runSpaceJoinTargetLoop(input) {
81993
82290
  space: target.space
81994
82291
  }), "reading an existing local space config before join");
81995
82292
  const targetBaseUrl = input.hasExplicitBaseUrlInput ? input.baseUrl : target.baseUrl ?? input.baseUrl;
81996
- await assertSpaceJoinTargetPreflightReady({
82293
+ if (await assertSpaceJoinTargetPreflightReady({
81997
82294
  atsProfile: input.atsProfile,
81998
82295
  baseUrl: targetBaseUrl,
82296
+ allowPrompt: input.canPromptPreJoinActions,
81999
82297
  localDemand: input.localDemand,
82000
82298
  presenter: input.presenter,
82001
82299
  resolvedView: input.runtime.resolvedView,
82300
+ serviceIntent: input.serviceIntent,
82002
82301
  view: input.view
82003
- });
82302
+ }) === "cancelled") return "cancelled";
82004
82303
  authenticatedGatewayUrl = await ensureSpaceCommandGatewayAuthenticationOrCancel({
82005
82304
  runtime: input.runtime,
82006
82305
  gatewayUrl: targetBaseUrl,
@@ -82042,6 +82341,14 @@ async function runSpaceJoinTargetLoop(input) {
82042
82341
  resolveCreateProfileName,
82043
82342
  resolveAgentProfileSetup,
82044
82343
  persistAgentTransportSelection,
82344
+ prepareSpaceMemberCandidatesLocalParticipation: async ({ actorProfile, candidates, presenter, resolvedView }) => await ensureSpaceMemberCandidatesLocalParticipationReady({
82345
+ atsProfile: actorProfile,
82346
+ candidates,
82347
+ presenter,
82348
+ resolvedView,
82349
+ allowPrompt: input.canPromptPreJoinActions,
82350
+ view: input.view
82351
+ }),
82045
82352
  applySpaceAddMembers,
82046
82353
  persistSpaceAddMembersJoinNotices,
82047
82354
  emitSpaceAddMembersResult
@@ -83072,6 +83379,7 @@ async function resolveSpaceMemberCandidatesForAdd(input) {
83072
83379
  ownerUserId: profile.ownerUserId,
83073
83380
  ownerName: profile.ownerName,
83074
83381
  controllerRef: profile.controllerBinding?.controllerRef,
83382
+ controllerEnabled: profile.controllerBinding?.controllerEnabled,
83075
83383
  alreadyJoined: memberProfileIds.has(profile.atsProfileId),
83076
83384
  needsActivation: false
83077
83385
  };
@@ -87071,11 +87379,13 @@ async function runStart(input) {
87071
87379
  const presenter = createPresenter(runtime);
87072
87380
  const interactive = canUseInteractivePrompts(runtime);
87073
87381
  if (interactive && runtime.resolvedView === "human") intro(`\n${renderAtsHeader()}`);
87074
- if (!await runStartDisclaimerStep({
87075
- runtime,
87076
- presenter,
87077
- interactive
87078
- })) return;
87382
+ if (!input.entryChecksHandled) {
87383
+ if (!await runStartDisclaimerStep({
87384
+ runtime,
87385
+ presenter,
87386
+ interactive
87387
+ })) return;
87388
+ }
87079
87389
  if (input.startSession) {
87080
87390
  await runStartHandoff({
87081
87391
  ...input,
@@ -91712,7 +92022,8 @@ async function runStartFromCliOptions(opts) {
91712
92022
  baseUrl: opts.gatewayUrl,
91713
92023
  startSession: opts.startSession,
91714
92024
  skillsMode: opts.skillsMode,
91715
- view: opts.view
92025
+ view: opts.view,
92026
+ entryChecksHandled: true
91716
92027
  });
91717
92028
  }
91718
92029
  function withSpaceProfileOption(cmd) {