godpowers 1.6.24 → 2.1.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/AGENTS.md +1 -1
- package/CHANGELOG.md +166 -0
- package/README.md +103 -8
- package/RELEASE.md +48 -50
- 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 +137 -655
- package/extensions/data-pack/manifest.yaml +1 -1
- package/extensions/data-pack/package.json +1 -1
- package/extensions/launch-pack/README.md +1 -1
- package/extensions/launch-pack/manifest.yaml +1 -1
- package/extensions/launch-pack/package.json +1 -1
- package/extensions/security-pack/manifest.yaml +1 -1
- package/extensions/security-pack/package.json +1 -1
- package/fixtures/quick-proof/manifest.json +19 -0
- package/fixtures/quick-proof/project/.godpowers/prep/INITIAL-FINDINGS.md +5 -0
- package/fixtures/quick-proof/project/.godpowers/state.json +69 -0
- package/fixtures/quick-proof/project/README.md +5 -0
- package/fixtures/quick-proof/project/package.json +6 -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/events.js +11 -4
- package/lib/extension-authoring.js +27 -0
- package/lib/feature-awareness.js +24 -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/quick-proof.js +153 -0
- 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 +7 -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-extension-info.md +1 -1
- 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-test-extension.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,468 +41,29 @@ 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 'automation-status':
|
|
326
|
-
case 'automation-setup':
|
|
327
|
-
case 'dogfood':
|
|
328
|
-
case 'extension-scaffold':
|
|
329
|
-
opts.command = arg;
|
|
330
|
-
break;
|
|
331
|
-
case '--json':
|
|
332
|
-
opts.json = true;
|
|
333
|
-
break;
|
|
334
|
-
case '--brief':
|
|
335
|
-
opts.brief = true;
|
|
336
|
-
break;
|
|
337
|
-
case '--project':
|
|
338
|
-
if (args[i + 1]) {
|
|
339
|
-
opts.project = path.resolve(args[i + 1]);
|
|
340
|
-
i++;
|
|
341
|
-
}
|
|
342
|
-
break;
|
|
343
|
-
case '-g':
|
|
344
|
-
case '--global':
|
|
345
|
-
opts.global = true;
|
|
346
|
-
break;
|
|
347
|
-
case '-l':
|
|
348
|
-
case '--local':
|
|
349
|
-
opts.local = true;
|
|
350
|
-
break;
|
|
351
|
-
case '--all':
|
|
352
|
-
opts.all = true;
|
|
353
|
-
break;
|
|
354
|
-
case '-h':
|
|
355
|
-
case '--help':
|
|
356
|
-
opts.help = true;
|
|
357
|
-
break;
|
|
358
|
-
case '-u':
|
|
359
|
-
case '--uninstall':
|
|
360
|
-
opts.uninstall = true;
|
|
361
|
-
break;
|
|
362
|
-
default:
|
|
363
|
-
if (arg.startsWith('--project=')) {
|
|
364
|
-
opts.project = path.resolve(arg.slice('--project='.length));
|
|
365
|
-
} else if (arg.startsWith('--name=')) {
|
|
366
|
-
opts.extensionName = arg.slice('--name='.length);
|
|
367
|
-
} else if (arg.startsWith('--output=')) {
|
|
368
|
-
opts.extensionOutput = path.resolve(arg.slice('--output='.length));
|
|
369
|
-
} else if (arg.startsWith('--skill=')) {
|
|
370
|
-
opts.extensionSkill = arg.slice('--skill='.length);
|
|
371
|
-
} else if (arg.startsWith('--agent=')) {
|
|
372
|
-
opts.extensionAgent = arg.slice('--agent='.length);
|
|
373
|
-
} else if (arg.startsWith('--workflow=')) {
|
|
374
|
-
opts.extensionWorkflow = arg.slice('--workflow='.length);
|
|
375
|
-
} else if (arg.startsWith('--') && RUNTIMES[arg.slice(2)]) {
|
|
376
|
-
opts.runtimes.push(arg.slice(2));
|
|
377
|
-
}
|
|
378
|
-
break;
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
return opts;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// ---------------------------------------------------------------------------
|
|
386
|
-
// Install
|
|
387
|
-
// ---------------------------------------------------------------------------
|
|
388
|
-
|
|
389
|
-
function installForRuntime(runtimeKey, srcDir, opts = {}) {
|
|
390
|
-
const runtime = resolveRuntime(runtimeKey, opts);
|
|
391
|
-
if (!runtime) {
|
|
392
|
-
error(`Unknown runtime: ${runtimeKey}`);
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
log(`\n Installing for \x1b[36m${runtime.name}\x1b[0m to \x1b[36m${runtime.configDir}\x1b[0m\n`);
|
|
397
|
-
|
|
398
|
-
ensureDir(runtime.configDir);
|
|
399
|
-
|
|
400
|
-
// 1. Install slash command skills to skills/
|
|
401
|
-
// Each skill in skills/ becomes a slash command (e.g. /god-mode)
|
|
402
|
-
const skillsSrc = path.join(srcDir, 'skills');
|
|
403
|
-
const skillsDest = path.join(runtime.configDir, runtime.skillsDir);
|
|
404
|
-
if (fs.existsSync(skillsSrc)) {
|
|
405
|
-
ensureDir(skillsDest);
|
|
406
|
-
let count = 0;
|
|
407
|
-
for (const file of fs.readdirSync(skillsSrc)) {
|
|
408
|
-
if (file.endsWith('.md')) {
|
|
409
|
-
installSkillFile(path.join(skillsSrc, file), skillsDest, runtimeKey);
|
|
410
|
-
count++;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
const shape = runtimeKey === 'codex' ? 'Codex skill directories' : 'skills/';
|
|
414
|
-
success(`Installed ${count} slash commands to ${shape}`);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// 2. Install specialist agents to agents/
|
|
418
|
-
// Each agent is spawnable from a skill (e.g., god-pm, god-architect, god-executor)
|
|
419
|
-
const agentsSrc = path.join(srcDir, 'agents');
|
|
420
|
-
const agentsDest = path.join(runtime.configDir, 'agents');
|
|
421
|
-
if (fs.existsSync(agentsSrc)) {
|
|
422
|
-
ensureDir(agentsDest);
|
|
423
|
-
let count = 0;
|
|
424
|
-
for (const file of fs.readdirSync(agentsSrc)) {
|
|
425
|
-
if (/^god-.*\.md$/.test(file)) {
|
|
426
|
-
const srcFile = path.join(agentsSrc, file);
|
|
427
|
-
installAgentFile(srcFile, agentsDest, runtime);
|
|
428
|
-
count++;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
const shape = runtime.agentMetadata === 'toml' ? 'agents/ with Codex metadata' : 'agents/';
|
|
432
|
-
success(`Installed ${count} specialist agents to ${shape}`);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
// 3. Install the master SKILL.md (always-on context)
|
|
436
|
-
const masterSkill = path.join(srcDir, 'SKILL.md');
|
|
437
|
-
if (fs.existsSync(masterSkill)) {
|
|
438
|
-
installSkillFile(masterSkill, skillsDest, runtimeKey, 'godpowers');
|
|
439
|
-
success('Installed master SKILL.md as godpowers');
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// 4. Install templates
|
|
443
|
-
const templatesSrc = path.join(srcDir, 'templates');
|
|
444
|
-
if (fs.existsSync(templatesSrc)) {
|
|
445
|
-
const templatesDest = path.join(runtime.configDir, 'godpowers-templates');
|
|
446
|
-
copyRecursive(templatesSrc, templatesDest);
|
|
447
|
-
success('Installed templates/');
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// 4b. Install references (HAVE-NOTS catalog and per-tier antipatterns)
|
|
451
|
-
const referencesSrc = path.join(srcDir, 'references');
|
|
452
|
-
if (fs.existsSync(referencesSrc)) {
|
|
453
|
-
const referencesDest = path.join(runtime.configDir, 'godpowers-references');
|
|
454
|
-
copyRecursive(referencesSrc, referencesDest);
|
|
455
|
-
success('Installed references/');
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// 4c. Install workflows (declarative YAML for /god-mode and friends)
|
|
459
|
-
const workflowsSrc = path.join(srcDir, 'workflows');
|
|
460
|
-
if (fs.existsSync(workflowsSrc)) {
|
|
461
|
-
const workflowsDest = path.join(runtime.configDir, 'godpowers-workflows');
|
|
462
|
-
copyRecursive(workflowsSrc, workflowsDest);
|
|
463
|
-
success('Installed workflows/');
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// 4d. Install schemas (for validation)
|
|
467
|
-
const schemaSrc = path.join(srcDir, 'schema');
|
|
468
|
-
if (fs.existsSync(schemaSrc)) {
|
|
469
|
-
const schemaDest = path.join(runtime.configDir, 'godpowers-schema');
|
|
470
|
-
copyRecursive(schemaSrc, schemaDest);
|
|
471
|
-
success('Installed schema/');
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// 4e. Install routing definitions (per-command prerequisites + next-suggestions)
|
|
475
|
-
const routingSrc = path.join(srcDir, 'routing');
|
|
476
|
-
if (fs.existsSync(routingSrc)) {
|
|
477
|
-
const routingDest = path.join(runtime.configDir, 'godpowers-routing');
|
|
478
|
-
copyRecursive(routingSrc, routingDest);
|
|
479
|
-
success('Installed routing/');
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// 4f. Install the executable runtime bundle with lib/ next to its data dirs.
|
|
483
|
-
const runtimeBundleDest = path.join(runtime.configDir, 'godpowers-runtime');
|
|
484
|
-
copyRuntimeBundle(srcDir, runtimeBundleDest);
|
|
485
|
-
success('Installed runtime bundle/');
|
|
486
|
-
|
|
487
|
-
// 5. Install hooks (Claude Code only for now)
|
|
488
|
-
if (runtimeKey === 'claude') {
|
|
489
|
-
const hooksSrc = path.join(srcDir, 'hooks');
|
|
490
|
-
const hooksDest = path.join(runtime.configDir, 'hooks');
|
|
491
|
-
if (fs.existsSync(hooksSrc)) {
|
|
492
|
-
ensureDir(hooksDest);
|
|
493
|
-
for (const file of fs.readdirSync(hooksSrc)) {
|
|
494
|
-
const src = path.join(hooksSrc, file);
|
|
495
|
-
const dest = path.join(hooksDest, file);
|
|
496
|
-
fs.copyFileSync(src, dest);
|
|
497
|
-
try { fs.chmodSync(dest, 0o755); } catch (e) {}
|
|
498
|
-
}
|
|
499
|
-
success('Installed hooks/');
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// 6. Write VERSION
|
|
504
|
-
fs.writeFileSync(path.join(runtime.configDir, 'GODPOWERS_VERSION'), VERSION);
|
|
505
|
-
success(`Wrote GODPOWERS_VERSION (${VERSION})`);
|
|
506
|
-
|
|
507
|
-
return true;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// ---------------------------------------------------------------------------
|
|
511
|
-
// Uninstall
|
|
512
|
-
// ---------------------------------------------------------------------------
|
|
513
|
-
|
|
514
|
-
function uninstallForRuntime(runtimeKey, opts = {}) {
|
|
515
|
-
const runtime = resolveRuntime(runtimeKey, opts);
|
|
516
|
-
if (!runtime) {
|
|
517
|
-
error(`Unknown runtime: ${runtimeKey}`);
|
|
518
|
-
return false;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
log(`\n Uninstalling from \x1b[36m${runtime.name}\x1b[0m at \x1b[36m${runtime.configDir}\x1b[0m\n`);
|
|
522
|
-
|
|
523
|
-
const skillsDir = path.join(runtime.configDir, runtime.skillsDir);
|
|
524
|
-
const agentsDir = path.join(runtime.configDir, 'agents');
|
|
525
|
-
const templatesDir = path.join(runtime.configDir, 'godpowers-templates');
|
|
526
|
-
const referencesDir = path.join(runtime.configDir, 'godpowers-references');
|
|
527
|
-
const workflowsDir = path.join(runtime.configDir, 'godpowers-workflows');
|
|
528
|
-
const schemaDir = path.join(runtime.configDir, 'godpowers-schema');
|
|
529
|
-
const routingDir = path.join(runtime.configDir, 'godpowers-routing');
|
|
530
|
-
const runtimeBundleDir = path.join(runtime.configDir, 'godpowers-runtime');
|
|
531
|
-
const versionFile = path.join(runtime.configDir, 'GODPOWERS_VERSION');
|
|
532
|
-
|
|
533
|
-
let removed = 0;
|
|
534
|
-
|
|
535
|
-
// Remove all god-* skills
|
|
536
|
-
if (fs.existsSync(skillsDir)) {
|
|
537
|
-
for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
538
|
-
if (removeSkillEntry(skillsDir, entry)) {
|
|
539
|
-
removed++;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
success(`Removed ${removed} god-* skill(s)`);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
// Remove all god-* agents
|
|
546
|
-
let agentsRemoved = 0;
|
|
547
|
-
if (fs.existsSync(agentsDir)) {
|
|
548
|
-
for (const file of fs.readdirSync(agentsDir)) {
|
|
549
|
-
if (file.startsWith('god-')) {
|
|
550
|
-
fs.unlinkSync(path.join(agentsDir, file));
|
|
551
|
-
agentsRemoved++;
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
success(`Removed ${agentsRemoved} god-* agent(s)`);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// Remove installed data and runtime directories
|
|
558
|
-
for (const dir of [
|
|
559
|
-
templatesDir,
|
|
560
|
-
referencesDir,
|
|
561
|
-
workflowsDir,
|
|
562
|
-
schemaDir,
|
|
563
|
-
routingDir,
|
|
564
|
-
runtimeBundleDir
|
|
565
|
-
]) {
|
|
566
|
-
if (fs.existsSync(dir)) {
|
|
567
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
568
|
-
success(`Removed ${path.basename(dir)}/`);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
// Remove hooks (Claude Code only)
|
|
573
|
-
if (runtimeKey === 'claude') {
|
|
574
|
-
const hooksDir = path.join(runtime.configDir, 'hooks');
|
|
575
|
-
for (const hook of ['session-start.sh', 'pre-tool-use.sh']) {
|
|
576
|
-
const hookPath = path.join(hooksDir, hook);
|
|
577
|
-
if (fs.existsSync(hookPath)) {
|
|
578
|
-
fs.unlinkSync(hookPath);
|
|
579
|
-
success(`Removed hooks/${hook}`);
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if (fs.existsSync(versionFile)) {
|
|
585
|
-
fs.unlinkSync(versionFile);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
return true;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
44
|
function showHelp() {
|
|
592
45
|
console.log(BANNER);
|
|
593
46
|
log('Usage: npx godpowers [command] [options]\n');
|
|
594
47
|
log('Commands:');
|
|
595
48
|
log(' status Show the Godpowers Dashboard for a project');
|
|
596
49
|
log(' next Show the dashboard and recommended next command');
|
|
50
|
+
log(' quick-proof Show a runnable proof from the shipped fixture');
|
|
597
51
|
log(' automation-status Show host automation provider support');
|
|
598
52
|
log(' automation-setup Show an opt-in automation setup plan');
|
|
599
53
|
log(' dogfood Run built-in messy-repo dogfood scenarios');
|
|
600
54
|
log(' extension-scaffold Create a publishable extension pack skeleton');
|
|
601
55
|
log('');
|
|
602
56
|
log('Options:');
|
|
603
|
-
log(' --project=<path> Project root for status, next, or automation commands');
|
|
604
|
-
log(' --json Emit JSON for status, next, or automation commands');
|
|
605
|
-
log(' --brief Render
|
|
57
|
+
log(' --project=<path> Project root for status, next, proof, or automation commands');
|
|
58
|
+
log(' --json Emit JSON for status, next, proof, or automation commands');
|
|
59
|
+
log(' --brief Render compact output for status, next, or proof');
|
|
606
60
|
log(' --name=<scope/name> Extension package name for extension-scaffold');
|
|
607
61
|
log(' --output=<path> Extension output root for extension-scaffold');
|
|
608
62
|
log(' --skill=<name> Extension skill name for extension-scaffold');
|
|
609
63
|
log(' --agent=<name> Extension agent name for extension-scaffold');
|
|
610
64
|
log(' --workflow=<name> Extension workflow name for extension-scaffold');
|
|
611
|
-
log(' -g, --global Install globally
|
|
612
|
-
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');
|
|
613
67
|
log(' --claude Install for Claude Code');
|
|
614
68
|
log(' --codex Install for Codex');
|
|
615
69
|
log(' --cursor Install for Cursor');
|
|
@@ -632,6 +86,7 @@ function showHelp() {
|
|
|
632
86
|
log('Examples:');
|
|
633
87
|
log(' npx godpowers status --project=.');
|
|
634
88
|
log(' npx godpowers next --project=.');
|
|
89
|
+
log(' npx godpowers quick-proof --project=.');
|
|
635
90
|
log(' npx godpowers automation-status --project=.');
|
|
636
91
|
log(' npx godpowers automation-setup --project=.');
|
|
637
92
|
log(' npx godpowers dogfood');
|
|
@@ -660,13 +115,14 @@ function runDashboardCommand(opts) {
|
|
|
660
115
|
const result = dashboard.compute(opts.project);
|
|
661
116
|
if (opts.json) {
|
|
662
117
|
console.log(JSON.stringify(result, null, 2));
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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'}`);
|
|
670
126
|
}
|
|
671
127
|
}
|
|
672
128
|
|
|
@@ -681,6 +137,16 @@ function runDogfoodCommand(opts) {
|
|
|
681
137
|
if (result.status !== 'pass') process.exit(1);
|
|
682
138
|
}
|
|
683
139
|
|
|
140
|
+
function runQuickProofCommand(opts) {
|
|
141
|
+
const quickProof = require('../lib/quick-proof');
|
|
142
|
+
const result = quickProof.compute(opts.project);
|
|
143
|
+
if (opts.json) {
|
|
144
|
+
console.log(JSON.stringify(result, null, 2));
|
|
145
|
+
} else {
|
|
146
|
+
console.log(quickProof.render(result, { brief: opts.brief }));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
684
150
|
function runExtensionScaffoldCommand(opts) {
|
|
685
151
|
const authoring = require('../lib/extension-authoring');
|
|
686
152
|
if (!opts.extensionName) {
|
|
@@ -696,90 +162,75 @@ function runExtensionScaffoldCommand(opts) {
|
|
|
696
162
|
});
|
|
697
163
|
if (opts.json) {
|
|
698
164
|
console.log(JSON.stringify(result, null, 2));
|
|
699
|
-
|
|
700
|
-
success(`Scaffolded ${result.name} at ${result.path}`);
|
|
701
|
-
if (result.written.length > 0) {
|
|
702
|
-
log(`Wrote ${result.written.length} file(s): ${result.written.join(', ')}`);
|
|
703
|
-
}
|
|
704
|
-
if (result.validation.length > 0) {
|
|
705
|
-
warn(`Validation warnings: ${result.validation.join('; ')}`);
|
|
706
|
-
} else {
|
|
707
|
-
success('Extension manifest validates');
|
|
708
|
-
}
|
|
165
|
+
return;
|
|
709
166
|
}
|
|
710
|
-
}
|
|
711
167
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
showHelp();
|
|
721
|
-
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(', ')}`);
|
|
171
|
+
}
|
|
172
|
+
if (result.validation.length > 0) {
|
|
173
|
+
warn(`Validation warnings: ${result.validation.join('; ')}`);
|
|
174
|
+
} else {
|
|
175
|
+
success('Extension manifest validates');
|
|
722
176
|
}
|
|
177
|
+
}
|
|
723
178
|
|
|
179
|
+
function runCommand(opts) {
|
|
724
180
|
if (opts.command === 'status' || opts.command === 'next') {
|
|
725
181
|
runDashboardCommand(opts);
|
|
726
|
-
return;
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
if (opts.command === 'quick-proof') {
|
|
185
|
+
runQuickProofCommand(opts);
|
|
186
|
+
return true;
|
|
727
187
|
}
|
|
728
|
-
|
|
729
188
|
if (opts.command === 'automation-status' || opts.command === 'automation-setup') {
|
|
730
189
|
runAutomationCommand(opts);
|
|
731
|
-
return;
|
|
190
|
+
return true;
|
|
732
191
|
}
|
|
733
|
-
|
|
734
192
|
if (opts.command === 'dogfood') {
|
|
735
193
|
runDogfoodCommand(opts);
|
|
736
|
-
return;
|
|
194
|
+
return true;
|
|
737
195
|
}
|
|
738
|
-
|
|
739
196
|
if (opts.command === 'extension-scaffold') {
|
|
740
197
|
runExtensionScaffoldCommand(opts);
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
console.log(BANNER);
|
|
745
|
-
|
|
746
|
-
const srcDir = path.resolve(__dirname, '..');
|
|
747
|
-
|
|
748
|
-
// Detect non-interactive and default to Claude Code.
|
|
749
|
-
if (opts.runtimes.length === 0 && !opts.all) {
|
|
750
|
-
if (!process.stdin.isTTY) {
|
|
751
|
-
warn('Non-interactive terminal detected, defaulting to Claude Code install');
|
|
752
|
-
opts.runtimes = ['claude'];
|
|
753
|
-
if (!opts.local) opts.global = true;
|
|
754
|
-
} else {
|
|
755
|
-
// Interactive mode: default to claude
|
|
756
|
-
opts.runtimes = ['claude'];
|
|
757
|
-
if (!opts.local) opts.global = true;
|
|
758
|
-
}
|
|
198
|
+
return true;
|
|
759
199
|
}
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
760
202
|
|
|
761
|
-
|
|
762
|
-
|
|
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);
|
|
763
212
|
}
|
|
213
|
+
opts.runtimes = ['claude'];
|
|
214
|
+
if (!opts.local) opts.global = true;
|
|
215
|
+
}
|
|
764
216
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
removed++;
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
log('');
|
|
774
|
-
if (removed > 0) {
|
|
775
|
-
log(`\x1b[32mUninstalled\x1b[0m from ${removed} runtime(s).`);
|
|
776
|
-
} else {
|
|
777
|
-
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++;
|
|
778
222
|
}
|
|
779
|
-
log('');
|
|
780
|
-
return;
|
|
781
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
|
+
}
|
|
782
232
|
|
|
233
|
+
function runInstall(opts, srcDir) {
|
|
783
234
|
let installed = 0;
|
|
784
235
|
for (const runtime of opts.runtimes) {
|
|
785
236
|
if (installForRuntime(runtime, srcDir, opts)) {
|
|
@@ -787,31 +238,62 @@ function main() {
|
|
|
787
238
|
}
|
|
788
239
|
}
|
|
789
240
|
|
|
790
|
-
if (installed
|
|
791
|
-
// Count slash commands for verification message
|
|
792
|
-
const skillsCount = fs.readdirSync(path.join(srcDir, 'skills')).filter(f => f.endsWith('.md')).length;
|
|
793
|
-
const agentsCount = fs.readdirSync(path.join(srcDir, 'agents')).filter(f => /^god-.*\.md$/.test(f)).length;
|
|
794
|
-
|
|
795
|
-
log('');
|
|
796
|
-
log(`\x1b[32mDone!\x1b[0m Installed Godpowers v${VERSION} for ${installed} runtime(s).`);
|
|
797
|
-
log('');
|
|
798
|
-
log(`\x1b[36mInstalled:\x1b[0m`);
|
|
799
|
-
log(` ${skillsCount} slash commands (try: /god-mode, /god-next, /god-status)`);
|
|
800
|
-
log(` ${agentsCount} specialist agents`);
|
|
801
|
-
log(` Templates and references for artifact discipline`);
|
|
802
|
-
log('');
|
|
803
|
-
log(`\x1b[36mNext steps:\x1b[0m`);
|
|
804
|
-
log(` 1. Open your AI coding tool in any project directory`);
|
|
805
|
-
log(` 2. Type: \x1b[36m/god-mode\x1b[0m for the full autonomous project run`);
|
|
806
|
-
log(` Or: \x1b[36m/god-next\x1b[0m to see what to run next`);
|
|
807
|
-
log(` Or: \x1b[36m/god-init\x1b[0m to start a new project`);
|
|
808
|
-
log('');
|
|
809
|
-
log(`\x1b[36mDocs:\x1b[0m https://github.com/godpowers/godpowers`);
|
|
810
|
-
log('');
|
|
811
|
-
} else {
|
|
241
|
+
if (installed === 0) {
|
|
812
242
|
error('No runtimes installed. Run with --help for usage.');
|
|
813
243
|
process.exit(1);
|
|
814
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
|
+
}
|
|
815
288
|
}
|
|
816
289
|
|
|
817
290
|
main();
|
|
291
|
+
|
|
292
|
+
module.exports = {
|
|
293
|
+
showHelp,
|
|
294
|
+
runCommand,
|
|
295
|
+
applyDefaultRuntimeSelection,
|
|
296
|
+
runInstall,
|
|
297
|
+
runUninstall,
|
|
298
|
+
RUNTIMES
|
|
299
|
+
};
|