pikiloom 0.4.45 → 0.4.47
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/dashboard/dist/assets/{AgentTab-B8V2eV_D.js → AgentTab-1PB5sNiV.js} +1 -1
- package/dashboard/dist/assets/{ConnectionModal-BOVwXLJB.js → ConnectionModal-MKdYiyph.js} +1 -1
- package/dashboard/dist/assets/{DirBrowser-DbeAWYiL.js → DirBrowser-CrTtSp7T.js} +1 -1
- package/dashboard/dist/assets/{ExtensionsTab-BMS3PW9N.js → ExtensionsTab-CpbFbTbu.js} +1 -1
- package/dashboard/dist/assets/{IMAccessTab-B1sRgJk3.js → IMAccessTab-DnoYQxhx.js} +1 -1
- package/dashboard/dist/assets/{Modal-DCwGz46r.js → Modal-BxMOpH7q.js} +1 -1
- package/dashboard/dist/assets/{Modals-Bh_0en5P.js → Modals-CgChd_Yq.js} +1 -1
- package/dashboard/dist/assets/{Select-DC6zguGC.js → Select-th1z50AY.js} +1 -1
- package/dashboard/dist/assets/SessionPanel-DTGtpuIp.js +1 -0
- package/dashboard/dist/assets/{SystemTab-uFqZinIZ.js → SystemTab-DYLYxrRz.js} +1 -1
- package/dashboard/dist/assets/{index-DooLxbPX.js → index-Bqx1Oo38.js} +15 -15
- package/dashboard/dist/assets/{index-CL5H13Cl.js → index-CnZm1BHw.js} +2 -2
- package/dashboard/dist/assets/{shared-Byy2BNLq.js → shared-D5m7uSRI.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dist/agent/stream.js +3 -3
- package/dist/bot/bot.js +21 -3
- package/package.json +1 -1
- package/packages/kernel/dist/drivers/claude.d.ts +4 -1
- package/packages/kernel/dist/drivers/claude.js +109 -20
- package/packages/kernel/dist/index.d.ts +1 -1
- package/packages/kernel/dist/index.js +1 -1
- package/dashboard/dist/assets/SessionPanel-DNlLd-PL.js +0 -1
package/dist/agent/stream.js
CHANGED
|
@@ -333,7 +333,7 @@ function prepareStreamOpts(opts) {
|
|
|
333
333
|
session.record.lastUserAttachments = [...attachmentRelPaths];
|
|
334
334
|
if (!session.record.title)
|
|
335
335
|
session.record.title = summarizePromptTitle(displayPrompt) || null;
|
|
336
|
-
session.record.lastQuestion =
|
|
336
|
+
session.record.lastQuestion = trimSessionText(displayPrompt);
|
|
337
337
|
session.record.lastMessageText = shortValue(displayPrompt, 500);
|
|
338
338
|
setSessionRunState(session.record, 'running', null);
|
|
339
339
|
if (session.sessionId)
|
|
@@ -381,7 +381,7 @@ function finalizeStreamResult(result, workdir, prompt, session, workflowEnabled,
|
|
|
381
381
|
const displayPrompt = collapseSkillPrompt(prompt) ?? prompt;
|
|
382
382
|
if (!session.record.title)
|
|
383
383
|
session.record.title = summarizePromptTitle(displayPrompt);
|
|
384
|
-
session.record.lastQuestion =
|
|
384
|
+
session.record.lastQuestion = trimSessionText(displayPrompt);
|
|
385
385
|
session.record.lastAnswer = shortValue(result.message, 500);
|
|
386
386
|
session.record.lastMessageText = shortValue(result.message, 500) || shortValue(displayPrompt, 500);
|
|
387
387
|
session.record.lastThinking = trimSessionText(result.thinking);
|
|
@@ -647,7 +647,7 @@ export async function doStream(opts) {
|
|
|
647
647
|
byokProfileName: prepared.byokProfileName ?? null,
|
|
648
648
|
};
|
|
649
649
|
const failureDisplayPrompt = collapseSkillPrompt(opts.prompt) ?? opts.prompt;
|
|
650
|
-
session.record.lastQuestion =
|
|
650
|
+
session.record.lastQuestion = trimSessionText(failureDisplayPrompt);
|
|
651
651
|
session.record.lastAnswer = shortValue(failedResult.message, 500);
|
|
652
652
|
session.record.lastMessageText = shortValue(failedResult.message, 500) || shortValue(failureDisplayPrompt, 500);
|
|
653
653
|
session.record.lastThinking = null;
|
package/dist/bot/bot.js
CHANGED
|
@@ -215,6 +215,19 @@ export class Bot {
|
|
|
215
215
|
}
|
|
216
216
|
return next;
|
|
217
217
|
}
|
|
218
|
+
updateTaskPrompt(taskId, fallbackKey, prompt) {
|
|
219
|
+
const task = this.activeTasks.get(taskId);
|
|
220
|
+
const prepared = prompt.trim();
|
|
221
|
+
if (!task || !prepared || task.prompt === prepared)
|
|
222
|
+
return;
|
|
223
|
+
task.prompt = prepared;
|
|
224
|
+
const key = this.liveSessionKey(taskId, fallbackKey);
|
|
225
|
+
const snap = this.streamSnapshots.get(key);
|
|
226
|
+
if (snap) {
|
|
227
|
+
snap.updatedAt = Date.now();
|
|
228
|
+
this.pushSnapshotToSSE(key, true);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
218
231
|
_onStreamSnapshot = null;
|
|
219
232
|
streamPushTimers = new Map();
|
|
220
233
|
streamPushPending = new Map();
|
|
@@ -1305,13 +1318,17 @@ export class Bot {
|
|
|
1305
1318
|
})
|
|
1306
1319
|
: null;
|
|
1307
1320
|
try {
|
|
1321
|
+
const extras = {
|
|
1322
|
+
...(opts.forkOf ? { forkOf: opts.forkOf } : {}),
|
|
1323
|
+
...(opts.workflowEnabled !== undefined ? { workflowEnabled: opts.workflowEnabled } : {}),
|
|
1324
|
+
...(opts.profileId !== undefined ? { profileId: opts.profileId } : {}),
|
|
1325
|
+
onPreparedPrompt: (preparedPrompt) => this.updateTaskPrompt(taskId, session.key, preparedPrompt),
|
|
1326
|
+
};
|
|
1308
1327
|
const result = await this.runStream(prompt, session, attachments, (text, thinking, activity, meta, plan) => {
|
|
1309
1328
|
opts.onText?.(text, thinking, activity, meta, plan);
|
|
1310
1329
|
presenter?.onText(text, thinking, activity, meta, plan);
|
|
1311
1330
|
this.emitStreamText(taskId, session.key, text, thinking, activity, meta, plan);
|
|
1312
|
-
}, undefined, undefined, abortController.signal, this.createInteractionHandler(chatId, taskId), undefined, undefined,
|
|
1313
|
-
? { ...(opts.forkOf ? { forkOf: opts.forkOf } : {}), ...(opts.workflowEnabled !== undefined ? { workflowEnabled: opts.workflowEnabled } : {}), ...(opts.profileId !== undefined ? { profileId: opts.profileId } : {}) }
|
|
1314
|
-
: undefined);
|
|
1331
|
+
}, undefined, undefined, abortController.signal, this.createInteractionHandler(chatId, taskId), undefined, undefined, extras);
|
|
1315
1332
|
this.emitStreamDone(taskId, session.key, {
|
|
1316
1333
|
sessionId: result.sessionId || session.sessionId,
|
|
1317
1334
|
incomplete: !!result.incomplete,
|
|
@@ -2030,6 +2047,7 @@ export class Bot {
|
|
|
2030
2047
|
});
|
|
2031
2048
|
if (result.ok && result.seed) {
|
|
2032
2049
|
prompt = result.seed + '\n\n' + prompt;
|
|
2050
|
+
extras?.onPreparedPrompt?.(prompt);
|
|
2033
2051
|
this.debug(`[runStream] handover ${describeHandoverRef(handoverFrom)} → ${cs.agent} `
|
|
2034
2052
|
+ `mode=${result.mode} msgs=${result.messagesIncluded}/${result.messagesTotal} `
|
|
2035
2053
|
+ `turnsTotal=${result.turnsTotal} chars=${result.charsIncluded}/${result.budgetChars}`);
|
package/package.json
CHANGED
|
@@ -31,13 +31,16 @@ export declare function claudeContextWindowFromModel(model: unknown): number | n
|
|
|
31
31
|
export declare function claudeEffectiveContextWindow(advertised: number | null): number | null;
|
|
32
32
|
export declare function handleClaudeEvent(ev: any, s: any, emit: (e: DriverEvent) => void): void;
|
|
33
33
|
export declare function claudeBgHoldCapMs(): number;
|
|
34
|
+
export declare function claudeBgSettleQuietMs(): number;
|
|
34
35
|
export declare function isTerminalTaskStatus(status: unknown): boolean;
|
|
35
36
|
export declare function trackClaudeBackgroundTask(ev: any, s: any): void;
|
|
37
|
+
export declare function markClaudeTaskNotificationTerminal(content: any, s: any): void;
|
|
36
38
|
export declare function pendingClaudeBackgroundTasks(s: any): number;
|
|
37
|
-
export type ClaudeResultSettleDecision = 'settle' | 'hold';
|
|
39
|
+
export type ClaudeResultSettleDecision = 'settle' | 'hold' | 'quiet-settle';
|
|
38
40
|
export declare function decideClaudeResultSettle(input: {
|
|
39
41
|
hasError: boolean;
|
|
40
42
|
pendingBackground: number;
|
|
43
|
+
sawBackground: boolean;
|
|
41
44
|
}): ClaudeResultSettleDecision;
|
|
42
45
|
export declare function claudeUserMessage(text: string, attachments?: string[]): string;
|
|
43
46
|
export declare function emitClaudeImages(blocks: any[], s: any, emit: (e: DriverEvent) => void): void;
|
|
@@ -72,12 +72,22 @@ export class ClaudeDriver {
|
|
|
72
72
|
return new Promise((resolve) => {
|
|
73
73
|
let child;
|
|
74
74
|
let settled = false;
|
|
75
|
+
// holdCap: hard backstop while a background task is still running (never-completing daemon).
|
|
76
|
+
// quiet: fires once all known background tasks finished AND Claude has gone quiet, so trailing
|
|
77
|
+
// wake-up turns can still land before we close (see claudeBgSettleQuietMs).
|
|
75
78
|
let holdCapTimer = null;
|
|
79
|
+
let quietTimer = null;
|
|
76
80
|
const usageOf = () => this.usage(state);
|
|
81
|
+
const unref = (tm) => { if (tm && typeof tm.unref === 'function')
|
|
82
|
+
tm.unref(); };
|
|
77
83
|
const clearHoldCap = () => { if (holdCapTimer) {
|
|
78
84
|
clearTimeout(holdCapTimer);
|
|
79
85
|
holdCapTimer = null;
|
|
80
86
|
} };
|
|
87
|
+
const clearQuiet = () => { if (quietTimer) {
|
|
88
|
+
clearTimeout(quietTimer);
|
|
89
|
+
quietTimer = null;
|
|
90
|
+
} };
|
|
81
91
|
// kill=true SIGTERMs immediately — fast exit, used once nothing is left running in the
|
|
82
92
|
// background (a normal turn, or a wake-up turn after every background task finished).
|
|
83
93
|
// kill=false only ends stdin and lets Claude shut down on its own, so any still-running
|
|
@@ -88,6 +98,7 @@ export class ClaudeDriver {
|
|
|
88
98
|
return;
|
|
89
99
|
settled = true;
|
|
90
100
|
clearHoldCap();
|
|
101
|
+
clearQuiet();
|
|
91
102
|
try {
|
|
92
103
|
child?.stdin?.end();
|
|
93
104
|
}
|
|
@@ -104,8 +115,7 @@ export class ClaudeDriver {
|
|
|
104
115
|
child?.kill('SIGTERM');
|
|
105
116
|
}
|
|
106
117
|
catch { /* ignore */ } }, CLAUDE_EXIT_LEAK_GUARD_MS);
|
|
107
|
-
|
|
108
|
-
guard.unref();
|
|
118
|
+
unref(guard);
|
|
109
119
|
}
|
|
110
120
|
}
|
|
111
121
|
resolve(r);
|
|
@@ -114,6 +124,23 @@ export class ClaudeDriver {
|
|
|
114
124
|
ok: !state.error, text: state.text, reasoning: state.reasoning || undefined,
|
|
115
125
|
error: state.error, stopReason: opts.stopReason ?? state.stopReason, sessionId: state.sessionId, usage: usageOf(),
|
|
116
126
|
}, opts.kill ?? true);
|
|
127
|
+
// Absolute cap while holding for a still-running background task (stopReason marks it as
|
|
128
|
+
// "still running in the background" so the empty-text fallback reads right). Idempotent.
|
|
129
|
+
const armHoldCap = () => {
|
|
130
|
+
if (holdCapTimer)
|
|
131
|
+
return;
|
|
132
|
+
holdCapTimer = setTimeout(() => { if (!settled)
|
|
133
|
+
settleResult({ stopReason: 'background', kill: false }); }, claudeBgHoldCapMs());
|
|
134
|
+
unref(holdCapTimer);
|
|
135
|
+
};
|
|
136
|
+
// Grace close once all background work is done: settle gracefully (no kill) if Claude stays
|
|
137
|
+
// quiet for the window. Re-armed on every event, so a still-streaming wake-up keeps it open.
|
|
138
|
+
const armQuiet = () => {
|
|
139
|
+
clearQuiet();
|
|
140
|
+
quietTimer = setTimeout(() => { if (!settled)
|
|
141
|
+
settleResult({ kill: false }); }, claudeBgSettleQuietMs());
|
|
142
|
+
unref(quietTimer);
|
|
143
|
+
};
|
|
117
144
|
try {
|
|
118
145
|
child = spawn(this.bin, args, { cwd: input.workdir, env: { ...process.env, ...(input.env || {}) }, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
119
146
|
}
|
|
@@ -162,24 +189,38 @@ export class ClaudeDriver {
|
|
|
162
189
|
continue;
|
|
163
190
|
}
|
|
164
191
|
handleClaudeEvent(ev, state, ctx.emit);
|
|
165
|
-
if (ev.type !== 'result')
|
|
166
|
-
continue;
|
|
167
|
-
const hasError = !!ev.is_error || (Array.isArray(ev.errors) && ev.errors.length > 0) || !!state.error;
|
|
168
192
|
const pending = pendingClaudeBackgroundTasks(state);
|
|
169
|
-
if (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
holdCapTimer = setTimeout(() => { if (!settled)
|
|
176
|
-
settleResult({ stopReason: 'background', kill: false }); }, claudeBgHoldCapMs());
|
|
177
|
-
if (typeof holdCapTimer.unref === 'function')
|
|
178
|
-
holdCapTimer.unref();
|
|
193
|
+
if (ev.type === 'result') {
|
|
194
|
+
const hasError = !!ev.is_error || (Array.isArray(ev.errors) && ev.errors.length > 0) || !!state.error;
|
|
195
|
+
const decision = decideClaudeResultSettle({ hasError, pendingBackground: pending, sawBackground: state.bgStarted.size > 0 });
|
|
196
|
+
if (decision === 'settle') {
|
|
197
|
+
settleResult();
|
|
198
|
+
return;
|
|
179
199
|
}
|
|
200
|
+
if (decision === 'hold') {
|
|
201
|
+
clearQuiet();
|
|
202
|
+
armHoldCap();
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
// 'quiet-settle': every known background task finished, but Claude may still be delivering
|
|
206
|
+
// wake-up turns whose delivery trails the completion status (with parallel agents the last
|
|
207
|
+
// one's completion can land before an earlier one's wake-up result). Don't exit here — wait
|
|
208
|
+
// for Claude to go quiet, then close gracefully so no in-flight wake-up is torn down. Keep
|
|
209
|
+
// the hold cap armed as an absolute backstop.
|
|
210
|
+
armHoldCap();
|
|
211
|
+
armQuiet();
|
|
180
212
|
continue;
|
|
181
213
|
}
|
|
182
|
-
|
|
214
|
+
// Non-result activity: a still-streaming wake-up refreshes the quiet window; a newly-started
|
|
215
|
+
// background task pulls us back into the hold.
|
|
216
|
+
if (quietTimer) {
|
|
217
|
+
if (pending > 0) {
|
|
218
|
+
clearQuiet();
|
|
219
|
+
armHoldCap();
|
|
220
|
+
}
|
|
221
|
+
else
|
|
222
|
+
armQuiet();
|
|
223
|
+
}
|
|
183
224
|
}
|
|
184
225
|
});
|
|
185
226
|
child.stderr.on('data', (c) => { stderr += c.toString('utf8'); });
|
|
@@ -424,10 +465,13 @@ export function handleClaudeEvent(ev, s, emit) {
|
|
|
424
465
|
return;
|
|
425
466
|
}
|
|
426
467
|
if (t === 'user') {
|
|
468
|
+
// Background wake-up delivery: a `<task-notification>` tag (as a string or a text block) marks
|
|
469
|
+
// its background task terminal — an extra completion signal alongside the system task events.
|
|
470
|
+
markClaudeTaskNotificationTerminal(ev.message?.content, s);
|
|
427
471
|
// Tool results: surface generated images as artifacts AND close out the tool call
|
|
428
472
|
// (status done/failed + a result detail) so toolCalls is a faithful structured SSOT
|
|
429
473
|
// and the runtime's activity projection can render the execution trail.
|
|
430
|
-
const contents = ev.message?.content
|
|
474
|
+
const contents = Array.isArray(ev.message?.content) ? ev.message.content : [];
|
|
431
475
|
for (const b of contents) {
|
|
432
476
|
if (b?.type !== 'tool_result')
|
|
433
477
|
continue;
|
|
@@ -503,6 +547,18 @@ export function claudeBgHoldCapMs() {
|
|
|
503
547
|
const raw = Number(process.env.PIKILOOM_CLAUDE_BG_HOLD_MS);
|
|
504
548
|
return Number.isFinite(raw) && raw > 0 ? raw : CLAUDE_BG_HOLD_CAP_DEFAULT_MS;
|
|
505
549
|
}
|
|
550
|
+
// Once every KNOWN background task has finished, how long Claude must stay quiet (no further
|
|
551
|
+
// output at all) before we close a background turn. A completed task's status races AHEAD of the
|
|
552
|
+
// wake-up turn that reports it — with N parallel agents finishing together, the last agent's
|
|
553
|
+
// completion can land before an earlier agent's wake-up result, so exiting at the first
|
|
554
|
+
// pending==0 result would kill the still-undelivered wake-ups (the "background was running when
|
|
555
|
+
// the process exited" failure). Refreshed on every event, so a still-streaming wake-up keeps it
|
|
556
|
+
// alive. Override with PIKILOOM_CLAUDE_BG_SETTLE_QUIET_MS.
|
|
557
|
+
const CLAUDE_BG_SETTLE_QUIET_DEFAULT_MS = 15_000;
|
|
558
|
+
export function claudeBgSettleQuietMs() {
|
|
559
|
+
const raw = Number(process.env.PIKILOOM_CLAUDE_BG_SETTLE_QUIET_MS);
|
|
560
|
+
return Number.isFinite(raw) && raw > 0 ? raw : CLAUDE_BG_SETTLE_QUIET_DEFAULT_MS;
|
|
561
|
+
}
|
|
506
562
|
// After we settle a held turn gracefully (stdin closed, no kill), force-kill the lingering
|
|
507
563
|
// process only if it hasn't exited on its own within this window. Backstop against leaks.
|
|
508
564
|
const CLAUDE_EXIT_LEAK_GUARD_MS = 15_000;
|
|
@@ -524,6 +580,32 @@ export function trackClaudeBackgroundTask(ev, s) {
|
|
|
524
580
|
if (isTerminalTaskStatus(ev?.patch?.status ?? ev?.status))
|
|
525
581
|
(s.bgTerminal ||= new Set()).add(id);
|
|
526
582
|
}
|
|
583
|
+
function claudeContentText(content) {
|
|
584
|
+
if (typeof content === 'string')
|
|
585
|
+
return content;
|
|
586
|
+
if (Array.isArray(content))
|
|
587
|
+
return content.filter((b) => b?.type === 'text' && typeof b.text === 'string').map((b) => b.text).join('\n');
|
|
588
|
+
return '';
|
|
589
|
+
}
|
|
590
|
+
// Extra completion signal (mirrors the legacy driver): Claude delivers a background wake-up as a
|
|
591
|
+
// `type:'user'` message carrying a `<task-notification>` tag (<task-id>/<tool-use-id>/<status>).
|
|
592
|
+
// Mark that task terminal too, so a missed/absent system task_notification still lets pending
|
|
593
|
+
// reach 0 (instead of the turn hanging to the hold cap).
|
|
594
|
+
export function markClaudeTaskNotificationTerminal(content, s) {
|
|
595
|
+
const text = claudeContentText(content);
|
|
596
|
+
if (!text || !text.includes('<task-notification>'))
|
|
597
|
+
return;
|
|
598
|
+
const tag = (name) => {
|
|
599
|
+
const m = text.match(new RegExp(`<${name}>\\s*([^<]*?)\\s*</${name}>`));
|
|
600
|
+
return m ? m[1].trim() : '';
|
|
601
|
+
};
|
|
602
|
+
const status = tag('status');
|
|
603
|
+
if (status && !isTerminalTaskStatus(status))
|
|
604
|
+
return;
|
|
605
|
+
for (const id of [tag('task-id'), tag('tool-use-id')])
|
|
606
|
+
if (id)
|
|
607
|
+
(s.bgTerminal ||= new Set()).add(id);
|
|
608
|
+
}
|
|
527
609
|
export function pendingClaudeBackgroundTasks(s) {
|
|
528
610
|
const started = s?.bgStarted;
|
|
529
611
|
if (!started?.size)
|
|
@@ -535,12 +617,19 @@ export function pendingClaudeBackgroundTasks(s) {
|
|
|
535
617
|
n++;
|
|
536
618
|
return n;
|
|
537
619
|
}
|
|
538
|
-
// At a `result` event
|
|
539
|
-
//
|
|
620
|
+
// At a `result` event, decide how to end the turn:
|
|
621
|
+
// - error → 'settle' now (hard exit).
|
|
622
|
+
// - a background task is still running → 'hold' the process open for its wake-up.
|
|
623
|
+
// - background done BUT this turn launched background work → 'quiet-settle': do NOT exit at this
|
|
624
|
+
// result. Claude may still be DELIVERING wake-up turns whose delivery trails their task's
|
|
625
|
+
// completion status (see claudeBgSettleQuietMs); wait for it to go quiet, then close gracefully.
|
|
626
|
+
// - a plain turn (no background) → 'settle' now.
|
|
540
627
|
export function decideClaudeResultSettle(input) {
|
|
541
628
|
if (input.hasError)
|
|
542
629
|
return 'settle';
|
|
543
|
-
|
|
630
|
+
if (input.pendingBackground > 0)
|
|
631
|
+
return 'hold';
|
|
632
|
+
return input.sawBackground ? 'quiet-settle' : 'settle';
|
|
544
633
|
}
|
|
545
634
|
// Claude vision input formats (matches the legacy driver / Anthropic API: png, jpeg, gif, webp).
|
|
546
635
|
const CLAUDE_IMAGE_MIME = {
|
|
@@ -9,7 +9,7 @@ export type { SessionStore, CoreSessionRecord, ModelResolver, ModelInjection, To
|
|
|
9
9
|
export type { LoomIO, PromptInput, Surface, SurfaceCapabilities, Plugin, SpawnContribution, } from './contracts/surface.js';
|
|
10
10
|
export { FsSessionStore, NullModelResolver, NoopToolProvider, PassthroughSystemPromptBuilder, AutoCancelInteractionHandler, DeferToTerminalInteractionHandler, NoopCatalog, defaultBaseDir, } from './ports/defaults.js';
|
|
11
11
|
export { EchoDriver } from './drivers/echo.js';
|
|
12
|
-
export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, decideClaudeResultSettle, claudeBgHoldCapMs, type ClaudeResultSettleDecision, } from './drivers/claude.js';
|
|
12
|
+
export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, markClaudeTaskNotificationTerminal, decideClaudeResultSettle, claudeBgHoldCapMs, claudeBgSettleQuietMs, type ClaudeResultSettleDecision, } from './drivers/claude.js';
|
|
13
13
|
export { CodexDriver } from './drivers/codex.js';
|
|
14
14
|
export { GeminiDriver } from './drivers/gemini.js';
|
|
15
15
|
export { AcpDriver, type AcpDriverConfig } from './drivers/acp.js';
|
|
@@ -19,7 +19,7 @@ export { attachTui } from './runtime/tui.js';
|
|
|
19
19
|
export { FsSessionStore, NullModelResolver, NoopToolProvider, PassthroughSystemPromptBuilder, AutoCancelInteractionHandler, DeferToTerminalInteractionHandler, NoopCatalog, defaultBaseDir, } from './ports/defaults.js';
|
|
20
20
|
// Drivers & surfaces (also available via subpath exports)
|
|
21
21
|
export { EchoDriver } from './drivers/echo.js';
|
|
22
|
-
export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, decideClaudeResultSettle, claudeBgHoldCapMs, } from './drivers/claude.js';
|
|
22
|
+
export { ClaudeDriver, isTerminalTaskStatus, trackClaudeBackgroundTask, pendingClaudeBackgroundTasks, markClaudeTaskNotificationTerminal, decideClaudeResultSettle, claudeBgHoldCapMs, claudeBgSettleQuietMs, } from './drivers/claude.js';
|
|
23
23
|
export { CodexDriver } from './drivers/codex.js';
|
|
24
24
|
export { GeminiDriver } from './drivers/gemini.js';
|
|
25
25
|
export { AcpDriver } from './drivers/acp.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as t,j as n}from"./react-vendor-C7Sl8SE7.js";import{c as Ut,I as Ft,S as Ce,m as Pe,a as j,u as Ze,d as Ht,g as Bt,l as Dt,e as Qt,j as _t,f as $t,s as Kt,Y as zt}from"./index-CL5H13Cl.js";import{s as Wt,l as Yt,n as pt,m as Xt,a as Gt,o as Vt,d as Jt,b as Zt,p as er,c as et,e as tt,T as tr,R as rr,U as ht,f as nr,g as xt,h as sr,L as lr,I as ar}from"./index-DooLxbPX.js";import{M as St,a as bt}from"./Modal-DCwGz46r.js";import"./router-DHISdpPk.js";import"./Select-DC6zguGC.js";import"./DirBrowser-DbeAWYiL.js";import"./markdown-DxQYQFeH.js";import"./ExtensionsTab-BMS3PW9N.js";function or({snapshot:a}){const[r,f]=t.useState(a.currentIndex??0),[O,v]=t.useState(""),[k,g]=t.useState(!1),[C,S]=t.useState(null);t.useEffect(()=>{f(a.currentIndex??0),v(""),S(null)},[a.promptId,a.currentIndex]);const L=a.questions||[],y=L[r]||null,K=L.length,P=!!(y?.options&&y.options.length),M=P?!!y?.allowFreeform:!0,ae=u=>{u&&(f(c=>c+1),v(""))},Ie=async u=>{if(!k){g(!0),S(null);try{const c=await j.interactionSelectOption(a.promptId,u);if(!c.ok){S(c.error||"Failed to submit selection.");return}ae(c.advanced)}catch(c){S(c?.message||"Network error.")}finally{g(!1)}}},oe=async()=>{if(k)return;const u=O.trim();if(!u&&!y?.allowEmpty){S("Please enter a response.");return}g(!0),S(null);try{const c=await j.interactionSubmitText(a.promptId,u);if(!c.ok){S(c.error||"Failed to submit answer.");return}ae(c.advanced)}catch(c){S(c?.message||"Network error.")}finally{g(!1)}},p=async()=>{if(!k){g(!0),S(null);try{const u=await j.interactionSkip(a.promptId);if(!u.ok){S(u.error||"Failed to skip.");return}ae(u.advanced)}catch(u){S(u?.message||"Network error.")}finally{g(!1)}}},ue=async()=>{if(!k){g(!0);try{await j.interactionCancel(a.promptId)}catch{}}},ve=t.useMemo(()=>{const u=[];return a.hint&&u.push(a.hint),K>1&&u.push(`Question ${r+1} of ${K}`),u.join(" · ")||void 0},[a.hint,r,K]);return n.jsxs(St,{open:!0,onClose:ue,wide:P&&(y?.options?.length||0)>3,children:[n.jsx(bt,{title:a.title||"Pikiloom needs your input",description:ve,onClose:ue}),y?n.jsxs("div",{className:"space-y-4",children:[n.jsxs("div",{children:[n.jsx("div",{className:"text-xs font-medium uppercase tracking-wide text-fg-5",children:y.header||"Question"}),n.jsx("div",{className:"mt-1 whitespace-pre-wrap text-sm leading-relaxed text-fg",children:y.prompt})]}),P&&n.jsx("div",{className:"grid grid-cols-1 gap-2 sm:grid-cols-2",children:(y.options||[]).map(u=>n.jsxs("button",{type:"button",disabled:k,onClick:()=>Ie(u.value||u.label),className:Ut("group rounded-lg border border-edge bg-panel-alt px-3 py-2 text-left text-sm transition","hover:border-control-border-h hover:bg-control-h hover:shadow-sm","focus:outline-none focus:ring-2 focus:ring-[var(--th-glow-a)]","disabled:cursor-not-allowed disabled:opacity-50"),children:[n.jsx("div",{className:"font-medium text-fg group-hover:text-fg",children:u.label}),u.description&&n.jsx("div",{className:"mt-0.5 text-xs leading-snug text-fg-4",children:u.description})]},u.value||u.label))}),M&&n.jsx("div",{children:n.jsx(Ft,{value:O,onChange:u=>v(u.target.value),onKeyDown:u=>{u.key==="Enter"&&!u.shiftKey&&!k&&(u.preventDefault(),oe())},placeholder:P?"Or type a custom answer…":"Type your answer…",disabled:k,autoFocus:!P})}),C&&n.jsx("div",{className:"rounded-md border border-red-300/40 bg-red-500/10 px-3 py-2 text-xs text-red-600",children:C}),n.jsxs("div",{className:"flex items-center justify-between gap-3",children:[n.jsx("div",{className:"text-xs text-fg-5",children:k?n.jsxs("span",{className:"inline-flex items-center gap-2",children:[n.jsx(Ce,{})," Submitting…"]}):n.jsxs("span",{children:["Press ",n.jsx("kbd",{className:"rounded border border-edge bg-panel-alt px-1.5 py-0.5 text-[10px] uppercase",children:"Enter"})," to send"]})}),n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(Pe,{variant:"ghost",size:"sm",onClick:p,disabled:k,children:"Skip"}),M&&n.jsx(Pe,{variant:"primary",size:"sm",onClick:oe,disabled:k||!O.trim()&&!y.allowEmpty,children:"Submit"})]})]})]}):n.jsxs("div",{className:"py-6 text-center text-sm text-fg-5",children:[n.jsx(Ce,{className:"mr-2 inline-block"})," Waiting for the agent…"]})]})}function ur(a){return a.isNull?a.localStreamPending||a.holdsActiveState?"reject-null":"apply":(typeof a.updatedAt=="number"?a.updatedAt:0)<a.lastAppliedUpdatedAt?"reject-stale":"apply"}function cr(a,r){return typeof r!="number"?a:r>a?r:a}function ir(a,r){return!a||!a.length?[]:r.size?a.filter(f=>!r.has(f)):a.slice()}function dr(a,r,f,O){if(!a.size)return a;const v=new Set(r);let k=!1;const g=new Map;for(const[C,S]of a){if(f-S>O||!v.has(C)){k=!0;continue}g.set(C,S)}return k?g:a}const rt=12,kt=160,fr=96,mr=[],gr=[],pr=[],hr=20,xr=6e4,le=new Map;function kr(a,r){return`${a}:${r}`}function Sr(a,r){for(le.delete(a),le.set(a,r);le.size>hr;)le.delete(le.keys().next().value)}const Ar=t.memo(function({session:r,workdir:f,active:O=!0,onSessionChange:v,initialPendingPrompt:k,initialPendingImageUrls:g,onPendingPromptConsumed:C}){const S=Ze(e=>e.locale),L=Ze(e=>e.agentStatus?.agents?.find(s=>s.agent===r.agent)??null),y=L?.selectedEffort??null,K=L?.selectedModel??null,P=Ze(e=>e.modelLayer),M=r.profileId?P?.profiles.find(e=>e.id===r.profileId)??null:null,ae=M?P?.providers.find(e=>e.id===M.providerId)??null:null,Ie=r.profileId===void 0?L?.byokProviderName??null:ae?.name??null,oe=r.profileId===void 0?L?.byokProfileName??null:M&&M.name.trim().toLowerCase()!==M.modelId.trim().toLowerCase()?M.name:null,p=t.useMemo(()=>Ht(S),[S]),ue=Bt(r.agent||""),ve=Dt(r),u=!!k||!!(g&&g.length),[c,qe]=t.useState(null),[Ue,ce]=t.useState(!u),[ie,nt]=t.useState(!1),[i,U]=t.useState(null),[de,fe]=t.useState(!1),[z,Fe]=t.useState(null),[It,st]=t.useState(0),[vt,He]=t.useState(null),[W,ye]=t.useState([]),[yt,Te]=t.useState([]),[me,Be]=t.useState([]),[h,Y]=t.useState(k||null),[E,X]=t.useState(g||[]),[Tt,G]=t.useState(null),F=t.useRef(null);F.current=Tt;const lt=t.useRef(h);lt.current=h;const[at,q]=t.useState([]),Re=t.useRef([]);Re.current=at;const ge=t.useRef(null),[Rt,ot]=t.useState(null),[je,pe]=t.useState(null),[he,De]=t.useState(""),[H,Qe]=t.useState(!1),jt=!!L?.capabilities?.fork,_e=t.useRef(null),A=t.useRef(g||[]),B=t.useRef(i),$e=t.useRef(de);B.current=i,$e.current=de;const Ke=t.useRef(W);Ke.current=W;const ut=t.useRef(z);ut.current=z;const D=t.useRef(null),we=t.useRef(null),V=t.useRef(!0),J=t.useRef(!1),Ne=t.useRef(null),ze=t.useRef(!1),Q=t.useRef(u),xe=t.useRef(!1),Z=t.useRef(!1),We=t.useRef(!1),Ye=t.useRef(!1),_=t.useRef(null),Ae=t.useRef(0),ke=t.useRef(new Map),ct=t.useRef({model:null,effort:null}),wt=t.useCallback(e=>{ct.current=e},[]);t.useEffect(()=>{We.current||!u||(We.current=!0,k&&!h&&Y(k),g&&g.length&&!E.length&&(X(g),A.current=g),ce(!1),st(e=>e+1),C?.())},[u,C]);const w=t.useCallback(()=>{Y(null),X(e=>{for(const s of e)URL.revokeObjectURL(s);return[]}),A.current=[],G(null)},[]),ee=t.useCallback(()=>{q(e=>{if(!e.length)return e;for(const s of e)for(const l of s.imageUrls)URL.revokeObjectURL(l);return[]}),ge.current=null},[]),it=t.useCallback((e,s)=>{const l=Wt({streaming:$e.current,liveStreamPhase:B.current?.phase??null,streamPhase:ut.current,queuedTaskCount:Ke.current.length,pendingQueuedCount:Re.current.length}),o=s||[];if(l){const d=`local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;ge.current=d,q(x=>[...x,{localId:d,taskId:null,prompt:e||"",imageUrls:o}]);return}B.current?.phase==="done"&&U(null);for(const d of A.current)URL.revokeObjectURL(d);ge.current=null,Y(e||null),X(o),A.current=o,G(null)},[]),Nt=t.useCallback(e=>{const s=ge.current;if(s){ge.current=null,q(l=>{const o=l.findIndex(x=>x.localId===s);if(o<0)return l;const d=l.slice();return d[o]={...d[o],taskId:e},d});return}G(e)},[]),At=t.useCallback(async()=>{if(!je)return;const e=he.trim();if(e){Qe(!0);try{const s=await j.forkSession(f,r.agent||"",r.sessionId,je.atTurn,e,{});if(!s.ok||!s.sessionKey){Qe(!1);return}const[l,o]=s.sessionKey.split(":");pe(null),De(""),v?.({agent:l,sessionId:o,workdir:f})}finally{Qe(!1)}}},[je,he,f,r.agent,r.sessionId,v]);_e.current=At;const Oe=t.useCallback(async(e,s={})=>{try{const l=await Yt({workdir:f,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:e.turnOffset,turnLimit:e.turnLimit,lastNTurns:e.lastNTurns},{force:s.force});return l.ok?pt(l):null}catch{return null}},[f,r.agent,r.sessionId]),N=t.useCallback(async({keepOlder:e,force:s=!1,scrollToBottom:l=!1})=>{const o=r.sessionId;if(Ne.current===o)return!1;Ne.current=o;try{const d=await Oe({turnOffset:0,turnLimit:rt},{force:s});if(!d||r.sessionId!==o)return!1;if(l&&(J.current=!0),qe(x=>!x||!e?d:Xt(x,d)),ce(!1),xe.current&&(xe.current=!1,w()),Z.current){const x=Z.current;Z.current=!1;const re=x!==!0?x.taskId:null;B.current&&(x===!0||B.current.taskId===re)&&U(null)}return!0}finally{Ne.current===o&&(Ne.current=null)}},[Oe,w,r.sessionId]),Le=t.useCallback(async()=>{if(!c?.hasOlder||ze.current)return;const e=D.current;e&&(we.current={scrollHeight:e.scrollHeight,scrollTop:e.scrollTop}),ze.current=!0,nt(!0);try{const s=await Oe({turnOffset:Math.max(0,c.totalTurns-c.startTurn),turnLimit:rt});s?qe(l=>l?Gt(l,s):s):we.current=null}finally{ze.current=!1,nt(!1)}},[Oe,c]),Me=t.useRef(null),te=t.useCallback((e,s="ws")=>{if(ur({updatedAt:e?.updatedAt,isNull:!e,lastAppliedUpdatedAt:Ae.current,localStreamPending:Q.current,holdsActiveState:$e.current||Ke.current.length>0})!=="apply")return;if(e&&(Ae.current=cr(Ae.current,e.updatedAt)),e?.sessionId&&e.sessionId!==r.sessionId&&(Ye.current=!0,Se.current=`${r.agent}:${e.sessionId}`,v?.({agent:r.agent||"",sessionId:e.sessionId,workdir:f})),!e){const m=Me.current;fe(!1),m==="streaming"?(xe.current=!0,Z.current=!0,N({keepOlder:!0,force:!0,scrollToBottom:V.current})):U(null),Q.current&&m!=="streaming"?N({keepOlder:!0,force:!0}):(m==="done"&&(w(),ee()),m!==null&&(Q.current=!1)),He(null),Fe(null),ye([]),Te([]),Be([]),Me.current=null;return}Fe(e.phase),He(e.taskId||null);const o=[];e.taskId&&o.push(e.taskId),Array.isArray(e.queuedTaskIds)&&o.push(...e.queuedTaskIds),ke.current=dr(ke.current,o,Date.now(),xr);const d=ke.current,x=ir(e.queuedTaskIds,d),re=(Array.isArray(e.queuedTasks)?e.queuedTasks:[]).filter(m=>!d.has(m.taskId));if(ye(x.length?x:mr),Te(re.length?re:gr),Be(Array.isArray(e.interactions)&&e.interactions.length?e.interactions:pr),Vt({pendingTaskId:F.current,streamTaskId:e.taskId||null,queuedTaskIds:e.queuedTaskIds})){const m=F.current,R=lt.current||"",I=A.current;q(b=>b.some(se=>se.taskId===m)?b:[...b,{localId:`demote-${m}`,taskId:m,prompt:R,imageUrls:I}]),Y(null),X([]),A.current=[],G(null),F.current=null}if(e.phase==="streaming"){if(U({taskId:e.taskId||null,phase:"streaming",text:e.text||"",thinking:e.thinking||"",activity:e.activity,plan:e.plan??null,model:e.model??null,effort:e.effort??null,previewMeta:e.previewMeta??null,subAgents:e.previewMeta?.subAgents??null,generatingImages:e.previewMeta?.generatingImages??0,artifacts:e.artifacts??null,startedAt:typeof e.startedAt=="number"?e.startedAt:null,error:null,question:e.question??null,questionBlocks:e.questionBlocks??null}),fe(!0),e.taskId&&e.taskId!==F.current){const m=Re.current,R=m.findIndex(I=>I.taskId===e.taskId);if(R>=0){const I=m[R];for(const b of A.current)URL.revokeObjectURL(b);Y(I.prompt||null),X(I.imageUrls),A.current=I.imageUrls,G(e.taskId),q(b=>b.filter((se,$)=>$!==R))}}V.current&&(J.current=!0)}else if(e.phase==="queued")U(null),fe(!1);else if(e.phase==="done"){const m=Jt(B.current?.taskId??null,e.taskId||null),R=x.length>0;if(m){fe(!1),U($=>$?{...$,phase:"done",error:e.error??null}:e.error?{taskId:e.taskId||null,phase:"done",text:"",thinking:"",activity:"",plan:null,model:e.model??null,effort:e.effort??null,previewMeta:e.previewMeta??null,subAgents:e.previewMeta?.subAgents??null,generatingImages:e.previewMeta?.generatingImages??0,artifacts:e.artifacts??null,error:e.error,question:e.question??null,questionBlocks:e.questionBlocks??null}:$);const I=B.current,b=!!I&&Zt(I),se=!!e.incomplete&&b&&!R;if(Me.current!=="done"){R||(xe.current=!0),Z.current=se?!1:{taskId:e.taskId||null},N({keepOlder:!0,force:!0,scrollToBottom:V.current});const $=r.agent||"",Ct=r.sessionId,Pt=Se.current;_.current&&clearTimeout(_.current),_.current=setTimeout(()=>{_.current=null,j.getSessionStreamState($,Ct).then(qt=>{Se.current===Pt&&Xe.current(qt.state,"seed")}).catch(()=>{})},900)}}R||(Q.current=!1)}const ne=new Set;if(e.taskId&&ne.add(e.taskId),Array.isArray(e.queuedTaskIds))for(const m of e.queuedTaskIds)ne.add(m);q(m=>{let R=!1;const I=[];for(const b of m)if(!b.taskId||ne.has(b.taskId))I.push(b);else{for(const se of b.imageUrls)URL.revokeObjectURL(se);R=!0}return R?I:m}),Me.current=e.phase},[w,ee,N,r.sessionId,r.agent,v,f]),Xe=t.useRef(te);Xe.current=te;const dt=t.useCallback(()=>{Q.current=!0,st(e=>e+1)},[]);t.useEffect(()=>()=>{_.current&&(clearTimeout(_.current),_.current=null)},[]);const Ot=t.useCallback(async e=>{try{ke.current.set(e,Date.now()),await j.recallSessionMessage(e),F.current===e&&w(),q(s=>{let l=!1;const o=[];for(const d of s)if(d.taskId===e){for(const x of d.imageUrls)URL.revokeObjectURL(x);l=!0}else o.push(d);return l?o:s}),ye(s=>s.filter(l=>l!==e)),Te(s=>s.filter(l=>l.taskId!==e)),He(s=>s===e?null:s)}catch{}},[w]),Lt=t.useCallback(async e=>{const s=Re.current.find(l=>l.taskId===e)||null;if(s&&s.imageUrls.length>0){for(const l of A.current)URL.revokeObjectURL(l);Y(s.prompt||null),X(s.imageUrls),A.current=s.imageUrls,G(e),F.current=e,q(l=>l.filter(o=>o.taskId!==e))}try{await j.steerSession(e)}catch{}},[]),Mt=t.useCallback(async()=>{try{await j.stopSession(r.agent||"",r.sessionId)}catch{}},[r.agent,r.sessionId]),Ee=kr(r.agent||"",r.sessionId);t.useEffect(()=>{if(Ye.current){Ye.current=!1;let d=!1;return N({keepOlder:!0,force:!0}).finally(()=>{d||ce(!1)}),()=>{d=!0}}let e=!1;const s=er({workdir:f,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:0,turnLimit:rt},{allowStale:!0}),l=u&&!We.current,o=s?.ok?pt(s):le.get(Ee)||null;return ce(l?!1:!o),qe(o),U(null),fe(!1),Fe(null),ye([]),Te([]),Be([]),Ae.current=0,ke.current=new Map,l||(w(),ee(),Q.current=!1,xe.current=!1,Z.current=!1),V.current=!0,J.current=!0,l||N({keepOlder:!1,force:!0}).finally(()=>{e||ce(!1)}),()=>{e=!0}},[N,r.agent,r.sessionId,f,Ee,w,ee]),t.useEffect(()=>{c&&c.turns.length>0&&Sr(Ee,c)},[Ee,c]),t.useEffect(()=>{O&&N({keepOlder:!0,force:!0})},[O,N]);const Se=t.useRef(`${r.agent}:${r.sessionId}`);Se.current=`${r.agent}:${r.sessionId}`,Qt("stream-update",t.useCallback(e=>{e.key===Se.current&&te(e.snapshot??null)},[te])),t.useEffect(()=>{let e=!0;return j.getSessionStreamState(r.agent||"",r.sessionId).then(s=>{e&&Xe.current(s.state,"seed")}).catch(()=>{}),()=>{e=!1}},[r.agent,r.sessionId,It]),_t(t.useCallback(()=>{j.getSessionStreamState(r.agent||"",r.sessionId).then(e=>{te(e.state,"seed")}).catch(()=>{}),N({keepOlder:!0,force:!0})},[te,r.agent,r.sessionId,N])),t.useEffect(()=>{!Q.current&&ve!=="running"&&!de&&!i&&!z&&W.length===0&&(w(),ee())},[ve,de,i,z,W.length,w,ee]),t.useLayoutEffect(()=>{const e=we.current,s=D.current;!e||!s||(we.current=null,s.scrollTop=e.scrollTop+(s.scrollHeight-e.scrollHeight))},[c?.turns.length]),t.useLayoutEffect(()=>{if(!J.current)return;const e=D.current;e&&(J.current=!1,e.scrollTop=e.scrollHeight,requestAnimationFrame(()=>{V.current&&(e.scrollTop=e.scrollHeight)}))},[c,i]),t.useLayoutEffect(()=>{if(!h)return;const e=D.current;e&&(e.scrollTop=e.scrollHeight)},[h]),t.useEffect(()=>{if(!c?.hasOlder||Ue||ie)return;const e=D.current;e&&e.scrollHeight<=e.clientHeight+kt&&Le()},[c?.hasOlder,c?.turns.length,Le,Ue,ie]);const Et=t.useCallback(()=>{const e=D.current;if(!e)return;const s=e.scrollHeight-e.scrollTop-e.clientHeight;V.current=s<=fr,e.scrollTop<=kt&&Le()},[Le]),be=i?.model||r.model||K||null,Ge=$t(r.agent||"",i?.effort||r.thinkingEffort||y||null,r.workflowEnabled??L?.workflowEnabled)||null,ft=oe&&(!be||be===K)?oe:be?Kt(be):null,Ve=zt(r,{streaming:de,hasLiveStream:!!i,streamPhase:z,queuedTaskCount:W.length}),T=c?.turns||[],Je=t.useMemo(()=>{if(!E.length||!T.length)return!1;const e=T[T.length-1];return!e.user||!et(e.user.text,h)?!1:e.user.blocks.filter(l=>l.type==="image").length<E.length},[T,h,E.length]),mt=t.useMemo(()=>E.length?E.map(e=>({type:"image",content:e})):!h||!i?.questionBlocks?.length?[]:et(h,i.question)?i.questionBlocks:[],[E,h,i]),gt=t.useMemo(()=>{let e=T;if(Je){const ne=e[e.length-1];e=[...e.slice(0,-1),{...ne,user:null}]}if(!i||!e.length)return e;const s=e[e.length-1];if(!s.assistant)return e;const l=h??(i.question||null),o=(i.text||"").trim(),d=s.assistant.text?.trim()||"";if(!(l!=null?tt(s.user?.text,l):!!d&&!!o&&(o.startsWith(d)||d.startsWith(o))))return e;const re=s.user&&l&&!et(s.user.text,l)?{...s.user,text:l}:s.user;return[...e.slice(0,-1),{...s,user:re,assistant:null}]},[T,i,h,Je]);return n.jsxs("div",{className:"flex flex-col h-full overflow-hidden",children:[n.jsx("div",{ref:D,onScroll:Et,className:"flex-1 overflow-y-auto overscroll-contain",children:Ue&&!h&&!E.length&&!i?n.jsx("div",{className:"flex items-center justify-center py-20",children:n.jsx(Ce,{className:"h-5 w-5 text-fg-4"})}):gt.length===0&&!h&&!E.length&&!i&&!Ve?n.jsx("div",{className:"py-20 text-center text-[13px] text-fg-5",children:p("hub.noMessages")}):n.jsxs("div",{className:"max-w-[900px] mx-auto px-6 py-6 space-y-0",children:[(c?.hasOlder||ie)&&n.jsxs("div",{className:"mb-4 flex items-center justify-center gap-2 text-[11px] text-fg-5",children:[ie?n.jsx(Ce,{className:"h-3 w-3 text-fg-5"}):n.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-fg-5/35"}),n.jsx("span",{children:p(ie?"hub.loadingOlderTurns":"hub.loadOlderTurnsHint")})]}),r.migratedFrom?.kind==="fork"&&r.migratedFrom.sessionId&&n.jsxs("button",{type:"button",onClick:()=>v?.({agent:r.migratedFrom.agent||r.agent||"",sessionId:r.migratedFrom.sessionId,workdir:f}),className:"mb-4 inline-flex items-center gap-1.5 rounded-md border border-edge bg-panel-alt px-2.5 py-1 text-[11px] text-fg-5 transition hover:border-edge-h hover:text-fg-2",title:`#${r.migratedFrom.sessionId.slice(0,8)}`,children:[n.jsxs("svg",{width:"10",height:"10",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[n.jsx("circle",{cx:"6",cy:"6",r:"2"}),n.jsx("circle",{cx:"18",cy:"6",r:"2"}),n.jsx("circle",{cx:"12",cy:"20",r:"2"}),n.jsx("path",{d:"M6 8v3a3 3 0 0 0 3 3h6a3 3 0 0 0 3-3V8"}),n.jsx("path",{d:"M12 14v4"})]}),n.jsx("span",{children:p("hub.forkBadge")}),n.jsxs("span",{className:"font-mono",children:["#",r.migratedFrom.sessionId.slice(0,8)]}),typeof r.migratedFrom.forkedAtTurn=="number"&&n.jsxs("span",{className:"text-fg-5/70",children:["· ",p("hub.forkBadgeAt").replace("{turn}",String(r.migratedFrom.forkedAtTurn+1))]})]}),gt.map((e,s)=>{const l=(c?.startTurn||0)+s;return n.jsx(tr,{turn:e,turnIndex:l,agent:r.agent||"",meta:ue,model:ft,effort:Ge,providerName:Ie,t:p,workdir:f,onResend:o=>{J.current=!0,it(o);const d=ct.current;j.sendSessionMessage(f,r.agent||"",r.sessionId,o,{model:d.model||be||void 0,effort:d.effort||Ge||void 0}).then(x=>{x.ok&&dt()}).catch(()=>{w()})},onEdit:o=>ot(o),onFork:jt?o=>{De(""),pe({atTurn:o})}:void 0},`${c?.startTurn||0}:${s}`)}),Ve&&n.jsx("div",{className:"mb-5 animate-in",children:n.jsx(rr,{detail:Ve,t:p})}),(h||mt.length>0)&&(Je||!(h&&T.length>0&&tt(T[T.length-1]?.user?.text,h)))&&n.jsxs("div",{className:"session-turn",children:[n.jsx(ht,{text:h||"",blocks:mt,t:p}),!i&&n.jsx("div",{className:"mt-3 mb-5 animate-in",children:n.jsx(nr,{className:"text-fg-5"})})]}),i&&xt(i)&&!h&&i.question&&!(T.length>0&&tt(T[T.length-1]?.user?.text,i.question))&&n.jsx("div",{className:"session-turn",children:n.jsx(ht,{text:i.question,blocks:i.questionBlocks||void 0,t:p})}),i&&xt(i)&&n.jsxs("div",{className:"mb-6",children:[n.jsx(sr,{agent:r.agent||"",meta:ue,model:ft,effort:Ge,providerName:Ie,previewMeta:i.previewMeta,hideContextUsage:!0}),n.jsx(lr,{stream:i,t:p,workdir:f})]}),n.jsx("div",{className:"h-4"})]})}),n.jsx(ar,{session:r,workdir:f,onStreamQueued:dt,onSendStart:it,onSendTaskAssigned:Nt,onSessionChange:v,t:p,streamPhase:z,streamTaskId:vt,queuedTaskIds:W,queuedTasks:yt,pendingQueuedSends:at,onRecall:Ot,onSteer:Lt,onStopAll:Mt,editDraft:Rt,onEditDraftConsumed:()=>ot(null),onSelectionChange:wt}),je&&n.jsxs(St,{open:!0,onClose:()=>{H||pe(null)},children:[n.jsx(bt,{title:p("hub.forkPromptTitle"),description:p("hub.forkPromptHint"),onClose:()=>{H||pe(null)}}),n.jsx("textarea",{autoFocus:!0,value:he,disabled:H,onChange:e=>De(e.target.value),onKeyDown:e=>{e.key==="Enter"&&(e.metaKey||e.ctrlKey)&&he.trim()&&!H&&(e.preventDefault(),_e.current?.())},placeholder:p("hub.forkPromptPlaceholder"),className:"w-full min-h-[120px] resize-y rounded-md border border-edge bg-panel-alt px-3 py-2 text-[13px] leading-relaxed text-fg outline-none focus:border-edge-h"}),n.jsxs("div",{className:"mt-4 flex items-center justify-end gap-2",children:[n.jsx(Pe,{variant:"ghost",disabled:H,onClick:()=>pe(null),children:p("modal.cancel")}),n.jsx(Pe,{variant:"primary",disabled:H||!he.trim(),onClick:()=>{_e.current?.()},children:p(H?"hub.forkSubmitting":"hub.forkSubmit")})]})]}),O&&me.length>0&&n.jsx(or,{snapshot:me[me.length-1]},me[me.length-1].promptId)]})});export{Ar as SessionPanel};
|