@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.
Files changed (81) hide show
  1. package/README.md +1 -1
  2. package/dist/server/db/migrations.js +7 -0
  3. package/dist/server/db/schema.js +1 -0
  4. package/dist/server/index.js +2 -2
  5. package/dist/server/routes/settings.js +11 -0
  6. package/dist/server/routes/workspaces.js +13 -5
  7. package/dist/server/services/agent-manager.js +4 -1
  8. package/dist/server/services/notion-service.js +35 -17
  9. package/dist/server/services/sentry-service.js +8 -3
  10. package/dist/server/services/settings-service.js +40 -4
  11. package/dist/server/services/workspace-service.js +16 -3
  12. package/dist/server/utils/mcp-client.js +33 -13
  13. package/dist/server/utils/paths.js +8 -0
  14. package/package.json +3 -3
  15. package/src/client/dist/spa/assets/ActivityFeed-CAgtfoqj.js +10 -0
  16. package/src/client/dist/spa/assets/{ClosePopup-jSuaV6dg.js → ClosePopup-BfANRQ7n.js} +1 -1
  17. package/src/client/dist/spa/assets/CreatePage-CNnVeRGC.css +1 -0
  18. package/src/client/dist/spa/assets/CreatePage-CnsmjbZl.js +2 -0
  19. package/src/client/dist/spa/assets/DiffViewer-CwAhR0Bt.js +2 -0
  20. package/src/client/dist/spa/assets/MainLayout-1KXWlMYS.css +1 -0
  21. package/src/client/dist/spa/assets/{MainLayout-z-GTmsNk.js → MainLayout-D9UzZ0l0.js} +17 -17
  22. package/src/client/dist/spa/assets/{QBadge-xNMZEqT-.js → QBadge-DENdn6Dv.js} +1 -1
  23. package/src/client/dist/spa/assets/QExpansionItem-ZAI_l6AW.js +1 -0
  24. package/src/client/dist/spa/assets/{QList-C0MyMgKh.js → QList-aKZe9BNZ.js} +1 -1
  25. package/src/client/dist/spa/assets/QMenu-DDXq2SFM.js +1 -0
  26. package/src/client/dist/spa/assets/{QSpinnerDots-FJCnAvfw.js → QSpinnerDots-DytntAbf.js} +1 -1
  27. package/src/client/dist/spa/assets/SettingsPage-DCgRTq-c.js +1 -0
  28. package/src/client/dist/spa/assets/SettingsPage-oWZ8sGFm.css +1 -0
  29. package/src/client/dist/spa/assets/{TouchPan-DuISf80E.js → TouchPan-D_gmnARo.js} +1 -1
  30. package/src/client/dist/spa/assets/WorkspacePage-BSBiQTKy.js +4 -0
  31. package/src/client/dist/spa/assets/{WorkspacePage-BIYgMXby.css → WorkspacePage-DZwv9kFd.css} +1 -1
  32. package/src/client/dist/spa/assets/{_plugin-vue_export-helper-fkfRoKj2.js → _plugin-vue_export-helper-DkL3SKZ8.js} +1 -1
  33. package/src/client/dist/spa/assets/{cssMode-4TH_2zaD.js → cssMode-CzYfUUcg.js} +1 -1
  34. package/src/client/dist/spa/assets/{editor.api-CyJb27tS.js → editor.api-Do3RvGrr.js} +1 -1
  35. package/src/client/dist/spa/assets/{editor.main-oZnnOWQQ.js → editor.main-BXGLrNaH.js} +3 -3
  36. package/src/client/dist/spa/assets/{formatters-B5Igo0Lf.js → formatters-hnFdqDO2.js} +1 -1
  37. package/src/client/dist/spa/assets/{freemarker2-QspagBXp.js → freemarker2-DD7dLGS5.js} +1 -1
  38. package/src/client/dist/spa/assets/{handlebars-DNK4bfk9.js → handlebars-C6fNrY_c.js} +1 -1
  39. package/src/client/dist/spa/assets/{html-DoAFaOJE.js → html-CsN_ZrNj.js} +1 -1
  40. package/src/client/dist/spa/assets/{htmlMode-Dd2XBcML.js → htmlMode-BePbSvxH.js} +1 -1
  41. package/src/client/dist/spa/assets/i18n-C_tQYbyT.js +1 -0
  42. package/src/client/dist/spa/assets/i18n-zwZDkEfm.js +1 -0
  43. package/src/client/dist/spa/assets/index-BJT6ZfVp.js +5 -0
  44. package/src/client/dist/spa/assets/{javascript-C8gxtWJG.js → javascript-CkZZHPRD.js} +1 -1
  45. package/src/client/dist/spa/assets/{jsonMode-BW-w1oEn.js → jsonMode-CsqbZ0c2.js} +1 -1
  46. package/src/client/dist/spa/assets/{liquid-CQDlB55c.js → liquid-CB4bbF-9.js} +1 -1
  47. package/src/client/dist/spa/assets/{marked.esm-CGMwQXW0.js → marked.esm-DIsIySzr.js} +1 -1
  48. package/src/client/dist/spa/assets/{mdx-DUS2o1l2.js → mdx-goM-jFgd.js} +1 -1
  49. package/src/client/dist/spa/assets/models-Dwzf2zDK.js +1 -0
  50. package/src/client/dist/spa/assets/{monaco.contribution-BSsdGujG.js → monaco.contribution-tq8HWx81.js} +2 -2
  51. package/src/client/dist/spa/assets/{private.use-form-1cZLVjGN.js → private.use-form-BWfHn8G9.js} +1 -1
  52. package/src/client/dist/spa/assets/{python-DVWLF-An.js → python-BKb3PkXw.js} +1 -1
  53. package/src/client/dist/spa/assets/{razor-bodgahcD.js → razor-rLKJylZh.js} +1 -1
  54. package/src/client/dist/spa/assets/scroll-CHtHNzvE.js +1 -0
  55. package/src/client/dist/spa/assets/settings-BdrDg_dO.js +1 -0
  56. package/src/client/dist/spa/assets/touch-5Jv2Ep3F.js +1 -0
  57. package/src/client/dist/spa/assets/{tsMode-C7oNyY1g.js → tsMode-CjX_dUdq.js} +1 -1
  58. package/src/client/dist/spa/assets/{typescript-C_X20eQu.js → typescript-Bg5NM6yP.js} +1 -1
  59. package/src/client/dist/spa/assets/{use-checkbox-DwkIkUAc.js → use-checkbox-By4PLtaB.js} +1 -1
  60. package/src/client/dist/spa/assets/vue-i18n-CFW7O-jl.js +3 -0
  61. package/src/client/dist/spa/assets/{xml-BVbLd8T0.js → xml-BMWcIRqp.js} +1 -1
  62. package/src/client/dist/spa/assets/{yaml-D5WOobuH.js → yaml-C2uOvXS0.js} +1 -1
  63. package/src/client/dist/spa/index.html +7 -7
  64. package/src/client/dist/spa/assets/ActivityFeed-C7knqOOL.js +0 -10
  65. package/src/client/dist/spa/assets/CreatePage-Owxm6Tpi.js +0 -2
  66. package/src/client/dist/spa/assets/CreatePage-y7wOGccu.css +0 -1
  67. package/src/client/dist/spa/assets/DiffViewer-mLBk-G-D.js +0 -2
  68. package/src/client/dist/spa/assets/MainLayout-DH5FgF9v.css +0 -1
  69. package/src/client/dist/spa/assets/QExpansionItem-BoxRv2sW.js +0 -1
  70. package/src/client/dist/spa/assets/QMenu-DayfIdY0.js +0 -1
  71. package/src/client/dist/spa/assets/QPage-D7SSe7S1.js +0 -1
  72. package/src/client/dist/spa/assets/SettingsPage-BzJ9LphQ.js +0 -1
  73. package/src/client/dist/spa/assets/SettingsPage-ai7Q_1KB.css +0 -1
  74. package/src/client/dist/spa/assets/WorkspacePage-Dv_vuDsw.js +0 -4
  75. package/src/client/dist/spa/assets/i18n-NIfrKJms.js +0 -1
  76. package/src/client/dist/spa/assets/i18n-ckoKODmn.js +0 -1
  77. package/src/client/dist/spa/assets/index-B4-QwpHI.js +0 -5
  78. package/src/client/dist/spa/assets/scroll-CWjBCoBR.js +0 -1
  79. package/src/client/dist/spa/assets/settings-CuK-S6HH.js +0 -1
  80. package/src/client/dist/spa/assets/touch-Bojc73iM.js +0 -1
  81. 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 `3000` (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.
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;
@@ -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,
@@ -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 && body.model === undefined && body.permissionMode === undefined && body.name === undefined) {
776
- return c.json({ error: 'Missing field: status, model, permissionMode, or name' }, 400);
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 readNotionTokenFromClaudeConfig() {
38
- const match = readClaudeMcpEntry((k) => k === 'notion');
39
- if (!match)
40
- return '';
41
- const env = match.entry.env ?? {};
42
- return env.NOTION_TOKEN ?? env.NOTION_API_TOKEN ?? '';
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 notionToken = process.env.NOTION_API_TOKEN ?? process.env.NOTION_TOKEN ?? readNotionTokenFromClaudeConfig();
46
- const command = process.env.NOTION_MCP_COMMAND ?? 'npx';
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
- OPENAPI_MCP_HEADERS: JSON.stringify({
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 mcpProcess = spawnNotionMcp();
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 mcpProcess = spawnNotionMcp();
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 match = readClaudeMcpEntry((k) => /sentry/i.test(k));
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 config = readSentryMcpConfig();
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 writeSettings(settings) {
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 homedir = process.env.HOME ?? process.env.USERPROFILE ?? '';
14
- const configPath = `${homedir}/.claude.json`;
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",
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-CWjBCoBR.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};
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};