@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 +1 -1
- package/src/agent/graph.js +3 -3
- package/src/agent/graph.test.js +1 -1
- package/src/commands/slash.js +11 -11
- package/src/core/agentLoop.js +3 -3
- package/src/core/agentLoop.test.js +1 -1
- package/src/core/buildInfo.json +2 -2
- package/src/core/mcp.js +1 -1
- package/src/runtime/runner.js +6 -6
- package/src/runtime/runner.test.js +1 -1
- package/src/shell/RightPane.tsx +17 -9
- package/src/shell/repl.js +12 -12
- package/src/shell/repl.test.js +5 -5
- package/src/shell/tui.tsx +6 -6
- package/src/shell/useAgent.ts +1 -1
- package/src/shell/useSession.ts +1 -1
package/package.json
CHANGED
package/src/agent/graph.js
CHANGED
|
@@ -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 ?? '
|
|
1299
|
-
return `⚠ LLM
|
|
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('
|
|
1458
|
+
return { response: formatLlmUnavailableMessage('no LLM client configured'), pendingToolCalls: null, readyToStream: false };
|
|
1459
1459
|
}
|
|
1460
1460
|
|
|
1461
1461
|
const iterations = state.toolIterations ?? 0;
|
package/src/agent/graph.test.js
CHANGED
|
@@ -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
|
|
295
|
+
assert.equal(result.response, '⚠ LLM unavailable: no LLM client configured');
|
|
296
296
|
assert.doesNotMatch(result.response, /Donna is active/);
|
|
297
297
|
});
|
|
298
298
|
|
package/src/commands/slash.js
CHANGED
|
@@ -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(`
|
|
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: `▶
|
|
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
|
|
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 || '
|
|
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: '
|
|
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
|
|
1663
|
-
parts.push(`store
|
|
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
|
|
1665
|
+
parts.push(`runtime kill failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1666
1666
|
}
|
|
1667
1667
|
} else {
|
|
1668
|
-
parts.push('runtime
|
|
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(`
|
|
1689
|
+
parts.push(`local queue: ${clearedQueue} finished item(s) cleared`);
|
|
1690
1690
|
|
|
1691
|
-
return { output: `Interface
|
|
1691
|
+
return { output: `Interface reset (--all) — ${parts.join(' · ')}.` };
|
|
1692
1692
|
}
|
|
1693
1693
|
case 'exit':
|
|
1694
1694
|
case 'quit':
|
package/src/core/agentLoop.js
CHANGED
|
@@ -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('
|
|
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('
|
|
52
|
+
return content.trim() || formatLlmUnavailableMessage('empty stream');
|
|
53
53
|
}
|
|
54
|
-
return formatLlmUnavailableMessage('
|
|
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
|
|
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 () => {
|
package/src/core/buildInfo.json
CHANGED
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.
|
|
4
|
+
const WIKI_MANAGER_VERSION = '0.15.66';
|
|
5
5
|
|
|
6
6
|
function envValue(key) {
|
|
7
7
|
const filePath = managerEnvFile();
|
package/src/runtime/runner.js
CHANGED
|
@@ -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
|
|
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: `
|
|
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
|
-
`⏸
|
|
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 ? ` …
|
|
576
|
-
'
|
|
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: `⏱
|
|
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
|
-
&& /
|
|
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
|
});
|
package/src/shell/RightPane.tsx
CHANGED
|
@@ -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(
|
|
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
|
|
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
|
-
<
|
|
274
|
-
{
|
|
275
|
-
|
|
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}
|
|
540
|
-
<text fg="#0B1020" bg="#FBBF24" content="
|
|
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
|
|
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
|
|
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
|
|
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('
|
|
1425
|
+
donnaMessage.content = formatLlmUnavailableMessage('empty stream');
|
|
1426
1426
|
}
|
|
1427
1427
|
} else {
|
|
1428
|
-
messages.push({ role: 'donna', content: formatLlmUnavailableMessage('
|
|
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('
|
|
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('
|
|
1484
|
+
donnaMessage.content = formatLlmUnavailableMessage('empty response');
|
|
1485
1485
|
} else {
|
|
1486
|
-
messages.push({ role: 'donna', content: formatLlmUnavailableMessage('
|
|
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
|
-
? '
|
|
1537
|
-
: (stripDsmlArtifacts(content).trimEnd() || formatLlmUnavailableMessage('
|
|
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('
|
|
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('
|
|
1642
|
+
return stripDsmlArtifacts(content).trimEnd() || formatLlmUnavailableMessage('empty stream');
|
|
1643
1643
|
}
|
|
1644
1644
|
return directChatUnavailableText(session);
|
|
1645
1645
|
}
|
package/src/shell/repl.test.js
CHANGED
|
@@ -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=\{
|
|
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\.
|
|
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
|
|
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
|
|
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, /
|
|
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('
|
|
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
|
|
184
|
-
//
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
return Math.max(32, Math.
|
|
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(() => {
|
package/src/shell/useAgent.ts
CHANGED
|
@@ -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
|
|
55
|
+
error: props.runtimeUnavailableReason ?? 'runtime unavailable',
|
|
56
56
|
});
|
|
57
57
|
props.addLog(message ?? 'runtime: disconnected');
|
|
58
58
|
props.refresh();
|
package/src/shell/useSession.ts
CHANGED
|
@@ -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
|
|
161
|
+
return runtimeUnavailableAgentMessage({ error: runtimeUnavailableReason() ?? 'runtime unavailable' });
|
|
162
162
|
});
|
|
163
163
|
const matchContext = createMemo(() => {
|
|
164
164
|
if (input() === dismissedSlashInput()) return null;
|