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.
Files changed (242) hide show
  1. package/CLAUDE.md +176 -2
  2. package/README.md +22 -0
  3. package/bin/specweave.js +18 -1
  4. package/dist/src/cli/commands/cache.d.ts +17 -0
  5. package/dist/src/cli/commands/cache.d.ts.map +1 -0
  6. package/dist/src/cli/commands/cache.js +126 -0
  7. package/dist/src/cli/commands/cache.js.map +1 -0
  8. package/dist/src/cli/commands/init.js +1 -1
  9. package/dist/src/cli/commands/init.js.map +1 -1
  10. package/dist/src/cli/commands/plan/increment-detector.js +2 -2
  11. package/dist/src/cli/commands/plan/increment-detector.js.map +1 -1
  12. package/dist/src/cli/commands/sync-spec-commits.js +1 -1
  13. package/dist/src/cli/commands/sync-spec-commits.js.map +1 -1
  14. package/dist/src/cli/commands/sync-specs.js +2 -2
  15. package/dist/src/cli/commands/sync-specs.js.map +1 -1
  16. package/dist/src/cli/helpers/github/increment-profile-selector.js +1 -1
  17. package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
  18. package/dist/src/cli/workers/living-docs-worker.js +66 -1
  19. package/dist/src/cli/workers/living-docs-worker.js.map +1 -1
  20. package/dist/src/config/types.d.ts +203 -1208
  21. package/dist/src/config/types.d.ts.map +1 -1
  22. package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -1
  23. package/dist/src/core/discrepancy/increment-generator.js +5 -2
  24. package/dist/src/core/discrepancy/increment-generator.js.map +1 -1
  25. package/dist/src/core/external-tools/external-items-counter.d.ts +62 -0
  26. package/dist/src/core/external-tools/external-items-counter.d.ts.map +1 -0
  27. package/dist/src/core/external-tools/external-items-counter.js +206 -0
  28. package/dist/src/core/external-tools/external-items-counter.js.map +1 -0
  29. package/dist/src/core/external-tools/external-items-display.d.ts +39 -0
  30. package/dist/src/core/external-tools/external-items-display.d.ts.map +1 -0
  31. package/dist/src/core/external-tools/external-items-display.js +185 -0
  32. package/dist/src/core/external-tools/external-items-display.js.map +1 -0
  33. package/dist/src/core/external-tools/index.d.ts +8 -0
  34. package/dist/src/core/external-tools/index.d.ts.map +1 -0
  35. package/dist/src/core/external-tools/index.js +8 -0
  36. package/dist/src/core/external-tools/index.js.map +1 -0
  37. package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts +39 -0
  38. package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts.map +1 -0
  39. package/dist/src/core/external-tools/providers/ado-items-adapter.js +188 -0
  40. package/dist/src/core/external-tools/providers/ado-items-adapter.js.map +1 -0
  41. package/dist/src/core/external-tools/providers/github-items-adapter.d.ts +38 -0
  42. package/dist/src/core/external-tools/providers/github-items-adapter.d.ts.map +1 -0
  43. package/dist/src/core/external-tools/providers/github-items-adapter.js +136 -0
  44. package/dist/src/core/external-tools/providers/github-items-adapter.js.map +1 -0
  45. package/dist/src/core/external-tools/providers/index.d.ts +7 -0
  46. package/dist/src/core/external-tools/providers/index.d.ts.map +1 -0
  47. package/dist/src/core/external-tools/providers/index.js +7 -0
  48. package/dist/src/core/external-tools/providers/index.js.map +1 -0
  49. package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts +42 -0
  50. package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts.map +1 -0
  51. package/dist/src/core/external-tools/providers/jira-items-adapter.js +153 -0
  52. package/dist/src/core/external-tools/providers/jira-items-adapter.js.map +1 -0
  53. package/dist/src/core/external-tools/types.d.ts +78 -0
  54. package/dist/src/core/external-tools/types.d.ts.map +1 -0
  55. package/dist/src/core/external-tools/types.js +19 -0
  56. package/dist/src/core/external-tools/types.js.map +1 -0
  57. package/dist/src/core/increment/duplicate-detector.js +2 -2
  58. package/dist/src/core/increment/duplicate-detector.js.map +1 -1
  59. package/dist/src/core/increment/increment-archiver.d.ts +24 -0
  60. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
  61. package/dist/src/core/increment/increment-archiver.js +59 -2
  62. package/dist/src/core/increment/increment-archiver.js.map +1 -1
  63. package/dist/src/core/increment/increment-status.js +2 -2
  64. package/dist/src/core/increment/increment-status.js.map +1 -1
  65. package/dist/src/core/increment/increment-utils.d.ts +98 -37
  66. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  67. package/dist/src/core/increment/increment-utils.js +119 -68
  68. package/dist/src/core/increment/increment-utils.js.map +1 -1
  69. package/dist/src/core/increment/metadata-validator.js +1 -1
  70. package/dist/src/core/increment/metadata-validator.js.map +1 -1
  71. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
  72. package/dist/src/core/increment/status-change-sync-trigger.js +4 -0
  73. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
  74. package/dist/src/core/living-docs/feature-id-manager.js +1 -1
  75. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
  76. package/dist/src/core/living-docs/hierarchy-mapper.js +3 -3
  77. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
  78. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts +18 -0
  79. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -0
  80. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +247 -0
  81. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -0
  82. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts +15 -0
  83. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -0
  84. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +138 -0
  85. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -0
  86. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts +24 -0
  87. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts.map +1 -0
  88. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js +198 -0
  89. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js.map +1 -0
  90. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts +17 -0
  91. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts.map +1 -0
  92. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js +241 -0
  93. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js.map +1 -0
  94. package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts +28 -0
  95. package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts.map +1 -0
  96. package/dist/src/core/living-docs/intelligent-analyzer/index.js +197 -0
  97. package/dist/src/core/living-docs/intelligent-analyzer/index.js.map +1 -0
  98. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +18 -0
  99. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -0
  100. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +154 -0
  101. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -0
  102. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts +42 -0
  103. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts.map +1 -0
  104. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js +343 -0
  105. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js.map +1 -0
  106. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +146 -0
  107. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -0
  108. package/dist/src/core/living-docs/intelligent-analyzer/types.js +7 -0
  109. package/dist/src/core/living-docs/intelligent-analyzer/types.js.map +1 -0
  110. package/dist/src/core/living-docs/living-docs-sync.d.ts +5 -0
  111. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  112. package/dist/src/core/living-docs/living-docs-sync.js +36 -2
  113. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  114. package/dist/src/core/llm/providers/azure-openai-provider.d.ts.map +1 -1
  115. package/dist/src/core/llm/providers/azure-openai-provider.js +1 -0
  116. package/dist/src/core/llm/providers/azure-openai-provider.js.map +1 -1
  117. package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
  118. package/dist/src/core/llm/providers/bedrock-provider.js +2 -0
  119. package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
  120. package/dist/src/core/llm/providers/openai-provider.d.ts.map +1 -1
  121. package/dist/src/core/llm/providers/openai-provider.js +1 -0
  122. package/dist/src/core/llm/providers/openai-provider.js.map +1 -1
  123. package/dist/src/core/llm/providers/vertex-ai-provider.d.ts.map +1 -1
  124. package/dist/src/core/llm/providers/vertex-ai-provider.js +1 -0
  125. package/dist/src/core/llm/providers/vertex-ai-provider.js.map +1 -1
  126. package/dist/src/core/sync/spec-increment-mapper.js +3 -3
  127. package/dist/src/core/sync/spec-increment-mapper.js.map +1 -1
  128. package/dist/src/importers/item-converter.d.ts +25 -0
  129. package/dist/src/importers/item-converter.d.ts.map +1 -1
  130. package/dist/src/importers/item-converter.js +135 -5
  131. package/dist/src/importers/item-converter.js.map +1 -1
  132. package/dist/src/init/architecture/types.d.ts +33 -140
  133. package/dist/src/init/architecture/types.d.ts.map +1 -1
  134. package/dist/src/init/compliance/types.d.ts +30 -27
  135. package/dist/src/init/compliance/types.d.ts.map +1 -1
  136. package/dist/src/init/repo/types.d.ts +11 -34
  137. package/dist/src/init/repo/types.d.ts.map +1 -1
  138. package/dist/src/init/research/src/config/types.d.ts +15 -82
  139. package/dist/src/init/research/src/config/types.d.ts.map +1 -1
  140. package/dist/src/init/research/types.d.ts +38 -93
  141. package/dist/src/init/research/types.d.ts.map +1 -1
  142. package/dist/src/init/team/types.d.ts +4 -42
  143. package/dist/src/init/team/types.d.ts.map +1 -1
  144. package/dist/src/types/dashboard-cache.d.ts +181 -0
  145. package/dist/src/types/dashboard-cache.d.ts.map +1 -0
  146. package/dist/src/types/dashboard-cache.js +65 -0
  147. package/dist/src/types/dashboard-cache.js.map +1 -0
  148. package/dist/src/utils/docs-validator.d.ts +131 -0
  149. package/dist/src/utils/docs-validator.d.ts.map +1 -0
  150. package/dist/src/utils/docs-validator.js +529 -0
  151. package/dist/src/utils/docs-validator.js.map +1 -0
  152. package/dist/src/utils/feature-id-collision.js +1 -1
  153. package/dist/src/utils/feature-id-collision.js.map +1 -1
  154. package/dist/src/utils/html-to-mdx.d.ts +1 -0
  155. package/dist/src/utils/html-to-mdx.d.ts.map +1 -1
  156. package/dist/src/utils/html-to-mdx.js +43 -5
  157. package/dist/src/utils/html-to-mdx.js.map +1 -1
  158. package/package.json +1 -5
  159. package/plugins/specweave/agents/pm/AGENT.md +10 -7
  160. package/plugins/specweave/commands/specweave-archive-features.md +5 -7
  161. package/plugins/specweave/commands/specweave-archive.md +2 -1
  162. package/plugins/specweave/commands/specweave-do.md +35 -1
  163. package/plugins/specweave/commands/specweave-done.md +96 -0
  164. package/plugins/specweave/commands/specweave-external.md +150 -0
  165. package/plugins/specweave/commands/specweave-import-external.md +45 -18
  166. package/plugins/specweave/commands/specweave-increment.md +331 -33
  167. package/plugins/specweave/commands/specweave-jobs.md +2 -2
  168. package/plugins/specweave/commands/specweave-progress.md +4 -4
  169. package/plugins/specweave/commands/specweave-restore-feature.md +5 -4
  170. package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
  171. package/plugins/specweave/commands/specweave-sync-specs.md +216 -322
  172. package/plugins/specweave/commands/specweave-validate-features.md +13 -8
  173. package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
  174. package/plugins/specweave/hooks/hooks.json +33 -4
  175. package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
  176. package/plugins/specweave/hooks/lib/common-setup.sh +375 -0
  177. package/plugins/specweave/hooks/lib/crash-prevention.sh +336 -0
  178. package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
  179. package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
  180. package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
  181. package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
  182. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
  183. package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
  184. package/plugins/specweave/hooks/post-task-completion.sh +4 -23
  185. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
  186. package/plugins/specweave/hooks/pre-command-deduplication.sh +1 -6
  187. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
  188. package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
  189. package/plugins/specweave/hooks/pre-task-completion.sh +8 -37
  190. package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
  191. package/plugins/specweave/hooks/pre-tool-use.sh +2 -11
  192. package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
  193. package/plugins/specweave/hooks/universal/dispatcher.mjs +135 -42
  194. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +183 -0
  195. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
  196. package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
  197. package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
  198. package/plugins/specweave/hooks/user-prompt-submit.sh +140 -38
  199. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
  200. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +12 -0
  201. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +89 -0
  202. package/plugins/specweave/hooks/v2/guards/bash-file-guard.sh +211 -0
  203. package/plugins/specweave/hooks/v2/guards/bash-file-guard.test.sh +163 -0
  204. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +26 -28
  205. package/plugins/specweave/hooks/v2/guards/features-folder-guard.sh +50 -0
  206. package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +2 -2
  207. package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -1
  208. package/plugins/specweave/scripts/README.md +166 -0
  209. package/plugins/specweave/scripts/cleanup-state.sh +142 -0
  210. package/plugins/specweave/scripts/force-kill.sh +142 -0
  211. package/plugins/specweave/scripts/jobs.js +171 -0
  212. package/plugins/specweave/scripts/progress.js +170 -0
  213. package/plugins/specweave/scripts/read-costs.sh +132 -0
  214. package/plugins/specweave/scripts/read-jobs.sh +324 -0
  215. package/plugins/specweave/scripts/read-progress.sh +185 -0
  216. package/plugins/specweave/scripts/read-status.sh +146 -0
  217. package/plugins/specweave/scripts/read-workflow.sh +173 -0
  218. package/plugins/specweave/scripts/rebuild-dashboard-cache.sh +327 -0
  219. package/plugins/specweave/scripts/session-watchdog.sh +192 -0
  220. package/plugins/specweave/scripts/status.js +154 -0
  221. package/plugins/specweave/scripts/update-dashboard-cache.sh +281 -0
  222. package/plugins/specweave/skills/increment-planner/SKILL.md +333 -24
  223. package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +17 -9
  224. package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +6 -2
  225. package/plugins/specweave/skills/instant-status/SKILL.md +70 -0
  226. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
  227. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
  228. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  229. package/plugins/specweave-docs/commands/build.md +32 -4
  230. package/plugins/specweave-docs/commands/preview.md +43 -1
  231. package/plugins/specweave-docs/commands/validate.md +250 -0
  232. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1262 -626
  233. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
  234. package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
  235. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
  236. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
  237. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1254 -939
  238. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
  239. package/plugins/specweave/hooks/post-edit-spec.sh +0 -265
  240. package/plugins/specweave/hooks/post-write-spec.sh +0 -267
  241. package/plugins/specweave/hooks/pre-edit-spec.sh +0 -151
  242. 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 ""