@openscout/scout 0.2.63 → 0.2.65

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.
@@ -5930,8 +5930,8 @@ class CodexAdapter extends BaseAdapter {
5930
5930
  const resumed = await this.request("thread/resume", {
5931
5931
  threadId: storedThreadId,
5932
5932
  cwd: options.cwd,
5933
- approvalPolicy: "never",
5934
- sandbox: "danger-full-access",
5933
+ approvalPolicy: options.approvalPolicy ?? "never",
5934
+ sandbox: options.sandbox ?? "danger-full-access",
5935
5935
  baseInstructions: options.systemPrompt,
5936
5936
  persistExtendedHistory: true
5937
5937
  });
@@ -5961,8 +5961,8 @@ class CodexAdapter extends BaseAdapter {
5961
5961
  }
5962
5962
  const started = await this.request("thread/start", {
5963
5963
  cwd: options.cwd,
5964
- approvalPolicy: "never",
5965
- sandbox: "danger-full-access",
5964
+ approvalPolicy: options.approvalPolicy ?? "never",
5965
+ sandbox: options.sandbox ?? "danger-full-access",
5966
5966
  baseInstructions: options.systemPrompt,
5967
5967
  ephemeral: false,
5968
5968
  experimentalRawEvents: false,
@@ -8321,10 +8321,12 @@ function scopesMatch(left, right) {
8321
8321
  if (left.sessionId !== right.sessionId) {
8322
8322
  return false;
8323
8323
  }
8324
- if (left.kind === "session") {
8325
- return true;
8324
+ switch (left.kind) {
8325
+ case "session":
8326
+ return true;
8327
+ case "file_change":
8328
+ return right.kind === "file_change" && left.turnId === right.turnId && left.blockId === right.blockId;
8326
8329
  }
8327
- return left.turnId === right.turnId && left.blockId === right.blockId;
8328
8330
  }
8329
8331
  function pathForWebHandoffScope(scope) {
8330
8332
  switch (scope.kind) {
@@ -9097,6 +9099,40 @@ var BUILT_IN_HARNESS_CATALOG = [
9097
9099
  cwdFlag: "--cwd"
9098
9100
  },
9099
9101
  capabilities: ["chat", "invoke", "deliver", "review", "execute"]
9102
+ },
9103
+ {
9104
+ name: "cursor",
9105
+ harness: "cursor",
9106
+ label: "Cursor Agent SDK",
9107
+ description: "Programmatic agent execution via the Cursor Agent SDK",
9108
+ homepage: "https://cursor.com",
9109
+ tags: ["coding", "sdk", "cursor"],
9110
+ featured: true,
9111
+ order: 3,
9112
+ support: {
9113
+ ...DEFAULT_SUPPORT,
9114
+ workspace: true,
9115
+ collaboration: true,
9116
+ files: true
9117
+ },
9118
+ install: {
9119
+ binary: "mw",
9120
+ requires: ["bun"],
9121
+ macos: "bun install -g missionwriter",
9122
+ linux: "bun install -g missionwriter",
9123
+ windows: "bun install -g missionwriter"
9124
+ },
9125
+ readiness: {
9126
+ anyOf: [
9127
+ { kind: "env", key: "CURSOR_API_KEY" }
9128
+ ],
9129
+ notReadyMessage: "Cursor Agent SDK is available but CURSOR_API_KEY is not set."
9130
+ },
9131
+ capabilities: ["invoke", "deliver", "execute"],
9132
+ metadata: {
9133
+ sdkType: "cursor",
9134
+ invocationModel: "one_shot"
9135
+ }
9100
9136
  }
9101
9137
  ];
9102
9138
  function expandHomePath(value) {
@@ -10671,6 +10707,22 @@ function diagnoseAgentIdentity(identity, candidates) {
10671
10707
  var parseAgentSelector = parseAgentIdentity;
10672
10708
  var formatAgentSelector = formatAgentIdentity;
10673
10709
  var resolveAgentSelector = resolveAgentIdentity;
10710
+ // ../protocol/src/permission-policy.ts
10711
+ var SCOUT_PERMISSION_PROFILES = [
10712
+ "observe",
10713
+ "review",
10714
+ "workspace_write",
10715
+ "sandboxed_write",
10716
+ "trusted_local",
10717
+ "external_sandbox"
10718
+ ];
10719
+ function normalizeScoutPermissionProfile(value) {
10720
+ const normalized = value?.trim().replaceAll("-", "_");
10721
+ return SCOUT_PERMISSION_PROFILES.find((profile) => profile === normalized);
10722
+ }
10723
+ function formatScoutPermissionProfiles() {
10724
+ return SCOUT_PERMISSION_PROFILES.join("|");
10725
+ }
10674
10726
  // ../runtime/src/user-project-hints.ts
10675
10727
  import { readdir, readFile as readFile3, stat } from "fs/promises";
10676
10728
  import { homedir as homedir11 } from "os";
@@ -10996,7 +11048,7 @@ async function collectUserLevelProjectRootHints(options = {}) {
10996
11048
  // ../runtime/src/setup.ts
10997
11049
  var SCOUT_AGENT_ID = "scout";
10998
11050
  var SCOUT_PRIMARY_CONVERSATION_ID = "dm.scout.primary";
10999
- var MANAGED_AGENT_HARNESSES = ["claude", "codex"];
11051
+ var MANAGED_AGENT_HARNESSES = ["claude", "codex", "cursor"];
11000
11052
  function titleCaseWords(value) {
11001
11053
  return value.split(/[\s._-]+/).map((part) => part.trim()).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
11002
11054
  }
@@ -11115,6 +11167,10 @@ var PROJECT_HARNESS_MARKERS = {
11115
11167
  "AGENTS.md",
11116
11168
  "CODEX.md",
11117
11169
  ".codex"
11170
+ ],
11171
+ cursor: [
11172
+ ".cursor",
11173
+ ".cursorrules"
11118
11174
  ]
11119
11175
  };
11120
11176
  function partitionFlatAndNestedMarkers(markers) {
@@ -11179,6 +11235,9 @@ function normalizeManagedHarness(value, fallback) {
11179
11235
  if (value === "claude") {
11180
11236
  return "claude";
11181
11237
  }
11238
+ if (value === "cursor") {
11239
+ return "cursor";
11240
+ }
11182
11241
  return fallback;
11183
11242
  }
11184
11243
  function titleCase(value) {
@@ -11352,12 +11411,15 @@ function normalizeCapabilities(value) {
11352
11411
  return normalized.length > 0 ? normalized : [...DEFAULT_CAPABILITIES];
11353
11412
  }
11354
11413
  function normalizeHarness(value, fallback) {
11355
- return value === "codex" ? "codex" : value === "claude" ? "claude" : fallback;
11414
+ return value === "codex" ? "codex" : value === "claude" ? "claude" : value === "cursor" ? "cursor" : fallback;
11356
11415
  }
11357
11416
  function normalizeTransport(value, harness, fallback) {
11358
11417
  if (harness === "codex") {
11359
11418
  return "codex_app_server";
11360
11419
  }
11420
+ if (harness === "cursor") {
11421
+ return "cursor_exec";
11422
+ }
11361
11423
  if (value === "claude_stream_json") {
11362
11424
  return "claude_stream_json";
11363
11425
  }
@@ -11367,11 +11429,13 @@ function normalizeTransport(value, harness, fallback) {
11367
11429
  return fallback === "codex_app_server" ? "claude_stream_json" : fallback;
11368
11430
  }
11369
11431
  function normalizeHarnessProfile(profile, harness, options) {
11432
+ const permissionProfile = normalizeScoutPermissionProfile(typeof profile?.permissionProfile === "string" ? profile.permissionProfile : options.fallbackPermissionProfile);
11370
11433
  return {
11371
11434
  cwd: profile?.cwd ? normalizeProjectRelativePath(options.projectRoot, profile.cwd) : options.projectRoot,
11372
11435
  transport: normalizeTransport(profile?.transport, harness, harness === "codex" ? "codex_app_server" : DEFAULT_TRANSPORT),
11373
11436
  sessionId: normalizeTmuxSessionName(profile?.sessionId, `${options.sessionKey}-${harness}`, options.sessionPrefix),
11374
- launchArgs: normalizeLaunchArgs(profile?.launchArgs ?? options.fallbackLaunchArgs)
11437
+ launchArgs: normalizeLaunchArgs(profile?.launchArgs ?? options.fallbackLaunchArgs),
11438
+ ...permissionProfile ? { permissionProfile } : {}
11375
11439
  };
11376
11440
  }
11377
11441
  function buildHarnessProfiles(input) {
@@ -11387,7 +11451,8 @@ function buildHarnessProfiles(input) {
11387
11451
  projectRoot: input.projectRoot,
11388
11452
  sessionKey: input.sessionKey,
11389
11453
  sessionPrefix: input.sessionPrefix,
11390
- fallbackLaunchArgs: input.launchArgs
11454
+ fallbackLaunchArgs: input.launchArgs,
11455
+ fallbackPermissionProfile: input.permissionProfile
11391
11456
  });
11392
11457
  }
11393
11458
  for (const harness of MANAGED_AGENT_HARNESSES) {
@@ -11400,7 +11465,8 @@ function buildHarnessProfiles(input) {
11400
11465
  projectRoot: input.projectRoot,
11401
11466
  sessionKey: input.sessionKey,
11402
11467
  sessionPrefix: input.sessionPrefix,
11403
- fallbackLaunchArgs: profiles[harness]?.launchArgs ?? input.launchArgs
11468
+ fallbackLaunchArgs: profiles[harness]?.launchArgs ?? input.launchArgs,
11469
+ fallbackPermissionProfile: profiles[harness]?.permissionProfile ?? input.permissionProfile
11404
11470
  });
11405
11471
  }
11406
11472
  }
@@ -11408,7 +11474,8 @@ function buildHarnessProfiles(input) {
11408
11474
  projectRoot: input.projectRoot,
11409
11475
  sessionKey: input.sessionKey,
11410
11476
  sessionPrefix: input.sessionPrefix,
11411
- fallbackLaunchArgs: input.launchArgs
11477
+ fallbackLaunchArgs: input.launchArgs,
11478
+ fallbackPermissionProfile: input.permissionProfile
11412
11479
  });
11413
11480
  profiles[input.defaultHarness] = ensuredHarness;
11414
11481
  return profiles;
@@ -11858,7 +11925,8 @@ async function readLegacyAgentRegistry() {
11858
11925
  async function detectHarnessMarkers(projectRoot) {
11859
11926
  const detected = {
11860
11927
  claude: [],
11861
- codex: []
11928
+ codex: [],
11929
+ cursor: []
11862
11930
  };
11863
11931
  for (const harness of MANAGED_AGENT_HARNESSES) {
11864
11932
  for (const marker of PROJECT_HARNESS_MARKERS[harness]) {
@@ -12440,7 +12508,8 @@ async function resolveManifestBackedAgent(projectRoot, config, settings, overrid
12440
12508
  defaultHarness,
12441
12509
  profiles: config.agent?.runtime?.profiles,
12442
12510
  runtime: runtimeDefaults,
12443
- launchArgs: normalizeLaunchArgs(runtimeDefaults?.launchArgs)
12511
+ launchArgs: normalizeLaunchArgs(runtimeDefaults?.launchArgs),
12512
+ permissionProfile: normalizeScoutPermissionProfile(runtimeDefaults?.permissionProfile)
12444
12513
  });
12445
12514
  const view = resolvedRuntimeView(defaultHarness, harnessProfiles);
12446
12515
  const base = {
@@ -12515,7 +12584,7 @@ async function buildProjectInventoryEntry(agent, sourceRoot) {
12515
12584
  });
12516
12585
  }
12517
12586
  }
12518
- if (manifestDefaultHarness === "claude" || manifestDefaultHarness === "codex") {
12587
+ if (manifestDefaultHarness === "claude" || manifestDefaultHarness === "codex" || manifestDefaultHarness === "cursor") {
12519
12588
  harnesses.set(manifestDefaultHarness, {
12520
12589
  harness: manifestDefaultHarness,
12521
12590
  source: "manifest",
@@ -12800,6 +12869,29 @@ function buildManagedAgentShellExports(options) {
12800
12869
  }
12801
12870
 
12802
12871
  // ../runtime/src/claude-stream-json.ts
12872
+ function resolveRequesterTimeoutMs(timeoutMs) {
12873
+ if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0) {
12874
+ return timeoutMs;
12875
+ }
12876
+ return null;
12877
+ }
12878
+ function waitForRequesterResult(promise, timeoutMs, label) {
12879
+ const effectiveTimeoutMs = resolveRequesterTimeoutMs(timeoutMs);
12880
+ if (effectiveTimeoutMs === null) {
12881
+ return promise;
12882
+ }
12883
+ let timer = null;
12884
+ const timeout = new Promise((_resolve, reject) => {
12885
+ timer = setTimeout(() => {
12886
+ reject(new Error(`Timed out after ${effectiveTimeoutMs}ms waiting for ${label}.`));
12887
+ }, effectiveTimeoutMs);
12888
+ });
12889
+ return Promise.race([promise, timeout]).finally(() => {
12890
+ if (timer) {
12891
+ clearTimeout(timer);
12892
+ }
12893
+ });
12894
+ }
12803
12895
  function resolveClaudeStreamJsonOutput(result, fallbackParts) {
12804
12896
  const trimmedResult = result?.trim();
12805
12897
  if (trimmedResult) {
@@ -12896,7 +12988,7 @@ class ClaudeStreamJsonSession {
12896
12988
  sessionId: this.claudeSessionId
12897
12989
  };
12898
12990
  }
12899
- async invoke(prompt, stallTimeoutMs = 10 * 60000) {
12991
+ async invoke(prompt, timeoutMs) {
12900
12992
  await this.ensureStarted();
12901
12993
  if (!this.process?.stdin) {
12902
12994
  throw new Error(`Claude stream-json session for ${this.options.agentName} is not running.`);
@@ -12908,13 +13000,10 @@ class ClaudeStreamJsonSession {
12908
13000
  const turn = {
12909
13001
  id: randomUUID(),
12910
13002
  output: [],
12911
- timer: null,
12912
- stallMs: stallTimeoutMs,
12913
13003
  resolve: resolve4,
12914
13004
  reject
12915
13005
  };
12916
13006
  this.activeTurn = turn;
12917
- this.resetTurnWatchdog(turn);
12918
13007
  });
12919
13008
  const payload = JSON.stringify({
12920
13009
  type: "user",
@@ -12927,7 +13016,7 @@ class ClaudeStreamJsonSession {
12927
13016
  }) + `
12928
13017
  `;
12929
13018
  this.process.stdin.write(payload);
12930
- const output = await outputPromise;
13019
+ const output = await waitForRequesterResult(outputPromise, timeoutMs, this.options.agentName);
12931
13020
  return {
12932
13021
  output,
12933
13022
  sessionId: this.claudeSessionId
@@ -12949,27 +13038,10 @@ class ClaudeStreamJsonSession {
12949
13038
  }) + `
12950
13039
  `);
12951
13040
  }
12952
- resetTurnWatchdog(turn) {
12953
- if (turn.timer) {
12954
- clearTimeout(turn.timer);
12955
- }
12956
- turn.timer = setTimeout(() => {
12957
- this.interrupt().catch(() => {
12958
- return;
12959
- });
12960
- if (this.activeTurn?.id === turn.id) {
12961
- this.activeTurn = null;
12962
- }
12963
- turn.reject(new Error(`${this.options.agentName} stalled \u2014 no stream event in ${turn.stallMs}ms`));
12964
- }, turn.stallMs);
12965
- }
12966
13041
  async shutdown(options = {}) {
12967
13042
  const turn = this.activeTurn;
12968
13043
  this.activeTurn = null;
12969
13044
  if (turn) {
12970
- if (turn.timer) {
12971
- clearTimeout(turn.timer);
12972
- }
12973
13045
  turn.reject(new Error(`Claude stream-json session for ${this.options.agentName} was shut down.`));
12974
13046
  }
12975
13047
  const child = this.process;
@@ -13047,9 +13119,6 @@ class ClaudeStreamJsonSession {
13047
13119
  if (this.activeTurn) {
13048
13120
  const turn = this.activeTurn;
13049
13121
  this.activeTurn = null;
13050
- if (turn.timer) {
13051
- clearTimeout(turn.timer);
13052
- }
13053
13122
  turn.reject(new Error(`Claude process error: ${error.message}`));
13054
13123
  }
13055
13124
  });
@@ -13080,9 +13149,6 @@ class ClaudeStreamJsonSession {
13080
13149
  if (code !== 0 && this.activeTurn) {
13081
13150
  const turn = this.activeTurn;
13082
13151
  this.activeTurn = null;
13083
- if (turn.timer) {
13084
- clearTimeout(turn.timer);
13085
- }
13086
13152
  turn.reject(new Error(`Claude exited with code ${code}`));
13087
13153
  }
13088
13154
  });
@@ -13104,7 +13170,6 @@ class ClaudeStreamJsonSession {
13104
13170
  if (!turn) {
13105
13171
  return;
13106
13172
  }
13107
- this.resetTurnWatchdog(turn);
13108
13173
  if (event.type === "assistant") {
13109
13174
  const content = event.message?.content ?? event.content ?? [];
13110
13175
  for (const part of content) {
@@ -13116,17 +13181,11 @@ class ClaudeStreamJsonSession {
13116
13181
  }
13117
13182
  if (event.type === "result") {
13118
13183
  this.activeTurn = null;
13119
- if (turn.timer) {
13120
- clearTimeout(turn.timer);
13121
- }
13122
13184
  turn.resolve(resolveClaudeStreamJsonOutput(event.result, turn.output));
13123
13185
  return;
13124
13186
  }
13125
13187
  if (event.type === "error") {
13126
13188
  this.activeTurn = null;
13127
- if (turn.timer) {
13128
- clearTimeout(turn.timer);
13129
- }
13130
13189
  turn.reject(new Error(event.error?.message ?? event.message ?? "Unknown Claude error"));
13131
13190
  }
13132
13191
  }
@@ -13179,10 +13238,17 @@ function normalizeCodexModelValue(value) {
13179
13238
  const trimmed = value?.trim();
13180
13239
  return trimmed ? trimmed : null;
13181
13240
  }
13241
+ function normalizeCodexReasoningEffortValue(value) {
13242
+ const trimmed = value?.trim();
13243
+ return trimmed ? trimmed : null;
13244
+ }
13182
13245
  function encodeCodexModelConfig(model) {
13183
13246
  return `model=${JSON.stringify(model)}`;
13184
13247
  }
13185
- function parseCodexModelConfig(value) {
13248
+ function encodeCodexReasoningEffortConfig(reasoningEffort) {
13249
+ return `model_reasoning_effort=${JSON.stringify(reasoningEffort)}`;
13250
+ }
13251
+ function parseCodexConfigValue(value, expectedKey) {
13186
13252
  const trimmed = value?.trim();
13187
13253
  if (!trimmed) {
13188
13254
  return null;
@@ -13192,7 +13258,7 @@ function parseCodexModelConfig(value) {
13192
13258
  return null;
13193
13259
  }
13194
13260
  const key = trimmed.slice(0, separatorIndex).trim();
13195
- if (key !== "model") {
13261
+ if (key !== expectedKey) {
13196
13262
  return null;
13197
13263
  }
13198
13264
  const rawValue = trimmed.slice(separatorIndex + 1).trim();
@@ -13204,6 +13270,12 @@ function parseCodexModelConfig(value) {
13204
13270
  }
13205
13271
  return rawValue;
13206
13272
  }
13273
+ function parseCodexModelConfig(value) {
13274
+ return parseCodexConfigValue(value, "model");
13275
+ }
13276
+ function parseCodexReasoningEffortConfig(value) {
13277
+ return parseCodexConfigValue(value, "model_reasoning_effort");
13278
+ }
13207
13279
  function normalizeCodexAppServerLaunchArgs(launchArgs) {
13208
13280
  const args = Array.isArray(launchArgs) ? launchArgs.map((entry) => String(entry).trim()).filter(Boolean) : [];
13209
13281
  const normalized = [];
@@ -13233,11 +13305,36 @@ function normalizeCodexAppServerLaunchArgs(launchArgs) {
13233
13305
  continue;
13234
13306
  }
13235
13307
  }
13308
+ if (current === "--reasoning-effort" || current === "--effort") {
13309
+ const reasoningEffort = normalizeCodexReasoningEffortValue(args[index + 1]);
13310
+ if (reasoningEffort) {
13311
+ normalized.push("-c", encodeCodexReasoningEffortConfig(reasoningEffort));
13312
+ index += 1;
13313
+ continue;
13314
+ }
13315
+ normalized.push(current);
13316
+ continue;
13317
+ }
13318
+ if (current.startsWith("--reasoning-effort=")) {
13319
+ const reasoningEffort = normalizeCodexReasoningEffortValue(current.slice("--reasoning-effort=".length));
13320
+ if (reasoningEffort) {
13321
+ normalized.push("-c", encodeCodexReasoningEffortConfig(reasoningEffort));
13322
+ continue;
13323
+ }
13324
+ }
13325
+ if (current.startsWith("--effort=")) {
13326
+ const reasoningEffort = normalizeCodexReasoningEffortValue(current.slice("--effort=".length));
13327
+ if (reasoningEffort) {
13328
+ normalized.push("-c", encodeCodexReasoningEffortConfig(reasoningEffort));
13329
+ continue;
13330
+ }
13331
+ }
13236
13332
  if (current === "-c" || current === "--config") {
13237
13333
  const next = args[index + 1];
13238
13334
  if (typeof next === "string") {
13239
13335
  const model = parseCodexModelConfig(next);
13240
- normalized.push(current === "--config" ? "--config" : "-c", model ? encodeCodexModelConfig(model) : next);
13336
+ const reasoningEffort = parseCodexReasoningEffortConfig(next);
13337
+ normalized.push(current === "--config" ? "--config" : "-c", model ? encodeCodexModelConfig(model) : reasoningEffort ? encodeCodexReasoningEffortConfig(reasoningEffort) : next);
13241
13338
  index += 1;
13242
13339
  continue;
13243
13340
  }
@@ -13245,7 +13342,8 @@ function normalizeCodexAppServerLaunchArgs(launchArgs) {
13245
13342
  if (current.startsWith("--config=")) {
13246
13343
  const value = current.slice("--config=".length);
13247
13344
  const model = parseCodexModelConfig(value);
13248
- normalized.push(model ? `--config=${encodeCodexModelConfig(model)}` : current);
13345
+ const reasoningEffort = parseCodexReasoningEffortConfig(value);
13346
+ normalized.push(model ? `--config=${encodeCodexModelConfig(model)}` : reasoningEffort ? `--config=${encodeCodexReasoningEffortConfig(reasoningEffort)}` : current);
13249
13347
  continue;
13250
13348
  }
13251
13349
  normalized.push(current);
@@ -13273,6 +13371,50 @@ function readCodexAppServerModelFromLaunchArgs(launchArgs) {
13273
13371
  }
13274
13372
  return null;
13275
13373
  }
13374
+ function readCodexAppServerReasoningEffortFromLaunchArgs(launchArgs) {
13375
+ const normalized = normalizeCodexAppServerLaunchArgs(launchArgs);
13376
+ for (let index = 0;index < normalized.length; index += 1) {
13377
+ const current = normalized[index] ?? "";
13378
+ if (current === "-c" || current === "--config") {
13379
+ const reasoningEffort = parseCodexReasoningEffortConfig(normalized[index + 1]);
13380
+ if (reasoningEffort) {
13381
+ return reasoningEffort;
13382
+ }
13383
+ index += 1;
13384
+ continue;
13385
+ }
13386
+ if (current.startsWith("--config=")) {
13387
+ const reasoningEffort = parseCodexReasoningEffortConfig(current.slice("--config=".length));
13388
+ if (reasoningEffort) {
13389
+ return reasoningEffort;
13390
+ }
13391
+ }
13392
+ }
13393
+ return null;
13394
+ }
13395
+ function resolveRequesterTimeoutMs2(timeoutMs) {
13396
+ if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0) {
13397
+ return timeoutMs;
13398
+ }
13399
+ return null;
13400
+ }
13401
+ function waitForRequesterResult2(promise, timeoutMs, label) {
13402
+ const effectiveTimeoutMs = resolveRequesterTimeoutMs2(timeoutMs);
13403
+ if (effectiveTimeoutMs === null) {
13404
+ return promise;
13405
+ }
13406
+ let timer = null;
13407
+ const timeout = new Promise((_resolve, reject) => {
13408
+ timer = setTimeout(() => {
13409
+ reject(new Error(`Timed out after ${effectiveTimeoutMs}ms waiting for ${label}.`));
13410
+ }, effectiveTimeoutMs);
13411
+ });
13412
+ return Promise.race([promise, timeout]).finally(() => {
13413
+ if (timer) {
13414
+ clearTimeout(timer);
13415
+ }
13416
+ });
13417
+ }
13276
13418
  function sessionKey2(options) {
13277
13419
  return `${options.agentName}:${options.sessionId}`;
13278
13420
  }
@@ -13375,23 +13517,86 @@ async function readOptionalFile2(filePath) {
13375
13517
  return null;
13376
13518
  }
13377
13519
  }
13520
+ var SESSION_CATALOG_FILENAME2 = "session-catalog.json";
13521
+ var SESSION_CATALOG_MAX_ENTRIES2 = 64;
13522
+ async function readCodexSessionCatalog(runtimeDirectory) {
13523
+ const raw = await readOptionalFile2(join13(runtimeDirectory, SESSION_CATALOG_FILENAME2));
13524
+ if (!raw) {
13525
+ return { activeSessionId: null, sessions: [] };
13526
+ }
13527
+ const parsed = parseCodexMaybeJson(raw);
13528
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
13529
+ return { activeSessionId: null, sessions: [] };
13530
+ }
13531
+ return {
13532
+ activeSessionId: typeof parsed.activeSessionId === "string" ? parsed.activeSessionId : null,
13533
+ sessions: Array.isArray(parsed.sessions) ? parsed.sessions.filter((entry) => Boolean(entry) && typeof entry === "object" && typeof entry.id === "string" && typeof entry.startedAt === "number" && typeof entry.cwd === "string") : []
13534
+ };
13535
+ }
13536
+ async function writeCodexSessionCatalog(runtimeDirectory, catalog) {
13537
+ await mkdir5(runtimeDirectory, { recursive: true });
13538
+ await writeFile5(join13(runtimeDirectory, SESSION_CATALOG_FILENAME2), JSON.stringify(catalog, null, 2) + `
13539
+ `);
13540
+ }
13541
+ async function recordCodexSessionCatalog(runtimeDirectory, threadId, input) {
13542
+ const catalog = await readCodexSessionCatalog(runtimeDirectory);
13543
+ const now = Date.now();
13544
+ const sessions2 = catalog.sessions.map((session) => session.id === catalog.activeSessionId && session.id !== threadId && !session.endedAt ? { ...session, endedAt: now } : session);
13545
+ if (!sessions2.some((session) => session.id === threadId)) {
13546
+ sessions2.push({
13547
+ id: threadId,
13548
+ startedAt: now,
13549
+ cwd: input.cwd,
13550
+ harness: input.harness,
13551
+ transport: input.transport,
13552
+ model: input.model,
13553
+ approvalPolicy: input.approvalPolicy,
13554
+ sandbox: input.sandbox
13555
+ });
13556
+ }
13557
+ while (sessions2.length > SESSION_CATALOG_MAX_ENTRIES2) {
13558
+ sessions2.shift();
13559
+ }
13560
+ await writeCodexSessionCatalog(runtimeDirectory, {
13561
+ activeSessionId: threadId,
13562
+ sessions: sessions2
13563
+ });
13564
+ }
13565
+ async function closeCodexSessionCatalog(runtimeDirectory, threadId) {
13566
+ const catalog = await readCodexSessionCatalog(runtimeDirectory);
13567
+ const now = Date.now();
13568
+ const activeSessionId = threadId ?? catalog.activeSessionId;
13569
+ const sessions2 = catalog.sessions.map((session) => session.id === activeSessionId && !session.endedAt ? { ...session, endedAt: now } : session);
13570
+ await writeCodexSessionCatalog(runtimeDirectory, {
13571
+ activeSessionId: null,
13572
+ sessions: sessions2
13573
+ });
13574
+ }
13575
+ function parseCodexMaybeJson(value) {
13576
+ if (typeof value !== "string") {
13577
+ return value;
13578
+ }
13579
+ const trimmed = value.trim();
13580
+ if (!trimmed) {
13581
+ return value;
13582
+ }
13583
+ try {
13584
+ return JSON.parse(trimmed);
13585
+ } catch {
13586
+ return value;
13587
+ }
13588
+ }
13378
13589
  function isMissingCodexRolloutError2(error) {
13379
13590
  const message = errorMessage3(error).toLowerCase();
13380
13591
  return message.includes("no rollout found for thread id");
13381
13592
  }
13382
- function resolveCodexCompletionGraceMs() {
13383
- const parsed = Number.parseInt(process.env.OPENSCOUT_CODEX_COMPLETION_GRACE_MS ?? "", 10);
13384
- if (Number.isFinite(parsed) && parsed >= 0) {
13385
- return parsed;
13386
- }
13387
- return 60000;
13388
- }
13389
13593
 
13390
13594
  class CodexAppServerSession {
13391
13595
  options;
13392
13596
  key;
13393
13597
  threadIdPath;
13394
13598
  statePath;
13599
+ replyContextPath;
13395
13600
  stdoutLogPath;
13396
13601
  stderrLogPath;
13397
13602
  process = null;
@@ -13409,6 +13614,7 @@ class CodexAppServerSession {
13409
13614
  this.key = sessionKey2(options);
13410
13615
  this.threadIdPath = join13(options.runtimeDirectory, "codex-thread-id.txt");
13411
13616
  this.statePath = join13(options.runtimeDirectory, "state.json");
13617
+ this.replyContextPath = join13(options.runtimeDirectory, "scout-reply-context.json");
13412
13618
  this.stdoutLogPath = join13(options.logsDirectory, "stdout.log");
13413
13619
  this.stderrLogPath = join13(options.logsDirectory, "stderr.log");
13414
13620
  this.lastConfigSignature = this.configSignature(options);
@@ -13432,15 +13638,16 @@ class CodexAppServerSession {
13432
13638
  threadId: this.threadId
13433
13639
  };
13434
13640
  }
13435
- async invoke(prompt, timeoutMs = 5 * 60000) {
13641
+ async invoke(prompt, timeoutMs, replyContext) {
13436
13642
  return this.enqueue(async () => {
13437
13643
  await this.ensureStarted();
13438
13644
  if (!this.threadId) {
13439
13645
  throw new Error(`Codex app-server session for ${this.options.agentName} has no active thread.`);
13440
13646
  }
13441
- const output = await new Promise(async (resolve4, reject) => {
13442
- const turn = this.createActiveTurn(resolve4, reject, timeoutMs);
13647
+ const outputPromise = new Promise(async (resolve4, reject) => {
13648
+ const turn = this.createActiveTurn(resolve4, reject);
13443
13649
  try {
13650
+ await this.writeReplyContext(replyContext ?? null);
13444
13651
  const response = await this.request("turn/start", {
13445
13652
  threadId: this.threadId,
13446
13653
  cwd: this.options.cwd,
@@ -13455,10 +13662,12 @@ class CodexAppServerSession {
13455
13662
  turn.turnId = response.turn.id;
13456
13663
  await this.persistState();
13457
13664
  } catch (error) {
13665
+ await this.clearReplyContext();
13458
13666
  this.clearActiveTurn(turn);
13459
13667
  reject(error instanceof Error ? error : new Error(errorMessage3(error)));
13460
13668
  }
13461
13669
  });
13670
+ const output = await waitForRequesterResult2(outputPromise, timeoutMs, this.options.agentName);
13462
13671
  return {
13463
13672
  output,
13464
13673
  threadId: this.threadId
@@ -13468,7 +13677,7 @@ class CodexAppServerSession {
13468
13677
  hasActiveTurn() {
13469
13678
  return Boolean(this.activeTurn);
13470
13679
  }
13471
- async steerAndWait(prompt, timeoutMs = 5 * 60000) {
13680
+ async steerAndWait(prompt, timeoutMs) {
13472
13681
  await this.ensureStarted();
13473
13682
  if (!this.threadId) {
13474
13683
  throw new Error(`Codex app-server session for ${this.options.agentName} has no active thread.`);
@@ -13532,9 +13741,6 @@ class CodexAppServerSession {
13532
13741
  const activeTurn = this.activeTurn;
13533
13742
  this.activeTurn = null;
13534
13743
  if (activeTurn) {
13535
- if (activeTurn.timer) {
13536
- clearTimeout(activeTurn.timer);
13537
- }
13538
13744
  activeTurn.reject(new Error(`Codex app-server session for ${this.options.agentName} was shut down.`));
13539
13745
  }
13540
13746
  for (const pending of this.pendingRequests.values()) {
@@ -13553,6 +13759,7 @@ class CodexAppServerSession {
13553
13759
  }
13554
13760
  }
13555
13761
  if (options.resetThread) {
13762
+ await closeCodexSessionCatalog(this.options.runtimeDirectory, this.threadId);
13556
13763
  this.threadId = null;
13557
13764
  this.threadPath = null;
13558
13765
  await rm4(this.threadIdPath, { force: true });
@@ -13573,6 +13780,8 @@ class CodexAppServerSession {
13573
13780
  cwd: options.cwd,
13574
13781
  sessionId: options.sessionId,
13575
13782
  systemPrompt: options.systemPrompt,
13783
+ approvalPolicy: options.approvalPolicy ?? "never",
13784
+ sandbox: options.sandbox ?? "danger-full-access",
13576
13785
  threadId: options.threadId ?? null,
13577
13786
  requireExistingThread: options.requireExistingThread === true,
13578
13787
  launchArgs: normalizeCodexAppServerLaunchArgs(options.launchArgs)
@@ -13603,6 +13812,7 @@ class CodexAppServerSession {
13603
13812
  currentDirectory: this.options.cwd,
13604
13813
  baseEnv: process.env
13605
13814
  });
13815
+ env.OPENSCOUT_REPLY_CONTEXT_FILE = this.replyContextPath;
13606
13816
  const child = spawn3(codexExecutable, [
13607
13817
  "app-server",
13608
13818
  ...buildScoutMcpCodexLaunchArgs({
@@ -13658,14 +13868,15 @@ class CodexAppServerSession {
13658
13868
  const resumed = await this.request("thread/resume", {
13659
13869
  threadId: storedThreadId,
13660
13870
  cwd: this.options.cwd,
13661
- approvalPolicy: "never",
13662
- sandbox: "danger-full-access",
13871
+ approvalPolicy: this.options.approvalPolicy ?? "never",
13872
+ sandbox: this.options.sandbox ?? "danger-full-access",
13663
13873
  baseInstructions: this.options.systemPrompt,
13664
13874
  persistExtendedHistory: true
13665
13875
  });
13666
13876
  this.threadId = resumed.thread.id;
13667
13877
  this.threadPath = resumed.thread.path ?? null;
13668
13878
  await this.persistThreadId();
13879
+ await recordCodexSessionCatalog(this.options.runtimeDirectory, this.threadId, this.catalogRuntimeMeta());
13669
13880
  return;
13670
13881
  } catch (error) {
13671
13882
  await appendFile3(this.stderrLogPath, `[openscout] failed to resume stored Codex thread ${storedThreadId}: ${errorMessage3(error)}
@@ -13688,8 +13899,8 @@ class CodexAppServerSession {
13688
13899
  }
13689
13900
  const started = await this.request("thread/start", {
13690
13901
  cwd: this.options.cwd,
13691
- approvalPolicy: "never",
13692
- sandbox: "danger-full-access",
13902
+ approvalPolicy: this.options.approvalPolicy ?? "never",
13903
+ sandbox: this.options.sandbox ?? "danger-full-access",
13693
13904
  baseInstructions: this.options.systemPrompt,
13694
13905
  ephemeral: false,
13695
13906
  experimentalRawEvents: false,
@@ -13698,71 +13909,47 @@ class CodexAppServerSession {
13698
13909
  this.threadId = started.thread.id;
13699
13910
  this.threadPath = started.thread.path ?? null;
13700
13911
  await this.persistThreadId();
13912
+ await recordCodexSessionCatalog(this.options.runtimeDirectory, this.threadId, this.catalogRuntimeMeta());
13701
13913
  }
13702
- createActiveTurn(resolve4, reject, timeoutMs) {
13914
+ catalogRuntimeMeta() {
13915
+ return {
13916
+ cwd: this.options.cwd,
13917
+ harness: "codex",
13918
+ transport: "codex_app_server",
13919
+ model: readCodexAppServerModelFromLaunchArgs(this.options.launchArgs),
13920
+ approvalPolicy: this.options.approvalPolicy ?? "never",
13921
+ sandbox: this.options.sandbox ?? "danger-full-access"
13922
+ };
13923
+ }
13924
+ createActiveTurn(resolve4, reject) {
13703
13925
  if (this.activeTurn) {
13704
13926
  throw new Error(`Codex app-server session for ${this.options.agentName} already has an active turn.`);
13705
13927
  }
13706
13928
  const turn = {
13707
13929
  turnId: "",
13708
13930
  startedAt: Date.now(),
13709
- timer: null,
13710
- graceTimer: null,
13711
- timedOutAt: null,
13712
13931
  messageOrder: [],
13713
13932
  messageByItemId: new Map,
13714
13933
  resolve: resolve4,
13715
13934
  reject,
13716
13935
  watchers: []
13717
13936
  };
13718
- turn.timer = setTimeout(() => {
13719
- this.scheduleTurnTimeout(turn, timeoutMs);
13720
- }, timeoutMs);
13721
13937
  this.activeTurn = turn;
13722
13938
  return turn;
13723
13939
  }
13724
- buildTurnTimeoutError(timeoutMs) {
13725
- return new Error(`Timed out after ${timeoutMs}ms waiting for ${this.options.agentName}.`);
13726
- }
13727
- scheduleTurnTimeout(turn, timeoutMs) {
13728
- if (turn.timedOutAt !== null) {
13729
- return;
13730
- }
13731
- turn.timedOutAt = Date.now();
13732
- this.interrupt().catch(() => {
13733
- return;
13734
- });
13735
- const graceMs = resolveCodexCompletionGraceMs();
13736
- if (graceMs <= 0) {
13737
- this.rejectTimedOutTurn(turn, timeoutMs);
13738
- return;
13739
- }
13740
- turn.graceTimer = setTimeout(() => {
13741
- this.rejectTimedOutTurn(turn, timeoutMs);
13742
- }, graceMs);
13743
- }
13744
- rejectTimedOutTurn(turn, timeoutMs) {
13745
- if (this.activeTurn !== turn) {
13746
- this.clearActiveTurn(turn);
13747
- return;
13748
- }
13749
- this.clearActiveTurn(turn);
13750
- const error = this.buildTurnTimeoutError(timeoutMs);
13751
- for (const watcher of this.drainTurnWatchers(turn)) {
13752
- watcher.reject(error);
13753
- }
13754
- turn.reject(error);
13755
- }
13756
13940
  addTurnWatcher(turn, resolve4, reject, timeoutMs) {
13757
13941
  const watcher = {
13758
13942
  resolve: resolve4,
13759
13943
  reject,
13760
13944
  timer: null
13761
13945
  };
13762
- watcher.timer = setTimeout(() => {
13763
- this.removeTurnWatcher(turn, watcher);
13764
- reject(new Error(`Timed out after ${timeoutMs}ms waiting for ${this.options.agentName}.`));
13765
- }, timeoutMs);
13946
+ const effectiveTimeoutMs = resolveRequesterTimeoutMs2(timeoutMs);
13947
+ if (effectiveTimeoutMs !== null) {
13948
+ watcher.timer = setTimeout(() => {
13949
+ this.removeTurnWatcher(turn, watcher);
13950
+ reject(new Error(`Timed out after ${effectiveTimeoutMs}ms waiting for ${this.options.agentName}.`));
13951
+ }, effectiveTimeoutMs);
13952
+ }
13766
13953
  turn.watchers.push(watcher);
13767
13954
  return watcher;
13768
13955
  }
@@ -13783,12 +13970,6 @@ class CodexAppServerSession {
13783
13970
  return watchers;
13784
13971
  }
13785
13972
  clearActiveTurn(turn) {
13786
- if (turn.timer) {
13787
- clearTimeout(turn.timer);
13788
- }
13789
- if (turn.graceTimer) {
13790
- clearTimeout(turn.graceTimer);
13791
- }
13792
13973
  if (this.activeTurn === turn) {
13793
13974
  this.activeTurn = null;
13794
13975
  }
@@ -13845,6 +14026,20 @@ class CodexAppServerSession {
13845
14026
  error: buildUnsupportedServerRequestError2(message)
13846
14027
  });
13847
14028
  }
14029
+ async writeReplyContext(context) {
14030
+ if (!context) {
14031
+ await this.clearReplyContext();
14032
+ return;
14033
+ }
14034
+ await mkdir5(this.options.runtimeDirectory, { recursive: true });
14035
+ await writeFile5(this.replyContextPath, `${JSON.stringify(context, null, 2)}
14036
+ `, "utf8");
14037
+ }
14038
+ async clearReplyContext() {
14039
+ await rm4(this.replyContextPath, { force: true }).catch(() => {
14040
+ return;
14041
+ });
14042
+ }
13848
14043
  handleNotification(message) {
13849
14044
  const method = message.method;
13850
14045
  const params = message.params ?? {};
@@ -13899,6 +14094,7 @@ class CodexAppServerSession {
13899
14094
  return;
13900
14095
  }
13901
14096
  if (method === "turn/completed") {
14097
+ this.clearReplyContext();
13902
14098
  this.completeTurn(params);
13903
14099
  return;
13904
14100
  }
@@ -13970,9 +14166,6 @@ class CodexAppServerSession {
13970
14166
  const activeTurn = this.activeTurn;
13971
14167
  this.activeTurn = null;
13972
14168
  if (activeTurn) {
13973
- if (activeTurn.timer) {
13974
- clearTimeout(activeTurn.timer);
13975
- }
13976
14169
  for (const watcher of this.drainTurnWatchers(activeTurn)) {
13977
14170
  watcher.reject(error);
13978
14171
  }
@@ -14076,6 +14269,8 @@ async function shutdownCodexAppServerAgent(options, shutdownOptions = {}) {
14076
14269
  if (!session) {
14077
14270
  if (shutdownOptions.resetThread) {
14078
14271
  const runtimeDirectory = options.runtimeDirectory;
14272
+ const threadId = await readOptionalFile2(join13(runtimeDirectory, "codex-thread-id.txt"));
14273
+ await closeCodexSessionCatalog(runtimeDirectory, threadId);
14079
14274
  await rm4(join13(runtimeDirectory, "codex-thread-id.txt"), { force: true });
14080
14275
  }
14081
14276
  return;
@@ -14627,12 +14822,15 @@ function runtimePackageDir() {
14627
14822
  const explicit = process.env.OPENSCOUT_RUNTIME_PACKAGE_DIR?.trim();
14628
14823
  if (explicit)
14629
14824
  return explicit;
14630
- const fromGlobal = findGlobalRuntimeDir();
14631
- if (fromGlobal)
14632
- return fromGlobal;
14825
+ const fromBundledPackage = findBundledRuntimeDir();
14826
+ if (fromBundledPackage)
14827
+ return fromBundledPackage;
14633
14828
  const fromCwd = findWorkspaceRuntimeDir(process.cwd());
14634
14829
  if (fromCwd)
14635
14830
  return fromCwd;
14831
+ const fromGlobal = findGlobalRuntimeDir();
14832
+ if (fromGlobal)
14833
+ return fromGlobal;
14636
14834
  const moduleDir = dirname6(fileURLToPath4(import.meta.url));
14637
14835
  return resolve5(moduleDir, "..");
14638
14836
  }
@@ -14654,6 +14852,8 @@ function findGlobalRuntimeDir() {
14654
14852
  const scoutBin = result.stdout?.trim();
14655
14853
  if (scoutBin) {
14656
14854
  const scoutPkg = resolve5(scoutBin, "..", "..");
14855
+ if (isInstalledRuntimePackageDir(scoutPkg))
14856
+ return scoutPkg;
14657
14857
  const nested = join15(scoutPkg, "node_modules", "@openscout", "runtime");
14658
14858
  if (isInstalledRuntimePackageDir(nested))
14659
14859
  return nested;
@@ -14664,6 +14864,11 @@ function findGlobalRuntimeDir() {
14664
14864
  } catch {}
14665
14865
  return null;
14666
14866
  }
14867
+ function findBundledRuntimeDir() {
14868
+ const moduleDir = dirname6(fileURLToPath4(import.meta.url));
14869
+ const candidate = resolve5(moduleDir, "..");
14870
+ return isInstalledRuntimePackageDir(candidate) ? candidate : null;
14871
+ }
14667
14872
  function findWorkspaceRuntimeDir(startDir) {
14668
14873
  let current = resolve5(startDir);
14669
14874
  while (true) {
@@ -14702,10 +14907,21 @@ function resolveBrokerStartTimeoutMs() {
14702
14907
  return DEFAULT_BROKER_START_TIMEOUT_MS;
14703
14908
  }
14704
14909
  function resolveBrokerServiceLabel(mode) {
14705
- const explicit = process.env.OPENSCOUT_BROKER_SERVICE_LABEL?.trim();
14910
+ const explicit = process.env.OPENSCOUT_SERVICE_LABEL?.trim() || process.env.OPENSCOUT_BROKER_SERVICE_LABEL?.trim();
14706
14911
  if (explicit) {
14707
14912
  return explicit;
14708
14913
  }
14914
+ switch (mode) {
14915
+ case "prod":
14916
+ return "com.openscout";
14917
+ case "custom":
14918
+ return "com.openscout.custom";
14919
+ case "dev":
14920
+ default:
14921
+ return "dev.openscout";
14922
+ }
14923
+ }
14924
+ function legacyBrokerServiceLabel(mode) {
14709
14925
  switch (mode) {
14710
14926
  case "prod":
14711
14927
  return "com.openscout.broker";
@@ -14764,6 +14980,7 @@ function renderLaunchAgentPlist(config) {
14764
14980
  OPENSCOUT_CONTROL_HOME: config.controlHome,
14765
14981
  OPENSCOUT_BROKER_SERVICE_MODE: config.mode,
14766
14982
  OPENSCOUT_BROKER_SERVICE_LABEL: config.label,
14983
+ OPENSCOUT_SERVICE_LABEL: config.label,
14767
14984
  OPENSCOUT_ADVERTISE_SCOPE: config.advertiseScope,
14768
14985
  HOME: homedir14(),
14769
14986
  PATH: launchPath,
@@ -14792,7 +15009,7 @@ function renderLaunchAgentPlist(config) {
14792
15009
  <array>
14793
15010
  <string>${xmlEscape(config.bunExecutable)}</string>
14794
15011
  <string>${xmlEscape(join15(config.runtimePackageDir, "bin", "openscout-runtime.mjs"))}</string>
14795
- <string>broker</string>
15012
+ <string>base</string>
14796
15013
  </array>
14797
15014
  <key>WorkingDirectory</key>
14798
15015
  <string>${xmlEscape(config.runtimePackageDir)}</string>
@@ -14856,6 +15073,22 @@ function writeLaunchAgentPlist(config) {
14856
15073
  ensureServiceDirectories(config);
14857
15074
  writeFileSync5(config.launchAgentPath, renderLaunchAgentPlist(config), "utf8");
14858
15075
  }
15076
+ function bootoutCommand(config) {
15077
+ return `${launchctlPath()} bootout ${config.serviceTarget}`;
15078
+ }
15079
+ function legacyLaunchAgentPath(config) {
15080
+ return join15(homedir14(), "Library", "LaunchAgents", `${legacyBrokerServiceLabel(config.mode)}.plist`);
15081
+ }
15082
+ function legacyServiceTarget(config) {
15083
+ return `${config.domainTarget}/${legacyBrokerServiceLabel(config.mode)}`;
15084
+ }
15085
+ function bootoutLegacyBrokerService(config) {
15086
+ const legacyTarget = legacyServiceTarget(config);
15087
+ if (legacyTarget === config.serviceTarget) {
15088
+ return;
15089
+ }
15090
+ runCommand(launchctlPath(), ["bootout", legacyTarget], { allowFailure: true });
15091
+ }
14859
15092
  function runCommand(command, args, options) {
14860
15093
  const result = spawnSync(command, args, {
14861
15094
  env: {
@@ -14974,6 +15207,7 @@ async function brokerServiceStatus(config = resolveBrokerServiceConfig()) {
14974
15207
  label: config.label,
14975
15208
  mode: config.mode,
14976
15209
  launchAgentPath: config.launchAgentPath,
15210
+ bootoutCommand: bootoutCommand(config),
14977
15211
  brokerUrl: config.brokerUrl,
14978
15212
  brokerSocketPath: config.brokerSocketPath,
14979
15213
  supportDirectory: config.supportDirectory,
@@ -14993,10 +15227,12 @@ async function brokerServiceStatus(config = resolveBrokerServiceConfig()) {
14993
15227
  };
14994
15228
  }
14995
15229
  async function installBrokerService(config = resolveBrokerServiceConfig()) {
15230
+ bootoutLegacyBrokerService(config);
14996
15231
  writeLaunchAgentPlist(config);
14997
15232
  return brokerServiceStatus(config);
14998
15233
  }
14999
15234
  async function startBrokerService(config = resolveBrokerServiceConfig()) {
15235
+ bootoutLegacyBrokerService(config);
15000
15236
  writeLaunchAgentPlist(config);
15001
15237
  runCommand(launchctlPath(), ["bootout", config.serviceTarget], { allowFailure: true });
15002
15238
  runCommand(launchctlPath(), ["bootstrap", config.domainTarget, config.launchAgentPath], { allowFailure: true });
@@ -15035,6 +15271,11 @@ async function uninstallBrokerService(config = resolveBrokerServiceConfig()) {
15035
15271
  if (existsSync13(config.launchAgentPath)) {
15036
15272
  rmSync2(config.launchAgentPath, { force: true });
15037
15273
  }
15274
+ const legacyPath = legacyLaunchAgentPath(config);
15275
+ bootoutLegacyBrokerService(config);
15276
+ if (existsSync13(legacyPath)) {
15277
+ rmSync2(legacyPath, { force: true });
15278
+ }
15038
15279
  return brokerServiceStatus(config);
15039
15280
  }
15040
15281
  async function main() {
@@ -15076,6 +15317,7 @@ function formatBrokerServiceStatus(status) {
15076
15317
  `label: ${status.label}`,
15077
15318
  `mode: ${status.mode}`,
15078
15319
  `launch agent: ${status.installed ? status.launchAgentPath : "not installed"}`,
15320
+ `bootout: ${status.bootoutCommand}`,
15079
15321
  `loaded: ${status.loaded ? "yes" : "no"}`,
15080
15322
  `pid: ${status.pid ?? "\u2014"}`,
15081
15323
  `launchd state: ${status.launchdState ?? "\u2014"}`,
@@ -15105,6 +15347,58 @@ var LOCAL_AGENT_SYSTEM_PROMPT_TEMPLATE_HINT = [
15105
15347
  "{{relay_hub}}, {{broker_url}}, {{relay_command}}, {{openscout_root}}, {{relay_agent_comms_skill}}, and {{env.NAME}} variables."
15106
15348
  ].join("");
15107
15349
 
15350
+ // ../runtime/src/permission-policy.ts
15351
+ function parseScoutPermissionProfile(value) {
15352
+ const profile = normalizeScoutPermissionProfile(value);
15353
+ if (value && !profile) {
15354
+ throw new Error(`Unknown permission profile "${value}". Expected one of: ${formatScoutPermissionProfiles()}.`);
15355
+ }
15356
+ return profile;
15357
+ }
15358
+ function compileCodexPermissionProfile(profileInput) {
15359
+ const profile = profileInput ? parseScoutPermissionProfile(profileInput) ?? "trusted_local" : "trusted_local";
15360
+ switch (profile) {
15361
+ case "observe":
15362
+ case "review":
15363
+ return {
15364
+ profile,
15365
+ sandbox: "read-only",
15366
+ approvalPolicy: "on-request",
15367
+ enforcement: "native"
15368
+ };
15369
+ case "workspace_write":
15370
+ return {
15371
+ profile,
15372
+ sandbox: "workspace-write",
15373
+ approvalPolicy: "on-request",
15374
+ enforcement: "native"
15375
+ };
15376
+ case "sandboxed_write":
15377
+ return {
15378
+ profile,
15379
+ sandbox: "workspace-write",
15380
+ approvalPolicy: "on-request",
15381
+ enforcement: "advisory",
15382
+ note: "External sandbox placement is not wired yet; Codex receives its native workspace-write sandbox."
15383
+ };
15384
+ case "external_sandbox":
15385
+ return {
15386
+ profile,
15387
+ sandbox: "workspace-write",
15388
+ approvalPolicy: "on-request",
15389
+ enforcement: "advisory",
15390
+ note: "External sandbox placement is not wired yet; Codex receives its native workspace-write sandbox."
15391
+ };
15392
+ case "trusted_local":
15393
+ return {
15394
+ profile,
15395
+ sandbox: "danger-full-access",
15396
+ approvalPolicy: "never",
15397
+ enforcement: "native"
15398
+ };
15399
+ }
15400
+ }
15401
+
15108
15402
  // ../runtime/src/local-agents.ts
15109
15403
  var MODULE_DIRECTORY = dirname7(fileURLToPath5(import.meta.url));
15110
15404
  var OPENSCOUT_REPO_ROOT = resolve6(MODULE_DIRECTORY, "..", "..", "..");
@@ -15554,6 +15848,46 @@ function buildLaunchArgsForRequestedModel(harness, model) {
15554
15848
  }
15555
15849
  return [];
15556
15850
  }
15851
+ function normalizeRequestedReasoningEffort(reasoningEffort) {
15852
+ const trimmed = reasoningEffort?.trim();
15853
+ return trimmed ? trimmed : undefined;
15854
+ }
15855
+ function stripLaunchReasoningEffortForHarness(harness, launchArgs) {
15856
+ if (harness !== "codex") {
15857
+ return normalizeLaunchArgsForHarness(harness, launchArgs);
15858
+ }
15859
+ const next = [];
15860
+ const normalized = normalizeCodexAppServerLaunchArgs(launchArgs);
15861
+ for (let index = 0;index < normalized.length; index += 1) {
15862
+ const current = normalized[index] ?? "";
15863
+ if (current === "-c" || current === "--config") {
15864
+ const value = normalized[index + 1];
15865
+ if (readCodexAppServerReasoningEffortFromLaunchArgs(value ? [current, value] : [current])) {
15866
+ index += 1;
15867
+ continue;
15868
+ }
15869
+ next.push(current);
15870
+ if (value) {
15871
+ next.push(value);
15872
+ index += 1;
15873
+ }
15874
+ continue;
15875
+ }
15876
+ if (current.startsWith("--config=")) {
15877
+ if (readCodexAppServerReasoningEffortFromLaunchArgs([current])) {
15878
+ continue;
15879
+ }
15880
+ }
15881
+ next.push(current);
15882
+ }
15883
+ return next;
15884
+ }
15885
+ function buildLaunchArgsForRequestedReasoningEffort(harness, reasoningEffort) {
15886
+ if (harness === "codex") {
15887
+ return normalizeCodexAppServerLaunchArgs(["--reasoning-effort", reasoningEffort]);
15888
+ }
15889
+ return [];
15890
+ }
15557
15891
  function applyRequestedModelToLaunchArgs(harness, launchArgs, model) {
15558
15892
  const normalized = normalizeLaunchArgsForHarness(harness, launchArgs);
15559
15893
  const requestedModel = normalizeRequestedModel(model);
@@ -15565,6 +15899,17 @@ function applyRequestedModelToLaunchArgs(harness, launchArgs, model) {
15565
15899
  ...buildLaunchArgsForRequestedModel(harness, requestedModel)
15566
15900
  ];
15567
15901
  }
15902
+ function applyRequestedRuntimeOptionsToLaunchArgs(harness, launchArgs, options) {
15903
+ const withModel = applyRequestedModelToLaunchArgs(harness, launchArgs, options.model);
15904
+ const requestedReasoningEffort = normalizeRequestedReasoningEffort(options.reasoningEffort);
15905
+ if (!requestedReasoningEffort) {
15906
+ return withModel;
15907
+ }
15908
+ return [
15909
+ ...stripLaunchReasoningEffortForHarness(harness, withModel),
15910
+ ...buildLaunchArgsForRequestedReasoningEffort(harness, requestedReasoningEffort)
15911
+ ];
15912
+ }
15568
15913
  function defaultHarnessForOverride(override, fallback = "claude") {
15569
15914
  return normalizeManagedHarness2(override.defaultHarness ?? override.runtime?.harness, fallback);
15570
15915
  }
@@ -15584,16 +15929,17 @@ function overrideHarnessProfile(override, harness) {
15584
15929
  cwd: normalizeProjectPath(profile?.cwd || override.runtime?.cwd || override.projectRoot || process.cwd()),
15585
15930
  transport: normalizeLocalAgentTransport(profile?.transport ?? override.runtime?.transport, harness),
15586
15931
  sessionId: normalizeTmuxSessionName2(profile?.sessionId, `${override.agentId}-${harness}`),
15587
- launchArgs: launchArgsForOverrideHarness(override, harness)
15932
+ launchArgs: launchArgsForOverrideHarness(override, harness),
15933
+ ...profile?.permissionProfile ? { permissionProfile: profile.permissionProfile } : {}
15588
15934
  };
15589
15935
  }
15590
15936
  function normalizeManagedHarness2(value, fallback) {
15591
- return value === "codex" ? "codex" : value === "claude" ? "claude" : fallback;
15937
+ return value === "codex" ? "codex" : value === "claude" ? "claude" : value === "cursor" ? "cursor" : fallback;
15592
15938
  }
15593
15939
  function normalizeLocalHarnessProfiles(agentId, record) {
15594
15940
  const defaultHarness = normalizeManagedHarness2(typeof record.defaultHarness === "string" ? record.defaultHarness : record.harness, "claude");
15595
15941
  const nextProfiles = {};
15596
- for (const harness of ["claude", "codex"]) {
15942
+ for (const harness of ["claude", "codex", "cursor"]) {
15597
15943
  const profile = record.harnessProfiles?.[harness];
15598
15944
  if (!profile) {
15599
15945
  continue;
@@ -15602,7 +15948,8 @@ function normalizeLocalHarnessProfiles(agentId, record) {
15602
15948
  cwd: normalizeProjectPath(profile.cwd || record.cwd || process.cwd()),
15603
15949
  transport: normalizeLocalAgentTransport(profile.transport, harness),
15604
15950
  sessionId: normalizeTmuxSessionName2(profile.sessionId, `${agentId}-${harness}`),
15605
- launchArgs: normalizeLaunchArgsForHarness(harness, profile.launchArgs)
15951
+ launchArgs: normalizeLaunchArgsForHarness(harness, profile.launchArgs),
15952
+ ...profile.permissionProfile ? { permissionProfile: profile.permissionProfile } : {}
15606
15953
  };
15607
15954
  }
15608
15955
  const runtimeHarness = normalizeManagedHarness2(record.harness, defaultHarness);
@@ -15611,7 +15958,8 @@ function normalizeLocalHarnessProfiles(agentId, record) {
15611
15958
  cwd: normalizeProjectPath(record.cwd || process.cwd()),
15612
15959
  transport: normalizeLocalAgentTransport(record.transport, runtimeHarness),
15613
15960
  sessionId: normalizeTmuxSessionName2(record.tmuxSession, `${agentId}-${runtimeHarness}`),
15614
- launchArgs: normalizeLaunchArgsForHarness(runtimeHarness, record.launchArgs)
15961
+ launchArgs: normalizeLaunchArgsForHarness(runtimeHarness, record.launchArgs),
15962
+ ...record.permissionProfile ? { permissionProfile: record.permissionProfile } : {}
15615
15963
  };
15616
15964
  }
15617
15965
  if (!nextProfiles[defaultHarness]) {
@@ -15619,10 +15967,11 @@ function normalizeLocalHarnessProfiles(agentId, record) {
15619
15967
  cwd: normalizeProjectPath(record.cwd || process.cwd()),
15620
15968
  transport: normalizeLocalAgentTransport(record.transport, defaultHarness),
15621
15969
  sessionId: normalizeTmuxSessionName2(record.tmuxSession, `${agentId}-${defaultHarness}`),
15622
- launchArgs: normalizeLaunchArgsForHarness(defaultHarness, record.launchArgs)
15970
+ launchArgs: normalizeLaunchArgsForHarness(defaultHarness, record.launchArgs),
15971
+ ...record.permissionProfile ? { permissionProfile: record.permissionProfile } : {}
15623
15972
  };
15624
15973
  }
15625
- for (const harness of ["claude", "codex"]) {
15974
+ for (const harness of ["claude", "codex", "cursor"]) {
15626
15975
  const profile = nextProfiles[harness];
15627
15976
  if (!profile) {
15628
15977
  continue;
@@ -15631,7 +15980,8 @@ function normalizeLocalHarnessProfiles(agentId, record) {
15631
15980
  cwd: normalizeProjectPath(profile.cwd || record.cwd || process.cwd()),
15632
15981
  transport: normalizeLocalAgentTransport(profile.transport, harness),
15633
15982
  sessionId: normalizeTmuxSessionName2(profile.sessionId, `${agentId}-${harness}`),
15634
- launchArgs: normalizeLaunchArgsForHarness(harness, profile.launchArgs)
15983
+ launchArgs: normalizeLaunchArgsForHarness(harness, profile.launchArgs),
15984
+ ...profile.permissionProfile ? { permissionProfile: profile.permissionProfile } : {}
15635
15985
  };
15636
15986
  }
15637
15987
  return nextProfiles;
@@ -15656,13 +16006,15 @@ function recordForHarness(record, harnessOverride) {
15656
16006
  cwd: fallbackCwd,
15657
16007
  transport: fallbackTransport,
15658
16008
  launchArgs: normalizeLaunchArgsForHarness(selectedHarness, normalized.launchArgs),
16009
+ ...normalized.permissionProfile ? { permissionProfile: normalized.permissionProfile } : {},
15659
16010
  harnessProfiles: {
15660
16011
  ...normalized.harnessProfiles,
15661
16012
  [selectedHarness]: {
15662
16013
  cwd: fallbackCwd,
15663
16014
  transport: fallbackTransport,
15664
16015
  sessionId: fallbackSessionId,
15665
- launchArgs: normalizeLaunchArgsForHarness(selectedHarness, normalized.launchArgs)
16016
+ launchArgs: normalizeLaunchArgsForHarness(selectedHarness, normalized.launchArgs),
16017
+ ...normalized.permissionProfile ? { permissionProfile: normalized.permissionProfile } : {}
15666
16018
  }
15667
16019
  }
15668
16020
  };
@@ -15674,7 +16026,8 @@ function recordForHarness(record, harnessOverride) {
15674
16026
  tmuxSession: profile.sessionId,
15675
16027
  cwd: profile.cwd,
15676
16028
  transport: profile.transport,
15677
- launchArgs: profile.launchArgs
16029
+ launchArgs: profile.launchArgs,
16030
+ permissionProfile: profile.permissionProfile
15678
16031
  };
15679
16032
  }
15680
16033
  function normalizeLocalAgentRecord(agentId, record) {
@@ -15705,6 +16058,7 @@ function normalizeLocalAgentRecord(agentId, record) {
15705
16058
  transport: activeProfile?.transport ?? normalizeLocalAgentTransport(record.transport, harness),
15706
16059
  capabilities: normalizeLocalAgentCapabilities(record.capabilities),
15707
16060
  launchArgs: activeProfile?.launchArgs ?? normalizeLaunchArgsForHarness(harness, record.launchArgs),
16061
+ permissionProfile: activeProfile?.permissionProfile ?? record.permissionProfile,
15708
16062
  registrationSource: record.registrationSource
15709
16063
  };
15710
16064
  }
@@ -15790,6 +16144,7 @@ function relayAgentOverrideFromLocalAgentRecord(agentId, record, existing) {
15790
16144
  };
15791
16145
  }
15792
16146
  function buildCodexAgentSessionOptions(agentName, record, systemPrompt) {
16147
+ const permissionPosture = compileCodexPermissionProfile(record.permissionProfile);
15793
16148
  return {
15794
16149
  agentName,
15795
16150
  sessionId: record.tmuxSession,
@@ -15797,7 +16152,10 @@ function buildCodexAgentSessionOptions(agentName, record, systemPrompt) {
15797
16152
  systemPrompt: systemPrompt ?? buildLocalAgentSystemPrompt(agentName, record.project, record.cwd, { transport: "codex_app_server" }),
15798
16153
  runtimeDirectory: relayAgentRuntimeDirectory(agentName),
15799
16154
  logsDirectory: relayAgentLogsDirectory(agentName),
15800
- launchArgs: normalizeLaunchArgsForHarness("codex", record.launchArgs)
16155
+ launchArgs: normalizeLaunchArgsForHarness("codex", record.launchArgs),
16156
+ permissionProfile: permissionPosture.profile,
16157
+ approvalPolicy: permissionPosture.approvalPolicy,
16158
+ sandbox: permissionPosture.sandbox
15801
16159
  };
15802
16160
  }
15803
16161
  function buildClaudeAgentSessionOptions(agentName, record, systemPrompt) {
@@ -16054,6 +16412,7 @@ async function startLocalAgent(input) {
16054
16412
  const currentDirectory = input.currentDirectory ?? projectPath;
16055
16413
  const effectiveCwd = input.cwdOverride ? normalizeProjectPath(input.cwdOverride) : undefined;
16056
16414
  const shouldEnsureOnline = input.ensureOnline !== false;
16415
+ const requestedPermissionProfile = parseScoutPermissionProfile(input.permissionProfile);
16057
16416
  const requestedDefinitionId = input.agentName?.trim() ? normalizeAgentSelectorSegment(input.agentName.trim()) : "";
16058
16417
  if (input.agentName?.trim() && !requestedDefinitionId) {
16059
16418
  throw new Error(`Invalid agent name "${input.agentName}".`);
@@ -16109,7 +16468,10 @@ async function startLocalAgent(input) {
16109
16468
  const effectiveHarness = normalizeManagedHarness2(preferredHarness ?? configDefaultHarness, "claude");
16110
16469
  const transport = normalizeLocalAgentTransport(undefined, effectiveHarness);
16111
16470
  const sessionId = normalizeTmuxSessionName2(undefined, `${instance.id}-${effectiveHarness}`);
16112
- const launchArgs = applyRequestedModelToLaunchArgs(effectiveHarness, [], input.model);
16471
+ const launchArgs = applyRequestedRuntimeOptionsToLaunchArgs(effectiveHarness, [], {
16472
+ model: input.model,
16473
+ reasoningEffort: input.reasoningEffort
16474
+ });
16113
16475
  const existingForInstance = overrides[instance.id];
16114
16476
  if (existingForInstance && normalizeProjectPath(existingForInstance.projectRoot) !== projectRoot) {
16115
16477
  throw new Error(`Another agent is already registered as ${instance.id} at ${existingForInstance.projectRoot}. ` + `Two clones of the same project on the same branch cannot both register here; ` + `rename one of the checkouts or switch its branch before running scout up.`);
@@ -16130,7 +16492,8 @@ async function startLocalAgent(input) {
16130
16492
  cwd: effectiveCwd ?? projectRoot,
16131
16493
  transport,
16132
16494
  sessionId,
16133
- launchArgs
16495
+ launchArgs,
16496
+ ...requestedPermissionProfile ? { permissionProfile: requestedPermissionProfile } : {}
16134
16497
  }
16135
16498
  },
16136
16499
  runtime: {
@@ -16154,7 +16517,10 @@ async function startLocalAgent(input) {
16154
16517
  const nextHarness = normalizeManagedHarness2(resolvedHarness, "claude");
16155
16518
  const nextDefaultHarness = preferredHarness ? normalizeManagedHarness2(preferredHarness, "claude") : defaultHarnessForOverride(matchingOverride, "claude");
16156
16519
  const nextSessionId = normalizeTmuxSessionName2(undefined, `${instance.id}-${nextHarness}`);
16157
- const nextLaunchArgs = applyRequestedModelToLaunchArgs(nextHarness, launchArgsForOverrideHarness(matchingOverride, nextHarness), input.model);
16520
+ const nextLaunchArgs = applyRequestedRuntimeOptionsToLaunchArgs(nextHarness, launchArgsForOverrideHarness(matchingOverride, nextHarness), {
16521
+ model: input.model,
16522
+ reasoningEffort: input.reasoningEffort
16523
+ });
16158
16524
  overrides[instance.id] = {
16159
16525
  agentId: instance.id,
16160
16526
  definitionId: requestedDefinitionId,
@@ -16172,7 +16538,8 @@ async function startLocalAgent(input) {
16172
16538
  [nextHarness]: {
16173
16539
  ...overrideHarnessProfile(matchingOverride, nextHarness),
16174
16540
  sessionId: nextSessionId,
16175
- launchArgs: nextLaunchArgs
16541
+ launchArgs: nextLaunchArgs,
16542
+ ...requestedPermissionProfile ? { permissionProfile: requestedPermissionProfile } : {}
16176
16543
  }
16177
16544
  },
16178
16545
  runtime: {
@@ -16186,9 +16553,12 @@ async function startLocalAgent(input) {
16186
16553
  await writeRelayAgentOverrides(overrides);
16187
16554
  targetAgentId = instance.id;
16188
16555
  } else {
16189
- if (input.model) {
16556
+ if (input.model || input.reasoningEffort || requestedPermissionProfile) {
16190
16557
  const existingHarness = normalizeManagedHarness2(preferredHarness ?? matchingOverride.defaultHarness ?? matchingOverride.runtime?.harness, "claude");
16191
- const nextLaunchArgs = applyRequestedModelToLaunchArgs(existingHarness, launchArgsForOverrideHarness(matchingOverride, existingHarness), input.model);
16558
+ const nextLaunchArgs = applyRequestedRuntimeOptionsToLaunchArgs(existingHarness, launchArgsForOverrideHarness(matchingOverride, existingHarness), {
16559
+ model: input.model,
16560
+ reasoningEffort: input.reasoningEffort
16561
+ });
16192
16562
  overrides[matchingAgentId] = {
16193
16563
  ...matchingOverride,
16194
16564
  launchArgs: existingHarness === defaultHarnessForOverride(matchingOverride, existingHarness) ? nextLaunchArgs : matchingOverride.launchArgs,
@@ -16196,7 +16566,8 @@ async function startLocalAgent(input) {
16196
16566
  ...matchingOverride.harnessProfiles ?? {},
16197
16567
  [existingHarness]: {
16198
16568
  ...overrideHarnessProfile(matchingOverride, existingHarness),
16199
- launchArgs: nextLaunchArgs
16569
+ launchArgs: nextLaunchArgs,
16570
+ ...requestedPermissionProfile ? { permissionProfile: requestedPermissionProfile } : {}
16200
16571
  }
16201
16572
  }
16202
16573
  };
@@ -16300,6 +16671,7 @@ function readPersistedClaudeSessionId(agentName) {
16300
16671
  function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
16301
16672
  const normalizedRecord = normalizeLocalAgentRecord(agentId, record);
16302
16673
  const configuredModel = readLaunchModelForHarness(normalizeLocalAgentHarness(normalizedRecord.harness), normalizedRecord.launchArgs);
16674
+ const codexPermissionPosture = normalizeLocalAgentHarness(normalizedRecord.harness) === "codex" ? compileCodexPermissionProfile(normalizedRecord.permissionProfile) : null;
16303
16675
  const definitionId = normalizedRecord.definitionId ?? agentId;
16304
16676
  const displayName = titleCaseLocalAgentName(definitionId);
16305
16677
  const projectRoot = normalizedRecord.projectRoot ?? normalizedRecord.cwd;
@@ -16326,7 +16698,13 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
16326
16698
  nodeQualifier: instance.nodeQualifier,
16327
16699
  workspaceQualifier: instance.workspaceQualifier,
16328
16700
  branch: instance.branch,
16329
- ...configuredModel ? { model: configuredModel } : {}
16701
+ ...configuredModel ? { model: configuredModel } : {},
16702
+ ...codexPermissionPosture ? {
16703
+ permissionProfile: codexPermissionPosture.profile,
16704
+ approvalPolicy: codexPermissionPosture.approvalPolicy,
16705
+ sandbox: codexPermissionPosture.sandbox,
16706
+ permissionEnforcement: codexPermissionPosture.enforcement
16707
+ } : {}
16330
16708
  }
16331
16709
  },
16332
16710
  agent: {
@@ -16355,7 +16733,13 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
16355
16733
  nodeQualifier: instance.nodeQualifier,
16356
16734
  workspaceQualifier: instance.workspaceQualifier,
16357
16735
  branch: instance.branch,
16358
- ...configuredModel ? { model: configuredModel } : {}
16736
+ ...configuredModel ? { model: configuredModel } : {},
16737
+ ...codexPermissionPosture ? {
16738
+ permissionProfile: codexPermissionPosture.profile,
16739
+ approvalPolicy: codexPermissionPosture.approvalPolicy,
16740
+ sandbox: codexPermissionPosture.sandbox,
16741
+ permissionEnforcement: codexPermissionPosture.enforcement
16742
+ } : {}
16359
16743
  },
16360
16744
  agentClass: "general",
16361
16745
  capabilities: normalizeLocalAgentCapabilities(normalizedRecord.capabilities),
@@ -16390,6 +16774,12 @@ function buildLocalAgentBinding(agentId, record, alive, nodeId, source) {
16390
16774
  workspaceQualifier: instance.workspaceQualifier,
16391
16775
  branch: instance.branch,
16392
16776
  ...configuredModel ? { model: configuredModel } : {},
16777
+ ...codexPermissionPosture ? {
16778
+ permissionProfile: codexPermissionPosture.profile,
16779
+ approvalPolicy: codexPermissionPosture.approvalPolicy,
16780
+ sandbox: codexPermissionPosture.sandbox,
16781
+ permissionEnforcement: codexPermissionPosture.enforcement
16782
+ } : {},
16393
16783
  ...externalSessionId ? { externalSessionId } : {}
16394
16784
  }
16395
16785
  }
@@ -16488,7 +16878,11 @@ var scoutBrokerPaths = {
16488
16878
  deliver: "/v1/deliver",
16489
16879
  activity: "/v1/activity",
16490
16880
  collaborationRecords: "/v1/collaboration/records",
16491
- collaborationEvents: "/v1/collaboration/events"
16881
+ collaborationEvents: "/v1/collaboration/events",
16882
+ pairingAttach: "/v1/pairing/attach",
16883
+ pairingDetach: "/v1/pairing/detach",
16884
+ localSessionsAttach: "/v1/local-sessions/attach",
16885
+ localSessionsDetach: "/v1/local-sessions/detach"
16492
16886
  }
16493
16887
  };
16494
16888
 
@@ -16845,7 +17239,10 @@ async function sendScoutDirectMessage(input) {
16845
17239
  body: input.body.trim(),
16846
17240
  intent: "consult",
16847
17241
  replyToMessageId: input.replyToMessageId ?? undefined,
16848
- execution: input.executionHarness ? { harness: input.executionHarness } : undefined,
17242
+ execution: {
17243
+ ...input.executionHarness ? { harness: input.executionHarness } : {},
17244
+ session: "new"
17245
+ },
16849
17246
  ensureAwake: true,
16850
17247
  messageMetadata: {
16851
17248
  source,
@@ -36238,7 +36635,7 @@ function deleteMobilePushRegistrationByToken(pushToken) {
36238
36635
  writeDb().query(`DELETE FROM mobile_push_registrations WHERE push_token = ?1`).run(token);
36239
36636
  }
36240
36637
  function base64UrlEncode(input) {
36241
- const buffer = typeof input === "string" ? Buffer.from(input, "utf8") : input;
36638
+ const buffer = typeof input === "string" ? Buffer.from(input, "utf8") : Buffer.from(Array.from(input));
36242
36639
  return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
36243
36640
  }
36244
36641
  function loadApnsCredentials() {
@@ -36283,7 +36680,7 @@ function apnsJwt(credentials) {
36283
36680
  }));
36284
36681
  const unsignedToken = `${header}.${claims}`;
36285
36682
  const privateKey = createPrivateKey(credentials.privateKeyPem);
36286
- const signature = signWithKey("sha256", Buffer.from(unsignedToken), privateKey);
36683
+ const signature = signWithKey("sha256", new TextEncoder().encode(unsignedToken), privateKey);
36287
36684
  const token = `${unsignedToken}.${base64UrlEncode(signature)}`;
36288
36685
  cachedApnsJwt = {
36289
36686
  cacheKey,
@@ -36339,11 +36736,11 @@ async function sendApnsAlertToRegistration(registration, alert) {
36339
36736
  apnsId = typeof headers["apns-id"] === "string" ? headers["apns-id"] : null;
36340
36737
  });
36341
36738
  request.on("data", (chunk) => {
36342
- chunks.push(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk);
36739
+ chunks.push(chunk);
36343
36740
  });
36344
36741
  request.on("end", () => {
36345
36742
  client.close();
36346
- const rawBody = chunks.length > 0 ? Buffer.concat(chunks).toString("utf8") : "";
36743
+ const rawBody = chunks.join("");
36347
36744
  let reason = null;
36348
36745
  if (rawBody.trim().length > 0) {
36349
36746
  try {
@@ -40062,6 +40459,7 @@ async function startSupervisorRuntime(state) {
40062
40459
  relay: activeRelayUrl,
40063
40460
  pairing: {
40064
40461
  relay: payload.relay,
40462
+ ...payload.fallbackRelays?.length ? { fallbackRelays: payload.fallbackRelays } : {},
40065
40463
  room: payload.room,
40066
40464
  publicKey: payload.publicKey,
40067
40465
  expiresAt: payload.expiresAt,