pikiloom 0.4.39 → 0.4.41

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.
Files changed (48) hide show
  1. package/dashboard/dist/assets/{AgentTab-Ds8D6yrl.js → AgentTab-B4ZC9QFL.js} +1 -1
  2. package/dashboard/dist/assets/{ConnectionModal-Buj2d5L5.js → ConnectionModal-CAlACYKM.js} +1 -1
  3. package/dashboard/dist/assets/{DirBrowser-BTv7rH8E.js → DirBrowser-D3KGIof1.js} +1 -1
  4. package/dashboard/dist/assets/{ExtensionsTab-BnGwxS9U.js → ExtensionsTab-C_69Y7CR.js} +1 -1
  5. package/dashboard/dist/assets/{IMAccessTab-DjQnpOmF.js → IMAccessTab-B5_6IS4X.js} +1 -1
  6. package/dashboard/dist/assets/{Modal-DpuinsE3.js → Modal-BjZifpga.js} +1 -1
  7. package/dashboard/dist/assets/{Modals-Bs842H3n.js → Modals-B_V24pNA.js} +1 -1
  8. package/dashboard/dist/assets/{Select-Dvia29HZ.js → Select-D7xW38wq.js} +1 -1
  9. package/dashboard/dist/assets/SessionPanel-BbrfUDLg.js +1 -0
  10. package/dashboard/dist/assets/{SystemTab-BzPtwDxq.js → SystemTab-i5nmYweA.js} +1 -1
  11. package/dashboard/dist/assets/{index-S0NmlDEH.js → index-A_dL4aEz.js} +13 -13
  12. package/dashboard/dist/assets/{index-yZ-iG1qk.js → index-D18pCeqv.js} +3 -3
  13. package/dashboard/dist/assets/{shared-p3kZpiD4.js → shared-BKwEgcmy.js} +1 -1
  14. package/dashboard/dist/index.html +1 -1
  15. package/dist/agent/drivers/codex.js +5 -3
  16. package/dist/agent/index.js +1 -1
  17. package/dist/agent/stream.js +13 -1
  18. package/dist/bot/render-shared.js +2 -1
  19. package/dist/core/config/runtime-config.js +14 -22
  20. package/dist/dashboard/routes/agents.js +8 -4
  21. package/package.json +1 -1
  22. package/packages/kernel/README.md +35 -0
  23. package/packages/kernel/dist/contracts/driver.d.ts +15 -0
  24. package/packages/kernel/dist/contracts/ports.d.ts +2 -0
  25. package/packages/kernel/dist/drivers/claude.d.ts +5 -1
  26. package/packages/kernel/dist/drivers/claude.js +21 -0
  27. package/packages/kernel/dist/drivers/codex.d.ts +22 -1
  28. package/packages/kernel/dist/drivers/codex.js +87 -7
  29. package/packages/kernel/dist/drivers/gemini.d.ts +5 -1
  30. package/packages/kernel/dist/drivers/gemini.js +4 -0
  31. package/packages/kernel/dist/index.d.ts +2 -1
  32. package/packages/kernel/dist/index.js +2 -0
  33. package/packages/kernel/dist/ports/defaults.js +7 -1
  34. package/packages/kernel/dist/runtime/loom.d.ts +10 -0
  35. package/packages/kernel/dist/runtime/loom.js +18 -2
  36. package/packages/kernel/dist/workspace/index.d.ts +5 -0
  37. package/packages/kernel/dist/workspace/index.js +7 -0
  38. package/packages/kernel/dist/workspace/mcp.d.ts +44 -0
  39. package/packages/kernel/dist/workspace/mcp.js +82 -0
  40. package/packages/kernel/dist/workspace/native.d.ts +14 -0
  41. package/packages/kernel/dist/workspace/native.js +340 -0
  42. package/packages/kernel/dist/workspace/paths.d.ts +33 -0
  43. package/packages/kernel/dist/workspace/paths.js +40 -0
  44. package/packages/kernel/dist/workspace/sessions.d.ts +49 -0
  45. package/packages/kernel/dist/workspace/sessions.js +130 -0
  46. package/packages/kernel/dist/workspace/skills.d.ts +44 -0
  47. package/packages/kernel/dist/workspace/skills.js +173 -0
  48. package/dashboard/dist/assets/SessionPanel-CVItEgcH.js +0 -1
@@ -0,0 +1,40 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ /** Normalize a state dir name to its bare form: strip a leading dot, trim. */
4
+ export function normalizeStateDirName(name) {
5
+ const trimmed = (name ?? '').trim().replace(/^\.+/, '');
6
+ return trimmed || 'pikiloom';
7
+ }
8
+ export function resolveLoomPaths(opts = {}) {
9
+ const stateDirName = normalizeStateDirName(opts.stateDirName);
10
+ const dirName = `.${stateDirName}`;
11
+ const home = opts.home || os.homedir();
12
+ const globalRoot = path.join(home, dirName);
13
+ const workspaceRoot = (workdir) => path.join(path.resolve(workdir), dirName);
14
+ const root = (scope, workdir) => {
15
+ if (scope === 'global')
16
+ return globalRoot;
17
+ if (!workdir)
18
+ throw new Error('workspace scope requires a workdir');
19
+ return workspaceRoot(workdir);
20
+ };
21
+ const agentHome = (scope, workdir) => {
22
+ if (scope === 'global')
23
+ return home;
24
+ if (!workdir)
25
+ throw new Error('workspace scope requires a workdir');
26
+ return path.resolve(workdir);
27
+ };
28
+ return {
29
+ stateDirName,
30
+ dirName,
31
+ home,
32
+ globalRoot,
33
+ workspaceRoot,
34
+ root,
35
+ agentHome,
36
+ sessionsDir: (scope, workdir) => path.join(root(scope, workdir), 'sessions'),
37
+ skillsDir: (scope, workdir) => path.join(root(scope, workdir), 'skills'),
38
+ mcpConfigPath: (scope, workdir) => path.join(root(scope, workdir), 'mcp.json'),
39
+ };
40
+ }
@@ -0,0 +1,49 @@
1
+ import type { AgentDriver } from '../contracts/driver.js';
2
+ import type { SessionStore } from '../contracts/ports.js';
3
+ import type { LoomScope } from './paths.js';
4
+ export type SessionSource = 'managed' | 'native';
5
+ export interface ManagedSessionInfo {
6
+ sessionKey: string;
7
+ agent: string;
8
+ sessionId: string;
9
+ title: string | null;
10
+ preview: string | null;
11
+ workdir: string | null;
12
+ model: string | null;
13
+ effort: string | null;
14
+ runState: 'running' | 'completed' | 'incomplete' | null;
15
+ running: boolean;
16
+ source: SessionSource;
17
+ createdAt: string | null;
18
+ updatedAt: string | null;
19
+ }
20
+ export interface ListSessionsOptions {
21
+ /**
22
+ * 'workspace' = only sessions for `workdir` (managed-with-matching-cwd + native for the cwd).
23
+ * 'global' = all managed sessions across every workdir, plus native for `workdir`.
24
+ * 'all' = global, the default.
25
+ */
26
+ scope?: LoomScope | 'all';
27
+ workdir?: string;
28
+ agent?: string;
29
+ includeNative?: boolean;
30
+ limit?: number;
31
+ }
32
+ export interface SearchSessionsOptions extends ListSessionsOptions {
33
+ query: string;
34
+ }
35
+ export interface SessionsManagerDeps {
36
+ store: SessionStore;
37
+ drivers: () => Map<string, AgentDriver>;
38
+ defaultWorkdir: string;
39
+ log?: (msg: string) => void;
40
+ }
41
+ export declare class SessionsManager {
42
+ private readonly deps;
43
+ constructor(deps: SessionsManagerDeps);
44
+ list(opts?: ListSessionsOptions): Promise<ManagedSessionInfo[]>;
45
+ search(opts: SearchSessionsOptions): Promise<ManagedSessionInfo[]>;
46
+ get(sessionKey: string, opts?: {
47
+ workdir?: string;
48
+ }): Promise<ManagedSessionInfo | null>;
49
+ }
@@ -0,0 +1,130 @@
1
+ import path from 'node:path';
2
+ function splitKey(sessionKey) {
3
+ const i = sessionKey.indexOf(':');
4
+ return i < 0 ? { agent: '', sessionId: sessionKey } : { agent: sessionKey.slice(0, i), sessionId: sessionKey.slice(i + 1) };
5
+ }
6
+ function ts(iso) {
7
+ if (!iso)
8
+ return 0;
9
+ const n = Date.parse(iso);
10
+ return Number.isNaN(n) ? 0 : n;
11
+ }
12
+ function newer(a, b) {
13
+ return ts(b) > ts(a) ? b : a;
14
+ }
15
+ function managedToInfo(agent, rec) {
16
+ return {
17
+ sessionKey: `${agent}:${rec.sessionId}`,
18
+ agent,
19
+ sessionId: rec.sessionId,
20
+ title: rec.title ?? null,
21
+ preview: rec.preview ?? null,
22
+ workdir: rec.workdir ?? null,
23
+ model: rec.model ?? null,
24
+ effort: rec.effort ?? null,
25
+ runState: rec.runState ?? null,
26
+ running: rec.runState === 'running',
27
+ source: 'managed',
28
+ createdAt: rec.createdAt ?? null,
29
+ updatedAt: rec.updatedAt ?? null,
30
+ };
31
+ }
32
+ function nativeToInfo(agent, n) {
33
+ return {
34
+ sessionKey: `${agent}:${n.sessionId}`,
35
+ agent,
36
+ sessionId: n.sessionId,
37
+ title: n.title,
38
+ preview: n.preview,
39
+ workdir: n.cwd,
40
+ model: n.model,
41
+ effort: null,
42
+ runState: n.running ? 'running' : 'completed',
43
+ running: n.running,
44
+ source: 'native',
45
+ createdAt: n.createdAt,
46
+ updatedAt: n.updatedAt,
47
+ };
48
+ }
49
+ export class SessionsManager {
50
+ deps;
51
+ constructor(deps) {
52
+ this.deps = deps;
53
+ }
54
+ async list(opts = {}) {
55
+ const scope = opts.scope ?? 'all';
56
+ const workdir = path.resolve(opts.workdir || this.deps.defaultWorkdir);
57
+ const includeNative = opts.includeNative !== false;
58
+ const drivers = this.deps.drivers();
59
+ const agentIds = opts.agent ? [opts.agent] : [...drivers.keys()];
60
+ const byKey = new Map();
61
+ // Managed sessions (the kernel's own store).
62
+ for (const agent of agentIds) {
63
+ let records = [];
64
+ try {
65
+ records = await this.deps.store.list(agent);
66
+ }
67
+ catch (e) {
68
+ this.deps.log?.(`[sessions] store.list(${agent}) failed: ${e?.message || e}`);
69
+ }
70
+ for (const rec of records) {
71
+ if (scope === 'workspace') {
72
+ if (!rec.workdir || path.resolve(rec.workdir) !== workdir)
73
+ continue;
74
+ }
75
+ byKey.set(`${agent}:${rec.sessionId}`, managedToInfo(agent, rec));
76
+ }
77
+ }
78
+ // Native sessions (the agents' own stores) — inherently per-workdir.
79
+ if (includeNative) {
80
+ for (const agent of agentIds) {
81
+ const driver = drivers.get(agent);
82
+ if (!driver?.listNativeSessions)
83
+ continue;
84
+ let natives = [];
85
+ try {
86
+ natives = await driver.listNativeSessions({ workdir, limit: opts.limit });
87
+ }
88
+ catch (e) {
89
+ this.deps.log?.(`[sessions] ${agent}.listNativeSessions failed: ${e?.message || e}`);
90
+ }
91
+ for (const n of natives) {
92
+ const key = `${agent}:${n.sessionId}`;
93
+ const existing = byKey.get(key);
94
+ if (existing) {
95
+ // Same identity discovered both ways: managed record wins, but adopt the newer
96
+ // timestamp and backfill any fields the managed record never captured.
97
+ existing.updatedAt = newer(existing.updatedAt, n.updatedAt);
98
+ existing.preview = existing.preview ?? n.preview;
99
+ existing.title = existing.title ?? n.title;
100
+ existing.model = existing.model ?? n.model;
101
+ existing.running = existing.running || n.running;
102
+ }
103
+ else {
104
+ byKey.set(key, nativeToInfo(agent, n));
105
+ }
106
+ }
107
+ }
108
+ }
109
+ const out = [...byKey.values()].sort((a, b) => ts(b.updatedAt) - ts(a.updatedAt));
110
+ return typeof opts.limit === 'number' ? out.slice(0, Math.max(0, opts.limit)) : out;
111
+ }
112
+ async search(opts) {
113
+ const q = (opts.query || '').trim().toLowerCase();
114
+ const all = await this.list({ ...opts, limit: undefined });
115
+ const matched = q
116
+ ? all.filter(s => [s.title, s.preview, s.sessionId, s.model, s.agent].some(v => v != null && v.toLowerCase().includes(q)))
117
+ : all;
118
+ return typeof opts.limit === 'number' ? matched.slice(0, Math.max(0, opts.limit)) : matched;
119
+ }
120
+ async get(sessionKey, opts = {}) {
121
+ const { agent, sessionId } = splitKey(sessionKey);
122
+ if (!agent)
123
+ return null;
124
+ const rec = await this.deps.store.get(agent, sessionId).catch(() => null);
125
+ if (rec)
126
+ return managedToInfo(agent, rec);
127
+ const list = await this.list({ agent, workdir: opts.workdir });
128
+ return list.find(s => s.sessionKey === sessionKey) ?? null;
129
+ }
130
+ }
@@ -0,0 +1,44 @@
1
+ import type { LoomPaths, LoomScope } from './paths.js';
2
+ export interface SkillInfo {
3
+ name: string;
4
+ label: string | null;
5
+ description: string | null;
6
+ scope: LoomScope;
7
+ path: string;
8
+ mcpRequires?: string[];
9
+ }
10
+ export interface SkillSearchResult {
11
+ name: string;
12
+ description: string | null;
13
+ source: string;
14
+ author?: string | null;
15
+ homepage?: string | null;
16
+ version?: string | null;
17
+ }
18
+ export interface SkillsManagerOptions {
19
+ paths: LoomPaths;
20
+ /** Agent skills dirs (relative to the scope's agentHome) to symlink to the canonical dir. */
21
+ agentSkillDirs?: string[];
22
+ log?: (msg: string) => void;
23
+ }
24
+ /** Make `linkPath` a symlink to `targetDir` (idempotent; replaces a stale link/dir). */
25
+ export declare function ensureDirSymlink(linkPath: string, targetDir: string): void;
26
+ export declare class SkillsManager {
27
+ private readonly paths;
28
+ private readonly agentSkillDirs;
29
+ private readonly log?;
30
+ constructor(opts: SkillsManagerOptions);
31
+ /** The canonical skills dir for a scope, e.g. <workdir>/.pikiloom/skills or ~/.pikiloom/skills. */
32
+ canonicalDir(scope: LoomScope, workdir?: string): string;
33
+ /** Absolute paths of the per-agent skill dirs that link to the canonical dir for a scope. */
34
+ agentLinkPaths(scope: LoomScope, workdir?: string): string[];
35
+ /** Ensure the canonical dir exists and each agent skills dir symlinks to it. */
36
+ ensureLinks(scope: LoomScope, workdir?: string): void;
37
+ /** List skills. scope 'all' (default) = workspace (if workdir) then global, project wins on name clash. */
38
+ list(opts?: {
39
+ workdir?: string;
40
+ scope?: LoomScope | 'all';
41
+ }): SkillInfo[];
42
+ /** Search installable skills on the npm registry (best-effort; [] on failure). */
43
+ search(query: string, limit?: number): Promise<SkillSearchResult[]>;
44
+ }
@@ -0,0 +1,173 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ const DEFAULT_AGENT_SKILL_DIRS = ['.claude/skills', '.agents/skills'];
4
+ function parseSkillMeta(content) {
5
+ let label = null;
6
+ let description = null;
7
+ let mcpRequires;
8
+ const fm = content.match(/^---\s*\n([\s\S]*?)\n---/);
9
+ if (fm) {
10
+ const lm = fm[1].match(/^label:\s*(.+)/m);
11
+ if (lm)
12
+ label = lm[1].trim();
13
+ const dm = fm[1].match(/^description:\s*(.+)/m);
14
+ if (dm)
15
+ description = dm[1].trim();
16
+ const mr = fm[1].match(/^mcp_requires:\s*\n((?:\s+-\s+.+\n?)+)/m);
17
+ if (mr) {
18
+ mcpRequires = mr[1].split('\n').map(l => l.replace(/^\s*-\s*/, '').replace(/["']/g, '').trim()).filter(Boolean);
19
+ }
20
+ }
21
+ if (!label) {
22
+ const hm = content.match(/^#\s+(.+)$/m);
23
+ if (hm)
24
+ label = hm[1].trim();
25
+ }
26
+ return { label, description, mcpRequires };
27
+ }
28
+ function realPathOrNull(p) {
29
+ try {
30
+ return fs.realpathSync(p);
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /** Make `linkPath` a symlink to `targetDir` (idempotent; replaces a stale link/dir). */
37
+ export function ensureDirSymlink(linkPath, targetDir) {
38
+ const desiredTarget = path.relative(path.dirname(linkPath), targetDir) || '.';
39
+ try {
40
+ const stat = fs.lstatSync(linkPath);
41
+ if (stat.isSymbolicLink()) {
42
+ const currentTarget = fs.readlinkSync(linkPath);
43
+ const currentReal = realPathOrNull(path.resolve(path.dirname(linkPath), currentTarget));
44
+ const desiredReal = realPathOrNull(targetDir);
45
+ if (currentTarget === desiredTarget || (currentReal && desiredReal && currentReal === desiredReal))
46
+ return;
47
+ fs.unlinkSync(linkPath);
48
+ }
49
+ else {
50
+ fs.rmSync(linkPath, { recursive: true, force: true });
51
+ }
52
+ }
53
+ catch { /* nothing there yet */ }
54
+ fs.mkdirSync(path.dirname(linkPath), { recursive: true });
55
+ try {
56
+ fs.symlinkSync(desiredTarget, linkPath, process.platform === 'win32' ? 'junction' : 'dir');
57
+ }
58
+ catch (err) {
59
+ if (err?.code !== 'EEXIST' || fs.readlinkSync(linkPath) !== desiredTarget)
60
+ throw err;
61
+ }
62
+ }
63
+ function discoverSkillsFromDir(dir, scope, seen) {
64
+ let entries;
65
+ try {
66
+ entries = fs.readdirSync(dir).sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }));
67
+ }
68
+ catch {
69
+ return [];
70
+ }
71
+ const out = [];
72
+ for (const name of entries) {
73
+ if (!name || seen.has(name))
74
+ continue;
75
+ const skillDir = path.join(dir, name);
76
+ const skillFile = path.join(skillDir, 'SKILL.md');
77
+ try {
78
+ if (!fs.statSync(skillDir).isDirectory())
79
+ continue;
80
+ }
81
+ catch {
82
+ continue;
83
+ }
84
+ try {
85
+ if (!fs.statSync(skillFile).isFile())
86
+ continue;
87
+ }
88
+ catch {
89
+ continue;
90
+ }
91
+ let meta = { label: null, description: null };
92
+ try {
93
+ meta = parseSkillMeta(fs.readFileSync(skillFile, 'utf8'));
94
+ }
95
+ catch { /* keep defaults */ }
96
+ out.push({ name, label: meta.label, description: meta.description, scope, path: skillDir, mcpRequires: meta.mcpRequires });
97
+ seen.add(name);
98
+ }
99
+ return out;
100
+ }
101
+ export class SkillsManager {
102
+ paths;
103
+ agentSkillDirs;
104
+ log;
105
+ constructor(opts) {
106
+ this.paths = opts.paths;
107
+ this.agentSkillDirs = opts.agentSkillDirs?.length ? opts.agentSkillDirs : DEFAULT_AGENT_SKILL_DIRS;
108
+ this.log = opts.log;
109
+ }
110
+ /** The canonical skills dir for a scope, e.g. <workdir>/.pikiloom/skills or ~/.pikiloom/skills. */
111
+ canonicalDir(scope, workdir) {
112
+ return this.paths.skillsDir(scope, workdir);
113
+ }
114
+ /** Absolute paths of the per-agent skill dirs that link to the canonical dir for a scope. */
115
+ agentLinkPaths(scope, workdir) {
116
+ const base = this.paths.agentHome(scope, workdir);
117
+ return this.agentSkillDirs.map(rel => path.join(base, rel));
118
+ }
119
+ /** Ensure the canonical dir exists and each agent skills dir symlinks to it. */
120
+ ensureLinks(scope, workdir) {
121
+ const canonical = this.canonicalDir(scope, workdir);
122
+ fs.mkdirSync(canonical, { recursive: true });
123
+ for (const link of this.agentLinkPaths(scope, workdir)) {
124
+ try {
125
+ ensureDirSymlink(link, canonical);
126
+ }
127
+ catch (e) {
128
+ this.log?.(`[skills] link ${link} -> ${canonical} failed: ${e?.message || e}`);
129
+ }
130
+ }
131
+ }
132
+ /** List skills. scope 'all' (default) = workspace (if workdir) then global, project wins on name clash. */
133
+ list(opts = {}) {
134
+ const scope = opts.scope ?? 'all';
135
+ const seen = new Set();
136
+ const out = [];
137
+ if ((scope === 'workspace' || scope === 'all') && opts.workdir) {
138
+ out.push(...discoverSkillsFromDir(this.paths.skillsDir('workspace', opts.workdir), 'workspace', seen));
139
+ }
140
+ if (scope === 'global' || scope === 'all') {
141
+ out.push(...discoverSkillsFromDir(this.paths.skillsDir('global'), 'global', seen));
142
+ }
143
+ return out;
144
+ }
145
+ /** Search installable skills on the npm registry (best-effort; [] on failure). */
146
+ async search(query, limit = 20) {
147
+ const q = (query || '').trim();
148
+ const text = encodeURIComponent(`agent skill ${q}`.trim());
149
+ const url = `https://registry.npmjs.org/-/v1/search?text=${text}&size=${Math.max(1, Math.min(50, limit))}`;
150
+ try {
151
+ const res = await fetch(url, { headers: { accept: 'application/json' } });
152
+ if (!res.ok)
153
+ return [];
154
+ const data = await res.json();
155
+ const objects = Array.isArray(data?.objects) ? data.objects : [];
156
+ return objects.map((o) => {
157
+ const pkg = o?.package ?? {};
158
+ return {
159
+ name: String(pkg.name ?? ''),
160
+ description: pkg.description ?? null,
161
+ source: 'npm',
162
+ author: pkg.publisher?.username ?? pkg.author?.name ?? null,
163
+ homepage: pkg.links?.homepage ?? pkg.links?.npm ?? null,
164
+ version: pkg.version ?? null,
165
+ };
166
+ }).filter(s => s.name);
167
+ }
168
+ catch (e) {
169
+ this.log?.(`[skills] search failed: ${e?.message || e}`);
170
+ return [];
171
+ }
172
+ }
173
+ }
@@ -1 +0,0 @@
1
- import{r as t,j as n}from"./react-vendor-C7Sl8SE7.js";import{c as Lt,I as Ct,S as Le,m as Ce,a as w,u as ct,d as Pt,g as Ut,l as qt,e as Ft,j as Ht,f as Dt,s as Qt,X as _t}from"./index-yZ-iG1qk.js";import{s as $t,l as Bt,n as it,m as Kt,a as zt,o as Wt,d as Xt,b as Yt,p as Gt,c as dt,e as Ge,T as Vt,R as Jt,U as ft,f as Zt,g as mt,h as er,L as tr,I as rr}from"./index-S0NmlDEH.js";import{M as pt,a as ht}from"./Modal-DpuinsE3.js";import"./router-DHISdpPk.js";import"./Select-Dvia29HZ.js";import"./DirBrowser-BTv7rH8E.js";import"./markdown-DxQYQFeH.js";import"./ExtensionsTab-BnGwxS9U.js";function nr({snapshot:a}){const[r,d]=t.useState(a.currentIndex??0),[M,v]=t.useState(""),[k,p]=t.useState(!1),[L,S]=t.useState(null);t.useEffect(()=>{d(a.currentIndex??0),v(""),S(null)},[a.promptId,a.currentIndex]);const E=a.questions||[],T=E[r]||null,z=E.length,C=!!(T?.options&&T.options.length),oe=C?!!T?.allowFreeform:!0,f=u=>{u&&(d(h=>h+1),v(""))},ye=async u=>{if(!k){p(!0),S(null);try{const h=await w.interactionSelectOption(a.promptId,u);if(!h.ok){S(h.error||"Failed to submit selection.");return}f(h.advanced)}catch(h){S(h?.message||"Network error.")}finally{p(!1)}}},ue=async()=>{if(k)return;const u=M.trim();if(!u&&!T?.allowEmpty){S("Please enter a response.");return}p(!0),S(null);try{const h=await w.interactionSubmitText(a.promptId,u);if(!h.ok){S(h.error||"Failed to submit answer.");return}f(h.advanced)}catch(h){S(h?.message||"Network error.")}finally{p(!1)}},q=async()=>{if(!k){p(!0),S(null);try{const u=await w.interactionSkip(a.promptId);if(!u.ok){S(u.error||"Failed to skip.");return}f(u.advanced)}catch(u){S(u?.message||"Network error.")}finally{p(!1)}}},m=async()=>{if(!k){p(!0);try{await w.interactionCancel(a.promptId)}catch{}}},ce=t.useMemo(()=>{const u=[];return a.hint&&u.push(a.hint),z>1&&u.push(`Question ${r+1} of ${z}`),u.join(" · ")||void 0},[a.hint,r,z]);return n.jsxs(pt,{open:!0,onClose:m,wide:C&&(T?.options?.length||0)>3,children:[n.jsx(ht,{title:a.title||"Pikiloom needs your input",description:ce,onClose:m}),T?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:T.header||"Question"}),n.jsx("div",{className:"mt-1 whitespace-pre-wrap text-sm leading-relaxed text-fg",children:T.prompt})]}),C&&n.jsx("div",{className:"grid grid-cols-1 gap-2 sm:grid-cols-2",children:(T.options||[]).map(u=>n.jsxs("button",{type:"button",disabled:k,onClick:()=>ye(u.value||u.label),className:Lt("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))}),oe&&n.jsx("div",{children:n.jsx(Ct,{value:M,onChange:u=>v(u.target.value),onKeyDown:u=>{u.key==="Enter"&&!u.shiftKey&&!k&&(u.preventDefault(),ue())},placeholder:C?"Or type a custom answer…":"Type your answer…",disabled:k,autoFocus:!C})}),L&&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:L}),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(Le,{})," 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(Ce,{variant:"ghost",size:"sm",onClick:q,disabled:k,children:"Skip"}),oe&&n.jsx(Ce,{variant:"primary",size:"sm",onClick:ue,disabled:k||!M.trim()&&!T.allowEmpty,children:"Submit"})]})]})]}):n.jsxs("div",{className:"py-6 text-center text-sm text-fg-5",children:[n.jsx(Le,{className:"mr-2 inline-block"})," Waiting for the agent…"]})]})}function sr(a){return a.isNull?a.localStreamPending||a.holdsActiveState?"reject-null":"apply":(typeof a.updatedAt=="number"?a.updatedAt:0)<a.lastAppliedUpdatedAt?"reject-stale":"apply"}function lr(a,r){return typeof r!="number"?a:r>a?r:a}function ar(a,r){return!a||!a.length?[]:r.size?a.filter(d=>!r.has(d)):a.slice()}function or(a,r,d,M){if(!a.size)return a;const v=new Set(r);let k=!1;const p=new Map;for(const[L,S]of a){if(d-S>M||!v.has(L)){k=!0;continue}p.set(L,S)}return k?p:a}const Ve=12,gt=160,ur=96,cr=[],ir=[],dr=[],fr=20,mr=6e4,ae=new Map;function gr(a,r){return`${a}:${r}`}function pr(a,r){for(ae.delete(a),ae.set(a,r);ae.size>fr;)ae.delete(ae.keys().next().value)}const Rr=t.memo(function({session:r,workdir:d,active:M=!0,onSessionChange:v,initialPendingPrompt:k,initialPendingImageUrls:p,onPendingPromptConsumed:L}){const S=ct(e=>e.locale),E=ct(e=>e.agentStatus?.agents?.find(s=>s.agent===r.agent)??null),T=E?.selectedEffort??null,z=E?.selectedModel??null,C=E?.byokProviderName??null,oe=E?.byokProfileName??null,f=t.useMemo(()=>Pt(S),[S]),ye=Ut(r.agent||""),ue=qt(r),q=!!k||!!(p&&p.length),[m,ce]=t.useState(null),[u,h]=t.useState(!q),[ie,Je]=t.useState(!1),[i,F]=t.useState(null),[de,fe]=t.useState(!1),[W,Pe]=t.useState(null),[xt,Ze]=t.useState(0),[kt,Ue]=t.useState(null),[X,Ie]=t.useState([]),[St,ve]=t.useState([]),[me,qe]=t.useState([]),[b,Y]=t.useState(k||null),[P,G]=t.useState(p||[]),[bt,V]=t.useState(null),H=t.useRef(null);H.current=bt;const et=t.useRef(b);et.current=b;const[tt,U]=t.useState([]),Te=t.useRef([]);Te.current=tt;const ge=t.useRef(null),[yt,rt]=t.useState(null),[Re,pe]=t.useState(null),[he,Fe]=t.useState(""),[D,He]=t.useState(!1),It=!!E?.capabilities?.fork,De=t.useRef(null),O=t.useRef(p||[]),Q=t.useRef(i),Qe=t.useRef(de);Q.current=i,Qe.current=de;const _e=t.useRef(X);_e.current=X;const nt=t.useRef(W);nt.current=W;const _=t.useRef(null),je=t.useRef(null),J=t.useRef(!0),Z=t.useRef(!1),we=t.useRef(null),$e=t.useRef(!1),$=t.useRef(q),xe=t.useRef(!1),ee=t.useRef(!1),Be=t.useRef(!1),Ke=t.useRef(!1),B=t.useRef(null),Ne=t.useRef(0),ke=t.useRef(new Map),st=t.useRef({model:null,effort:null}),vt=t.useCallback(e=>{st.current=e},[]);t.useEffect(()=>{Be.current||!q||(Be.current=!0,k&&!b&&Y(k),p&&p.length&&!P.length&&(G(p),O.current=p),h(!1),Ze(e=>e+1),L?.())},[q,L]);const N=t.useCallback(()=>{Y(null),G(e=>{for(const s of e)URL.revokeObjectURL(s);return[]}),O.current=[],V(null)},[]),te=t.useCallback(()=>{U(e=>{if(!e.length)return e;for(const s of e)for(const l of s.imageUrls)URL.revokeObjectURL(l);return[]}),ge.current=null},[]),lt=t.useCallback((e,s)=>{const l=$t({streaming:Qe.current,liveStreamPhase:Q.current?.phase??null,streamPhase:nt.current,queuedTaskCount:_e.current.length,pendingQueuedCount:Te.current.length}),o=s||[];if(l){const c=`local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;ge.current=c,U(x=>[...x,{localId:c,taskId:null,prompt:e||"",imageUrls:o}]);return}Q.current?.phase==="done"&&F(null);for(const c of O.current)URL.revokeObjectURL(c);ge.current=null,Y(e||null),G(o),O.current=o,V(null)},[]),Tt=t.useCallback(e=>{const s=ge.current;if(s){ge.current=null,U(l=>{const o=l.findIndex(x=>x.localId===s);if(o<0)return l;const c=l.slice();return c[o]={...c[o],taskId:e},c});return}V(e)},[]),Rt=t.useCallback(async()=>{if(!Re)return;const e=he.trim();if(e){He(!0);try{const s=await w.forkSession(d,r.agent||"",r.sessionId,Re.atTurn,e,{});if(!s.ok||!s.sessionKey){He(!1);return}const[l,o]=s.sessionKey.split(":");pe(null),Fe(""),v?.({agent:l,sessionId:o,workdir:d})}finally{He(!1)}}},[Re,he,d,r.agent,r.sessionId,v]);De.current=Rt;const Ae=t.useCallback(async(e,s={})=>{try{const l=await Bt({workdir:d,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:e.turnOffset,turnLimit:e.turnLimit,lastNTurns:e.lastNTurns},{force:s.force});return l.ok?it(l):null}catch{return null}},[d,r.agent,r.sessionId]),A=t.useCallback(async({keepOlder:e,force:s=!1,scrollToBottom:l=!1})=>{const o=r.sessionId;if(we.current===o)return!1;we.current=o;try{const c=await Ae({turnOffset:0,turnLimit:Ve},{force:s});if(!c||r.sessionId!==o)return!1;if(l&&(Z.current=!0),ce(x=>!x||!e?c:Kt(x,c)),h(!1),xe.current&&(xe.current=!1,N()),ee.current){const x=ee.current;ee.current=!1;const ne=x!==!0?x.taskId:null;Q.current&&(x===!0||Q.current.taskId===ne)&&F(null)}return!0}finally{we.current===o&&(we.current=null)}},[Ae,N,r.sessionId]),Oe=t.useCallback(async()=>{if(!m?.hasOlder||$e.current)return;const e=_.current;e&&(je.current={scrollHeight:e.scrollHeight,scrollTop:e.scrollTop}),$e.current=!0,Je(!0);try{const s=await Ae({turnOffset:Math.max(0,m.totalTurns-m.startTurn),turnLimit:Ve});s?ce(l=>l?zt(l,s):s):je.current=null}finally{$e.current=!1,Je(!1)}},[Ae,m]),Me=t.useRef(null),re=t.useCallback((e,s="ws")=>{if(sr({updatedAt:e?.updatedAt,isNull:!e,lastAppliedUpdatedAt:Ne.current,localStreamPending:$.current,holdsActiveState:Qe.current||_e.current.length>0})!=="apply")return;if(e&&(Ne.current=lr(Ne.current,e.updatedAt)),e?.sessionId&&e.sessionId!==r.sessionId&&(Ke.current=!0,Se.current=`${r.agent}:${e.sessionId}`,v?.({agent:r.agent||"",sessionId:e.sessionId,workdir:d})),!e){const g=Me.current;fe(!1),g==="streaming"?(xe.current=!0,ee.current=!0,A({keepOlder:!0,force:!0,scrollToBottom:J.current})):F(null),$.current&&g!=="streaming"?A({keepOlder:!0,force:!0}):(g==="done"&&(N(),te()),g!==null&&($.current=!1)),Ue(null),Pe(null),Ie([]),ve([]),qe([]),Me.current=null;return}Pe(e.phase),Ue(e.taskId||null);const o=[];e.taskId&&o.push(e.taskId),Array.isArray(e.queuedTaskIds)&&o.push(...e.queuedTaskIds),ke.current=or(ke.current,o,Date.now(),mr);const c=ke.current,x=ar(e.queuedTaskIds,c),ne=(Array.isArray(e.queuedTasks)?e.queuedTasks:[]).filter(g=>!c.has(g.taskId));if(Ie(x.length?x:cr),ve(ne.length?ne:ir),qe(Array.isArray(e.interactions)&&e.interactions.length?e.interactions:dr),Wt({pendingTaskId:H.current,streamTaskId:e.taskId||null,queuedTaskIds:e.queuedTaskIds})){const g=H.current,j=et.current||"",I=O.current;U(y=>y.some(le=>le.taskId===g)?y:[...y,{localId:`demote-${g}`,taskId:g,prompt:j,imageUrls:I}]),Y(null),G([]),O.current=[],V(null),H.current=null}if(e.phase==="streaming"){if(F({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}),fe(!0),e.taskId&&e.taskId!==H.current){const g=Te.current,j=g.findIndex(I=>I.taskId===e.taskId);if(j>=0){const I=g[j];for(const y of O.current)URL.revokeObjectURL(y);Y(I.prompt||null),G(I.imageUrls),O.current=I.imageUrls,V(e.taskId),U(y=>y.filter((le,K)=>K!==j))}}J.current&&(Z.current=!0)}else if(e.phase==="queued")F(null),fe(!1);else if(e.phase==="done"){const g=Xt(Q.current?.taskId??null,e.taskId||null),j=x.length>0;if(g){fe(!1),F(K=>K?{...K,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}:K);const I=Q.current,y=!!I&&Yt(I),le=!!e.incomplete&&y&&!j;if(Me.current!=="done"){j||(xe.current=!0),ee.current=le?!1:{taskId:e.taskId||null},A({keepOlder:!0,force:!0,scrollToBottom:J.current});const K=r.agent||"",Ot=r.sessionId,Mt=Se.current;B.current&&clearTimeout(B.current),B.current=setTimeout(()=>{B.current=null,w.getSessionStreamState(K,Ot).then(Et=>{Se.current===Mt&&ze.current(Et.state,"seed")}).catch(()=>{})},900)}}j||($.current=!1)}const se=new Set;if(e.taskId&&se.add(e.taskId),Array.isArray(e.queuedTaskIds))for(const g of e.queuedTaskIds)se.add(g);U(g=>{let j=!1;const I=[];for(const y of g)if(!y.taskId||se.has(y.taskId))I.push(y);else{for(const le of y.imageUrls)URL.revokeObjectURL(le);j=!0}return j?I:g}),Me.current=e.phase},[N,te,A,r.sessionId,r.agent,v,d]),ze=t.useRef(re);ze.current=re;const at=t.useCallback(()=>{$.current=!0,Ze(e=>e+1)},[]);t.useEffect(()=>()=>{B.current&&(clearTimeout(B.current),B.current=null)},[]);const jt=t.useCallback(async e=>{try{ke.current.set(e,Date.now()),await w.recallSessionMessage(e),H.current===e&&N(),U(s=>{let l=!1;const o=[];for(const c of s)if(c.taskId===e){for(const x of c.imageUrls)URL.revokeObjectURL(x);l=!0}else o.push(c);return l?o:s}),Ie(s=>s.filter(l=>l!==e)),ve(s=>s.filter(l=>l.taskId!==e)),Ue(s=>s===e?null:s)}catch{}},[N]),wt=t.useCallback(async e=>{const s=Te.current.find(l=>l.taskId===e)||null;if(s&&s.imageUrls.length>0){for(const l of O.current)URL.revokeObjectURL(l);Y(s.prompt||null),G(s.imageUrls),O.current=s.imageUrls,V(e),H.current=e,U(l=>l.filter(o=>o.taskId!==e))}try{await w.steerSession(e)}catch{}},[]),Nt=t.useCallback(async()=>{try{await w.stopSession(r.agent||"",r.sessionId)}catch{}},[r.agent,r.sessionId]),Ee=gr(r.agent||"",r.sessionId);t.useEffect(()=>{if(Ke.current){Ke.current=!1;let c=!1;return A({keepOlder:!0,force:!0}).finally(()=>{c||h(!1)}),()=>{c=!0}}let e=!1;const s=Gt({workdir:d,agent:r.agent||"",sessionId:r.sessionId,rich:!0,turnOffset:0,turnLimit:Ve},{allowStale:!0}),l=q&&!Be.current,o=s?.ok?it(s):ae.get(Ee)||null;return h(l?!1:!o),ce(o),F(null),fe(!1),Pe(null),Ie([]),ve([]),qe([]),Ne.current=0,ke.current=new Map,l||(N(),te(),$.current=!1,xe.current=!1,ee.current=!1),J.current=!0,Z.current=!0,l||A({keepOlder:!1,force:!0}).finally(()=>{e||h(!1)}),()=>{e=!0}},[A,r.agent,r.sessionId,d,Ee,N,te]),t.useEffect(()=>{m&&m.turns.length>0&&pr(Ee,m)},[Ee,m]),t.useEffect(()=>{M&&A({keepOlder:!0,force:!0})},[M,A]);const Se=t.useRef(`${r.agent}:${r.sessionId}`);Se.current=`${r.agent}:${r.sessionId}`,Ft("stream-update",t.useCallback(e=>{e.key===Se.current&&re(e.snapshot??null)},[re])),t.useEffect(()=>{let e=!0;return w.getSessionStreamState(r.agent||"",r.sessionId).then(s=>{e&&ze.current(s.state,"seed")}).catch(()=>{}),()=>{e=!1}},[r.agent,r.sessionId,xt]),Ht(t.useCallback(()=>{w.getSessionStreamState(r.agent||"",r.sessionId).then(e=>{re(e.state,"seed")}).catch(()=>{}),A({keepOlder:!0,force:!0})},[re,r.agent,r.sessionId,A])),t.useEffect(()=>{!$.current&&ue!=="running"&&!de&&!i&&!W&&X.length===0&&(N(),te())},[ue,de,i,W,X.length,N,te]),t.useLayoutEffect(()=>{const e=je.current,s=_.current;!e||!s||(je.current=null,s.scrollTop=e.scrollTop+(s.scrollHeight-e.scrollHeight))},[m?.turns.length]),t.useLayoutEffect(()=>{if(!Z.current)return;const e=_.current;e&&(Z.current=!1,e.scrollTop=e.scrollHeight,requestAnimationFrame(()=>{J.current&&(e.scrollTop=e.scrollHeight)}))},[m,i]),t.useLayoutEffect(()=>{if(!b)return;const e=_.current;e&&(e.scrollTop=e.scrollHeight)},[b]),t.useEffect(()=>{if(!m?.hasOlder||u||ie)return;const e=_.current;e&&e.scrollHeight<=e.clientHeight+gt&&Oe()},[m?.hasOlder,m?.turns.length,Oe,u,ie]);const At=t.useCallback(()=>{const e=_.current;if(!e)return;const s=e.scrollHeight-e.scrollTop-e.clientHeight;J.current=s<=ur,e.scrollTop<=gt&&Oe()},[Oe]),be=i?.model||r.model||z||null,We=Dt(r.agent||"",i?.effort||r.thinkingEffort||T||null,r.workflowEnabled??E?.workflowEnabled)||null,ot=oe&&(!be||be===z)?oe:be?Qt(be):null,Xe=_t(r,{streaming:de,hasLiveStream:!!i,streamPhase:W,queuedTaskCount:X.length}),R=m?.turns||[],Ye=t.useMemo(()=>{if(!P.length||!R.length)return!1;const e=R[R.length-1];return!e.user||!dt(e.user.text,b)?!1:e.user.blocks.filter(l=>l.type==="image").length<P.length},[R,b,P.length]),ut=t.useMemo(()=>{let e=R;if(Ye){const se=e[e.length-1];e=[...e.slice(0,-1),{...se,user:null}]}if(!i||!e.length)return e;const s=e[e.length-1];if(!s.assistant)return e;const l=b??(i.question||null),o=(i.text||"").trim(),c=s.assistant.text?.trim()||"";if(!(l!=null?Ge(s.user?.text,l):!!c&&!!o&&(o.startsWith(c)||c.startsWith(o))))return e;const ne=s.user&&l&&!dt(s.user.text,l)?{...s.user,text:l}:s.user;return[...e.slice(0,-1),{...s,user:ne,assistant:null}]},[R,i,b,Ye]);return n.jsxs("div",{className:"flex flex-col h-full overflow-hidden",children:[n.jsx("div",{ref:_,onScroll:At,className:"flex-1 overflow-y-auto overscroll-contain",children:u&&!b&&!P.length&&!i?n.jsx("div",{className:"flex items-center justify-center py-20",children:n.jsx(Le,{className:"h-5 w-5 text-fg-4"})}):ut.length===0&&!b&&!P.length&&!i&&!Xe?n.jsx("div",{className:"py-20 text-center text-[13px] text-fg-5",children:f("hub.noMessages")}):n.jsxs("div",{className:"max-w-[900px] mx-auto px-6 py-6 space-y-0",children:[(m?.hasOlder||ie)&&n.jsxs("div",{className:"mb-4 flex items-center justify-center gap-2 text-[11px] text-fg-5",children:[ie?n.jsx(Le,{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:f(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:d}),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:f("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:["· ",f("hub.forkBadgeAt").replace("{turn}",String(r.migratedFrom.forkedAtTurn+1))]})]}),ut.map((e,s)=>{const l=(m?.startTurn||0)+s;return n.jsx(Vt,{turn:e,turnIndex:l,agent:r.agent||"",meta:ye,model:ot,effort:We,providerName:C,t:f,workdir:d,onResend:o=>{Z.current=!0,lt(o);const c=st.current;w.sendSessionMessage(d,r.agent||"",r.sessionId,o,{model:c.model||be||void 0,effort:c.effort||We||void 0}).then(x=>{x.ok&&at()}).catch(()=>{N()})},onEdit:o=>rt(o),onFork:It?o=>{Fe(""),pe({atTurn:o})}:void 0},`${m?.startTurn||0}:${s}`)}),Xe&&n.jsx("div",{className:"mb-5 animate-in",children:n.jsx(Jt,{detail:Xe,t:f})}),(b||P.length>0)&&(Ye||!(b&&R.length>0&&Ge(R[R.length-1]?.user?.text,b)))&&n.jsxs("div",{className:"session-turn",children:[n.jsx(ft,{text:b||"",blocks:P.map(e=>({type:"image",content:e})),t:f}),!i&&n.jsx("div",{className:"mt-3 mb-5 animate-in",children:n.jsx(Zt,{className:"text-fg-5"})})]}),i&&mt(i)&&!b&&i.question&&!(R.length>0&&Ge(R[R.length-1]?.user?.text,i.question))&&n.jsx("div",{className:"session-turn",children:n.jsx(ft,{text:i.question,t:f})}),i&&mt(i)&&n.jsxs("div",{className:"mb-6",children:[n.jsx(er,{agent:r.agent||"",meta:ye,model:ot,effort:We,providerName:C,previewMeta:i.previewMeta,hideContextUsage:!0}),n.jsx(tr,{stream:i,t:f,workdir:d})]}),n.jsx("div",{className:"h-4"})]})}),n.jsx(rr,{session:r,workdir:d,onStreamQueued:at,onSendStart:lt,onSendTaskAssigned:Tt,onSessionChange:v,t:f,streamPhase:W,streamTaskId:kt,queuedTaskIds:X,queuedTasks:St,pendingQueuedSends:tt,onRecall:jt,onSteer:wt,onStopAll:Nt,editDraft:yt,onEditDraftConsumed:()=>rt(null),onSelectionChange:vt}),Re&&n.jsxs(pt,{open:!0,onClose:()=>{D||pe(null)},children:[n.jsx(ht,{title:f("hub.forkPromptTitle"),description:f("hub.forkPromptHint"),onClose:()=>{D||pe(null)}}),n.jsx("textarea",{autoFocus:!0,value:he,disabled:D,onChange:e=>Fe(e.target.value),onKeyDown:e=>{e.key==="Enter"&&(e.metaKey||e.ctrlKey)&&he.trim()&&!D&&(e.preventDefault(),De.current?.())},placeholder:f("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(Ce,{variant:"ghost",disabled:D,onClick:()=>pe(null),children:f("modal.cancel")}),n.jsx(Ce,{variant:"primary",disabled:D||!he.trim(),onClick:()=>{De.current?.()},children:f(D?"hub.forkSubmitting":"hub.forkSubmit")})]})]}),M&&me.length>0&&n.jsx(nr,{snapshot:me[me.length-1]},me[me.length-1].promptId)]})});export{Rr as SessionPanel};