meto-cli 0.4.0 → 0.7.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [0.7.0] - 2026-03-05
9
+
10
+ ### Added
11
+
12
+ - Doctor command (`meto-cli doctor`) that checks methodology health of a Meto-scaffolded project
13
+ - 7 health checks: required files, context content, board format, epics content, agent definitions, WIP limit, orphan tasks
14
+ - Project root detection by walking up from current directory looking for `ai/tasks/`
15
+ - Scannable report with pass/warn/fail per check and summary line
16
+ - Exit code 1 when any check fails (0 for pass or warnings only)
17
+
18
+ ## [0.6.0] - 2026-03-05
19
+
20
+ ### Added
21
+
22
+ - 4 new stack presets: Python (FastAPI), Go, Vite + React, Flutter
23
+ - Each preset includes tailored tech-stack description, definition of done, and starter epics
24
+
25
+ ## [0.4.0] - 2026-03-05
26
+
27
+ ### Added
28
+
29
+ - AI-powered init: when Claude Code is detected, generates product vision, epics, and sliced backlog automatically
30
+ - User answers 5 questions instead of 10 when AI is available
31
+ - `--no-ai` flag to force static prompts even when Claude Code is installed
32
+ - AI generation with 90-second timeout and progress spinner
33
+ - Fallback to static prompts when AI generation fails (timeout, parse error, subprocess crash)
34
+ - Section-delimited AI output parsing with validation
35
+ - AI generation summary note showing what was generated
36
+ - Agent memory files scaffolded for PM, developer, and tester agents
37
+ - Agent Teams support with `.claude/settings.json` and file ownership boundaries
38
+
8
39
  ## [0.1.0] - 2026-03-04
9
40
 
10
41
  ### Added
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Lovable gives you an app. Meto gives you a project -- built the right way, your way.
4
4
 
5
- Meto scaffolds structured software projects with built-in methodology. You describe what you want to build, and Meto bootstraps a project with a kanban board, agent definitions, product context, and coding conventions -- ready for your first Claude Code session.
5
+ Meto scaffolds structured software projects with built-in methodology. You describe what you want to build, and Meto bootstraps a project with AI-generated epics, a sliced backlog, agent definitions, product context, and coding conventions -- ready for your first Claude Code session.
6
6
 
7
7
  ![demo](https://raw.githubusercontent.com/iLomer/Metho_agentic/main/assets/demo.gif)
8
8
 
@@ -14,23 +14,45 @@ Meto scaffolds structured software projects with built-in methodology. You descr
14
14
  npx meto-cli init
15
15
  ```
16
16
 
17
- Answer a few questions about your project, and Meto generates a fully structured repository in seconds.
17
+ Answer a few questions, and Meto generates a fully structured repository in seconds -- with AI-powered content if Claude Code is installed.
18
18
 
19
19
  ---
20
20
 
21
- ## What Just Happened?
21
+ ## How It Works
22
22
 
23
- After running `meto-cli init`, your new project comes pre-loaded with everything you need to start building with discipline:
23
+ Meto detects whether Claude Code is installed on your machine and offers two paths:
24
24
 
25
- - **CLAUDE.md** -- a project instruction file that Claude Code reads every session, pre-filled with your vision, stack, and conventions
26
- - **Kanban board** -- a task pipeline (backlog, todo, in-progress, testing, done) ready for your first sprint
27
- - **Agent definitions** -- PM, developer, and tester agents configured to follow your methodology from day one
28
- - **Product context** -- your vision, tech stack, and decisions captured in structured files so every session starts with shared context
29
- - **Epics and workflows** -- definition of done, commit conventions, and an epic backlog to plan against
30
- - **Agent Teams ready** -- three agents configured to work in parallel with file ownership boundaries
31
- - **Token optimized** -- generated files are optimized for token consumption with Claude Code, so every session gets more productive output per dollar spent
25
+ **With Claude Code (AI-powered):**
26
+ 1. You answer 5 questions -- project name, description, target users, tech stack, output directory
27
+ 2. Claude Code generates your product vision, problem statement, epics, and a sliced backlog with acceptance criteria
28
+ 3. Meto renders everything into a structured project ready for your first sprint
29
+
30
+ **Without Claude Code (static):**
31
+ 1. You answer 10 questions -- the 5 above plus problem statement, success criteria, value proposition, out of scope, and code conventions
32
+ 2. Meto renders your answers into the same structured project with sensible defaults
33
+
34
+ Both paths produce the same project structure. The AI path just fills in more content so you spend less time on setup and more time building.
35
+
36
+ Use `--no-ai` to force the static path even when Claude Code is available.
37
+
38
+ ---
39
+
40
+ ## Stack Presets
32
41
 
33
- No more hours of manual setup. No more "I forgot to write the CLAUDE.md." It is all there from the start.
42
+ Choose from 7 built-in tech stacks, each with a tailored description, definition of done, and starter epics:
43
+
44
+ | Stack | What you get |
45
+ |---|---|
46
+ | **Next.js + Supabase** | Full-stack web app with auth, database, and edge functions |
47
+ | **React Native** | Cross-platform mobile app |
48
+ | **Node.js CLI** | Command-line tool distributed via npm |
49
+ | **Python (FastAPI)** | REST API with async support, auto-generated docs |
50
+ | **Go** | Compiled backend service or CLI tool |
51
+ | **Vite + React** | Client-side SPA with fast dev server |
52
+ | **Flutter** | Cross-platform mobile and web app with Dart |
53
+ | **Custom** | Describe your own stack |
54
+
55
+ Each preset populates your tech-stack description, definition of done (with stack-specific checks), and starter epics so your backlog has real structure from day one.
34
56
 
35
57
  ---
36
58
 
@@ -70,6 +92,15 @@ your-project/
70
92
  └── CLAUDE.md
71
93
  ```
72
94
 
95
+ **What's inside:**
96
+ - **CLAUDE.md** -- project instructions that Claude Code reads every session, pre-filled with your vision, stack, and conventions
97
+ - **Kanban board** -- task pipeline (backlog, todo, in-progress, testing, done) ready for your first sprint
98
+ - **Agent definitions** -- PM, developer, and tester agents configured to follow your methodology from day one
99
+ - **Agent memory** -- persistent memory files so agents retain context across sessions
100
+ - **Product context** -- vision, tech stack, and decisions captured in structured files
101
+ - **Epics and workflows** -- definition of done, commit conventions, and an epic backlog to plan against
102
+ - **Agent Teams ready** -- three agents configured to work in parallel with file ownership boundaries
103
+
73
104
  ---
74
105
 
75
106
  ## Agent Teams
@@ -86,10 +117,6 @@ Meto scaffolds projects ready for Agent Teams out of the box:
86
117
 
87
118
  > "Create an agent team with @meto-pm for planning, @meto-developer for building, @meto-tester for validation"
88
119
 
89
- **Display modes:** use Shift+Down to cycle between agents in-process, or run each agent in its own split pane (tmux/iTerm2).
90
-
91
- This feature is experimental and enabled via `.claude/settings.json` in the scaffold.
92
-
93
120
  ---
94
121
 
95
122
  ## Next Steps
@@ -107,8 +134,8 @@ This feature is experimental and enabled via `.claude/settings.json` in the scaf
107
134
  | Requirement | Version | Notes |
108
135
  |---|---|---|
109
136
  | Node.js | >= 18 | Required to run the CLI |
110
- | git | any | Recommended -- Meto will initialize a repository if git is available |
111
- | Claude Code | latest | For the generated project to work with agents |
137
+ | git | any | Recommended -- Meto initializes a repository if git is available |
138
+ | Claude Code | latest | Optional -- enables AI-powered generation. Without it, Meto uses static prompts |
112
139
 
113
140
  ---
114
141
 
@@ -116,7 +143,8 @@ This feature is experimental and enabled via `.claude/settings.json` in the scaf
116
143
 
117
144
  | Command | Description |
118
145
  |---|---|
119
- | `meto-cli init` | Scaffold a new structured project |
146
+ | `meto-cli init` | Scaffold a new structured project (AI-powered if Claude Code is detected) |
147
+ | `meto-cli init --no-ai` | Scaffold using static prompts only, skip AI generation |
120
148
  | `meto-cli init --dry-run` | Preview the generated file tree without writing to disk |
121
149
  | `meto-cli --help` | Show available commands and options |
122
150
  | `meto-cli --version` | Show the installed version |
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Result of a single health check performed by the doctor command.
3
+ */
4
+ export interface HealthCheckResult {
5
+ /** Human-readable name of the check */
6
+ name: string;
7
+ /** Whether the check passed, produced a warning, or failed */
8
+ status: "pass" | "warn" | "fail";
9
+ /** Descriptive message explaining the result */
10
+ message: string;
11
+ }
12
+ /**
13
+ * Extracts all task slice identifiers (e.g. "slice-001") from a markdown file's
14
+ * ## [slice-NNN] headings.
15
+ */
16
+ export declare function extractSliceIds(content: string): string[];
17
+ /**
18
+ * Check 1: Required files exist.
19
+ * Each required file that is missing produces a "fail" result.
20
+ */
21
+ export declare function checkRequiredFiles(projectRoot: string): Promise<HealthCheckResult[]>;
22
+ /**
23
+ * Check 2: Context files are not empty.
24
+ * Files with 2 or fewer lines of content produce a "warn" result.
25
+ */
26
+ export declare function checkContextFilesNotEmpty(projectRoot: string): Promise<HealthCheckResult[]>;
27
+ /**
28
+ * Check 3: Board files start with a # heading.
29
+ */
30
+ export declare function checkBoardFileFormat(projectRoot: string): Promise<HealthCheckResult[]>;
31
+ /**
32
+ * Check 4: Epics file has content (at least one ## E heading).
33
+ */
34
+ export declare function checkEpicsFileHasContent(projectRoot: string): Promise<HealthCheckResult[]>;
35
+ /**
36
+ * Check 5: Agent definitions exist in .claude/agents/.
37
+ */
38
+ export declare function checkAgentDefinitions(projectRoot: string): Promise<HealthCheckResult[]>;
39
+ /**
40
+ * Check 6: In-progress limit (max 1 task in tasks-in-progress.md).
41
+ */
42
+ export declare function checkInProgressLimit(projectRoot: string): Promise<HealthCheckResult[]>;
43
+ /**
44
+ * Check 7: No orphan tasks (tasks in in-progress or in-testing must exist in backlog).
45
+ */
46
+ export declare function checkNoOrphanTasks(projectRoot: string): Promise<HealthCheckResult[]>;
47
+ /**
48
+ * Runs all methodology health checks against the given project root.
49
+ * Returns an array of check results -- one per individual check.
50
+ */
51
+ export declare function runHealthChecks(projectRoot: string): Promise<HealthCheckResult[]>;
52
+ //# sourceMappingURL=doctor-checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-checks.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-checks.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAsED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CASzD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAqB9B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA2B9B;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA2B9B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAyB9B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAoC9B;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA4B9B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA+D9B;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAmB9B"}
@@ -0,0 +1,331 @@
1
+ import { readFile, readdir, access } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ /**
4
+ * Files that must exist in every Meto-scaffolded project.
5
+ */
6
+ const REQUIRED_FILES = [
7
+ "CLAUDE.md",
8
+ "ai/context/product-vision.md",
9
+ "ai/context/tech-stack.md",
10
+ "ai/context/decisions.md",
11
+ "ai/backlog/epics.md",
12
+ "ai/tasks/tasks-backlog.md",
13
+ "ai/tasks/tasks-todo.md",
14
+ "ai/tasks/tasks-in-progress.md",
15
+ "ai/tasks/tasks-in-testing.md",
16
+ "ai/tasks/tasks-done.md",
17
+ "ai/workflows/definition-of-done.md",
18
+ ];
19
+ /**
20
+ * Context files that should have meaningful content (more than 2 lines).
21
+ */
22
+ const CONTEXT_FILES = [
23
+ "ai/context/product-vision.md",
24
+ "ai/context/tech-stack.md",
25
+ ];
26
+ /**
27
+ * Board files that should start with a # heading.
28
+ */
29
+ const BOARD_FILES = [
30
+ "ai/tasks/tasks-backlog.md",
31
+ "ai/tasks/tasks-todo.md",
32
+ "ai/tasks/tasks-in-progress.md",
33
+ "ai/tasks/tasks-in-testing.md",
34
+ "ai/tasks/tasks-done.md",
35
+ ];
36
+ /**
37
+ * Agent definition files that must exist in .claude/agents/.
38
+ */
39
+ const REQUIRED_AGENTS = [
40
+ "pm-agent.md",
41
+ "developer-agent.md",
42
+ "tester-agent.md",
43
+ ];
44
+ /**
45
+ * Checks whether a file exists at the given path.
46
+ */
47
+ async function fileExists(filePath) {
48
+ try {
49
+ await access(filePath);
50
+ return true;
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }
56
+ /**
57
+ * Safely reads a file, returning undefined if the file does not exist.
58
+ */
59
+ async function safeReadFile(filePath) {
60
+ try {
61
+ return await readFile(filePath, "utf-8");
62
+ }
63
+ catch {
64
+ return undefined;
65
+ }
66
+ }
67
+ /**
68
+ * Extracts all task slice identifiers (e.g. "slice-001") from a markdown file's
69
+ * ## [slice-NNN] headings.
70
+ */
71
+ export function extractSliceIds(content) {
72
+ const matches = content.match(/## \[slice-\d+\]/g);
73
+ if (matches === null) {
74
+ return [];
75
+ }
76
+ return matches.map((m) => {
77
+ const idMatch = /\[slice-\d+\]/.exec(m);
78
+ return idMatch ? idMatch[0] : "";
79
+ }).filter((id) => id.length > 0);
80
+ }
81
+ /**
82
+ * Check 1: Required files exist.
83
+ * Each required file that is missing produces a "fail" result.
84
+ */
85
+ export async function checkRequiredFiles(projectRoot) {
86
+ const results = [];
87
+ for (const file of REQUIRED_FILES) {
88
+ const exists = await fileExists(join(projectRoot, file));
89
+ if (exists) {
90
+ results.push({
91
+ name: `Required file: ${file}`,
92
+ status: "pass",
93
+ message: "File exists",
94
+ });
95
+ }
96
+ else {
97
+ results.push({
98
+ name: `Required file: ${file}`,
99
+ status: "fail",
100
+ message: `Missing required file: ${file}`,
101
+ });
102
+ }
103
+ }
104
+ return results;
105
+ }
106
+ /**
107
+ * Check 2: Context files are not empty.
108
+ * Files with 2 or fewer lines of content produce a "warn" result.
109
+ */
110
+ export async function checkContextFilesNotEmpty(projectRoot) {
111
+ const results = [];
112
+ for (const file of CONTEXT_FILES) {
113
+ const content = await safeReadFile(join(projectRoot, file));
114
+ if (content === undefined) {
115
+ // File missing is caught by checkRequiredFiles; skip here
116
+ continue;
117
+ }
118
+ const lines = content.split("\n").filter((line) => line.trim().length > 0);
119
+ if (lines.length > 2) {
120
+ results.push({
121
+ name: `Content check: ${file}`,
122
+ status: "pass",
123
+ message: "File has meaningful content",
124
+ });
125
+ }
126
+ else {
127
+ results.push({
128
+ name: `Content check: ${file}`,
129
+ status: "warn",
130
+ message: `${file} has ${lines.length} non-empty lines -- expected more than 2`,
131
+ });
132
+ }
133
+ }
134
+ return results;
135
+ }
136
+ /**
137
+ * Check 3: Board files start with a # heading.
138
+ */
139
+ export async function checkBoardFileFormat(projectRoot) {
140
+ const results = [];
141
+ for (const file of BOARD_FILES) {
142
+ const content = await safeReadFile(join(projectRoot, file));
143
+ if (content === undefined) {
144
+ // File missing is caught by checkRequiredFiles; skip here
145
+ continue;
146
+ }
147
+ const firstLine = content.trimStart().split("\n")[0];
148
+ if (firstLine.startsWith("# ")) {
149
+ results.push({
150
+ name: `Board format: ${file}`,
151
+ status: "pass",
152
+ message: "File starts with a heading",
153
+ });
154
+ }
155
+ else {
156
+ results.push({
157
+ name: `Board format: ${file}`,
158
+ status: "warn",
159
+ message: `${file} does not start with a # heading`,
160
+ });
161
+ }
162
+ }
163
+ return results;
164
+ }
165
+ /**
166
+ * Check 4: Epics file has content (at least one ## E heading).
167
+ */
168
+ export async function checkEpicsFileHasContent(projectRoot) {
169
+ const content = await safeReadFile(join(projectRoot, "ai/backlog/epics.md"));
170
+ if (content === undefined) {
171
+ // File missing is caught by checkRequiredFiles; skip here
172
+ return [];
173
+ }
174
+ const hasEpicHeading = /## E/.test(content);
175
+ if (hasEpicHeading) {
176
+ return [
177
+ {
178
+ name: "Epics file content",
179
+ status: "pass",
180
+ message: "Epics file contains at least one epic",
181
+ },
182
+ ];
183
+ }
184
+ return [
185
+ {
186
+ name: "Epics file content",
187
+ status: "warn",
188
+ message: "epics.md does not contain any ## E headings",
189
+ },
190
+ ];
191
+ }
192
+ /**
193
+ * Check 5: Agent definitions exist in .claude/agents/.
194
+ */
195
+ export async function checkAgentDefinitions(projectRoot) {
196
+ const results = [];
197
+ const agentsDir = join(projectRoot, ".claude", "agents");
198
+ let agentFiles;
199
+ try {
200
+ agentFiles = await readdir(agentsDir);
201
+ }
202
+ catch {
203
+ // Directory doesn't exist -- all agents are missing
204
+ for (const agent of REQUIRED_AGENTS) {
205
+ results.push({
206
+ name: `Agent definition: ${agent}`,
207
+ status: "fail",
208
+ message: `Missing agent definition: .claude/agents/${agent}`,
209
+ });
210
+ }
211
+ return results;
212
+ }
213
+ for (const agent of REQUIRED_AGENTS) {
214
+ if (agentFiles.includes(agent)) {
215
+ results.push({
216
+ name: `Agent definition: ${agent}`,
217
+ status: "pass",
218
+ message: "Agent definition exists",
219
+ });
220
+ }
221
+ else {
222
+ results.push({
223
+ name: `Agent definition: ${agent}`,
224
+ status: "fail",
225
+ message: `Missing agent definition: .claude/agents/${agent}`,
226
+ });
227
+ }
228
+ }
229
+ return results;
230
+ }
231
+ /**
232
+ * Check 6: In-progress limit (max 1 task in tasks-in-progress.md).
233
+ */
234
+ export async function checkInProgressLimit(projectRoot) {
235
+ const content = await safeReadFile(join(projectRoot, "ai/tasks/tasks-in-progress.md"));
236
+ if (content === undefined) {
237
+ return [];
238
+ }
239
+ const sliceIds = extractSliceIds(content);
240
+ const count = sliceIds.length;
241
+ if (count <= 1) {
242
+ return [
243
+ {
244
+ name: "WIP limit",
245
+ status: "pass",
246
+ message: `${count} task(s) in progress`,
247
+ },
248
+ ];
249
+ }
250
+ return [
251
+ {
252
+ name: "WIP limit",
253
+ status: "warn",
254
+ message: `WIP limit exceeded: ${count} tasks in progress, expected max 1.`,
255
+ },
256
+ ];
257
+ }
258
+ /**
259
+ * Check 7: No orphan tasks (tasks in in-progress or in-testing must exist in backlog).
260
+ */
261
+ export async function checkNoOrphanTasks(projectRoot) {
262
+ const backlogContent = await safeReadFile(join(projectRoot, "ai/tasks/tasks-backlog.md"));
263
+ const inProgressContent = await safeReadFile(join(projectRoot, "ai/tasks/tasks-in-progress.md"));
264
+ const inTestingContent = await safeReadFile(join(projectRoot, "ai/tasks/tasks-in-testing.md"));
265
+ if (backlogContent === undefined) {
266
+ return [];
267
+ }
268
+ const backlogIds = extractSliceIds(backlogContent);
269
+ const activeTasks = [];
270
+ if (inProgressContent !== undefined) {
271
+ for (const id of extractSliceIds(inProgressContent)) {
272
+ activeTasks.push({ id, source: "tasks-in-progress.md" });
273
+ }
274
+ }
275
+ if (inTestingContent !== undefined) {
276
+ for (const id of extractSliceIds(inTestingContent)) {
277
+ activeTasks.push({ id, source: "tasks-in-testing.md" });
278
+ }
279
+ }
280
+ if (activeTasks.length === 0) {
281
+ return [
282
+ {
283
+ name: "Orphan tasks",
284
+ status: "pass",
285
+ message: "No active tasks to check",
286
+ },
287
+ ];
288
+ }
289
+ const results = [];
290
+ let hasOrphan = false;
291
+ for (const task of activeTasks) {
292
+ if (!backlogIds.includes(task.id)) {
293
+ hasOrphan = true;
294
+ results.push({
295
+ name: `Orphan task: ${task.id}`,
296
+ status: "warn",
297
+ message: `${task.id} in ${task.source} has no matching entry in tasks-backlog.md`,
298
+ });
299
+ }
300
+ }
301
+ if (!hasOrphan) {
302
+ results.push({
303
+ name: "Orphan tasks",
304
+ status: "pass",
305
+ message: "All active tasks have backlog entries",
306
+ });
307
+ }
308
+ return results;
309
+ }
310
+ /**
311
+ * Runs all methodology health checks against the given project root.
312
+ * Returns an array of check results -- one per individual check.
313
+ */
314
+ export async function runHealthChecks(projectRoot) {
315
+ const allResults = [];
316
+ const checkFunctions = [
317
+ checkRequiredFiles,
318
+ checkContextFilesNotEmpty,
319
+ checkBoardFileFormat,
320
+ checkEpicsFileHasContent,
321
+ checkAgentDefinitions,
322
+ checkInProgressLimit,
323
+ checkNoOrphanTasks,
324
+ ];
325
+ for (const checkFn of checkFunctions) {
326
+ const results = await checkFn(projectRoot);
327
+ allResults.push(...results);
328
+ }
329
+ return allResults;
330
+ }
331
+ //# sourceMappingURL=doctor-checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-checks.js","sourceRoot":"","sources":["../../src/cli/doctor-checks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { HealthCheckResult } from "./doctor-checks.js";
2
+ /**
3
+ * Searches upward from the given starting directory for a Meto project root.
4
+ * A Meto project root is identified by the presence of an `ai/tasks/` directory.
5
+ *
6
+ * Returns the absolute path to the project root, or undefined if not found.
7
+ */
8
+ export declare function findProjectRoot(startDir: string): Promise<string | undefined>;
9
+ /**
10
+ * Determines the exit code based on health check results.
11
+ * Returns 0 if no failures (warnings are OK), 1 if any check failed.
12
+ */
13
+ export declare function determineExitCode(results: HealthCheckResult[]): number;
14
+ /**
15
+ * Entry point for the `meto-cli doctor` command.
16
+ * Detects the project root, runs health checks, and displays a report.
17
+ */
18
+ export declare function runDoctor(): Promise<void>;
19
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoB7B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAGtE;AA2BD;;;GAGG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CA6B/C"}
@@ -0,0 +1,87 @@
1
+ import { access } from "node:fs/promises";
2
+ import { join, dirname, resolve } from "node:path";
3
+ import * as p from "@clack/prompts";
4
+ import { runHealthChecks } from "./doctor-checks.js";
5
+ /**
6
+ * Searches upward from the given starting directory for a Meto project root.
7
+ * A Meto project root is identified by the presence of an `ai/tasks/` directory.
8
+ *
9
+ * Returns the absolute path to the project root, or undefined if not found.
10
+ */
11
+ export async function findProjectRoot(startDir) {
12
+ let current = resolve(startDir);
13
+ // eslint-disable-next-line no-constant-condition
14
+ while (true) {
15
+ const candidate = join(current, "ai", "tasks");
16
+ try {
17
+ await access(candidate);
18
+ return current;
19
+ }
20
+ catch {
21
+ // ai/tasks/ not found at this level, move up
22
+ }
23
+ const parent = dirname(current);
24
+ if (parent === current) {
25
+ // Reached filesystem root without finding a project
26
+ return undefined;
27
+ }
28
+ current = parent;
29
+ }
30
+ }
31
+ /**
32
+ * Determines the exit code based on health check results.
33
+ * Returns 0 if no failures (warnings are OK), 1 if any check failed.
34
+ */
35
+ export function determineExitCode(results) {
36
+ const hasFail = results.some((r) => r.status === "fail");
37
+ return hasFail ? 1 : 0;
38
+ }
39
+ /**
40
+ * Formats and displays health check results using clack output functions.
41
+ */
42
+ function displayResults(results) {
43
+ for (const result of results) {
44
+ switch (result.status) {
45
+ case "pass":
46
+ p.log.success(result.name);
47
+ break;
48
+ case "warn":
49
+ p.log.warning(`${result.name}: ${result.message}`);
50
+ break;
51
+ case "fail":
52
+ p.log.error(`${result.name}: ${result.message}`);
53
+ break;
54
+ }
55
+ }
56
+ const passed = results.filter((r) => r.status === "pass").length;
57
+ const warnings = results.filter((r) => r.status === "warn").length;
58
+ const failed = results.filter((r) => r.status === "fail").length;
59
+ p.note(`${passed} passed, ${warnings} warnings, ${failed} failed`, "Summary");
60
+ }
61
+ /**
62
+ * Entry point for the `meto-cli doctor` command.
63
+ * Detects the project root, runs health checks, and displays a report.
64
+ */
65
+ export async function runDoctor() {
66
+ p.intro("meto-cli doctor");
67
+ const projectRoot = await findProjectRoot(process.cwd());
68
+ if (projectRoot === undefined) {
69
+ p.log.error("No Meto project found. Run this command from within a Meto-scaffolded project.");
70
+ p.outro("");
71
+ process.exit(1);
72
+ }
73
+ p.log.info(`Meto project detected at ${projectRoot}`);
74
+ const results = await runHealthChecks(projectRoot);
75
+ displayResults(results);
76
+ const exitCode = determineExitCode(results);
77
+ if (exitCode === 0) {
78
+ p.outro("All checks passed.");
79
+ }
80
+ else {
81
+ p.outro("Some checks failed. Review the issues above.");
82
+ }
83
+ if (exitCode !== 0) {
84
+ process.exit(exitCode);
85
+ }
86
+ }
87
+ //# sourceMappingURL=doctor.js.map