agent-transport-system 0.7.56 → 0.7.58

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,12 +27,12 @@ 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.56";
30
+ var version = "0.7.58";
31
31
  var package_default = {
32
32
  $schema: "https://www.schemastore.org/package.json",
33
33
  name: "agent-transport-system",
34
34
  version,
35
- atsReleaseDate: "2026-06-11",
35
+ atsReleaseDate: "2026-06-12",
36
36
  description: "Agent Transport System CLI - https://ats.sh",
37
37
  license: "MIT",
38
38
  type: "module",
@@ -15223,6 +15223,7 @@ const PROVIDER_CONVERSATION_PROOF_SYNC_RETRY_INTERVAL_MS = 6e4;
15223
15223
  const RUNTIME_STATE_PERSIST_MIN_INTERVAL_MS = 6e4;
15224
15224
  const DEFAULT_RECONNECT_DELAY_MS = 1e3;
15225
15225
  const MAX_RECONNECT_DELAY_MS = 1e4;
15226
+ const DAEMON_STREAM_CONNECT_TIMEOUT_MS = 15e3;
15226
15227
  const REGISTER_RESPONSE_TIMEOUT_MS = 1e4;
15227
15228
  const HEARTBEAT_RESPONSE_TIMEOUT_MS = 15e3;
15228
15229
  const HEARTBEAT_CONSECUTIVE_FAILURES_BEFORE_CLOSE = 3;
@@ -27953,9 +27954,12 @@ async function resolveDaemonStatusSnapshot(input = {}) {
27953
27954
  });
27954
27955
  const runtimeContractRepairReport = currentReplyReadiness.daemonStatus.installed ? await readDaemonRuntimeContractRepairReport().catch(() => null) : null;
27955
27956
  const latestLifecycleEvent = await readLatestDaemonLifecycleOriginEvent().catch(() => null);
27956
- const baseAttention = resolveDaemonStatusAttention({
27957
- inventory: currentReplyReadiness.inventory,
27958
- runtimeState: currentReplyReadiness.displayRuntimeStatus ?? currentReplyReadiness.runtimeStatus
27957
+ const baseAttention = demoteRepairAttentionForLiveRoute({
27958
+ attention: resolveDaemonStatusAttention({
27959
+ inventory: currentReplyReadiness.inventory,
27960
+ runtimeState: currentReplyReadiness.displayRuntimeStatus ?? currentReplyReadiness.runtimeStatus
27961
+ }),
27962
+ daemonRouteObservation: currentReplyReadiness.daemonRouteObservation
27959
27963
  });
27960
27964
  const liveDependencyDiagnostics = shouldCheckDaemonServiceDependenciesForStatus(currentReplyReadiness.displayRuntimeStatus ?? currentReplyReadiness.runtimeStatus) ? await resolveDaemonServiceDependencyDiagnostics({ scopePolicy: "loopback_only" }).catch(() => null) : null;
27961
27965
  const recordedStartFailure = shouldCheckDaemonServiceDependenciesForStatus(currentReplyReadiness.displayRuntimeStatus ?? currentReplyReadiness.runtimeStatus) ? await readDaemonStartFailureState().catch(() => null) : null;
@@ -27969,6 +27973,12 @@ async function resolveDaemonStatusSnapshot(input = {}) {
27969
27973
  runtimeContractRepairReport
27970
27974
  };
27971
27975
  }
27976
+ function demoteRepairAttentionForLiveRoute(input) {
27977
+ if (!input.attention) return null;
27978
+ if (input.attention.code !== "service_repair_recommended") return input.attention;
27979
+ if (input.daemonRouteObservation.status !== "online") return input.attention;
27980
+ return null;
27981
+ }
27972
27982
  function shouldCheckDaemonServiceDependenciesForStatus(runtimeState) {
27973
27983
  return runtimeState?.status !== "running";
27974
27984
  }
@@ -36119,6 +36129,12 @@ async function submitRuntimeAgentControllerReports(input) {
36119
36129
  reasonCode: "runtime.reporting.service_contract_unavailable"
36120
36130
  });
36121
36131
  const authCompatibility = await resolveRuntimeReportingAuthCompatibility(serviceContract.gatewayUrl);
36132
+ if (authCompatibility.status === "unavailable") return failedSubmissions({
36133
+ gatewayUrl: serviceContract.gatewayUrl,
36134
+ reports: input.reports,
36135
+ reason: "auth_unavailable",
36136
+ reasonCode: `runtime.reporting.auth_${authCompatibility.authState}`
36137
+ });
36122
36138
  if (authCompatibility.status === "mismatch") return failedSubmissions({
36123
36139
  authBaseUrl: authCompatibility.authBaseUrl,
36124
36140
  gatewayUrl: serviceContract.gatewayUrl,
@@ -36185,6 +36201,12 @@ async function submitRuntimeProviderConversationProofs(input) {
36185
36201
  reasonCode: "provider_conversation.runtime_reporting.service_contract_unavailable"
36186
36202
  });
36187
36203
  const authCompatibility = await resolveRuntimeReportingAuthCompatibility(serviceContract.gatewayUrl);
36204
+ if (authCompatibility.status === "unavailable") return failedProviderConversationProofSubmissions({
36205
+ gatewayUrl: serviceContract.gatewayUrl,
36206
+ proofs: input.proofs,
36207
+ reason: "auth_unavailable",
36208
+ reasonCode: `provider_conversation.runtime_reporting.auth_${authCompatibility.authState}`
36209
+ });
36188
36210
  if (authCompatibility.status === "mismatch") return failedProviderConversationProofSubmissions({
36189
36211
  authBaseUrl: authCompatibility.authBaseUrl,
36190
36212
  gatewayUrl: serviceContract.gatewayUrl,
@@ -36352,7 +36374,14 @@ function failedProviderConversationProofSubmissions(input) {
36352
36374
  }
36353
36375
  async function resolveRuntimeReportingAuthCompatibility(gatewayUrl) {
36354
36376
  const authState = await getAuthSessionState().catch(() => null);
36355
- if (!(authState?.state === "valid" && authState.session)) return { status: "compatible" };
36377
+ if (!authState) return {
36378
+ authState: "error",
36379
+ status: "unavailable"
36380
+ };
36381
+ if (!(authState.state === "valid" && authState.session)) return {
36382
+ authState: authState.state === "expired" || authState.state === "invalid" ? authState.state : "missing",
36383
+ status: "unavailable"
36384
+ };
36356
36385
  if (canAttachAuthTokenToRequest(authState.session, gatewayUrl)) return { status: "compatible" };
36357
36386
  return {
36358
36387
  authBaseUrl: authState.session.authBaseUrl,
@@ -39544,12 +39573,29 @@ function buildDaemonAgentOverviewPayload(command) {
39544
39573
  //#region src/transport/ws.ts
39545
39574
  async function connectWebSocket(url, input) {
39546
39575
  return await new Promise((resolve, reject) => {
39576
+ let settled = false;
39547
39577
  const ws = new WebSocket(url, { headers: input?.headers });
39578
+ const openTimeoutMs = normalizeOpenTimeoutMs(input?.openTimeoutMs);
39579
+ const openTimeout = openTimeoutMs === null ? null : setTimeout(() => {
39580
+ if (settled) return;
39581
+ settled = true;
39582
+ ws.terminate();
39583
+ reject(/* @__PURE__ */ new Error(`websocket open timeout after ${openTimeoutMs}ms`));
39584
+ }, openTimeoutMs);
39548
39585
  const closePromise = new Promise((r) => {
39549
39586
  ws.on("close", () => r());
39550
39587
  ws.on("error", () => r());
39551
39588
  });
39589
+ ws.on("close", (code, reason) => {
39590
+ if (settled) return;
39591
+ settled = true;
39592
+ if (openTimeout) clearTimeout(openTimeout);
39593
+ reject(/* @__PURE__ */ new Error(`websocket closed before open (code=${String(code)}, reason=${reason.toString("utf8")})`));
39594
+ });
39552
39595
  ws.on("open", () => {
39596
+ if (settled) return;
39597
+ settled = true;
39598
+ if (openTimeout) clearTimeout(openTimeout);
39553
39599
  resolve({
39554
39600
  send: (data) => ws.send(data),
39555
39601
  close: (code, reason) => ws.close(code, reason),
@@ -39569,10 +39615,19 @@ async function connectWebSocket(url, input) {
39569
39615
  });
39570
39616
  });
39571
39617
  ws.on("error", (err) => {
39618
+ if (settled) return;
39619
+ settled = true;
39620
+ if (openTimeout) clearTimeout(openTimeout);
39572
39621
  reject(err);
39573
39622
  });
39574
39623
  });
39575
39624
  }
39625
+ function normalizeOpenTimeoutMs(value) {
39626
+ if (value === void 0 || value === null) return null;
39627
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
39628
+ const normalized = Math.trunc(value);
39629
+ return normalized > 0 ? normalized : null;
39630
+ }
39576
39631
  function toUtf8(value) {
39577
39632
  if (typeof value === "string") return value;
39578
39633
  if (value instanceof Buffer) return value.toString("utf8");
@@ -40776,6 +40831,54 @@ function buildDaemonRuntimeLease(input) {
40776
40831
  };
40777
40832
  }
40778
40833
 
40834
+ //#endregion
40835
+ //#region src/local-service/state/service-connection-state.ts
40836
+ function createServiceConnectionStateTracker(input) {
40837
+ let current = {
40838
+ state: "starting",
40839
+ reason: null,
40840
+ detail: null,
40841
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
40842
+ };
40843
+ return {
40844
+ get: () => current,
40845
+ set: (state, options) => {
40846
+ const reason = options?.reason ?? null;
40847
+ if (current.state === state && current.reason === reason) return;
40848
+ current = {
40849
+ state,
40850
+ reason,
40851
+ detail: options?.detail ?? null,
40852
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
40853
+ };
40854
+ input?.onTransition?.(current);
40855
+ }
40856
+ };
40857
+ }
40858
+ function classifyConnectionFailureReason(message) {
40859
+ const lowered = message.toLowerCase();
40860
+ if (lowered.includes("authentication required") || lowered.includes("401") || lowered.includes("unauthorized")) return "auth_rejected";
40861
+ if (lowered.includes("fetch failed") || lowered.includes("timed out") || lowered.includes("timeout") || lowered.includes("econn") || lowered.includes("enotfound") || lowered.includes("socket") || lowered.includes("network")) return "network_unreachable";
40862
+ return "internal";
40863
+ }
40864
+ function toHealthProjection(state) {
40865
+ if (state.state === "online") return {
40866
+ state: "ok",
40867
+ runtimeState: "healthy",
40868
+ reasonCode: "ok"
40869
+ };
40870
+ if (state.state === "stopping") return {
40871
+ state: "degraded",
40872
+ runtimeState: "idle",
40873
+ reasonCode: "stopping"
40874
+ };
40875
+ return {
40876
+ state: "degraded",
40877
+ runtimeState: "suspect",
40878
+ reasonCode: state.reason ?? state.state
40879
+ };
40880
+ }
40881
+
40779
40882
  //#endregion
40780
40883
  //#region src/local-service/adapters/resolve-daemon-capabilities.ts
40781
40884
  function resolveDaemonCapabilities(input) {
@@ -46067,7 +46170,7 @@ async function runDaemonSocketSession(input) {
46067
46170
  text: `heartbeat failed (${String(consecutiveHeartbeatFailures)}/${String(HEARTBEAT_CONSECUTIVE_FAILURES_BEFORE_CLOSE)}): ${toErrorMessage$29(error)}`
46068
46171
  });
46069
46172
  if (shouldCloseSocket) {
46070
- input.socket.close(1011, "heartbeat_failed");
46173
+ input.socket.terminate();
46071
46174
  return;
46072
46175
  }
46073
46176
  updateHeartbeatInterval({
@@ -46782,6 +46885,7 @@ const runDaemonServiceLoop = async (input) => {
46782
46885
  initialState: daemonRuntimeState,
46783
46886
  leaseDescriptor: await resolveDaemonRuntimeLeaseDescriptor({ command: daemonRuntimeState.command })
46784
46887
  });
46888
+ const connectionState = createRunLoopConnectionStateTracker(input.presenter);
46785
46889
  const localAdapterContainer = createLocalAdapterContainer(createLocalAdapterEntries({
46786
46890
  registerRuntimeProcess: (event) => {
46787
46891
  const nextProcessId = event.phase === "process_exit" ? null : event.processId;
@@ -46836,9 +46940,10 @@ const runDaemonServiceLoop = async (input) => {
46836
46940
  getContext: async () => ({
46837
46941
  healthPayload: {
46838
46942
  checkedAt: nowIsoString(),
46839
- reasonCode: stopRequested ? "stopping" : "ok",
46840
- runtimeState: stopRequested ? "idle" : "healthy",
46841
- state: stopRequested ? "degraded" : "ok"
46943
+ ...toHealthProjection(stopRequested ? {
46944
+ ...connectionState.get(),
46945
+ state: "stopping"
46946
+ } : connectionState.get())
46842
46947
  },
46843
46948
  historyEntries: [],
46844
46949
  interruptHandler: async (payload) => await handleLocalControlPlaneInterrupt({
@@ -46878,6 +46983,7 @@ const runDaemonServiceLoop = async (input) => {
46878
46983
  const requestStop = () => {
46879
46984
  if (stopRequested) return;
46880
46985
  stopRequested = true;
46986
+ connectionState.set("stopping");
46881
46987
  activeSocket?.close(1e3, "shutdown");
46882
46988
  };
46883
46989
  const onSigint = () => {
@@ -46927,11 +47033,15 @@ const runDaemonServiceLoop = async (input) => {
46927
47033
  });
46928
47034
  }
46929
47035
  while (!stopRequested) try {
47036
+ connectionState.set("connecting", { reason: resolveConnectingReason(reconnectAttempt) });
46930
47037
  const wsUrl = toDaemonStreamUrl(baseUrl);
46931
- const ws = await connectWebSocket(wsUrl, { headers: selectedAtsProfile ? await buildAtsProfileRequestHeadersWithAuth({
46932
- atsProfile: selectedAtsProfile,
46933
- requestUrl: wsUrl
46934
- }) : await buildRequestAuthHeaders({ requestUrl: wsUrl }) });
47038
+ const ws = await connectWebSocket(wsUrl, {
47039
+ headers: selectedAtsProfile ? await buildAtsProfileRequestHeadersWithAuth({
47040
+ atsProfile: selectedAtsProfile,
47041
+ requestUrl: wsUrl
47042
+ }) : await buildRequestAuthHeaders({ requestUrl: wsUrl }),
47043
+ openTimeoutMs: DAEMON_STREAM_CONNECT_TIMEOUT_MS
47044
+ });
46935
47045
  activeSocket = ws;
46936
47046
  emitRunLine({
46937
47047
  presenter: input.presenter,
@@ -46969,7 +47079,10 @@ const runDaemonServiceLoop = async (input) => {
46969
47079
  reconnectAttempt,
46970
47080
  routeCatalogState,
46971
47081
  socket: ws,
46972
- touchRuntimeState: runtimeStateTracker.touchRuntimeState
47082
+ touchRuntimeState: async (updates) => {
47083
+ if (typeof updates.heartbeatAt === "string") connectionState.set("online");
47084
+ await runtimeStateTracker.touchRuntimeState(updates);
47085
+ }
46973
47086
  });
46974
47087
  reconnectAttempt = 0;
46975
47088
  activeSocket = null;
@@ -46986,6 +47099,11 @@ const runDaemonServiceLoop = async (input) => {
46986
47099
  if (stopRequested) break;
46987
47100
  reconnectAttempt += 1;
46988
47101
  const backoffMs = resolveReconnectBackoffMs(reconnectAttempt);
47102
+ noteReconnectFailureState({
47103
+ connectionState,
47104
+ errorMessage: toErrorMessage$29(error),
47105
+ reconnectAttempt
47106
+ });
46989
47107
  const reconcileDecision = resolveRouteRegistrationReconcileDecision({
46990
47108
  driftDetected: true,
46991
47109
  foregroundActive: mode === "foreground"
@@ -47281,6 +47399,31 @@ function summarizeLocalControlSyncSkippedProfiles(payload) {
47281
47399
  if (!payload.skippedProfiles || payload.skippedProfiles.length === 0) return "";
47282
47400
  return `; skipped=${payload.skippedProfiles.length} (${summarizeSkippedDaemonProfiles(payload.skippedProfiles)})`;
47283
47401
  }
47402
+ function createRunLoopConnectionStateTracker(presenter) {
47403
+ return createServiceConnectionStateTracker({ onTransition: (next) => {
47404
+ emitRunLine({
47405
+ presenter,
47406
+ code: "daemon.run.connection_state",
47407
+ text: `connection state: ${next.state}${next.reason ? ` (${next.reason})` : ""}${next.detail ? ` - ${next.detail}` : ""}`,
47408
+ payload: {
47409
+ detail: next.detail,
47410
+ reason: next.reason,
47411
+ state: next.state,
47412
+ updatedAt: next.updatedAt
47413
+ }
47414
+ });
47415
+ } });
47416
+ }
47417
+ function noteReconnectFailureState(input) {
47418
+ if (input.reconnectAttempt < 2) return;
47419
+ input.connectionState.set("degraded", {
47420
+ detail: input.errorMessage,
47421
+ reason: classifyConnectionFailureReason(input.errorMessage)
47422
+ });
47423
+ }
47424
+ function resolveConnectingReason(reconnectAttempt) {
47425
+ return reconnectAttempt > 0 ? "reconnecting" : null;
47426
+ }
47284
47427
 
47285
47428
  //#endregion
47286
47429
  //#region src/local-service/lifecycle/daemon-service-hygiene.ts