ai-development-protocol 1.0.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/dist/index.js ADDED
@@ -0,0 +1,1192 @@
1
+ // src/core/constants.ts
2
+ import path from "path";
3
+ var AI_DIR = ".ai";
4
+ var CONTEXT_DIR = path.join(AI_DIR, "context");
5
+ var DECISIONS_DIR = path.join(AI_DIR, "decisions");
6
+ var TASKS_DIR = path.join(AI_DIR, "tasks");
7
+ var REPORTS_DIR = path.join(AI_DIR, "reports");
8
+ var TASKS_SUBDIRS = ["planned", "active", "completed"];
9
+ var REPORTS_SUBDIRS = ["reviews", "security", "testing"];
10
+ var REQUIRED_CONTEXT_FILES = [
11
+ "project.md",
12
+ "requirements.md",
13
+ "architecture.md",
14
+ "development.md",
15
+ "operations.md"
16
+ ];
17
+ var MATURITY_LEVELS = [
18
+ { level: 0, name: "IDEA", description: "A rough concept exists." },
19
+ { level: 1, name: "DISCOVERY", description: "Problem and users are becoming clear." },
20
+ { level: 2, name: "PRODUCT DEFINITION", description: "Core workflow and MVP are defined." },
21
+ { level: 3, name: "ARCHITECTURE", description: "Technical architecture is established." },
22
+ { level: 4, name: "IMPLEMENTATION", description: "The system is actively being built." },
23
+ { level: 5, name: "VALIDATION", description: "The implementation is being tested and refined." },
24
+ { level: 6, name: "OPERATIONS", description: "The system is deployed and maintained." },
25
+ { level: 7, name: "EVOLUTION", description: "The system continues to change based on new requirements." }
26
+ ];
27
+
28
+ // src/core/init.ts
29
+ import fs2 from "fs";
30
+ import path3 from "path";
31
+
32
+ // src/utils/fs.ts
33
+ import fs from "fs";
34
+ import path2 from "path";
35
+ function findProjectRoot(startDir = process.cwd()) {
36
+ let current = path2.resolve(startDir);
37
+ while (true) {
38
+ if (fs.existsSync(path2.join(current, ".ai"))) {
39
+ return current;
40
+ }
41
+ if (fs.existsSync(path2.join(current, "agent.md"))) {
42
+ return current;
43
+ }
44
+ if (fs.existsSync(path2.join(current, ".git"))) {
45
+ return current;
46
+ }
47
+ const parent = path2.dirname(current);
48
+ if (parent === current) {
49
+ return path2.resolve(startDir);
50
+ }
51
+ current = parent;
52
+ }
53
+ }
54
+ function ensureDir(dirPath) {
55
+ if (!fs.existsSync(dirPath)) {
56
+ fs.mkdirSync(dirPath, { recursive: true });
57
+ }
58
+ }
59
+ function slugify(text) {
60
+ return text.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
61
+ }
62
+ function writeFileAtomic(filePath, content) {
63
+ ensureDir(path2.dirname(filePath));
64
+ fs.writeFileSync(filePath, content, "utf-8");
65
+ }
66
+
67
+ // src/templates/readme.ts
68
+ function generateReadme(projectName = "Project") {
69
+ return `# AI Project Knowledge Base (${projectName})
70
+
71
+ This directory maintains the living engineering knowledge for **${projectName}**, following the **AI Project Development Protocol (v1.0.0)**.
72
+
73
+ ## How This Works
74
+
75
+ 1. **Conversation is the Primary Interface**: The project owner interacts through natural dialogue.
76
+ 2. **AI-Maintained**: The AI agent creates, updates, and synchronizes these artifacts progressively as decisions are confirmed.
77
+ 3. **Living Knowledge**: Designed to be accumulative, preserving context, architectural decisions, and tasks without documentation drift.
78
+
79
+ ## Directory Structure
80
+
81
+ \`\`\`text
82
+ .ai/
83
+ \u251C\u2500\u2500 README.md # This guide
84
+ \u251C\u2500\u2500 context/ # Authoritative system context
85
+ \u2502 \u251C\u2500\u2500 project.md # Identity, scope, state, and goals
86
+ \u2502 \u251C\u2500\u2500 requirements.md # Requirements, assumptions, and open questions
87
+ \u2502 \u251C\u2500\u2500 architecture.md # System structure, components, boundaries
88
+ \u2502 \u251C\u2500\u2500 development.md # Conventions, workflows, testing rules
89
+ \u2502 \u2514\u2500\u2500 operations.md # Deployment, environments, runbooks
90
+ \u251C\u2500\u2500 decisions/ # Architecture Decision Records (ADRs)
91
+ \u251C\u2500\u2500 tasks/ # Actionable work breakdown
92
+ \u2502 \u251C\u2500\u2500 planned/ # Ready to be started
93
+ \u2502 \u251C\u2500\u2500 active/ # Currently in progress
94
+ \u2502 \u2514\u2500\u2500 completed/ # Done and validated
95
+ \u2514\u2500\u2500 reports/ # Periodic evaluation records
96
+ \u251C\u2500\u2500 reviews/ # Code and design reviews
97
+ \u251C\u2500\u2500 security/ # Security audits
98
+ \u2514\u2500\u2500 testing/ # Test summaries
99
+ \`\`\`
100
+
101
+ ## Protocol Reference
102
+
103
+ See \`agent.md\` in the project root for the complete specification.
104
+ `;
105
+ }
106
+
107
+ // src/templates/project.ts
108
+ function generateProjectContext(meta = {}) {
109
+ const name = meta.name || "My Project";
110
+ const purpose = meta.purpose || "To be defined through discovery.";
111
+ const problem = meta.problem || "To be identified through conversation.";
112
+ const targetUsers = meta.targetUsers || "To be determined.";
113
+ const valueProposition = meta.valueProposition || "To be articulated.";
114
+ return `# Project Identity & State
115
+
116
+ ## 1. Project Identity
117
+
118
+ * **Project Name:** ${name}
119
+ * **Purpose:** ${purpose}
120
+ * **Problem:** ${problem}
121
+ * **Target Users:** ${targetUsers}
122
+ * **Value Proposition:** ${valueProposition}
123
+
124
+ ---
125
+
126
+ ## 2. Product Scope
127
+
128
+ ### Current Goals
129
+ - [ ] Initialize project foundation and requirements discovery.
130
+
131
+ ### MVP Scope
132
+ *To be defined.*
133
+
134
+ ### Future Possibilities
135
+ *To be explored.*
136
+
137
+ ### Out of Scope
138
+ *To be established.*
139
+
140
+ ---
141
+
142
+ ## 3. Project State
143
+
144
+ * **Current Goal:** Establish problem and user requirements.
145
+ * **Current Phase:** Level 1 \u2014 DISCOVERY
146
+ * **Confirmed Decisions:** Initial protocol structure established.
147
+ * **Active Work:** Initial discovery.
148
+ * **Open Questions:** See \`requirements.md\`.
149
+ * **Deferred Work:** None yet.
150
+ * **Known Constraints:** None yet.
151
+ * **Known Risks:** None identified.
152
+ `;
153
+ }
154
+
155
+ // src/templates/requirements.ts
156
+ function generateRequirementsContext() {
157
+ return `# Requirements & Discovery
158
+
159
+ ## 1. Functional Requirements
160
+
161
+ *Each requirement should preserve rationale (Reason) and confirmation status.*
162
+
163
+ *No confirmed functional requirements yet.*
164
+
165
+ ---
166
+
167
+ ## 2. Non-Functional Requirements
168
+
169
+ * **Performance:** Standard expectations.
170
+ * **Security:** Secure by default.
171
+ * **Maintainability:** Modular and clean code standards.
172
+
173
+ ---
174
+
175
+ ## 3. Constraints & Assumptions
176
+
177
+ ### Constraints
178
+ * None established.
179
+
180
+ ### Assumptions
181
+ * None established.
182
+
183
+ ---
184
+
185
+ ## 4. Open Questions
186
+
187
+ <!-- Questions being explored. When answered, move to confirmed decisions and remove from here. -->
188
+
189
+ - What is the primary problem this project solves?
190
+ - Who is the initial target audience?
191
+ - What are the absolute minimum features required for the MVP?
192
+ `;
193
+ }
194
+
195
+ // src/templates/architecture.ts
196
+ function generateArchitectureContext() {
197
+ return `# Architecture & System Design
198
+
199
+ ## 1. System Overview
200
+
201
+ *A high-level summary of the architecture once established.*
202
+
203
+ ---
204
+
205
+ ## 2. Core Components & Boundaries
206
+
207
+ *To be defined.*
208
+
209
+ ---
210
+
211
+ ## 3. Technology Stack
212
+
213
+ * **Runtime / Language:** To be determined.
214
+ * **Storage / Database:** To be determined.
215
+ * **Frameworks / Libraries:** To be determined.
216
+
217
+ ---
218
+
219
+ ## 4. Architectural Decisions Index
220
+
221
+ *See \`.ai/decisions/\` for detailed ADRs.*
222
+
223
+ | ID | Title | Status | Date |
224
+ |---|---|---|---|
225
+ | - | No ADRs created yet | - | - |
226
+ `;
227
+ }
228
+
229
+ // src/templates/development.ts
230
+ function generateDevelopmentContext() {
231
+ return `# Development Workflow & Conventions
232
+
233
+ ## 1. Environment & Setup
234
+
235
+ *Prerequisites and commands to get started.*
236
+
237
+ ---
238
+
239
+ ## 2. Coding Conventions
240
+
241
+ * Code style, linting, formatting rules, and naming conventions.
242
+
243
+ ---
244
+
245
+ ## 3. Implementation Workflow
246
+
247
+ Before implementing significant features:
248
+ 1. Understand the requirement.
249
+ 2. Inspect existing implementation.
250
+ 3. Identify affected components and boundaries.
251
+ 4. Check relevant architecture and ADRs.
252
+ 5. Identify dependencies and risks.
253
+ 6. Produce a concise implementation approach.
254
+ 7. Implement cleanly.
255
+ 8. Validate (tests, build, type checks).
256
+
257
+ ---
258
+
259
+ ## 4. Testing & Validation Strategy
260
+
261
+ * Test commands, coverage expectations, and verification steps.
262
+ `;
263
+ }
264
+
265
+ // src/templates/operations.ts
266
+ function generateOperationsContext() {
267
+ return `# Operations & Deployment
268
+
269
+ ## 1. Deployment Strategy
270
+
271
+ *Target hosting, CI/CD pipelines, containerization, and release process.*
272
+
273
+ ---
274
+
275
+ ## 2. Environment Configuration
276
+
277
+ *Required environment variables and secret management.*
278
+
279
+ ---
280
+
281
+ ## 3. Observability & Monitoring
282
+
283
+ *Logging standards, health checks, metrics, and error alerting.*
284
+ `;
285
+ }
286
+
287
+ // src/templates/agentBridge.ts
288
+ function generateAgentBridge(projectName = "Project") {
289
+ return `# AI Coding Assistant Instructions
290
+
291
+ You are the AI engineering partner for **${projectName}**, operating under the **AI Project Development Protocol** specified in \`agent.md\`.
292
+
293
+ ---
294
+
295
+ ## \u{1F680} Session Initialization (Every Fresh Session)
296
+
297
+ Whenever a new conversation session starts:
298
+
299
+ 1. **Check Project State First**:
300
+ - Inspect \`.ai/context/project.md\` and \`.ai/context/requirements.md\` (or run \`npx aidp status\`).
301
+ - Identify: Current Phase, Current Goal, Active Tasks, and Open Questions.
302
+
303
+ 2. **If This Is a Brand New / Greenfield Project (Level 0 or Level 1)**:
304
+ - Proactively greet the project owner:
305
+ > *"Tell me what you're thinking about. It doesn't need to be fully defined. We'll progressively turn the idea into a product, requirements, architecture, and implementation plan."*
306
+ - Guide the owner through discovery: problem, target users, core workflow, and MVP boundary.
307
+ - Do NOT start generating large boilerplate code until the core idea and architecture are confirmed.
308
+
309
+ 3. **If the Project Is Already Underway (Level 2+)**:
310
+ - Briefly summarize where the project currently stands based on \`.ai/context/project.md\` and active tasks.
311
+ - Ask how the owner would like to proceed with the active or planned tasks.
312
+
313
+ ---
314
+
315
+ ## \u{1F4CB} Core Operating Rules (from \`agent.md\`)
316
+
317
+ * **Conversation is the Primary Interface**: The project owner interacts through chat; you (the AI) maintain the \`.ai/\` artifacts automatically.
318
+ * **Brainstorming vs. Decisions**: Treat exploratory ideas as proposals. Only record ADRs when the owner explicitly confirms a technical choice.
319
+ * **Preserve Reasoning**: Every architectural choice must be recorded as an ADR with Problem, Options, Decision, and Consequences.
320
+ * **Implementation Boundary**: Do not write production code until the owner signals clear implementation intent (e.g. *"Build it"*, *"Let's implement this"*).
321
+ * **Validation Truth**: Always run real tests and build commands in the terminal before marking any task as complete. Never claim validation that was not run.
322
+ `;
323
+ }
324
+
325
+ // src/core/init.ts
326
+ import { fileURLToPath } from "url";
327
+ function initProtocol(options = {}) {
328
+ const root = path3.resolve(options.targetDir || process.cwd());
329
+ const aiPath = path3.join(root, AI_DIR);
330
+ const isAlreadyInit = fs2.existsSync(aiPath);
331
+ const createdFiles = [];
332
+ const skippedFiles = [];
333
+ ensureDir(aiPath);
334
+ ensureDir(path3.join(root, CONTEXT_DIR));
335
+ ensureDir(path3.join(root, DECISIONS_DIR));
336
+ for (const sub of TASKS_SUBDIRS) {
337
+ ensureDir(path3.join(root, TASKS_DIR, sub));
338
+ }
339
+ for (const sub of REPORTS_SUBDIRS) {
340
+ ensureDir(path3.join(root, REPORTS_DIR, sub));
341
+ }
342
+ const projectName = options.projectName || path3.basename(root);
343
+ const bridgeContent = generateAgentBridge(projectName);
344
+ const files = {
345
+ [path3.join(root, AI_DIR, "README.md")]: generateReadme(projectName),
346
+ [path3.join(root, CONTEXT_DIR, "project.md")]: generateProjectContext({
347
+ name: projectName,
348
+ ...options.meta
349
+ }),
350
+ [path3.join(root, CONTEXT_DIR, "requirements.md")]: generateRequirementsContext(),
351
+ [path3.join(root, CONTEXT_DIR, "architecture.md")]: generateArchitectureContext(),
352
+ [path3.join(root, CONTEXT_DIR, "development.md")]: generateDevelopmentContext(),
353
+ [path3.join(root, CONTEXT_DIR, "operations.md")]: generateOperationsContext()
354
+ };
355
+ if (options.includeBridges !== false) {
356
+ files[path3.join(root, "AGENTS.md")] = bridgeContent;
357
+ files[path3.join(root, "CLAUDE.md")] = bridgeContent;
358
+ files[path3.join(root, ".cursorrules")] = bridgeContent;
359
+ files[path3.join(root, ".github", "copilot-instructions.md")] = bridgeContent;
360
+ const rootAgentMd = path3.join(root, "agent.md");
361
+ if (!fs2.existsSync(rootAgentMd) || options.force) {
362
+ try {
363
+ const sourceAgentMd = fileURLToPath(new URL("../../agent.md", import.meta.url));
364
+ if (fs2.existsSync(sourceAgentMd)) {
365
+ files[rootAgentMd] = fs2.readFileSync(sourceAgentMd, "utf-8");
366
+ }
367
+ } catch {
368
+ }
369
+ }
370
+ }
371
+ for (const [filePath, content] of Object.entries(files)) {
372
+ if (fs2.existsSync(filePath) && !options.force) {
373
+ skippedFiles.push(path3.relative(root, filePath));
374
+ } else {
375
+ writeFileAtomic(filePath, content);
376
+ createdFiles.push(path3.relative(root, filePath));
377
+ }
378
+ }
379
+ const emptyDirs = [
380
+ path3.join(root, DECISIONS_DIR),
381
+ ...TASKS_SUBDIRS.map((s) => path3.join(root, TASKS_DIR, s)),
382
+ ...REPORTS_SUBDIRS.map((s) => path3.join(root, REPORTS_DIR, s))
383
+ ];
384
+ for (const dir of emptyDirs) {
385
+ const keepPath = path3.join(dir, ".gitkeep");
386
+ if (!fs2.existsSync(keepPath) && fs2.readdirSync(dir).length === 0) {
387
+ writeFileAtomic(keepPath, "");
388
+ }
389
+ }
390
+ return {
391
+ aiPath,
392
+ createdFiles,
393
+ skippedFiles,
394
+ alreadyInitialized: isAlreadyInit && !options.force
395
+ };
396
+ }
397
+
398
+ // src/core/status.ts
399
+ import fs6 from "fs";
400
+ import path7 from "path";
401
+
402
+ // src/core/adr.ts
403
+ import fs3 from "fs";
404
+ import path4 from "path";
405
+
406
+ // src/templates/adr.ts
407
+ function generateAdr(options) {
408
+ const padId = String(options.id).padStart(4, "0");
409
+ const dateStr = options.date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
410
+ const status = options.status || "Accepted";
411
+ const problem = options.problem || "Describe the architectural context and problem here.";
412
+ const optionsList = options.options && options.options.length > 0 ? options.options.map((opt, i) => `${i + 1}. **${opt}**`).join("\n") : "1. **Option 1:** Description\n2. **Option 2:** Description";
413
+ const decision = options.decision || "Describe the decision made and rationale.";
414
+ const consequences = options.consequences || "Describe positive and negative implications.";
415
+ return `# ADR-${padId}: ${options.title}
416
+
417
+ * **Status:** ${status}
418
+ * **Date:** ${dateStr}
419
+ * **Deciders:** AI & Project Owner
420
+
421
+ ## 1. Problem
422
+ ${problem}
423
+
424
+ ## 2. Options Considered
425
+ ${optionsList}
426
+
427
+ ## 3. Trade-offs
428
+ *Pros and cons evaluated during discussion.*
429
+
430
+ ## 4. Decision
431
+ ${decision}
432
+
433
+ ## 5. Consequences
434
+ ${consequences}
435
+ `;
436
+ }
437
+
438
+ // src/core/adr.ts
439
+ function listAdrs(projectRoot = findProjectRoot()) {
440
+ const decisionsPath = path4.join(projectRoot, DECISIONS_DIR);
441
+ if (!fs3.existsSync(decisionsPath)) {
442
+ return [];
443
+ }
444
+ const files = fs3.readdirSync(decisionsPath).filter((f) => f.endsWith(".md") && /^\d{4}-/.test(f)).sort();
445
+ const records = [];
446
+ for (const filename of files) {
447
+ const filePath = path4.join(decisionsPath, filename);
448
+ const content = fs3.readFileSync(filePath, "utf-8");
449
+ const idMatch = filename.match(/^(\d{4})/);
450
+ const id = idMatch ? parseInt(idMatch[1], 10) : 0;
451
+ const formattedId = idMatch ? idMatch[1] : "0000";
452
+ const titleMatch = content.match(/^#\s+ADR-\d+:\s*(.+)$/m);
453
+ const title2 = titleMatch ? titleMatch[1].trim() : filename.replace(/^\d{4}-|\.md$/g, "");
454
+ const statusMatch = content.match(/\*\s*\*\*Status:\*\*\s*(.+)$/m);
455
+ const status = statusMatch ? statusMatch[1].trim() : "Unknown";
456
+ const dateMatch = content.match(/\*\s*\*\*Date:\*\*\s*(.+)$/m);
457
+ const date = dateMatch ? dateMatch[1].trim() : "";
458
+ records.push({
459
+ id,
460
+ formattedId,
461
+ title: title2,
462
+ status,
463
+ date,
464
+ filename,
465
+ filePath
466
+ });
467
+ }
468
+ return records;
469
+ }
470
+ function getNextAdrId(projectRoot = findProjectRoot()) {
471
+ const adrs = listAdrs(projectRoot);
472
+ if (adrs.length === 0) return 1;
473
+ const maxId = Math.max(...adrs.map((a) => a.id));
474
+ return maxId + 1;
475
+ }
476
+ function createAdr(options) {
477
+ const root = options.projectRoot || findProjectRoot();
478
+ const nextId = getNextAdrId(root);
479
+ const formattedId = String(nextId).padStart(4, "0");
480
+ const slug = slugify(options.title);
481
+ const filename = `${formattedId}-${slug}.md`;
482
+ const decisionsPath = path4.join(root, DECISIONS_DIR);
483
+ ensureDir(decisionsPath);
484
+ const filePath = path4.join(decisionsPath, filename);
485
+ const content = generateAdr({
486
+ ...options,
487
+ id: nextId
488
+ });
489
+ writeFileAtomic(filePath, content);
490
+ syncAdrWithArchitecture(root, {
491
+ formattedId,
492
+ title: options.title,
493
+ status: options.status || "Accepted",
494
+ date: options.date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
495
+ filename
496
+ });
497
+ return {
498
+ id: nextId,
499
+ formattedId,
500
+ title: options.title,
501
+ status: options.status || "Accepted",
502
+ date: options.date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
503
+ filename,
504
+ filePath
505
+ };
506
+ }
507
+ function syncAdrWithArchitecture(projectRoot, adr) {
508
+ const archFile = path4.join(projectRoot, CONTEXT_DIR, "architecture.md");
509
+ if (!fs3.existsSync(archFile)) return;
510
+ let content = fs3.readFileSync(archFile, "utf-8");
511
+ const tableHeaderRegex = /(\| ID \| Title \| Status \| Date \|\r?\n\|---\|---\|---\|---\|\r?\n)([\s\S]*?)(?=\r?\n#|$)/;
512
+ const row = `| [ADR-${adr.formattedId}](../decisions/${adr.filename}) | ${adr.title} | ${adr.status} | ${adr.date} |`;
513
+ if (tableHeaderRegex.test(content)) {
514
+ content = content.replace(tableHeaderRegex, (match, header, body) => {
515
+ let rows = body.split(/\r?\n/).map((r) => r.trim()).filter((r) => r.length > 0 && !r.includes("No ADRs created yet"));
516
+ rows.push(row);
517
+ return `${header}${rows.join("\n")}
518
+ `;
519
+ });
520
+ writeFileAtomic(archFile, content);
521
+ }
522
+ }
523
+
524
+ // src/core/task.ts
525
+ import fs4 from "fs";
526
+ import path5 from "path";
527
+
528
+ // src/templates/task.ts
529
+ function generateTask(options) {
530
+ const status = options.status || "planned";
531
+ const createdDate = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
532
+ const goal = options.goal || "Describe the objective of this task.";
533
+ const reqRef = options.requirementsRef || "Refer to requirements.md";
534
+ const archRef = options.architectureRef || "Refer to architecture.md";
535
+ const stepsList = options.steps && options.steps.length > 0 ? options.steps.map((s) => `- [ ] ${s}`).join("\n") : "- [ ] Step 1: Design and setup\n- [ ] Step 2: Implementation\n- [ ] Step 3: Tests";
536
+ const validationList = options.validation && options.validation.length > 0 ? options.validation.map((v) => `- [ ] ${v}`).join("\n") : "- [ ] Unit and integration tests pass\n- [ ] Working behavior validated";
537
+ return `# ${options.id.toUpperCase()}: ${options.title}
538
+
539
+ * **Status:** ${status.toUpperCase()}
540
+ * **Created:** ${createdDate}
541
+ * **Category:** Implementation
542
+
543
+ ## Goal
544
+ ${goal}
545
+
546
+ ## Requirements Reference
547
+ ${reqRef}
548
+
549
+ ## Architecture Reference
550
+ ${archRef}
551
+
552
+ ## Implementation Steps
553
+ ${stepsList}
554
+
555
+ ## Validation Criteria
556
+ ${validationList}
557
+ `;
558
+ }
559
+
560
+ // src/core/task.ts
561
+ function listTasks(projectRoot = findProjectRoot()) {
562
+ const result = {
563
+ planned: [],
564
+ active: [],
565
+ completed: []
566
+ };
567
+ const tasksBase = path5.join(projectRoot, TASKS_DIR);
568
+ if (!fs4.existsSync(tasksBase)) {
569
+ return result;
570
+ }
571
+ for (const status of TASKS_SUBDIRS) {
572
+ const dir = path5.join(tasksBase, status);
573
+ if (!fs4.existsSync(dir)) continue;
574
+ const files = fs4.readdirSync(dir).filter((f) => f.endsWith(".md"));
575
+ for (const filename of files) {
576
+ const filePath = path5.join(dir, filename);
577
+ const content = fs4.readFileSync(filePath, "utf-8");
578
+ const titleMatch = content.match(/^#\s+([^:]+):\s*(.+)$/m);
579
+ const id = titleMatch ? titleMatch[1].trim() : filename.replace(/\.md$/, "");
580
+ const title2 = titleMatch ? titleMatch[2].trim() : filename.replace(/\.md$/, "");
581
+ result[status].push({
582
+ id,
583
+ title: title2,
584
+ status,
585
+ filename,
586
+ filePath
587
+ });
588
+ }
589
+ }
590
+ return result;
591
+ }
592
+ function getNextTaskId(projectRoot = findProjectRoot()) {
593
+ const all = listTasks(projectRoot);
594
+ const allTasks = [...all.planned, ...all.active, ...all.completed];
595
+ let maxNum = 0;
596
+ for (const t of allTasks) {
597
+ const m = t.filename.match(/task-(\d+)/i) || t.id.match(/task-(\d+)/i);
598
+ if (m) {
599
+ const num = parseInt(m[1], 10);
600
+ if (num > maxNum) maxNum = num;
601
+ }
602
+ }
603
+ return `TASK-${String(maxNum + 1).padStart(4, "0")}`;
604
+ }
605
+ function createTask(options) {
606
+ const root = options.projectRoot || findProjectRoot();
607
+ const id = options.id || getNextTaskId(root);
608
+ const status = options.status || "planned";
609
+ const slug = slugify(options.title);
610
+ const filename = `${id.toLowerCase()}-${slug}.md`;
611
+ const destDir = path5.join(root, TASKS_DIR, status);
612
+ ensureDir(destDir);
613
+ const filePath = path5.join(destDir, filename);
614
+ const content = generateTask({
615
+ ...options,
616
+ id,
617
+ status
618
+ });
619
+ writeFileAtomic(filePath, content);
620
+ return {
621
+ id,
622
+ title: options.title,
623
+ status,
624
+ filename,
625
+ filePath
626
+ };
627
+ }
628
+ function moveTask(taskIdOrName, newStatus, projectRoot = findProjectRoot()) {
629
+ const all = listTasks(projectRoot);
630
+ let found = null;
631
+ const search = taskIdOrName.toLowerCase();
632
+ for (const status of TASKS_SUBDIRS) {
633
+ const match = all[status].find(
634
+ (t) => t.id.toLowerCase() === search || t.filename.toLowerCase().includes(search)
635
+ );
636
+ if (match) {
637
+ found = match;
638
+ break;
639
+ }
640
+ }
641
+ if (!found) {
642
+ throw new Error(`Task matching "${taskIdOrName}" was not found.`);
643
+ }
644
+ if (found.status === newStatus) {
645
+ return found;
646
+ }
647
+ const oldPath = found.filePath;
648
+ const newDir = path5.join(projectRoot, TASKS_DIR, newStatus);
649
+ ensureDir(newDir);
650
+ const newPath = path5.join(newDir, found.filename);
651
+ let content = fs4.readFileSync(oldPath, "utf-8");
652
+ content = content.replace(/\*\s*\*\*Status:\*\*\s*(.+)$/m, `* **Status:** ${newStatus.toUpperCase()}`);
653
+ fs4.unlinkSync(oldPath);
654
+ writeFileAtomic(newPath, content);
655
+ return {
656
+ ...found,
657
+ status: newStatus,
658
+ filePath: newPath
659
+ };
660
+ }
661
+
662
+ // src/core/question.ts
663
+ import fs5 from "fs";
664
+ import path6 from "path";
665
+ function listOpenQuestions(projectRoot = findProjectRoot()) {
666
+ const reqPath = path6.join(projectRoot, CONTEXT_DIR, "requirements.md");
667
+ if (!fs5.existsSync(reqPath)) return [];
668
+ const content = fs5.readFileSync(reqPath, "utf-8");
669
+ const sectionMatch = content.match(/## 4\. Open Questions([\s\S]*?)(?=\r?\n##|$)/);
670
+ if (!sectionMatch) return [];
671
+ const lines = sectionMatch[1].split(/\r?\n/);
672
+ const questions = [];
673
+ for (const line of lines) {
674
+ const trimmed = line.trim();
675
+ if (trimmed.startsWith("- ") || trimmed.startsWith("* ")) {
676
+ questions.push(trimmed.slice(2).trim());
677
+ }
678
+ }
679
+ return questions;
680
+ }
681
+ function addOpenQuestion(question, projectRoot = findProjectRoot()) {
682
+ const reqPath = path6.join(projectRoot, CONTEXT_DIR, "requirements.md");
683
+ if (!fs5.existsSync(reqPath)) {
684
+ throw new Error(`requirements.md not found at ${reqPath}`);
685
+ }
686
+ let content = fs5.readFileSync(reqPath, "utf-8");
687
+ const sectionHeader = "## 4. Open Questions";
688
+ const idx = content.indexOf(sectionHeader);
689
+ if (idx === -1) {
690
+ content += `
691
+
692
+ ${sectionHeader}
693
+
694
+ - ${question}
695
+ `;
696
+ } else {
697
+ content = content.replace(/(## 4\. Open Questions[\s\S]*?)(\r?\n\r?\n##|\r?\n?$)/, (match, prefix, suffix) => {
698
+ return `${prefix.trimEnd()}
699
+ - ${question}
700
+ ${suffix}`;
701
+ });
702
+ }
703
+ writeFileAtomic(reqPath, content);
704
+ }
705
+
706
+ // src/core/status.ts
707
+ function getProjectStatus(projectRoot = findProjectRoot()) {
708
+ const projectFile = path7.join(projectRoot, CONTEXT_DIR, "project.md");
709
+ const isInitialized = fs6.existsSync(projectFile);
710
+ if (!isInitialized) {
711
+ return {
712
+ isInitialized: false,
713
+ name: path7.basename(projectRoot),
714
+ currentGoal: "Not initialized",
715
+ currentPhase: "Unknown",
716
+ adrs: [],
717
+ tasks: { planned: [], active: [], completed: [] },
718
+ openQuestions: []
719
+ };
720
+ }
721
+ const projectContent = fs6.readFileSync(projectFile, "utf-8");
722
+ const nameMatch = projectContent.match(/\*\s*\*\*Project Name:\*\*\s*(.+)$/m);
723
+ const name = nameMatch ? nameMatch[1].trim() : path7.basename(projectRoot);
724
+ const goalMatch = projectContent.match(/\*\s*\*\*Current Goal:\*\*\s*(.+)$/m);
725
+ const currentGoal = goalMatch ? goalMatch[1].trim() : "Unspecified";
726
+ const phaseMatch = projectContent.match(/\*\s*\*\*Current Phase:\*\*\s*(.+)$/m);
727
+ const currentPhase = phaseMatch ? phaseMatch[1].trim() : "Unknown";
728
+ const adrs = listAdrs(projectRoot);
729
+ const tasks = listTasks(projectRoot);
730
+ const openQuestions = listOpenQuestions(projectRoot);
731
+ return {
732
+ isInitialized: true,
733
+ name,
734
+ currentGoal,
735
+ currentPhase,
736
+ adrs,
737
+ tasks,
738
+ openQuestions
739
+ };
740
+ }
741
+
742
+ // src/core/validate.ts
743
+ import fs7 from "fs";
744
+ import path8 from "path";
745
+ function validateProtocol(projectRoot = findProjectRoot()) {
746
+ const errors = [];
747
+ const warnings = [];
748
+ let checkedItems = 0;
749
+ const aiPath = path8.join(projectRoot, AI_DIR);
750
+ checkedItems++;
751
+ if (!fs7.existsSync(aiPath)) {
752
+ return {
753
+ valid: false,
754
+ errors: [`AI protocol directory '${AI_DIR}' does not exist at ${projectRoot}`],
755
+ warnings: [],
756
+ checkedItems
757
+ };
758
+ }
759
+ checkedItems++;
760
+ const readmePath = path8.join(aiPath, "README.md");
761
+ if (!fs7.existsSync(readmePath)) {
762
+ warnings.push(`Missing '${AI_DIR}/README.md' guide.`);
763
+ }
764
+ const contextPath = path8.join(projectRoot, CONTEXT_DIR);
765
+ checkedItems++;
766
+ if (!fs7.existsSync(contextPath)) {
767
+ errors.push(`Missing context directory at '${CONTEXT_DIR}'.`);
768
+ } else {
769
+ for (const file of REQUIRED_CONTEXT_FILES) {
770
+ checkedItems++;
771
+ const filePath = path8.join(contextPath, file);
772
+ if (!fs7.existsSync(filePath)) {
773
+ errors.push(`Missing required context file: '${path8.join(CONTEXT_DIR, file)}'.`);
774
+ }
775
+ }
776
+ }
777
+ const decisionsPath = path8.join(projectRoot, DECISIONS_DIR);
778
+ checkedItems++;
779
+ if (!fs7.existsSync(decisionsPath)) {
780
+ errors.push(`Missing decisions directory at '${DECISIONS_DIR}'.`);
781
+ } else {
782
+ const files = fs7.readdirSync(decisionsPath).filter((f) => f.endsWith(".md"));
783
+ for (const f of files) {
784
+ checkedItems++;
785
+ if (!/^\d{4}-[\w-]+\.md$/.test(f)) {
786
+ warnings.push(`ADR file '${f}' does not follow the naming convention: '0001-slug-title.md'.`);
787
+ }
788
+ }
789
+ }
790
+ const tasksPath = path8.join(projectRoot, TASKS_DIR);
791
+ checkedItems++;
792
+ if (!fs7.existsSync(tasksPath)) {
793
+ errors.push(`Missing tasks directory at '${TASKS_DIR}'.`);
794
+ } else {
795
+ for (const sub of TASKS_SUBDIRS) {
796
+ checkedItems++;
797
+ const subPath = path8.join(tasksPath, sub);
798
+ if (!fs7.existsSync(subPath)) {
799
+ errors.push(`Missing task subfolder: '${path8.join(TASKS_DIR, sub)}'.`);
800
+ }
801
+ }
802
+ }
803
+ const reportsPath = path8.join(projectRoot, REPORTS_DIR);
804
+ checkedItems++;
805
+ if (!fs7.existsSync(reportsPath)) {
806
+ warnings.push(`Missing reports directory at '${REPORTS_DIR}'.`);
807
+ } else {
808
+ for (const sub of REPORTS_SUBDIRS) {
809
+ checkedItems++;
810
+ const subPath = path8.join(reportsPath, sub);
811
+ if (!fs7.existsSync(subPath)) {
812
+ warnings.push(`Missing report subfolder: '${path8.join(REPORTS_DIR, sub)}'.`);
813
+ }
814
+ }
815
+ }
816
+ return {
817
+ valid: errors.length === 0,
818
+ errors,
819
+ warnings,
820
+ checkedItems
821
+ };
822
+ }
823
+
824
+ // src/cli.ts
825
+ import path9 from "path";
826
+
827
+ // src/utils/format.ts
828
+ var isColorSupported = !process.env.NO_COLOR && (process.stdout?.isTTY ?? false);
829
+ var colors = {
830
+ reset: isColorSupported ? "\x1B[0m" : "",
831
+ bold: isColorSupported ? "\x1B[1m" : "",
832
+ dim: isColorSupported ? "\x1B[2m" : "",
833
+ italic: isColorSupported ? "\x1B[3m" : "",
834
+ underline: isColorSupported ? "\x1B[4m" : "",
835
+ red: isColorSupported ? "\x1B[31m" : "",
836
+ green: isColorSupported ? "\x1B[32m" : "",
837
+ yellow: isColorSupported ? "\x1B[33m" : "",
838
+ blue: isColorSupported ? "\x1B[34m" : "",
839
+ magenta: isColorSupported ? "\x1B[35m" : "",
840
+ cyan: isColorSupported ? "\x1B[36m" : "",
841
+ gray: isColorSupported ? "\x1B[90m" : ""
842
+ };
843
+ function success(msg) {
844
+ return `${colors.green}\u2714${colors.reset} ${msg}`;
845
+ }
846
+ function info(msg) {
847
+ return `${colors.cyan}\u2139${colors.reset} ${msg}`;
848
+ }
849
+ function warn(msg) {
850
+ return `${colors.yellow}\u26A0${colors.reset} ${msg}`;
851
+ }
852
+ function error(msg) {
853
+ return `${colors.red}\u2716${colors.reset} ${msg}`;
854
+ }
855
+ function title(msg) {
856
+ return `${colors.bold}${colors.cyan}${msg}${colors.reset}`;
857
+ }
858
+
859
+ // src/cli.ts
860
+ function runCli(argv) {
861
+ const args = argv.slice(2);
862
+ const command = args[0] || "help";
863
+ switch (command) {
864
+ case "init": {
865
+ handleInit(args.slice(1));
866
+ break;
867
+ }
868
+ case "status": {
869
+ handleStatus(args.slice(1));
870
+ break;
871
+ }
872
+ case "validate": {
873
+ handleValidate(args.slice(1));
874
+ break;
875
+ }
876
+ case "adr": {
877
+ handleAdr(args.slice(1));
878
+ break;
879
+ }
880
+ case "task": {
881
+ handleTask(args.slice(1));
882
+ break;
883
+ }
884
+ case "question": {
885
+ handleQuestion(args.slice(1));
886
+ break;
887
+ }
888
+ case "help":
889
+ case "--help":
890
+ case "-h":
891
+ printHelp();
892
+ break;
893
+ case "version":
894
+ case "--version":
895
+ case "-v":
896
+ console.log("aidp (AI Development Protocol CLI) v1.0.0");
897
+ break;
898
+ default:
899
+ console.error(error(`Unknown command: "${command}"`));
900
+ console.log(info("Run `aidp help` for a list of available commands."));
901
+ process.exit(1);
902
+ }
903
+ }
904
+ function handleInit(args) {
905
+ let targetDir = process.cwd();
906
+ let projectName;
907
+ let force = false;
908
+ for (let i = 0; i < args.length; i++) {
909
+ if (args[i] === "--force" || args[i] === "-f") {
910
+ force = true;
911
+ } else if (args[i] === "--name" || args[i] === "-n") {
912
+ projectName = args[++i];
913
+ } else if (!args[i].startsWith("-")) {
914
+ targetDir = path9.resolve(args[i]);
915
+ }
916
+ }
917
+ console.log(title("Initializing AI Project Development Protocol..."));
918
+ const res = initProtocol({ targetDir, projectName, force });
919
+ if (res.createdFiles.length > 0) {
920
+ console.log(success(`Created ${res.createdFiles.length} file(s) in ${res.aiPath}:`));
921
+ for (const f of res.createdFiles) {
922
+ console.log(` + ${f}`);
923
+ }
924
+ }
925
+ if (res.skippedFiles.length > 0) {
926
+ console.log(warn(`Skipped ${res.skippedFiles.length} existing file(s) (use --force to overwrite):`));
927
+ for (const f of res.skippedFiles) {
928
+ console.log(` ~ ${f}`);
929
+ }
930
+ }
931
+ console.log(success("Initialization complete!"));
932
+ }
933
+ function handleStatus(args) {
934
+ const targetDir = args[0] ? path9.resolve(args[0]) : findProjectRoot();
935
+ const status = getProjectStatus(targetDir);
936
+ if (!status.isInitialized) {
937
+ console.log(warn(`No AI Project Development Protocol found at ${targetDir}`));
938
+ console.log(info("Run `aidp init` to set up the protocol."));
939
+ return;
940
+ }
941
+ console.log(title(`=== ${status.name} ===`));
942
+ console.log(`${colors.bold}Current Phase:${colors.reset} ${status.currentPhase}`);
943
+ console.log(`${colors.bold}Current Goal:${colors.reset} ${status.currentGoal}`);
944
+ console.log();
945
+ const totalTasks = status.tasks.planned.length + status.tasks.active.length + status.tasks.completed.length;
946
+ console.log(`${colors.bold}Tasks (${totalTasks}):${colors.reset}`);
947
+ console.log(` ${colors.blue}Active (${status.tasks.active.length}):${colors.reset}`);
948
+ for (const t of status.tasks.active) {
949
+ console.log(` * [${t.id}] ${t.title}`);
950
+ }
951
+ console.log(` ${colors.yellow}Planned (${status.tasks.planned.length}):${colors.reset}`);
952
+ for (const t of status.tasks.planned) {
953
+ console.log(` * [${t.id}] ${t.title}`);
954
+ }
955
+ console.log(` ${colors.green}Completed (${status.tasks.completed.length}):${colors.reset}`);
956
+ for (const t of status.tasks.completed) {
957
+ console.log(` * [${t.id}] ${t.title}`);
958
+ }
959
+ console.log();
960
+ console.log(`${colors.bold}Architectural Decisions (${status.adrs.length}):${colors.reset}`);
961
+ if (status.adrs.length === 0) {
962
+ console.log(" (None recorded yet)");
963
+ } else {
964
+ for (const adr of status.adrs) {
965
+ console.log(` * ADR-${adr.formattedId}: ${adr.title} [${adr.status}] (${adr.date})`);
966
+ }
967
+ }
968
+ console.log();
969
+ console.log(`${colors.bold}Open Questions (${status.openQuestions.length}):${colors.reset}`);
970
+ if (status.openQuestions.length === 0) {
971
+ console.log(" (No open questions)");
972
+ } else {
973
+ for (const q of status.openQuestions) {
974
+ console.log(` ? ${q}`);
975
+ }
976
+ }
977
+ }
978
+ function handleValidate(args) {
979
+ const targetDir = args[0] ? path9.resolve(args[0]) : findProjectRoot();
980
+ console.log(title("Validating AI Project Development Protocol structure..."));
981
+ const report = validateProtocol(targetDir);
982
+ if (report.warnings.length > 0) {
983
+ console.log(warn(`Warnings (${report.warnings.length}):`));
984
+ for (const w of report.warnings) {
985
+ console.log(` \u26A0 ${w}`);
986
+ }
987
+ }
988
+ if (report.errors.length > 0) {
989
+ console.log(error(`Errors (${report.errors.length}):`));
990
+ for (const e of report.errors) {
991
+ console.log(` \u2716 ${e}`);
992
+ }
993
+ console.log(error(`Validation FAILED with ${report.errors.length} error(s).`));
994
+ process.exit(1);
995
+ } else {
996
+ console.log(success(`Validation PASSED! Checked ${report.checkedItems} items.`));
997
+ }
998
+ }
999
+ function handleAdr(args) {
1000
+ const sub = args[0];
1001
+ if (sub === "list") {
1002
+ const root = findProjectRoot();
1003
+ const adrs = listAdrs(root);
1004
+ console.log(title(`Architecture Decision Records (${adrs.length}):`));
1005
+ if (adrs.length === 0) {
1006
+ console.log(info("No ADRs found. Create one with `aidp adr new <title>`."));
1007
+ return;
1008
+ }
1009
+ for (const adr of adrs) {
1010
+ console.log(` ADR-${adr.formattedId} [${adr.status}] - ${adr.title} (${adr.date})`);
1011
+ }
1012
+ return;
1013
+ }
1014
+ if (sub === "new") {
1015
+ const titleParts = [];
1016
+ let status = "Accepted";
1017
+ for (let i = 1; i < args.length; i++) {
1018
+ if (args[i] === "--status" && args[i + 1]) {
1019
+ status = args[++i];
1020
+ } else {
1021
+ titleParts.push(args[i]);
1022
+ }
1023
+ }
1024
+ const titleStr = titleParts.join(" ").trim();
1025
+ if (!titleStr) {
1026
+ console.error(error("Please provide a title for the ADR: `aidp adr new <title>`"));
1027
+ process.exit(1);
1028
+ }
1029
+ const record = createAdr({ title: titleStr, status });
1030
+ console.log(success(`Created ADR-${record.formattedId}: ${record.title}`));
1031
+ console.log(info(`File saved to: ${record.filePath}`));
1032
+ return;
1033
+ }
1034
+ console.error(error(`Unknown adr subcommand: "${sub}"`));
1035
+ console.log(info("Available subcommands: `aidp adr list`, `aidp adr new <title>`"));
1036
+ process.exit(1);
1037
+ }
1038
+ function handleTask(args) {
1039
+ const sub = args[0];
1040
+ if (sub === "list") {
1041
+ const root = findProjectRoot();
1042
+ const tasks = listTasks(root);
1043
+ console.log(title("Project Tasks:"));
1044
+ for (const s of ["active", "planned", "completed"]) {
1045
+ console.log(`
1046
+ ${colors.bold}${s.toUpperCase()} (${tasks[s].length}):${colors.reset}`);
1047
+ if (tasks[s].length === 0) {
1048
+ console.log(" (None)");
1049
+ } else {
1050
+ for (const t of tasks[s]) {
1051
+ console.log(` * [${t.id}] ${t.title}`);
1052
+ }
1053
+ }
1054
+ }
1055
+ return;
1056
+ }
1057
+ if (sub === "new") {
1058
+ const titleParts = [];
1059
+ let status = "planned";
1060
+ let goal;
1061
+ for (let i = 1; i < args.length; i++) {
1062
+ if (args[i] === "--status" && args[i + 1]) {
1063
+ status = args[++i];
1064
+ } else if (args[i] === "--active") {
1065
+ status = "active";
1066
+ } else if (args[i] === "--goal" && args[i + 1]) {
1067
+ goal = args[++i];
1068
+ } else {
1069
+ titleParts.push(args[i]);
1070
+ }
1071
+ }
1072
+ const titleStr = titleParts.join(" ").trim();
1073
+ if (!titleStr) {
1074
+ console.error(error("Please provide a title for the task: `aidp task new <title>`"));
1075
+ process.exit(1);
1076
+ }
1077
+ const task = createTask({ title: titleStr, status, goal });
1078
+ console.log(success(`Created task [${task.id}] in ${task.status}: ${task.title}`));
1079
+ console.log(info(`File saved to: ${task.filePath}`));
1080
+ return;
1081
+ }
1082
+ if (sub === "move") {
1083
+ const taskId = args[1];
1084
+ const targetStatus = args[2];
1085
+ if (!taskId || !targetStatus) {
1086
+ console.error(error("Usage: `aidp task move <taskId> <planned|active|completed>`"));
1087
+ process.exit(1);
1088
+ }
1089
+ if (!["planned", "active", "completed"].includes(targetStatus)) {
1090
+ console.error(error(`Invalid status "${targetStatus}". Must be planned, active, or completed.`));
1091
+ process.exit(1);
1092
+ }
1093
+ try {
1094
+ const moved = moveTask(taskId, targetStatus);
1095
+ console.log(success(`Moved [${moved.id}] "${moved.title}" to ${moved.status}`));
1096
+ } catch (err) {
1097
+ console.error(error(err.message));
1098
+ process.exit(1);
1099
+ }
1100
+ return;
1101
+ }
1102
+ console.error(error(`Unknown task subcommand: "${sub}"`));
1103
+ console.log(info("Available subcommands: `aidp task list`, `aidp task new <title>`, `aidp task move <id> <status>`"));
1104
+ process.exit(1);
1105
+ }
1106
+ function handleQuestion(args) {
1107
+ const sub = args[0];
1108
+ if (sub === "list") {
1109
+ const root = findProjectRoot();
1110
+ const questions = listOpenQuestions(root);
1111
+ console.log(title(`Open Questions (${questions.length}):`));
1112
+ if (questions.length === 0) {
1113
+ console.log(info("No open questions tracked."));
1114
+ return;
1115
+ }
1116
+ for (const q of questions) {
1117
+ console.log(` ? ${q}`);
1118
+ }
1119
+ return;
1120
+ }
1121
+ if (sub === "add") {
1122
+ const qStr = args.slice(1).join(" ").trim();
1123
+ if (!qStr) {
1124
+ console.error(error("Please provide a question: `aidp question add <question>`"));
1125
+ process.exit(1);
1126
+ }
1127
+ addOpenQuestion(qStr);
1128
+ console.log(success(`Added open question to requirements.md: "${qStr}"`));
1129
+ return;
1130
+ }
1131
+ console.error(error(`Unknown question subcommand: "${sub}"`));
1132
+ console.log(info("Available subcommands: `aidp question list`, `aidp question add <question>`"));
1133
+ process.exit(1);
1134
+ }
1135
+ function printHelp() {
1136
+ console.log(`
1137
+ ${colors.bold}${colors.cyan}AI Project Development Protocol (AIDP) CLI${colors.reset}
1138
+ Version 1.0.0 \u2014 Tool-agnostic protocol automation and management
1139
+
1140
+ ${colors.bold}USAGE:${colors.reset}
1141
+ aidp <command> [options]
1142
+
1143
+ ${colors.bold}COMMANDS:${colors.reset}
1144
+ ${colors.green}init [path]${colors.reset} Scaffold the .ai/ protocol directory & context files
1145
+ --name, -n <name> Set project name
1146
+ --force, -f Overwrite existing files
1147
+
1148
+ ${colors.green}status [path]${colors.reset} Show project state, active tasks, ADRs, questions
1149
+ ${colors.green}validate [path]${colors.reset} Verify protocol directory structure & context
1150
+
1151
+ ${colors.green}adr list${colors.reset} List all Architecture Decision Records
1152
+ ${colors.green}adr new <title> [options]${colors.reset} Create a new numbered ADR
1153
+ --status <status> Status (Proposed | Accepted | Rejected | Superseded)
1154
+
1155
+ ${colors.green}task list${colors.reset} List all tasks by lifecycle status
1156
+ ${colors.green}task new <title> [options]${colors.reset} Create a new task specification
1157
+ --active Set status to active (default: planned)
1158
+ --goal <text> Set task goal
1159
+ ${colors.green}task move <id> <status>${colors.reset} Move task between planned | active | completed
1160
+
1161
+ ${colors.green}question list${colors.reset} List open questions from requirements.md
1162
+ ${colors.green}question add <question>${colors.reset} Add a new open question to requirements.md
1163
+
1164
+ ${colors.green}help, --help${colors.reset} Show this help message
1165
+ ${colors.green}version, --version${colors.reset} Display version number
1166
+ `);
1167
+ }
1168
+ export {
1169
+ AI_DIR,
1170
+ CONTEXT_DIR,
1171
+ DECISIONS_DIR,
1172
+ MATURITY_LEVELS,
1173
+ REPORTS_DIR,
1174
+ REPORTS_SUBDIRS,
1175
+ REQUIRED_CONTEXT_FILES,
1176
+ TASKS_DIR,
1177
+ TASKS_SUBDIRS,
1178
+ addOpenQuestion,
1179
+ createAdr,
1180
+ createTask,
1181
+ getNextAdrId,
1182
+ getNextTaskId,
1183
+ getProjectStatus,
1184
+ initProtocol,
1185
+ listAdrs,
1186
+ listOpenQuestions,
1187
+ listTasks,
1188
+ moveTask,
1189
+ runCli,
1190
+ validateProtocol
1191
+ };
1192
+ //# sourceMappingURL=index.js.map