lean-spec 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/{chunk-J7ZSZ5VJ.js → chunk-7MCDTSVE.js} +2457 -883
  2. package/dist/chunk-7MCDTSVE.js.map +1 -0
  3. package/dist/{chunk-S4YNQ5KE.js → chunk-LVD7ZAVZ.js} +9 -17
  4. package/dist/chunk-LVD7ZAVZ.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +52 -36
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands-GRG5UUOF.js +4 -0
  9. package/dist/commands-GRG5UUOF.js.map +1 -0
  10. package/dist/frontmatter-R2DANL5X.js +3 -0
  11. package/dist/frontmatter-R2DANL5X.js.map +1 -0
  12. package/dist/mcp-server.d.ts +16 -0
  13. package/dist/mcp-server.js +3 -7
  14. package/dist/mcp-server.js.map +1 -1
  15. package/package.json +17 -22
  16. package/templates/_shared/agents-components/core-rules-base.md +5 -0
  17. package/templates/_shared/agents-components/core-rules-enterprise.md +5 -0
  18. package/templates/_shared/agents-components/discovery-commands-enterprise.md +10 -0
  19. package/templates/_shared/agents-components/discovery-commands-minimal.md +8 -0
  20. package/templates/_shared/agents-components/discovery-commands-standard.md +9 -0
  21. package/templates/_shared/agents-components/enterprise-approval.md +10 -0
  22. package/templates/_shared/agents-components/enterprise-compliance.md +12 -0
  23. package/templates/_shared/agents-components/enterprise-when-required.md +13 -0
  24. package/templates/_shared/agents-components/frontmatter-enterprise.md +33 -0
  25. package/templates/_shared/agents-components/frontmatter-minimal.md +18 -0
  26. package/templates/_shared/agents-components/frontmatter-standard.md +23 -0
  27. package/templates/_shared/agents-components/quality-standards-base.md +5 -0
  28. package/templates/_shared/agents-components/quality-standards-enterprise.md +6 -0
  29. package/templates/_shared/agents-components/when-to-use-enterprise.md +11 -0
  30. package/templates/_shared/agents-components/when-to-use-minimal.md +9 -0
  31. package/templates/_shared/agents-components/when-to-use-standard.md +9 -0
  32. package/templates/_shared/agents-components/workflow-enterprise.md +8 -0
  33. package/templates/_shared/agents-components/workflow-standard-detailed.md +7 -0
  34. package/templates/_shared/agents-components/workflow-standard.md +5 -0
  35. package/templates/_shared/agents-template.hbs +39 -0
  36. package/templates/enterprise/agents-config.json +15 -0
  37. package/templates/enterprise/files/AGENTS.md +1 -0
  38. package/templates/minimal/agents-config.json +12 -0
  39. package/templates/minimal/files/AGENTS.md +1 -0
  40. package/templates/standard/agents-config.json +12 -0
  41. package/templates/standard/files/AGENTS.md +1 -0
  42. package/CHANGELOG.md +0 -326
  43. package/LICENSE +0 -21
  44. package/README.md +0 -421
  45. package/dist/chunk-J7ZSZ5VJ.js.map +0 -1
  46. package/dist/chunk-S4YNQ5KE.js.map +0 -1
  47. package/dist/frontmatter-26SOQGYM.js +0 -23
  48. package/dist/frontmatter-26SOQGYM.js.map +0 -1
@@ -1,9 +1,10 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import matter from 'gray-matter';
4
+ import yaml from 'js-yaml';
5
+ import dayjs from 'dayjs';
6
+
1
7
  // src/frontmatter.ts
2
- import * as fs from "fs/promises";
3
- import * as path from "path";
4
- import matter from "gray-matter";
5
- import yaml from "js-yaml";
6
- import dayjs from "dayjs";
7
8
  function normalizeDateFields(data) {
8
9
  const dateFields = ["created", "completed", "updated", "due"];
9
10
  for (const field of dateFields) {
@@ -292,15 +293,6 @@ function matchesFilter(frontmatter, filter) {
292
293
  return true;
293
294
  }
294
295
 
295
- export {
296
- normalizeDateFields,
297
- enrichWithTimestamps,
298
- normalizeTagsField,
299
- validateCustomField,
300
- validateCustomFields,
301
- parseFrontmatter,
302
- updateFrontmatter,
303
- getSpecFile,
304
- matchesFilter
305
- };
306
- //# sourceMappingURL=chunk-S4YNQ5KE.js.map
296
+ export { enrichWithTimestamps, getSpecFile, matchesFilter, normalizeDateFields, normalizeTagsField, parseFrontmatter, updateFrontmatter, validateCustomField, validateCustomFields };
297
+ //# sourceMappingURL=chunk-LVD7ZAVZ.js.map
298
+ //# sourceMappingURL=chunk-LVD7ZAVZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/frontmatter.ts"],"names":[],"mappings":"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","file":"chunk-LVD7ZAVZ.js","sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport matter from 'gray-matter';\nimport yaml from 'js-yaml';\nimport dayjs from 'dayjs';\nimport type { LeanSpecConfig } from './config.js';\n\n// Valid status values\nexport type SpecStatus = 'planned' | 'in-progress' | 'complete' | 'archived';\n\n// Valid priority values\nexport type SpecPriority = 'low' | 'medium' | 'high' | 'critical';\n\n// Status transition record\nexport interface StatusTransition {\n status: SpecStatus;\n at: string; // ISO 8601 timestamp\n}\n\n// Core frontmatter fields\nexport interface SpecFrontmatter {\n // Required fields\n status: SpecStatus;\n created: string; // YYYY-MM-DD format\n\n // Recommended fields\n tags?: string[];\n priority?: SpecPriority;\n\n // Power user fields\n related?: string[];\n depends_on?: string[];\n updated?: string;\n completed?: string;\n assignee?: string;\n reviewer?: string;\n issue?: string;\n pr?: string;\n epic?: string;\n breaking?: boolean;\n due?: string; // YYYY-MM-DD format\n\n // Timestamp fields (for velocity tracking)\n created_at?: string; // ISO 8601 timestamp\n updated_at?: string; // ISO 8601 timestamp\n completed_at?: string; // ISO 8601 timestamp\n transitions?: StatusTransition[]; // Status change history\n\n // Allow any additional fields (for extensibility)\n [key: string]: unknown;\n}\n\n/**\n * Convert Date objects to YYYY-MM-DD string format\n * (gray-matter auto-parses YYYY-MM-DD strings as Date objects)\n */\nexport function normalizeDateFields(data: Record<string, unknown>): void {\n const dateFields = ['created', 'completed', 'updated', 'due'];\n \n for (const field of dateFields) {\n if (data[field] instanceof Date) {\n data[field] = (data[field] as Date).toISOString().split('T')[0];\n }\n }\n}\n\n/**\n * Enrich frontmatter with timestamps for velocity tracking\n * Auto-generates timestamps when missing and tracks status transitions\n */\nexport function enrichWithTimestamps(\n data: Record<string, unknown>,\n previousData?: Record<string, unknown>\n): void {\n const now = new Date().toISOString();\n\n // Set created_at if missing - always use current timestamp\n // Do NOT infer from created date field since that's just YYYY-MM-DD without time\n if (!data.created_at) {\n data.created_at = now;\n }\n\n // Update updated_at on any change (if previousData exists)\n if (previousData) {\n data.updated_at = now;\n }\n\n // Set completed_at when status changes to complete\n if (\n data.status === 'complete' &&\n previousData?.status !== 'complete' &&\n !data.completed_at\n ) {\n data.completed_at = now;\n // Also set the completed date field\n if (!data.completed) {\n data.completed = new Date().toISOString().split('T')[0];\n }\n }\n\n // Track status transition (optional)\n if (previousData && data.status !== previousData.status) {\n if (!Array.isArray(data.transitions)) {\n data.transitions = [];\n }\n (data.transitions as StatusTransition[]).push({\n status: data.status as SpecStatus,\n at: now,\n });\n }\n}\n\n/**\n * Normalize tags field - parse JSON strings into arrays\n * Handles cases where AI accidentally creates tags as '[\"..\",\"..\"]' strings\n */\nexport function normalizeTagsField(data: Record<string, unknown>): void {\n if (data.tags && typeof data.tags === 'string') {\n try {\n // Try to parse as JSON array\n const parsed = JSON.parse(data.tags as string);\n if (Array.isArray(parsed)) {\n data.tags = parsed;\n }\n } catch {\n // If not valid JSON, treat as comma-separated string\n data.tags = (data.tags as string).split(',').map(t => t.trim());\n }\n }\n}\n\n/**\n * Validate and coerce custom field types\n */\nexport function validateCustomField(\n value: unknown,\n expectedType: 'string' | 'number' | 'boolean' | 'array'\n): { valid: boolean; coerced?: unknown; error?: string } {\n switch (expectedType) {\n case 'string':\n if (typeof value === 'string') {\n return { valid: true, coerced: value };\n }\n // Coerce to string\n return { valid: true, coerced: String(value) };\n \n case 'number':\n if (typeof value === 'number') {\n return { valid: true, coerced: value };\n }\n // Try to coerce to number\n const num = Number(value);\n if (!isNaN(num)) {\n return { valid: true, coerced: num };\n }\n return { valid: false, error: `Cannot convert '${value}' to number` };\n \n case 'boolean':\n if (typeof value === 'boolean') {\n return { valid: true, coerced: value };\n }\n // Coerce string to boolean\n if (value === 'true' || value === 'yes' || value === '1') {\n return { valid: true, coerced: true };\n }\n if (value === 'false' || value === 'no' || value === '0') {\n return { valid: true, coerced: false };\n }\n return { valid: false, error: `Cannot convert '${value}' to boolean` };\n \n case 'array':\n if (Array.isArray(value)) {\n return { valid: true, coerced: value };\n }\n return { valid: false, error: `Expected array but got ${typeof value}` };\n \n default:\n return { valid: false, error: `Unknown type: ${expectedType}` };\n }\n}\n\n/**\n * Validate custom fields according to config\n */\nexport function validateCustomFields(\n frontmatter: Record<string, unknown>,\n config?: LeanSpecConfig\n): Record<string, unknown> {\n if (!config?.frontmatter?.custom) {\n return frontmatter;\n }\n \n const result = { ...frontmatter };\n \n for (const [fieldName, expectedType] of Object.entries(config.frontmatter.custom)) {\n if (fieldName in result) {\n const validation = validateCustomField(result[fieldName], expectedType);\n if (validation.valid) {\n result[fieldName] = validation.coerced;\n } else {\n console.warn(`Warning: Invalid custom field '${fieldName}': ${validation.error}`);\n }\n }\n }\n \n return result;\n}\n\n// Parse frontmatter from a spec file\nexport async function parseFrontmatter(\n filePath: string,\n config?: LeanSpecConfig\n): Promise<SpecFrontmatter | null> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsed = matter(content, {\n engines: {\n yaml: (str) => yaml.load(str, { schema: yaml.FAILSAFE_SCHEMA }) as Record<string, unknown>\n }\n });\n\n if (!parsed.data || Object.keys(parsed.data).length === 0) {\n // No frontmatter found, try fallback to inline fields\n return parseFallbackFields(content);\n }\n\n // Validate required fields\n if (!parsed.data.status) {\n console.warn(`Warning: Missing required field 'status' in ${filePath}`);\n return null;\n }\n\n if (!parsed.data.created) {\n console.warn(`Warning: Missing required field 'created' in ${filePath}`);\n return null;\n }\n\n // Validate status enum\n const validStatuses: SpecStatus[] = ['planned', 'in-progress', 'complete', 'archived'];\n if (!validStatuses.includes(parsed.data.status)) {\n console.warn(`Warning: Invalid status '${parsed.data.status}' in ${filePath}. Valid values: ${validStatuses.join(', ')}`);\n }\n\n // Validate priority enum if present\n if (parsed.data.priority) {\n const validPriorities: SpecPriority[] = ['low', 'medium', 'high', 'critical'];\n if (!validPriorities.includes(parsed.data.priority)) {\n console.warn(`Warning: Invalid priority '${parsed.data.priority}' in ${filePath}. Valid values: ${validPriorities.join(', ')}`);\n }\n }\n\n // Normalize tags field (parse JSON strings to arrays)\n normalizeTagsField(parsed.data);\n \n // Warn about unknown fields (informational only)\n const knownFields = [\n 'status', 'created', 'tags', 'priority', 'related', 'depends_on',\n 'updated', 'completed', 'assignee', 'reviewer', 'issue', 'pr', 'epic', 'breaking', 'due',\n 'created_at', 'updated_at', 'completed_at', 'transitions'\n ];\n \n // Add custom fields from config to known fields\n const customFields = config?.frontmatter?.custom ? Object.keys(config.frontmatter.custom) : [];\n const allKnownFields = [...knownFields, ...customFields];\n \n const unknownFields = Object.keys(parsed.data).filter(k => !allKnownFields.includes(k));\n if (unknownFields.length > 0) {\n console.warn(`Info: Unknown fields in ${filePath}: ${unknownFields.join(', ')}`);\n }\n \n // Validate and coerce custom fields\n const validatedData = validateCustomFields(parsed.data, config);\n\n return validatedData as SpecFrontmatter;\n } catch (error) {\n console.error(`Error parsing frontmatter from ${filePath}:`, error);\n return null;\n }\n}\n\n// Fallback: Parse inline fields from older specs\nfunction parseFallbackFields(content: string): SpecFrontmatter | null {\n const statusMatch = content.match(/\\*\\*Status\\*\\*:\\s*(?:📅\\s*)?(\\w+(?:-\\w+)?)/i);\n const createdMatch = content.match(/\\*\\*Created\\*\\*:\\s*(\\d{4}-\\d{2}-\\d{2})/);\n\n if (statusMatch && createdMatch) {\n const status = statusMatch[1].toLowerCase().replace(/\\s+/g, '-') as SpecStatus;\n const created = createdMatch[1];\n\n return {\n status,\n created,\n };\n }\n\n return null;\n}\n\n// Update frontmatter in a spec file\nexport async function updateFrontmatter(\n filePath: string,\n updates: Partial<SpecFrontmatter>\n): Promise<void> {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsed = matter(content, {\n engines: {\n yaml: (str) => yaml.load(str, { schema: yaml.FAILSAFE_SCHEMA }) as Record<string, unknown>\n }\n });\n\n // Store previous data for timestamp enrichment\n const previousData = { ...parsed.data };\n\n // Merge updates with existing data\n const newData = { ...parsed.data, ...updates };\n\n // Ensure date fields remain as strings (gray-matter auto-parses YYYY-MM-DD as Date objects)\n normalizeDateFields(newData);\n\n // Enrich with timestamps\n enrichWithTimestamps(newData, previousData);\n\n // Auto-update timestamps if fields exist (legacy behavior)\n if (updates.status === 'complete' && !newData.completed) {\n newData.completed = dayjs().format('YYYY-MM-DD');\n }\n\n if ('updated' in parsed.data) {\n newData.updated = dayjs().format('YYYY-MM-DD');\n }\n\n // Update visual metadata badges in content\n let updatedContent = parsed.content;\n updatedContent = updateVisualMetadata(updatedContent, newData as SpecFrontmatter);\n\n // Stringify back to file\n const newContent = matter.stringify(updatedContent, newData);\n await fs.writeFile(filePath, newContent, 'utf-8');\n}\n\n// Update visual metadata badges in content\nfunction updateVisualMetadata(content: string, frontmatter: SpecFrontmatter): string {\n const statusEmoji = getStatusEmojiPlain(frontmatter.status);\n const statusLabel = frontmatter.status.charAt(0).toUpperCase() + frontmatter.status.slice(1).replace('-', ' ');\n \n // Parse created date with dayjs - handles all formats consistently\n const created = dayjs(frontmatter.created).format('YYYY-MM-DD');\n \n // Build metadata line\n let metadataLine = `> **Status**: ${statusEmoji} ${statusLabel}`;\n \n if (frontmatter.priority) {\n const priorityLabel = frontmatter.priority.charAt(0).toUpperCase() + frontmatter.priority.slice(1);\n metadataLine += ` · **Priority**: ${priorityLabel}`;\n }\n \n metadataLine += ` · **Created**: ${created}`;\n \n if (frontmatter.tags && frontmatter.tags.length > 0) {\n metadataLine += ` · **Tags**: ${frontmatter.tags.join(', ')}`;\n }\n \n // For enterprise template with assignee/reviewer\n let secondLine = '';\n if (frontmatter.assignee || frontmatter.reviewer) {\n const assignee = frontmatter.assignee || 'TBD';\n const reviewer = frontmatter.reviewer || 'TBD';\n secondLine = `\\n> **Assignee**: ${assignee} · **Reviewer**: ${reviewer}`;\n }\n \n // Replace existing metadata block or add after title\n const metadataPattern = /^>\\s+\\*\\*Status\\*\\*:.*(?:\\n>\\s+\\*\\*Assignee\\*\\*:.*)?/m;\n \n if (metadataPattern.test(content)) {\n // Replace existing metadata\n return content.replace(metadataPattern, metadataLine + secondLine);\n } else {\n // Add after title (# title)\n const titleMatch = content.match(/^#\\s+.+$/m);\n if (titleMatch) {\n const insertPos = titleMatch.index! + titleMatch[0].length;\n return content.slice(0, insertPos) + '\\n\\n' + metadataLine + secondLine + '\\n' + content.slice(insertPos);\n }\n }\n \n return content;\n}\n\nfunction getStatusEmojiPlain(status: string): string {\n switch (status) {\n case 'planned': return '🗓️';\n case 'in-progress': return '⏳';\n case 'complete': return '✅';\n case 'archived': return '📦';\n default: return '📄';\n }\n}\n\n// Get spec file path from spec directory\nexport async function getSpecFile(specDir: string, defaultFile: string = 'README.md'): Promise<string | null> {\n const specFile = path.join(specDir, defaultFile);\n \n try {\n await fs.access(specFile);\n return specFile;\n } catch {\n return null;\n }\n}\n\n// Filter specs by criteria\nexport interface SpecFilterOptions {\n status?: SpecStatus | SpecStatus[];\n tags?: string[];\n priority?: SpecPriority | SpecPriority[];\n assignee?: string;\n customFields?: Record<string, unknown>;\n}\n\nexport function matchesFilter(frontmatter: SpecFrontmatter, filter: SpecFilterOptions): boolean {\n // Status filter\n if (filter.status) {\n const statuses = Array.isArray(filter.status) ? filter.status : [filter.status];\n if (!statuses.includes(frontmatter.status)) {\n return false;\n }\n }\n\n // Tags filter (spec must have ALL specified tags)\n if (filter.tags && filter.tags.length > 0) {\n if (!frontmatter.tags || frontmatter.tags.length === 0) {\n return false;\n }\n const hasAllTags = filter.tags.every(tag => frontmatter.tags!.includes(tag));\n if (!hasAllTags) {\n return false;\n }\n }\n\n // Priority filter\n if (filter.priority) {\n const priorities = Array.isArray(filter.priority) ? filter.priority : [filter.priority];\n if (!frontmatter.priority || !priorities.includes(frontmatter.priority)) {\n return false;\n }\n }\n\n // Assignee filter\n if (filter.assignee) {\n if (frontmatter.assignee !== filter.assignee) {\n return false;\n }\n }\n \n // Custom fields filter\n if (filter.customFields) {\n for (const [key, value] of Object.entries(filter.customFields)) {\n if (frontmatter[key] !== value) {\n return false;\n }\n }\n }\n\n return true;\n}\n"]}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/cli.js CHANGED
@@ -1,36 +1,9 @@
1
- import {
2
- addTemplate,
3
- archiveSpec,
4
- backfillTimestamps,
5
- boardCommand,
6
- checkSpecs,
7
- copyTemplate,
8
- createSpec,
9
- depsCommand,
10
- filesCommand,
11
- ganttCommand,
12
- initProject,
13
- listSpecs,
14
- listTemplates,
15
- mcpCommand,
16
- migrateCommand,
17
- openCommand,
18
- removeTemplate,
19
- searchCommand,
20
- showTemplate,
21
- statsCommand,
22
- timelineCommand,
23
- updateSpec,
24
- validateCommand,
25
- viewCommand
26
- } from "./chunk-J7ZSZ5VJ.js";
27
- import "./chunk-S4YNQ5KE.js";
28
-
29
- // src/cli.ts
30
- import { Command } from "commander";
31
- import { readFileSync } from "fs";
32
- import { fileURLToPath } from "url";
33
- import { dirname, join } from "path";
1
+ import { archiveSpec, backfillTimestamps, boardCommand, checkSpecs, validateCommand, createSpec, depsCommand, filesCommand, ganttCommand, initProject, listSpecs, openCommand, searchCommand, statsCommand, listTemplates, showTemplate, addTemplate, removeTemplate, copyTemplate, timelineCommand, updateSpec, viewCommand, migrateCommand, mcpCommand } from './chunk-7MCDTSVE.js';
2
+ import './chunk-LVD7ZAVZ.js';
3
+ import { Command } from 'commander';
4
+ import { readFileSync } from 'fs';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname, join } from 'path';
34
7
 
35
8
  // src/utils/cli-helpers.ts
36
9
  function parseCustomFieldOptions(fieldOptions) {
@@ -49,10 +22,10 @@ function parseCustomFieldOptions(fieldOptions) {
49
22
  }
50
23
 
51
24
  // src/cli.ts
52
- var __filename2 = fileURLToPath(import.meta.url);
53
- var __dirname2 = dirname(__filename2);
25
+ var __filename = fileURLToPath(import.meta.url);
26
+ var __dirname = dirname(__filename);
54
27
  var packageJson = JSON.parse(
55
- readFileSync(join(__dirname2, "../package.json"), "utf-8")
28
+ readFileSync(join(__dirname, "../package.json"), "utf-8")
56
29
  );
57
30
  var program = new Command();
58
31
  program.name("lean-spec").description("Manage LeanSpec documents").version(packageJson.version);
@@ -197,6 +170,48 @@ program.command("search <query>").description("Full-text search with metadata fi
197
170
  program.command("stats").description("Show aggregate statistics (default: simplified view)").option("--tag <tag>", "Filter by tag").option("--assignee <name>", "Filter by assignee").option("--full", "Show full detailed analytics (all sections)").option("--timeline", "Show only timeline section").option("--velocity", "Show only velocity section").option("--json", "Output as JSON").action(async (options) => {
198
171
  await statsCommand(options);
199
172
  });
173
+ program.command("analyze <spec>").description("Analyze spec complexity and structure (spec 059)").option("--json", "Output as JSON for AI agents").option("--verbose", "Include detailed section breakdown").action(async (specPath, options) => {
174
+ const { analyzeCommand } = await import('./commands-GRG5UUOF.js');
175
+ await analyzeCommand(specPath, options);
176
+ });
177
+ program.command("split <spec>").description("Split spec into multiple files by line ranges (spec 059)").option("--output <file:lines>", "Output file with line range (e.g., README.md:1-150)", collectOutputs, []).option("--update-refs", "Update cross-references in README.md").option("--dry-run", "Show what would be created without making changes").option("--force", "Overwrite existing files").action(async (specPath, options) => {
178
+ const { splitCommand } = await import('./commands-GRG5UUOF.js');
179
+ const outputs = options.output.map((opt) => {
180
+ const [file, lines] = opt.split(":");
181
+ if (!file || !lines) {
182
+ throw new Error(`Invalid --output format: ${opt}. Expected: file.md:1-150`);
183
+ }
184
+ return { file, lines };
185
+ });
186
+ await splitCommand(specPath, {
187
+ outputs,
188
+ updateRefs: options.updateRefs,
189
+ dryRun: options.dryRun,
190
+ force: options.force
191
+ });
192
+ });
193
+ function collectOutputs(value, previous) {
194
+ return previous.concat([value]);
195
+ }
196
+ function collectRemoves(value, previous) {
197
+ return previous.concat([value]);
198
+ }
199
+ program.command("compact <spec>").description("Remove specified line ranges from spec (spec 059)").option("--remove <lines>", "Line range to remove (e.g., 145-153)", collectRemoves, []).option("--dry-run", "Show what would be removed without making changes").option("--force", "Skip confirmation").action(async (specPath, options) => {
200
+ const { compactCommand } = await import('./commands-GRG5UUOF.js');
201
+ await compactCommand(specPath, {
202
+ removes: options.remove,
203
+ dryRun: options.dryRun,
204
+ force: options.force
205
+ });
206
+ });
207
+ program.command("tokens [spec]").description("Count tokens in spec(s) for LLM context management").option("--detailed", "Show content type breakdown (code, prose, tables)").option("--include-sub-specs", "Count all sub-spec files (DESIGN.md, etc.)").option("--all", "Show all specs (when [spec] is omitted)").option("--sort-by <field>", "Sort by: tokens, lines, name (default: tokens)").option("--json", "Output as JSON").action(async (specPath, options) => {
208
+ const { tokensCommand, tokensAllCommand } = await import('./commands-GRG5UUOF.js');
209
+ if (specPath) {
210
+ await tokensCommand(specPath, options);
211
+ } else {
212
+ await tokensAllCommand(options);
213
+ }
214
+ });
200
215
  var templatesCmd = program.command("templates").description("Manage spec templates");
201
216
  templatesCmd.command("list").description("List available templates").action(async () => {
202
217
  await listTemplates();
@@ -268,4 +283,5 @@ program.command("mcp").description("Start MCP server for AI assistants (Claude D
268
283
  await mcpCommand();
269
284
  });
270
285
  program.parse();
286
+ //# sourceMappingURL=cli.js.map
271
287
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/utils/cli-helpers.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport {\n createSpec,\n archiveSpec,\n listSpecs,\n updateSpec,\n checkSpecs,\n backfillTimestamps,\n listTemplates,\n showTemplate,\n addTemplate,\n removeTemplate,\n copyTemplate,\n initProject,\n statsCommand,\n boardCommand,\n timelineCommand,\n depsCommand,\n searchCommand,\n ganttCommand,\n filesCommand,\n viewCommand,\n openCommand,\n validateCommand,\n mcpCommand,\n migrateCommand,\n} from './commands/index.js';\nimport { parseCustomFieldOptions } from './utils/cli-helpers.js';\nimport type { SpecStatus, SpecPriority } from './frontmatter.js';\n\n// Get version from package.json\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, '../package.json'), 'utf-8')\n);\n\nconst program = new Command();\n\nprogram\n .name('lean-spec')\n .description('Manage LeanSpec documents')\n .version(packageJson.version);\n\n// Add custom help text with grouped commands\nprogram.addHelpText('after', `\nCommand Groups:\n \n Core Commands:\n init Initialize LeanSpec in current directory\n create <name> Create new spec in folder structure\n list List all specs\n update <spec> Update spec metadata\n archive <spec> Move spec to archived/\n backfill [specs...] Backfill timestamps from git history\n migrate <input-path> Migrate specs from other SDD tools\n \n Viewing & Navigation:\n view <spec> View spec content\n open <spec> Open spec in editor\n search <query> Full-text search with metadata filters\n files <spec> List files in a spec\n \n Project & Analytics:\n board Show Kanban-style board view\n stats Show aggregate statistics\n timeline Show creation/completion over time\n gantt Show timeline with dependencies\n deps <spec> Show dependency graph for a spec\n \n Maintenance:\n check Check for sequence conflicts\n validate [specs...] Validate specs for quality issues\n templates Manage spec templates\n \n Server:\n mcp Start MCP server for AI assistants\n\nExamples:\n $ lean-spec init\n $ lean-spec create my-feature --priority high\n $ lean-spec list --status in-progress\n $ lean-spec view 042\n $ lean-spec backfill --dry-run\n $ lean-spec migrate ./docs/adr\n $ lean-spec migrate ./docs/rfcs --with copilot\n $ lean-spec board --tag backend\n $ lean-spec search \"authentication\"\n $ lean-spec validate\n $ lean-spec validate --verbose\n $ lean-spec validate --quiet --rule max-lines\n $ lean-spec validate 018 --max-lines 500\n`);\n\n// archive command\nprogram\n .command('archive <spec>')\n .description('Move spec to archived/')\n .action(async (specPath: string) => {\n await archiveSpec(specPath);\n });\n\n// backfill command\nprogram\n .command('backfill [specs...]')\n .description('Backfill timestamps from git history')\n .option('--dry-run', 'Show what would be updated without making changes')\n .option('--force', 'Overwrite existing timestamp values')\n .option('--assignee', 'Include assignee from first commit author')\n .option('--transitions', 'Include full status transition history')\n .option('--all', 'Include all optional fields (assignee + transitions)')\n .action(async (specs: string[] | undefined, options: {\n dryRun?: boolean;\n force?: boolean;\n assignee?: boolean;\n transitions?: boolean;\n all?: boolean;\n }) => {\n await backfillTimestamps({\n dryRun: options.dryRun,\n force: options.force,\n includeAssignee: options.assignee || options.all,\n includeTransitions: options.transitions || options.all,\n specs: specs && specs.length > 0 ? specs : undefined,\n });\n });\n\n// board command\nprogram\n .command('board')\n .description('Show Kanban-style board view with project completion summary')\n .option('--complete', 'Include complete specs (default: hidden)')\n .option('--simple', 'Hide completion summary (kanban only)')\n .option('--completion-only', 'Show only completion summary (no kanban)')\n .option('--tag <tag>', 'Filter by tag')\n .option('--assignee <name>', 'Filter by assignee')\n .action(async (options: {\n showComplete?: boolean;\n simple?: boolean;\n completionOnly?: boolean;\n tag?: string;\n assignee?: string;\n }) => {\n await boardCommand(options);\n });\n\n// check command\nprogram\n .command('check')\n .description('Check for sequence conflicts')\n .option('-q, --quiet', 'Brief output')\n .action(async (options: {\n quiet?: boolean;\n }) => {\n const hasNoConflicts = await checkSpecs(options);\n // Exit with 0 (success) if no conflicts, 1 (error) if conflicts found\n process.exit(hasNoConflicts ? 0 : 1);\n });\n\n// validate command\nprogram\n .command('validate [specs...]')\n .description('Validate specs for quality issues')\n .option('--max-lines <number>', 'Custom line limit (default: 400)', parseInt)\n .option('--verbose', 'Show passing specs')\n .option('--quiet', 'Suppress warnings, only show errors')\n .option('--format <format>', 'Output format: default, json, compact', 'default')\n .option('--rule <rule>', 'Filter by specific rule name (e.g., max-lines, frontmatter)')\n .action(async (specs: string[] | undefined, options: {\n maxLines?: number;\n verbose?: boolean;\n quiet?: boolean;\n format?: 'default' | 'json' | 'compact';\n rule?: string;\n }) => {\n const passed = await validateCommand({\n maxLines: options.maxLines,\n specs: specs && specs.length > 0 ? specs : undefined,\n verbose: options.verbose,\n quiet: options.quiet,\n format: options.format,\n rule: options.rule,\n });\n // Exit with 0 (success) if all passed, 1 (error) if any failed\n process.exit(passed ? 0 : 1);\n });\n\n// create command\nprogram\n .command('create <name>')\n .description('Create new spec in folder structure')\n .option('--title <title>', 'Set custom title')\n .option('--description <desc>', 'Set initial description')\n .option('--tags <tags>', 'Set tags (comma-separated)')\n .option('--priority <priority>', 'Set priority (low, medium, high, critical)')\n .option('--assignee <name>', 'Set assignee')\n .option('--template <template>', 'Use a specific template')\n .option('--field <name=value...>', 'Set custom field (can specify multiple)')\n .option('--no-prefix', 'Skip date prefix even if configured')\n .action(async (name: string, options: {\n title?: string;\n description?: string;\n tags?: string;\n priority?: SpecPriority;\n assignee?: string;\n template?: string;\n field?: string[];\n prefix?: boolean;\n }) => {\n // Parse custom fields from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n const createOptions: {\n title?: string;\n description?: string;\n tags?: string[];\n priority?: SpecPriority;\n assignee?: string;\n template?: string;\n customFields?: Record<string, unknown>;\n noPrefix?: boolean;\n } = {\n title: options.title,\n description: options.description,\n tags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n priority: options.priority,\n assignee: options.assignee,\n template: options.template,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n noPrefix: options.prefix === false,\n };\n await createSpec(name, createOptions);\n });\n\n// deps command\nprogram\n .command('deps <spec>')\n .description('Show dependency graph for a spec. Related specs (⟷) are shown bidirectionally, depends_on (→) are directional.')\n .option('--depth <n>', 'Show N levels deep (default: 3)', parseInt)\n .option('--graph', 'ASCII graph visualization')\n .option('--json', 'Output as JSON')\n .action(async (specPath: string, options: {\n depth?: number;\n graph?: boolean;\n json?: boolean;\n }) => {\n await depsCommand(specPath, options);\n });\n\n// files command\nprogram\n .command('files <spec>')\n .description('List files in a spec')\n .option('--type <type>', 'Filter by type: docs, assets')\n .option('--tree', 'Show tree structure')\n .action(async (specPath: string, options: {\n type?: 'docs' | 'assets';\n tree?: boolean;\n }) => {\n await filesCommand(specPath, options);\n });\n\n// gantt command\nprogram\n .command('gantt')\n .description('Show timeline with dependencies')\n .option('--weeks <n>', 'Show N weeks (default: 4)', parseInt)\n .option('--show-complete', 'Include completed specs')\n .option('--critical-path', 'Highlight critical path')\n .action(async (options: {\n weeks?: number;\n showComplete?: boolean;\n criticalPath?: boolean;\n }) => {\n await ganttCommand(options);\n });\n\n// init command\nprogram\n .command('init')\n .description('Initialize LeanSpec in current directory')\n .action(async () => {\n await initProject();\n });\n\n// list command\nprogram\n .command('list')\n .description('List all specs')\n .option('--archived', 'Include archived specs')\n .option('--status <status>', 'Filter by status (planned, in-progress, complete, archived)')\n .option('--tag <tag...>', 'Filter by tag (can specify multiple)')\n .option('--priority <priority>', 'Filter by priority (low, medium, high, critical)')\n .option('--assignee <name>', 'Filter by assignee')\n .option('--field <name=value...>', 'Filter by custom field (can specify multiple)')\n .option('--sort <field>', 'Sort by field (id, created, name, status, priority)', 'id')\n .option('--order <order>', 'Sort order (asc, desc)', 'desc')\n .action(async (options: {\n archived?: boolean;\n status?: SpecStatus;\n tag?: string[];\n priority?: SpecPriority;\n assignee?: string;\n field?: string[];\n sort?: string;\n order?: string;\n }) => {\n // Parse custom field filters from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n const listOptions: {\n showArchived?: boolean;\n status?: SpecStatus;\n tags?: string[];\n priority?: SpecPriority;\n assignee?: string;\n customFields?: Record<string, unknown>;\n sortBy?: string;\n sortOrder?: 'asc' | 'desc';\n } = {\n showArchived: options.archived,\n status: options.status,\n tags: options.tag,\n priority: options.priority,\n assignee: options.assignee,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n sortBy: options.sort || 'id',\n sortOrder: (options.order as 'asc' | 'desc') || 'desc',\n };\n await listSpecs(listOptions);\n });\n\n// open command\nprogram\n .command('open <spec>')\n .description('Open spec in editor')\n .option('--editor <editor>', 'Specify editor command')\n .action(async (specPath: string, options: {\n editor?: string;\n }) => {\n try {\n await openCommand(specPath, {\n editor: options.editor,\n });\n } catch (error) {\n console.error('\\x1b[31mError:\\x1b[0m', error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n\n// search command\nprogram\n .command('search <query>')\n .description('Full-text search with metadata filters')\n .option('--status <status>', 'Filter by status')\n .option('--tag <tag>', 'Filter by tag')\n .option('--priority <priority>', 'Filter by priority')\n .option('--assignee <name>', 'Filter by assignee')\n .option('--field <name=value...>', 'Filter by custom field (can specify multiple)')\n .action(async (query: string, options: {\n status?: SpecStatus;\n tag?: string;\n priority?: SpecPriority;\n assignee?: string;\n field?: string[];\n }) => {\n // Parse custom field filters from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n await searchCommand(query, {\n status: options.status,\n tag: options.tag,\n priority: options.priority,\n assignee: options.assignee,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n });\n });\n\n// stats command\nprogram\n .command('stats')\n .description('Show aggregate statistics (default: simplified view)')\n .option('--tag <tag>', 'Filter by tag')\n .option('--assignee <name>', 'Filter by assignee')\n .option('--full', 'Show full detailed analytics (all sections)')\n .option('--timeline', 'Show only timeline section')\n .option('--velocity', 'Show only velocity section')\n .option('--json', 'Output as JSON')\n .action(async (options: {\n tag?: string;\n assignee?: string;\n full?: boolean;\n timeline?: boolean;\n velocity?: boolean;\n json?: boolean;\n }) => {\n await statsCommand(options);\n });\n\n// templates command and subcommands\nconst templatesCmd = program\n .command('templates')\n .description('Manage spec templates');\n\ntemplatesCmd\n .command('list')\n .description('List available templates')\n .action(async () => {\n await listTemplates();\n });\n\ntemplatesCmd\n .command('show <name>')\n .description('Show template content')\n .action(async (name: string) => {\n await showTemplate(name);\n });\n\ntemplatesCmd\n .command('add <name> <file>')\n .description('Register a template')\n .action(async (name: string, file: string) => {\n await addTemplate(name, file);\n });\n\ntemplatesCmd\n .command('remove <name>')\n .description('Unregister a template')\n .action(async (name: string) => {\n await removeTemplate(name);\n });\n\ntemplatesCmd\n .command('copy <source> <target>')\n .description('Copy a template to create a new one')\n .action(async (source: string, target: string) => {\n await copyTemplate(source, target);\n });\n\n// Default action for templates (list)\ntemplatesCmd\n .action(async () => {\n await listTemplates();\n });\n\n// timeline command\nprogram\n .command('timeline')\n .description('Show creation/completion over time')\n .option('--days <n>', 'Show last N days (default: 30)', parseInt)\n .option('--by-tag', 'Group by tag')\n .option('--by-assignee', 'Group by assignee')\n .action(async (options: {\n days?: number;\n byTag?: boolean;\n byAssignee?: boolean;\n }) => {\n await timelineCommand(options);\n });\n\n// update command\nprogram\n .command('update <spec>')\n .description('Update spec metadata')\n .option('--status <status>', 'Set status (planned, in-progress, complete, archived)')\n .option('--priority <priority>', 'Set priority (low, medium, high, critical)')\n .option('--tags <tags>', 'Set tags (comma-separated)')\n .option('--assignee <name>', 'Set assignee')\n .option('--field <name=value...>', 'Set custom field (can specify multiple)')\n .action(async (specPath: string, options: {\n status?: SpecStatus;\n priority?: SpecPriority;\n tags?: string;\n assignee?: string;\n field?: string[];\n }) => {\n // Parse custom fields from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n const updates: {\n status?: SpecStatus;\n priority?: SpecPriority;\n tags?: string[];\n assignee?: string;\n customFields?: Record<string, unknown>;\n } = {\n status: options.status,\n priority: options.priority,\n tags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n assignee: options.assignee,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n };\n \n // Filter out undefined values\n Object.keys(updates).forEach(key => {\n if (updates[key as keyof typeof updates] === undefined) {\n delete updates[key as keyof typeof updates];\n }\n });\n \n if (Object.keys(updates).length === 0) {\n console.error('Error: At least one update option required (--status, --priority, --tags, --assignee, --field)');\n process.exit(1);\n }\n \n await updateSpec(specPath, updates);\n });\n\n// view command (primary viewer)\nprogram\n .command('view <spec>')\n .description('View spec content (supports sub-specs like \"045/DESIGN.md\")')\n .option('--raw', 'Output raw markdown (for piping/scripting)')\n .option('--json', 'Output as JSON')\n .option('--no-color', 'Disable colors')\n .action(async (specPath: string, options: {\n raw?: boolean;\n json?: boolean;\n color?: boolean;\n }) => {\n try {\n await viewCommand(specPath, {\n raw: options.raw,\n json: options.json,\n noColor: options.color === false,\n });\n } catch (error) {\n console.error('\\x1b[31mError:\\x1b[0m', error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n\n// migrate command\nprogram\n .command('migrate <input-path>')\n .description('Migrate specs from other SDD tools (ADR, RFC, OpenSpec, spec-kit, etc.)')\n .option('--with <provider>', 'AI-assisted migration (copilot, claude, gemini)')\n .option('--dry-run', 'Preview without making changes')\n .option('--batch-size <n>', 'Process N docs at a time', parseInt)\n .option('--skip-validation', \"Don't validate after migration\")\n .option('--backfill', 'Auto-run backfill after migration')\n .action(async (inputPath: string, options: {\n with?: string;\n dryRun?: boolean;\n batchSize?: number;\n skipValidation?: boolean;\n backfill?: boolean;\n }) => {\n // Validate AI provider if specified\n if (options.with && !['copilot', 'claude', 'gemini'].includes(options.with)) {\n console.error('\\x1b[31m❌ Error:\\x1b[0m Invalid AI provider. Use: copilot, claude, or gemini');\n process.exit(1);\n }\n \n await migrateCommand(inputPath, {\n aiProvider: options.with as 'copilot' | 'claude' | 'gemini' | undefined,\n dryRun: options.dryRun,\n batchSize: options.batchSize,\n skipValidation: options.skipValidation,\n backfill: options.backfill,\n });\n });\n\n// mcp command\nprogram\n .command('mcp')\n .description('Start MCP server for AI assistants (Claude Desktop, Cline, etc.)')\n .action(async () => {\n await mcpCommand();\n });\n\n// Parse and execute\nprogram.parse();\n","/**\n * Parse custom fields from CLI --field options\n * @param fieldOptions Array of \"name=value\" strings\n * @returns Record of parsed field names and values\n */\nexport function parseCustomFieldOptions(fieldOptions?: string[]): Record<string, unknown> {\n const customFields: Record<string, unknown> = {};\n \n if (!fieldOptions) {\n return customFields;\n }\n \n for (const field of fieldOptions) {\n const [key, ...valueParts] = field.split('=');\n if (key && valueParts.length > 0) {\n const value = valueParts.join('='); // Handle values with '=' in them\n customFields[key.trim()] = value.trim();\n }\n }\n \n return customFields;\n}\n"],"mappings":"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","names":["__filename","__dirname"]}
1
+ {"version":3,"sources":["../src/utils/cli-helpers.ts","../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Parse custom fields from CLI --field options\n * @param fieldOptions Array of \"name=value\" strings\n * @returns Record of parsed field names and values\n */\nexport function parseCustomFieldOptions(fieldOptions?: string[]): Record<string, unknown> {\n const customFields: Record<string, unknown> = {};\n \n if (!fieldOptions) {\n return customFields;\n }\n \n for (const field of fieldOptions) {\n const [key, ...valueParts] = field.split('=');\n if (key && valueParts.length > 0) {\n const value = valueParts.join('='); // Handle values with '=' in them\n customFields[key.trim()] = value.trim();\n }\n }\n \n return customFields;\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport {\n createSpec,\n archiveSpec,\n listSpecs,\n updateSpec,\n checkSpecs,\n backfillTimestamps,\n listTemplates,\n showTemplate,\n addTemplate,\n removeTemplate,\n copyTemplate,\n initProject,\n statsCommand,\n boardCommand,\n timelineCommand,\n depsCommand,\n searchCommand,\n ganttCommand,\n filesCommand,\n viewCommand,\n openCommand,\n validateCommand,\n mcpCommand,\n migrateCommand,\n} from './commands/index.js';\nimport { parseCustomFieldOptions } from './utils/cli-helpers.js';\nimport type { SpecStatus, SpecPriority } from './frontmatter.js';\n\n// Get version from package.json\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, '../package.json'), 'utf-8')\n);\n\nconst program = new Command();\n\nprogram\n .name('lean-spec')\n .description('Manage LeanSpec documents')\n .version(packageJson.version);\n\n// Add custom help text with grouped commands\nprogram.addHelpText('after', `\nCommand Groups:\n \n Core Commands:\n init Initialize LeanSpec in current directory\n create <name> Create new spec in folder structure\n list List all specs\n update <spec> Update spec metadata\n archive <spec> Move spec to archived/\n backfill [specs...] Backfill timestamps from git history\n migrate <input-path> Migrate specs from other SDD tools\n \n Viewing & Navigation:\n view <spec> View spec content\n open <spec> Open spec in editor\n search <query> Full-text search with metadata filters\n files <spec> List files in a spec\n \n Project & Analytics:\n board Show Kanban-style board view\n stats Show aggregate statistics\n timeline Show creation/completion over time\n gantt Show timeline with dependencies\n deps <spec> Show dependency graph for a spec\n \n Maintenance:\n check Check for sequence conflicts\n validate [specs...] Validate specs for quality issues\n templates Manage spec templates\n \n Server:\n mcp Start MCP server for AI assistants\n\nExamples:\n $ lean-spec init\n $ lean-spec create my-feature --priority high\n $ lean-spec list --status in-progress\n $ lean-spec view 042\n $ lean-spec backfill --dry-run\n $ lean-spec migrate ./docs/adr\n $ lean-spec migrate ./docs/rfcs --with copilot\n $ lean-spec board --tag backend\n $ lean-spec search \"authentication\"\n $ lean-spec validate\n $ lean-spec validate --verbose\n $ lean-spec validate --quiet --rule max-lines\n $ lean-spec validate 018 --max-lines 500\n`);\n\n// archive command\nprogram\n .command('archive <spec>')\n .description('Move spec to archived/')\n .action(async (specPath: string) => {\n await archiveSpec(specPath);\n });\n\n// backfill command\nprogram\n .command('backfill [specs...]')\n .description('Backfill timestamps from git history')\n .option('--dry-run', 'Show what would be updated without making changes')\n .option('--force', 'Overwrite existing timestamp values')\n .option('--assignee', 'Include assignee from first commit author')\n .option('--transitions', 'Include full status transition history')\n .option('--all', 'Include all optional fields (assignee + transitions)')\n .action(async (specs: string[] | undefined, options: {\n dryRun?: boolean;\n force?: boolean;\n assignee?: boolean;\n transitions?: boolean;\n all?: boolean;\n }) => {\n await backfillTimestamps({\n dryRun: options.dryRun,\n force: options.force,\n includeAssignee: options.assignee || options.all,\n includeTransitions: options.transitions || options.all,\n specs: specs && specs.length > 0 ? specs : undefined,\n });\n });\n\n// board command\nprogram\n .command('board')\n .description('Show Kanban-style board view with project completion summary')\n .option('--complete', 'Include complete specs (default: hidden)')\n .option('--simple', 'Hide completion summary (kanban only)')\n .option('--completion-only', 'Show only completion summary (no kanban)')\n .option('--tag <tag>', 'Filter by tag')\n .option('--assignee <name>', 'Filter by assignee')\n .action(async (options: {\n showComplete?: boolean;\n simple?: boolean;\n completionOnly?: boolean;\n tag?: string;\n assignee?: string;\n }) => {\n await boardCommand(options);\n });\n\n// check command\nprogram\n .command('check')\n .description('Check for sequence conflicts')\n .option('-q, --quiet', 'Brief output')\n .action(async (options: {\n quiet?: boolean;\n }) => {\n const hasNoConflicts = await checkSpecs(options);\n // Exit with 0 (success) if no conflicts, 1 (error) if conflicts found\n process.exit(hasNoConflicts ? 0 : 1);\n });\n\n// validate command\nprogram\n .command('validate [specs...]')\n .description('Validate specs for quality issues')\n .option('--max-lines <number>', 'Custom line limit (default: 400)', parseInt)\n .option('--verbose', 'Show passing specs')\n .option('--quiet', 'Suppress warnings, only show errors')\n .option('--format <format>', 'Output format: default, json, compact', 'default')\n .option('--rule <rule>', 'Filter by specific rule name (e.g., max-lines, frontmatter)')\n .action(async (specs: string[] | undefined, options: {\n maxLines?: number;\n verbose?: boolean;\n quiet?: boolean;\n format?: 'default' | 'json' | 'compact';\n rule?: string;\n }) => {\n const passed = await validateCommand({\n maxLines: options.maxLines,\n specs: specs && specs.length > 0 ? specs : undefined,\n verbose: options.verbose,\n quiet: options.quiet,\n format: options.format,\n rule: options.rule,\n });\n // Exit with 0 (success) if all passed, 1 (error) if any failed\n process.exit(passed ? 0 : 1);\n });\n\n// create command\nprogram\n .command('create <name>')\n .description('Create new spec in folder structure')\n .option('--title <title>', 'Set custom title')\n .option('--description <desc>', 'Set initial description')\n .option('--tags <tags>', 'Set tags (comma-separated)')\n .option('--priority <priority>', 'Set priority (low, medium, high, critical)')\n .option('--assignee <name>', 'Set assignee')\n .option('--template <template>', 'Use a specific template')\n .option('--field <name=value...>', 'Set custom field (can specify multiple)')\n .option('--no-prefix', 'Skip date prefix even if configured')\n .action(async (name: string, options: {\n title?: string;\n description?: string;\n tags?: string;\n priority?: SpecPriority;\n assignee?: string;\n template?: string;\n field?: string[];\n prefix?: boolean;\n }) => {\n // Parse custom fields from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n const createOptions: {\n title?: string;\n description?: string;\n tags?: string[];\n priority?: SpecPriority;\n assignee?: string;\n template?: string;\n customFields?: Record<string, unknown>;\n noPrefix?: boolean;\n } = {\n title: options.title,\n description: options.description,\n tags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n priority: options.priority,\n assignee: options.assignee,\n template: options.template,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n noPrefix: options.prefix === false,\n };\n await createSpec(name, createOptions);\n });\n\n// deps command\nprogram\n .command('deps <spec>')\n .description('Show dependency graph for a spec. Related specs (⟷) are shown bidirectionally, depends_on (→) are directional.')\n .option('--depth <n>', 'Show N levels deep (default: 3)', parseInt)\n .option('--graph', 'ASCII graph visualization')\n .option('--json', 'Output as JSON')\n .action(async (specPath: string, options: {\n depth?: number;\n graph?: boolean;\n json?: boolean;\n }) => {\n await depsCommand(specPath, options);\n });\n\n// files command\nprogram\n .command('files <spec>')\n .description('List files in a spec')\n .option('--type <type>', 'Filter by type: docs, assets')\n .option('--tree', 'Show tree structure')\n .action(async (specPath: string, options: {\n type?: 'docs' | 'assets';\n tree?: boolean;\n }) => {\n await filesCommand(specPath, options);\n });\n\n// gantt command\nprogram\n .command('gantt')\n .description('Show timeline with dependencies')\n .option('--weeks <n>', 'Show N weeks (default: 4)', parseInt)\n .option('--show-complete', 'Include completed specs')\n .option('--critical-path', 'Highlight critical path')\n .action(async (options: {\n weeks?: number;\n showComplete?: boolean;\n criticalPath?: boolean;\n }) => {\n await ganttCommand(options);\n });\n\n// init command\nprogram\n .command('init')\n .description('Initialize LeanSpec in current directory')\n .action(async () => {\n await initProject();\n });\n\n// list command\nprogram\n .command('list')\n .description('List all specs')\n .option('--archived', 'Include archived specs')\n .option('--status <status>', 'Filter by status (planned, in-progress, complete, archived)')\n .option('--tag <tag...>', 'Filter by tag (can specify multiple)')\n .option('--priority <priority>', 'Filter by priority (low, medium, high, critical)')\n .option('--assignee <name>', 'Filter by assignee')\n .option('--field <name=value...>', 'Filter by custom field (can specify multiple)')\n .option('--sort <field>', 'Sort by field (id, created, name, status, priority)', 'id')\n .option('--order <order>', 'Sort order (asc, desc)', 'desc')\n .action(async (options: {\n archived?: boolean;\n status?: SpecStatus;\n tag?: string[];\n priority?: SpecPriority;\n assignee?: string;\n field?: string[];\n sort?: string;\n order?: string;\n }) => {\n // Parse custom field filters from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n const listOptions: {\n showArchived?: boolean;\n status?: SpecStatus;\n tags?: string[];\n priority?: SpecPriority;\n assignee?: string;\n customFields?: Record<string, unknown>;\n sortBy?: string;\n sortOrder?: 'asc' | 'desc';\n } = {\n showArchived: options.archived,\n status: options.status,\n tags: options.tag,\n priority: options.priority,\n assignee: options.assignee,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n sortBy: options.sort || 'id',\n sortOrder: (options.order as 'asc' | 'desc') || 'desc',\n };\n await listSpecs(listOptions);\n });\n\n// open command\nprogram\n .command('open <spec>')\n .description('Open spec in editor')\n .option('--editor <editor>', 'Specify editor command')\n .action(async (specPath: string, options: {\n editor?: string;\n }) => {\n try {\n await openCommand(specPath, {\n editor: options.editor,\n });\n } catch (error) {\n console.error('\\x1b[31mError:\\x1b[0m', error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n\n// search command\nprogram\n .command('search <query>')\n .description('Full-text search with metadata filters')\n .option('--status <status>', 'Filter by status')\n .option('--tag <tag>', 'Filter by tag')\n .option('--priority <priority>', 'Filter by priority')\n .option('--assignee <name>', 'Filter by assignee')\n .option('--field <name=value...>', 'Filter by custom field (can specify multiple)')\n .action(async (query: string, options: {\n status?: SpecStatus;\n tag?: string;\n priority?: SpecPriority;\n assignee?: string;\n field?: string[];\n }) => {\n // Parse custom field filters from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n await searchCommand(query, {\n status: options.status,\n tag: options.tag,\n priority: options.priority,\n assignee: options.assignee,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n });\n });\n\n// stats command\nprogram\n .command('stats')\n .description('Show aggregate statistics (default: simplified view)')\n .option('--tag <tag>', 'Filter by tag')\n .option('--assignee <name>', 'Filter by assignee')\n .option('--full', 'Show full detailed analytics (all sections)')\n .option('--timeline', 'Show only timeline section')\n .option('--velocity', 'Show only velocity section')\n .option('--json', 'Output as JSON')\n .action(async (options: {\n tag?: string;\n assignee?: string;\n full?: boolean;\n timeline?: boolean;\n velocity?: boolean;\n json?: boolean;\n }) => {\n await statsCommand(options);\n });\n\n// analyze command - for spec 059\nprogram\n .command('analyze <spec>')\n .description('Analyze spec complexity and structure (spec 059)')\n .option('--json', 'Output as JSON for AI agents')\n .option('--verbose', 'Include detailed section breakdown')\n .action(async (specPath: string, options: { json?: boolean; verbose?: boolean }) => {\n const { analyzeCommand } = await import('./commands/index.js');\n await analyzeCommand(specPath, options);\n });\n\n// split command - for spec 059\nprogram\n .command('split <spec>')\n .description('Split spec into multiple files by line ranges (spec 059)')\n .option('--output <file:lines>', 'Output file with line range (e.g., README.md:1-150)', collectOutputs, [])\n .option('--update-refs', 'Update cross-references in README.md')\n .option('--dry-run', 'Show what would be created without making changes')\n .option('--force', 'Overwrite existing files')\n .action(async (specPath: string, options: { \n output: Array<string>;\n updateRefs?: boolean;\n dryRun?: boolean;\n force?: boolean;\n }) => {\n const { splitCommand } = await import('./commands/index.js');\n \n // Parse outputs into structured format\n const outputs = options.output.map((opt: string) => {\n const [file, lines] = opt.split(':');\n if (!file || !lines) {\n throw new Error(`Invalid --output format: ${opt}. Expected: file.md:1-150`);\n }\n return { file, lines };\n });\n \n await splitCommand(specPath, {\n outputs,\n updateRefs: options.updateRefs,\n dryRun: options.dryRun,\n force: options.force,\n });\n });\n\n// Helper function to collect multiple --output options\nfunction collectOutputs(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n\n// Helper function to collect multiple --remove options\nfunction collectRemoves(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n\n// compact command - for spec 059\nprogram\n .command('compact <spec>')\n .description('Remove specified line ranges from spec (spec 059)')\n .option('--remove <lines>', 'Line range to remove (e.g., 145-153)', collectRemoves, [])\n .option('--dry-run', 'Show what would be removed without making changes')\n .option('--force', 'Skip confirmation')\n .action(async (specPath: string, options: { \n remove: string[];\n dryRun?: boolean;\n force?: boolean;\n }) => {\n const { compactCommand } = await import('./commands/index.js');\n \n await compactCommand(specPath, {\n removes: options.remove,\n dryRun: options.dryRun,\n force: options.force,\n });\n });\n\n// tokens command\nprogram\n .command('tokens [spec]')\n .description('Count tokens in spec(s) for LLM context management')\n .option('--detailed', 'Show content type breakdown (code, prose, tables)')\n .option('--include-sub-specs', 'Count all sub-spec files (DESIGN.md, etc.)')\n .option('--all', 'Show all specs (when [spec] is omitted)')\n .option('--sort-by <field>', 'Sort by: tokens, lines, name (default: tokens)')\n .option('--json', 'Output as JSON')\n .action(async (specPath: string | undefined, options: {\n detailed?: boolean;\n includeSubSpecs?: boolean;\n all?: boolean;\n sortBy?: 'tokens' | 'lines' | 'name';\n json?: boolean;\n }) => {\n const { tokensCommand, tokensAllCommand } = await import('./commands/index.js');\n \n if (specPath) {\n // Count specific spec\n await tokensCommand(specPath, options);\n } else {\n // Count all specs\n await tokensAllCommand(options);\n }\n });\n\n// templates command and subcommands\nconst templatesCmd = program\n .command('templates')\n .description('Manage spec templates');\n\ntemplatesCmd\n .command('list')\n .description('List available templates')\n .action(async () => {\n await listTemplates();\n });\n\ntemplatesCmd\n .command('show <name>')\n .description('Show template content')\n .action(async (name: string) => {\n await showTemplate(name);\n });\n\ntemplatesCmd\n .command('add <name> <file>')\n .description('Register a template')\n .action(async (name: string, file: string) => {\n await addTemplate(name, file);\n });\n\ntemplatesCmd\n .command('remove <name>')\n .description('Unregister a template')\n .action(async (name: string) => {\n await removeTemplate(name);\n });\n\ntemplatesCmd\n .command('copy <source> <target>')\n .description('Copy a template to create a new one')\n .action(async (source: string, target: string) => {\n await copyTemplate(source, target);\n });\n\n// Default action for templates (list)\ntemplatesCmd\n .action(async () => {\n await listTemplates();\n });\n\n// timeline command\nprogram\n .command('timeline')\n .description('Show creation/completion over time')\n .option('--days <n>', 'Show last N days (default: 30)', parseInt)\n .option('--by-tag', 'Group by tag')\n .option('--by-assignee', 'Group by assignee')\n .action(async (options: {\n days?: number;\n byTag?: boolean;\n byAssignee?: boolean;\n }) => {\n await timelineCommand(options);\n });\n\n// update command\nprogram\n .command('update <spec>')\n .description('Update spec metadata')\n .option('--status <status>', 'Set status (planned, in-progress, complete, archived)')\n .option('--priority <priority>', 'Set priority (low, medium, high, critical)')\n .option('--tags <tags>', 'Set tags (comma-separated)')\n .option('--assignee <name>', 'Set assignee')\n .option('--field <name=value...>', 'Set custom field (can specify multiple)')\n .action(async (specPath: string, options: {\n status?: SpecStatus;\n priority?: SpecPriority;\n tags?: string;\n assignee?: string;\n field?: string[];\n }) => {\n // Parse custom fields from --field options\n const customFields = parseCustomFieldOptions(options.field);\n \n const updates: {\n status?: SpecStatus;\n priority?: SpecPriority;\n tags?: string[];\n assignee?: string;\n customFields?: Record<string, unknown>;\n } = {\n status: options.status,\n priority: options.priority,\n tags: options.tags ? options.tags.split(',').map(t => t.trim()) : undefined,\n assignee: options.assignee,\n customFields: Object.keys(customFields).length > 0 ? customFields : undefined,\n };\n \n // Filter out undefined values\n Object.keys(updates).forEach(key => {\n if (updates[key as keyof typeof updates] === undefined) {\n delete updates[key as keyof typeof updates];\n }\n });\n \n if (Object.keys(updates).length === 0) {\n console.error('Error: At least one update option required (--status, --priority, --tags, --assignee, --field)');\n process.exit(1);\n }\n \n await updateSpec(specPath, updates);\n });\n\n// view command (primary viewer)\nprogram\n .command('view <spec>')\n .description('View spec content (supports sub-specs like \"045/DESIGN.md\")')\n .option('--raw', 'Output raw markdown (for piping/scripting)')\n .option('--json', 'Output as JSON')\n .option('--no-color', 'Disable colors')\n .action(async (specPath: string, options: {\n raw?: boolean;\n json?: boolean;\n color?: boolean;\n }) => {\n try {\n await viewCommand(specPath, {\n raw: options.raw,\n json: options.json,\n noColor: options.color === false,\n });\n } catch (error) {\n console.error('\\x1b[31mError:\\x1b[0m', error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n });\n\n// migrate command\nprogram\n .command('migrate <input-path>')\n .description('Migrate specs from other SDD tools (ADR, RFC, OpenSpec, spec-kit, etc.)')\n .option('--with <provider>', 'AI-assisted migration (copilot, claude, gemini)')\n .option('--dry-run', 'Preview without making changes')\n .option('--batch-size <n>', 'Process N docs at a time', parseInt)\n .option('--skip-validation', \"Don't validate after migration\")\n .option('--backfill', 'Auto-run backfill after migration')\n .action(async (inputPath: string, options: {\n with?: string;\n dryRun?: boolean;\n batchSize?: number;\n skipValidation?: boolean;\n backfill?: boolean;\n }) => {\n // Validate AI provider if specified\n if (options.with && !['copilot', 'claude', 'gemini'].includes(options.with)) {\n console.error('\\x1b[31m❌ Error:\\x1b[0m Invalid AI provider. Use: copilot, claude, or gemini');\n process.exit(1);\n }\n \n await migrateCommand(inputPath, {\n aiProvider: options.with as 'copilot' | 'claude' | 'gemini' | undefined,\n dryRun: options.dryRun,\n batchSize: options.batchSize,\n skipValidation: options.skipValidation,\n backfill: options.backfill,\n });\n });\n\n// mcp command\nprogram\n .command('mcp')\n .description('Start MCP server for AI assistants (Claude Desktop, Cline, etc.)')\n .action(async () => {\n await mcpCommand();\n });\n\n// Parse and execute\nprogram.parse();\n"]}
@@ -0,0 +1,4 @@
1
+ export { addTemplate, analyzeCommand, archiveSpec, backfillTimestamps, boardCommand, checkSpecs, compactCommand, copyTemplate, createSpec, depsCommand, filesCommand, ganttCommand, initProject, listSpecs, listTemplates, mcpCommand, migrateCommand, openCommand, removeTemplate, searchCommand, showTemplate, splitCommand, statsCommand, timelineCommand, tokensAllCommand, tokensCommand, updateSpec, validateCommand, viewCommand } from './chunk-7MCDTSVE.js';
2
+ import './chunk-LVD7ZAVZ.js';
3
+ //# sourceMappingURL=commands-GRG5UUOF.js.map
4
+ //# sourceMappingURL=commands-GRG5UUOF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"commands-GRG5UUOF.js"}
@@ -0,0 +1,3 @@
1
+ export { enrichWithTimestamps, getSpecFile, matchesFilter, normalizeDateFields, normalizeTagsField, parseFrontmatter, updateFrontmatter, validateCustomField, validateCustomFields } from './chunk-LVD7ZAVZ.js';
2
+ //# sourceMappingURL=frontmatter-R2DANL5X.js.map
3
+ //# sourceMappingURL=frontmatter-R2DANL5X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"frontmatter-R2DANL5X.js"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+
4
+ /**
5
+ * LeanSpec MCP Server
6
+ *
7
+ * Model Context Protocol server that exposes LeanSpec functionality to AI assistants.
8
+ * This enables AI agents to interact with LeanSpec projects directly from their environment.
9
+ */
10
+
11
+ /**
12
+ * Create the MCP server
13
+ */
14
+ declare function createMcpServer(): Promise<McpServer>;
15
+
16
+ export { createMcpServer };
@@ -1,9 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- createMcpServer
4
- } from "./chunk-J7ZSZ5VJ.js";
5
- import "./chunk-S4YNQ5KE.js";
6
- export {
7
- createMcpServer
8
- };
2
+ export { createMcpServer } from './chunk-7MCDTSVE.js';
3
+ import './chunk-LVD7ZAVZ.js';
4
+ //# sourceMappingURL=mcp-server.js.map
9
5
  //# sourceMappingURL=mcp-server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"mcp-server.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lean-spec",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Lightweight spec methodology for AI-powered development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,14 +10,8 @@
10
10
  "build": "tsup",
11
11
  "dev": "tsup --watch",
12
12
  "typecheck": "tsc --noEmit",
13
- "format": "prettier --write .",
14
- "test": "pnpm test:run",
15
- "test:ui": "vitest --ui",
16
- "test:run": "vitest run",
17
- "test:coverage": "vitest run --coverage",
18
- "docs:dev": "pnpm -F docs-site start",
19
- "docs:build": "pnpm -F docs-site build",
20
- "docs:serve": "pnpm -F docs-site serve"
13
+ "test": "vitest run",
14
+ "test:watch": "vitest"
21
15
  },
22
16
  "keywords": [
23
17
  "spec",
@@ -45,18 +39,6 @@
45
39
  "LICENSE",
46
40
  "CHANGELOG.md"
47
41
  ],
48
- "devDependencies": {
49
- "@types/js-yaml": "^4.0.9",
50
- "@types/marked-terminal": "^6.1.1",
51
- "@types/node": "^20.10.0",
52
- "@types/react": "^19.2.2",
53
- "@vitest/coverage-v8": "^4.0.6",
54
- "@vitest/ui": "^4.0.6",
55
- "prettier": "^3.1.1",
56
- "tsup": "^8.0.1",
57
- "typescript": "^5.3.3",
58
- "vitest": "^4.0.6"
59
- },
60
42
  "dependencies": {
61
43
  "@inquirer/prompts": "^7.9.0",
62
44
  "@modelcontextprotocol/sdk": "^1.21.0",
@@ -66,8 +48,8 @@
66
48
  "commander": "^14.0.2",
67
49
  "dayjs": "^1.11.19",
68
50
  "gray-matter": "^4.0.3",
51
+ "handlebars": "^4.7.8",
69
52
  "ink": "^6.4.0",
70
- "ink-box": "^2.0.0",
71
53
  "ink-gradient": "^3.0.0",
72
54
  "ink-progress-bar": "^3.0.0",
73
55
  "ink-select-input": "^6.2.0",
@@ -80,8 +62,21 @@
80
62
  "ora": "^9.0.0",
81
63
  "react": "^19.2.0",
82
64
  "strip-ansi": "^7.1.2",
65
+ "tiktoken": "^1.0.22",
66
+ "tokenx": "^1.2.1",
83
67
  "zod": "^3.25.76"
84
68
  },
69
+ "devDependencies": {
70
+ "@leanspec/core": "workspace:*",
71
+ "@types/handlebars": "^4.1.0",
72
+ "@types/js-yaml": "^4.0.9",
73
+ "@types/marked-terminal": "^6.1.1",
74
+ "@types/node": "^20.10.0",
75
+ "@types/react": "^19.2.2",
76
+ "tsup": "^8.0.1",
77
+ "typescript": "^5.3.3",
78
+ "vitest": "^4.0.6"
79
+ },
85
80
  "engines": {
86
81
  "node": ">=18"
87
82
  }
@@ -0,0 +1,5 @@
1
+ 1. **Read README.md first** - Understand project context
2
+ 2. **Check specs/** - Review existing specs before starting
3
+ 3. **Follow LeanSpec principles** - Clarity over documentation
4
+ 4. **Keep it minimal** - If it doesn't add clarity, cut it
5
+ 5. **Never use nested code blocks** - Markdown doesn't support code blocks within code blocks. Use indentation or describe the structure instead
@@ -0,0 +1,5 @@
1
+ 1. **Security first** - Follow security standards, no shortcuts
2
+ 2. **Read specs/** - Check for compliance requirements
3
+ 3. **Follow LeanSpec** - Lean doesn't mean skipping governance
4
+ 4. **Document decisions** - Especially security and compliance choices
5
+ 5. **Never use nested code blocks** - Markdown doesn't support code blocks within code blocks. Use indentation or describe the structure instead
@@ -0,0 +1,10 @@
1
+ Before starting work, understand project context and dependencies:
2
+
3
+ - `lean-spec stats` - See work distribution across specs
4
+ - `lean-spec board` - View specs organized by status
5
+ - `lean-spec list --tag=<tag>` - Find specs by tag (e.g., `--tag=security`)
6
+ - `lean-spec search "<query>"` - Full-text search across specs
7
+ - `lean-spec deps <spec>` - Check dependencies before starting work
8
+ - `lean-spec gantt` - View project timeline and milestones
9
+
10
+ These commands help you understand what exists, what's in progress, and what depends on what.
@@ -0,0 +1,8 @@
1
+ Before starting work, understand project context:
2
+
3
+ - `lean-spec stats` - See work distribution
4
+ - `lean-spec board` - View specs by status
5
+ - `lean-spec search "<query>"` - Find relevant work
6
+ - `lean-spec list` - List all specs
7
+
8
+ These help you understand what exists and what's in progress.
@@ -0,0 +1,9 @@
1
+ Before starting work, understand project context:
2
+
3
+ - `lean-spec stats` - See work distribution across specs
4
+ - `lean-spec board` - View specs organized by status
5
+ - `lean-spec list --tag=<tag>` - Find specs by tag (e.g., `--tag=api`)
6
+ - `lean-spec search "<query>"` - Full-text search across specs
7
+ - `lean-spec deps <spec>` - Check dependencies before starting work
8
+
9
+ These commands help you understand what exists, what's in progress, and what depends on what.
@@ -0,0 +1,10 @@
1
+ ## Approval Workflow
2
+
3
+ 1. **Discover context** - Run `lean-spec stats`, `lean-spec board`, `lean-spec deps`
4
+ 2. **Create spec** - Include all required frontmatter fields
5
+ 3. **Technical review** - Assign reviewer in frontmatter
6
+ 4. **Security team review** - For security/compliance-tagged specs
7
+ 5. **Stakeholder sign-off** - Update status to `planned`
8
+ 6. **Implementation** - Update status to `in-progress`, keep spec in sync
9
+ 7. **Final review** - Before deployment
10
+ 8. **Complete & archive** - Mark `complete`, then archive
@@ -0,0 +1,12 @@
1
+ ## Security & Compliance in Frontmatter
2
+
3
+ Tag specs with relevant compliance standards:
4
+ ```yaml
5
+ tags: [security, api, pii]
6
+ compliance: [SOC2, GDPR]
7
+ ```
8
+
9
+ This helps with:
10
+ - Compliance audits and reporting
11
+ - Security review prioritization
12
+ - Regulatory requirement tracking
@@ -0,0 +1,13 @@
1
+ ## When Specs Are Required
2
+
3
+ Required for:
4
+ - Features touching PII or sensitive data
5
+ - Changes to authentication/authorization
6
+ - New external integrations
7
+ - Breaking changes to APIs
8
+ - Infrastructure changes
9
+
10
+ Optional for:
11
+ - Internal refactors
12
+ - Bug fixes (unless security-related)
13
+ - Minor UI changes