@namzu/cli 16.0.0 → 17.0.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.
- package/README.md +34 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +43 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/drain.d.ts.map +1 -1
- package/dist/commands/drain.js +23 -1
- package/dist/commands/drain.js.map +1 -1
- package/dist/commands/run-stream.d.ts +3 -2
- package/dist/commands/run-stream.d.ts.map +1 -1
- package/dist/commands/run-stream.js +32 -37
- package/dist/commands/run-stream.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +26 -24
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/state.d.ts +9 -0
- package/dist/commands/state.d.ts.map +1 -0
- package/dist/commands/state.js +110 -0
- package/dist/commands/state.js.map +1 -0
- package/dist/config/load.d.ts +1 -1
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +3 -4
- package/dist/config/load.js.map +1 -1
- package/dist/doctor/checks/chain.d.ts +1 -1
- package/dist/doctor/checks/chain.d.ts.map +1 -1
- package/dist/doctor/checks/chain.js +2 -4
- package/dist/doctor/checks/chain.js.map +1 -1
- package/dist/integrations/files/attachment-store.d.ts.map +1 -1
- package/dist/integrations/files/attachment-store.js +3 -3
- package/dist/integrations/files/attachment-store.js.map +1 -1
- package/dist/integrations/plugins/runtime.d.ts.map +1 -1
- package/dist/integrations/plugins/runtime.js +4 -2
- package/dist/integrations/plugins/runtime.js.map +1 -1
- package/dist/integrations/providers/credential-store.d.ts.map +1 -1
- package/dist/integrations/providers/credential-store.js +13 -12
- package/dist/integrations/providers/credential-store.js.map +1 -1
- package/dist/integrations/providers/preferences.d.ts.map +1 -1
- package/dist/integrations/providers/preferences.js +5 -5
- package/dist/integrations/providers/preferences.js.map +1 -1
- package/dist/integrations/sessions/store.d.ts +31 -9
- package/dist/integrations/sessions/store.d.ts.map +1 -1
- package/dist/integrations/sessions/store.js +308 -63
- package/dist/integrations/sessions/store.js.map +1 -1
- package/dist/integrations/state/home.d.ts +25 -0
- package/dist/integrations/state/home.d.ts.map +1 -0
- package/dist/integrations/state/home.js +53 -0
- package/dist/integrations/state/home.js.map +1 -0
- package/dist/integrations/state/private-directory.d.ts +15 -0
- package/dist/integrations/state/private-directory.d.ts.map +1 -0
- package/dist/integrations/state/private-directory.js +41 -0
- package/dist/integrations/state/private-directory.js.map +1 -0
- package/dist/integrations/state/report.d.ts +129 -0
- package/dist/integrations/state/report.d.ts.map +1 -0
- package/dist/integrations/state/report.js +831 -0
- package/dist/integrations/state/report.js.map +1 -0
- package/dist/integrations/subagents/activity.d.ts +18 -0
- package/dist/integrations/subagents/activity.d.ts.map +1 -1
- package/dist/integrations/subagents/activity.js +64 -7
- package/dist/integrations/subagents/activity.js.map +1 -1
- package/dist/integrations/subagents/runtime.d.ts +3 -1
- package/dist/integrations/subagents/runtime.d.ts.map +1 -1
- package/dist/integrations/subagents/runtime.js +46 -7
- package/dist/integrations/subagents/runtime.js.map +1 -1
- package/dist/integrations/trust/store.d.ts.map +1 -1
- package/dist/integrations/trust/store.js +6 -6
- package/dist/integrations/trust/store.js.map +1 -1
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +7 -7
- package/dist/memory/store.js.map +1 -1
- package/dist/skills/store.d.ts +2 -1
- package/dist/skills/store.d.ts.map +1 -1
- package/dist/skills/store.js +11 -4
- package/dist/skills/store.js.map +1 -1
- package/dist/tui/AgentExplorer.d.ts +26 -5
- package/dist/tui/AgentExplorer.d.ts.map +1 -1
- package/dist/tui/AgentExplorer.js +125 -14
- package/dist/tui/AgentExplorer.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +263 -96
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/agent.d.ts +10 -2
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +87 -21
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/slashCommands.d.ts +1 -1
- package/dist/tui/slashCommands.d.ts.map +1 -1
- package/dist/tui/slashCommands.js +2 -2
- package/dist/tui/slashCommands.js.map +1 -1
- package/dist/user-commands/store.d.ts.map +1 -1
- package/dist/user-commands/store.js +29 -7
- package/dist/user-commands/store.js.map +1 -1
- package/package.json +2 -2
package/dist/tui/App.js
CHANGED
|
@@ -12,7 +12,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
12
12
|
* automatic reuse is not mistaken for a durable operator preference.
|
|
13
13
|
*/
|
|
14
14
|
import { join, relative } from 'node:path';
|
|
15
|
-
import { DiskMessageFeedbackStore, GoalRoundLimitError, HostCommandRegistry, RunCancelled, SessionGoalActivation, StaleGoalError, asSessionId, createAssistantMessage, createUserMessage, generateRunId, isCompactionMessage, kernelHostCommands, } from '@namzu/sdk';
|
|
15
|
+
import { DefaultPathBuilder, DiskMessageFeedbackStore, GoalRoundLimitError, HostCommandRegistry, RunCancelled, SessionGoalActivation, StaleGoalError, asSessionId, createAssistantMessage, createUserMessage, generateRunId, generateSessionId, isCompactionMessage, kernelHostCommands, } from '@namzu/sdk';
|
|
16
16
|
import { Box, Text, useApp, useInput, useStdout, useWindowSize } from 'ink';
|
|
17
17
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
18
18
|
import { pinTrustedProjectPath, resolveTrustedProjectContext, } from '../config/trusted-project-context.js';
|
|
@@ -28,7 +28,7 @@ import { checkUpdates } from '../integrations/updates.js';
|
|
|
28
28
|
import { appendMemory, composeMemoryPrompt, readMemory } from '../memory/store.js';
|
|
29
29
|
import { composeSkillsPrompt, discoverSkills, loadSkillBody } from '../skills/store.js';
|
|
30
30
|
import { discoverUserCommands } from '../user-commands/store.js';
|
|
31
|
-
import {
|
|
31
|
+
import { AgentCockpit, AgentTranscript, agentCockpitIsWide, agentPickerPageSize, agentPhasePageSize, agentPhases, agentTranscriptPageSize, maxAgentTranscriptTailOffset, } from './AgentExplorer.js';
|
|
32
32
|
import { ChoicePicker } from './ChoicePicker.js';
|
|
33
33
|
import { Composer, suggestionWindowSize, } from './Composer.js';
|
|
34
34
|
import { CopyPicker } from './CopyPicker.js';
|
|
@@ -462,9 +462,21 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
462
462
|
subagentsRef.current = next;
|
|
463
463
|
setSubagentsState(next);
|
|
464
464
|
const surface = agentSurfaceRef.current;
|
|
465
|
-
if (surface
|
|
465
|
+
if (!surface || next.some((agent) => agent.viewId === surface.selectedId))
|
|
466
|
+
return;
|
|
467
|
+
const phases = agentPhases(next);
|
|
468
|
+
const fallbackPhase = phases.find((phase) => phase.id === surface.selectedPhaseId) ?? phases[0];
|
|
469
|
+
const fallbackAgent = fallbackPhase?.agents[0];
|
|
470
|
+
if (!fallbackPhase || !fallbackAgent) {
|
|
466
471
|
setAgentSurface(null);
|
|
472
|
+
return;
|
|
467
473
|
}
|
|
474
|
+
setAgentSurface({
|
|
475
|
+
kind: 'cockpit',
|
|
476
|
+
selectedPhaseId: fallbackPhase.id,
|
|
477
|
+
selectedId: fallbackAgent.viewId,
|
|
478
|
+
focus: surface.kind === 'cockpit' ? surface.focus : surface.returnFocus,
|
|
479
|
+
});
|
|
468
480
|
}, [setAgentSurface]);
|
|
469
481
|
/** One git-backed review choice may be resolving while its visible picker remains authoritative. */
|
|
470
482
|
const reviewChoiceInFlightRef = useRef(null);
|
|
@@ -551,9 +563,19 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
551
563
|
// turns attribute to the resumed conversation.
|
|
552
564
|
const sessionsRef = useRef(null);
|
|
553
565
|
const scopeRef = useRef(null);
|
|
566
|
+
/**
|
|
567
|
+
* A provider session can be ready before a person has started a conversation.
|
|
568
|
+
* The scope still needs a mutable session cursor, but its generated id is
|
|
569
|
+
* provisional until the first admitted prompt or an explicit conversation
|
|
570
|
+
* operation publishes the durable Session.
|
|
571
|
+
*/
|
|
572
|
+
const conversationMaterializedRef = useRef(false);
|
|
573
|
+
const materializationRef = useRef(null);
|
|
554
574
|
const exitWithSummary = useCallback(() => {
|
|
555
575
|
onExitSummary?.({
|
|
556
|
-
...(
|
|
576
|
+
...(conversationMaterializedRef.current && scopeRef.current?.sessionId
|
|
577
|
+
? { conversationId: scopeRef.current.sessionId }
|
|
578
|
+
: {}),
|
|
557
579
|
});
|
|
558
580
|
exit();
|
|
559
581
|
}, [exit, onExitSummary]);
|
|
@@ -830,12 +852,21 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
830
852
|
}
|
|
831
853
|
applyReasoningEffort(next);
|
|
832
854
|
}, [applyReasoningEffort, pushMessage, session]);
|
|
833
|
-
const recordFeedback = useCallback((runIdValue, messageIdValue, rating, note) => {
|
|
834
|
-
|
|
835
|
-
|
|
855
|
+
const recordFeedback = useCallback((sessionId, runIdValue, messageIdValue, rating, note) => {
|
|
856
|
+
const sessions = sessionsRef.current;
|
|
857
|
+
if (!sessions) {
|
|
858
|
+
pushMessage('system', 'Could not record feedback: conversation persistence is unavailable.');
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
// Run evidence is session-scoped in the canonical store. The old flat
|
|
862
|
+
// `<cwd>/.namzu/runs` lookup never existed after the hierarchy migration,
|
|
863
|
+
// so the feedback store correctly refused every TUI rating as unverifiable.
|
|
864
|
+
// Bind both trees to the exact conversation captured with the streamed
|
|
865
|
+
// message; `/resume` may change the active scope before a delayed click.
|
|
866
|
+
const sessionDir = new DefaultPathBuilder(sessions.root).sessionDir(sessions.projectId, sessionId);
|
|
836
867
|
const store = new DiskMessageFeedbackStore({
|
|
837
|
-
rootDir: join(
|
|
838
|
-
runsDir: join(
|
|
868
|
+
rootDir: join(sessionDir, 'feedback'),
|
|
869
|
+
runsDir: join(sessionDir, 'runs'),
|
|
839
870
|
});
|
|
840
871
|
const runId = runIdValue;
|
|
841
872
|
const messageId = messageIdValue;
|
|
@@ -857,7 +888,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
857
888
|
pushMessage('system', `Could not record feedback: ${error instanceof Error ? error.message : String(error)}`);
|
|
858
889
|
}
|
|
859
890
|
})();
|
|
860
|
-
}, [
|
|
891
|
+
}, [pushMessage]);
|
|
861
892
|
const activateSkill = useCallback((name) => {
|
|
862
893
|
const info = discoverSkills({ cwd: ctx.cwd }).find((skill) => skill.name === name);
|
|
863
894
|
if (!info) {
|
|
@@ -904,8 +935,10 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
904
935
|
return;
|
|
905
936
|
const sessions = sessionsRef.current;
|
|
906
937
|
const sessionId = scopeRef.current?.sessionId;
|
|
907
|
-
if (!sessions || !sessionId) {
|
|
908
|
-
pushMessage('system',
|
|
938
|
+
if (!sessions || !sessionId || !conversationMaterializedRef.current) {
|
|
939
|
+
pushMessage('system', !conversationMaterializedRef.current
|
|
940
|
+
? 'There is no conversation to archive yet — send a message first.'
|
|
941
|
+
: 'Cannot archive this conversation because durable session persistence is unavailable.');
|
|
909
942
|
return;
|
|
910
943
|
}
|
|
911
944
|
if (state !== 'idle' ||
|
|
@@ -956,8 +989,10 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
956
989
|
const stableExportSource = useCallback(() => {
|
|
957
990
|
const sessions = sessionsRef.current;
|
|
958
991
|
const sessionId = scopeRef.current?.sessionId;
|
|
959
|
-
if (!sessions || !sessionId) {
|
|
960
|
-
pushMessage('system',
|
|
992
|
+
if (!sessions || !sessionId || !conversationMaterializedRef.current) {
|
|
993
|
+
pushMessage('system', !conversationMaterializedRef.current
|
|
994
|
+
? 'There is no conversation to export yet — send a message first.'
|
|
995
|
+
: 'Cannot export this conversation because durable session persistence is unavailable.');
|
|
961
996
|
return null;
|
|
962
997
|
}
|
|
963
998
|
if (abortRef.current ||
|
|
@@ -1204,7 +1239,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
1204
1239
|
return;
|
|
1205
1240
|
}
|
|
1206
1241
|
if (picker.kind === 'feedback-rating') {
|
|
1207
|
-
recordFeedback(picker.runId, picker.messageId, value);
|
|
1242
|
+
recordFeedback(picker.sessionId, picker.runId, picker.messageId, value);
|
|
1208
1243
|
return;
|
|
1209
1244
|
}
|
|
1210
1245
|
if (picker.kind === 'skill') {
|
|
@@ -1303,45 +1338,81 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
1303
1338
|
setMessages((prev) => prev.map((m) => m.id === id ? { ...m, content: finalContent ?? m.content, pending: false } : m));
|
|
1304
1339
|
}, []);
|
|
1305
1340
|
// Open the SDK session store and select the durable conversation once.
|
|
1306
|
-
//
|
|
1307
|
-
//
|
|
1341
|
+
// This is an admission gate for every startup, not optional persistence: a
|
|
1342
|
+
// corrupt or split estate must not silently widen into cwd-local state and
|
|
1343
|
+
// let the model run against a different history than the operator selected.
|
|
1308
1344
|
const ensureSessions = useCallback(async () => {
|
|
1309
1345
|
if (scopeRef.current)
|
|
1310
1346
|
return scopeRef.current;
|
|
1311
1347
|
const requestedConversationId = initialConversationIdRef.current;
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1348
|
+
const sessions = await openSessions(ctxRef.current.cwd);
|
|
1349
|
+
let sessionId;
|
|
1350
|
+
if (requestedConversationId) {
|
|
1351
|
+
const restored = await loadResumableConversation(sessions, requestedConversationId);
|
|
1352
|
+
sessionId = asSessionId(requestedConversationId);
|
|
1353
|
+
modelHistoryRef.current = restored;
|
|
1354
|
+
setMessages(projectConversation(restored, nextId));
|
|
1355
|
+
setHistory(promptHistoryFromConversation(restored));
|
|
1356
|
+
const persistedOutput = latestAssistantOutput(restored);
|
|
1357
|
+
lastCompletedOutputRef.current = persistedOutput
|
|
1358
|
+
? { text: persistedOutput, provenance: 'persisted' }
|
|
1359
|
+
: null;
|
|
1360
|
+
initialConversationIdRef.current = undefined;
|
|
1361
|
+
conversationMaterializedRef.current = true;
|
|
1362
|
+
}
|
|
1363
|
+
else {
|
|
1364
|
+
// Provider/tool startup needs stable project/tenant/topic ids, not a
|
|
1365
|
+
// durable conversation. The cursor is replaced on first admitted use.
|
|
1366
|
+
sessionId = generateSessionId();
|
|
1367
|
+
}
|
|
1368
|
+
sessionsRef.current = sessions;
|
|
1369
|
+
scopeRef.current = {
|
|
1370
|
+
sessionId,
|
|
1371
|
+
topicId: sessions.topicId,
|
|
1372
|
+
projectId: sessions.projectId,
|
|
1373
|
+
tenantId: sessions.tenantId,
|
|
1374
|
+
};
|
|
1375
|
+
return scopeRef.current;
|
|
1376
|
+
}, [nextId]);
|
|
1377
|
+
/** Publish the provisional conversation exactly once, at first durable use. */
|
|
1378
|
+
const materializeConversation = useCallback(async () => {
|
|
1379
|
+
const existing = await ensureSessions();
|
|
1380
|
+
if (!existing)
|
|
1381
|
+
return undefined;
|
|
1382
|
+
if (conversationMaterializedRef.current)
|
|
1383
|
+
return existing;
|
|
1384
|
+
if (materializationRef.current)
|
|
1385
|
+
return materializationRef.current;
|
|
1386
|
+
const pending = (async () => {
|
|
1387
|
+
const sessions = sessionsRef.current;
|
|
1388
|
+
const scope = scopeRef.current;
|
|
1389
|
+
if (!sessions || !scope)
|
|
1390
|
+
return undefined;
|
|
1391
|
+
conversationMutationRef.current = 'materialize';
|
|
1392
|
+
try {
|
|
1393
|
+
const sessionId = await startConversation(sessions);
|
|
1394
|
+
if (scopeRef.current !== scope || conversationMaterializedRef.current) {
|
|
1395
|
+
throw new Error('the active conversation changed while its first session was published');
|
|
1396
|
+
}
|
|
1397
|
+
scope.sessionId = sessionId;
|
|
1398
|
+
conversationMaterializedRef.current = true;
|
|
1399
|
+
return scope;
|
|
1326
1400
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1401
|
+
finally {
|
|
1402
|
+
if (conversationMutationRef.current === 'materialize') {
|
|
1403
|
+
conversationMutationRef.current = null;
|
|
1404
|
+
}
|
|
1329
1405
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
projectId: sessions.projectId,
|
|
1335
|
-
tenantId: sessions.tenantId,
|
|
1336
|
-
};
|
|
1337
|
-
return scopeRef.current;
|
|
1406
|
+
})();
|
|
1407
|
+
materializationRef.current = pending;
|
|
1408
|
+
try {
|
|
1409
|
+
return await pending;
|
|
1338
1410
|
}
|
|
1339
|
-
|
|
1340
|
-
if (
|
|
1341
|
-
|
|
1342
|
-
return undefined;
|
|
1411
|
+
finally {
|
|
1412
|
+
if (materializationRef.current === pending)
|
|
1413
|
+
materializationRef.current = null;
|
|
1343
1414
|
}
|
|
1344
|
-
}, [
|
|
1415
|
+
}, [ensureSessions]);
|
|
1345
1416
|
const hydrateSession = useCallback(async (prefs, detectedNow, signal) => {
|
|
1346
1417
|
if (signal?.aborted)
|
|
1347
1418
|
return;
|
|
@@ -1352,6 +1423,9 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
1352
1423
|
const s = await createAgentSession(prefs, detectedNow, {
|
|
1353
1424
|
scope,
|
|
1354
1425
|
cwd: activeCtx.cwd,
|
|
1426
|
+
...(sessionsRef.current?.backend === 'central'
|
|
1427
|
+
? { stateRoot: sessionsRef.current.root }
|
|
1428
|
+
: {}),
|
|
1355
1429
|
enableComputerUse: true,
|
|
1356
1430
|
rules: activeCtx.rules,
|
|
1357
1431
|
...(sessionsRef.current ? { sessionGoals: sessionsRef.current.goals } : {}),
|
|
@@ -1985,11 +2059,16 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
1985
2059
|
setMessages(restored);
|
|
1986
2060
|
modelHistoryRef.current = msgs;
|
|
1987
2061
|
setHistory((previous) => [...previous, ...promptHistoryFromConversation(msgs)]);
|
|
2062
|
+
// Persisted conversation rows do not carry the live run/message identity
|
|
2063
|
+
// required by feedback validation. Do not leave the answer from the
|
|
2064
|
+
// conversation we just exited as a hidden `/feedback` target.
|
|
2065
|
+
lastAssistantMessage.current = null;
|
|
1988
2066
|
const persistedOutput = latestAssistantOutput(msgs);
|
|
1989
2067
|
lastCompletedOutputRef.current = persistedOutput
|
|
1990
2068
|
? { text: persistedOutput, provenance: 'persisted' }
|
|
1991
2069
|
: null;
|
|
1992
2070
|
scope.sessionId = conv.id; // new turns now attribute to the resumed session
|
|
2071
|
+
conversationMaterializedRef.current = true;
|
|
1993
2072
|
pushMessage('system', `Resumed: ${conv.title}`);
|
|
1994
2073
|
if (discardedQueued > 0) {
|
|
1995
2074
|
pushMessage('system', `Discarded ${discardedQueued} queued prompt${discardedQueued === 1 ? '' : 's'} from the conversation you left.`);
|
|
@@ -2053,8 +2132,10 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2053
2132
|
modelHistoryRef.current = [];
|
|
2054
2133
|
lastAssistantMessage.current = null;
|
|
2055
2134
|
lastCompletedOutputRef.current = null;
|
|
2056
|
-
if (sourceScope && targetSessionId)
|
|
2135
|
+
if (sourceScope && targetSessionId) {
|
|
2057
2136
|
sourceScope.sessionId = targetSessionId;
|
|
2137
|
+
conversationMaterializedRef.current = true;
|
|
2138
|
+
}
|
|
2058
2139
|
if (clearScreen) {
|
|
2059
2140
|
setMessages([]);
|
|
2060
2141
|
resetTranscript();
|
|
@@ -2098,8 +2179,8 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2098
2179
|
* history; it is a session-store operation with the session id captured here.
|
|
2099
2180
|
*/
|
|
2100
2181
|
const doTitle = useCallback(async (title, clear) => {
|
|
2101
|
-
const
|
|
2102
|
-
const
|
|
2182
|
+
const scope = await materializeConversation();
|
|
2183
|
+
const sessions = sessionsRef.current;
|
|
2103
2184
|
if (!sessions || !scope) {
|
|
2104
2185
|
pushMessage('system', 'Conversation history is unavailable in this folder.');
|
|
2105
2186
|
return;
|
|
@@ -2127,7 +2208,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2127
2208
|
catch (err) {
|
|
2128
2209
|
pushMessage('system', `Could not save the name: ${err instanceof Error ? err.message : String(err)}`);
|
|
2129
2210
|
}
|
|
2130
|
-
}, [
|
|
2211
|
+
}, [materializeConversation, pushMessage, setTextPrompt]);
|
|
2131
2212
|
const submitTextPrompt = useCallback((value) => {
|
|
2132
2213
|
const prompt = textPromptRef.current;
|
|
2133
2214
|
if (!prompt)
|
|
@@ -2195,8 +2276,8 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2195
2276
|
conversationMutationRef.current = 'fork';
|
|
2196
2277
|
setConversationMutation('fork');
|
|
2197
2278
|
try {
|
|
2198
|
-
const
|
|
2199
|
-
const
|
|
2279
|
+
const scope = await materializeConversation();
|
|
2280
|
+
const sessions = sessionsRef.current;
|
|
2200
2281
|
if (!sessions || !scope) {
|
|
2201
2282
|
pushMessage('system', 'Conversation history is unavailable in this folder.');
|
|
2202
2283
|
return;
|
|
@@ -2223,9 +2304,9 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2223
2304
|
setConversationMutation(null);
|
|
2224
2305
|
}
|
|
2225
2306
|
}, [
|
|
2226
|
-
ensureSessions,
|
|
2227
2307
|
goalActivation,
|
|
2228
2308
|
hasUnsettledTurn,
|
|
2309
|
+
materializeConversation,
|
|
2229
2310
|
pushMessage,
|
|
2230
2311
|
resetSubagentActivity,
|
|
2231
2312
|
wakeGoalDriver,
|
|
@@ -2374,10 +2455,11 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2374
2455
|
switch (event.kind) {
|
|
2375
2456
|
case 'delta': {
|
|
2376
2457
|
setState('thinking');
|
|
2377
|
-
if (event.messageId && event.runId) {
|
|
2458
|
+
if (event.messageId && event.runId && st.sessionId) {
|
|
2378
2459
|
lastAssistantMessage.current = {
|
|
2379
2460
|
runId: event.runId,
|
|
2380
2461
|
messageId: event.messageId,
|
|
2462
|
+
sessionId: st.sessionId,
|
|
2381
2463
|
};
|
|
2382
2464
|
}
|
|
2383
2465
|
st.text += event.text;
|
|
@@ -2441,7 +2523,11 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2441
2523
|
activeToolsRef.current = [...running.slice(0, i), ...running.slice(i + 1)];
|
|
2442
2524
|
setActiveTools(activeToolsRef.current);
|
|
2443
2525
|
}
|
|
2444
|
-
pushMessage('tool', done?.label ?? formatToolCall(event.toolName, event.summary), false, event.isError ? '✗' : '✓', done?.detail, event.isError ? theme.status.error : theme.status.ok,
|
|
2526
|
+
pushMessage('tool', done?.label ?? formatToolCall(event.toolName, event.summary), false, event.isError ? '✗' : '✓', done?.detail, event.isError ? theme.status.error : theme.status.ok, event.durationMs !== undefined
|
|
2527
|
+
? formatElapsed(event.durationMs)
|
|
2528
|
+
: done
|
|
2529
|
+
? formatElapsed(Date.now() - done.startedAt)
|
|
2530
|
+
: undefined);
|
|
2445
2531
|
if (event.isError ||
|
|
2446
2532
|
(!event.hidden && (event.summary.length > 0 || (event.detail?.length ?? 0) > 0))) {
|
|
2447
2533
|
pushMessage('tool', event.isError ? `failed: ${event.summary}` : event.summary, false, '⎿', event.detail);
|
|
@@ -2533,13 +2619,22 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2533
2619
|
// state idle while the admission read was pending let a second submit
|
|
2534
2620
|
// start beside it and broke the queue's FIFO ownership.
|
|
2535
2621
|
setState('thinking');
|
|
2622
|
+
let durableScope;
|
|
2623
|
+
try {
|
|
2624
|
+
durableScope = await materializeConversation();
|
|
2625
|
+
}
|
|
2626
|
+
catch (error) {
|
|
2627
|
+
pushMessage('system', `Conversation persistence could not start: ${error instanceof Error ? error.message : String(error)}. This turn will continue in memory and cannot be resumed.`);
|
|
2628
|
+
}
|
|
2536
2629
|
// A conversation can be closed outside this App after it was opened or
|
|
2537
2630
|
// resumed. Re-check at the actual turn boundary, before expanding file
|
|
2538
2631
|
// mentions, recording run evidence, or creating a provider iterator.
|
|
2539
2632
|
// The persistence helpers repeat the same check at their own boundary;
|
|
2540
2633
|
// neither read is claimed to serialize a concurrent archive (that needs
|
|
2541
2634
|
// a store-level lease shared with ProjectManager).
|
|
2542
|
-
const destination =
|
|
2635
|
+
const destination = conversationMaterializedRef.current
|
|
2636
|
+
? (durableScope?.sessionId ?? scopeRef.current?.sessionId ?? null)
|
|
2637
|
+
: null;
|
|
2543
2638
|
const turnSessions = sessionsRef.current;
|
|
2544
2639
|
if (turnSessions && destination) {
|
|
2545
2640
|
try {
|
|
@@ -2591,6 +2686,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2591
2686
|
pending: '',
|
|
2592
2687
|
completed: false,
|
|
2593
2688
|
outcome: null,
|
|
2689
|
+
sessionId: destination,
|
|
2594
2690
|
notification: null,
|
|
2595
2691
|
};
|
|
2596
2692
|
const ac = new AbortController();
|
|
@@ -2917,6 +3013,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2917
3013
|
finalizeMessage,
|
|
2918
3014
|
flushStream,
|
|
2919
3015
|
goalActivation,
|
|
3016
|
+
materializeConversation,
|
|
2920
3017
|
onPermission,
|
|
2921
3018
|
pushMessage,
|
|
2922
3019
|
replaceQueued,
|
|
@@ -2941,7 +3038,9 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2941
3038
|
? 'branched for prompt editing'
|
|
2942
3039
|
: conversationMutationRef.current === 'archive'
|
|
2943
3040
|
? 'archived'
|
|
2944
|
-
:
|
|
3041
|
+
: conversationMutationRef.current === 'materialize'
|
|
3042
|
+
? 'initialized'
|
|
3043
|
+
: 'moved to a fresh conversation';
|
|
2945
3044
|
pushMessage('system', `Conversation history is being ${operation}. Wait for it to finish before sending another command or prompt.`);
|
|
2946
3045
|
return;
|
|
2947
3046
|
}
|
|
@@ -2978,15 +3077,21 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
2978
3077
|
});
|
|
2979
3078
|
return;
|
|
2980
3079
|
}
|
|
2981
|
-
case 'agent-
|
|
3080
|
+
case 'agent-cockpit': {
|
|
2982
3081
|
const agents = subagentsRef.current;
|
|
2983
3082
|
if (agents.length === 0) {
|
|
2984
3083
|
pushMessage('system', 'No delegated agents are available in this conversation yet. When an Agent tool starts one, /agent opens its live activity and retained transcript.');
|
|
2985
3084
|
return;
|
|
2986
3085
|
}
|
|
3086
|
+
const firstPhase = agentPhases(agents)[0];
|
|
3087
|
+
const firstAgent = firstPhase?.agents[0];
|
|
3088
|
+
if (!firstPhase || !firstAgent)
|
|
3089
|
+
return;
|
|
2987
3090
|
setAgentSurface({
|
|
2988
|
-
kind: '
|
|
2989
|
-
|
|
3091
|
+
kind: 'cockpit',
|
|
3092
|
+
selectedPhaseId: firstPhase.id,
|
|
3093
|
+
selectedId: firstAgent.viewId,
|
|
3094
|
+
focus: 'agents',
|
|
2990
3095
|
});
|
|
2991
3096
|
return;
|
|
2992
3097
|
}
|
|
@@ -3324,29 +3429,46 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
3324
3429
|
// THIS session can answer from. The descriptors used for
|
|
3325
3430
|
// the merge above carry no store — they are names — so the
|
|
3326
3431
|
// registry is rebuilt here with the live one.
|
|
3327
|
-
const durableSessions = sessionsRef.current;
|
|
3328
|
-
const runScope = scopeRef.current;
|
|
3329
3432
|
const generation = conversationGenRef.current;
|
|
3330
3433
|
const goalCommand = slash.name === 'goal';
|
|
3331
3434
|
if (goalCommand)
|
|
3332
3435
|
goalCommandInFlightRef.current = true;
|
|
3333
|
-
const registry = new HostCommandRegistry();
|
|
3334
|
-
registry.register(kernelHostCommands({
|
|
3335
|
-
allowedAgentIds: session?.agentIds ?? [],
|
|
3336
|
-
...(durableSessions && runScope
|
|
3337
|
-
? {
|
|
3338
|
-
goal: {
|
|
3339
|
-
store: durableSessions.goals,
|
|
3340
|
-
sessionId: runScope.sessionId,
|
|
3341
|
-
tenantId: durableSessions.tenantId,
|
|
3342
|
-
activation: goalActivation,
|
|
3343
|
-
},
|
|
3344
|
-
}
|
|
3345
|
-
: {}),
|
|
3346
|
-
}));
|
|
3347
3436
|
void (async () => {
|
|
3437
|
+
let goalCommandReleased = false;
|
|
3438
|
+
const releaseGoalCommand = () => {
|
|
3439
|
+
if (!goalCommand || goalCommandReleased)
|
|
3440
|
+
return;
|
|
3441
|
+
goalCommandReleased = true;
|
|
3442
|
+
goalCommandInFlightRef.current = false;
|
|
3443
|
+
wakeGoalDriver();
|
|
3444
|
+
};
|
|
3348
3445
|
try {
|
|
3446
|
+
if (goalCommand)
|
|
3447
|
+
await materializeConversation();
|
|
3448
|
+
const durableSessions = sessionsRef.current;
|
|
3449
|
+
const runScope = scopeRef.current;
|
|
3450
|
+
const registry = new HostCommandRegistry();
|
|
3451
|
+
registry.register(kernelHostCommands({
|
|
3452
|
+
allowedAgentIds: session?.agentIds ?? [],
|
|
3453
|
+
...(durableSessions && runScope && conversationMaterializedRef.current
|
|
3454
|
+
? {
|
|
3455
|
+
goal: {
|
|
3456
|
+
store: durableSessions.goals,
|
|
3457
|
+
sessionId: runScope.sessionId,
|
|
3458
|
+
tenantId: durableSessions.tenantId,
|
|
3459
|
+
activation: goalActivation,
|
|
3460
|
+
},
|
|
3461
|
+
}
|
|
3462
|
+
: {}),
|
|
3463
|
+
}));
|
|
3349
3464
|
const outcome = await registry.dispatch(`/${slash.name} ${slash.args.join(' ')}`.trim());
|
|
3465
|
+
// The dispatch result is the durable boundary. Release the input
|
|
3466
|
+
// gate before publishing that result: once the operator can see a
|
|
3467
|
+
// completed `/goal` row, the next goal command must be admissible.
|
|
3468
|
+
// Keeping the gate until `finally` left one render-sized window in
|
|
3469
|
+
// which a visible success was followed by "still reaching durable
|
|
3470
|
+
// state" when the operator immediately typed `/goal resume`.
|
|
3471
|
+
releaseGoalCommand();
|
|
3350
3472
|
// A late readout from the conversation just left must not be
|
|
3351
3473
|
// painted as state of the one now on screen.
|
|
3352
3474
|
if (conversationGenRef.current !== generation)
|
|
@@ -3361,10 +3483,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
3361
3483
|
pushMessage('system', `Could not run /${slash.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
3362
3484
|
}
|
|
3363
3485
|
finally {
|
|
3364
|
-
|
|
3365
|
-
goalCommandInFlightRef.current = false;
|
|
3366
|
-
wakeGoalDriver();
|
|
3367
|
-
}
|
|
3486
|
+
releaseGoalCommand();
|
|
3368
3487
|
}
|
|
3369
3488
|
})();
|
|
3370
3489
|
return;
|
|
@@ -3382,6 +3501,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
3382
3501
|
title: 'Rate the latest answer',
|
|
3383
3502
|
runId: target.runId,
|
|
3384
3503
|
messageId: target.messageId,
|
|
3504
|
+
sessionId: target.sessionId,
|
|
3385
3505
|
values,
|
|
3386
3506
|
options: [
|
|
3387
3507
|
{
|
|
@@ -3399,7 +3519,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
3399
3519
|
pushMessage('system', 'Nothing to rate yet.');
|
|
3400
3520
|
return;
|
|
3401
3521
|
}
|
|
3402
|
-
recordFeedback(target.runId, slash.messageId, slash.rating, slash.note);
|
|
3522
|
+
recordFeedback(target.sessionId, target.runId, slash.messageId, slash.rating, slash.note);
|
|
3403
3523
|
return;
|
|
3404
3524
|
}
|
|
3405
3525
|
case 'review': {
|
|
@@ -4115,21 +4235,42 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
4115
4235
|
if (agentSurfaceCommittedRef.current !== agentView)
|
|
4116
4236
|
return;
|
|
4117
4237
|
const agents = subagentsRef.current;
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4238
|
+
if (agentView.kind === 'cockpit') {
|
|
4239
|
+
const phases = agentPhases(agents);
|
|
4240
|
+
const phaseIndex = Math.max(0, phases.findIndex((phase) => phase.id === agentView.selectedPhaseId));
|
|
4241
|
+
const phase = phases[phaseIndex];
|
|
4242
|
+
const phaseAgents = phase?.agents ?? [];
|
|
4243
|
+
const agentIndex = Math.max(0, phaseAgents.findIndex((agent) => agent.viewId === agentView.selectedId));
|
|
4244
|
+
const selected = phaseAgents[agentIndex];
|
|
4245
|
+
if (!phase || !selected) {
|
|
4246
|
+
setAgentSurface(null);
|
|
4247
|
+
return;
|
|
4248
|
+
}
|
|
4125
4249
|
if (key.escape || (key.ctrl && input === 'c') || input.toLowerCase() === 'q') {
|
|
4126
4250
|
setAgentSurface(null);
|
|
4127
4251
|
return;
|
|
4128
4252
|
}
|
|
4253
|
+
if (key.leftArrow || key.rightArrow || key.tab) {
|
|
4254
|
+
const focus = key.leftArrow
|
|
4255
|
+
? 'phases'
|
|
4256
|
+
: key.rightArrow
|
|
4257
|
+
? 'agents'
|
|
4258
|
+
: agentView.focus === 'phases'
|
|
4259
|
+
? 'agents'
|
|
4260
|
+
: 'phases';
|
|
4261
|
+
setAgentSurface({ ...agentView, focus });
|
|
4262
|
+
return;
|
|
4263
|
+
}
|
|
4129
4264
|
if (key.return) {
|
|
4265
|
+
if (agentView.focus === 'phases') {
|
|
4266
|
+
setAgentSurface({ ...agentView, focus: 'agents' });
|
|
4267
|
+
return;
|
|
4268
|
+
}
|
|
4130
4269
|
setAgentSurface({
|
|
4131
4270
|
kind: 'transcript',
|
|
4271
|
+
selectedPhaseId: phase.id,
|
|
4132
4272
|
selectedId: selected.viewId,
|
|
4273
|
+
returnFocus: agentView.focus,
|
|
4133
4274
|
tailOffset: 0,
|
|
4134
4275
|
});
|
|
4135
4276
|
return;
|
|
@@ -4146,19 +4287,43 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
4146
4287
|
: key.upArrow
|
|
4147
4288
|
? 'previous'
|
|
4148
4289
|
: 'next';
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4290
|
+
if (agentView.focus === 'phases') {
|
|
4291
|
+
const next = moveSelection(phaseIndex, phases.length, movement, agentPhasePageSize(terminal.rows, agentCockpitIsWide(terminal.columns)));
|
|
4292
|
+
const targetPhase = phases[next];
|
|
4293
|
+
const targetAgent = targetPhase?.agents[0];
|
|
4294
|
+
if (targetPhase && targetAgent) {
|
|
4295
|
+
setAgentSurface({
|
|
4296
|
+
...agentView,
|
|
4297
|
+
selectedPhaseId: targetPhase.id,
|
|
4298
|
+
selectedId: targetAgent.viewId,
|
|
4299
|
+
});
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
else {
|
|
4303
|
+
const next = moveSelection(agentIndex, phaseAgents.length, movement, agentPickerPageSize(terminal.rows, agentCockpitIsWide(terminal.columns)));
|
|
4304
|
+
const target = phaseAgents[next];
|
|
4305
|
+
if (target)
|
|
4306
|
+
setAgentSurface({ ...agentView, selectedId: target.viewId });
|
|
4307
|
+
}
|
|
4153
4308
|
}
|
|
4154
4309
|
return;
|
|
4155
4310
|
}
|
|
4311
|
+
const selected = agents.find((agent) => agent.viewId === agentView.selectedId);
|
|
4312
|
+
if (!selected) {
|
|
4313
|
+
setAgentSurface(null);
|
|
4314
|
+
return;
|
|
4315
|
+
}
|
|
4156
4316
|
if (input.toLowerCase() === 'q' || (key.ctrl && input === 'c')) {
|
|
4157
4317
|
setAgentSurface(null);
|
|
4158
4318
|
return;
|
|
4159
4319
|
}
|
|
4160
4320
|
if (key.escape) {
|
|
4161
|
-
setAgentSurface({
|
|
4321
|
+
setAgentSurface({
|
|
4322
|
+
kind: 'cockpit',
|
|
4323
|
+
selectedPhaseId: agentView.selectedPhaseId,
|
|
4324
|
+
selectedId: selected.viewId,
|
|
4325
|
+
focus: agentView.returnFocus,
|
|
4326
|
+
});
|
|
4162
4327
|
return;
|
|
4163
4328
|
}
|
|
4164
4329
|
if (key.home || key.end || key.pageUp || key.pageDown || key.upArrow || key.downArrow) {
|
|
@@ -4383,8 +4548,10 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
4383
4548
|
? 'compacting conversation — input is paused'
|
|
4384
4549
|
: permission
|
|
4385
4550
|
? hintForPhase(phase, state, session?.hasProvider === true)
|
|
4386
|
-
: agentSurface?.kind === '
|
|
4387
|
-
?
|
|
4551
|
+
: agentSurface?.kind === 'cockpit'
|
|
4552
|
+
? agentSurface.focus === 'phases'
|
|
4553
|
+
? 'agent phases — enter agents · esc return'
|
|
4554
|
+
: 'agents — enter inspect · left phases · esc return'
|
|
4388
4555
|
: agentSurface?.kind === 'transcript'
|
|
4389
4556
|
? 'observing agent — esc agents · q parent'
|
|
4390
4557
|
: textPrompt
|
|
@@ -4396,7 +4563,7 @@ export function App({ ctx: initialCtx, onExitSummary, externalEditor = defaultEx
|
|
|
4396
4563
|
: goalStatus && phase === 'ready' && state === 'idle'
|
|
4397
4564
|
? undefined
|
|
4398
4565
|
: hintForPhase(phase, state, session?.hasProvider === true, composerHasDraft);
|
|
4399
|
-
return (_jsx(Box, { flexDirection: "column", display: externalEditorRequest ? 'none' : 'flex', children: _jsxs(Box, { flexDirection: "column", paddingX: 1, children: [transcriptOwned || !lifecycleOwnsViewport ? (_jsx(TranscriptFrame, { children: _jsx(Transcript, { messages: finalized, pending: messages.find((m) => m.pending) ?? null, state: state, settled: renderedSettled, resetKey: resetKey, raw: rawOutput, hyperlinks: hyperlinks, showLive: !lifecycleOwnsViewport, header: transcriptOwned ? (_jsx(Banner, { version: ctx.version, session: session, permissionMode: permissionMode, cwd: ctx.cwd })) : undefined }) })) : null, phase === 'trust' ? (_jsx(TrustPrompt, { cwd: ctx.cwd })) : phase === 'resume' ? (_jsx(ResumePicker, { conversations: resumeList, selected: selectedResume })) : phase === 'edit' ? (_jsx(EditPromptPicker, { prompts: editList, selected: selectedEdit })) : phase === 'picker' ? (_jsx(Picker, { detected: pickerDetected ?? detected, currentProvider: currentProvider, selectionKind: pickerSelectionKind, currentModel: session?.modelSummary ?? null, initialView: pickerInitialView, onSubmit: handlePickerSubmit, onCancel: handlePickerCancel, onCredential: handleTypedCredential, onLogin: startLoginFromPicker, onLoginComplete: finishLoginFromPicker, keyEntryFor: keyEntryFor, notice: pickerNotice })) : (_jsxs(_Fragment, { children: [agentSurface === null ? (_jsx(LiveActivity, { activeTools: activeTools, working: state === 'thinking' || state === 'tool', agentCount: liveSubagentCount, interruptible: abortRef.current !== null, animate: stdout.isTTY === true })) : null, permission ? (_jsx(PermissionOverlay, { toolCalls: permission.toolCalls, review: permission.review, summary: permission.summary, detailsOpen: permissionDetailsOpen, reviewOffset: permissionReviewOffset, columns: terminal.columns })) : null, permission === null && agentSurface?.kind === '
|
|
4566
|
+
return (_jsx(Box, { flexDirection: "column", display: externalEditorRequest ? 'none' : 'flex', children: _jsxs(Box, { flexDirection: "column", paddingX: 1, children: [transcriptOwned || !lifecycleOwnsViewport ? (_jsx(TranscriptFrame, { children: _jsx(Transcript, { messages: finalized, pending: messages.find((m) => m.pending) ?? null, state: state, settled: renderedSettled, resetKey: resetKey, raw: rawOutput, hyperlinks: hyperlinks, showLive: !lifecycleOwnsViewport, header: transcriptOwned ? (_jsx(Banner, { version: ctx.version, session: session, permissionMode: permissionMode, cwd: ctx.cwd })) : undefined }) })) : null, phase === 'trust' ? (_jsx(TrustPrompt, { cwd: ctx.cwd })) : phase === 'resume' ? (_jsx(ResumePicker, { conversations: resumeList, selected: selectedResume })) : phase === 'edit' ? (_jsx(EditPromptPicker, { prompts: editList, selected: selectedEdit })) : phase === 'picker' ? (_jsx(Picker, { detected: pickerDetected ?? detected, currentProvider: currentProvider, selectionKind: pickerSelectionKind, currentModel: session?.modelSummary ?? null, initialView: pickerInitialView, onSubmit: handlePickerSubmit, onCancel: handlePickerCancel, onCredential: handleTypedCredential, onLogin: startLoginFromPicker, onLoginComplete: finishLoginFromPicker, keyEntryFor: keyEntryFor, notice: pickerNotice })) : (_jsxs(_Fragment, { children: [agentSurface === null ? (_jsx(LiveActivity, { activeTools: activeTools, working: state === 'thinking' || state === 'tool', agentCount: liveSubagentCount, interruptible: abortRef.current !== null, animate: stdout.isTTY === true })) : null, permission ? (_jsx(PermissionOverlay, { toolCalls: permission.toolCalls, review: permission.review, summary: permission.summary, detailsOpen: permissionDetailsOpen, reviewOffset: permissionReviewOffset, columns: terminal.columns })) : null, permission === null && agentSurface?.kind === 'cockpit' ? (_jsx(AgentCockpit, { agents: subagents, selectedPhaseId: agentSurface.selectedPhaseId, selectedId: agentSurface.selectedId, focus: agentSurface.focus, terminalRows: terminal.rows, terminalColumns: terminal.columns })) : permission === null && agentSurface?.kind === 'transcript' && selectedSubagent ? (_jsx(AgentTranscript, { agent: selectedSubagent, tailOffset: agentSurface.tailOffset, terminalRows: terminal.rows, terminalColumns: terminal.columns })) : null, textPrompt ? (_jsx(TextPrompt, { title: textPrompt.title, placeholder: textPrompt.placeholder, initialValue: textPrompt.initialValue, emptyNotice: textPrompt.emptyNotice, hidden: permission !== null || agentSurface !== null, onSubmit: submitTextPrompt, onCancel: cancelTextPrompt }, textPrompt.token)) : permission === null && agentSurface === null && choicePicker ? (_jsx(ChoicePicker, { title: choicePicker.title, notice: choicePicker.notice, options: choicePicker.options, selected: selectedChoice, windowSize: choicePicker.kind === 'command' ? choicePicker.windowSize : undefined })) : permission === null && agentSurface === null && copyPicker ? (_jsx(CopyPicker, { targets: copyPicker.targets, selected: selectedCopy })) : null, _jsxs(ComposerFrame, { focus: state === 'idle' &&
|
|
4400
4567
|
phase === 'ready' &&
|
|
4401
4568
|
conversationMutation === null &&
|
|
4402
4569
|
textPrompt === null &&
|