@dotdrelle/wiki-manager 0.15.64 → 0.15.66

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotdrelle/wiki-manager",
3
- "version": "0.15.64",
3
+ "version": "0.15.66",
4
4
  "description": "Agentic shell and orchestration cockpit for llm-wiki workspaces.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1295,8 +1295,8 @@ export function buildLimitedAgentResponse(state, reason = 'no workspace loaded w
1295
1295
  }
1296
1296
 
1297
1297
  export function formatLlmUnavailableMessage(reason) {
1298
- const clean = String(reason ?? 'raison inconnue').replace(/\s+/g, ' ').trim();
1299
- return `⚠ LLM injoignable : ${clean || 'raison inconnue'}`;
1298
+ const clean = String(reason ?? 'unknown reason').replace(/\s+/g, ' ').trim();
1299
+ return `⚠ LLM unavailable: ${clean || 'unknown reason'}`;
1300
1300
  }
1301
1301
 
1302
1302
  function toolsForClassification(classification, writeTools, session = null) {
@@ -1455,7 +1455,7 @@ export function createAgentGraph(options = {}) {
1455
1455
  const llm = state.session.llm ?? options.llm ?? null;
1456
1456
 
1457
1457
  if (!llm) {
1458
- return { response: formatLlmUnavailableMessage('aucun client LLM configure'), pendingToolCalls: null, readyToStream: false };
1458
+ return { response: formatLlmUnavailableMessage('no LLM client configured'), pendingToolCalls: null, readyToStream: false };
1459
1459
  }
1460
1460
 
1461
1461
  const iterations = state.toolIterations ?? 0;
@@ -292,7 +292,7 @@ test('agent graph reports LLM unavailable without Donna active boilerplate', asy
292
292
  const agent = createAgentGraph();
293
293
  const result = await agent.invoke({ input: 'salut', session: sessionBase({ llm: null }) });
294
294
 
295
- assert.equal(result.response, '⚠ LLM injoignable : aucun client LLM configure');
295
+ assert.equal(result.response, '⚠ LLM unavailable: no LLM client configured');
296
296
  assert.doesNotMatch(result.response, /Donna is active/);
297
297
  });
298
298
 
@@ -1386,7 +1386,7 @@ export async function handleSlashCommand(line, context) {
1386
1386
  if (!context.session.workspace) return { output: 'No workspace loaded. Use /use <workspace> first.' };
1387
1387
  const operation = args[3] && !args[3].includes('.') && !args[3].includes('/') ? args[3] : undefined;
1388
1388
  const inputs = args.slice(operation ? 4 : 3);
1389
- const result = await postRuntimeRun(`Run de capability ${capability}${operation ? ` (${operation})` : ''} demandé via /run capability.`, {
1389
+ const result = await postRuntimeRun(`Capability run ${capability}${operation ? ` (${operation})` : ''} requested via /run capability.`, {
1390
1390
  url,
1391
1391
  workspace: context.session.workspace,
1392
1392
  capabilityPlan: {
@@ -1396,9 +1396,9 @@ export async function handleSlashCommand(line, context) {
1396
1396
  },
1397
1397
  });
1398
1398
  if (result?.runId) {
1399
- return { output: `▶ Run de capability accepté (${String(result.runId).slice(0, 8)}) — le plan de l'agent sera intégré et dispatché en parallèle ; approbation demandée avant les mutations (/approve).` };
1399
+ return { output: `▶ Capability run accepted (${String(result.runId).slice(0, 8)}) — the agent's plan will be integrated and dispatched in parallel; approval requested before mutations (/approve).` };
1400
1400
  }
1401
- return { output: `Run non démarré: ${result?.explanation ?? result?.error ?? JSON.stringify(result)}` };
1401
+ return { output: `Run not started: ${result?.explanation ?? result?.error ?? JSON.stringify(result)}` };
1402
1402
  }
1403
1403
  if (subcommand === 'kill') {
1404
1404
  const result = await postRuntimeKill({ url, workspace: context.session.workspace ?? null, runId: args[2] ?? null });
@@ -1419,7 +1419,7 @@ export async function handleSlashCommand(line, context) {
1419
1419
  const runActive = String(context.session.agentProjection?.status ?? '').toLowerCase() === 'running';
1420
1420
  if (count === 0 && (activeRuntimeItems > 0 || runActive)) {
1421
1421
  return {
1422
- output: `Cleared 0 finished queue items — ${activeRuntimeItems || 'des'} item(s) actifs sont gérés par le runtime${runActive ? ' (run en cours)' : ''}. Utilisez /run cancel (arrêt doux) ou /run kill (abort + purge complète).`,
1422
+ output: `Cleared 0 finished queue items — ${activeRuntimeItems || 'the'} active item(s) are managed by the runtime${runActive ? ' (run in progress)' : ''}. Use /run cancel (graceful stop) or /run kill (abort + full purge).`,
1423
1423
  };
1424
1424
  }
1425
1425
  return { output: `Cleared ${count} finished queue item${count === 1 ? '' : 's'}.` };
@@ -1433,7 +1433,7 @@ export async function handleSlashCommand(line, context) {
1433
1433
  // would silently revert the item to waiting (fake cancel).
1434
1434
  const localItem = (context.session.jobQueue ?? []).find((item) => String(item.id) === String(id));
1435
1435
  if (localItem?.origin === 'runtime' || (!localItem && runtimeManagedItemId(context, id))) {
1436
- if (!context.runtime?.url) return { output: 'Item géré par le runtime — reconnectez le runtime pour l’annuler, ou utilisez /run cancel ou /run kill.' };
1436
+ if (!context.runtime?.url) return { output: 'Runtime-managed item — reconnect the runtime to cancel it, or use /run cancel or /run kill.' };
1437
1437
  try {
1438
1438
  const result = await postRuntimeControl('cancel_item', {
1439
1439
  url: context.runtime.url,
@@ -1659,13 +1659,13 @@ export async function handleSlashCommand(line, context) {
1659
1659
  try {
1660
1660
  const killed = await postRuntimeKill({ url: runtime.url, workspace, runId: null, purge: true });
1661
1661
  const purged = killed.purged ?? { runs: 0, events: 0, queue: 0 };
1662
- parts.push(`runtime : ${killed.runs ?? 0} run(s) interrompu(s), ${killed.tasks ?? 0} tâche(s), ${killed.queued ?? 0} requête(s)`);
1663
- parts.push(`store purgé : ${purged.runs ?? 0} run(s), ${purged.events ?? 0} événement(s), ${purged.queue ?? 0} item(s) de file`);
1662
+ parts.push(`runtime: ${killed.runs ?? 0} run(s) stopped, ${killed.tasks ?? 0} task(s), ${killed.queued ?? 0} request(s)`);
1663
+ parts.push(`store purged: ${purged.runs ?? 0} run(s), ${purged.events ?? 0} event(s), ${purged.queue ?? 0} queue item(s)`);
1664
1664
  } catch (err) {
1665
- parts.push(`runtime kill échoué : ${err instanceof Error ? err.message : String(err)}`);
1665
+ parts.push(`runtime kill failed: ${err instanceof Error ? err.message : String(err)}`);
1666
1666
  }
1667
1667
  } else {
1668
- parts.push('runtime non connecté (rien à purger côté serveur)');
1668
+ parts.push('runtime not connected (nothing to purge server-side)');
1669
1669
  }
1670
1670
 
1671
1671
  const clearedQueue = clearFinishedQueueItems(context.session);
@@ -1686,9 +1686,9 @@ export async function handleSlashCommand(line, context) {
1686
1686
  context.session.workflow = null;
1687
1687
  context.session.jobQueue = [];
1688
1688
  context.session.productionActivity = null;
1689
- parts.push(`file locale : ${clearedQueue} item(s) terminés nettoyés`);
1689
+ parts.push(`local queue: ${clearedQueue} finished item(s) cleared`);
1690
1690
 
1691
- return { output: `Interface réinitialisée (--all) — ${parts.join(' · ')}.` };
1691
+ return { output: `Interface reset (--all) — ${parts.join(' · ')}.` };
1692
1692
  }
1693
1693
  case 'exit':
1694
1694
  case 'quit':
@@ -36,7 +36,7 @@ export async function runAgentTurn(agent, session, input, {
36
36
  if (session._abortSignal === signal) delete session._abortSignal;
37
37
  }
38
38
  if (result.streamedInline) {
39
- return streamedContent.trim() || formatLlmUnavailableMessage('flux vide');
39
+ return streamedContent.trim() || formatLlmUnavailableMessage('empty stream');
40
40
  }
41
41
  if (result.response != null) return result.response;
42
42
  if (result.readyToStream && session.llm?.stream) {
@@ -49,9 +49,9 @@ export async function runAgentTurn(agent, session, input, {
49
49
  })) {
50
50
  content += delta;
51
51
  }
52
- return content.trim() || formatLlmUnavailableMessage('flux vide');
52
+ return content.trim() || formatLlmUnavailableMessage('empty stream');
53
53
  }
54
- return formatLlmUnavailableMessage('reponse vide');
54
+ return formatLlmUnavailableMessage('empty response');
55
55
  }
56
56
 
57
57
  export async function runAgenticLoop(agent, session, initialInput, {
@@ -18,7 +18,7 @@ test('runAgentTurn returns a one-line LLM error on empty stream', async () => {
18
18
 
19
19
  const response = await runAgentTurn(agent, session, 'salut');
20
20
 
21
- assert.equal(response, '⚠ LLM injoignable : flux vide');
21
+ assert.equal(response, '⚠ LLM unavailable: empty stream');
22
22
  });
23
23
 
24
24
  test('runAgenticLoop waits for new activities and continues with a completion summary', async () => {
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.15.64",
3
- "commit": "d77449c"
2
+ "version": "0.15.66",
3
+ "commit": "d9639a4"
4
4
  }
package/src/core/mcp.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { managerEnvFile, managerMcpEndpointsFile, readEnvFile } from './env.js';
3
3
 
4
- const WIKI_MANAGER_VERSION = '0.15.64';
4
+ const WIKI_MANAGER_VERSION = '0.15.66';
5
5
 
6
6
  function envValue(key) {
7
7
  const filePath = managerEnvFile();
@@ -116,7 +116,7 @@ export async function runRuntimeAgenticLoop(agent, session, initialInput, { sign
116
116
  dispatchAgentEvent(session, createAgentEvent('assistant_message', {
117
117
  origin: 'runtime',
118
118
  runId,
119
- payload: { content: summary || 'Action terminée.' },
119
+ payload: { content: summary || 'Action completed.' },
120
120
  }));
121
121
  },
122
122
  onMaxTurns: ({ maxTurns: totalTurns }) => {
@@ -261,7 +261,7 @@ export async function runRuntimeAgenticWorkflow(agent, session, input, {
261
261
  origin: 'runtime',
262
262
  runId,
263
263
  payload: {
264
- content: `Le run est terminé mais l'évaluation le juge incomplet : ${evaluation.reason}`,
264
+ content: `The run finished but the evaluation judged it incomplete: ${evaluation.reason}`,
265
265
  },
266
266
  }));
267
267
  dispatchAgentEvent(session, createAgentEvent('run_error', {
@@ -570,10 +570,10 @@ export async function runRuntimeParallelPlan(agent, session, input, {
570
570
  runId,
571
571
  payload: {
572
572
  content: [
573
- `⏸ Approbation requise avant exécution : ${newlyRequested.length} tâche(s) mutante(s) en attente.`,
573
+ `⏸ Approval required before execution: ${newlyRequested.length} mutating task(s) pending.`,
574
574
  ...newlyRequested.slice(0, 5).map((step) => ` - ${step.description ?? step.id}`),
575
- newlyRequested.length > 5 ? ` … et ${newlyRequested.length - 5} autre(s).` : null,
576
- 'Tape /approve (ou clique sur « Approuver ») pour lancer, « annule » pour abandonner.',
575
+ newlyRequested.length > 5 ? ` … and ${newlyRequested.length - 5} more.` : null,
576
+ 'Type /approve (or click "Approve") to start, "cancel" to abandon.',
577
577
  ].filter(Boolean).join('\n'),
578
578
  },
579
579
  }));
@@ -591,7 +591,7 @@ export async function runRuntimeParallelPlan(agent, session, input, {
591
591
  origin: 'runtime',
592
592
  runId,
593
593
  payload: {
594
- content: `⏱ Approbation non reçue dans le délai imparti — run arrêté, ${needingApproval.length} tâche(s) annulée(s). Relance la demande quand tu veux.`,
594
+ content: `⏱ Approval not received in time — run stopped, ${needingApproval.length} task(s) cancelled. Ask again whenever you're ready.`,
595
595
  },
596
596
  }));
597
597
  return { ok: false, stalled: true, reason: 'awaiting_approval', completed: sessionActivities(session), failures };
@@ -865,7 +865,7 @@ test('runRuntimeParallelPlan skips work stuck behind a failed dependency instead
865
865
  // tâche disparaître sans savoir pourquoi.
866
866
  assert.match(session.headlessPlan[1].error.message, /\ba\b/);
867
867
  assert.equal(session.agentEvents.some((event) => event.type === 'assistant_message'
868
- && /Approbation requise/.test(event.payload?.content ?? '')), false);
868
+ && /Approval required/.test(event.payload?.content ?? '')), false);
869
869
  assert.equal(session.agentEvents.some((event) => event.type === 'plan_step_updated'
870
870
  && event.payload?.status === 'skipped'), true);
871
871
  });
@@ -263,16 +263,23 @@ export function PlanPanel(props: { plan: PlanStep[]; width: number; jobName?: st
263
263
 
264
264
  export function ActivityPanel(props: { activities: any[]; width: number }) {
265
265
  const lineWidth = () => Math.max(8, props.width - 2);
266
- const visible = () => props.activities.slice(-ACTIVITY_SLOTS.length).reverse();
267
- const visibleSlots = () => visible().map((_activity, index) => index);
268
- const activityAt = (index: number) => visible()[index] ?? null;
266
+ const visible = () => props.activities.slice().reverse();
269
267
  return (
270
- <box flexShrink={0} flexDirection="column" paddingX={1} backgroundColor="#111318">
268
+ <box flexGrow={1} flexDirection="column" paddingX={1} backgroundColor="#111318">
271
269
  <text width={lineWidth()} fg="#D6DEE8" content="Activity" />
272
270
  <Show when={visible().length > 0} fallback={<text width={lineWidth()} fg="#7F8C8D" content="no active jobs" />}>
273
- <Index each={visibleSlots()}>
274
- {(slot) => {
275
- const activity = () => activityAt(slot());
271
+ <scrollbox
272
+ flexGrow={1}
273
+ flexShrink={1}
274
+ focusable={false}
275
+ scrollY={true}
276
+ scrollX={false}
277
+ stickyStart="top"
278
+ viewportCulling={true}
279
+ verticalScrollbarOptions={{ visible: visible().length > 3 }}
280
+ >
281
+ <Index each={visible()}>
282
+ {(activity) => {
276
283
  // Wrap instead of hard-truncating: a 40-column pane cut labels to
277
284
  // "Appliquer la config recommandée (doct…" and hid the one thing
278
285
  // that mattered. Labels get up to 2 lines, the status/error line
@@ -320,6 +327,7 @@ export function ActivityPanel(props: { activities: any[]; width: number }) {
320
327
  );
321
328
  }}
322
329
  </Index>
330
+ </scrollbox>
323
331
  </Show>
324
332
  </box>
325
333
  );
@@ -536,8 +544,8 @@ export function RightPane(props: {
536
544
  <TabHeader active={props.activeTab} queueCount={props.queueInfo.active} onTabClick={props.onTabClick} />
537
545
  <Show when={props.pendingApprovals.length > 0}>
538
546
  <box height={2} flexDirection="column" border={['left']} borderStyle="heavy" borderColor="#FBBF24" paddingX={1}>
539
- <text fg="#FBBF24" content={`${props.pendingApprovals.length} approbation(s) requise(s)`} />
540
- <text fg="#0B1020" bg="#FBBF24" content=" Approuver le run " onMouseUp={props.onApprove} />
547
+ <text fg="#FBBF24" content={`${props.pendingApprovals.length} approval(s) required`} />
548
+ <text fg="#0B1020" bg="#FBBF24" content=" Approve run " onMouseUp={props.onApprove} />
541
549
  </box>
542
550
  </Show>
543
551
  <Show when={props.activeTab === 'queue'} fallback={(
package/src/shell/repl.js CHANGED
@@ -127,12 +127,12 @@ const SUBCOMMAND_COMPLETION_DESCRIPTIONS = {
127
127
  export function runtimeUnavailableReason(runtime) {
128
128
  if (runtime?.url) return null;
129
129
  const reason = runtime?.error ?? runtime?.unavailableReason ?? runtime?.reason ?? null;
130
- return reason ? String(reason) : 'runtime introuvable';
130
+ return reason ? String(reason) : 'runtime unavailable';
131
131
  }
132
132
 
133
133
  export function runtimeUnavailableAgentMessage(runtime) {
134
134
  const reason = runtimeUnavailableReason(runtime);
135
- return reason ? `⚠ Runtime indisponible : ${reason} — /agent désactivé, /chat reste possible` : null;
135
+ return reason ? `⚠ Runtime unavailable: ${reason} — /agent disabled, /chat still available` : null;
136
136
  }
137
137
 
138
138
  export function runtimeStatusLine(runtime, session) {
@@ -145,7 +145,7 @@ export function runtimeStatusLine(runtime, session) {
145
145
  export function recordRuntimeUnavailableAgentInput(session, line, runtime) {
146
146
  const message = runtimeUnavailableAgentMessage(runtime);
147
147
  conversationMessages(session).push({ role: 'user', content: line });
148
- conversationMessages(session).push({ role: 'command', content: message ?? 'Runtime indisponible.' });
148
+ conversationMessages(session).push({ role: 'command', content: message ?? 'Runtime unavailable.' });
149
149
  return message;
150
150
  }
151
151
 
@@ -1422,10 +1422,10 @@ async function runAgentTurn(input, {
1422
1422
  if (donnaMessage) {
1423
1423
  donnaMessage.content = stripDsmlArtifacts(donnaMessage.content).trimEnd();
1424
1424
  if (!donnaMessage.content.trim()) {
1425
- donnaMessage.content = formatLlmUnavailableMessage('flux vide');
1425
+ donnaMessage.content = formatLlmUnavailableMessage('empty stream');
1426
1426
  }
1427
1427
  } else {
1428
- messages.push({ role: 'donna', content: formatLlmUnavailableMessage('flux vide') });
1428
+ messages.push({ role: 'donna', content: formatLlmUnavailableMessage('empty stream') });
1429
1429
  }
1430
1430
  onUpdate?.();
1431
1431
  return {};
@@ -1464,7 +1464,7 @@ async function runAgentTurn(input, {
1464
1464
  }
1465
1465
  donnaMessage.content = stripDsmlArtifacts(donnaMessage.content).trimEnd();
1466
1466
  if (!donnaMessage.content.trim()) {
1467
- donnaMessage.content = formatLlmUnavailableMessage('flux vide');
1467
+ donnaMessage.content = formatLlmUnavailableMessage('empty stream');
1468
1468
  onUpdate?.();
1469
1469
  }
1470
1470
  } catch (err) {
@@ -1481,9 +1481,9 @@ async function runAgentTurn(input, {
1481
1481
  }
1482
1482
 
1483
1483
  if (donnaMessage) {
1484
- donnaMessage.content = formatLlmUnavailableMessage('reponse vide');
1484
+ donnaMessage.content = formatLlmUnavailableMessage('empty response');
1485
1485
  } else {
1486
- messages.push({ role: 'donna', content: formatLlmUnavailableMessage('reponse vide') });
1486
+ messages.push({ role: 'donna', content: formatLlmUnavailableMessage('empty response') });
1487
1487
  }
1488
1488
  onUpdate?.();
1489
1489
  return {};
@@ -1533,8 +1533,8 @@ async function runChatToolLoop({ input, session, history, donnaMessage, onUpdate
1533
1533
  onTextReset,
1534
1534
  });
1535
1535
  donnaMessage.content = capped
1536
- ? 'Je n’ai pas pu conclure dans la limite d’itérations du mode chat. Passe en /agent si besoin.'
1537
- : (stripDsmlArtifacts(content).trimEnd() || formatLlmUnavailableMessage('reponse vide'));
1536
+ ? 'Could not finish within the chat mode iteration limit. Switch to /agent if needed.'
1537
+ : (stripDsmlArtifacts(content).trimEnd() || formatLlmUnavailableMessage('empty response'));
1538
1538
  onUpdate?.();
1539
1539
  }
1540
1540
 
@@ -1580,7 +1580,7 @@ async function runDirectChatTurn(input, { session, onUpdate, onStep }) {
1580
1580
  }
1581
1581
  donnaMessage.content = stripDsmlArtifacts(donnaMessage.content).trimEnd();
1582
1582
  if (!donnaMessage.content.trim()) {
1583
- donnaMessage.content = formatLlmUnavailableMessage('flux vide');
1583
+ donnaMessage.content = formatLlmUnavailableMessage('empty stream');
1584
1584
  onUpdate?.();
1585
1585
  }
1586
1586
  }
@@ -1639,7 +1639,7 @@ export async function runHeadlessChatTurn(session, input, { history = [], onStep
1639
1639
  const clean = stripDsmlArtifacts(delta);
1640
1640
  if (clean) { content += clean; onTextDelta?.(clean); }
1641
1641
  }
1642
- return stripDsmlArtifacts(content).trimEnd() || formatLlmUnavailableMessage('flux vide');
1642
+ return stripDsmlArtifacts(content).trimEnd() || formatLlmUnavailableMessage('empty stream');
1643
1643
  }
1644
1644
  return directChatUnavailableText(session);
1645
1645
  }
@@ -114,7 +114,7 @@ test('Activity uses only visible jobs and leaves remaining height to Flow/Trace'
114
114
  source.indexOf('export function ActivityPanel'),
115
115
  source.indexOf('type LogSegment'),
116
116
  );
117
- assert.match(activityPanel, /<Index each=\{visibleSlots\(\)\}>/);
117
+ assert.match(activityPanel, /<Index each=\{visible\(\)\}>/);
118
118
  assert.doesNotMatch(activityPanel, /<Index each=\{ACTIVITY_SLOTS\}>/);
119
119
  assert.match(activityPanel, /paddingX=\{1\}/);
120
120
  assert.doesNotMatch(activityPanel, /updatedLine\(activity\(\)\)/);
@@ -144,7 +144,7 @@ test('ShellUI launcher never starts agents or workspace services implicitly', as
144
144
  test('ShellUI lets the right pane extend to the terminal edge', async () => {
145
145
  const tui = await readFile(new URL('./tui.tsx', import.meta.url), 'utf8');
146
146
  const pane = await readFile(new URL('./RightPane.tsx', import.meta.url), 'utf8');
147
- assert.match(tui, /Math\.min\(58, Math\.floor\(width \* 0\.38\) \+ 2\)/);
147
+ assert.match(tui, /Math\.max\(32, Math\.floor\(width \* 0\.38\) \+ 2\)/);
148
148
  assert.match(pane, /paddingLeft=\{1\}/);
149
149
  assert.doesNotMatch(pane, /height="100%" flexDirection="column" padding=\{1\}/);
150
150
  });
@@ -742,7 +742,7 @@ test('agent mode without runtime records a visible error instead of falling back
742
742
 
743
743
  const message = recordRuntimeUnavailableAgentInput(session, 'salut', { error: 'port 7788 already in use' });
744
744
 
745
- assert.equal(message, '⚠ Runtime indisponible : port 7788 already in use — /agent désactivé, /chat reste possible');
745
+ assert.equal(message, '⚠ Runtime unavailable: port 7788 already in use — /agent disabled, /chat still available');
746
746
  // `at` est posé à l'insertion : on compare le reste.
747
747
  assert.deepEqual(
748
748
  conversationMessages(session).map(({ at, ...rest }) => rest),
@@ -760,7 +760,7 @@ test('runtime status exposes the disconnected reason', () => {
760
760
  );
761
761
  assert.equal(
762
762
  runtimeUnavailableAgentMessage({ error: 'token mismatch' }),
763
- '⚠ Runtime indisponible : token mismatch — /agent désactivé, /chat reste possible',
763
+ '⚠ Runtime unavailable: token mismatch — /agent disabled, /chat still available',
764
764
  );
765
765
  });
766
766
 
@@ -806,7 +806,7 @@ test('/queue cancel on a runtime workflow id points to run cancellation commands
806
806
  });
807
807
 
808
808
  assert.equal(result.exit, false);
809
- assert.match(conversationMessages(session).at(-1).content, /Item géré par le runtime/);
809
+ assert.match(conversationMessages(session).at(-1).content, /Runtime-managed item/);
810
810
  assert.match(conversationMessages(session).at(-1).content, /\/run kill/);
811
811
  });
812
812
 
package/src/shell/tui.tsx CHANGED
@@ -156,7 +156,7 @@ function App(props: {
156
156
  const exitShell = () => {
157
157
  if (exiting) return;
158
158
  exiting = true;
159
- setExitStatus('Fermeture enclenchée…');
159
+ setExitStatus('Shutting down…');
160
160
  const task = Promise.resolve().then(async () => {
161
161
  renderer.destroy();
162
162
  console.log('[wiki-manager] shell closed; shared runtime left running.');
@@ -180,11 +180,11 @@ function App(props: {
180
180
  const conversationRows = createMemo(() => Math.max(4, dimensions().height - 5 - chatInputHeight() - 4));
181
181
  const rightColumns = createMemo(() => {
182
182
  const width = dimensions().width;
183
- // 38% + 2 columns / cap 58: the Plan/Activity/Logs panes carry job
184
- // labels, file names and error messages — 40 columns truncated everything
185
- // into unreadable stubs. The small addition uses the terminal's right-side
186
- // slack without making the conversation pane noticeably narrower.
187
- return Math.max(32, Math.min(58, Math.floor(width * 0.38) + 2));
183
+ // 38% + 2 columns: the Plan/Activity/Logs panes carry job labels, file
184
+ // names and error messages. The pane scales with the terminal instead of
185
+ // being capped, so a wide screen widens the detail pane rather than leaving
186
+ // it narrow while the conversation column absorbs all the extra slack.
187
+ return Math.max(32, Math.floor(width * 0.38) + 2);
188
188
  });
189
189
  const leftColumns = createMemo(() => Math.max(32, dimensions().width - rightColumns() - 1));
190
190
  const conversationColumns = createMemo(() => {
@@ -52,7 +52,7 @@ export function useAgent(props: { agent: unknown; packageJson: Record<string, un
52
52
  }
53
53
  if (!props.chatMode() && !trimmed.startsWith('/') && !freeTextRouting?.local) {
54
54
  const message = recordRuntimeUnavailableAgentInput(props.session, trimmed, {
55
- error: props.runtimeUnavailableReason ?? 'runtime introuvable',
55
+ error: props.runtimeUnavailableReason ?? 'runtime unavailable',
56
56
  });
57
57
  props.addLog(message ?? 'runtime: disconnected');
58
58
  props.refresh();
@@ -158,7 +158,7 @@ export function useSession(props: { agent: unknown; packageJson: Record<string,
158
158
  const runtimeHint = createMemo(() => {
159
159
  version();
160
160
  if (props.runtime?.url) return null;
161
- return runtimeUnavailableAgentMessage({ error: runtimeUnavailableReason() ?? 'runtime introuvable' });
161
+ return runtimeUnavailableAgentMessage({ error: runtimeUnavailableReason() ?? 'runtime unavailable' });
162
162
  });
163
163
  const matchContext = createMemo(() => {
164
164
  if (input() === dismissedSlashInput()) return null;