@josharsh/demon-cli 0.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.
Files changed (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +130 -0
  3. package/dist/actions/base.d.ts +4 -0
  4. package/dist/actions/base.d.ts.map +1 -0
  5. package/dist/actions/base.js +32 -0
  6. package/dist/actions/base.js.map +1 -0
  7. package/dist/actions/file.d.ts +7 -0
  8. package/dist/actions/file.d.ts.map +1 -0
  9. package/dist/actions/file.js +35 -0
  10. package/dist/actions/file.js.map +1 -0
  11. package/dist/actions/github.d.ts +7 -0
  12. package/dist/actions/github.d.ts.map +1 -0
  13. package/dist/actions/github.js +125 -0
  14. package/dist/actions/github.js.map +1 -0
  15. package/dist/actions/index.d.ts +5 -0
  16. package/dist/actions/index.d.ts.map +1 -0
  17. package/dist/actions/index.js +22 -0
  18. package/dist/actions/index.js.map +1 -0
  19. package/dist/actions/log.d.ts +7 -0
  20. package/dist/actions/log.d.ts.map +1 -0
  21. package/dist/actions/log.js +30 -0
  22. package/dist/actions/log.js.map +1 -0
  23. package/dist/actions/notify.d.ts +11 -0
  24. package/dist/actions/notify.d.ts.map +1 -0
  25. package/dist/actions/notify.js +34 -0
  26. package/dist/actions/notify.js.map +1 -0
  27. package/dist/actions/script.d.ts +7 -0
  28. package/dist/actions/script.d.ts.map +1 -0
  29. package/dist/actions/script.js +46 -0
  30. package/dist/actions/script.js.map +1 -0
  31. package/dist/actions/slack.d.ts +7 -0
  32. package/dist/actions/slack.d.ts.map +1 -0
  33. package/dist/actions/slack.js +47 -0
  34. package/dist/actions/slack.js.map +1 -0
  35. package/dist/actions/webhook.d.ts +7 -0
  36. package/dist/actions/webhook.d.ts.map +1 -0
  37. package/dist/actions/webhook.js +41 -0
  38. package/dist/actions/webhook.js.map +1 -0
  39. package/dist/adapters/clock.d.ts +3 -0
  40. package/dist/adapters/clock.d.ts.map +1 -0
  41. package/dist/adapters/clock.js +8 -0
  42. package/dist/adapters/clock.js.map +1 -0
  43. package/dist/adapters/fs-kv.d.ts +3 -0
  44. package/dist/adapters/fs-kv.d.ts.map +1 -0
  45. package/dist/adapters/fs-kv.js +34 -0
  46. package/dist/adapters/fs-kv.js.map +1 -0
  47. package/dist/adapters/keys.d.ts +3 -0
  48. package/dist/adapters/keys.d.ts.map +1 -0
  49. package/dist/adapters/keys.js +17 -0
  50. package/dist/adapters/keys.js.map +1 -0
  51. package/dist/commands/ensure-provider.d.ts +7 -0
  52. package/dist/commands/ensure-provider.d.ts.map +1 -0
  53. package/dist/commands/ensure-provider.js +121 -0
  54. package/dist/commands/ensure-provider.js.map +1 -0
  55. package/dist/commands/init.d.ts +2 -0
  56. package/dist/commands/init.d.ts.map +1 -0
  57. package/dist/commands/init.js +196 -0
  58. package/dist/commands/init.js.map +1 -0
  59. package/dist/commands/inspect.d.ts +7 -0
  60. package/dist/commands/inspect.d.ts.map +1 -0
  61. package/dist/commands/inspect.js +97 -0
  62. package/dist/commands/inspect.js.map +1 -0
  63. package/dist/commands/install.d.ts +3 -0
  64. package/dist/commands/install.d.ts.map +1 -0
  65. package/dist/commands/install.js +192 -0
  66. package/dist/commands/install.js.map +1 -0
  67. package/dist/commands/logs.d.ts +8 -0
  68. package/dist/commands/logs.d.ts.map +1 -0
  69. package/dist/commands/logs.js +103 -0
  70. package/dist/commands/logs.js.map +1 -0
  71. package/dist/commands/providers.d.ts +5 -0
  72. package/dist/commands/providers.d.ts.map +1 -0
  73. package/dist/commands/providers.js +251 -0
  74. package/dist/commands/providers.js.map +1 -0
  75. package/dist/commands/ps.d.ts +2 -0
  76. package/dist/commands/ps.d.ts.map +1 -0
  77. package/dist/commands/ps.js +87 -0
  78. package/dist/commands/ps.js.map +1 -0
  79. package/dist/commands/secrets.d.ts +9 -0
  80. package/dist/commands/secrets.d.ts.map +1 -0
  81. package/dist/commands/secrets.js +97 -0
  82. package/dist/commands/secrets.js.map +1 -0
  83. package/dist/commands/start.d.ts +10 -0
  84. package/dist/commands/start.d.ts.map +1 -0
  85. package/dist/commands/start.js +238 -0
  86. package/dist/commands/start.js.map +1 -0
  87. package/dist/commands/status.d.ts +2 -0
  88. package/dist/commands/status.d.ts.map +1 -0
  89. package/dist/commands/status.js +69 -0
  90. package/dist/commands/status.js.map +1 -0
  91. package/dist/commands/stop.d.ts +6 -0
  92. package/dist/commands/stop.d.ts.map +1 -0
  93. package/dist/commands/stop.js +43 -0
  94. package/dist/commands/stop.js.map +1 -0
  95. package/dist/index.d.ts +3 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +253 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/providers/config.d.ts +8 -0
  100. package/dist/providers/config.d.ts.map +1 -0
  101. package/dist/providers/config.js +31 -0
  102. package/dist/providers/config.js.map +1 -0
  103. package/dist/providers/credentials.d.ts +5 -0
  104. package/dist/providers/credentials.d.ts.map +1 -0
  105. package/dist/providers/credentials.js +69 -0
  106. package/dist/providers/credentials.js.map +1 -0
  107. package/dist/providers/registry.d.ts +12 -0
  108. package/dist/providers/registry.d.ts.map +1 -0
  109. package/dist/providers/registry.js +58 -0
  110. package/dist/providers/registry.js.map +1 -0
  111. package/dist/providers/secrets.d.ts +9 -0
  112. package/dist/providers/secrets.d.ts.map +1 -0
  113. package/dist/providers/secrets.js +44 -0
  114. package/dist/providers/secrets.js.map +1 -0
  115. package/dist/providers/system-auth.d.ts +8 -0
  116. package/dist/providers/system-auth.d.ts.map +1 -0
  117. package/dist/providers/system-auth.js +168 -0
  118. package/dist/providers/system-auth.js.map +1 -0
  119. package/dist/runtime/daemon.d.ts +10 -0
  120. package/dist/runtime/daemon.d.ts.map +1 -0
  121. package/dist/runtime/daemon.js +264 -0
  122. package/dist/runtime/daemon.js.map +1 -0
  123. package/dist/runtime/supervisor.d.ts +6 -0
  124. package/dist/runtime/supervisor.d.ts.map +1 -0
  125. package/dist/runtime/supervisor.js +45 -0
  126. package/dist/runtime/supervisor.js.map +1 -0
  127. package/dist/types.d.ts +27 -0
  128. package/dist/types.d.ts.map +1 -0
  129. package/dist/types.js +7 -0
  130. package/dist/types.js.map +1 -0
  131. package/dist/utils/logger.d.ts +4 -0
  132. package/dist/utils/logger.d.ts.map +1 -0
  133. package/dist/utils/logger.js +44 -0
  134. package/dist/utils/logger.js.map +1 -0
  135. package/dist/utils/manifest.d.ts +5 -0
  136. package/dist/utils/manifest.d.ts.map +1 -0
  137. package/dist/utils/manifest.js +276 -0
  138. package/dist/utils/manifest.js.map +1 -0
  139. package/dist/utils/paths.d.ts +13 -0
  140. package/dist/utils/paths.d.ts.map +1 -0
  141. package/dist/utils/paths.js +52 -0
  142. package/dist/utils/paths.js.map +1 -0
  143. package/dist/utils/time.d.ts +11 -0
  144. package/dist/utils/time.d.ts.map +1 -0
  145. package/dist/utils/time.js +40 -0
  146. package/dist/utils/time.js.map +1 -0
  147. package/dist/watchers/base.d.ts +3 -0
  148. package/dist/watchers/base.d.ts.map +1 -0
  149. package/dist/watchers/base.js +20 -0
  150. package/dist/watchers/base.js.map +1 -0
  151. package/dist/watchers/filesystem.d.ts +12 -0
  152. package/dist/watchers/filesystem.d.ts.map +1 -0
  153. package/dist/watchers/filesystem.js +211 -0
  154. package/dist/watchers/filesystem.js.map +1 -0
  155. package/dist/watchers/github.d.ts +3 -0
  156. package/dist/watchers/github.d.ts.map +1 -0
  157. package/dist/watchers/github.js +322 -0
  158. package/dist/watchers/github.js.map +1 -0
  159. package/dist/watchers/http.d.ts +13 -0
  160. package/dist/watchers/http.d.ts.map +1 -0
  161. package/dist/watchers/http.js +149 -0
  162. package/dist/watchers/http.js.map +1 -0
  163. package/dist/watchers/index.d.ts +8 -0
  164. package/dist/watchers/index.d.ts.map +1 -0
  165. package/dist/watchers/index.js +25 -0
  166. package/dist/watchers/index.js.map +1 -0
  167. package/examples/README.md +9 -0
  168. package/examples/codebase-guardian.yaml +22 -0
  169. package/examples/competitor-watch.yaml +18 -0
  170. package/examples/founder-sentinel.md +126 -0
  171. package/examples/founder-sentinel.yaml +27 -0
  172. package/package.json +62 -0
@@ -0,0 +1,238 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import fs from 'fs-extra';
4
+ import { join } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname } from 'path';
7
+ import { spawn } from 'child_process';
8
+ import { parseManifestFile, parseManifestNL } from '../utils/manifest.js';
9
+ import { ensureAll, statePath, memoryDir, secretsDir, providerPath, manifestsDir } from '../utils/paths.js';
10
+ import { parseInterval } from '../utils/time.js';
11
+ import { createLLMProvider } from '@josharsh/demon';
12
+ import { resolveKeysFromEnv } from '../adapters/keys.js';
13
+ import { ensureProviderForModel } from './ensure-provider.js';
14
+ import { installCommand } from './install.js';
15
+ import inquirer from 'inquirer';
16
+ // Load ~/.demon/secrets/*.json and ~/.demon/providers/*.json into process.env
17
+ // so buildLLMProvider can find keys regardless of how they were stored.
18
+ async function injectStoredCredentials() {
19
+ // 1. Per-key secrets (demon secrets set KEY)
20
+ const sDir = secretsDir();
21
+ if (await fs.pathExists(sDir)) {
22
+ const files = await fs.readdir(sDir).catch(() => []);
23
+ for (const file of files) {
24
+ if (!file.endsWith('.json'))
25
+ continue;
26
+ try {
27
+ const rec = await fs.readJson(join(sDir, file));
28
+ if (rec.key && rec.value && !process.env[rec.key]) {
29
+ process.env[rec.key] = rec.value;
30
+ }
31
+ }
32
+ catch { }
33
+ }
34
+ }
35
+ // 2. Provider credential files (demon providers add anthropic)
36
+ const ENV_MAP = {
37
+ anthropic: ['ANTHROPIC_API_KEY', 'api_key'],
38
+ openai: ['OPENAI_API_KEY', 'api_key'],
39
+ openrouter: ['OPENROUTER_API_KEY', 'api_key'],
40
+ groq: ['GROQ_API_KEY', 'api_key'],
41
+ gemini: ['GEMINI_API_KEY', 'api_key'],
42
+ mistral: ['MISTRAL_API_KEY', 'api_key'],
43
+ github: ['GITHUB_TOKEN', 'token'],
44
+ };
45
+ for (const [provider, [envVar, field]] of Object.entries(ENV_MAP)) {
46
+ if (process.env[envVar])
47
+ continue;
48
+ const pFile = providerPath(provider);
49
+ if (await fs.pathExists(pFile)) {
50
+ try {
51
+ const rec = await fs.readJson(pFile);
52
+ const val = rec.credentials?.[field];
53
+ if (val)
54
+ process.env[envVar] = val;
55
+ }
56
+ catch { }
57
+ }
58
+ }
59
+ }
60
+ export async function startCommand(fileOrIntent, options) {
61
+ await ensureAll();
62
+ await injectStoredCredentials();
63
+ let manifest;
64
+ const spinner = ora('Parsing manifest...').start();
65
+ const isFilePath = fileOrIntent.endsWith('.yaml') ||
66
+ fileOrIntent.endsWith('.yml') ||
67
+ fileOrIntent.endsWith('.json') ||
68
+ (await fs.pathExists(fileOrIntent).catch(() => false));
69
+ if (isFilePath) {
70
+ try {
71
+ manifest = await parseManifestFile(fileOrIntent);
72
+ spinner.succeed(`Loaded manifest: ${chalk.bold(manifest.name)}`);
73
+ }
74
+ catch (err) {
75
+ spinner.fail(`Failed to load manifest: ${err.message}`);
76
+ process.exit(1);
77
+ }
78
+ // Pre-flight: make sure this manifest's model has a usable provider/key
79
+ // before we spawn the background daemon (which would otherwise fail silently).
80
+ await ensureProviderForModel(manifest.model);
81
+ }
82
+ else {
83
+ // Natural language intent — generate manifest via LLM.
84
+ // Pre-flight the provider first so we don't fail mid-spinner.
85
+ spinner.stop();
86
+ await ensureProviderForModel(options.model ?? 'claude-sonnet-4-6');
87
+ spinner.start('Generating manifest from natural language...');
88
+ let llmProvider;
89
+ try {
90
+ llmProvider = createLLMProvider(options.model ?? 'claude-sonnet-4-6', resolveKeysFromEnv());
91
+ }
92
+ catch (err) {
93
+ spinner.fail(`Failed to initialize LLM: ${err.message}`);
94
+ process.exit(1);
95
+ }
96
+ try {
97
+ manifest = await parseManifestNL(fileOrIntent, llmProvider);
98
+ spinner.succeed('Generated manifest from intent');
99
+ }
100
+ catch (err) {
101
+ spinner.fail(`Failed to generate manifest: ${err.message}`);
102
+ process.exit(1);
103
+ }
104
+ // Show manifest and ask for confirmation
105
+ console.log('\n' + chalk.bold('Generated manifest:'));
106
+ console.log(chalk.gray(JSON.stringify(manifest, null, 2)));
107
+ const { confirmed } = await inquirer.prompt([
108
+ {
109
+ type: 'confirm',
110
+ name: 'confirmed',
111
+ message: 'Start this demon with the above manifest?',
112
+ default: true,
113
+ },
114
+ ]);
115
+ if (!confirmed) {
116
+ console.log(chalk.yellow('Aborted. Edit the manifest and try again.'));
117
+ process.exit(0);
118
+ }
119
+ }
120
+ // Apply CLI overrides
121
+ if (options.dryRun)
122
+ manifest.action_mode = 'dry_run';
123
+ if (options.auto)
124
+ manifest.action_mode = 'auto';
125
+ if (options.interval)
126
+ manifest.interval = options.interval;
127
+ if (options.model)
128
+ manifest.model = options.model;
129
+ // Check if already running
130
+ const stateFile = statePath(manifest.name);
131
+ if (await fs.pathExists(stateFile)) {
132
+ const existing = await fs.readJson(stateFile);
133
+ if (existing.status === 'running') {
134
+ const alive = isProcessAlive(existing.pid);
135
+ if (alive) {
136
+ console.log(chalk.yellow(`Demon "${manifest.name}" is already running (PID ${existing.pid}).`));
137
+ console.log(chalk.dim('Use `demon stop <name>` first, or `demon ps` to list all demons.'));
138
+ process.exit(1);
139
+ }
140
+ }
141
+ }
142
+ // Validate interval
143
+ try {
144
+ parseInterval(manifest.interval);
145
+ }
146
+ catch (err) {
147
+ console.error(chalk.red(`Invalid interval "${manifest.interval}": ${err.message}`));
148
+ process.exit(1);
149
+ }
150
+ // Ensure memory dir for this demon
151
+ await fs.ensureDir(join(memoryDir(), manifest.name));
152
+ // Write manifest to ~/.demon/manifests/<name>.json so the daemon can read it
153
+ const manifestJsonPath = join(manifestsDir(), `${manifest.name}.json`);
154
+ await fs.writeJson(manifestJsonPath, manifest, { spaces: 2 });
155
+ // Write initial state — pid is 0 placeholder; daemon will overwrite with its real pid
156
+ const state = {
157
+ pid: 0,
158
+ name: manifest.name,
159
+ manifestPath: isFilePath ? fileOrIntent : '(generated from natural language)',
160
+ startedAt: new Date().toISOString(),
161
+ cycles: 0,
162
+ actionsCount: 0,
163
+ lastCheck: null,
164
+ status: 'starting',
165
+ model: manifest.model,
166
+ actionMode: manifest.action_mode,
167
+ };
168
+ await fs.writeJson(stateFile, state, { spaces: 2 });
169
+ // Resolve path to compiled daemon entry point
170
+ const __filename = fileURLToPath(import.meta.url);
171
+ const __dirname = dirname(__filename);
172
+ const daemonScript = join(__dirname, '../runtime/daemon.js');
173
+ // Spawn daemon as a true background process — detached, stdio ignored
174
+ const child = spawn(process.execPath, [daemonScript, manifestJsonPath, stateFile], {
175
+ detached: true,
176
+ stdio: 'ignore',
177
+ env: { ...process.env }, // pass injected secrets to child
178
+ });
179
+ child.unref(); // allow parent CLI to exit immediately
180
+ // Wait up to 3 seconds for daemon to update state to 'running'
181
+ const daemonPid = child.pid ?? 0;
182
+ const pollStart = Date.now();
183
+ let started = false;
184
+ while (Date.now() - pollStart < 3000) {
185
+ await sleep(200);
186
+ try {
187
+ const current = await fs.readJson(stateFile);
188
+ if (current.status === 'running') {
189
+ started = true;
190
+ break;
191
+ }
192
+ if (current.status === 'error') {
193
+ console.error(chalk.red(`\n Demon "${manifest.name}" failed to start. Check logs: demon logs ${manifest.name}`));
194
+ process.exit(1);
195
+ }
196
+ }
197
+ catch {
198
+ // state file may not be readable yet
199
+ }
200
+ }
201
+ if (!started) {
202
+ // Daemon may still be initializing (slow LLM warmup etc.) — not a hard failure
203
+ console.log(chalk.yellow(`\n Demon "${manifest.name}" is starting (PID ${daemonPid}) — not yet confirmed running.`));
204
+ console.log(chalk.dim(` Check status: demon ps | demon logs ${manifest.name}`));
205
+ }
206
+ else {
207
+ // Read back the real pid written by daemon
208
+ let realPid = daemonPid;
209
+ try {
210
+ const current = await fs.readJson(stateFile);
211
+ if (current.pid)
212
+ realPid = current.pid;
213
+ }
214
+ catch { }
215
+ console.log(chalk.bold.green(`\n Demon ${manifest.name} started (PID ${realPid})`));
216
+ console.log(chalk.dim(` Purpose: ${manifest.purpose}`));
217
+ console.log(chalk.dim(` Interval: ${manifest.interval}`));
218
+ console.log(chalk.dim(` Model: ${manifest.model}`));
219
+ console.log(chalk.dim(` Action mode: ${manifest.action_mode}`));
220
+ console.log(chalk.dim(` Logs: demon logs ${manifest.name}\n`));
221
+ if (options.install) {
222
+ await installCommand(manifest.name);
223
+ }
224
+ }
225
+ }
226
+ function isProcessAlive(pid) {
227
+ try {
228
+ process.kill(pid, 0);
229
+ return true;
230
+ }
231
+ catch {
232
+ return false;
233
+ }
234
+ }
235
+ function sleep(ms) {
236
+ return new Promise(resolve => setTimeout(resolve, ms));
237
+ }
238
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function statusCommand(name: string): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAMA,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6D/D"}
@@ -0,0 +1,69 @@
1
+ import chalk from 'chalk';
2
+ import fs from 'fs-extra';
3
+ import { statePath } from '../utils/paths.js';
4
+ import prettyMs from 'pretty-ms';
5
+ export async function statusCommand(name) {
6
+ const stateFile = statePath(name);
7
+ if (!(await fs.pathExists(stateFile))) {
8
+ console.error(chalk.red(`\n No demon named "${name}" found.\n`));
9
+ process.exit(1);
10
+ }
11
+ let state;
12
+ try {
13
+ state = await fs.readJson(stateFile);
14
+ }
15
+ catch {
16
+ console.error(chalk.red(`\n Could not read state for demon "${name}". File may be corrupt.\n`));
17
+ process.exit(1);
18
+ }
19
+ // Check live status
20
+ let effectiveStatus = state.status;
21
+ if (state.status === 'running') {
22
+ if (!isProcessAlive(state.pid)) {
23
+ effectiveStatus = 'stopped';
24
+ }
25
+ }
26
+ const statusColor = {
27
+ running: chalk.green,
28
+ paused: chalk.yellow,
29
+ stopped: chalk.gray,
30
+ error: chalk.red,
31
+ starting: chalk.cyan,
32
+ }[effectiveStatus] ?? chalk.white;
33
+ const uptime = state.startedAt
34
+ ? prettyMs(Date.now() - new Date(state.startedAt).getTime())
35
+ : 'unknown';
36
+ const lastCheck = state.lastCheck
37
+ ? `${new Date(state.lastCheck).toLocaleString()} (${prettyMs(Date.now() - new Date(state.lastCheck).getTime())} ago)`
38
+ : 'Never';
39
+ console.log();
40
+ console.log(chalk.bold.magenta(` ${state.name}`));
41
+ console.log(chalk.dim(' ─'.repeat(30)));
42
+ row('Status', statusColor(effectiveStatus));
43
+ row('PID', String(state.pid));
44
+ row('Model', state.model);
45
+ row('Action Mode', state.actionMode);
46
+ row('Started', `${new Date(state.startedAt).toLocaleString()} (${uptime} ago)`);
47
+ row('Last Check', lastCheck);
48
+ row('Cycles', String(state.cycles));
49
+ row('Actions Fired', String(state.actionsCount));
50
+ row('Manifest', state.manifestPath);
51
+ console.log();
52
+ if (effectiveStatus === 'stopped' && state.status === 'running') {
53
+ console.log(chalk.yellow(' Warning: demon process is not running but state shows "running". It may have crashed.\n'));
54
+ }
55
+ }
56
+ function row(label, value) {
57
+ const pad = 18;
58
+ console.log(` ${chalk.dim(label.padEnd(pad))} ${value}`);
59
+ }
60
+ function isProcessAlive(pid) {
61
+ try {
62
+ process.kill(pid, 0);
63
+ return true;
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ interface StopOptions {
2
+ force?: boolean;
3
+ }
4
+ export declare function stopCommand(name: string, options: StopOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=stop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAKA,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CnF"}
@@ -0,0 +1,43 @@
1
+ import chalk from 'chalk';
2
+ import fs from 'fs-extra';
3
+ import { statePath } from '../utils/paths.js';
4
+ export async function stopCommand(name, options) {
5
+ const stateFile = statePath(name);
6
+ if (!(await fs.pathExists(stateFile))) {
7
+ console.error(chalk.red(`No demon named "${name}" found.`));
8
+ console.log(chalk.dim('Run `demon ps` to list running demons.'));
9
+ process.exit(1);
10
+ }
11
+ let state;
12
+ try {
13
+ state = await fs.readJson(stateFile);
14
+ }
15
+ catch {
16
+ console.error(chalk.red(`Could not read state for demon "${name}". File may be corrupt.`));
17
+ process.exit(1);
18
+ }
19
+ if (state.status === 'stopped') {
20
+ console.log(chalk.yellow(`Demon "${name}" is already stopped.`));
21
+ return;
22
+ }
23
+ // Send SIGTERM to the process
24
+ try {
25
+ process.kill(state.pid, options.force ? 'SIGKILL' : 'SIGTERM');
26
+ console.log(chalk.green(`Sent ${options.force ? 'SIGKILL' : 'SIGTERM'} to demon "${name}" (PID ${state.pid})`));
27
+ }
28
+ catch (err) {
29
+ const code = err.code;
30
+ if (code === 'ESRCH') {
31
+ // Process doesn't exist — clean up stale state
32
+ console.log(chalk.yellow(`Demon "${name}" (PID ${state.pid}) is not running. Cleaning up stale state.`));
33
+ }
34
+ else {
35
+ console.error(chalk.red(`Failed to stop demon "${name}": ${err.message}`));
36
+ process.exit(1);
37
+ }
38
+ }
39
+ // Update state on disk
40
+ await fs.writeJson(stateFile, { ...state, status: 'stopped' }, { spaces: 2 });
41
+ console.log(chalk.dim(`State updated → stopped`));
42
+ }
43
+ //# sourceMappingURL=stop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,MAAM,UAAU,CAAA;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAO7C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAAoB;IAClE,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAEjC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,IAAI,UAAU,CAAC,CAAC,CAAA;QAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC,CAAA;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,IAAI,KAAiB,CAAA;IACrB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mCAAmC,IAAI,yBAAyB,CAAC,CAAC,CAAA;QAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,IAAI,uBAAuB,CAAC,CAAC,CAAA;QAChE,OAAM;IACR,CAAC;IAED,8BAA8B;IAC9B,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC9D,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CACT,QAAQ,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,cAAc,IAAI,UAAU,KAAK,CAAC,GAAG,GAAG,CACtF,CACF,CAAA;IACH,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAA;QAChD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,+CAA+C;YAC/C,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,UAAU,IAAI,UAAU,KAAK,CAAC,GAAG,4CAA4C,CAAC,CAC5F,CAAA;QACH,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,IAAI,MAAO,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;YACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;IAED,uBAAuB;IACvB,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAA;IAC7E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAA;AACnD,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+ import { readFileSync } from 'fs';
6
+ // Load package.json for version
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ let version = '0.1.0';
9
+ try {
10
+ const pkgPath = join(__dirname, '..', 'package.json');
11
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
12
+ version = pkg.version;
13
+ }
14
+ catch {
15
+ // fall back to hardcoded version
16
+ }
17
+ // Lazy imports for each command (avoids loading everything on every invocation)
18
+ import { initCommand } from './commands/init.js';
19
+ import { startCommand } from './commands/start.js';
20
+ import { stopCommand } from './commands/stop.js';
21
+ import { psCommand } from './commands/ps.js';
22
+ import { statusCommand } from './commands/status.js';
23
+ import { logsCommand } from './commands/logs.js';
24
+ import { inspectCommand } from './commands/inspect.js';
25
+ import { providersAddCommand, providersListCommand, providersRemoveCommand, } from './commands/providers.js';
26
+ import { secretsSetCommand, secretsGetCommand, secretsListCommand, } from './commands/secrets.js';
27
+ import { installCommand, uninstallCommand } from './commands/install.js';
28
+ const program = new Command();
29
+ program
30
+ .name('demon')
31
+ .description('AI-native daemon runtime — persistent reasoning processes with purpose')
32
+ .version(version, '-v, --version', 'Print version number')
33
+ .option('--verbose', 'Enable verbose/debug output')
34
+ .hook('preAction', (thisCommand) => {
35
+ if (thisCommand.opts().verbose) {
36
+ process.env.DEMON_LOG_LEVEL = 'debug';
37
+ }
38
+ });
39
+ // ─── demon init ───────────────────────────────────────────────
40
+ program
41
+ .command('init')
42
+ .description('Interactive wizard to create a new demon manifest')
43
+ .action(async () => {
44
+ try {
45
+ await initCommand();
46
+ }
47
+ catch (err) {
48
+ handleError(err);
49
+ }
50
+ });
51
+ // ─── demon start ──────────────────────────────────────────────
52
+ program
53
+ .command('start <fileOrIntent>')
54
+ .description('Start a demon from a manifest file (.yaml/.yml/.json) or natural language intent')
55
+ .option('--dry-run', 'Override action_mode to dry_run (never executes actions)')
56
+ .option('--auto', 'Override action_mode to auto (full autonomy)')
57
+ .option('--interval <interval>', 'Override check interval (e.g. 5m, 1h)')
58
+ .option('--model <model>', 'Override LLM model (e.g. claude-sonnet-4-6, gpt-4o)')
59
+ .option('--install', 'Register demon with OS init system for reboot persistence')
60
+ .action(async (fileOrIntent, options) => {
61
+ try {
62
+ await startCommand(fileOrIntent, options);
63
+ }
64
+ catch (err) {
65
+ handleError(err);
66
+ }
67
+ });
68
+ // ─── demon stop ───────────────────────────────────────────────
69
+ program
70
+ .command('stop <name>')
71
+ .description('Stop a running demon by name')
72
+ .option('-f, --force', 'Send SIGKILL instead of SIGTERM')
73
+ .action(async (name, options) => {
74
+ try {
75
+ await stopCommand(name, options);
76
+ }
77
+ catch (err) {
78
+ handleError(err);
79
+ }
80
+ });
81
+ // ─── demon install ────────────────────────────────────────────
82
+ program
83
+ .command('install <name>')
84
+ .description('Register a demon with the OS init system so it auto-starts on reboot')
85
+ .action(async (name) => {
86
+ try {
87
+ await installCommand(name);
88
+ }
89
+ catch (err) {
90
+ handleError(err);
91
+ }
92
+ });
93
+ // ─── demon uninstall ──────────────────────────────────────────
94
+ program
95
+ .command('uninstall <name>')
96
+ .description('Unregister a demon from the OS init system')
97
+ .action(async (name) => {
98
+ try {
99
+ await uninstallCommand(name);
100
+ }
101
+ catch (err) {
102
+ handleError(err);
103
+ }
104
+ });
105
+ // ─── demon ps ─────────────────────────────────────────────────
106
+ program
107
+ .command('ps')
108
+ .description('List all demons and their status')
109
+ .action(async () => {
110
+ try {
111
+ await psCommand();
112
+ }
113
+ catch (err) {
114
+ handleError(err);
115
+ }
116
+ });
117
+ // ─── demon status ─────────────────────────────────────────────
118
+ program
119
+ .command('status <name>')
120
+ .description('Show detailed status of a specific demon')
121
+ .action(async (name) => {
122
+ try {
123
+ await statusCommand(name);
124
+ }
125
+ catch (err) {
126
+ handleError(err);
127
+ }
128
+ });
129
+ // ─── demon logs ───────────────────────────────────────────────
130
+ program
131
+ .command('logs <name>')
132
+ .description('View logs for a demon')
133
+ .option('-f, --follow', 'Stream new logs as they arrive')
134
+ .option('-n, --lines <count>', 'Number of lines to show (default: 50)', '50')
135
+ .option('--raw', 'Print raw JSON log lines without formatting')
136
+ .action(async (name, options) => {
137
+ try {
138
+ await logsCommand(name, options);
139
+ }
140
+ catch (err) {
141
+ handleError(err);
142
+ }
143
+ });
144
+ // ─── demon inspect ────────────────────────────────────────────
145
+ program
146
+ .command('inspect <name>')
147
+ .description('Detailed view with reasoning history and action log')
148
+ .option('-n, --last <count>', 'Number of recent cycles to show (default: 10)', '10')
149
+ .option('--json', 'Output raw JSON')
150
+ .action(async (name, options) => {
151
+ try {
152
+ await inspectCommand(name, options);
153
+ }
154
+ catch (err) {
155
+ handleError(err);
156
+ }
157
+ });
158
+ // ─── demon providers ──────────────────────────────────────────
159
+ const providers = program
160
+ .command('providers')
161
+ .description('Manage action provider credentials (GitHub, Slack, etc.)');
162
+ providers
163
+ .command('add [name]')
164
+ .description('Add or update credentials for a provider')
165
+ .action(async (name) => {
166
+ try {
167
+ await providersAddCommand(name);
168
+ }
169
+ catch (err) {
170
+ handleError(err);
171
+ }
172
+ });
173
+ providers
174
+ .command('list')
175
+ .description('List configured providers')
176
+ .action(async () => {
177
+ try {
178
+ await providersListCommand();
179
+ }
180
+ catch (err) {
181
+ handleError(err);
182
+ }
183
+ });
184
+ providers
185
+ .command('remove <name>')
186
+ .description('Remove a provider and its credentials')
187
+ .action(async (name) => {
188
+ try {
189
+ await providersRemoveCommand(name);
190
+ }
191
+ catch (err) {
192
+ handleError(err);
193
+ }
194
+ });
195
+ // ─── demon secrets ────────────────────────────────────────────
196
+ const secrets = program
197
+ .command('secrets')
198
+ .description('Manage secrets used by demons (API keys, tokens)');
199
+ secrets
200
+ .command('set <key> [value]')
201
+ .description('Set a secret (prompts for value if not provided)')
202
+ .action(async (key, value) => {
203
+ try {
204
+ await secretsSetCommand(key, value);
205
+ }
206
+ catch (err) {
207
+ handleError(err);
208
+ }
209
+ });
210
+ secrets
211
+ .command('get <key>')
212
+ .description('Print a secret value to stdout')
213
+ .action(async (key) => {
214
+ try {
215
+ await secretsGetCommand(key);
216
+ }
217
+ catch (err) {
218
+ handleError(err);
219
+ }
220
+ });
221
+ secrets
222
+ .command('list')
223
+ .description('List stored secret keys (values are never shown)')
224
+ .action(async () => {
225
+ try {
226
+ await secretsListCommand();
227
+ }
228
+ catch (err) {
229
+ handleError(err);
230
+ }
231
+ });
232
+ // ─── Global error handling ────────────────────────────────────
233
+ process.on('uncaughtException', (err) => {
234
+ console.error('\n Uncaught exception:', err.message);
235
+ if (process.env.DEMON_LOG_LEVEL === 'debug') {
236
+ console.error(err.stack);
237
+ }
238
+ process.exit(1);
239
+ });
240
+ process.on('unhandledRejection', (reason) => {
241
+ console.error('\n Unhandled rejection:', reason);
242
+ process.exit(1);
243
+ });
244
+ function handleError(err) {
245
+ const message = err instanceof Error ? err.message : String(err);
246
+ console.error(`\n Error: ${message}\n`);
247
+ if (process.env.DEMON_LOG_LEVEL === 'debug' && err instanceof Error) {
248
+ console.error(err.stack);
249
+ }
250
+ process.exit(1);
251
+ }
252
+ program.parse(process.argv);
253
+ //# sourceMappingURL=index.js.map