@triflux/remote 10.41.1 → 10.43.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.
@@ -6,6 +6,11 @@ import { tmpdir } from "node:os";
6
6
  import { join as pathJoin } from "node:path";
7
7
 
8
8
  import { execute as defaultExecuteCodex } from "@triflux/core/hub/codex-adapter.mjs";
9
+ import {
10
+ createActivityLifecycle,
11
+ isActivityLifecycleEnabled,
12
+ resolveHardCeilingMs,
13
+ } from "@triflux/core/hub/lib/worker-lifecycle.mjs";
9
14
  import { JsonRpcWsUdsClient } from "../workers/lib/jsonrpc-ws-uds.mjs";
10
15
  import {
11
16
  buildClaudePromptDispatchPayload,
@@ -141,8 +146,11 @@ export async function runUdsOrchestration({ mode, task, claude, codex } = {}) {
141
146
  throw new Error(`Unsupported UDS orchestration mode: ${selectedMode}`);
142
147
  }
143
148
 
144
- function scanMessage(message, marker, state) {
149
+ function scanMessage(message, marker, state, onActivity = () => {}) {
145
150
  const scan = (text) => {
151
+ // Only stream/snapshot content advances liveness. "state" heartbeats do
152
+ // not keep an otherwise silent turn alive forever.
153
+ onActivity();
146
154
  state.streamBytes += Buffer.byteLength(text);
147
155
  state.stream.push(text);
148
156
  if (/⏺/.test(stripAnsi(text))) state.assistantStarted = true;
@@ -167,7 +175,10 @@ export function subscribeClaudeUntilMarker(
167
175
  controlSock,
168
176
  short,
169
177
  marker,
170
- { timeoutMs = DEFAULT_TIMEOUT_MS } = {},
178
+ {
179
+ timeoutMs = DEFAULT_TIMEOUT_MS,
180
+ maxTurnMs = Math.min(resolveHardCeilingMs(), 15 * 60_000),
181
+ } = {},
171
182
  ) {
172
183
  return new Promise((resolve) => {
173
184
  const socket = net.connect(controlSock);
@@ -185,7 +196,23 @@ export function subscribeClaudeUntilMarker(
185
196
  stream: [],
186
197
  assistantStarted: false,
187
198
  };
188
- const timer = setTimeout(() => finish({ timedOut: true }), timeoutMs);
199
+ const activityEnabled = isActivityLifecycleEnabled();
200
+ const lifecycle = createActivityLifecycle({
201
+ enabled: activityEnabled,
202
+ interventionMs: timeoutMs,
203
+ hardCeilingMs: maxTurnMs,
204
+ });
205
+ let timer = null;
206
+
207
+ const armTimer = () => {
208
+ timer = setTimeout(async () => {
209
+ if (!activityEnabled) return finish({ timedOut: true });
210
+ const reason = await lifecycle.check();
211
+ if (reason) return finish({ timedOut: true, timeoutReason: reason });
212
+ armTimer();
213
+ }, timeoutMs);
214
+ };
215
+ armTimer();
189
216
 
190
217
  function finish(extra = {}) {
191
218
  if (finished) return;
@@ -209,7 +236,9 @@ export function subscribeClaudeUntilMarker(
209
236
  data = data.slice(index + 1);
210
237
  if (!line) continue;
211
238
  try {
212
- scanMessage(JSON.parse(line), marker, state);
239
+ scanMessage(JSON.parse(line), marker, state, () =>
240
+ lifecycle.observe(),
241
+ );
213
242
  } catch (_error) {
214
243
  state.messageCount += 1;
215
244
  }
@@ -263,6 +292,7 @@ export function createClaudeUdsEndpoint({
263
292
  daemonPaths = deriveClaudeDaemonPaths(),
264
293
  cwd = process.cwd(),
265
294
  timeoutMs = DEFAULT_TIMEOUT_MS,
295
+ maxTurnMs = Math.min(resolveHardCeilingMs(), 15 * 60_000),
266
296
  markerFactory = () =>
267
297
  `TFX_UDS_ORCH_DONE_${crypto.randomBytes(6).toString("hex")}`,
268
298
  shortFactory,
@@ -299,7 +329,7 @@ export function createClaudeUdsEndpoint({
299
329
  sock,
300
330
  payload.short,
301
331
  marker,
302
- { timeoutMs },
332
+ { timeoutMs, maxTurnMs },
303
333
  );
304
334
  await teardownDaemonJob({
305
335
  controlSock: sock,
@@ -441,6 +471,7 @@ export function createCodexAppServerUdsEndpoint({
441
471
  cwd = process.cwd(),
442
472
  model,
443
473
  timeoutMs = DEFAULT_CODEX_APP_SERVER_UDS_TIMEOUT_MS,
474
+ maxTurnMs = Math.min(resolveHardCeilingMs(), 15 * 60_000),
444
475
  bootstrapTimeoutMs = DEFAULT_CODEX_APP_SERVER_UDS_BOOTSTRAP_MS,
445
476
  clientFactory = (opts) => new JsonRpcWsUdsClient(opts),
446
477
  spawnFn = spawn,
@@ -536,10 +567,12 @@ export function createCodexAppServerUdsEndpoint({
536
567
  let offDelta = () => {};
537
568
  let offError = () => {};
538
569
  let offDone = () => {};
570
+ let offActivity = () => {};
539
571
  const cleanup = () => {
540
572
  offDelta();
541
573
  offError();
542
574
  offDone();
575
+ offActivity();
543
576
  };
544
577
  const completion = new Promise((resolve) => {
545
578
  offDelta = client.onNotification(
@@ -566,12 +599,32 @@ export function createCodexAppServerUdsEndpoint({
566
599
  { threadId, input: [{ type: "text", text: prompt }] },
567
600
  timeoutMs,
568
601
  );
602
+ const activityEnabled = isActivityLifecycleEnabled();
603
+ const lifecycle = createActivityLifecycle({
604
+ enabled: activityEnabled,
605
+ interventionMs: timeoutMs,
606
+ hardCeilingMs: maxTurnMs,
607
+ });
608
+ offActivity = client.onNotification("*", () => lifecycle.observe());
569
609
  let timeoutHandle = null;
570
610
  const timeoutPromise = new Promise((resolve) => {
571
- timeoutHandle = setTimeout(() => {
572
- cleanup();
573
- resolve({ status: "timeout" });
574
- }, timeoutMs);
611
+ const arm = () => {
612
+ timeoutHandle = setTimeout(async () => {
613
+ if (!activityEnabled) {
614
+ cleanup();
615
+ resolve({ status: "timeout" });
616
+ return;
617
+ }
618
+ const reason = await lifecycle.check();
619
+ if (reason) {
620
+ cleanup();
621
+ resolve({ status: "timeout", reason });
622
+ return;
623
+ }
624
+ arm();
625
+ }, timeoutMs);
626
+ };
627
+ arm();
575
628
  });
576
629
  let settled;
577
630
  try {
package/hub/tools.mjs CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  } from "@triflux/core/hub/pipeline/state.mjs";
11
11
  import { sendInputToConductorSession } from "./team/conductor-registry.mjs";
12
12
  import { getTeamBridge } from "@triflux/core/hub/team-bridge.mjs";
13
+ import { DEFAULT_ASSIGN_TIMEOUT_MS, DEFAULT_ASSIGN_TTL_MS, DEFAULT_HANDOFF_TTL_MS } from "@triflux/core/hub/lib/timeout-defaults.mjs";
13
14
 
14
15
  const TEAM_BRIDGE_NOT_REGISTERED = "bridge_not_registered";
15
16
 
@@ -155,10 +156,7 @@ export function createTools(store, router, hitl, pipe = null) {
155
156
  },
156
157
  },
157
158
  },
158
- handler: wrap("REGISTER_FAILED", (args) => {
159
- const data = router.registerAgent(args);
160
- return { ok: true, data };
161
- }),
159
+ handler: wrap("REGISTER_FAILED", (args) => router.registerAgent(args)),
162
160
  },
163
161
 
164
162
  // ── 2. status ──
@@ -362,7 +360,7 @@ export function createTools(store, router, hitl, pipe = null) {
362
360
  type: "integer",
363
361
  minimum: 1000,
364
362
  maximum: 86400000,
365
- default: 600000,
363
+ default: DEFAULT_HANDOFF_TTL_MS,
366
364
  },
367
365
  trace_id: { type: "string" },
368
366
  correlation_id: { type: "string" },
@@ -399,13 +397,13 @@ export function createTools(store, router, hitl, pipe = null) {
399
397
  type: "integer",
400
398
  minimum: 1000,
401
399
  maximum: 86400000,
402
- default: 600000,
400
+ default: DEFAULT_ASSIGN_TTL_MS,
403
401
  },
404
402
  timeout_ms: {
405
403
  type: "integer",
406
404
  minimum: 1000,
407
405
  maximum: 86400000,
408
- default: 600000,
406
+ default: DEFAULT_ASSIGN_TIMEOUT_MS,
409
407
  },
410
408
  max_retries: { type: "integer", minimum: 0, maximum: 20, default: 0 },
411
409
  trace_id: { type: "string" },
@@ -12,6 +12,12 @@ import { createHash, randomUUID } from "node:crypto";
12
12
  import { isAbsolute } from "node:path";
13
13
  import process from "node:process";
14
14
 
15
+ import {
16
+ createActivityLifecycle,
17
+ isActivityLifecycleEnabled,
18
+ resolveHardCeilingMs,
19
+ resolveStallInterventionMs,
20
+ } from "@triflux/core/hub/lib/worker-lifecycle.mjs";
15
21
  import {
16
22
  JsonRpcProtocolError,
17
23
  JsonRpcStdioClient,
@@ -25,6 +31,7 @@ export const CODEX_APP_SERVER_TRANSPORT_EXIT_CODE = 70;
25
31
  export const CODEX_APP_SERVER_TIMEOUT_EXIT_CODE = 124;
26
32
 
27
33
  export const DEFAULT_CODEX_APP_SERVER_BOOTSTRAP_TIMEOUT_MS = 10_000;
34
+ // Legacy wall-clock default retained for TFX_ACTIVITY_LIFECYCLE=0 compatibility.
28
35
  export const DEFAULT_CODEX_APP_SERVER_EXECUTION_TIMEOUT_MS = 10 * 60 * 1000;
29
36
  export const DEFAULT_UNKNOWN_METHOD_WARN_THRESHOLD = 5;
30
37
  /**
@@ -327,6 +334,7 @@ export class CodexAppServerWorker {
327
334
  * @param {number} [options.unknownMethodWarnThreshold]
328
335
  * @param {(method: string) => void} [options.onUnknownMethod]
329
336
  * @param {(label: string, payload: object) => void} [options.warn]
337
+ * @param {(context: object) => Promise<boolean|string>|boolean|string} [options.interveneFn]
330
338
  */
331
339
  constructor(options = {}) {
332
340
  this.command = options.command || process.env.CODEX_BIN || "codex";
@@ -370,6 +378,8 @@ export class CodexAppServerWorker {
370
378
  typeof options.onUnknownMethod === "function"
371
379
  ? options.onUnknownMethod
372
380
  : null;
381
+ this._interveneFn =
382
+ typeof options.interveneFn === "function" ? options.interveneFn : null;
373
383
 
374
384
  /** @type {import('node:child_process').ChildProcess | null} */
375
385
  this.child = null;
@@ -643,6 +653,8 @@ export class CodexAppServerWorker {
643
653
  }
644
654
 
645
655
  const outputParts = [];
656
+ let lastActivityAt = Date.now();
657
+ let activityLifecycle = null;
646
658
  const unknownMethodsThisTurn = new Set();
647
659
  let threadId =
648
660
  typeof opts.threadId === "string" && opts.threadId ? opts.threadId : null;
@@ -714,6 +726,10 @@ export class CodexAppServerWorker {
714
726
  };
715
727
 
716
728
  const handleNotification = (method, params) => {
729
+ // Any notification, including unknown and opt-out methods, proves the
730
+ // transport is live. Content filtering below remains unchanged.
731
+ lastActivityAt = Date.now();
732
+ activityLifecycle?.observe();
717
733
  // AC5 defense: opt-out should already be filtered server-side.
718
734
  if (OPT_OUT_METHODS.includes(method)) return;
719
735
 
@@ -854,16 +870,40 @@ export class CodexAppServerWorker {
854
870
  };
855
871
  }
856
872
 
857
- // Timeout: SIGTERM + partial WorkerResult (AC8)
873
+ // In activity mode timeoutMs is the inactivity window. Notifications
874
+ // re-arm the lifecycle; hardCeilingMs remains the leak-prevention bound.
875
+ const activityEnabled = isActivityLifecycleEnabled();
858
876
  const timeoutMs = Number.isFinite(opts.timeoutMs)
859
877
  ? opts.timeoutMs
860
- : DEFAULT_CODEX_APP_SERVER_EXECUTION_TIMEOUT_MS;
878
+ : activityEnabled
879
+ ? resolveStallInterventionMs()
880
+ : DEFAULT_CODEX_APP_SERVER_EXECUTION_TIMEOUT_MS;
881
+ const hardCeilingMs = Number.isFinite(opts.hardCeilingMs)
882
+ ? opts.hardCeilingMs
883
+ : resolveHardCeilingMs();
861
884
  // Capture current child so a stale timer (post-result) cannot SIGTERM a
862
885
  // later reused worker's child process.
863
886
  const capturedChild = this.child;
887
+ activityLifecycle = createActivityLifecycle({
888
+ enabled: activityEnabled,
889
+ interventionMs: timeoutMs,
890
+ hardCeilingMs,
891
+ onIntervene: async (context) => {
892
+ if (this._interveneFn) {
893
+ const result = await this._interveneFn({
894
+ threadId,
895
+ client,
896
+ lastActivityAt,
897
+ ...context,
898
+ });
899
+ return result === true || result === "resolved";
900
+ }
901
+ return false;
902
+ },
903
+ });
864
904
  const timeoutPromise = new Promise((resolve) => {
865
- timer = setTimeout(() => {
866
- this._warn("execution timeout", { timeoutMs });
905
+ const fire = (reason) => {
906
+ this._warn("execution timeout", { timeoutMs, reason });
867
907
  try {
868
908
  capturedChild?.kill?.("SIGTERM");
869
909
  } catch {}
@@ -878,7 +918,16 @@ export class CodexAppServerWorker {
878
918
  ),
879
919
  raw: null,
880
920
  });
881
- }, timeoutMs);
921
+ };
922
+ const arm = () => {
923
+ timer = setTimeout(async () => {
924
+ if (!activityEnabled) return fire("timeout");
925
+ const reason = await activityLifecycle.check({ threadId, client });
926
+ if (reason) return fire(reason);
927
+ arm();
928
+ }, timeoutMs);
929
+ };
930
+ arm();
882
931
  });
883
932
 
884
933
  const result = await Promise.race([resultPromise, timeoutPromise]);
@@ -119,7 +119,7 @@ function readTomlScalar(raw, key) {
119
119
  }
120
120
 
121
121
  /**
122
- * Resolve a Codex effort profile name (e.g. "gpt55_high") to its concrete
122
+ * Resolve a Codex effort profile name (e.g. "gpt56_terra_high") to its concrete
123
123
  * `model` + reasoning effort. SSOT = the per-profile file written by
124
124
  * `tfx setup` at `~/.codex/<profile>.config.toml`. Falls back to deriving the
125
125
  * effort from the `<...>_<effort>` naming convention when the file is absent.
@@ -64,24 +64,24 @@ const AGENT_TIMEOUT_SEC = Object.freeze({
64
64
  });
65
65
 
66
66
  const CODEX_PROFILE_BY_AGENT = Object.freeze({
67
- executor: "gpt55_high",
68
- "build-fixer": "gpt55_low",
69
- debugger: "gpt55_xhigh",
70
- "deep-executor": "gpt55_xhigh",
71
- architect: "gpt55_xhigh",
72
- planner: "gpt55_xhigh",
73
- critic: "gpt55_xhigh",
74
- analyst: "gpt55_xhigh",
75
- "code-reviewer": "gpt55_high",
76
- "security-reviewer": "gpt55_xhigh",
77
- "quality-reviewer": "gpt55_high",
78
- scientist: "gpt55_high",
79
- "scientist-deep": "gpt55_xhigh",
80
- "document-specialist": "gpt55_high",
81
- verifier: "gpt55_high",
82
- designer: "gpt55_xhigh",
83
- writer: "gpt55_low",
84
- spark: "gpt55_low",
67
+ executor: "gpt56_terra_high",
68
+ "build-fixer": "gpt56_luna_low",
69
+ debugger: "gpt56_sol_xhigh",
70
+ "deep-executor": "gpt56_sol_xhigh",
71
+ architect: "gpt56_sol_xhigh",
72
+ planner: "gpt56_sol_xhigh",
73
+ critic: "gpt56_sol_xhigh",
74
+ analyst: "gpt56_sol_xhigh",
75
+ "code-reviewer": "gpt56_terra_high",
76
+ "security-reviewer": "gpt56_sol_xhigh",
77
+ "quality-reviewer": "gpt56_terra_high",
78
+ scientist: "gpt56_terra_high",
79
+ "scientist-deep": "gpt56_sol_xhigh",
80
+ "document-specialist": "gpt56_terra_high",
81
+ verifier: "gpt56_terra_high",
82
+ designer: "gpt56_sol_xhigh",
83
+ writer: "gpt56_luna_low",
84
+ spark: "gpt56_luna_low",
85
85
  });
86
86
 
87
87
  const REVIEW_INSTRUCTION_BY_AGENT = Object.freeze({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@triflux/remote",
3
- "version": "10.41.1",
3
+ "version": "10.43.0",
4
4
  "description": "triflux remote — team mode, psmux, MCP workers, SQLite store.",
5
5
  "type": "module",
6
6
  "main": "hub/index.mjs",
@@ -5,6 +5,7 @@
5
5
  //
6
6
  // 출처: scripts/tfx-route.sh route_agent() L1052-L1059, run_codex_exec() L2036-L2046.
7
7
  // .claude/rules/tfx-update-logic.md Antigravity CLI 1.0.0 정밀 sanity matrix.
8
+ // timeoutSec은 lane 예상 소요 시간(advisory)이다. hard ceiling 집행은 Bash route가 소유한다.
8
9
 
9
10
  export const id = "agy";
10
11
  export const cliType = "antigravity";
@@ -5,6 +5,7 @@
5
5
  //
6
6
  // 출처: scripts/tfx-route.sh route_agent() L1062-L1063 (explore|claude),
7
7
  // L1196-L1203 (TFX_CLI_MODE=gemini fallback), TFX_VERIFIER_OVERRIDE=claude.
8
+ // timeoutSec은 lane 예상 소요 시간(advisory)이다. hard ceiling 집행은 Bash route가 소유한다.
8
9
 
9
10
  export const id = "claude";
10
11
  export const cliType = "claude-native";
@@ -5,6 +5,7 @@
5
5
  //
6
6
  // 진입점: tfx-route.mjs → selectAdapter("codex") → plan({...}).
7
7
  // 출처: scripts/tfx-route.sh route_agent() L1001-L1079 case 문 미러.
8
+ // timeoutSec은 lane 예상 소요 시간(advisory)이다. hard ceiling 집행은 Bash route가 소유한다.
8
9
 
9
10
  export const id = "codex";
10
11
  export const cliType = "codex";
@@ -12,84 +13,84 @@ export const command = "codex";
12
13
 
13
14
  const AGENT_PROFILES = {
14
15
  executor: {
15
- profile: "gpt55_high",
16
+ profile: "gpt56_terra_high",
16
17
  timeoutSec: 1080,
17
18
  runMode: "fg",
18
19
  opusOversight: false,
19
20
  mcpHint: "implement",
20
21
  },
21
22
  codex: {
22
- profile: "gpt55_high",
23
+ profile: "gpt56_terra_high",
23
24
  timeoutSec: 1080,
24
25
  runMode: "fg",
25
26
  opusOversight: false,
26
27
  mcpHint: "implement",
27
28
  },
28
29
  "build-fixer": {
29
- profile: "gpt55_low",
30
+ profile: "gpt56_luna_low",
30
31
  timeoutSec: 540,
31
32
  runMode: "fg",
32
33
  opusOversight: false,
33
34
  mcpHint: "implement",
34
35
  },
35
36
  cleanup: {
36
- profile: "gpt55_med",
37
+ profile: "gpt56_terra_med",
37
38
  timeoutSec: 540,
38
39
  runMode: "fg",
39
40
  opusOversight: false,
40
41
  mcpHint: "implement",
41
42
  },
42
43
  deslop: {
43
- profile: "gpt55_med",
44
+ profile: "gpt56_terra_med",
44
45
  timeoutSec: 540,
45
46
  runMode: "fg",
46
47
  opusOversight: false,
47
48
  mcpHint: "implement",
48
49
  },
49
50
  debugger: {
50
- profile: "gpt55_xhigh",
51
+ profile: "gpt56_sol_xhigh",
51
52
  timeoutSec: 900,
52
53
  runMode: "bg",
53
54
  opusOversight: false,
54
55
  mcpHint: "implement",
55
56
  },
56
57
  "deep-executor": {
57
- profile: "gpt55_xhigh",
58
+ profile: "gpt56_sol_xhigh",
58
59
  timeoutSec: 3600,
59
60
  runMode: "bg",
60
61
  opusOversight: true,
61
62
  mcpHint: "implement",
62
63
  },
63
64
  architect: {
64
- profile: "gpt55_xhigh",
65
+ profile: "gpt56_sol_xhigh",
65
66
  timeoutSec: 3600,
66
67
  runMode: "bg",
67
68
  opusOversight: true,
68
69
  mcpHint: "analyze",
69
70
  },
70
71
  critic: {
71
- profile: "gpt55_xhigh",
72
+ profile: "gpt56_sol_xhigh",
72
73
  timeoutSec: 3600,
73
74
  runMode: "bg",
74
75
  opusOversight: true,
75
76
  mcpHint: "analyze",
76
77
  },
77
78
  planner: {
78
- profile: "gpt55_xhigh",
79
+ profile: "gpt56_sol_xhigh",
79
80
  timeoutSec: 3600,
80
81
  runMode: "fg",
81
82
  opusOversight: true,
82
83
  mcpHint: "analyze",
83
84
  },
84
85
  analyst: {
85
- profile: "gpt55_xhigh",
86
+ profile: "gpt56_sol_xhigh",
86
87
  timeoutSec: 3600,
87
88
  runMode: "fg",
88
89
  opusOversight: true,
89
90
  mcpHint: "analyze",
90
91
  },
91
92
  "code-reviewer": {
92
- profile: "gpt55_high",
93
+ profile: "gpt56_terra_high",
93
94
  timeoutSec: 1800,
94
95
  runMode: "bg",
95
96
  opusOversight: false,
@@ -97,7 +98,7 @@ const AGENT_PROFILES = {
97
98
  subcommand: "review",
98
99
  },
99
100
  "quality-reviewer": {
100
- profile: "gpt55_high",
101
+ profile: "gpt56_terra_high",
101
102
  timeoutSec: 1800,
102
103
  runMode: "bg",
103
104
  opusOversight: false,
@@ -105,7 +106,7 @@ const AGENT_PROFILES = {
105
106
  subcommand: "review",
106
107
  },
107
108
  "security-reviewer": {
108
- profile: "gpt55_xhigh",
109
+ profile: "gpt56_sol_xhigh",
109
110
  timeoutSec: 1800,
110
111
  runMode: "bg",
111
112
  opusOversight: true,
@@ -113,28 +114,28 @@ const AGENT_PROFILES = {
113
114
  subcommand: "review",
114
115
  },
115
116
  scientist: {
116
- profile: "gpt55_high",
117
+ profile: "gpt56_terra_high",
117
118
  timeoutSec: 1440,
118
119
  runMode: "bg",
119
120
  opusOversight: false,
120
121
  mcpHint: "analyze",
121
122
  },
122
123
  "document-specialist": {
123
- profile: "gpt55_high",
124
+ profile: "gpt56_terra_high",
124
125
  timeoutSec: 1440,
125
126
  runMode: "bg",
126
127
  opusOversight: false,
127
128
  mcpHint: "analyze",
128
129
  },
129
130
  "scientist-deep": {
130
- profile: "gpt55_xhigh",
131
+ profile: "gpt56_sol_xhigh",
131
132
  timeoutSec: 3600,
132
133
  runMode: "bg",
133
134
  opusOversight: false,
134
135
  mcpHint: "analyze",
135
136
  },
136
137
  verifier: {
137
- profile: "gpt55_high",
138
+ profile: "gpt56_terra_high",
138
139
  timeoutSec: 1200,
139
140
  runMode: "fg",
140
141
  opusOversight: false,
@@ -142,14 +143,14 @@ const AGENT_PROFILES = {
142
143
  subcommand: "review",
143
144
  },
144
145
  "test-engineer": {
145
- profile: "gpt55_high",
146
+ profile: "gpt56_terra_high",
146
147
  timeoutSec: 1200,
147
148
  runMode: "bg",
148
149
  opusOversight: false,
149
150
  mcpHint: "implement",
150
151
  },
151
152
  "qa-tester": {
152
- profile: "gpt55_high",
153
+ profile: "gpt56_terra_high",
153
154
  timeoutSec: 1200,
154
155
  runMode: "bg",
155
156
  opusOversight: false,
@@ -157,7 +158,7 @@ const AGENT_PROFILES = {
157
158
  subcommand: "review",
158
159
  },
159
160
  spark: {
160
- profile: "gpt55_low",
161
+ profile: "gpt56_luna_low",
161
162
  timeoutSec: 180,
162
163
  runMode: "fg",
163
164
  opusOversight: false,
@@ -29,7 +29,7 @@ function readProfileScalar(raw, key) {
29
29
  }
30
30
 
31
31
  /**
32
- * Resolve a Codex effort profile name (e.g. "gpt55_high") to the `-c key=value`
32
+ * Resolve a Codex effort profile name (e.g. "gpt56_terra_high") to the `-c key=value`
33
33
  * config overrides that `codex exec` accepts, so the headless CLI lanes can
34
34
  * select a profile WITHOUT `codex exec --profile <name>`. codex 0.134+ rejects
35
35
  * `--profile X` whenever config.toml still contains an inline `[profiles.X]`
@@ -47,7 +47,7 @@ function readProfileScalar(raw, key) {
47
47
  *
48
48
  * @param {string} profileName
49
49
  * @param {{ codexHome?: string }} [opts]
50
- * @returns {string[]} e.g. ['model="gpt-5.5"', 'model_reasoning_effort="high"']
50
+ * @returns {string[]} e.g. ['model="gpt-5.6-terra"', 'model_reasoning_effort="high"']
51
51
  */
52
52
  export function codexProfileConfigOverrides(profileName, opts = {}) {
53
53
  if (typeof profileName !== "string" || !profileName) return [];