@dmrlzz/davecode 0.5.0 → 0.5.2

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 (73) hide show
  1. package/dist/{ChatApp-CJBICQGA.js → ChatApp-Z6PQIZ5J.js} +7 -6
  2. package/dist/{ChatApp-CJBICQGA.js.map → ChatApp-Z6PQIZ5J.js.map} +1 -1
  3. package/dist/{account-QWDPJWAA.js → account-RTPS2V6O.js} +4 -3
  4. package/dist/{accounts-IQMR72FC.js → accounts-IYQ4ZRL7.js} +6 -5
  5. package/dist/{budget-XANOUVWO.js → budget-N2ZB66FF.js} +5 -4
  6. package/dist/{budget-XANOUVWO.js.map → budget-N2ZB66FF.js.map} +1 -1
  7. package/dist/{chat-KDDRNC5V.js → chat-6TX6JX45.js} +9 -8
  8. package/dist/{chat-KDDRNC5V.js.map → chat-6TX6JX45.js.map} +1 -1
  9. package/dist/chunk-732GIHRQ.js +23 -0
  10. package/dist/chunk-732GIHRQ.js.map +1 -0
  11. package/dist/{chunk-AZKACMME.js → chunk-BJTXMET2.js} +2 -2
  12. package/dist/{chunk-FYPMA55O.js → chunk-KUY3QHGS.js} +239 -106
  13. package/dist/chunk-KUY3QHGS.js.map +1 -0
  14. package/dist/{chunk-JLATEHS7.js → chunk-LEU46DGH.js} +2 -2
  15. package/dist/{chunk-HSBJDV3O.js → chunk-QKY3OKVG.js} +309 -23
  16. package/dist/chunk-QKY3OKVG.js.map +1 -0
  17. package/dist/{chunk-WQ7MEWDF.js → chunk-UEV5K3DH.js} +10 -4
  18. package/dist/chunk-UEV5K3DH.js.map +1 -0
  19. package/dist/{chunk-44AFJL2X.js → chunk-UNK3EQD6.js} +6 -5
  20. package/dist/chunk-UNK3EQD6.js.map +1 -0
  21. package/dist/{chunk-W7GPBEBZ.js → chunk-WAARDGCZ.js} +5 -21
  22. package/dist/chunk-WAARDGCZ.js.map +1 -0
  23. package/dist/{chunk-PGAJIGUF.js → chunk-YNAMNQLW.js} +3 -3
  24. package/dist/{config-YTUPIYZT.js → config-YQKY2AA4.js} +4 -3
  25. package/dist/{config-YTUPIYZT.js.map → config-YQKY2AA4.js.map} +1 -1
  26. package/dist/dashboard/assets/Accounts-DXiGsutB.js +1 -0
  27. package/dist/dashboard/assets/{Badge-Z4RBdO9j.js → Badge-DUGKlx3Z.js} +1 -1
  28. package/dist/dashboard/assets/{Callout-w8BTYh4k.js → Callout-1E8Wsl9W.js} +1 -1
  29. package/dist/dashboard/assets/{Goals-Bw02to72.js → Goals-kL4VAxw3.js} +1 -1
  30. package/dist/dashboard/assets/{Library-DK7mlpRb.js → Library-DZxBVUo_.js} +1 -1
  31. package/dist/dashboard/assets/Markdown-CGgIydUh.js +71 -0
  32. package/dist/dashboard/assets/{Panes-_KTf8pbZ.js → Panes-C-TJekjs.js} +1 -1
  33. package/dist/dashboard/assets/{RoutesPage-QV0oPRW9.js → RoutesPage-DWYm9tW8.js} +1 -1
  34. package/dist/dashboard/assets/{Runner-CkHBLQl0.js → Runner-CmHBjECR.js} +1 -1
  35. package/dist/dashboard/assets/{Settings-BLz2gTBR.js → Settings-BANphxva.js} +1 -1
  36. package/dist/dashboard/assets/{Tasks-BiUQSTpt.js → Tasks-cSx1PKyQ.js} +1 -1
  37. package/dist/dashboard/assets/{Traffic-BVfBuC70.js → Traffic-DEAuM6jq.js} +1 -1
  38. package/dist/dashboard/assets/{Workspace-CJTgiiU5.js → Workspace-BQFjc1jH.js} +1 -1
  39. package/dist/dashboard/assets/index-B8kld9xo.js +104 -0
  40. package/dist/dashboard/assets/{task-errors-Daqwi0ue.js → task-errors-r-WYZ_S3.js} +1 -1
  41. package/dist/dashboard/index.html +2 -2
  42. package/dist/{dist-37VQSHHA.js → dist-PIC255RX.js} +20 -2
  43. package/dist/{doctor-PYUQRRCB.js → doctor-PQC7JQPP.js} +4 -3
  44. package/dist/{doctor-PYUQRRCB.js.map → doctor-PQC7JQPP.js.map} +1 -1
  45. package/dist/{goal-SXZUDUCL.js → goal-STLEU7C7.js} +4 -3
  46. package/dist/{goal-SXZUDUCL.js.map → goal-STLEU7C7.js.map} +1 -1
  47. package/dist/index.js +31 -31
  48. package/dist/{init-Z2AFQEEP.js → init-NHU5LJSS.js} +4 -3
  49. package/dist/{init-Z2AFQEEP.js.map → init-NHU5LJSS.js.map} +1 -1
  50. package/dist/{run-AOS7L3RT.js → run-7HWSHMRJ.js} +4 -3
  51. package/dist/{run-AOS7L3RT.js.map → run-7HWSHMRJ.js.map} +1 -1
  52. package/dist/runtime.js +3 -2
  53. package/dist/{start-CEPXKZUE.js → start-WVAEAQWL.js} +4 -3
  54. package/dist/{start-CEPXKZUE.js.map → start-WVAEAQWL.js.map} +1 -1
  55. package/dist/{status-WNJ3GGKU.js → status-ZRHPFLFT.js} +5 -4
  56. package/dist/{tasks-TFUTUMWB.js → tasks-JVWXUNXN.js} +5 -4
  57. package/dist/{tasks-TFUTUMWB.js.map → tasks-JVWXUNXN.js.map} +1 -1
  58. package/package.json +6 -6
  59. package/dist/chunk-44AFJL2X.js.map +0 -1
  60. package/dist/chunk-FYPMA55O.js.map +0 -1
  61. package/dist/chunk-HSBJDV3O.js.map +0 -1
  62. package/dist/chunk-W7GPBEBZ.js.map +0 -1
  63. package/dist/chunk-WQ7MEWDF.js.map +0 -1
  64. package/dist/dashboard/assets/Accounts-cq8RLMoI.js +0 -1
  65. package/dist/dashboard/assets/Markdown-DCZ4Awcc.js +0 -69
  66. package/dist/dashboard/assets/index-BDBa5cb0.js +0 -104
  67. /package/dist/{account-QWDPJWAA.js.map → account-RTPS2V6O.js.map} +0 -0
  68. /package/dist/{accounts-IQMR72FC.js.map → accounts-IYQ4ZRL7.js.map} +0 -0
  69. /package/dist/{chunk-AZKACMME.js.map → chunk-BJTXMET2.js.map} +0 -0
  70. /package/dist/{chunk-JLATEHS7.js.map → chunk-LEU46DGH.js.map} +0 -0
  71. /package/dist/{chunk-PGAJIGUF.js.map → chunk-YNAMNQLW.js.map} +0 -0
  72. /package/dist/{dist-37VQSHHA.js.map → dist-PIC255RX.js.map} +0 -0
  73. /package/dist/{status-WNJ3GGKU.js.map → status-ZRHPFLFT.js.map} +0 -0
@@ -1 +1 @@
1
- import{n as e}from"./cn-BwE4cei0.js";import{ft as t,pt as n}from"./Badge-Z4RBdO9j.js";var r={name:`pencil`,size:24,node:[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]};r.node;var i=e(r);function a(e){if(!n(e))return t(e);switch(e.code){case`brain_read_only`:return`This gateway exposes the project brain read-only, so the task graph cannot be edited here.`;case`no_brain`:return`No project is loaded. Start the gateway inside an initialised project (davecode init).`;case`cycle`:return e.cycle?`That would create a dependency cycle: ${e.cycle.join(` → `)}.`:e.message;case`has_dependents`:return e.dependents?.length?`Other tasks still depend on it: ${e.dependents.join(`, `)}. Remove those dependencies first.`:e.message;case`task_in_progress`:return`The task is in progress. Reopen it before deleting it.`;case`duplicate_id`:return`A task with this id already exists.`;case`invalid_transition`:return`The task cannot move to that status from its current one. ${e.message}`;case`config_invalid`:return`The global config file is not valid, so it was left untouched. ${e.message}`;default:return t(e)}}export{i as n,a as t};
1
+ import{n as e}from"./cn-BwE4cei0.js";import{ft as t,pt as n}from"./Badge-DUGKlx3Z.js";var r={name:`pencil`,size:24,node:[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]};r.node;var i=e(r);function a(e){if(!n(e))return t(e);switch(e.code){case`brain_read_only`:return`This gateway exposes the project brain read-only, so the task graph cannot be edited here.`;case`no_brain`:return`No project is loaded. Start the gateway inside an initialised project (davecode init).`;case`cycle`:return e.cycle?`That would create a dependency cycle: ${e.cycle.join(` → `)}.`:e.message;case`has_dependents`:return e.dependents?.length?`Other tasks still depend on it: ${e.dependents.join(`, `)}. Remove those dependencies first.`:e.message;case`task_in_progress`:return`The task is in progress. Reopen it before deleting it.`;case`duplicate_id`:return`A task with this id already exists.`;case`invalid_transition`:return`The task cannot move to that status from its current one. ${e.message}`;case`config_invalid`:return`The global config file is not valid, so it was left untouched. ${e.message}`;default:return t(e)}}export{i as n,a as t};
@@ -20,9 +20,9 @@
20
20
  document.documentElement.dataset.theme = storedTheme;
21
21
  }
22
22
  </script>
23
- <script type="module" crossorigin src="./assets/index-BDBa5cb0.js"></script>
23
+ <script type="module" crossorigin src="./assets/index-B8kld9xo.js"></script>
24
24
  <link rel="modulepreload" crossorigin href="./assets/cn-BwE4cei0.js">
25
- <link rel="modulepreload" crossorigin href="./assets/Badge-Z4RBdO9j.js">
25
+ <link rel="modulepreload" crossorigin href="./assets/Badge-DUGKlx3Z.js">
26
26
  <link rel="stylesheet" crossorigin href="./assets/index-BEmBgsbP.css">
27
27
  </head>
28
28
  <body>
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ACCOUNT_SERVICE,
3
+ API_CONFIG_KEYS,
3
4
  AccountClient,
4
5
  AccountError,
5
6
  AccountRepository,
@@ -29,6 +30,7 @@ import {
29
30
  DEFAULT_JEV_BASE_URL,
30
31
  DEFAULT_JEV_MODEL,
31
32
  DEFAULT_ROLES,
33
+ ENDPOINT_CONFIG_KEYS,
32
34
  EXPERIMENTAL_PROVIDER_KINDS,
33
35
  EventBus,
34
36
  ExecutorAbortedError,
@@ -62,6 +64,7 @@ import {
62
64
  OAUTH_PROVIDERS,
63
65
  OpenAICompatibleProvider,
64
66
  OpenAIProvider,
67
+ PROJECT_SETTABLE_KEYS,
65
68
  PROVIDER_KINDS,
66
69
  PathEscapeError,
67
70
  ProjectBrain,
@@ -97,6 +100,7 @@ import {
97
100
  accountServes,
98
101
  accountService,
99
102
  addTask,
103
+ apiConfigIssues,
100
104
  applySafetyGuard,
101
105
  approximateTokens,
102
106
  assertSafeRef,
@@ -111,6 +115,7 @@ import {
111
115
  configuredModels,
112
116
  connectionMethod,
113
117
  countTextTokens,
118
+ createAccountControl,
114
119
  createEngine,
115
120
  createExecutor,
116
121
  createGoalService,
@@ -121,10 +126,13 @@ import {
121
126
  deepMerge,
122
127
  defaultModelFor,
123
128
  dependentsOf,
129
+ endpointChanged,
130
+ endpointRebindIssue,
124
131
  envLayer,
125
132
  errorKindFromStatus,
126
133
  estimateTokens2,
127
134
  extractJsonObject,
135
+ filterProjectLayer,
128
136
  findCycles,
129
137
  findProjectRoot,
130
138
  geminiCliEnv,
@@ -144,6 +152,7 @@ import {
144
152
  loginCommandFor,
145
153
  loginEnv,
146
154
  loginFromEnv,
155
+ mergeApiConfig,
147
156
  migrate,
148
157
  newId2,
149
158
  nextTask,
@@ -186,9 +195,10 @@ import {
186
195
  validateTaskGraph,
187
196
  withFileLock,
188
197
  writeGlobalRouting
189
- } from "./chunk-HSBJDV3O.js";
198
+ } from "./chunk-QKY3OKVG.js";
190
199
  export {
191
200
  ACCOUNT_SERVICE,
201
+ API_CONFIG_KEYS,
192
202
  AccountClient,
193
203
  AccountError,
194
204
  AccountRepository,
@@ -218,6 +228,7 @@ export {
218
228
  DEFAULT_JEV_BASE_URL,
219
229
  DEFAULT_JEV_MODEL,
220
230
  DEFAULT_ROLES,
231
+ ENDPOINT_CONFIG_KEYS,
221
232
  EXPERIMENTAL_PROVIDER_KINDS,
222
233
  EventBus,
223
234
  ExecutorAbortedError,
@@ -251,6 +262,7 @@ export {
251
262
  OAUTH_PROVIDERS,
252
263
  OpenAICompatibleProvider,
253
264
  OpenAIProvider,
265
+ PROJECT_SETTABLE_KEYS,
254
266
  PROVIDER_KINDS,
255
267
  PathEscapeError,
256
268
  ProjectBrain,
@@ -286,6 +298,7 @@ export {
286
298
  accountServes,
287
299
  accountService,
288
300
  addTask,
301
+ apiConfigIssues,
289
302
  applySafetyGuard,
290
303
  approximateTokens,
291
304
  assertSafeRef,
@@ -300,6 +313,7 @@ export {
300
313
  configuredModels,
301
314
  connectionMethod,
302
315
  countTextTokens,
316
+ createAccountControl,
303
317
  createEngine,
304
318
  createExecutor,
305
319
  createGoalService,
@@ -310,10 +324,13 @@ export {
310
324
  deepMerge,
311
325
  defaultModelFor,
312
326
  dependentsOf,
327
+ endpointChanged,
328
+ endpointRebindIssue,
313
329
  envLayer,
314
330
  errorKindFromStatus,
315
331
  estimateTokens2 as estimateTokens,
316
332
  extractJsonObject,
333
+ filterProjectLayer,
317
334
  findCycles,
318
335
  findProjectRoot,
319
336
  geminiCliEnv,
@@ -333,6 +350,7 @@ export {
333
350
  loginCommandFor,
334
351
  loginEnv,
335
352
  loginFromEnv,
353
+ mergeApiConfig,
336
354
  migrate,
337
355
  newId2 as newId,
338
356
  nextTask,
@@ -376,4 +394,4 @@ export {
376
394
  withFileLock,
377
395
  writeGlobalRouting
378
396
  };
379
- //# sourceMappingURL=dist-37VQSHHA.js.map
397
+ //# sourceMappingURL=dist-PIC255RX.js.map
@@ -10,14 +10,15 @@ import {
10
10
  detectProjectRoot,
11
11
  resolveDashboardDir,
12
12
  which
13
- } from "./chunk-FYPMA55O.js";
13
+ } from "./chunk-KUY3QHGS.js";
14
14
  import {
15
15
  EXIT
16
16
  } from "./chunk-7XVXEO7U.js";
17
+ import "./chunk-732GIHRQ.js";
17
18
  import {
18
19
  loadConfig,
19
20
  openDatabase
20
- } from "./chunk-HSBJDV3O.js";
21
+ } from "./chunk-QKY3OKVG.js";
21
22
  import "./chunk-MC7RIPL7.js";
22
23
 
23
24
  // src/commands/doctor.ts
@@ -276,4 +277,4 @@ export {
276
277
  renderDoctor,
277
278
  runDoctor
278
279
  };
279
- //# sourceMappingURL=doctor-PYUQRRCB.js.map
280
+ //# sourceMappingURL=doctor-PQC7JQPP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:net';\nimport { join } from 'node:path';\nimport { type DaveConfig, loadConfig, openDatabase } from '@davecode/core';\nimport { connectHost, GatewayClient } from '../client';\nimport { type CliContext, printJson } from '../context';\nimport { EXIT } from '../errors';\nimport { which } from '../lib/proc';\nimport { detectProjectRoot, resolveDashboardDir } from '../runtime';\nimport { padEnd } from '../ui/format';\n\nexport type CheckStatus = 'ok' | 'warn' | 'fail';\n\nexport interface CheckResult {\n id: string;\n label: string;\n status: CheckStatus;\n detail: string;\n fix?: string;\n}\n\n/** Everything doctor touches outside its own logic, injectable for tests. */\nexport interface DoctorProbes {\n nodeVersion: string;\n loadConfig(): DaveConfig;\n /** Open an in-memory database; resolves with a detail string. */\n loadSqlite(): Promise<string>;\n /** Throws when `dir` cannot be created or written. */\n checkWritable(dir: string): Promise<void>;\n exists(path: string): boolean;\n portInUse(host: string, port: number): Promise<boolean>;\n /** Version of the DaveCode gateway answering on `baseUrl`, if any. */\n gatewayVersion(baseUrl: string, token?: string): Promise<string | undefined>;\n which(command: string): string | undefined;\n /** True when `url` answers with any HTTP response within the timeout. */\n reachable(url: string): Promise<boolean>;\n dashboardDir(): string | undefined;\n}\n\nexport interface DoctorInput {\n home: string;\n env: NodeJS.ProcessEnv;\n}\n\nconst MIN_NODE: [number, number] = [22, 12];\n\nexport function nodeVersionOk(version: string): boolean {\n const [major = 0, minor = 0] = version.replace(/^v/, '').split('.').map(Number);\n return major > MIN_NODE[0] || (major === MIN_NODE[0] && minor >= MIN_NODE[1]);\n}\n\nexport async function runDoctor(input: DoctorInput, probes: DoctorProbes): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n const add = (r: CheckResult) => results.push(r);\n\n add(\n nodeVersionOk(probes.nodeVersion)\n ? { id: 'node', label: 'Node.js', status: 'ok', detail: probes.nodeVersion }\n : {\n id: 'node',\n label: 'Node.js',\n status: 'fail',\n detail: `${probes.nodeVersion} (needs ${MIN_NODE.join('.')}+)`,\n fix: 'Install Node.js 22.12 or newer: https://nodejs.org',\n },\n );\n\n let config: DaveConfig | undefined;\n try {\n config = probes.loadConfig();\n add({ id: 'config', label: 'Config', status: 'ok', detail: 'valid' });\n } catch (err) {\n add({\n id: 'config',\n label: 'Config',\n status: 'fail',\n detail: (err as Error).message.split('\\n').slice(0, 3).join(' '),\n fix: 'Fix the file named above; `davecode config path` lists every config location.',\n });\n }\n\n try {\n add({ id: 'sqlite', label: 'better-sqlite3', status: 'ok', detail: await probes.loadSqlite() });\n } catch (err) {\n add({\n id: 'sqlite',\n label: 'better-sqlite3',\n status: 'fail',\n detail: `cannot load: ${(err as Error).message.split('\\n')[0]}`,\n fix: 'Rebuild the native module: pnpm rebuild better-sqlite3 (needs a C++ toolchain if no prebuilt binary matches your Node version).',\n });\n }\n\n try {\n await probes.checkWritable(input.home);\n add({ id: 'home', label: 'Home directory', status: 'ok', detail: `${input.home} is writable` });\n } catch (err) {\n add({\n id: 'home',\n label: 'Home directory',\n status: 'fail',\n detail: `${input.home} is not writable (${(err as NodeJS.ErrnoException).code ?? (err as Error).message})`,\n fix: 'Fix the permissions or point DaveCode elsewhere with --home <dir> / DAVECODE_HOME.',\n });\n }\n\n const keyPath = join(input.home, 'master.key');\n if (input.env.DAVECODE_MASTER_KEY) {\n add({\n id: 'master-key',\n label: 'Master key',\n status: 'ok',\n detail: 'from DAVECODE_MASTER_KEY',\n });\n } else if (probes.exists(keyPath)) {\n add({ id: 'master-key', label: 'Master key', status: 'ok', detail: keyPath });\n } else {\n add({\n id: 'master-key',\n label: 'Master key',\n status: 'warn',\n detail: 'not created yet',\n fix: 'It is generated on first use (davecode start or accounts add). Back it up: without it stored secrets cannot be decrypted.',\n });\n }\n\n if (config) {\n const { host, port, authToken } = config.server;\n const baseUrl = `http://${connectHost(host)}:${port}`;\n if (!(await probes.portInUse(host, port))) {\n add({ id: 'port', label: 'Gateway port', status: 'ok', detail: `${host}:${port} is free` });\n } else {\n const version = await probes.gatewayVersion(baseUrl, authToken);\n add(\n version\n ? {\n id: 'port',\n label: 'Gateway port',\n status: 'ok',\n detail: `DaveCode ${version} is already running at ${baseUrl}`,\n }\n : {\n id: 'port',\n label: 'Gateway port',\n status: 'fail',\n detail: `${host}:${port} is used by another program`,\n fix: `Stop it, or use another port: davecode start --port ${port + 1} (or DAVECODE_PORT).`,\n },\n );\n }\n }\n\n const tools: Array<{ cmd: string; label: string; required: boolean; why: string; fix: string }> =\n [\n {\n cmd: 'git',\n label: 'git',\n required: true,\n why: 'needed by the autonomous runner (task branches and merges)',\n fix: 'Install git: https://git-scm.com/downloads',\n },\n {\n cmd: 'claude',\n label: 'Claude Code CLI',\n required: false,\n why: 'only for claude-cli accounts',\n fix: 'npm install -g @anthropic-ai/claude-code',\n },\n {\n cmd: 'codex',\n label: 'Codex CLI',\n required: false,\n why: 'only for codex-cli accounts',\n fix: 'npm install -g @openai/codex',\n },\n {\n cmd: 'gemini',\n label: 'Gemini CLI',\n required: false,\n why: 'only for gemini-cli accounts',\n fix: 'npm install -g @google/gemini-cli',\n },\n {\n cmd: 'gh',\n label: 'GitHub CLI',\n required: false,\n why: 'optional, for opening pull requests',\n fix: 'Install gh: https://cli.github.com',\n },\n ];\n for (const tool of tools) {\n const path = probes.which(tool.cmd);\n add(\n path\n ? { id: tool.cmd, label: tool.label, status: 'ok', detail: path }\n : {\n id: tool.cmd,\n label: tool.label,\n status: tool.required ? 'fail' : 'warn',\n detail: `not found on PATH (${tool.why})`,\n fix: tool.fix,\n },\n );\n }\n\n const dashboard = probes.dashboardDir();\n add(\n dashboard\n ? { id: 'dashboard', label: 'Dashboard build', status: 'ok', detail: dashboard }\n : {\n id: 'dashboard',\n label: 'Dashboard build',\n status: 'warn',\n detail: 'not built (the gateway still works without it)',\n fix: 'pnpm --filter @davecode/ui build',\n },\n );\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Real probes\n// ---------------------------------------------------------------------------\n\nfunction portInUse(host: string, port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = createServer();\n server.once('error', (err: NodeJS.ErrnoException) => {\n resolve(err.code === 'EADDRINUSE' || err.code === 'EACCES');\n });\n server.listen({ host, port, exclusive: true }, () => {\n server.close(() => resolve(false));\n });\n });\n}\n\nexport function defaultProbes(\n ctx: Pick<CliContext, 'home' | 'env'>,\n projectRoot?: string,\n): DoctorProbes {\n return {\n nodeVersion: process.version,\n loadConfig: () =>\n loadConfig({ home: ctx.home, env: ctx.env, ...(projectRoot ? { projectRoot } : {}) }),\n async loadSqlite() {\n const db = openDatabase(':memory:');\n try {\n const row = db.prepare('select sqlite_version() as v').get() as { v: string };\n return `loads (SQLite ${row.v})`;\n } finally {\n db.close();\n }\n },\n async checkWritable(dir) {\n await mkdir(dir, { recursive: true });\n const probe = join(dir, `.doctor-${process.pid}.tmp`);\n await writeFile(probe, 'ok');\n await rm(probe, { force: true });\n },\n exists: existsSync,\n portInUse,\n async gatewayVersion(baseUrl, token) {\n const client = new GatewayClient({ baseUrl, ...(token ? { token } : {}) });\n try {\n return (await client.health(800))?.version;\n } catch {\n return undefined;\n }\n },\n which: (cmd) => which(cmd, ctx.env),\n async reachable(url) {\n try {\n await fetch(url, { signal: AbortSignal.timeout(800) });\n return true;\n } catch {\n return false;\n }\n },\n dashboardDir: () => resolveDashboardDir(ctx.env),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Command\n// ---------------------------------------------------------------------------\n\nexport function renderDoctor(ctx: Pick<CliContext, 'theme'>, results: CheckResult[]): string[] {\n const { theme } = ctx;\n const lines = [theme.bold(theme.accent('DaveCode doctor')), ''];\n const width = Math.max(...results.map((r) => r.label.length)) + 2;\n for (const r of results) {\n const mark =\n r.status === 'ok'\n ? theme.ok(theme.glyph.ok)\n : r.status === 'warn'\n ? theme.warn(theme.glyph.warn)\n : theme.error(theme.glyph.fail);\n const detail = r.status === 'ok' ? theme.dim(r.detail) : r.detail;\n lines.push(` ${mark} ${padEnd(r.label, width)} ${detail}`);\n if (r.fix && r.status !== 'ok')\n lines.push(` ${' '.repeat(width)}${theme.dim(`fix: ${r.fix}`)}`);\n }\n const count = (s: CheckStatus) => results.filter((r) => r.status === s).length;\n const fails = count('fail');\n const warns = count('warn');\n lines.push('');\n lines.push(\n [\n theme.ok(`${count('ok')} ok`),\n warns ? theme.warn(`${warns} warning${warns === 1 ? '' : 's'}`) : `${warns} warnings`,\n fails ? theme.error(`${fails} failure${fails === 1 ? '' : 's'}`) : '0 failures',\n ].join(theme.dim(' · ')),\n );\n return lines;\n}\n\nexport async function doctorCommand(\n ctx: CliContext,\n probes?: Partial<DoctorProbes>,\n): Promise<number> {\n const projectRoot = await detectProjectRoot(ctx.cwd, ctx.home);\n const merged: DoctorProbes = { ...defaultProbes(ctx, projectRoot), ...probes };\n const results = await runDoctor({ home: ctx.home, env: ctx.env }, merged);\n const failed = results.some((r) => r.status === 'fail');\n if (ctx.json) {\n printJson(ctx, { ok: !failed, checks: results });\n } else {\n for (const line of renderDoctor(ctx, results)) ctx.out(line);\n }\n return failed ? EXIT.failure : EXIT.ok;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { mkdir, rm, writeFile } from 'node:fs/promises';\nimport { createServer } from 'node:net';\nimport { join } from 'node:path';\nimport { type DaveConfig, loadConfig, openDatabase } from '@davecode/core';\nimport { connectHost, GatewayClient } from '../client';\nimport { type CliContext, printJson } from '../context';\nimport { EXIT } from '../errors';\nimport { which } from '../lib/proc';\nimport { detectProjectRoot, resolveDashboardDir } from '../runtime';\nimport { padEnd } from '../ui/format';\n\nexport type CheckStatus = 'ok' | 'warn' | 'fail';\n\nexport interface CheckResult {\n id: string;\n label: string;\n status: CheckStatus;\n detail: string;\n fix?: string;\n}\n\n/** Everything doctor touches outside its own logic, injectable for tests. */\nexport interface DoctorProbes {\n nodeVersion: string;\n loadConfig(): DaveConfig;\n /** Open an in-memory database; resolves with a detail string. */\n loadSqlite(): Promise<string>;\n /** Throws when `dir` cannot be created or written. */\n checkWritable(dir: string): Promise<void>;\n exists(path: string): boolean;\n portInUse(host: string, port: number): Promise<boolean>;\n /** Version of the DaveCode gateway answering on `baseUrl`, if any. */\n gatewayVersion(baseUrl: string, token?: string): Promise<string | undefined>;\n which(command: string): string | undefined;\n /** True when `url` answers with any HTTP response within the timeout. */\n reachable(url: string): Promise<boolean>;\n dashboardDir(): string | undefined;\n}\n\nexport interface DoctorInput {\n home: string;\n env: NodeJS.ProcessEnv;\n}\n\nconst MIN_NODE: [number, number] = [22, 12];\n\nexport function nodeVersionOk(version: string): boolean {\n const [major = 0, minor = 0] = version.replace(/^v/, '').split('.').map(Number);\n return major > MIN_NODE[0] || (major === MIN_NODE[0] && minor >= MIN_NODE[1]);\n}\n\nexport async function runDoctor(input: DoctorInput, probes: DoctorProbes): Promise<CheckResult[]> {\n const results: CheckResult[] = [];\n const add = (r: CheckResult) => results.push(r);\n\n add(\n nodeVersionOk(probes.nodeVersion)\n ? { id: 'node', label: 'Node.js', status: 'ok', detail: probes.nodeVersion }\n : {\n id: 'node',\n label: 'Node.js',\n status: 'fail',\n detail: `${probes.nodeVersion} (needs ${MIN_NODE.join('.')}+)`,\n fix: 'Install Node.js 22.12 or newer: https://nodejs.org',\n },\n );\n\n let config: DaveConfig | undefined;\n try {\n config = probes.loadConfig();\n add({ id: 'config', label: 'Config', status: 'ok', detail: 'valid' });\n } catch (err) {\n add({\n id: 'config',\n label: 'Config',\n status: 'fail',\n detail: (err as Error).message.split('\\n').slice(0, 3).join(' '),\n fix: 'Fix the file named above; `davecode config path` lists every config location.',\n });\n }\n\n try {\n add({ id: 'sqlite', label: 'better-sqlite3', status: 'ok', detail: await probes.loadSqlite() });\n } catch (err) {\n add({\n id: 'sqlite',\n label: 'better-sqlite3',\n status: 'fail',\n detail: `cannot load: ${(err as Error).message.split('\\n')[0]}`,\n fix: 'Rebuild the native module: pnpm rebuild better-sqlite3 (needs a C++ toolchain if no prebuilt binary matches your Node version).',\n });\n }\n\n try {\n await probes.checkWritable(input.home);\n add({ id: 'home', label: 'Home directory', status: 'ok', detail: `${input.home} is writable` });\n } catch (err) {\n add({\n id: 'home',\n label: 'Home directory',\n status: 'fail',\n detail: `${input.home} is not writable (${(err as NodeJS.ErrnoException).code ?? (err as Error).message})`,\n fix: 'Fix the permissions or point DaveCode elsewhere with --home <dir> / DAVECODE_HOME.',\n });\n }\n\n const keyPath = join(input.home, 'master.key');\n if (input.env.DAVECODE_MASTER_KEY) {\n add({\n id: 'master-key',\n label: 'Master key',\n status: 'ok',\n detail: 'from DAVECODE_MASTER_KEY',\n });\n } else if (probes.exists(keyPath)) {\n add({ id: 'master-key', label: 'Master key', status: 'ok', detail: keyPath });\n } else {\n add({\n id: 'master-key',\n label: 'Master key',\n status: 'warn',\n detail: 'not created yet',\n fix: 'It is generated on first use (davecode start or accounts add). Back it up: without it stored secrets cannot be decrypted.',\n });\n }\n\n if (config) {\n const { host, port, authToken } = config.server;\n const baseUrl = `http://${connectHost(host)}:${port}`;\n if (!(await probes.portInUse(host, port))) {\n add({ id: 'port', label: 'Gateway port', status: 'ok', detail: `${host}:${port} is free` });\n } else {\n const version = await probes.gatewayVersion(baseUrl, authToken);\n add(\n version\n ? {\n id: 'port',\n label: 'Gateway port',\n status: 'ok',\n detail: `DaveCode ${version} is already running at ${baseUrl}`,\n }\n : {\n id: 'port',\n label: 'Gateway port',\n status: 'fail',\n detail: `${host}:${port} is used by another program`,\n fix: `Stop it, or use another port: davecode start --port ${port + 1} (or DAVECODE_PORT).`,\n },\n );\n }\n }\n\n const tools: Array<{ cmd: string; label: string; required: boolean; why: string; fix: string }> =\n [\n {\n cmd: 'git',\n label: 'git',\n required: true,\n why: 'needed by the autonomous runner (task branches and merges)',\n fix: 'Install git: https://git-scm.com/downloads',\n },\n {\n cmd: 'claude',\n label: 'Claude Code CLI',\n required: false,\n why: 'only for claude-cli accounts',\n fix: 'npm install -g @anthropic-ai/claude-code',\n },\n {\n cmd: 'codex',\n label: 'Codex CLI',\n required: false,\n why: 'only for codex-cli accounts',\n fix: 'npm install -g @openai/codex',\n },\n {\n cmd: 'gemini',\n label: 'Gemini CLI',\n required: false,\n why: 'only for gemini-cli accounts',\n fix: 'npm install -g @google/gemini-cli',\n },\n {\n cmd: 'gh',\n label: 'GitHub CLI',\n required: false,\n why: 'optional, for opening pull requests',\n fix: 'Install gh: https://cli.github.com',\n },\n ];\n for (const tool of tools) {\n const path = probes.which(tool.cmd);\n add(\n path\n ? { id: tool.cmd, label: tool.label, status: 'ok', detail: path }\n : {\n id: tool.cmd,\n label: tool.label,\n status: tool.required ? 'fail' : 'warn',\n detail: `not found on PATH (${tool.why})`,\n fix: tool.fix,\n },\n );\n }\n\n const dashboard = probes.dashboardDir();\n add(\n dashboard\n ? { id: 'dashboard', label: 'Dashboard build', status: 'ok', detail: dashboard }\n : {\n id: 'dashboard',\n label: 'Dashboard build',\n status: 'warn',\n detail: 'not built (the gateway still works without it)',\n fix: 'pnpm --filter @davecode/ui build',\n },\n );\n\n return results;\n}\n\n// ---------------------------------------------------------------------------\n// Real probes\n// ---------------------------------------------------------------------------\n\nfunction portInUse(host: string, port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = createServer();\n server.once('error', (err: NodeJS.ErrnoException) => {\n resolve(err.code === 'EADDRINUSE' || err.code === 'EACCES');\n });\n server.listen({ host, port, exclusive: true }, () => {\n server.close(() => resolve(false));\n });\n });\n}\n\nexport function defaultProbes(\n ctx: Pick<CliContext, 'home' | 'env'>,\n projectRoot?: string,\n): DoctorProbes {\n return {\n nodeVersion: process.version,\n loadConfig: () =>\n loadConfig({ home: ctx.home, env: ctx.env, ...(projectRoot ? { projectRoot } : {}) }),\n async loadSqlite() {\n const db = openDatabase(':memory:');\n try {\n const row = db.prepare('select sqlite_version() as v').get() as { v: string };\n return `loads (SQLite ${row.v})`;\n } finally {\n db.close();\n }\n },\n async checkWritable(dir) {\n await mkdir(dir, { recursive: true });\n const probe = join(dir, `.doctor-${process.pid}.tmp`);\n await writeFile(probe, 'ok');\n await rm(probe, { force: true });\n },\n exists: existsSync,\n portInUse,\n async gatewayVersion(baseUrl, token) {\n const client = new GatewayClient({ baseUrl, ...(token ? { token } : {}) });\n try {\n return (await client.health(800))?.version;\n } catch {\n return undefined;\n }\n },\n which: (cmd) => which(cmd, ctx.env),\n async reachable(url) {\n try {\n await fetch(url, { signal: AbortSignal.timeout(800) });\n return true;\n } catch {\n return false;\n }\n },\n dashboardDir: () => resolveDashboardDir(ctx.env),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Command\n// ---------------------------------------------------------------------------\n\nexport function renderDoctor(ctx: Pick<CliContext, 'theme'>, results: CheckResult[]): string[] {\n const { theme } = ctx;\n const lines = [theme.bold(theme.accent('DaveCode doctor')), ''];\n const width = Math.max(...results.map((r) => r.label.length)) + 2;\n for (const r of results) {\n const mark =\n r.status === 'ok'\n ? theme.ok(theme.glyph.ok)\n : r.status === 'warn'\n ? theme.warn(theme.glyph.warn)\n : theme.error(theme.glyph.fail);\n const detail = r.status === 'ok' ? theme.dim(r.detail) : r.detail;\n lines.push(` ${mark} ${padEnd(r.label, width)} ${detail}`);\n if (r.fix && r.status !== 'ok')\n lines.push(` ${' '.repeat(width)}${theme.dim(`fix: ${r.fix}`)}`);\n }\n const count = (s: CheckStatus) => results.filter((r) => r.status === s).length;\n const fails = count('fail');\n const warns = count('warn');\n lines.push('');\n lines.push(\n [\n theme.ok(`${count('ok')} ok`),\n warns ? theme.warn(`${warns} warning${warns === 1 ? '' : 's'}`) : `${warns} warnings`,\n fails ? theme.error(`${fails} failure${fails === 1 ? '' : 's'}`) : '0 failures',\n ].join(theme.dim(' · ')),\n );\n return lines;\n}\n\nexport async function doctorCommand(\n ctx: CliContext,\n probes?: Partial<DoctorProbes>,\n): Promise<number> {\n const projectRoot = await detectProjectRoot(ctx.cwd, ctx.home);\n const merged: DoctorProbes = { ...defaultProbes(ctx, projectRoot), ...probes };\n const results = await runDoctor({ home: ctx.home, env: ctx.env }, merged);\n const failed = results.some((r) => r.status === 'fail');\n if (ctx.json) {\n printJson(ctx, { ok: !failed, checks: results });\n } else {\n for (const line of renderDoctor(ctx, results)) ctx.out(line);\n }\n return failed ? EXIT.failure : EXIT.ok;\n}\n"],"mappings":"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","names":[]}
@@ -9,17 +9,18 @@ import {
9
9
  detectProjectRoot,
10
10
  findGateway,
11
11
  wireProject
12
- } from "./chunk-FYPMA55O.js";
12
+ } from "./chunk-KUY3QHGS.js";
13
13
  import {
14
14
  CliError,
15
15
  EXIT
16
16
  } from "./chunk-7XVXEO7U.js";
17
+ import "./chunk-732GIHRQ.js";
17
18
  import {
18
19
  GoalStore,
19
20
  createEngine,
20
21
  isTerminalGoal,
21
22
  loadConfig
22
- } from "./chunk-HSBJDV3O.js";
23
+ } from "./chunk-QKY3OKVG.js";
23
24
  import "./chunk-MC7RIPL7.js";
24
25
 
25
26
  // src/commands/goal.ts
@@ -299,4 +300,4 @@ export {
299
300
  goalsList,
300
301
  goalsShow
301
302
  };
302
- //# sourceMappingURL=goal-SXZUDUCL.js.map
303
+ //# sourceMappingURL=goal-STLEU7C7.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/goal.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport {\n createEngine,\n type DaveEvent,\n type Engine,\n type Goal,\n GoalStore,\n isTerminalGoal,\n loadConfig,\n} from '@davecode/core';\nimport { findGateway, type GatewayClient, GatewayError } from '../client';\nimport { type CliContext, printJson } from '../context';\nimport { CliError, EXIT } from '../errors';\nimport { detectProjectRoot, wireProject } from '../runtime';\nimport { formatDuration } from '../ui/format';\nimport type { Theme } from '../ui/theme';\n\nexport interface GoalOptions {\n maxRounds?: number;\n maxTasks?: number;\n maxTokens?: number;\n dryRun?: boolean;\n project?: string;\n}\n\n/** Goal control used by the command: in-process `GoalService` or the gateway's `/api/goals`. */\ninterface GoalBackend {\n start(input: GoalStartBody): Promise<Goal>;\n cancel(id: string): Promise<Goal>;\n /** Resolves with the finished goal. */\n wait(id: string): Promise<Goal>;\n}\n\ninterface GoalStartBody {\n objective: string;\n maxRounds?: number;\n maxTasks?: number;\n maxTokens?: number;\n dryRun?: boolean;\n}\n\n/** Test seams. */\nexport interface GoalDeps {\n engine?: Engine;\n /** Resolves when the user asks to stop (default: SIGINT/SIGTERM). */\n interrupt?: () => Promise<void>;\n noGateway?: boolean;\n}\n\nasync function projectRoot(ctx: CliContext, project?: string): Promise<string> {\n const root = project ? resolve(ctx.cwd, project) : await detectProjectRoot(ctx.cwd, ctx.home);\n if (!root || !existsSync(root)) {\n throw new CliError('Not inside a project', {\n hint: 'Run goal mode inside a repository with a project brain (`git init` and `davecode init`).',\n });\n }\n return root;\n}\n\nfunction interruptSignal(deps: GoalDeps): { promise: Promise<void>; dispose(): void } {\n if (deps.interrupt) return { promise: deps.interrupt(), dispose: () => {} };\n let dispose = () => {};\n const promise = new Promise<void>((done) => {\n const handler = () => {\n dispose();\n done();\n };\n dispose = () => {\n process.off('SIGINT', handler);\n process.off('SIGTERM', handler);\n };\n process.on('SIGINT', handler);\n process.on('SIGTERM', handler);\n });\n return { promise, dispose };\n}\n\nfunction explainGoalError(err: unknown): unknown {\n const code =\n err instanceof GatewayError ? err.code : (err as { code?: unknown } | undefined)?.code;\n const message = err instanceof Error ? err.message : String(err);\n if (code === 'busy') {\n return new CliError(message, {\n hint: 'Wait for the runner or the other goal to finish, or stop it from the dashboard.',\n });\n }\n if (code === 'goals_unavailable') {\n return new CliError('The running gateway has no project to run goals in', {\n hint: 'Restart `davecode start` inside this repository, or stop it so `davecode goal` runs in-process.',\n });\n }\n return err;\n}\n\n// ---------------------------------------------------------------------------\n// Printing\n// ---------------------------------------------------------------------------\n\nconst STATUS_GLYPH: Record<Goal['tasks'][number]['status'], (t: Theme) => string> = {\n SUCCESS: (t) => t.ok(t.glyph.success),\n FAILED: (t) => t.error(t.glyph.failed),\n IN_PROGRESS: (t) => t.accent(t.glyph.running),\n PENDING: (t) => t.dim(t.glyph.pending),\n};\n\nfunction printEvent(ctx: CliContext, goalId: string, event: DaveEvent): void {\n if (event.type !== 'goal.log' || event.goalId !== goalId || event.level === 'debug') return;\n const theme = ctx.errTheme;\n const time = new Date(event.ts).toTimeString().slice(0, 8);\n const who = event.role ? theme.accent(`[${event.role}]`) : theme.dim('[goal]');\n const message =\n event.level === 'error'\n ? theme.error(event.message)\n : event.level === 'warn'\n ? theme.warn(event.message)\n : event.message;\n ctx.err(`${theme.dim(time)} ${who} ${message}`);\n}\n\nexport function describeGoal(theme: Theme, goal: Goal): string[] {\n const lines: string[] = [];\n const colour =\n goal.status === 'succeeded' || goal.status === 'planned'\n ? theme.ok\n : goal.status === 'cancelled' || goal.status === 'budget_exhausted'\n ? theme.warn\n : goal.status === 'failed'\n ? theme.error\n : theme.accent;\n lines.push(\n `${theme.bold(goal.id)} ${colour(goal.status)} ${theme.dim(`round ${goal.round}/${goal.limits.maxRounds}`)}`,\n );\n lines.push(` ${goal.objective}`);\n lines.push(\n theme.dim(\n ` tokens ${goal.limits.tokensUsed.toLocaleString('en-US')} / ${goal.limits.maxTokens.toLocaleString('en-US')} · tasks ${goal.tasks.length} / ${goal.limits.maxTasks}`,\n ),\n );\n if (goal.tasks.length > 0) lines.push('');\n for (const task of goal.tasks) {\n const glyph = STATUS_GLYPH[task.status](theme);\n lines.push(\n `${glyph} ${theme.bold(task.id)} ${theme.dim(`${task.role}·${task.kind}`)} ${task.title}`,\n );\n if (task.artifact) lines.push(theme.dim(` ${task.artifact}`));\n else if (task.status === 'FAILED' && task.notes) {\n lines.push(theme.dim(` ${task.notes.split('\\n')[0]?.slice(0, 160) ?? ''}`));\n }\n }\n if (goal.summary) lines.push('', goal.summary.trim());\n if (goal.lastError) lines.push('', theme.error(goal.lastError));\n return lines;\n}\n\nexport function goalExitCode(goal: Goal): number {\n if (goal.status === 'succeeded' || goal.status === 'planned') return EXIT.ok;\n if (goal.status === 'cancelled') return 130;\n return EXIT.failure;\n}\n\n// ---------------------------------------------------------------------------\n// Backends\n// ---------------------------------------------------------------------------\n\nfunction gatewayBackend(\n client: GatewayClient,\n onEvent: (e: DaveEvent) => void,\n): {\n backend: GoalBackend;\n close(): Promise<void>;\n} {\n const controller = new AbortController();\n const finished = new Map<string, (goal: Goal) => void>();\n const pump = (async () => {\n try {\n for await (const event of client.events(controller.signal)) {\n onEvent(event);\n if (event.type === 'goal.updated' && isTerminalGoal(event.goal)) {\n finished.get(event.goal.id)?.(event.goal);\n }\n }\n } catch {\n // aborted or disconnected\n }\n })();\n const backend: GoalBackend = {\n start: async (input) => (await client.post<{ goal: Goal }>('/api/goals', input)).goal,\n cancel: async (id) =>\n (\n await client.post<{ goal: Goal }>(`/api/goals/${id}/cancel`, undefined, {\n timeoutMs: 10 * 60_000,\n })\n ).goal,\n wait: (id) =>\n new Promise<Goal>((resolveGoal) => {\n finished.set(id, resolveGoal);\n // The goal may have finished before the listener was registered.\n void client\n .get<{ goal: Goal }>(`/api/goals/${id}`)\n .then(({ goal }) => {\n if (isTerminalGoal(goal)) resolveGoal(goal);\n })\n .catch(() => undefined);\n }),\n };\n return {\n backend,\n close: async () => {\n controller.abort();\n await pump;\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Commands\n// ---------------------------------------------------------------------------\n\n/** `davecode goal \"<objective>\"`: plan and run a goal with the agent team, following its log. */\nexport async function goalCommand(\n ctx: CliContext,\n words: string[],\n opts: GoalOptions,\n deps: GoalDeps = {},\n): Promise<number> {\n const objective = words.join(' ').trim();\n if (!objective)\n throw new CliError('Describe the objective', {\n hint: 'davecode goal \"Launch a landing page for my app\"',\n });\n const root = await projectRoot(ctx, opts.project);\n const input: GoalStartBody = {\n objective,\n ...(opts.maxRounds !== undefined ? { maxRounds: opts.maxRounds } : {}),\n ...(opts.maxTasks !== undefined ? { maxTasks: opts.maxTasks } : {}),\n ...(opts.maxTokens !== undefined ? { maxTokens: opts.maxTokens } : {}),\n ...(opts.dryRun ? { dryRun: true } : {}),\n };\n\n const config =\n deps.engine?.config ?? loadConfig({ home: ctx.home, env: ctx.env, projectRoot: root });\n const gateway = deps.noGateway ? undefined : await findGateway(config).catch(() => undefined);\n let goalId: string | undefined;\n const onEvent = (event: DaveEvent) => {\n if (goalId) printEvent(ctx, goalId, event);\n };\n\n let engine: Engine | undefined;\n let backend: GoalBackend;\n let close: () => Promise<void>;\n if (gateway) {\n const remote = gatewayBackend(gateway.client, onEvent);\n backend = remote.backend;\n close = remote.close;\n if (!ctx.json) ctx.err(ctx.errTheme.dim(`Using the gateway at ${gateway.client.baseUrl}`));\n } else {\n engine = deps.engine ?? createEngine({ home: ctx.home, env: ctx.env, projectRoot: root });\n const { goals } = wireProject(engine, root, { env: ctx.env });\n const unsubscribe = engine.events.subscribe(onEvent);\n backend = {\n start: (body) => goals.start(body),\n cancel: (id) => goals.cancel(id),\n wait: async (id) => {\n const goal = await goals.wait(id);\n if (!goal) throw new CliError(`Goal ${id} disappeared`);\n return goal;\n },\n };\n const owned = !deps.engine;\n const used = engine;\n close = async () => {\n unsubscribe();\n if (owned) used.close();\n };\n }\n\n const interrupt = interruptSignal(deps);\n const started = Date.now();\n try {\n let goal: Goal;\n try {\n goal = await backend.start(input);\n } catch (err) {\n throw explainGoalError(err);\n }\n goalId = goal.id;\n if (!ctx.json) {\n ctx.err(\n ctx.errTheme.dim(\n `Goal ${goal.id} started${input.dryRun ? ' (dry run: plan only)' : ''}. Ctrl+C cancels.`,\n ),\n );\n }\n let cancelling = false;\n void interrupt.promise.then(() => {\n cancelling = true;\n if (!ctx.json) ctx.err(ctx.errTheme.dim('Cancelling…'));\n void backend.cancel(goal.id).catch(() => undefined);\n });\n goal = await backend.wait(goal.id);\n if (ctx.json) printJson(ctx, { goal, cancelled: cancelling });\n else {\n ctx.out();\n for (const line of describeGoal(ctx.theme, goal)) ctx.out(line);\n ctx.out(ctx.theme.dim(` took ${formatDuration((Date.now() - started) / 1000)}`));\n if (goal.tasks.some((t) => t.artifact)) {\n ctx.out(ctx.theme.dim(` artifacts in ${root}`));\n }\n }\n return goalExitCode(goal);\n } finally {\n interrupt.dispose();\n await close();\n }\n}\n\n/** `davecode goals`: goals of this repository, newest first (read from `.davecode/goals`). */\nexport async function goalsList(ctx: CliContext, opts: { project?: string }): Promise<number> {\n const root = await projectRoot(ctx, opts.project);\n const goals = await new GoalStore(root).list();\n if (ctx.json) {\n printJson(ctx, { goals });\n return EXIT.ok;\n }\n if (goals.length === 0) {\n ctx.out(ctx.theme.dim('No goals yet. Start one with `davecode goal \"<objective>\"`.'));\n return EXIT.ok;\n }\n for (const goal of goals) {\n const done = goal.tasks.filter((t) => t.status === 'SUCCESS').length;\n ctx.out(\n `${ctx.theme.bold(goal.id)} ${goal.status.padEnd(16)} ${ctx.theme.dim(`${done}/${goal.tasks.length} tasks · ${goal.createdAt.slice(0, 16).replace('T', ' ')}`)} ${goal.objective.slice(0, 80)}`,\n );\n }\n return EXIT.ok;\n}\n\n/** `davecode goals show <id>`. */\nexport async function goalsShow(\n ctx: CliContext,\n id: string,\n opts: { project?: string },\n): Promise<number> {\n const root = await projectRoot(ctx, opts.project);\n const goal = await new GoalStore(root).load(id);\n if (!goal)\n throw new CliError(`Unknown goal \"${id}\"`, { hint: 'See `davecode goals` for the ids.' });\n if (ctx.json) printJson(ctx, { goal });\n else for (const line of describeGoal(ctx.theme, goal)) ctx.out(line);\n return EXIT.ok;\n}\n\n/** `davecode goals cancel <id>`: through the gateway when one runs it, else marks it cancelled. */\nexport async function goalsCancel(\n ctx: CliContext,\n id: string,\n opts: { project?: string },\n deps: GoalDeps = {},\n): Promise<number> {\n const root = await projectRoot(ctx, opts.project);\n const config =\n deps.engine?.config ?? loadConfig({ home: ctx.home, env: ctx.env, projectRoot: root });\n const gateway = deps.noGateway ? undefined : await findGateway(config).catch(() => undefined);\n let goal: Goal;\n if (gateway) {\n goal = (\n await gateway.client.post<{ goal: Goal }>(`/api/goals/${id}/cancel`, undefined, {\n timeoutMs: 10 * 60_000,\n })\n ).goal;\n } else {\n const store = new GoalStore(root);\n const stored = await store.load(id);\n if (!stored)\n throw new CliError(`Unknown goal \"${id}\"`, { hint: 'See `davecode goals` for the ids.' });\n goal = stored;\n if (!isTerminalGoal(goal)) {\n const stamp = new Date().toISOString();\n goal.status = 'cancelled';\n goal.updatedAt = stamp;\n goal.finishedAt = stamp;\n delete goal.activeTaskId;\n await store.save(goal);\n }\n }\n if (ctx.json) printJson(ctx, { goal });\n else ctx.out(`${ctx.theme.bold(goal.id)} ${goal.status}`);\n return EXIT.ok;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/goal.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport {\n createEngine,\n type DaveEvent,\n type Engine,\n type Goal,\n GoalStore,\n isTerminalGoal,\n loadConfig,\n} from '@davecode/core';\nimport { findGateway, type GatewayClient, GatewayError } from '../client';\nimport { type CliContext, printJson } from '../context';\nimport { CliError, EXIT } from '../errors';\nimport { detectProjectRoot, wireProject } from '../runtime';\nimport { formatDuration } from '../ui/format';\nimport type { Theme } from '../ui/theme';\n\nexport interface GoalOptions {\n maxRounds?: number;\n maxTasks?: number;\n maxTokens?: number;\n dryRun?: boolean;\n project?: string;\n}\n\n/** Goal control used by the command: in-process `GoalService` or the gateway's `/api/goals`. */\ninterface GoalBackend {\n start(input: GoalStartBody): Promise<Goal>;\n cancel(id: string): Promise<Goal>;\n /** Resolves with the finished goal. */\n wait(id: string): Promise<Goal>;\n}\n\ninterface GoalStartBody {\n objective: string;\n maxRounds?: number;\n maxTasks?: number;\n maxTokens?: number;\n dryRun?: boolean;\n}\n\n/** Test seams. */\nexport interface GoalDeps {\n engine?: Engine;\n /** Resolves when the user asks to stop (default: SIGINT/SIGTERM). */\n interrupt?: () => Promise<void>;\n noGateway?: boolean;\n}\n\nasync function projectRoot(ctx: CliContext, project?: string): Promise<string> {\n const root = project ? resolve(ctx.cwd, project) : await detectProjectRoot(ctx.cwd, ctx.home);\n if (!root || !existsSync(root)) {\n throw new CliError('Not inside a project', {\n hint: 'Run goal mode inside a repository with a project brain (`git init` and `davecode init`).',\n });\n }\n return root;\n}\n\nfunction interruptSignal(deps: GoalDeps): { promise: Promise<void>; dispose(): void } {\n if (deps.interrupt) return { promise: deps.interrupt(), dispose: () => {} };\n let dispose = () => {};\n const promise = new Promise<void>((done) => {\n const handler = () => {\n dispose();\n done();\n };\n dispose = () => {\n process.off('SIGINT', handler);\n process.off('SIGTERM', handler);\n };\n process.on('SIGINT', handler);\n process.on('SIGTERM', handler);\n });\n return { promise, dispose };\n}\n\nfunction explainGoalError(err: unknown): unknown {\n const code =\n err instanceof GatewayError ? err.code : (err as { code?: unknown } | undefined)?.code;\n const message = err instanceof Error ? err.message : String(err);\n if (code === 'busy') {\n return new CliError(message, {\n hint: 'Wait for the runner or the other goal to finish, or stop it from the dashboard.',\n });\n }\n if (code === 'goals_unavailable') {\n return new CliError('The running gateway has no project to run goals in', {\n hint: 'Restart `davecode start` inside this repository, or stop it so `davecode goal` runs in-process.',\n });\n }\n return err;\n}\n\n// ---------------------------------------------------------------------------\n// Printing\n// ---------------------------------------------------------------------------\n\nconst STATUS_GLYPH: Record<Goal['tasks'][number]['status'], (t: Theme) => string> = {\n SUCCESS: (t) => t.ok(t.glyph.success),\n FAILED: (t) => t.error(t.glyph.failed),\n IN_PROGRESS: (t) => t.accent(t.glyph.running),\n PENDING: (t) => t.dim(t.glyph.pending),\n};\n\nfunction printEvent(ctx: CliContext, goalId: string, event: DaveEvent): void {\n if (event.type !== 'goal.log' || event.goalId !== goalId || event.level === 'debug') return;\n const theme = ctx.errTheme;\n const time = new Date(event.ts).toTimeString().slice(0, 8);\n const who = event.role ? theme.accent(`[${event.role}]`) : theme.dim('[goal]');\n const message =\n event.level === 'error'\n ? theme.error(event.message)\n : event.level === 'warn'\n ? theme.warn(event.message)\n : event.message;\n ctx.err(`${theme.dim(time)} ${who} ${message}`);\n}\n\nexport function describeGoal(theme: Theme, goal: Goal): string[] {\n const lines: string[] = [];\n const colour =\n goal.status === 'succeeded' || goal.status === 'planned'\n ? theme.ok\n : goal.status === 'cancelled' || goal.status === 'budget_exhausted'\n ? theme.warn\n : goal.status === 'failed'\n ? theme.error\n : theme.accent;\n lines.push(\n `${theme.bold(goal.id)} ${colour(goal.status)} ${theme.dim(`round ${goal.round}/${goal.limits.maxRounds}`)}`,\n );\n lines.push(` ${goal.objective}`);\n lines.push(\n theme.dim(\n ` tokens ${goal.limits.tokensUsed.toLocaleString('en-US')} / ${goal.limits.maxTokens.toLocaleString('en-US')} · tasks ${goal.tasks.length} / ${goal.limits.maxTasks}`,\n ),\n );\n if (goal.tasks.length > 0) lines.push('');\n for (const task of goal.tasks) {\n const glyph = STATUS_GLYPH[task.status](theme);\n lines.push(\n `${glyph} ${theme.bold(task.id)} ${theme.dim(`${task.role}·${task.kind}`)} ${task.title}`,\n );\n if (task.artifact) lines.push(theme.dim(` ${task.artifact}`));\n else if (task.status === 'FAILED' && task.notes) {\n lines.push(theme.dim(` ${task.notes.split('\\n')[0]?.slice(0, 160) ?? ''}`));\n }\n }\n if (goal.summary) lines.push('', goal.summary.trim());\n if (goal.lastError) lines.push('', theme.error(goal.lastError));\n return lines;\n}\n\nexport function goalExitCode(goal: Goal): number {\n if (goal.status === 'succeeded' || goal.status === 'planned') return EXIT.ok;\n if (goal.status === 'cancelled') return 130;\n return EXIT.failure;\n}\n\n// ---------------------------------------------------------------------------\n// Backends\n// ---------------------------------------------------------------------------\n\nfunction gatewayBackend(\n client: GatewayClient,\n onEvent: (e: DaveEvent) => void,\n): {\n backend: GoalBackend;\n close(): Promise<void>;\n} {\n const controller = new AbortController();\n const finished = new Map<string, (goal: Goal) => void>();\n const pump = (async () => {\n try {\n for await (const event of client.events(controller.signal)) {\n onEvent(event);\n if (event.type === 'goal.updated' && isTerminalGoal(event.goal)) {\n finished.get(event.goal.id)?.(event.goal);\n }\n }\n } catch {\n // aborted or disconnected\n }\n })();\n const backend: GoalBackend = {\n start: async (input) => (await client.post<{ goal: Goal }>('/api/goals', input)).goal,\n cancel: async (id) =>\n (\n await client.post<{ goal: Goal }>(`/api/goals/${id}/cancel`, undefined, {\n timeoutMs: 10 * 60_000,\n })\n ).goal,\n wait: (id) =>\n new Promise<Goal>((resolveGoal) => {\n finished.set(id, resolveGoal);\n // The goal may have finished before the listener was registered.\n void client\n .get<{ goal: Goal }>(`/api/goals/${id}`)\n .then(({ goal }) => {\n if (isTerminalGoal(goal)) resolveGoal(goal);\n })\n .catch(() => undefined);\n }),\n };\n return {\n backend,\n close: async () => {\n controller.abort();\n await pump;\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Commands\n// ---------------------------------------------------------------------------\n\n/** `davecode goal \"<objective>\"`: plan and run a goal with the agent team, following its log. */\nexport async function goalCommand(\n ctx: CliContext,\n words: string[],\n opts: GoalOptions,\n deps: GoalDeps = {},\n): Promise<number> {\n const objective = words.join(' ').trim();\n if (!objective)\n throw new CliError('Describe the objective', {\n hint: 'davecode goal \"Launch a landing page for my app\"',\n });\n const root = await projectRoot(ctx, opts.project);\n const input: GoalStartBody = {\n objective,\n ...(opts.maxRounds !== undefined ? { maxRounds: opts.maxRounds } : {}),\n ...(opts.maxTasks !== undefined ? { maxTasks: opts.maxTasks } : {}),\n ...(opts.maxTokens !== undefined ? { maxTokens: opts.maxTokens } : {}),\n ...(opts.dryRun ? { dryRun: true } : {}),\n };\n\n const config =\n deps.engine?.config ?? loadConfig({ home: ctx.home, env: ctx.env, projectRoot: root });\n const gateway = deps.noGateway ? undefined : await findGateway(config).catch(() => undefined);\n let goalId: string | undefined;\n const onEvent = (event: DaveEvent) => {\n if (goalId) printEvent(ctx, goalId, event);\n };\n\n let engine: Engine | undefined;\n let backend: GoalBackend;\n let close: () => Promise<void>;\n if (gateway) {\n const remote = gatewayBackend(gateway.client, onEvent);\n backend = remote.backend;\n close = remote.close;\n if (!ctx.json) ctx.err(ctx.errTheme.dim(`Using the gateway at ${gateway.client.baseUrl}`));\n } else {\n engine = deps.engine ?? createEngine({ home: ctx.home, env: ctx.env, projectRoot: root });\n const { goals } = wireProject(engine, root, { env: ctx.env });\n const unsubscribe = engine.events.subscribe(onEvent);\n backend = {\n start: (body) => goals.start(body),\n cancel: (id) => goals.cancel(id),\n wait: async (id) => {\n const goal = await goals.wait(id);\n if (!goal) throw new CliError(`Goal ${id} disappeared`);\n return goal;\n },\n };\n const owned = !deps.engine;\n const used = engine;\n close = async () => {\n unsubscribe();\n if (owned) used.close();\n };\n }\n\n const interrupt = interruptSignal(deps);\n const started = Date.now();\n try {\n let goal: Goal;\n try {\n goal = await backend.start(input);\n } catch (err) {\n throw explainGoalError(err);\n }\n goalId = goal.id;\n if (!ctx.json) {\n ctx.err(\n ctx.errTheme.dim(\n `Goal ${goal.id} started${input.dryRun ? ' (dry run: plan only)' : ''}. Ctrl+C cancels.`,\n ),\n );\n }\n let cancelling = false;\n void interrupt.promise.then(() => {\n cancelling = true;\n if (!ctx.json) ctx.err(ctx.errTheme.dim('Cancelling…'));\n void backend.cancel(goal.id).catch(() => undefined);\n });\n goal = await backend.wait(goal.id);\n if (ctx.json) printJson(ctx, { goal, cancelled: cancelling });\n else {\n ctx.out();\n for (const line of describeGoal(ctx.theme, goal)) ctx.out(line);\n ctx.out(ctx.theme.dim(` took ${formatDuration((Date.now() - started) / 1000)}`));\n if (goal.tasks.some((t) => t.artifact)) {\n ctx.out(ctx.theme.dim(` artifacts in ${root}`));\n }\n }\n return goalExitCode(goal);\n } finally {\n interrupt.dispose();\n await close();\n }\n}\n\n/** `davecode goals`: goals of this repository, newest first (read from `.davecode/goals`). */\nexport async function goalsList(ctx: CliContext, opts: { project?: string }): Promise<number> {\n const root = await projectRoot(ctx, opts.project);\n const goals = await new GoalStore(root).list();\n if (ctx.json) {\n printJson(ctx, { goals });\n return EXIT.ok;\n }\n if (goals.length === 0) {\n ctx.out(ctx.theme.dim('No goals yet. Start one with `davecode goal \"<objective>\"`.'));\n return EXIT.ok;\n }\n for (const goal of goals) {\n const done = goal.tasks.filter((t) => t.status === 'SUCCESS').length;\n ctx.out(\n `${ctx.theme.bold(goal.id)} ${goal.status.padEnd(16)} ${ctx.theme.dim(`${done}/${goal.tasks.length} tasks · ${goal.createdAt.slice(0, 16).replace('T', ' ')}`)} ${goal.objective.slice(0, 80)}`,\n );\n }\n return EXIT.ok;\n}\n\n/** `davecode goals show <id>`. */\nexport async function goalsShow(\n ctx: CliContext,\n id: string,\n opts: { project?: string },\n): Promise<number> {\n const root = await projectRoot(ctx, opts.project);\n const goal = await new GoalStore(root).load(id);\n if (!goal)\n throw new CliError(`Unknown goal \"${id}\"`, { hint: 'See `davecode goals` for the ids.' });\n if (ctx.json) printJson(ctx, { goal });\n else for (const line of describeGoal(ctx.theme, goal)) ctx.out(line);\n return EXIT.ok;\n}\n\n/** `davecode goals cancel <id>`: through the gateway when one runs it, else marks it cancelled. */\nexport async function goalsCancel(\n ctx: CliContext,\n id: string,\n opts: { project?: string },\n deps: GoalDeps = {},\n): Promise<number> {\n const root = await projectRoot(ctx, opts.project);\n const config =\n deps.engine?.config ?? loadConfig({ home: ctx.home, env: ctx.env, projectRoot: root });\n const gateway = deps.noGateway ? undefined : await findGateway(config).catch(() => undefined);\n let goal: Goal;\n if (gateway) {\n goal = (\n await gateway.client.post<{ goal: Goal }>(`/api/goals/${id}/cancel`, undefined, {\n timeoutMs: 10 * 60_000,\n })\n ).goal;\n } else {\n const store = new GoalStore(root);\n const stored = await store.load(id);\n if (!stored)\n throw new CliError(`Unknown goal \"${id}\"`, { hint: 'See `davecode goals` for the ids.' });\n goal = stored;\n if (!isTerminalGoal(goal)) {\n const stamp = new Date().toISOString();\n goal.status = 'cancelled';\n goal.updatedAt = stamp;\n goal.finishedAt = stamp;\n delete goal.activeTaskId;\n await store.save(goal);\n }\n }\n if (ctx.json) printJson(ctx, { goal });\n else ctx.out(`${ctx.theme.bold(goal.id)} ${goal.status}`);\n return EXIT.ok;\n}\n"],"mappings":"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","names":[]}