agent-transport-system 0.7.4 → 0.7.5

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
@@ -27,7 +27,7 @@ import wrapAnsi from "wrap-ansi";
27
27
  import { Box, Container, Editor, Key, ProcessTerminal, TUI, Text, getEditorKeybindings, matchesKey } from "@mariozechner/pi-tui";
28
28
 
29
29
  //#region package.json
30
- var version = "0.7.4";
30
+ var version = "0.7.5";
31
31
  var package_default = {
32
32
  $schema: "https://www.schemastore.org/package.json",
33
33
  name: "agent-transport-system",
@@ -2492,6 +2492,14 @@ const SPACE_ADD_MEMBERS_PROGRESS_PHASES = [
2492
2492
  factSource: "space_membership_api_write",
2493
2493
  summary: "Adding selected profiles to the Space."
2494
2494
  },
2495
+ {
2496
+ stage: "add_members",
2497
+ phase: "confirm_membership_projection",
2498
+ owner: "space",
2499
+ waitingFor: "Space membership and Wake availability projection",
2500
+ factSource: "space_membership_projection",
2501
+ summary: "Confirming the Space can see newly added wakeable members before returning."
2502
+ },
2495
2503
  {
2496
2504
  stage: "record_join_notices",
2497
2505
  phase: "write_join_notices",
@@ -28706,11 +28714,11 @@ async function readSystemLayoutWithRetry(path) {
28706
28714
  }
28707
28715
  const parsed = raw ? parseSystemLayout(raw) : null;
28708
28716
  if (parsed) return parsed;
28709
- if (attempt < SYSTEM_LAYOUT_READ_RETRY_COUNT - 1) await delay(SYSTEM_LAYOUT_READ_RETRY_DELAY_MS);
28717
+ if (attempt < SYSTEM_LAYOUT_READ_RETRY_COUNT - 1) await delay$1(SYSTEM_LAYOUT_READ_RETRY_DELAY_MS);
28710
28718
  }
28711
28719
  return null;
28712
28720
  }
28713
- function delay(ms) {
28721
+ function delay$1(ms) {
28714
28722
  return new Promise((resolve) => {
28715
28723
  setTimeout(resolve, ms);
28716
28724
  });
@@ -68222,7 +68230,14 @@ function isAgentProfile(profile) {
68222
68230
  //#region src/commands/setup.ts
68223
68231
  const ROUTE_CATALOG_SYNC_MAX_ATTEMPTS = 8;
68224
68232
  const ROUTE_CATALOG_SYNC_RETRY_DELAY_MS = 750;
68233
+ const SETUP_COMMAND_LOCK_PROFILE = "setup";
68234
+ const SETUP_COMMAND_LOCK_KEY = "setup-command";
68225
68235
  async function runSetup(input) {
68236
+ return await withSetupCommandLock(input, async () => {
68237
+ await runSetupUnlocked(input);
68238
+ });
68239
+ }
68240
+ async function runSetupUnlocked(input) {
68226
68241
  if (shouldUseSetupLocalAgentConnection(input)) {
68227
68242
  const setupResult = await runSetupLocalAgentConnection(input);
68228
68243
  if (setupResult.status !== "completed") return;
@@ -68326,6 +68341,33 @@ async function runSetup(input) {
68326
68341
  view: runtime.resolvedView
68327
68342
  });
68328
68343
  }
68344
+ async function withSetupCommandLock(input, run) {
68345
+ try {
68346
+ return await runWithHeldLock({
68347
+ lock: await acquireLock({
68348
+ atsProfileId: SETUP_COMMAND_LOCK_PROFILE,
68349
+ key: SETUP_COMMAND_LOCK_KEY,
68350
+ meta: {
68351
+ command: "ats setup",
68352
+ path: shouldUseSetupLocalAgentConnection(input) ? "delegated_or_profile_setup" : "local_setup",
68353
+ view: input.view ?? null
68354
+ }
68355
+ }),
68356
+ run,
68357
+ releaseContext: {
68358
+ atsProfileId: SETUP_COMMAND_LOCK_PROFILE,
68359
+ component: "setup_command",
68360
+ lockKey: SETUP_COMMAND_LOCK_KEY
68361
+ }
68362
+ });
68363
+ } catch (error) {
68364
+ if (isAtsLockError(error)) throw new Error(buildSetupCommandLockMessage(error));
68365
+ throw error;
68366
+ }
68367
+ }
68368
+ function buildSetupCommandLockMessage(error) {
68369
+ return `Another ATS setup is already running on this computer. Wait for it to finish, then run setup again.${error.metaRaw ? ` Existing setup: ${error.metaRaw}` : ""}`;
68370
+ }
68329
68371
  function shouldUseSetupLocalAgentConnection(input) {
68330
68372
  return Boolean(normalizeOptionalString$5(input.startSession) ?? normalizeOptionalString$5(input.humanProfile) ?? normalizeOptionalString$5(input.profile) ?? (input.agent && input.agent.length > 0 ? "agent" : null));
68331
68373
  }
@@ -84931,6 +84973,8 @@ const TRAILING_SLASHES_RE = /\/+$/u;
84931
84973
  const SPACE_CREATE_AUTH_CHECK_TIMEOUT_MS = 8e3;
84932
84974
  const SPACE_CREATE_AUTH_CHECK_LOOPBACK_TIMEOUT_MS = 1500;
84933
84975
  const SPACE_LOADING_SPINNER_MESSAGE = "Loading spaces...";
84976
+ const SPACE_ADD_MEMBERS_PROJECTION_WAIT_MAX_ATTEMPTS = 3;
84977
+ const SPACE_ADD_MEMBERS_PROJECTION_WAIT_DELAY_MS = 500;
84934
84978
  function requireReadableSpaceConfigList(result, operation) {
84935
84979
  if (result.kind === "corrupt") throw toSpaceConfigListIntegrityError({
84936
84980
  operation,
@@ -85133,6 +85177,7 @@ async function runSpaceCreate(input) {
85133
85177
  guide: typeof parsed.meta?.guide === "string" ? parsed.meta.guide : createInput.value.guide
85134
85178
  });
85135
85179
  emitSpaceCreateSuccessOutput({
85180
+ baseUrl,
85136
85181
  presenter: contextPresenter,
85137
85182
  parsed,
85138
85183
  outputMode,
@@ -85151,6 +85196,7 @@ async function runSpaceCreate(input) {
85151
85196
  const joinNow = isHumanInteractiveSpaceRuntime(contextRuntime) ? Boolean(createInput.value.joinInput) : await resolveJoinAfterCreate(createInput.value.joinInput, contextInteractive);
85152
85197
  if (contextRuntime.resolvedView === "agent") {
85153
85198
  emitSpaceCreateAgentFollowUp({
85199
+ baseUrl,
85154
85200
  presenter: contextPresenter,
85155
85201
  profileId: atsProfile.atsProfileId,
85156
85202
  spaceId: parsed.spaceId,
@@ -85186,12 +85232,14 @@ async function runSpaceCreate(input) {
85186
85232
  }
85187
85233
  }
85188
85234
  function emitSpaceCreateAgentFollowUp(input) {
85235
+ const spaceUrl = buildSpaceWebUrl(input.baseUrl, input.spaceId);
85189
85236
  const historyCommand = formatAtsCliCommand(`ats space history ${input.spaceId} --profile ${input.profileId} --kind text --brief --limit 20 --view agent`);
85190
85237
  const sendCommand = formatAtsCliCommand(`ats space send ${input.spaceId} --profile ${input.profileId} "hello" --view agent`);
85191
85238
  input.presenter.data({
85192
85239
  code: "space.create.next_commands",
85193
85240
  payload: {
85194
85241
  spaceId: input.spaceId,
85242
+ spaceUrl,
85195
85243
  joinRequested: input.joinRequested,
85196
85244
  joinedByCreate: true,
85197
85245
  note: "Agent View create returns after creating the Space. Use explicit follow-up commands instead of opening a long-running join session.",
@@ -85278,6 +85326,9 @@ function renderHumanSpaceCreateCard(input) {
85278
85326
  const rows = [{
85279
85327
  label: "🆔 Space ID",
85280
85328
  value: input.spaceId
85329
+ }, {
85330
+ label: "🔗 Space URL",
85331
+ value: input.spaceUrl
85281
85332
  }];
85282
85333
  if (input.passwordProtected) {
85283
85334
  rows.push({
@@ -85563,6 +85614,14 @@ function toAuthEndpoint(baseUrl, pathname) {
85563
85614
  url.hash = "";
85564
85615
  return url.toString();
85565
85616
  }
85617
+ function buildSpaceWebUrl(baseUrl, spaceId) {
85618
+ const url = new URL(baseUrl);
85619
+ if (isLoopbackHostname(url.hostname) && url.port === "8080") url.port = "3000";
85620
+ url.pathname = `/app/spaces/${encodeURIComponent(spaceId)}`;
85621
+ url.search = "";
85622
+ url.hash = "";
85623
+ return url.toString();
85624
+ }
85566
85625
  function resolveSpaceCreateAuthCheckTimeoutMs(endpoint) {
85567
85626
  const url = parseUrlOrNull(endpoint);
85568
85627
  if (url && isLoopbackHostname(url.hostname)) return SPACE_CREATE_AUTH_CHECK_LOOPBACK_TIMEOUT_MS;
@@ -85579,10 +85638,14 @@ function isLoopbackHostname(hostname) {
85579
85638
  return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
85580
85639
  }
85581
85640
  function emitSpaceCreateSuccessOutput(input) {
85641
+ const spaceUrl = buildSpaceWebUrl(input.baseUrl, input.parsed.spaceId);
85582
85642
  if (input.outputMode === "ndjson") {
85583
85643
  input.presenter.data({
85584
85644
  code: "space.create.response",
85585
- payload: input.parsed
85645
+ payload: {
85646
+ ...input.parsed,
85647
+ spaceUrl
85648
+ }
85586
85649
  });
85587
85650
  return;
85588
85651
  }
@@ -85590,6 +85653,7 @@ function emitSpaceCreateSuccessOutput(input) {
85590
85653
  renderHumanSpaceCreateCard({
85591
85654
  presenter: input.presenter,
85592
85655
  spaceId: input.parsed.spaceId,
85656
+ spaceUrl,
85593
85657
  passwordProtected: input.passwordProtected
85594
85658
  });
85595
85659
  return;
@@ -85599,6 +85663,14 @@ function emitSpaceCreateSuccessOutput(input) {
85599
85663
  text: formatMessage(input.resolvedView, "space.create.created", { spaceId: input.parsed.spaceId }),
85600
85664
  data: { spaceId: input.parsed.spaceId }
85601
85665
  });
85666
+ input.presenter.line({
85667
+ code: "space.create.url",
85668
+ text: `Space URL: ${spaceUrl}`,
85669
+ data: {
85670
+ spaceId: input.parsed.spaceId,
85671
+ spaceUrl
85672
+ }
85673
+ });
85602
85674
  if (!input.passwordProtected) return;
85603
85675
  input.presenter.line({
85604
85676
  code: "space.password.warning",
@@ -86340,6 +86412,14 @@ async function runSpaceAddMembersForTarget(input) {
86340
86412
  baseUrl: targetBaseUrl,
86341
86413
  password: input.password
86342
86414
  });
86415
+ await waitForAddedMembersWakeProjection({
86416
+ actorProfile: input.atsProfile,
86417
+ baseUrl: targetBaseUrl,
86418
+ password: input.password,
86419
+ progress,
86420
+ result,
86421
+ space: input.target.space
86422
+ });
86343
86423
  emitSpaceAddMembersProgressIfRequested(progress, {
86344
86424
  stage: "record_join_notices",
86345
86425
  phase: "write_join_notices",
@@ -88542,6 +88622,42 @@ async function applySpaceAddMembers(input) {
88542
88622
  }
88543
88623
  return result;
88544
88624
  }
88625
+ async function waitForAddedMembersWakeProjection(input) {
88626
+ const expectedWakeableProfileIds = resolveExpectedWakeProjectionProfileIds(input.result);
88627
+ if (expectedWakeableProfileIds.length === 0) return;
88628
+ emitSpaceAddMembersProgressIfRequested(input.progress, {
88629
+ stage: "add_members",
88630
+ phase: "confirm_membership_projection",
88631
+ summary: "Confirming the Space can see newly added wakeable members before returning.",
88632
+ profileIds: expectedWakeableProfileIds
88633
+ });
88634
+ const expected = new Set(expectedWakeableProfileIds);
88635
+ for (let attempt = 0; attempt < SPACE_ADD_MEMBERS_PROJECTION_WAIT_MAX_ATTEMPTS; attempt += 1) {
88636
+ if (attempt > 0) await delay(SPACE_ADD_MEMBERS_PROJECTION_WAIT_DELAY_MS);
88637
+ let membersSnapshot;
88638
+ try {
88639
+ membersSnapshot = await createCliSpaceApi(input.baseUrl).getMembersSnapshot({
88640
+ spaceId: input.space,
88641
+ requestContext: buildAtsRequestContextFromProfile({ atsProfile: input.actorProfile }),
88642
+ ...input.password === void 0 ? {} : { spacePassword: input.password }
88643
+ });
88644
+ } catch {
88645
+ return;
88646
+ }
88647
+ if (hasExpectedWakeProjection(membersSnapshot, expected)) return;
88648
+ }
88649
+ }
88650
+ function resolveExpectedWakeProjectionProfileIds(result) {
88651
+ return result.added.filter((candidate) => candidate.profileKind === "agent" && candidate.localParticipationReadiness === "ready").map((candidate) => candidate.profileId);
88652
+ }
88653
+ function hasExpectedWakeProjection(membersSnapshot, expectedProfileIds) {
88654
+ const wakeableProfileIds = new Set(membersSnapshot.agents.filter((member) => member.status === "active" && member.publicReplyPresence?.status === "ready").map((member) => member.profileId));
88655
+ for (const profileId of expectedProfileIds) if (!wakeableProfileIds.has(profileId)) return false;
88656
+ return true;
88657
+ }
88658
+ async function delay(ms) {
88659
+ await new Promise((resolve) => setTimeout(resolve, ms));
88660
+ }
88545
88661
  function emitSpaceAddMembersResult(input) {
88546
88662
  const localParticipationFollowUps = input.result.added.map((candidate) => buildSpaceMemberJoinedFollowUp(candidate)).filter((followUp) => followUp !== null);
88547
88663
  if (input.resolvedView === "agent") {