lean-spec 0.1.1 → 0.1.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.
package/dist/cli.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  updateSpec,
23
23
  validateCommand,
24
24
  viewCommand
25
- } from "./chunk-GLXYUS7F.js";
25
+ } from "./chunk-OXTU3PN4.js";
26
26
  import "./chunk-S4YNQ5KE.js";
27
27
 
28
28
  // src/cli.ts
@@ -46,7 +46,7 @@ function parseCustomFieldOptions(fieldOptions) {
46
46
 
47
47
  // src/cli.ts
48
48
  var program = new Command();
49
- program.name("lspec").description("Manage LeanSpec documents").version("0.1.0");
49
+ program.name("lean-spec").description("Manage LeanSpec documents").version("0.1.2");
50
50
  program.addHelpText("after", `
51
51
  Command Groups:
52
52
 
@@ -80,17 +80,17 @@ Command Groups:
80
80
  mcp Start MCP server for AI assistants
81
81
 
82
82
  Examples:
83
- $ lspec init
84
- $ lspec create my-feature --priority high
85
- $ lspec list --status in-progress
86
- $ lspec view 042
87
- $ lspec backfill --dry-run
88
- $ lspec board --tag backend
89
- $ lspec search "authentication"
90
- $ lspec validate
91
- $ lspec validate --verbose
92
- $ lspec validate --quiet --rule max-lines
93
- $ lspec validate 018 --max-lines 500
83
+ $ lean-spec init
84
+ $ lean-spec create my-feature --priority high
85
+ $ lean-spec list --status in-progress
86
+ $ lean-spec view 042
87
+ $ lean-spec backfill --dry-run
88
+ $ lean-spec board --tag backend
89
+ $ lean-spec search "authentication"
90
+ $ lean-spec validate
91
+ $ lean-spec validate --verbose
92
+ $ lean-spec validate --quiet --rule max-lines
93
+ $ lean-spec validate 018 --max-lines 500
94
94
  `);
95
95
  program.command("archive <spec>").description("Move spec to archived/").action(async (specPath) => {
96
96
  await archiveSpec(specPath);
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 {\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} from './commands/index.js';\nimport { parseCustomFieldOptions } from './utils/cli-helpers.js';\nimport type { SpecStatus, SpecPriority } from './frontmatter.js';\n\nconst program = new Command();\n\nprogram\n .name('lspec')\n .description('Manage LeanSpec documents')\n .version('0.1.0');\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 \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 $ lspec init\n $ lspec create my-feature --priority high\n $ lspec list --status in-progress\n $ lspec view 042\n $ lspec backfill --dry-run\n $ lspec board --tag backend\n $ lspec search \"authentication\"\n $ lspec validate\n $ lspec validate --verbose\n $ lspec validate --quiet --rule max-lines\n $ lspec 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// 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":[]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/utils/cli-helpers.ts"],"sourcesContent":["import { Command } from 'commander';\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} from './commands/index.js';\nimport { parseCustomFieldOptions } from './utils/cli-helpers.js';\nimport type { SpecStatus, SpecPriority } from './frontmatter.js';\n\nconst program = new Command();\n\nprogram\n .name('lean-spec')\n .description('Manage LeanSpec documents')\n .version('0.1.2');\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 \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 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// 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":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createMcpServer
4
- } from "./chunk-GLXYUS7F.js";
4
+ } from "./chunk-OXTU3PN4.js";
5
5
  import "./chunk-S4YNQ5KE.js";
6
6
  export {
7
7
  createMcpServer
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "lean-spec",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Lightweight spec methodology for AI-powered development",
5
5
  "type": "module",
6
6
  "bin": {
7
- "lspec": "./bin/lspec.js"
7
+ "lean-spec": "./bin/lean-spec.js"
8
8
  },
9
9
  "scripts": {
10
10
  "build": "tsup",