@loicngr/kobo 1.11.43 → 1.11.44
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 +36 -1
- package/CHANGELOG.md +6 -0
- package/dist/mcp-server/kobo-tasks-handlers.js +31 -74
- package/dist/mcp-server/kobo-tasks-server.js +51 -4
- package/dist/server/db/auto-loop-schema.js +44 -0
- package/dist/server/db/migrations.js +4 -0
- package/dist/server/db/review-return-schema.js +10 -0
- package/dist/server/db/schema.js +4 -0
- package/dist/server/index.js +10 -9
- package/dist/server/routes/auto-loop-messages.js +51 -0
- package/dist/server/routes/workspaces.js +46 -136
- package/dist/server/services/agent/engines/claude-code/engine.js +1 -0
- package/dist/server/services/agent/engines/codex/engine.js +91 -31
- package/dist/server/services/agent/orchestrator.js +237 -88
- package/dist/server/services/agent/session-controller.js +42 -2
- package/dist/server/services/auto-loop-message-service.js +79 -0
- package/dist/server/services/auto-loop-service.js +225 -86
- package/dist/server/services/auto-loop-state-service.js +30 -0
- package/dist/server/services/cron-service.js +30 -16
- package/dist/server/services/quota-backoff-service.js +42 -10
- package/dist/server/services/review-return-service.js +64 -0
- package/dist/server/services/review-service.js +187 -0
- package/dist/server/services/settings-service.js +3 -3
- package/dist/server/services/task-mutations.js +186 -0
- package/dist/server/services/wakeup-service.js +16 -1
- package/dist/server/services/workspace-message-service.js +16 -2
- package/dist/server/services/workspace-service.js +25 -36
- package/dist/shared/auto-loop-prompts.js +22 -11
- package/dist/shared/auto-loop-types.js +1 -0
- package/dist/shared/review.js +6 -0
- package/dist/shared/task-verification.js +11 -0
- package/package.json +12 -12
- package/src/client/dist/pwa/assets/{ActivityFeed-D1e-zV3O.js → ActivityFeed-D_y4aikp.js} +1 -1
- package/src/client/dist/pwa/assets/{ChangelogPage-DX1WGFea.js → ChangelogPage-DSKCvpr2.js} +1 -1
- package/src/client/dist/pwa/assets/{ClosePopup-BqW5dy-O.js → ClosePopup-CWjIRHxu.js} +1 -1
- package/src/client/dist/pwa/assets/{ComparisonPanel-B4ne55Xj.js → ComparisonPanel-DDxcsxyC.js} +1 -1
- package/src/client/dist/pwa/assets/{CreatePage-Bx_GpUni.js → CreatePage-DKVEknbL.js} +2 -2
- package/src/client/dist/pwa/assets/{DashboardPage-Cv6HJEcO.js → DashboardPage-Dg2s9nnv.js} +1 -1
- package/src/client/dist/pwa/assets/{DiffViewer-COwGxPt6.js → DiffViewer-BSzNScIr.js} +4 -4
- package/src/client/dist/pwa/assets/{DocumentsPanel-DCXpLLb7.js → DocumentsPanel-DfEoI_f7.js} +1 -1
- package/src/client/dist/pwa/assets/{DrawerToggleButton-DRL3RCkM.js → DrawerToggleButton-D85PwhKb.js} +1 -1
- package/src/client/dist/pwa/assets/GitPanel-CuG8MlgF.js +3 -0
- package/src/client/dist/pwa/assets/{HealthPage-XrOuMoDJ.js → HealthPage-CaLCpejR.js} +1 -1
- package/src/client/dist/pwa/assets/MainLayout-CDxYIJ_s.js +2 -0
- package/src/client/dist/pwa/assets/MainLayout-DTLNunOi.css +1 -0
- package/src/client/dist/pwa/assets/{QBadge-DbkxGtht.js → QBadge-FWC1zDCq.js} +1 -1
- package/src/client/dist/pwa/assets/{QBanner-DhqH95GW.js → QBanner-CcRI_QIy.js} +1 -1
- package/src/client/dist/pwa/assets/QBtn-DEdx_Y1V.js +1 -0
- package/src/client/dist/pwa/assets/{QBtnDropdown-163oM6T_.js → QBtnDropdown-qJWGcZpC.js} +1 -1
- package/src/client/dist/pwa/assets/{QBtnGroup-DELKYo3u.js → QBtnGroup-CAoD6G0Q.js} +1 -1
- package/src/client/dist/pwa/assets/{QBtnToggle-BI3k3Ch2.js → QBtnToggle-C_hQ2UCQ.js} +1 -1
- package/src/client/dist/pwa/assets/{QChip-owciRuZu.js → QChip-DCPUhqXX.js} +1 -1
- package/src/client/dist/pwa/assets/QDrawer-DX3PhMqC.js +1 -0
- package/src/client/dist/pwa/assets/{QItemSection-D_5_0UrX.js → QItemSection-BhqphaH6.js} +1 -1
- package/src/client/dist/pwa/assets/{QList-qupzuEqO.js → QList-CHm4JNP0.js} +1 -1
- package/src/client/dist/pwa/assets/{QMarkupTable-B9QuKtK_.js → QMarkupTable-CNpiA9oq.js} +1 -1
- package/src/client/dist/pwa/assets/{QPage-DaX9sMQC.js → QPage-BXBw2Alx.js} +1 -1
- package/src/client/dist/pwa/assets/QSelect-CY4TWW_j.js +1 -0
- package/src/client/dist/pwa/assets/{QSpinnerDots-DnCV3VzI.js → QSpinnerDots-BkFiCsH3.js} +1 -1
- package/src/client/dist/pwa/assets/{QTooltip-BQWY7aeM.js → QTooltip-cDK5AOQ5.js} +1 -1
- package/src/client/dist/pwa/assets/{SchedulePanel-Bos94OyR.js → SchedulePanel-LvHiZ6ZH.js} +1 -1
- package/src/client/dist/pwa/assets/{SearchPage-DOHkP5lj.js → SearchPage-BO-J4aNc.js} +1 -1
- package/src/client/dist/pwa/assets/{SettingsPage-DtGsd0XH.js → SettingsPage-Aw89fRSq.js} +2 -2
- package/src/client/dist/pwa/assets/{SplitWorkspacePage-DL4kp9Ah.js → SplitWorkspacePage-BIEceNwH.js} +1 -1
- package/src/client/dist/pwa/assets/{TerminalPanel-DHDnyiYh.js → TerminalPanel-DitOCad1.js} +1 -1
- package/src/client/dist/pwa/assets/{TouchPan-BnHXDR6F.js → TouchPan-DvPAhZsa.js} +1 -1
- package/src/client/dist/pwa/assets/{TourReplayButton-ClVcB6mO.js → TourReplayButton-CJYdH3Jf.js} +1 -1
- package/src/client/dist/pwa/assets/{WorkspaceAttentionLabels-Bxe6oIJI.js → WorkspaceAttentionLabels-CY-9z9nw.js} +1 -1
- package/src/client/dist/pwa/assets/WorkspacePage-DAVo-E4p.css +1 -0
- package/src/client/dist/pwa/assets/WorkspacePage-xH_OyA3r.js +4 -0
- package/src/client/dist/pwa/assets/{browser-Bkx4fbxl.js → browser-BsB6cFv4.js} +1 -1
- package/src/client/dist/pwa/assets/build-path-tree-CW-ER1Mt.js +1 -0
- package/src/client/dist/pwa/assets/{de-BU0dILBs.js → de-Mu7biceO.js} +2 -2
- package/src/client/dist/pwa/assets/documents-SCd3w8xV.js +1 -0
- package/src/client/dist/pwa/assets/{editor.api-DreEG0If.js → editor.api-BUdM7I6y.js} +1 -1
- package/src/client/dist/pwa/assets/editor.worker-iO5iN0DB.js +33 -0
- package/src/client/dist/pwa/assets/efforts-DTJQP9or.js +9 -0
- package/src/client/dist/pwa/assets/engineFeatures-B-9jHocY.css +1 -0
- package/src/client/dist/pwa/assets/engineFeatures-Bj6Ob41d.js +1 -0
- package/src/client/dist/pwa/assets/{es-CNp0s9na.js → es-BY5IfNI2.js} +2 -2
- package/src/client/dist/pwa/assets/expand-template-SM8vvYyO.js +1 -0
- package/src/client/dist/pwa/assets/{format-B7z3F-Mw.js → format-BjQxf4pe.js} +3 -3
- package/src/client/dist/pwa/assets/{formatters-BTBiU0v3.js → formatters-BejhmNTV.js} +1 -1
- package/src/client/dist/pwa/assets/{fr-RqJyWSdm.js → fr-BMXCzFCM.js} +2 -2
- package/src/client/dist/pwa/assets/{freemarker2-BZNTVQ3K.js → freemarker2-5d5GhyRp.js} +1 -1
- package/src/client/dist/pwa/assets/{handlebars-k8tN0dI3.js → handlebars-DaafEsDK.js} +1 -1
- package/src/client/dist/pwa/assets/{html-iZL3bbXq.js → html-CwHBDd2A.js} +1 -1
- package/src/client/dist/pwa/assets/i18n-CgWW5vfb.js +1 -0
- package/src/client/dist/pwa/assets/index-0wtBh1Xt.css +1 -0
- package/src/client/dist/pwa/assets/index-Di9Sz5E8.js +20 -0
- package/src/client/dist/pwa/assets/{it-DSxNuCwL.js → it-ByPZQK_K.js} +2 -2
- package/src/client/dist/pwa/assets/{javascript-TV6gg0MO.js → javascript-DSNIEEH5.js} +1 -1
- package/src/client/dist/pwa/assets/{liquid-Cifa5ujF.js → liquid-Dma1UpA1.js} +1 -1
- package/src/client/dist/pwa/assets/{mdx-Bnj_8yGE.js → mdx-D8rqEAws.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco-contributions-pEh0n9Wk.js → monaco-contributions-2E7O2zoi.js} +1 -1
- package/src/client/dist/pwa/assets/{monaco.contribution-D7NmJUJH.js → monaco.contribution-DqOgo72G.js} +2 -2
- package/src/client/dist/pwa/assets/{network-auth-3_5p4fdc.js → network-auth-DNmhJTZn.js} +1 -1
- package/src/client/dist/pwa/assets/{notify-theme-D_nf9AeF.js → notify-theme-B6Hiwvwb.js} +1 -1
- package/src/client/dist/pwa/assets/{pending-diff-open-CUnxC1xw.js → pending-diff-open-CeiVIFZn.js} +1 -1
- package/src/client/dist/pwa/assets/permissionModes-DWdtf81n.js +36 -0
- package/src/client/dist/pwa/assets/{pinia-BKqmoVru.js → pinia-CTJ3OfP3.js} +1 -1
- package/src/client/dist/pwa/assets/{private.use-form-C7umbGO-.js → private.use-form-Bk8ti264.js} +1 -1
- package/src/client/dist/pwa/assets/{project-color-CihwpDAA.js → project-color-BCp9SWoI.js} +1 -1
- package/src/client/dist/pwa/assets/{python-DOoNBSNL.js → python-f-9NqRlI.js} +1 -1
- package/src/client/dist/pwa/assets/{razor-Bvq5vVpJ.js → razor-DsCmoX0h.js} +1 -1
- package/src/client/dist/pwa/assets/reactivity.esm-bundler-Bo9anJjg.js +1 -0
- package/src/client/dist/pwa/assets/render-chat-markdown-DK5BD9mU.js +67 -0
- package/src/client/dist/pwa/assets/{runtime-core.esm-bundler-CDnVUfeZ.js → runtime-core.esm-bundler-CNFKm4ij.js} +1 -1
- package/src/client/dist/pwa/assets/{typescript-VVzxoeyM.js → typescript-cEHg4L10.js} +1 -1
- package/src/client/dist/pwa/assets/{use-checkbox-FnauAgTp.js → use-checkbox-CnvHBhSK.js} +1 -1
- package/src/client/dist/pwa/assets/{use-id-BIuaWKkB.js → use-id-wXd4c8FA.js} +1 -1
- package/src/client/dist/pwa/assets/use-is-mobile-DpKI3XMy.js +1 -0
- package/src/client/dist/pwa/assets/{use-search-index-status-DtLzygcy.js → use-search-index-status-Bluf9L99.js} +1 -1
- package/src/client/dist/pwa/assets/use-tours-BmTbosmB.js +2 -0
- package/src/client/dist/pwa/assets/{workspace-templates-1ui80Kqo.js → workspace-templates-DUWDLMIX.js} +1 -1
- package/src/client/dist/pwa/assets/{xml-CzGFIxQa.js → xml-Plt-Y7we.js} +1 -1
- package/src/client/dist/pwa/assets/{yaml-Bl7nDJeC.js → yaml-ScEmaAeN.js} +1 -1
- package/src/client/dist/pwa/index.html +10 -10
- package/src/client/dist/pwa/sw.js +1 -1
- package/src/mcp-server/kobo-tasks-handlers.ts +68 -104
- package/src/mcp-server/kobo-tasks-server.ts +56 -4
- package/src/client/dist/pwa/assets/GitPanel-C9mz4GXF.js +0 -3
- package/src/client/dist/pwa/assets/MainLayout-BwV89R-l.css +0 -1
- package/src/client/dist/pwa/assets/MainLayout-CwWavQjV.js +0 -2
- package/src/client/dist/pwa/assets/QBtn-CZaBclNw.js +0 -1
- package/src/client/dist/pwa/assets/QDrawer-DNEj8wLZ.js +0 -1
- package/src/client/dist/pwa/assets/QSelect-BUlOQe5k.js +0 -1
- package/src/client/dist/pwa/assets/WorkspacePage-Clc4Fl3B.js +0 -4
- package/src/client/dist/pwa/assets/WorkspacePage-DCg9zSxz.css +0 -1
- package/src/client/dist/pwa/assets/build-path-tree-BpSY7N5O.js +0 -1
- package/src/client/dist/pwa/assets/documents-BIlWh3o-.js +0 -1
- package/src/client/dist/pwa/assets/editor.worker-CwQAd_xr.js +0 -30
- package/src/client/dist/pwa/assets/efforts-D_yTzymv.js +0 -9
- package/src/client/dist/pwa/assets/engineFeatures-C33LTVkK.js +0 -1
- package/src/client/dist/pwa/assets/expand-template-wRhAXT-1.js +0 -1
- package/src/client/dist/pwa/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa-Dr0goTwe.woff +0 -0
- package/src/client/dist/pwa/assets/i18n--PCet00a.js +0 -1
- package/src/client/dist/pwa/assets/index-CPfrY38K.js +0 -20
- package/src/client/dist/pwa/assets/index-CUoUy6tH.css +0 -1
- package/src/client/dist/pwa/assets/permissionModes-DC51Pz84.js +0 -36
- package/src/client/dist/pwa/assets/reactivity.esm-bundler-DEJj9cFv.js +0 -1
- package/src/client/dist/pwa/assets/render-chat-markdown-BQ_saiy5.js +0 -67
- package/src/client/dist/pwa/assets/use-is-mobile-CWjqe8gC.js +0 -1
- package/src/client/dist/pwa/assets/use-tours-BKeYrJaQ.js +0 -2
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { assertWorkspaceLifecycleAvailable } from '../utils/workspace-lifecycle-guard.js';
|
|
2
2
|
import { isAgentUnavailableError, isShuttingDown, sendMessage, startAgent } from './agent/orchestrator.js';
|
|
3
|
+
import { hasLoopMessage } from './auto-loop-message-service.js';
|
|
3
4
|
import * as autoLoop from './auto-loop-service.js';
|
|
4
5
|
import { createChatReceipt } from './chat-receipt-service.js';
|
|
6
|
+
import { emitEphemeral } from './websocket-service.js';
|
|
5
7
|
import { getActiveSession, getWorkspace, updateWorkspaceStatus } from './workspace-service.js';
|
|
6
8
|
/** Shared delivery for WebSocket chat and external MCP clients. */
|
|
7
9
|
export async function deliverWorkspaceMessage(workspaceId, message, hooks) {
|
|
@@ -18,6 +20,18 @@ export async function deliverWorkspaceMessage(workspaceId, message, hooks) {
|
|
|
18
20
|
throw new Error(`Workspace '${workspaceId}' not found`);
|
|
19
21
|
if (workspace.archivedAt || workspace.worktreePurgedAt)
|
|
20
22
|
throw new Error('Restore the workspace before sending a message');
|
|
23
|
+
if (message.delivery === 'next_iteration') {
|
|
24
|
+
if (!message.clientMessageId)
|
|
25
|
+
throw new Error('clientMessageId is required for queued delivery');
|
|
26
|
+
const acceptedBefore = hasLoopMessage(workspaceId, message.clientMessageId);
|
|
27
|
+
if (!autoLoop.queueInstruction(workspaceId, message.content, message.clientMessageId, message.source))
|
|
28
|
+
throw new Error('Auto-loop is not enabled');
|
|
29
|
+
if (!acceptedBefore)
|
|
30
|
+
receipt.accept();
|
|
31
|
+
else
|
|
32
|
+
emitEphemeral(workspaceId, 'chat:accepted', { clientMessageId: message.clientMessageId });
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
21
35
|
if (workspace.status === 'compacting') {
|
|
22
36
|
reason = 'compacting';
|
|
23
37
|
throw new Error('Workspace is compacting its context; wait until compaction finishes before sending a message');
|
|
@@ -27,8 +41,6 @@ export async function deliverWorkspaceMessage(workspaceId, message, hooks) {
|
|
|
27
41
|
throw new Error('Answer the pending question or permission request before sending a chat message');
|
|
28
42
|
}
|
|
29
43
|
const loop = autoLoop.getStatus(workspaceId);
|
|
30
|
-
if (loop.auto_loop && loop.auto_loop_ready)
|
|
31
|
-
autoLoop.disable(workspaceId, 'user-action');
|
|
32
44
|
let sessionId = message.sessionId ?? getActiveSession(workspaceId)?.id;
|
|
33
45
|
try {
|
|
34
46
|
if (hooks?.beforeDispatch)
|
|
@@ -48,6 +60,8 @@ export async function deliverWorkspaceMessage(workspaceId, message, hooks) {
|
|
|
48
60
|
updateWorkspaceStatus(workspaceId, 'executing');
|
|
49
61
|
sessionId = message.sessionId ?? started.agentSessionId;
|
|
50
62
|
}
|
|
63
|
+
if (loop.auto_loop && loop.auto_loop_ready)
|
|
64
|
+
autoLoop.disable(workspaceId, 'user-action');
|
|
51
65
|
receipt.accept(sessionId);
|
|
52
66
|
return { sessionId };
|
|
53
67
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { nanoid } from 'nanoid';
|
|
2
|
+
import { parseTaskVerification } from '../../shared/task-verification.js';
|
|
2
3
|
import { getDb } from '../db/index.js';
|
|
3
4
|
import { isValidBranchName } from '../utils/git-ops.js';
|
|
4
5
|
import { resolveWorkspaceWorktreePath } from '../utils/worktree-paths.js';
|
|
@@ -6,6 +7,7 @@ import * as orchestrator from './agent/orchestrator.js';
|
|
|
6
7
|
import * as autoLoopService from './auto-loop-service.js';
|
|
7
8
|
import * as cronService from './cron-service.js';
|
|
8
9
|
import * as quotaBackoffService from './quota-backoff-service.js';
|
|
10
|
+
import { createTaskRecord, deleteTaskRecord, updateTaskRecord } from './task-mutations.js';
|
|
9
11
|
import * as wakeupService from './wakeup-service.js';
|
|
10
12
|
import { emitEphemeral } from './websocket-service.js';
|
|
11
13
|
/** Allowed status transitions per current status. Enforced by updateWorkspaceStatus. */
|
|
@@ -112,6 +114,8 @@ function mapTask(row) {
|
|
|
112
114
|
status: row.status,
|
|
113
115
|
isAcceptanceCriterion: row.is_acceptance_criterion === 1,
|
|
114
116
|
sortOrder: row.sort_order,
|
|
117
|
+
role: row.role,
|
|
118
|
+
verification: parseTaskVerification(row.verification),
|
|
115
119
|
createdAt: row.created_at,
|
|
116
120
|
updatedAt: row.updated_at,
|
|
117
121
|
};
|
|
@@ -590,18 +594,10 @@ export function deleteWorkspace(id) {
|
|
|
590
594
|
/** Create a new task under a workspace. Throws if the workspace does not exist. */
|
|
591
595
|
export function createTask(workspaceId, data) {
|
|
592
596
|
const db = getDb();
|
|
593
|
-
|
|
594
|
-
if (!exists) {
|
|
597
|
+
if (!db.prepare('SELECT 1 FROM workspaces WHERE id = ?').get(workspaceId)) {
|
|
595
598
|
throw new Error(`Workspace not found: '${workspaceId}'`);
|
|
596
599
|
}
|
|
597
|
-
|
|
598
|
-
const id = nanoid();
|
|
599
|
-
db.prepare(`
|
|
600
|
-
INSERT INTO tasks (id, workspace_id, title, status, is_acceptance_criterion, sort_order, created_at, updated_at)
|
|
601
|
-
VALUES (?, ?, ?, 'pending', ?, ?, ?, ?)
|
|
602
|
-
`).run(id, workspaceId, data.title, data.isAcceptanceCriterion ? 1 : 0, data.sortOrder ?? 0, now, now);
|
|
603
|
-
const row = db.prepare('SELECT * FROM tasks WHERE id = ?').get(id);
|
|
604
|
-
return mapTask(row);
|
|
600
|
+
return mapTask(createTaskRecord(db, workspaceId, data));
|
|
605
601
|
}
|
|
606
602
|
/** Fetch a single task by ID scoped to a workspace, or null if not found. */
|
|
607
603
|
export function getTask(taskId, workspaceId) {
|
|
@@ -613,39 +609,32 @@ export function getTask(taskId, workspaceId) {
|
|
|
613
609
|
export function listTasks(workspaceId) {
|
|
614
610
|
const db = getDb();
|
|
615
611
|
const rows = db
|
|
616
|
-
.prepare('SELECT * FROM tasks WHERE workspace_id = ? ORDER BY sort_order ASC')
|
|
612
|
+
.prepare('SELECT * FROM tasks WHERE workspace_id = ? ORDER BY sort_order ASC, rowid ASC')
|
|
617
613
|
.all(workspaceId);
|
|
618
614
|
return rows.map(mapTask);
|
|
619
615
|
}
|
|
620
|
-
/** Update
|
|
621
|
-
export function
|
|
616
|
+
/** Update task fields atomically through the same completion policy as MCP. */
|
|
617
|
+
export function updateTask(taskId, data) {
|
|
622
618
|
const db = getDb();
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
const row = db.prepare('SELECT * FROM tasks WHERE id = ?').get(taskId);
|
|
626
|
-
if (!row) {
|
|
619
|
+
const existing = db.prepare('SELECT workspace_id FROM tasks WHERE id = ?').get(taskId);
|
|
620
|
+
if (!existing)
|
|
627
621
|
throw new Error(`Task '${taskId}' not found`);
|
|
628
|
-
|
|
629
|
-
|
|
622
|
+
return mapTask(updateTaskRecord(db, existing.workspace_id, taskId, data));
|
|
623
|
+
}
|
|
624
|
+
/** Update a task's status; auto-loop completion requires successful verification. */
|
|
625
|
+
export function updateTaskStatus(taskId, status, verification) {
|
|
626
|
+
return updateTask(taskId, { status, ...(verification !== undefined ? { verification } : {}) });
|
|
630
627
|
}
|
|
631
|
-
/** Update a task's title
|
|
628
|
+
/** Update a task's title and invalidate obsolete verification. */
|
|
632
629
|
export function updateTaskTitle(taskId, title) {
|
|
633
|
-
|
|
634
|
-
throw new Error('Task title cannot be empty');
|
|
635
|
-
}
|
|
636
|
-
const db = getDb();
|
|
637
|
-
const now = new Date().toISOString();
|
|
638
|
-
const result = db.prepare('UPDATE tasks SET title = ?, updated_at = ? WHERE id = ?').run(title.trim(), now, taskId);
|
|
639
|
-
if (result.changes === 0) {
|
|
640
|
-
throw new Error(`Task '${taskId}' not found`);
|
|
641
|
-
}
|
|
642
|
-
const row = db.prepare('SELECT * FROM tasks WHERE id = ?').get(taskId);
|
|
643
|
-
return mapTask(row);
|
|
630
|
+
return updateTask(taskId, { title });
|
|
644
631
|
}
|
|
645
632
|
/** Delete a task by ID. */
|
|
646
633
|
export function deleteTask(taskId) {
|
|
647
634
|
const db = getDb();
|
|
648
|
-
db.prepare('
|
|
635
|
+
const existing = db.prepare('SELECT workspace_id FROM tasks WHERE id = ?').get(taskId);
|
|
636
|
+
if (existing)
|
|
637
|
+
deleteTaskRecord(db, existing.workspace_id, taskId);
|
|
649
638
|
}
|
|
650
639
|
/** Fetch a workspace with all its tasks eagerly loaded. */
|
|
651
640
|
export function getWorkspaceWithTasks(id) {
|
|
@@ -809,8 +798,8 @@ export function getLatestSession(workspaceId) {
|
|
|
809
798
|
/**
|
|
810
799
|
* Return the "active" session for tagging events like push/pull/open-pr traces
|
|
811
800
|
* or resumed chat messages. Skips idle sessions (never started) and prefers a
|
|
812
|
-
* running session, falling back to the
|
|
813
|
-
*
|
|
801
|
+
* running session, falling back to the last used session (any non-idle status).
|
|
802
|
+
* A resumed conversation keeps its started_at, but updates ended_at on stop.
|
|
814
803
|
*/
|
|
815
804
|
export function getActiveSession(workspaceId) {
|
|
816
805
|
const db = getDb();
|
|
@@ -820,9 +809,9 @@ export function getActiveSession(workspaceId) {
|
|
|
820
809
|
.get(workspaceId);
|
|
821
810
|
if (running)
|
|
822
811
|
return mapSession(running);
|
|
823
|
-
// Otherwise the
|
|
812
|
+
// Otherwise the last used non-idle session (completed, error, quota, etc.)
|
|
824
813
|
const latestNonIdle = db
|
|
825
|
-
.prepare("SELECT * FROM agent_sessions WHERE workspace_id = ? AND status != 'idle' ORDER BY started_at DESC LIMIT 1")
|
|
814
|
+
.prepare("SELECT * FROM agent_sessions WHERE workspace_id = ? AND status != 'idle' ORDER BY MAX(started_at, COALESCE(ended_at, started_at)) DESC, started_at DESC LIMIT 1")
|
|
826
815
|
.get(workspaceId);
|
|
827
816
|
return latestNonIdle ? mapSession(latestNonIdle) : null;
|
|
828
817
|
}
|
|
@@ -50,25 +50,35 @@ export function buildAutoLoopGroomingSteps(e2e, finalization) {
|
|
|
50
50
|
if (e2e.framework) {
|
|
51
51
|
const skillHint = e2e.skill ? `Use the \`${e2e.skill}\` skill for this task. ` : '';
|
|
52
52
|
const promptHint = e2e.prompt ? `Additional guidance: ${e2e.prompt}` : '';
|
|
53
|
-
steps.push(`${nextNum}. **E2E review**: walk the task list and identify which tasks produce user-visible behavior (UI flows, form submissions, page renders, etc.). For each one that warrants regression coverage, INSERT a follow-up sub-task with title prefixed \`[E2E] \` describing the test to write.
|
|
53
|
+
steps.push(`${nextNum}. **E2E review**: walk the task list and identify which tasks produce user-visible behavior (UI flows, form submissions, page renders, etc.). For each one that warrants regression coverage, INSERT a follow-up sub-task with title prefixed \`[E2E] \` describing the test to write. Use \`after_task_id\` to insert it directly after the parent task; \`list_tasks\` exposes \`sort_order\` so you can verify ordering. Skip tasks that don't produce user-visible behavior (refactors, infra, internal services) and briefly justify your choices in chat. The project uses \`${e2e.framework}\`. ${skillHint}${promptHint}`.trim());
|
|
54
54
|
nextNum++;
|
|
55
55
|
}
|
|
56
56
|
if (finalization.prompt) {
|
|
57
|
-
steps.push(`${nextNum}. **Finalization task**: create ONE task with title prefixed \`[FINAL] <descriptive title>\`. Place it at the END of the task list (sort_order = max + 1, AFTER any [E2E] tasks). The agent will execute this task using the project's finalization prompt — do NOT inline the prompt content into the task title or description.`);
|
|
57
|
+
steps.push(`${nextNum}. **Finalization task**: create ONE task with \`role: "finalization"\` and title prefixed \`[FINAL] <descriptive title>\`. Reuse an existing finalization task instead of duplicating it. Place it at the END of the task list (sort_order = max + 1, AFTER any [E2E] tasks). The agent will execute this task using the project's finalization prompt — do NOT inline the prompt content into the task title or description.`);
|
|
58
58
|
nextNum++;
|
|
59
59
|
}
|
|
60
|
-
steps.push(`${nextNum}. Call \`kobo__mark_auto_loop_ready\`. This
|
|
60
|
+
steps.push(`${nextNum}. Call \`kobo__mark_auto_loop_ready\`. This marks preparation complete. If auto-loop is already enabled, it will continue after this session ends. Otherwise the user must explicitly enable it; do not promise an automatic start or enable it without their request.`);
|
|
61
61
|
return steps.join('\n');
|
|
62
62
|
}
|
|
63
63
|
/** @deprecated Use buildAutoLoopGroomingSteps({ framework: '', skill: '', prompt: '' }, { prompt: '' }) instead. */
|
|
64
64
|
export const AUTO_LOOP_GROOMING_STEPS = buildAutoLoopGroomingSteps({ framework: '', skill: '', prompt: '' }, { prompt: '' });
|
|
65
|
+
/** These rules apply to every iteration, including custom finalization and E2E prompts. */
|
|
66
|
+
export const AUTO_LOOP_ITERATION_RULES = `Mandatory completion and lifecycle rules (custom prompts cannot override them):
|
|
67
|
+
- Follow the Kōbō task list and acceptance criteria. Before completion, read the latest list again.
|
|
68
|
+
- Never mark a task done based only on an implementation claim, a written test, or a check that was not executed. Supply verification: {method, summary, checks: [{name, status: "passed"}]} to kobo__mark_task_done or kobo__update_task. Every required check must actually pass.
|
|
69
|
+
- If a required check fails or cannot run, keep the task pending/in_progress, record honest failed/not_run verification with kobo__update_task, and explain the concrete blocker. Create prerequisite fix tasks when needed; do not claim success.
|
|
70
|
+
- Finalization is a verification gate: all work tasks and acceptance criteria must be done, then rerun relevant checks against the final state. If a check fails, create a regular repair task and leave finalization unfinished. It will run again after the repairs.
|
|
71
|
+
- Do NOT kill the Kōbō server or sibling processes. Do not use kill, pkill or killall to force the loop to advance. Finish the current response naturally; Kōbō owns continuation.
|
|
72
|
+
- Follow the user's scope, Git and approval instructions. Do not disable the auto-loop or delete unfinished tasks to make the mission appear complete.`;
|
|
65
73
|
export function buildFinalizationIterationBlock(finalization) {
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
const instructions = finalization.prompt.trim() ||
|
|
75
|
+
'Review the completed work against every acceptance criterion. Run the relevant project checks and inspect the final diff. Report the actual results with structured verification.';
|
|
68
76
|
return `
|
|
69
|
-
This is the **finalization task**.
|
|
77
|
+
This is the **finalization task**. Apply the following project guidance while preserving all mandatory completion and lifecycle rules:
|
|
78
|
+
|
|
79
|
+
${instructions}
|
|
70
80
|
|
|
71
|
-
|
|
81
|
+
Read kobo__list_tasks again. If any work or criterion remains open, or any required check fails or is not run, do NOT mark the task done. Add necessary repair tasks and keep finalization pending. Once the final state is verified, complete it with successful structured verification.
|
|
72
82
|
`;
|
|
73
83
|
}
|
|
74
84
|
export function buildE2eIterationBlock(e2e) {
|
|
@@ -81,11 +91,12 @@ This is an **E2E regression test** task.
|
|
|
81
91
|
|
|
82
92
|
Project E2E framework: ${e2e.framework}
|
|
83
93
|
${skillLine}${promptLine}
|
|
84
|
-
|
|
94
|
+
E2E instructions, subject to the mandatory completion and lifecycle rules:
|
|
85
95
|
1. Write the test source file in the project's existing E2E directory (look at \`cypress/\`, \`e2e/\`, \`tests/e2e/\`, or follow the skill / guidance above). Reuse existing fixtures and patterns.
|
|
86
|
-
2.
|
|
87
|
-
3.
|
|
88
|
-
4. The code-review gate
|
|
96
|
+
2. Run the tests and provide the actual successful results as structured verification before completion.
|
|
97
|
+
3. If the environment is broken (Docker down, browser missing, port busy, dependencies absent), do NOT mark the task done. Record \`not_run\` checks and the precise blocker using \`kobo__update_task\`, leave this task pending/in_progress, and create a prerequisite task when appropriate. A test source file by itself is not a verified result.
|
|
98
|
+
4. The code-review gate still applies. Review both the relevance of the test and the evidence that it passed.
|
|
99
|
+
|
|
89
100
|
`;
|
|
90
101
|
}
|
|
91
102
|
export const AUTO_LOOP_HARD_RULES = `Hard rules:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loicngr/kobo",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.44",
|
|
4
4
|
"description": "Kōbō — multi-workspace agent manager for Claude Code. Orchestrates isolated git worktrees with dev servers, Notion integration, and MCP tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
|
@@ -69,15 +69,15 @@
|
|
|
69
69
|
"prepublishOnly": "npm run build"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
72
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.274",
|
|
73
73
|
"@emnapi/core": "^1.11.3",
|
|
74
74
|
"@emnapi/runtime": "^1.11.3",
|
|
75
|
-
"@hono/node-server": "^2.1.
|
|
75
|
+
"@hono/node-server": "^2.1.1",
|
|
76
76
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
77
|
-
"@openai/codex": "^0.
|
|
77
|
+
"@openai/codex": "^0.154.0",
|
|
78
78
|
"better-sqlite3": "^13.0.3",
|
|
79
|
-
"cron-parser": "^5.
|
|
80
|
-
"hono": "^4.13.
|
|
79
|
+
"cron-parser": "^5.10.1",
|
|
80
|
+
"hono": "^4.13.8",
|
|
81
81
|
"nanoid": "^6.0.1",
|
|
82
82
|
"node-pty": "^1.1.0",
|
|
83
83
|
"ws": "^8.21.3"
|
|
@@ -85,16 +85,16 @@
|
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@biomejs/biome": "2.5.7",
|
|
87
87
|
"@types/better-sqlite3": "^9.6.0",
|
|
88
|
-
"@types/node": "^26.
|
|
88
|
+
"@types/node": "^26.6.1",
|
|
89
89
|
"@types/ws": "^8.18.1",
|
|
90
|
-
"@vitest/runner": "^4.1.
|
|
91
|
-
"concurrently": "^10.0.
|
|
92
|
-
"tsx": "^4.23.
|
|
90
|
+
"@vitest/runner": "^4.1.11",
|
|
91
|
+
"concurrently": "^10.0.5",
|
|
92
|
+
"tsx": "^4.23.13",
|
|
93
93
|
"typescript": "^6.0.3",
|
|
94
|
-
"vitest": "^4.1.
|
|
94
|
+
"vitest": "^4.1.11"
|
|
95
95
|
},
|
|
96
96
|
"overrides": {
|
|
97
|
-
"@hono/node-server": "^2.1.
|
|
97
|
+
"@hono/node-server": "^2.1.1",
|
|
98
98
|
"shell-quote": "^1.10.0"
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{S as e,ct as t,j as n,ot as r,p as i,ut as a,v as o}from"./reactivity.esm-bundler-
|
|
1
|
+
import{S as e,ct as t,j as n,ot as r,p as i,ut as a,v as o}from"./reactivity.esm-bundler-Bo9anJjg.js";import{C as s,F as c,J as l,L as u,N as d,O as f,P as p,Y as m,_ as h,d as g,f as _,g as v,j as y,k as b,l as x,p as S,r as C,u as w,y as T,z as ee}from"./runtime-core.esm-bundler-CNFKm4ij.js";import{J as E,b as D,ct as te,l as O,pt as k,t as ne,tt as A,w as re,y as ie}from"./QBtn-DEdx_Y1V.js";import{A as ae,Dt as oe,Lt as j,N as se,P as M,Pt as ce,Tt as N,Z as le,d as ue,m as de,p as fe,x as P}from"./index-Di9Sz5E8.js";import{t as pe}from"./QSpinnerDots-BkFiCsH3.js";import{t as me}from"./QList-CHm4JNP0.js";import{t as F}from"./QMarkupTable-CNpiA9oq.js";import{c as I,l as L}from"./QSelect-CY4TWW_j.js";import{d as he}from"./permissionModes-DWdtf81n.js";import{r as ge,t as R}from"./pending-diff-open-CeiVIFZn.js";import{t as z}from"./documents-SCd3w8xV.js";import{a as B}from"./use-tours-BmTbosmB.js";import{t as V}from"./QTooltip-cDK5AOQ5.js";import{i as _e,n as ve,o as H,r as ye,t as U}from"./render-chat-markdown-DK5BD9mU.js";import{a as be,i as xe,n as Se,o as Ce,r as we,s as W}from"./WorkspacePage-xH_OyA3r.js";function Te(e,t){return s(`div`,e,[s(`table`,{class:`q-table`},t)])}var Ee={list:me,table:F},G=[`list`,`table`,`__qtable`],De=A({name:`QVirtualScroll`,props:{...L,type:{type:String,default:`list`,validator:e=>G.includes(e)},items:{type:Array,default:()=>[]},itemsFn:Function,itemsSize:Number,scrollTarget:j},setup(t,{slots:n,attrs:r}){let i,a=e(null),o=x(()=>t.itemsSize>=0&&t.itemsFn!==void 0?Number.parseInt(t.itemsSize,10):Array.isArray(t.items)?t.items.length:0),{virtualScrollSliceRange:c,localResetVirtualScroll:u,padVirtualScroll:f,onVirtualScrollEvt:m}=I({virtualScrollLength:o,getVirtualScrollTarget:S,getVirtualScrollEl:v}),h=x(()=>{if(o.value===0)return[];let e=(e,t)=>({index:c.value.from+t,item:e});return t.itemsFn===void 0?t.items.slice(c.value.from,c.value.to).map(e):t.itemsFn(c.value.from,c.value.to-c.value.from).map(e)}),g=x(()=>`q-virtual-scroll q-virtual-scroll`+(t.virtualScrollHorizontal?`--horizontal`:`--vertical`)+(t.scrollTarget===void 0?` scroll`:``)),_=x(()=>t.scrollTarget===void 0?{tabindex:0}:{});l(o,()=>{u()}),l(()=>t.scrollTarget,()=>{w(),C()});function v(){let e=a.value;return e===null?null:e.$el||e}function S(){return i}function C(){let e=v();e!==null&&(i=ce(e,t.scrollTarget),i.addEventListener(`scroll`,m,E.passive))}function w(){i!==void 0&&(i.removeEventListener(`scroll`,m,E.passive),i=void 0)}function T(){let e=f(t.type===`list`?`div`:`tbody`,h.value.map(n.default));return n.before!==void 0&&(e=n.before().concat(e)),D(n.after,e)}return u(),p(()=>{C()}),b(()=>{C()}),d(()=>{w()}),y(()=>{w()}),()=>{if(n.default===void 0){console.error(`QVirtualScroll: default scoped slot is required for rendering`);return}return t.type===`__qtable`?Te({ref:a,class:`q-table__middle `+g.value,tabindex:0},T()):s(Ee[t.type],{...r,ref:a,class:[r.class,g.value],..._.value},T)}}}),K=new Set([`setup`,`cleanup`,`archive`]);function Oe(e){switch(e.type){case`user`:return e.sender===`system-prompt`?`system-prompt`:K.has(e.sender)||ae(e.sender)?`script`:`user`;case`session`:return`session`;default:return`agent`}}function ke(e){let t=[],n=null,r=null;for(let i of e){let e=Oe(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 Ae(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 je(e){let t=e.items[0];return`${e.speaker}:${t?Ae(t):`empty`}`}function Me(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 Ne(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 Pe={class:`agent-error-item`},Fe={class:`agent-error-item__body`},Ie={class:`agent-error-item__title`},Le={class:`agent-error-item__message`},Re=B(T({__name:`AgentErrorItem`,props:{item:{}},setup(e){let t=e,{te:n}=N(),r=x(()=>{let e=`agent.error.${t.item.category}`;return n(e)?e:`agent.error.other`});return(t,n)=>(u(),S(`div`,Pe,[h(O,{name:`error_outline`,size:`16px`,class:`agent-error-item__icon`}),w(`div`,Fe,[w(`div`,Ie,a(t.$t(r.value)),1),w(`div`,Le,a(e.item.message),1)])]))}}),[[`__scopeId`,`data-v-e98c3c02`]]),q={class:`text-caption text-kobo-3`},ze=T({__name:`SessionEventItem`,props:{item:{}},setup(e){let t=e,n=x(()=>{switch(t.item.kind){case`started`:return`session.started`;case`ended`:return W(t.item.detail);case`compacted`:return`session.compacted`;default:return`session.started`}});return(e,t)=>(u(),S(`span`,q,a(e.$t(n.value)),1))}});function J(e,t){if(t.length===0||e.length===0)return e;let n=[...t].sort((e,t)=>t.length-e.length),r=new DOMParser().parseFromString(`<div>${e}</div>`,`text/html`),i=r.body.firstChild;if(!i)return e;function a(e){if(e.nodeType===Node.TEXT_NODE){Be(e,n,r);return}if(e.nodeName===`A`)return;let t=Array.from(e.childNodes);for(let e of t)a(e)}return a(i),i.innerHTML}function Be(e,t,n){let r=e.textContent??``;if(!t.some(e=>r.includes(e)))return;let i=n.createDocumentFragment(),a=0;for(;a<r.length;){let e=Y(r,a,t);if(!e){i.appendChild(n.createTextNode(r.slice(a)));break}e.index>a&&i.appendChild(n.createTextNode(r.slice(a,e.index)));let o=n.createElement(`a`);o.className=`document-link`,o.setAttribute(`data-document-path`,e.path),o.setAttribute(`href`,`#`),o.textContent=e.path,i.appendChild(o),a=e.index+e.path.length}e.parentNode?.replaceChild(i,e)}function Y(e,t,n){let r=null;for(let i of n){let n=e.indexOf(i,t);n<0||(!r||n<r.index||n===r.index&&i.length>r.path.length)&&(r={index:n,path:i})}return r}var X=[`innerHTML`],Ve=B(T({__name:`TextMessageItem`,props:{item:{}},setup(e){let t=e,n=z(),r=fe(),i=ie(),{t:a}=N(),o=x(()=>{let e=r.selectedWorkspaceId;return e?n.documentsFor(e).map(e=>e.path):[]}),s=x(()=>{let e=t.item;if(e.streaming)return U(e.text);let n=o.value;return ye(`${e.messageId}|${n.join(`,`)}`,e.text,e=>{let t=J(H.parse(e,{async:!1,breaks:!0,gfm:!0}),n);return _e(t,{addAttr:[`data-document-path`]})})});function c(e){let t=e.target?.closest(`.document-link`);if(!t)return;e.preventDefault();let o=t.getAttribute(`data-document-path`),s=r.selectedWorkspaceId;o&&s&&n.openDocumentByPath(s,o).catch(e=>{console.error(`[TextMessageItem] openDocumentByPath failed:`,e),i.notify({type:`negative`,message:a(`documents.loadFailed`),position:`top`})})}return(t,n)=>(u(),S(`div`,{class:`markdown-message`,onClick:c},[w(`div`,{innerHTML:s.value},null,8,X),e.item.streaming?(u(),g(re,{key:0,size:`xs`,class:`q-ml-xs`})):_(``,!0)]))}}),[[`__scopeId`,`data-v-99371035`]]);function He(e,t){let n=e.split(`
|
|
2
2
|
`),r=t.split(`
|
|
3
3
|
`),i=0;for(;i<n.length&&i<r.length&&n[i]===r[i];)i++;let a=n.length,o=r.length;for(;a>i&&o>i&&n[a-1]===r[o-1];)a--,o--;let s=n.slice(0,i).map(e=>({type:`context`,content:e})),c=n.slice(a).map(e=>({type:`context`,content:e})),l=n.slice(i,a),u=r.slice(i,o);return l.length>800||u.length>800?[...s,...l.map(e=>({type:`del`,content:e})),...u.map(e=>({type:`add`,content:e})),...c]:[...s,...Z(l,u),...c]}function Z(e,t){let n=e.length,r=t.length;if(n===0&&r===0)return[];if(n===0)return t.map(e=>({type:`add`,content:e}));if(r===0)return e.map(e=>({type:`del`,content:e}));let i=r+1,a=new Int32Array((n+1)*i);for(let o=n-1;o>=0;o--)for(let n=r-1;n>=0;n--)a[o*i+n]=e[o]===t[n]?a[(o+1)*i+(n+1)]+1:Math.max(a[(o+1)*i+n],a[o*i+(n+1)]);let o=[],s=0,c=0;for(;s<n&&c<r;)e[s]===t[c]?(o.push({type:`context`,content:e[s]}),s++,c++):a[(s+1)*i+c]>=a[s*i+(c+1)]?(o.push({type:`del`,content:e[s]}),s++):(o.push({type:`add`,content:t[c]}),c++);for(;s<n;)o.push({type:`del`,content:e[s++]});for(;c<r;)o.push({type:`add`,content:t[c++]});return o}function Q(e){let t=e.split(`
|
|
4
4
|
`),n=[],r=!1;for(let e of t){if(e.startsWith(`@@`)){r=!0;continue}(r||!e.startsWith(`+++`)&&!e.startsWith(`---`))&&(e.startsWith(`+`)?n.push({type:`add`,content:e.slice(1)}):e.startsWith(`-`)?n.push({type:`del`,content:e.slice(1)}):e.startsWith(` `)?n.push({type:`context`,content:e.slice(1)}):e.length>0&&n.push({type:`context`,content:e}))}return n}function Ue(e,t){if(!t||typeof t!=`object`)return null;let n=t;if(e===`Edit`){let e=n.file_path;if(!e)return null;let t=n.old_string??``,r=n.new_string??``,i=typeof n.diff==`string`?n.diff:``;if(!t&&!r&&i.length>0){let t=Q(i);return{toolName:`Edit`,filePath:e,additions:t.filter(e=>e.type===`add`).length,deletions:t.filter(e=>e.type===`del`).length,diffLines:t}}return{toolName:`Edit`,filePath:e,oldString:t,newString:r,replaceAll:n.replace_all??!1,additions:r?r.split(`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e,ut as t,v as n}from"./reactivity.esm-bundler-
|
|
1
|
+
import{j as e,ut as t,v as n}from"./reactivity.esm-bundler-Bo9anJjg.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-CNFKm4ij.js";import{t as m}from"./QBtn-DEdx_Y1V.js";import{Ht as h,Wt as g,n as _}from"./index-Di9Sz5E8.js";import{a as v,i as y,n as b}from"./use-tours-BmTbosmB.js";import{n as x}from"./render-chat-markdown-DK5BD9mU.js";import{t as S}from"./QChip-DCPUhqXX.js";import{t as C}from"./QPage-BXBw2Alx.js";import{t as w}from"./DrawerToggleButton-D85PwhKb.js";import{t as T}from"./TourReplayButton-CJYdH3Jf.js";var E={class:`row items-center q-mb-md`},D={class:`text-h6 q-ml-sm`},O={key:0,class:`text-kobo-3 text-center q-pa-lg`},k={key:1,class:`text-negative text-center q-pa-lg`},A={key:2,class:`text-kobo-3 text-center q-pa-lg`},j={key:3,class:`column q-gutter-md`,"data-tour":`changelog-list`},M={key:0,class:`text-caption text-kobo-3`},N={class:`row items-center q-mb-sm`},P={class:`text-subtitle1 text-kobo-2`,style:{"font-family":`var(--kobo-font-mono, monospace)`}},F=[`innerHTML`],I=v(f({__name:`ChangelogPage`,setup(f){let v=_(),{scheduleAutoRun:I}=b(),L=n([]),R=n(``),z=n(!1),B=n(null);function V(e){return x(e)}async function H(){z.value=!0,B.value=null;try{let e=await fetch(`/api/changelog`);if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();R.value=t.currentVersion??``,L.value=t.versions??[]}catch(e){B.value=e instanceof Error?e.message:String(e)}finally{z.value=!1}}return i(()=>{H(),I(`changelog`)}),(n,i)=>(r(),s(C,{class:`q-pa-md`,style:{"max-width":`900px`,margin:`0 auto`}},{default:a(()=>[d(`div`,E,[o(w,{class:`q-mr-xs`}),o(m,{flat:``,dense:``,round:``,icon:`arrow_back`,onClick:i[0]||=t=>e(v).back()}),d(`div`,D,t(n.$t(`changelog.title`)),1),o(y),o(m,{flat:``,dense:``,icon:`refresh`,loading:z.value,label:n.$t(`common.refresh`),onClick:H},null,8,[`loading`,`label`]),o(T,{"tour-id":`changelog`,class:`q-ml-xs`})]),z.value&&L.value.length===0?(r(),l(`div`,O,t(n.$t(`common.loading`)),1)):B.value?(r(),l(`div`,k,t(B.value),1)):L.value.length===0?(r(),l(`div`,A,t(n.$t(`changelog.empty`)),1)):(r(),l(`div`,j,[R.value?(r(),l(`div`,M,t(n.$t(`changelog.currentVersion`,{version:R.value})),1)):c(``,!0),(r(!0),l(u,null,p(L.value,e=>(r(),s(h,{key:e.version,dark:``,flat:``,bordered:``},{default:a(()=>[o(g,null,{default:a(()=>[d(`div`,N,[d(`div`,P,` v`+t(e.version),1),e.version===R.value?(r(),s(S,{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:V(e.notes)},null,8,F)]),_:2},1024)]),_:2},1024))),128))]))]),_:1}))}}),[[`__scopeId`,`data-v-6137cb7c`]]);export{I as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{V as e,nt as t}from"./QBtn-
|
|
1
|
+
import{V as e,nt as t}from"./QBtn-DEdx_Y1V.js";import{m as n,p as r}from"./use-id-wXd4c8FA.js";function i(e){return e===!1?0:e===!0||e===void 0?1:Number.parseInt(e,10)||0}function a(e){let t=e.currentTarget,i=t.__qclosepopup;i!==0&&setTimeout(()=>{let a=n(t);a!==void 0&&r(a,e,i)},0)}function o(t){e(t,13)&&a(t)}var s=t({name:`close-popup`,beforeMount(e,{value:t}){e.__qclosepopup=i(t),e.addEventListener(`click`,a),e.addEventListener(`keyup`,o)},updated(e,{value:t,oldValue:n}){t!==n&&e.__qclosepopup!==void 0&&(e.__qclosepopup=i(t))},beforeUnmount(e){e.__qclosepopup!==void 0&&(e.removeEventListener(`click`,a),e.removeEventListener(`keyup`,o),e.__qclosepopup=void 0)}});export{s as t};
|
package/src/client/dist/pwa/assets/{ComparisonPanel-B4ne55Xj.js → ComparisonPanel-DDxcsxyC.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ot as e,ut as t,v as n}from"./reactivity.esm-bundler-
|
|
1
|
+
import{ot as e,ut as t,v as n}from"./reactivity.esm-bundler-Bo9anJjg.js";import{J as r,L as i,P as a,Y as ee,_ as o,d as te,f as s,g as ne,l as c,p as l,r as u,u as d,y as f,z as re}from"./runtime-core.esm-bundler-CNFKm4ij.js";import{t as p}from"./QBtn-DEdx_Y1V.js";import{Tt as ie,n as ae,p as oe}from"./index-Di9Sz5E8.js";import{t as se}from"./QMarkupTable-CNpiA9oq.js";import{a as m,i as h}from"./use-tours-BmTbosmB.js";var g=[`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 _(e){if(e==null)return``;let t=String(e);return/[",\r\n]/.test(t)?`"${t.replace(/"/g,`""`)}"`:t}function v(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(_).join(`,`)});return`${[g.join(`,`),...t].join(`\r
|
|
2
2
|
`)}`}var y={key:0,class:`comparison-panel q-pa-md`},b={class:`row items-center q-mb-sm`},x={class:`text-subtitle2`},S={class:`text-caption text-kobo-3 q-mb-sm`},C={class:`text-left`},w={class:`text-left`},T={class:`text-right`},E={class:`text-right`},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-caption text-kobo-3 comparison-mono`},L={key:0,class:`text-caption text-kobo-3`},R={class:`text-right comparison-mono`},z={class:`text-right`},B={class:`text-right`},V={class:`text-right`},ce={key:0,class:`comparison-mono`},H={class:`text-kobo-success`},U={class:`text-kobo-danger q-ml-xs`},W={key:1,class:`text-kobo-3`},G={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`},K=m(f({__name:`ComparisonPanel`,props:{workspaceId:{}},setup(f){let m=f;function g(e){return e<1e3?String(e):e<1e6?`${(e/1e3).toFixed(+(e<1e4))}k`:`${(e/1e6).toFixed(1)}M`}function _(e){if(e<=0)return`-`;let t=Math.round(e/1e3);if(t<60)return q(`reliability.durationSeconds`,{s:t});let n=Math.floor(t/60);return n<60?q(`reliability.durationMinutes`,{m:n,s:t%60}):q(`reliability.durationHours`,{h:Math.floor(n/60),m:n%60})}let K=ae(),ye=oe(),{t:q}=ie(),J=n([]),Y=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`},X=n({});function xe(e){return X.value[e]??e}async function Se(){try{let e=await fetch(`/api/engines`);if(!e.ok)return;let t=await e.json();X.value=Object.fromEntries(t.map(e=>[e.id,e.displayName]))}catch{}}function Z(e){let t=be[e];return t?q(t):e}let Ce=c(()=>m.workspaceId);function Q(e){return e.workspace.id===Ce.value}function we(e){ye.selectWorkspace(e),K.push({name:`workspace`,params:{id:e}})}function Te(){let e=v(J.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-${J.value[0]?.workspace.comparisonId??`comparison`}.csv`,r.click(),URL.revokeObjectURL(n)}async function $(){Y.value=!0;try{let e=await fetch(`/api/workspaces/${m.workspaceId}/comparison`);if(!e.ok){J.value=[];return}let t=await e.json();J.value=t.members??[]}catch{J.value=[]}finally{Y.value=!1}}return a(()=>{Se(),$()}),r(()=>m.workspaceId,$),(n,r)=>J.value.length>0?(i(),l(`div`,y,[d(`div`,b,[d(`div`,x,t(n.$t(`comparison.title`)),1),o(h),o(p,{flat:``,dense:``,round:``,size:`sm`,icon:`download`,title:n.$t(`comparison.exportCsv`),onClick:Te},null,8,[`title`]),o(p,{flat:``,dense:``,round:``,size:`sm`,icon:`refresh`,loading:Y.value,onClick:$},null,8,[`loading`])]),d(`div`,S,t(n.$t(`comparison.hint`)),1),o(se,{flat:``,dense:``,dark:``,class:`comparison-table`},{default:ee(()=>[d(`thead`,null,[d(`tr`,null,[d(`th`,C,t(n.$t(`comparison.engine`)),1),d(`th`,w,t(n.$t(`comparison.status`)),1),d(`th`,T,t(n.$t(`comparison.tasks`)),1),d(`th`,E,t(n.$t(`comparison.commits`)),1),d(`th`,D,t(n.$t(`comparison.files`)),1),d(`th`,O,t(n.$t(`comparison.diff`)),1),d(`th`,k,t(n.$t(`comparison.messages`)),1),d(`th`,A,t(n.$t(`comparison.questions`)),1),d(`th`,j,t(n.$t(`comparison.tools`)),1),d(`th`,M,t(n.$t(`comparison.errors`)),1),d(`th`,N,t(n.$t(`comparison.tokens`)),1),d(`th`,P,t(n.$t(`comparison.sessions`)),1),d(`th`,F,t(n.$t(`comparison.duration`)),1),r[0]||=d(`th`,null,null,-1)])]),d(`tbody`,null,[(i(!0),l(u,null,re(J.value,r=>(i(),l(`tr`,{key:r.workspace.id,class:e({"comparison-current":Q(r)})},[d(`td`,null,[d(`div`,null,t(xe(r.workspace.engine)),1),d(`div`,I,t(r.workspace.model),1)]),d(`td`,null,[ne(t(Z(r.workspace.status))+` `,1),r.workspace.archivedAt?(i(),l(`span`,L,` · `+t(n.$t(`comparison.archived`)),1)):s(``,!0)]),d(`td`,R,t(r.tasks.done)+`/`+t(r.tasks.total),1),d(`td`,z,t(r.gitStats?.commitCount??`-`),1),d(`td`,B,t(r.gitStats?.filesChanged??`-`),1),d(`td`,V,[r.gitStats?(i(),l(`span`,ce,[d(`span`,H,`+`+t(r.gitStats.insertions),1),d(`span`,U,`-`+t(r.gitStats.deletions),1)])):(i(),l(`span`,W,`-`))]),d(`td`,G,[d(`span`,{title:n.$t(`comparison.messagesTitle`)},t(r.activity.agentMessages)+` / `+t(r.activity.userMessages),9,le)]),d(`td`,ue,t(r.activity.questions),1),d(`td`,de,t(r.activity.toolCalls),1),d(`td`,{class:e([`text-right`,r.activity.errors>0?`text-kobo-danger`:``])},t(r.activity.errors),3),d(`td`,fe,[d(`span`,{title:n.$t(`comparison.tokensTitle`)},t(g(r.activity.inputTokens))+` / `+t(g(r.activity.outputTokens)),9,pe)]),d(`td`,me,t(r.activity.sessions),1),d(`td`,he,t(_(r.activity.durationMs)),1),d(`td`,ge,[Q(r)?(i(),l(`span`,_e,t(n.$t(`comparison.current`)),1)):(i(),te(p,{key:0,flat:``,dense:``,"no-caps":``,size:`sm`,label:n.$t(`comparison.open`),onClick:e=>we(r.workspace.id)},null,8,[`label`,`onClick`]))])],2))),128))])]),_:1}),J.value.length<2?(i(),l(`div`,ve,t(n.$t(`comparison.incomplete`)),1)):s(``,!0)])):s(``,!0)}}),[[`__scopeId`,`data-v-e1a1dbcc`]]);export{K as default};
|