godpowers 2.0.0 → 2.1.1
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/AGENTS.md +1 -1
- package/CHANGELOG.md +141 -0
- package/README.md +45 -5
- package/RELEASE.md +30 -48
- package/SKILL.md +9 -1
- package/agents/god-design-reviewer.md +6 -6
- package/agents/god-designer.md +1 -1
- package/agents/god-executor.md +23 -0
- package/agents/god-quality-reviewer.md +12 -1
- package/agents/god-spec-reviewer.md +10 -0
- package/bin/install.js +119 -655
- package/extensions/launch-pack/README.md +1 -1
- package/lib/README.md +16 -0
- package/lib/agent-browser-driver.js +13 -13
- package/lib/agent-cache.js +8 -1
- package/lib/agent-refs.js +161 -0
- package/lib/budget.js +25 -11
- package/lib/context-writer.js +17 -6
- package/lib/events.js +11 -4
- package/lib/extension-authoring.js +27 -0
- package/lib/feature-awareness.js +18 -0
- package/lib/fs-async.js +28 -0
- package/lib/installer-args.js +99 -0
- package/lib/installer-core.js +345 -0
- package/lib/installer-files.js +80 -0
- package/lib/installer-runtimes.js +112 -0
- package/lib/intent.js +111 -16
- package/lib/release-surface-sync.js +8 -1
- package/lib/repo-surface-sync.js +9 -2
- package/lib/review-required.js +2 -1
- package/lib/router.js +23 -3
- package/lib/skill-surface.js +42 -0
- package/lib/state-lock.js +10 -0
- package/lib/state.js +101 -8
- package/lib/workflow-runner.js +42 -5
- package/package.json +4 -3
- package/references/HAVE-NOTS.md +4 -3
- package/references/orchestration/GOD-MODE-RUNBOOK.md +273 -0
- package/routing/god-arch.yaml +1 -1
- package/routing/god-build.yaml +1 -1
- package/skills/god-add-backlog.md +1 -1
- package/skills/god-agent-audit.md +2 -2
- package/skills/god-build.md +5 -3
- package/skills/god-context-scan.md +2 -3
- package/skills/god-design.md +2 -2
- package/skills/god-doctor.md +2 -2
- package/skills/god-help.md +4 -3
- package/skills/god-mode.md +10 -266
- package/skills/god-org-context.md +1 -1
- package/skills/god-repair.md +3 -3
- package/skills/god-review.md +9 -0
- package/skills/god-stories.md +1 -1
- package/skills/god-version.md +2 -2
package/bin/install.js
CHANGED
|
@@ -1,137 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Godpowers
|
|
4
|
+
* Godpowers installer and local CLI helpers.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* The executable stays intentionally thin. Runtime definitions, argument
|
|
7
|
+
* parsing, and install/uninstall file operations live in lib/ so they can be
|
|
8
|
+
* tested and reused without shelling through the binary.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
|
-
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
const { parseArgs } = require('../lib/installer-args');
|
|
14
|
+
const { RUNTIMES, runtimeKeys } = require('../lib/installer-runtimes');
|
|
15
|
+
const {
|
|
16
|
+
installForRuntime,
|
|
17
|
+
uninstallForRuntime,
|
|
18
|
+
countInstalledSurface
|
|
19
|
+
} = require('../lib/installer-core');
|
|
13
20
|
|
|
14
21
|
const VERSION = require('../package.json').version;
|
|
15
22
|
|
|
16
23
|
const BANNER = `
|
|
17
|
-
██████╗ ██████╗ ██████╗
|
|
18
|
-
██╔════╝ ██╔═══██╗██╔══██╗
|
|
19
|
-
██║ ███╗██║ ██║██║ ██║
|
|
20
|
-
██║ ██║██║ ██║██║ ██║
|
|
21
|
-
╚██████╔╝╚██████╔╝██████╔╝
|
|
22
|
-
╚═════╝ ╚═════╝ ╚═════╝
|
|
23
24
|
GODPOWERS v${VERSION}
|
|
24
25
|
Ship fast. Ship right. Ship everything.
|
|
25
26
|
`;
|
|
26
27
|
|
|
27
|
-
const RUNTIMES = {
|
|
28
|
-
claude: {
|
|
29
|
-
name: 'Claude Code',
|
|
30
|
-
configDir: path.join(os.homedir(), '.claude'),
|
|
31
|
-
skillsDir: 'skills',
|
|
32
|
-
configFile: null,
|
|
33
|
-
},
|
|
34
|
-
codex: {
|
|
35
|
-
name: 'Codex',
|
|
36
|
-
configDir: path.join(os.homedir(), '.codex'),
|
|
37
|
-
skillsDir: 'skills',
|
|
38
|
-
configFile: 'config.toml',
|
|
39
|
-
agentMetadata: 'toml',
|
|
40
|
-
},
|
|
41
|
-
cursor: {
|
|
42
|
-
name: 'Cursor',
|
|
43
|
-
configDir: path.join(os.homedir(), '.cursor'),
|
|
44
|
-
skillsDir: 'rules',
|
|
45
|
-
configFile: null,
|
|
46
|
-
},
|
|
47
|
-
windsurf: {
|
|
48
|
-
name: 'Windsurf',
|
|
49
|
-
configDir: path.join(os.homedir(), '.windsurf'),
|
|
50
|
-
skillsDir: 'rules',
|
|
51
|
-
configFile: null,
|
|
52
|
-
},
|
|
53
|
-
opencode: {
|
|
54
|
-
name: 'OpenCode',
|
|
55
|
-
configDir: path.join(os.homedir(), '.opencode'),
|
|
56
|
-
skillsDir: 'skills',
|
|
57
|
-
configFile: null,
|
|
58
|
-
},
|
|
59
|
-
gemini: {
|
|
60
|
-
name: 'Gemini CLI',
|
|
61
|
-
configDir: path.join(os.homedir(), '.gemini'),
|
|
62
|
-
skillsDir: 'skills',
|
|
63
|
-
configFile: null,
|
|
64
|
-
},
|
|
65
|
-
copilot: {
|
|
66
|
-
name: 'GitHub Copilot',
|
|
67
|
-
configDir: path.join(os.homedir(), '.copilot'),
|
|
68
|
-
skillsDir: 'skills',
|
|
69
|
-
configFile: null,
|
|
70
|
-
},
|
|
71
|
-
augment: {
|
|
72
|
-
name: 'Augment',
|
|
73
|
-
configDir: path.join(os.homedir(), '.augment'),
|
|
74
|
-
skillsDir: 'skills',
|
|
75
|
-
configFile: null,
|
|
76
|
-
},
|
|
77
|
-
trae: {
|
|
78
|
-
name: 'Trae',
|
|
79
|
-
configDir: path.join(os.homedir(), '.trae'),
|
|
80
|
-
skillsDir: 'skills',
|
|
81
|
-
configFile: null,
|
|
82
|
-
},
|
|
83
|
-
cline: {
|
|
84
|
-
name: 'Cline',
|
|
85
|
-
configDir: path.join(os.homedir(), '.cline'),
|
|
86
|
-
skillsDir: 'skills',
|
|
87
|
-
configFile: null,
|
|
88
|
-
},
|
|
89
|
-
kilo: {
|
|
90
|
-
name: 'Kilo',
|
|
91
|
-
configDir: path.join(os.homedir(), '.kilo'),
|
|
92
|
-
skillsDir: 'skills',
|
|
93
|
-
configFile: null,
|
|
94
|
-
},
|
|
95
|
-
antigravity: {
|
|
96
|
-
name: 'Antigravity',
|
|
97
|
-
configDir: path.join(os.homedir(), '.antigravity'),
|
|
98
|
-
skillsDir: 'skills',
|
|
99
|
-
configFile: null,
|
|
100
|
-
},
|
|
101
|
-
qwen: {
|
|
102
|
-
name: 'Qwen Code',
|
|
103
|
-
configDir: path.join(os.homedir(), '.qwen'),
|
|
104
|
-
skillsDir: 'skills',
|
|
105
|
-
configFile: null,
|
|
106
|
-
},
|
|
107
|
-
codebuddy: {
|
|
108
|
-
name: 'CodeBuddy',
|
|
109
|
-
configDir: path.join(os.homedir(), '.codebuddy'),
|
|
110
|
-
skillsDir: 'skills',
|
|
111
|
-
configFile: null,
|
|
112
|
-
},
|
|
113
|
-
pi: {
|
|
114
|
-
name: 'Pi',
|
|
115
|
-
configDir: path.join(os.homedir(), '.pi'),
|
|
116
|
-
skillsDir: 'skills',
|
|
117
|
-
configFile: null,
|
|
118
|
-
},
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
function resolveRuntime(runtimeKey, opts = {}) {
|
|
122
|
-
const runtime = RUNTIMES[runtimeKey];
|
|
123
|
-
if (!runtime) return null;
|
|
124
|
-
const resolved = { ...runtime };
|
|
125
|
-
if (opts.local && !opts.global) {
|
|
126
|
-
resolved.configDir = path.join(process.cwd(), path.basename(runtime.configDir));
|
|
127
|
-
}
|
|
128
|
-
return resolved;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
// Helpers
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
|
|
135
28
|
function log(msg) {
|
|
136
29
|
console.log(` ${msg}`);
|
|
137
30
|
}
|
|
@@ -148,447 +41,6 @@ function error(msg) {
|
|
|
148
41
|
console.error(` \x1b[31mx\x1b[0m ${msg}`);
|
|
149
42
|
}
|
|
150
43
|
|
|
151
|
-
function ensureDir(dir) {
|
|
152
|
-
if (!fs.existsSync(dir)) {
|
|
153
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function copyRecursive(src, dest) {
|
|
158
|
-
ensureDir(dest);
|
|
159
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
160
|
-
for (const entry of entries) {
|
|
161
|
-
const srcPath = path.join(src, entry.name);
|
|
162
|
-
const destPath = path.join(dest, entry.name);
|
|
163
|
-
if (entry.isDirectory()) {
|
|
164
|
-
copyRecursive(srcPath, destPath);
|
|
165
|
-
} else {
|
|
166
|
-
fs.copyFileSync(srcPath, destPath);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function copyRuntimeBundle(srcDir, destDir) {
|
|
172
|
-
ensureDir(destDir);
|
|
173
|
-
for (const dir of ['lib', 'routing', 'workflows', 'schema', 'templates', 'references']) {
|
|
174
|
-
const src = path.join(srcDir, dir);
|
|
175
|
-
if (fs.existsSync(src)) {
|
|
176
|
-
copyRecursive(src, path.join(destDir, dir));
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
const packageJson = path.join(srcDir, 'package.json');
|
|
180
|
-
if (fs.existsSync(packageJson)) {
|
|
181
|
-
fs.copyFileSync(packageJson, path.join(destDir, 'package.json'));
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function installSkillFile(srcFile, skillsDest, runtimeKey, targetName = null) {
|
|
186
|
-
const baseName = targetName || path.basename(srcFile, '.md');
|
|
187
|
-
if (runtimeKey === 'codex') {
|
|
188
|
-
const skillDir = path.join(skillsDest, baseName);
|
|
189
|
-
if (fs.existsSync(skillDir)) {
|
|
190
|
-
fs.rmSync(skillDir, { recursive: true, force: true });
|
|
191
|
-
}
|
|
192
|
-
ensureDir(skillDir);
|
|
193
|
-
fs.copyFileSync(srcFile, path.join(skillDir, 'SKILL.md'));
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
fs.copyFileSync(srcFile, path.join(skillsDest, `${baseName}.md`));
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function parseAgentFrontmatter(content) {
|
|
200
|
-
const fallback = { name: null, description: null };
|
|
201
|
-
if (!content.startsWith('---\n')) return fallback;
|
|
202
|
-
|
|
203
|
-
const end = content.indexOf('\n---', 4);
|
|
204
|
-
if (end === -1) return fallback;
|
|
205
|
-
|
|
206
|
-
const lines = content.slice(4, end).split('\n');
|
|
207
|
-
const parsed = { ...fallback };
|
|
208
|
-
|
|
209
|
-
for (let i = 0; i < lines.length; i++) {
|
|
210
|
-
const line = lines[i];
|
|
211
|
-
const nameMatch = line.match(/^name:\s*(.+)\s*$/);
|
|
212
|
-
if (nameMatch) {
|
|
213
|
-
parsed.name = nameMatch[1].replace(/^["']|["']$/g, '');
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (line === 'description: |') {
|
|
218
|
-
const desc = [];
|
|
219
|
-
i++;
|
|
220
|
-
while (i < lines.length && /^ {2}/.test(lines[i])) {
|
|
221
|
-
desc.push(lines[i].slice(2));
|
|
222
|
-
i++;
|
|
223
|
-
}
|
|
224
|
-
i--;
|
|
225
|
-
parsed.description = desc.join('\n').trim();
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const descMatch = line.match(/^description:\s*(.+)\s*$/);
|
|
230
|
-
if (descMatch) {
|
|
231
|
-
parsed.description = descMatch[1].replace(/^["']|["']$/g, '');
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return parsed;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function stripFrontmatter(content) {
|
|
239
|
-
if (!content.startsWith('---\n')) return content.trim();
|
|
240
|
-
const end = content.indexOf('\n---', 4);
|
|
241
|
-
if (end === -1) return content.trim();
|
|
242
|
-
return content.slice(end + 4).trim();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function tomlString(value) {
|
|
246
|
-
return JSON.stringify(value || '');
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function tomlLiteral(value) {
|
|
250
|
-
return `'''\n${(value || '').replace(/'''/g, "'''\\'''")}\n'''`;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
function writeCodexAgentToml(srcFile, agentsDest) {
|
|
254
|
-
const content = fs.readFileSync(srcFile, 'utf8');
|
|
255
|
-
const frontmatter = parseAgentFrontmatter(content);
|
|
256
|
-
const name = frontmatter.name || path.basename(srcFile, '.md');
|
|
257
|
-
const description = frontmatter.description || `Godpowers specialist agent: ${name}.`;
|
|
258
|
-
const instructions = stripFrontmatter(content);
|
|
259
|
-
const toml = [
|
|
260
|
-
`name = ${tomlString(name)}`,
|
|
261
|
-
`description = ${tomlString(description)}`,
|
|
262
|
-
'sandbox_mode = "workspace-write"',
|
|
263
|
-
`developer_instructions = ${tomlLiteral(instructions)}`,
|
|
264
|
-
''
|
|
265
|
-
].join('\n');
|
|
266
|
-
|
|
267
|
-
fs.writeFileSync(path.join(agentsDest, `${name}.toml`), toml);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function installAgentFile(srcFile, agentsDest, runtime) {
|
|
271
|
-
fs.copyFileSync(srcFile, path.join(agentsDest, path.basename(srcFile)));
|
|
272
|
-
if (runtime.agentMetadata === 'toml') {
|
|
273
|
-
writeCodexAgentToml(srcFile, agentsDest);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function removeSkillEntry(skillsDir, entry) {
|
|
278
|
-
const entryPath = path.join(skillsDir, entry.name);
|
|
279
|
-
if (entry.isDirectory()) {
|
|
280
|
-
const skillFile = path.join(entryPath, 'SKILL.md');
|
|
281
|
-
if (entry.name.startsWith('god-') || entry.name === 'god' || entry.name === 'godpowers') {
|
|
282
|
-
if (fs.existsSync(skillFile)) {
|
|
283
|
-
fs.rmSync(entryPath, { recursive: true, force: true });
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return false;
|
|
288
|
-
}
|
|
289
|
-
if (entry.name.startsWith('god-') || entry.name === 'god.md' || entry.name === 'godpowers.md') {
|
|
290
|
-
fs.unlinkSync(entryPath);
|
|
291
|
-
return true;
|
|
292
|
-
}
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// ---------------------------------------------------------------------------
|
|
297
|
-
// Parse args
|
|
298
|
-
// ---------------------------------------------------------------------------
|
|
299
|
-
|
|
300
|
-
function parseArgs(argv) {
|
|
301
|
-
const args = argv.slice(2);
|
|
302
|
-
const opts = {
|
|
303
|
-
command: null,
|
|
304
|
-
project: process.cwd(),
|
|
305
|
-
json: false,
|
|
306
|
-
brief: false,
|
|
307
|
-
extensionName: null,
|
|
308
|
-
extensionOutput: process.cwd(),
|
|
309
|
-
extensionSkill: null,
|
|
310
|
-
extensionAgent: null,
|
|
311
|
-
extensionWorkflow: null,
|
|
312
|
-
runtimes: [],
|
|
313
|
-
global: false,
|
|
314
|
-
local: false,
|
|
315
|
-
all: false,
|
|
316
|
-
help: false,
|
|
317
|
-
uninstall: false,
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
for (let i = 0; i < args.length; i++) {
|
|
321
|
-
const arg = args[i];
|
|
322
|
-
switch (arg) {
|
|
323
|
-
case 'status':
|
|
324
|
-
case 'next':
|
|
325
|
-
case 'quick-proof':
|
|
326
|
-
case 'automation-status':
|
|
327
|
-
case 'automation-setup':
|
|
328
|
-
case 'dogfood':
|
|
329
|
-
case 'extension-scaffold':
|
|
330
|
-
opts.command = arg;
|
|
331
|
-
break;
|
|
332
|
-
case '--json':
|
|
333
|
-
opts.json = true;
|
|
334
|
-
break;
|
|
335
|
-
case '--brief':
|
|
336
|
-
opts.brief = true;
|
|
337
|
-
break;
|
|
338
|
-
case '--project':
|
|
339
|
-
if (args[i + 1]) {
|
|
340
|
-
opts.project = path.resolve(args[i + 1]);
|
|
341
|
-
i++;
|
|
342
|
-
}
|
|
343
|
-
break;
|
|
344
|
-
case '-g':
|
|
345
|
-
case '--global':
|
|
346
|
-
opts.global = true;
|
|
347
|
-
break;
|
|
348
|
-
case '-l':
|
|
349
|
-
case '--local':
|
|
350
|
-
opts.local = true;
|
|
351
|
-
break;
|
|
352
|
-
case '--all':
|
|
353
|
-
opts.all = true;
|
|
354
|
-
break;
|
|
355
|
-
case '-h':
|
|
356
|
-
case '--help':
|
|
357
|
-
opts.help = true;
|
|
358
|
-
break;
|
|
359
|
-
case '-u':
|
|
360
|
-
case '--uninstall':
|
|
361
|
-
opts.uninstall = true;
|
|
362
|
-
break;
|
|
363
|
-
default:
|
|
364
|
-
if (arg.startsWith('--project=')) {
|
|
365
|
-
opts.project = path.resolve(arg.slice('--project='.length));
|
|
366
|
-
} else if (arg.startsWith('--name=')) {
|
|
367
|
-
opts.extensionName = arg.slice('--name='.length);
|
|
368
|
-
} else if (arg.startsWith('--output=')) {
|
|
369
|
-
opts.extensionOutput = path.resolve(arg.slice('--output='.length));
|
|
370
|
-
} else if (arg.startsWith('--skill=')) {
|
|
371
|
-
opts.extensionSkill = arg.slice('--skill='.length);
|
|
372
|
-
} else if (arg.startsWith('--agent=')) {
|
|
373
|
-
opts.extensionAgent = arg.slice('--agent='.length);
|
|
374
|
-
} else if (arg.startsWith('--workflow=')) {
|
|
375
|
-
opts.extensionWorkflow = arg.slice('--workflow='.length);
|
|
376
|
-
} else if (arg.startsWith('--') && RUNTIMES[arg.slice(2)]) {
|
|
377
|
-
opts.runtimes.push(arg.slice(2));
|
|
378
|
-
}
|
|
379
|
-
break;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
return opts;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// ---------------------------------------------------------------------------
|
|
387
|
-
// Install
|
|
388
|
-
// ---------------------------------------------------------------------------
|
|
389
|
-
|
|
390
|
-
function installForRuntime(runtimeKey, srcDir, opts = {}) {
|
|
391
|
-
const runtime = resolveRuntime(runtimeKey, opts);
|
|
392
|
-
if (!runtime) {
|
|
393
|
-
error(`Unknown runtime: ${runtimeKey}`);
|
|
394
|
-
return false;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
log(`\n Installing for \x1b[36m${runtime.name}\x1b[0m to \x1b[36m${runtime.configDir}\x1b[0m\n`);
|
|
398
|
-
|
|
399
|
-
ensureDir(runtime.configDir);
|
|
400
|
-
|
|
401
|
-
// 1. Install slash command skills to skills/
|
|
402
|
-
// Each skill in skills/ becomes a slash command (e.g. /god-mode)
|
|
403
|
-
const skillsSrc = path.join(srcDir, 'skills');
|
|
404
|
-
const skillsDest = path.join(runtime.configDir, runtime.skillsDir);
|
|
405
|
-
if (fs.existsSync(skillsSrc)) {
|
|
406
|
-
ensureDir(skillsDest);
|
|
407
|
-
let count = 0;
|
|
408
|
-
for (const file of fs.readdirSync(skillsSrc)) {
|
|
409
|
-
if (file.endsWith('.md')) {
|
|
410
|
-
installSkillFile(path.join(skillsSrc, file), skillsDest, runtimeKey);
|
|
411
|
-
count++;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
const shape = runtimeKey === 'codex' ? 'Codex skill directories' : 'skills/';
|
|
415
|
-
success(`Installed ${count} slash commands to ${shape}`);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// 2. Install specialist agents to agents/
|
|
419
|
-
// Each agent is spawnable from a skill (e.g., god-pm, god-architect, god-executor)
|
|
420
|
-
const agentsSrc = path.join(srcDir, 'agents');
|
|
421
|
-
const agentsDest = path.join(runtime.configDir, 'agents');
|
|
422
|
-
if (fs.existsSync(agentsSrc)) {
|
|
423
|
-
ensureDir(agentsDest);
|
|
424
|
-
let count = 0;
|
|
425
|
-
for (const file of fs.readdirSync(agentsSrc)) {
|
|
426
|
-
if (/^god-.*\.md$/.test(file)) {
|
|
427
|
-
const srcFile = path.join(agentsSrc, file);
|
|
428
|
-
installAgentFile(srcFile, agentsDest, runtime);
|
|
429
|
-
count++;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
const shape = runtime.agentMetadata === 'toml' ? 'agents/ with Codex metadata' : 'agents/';
|
|
433
|
-
success(`Installed ${count} specialist agents to ${shape}`);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// 3. Install the master SKILL.md (always-on context)
|
|
437
|
-
const masterSkill = path.join(srcDir, 'SKILL.md');
|
|
438
|
-
if (fs.existsSync(masterSkill)) {
|
|
439
|
-
installSkillFile(masterSkill, skillsDest, runtimeKey, 'godpowers');
|
|
440
|
-
success('Installed master SKILL.md as godpowers');
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// 4. Install templates
|
|
444
|
-
const templatesSrc = path.join(srcDir, 'templates');
|
|
445
|
-
if (fs.existsSync(templatesSrc)) {
|
|
446
|
-
const templatesDest = path.join(runtime.configDir, 'godpowers-templates');
|
|
447
|
-
copyRecursive(templatesSrc, templatesDest);
|
|
448
|
-
success('Installed templates/');
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// 4b. Install references (HAVE-NOTS catalog and per-tier antipatterns)
|
|
452
|
-
const referencesSrc = path.join(srcDir, 'references');
|
|
453
|
-
if (fs.existsSync(referencesSrc)) {
|
|
454
|
-
const referencesDest = path.join(runtime.configDir, 'godpowers-references');
|
|
455
|
-
copyRecursive(referencesSrc, referencesDest);
|
|
456
|
-
success('Installed references/');
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// 4c. Install workflows (declarative YAML for /god-mode and friends)
|
|
460
|
-
const workflowsSrc = path.join(srcDir, 'workflows');
|
|
461
|
-
if (fs.existsSync(workflowsSrc)) {
|
|
462
|
-
const workflowsDest = path.join(runtime.configDir, 'godpowers-workflows');
|
|
463
|
-
copyRecursive(workflowsSrc, workflowsDest);
|
|
464
|
-
success('Installed workflows/');
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// 4d. Install schemas (for validation)
|
|
468
|
-
const schemaSrc = path.join(srcDir, 'schema');
|
|
469
|
-
if (fs.existsSync(schemaSrc)) {
|
|
470
|
-
const schemaDest = path.join(runtime.configDir, 'godpowers-schema');
|
|
471
|
-
copyRecursive(schemaSrc, schemaDest);
|
|
472
|
-
success('Installed schema/');
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// 4e. Install routing definitions (per-command prerequisites + next-suggestions)
|
|
476
|
-
const routingSrc = path.join(srcDir, 'routing');
|
|
477
|
-
if (fs.existsSync(routingSrc)) {
|
|
478
|
-
const routingDest = path.join(runtime.configDir, 'godpowers-routing');
|
|
479
|
-
copyRecursive(routingSrc, routingDest);
|
|
480
|
-
success('Installed routing/');
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
// 4f. Install the executable runtime bundle with lib/ next to its data dirs.
|
|
484
|
-
const runtimeBundleDest = path.join(runtime.configDir, 'godpowers-runtime');
|
|
485
|
-
copyRuntimeBundle(srcDir, runtimeBundleDest);
|
|
486
|
-
success('Installed runtime bundle/');
|
|
487
|
-
|
|
488
|
-
// 5. Install hooks (Claude Code only for now)
|
|
489
|
-
if (runtimeKey === 'claude') {
|
|
490
|
-
const hooksSrc = path.join(srcDir, 'hooks');
|
|
491
|
-
const hooksDest = path.join(runtime.configDir, 'hooks');
|
|
492
|
-
if (fs.existsSync(hooksSrc)) {
|
|
493
|
-
ensureDir(hooksDest);
|
|
494
|
-
for (const file of fs.readdirSync(hooksSrc)) {
|
|
495
|
-
const src = path.join(hooksSrc, file);
|
|
496
|
-
const dest = path.join(hooksDest, file);
|
|
497
|
-
fs.copyFileSync(src, dest);
|
|
498
|
-
try { fs.chmodSync(dest, 0o755); } catch (e) {}
|
|
499
|
-
}
|
|
500
|
-
success('Installed hooks/');
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// 6. Write VERSION
|
|
505
|
-
fs.writeFileSync(path.join(runtime.configDir, 'GODPOWERS_VERSION'), VERSION);
|
|
506
|
-
success(`Wrote GODPOWERS_VERSION (${VERSION})`);
|
|
507
|
-
|
|
508
|
-
return true;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// ---------------------------------------------------------------------------
|
|
512
|
-
// Uninstall
|
|
513
|
-
// ---------------------------------------------------------------------------
|
|
514
|
-
|
|
515
|
-
function uninstallForRuntime(runtimeKey, opts = {}) {
|
|
516
|
-
const runtime = resolveRuntime(runtimeKey, opts);
|
|
517
|
-
if (!runtime) {
|
|
518
|
-
error(`Unknown runtime: ${runtimeKey}`);
|
|
519
|
-
return false;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
log(`\n Uninstalling from \x1b[36m${runtime.name}\x1b[0m at \x1b[36m${runtime.configDir}\x1b[0m\n`);
|
|
523
|
-
|
|
524
|
-
const skillsDir = path.join(runtime.configDir, runtime.skillsDir);
|
|
525
|
-
const agentsDir = path.join(runtime.configDir, 'agents');
|
|
526
|
-
const templatesDir = path.join(runtime.configDir, 'godpowers-templates');
|
|
527
|
-
const referencesDir = path.join(runtime.configDir, 'godpowers-references');
|
|
528
|
-
const workflowsDir = path.join(runtime.configDir, 'godpowers-workflows');
|
|
529
|
-
const schemaDir = path.join(runtime.configDir, 'godpowers-schema');
|
|
530
|
-
const routingDir = path.join(runtime.configDir, 'godpowers-routing');
|
|
531
|
-
const runtimeBundleDir = path.join(runtime.configDir, 'godpowers-runtime');
|
|
532
|
-
const versionFile = path.join(runtime.configDir, 'GODPOWERS_VERSION');
|
|
533
|
-
|
|
534
|
-
let removed = 0;
|
|
535
|
-
|
|
536
|
-
// Remove all god-* skills
|
|
537
|
-
if (fs.existsSync(skillsDir)) {
|
|
538
|
-
for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
539
|
-
if (removeSkillEntry(skillsDir, entry)) {
|
|
540
|
-
removed++;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
success(`Removed ${removed} god-* skill(s)`);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
// Remove all god-* agents
|
|
547
|
-
let agentsRemoved = 0;
|
|
548
|
-
if (fs.existsSync(agentsDir)) {
|
|
549
|
-
for (const file of fs.readdirSync(agentsDir)) {
|
|
550
|
-
if (file.startsWith('god-')) {
|
|
551
|
-
fs.unlinkSync(path.join(agentsDir, file));
|
|
552
|
-
agentsRemoved++;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
success(`Removed ${agentsRemoved} god-* agent(s)`);
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
// Remove installed data and runtime directories
|
|
559
|
-
for (const dir of [
|
|
560
|
-
templatesDir,
|
|
561
|
-
referencesDir,
|
|
562
|
-
workflowsDir,
|
|
563
|
-
schemaDir,
|
|
564
|
-
routingDir,
|
|
565
|
-
runtimeBundleDir
|
|
566
|
-
]) {
|
|
567
|
-
if (fs.existsSync(dir)) {
|
|
568
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
569
|
-
success(`Removed ${path.basename(dir)}/`);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// Remove hooks (Claude Code only)
|
|
574
|
-
if (runtimeKey === 'claude') {
|
|
575
|
-
const hooksDir = path.join(runtime.configDir, 'hooks');
|
|
576
|
-
for (const hook of ['session-start.sh', 'pre-tool-use.sh']) {
|
|
577
|
-
const hookPath = path.join(hooksDir, hook);
|
|
578
|
-
if (fs.existsSync(hookPath)) {
|
|
579
|
-
fs.unlinkSync(hookPath);
|
|
580
|
-
success(`Removed hooks/${hook}`);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (fs.existsSync(versionFile)) {
|
|
586
|
-
fs.unlinkSync(versionFile);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
return true;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
44
|
function showHelp() {
|
|
593
45
|
console.log(BANNER);
|
|
594
46
|
log('Usage: npx godpowers [command] [options]\n');
|
|
@@ -610,8 +62,8 @@ function showHelp() {
|
|
|
610
62
|
log(' --skill=<name> Extension skill name for extension-scaffold');
|
|
611
63
|
log(' --agent=<name> Extension agent name for extension-scaffold');
|
|
612
64
|
log(' --workflow=<name> Extension workflow name for extension-scaffold');
|
|
613
|
-
log(' -g, --global Install globally
|
|
614
|
-
log(' -l, --local Install locally
|
|
65
|
+
log(' -g, --global Install globally to the config directory');
|
|
66
|
+
log(' -l, --local Install locally to the current directory');
|
|
615
67
|
log(' --claude Install for Claude Code');
|
|
616
68
|
log(' --codex Install for Codex');
|
|
617
69
|
log(' --cursor Install for Cursor');
|
|
@@ -663,13 +115,14 @@ function runDashboardCommand(opts) {
|
|
|
663
115
|
const result = dashboard.compute(opts.project);
|
|
664
116
|
if (opts.json) {
|
|
665
117
|
console.log(JSON.stringify(result, null, 2));
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log(dashboard.render(result, { brief: opts.brief }));
|
|
122
|
+
if (opts.command === 'next') {
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log('Suggested next command:');
|
|
125
|
+
console.log(` ${result.next && result.next.command ? result.next.command : 'describe the next intent'}`);
|
|
673
126
|
}
|
|
674
127
|
}
|
|
675
128
|
|
|
@@ -709,95 +162,75 @@ function runExtensionScaffoldCommand(opts) {
|
|
|
709
162
|
});
|
|
710
163
|
if (opts.json) {
|
|
711
164
|
console.log(JSON.stringify(result, null, 2));
|
|
712
|
-
|
|
713
|
-
success(`Scaffolded ${result.name} at ${result.path}`);
|
|
714
|
-
if (result.written.length > 0) {
|
|
715
|
-
log(`Wrote ${result.written.length} file(s): ${result.written.join(', ')}`);
|
|
716
|
-
}
|
|
717
|
-
if (result.validation.length > 0) {
|
|
718
|
-
warn(`Validation warnings: ${result.validation.join('; ')}`);
|
|
719
|
-
} else {
|
|
720
|
-
success('Extension manifest validates');
|
|
721
|
-
}
|
|
165
|
+
return;
|
|
722
166
|
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// ---------------------------------------------------------------------------
|
|
726
|
-
// Main
|
|
727
|
-
// ---------------------------------------------------------------------------
|
|
728
167
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
if (opts.help) {
|
|
733
|
-
showHelp();
|
|
734
|
-
process.exit(0);
|
|
168
|
+
success(`Scaffolded ${result.name} at ${result.path}`);
|
|
169
|
+
if (result.written.length > 0) {
|
|
170
|
+
log(`Wrote ${result.written.length} file(s): ${result.written.join(', ')}`);
|
|
735
171
|
}
|
|
172
|
+
if (result.validation.length > 0) {
|
|
173
|
+
warn(`Validation warnings: ${result.validation.join('; ')}`);
|
|
174
|
+
} else {
|
|
175
|
+
success('Extension manifest validates');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
736
178
|
|
|
179
|
+
function runCommand(opts) {
|
|
737
180
|
if (opts.command === 'status' || opts.command === 'next') {
|
|
738
181
|
runDashboardCommand(opts);
|
|
739
|
-
return;
|
|
182
|
+
return true;
|
|
740
183
|
}
|
|
741
|
-
|
|
742
184
|
if (opts.command === 'quick-proof') {
|
|
743
185
|
runQuickProofCommand(opts);
|
|
744
|
-
return;
|
|
186
|
+
return true;
|
|
745
187
|
}
|
|
746
|
-
|
|
747
188
|
if (opts.command === 'automation-status' || opts.command === 'automation-setup') {
|
|
748
189
|
runAutomationCommand(opts);
|
|
749
|
-
return;
|
|
190
|
+
return true;
|
|
750
191
|
}
|
|
751
|
-
|
|
752
192
|
if (opts.command === 'dogfood') {
|
|
753
193
|
runDogfoodCommand(opts);
|
|
754
|
-
return;
|
|
194
|
+
return true;
|
|
755
195
|
}
|
|
756
|
-
|
|
757
196
|
if (opts.command === 'extension-scaffold') {
|
|
758
197
|
runExtensionScaffoldCommand(opts);
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
console.log(BANNER);
|
|
763
|
-
|
|
764
|
-
const srcDir = path.resolve(__dirname, '..');
|
|
765
|
-
|
|
766
|
-
// Detect non-interactive and default to Claude Code.
|
|
767
|
-
if (opts.runtimes.length === 0 && !opts.all) {
|
|
768
|
-
if (!process.stdin.isTTY) {
|
|
769
|
-
warn('Non-interactive terminal detected, defaulting to Claude Code install');
|
|
770
|
-
opts.runtimes = ['claude'];
|
|
771
|
-
if (!opts.local) opts.global = true;
|
|
772
|
-
} else {
|
|
773
|
-
// Interactive mode: default to claude
|
|
774
|
-
opts.runtimes = ['claude'];
|
|
775
|
-
if (!opts.local) opts.global = true;
|
|
776
|
-
}
|
|
198
|
+
return true;
|
|
777
199
|
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
778
202
|
|
|
779
|
-
|
|
780
|
-
|
|
203
|
+
function applyDefaultRuntimeSelection(opts) {
|
|
204
|
+
if (opts.runtimes.length > 0 || opts.all) return;
|
|
205
|
+
if (!process.stdin.isTTY) {
|
|
206
|
+
// Refuse to perform a silent global install when there is no human to
|
|
207
|
+
// confirm and no explicit target was given (CI, piped, some npx contexts).
|
|
208
|
+
warn('No runtime selected and stdin is not a TTY.');
|
|
209
|
+
warn('Refusing a silent global install. Re-run with an explicit target,');
|
|
210
|
+
warn('for example: npx godpowers --claude --global (or --all).');
|
|
211
|
+
process.exit(1);
|
|
781
212
|
}
|
|
213
|
+
opts.runtimes = ['claude'];
|
|
214
|
+
if (!opts.local) opts.global = true;
|
|
215
|
+
}
|
|
782
216
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
removed++;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
log('');
|
|
792
|
-
if (removed > 0) {
|
|
793
|
-
log(`\x1b[32mUninstalled\x1b[0m from ${removed} runtime(s).`);
|
|
794
|
-
} else {
|
|
795
|
-
warn('No runtimes uninstalled.');
|
|
217
|
+
function runUninstall(opts) {
|
|
218
|
+
let removed = 0;
|
|
219
|
+
for (const runtime of opts.runtimes) {
|
|
220
|
+
if (uninstallForRuntime(runtime, opts)) {
|
|
221
|
+
removed++;
|
|
796
222
|
}
|
|
797
|
-
log('');
|
|
798
|
-
return;
|
|
799
223
|
}
|
|
224
|
+
log('');
|
|
225
|
+
if (removed > 0) {
|
|
226
|
+
log(`\x1b[32mUninstalled\x1b[0m from ${removed} runtime(s).`);
|
|
227
|
+
} else {
|
|
228
|
+
warn('No runtimes uninstalled.');
|
|
229
|
+
}
|
|
230
|
+
log('');
|
|
231
|
+
}
|
|
800
232
|
|
|
233
|
+
function runInstall(opts, srcDir) {
|
|
801
234
|
let installed = 0;
|
|
802
235
|
for (const runtime of opts.runtimes) {
|
|
803
236
|
if (installForRuntime(runtime, srcDir, opts)) {
|
|
@@ -805,31 +238,62 @@ function main() {
|
|
|
805
238
|
}
|
|
806
239
|
}
|
|
807
240
|
|
|
808
|
-
if (installed
|
|
809
|
-
// Count slash commands for verification message
|
|
810
|
-
const skillsCount = fs.readdirSync(path.join(srcDir, 'skills')).filter(f => f.endsWith('.md')).length;
|
|
811
|
-
const agentsCount = fs.readdirSync(path.join(srcDir, 'agents')).filter(f => /^god-.*\.md$/.test(f)).length;
|
|
812
|
-
|
|
813
|
-
log('');
|
|
814
|
-
log(`\x1b[32mDone!\x1b[0m Installed Godpowers v${VERSION} for ${installed} runtime(s).`);
|
|
815
|
-
log('');
|
|
816
|
-
log(`\x1b[36mInstalled:\x1b[0m`);
|
|
817
|
-
log(` ${skillsCount} slash commands (try: /god-mode, /god-next, /god-status)`);
|
|
818
|
-
log(` ${agentsCount} specialist agents`);
|
|
819
|
-
log(` Templates and references for artifact discipline`);
|
|
820
|
-
log('');
|
|
821
|
-
log(`\x1b[36mNext steps:\x1b[0m`);
|
|
822
|
-
log(` 1. Open your AI coding tool in any project directory`);
|
|
823
|
-
log(` 2. Type: \x1b[36m/god-mode\x1b[0m for the full autonomous project run`);
|
|
824
|
-
log(` Or: \x1b[36m/god-next\x1b[0m to see what to run next`);
|
|
825
|
-
log(` Or: \x1b[36m/god-init\x1b[0m to start a new project`);
|
|
826
|
-
log('');
|
|
827
|
-
log(`\x1b[36mDocs:\x1b[0m https://github.com/godpowers/godpowers`);
|
|
828
|
-
log('');
|
|
829
|
-
} else {
|
|
241
|
+
if (installed === 0) {
|
|
830
242
|
error('No runtimes installed. Run with --help for usage.');
|
|
831
243
|
process.exit(1);
|
|
832
244
|
}
|
|
245
|
+
|
|
246
|
+
const surface = countInstalledSurface(srcDir);
|
|
247
|
+
log('');
|
|
248
|
+
log(`\x1b[32mDone!\x1b[0m Installed Godpowers v${VERSION} for ${installed} runtime(s).`);
|
|
249
|
+
log('');
|
|
250
|
+
log(`\x1b[36mInstalled:\x1b[0m`);
|
|
251
|
+
log(` ${surface.skills} slash commands (try: /god-mode, /god-next, /god-status)`);
|
|
252
|
+
log(` ${surface.agents} specialist agents`);
|
|
253
|
+
log(' Templates and references for artifact discipline');
|
|
254
|
+
log('');
|
|
255
|
+
log(`\x1b[36mNext steps:\x1b[0m`);
|
|
256
|
+
log(' 1. Open your AI coding tool in any project directory');
|
|
257
|
+
log(` 2. Type: \x1b[36m/god-mode\x1b[0m for the full autonomous project run`);
|
|
258
|
+
log(` Or: \x1b[36m/god-next\x1b[0m to see what to run next`);
|
|
259
|
+
log(` Or: \x1b[36m/god-init\x1b[0m to start a new project`);
|
|
260
|
+
log('');
|
|
261
|
+
log(`\x1b[36mDocs:\x1b[0m https://github.com/godpowers/godpowers`);
|
|
262
|
+
log('');
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function main() {
|
|
266
|
+
const opts = parseArgs(process.argv);
|
|
267
|
+
|
|
268
|
+
if (opts.help) {
|
|
269
|
+
showHelp();
|
|
270
|
+
process.exit(0);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (runCommand(opts)) return;
|
|
274
|
+
|
|
275
|
+
console.log(BANNER);
|
|
276
|
+
const srcDir = path.resolve(__dirname, '..');
|
|
277
|
+
|
|
278
|
+
applyDefaultRuntimeSelection(opts);
|
|
279
|
+
if (opts.all) {
|
|
280
|
+
opts.runtimes = runtimeKeys();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (opts.uninstall) {
|
|
284
|
+
runUninstall(opts);
|
|
285
|
+
} else {
|
|
286
|
+
runInstall(opts, srcDir);
|
|
287
|
+
}
|
|
833
288
|
}
|
|
834
289
|
|
|
835
290
|
main();
|
|
291
|
+
|
|
292
|
+
module.exports = {
|
|
293
|
+
showHelp,
|
|
294
|
+
runCommand,
|
|
295
|
+
applyDefaultRuntimeSelection,
|
|
296
|
+
runInstall,
|
|
297
|
+
runUninstall,
|
|
298
|
+
RUNTIMES
|
|
299
|
+
};
|