@phnx-labs/agents-cli 1.20.63 → 1.20.65

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 (197) hide show
  1. package/CHANGELOG.md +56 -3
  2. package/README.md +46 -2
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/apply.d.ts +12 -0
  5. package/dist/commands/apply.js +274 -0
  6. package/dist/commands/browser.js +2 -2
  7. package/dist/commands/cloud.js +32 -2
  8. package/dist/commands/doctor.js +4 -1
  9. package/dist/commands/exec.js +149 -77
  10. package/dist/commands/feed.d.ts +4 -0
  11. package/dist/commands/feed.js +52 -19
  12. package/dist/commands/hosts.js +44 -6
  13. package/dist/commands/lease.d.ts +23 -0
  14. package/dist/commands/lease.js +201 -0
  15. package/dist/commands/mailboxes.d.ts +20 -0
  16. package/dist/commands/mailboxes.js +390 -0
  17. package/dist/commands/mcp.js +55 -5
  18. package/dist/commands/monitors.d.ts +12 -0
  19. package/dist/commands/monitors.js +740 -0
  20. package/dist/commands/output.js +2 -2
  21. package/dist/commands/routines.js +43 -16
  22. package/dist/commands/secrets.d.ts +16 -0
  23. package/dist/commands/secrets.js +215 -64
  24. package/dist/commands/serve.js +31 -0
  25. package/dist/commands/sessions-export.d.ts +2 -0
  26. package/dist/commands/sessions-export.js +284 -0
  27. package/dist/commands/sessions-import.d.ts +2 -0
  28. package/dist/commands/sessions-import.js +230 -0
  29. package/dist/commands/sessions.d.ts +16 -0
  30. package/dist/commands/sessions.js +40 -6
  31. package/dist/commands/ssh.js +143 -5
  32. package/dist/commands/usage.d.ts +2 -0
  33. package/dist/commands/usage.js +7 -2
  34. package/dist/commands/versions.js +7 -3
  35. package/dist/commands/view.d.ts +27 -1
  36. package/dist/commands/view.js +32 -9
  37. package/dist/commands/webhook.js +10 -2
  38. package/dist/index.js +35 -14
  39. package/dist/lib/agents.d.ts +36 -0
  40. package/dist/lib/agents.js +80 -20
  41. package/dist/lib/auto-dispatch-provider.js +7 -2
  42. package/dist/lib/auto-dispatch.d.ts +3 -0
  43. package/dist/lib/auto-dispatch.js +3 -0
  44. package/dist/lib/browser/chrome.js +2 -2
  45. package/dist/lib/browser/drivers/ssh.js +19 -2
  46. package/dist/lib/cloud/antigravity.js +2 -2
  47. package/dist/lib/cloud/host.d.ts +59 -0
  48. package/dist/lib/cloud/host.js +224 -0
  49. package/dist/lib/cloud/registry.js +4 -0
  50. package/dist/lib/cloud/types.d.ts +6 -4
  51. package/dist/lib/comms-render.d.ts +37 -0
  52. package/dist/lib/comms-render.js +89 -0
  53. package/dist/lib/computer-rpc.js +3 -1
  54. package/dist/lib/crabbox/cli.d.ts +72 -0
  55. package/dist/lib/crabbox/cli.js +162 -9
  56. package/dist/lib/crabbox/runtimes.d.ts +13 -0
  57. package/dist/lib/crabbox/runtimes.js +35 -2
  58. package/dist/lib/daemon.d.ts +20 -4
  59. package/dist/lib/daemon.js +68 -20
  60. package/dist/lib/devices/fleet.d.ts +3 -2
  61. package/dist/lib/devices/fleet.js +9 -0
  62. package/dist/lib/devices/health.d.ts +77 -0
  63. package/dist/lib/devices/health.js +186 -0
  64. package/dist/lib/devices/registry.d.ts +15 -0
  65. package/dist/lib/devices/registry.js +9 -0
  66. package/dist/lib/exec.d.ts +19 -2
  67. package/dist/lib/exec.js +41 -13
  68. package/dist/lib/fleet/apply.d.ts +63 -0
  69. package/dist/lib/fleet/apply.js +214 -0
  70. package/dist/lib/fleet/auth-sync.d.ts +67 -0
  71. package/dist/lib/fleet/auth-sync.js +142 -0
  72. package/dist/lib/fleet/manifest.d.ts +29 -0
  73. package/dist/lib/fleet/manifest.js +127 -0
  74. package/dist/lib/fleet/types.d.ts +129 -0
  75. package/dist/lib/fleet/types.js +13 -0
  76. package/dist/lib/git.d.ts +27 -0
  77. package/dist/lib/git.js +34 -2
  78. package/dist/lib/hosts/dispatch.d.ts +29 -8
  79. package/dist/lib/hosts/dispatch.js +46 -18
  80. package/dist/lib/hosts/passthrough.js +2 -0
  81. package/dist/lib/hosts/providers/devices.d.ts +27 -0
  82. package/dist/lib/hosts/providers/devices.js +98 -0
  83. package/dist/lib/hosts/registry.d.ts +10 -16
  84. package/dist/lib/hosts/registry.js +17 -50
  85. package/dist/lib/hosts/remote-cmd.d.ts +23 -0
  86. package/dist/lib/hosts/remote-cmd.js +71 -0
  87. package/dist/lib/hosts/run-target.d.ts +84 -0
  88. package/dist/lib/hosts/run-target.js +99 -0
  89. package/dist/lib/hosts/types.d.ts +23 -5
  90. package/dist/lib/hosts/types.js +22 -4
  91. package/dist/lib/linear-autoclose.d.ts +30 -0
  92. package/dist/lib/linear-autoclose.js +22 -0
  93. package/dist/lib/mailbox.d.ts +39 -0
  94. package/dist/lib/mailbox.js +112 -0
  95. package/dist/lib/mcp.d.ts +27 -1
  96. package/dist/lib/mcp.js +126 -12
  97. package/dist/lib/monitors/config.d.ts +161 -0
  98. package/dist/lib/monitors/config.js +372 -0
  99. package/dist/lib/monitors/dispatch.d.ts +28 -0
  100. package/dist/lib/monitors/dispatch.js +91 -0
  101. package/dist/lib/monitors/engine.d.ts +61 -0
  102. package/dist/lib/monitors/engine.js +201 -0
  103. package/dist/lib/monitors/sources/command.d.ts +11 -0
  104. package/dist/lib/monitors/sources/command.js +31 -0
  105. package/dist/lib/monitors/sources/device.d.ts +13 -0
  106. package/dist/lib/monitors/sources/device.js +35 -0
  107. package/dist/lib/monitors/sources/file.d.ts +14 -0
  108. package/dist/lib/monitors/sources/file.js +57 -0
  109. package/dist/lib/monitors/sources/http.d.ts +10 -0
  110. package/dist/lib/monitors/sources/http.js +34 -0
  111. package/dist/lib/monitors/sources/index.d.ts +14 -0
  112. package/dist/lib/monitors/sources/index.js +31 -0
  113. package/dist/lib/monitors/sources/poll.d.ts +9 -0
  114. package/dist/lib/monitors/sources/poll.js +9 -0
  115. package/dist/lib/monitors/sources/types.d.ts +18 -0
  116. package/dist/lib/monitors/sources/types.js +9 -0
  117. package/dist/lib/monitors/sources/webhook.d.ts +23 -0
  118. package/dist/lib/monitors/sources/webhook.js +47 -0
  119. package/dist/lib/monitors/sources/ws.d.ts +14 -0
  120. package/dist/lib/monitors/sources/ws.js +45 -0
  121. package/dist/lib/monitors/state.d.ts +69 -0
  122. package/dist/lib/monitors/state.js +144 -0
  123. package/dist/lib/paths.d.ts +13 -0
  124. package/dist/lib/paths.js +26 -4
  125. package/dist/lib/platform/exec.d.ts +16 -0
  126. package/dist/lib/platform/exec.js +17 -0
  127. package/dist/lib/plugins.js +101 -2
  128. package/dist/lib/redact.d.ts +14 -1
  129. package/dist/lib/redact.js +47 -1
  130. package/dist/lib/remote-agents-json.js +7 -1
  131. package/dist/lib/rotate.d.ts +6 -3
  132. package/dist/lib/rotate.js +0 -1
  133. package/dist/lib/routines.d.ts +37 -2
  134. package/dist/lib/routines.js +54 -12
  135. package/dist/lib/runner.d.ts +1 -0
  136. package/dist/lib/runner.js +348 -13
  137. package/dist/lib/sandbox.d.ts +9 -1
  138. package/dist/lib/sandbox.js +11 -2
  139. package/dist/lib/secrets/agent.d.ts +48 -10
  140. package/dist/lib/secrets/agent.js +123 -15
  141. package/dist/lib/secrets/bundles.d.ts +26 -0
  142. package/dist/lib/secrets/bundles.js +59 -8
  143. package/dist/lib/secrets/mcp.js +4 -2
  144. package/dist/lib/secrets/remote.d.ts +17 -0
  145. package/dist/lib/secrets/remote.js +40 -0
  146. package/dist/lib/self-update.d.ts +20 -0
  147. package/dist/lib/self-update.js +54 -1
  148. package/dist/lib/serve/control.d.ts +95 -0
  149. package/dist/lib/serve/control.js +260 -0
  150. package/dist/lib/serve/server.d.ts +35 -1
  151. package/dist/lib/serve/server.js +106 -76
  152. package/dist/lib/serve/stream.d.ts +43 -0
  153. package/dist/lib/serve/stream.js +116 -0
  154. package/dist/lib/serve/token.d.ts +35 -0
  155. package/dist/lib/serve/token.js +85 -0
  156. package/dist/lib/session/bundle.d.ts +164 -0
  157. package/dist/lib/session/bundle.js +200 -0
  158. package/dist/lib/session/remote-bundle.d.ts +12 -0
  159. package/dist/lib/session/remote-bundle.js +61 -0
  160. package/dist/lib/session/remote-list.js +5 -1
  161. package/dist/lib/session/state.d.ts +7 -25
  162. package/dist/lib/session/state.js +16 -6
  163. package/dist/lib/session/sync/agents.d.ts +54 -6
  164. package/dist/lib/session/sync/agents.js +0 -0
  165. package/dist/lib/session/sync/config.js +8 -2
  166. package/dist/lib/session/sync/manifest.d.ts +14 -3
  167. package/dist/lib/session/sync/manifest.js +4 -0
  168. package/dist/lib/session/sync/sync.d.ts +23 -2
  169. package/dist/lib/session/sync/sync.js +177 -74
  170. package/dist/lib/session/types.d.ts +30 -0
  171. package/dist/lib/ssh-tunnel.d.ts +19 -1
  172. package/dist/lib/ssh-tunnel.js +99 -8
  173. package/dist/lib/staleness/detectors/subagents.d.ts +5 -0
  174. package/dist/lib/staleness/detectors/subagents.js +5 -192
  175. package/dist/lib/staleness/writers/subagents.d.ts +10 -0
  176. package/dist/lib/staleness/writers/subagents.js +11 -102
  177. package/dist/lib/startup/command-registry.d.ts +4 -0
  178. package/dist/lib/startup/command-registry.js +9 -0
  179. package/dist/lib/state.d.ts +5 -0
  180. package/dist/lib/state.js +12 -0
  181. package/dist/lib/subagents-registry.d.ts +85 -0
  182. package/dist/lib/subagents-registry.js +393 -0
  183. package/dist/lib/subagents.d.ts +8 -8
  184. package/dist/lib/subagents.js +32 -663
  185. package/dist/lib/sync-umbrella.d.ts +1 -0
  186. package/dist/lib/sync-umbrella.js +14 -3
  187. package/dist/lib/tmux/session.d.ts +7 -0
  188. package/dist/lib/tmux/session.js +3 -1
  189. package/dist/lib/triggers/webhook.d.ts +18 -0
  190. package/dist/lib/triggers/webhook.js +105 -0
  191. package/dist/lib/types.d.ts +35 -1
  192. package/dist/lib/usage.d.ts +42 -3
  193. package/dist/lib/usage.js +163 -21
  194. package/dist/lib/versions.js +14 -11
  195. package/dist/lib/workflows.d.ts +20 -0
  196. package/dist/lib/workflows.js +24 -0
  197. package/package.json +2 -1
@@ -66,8 +66,16 @@ export interface JobConfig {
66
66
  schedule?: string;
67
67
  /** Event/webhook fire condition. Optional when `schedule` is set. */
68
68
  trigger?: JobTrigger;
69
- agent: AgentId;
69
+ /** Which agent runs the routine. Optional — omitted for `workflow`/`command` routines. Exactly one of agent/workflow/command must be set. */
70
+ agent?: AgentId;
70
71
  workflow?: string;
72
+ /**
73
+ * A plain shell command run directly instead of an agent/workflow — no LLM,
74
+ * no auth, no rotation, no tokens, no sandbox overlay. For deterministic
75
+ * housekeeping routines (version-check, `npm i -g`, `git pull`, notify).
76
+ * Mutually exclusive with `agent` and `workflow`.
77
+ */
78
+ command?: string;
71
79
  mode: 'plan' | 'edit' | 'auto' | 'skip' | 'full';
72
80
  effort: 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto';
73
81
  timeout: string;
@@ -83,6 +91,17 @@ export interface JobConfig {
83
91
  * overdue; everywhere else it is inert and `run` refuses with a pointer.
84
92
  */
85
93
  devices?: string[];
94
+ /**
95
+ * Execution placement — run the job body on this machine over SSH (a
96
+ * registered host, device, capability tag, or user@host) instead of locally.
97
+ * Distinct from `devices`: `devices` says which daemon may FIRE the job,
98
+ * `host` says where the dispatched run EXECUTES. CLI flag: `--run-on`
99
+ * (`--host` on routines commands already means "manage routines on that
100
+ * machine" via the remote passthrough).
101
+ */
102
+ host?: string;
103
+ /** Working directory on the host for `host:`-placed runs. */
104
+ remoteCwd?: string;
86
105
  variables?: Record<string, string>;
87
106
  sandbox?: boolean;
88
107
  allow?: JobAllowConfig;
@@ -104,8 +123,10 @@ export interface JobConfig {
104
123
  export interface RunMeta {
105
124
  jobName: string;
106
125
  runId: string;
107
- agent: AgentId;
126
+ agent?: AgentId;
108
127
  workflow?: string;
128
+ /** The shell command that ran, for command-mode routines (no agent). */
129
+ command?: string;
109
130
  pid: number | null;
110
131
  /** Process birth time (epoch ms) recorded at spawn for pid-reuse detection. */
111
132
  spawnedAt?: number;
@@ -113,6 +134,11 @@ export interface RunMeta {
113
134
  startedAt: string;
114
135
  completedAt: string | null;
115
136
  exitCode: number | null;
137
+ /** Set for `host:`-placed runs — where the job body executes (no local pid). */
138
+ host?: string;
139
+ /** The host-task sidecar id backing a `host:` run; the daemon monitor
140
+ * finalizes the run by reconciling it against the remote `.exit`. */
141
+ hostTaskId?: string;
116
142
  }
117
143
  /**
118
144
  * True when the job may execute on this machine: no `devices` allowlist (or
@@ -205,6 +231,15 @@ export declare function getLatestRun(jobName: string): RunMeta | null;
205
231
  export declare function writeRunMeta(meta: RunMeta): void;
206
232
  /** Read run metadata from disk. Returns null if missing or corrupt. */
207
233
  export declare function readRunMeta(jobName: string, runId: string): RunMeta | null;
234
+ /**
235
+ * Runs directory for a single job, with the (untrusted) job name contained to a
236
+ * single segment beneath the runs dir — same guard as `getJobHomePath`. The name
237
+ * comes from routine YAML and can arrive via a synced config repo; every runs-dir
238
+ * sink (run dir, meta read/write, last-report read) routes through here so a
239
+ * crafted `name` like `../../../../tmp/x` can't `mkdirSync`/write `stdout.log`,
240
+ * `meta.json`, or `report.md` outside `~/.agents/.history/runs`.
241
+ */
242
+ export declare function getJobRunsDir(jobName: string): string;
208
243
  /** Get the filesystem path for a specific run's directory. */
209
244
  export declare function getRunDir(jobName: string, runId: string): string;
210
245
  /** Discover routine YAML files in a repository's routines/ directory. */
@@ -11,7 +11,7 @@ import * as path from 'path';
11
11
  import * as yaml from 'yaml';
12
12
  import { Cron } from 'croner';
13
13
  import { getRoutinesDir, getSystemRoutinesDir, getRunsDir, ensureAgentsDir, getProjectRoutinesDir } from './state.js';
14
- import { safeJoin } from './paths.js';
14
+ import { safeJoin, isSafeSegmentName } from './paths.js';
15
15
  import { atomicWriteFileSync } from './fs-atomic.js';
16
16
  import { ALL_AGENT_IDS } from './agents.js';
17
17
  import { machineId, normalizeHost } from './machine-id.js';
@@ -274,6 +274,13 @@ export function validateJob(config) {
274
274
  if (!config.name || typeof config.name !== 'string') {
275
275
  errors.push('name is required');
276
276
  }
277
+ else if (!isSafeSegmentName(config.name)) {
278
+ // The name becomes a filesystem path segment (overlay HOME under the
279
+ // routines dir). Reject separators, '.'/'..', and null bytes so a synced
280
+ // config can't traverse out of ~/.agents/routines.
281
+ errors.push(`invalid name ${JSON.stringify(config.name)}: must be a single path segment ` +
282
+ `(no '/', '\\\\', or null bytes, and not '.' or '..')`);
283
+ }
277
284
  const hasSchedule = Boolean(config.schedule && typeof config.schedule === 'string');
278
285
  const hasTrigger = config.trigger !== undefined;
279
286
  if (!hasSchedule && !hasTrigger) {
@@ -298,11 +305,16 @@ export function validateJob(config) {
298
305
  }
299
306
  const hasAgent = Boolean(config.agent && typeof config.agent === 'string');
300
307
  const hasWorkflow = Boolean(config.workflow && typeof config.workflow === 'string');
301
- if (!hasAgent && !hasWorkflow) {
302
- errors.push('exactly one of agent or workflow is required');
308
+ const hasCommand = Boolean(config.command && typeof config.command === 'string');
309
+ const set = [hasAgent, hasWorkflow, hasCommand].filter(Boolean).length;
310
+ if (set === 0) {
311
+ errors.push('exactly one of agent, workflow, or command is required');
312
+ }
313
+ else if (set > 1) {
314
+ errors.push('exactly one of agent, workflow, or command may be set (not more)');
303
315
  }
304
- else if (hasAgent && hasWorkflow) {
305
- errors.push('exactly one of agent or workflow must be set (not both)');
316
+ if (config.command !== undefined && (typeof config.command !== 'string' || config.command.trim() === '')) {
317
+ errors.push('command must be a non-empty shell command string');
306
318
  }
307
319
  if (hasAgent && config.agent && !ALL_AGENT_IDS.includes(config.agent)) {
308
320
  errors.push(`agent must be one of: ${ALL_AGENT_IDS.join(', ')}`);
@@ -336,7 +348,8 @@ export function validateJob(config) {
336
348
  if (config.effort && !['low', 'medium', 'high', 'xhigh', 'max', 'auto'].includes(config.effort)) {
337
349
  errors.push('effort must be low, medium, high, xhigh, max, or auto');
338
350
  }
339
- if (!config.prompt || typeof config.prompt !== 'string') {
351
+ // command routines run a plain shell and never build a prompt; agent/workflow routines require one.
352
+ if (!hasCommand && (!config.prompt || typeof config.prompt !== 'string')) {
340
353
  errors.push('prompt is required');
341
354
  }
342
355
  if (config.timeout && !parseTimeout(config.timeout)) {
@@ -350,6 +363,25 @@ export function validateJob(config) {
350
363
  if (config.device !== undefined) {
351
364
  errors.push('singular "device" key is no longer supported — replace with devices: [<name>] (an array)');
352
365
  }
366
+ if (config.host !== undefined) {
367
+ if (typeof config.host !== 'string' || config.host.trim() === '') {
368
+ errors.push('host must be a non-empty machine name (a registered host, device, capability tag, or user@host)');
369
+ }
370
+ // v1: the workflow bundle and the loop driver (with its signal files) live
371
+ // on the firing machine — neither can cross SSH to the target yet.
372
+ if (config.workflow) {
373
+ errors.push("host: can't be combined with workflow: yet (the bundle lives on the firing machine) — run the workflow locally or convert it to a plain prompt");
374
+ }
375
+ if (config.loop) {
376
+ errors.push("host: can't be combined with loop: yet (the loop driver and its signal files live on the firing machine)");
377
+ }
378
+ if (config.command) {
379
+ errors.push("host: can't be combined with command: yet (a plain shell command has no agent to place remotely) — run it locally, or convert it to a prompt");
380
+ }
381
+ }
382
+ if (config.remoteCwd !== undefined && config.host === undefined) {
383
+ errors.push('remoteCwd only applies to host:-placed routines — set host: too, or drop it');
384
+ }
353
385
  if (config.devices !== undefined) {
354
386
  if (!Array.isArray(config.devices)) {
355
387
  errors.push('devices must be an array of device names (as shown by `agents devices`)');
@@ -445,7 +477,7 @@ export function resolveJobPrompt(config) {
445
477
  // Last report (special handling)
446
478
  const latestRun = getLatestRun(config.name);
447
479
  if (latestRun) {
448
- const reportPath = path.join(getRunsDir(), config.name, latestRun.runId, 'report.md');
480
+ const reportPath = path.join(getJobRunsDir(config.name), latestRun.runId, 'report.md');
449
481
  if (fs.existsSync(reportPath)) {
450
482
  const report = fs.readFileSync(reportPath, 'utf-8');
451
483
  prompt = prompt.replace(/\{last_report\}/g, report);
@@ -481,8 +513,7 @@ export function parseTimeout(timeout) {
481
513
  }
482
514
  /** List all run metadata entries for a job, sorted chronologically. */
483
515
  export function listRuns(jobName) {
484
- const runsDir = getRunsDir();
485
- const jobRunsDir = path.join(runsDir, jobName);
516
+ const jobRunsDir = getJobRunsDir(jobName);
486
517
  if (!fs.existsSync(jobRunsDir))
487
518
  return [];
488
519
  const entries = fs.readdirSync(jobRunsDir, { withFileTypes: true })
@@ -505,13 +536,13 @@ export function getLatestRun(jobName) {
505
536
  /** Persist run metadata to its run directory as meta.json. */
506
537
  export function writeRunMeta(meta) {
507
538
  ensureAgentsDir();
508
- const runDir = path.join(getRunsDir(), meta.jobName, meta.runId);
539
+ const runDir = path.join(getJobRunsDir(meta.jobName), meta.runId);
509
540
  fs.mkdirSync(runDir, { recursive: true });
510
541
  fs.writeFileSync(path.join(runDir, 'meta.json'), JSON.stringify(meta, null, 2), 'utf-8');
511
542
  }
512
543
  /** Read run metadata from disk. Returns null if missing or corrupt. */
513
544
  export function readRunMeta(jobName, runId) {
514
- const metaPath = path.join(getRunsDir(), jobName, runId, 'meta.json');
545
+ const metaPath = path.join(getJobRunsDir(jobName), runId, 'meta.json');
515
546
  if (!fs.existsSync(metaPath))
516
547
  return null;
517
548
  try {
@@ -521,9 +552,20 @@ export function readRunMeta(jobName, runId) {
521
552
  return null;
522
553
  }
523
554
  }
555
+ /**
556
+ * Runs directory for a single job, with the (untrusted) job name contained to a
557
+ * single segment beneath the runs dir — same guard as `getJobHomePath`. The name
558
+ * comes from routine YAML and can arrive via a synced config repo; every runs-dir
559
+ * sink (run dir, meta read/write, last-report read) routes through here so a
560
+ * crafted `name` like `../../../../tmp/x` can't `mkdirSync`/write `stdout.log`,
561
+ * `meta.json`, or `report.md` outside `~/.agents/.history/runs`.
562
+ */
563
+ export function getJobRunsDir(jobName) {
564
+ return safeJoin(getRunsDir(), jobName);
565
+ }
524
566
  /** Get the filesystem path for a specific run's directory. */
525
567
  export function getRunDir(jobName, runId) {
526
- return path.join(getRunsDir(), jobName, runId);
568
+ return path.join(getJobRunsDir(jobName), runId);
527
569
  }
528
570
  /** Discover routine YAML files in a repository's routines/ directory. */
529
571
  export function discoverJobsFromRepo(repoPath) {
@@ -77,6 +77,7 @@ export declare function buildRoutineSpawnEnv(baseEnv: Record<string, string>, ag
77
77
  */
78
78
  export declare function executeJob(config: JobConfig, deps?: LoopDeps): Promise<RunResult>;
79
79
  /** Spawn a job as a detached process and return immediately with run metadata. */
80
+ /** Spawn a job as a detached process and return immediately with run metadata. */
80
81
  export declare function executeJobDetached(config: JobConfig): Promise<RunMeta>;
81
82
  /** Extract the final assistant message from a stream-JSON log file as a markdown report. */
82
83
  export declare function extractReport(stdoutPath: string, agentType: AgentId): string | null;