godpowers 1.6.12 → 1.6.14

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.
@@ -0,0 +1,596 @@
1
+ /**
2
+ * Godpowers Automation Providers
3
+ *
4
+ * Detects host-native automation surfaces, renders opt-in setup guidance, and
5
+ * records completed host setup after explicit confirmation. This module never
6
+ * creates schedules, routines, background agents, commits, pushes, packages,
7
+ * publishes, deploys, or clears reviews by itself.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const cp = require('child_process');
13
+ const os = require('os');
14
+
15
+ const CONFIG_PATH = '.godpowers/automations.json';
16
+
17
+ const SAFE_TEMPLATES = [
18
+ {
19
+ id: 'daily-status',
20
+ title: 'Daily Godpowers status',
21
+ cadence: 'Daily at 9am local time',
22
+ risk: 'read-only',
23
+ prompt: 'Run godpowers status --project . and summarize current phase, progress, open items, and recommended next action.'
24
+ },
25
+ {
26
+ id: 'stale-checkpoint',
27
+ title: 'Stale checkpoint watcher',
28
+ cadence: 'Weekdays at 9am local time',
29
+ risk: 'read-only',
30
+ prompt: 'Check .godpowers/CHECKPOINT.md freshness. If stale, report that /god-sync or /god-resume-work should run.'
31
+ },
32
+ {
33
+ id: 'review-queue',
34
+ title: 'Review queue watcher',
35
+ cadence: 'Daily at 10am local time',
36
+ risk: 'read-only',
37
+ prompt: 'Inspect .godpowers/REVIEW-REQUIRED.md and report unresolved review items without clearing them.'
38
+ },
39
+ {
40
+ id: 'weekly-hygiene',
41
+ title: 'Weekly hygiene report',
42
+ cadence: 'Monday at 9am local time',
43
+ risk: 'read-only',
44
+ prompt: 'Run a read-only hygiene summary for docs drift, dependency signals, checkpoint age, and pending reviews.'
45
+ },
46
+ {
47
+ id: 'release-readiness',
48
+ title: 'Release readiness report',
49
+ cadence: 'Manual or before release',
50
+ risk: 'read-only',
51
+ prompt: 'Report release readiness from tests, package metadata, changelog, release notes, and unstaged work. Do not publish.'
52
+ }
53
+ ];
54
+
55
+ const PROVIDERS = [
56
+ {
57
+ id: 'codex-app',
58
+ label: 'Codex App automations',
59
+ runtime: 'codex',
60
+ class: 'native-scheduler',
61
+ detect: (ctx) => hasRuntime(ctx, 'codex') || hasEnv(ctx, 'CODEX_HOME'),
62
+ setup: [
63
+ 'Use /god-automation-setup inside Codex App so the host can create reviewed automations.',
64
+ 'Prefer thread heartbeat for short follow-ups and worktree cron for durable project checks.'
65
+ ]
66
+ },
67
+ {
68
+ id: 'claude-routines',
69
+ label: 'Claude Code routines',
70
+ runtime: 'claude',
71
+ class: 'native-scheduler',
72
+ detect: (ctx) => hasCommand(ctx, 'claude') || hasRuntime(ctx, 'claude'),
73
+ setup: [
74
+ 'Run /schedule in Claude Code for scheduled routines.',
75
+ 'Use claude.ai/code/routines for API or GitHub triggers.'
76
+ ]
77
+ },
78
+ {
79
+ id: 'cline-schedule',
80
+ label: 'Cline scheduled agents',
81
+ runtime: 'cline',
82
+ class: 'native-scheduler',
83
+ detect: (ctx) => hasCommand(ctx, 'cline') || hasRuntime(ctx, 'cline'),
84
+ setup: [
85
+ 'Run cline schedule to create, list, trigger, pause, resume, or delete schedules.',
86
+ 'Use read-only prompts unless the user explicitly approves branch or PR automation.'
87
+ ]
88
+ },
89
+ {
90
+ id: 'kilo-scheduled-triggers',
91
+ label: 'Kilo scheduled triggers',
92
+ runtime: 'kilo',
93
+ class: 'native-scheduler',
94
+ detect: (ctx) => hasRuntime(ctx, 'kilo'),
95
+ setup: [
96
+ 'Use KiloClaw Scheduled Triggers from Kilo settings.',
97
+ 'Limit each trigger to read-only Godpowers reports unless the user approves write scope.'
98
+ ]
99
+ },
100
+ {
101
+ id: 'qwen-loop',
102
+ label: 'Qwen Code /loop',
103
+ runtime: 'qwen',
104
+ class: 'session-scheduler',
105
+ detect: (ctx) => hasCommand(ctx, 'qwen') || hasRuntime(ctx, 'qwen'),
106
+ setup: [
107
+ 'Enable Qwen experimental cron support, then use /loop for session-scoped recurring prompts.',
108
+ 'Do not treat Qwen loops as durable because they do not persist across restarts.'
109
+ ]
110
+ },
111
+ {
112
+ id: 'cursor-background-agent',
113
+ label: 'Cursor Background Agents',
114
+ runtime: 'cursor',
115
+ class: 'background-agent',
116
+ detect: (ctx) => hasCommand(ctx, 'cursor') || hasRuntime(ctx, 'cursor'),
117
+ setup: [
118
+ 'Use Cursor Background Agent mode or Background Agent API for asynchronous branch work.',
119
+ 'Prefer issue or branch scoped tasks and require human review before merge.'
120
+ ]
121
+ },
122
+ {
123
+ id: 'github-copilot-cloud-agent',
124
+ label: 'GitHub Copilot cloud agent',
125
+ runtime: 'copilot',
126
+ class: 'background-agent',
127
+ detect: (ctx) => hasGitRemote(ctx) || hasRuntime(ctx, 'copilot'),
128
+ setup: [
129
+ 'Use GitHub issues, pull requests, or Copilot chat to delegate work to Copilot cloud agent.',
130
+ 'Keep Godpowers automations branch or PR scoped and require human merge authority.'
131
+ ]
132
+ },
133
+ {
134
+ id: 'windsurf-workflows',
135
+ label: 'Windsurf workflows',
136
+ runtime: 'windsurf',
137
+ class: 'manual-workflow',
138
+ detect: (ctx) => hasRuntime(ctx, 'windsurf'),
139
+ setup: [
140
+ 'Install reusable workflows under .windsurf/workflows/ or the global Windsurf workflow folder.',
141
+ 'Windsurf workflows are manual-only; use Skills when Cascade should discover a procedure.'
142
+ ]
143
+ },
144
+ {
145
+ id: 'gemini-headless',
146
+ label: 'Gemini CLI headless mode',
147
+ runtime: 'gemini',
148
+ class: 'scriptable-headless',
149
+ detect: (ctx) => hasCommand(ctx, 'gemini') || hasRuntime(ctx, 'gemini'),
150
+ setup: [
151
+ 'Use gemini -p for non-interactive scripting.',
152
+ 'Use an external scheduler only when the user explicitly asks for OS or CI scheduling.'
153
+ ]
154
+ },
155
+ {
156
+ id: 'opencode-run',
157
+ label: 'OpenCode run and serve',
158
+ runtime: 'opencode',
159
+ class: 'scriptable-headless',
160
+ detect: (ctx) => hasCommand(ctx, 'opencode') || hasRuntime(ctx, 'opencode'),
161
+ setup: [
162
+ 'Use opencode run for non-interactive prompts or opencode serve for an attachable server.',
163
+ 'Use opencode github install when repo-native GitHub automation is preferred.'
164
+ ]
165
+ },
166
+ {
167
+ id: 'augment-subagents',
168
+ label: 'Augment Agent and subagents',
169
+ runtime: 'augment',
170
+ class: 'manual-workflow',
171
+ detect: (ctx) => hasRuntime(ctx, 'augment'),
172
+ setup: [
173
+ 'Use Augment Agent or Agent Auto for supervised tasks.',
174
+ 'Use Augment subagents for specialized review, test, or docs work.'
175
+ ]
176
+ },
177
+ {
178
+ id: 'codebuddy-sdk',
179
+ label: 'CodeBuddy Agent SDK',
180
+ runtime: 'codebuddy',
181
+ class: 'scriptable-headless',
182
+ detect: (ctx) => hasCommand(ctx, 'codebuddy') || hasRuntime(ctx, 'codebuddy'),
183
+ setup: [
184
+ 'Use the CodeBuddy Agent SDK for programmatic automation.',
185
+ 'Keep filesystem config loading explicit so automation stays predictable.'
186
+ ]
187
+ },
188
+ {
189
+ id: 'pi-sdk',
190
+ label: 'Pi CLI and SDK',
191
+ runtime: 'pi',
192
+ class: 'scriptable-headless',
193
+ detect: (ctx) => hasCommand(ctx, 'pi') || hasRuntime(ctx, 'pi'),
194
+ setup: [
195
+ 'Use Pi CLI or SDK for scriptable coding-agent sessions.',
196
+ 'Use host or CI scheduling only after explicit user approval.'
197
+ ]
198
+ },
199
+ {
200
+ id: 'trae',
201
+ label: 'Trae',
202
+ runtime: 'trae',
203
+ class: 'unknown',
204
+ detect: (ctx) => hasRuntime(ctx, 'trae'),
205
+ setup: [
206
+ 'No stable scheduled automation provider is documented for Godpowers yet.',
207
+ 'Use manual Godpowers commands until a native Trae automation surface is confirmed.'
208
+ ]
209
+ },
210
+ {
211
+ id: 'antigravity',
212
+ label: 'Google Antigravity',
213
+ runtime: 'antigravity',
214
+ class: 'unknown',
215
+ detect: (ctx) => hasRuntime(ctx, 'antigravity'),
216
+ setup: [
217
+ 'Agent-first workflows are supported, but scheduled automation is not confirmed for Godpowers yet.',
218
+ 'Use manual workflows and require artifact review for autonomous agent work.'
219
+ ]
220
+ }
221
+ ];
222
+
223
+ const EXECUTION_ADAPTERS = {
224
+ 'codex-app': {
225
+ method: 'host-tool-calling',
226
+ hostTool: 'codex_app.automation_update',
227
+ action: 'Call the Codex App automation tool after the user approves provider, template, cadence, and scope.'
228
+ },
229
+ 'claude-routines': {
230
+ method: 'host-native-command',
231
+ hostCommand: '/schedule',
232
+ action: 'Use Claude Code schedule or routine creation after explicit user approval.'
233
+ },
234
+ 'cline-schedule': {
235
+ method: 'local-command',
236
+ localCommand: 'cline schedule',
237
+ action: 'Use the Cline scheduler after explicit user approval.'
238
+ },
239
+ 'kilo-scheduled-triggers': {
240
+ method: 'host-native-ui',
241
+ action: 'Use KiloClaw Scheduled Triggers after explicit user approval.'
242
+ },
243
+ 'qwen-loop': {
244
+ method: 'session-command',
245
+ hostCommand: '/loop',
246
+ action: 'Use Qwen Code loop only for session-scoped recurring checks.'
247
+ },
248
+ 'cursor-background-agent': {
249
+ method: 'background-agent',
250
+ action: 'Use Cursor Background Agent mode or API for branch-scoped asynchronous work.'
251
+ },
252
+ 'github-copilot-cloud-agent': {
253
+ method: 'background-agent',
254
+ action: 'Use GitHub issue, pull request, or Copilot cloud agent entry points for branch-scoped work.'
255
+ },
256
+ 'windsurf-workflows': {
257
+ method: 'manual-workflow',
258
+ action: 'Install or select a Windsurf workflow manually because durable scheduling is not confirmed.'
259
+ },
260
+ 'gemini-headless': {
261
+ method: 'scriptable-headless',
262
+ localCommand: 'gemini -p',
263
+ action: 'Use Gemini CLI headless execution only with an approved host, CI, or OS scheduler.'
264
+ },
265
+ 'opencode-run': {
266
+ method: 'scriptable-headless',
267
+ localCommand: 'opencode run',
268
+ action: 'Use OpenCode run or serve only with an approved host, CI, or OS scheduler.'
269
+ },
270
+ 'augment-subagents': {
271
+ method: 'manual-workflow',
272
+ action: 'Use Augment Agent, Agent Auto, or subagents manually unless a native scheduler is confirmed.'
273
+ },
274
+ 'codebuddy-sdk': {
275
+ method: 'scriptable-headless',
276
+ action: 'Use CodeBuddy SDK only with an approved host, CI, or OS scheduler.'
277
+ },
278
+ 'pi-sdk': {
279
+ method: 'scriptable-headless',
280
+ action: 'Use Pi CLI or SDK only with an approved host, CI, or OS scheduler.'
281
+ },
282
+ trae: {
283
+ method: 'unsupported',
284
+ action: 'Report scheduled automation as unknown until Trae exposes a confirmed provider.'
285
+ },
286
+ antigravity: {
287
+ method: 'unsupported',
288
+ action: 'Report scheduled automation as unknown until Antigravity exposes a confirmed provider.'
289
+ }
290
+ };
291
+
292
+ const EXECUTION_GUARDRAILS = [
293
+ 'Ask for explicit approval before creating, updating, triggering, pausing, resuming, or deleting host automations.',
294
+ 'Use direct host tool calling only for one read-only template with a known provider and approved cadence.',
295
+ 'Spawn god-automation-engineer for multiple templates, write-capable automation, background agents, scriptable schedulers, or provider uncertainty.',
296
+ 'Write .godpowers/automations.json only after host setup succeeds.'
297
+ ];
298
+
299
+ function detect(projectRoot = process.cwd(), opts = {}) {
300
+ const ctx = {
301
+ projectRoot,
302
+ home: opts.home || os.homedir(),
303
+ env: opts.env || process.env,
304
+ commands: opts.commands || null,
305
+ gitRemote: opts.gitRemote
306
+ };
307
+ const active = readConfig(projectRoot).automations || [];
308
+ const providers = PROVIDERS.map(provider => {
309
+ const installed = Boolean(provider.detect(ctx));
310
+ return {
311
+ id: provider.id,
312
+ label: provider.label,
313
+ runtime: provider.runtime,
314
+ class: provider.class,
315
+ installed,
316
+ status: providerStatus(provider.class, installed),
317
+ active: active.filter(item => item.provider === provider.id),
318
+ setup: provider.setup.slice()
319
+ };
320
+ });
321
+
322
+ const safeTemplates = SAFE_TEMPLATES.map(template => ({
323
+ ...template,
324
+ active: active.some(item => item.id === template.id && item.status !== 'disabled')
325
+ }));
326
+
327
+ return {
328
+ configPath: path.join(projectRoot, CONFIG_PATH),
329
+ providers,
330
+ safeTemplates,
331
+ active,
332
+ recommendedProvider: recommendProvider(providers),
333
+ safety: [
334
+ 'Do not create automations during install.',
335
+ 'Create schedules, routines, background agents, or API triggers only after explicit user approval.',
336
+ 'Default templates are read-only and must not commit, push, publish, deploy, clear reviews, or access provider dashboards.'
337
+ ]
338
+ };
339
+ }
340
+
341
+ function render(report) {
342
+ const active = report.active && report.active.length > 0
343
+ ? report.active.map(item => ` - ${item.id} via ${item.provider}: ${item.status || 'active'}`)
344
+ : [' - none recorded'];
345
+ const providers = report.providers.map(provider => (
346
+ ` - ${provider.label}: ${provider.status} (${provider.class})`
347
+ ));
348
+ const recommended = report.recommendedProvider
349
+ ? `${report.recommendedProvider.label} (${report.recommendedProvider.class})`
350
+ : 'none available';
351
+ const templates = report.safeTemplates.map(template => (
352
+ ` - ${template.id}: ${template.title}, ${template.cadence}, ${template.risk}`
353
+ ));
354
+
355
+ return [
356
+ 'Godpowers Automation Providers',
357
+ '',
358
+ `Config: ${report.configPath}`,
359
+ `Recommended provider: ${recommended}`,
360
+ '',
361
+ 'Active automations:',
362
+ ...active,
363
+ '',
364
+ 'Provider status:',
365
+ ...providers,
366
+ '',
367
+ 'Safe templates:',
368
+ ...templates,
369
+ '',
370
+ 'Safety rules:',
371
+ ...report.safety.map(rule => ` - ${rule}`)
372
+ ].join('\n');
373
+ }
374
+
375
+ function setupPlan(projectRoot = process.cwd(), opts = {}) {
376
+ const report = detect(projectRoot, opts);
377
+ const provider = report.recommendedProvider;
378
+ const selectedTemplates = selectTemplates(report.safeTemplates, opts.templates);
379
+ return {
380
+ ...report,
381
+ selectedTemplates,
382
+ setup: provider ? provider.setup : ['No automation provider is available. Use /god-next or godpowers next --project . manually.'],
383
+ execution: buildExecutionPlan(projectRoot, provider, selectedTemplates, opts)
384
+ };
385
+ }
386
+
387
+ function renderSetupPlan(plan) {
388
+ const provider = plan.recommendedProvider
389
+ ? `${plan.recommendedProvider.label} (${plan.recommendedProvider.id})`
390
+ : 'none available';
391
+ return [
392
+ 'Godpowers Automation Setup Plan',
393
+ '',
394
+ `Recommended provider: ${provider}`,
395
+ '',
396
+ 'Setup steps:',
397
+ ...plan.setup.map((step, index) => ` ${index + 1}. ${step}`),
398
+ '',
399
+ 'Execution path:',
400
+ ` - Method: ${plan.execution.method}`,
401
+ ` - Action: ${plan.execution.action}`,
402
+ ` - Direct host tool calling: ${plan.execution.directHostToolCalling ? 'available after approval' : 'not available'}`,
403
+ ` - Specialist agent: ${plan.execution.specialistAgent || 'not required for simple read-only setup'}`,
404
+ ` - Record after success: ${plan.execution.recordPath}`,
405
+ '',
406
+ 'Recommended safe templates:',
407
+ ...plan.safeTemplates.map(template => ` - ${template.id}: ${template.prompt}`),
408
+ '',
409
+ 'Approval required:',
410
+ ' - Choose a provider',
411
+ ' - Choose one or more templates',
412
+ ' - Confirm any host-native schedule, routine, background agent, API trigger, or connector scope'
413
+ ].join('\n');
414
+ }
415
+
416
+ function selectTemplates(safeTemplates, selectedIds) {
417
+ if (!Array.isArray(selectedIds) || selectedIds.length === 0) {
418
+ const daily = safeTemplates.find(template => template.id === 'daily-status');
419
+ return daily ? [daily] : safeTemplates.slice(0, 1);
420
+ }
421
+ const selected = [];
422
+ for (const id of selectedIds) {
423
+ const found = safeTemplates.find(template => template.id === id);
424
+ if (found) selected.push(found);
425
+ }
426
+ return selected;
427
+ }
428
+
429
+ function buildExecutionPlan(projectRoot, provider, selectedTemplates, opts = {}) {
430
+ if (!provider) {
431
+ return {
432
+ method: 'manual',
433
+ action: 'No provider is available. Run Godpowers commands manually.',
434
+ directHostToolCalling: false,
435
+ hostTool: null,
436
+ hostCommand: null,
437
+ localCommand: null,
438
+ specialistAgent: null,
439
+ approvalRequired: true,
440
+ recordPath: path.join(projectRoot, CONFIG_PATH),
441
+ guardrails: EXECUTION_GUARDRAILS.slice()
442
+ };
443
+ }
444
+
445
+ const adapter = EXECUTION_ADAPTERS[provider.id] || {
446
+ method: provider.class,
447
+ action: 'Use the provider-native setup surface after explicit user approval.'
448
+ };
449
+ const writeCapable = Boolean(opts.writeCapable);
450
+ const complex = writeCapable ||
451
+ selectedTemplates.length > 1 ||
452
+ provider.class === 'background-agent' ||
453
+ provider.class === 'scriptable-headless' ||
454
+ provider.class === 'unknown';
455
+ const directHostToolCalling = !complex && (
456
+ adapter.method === 'host-tool-calling' ||
457
+ adapter.method === 'host-native-command' ||
458
+ adapter.method === 'local-command' ||
459
+ adapter.method === 'session-command'
460
+ );
461
+
462
+ return {
463
+ method: adapter.method,
464
+ action: adapter.action,
465
+ directHostToolCalling,
466
+ hostTool: adapter.hostTool || null,
467
+ hostCommand: adapter.hostCommand || null,
468
+ localCommand: adapter.localCommand || null,
469
+ specialistAgent: complex ? 'god-automation-engineer' : null,
470
+ approvalRequired: true,
471
+ recordPath: path.join(projectRoot, CONFIG_PATH),
472
+ guardrails: EXECUTION_GUARDRAILS.slice()
473
+ };
474
+ }
475
+
476
+ function buildAutomationRecord(providerId, templateId, opts = {}) {
477
+ const provider = PROVIDERS.find(item => item.id === providerId);
478
+ const template = SAFE_TEMPLATES.find(item => item.id === templateId);
479
+ if (!provider) throw new Error(`unknown automation provider: ${providerId}`);
480
+ if (!template) throw new Error(`unknown automation template: ${templateId}`);
481
+ return {
482
+ id: template.id,
483
+ provider: provider.id,
484
+ status: opts.status || 'active',
485
+ cadence: opts.cadence || template.cadence,
486
+ summary: opts.summary || template.prompt,
487
+ risk: template.risk,
488
+ createdAt: opts.createdAt || new Date().toISOString(),
489
+ host: opts.host || provider.label,
490
+ hostId: opts.hostId || null,
491
+ hostSurface: opts.hostSurface || (EXECUTION_ADAPTERS[provider.id] && EXECUTION_ADAPTERS[provider.id].method) || provider.class
492
+ };
493
+ }
494
+
495
+ function recordAutomation(projectRoot, record, opts = {}) {
496
+ if (!opts.confirmedHostSuccess) {
497
+ throw new Error('confirmedHostSuccess is required before recording automation');
498
+ }
499
+ const file = path.join(projectRoot, CONFIG_PATH);
500
+ const config = readConfig(projectRoot);
501
+ const next = config.automations.filter(item =>
502
+ !(item.id === record.id && item.provider === record.provider)
503
+ );
504
+ next.push(record);
505
+ fs.mkdirSync(path.dirname(file), { recursive: true });
506
+ fs.writeFileSync(file, `${JSON.stringify({ automations: next }, null, 2)}\n`);
507
+ return { automations: next };
508
+ }
509
+
510
+ function readConfig(projectRoot) {
511
+ const file = path.join(projectRoot, CONFIG_PATH);
512
+ if (!fs.existsSync(file)) return { automations: [] };
513
+ try {
514
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
515
+ return {
516
+ automations: Array.isArray(parsed.automations) ? parsed.automations : []
517
+ };
518
+ } catch (e) {
519
+ return { automations: [] };
520
+ }
521
+ }
522
+
523
+ function providerStatus(providerClass, installed) {
524
+ if (providerClass === 'unknown') return installed ? 'installed, capability unknown' : 'unknown';
525
+ if (providerClass === 'manual-workflow') return installed ? 'manual workflow available' : 'supported, not detected';
526
+ if (providerClass === 'session-scheduler') return installed ? 'session scheduler available' : 'supported, not detected';
527
+ if (providerClass === 'background-agent') return installed ? 'background agent available' : 'supported, not detected';
528
+ if (providerClass === 'scriptable-headless') return installed ? 'scriptable headless available' : 'supported, not detected';
529
+ if (providerClass === 'native-scheduler') return installed ? 'native scheduler available' : 'supported, not detected';
530
+ return installed ? 'available' : 'not detected';
531
+ }
532
+
533
+ function recommendProvider(providers) {
534
+ const order = [
535
+ 'native-scheduler',
536
+ 'background-agent',
537
+ 'scriptable-headless',
538
+ 'session-scheduler',
539
+ 'manual-workflow'
540
+ ];
541
+ for (const providerClass of order) {
542
+ const found = providers.find(provider => provider.installed && provider.class === providerClass);
543
+ if (found) return found;
544
+ }
545
+ return null;
546
+ }
547
+
548
+ function hasRuntime(ctx, runtime) {
549
+ const homePath = path.join(ctx.home, `.${runtime}`, 'GODPOWERS_VERSION');
550
+ return fs.existsSync(homePath);
551
+ }
552
+
553
+ function hasEnv(ctx, key) {
554
+ return Boolean(ctx.env && ctx.env[key]);
555
+ }
556
+
557
+ function hasCommand(ctx, command) {
558
+ if (ctx.commands) {
559
+ return Boolean(ctx.commands[command]);
560
+ }
561
+ try {
562
+ cp.execFileSync('which', [command], { stdio: ['ignore', 'ignore', 'ignore'] });
563
+ return true;
564
+ } catch (e) {
565
+ return false;
566
+ }
567
+ }
568
+
569
+ function hasGitRemote(ctx) {
570
+ if (ctx.gitRemote !== undefined) return Boolean(ctx.gitRemote);
571
+ try {
572
+ const out = cp.execFileSync('git', ['remote', '-v'], {
573
+ cwd: ctx.projectRoot,
574
+ encoding: 'utf8',
575
+ stdio: ['ignore', 'pipe', 'ignore']
576
+ });
577
+ return /github\.com[:/]/.test(out);
578
+ } catch (e) {
579
+ return false;
580
+ }
581
+ }
582
+
583
+ module.exports = {
584
+ CONFIG_PATH,
585
+ SAFE_TEMPLATES,
586
+ PROVIDERS,
587
+ detect,
588
+ render,
589
+ setupPlan,
590
+ renderSetupPlan,
591
+ selectTemplates,
592
+ buildExecutionPlan,
593
+ buildAutomationRecord,
594
+ recordAutomation,
595
+ readConfig
596
+ };
package/lib/dashboard.js CHANGED
@@ -11,6 +11,7 @@ const cp = require('child_process');
11
11
 
12
12
  const state = require('./state');
13
13
  const router = require('./router');
14
+ const automationProviders = require('./automation-providers');
14
15
 
15
16
  const GOD_DIR = '.godpowers';
16
17
  const PRD_PATH = '.godpowers/prd/PRD.md';
@@ -164,12 +165,24 @@ function proactiveChecks(projectRoot, changedFiles = []) {
164
165
  sync,
165
166
  docs: 'fresh',
166
167
  runtime: 'not-applicable',
168
+ automation: automationSummary(projectRoot),
167
169
  security: sensitiveChanged ? 'sensitive files changed, suggest /god-harden' : 'clear',
168
170
  dependencies: pkgChanged ? 'dependency files changed, suggest /god-update-deps' : 'clear',
169
171
  hygiene: hygieneFresh ? 'fresh' : 'stale, suggest /god-hygiene'
170
172
  };
171
173
  }
172
174
 
175
+ function automationSummary(projectRoot) {
176
+ const report = automationProviders.detect(projectRoot);
177
+ if (report.active.length > 0) {
178
+ return `${report.active.length} active`;
179
+ }
180
+ if (report.recommendedProvider) {
181
+ return `available via ${report.recommendedProvider.id}, suggest /god-automation-setup`;
182
+ }
183
+ return 'not configured';
184
+ }
185
+
173
186
  function matchesAnyPrefix(file, prefixes) {
174
187
  return prefixes.some(prefix => file === prefix || file.startsWith(`${prefix}/`));
175
188
  }
@@ -273,6 +286,7 @@ function render(dashboard) {
273
286
  ` Sync: ${proactive.sync || 'unknown'}`,
274
287
  ` Docs: ${proactive.docs || 'unknown'}`,
275
288
  ` Runtime: ${proactive.runtime || 'unknown'}`,
289
+ ` Automation: ${proactive.automation || 'unknown'}`,
276
290
  ` Security: ${proactive.security || 'unknown'}`,
277
291
  ` Dependencies: ${proactive.dependencies || 'unknown'}`,
278
292
  ` Hygiene: ${proactive.hygiene || 'unknown'}`,
@@ -292,5 +306,6 @@ module.exports = {
292
306
  worktree,
293
307
  parseGitStatus,
294
308
  proactiveChecks,
309
+ automationSummary,
295
310
  planningVisibility
296
311
  };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "godpowers",
3
- "version": "1.6.12",
4
- "description": "AI-powered development system: 106 slash commands and 39 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.",
3
+ "version": "1.6.14",
4
+ "description": "AI-powered development system: 108 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"
7
7
  },
8
8
  "scripts": {
9
- "test": "node scripts/validate-skills.js && node scripts/test-doc-surface-counts.js && bash scripts/smoke.sh && node scripts/test-runtime.js && node scripts/test-router.js && node scripts/test-recipes.js && node scripts/test-context-writer.js && node scripts/test-pillars.js && node scripts/test-artifact-linter.js && node scripts/test-artifact-diff.js && node scripts/test-design-foundation.js && node scripts/test-linkage.js && node scripts/test-impact.js && node scripts/test-reverse-sync.js && node scripts/test-integration.js && node scripts/test-cross-artifact.js && node scripts/test-awesome-design.js && node scripts/test-skillui-bridge.js && node scripts/test-runtime-verification.js && node scripts/test-agent-browser.js && node scripts/test-mode-d.js && node scripts/test-runtime-heuristics.js && node scripts/test-agent-validator.js && node scripts/test-story-validator.js && node scripts/test-state.js && node scripts/test-dashboard.js && node scripts/test-intent.js && node scripts/test-events.js && node scripts/test-golden-artifacts.js && node scripts/test-install-smoke.js && node scripts/test-checkpoint.js && node scripts/test-extensions.js && node scripts/test-event-reader.js && node scripts/test-state-lock.js && node scripts/test-cost-saver.js && node scripts/test-budget-onoff.js && node scripts/test-workflow-runner.js && npm run test:e2e && node scripts/test-otel-exporter.js && node scripts/test-extensions-publish.js",
9
+ "test": "node scripts/validate-skills.js && node scripts/test-doc-surface-counts.js && bash scripts/smoke.sh && node scripts/test-runtime.js && node scripts/test-router.js && node scripts/test-recipes.js && node scripts/test-context-writer.js && node scripts/test-pillars.js && node scripts/test-artifact-linter.js && node scripts/test-artifact-diff.js && node scripts/test-design-foundation.js && node scripts/test-linkage.js && node scripts/test-impact.js && node scripts/test-reverse-sync.js && node scripts/test-integration.js && node scripts/test-cross-artifact.js && node scripts/test-awesome-design.js && node scripts/test-skillui-bridge.js && node scripts/test-runtime-verification.js && node scripts/test-agent-browser.js && node scripts/test-mode-d.js && node scripts/test-runtime-heuristics.js && node scripts/test-agent-validator.js && node scripts/test-story-validator.js && node scripts/test-state.js && node scripts/test-dashboard.js && node scripts/test-automation-providers.js && node scripts/test-intent.js && node scripts/test-events.js && node scripts/test-golden-artifacts.js && node scripts/test-install-smoke.js && node scripts/test-checkpoint.js && node scripts/test-extensions.js && node scripts/test-event-reader.js && node scripts/test-state-lock.js && node scripts/test-cost-saver.js && node scripts/test-budget-onoff.js && node scripts/test-workflow-runner.js && npm run test:e2e && node scripts/test-otel-exporter.js && node scripts/test-extensions-publish.js",
10
10
  "prepublishOnly": "npm test",
11
11
  "validate-skills": "node scripts/validate-skills.js",
12
12
  "test:surface": "node scripts/test-doc-surface-counts.js",
@@ -0,0 +1,25 @@
1
+ apiVersion: godpowers/v1
2
+ kind: CommandRouting
3
+ metadata:
4
+ command: /god-automation-setup
5
+ description: Prepare opt-in host automation setup
6
+ tier: 0
7
+
8
+ prerequisites:
9
+ required: []
10
+
11
+ execution:
12
+ spawns: [built-in, god-automation-engineer]
13
+ context: fresh
14
+ writes:
15
+ - .godpowers/automations.json
16
+
17
+ success-path:
18
+ next-recommended: /god-automation-status
19
+
20
+ failure-path:
21
+ on-error: /god-doctor
22
+
23
+ endoff:
24
+ state-update: tier-0 updated for /god-automation-setup
25
+ events: [agent.start, artifact.created, agent.end]