devworkspace 0.3.1 → 0.3.3

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 (78) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/README.md +3 -1
  3. package/dist/agents/claude/content.js +27 -4
  4. package/dist/agents/claude/content.js.map +1 -1
  5. package/dist/cli/args.d.ts +45 -0
  6. package/dist/cli/args.js +13 -0
  7. package/dist/cli/args.js.map +1 -1
  8. package/dist/cli/help.js +67 -8
  9. package/dist/cli/help.js.map +1 -1
  10. package/dist/cli/render.d.ts +10 -0
  11. package/dist/cli/render.js +197 -1
  12. package/dist/cli/render.js.map +1 -1
  13. package/dist/cli/run.js +100 -6
  14. package/dist/cli/run.js.map +1 -1
  15. package/dist/config/schemas.d.ts +6 -0
  16. package/dist/config/schemas.js +6 -0
  17. package/dist/config/schemas.js.map +1 -1
  18. package/dist/core/version.d.ts +7 -0
  19. package/dist/core/version.js +13 -0
  20. package/dist/core/version.js.map +1 -1
  21. package/dist/core/workspace.d.ts +1 -0
  22. package/dist/core/workspace.js +1 -0
  23. package/dist/core/workspace.js.map +1 -1
  24. package/dist/discovery/commands.d.ts +1 -0
  25. package/dist/discovery/commands.js +3 -1
  26. package/dist/discovery/commands.js.map +1 -1
  27. package/dist/features/schema.d.ts +3 -0
  28. package/dist/features/schema.js +79 -0
  29. package/dist/features/schema.js.map +1 -0
  30. package/dist/features/types.d.ts +77 -0
  31. package/dist/features/types.js +2 -0
  32. package/dist/features/types.js.map +1 -0
  33. package/dist/features/validate.d.ts +14 -0
  34. package/dist/features/validate.js +124 -0
  35. package/dist/features/validate.js.map +1 -0
  36. package/dist/index.d.ts +5 -0
  37. package/dist/index.js +3 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/services/doctor.js +34 -0
  40. package/dist/services/doctor.js.map +1 -1
  41. package/dist/services/drift.d.ts +21 -0
  42. package/dist/services/drift.js +89 -0
  43. package/dist/services/drift.js.map +1 -0
  44. package/dist/services/features.d.ts +22 -0
  45. package/dist/services/features.js +105 -0
  46. package/dist/services/features.js.map +1 -0
  47. package/dist/services/graph.d.ts +97 -0
  48. package/dist/services/graph.js +342 -0
  49. package/dist/services/graph.js.map +1 -0
  50. package/dist/services/refresh.js +15 -0
  51. package/dist/services/refresh.js.map +1 -1
  52. package/dist/services/setup.d.ts +56 -0
  53. package/dist/services/setup.js +116 -0
  54. package/dist/services/setup.js.map +1 -0
  55. package/dist/services/status.d.ts +6 -0
  56. package/dist/services/status.js +16 -0
  57. package/dist/services/status.js.map +1 -1
  58. package/dist/services/taskContext.d.ts +28 -5
  59. package/dist/services/taskContext.js +221 -4
  60. package/dist/services/taskContext.js.map +1 -1
  61. package/dist/services/verify.d.ts +11 -0
  62. package/dist/services/verify.js +64 -2
  63. package/dist/services/verify.js.map +1 -1
  64. package/docs/architecture-report/01-executive-summary.md +168 -0
  65. package/docs/architecture-report/02-system-architecture.md +356 -0
  66. package/docs/architecture-report/03-tools-and-technologies.md +112 -0
  67. package/docs/architecture-report/04-execution-flows.md +257 -0
  68. package/docs/architecture-report/05-codebase-map.md +150 -0
  69. package/docs/architecture-report/06-command-reference.md +446 -0
  70. package/docs/architecture-report/07-data-flow-and-integrations.md +268 -0
  71. package/docs/architecture-report/08-build-test-deployment.md +185 -0
  72. package/docs/architecture-report/09-security-and-reliability.md +165 -0
  73. package/docs/architecture-report/10-feature-status.md +110 -0
  74. package/docs/architecture-report/11-glossary.md +97 -0
  75. package/docs/architecture-report/README.md +103 -0
  76. package/docs/architecture-report/diagrams.md +446 -0
  77. package/docs/getting-started.md +38 -1
  78. package/package.json +1 -1
@@ -14,6 +14,9 @@ import { listTasks } from '../tasks/task.js';
14
14
  import { ensureDir, listFilesRecursive, pathExists, readJsonFile, readTextBounded, atomicWriteFile } from '../utils/fs.js';
15
15
  import { ALWAYS_SKIP_DIRS } from '../discovery/scan.js';
16
16
  import { isAuxPath } from '../discovery/detect.js';
17
+ import { detectContractDrift } from '../discovery/commands.js';
18
+ import { loadFeatures } from './features.js';
19
+ import { validateFeatureMap } from '../features/validate.js';
17
20
  import { findAbsolutePaths } from '../utils/paths.js';
18
21
  import { detectInstalledAgents, instructionsInstalled, knowledgeWritten } from './status.js';
19
22
  import { managerEnv } from './common.js';
@@ -127,6 +130,15 @@ export async function runDoctor(o) {
127
130
  const ids = [...new Set(configured.map((x) => x.id))];
128
131
  const dirs = [...new Set(configured.map((x) => x.cwd).filter((d) => !!d))];
129
132
  add('verification-commands', 'pass', `${ids.length} verification check(s) configured: ${ids.join(', ')}${dirs.length ? ` (in ${dirs.join(', ')})` : ''}`);
133
+ const drift = await detectContractDrift(ws.root, c.checks);
134
+ if (drift.hasDrift) {
135
+ const summary = drift.issues.slice(0, 3).map((i) => `${i.id}${i.cwd ? ` [${i.cwd}]` : ''}: ${i.message}`).join('; ');
136
+ const more = drift.issues.length > 3 ? ` (+${drift.issues.length - 3} more)` : '';
137
+ add('contract-drift', 'warn', `Verification contract has drifted from actual repository scripts (${drift.issues.length} issue(s): ${summary}${more})`, 'Run "devworkspace refresh" to resynchronize with package manifests, or edit .devworkspace/context/commands.json.');
138
+ }
139
+ else {
140
+ add('contract-drift', 'pass', 'Verification commands match repository manifests and directories');
141
+ }
130
142
  }
131
143
  else if (acknowledgedNoVerification) {
132
144
  add('verification-commands', 'info', 'No verification commands; acknowledged in project.json (settings.acknowledgeNoVerification)');
@@ -141,6 +153,28 @@ export async function runDoctor(o) {
141
153
  }
142
154
  else
143
155
  add('contract', 'warn', 'Testing contract not generated yet', 'Run: devworkspace analyze');
156
+ if (await pathExists(ws.features)) {
157
+ try {
158
+ const f = await loadFeatures(ws);
159
+ const rep = await validateFeatureMap(ws.root, f.features);
160
+ if (rep.total === 0) {
161
+ add('features', 'info', 'Feature map present but contains no features (.devworkspace/context/features.json)');
162
+ }
163
+ else if (rep.unknown > 0 || rep.features.some((x) => !x.valid)) {
164
+ const broken = rep.features.filter((x) => !x.valid).map((x) => `${x.featureId}: ${x.issues[0]}`).slice(0, 3).join('; ');
165
+ add('features', 'warn', `${rep.total} feature(s) mapped, but some contain missing files or broken symbols (${broken})`, 'Run "devworkspace feature validate" or update .devworkspace/context/features.json.');
166
+ }
167
+ else {
168
+ add('features', 'pass', `${rep.total} feature(s) mapped: ${rep.verified} verified, ${rep.inferred} inferred`);
169
+ }
170
+ }
171
+ catch (e) {
172
+ add('features', 'fail', e.message.split('\n')[0], 'Fix .devworkspace/context/features.json');
173
+ }
174
+ }
175
+ else {
176
+ add('features', 'info', 'No feature map defined (.devworkspace/context/features.json is optional)');
177
+ }
144
178
  await checkDiscovery(ws, add);
145
179
  if (await pathExists(ws.analysisState)) {
146
180
  try {
@@ -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 { inspectAll, summarize, type IntegrationReport } from '../integrations/index.js';\nimport { evaluateStaleness, 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, readJsonFile, readTextBounded, atomicWriteFile } from '../utils/fs.js';\nimport { ALWAYS_SKIP_DIRS } from '../discovery/scan.js';\nimport { isAuxPath } from '../discovery/detect.js';\nimport { findAbsolutePaths } from '../utils/paths.js';\nimport { detectInstalledAgents, instructionsInstalled, knowledgeWritten } from './status.js';\nimport { managerEnv, type ServiceOptions } from './common.js';\nimport { withLock } from '../utils/lock.js';\nimport type { AgentAdapter } from '../agents/types.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 let acknowledgedNoVerification = false;\n try {\n const p = await loadProject(ws);\n projectOk = true;\n acknowledgedNoVerification = p.settings.acknowledgeNoVerification === 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 view = await evaluateStaleness(ws.root, facts, new Date().toISOString());\n const stale = [...view.recorded, ...view.detected];\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} (${f.reason})`).join('; ')}`, 'Run: devworkspace refresh, then re-check the listed facts against the repository.');\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 if (!c.checks.some((x) => x.id === 'unit' && x.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 const configured = c.checks.filter((x) => x.available);\n if (configured.length > 0) {\n const ids = [...new Set(configured.map((x) => x.id))];\n const dirs = [...new Set(configured.map((x) => x.cwd).filter((d): d is string => !!d))];\n add('verification-commands', 'pass', `${ids.length} verification check(s) configured: ${ids.join(', ')}${dirs.length ? ` (in ${dirs.join(', ')})` : ''}`);\n } else if (acknowledgedNoVerification) {\n add('verification-commands', 'info', 'No verification commands; acknowledged in project.json (settings.acknowledgeNoVerification)');\n } else {\n add(\n 'verification-commands',\n 'warn',\n 'No verification commands (tests, lint, typecheck, build) are configured, so tasks cannot require any verification',\n 'Run: devworkspace analyze. If the project intentionally has none, set \"acknowledgeNoVerification\": true under settings in .devworkspace/project.json.',\n );\n }\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 await checkDiscovery(ws, add);\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 const installedAgents = await detectInstalledAgents(ws);\n if (installedAgents.length > 0) {\n const names = installedAgents.map((a) => a.displayName).join(', ');\n const msg = installedAgents.length === 1 && installedAgents[0]!.id === 'claude'\n ? 'Claude instructions and skill installed'\n : `${names} instructions installed`;\n add('agent-instructions', 'pass', msg);\n\n // Read-only: plan() only computes what an install would write; nothing is touched here.\n const projectName = (await loadProject(ws).catch(() => null))?.name ?? path.basename(root);\n const outdatedByAgent: { agent: AgentAdapter; paths: string[] }[] = [];\n for (const adapter of installedAgents) {\n const planned = await adapter.plan({ root, projectName });\n const outdated = planned.filter((c) => c.kind === 'update').map((c) => c.path);\n if (outdated.length > 0) {\n outdatedByAgent.push({ agent: adapter, paths: outdated });\n }\n }\n if (outdatedByAgent.length > 0) {\n const allPaths = outdatedByAgent.flatMap((x) => x.paths);\n const namesStale = outdatedByAgent.map((x) => x.agent.displayName).join(', ');\n add(\n 'agent-freshness',\n 'warn',\n `Installed ${namesStale} instructions are older than this DevWorkspace version (${allPaths.join(', ')})`,\n 'Run: devworkspace agent install (add --dry-run to preview; only the managed block and the devworkspace skill change).',\n );\n } else {\n add(\n 'agent-freshness',\n 'pass',\n installedAgents.length === 1 && installedAgents[0]!.id === 'claude'\n ? 'Installed Claude instructions and skill match this DevWorkspace version'\n : `Installed ${names} instructions match this DevWorkspace version`,\n );\n }\n } else {\n add(\n 'agent-instructions',\n 'warn',\n 'Agent instructions are not installed (or the managed section is missing)',\n 'Run: devworkspace agent install',\n );\n }\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 your coding agent (Claude Code, Cursor, Copilot, Codex, etc.).');\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 const discoveryOk = !checks.some((c) => DISCOVERY_CHECKS.has(c.id) && c.status === 'warn');\n if (ws) ready = counts.fail === 0 && discoveryOk && (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\n/** Doctor checks that say whether the repository was actually understood, as opposed to the folder merely existing. */\nconst DISCOVERY_CHECKS = new Set(['discovery-incomplete', 'discovery-ecosystem', 'verification-commands']);\n\n/** package.json files near the top of the tree (two levels), found without a full scan. */\nasync function findNearbyManifests(root: string): Promise<string[]> {\n const found: string[] = [];\n const skip = (name: string, rel: string): boolean => name.startsWith('.') || ALWAYS_SKIP_DIRS.has(name) || isAuxPath(`${rel}/x`);\n async function dirs(rel: string): Promise<string[]> {\n try {\n return (await fs.readdir(path.join(root, rel), { withFileTypes: true })).filter((e) => e.isDirectory() && !skip(e.name, rel ? `${rel}/${e.name}` : e.name)).map((e) => (rel ? `${rel}/${e.name}` : e.name));\n } catch {\n return [];\n }\n }\n for (const d1 of await dirs('')) {\n if (await pathExists(path.join(root, d1, 'package.json'))) found.push(`${d1}/package.json`);\n for (const d2 of (await dirs(d1)).slice(0, 100)) if (await pathExists(path.join(root, d2, 'package.json'))) found.push(`${d2}/package.json`);\n }\n return found.sort();\n}\n\nasync function checkDiscovery(ws: Ws, add: (id: string, status: CheckStatus, message: string, remediation?: string) => void): Promise<void> {\n if (!(await pathExists(ws.discovery))) return; // \"not analyzed yet\" is reported by the analysis check\n let d: { ecosystems?: string[]; languages?: { name: string; files: number }[]; manifests?: string[]; monorepo?: { packages?: { path: string }[] }; scan?: { fileCount?: number } };\n try {\n d = (await readJsonFile(ws.discovery)) as typeof d;\n } catch (e) {\n add('discovery-ecosystem', 'fail', (e as Error).message.split('\\n')[0]!, 'Re-run: devworkspace analyze');\n return;\n }\n const eco = d.ecosystems ?? [];\n const languages = (d.languages ?? []).map((l) => l.name);\n // Manifests the analysis recorded. Older reports lack the list, so reconstruct it from the packages they did record.\n const known = new Set<string>(d.manifests ?? []);\n for (const p of d.monorepo?.packages ?? []) known.add(`${p.path}/package.json`);\n if (eco.includes('node')) known.add('package.json');\n const missed = (await findNearbyManifests(ws.root)).filter((m) => !known.has(m));\n if (missed.length > 0) {\n add(\n 'discovery-incomplete',\n 'warn',\n `The repository has package manifest(s) the last analysis did not record: ${missed.slice(0, 4).join(', ')}${missed.length > 4 ? ', ...' : ''}`,\n 'Run: devworkspace analyze (current versions detect nested packages). Commands you confirmed earlier are kept.',\n );\n } else if (eco.length === 0 && languages.length > 0) {\n add(\n 'discovery-ecosystem',\n 'warn',\n `No ecosystem was detected although ${d.scan?.fileCount ?? 'several'} files were scanned (${languages.slice(0, 3).join(', ')}), so build and test tooling is unknown`,\n 'Run: devworkspace analyze. If the project has no package manifest, record its commands by hand in .devworkspace/context/commands.json.',\n );\n } else if (eco.length > 0) {\n const n = d.monorepo?.packages?.length ?? 0;\n add('discovery-ecosystem', 'pass', `Detected ${eco.join(', ')}${n > 0 ? ` (${n} package${n === 1 ? '' : 's'})` : ''}`);\n } else {\n add('discovery-ecosystem', 'info', 'No source files or manifests detected');\n }\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 { evaluateStaleness, 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, readJsonFile, readTextBounded, atomicWriteFile } from '../utils/fs.js';\nimport { ALWAYS_SKIP_DIRS } from '../discovery/scan.js';\nimport { isAuxPath } from '../discovery/detect.js';\nimport { detectContractDrift } from '../discovery/commands.js';\nimport { loadFeatures } from './features.js';\nimport { validateFeatureMap } from '../features/validate.js';\nimport { findAbsolutePaths } from '../utils/paths.js';\nimport { detectInstalledAgents, instructionsInstalled, knowledgeWritten } from './status.js';\nimport { managerEnv, type ServiceOptions } from './common.js';\nimport { withLock } from '../utils/lock.js';\nimport type { AgentAdapter } from '../agents/types.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 let acknowledgedNoVerification = false;\n try {\n const p = await loadProject(ws);\n projectOk = true;\n acknowledgedNoVerification = p.settings.acknowledgeNoVerification === 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 view = await evaluateStaleness(ws.root, facts, new Date().toISOString());\n const stale = [...view.recorded, ...view.detected];\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} (${f.reason})`).join('; ')}`, 'Run: devworkspace refresh, then re-check the listed facts against the repository.');\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 if (!c.checks.some((x) => x.id === 'unit' && x.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 const configured = c.checks.filter((x) => x.available);\n if (configured.length > 0) {\n const ids = [...new Set(configured.map((x) => x.id))];\n const dirs = [...new Set(configured.map((x) => x.cwd).filter((d): d is string => !!d))];\n add('verification-commands', 'pass', `${ids.length} verification check(s) configured: ${ids.join(', ')}${dirs.length ? ` (in ${dirs.join(', ')})` : ''}`);\n\n const drift = await detectContractDrift(ws.root, c.checks);\n if (drift.hasDrift) {\n const summary = drift.issues.slice(0, 3).map((i) => `${i.id}${i.cwd ? ` [${i.cwd}]` : ''}: ${i.message}`).join('; ');\n const more = drift.issues.length > 3 ? ` (+${drift.issues.length - 3} more)` : '';\n add(\n 'contract-drift',\n 'warn',\n `Verification contract has drifted from actual repository scripts (${drift.issues.length} issue(s): ${summary}${more})`,\n 'Run \"devworkspace refresh\" to resynchronize with package manifests, or edit .devworkspace/context/commands.json.',\n );\n } else {\n add('contract-drift', 'pass', 'Verification commands match repository manifests and directories');\n }\n } else if (acknowledgedNoVerification) {\n add('verification-commands', 'info', 'No verification commands; acknowledged in project.json (settings.acknowledgeNoVerification)');\n } else {\n add(\n 'verification-commands',\n 'warn',\n 'No verification commands (tests, lint, typecheck, build) are configured, so tasks cannot require any verification',\n 'Run: devworkspace analyze. If the project intentionally has none, set \"acknowledgeNoVerification\": true under settings in .devworkspace/project.json.',\n );\n }\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.features)) {\n try {\n const f = await loadFeatures(ws);\n const rep = await validateFeatureMap(ws.root, f.features);\n if (rep.total === 0) {\n add('features', 'info', 'Feature map present but contains no features (.devworkspace/context/features.json)');\n } else if (rep.unknown > 0 || rep.features.some((x) => !x.valid)) {\n const broken = rep.features.filter((x) => !x.valid).map((x) => `${x.featureId}: ${x.issues[0]}`).slice(0, 3).join('; ');\n add(\n 'features',\n 'warn',\n `${rep.total} feature(s) mapped, but some contain missing files or broken symbols (${broken})`,\n 'Run \"devworkspace feature validate\" or update .devworkspace/context/features.json.',\n );\n } else {\n add('features', 'pass', `${rep.total} feature(s) mapped: ${rep.verified} verified, ${rep.inferred} inferred`);\n }\n } catch (e) {\n add('features', 'fail', (e as Error).message.split('\\n')[0]!, 'Fix .devworkspace/context/features.json');\n }\n } else {\n add('features', 'info', 'No feature map defined (.devworkspace/context/features.json is optional)');\n }\n\n await checkDiscovery(ws, add);\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 const installedAgents = await detectInstalledAgents(ws);\n if (installedAgents.length > 0) {\n const names = installedAgents.map((a) => a.displayName).join(', ');\n const msg = installedAgents.length === 1 && installedAgents[0]!.id === 'claude'\n ? 'Claude instructions and skill installed'\n : `${names} instructions installed`;\n add('agent-instructions', 'pass', msg);\n\n // Read-only: plan() only computes what an install would write; nothing is touched here.\n const projectName = (await loadProject(ws).catch(() => null))?.name ?? path.basename(root);\n const outdatedByAgent: { agent: AgentAdapter; paths: string[] }[] = [];\n for (const adapter of installedAgents) {\n const planned = await adapter.plan({ root, projectName });\n const outdated = planned.filter((c) => c.kind === 'update').map((c) => c.path);\n if (outdated.length > 0) {\n outdatedByAgent.push({ agent: adapter, paths: outdated });\n }\n }\n if (outdatedByAgent.length > 0) {\n const allPaths = outdatedByAgent.flatMap((x) => x.paths);\n const namesStale = outdatedByAgent.map((x) => x.agent.displayName).join(', ');\n add(\n 'agent-freshness',\n 'warn',\n `Installed ${namesStale} instructions are older than this DevWorkspace version (${allPaths.join(', ')})`,\n 'Run: devworkspace agent install (add --dry-run to preview; only the managed block and the devworkspace skill change).',\n );\n } else {\n add(\n 'agent-freshness',\n 'pass',\n installedAgents.length === 1 && installedAgents[0]!.id === 'claude'\n ? 'Installed Claude instructions and skill match this DevWorkspace version'\n : `Installed ${names} instructions match this DevWorkspace version`,\n );\n }\n } else {\n add(\n 'agent-instructions',\n 'warn',\n 'Agent instructions are not installed (or the managed section is missing)',\n 'Run: devworkspace agent install',\n );\n }\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 your coding agent (Claude Code, Cursor, Copilot, Codex, etc.).');\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 const discoveryOk = !checks.some((c) => DISCOVERY_CHECKS.has(c.id) && c.status === 'warn');\n if (ws) ready = counts.fail === 0 && discoveryOk && (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\n/** Doctor checks that say whether the repository was actually understood, as opposed to the folder merely existing. */\nconst DISCOVERY_CHECKS = new Set(['discovery-incomplete', 'discovery-ecosystem', 'verification-commands']);\n\n/** package.json files near the top of the tree (two levels), found without a full scan. */\nasync function findNearbyManifests(root: string): Promise<string[]> {\n const found: string[] = [];\n const skip = (name: string, rel: string): boolean => name.startsWith('.') || ALWAYS_SKIP_DIRS.has(name) || isAuxPath(`${rel}/x`);\n async function dirs(rel: string): Promise<string[]> {\n try {\n return (await fs.readdir(path.join(root, rel), { withFileTypes: true })).filter((e) => e.isDirectory() && !skip(e.name, rel ? `${rel}/${e.name}` : e.name)).map((e) => (rel ? `${rel}/${e.name}` : e.name));\n } catch {\n return [];\n }\n }\n for (const d1 of await dirs('')) {\n if (await pathExists(path.join(root, d1, 'package.json'))) found.push(`${d1}/package.json`);\n for (const d2 of (await dirs(d1)).slice(0, 100)) if (await pathExists(path.join(root, d2, 'package.json'))) found.push(`${d2}/package.json`);\n }\n return found.sort();\n}\n\nasync function checkDiscovery(ws: Ws, add: (id: string, status: CheckStatus, message: string, remediation?: string) => void): Promise<void> {\n if (!(await pathExists(ws.discovery))) return; // \"not analyzed yet\" is reported by the analysis check\n let d: { ecosystems?: string[]; languages?: { name: string; files: number }[]; manifests?: string[]; monorepo?: { packages?: { path: string }[] }; scan?: { fileCount?: number } };\n try {\n d = (await readJsonFile(ws.discovery)) as typeof d;\n } catch (e) {\n add('discovery-ecosystem', 'fail', (e as Error).message.split('\\n')[0]!, 'Re-run: devworkspace analyze');\n return;\n }\n const eco = d.ecosystems ?? [];\n const languages = (d.languages ?? []).map((l) => l.name);\n // Manifests the analysis recorded. Older reports lack the list, so reconstruct it from the packages they did record.\n const known = new Set<string>(d.manifests ?? []);\n for (const p of d.monorepo?.packages ?? []) known.add(`${p.path}/package.json`);\n if (eco.includes('node')) known.add('package.json');\n const missed = (await findNearbyManifests(ws.root)).filter((m) => !known.has(m));\n if (missed.length > 0) {\n add(\n 'discovery-incomplete',\n 'warn',\n `The repository has package manifest(s) the last analysis did not record: ${missed.slice(0, 4).join(', ')}${missed.length > 4 ? ', ...' : ''}`,\n 'Run: devworkspace analyze (current versions detect nested packages). Commands you confirmed earlier are kept.',\n );\n } else if (eco.length === 0 && languages.length > 0) {\n add(\n 'discovery-ecosystem',\n 'warn',\n `No ecosystem was detected although ${d.scan?.fileCount ?? 'several'} files were scanned (${languages.slice(0, 3).join(', ')}), so build and test tooling is unknown`,\n 'Run: devworkspace analyze. If the project has no package manifest, record its commands by hand in .devworkspace/context/commands.json.',\n );\n } else if (eco.length > 0) {\n const n = d.monorepo?.packages?.length ?? 0;\n add('discovery-ecosystem', 'pass', `Detected ${eco.join(', ')}${n > 0 ? ` (${n} package${n === 1 ? '' : 's'})` : ''}`);\n } else {\n add('discovery-ecosystem', 'info', 'No source files or manifests detected');\n }\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import type { CheckId, CommandEntry } from '../config/schemas.js';
2
+ export type ContractDriftType = 'missing-cwd' | 'missing-manifest' | 'missing-script' | 'duplicate-check' | 'unavailable-command';
3
+ export interface ContractDriftItem {
4
+ id: CheckId;
5
+ cwd?: string;
6
+ command: string | null;
7
+ type: ContractDriftType;
8
+ message: string;
9
+ remediation: string;
10
+ }
11
+ export interface ContractDriftReport {
12
+ hasDrift: boolean;
13
+ issues: ContractDriftItem[];
14
+ }
15
+ export type ContractDriftIssue = ContractDriftItem;
16
+ export type ContractDriftResult = ContractDriftReport;
17
+ /**
18
+ * Validates configured verification commands against actual directories and package manifests on disk.
19
+ * Detects missing script bodies, deleted directories, duplicate checks, and missing manifests.
20
+ */
21
+ export declare function detectContractDrift(root: string, commands: CommandEntry[]): Promise<ContractDriftReport>;
@@ -0,0 +1,89 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { pathExists } from '../utils/fs.js';
4
+ /**
5
+ * Validates configured verification commands against actual directories and package manifests on disk.
6
+ * Detects missing script bodies, deleted directories, duplicate checks, and missing manifests.
7
+ */
8
+ export async function detectContractDrift(root, commands) {
9
+ const issues = [];
10
+ const seen = new Set();
11
+ for (const c of commands) {
12
+ const key = `${c.id}:${c.cwd ?? '.'}`;
13
+ if (seen.has(key)) {
14
+ issues.push({
15
+ id: c.id,
16
+ cwd: c.cwd,
17
+ command: c.command,
18
+ type: 'duplicate-check',
19
+ message: `Duplicate check configured for "${c.id}" in "${c.cwd ?? '.'}"`,
20
+ remediation: 'Keep only one check definition per check ID and directory in .devworkspace/context/commands.json.',
21
+ });
22
+ }
23
+ seen.add(key);
24
+ if (!c.available)
25
+ continue;
26
+ if (!c.command || !c.command.trim()) {
27
+ issues.push({
28
+ id: c.id,
29
+ cwd: c.cwd,
30
+ command: c.command,
31
+ type: 'unavailable-command',
32
+ message: `Check "${c.id}" is marked available but has no executable command`,
33
+ remediation: 'Specify an executable command or set available: false in .devworkspace/context/commands.json.',
34
+ });
35
+ continue;
36
+ }
37
+ if (c.cwd && c.cwd !== '.' && c.cwd !== '') {
38
+ const fullDir = path.join(root, ...c.cwd.split('/'));
39
+ if (!(await pathExists(fullDir))) {
40
+ issues.push({
41
+ id: c.id,
42
+ cwd: c.cwd,
43
+ command: c.command,
44
+ type: 'missing-cwd',
45
+ message: `Package directory "${c.cwd}" does not exist on disk`,
46
+ remediation: `Re-create directory "${c.cwd}", remove the entry from .devworkspace/context/commands.json, or run "devworkspace refresh".`,
47
+ });
48
+ continue;
49
+ }
50
+ }
51
+ if (c.source && c.source.includes('#scripts.')) {
52
+ const [manifestRel, scriptName] = c.source.split('#scripts.');
53
+ if (manifestRel && scriptName) {
54
+ const fullManifest = path.join(root, ...manifestRel.split('/'));
55
+ if (!(await pathExists(fullManifest))) {
56
+ issues.push({
57
+ id: c.id,
58
+ cwd: c.cwd,
59
+ command: c.command,
60
+ type: 'missing-manifest',
61
+ message: `Referenced package manifest "${manifestRel}" does not exist on disk`,
62
+ remediation: `Remove stale command from .devworkspace/context/commands.json or run "devworkspace refresh".`,
63
+ });
64
+ }
65
+ else {
66
+ try {
67
+ const raw = await fs.readFile(fullManifest, 'utf8');
68
+ const parsed = JSON.parse(raw);
69
+ if (!parsed.scripts || typeof parsed.scripts[scriptName] !== 'string') {
70
+ issues.push({
71
+ id: c.id,
72
+ cwd: c.cwd,
73
+ command: c.command,
74
+ type: 'missing-script',
75
+ message: `Script "${scriptName}" is missing from "${manifestRel}"`,
76
+ remediation: `Add script "${scriptName}" back to "${manifestRel}" or run "devworkspace refresh" to resynchronize commands.json.`,
77
+ });
78
+ }
79
+ }
80
+ catch {
81
+ // manifest unreadable / unparseable - handled by manifest health checks
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ return { hasDrift: issues.length > 0, issues };
88
+ }
89
+ //# sourceMappingURL=drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../../src/services/drift.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { CheckId, CommandEntry } from '../config/schemas.js';\nimport { pathExists } from '../utils/fs.js';\n\nexport type ContractDriftType = 'missing-cwd' | 'missing-manifest' | 'missing-script' | 'duplicate-check' | 'unavailable-command';\n\nexport interface ContractDriftItem {\n id: CheckId;\n cwd?: string;\n command: string | null;\n type: ContractDriftType;\n message: string;\n remediation: string;\n}\n\nexport interface ContractDriftReport {\n hasDrift: boolean;\n issues: ContractDriftItem[];\n}\n\nexport type ContractDriftIssue = ContractDriftItem;\nexport type ContractDriftResult = ContractDriftReport;\n\n/**\n * Validates configured verification commands against actual directories and package manifests on disk.\n * Detects missing script bodies, deleted directories, duplicate checks, and missing manifests.\n */\nexport async function detectContractDrift(root: string, commands: CommandEntry[]): Promise<ContractDriftReport> {\n const issues: ContractDriftItem[] = [];\n const seen = new Set<string>();\n\n for (const c of commands) {\n const key = `${c.id}:${c.cwd ?? '.'}`;\n if (seen.has(key)) {\n issues.push({\n id: c.id,\n cwd: c.cwd,\n command: c.command,\n type: 'duplicate-check',\n message: `Duplicate check configured for \"${c.id}\" in \"${c.cwd ?? '.'}\"`,\n remediation: 'Keep only one check definition per check ID and directory in .devworkspace/context/commands.json.',\n });\n }\n seen.add(key);\n\n if (!c.available) continue;\n\n if (!c.command || !c.command.trim()) {\n issues.push({\n id: c.id,\n cwd: c.cwd,\n command: c.command,\n type: 'unavailable-command',\n message: `Check \"${c.id}\" is marked available but has no executable command`,\n remediation: 'Specify an executable command or set available: false in .devworkspace/context/commands.json.',\n });\n continue;\n }\n\n if (c.cwd && c.cwd !== '.' && c.cwd !== '') {\n const fullDir = path.join(root, ...c.cwd.split('/'));\n if (!(await pathExists(fullDir))) {\n issues.push({\n id: c.id,\n cwd: c.cwd,\n command: c.command,\n type: 'missing-cwd',\n message: `Package directory \"${c.cwd}\" does not exist on disk`,\n remediation: `Re-create directory \"${c.cwd}\", remove the entry from .devworkspace/context/commands.json, or run \"devworkspace refresh\".`,\n });\n continue;\n }\n }\n\n if (c.source && c.source.includes('#scripts.')) {\n const [manifestRel, scriptName] = c.source.split('#scripts.');\n if (manifestRel && scriptName) {\n const fullManifest = path.join(root, ...manifestRel.split('/'));\n if (!(await pathExists(fullManifest))) {\n issues.push({\n id: c.id,\n cwd: c.cwd,\n command: c.command,\n type: 'missing-manifest',\n message: `Referenced package manifest \"${manifestRel}\" does not exist on disk`,\n remediation: `Remove stale command from .devworkspace/context/commands.json or run \"devworkspace refresh\".`,\n });\n } else {\n try {\n const raw = await fs.readFile(fullManifest, 'utf8');\n const parsed = JSON.parse(raw) as { scripts?: Record<string, string> };\n if (!parsed.scripts || typeof parsed.scripts[scriptName] !== 'string') {\n issues.push({\n id: c.id,\n cwd: c.cwd,\n command: c.command,\n type: 'missing-script',\n message: `Script \"${scriptName}\" is missing from \"${manifestRel}\"`,\n remediation: `Add script \"${scriptName}\" back to \"${manifestRel}\" or run \"devworkspace refresh\" to resynchronize commands.json.`,\n });\n }\n } catch {\n // manifest unreadable / unparseable - handled by manifest health checks\n }\n }\n }\n }\n }\n\n return { hasDrift: issues.length > 0, issues };\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import type { FeatureItem, FeaturesFile, FeatureValidationReport } from '../features/types.js';
2
+ import { type Ws } from '../core/workspace.js';
3
+ import { type ServiceOptions } from './common.js';
4
+ export interface FeatureSummary {
5
+ id: string;
6
+ name: string;
7
+ description?: string;
8
+ status: string;
9
+ componentsCount: number;
10
+ testsCount: number;
11
+ tags?: string[];
12
+ updatedAt: string;
13
+ }
14
+ export declare function loadFeatures(ws: Ws): Promise<FeaturesFile>;
15
+ export declare function saveFeatures(ws: Ws, file: FeaturesFile): Promise<void>;
16
+ export declare function listFeaturesService(o: ServiceOptions): Promise<FeatureSummary[]>;
17
+ export declare function getFeatureService(o: ServiceOptions, id: string): Promise<FeatureItem>;
18
+ export declare function validateFeatureMapService(o: ServiceOptions): Promise<FeatureValidationReport>;
19
+ export declare function saveFeatureService(o: ServiceOptions, input: Partial<FeatureItem> & {
20
+ id: string;
21
+ name: string;
22
+ }): Promise<FeatureItem>;
@@ -0,0 +1,105 @@
1
+ import { FEATURE_SCHEMA_VERSION, validateFeatures } from '../features/schema.js';
2
+ import { readVersioned, writeVersioned } from '../core/versioned.js';
3
+ import { requireWorkspace } from '../core/workspace.js';
4
+ import { DevWorkspaceError } from '../errors/index.js';
5
+ import { pathExists } from '../utils/fs.js';
6
+ import { validateFeature, validateFeatureMap } from '../features/validate.js';
7
+ import { isoNow, mutate } from './common.js';
8
+ export async function loadFeatures(ws) {
9
+ if (!(await pathExists(ws.features))) {
10
+ return { schemaVersion: FEATURE_SCHEMA_VERSION, features: [] };
11
+ }
12
+ return (await readVersioned(ws.features, 'features', FEATURE_SCHEMA_VERSION, validateFeatures)).data;
13
+ }
14
+ export async function saveFeatures(ws, file) {
15
+ validateFeatures(file);
16
+ await writeVersioned(ws, ws.features, file);
17
+ }
18
+ function countComponents(f) {
19
+ let total = 0;
20
+ let tests = 0;
21
+ const countGroup = (g, isTest = false) => {
22
+ if (!g)
23
+ return;
24
+ for (const arr of Object.values(g)) {
25
+ if (Array.isArray(arr)) {
26
+ total += arr.length;
27
+ if (isTest)
28
+ tests += arr.length;
29
+ }
30
+ }
31
+ };
32
+ countGroup(f.frontend);
33
+ countGroup(f.backend);
34
+ countGroup(f.database);
35
+ countGroup(f.tests, true);
36
+ return { total, tests };
37
+ }
38
+ export async function listFeaturesService(o) {
39
+ const ws = await requireWorkspace(o.cwd);
40
+ const file = await loadFeatures(ws);
41
+ return file.features.map((f) => {
42
+ const counts = countComponents(f);
43
+ return {
44
+ id: f.id,
45
+ name: f.name,
46
+ ...(f.description ? { description: f.description } : {}),
47
+ status: f.status ?? 'inferred',
48
+ componentsCount: counts.total,
49
+ testsCount: counts.tests,
50
+ ...(f.tags ? { tags: f.tags } : {}),
51
+ updatedAt: f.updatedAt ?? '',
52
+ };
53
+ });
54
+ }
55
+ export async function getFeatureService(o, id) {
56
+ const ws = await requireWorkspace(o.cwd);
57
+ const file = await loadFeatures(ws);
58
+ const target = file.features.find((f) => f.id.toLowerCase() === id.toLowerCase());
59
+ if (!target) {
60
+ throw new DevWorkspaceError('NOT_FOUND', `Feature "${id}" not found in .devworkspace/context/features.json.`, {
61
+ hint: 'Run "devworkspace feature list" to see existing features, or "devworkspace feature add" to create one.',
62
+ });
63
+ }
64
+ return target;
65
+ }
66
+ export async function validateFeatureMapService(o) {
67
+ const ws = await requireWorkspace(o.cwd);
68
+ const file = await loadFeatures(ws);
69
+ return validateFeatureMap(ws.root, file.features);
70
+ }
71
+ export async function saveFeatureService(o, input) {
72
+ const ws = await requireWorkspace(o.cwd);
73
+ const now = isoNow(o);
74
+ const item = {
75
+ id: input.id.trim(),
76
+ name: input.name.trim(),
77
+ ...(input.description ? { description: input.description.trim() } : {}),
78
+ status: input.status ?? 'inferred',
79
+ origin: input.origin ?? 'user',
80
+ ...(input.frontend ? { frontend: input.frontend } : {}),
81
+ ...(input.backend ? { backend: input.backend } : {}),
82
+ ...(input.database ? { database: input.database } : {}),
83
+ ...(input.tests ? { tests: input.tests } : {}),
84
+ ...(input.tags ? { tags: input.tags } : {}),
85
+ updatedAt: now,
86
+ };
87
+ // Perform self-validation through the schema
88
+ validateFeatures({ schemaVersion: FEATURE_SCHEMA_VERSION, features: [item] });
89
+ // Validate components against the disk to assign accurate initial status
90
+ const checked = await validateFeature(ws.root, item);
91
+ item.status = checked.status;
92
+ await mutate(o, async (w) => {
93
+ const current = await loadFeatures(w);
94
+ const index = current.features.findIndex((f) => f.id.toLowerCase() === item.id.toLowerCase());
95
+ if (index >= 0) {
96
+ current.features[index] = item;
97
+ }
98
+ else {
99
+ current.features.push(item);
100
+ }
101
+ await saveFeatures(w, current);
102
+ });
103
+ return item;
104
+ }
105
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/services/features.ts"],"names":[],"mappings":"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","sourcesContent":["import { FEATURE_SCHEMA_VERSION, validateFeatures } from '../features/schema.js';\nimport type { FeatureItem, FeaturesFile, FeatureValidationReport } from '../features/types.js';\nimport { readVersioned, writeVersioned } from '../core/versioned.js';\nimport { requireWorkspace, type Ws } from '../core/workspace.js';\nimport { DevWorkspaceError } from '../errors/index.js';\nimport { pathExists } from '../utils/fs.js';\nimport { validateFeature, validateFeatureMap } from '../features/validate.js';\nimport { isoNow, mutate, type ServiceOptions } from './common.js';\n\nexport interface FeatureSummary {\n id: string;\n name: string;\n description?: string;\n status: string;\n componentsCount: number;\n testsCount: number;\n tags?: string[];\n updatedAt: string;\n}\n\nexport async function loadFeatures(ws: Ws): Promise<FeaturesFile> {\n if (!(await pathExists(ws.features))) {\n return { schemaVersion: FEATURE_SCHEMA_VERSION, features: [] };\n }\n return (await readVersioned(ws.features, 'features', FEATURE_SCHEMA_VERSION, validateFeatures)).data;\n}\n\nexport async function saveFeatures(ws: Ws, file: FeaturesFile): Promise<void> {\n validateFeatures(file);\n await writeVersioned(ws, ws.features, file);\n}\n\nfunction countComponents(f: FeatureItem): { total: number; tests: number } {\n let total = 0;\n let tests = 0;\n\n const countGroup = (g?: Record<string, unknown[] | undefined>, isTest = false): void => {\n if (!g) return;\n for (const arr of Object.values(g)) {\n if (Array.isArray(arr)) {\n total += arr.length;\n if (isTest) tests += arr.length;\n }\n }\n };\n\n countGroup(f.frontend);\n countGroup(f.backend);\n countGroup(f.database);\n countGroup(f.tests, true);\n\n return { total, tests };\n}\n\nexport async function listFeaturesService(o: ServiceOptions): Promise<FeatureSummary[]> {\n const ws = await requireWorkspace(o.cwd);\n const file = await loadFeatures(ws);\n return file.features.map((f) => {\n const counts = countComponents(f);\n return {\n id: f.id,\n name: f.name,\n ...(f.description ? { description: f.description } : {}),\n status: f.status ?? 'inferred',\n componentsCount: counts.total,\n testsCount: counts.tests,\n ...(f.tags ? { tags: f.tags } : {}),\n updatedAt: f.updatedAt ?? '',\n };\n });\n}\n\nexport async function getFeatureService(o: ServiceOptions, id: string): Promise<FeatureItem> {\n const ws = await requireWorkspace(o.cwd);\n const file = await loadFeatures(ws);\n const target = file.features.find((f) => f.id.toLowerCase() === id.toLowerCase());\n if (!target) {\n throw new DevWorkspaceError('NOT_FOUND', `Feature \"${id}\" not found in .devworkspace/context/features.json.`, {\n hint: 'Run \"devworkspace feature list\" to see existing features, or \"devworkspace feature add\" to create one.',\n });\n }\n return target;\n}\n\nexport async function validateFeatureMapService(o: ServiceOptions): Promise<FeatureValidationReport> {\n const ws = await requireWorkspace(o.cwd);\n const file = await loadFeatures(ws);\n return validateFeatureMap(ws.root, file.features);\n}\n\nexport async function saveFeatureService(o: ServiceOptions, input: Partial<FeatureItem> & { id: string; name: string }): Promise<FeatureItem> {\n const ws = await requireWorkspace(o.cwd);\n const now = isoNow(o);\n\n const item: FeatureItem = {\n id: input.id.trim(),\n name: input.name.trim(),\n ...(input.description ? { description: input.description.trim() } : {}),\n status: input.status ?? 'inferred',\n origin: input.origin ?? 'user',\n ...(input.frontend ? { frontend: input.frontend } : {}),\n ...(input.backend ? { backend: input.backend } : {}),\n ...(input.database ? { database: input.database } : {}),\n ...(input.tests ? { tests: input.tests } : {}),\n ...(input.tags ? { tags: input.tags } : {}),\n updatedAt: now,\n };\n\n // Perform self-validation through the schema\n validateFeatures({ schemaVersion: FEATURE_SCHEMA_VERSION, features: [item] });\n\n // Validate components against the disk to assign accurate initial status\n const checked = await validateFeature(ws.root, item);\n item.status = checked.status;\n\n await mutate(o, async (w) => {\n const current = await loadFeatures(w);\n const index = current.features.findIndex((f) => f.id.toLowerCase() === item.id.toLowerCase());\n if (index >= 0) {\n current.features[index] = item;\n } else {\n current.features.push(item);\n }\n await saveFeatures(w, current);\n });\n\n return item;\n}\n\n"]}
@@ -0,0 +1,97 @@
1
+ import type { ServiceOptions } from './common.js';
2
+ export type NodeVerificationStatus = 'verified' | 'hypothesis';
3
+ export interface RawGraphNode {
4
+ id: string;
5
+ name?: string;
6
+ label?: string;
7
+ type?: string;
8
+ path?: string;
9
+ file?: string;
10
+ [key: string]: unknown;
11
+ }
12
+ export interface RawGraphEdge {
13
+ source: string;
14
+ target: string;
15
+ relation?: string;
16
+ type?: string;
17
+ label?: string;
18
+ weight?: number;
19
+ [key: string]: unknown;
20
+ }
21
+ export interface RawGraphData {
22
+ nodes?: RawGraphNode[];
23
+ edges?: RawGraphEdge[];
24
+ links?: RawGraphEdge[];
25
+ [key: string]: unknown;
26
+ }
27
+ export interface TracedNode {
28
+ id: string;
29
+ name: string;
30
+ type: string;
31
+ path: string | null;
32
+ symbol: string | null;
33
+ depth: number;
34
+ status: NodeVerificationStatus;
35
+ fileExists: boolean;
36
+ symbolFound: boolean | null;
37
+ reason?: string;
38
+ }
39
+ export interface TracedEdge {
40
+ source: string;
41
+ target: string;
42
+ relation: string;
43
+ status: NodeVerificationStatus;
44
+ }
45
+ export interface GraphStatusResult {
46
+ available: boolean;
47
+ graphPath: string;
48
+ nodesCount: number;
49
+ edgesCount: number;
50
+ nodeTypes: Record<string, number>;
51
+ message: string;
52
+ hint?: string;
53
+ }
54
+ export interface GraphTraceResult {
55
+ available: boolean;
56
+ query: string;
57
+ depth: number;
58
+ matchedNode: TracedNode | null;
59
+ totalNodes: number;
60
+ verifiedNodes: number;
61
+ hypothesisNodes: number;
62
+ nodes: TracedNode[];
63
+ edges: TracedEdge[];
64
+ warnings: string[];
65
+ }
66
+ /**
67
+ * Resolves the location of Graphify's output graph in the repository.
68
+ */
69
+ export declare function getGraphPath(root: string): string;
70
+ /**
71
+ * Loads and validates Graphify graph JSON data safely.
72
+ */
73
+ export declare function loadGraphData(root: string): Promise<{
74
+ exists: boolean;
75
+ path: string;
76
+ data?: {
77
+ nodes: RawGraphNode[];
78
+ edges: RawGraphEdge[];
79
+ };
80
+ }>;
81
+ /**
82
+ * Reports the presence, size, and basic schema health of the Graphify graph.
83
+ */
84
+ export declare function getGraphStatusService(o: ServiceOptions): Promise<GraphStatusResult>;
85
+ /**
86
+ * Finds the starting node in a graph that matches the user's query.
87
+ */
88
+ export declare function findMatchingStartNode(nodes: RawGraphNode[], query: string): RawGraphNode | null;
89
+ /**
90
+ * Performs a bounded graph trace starting from a specified file or symbol node up to maxDepth.
91
+ * Verifies every traversed node against the repository filesystem, marking unverified nodes
92
+ * and edges as hypotheses.
93
+ */
94
+ export declare function traceGraphService(o: ServiceOptions, query: string, options?: {
95
+ depth?: number;
96
+ maxNodes?: number;
97
+ }): Promise<GraphTraceResult>;