@loicngr/kobo 2.1.5 → 2.1.7
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/CHANGELOG.md +9 -0
- package/dist/mcp-server/kobo-tasks-handlers.js +17 -4
- package/dist/mcp-server/kobo-tasks-server.js +14 -2
- package/dist/server/routes/workspaces.js +45 -34
- package/dist/server/services/agent/engines/claude-code/event-mapper.js +33 -0
- package/dist/server/services/agent/engines/codex/engine.js +10 -1
- package/dist/server/services/agent/engines/codex/event-mapper.js +2 -0
- package/dist/server/services/agent/streaming-batcher.js +14 -3
- package/dist/server/services/dev-server-service.js +7 -1
- package/dist/shared/codex-models.js +0 -48
- package/dist/shared/models.js +6 -54
- package/package.json +6 -6
- package/src/client/dist/pwa/assets/ActivityFeed-B8tJgXwD.js +2 -0
- package/src/client/dist/pwa/assets/ActivityFeed-BfMUdSXQ.css +1 -0
- package/src/client/dist/pwa/assets/{ChangelogPage-BL5Jh8-v.js → ChangelogPage-YjWYsB_s.js} +1 -1
- package/src/client/dist/pwa/assets/{ComparisonPanel-Bv2SZrVZ.js → ComparisonPanel-azVvpfGW.js} +1 -1
- package/src/client/dist/pwa/assets/CreatePage-BVNtCTdA.js +2 -0
- package/src/client/dist/pwa/assets/CreatePage-C7fLOpai.css +1 -0
- package/src/client/dist/pwa/assets/{DashboardPage-BEXXRguE.js → DashboardPage-DydscFLA.js} +1 -1
- package/src/client/dist/pwa/assets/{DiffViewer-B92w_jd7.js → DiffViewer-DfMqxOYw.js} +3 -3
- package/src/client/dist/pwa/assets/DocumentsPanel-DCGgj9pc.js +1 -0
- package/src/client/dist/pwa/assets/{DrawerToggleButton-Btx8QwHo.js → DrawerToggleButton-CQVSfKpY.js} +1 -1
- package/src/client/dist/pwa/assets/GitPanel-D6ZCZPbj.js +3 -0
- package/src/client/dist/pwa/assets/{HealthPage-CDhgJQkL.js → HealthPage-D_A6DTiH.js} +1 -1
- package/src/client/dist/pwa/assets/MainLayout-CFLswVqP.css +1 -0
- package/src/client/dist/pwa/assets/MainLayout-CeHg73-f.js +2 -0
- package/src/client/dist/pwa/assets/{QBanner-7EWRdc4U.js → QBanner-CtppfNDn.js} +1 -1
- package/src/client/dist/pwa/assets/{QBtnDropdown-vjat4GZl.js → QBtnDropdown-D8I04HPE.js} +1 -1
- package/src/client/dist/pwa/assets/{QChip-CG1kWhFm.js → QChip-Btg1Lp_6.js} +1 -1
- package/src/client/dist/pwa/assets/{QExpansionItem-BQuy89vv.js → QExpansionItem-DmzCAbka.js} +1 -1
- package/src/client/dist/pwa/assets/{QItemSection-BrVklYfM.js → QItemSection-BhGnulVQ.js} +1 -1
- package/src/client/dist/pwa/assets/{QList-BVX-b8nc.js → QList-Cw2xs69W.js} +1 -1
- package/src/client/dist/pwa/assets/{QMarkupTable-B8_FKLvo.js → QMarkupTable-Ck2E2TaI.js} +1 -1
- package/src/client/dist/pwa/assets/QScrollArea-BmBuij9J.js +1 -0
- package/src/client/dist/pwa/assets/{QSelect-DBW_TZri.js → QSelect-DUuWu79L.js} +1 -1
- package/src/client/dist/pwa/assets/{QTooltip-DzYbguTR.js → QTooltip-Dhy3hNTO.js} +1 -1
- package/src/client/dist/pwa/assets/{SchedulePanel-BX6iKh6S.js → SchedulePanel-BCiV6rMr.js} +1 -1
- package/src/client/dist/pwa/assets/{SearchPage-_In2gH2P.js → SearchPage-of0gPqV4.js} +1 -1
- package/src/client/dist/pwa/assets/{SettingsPage-BqkNYzC5.js → SettingsPage-BPg3-Lhb.js} +1 -1
- package/src/client/dist/pwa/assets/{SplitWorkspacePage-DRoXbSRP.js → SplitWorkspacePage-BcdPVE9B.js} +1 -1
- package/src/client/dist/pwa/assets/{TerminalPanel-CfqiuSuk.js → TerminalPanel-auHWDK9i.js} +1 -1
- package/src/client/dist/pwa/assets/ToolCallItem-BQmqNcfF.js +8 -0
- package/src/client/dist/pwa/assets/ToolCallItem-DhjdG8vp.css +1 -0
- package/src/client/dist/pwa/assets/{TouchPan-DcOCRf7x.js → TouchPan-DKpZbMAf.js} +1 -1
- package/src/client/dist/pwa/assets/{TourReplayButton-gp7m6tSV.js → TourReplayButton-uCZpvYlj.js} +1 -1
- package/src/client/dist/pwa/assets/{WorkspaceAttentionLabels-IcoMGkJh.js → WorkspaceAttentionLabels-jDKgkf3G.js} +1 -1
- package/src/client/dist/pwa/assets/{WorkspacePage-BnW-gp3u.css → WorkspacePage-Ba0jAHhn.css} +1 -1
- package/src/client/dist/pwa/assets/WorkspacePage-DQ-jvLEj.js +4 -0
- package/src/client/dist/pwa/assets/{browser-BveHkbe-.js → browser-CU7taghA.js} +1 -1
- package/src/client/dist/pwa/assets/{build-path-tree-Dtp7rlxS.js → build-path-tree-fw6KlTB4.js} +1 -1
- package/src/client/dist/pwa/assets/{custom-sounds-CBoWzJ85.js → custom-sounds-Dfi-grUv.js} +1 -1
- package/src/client/dist/pwa/assets/{de-BJsWkZro.js → de-C_20Oxyv.js} +2 -2
- package/src/client/dist/pwa/assets/{editor.api-CbkPxoJf.js → editor.api-CBaHnF7Q.js} +1 -1
- package/src/client/dist/pwa/assets/{efforts-BCli1Unj.js → efforts-CNJXztO0.js} +1 -1
- package/src/client/dist/pwa/assets/{es-tNYw7itB.js → es-B3_j4CWr.js} +2 -2
- package/src/client/dist/pwa/assets/{expand-template-CfaEhb2f.js → expand-template-BtpC0GKE.js} +1 -1
- package/src/client/dist/pwa/assets/{format-BRl2DUlm.js → format-MtzcnR3z.js} +1 -1
- package/src/client/dist/pwa/assets/{formatters-C5TjPSR_.js → formatters-BZm4POkA.js} +1 -1
- package/src/client/dist/pwa/assets/{fr-B5sFski4.js → fr-DbPOG-xd.js} +2 -2
- package/src/client/dist/pwa/assets/{freemarker2-CDmvOQyn.js → freemarker2-BtVwKuc0.js} +1 -1
- package/src/client/dist/pwa/assets/{handlebars-Bx_w8mx1.js → handlebars-Bhl5yJrV.js} +1 -1
- package/src/client/dist/pwa/assets/{html-DVRfiRkS.js → html-DKXLlkkM.js} +1 -1
- package/src/client/dist/pwa/assets/i18n-B9eF3pgw.js +1 -0
- package/src/client/dist/pwa/assets/{i18n-D21JKsVt.js → i18n-CPFleoLe.js} +4 -4
- package/src/client/dist/pwa/assets/{index-C7vFf6p2.js → index-BVJWwOvK.js} +2 -2
- package/src/client/dist/pwa/assets/{it-Bc2FncM9.js → it--6niM3qU.js} +2 -2
- package/src/client/dist/pwa/assets/{javascript-CPvttU5J.js → javascript-Cdfy_faM.js} +1 -1
- package/src/client/dist/pwa/assets/{latest-request-CN4-B22z.js → latest-request-7rgsEfKZ.js} +1 -1
- package/src/client/dist/pwa/assets/{liquid-CI0gQddb.js → liquid-0NoEATfB.js} +1 -1
- package/src/client/dist/pwa/assets/{mdx-BveBwYJH.js → mdx-hvP0EAwa.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco-contributions-CHXFh4P2.js → monaco-contributions-Be_o6s3m.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco.contribution-DOK8t_9B.js → monaco.contribution-DRQLCBp8.js} +2 -2
- package/src/client/dist/pwa/assets/{network-auth-CItnNZDh.js → network-auth-DVXmkvPH.js} +1 -1
- package/src/client/dist/pwa/assets/{notify-theme-BO6r1Rd7.js → notify-theme-I_sWGwy6.js} +1 -1
- package/src/client/dist/pwa/assets/{permissionModes-Cc5VaOdC.js → permissionModes-BDi77lhg.js} +1 -1
- package/src/client/dist/pwa/assets/preload-helper-DjzSQ1t3.js +1 -0
- package/src/client/dist/pwa/assets/{project-color-Bnv02P9D.js → project-color-i2bg2TfP.js} +1 -1
- package/src/client/dist/pwa/assets/{python-BesLCxpi.js → python-Bz-bbYMw.js} +1 -1
- package/src/client/dist/pwa/assets/{razor-Dv1PMxuY.js → razor-CyafkF-1.js} +1 -1
- package/src/client/dist/pwa/assets/{typescript-26L2Xsu9.js → typescript-BSLweq4l.js} +1 -1
- package/src/client/dist/pwa/assets/{use-checkbox-BLeif5-t.js → use-checkbox-BAt9fjK-.js} +1 -1
- package/src/client/dist/pwa/assets/{use-search-index-status-Mv3pIO6p.js → use-search-index-status-BzsGSHGh.js} +1 -1
- package/src/client/dist/pwa/assets/{use-tours-B5uIqxRS.js → use-tours-CM4E53aB.js} +1 -1
- package/src/client/dist/pwa/assets/use-worktree-restore-C__ResAR.js +1 -0
- package/src/client/dist/pwa/assets/{workspace-templates-CDY-MiH2.js → workspace-templates-TOa0yVyr.js} +1 -1
- package/src/client/dist/pwa/assets/{xml-CkRojTcc.js → xml-DOY7F605.js} +1 -1
- package/src/client/dist/pwa/assets/{yaml-DKkQHwew.js → yaml-CnWF0ZRJ.js} +1 -1
- package/src/client/dist/pwa/index.html +5 -5
- package/src/client/dist/pwa/sw.js +1 -1
- package/src/mcp-server/kobo-tasks-handlers.ts +24 -9
- package/src/mcp-server/kobo-tasks-server.ts +14 -2
- package/src/client/dist/pwa/assets/ActivityFeed-B4lTKMVE.css +0 -1
- package/src/client/dist/pwa/assets/ActivityFeed-DXWXioW9.js +0 -8
- package/src/client/dist/pwa/assets/CreatePage-CMyl2j8Z.css +0 -1
- package/src/client/dist/pwa/assets/CreatePage-d43ITOC1.js +0 -2
- package/src/client/dist/pwa/assets/DocumentsPanel-C9JXyqHg.js +0 -1
- package/src/client/dist/pwa/assets/GitPanel-Cgz9crLN.js +0 -3
- package/src/client/dist/pwa/assets/MainLayout-DTTtj9sq.js +0 -2
- package/src/client/dist/pwa/assets/MainLayout-knNNtkre.css +0 -1
- package/src/client/dist/pwa/assets/WorkspacePage-CR2xAzW_.js +0 -4
- package/src/client/dist/pwa/assets/documents-sb2sQ4JC.js +0 -1
- package/src/client/dist/pwa/assets/i18n-Bm-L4nW3.js +0 -1
- package/src/client/dist/pwa/assets/pending-diff-open-DpS4iyDM.js +0 -1
- package/src/client/dist/pwa/assets/preload-helper-BZ1Pz5am.js +0 -1
- package/src/client/dist/pwa/assets/use-worktree-restore-BBChALUM.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ All notable changes to Kōbō are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/). Each release is an `## <version>`
|
|
5
5
|
section — the in-app "What's new" dialog reads this file.
|
|
6
6
|
|
|
7
|
+
## 2.1.7
|
|
8
|
+
|
|
9
|
+
- feat: improve workspace agent visibility
|
|
10
|
+
- fix(dev-server): tolerate EPERM process probes
|
|
11
|
+
|
|
12
|
+
## 2.1.6
|
|
13
|
+
|
|
14
|
+
- feat(subagents): add focused activity views
|
|
15
|
+
|
|
7
16
|
## 2.1.5
|
|
8
17
|
|
|
9
18
|
- fix(workspace): improve reliability and git controls
|
|
@@ -31,6 +31,15 @@ export function listTasksHandler(db, workspaceId) {
|
|
|
31
31
|
.all(workspaceId);
|
|
32
32
|
return rows.map(rowToDto);
|
|
33
33
|
}
|
|
34
|
+
function parseWorkspaceTags(raw) {
|
|
35
|
+
try {
|
|
36
|
+
const tags = JSON.parse(raw);
|
|
37
|
+
return Array.isArray(tags) ? tags.filter((tag) => typeof tag === 'string') : [];
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
34
43
|
/**
|
|
35
44
|
* List workspaces for the global `list_workspaces` MCP tool. Reads SQLite
|
|
36
45
|
* directly (no backend HTTP dependency) so it works even when the Kōbō
|
|
@@ -39,15 +48,19 @@ export function listTasksHandler(db, workspaceId) {
|
|
|
39
48
|
export function listWorkspacesHandler(db, opts) {
|
|
40
49
|
// updated_at can collide at second resolution (e.g. bulk-seeded test data); rowid DESC breaks ties, most-recently-inserted first.
|
|
41
50
|
const sql = opts.includeArchived
|
|
42
|
-
? 'SELECT id, name, status, created_at FROM workspaces ORDER BY updated_at DESC, rowid DESC'
|
|
43
|
-
: 'SELECT id, name, status, created_at FROM workspaces WHERE archived_at IS NULL ORDER BY updated_at DESC, rowid DESC';
|
|
51
|
+
? 'SELECT id, name, status, tags, created_at FROM workspaces ORDER BY updated_at DESC, rowid DESC'
|
|
52
|
+
: 'SELECT id, name, status, tags, created_at FROM workspaces WHERE archived_at IS NULL ORDER BY updated_at DESC, rowid DESC';
|
|
44
53
|
const rows = db.prepare(sql).all();
|
|
45
|
-
|
|
54
|
+
const tag = opts.tag?.trim();
|
|
55
|
+
return rows
|
|
56
|
+
.map((row) => ({
|
|
46
57
|
id: row.id,
|
|
47
58
|
title: row.name,
|
|
48
59
|
status: row.status,
|
|
60
|
+
tags: parseWorkspaceTags(row.tags),
|
|
49
61
|
createdAt: row.created_at,
|
|
50
|
-
}))
|
|
62
|
+
}))
|
|
63
|
+
.filter((workspace) => !tag || workspace.tags.includes(tag));
|
|
51
64
|
}
|
|
52
65
|
/**
|
|
53
66
|
* Flip the workspace's `auto_loop_ready` flag. Called at the end of a
|
|
@@ -536,7 +536,7 @@ const GLOBAL_TOOLS = [
|
|
|
536
536
|
...WORKSPACE_DIALOGUE_TOOLS,
|
|
537
537
|
{
|
|
538
538
|
name: 'list_workspaces',
|
|
539
|
-
description: 'List Kōbō workspaces with their id, title, status, and creation date. Works even when the Kōbō backend server is not running (reads the database directly). Use this to discover existing workspaces before creating one or targeting one with archive_workspace/stop_workspace.',
|
|
539
|
+
description: 'List Kōbō workspaces with their id, title, status, tags, and creation date. Set tag to return only workspaces carrying that exact tag. Works even when the Kōbō backend server is not running (reads the database directly). Use this to discover existing workspaces before creating one or targeting one with archive_workspace/stop_workspace.',
|
|
540
540
|
inputSchema: {
|
|
541
541
|
type: 'object',
|
|
542
542
|
properties: {
|
|
@@ -544,6 +544,11 @@ const GLOBAL_TOOLS = [
|
|
|
544
544
|
type: 'boolean',
|
|
545
545
|
description: 'Include archived workspaces (default false).',
|
|
546
546
|
},
|
|
547
|
+
tag: {
|
|
548
|
+
type: 'string',
|
|
549
|
+
minLength: 1,
|
|
550
|
+
description: 'Return only workspaces with this exact tag, for example "API".',
|
|
551
|
+
},
|
|
547
552
|
},
|
|
548
553
|
required: [],
|
|
549
554
|
},
|
|
@@ -566,6 +571,11 @@ const GLOBAL_TOOLS = [
|
|
|
566
571
|
reasoning_effort: { type: 'string', description: 'Reasoning effort override (optional).' },
|
|
567
572
|
engine: { type: 'string', description: 'Agent engine id, e.g. "claude-code" or "codex" (optional).' },
|
|
568
573
|
description: { type: 'string', description: 'Task description / initial brainstorming prompt (optional).' },
|
|
574
|
+
tags: {
|
|
575
|
+
type: 'array',
|
|
576
|
+
items: { type: 'string' },
|
|
577
|
+
description: 'Workspace tags to assign at creation (optional).',
|
|
578
|
+
},
|
|
569
579
|
tasks: { type: 'array', items: { type: 'string' }, description: 'Initial manual task titles (optional).' },
|
|
570
580
|
acceptance_criteria: {
|
|
571
581
|
type: 'array',
|
|
@@ -938,7 +948,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
938
948
|
}
|
|
939
949
|
if (name === 'list_workspaces') {
|
|
940
950
|
const includeArchived = a.include_archived === true;
|
|
941
|
-
|
|
951
|
+
const tag = typeof a.tag === 'string' ? a.tag : undefined;
|
|
952
|
+
return ok(listWorkspacesHandler(db, { includeArchived, tag }));
|
|
942
953
|
}
|
|
943
954
|
if (name === 'create_workspace') {
|
|
944
955
|
const workspaceName = a.name;
|
|
@@ -958,6 +969,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
958
969
|
reasoningEffort: a.reasoning_effort,
|
|
959
970
|
engine: a.engine,
|
|
960
971
|
description: a.description,
|
|
972
|
+
tags: a.tags,
|
|
961
973
|
tasks: a.tasks,
|
|
962
974
|
acceptanceCriteria: a.acceptance_criteria,
|
|
963
975
|
agentPermissionMode: a.agent_permission_mode,
|
|
@@ -492,6 +492,9 @@ app.post('/', migrationGuard, creationBodyLimit, async (c) => {
|
|
|
492
492
|
if (body.comparisonId !== undefined && typeof body.comparisonId !== 'string') {
|
|
493
493
|
return c.json({ error: 'comparisonId must be a string' }, 400);
|
|
494
494
|
}
|
|
495
|
+
if (body.tags !== undefined && (!Array.isArray(body.tags) || body.tags.some((tag) => typeof tag !== 'string'))) {
|
|
496
|
+
return c.json({ error: 'tags must be an array of strings' }, 400);
|
|
497
|
+
}
|
|
495
498
|
creationId = typeof body.creationId === 'string' && body.creationId.length > 0 ? body.creationId : undefined;
|
|
496
499
|
currentStep = 'validate';
|
|
497
500
|
emitCreateProgress(creationId, currentStep);
|
|
@@ -841,7 +844,7 @@ app.post('/', migrationGuard, creationBodyLimit, async (c) => {
|
|
|
841
844
|
// Skip any tag the user has removed from the catalogue so we respect
|
|
842
845
|
// their choice (they may have pruned "notion"/"sentry" on purpose).
|
|
843
846
|
const catalogTags = new Set(globalSettings.tags ?? []);
|
|
844
|
-
const autoTags = [];
|
|
847
|
+
const autoTags = [...(body.tags ?? [])];
|
|
845
848
|
if (body.notionUrl && catalogTags.has('notion'))
|
|
846
849
|
autoTags.push('notion');
|
|
847
850
|
if (body.sentryUrl && catalogTags.has('sentry'))
|
|
@@ -2418,8 +2421,34 @@ app.get('/:id/events', (c) => {
|
|
|
2418
2421
|
// optional: scope to a session view. Session views also include
|
|
2419
2422
|
// workspace-level rows where session_id IS NULL (legacy/pre-session items).
|
|
2420
2423
|
const session = c.req.query('session');
|
|
2424
|
+
// Optional, narrow history to one child. Nested tool calls keep their
|
|
2425
|
+
// parent origin, so match both that origin and their own toolCallId.
|
|
2426
|
+
const subagentToolCallId = c.req.query('subagentToolCallId');
|
|
2427
|
+
const subagentThreadIds = (c.req.query('subagentThreadIds') ?? '')
|
|
2428
|
+
.split(',')
|
|
2429
|
+
.map((threadId) => threadId.trim())
|
|
2430
|
+
.filter(Boolean)
|
|
2431
|
+
.slice(0, 50);
|
|
2421
2432
|
const parsedLimit = parseInt(c.req.query('limit') ?? '100', 10);
|
|
2422
2433
|
const limit = Math.max(1, Math.min(Number.isFinite(parsedLimit) ? parsedLimit : 100, 500));
|
|
2434
|
+
const sessionClause = session ? ' AND (session_id = ? OR session_id IS NULL)' : '';
|
|
2435
|
+
const sessionParams = session ? [session] : [];
|
|
2436
|
+
const originPayload = "CASE WHEN json_valid(payload) THEN payload ELSE '{}' END";
|
|
2437
|
+
const originClauses = [];
|
|
2438
|
+
const originParams = [];
|
|
2439
|
+
if (subagentToolCallId) {
|
|
2440
|
+
originClauses.push(`(json_extract(${originPayload}, '$.origin.toolCallId') = ? OR json_extract(${originPayload}, '$.toolCallId') = ?)`);
|
|
2441
|
+
originParams.push(subagentToolCallId, subagentToolCallId);
|
|
2442
|
+
}
|
|
2443
|
+
if (subagentThreadIds.length > 0) {
|
|
2444
|
+
originClauses.push(`json_extract(${originPayload}, '$.origin.threadId') IN (${subagentThreadIds.map(() => '?').join(', ')})`);
|
|
2445
|
+
originParams.push(...subagentThreadIds);
|
|
2446
|
+
}
|
|
2447
|
+
const originClause = originClauses.length
|
|
2448
|
+
? ` AND type = 'agent:event' AND json_extract(${originPayload}, '$.origin.kind') = 'subagent' AND (${originClauses.join(' OR ')})`
|
|
2449
|
+
: '';
|
|
2450
|
+
const scopedClause = `${sessionClause}${originClause}`;
|
|
2451
|
+
const scopedParams = [...sessionParams, ...originParams];
|
|
2423
2452
|
const db = getDb();
|
|
2424
2453
|
let rows;
|
|
2425
2454
|
if (around) {
|
|
@@ -2427,13 +2456,9 @@ app.get('/:id/events', (c) => {
|
|
|
2427
2456
|
if (!targetRow)
|
|
2428
2457
|
return c.json({ events: [], hasMore: false });
|
|
2429
2458
|
const halfWindow = Math.floor(limit / 2);
|
|
2430
|
-
rows =
|
|
2431
|
-
?
|
|
2432
|
-
|
|
2433
|
-
.all(id, session, targetRow.rowid - halfWindow, targetRow.rowid + halfWindow)
|
|
2434
|
-
: db
|
|
2435
|
-
.prepare('SELECT * FROM ws_events WHERE workspace_id = ? AND rowid BETWEEN ? AND ? ORDER BY rowid ASC')
|
|
2436
|
-
.all(id, targetRow.rowid - halfWindow, targetRow.rowid + halfWindow);
|
|
2459
|
+
rows = db
|
|
2460
|
+
.prepare(`SELECT * FROM ws_events WHERE workspace_id = ?${scopedClause} AND rowid BETWEEN ? AND ? ORDER BY rowid ASC`)
|
|
2461
|
+
.all(id, ...scopedParams, targetRow.rowid - halfWindow, targetRow.rowid + halfWindow);
|
|
2437
2462
|
}
|
|
2438
2463
|
else if (before) {
|
|
2439
2464
|
// Get the rowid of the cursor event
|
|
@@ -2441,25 +2466,17 @@ app.get('/:id/events', (c) => {
|
|
|
2441
2466
|
if (!cursorRow) {
|
|
2442
2467
|
return c.json({ events: [], hasMore: false });
|
|
2443
2468
|
}
|
|
2444
|
-
rows =
|
|
2445
|
-
?
|
|
2446
|
-
|
|
2447
|
-
.all(id, session, cursorRow.rowid, limit)
|
|
2448
|
-
: db
|
|
2449
|
-
.prepare('SELECT * FROM ws_events WHERE workspace_id = ? AND rowid < ? ORDER BY rowid DESC LIMIT ?')
|
|
2450
|
-
.all(id, cursorRow.rowid, limit);
|
|
2469
|
+
rows = db
|
|
2470
|
+
.prepare(`SELECT * FROM ws_events WHERE workspace_id = ?${scopedClause} AND rowid < ? ORDER BY rowid DESC LIMIT ?`)
|
|
2471
|
+
.all(id, ...scopedParams, cursorRow.rowid, limit);
|
|
2451
2472
|
}
|
|
2452
2473
|
else {
|
|
2453
2474
|
// No cursor — return events. When filtering by session, we want the
|
|
2454
2475
|
// MOST RECENT events of that session first (so the feed renders from
|
|
2455
2476
|
// the end), reversed to chronological order below.
|
|
2456
|
-
rows =
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
.all(id, session, limit)
|
|
2460
|
-
: db
|
|
2461
|
-
.prepare('SELECT * FROM ws_events WHERE workspace_id = ? ORDER BY rowid DESC LIMIT ?')
|
|
2462
|
-
.all(id, limit);
|
|
2477
|
+
rows = db
|
|
2478
|
+
.prepare(`SELECT * FROM ws_events WHERE workspace_id = ?${scopedClause} ORDER BY rowid DESC LIMIT ?`)
|
|
2479
|
+
.all(id, ...scopedParams, limit);
|
|
2463
2480
|
}
|
|
2464
2481
|
// Reverse to chronological order (we queried DESC for "before" pagination,
|
|
2465
2482
|
// or for the "session + no cursor" case where we fetched the newest first).
|
|
@@ -2488,13 +2505,9 @@ app.get('/:id/events', (c) => {
|
|
|
2488
2505
|
if (before || around) {
|
|
2489
2506
|
const firstRow = db.prepare('SELECT rowid FROM ws_events WHERE id = ?').get(rows[0].id);
|
|
2490
2507
|
if (firstRow) {
|
|
2491
|
-
const older =
|
|
2492
|
-
?
|
|
2493
|
-
|
|
2494
|
-
.get(id, session, firstRow.rowid)
|
|
2495
|
-
: db
|
|
2496
|
-
.prepare('SELECT 1 as c FROM ws_events WHERE workspace_id = ? AND rowid < ? LIMIT 1')
|
|
2497
|
-
.get(id, firstRow.rowid);
|
|
2508
|
+
const older = db
|
|
2509
|
+
.prepare(`SELECT 1 as c FROM ws_events WHERE workspace_id = ?${scopedClause} AND rowid < ? LIMIT 1`)
|
|
2510
|
+
.get(id, ...scopedParams, firstRow.rowid);
|
|
2498
2511
|
hasMore = older !== undefined;
|
|
2499
2512
|
}
|
|
2500
2513
|
}
|
|
@@ -2502,11 +2515,9 @@ app.get('/:id/events', (c) => {
|
|
|
2502
2515
|
// `LIMIT 1 OFFSET <page size>` answers "is there anything past this
|
|
2503
2516
|
// page?" by reading one row, where COUNT(*) walked every event the
|
|
2504
2517
|
// workspace ever produced — on each page, synchronously.
|
|
2505
|
-
const beyond =
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
.get(id, session, rows.length)
|
|
2509
|
-
: db.prepare('SELECT 1 as c FROM ws_events WHERE workspace_id = ? LIMIT 1 OFFSET ?').get(id, rows.length);
|
|
2518
|
+
const beyond = db
|
|
2519
|
+
.prepare(`SELECT 1 as c FROM ws_events WHERE workspace_id = ?${scopedClause} LIMIT 1 OFFSET ?`)
|
|
2520
|
+
.get(id, ...scopedParams, rows.length);
|
|
2510
2521
|
hasMore = beyond !== undefined;
|
|
2511
2522
|
}
|
|
2512
2523
|
}
|
|
@@ -94,6 +94,8 @@ const TASK_UPDATED_TERMINAL_STATUS = {
|
|
|
94
94
|
};
|
|
95
95
|
export function createMapperState() {
|
|
96
96
|
return {
|
|
97
|
+
childMessageOrigins: new Map(),
|
|
98
|
+
childToolOrigins: new Map(),
|
|
97
99
|
sessionStartedEmitted: false,
|
|
98
100
|
openMessages: new Map(),
|
|
99
101
|
sawErrorResult: false,
|
|
@@ -147,6 +149,37 @@ function tryEmitQuotaError(state, events, message) {
|
|
|
147
149
|
* `state` as needed.
|
|
148
150
|
*/
|
|
149
151
|
export function mapSdkMessage(msg, state) {
|
|
152
|
+
const parsed = msg;
|
|
153
|
+
const parentId = typeof parsed.parent_tool_use_id === 'string' ? parsed.parent_tool_use_id : undefined;
|
|
154
|
+
const origin = parentId ? { kind: 'subagent', toolCallId: parentId } : undefined;
|
|
155
|
+
const streamed = parsed.event;
|
|
156
|
+
if (origin && streamed?.type === 'message_start' && streamed.message?.id) {
|
|
157
|
+
state.childMessageOrigins.set(streamed.message.id, origin);
|
|
158
|
+
}
|
|
159
|
+
const events = mapSdkMessagePayload(msg, state);
|
|
160
|
+
return events.map((event) => {
|
|
161
|
+
if (event.kind === 'message:text' || event.kind === 'message:thinking' || event.kind === 'message:end') {
|
|
162
|
+
const eventOrigin = origin ?? state.childMessageOrigins.get(event.messageId);
|
|
163
|
+
if (origin)
|
|
164
|
+
state.childMessageOrigins.set(event.messageId, origin);
|
|
165
|
+
if (event.kind === 'message:end')
|
|
166
|
+
state.childMessageOrigins.delete(event.messageId);
|
|
167
|
+
return eventOrigin ? { ...event, origin: eventOrigin } : event;
|
|
168
|
+
}
|
|
169
|
+
if (event.kind === 'tool:call') {
|
|
170
|
+
if (origin)
|
|
171
|
+
state.childToolOrigins.set(event.toolCallId, origin);
|
|
172
|
+
return origin ? { ...event, origin } : event;
|
|
173
|
+
}
|
|
174
|
+
if (event.kind === 'tool:result') {
|
|
175
|
+
const eventOrigin = origin ?? state.childToolOrigins.get(event.toolCallId);
|
|
176
|
+
state.childToolOrigins.delete(event.toolCallId);
|
|
177
|
+
return eventOrigin ? { ...event, origin: eventOrigin } : event;
|
|
178
|
+
}
|
|
179
|
+
return event;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function mapSdkMessagePayload(msg, state) {
|
|
150
183
|
// Treat as a generic record — the SDK discriminated union is too broad to
|
|
151
184
|
// narrow per branch here.
|
|
152
185
|
const parsed = msg;
|
|
@@ -276,7 +276,16 @@ export function createCodexEngine() {
|
|
|
276
276
|
}
|
|
277
277
|
// Child output remains visible, but its failures/compaction/markers
|
|
278
278
|
// cannot control the parent session or its auto-loop lifecycle.
|
|
279
|
-
return map(state)
|
|
279
|
+
return map(state)
|
|
280
|
+
.filter((event) => event.kind !== 'error' && !event.kind.startsWith('session:'))
|
|
281
|
+
.map((event) => {
|
|
282
|
+
const origin = { kind: 'subagent', threadId: notification.threadId };
|
|
283
|
+
if (event.kind === 'message:text' || event.kind === 'message:thinking' || event.kind === 'message:end')
|
|
284
|
+
return { ...event, origin };
|
|
285
|
+
if (event.kind === 'tool:call' || event.kind === 'tool:result')
|
|
286
|
+
return { ...event, origin };
|
|
287
|
+
return event;
|
|
288
|
+
});
|
|
280
289
|
};
|
|
281
290
|
const itemKey = (threadId, turnId, itemId) => JSON.stringify([threadId, turnId, itemId]);
|
|
282
291
|
const client = createAppServerClient({
|
|
@@ -134,6 +134,7 @@ export function handleItemStarted(item, state) {
|
|
|
134
134
|
events.push({
|
|
135
135
|
kind: 'subagent:progress',
|
|
136
136
|
toolCallId,
|
|
137
|
+
threadIds: item.receiverThreadIds,
|
|
137
138
|
status: 'running',
|
|
138
139
|
description: item.prompt ?? item.tool,
|
|
139
140
|
taskType: item.tool,
|
|
@@ -271,6 +272,7 @@ export function handleItemCompleted(item, state) {
|
|
|
271
272
|
events.push({
|
|
272
273
|
kind: 'subagent:progress',
|
|
273
274
|
toolCallId,
|
|
275
|
+
threadIds: item.receiverThreadIds,
|
|
274
276
|
status: hasActiveAgent ? 'running' : 'done',
|
|
275
277
|
description: item.prompt ?? item.tool,
|
|
276
278
|
taskType: item.tool,
|
|
@@ -8,19 +8,30 @@ export function createStreamingBatcher(emit, options = {}) {
|
|
|
8
8
|
return;
|
|
9
9
|
clearTimeout(entry.timer);
|
|
10
10
|
pending.delete(messageId);
|
|
11
|
-
emit({
|
|
11
|
+
emit({
|
|
12
|
+
kind: 'message:text',
|
|
13
|
+
messageId,
|
|
14
|
+
text: entry.text,
|
|
15
|
+
streaming: true,
|
|
16
|
+
...(entry.origin ? { origin: entry.origin } : {}),
|
|
17
|
+
});
|
|
12
18
|
};
|
|
13
19
|
return {
|
|
14
20
|
push(event) {
|
|
15
21
|
if (event.kind === 'message:text' && event.streaming) {
|
|
16
|
-
|
|
22
|
+
let entry = pending.get(event.messageId);
|
|
23
|
+
if (entry &&
|
|
24
|
+
(entry.origin?.toolCallId !== event.origin?.toolCallId || entry.origin?.threadId !== event.origin?.threadId)) {
|
|
25
|
+
flush(event.messageId);
|
|
26
|
+
entry = undefined;
|
|
27
|
+
}
|
|
17
28
|
if (entry) {
|
|
18
29
|
entry.text += event.text;
|
|
19
30
|
return;
|
|
20
31
|
}
|
|
21
32
|
const timer = setTimeout(() => flush(event.messageId), windowMs);
|
|
22
33
|
timer.unref?.();
|
|
23
|
-
pending.set(event.messageId, { text: event.text, timer });
|
|
34
|
+
pending.set(event.messageId, { text: event.text, origin: event.origin, timer });
|
|
24
35
|
return;
|
|
25
36
|
}
|
|
26
37
|
if (event.kind === 'message:end')
|
|
@@ -306,7 +306,13 @@ async function hasLiveProcessGroup(groupId) {
|
|
|
306
306
|
catch (err) {
|
|
307
307
|
if (err.code === 'ESRCH')
|
|
308
308
|
return false;
|
|
309
|
-
|
|
309
|
+
// Some CI process supervisors reject the signal-0 probe after the shell
|
|
310
|
+
// exits even though `ps` can still inspect its former group. `ps` below is
|
|
311
|
+
// our authoritative liveness check and distinguishes live descendants
|
|
312
|
+
// from a reaped group without turning that platform quirk into a failed
|
|
313
|
+
// dev-server stop.
|
|
314
|
+
if (err.code !== 'EPERM')
|
|
315
|
+
throw err;
|
|
310
316
|
}
|
|
311
317
|
const processes = await runCommand('ps', ['-eo', 'pgid=,stat='], { timeout: 1000 });
|
|
312
318
|
return processes.split('\n').some((line) => {
|
|
@@ -39,52 +39,4 @@ export const CODEX_MODELS = [
|
|
|
39
39
|
i18nLabelKey: 'model.gpt6luna',
|
|
40
40
|
i18nDescriptionKey: 'model.gpt6lunaDescription',
|
|
41
41
|
},
|
|
42
|
-
{
|
|
43
|
-
id: 'gpt-5.6-sol',
|
|
44
|
-
label: 'GPT-5.6 Sol',
|
|
45
|
-
i18nLabelKey: 'model.gpt56sol',
|
|
46
|
-
i18nDescriptionKey: 'model.gpt56solDescription',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
id: 'gpt-5.6-terra',
|
|
50
|
-
label: 'GPT-5.6 Terra',
|
|
51
|
-
i18nLabelKey: 'model.gpt56terra',
|
|
52
|
-
i18nDescriptionKey: 'model.gpt56terraDescription',
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
id: 'gpt-5.6-luna',
|
|
56
|
-
label: 'GPT-5.6 Luna',
|
|
57
|
-
i18nLabelKey: 'model.gpt56luna',
|
|
58
|
-
i18nDescriptionKey: 'model.gpt56lunaDescription',
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: 'gpt-5.5',
|
|
62
|
-
label: 'GPT-5.5',
|
|
63
|
-
i18nLabelKey: 'model.gpt55',
|
|
64
|
-
i18nDescriptionKey: 'model.gpt55Description',
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
id: 'gpt-5.4',
|
|
68
|
-
label: 'GPT-5.4',
|
|
69
|
-
i18nLabelKey: 'model.gpt54',
|
|
70
|
-
i18nDescriptionKey: 'model.gpt54Description',
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
id: 'gpt-5.4-mini',
|
|
74
|
-
label: 'GPT-5.4 mini',
|
|
75
|
-
i18nLabelKey: 'model.gpt54mini',
|
|
76
|
-
i18nDescriptionKey: 'model.gpt54miniDescription',
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: 'gpt-5.2',
|
|
80
|
-
label: 'GPT-5.2',
|
|
81
|
-
i18nLabelKey: 'model.gpt52',
|
|
82
|
-
i18nDescriptionKey: 'model.gpt52Description',
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
id: 'gpt-5.3-codex',
|
|
86
|
-
label: 'GPT-5.3 Codex',
|
|
87
|
-
i18nLabelKey: 'model.gpt53codex',
|
|
88
|
-
i18nDescriptionKey: 'model.gpt53codexDescription',
|
|
89
|
-
},
|
|
90
42
|
];
|
package/dist/shared/models.js
CHANGED
|
@@ -11,6 +11,12 @@ export const CLAUDE_MODELS = [
|
|
|
11
11
|
i18nLabelKey: 'model.fable51',
|
|
12
12
|
i18nDescriptionKey: 'model.fable51Description',
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
id: 'claude-mythos-5-1',
|
|
16
|
+
label: 'Mythos 5.1 (Glasswing)',
|
|
17
|
+
i18nLabelKey: 'model.mythos51',
|
|
18
|
+
i18nDescriptionKey: 'model.mythos51Description',
|
|
19
|
+
},
|
|
14
20
|
{
|
|
15
21
|
id: 'claude-mythos-5',
|
|
16
22
|
label: 'Mythos 5 (Glasswing)',
|
|
@@ -23,66 +29,12 @@ export const CLAUDE_MODELS = [
|
|
|
23
29
|
i18nLabelKey: 'model.opus55',
|
|
24
30
|
i18nDescriptionKey: 'model.opus55Description',
|
|
25
31
|
},
|
|
26
|
-
{
|
|
27
|
-
id: 'claude-opus-5',
|
|
28
|
-
label: 'Opus 5',
|
|
29
|
-
i18nLabelKey: 'model.opus5',
|
|
30
|
-
i18nDescriptionKey: 'model.opus5Description',
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
id: 'claude-opus-4-8',
|
|
34
|
-
label: 'Opus 4.8',
|
|
35
|
-
i18nLabelKey: 'model.opus48',
|
|
36
|
-
i18nDescriptionKey: 'model.opus48Description',
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
id: 'claude-opus-4-7',
|
|
40
|
-
label: 'Opus 4.7 (Classic)',
|
|
41
|
-
i18nLabelKey: 'model.opus47Classic',
|
|
42
|
-
i18nDescriptionKey: 'model.opus47ClassicDescription',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: 'claude-opus-4-7[1m]',
|
|
46
|
-
label: 'Opus 4.7 (1M)',
|
|
47
|
-
i18nLabelKey: 'model.opus471m',
|
|
48
|
-
i18nDescriptionKey: 'model.opus471mDescription',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: 'claude-opus-4-6',
|
|
52
|
-
label: 'Opus 4.6 (Classic)',
|
|
53
|
-
i18nLabelKey: 'model.opusClassic',
|
|
54
|
-
i18nDescriptionKey: 'model.opusClassicDescription',
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
id: 'claude-opus-4-6[1m]',
|
|
58
|
-
label: 'Opus 4.6 (1M)',
|
|
59
|
-
i18nLabelKey: 'model.opus1m',
|
|
60
|
-
i18nDescriptionKey: 'model.opus1mDescription',
|
|
61
|
-
},
|
|
62
32
|
{
|
|
63
33
|
id: 'claude-sonnet-5-5',
|
|
64
34
|
label: 'Sonnet 5.5',
|
|
65
35
|
i18nLabelKey: 'model.sonnet55',
|
|
66
36
|
i18nDescriptionKey: 'model.sonnet55Description',
|
|
67
37
|
},
|
|
68
|
-
{
|
|
69
|
-
id: 'claude-sonnet-5',
|
|
70
|
-
label: 'Sonnet 5',
|
|
71
|
-
i18nLabelKey: 'model.sonnet5',
|
|
72
|
-
i18nDescriptionKey: 'model.sonnet5Description',
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
id: 'claude-sonnet-4-6',
|
|
76
|
-
label: 'Sonnet 4.6 (Classic)',
|
|
77
|
-
i18nLabelKey: 'model.sonnetClassic',
|
|
78
|
-
i18nDescriptionKey: 'model.sonnetClassicDescription',
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
id: 'claude-sonnet-4-6[1m]',
|
|
82
|
-
label: 'Sonnet 4.6 (1M)',
|
|
83
|
-
i18nLabelKey: 'model.sonnet1m',
|
|
84
|
-
i18nDescriptionKey: 'model.sonnet1mDescription',
|
|
85
|
-
},
|
|
86
38
|
{
|
|
87
39
|
id: 'claude-haiku-4-5-20251001',
|
|
88
40
|
label: 'Haiku 4.5',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loicngr/kobo",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.7",
|
|
4
4
|
"description": "Kōbō — local multi-workspace orchestrator for Claude Code and OpenAI Codex, with isolated Git worktrees, live review and optional automation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -81,12 +81,12 @@
|
|
|
81
81
|
"security:scan": "node scripts/scan-secrets.mjs"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
84
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.287",
|
|
85
85
|
"@emnapi/core": "^1.11.3",
|
|
86
86
|
"@emnapi/runtime": "^1.11.3",
|
|
87
87
|
"@hono/node-server": "^2.1.3",
|
|
88
88
|
"@modelcontextprotocol/sdk": "^1.31.0",
|
|
89
|
-
"@openai/codex": "^0.159.
|
|
89
|
+
"@openai/codex": "^0.159.3",
|
|
90
90
|
"better-sqlite3": "^13.0.3",
|
|
91
91
|
"cron-parser": "^5.10.1",
|
|
92
92
|
"hono": "^4.13.12",
|
|
@@ -97,16 +97,16 @@
|
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@biomejs/biome": "2.5.14",
|
|
99
99
|
"@types/better-sqlite3": "^9.6.0",
|
|
100
|
-
"@types/node": "^26.6.
|
|
100
|
+
"@types/node": "^26.6.4",
|
|
101
101
|
"@types/ws": "^8.18.2",
|
|
102
102
|
"@vitest/runner": "^4.1.11",
|
|
103
103
|
"concurrently": "^10.0.5",
|
|
104
104
|
"tsx": "^4.23.15",
|
|
105
105
|
"typescript": "^7.0.2",
|
|
106
|
-
"vitest": "^5.0.
|
|
106
|
+
"vitest": "^5.0.3"
|
|
107
107
|
},
|
|
108
108
|
"overrides": {
|
|
109
109
|
"@hono/node-server": "^2.1.3",
|
|
110
|
-
"shell-quote": "^1.
|
|
110
|
+
"shell-quote": "^1.11.0"
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{M as e,S as t,dt as n,lt as r,p as i,st as a,v as o}from"./reactivity.esm-bundler-tuEvQ47f.js";import{C as s,F as c,J as l,L as u,N as d,O as f,P as p,T as m,Y as h,_ as g,d as _,f as v,g as y,j as ee,k as b,l as x,p as S,r as C,u as w,y as T,z as te}from"./runtime-core.esm-bundler-DOiZcasU.js";import{T as ne,Y as re,l as ie,lt as ae,mt as E,nt as D,t as O,x as oe}from"./QBtn-b_baQtAt.js";import{l as se,n as ce,o as le,t as ue}from"./latest-request-7rgsEfKZ.js";import{a as de}from"./i18n-CPFleoLe.js";import{O as fe,Rt as pe,T as me,Vt as k,ct as he,g as ge,jt as A,nt as _e,p as ve,rt as ye}from"./index-BVJWwOvK.js";import{t as be}from"./QSpinnerDots-BsKmccpX.js";import{t as xe}from"./QList-Cw2xs69W.js";import{t as Se}from"./QMarkupTable-Ck2E2TaI.js";import{c as j,l as M,s as N}from"./QSelect-DUuWu79L.js";import{t as P}from"./QItemSection-BhGnulVQ.js";import{t as Ce}from"./QExpansionItem-DmzCAbka.js";import{a as F,c as we,r as I,t as L}from"./ToolCallItem-BQmqNcfF.js";import{t as Te}from"./QScrollArea-BmBuij9J.js";import{a as R}from"./use-tours-CM4E53aB.js";import{f as Ee,g as z,m as De,p as Oe,u as ke}from"./use-worktree-restore-C__ResAR.js";import{t as B}from"./QTooltip-Dhy3hNTO.js";import{n as V}from"./render-chat-markdown-CafzCcmu.js";import{n as H}from"./WorkspacePage-DQ-jvLEj.js";function Ae(e,t){return s(`div`,e,[s(`table`,{class:`q-table`},t)])}var je={list:xe,table:Se},U=[`list`,`table`,`__qtable`],Me=D({name:`QVirtualScroll`,props:{...M,type:{type:String,default:`list`,validator:e=>U.includes(e)},items:{type:Array,default:()=>[]},itemsFn:Function,itemsSize:Number,scrollTarget:k},setup(e,{slots:n,attrs:r}){let i,a=t(null),o=x(()=>e.itemsSize>=0&&e.itemsFn!==void 0?Number.parseInt(e.itemsSize,10):Array.isArray(e.items)?e.items.length:0),{virtualScrollSliceRange:c,localResetVirtualScroll:u,padVirtualScroll:f,onVirtualScrollEvt:m}=j({virtualScrollLength:o,getVirtualScrollTarget:y,getVirtualScrollEl:v}),h=x(()=>{if(o.value===0)return[];let t=(e,t)=>({index:c.value.from+t,item:e});return e.itemsFn===void 0?e.items.slice(c.value.from,c.value.to).map(t):e.itemsFn(c.value.from,c.value.to-c.value.from).map(t)}),g=x(()=>`q-virtual-scroll q-virtual-scroll`+(e.virtualScrollHorizontal?`--horizontal`:`--vertical`)+(e.scrollTarget===void 0?` scroll`:``)),_=x(()=>e.scrollTarget===void 0?{tabindex:0}:{});l(o,()=>{u()}),l(()=>e.scrollTarget,()=>{C(),S()});function v(){let e=a.value;return e===null?null:e.$el||e}function y(){return i}function S(){let t=v();t!==null&&(i=pe(t,e.scrollTarget),i.addEventListener(`scroll`,m,re.passive))}function C(){i!==void 0&&(i.removeEventListener(`scroll`,m,re.passive),i=void 0)}function w(){let t=f(e.type===`list`?`div`:`tbody`,h.value.map(n.default));return n.before!==void 0&&(t=n.before().concat(t)),oe(n.after,t)}return u(),p(()=>{S()}),b(()=>{S()}),d(()=>{C()}),ee(()=>{C()}),()=>{if(n.default===void 0){console.error(`QVirtualScroll: default scoped slot is required for rendering`);return}return e.type===`__qtable`?Ae({ref:a,class:`q-table__middle `+g.value,tabindex:0},w()):s(je[e.type],{...r,ref:a,class:[r.class,g.value],..._.value},w)}}}),Ne=new Set([`setup`,`cleanup`,`archive`]);function Pe(e){switch(e.type){case`user`:return e.sender===`system-prompt`?`system-prompt`:Ne.has(e.sender)||me(e.sender)?`script`:`user`;case`session`:return`session`;default:return`agent`}}function Fe(e){let t=[],n=null,r=null;for(let i of e){let e=Pe(i),a=e===`session`||e===`system-prompt`,o=e===`script`&&i.type===`user`?`script:${i.sender}`:e===`user`&&i.type===`user`&&i.source?JSON.stringify([`mcp`,i.source.transport,i.source.clientName]):e;!n||r!==o||a?(n={speaker:e,ts:i.ts,items:[i]},r=o,t.push(n),a&&(n=null)):n.items.push(i)}return t}function W(e){switch(e.type){case`text`:return`text:${e.messageId}`;case`thinking`:return`thinking:${e.messageId}:${e.eventIds?.[0]??e.ts??``}`;case`tool`:return`tool:${e.toolCallId}`;case`session`:return`session:${e.kind}:${e.eventIds?.[0]??e.ts??``}`;case`user`:return`user:${e.eventIds?.[0]??`${e.sender}:${e.ts??``}`}`;case`error`:return`error:${e.eventIds?.[0]??`${e.category}:${e.ts??``}`}`}}function Ie(e){let t=e.items[0];return`${e.speaker}:${t?W(t):`empty`}`}function Le(e,t){let n=Math.min(t,e.length)-1;for(let t=n;t>=0;t--)if(e[t]?.speaker===`user`)return t;return-1}function Re(e,t,n){return new Promise(r=>{let i=!1,a=null,o=null,s=e=>{i||(i=!0,a!==null&&clearTimeout(a),a=null,o?.(),r(e))};if(o=l(e,e=>{t(e)&&s(!0)},{immediate:!0}),i){o();return}a=setTimeout(()=>s(!1),n)})}var ze={class:`agent-error-item`},Be={class:`agent-error-item__body`},Ve={class:`agent-error-item__title`},G={class:`agent-error-item__message`},He=R(T({__name:`AgentErrorItem`,props:{item:{}},setup(e){let t=e,{te:r}=de(),i=x(()=>{let e=`agent.error.${t.item.category}`;return r(e)?e:`agent.error.other`});return(t,r)=>(u(),S(`div`,ze,[g(ie,{name:`error_outline`,size:`16px`,class:`agent-error-item__icon`}),w(`div`,Be,[w(`div`,Ve,n(t.$t(i.value)),1),w(`div`,G,n(e.item.message),1)])]))}}),[[`__scopeId`,`data-v-e98c3c02`]]),Ue={class:`text-caption text-kobo-3`},We=T({__name:`SessionEventItem`,props:{item:{}},setup(e){let t=e,r=x(()=>{switch(t.item.kind){case`started`:return`session.started`;case`ended`:return z(t.item.detail);case`compacted`:return`session.compacted`;default:return`session.started`}});return(e,t)=>(u(),S(`span`,Ue,n(e.$t(r.value)),1))}}),K=new Map;function q(){for(let e of K.values())e.controller.abort(),e.blobUrl&&URL.revokeObjectURL(e.blobUrl);K.clear()}typeof window<`u`&&(window.addEventListener(`kobo:auth-token-changed`,q),window.addEventListener(`storage`,e=>{(e.key===`kobo:network-token`||e.key===null)&&q()}));function J(e){if(!/^\/api\/workspaces\/[^/]+\/images\/file\?path=/.test(e))throw Error(`Invalid workspace image URL`);let t=K.get(e);if(!t){let n=new AbortController,r={references:0,controller:n,ready:Promise.resolve(``)};r.ready=le(e,{signal:n.signal}).then(async e=>{if(!e.ok)throw await se(e);let t=await e.blob();if(n.signal.aborted)throw new DOMException(`Aborted`,`AbortError`);return r.blobUrl=URL.createObjectURL(t),r.blobUrl}),t=r,K.set(e,t)}t.references++;let n=!1,r=t;return{ready:r.ready,release(){n||(n=!0,!(--r.references>0)&&(r.controller.abort(),r.blobUrl&&URL.revokeObjectURL(r.blobUrl),K.get(e)===r&&K.delete(e)))}}}function Ge(e,t){let n=o(``),r=o(0),a=()=>{r.value++},s=e=>{(e.key===`kobo:network-token`||e.key===null)&&a()};return window.addEventListener(`kobo:auth-token-changed`,a),window.addEventListener(`storage`,s),i(()=>{window.removeEventListener(`kobo:auth-token-changed`,a),window.removeEventListener(`storage`,s)}),l([e,r],([e],r,i)=>{let a=!0,o=[],s=document.createElement(`template`);s.innerHTML=e;for(let e of s.content.querySelectorAll(`img`)){let r=e.getAttribute(`src`)??``;if(e.removeAttribute(`data-kobo-image-url`),!/^\/api\/workspaces\/[^/]+\/images\/file\?path=/.test(r))continue;e.removeAttribute(`src`);let i=J(r);o.push(i),i.ready.then(t=>{a&&(e.setAttribute(`src`,t),e.setAttribute(`data-kobo-image-url`,r),n.value=s.innerHTML)}).catch(()=>{a&&(e.setAttribute(`title`,t()),n.value=s.innerHTML)})}n.value=s.innerHTML,i(()=>{a=!1;for(let e of o)e.release()})},{immediate:!0}),n}function Ke(e,t){return t?e.replace(/\[image:\s+([^\]]+)\]/g,(e,n)=>{let r=String(n).trim();return/^(\.ai\/images\/|images\/)/.test(r)?`}/images/file?path=${encodeURIComponent(r)}`})`:e}):e}var qe=[`innerHTML`],Je=[`innerHTML`],Ye=[`src`],Y=R(T({__name:`UserMessageItem`,props:{item:{},workspaceId:{}},setup(t){let n=t,{t:r}=de(),a=x(()=>n.item.sender===`system-prompt`),s=Ge(x(()=>{let e=Ke(n.item.content,n.workspaceId);return V(e)}),()=>r(`network.login.unreachable`)),c=o(null),d=o(!1),f;function p(){d.value=!1,c.value=null,f?.release(),f=void 0}l(d,e=>{e||p()}),l(()=>n.workspaceId,p);let m=e=>{(e.key===`kobo:network-token`||e.key===null)&&p()};window.addEventListener(`storage`,m),window.addEventListener(`kobo:auth-token-changed`,p),i(()=>{p(),window.removeEventListener(`kobo:auth-token-changed`,p),window.removeEventListener(`storage`,m)});function y(e){let t=e.target;if(t?.tagName!==`IMG`)return;let n=t;n.src&&(p(),n.dataset.koboImageUrl&&(f=J(n.dataset.koboImageUrl),f.ready.catch(p)),c.value=n.src,d.value=!0)}return(t,n)=>(u(),S(C,null,[a.value?(u(),_(Ce,{key:0,dense:``,"dense-toggle":``,label:t.$t(`chat.systemPrompt`),"header-class":`text-kobo-2 text-caption`},{default:h(()=>[w(`div`,{class:`q-py-xs markdown-user-prompt`,innerHTML:e(s)},null,8,qe)]),_:1},8,[`label`])):(u(),S(`div`,{key:1,class:`markdown-message`,onClick:y},[w(`div`,{innerHTML:e(s)},null,8,Je)])),g(A,{modelValue:d.value,"onUpdate:modelValue":n[1]||=e=>d.value=e},{default:h(()=>[c.value?(u(),S(`img`,{key:0,src:c.value,alt:``,class:`image-lightbox-img`,onClick:n[0]||=e=>d.value=!1},null,8,Ye)):v(``,!0)]),_:1},8,[`modelValue`])],64))}}),[[`__scopeId`,`data-v-db2fc622`]]),Xe=[`data-event-ids`],X={class:`turn-header`},Ze={key:0,class:`turn-time`},Qe={class:`turn-time turn-time-updated`},$e={key:2,class:`turn-actions`},et={class:`turn-body`},tt={class:`ellipsis`},nt={class:`q-px-sm q-pb-sm`},rt={key:0,class:`turn-scroll-top`},it=R(T({__name:`TurnCard`,props:{turn:{},workspaceId:{},highlighted:{type:Boolean}},emits:[`scrollTo`],setup(t,{emit:i}){let s=t,c=i,{t:l}=de(),d=_e(),f=m(F),p=o(null);function ee(){let e=p.value;if(!e)return;let t=e.closest(`.q-scrollarea`)?.querySelector(`.q-scrollarea__content`);if(!t){e.scrollIntoView({behavior:`smooth`,block:`start`});return}let n=e.getBoundingClientRect().top-t.getBoundingClientRect().top;c(`scrollTo`,Math.max(0,n-8))}let b=x(()=>{switch(s.turn.speaker){case`user`:{let e=s.turn.items[0],t=e?.type===`user`?e.source:void 0;return{label:t?l(`chat.externalLlm`,{name:t.clientName}):l(`chat.you`),accent:`var(--kobo-turn-user)`,badgeClass:`turn-badge-user`}}case`agent`:return{label:l(`chat.agent`),accent:`var(--kobo-turn-agent)`,badgeClass:`turn-badge-agent`};case`system-prompt`:return{label:l(`chat.systemPrompt`),accent:`var(--kobo-text-3)`,badgeClass:`turn-badge-system`};case`session`:return{label:l(`chat.session`),accent:`var(--kobo-text-3)`,badgeClass:`turn-badge-session`};case`script`:{let e=s.turn.items[0],t=e?.type===`user`?e.sender:``;return{label:me(t)?l(`chat.hookScript`,{event:t.slice(5)}):l(t===`archive`?`chat.archiveScript`:t===`setup`?`chat.setupScript`:`chat.cleanupScript`),accent:`var(--kobo-success)`,badgeClass:`turn-badge-script`}}}});function T(e,t=!1){if(!e)return``;let n=new Date(e);return Number.isNaN(n.getTime())?``:n.toLocaleTimeString(void 0,t?{hour:`2-digit`,minute:`2-digit`,second:`2-digit`}:{hour:`2-digit`,minute:`2-digit`})}let ne=x(()=>T(s.turn.ts)),re=x(()=>s.turn.items.flatMap(e=>e.eventIds??[]).join(` `)),ae=x(()=>{let e=s.turn.items;if(e.length===0)return null;for(let t=e.length-1;t>=0;t--){let n=e[t].ts;if(n)return n}return null}),D=x(()=>{let e=s.turn.ts,t=ae.value;if(!t||!e||t===e)return``;let n=new Date(e).getTime(),r=new Date(t).getTime();return Number.isNaN(n)||Number.isNaN(r)||r<=n?``:T(t,r-n<6e4)}),oe=x(()=>D.value!==``);function se(e){return we(e.origin,Object.values(d.subagents[s.workspaceId]??{}),e.type===`tool`?e.toolCallId:void 0)}function ce(e){return e||l(`chat.subagentActivity`)}function le(e){return(e.type===`text`||e.type===`thinking`||e.type===`tool`)&&e.origin?.kind===`subagent`}let ue=x(()=>{let e=[];for(let t of s.turn.items){if(!le(t)){e.push({type:`item`,key:W(t),item:t});continue}let n=se(t),r=n?.toolUseId??t.origin?.toolCallId??t.origin?.threadId??W(t),i=e.at(-1);if(i?.type===`subagent`&&i.subagentKey===r){i.items.push(t);continue}e.push({type:`subagent`,key:`subagent:${W(t)}`,items:[t],subagentKey:r,subagentName:n?.description||null})}return e});function fe(e){e.origin&&f?.({origin:e.origin})}let pe=x(()=>s.turn.items.filter(e=>e.type===`tool`).length);return(i,o)=>(u(),S(`div`,{ref_key:`cardEl`,ref:p,class:a([`turn-card`,{"turn-card--user":t.turn.speaker===`user`,"turn-card--highlighted":t.highlighted}]),"data-event-ids":re.value,style:r({"--turn-accent":b.value.accent})},[w(`div`,X,[w(`span`,{class:a([`turn-badge`,b.value.badgeClass])},n(b.value.label),3),ne.value?(u(),S(`span`,Ze,n(ne.value),1)):v(``,!0),oe.value?(u(),S(C,{key:1},[g(ie,{name:`arrow_forward`,size:`10px`,color:`kobo-3`,class:`turn-time-arrow`}),w(`span`,Qe,[y(n(D.value)+` `,1),g(B,null,{default:h(()=>[y(n(e(l)(`chat.lastUpdatedAt`,{time:D.value})),1)]),_:1})])],64)):v(``,!0),pe.value>0?(u(),S(`span`,$e,` · `+n(e(l)(`chat.nActions`,{n:pe.value})),1)):v(``,!0)]),w(`div`,et,[(u(!0),S(C,null,te(ue.value,r=>(u(),S(C,{key:r.key},[r.type===`subagent`?(u(),_(Ce,{key:0,class:`turn-subagent-activity`,dense:``,label:ce(r.subagentName),caption:e(l)(`chat.nActions`,{n:r.items.length}),"default-opened":t.highlighted&&r.items.some(e=>e.eventIds?.some(e=>re.value.includes(e)))},{header:h(()=>[g(P,null,{default:h(()=>[g(N,{class:`row items-center no-wrap`,title:r.subagentName??void 0},{default:h(()=>[g(ie,{name:`hub`,size:`16px`,class:`q-mr-xs`},{default:h(()=>[g(B,null,{default:h(()=>[y(n(e(l)(`chat.subagentActivity`)),1)]),_:1})]),_:1}),w(`span`,tt,n(ce(r.subagentName)),1)]),_:2},1032,[`title`]),g(N,{caption:``},{default:h(()=>[y(n(e(l)(`chat.nActions`,{n:r.items.length})),1)]),_:2},1024)]),_:2},1024),g(P,{side:``},{default:h(()=>[g(O,{flat:``,round:``,dense:``,size:`sm`,icon:`open_in_new`,"aria-label":e(l)(`chat.openSubagentActivity`),onClick:E(e=>fe(r.items[0]),[`stop`])},{default:h(()=>[g(B,null,{default:h(()=>[y(n(e(l)(`chat.openSubagentActivity`)),1)]),_:1})]),_:1},8,[`aria-label`,`onClick`])]),_:2},1024)]),default:h(()=>[w(`div`,nt,[(u(!0),S(C,null,te(r.items,t=>(u(),S(C,{key:e(W)(t)},[t.type===`text`?(u(),_(I,{key:0,item:t},null,8,[`item`])):t.type===`thinking`?(u(),_(H,{key:1,item:t},null,8,[`item`])):t.type===`tool`?(u(),_(L,{key:2,item:t},null,8,[`item`])):v(``,!0)],64))),128))])]),_:2},1032,[`label`,`caption`,`default-opened`])):(u(),S(C,{key:1},[r.item.type===`text`?(u(),_(I,{key:0,item:r.item},null,8,[`item`])):r.item.type===`thinking`?(u(),_(H,{key:1,item:r.item},null,8,[`item`])):r.item.type===`tool`?(u(),_(L,{key:2,item:r.item},null,8,[`item`])):r.item.type===`user`?(u(),_(Y,{key:3,item:r.item,"workspace-id":t.workspaceId},null,8,[`item`,`workspace-id`])):r.item.type===`session`?(u(),_(We,{key:4,item:r.item},null,8,[`item`])):r.item.type===`error`?(u(),_(He,{key:5,item:r.item},null,8,[`item`])):v(``,!0)],64))],64))),128))]),t.turn.items.length>4?(u(),S(`div`,rt,[g(O,{flat:``,round:``,dense:``,size:`xs`,icon:`arrow_upward`,color:`kobo-3`,class:`turn-scroll-top-btn`,onClick:ee},{default:h(()=>[g(B,null,{default:h(()=>[y(n(e(l)(`chat.scrollToTurnTop`)),1)]),_:1})]),_:1})])):v(``,!0)],14,Xe))}}),[[`__scopeId`,`data-v-7f80d364`]]),at={key:0,class:`activity-feed-switching`},ot={key:1,class:`activity-feed-wrap`,"data-tour":`ws-chat`},st={key:0,role:`alert`,class:`q-pa-sm text-negative`},ct={key:1,"data-testid":`history-load-error`,role:`alert`,class:`q-pa-sm text-negative`},lt=[`aria-label`],ut={key:0,class:`activity-feed-compacting`},dt={class:`text-caption text-kobo-2`},ft={key:0,class:`text-center q-py-sm text-caption text-kobo-3`},pt={key:1,class:`activity-feed-empty q-pa-md`},mt={class:`activity-feed-empty__title`},ht={class:`activity-feed-empty__hint`},gt={key:2,class:`q-px-md q-pb-md`},_t=[`title`],vt={class:`ellipsis`},yt={class:`activity-feed-nav-cluster`},bt=300,xt=60,St=200,Ct=180,wt=255,Tt=3,Et=60,Dt=R(T({__name:`ActivityFeed`,props:{workspaceId:{}},setup(t){let{t:r}=de(),i=t,a=he(),s=fe(),d=_e(),m=ve(),ee=x(()=>m.isCompacting(i.workspaceId)),b=x(()=>d.selectedSessionId),T=x(()=>d.sessions.find(e=>e.id===b.value)?.engineSessionId??null),re=x(()=>{let e=d.sessions;return e.length!==0&&b.value===e[e.length-1].id});function E(e){return b.value?e?e===b.value||e===T.value:re.value:!0}let D=x(()=>(d.activityFeeds[i.workspaceId]??[]).filter(e=>e.type===`text`&&typeof e.content==`string`&&E(e.sessionId)).map(e=>({content:e.content,sender:e.meta?.sender??`user`,source:ge(e.meta?.source),ts:e.timestamp,sessionId:e.sessionId,eventIds:[e.id]}))),oe=x(()=>{let e=d.workspaces.find(e=>e.id===i.workspaceId);return ye(e?.status)}),pe=ke(),me=``,k=x(()=>{let e=a.eventsFor(i.workspaceId),t=a.timestampsFor(i.workspaceId),n=a.sessionIdsFor(i.workspaceId),r=a.eventIdsFor(i.workspaceId),o=[],c=[],l=[];for(let i=0;i<e.length;i++)E(n[i])&&(o.push(e[i]),c.push(t[i]),l.push(r[i]??null));let u=`${i.workspaceId}::${b.value??`*`}`;u!==me&&(pe=ke(),me=u);let d=Ee(pe,o,c,oe.value,l);return Fe(De(d,D.value).filter(e=>e.type===`thinking`?!1:e.type===`session`?e.kind===`ended`?s.showVerboseSystemMessages||!Oe(e.detail):s.showVerboseSystemMessages:!0))}),A=x(()=>s.showVerboseSystemMessages?a.eventsFor(i.workspaceId).filter(e=>e.kind===`message:raw`).map(e=>e.content):[]),xe=x(()=>{for(let e=k.value.length-1;e>=0;e--){let t=k.value[e]?.items??[];for(let e=t.length-1;e>=0;e--){let n=t[e];if(n){if(n.type===`text`&&!n.streaming)return{key:`text:${n.messageId}`,text:n.text};if(n.type===`tool`)return n.result?{key:`tool:${n.toolCallId}:end`,text:n.result.isError?r(`activity.a11y.toolFailed`,{name:n.name}):r(`activity.a11y.toolFinished`,{name:n.name})}:{key:`tool:${n.toolCallId}:start`,text:r(`activity.a11y.toolStarted`,{name:n.name})}}}}return null}),Se=o(``);l(xe,(e,t)=>{if(!e||e.key===t?.key)return;let n=e.key.startsWith(`text:`)?r(`activity.a11y.agentSaid`,{text:e.text.slice(0,bt)}):e.text;Se.value=n});let j=o(null),M=o(!0),N=o(!1),P=o(``),F=ue(),we=ue(),I=ue(),L=o(null),R=!1,z=!0,B=null,V=o(new Set),H=new Map,Ae=x(()=>{if(k.value.length>0||A.value.length>0)return!1;let e=i.workspaceId,t=b.value;return!!d.loadingSessions[e]||m.isSyncPending(e)||t!==null&&V.value.has(W(e,t))}),je=o(new Map),U=x(()=>k.value.length>0||A.value.length>0),Ne=x(()=>!!d.loadingSessions[i.workspaceId]||m.isSyncPending(i.workspaceId)||b.value!==null&&V.value.has(W(i.workspaceId,b.value)));function Pe(e){tt();let t=B;if(B=e.verticalSize,t!==null&&e.verticalSize>t&&M.value&&!N.value){q(0);return}let n=e.verticalSize-e.verticalPosition-e.verticalContainerSize;M.value=n<=xt,R&&e.verticalPosition<=St&&!N.value&&!P.value&&ze()&&He()}function W(e,t){return`${e}:${t}`}function ze(){let e=b.value;return e?je.value.get(W(i.workspaceId,e))??!0:a.hasMoreOlderFor(i.workspaceId)}function Be(e,t,n){je.value.set(W(e,t),n)}function Ve(e){if(!b.value)return a.oldestIdFor(e);let t=a.eventIdsFor(e),n=a.sessionIdsFor(e);for(let e=0;e<t.length;e++){if(!E(n[e]))continue;let r=t[e];if(r)return r}}let G=null;function He(){if(G)return G;let e=K().finally(()=>{G===e&&(G=null)});return G=e,G}function Ue(){F.abort(),we.abort(),I.abort(),N.value=!1,G=null;for(let e of V.value)Ft.delete(e);H.clear(),V.value.clear(),P.value=``}function We(){P.value=``,Nt.value===0&&b.value?It():He()}l(()=>[i.workspaceId,b.value],Ue,{flush:`sync`});async function K(){let e=i.workspaceId,t=b.value,n=Ve(e);if(!n)return;let r=F.begin();P.value=``,N.value=!0;try{let i=j.value;if(await f(),!F.isCurrent(r))return;let o=i?.getScroll().verticalSize??0,s=i?.getScroll().verticalPosition??0,c=new URLSearchParams({before:n,limit:`200`});t&&c.set(`session`,t);let l=await le(`/api/workspaces/${e}/events?${c.toString()}`,{signal:r});if(!l.ok)throw await se(l);let u=await l.json();if(!F.isCurrent(r))return;let p=u.events??[],m=p.filter(t=>t.type===`agent:event`&&t.workspaceId===e),h=p.filter(t=>t.type===`user:message`&&t.workspaceId===e),g=m.map(e=>e.payload),_=m.map(e=>e.createdAt),v=m.map(e=>e.sessionId??null),y=m.map(e=>e.id),ee=p.length>0?p[0].id:n;t&&Be(e,t,u.hasMore),a.prepend(e,g,_,{oldestId:ee,hasMoreOlder:t?a.hasMoreOlderFor(e):u.hasMore,sessionIds:v,eventIds:y});for(let t of h){let n=t.payload;typeof n.content==`string`&&d.addActivityItem(e,{id:t.id,type:`text`,content:n.content,timestamp:t.createdAt,sessionId:t.sessionId??void 0,meta:{sender:n.sender??`user`,source:ge(n.source)}})}if(await f(),i&&F.isCurrent(r)){let e=i.getScroll().verticalSize-o;if(e>0){let t=Math.max(s+e,250);i.setScrollPosition(`vertical`,t,0)}}}catch(e){if(ce(e)||!F.isCurrent(r))return;P.value=e instanceof Error?e.message:String(e),console.error(`[ActivityFeed] failed to load older events:`,e)}finally{F.isCurrent(r)&&(N.value=!1)}}async function q(e=0){let t=$();if(await f(),t!==$())return;let n=j.value;if(!n)return;let r=n.getScroll();n.setScrollPosition(`vertical`,r.verticalSize,e)}let J=null,Ge=0;function Ke(){if(J!=null)return;let e=performance.now()-Ge<Ct,t=$();J=requestAnimationFrame(()=>{J=null,t===$()&&(Ge=performance.now(),q(e?0:180))})}function qe(e){Q(),M.value=!1;let t=j.value;t&&t.setScrollPosition(`vertical`,Math.max(0,e),250)}function Je(){let e=window.location.hash,t=e.indexOf(`?`);if(t===-1||!new URLSearchParams(e.slice(t+1)).has(`eventId`))return;let n=e.slice(0,t);window.history.replaceState(window.history.state,``,`${window.location.pathname}${window.location.search}${n}`)}async function Ye(e){let t=e.detail;if(t?.workspaceId!==i.workspaceId||!t.eventId)return;Q(),M.value=!1;let n=I.begin(),r=i.workspaceId;try{let e=new URLSearchParams({around:t.eventId,limit:`200`});t.sessionId&&e.set(`session`,t.sessionId);let o=await le(`/api/workspaces/${r}/events?${e}`,{signal:n});if(!o.ok)throw await se(o);let s=await o.json();if(!I.isCurrent(n))return;let c=s.events??[],l=c.filter(e=>e.type===`agent:event`&&e.workspaceId===i.workspaceId),u=c.filter(e=>e.type===`user:message`&&e.workspaceId===i.workspaceId);a.reset(i.workspaceId,l.map(e=>e.payload),l.map(e=>e.createdAt),{oldestId:c[0]?.id,hasMoreOlder:s.hasMore??!1,sessionIds:l.map(e=>e.sessionId),eventIds:l.map(e=>e.id)});for(let e of u){let t=e.payload;typeof t.content==`string`&&d.addActivityItem(i.workspaceId,{id:e.id,type:`text`,content:t.content,timestamp:e.createdAt,sessionId:e.sessionId??void 0,meta:{sender:t.sender??`user`,source:ge(t.source)}})}if(await Re(Ae,e=>!e,5e3),await f(),await new Promise(e=>requestAnimationFrame(()=>requestAnimationFrame(()=>e()))),!I.isCurrent(n))return;let p=k.value.findIndex(e=>e.items.some(e=>e.eventIds?.includes(t.eventId)??!1));if(p<0)return;L.value=t.eventId,Y.value?.scrollTo(p,`center`),X.value=p,window.setTimeout(()=>{L.value===t.eventId&&(L.value=null)},1800)}catch(e){if(ce(e)||!I.isCurrent(n))return;P.value=e instanceof Error?e.message:String(e),console.error(`[ActivityFeed] failed to focus history event:`,e)}}let Y=o(null),Xe=o(null),X=o(0),Ze=o(!1),Qe=x(()=>{for(let e=k.value.length-1;e>=0;e--)if(k.value[e]?.speaker===`user`)return e;return-1}),$e=null;function et(){let e=Qe.value,t=j.value?.getScrollTarget(),n=t?.querySelector(`[data-turn-index="${e}"]`);if(!n||!t){Ze.value=!1;return}let r=t.getBoundingClientRect(),i=n.getBoundingClientRect();Ze.value=i.bottom>r.top&&i.top<r.bottom}function tt(){$e===null&&($e=requestAnimationFrame(()=>{$e=null,et()}))}function nt(e){return e.length<=wt?e:`${e.slice(0,252)}...`}let rt=x(()=>{let e=Qe.value,t=k.value[e];if(!t||X.value<=e||Ze.value)return null;let n=t.items.filter(e=>e.type===`user`).map(e=>e.content).join(`
|
|
2
|
+
`).trim();return n?{index:e,content:nt(n)}:null});function Dt(e){X.value=e.index,tt()}function Ot(){let e=rt.value;e&&(Q(),M.value=!1,Y.value?.scrollTo(e.index,`start`),X.value=e.index)}let kt=o(!1);async function At(){if(kt.value)return;Q(),M.value=!1,kt.value=!0;let e=i.workspaceId;try{let t=Le(k.value,X.value);if(t<0)for(let n=0;n<15;n++){if(e!==i.workspaceId)return;if(!ze())break;let n=k.value.length;if(await He(),await f(),e!==i.workspaceId)return;if(X.value+=k.value.length-n,t=Le(k.value,X.value),t>=0)break}t>=0&&e===i.workspaceId&&(Y.value?.scrollTo(t,`start`),X.value=t)}finally{kt.value=!1}}let Z=0;function jt(){return new Promise(e=>requestAnimationFrame(()=>e()))}async function Mt(){if(!z||!U.value||Ae.value)return;R=!1;let e=++Z;if(await f(),e!==Z||!z||(Xe.value=j.value?.getScrollTarget()??null,await f(),e!==Z||!z))return;k.value.length>0&&Y.value?.scrollTo(k.value.length-1,`end-force`),await jt();let t=-1,n=0;for(let r=0;r<Et&&n<Tt;r++){if(e!==Z||!z)return;await q(0),await jt();let r=j.value?.getScroll().verticalSize??0;B=r,n=r===t?n+1:0,t=r}e===Z&&!Ne.value&&(R=!0,z=!1)}function Q(){z=!1,!R&&(Z++,R=!0)}let Nt=x(()=>{let e=a.sessionIdsFor(i.workspaceId);if(!b.value)return e.length;let t=0;for(let n of e)E(n)&&t++;return t});l(Ae,async e=>{!e&&U.value&&await Mt(),e||f(()=>{Xe.value=j.value?.getScrollTarget()??null,tt()})}),l(Ne,(e,t)=>{!e&&t&&z&&U.value&&Mt()}),p(()=>{window.addEventListener(`kobo:focus-history-event`,Ye),f(()=>{Xe.value=j.value?.getScrollTarget()??null,tt()}),U.value&&Mt(),b.value&&It();let e=new URLSearchParams(window.location.hash.split(`?`)[1]??``).get(`eventId`);e&&(Ye(new CustomEvent(`kobo:focus-history-event`,{detail:{workspaceId:i.workspaceId,sessionId:b.value,eventId:e}})),Je())}),l([Nt,()=>D.value.length,()=>A.value.length],async([e,t,n])=>{N.value||z&&e+t+n>0&&await Mt()}),l([Qe,()=>k.value.length],()=>{f(tt)});let Pt=x(()=>a.liveAppendCountFor(i.workspaceId,E)),$=()=>`${i.workspaceId}\u0000${d.selectedSessionId??``}`;l([Pt,$],([e,t],[n,r])=>{t===r&&e>n&&M.value&&!N.value&&Ke()}),c(()=>{Z++,z=!1,Ue(),window.removeEventListener(`kobo:focus-history-event`,Ye),J!=null&&(cancelAnimationFrame(J),J=null),$e!==null&&cancelAnimationFrame($e)}),l([()=>i.workspaceId,()=>d.selectedSessionId],()=>{Z++,z=!0,B=null,M.value=!0,R=!1,It(),U.value&&Mt()});let Ft=new Set;async function It(){let e=i.workspaceId,t=b.value;if(!t||Nt.value>0)return;let n=W(e,t);if(Ft.has(n))return;Ft.add(n),V.value.add(n);let r=we.begin();H.set(n,r),P.value=``;try{let n=await le(`/api/workspaces/${e}/events?session=${encodeURIComponent(t)}&limit=500`,{signal:r});if(!n.ok)throw await se(n);let i=await n.json();if(!we.isCurrent(r))return;let o=i.events??[];if(o.length===0)return;let s=o.filter(t=>t.type===`agent:event`&&t.workspaceId===e),c=o.filter(t=>t.type===`user:message`&&t.workspaceId===e),l=s.map(e=>e.payload),u=s.map(e=>e.createdAt),f=s.map(e=>e.sessionId??null),p=s.map(e=>e.id);Be(e,t,i.hasMore),l.length>0&&a.prepend(e,l,u,{oldestId:o[0].id,hasMoreOlder:a.hasMoreOlderFor(e),sessionIds:f,eventIds:p});for(let t of c){let n=t.payload;typeof n.content==`string`&&d.addActivityItem(e,{id:t.id,type:`text`,content:n.content,timestamp:t.createdAt,sessionId:t.sessionId??void 0,meta:{sender:n.sender??`user`,source:ge(n.source)}})}}catch(e){if(ce(e)||!we.isCurrent(r)){(!H.has(n)||H.get(n)===r)&&Ft.delete(n);return}P.value=e instanceof Error?e.message:String(e),console.error(`[ActivityFeed] fetchSessionIfMissing failed:`,e),Ft.delete(n)}finally{H.get(n)===r&&(H.delete(n),V.value.delete(n))}}let Lt=x(()=>D.value.filter(e=>e.sender===`user`).length),Rt=x(()=>(d.activityFeeds[i.workspaceId]??[]).filter(e=>e.meta?.sender===`user`&&e.meta.pending&&E(e.sessionId)).length);l([Lt,Rt,$],async([e,t,n],[r,i,a])=>{let o=t>i;n===a&&(o||e>r&&M.value&&!N.value&&!Ne.value)&&(M.value=!0,await q(o?180:0))});async function zt(){M.value=!0,await q(250)}return(t,r)=>Ae.value?(u(),S(`div`,at,[g(be,{size:`40px`,color:`primary`})])):(u(),S(`div`,ot,[e(d).sessionsErrors[i.workspaceId]?(u(),S(`div`,st,[y(n(t.$t(`activity.sessionsError`,{message:e(d).sessionsErrors[i.workspaceId]}))+` `,1),g(O,{flat:``,dense:``,label:t.$t(`common.retry`),onClick:r[0]||=t=>e(d).fetchSessions(i.workspaceId)},null,8,[`label`])])):v(``,!0),P.value?(u(),S(`div`,ct,[y(n(t.$t(`activity.historyError`,{message:P.value}))+` `,1),g(O,{flat:``,dense:``,label:t.$t(`common.retry`),onClick:We},null,8,[`label`])])):v(``,!0),w(`div`,{"data-testid":`activity-live-region`,class:`sr-only`,role:`log`,"aria-live":`polite`,"aria-atomic":`true`,"aria-label":t.$t(`activity.a11y.region`)},n(Se.value),9,lt),g(ae,{name:`fade`},{default:h(()=>[ee.value?(u(),S(`div`,ut,[g(be,{size:`18px`,color:`primary`}),w(`span`,dt,n(t.$t(`activity.compacting`)),1)])):v(``,!0)]),_:1}),g(Te,{ref_key:`scrollRef`,ref:j,class:`activity-feed-scroll`,onScroll:Pe,onWheelPassive:Q,onTouchstartPassive:Q,onKeydown:Q},{default:h(()=>[N.value?(u(),S(`div`,ft,[g(ne,{size:`sm`}),y(` `+n(t.$t(`activity.loading_older`)),1)])):v(``,!0),g(Me,{ref_key:`virtualScrollRef`,ref:Y,class:`q-pa-md`,items:k.value,"scroll-target":Xe.value??void 0,"virtual-scroll-item-size":160,"virtual-scroll-slice-size":20,onVirtualScroll:Dt},{default:h(({item:t,index:n})=>[(u(),_(it,{key:e(Ie)(t),turn:t,"workspace-id":i.workspaceId,"data-turn-index":n,highlighted:t.items.some(e=>e.eventIds?.includes(L.value??``)??!1),onScrollTo:qe},null,8,[`turn`,`workspace-id`,`data-turn-index`,`highlighted`]))]),_:1},8,[`items`,`scroll-target`]),k.value.length===0&&A.value.length===0&&!N.value?(u(),S(`div`,pt,[g(ie,{name:`forum`,size:`28px`}),w(`div`,mt,n(t.$t(`activity.empty`)),1),w(`div`,ht,n(t.$t(`activity.emptyHint`)),1)])):v(``,!0),A.value.length?(u(),S(`div`,gt,[g(Ce,{label:t.$t(`activity.raw_lines`,{n:A.value.length}),dense:``},{default:h(()=>[(u(!0),S(C,null,te(A.value,(e,t)=>(u(),S(`div`,{key:t,class:`text-caption text-kobo-3 q-pa-xs`},n(e),1))),128))]),_:1},8,[`label`])])):v(``,!0)]),_:1},512),rt.value?(u(),S(`button`,{key:2,type:`button`,class:`activity-feed-last-user`,"data-testid":`latest-user-message`,title:rt.value.content,onClick:Ot},[g(ie,{name:`person`,size:`16px`}),w(`span`,vt,n(rt.value.content),1)],8,_t)):v(``,!0),w(`div`,yt,[M.value?v(``,!0):(u(),_(O,{key:0,round:``,dense:``,unelevated:``,color:`kobo-surface-2`,"text-color":`kobo-1`,icon:`arrow_downward`,size:`sm`,class:`activity-feed-nav-btn`,title:t.$t(`activity.scroll_to_bottom`),"aria-label":t.$t(`activity.scroll_to_bottom`),onClick:zt},null,8,[`title`,`aria-label`])),g(O,{round:``,dense:``,unelevated:``,color:`kobo-surface-2`,"text-color":`kobo-1`,icon:`arrow_upward`,size:`sm`,class:`activity-feed-nav-btn`,title:t.$t(`activity.prev_user_message`),"aria-label":t.$t(`activity.prev_user_message`),loading:kt.value,disable:kt.value,onClick:At},null,8,[`title`,`aria-label`,`loading`,`disable`])])]))}}),[[`__scopeId`,`data-v-58324159`]]);export{Dt as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.agent-error-item[data-v-e98c3c02]{gap:var(--kobo-space-sm);padding:var(--kobo-space-sm) var(--kobo-space-md);border-left:2px solid var(--kobo-danger);background:var(--kobo-surface-2);border-radius:var(--kobo-radius-sm);align-items:flex-start;display:flex}.agent-error-item__icon[data-v-e98c3c02]{color:var(--kobo-danger);flex:none;margin-top:2px}.agent-error-item__body[data-v-e98c3c02]{min-width:0}.agent-error-item__title[data-v-e98c3c02]{color:var(--kobo-text);font-weight:600}.agent-error-item__message[data-v-e98c3c02]{color:var(--kobo-text-2);font-family:var(--kobo-font-mono);white-space:pre-wrap;word-break:break-word;font-size:12px}.markdown-message[data-v-db2fc622]{color:var(--kobo-text-2);word-break:break-word;overflow-wrap:anywhere;min-width:0;max-width:100%;font-size:13px;line-height:1.55}.markdown-message[data-v-db2fc622] *{max-width:100%}.markdown-message[data-v-db2fc622] img{-o-object-fit:contain;object-fit:contain;cursor:zoom-in;background:#0003;border-radius:4px;max-width:180px;max-height:100px;margin:.3em 0;display:block}.markdown-message[data-v-db2fc622] code{word-break:break-all}.markdown-message[data-v-db2fc622] p{margin:0 0 .4em}.markdown-message[data-v-db2fc622] p:last-child{margin-bottom:0}.markdown-message[data-v-db2fc622] code{background:#00000040;border-radius:3px;padding:.1em .3em}.markdown-message[data-v-db2fc622] h1,.markdown-message[data-v-db2fc622] h2,.markdown-message[data-v-db2fc622] h3,.markdown-message[data-v-db2fc622] h4,.markdown-message[data-v-db2fc622] h5,.markdown-message[data-v-db2fc622] h6{margin:.4em 0 .25em;font-weight:600;line-height:1.3}.markdown-message[data-v-db2fc622] h1{font-size:1.25em}.markdown-message[data-v-db2fc622] h2{font-size:1.15em}.markdown-message[data-v-db2fc622] h3{font-size:1.08em}.markdown-message[data-v-db2fc622] h4,.markdown-message[data-v-db2fc622] h5,.markdown-message[data-v-db2fc622] h6{font-size:1em}.markdown-user-prompt[data-v-db2fc622]{color:var(--kobo-text-2);font-size:12px;font-style:italic}.markdown-user-prompt[data-v-db2fc622] p{margin:0 0 .4em}.markdown-user-prompt[data-v-db2fc622] code{background:#ffffff14;border-radius:3px;padding:.1em .3em;font-style:normal}.image-lightbox-img{-o-object-fit:contain;object-fit:contain;cursor:zoom-out;background:#0000004d;border-radius:4px;max-width:92vw;max-height:92vh;display:block}.turn-card[data-v-7f80d364]{border:1px solid #ffffff14;border-left:3px solid var(--turn-accent);background:#ffffff05;border-radius:6px;min-width:0;max-width:100%;margin:14px 0;overflow:hidden}.turn-card--highlighted[data-v-7f80d364]{animation:1.8s ease-out search-highlight-7f80d364}@keyframes search-highlight-7f80d364{0%,45%{box-shadow:0 0 0 2px #818cf8f2,0 0 22px #818cf873}to{box-shadow:none}}.turn-header[data-v-7f80d364]{color:var(--kobo-text-3);background:#ffffff08;border-bottom:1px solid #ffffff0d;align-items:center;gap:8px;padding:8px 14px;font-size:11px;display:flex}.turn-badge[data-v-7f80d364]{letter-spacing:.3px;border-radius:3px;padding:2px 8px;font-size:11px;font-weight:700}.turn-badge-user[data-v-7f80d364]{color:var(--kobo-turn-user);background:#ce93d826}.turn-badge-agent[data-v-7f80d364]{color:var(--kobo-turn-agent);background:#7986cb26}.turn-badge-system[data-v-7f80d364]{color:var(--kobo-text-2);background:#75757533;font-style:italic}.turn-badge-session[data-v-7f80d364]{color:var(--kobo-text-3);background:#61616133}.turn-badge-script[data-v-7f80d364]{color:var(--kobo-success);background:#4db6ac26}.turn-time[data-v-7f80d364]{color:var(--kobo-text-disabled);font-family:var(--kobo-font-mono);font-size:11px}.turn-time-arrow[data-v-7f80d364]{opacity:.7;margin:0 -2px}.turn-time-updated[data-v-7f80d364]{color:var(--kobo-text-3)}.turn-actions[data-v-7f80d364]{color:var(--kobo-text-3);font-size:11px}.turn-body[data-v-7f80d364]{flex-direction:column;gap:12px;min-width:0;padding:14px 18px;display:flex}.turn-body[data-v-7f80d364]>*{min-width:0;max-width:100%}.turn-body[data-v-7f80d364] .tool-row+.tool-row{margin-top:-8px}.turn-scroll-top[data-v-7f80d364]{justify-content:flex-start;padding:0 8px 6px;display:flex}.turn-scroll-top-btn[data-v-7f80d364]{opacity:.5;transition:opacity .15s}.turn-scroll-top-btn[data-v-7f80d364]:hover{opacity:1}.activity-feed-wrap[data-v-58324159]{flex-direction:column;width:100%;height:100%;display:flex;position:relative}.activity-feed-scroll[data-v-58324159]{flex:1;width:100%;height:100%;min-height:0}.activity-feed-nav-cluster[data-v-58324159]{z-index:2;align-items:center;gap:8px;display:flex;position:absolute;bottom:14px;right:14px}.activity-feed-last-user[data-v-58324159]{z-index:2;border:1px solid var(--kobo-border);background:var(--kobo-surface-2);min-width:0;color:var(--kobo-text-2);font:inherit;text-align:left;cursor:pointer;border-radius:6px;align-items:center;gap:8px;padding:7px 10px;font-size:12px;display:flex;position:absolute;top:14px;left:14px;right:104px;box-shadow:0 4px 16px #00000059}.activity-feed-last-user[data-v-58324159]:hover{color:var(--kobo-text);border-color:var(--q-primary)}.activity-feed-last-user[data-v-58324159]:focus-visible{outline:2px solid var(--q-primary);outline-offset:2px}.activity-feed-compacting[data-v-58324159]{z-index:3;background:var(--kobo-surface);border:1px solid var(--kobo-border);border-radius:6px;align-items:center;gap:8px;padding:6px 14px;display:flex;position:absolute;top:12px;left:50%;transform:translate(-50%);box-shadow:0 4px 16px #00000059}.fade-enter-active[data-v-58324159],.fade-leave-active[data-v-58324159]{transition:opacity .16s}.fade-enter-from[data-v-58324159],.fade-leave-to[data-v-58324159]{opacity:0}.activity-feed-nav-btn[data-v-58324159]{opacity:.8;transition:opacity .12s}.activity-feed-nav-btn[data-v-58324159]:hover{opacity:1}.activity-feed-scroll[data-v-58324159] .q-scrollarea__content{max-width:100%;overflow-x:hidden}.activity-feed-switching[data-v-58324159]{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.activity-feed-empty[data-v-58324159]{align-items:center;gap:var(--kobo-space-sm);padding:var(--kobo-space-4xl) var(--kobo-space-xl);color:var(--kobo-text-3);text-align:center;flex-direction:column;display:flex}.activity-feed-empty__title[data-v-58324159]{font-family:var(--kobo-font-sans);color:var(--kobo-text-2);font-size:14px;font-weight:500}.activity-feed-empty__hint[data-v-58324159]{font-family:var(--kobo-font-sans);color:var(--kobo-text-3);max-width:380px;font-size:13px}
|