parallel-codex-tui 0.2.10 → 0.3.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.
@@ -236,6 +236,9 @@ function viewLabel(view) {
236
236
  return shortViewLabel(view);
237
237
  }
238
238
  function shortcutHint(view) {
239
+ if (view === "roles") {
240
+ return "^E back";
241
+ }
239
242
  if (view === "status") {
240
243
  return "^S back";
241
244
  }
@@ -245,6 +248,9 @@ function shortcutHint(view) {
245
248
  return "^S status · ^C exit";
246
249
  }
247
250
  function shortViewLabel(view) {
251
+ if (view === "roles") {
252
+ return "roles";
253
+ }
248
254
  if (view === "status") {
249
255
  return "status";
250
256
  }
@@ -272,7 +278,7 @@ function shortViewLabel(view) {
272
278
  return "chat";
273
279
  }
274
280
  function shortShortcutHint(view) {
275
- return view === "native" ? "^]" : view === "status" ? "^S" : "^C";
281
+ return view === "native" ? "^]" : view === "status" ? "^S" : view === "roles" ? "^E" : "^C";
276
282
  }
277
283
  function compactHeaderProject(cwd, maxLength) {
278
284
  const project = basename(cwd) || cwd;
@@ -142,7 +142,10 @@ function featureBoardEvidenceText(timeline, feature, width) {
142
142
  ? `deps ${dependencies.map((item) => safeFeatureBoardText(item.title)).join(", ")}`
143
143
  : "independent";
144
144
  const assignmentText = feature.actorEngine && feature.criticEngine
145
- ? `actor ${feature.actorEngine} · critic ${feature.criticEngine}`
145
+ ? [
146
+ `actor ${feature.actorEngine}/${feature.actorModel?.trim() || "default"}`,
147
+ `critic ${feature.criticEngine}/${feature.criticModel?.trim() || "default"}`
148
+ ].join(" · ")
146
149
  : "";
147
150
  const evidence = feature.latestFinding
148
151
  ? `finding · ${safeFeatureBoardText(feature.latestFinding)}`
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { Box, Text } from "ink";
3
3
  import { compactEndByDisplayWidth, compactTailByDisplayWidth, displayWidth } from "./display-width.js";
4
4
  import { TUI_THEME } from "./theme.js";
5
- export function InputBar({ mode, ready = true, busy = false, routeFallback = false, collaborationDetail = false, collaborationUnresolved = false, collaborationBack = "workers", featureCanCancel = false, featureCanPause = false, featureCanReassign = false, featureCancelConfirm = false, featurePauseConfirm = false, featureAssignment = false, taskSessionAction = null, taskSessionsIncludeArchived = false, mainConversationSessions = false, taskSessionDetail = false, taskSessionDetailHasNative = false, taskSessionDetailCanFork = false, canRetry = false, hasWorkers = false, hasActiveTask = false, hasTaskResult = false, taskResultExpanded = false, chatScrollOffset = 0, chatMaxScrollOffset = 0, nativeClosed = false, searchMatchIndex = 0, searchMatchCount = 0, clipboardNotice = null, value, cursor, terminalWidth: providedTerminalWidth, onChange, onSubmit }) {
5
+ export function InputBar({ mode, ready = true, busy = false, routeFallback = false, collaborationDetail = false, collaborationUnresolved = false, collaborationBack = "workers", featureCanCancel = false, featureCanPause = false, featureCanReassign = false, featureCancelConfirm = false, featurePauseConfirm = false, featureAssignment = false, featureEditingModel = null, taskSessionAction = null, taskSessionsIncludeArchived = false, mainConversationSessions = false, taskSessionDetail = false, taskSessionDetailHasNative = false, taskSessionDetailCanFork = false, canRetry = false, hasWorkers = false, hasActiveTask = false, hasTaskResult = false, taskResultExpanded = false, chatScrollOffset = 0, chatMaxScrollOffset = 0, nativeClosed = false, searchMatchIndex = 0, searchMatchCount = 0, clipboardNotice = null, roleScope = "next", roleEditingModel = null, roleCanApply = true, roleSaving = false, roleHasOverride = false, value, cursor, terminalWidth: providedTerminalWidth, onChange, onSubmit }) {
6
6
  const terminalWidth = providedTerminalWidth ?? process.stdout.columns ?? 120;
7
7
  const fillRail = providedTerminalWidth !== undefined || typeof process.stdout.columns === "number";
8
8
  if (clipboardNotice) {
@@ -19,6 +19,24 @@ export function InputBar({ mode, ready = true, busy = false, routeFallback = fal
19
19
  const textWidth = displayWidth(`${prefix}${display.before}|${display.after}${suffix}`);
20
20
  return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: textWidth, fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: prefix }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.before }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: "|" }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.after }), suffix ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: suffix }) : null] }));
21
21
  }
22
+ if (mode === "roles") {
23
+ if (roleEditingModel) {
24
+ const prefix = `${roleEditingModel.role} model > `;
25
+ const valueWidth = Math.max(1, terminalWidth - displayWidth(prefix) - 3);
26
+ const display = chatInputDisplayParts(roleEditingModel.value, roleEditingModel.cursor, valueWidth);
27
+ const textWidth = displayWidth(`${prefix}${display.before}|${display.after}`);
28
+ return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: textWidth, fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: prefix }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.before }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: "|" }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.after })] }));
29
+ }
30
+ const hints = roleConfigurationInputHints(terminalWidth, roleScope, roleCanApply, roleSaving, roleHasOverride);
31
+ return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: roleSaving ? TUI_THEME.warning : TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
32
+ }
33
+ if (mode === "features" && featureEditingModel) {
34
+ const prefix = `${featureEditingModel.role} model > `;
35
+ const valueWidth = Math.max(1, terminalWidth - displayWidth(prefix) - 3);
36
+ const display = chatInputDisplayParts(featureEditingModel.value, featureEditingModel.cursor, valueWidth);
37
+ const textWidth = displayWidth(`${prefix}${display.before}|${display.after}`);
38
+ return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: textWidth, fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: prefix }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.before }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: "|" }), _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.text, children: display.after })] }));
39
+ }
22
40
  if (mode === "status") {
23
41
  const hints = statusDetailInputHints(terminalWidth);
24
42
  return (_jsxs(InputRail, { terminalWidth: terminalWidth, textWidth: displayWidth(`${hints.label}${hints.detail}`), fill: fillRail, children: [_jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.accent, bold: true, children: hints.label }), hints.detail ? _jsx(Text, { backgroundColor: TUI_THEME.rail, color: TUI_THEME.muted, children: hints.detail }) : null] }));
@@ -422,14 +440,27 @@ function workerInputHints(width) {
422
440
  }
423
441
  function statusDetailInputHints(width) {
424
442
  return selectInputHints(width, [
425
- { label: "status", detail: " · ^X diagnostics · ^S/Esc back · ^C exit" },
426
- { label: "status", detail: " · ^X diag · ^S/Esc back · ^C exit" },
443
+ { label: "status", detail: " · ^E roles · ^X diagnostics · ^S/Esc back · ^C exit" },
444
+ { label: "status", detail: " · ^E roles · ^X diag · ^S/Esc back · ^C exit" },
427
445
  { label: "status", detail: " · ^S back · ^C exit" },
428
446
  { label: "status", detail: " · ^S back" },
429
447
  { label: "status", detail: "" },
430
448
  { label: "st", detail: "" }
431
449
  ]);
432
450
  }
451
+ function roleConfigurationInputHints(width, scope, canApply, saving, hasOverride) {
452
+ const label = saving ? "roles · saving" : `roles · ${scope}`;
453
+ const apply = canApply ? "Enter apply" : "task unavailable";
454
+ const reset = hasOverride ? " · X reset" : "";
455
+ return selectInputHints(width, [
456
+ { label, detail: ` · Tab scope · Up/Dn role · Left/Right provider · M model · ${apply}${reset} · ^E/Esc back` },
457
+ { label, detail: ` · Tab scope · Up/Dn · Left/Right provider · M model · ${apply}${reset} · Esc back` },
458
+ { label, detail: ` · Tab · Up/Dn · Left/Right · M model · ${apply}${reset}` },
459
+ { label, detail: ` · Tab · arrows · M · ${canApply ? "Enter" : "no task"}` },
460
+ { label: "roles", detail: " · Tab · arrows · M · Enter" },
461
+ { label: "roles", detail: "" }
462
+ ]);
463
+ }
433
464
  function workerOverviewInputHints(width) {
434
465
  if (width < 16) {
435
466
  return { label: "wrk", detail: "" };
@@ -457,9 +488,9 @@ function workerOverviewInputHints(width) {
457
488
  function featureBoardInputHints(width, options) {
458
489
  if (options.assignment) {
459
490
  return selectInputHints(width, [
460
- { label: "assign provider", detail: " · A Actor · C Critic · M/Esc done" },
461
- { label: "assign", detail: " · A Actor · C Critic · Esc done" },
462
- { label: "assign", detail: " · A actor · C critic" },
491
+ { label: "assign", detail: " · A/C provider · 1/2 model · M/Esc done" },
492
+ { label: "assign", detail: " · A/C provider · 1/2 model · Esc done" },
493
+ { label: "assign", detail: " · A/C provider · 1/2 model" },
463
494
  { label: "provider", detail: " · A · C · Esc" },
464
495
  { label: "provider", detail: "" },
465
496
  { label: "M", detail: "" }
@@ -0,0 +1,96 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { CONFIGURABLE_ROLES } from "../core/role-configuration.js";
4
+ import { compactEndByDisplayWidth, displayWidth } from "./display-width.js";
5
+ import { roleConfigurationScopeHasOverride, roleConfigurationScopeLabel } from "./role-configuration-state.js";
6
+ import { TUI_THEME } from "./theme.js";
7
+ export function RoleConfigurationView({ height = 20, terminalWidth = process.stdout.columns || 120, ...input }) {
8
+ const viewportHeight = Math.max(1, Math.trunc(height));
9
+ const width = Math.max(1, terminalWidth - 2);
10
+ const lines = roleConfigurationDisplayLines(input, width).slice(0, viewportHeight);
11
+ const blanks = Math.max(0, viewportHeight - lines.length);
12
+ return (_jsxs(Box, { flexDirection: "column", height: viewportHeight, children: [lines.map((line, index) => (_jsx(RoleConfigurationRow, { line: line, width: width }, `${line.text}-${index}`))), Array.from({ length: blanks }, (_, index) => (_jsx(Text, { backgroundColor: TUI_THEME.surface, children: " ".repeat(width) }, `role-config-fill-${index}`)))] }));
13
+ }
14
+ export function roleConfigurationDisplayLines(input, width) {
15
+ const safeWidth = Math.max(1, Math.trunc(width));
16
+ const lines = [
17
+ { text: "Role & model control", tone: "heading" },
18
+ {
19
+ text: `scope · ${roleConfigurationScopeLabel(input.scope)}`,
20
+ tone: input.scope === "task" && !input.hasActiveTask ? "warning" : "accent"
21
+ }
22
+ ];
23
+ if (input.loading || !input.snapshot || !input.draft) {
24
+ lines.push({ text: "loading role configuration...", tone: "muted" });
25
+ return lines.map((line) => fittedRoleLine(line, safeWidth));
26
+ }
27
+ if (input.scope === "task" && !input.hasActiveTask) {
28
+ lines.push({ text: "No active Task · choose next request or future requests.", tone: "warning" });
29
+ }
30
+ else {
31
+ lines.push({
32
+ text: roleConfigurationScopeHasOverride(input.snapshot, input.scope)
33
+ ? "saved override · Enter updates it · X resets inheritance"
34
+ : "inheriting defaults · Enter saves this matrix",
35
+ tone: roleConfigurationScopeHasOverride(input.snapshot, input.scope) ? "success" : "muted"
36
+ });
37
+ }
38
+ lines.push({ text: "", tone: "text" });
39
+ for (const [index, role] of CONFIGURABLE_ROLES.entries()) {
40
+ const target = input.draft[role];
41
+ const provider = input.snapshot.providers.find((candidate) => candidate.id === target.engine);
42
+ const remote = provider?.modelProvider.trim();
43
+ const model = target.model.trim() || provider?.model.trim() || "default";
44
+ const prefix = index === input.selectedRoleIndex ? ">" : " ";
45
+ const roleLabel = `${role[0]?.toUpperCase() ?? ""}${role.slice(1)}`.padEnd(7, " ");
46
+ lines.push({
47
+ text: `${prefix} ${roleLabel} ${target.engine} · ${[remote, model].filter(Boolean).join("/")}`,
48
+ tone: index === input.selectedRoleIndex ? "accent" : "text",
49
+ selected: index === input.selectedRoleIndex
50
+ });
51
+ }
52
+ lines.push({ text: "", tone: "text" });
53
+ const active = input.snapshot.activeTurn;
54
+ if (active) {
55
+ lines.push({
56
+ text: `active turn · ${CONFIGURABLE_ROLES.map((role) => `${role}/${active[role].engine}/${active[role].model || "default"}`).join(" · ")}`,
57
+ tone: "muted"
58
+ });
59
+ }
60
+ if (input.saving) {
61
+ lines.push({ text: "saving role configuration...", tone: "warning" });
62
+ }
63
+ else if (input.error?.trim()) {
64
+ lines.push({ text: `error · ${input.error.trim()}`, tone: "danger" });
65
+ }
66
+ else if (input.notice?.trim()) {
67
+ lines.push({ text: input.notice.trim(), tone: "success" });
68
+ }
69
+ return lines.map((line) => fittedRoleLine(line, safeWidth));
70
+ }
71
+ function RoleConfigurationRow({ line, width }) {
72
+ const text = compactEndByDisplayWidth(line.text, width);
73
+ const trailing = Math.max(0, width - displayWidth(text));
74
+ const theme = roleConfigurationLineTheme(line.tone, line.selected);
75
+ return (_jsxs(Text, { children: [_jsx(Text, { ...theme, children: text }), trailing > 0 ? _jsx(Text, { backgroundColor: theme.backgroundColor, children: " ".repeat(trailing) }) : null] }));
76
+ }
77
+ export function roleConfigurationLineTheme(tone, selected = false) {
78
+ return {
79
+ backgroundColor: selected ? TUI_THEME.rail : TUI_THEME.surface,
80
+ color: tone === "heading" || tone === "accent"
81
+ ? TUI_THEME.accent
82
+ : tone === "success"
83
+ ? TUI_THEME.success
84
+ : tone === "warning"
85
+ ? TUI_THEME.warning
86
+ : tone === "danger"
87
+ ? TUI_THEME.danger
88
+ : tone === "muted"
89
+ ? TUI_THEME.muted
90
+ : TUI_THEME.text,
91
+ ...(tone === "heading" || tone === "danger" || selected ? { bold: true } : {})
92
+ };
93
+ }
94
+ function fittedRoleLine(line, width) {
95
+ return { ...line, text: compactEndByDisplayWidth(line.text, width) };
96
+ }
@@ -24,10 +24,10 @@ export function statusDetailDisplayLines(input, width, height) {
24
24
  text: fitStatusDetailText(`workspace · ${basename(input.cwd) || input.cwd} · ${input.cwd}`, safeWidth),
25
25
  tone: "muted"
26
26
  },
27
- {
28
- text: fitStatusDetailText(rolePairingDetail(input.pairing), safeWidth),
29
- tone: "text"
30
- }
27
+ ...roleMatrixDetailLines(input).map((line) => ({
28
+ text: fitStatusDetailText(line.text, safeWidth),
29
+ tone: line.tone
30
+ }))
31
31
  ];
32
32
  if (input.configStatus?.trim()) {
33
33
  lines.push({
@@ -59,15 +59,39 @@ export function statusDetailDisplayLines(input, width, height) {
59
59
  }
60
60
  return lines.slice(0, maxLines);
61
61
  }
62
- function rolePairingDetail(pairing) {
62
+ function roleMatrixDetail(label, pairing, selection) {
63
63
  return [
64
- "active roles",
65
- `main/${pairing.main}`,
66
- `judge/${pairing.judge}`,
67
- `actor/${pairing.actor}`,
68
- `critic/${pairing.critic}`
64
+ label,
65
+ rolePairingEntry("main", selection?.main.engine ?? pairing.main, selection?.main.model),
66
+ rolePairingEntry("judge", selection?.judge.engine ?? pairing.judge, selection?.judge.model),
67
+ rolePairingEntry("actor", selection?.actor.engine ?? pairing.actor, selection?.actor.model),
68
+ rolePairingEntry("critic", selection?.critic.engine ?? pairing.critic, selection?.critic.model)
69
69
  ].join(" · ");
70
70
  }
71
+ function roleMatrixDetailLines(input) {
72
+ const snapshot = input.roleConfigurationSnapshot;
73
+ const lines = [{
74
+ text: roleMatrixDetail("actual roles", input.pairing, input.roleSelection),
75
+ tone: "text"
76
+ }];
77
+ if (!snapshot) {
78
+ return lines;
79
+ }
80
+ const next = snapshot.next ?? snapshot.task ?? snapshot.future;
81
+ const source = snapshot.next ? "one shot" : snapshot.task ? "task default" : "future default";
82
+ lines.push({
83
+ text: roleMatrixDetail(`next roles (${source})`, input.pairing, next),
84
+ tone: snapshot.next ? "active" : "muted"
85
+ });
86
+ lines.push({
87
+ text: roleMatrixDetail("future roles", input.pairing, snapshot.future),
88
+ tone: "muted"
89
+ });
90
+ return lines;
91
+ }
92
+ function rolePairingEntry(role, engine, model) {
93
+ return [role, engine, model?.trim()].filter(Boolean).join("/");
94
+ }
71
95
  function taskDetail(input) {
72
96
  if (!input.taskId) {
73
97
  return "task · none";
@@ -38,6 +38,9 @@ export function isCopyShortcut(input, key) {
38
38
  export function isDiagnosticsShortcut(input, key) {
39
39
  return (key.ctrl === true && input.toLowerCase() === "x") || input === "\u0018";
40
40
  }
41
+ export function isRoleConfigurationShortcut(input, key) {
42
+ return (key.ctrl === true && input.toLowerCase() === "e") || input === "\u0005";
43
+ }
41
44
  export function workerLogJumpKind(input) {
42
45
  if (input === "e" || input === "E") {
43
46
  return "error";
@@ -80,6 +83,14 @@ export function rawPlainArrowDelta(input) {
80
83
  }
81
84
  return delta;
82
85
  }
86
+ export function rawHorizontalArrowDelta(input) {
87
+ let delta = 0;
88
+ for (const match of input.matchAll(/\x1b(?:O([CD])|\[[0-9;?]*([CD]))/g)) {
89
+ const direction = match[1] ?? match[2];
90
+ delta += direction === "C" ? 1 : -1;
91
+ }
92
+ return delta;
93
+ }
83
94
  export function rawChatScrollArrowDelta(input) {
84
95
  const delta = rawPlainArrowDelta(input);
85
96
  // Alternate-scroll wheels arrive as arrow bursts; one arrow remains a draft-history keypress.
@@ -0,0 +1,74 @@
1
+ import { CONFIGURABLE_ROLES, cloneRoleSelection } from "../core/role-configuration.js";
2
+ const ROLE_CONFIGURATION_SCOPES = ["next", "task", "future"];
3
+ export function roleConfigurationSelectionForScope(snapshot, scope) {
4
+ if (scope === "future") {
5
+ return cloneRoleSelection(snapshot.future);
6
+ }
7
+ if (scope === "task") {
8
+ return cloneRoleSelection(snapshot.task ?? snapshot.future);
9
+ }
10
+ return cloneRoleSelection(snapshot.next ?? snapshot.future);
11
+ }
12
+ export function roleConfigurationScopeHasOverride(snapshot, scope) {
13
+ if (!snapshot) {
14
+ return false;
15
+ }
16
+ if (scope === "future") {
17
+ return !sameRoleSelection(snapshot.future, snapshot.baseline);
18
+ }
19
+ return scope === "next" ? snapshot.next !== null : snapshot.task !== null;
20
+ }
21
+ export function nextRoleConfigurationScope(scope, delta, hasTask) {
22
+ const available = ROLE_CONFIGURATION_SCOPES.filter((candidate) => candidate !== "task" || hasTask);
23
+ const index = Math.max(0, available.indexOf(scope));
24
+ return available[((index + delta) % available.length + available.length) % available.length] ?? "next";
25
+ }
26
+ export function moveRoleConfigurationSelection(index, delta) {
27
+ const length = CONFIGURABLE_ROLES.length;
28
+ return ((index + delta) % length + length) % length;
29
+ }
30
+ export function selectedConfigurableRole(index) {
31
+ return CONFIGURABLE_ROLES[Math.max(0, Math.min(CONFIGURABLE_ROLES.length - 1, index))] ?? "main";
32
+ }
33
+ export function cycleRoleProvider(roles, role, providers, delta) {
34
+ const currentEngine = roles[role].engine;
35
+ const selectableProviders = providers.filter((provider) => (provider.assignable || provider.id === currentEngine));
36
+ if (selectableProviders.length === 0) {
37
+ return cloneRoleSelection(roles);
38
+ }
39
+ const currentIndex = selectableProviders.findIndex((provider) => provider.id === currentEngine);
40
+ const start = currentIndex >= 0 ? currentIndex : 0;
41
+ const provider = selectableProviders[((start + delta) % selectableProviders.length + selectableProviders.length) % selectableProviders.length] ?? selectableProviders[0];
42
+ if (!provider) {
43
+ return cloneRoleSelection(roles);
44
+ }
45
+ return {
46
+ ...cloneRoleSelection(roles),
47
+ [role]: {
48
+ engine: provider.id,
49
+ model: provider.model
50
+ }
51
+ };
52
+ }
53
+ export function updateRoleModel(roles, role, model) {
54
+ return {
55
+ ...cloneRoleSelection(roles),
56
+ [role]: {
57
+ ...roles[role],
58
+ model
59
+ }
60
+ };
61
+ }
62
+ export function sameRoleSelection(left, right) {
63
+ return CONFIGURABLE_ROLES.every((role) => (left[role].engine === right[role].engine
64
+ && left[role].model === right[role].model));
65
+ }
66
+ export function roleConfigurationScopeLabel(scope) {
67
+ if (scope === "next") {
68
+ return "next request · one shot";
69
+ }
70
+ if (scope === "task") {
71
+ return "current task · retries and follow-ups";
72
+ }
73
+ return "future requests · persisted default";
74
+ }
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = "0.2.10";
1
+ export const version = "0.3.1";
@@ -18,7 +18,11 @@ export async function buildNativeForkLaunch(input) {
18
18
  async function buildNativeSessionLaunch(input, mode) {
19
19
  const workerConfig = workerProvider(input.config, input.worker.engine).config;
20
20
  const nativeSession = await readWorkerNativeSession(input.worker, workerConfig.capabilities.profile);
21
- const modelConfig = workerConfig.model;
21
+ const modelConfig = {
22
+ ...workerConfig.model,
23
+ name: input.worker.runtimeStatus?.model_name?.trim() || workerConfig.model.name,
24
+ provider: input.worker.runtimeStatus?.model_provider?.trim() || workerConfig.model.provider
25
+ };
22
26
  const env = modelEnvironment(modelConfig);
23
27
  const interactiveArgs = mode === "fork"
24
28
  ? workerConfig.interactive.forkArgs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "parallel-codex-tui",
3
- "version": "0.2.10",
3
+ "version": "0.3.1",
4
4
  "description": "A TypeScript TUI wrapper for routed parallel coding with Codex and Claude workers.",
5
5
  "license": "MIT",
6
6
  "type": "module",