@ganglion/xacpx 0.22.1-beta.0 → 0.23.0-beta.0

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.
@@ -2071,6 +2071,30 @@ var init_prompt_output = __esm(() => {
2071
2071
  };
2072
2072
  });
2073
2073
 
2074
+ // src/transport/message-injection.ts
2075
+ function isMessageInjectionErrorCode(value) {
2076
+ return typeof value === "string" && MESSAGE_INJECTION_ERROR_CODES.has(value);
2077
+ }
2078
+ var MESSAGE_INJECTION_ERROR_CODES, MessageInjectionError;
2079
+ var init_message_injection = __esm(() => {
2080
+ MESSAGE_INJECTION_ERROR_CODES = new Set([
2081
+ "TARGET_NOT_RUNNING",
2082
+ "TARGET_NOT_STEERABLE",
2083
+ "TARGET_NOT_INTERRUPTIBLE",
2084
+ "DELIVERY_RACE",
2085
+ "DELIVERY_TIMEOUT",
2086
+ "DELIVERY_FAILED"
2087
+ ]);
2088
+ MessageInjectionError = class MessageInjectionError extends Error {
2089
+ code;
2090
+ name = "MessageInjectionError";
2091
+ constructor(code, message) {
2092
+ super(message);
2093
+ this.code = code;
2094
+ }
2095
+ };
2096
+ });
2097
+
2074
2098
  // src/process/spawn-command.ts
2075
2099
  function resolveSpawnCommand(command, args) {
2076
2100
  if (SCRIPT_FILE_PATTERN.test(command)) {
@@ -9246,6 +9270,9 @@ function buildPromptArgs(input, tail) {
9246
9270
  ];
9247
9271
  return appendAgentAndTail(prefix, input, tail);
9248
9272
  }
9273
+ function buildQueueMessagePromptArgs(input, sessionName, text) {
9274
+ return buildPromptArgs(input, ["prompt", "-s", sessionName, "--no-wait", text]);
9275
+ }
9249
9276
  function buildAgentQueryArgs(input, format, tail) {
9250
9277
  const prefix = ["--format", format, "--cwd", input.cwd, ...buildPermissionArgs(input.permission)];
9251
9278
  return appendAgentAndTail(prefix, input, tail);
@@ -9682,6 +9709,9 @@ class AcpxQueueOverflowError extends Error {
9682
9709
  }
9683
9710
  }
9684
9711
 
9712
+ // src/bridge/bridge-server.ts
9713
+ init_message_injection();
9714
+
9685
9715
  // src/bridge/bridge-request-scheduler.ts
9686
9716
  class BridgeRequestScheduler {
9687
9717
  sessions = new Map;
@@ -9690,16 +9720,18 @@ class BridgeRequestScheduler {
9690
9720
  return Promise.resolve().then(task);
9691
9721
  }
9692
9722
  const state = this.sessions.get(sessionName) ?? this.createSessionState(sessionName);
9693
- state.pendingNormals += 1;
9694
- const result = state.tail.then(() => task());
9695
- state.tail = result.then(() => {
9723
+ const tailName = lane === "message" ? "messageTail" : "normalTail";
9724
+ const pendingName = lane === "message" ? "pendingMessages" : "pendingNormals";
9725
+ state[pendingName] += 1;
9726
+ const result = state[tailName].then(() => task());
9727
+ state[tailName] = result.then(() => {
9696
9728
  return;
9697
9729
  }, () => {
9698
9730
  return;
9699
9731
  });
9700
9732
  return result.finally(() => {
9701
- state.pendingNormals -= 1;
9702
- if (state.pendingNormals === 0 && this.sessions.get(sessionName) === state) {
9733
+ state[pendingName] -= 1;
9734
+ if (state.pendingNormals === 0 && state.pendingMessages === 0 && this.sessions.get(sessionName) === state) {
9703
9735
  this.sessions.delete(sessionName);
9704
9736
  }
9705
9737
  });
@@ -9707,7 +9739,9 @@ class BridgeRequestScheduler {
9707
9739
  createSessionState(sessionName) {
9708
9740
  const state = {
9709
9741
  pendingNormals: 0,
9710
- tail: Promise.resolve()
9742
+ pendingMessages: 0,
9743
+ normalTail: Promise.resolve(),
9744
+ messageTail: Promise.resolve()
9711
9745
  };
9712
9746
  this.sessions.set(sessionName, state);
9713
9747
  return state;
@@ -9753,6 +9787,7 @@ init_command_timeouts();
9753
9787
  init_command_timeouts();
9754
9788
  init_acpx_command_builder();
9755
9789
  init_session_effort();
9790
+ init_message_injection();
9756
9791
  class EnsureSessionFailedError extends Error {
9757
9792
  kind;
9758
9793
  data;
@@ -10037,6 +10072,35 @@ class BridgeRuntime {
10037
10072
  } catch {}
10038
10073
  }
10039
10074
  }
10075
+ async injectMessage(input) {
10076
+ if (input.mode === "steer") {
10077
+ throw new MessageInjectionError("TARGET_NOT_STEERABLE", "The target does not support same-turn steering.");
10078
+ }
10079
+ if (input.mode === "interrupt") {
10080
+ throw new MessageInjectionError("TARGET_NOT_INTERRUPTIBLE", "The target does not support interrupt delivery.");
10081
+ }
10082
+ await this.syncPersistedSessionEffort(input);
10083
+ await this.launchMcpQueueOwnerIfNeeded(input);
10084
+ const spawnSpec = resolveSpawnCommand(this.command, buildQueueMessagePromptArgs({
10085
+ agent: input.agent,
10086
+ agentCommand: input.agentCommand,
10087
+ acpxAgent: input.acpxAgent,
10088
+ rawCommand: input.rawCommand,
10089
+ cwd: input.cwd,
10090
+ model: input.model,
10091
+ permission: this.permissionInput(),
10092
+ queueOwnerTtlSeconds: this.options.queueOwnerTtlSeconds
10093
+ }, input.name, input.text));
10094
+ const result = await this.run(spawnSpec.command, spawnSpec.args, this.withSpawnEnvironment(input, {
10095
+ timeoutMs: this.managementCommandTimeoutMs(),
10096
+ stage: "inject-message"
10097
+ }));
10098
+ if (result.code !== 0) {
10099
+ const detail = normalizeCommandError(result) ?? (result.stderr || result.stdout || `inject-message failed with exit code ${result.code}`);
10100
+ throw new Error(detail);
10101
+ }
10102
+ return { status: "queued", modeUsed: "queue" };
10103
+ }
10040
10104
  async cleanupOverflowedOwner(input) {
10041
10105
  const diagnostics = [];
10042
10106
  let cancelSucceeded = false;
@@ -10596,6 +10660,7 @@ var BRIDGE_METHODS = new Set([
10596
10660
  "listAgentSessions",
10597
10661
  "resumeAgentSession",
10598
10662
  "prompt",
10663
+ "injectMessage",
10599
10664
  "setMode",
10600
10665
  "setModel",
10601
10666
  "getSessionModel",
@@ -10614,6 +10679,7 @@ var SESSION_SCOPED_METHODS = new Set([
10614
10679
  "tailSessionHistory",
10615
10680
  "resumeAgentSession",
10616
10681
  "prompt",
10682
+ "injectMessage",
10617
10683
  "setMode",
10618
10684
  "setModel",
10619
10685
  "getSessionModel",
@@ -10670,7 +10736,7 @@ class BridgeServer {
10670
10736
  ...error.stderrTail ? { stderrTail: error.stderrTail } : {}
10671
10737
  }
10672
10738
  } : {};
10673
- const errorCode = error instanceof AcpxQueueOverflowError ? error.code : error instanceof BridgeInvalidRequestError ? "BRIDGE_INVALID_REQUEST" : "BRIDGE_INTERNAL_ERROR";
10739
+ const errorCode = error instanceof AcpxQueueOverflowError ? error.code : error instanceof MessageInjectionError ? error.code : error instanceof BridgeInvalidRequestError ? "BRIDGE_INVALID_REQUEST" : "BRIDGE_INTERNAL_ERROR";
10674
10740
  return `${JSON.stringify({
10675
10741
  id: requestId,
10676
10742
  ok: false,
@@ -10763,7 +10829,7 @@ class BridgeServer {
10763
10829
  if (!sessionKey) {
10764
10830
  return await this.dispatch(requestId, method, params, writeLine);
10765
10831
  }
10766
- const lane = method === "cancel" || method === "isSessionWarm" ? "control" : "normal";
10832
+ const lane = method === "cancel" || method === "isSessionWarm" ? "control" : method === "injectMessage" ? "message" : "normal";
10767
10833
  return await this.scheduler.run(sessionKey, lane, () => this.dispatch(requestId, method, params, writeLine));
10768
10834
  }
10769
10835
  async dispatch(requestId, method, params, writeLine) {
@@ -10897,6 +10963,23 @@ class BridgeServer {
10897
10963
  }));
10898
10964
  }
10899
10965
  });
10966
+ case "injectMessage":
10967
+ return await this.runtime.injectMessage({
10968
+ agent: requireString(params, "agent"),
10969
+ ...agentExecutionSettings(params),
10970
+ agentCommand: asOptionalString(params.agentCommand),
10971
+ ...agentLaunchSelection(params),
10972
+ cwd: requireString(params, "cwd"),
10973
+ name: requireString(params, "name"),
10974
+ sessionKey: asOptionalString(params.sessionKey),
10975
+ model: asOptionalString(params.model),
10976
+ effort: asOptionalString(params.effort),
10977
+ mcpCoordinatorSession: asOptionalString(params.mcpCoordinatorSession),
10978
+ mcpSourceHandle: asOptionalString(params.mcpSourceHandle),
10979
+ text: requireString(params, "text"),
10980
+ mode: requireMessageMode(params, "mode"),
10981
+ messageId: requireString(params, "messageId")
10982
+ });
10900
10983
  case "resumeAgentSession":
10901
10984
  return await this.runtime.resumeAgentSession({
10902
10985
  agent: requireString(params, "agent"),
@@ -11119,6 +11202,13 @@ function requirePromptText(params, media) {
11119
11202
  }
11120
11203
  return value;
11121
11204
  }
11205
+ function requireMessageMode(params, key) {
11206
+ const value = params[key];
11207
+ if (value === "auto" || value === "steer" || value === "queue" || value === "interrupt") {
11208
+ return value;
11209
+ }
11210
+ throw new BridgeInvalidRequestError(key + " must be auto, steer, queue, or interrupt");
11211
+ }
11122
11212
  function requirePermissionMode(params, key) {
11123
11213
  const value = params[key];
11124
11214
  if (value === "approve-all" || value === "approve-reads" || value === "deny-all") {
@@ -157,6 +157,28 @@ export interface MessageChannelRuntime {
157
157
  * treated as "table".
158
158
  */
159
159
  nativeSessionListFormat?: "cards" | "table";
160
+ /** Relay-capable channels: route an Agent Message to a remote messaging node.
161
+ * Optional — absent channels make the router report ROUTE_UNAVAILABLE. */
162
+ sendAgentMessageRoute?(payload: {
163
+ sourceNodeId: string;
164
+ sourceEndpointId: string;
165
+ targetNodeId: string;
166
+ targetEndpointId: string;
167
+ messageId: string;
168
+ content: string;
169
+ requestedMode: string;
170
+ replyTo?: string;
171
+ }): Promise<{
172
+ messageId: string;
173
+ status: "injected" | "queued" | "failed";
174
+ modeUsed?: "steer" | "queue" | "interrupt" | "prompt";
175
+ targetState?: "idle" | "running";
176
+ errorCode?: string;
177
+ deduplicated?: boolean;
178
+ }>;
179
+ /** Relay-capable channels: publish this instance's agent endpoint directory to
180
+ * the hub. The FULL snapshot replaces the previous one (no delta protocol). */
181
+ syncAgentEndpoints?(endpoints: unknown[]): void;
160
182
  }
161
183
  export type ToolUseStatus = "running" | "success" | "error";
162
184
  export type ToolUseKind = "read" | "search" | "execute" | "edit" | "think" | "other";