steroids-cli 0.4.47
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/LICENSE +21 -0
- package/README.md +640 -0
- package/dist/cli/colors.d.ts +110 -0
- package/dist/cli/colors.d.ts.map +1 -0
- package/dist/cli/colors.js +228 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/env.d.ts +159 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +227 -0
- package/dist/cli/env.js.map +1 -0
- package/dist/cli/errors.d.ts +166 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +244 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/flags.d.ts +75 -0
- package/dist/cli/flags.d.ts.map +1 -0
- package/dist/cli/flags.js +232 -0
- package/dist/cli/flags.js.map +1 -0
- package/dist/cli/help.d.ts +97 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +275 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +29 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/interactive.d.ts +58 -0
- package/dist/cli/interactive.d.ts.map +1 -0
- package/dist/cli/interactive.js +127 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/output.d.ts +116 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +178 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/commands/about.d.ts +7 -0
- package/dist/commands/about.d.ts.map +1 -0
- package/dist/commands/about.js +259 -0
- package/dist/commands/about.js.map +1 -0
- package/dist/commands/ai.d.ts +6 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +382 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/backup.d.ts +3 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +528 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/completion.d.ts +3 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +405 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +665 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/disputes.d.ts +3 -0
- package/dist/commands/disputes.d.ts.map +1 -0
- package/dist/commands/disputes.js +499 -0
- package/dist/commands/disputes.js.map +1 -0
- package/dist/commands/gc.d.ts +3 -0
- package/dist/commands/gc.d.ts.map +1 -0
- package/dist/commands/gc.js +300 -0
- package/dist/commands/gc.js.map +1 -0
- package/dist/commands/git.d.ts +3 -0
- package/dist/commands/git.d.ts.map +1 -0
- package/dist/commands/git.js +458 -0
- package/dist/commands/git.js.map +1 -0
- package/dist/commands/health.d.ts +3 -0
- package/dist/commands/health.d.ts.map +1 -0
- package/dist/commands/health.js +604 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/hooks.d.ts +6 -0
- package/dist/commands/hooks.d.ts.map +1 -0
- package/dist/commands/hooks.js +529 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +200 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/llm.d.ts +7 -0
- package/dist/commands/llm.d.ts.map +1 -0
- package/dist/commands/llm.js +285 -0
- package/dist/commands/llm.js.map +1 -0
- package/dist/commands/locks.d.ts +3 -0
- package/dist/commands/locks.d.ts.map +1 -0
- package/dist/commands/locks.js +431 -0
- package/dist/commands/locks.js.map +1 -0
- package/dist/commands/logs.d.ts +3 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +487 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/loop-phases.d.ts +11 -0
- package/dist/commands/loop-phases.d.ts.map +1 -0
- package/dist/commands/loop-phases.js +204 -0
- package/dist/commands/loop-phases.js.map +1 -0
- package/dist/commands/loop.d.ts +3 -0
- package/dist/commands/loop.d.ts.map +1 -0
- package/dist/commands/loop.js +396 -0
- package/dist/commands/loop.js.map +1 -0
- package/dist/commands/projects.d.ts +6 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +362 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/purge.d.ts +3 -0
- package/dist/commands/purge.d.ts.map +1 -0
- package/dist/commands/purge.js +516 -0
- package/dist/commands/purge.js.map +1 -0
- package/dist/commands/runners.d.ts +3 -0
- package/dist/commands/runners.d.ts.map +1 -0
- package/dist/commands/runners.js +1076 -0
- package/dist/commands/runners.js.map +1 -0
- package/dist/commands/scan.d.ts +3 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +291 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/sections-commands.d.ts +9 -0
- package/dist/commands/sections-commands.d.ts.map +1 -0
- package/dist/commands/sections-commands.js +282 -0
- package/dist/commands/sections-commands.js.map +1 -0
- package/dist/commands/sections-graph.d.ts +25 -0
- package/dist/commands/sections-graph.d.ts.map +1 -0
- package/dist/commands/sections-graph.js +180 -0
- package/dist/commands/sections-graph.js.map +1 -0
- package/dist/commands/sections.d.ts +3 -0
- package/dist/commands/sections.d.ts.map +1 -0
- package/dist/commands/sections.js +376 -0
- package/dist/commands/sections.js.map +1 -0
- package/dist/commands/stats.d.ts +6 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +324 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/tasks.d.ts +3 -0
- package/dist/commands/tasks.d.ts.map +1 -0
- package/dist/commands/tasks.js +1115 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/commands/web.d.ts +7 -0
- package/dist/commands/web.d.ts.map +1 -0
- package/dist/commands/web.js +204 -0
- package/dist/commands/web.js.map +1 -0
- package/dist/config/ai-setup.d.ts +27 -0
- package/dist/config/ai-setup.d.ts.map +1 -0
- package/dist/config/ai-setup.js +432 -0
- package/dist/config/ai-setup.js.map +1 -0
- package/dist/config/browser.d.ts +9 -0
- package/dist/config/browser.d.ts.map +1 -0
- package/dist/config/browser.js +200 -0
- package/dist/config/browser.js.map +1 -0
- package/dist/config/json-schema.d.ts +28 -0
- package/dist/config/json-schema.d.ts.map +1 -0
- package/dist/config/json-schema.js +84 -0
- package/dist/config/json-schema.js.map +1 -0
- package/dist/config/loader.d.ts +152 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +270 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +34 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +437 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/validator.d.ts +32 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +187 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/database/connection.d.ts +35 -0
- package/dist/database/connection.d.ts.map +1 -0
- package/dist/database/connection.js +208 -0
- package/dist/database/connection.js.map +1 -0
- package/dist/database/queries.d.ts +218 -0
- package/dist/database/queries.d.ts.map +1 -0
- package/dist/database/queries.js +613 -0
- package/dist/database/queries.js.map +1 -0
- package/dist/database/schema.d.ts +8 -0
- package/dist/database/schema.d.ts.map +1 -0
- package/dist/database/schema.js +160 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/disputes/behavior.d.ts +106 -0
- package/dist/disputes/behavior.d.ts.map +1 -0
- package/dist/disputes/behavior.js +150 -0
- package/dist/disputes/behavior.js.map +1 -0
- package/dist/disputes/create.d.ts +59 -0
- package/dist/disputes/create.d.ts.map +1 -0
- package/dist/disputes/create.js +222 -0
- package/dist/disputes/create.js.map +1 -0
- package/dist/disputes/index.d.ts +21 -0
- package/dist/disputes/index.d.ts.map +1 -0
- package/dist/disputes/index.js +76 -0
- package/dist/disputes/index.js.map +1 -0
- package/dist/disputes/markdown.d.ts +41 -0
- package/dist/disputes/markdown.d.ts.map +1 -0
- package/dist/disputes/markdown.js +261 -0
- package/dist/disputes/markdown.js.map +1 -0
- package/dist/disputes/queries.d.ts +83 -0
- package/dist/disputes/queries.d.ts.map +1 -0
- package/dist/disputes/queries.js +180 -0
- package/dist/disputes/queries.js.map +1 -0
- package/dist/disputes/resolve.d.ts +57 -0
- package/dist/disputes/resolve.d.ts.map +1 -0
- package/dist/disputes/resolve.js +171 -0
- package/dist/disputes/resolve.js.map +1 -0
- package/dist/disputes/stale.d.ts +98 -0
- package/dist/disputes/stale.d.ts.map +1 -0
- package/dist/disputes/stale.js +205 -0
- package/dist/disputes/stale.js.map +1 -0
- package/dist/disputes/types.d.ts +92 -0
- package/dist/disputes/types.d.ts.map +1 -0
- package/dist/disputes/types.js +100 -0
- package/dist/disputes/types.js.map +1 -0
- package/dist/git/push.d.ts +26 -0
- package/dist/git/push.d.ts.map +1 -0
- package/dist/git/push.js +97 -0
- package/dist/git/push.js.map +1 -0
- package/dist/git/status.d.ts +61 -0
- package/dist/git/status.d.ts.map +1 -0
- package/dist/git/status.js +251 -0
- package/dist/git/status.js.map +1 -0
- package/dist/hooks/events.d.ts +72 -0
- package/dist/hooks/events.d.ts.map +1 -0
- package/dist/hooks/events.js +120 -0
- package/dist/hooks/events.js.map +1 -0
- package/dist/hooks/index.d.ts +19 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +48 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/integration.d.ts +69 -0
- package/dist/hooks/integration.d.ts.map +1 -0
- package/dist/hooks/integration.js +179 -0
- package/dist/hooks/integration.js.map +1 -0
- package/dist/hooks/merge.d.ts +115 -0
- package/dist/hooks/merge.d.ts.map +1 -0
- package/dist/hooks/merge.js +161 -0
- package/dist/hooks/merge.js.map +1 -0
- package/dist/hooks/orchestrator.d.ts +115 -0
- package/dist/hooks/orchestrator.d.ts.map +1 -0
- package/dist/hooks/orchestrator.js +226 -0
- package/dist/hooks/orchestrator.js.map +1 -0
- package/dist/hooks/payload.d.ts +294 -0
- package/dist/hooks/payload.d.ts.map +1 -0
- package/dist/hooks/payload.js +267 -0
- package/dist/hooks/payload.js.map +1 -0
- package/dist/hooks/script-runner.d.ts +63 -0
- package/dist/hooks/script-runner.d.ts.map +1 -0
- package/dist/hooks/script-runner.js +221 -0
- package/dist/hooks/script-runner.js.map +1 -0
- package/dist/hooks/templates.d.ts +104 -0
- package/dist/hooks/templates.d.ts.map +1 -0
- package/dist/hooks/templates.js +327 -0
- package/dist/hooks/templates.js.map +1 -0
- package/dist/hooks/webhook-runner.d.ts +69 -0
- package/dist/hooks/webhook-runner.d.ts.map +1 -0
- package/dist/hooks/webhook-runner.js +208 -0
- package/dist/hooks/webhook-runner.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +281 -0
- package/dist/index.js.map +1 -0
- package/dist/locking/cleanup.d.ts +70 -0
- package/dist/locking/cleanup.d.ts.map +1 -0
- package/dist/locking/cleanup.js +157 -0
- package/dist/locking/cleanup.js.map +1 -0
- package/dist/locking/queries.d.ts +116 -0
- package/dist/locking/queries.d.ts.map +1 -0
- package/dist/locking/queries.js +255 -0
- package/dist/locking/queries.js.map +1 -0
- package/dist/locking/section-lock.d.ts +74 -0
- package/dist/locking/section-lock.d.ts.map +1 -0
- package/dist/locking/section-lock.js +207 -0
- package/dist/locking/section-lock.js.map +1 -0
- package/dist/locking/task-lock.d.ts +92 -0
- package/dist/locking/task-lock.d.ts.map +1 -0
- package/dist/locking/task-lock.js +246 -0
- package/dist/locking/task-lock.js.map +1 -0
- package/dist/migrations/index.d.ts +7 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +37 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/manifest.d.ts +92 -0
- package/dist/migrations/manifest.d.ts.map +1 -0
- package/dist/migrations/manifest.js +270 -0
- package/dist/migrations/manifest.js.map +1 -0
- package/dist/migrations/runner.d.ts +84 -0
- package/dist/migrations/runner.d.ts.map +1 -0
- package/dist/migrations/runner.js +351 -0
- package/dist/migrations/runner.js.map +1 -0
- package/dist/orchestrator/coder.d.ts +32 -0
- package/dist/orchestrator/coder.d.ts.map +1 -0
- package/dist/orchestrator/coder.js +174 -0
- package/dist/orchestrator/coder.js.map +1 -0
- package/dist/orchestrator/coordinator.d.ts +28 -0
- package/dist/orchestrator/coordinator.d.ts.map +1 -0
- package/dist/orchestrator/coordinator.js +256 -0
- package/dist/orchestrator/coordinator.js.map +1 -0
- package/dist/orchestrator/reviewer.d.ts +35 -0
- package/dist/orchestrator/reviewer.d.ts.map +1 -0
- package/dist/orchestrator/reviewer.js +241 -0
- package/dist/orchestrator/reviewer.js.map +1 -0
- package/dist/orchestrator/task-selector.d.ts +102 -0
- package/dist/orchestrator/task-selector.d.ts.map +1 -0
- package/dist/orchestrator/task-selector.js +341 -0
- package/dist/orchestrator/task-selector.js.map +1 -0
- package/dist/prompts/coder.d.ts +36 -0
- package/dist/prompts/coder.d.ts.map +1 -0
- package/dist/prompts/coder.js +315 -0
- package/dist/prompts/coder.js.map +1 -0
- package/dist/prompts/prompt-helpers.d.ts +51 -0
- package/dist/prompts/prompt-helpers.d.ts.map +1 -0
- package/dist/prompts/prompt-helpers.js +312 -0
- package/dist/prompts/prompt-helpers.js.map +1 -0
- package/dist/prompts/reviewer.d.ts +40 -0
- package/dist/prompts/reviewer.d.ts.map +1 -0
- package/dist/prompts/reviewer.js +438 -0
- package/dist/prompts/reviewer.js.map +1 -0
- package/dist/providers/api-models.d.ts +65 -0
- package/dist/providers/api-models.d.ts.map +1 -0
- package/dist/providers/api-models.js +323 -0
- package/dist/providers/api-models.js.map +1 -0
- package/dist/providers/claude.d.ts +53 -0
- package/dist/providers/claude.d.ts.map +1 -0
- package/dist/providers/claude.js +229 -0
- package/dist/providers/claude.js.map +1 -0
- package/dist/providers/codex.d.ts +53 -0
- package/dist/providers/codex.d.ts.map +1 -0
- package/dist/providers/codex.js +214 -0
- package/dist/providers/codex.js.map +1 -0
- package/dist/providers/gemini.d.ts +58 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +242 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +49 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/interface.d.ts +173 -0
- package/dist/providers/interface.d.ts.map +1 -0
- package/dist/providers/interface.js +96 -0
- package/dist/providers/interface.js.map +1 -0
- package/dist/providers/invocation-logger.d.ts +114 -0
- package/dist/providers/invocation-logger.d.ts.map +1 -0
- package/dist/providers/invocation-logger.js +298 -0
- package/dist/providers/invocation-logger.js.map +1 -0
- package/dist/providers/openai.d.ts +53 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +232 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/registry.d.ts +100 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +178 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/runners/activity-log.d.ts +65 -0
- package/dist/runners/activity-log.d.ts.map +1 -0
- package/dist/runners/activity-log.js +148 -0
- package/dist/runners/activity-log.js.map +1 -0
- package/dist/runners/cron.d.ts +26 -0
- package/dist/runners/cron.d.ts.map +1 -0
- package/dist/runners/cron.js +176 -0
- package/dist/runners/cron.js.map +1 -0
- package/dist/runners/daemon.d.ts +71 -0
- package/dist/runners/daemon.d.ts.map +1 -0
- package/dist/runners/daemon.js +245 -0
- package/dist/runners/daemon.js.map +1 -0
- package/dist/runners/global-db.d.ts +31 -0
- package/dist/runners/global-db.d.ts.map +1 -0
- package/dist/runners/global-db.js +230 -0
- package/dist/runners/global-db.js.map +1 -0
- package/dist/runners/hang-detector.d.ts +38 -0
- package/dist/runners/hang-detector.d.ts.map +1 -0
- package/dist/runners/hang-detector.js +136 -0
- package/dist/runners/hang-detector.js.map +1 -0
- package/dist/runners/heartbeat.d.ts +39 -0
- package/dist/runners/heartbeat.d.ts.map +1 -0
- package/dist/runners/heartbeat.js +79 -0
- package/dist/runners/heartbeat.js.map +1 -0
- package/dist/runners/lock.d.ts +47 -0
- package/dist/runners/lock.d.ts.map +1 -0
- package/dist/runners/lock.js +150 -0
- package/dist/runners/lock.js.map +1 -0
- package/dist/runners/orchestrator-loop.d.ts +20 -0
- package/dist/runners/orchestrator-loop.d.ts.map +1 -0
- package/dist/runners/orchestrator-loop.js +285 -0
- package/dist/runners/orchestrator-loop.js.map +1 -0
- package/dist/runners/projects.d.ts +96 -0
- package/dist/runners/projects.d.ts.map +1 -0
- package/dist/runners/projects.js +255 -0
- package/dist/runners/projects.js.map +1 -0
- package/dist/runners/wakeup.d.ts +34 -0
- package/dist/runners/wakeup.d.ts.map +1 -0
- package/dist/runners/wakeup.js +291 -0
- package/dist/runners/wakeup.js.map +1 -0
- package/migrations/001_initial_schema.sql +106 -0
- package/migrations/002_add_commit_sha.sql +12 -0
- package/migrations/003_add_section_priority.sql +13 -0
- package/migrations/004_add_section_dependencies.sql +18 -0
- package/migrations/005_add_audit_actor_model.sql +10 -0
- package/migrations/006_add_task_invocations.sql +33 -0
- package/migrations/007_add_file_anchor.sql +14 -0
- package/migrations/manifest.json +62 -0
- package/package.json +49 -0
|
@@ -0,0 +1,1076 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runnersCommand = runnersCommand;
|
|
37
|
+
/**
|
|
38
|
+
* steroids runners - Manage runner daemons
|
|
39
|
+
*/
|
|
40
|
+
const node_util_1 = require("node:util");
|
|
41
|
+
const node_child_process_1 = require("node:child_process");
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const os = __importStar(require("node:os"));
|
|
45
|
+
const loader_js_1 = require("../config/loader.js");
|
|
46
|
+
const daemon_js_1 = require("../runners/daemon.js");
|
|
47
|
+
const lock_js_1 = require("../runners/lock.js");
|
|
48
|
+
const wakeup_js_1 = require("../runners/wakeup.js");
|
|
49
|
+
const cron_js_1 = require("../runners/cron.js");
|
|
50
|
+
const connection_js_1 = require("../database/connection.js");
|
|
51
|
+
const queries_js_1 = require("../database/queries.js");
|
|
52
|
+
const node_fs_1 = require("node:fs");
|
|
53
|
+
const node_path_1 = require("node:path");
|
|
54
|
+
const projects_js_1 = require("../runners/projects.js");
|
|
55
|
+
const help_js_1 = require("../cli/help.js");
|
|
56
|
+
const HELP = (0, help_js_1.generateHelp)({
|
|
57
|
+
command: 'runners',
|
|
58
|
+
description: 'Manage background runner daemons for automated task execution',
|
|
59
|
+
details: `Runners are daemon processes that execute the orchestrator loop in the background.
|
|
60
|
+
Each project can have one active runner processing tasks.
|
|
61
|
+
Runners can be started manually or managed automatically via cron.`,
|
|
62
|
+
usage: ['steroids runners <subcommand> [options]'],
|
|
63
|
+
subcommands: [
|
|
64
|
+
{ name: 'start', description: 'Start runner daemon (foreground or background)' },
|
|
65
|
+
{ name: 'stop', description: 'Stop runner(s) for current or all projects' },
|
|
66
|
+
{ name: 'status', description: 'Show runner status for current project' },
|
|
67
|
+
{ name: 'list', description: 'List all runners across all projects' },
|
|
68
|
+
{ name: 'logs', args: '[pid]', description: 'View daemon crash/output logs' },
|
|
69
|
+
{ name: 'wakeup', description: 'Check and restart stale runners' },
|
|
70
|
+
{ name: 'cron', args: '<install|uninstall|status>', description: 'Manage cron job for auto-wakeup' },
|
|
71
|
+
],
|
|
72
|
+
options: [
|
|
73
|
+
{ long: 'detach', description: 'Run in background (daemonize) - start subcommand' },
|
|
74
|
+
{ long: 'project', description: 'Project path to work on', values: '<path>' },
|
|
75
|
+
{ long: 'section', description: 'Focus on specific section only', values: '<id|name>' },
|
|
76
|
+
{ long: 'id', description: 'Stop specific runner by ID - stop subcommand', values: '<id>' },
|
|
77
|
+
{ long: 'all', description: 'Stop all runners - stop subcommand' },
|
|
78
|
+
{ long: 'tree', description: 'Show tree view with projects/runners/tasks - list subcommand' },
|
|
79
|
+
{ long: 'tail', description: 'Show last n lines of logs', values: '<n>', default: '50' },
|
|
80
|
+
{ long: 'follow', description: 'Follow log output in real-time' },
|
|
81
|
+
{ long: 'clear', description: 'Clear all daemon logs' },
|
|
82
|
+
],
|
|
83
|
+
examples: [
|
|
84
|
+
{ command: 'steroids runners start', description: 'Start in foreground' },
|
|
85
|
+
{ command: 'steroids runners start --detach', description: 'Start in background' },
|
|
86
|
+
{ command: 'steroids runners start --section "Phase 2"', description: 'Focus on specific section' },
|
|
87
|
+
{ command: 'steroids runners stop', description: 'Stop runner for current project' },
|
|
88
|
+
{ command: 'steroids runners stop --all', description: 'Stop all runners' },
|
|
89
|
+
{ command: 'steroids runners status', description: 'Show runner status' },
|
|
90
|
+
{ command: 'steroids runners list', description: 'List all runners (all projects)' },
|
|
91
|
+
{ command: 'steroids runners list --tree', description: 'Tree view with tasks' },
|
|
92
|
+
{ command: 'steroids runners list --json', description: 'JSON output' },
|
|
93
|
+
{ command: 'steroids runners logs', description: 'List available logs' },
|
|
94
|
+
{ command: 'steroids runners logs 12345', description: 'View logs for PID 12345' },
|
|
95
|
+
{ command: 'steroids runners logs --follow', description: 'Follow latest log' },
|
|
96
|
+
{ command: 'steroids runners wakeup', description: 'Restart stale runners' },
|
|
97
|
+
{ command: 'steroids runners cron install', description: 'Install cron wake-up' },
|
|
98
|
+
{ command: 'steroids runners cron status', description: 'Check cron status' },
|
|
99
|
+
],
|
|
100
|
+
related: [
|
|
101
|
+
{ command: 'steroids loop', description: 'Run orchestrator loop manually' },
|
|
102
|
+
{ command: 'steroids tasks', description: 'View tasks being processed' },
|
|
103
|
+
],
|
|
104
|
+
sections: [
|
|
105
|
+
{
|
|
106
|
+
title: 'MULTI-PROJECT',
|
|
107
|
+
content: `Different projects can run runners in parallel (one per project).
|
|
108
|
+
The 'list' command shows runners from ALL registered projects.
|
|
109
|
+
Use 'wakeup' to check if any projects need runners restarted.`,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
async function runnersCommand(args, flags) {
|
|
114
|
+
if (args.length === 0 || args[0] === '-h' || args[0] === '--help') {
|
|
115
|
+
console.log(HELP);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const subcommand = args[0];
|
|
119
|
+
const subArgs = args.slice(1);
|
|
120
|
+
switch (subcommand) {
|
|
121
|
+
case 'start':
|
|
122
|
+
await runStart(subArgs);
|
|
123
|
+
break;
|
|
124
|
+
case 'stop':
|
|
125
|
+
await runStop(subArgs);
|
|
126
|
+
break;
|
|
127
|
+
case 'status':
|
|
128
|
+
await runStatus(subArgs);
|
|
129
|
+
break;
|
|
130
|
+
case 'list':
|
|
131
|
+
await runList(subArgs, flags);
|
|
132
|
+
break;
|
|
133
|
+
case 'logs':
|
|
134
|
+
await runLogs(subArgs);
|
|
135
|
+
break;
|
|
136
|
+
case 'wakeup':
|
|
137
|
+
await runWakeup(subArgs, flags);
|
|
138
|
+
break;
|
|
139
|
+
case 'cron':
|
|
140
|
+
await runCron(subArgs);
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
144
|
+
console.log(HELP);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function runStart(args) {
|
|
149
|
+
const { values } = (0, node_util_1.parseArgs)({
|
|
150
|
+
args,
|
|
151
|
+
options: {
|
|
152
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
153
|
+
json: { type: 'boolean', short: 'j', default: false },
|
|
154
|
+
detach: { type: 'boolean', short: 'd', default: false },
|
|
155
|
+
project: { type: 'string', short: 'p' },
|
|
156
|
+
section: { type: 'string' },
|
|
157
|
+
},
|
|
158
|
+
allowPositionals: false,
|
|
159
|
+
});
|
|
160
|
+
if (values.help) {
|
|
161
|
+
console.log(`
|
|
162
|
+
steroids runners start - Start runner daemon
|
|
163
|
+
|
|
164
|
+
USAGE:
|
|
165
|
+
steroids runners start [options]
|
|
166
|
+
|
|
167
|
+
OPTIONS:
|
|
168
|
+
--detach Run in background
|
|
169
|
+
--project <path> Project path
|
|
170
|
+
--section <id|name> Focus on a specific section only
|
|
171
|
+
-j, --json Output as JSON
|
|
172
|
+
-h, --help Show help
|
|
173
|
+
`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// Check if we can start
|
|
177
|
+
// Default to cwd if --project not specified, to ensure proper per-project tracking
|
|
178
|
+
// Always resolve to absolute path for consistent tracking across processes
|
|
179
|
+
const projectPath = path.resolve(values.project ?? process.cwd());
|
|
180
|
+
const check = (0, daemon_js_1.canStartDaemon)(projectPath);
|
|
181
|
+
if (!check.canStart && !check.reason?.includes('zombie')) {
|
|
182
|
+
if (values.json) {
|
|
183
|
+
console.log(JSON.stringify({
|
|
184
|
+
success: false,
|
|
185
|
+
error: check.reason,
|
|
186
|
+
existingPid: check.existingPid,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.error(`Cannot start: ${check.reason}`);
|
|
191
|
+
if (check.existingPid) {
|
|
192
|
+
console.error(`Existing runner PID: ${check.existingPid}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
process.exit(6);
|
|
196
|
+
}
|
|
197
|
+
// Resolve section if --section flag is provided
|
|
198
|
+
let focusedSectionId;
|
|
199
|
+
if (values.section) {
|
|
200
|
+
const sectionInput = values.section;
|
|
201
|
+
const { db, close } = (0, connection_js_1.openDatabase)(projectPath);
|
|
202
|
+
try {
|
|
203
|
+
// Try to resolve by ID (exact or prefix match)
|
|
204
|
+
let section;
|
|
205
|
+
try {
|
|
206
|
+
section = (0, queries_js_1.getSection)(db, sectionInput);
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
// Handle ambiguous prefix error
|
|
210
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
211
|
+
if (values.json) {
|
|
212
|
+
console.log(JSON.stringify({ success: false, error: errorMsg }));
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.error(`Error: ${errorMsg}`);
|
|
216
|
+
console.error('');
|
|
217
|
+
console.error('Available sections:');
|
|
218
|
+
const sections = (0, queries_js_1.listSections)(db);
|
|
219
|
+
if (sections.length === 0) {
|
|
220
|
+
console.error(' (no sections defined)');
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
for (const s of sections) {
|
|
224
|
+
console.error(` ${s.id.substring(0, 8)} ${s.name}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
close();
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
// If not found by ID, try by name
|
|
232
|
+
if (!section) {
|
|
233
|
+
section = (0, queries_js_1.getSectionByName)(db, sectionInput);
|
|
234
|
+
}
|
|
235
|
+
if (!section) {
|
|
236
|
+
const errorMsg = `Section not found: ${sectionInput}`;
|
|
237
|
+
if (values.json) {
|
|
238
|
+
console.log(JSON.stringify({ success: false, error: errorMsg }));
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
console.error(`Error: ${errorMsg}`);
|
|
242
|
+
console.error('');
|
|
243
|
+
console.error('Available sections:');
|
|
244
|
+
const sections = (0, queries_js_1.listSections)(db);
|
|
245
|
+
if (sections.length === 0) {
|
|
246
|
+
console.error(' (no sections defined)');
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
for (const s of sections) {
|
|
250
|
+
console.error(` ${s.id.substring(0, 8)} ${s.name}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
close();
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
// Check if section is skipped (Phase 0.6 feature)
|
|
258
|
+
if (section.skipped === 1) {
|
|
259
|
+
const errorMsg = `Section "${section.name}" is currently skipped`;
|
|
260
|
+
if (values.json) {
|
|
261
|
+
console.log(JSON.stringify({ success: false, error: errorMsg }));
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
console.error(`Error: ${errorMsg}`);
|
|
265
|
+
console.error('');
|
|
266
|
+
console.error(`Run 'steroids sections unskip "${section.name}"' to re-enable it.`);
|
|
267
|
+
}
|
|
268
|
+
close();
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
focusedSectionId = section.id;
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
close();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (values.detach) {
|
|
278
|
+
// Spawn detached process - always pass --project for proper tracking
|
|
279
|
+
const spawnArgs = [process.argv[1], 'runners', 'start', '--project', projectPath];
|
|
280
|
+
// Pass --section if specified
|
|
281
|
+
if (values.section) {
|
|
282
|
+
spawnArgs.push('--section', values.section);
|
|
283
|
+
}
|
|
284
|
+
// Check config for daemon logging preference
|
|
285
|
+
const config = (0, loader_js_1.loadConfig)(projectPath);
|
|
286
|
+
const daemonLogsEnabled = config.runners?.daemonLogs !== false;
|
|
287
|
+
let logFile;
|
|
288
|
+
let logFd;
|
|
289
|
+
if (daemonLogsEnabled) {
|
|
290
|
+
// Create logs directory and log file for daemon output
|
|
291
|
+
const logsDir = path.join(os.homedir(), '.steroids', 'runners', 'logs');
|
|
292
|
+
fs.mkdirSync(logsDir, { recursive: true });
|
|
293
|
+
// Use timestamp for now, will rename after we have PID
|
|
294
|
+
const tempLogPath = path.join(logsDir, `daemon-${Date.now()}.log`);
|
|
295
|
+
logFd = fs.openSync(tempLogPath, 'a');
|
|
296
|
+
logFile = tempLogPath;
|
|
297
|
+
}
|
|
298
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, spawnArgs, {
|
|
299
|
+
detached: true,
|
|
300
|
+
stdio: daemonLogsEnabled && logFd !== undefined
|
|
301
|
+
? ['ignore', logFd, logFd]
|
|
302
|
+
: 'ignore',
|
|
303
|
+
});
|
|
304
|
+
child.unref();
|
|
305
|
+
// Clean up file descriptor and rename log file
|
|
306
|
+
if (logFd !== undefined) {
|
|
307
|
+
fs.closeSync(logFd);
|
|
308
|
+
}
|
|
309
|
+
let finalLogPath;
|
|
310
|
+
if (logFile && child.pid) {
|
|
311
|
+
const logsDir = path.dirname(logFile);
|
|
312
|
+
finalLogPath = path.join(logsDir, `daemon-${child.pid}.log`);
|
|
313
|
+
try {
|
|
314
|
+
fs.renameSync(logFile, finalLogPath);
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
finalLogPath = logFile; // Keep temp name if rename fails
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (values.json) {
|
|
321
|
+
console.log(JSON.stringify({
|
|
322
|
+
success: true,
|
|
323
|
+
pid: child.pid,
|
|
324
|
+
detached: true,
|
|
325
|
+
logFile: finalLogPath,
|
|
326
|
+
}));
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
console.log(`Runner started in background (PID: ${child.pid})`);
|
|
330
|
+
if (finalLogPath) {
|
|
331
|
+
console.log(` Log file: ${finalLogPath}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
// Start in foreground
|
|
337
|
+
await (0, daemon_js_1.startDaemon)({ projectPath, sectionId: focusedSectionId });
|
|
338
|
+
}
|
|
339
|
+
async function runStop(args) {
|
|
340
|
+
const { values } = (0, node_util_1.parseArgs)({
|
|
341
|
+
args,
|
|
342
|
+
options: {
|
|
343
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
344
|
+
json: { type: 'boolean', short: 'j', default: false },
|
|
345
|
+
id: { type: 'string' },
|
|
346
|
+
all: { type: 'boolean', default: false },
|
|
347
|
+
},
|
|
348
|
+
allowPositionals: false,
|
|
349
|
+
});
|
|
350
|
+
if (values.help) {
|
|
351
|
+
console.log(`
|
|
352
|
+
steroids runners stop - Stop runner(s)
|
|
353
|
+
|
|
354
|
+
USAGE:
|
|
355
|
+
steroids runners stop [options]
|
|
356
|
+
|
|
357
|
+
OPTIONS:
|
|
358
|
+
--id <id> Stop specific runner
|
|
359
|
+
--all Stop all runners
|
|
360
|
+
-j, --json Output as JSON
|
|
361
|
+
-h, --help Show help
|
|
362
|
+
`);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
// Capture stop context for logging
|
|
366
|
+
const stopContext = {
|
|
367
|
+
calledFrom: process.cwd(),
|
|
368
|
+
callerPid: process.pid,
|
|
369
|
+
timestamp: new Date().toISOString(),
|
|
370
|
+
user: process.env.USER || process.env.USERNAME || 'unknown',
|
|
371
|
+
args: {
|
|
372
|
+
id: values.id,
|
|
373
|
+
all: values.all,
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
const runners = (0, daemon_js_1.listRunners)();
|
|
377
|
+
let stopped = 0;
|
|
378
|
+
const stoppedRunners = [];
|
|
379
|
+
const runnersToStop = values.id
|
|
380
|
+
? runners.filter((r) => r.id === values.id || r.id.startsWith(values.id))
|
|
381
|
+
: values.all
|
|
382
|
+
? runners
|
|
383
|
+
: runners.filter((r) => r.pid === process.pid || r.pid !== null);
|
|
384
|
+
// Log stop action to daemon logs
|
|
385
|
+
const logsDir = path.join(os.homedir(), '.steroids', 'runners', 'logs');
|
|
386
|
+
const stopLogPath = path.join(logsDir, 'stop-audit.log');
|
|
387
|
+
fs.mkdirSync(logsDir, { recursive: true });
|
|
388
|
+
for (const runner of runnersToStop) {
|
|
389
|
+
if (runner.pid && (0, lock_js_1.isProcessAlive)(runner.pid)) {
|
|
390
|
+
try {
|
|
391
|
+
process.kill(runner.pid, 'SIGTERM');
|
|
392
|
+
stopped++;
|
|
393
|
+
stoppedRunners.push({
|
|
394
|
+
id: runner.id,
|
|
395
|
+
pid: runner.pid,
|
|
396
|
+
project: runner.project_path,
|
|
397
|
+
});
|
|
398
|
+
// Log each stop to audit log
|
|
399
|
+
const logEntry = {
|
|
400
|
+
...stopContext,
|
|
401
|
+
action: 'stop',
|
|
402
|
+
runner: {
|
|
403
|
+
id: runner.id,
|
|
404
|
+
pid: runner.pid,
|
|
405
|
+
project: runner.project_path,
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
fs.appendFileSync(stopLogPath, JSON.stringify(logEntry) + '\n');
|
|
409
|
+
}
|
|
410
|
+
catch {
|
|
411
|
+
// Process already dead
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
(0, daemon_js_1.unregisterRunner)(runner.id);
|
|
415
|
+
}
|
|
416
|
+
if (values.json) {
|
|
417
|
+
console.log(JSON.stringify({
|
|
418
|
+
success: true,
|
|
419
|
+
stopped,
|
|
420
|
+
stoppedRunners,
|
|
421
|
+
context: stopContext,
|
|
422
|
+
}));
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
console.log(`Stopped ${stopped} runner(s)`);
|
|
426
|
+
if (stopped > 0 && !values.all) {
|
|
427
|
+
console.log(` Called from: ${stopContext.calledFrom}`);
|
|
428
|
+
console.log(` Audit log: ${stopLogPath}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async function runStatus(args) {
|
|
433
|
+
const { values } = (0, node_util_1.parseArgs)({
|
|
434
|
+
args,
|
|
435
|
+
options: {
|
|
436
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
437
|
+
json: { type: 'boolean', short: 'j', default: false },
|
|
438
|
+
},
|
|
439
|
+
allowPositionals: false,
|
|
440
|
+
});
|
|
441
|
+
if (values.help) {
|
|
442
|
+
console.log(`
|
|
443
|
+
steroids runners status - Show runner status
|
|
444
|
+
|
|
445
|
+
USAGE:
|
|
446
|
+
steroids runners status [options]
|
|
447
|
+
|
|
448
|
+
OPTIONS:
|
|
449
|
+
-j, --json Output as JSON
|
|
450
|
+
-h, --help Show help
|
|
451
|
+
`);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const lockStatus = (0, lock_js_1.checkLockStatus)();
|
|
455
|
+
const runners = (0, daemon_js_1.listRunners)();
|
|
456
|
+
const activeRunner = runners.find((r) => r.pid && (0, lock_js_1.isProcessAlive)(r.pid));
|
|
457
|
+
const status = {
|
|
458
|
+
locked: lockStatus.locked,
|
|
459
|
+
lockPid: lockStatus.pid,
|
|
460
|
+
isZombie: lockStatus.isZombie,
|
|
461
|
+
activeRunner: activeRunner
|
|
462
|
+
? {
|
|
463
|
+
id: activeRunner.id,
|
|
464
|
+
pid: activeRunner.pid,
|
|
465
|
+
status: activeRunner.status,
|
|
466
|
+
project: activeRunner.project_path,
|
|
467
|
+
currentTask: activeRunner.current_task_id,
|
|
468
|
+
heartbeat: activeRunner.heartbeat_at,
|
|
469
|
+
}
|
|
470
|
+
: null,
|
|
471
|
+
totalRunners: runners.length,
|
|
472
|
+
};
|
|
473
|
+
if (values.json) {
|
|
474
|
+
console.log(JSON.stringify(status, null, 2));
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (activeRunner) {
|
|
478
|
+
console.log(`Runner Status: ACTIVE`);
|
|
479
|
+
console.log(` ID: ${activeRunner.id}`);
|
|
480
|
+
console.log(` PID: ${activeRunner.pid}`);
|
|
481
|
+
console.log(` Status: ${activeRunner.status}`);
|
|
482
|
+
if (activeRunner.project_path) {
|
|
483
|
+
console.log(` Project: ${activeRunner.project_path}`);
|
|
484
|
+
}
|
|
485
|
+
if (activeRunner.current_task_id) {
|
|
486
|
+
console.log(` Current Task: ${activeRunner.current_task_id}`);
|
|
487
|
+
}
|
|
488
|
+
console.log(` Last Heartbeat: ${activeRunner.heartbeat_at}`);
|
|
489
|
+
}
|
|
490
|
+
else if (lockStatus.isZombie) {
|
|
491
|
+
console.log(`Runner Status: ZOMBIE`);
|
|
492
|
+
console.log(` Lock exists but process (PID: ${lockStatus.pid}) is dead`);
|
|
493
|
+
console.log(` Run 'steroids runners wakeup' to clean up`);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
console.log(`Runner Status: INACTIVE`);
|
|
497
|
+
console.log(` No runner is currently active`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
async function runList(args, flags) {
|
|
501
|
+
const { values } = (0, node_util_1.parseArgs)({
|
|
502
|
+
args,
|
|
503
|
+
options: {
|
|
504
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
505
|
+
tree: { type: 'boolean', short: 't', default: false },
|
|
506
|
+
},
|
|
507
|
+
allowPositionals: false,
|
|
508
|
+
});
|
|
509
|
+
if (values.help || flags.help) {
|
|
510
|
+
console.log(`
|
|
511
|
+
steroids runners list - List all runners
|
|
512
|
+
|
|
513
|
+
USAGE:
|
|
514
|
+
steroids runners list [options]
|
|
515
|
+
|
|
516
|
+
OPTIONS:
|
|
517
|
+
-t, --tree Show tree view with tasks
|
|
518
|
+
-j, --json Output as JSON (global flag)
|
|
519
|
+
-h, --help Show help
|
|
520
|
+
`);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
// Tree view mode
|
|
524
|
+
if (values.tree) {
|
|
525
|
+
await runListTree(flags.json);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const runners = (0, daemon_js_1.listRunners)();
|
|
529
|
+
if (flags.json) {
|
|
530
|
+
// For JSON output, enrich with section names if available
|
|
531
|
+
const enrichedRunners = runners.map((runner) => {
|
|
532
|
+
if (!runner.section_id || !runner.project_path) {
|
|
533
|
+
return runner;
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
const { db, close } = (0, connection_js_1.openDatabase)(runner.project_path);
|
|
537
|
+
try {
|
|
538
|
+
const section = (0, queries_js_1.getSection)(db, runner.section_id);
|
|
539
|
+
return { ...runner, section_name: section?.name };
|
|
540
|
+
}
|
|
541
|
+
finally {
|
|
542
|
+
close();
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
catch {
|
|
546
|
+
return runner;
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
console.log(JSON.stringify({ runners: enrichedRunners }, null, 2));
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
if (runners.length === 0) {
|
|
553
|
+
console.log('No runners registered');
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
console.log('RUNNERS');
|
|
557
|
+
console.log('─'.repeat(120));
|
|
558
|
+
console.log('ID STATUS PID PROJECT SECTION HEARTBEAT');
|
|
559
|
+
console.log('─'.repeat(120));
|
|
560
|
+
for (const runner of runners) {
|
|
561
|
+
const shortId = runner.id.substring(0, 8);
|
|
562
|
+
const status = runner.status.padEnd(10);
|
|
563
|
+
const pid = (runner.pid?.toString() ?? '-').padEnd(9);
|
|
564
|
+
const project = (runner.project_path ?? '-').substring(0, 30).padEnd(30);
|
|
565
|
+
// Fetch section name if available
|
|
566
|
+
let sectionDisplay = '-';
|
|
567
|
+
if (runner.section_id && runner.project_path) {
|
|
568
|
+
try {
|
|
569
|
+
const { db, close } = (0, connection_js_1.openDatabase)(runner.project_path);
|
|
570
|
+
try {
|
|
571
|
+
const section = (0, queries_js_1.getSection)(db, runner.section_id);
|
|
572
|
+
if (section) {
|
|
573
|
+
sectionDisplay = section.name.substring(0, 30);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
finally {
|
|
577
|
+
close();
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
catch {
|
|
581
|
+
// If we can't fetch the section name, just show the ID prefix
|
|
582
|
+
sectionDisplay = runner.section_id.substring(0, 8);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
const section = sectionDisplay.padEnd(30);
|
|
586
|
+
const heartbeat = runner.heartbeat_at.substring(11, 19);
|
|
587
|
+
const alive = runner.pid && (0, lock_js_1.isProcessAlive)(runner.pid) ? '' : ' (dead)';
|
|
588
|
+
console.log(`${shortId} ${status} ${pid} ${project} ${section} ${heartbeat}${alive}`);
|
|
589
|
+
}
|
|
590
|
+
// Check if there are multiple projects
|
|
591
|
+
const uniqueProjects = new Set(runners.map(r => r.project_path).filter(Boolean));
|
|
592
|
+
if (uniqueProjects.size > 1) {
|
|
593
|
+
const currentProject = process.cwd();
|
|
594
|
+
console.log('');
|
|
595
|
+
console.log('─'.repeat(120));
|
|
596
|
+
console.log(`⚠️ MULTI-PROJECT WARNING: ${uniqueProjects.size} different projects have runners.`);
|
|
597
|
+
console.log(` Your current project: ${currentProject}`);
|
|
598
|
+
console.log(' DO NOT modify files in other projects. Each runner works only on its own project.');
|
|
599
|
+
console.log('─'.repeat(120));
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Tree view of runners grouped by project with their current tasks
|
|
604
|
+
*/
|
|
605
|
+
async function runListTree(json) {
|
|
606
|
+
const runners = (0, daemon_js_1.listRunners)();
|
|
607
|
+
const projects = (0, projects_js_1.getRegisteredProjects)(false);
|
|
608
|
+
const projectMap = new Map();
|
|
609
|
+
// Initialize with all registered projects
|
|
610
|
+
for (const project of projects) {
|
|
611
|
+
projectMap.set(project.path, {
|
|
612
|
+
path: project.path,
|
|
613
|
+
name: project.name || (0, node_path_1.basename)(project.path),
|
|
614
|
+
runners: [],
|
|
615
|
+
activeTasks: [],
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
// Add runners to their projects
|
|
619
|
+
for (const runner of runners) {
|
|
620
|
+
const projectPath = runner.project_path;
|
|
621
|
+
if (!projectPath)
|
|
622
|
+
continue;
|
|
623
|
+
if (!projectMap.has(projectPath)) {
|
|
624
|
+
projectMap.set(projectPath, {
|
|
625
|
+
path: projectPath,
|
|
626
|
+
name: (0, node_path_1.basename)(projectPath),
|
|
627
|
+
runners: [],
|
|
628
|
+
activeTasks: [],
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
const info = projectMap.get(projectPath);
|
|
632
|
+
info.runners.push(runner);
|
|
633
|
+
}
|
|
634
|
+
// Fetch active tasks for each project
|
|
635
|
+
for (const [projectPath, info] of projectMap) {
|
|
636
|
+
const dbPath = `${projectPath}/.steroids/steroids.db`;
|
|
637
|
+
if (!(0, node_fs_1.existsSync)(dbPath))
|
|
638
|
+
continue;
|
|
639
|
+
try {
|
|
640
|
+
const { db, close } = (0, connection_js_1.openDatabase)(projectPath);
|
|
641
|
+
try {
|
|
642
|
+
const inProgress = (0, queries_js_1.listTasks)(db, { status: 'in_progress' });
|
|
643
|
+
const review = (0, queries_js_1.listTasks)(db, { status: 'review' });
|
|
644
|
+
info.activeTasks = [...inProgress, ...review];
|
|
645
|
+
}
|
|
646
|
+
finally {
|
|
647
|
+
close();
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
catch {
|
|
651
|
+
// Skip inaccessible projects
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
// JSON output
|
|
655
|
+
if (json) {
|
|
656
|
+
const output = Array.from(projectMap.values()).map((info) => ({
|
|
657
|
+
project: info.path,
|
|
658
|
+
name: info.name,
|
|
659
|
+
runners: info.runners.map((r) => ({
|
|
660
|
+
id: r.id,
|
|
661
|
+
status: r.status,
|
|
662
|
+
pid: r.pid,
|
|
663
|
+
currentTaskId: r.current_task_id,
|
|
664
|
+
alive: r.pid ? (0, lock_js_1.isProcessAlive)(r.pid) : false,
|
|
665
|
+
})),
|
|
666
|
+
activeTasks: info.activeTasks.map((t) => ({
|
|
667
|
+
id: t.id,
|
|
668
|
+
title: t.title,
|
|
669
|
+
status: t.status,
|
|
670
|
+
})),
|
|
671
|
+
}));
|
|
672
|
+
console.log(JSON.stringify({ projects: output }, null, 2));
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
// Text tree view
|
|
676
|
+
const projectList = Array.from(projectMap.values());
|
|
677
|
+
const currentProject = process.cwd();
|
|
678
|
+
if (projectList.length === 0) {
|
|
679
|
+
console.log('No registered projects.');
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
console.log('');
|
|
683
|
+
console.log('RUNNERS TREE');
|
|
684
|
+
console.log('═'.repeat(80));
|
|
685
|
+
for (let i = 0; i < projectList.length; i++) {
|
|
686
|
+
const info = projectList[i];
|
|
687
|
+
const isLast = i === projectList.length - 1;
|
|
688
|
+
const isCurrent = info.path === currentProject;
|
|
689
|
+
const currentMarker = isCurrent ? ' ← (current)' : '';
|
|
690
|
+
console.log('');
|
|
691
|
+
console.log(`📁 ${info.name}${currentMarker}`);
|
|
692
|
+
console.log(` ${info.path}`);
|
|
693
|
+
if (info.runners.length === 0) {
|
|
694
|
+
console.log(' └─ (no runners)');
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
for (let j = 0; j < info.runners.length; j++) {
|
|
698
|
+
const runner = info.runners[j];
|
|
699
|
+
const isLastRunner = j === info.runners.length - 1;
|
|
700
|
+
const runnerPrefix = isLastRunner ? '└─' : '├─';
|
|
701
|
+
const childPrefix = isLastRunner ? ' ' : '│ ';
|
|
702
|
+
const alive = runner.pid && (0, lock_js_1.isProcessAlive)(runner.pid);
|
|
703
|
+
const statusIcon = alive ? '🟢' : '🔴';
|
|
704
|
+
const statusText = alive ? runner.status : 'dead';
|
|
705
|
+
const pidText = runner.pid ? ` PID ${runner.pid}` : '';
|
|
706
|
+
console.log(` ${runnerPrefix} ${statusIcon} Runner ${runner.id.substring(0, 8)} (${statusText}${pidText})`);
|
|
707
|
+
// Show section if focused
|
|
708
|
+
if (runner.section_id && runner.project_path) {
|
|
709
|
+
try {
|
|
710
|
+
const { db, close } = (0, connection_js_1.openDatabase)(runner.project_path);
|
|
711
|
+
try {
|
|
712
|
+
const section = (0, queries_js_1.getSection)(db, runner.section_id);
|
|
713
|
+
if (section) {
|
|
714
|
+
console.log(` ${childPrefix} Section: ${section.name}`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
finally {
|
|
718
|
+
close();
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
catch {
|
|
722
|
+
// Ignore section fetch errors
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
// Show current task if available
|
|
726
|
+
if (runner.current_task_id && runner.project_path) {
|
|
727
|
+
try {
|
|
728
|
+
const { db, close } = (0, connection_js_1.openDatabase)(runner.project_path);
|
|
729
|
+
try {
|
|
730
|
+
const task = (0, queries_js_1.getTask)(db, runner.current_task_id);
|
|
731
|
+
if (task) {
|
|
732
|
+
const statusMarker = task.status === 'in_progress' ? '🔧' : '👁️';
|
|
733
|
+
console.log(` ${childPrefix} ${statusMarker} ${task.title.substring(0, 50)}`);
|
|
734
|
+
console.log(` ${childPrefix} [${task.status}] ${task.id.substring(0, 8)}`);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
finally {
|
|
738
|
+
close();
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
catch {
|
|
742
|
+
console.log(` ${childPrefix} Task: ${runner.current_task_id.substring(0, 8)}`);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
else if (alive) {
|
|
746
|
+
console.log(` ${childPrefix} (idle - no task)`);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
// Show other active tasks not being worked on by runners
|
|
751
|
+
const runnerTaskIds = new Set(info.runners.map((r) => r.current_task_id).filter(Boolean));
|
|
752
|
+
const unassignedTasks = info.activeTasks.filter((t) => !runnerTaskIds.has(t.id));
|
|
753
|
+
if (unassignedTasks.length > 0) {
|
|
754
|
+
console.log(' │');
|
|
755
|
+
console.log(' └─ 📋 Queued active tasks:');
|
|
756
|
+
for (const task of unassignedTasks.slice(0, 5)) {
|
|
757
|
+
const statusIcon = task.status === 'in_progress' ? '🔧' : '👁️';
|
|
758
|
+
console.log(` ${statusIcon} ${task.title.substring(0, 45)} [${task.status}]`);
|
|
759
|
+
}
|
|
760
|
+
if (unassignedTasks.length > 5) {
|
|
761
|
+
console.log(` ... and ${unassignedTasks.length - 5} more`);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
console.log('');
|
|
766
|
+
console.log('═'.repeat(80));
|
|
767
|
+
// Multi-project warning
|
|
768
|
+
const activeProjects = projectList.filter((p) => p.runners.length > 0);
|
|
769
|
+
if (activeProjects.length > 1) {
|
|
770
|
+
console.log('');
|
|
771
|
+
console.log('⚠️ MULTI-PROJECT: Multiple projects have active runners.');
|
|
772
|
+
console.log(' Each runner works ONLY on its own project.');
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
async function runLogs(args) {
|
|
776
|
+
const { values, positionals } = (0, node_util_1.parseArgs)({
|
|
777
|
+
args,
|
|
778
|
+
options: {
|
|
779
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
780
|
+
json: { type: 'boolean', short: 'j', default: false },
|
|
781
|
+
tail: { type: 'string', short: 'n', default: '50' },
|
|
782
|
+
follow: { type: 'boolean', short: 'f', default: false },
|
|
783
|
+
clear: { type: 'boolean', default: false },
|
|
784
|
+
},
|
|
785
|
+
allowPositionals: true,
|
|
786
|
+
});
|
|
787
|
+
if (values.help) {
|
|
788
|
+
console.log(`
|
|
789
|
+
steroids runners logs - View daemon crash/output logs
|
|
790
|
+
|
|
791
|
+
USAGE:
|
|
792
|
+
steroids runners logs [pid] [options]
|
|
793
|
+
|
|
794
|
+
OPTIONS:
|
|
795
|
+
<pid> Show logs for specific daemon PID
|
|
796
|
+
--tail <n> Show last n lines (default: 50)
|
|
797
|
+
--follow Follow log output (latest log)
|
|
798
|
+
--clear Clear all daemon logs
|
|
799
|
+
-j, --json Output as JSON
|
|
800
|
+
-h, --help Show help
|
|
801
|
+
|
|
802
|
+
LOG LOCATION:
|
|
803
|
+
Logs are stored in ~/.steroids/runners/logs/
|
|
804
|
+
Each daemon gets its own log file: daemon-<pid>.log
|
|
805
|
+
|
|
806
|
+
To disable daemon logging, set in config:
|
|
807
|
+
steroids config set runners.daemonLogs false
|
|
808
|
+
|
|
809
|
+
EXAMPLES:
|
|
810
|
+
steroids runners logs # List available log files
|
|
811
|
+
steroids runners logs 12345 # View logs for PID 12345
|
|
812
|
+
steroids runners logs --follow # Follow the latest log
|
|
813
|
+
steroids runners logs --clear # Remove all log files
|
|
814
|
+
`);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const logsDir = path.join(os.homedir(), '.steroids', 'runners', 'logs');
|
|
818
|
+
// Handle --clear
|
|
819
|
+
if (values.clear) {
|
|
820
|
+
if (!fs.existsSync(logsDir)) {
|
|
821
|
+
if (values.json) {
|
|
822
|
+
console.log(JSON.stringify({ success: true, cleared: 0 }));
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
console.log('No logs directory found');
|
|
826
|
+
}
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const files = fs.readdirSync(logsDir).filter((f) => f.endsWith('.log'));
|
|
830
|
+
for (const file of files) {
|
|
831
|
+
fs.unlinkSync(path.join(logsDir, file));
|
|
832
|
+
}
|
|
833
|
+
if (values.json) {
|
|
834
|
+
console.log(JSON.stringify({ success: true, cleared: files.length }));
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
console.log(`Cleared ${files.length} log file(s)`);
|
|
838
|
+
}
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
// Ensure logs directory exists
|
|
842
|
+
if (!fs.existsSync(logsDir)) {
|
|
843
|
+
if (values.json) {
|
|
844
|
+
console.log(JSON.stringify({ logs: [], logsDir }));
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
console.log('No daemon logs found');
|
|
848
|
+
console.log(` Logs are stored in: ${logsDir}`);
|
|
849
|
+
}
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
const logFiles = fs.readdirSync(logsDir)
|
|
853
|
+
.filter((f) => f.startsWith('daemon-') && f.endsWith('.log'))
|
|
854
|
+
.map((f) => {
|
|
855
|
+
const filePath = path.join(logsDir, f);
|
|
856
|
+
const stats = fs.statSync(filePath);
|
|
857
|
+
const pidMatch = f.match(/daemon-(\d+)\.log/);
|
|
858
|
+
return {
|
|
859
|
+
file: f,
|
|
860
|
+
path: filePath,
|
|
861
|
+
pid: pidMatch ? parseInt(pidMatch[1], 10) : null,
|
|
862
|
+
size: stats.size,
|
|
863
|
+
modified: stats.mtime,
|
|
864
|
+
};
|
|
865
|
+
})
|
|
866
|
+
.sort((a, b) => b.modified.getTime() - a.modified.getTime());
|
|
867
|
+
// If a PID is specified, show that log
|
|
868
|
+
if (positionals.length > 0) {
|
|
869
|
+
const pidArg = positionals[0];
|
|
870
|
+
const logFile = logFiles.find((l) => l.pid?.toString() === pidArg || l.file.includes(pidArg));
|
|
871
|
+
if (!logFile) {
|
|
872
|
+
console.error(`No log found for PID: ${pidArg}`);
|
|
873
|
+
process.exit(1);
|
|
874
|
+
}
|
|
875
|
+
const content = fs.readFileSync(logFile.path, 'utf-8');
|
|
876
|
+
const lines = content.split('\n');
|
|
877
|
+
const tailLines = parseInt(values.tail, 10) || 50;
|
|
878
|
+
const output = lines.slice(-tailLines).join('\n');
|
|
879
|
+
if (values.json) {
|
|
880
|
+
console.log(JSON.stringify({ pid: logFile.pid, path: logFile.path, content: output }));
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
console.log(`=== Daemon log for PID ${logFile.pid} ===`);
|
|
884
|
+
console.log(`File: ${logFile.path}`);
|
|
885
|
+
console.log(`Modified: ${logFile.modified.toISOString()}`);
|
|
886
|
+
console.log('─'.repeat(60));
|
|
887
|
+
console.log(output);
|
|
888
|
+
}
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
// If --follow, tail the most recent log
|
|
892
|
+
if (values.follow) {
|
|
893
|
+
if (logFiles.length === 0) {
|
|
894
|
+
console.error('No log files to follow');
|
|
895
|
+
process.exit(1);
|
|
896
|
+
}
|
|
897
|
+
const latestLog = logFiles[0];
|
|
898
|
+
console.log(`Following: ${latestLog.path} (PID: ${latestLog.pid})`);
|
|
899
|
+
console.log('─'.repeat(60));
|
|
900
|
+
// Use spawn to tail -f
|
|
901
|
+
const tail = (0, node_child_process_1.spawn)('tail', ['-f', latestLog.path], { stdio: 'inherit' });
|
|
902
|
+
tail.on('error', (err) => {
|
|
903
|
+
console.error(`Error following log: ${err.message}`);
|
|
904
|
+
process.exit(1);
|
|
905
|
+
});
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
// List all log files
|
|
909
|
+
if (values.json) {
|
|
910
|
+
console.log(JSON.stringify({ logs: logFiles, logsDir }, null, 2));
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
if (logFiles.length === 0) {
|
|
914
|
+
console.log('No daemon logs found');
|
|
915
|
+
console.log(` Logs are stored in: ${logsDir}`);
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
console.log('DAEMON LOGS');
|
|
919
|
+
console.log('─'.repeat(80));
|
|
920
|
+
console.log('PID SIZE MODIFIED FILE');
|
|
921
|
+
console.log('─'.repeat(80));
|
|
922
|
+
for (const log of logFiles) {
|
|
923
|
+
const pid = (log.pid?.toString() ?? 'unknown').padEnd(10);
|
|
924
|
+
const size = formatBytes(log.size).padEnd(9);
|
|
925
|
+
const modified = log.modified.toISOString().substring(0, 19).padEnd(22);
|
|
926
|
+
console.log(`${pid} ${size} ${modified} ${log.file}`);
|
|
927
|
+
}
|
|
928
|
+
console.log('');
|
|
929
|
+
console.log(`Logs directory: ${logsDir}`);
|
|
930
|
+
console.log(`Use 'steroids runners logs <pid>' to view a specific log`);
|
|
931
|
+
}
|
|
932
|
+
function formatBytes(bytes) {
|
|
933
|
+
if (bytes === 0)
|
|
934
|
+
return '0 B';
|
|
935
|
+
const k = 1024;
|
|
936
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
937
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
938
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
939
|
+
}
|
|
940
|
+
async function runWakeup(args, flags) {
|
|
941
|
+
const { values } = (0, node_util_1.parseArgs)({
|
|
942
|
+
args,
|
|
943
|
+
options: {
|
|
944
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
945
|
+
json: { type: 'boolean', short: 'j', default: false },
|
|
946
|
+
quiet: { type: 'boolean', short: 'q', default: false },
|
|
947
|
+
},
|
|
948
|
+
allowPositionals: false,
|
|
949
|
+
});
|
|
950
|
+
if (values.help) {
|
|
951
|
+
console.log(`
|
|
952
|
+
steroids runners wakeup - Check and restart stale runners
|
|
953
|
+
|
|
954
|
+
USAGE:
|
|
955
|
+
steroids runners wakeup [options]
|
|
956
|
+
|
|
957
|
+
OPTIONS:
|
|
958
|
+
--quiet Suppress output (for cron)
|
|
959
|
+
--dry-run Check without acting
|
|
960
|
+
-j, --json Output as JSON
|
|
961
|
+
-h, --help Show help
|
|
962
|
+
`);
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const results = await (0, wakeup_js_1.wakeup)({
|
|
966
|
+
quiet: values.quiet || flags.quiet || values.json || flags.json,
|
|
967
|
+
dryRun: flags.dryRun,
|
|
968
|
+
});
|
|
969
|
+
if (values.json || flags.json) {
|
|
970
|
+
console.log(JSON.stringify({ results }, null, 2));
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
if (!values.quiet && !flags.quiet) {
|
|
974
|
+
// Summarize results
|
|
975
|
+
const started = results.filter(r => r.action === 'started').length;
|
|
976
|
+
const cleaned = results.filter(r => r.action === 'cleaned').length;
|
|
977
|
+
const wouldStart = results.filter(r => r.action === 'would_start').length;
|
|
978
|
+
if (started > 0) {
|
|
979
|
+
console.log(`Started ${started} runner(s)`);
|
|
980
|
+
}
|
|
981
|
+
if (cleaned > 0) {
|
|
982
|
+
console.log(`Cleaned ${cleaned} stale runner(s)`);
|
|
983
|
+
}
|
|
984
|
+
if (wouldStart > 0) {
|
|
985
|
+
console.log(`Would start ${wouldStart} runner(s) (dry-run)`);
|
|
986
|
+
}
|
|
987
|
+
if (started === 0 && cleaned === 0 && wouldStart === 0) {
|
|
988
|
+
console.log('No action needed');
|
|
989
|
+
}
|
|
990
|
+
// Show per-project details
|
|
991
|
+
for (const result of results) {
|
|
992
|
+
if (result.projectPath) {
|
|
993
|
+
const status = result.action === 'started' ? '✓' :
|
|
994
|
+
result.action === 'would_start' ? '~' : '-';
|
|
995
|
+
console.log(` ${status} ${result.projectPath}: ${result.reason}`);
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
async function runCron(args) {
|
|
1001
|
+
if (args.length === 0 || args[0] === '-h' || args[0] === '--help') {
|
|
1002
|
+
console.log(`
|
|
1003
|
+
steroids runners cron - Manage cron job
|
|
1004
|
+
|
|
1005
|
+
USAGE:
|
|
1006
|
+
steroids runners cron <subcommand>
|
|
1007
|
+
|
|
1008
|
+
SUBCOMMANDS:
|
|
1009
|
+
install Add cron job (every minute)
|
|
1010
|
+
uninstall Remove cron job
|
|
1011
|
+
status Check cron status
|
|
1012
|
+
|
|
1013
|
+
OPTIONS:
|
|
1014
|
+
-j, --json Output as JSON
|
|
1015
|
+
-h, --help Show help
|
|
1016
|
+
`);
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
const subcommand = args[0];
|
|
1020
|
+
const subArgs = args.slice(1);
|
|
1021
|
+
const { values } = (0, node_util_1.parseArgs)({
|
|
1022
|
+
args: subArgs,
|
|
1023
|
+
options: {
|
|
1024
|
+
json: { type: 'boolean', short: 'j', default: false },
|
|
1025
|
+
},
|
|
1026
|
+
allowPositionals: false,
|
|
1027
|
+
});
|
|
1028
|
+
switch (subcommand) {
|
|
1029
|
+
case 'install': {
|
|
1030
|
+
const result = (0, cron_js_1.cronInstall)();
|
|
1031
|
+
if (values.json) {
|
|
1032
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1033
|
+
}
|
|
1034
|
+
else {
|
|
1035
|
+
console.log(result.message);
|
|
1036
|
+
if (result.error) {
|
|
1037
|
+
console.error(result.error);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
break;
|
|
1041
|
+
}
|
|
1042
|
+
case 'uninstall': {
|
|
1043
|
+
const result = (0, cron_js_1.cronUninstall)();
|
|
1044
|
+
if (values.json) {
|
|
1045
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
console.log(result.message);
|
|
1049
|
+
}
|
|
1050
|
+
break;
|
|
1051
|
+
}
|
|
1052
|
+
case 'status': {
|
|
1053
|
+
const status = (0, cron_js_1.cronStatus)();
|
|
1054
|
+
if (values.json) {
|
|
1055
|
+
console.log(JSON.stringify(status, null, 2));
|
|
1056
|
+
}
|
|
1057
|
+
else {
|
|
1058
|
+
if (status.installed) {
|
|
1059
|
+
console.log('Cron job: INSTALLED');
|
|
1060
|
+
console.log(` Entry: ${status.entry}`);
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
console.log('Cron job: NOT INSTALLED');
|
|
1064
|
+
if (status.error) {
|
|
1065
|
+
console.log(` ${status.error}`);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
break;
|
|
1070
|
+
}
|
|
1071
|
+
default:
|
|
1072
|
+
console.error(`Unknown cron subcommand: ${subcommand}`);
|
|
1073
|
+
process.exit(1);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
//# sourceMappingURL=runners.js.map
|