agl 41.0.0 → 41.0.1

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.
@@ -75,6 +75,8 @@ type TReproof = { kind: 'rebound' } | { kind: 'refused'; reason: string } | { ki
75
75
 
76
76
  export interface IControllerWorkerCallerOptions {
77
77
  controllerGeneration: string;
78
+ /** The port this controller is configured to serve: a bridge an upgrade re-executed in place names it (`aglMcpReexecArguments`). */
79
+ controllerPort: number;
78
80
  registry: ControllerMcpCallerRegistry;
79
81
  readMaster(): Promise<IConfigurationMaster>;
80
82
  captureCodexOrigin(launch: Extract<TFleetWorkerCallerLaunch, { harnessId: 'codex' }>): Promise<IWorkerCodexCallerOrigin>;
@@ -103,8 +105,10 @@ const pending = (): IWorkerCallerEnrollmentResponse => ({ callerPending: true, b
103
105
  const transientRefusalMs = 5_000;
104
106
  const maximumRefusals = 64;
105
107
  const maximumLoggedReasons = 4096;
108
+ /** A message as a clause of a pending reason, without its final period: the log line ends the sentence. */
109
+ const clause = (messageArg: string): string => messageArg.replace(/\.+$/u, '');
106
110
  const proofReason = (errorArg: unknown): string => errorArg instanceof WorkerCallerProofError
107
- ? errorArg.message : `a process could not be read (${(errorArg as NodeJS.ErrnoException).code ?? 'unknown'})`;
111
+ ? clause(errorArg.message) : `a process could not be read (${(errorArg as NodeJS.ErrnoException).code ?? 'unknown'})`;
108
112
  const assertIdentifier = (valueArg: string): void => {
109
113
  if (typeof valueArg !== 'string' || !/^[A-Za-z0-9_.:-]{1,256}$/u.test(valueArg)) throw new Error('Invalid worker launch identifier.');
110
114
  };
@@ -377,19 +381,20 @@ export class ControllerWorkerCallers implements IFleetWorkerCallerHooks {
377
381
  private async reprove(recordArg: IWorkerLaunch, bridgePidArg: number, connectionArg?: IWorkerCallerConnection): Promise<TReproof> {
378
382
  const observe = this.options.observeClaudeJob;
379
383
  if (!observe) return { kind: 'refused', reason: 'the process its launch is bound to is gone, and no fleet proves the job\'s next process' };
384
+ const port = this.options.controllerPort;
380
385
  let bridge: IWorkerProcessSnapshot, command = recordArg.command!;
381
- try { bridge = await this.proof.readBridge(connectionArg, bridgePidArg, command); } catch (errorArg) {
386
+ try { bridge = await this.proof.readBridge(connectionArg, bridgePidArg, command, port); } catch (errorArg) {
382
387
  if (!isWorkerCallerProofRefusal(errorArg)) throw errorArg;
383
388
  // An upgrade re-executes a bridge in place onto the build the controller runs now: it runs the command this
384
389
  // controller resolves from its own configured `agl` entry, never one the bridge names.
385
390
  let current: IWorkerBridgeCommand;
386
391
  try { current = await this.currentCommand(); } catch (resolveArg) {
387
- return { kind: 'refused', reason: `${proofReason(errorArg)} (the approved bridge command cannot be resolved now: ${resolveArg instanceof Error ? resolveArg.message : 'unknown failure'})` };
392
+ return { kind: 'refused', reason: `${proofReason(errorArg)} (the approved bridge command cannot be resolved now: ${resolveArg instanceof Error ? clause(resolveArg.message) : 'unknown failure'})` };
388
393
  }
389
394
  if (plugins.util.isDeepStrictEqual(current, command)) return { kind: 'refused', reason: proofReason(errorArg) };
390
- try { bridge = await this.proof.readBridge(connectionArg, bridgePidArg, current); } catch (currentArg) {
395
+ try { bridge = await this.proof.readBridge(connectionArg, bridgePidArg, current, port); } catch (currentArg) {
391
396
  if (!isWorkerCallerProofRefusal(currentArg)) throw currentArg;
392
- return { kind: 'refused', reason: proofReason(errorArg) };
397
+ return { kind: 'refused', reason: `recorded bridge command: ${proofReason(errorArg)}; current bridge command: ${proofReason(currentArg)}` };
393
398
  }
394
399
  command = current;
395
400
  }
@@ -433,7 +438,7 @@ export class ControllerWorkerCallers implements IFleetWorkerCallerHooks {
433
438
  if (!isWorkerCallerProofRefusal(errorArg)) throw errorArg;
434
439
  return refuse('the process of its Claude job is not the approved Claude Code executable', false);
435
440
  }
436
- try { await this.proof.verifyBridge(connectionArg, bridge.pid, command, parent); } catch (errorArg) {
441
+ try { await this.proof.verifyBridge(connectionArg, bridge.pid, command, parent, port); } catch (errorArg) {
437
442
  if (!isWorkerCallerProofRefusal(errorArg)) throw errorArg;
438
443
  return refuse('its bridge is not proved to be a direct child of the process of its Claude job', true);
439
444
  }
@@ -678,7 +683,7 @@ export class ControllerWorkerCallers implements IFleetWorkerCallerHooks {
678
683
  private async safeSnapshot(recordArg: IWorkerLaunch, bridgePidArg: number, connectionArg?: IWorkerCallerConnection): Promise<IWorkerProcessSnapshot> {
679
684
  if (recordArg.state !== 'bound' || !recordArg.command || !recordArg.parent || this.closed
680
685
  || (recordArg.codex && !await recordArg.codex.isCurrent())) throw new WorkerCallerProofError('Worker caller proof is unavailable.');
681
- return this.proof.verifyBridge(connectionArg, bridgePidArg, recordArg.command, recordArg.parent);
686
+ return this.proof.verifyBridge(connectionArg, bridgePidArg, recordArg.command, recordArg.parent, this.options.controllerPort);
682
687
  }
683
688
 
684
689
  private async prove(recordArg: IWorkerLaunch, bridgePidArg: number, connectionArg?: IWorkerCallerConnection,
@@ -142,15 +142,26 @@ const processOwnsLoopbackConnection = async (connectionArg: IWorkerCallerConnect
142
142
  return matches.length === 1 && await processOwnsInode(pidArg, matches[0][9]);
143
143
  };
144
144
 
145
+ /**
146
+ * The arguments after its `cli.js` entry that an upgrade re-executes an `agl mcp` bridge of the controller on
147
+ * `controllerPortArg` with (`AglMcpReexecCoordinator`): the port pins the next image to its handover record's.
148
+ * A bridge proof accepts exactly these besides the approved command's own.
149
+ */
150
+ export const aglMcpReexecArguments = (controllerPortArg: number): string[] => ['mcp', '--port', String(controllerPortArg)];
151
+
145
152
  /**
146
153
  * The bridge process `bridgePidArg`, proved to hold the caller's end of the direct loopback connection and to run the
147
154
  * approved command, whatever its parent. The command is the one recorded when the launch was prepared: an upgrade
148
- * installs AGL under another path, and a command whose files are gone is refused as such.
155
+ * installs AGL under another path, and a command whose files are gone is refused as such. Its arguments are the
156
+ * approved ones or, once an upgrade re-executed the bridge in place, `aglMcpReexecArguments` for `controllerPortArg`,
157
+ * the port this controller is configured with, never one the bridge names: the connection proof already shows that
158
+ * the bridge talks to this controller.
149
159
  */
150
160
  export const readWorkerBridge = async (
151
161
  connectionArg: IWorkerCallerConnection | undefined,
152
162
  bridgePidArg: number,
153
163
  commandArg: IWorkerBridgeCommand,
164
+ controllerPortArg: number,
154
165
  ): Promise<IWorkerProcessSnapshot> => {
155
166
  for (const file of [commandArg.executable, commandArg.entry]) {
156
167
  let resolved: string;
@@ -165,8 +176,10 @@ export const readWorkerBridge = async (
165
176
  }
166
177
  const bridge = await readWorkerProcessSnapshot(bridgePidArg);
167
178
  const entry = await plugins.fs.promises.realpath(bridge.arguments[1] ?? '');
179
+ const argumentsTail = bridge.arguments.slice(2);
168
180
  if (bridge.executable !== commandArg.executable || entry !== commandArg.entry
169
- || !plugins.util.isDeepStrictEqual(bridge.arguments.slice(2), commandArg.arguments)) {
181
+ || (!plugins.util.isDeepStrictEqual(argumentsTail, commandArg.arguments)
182
+ && !plugins.util.isDeepStrictEqual(argumentsTail, aglMcpReexecArguments(controllerPortArg)))) {
170
183
  throw new WorkerCallerProofError('Worker bridge does not match the approved launch.');
171
184
  }
172
185
  return bridge;
@@ -177,8 +190,9 @@ export const verifyWorkerBridge = async (
177
190
  bridgePidArg: number,
178
191
  commandArg: IWorkerBridgeCommand,
179
192
  parentArg: IWorkerProcessSnapshot,
193
+ controllerPortArg: number,
180
194
  ): Promise<IWorkerProcessSnapshot> => {
181
- const bridge = await readWorkerBridge(connectionArg, bridgePidArg, commandArg);
195
+ const bridge = await readWorkerBridge(connectionArg, bridgePidArg, commandArg, controllerPortArg);
182
196
  if (bridge.parentPid !== parentArg.pid) throw new WorkerCallerProofError('Worker bridge does not match the approved launch.');
183
197
  if (!workerSnapshotsEqual(parentArg, await readWorkerProcessSnapshot(parentArg.pid))
184
198
  || !workerSnapshotsEqual(bridge, await readWorkerProcessSnapshot(bridge.pid))) {
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: 'agl',
6
- version: '41.0.0',
6
+ version: '41.0.1',
7
7
  description: 'Agent Gateway Layer for OpenCode, FlexHarness, and Codex sessions'
8
8
  }