bigpowers 2.81.0 → 2.82.0

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/.pi/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.81.0",
3
+ "version": "2.82.0",
4
4
  "description": "80 skills — 73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "keywords": [
6
6
  "pi-package"
package/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ # [2.82.0](https://github.com/danielvm-git/bigpowers/compare/v2.81.0...v2.82.0) (2026-07-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **e55:** add gemini configuration to extension manifest for AGY CLI discovery ([8c717db](https://github.com/danielvm-git/bigpowers/commit/8c717db2bb85126adcab02354f5ca45da8482b4c))
7
+ * **plan-consistency-check:** stop treating story deliverables as specs ([8d9814a](https://github.com/danielvm-git/bigpowers/commit/8d9814a5ce09e8b8ce563accb785f109dc55b56e))
8
+
9
+
10
+ ### Features
11
+
12
+ * **installer:** add interactive setup with BMAD-polished UI ([5ba8da8](https://github.com/danielvm-git/bigpowers/commit/5ba8da851987ac6e856a6efee6e2729d0fab3ec7))
13
+
1
14
  # [2.81.0](https://github.com/danielvm-git/bigpowers/compare/v2.80.0...v2.81.0) (2026-07-23)
2
15
 
3
16
 
package/CLAUDE.md CHANGED
@@ -2,11 +2,18 @@
2
2
  # story: e51s05
3
3
  # story: e45s22
4
4
  # story: e45s23
5
+ # story: e55s03
5
6
 
6
7
  # bigpowers — Claude Code
7
8
 
8
9
  Read CONVENTIONS.md before any GitHub or git operation.
9
10
 
11
+ [`constitution.md`](constitution.md) is a consolidated entry point synthesizing
12
+ this project's doctrine (this file, CONVENTIONS.md, docs/PRINCIPLES.md,
13
+ docs/references/*.md) into bigspec's B0-B10 + Capstone blocks, with citations
14
+ back to the fuller text. It's a starting point for a reader, not a
15
+ replacement — this file remains fully authoritative for its own content today.
16
+
10
17
  <!-- BEGIN bigpowers:context-routing -->
11
18
  ## Context Routing
12
19
 
package/CONVENTIONS.md CHANGED
@@ -10,9 +10,17 @@
10
10
  # story: e45s36
11
11
  # story: e27s01
12
12
  # story: e29s03
13
+ # story: e54s03
14
+ # story: e55s03
13
15
 
14
16
  # Conventions
15
17
 
18
+ [`constitution.md`](constitution.md) is a consolidated entry point synthesizing
19
+ this project's doctrine (this file, CLAUDE.md, docs/PRINCIPLES.md,
20
+ docs/references/*.md) into bigspec's B0-B10 + Capstone blocks, with citations
21
+ back to the fuller text below. It's a starting point for a reader, not a
22
+ replacement — this file remains fully authoritative for its own content today.
23
+
16
24
  ## Conventional Commits & Semantic Versioning
17
25
 
18
26
  All changes to this repository MUST follow the [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/) specification. Versioning MUST strictly adhere to [Semantic Versioning 2.0.0](https://semver.org/).
@@ -386,6 +394,44 @@ This story (e53s02) builds the mechanism only; it creates no real tombstone stub
386
394
  itself, so the live skill count doesn't move yet. The first real use is expected in
387
395
  e56 (skill reclassification/merges).
388
396
 
397
+ ## Catalog Freeze (e54-e59 migration)
398
+
399
+ The 80-skill catalog is frozen as of `specs/tech-architecture/CATALOG-BASELINE-<date>.yaml`
400
+ (e54s01) so e56's reclassification work (80 skills → ~28 procedures) has a stable
401
+ starting point instead of a moving target. `bash scripts/check-catalog-drift.sh`
402
+ (e54s02) diffs the live catalog against that baseline on every Preflight run and
403
+ prints `WARNING:` lines for drift — it is advisory only (always exits 0) and never
404
+ blocks Preflight or CI.
405
+
406
+ **Frozen (triggers a drift warning):**
407
+ - Adding a new `skills/<name>/SKILL.md` directory
408
+ - Structural changes to an existing skill's `phase`, `effort`, or `model` frontmatter
409
+ fields
410
+
411
+ **Not frozen (no warning; proceed as normal):**
412
+ - Bug fixes within an existing skill's existing shape
413
+ - `description:` edits
414
+ - Any other content fix that doesn't touch `phase`/`effort`/`model`
415
+
416
+ **Exit criterion:** the freeze ends when e56 (reclassify-catalog) merges. e56's
417
+ completion is the unfreeze event itself — there is no calendar date, and no other
418
+ story or action lifts the freeze early.
419
+
420
+ **Exception marker:** a change that is genuinely unrelated to the migration (e.g. an
421
+ urgent fix that happens to touch a frozen field) can suppress its own drift warning
422
+ by adding a comment containing the literal string `freeze-exception` to the affected
423
+ `SKILL.md`, for example:
424
+
425
+ ```
426
+ <!-- freeze-exception: urgent security fix, unrelated to the e54-e59 migration -->
427
+ ```
428
+
429
+ `scripts/check-catalog-drift.sh` checks for this exact substring — it must remain
430
+ byte-identical between this document and the script, or the exception path silently
431
+ stops working. Use it sparingly: it should be a marker for something a human decided
432
+ was safe to change during the freeze, not a way to permanently silence the gate for a
433
+ skill that should just wait until e56.
434
+
389
435
  ## File-Size Exceptions
390
436
 
391
437
  The 300-line file cap exists to ensure files fit in a single agent context
package/bin/bigpowers.js CHANGED
@@ -32,21 +32,17 @@ function run(cmd, cwd = ROOT) {
32
32
  const cmd = process.argv[2];
33
33
 
34
34
  if (cmd === 'setup' || cmd === 'install') {
35
- console.log(`🚀 bigpowers v${pkg.version} — setting up...\n`);
36
- run('bash scripts/sync-skills.sh');
37
- run('bash scripts/install.sh');
38
- console.log(`\n✅ bigpowers v${pkg.version} setup complete!`);
39
- console.log(' Skills installed in ~/.claude/skills/');
40
- console.log(' Run again anytime to update: bigpowers setup\n');
41
- process.exit(0);
35
+ // Delegate to interactive installer
36
+ const setupScript = path.join(ROOT, 'bin', 'setup.js');
37
+ require(setupScript);
38
+ return;
42
39
  }
43
40
 
44
41
  if (cmd === 'update') {
45
- console.log(`🔄 Updating bigpowers v${pkg.version}...\n`);
46
- run('bash scripts/sync-skills.sh');
47
- run('bash scripts/install.sh');
48
- console.log(`\n✅ bigpowers v${pkg.version} updated!\n`);
49
- process.exit(0);
42
+ // Delegate to interactive installer (same as setup)
43
+ const setupScript = path.join(ROOT, 'bin', 'setup.js');
44
+ require(setupScript);
45
+ return;
50
46
  }
51
47
 
52
48
  if (cmd === 'status') {
package/bin/setup.js ADDED
@@ -0,0 +1,288 @@
1
+ #!/usr/bin/env node
2
+ // bigpowers setup — interactive installer
3
+ // Combines GSD simplicity with BMAD visual polish.
4
+
5
+ const { execSync } = require('child_process');
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const { installGlobal, installLocal, uninstallTool, detectExistingInstall } = require('../scripts/lib/install-helpers');
9
+
10
+ const ROOT = path.resolve(path.dirname(__filename), '..');
11
+ const pkg = require(path.join(ROOT, 'package.json'));
12
+
13
+ // ── ANSI helpers ─────────────────────────────────────────────────────────────
14
+ const c = {
15
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
16
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
17
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
18
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
19
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
20
+ };
21
+
22
+ // ── ASCII banner ─────────────────────────────────────────────────────────────
23
+ const BANNER = `
24
+ ${c.cyan('╔════════════════════════════════════════════════════════════════════════════╗')}
25
+ ${c.cyan('║')} ${c.cyan('║')}
26
+ ${c.cyan('║')} ${c.bold(c.cyan('██████╗ ██╗ ██████╗ ██████╗ ██████╗ █ █ ███████╗██████╗ ███████╗'))} ${c.cyan('║')}
27
+ ${c.cyan('║')} ${c.bold(c.cyan('██╔══██╗██║██╔════╝ ██╔══██╗██╔═══██╗█ █ ██╔════╝██╔══██╗██╔════╝'))} ${c.cyan('║')}
28
+ ${c.cyan('║')} ${c.bold(c.cyan('██████╔╝██║██║ ███╗██████╔╝██║ ██║█ ██ █ █████╗ ██████╔╝███████╗'))} ${c.cyan('║')}
29
+ ${c.cyan('║')} ${c.bold(c.cyan('██╔══██╗██║██║ ██║██╔═══╝ ██║ ██║█ ████ █ ██╔══╝ ██╔══██╗╚════██║'))} ${c.cyan('║')}
30
+ ${c.cyan('║')} ${c.bold(c.cyan('██████╔╝██║╚██████╔╝██║ ╚██████╔╝███ ███ ███████╗██║ ██║███████║'))} ${c.cyan('║')}
31
+ ${c.cyan('║')} ${c.bold(c.cyan('╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝'))} ${c.cyan('║')}
32
+ ${c.cyan('║')} ${c.cyan('║')}
33
+ ${c.cyan('║')} ${c.dim('Spec-Driven & Test-First Skills for Solo Developers')} ${c.cyan('║')}
34
+ ${c.cyan('║')} ${c.dim(`v${pkg.version}`)} ${c.cyan('║')}
35
+ ${c.cyan('╚════════════════════════════════════════════════════════════════════════════╝')}
36
+ `;
37
+
38
+ // ── Tool definitions ─────────────────────────────────────────────────────────
39
+ const TOOLS = [
40
+ { id: 'claude', name: 'Claude Code', globalPath: '~/.claude', localPath: '.claude' },
41
+ { id: 'antigravity', name: 'Antigravity', globalPath: '~/.gemini/antigravity', localPath: '.gemini/antigravity' },
42
+ { id: 'augment', name: 'Augment', globalPath: '~/.augment', localPath: '.augment' },
43
+ { id: 'cline', name: 'Cline', globalPath: '.clinerules', localPath: '.clinerules' },
44
+ { id: 'codebuddy', name: 'CodeBuddy', globalPath: '~/.codebuddy', localPath: '.codebuddy' },
45
+ { id: 'codex', name: 'Codex', globalPath: '~/.codex', localPath: '.codex' },
46
+ { id: 'copilot', name: 'Copilot', globalPath: '~/.copilot', localPath: '.copilot' },
47
+ { id: 'cursor', name: 'Cursor', globalPath: '~/.cursor', localPath: '.cursor' },
48
+ { id: 'gemini', name: 'Gemini', globalPath: '~/.gemini', localPath: '.gemini' },
49
+ { id: 'hermes', name: 'Hermes Agent', globalPath: '~/.hermes', localPath: '.hermes' },
50
+ { id: 'kilo', name: 'Kilo', globalPath: '~/.config/kilo', localPath: '.config/kilo' },
51
+ { id: 'opencode', name: 'OpenCode', globalPath: '~/.config/opencode', localPath: '.config/opencode' },
52
+ { id: 'qwen', name: 'Qwen Code', globalPath: '~/.qwen', localPath: '.qwen' },
53
+ { id: 'trae', name: 'Trae', globalPath: '~/.trae', localPath: '.trae' },
54
+ { id: 'windsurf', name: 'Windsurf', globalPath: '~/.codeium/windsurf', localPath: '.codeium/windsurf' },
55
+ ];
56
+ const ALL_ID = '__all__';
57
+ const SUPPORTED_IDS = new Set(['claude', 'gemini', 'pi', 'cursor', 'codex']);
58
+ const UNSUPPORTED_HINT = '(TODO)';
59
+
60
+ // ── clack helpers (lazy ESM import from CJS) ─────────────────────────────────
61
+ let _clack;
62
+ async function clack() {
63
+ if (!_clack) _clack = await import('@clack/prompts');
64
+ return _clack;
65
+ }
66
+
67
+ function sleep(ms) {
68
+ return new Promise((r) => setTimeout(r, ms));
69
+ }
70
+
71
+ function runInherited(cmd) {
72
+ execSync(cmd, { cwd: ROOT, stdio: 'inherit' });
73
+ }
74
+
75
+
76
+
77
+ // ── Uninstall flow ──────────────────────────────────────────────────────────
78
+ async function handleUninstall() {
79
+ const { multiselect: ms, confirm: cf, spinner: sp, outro: ot, isCancel: ic } = await clack();
80
+
81
+ const toolOptions = TOOLS.filter((t) => SUPPORTED_IDS.has(t.id)).map((tool) => {
82
+ return { value: tool.id, label: tool.name, hint: `(${tool.globalPath})` };
83
+ });
84
+
85
+ const selectedToolIds = await ms({
86
+ message: 'Uninstall from which tools?',
87
+ options: toolOptions,
88
+ initialValues: ['claude'],
89
+ required: true,
90
+ });
91
+
92
+ if (ic(selectedToolIds)) {
93
+ ot('Cancelled.');
94
+ process.exit(0);
95
+ }
96
+
97
+ const yes = await cf({
98
+ message: `Remove symlinks from ${selectedToolIds.length} tool${selectedToolIds.length > 1 ? 's' : ''}?`,
99
+ initialValue: true,
100
+ });
101
+
102
+ if (!yes || ic(yes)) {
103
+ ot('Cancelled.');
104
+ process.exit(0);
105
+ }
106
+
107
+ const s = await sp();
108
+ s.start('Removing...');
109
+
110
+ const results = [];
111
+ for (const toolId of selectedToolIds) {
112
+ const tool = TOOLS.find((t) => t.id === toolId);
113
+ try {
114
+ uninstallTool(toolId, ROOT);
115
+ results.push({ name: tool.name, ok: true });
116
+ } catch (err) {
117
+ results.push({ name: tool.name, ok: false, error: err.message });
118
+ }
119
+ }
120
+
121
+ s.stop('Done.');
122
+
123
+ console.log('');
124
+ for (const r of results) {
125
+ const icon = r.ok ? c.green('✓') : c.red('✗');
126
+ const detail = r.ok ? c.dim('removed') : c.red(r.error);
127
+ console.log(` ${icon} ${r.name} — ${detail}`);
128
+ }
129
+ console.log('');
130
+
131
+ ot('Uninstall complete.');
132
+ }
133
+
134
+ // ── Main ─────────────────────────────────────────────────────────────────────
135
+ async function main() {
136
+ const { intro, outro, select, multiselect, spinner, confirm, isCancel } = await clack();
137
+
138
+ console.log(BANNER);
139
+ intro(c.bold(`bigpowers v${pkg.version}`));
140
+
141
+ // ── Step 0: Detect existing install ────────────────────────────────────
142
+ const hasExisting = detectExistingInstall();
143
+ let mode = 'install';
144
+
145
+ if (hasExisting) {
146
+ mode = await select({
147
+ message: 'Existing installation detected. How would you like to proceed?',
148
+ options: [
149
+ { value: 'install', label: 'Setup / Update', hint: '(reinstall or add tools)' },
150
+ { value: 'uninstall', label: 'Uninstall', hint: '(remove symlinks and hooks)' },
151
+ ],
152
+ });
153
+
154
+ if (isCancel(mode)) {
155
+ outro('Cancelled.');
156
+ process.exit(0);
157
+ }
158
+ }
159
+
160
+ if (mode === 'uninstall') {
161
+ await handleUninstall(clack);
162
+ return;
163
+ }
164
+
165
+ // ── Step 1: Global vs Local ──────────────────────────────────────────────
166
+ const installMode = await select({
167
+ message: 'Where would you like to install?',
168
+ options: [
169
+ { value: 'global', label: 'Global', hint: '(~/.claude/skills/) — available in all projects' },
170
+ { value: 'local', label: 'Local', hint: '(./.claude/skills/) — this project only' },
171
+ ],
172
+ });
173
+
174
+ if (isCancel(installMode)) {
175
+ outro('Setup cancelled.');
176
+ process.exit(0);
177
+ }
178
+
179
+ // ── Step 2: Tool selection ─────────────────────────────────────────────
180
+ const toolOptions = TOOLS.map((tool) => {
181
+ const p = installMode === 'global' ? tool.globalPath : tool.localPath;
182
+ const supported = SUPPORTED_IDS.has(tool.id);
183
+ return {
184
+ value: tool.id,
185
+ label: supported ? tool.name : c.dim(tool.name),
186
+ hint: supported ? `(${p})` : c.dim(`${UNSUPPORTED_HINT} ${p}`),
187
+ };
188
+ });
189
+
190
+ let selectedToolIds = await multiselect({
191
+ message: 'Install for which tools?',
192
+ options: toolOptions,
193
+ initialValues: ['claude'],
194
+ required: true,
195
+ });
196
+
197
+ if (isCancel(selectedToolIds)) {
198
+ outro('Setup cancelled.');
199
+ process.exit(0);
200
+ }
201
+
202
+ // Filter out TODO tools — they can't be installed yet
203
+ const selectedTools = selectedToolIds.filter((id) => SUPPORTED_IDS.has(id));
204
+ const todoSkipped = selectedToolIds.filter((id) => !SUPPORTED_IDS.has(id));
205
+ if (todoSkipped.length > 0) {
206
+ const names = todoSkipped.map((id) => TOOLS.find((t) => t.id === id)?.name || id);
207
+ console.log(`\n ${c.dim('TODO (not yet implemented):')} ${names.join(', ')}`);
208
+ }
209
+ if (selectedTools.length === 0) {
210
+ console.log(`\n ${c.red('No supported tools selected.')}`);
211
+ outro('Setup cancelled.');
212
+ process.exit(0);
213
+ }
214
+
215
+ // ── Step 3: Confirm ───────────────────────────────────────────────────
216
+ const skillsDir = path.join(ROOT, 'skills');
217
+ const skillCount = fs
218
+ .readdirSync(skillsDir)
219
+ .filter((d) => fs.existsSync(path.join(skillsDir, d, 'SKILL.md'))).length;
220
+
221
+ const yes = await confirm({
222
+ message: `Install ${skillCount} skills to ${selectedTools.length} runtime${selectedTools.length > 1 ? 's' : ''}?`,
223
+ initialValue: true,
224
+ });
225
+
226
+ if (!yes || isCancel(yes)) {
227
+ outro('Setup cancelled.');
228
+ process.exit(0);
229
+ }
230
+
231
+ // ── Step 4: Install ───────────────────────────────────────────────────
232
+ const s = await spinner();
233
+ s.start('Preparing installation...');
234
+ await sleep(200);
235
+
236
+ s.message('Syncing skills...');
237
+ try {
238
+ runInherited('bash scripts/sync-skills.sh');
239
+ } catch {
240
+ s.error('Sync failed.');
241
+ process.exit(1);
242
+ }
243
+
244
+ const results = [];
245
+ for (const toolId of selectedTools) {
246
+ const tool = TOOLS.find((t) => t.id === toolId);
247
+ const p = installMode === 'global' ? tool.globalPath : tool.localPath;
248
+
249
+ s.message(`Installing ${tool.name}...`);
250
+ await sleep(300);
251
+
252
+ try {
253
+ if (installMode === 'global') {
254
+ installGlobal(tool, ROOT);
255
+ } else {
256
+ installLocal(tool, ROOT);
257
+ }
258
+ results.push({ name: tool.name, path: p, ok: true });
259
+ } catch (err) {
260
+ results.push({ name: tool.name, path: p, ok: false, error: err.message });
261
+ }
262
+ }
263
+
264
+ s.stop('Installation complete.');
265
+
266
+ // ── Step 5: Results ────────────────────────────────────────────────────
267
+ console.log('');
268
+ for (const r of results) {
269
+ const icon = r.ok ? c.green('✓') : c.red('✗');
270
+ const detail = r.ok ? c.dim(r.path) : c.red(r.error);
271
+ console.log(` ${icon} ${r.name} — ${detail}`);
272
+ }
273
+ console.log('');
274
+
275
+ const allOk = results.every((r) => r.ok);
276
+ if (allOk) {
277
+ outro(`bigpowers installed. ${c.dim('Run bigpowers update anytime.')}`);
278
+ } else {
279
+ outro('Some installations failed. Check errors above.');
280
+ process.exit(1);
281
+ }
282
+ }
283
+
284
+ // ── Run ──────────────────────────────────────────────────────────────────────
285
+ main().catch((err) => {
286
+ console.error(`${c.red('Error:')} ${err.message}`);
287
+ process.exit(1);
288
+ });
@@ -0,0 +1,217 @@
1
+ # bigpowers Constitution
2
+
3
+ <!-- story: e55s02 -->
4
+
5
+ > **Status:** consolidated entry point for bigpowers' doctrine, built from a
6
+ > full audit of every current rule source
7
+ > (`specs/epics/e55-extract-constitution/e55s01-doctrine-mapping.md`).
8
+ >
9
+ > **Authority:** this file is where a reader starts. It does **not** yet
10
+ > replace `CLAUDE.md` or `CONVENTIONS.md` — both remain fully authoritative in
11
+ > their own right today. Each block below synthesizes what those files (and
12
+ > the supporting `docs/references/*.md` sources) currently say, with citations
13
+ > to the fuller text rather than a full copy of it, so this file doesn't
14
+ > become a second place the same rule can drift out of sync.
15
+ >
16
+ > This file has no `constitution_version` or amendment scheme — that
17
+ > compatibility-tracking mechanism is a later concern (e59, absorb-fresh-
18
+ > references), not something this story invents ahead of schedule.
19
+ >
20
+ > Structure follows bigspec's 11 blocks (B0–B10) plus a Capstone category, used
21
+ > here purely as an organizing skeleton (`specs/reborn-constitution.md` Part I),
22
+ > not as a source of content — every claim below is about what *this* repo's
23
+ > doctrine actually says today.
24
+
25
+ ---
26
+
27
+ ## B0 · Token/Context Substrate
28
+
29
+ Content is written to be consumed by an agent under a real token budget, not
30
+ skimmed by a human. Files stay under size caps so they fit a single context
31
+ window; skills load progressively (frontmatter → summary → detail) instead of
32
+ being read in full up front; `verify:` commands are one-line and runnable.
33
+
34
+ - 300-line file cap, `SKILL.md` size caps — `CONVENTIONS.md` §Code Style, `docs/PRINCIPLES.md` §5/§8
35
+ - Context Routing (load by glob, not the full doc tree) — `CLAUDE.md`
36
+ - Token Economy, high-density skill descriptions — `docs/PRINCIPLES.md` §5, `docs/references/akita.md`
37
+ - Full progressive-disclosure framework, `bts_map`/`bts_compress`/`sqz`/`rtk` tooling — `docs/references/context-engineering.md`
38
+ - `terse-mode` past ~20 turns — `CONVENTIONS.md` §Risk Tiers (`terse-when-heavy`)
39
+
40
+ ## B1 · Agent-Grade Craftsmanship
41
+
42
+ The code floor: functions 4–20 lines, files under 300 lines, one responsibility
43
+ per module, names specific enough that `grep` returns under 5 hits, no
44
+ duplication, exceptions over error codes, dead code deleted not commented out,
45
+ Boy Scout Rule, Law of Demeter, error messages that carry a remediation hint.
46
+
47
+ - Full Code Style, Comments, Dependencies, Structure, Formatting, Logging sections — `CONVENTIONS.md`
48
+ - SRP, Boy Scout Rule, intention-revealing names — `docs/PRINCIPLES.md` §1
49
+ - Deep modules, information hiding — `docs/PRINCIPLES.md` §2, `docs/references/ousterhout.md`, `docs/references/pocock.md`
50
+ - Grep-ability, structured observability, remediation hints — `docs/PRINCIPLES.md` §5, `docs/references/akita.md`
51
+ - SOLID, DRY, refactoring catalog, seams for testability — `docs/references/sandi-metz.md`, `docs/references/fowler.md`, `docs/references/uncle-bob.md`, `docs/references/feathers.md`, `docs/references/pragmatic-programmer.md`, `docs/references/rich-hickey.md`
52
+ - Conventional Commits message mechanics — `docs/references/git-integration.md`
53
+
54
+ ## B2 · Think-First Behavior
55
+
56
+ Understand before acting; act minimally. Assumptions get surfaced before code
57
+ is written, ambiguous requests get multiple readings named explicitly, and
58
+ edits stay surgical — touching only what the task requires.
59
+
60
+ - Session Start read order, "minimum code", "one clarifying question beats a wrong assumption" — `CLAUDE.md`
61
+ - Think First, Zoom-Out Strategy, Surgical Edits — `docs/PRINCIPLES.md` §3
62
+ - Zoom-out mandate, `define-success` hard gate, "we'll decide during code" red flag — `docs/references/orchestration.md`, `docs/references/workflow-steps.md`
63
+ - Tidy First?, tracer bullets, good-enough software — `docs/references/kent-beck.md`, `docs/references/pragmatic-programmer.md`
64
+ - System 1 vs System 2 thinking, model-escalation cost-benefit — `docs/references/thinking-models.md`
65
+ - Domain probes (`grill-me`), model-domain invariant grilling — `docs/references/domain-probes.md`, `docs/references/ddd.md`
66
+
67
+ ## B3 · The Skill Primitive
68
+
69
+ A skill is a verb-noun procedure, not a class of code. Every critical-path
70
+ skill writes `handoff.next_skill` as its last action so work can resume
71
+ anywhere it stopped.
72
+
73
+ - Workflow Mandate: route work through bigpowers skills, never write code directly — `CLAUDE.md`, `CONVENTIONS.md` §Agent Workflow Mandates
74
+ - Skill Naming, Tombstone Aliases, next_skill signaling mandate — `CONVENTIONS.md`
75
+ - Skill-Based Architecture, zoom-out mandate — `docs/PRINCIPLES.md` §3
76
+ - `seed-conventions` bootstrap, `survey-context` phase mapping — `docs/references/agent-config-files-and-okf.md`, `docs/references/workflow-steps.md`
77
+
78
+ ## B4 · Spec-as-Contract
79
+
80
+ The spec is the source of truth, not the chat history. `plan-work` produces
81
+ `verify:`-bearing tasks before any feature code is written; a story only
82
+ counts as done once `verify-work` confirms it against those criteria.
83
+
84
+ - `plan-work` before feature code, UAT sign-off mandate, delta-tag requirement — `CONVENTIONS.md` §Agent Workflow Mandates
85
+ - Intent/delivery/execution file ownership table — `CONVENTIONS.md` §specs/
86
+ - SDD, BDD/Gherkin as the link — `docs/PRINCIPLES.md` §4, `docs/references/wasowski.md`
87
+ - Ubiquitous Language, information-first design — `docs/references/pocock.md`, `docs/references/rich-hickey.md`
88
+ - Story maturity/INVEST gates, NFR Gate pattern, structured-spec pattern — `docs/references/bcp.md`, `docs/references/bcp-plus.md`, `docs/references/spec-kit.md`
89
+ - Bounded context, context mapping, `define-language` — `docs/references/ddd.md`
90
+
91
+ ## B5 · Risk-Tiered Verification
92
+
93
+ Proof is proportionate to risk. Every story is tagged P0–P3 at plan time; that
94
+ tier picks how much verification it gets — full multi-phase UAT for P0, down
95
+ to typecheck-and-lint for P3.
96
+
97
+ - Full Risk Tiers (P0–P3) table, Tests (F.I.R.S.T) — `CONVENTIONS.md` §Risk Tiers, §Tests
98
+ - F.I.R.S.T Testing — `docs/PRINCIPLES.md` §1, `docs/references/kent-beck.md`, `docs/references/uncle-bob.md`, `docs/references/tdd.md`, `docs/references/wasowski.md` *(stated in at least 5 sources — a live duplication instance, not evidence of 5 distinct rules)*
99
+ - P0–P3 risk-based test-depth tables — `docs/references/bmad.md`, `docs/references/tea.md`
100
+ - Boundary conditions, public-interface-only testing (T4/T5/T8), ≥95% coverage, NFR Evidence Audit — `docs/references/tdd.md`, `docs/references/bmad.md`, `docs/references/tea.md`
101
+ - OKF validation gates on structure/provenance, never a value — `docs/references/okf.md`
102
+ - Slopcheck [OK]/[SUS]/[SLOP], supply-chain and security-audit checklists — `docs/references/security-threats.md`
103
+
104
+ ## B6 · Gates & Hard-Stops
105
+
106
+ Forward progress blocks until conditions are met — Preflight and CI must be
107
+ green before any forward work, and any reproducible gate failure is a
108
+ discovered defect, not something to note and move past.
109
+
110
+ - Always Green / Shift Left, Discovered Defects fix-or-log ladder, banned dismissive phrases — `CONVENTIONS.md` §Always Green, §Discovered Defects
111
+ - Hard Gates — `docs/PRINCIPLES.md` §6
112
+ - Broken Windows, quality-score gate, review workflow gate — `docs/references/pragmatic-programmer.md`, `docs/references/code-review.md`
113
+ - Checkpoint state machine, safety checkpoints, never-auto-merge — `docs/references/checkpoints.md`, `docs/references/git-integration.md`
114
+ - 6-phase Confirm-gates, deviation-from-plan red flag, mode-scaled strictness — `docs/references/orchestration.md`, `docs/references/orchestration-modes.md`
115
+ - Full Traceability Gate pipeline (coverage matrix, blind-spot categories, PASS/CONCERNS/FAIL/WAIVED verdicts) — `docs/references/traceability-gate.md`
116
+ - Four gate types (Confirm/Quality/Safety/Transition) — `docs/references/gates.md`
117
+
118
+ **Today's proof mechanism, described honestly:** the actual gate that runs on
119
+ every `npm run compliance` invocation is a Gherkin-based self-compliance suite
120
+ with a 94% pass threshold (`docs/PRINCIPLES.md` §6/§7, `CLAUDE.md` §Commands,
121
+ `docs/references/gates.md`). This is what genuinely exists and gates merges
122
+ today. `specs/reborn-constitution.md`'s Capstone block describes a *target*
123
+ state where outcome evals (with-skill vs without-skill delta) replace this
124
+ threshold — that replacement is **e58's job (evals-over-compliance), not yet
125
+ built**. The 94% Gherkin gate is not deprecated; it is the live mechanism
126
+ until e58 ships something to replace it with.
127
+
128
+ ## B7 · Context Isolation
129
+
130
+ Context rot is the primary failure mode of long agentic sessions. The fix is
131
+ fresh-context subagents with file-based handoff, not a bigger prompt —
132
+ `state.yaml` tracks precise session state so any interruption can resume
133
+ exactly where it stopped.
134
+
135
+ - Token Management (Write/Select/Compress/Isolate, effort classification) — `CLAUDE.md`
136
+ - Session Governance via `state.yaml`/`release-plan.yaml` — `docs/PRINCIPLES.md` §6
137
+ - Model-escalation to fresh-context subagents — `docs/references/thinking-models.md`
138
+ - Handoff-contract principle, `dispatch-agents`/`delegate-task` scoped file access, `kickoff-branch` worktree isolation, `agent-locks.yaml` concurrency — `docs/references/context-engineering.md`
139
+ - `state.yaml` tracking, resume-via-survey-context, stale-lock detection — `docs/references/gsd.md`, `docs/references/semantic-context-bridge.md`
140
+
141
+ ## B8 · Self-Describing Artifacts
142
+
143
+ Every planning artifact has exactly one owning file — `specs/execution-status.yaml`
144
+ is the sole source of truth for story status, `specs/release-plan.yaml` for
145
+ epic ordering, and so on. Generated artifacts (`.cursor/`, `.gemini/`,
146
+ `.pi/`, `website/`) are never hand-edited; their `SKILL.md` sources are.
147
+
148
+ - Full specs/ ownership model, Documentation Responsibilities table, Generated artifact targets, docs/references SSOT Sync — `CONVENTIONS.md` §specs/
149
+ - Never-edit-generated-artifacts, single-source-of-truth `SKILL.md` — `CLAUDE.md`
150
+ - OKF bundle frontmatter (`okf_kind`/`okf_version`/provenance), kind-aware validation, "gate on pipeline not value" — `docs/references/okf.md`
151
+ - CLAUDE.md/AGENTS.md dual-pattern — `docs/references/agent-config-files-and-okf.md`
152
+ - Skill graph, OKF wiki bundle, targets-registry as the single Integration Registry — `docs/references/semantic-context-bridge.md`, `docs/references/targets-registry.md`
153
+
154
+ *Note: `docs/references/okf.md` describes OKF-bundle conformance as achievable
155
+ "if all `SKILL.md` files add frontmatter fields" — that's a conditional, not a
156
+ claim that every generated file already carries this envelope today. Making
157
+ that universal across the whole `specs/` tree is e57's job (adopt-okf-envelope),
158
+ not yet built.*
159
+
160
+ ## B9 · Effort Accounting (BCP)
161
+
162
+ BCP (Business Complexity Points) sizes a story before it's built, from a
163
+ 6-step method summing per-element Fibonacci scores. It lives at the story
164
+ level only — there is no per-task `[BCP N]` annotation in the current method.
165
+
166
+ - Full BCP accounting mandate, Timestamp mandate, story-level-only rule — `CONVENTIONS.md` §BCP accounting mandate, §Timestamp mandate
167
+ - `effort:` frontmatter (light/standard/heavy) — `docs/references/context-engineering.md`, `docs/references/model-profiles.md`
168
+ - 6-step sizing method, size bands, velocity tracking — `docs/references/bcp.md`
169
+ - BCP-Plus 13-dimension framework — `docs/references/bcp-plus.md`
170
+
171
+ *Note: some older docs (`docs/references/workflow-artifacts.md`,
172
+ `docs/references/orchestration.md`) still reference a per-task `[BCP N]` tag
173
+ convention that `CONVENTIONS.md` has since superseded — a live drift instance
174
+ this consolidation surfaces rather than resolves. Resolving it is a
175
+ `docs/references` sync task, not this story's job.*
176
+
177
+ ## B10 · The Synthesis
178
+
179
+ The 6-phase core loop — Discover → Elaborate → Plan → Build → Verify →
180
+ Release — runs at project, epic, and story scope alike. *Sustain* is a
181
+ session-flow state, not a seventh lifecycle phase.
182
+
183
+ - 6-Phase Lifecycle, Hard Gates, 94% threshold — `docs/PRINCIPLES.md` §6
184
+ - Same 6-phase loop, `orchestrate-project` phase sequencing — `docs/references/orchestration.md`, `docs/references/workflow-steps.md`
185
+ - BMAD's Discover→Elaborate→Plan→Build→Sustain arc, TEA's workflows, SDD lifecycle integration — `docs/references/bmad.md`, `docs/references/tea.md`, `docs/references/wasowski.md`
186
+
187
+ ## ★ Capstone · Outcome Evals
188
+
189
+ The foundation should prove it produces better software, not just that it
190
+ follows its own rules. Bigpowers doesn't have this yet in the target form —
191
+ what exists today is described honestly in B6 above: a 94% Gherkin
192
+ self-compliance gate. `reborn-constitution.md`'s Capstone block names the
193
+ target (with-skill vs without-skill delta, pass@k + token cost) as what
194
+ **e58 (evals-over-compliance)** is expected to build. Until then:
195
+
196
+ - Request-review checklist / quality-score gate as today's closest analog — `docs/references/code-review.md`
197
+ - Human-in-the-loop UAT mandate after every story — `docs/references/spec-kit.md`
198
+ - `run-evals` + regression UAT phase, `specs/EVALS-<feature>.md` — `docs/references/workflow-steps.md`, `docs/references/workflow-artifacts.md`
199
+
200
+ ---
201
+
202
+ ## What this file deliberately doesn't do (yet)
203
+
204
+ - **No content migration.** Full rule text stays in `CONVENTIONS.md`,
205
+ `CLAUDE.md`, `docs/PRINCIPLES.md`, and `docs/references/*.md`. Moving
206
+ rule-classified content in is e56's job (reclassify-catalog) — this file
207
+ only builds the destination structure.
208
+ - **No cross-references back from `CLAUDE.md`/`CONVENTIONS.md` yet.** Those
209
+ files don't point here yet; that's e55s03.
210
+ - **No amendment/versioning scheme.** `constitution_version`, SemVer bumps,
211
+ and ADR-gated amendments are e59's job (absorb-fresh-references).
212
+ - **No universal OKF envelope claim.** Not every generated file in this repo
213
+ carries `okf_kind`/`okf_version` frontmatter yet — that's e57's job
214
+ (adopt-okf-envelope).
215
+ - **No `count-bcp` skill.** BCP sizing today is the 6-step method in
216
+ `docs/references/bcp.md`, applied by hand during `plan-work`/`plan-release` —
217
+ not a dedicated skill or kernel module.
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "bigpowers",
3
- "version": "2.81.0",
3
+ "version": "2.82.0",
4
4
  "description": "73 agent skills synthesizing 17 years of software engineering discipline into a prescriptive methodology for solo developers",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
+ "setup": "node bin/setup.js",
7
8
  "compliance": "bash scripts/audit-compliance.sh specs/verifications/features && bash scripts/validate-doctrine.sh && python3 scripts/check-skill-links.py",
8
9
  "doctrine": "bash scripts/validate-doctrine.sh",
9
10
  "sync": "bash scripts/sync-skills.sh",
@@ -47,11 +48,16 @@
47
48
  },
48
49
  "bin": {
49
50
  "bigpowers": "./bin/bigpowers.js",
51
+ "bigpowers-setup": "./bin/setup.js",
50
52
  "bigpowers-dashboard": "./dashboard/bin/dashboard.js"
51
53
  },
52
54
  "engines": {
53
55
  "node": ">=14.0.0"
54
56
  },
57
+ "dependencies": {
58
+ "@clack/prompts": "^0.10.0",
59
+ "picocolors": "^1.1.1"
60
+ },
55
61
  "devDependencies": {
56
62
  "@semantic-release/changelog": "^6.0.3",
57
63
  "@semantic-release/exec": "^7.1.0",
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env node
2
+ // install-helpers.js — symlink helpers for bigpowers setup
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ function linkSkills(skillsDir, targetDir) {
8
+ for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
9
+ if (!entry.isDirectory()) continue;
10
+ if (!fs.existsSync(path.join(skillsDir, entry.name, 'SKILL.md'))) continue;
11
+
12
+ const src = path.join(skillsDir, entry.name);
13
+ const dst = path.join(targetDir, entry.name);
14
+
15
+ try {
16
+ const stat = fs.lstatSync(dst);
17
+ if (stat.isSymbolicLink()) fs.unlinkSync(dst);
18
+ } catch {}
19
+
20
+ fs.symlinkSync(src, dst);
21
+ }
22
+ }
23
+
24
+ function linkDir(src, dst) {
25
+ try {
26
+ const stat = fs.lstatSync(dst);
27
+ if (stat.isSymbolicLink()) fs.unlinkSync(dst);
28
+ } catch {}
29
+ fs.symlinkSync(src, dst);
30
+ }
31
+
32
+ function linkFile(src, dst) {
33
+ try {
34
+ const stat = fs.lstatSync(dst);
35
+ if (stat.isSymbolicLink()) fs.unlinkSync(dst);
36
+ } catch {}
37
+ fs.symlinkSync(src, dst);
38
+ }
39
+
40
+ function linkHook(src, dst) {
41
+ if (!fs.existsSync(src)) return;
42
+ try {
43
+ const stat = fs.lstatSync(dst);
44
+ if (stat.isSymbolicLink()) fs.unlinkSync(dst);
45
+ } catch {}
46
+ fs.symlinkSync(src, dst);
47
+ try { fs.chmodSync(src, 0o755); } catch {}
48
+ }
49
+
50
+ // ── Install per tool ─────────────────────────────────────────────────────────
51
+
52
+ function installGlobal(tool, repoRoot) {
53
+ const homeDir = require('os').homedir();
54
+ const skillsDir = path.join(repoRoot, 'skills');
55
+
56
+ switch (tool.id) {
57
+ case 'claude': {
58
+ const targetDir = path.join(homeDir, '.claude', 'skills');
59
+ fs.mkdirSync(targetDir, { recursive: true });
60
+ linkSkills(skillsDir, targetDir);
61
+
62
+ const hooksDir = path.join(homeDir, '.claude', 'hooks');
63
+ fs.mkdirSync(hooksDir, { recursive: true });
64
+ linkHook(
65
+ path.join(repoRoot, 'guard-git', 'scripts', 'block-dangerous-git.sh'),
66
+ path.join(hooksDir, 'block-dangerous-git.sh')
67
+ );
68
+ linkHook(
69
+ path.join(repoRoot, 'scripts', 'hooks', 'rtk-rewrite.sh'),
70
+ path.join(hooksDir, 'rtk-rewrite.sh')
71
+ );
72
+ break;
73
+ }
74
+ case 'gemini': {
75
+ const extSrc = path.join(repoRoot, '.gemini', 'extensions', 'bigpowers');
76
+ const extDst = path.join(homeDir, '.gemini', 'config', 'plugins', 'bigpowers');
77
+ fs.mkdirSync(path.dirname(extDst), { recursive: true });
78
+ linkDir(extSrc, extDst);
79
+ break;
80
+ }
81
+ case 'pi': {
82
+ const targetDir = path.join(homeDir, '.pi', 'agent', 'skills');
83
+ fs.mkdirSync(targetDir, { recursive: true });
84
+ linkSkills(skillsDir, targetDir);
85
+ break;
86
+ }
87
+ case 'cursor': {
88
+ const rulesSrc = path.join(repoRoot, '.cursor', 'rules');
89
+ const rulesDst = path.join(homeDir, '.cursor', 'rules');
90
+ fs.mkdirSync(path.dirname(rulesDst), { recursive: true });
91
+ linkDir(rulesSrc, rulesDst);
92
+ break;
93
+ }
94
+ case 'codex': {
95
+ const templatePath = path.join(repoRoot, 'templates', 'codex', 'AGENTS.md');
96
+ const targetPath = path.join(homeDir, '.codex', 'AGENTS.md');
97
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
98
+ linkFile(templatePath, targetPath);
99
+ break;
100
+ }
101
+ }
102
+ }
103
+
104
+ function installLocal(tool, repoRoot) {
105
+ const skillsDir = path.join(repoRoot, 'skills');
106
+ const cwd = process.cwd();
107
+
108
+ switch (tool.id) {
109
+ case 'claude': {
110
+ const targetDir = path.join(cwd, '.claude', 'skills');
111
+ fs.mkdirSync(targetDir, { recursive: true });
112
+ linkSkills(skillsDir, targetDir);
113
+ break;
114
+ }
115
+ case 'gemini': {
116
+ const extSrc = path.join(repoRoot, '.gemini', 'extensions', 'bigpowers');
117
+ const extDst = path.join(cwd, '.gemini', 'extensions', 'bigpowers');
118
+ fs.mkdirSync(path.dirname(extDst), { recursive: true });
119
+ linkDir(extSrc, extDst);
120
+ break;
121
+ }
122
+ case 'pi': {
123
+ const targetDir = path.join(cwd, '.pi', 'agent', 'skills');
124
+ fs.mkdirSync(targetDir, { recursive: true });
125
+ linkSkills(skillsDir, targetDir);
126
+ break;
127
+ }
128
+ case 'cursor': {
129
+ const rulesSrc = path.join(repoRoot, '.cursor', 'rules');
130
+ const rulesDst = path.join(cwd, '.cursor', 'rules');
131
+ fs.mkdirSync(path.dirname(rulesDst), { recursive: true });
132
+ linkDir(rulesSrc, rulesDst);
133
+ break;
134
+ }
135
+ case 'codex': {
136
+ const templatePath = path.join(repoRoot, 'templates', 'codex', 'AGENTS.md');
137
+ const targetPath = path.join(cwd, '.codex', 'AGENTS.md');
138
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
139
+ linkFile(templatePath, targetPath);
140
+ break;
141
+ }
142
+ }
143
+ }
144
+
145
+ // ── Uninstall per tool ───────────────────────────────────────────────────────
146
+
147
+ function uninstallTool(toolId, repoRoot) {
148
+ const homeDir = require('os').homedir();
149
+
150
+ switch (toolId) {
151
+ case 'claude': {
152
+ const skillsDir = path.join(homeDir, '.claude', 'skills');
153
+ if (fs.existsSync(skillsDir)) {
154
+ for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
155
+ if (!entry.isSymbolicLink()) continue;
156
+ const target = fs.readlinkSync(path.join(skillsDir, entry.name));
157
+ if (target.includes('bigpowers')) {
158
+ removeSymlink(path.join(skillsDir, entry.name));
159
+ }
160
+ }
161
+ }
162
+ const hooksDir = path.join(homeDir, '.claude', 'hooks');
163
+ removeSymlink(path.join(hooksDir, 'block-dangerous-git.sh'));
164
+ removeSymlink(path.join(hooksDir, 'rtk-rewrite.sh'));
165
+ break;
166
+ }
167
+ case 'gemini':
168
+ removeSymlink(path.join(homeDir, '.gemini', 'config', 'plugins', 'bigpowers'));
169
+ break;
170
+ case 'pi': {
171
+ const skillsDir = path.join(homeDir, '.pi', 'agent', 'skills');
172
+ if (fs.existsSync(skillsDir)) {
173
+ for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
174
+ if (!entry.isSymbolicLink()) continue;
175
+ const target = fs.readlinkSync(path.join(skillsDir, entry.name));
176
+ if (target.includes('bigpowers')) {
177
+ removeSymlink(path.join(skillsDir, entry.name));
178
+ }
179
+ }
180
+ }
181
+ break;
182
+ }
183
+ case 'cursor':
184
+ removeSymlink(path.join(homeDir, '.cursor', 'rules'));
185
+ break;
186
+ case 'codex':
187
+ removeSymlink(path.join(homeDir, '.codex', 'AGENTS.md'));
188
+ break;
189
+ }
190
+ }
191
+
192
+ function removeSymlink(p) {
193
+ try {
194
+ const stat = fs.lstatSync(p);
195
+ if (stat.isSymbolicLink()) {
196
+ fs.unlinkSync(p);
197
+ return true;
198
+ }
199
+ } catch {}
200
+ return false;
201
+ }
202
+
203
+ function detectExistingInstall() {
204
+ const homeDir = require('os').homedir();
205
+ const marker = path.join(homeDir, '.claude', 'skills', 'survey-context');
206
+ try {
207
+ const stat = fs.lstatSync(marker);
208
+ return stat.isSymbolicLink();
209
+ } catch {
210
+ return false;
211
+ }
212
+ }
213
+
214
+ module.exports = {
215
+ linkSkills,
216
+ linkDir,
217
+ linkFile,
218
+ linkHook,
219
+ installGlobal,
220
+ installLocal,
221
+ uninstallTool,
222
+ removeSymlink,
223
+ detectExistingInstall,
224
+ };
@@ -51,26 +51,29 @@ shopt -u nullglob
51
51
  (( ${#SPECS[@]} > 0 )) || report CRITICAL "No story spec .md files in capsule (run slice-tasks first)"
52
52
  (( ${#TASKS[@]} > 0 )) || report CRITICAL "No *-tasks.yaml files in capsule (run plan-work first)"
53
53
 
54
+ # A story's real spec is whatever its own tasks.yaml declares via `spec:` —
55
+ # not every e*s*.md file, which also matches non-spec deliverables a story
56
+ # produces (e.g. an audit story's own eNNsYY-<slug>.md output document).
54
57
  SPEC_IDS=()
55
- for spec in "${SPECS[@]+"${SPECS[@]}"}"; do
56
- base="$(basename "$spec" .md)"
57
- sid="$(echo "$base" | grep -oE 'e[0-9]+s[0-9]+' | head -1)"
58
- [[ -n "$sid" ]] || continue
59
- SPEC_IDS+=("$sid")
60
- in_array "$sid" "${EPIC_STORIES[@]+"${EPIC_STORIES[@]}"}" \
61
- || report HIGH "Story $sid in spec file but missing from epic.yaml manifest"
62
- grep -qE '^#{2,3} (17\.|Acceptance|Verification Script)' "$spec" \
63
- || report HIGH "Story $sid spec missing §17 acceptance criteria or Verification Script"
64
- grep -qiE 'ambiguous|TBD|TODO|FIXME' "$spec" \
65
- && report MED "Story $sid spec contains ambiguous/TBD markers"
66
- done
67
-
68
58
  for tasks in "${TASKS[@]+"${TASKS[@]}"}"; do
69
59
  base="$(basename "$tasks" -tasks.yaml)"
70
60
  sid="$(echo "$base" | grep -oE 'e[0-9]+s[0-9]+' | head -1)"
71
61
  [[ -n "$sid" ]] || continue
72
- in_array "$sid" "${SPEC_IDS[@]+"${SPEC_IDS[@]}"}" \
73
- || report CRITICAL "tasks.yaml for $sid without matching story spec .md"
62
+
63
+ spec_name="$(grep -E '^spec:' "$tasks" | head -1 | sed -E 's/^spec:[[:space:]]*//; s/^"(.*)"$/\1/')"
64
+ spec="$CAPSULE/$spec_name"
65
+ if [[ -z "$spec_name" || ! -f "$spec" ]]; then
66
+ report CRITICAL "Story $sid tasks.yaml declares no valid spec: file"
67
+ else
68
+ SPEC_IDS+=("$sid")
69
+ in_array "$sid" "${EPIC_STORIES[@]+"${EPIC_STORIES[@]}"}" \
70
+ || report HIGH "Story $sid in spec file but missing from epic.yaml manifest"
71
+ grep -qE '^#{2,3} (17\.|Acceptance|Verification Script)' "$spec" \
72
+ || report HIGH "Story $sid spec missing §17 acceptance criteria or Verification Script"
73
+ grep -qiE 'ambiguous|TBD|TODO|FIXME' "$spec" \
74
+ && report MED "Story $sid spec contains ambiguous/TBD markers"
75
+ fi
76
+
74
77
  grep -qE '^[[:space:]]*verify:' "$tasks" \
75
78
  || report CRITICAL "Story $sid tasks.yaml missing runnable verify: commands"
76
79
  grep -qE '^status:[[:space:]]*(failing|todo|passing)' "$tasks" \
@@ -24,7 +24,16 @@ sync_post_run() {
24
24
  jq -n --arg name "bigpowers" \
25
25
  --arg version "$pkg_version" \
26
26
  --arg desc "${skill_count} skills — ${pkg_desc}" \
27
- '{name: $name, version: $version, description: $desc}' > "$GEMINI_MANIFEST"
27
+ '{
28
+ name: $name,
29
+ version: $version,
30
+ description: $desc,
31
+ keywords: ["gemini-extension"],
32
+ gemini: {
33
+ skills: ["./skills"],
34
+ commands: ["./commands"]
35
+ }
36
+ }' > "$GEMINI_MANIFEST"
28
37
 
29
38
  jq -n --arg version "$pkg_version" \
30
39
  --arg desc "${skill_count} skills — ${pkg_desc}" \