specweave 3.1.16 → 3.1.18
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/.claude-plugin/marketplace.json +2 -2
- package/bin/help.js +18 -36
- package/bin/specweave.js +19 -19
- package/dist/src/adapters/generic/adapter.d.ts.map +1 -1
- package/dist/src/adapters/generic/adapter.js +4 -44
- package/dist/src/adapters/generic/adapter.js.map +1 -1
- package/dist/src/cli/commands/complete.d.ts +6 -0
- package/dist/src/cli/commands/complete.d.ts.map +1 -1
- package/dist/src/cli/commands/complete.js +18 -0
- package/dist/src/cli/commands/complete.js.map +1 -1
- package/dist/src/cli/commands/task.d.ts +19 -1
- package/dist/src/cli/commands/task.d.ts.map +1 -1
- package/dist/src/cli/commands/task.js +62 -5
- package/dist/src/cli/commands/task.js.map +1 -1
- package/dist/src/cli/helpers/init/gitignore-generator.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/gitignore-generator.js +32 -7
- package/dist/src/cli/helpers/init/gitignore-generator.js.map +1 -1
- package/dist/src/cli/helpers/init/next-steps.d.ts +3 -2
- package/dist/src/cli/helpers/init/next-steps.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/next-steps.js +18 -31
- package/dist/src/cli/helpers/init/next-steps.js.map +1 -1
- package/dist/src/cli/helpers/init/summary-banner.js +1 -1
- package/dist/src/cli/helpers/init/summary-banner.js.map +1 -1
- package/dist/src/core/increment/template-creator.js +1 -1
- package/dist/src/core/increment/template-creator.js.map +1 -1
- package/dist/src/core/tasks/task-board.d.ts +5 -2
- package/dist/src/core/tasks/task-board.d.ts.map +1 -1
- package/dist/src/core/tasks/task-board.js +6 -2
- package/dist/src/core/tasks/task-board.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave/skills/do/SKILL.md +6 -4
- package/src/templates/.gitignore.template +1 -4
- package/src/templates/AGENTS.md.template +4 -6
- package/src/templates/CLAUDE.md.template +0 -1
- package/src/templates/README.md.template +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specweave",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.18",
|
|
4
4
|
"description": "Portable intent, specifications, task evidence, and handoffs across AI coding tools.",
|
|
5
5
|
"owner": {
|
|
6
6
|
"name": "Anton Abyzov",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"description": "SpecWeave unified plugin — increment lifecycle (plan, work the ledger, verify, review, complete), cross-tool handoff, GitHub/Jira/ADO sync",
|
|
13
13
|
"source": "./plugins/specweave",
|
|
14
14
|
"category": "development",
|
|
15
|
-
"version": "3.1.
|
|
15
|
+
"version": "3.1.18",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "Anton Abyzov",
|
|
18
18
|
"email": "anton.abyzov@gmail.com"
|
package/bin/help.js
CHANGED
|
@@ -1,44 +1,26 @@
|
|
|
1
1
|
export function registerHelp(program) {
|
|
2
|
-
// Help text
|
|
2
|
+
// Help text: the loop first, then a few everyday commands. Plumbing and legacy
|
|
3
|
+
// commands are registered with { hidden: true } and still run.
|
|
3
4
|
program.on('--help', () => {
|
|
4
5
|
console.log('');
|
|
5
|
-
console.log('
|
|
6
|
-
console.log(' $ specweave init
|
|
7
|
-
console.log(' $ specweave
|
|
8
|
-
console.log(' $ specweave
|
|
9
|
-
console.log(' $ specweave
|
|
10
|
-
console.log(' $ specweave
|
|
11
|
-
console.log(' $ specweave
|
|
12
|
-
console.log(' $ specweave
|
|
13
|
-
console.log(' $ specweave abandon 0007 --reason "obsolete" # Abandon increment 0007');
|
|
14
|
-
console.log(' $ specweave qa 0008 # Quick quality check');
|
|
15
|
-
console.log(' $ specweave qa 0008 --pre # Pre-implementation check');
|
|
16
|
-
console.log(' $ specweave qa 0008 --gate --export # Quality gate + export to tasks');
|
|
17
|
-
console.log(' $ specweave sync status # Token/account, provider health, sync gaps');
|
|
18
|
-
console.log(' $ specweave sync push 0008 # Push increment progress to GitHub/Jira/ADO');
|
|
19
|
-
console.log(' $ specweave sync pull --since 3 # Show external changes from the last 3 days');
|
|
20
|
-
console.log(' $ specweave sync setup --validate # Validate tracker configuration + credentials');
|
|
21
|
-
console.log(' $ specweave doctor --fix-status # Fix metadata/spec status desyncs');
|
|
22
|
-
console.log(' $ specweave refresh-plugins # Refresh core SpecWeave plugin');
|
|
23
|
-
console.log(' $ specweave refresh-plugins --all # Refresh every installed plugin');
|
|
24
|
-
console.log(' $ specweave refresh-plugins --force # Force reinstall (skip hash check)');
|
|
25
|
-
console.log(' $ specweave update # Update CLI + instructions + config');
|
|
26
|
-
console.log(' $ specweave update --plugins # Also refresh marketplace plugins');
|
|
27
|
-
console.log(' $ specweave update --no-self # Skip CLI update, only project files');
|
|
28
|
-
console.log(' $ specweave update --check # Dry run - preview changes');
|
|
6
|
+
console.log('The loop:');
|
|
7
|
+
console.log(' $ specweave init # Set up SpecWeave in this folder');
|
|
8
|
+
console.log(' $ specweave create-increment "Add login form" # Plan: fill spec.md (Problem, ACs, Tasks)');
|
|
9
|
+
console.log(' $ specweave task done T-01 --run "npm test" # After the commit: run the task\'s Test, record it');
|
|
10
|
+
console.log(' $ specweave verify # Run the project\'s build/test/lint commands');
|
|
11
|
+
console.log(' $ specweave complete 0001 # Close the increment');
|
|
12
|
+
console.log(' $ specweave handoff --reason "out of tokens" # Stop here; another tool or account continues');
|
|
13
|
+
console.log(' $ specweave pickup # Continue handed-off work');
|
|
29
14
|
console.log('');
|
|
30
|
-
console.log('
|
|
31
|
-
console.log(' $
|
|
32
|
-
console.log(' $
|
|
33
|
-
console.log(' $
|
|
15
|
+
console.log('Also:');
|
|
16
|
+
console.log(' $ specweave status # Increments and their progress');
|
|
17
|
+
console.log(' $ specweave task next # The next open task with its acceptance criteria');
|
|
18
|
+
console.log(' $ specweave sync setup # Connect GitHub Issues, Jira or Azure DevOps');
|
|
19
|
+
console.log(' $ specweave doctor # Check project health');
|
|
20
|
+
console.log(' $ specweave update # Update the CLI, instructions and skills');
|
|
34
21
|
console.log('');
|
|
35
|
-
console.log('
|
|
36
|
-
console.log('
|
|
37
|
-
console.log(' - Cursor (semi-automation) - .cursorrules, @ shortcuts');
|
|
38
|
-
console.log(' - GitHub Copilot (basic) - Workspace instructions');
|
|
39
|
-
console.log(' - Generic (manual) - Works with ANY AI (ChatGPT, Gemini, etc.)');
|
|
40
|
-
console.log('');
|
|
41
|
-
console.log('For more information, visit: https://spec-weave.com');
|
|
22
|
+
console.log('Works with Claude Code, Codex, Cursor, Copilot, Gemini CLI and any tool that reads AGENTS.md.');
|
|
23
|
+
console.log('More: https://spec-weave.com');
|
|
42
24
|
});
|
|
43
25
|
|
|
44
26
|
}
|
package/bin/specweave.js
CHANGED
|
@@ -23,7 +23,7 @@ const program = new Command();
|
|
|
23
23
|
|
|
24
24
|
program
|
|
25
25
|
.name('specweave')
|
|
26
|
-
.description('Spec-
|
|
26
|
+
.description('Spec-driven increments for AI coding agents: plan in spec.md, do each task, verify, close, hand off')
|
|
27
27
|
.version(packageJson.version)
|
|
28
28
|
.option('--workspace <root>', 'Select the planning workspace explicitly');
|
|
29
29
|
|
|
@@ -256,7 +256,7 @@ program
|
|
|
256
256
|
// Create Increment command - Create template files for a new increment
|
|
257
257
|
program
|
|
258
258
|
.command('create-increment [title]')
|
|
259
|
-
.description('Create increment
|
|
259
|
+
.description('Create an increment: metadata.json and spec.md (Problem, Scope, ACs, Approach, Tasks). Short form: specweave create-increment "Add login form"')
|
|
260
260
|
.option('--id <increment-id>', 'Increment ID (e.g., "0042-my-feature")')
|
|
261
261
|
.option('--auto-id', 'Auto-generate next available increment ID (default when --id is absent)')
|
|
262
262
|
.option('--name <name>', 'Increment name suffix (defaults to a slug of the title)')
|
|
@@ -382,7 +382,7 @@ program
|
|
|
382
382
|
});
|
|
383
383
|
|
|
384
384
|
program
|
|
385
|
-
.command('statusline')
|
|
385
|
+
.command('statusline', { hidden: true })
|
|
386
386
|
.description('Claude Code status line that records usage for auto-handoff')
|
|
387
387
|
.option('--wrap <command>', 'Print this status line command\'s output instead of the built-in line')
|
|
388
388
|
.action(async (options) => {
|
|
@@ -391,7 +391,7 @@ program
|
|
|
391
391
|
});
|
|
392
392
|
|
|
393
393
|
program
|
|
394
|
-
.command('usage-guard')
|
|
394
|
+
.command('usage-guard', { hidden: true })
|
|
395
395
|
.description('Stop hook: save a local checkpoint; at the auto-handoff threshold, suggest or ask for a handoff once')
|
|
396
396
|
.option('--limit-hit', 'StopFailure hook: the turn hit the rate limit, so hand off now (or only save, in checkpoint-only mode)')
|
|
397
397
|
.action(async (options) => {
|
|
@@ -401,7 +401,7 @@ program
|
|
|
401
401
|
|
|
402
402
|
// Auto-compact window for Claude Code (400K keeps 1M-context turns small)
|
|
403
403
|
program
|
|
404
|
-
.command('autocompact [action]')
|
|
404
|
+
.command('autocompact [action]', { hidden: true })
|
|
405
405
|
.description('on | off | status: where Claude Code summarizes a long session (default 400k)')
|
|
406
406
|
.option('--at <tokens>', 'Window for `on`, 100k to 1M (default 400k)')
|
|
407
407
|
.option('--project', 'Write .claude/settings.json in this project instead of ~/.claude/settings.json')
|
|
@@ -457,7 +457,7 @@ program
|
|
|
457
457
|
|
|
458
458
|
// Next ID command - Return the next available increment number
|
|
459
459
|
program
|
|
460
|
-
.command('next-id')
|
|
460
|
+
.command('next-id', { hidden: true })
|
|
461
461
|
.description('Return the next available increment number. Prefer: create-increment --auto-id')
|
|
462
462
|
.option('--project <project-id>', 'Project ID for per-project collision prevention')
|
|
463
463
|
.option('--project-root <path>', 'Override project root directory')
|
|
@@ -512,7 +512,7 @@ program
|
|
|
512
512
|
|
|
513
513
|
// Save command - Smart save with auto-sync
|
|
514
514
|
program
|
|
515
|
-
.command('save [message]')
|
|
515
|
+
.command('save [message]', { hidden: true })
|
|
516
516
|
.description('Smart save - auto-generate commit message, sync with remote, commit and push')
|
|
517
517
|
.option('-i, --interactive', 'Interactive mode - ask before each step')
|
|
518
518
|
.option('--dry-run', 'Preview without executing')
|
|
@@ -559,7 +559,7 @@ program
|
|
|
559
559
|
// Auto mode commands - Autonomous execution with stop hook feedback loop (v3.0)
|
|
560
560
|
// No session files. No complex state. Just: "Are there active increments?"
|
|
561
561
|
program
|
|
562
|
-
.command('auto [incrementIds...]')
|
|
562
|
+
.command('auto [incrementIds...]', { hidden: true })
|
|
563
563
|
.description('Start autonomous execution (stop hook feedback loop)')
|
|
564
564
|
.option('--dry-run', 'Preview without activating')
|
|
565
565
|
.option('--all-backlog', 'Activate all backlog items')
|
|
@@ -588,7 +588,7 @@ program
|
|
|
588
588
|
});
|
|
589
589
|
|
|
590
590
|
program
|
|
591
|
-
.command('auto-status')
|
|
591
|
+
.command('auto-status', { hidden: true })
|
|
592
592
|
.description('Check auto session status and progress')
|
|
593
593
|
.option('--verbose', 'Show detailed information')
|
|
594
594
|
.option('--json', 'Output as JSON')
|
|
@@ -602,7 +602,7 @@ program
|
|
|
602
602
|
});
|
|
603
603
|
|
|
604
604
|
program
|
|
605
|
-
.command('cancel-auto')
|
|
605
|
+
.command('cancel-auto', { hidden: true })
|
|
606
606
|
.description('Cancel running auto session')
|
|
607
607
|
.option('--force', 'Force cancel without confirmation')
|
|
608
608
|
.action(async (options) => {
|
|
@@ -615,7 +615,7 @@ program
|
|
|
615
615
|
|
|
616
616
|
// Team command - Launch Claude Code with native agent teams
|
|
617
617
|
program
|
|
618
|
-
.command('team [description]')
|
|
618
|
+
.command('team [description]', { hidden: true })
|
|
619
619
|
.description('Launch Claude Code with agent teams (tmux/iTerm2 split panes)')
|
|
620
620
|
.option('--mode <mode>', 'Display mode: tmux (default) or in-process', 'tmux')
|
|
621
621
|
.option('--no-increment', 'Launch without requiring a SpecWeave increment (free-form agent swarm)')
|
|
@@ -632,7 +632,7 @@ program
|
|
|
632
632
|
|
|
633
633
|
// Update instructions command - Smart merge CLAUDE.md/AGENTS.md
|
|
634
634
|
program
|
|
635
|
-
.command('update-instructions')
|
|
635
|
+
.command('update-instructions', { hidden: true })
|
|
636
636
|
.description('Update CLAUDE.md and AGENTS.md with smart merge (preserves user content)')
|
|
637
637
|
.option('--dry-run', 'Preview changes without writing')
|
|
638
638
|
.option('-v, --verbose', 'Show detailed merge information')
|
|
@@ -661,7 +661,7 @@ program
|
|
|
661
661
|
|
|
662
662
|
// Check discipline command - Validate increment discipline
|
|
663
663
|
program
|
|
664
|
-
.command('check-discipline')
|
|
664
|
+
.command('check-discipline', { hidden: true })
|
|
665
665
|
.description('Report increment status counts, advisory WIP note and metadata consistency')
|
|
666
666
|
.option('-v, --verbose', 'Show detailed increment information')
|
|
667
667
|
.option('--json', 'Output results as JSON')
|
|
@@ -677,7 +677,7 @@ program
|
|
|
677
677
|
|
|
678
678
|
// GC command - purge junk from .specweave/state (dry-run by default)
|
|
679
679
|
program
|
|
680
|
-
.command('gc')
|
|
680
|
+
.command('gc', { hidden: true })
|
|
681
681
|
.description('Purge stale .specweave/state files (dry-run; --yes to delete), report .worktrees size and nested .specweave dirs, expire session checkpoints older than 7 days')
|
|
682
682
|
.option('-y, --yes', 'Actually delete (default is dry-run)')
|
|
683
683
|
.option('--json', 'Output as JSON')
|
|
@@ -689,7 +689,7 @@ program
|
|
|
689
689
|
|
|
690
690
|
// QA command - Quality assessment
|
|
691
691
|
program
|
|
692
|
-
.command('qa <increment-id>')
|
|
692
|
+
.command('qa <increment-id>', { hidden: true })
|
|
693
693
|
.description('Run quality assessment on an increment')
|
|
694
694
|
.option('--quick', 'Quick mode (default)')
|
|
695
695
|
.option('--pre', 'Pre-implementation check')
|
|
@@ -708,7 +708,7 @@ program
|
|
|
708
708
|
|
|
709
709
|
// Link PR - Link pull requests to external tickets (JIRA remote links, ADO hyperlinks)
|
|
710
710
|
program
|
|
711
|
-
.command('link-pr')
|
|
711
|
+
.command('link-pr', { hidden: true })
|
|
712
712
|
.description('Link a pull request to external tickets (JIRA, ADO)')
|
|
713
713
|
.requiredOption('--increment <id>', 'Increment ID')
|
|
714
714
|
.requiredOption('--pr-url <url>', 'Pull request URL')
|
|
@@ -721,7 +721,7 @@ program
|
|
|
721
721
|
|
|
722
722
|
// Branch-name command - Compute branch name with optional external ticket key
|
|
723
723
|
program
|
|
724
|
-
.command('branch-name <increment-id>')
|
|
724
|
+
.command('branch-name <increment-id>', { hidden: true })
|
|
725
725
|
.description('Output the computed branch name for an increment (with optional JIRA/ADO ticket key)')
|
|
726
726
|
.action(async (incrementId) => {
|
|
727
727
|
const { branchNameCommand } = await import('../dist/src/cli/commands/branch-name.js');
|
|
@@ -737,7 +737,7 @@ async function runLspCommand(args) {
|
|
|
737
737
|
|
|
738
738
|
// LSP command - Code intelligence operations
|
|
739
739
|
const lspCmd = program
|
|
740
|
-
.command('lsp')
|
|
740
|
+
.command('lsp', { hidden: true })
|
|
741
741
|
.description('LSP code intelligence (refs, def, hover, symbols, search)');
|
|
742
742
|
|
|
743
743
|
lspCmd
|
|
@@ -865,7 +865,7 @@ syncCmd
|
|
|
865
865
|
|
|
866
866
|
// Refresh plugins command - Copy first-party plugins to ~/.claude/commands/
|
|
867
867
|
program
|
|
868
|
-
.command('refresh-plugins')
|
|
868
|
+
.command('refresh-plugins', { hidden: true })
|
|
869
869
|
.description('Refresh SpecWeave plugins (core only by default, use --all for everything)')
|
|
870
870
|
.option('--all', 'Install ALL plugins (not just core sw)')
|
|
871
871
|
.option('--plugin <name>', 'Install a specific plugin by name')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/adapters/generic/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEzD,qBAAa,cAAe,SAAQ,WAAW;IAC7C,IAAI,SAAa;IACjB,WAAW,SAAyF;IACpG,eAAe,EAAG,QAAQ,CAAU;IAEpC;;;;;OAKG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAKhC;;;;;OAKG;IACH,QAAQ,IAAI,WAAW,EAAE;IAIzB;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrD;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD;;OAEG;IACH,eAAe,IAAI,MAAM;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/adapters/generic/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEzD,qBAAa,cAAe,SAAQ,WAAW;IAC7C,IAAI,SAAa;IACjB,WAAW,SAAyF;IACpG,eAAe,EAAG,QAAQ,CAAU;IAEpC;;;;;OAKG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAKhC;;;;;OAKG;IACH,QAAQ,IAAI,WAAW,EAAE;IAIzB;;OAEG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrD;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzD;;OAEG;IACH,eAAe,IAAI,MAAM;IAQzB;;;;;;OAMG;IACH,eAAe,IAAI,OAAO;IAI1B,kBAAkB,IAAI,MAAM;IAI5B;;;;;;;OAOG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+DlD;;;;OAIG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCrD;;;;OAIG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;CAwB/C"}
|
|
@@ -54,51 +54,11 @@ export class GenericAdapter extends AdapterBase {
|
|
|
54
54
|
* Get usage instructions for Generic adapter
|
|
55
55
|
*/
|
|
56
56
|
getInstructions() {
|
|
57
|
+
// Short on purpose: init's "Next steps" prints the loop right after this.
|
|
57
58
|
return `
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
Your project is now configured for ANY AI tool!
|
|
63
|
-
|
|
64
|
-
WHAT THIS PROVIDES:
|
|
65
|
-
|
|
66
|
-
- AGENTS.md (Universal Standard)
|
|
67
|
-
- Works with: GitHub Copilot, ChatGPT, Gemini, Claude web, etc.
|
|
68
|
-
- Contains all workflow instructions and project structure
|
|
69
|
-
- Following agents.md standard (https://agents.md/)
|
|
70
|
-
|
|
71
|
-
HOW TO USE AGENTS.MD:
|
|
72
|
-
|
|
73
|
-
Method 1: Auto-Discovery (Copilot - Recommended)
|
|
74
|
-
AI reads AGENTS.md → Ask "create increment for payments" → Done!
|
|
75
|
-
|
|
76
|
-
Method 2: Copy-Paste (ChatGPT, Claude web, etc.)
|
|
77
|
-
Open AGENTS.md → Copy workflow section → Paste to AI → Save output
|
|
78
|
-
|
|
79
|
-
Method 3: File System Access (AI with file access)
|
|
80
|
-
AI reads AGENTS.md automatically → Ask "Create increment" → Files created
|
|
81
|
-
|
|
82
|
-
QUICK START:
|
|
83
|
-
|
|
84
|
-
1. Open AGENTS.md - read "Common Workflows" section
|
|
85
|
-
2. Use your AI tool: ChatGPT, Claude web, Gemini, Copilot, etc.
|
|
86
|
-
3. Ask AI to follow the workflow instructions
|
|
87
|
-
4. Save generated files to .specweave/increments/
|
|
88
|
-
|
|
89
|
-
AVAILABLE COMMANDS (the CLI works in any tool):
|
|
90
|
-
specweave create-increment "feature" Plan the work (spec.md + tasks.md)
|
|
91
|
-
specweave task next | task claim T-01 | task done T-01 --run "<test>"
|
|
92
|
-
specweave verify <id> Run the checks, write reports/verify.json
|
|
93
|
-
specweave complete <id> Close the increment
|
|
94
|
-
specweave handoff [id] Write handoff.md before you stop
|
|
95
|
-
|
|
96
|
-
DOCUMENTATION:
|
|
97
|
-
- AGENTS.md - Workflow instructions (works with any AI!)
|
|
98
|
-
- .specweave/docs/ - Project documentation
|
|
99
|
-
|
|
100
|
-
Ready to build with SpecWeave using ANY AI tool!
|
|
101
|
-
`;
|
|
59
|
+
AGENTS.md now holds the workflow for any AI tool (Copilot, Gemini, ChatGPT and others).
|
|
60
|
+
Open the project in your tool and ask: "Create an increment for <your feature>".
|
|
61
|
+
`;
|
|
102
62
|
}
|
|
103
63
|
/**
|
|
104
64
|
* Check if Generic adapter supports plugins
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../../src/adapters/generic/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD,MAAM,OAAO,cAAe,SAAQ,WAAW;IAA/C;;QACE,SAAI,GAAG,SAAS,CAAC;QACjB,gBAAW,GAAG,qFAAqF,CAAC;QACpG,oBAAe,GAAG,QAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../../src/adapters/generic/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,5 +26,11 @@ interface CompleteCommandOptions {
|
|
|
26
26
|
* @since v4.1 - Short-ID resolution and batch mode
|
|
27
27
|
*/
|
|
28
28
|
export declare function completeCommand(incrementId: string | undefined, moreIds?: string[], options?: CompleteCommandOptions): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* `complete` never commits, so say how when the closed increment has
|
|
31
|
+
* uncommitted changes. Only inside a git work tree. The pathspec keeps other
|
|
32
|
+
* staged work out of the commit; the path is relative to where the user is.
|
|
33
|
+
*/
|
|
34
|
+
export declare function commitHint(projectRoot: string, incrementId: string, cwd?: string): string | undefined;
|
|
29
35
|
export {};
|
|
30
36
|
//# sourceMappingURL=complete.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/complete.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/complete.ts"],"names":[],"mappings":"AASA,UAAU,sBAAsB;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,OAAO,GAAE,MAAM,EAAO,EACtB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAmFf;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,SAAc,GAAG,MAAM,GAAG,SAAS,CAO1G"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
2
3
|
import { detectSessionId } from '../../core/tasks/ledger.js';
|
|
3
4
|
import { recordIncrementWork } from '../../core/tasks/work-session.js';
|
|
4
5
|
import { completeIncrement } from '../../core/increment/status-commands.js';
|
|
@@ -78,6 +79,9 @@ export async function completeCommand(incrementId, moreIds = [], options = {}) {
|
|
|
78
79
|
}
|
|
79
80
|
if (success) {
|
|
80
81
|
recordIncrementWork(path.join(projectRoot, '.specweave', 'increments', resolved), { e: 'complete' }, { sessionId: detectSessionId() });
|
|
82
|
+
const hint = options.silent || options.yes ? undefined : commitHint(projectRoot, resolved, process.cwd());
|
|
83
|
+
if (hint)
|
|
84
|
+
console.log(hint);
|
|
81
85
|
}
|
|
82
86
|
results.push({ id, resolved, success });
|
|
83
87
|
}
|
|
@@ -98,4 +102,18 @@ export async function completeCommand(incrementId, moreIds = [], options = {}) {
|
|
|
98
102
|
process.exit(1);
|
|
99
103
|
}
|
|
100
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* `complete` never commits, so say how when the closed increment has
|
|
107
|
+
* uncommitted changes. Only inside a git work tree. The pathspec keeps other
|
|
108
|
+
* staged work out of the commit; the path is relative to where the user is.
|
|
109
|
+
*/
|
|
110
|
+
export function commitHint(projectRoot, incrementId, cwd = projectRoot) {
|
|
111
|
+
const folder = path.join(projectRoot, '.specweave', 'increments', incrementId);
|
|
112
|
+
const status = spawnSync('git', ['status', '--porcelain', '--', folder], { cwd: projectRoot, encoding: 'utf-8' });
|
|
113
|
+
if (status.status !== 0 || !status.stdout.trim())
|
|
114
|
+
return undefined;
|
|
115
|
+
const rel = path.relative(cwd, folder).split(path.sep).join('/') || '.';
|
|
116
|
+
const num = incrementId.match(/^\d{3,}[A-Za-z]?(?=-)/)?.[0] ?? incrementId;
|
|
117
|
+
return `Commit it: git add ${rel} && git commit -m "${num}: close" -- ${rel}`;
|
|
118
|
+
}
|
|
101
119
|
//# sourceMappingURL=complete.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../../src/cli/commands/complete.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../../src/cli/commands/complete.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* task whoami print the agent id
|
|
5
5
|
* task list [inc] [--json] table: task, status, by, evidence
|
|
6
6
|
* task next [inc] [--json] first open task with deps met + no Files overlap
|
|
7
|
-
*
|
|
7
|
+
* (exit 7 while it is still a template placeholder)
|
|
8
|
+
* task claim T-01 [inc] [--force] append a claim (exit 3 lost race, 4 Files overlap,
|
|
9
|
+
* 7 unfilled template placeholder)
|
|
8
10
|
* task done T-01 [inc] --evidence "…" | --run "<cmd>" (exit 5 when the command fails;
|
|
9
11
|
* auto-claims when nobody holds a live claim)
|
|
10
12
|
* task release T-01 [inc] | --all-mine
|
|
@@ -26,6 +28,7 @@
|
|
|
26
28
|
*
|
|
27
29
|
* @module cli/commands/task
|
|
28
30
|
*/
|
|
31
|
+
import { type BoardTask } from '../../core/tasks/task-board.js';
|
|
29
32
|
export interface TaskCommandOptions {
|
|
30
33
|
force?: boolean;
|
|
31
34
|
evidence?: string;
|
|
@@ -52,6 +55,21 @@ export declare const EXIT_LOST_RACE = 3;
|
|
|
52
55
|
export declare const EXIT_FILES_OVERLAP = 4;
|
|
53
56
|
export declare const EXIT_RUN_FAILED = 5;
|
|
54
57
|
export declare const EXIT_DEPS_UNMET = 6;
|
|
58
|
+
/** `next` / `claim` on a task still holding create-increment's bracketed placeholders. */
|
|
59
|
+
export declare const EXIT_TEMPLATE_TASK = 7;
|
|
55
60
|
/** Entry point. Returns the process exit code (the bin sets process.exitCode). */
|
|
56
61
|
export declare function taskCommand(action: string, a?: string, b?: string, opts?: TaskCommandOptions): Promise<number>;
|
|
62
|
+
/**
|
|
63
|
+
* Quote a Test so the printed `--run` argument pastes as one shell word. Plain
|
|
64
|
+
* text stays in double quotes (works in every shell); anything a shell would
|
|
65
|
+
* expand or that would end the double quotes goes in POSIX single quotes.
|
|
66
|
+
*/
|
|
67
|
+
export declare function shellQuote(s: string): string;
|
|
68
|
+
/** A task still titled as create-increment's scaffold. */
|
|
69
|
+
export declare function isTemplateTask(t: Pick<BoardTask, 'title'>): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* A Test that is a bracketed placeholder (`[command]`, `[command that checks …]`).
|
|
72
|
+
* A letter must follow the bracket, so a shell test such as `[ -f dist/cli.js ]` is real.
|
|
73
|
+
*/
|
|
74
|
+
export declare function isPlaceholderTest(test: string | undefined): boolean;
|
|
57
75
|
//# sourceMappingURL=task.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/task.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/task.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AASH,OAAO,EASL,KAAK,SAAS,EACf,MAAM,gCAAgC,CAAC;AAOxC,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAIpC,kFAAkF;AAClF,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwQxH;AAoFD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5C;AASD,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,OAAO,CAEnE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEnE"}
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* task whoami print the agent id
|
|
5
5
|
* task list [inc] [--json] table: task, status, by, evidence
|
|
6
6
|
* task next [inc] [--json] first open task with deps met + no Files overlap
|
|
7
|
-
*
|
|
7
|
+
* (exit 7 while it is still a template placeholder)
|
|
8
|
+
* task claim T-01 [inc] [--force] append a claim (exit 3 lost race, 4 Files overlap,
|
|
9
|
+
* 7 unfilled template placeholder)
|
|
8
10
|
* task done T-01 [inc] --evidence "…" | --run "<cmd>" (exit 5 when the command fails;
|
|
9
11
|
* auto-claims when nobody holds a live claim)
|
|
10
12
|
* task release T-01 [inc] | --all-mine
|
|
@@ -43,6 +45,8 @@ export const EXIT_LOST_RACE = 3;
|
|
|
43
45
|
export const EXIT_FILES_OVERLAP = 4;
|
|
44
46
|
export const EXIT_RUN_FAILED = 5;
|
|
45
47
|
export const EXIT_DEPS_UNMET = 6;
|
|
48
|
+
/** `next` / `claim` on a task still holding create-increment's bracketed placeholders. */
|
|
49
|
+
export const EXIT_TEMPLATE_TASK = 7;
|
|
46
50
|
const ACTIONS = new Set(['whoami', 'list', 'next', 'claim', 'done', 'release', 'block', 'skip', 'render']);
|
|
47
51
|
/** Entry point. Returns the process exit code (the bin sets process.exitCode). */
|
|
48
52
|
export async function taskCommand(action, a, b, opts = {}) {
|
|
@@ -138,7 +142,16 @@ export async function taskCommand(action, a, b, opts = {}) {
|
|
|
138
142
|
return 0;
|
|
139
143
|
}
|
|
140
144
|
if (action === 'next') {
|
|
141
|
-
const t = nextTask(board, agent);
|
|
145
|
+
const t = nextTask(board, agent, isTemplateTask);
|
|
146
|
+
// Only unfilled placeholders are left to hand out: say so instead of "nothing to do".
|
|
147
|
+
const placeholder = t ? undefined : nextTask(board, agent);
|
|
148
|
+
if (placeholder) {
|
|
149
|
+
if (opts.json)
|
|
150
|
+
out(JSON.stringify({ increment: inc.id, next: null, error: 'template-task', task: placeholder.id }));
|
|
151
|
+
else
|
|
152
|
+
err(templateRefusal(placeholder, inc.id));
|
|
153
|
+
return EXIT_TEMPLATE_TASK;
|
|
154
|
+
}
|
|
142
155
|
if (!t) {
|
|
143
156
|
const c = board.counts;
|
|
144
157
|
const finished = c.total > 0 && c.done + c.skipped === c.total;
|
|
@@ -188,6 +201,10 @@ export async function taskCommand(action, a, b, opts = {}) {
|
|
|
188
201
|
err(`${taskId} is already ${task.state.status}`);
|
|
189
202
|
return 1;
|
|
190
203
|
}
|
|
204
|
+
if (isTemplateTask(task)) {
|
|
205
|
+
err(templateRefusal(task, inc.id));
|
|
206
|
+
return EXIT_TEMPLATE_TASK;
|
|
207
|
+
}
|
|
191
208
|
// Claiming a task starts the increment (planned → active). This is the
|
|
192
209
|
// CLI transition the skills point at; nobody hand-edits metadata.json.
|
|
193
210
|
const started = ensureIncrementStarted(inc.dir);
|
|
@@ -229,12 +246,18 @@ export async function taskCommand(action, a, b, opts = {}) {
|
|
|
229
246
|
err(`${taskId} was skipped by ${task.state.by}${task.state.note ? ` (${task.state.note})` : ''} — skip is terminal; add a new task to ${tasksFileName(inc.dir)} if the work is needed after all`);
|
|
230
247
|
return 1;
|
|
231
248
|
}
|
|
249
|
+
if (isTemplateTask(task)) {
|
|
250
|
+
err(templateRefusal(task, inc.id));
|
|
251
|
+
return EXIT_TEMPLATE_TASK;
|
|
252
|
+
}
|
|
232
253
|
if (heldByOther(task) && !opts.force) {
|
|
233
254
|
err(refusal(task, taskId, leaseHours));
|
|
234
255
|
return EXIT_LOST_RACE;
|
|
235
256
|
}
|
|
236
257
|
let evidence = (opts.evidence ?? '').trim();
|
|
237
|
-
|
|
258
|
+
// A placeholder Test (`[command]`) is not run: the agent passes --run or --evidence.
|
|
259
|
+
const runnable = isShellCommand(task.test) && !isPlaceholderTest(task.test);
|
|
260
|
+
const cmd = opts.run?.trim() || (!evidence && runnable ? task.test : undefined);
|
|
238
261
|
let logPath;
|
|
239
262
|
if (cmd) {
|
|
240
263
|
const result = await runShell(cmd, projectRoot);
|
|
@@ -283,10 +306,14 @@ export async function taskCommand(action, a, b, opts = {}) {
|
|
|
283
306
|
const c = board.counts;
|
|
284
307
|
const allDone = c.done + c.skipped === c.total && c.total > 0;
|
|
285
308
|
const committed = commitIncrement('done', [taskId]);
|
|
286
|
-
|
|
309
|
+
// Not the last task: hand the agent the next one, so it needs no `task next`.
|
|
310
|
+
const following = allDone ? undefined : nextTask(board, agent, isTemplateTask);
|
|
311
|
+
out(opts.json ? JSON.stringify({ done: taskId, evidence, log: logPath ? rel(projectRoot, logPath) : undefined, counts: c, ...(allDone ? { close: closeChain(inc.id) } : {}), ...(following ? { next: brief(following, acsOf()) } : {}), ...commitJson(committed) }) : `Done ${taskId} (${c.done}/${c.total}) — evidence: ${firstLine(evidence)}`);
|
|
287
312
|
reportCommit(committed);
|
|
288
313
|
if (allDone)
|
|
289
314
|
finishedAll(inc.id);
|
|
315
|
+
else if (following && !opts.json)
|
|
316
|
+
out(`\nNext: ${describeTask(following, inc.id, acsOf())}`);
|
|
290
317
|
return 0;
|
|
291
318
|
}
|
|
292
319
|
case 'release': {
|
|
@@ -423,7 +450,37 @@ function describeTask(t, incId, acs = []) {
|
|
|
423
450
|
...(criteria.length ? criteria.map((a) => ` ${a.id}: ${a.text || '(text not found in spec.md)'}`) : [' AC: -']),
|
|
424
451
|
` Files: ${(t.filesAffected ?? []).join(', ') || '-'} | Test: ${t.test ?? '-'}`,
|
|
425
452
|
` state: ${describeState(t.state)}`,
|
|
426
|
-
` when done: specweave task done ${t.id} ${incId}${t.test ? ` --run
|
|
453
|
+
` when done: specweave task done ${t.id} ${incId}${t.test && !isPlaceholderTest(t.test) ? ` --run ${shellQuote(t.test)}` : ' --run "<command that checks the AC>"'}`,
|
|
427
454
|
].join('\n');
|
|
428
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Quote a Test so the printed `--run` argument pastes as one shell word. Plain
|
|
458
|
+
* text stays in double quotes (works in every shell); anything a shell would
|
|
459
|
+
* expand or that would end the double quotes goes in POSIX single quotes.
|
|
460
|
+
*/
|
|
461
|
+
export function shellQuote(s) {
|
|
462
|
+
if (!/["$`\\!]/.test(s))
|
|
463
|
+
return `"${s}"`;
|
|
464
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* create-increment's scaffold task titles. Only these mark a task as unfilled:
|
|
468
|
+
* imported increments keep real titles next to `[src/...]` and `[command]`, and
|
|
469
|
+
* a user's own `[WIP] …` title is a real task.
|
|
470
|
+
*/
|
|
471
|
+
const SCAFFOLD_TITLES = new Set(['[First task]', '[Second task]']);
|
|
472
|
+
/** A task still titled as create-increment's scaffold. */
|
|
473
|
+
export function isTemplateTask(t) {
|
|
474
|
+
return SCAFFOLD_TITLES.has(t.title.trim());
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* A Test that is a bracketed placeholder (`[command]`, `[command that checks …]`).
|
|
478
|
+
* A letter must follow the bracket, so a shell test such as `[ -f dist/cli.js ]` is real.
|
|
479
|
+
*/
|
|
480
|
+
export function isPlaceholderTest(test) {
|
|
481
|
+
return test !== undefined && /^\[[A-Za-z][^\]]*\]$/.test(test.trim());
|
|
482
|
+
}
|
|
483
|
+
function templateRefusal(t, incId) {
|
|
484
|
+
return `refused: ${t.id} in ${incId} is still the create-increment placeholder ("${t.title}"). Fill in spec.md ## Tasks first: a real title, then "- AC: AC-01 | Files: <paths> | Test: <command that checks the AC>".`;
|
|
485
|
+
}
|
|
429
486
|
//# sourceMappingURL=task.js.map
|