specweave 0.30.19 → 0.32.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/CLAUDE.md +176 -2
- package/README.md +22 -0
- package/bin/specweave.js +18 -1
- package/dist/src/cli/commands/cache.d.ts +17 -0
- package/dist/src/cli/commands/cache.d.ts.map +1 -0
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/cache.js.map +1 -0
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/plan/increment-detector.js +2 -2
- package/dist/src/cli/commands/plan/increment-detector.js.map +1 -1
- package/dist/src/cli/commands/sync-spec-commits.js +1 -1
- package/dist/src/cli/commands/sync-spec-commits.js.map +1 -1
- package/dist/src/cli/commands/sync-specs.js +2 -2
- package/dist/src/cli/commands/sync-specs.js.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
- package/dist/src/cli/workers/living-docs-worker.js +66 -1
- package/dist/src/cli/workers/living-docs-worker.js.map +1 -1
- package/dist/src/config/types.d.ts +203 -1208
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -1
- package/dist/src/core/discrepancy/increment-generator.js +5 -2
- package/dist/src/core/discrepancy/increment-generator.js.map +1 -1
- package/dist/src/core/external-tools/external-items-counter.d.ts +62 -0
- package/dist/src/core/external-tools/external-items-counter.d.ts.map +1 -0
- package/dist/src/core/external-tools/external-items-counter.js +206 -0
- package/dist/src/core/external-tools/external-items-counter.js.map +1 -0
- package/dist/src/core/external-tools/external-items-display.d.ts +39 -0
- package/dist/src/core/external-tools/external-items-display.d.ts.map +1 -0
- package/dist/src/core/external-tools/external-items-display.js +185 -0
- package/dist/src/core/external-tools/external-items-display.js.map +1 -0
- package/dist/src/core/external-tools/index.d.ts +8 -0
- package/dist/src/core/external-tools/index.d.ts.map +1 -0
- package/dist/src/core/external-tools/index.js +8 -0
- package/dist/src/core/external-tools/index.js.map +1 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts +39 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.js +188 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.js.map +1 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.d.ts +38 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.js +136 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.js.map +1 -0
- package/dist/src/core/external-tools/providers/index.d.ts +7 -0
- package/dist/src/core/external-tools/providers/index.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/index.js +7 -0
- package/dist/src/core/external-tools/providers/index.js.map +1 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts +42 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.js +153 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.js.map +1 -0
- package/dist/src/core/external-tools/types.d.ts +78 -0
- package/dist/src/core/external-tools/types.d.ts.map +1 -0
- package/dist/src/core/external-tools/types.js +19 -0
- package/dist/src/core/external-tools/types.js.map +1 -0
- package/dist/src/core/increment/duplicate-detector.js +2 -2
- package/dist/src/core/increment/duplicate-detector.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +24 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +59 -2
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/increment-status.js +2 -2
- package/dist/src/core/increment/increment-status.js.map +1 -1
- package/dist/src/core/increment/increment-utils.d.ts +98 -37
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +119 -68
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/increment/metadata-validator.js +1 -1
- package/dist/src/core/increment/metadata-validator.js.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.js +4 -0
- package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.js +3 -3
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts +18 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +247 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts +15 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +138 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts +24 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js +198 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts +17 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js +241 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts +28 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.js +197 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +18 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +154 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts +42 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js +343 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +146 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.js +7 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.js.map +1 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts +5 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +36 -2
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/llm/providers/azure-openai-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/azure-openai-provider.js +1 -0
- package/dist/src/core/llm/providers/azure-openai-provider.js.map +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.js +2 -0
- package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
- package/dist/src/core/llm/providers/openai-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/openai-provider.js +1 -0
- package/dist/src/core/llm/providers/openai-provider.js.map +1 -1
- package/dist/src/core/llm/providers/vertex-ai-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/vertex-ai-provider.js +1 -0
- package/dist/src/core/llm/providers/vertex-ai-provider.js.map +1 -1
- package/dist/src/core/sync/spec-increment-mapper.js +3 -3
- package/dist/src/core/sync/spec-increment-mapper.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +25 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +135 -5
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/init/architecture/types.d.ts +33 -140
- package/dist/src/init/architecture/types.d.ts.map +1 -1
- package/dist/src/init/compliance/types.d.ts +30 -27
- package/dist/src/init/compliance/types.d.ts.map +1 -1
- package/dist/src/init/repo/types.d.ts +11 -34
- package/dist/src/init/repo/types.d.ts.map +1 -1
- package/dist/src/init/research/src/config/types.d.ts +15 -82
- package/dist/src/init/research/src/config/types.d.ts.map +1 -1
- package/dist/src/init/research/types.d.ts +38 -93
- package/dist/src/init/research/types.d.ts.map +1 -1
- package/dist/src/init/team/types.d.ts +4 -42
- package/dist/src/init/team/types.d.ts.map +1 -1
- package/dist/src/types/dashboard-cache.d.ts +181 -0
- package/dist/src/types/dashboard-cache.d.ts.map +1 -0
- package/dist/src/types/dashboard-cache.js +65 -0
- package/dist/src/types/dashboard-cache.js.map +1 -0
- package/dist/src/utils/docs-validator.d.ts +131 -0
- package/dist/src/utils/docs-validator.d.ts.map +1 -0
- package/dist/src/utils/docs-validator.js +529 -0
- package/dist/src/utils/docs-validator.js.map +1 -0
- package/dist/src/utils/feature-id-collision.js +1 -1
- package/dist/src/utils/feature-id-collision.js.map +1 -1
- package/dist/src/utils/html-to-mdx.d.ts +1 -0
- package/dist/src/utils/html-to-mdx.d.ts.map +1 -1
- package/dist/src/utils/html-to-mdx.js +43 -5
- package/dist/src/utils/html-to-mdx.js.map +1 -1
- package/package.json +1 -5
- package/plugins/specweave/agents/pm/AGENT.md +10 -7
- package/plugins/specweave/commands/specweave-archive-features.md +5 -7
- package/plugins/specweave/commands/specweave-archive.md +2 -1
- package/plugins/specweave/commands/specweave-do.md +35 -1
- package/plugins/specweave/commands/specweave-done.md +96 -0
- package/plugins/specweave/commands/specweave-external.md +150 -0
- package/plugins/specweave/commands/specweave-import-external.md +45 -18
- package/plugins/specweave/commands/specweave-increment.md +331 -33
- package/plugins/specweave/commands/specweave-jobs.md +2 -2
- package/plugins/specweave/commands/specweave-progress.md +4 -4
- package/plugins/specweave/commands/specweave-restore-feature.md +5 -4
- package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
- package/plugins/specweave/commands/specweave-sync-specs.md +216 -322
- package/plugins/specweave/commands/specweave-validate-features.md +13 -8
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/hooks.json +33 -4
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/lib/common-setup.sh +375 -0
- package/plugins/specweave/hooks/lib/crash-prevention.sh +336 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-task-completion.sh +4 -23
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh +1 -6
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh +8 -37
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh +2 -11
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/universal/dispatcher.mjs +135 -42
- package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +183 -0
- package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
- package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
- package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
- package/plugins/specweave/hooks/user-prompt-submit.sh +140 -38
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +12 -0
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +89 -0
- package/plugins/specweave/hooks/v2/guards/bash-file-guard.sh +211 -0
- package/plugins/specweave/hooks/v2/guards/bash-file-guard.test.sh +163 -0
- package/plugins/specweave/hooks/v2/guards/completion-guard.sh +26 -28
- package/plugins/specweave/hooks/v2/guards/features-folder-guard.sh +50 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +2 -2
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -1
- package/plugins/specweave/scripts/README.md +166 -0
- package/plugins/specweave/scripts/cleanup-state.sh +142 -0
- package/plugins/specweave/scripts/force-kill.sh +142 -0
- package/plugins/specweave/scripts/jobs.js +171 -0
- package/plugins/specweave/scripts/progress.js +170 -0
- package/plugins/specweave/scripts/read-costs.sh +132 -0
- package/plugins/specweave/scripts/read-jobs.sh +324 -0
- package/plugins/specweave/scripts/read-progress.sh +185 -0
- package/plugins/specweave/scripts/read-status.sh +146 -0
- package/plugins/specweave/scripts/read-workflow.sh +173 -0
- package/plugins/specweave/scripts/rebuild-dashboard-cache.sh +327 -0
- package/plugins/specweave/scripts/session-watchdog.sh +192 -0
- package/plugins/specweave/scripts/status.js +154 -0
- package/plugins/specweave/scripts/update-dashboard-cache.sh +281 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +333 -24
- package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +17 -9
- package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +6 -2
- package/plugins/specweave/skills/instant-status/SKILL.md +70 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-docs/commands/build.md +32 -4
- package/plugins/specweave-docs/commands/preview.md +43 -1
- package/plugins/specweave-docs/commands/validate.md +250 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1262 -626
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1254 -939
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- package/plugins/specweave/hooks/post-edit-spec.sh +0 -265
- package/plugins/specweave/hooks/post-write-spec.sh +0 -267
- package/plugins/specweave/hooks/pre-edit-spec.sh +0 -151
- package/plugins/specweave/hooks/pre-write-spec.sh +0 -151
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Instant Increment Progress
|
|
4
|
+
*
|
|
5
|
+
* Executed by UserPromptSubmit hook for /specweave:progress
|
|
6
|
+
* Bypasses LLM entirely - output shown directly to user
|
|
7
|
+
*
|
|
8
|
+
* Usage: node progress.js [incrementId] [--help]
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
|
|
14
|
+
// Handle --help
|
|
15
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
16
|
+
console.log(`
|
|
17
|
+
SpecWeave Instant Progress
|
|
18
|
+
|
|
19
|
+
USAGE
|
|
20
|
+
node plugins/specweave/scripts/progress.js [incrementId] [options]
|
|
21
|
+
specweave status --verbose
|
|
22
|
+
|
|
23
|
+
OPTIONS
|
|
24
|
+
--help, -h Show this help message
|
|
25
|
+
[incrementId] Show progress for specific increment (e.g., 0045)
|
|
26
|
+
|
|
27
|
+
DESCRIPTION
|
|
28
|
+
Shows task completion progress for active increments with visual progress bars.
|
|
29
|
+
This script bypasses LLM processing for instant results (<100ms).
|
|
30
|
+
|
|
31
|
+
EXECUTION PATHS
|
|
32
|
+
1. Claude Code: /specweave:progress (hook intercepts, <100ms)
|
|
33
|
+
2. Any LLM: Skill instructs to run this script (~2s)
|
|
34
|
+
3. Terminal: specweave status --verbose (~500ms)
|
|
35
|
+
|
|
36
|
+
EXAMPLES
|
|
37
|
+
node plugins/specweave/scripts/progress.js
|
|
38
|
+
node plugins/specweave/scripts/progress.js 0045
|
|
39
|
+
specweave status --verbose
|
|
40
|
+
`);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const cwd = process.cwd();
|
|
45
|
+
const incrementsDir = path.join(cwd, '.specweave/increments');
|
|
46
|
+
const args = process.argv.slice(2);
|
|
47
|
+
const specificId = args[0];
|
|
48
|
+
|
|
49
|
+
// Check if increments directory exists
|
|
50
|
+
if (!fs.existsSync(incrementsDir)) {
|
|
51
|
+
console.log('No SpecWeave project found (missing .specweave/increments/)');
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Find increments
|
|
56
|
+
const entries = fs.readdirSync(incrementsDir, { withFileTypes: true });
|
|
57
|
+
const incrementFolders = entries
|
|
58
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('_') && /^\d{4}/.test(e.name))
|
|
59
|
+
.map(e => e.name);
|
|
60
|
+
|
|
61
|
+
if (incrementFolders.length === 0) {
|
|
62
|
+
console.log('No increments found.');
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Parse increment data
|
|
67
|
+
function parseIncrement(folder) {
|
|
68
|
+
const metaPath = path.join(incrementsDir, folder, 'metadata.json');
|
|
69
|
+
const tasksPath = path.join(incrementsDir, folder, 'tasks.md');
|
|
70
|
+
|
|
71
|
+
let metadata = { status: 'unknown' };
|
|
72
|
+
if (fs.existsSync(metaPath)) {
|
|
73
|
+
try {
|
|
74
|
+
metadata = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
75
|
+
} catch {}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let totalTasks = 0;
|
|
79
|
+
let completedTasks = 0;
|
|
80
|
+
|
|
81
|
+
if (fs.existsSync(tasksPath)) {
|
|
82
|
+
const content = fs.readFileSync(tasksPath, 'utf-8');
|
|
83
|
+
const taskMatches = content.match(/### T-\d+/g);
|
|
84
|
+
totalTasks = taskMatches ? taskMatches.length : 0;
|
|
85
|
+
|
|
86
|
+
const completedMatches = content.match(/\*\*Status\*\*:\s*\[x\]/gi);
|
|
87
|
+
completedTasks = completedMatches ? completedMatches.length : 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
id: folder,
|
|
92
|
+
status: metadata.status || 'unknown',
|
|
93
|
+
type: metadata.type || 'feature',
|
|
94
|
+
totalTasks,
|
|
95
|
+
completedTasks,
|
|
96
|
+
percentage: totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// If specific increment requested
|
|
101
|
+
if (specificId) {
|
|
102
|
+
const folder = incrementFolders.find(f => f === specificId || f.startsWith(specificId));
|
|
103
|
+
if (!folder) {
|
|
104
|
+
console.log(`Increment not found: ${specificId}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const inc = parseIncrement(folder);
|
|
109
|
+
const bar = createProgressBar(inc.percentage);
|
|
110
|
+
|
|
111
|
+
console.log(`\n📊 Progress: ${inc.id}\n`);
|
|
112
|
+
console.log(`Status: ${formatStatus(inc.status)}`);
|
|
113
|
+
console.log(`Type: ${inc.type}`);
|
|
114
|
+
console.log(`Tasks: ${inc.completedTasks}/${inc.totalTasks} (${inc.percentage}%)`);
|
|
115
|
+
console.log(`Progress: ${bar}`);
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Show all active increments
|
|
120
|
+
const increments = incrementFolders.map(parseIncrement);
|
|
121
|
+
const active = increments.filter(i => ['active', 'planning', 'in-progress'].includes(i.status));
|
|
122
|
+
const paused = increments.filter(i => i.status === 'paused');
|
|
123
|
+
|
|
124
|
+
console.log('\n📊 Increment Progress\n');
|
|
125
|
+
|
|
126
|
+
if (active.length > 0) {
|
|
127
|
+
console.log(`🔄 Active (${active.length}):`);
|
|
128
|
+
for (const inc of active) {
|
|
129
|
+
const bar = createProgressBar(inc.percentage, 15);
|
|
130
|
+
console.log(` ${inc.id}`);
|
|
131
|
+
console.log(` ${bar} ${inc.completedTasks}/${inc.totalTasks} (${inc.percentage}%)`);
|
|
132
|
+
}
|
|
133
|
+
console.log('');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (paused.length > 0) {
|
|
137
|
+
console.log(`⏸️ Paused (${paused.length}):`);
|
|
138
|
+
for (const inc of paused) {
|
|
139
|
+
console.log(` ${inc.id} - ${inc.percentage}%`);
|
|
140
|
+
}
|
|
141
|
+
console.log('');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (active.length === 0 && paused.length === 0) {
|
|
145
|
+
console.log('No active increments.');
|
|
146
|
+
const completed = increments.filter(i => i.status === 'completed');
|
|
147
|
+
if (completed.length > 0) {
|
|
148
|
+
console.log(`${completed.length} completed increment(s).`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log('💡 For details: /specweave:progress <incrementId>');
|
|
153
|
+
|
|
154
|
+
// Helpers
|
|
155
|
+
function createProgressBar(pct, width = 20) {
|
|
156
|
+
const filled = Math.round((pct / 100) * width);
|
|
157
|
+
const empty = width - filled;
|
|
158
|
+
return `[${'█'.repeat(filled)}${'░'.repeat(empty)}]`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function formatStatus(status) {
|
|
162
|
+
const icons = {
|
|
163
|
+
'active': '🔄 active',
|
|
164
|
+
'planning': '📝 planning',
|
|
165
|
+
'paused': '⏸️ paused',
|
|
166
|
+
'completed': '✅ completed',
|
|
167
|
+
'abandoned': '❌ abandoned'
|
|
168
|
+
};
|
|
169
|
+
return icons[status] || status;
|
|
170
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# read-costs.sh - Pure bash reader for /specweave:costs
|
|
3
|
+
#
|
|
4
|
+
# Shows cost/token tracking dashboard.
|
|
5
|
+
# Reads from pre-computed dashboard cache for <10ms response time.
|
|
6
|
+
#
|
|
7
|
+
# Usage: bash read-costs.sh [incrementId]
|
|
8
|
+
#
|
|
9
|
+
# Compatible with bash 3.x (macOS default)
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
INCREMENT_ID="${1:-}"
|
|
14
|
+
|
|
15
|
+
# Find project root
|
|
16
|
+
PROJECT_ROOT="$PWD"
|
|
17
|
+
while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -d "$PROJECT_ROOT/.specweave" ]]; do
|
|
18
|
+
PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
|
|
19
|
+
done
|
|
20
|
+
|
|
21
|
+
if [[ ! -d "$PROJECT_ROOT/.specweave" ]]; then
|
|
22
|
+
echo "No SpecWeave project found (missing .specweave/)"
|
|
23
|
+
exit 0
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
CACHE_FILE="$PROJECT_ROOT/.specweave/state/dashboard.json"
|
|
27
|
+
SCRIPTS_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
|
28
|
+
|
|
29
|
+
# Check if jq is available
|
|
30
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
31
|
+
echo "❌ jq required for costs command. Install with: brew install jq"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# If cache doesn't exist or is corrupted, rebuild it
|
|
36
|
+
NEED_REBUILD=false
|
|
37
|
+
if [[ ! -f "$CACHE_FILE" ]]; then
|
|
38
|
+
NEED_REBUILD=true
|
|
39
|
+
elif ! jq -e '.' "$CACHE_FILE" >/dev/null 2>&1; then
|
|
40
|
+
# Cache exists but is corrupted (invalid JSON)
|
|
41
|
+
NEED_REBUILD=true
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [[ "$NEED_REBUILD" == "true" ]]; then
|
|
45
|
+
bash "$SCRIPTS_DIR/rebuild-dashboard-cache.sh" --quiet 2>/dev/null || true
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
if [[ ! -f "$CACHE_FILE" ]] || ! jq -e '.' "$CACHE_FILE" >/dev/null 2>&1; then
|
|
49
|
+
echo "❌ Cache unavailable. Try: bash plugins/specweave/scripts/rebuild-dashboard-cache.sh"
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
echo ""
|
|
54
|
+
echo "💰 SpecWeave Cost Dashboard"
|
|
55
|
+
echo ""
|
|
56
|
+
|
|
57
|
+
# Read costs from cache
|
|
58
|
+
TOTAL_TOKENS=$(jq '.costs.totalTokens // 0' "$CACHE_FILE")
|
|
59
|
+
TOTAL_COST=$(jq '.costs.totalCost // 0' "$CACHE_FILE")
|
|
60
|
+
TOTAL_SAVINGS=$(jq '.costs.totalSavings // 0' "$CACHE_FILE")
|
|
61
|
+
|
|
62
|
+
if [[ "$TOTAL_TOKENS" -eq 0 ]] && [[ "$TOTAL_COST" == "0" ]]; then
|
|
63
|
+
echo "📊 No cost data yet"
|
|
64
|
+
echo ""
|
|
65
|
+
echo "Cost tracking starts when you run agents with model hints."
|
|
66
|
+
echo ""
|
|
67
|
+
echo "💡 Tips:"
|
|
68
|
+
echo " • Use ⚡ haiku for simple tasks (3x faster, 20x cheaper)"
|
|
69
|
+
echo " • Use 🧠 sonnet for complex reasoning"
|
|
70
|
+
echo " • Use 💎 opus only for critical decisions"
|
|
71
|
+
echo ""
|
|
72
|
+
echo "Model hints in tasks.md:"
|
|
73
|
+
echo " ### T-001: Setup project structure ⚡"
|
|
74
|
+
echo " ### T-002: Design architecture 🧠"
|
|
75
|
+
exit 0
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# Format numbers
|
|
79
|
+
format_tokens() {
|
|
80
|
+
local tokens=$1
|
|
81
|
+
if [[ "$tokens" -ge 1000000 ]]; then
|
|
82
|
+
echo "$((tokens / 1000000))M"
|
|
83
|
+
elif [[ "$tokens" -ge 1000 ]]; then
|
|
84
|
+
echo "$((tokens / 1000))k"
|
|
85
|
+
else
|
|
86
|
+
echo "$tokens"
|
|
87
|
+
fi
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
format_cost() {
|
|
91
|
+
local cost=$1
|
|
92
|
+
if [[ "${cost%.*}" -ge 100 ]]; then
|
|
93
|
+
printf "\$%.0f" "$cost"
|
|
94
|
+
else
|
|
95
|
+
printf "\$%.2f" "$cost"
|
|
96
|
+
fi
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Display totals
|
|
100
|
+
echo "📈 Totals:"
|
|
101
|
+
echo " Tokens: $(format_tokens "$TOTAL_TOKENS")"
|
|
102
|
+
echo " Cost: $(format_cost "$TOTAL_COST")"
|
|
103
|
+
echo " Savings: $(format_cost "$TOTAL_SAVINGS") (vs all-Sonnet)"
|
|
104
|
+
echo ""
|
|
105
|
+
|
|
106
|
+
# If specific increment requested
|
|
107
|
+
if [[ -n "$INCREMENT_ID" ]]; then
|
|
108
|
+
INC_COSTS=$(jq --arg id "$INCREMENT_ID" '.costs.byIncrement[$id] // empty' "$CACHE_FILE" 2>/dev/null)
|
|
109
|
+
if [[ -n "$INC_COSTS" ]]; then
|
|
110
|
+
INC_TOKENS=$(echo "$INC_COSTS" | jq -r '.tokens // 0')
|
|
111
|
+
INC_COST=$(echo "$INC_COSTS" | jq -r '.cost // 0')
|
|
112
|
+
INC_SAVINGS=$(echo "$INC_COSTS" | jq -r '.savings // 0')
|
|
113
|
+
echo "📦 Increment: $INCREMENT_ID"
|
|
114
|
+
echo " Tokens: $(format_tokens "$INC_TOKENS")"
|
|
115
|
+
echo " Cost: $(format_cost "$INC_COST")"
|
|
116
|
+
echo " Savings: $(format_cost "$INC_SAVINGS")"
|
|
117
|
+
echo ""
|
|
118
|
+
else
|
|
119
|
+
echo "No cost data for increment: $INCREMENT_ID"
|
|
120
|
+
echo ""
|
|
121
|
+
fi
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
# Show top increments by cost
|
|
125
|
+
echo "📊 Cost by Increment (top 5):"
|
|
126
|
+
jq -r '.costs.byIncrement | to_entries | sort_by(-.value.cost) | .[0:5][] |
|
|
127
|
+
" \(.key): $\(.value.cost | tostring | .[0:6])"' "$CACHE_FILE" 2>/dev/null || echo " (no data)"
|
|
128
|
+
echo ""
|
|
129
|
+
|
|
130
|
+
echo "💡 Commands:"
|
|
131
|
+
echo " /specweave:costs <id> View increment costs"
|
|
132
|
+
echo " /specweave:progress View task progress"
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# read-jobs.sh - Pure bash reader for /specweave:jobs
|
|
3
|
+
#
|
|
4
|
+
# Shows current work status (increments) + background jobs + helpful context.
|
|
5
|
+
# Reads from pre-computed dashboard cache for <10ms response time.
|
|
6
|
+
#
|
|
7
|
+
# Usage: bash read-jobs.sh [--all] [--id <jobId>]
|
|
8
|
+
#
|
|
9
|
+
# Compatible with bash 3.x (macOS default)
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
# Parse arguments
|
|
14
|
+
SHOW_ALL=false
|
|
15
|
+
SPECIFIC_ID=""
|
|
16
|
+
while [[ $# -gt 0 ]]; do
|
|
17
|
+
case "$1" in
|
|
18
|
+
--all) SHOW_ALL=true; shift ;;
|
|
19
|
+
--id) SPECIFIC_ID="$2"; shift 2 ;;
|
|
20
|
+
*) shift ;;
|
|
21
|
+
esac
|
|
22
|
+
done
|
|
23
|
+
|
|
24
|
+
# Find project root
|
|
25
|
+
PROJECT_ROOT="$PWD"
|
|
26
|
+
while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -d "$PROJECT_ROOT/.specweave" ]]; do
|
|
27
|
+
PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
|
|
28
|
+
done
|
|
29
|
+
|
|
30
|
+
if [[ ! -d "$PROJECT_ROOT/.specweave" ]]; then
|
|
31
|
+
echo "No SpecWeave project found (missing .specweave/)"
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
CACHE_FILE="$PROJECT_ROOT/.specweave/state/dashboard.json"
|
|
36
|
+
JOBS_FILE="$PROJECT_ROOT/.specweave/state/background-jobs.json"
|
|
37
|
+
SCRIPTS_DIR="$PROJECT_ROOT/plugins/specweave/scripts"
|
|
38
|
+
|
|
39
|
+
# Check if jq is available, fall back to Node if not
|
|
40
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
41
|
+
if [[ -f "$SCRIPTS_DIR/jobs.js" ]]; then
|
|
42
|
+
echo "⚠️ Install jq for instant status commands: brew install jq"
|
|
43
|
+
exec node "$SCRIPTS_DIR/jobs.js" "$@"
|
|
44
|
+
else
|
|
45
|
+
echo "❌ jq not found and no fallback script available"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# ============================================================================
|
|
51
|
+
# If specific job ID requested, show details and exit
|
|
52
|
+
# ============================================================================
|
|
53
|
+
|
|
54
|
+
if [[ -n "$SPECIFIC_ID" ]] && [[ -f "$JOBS_FILE" ]]; then
|
|
55
|
+
JOB=$(jq --arg id "$SPECIFIC_ID" '
|
|
56
|
+
.jobs[] | select(.id == $id or (.id | startswith($id)))
|
|
57
|
+
' "$JOBS_FILE" 2>/dev/null)
|
|
58
|
+
|
|
59
|
+
if [[ -z "$JOB" ]]; then
|
|
60
|
+
echo "Job not found: $SPECIFIC_ID"
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
ID=$(echo "$JOB" | jq -r '.id')
|
|
65
|
+
TYPE=$(echo "$JOB" | jq -r '.type')
|
|
66
|
+
STATUS=$(echo "$JOB" | jq -r '.status')
|
|
67
|
+
STARTED=$(echo "$JOB" | jq -r '.startedAt')
|
|
68
|
+
UPDATED=$(echo "$JOB" | jq -r '.updatedAt')
|
|
69
|
+
CURRENT=$(echo "$JOB" | jq -r '.progress.current // 0')
|
|
70
|
+
TOTAL=$(echo "$JOB" | jq -r '.progress.total // 0')
|
|
71
|
+
ERROR=$(echo "$JOB" | jq -r '.error // empty')
|
|
72
|
+
|
|
73
|
+
if [[ "$TOTAL" -gt 0 ]]; then
|
|
74
|
+
PCT=$((CURRENT * 100 / TOTAL))
|
|
75
|
+
else
|
|
76
|
+
PCT=0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
echo ""
|
|
80
|
+
echo "📦 Job Details: $ID"
|
|
81
|
+
echo ""
|
|
82
|
+
echo "Type: $TYPE"
|
|
83
|
+
echo "Status: $STATUS"
|
|
84
|
+
echo "Started: $STARTED"
|
|
85
|
+
echo "Updated: $UPDATED"
|
|
86
|
+
echo "Progress: $CURRENT/$TOTAL ($PCT%)"
|
|
87
|
+
|
|
88
|
+
if [[ -n "$ERROR" ]]; then
|
|
89
|
+
echo "Error: $ERROR"
|
|
90
|
+
fi
|
|
91
|
+
exit 0
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# ============================================================================
|
|
95
|
+
# SECTION 1: Current Work Status (from dashboard cache)
|
|
96
|
+
# ============================================================================
|
|
97
|
+
|
|
98
|
+
echo ""
|
|
99
|
+
echo "📊 Current Work Status"
|
|
100
|
+
echo "────────────────────────────────────────"
|
|
101
|
+
|
|
102
|
+
# Rebuild cache if needed
|
|
103
|
+
if [[ ! -f "$CACHE_FILE" ]] || ! jq -e '.' "$CACHE_FILE" >/dev/null 2>&1; then
|
|
104
|
+
if [[ -f "$SCRIPTS_DIR/rebuild-dashboard-cache.sh" ]]; then
|
|
105
|
+
bash "$SCRIPTS_DIR/rebuild-dashboard-cache.sh" --quiet 2>/dev/null || true
|
|
106
|
+
fi
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
if [[ -f "$CACHE_FILE" ]] && jq -e '.' "$CACHE_FILE" >/dev/null 2>&1; then
|
|
110
|
+
# Show active increments
|
|
111
|
+
ACTIVE=$(jq -r '
|
|
112
|
+
.increments | to_entries[] |
|
|
113
|
+
select(.value.status == "active" or .value.status == "planning" or .value.status == "in-progress") |
|
|
114
|
+
"\(.key)|\(.value.status)|\(.value.tasks.completed)|\(.value.tasks.total)"
|
|
115
|
+
' "$CACHE_FILE" 2>/dev/null)
|
|
116
|
+
|
|
117
|
+
if [[ -n "$ACTIVE" ]]; then
|
|
118
|
+
echo ""
|
|
119
|
+
echo "🔄 In Progress:"
|
|
120
|
+
while IFS='|' read -r id status completed total; do
|
|
121
|
+
[[ -z "$id" ]] && continue
|
|
122
|
+
if [[ "$total" -gt 0 ]]; then
|
|
123
|
+
pct=$((completed * 100 / total))
|
|
124
|
+
else
|
|
125
|
+
pct=0
|
|
126
|
+
fi
|
|
127
|
+
echo " $id ($status)"
|
|
128
|
+
echo " Tasks: $completed/$total ($pct%)"
|
|
129
|
+
done <<< "$ACTIVE"
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Show paused increments
|
|
133
|
+
PAUSED_INC=$(jq -r '
|
|
134
|
+
.increments | to_entries[] |
|
|
135
|
+
select(.value.status == "paused") |
|
|
136
|
+
"\(.key)|\(.value.tasks.completed)|\(.value.tasks.total)"
|
|
137
|
+
' "$CACHE_FILE" 2>/dev/null)
|
|
138
|
+
|
|
139
|
+
if [[ -n "$PAUSED_INC" ]]; then
|
|
140
|
+
echo ""
|
|
141
|
+
PAUSED_INC_COUNT=$(echo "$PAUSED_INC" | wc -l | tr -d ' ')
|
|
142
|
+
echo "⏸️ Paused Increments ($PAUSED_INC_COUNT):"
|
|
143
|
+
while IFS='|' read -r id completed total; do
|
|
144
|
+
[[ -z "$id" ]] && continue
|
|
145
|
+
if [[ "$total" -gt 0 ]]; then
|
|
146
|
+
pct=$((completed * 100 / total))
|
|
147
|
+
else
|
|
148
|
+
pct=0
|
|
149
|
+
fi
|
|
150
|
+
echo " $id - $pct% done"
|
|
151
|
+
done <<< "$PAUSED_INC"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# Show ready for review
|
|
155
|
+
READY=$(jq -r '
|
|
156
|
+
.increments | to_entries[] |
|
|
157
|
+
select(.value.status == "ready_for_review") |
|
|
158
|
+
.key
|
|
159
|
+
' "$CACHE_FILE" 2>/dev/null)
|
|
160
|
+
|
|
161
|
+
if [[ -n "$READY" ]]; then
|
|
162
|
+
echo ""
|
|
163
|
+
echo "👀 Ready for Review:"
|
|
164
|
+
while read -r id; do
|
|
165
|
+
[[ -z "$id" ]] && continue
|
|
166
|
+
echo " $id"
|
|
167
|
+
done <<< "$READY"
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Summary stats
|
|
171
|
+
TOTAL_INC=$(jq '.summary.total // 0' "$CACHE_FILE")
|
|
172
|
+
ACTIVE_COUNT=$(jq '.summary.active // 0' "$CACHE_FILE")
|
|
173
|
+
COMPLETED_INC_COUNT=$(jq '.summary.completed // 0' "$CACHE_FILE")
|
|
174
|
+
|
|
175
|
+
if [[ -z "$ACTIVE" ]] && [[ -z "$PAUSED_INC" ]] && [[ -z "$READY" ]]; then
|
|
176
|
+
echo ""
|
|
177
|
+
echo " No active increments."
|
|
178
|
+
if [[ "$COMPLETED_INC_COUNT" -gt 0 ]]; then
|
|
179
|
+
echo " $COMPLETED_INC_COUNT increment(s) completed."
|
|
180
|
+
fi
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
echo ""
|
|
184
|
+
echo " Summary: $TOTAL_INC total | $ACTIVE_COUNT active | $COMPLETED_INC_COUNT completed"
|
|
185
|
+
else
|
|
186
|
+
echo ""
|
|
187
|
+
echo " No increment data available (cache not found)."
|
|
188
|
+
echo " Run /specweave:status to rebuild cache."
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
echo ""
|
|
192
|
+
echo "────────────────────────────────────────"
|
|
193
|
+
|
|
194
|
+
# ============================================================================
|
|
195
|
+
# SECTION 2: Background Jobs
|
|
196
|
+
# ============================================================================
|
|
197
|
+
|
|
198
|
+
echo ""
|
|
199
|
+
echo "⚙️ Background Jobs"
|
|
200
|
+
echo "────────────────────────────────────────"
|
|
201
|
+
|
|
202
|
+
# Check if jobs file exists and has jobs
|
|
203
|
+
HAS_JOBS=false
|
|
204
|
+
if [[ -f "$JOBS_FILE" ]] && jq -e '.jobs | length > 0' "$JOBS_FILE" >/dev/null 2>&1; then
|
|
205
|
+
HAS_JOBS=true
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
if [[ "$HAS_JOBS" == "false" ]]; then
|
|
209
|
+
echo ""
|
|
210
|
+
echo " No background jobs."
|
|
211
|
+
echo ""
|
|
212
|
+
echo " Background jobs are created for:"
|
|
213
|
+
echo " • Large issue imports (1000+ items from GitHub/JIRA/ADO)"
|
|
214
|
+
echo " • Multi-repository cloning (umbrella setup)"
|
|
215
|
+
echo " • Brownfield analysis (documentation gap detection)"
|
|
216
|
+
echo ""
|
|
217
|
+
echo " Start jobs with:"
|
|
218
|
+
echo " • /specweave:import-external - Import from external tools"
|
|
219
|
+
echo " • specweave init - May spawn background jobs"
|
|
220
|
+
else
|
|
221
|
+
echo ""
|
|
222
|
+
|
|
223
|
+
# Running jobs
|
|
224
|
+
RUNNING=$(jq -r '.jobs[] | select(.status == "running") | "\(.id)|\(.type)|\(.progress.current)|\(.progress.total)|\(.startedAt)"' "$JOBS_FILE" 2>/dev/null)
|
|
225
|
+
|
|
226
|
+
if [[ -n "$RUNNING" ]]; then
|
|
227
|
+
RUNNING_COUNT=$(echo "$RUNNING" | wc -l | tr -d ' ')
|
|
228
|
+
echo "🔄 Running ($RUNNING_COUNT):"
|
|
229
|
+
while IFS='|' read -r id type current total started; do
|
|
230
|
+
[[ -z "$id" ]] && continue
|
|
231
|
+
if [[ "$total" -gt 0 ]]; then
|
|
232
|
+
pct=$((current * 100 / total))
|
|
233
|
+
else
|
|
234
|
+
pct=0
|
|
235
|
+
fi
|
|
236
|
+
echo " [${id:0:8}] $type"
|
|
237
|
+
echo " Progress: $current/$total ($pct%)"
|
|
238
|
+
done <<< "$RUNNING"
|
|
239
|
+
echo ""
|
|
240
|
+
fi
|
|
241
|
+
|
|
242
|
+
# Paused jobs
|
|
243
|
+
PAUSED=$(jq -r '.jobs[] | select(.status == "paused") | "\(.id)|\(.type)|\(.progress.current)|\(.progress.total)"' "$JOBS_FILE" 2>/dev/null)
|
|
244
|
+
|
|
245
|
+
if [[ -n "$PAUSED" ]]; then
|
|
246
|
+
PAUSED_COUNT=$(echo "$PAUSED" | wc -l | tr -d ' ')
|
|
247
|
+
echo "⏸️ Paused ($PAUSED_COUNT):"
|
|
248
|
+
while IFS='|' read -r id type current total; do
|
|
249
|
+
[[ -z "$id" ]] && continue
|
|
250
|
+
if [[ "$total" -gt 0 ]]; then
|
|
251
|
+
pct=$((current * 100 / total))
|
|
252
|
+
else
|
|
253
|
+
pct=0
|
|
254
|
+
fi
|
|
255
|
+
echo " [${id:0:8}] $type - $pct%"
|
|
256
|
+
done <<< "$PAUSED"
|
|
257
|
+
echo ""
|
|
258
|
+
fi
|
|
259
|
+
|
|
260
|
+
# Failed jobs
|
|
261
|
+
FAILED=$(jq -r '.jobs[] | select(.status == "failed") | "\(.id)|\(.type)|\(.error // "unknown")"' "$JOBS_FILE" 2>/dev/null)
|
|
262
|
+
|
|
263
|
+
if [[ -n "$FAILED" ]]; then
|
|
264
|
+
FAILED_COUNT=$(echo "$FAILED" | wc -l | tr -d ' ')
|
|
265
|
+
echo "❌ Failed ($FAILED_COUNT):"
|
|
266
|
+
while IFS='|' read -r id type error; do
|
|
267
|
+
[[ -z "$id" ]] && continue
|
|
268
|
+
echo " [${id:0:8}] $type"
|
|
269
|
+
if [[ -n "$error" ]] && [[ "$error" != "null" ]]; then
|
|
270
|
+
echo " Error: $error"
|
|
271
|
+
fi
|
|
272
|
+
done <<< "$FAILED"
|
|
273
|
+
echo ""
|
|
274
|
+
fi
|
|
275
|
+
|
|
276
|
+
# Completed jobs (only with --all)
|
|
277
|
+
if [[ "$SHOW_ALL" == "true" ]]; then
|
|
278
|
+
COMPLETED=$(jq -r '.jobs[] | select(.status == "completed") | "\(.id)|\(.type)|\(.progress.current)"' "$JOBS_FILE" 2>/dev/null)
|
|
279
|
+
|
|
280
|
+
if [[ -n "$COMPLETED" ]]; then
|
|
281
|
+
COMPLETED_COUNT=$(echo "$COMPLETED" | wc -l | tr -d ' ')
|
|
282
|
+
echo "✅ Completed ($COMPLETED_COUNT):"
|
|
283
|
+
COUNT=0
|
|
284
|
+
while IFS='|' read -r id type items; do
|
|
285
|
+
[[ -z "$id" ]] && continue
|
|
286
|
+
if [[ $COUNT -lt 10 ]]; then
|
|
287
|
+
echo " [${id:0:8}] $type - $items items"
|
|
288
|
+
COUNT=$((COUNT + 1))
|
|
289
|
+
fi
|
|
290
|
+
done <<< "$COMPLETED"
|
|
291
|
+
if [[ $COMPLETED_COUNT -gt 10 ]]; then
|
|
292
|
+
echo " ... and $((COMPLETED_COUNT - 10)) more"
|
|
293
|
+
fi
|
|
294
|
+
echo ""
|
|
295
|
+
fi
|
|
296
|
+
fi
|
|
297
|
+
|
|
298
|
+
# Summary if no active jobs
|
|
299
|
+
RUNNING_COUNT=$(jq '[.jobs[] | select(.status == "running")] | length' "$JOBS_FILE" 2>/dev/null || echo "0")
|
|
300
|
+
PAUSED_COUNT=$(jq '[.jobs[] | select(.status == "paused")] | length' "$JOBS_FILE" 2>/dev/null || echo "0")
|
|
301
|
+
FAILED_COUNT=$(jq '[.jobs[] | select(.status == "failed")] | length' "$JOBS_FILE" 2>/dev/null || echo "0")
|
|
302
|
+
COMPLETED_COUNT=$(jq '[.jobs[] | select(.status == "completed")] | length' "$JOBS_FILE" 2>/dev/null || echo "0")
|
|
303
|
+
|
|
304
|
+
if [[ "$RUNNING_COUNT" -eq 0 ]] && [[ "$PAUSED_COUNT" -eq 0 ]] && [[ "$FAILED_COUNT" -eq 0 ]]; then
|
|
305
|
+
if [[ "$COMPLETED_COUNT" -gt 0 ]]; then
|
|
306
|
+
echo " No active jobs. $COMPLETED_COUNT completed (use --all to see)."
|
|
307
|
+
fi
|
|
308
|
+
fi
|
|
309
|
+
fi
|
|
310
|
+
|
|
311
|
+
# ============================================================================
|
|
312
|
+
# SECTION 3: Commands Help
|
|
313
|
+
# ============================================================================
|
|
314
|
+
|
|
315
|
+
echo ""
|
|
316
|
+
echo "────────────────────────────────────────"
|
|
317
|
+
echo ""
|
|
318
|
+
echo "💡 Commands:"
|
|
319
|
+
echo " /specweave:do Execute current tasks"
|
|
320
|
+
echo " /specweave:progress Show task progress details"
|
|
321
|
+
echo " /specweave:done <id> Close increment"
|
|
322
|
+
echo " /specweave:jobs --id <id> View background job details"
|
|
323
|
+
echo " /specweave:jobs --all Show completed jobs"
|
|
324
|
+
echo ""
|