@loicngr/kobo 2.1.22 → 2.1.24
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/AGENTS.md +72 -1
- package/CHANGELOG.md +8 -0
- package/CONFIGURATION.md +145 -3
- package/dist/mcp-server/kobo-tasks-server.js +7 -6
- package/dist/server/index.js +21 -6
- package/dist/server/routes/mcp.js +13 -7
- package/dist/server/services/agent/orchestrator.js +1 -0
- package/dist/server/services/dev-server-service.js +44 -72
- package/dist/server/services/lifecycle-hook-service.js +21 -2
- package/dist/server/services/mcp-message-delivery-service.js +1 -1
- package/dist/server/services/mcp-message-request-service.js +11 -5
- package/dist/server/services/settings-service.js +51 -0
- package/dist/server/services/workspace-dialogue-service.js +2 -0
- package/dist/server/services/workspace-message-service.js +61 -5
- package/dist/server/utils/dev-server-instance.js +58 -0
- package/dist/server/utils/script-runner.js +6 -1
- package/dist/shared/launch-instructions.js +8 -4
- package/dist/shared/mcp-attachments.js +58 -0
- package/dist/shared/memory-tools.js +2 -2
- package/dist/shared/workspace-creation-tools.js +4 -28
- package/dist/shared/workspace-dialogue-tools.js +18 -6
- package/docker-compose.vps.yml +1 -1
- package/docs/deployment-vps.md +11 -0
- package/package.json +1 -1
- package/scripts/kobo-update +6 -2
- package/src/client/dist/pwa/assets/ActivityFeed-BYspOKKg.js +2 -0
- package/src/client/dist/pwa/assets/{ActivityFeed-DdJvMzRI.css → ActivityFeed-CmAFv-2c.css} +1 -1
- package/src/client/dist/pwa/assets/{AutoLoopFinalReviewSettings-CwnNUWCh.js → AutoLoopFinalReviewSettings-DXX3CqrY.js} +1 -1
- package/src/client/dist/pwa/assets/{ChangelogPage-D9ke0TYz.js → ChangelogPage-DKkI5IU-.js} +1 -1
- package/src/client/dist/pwa/assets/{ComparisonPanel-ytDu1L7a.js → ComparisonPanel-Cw5Dkan0.js} +1 -1
- package/src/client/dist/pwa/assets/{CreatePage-YQ_jGilf.js → CreatePage-B7PLFOH6.js} +1 -1
- package/src/client/dist/pwa/assets/{DashboardPage-C-PyArla.js → DashboardPage-Dw8nfkYR.js} +1 -1
- package/src/client/dist/pwa/assets/{DiffViewer-CPobwSwm.js → DiffViewer-DFlDwkmd.js} +3 -3
- package/src/client/dist/pwa/assets/{DocumentsPanel-BjZGNI-p.js → DocumentsPanel-CH0KzdJV.js} +1 -1
- package/src/client/dist/pwa/assets/{DrawerToggleButton-Dtd6fhYu.js → DrawerToggleButton-CZVpU8HH.js} +1 -1
- package/src/client/dist/pwa/assets/{GitPanel-BHJ3lpJZ.js → GitPanel-DjKL30gM.js} +3 -3
- package/src/client/dist/pwa/assets/{HealthPage-Lv_IdF1l.js → HealthPage-DnPp8GSx.js} +1 -1
- package/src/client/dist/pwa/assets/{MainLayout-DYumlWcP.js → MainLayout-1PaKfzdy.js} +2 -2
- package/src/client/dist/pwa/assets/{MemoryPanel-DS2F3x-S.js → MemoryPanel-BarliK2r.js} +1 -1
- package/src/client/dist/pwa/assets/{MemoryProposalList-D_KDS3uX.js → MemoryProposalList-BtVjVPp7.js} +1 -1
- package/src/client/dist/pwa/assets/{QBtnDropdown-XkBxmJO9.js → QBtnDropdown-Rzurb7nO.js} +1 -1
- package/src/client/dist/pwa/assets/{QExpansionItem-B5vbHxJ2.js → QExpansionItem-CaKEBcyx.js} +1 -1
- package/src/client/dist/pwa/assets/{QScrollArea-BE_fAg20.js → QScrollArea-hrsAyyJf.js} +1 -1
- package/src/client/dist/pwa/assets/{QSelect-BjZk4-r8.js → QSelect-Dr7rAt6u.js} +1 -1
- package/src/client/dist/pwa/assets/{QTooltip-Dhn6VXWR.js → QTooltip-CNMsXTmD.js} +1 -1
- package/src/client/dist/pwa/assets/{SchedulePanel-BDhIt9pX.js → SchedulePanel-nDw2eZ9K.js} +1 -1
- package/src/client/dist/pwa/assets/{SearchPage-CJrtIenZ.js → SearchPage-BXJ6iVt1.js} +1 -1
- package/src/client/dist/pwa/assets/SettingsPage-Dcq1Jeoo.css +1 -0
- package/src/client/dist/pwa/assets/SettingsPage-SHpE2q9Z.js +9 -0
- package/src/client/dist/pwa/assets/{SplitWorkspacePage-BV62otQw.js → SplitWorkspacePage-tfZ1kAdZ.js} +1 -1
- package/src/client/dist/pwa/assets/{TerminalPanel-TQUHtZ-q.js → TerminalPanel-Cw8R7lAw.js} +1 -1
- package/src/client/dist/pwa/assets/{ToolCallItem-DxdYefuz.js → ToolCallItem-DEKhFJEv.js} +2 -2
- package/src/client/dist/pwa/assets/{TouchPan-CtwfZgkX.js → TouchPan-DybGzRRK.js} +1 -1
- package/src/client/dist/pwa/assets/{TourReplayButton-DEC_Yt6E.js → TourReplayButton-BNdlAZUR.js} +1 -1
- package/src/client/dist/pwa/assets/{WorkspaceAttentionLabels-BehGsWhI.js → WorkspaceAttentionLabels-B0H9omcK.js} +1 -1
- package/src/client/dist/pwa/assets/{WorkspacePage-Bk-WWOYM.css → WorkspacePage-B-82Rw9T.css} +1 -1
- package/src/client/dist/pwa/assets/{WorkspacePage-CQz6QL5L.js → WorkspacePage-tWGXnmrz.js} +3 -3
- package/src/client/dist/pwa/assets/{browser-B3bGJv7H.js → browser-DUTZhU-w.js} +1 -1
- package/src/client/dist/pwa/assets/{build-path-tree-Bwwe_8vU.js → build-path-tree-ZThcsIN5.js} +1 -1
- package/src/client/dist/pwa/assets/{custom-sounds-1Rb1a5LA.js → custom-sounds-CquHn2gw.js} +1 -1
- package/src/client/dist/pwa/assets/{de-bfOiFUu1.js → de-B3H0T-ft.js} +2 -2
- package/src/client/dist/pwa/assets/{editor.api-D2PTZoSF.js → editor.api-pSvhgban.js} +1 -1
- package/src/client/dist/pwa/assets/{efforts-JkWc_mU5.js → efforts-DJaFsLgd.js} +1 -1
- package/src/client/dist/pwa/assets/{es-C5Sk8pec.js → es-B4lACW6k.js} +2 -2
- package/src/client/dist/pwa/assets/{expand-template-C-aGZz7k.js → expand-template-C5D_p5eV.js} +1 -1
- package/src/client/dist/pwa/assets/{format-BbXB3nKS.js → format-DRfnkeRP.js} +1 -1
- package/src/client/dist/pwa/assets/{formatters-Bu3lC0Jk.js → formatters-Cog2icjt.js} +1 -1
- package/src/client/dist/pwa/assets/{fr-BNVJp67K.js → fr-3uNi02Jz.js} +2 -2
- package/src/client/dist/pwa/assets/{freemarker2-qq6O820q.js → freemarker2-W-OLsqOk.js} +1 -1
- package/src/client/dist/pwa/assets/{handlebars-nXATCa7t.js → handlebars-Kt5RbWuO.js} +1 -1
- package/src/client/dist/pwa/assets/{html-ZSNyTQeY.js → html-D5VKPBbB.js} +1 -1
- package/src/client/dist/pwa/assets/i18n-CEzCwMir.js +1 -0
- package/src/client/dist/pwa/assets/{index-BZKHE14f.js → index-BZwhT2-I.js} +4 -4
- package/src/client/dist/pwa/assets/{it-B9g24VRZ.js → it-DtFWyLHb.js} +2 -2
- package/src/client/dist/pwa/assets/{javascript-B3Elzrc0.js → javascript-DBjx8Bg2.js} +1 -1
- package/src/client/dist/pwa/assets/{liquid-CrMGh9mA.js → liquid-DYT4a7D7.js} +1 -1
- package/src/client/dist/pwa/assets/{mdx-C6nxSGQ5.js → mdx-9L1kysEY.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco-contributions-WtuTHJJ8.js → monaco-contributions-DAme5TZS.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco.contribution--KeSH1BU.js → monaco.contribution-C58k7TPw.js} +2 -2
- package/src/client/dist/pwa/assets/{network-auth-DknPaiQS.js → network-auth-BDUlgV-U.js} +1 -1
- package/src/client/dist/pwa/assets/{notify-theme-DTaB0RsK.js → notify-theme-DrQB-mrb.js} +1 -1
- package/src/client/dist/pwa/assets/{project-color-bm_jpHka.js → project-color-BlV5PUUW.js} +1 -1
- package/src/client/dist/pwa/assets/{python-CQI_FwfK.js → python-DJIlKr-Y.js} +1 -1
- package/src/client/dist/pwa/assets/{razor-BT2wh4_7.js → razor-CC3uqdaH.js} +1 -1
- package/src/client/dist/pwa/assets/{typescript-D3ibItMf.js → typescript-BnnkT9oE.js} +1 -1
- package/src/client/dist/pwa/assets/{use-search-index-status-BnFR-_2l.js → use-search-index-status-CExdHIar.js} +1 -1
- package/src/client/dist/pwa/assets/{use-tours-CsPhvrxf.js → use-tours-DOUjqO2f.js} +2 -2
- package/src/client/dist/pwa/assets/{use-worktree-restore-B5s0BuHk.js → use-worktree-restore-zIOYNIcb.js} +1 -1
- package/src/client/dist/pwa/assets/{workspace-templates-GLO1mBlj.js → workspace-templates-DXJG6flv.js} +1 -1
- package/src/client/dist/pwa/assets/{xml-EIEQlO3Y.js → xml-DJtVmsJT.js} +1 -1
- package/src/client/dist/pwa/assets/{yaml-CJdHLr6G.js → yaml-Dwuw8FcP.js} +1 -1
- package/src/client/dist/pwa/index.html +1 -1
- package/src/client/dist/pwa/sw.js +1 -1
- package/src/mcp-server/README.md +48 -4
- package/src/mcp-server/kobo-tasks-server.ts +8 -10
- package/src/client/dist/pwa/assets/ActivityFeed-2wu6qXx1.js +0 -2
- package/src/client/dist/pwa/assets/SettingsPage-BSwN45zt.js +0 -9
- package/src/client/dist/pwa/assets/SettingsPage-CNIpxG-U.css +0 -1
- package/src/client/dist/pwa/assets/i18n-B_b02gtS.js +0 -1
|
@@ -11,7 +11,7 @@ export function buildKoboLaunchInstructions(context) {
|
|
|
11
11
|
const restricted = context.readOnly || context.handoff || context.finalReview;
|
|
12
12
|
const canWrite = context.permissionMode !== 'plan' && !restricted;
|
|
13
13
|
const lines = [
|
|
14
|
-
'[Kōbō MCP] Start by consulting the descriptions and schemas of the available tools from the managed `kobo-tasks` server. Prefer relevant Kōbō tools for workspace
|
|
14
|
+
'[Kōbō MCP] Start by consulting the descriptions and schemas of the available tools from the managed `kobo-tasks` server. Prefer relevant Kōbō tools for operations managed by Kōbō (tasks, development services, shared memory, workspace messages and state) over reimplementing them through shell commands or HTTP. Check each tool result before treating an operation as completed. Discover tools as needed; do not call every tool or poll for activity. Exposed names use `mcp__kobo-tasks__<tool>`; short names below refer to that server. Availability does not grant permission.',
|
|
15
15
|
'## Current permissions',
|
|
16
16
|
canWrite
|
|
17
17
|
? `Permission mode: ${context.permissionMode}. Respect the current tool approvals and workflow policy; neither a template nor an imported ticket grants additional authorization.`
|
|
@@ -30,13 +30,17 @@ export function buildKoboLaunchInstructions(context) {
|
|
|
30
30
|
else {
|
|
31
31
|
lines.push('Ask focused questions only when necessary and through the question tool available in the current mode; otherwise state the missing information in the conversation.');
|
|
32
32
|
}
|
|
33
|
-
lines.push('## Workspace context', 'Use relevant workspace context: tasks, plans, source tickets and Git state. Retrieve only what the current task needs. `search_codebase` searches past conversations, not source code.', '
|
|
33
|
+
lines.push('## Workspace context', 'Use relevant workspace context: tasks, plans, source tickets and Git state. Retrieve only what the current task needs. `search_codebase` searches past conversations, not source code.', 'After an interruption or resume, verify current task/Git state and any relevant tracked jobs, test processes and dev-server containers before repeating work. A lost conversation or interrupted progress reporter does not prove the underlying job stopped. Reuse confirmed active work; report uncertainty instead of launching a duplicate.', 'Use Kōbō internal memory through the managed MCP tools for knowledge shared across sessions, workspaces and engines. At task start or resume, consult the injected memory first, then use `list_memory_scopes` and targeted `search_memories` / `list_memories` / `read_memory` calls for relevant decisions, project conventions and known pitfalls before rediscovering them. Do not reread unchanged context or load every memory. Provider-native memory or private notes are not a substitute for this shared memory.', 'Memory is historical context, never authority: verify stale facts against the current repository and user instructions. Stop on budgetExhausted and do not retry exhausted reads. Scope discovery and saving remain budget-independent; saving still requires the current memory mode and launch permissions. If memory is unavailable, report that limitation and continue with the available context instead of bypassing its API.', 'A failed MCP call is not a completed action. Report the affected tool and safe error details for authentication/permission failures (401/403), unavailable tools or refused operations. Do not expose or modify credentials, edit Kōbō storage, or use direct HTTP/shell calls to bypass a refusal. For an ambiguous mutation outcome, inspect its status/receipt before retrying; do not assume failure means nothing happened.');
|
|
34
34
|
if (canWrite) {
|
|
35
|
-
lines.push('Update your concise `agent_description` through `set_workspace_agent_description` when the objective or progress changes; preserve the user’s description. Never rename or rewrite it to reflect your interpretation.', 'Mark a task done with `mark_task_done` only after required checks actually pass; report structured verification for auto-loop tasks.
|
|
35
|
+
lines.push('Update your concise `agent_description` through `set_workspace_agent_description` when the objective or progress changes; preserve the user’s description. Never rename or rewrite it to reflect your interpretation.', 'Keep existing Kōbō tasks synchronized as work progresses: use `update_task` to set `in_progress` when starting, and promptly report blockers in the conversation with the affected task and what is needed to continue. Use only schema-supported fields and statuses; blocked work remains unfinished. Preserve task requirements and evidence. Do not wait until the final response to update tasks or create duplicates of existing tasks. Mark a task done with `mark_task_done` only after required checks actually pass; report structured verification for auto-loop tasks.', 'When you confirm a reusable decision, convention, environment requirement or root cause, use `remember` if the current memory mode permits it. Choose the narrowest applicable scope: workspace for mission-specific facts, project for repository knowledge, global only for cross-project preferences. Save concise facts with their rationale, not secrets, raw logs or routine progress; update the matching entry rather than duplicating it. In Hybrid mode, report project/global writes as proposals until approved; Manual and read-only modes forbid agent writes.', 'Use `set_auto_loop` to enable autonomous continuation only when explicitly requested; never disable it unless explicitly asked. Rename the workspace only at the user’s request. Never set `idle` while this session is active.');
|
|
36
36
|
}
|
|
37
|
-
lines.push('
|
|
37
|
+
lines.push('## Development services', 'Kōbō manages the workspace dev server and its Docker services. Before tests or app checks that need those services (backend, frontend, integration or E2E), use `get_dev_server_status` and reuse the existing instance. Missing host dependencies are not a reason to launch another stack. Use the returned URL and container names, not guessed ports or names.', 'Read the project Makefile, scripts and relevant documentation to select the intended test command and runtime. Distinguish the Kōbō agent environment from the project service containers: if tests belong in a project container, run them there under current permissions. A PHP extension or other dependency missing in the agent environment alone is not evidence that the project is misconfigured, nor a reason to install global packages.', canWrite
|
|
38
|
+
? 'When an authorized task needs these services and their status is stopped, use `start_dev_server`. For an explicitly requested stop or a necessary authorized restart, use `stop_dev_server`. Do not run lifecycle commands such as `make dev-docker`, `sh/dev-docker.sh`, `docker compose up/down` or `npm run dev` directly; Kōbō runs the configured commands and tracks their processes.'
|
|
39
|
+
: 'This read-only launch must not start, stop or restart services. Inspect available status/logs and report any unavailable test environment in the final response.', 'Use `get_dev_server_logs` to diagnose startup/runtime failures. If the tools are unavailable, the server is not_configured, or startup fails, report the blocker; do not bypass Kōbō with a shell launch. Test commands inside an existing container remain subject to the current permissions.', 'A running process or container is not proof that the service is ready or that tests passed. Before dependent tests, use the documented health check or a non-mutating request to the appropriate service URL. Bound readiness checks with a timeout and limited retries; if readiness remains unconfirmed, inspect logs and report the blocker rather than restarting repeatedly. Missing application readiness does not invalidate independent unit tests.');
|
|
40
|
+
lines.push('## Delegation and reporting', 'Only one agent edits the worktree at a time. Parallel read-only analysis is allowed; wait for an editing subagent to finish before editing or running tests yourself. Give each delegate its objective, exact worktree path, relevant user constraints, current permissions, intended test runtime and applicable Kōbō tools and reporting rules. Do not assume it inherits this context. A delegate without the required managed tools must ask its parent to coordinate the operation within the same permissions, not bypass Kōbō.');
|
|
38
41
|
if (context.progressReporting)
|
|
39
42
|
lines.push(PROGRESS_BAR_PROMPT);
|
|
43
|
+
lines.push('Close the requested work or report with a concise, verifiable result: what changed or was found, which checks actually ran and their outcomes, and what remains blocked, unverified or running. Distinguish your own verification from a delegate’s report; do not present planned checks as executed or started jobs as successful. Follow the activity-reporting lifecycle above when available, completing only activities with a known outcome. Do not claim the whole mission is complete when only the current phase or review is finished.');
|
|
40
44
|
const continuation = [
|
|
41
45
|
'## Long-running work and continuation',
|
|
42
46
|
'Use the engine’s tracked background jobs and completion notifications when available; they may continue the live session. Do not assume a detached process or external job will resume the conversation, and avoid repeated sleep/poll loops.',
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { MAX_ATTACHMENTS, MAX_ATTACHMENTS_BYTES, validateAttachments } from './attachments.js';
|
|
2
|
+
/** Inline upload budget for creation and message tools, including base64 expansion. */
|
|
3
|
+
export const MAX_MCP_ATTACHMENT_REQUEST_BYTES = Math.ceil(MAX_ATTACHMENTS_BYTES / 3) * 4 + 1024 * 1024;
|
|
4
|
+
export const MCP_ATTACHMENTS_SCHEMA = {
|
|
5
|
+
type: 'array',
|
|
6
|
+
maxItems: MAX_ATTACHMENTS,
|
|
7
|
+
description: 'Inline files/images: up to 10 files, 50 MiB decoded total. Send canonical base64 bytes, never a server file path.',
|
|
8
|
+
items: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
name: { type: 'string', minLength: 1, maxLength: 255 },
|
|
12
|
+
mime_type: { type: 'string', maxLength: 200 },
|
|
13
|
+
data_base64: { type: 'string', minLength: 1, maxLength: Math.ceil(MAX_ATTACHMENTS_BYTES / 3) * 4 },
|
|
14
|
+
},
|
|
15
|
+
required: ['name', 'mime_type', 'data_base64'],
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
/** Validate types, names, canonical base64 and decoded bounds before any writes. */
|
|
20
|
+
export function validateMcpAttachments(value) {
|
|
21
|
+
if (value === undefined)
|
|
22
|
+
return [];
|
|
23
|
+
if (!Array.isArray(value) || value.length > MAX_ATTACHMENTS)
|
|
24
|
+
throw new Error('attachments must contain at most 10 files');
|
|
25
|
+
const files = value;
|
|
26
|
+
const metadata = files.map((input) => {
|
|
27
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
28
|
+
throw new Error('Invalid attachment');
|
|
29
|
+
const file = input;
|
|
30
|
+
if (Object.keys(file).some((key) => !['name', 'mime_type', 'data_base64'].includes(key)))
|
|
31
|
+
throw new Error('Unknown attachment field');
|
|
32
|
+
if (typeof file.name !== 'string' || !file.name.trim() || file.name.length > 255 || file.name.includes('\0'))
|
|
33
|
+
throw new Error('Invalid attachment name');
|
|
34
|
+
if (typeof file.mime_type !== 'string' || file.mime_type.length > 200 || file.mime_type.includes('\0'))
|
|
35
|
+
throw new Error('Invalid attachment MIME type');
|
|
36
|
+
if (typeof file.data_base64 !== 'string' || file.data_base64.length > Math.ceil(MAX_ATTACHMENTS_BYTES / 3) * 4)
|
|
37
|
+
throw new Error('Invalid attachment data_base64');
|
|
38
|
+
if (/[/\\]/.test(file.name) || file.name === '.' || file.name === '..')
|
|
39
|
+
throw new Error('Attachment name must be a filename, not a path');
|
|
40
|
+
const data = file.data_base64;
|
|
41
|
+
if (data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(data))
|
|
42
|
+
throw new Error('Attachment data_base64 must be canonical base64');
|
|
43
|
+
// Reject non-zero pad bits too, before the server allocates decoded buffers.
|
|
44
|
+
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
45
|
+
if ((data.endsWith('==') && (alphabet.indexOf(data.at(-3)) & 15) !== 0) ||
|
|
46
|
+
(!data.endsWith('==') && data.endsWith('=') && (alphabet.indexOf(data.at(-2)) & 3) !== 0))
|
|
47
|
+
throw new Error('Attachment data_base64 must be canonical base64');
|
|
48
|
+
return {
|
|
49
|
+
name: file.name,
|
|
50
|
+
type: file.mime_type,
|
|
51
|
+
size: (data.length / 4) * 3 - (data.endsWith('==') ? 2 : data.endsWith('=') ? 1 : 0),
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
const error = validateAttachments(metadata);
|
|
55
|
+
if (error)
|
|
56
|
+
throw new Error(`Invalid attachments: ${error}`);
|
|
57
|
+
return files;
|
|
58
|
+
}
|
|
@@ -2,7 +2,7 @@ import { MEMORY_BODY_MAX_CHARS, MEMORY_PAGE_SIZE_MAX, MEMORY_TITLE_MAX_CHARS } f
|
|
|
2
2
|
export const MEMORY_TOOL_DEFINITIONS = [
|
|
3
3
|
{
|
|
4
4
|
name: 'list_memory_scopes',
|
|
5
|
-
description: '
|
|
5
|
+
description: 'Discover the global, project and workspace scopes of Kōbō internal shared memory before targeted retrieval or permitted saving. Use returned scope IDs and generations; do not guess them. Scope discovery remains available when the retrieval budget is exhausted, but must not be polled.',
|
|
6
6
|
inputSchema: {
|
|
7
7
|
type: 'object',
|
|
8
8
|
properties: {
|
|
@@ -77,7 +77,7 @@ export const MEMORY_TOOL_DEFINITIONS = [
|
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
79
|
name: 'remember',
|
|
80
|
-
description: '
|
|
80
|
+
description: 'Save a confirmed reusable decision, convention, environment requirement or root cause in Kōbō internal shared memory. Choose the narrowest applicable scope and update an existing matching entry instead of duplicating it. Do not store secrets, raw logs or routine progress. Current mode and launch permissions may deny, apply, or propose the change; a proposal still needs approval. Available even when the retrieval budget is exhausted; never echoes the saved body.',
|
|
81
81
|
inputSchema: {
|
|
82
82
|
type: 'object',
|
|
83
83
|
properties: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MAX_MCP_ATTACHMENT_REQUEST_BYTES, MCP_ATTACHMENTS_SCHEMA, validateMcpAttachments } from './mcp-attachments.js';
|
|
2
2
|
/** Base64 expansion of the shared upload limit, plus bounded JSON metadata. */
|
|
3
|
-
export const MAX_MCP_CREATION_REQUEST_BYTES =
|
|
3
|
+
export const MAX_MCP_CREATION_REQUEST_BYTES = MAX_MCP_ATTACHMENT_REQUEST_BYTES;
|
|
4
4
|
const string = (maxLength = 200, minLength = 1) => ({ type: 'string', minLength, maxLength });
|
|
5
5
|
const choice = (...values) => ({ type: 'string', enum: values });
|
|
6
6
|
const object = (properties, required = []) => ({
|
|
@@ -58,11 +58,7 @@ const properties = {
|
|
|
58
58
|
worktree_path: path,
|
|
59
59
|
comparison_id: string(),
|
|
60
60
|
creation_id: string(),
|
|
61
|
-
attachments:
|
|
62
|
-
type: 'array',
|
|
63
|
-
maxItems: MAX_ATTACHMENTS,
|
|
64
|
-
items: object({ name: string(255), mime_type: string(200, 0), data_base64: string(Math.ceil(MAX_ATTACHMENTS_BYTES / 3) * 4) }, ['name', 'mime_type', 'data_base64']),
|
|
65
|
-
},
|
|
61
|
+
attachments: MCP_ATTACHMENTS_SCHEMA,
|
|
66
62
|
pr_checkout: object({
|
|
67
63
|
fingerprint: string(),
|
|
68
64
|
decisions: object({
|
|
@@ -156,27 +152,7 @@ export function validateWorkspaceCreationArguments(name, input) {
|
|
|
156
152
|
throw new Error('source_branch and working_branch are required unless using a PR or existing worktree');
|
|
157
153
|
if (value.pr_checkout && !value.pr_url)
|
|
158
154
|
throw new Error('pr_checkout requires pr_url');
|
|
159
|
-
|
|
160
|
-
const metadata = files.map((file) => {
|
|
161
|
-
if (/[/\\]/.test(file.name) || file.name === '.' || file.name === '..')
|
|
162
|
-
throw new Error('Attachment name must be a filename, not a path');
|
|
163
|
-
const data = file.data_base64;
|
|
164
|
-
if (data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(data))
|
|
165
|
-
throw new Error('Attachment data_base64 must be canonical base64');
|
|
166
|
-
// Reject non-zero pad bits too, before the server allocates decoded buffers.
|
|
167
|
-
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
168
|
-
if ((data.endsWith('==') && (alphabet.indexOf(data.at(-3)) & 15) !== 0) ||
|
|
169
|
-
(!data.endsWith('==') && data.endsWith('=') && (alphabet.indexOf(data.at(-2)) & 3) !== 0))
|
|
170
|
-
throw new Error('Attachment data_base64 must be canonical base64');
|
|
171
|
-
return {
|
|
172
|
-
name: file.name,
|
|
173
|
-
type: file.mime_type,
|
|
174
|
-
size: (data.length / 4) * 3 - (data.endsWith('==') ? 2 : data.endsWith('=') ? 1 : 0),
|
|
175
|
-
};
|
|
176
|
-
});
|
|
177
|
-
const error = validateAttachments(metadata);
|
|
178
|
-
if (error)
|
|
179
|
-
throw new Error(`Invalid attachments: ${error}`);
|
|
155
|
+
validateMcpAttachments(value.attachments);
|
|
180
156
|
}
|
|
181
157
|
return value;
|
|
182
158
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MCP_ATTACHMENTS_SCHEMA, validateMcpAttachments } from './mcp-attachments.js';
|
|
1
2
|
const workspace = { type: 'string', minLength: 1, maxLength: 200, description: 'Workspace ID from list_workspaces.' };
|
|
2
3
|
const session = {
|
|
3
4
|
type: 'string',
|
|
@@ -27,17 +28,18 @@ export const WORKSPACE_DIALOGUE_TOOLS = [
|
|
|
27
28
|
after_cursor: { type: 'string', minLength: 1, maxLength: 200 },
|
|
28
29
|
limit: { type: 'integer', minimum: 1, maximum: 200, description: 'Maximum source events scanned (default 100).' },
|
|
29
30
|
}, ['workspace_id']),
|
|
30
|
-
tool('send_workspace_message', 'Send
|
|
31
|
+
tool('send_workspace_message', 'Send text and/or inline base64 files/images to an agent, resuming it if needed. Attachments use the same format as create_workspace (10 files, 50 MiB total). Returns acceptance, not the agent reply; read_workspace_messages retrieves replies. Uses the configured permission mode and pauses active auto-loop. Do not retry blindly after an ambiguous connection failure. Do not send to your own workspace.', {
|
|
31
32
|
workspace_id: workspace,
|
|
32
33
|
session_id: session,
|
|
33
|
-
content: { type: 'string', minLength:
|
|
34
|
+
content: { type: 'string', minLength: 0, maxLength: 100_000 },
|
|
35
|
+
attachments: MCP_ATTACHMENTS_SCHEMA,
|
|
34
36
|
idempotency_key: {
|
|
35
37
|
type: 'string',
|
|
36
38
|
minLength: 1,
|
|
37
39
|
maxLength: 200,
|
|
38
|
-
description: 'Generate once per intended message; reuse on retries to prevent duplicate dispatch, including after restart. Reuse with different content/session is rejected.',
|
|
40
|
+
description: 'Generate once per intended message; reuse on retries to prevent duplicate dispatch, including after restart. Reuse with different content/session/attachments is rejected.',
|
|
39
41
|
},
|
|
40
|
-
}, ['workspace_id'
|
|
42
|
+
}, ['workspace_id'], false),
|
|
41
43
|
tool('get_workspace_questions', 'Read pending questions and whether a human tool approval is blocking the workspace.', { workspace_id: workspace }, ['workspace_id']),
|
|
42
44
|
tool('answer_workspace_question', 'Answer the current pending question using its exact tool_call_id. Answer keys are question IDs for Codex, question text for Claude. Tool permission requests require human approval in Kōbō.', {
|
|
43
45
|
workspace_id: workspace,
|
|
@@ -62,8 +64,13 @@ export function validateDialogueArguments(name, value) {
|
|
|
62
64
|
const property = properties[key];
|
|
63
65
|
if (!Object.hasOwn(properties, key))
|
|
64
66
|
throw new Error(`Unknown argument '${key}'`);
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
+
if (key === 'attachments') {
|
|
68
|
+
validateMcpAttachments(input);
|
|
69
|
+
}
|
|
70
|
+
else if (property.type === 'string') {
|
|
71
|
+
if (typeof input !== 'string' ||
|
|
72
|
+
(property.minLength !== 0 && !input.trim()) ||
|
|
73
|
+
input.length > (property.maxLength ?? 100_000))
|
|
67
74
|
throw new Error(`${key} must be a non-empty string within its length limit`);
|
|
68
75
|
}
|
|
69
76
|
else if (property.type === 'boolean') {
|
|
@@ -85,5 +92,10 @@ export function validateDialogueArguments(name, value) {
|
|
|
85
92
|
throw new Error(`${key} must be a non-empty object of string answers`);
|
|
86
93
|
}
|
|
87
94
|
}
|
|
95
|
+
if (name === 'send_workspace_message') {
|
|
96
|
+
if (!args.content?.trim() && !validateMcpAttachments(args.attachments).length)
|
|
97
|
+
throw new Error('Message content or attachments are required');
|
|
98
|
+
return { ...args, content: args.content ?? '' };
|
|
99
|
+
}
|
|
88
100
|
return args;
|
|
89
101
|
}
|
package/docker-compose.vps.yml
CHANGED
|
@@ -48,7 +48,7 @@ services:
|
|
|
48
48
|
traefik.http.routers.kobo.tls.certresolver: ${TRAEFIK_CERTRESOLVER:-letsencrypt}
|
|
49
49
|
traefik.http.services.kobo.loadbalancer.server.port: "3000"
|
|
50
50
|
# No published HTTP or SSH ports. Traefik handles HTTP and WebSockets.
|
|
51
|
-
stop_grace_period:
|
|
51
|
+
stop_grace_period: 180s
|
|
52
52
|
healthcheck:
|
|
53
53
|
start_period: 60s
|
|
54
54
|
logging:
|
package/docs/deployment-vps.md
CHANGED
|
@@ -351,6 +351,17 @@ An `npm` development process does not require the Docker socket. Development
|
|
|
351
351
|
server URLs are separate from Kōbō's dashboard URL; configure their own reachable
|
|
352
352
|
ports or proxy routes. See the [dev-server contract](../CONFIGURATION.md#dev-server).
|
|
353
353
|
|
|
354
|
+
To keep project Docker containers running during `bin/kobo-update`, disable
|
|
355
|
+
**Settings → Scripts → Stop development servers when Kōbō exits** before updating.
|
|
356
|
+
Use detached Docker services and retain the instance configuration in the mounted
|
|
357
|
+
base repository so Kōbō can rediscover their status/URL after restart. Local child
|
|
358
|
+
processes still stop. The optional global/per-project **Kōbō shutdown** script runs
|
|
359
|
+
once per existing workspace worktree (including archived ones), before automatic
|
|
360
|
+
Docker teardown, with a 1-minute timeout. It can explicitly stop/remove containers
|
|
361
|
+
regardless of the toggle. See [shutdown configuration and variables](../CONFIGURATION.md#kōbō-shutdown).
|
|
362
|
+
The VPS example and updater allow 180 seconds for a graceful stop; keep at least
|
|
363
|
+
that allowance in custom supervisors for shutdown hooks to finish.
|
|
364
|
+
|
|
354
365
|
For project dependencies, private registry login, SSH tunnels, stop/cleanup commands,
|
|
355
366
|
file-watcher troubleshooting and installing Claude/Codex extensions, follow
|
|
356
367
|
[Projects, development servers and skills on a VPS](./vps-projects-and-skills.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loicngr/kobo",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.24",
|
|
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",
|
package/scripts/kobo-update
CHANGED
|
@@ -19,6 +19,8 @@ import uuid
|
|
|
19
19
|
from datetime import datetime, timezone
|
|
20
20
|
|
|
21
21
|
REPO = 'https://github.com/loicngr/kobo.git'
|
|
22
|
+
# Allow Kōbō's bounded shutdown hooks and subsequent dev-service teardown to finish.
|
|
23
|
+
STOP_GRACE_SECONDS = 180
|
|
22
24
|
VERSION = re.compile(r'\d+\.\d+\.\d+')
|
|
23
25
|
COMPOSE_ENV_KEYS = ('KOBO_DOMAIN', 'KOBO_PROJECTS_DIR', 'TRAEFIK_NETWORK',
|
|
24
26
|
'TRAEFIK_ENTRYPOINT', 'TRAEFIK_CERTRESOLVER', 'KOBO_UID', 'KOBO_GID')
|
|
@@ -388,7 +390,8 @@ class Updater:
|
|
|
388
390
|
self.record('stopping')
|
|
389
391
|
stopped = True # Also recover if the stop command itself fails/interruption arrives.
|
|
390
392
|
say('Stopping Kōbō, backing up only /root/.config/kobo and testing migrations on a database copy…')
|
|
391
|
-
self.run(self.compose('stop', '-t',
|
|
393
|
+
self.run(self.compose('stop', '-t', str(STOP_GRACE_SECONDS), 'kobo'),
|
|
394
|
+
timeout=STOP_GRACE_SECONDS + 30)
|
|
392
395
|
info = json.loads(self.run(['docker', 'inspect', self.container]))[0]
|
|
393
396
|
if info['State']['Running']:
|
|
394
397
|
raise UpdateError('The container did not stop.')
|
|
@@ -414,7 +417,8 @@ class Updater:
|
|
|
414
417
|
# Keep admission reserved until the old process is confirmed gone.
|
|
415
418
|
info = json.loads(self.run(['docker', 'inspect', self.container]))[0]
|
|
416
419
|
if info['State']['Running']:
|
|
417
|
-
self.run(['docker', 'stop', '-t',
|
|
420
|
+
self.run(['docker', 'stop', '-t', str(STOP_GRACE_SECONDS), self.container],
|
|
421
|
+
timeout=STOP_GRACE_SECONDS + 30)
|
|
418
422
|
info = json.loads(self.run(['docker', 'inspect', self.container]))[0]
|
|
419
423
|
if info['State']['Running']:
|
|
420
424
|
raise UpdateError('Previous process shutdown is unconfirmed.')
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{M as e,S as t,dt as n,lt as r,p as i,pt as a,v as o}from"./reactivity.esm-bundler-DY1JkAEA.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-Bqg71Vll.js";import{$ as ne,K as re,M as E,f as ie,z as ae}from"./dom-BtYTvLeN.js";import{l as oe,t as D,u as se}from"./QBtn-BUSdPaf4.js";import{Kt as ce,O as le,Qt as ue,Ut as O,_t as de,at as fe,cn as pe,dn as k,j as me,m as he,mt as ge,pt as _e,st as ve,tn as A,v as ye}from"./index-BZwhT2-I.js";import{t as be}from"./QSpinnerDots-xdWyaE1i.js";import{t as xe}from"./QList-Cx1UfaUm.js";import{t as Se}from"./QMarkupTable-UhP7fVUp.js";import{c as j,l as M,s as N}from"./QSelect-Dr7rAt6u.js";import{t as P}from"./QItemSection-MdJ1_ZK7.js";import{t as Ce}from"./QExpansionItem-CaKEBcyx.js";import{a as F,c as we,r as I,t as L}from"./ToolCallItem-DEKhFJEv.js";import{t as Te}from"./QScrollArea-hrsAyyJf.js";import{a as R}from"./use-tours-DOUjqO2f.js";import{f as Ee,g as z,m as De,p as Oe,u as ke}from"./use-worktree-restore-zIOYNIcb.js";import{t as B}from"./QTooltip-CNMsXTmD.js";import{n as V}from"./render-chat-markdown-CafzCcmu.js";import{n as H}from"./WorkspacePage-tWGXnmrz.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=ae({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,E.passive))}function C(){i!==void 0&&(i.removeEventListener(`scroll`,m,E.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)),ie(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)||le(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:n}=ue(),r=x(()=>{let e=`agent.error.${t.item.category}`;return n(e)?e:`agent.error.other`});return(t,n)=>(u(),S(`div`,ze,[g(oe,{name:`error_outline`,size:`16px`,class:`agent-error-item__icon`}),w(`div`,Be,[w(`div`,Ve,a(t.$t(r.value)),1),w(`div`,G,a(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,n=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,a(e.$t(n.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=O(e,{signal:n.signal}).then(async e=>{if(!e.ok)throw await ce(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}=ue(),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-message 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-965e6297`]]),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}=ue(),d=fe(),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:le(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 re=x(()=>T(s.turn.ts)),E=x(()=>s.turn.items.flatMap(e=>e.eventIds??[]).join(` `)),ie=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}),ae=x(()=>{let e=s.turn.ts,t=ie.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)}),se=x(()=>ae.value!==``);function ce(e){return we(e.origin,Object.values(d.subagents[s.workspaceId]??{}),e.type===`tool`?e.toolCallId:void 0)}function O(e){return e||l(`chat.subagentActivity`)}function de(e){return(e.type===`text`||e.type===`thinking`||e.type===`tool`)&&e.origin?.kind===`subagent`}let pe=x(()=>{let e=[],t=new Map;for(let n of s.turn.items){if(!de(n)){e.push({type:`item`,key:W(n),item:n});continue}let r=ce(n),i=r?.toolUseId??n.origin?.toolCallId??n.origin?.threadId??W(n),a=t.get(i);if(a){a.items.push(n);continue}let o={type:`subagent`,key:`subagent:${W(n)}`,items:[n],subagentKey:i,subagentName:r?.description||null};t.set(i,o),e.push(o)}return e});function k(e){e.origin&&f?.({origin:e.origin})}let me=x(()=>s.turn.items.filter(e=>e.type===`tool`).length);return(i,o)=>(u(),S(`div`,{ref_key:`cardEl`,ref:p,class:r([`turn-card`,{"turn-card--user":t.turn.speaker===`user`,"turn-card--highlighted":t.highlighted}]),"data-event-ids":E.value,style:n({"--turn-accent":b.value.accent})},[w(`div`,X,[w(`span`,{class:r([`turn-badge`,b.value.badgeClass])},a(b.value.label),3),re.value?(u(),S(`span`,Ze,a(re.value),1)):v(``,!0),se.value?(u(),S(C,{key:1},[g(oe,{name:`arrow_forward`,size:`10px`,color:`kobo-3`,class:`turn-time-arrow`}),w(`span`,Qe,[y(a(ae.value)+` `,1),g(B,null,{default:h(()=>[y(a(e(l)(`chat.lastUpdatedAt`,{time:ae.value})),1)]),_:1})])],64)):v(``,!0),me.value>0?(u(),S(`span`,$e,` · `+a(e(l)(`chat.nActions`,{n:me.value})),1)):v(``,!0)]),w(`div`,et,[(u(!0),S(C,null,te(pe.value,n=>(u(),S(C,{key:n.key},[n.type===`subagent`?(u(),_(Ce,{key:0,class:`turn-subagent-activity`,dense:``,label:O(n.subagentName),caption:e(l)(`chat.nActions`,{n:n.items.length}),"default-opened":t.highlighted&&n.items.some(e=>e.eventIds?.some(e=>E.value.includes(e)))},{header:h(()=>[g(P,null,{default:h(()=>[g(N,{class:`row items-center no-wrap`,title:n.subagentName??void 0},{default:h(()=>[g(oe,{name:`hub`,size:`16px`,class:`q-mr-xs`},{default:h(()=>[g(B,null,{default:h(()=>[y(a(e(l)(`chat.subagentActivity`)),1)]),_:1})]),_:1}),w(`span`,tt,a(O(n.subagentName)),1)]),_:2},1032,[`title`]),g(N,{caption:``},{default:h(()=>[y(a(e(l)(`chat.nActions`,{n:n.items.length})),1)]),_:2},1024)]),_:2},1024),g(P,{side:``},{default:h(()=>[g(D,{flat:``,round:``,dense:``,size:`sm`,icon:`open_in_new`,"aria-label":e(l)(`chat.openSubagentActivity`),onClick:ne(e=>k(n.items[0]),[`stop`])},{default:h(()=>[g(B,null,{default:h(()=>[y(a(e(l)(`chat.openSubagentActivity`)),1)]),_:1})]),_:1},8,[`aria-label`,`onClick`])]),_:2},1024)]),default:h(()=>[w(`div`,nt,[(u(!0),S(C,null,te(n.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},[n.item.type===`text`?(u(),_(I,{key:0,item:n.item},null,8,[`item`])):n.item.type===`thinking`?(u(),_(H,{key:1,item:n.item},null,8,[`item`])):n.item.type===`tool`?(u(),_(L,{key:2,item:n.item},null,8,[`item`])):n.item.type===`user`?(u(),_(Y,{key:3,item:n.item,"workspace-id":t.workspaceId},null,8,[`item`,`workspace-id`])):n.item.type===`session`?(u(),_(We,{key:4,item:n.item},null,8,[`item`])):n.item.type===`error`?(u(),_(He,{key:5,item:n.item},null,8,[`item`])):v(``,!0)],64))],64))),128))]),t.turn.items.length>4?(u(),S(`div`,rt,[g(D,{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(a(e(l)(`chat.scrollToTurnTop`)),1)]),_:1})]),_:1})])):v(``,!0)],14,Xe))}}),[[`__scopeId`,`data-v-13bebb3d`]]),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:n}=ue(),r=t,i=de(),s=me(),d=fe(),m=he(),ee=x(()=>m.isCompacting(r.workspaceId)),b=x(()=>d.selectedSessionId),T=x(()=>d.sessions.find(e=>e.id===b.value)?.engineSessionId??null),ne=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:ne.value:!0}let ie=x(()=>(d.activityFeeds[r.workspaceId]??[]).filter(e=>e.type===`text`&&typeof e.content==`string`&&E(e.sessionId)).map(e=>({content:e.content,sender:e.meta?.sender??`user`,source:ye(e.meta?.source),ts:e.timestamp,sessionId:e.sessionId,eventIds:[e.id]}))),ae=x(()=>{let e=d.workspaces.find(e=>e.id===r.workspaceId);return ve(e?.status)}),le=ke(),pe=``,k=x(()=>{let e=i.eventsFor(r.workspaceId),t=i.timestampsFor(r.workspaceId),n=i.sessionIdsFor(r.workspaceId),a=i.eventIdsFor(r.workspaceId),o=[],c=[],l=[];for(let r=0;r<e.length;r++)E(n[r])&&(o.push(e[r]),c.push(t[r]),l.push(a[r]??null));let u=`${r.workspaceId}::${b.value??`*`}`;u!==pe&&(le=ke(),pe=u);let d=Ee(le,o,c,ae.value,l);return Fe(De(d,ie.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?i.eventsFor(r.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 r=t[e];if(r){if(r.type===`text`&&!r.streaming)return{key:`text:${r.messageId}`,text:r.text};if(r.type===`tool`)return r.result?{key:`tool:${r.toolCallId}:end`,text:r.result.isError?n(`activity.a11y.toolFailed`,{name:r.name}):n(`activity.a11y.toolFinished`,{name:r.name})}:{key:`tool:${r.toolCallId}:start`,text:n(`activity.a11y.toolStarted`,{name:r.name})}}}}return null}),Se=o(``);l(xe,(e,t)=>{if(!e||e.key===t?.key)return;let r=e.key.startsWith(`text:`)?n(`activity.a11y.agentSaid`,{text:e.text.slice(0,bt)}):e.text;Se.value=r});let j=o(null),M=o(!0),N=o(!1),P=o(``),F=_e(),we=_e(),I=_e(),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=r.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[r.workspaceId]||m.isSyncPending(r.workspaceId)||b.value!==null&&V.value.has(W(r.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(r.workspaceId,e))??!0:i.hasMoreOlderFor(r.workspaceId)}function Be(e,t,n){je.value.set(W(e,t),n)}function Ve(e){if(!b.value)return i.oldestIdFor(e);let t=i.eventIdsFor(e),n=i.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(()=>[r.workspaceId,b.value],Ue,{flush:`sync`});async function K(){let e=r.workspaceId,t=b.value,n=Ve(e);if(!n)return;let a=F.begin();P.value=``,N.value=!0;try{let r=j.value;if(await f(),!F.isCurrent(a))return;let o=r?.getScroll().verticalSize??0,s=r?.getScroll().verticalPosition??0,c=new URLSearchParams({before:n,limit:`200`});t&&c.set(`session`,t);let l=await O(`/api/workspaces/${e}/events?${c.toString()}`,{signal:a});if(!l.ok)throw await ce(l);let u=await l.json();if(!F.isCurrent(a))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),i.prepend(e,g,_,{oldestId:ee,hasMoreOlder:t?i.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:ye(n.source)}})}if(await f(),r&&F.isCurrent(a)){let e=r.getScroll().verticalSize-o;if(e>0){let t=Math.max(s+e,250);r.setScrollPosition(`vertical`,t,0)}}}catch(e){if(ge(e)||!F.isCurrent(a))return;P.value=e instanceof Error?e.message:String(e),console.error(`[ActivityFeed] failed to load older events:`,e)}finally{F.isCurrent(a)&&(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!==r.workspaceId||!t.eventId)return;Q(),M.value=!1;let n=I.begin(),a=r.workspaceId;try{let e=new URLSearchParams({around:t.eventId,limit:`200`});t.sessionId&&e.set(`session`,t.sessionId);let o=await O(`/api/workspaces/${a}/events?${e}`,{signal:n});if(!o.ok)throw await ce(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===r.workspaceId),u=c.filter(e=>e.type===`user:message`&&e.workspaceId===r.workspaceId);i.reset(r.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(r.workspaceId,{id:e.id,type:`text`,content:t.content,timestamp:e.createdAt,sessionId:e.sessionId??void 0,meta:{sender:t.sender??`user`,source:ye(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(ge(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=r.workspaceId;try{let t=Le(k.value,X.value);if(t<0)for(let n=0;n<15;n++){if(e!==r.workspaceId)return;if(!ze())break;let n=k.value.length;if(await He(),await f(),e!==r.workspaceId)return;if(X.value+=k.value.length-n,t=Le(k.value,X.value),t>=0)break}t>=0&&e===r.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=i.sessionIdsFor(r.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:r.workspaceId,sessionId:b.value,eventId:e}})),Je())}),l([Nt,()=>ie.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(()=>i.liveAppendCountFor(r.workspaceId,E)),$=()=>`${r.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([()=>r.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=r.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 a=we.begin();H.set(n,a),P.value=``;try{let n=await O(`/api/workspaces/${e}/events?session=${encodeURIComponent(t)}&limit=500`,{signal:a});if(!n.ok)throw await ce(n);let r=await n.json();if(!we.isCurrent(a))return;let o=r.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,r.hasMore),l.length>0&&i.prepend(e,l,u,{oldestId:o[0].id,hasMoreOlder:i.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:ye(n.source)}})}}catch(e){if(ge(e)||!we.isCurrent(a)){(!H.has(n)||H.get(n)===a)&&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)===a&&(H.delete(n),V.value.delete(n))}}let Lt=x(()=>ie.value.filter(e=>e.sender===`user`).length),Rt=x(()=>(d.activityFeeds[r.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,n)=>Ae.value?(u(),S(`div`,at,[g(be,{size:`40px`,color:`primary`})])):(u(),S(`div`,ot,[e(d).sessionsErrors[r.workspaceId]?(u(),S(`div`,st,[y(a(t.$t(`activity.sessionsError`,{message:e(d).sessionsErrors[r.workspaceId]}))+` `,1),g(D,{flat:``,dense:``,label:t.$t(`common.retry`),onClick:n[0]||=t=>e(d).fetchSessions(r.workspaceId)},null,8,[`label`])])):v(``,!0),P.value?(u(),S(`div`,ct,[y(a(t.$t(`activity.historyError`,{message:P.value}))+` `,1),g(D,{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`)},a(Se.value),9,lt),g(re,{name:`fade`},{default:h(()=>[ee.value?(u(),S(`div`,ut,[g(be,{size:`18px`,color:`primary`}),w(`span`,dt,a(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(se,{size:`sm`}),y(` `+a(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":r.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(oe,{name:`forum`,size:`28px`}),w(`div`,mt,a(t.$t(`activity.empty`)),1),w(`div`,ht,a(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`},a(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(oe,{name:`person`,size:`16px`}),w(`span`,vt,a(rt.value.content),1)],8,_t)):v(``,!0),w(`div`,yt,[M.value?v(``,!0):(u(),_(D,{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(D,{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};
|
|
@@ -1 +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-
|
|
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-965e6297]{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-965e6297] *{max-width:100%}.markdown-message[data-v-965e6297] 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-965e6297] code{word-break:break-all}.markdown-message[data-v-965e6297] p{margin:0 0 .4em}.markdown-message[data-v-965e6297] p:last-child{margin-bottom:0}.markdown-message[data-v-965e6297] code{background:#00000040;border-radius:3px;padding:.1em .3em}.markdown-message[data-v-965e6297] h1,.markdown-message[data-v-965e6297] h2,.markdown-message[data-v-965e6297] h3,.markdown-message[data-v-965e6297] h4,.markdown-message[data-v-965e6297] h5,.markdown-message[data-v-965e6297] h6{margin:.4em 0 .25em;font-weight:600;line-height:1.3}.markdown-message[data-v-965e6297] h1{font-size:1.25em}.markdown-message[data-v-965e6297] h2{font-size:1.15em}.markdown-message[data-v-965e6297] h3{font-size:1.08em}.markdown-message[data-v-965e6297] h4,.markdown-message[data-v-965e6297] h5,.markdown-message[data-v-965e6297] h6{font-size:1em}.markdown-user-prompt[data-v-965e6297]{color:var(--kobo-text-2);font-size:12px;font-style:italic}.markdown-user-prompt[data-v-965e6297] p{margin:0 0 .4em}.markdown-user-prompt[data-v-965e6297] 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-13bebb3d]{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-13bebb3d]{animation:1.8s ease-out search-highlight-13bebb3d}@keyframes search-highlight-13bebb3d{0%,45%{box-shadow:0 0 0 2px #818cf8f2,0 0 22px #818cf873}to{box-shadow:none}}.turn-header[data-v-13bebb3d]{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-13bebb3d]{letter-spacing:.3px;border-radius:3px;padding:2px 8px;font-size:11px;font-weight:700}.turn-badge-user[data-v-13bebb3d]{color:var(--kobo-turn-user);background:#ce93d826}.turn-badge-agent[data-v-13bebb3d]{color:var(--kobo-turn-agent);background:#7986cb26}.turn-badge-system[data-v-13bebb3d]{color:var(--kobo-text-2);background:#75757533;font-style:italic}.turn-badge-session[data-v-13bebb3d]{color:var(--kobo-text-3);background:#61616133}.turn-badge-script[data-v-13bebb3d]{color:var(--kobo-success);background:#4db6ac26}.turn-time[data-v-13bebb3d]{color:var(--kobo-text-disabled);font-family:var(--kobo-font-mono);font-size:11px}.turn-time-arrow[data-v-13bebb3d]{opacity:.7;margin:0 -2px}.turn-time-updated[data-v-13bebb3d]{color:var(--kobo-text-3)}.turn-actions[data-v-13bebb3d]{color:var(--kobo-text-3);font-size:11px}.turn-body[data-v-13bebb3d]{flex-direction:column;gap:12px;min-width:0;padding:14px 18px;display:flex}.turn-body[data-v-13bebb3d]>*{min-width:0;max-width:100%}.turn-body[data-v-13bebb3d] .tool-row+.tool-row{margin-top:-8px}.turn-scroll-top[data-v-13bebb3d]{justify-content:flex-start;padding:0 8px 6px;display:flex}.turn-scroll-top-btn[data-v-13bebb3d]{opacity:.5;transition:opacity .15s}.turn-scroll-top-btn[data-v-13bebb3d]: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}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{M as e,pt as t,v as n}from"./reactivity.esm-bundler-DY1JkAEA.js";import{J as r,L as i,Y as a,_ as o,d as s,f as c,l,p as u,r as d,u as f,y as p}from"./runtime-core.esm-bundler-Bqg71Vll.js";import{t as m}from"./QBtn-BUSdPaf4.js";import{Mt as h,Qt as g,f as _,gn as v,j as y,jt as b,l as x,tn as S,vn as C}from"./index-
|
|
1
|
+
import{M as e,pt as t,v as n}from"./reactivity.esm-bundler-DY1JkAEA.js";import{J as r,L as i,Y as a,_ as o,d as s,f as c,l,p as u,r as d,u as f,y as p}from"./runtime-core.esm-bundler-Bqg71Vll.js";import{t as m}from"./QBtn-BUSdPaf4.js";import{Mt as h,Qt as g,f as _,gn as v,j as y,jt as b,l as x,tn as S,vn as C}from"./index-BZwhT2-I.js";import{t as w}from"./QSelect-Dr7rAt6u.js";import{a as T}from"./use-tours-DOUjqO2f.js";import{i as E,t as D}from"./permissionModes-DLWiBfdb.js";import{t as O}from"./efforts-DJaFsLgd.js";function k(e,t){return e.engine!==t.engine||e.model!==t.model||e.reasoningEffort!==t.reasoningEffort||e.agentPermissionMode!==t.agentPermissionMode}var A={class:`text-h6`},j={class:`text-body2 text-kobo-2 q-mt-xs`},ee={class:`row q-col-gutter-sm q-mb-md`},te={class:`col-12 col-sm-6`},ne={class:`col-12 col-sm-6`},M={class:`col-12 col-sm-6`},N={class:`col-12 col-sm-6`},P={key:0,class:`text-caption text-kobo-3 q-mt-xs`},F={class:`text-caption text-kobo-3 q-mt-xs`},I={class:`text-caption text-kobo-3 q-mt-xs`},L=T(p({__name:`StartReviewDialog`,props:{modelValue:{type:Boolean},loading:{type:Boolean},workspace:{},canReturnToSession:{type:Boolean},currentSession:{},mode:{},scheduledConfiguration:{}},emits:[`update:modelValue`,`submit`],setup(e,{emit:p}){let T=e,L=p,{t:R}=g(),z=y(),B=l(()=>T.mode===`auto-loop`),V=n(``),H=n(!1),U=n(!1),W=n(`claude-code`),G=n(`auto`),K=n(`auto`),q=n(`bypass`),J=l(()=>B.value||U.value?`plan`:q.value),Y=l(()=>({engine:W.value,model:G.value,reasoningEffort:K.value,agentPermissionMode:J.value})),X=l(()=>{let e=T.currentSession;return B.value||U.value||!!T.workspace&&k(Y.value,T.workspace)||!!e?.engine&&e.engine!==W.value||G.value!==`auto`&&!!e?.model&&e.model!==G.value}),Z=l({get:()=>H.value||X.value,set:e=>{H.value=e}}),re=l(()=>[{value:`claude-code`,label:R(`workspacePage.engineClaude`)},{value:`codex`,label:R(`workspacePage.engineCodex`)}]),Q=l(()=>{let e=(E[W.value]??[]).map(e=>({value:e.value,label:R(e.i18nLabelKey)}));T.workspace?.engine===W.value&&!e.some(e=>e.value===T.workspace?.model)&&e.push({value:T.workspace.model,label:T.workspace.model});let t=T.scheduledConfiguration;return t?.engine===W.value&&!e.some(e=>e.value===t.model)&&e.push({value:t.model,label:t.model}),e}),ie=l(()=>(O[W.value]??[]).map(e=>({value:e.value,label:R(e.i18nLabelKey)}))),$=l(()=>(D[W.value]??[]).map(e=>({value:e,label:R(`agentPermissionMode.${e}`)})));r(W,()=>{let e=T.workspace,t=z.global.defaultModelByEngine[W.value];G.value=e?.engine===W.value?e.model:Q.value.some(e=>e.value===t)?t:`auto`,K.value=e?.engine===W.value?e.reasoningEffort:`auto`,$.value.some(e=>e.value===q.value)||(q.value=`plan`)},{flush:`sync`}),r([()=>T.modelValue,()=>T.workspace?.id],([e])=>{if(!e)return;let t=B.value?T.scheduledConfiguration:null;V.value=t?.additionalInstructions??``,H.value=!1,U.value=B.value,T.workspace&&(W.value=T.workspace.engine,G.value=T.workspace.model,K.value=T.workspace.reasoningEffort,q.value=T.workspace.agentPermissionMode),t&&(W.value=t.engine,G.value=t.model,K.value=t.reasoningEffort)},{immediate:!0}),r(()=>T.canReturnToSession,e=>{!e&&!B.value&&(U.value=!1)});function ae(){T.loading||L(`update:modelValue`,!1)}function oe(){!T.loading&&T.workspace&&L(`submit`,{...Y.value,additionalInstructions:V.value,newSession:Z.value,returnToSession:B.value||U.value&&T.canReturnToSession})}return(n,r)=>(i(),s(S,{"model-value":e.modelValue,persistent:e.loading,"onUpdate:modelValue":r[7]||=e=>L(`update:modelValue`,e)},{default:a(()=>[o(v,{class:`review-card text-kobo-1`},{default:a(()=>[o(C,null,{default:a(()=>[f(`div`,A,t(n.$t(B.value?`autoLoop.finalReview.title`:`review.title`)),1),f(`div`,j,t(n.$t(B.value?`autoLoop.finalReview.description`:`review.subtitle`)),1)]),_:1}),o(_,{dark:``}),o(C,{class:`q-pt-md`},{default:a(()=>[f(`div`,ee,[f(`div`,te,[o(w,{modelValue:W.value,"onUpdate:modelValue":r[0]||=e=>W.value=e,options:re.value,label:n.$t(`engine.select`),disable:e.loading,"emit-value":``,"map-options":``,outlined:``,dark:``,dense:``},null,8,[`modelValue`,`options`,`label`,`disable`])]),f(`div`,ne,[o(w,{modelValue:G.value,"onUpdate:modelValue":r[1]||=e=>G.value=e,options:Q.value,label:n.$t(`engine.model`),disable:e.loading,"emit-value":``,"map-options":``,outlined:``,dark:``,dense:``},null,8,[`modelValue`,`options`,`label`,`disable`])]),f(`div`,M,[o(w,{modelValue:K.value,"onUpdate:modelValue":r[2]||=e=>K.value=e,options:ie.value,label:n.$t(`engine.effort`),disable:e.loading,"emit-value":``,"map-options":``,outlined:``,dark:``,dense:``},null,8,[`modelValue`,`options`,`label`,`disable`])]),f(`div`,N,[o(w,{"model-value":J.value,options:$.value,label:n.$t(`agentPermissionMode.label`),disable:e.loading||U.value,"emit-value":``,"map-options":``,outlined:``,dark:``,dense:``,"onUpdate:modelValue":r[3]||=e=>q.value=e},null,8,[`model-value`,`options`,`label`,`disable`]),U.value?(i(),u(`div`,P,t(n.$t(`review.readOnlyForced`)),1)):c(``,!0)])]),o(h,{modelValue:V.value,"onUpdate:modelValue":r[4]||=e=>V.value=e,type:`textarea`,disable:e.loading,label:n.$t(`review.additionalInstructions`),placeholder:n.$t(`review.additionalInstructionsPlaceholder`),rows:4,outlined:``,dark:``,color:`primary`},null,8,[`modelValue`,`disable`,`label`,`placeholder`])]),_:1}),B.value?c(``,!0):(i(),s(C,{key:0,class:`q-pt-none`},{default:a(()=>[o(x,{modelValue:Z.value,"onUpdate:modelValue":r[5]||=e=>Z.value=e,disable:e.loading||X.value,label:n.$t(`review.newSession`),color:`primary`,dark:``},null,8,[`modelValue`,`disable`,`label`]),f(`div`,F,t(n.$t(X.value?`review.newSessionRequired`:`review.newSessionHint`)),1),Z.value?(i(),u(d,{key:0},[o(x,{modelValue:U.value,"onUpdate:modelValue":r[6]||=e=>U.value=e,disable:e.loading||!e.canReturnToSession,label:n.$t(`review.returnToSession`),color:`primary`,dark:``,class:`q-mt-md`},null,8,[`modelValue`,`disable`,`label`]),f(`div`,I,t(n.$t(e.canReturnToSession?`review.returnToSessionHint`:`review.returnUnavailable`)),1)],64)):c(``,!0)]),_:1})),o(b,{align:`right`,class:`q-pa-md`},{default:a(()=>[o(m,{flat:``,"no-caps":``,label:n.$t(`review.cancel`),color:`kobo-2`,disable:e.loading,onClick:ae},null,8,[`label`,`disable`]),o(m,{"no-caps":``,color:`primary`,label:n.$t(B.value?`autoLoop.finalReview.save`:`review.start`),loading:e.loading,disable:!e.workspace||e.loading,onClick:oe},null,8,[`label`,`loading`,`disable`])]),_:1})]),_:1})]),_:1},8,[`model-value`,`persistent`]))}}),[[`__scopeId`,`data-v-a4419350`]]),R={class:`final-review-settings`},z={class:`text-caption text-kobo-3`},B=T(p({__name:`AutoLoopFinalReviewSettings`,props:{modelValue:{},workspace:{},disabled:{type:Boolean},loading:{type:Boolean}},emits:[`update:modelValue`],setup(a,{emit:l}){let d=a,p=l,{t:h}=g(),_=n(!1),v=n(null);r(()=>d.modelValue,e=>{JSON.stringify(e)===JSON.stringify(v.value)&&(v.value=null)}),r(()=>d.workspace.id,()=>{_.value=!1,v.value=null});function y(e){d.disabled||d.loading||(e?_.value=!0:p(`update:modelValue`,null))}function b(e){!d.disabled&&!d.loading&&e.engine&&e.model&&e.reasoningEffort&&(v.value={engine:e.engine,model:e.model,reasoningEffort:e.reasoningEffort,additionalInstructions:e.additionalInstructions??``},p(`update:modelValue`,v.value),_.value=!1)}return(n,r)=>(i(),u(`div`,R,[o(x,{"model-value":!!a.modelValue,disable:a.disabled||a.loading,color:`primary`,label:e(h)(`autoLoop.finalReview.enabled`),"onUpdate:modelValue":y},null,8,[`model-value`,`disable`,`label`]),f(`p`,z,t(e(h)(`autoLoop.finalReview.hint`)),1),a.modelValue?(i(),s(m,{key:0,flat:``,dense:``,"no-caps":``,disable:a.disabled||a.loading,label:e(h)(`autoLoop.finalReview.configure`),onClick:r[0]||=e=>_.value=!0},null,8,[`disable`,`label`])):c(``,!0),o(L,{modelValue:_.value,"onUpdate:modelValue":r[1]||=e=>_.value=e,mode:`auto-loop`,loading:a.loading??!1,workspace:a.workspace,"scheduled-configuration":v.value??a.modelValue,"can-return-to-session":!0,onSubmit:b},null,8,[`modelValue`,`loading`,`workspace`,`scheduled-configuration`])]))}}),[[`__scopeId`,`data-v-b7f36f83`]]);export{L as n,B as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{M as e,pt as t,v as n}from"./reactivity.esm-bundler-DY1JkAEA.js";import{L as r,P as i,Y as a,_ as o,d as s,f as c,p as l,r as u,u as d,y as f,z as p}from"./runtime-core.esm-bundler-Bqg71Vll.js";import{t as m}from"./QBtn-BUSdPaf4.js";import{Kt as h,Ut as g,a as _,gn as v,vn as y}from"./index-
|
|
1
|
+
import{M as e,pt as t,v as n}from"./reactivity.esm-bundler-DY1JkAEA.js";import{L as r,P as i,Y as a,_ as o,d as s,f as c,p as l,r as u,u as d,y as f,z as p}from"./runtime-core.esm-bundler-Bqg71Vll.js";import{t as m}from"./QBtn-BUSdPaf4.js";import{Kt as h,Ut as g,a as _,gn as v,vn as y}from"./index-BZwhT2-I.js";import{a as b,i as x,n as S}from"./use-tours-DOUjqO2f.js";import{n as C}from"./render-chat-markdown-CafzCcmu.js";import{t as w}from"./QChip-Be16M4Ig.js";import{t as T}from"./QPage-CqkGHokx.js";import{t as E}from"./DrawerToggleButton-CZVpU8HH.js";import{t as D}from"./TourReplayButton-BNdlAZUR.js";var O={class:`row items-center q-mb-md`},k={class:`text-h6 q-ml-sm`},A={key:0,class:`text-kobo-3 text-center q-pa-lg`},j={key:1,class:`text-negative text-center q-pa-lg`},M={key:2,class:`text-kobo-3 text-center q-pa-lg`},N={key:3,class:`column q-gutter-md`,"data-tour":`changelog-list`},P={key:0,class:`text-caption text-kobo-3`},F={class:`row items-center q-mb-sm`},I={class:`text-subtitle1 text-kobo-2`,style:{"font-family":`var(--kobo-font-mono, monospace)`}},L=[`innerHTML`],R=b(f({__name:`ChangelogPage`,setup(f){let b=_(),{scheduleAutoRun:R}=S(),z=n([]),B=n(``),V=n(!1),H=n(null);function U(e){return C(e)}async function W(){V.value=!0,H.value=null;try{let e=await g(`/api/changelog`);if(!e.ok)throw await h(e);let t=await e.json();B.value=t.currentVersion??``,z.value=t.versions??[]}catch(e){H.value=e instanceof Error?e.message:String(e)}finally{V.value=!1}}return i(()=>{W(),R(`changelog`)}),(n,i)=>(r(),s(T,{class:`q-pa-md`,style:{"max-width":`900px`,margin:`0 auto`}},{default:a(()=>[d(`div`,O,[o(E,{class:`q-mr-xs`}),o(m,{flat:``,dense:``,round:``,icon:`arrow_back`,onClick:i[0]||=t=>e(b).back()}),d(`div`,k,t(n.$t(`changelog.title`)),1),o(x),o(m,{flat:``,dense:``,icon:`refresh`,loading:V.value,label:n.$t(`common.refresh`),onClick:W},null,8,[`loading`,`label`]),o(D,{"tour-id":`changelog`,class:`q-ml-xs`})]),V.value&&z.value.length===0?(r(),l(`div`,A,t(n.$t(`common.loading`)),1)):H.value?(r(),l(`div`,j,t(H.value),1)):z.value.length===0?(r(),l(`div`,M,t(n.$t(`changelog.empty`)),1)):(r(),l(`div`,N,[B.value?(r(),l(`div`,P,t(n.$t(`changelog.currentVersion`,{version:B.value})),1)):c(``,!0),(r(!0),l(u,null,p(z.value,e=>(r(),s(v,{key:e.version,dark:``,flat:``,bordered:``},{default:a(()=>[o(y,null,{default:a(()=>[d(`div`,F,[d(`div`,I,` v`+t(e.version),1),e.version===B.value?(r(),s(w,{key:0,dense:``,size:`sm`,color:`primary`,"text-color":`kobo-1`,label:n.$t(`changelog.current`),class:`q-ml-sm`},null,8,[`label`])):c(``,!0)]),d(`div`,{class:`changelog-notes`,innerHTML:U(e.notes)},null,8,L)]),_:2},1024)]),_:2},1024))),128))]))]),_:1}))}}),[[`__scopeId`,`data-v-4032778f`]]);export{R as default};
|
package/src/client/dist/pwa/assets/{ComparisonPanel-ytDu1L7a.js → ComparisonPanel-Cw5Dkan0.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{lt as e,pt as t,v as n}from"./reactivity.esm-bundler-DY1JkAEA.js";import{J as r,L as i,P as ee,Y as a,_ as o,d as te,f as s,g as ne,l as c,p as l,r as re,u,y as d,z as ie}from"./runtime-core.esm-bundler-Bqg71Vll.js";import{t as f}from"./QBtn-BUSdPaf4.js";import{Qt as p,Ut as m,a as h,at as ae}from"./index-
|
|
1
|
+
import{lt as e,pt as t,v as n}from"./reactivity.esm-bundler-DY1JkAEA.js";import{J as r,L as i,P as ee,Y as a,_ as o,d as te,f as s,g as ne,l as c,p as l,r as re,u,y as d,z as ie}from"./runtime-core.esm-bundler-Bqg71Vll.js";import{t as f}from"./QBtn-BUSdPaf4.js";import{Qt as p,Ut as m,a as h,at as ae}from"./index-BZwhT2-I.js";import{t as oe}from"./QMarkupTable-UhP7fVUp.js";import{a as g,i as _}from"./use-tours-DOUjqO2f.js";var v=[`workspace`,`engine`,`model`,`status`,`branch`,`tasks_done`,`tasks_total`,`commits`,`files_changed`,`insertions`,`deletions`,`agent_messages`,`user_messages`,`injected_prompts`,`questions`,`tool_calls`,`errors`,`input_tokens`,`output_tokens`,`sessions`,`duration_seconds`];function y(e){if(e==null)return``;let t=String(e);return/[",\r\n]/.test(t)?`"${t.replace(/"/g,`""`)}"`:t}function b(e){let t=e.map(e=>{let t=e.gitStats,n=e.activity;return[e.workspace.name,e.workspace.engine,e.workspace.model,e.workspace.status,e.workspace.workingBranch,e.tasks.done,e.tasks.total,t?.commitCount??null,t?.filesChanged??null,t?.insertions??null,t?.deletions??null,n.agentMessages,n.userMessages,n.injectedPrompts,n.questions,n.toolCalls,n.errors,n.inputTokens,n.outputTokens,n.sessions,Math.round(n.durationMs/1e3)].map(y).join(`,`)});return`${[v.join(`,`),...t].join(`\r
|
|
2
2
|
`)}`}var x={key:0,class:`comparison-panel q-pa-md`},S={class:`row items-center q-mb-sm`},C={class:`text-subtitle2`},w={class:`text-caption text-kobo-3 q-mb-sm`},T={class:`text-left`},E={class:`text-left`},D={class:`text-right`},O={class:`text-right`},k={class:`text-right`},A={class:`text-right`},j={class:`text-right`},M={class:`text-right`},N={class:`text-right`},P={class:`text-right`},F={class:`text-right`},I={class:`text-right`},L={class:`text-right`},R={class:`text-caption text-kobo-3 comparison-mono`},z={key:0,class:`text-caption text-kobo-3`},B={class:`text-right comparison-mono`},V={class:`text-right`},H={class:`text-right`},U={class:`text-right`},se={key:0,class:`comparison-mono`},W={class:`text-kobo-success`},G={class:`text-kobo-danger q-ml-xs`},K={key:1,class:`text-kobo-3`},ce={class:`text-right comparison-mono`},le=[`title`],ue={class:`text-right`},de={class:`text-right`},fe={class:`text-right comparison-mono`},pe=[`title`],me={class:`text-right`},he={class:`text-right comparison-mono`},ge={class:`text-right`},_e={key:1,class:`text-caption text-kobo-3`},ve={key:0,class:`text-caption text-kobo-warning q-mt-sm`},q=g(d({__name:`ComparisonPanel`,props:{workspaceId:{}},setup(d){let g=d;function v(e){return e<1e3?String(e):e<1e6?`${(e/1e3).toFixed(+(e<1e4))}k`:`${(e/1e6).toFixed(1)}M`}function y(e){if(e<=0)return`-`;let t=Math.round(e/1e3);if(t<60)return J(`reliability.durationSeconds`,{s:t});let n=Math.floor(t/60);return n<60?J(`reliability.durationMinutes`,{m:n,s:t%60}):J(`reliability.durationHours`,{h:Math.floor(n/60),m:n%60})}let q=h(),ye=ae(),{t:J}=p(),Y=n([]),X=n(!1),be={created:`workspaceStatus.created`,extracting:`workspaceStatus.extracting`,brainstorming:`workspaceStatus.brainstorming`,executing:`workspaceStatus.executing`,compacting:`workspaceStatus.compacting`,"awaiting-user":`workspaceStatus.awaitingUser`,completed:`workspaceStatus.completed`,idle:`workspaceStatus.idle`,error:`workspaceStatus.error`,quota:`workspaceStatus.quota`,retrying:`workspaceStatus.retrying`},Z=n({});function xe(e){return Z.value[e]??e}async function Se(){try{let e=await m(`/api/engines`);if(!e.ok)return;let t=await e.json();Z.value=Object.fromEntries(t.map(e=>[e.id,e.displayName]))}catch{}}function Ce(e){let t=be[e];return t?J(t):e}let we=c(()=>g.workspaceId);function Q(e){return e.workspace.id===we.value}function Te(e){ye.selectWorkspace(e),q.push({name:`workspace`,params:{id:e}})}function Ee(){let e=b(Y.value),t=new Blob([e],{type:`text/csv;charset=utf-8`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`kobo-comparison-${Y.value[0]?.workspace.comparisonId??`comparison`}.csv`,r.click(),URL.revokeObjectURL(n)}async function $(){X.value=!0;try{let e=await m(`/api/workspaces/${g.workspaceId}/comparison`);if(!e.ok){Y.value=[];return}let t=await e.json();Y.value=t.members??[]}catch{Y.value=[]}finally{X.value=!1}}return ee(()=>{Se(),$()}),r(()=>g.workspaceId,$),(n,r)=>Y.value.length>0?(i(),l(`div`,x,[u(`div`,S,[u(`div`,C,t(n.$t(`comparison.title`)),1),o(_),o(f,{flat:``,dense:``,round:``,size:`sm`,icon:`download`,title:n.$t(`comparison.exportCsv`),onClick:Ee},null,8,[`title`]),o(f,{flat:``,dense:``,round:``,size:`sm`,icon:`refresh`,loading:X.value,onClick:$},null,8,[`loading`])]),u(`div`,w,t(n.$t(`comparison.hint`)),1),o(oe,{flat:``,dense:``,dark:``,class:`comparison-table`},{default:a(()=>[u(`thead`,null,[u(`tr`,null,[u(`th`,T,t(n.$t(`comparison.engine`)),1),u(`th`,E,t(n.$t(`comparison.status`)),1),u(`th`,D,t(n.$t(`comparison.tasks`)),1),u(`th`,O,t(n.$t(`comparison.commits`)),1),u(`th`,k,t(n.$t(`comparison.files`)),1),u(`th`,A,t(n.$t(`comparison.diff`)),1),u(`th`,j,t(n.$t(`comparison.messages`)),1),u(`th`,M,t(n.$t(`comparison.questions`)),1),u(`th`,N,t(n.$t(`comparison.tools`)),1),u(`th`,P,t(n.$t(`comparison.errors`)),1),u(`th`,F,t(n.$t(`comparison.tokens`)),1),u(`th`,I,t(n.$t(`comparison.sessions`)),1),u(`th`,L,t(n.$t(`comparison.duration`)),1),r[0]||=u(`th`,null,null,-1)])]),u(`tbody`,null,[(i(!0),l(re,null,ie(Y.value,r=>(i(),l(`tr`,{key:r.workspace.id,class:e({"comparison-current":Q(r)})},[u(`td`,null,[u(`div`,null,t(xe(r.workspace.engine)),1),u(`div`,R,t(r.workspace.model),1)]),u(`td`,null,[ne(t(Ce(r.workspace.status))+` `,1),r.workspace.archivedAt?(i(),l(`span`,z,` · `+t(n.$t(`comparison.archived`)),1)):s(``,!0)]),u(`td`,B,t(r.tasks.done)+`/`+t(r.tasks.total),1),u(`td`,V,t(r.gitStats?.commitCount??`-`),1),u(`td`,H,t(r.gitStats?.filesChanged??`-`),1),u(`td`,U,[r.gitStats?(i(),l(`span`,se,[u(`span`,W,`+`+t(r.gitStats.insertions),1),u(`span`,G,`-`+t(r.gitStats.deletions),1)])):(i(),l(`span`,K,`-`))]),u(`td`,ce,[u(`span`,{title:n.$t(`comparison.messagesTitle`)},t(r.activity.agentMessages)+` / `+t(r.activity.userMessages),9,le)]),u(`td`,ue,t(r.activity.questions),1),u(`td`,de,t(r.activity.toolCalls),1),u(`td`,{class:e([`text-right`,r.activity.errors>0?`text-kobo-danger`:``])},t(r.activity.errors),3),u(`td`,fe,[u(`span`,{title:n.$t(`comparison.tokensTitle`)},t(v(r.activity.inputTokens))+` / `+t(v(r.activity.outputTokens)),9,pe)]),u(`td`,me,t(r.activity.sessions),1),u(`td`,he,t(y(r.activity.durationMs)),1),u(`td`,ge,[Q(r)?(i(),l(`span`,_e,t(n.$t(`comparison.current`)),1)):(i(),te(f,{key:0,flat:``,dense:``,"no-caps":``,size:`sm`,label:n.$t(`comparison.open`),onClick:e=>Te(r.workspace.id)},null,8,[`label`,`onClick`]))])],2))),128))])]),_:1}),Y.value.length<2?(i(),l(`div`,ve,t(n.$t(`comparison.incomplete`)),1)):s(``,!0)])):s(``,!0)}}),[[`__scopeId`,`data-v-bda71e6d`]]);export{q as default};
|