godpowers 2.4.2 → 2.5.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/CHANGELOG.md +50 -0
- package/README.md +22 -6
- package/RELEASE.md +29 -35
- package/SKILL.md +5 -0
- package/agents/god-orchestrator.md +31 -1255
- package/bin/install.js +16 -107
- package/fixtures/gate/build-pass/.godpowers/build/STATE.md +10 -0
- package/fixtures/gate/harden-pass/.godpowers/harden/FINDINGS.md +14 -0
- package/fixtures/gate/repo-pass/.godpowers/repo/AUDIT.md +9 -0
- package/lib/artifact-map.js +60 -0
- package/lib/cli-dispatch.js +162 -0
- package/lib/command-families.js +10 -2
- package/lib/dashboard.js +3 -2
- package/lib/gate.js +271 -0
- package/lib/installer-args.js +11 -1
- package/lib/route-quality-sync.js +38 -0
- package/package.json +3 -2
- package/references/orchestration/GOD-MODE-RUNBOOK.md +19 -0
- package/references/orchestration/GOD-NEXT-RUNBOOK.md +32 -0
- package/references/orchestration/GOD-ORCHESTRATOR-RUNBOOK.md +1259 -0
- package/references/orchestration/README.md +6 -0
- package/references/shared/DASHBOARD-CONTRACT.md +93 -0
- package/references/shared/LOCKING.md +15 -0
- package/references/shared/README.md +2 -0
- package/routing/god-arch.yaml +1 -0
- package/routing/god-build.yaml +1 -0
- package/routing/god-design.yaml +1 -0
- package/routing/god-harden.yaml +1 -0
- package/routing/god-prd.yaml +1 -0
- package/routing/god-repo.yaml +1 -0
- package/routing/god-roadmap-check.yaml +1 -1
- package/routing/god-roadmap.yaml +1 -0
- package/routing/god-stack.yaml +1 -0
- package/skills/god-arch.md +3 -13
- package/skills/god-build.md +5 -14
- package/skills/god-deploy.md +1 -12
- package/skills/god-design.md +9 -12
- package/skills/god-feature.md +1 -12
- package/skills/god-harden.md +3 -13
- package/skills/god-hotfix.md +1 -12
- package/skills/god-launch.md +1 -12
- package/skills/god-link.md +1 -12
- package/skills/god-migrate.md +1 -3
- package/skills/god-mode.md +4 -0
- package/skills/god-next.md +34 -410
- package/skills/god-observe.md +1 -12
- package/skills/god-prd.md +3 -13
- package/skills/god-redo.md +1 -12
- package/skills/god-refactor.md +1 -12
- package/skills/god-repair.md +1 -12
- package/skills/god-repo.md +3 -13
- package/skills/god-restore.md +1 -12
- package/skills/god-roadmap-check.md +5 -0
- package/skills/god-roadmap.md +3 -13
- package/skills/god-rollback.md +1 -12
- package/skills/god-scan.md +1 -12
- package/skills/god-skip.md +1 -12
- package/skills/god-stack.md +3 -13
- package/skills/god-status.md +27 -204
- package/skills/god-story-build.md +1 -12
- package/skills/god-story-close.md +1 -12
- package/skills/god-story.md +1 -12
- package/skills/god-sync.md +1 -12
- package/skills/god-undo.md +1 -12
- package/skills/god-update-deps.md +1 -12
- package/skills/god-upgrade.md +1 -12
package/lib/gate.js
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executable Godpowers tier gates.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 gates are intentionally mechanical. They check expected artifacts on
|
|
5
|
+
* disk, run the shared artifact linter, and apply narrow tier-specific checks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const artifactMap = require('./artifact-map');
|
|
12
|
+
const linter = require('./artifact-linter');
|
|
13
|
+
const router = require('./router');
|
|
14
|
+
|
|
15
|
+
function relToAbs(projectRoot, relPath) {
|
|
16
|
+
return path.join(projectRoot, relPath);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function makeCheck(id, status, artifact, reason) {
|
|
20
|
+
return { id, status, artifact, reason };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function makeFinding(id, severity, artifact, reason, extra = {}) {
|
|
24
|
+
return { id, severity, artifact, reason, ...extra };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function emptySummary() {
|
|
28
|
+
return {
|
|
29
|
+
errors: 0,
|
|
30
|
+
warnings: 0,
|
|
31
|
+
infos: 0,
|
|
32
|
+
missing: 0,
|
|
33
|
+
checkedArtifacts: 0
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function addFindingSummary(summary, severity) {
|
|
38
|
+
if (severity === 'error') summary.errors++;
|
|
39
|
+
else if (severity === 'warning') summary.warnings++;
|
|
40
|
+
else summary.infos++;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function lintArtifact(projectRoot, relPath, opts = {}) {
|
|
44
|
+
return linter.lintFile(relToAbs(projectRoot, relPath), {
|
|
45
|
+
projectRoot,
|
|
46
|
+
today: opts.today
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function checkArtifacts(projectRoot, tier, artifacts, opts, result) {
|
|
51
|
+
for (const artifact of artifacts) {
|
|
52
|
+
const exists = fs.existsSync(relToAbs(projectRoot, artifact.path));
|
|
53
|
+
const artifactResult = {
|
|
54
|
+
path: artifact.path,
|
|
55
|
+
required: artifact.required,
|
|
56
|
+
exists,
|
|
57
|
+
lint: null
|
|
58
|
+
};
|
|
59
|
+
result.artifacts.push(artifactResult);
|
|
60
|
+
|
|
61
|
+
if (!exists) {
|
|
62
|
+
const status = artifact.required ? 'fail' : 'skipped';
|
|
63
|
+
result.checks.push(makeCheck(
|
|
64
|
+
`artifact:${tier}:${artifact.path}`,
|
|
65
|
+
status,
|
|
66
|
+
artifact.path,
|
|
67
|
+
artifact.required ? 'Required artifact is missing.' : 'Optional artifact is absent.'
|
|
68
|
+
));
|
|
69
|
+
if (artifact.required) {
|
|
70
|
+
result.summary.missing++;
|
|
71
|
+
const finding = makeFinding(
|
|
72
|
+
`missing-artifact:${tier}:${artifact.path}`,
|
|
73
|
+
'error',
|
|
74
|
+
artifact.path,
|
|
75
|
+
'Required artifact is missing.'
|
|
76
|
+
);
|
|
77
|
+
result.findings.push(finding);
|
|
78
|
+
addFindingSummary(result.summary, finding.severity);
|
|
79
|
+
}
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
result.checks.push(makeCheck(
|
|
84
|
+
`artifact:${tier}:${artifact.path}`,
|
|
85
|
+
'pass',
|
|
86
|
+
artifact.path,
|
|
87
|
+
'Artifact exists on disk.'
|
|
88
|
+
));
|
|
89
|
+
|
|
90
|
+
if (!artifact.lint) continue;
|
|
91
|
+
const lintResult = lintArtifact(projectRoot, artifact.path, opts);
|
|
92
|
+
artifactResult.lint = {
|
|
93
|
+
type: lintResult.type,
|
|
94
|
+
summary: lintResult.summary
|
|
95
|
+
};
|
|
96
|
+
result.summary.checkedArtifacts++;
|
|
97
|
+
for (const finding of lintResult.findings) {
|
|
98
|
+
result.findings.push({
|
|
99
|
+
...finding,
|
|
100
|
+
id: `lint:${artifact.path}:${finding.code}:${finding.line}`,
|
|
101
|
+
artifact: artifact.path,
|
|
102
|
+
reason: finding.message
|
|
103
|
+
});
|
|
104
|
+
addFindingSummary(result.summary, finding.severity);
|
|
105
|
+
}
|
|
106
|
+
result.checks.push(makeCheck(
|
|
107
|
+
`lint:${tier}:${artifact.path}`,
|
|
108
|
+
lintResult.summary.errors > 0 ? 'fail' : 'pass',
|
|
109
|
+
artifact.path,
|
|
110
|
+
lintResult.summary.errors > 0
|
|
111
|
+
? `${lintResult.summary.errors} lint error(s) block this gate.`
|
|
112
|
+
: `${lintResult.summary.warnings} warning(s), ${lintResult.summary.infos} info finding(s).`
|
|
113
|
+
));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function extractPassedCommands(text) {
|
|
118
|
+
const commands = [];
|
|
119
|
+
for (const line of text.split(/\r?\n/)) {
|
|
120
|
+
const backtick = line.match(/`([^`\n]+)`/);
|
|
121
|
+
const labeled = line.match(/\bcommand\s*:\s*([^;]+?)(?:\s{2,}|\s+status\s*:|\s+result\s*:|$)/i);
|
|
122
|
+
const command = backtick ? backtick[1].trim() : (labeled ? labeled[1].trim() : null);
|
|
123
|
+
if (!command) continue;
|
|
124
|
+
if (/\b(pass|passed|green|success|succeeded|ok)\b/i.test(line)) {
|
|
125
|
+
commands.push(command);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return [...new Set(commands)];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function checkBuildEvidence(projectRoot, result) {
|
|
132
|
+
const relPath = '.godpowers/build/STATE.md';
|
|
133
|
+
const file = relToAbs(projectRoot, relPath);
|
|
134
|
+
if (!fs.existsSync(file)) return;
|
|
135
|
+
const text = fs.readFileSync(file, 'utf8');
|
|
136
|
+
const passedCommands = extractPassedCommands(text);
|
|
137
|
+
if (passedCommands.length === 0) {
|
|
138
|
+
const finding = makeFinding(
|
|
139
|
+
'build-verification-evidence',
|
|
140
|
+
'error',
|
|
141
|
+
relPath,
|
|
142
|
+
'Build state does not record exact project verification commands that passed.'
|
|
143
|
+
);
|
|
144
|
+
result.findings.push(finding);
|
|
145
|
+
addFindingSummary(result.summary, finding.severity);
|
|
146
|
+
result.checks.push(makeCheck(
|
|
147
|
+
'build-verification-evidence',
|
|
148
|
+
'fail',
|
|
149
|
+
relPath,
|
|
150
|
+
finding.reason
|
|
151
|
+
));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
result.checks.push(makeCheck(
|
|
155
|
+
'build-verification-evidence',
|
|
156
|
+
'pass',
|
|
157
|
+
relPath,
|
|
158
|
+
`Build state records ${passedCommands.length} passed verification command(s).`
|
|
159
|
+
));
|
|
160
|
+
result.summary.buildVerificationCommands = passedCommands;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function checkHardenCriticals(projectRoot, result) {
|
|
164
|
+
const relPath = '.godpowers/harden/FINDINGS.md';
|
|
165
|
+
const file = relToAbs(projectRoot, relPath);
|
|
166
|
+
if (!fs.existsSync(file)) return;
|
|
167
|
+
const pass = router.hasNoCriticalFindings(projectRoot);
|
|
168
|
+
if (!pass) {
|
|
169
|
+
const finding = makeFinding(
|
|
170
|
+
'harden-critical-findings',
|
|
171
|
+
'error',
|
|
172
|
+
relPath,
|
|
173
|
+
'Harden findings contain unresolved Critical findings or a blocked launch gate.'
|
|
174
|
+
);
|
|
175
|
+
result.findings.push(finding);
|
|
176
|
+
addFindingSummary(result.summary, finding.severity);
|
|
177
|
+
}
|
|
178
|
+
result.checks.push(makeCheck(
|
|
179
|
+
'harden-critical-findings',
|
|
180
|
+
pass ? 'pass' : 'fail',
|
|
181
|
+
relPath,
|
|
182
|
+
pass
|
|
183
|
+
? 'No unresolved Critical findings or blocked launch gate found.'
|
|
184
|
+
: 'Unresolved Critical findings or a blocked launch gate block this gate.'
|
|
185
|
+
));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function finalize(result) {
|
|
189
|
+
result.verdict = result.findings.some((finding) => finding.severity === 'error')
|
|
190
|
+
? 'fail'
|
|
191
|
+
: 'pass';
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function check(opts = {}) {
|
|
196
|
+
const projectRoot = path.resolve(opts.projectRoot || opts.project || process.cwd());
|
|
197
|
+
const tier = artifactMap.normalizeTier(opts.tier);
|
|
198
|
+
const artifacts = artifactMap.artifactsForTier(tier);
|
|
199
|
+
const result = {
|
|
200
|
+
tier,
|
|
201
|
+
verdict: 'fail',
|
|
202
|
+
project: projectRoot,
|
|
203
|
+
artifacts: [],
|
|
204
|
+
checks: [],
|
|
205
|
+
findings: [],
|
|
206
|
+
summary: emptySummary()
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
if (!tier || !artifacts) {
|
|
210
|
+
const supported = artifactMap.tiers().join(', ');
|
|
211
|
+
const finding = makeFinding(
|
|
212
|
+
'unknown-tier',
|
|
213
|
+
'error',
|
|
214
|
+
null,
|
|
215
|
+
`Unknown gate tier. Supported tiers: ${supported}.`
|
|
216
|
+
);
|
|
217
|
+
result.findings.push(finding);
|
|
218
|
+
addFindingSummary(result.summary, finding.severity);
|
|
219
|
+
result.checks.push(makeCheck('tier-supported', 'fail', null, finding.reason));
|
|
220
|
+
return finalize(result);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
checkArtifacts(projectRoot, tier, artifacts, opts, result);
|
|
224
|
+
if (tier === 'build') checkBuildEvidence(projectRoot, result);
|
|
225
|
+
if (tier === 'harden') checkHardenCriticals(projectRoot, result);
|
|
226
|
+
return finalize(result);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function checkAsync(opts = {}) {
|
|
230
|
+
return check(opts);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function exitCode(result) {
|
|
234
|
+
return result.verdict === 'pass' ? 0 : 1;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function render(result) {
|
|
238
|
+
const lines = [];
|
|
239
|
+
lines.push(`Godpowers Gate: ${result.tier || 'unknown'}`);
|
|
240
|
+
lines.push(`Verdict: ${result.verdict}`);
|
|
241
|
+
lines.push('');
|
|
242
|
+
lines.push('Artifacts:');
|
|
243
|
+
for (const artifact of result.artifacts) {
|
|
244
|
+
const marker = artifact.exists ? '+' : (artifact.required ? 'x' : '-');
|
|
245
|
+
lines.push(` ${marker} ${artifact.path}${artifact.required ? '' : ' (optional)'}`);
|
|
246
|
+
}
|
|
247
|
+
lines.push('');
|
|
248
|
+
lines.push('Checks:');
|
|
249
|
+
for (const checkResult of result.checks) {
|
|
250
|
+
lines.push(` ${checkResult.status.toUpperCase()} ${checkResult.id}: ${checkResult.reason}`);
|
|
251
|
+
}
|
|
252
|
+
if (result.findings.length > 0) {
|
|
253
|
+
lines.push('');
|
|
254
|
+
lines.push('Findings:');
|
|
255
|
+
for (const finding of result.findings) {
|
|
256
|
+
const where = finding.artifact ? `${finding.artifact}: ` : '';
|
|
257
|
+
lines.push(` ${finding.severity.toUpperCase()} ${finding.id}: ${where}${finding.reason}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
lines.push('');
|
|
261
|
+
lines.push(`Summary: ${result.summary.errors} error(s), ${result.summary.warnings} warning(s), ${result.summary.infos} info finding(s)`);
|
|
262
|
+
return lines.join('\n');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
module.exports = {
|
|
266
|
+
check,
|
|
267
|
+
checkAsync,
|
|
268
|
+
extractPassedCommands,
|
|
269
|
+
exitCode,
|
|
270
|
+
render
|
|
271
|
+
};
|
package/lib/installer-args.js
CHANGED
|
@@ -8,7 +8,8 @@ const COMMANDS = new Set([
|
|
|
8
8
|
'automation-status',
|
|
9
9
|
'automation-setup',
|
|
10
10
|
'dogfood',
|
|
11
|
-
'extension-scaffold'
|
|
11
|
+
'extension-scaffold',
|
|
12
|
+
'gate'
|
|
12
13
|
]);
|
|
13
14
|
|
|
14
15
|
function parseArgs(argv, cwd = process.cwd()) {
|
|
@@ -23,6 +24,7 @@ function parseArgs(argv, cwd = process.cwd()) {
|
|
|
23
24
|
extensionSkill: null,
|
|
24
25
|
extensionAgent: null,
|
|
25
26
|
extensionWorkflow: null,
|
|
27
|
+
tier: null,
|
|
26
28
|
runtimes: [],
|
|
27
29
|
global: false,
|
|
28
30
|
local: false,
|
|
@@ -46,6 +48,12 @@ function parseArgs(argv, cwd = process.cwd()) {
|
|
|
46
48
|
case '--brief':
|
|
47
49
|
opts.brief = true;
|
|
48
50
|
break;
|
|
51
|
+
case '--tier':
|
|
52
|
+
if (args[i + 1]) {
|
|
53
|
+
opts.tier = args[i + 1];
|
|
54
|
+
i++;
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
49
57
|
case '--project':
|
|
50
58
|
if (args[i + 1]) {
|
|
51
59
|
opts.project = path.resolve(args[i + 1]);
|
|
@@ -93,6 +101,8 @@ function parseArgs(argv, cwd = process.cwd()) {
|
|
|
93
101
|
opts.extensionAgent = arg.slice('--agent='.length);
|
|
94
102
|
} else if (arg.startsWith('--workflow=')) {
|
|
95
103
|
opts.extensionWorkflow = arg.slice('--workflow='.length);
|
|
104
|
+
} else if (arg.startsWith('--tier=')) {
|
|
105
|
+
opts.tier = arg.slice('--tier='.length);
|
|
96
106
|
} else if (arg.startsWith('--profile=')) {
|
|
97
107
|
opts.profile = arg.slice('--profile='.length);
|
|
98
108
|
} else if (arg.startsWith('--') && RUNTIMES[arg.slice(2)]) {
|
|
@@ -89,6 +89,17 @@ const STANDARDS_EXEMPT_COMMANDS = new Set([
|
|
|
89
89
|
'/god-tech-debt'
|
|
90
90
|
]);
|
|
91
91
|
|
|
92
|
+
const TIER_GATE_COMMANDS = new Set([
|
|
93
|
+
'/god-prd',
|
|
94
|
+
'/god-design',
|
|
95
|
+
'/god-arch',
|
|
96
|
+
'/god-roadmap',
|
|
97
|
+
'/god-stack',
|
|
98
|
+
'/god-repo',
|
|
99
|
+
'/god-build',
|
|
100
|
+
'/god-harden'
|
|
101
|
+
]);
|
|
102
|
+
|
|
92
103
|
function read(projectRoot, relPath) {
|
|
93
104
|
const file = path.join(projectRoot, relPath);
|
|
94
105
|
if (!fs.existsSync(file)) return '';
|
|
@@ -166,6 +177,7 @@ function detect(projectRoot) {
|
|
|
166
177
|
let typedOutcomeCount = 0;
|
|
167
178
|
let standardsExemptCount = 0;
|
|
168
179
|
let traceEventMissingCount = 0;
|
|
180
|
+
let gateCommandCount = 0;
|
|
169
181
|
|
|
170
182
|
for (const routePath of routes) {
|
|
171
183
|
const route = parseRoute(projectRoot, routePath);
|
|
@@ -253,6 +265,24 @@ function detect(projectRoot) {
|
|
|
253
265
|
);
|
|
254
266
|
}
|
|
255
267
|
}
|
|
268
|
+
|
|
269
|
+
if (TIER_GATE_COMMANDS.has(command)) {
|
|
270
|
+
const tierName = command.replace('/god-', '');
|
|
271
|
+
const expected = `npx godpowers gate --tier=${tierName} --project=.`;
|
|
272
|
+
const actual = route.standards && route.standards['gate-command'];
|
|
273
|
+
if (actual === expected) {
|
|
274
|
+
gateCommandCount++;
|
|
275
|
+
} else {
|
|
276
|
+
addCheck(
|
|
277
|
+
checks,
|
|
278
|
+
`missing-gate-command-${command.replace(/[^a-z0-9]+/gi, '-')}`,
|
|
279
|
+
'stale',
|
|
280
|
+
routePath,
|
|
281
|
+
`${command} must declare standards.gate-command as ${expected}.`,
|
|
282
|
+
{ spawn: 'god-auditor' }
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
256
286
|
}
|
|
257
287
|
|
|
258
288
|
if (symbolicCount === 0) {
|
|
@@ -287,6 +317,14 @@ function detect(projectRoot) {
|
|
|
287
317
|
: `${traceEventMissingCount} agent-spawning routes are missing required trace events.`,
|
|
288
318
|
{ spawn: traceEventMissingCount === 0 ? null : 'god-auditor' }
|
|
289
319
|
);
|
|
320
|
+
addCheck(
|
|
321
|
+
checks,
|
|
322
|
+
'gate-command-policy',
|
|
323
|
+
checks.some((check) => check.id.startsWith('missing-gate-command-')) ? 'stale' : 'fresh',
|
|
324
|
+
'routing/',
|
|
325
|
+
`${gateCommandCount} tier routes declare executable gate commands.`,
|
|
326
|
+
{ spawn: checks.some((check) => check.id.startsWith('missing-gate-command-')) ? 'god-auditor' : null }
|
|
327
|
+
);
|
|
290
328
|
|
|
291
329
|
const stale = checks.filter((check) => check.status !== 'fresh');
|
|
292
330
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "godpowers",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "AI-powered development system: 112 slash commands and 40 specialist agents that take a project from raw idea to hardened production. Runs inside Claude Code, Codex, Cursor, Windsurf, Gemini, and 10+ other AI coding tools.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"godpowers": "./bin/install.js"
|
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
"test:diff": "node scripts/test-artifact-diff.js",
|
|
24
24
|
"test:e2e": "node tests/integration/full-arc.test.js",
|
|
25
25
|
"coverage": "c8 --reporter=text --reporter=lcov node scripts/run-tests.js",
|
|
26
|
+
"coverage:lib": "c8 --include=lib/**/*.js --check-coverage --lines 90 --reporter=text node scripts/run-tests.js",
|
|
26
27
|
"test:audit": "npm audit --omit=dev && git diff --check && npm run test:surface",
|
|
27
28
|
"pack:check": "node scripts/check-package-contents.js",
|
|
28
|
-
"release:check": "npm
|
|
29
|
+
"release:check": "npm run coverage:lib && npm run test:audit && npm run pack:check",
|
|
29
30
|
"lint": "node scripts/static-check.js"
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|
|
@@ -124,6 +124,25 @@ quality drift before declaring complete.
|
|
|
124
124
|
### --skip-hygiene
|
|
125
125
|
Default. Skip the hygiene pass. Use when iterating quickly.
|
|
126
126
|
|
|
127
|
+
## Tier transition gates
|
|
128
|
+
|
|
129
|
+
After each tier skill returns, run the matching executable gate before starting
|
|
130
|
+
the downstream tier:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx godpowers gate --tier=prd --project=.
|
|
134
|
+
npx godpowers gate --tier=design --project=.
|
|
135
|
+
npx godpowers gate --tier=arch --project=.
|
|
136
|
+
npx godpowers gate --tier=roadmap --project=.
|
|
137
|
+
npx godpowers gate --tier=stack --project=.
|
|
138
|
+
npx godpowers gate --tier=repo --project=.
|
|
139
|
+
npx godpowers gate --tier=build --project=.
|
|
140
|
+
npx godpowers gate --tier=harden --project=.
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Run the design gate only when the project requires design. A non-zero gate exit
|
|
144
|
+
pauses the project run for repair and blocks downstream tier dispatch.
|
|
145
|
+
|
|
127
146
|
## Mandatory final sync
|
|
128
147
|
|
|
129
148
|
Regardless of flags, `/god-mode` always runs `/god-sync` before declaring
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# God Next Runbook
|
|
2
|
+
|
|
3
|
+
This reference owns the detailed process notes for `/god-next`. The skill file stays a concise dispatch contract.
|
|
4
|
+
|
|
5
|
+
## Invocation modes
|
|
6
|
+
|
|
7
|
+
1. Post-completion routing reads `routing/<just-completed>.yaml`, applies success-path and conditional-next rules, runs any configured standards gate, and announces the next command.
|
|
8
|
+
2. Pre-flight routing reads `routing/<target>.yaml`, evaluates prerequisites, and offers auto-completable prerequisites before the target command runs.
|
|
9
|
+
3. Standalone routing reads disk state, uses `lib/router.js` for structural next steps, then uses recipes when the project is already in steady state.
|
|
10
|
+
4. Intent-based routing uses `lib/recipes.js` for fuzzy text, ranked recipes, and state-aware command sequences.
|
|
11
|
+
|
|
12
|
+
## Data sources
|
|
13
|
+
|
|
14
|
+
Use runtime routing YAML, recipes, `lib/command-families.js`, `lib/router.js`, `lib/dashboard.js`, state.json, PROGRESS.md, CHECKPOINT.md, and completed artifacts.
|
|
15
|
+
|
|
16
|
+
Read `.godpowers/prep/INITIAL-FINDINGS.md` and `.godpowers/prep/IMPORTED-CONTEXT.md` when present. Treat them as preparation context only.
|
|
17
|
+
|
|
18
|
+
## Route detail
|
|
19
|
+
|
|
20
|
+
When the suggestion is based on state.json, show a three-line path ahead: current state, next command, and the following gate if known.
|
|
21
|
+
|
|
22
|
+
When prerequisites are missing, name the missing prerequisite, the auto-completable command when available, and the exact decision needed from the user.
|
|
23
|
+
|
|
24
|
+
When a standards gate fails, show the failures, suggest `/god-redo` with feedback or `/god-skip` with a reason, and do not auto-progress.
|
|
25
|
+
|
|
26
|
+
## Edge cases
|
|
27
|
+
|
|
28
|
+
State drift routes to `/god-repair`. Safe sync blockers route to `/god-reconcile Release Truth And Safe Sync` before deploy, observe, harden, launch, broad migration, or resume work.
|
|
29
|
+
|
|
30
|
+
Unresolved Critical harden findings block launch in default mode and under `--yolo`.
|
|
31
|
+
|
|
32
|
+
In steady state, use the work-family ladders before raw route order so feature, hotfix, refactor, docs, dependency, audit, hygiene, and preflight intents resolve to the narrowest useful command.
|