devworkspace 0.1.0 → 0.2.0

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 (115) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +16 -2
  3. package/dist/agents/claude/adapter.d.ts +5 -0
  4. package/dist/agents/claude/adapter.js +10 -0
  5. package/dist/agents/claude/adapter.js.map +1 -1
  6. package/dist/agents/claude/content.js +3 -3
  7. package/dist/agents/claude/content.js.map +1 -1
  8. package/dist/cli/args.d.ts +22 -0
  9. package/dist/cli/args.js +7 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/help.js +54 -7
  12. package/dist/cli/help.js.map +1 -1
  13. package/dist/cli/render.d.ts +9 -0
  14. package/dist/cli/render.js +105 -13
  15. package/dist/cli/render.js.map +1 -1
  16. package/dist/cli/run.d.ts +6 -0
  17. package/dist/cli/run.js +75 -3
  18. package/dist/cli/run.js.map +1 -1
  19. package/dist/core/workspace.js +2 -1
  20. package/dist/core/workspace.js.map +1 -1
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.js +2 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/integrations/adapters/agent-skills.d.ts +8 -0
  25. package/dist/integrations/adapters/agent-skills.js +25 -0
  26. package/dist/integrations/adapters/agent-skills.js.map +1 -0
  27. package/dist/integrations/adapters/claudePlugin.d.ts +41 -0
  28. package/dist/integrations/adapters/claudePlugin.js +129 -0
  29. package/dist/integrations/adapters/claudePlugin.js.map +1 -0
  30. package/dist/integrations/adapters/graphify.d.ts +2 -0
  31. package/dist/integrations/adapters/graphify.js +239 -0
  32. package/dist/integrations/adapters/graphify.js.map +1 -0
  33. package/dist/integrations/adapters/omniroute.d.ts +6 -0
  34. package/dist/integrations/adapters/omniroute.js +32 -0
  35. package/dist/integrations/adapters/omniroute.js.map +1 -0
  36. package/dist/integrations/adapters/pluginSkill.d.ts +28 -0
  37. package/dist/integrations/adapters/pluginSkill.js +195 -0
  38. package/dist/integrations/adapters/pluginSkill.js.map +1 -0
  39. package/dist/integrations/adapters/ponytail.d.ts +8 -0
  40. package/dist/integrations/adapters/ponytail.js +33 -0
  41. package/dist/integrations/adapters/ponytail.js.map +1 -0
  42. package/dist/integrations/exec.d.ts +26 -0
  43. package/dist/integrations/exec.js +167 -0
  44. package/dist/integrations/exec.js.map +1 -0
  45. package/dist/integrations/index.d.ts +5 -6
  46. package/dist/integrations/index.js +3 -29
  47. package/dist/integrations/index.js.map +1 -1
  48. package/dist/integrations/manager.d.ts +62 -0
  49. package/dist/integrations/manager.js +248 -0
  50. package/dist/integrations/manager.js.map +1 -0
  51. package/dist/integrations/notices.d.ts +13 -0
  52. package/dist/integrations/notices.js +68 -0
  53. package/dist/integrations/notices.js.map +1 -0
  54. package/dist/integrations/protect.d.ts +20 -0
  55. package/dist/integrations/protect.js +131 -0
  56. package/dist/integrations/protect.js.map +1 -0
  57. package/dist/integrations/state.d.ts +10 -0
  58. package/dist/integrations/state.js +81 -0
  59. package/dist/integrations/state.js.map +1 -0
  60. package/dist/integrations/types.d.ts +133 -16
  61. package/dist/integrations/types.js +13 -1
  62. package/dist/integrations/types.js.map +1 -1
  63. package/dist/prompts/onboarding.d.ts +3 -3
  64. package/dist/prompts/onboarding.js +5 -4
  65. package/dist/prompts/onboarding.js.map +1 -1
  66. package/dist/services/analysis.d.ts +2 -2
  67. package/dist/services/analysis.js +4 -5
  68. package/dist/services/analysis.js.map +1 -1
  69. package/dist/services/common.d.ts +8 -5
  70. package/dist/services/common.js +2 -5
  71. package/dist/services/common.js.map +1 -1
  72. package/dist/services/doctor.d.ts +10 -0
  73. package/dist/services/doctor.js +9 -15
  74. package/dist/services/doctor.js.map +1 -1
  75. package/dist/services/init.d.ts +9 -2
  76. package/dist/services/init.js +10 -7
  77. package/dist/services/init.js.map +1 -1
  78. package/dist/services/integrations.d.ts +26 -0
  79. package/dist/services/integrations.js +35 -0
  80. package/dist/services/integrations.js.map +1 -0
  81. package/dist/services/reset.d.ts +23 -0
  82. package/dist/services/reset.js +96 -0
  83. package/dist/services/reset.js.map +1 -0
  84. package/dist/services/status.d.ts +3 -2
  85. package/dist/services/status.js +3 -3
  86. package/dist/services/status.js.map +1 -1
  87. package/dist/utils/lock.d.ts +2 -0
  88. package/dist/utils/lock.js +2 -2
  89. package/dist/utils/lock.js.map +1 -1
  90. package/dist/utils/proc.d.ts +8 -1
  91. package/dist/utils/proc.js +31 -8
  92. package/dist/utils/proc.js.map +1 -1
  93. package/docs/architecture.md +1 -1
  94. package/docs/claude.md +4 -0
  95. package/docs/getting-started.md +13 -2
  96. package/docs/integrations.md +98 -33
  97. package/docs/security.md +5 -1
  98. package/docs/testing.md +2 -0
  99. package/docs/troubleshooting.md +9 -1
  100. package/package.json +1 -1
  101. package/dist/integrations/agent-skills.d.ts +0 -10
  102. package/dist/integrations/agent-skills.js +0 -45
  103. package/dist/integrations/agent-skills.js.map +0 -1
  104. package/dist/integrations/graphify.d.ts +0 -7
  105. package/dist/integrations/graphify.js +0 -54
  106. package/dist/integrations/graphify.js.map +0 -1
  107. package/dist/integrations/omniroute.d.ts +0 -7
  108. package/dist/integrations/omniroute.js +0 -24
  109. package/dist/integrations/omniroute.js.map +0 -1
  110. package/dist/integrations/ponytail.d.ts +0 -10
  111. package/dist/integrations/ponytail.js +0 -58
  112. package/dist/integrations/ponytail.js.map +0 -1
  113. package/dist/integrations/probe.d.ts +0 -6
  114. package/dist/integrations/probe.js +0 -41
  115. package/dist/integrations/probe.js.map +0 -1
@@ -1,4 +1,5 @@
1
- import type { IntegrationContext } from '../integrations/types.js';
1
+ import type { ManagerEnv } from '../integrations/manager.js';
2
+ import type { Runner } from '../integrations/types.js';
2
3
  import { type Ws } from '../core/workspace.js';
3
4
  export interface ServiceOptions {
4
5
  /** Directory the command was started in. */
@@ -6,13 +7,15 @@ export interface ServiceOptions {
6
7
  dryRun?: boolean;
7
8
  /** Injectable clock for deterministic tests. */
8
9
  now?: () => Date;
9
- /** Injectable integration context (home directory, PATH lookup) for tests. */
10
- integrationContext?: (root: string) => IntegrationContext;
10
+ /** Home directory used to look for user-level Claude Code files (defaults to the real one). */
11
11
  homeDir?: string;
12
- /** Environment used for PATH lookups (defaults to process.env). */
12
+ /** Environment used for PATH lookups and child processes (defaults to process.env). */
13
13
  env?: NodeJS.ProcessEnv;
14
+ /** Injectable process runner for tests; the default runs real processes without a shell. */
15
+ runner?: Runner;
16
+ platform?: NodeJS.Platform;
14
17
  }
15
18
  export declare function isoNow(o: ServiceOptions): string;
16
- export declare function integrationCtx(o: ServiceOptions, root: string): IntegrationContext;
19
+ export declare function managerEnv(o: ServiceOptions, root: string): ManagerEnv;
17
20
  /** Resolve the workspace and run a mutation under the workspace lock. */
18
21
  export declare function mutate<T>(o: ServiceOptions, fn: (ws: Ws) => Promise<T>): Promise<T>;
@@ -1,14 +1,11 @@
1
1
  import os from 'node:os';
2
- import { defaultIntegrationContext } from '../integrations/index.js';
3
2
  import { requireWorkspace } from '../core/workspace.js';
4
3
  import { withLock } from '../utils/lock.js';
5
4
  export function isoNow(o) {
6
5
  return (o.now ? o.now() : new Date()).toISOString();
7
6
  }
8
- export function integrationCtx(o, root) {
9
- if (o.integrationContext)
10
- return o.integrationContext(root);
11
- return defaultIntegrationContext(root, o.env ?? process.env, o.homeDir ?? os.homedir());
7
+ export function managerEnv(o, root) {
8
+ return { root, home: o.homeDir ?? os.homedir(), env: o.env, platform: o.platform, runner: o.runner, now: o.now };
12
9
  }
13
10
  /** Resolve the workspace and run a mutation under the workspace lock. */
14
11
  export async function mutate(o, fn) {
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/services/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,EAAE,gBAAgB,EAAW,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAe5C,MAAM,UAAU,MAAM,CAAC,CAAiB;IACtC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,CAAiB,EAAE,IAAY;IAC5D,IAAI,CAAC,CAAC,kBAAkB;QAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC5D,OAAO,yBAAyB,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAI,CAAiB,EAAE,EAA0B;IAC3E,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC","sourcesContent":["import os from 'node:os';\nimport { defaultIntegrationContext } from '../integrations/index.js';\nimport type { IntegrationContext } from '../integrations/types.js';\nimport { requireWorkspace, type Ws } from '../core/workspace.js';\nimport { withLock } from '../utils/lock.js';\n\nexport interface ServiceOptions {\n /** Directory the command was started in. */\n cwd: string;\n dryRun?: boolean;\n /** Injectable clock for deterministic tests. */\n now?: () => Date;\n /** Injectable integration context (home directory, PATH lookup) for tests. */\n integrationContext?: (root: string) => IntegrationContext;\n homeDir?: string;\n /** Environment used for PATH lookups (defaults to process.env). */\n env?: NodeJS.ProcessEnv;\n}\n\nexport function isoNow(o: ServiceOptions): string {\n return (o.now ? o.now() : new Date()).toISOString();\n}\n\nexport function integrationCtx(o: ServiceOptions, root: string): IntegrationContext {\n if (o.integrationContext) return o.integrationContext(root);\n return defaultIntegrationContext(root, o.env ?? process.env, o.homeDir ?? os.homedir());\n}\n\n/** Resolve the workspace and run a mutation under the workspace lock. */\nexport async function mutate<T>(o: ServiceOptions, fn: (ws: Ws) => Promise<T>): Promise<T> {\n const ws = await requireWorkspace(o.cwd);\n return withLock(ws.dir, () => fn(ws));\n}\n"]}
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/services/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAGzB,OAAO,EAAE,gBAAgB,EAAW,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAiB5C,MAAM,UAAU,MAAM,CAAC,CAAiB;IACtC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAiB,EAAE,IAAY;IACxD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;AACnH,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAI,CAAiB,EAAE,EAA0B;IAC3E,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC","sourcesContent":["import os from 'node:os';\nimport type { ManagerEnv } from '../integrations/manager.js';\nimport type { Runner } from '../integrations/types.js';\nimport { requireWorkspace, type Ws } from '../core/workspace.js';\nimport { withLock } from '../utils/lock.js';\n\nexport interface ServiceOptions {\n /** Directory the command was started in. */\n cwd: string;\n dryRun?: boolean;\n /** Injectable clock for deterministic tests. */\n now?: () => Date;\n /** Home directory used to look for user-level Claude Code files (defaults to the real one). */\n homeDir?: string;\n /** Environment used for PATH lookups and child processes (defaults to process.env). */\n env?: NodeJS.ProcessEnv;\n /** Injectable process runner for tests; the default runs real processes without a shell. */\n runner?: Runner;\n platform?: NodeJS.Platform;\n}\n\nexport function isoNow(o: ServiceOptions): string {\n return (o.now ? o.now() : new Date()).toISOString();\n}\n\nexport function managerEnv(o: ServiceOptions, root: string): ManagerEnv {\n return { root, home: o.homeDir ?? os.homedir(), env: o.env, platform: o.platform, runner: o.runner, now: o.now };\n}\n\n/** Resolve the workspace and run a mutation under the workspace lock. */\nexport async function mutate<T>(o: ServiceOptions, fn: (ws: Ws) => Promise<T>): Promise<T> {\n const ws = await requireWorkspace(o.cwd);\n return withLock(ws.dir, () => fn(ws));\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { type IntegrationReport } from '../integrations/index.js';
1
2
  import { type ServiceOptions } from './common.js';
2
3
  export type CheckStatus = 'pass' | 'warn' | 'fail' | 'info';
3
4
  export interface DoctorCheck {
@@ -15,9 +16,18 @@ export interface DoctorResult {
15
16
  fail: number;
16
17
  info: number;
17
18
  };
19
+ /** Core workspace has no failing checks. */
18
20
  healthy: boolean;
21
+ /** Core workspace is onboarded: instructions installed and architecture knowledge written. */
19
22
  ready: boolean;
20
23
  fixed: string[];
24
+ /** Observed integration state, kept separate from core readiness. */
25
+ integrations: IntegrationReport[];
26
+ integrationSummary: {
27
+ complete: boolean;
28
+ required: number;
29
+ verified: number;
30
+ };
21
31
  }
22
32
  export interface DoctorOptions extends ServiceOptions {
23
33
  fix?: boolean;
@@ -4,7 +4,7 @@ import { SCHEMA_VERSION, validateAnalysisState, validateCommands } from '../conf
4
4
  import { findWorkspaceRoot, LOCAL_GITIGNORE, loadProject, wsPaths } from '../core/workspace.js';
5
5
  import { readVersioned } from '../core/versioned.js';
6
6
  import { getGitState, gitAvailable, gitTrackedFiles } from '../git/git.js';
7
- import { detectIntegrations } from '../integrations/index.js';
7
+ import { inspectAll, summarize } from '../integrations/index.js';
8
8
  import { loadFacts } from '../knowledge/facts.js';
9
9
  import { ONBOARDING_REQUIREMENTS, validatePrompt } from '../prompts/requirements.js';
10
10
  import { isSensitiveFile } from '../security/files.js';
@@ -14,7 +14,7 @@ import { listTasks } from '../tasks/task.js';
14
14
  import { ensureDir, listFilesRecursive, pathExists, readTextBounded, atomicWriteFile } from '../utils/fs.js';
15
15
  import { findAbsolutePaths } from '../utils/paths.js';
16
16
  import { instructionsInstalled, knowledgeWritten } from './status.js';
17
- import { integrationCtx } from './common.js';
17
+ import { managerEnv } from './common.js';
18
18
  import { withLock } from '../utils/lock.js';
19
19
  export const MIN_NODE_MAJOR = 20;
20
20
  export async function runDoctor(o) {
@@ -42,7 +42,7 @@ export async function runDoctor(o) {
42
42
  else {
43
43
  add('workspace', 'fail', 'No DevWorkspace found in this directory or any parent', 'Run: devworkspace init');
44
44
  }
45
- return finish(null, checks, fixed);
45
+ return finish(null, checks, fixed, undefined, o);
46
46
  }
47
47
  const ws = wsPaths(root);
48
48
  add('workspace', 'pass', 'Workspace found');
@@ -154,15 +154,6 @@ export async function runDoctor(o) {
154
154
  add('onboarding', 'pass', 'Architecture knowledge written');
155
155
  else
156
156
  add('onboarding', 'warn', 'Onboarding is not complete: .devworkspace/context/architecture.md is missing or empty', 'Paste .devworkspace/analysis/onboarding-prompt.md into Claude Code.');
157
- // Integrations.
158
- for (const i of await detectIntegrations(integrationCtx(o, root))) {
159
- if (i.state === 'READY')
160
- add(`integration-${i.id}`, 'pass', `${i.name}: ready`);
161
- else if (i.optional)
162
- add(`integration-${i.id}`, 'info', `${i.name}: ${i.state.toLowerCase().replace('_', ' ')} (optional)`);
163
- else
164
- add(`integration-${i.id}`, 'warn', `${i.name}: ${i.state.toLowerCase().replace('_', ' ')}${i.details[0] ? ` - ${i.details[0]}` : ''}`, i.remediation[0]);
165
- }
166
157
  // Security and portability.
167
158
  const wsFiles = (await listFilesRecursive(ws.dir, 3000)).filter((f) => !f.startsWith(ws.localDir) && !/\.tmp$/.test(f));
168
159
  const secretHits = [];
@@ -209,15 +200,18 @@ export async function runDoctor(o) {
209
200
  const dec = await listDecisions(ws);
210
201
  if (dec.unreadable.length > 0)
211
202
  add('decisions', 'warn', `Unreadable decision file(s): ${dec.unreadable.join(', ')}`, 'Check their front matter.');
212
- return finish(root, checks, fixed, ws);
203
+ return finish(root, checks, fixed, ws, o);
213
204
  }
214
- async function finish(root, checks, fixed, ws) {
205
+ async function finish(root, checks, fixed, ws, o) {
215
206
  const counts = { pass: 0, warn: 0, fail: 0, info: 0 };
216
207
  for (const c of checks)
217
208
  counts[c.status]++;
218
209
  let ready = false;
219
210
  if (ws)
220
211
  ready = counts.fail === 0 && (await instructionsInstalled(ws)) && (await knowledgeWritten(ws));
221
- return { root, checks, counts, healthy: counts.fail === 0, ready, fixed };
212
+ // Integrations are observed (tools are run), and reported separately: a missing optional tool never makes the core workspace unhealthy.
213
+ const integrations = root && ws ? await inspectAll(ws, managerEnv(o, root), { deep: true }) : [];
214
+ const s = summarize(integrations);
215
+ return { root, checks, counts, healthy: counts.fail === 0, ready, fixed, integrations, integrationSummary: { complete: integrations.length > 0 && s.complete, required: s.required, verified: s.verified } };
222
216
  }
223
217
  //# sourceMappingURL=doctor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/services/doctor.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { SCHEMA_VERSION, validateAnalysisState, validateCommands } from '../config/schemas.js';\nimport { findWorkspaceRoot, LOCAL_GITIGNORE, loadProject, wsPaths, type Ws } from '../core/workspace.js';\nimport { readVersioned } from '../core/versioned.js';\nimport { getGitState, gitAvailable, gitTrackedFiles } from '../git/git.js';\nimport { detectIntegrations } from '../integrations/index.js';\nimport { loadFacts } from '../knowledge/facts.js';\nimport { ONBOARDING_REQUIREMENTS, validatePrompt } from '../prompts/requirements.js';\nimport { isSensitiveFile } from '../security/files.js';\nimport { findSecrets } from '../security/redact.js';\nimport { listDecisions } from '../decisions/decision.js';\nimport { listTasks } from '../tasks/task.js';\nimport { ensureDir, listFilesRecursive, pathExists, readTextBounded, atomicWriteFile } from '../utils/fs.js';\nimport { findAbsolutePaths } from '../utils/paths.js';\nimport { instructionsInstalled, knowledgeWritten } from './status.js';\nimport { integrationCtx, type ServiceOptions } from './common.js';\nimport { withLock } from '../utils/lock.js';\n\nexport type CheckStatus = 'pass' | 'warn' | 'fail' | 'info';\n\nexport interface DoctorCheck {\n id: string;\n status: CheckStatus;\n message: string;\n remediation?: string;\n}\n\nexport interface DoctorResult {\n root: string | null;\n checks: DoctorCheck[];\n counts: { pass: number; warn: number; fail: number; info: number };\n healthy: boolean;\n ready: boolean;\n fixed: string[];\n}\n\nexport interface DoctorOptions extends ServiceOptions {\n fix?: boolean;\n minNodeMajor?: number;\n}\n\nexport const MIN_NODE_MAJOR = 20;\n\nexport async function runDoctor(o: DoctorOptions): Promise<DoctorResult> {\n const checks: DoctorCheck[] = [];\n const fixed: string[] = [];\n const add = (id: string, status: CheckStatus, message: string, remediation?: string): void => {\n checks.push({ id, status, message, ...(remediation ? { remediation } : {}) });\n };\n\n const major = Number(process.versions.node.split('.')[0]);\n const minNode = o.minNodeMajor ?? MIN_NODE_MAJOR;\n if (major >= minNode) add('node', 'pass', `Node.js ${process.versions.node}`);\n else add('node', 'fail', `Node.js ${process.versions.node} is older than the required ${minNode}`, `Install Node.js ${minNode} or newer (https://nodejs.org).`);\n\n const hasGit = await gitAvailable();\n if (hasGit) add('git', 'pass', 'Git is available');\n else add('git', 'warn', 'Git was not found on PATH', 'Install Git; DevWorkspace works without it but cannot protect uncommitted changes.');\n\n const root = await findWorkspaceRoot(o.cwd);\n if (!root) {\n if (await pathExists(path.join(o.cwd, '.devworkspace'))) {\n add('workspace', 'fail', 'Partial initialization: .devworkspace/ exists but project.json is missing', 'Restore project.json from Git, or run \"devworkspace init\" to complete the setup (existing files are kept).');\n } else {\n add('workspace', 'fail', 'No DevWorkspace found in this directory or any parent', 'Run: devworkspace init');\n }\n return finish(null, checks, fixed);\n }\n const ws = wsPaths(root);\n add('workspace', 'pass', 'Workspace found');\n\n // Project config and schema compatibility.\n let projectOk = false;\n try {\n const p = await loadProject(ws);\n projectOk = true;\n add('project', 'pass', `project.json valid (schema v${p.schemaVersion}, id ${p.projectId.slice(0, 8)})`);\n } catch (e) {\n const code = (e as { code?: string }).code;\n add('project', 'fail', (e as Error).message.split('\\n')[0]!, code === 'SCHEMA_TOO_NEW' ? 'Upgrade DevWorkspace: npm install -g devworkspace@latest' : 'Restore .devworkspace/project.json from Git, or re-run \"devworkspace init\" after moving the broken file away.');\n }\n\n // Layout.\n const dirs = [ws.contextDir, ws.decisionsDir, ws.tasksActive, ws.tasksCompleted, ws.sessionsDir, ws.analysisDir, ws.stateDir];\n const missingDirs: string[] = [];\n for (const d of dirs) if (!(await pathExists(d))) missingDirs.push(d);\n if (missingDirs.length === 0) add('layout', 'pass', 'Workspace folders present');\n else if (o.fix && projectOk) {\n await withLock(ws.dir, async () => {\n for (const d of missingDirs) await ensureDir(d);\n });\n fixed.push(`created ${missingDirs.length} missing folder(s)`);\n add('layout', 'pass', `Recreated ${missingDirs.length} missing folder(s)`);\n } else {\n add('layout', 'warn', `Missing folders: ${missingDirs.map((d) => path.basename(d)).join(', ')}`, 'Run: devworkspace doctor --fix');\n }\n\n // Ignore rules.\n const giOk = await fs.readFile(ws.gitignore, 'utf8').then(\n (gi) => gi.split(/\\r?\\n/).some((l) => l.trim() === 'local/'),\n () => false,\n );\n if (giOk) add('ignore-local', 'pass', 'Machine-local state is git-ignored');\n else if (o.fix && projectOk) {\n await atomicWriteFile(ws.gitignore, LOCAL_GITIGNORE);\n fixed.push('wrote .devworkspace/.gitignore');\n add('ignore-local', 'pass', 'Wrote .devworkspace/.gitignore');\n } else add('ignore-local', 'fail', '.devworkspace/.gitignore does not ignore local/', 'Run: devworkspace doctor --fix');\n\n try {\n const rootGi = await fs.readFile(path.join(root, '.gitignore'), 'utf8');\n if (rootGi.split(/\\r?\\n/).some((l) => /^\\/?\\.devworkspace\\/?\\*?$/.test(l.trim()))) {\n add('ignore-root', 'warn', 'The root .gitignore ignores all of .devworkspace/, so project knowledge will not be shared', 'Remove that rule; .devworkspace/.gitignore already excludes machine-local files.');\n }\n } catch {\n /* no root .gitignore */\n }\n\n // Knowledge and contract.\n try {\n const facts = await loadFacts(ws);\n const stale = facts.facts.filter((f) => f.status === 'STALE');\n add('facts', 'pass', `${facts.facts.length} fact(s) stored`);\n if (stale.length > 0) add('staleness', 'warn', `${stale.length} stale fact(s): ${stale.slice(0, 5).map((f) => f.key).join(', ')}`, 'Run: devworkspace refresh');\n else if (facts.facts.length > 0) add('staleness', 'pass', 'No stale facts recorded');\n } catch (e) {\n add('facts', 'fail', (e as Error).message.split('\\n')[0]!, 'Restore .devworkspace/context/facts.json from Git or a backup under .devworkspace/local/backups.');\n }\n\n if (await pathExists(ws.commands)) {\n try {\n const c = (await readVersioned(ws.commands, 'commands', SCHEMA_VERSION, validateCommands)).data;\n add('contract', 'pass', 'Testing contract present');\n const unit = c.checks.find((x) => x.id === 'unit');\n if (!unit?.available) add('tests-available', 'warn', 'No unit-test command detected', 'Add a test script or edit .devworkspace/context/commands.json; tasks will not be able to demand tests.');\n if (!c.checks.some((x) => x.id === 'build' && x.available)) add('build-available', 'info', 'No build command detected');\n } catch (e) {\n add('contract', 'fail', (e as Error).message.split('\\n')[0]!, 'Fix commands.json or re-run: devworkspace analyze');\n }\n } else add('contract', 'warn', 'Testing contract not generated yet', 'Run: devworkspace analyze');\n\n if (await pathExists(ws.analysisState)) {\n try {\n const a = (await readVersioned(ws.analysisState, 'analysis', SCHEMA_VERSION, validateAnalysisState)).data;\n add('analysis', 'pass', `Last analysis ${a.analyzedAt}${a.truncated ? ' (partial: size limits hit)' : ''}`);\n } catch (e) {\n add('analysis', 'fail', (e as Error).message.split('\\n')[0]!, 'Re-run: devworkspace analyze');\n }\n } else add('analysis', 'warn', 'Repository has not been analyzed', 'Run: devworkspace analyze');\n\n // Prompt quality (when present).\n if (await pathExists(ws.onboardingPrompt)) {\n const text = (await readTextBounded(ws.onboardingPrompt, 1024 * 1024)) ?? '';\n const missing = validatePrompt(text, ONBOARDING_REQUIREMENTS);\n if (missing.length === 0) add('onboarding-prompt', 'pass', 'Onboarding prompt satisfies all behavioural requirements');\n else add('onboarding-prompt', 'fail', `Onboarding prompt is missing: ${missing.join(', ')}`, 'Re-run: devworkspace analyze');\n }\n\n // Agent wiring.\n if (await instructionsInstalled(ws)) add('agent-instructions', 'pass', 'Claude instructions and skill installed');\n else add('agent-instructions', 'warn', 'Claude instructions are not installed (or the managed section is missing)', 'Run: devworkspace agent install');\n if (await knowledgeWritten(ws)) add('onboarding', 'pass', 'Architecture knowledge written');\n else add('onboarding', 'warn', 'Onboarding is not complete: .devworkspace/context/architecture.md is missing or empty', 'Paste .devworkspace/analysis/onboarding-prompt.md into Claude Code.');\n\n // Integrations.\n for (const i of await detectIntegrations(integrationCtx(o, root))) {\n if (i.state === 'READY') add(`integration-${i.id}`, 'pass', `${i.name}: ready`);\n else if (i.optional) add(`integration-${i.id}`, 'info', `${i.name}: ${i.state.toLowerCase().replace('_', ' ')} (optional)`);\n else add(`integration-${i.id}`, 'warn', `${i.name}: ${i.state.toLowerCase().replace('_', ' ')}${i.details[0] ? ` - ${i.details[0]}` : ''}`, i.remediation[0]);\n }\n\n // Security and portability.\n const wsFiles = (await listFilesRecursive(ws.dir, 3000)).filter((f) => !f.startsWith(ws.localDir) && !/\\.tmp$/.test(f));\n const secretHits: string[] = [];\n const absHits: string[] = [];\n for (const f of wsFiles) {\n if (!/\\.(json|md)$/.test(f)) continue;\n const rel = path.relative(ws.dir, f).replace(/\\\\/g, '/');\n const text = await readTextBounded(f, 1024 * 1024);\n if (!text) continue;\n if (findSecrets(text).length > 0) secretHits.push(rel);\n if (rel !== 'analysis/onboarding-prompt.md' && rel !== 'analysis/refresh-prompt.md' && findAbsolutePaths(text).length > 0) absHits.push(rel);\n }\n if (secretHits.length === 0) add('secrets', 'pass', 'No secret-like values in .devworkspace');\n else add('secrets', 'fail', `Secret-like values found in: ${secretHits.join(', ')}`, 'Remove the values, rotate the credential if it was real, and re-run doctor.');\n if (absHits.length === 0) add('portability', 'pass', 'No machine-specific absolute paths in portable knowledge');\n else add('portability', 'warn', `Absolute paths found in: ${absHits.join(', ')}`, 'Replace them with project-relative paths so the workspace works after the project moves.');\n\n const git = await getGitState(root);\n if (git.isRepo) {\n const tracked = await gitTrackedFiles(root);\n const bad = (tracked ?? []).filter((f) => isSensitiveFile(f));\n if (bad.length > 0) add('tracked-secrets', 'warn', `Credential-like files are tracked by Git: ${bad.slice(0, 5).join(', ')}`, 'Remove them from Git history if they hold real secrets (git rm --cached, then rotate).');\n else add('tracked-secrets', 'pass', 'No credential-like files tracked by Git');\n }\n\n const leftovers = wsFiles.filter((f) => f.endsWith('.tmp'));\n const allTmp = (await listFilesRecursive(ws.dir, 3000)).filter((f) => f.endsWith('.tmp'));\n if (allTmp.length > 0 || leftovers.length > 0) add('tmp-files', 'warn', `${allTmp.length} leftover temporary file(s) from an interrupted write`, 'They are safe to delete: ' + allTmp.slice(0, 3).map((f) => path.relative(root, f).replace(/\\\\/g, '/')).join(', '));\n\n // Tasks and decisions.\n const { tasks, corrupt } = await listTasks(ws, { includeCompleted: true });\n if (corrupt.length > 0) add('tasks', 'fail', `${corrupt.length} unreadable task file(s): ${corrupt.map((c) => c.file).join(', ')}`, 'Restore them from Git or delete the broken file.');\n else add('tasks', 'pass', `${tasks.length} task(s) readable`);\n const dec = await listDecisions(ws);\n if (dec.unreadable.length > 0) add('decisions', 'warn', `Unreadable decision file(s): ${dec.unreadable.join(', ')}`, 'Check their front matter.');\n\n return finish(root, checks, fixed, ws);\n}\n\nasync function finish(root: string | null, checks: DoctorCheck[], fixed: string[], ws?: Ws): Promise<DoctorResult> {\n const counts = { pass: 0, warn: 0, fail: 0, info: 0 };\n for (const c of checks) counts[c.status]++;\n let ready = false;\n if (ws) ready = counts.fail === 0 && (await instructionsInstalled(ws)) && (await knowledgeWritten(ws));\n return { root, checks, counts, healthy: counts.fail === 0, ready, fixed };\n}\n"]}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/services/doctor.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { SCHEMA_VERSION, validateAnalysisState, validateCommands } from '../config/schemas.js';\nimport { findWorkspaceRoot, LOCAL_GITIGNORE, loadProject, wsPaths, type Ws } from '../core/workspace.js';\nimport { readVersioned } from '../core/versioned.js';\nimport { getGitState, gitAvailable, gitTrackedFiles } from '../git/git.js';\nimport { inspectAll, summarize, type IntegrationReport } from '../integrations/index.js';\nimport { loadFacts } from '../knowledge/facts.js';\nimport { ONBOARDING_REQUIREMENTS, validatePrompt } from '../prompts/requirements.js';\nimport { isSensitiveFile } from '../security/files.js';\nimport { findSecrets } from '../security/redact.js';\nimport { listDecisions } from '../decisions/decision.js';\nimport { listTasks } from '../tasks/task.js';\nimport { ensureDir, listFilesRecursive, pathExists, readTextBounded, atomicWriteFile } from '../utils/fs.js';\nimport { findAbsolutePaths } from '../utils/paths.js';\nimport { instructionsInstalled, knowledgeWritten } from './status.js';\nimport { managerEnv, type ServiceOptions } from './common.js';\nimport { withLock } from '../utils/lock.js';\n\nexport type CheckStatus = 'pass' | 'warn' | 'fail' | 'info';\n\nexport interface DoctorCheck {\n id: string;\n status: CheckStatus;\n message: string;\n remediation?: string;\n}\n\nexport interface DoctorResult {\n root: string | null;\n checks: DoctorCheck[];\n counts: { pass: number; warn: number; fail: number; info: number };\n /** Core workspace has no failing checks. */\n healthy: boolean;\n /** Core workspace is onboarded: instructions installed and architecture knowledge written. */\n ready: boolean;\n fixed: string[];\n /** Observed integration state, kept separate from core readiness. */\n integrations: IntegrationReport[];\n integrationSummary: { complete: boolean; required: number; verified: number };\n}\n\nexport interface DoctorOptions extends ServiceOptions {\n fix?: boolean;\n minNodeMajor?: number;\n}\n\nexport const MIN_NODE_MAJOR = 20;\n\nexport async function runDoctor(o: DoctorOptions): Promise<DoctorResult> {\n const checks: DoctorCheck[] = [];\n const fixed: string[] = [];\n const add = (id: string, status: CheckStatus, message: string, remediation?: string): void => {\n checks.push({ id, status, message, ...(remediation ? { remediation } : {}) });\n };\n\n const major = Number(process.versions.node.split('.')[0]);\n const minNode = o.minNodeMajor ?? MIN_NODE_MAJOR;\n if (major >= minNode) add('node', 'pass', `Node.js ${process.versions.node}`);\n else add('node', 'fail', `Node.js ${process.versions.node} is older than the required ${minNode}`, `Install Node.js ${minNode} or newer (https://nodejs.org).`);\n\n const hasGit = await gitAvailable();\n if (hasGit) add('git', 'pass', 'Git is available');\n else add('git', 'warn', 'Git was not found on PATH', 'Install Git; DevWorkspace works without it but cannot protect uncommitted changes.');\n\n const root = await findWorkspaceRoot(o.cwd);\n if (!root) {\n if (await pathExists(path.join(o.cwd, '.devworkspace'))) {\n add('workspace', 'fail', 'Partial initialization: .devworkspace/ exists but project.json is missing', 'Restore project.json from Git, or run \"devworkspace init\" to complete the setup (existing files are kept).');\n } else {\n add('workspace', 'fail', 'No DevWorkspace found in this directory or any parent', 'Run: devworkspace init');\n }\n return finish(null, checks, fixed, undefined, o);\n }\n const ws = wsPaths(root);\n add('workspace', 'pass', 'Workspace found');\n\n // Project config and schema compatibility.\n let projectOk = false;\n try {\n const p = await loadProject(ws);\n projectOk = true;\n add('project', 'pass', `project.json valid (schema v${p.schemaVersion}, id ${p.projectId.slice(0, 8)})`);\n } catch (e) {\n const code = (e as { code?: string }).code;\n add('project', 'fail', (e as Error).message.split('\\n')[0]!, code === 'SCHEMA_TOO_NEW' ? 'Upgrade DevWorkspace: npm install -g devworkspace@latest' : 'Restore .devworkspace/project.json from Git, or re-run \"devworkspace init\" after moving the broken file away.');\n }\n\n // Layout.\n const dirs = [ws.contextDir, ws.decisionsDir, ws.tasksActive, ws.tasksCompleted, ws.sessionsDir, ws.analysisDir, ws.stateDir];\n const missingDirs: string[] = [];\n for (const d of dirs) if (!(await pathExists(d))) missingDirs.push(d);\n if (missingDirs.length === 0) add('layout', 'pass', 'Workspace folders present');\n else if (o.fix && projectOk) {\n await withLock(ws.dir, async () => {\n for (const d of missingDirs) await ensureDir(d);\n });\n fixed.push(`created ${missingDirs.length} missing folder(s)`);\n add('layout', 'pass', `Recreated ${missingDirs.length} missing folder(s)`);\n } else {\n add('layout', 'warn', `Missing folders: ${missingDirs.map((d) => path.basename(d)).join(', ')}`, 'Run: devworkspace doctor --fix');\n }\n\n // Ignore rules.\n const giOk = await fs.readFile(ws.gitignore, 'utf8').then(\n (gi) => gi.split(/\\r?\\n/).some((l) => l.trim() === 'local/'),\n () => false,\n );\n if (giOk) add('ignore-local', 'pass', 'Machine-local state is git-ignored');\n else if (o.fix && projectOk) {\n await atomicWriteFile(ws.gitignore, LOCAL_GITIGNORE);\n fixed.push('wrote .devworkspace/.gitignore');\n add('ignore-local', 'pass', 'Wrote .devworkspace/.gitignore');\n } else add('ignore-local', 'fail', '.devworkspace/.gitignore does not ignore local/', 'Run: devworkspace doctor --fix');\n\n try {\n const rootGi = await fs.readFile(path.join(root, '.gitignore'), 'utf8');\n if (rootGi.split(/\\r?\\n/).some((l) => /^\\/?\\.devworkspace\\/?\\*?$/.test(l.trim()))) {\n add('ignore-root', 'warn', 'The root .gitignore ignores all of .devworkspace/, so project knowledge will not be shared', 'Remove that rule; .devworkspace/.gitignore already excludes machine-local files.');\n }\n } catch {\n /* no root .gitignore */\n }\n\n // Knowledge and contract.\n try {\n const facts = await loadFacts(ws);\n const stale = facts.facts.filter((f) => f.status === 'STALE');\n add('facts', 'pass', `${facts.facts.length} fact(s) stored`);\n if (stale.length > 0) add('staleness', 'warn', `${stale.length} stale fact(s): ${stale.slice(0, 5).map((f) => f.key).join(', ')}`, 'Run: devworkspace refresh');\n else if (facts.facts.length > 0) add('staleness', 'pass', 'No stale facts recorded');\n } catch (e) {\n add('facts', 'fail', (e as Error).message.split('\\n')[0]!, 'Restore .devworkspace/context/facts.json from Git or a backup under .devworkspace/local/backups.');\n }\n\n if (await pathExists(ws.commands)) {\n try {\n const c = (await readVersioned(ws.commands, 'commands', SCHEMA_VERSION, validateCommands)).data;\n add('contract', 'pass', 'Testing contract present');\n const unit = c.checks.find((x) => x.id === 'unit');\n if (!unit?.available) add('tests-available', 'warn', 'No unit-test command detected', 'Add a test script or edit .devworkspace/context/commands.json; tasks will not be able to demand tests.');\n if (!c.checks.some((x) => x.id === 'build' && x.available)) add('build-available', 'info', 'No build command detected');\n } catch (e) {\n add('contract', 'fail', (e as Error).message.split('\\n')[0]!, 'Fix commands.json or re-run: devworkspace analyze');\n }\n } else add('contract', 'warn', 'Testing contract not generated yet', 'Run: devworkspace analyze');\n\n if (await pathExists(ws.analysisState)) {\n try {\n const a = (await readVersioned(ws.analysisState, 'analysis', SCHEMA_VERSION, validateAnalysisState)).data;\n add('analysis', 'pass', `Last analysis ${a.analyzedAt}${a.truncated ? ' (partial: size limits hit)' : ''}`);\n } catch (e) {\n add('analysis', 'fail', (e as Error).message.split('\\n')[0]!, 'Re-run: devworkspace analyze');\n }\n } else add('analysis', 'warn', 'Repository has not been analyzed', 'Run: devworkspace analyze');\n\n // Prompt quality (when present).\n if (await pathExists(ws.onboardingPrompt)) {\n const text = (await readTextBounded(ws.onboardingPrompt, 1024 * 1024)) ?? '';\n const missing = validatePrompt(text, ONBOARDING_REQUIREMENTS);\n if (missing.length === 0) add('onboarding-prompt', 'pass', 'Onboarding prompt satisfies all behavioural requirements');\n else add('onboarding-prompt', 'fail', `Onboarding prompt is missing: ${missing.join(', ')}`, 'Re-run: devworkspace analyze');\n }\n\n // Agent wiring.\n if (await instructionsInstalled(ws)) add('agent-instructions', 'pass', 'Claude instructions and skill installed');\n else add('agent-instructions', 'warn', 'Claude instructions are not installed (or the managed section is missing)', 'Run: devworkspace agent install');\n if (await knowledgeWritten(ws)) add('onboarding', 'pass', 'Architecture knowledge written');\n else add('onboarding', 'warn', 'Onboarding is not complete: .devworkspace/context/architecture.md is missing or empty', 'Paste .devworkspace/analysis/onboarding-prompt.md into Claude Code.');\n\n // Security and portability.\n const wsFiles = (await listFilesRecursive(ws.dir, 3000)).filter((f) => !f.startsWith(ws.localDir) && !/\\.tmp$/.test(f));\n const secretHits: string[] = [];\n const absHits: string[] = [];\n for (const f of wsFiles) {\n if (!/\\.(json|md)$/.test(f)) continue;\n const rel = path.relative(ws.dir, f).replace(/\\\\/g, '/');\n const text = await readTextBounded(f, 1024 * 1024);\n if (!text) continue;\n if (findSecrets(text).length > 0) secretHits.push(rel);\n if (rel !== 'analysis/onboarding-prompt.md' && rel !== 'analysis/refresh-prompt.md' && findAbsolutePaths(text).length > 0) absHits.push(rel);\n }\n if (secretHits.length === 0) add('secrets', 'pass', 'No secret-like values in .devworkspace');\n else add('secrets', 'fail', `Secret-like values found in: ${secretHits.join(', ')}`, 'Remove the values, rotate the credential if it was real, and re-run doctor.');\n if (absHits.length === 0) add('portability', 'pass', 'No machine-specific absolute paths in portable knowledge');\n else add('portability', 'warn', `Absolute paths found in: ${absHits.join(', ')}`, 'Replace them with project-relative paths so the workspace works after the project moves.');\n\n const git = await getGitState(root);\n if (git.isRepo) {\n const tracked = await gitTrackedFiles(root);\n const bad = (tracked ?? []).filter((f) => isSensitiveFile(f));\n if (bad.length > 0) add('tracked-secrets', 'warn', `Credential-like files are tracked by Git: ${bad.slice(0, 5).join(', ')}`, 'Remove them from Git history if they hold real secrets (git rm --cached, then rotate).');\n else add('tracked-secrets', 'pass', 'No credential-like files tracked by Git');\n }\n\n const leftovers = wsFiles.filter((f) => f.endsWith('.tmp'));\n const allTmp = (await listFilesRecursive(ws.dir, 3000)).filter((f) => f.endsWith('.tmp'));\n if (allTmp.length > 0 || leftovers.length > 0) add('tmp-files', 'warn', `${allTmp.length} leftover temporary file(s) from an interrupted write`, 'They are safe to delete: ' + allTmp.slice(0, 3).map((f) => path.relative(root, f).replace(/\\\\/g, '/')).join(', '));\n\n // Tasks and decisions.\n const { tasks, corrupt } = await listTasks(ws, { includeCompleted: true });\n if (corrupt.length > 0) add('tasks', 'fail', `${corrupt.length} unreadable task file(s): ${corrupt.map((c) => c.file).join(', ')}`, 'Restore them from Git or delete the broken file.');\n else add('tasks', 'pass', `${tasks.length} task(s) readable`);\n const dec = await listDecisions(ws);\n if (dec.unreadable.length > 0) add('decisions', 'warn', `Unreadable decision file(s): ${dec.unreadable.join(', ')}`, 'Check their front matter.');\n\n return finish(root, checks, fixed, ws, o);\n}\n\nasync function finish(root: string | null, checks: DoctorCheck[], fixed: string[], ws: Ws | undefined, o: DoctorOptions): Promise<DoctorResult> {\n const counts = { pass: 0, warn: 0, fail: 0, info: 0 };\n for (const c of checks) counts[c.status]++;\n let ready = false;\n if (ws) ready = counts.fail === 0 && (await instructionsInstalled(ws)) && (await knowledgeWritten(ws));\n // Integrations are observed (tools are run), and reported separately: a missing optional tool never makes the core workspace unhealthy.\n const integrations = root && ws ? await inspectAll(ws, managerEnv(o, root), { deep: true }) : [];\n const s = summarize(integrations);\n return { root, checks, counts, healthy: counts.fail === 0, ready, fixed, integrations, integrationSummary: { complete: integrations.length > 0 && s.complete, required: s.required, verified: s.verified } };\n}\n"]}
@@ -1,8 +1,13 @@
1
- import { detectIntegrations } from '../integrations/index.js';
1
+ import { type IntegrationReport, type SetupResult } from '../integrations/index.js';
2
2
  import { type ServiceOptions } from './common.js';
3
3
  export interface InitOptions extends ServiceOptions {
4
4
  /** Explicit project root; defaults to the Git top-level or the current directory. */
5
5
  root?: string;
6
+ /** Also run the integration manager (same code path as `devworkspace setup --integrations`). */
7
+ withIntegrations?: {
8
+ yes: boolean;
9
+ scope: 'project' | 'user';
10
+ };
6
11
  }
7
12
  export interface InitResult {
8
13
  root: string;
@@ -12,7 +17,9 @@ export interface InitResult {
12
17
  unchanged: string[];
13
18
  gitignoreUpdated: boolean;
14
19
  notes: string[];
15
- integrations: Awaited<ReturnType<typeof detectIntegrations>>;
20
+ integrations: IntegrationReport[];
21
+ /** Present when withIntegrations was requested. */
22
+ setup?: SetupResult;
16
23
  nextSteps: string[];
17
24
  }
18
25
  export declare function initWorkspace(o: InitOptions): Promise<InitResult>;
@@ -3,14 +3,14 @@ import path from 'node:path';
3
3
  import { SCHEMA_VERSION, validateProject } from '../config/schemas.js';
4
4
  import { DevWorkspaceError } from '../errors/index.js';
5
5
  import { gitTopLevel } from '../git/git.js';
6
- import { detectIntegrations } from '../integrations/index.js';
6
+ import { inspectAll, runSetup } from '../integrations/index.js';
7
7
  import { atomicWriteFile, atomicWriteJson, ensureDir, pathExists } from '../utils/fs.js';
8
8
  import { findWorkspaceRoot, LOCAL_GITIGNORE, loadProject, wsPaths, WORKSPACE_DIR } from '../core/workspace.js';
9
9
  import { packageVersion } from '../core/version.js';
10
10
  import { withLock } from '../utils/lock.js';
11
11
  import { readPackageJson } from '../discovery/detect.js';
12
12
  import { newProjectId } from './analysis.js';
13
- import { integrationCtx, isoNow } from './common.js';
13
+ import { isoNow, managerEnv } from './common.js';
14
14
  async function resolveRoot(o, notes) {
15
15
  if (o.root)
16
16
  return path.resolve(o.cwd, o.root);
@@ -58,7 +58,6 @@ export async function initWorkspace(o) {
58
58
  const pkg = (await pathExists(path.join(root, 'package.json'))) ? await readPackageJson(root, 'package.json').catch(() => null) : null;
59
59
  const name = pkg?.name ?? path.basename(root);
60
60
  const now = isoNow(o);
61
- const integrations = await detectIntegrations(integrationCtx(o, root));
62
61
  const result = (extra) => ({
63
62
  root,
64
63
  dryRun: !!o.dryRun,
@@ -67,10 +66,11 @@ export async function initWorkspace(o) {
67
66
  unchanged,
68
67
  gitignoreUpdated: false,
69
68
  notes,
70
- integrations,
69
+ integrations: [],
71
70
  nextSteps: ['Run: devworkspace analyze', 'Then paste .devworkspace/analysis/onboarding-prompt.md into Claude Code'],
72
71
  ...extra,
73
72
  });
73
+ const shallow = async () => inspectAll(ws, managerEnv(o, root), { deep: false });
74
74
  if (o.dryRun) {
75
75
  for (const d of dirs)
76
76
  if (!(await pathExists(d)))
@@ -79,7 +79,7 @@ export async function initWorkspace(o) {
79
79
  created.push(rel(ws.projectJson));
80
80
  if (!(await pathExists(ws.gitignore)))
81
81
  created.push(rel(ws.gitignore));
82
- return result({});
82
+ return result({ integrations: await shallow() });
83
83
  }
84
84
  await ensureDir(ws.dir);
85
85
  return withLock(ws.dir, async () => {
@@ -128,8 +128,11 @@ export async function initWorkspace(o) {
128
128
  notes.push('Added missing ignore rules to .devworkspace/.gitignore.');
129
129
  else
130
130
  unchanged.push(rel(ws.gitignore));
131
- await atomicWriteJson(ws.integrationsState, { schemaVersion: SCHEMA_VERSION, detectedAt: now, integrations });
132
- return result({ gitignoreUpdated: gi === 'updated' });
131
+ let setup;
132
+ if (o.withIntegrations) {
133
+ setup = await runSetup(ws, managerEnv(o, root), { scope: o.withIntegrations.scope, yes: o.withIntegrations.yes, dryRun: false, repair: false });
134
+ }
135
+ return result({ gitignoreUpdated: gi === 'updated', integrations: setup ? setup.outcomes.map((x) => x.report) : await shallow(), ...(setup ? { setup } : {}) });
133
136
  });
134
137
  }
135
138
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/services/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,eAAe,EAAsB,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAW,MAAM,sBAAsB,CAAC;AACxH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,EAAuB,MAAM,aAAa,CAAC;AAmB1E,KAAK,UAAU,WAAW,CAAC,CAAc,EAAE,KAAe;IACxD,IAAI,CAAC,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,sCAAsC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QAChJ,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACjF,KAAK,CAAC,IAAI,CAAC,uHAAuH,CAAC,CAAC;QACpI,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,oHAAoH;AACpH,KAAK,UAAU,eAAe,CAAC,EAAM;IACnC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACtC,MAAM,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QACrD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnG,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,MAAM,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;IACvG,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,CAAc;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,iBAAiB,CAAC,WAAW,EAAE,gCAAgC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,4DAA4D,EAAE,CAAC,CAAC;IAC3J,CAAC;IACD,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9E,MAAM,kBAAkB,GAAG,MAAM,UAAU,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;IAE5D,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC9H,MAAM,GAAG,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvI,MAAM,IAAI,GAAG,GAAG,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAEtB,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAAC,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IAEvE,MAAM,MAAM,GAAG,CAAC,KAA0B,EAAc,EAAE,CAAC,CAAC;QAC1D,IAAI;QACJ,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;QAClB,kBAAkB;QAClB,OAAO;QACP,SAAS;QACT,gBAAgB,EAAE,KAAK;QACvB,KAAK;QACL,YAAY;QACZ,SAAS,EAAE,CAAC,2BAA2B,EAAE,yEAAyE,CAAC;QACnH,GAAG,KAAK;KACT,CAAC,CAAC;IAEH,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAC7E,IAAI,CAAC,kBAAkB;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;QACvE,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;QACjC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,MAAM,UAAU,CAAC,CAAC,CAAC;gBAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;iBACjD,CAAC;gBACJ,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,wEAAwE;QACxE,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;YACrF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YACtC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;gBAAE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,OAAsB,CAAC;QAC3B,IAAI,kBAAkB,EAAE,CAAC;YACvB,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,CAAC,CAAC;YAChC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;YACpC,IAAI,OAAO,CAAC,mBAAmB,KAAK,cAAc,EAAE,EAAE,CAAC;gBACrD,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;gBAChF,MAAM,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;gBAChE,KAAK,CAAC,IAAI,CAAC,yBAAyB,cAAc,EAAE,mBAAmB,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;aAAM,CAAC;YACN,OAAO,GAAG;gBACR,aAAa,EAAE,cAAc;gBAC7B,SAAS,EAAE,YAAY,EAAE;gBACzB,IAAI;gBACJ,SAAS,EAAE,GAAG;gBACd,SAAS,EAAE,GAAG;gBACd,mBAAmB,EAAE,cAAc,EAAE;gBACrC,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE;gBAC/C,YAAY,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,aAAa,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;aACvE,CAAC;YACF,MAAM,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;YAChE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;aACjD,IAAI,EAAE,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;;YAC5F,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;QAEvC,MAAM,eAAe,CAAC,EAAE,CAAC,iBAAiB,EAAE,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;QAC9G,OAAO,MAAM,CAAC,EAAE,gBAAgB,EAAE,EAAE,KAAK,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { SCHEMA_VERSION, validateProject, type ProjectConfig } from '../config/schemas.js';\nimport { DevWorkspaceError } from '../errors/index.js';\nimport { gitTopLevel } from '../git/git.js';\nimport { detectIntegrations } from '../integrations/index.js';\nimport { atomicWriteFile, atomicWriteJson, ensureDir, pathExists } from '../utils/fs.js';\nimport { findWorkspaceRoot, LOCAL_GITIGNORE, loadProject, wsPaths, WORKSPACE_DIR, type Ws } from '../core/workspace.js';\nimport { packageVersion } from '../core/version.js';\nimport { withLock } from '../utils/lock.js';\nimport { readPackageJson } from '../discovery/detect.js';\nimport { newProjectId } from './analysis.js';\nimport { integrationCtx, isoNow, type ServiceOptions } from './common.js';\n\nexport interface InitOptions extends ServiceOptions {\n /** Explicit project root; defaults to the Git top-level or the current directory. */\n root?: string;\n}\n\nexport interface InitResult {\n root: string;\n dryRun: boolean;\n alreadyInitialized: boolean;\n created: string[];\n unchanged: string[];\n gitignoreUpdated: boolean;\n notes: string[];\n integrations: Awaited<ReturnType<typeof detectIntegrations>>;\n nextSteps: string[];\n}\n\nasync function resolveRoot(o: InitOptions, notes: string[]): Promise<string> {\n if (o.root) return path.resolve(o.cwd, o.root);\n const existing = await findWorkspaceRoot(o.cwd);\n if (existing) {\n if (path.resolve(existing) !== path.resolve(o.cwd)) notes.push(`Using the existing workspace root (${path.relative(o.cwd, existing) || '.'}).`);\n return existing;\n }\n const top = await gitTopLevel(o.cwd);\n if (top && path.resolve(top).toLowerCase() !== path.resolve(o.cwd).toLowerCase()) {\n notes.push('Current directory is inside a Git repository; using the repository root. Pass --root to choose a different directory.');\n return path.resolve(top);\n }\n return path.resolve(o.cwd);\n}\n\n/** Make sure each required line is present in .devworkspace/.gitignore without removing anything the user added. */\nasync function ensureGitignore(ws: Ws): Promise<'created' | 'updated' | 'unchanged'> {\n if (!(await pathExists(ws.gitignore))) {\n await atomicWriteFile(ws.gitignore, LOCAL_GITIGNORE);\n return 'created';\n }\n const text = await fs.readFile(ws.gitignore, 'utf8');\n const have = new Set(text.split(/\\r?\\n/).map((l) => l.trim()));\n const missing = LOCAL_GITIGNORE.split('\\n').filter((l) => l && !l.startsWith('#') && !have.has(l));\n if (missing.length === 0) return 'unchanged';\n const eol = text.includes('\\r\\n') ? '\\r\\n' : '\\n';\n await atomicWriteFile(ws.gitignore, text + (text.endsWith('\\n') ? '' : eol) + missing.join(eol) + eol);\n return 'updated';\n}\n\nexport async function initWorkspace(o: InitOptions): Promise<InitResult> {\n const notes: string[] = [];\n const root = await resolveRoot(o, notes);\n const st = await fs.stat(root).catch(() => null);\n if (!st?.isDirectory()) {\n throw new DevWorkspaceError('NOT_FOUND', `Project root does not exist: ${root}`, { hint: 'Run the command inside your project, or pass --root <dir>.' });\n }\n const ws = wsPaths(root);\n const created: string[] = [];\n const unchanged: string[] = [];\n const rel = (p: string): string => path.relative(root, p).replace(/\\\\/g, '/');\n const alreadyInitialized = await pathExists(ws.projectJson);\n\n const dirs = [ws.contextDir, ws.decisionsDir, ws.tasksActive, ws.tasksCompleted, ws.sessionsDir, ws.analysisDir, ws.stateDir];\n const pkg = (await pathExists(path.join(root, 'package.json'))) ? await readPackageJson(root, 'package.json').catch(() => null) : null;\n const name = pkg?.name ?? path.basename(root);\n const now = isoNow(o);\n\n const integrations = await detectIntegrations(integrationCtx(o, root));\n\n const result = (extra: Partial<InitResult>): InitResult => ({\n root,\n dryRun: !!o.dryRun,\n alreadyInitialized,\n created,\n unchanged,\n gitignoreUpdated: false,\n notes,\n integrations,\n nextSteps: ['Run: devworkspace analyze', 'Then paste .devworkspace/analysis/onboarding-prompt.md into Claude Code'],\n ...extra,\n });\n\n if (o.dryRun) {\n for (const d of dirs) if (!(await pathExists(d))) created.push(rel(d) + '/');\n if (!alreadyInitialized) created.push(rel(ws.projectJson));\n if (!(await pathExists(ws.gitignore))) created.push(rel(ws.gitignore));\n return result({});\n }\n\n await ensureDir(ws.dir);\n return withLock(ws.dir, async () => {\n for (const d of dirs) {\n if (await pathExists(d)) unchanged.push(rel(d) + '/');\n else {\n await ensureDir(d);\n created.push(rel(d) + '/');\n }\n }\n // Empty directories do not survive Git, so keep portable folders alive.\n for (const d of [ws.decisionsDir, ws.tasksActive, ws.tasksCompleted, ws.sessionsDir]) {\n const keep = path.join(d, '.gitkeep');\n if (!(await pathExists(keep))) await fs.writeFile(keep, '');\n }\n\n let project: ProjectConfig;\n if (alreadyInitialized) {\n project = await loadProject(ws);\n unchanged.push(rel(ws.projectJson));\n if (project.devworkspaceVersion !== packageVersion()) {\n project = { ...project, devworkspaceVersion: packageVersion(), updatedAt: now };\n await atomicWriteJson(ws.projectJson, validateProject(project));\n notes.push(`Recorded DevWorkspace ${packageVersion()} in project.json.`);\n }\n } else {\n project = {\n schemaVersion: SCHEMA_VERSION,\n projectId: newProjectId(),\n name,\n createdAt: now,\n updatedAt: now,\n devworkspaceVersion: packageVersion(),\n settings: { review: 'light', maxFiles: 50_000 },\n managedFiles: [{ path: `${WORKSPACE_DIR}/.gitignore`, mode: 'owned' }],\n };\n await atomicWriteJson(ws.projectJson, validateProject(project));\n created.push(rel(ws.projectJson));\n }\n\n const gi = await ensureGitignore(ws);\n if (gi === 'created') created.push(rel(ws.gitignore));\n else if (gi === 'updated') notes.push('Added missing ignore rules to .devworkspace/.gitignore.');\n else unchanged.push(rel(ws.gitignore));\n\n await atomicWriteJson(ws.integrationsState, { schemaVersion: SCHEMA_VERSION, detectedAt: now, integrations });\n return result({ gitignoreUpdated: gi === 'updated' });\n });\n}\n"]}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/services/init.ts"],"names":[],"mappings":"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","sourcesContent":["import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { SCHEMA_VERSION, validateProject, type ProjectConfig } from '../config/schemas.js';\nimport { DevWorkspaceError } from '../errors/index.js';\nimport { gitTopLevel } from '../git/git.js';\nimport { inspectAll, runSetup, type IntegrationReport, type SetupResult } from '../integrations/index.js';\nimport { atomicWriteFile, atomicWriteJson, ensureDir, pathExists } from '../utils/fs.js';\nimport { findWorkspaceRoot, LOCAL_GITIGNORE, loadProject, wsPaths, WORKSPACE_DIR, type Ws } from '../core/workspace.js';\nimport { packageVersion } from '../core/version.js';\nimport { withLock } from '../utils/lock.js';\nimport { readPackageJson } from '../discovery/detect.js';\nimport { newProjectId } from './analysis.js';\nimport { isoNow, managerEnv, type ServiceOptions } from './common.js';\n\nexport interface InitOptions extends ServiceOptions {\n /** Explicit project root; defaults to the Git top-level or the current directory. */\n root?: string;\n /** Also run the integration manager (same code path as `devworkspace setup --integrations`). */\n withIntegrations?: { yes: boolean; scope: 'project' | 'user' };\n}\n\nexport interface InitResult {\n root: string;\n dryRun: boolean;\n alreadyInitialized: boolean;\n created: string[];\n unchanged: string[];\n gitignoreUpdated: boolean;\n notes: string[];\n integrations: IntegrationReport[];\n /** Present when withIntegrations was requested. */\n setup?: SetupResult;\n nextSteps: string[];\n}\n\nasync function resolveRoot(o: InitOptions, notes: string[]): Promise<string> {\n if (o.root) return path.resolve(o.cwd, o.root);\n const existing = await findWorkspaceRoot(o.cwd);\n if (existing) {\n if (path.resolve(existing) !== path.resolve(o.cwd)) notes.push(`Using the existing workspace root (${path.relative(o.cwd, existing) || '.'}).`);\n return existing;\n }\n const top = await gitTopLevel(o.cwd);\n if (top && path.resolve(top).toLowerCase() !== path.resolve(o.cwd).toLowerCase()) {\n notes.push('Current directory is inside a Git repository; using the repository root. Pass --root to choose a different directory.');\n return path.resolve(top);\n }\n return path.resolve(o.cwd);\n}\n\n/** Make sure each required line is present in .devworkspace/.gitignore without removing anything the user added. */\nasync function ensureGitignore(ws: Ws): Promise<'created' | 'updated' | 'unchanged'> {\n if (!(await pathExists(ws.gitignore))) {\n await atomicWriteFile(ws.gitignore, LOCAL_GITIGNORE);\n return 'created';\n }\n const text = await fs.readFile(ws.gitignore, 'utf8');\n const have = new Set(text.split(/\\r?\\n/).map((l) => l.trim()));\n const missing = LOCAL_GITIGNORE.split('\\n').filter((l) => l && !l.startsWith('#') && !have.has(l));\n if (missing.length === 0) return 'unchanged';\n const eol = text.includes('\\r\\n') ? '\\r\\n' : '\\n';\n await atomicWriteFile(ws.gitignore, text + (text.endsWith('\\n') ? '' : eol) + missing.join(eol) + eol);\n return 'updated';\n}\n\nexport async function initWorkspace(o: InitOptions): Promise<InitResult> {\n const notes: string[] = [];\n const root = await resolveRoot(o, notes);\n const st = await fs.stat(root).catch(() => null);\n if (!st?.isDirectory()) {\n throw new DevWorkspaceError('NOT_FOUND', `Project root does not exist: ${root}`, { hint: 'Run the command inside your project, or pass --root <dir>.' });\n }\n const ws = wsPaths(root);\n const created: string[] = [];\n const unchanged: string[] = [];\n const rel = (p: string): string => path.relative(root, p).replace(/\\\\/g, '/');\n const alreadyInitialized = await pathExists(ws.projectJson);\n\n const dirs = [ws.contextDir, ws.decisionsDir, ws.tasksActive, ws.tasksCompleted, ws.sessionsDir, ws.analysisDir, ws.stateDir];\n const pkg = (await pathExists(path.join(root, 'package.json'))) ? await readPackageJson(root, 'package.json').catch(() => null) : null;\n const name = pkg?.name ?? path.basename(root);\n const now = isoNow(o);\n\n\n const result = (extra: Partial<InitResult>): InitResult => ({\n root,\n dryRun: !!o.dryRun,\n alreadyInitialized,\n created,\n unchanged,\n gitignoreUpdated: false,\n notes,\n integrations: [],\n nextSteps: ['Run: devworkspace analyze', 'Then paste .devworkspace/analysis/onboarding-prompt.md into Claude Code'],\n ...extra,\n });\n const shallow = async (): Promise<IntegrationReport[]> => inspectAll(ws, managerEnv(o, root), { deep: false });\n\n if (o.dryRun) {\n for (const d of dirs) if (!(await pathExists(d))) created.push(rel(d) + '/');\n if (!alreadyInitialized) created.push(rel(ws.projectJson));\n if (!(await pathExists(ws.gitignore))) created.push(rel(ws.gitignore));\n return result({ integrations: await shallow() });\n }\n\n await ensureDir(ws.dir);\n return withLock(ws.dir, async () => {\n for (const d of dirs) {\n if (await pathExists(d)) unchanged.push(rel(d) + '/');\n else {\n await ensureDir(d);\n created.push(rel(d) + '/');\n }\n }\n // Empty directories do not survive Git, so keep portable folders alive.\n for (const d of [ws.decisionsDir, ws.tasksActive, ws.tasksCompleted, ws.sessionsDir]) {\n const keep = path.join(d, '.gitkeep');\n if (!(await pathExists(keep))) await fs.writeFile(keep, '');\n }\n\n let project: ProjectConfig;\n if (alreadyInitialized) {\n project = await loadProject(ws);\n unchanged.push(rel(ws.projectJson));\n if (project.devworkspaceVersion !== packageVersion()) {\n project = { ...project, devworkspaceVersion: packageVersion(), updatedAt: now };\n await atomicWriteJson(ws.projectJson, validateProject(project));\n notes.push(`Recorded DevWorkspace ${packageVersion()} in project.json.`);\n }\n } else {\n project = {\n schemaVersion: SCHEMA_VERSION,\n projectId: newProjectId(),\n name,\n createdAt: now,\n updatedAt: now,\n devworkspaceVersion: packageVersion(),\n settings: { review: 'light', maxFiles: 50_000 },\n managedFiles: [{ path: `${WORKSPACE_DIR}/.gitignore`, mode: 'owned' }],\n };\n await atomicWriteJson(ws.projectJson, validateProject(project));\n created.push(rel(ws.projectJson));\n }\n\n const gi = await ensureGitignore(ws);\n if (gi === 'created') created.push(rel(ws.gitignore));\n else if (gi === 'updated') notes.push('Added missing ignore rules to .devworkspace/.gitignore.');\n else unchanged.push(rel(ws.gitignore));\n\n let setup: SetupResult | undefined;\n if (o.withIntegrations) {\n setup = await runSetup(ws, managerEnv(o, root), { scope: o.withIntegrations.scope, yes: o.withIntegrations.yes, dryRun: false, repair: false });\n }\n return result({ gitignoreUpdated: gi === 'updated', integrations: setup ? setup.outcomes.map((x) => x.report) : await shallow(), ...(setup ? { setup } : {}) });\n });\n}\n"]}
@@ -0,0 +1,26 @@
1
+ import { type IntegrationId, type IntegrationReport, type InstallScope, type ProgressEvent, type SetupResult } from '../integrations/index.js';
2
+ import { type ServiceOptions } from './common.js';
3
+ export interface SetupRequest {
4
+ yes?: boolean;
5
+ scope?: InstallScope;
6
+ only?: string[];
7
+ repair?: boolean;
8
+ }
9
+ export declare function parseOnly(only: string[] | undefined): IntegrationId[] | undefined;
10
+ /** Install and verify the integrations. Without `yes`, only project-local, non-executing steps may run. */
11
+ export declare function setupIntegrations(o: ServiceOptions, req?: SetupRequest, onEvent?: (e: ProgressEvent) => void): Promise<SetupResult>;
12
+ export interface IntegrationsStatus {
13
+ deep: boolean;
14
+ reports: IntegrationReport[];
15
+ summary: {
16
+ complete: boolean;
17
+ required: number;
18
+ verified: number;
19
+ };
20
+ acknowledged?: string[];
21
+ }
22
+ /** Observed state (never the saved file alone). `deep` runs the tools; shallow only looks at files and PATH. */
23
+ export declare function integrationsStatus(o: ServiceOptions, opts?: {
24
+ deep?: boolean;
25
+ restarted?: boolean;
26
+ }): Promise<IntegrationsStatus>;
@@ -0,0 +1,35 @@
1
+ import { DevWorkspaceError } from '../errors/index.js';
2
+ import { requireWorkspace } from '../core/workspace.js';
3
+ import { INTEGRATION_IDS, acknowledgeRestart, inspectAll, runSetup, summarize, } from '../integrations/index.js';
4
+ import { isoNow, managerEnv } from './common.js';
5
+ export function parseOnly(only) {
6
+ if (!only || only.length === 0)
7
+ return undefined;
8
+ const ids = only.flatMap((s) => s.split(',')).map((s) => s.trim()).filter(Boolean);
9
+ for (const id of ids) {
10
+ if (!INTEGRATION_IDS.includes(id)) {
11
+ throw new DevWorkspaceError('USAGE', `Unknown integration "${id}".`, { hint: `Use: ${INTEGRATION_IDS.join(', ')}.` });
12
+ }
13
+ }
14
+ return ids;
15
+ }
16
+ /** Install and verify the integrations. Without `yes`, only project-local, non-executing steps may run. */
17
+ export async function setupIntegrations(o, req = {}, onEvent) {
18
+ const ws = await requireWorkspace(o.cwd);
19
+ return runSetup(ws, managerEnv(o, ws.root), { scope: req.scope ?? 'project', yes: !!req.yes, dryRun: !!o.dryRun, repair: !!req.repair, only: parseOnly(req.only) }, onEvent);
20
+ }
21
+ /** Observed state (never the saved file alone). `deep` runs the tools; shallow only looks at files and PATH. */
22
+ export async function integrationsStatus(o, opts = {}) {
23
+ const ws = await requireWorkspace(o.cwd);
24
+ const env = managerEnv(o, ws.root);
25
+ let acknowledged;
26
+ if (opts.restarted) {
27
+ const before = await inspectAll(ws, env, { deep: false });
28
+ acknowledged = before.filter((r) => r.status === 'RESTART_REQUIRED').map((r) => r.id);
29
+ await acknowledgeRestart(ws, acknowledged, isoNow(o));
30
+ }
31
+ const reports = await inspectAll(ws, env, { deep: opts.deep ?? true });
32
+ const s = summarize(reports);
33
+ return { deep: opts.deep ?? true, reports, summary: { complete: s.complete, required: s.required, verified: s.verified }, ...(acknowledged ? { acknowledged } : {}) };
34
+ }
35
+ //# sourceMappingURL=integrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrations.js","sourceRoot":"","sources":["../../src/services/integrations.ts"],"names":[],"mappings":"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","sourcesContent":["import { DevWorkspaceError } from '../errors/index.js';\nimport { requireWorkspace } from '../core/workspace.js';\nimport {\n INTEGRATION_IDS,\n acknowledgeRestart,\n inspectAll,\n runSetup,\n summarize,\n type IntegrationId,\n type IntegrationReport,\n type InstallScope,\n type ProgressEvent,\n type SetupResult,\n} from '../integrations/index.js';\nimport { isoNow, managerEnv, type ServiceOptions } from './common.js';\n\nexport interface SetupRequest {\n yes?: boolean;\n scope?: InstallScope;\n only?: string[];\n repair?: boolean;\n}\n\nexport function parseOnly(only: string[] | undefined): IntegrationId[] | undefined {\n if (!only || only.length === 0) return undefined;\n const ids = only.flatMap((s) => s.split(',')).map((s) => s.trim()).filter(Boolean);\n for (const id of ids) {\n if (!(INTEGRATION_IDS as readonly string[]).includes(id)) {\n throw new DevWorkspaceError('USAGE', `Unknown integration \"${id}\".`, { hint: `Use: ${INTEGRATION_IDS.join(', ')}.` });\n }\n }\n return ids as IntegrationId[];\n}\n\n/** Install and verify the integrations. Without `yes`, only project-local, non-executing steps may run. */\nexport async function setupIntegrations(o: ServiceOptions, req: SetupRequest = {}, onEvent?: (e: ProgressEvent) => void): Promise<SetupResult> {\n const ws = await requireWorkspace(o.cwd);\n return runSetup(\n ws,\n managerEnv(o, ws.root),\n { scope: req.scope ?? 'project', yes: !!req.yes, dryRun: !!o.dryRun, repair: !!req.repair, only: parseOnly(req.only) },\n onEvent,\n );\n}\n\nexport interface IntegrationsStatus {\n deep: boolean;\n reports: IntegrationReport[];\n summary: { complete: boolean; required: number; verified: number };\n acknowledged?: string[];\n}\n\n/** Observed state (never the saved file alone). `deep` runs the tools; shallow only looks at files and PATH. */\nexport async function integrationsStatus(o: ServiceOptions, opts: { deep?: boolean; restarted?: boolean } = {}): Promise<IntegrationsStatus> {\n const ws = await requireWorkspace(o.cwd);\n const env = managerEnv(o, ws.root);\n let acknowledged: string[] | undefined;\n if (opts.restarted) {\n const before = await inspectAll(ws, env, { deep: false });\n acknowledged = before.filter((r) => r.status === 'RESTART_REQUIRED').map((r) => r.id);\n await acknowledgeRestart(ws, acknowledged as IntegrationId[], isoNow(o));\n }\n const reports = await inspectAll(ws, env, { deep: opts.deep ?? true });\n const s = summarize(reports);\n return { deep: opts.deep ?? true, reports, summary: { complete: s.complete, required: s.required, verified: s.verified }, ...(acknowledged ? { acknowledged } : {}) };\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import type { ServiceOptions } from './common.js';
2
+ export interface ResetOptions extends ServiceOptions {
3
+ /** Actually delete. Without it, reset only reports what it would remove. */
4
+ confirm?: boolean;
5
+ /** Also remove the DevWorkspace block from CLAUDE.md and the managed devworkspace skill. */
6
+ includeAgentFiles?: boolean;
7
+ }
8
+ export interface ResetAction {
9
+ path: string;
10
+ action: 'delete-folder' | 'remove-managed-section' | 'delete-file' | 'skip';
11
+ note: string;
12
+ }
13
+ export interface ResetResult {
14
+ root: string;
15
+ executed: boolean;
16
+ actions: ResetAction[];
17
+ fileCount: number;
18
+ }
19
+ /**
20
+ * Remove .devworkspace/ so the user can start again with `init`. Only DevWorkspace's own folder is ever deleted;
21
+ * application files are never touched, and with includeAgentFiles only the managed block / managed skill are removed.
22
+ */
23
+ export declare function resetWorkspace(o: ResetOptions): Promise<ResetResult>;