@loicngr/kobo 1.5.3 → 1.5.5
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/README.md +1 -1
- package/dist/server/db/migrations.js +7 -0
- package/dist/server/db/schema.js +1 -0
- package/dist/server/index.js +2 -2
- package/dist/server/routes/settings.js +11 -0
- package/dist/server/routes/workspaces.js +13 -5
- package/dist/server/services/agent-manager.js +4 -1
- package/dist/server/services/notion-service.js +35 -17
- package/dist/server/services/sentry-service.js +8 -3
- package/dist/server/services/settings-service.js +40 -4
- package/dist/server/services/workspace-service.js +16 -3
- package/dist/server/utils/mcp-client.js +33 -13
- package/dist/server/utils/paths.js +8 -0
- package/package.json +3 -3
- package/src/client/dist/spa/assets/ActivityFeed-CAgtfoqj.js +10 -0
- package/src/client/dist/spa/assets/{ClosePopup-jSuaV6dg.js → ClosePopup-BfANRQ7n.js} +1 -1
- package/src/client/dist/spa/assets/CreatePage-CNnVeRGC.css +1 -0
- package/src/client/dist/spa/assets/CreatePage-CnsmjbZl.js +2 -0
- package/src/client/dist/spa/assets/DiffViewer-CwAhR0Bt.js +2 -0
- package/src/client/dist/spa/assets/MainLayout-1KXWlMYS.css +1 -0
- package/src/client/dist/spa/assets/{MainLayout-z-GTmsNk.js → MainLayout-D9UzZ0l0.js} +17 -17
- package/src/client/dist/spa/assets/{QBadge-xNMZEqT-.js → QBadge-DENdn6Dv.js} +1 -1
- package/src/client/dist/spa/assets/QExpansionItem-ZAI_l6AW.js +1 -0
- package/src/client/dist/spa/assets/{QList-C0MyMgKh.js → QList-aKZe9BNZ.js} +1 -1
- package/src/client/dist/spa/assets/QMenu-DDXq2SFM.js +1 -0
- package/src/client/dist/spa/assets/{QSpinnerDots-FJCnAvfw.js → QSpinnerDots-DytntAbf.js} +1 -1
- package/src/client/dist/spa/assets/SettingsPage-DCgRTq-c.js +1 -0
- package/src/client/dist/spa/assets/SettingsPage-oWZ8sGFm.css +1 -0
- package/src/client/dist/spa/assets/{TouchPan-DuISf80E.js → TouchPan-D_gmnARo.js} +1 -1
- package/src/client/dist/spa/assets/WorkspacePage-BSBiQTKy.js +4 -0
- package/src/client/dist/spa/assets/{WorkspacePage-BIYgMXby.css → WorkspacePage-DZwv9kFd.css} +1 -1
- package/src/client/dist/spa/assets/{_plugin-vue_export-helper-fkfRoKj2.js → _plugin-vue_export-helper-DkL3SKZ8.js} +1 -1
- package/src/client/dist/spa/assets/{cssMode-4TH_2zaD.js → cssMode-CzYfUUcg.js} +1 -1
- package/src/client/dist/spa/assets/{editor.api-CyJb27tS.js → editor.api-Do3RvGrr.js} +1 -1
- package/src/client/dist/spa/assets/{editor.main-oZnnOWQQ.js → editor.main-BXGLrNaH.js} +3 -3
- package/src/client/dist/spa/assets/{formatters-B5Igo0Lf.js → formatters-hnFdqDO2.js} +1 -1
- package/src/client/dist/spa/assets/{freemarker2-QspagBXp.js → freemarker2-DD7dLGS5.js} +1 -1
- package/src/client/dist/spa/assets/{handlebars-DNK4bfk9.js → handlebars-C6fNrY_c.js} +1 -1
- package/src/client/dist/spa/assets/{html-DoAFaOJE.js → html-CsN_ZrNj.js} +1 -1
- package/src/client/dist/spa/assets/{htmlMode-Dd2XBcML.js → htmlMode-BePbSvxH.js} +1 -1
- package/src/client/dist/spa/assets/i18n-C_tQYbyT.js +1 -0
- package/src/client/dist/spa/assets/i18n-zwZDkEfm.js +1 -0
- package/src/client/dist/spa/assets/index-BJT6ZfVp.js +5 -0
- package/src/client/dist/spa/assets/{javascript-C8gxtWJG.js → javascript-CkZZHPRD.js} +1 -1
- package/src/client/dist/spa/assets/{jsonMode-BW-w1oEn.js → jsonMode-CsqbZ0c2.js} +1 -1
- package/src/client/dist/spa/assets/{liquid-CQDlB55c.js → liquid-CB4bbF-9.js} +1 -1
- package/src/client/dist/spa/assets/{marked.esm-CGMwQXW0.js → marked.esm-DIsIySzr.js} +1 -1
- package/src/client/dist/spa/assets/{mdx-DUS2o1l2.js → mdx-goM-jFgd.js} +1 -1
- package/src/client/dist/spa/assets/models-Dwzf2zDK.js +1 -0
- package/src/client/dist/spa/assets/{monaco.contribution-BSsdGujG.js → monaco.contribution-tq8HWx81.js} +2 -2
- package/src/client/dist/spa/assets/{private.use-form-1cZLVjGN.js → private.use-form-BWfHn8G9.js} +1 -1
- package/src/client/dist/spa/assets/{python-DVWLF-An.js → python-BKb3PkXw.js} +1 -1
- package/src/client/dist/spa/assets/{razor-bodgahcD.js → razor-rLKJylZh.js} +1 -1
- package/src/client/dist/spa/assets/scroll-CHtHNzvE.js +1 -0
- package/src/client/dist/spa/assets/settings-BdrDg_dO.js +1 -0
- package/src/client/dist/spa/assets/touch-5Jv2Ep3F.js +1 -0
- package/src/client/dist/spa/assets/{tsMode-C7oNyY1g.js → tsMode-CjX_dUdq.js} +1 -1
- package/src/client/dist/spa/assets/{typescript-C_X20eQu.js → typescript-Bg5NM6yP.js} +1 -1
- package/src/client/dist/spa/assets/{use-checkbox-DwkIkUAc.js → use-checkbox-By4PLtaB.js} +1 -1
- package/src/client/dist/spa/assets/vue-i18n-CFW7O-jl.js +3 -0
- package/src/client/dist/spa/assets/{xml-BVbLd8T0.js → xml-BMWcIRqp.js} +1 -1
- package/src/client/dist/spa/assets/{yaml-D5WOobuH.js → yaml-C2uOvXS0.js} +1 -1
- package/src/client/dist/spa/index.html +7 -7
- package/src/client/dist/spa/assets/ActivityFeed-C7knqOOL.js +0 -10
- package/src/client/dist/spa/assets/CreatePage-Owxm6Tpi.js +0 -2
- package/src/client/dist/spa/assets/CreatePage-y7wOGccu.css +0 -1
- package/src/client/dist/spa/assets/DiffViewer-mLBk-G-D.js +0 -2
- package/src/client/dist/spa/assets/MainLayout-DH5FgF9v.css +0 -1
- package/src/client/dist/spa/assets/QExpansionItem-BoxRv2sW.js +0 -1
- package/src/client/dist/spa/assets/QMenu-DayfIdY0.js +0 -1
- package/src/client/dist/spa/assets/QPage-D7SSe7S1.js +0 -1
- package/src/client/dist/spa/assets/SettingsPage-BzJ9LphQ.js +0 -1
- package/src/client/dist/spa/assets/SettingsPage-ai7Q_1KB.css +0 -1
- package/src/client/dist/spa/assets/WorkspacePage-Dv_vuDsw.js +0 -4
- package/src/client/dist/spa/assets/i18n-NIfrKJms.js +0 -1
- package/src/client/dist/spa/assets/i18n-ckoKODmn.js +0 -1
- package/src/client/dist/spa/assets/index-B4-QwpHI.js +0 -5
- package/src/client/dist/spa/assets/scroll-CWjBCoBR.js +0 -1
- package/src/client/dist/spa/assets/settings-CuK-S6HH.js +0 -1
- package/src/client/dist/spa/assets/touch-Bojc73iM.js +0 -1
- package/src/client/dist/spa/assets/vue-i18n-nv59vAyH.js +0 -3
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ npm install
|
|
|
69
69
|
npm run dev:all
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
This starts the Hono backend on port `
|
|
72
|
+
This starts the Hono backend on port `3300` (via `tsx watch`, with `KOBO_HOME=./data` so dev uses the repo-local data directory and never touches your real `~/.config/kobo/`) and the Quasar dev server on port `8080` concurrently. Open <http://localhost:8080> in your browser.
|
|
73
73
|
|
|
74
74
|
You can run a production-installed Kōbō (`npx @loicngr/kobo`) alongside a dev server without any conflict — they use different data directories by design.
|
|
75
75
|
|
|
@@ -57,6 +57,13 @@ export const migrations = [
|
|
|
57
57
|
`);
|
|
58
58
|
},
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
version: 7,
|
|
62
|
+
name: 'add-reasoning-effort',
|
|
63
|
+
migrate: (db) => {
|
|
64
|
+
db.exec("ALTER TABLE workspaces ADD COLUMN reasoning_effort TEXT NOT NULL DEFAULT 'auto'");
|
|
65
|
+
},
|
|
66
|
+
},
|
|
60
67
|
];
|
|
61
68
|
/** Current schema version — always equals the highest migration version. */
|
|
62
69
|
export const SCHEMA_VERSION = migrations.length > 0 ? migrations[migrations.length - 1].version : 1;
|
package/dist/server/db/schema.js
CHANGED
|
@@ -11,6 +11,7 @@ export function initSchema(db) {
|
|
|
11
11
|
notion_url TEXT,
|
|
12
12
|
notion_page_id TEXT,
|
|
13
13
|
model TEXT NOT NULL DEFAULT 'claude-opus-4-6',
|
|
14
|
+
reasoning_effort TEXT NOT NULL DEFAULT 'auto',
|
|
14
15
|
permission_mode TEXT NOT NULL DEFAULT 'auto-accept',
|
|
15
16
|
dev_server_status TEXT NOT NULL DEFAULT 'stopped',
|
|
16
17
|
has_unread INTEGER NOT NULL DEFAULT 0,
|
package/dist/server/index.js
CHANGED
|
@@ -217,7 +217,7 @@ setMessageHandler((type, payload) => {
|
|
|
217
217
|
const workspace = getWorkspace(p.workspaceId);
|
|
218
218
|
if (workspace) {
|
|
219
219
|
const worktreePath = `${workspace.projectPath}/.worktrees/${workspace.workingBranch}`;
|
|
220
|
-
startAgent(p.workspaceId, worktreePath, p.content, workspace.model, true, workspace.permissionMode, p.sessionId);
|
|
220
|
+
startAgent(p.workspaceId, worktreePath, p.content, workspace.model, true, workspace.permissionMode, p.sessionId, workspace.reasoningEffort);
|
|
221
221
|
updateWorkspaceStatus(p.workspaceId, 'executing');
|
|
222
222
|
}
|
|
223
223
|
}
|
|
@@ -235,7 +235,7 @@ setMessageHandler((type, payload) => {
|
|
|
235
235
|
}
|
|
236
236
|
const worktreePath = `${workspace.projectPath}/.worktrees/${workspace.workingBranch}`;
|
|
237
237
|
const prompt = p.prompt ?? 'Continue the previous task where you left off.';
|
|
238
|
-
startAgent(p.workspaceId, worktreePath, prompt, workspace.model, false, workspace.permissionMode);
|
|
238
|
+
startAgent(p.workspaceId, worktreePath, prompt, workspace.model, false, workspace.permissionMode, undefined, workspace.reasoningEffort);
|
|
239
239
|
}
|
|
240
240
|
catch (err) {
|
|
241
241
|
console.error('[ws] Failed to start agent:', err);
|
|
@@ -24,6 +24,17 @@ app.get('/global', (c) => {
|
|
|
24
24
|
return c.json({ error: message }, 500);
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
|
+
// GET /api/settings/mcp-servers — list active MCP servers from Claude config
|
|
28
|
+
app.get('/mcp-servers', (c) => {
|
|
29
|
+
try {
|
|
30
|
+
const servers = settingsService.listActiveClaudeMcpServers();
|
|
31
|
+
return c.json(servers);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
35
|
+
return c.json({ error: message }, 500);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
27
38
|
// PUT /api/settings/global — update global settings
|
|
28
39
|
app.put('/global', async (c) => {
|
|
29
40
|
try {
|
|
@@ -50,6 +50,7 @@ app.post('/', async (c) => {
|
|
|
50
50
|
notionUrl: body.notionUrl,
|
|
51
51
|
notionPageId: body.notionPageId,
|
|
52
52
|
model: body.model,
|
|
53
|
+
reasoningEffort: body.reasoningEffort,
|
|
53
54
|
permissionMode: body.permissionMode || globalSettings.defaultPermissionMode || 'plan',
|
|
54
55
|
});
|
|
55
56
|
let notionContent = null;
|
|
@@ -410,7 +411,7 @@ app.post('/', async (c) => {
|
|
|
410
411
|
brainstormPrompt += `\nIMPORTANT: Start by reading CLAUDE.md and/or AGENTS.md at the project root if they exist — they contain project conventions and instructions you must follow.`;
|
|
411
412
|
brainstormPrompt += `\n\nThen brainstorm the implementation approach. Explore the codebase to understand the existing structure. Ask clarifying questions if needed. When you're done brainstorming and have a clear plan, create a plan file and proceed with implementation. Once you have completed the brainstorming phase, output [BRAINSTORM_COMPLETE] on its own line.`;
|
|
412
413
|
try {
|
|
413
|
-
const agent = agentManager.startAgent(workspace.id, worktreePath, brainstormPrompt, workspace.model);
|
|
414
|
+
const agent = agentManager.startAgent(workspace.id, worktreePath, brainstormPrompt, workspace.model, false, workspace.permissionMode, undefined, workspace.reasoningEffort);
|
|
414
415
|
// Persist the initial prompt in the feed so it's visible in the chat,
|
|
415
416
|
// tagged with the freshly created session id so the strict session filter shows it.
|
|
416
417
|
wsService.emit(workspace.id, 'user:message', { content: brainstormPrompt, sender: 'system-prompt' }, agent.agentSessionId);
|
|
@@ -759,6 +760,9 @@ app.patch('/:id', async (c) => {
|
|
|
759
760
|
if (body.model !== undefined) {
|
|
760
761
|
updated = workspaceService.updateWorkspaceModel(id, body.model);
|
|
761
762
|
}
|
|
763
|
+
if (body.reasoningEffort !== undefined) {
|
|
764
|
+
updated = workspaceService.updateWorkspaceReasoningEffort(id, body.reasoningEffort);
|
|
765
|
+
}
|
|
762
766
|
if (body.permissionMode !== undefined) {
|
|
763
767
|
const validModes = ['auto-accept', 'plan'];
|
|
764
768
|
if (!validModes.includes(body.permissionMode)) {
|
|
@@ -772,8 +776,12 @@ app.patch('/:id', async (c) => {
|
|
|
772
776
|
if (body.name !== undefined) {
|
|
773
777
|
updated = workspaceService.updateWorkspaceName(id, body.name);
|
|
774
778
|
}
|
|
775
|
-
if (!body.status &&
|
|
776
|
-
|
|
779
|
+
if (!body.status &&
|
|
780
|
+
body.model === undefined &&
|
|
781
|
+
body.reasoningEffort === undefined &&
|
|
782
|
+
body.permissionMode === undefined &&
|
|
783
|
+
body.name === undefined) {
|
|
784
|
+
return c.json({ error: 'Missing field: status, model, reasoningEffort, permissionMode, or name' }, 400);
|
|
777
785
|
}
|
|
778
786
|
return c.json(updated);
|
|
779
787
|
}
|
|
@@ -1011,7 +1019,7 @@ app.post('/:id/start', async (c) => {
|
|
|
1011
1019
|
// Agent may not be running — ignore
|
|
1012
1020
|
}
|
|
1013
1021
|
const worktreePath = `${workspace.projectPath}/.worktrees/${workspace.workingBranch}`;
|
|
1014
|
-
const agent = agentManager.startAgent(id, worktreePath, prompt, workspace.model, resume, workspace.permissionMode, agentSessionId);
|
|
1022
|
+
const agent = agentManager.startAgent(id, worktreePath, prompt, workspace.model, resume, workspace.permissionMode, agentSessionId, workspace.reasoningEffort);
|
|
1015
1023
|
workspaceService.updateWorkspaceStatus(id, 'executing');
|
|
1016
1024
|
// Persist the user prompt so it survives page refresh.
|
|
1017
1025
|
// When agentSessionId is provided (idle-session flow), the prompt was typed
|
|
@@ -1288,7 +1296,7 @@ app.post('/:id/open-pr', async (c) => {
|
|
|
1288
1296
|
// Agent not running — resume it with the PR prompt
|
|
1289
1297
|
try {
|
|
1290
1298
|
const worktreePathForResume = `${workspace.projectPath}/.worktrees/${workspace.workingBranch}`;
|
|
1291
|
-
agentManager.startAgent(workspace.id, worktreePathForResume, rendered, workspace.model, true, workspace.permissionMode);
|
|
1299
|
+
agentManager.startAgent(workspace.id, worktreePathForResume, rendered, workspace.model, true, workspace.permissionMode, undefined, workspace.reasoningEffort);
|
|
1292
1300
|
workspaceService.updateWorkspaceStatus(workspace.id, 'executing');
|
|
1293
1301
|
messageSent = true;
|
|
1294
1302
|
}
|
|
@@ -108,7 +108,7 @@ export function stopWatchdog() {
|
|
|
108
108
|
}
|
|
109
109
|
// ── Start agent ────────────────────────────────────────────────────────────────
|
|
110
110
|
/** Spawn a Claude Code CLI process for a workspace and wire up stdout/stderr/exit handling. */
|
|
111
|
-
export function startAgent(workspaceId, workingDir, prompt, model, resume = false, permissionMode = 'auto-accept', existingSessionId) {
|
|
111
|
+
export function startAgent(workspaceId, workingDir, prompt, model, resume = false, permissionMode = 'auto-accept', existingSessionId, reasoningEffort) {
|
|
112
112
|
// Check if agent already running for this workspace
|
|
113
113
|
if (agents.has(workspaceId)) {
|
|
114
114
|
throw new Error(`Agent already running for workspace '${workspaceId}'`);
|
|
@@ -131,6 +131,9 @@ export function startAgent(workspaceId, workingDir, prompt, model, resume = fals
|
|
|
131
131
|
if (model && model !== 'auto') {
|
|
132
132
|
args.push('--model', model);
|
|
133
133
|
}
|
|
134
|
+
if (reasoningEffort && reasoningEffort !== 'auto') {
|
|
135
|
+
args.push('--effort', reasoningEffort);
|
|
136
|
+
}
|
|
134
137
|
if (resume) {
|
|
135
138
|
// Prefer resuming the specific session requested by the caller (existingSessionId).
|
|
136
139
|
// Otherwise fall back to the most recent session for the workspace.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { callMcpTool, initializeMcp, readClaudeMcpEntry, spawnMcpProcess, unwrapMcpResult, } from '../utils/mcp-client.js';
|
|
2
|
+
import { getGlobalSettings } from './settings-service.js';
|
|
2
3
|
// Gherkin keywords (French and English)
|
|
3
4
|
const GHERKIN_PATTERN = /^(Scénario|Étant donné|Quand|Alors|Scenario|Given|When|Then|Feature|Fonctionnalité|And|Et|But|Mais)/i;
|
|
4
5
|
// Keywords that start a NEW scenario and must flush the current block.
|
|
@@ -34,30 +35,45 @@ export function parseNotionUrl(url) {
|
|
|
34
35
|
* Picks the first enabled `mcpServers` entry named `notion` (disabled entries
|
|
35
36
|
* are skipped). Returns an empty string when none is found.
|
|
36
37
|
*/
|
|
37
|
-
function
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
function readNotionMcpEntryFromClaudeConfig(preferredKey) {
|
|
39
|
+
const normalizedPreferred = preferredKey?.trim();
|
|
40
|
+
const match = normalizedPreferred
|
|
41
|
+
? readClaudeMcpEntry((k) => k === normalizedPreferred)
|
|
42
|
+
: readClaudeMcpEntry((k) => k === 'notion');
|
|
43
|
+
if (!match) {
|
|
44
|
+
if (normalizedPreferred) {
|
|
45
|
+
throw new Error(`Notion MCP key '${normalizedPreferred}' not found or disabled in ~/.claude.json (mcpServers section)`);
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return match;
|
|
43
50
|
}
|
|
44
|
-
function buildNotionMcpConfig() {
|
|
45
|
-
const
|
|
46
|
-
const
|
|
51
|
+
export function buildNotionMcpConfig(preferredKey) {
|
|
52
|
+
const configEntry = readNotionMcpEntryFromClaudeConfig(preferredKey);
|
|
53
|
+
const configEnv = configEntry?.entry.env ?? {};
|
|
54
|
+
const notionToken = process.env.NOTION_API_TOKEN ??
|
|
55
|
+
process.env.NOTION_TOKEN ??
|
|
56
|
+
configEnv.NOTION_TOKEN ??
|
|
57
|
+
configEnv.NOTION_API_TOKEN ??
|
|
58
|
+
'';
|
|
59
|
+
const command = process.env.NOTION_MCP_COMMAND ?? configEntry?.entry.command ?? 'npx';
|
|
47
60
|
const args = process.env.NOTION_MCP_ARGS
|
|
48
61
|
? process.env.NOTION_MCP_ARGS.split(' ')
|
|
49
|
-
: ['-y', '@notionhq/notion-mcp-server'];
|
|
62
|
+
: (configEntry?.entry.args ?? ['-y', '@notionhq/notion-mcp-server']);
|
|
50
63
|
const env = {
|
|
51
64
|
...process.env,
|
|
52
|
-
|
|
65
|
+
...configEnv,
|
|
66
|
+
};
|
|
67
|
+
if (!env.OPENAPI_MCP_HEADERS && notionToken) {
|
|
68
|
+
env.OPENAPI_MCP_HEADERS = JSON.stringify({
|
|
53
69
|
Authorization: `Bearer ${notionToken}`,
|
|
54
70
|
'Notion-Version': '2022-06-28',
|
|
55
|
-
})
|
|
56
|
-
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
57
73
|
return { command, args, env };
|
|
58
74
|
}
|
|
59
|
-
function spawnNotionMcp() {
|
|
60
|
-
const { command, args, env } = buildNotionMcpConfig();
|
|
75
|
+
function spawnNotionMcp(preferredKey) {
|
|
76
|
+
const { command, args, env } = buildNotionMcpConfig(preferredKey);
|
|
61
77
|
return spawnMcpProcess(command, args, env);
|
|
62
78
|
}
|
|
63
79
|
function extractTextFromRichText(richText) {
|
|
@@ -178,7 +194,8 @@ export function parseBlocks(blocks) {
|
|
|
178
194
|
*/
|
|
179
195
|
export async function extractNotionPage(notionUrl) {
|
|
180
196
|
const pageId = parseNotionUrl(notionUrl);
|
|
181
|
-
const
|
|
197
|
+
const global = getGlobalSettings();
|
|
198
|
+
const mcpProcess = spawnNotionMcp(global.notionMcpKey);
|
|
182
199
|
// Give the process a moment to start
|
|
183
200
|
await new Promise((resolve, reject) => {
|
|
184
201
|
const timeout = setTimeout(() => resolve(), 1000);
|
|
@@ -243,7 +260,8 @@ export async function extractNotionPage(notionUrl) {
|
|
|
243
260
|
/** Update a status property on a Notion page. Best-effort, does not throw. */
|
|
244
261
|
export async function updateNotionStatus(notionUrl, propertyName, statusValue) {
|
|
245
262
|
const pageId = parseNotionUrl(notionUrl);
|
|
246
|
-
const
|
|
263
|
+
const global = getGlobalSettings();
|
|
264
|
+
const mcpProcess = spawnNotionMcp(global.notionMcpKey);
|
|
247
265
|
try {
|
|
248
266
|
await new Promise((resolve, reject) => {
|
|
249
267
|
const timeout = setTimeout(() => resolve(), 1000);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { callMcpTool, initializeMcp, readClaudeMcpEntry, spawnMcpProcess, unwrapMcpResult, } from '../utils/mcp-client.js';
|
|
2
|
+
import { getGlobalSettings } from './settings-service.js';
|
|
2
3
|
// ─── parseSentryUrl ───────────────────────────────────────────────────────────
|
|
3
4
|
/**
|
|
4
5
|
* Parse a Sentry issue URL and extract the numeric issue ID.
|
|
@@ -21,8 +22,11 @@ const SENTRY_CONFIG_ERROR = "Sentry MCP server not configured in ~/.claude.json
|
|
|
21
22
|
*
|
|
22
23
|
* Throws with a clear setup message when no enabled Sentry entry exists.
|
|
23
24
|
*/
|
|
24
|
-
export function readSentryMcpConfig() {
|
|
25
|
-
const
|
|
25
|
+
export function readSentryMcpConfig(preferredKey) {
|
|
26
|
+
const normalizedPreferred = preferredKey?.trim();
|
|
27
|
+
const match = normalizedPreferred
|
|
28
|
+
? readClaudeMcpEntry((k) => k === normalizedPreferred)
|
|
29
|
+
: readClaudeMcpEntry((k) => /sentry/i.test(k));
|
|
26
30
|
if (!match) {
|
|
27
31
|
throw new Error(SENTRY_CONFIG_ERROR);
|
|
28
32
|
}
|
|
@@ -104,7 +108,8 @@ export function parseSentryResponse(markdown, numericId) {
|
|
|
104
108
|
*/
|
|
105
109
|
export async function extractSentryIssue(url) {
|
|
106
110
|
const numericId = parseSentryUrl(url);
|
|
107
|
-
const
|
|
111
|
+
const global = getGlobalSettings();
|
|
112
|
+
const config = readSentryMcpConfig(global.sentryMcpKey);
|
|
108
113
|
const mcpProcess = spawnMcpProcess(config.command, config.args, config.env);
|
|
109
114
|
try {
|
|
110
115
|
// Give the process a moment to start; reject if it errors immediately.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { listClaudeMcpEntries } from '../utils/mcp-client.js';
|
|
3
4
|
import { getSettingsPath } from '../utils/paths.js';
|
|
4
5
|
const DEFAULT_GIT_CONVENTIONS = `# Git conventions
|
|
5
6
|
|
|
@@ -125,10 +126,21 @@ const settingsMigrations = [
|
|
|
125
126
|
global.defaultPermissionMode = 'plan';
|
|
126
127
|
},
|
|
127
128
|
},
|
|
129
|
+
{
|
|
130
|
+
version: 7,
|
|
131
|
+
name: 'add-mcp-selection-keys',
|
|
132
|
+
migrate({ global }) {
|
|
133
|
+
if (typeof global.notionMcpKey !== 'string')
|
|
134
|
+
global.notionMcpKey = '';
|
|
135
|
+
if (typeof global.sentryMcpKey !== 'string')
|
|
136
|
+
global.sentryMcpKey = '';
|
|
137
|
+
},
|
|
138
|
+
},
|
|
128
139
|
];
|
|
129
140
|
/** Current settings schema version — always equals the highest migration version. */
|
|
130
141
|
export const SETTINGS_SCHEMA_VERSION = settingsMigrations.length > 0 ? settingsMigrations[settingsMigrations.length - 1].version : 0;
|
|
131
142
|
let settingsFilePath = getSettingsPath();
|
|
143
|
+
let settingsBackupSequence = 0;
|
|
132
144
|
/** Override the settings file path (used by tests). */
|
|
133
145
|
export function _setSettingsPath(p) {
|
|
134
146
|
settingsFilePath = p;
|
|
@@ -147,6 +159,8 @@ function defaultSettings() {
|
|
|
147
159
|
notionStatusProperty: '',
|
|
148
160
|
notionInProgressStatus: '',
|
|
149
161
|
defaultPermissionMode: 'plan',
|
|
162
|
+
notionMcpKey: '',
|
|
163
|
+
sentryMcpKey: '',
|
|
150
164
|
},
|
|
151
165
|
projects: [],
|
|
152
166
|
};
|
|
@@ -221,12 +235,24 @@ function readSettings() {
|
|
|
221
235
|
}
|
|
222
236
|
return migrated;
|
|
223
237
|
}
|
|
224
|
-
function
|
|
238
|
+
function createSettingsBackupIfPresent() {
|
|
239
|
+
if (!fs.existsSync(settingsFilePath))
|
|
240
|
+
return;
|
|
241
|
+
const dir = path.dirname(settingsFilePath);
|
|
242
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
243
|
+
settingsBackupSequence += 1;
|
|
244
|
+
const backupPath = path.join(dir, `settings.json.backup-${stamp}-${settingsBackupSequence}`);
|
|
245
|
+
fs.copyFileSync(settingsFilePath, backupPath);
|
|
246
|
+
}
|
|
247
|
+
function writeSettings(settings, options) {
|
|
225
248
|
const tmpPath = `${settingsFilePath}.tmp`;
|
|
226
249
|
const dir = path.dirname(settingsFilePath);
|
|
227
250
|
if (!fs.existsSync(dir)) {
|
|
228
251
|
fs.mkdirSync(dir, { recursive: true });
|
|
229
252
|
}
|
|
253
|
+
if (options?.backup) {
|
|
254
|
+
createSettingsBackupIfPresent();
|
|
255
|
+
}
|
|
230
256
|
fs.writeFileSync(tmpPath, JSON.stringify(settings, null, 2), 'utf-8');
|
|
231
257
|
fs.renameSync(tmpPath, settingsFilePath);
|
|
232
258
|
}
|
|
@@ -286,10 +312,12 @@ export function updateGlobalSettings(data) {
|
|
|
286
312
|
'notionStatusProperty',
|
|
287
313
|
'notionInProgressStatus',
|
|
288
314
|
'defaultPermissionMode',
|
|
315
|
+
'notionMcpKey',
|
|
316
|
+
'sentryMcpKey',
|
|
289
317
|
];
|
|
290
318
|
const filtered = pickKnownKeys(data, allowedGlobalKeys);
|
|
291
319
|
settings.global = { ...settings.global, ...filtered };
|
|
292
|
-
writeSettings(settings);
|
|
320
|
+
writeSettings(settings, { backup: true });
|
|
293
321
|
return settings.global;
|
|
294
322
|
}
|
|
295
323
|
/** Create or update project-specific settings. Merges devServer fields on update. */
|
|
@@ -336,16 +364,24 @@ export function upsertProject(projectPath, data) {
|
|
|
336
364
|
}
|
|
337
365
|
settings.projects.push(newProject);
|
|
338
366
|
}
|
|
339
|
-
writeSettings(settings);
|
|
367
|
+
writeSettings(settings, { backup: true });
|
|
340
368
|
return settings.projects.find((p) => p.path === projectPath);
|
|
341
369
|
}
|
|
342
370
|
/** Remove a project from the settings file. */
|
|
343
371
|
export function deleteProject(projectPath) {
|
|
344
372
|
const settings = readSettings();
|
|
345
373
|
settings.projects = settings.projects.filter((p) => p.path !== projectPath);
|
|
346
|
-
writeSettings(settings);
|
|
374
|
+
writeSettings(settings, { backup: true });
|
|
347
375
|
}
|
|
348
376
|
/** List all configured projects. */
|
|
349
377
|
export function listProjects() {
|
|
350
378
|
return readSettings().projects;
|
|
351
379
|
}
|
|
380
|
+
/** List active MCP servers from Claude Code config (~/.claude.json). */
|
|
381
|
+
export function listActiveClaudeMcpServers() {
|
|
382
|
+
return listClaudeMcpEntries().map(({ key, entry }) => ({
|
|
383
|
+
key,
|
|
384
|
+
command: entry.command ?? 'npx',
|
|
385
|
+
args: entry.args ?? [],
|
|
386
|
+
}));
|
|
387
|
+
}
|
|
@@ -22,6 +22,7 @@ function mapWorkspace(row) {
|
|
|
22
22
|
notionUrl: row.notion_url,
|
|
23
23
|
notionPageId: row.notion_page_id,
|
|
24
24
|
model: row.model,
|
|
25
|
+
reasoningEffort: row.reasoning_effort ?? 'auto',
|
|
25
26
|
permissionMode: (row.permission_mode ?? 'auto-accept'),
|
|
26
27
|
devServerStatus: row.dev_server_status,
|
|
27
28
|
hasUnread: row.has_unread === 1,
|
|
@@ -48,9 +49,9 @@ export function createWorkspace(data) {
|
|
|
48
49
|
const now = new Date().toISOString();
|
|
49
50
|
const id = nanoid();
|
|
50
51
|
db.prepare(`
|
|
51
|
-
INSERT INTO workspaces (id, name, project_path, source_branch, working_branch, status, notion_url, notion_page_id, model, permission_mode, created_at, updated_at)
|
|
52
|
-
VALUES (?, ?, ?, ?, ?, 'created', ?, ?, ?, ?, ?, ?)
|
|
53
|
-
`).run(id, data.name, data.projectPath, data.sourceBranch, data.workingBranch, data.notionUrl ?? null, data.notionPageId ?? null, data.model ?? 'claude-opus-4-6', data.permissionMode ?? 'auto-accept', now, now);
|
|
52
|
+
INSERT INTO workspaces (id, name, project_path, source_branch, working_branch, status, notion_url, notion_page_id, model, reasoning_effort, permission_mode, created_at, updated_at)
|
|
53
|
+
VALUES (?, ?, ?, ?, ?, 'created', ?, ?, ?, ?, ?, ?, ?)
|
|
54
|
+
`).run(id, data.name, data.projectPath, data.sourceBranch, data.workingBranch, data.notionUrl ?? null, data.notionPageId ?? null, data.model ?? 'claude-opus-4-6', data.reasoningEffort ?? 'auto', data.permissionMode ?? 'auto-accept', now, now);
|
|
54
55
|
return getWorkspace(id);
|
|
55
56
|
}
|
|
56
57
|
/** Fetch a single workspace by ID, or null if not found. */
|
|
@@ -124,6 +125,18 @@ export function updateWorkspaceModel(id, model) {
|
|
|
124
125
|
}
|
|
125
126
|
return getWorkspace(id);
|
|
126
127
|
}
|
|
128
|
+
/** Update the reasoning effort used by a workspace's agent. */
|
|
129
|
+
export function updateWorkspaceReasoningEffort(id, reasoningEffort) {
|
|
130
|
+
const db = getDb();
|
|
131
|
+
const now = new Date().toISOString();
|
|
132
|
+
const result = db
|
|
133
|
+
.prepare('UPDATE workspaces SET reasoning_effort = ?, updated_at = ? WHERE id = ?')
|
|
134
|
+
.run(reasoningEffort, now, id);
|
|
135
|
+
if (result.changes === 0) {
|
|
136
|
+
throw new Error(`Workspace '${id}' not found`);
|
|
137
|
+
}
|
|
138
|
+
return getWorkspace(id);
|
|
139
|
+
}
|
|
127
140
|
/** Update the working branch for a workspace (e.g. after ticket ID injection). */
|
|
128
141
|
export function updateWorkingBranch(id, workingBranch) {
|
|
129
142
|
const db = getDb();
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { getPackageVersion } from './paths.js';
|
|
4
|
+
function getClaudeConfigPath() {
|
|
5
|
+
const homedir = process.env.HOME ?? process.env.USERPROFILE ?? '';
|
|
6
|
+
return `${homedir}/.claude.json`;
|
|
7
|
+
}
|
|
8
|
+
function readClaudeConfig() {
|
|
9
|
+
try {
|
|
10
|
+
const raw = readFileSync(getClaudeConfigPath(), 'utf-8');
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
4
17
|
/**
|
|
5
18
|
* Read `~/.claude.json` and return the first `mcpServers` entry whose key
|
|
6
19
|
* matches the predicate AND is not disabled (`disabled !== true`).
|
|
@@ -10,20 +23,27 @@ import { getPackageVersion } from './paths.js';
|
|
|
10
23
|
* (Notion, Sentry, …) picks entries by the same rule.
|
|
11
24
|
*/
|
|
12
25
|
export function readClaudeMcpEntry(match) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
const raw = readFileSync(configPath, 'utf-8');
|
|
17
|
-
const config = JSON.parse(raw);
|
|
18
|
-
const servers = config.mcpServers ?? {};
|
|
19
|
-
const key = Object.keys(servers).find((k) => match(k) && servers[k].disabled !== true);
|
|
20
|
-
if (!key)
|
|
21
|
-
return null;
|
|
22
|
-
return { key, entry: servers[key] };
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
26
|
+
const config = readClaudeConfig();
|
|
27
|
+
if (!config)
|
|
25
28
|
return null;
|
|
26
|
-
}
|
|
29
|
+
const servers = config.mcpServers ?? {};
|
|
30
|
+
const key = Object.keys(servers).find((k) => match(k) && servers[k].disabled !== true);
|
|
31
|
+
if (!key)
|
|
32
|
+
return null;
|
|
33
|
+
return { key, entry: servers[key] };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read all enabled MCP entries from `~/.claude.json`.
|
|
37
|
+
* Disabled entries (`disabled === true`) are excluded.
|
|
38
|
+
*/
|
|
39
|
+
export function listClaudeMcpEntries() {
|
|
40
|
+
const config = readClaudeConfig();
|
|
41
|
+
if (!config)
|
|
42
|
+
return [];
|
|
43
|
+
const servers = config.mcpServers ?? {};
|
|
44
|
+
return Object.keys(servers)
|
|
45
|
+
.filter((key) => servers[key].disabled !== true)
|
|
46
|
+
.map((key) => ({ key, entry: servers[key] }));
|
|
27
47
|
}
|
|
28
48
|
const nextRpcId = (() => {
|
|
29
49
|
let counter = 1;
|
|
@@ -28,8 +28,16 @@ export function getPackageAssetPath(...parts) {
|
|
|
28
28
|
*
|
|
29
29
|
* Dev workflow: `npm run dev` sets KOBO_HOME=./data so local development uses
|
|
30
30
|
* the repo-relative data/ directory and never touches the user's real home.
|
|
31
|
+
* For stricter isolation, set KOBO_ENFORCE_LOCAL_HOME=1 to force local writes
|
|
32
|
+
* to either KOBO_HOME (if provided) or <packageRoot>/data.
|
|
31
33
|
*/
|
|
32
34
|
export function getKoboHome() {
|
|
35
|
+
if (process.env.KOBO_ENFORCE_LOCAL_HOME === '1') {
|
|
36
|
+
if (process.env.KOBO_HOME) {
|
|
37
|
+
return path.resolve(process.env.KOBO_HOME);
|
|
38
|
+
}
|
|
39
|
+
return getPackageAssetPath('data');
|
|
40
|
+
}
|
|
33
41
|
if (process.env.KOBO_HOME) {
|
|
34
42
|
return path.resolve(process.env.KOBO_HOME);
|
|
35
43
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loicngr/kobo",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.5",
|
|
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",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"node": ">=20"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
|
-
"dev": "KOBO_HOME=./data tsx watch src/server/index.ts",
|
|
51
|
-
"dev:client": "cd src/client && npx quasar dev",
|
|
50
|
+
"dev": "KOBO_ENFORCE_LOCAL_HOME=1 KOBO_HOME=./data PORT=3300 tsx watch src/server/index.ts",
|
|
51
|
+
"dev:client": "cd src/client && KOBO_BACKEND_PORT=3300 npx quasar dev",
|
|
52
52
|
"dev:all": "concurrently \"npm run dev\" \"npm run dev:client\"",
|
|
53
53
|
"build:client": "cd src/client && npx quasar build",
|
|
54
54
|
"build:server": "npx tsc && chmod +x dist/server/index.js",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{$ as e,D as t,I as n,N as r,P as i,R as a,U as o,W as s,_ as c,a as l,d as u,f as d,g as f,it as ee,m as p,n as te,p as m,u as h,vt as g,xt as _,y as ne}from"./vue-i18n-CFW7O-jl.js";import{L as v,T as y,bt as re}from"./scroll-CHtHNzvE.js";import{E as ie,O as ae}from"./index-BJT6ZfVp.js";import{t as b}from"./QSpinnerDots-DytntAbf.js";import{n as x,p as S,t as C}from"./_plugin-vue_export-helper-DkL3SKZ8.js";import{n as oe,t as se}from"./marked.esm-DIsIySzr.js";var ce={key:0,class:`af-empty column items-center justify-center text-center q-pa-xl`},le={class:`text-grey-6 q-mt-md text-body2`},ue={class:`text-grey-8 text-caption q-mt-xs`},de={key:1,class:`row justify-center q-my-sm`},fe=[`data-item-id`],pe={class:`af-tool row items-center q-gutter-xs`},me={class:`af-tool-label text-indigo-4`},he={class:`af-time`},ge={key:0,class:`text-grey-4 q-mb-xs`},_e={class:`af-ask-options-list q-mb-sm`},ve={class:`text-weight-bold text-grey-3`},ye={key:0},be={key:1,class:`af-ask-buttons q-gutter-xs`},xe={key:0,class:`q-mt-sm row justify-end`},Se=[`onClick`],Ce={class:`af-file-header row items-center no-wrap q-gutter-xs`},we={class:`af-file-path text-grey-4 ellipsis`},Te={class:`af-diff-stats`},Ee={key:0,class:`text-green-5`},De={key:1,class:`text-red-5 q-ml-xs`},Oe={class:`af-time`},ke={class:`af-diff-sign`},Ae={key:1,class:`af-diff-line af-diff-del`},je={key:0,class:`af-diff-line text-grey-7 text-italic`},Me=[`onClick`],Ne={class:`af-tool-label text-grey-7`},Pe={key:0,class:`af-tool-desc text-grey-8`},Fe={class:`af-time`},Ie={key:0,class:`af-tool-args q-mt-xs rounded-borders`},Le={class:`af-args-pre`},Re={class:`af-text-header row items-center q-mb-xs`},ze={class:`af-time`},Be=[`innerHTML`],Ve=[`onClick`],He={class:`af-system-content text-caption text-amber-6`},Ue={class:`af-time`},We={key:0,class:`af-system-details q-mt-xs rounded-borders`},Ge={class:`af-args-pre`},Ke={key:5,class:`row items-center`},qe={class:`af-error-content text-red-5`},Je={class:`af-time`},Ye={key:6,class:`row items-center`},Xe={class:`af-raw-content text-grey-7`},Ze={class:`af-time`},Qe={class:`scroll-buttons`},w=50,$e=50,T=C(ne({__name:`ActivityFeed`,setup(ne){function C(e){let t=se.parse(e,{async:!1,breaks:!0,gfm:!0});return oe.sanitize(t)}let{t:T}=te(),E=ae(),et=ie(),D=e(null),O=e(!1),k=e(new Set),A=new Map;function j(e,t){return A.has(e)||A.set(e,Y(t)),A.get(e)}let M=new Map;function tt(e,t){return M.has(e)||M.set(e,C(t)),M.get(e)}let N=h(()=>{let e=E.activityFeed;for(let t=e.length-1;t>=0;t--){let n=e[t];if(n.meta?.sender===`user`)return null;if(n.type===`tool_use`&&n.content===`AskUserQuestion`)return n.id}return null}),P=e(new Map);function nt(e,t,n){P.value.has(e)||P.value.set(e,new Map);let r=P.value.get(e);r.get(t)===n?r.delete(t):r.set(t,n)}function F(e,t,n){return P.value.get(e)?.get(t)===n}function rt(e){let t=P.value.get(e);return!!t&&t.size>0}function it(e,t){let n=E.selectedWorkspaceId;if(!n)return;let r=P.value.get(e);if(!r||r.size===0)return;let i=[];for(let[e,n]of r.entries()){let r=t[e];if(!r)continue;let a=r.options[n];a&&i.push(`${r.question}: ${a.label}`)}i.length>0&&et.sendChatMessage(n,i.join(`
|
|
2
|
+
`))}let I=e(-1);function at(){let e=E.activityFeed,n=e.map((e,t)=>({item:e,idx:t})).filter(({item:e})=>e.meta?.sender===`user`);if(n.length===0)return;I.value<=0?I.value=n.length-1:I.value--;let r=n[I.value].idx,i=n[I.value].item.id,a=e.length-r;a>L.value&&(L.value=Math.min(a+10,e.length)),t(()=>{let e=D.value?.querySelector(`[data-item-id="${i}"]`);e&&e.scrollIntoView({behavior:`smooth`,block:`center`})})}o(()=>E.selectedWorkspaceId,()=>{I.value=-1,A.clear(),P.value.clear(),M.clear(),W.clear(),B=0,O.value=!1});let L=e(w),R=h(()=>{let e=E.activityFeed;return e.length<=L.value?e:e.slice(-L.value)});o(()=>E.selectedWorkspaceId,()=>{L.value=w}),o(R,e=>{let t=new Set(e.map(e=>e.id));for(let e of A.keys())t.has(e)||A.delete(e);for(let e of P.value.keys())t.has(e)||P.value.delete(e);for(let e of M.keys())t.has(e)||M.delete(e);for(let e of W.keys())t.has(e)||W.delete(e)},{flush:`post`});let z=e(!1),B=0;function V(){let e=D.value;if(e&&(e.scrollHeight-e.scrollTop-e.clientHeight<50?z.value=!1:e.scrollTop<B&&(z.value=!0),B=e.scrollTop,e.scrollTop<200&&!O.value)){let n=E.activityFeed.length;if(L.value<n){O.value=!0;let r=e.scrollHeight;L.value=Math.min(L.value+$e,n),t(()=>{D.value&&(D.value.scrollTop+=D.value.scrollHeight-r),O.value=!1})}else if(E.selectedWorkspaceId&&E.hasMoreEvents[E.selectedWorkspaceId]!==!1){O.value=!0;let n=e.scrollHeight;E.fetchOlderEvents(E.selectedWorkspaceId).then(e=>{e?(L.value=E.activityFeed.length,t(()=>{D.value&&(D.value.scrollTop+=D.value.scrollHeight-n),O.value=!1})):O.value=!1})}}}function H(){if(z.value)return;let e=D.value;e&&(e.scrollTop=e.scrollHeight)}function ot(){z.value=!1,L.value=w,t(()=>{let e=D.value;e&&(e.scrollTop=e.scrollHeight)})}o(()=>E.activityFeed.length,()=>{t(H)}),r(()=>{D.value?.addEventListener(`scroll`,V),t(H)}),i(()=>{D.value?.removeEventListener(`scroll`,V)});function U(e){return new Date(e).toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`})}function st(e,t){let n=e.split(`
|
|
3
|
+
`),r=t.split(`
|
|
4
|
+
`),i=n.length,a=r.length,o=Array.from({length:i+1},()=>Array(a+1).fill(0));for(let e=i-1;e>=0;e--)for(let t=a-1;t>=0;t--)n[e]===r[t]?o[e][t]=o[e+1][t+1]+1:o[e][t]=Math.max(o[e+1][t],o[e][t+1]);let s=[],c=0,l=0;for(;c<i&&l<a;)n[c]===r[l]?(s.push({type:`context`,content:n[c]}),c++,l++):o[c+1][l]>=o[c][l+1]?(s.push({type:`del`,content:n[c]}),c++):(s.push({type:`add`,content:r[l]}),l++);for(;c<i;)s.push({type:`del`,content:n[c++]});for(;l<a;)s.push({type:`add`,content:r[l++]});return s}let W=new Map;function ct(e,t,n){return W.has(e)||W.set(e,st(t,n)),W.get(e)}function G(e){if(e.type!==`tool_use`)return null;let t=e.meta?.input;if(e.content===`Edit`){if(!t?.file_path)return null;let e=t.file_path,n=t.old_string??``,r=t.new_string??``,i=n.split(`
|
|
5
|
+
`),a=r.split(`
|
|
6
|
+
`);return{toolName:`Edit`,filePath:e,oldString:n,newString:r,replaceAll:t.replace_all??!1,additions:a.length,deletions:i.length}}if(e.content===`Write`){if(!t?.file_path)return null;let e=t.file_path,n=t.content??``;return{toolName:`Write`,filePath:e,content:n,additions:n.split(`
|
|
7
|
+
`).length,deletions:0}}if(e.content===`Bash`){let e=(t?.command??``).match(/^\s*rm\s+(?:-[a-zA-Z]*\s+)*(.+)/);if(e)return{toolName:`Bash:rm`,filePath:e[1].trim().replace(/["']/g,``),additions:0,deletions:1}}return null}function K(e){let t=E.selectedWorkspace;if(t){let n=`${t.projectPath}/.worktrees/${t.workingBranch}/`;if(e.startsWith(n))return e.slice(n.length);if(e.startsWith(`${t.projectPath}/`))return e.slice(t.projectPath.length+1)}return e.startsWith(`/`)&&e.split(`/`).length>4?`…/${e.split(`/`).slice(-3).join(`/`)}`:e}function lt(e){return e.split(`/`).pop()??e}function q(e){let t=lt(e),n=t.lastIndexOf(`.`);return n>=0?t.substring(n+1):``}function ut(e){return{ts:`JS`,tsx:`TS`,js:`JS`,jsx:`JS`,vue:`VU`,py:`PY`,rs:`RS`,go:`GO`,java:`JA`,php:`PH`,css:`CS`,scss:`SC`,html:`HT`,md:`MD`,json:`JS`,sql:`SQ`,sh:`SH`,yaml:`YA`,yml:`YA`,toml:`TM`}[e.toLowerCase()]??e.substring(0,2).toUpperCase()}function dt(e){return{ts:`blue-5`,tsx:`blue-5`,js:`yellow-8`,jsx:`yellow-8`,vue:`green-5`,py:`blue-4`,rs:`orange-5`,go:`cyan-5`,java:`red-5`,php:`indigo-4`,css:`purple-4`,scss:`pink-4`,html:`orange-4`,md:`grey-5`,json:`yellow-6`}[e.toLowerCase()]??`grey-5`}function ft(e){let t=e.toLowerCase();return t.includes(`read`)||t.includes(`grep`)||t.includes(`glob`)?`search`:t.includes(`write`)||t.includes(`edit`)?`edit`:t.includes(`bash`)||t.includes(`terminal`)?`terminal`:t.includes(`agent`)||t.includes(`task`)?`smart_toy`:`build`}function pt(e){switch(e.type){case`text`:return e.meta?.sender===`system-prompt`?`af-item--prompt`:e.meta?.sender===`user`?`af-item--user`:`af-item--text`;case`system`:return`af-item--system`;case`error`:return`af-item--error`;case`tool_use`:return`af-item--tool`;case`raw`:return`af-item--raw`;default:return``}}function mt(e){switch(e.meta?.sender){case`system-prompt`:return T(`activityFeed.initialPrompt`);case`user`:return T(`activityFeed.you`);default:return T(`activityFeed.agent`)}}function ht(e){switch(e.meta?.sender){case`system-prompt`:return`text-indigo-4`;case`user`:return`text-green-4`;default:return`text-blue-4`}}function gt(e){if(e.content===`Skill`&&e.meta){let t=e.meta.input;if(t&&typeof t.skill==`string`)return`Skill — ${t.skill}`}return e.content}function J(e){if(!e.meta)return``;let t=e.meta.input;if(!t)return``;if(typeof t.description==`string`)return t.description;if(typeof t.file_path==`string`)return K(t.file_path);if(typeof t.pattern==`string`)return`${typeof t.path==`string`?`${K(t.path)}/`:``}${t.pattern}`;if(typeof t.path==`string`)return K(t.path);if(typeof t.command==`string`){let e=t.command;return e.length>80?`${e.slice(0,80)}…`:e}return``}function Y(e){if(e.type!==`tool_use`||e.content!==`AskUserQuestion`)return null;let t=e.meta?.input;return!t?.questions||!Array.isArray(t.questions)?null:t.questions.filter(e=>Array.isArray(e.options)&&e.options.length>0).map(e=>({question:e.question??``,options:e.options.map(e=>({label:e.label??``,description:e.description??``}))}))}function X(e){if(!e.meta)return!1;let t=e.meta;return t.input!==void 0&&t.input!==null}function Z(e){k.value.has(e)?k.value.delete(e):k.value.add(e)}function Q(e){return k.value.has(e)}function _t(e){if(!e.meta)return``;let t=e.meta;if(!t.input)return``;try{return JSON.stringify(t.input,null,2)}catch{return String(t.input)}}let vt=h(()=>E.activityFeed.some(e=>e.meta?.sender===`user`));function $(e){return e.type!==`system`||!e.meta?!1:Object.keys(e.meta).length>0}function yt(e){if(!e.meta)return``;try{return JSON.stringify(e.meta,null,2)}catch{return``}}return(e,t)=>(n(),p(`div`,{ref_key:`feedContainer`,ref:D,class:`activity-feed q-pa-sm`},[ee(E).activityFeed.length===0?(n(),p(`div`,ce,[c(v,{name:`forum`,size:`48px`,color:`grey-8`}),u(`div`,le,_(e.$t(`activityFeed.empty`)),1),u(`div`,ue,_(e.$t(`activityFeed.emptyHint`)),1)])):m(``,!0),O.value?(n(),p(`div`,de,[c(b,{size:`24px`,color:`grey-6`})])):m(``,!0),(n(!0),p(l,null,a(R.value,r=>(n(),p(`div`,{key:r.id,"data-item-id":r.id,class:g([`af-item text-caption rounded-borders`,pt(r)])},[r.type===`tool_use`&&j(r.id,r)?(n(),p(l,{key:0},[u(`div`,pe,[c(v,{name:`help_outline`,size:`14px`,color:`indigo-4`}),u(`span`,me,_(e.$t(`activityFeed.question`)),1),c(S),u(`span`,he,_(U(r.timestamp)),1)]),(n(!0),p(l,null,a(j(r.id,r),(e,t)=>(n(),p(`div`,{key:t,class:`q-mt-sm`},[e.question?(n(),p(`div`,ge,_(e.question),1)):m(``,!0),u(`div`,_e,[(n(!0),p(l,null,a(e.options,(e,t)=>(n(),p(`div`,{key:t,class:`af-ask-option-item text-caption text-grey-5`},[u(`span`,ve,_(t+1)+`. `+_(e.label),1),e.description?(n(),p(`span`,ye,` — `+_(e.description),1)):m(``,!0)]))),128))]),r.id===N.value?(n(),p(`div`,be,[(n(!0),p(l,null,a(e.options,(e,i)=>(n(),d(y,{key:e.label,"no-caps":``,dense:``,outline:!F(r.id,t,i),unelevated:F(r.id,t,i),color:F(r.id,t,i)?`indigo-6`:`indigo-4`,"text-color":F(r.id,t,i)?`white`:void 0,class:`af-option-btn`,onClick:e=>nt(r.id,t,i)},{default:s(()=>[f(_(e.label),1)]),_:2},1032,[`outline`,`unelevated`,`color`,`text-color`,`onClick`]))),128))])):m(``,!0)]))),128)),r.id===N.value?(n(),p(`div`,xe,[c(y,{"no-caps":``,unelevated:``,dense:``,color:`indigo-6`,label:e.$t(`activityFeed.sendAnswers`),icon:`send`,disable:!rt(r.id),onClick:e=>it(r.id,j(r.id,r))},null,8,[`label`,`disable`,`onClick`])])):m(``,!0)],64)):r.type===`tool_use`&&G(r)?(n(),p(`div`,{key:1,class:`af-file-change cursor-pointer`,onClick:e=>Z(r.id)},[u(`div`,Ce,[u(`span`,{class:g([`af-lang-badge`,`text-${dt(q(G(r).filePath))}`])},_(ut(q(G(r).filePath))),3),u(`span`,we,_(K(G(r).filePath)),1),u(`span`,Te,[G(r).additions?(n(),p(`span`,Ee,`+`+_(G(r).additions),1)):m(``,!0),G(r).deletions?(n(),p(`span`,De,`-`+_(G(r).deletions),1)):m(``,!0)]),c(v,{name:Q(r.id)?`expand_less`:`expand_more`,size:`14px`,color:`grey-6`},null,8,[`name`]),c(S),u(`span`,Oe,_(U(r.timestamp)),1)]),Q(r.id)?(n(),p(`div`,{key:0,class:`af-diff-body q-mt-xs`,onClick:t[0]||=re(()=>{},[`stop`])},[G(r).toolName===`Edit`?(n(!0),p(l,{key:0},a(ct(r.id,G(r).oldString??``,G(r).newString??``),(e,t)=>(n(),p(`div`,{key:t,class:g([`af-diff-line`,{"af-diff-del":e.type===`del`,"af-diff-add":e.type===`add`,"af-diff-context":e.type===`context`}])},[u(`span`,ke,_(e.type===`del`?`-`:e.type===`add`?`+`:` `),1),f(_(e.content),1)],2))),128)):G(r).toolName===`Bash:rm`?(n(),p(`div`,Ae,[...t[1]||=[u(`span`,{class:`af-diff-sign`},`-`,-1),f(`File deleted`,-1)]])):(n(),p(l,{key:2},[(n(!0),p(l,null,a((G(r).content??``).split(`
|
|
8
|
+
`).slice(0,30),(e,r)=>(n(),p(`div`,{key:`w-${r}`,class:`af-diff-line af-diff-add`},[t[2]||=u(`span`,{class:`af-diff-sign`},`+`,-1),f(_(e),1)]))),128)),(G(r).content??``).split(`
|
|
9
|
+
`).length>30?(n(),p(`div`,je,`… `+_((G(r).content??``).split(`
|
|
10
|
+
`).length-30)+` more lines`,1)):m(``,!0)],64))])):m(``,!0)],8,Se)):r.type===`tool_use`?(n(),p(l,{key:2},[u(`div`,{class:g([`af-tool row items-center q-gutter-xs`,{"cursor-pointer":X(r)}]),onClick:e=>X(r)&&Z(r.id)},[c(v,{name:ft(r.content),size:`14px`,color:`grey-6`},null,8,[`name`]),u(`span`,Ne,_(gt(r)),1),J(r)?(n(),p(`span`,Pe,`— `+_(J(r)),1)):m(``,!0),X(r)?(n(),d(v,{key:1,name:Q(r.id)?`expand_less`:`expand_more`,size:`14px`,color:`grey-7`},null,8,[`name`])):m(``,!0),c(S),u(`span`,Fe,_(U(r.timestamp)),1)],10,Me),Q(r.id)?(n(),p(`div`,Ie,[u(`pre`,Le,_(_t(r)),1)])):m(``,!0)],64)):r.type===`text`?(n(),p(l,{key:3},[u(`div`,Re,[u(`span`,{class:g([`text-caption text-weight-bold`,ht(r)])},_(mt(r)),3),r.meta?.pending?(n(),d(b,{key:0,size:`14px`,color:`grey-5`,class:`q-ml-sm`})):m(``,!0),c(S),u(`span`,ze,_(U(r.timestamp)),1)]),u(`div`,{class:`af-text-content af-markdown`,innerHTML:tt(r.id,r.content)},null,8,Be)],64)):r.type===`system`?(n(),p(l,{key:4},[u(`div`,{class:g([`row items-center`,{"cursor-pointer":$(r)}]),onClick:e=>$(r)&&Z(r.id)},[c(v,{name:`info`,size:`14px`,color:`amber-6`,class:`q-mr-xs`}),u(`span`,He,_(r.content),1),$(r)?(n(),d(v,{key:0,name:Q(r.id)?`expand_less`:`expand_more`,size:`14px`,color:`amber-8`,class:`q-ml-xs`},null,8,[`name`])):m(``,!0),c(S),u(`span`,Ue,_(U(r.timestamp)),1)],10,Ve),Q(r.id)&&$(r)?(n(),p(`div`,We,[u(`pre`,Ge,_(yt(r)),1)])):m(``,!0)],64)):r.type===`error`?(n(),p(`div`,Ke,[c(v,{name:`error`,size:`14px`,color:`red-5`,class:`q-mr-xs`}),u(`span`,qe,_(r.content),1),c(S),u(`span`,Je,_(U(r.timestamp)),1)])):(n(),p(`div`,Ye,[u(`span`,Xe,_(r.content),1),c(S),u(`span`,Ze,_(U(r.timestamp)),1)]))],10,fe))),128)),u(`div`,Qe,[vt.value?(n(),d(y,{key:0,round:``,dense:``,size:`sm`,icon:`person_search`,color:`indigo-8`,class:`scroll-btn`,onClick:at},{default:s(()=>[c(x,null,{default:s(()=>[f(_(e.$t(`activityFeed.goToPrevious`)),1)]),_:1})]),_:1})):m(``,!0),z.value?(n(),d(y,{key:1,round:``,dense:``,size:`sm`,icon:`keyboard_double_arrow_down`,color:`indigo-8`,class:`scroll-btn`,onClick:ot},{default:s(()=>[c(x,null,{default:s(()=>[f(_(e.$t(`activityFeed.scrollToBottom`)),1)]),_:1})]),_:1})):m(``,!0)])],512))}}),[[`__scopeId`,`data-v-c5b7e063`]]);export{T as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{J as e,d as t,f as n,lt as r}from"./scroll-
|
|
1
|
+
import{J as e,d as t,f as n,lt as r}from"./scroll-CHtHNzvE.js";function i(e){if(e===!1)return 0;if(e===!0||e===void 0)return 1;let t=parseInt(e,10);return isNaN(t)?0:t}var a=r({name:`close-popup`,beforeMount(r,{value:a}){let o={depth:i(a),handler(e){o.depth!==0&&setTimeout(()=>{let i=n(r);i!==void 0&&t(i,e,o.depth)})},handlerKey(t){e(t,13)===!0&&o.handler(t)}};r.__qclosepopup=o,r.addEventListener(`click`,o.handler),r.addEventListener(`keyup`,o.handlerKey)},updated(e,{value:t,oldValue:n}){t!==n&&(e.__qclosepopup.depth=i(t))},beforeUnmount(e){let t=e.__qclosepopup;e.removeEventListener(`click`,t.handler),e.removeEventListener(`keyup`,t.handlerKey),delete e.__qclosepopup}});export{a as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.create-page[data-v-9808a4a1]{background-color:#1a1a2e;min-height:100%;padding:48px 24px}.create-inner[data-v-9808a4a1]{width:100%;max-width:700px}.create-title[data-v-9808a4a1]{font-size:24px;line-height:1.3}.create-card[data-v-9808a4a1]{background:#224;border:1px solid #444;overflow:hidden}.card-top-bar[data-v-9808a4a1]{background:#1e1e3a;min-height:36px}.card-name-wrap[data-v-9808a4a1]{background:#224;padding:8px 16px 4px}.card-name-wrap[data-v-9808a4a1] .q-field__control{height:32px;min-height:32px;padding:0}.card-name-wrap[data-v-9808a4a1] input{color:#e0e0e0;font-size:15px;font-weight:500}.card-name-wrap[data-v-9808a4a1] input::placeholder{color:#555}.card-textarea-wrap[data-v-9808a4a1]{background:#224}.repo-select[data-v-9808a4a1]{min-width:160px;max-width:260px}.repo-select[data-v-9808a4a1] .q-field__prepend{align-items:center;height:auto;padding-top:0}.create-textarea[data-v-9808a4a1]{color:#d0d0d0;width:100%;padding:12px 16px 4px}.create-textarea[data-v-9808a4a1] .q-field__control{padding:0}.create-textarea[data-v-9808a4a1] textarea{color:#d0d0d0;resize:none;min-height:100px;font-size:14px;line-height:1.6}.create-textarea[data-v-9808a4a1] textarea::placeholder{color:#666}.notion-toggle-btn[data-v-9808a4a1]{background:#333;padding:2px 10px}.notion-url-wrap[data-v-9808a4a1]{background:#1e1e3a;padding:8px 0 0}.notion-url-input[data-v-9808a4a1]{padding:0 12px}.notion-url-input[data-v-9808a4a1] .q-field__control{height:36px;min-height:36px;padding:0}.notion-url-input[data-v-9808a4a1] input{color:#d0d0d0;font-size:13px}.notion-url-input[data-v-9808a4a1] input::placeholder{color:#555;font-size:12px}.notion-error[data-v-9808a4a1],.notion-valid[data-v-9808a4a1]{padding-bottom:6px}.sentry-toggle-btn[data-v-9808a4a1]{background:#333;padding:2px 10px}.sentry-url-wrap[data-v-9808a4a1]{background:#1e1e3a;padding:8px 0 0}.sentry-url-input[data-v-9808a4a1]{padding:0 12px}.sentry-url-input[data-v-9808a4a1] .q-field__control{height:36px;min-height:36px;padding:0}.sentry-url-input[data-v-9808a4a1] input{color:#d0d0d0;font-size:13px}.sentry-url-input[data-v-9808a4a1] input::placeholder{color:#555;font-size:12px}.sentry-error[data-v-9808a4a1],.sentry-valid[data-v-9808a4a1]{padding-bottom:6px}.slide-enter-active[data-v-9808a4a1],.slide-leave-active[data-v-9808a4a1]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-9808a4a1],.slide-leave-to[data-v-9808a4a1]{opacity:0;max-height:0}.slide-enter-to[data-v-9808a4a1],.slide-leave-from[data-v-9808a4a1]{opacity:1;max-height:120px}.card-bottom-bar[data-v-9808a4a1]{background:#1e1e3a;min-height:40px}.bottom-select[data-v-9808a4a1]{background:#333;min-width:60px;height:28px;padding:0 6px}.bottom-select[data-v-9808a4a1] .q-field__control{height:28px;min-height:28px;padding:0}.bottom-select[data-v-9808a4a1] .q-field__native{min-height:unset;padding:0}.bottom-select-label[data-v-9808a4a1]{color:#bbb;gap:2px;font-size:11px}.bottom-sep[data-v-9808a4a1]{color:#555;padding:0 2px;font-size:12px;line-height:1}.repo-path-wrap[data-v-9808a4a1]{background:#333;border-radius:6px;height:28px;padding:0 8px}.repo-input[data-v-9808a4a1]{min-width:140px}.repo-input[data-v-9808a4a1] .q-field__control{height:28px;min-height:28px;padding:0}.repo-input[data-v-9808a4a1] input{color:#bbb;font-size:11px}.repo-input[data-v-9808a4a1] input::placeholder{color:#666;font-size:11px}.branch-select[data-v-9808a4a1]{min-width:80px}.create-btn[data-v-9808a4a1]{color:#fff;background:#4f46e5;height:28px;padding:0 14px;font-size:12px}.create-btn[data-v-9808a4a1] .q-btn__content{height:28px}.create-hint[data-v-9808a4a1]{line-height:1.5}.fade-enter-active[data-v-9808a4a1],.fade-leave-active[data-v-9808a4a1]{transition:opacity .2s}.fade-enter-from[data-v-9808a4a1],.fade-leave-to[data-v-9808a4a1]{opacity:0}.manual-hint[data-v-9808a4a1]{background:#1e1e3a;line-height:1.4}.manual-expansion[data-v-9808a4a1]{background:#1e1e3a;border:1px solid #333;border-radius:4px;margin-top:6px;overflow:hidden}.manual-expansion[data-v-9808a4a1] .manual-expansion-header{min-height:32px;padding:4px 10px;font-size:12px}.manual-expansion[data-v-9808a4a1] .q-expansion-item__content,.manual-section-body[data-v-9808a4a1]{background:#1a1a2e}.manual-input[data-v-9808a4a1] .q-field__control{height:26px;min-height:26px;padding:0}.manual-input[data-v-9808a4a1] input{color:#e0e0e0;font-size:12px}.manual-input[data-v-9808a4a1] input::placeholder{color:#555}.manual-item[data-v-9808a4a1]{border-top:1px solid #ffffff0a}.manual-item[data-v-9808a4a1]:first-child{border-top:none}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{$ as e,E as t,I as n,N as r,P as i,R as ee,S as te,U as ne,W as a,_ as o,a as s,d as c,f as l,g as u,it as re,m as d,n as ie,p as f,u as p,xt as m,y as ae,yt as oe}from"./vue-i18n-CFW7O-jl.js";import{L as h,T as g,bt as _,ht as se,yt as v}from"./scroll-CHtHNzvE.js";import{i as y}from"./private.use-form-BWfHn8G9.js";import{t as ce}from"./settings-BdrDg_dO.js";import{E as le,O as ue,r as b,w as de}from"./index-BJT6ZfVp.js";import{n as x,p as fe,t as pe}from"./_plugin-vue_export-helper-DkL3SKZ8.js";import{a as me,i as S,n as C,r as w}from"./QMenu-DDXq2SFM.js";import{t as he}from"./QExpansionItem-ZAI_l6AW.js";import{n as ge,r as T,t as _e}from"./models-Dwzf2zDK.js";var ve={class:`create-inner`},ye={class:`create-title text-center text-weight-bold q-mb-lg text-grey-3`},be={class:`create-card rounded-borders`},xe={class:`card-top-bar row items-center q-px-md q-py-xs`},Se={class:`model-badge cursor-default row items-center q-gutter-xs`},Ce={class:`text-indigo-3 text-weight-medium text-caption`},we={key:0,class:`notion-url-wrap`},Te={key:0,class:`notion-error text-caption q-px-md q-pb-xs text-red-5`},Ee={key:1,class:`notion-valid text-caption q-px-md q-pb-xs text-green-4`},De={key:0,class:`sentry-url-wrap`},Oe={key:0,class:`sentry-error text-caption q-px-md q-pb-xs text-red-5`},ke={key:1,class:`sentry-valid text-caption q-px-md q-pb-xs text-red-4`},Ae={class:`card-name-wrap`},je={class:`card-textarea-wrap`},Me={class:`manual-hint q-px-md q-py-sm text-caption text-grey-6`},Ne={class:`q-pa-sm manual-section-body`},Pe={class:`row items-center q-gutter-sm q-mb-sm`},Fe={class:`col text-caption text-grey-4`},Ie={class:`q-pa-sm manual-section-body`},Le={class:`row items-center q-gutter-sm q-mb-sm`},Re={class:`col text-caption text-grey-4`},ze={class:`card-bottom-bar row items-center wrap q-px-sm q-py-xs q-gutter-xs`},Be={class:`bottom-select-label row items-center no-wrap`},Ve={class:`bottom-select-label row items-center no-wrap`},He={class:`bottom-select-label row items-center no-wrap`},Ue={class:`bottom-select-label row items-center no-wrap`},We={class:`bottom-select-label row items-center no-wrap`},Ge={class:`bottom-select-label row items-center no-wrap`},Ke={class:`create-hint text-center text-body2 q-mt-md text-grey-8`},E=pe(ae({__name:`CreatePage`,setup(ae){let pe=de(),E=me(),qe=ue(),D=ce(),{t:O}=ie(),Je=e([]),k=e(``),A=e(``),j=e(``),M=e(!1),N=e(`auto`),P=e(`auto`),F=e(``),I=e(null),L=e(`feature`),R=e(!1),Ye=[{label:`feature/`,value:`feature`},{label:`fix/`,value:`fix`},{label:`hotfix/`,value:`hotfix`},{label:`chore/`,value:`chore`},{label:`refactor/`,value:`refactor`},{label:`docs/`,value:`docs`},{label:`test/`,value:`test`}],z=e(D.global.defaultPermissionMode||`plan`),B=e([]),V=e(!1),H=e(!1),Xe=p(()=>[..._e.map(e=>({label:O(e.i18nLabelKey),value:e.value,description:O(e.i18nDescriptionKey)}))]);function U(e){let t=e.indexOf(`:`);return t>=0?e.slice(t+1).trim():e}let Ze=p(()=>[{label:U(O(`reasoning.auto`)),value:`auto`,description:O(`reasoning.autoDescription`)},{label:U(O(`reasoning.low`)),value:`low`,description:O(`reasoning.lowDescription`)},{label:U(O(`reasoning.medium`)),value:`medium`,description:O(`reasoning.mediumDescription`)},{label:U(O(`reasoning.high`)),value:`high`,description:O(`reasoning.highDescription`)},{label:U(O(`reasoning.max`)),value:`max`,description:O(`reasoning.maxDescription`)}]),W=p(()=>j.value.trim().startsWith(`https://www.notion.so/`)),G=e([]),K=e([]),q=e(``),J=e(``),Y=p(()=>!M.value||!W.value);function Qe(){let e=q.value.trim();e&&(G.value.push(e),q.value=``)}function $e(e){G.value.splice(e,1)}function et(){let e=J.value.trim();e&&(K.value.push(e),J.value=``)}function tt(e){K.value.splice(e,1)}function nt(){M.value=!M.value,M.value||(j.value=``)}let X=e(!1),Z=e(``),Q=p(()=>/\/issues\/\d+/.test(Z.value.trim()));function rt(){X.value=!X.value,X.value||(Z.value=``)}async function it(e){if(!e.trim()){B.value=[],I.value=null;return}V.value=!0;try{let t=await fetch(`/api/git/branches?path=${encodeURIComponent(e.trim())}`);if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.json();B.value=n.local??n.branches??[],B.value.length>0&&!I.value&&(I.value=B.value[0]??null)}catch{B.value=[],I.value=null}finally{V.value=!1}}function at(e){let t=D.getProjectByPath(e);t&&(t.defaultSourceBranch&&(I.value=t.defaultSourceBranch),t.defaultModel?N.value=t.defaultModel:D.global.defaultModel&&(N.value=D.global.defaultModel))}let $=null;ne(F,e=>{$&&clearTimeout($),$=setTimeout(()=>{I.value=null,it(e),at(e)},500)});function ot(e,t){t(()=>{Je.value=D.projectPaths.filter(t=>t.toLowerCase().includes(e.toLowerCase()))})}r(()=>{D.fetchSettings()}),i(()=>{$&&clearTimeout($)});function st(e){return e.normalize(`NFD`).replace(/[\u0300-\u036f]/g,``).toLowerCase().replace(/[^a-z0-9\s-]/g,``).trim().replace(/\s+/g,`-`).replace(/-+/g,`-`).substring(0,50)}function ct(){return k.value.trim()?k.value.trim().substring(0,80):!M.value&&A.value.trim()&&(A.value.trim().split(`
|
|
2
|
+
`)[0]??``).substring(0,80)||`workspace`}function lt(e){let t=(e.split(`/`).pop()??``).split(`-`);t.length>1&&/^[0-9a-f]{12,}$/i.test(t[t.length-1])&&t.pop();let n=t.join(`-`).toLowerCase(),r=n.match(/tk-(\d+)/);if(r){let e=`TK-${r[1]}`,t=n.replace(/tk-\d+/i,``).replace(/-+/g,`-`).replace(/^-|-$/g,``).substring(0,40);return t?`${e}--${t}`:e}return n.substring(0,50)||`task-${Date.now()}`}function ut(){return M.value&&!W.value?O(`createPage.validationNotionUrl`):X.value&&!Q.value?O(`createPage.sentryValidation`):!M.value&&!X.value&&!A.value.trim()?O(`createPage.validationDescription`):!M.value&&!X.value&&(!ct()||ct()===`workspace`)&&!k.value.trim()&&!A.value.trim()?O(`createPage.validationName`):F.value.trim()?I.value?null:O(`createPage.validationBranch`):O(`createPage.validationPath`)}async function dt(){let e=ut();if(e){E.notify({type:`negative`,message:e,position:`top`});return}H.value=!0;try{let e=ct(),t;t=M.value&&W.value?lt(j.value.trim()):e===`workspace`?`task-${Date.now()}`:st(e);let n=`${L.value}/${t}`,r={name:e,projectPath:F.value.trim(),sourceBranch:I.value,workingBranch:n,model:N.value,reasoningEffort:P.value,...M.value&&W.value?{notionUrl:j.value.trim()}:{},...X.value&&Q.value?{sentryUrl:Z.value.trim()}:{},...Y.value&&G.value.length>0?{tasks:G.value}:{},...Y.value&&K.value.length>0?{acceptanceCriteria:K.value}:{},...R.value?{skipSetupScript:!0}:{},...A.value.trim()?{description:A.value.trim()}:{},permissionMode:z.value},i=await qe.createWorkspace(r);le().subscribe(i.id),qe.selectWorkspace(i.id),pe.push({name:`workspace`,params:{id:i.id}})}catch{E.notify({type:`negative`,message:O(`createPage.errorCreating`),position:`top`})}finally{H.value=!1}}return(e,r)=>(n(),l(ge,{class:`create-page flex flex-center column`},{default:a(()=>[c(`div`,ve,[c(`div`,ye,m(e.$t(`createPage.title`)),1),c(`div`,be,[c(`div`,xe,[c(`span`,Se,[o(h,{name:`auto_awesome`,size:`14px`,color:`indigo-4`}),c(`span`,Ce,m(e.$t(`createPage.claudeCode`)),1)]),o(fe),o(g,{flat:``,dense:``,"no-caps":``,size:`sm`,color:M.value?`green-4`:`grey-5`,class:`notion-toggle-btn text-caption rounded-borders`,onClick:nt},{default:a(()=>[o(h,{name:`description`,size:`14px`,class:`q-mr-xs`}),u(` `+m(M.value?e.$t(`createPage.notionEnabled`):e.$t(`createPage.importNotion`)),1)]),_:1},8,[`color`]),o(g,{flat:``,dense:``,"no-caps":``,size:`sm`,color:X.value?`red-4`:`grey-5`,class:`sentry-toggle-btn text-caption rounded-borders q-ml-sm`,onClick:rt},{default:a(()=>[o(h,{name:`bug_report`,size:`14px`,class:`q-mr-xs`}),u(` `+m(X.value?e.$t(`createPage.sentryEnabled`):e.$t(`createPage.importSentry`)),1)]),_:1},8,[`color`])]),o(y,{color:`grey-9`}),o(se,{name:`slide`},{default:a(()=>[M.value?(n(),d(`div`,we,[o(b,{modelValue:j.value,"onUpdate:modelValue":r[0]||=e=>j.value=e,borderless:``,dense:``,placeholder:e.$t(`createPage.notionPlaceholder`),class:`notion-url-input`,"input-class":`notion-url-input-inner`},{prepend:a(()=>[o(h,{name:`link`,size:`16px`,color:W.value?`green-4`:`grey-6`},null,8,[`color`])]),_:1},8,[`modelValue`,`placeholder`]),j.value.trim()&&!W.value?(n(),d(`div`,Te,m(e.$t(`createPage.notionValidation`)),1)):f(``,!0),W.value?(n(),d(`div`,Ee,m(e.$t(`createPage.notionAutoExtract`)),1)):f(``,!0)])):f(``,!0)]),_:1}),M.value?(n(),l(y,{key:0,color:`grey-9`})):f(``,!0),o(se,{name:`slide`},{default:a(()=>[X.value?(n(),d(`div`,De,[o(b,{modelValue:Z.value,"onUpdate:modelValue":r[1]||=e=>Z.value=e,borderless:``,dense:``,placeholder:e.$t(`createPage.sentryPlaceholder`),class:`sentry-url-input`,"input-class":`sentry-url-input-inner`},{prepend:a(()=>[o(h,{name:`link`,size:`16px`,color:Q.value?`red-4`:`grey-6`},null,8,[`color`])]),_:1},8,[`modelValue`,`placeholder`]),Z.value.trim()&&!Q.value?(n(),d(`div`,Oe,m(e.$t(`createPage.sentryValidation`)),1)):f(``,!0),Q.value?(n(),d(`div`,ke,m(e.$t(`createPage.sentryAutoExtract`)),1)):f(``,!0)])):f(``,!0)]),_:1}),X.value?(n(),l(y,{key:1,color:`grey-9`})):f(``,!0),c(`div`,Ae,[o(b,{modelValue:k.value,"onUpdate:modelValue":r[2]||=e=>k.value=e,borderless:``,dense:``,placeholder:M.value&&W.value?e.$t(`createPage.workspaceName`):e.$t(`createPage.workspaceNamePlaceholder`),class:`name-input`,"input-class":`name-input-inner`},null,8,[`modelValue`,`placeholder`])]),o(y,{color:`grey-9`}),c(`div`,je,[o(b,{modelValue:A.value,"onUpdate:modelValue":r[3]||=e=>A.value=e,type:`textarea`,borderless:``,autogrow:``,rows:3,placeholder:M.value?e.$t(`createPage.instructions`):e.$t(`createPage.instructionsPlaceholder`),class:`create-textarea`,"input-class":`create-textarea-input`,onKeydown:[v(_(dt,[`ctrl`]),[`enter`]),v(_(dt,[`meta`]),[`enter`])]},null,8,[`modelValue`,`placeholder`,`onKeydown`])]),o(y,{color:`grey-9`}),Y.value?(n(),d(s,{key:2},[c(`div`,Me,m(e.$t(`createPage.manualHint`)),1),o(he,{dark:``,dense:``,label:e.$t(`createPage.tasks`,{count:G.value.length}),"header-class":`text-grey-4 manual-expansion-header`,class:`manual-expansion q-mx-sm`},{default:a(()=>[c(`div`,Ne,[c(`div`,Pe,[o(b,{modelValue:q.value,"onUpdate:modelValue":r[4]||=e=>q.value=e,dark:``,dense:``,borderless:``,placeholder:e.$t(`createPage.addTask`),class:`col manual-input`,"input-class":`manual-input-inner`,onKeydown:v(_(Qe,[`prevent`]),[`enter`])},null,8,[`modelValue`,`placeholder`,`onKeydown`]),o(g,{flat:``,dense:``,round:``,icon:`add`,color:`indigo-4`,disable:!q.value.trim(),onClick:Qe},{default:a(()=>[o(x,null,{default:a(()=>[u(m(e.$t(`tooltip.addTask`)),1)]),_:1})]),_:1},8,[`disable`])]),(n(!0),d(s,null,ee(G.value,(t,r)=>(n(),d(`div`,{key:`task-${r}`,class:`row items-center q-py-xs manual-item`},[c(`span`,Fe,m(t),1),o(g,{flat:``,dense:``,round:``,icon:`close`,size:`xs`,color:`grey-6`,onClick:e=>$e(r)},{default:a(()=>[o(x,null,{default:a(()=>[u(m(e.$t(`tooltip.removeTask`)),1)]),_:1})]),_:1},8,[`onClick`])]))),128))])]),_:1},8,[`label`]),o(he,{dark:``,dense:``,label:e.$t(`createPage.acceptanceCriteria`,{count:K.value.length}),"header-class":`text-grey-4 manual-expansion-header`,class:`manual-expansion q-mx-sm q-mb-sm`},{default:a(()=>[c(`div`,Ie,[c(`div`,Le,[o(b,{modelValue:J.value,"onUpdate:modelValue":r[5]||=e=>J.value=e,dark:``,dense:``,borderless:``,placeholder:e.$t(`createPage.addCriterion`),class:`col manual-input`,"input-class":`manual-input-inner`,onKeydown:v(_(et,[`prevent`]),[`enter`])},null,8,[`modelValue`,`placeholder`,`onKeydown`]),o(g,{flat:``,dense:``,round:``,icon:`add`,color:`indigo-4`,disable:!J.value.trim(),onClick:et},{default:a(()=>[o(x,null,{default:a(()=>[u(m(e.$t(`tooltip.addCriterion`)),1)]),_:1})]),_:1},8,[`disable`])]),(n(!0),d(s,null,ee(K.value,(t,r)=>(n(),d(`div`,{key:`crit-${r}`,class:`row items-center q-py-xs manual-item`},[c(`span`,Re,m(t),1),o(g,{flat:``,dense:``,round:``,icon:`close`,size:`xs`,color:`grey-6`,onClick:e=>tt(r)},{default:a(()=>[o(x,null,{default:a(()=>[u(m(e.$t(`tooltip.removeCriterion`)),1)]),_:1})]),_:1},8,[`onClick`])]))),128))])]),_:1},8,[`label`]),o(y,{color:`grey-9`})],64)):f(``,!0),c(`div`,ze,[o(T,{modelValue:N.value,"onUpdate:modelValue":r[6]||=e=>N.value=e,options:Xe.value,dense:``,borderless:``,class:`bottom-select rounded-borders model-select`,"hide-dropdown-icon":``,"emit-value":``,"map-options":``,"option-value":`value`,"option-label":`label`},{selected:a(()=>[c(`span`,Be,[u(m(Xe.value.find(e=>e.value===N.value)?.label??N.value)+` `,1),o(h,{name:`expand_more`,size:`12px`,color:`grey-5`})])]),option:a(({opt:e,itemProps:n})=>[o(C,t(n,{class:`model-option`}),{default:a(()=>[o(S,null,{default:a(()=>[o(w,{class:`text-white`},{default:a(()=>[u(m(e.label),1)]),_:2},1024),o(w,{caption:``,class:`text-grey-5`},{default:a(()=>[u(m(e.description),1)]),_:2},1024)]),_:2},1024)]),_:2},1040)]),_:1},8,[`modelValue`,`options`]),o(T,{modelValue:P.value,"onUpdate:modelValue":r[7]||=e=>P.value=e,options:Ze.value,dense:``,borderless:``,class:`bottom-select rounded-borders`,"hide-dropdown-icon":``,"emit-value":``,"map-options":``,"option-value":`value`,"option-label":`label`},{selected:a(()=>[c(`span`,Ve,[o(h,{name:`psychology`,size:`12px`,color:`grey-5`,class:`q-mr-xs`}),u(` `+m(Ze.value.find(e=>e.value===P.value)?.label??P.value)+` `,1),o(h,{name:`expand_more`,size:`12px`,color:`grey-5`})])]),option:a(({opt:e,itemProps:t})=>[o(C,oe(te(t)),{default:a(()=>[o(S,null,{default:a(()=>[o(w,{class:`text-white`},{default:a(()=>[u(m(e.label),1)]),_:2},1024),o(w,{caption:``,class:`text-grey-5`},{default:a(()=>[u(m(e.description),1)]),_:2},1024)]),_:2},1024)]),_:2},1040)]),_:1},8,[`modelValue`,`options`]),o(T,{modelValue:z.value,"onUpdate:modelValue":r[8]||=e=>z.value=e,options:[{label:e.$t(`permissionMode.plan`),value:`plan`},{label:e.$t(`permissionMode.autoAccept`),value:`auto-accept`}],dense:``,borderless:``,class:`bottom-select rounded-borders`,"hide-dropdown-icon":``,"emit-value":``,"map-options":``},{selected:a(()=>[c(`span`,He,[o(h,{name:z.value===`plan`?`visibility`:`flash_on`,size:`12px`,color:`amber-6`,class:`q-mr-xs`},null,8,[`name`]),u(` `+m(z.value===`plan`?e.$t(`permissionMode.plan`):e.$t(`permissionMode.autoAccept`))+` `,1),o(h,{name:`expand_more`,size:`12px`,color:`grey-5`})])]),_:1},8,[`modelValue`,`options`]),o(g,{flat:``,round:``,dense:``,size:`sm`,icon:R.value?`play_disabled`:`play_circle`,color:R.value?`orange-4`:`grey-6`,onClick:r[9]||=e=>R.value=!R.value},{default:a(()=>[o(x,null,{default:a(()=>[u(m(e.$t(`createPage.skipSetupScript`)),1)]),_:1})]),_:1},8,[`icon`,`color`]),o(fe),o(T,{modelValue:F.value,"onUpdate:modelValue":r[10]||=e=>F.value=e,options:Je.value,dense:``,borderless:``,"use-input":``,"hide-selected":``,"fill-input":``,"input-debounce":`0`,"new-value-mode":`add`,class:`bottom-select rounded-borders repo-select`,"hide-dropdown-icon":``,behavior:re(D).projectPaths.length>0?`menu`:`dialog`,onFilter:ot,onInputValue:r[11]||=e=>{F.value=e}},{prepend:a(()=>[o(h,{name:`attach_file`,size:`12px`,color:`grey-5`})]),selected:a(()=>[c(`span`,Ue,m(F.value||e.$t(`createPage.projectPath`)),1)]),"no-option":a(()=>[o(C,null,{default:a(()=>[o(S,{class:`text-grey-6 text-caption`},{default:a(()=>[u(m(e.$t(`createPage.enterPath`)),1)]),_:1})]),_:1})]),_:1},8,[`modelValue`,`options`,`behavior`]),o(T,{modelValue:L.value,"onUpdate:modelValue":r[12]||=e=>L.value=e,options:Ye,"emit-value":``,"map-options":``,dense:``,borderless:``,class:`bottom-select rounded-borders branch-type-select`,"hide-dropdown-icon":``},{selected:a(()=>[c(`span`,We,[o(h,{name:`account_tree`,size:`12px`,color:`grey-5`,class:`q-mr-xs`}),u(` `+m(L.value)+`/ `,1),o(h,{name:`expand_more`,size:`12px`,color:`grey-5`})])]),default:a(()=>[o(x,null,{default:a(()=>[u(m(e.$t(`createPage.branchType`)),1)]),_:1})]),_:1},8,[`modelValue`]),o(T,{modelValue:I.value,"onUpdate:modelValue":r[13]||=e=>I.value=e,options:B.value,dense:``,borderless:``,class:`bottom-select rounded-borders branch-select`,"hide-dropdown-icon":``,loading:V.value,disable:!F.value.trim()||V.value},{selected:a(()=>[c(`span`,Ge,[o(h,{name:`call_split`,size:`12px`,color:`grey-5`,class:`q-mr-xs`}),u(` `+m(I.value??e.$t(`createPage.branch`))+` `,1),o(h,{name:`expand_more`,size:`12px`,color:`grey-5`})])]),"no-option":a(()=>[o(C,null,{default:a(()=>[o(S,{class:`text-grey-6 text-caption`},{default:a(()=>[u(m(F.value.trim()?e.$t(`createPage.noBranches`):e.$t(`createPage.enterPath`)),1)]),_:1})]),_:1})]),_:1},8,[`modelValue`,`options`,`loading`,`disable`]),o(g,{label:e.$t(`createPage.create`),"no-caps":``,unelevated:``,class:`create-btn text-weight-bold rounded-borders`,loading:H.value,onClick:dt},null,8,[`label`,`loading`])])]),c(`div`,Ke,m(M.value?e.$t(`createPage.notionExtractHint`):e.$t(`createPage.notionImportHint`)),1)])]),_:1}))}}),[[`__scopeId`,`data-v-9808a4a1`]]);export{E as default};
|