@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.
- package/CHANGELOG.md +56 -3
- package/README.md +46 -2
- package/dist/bin/agents +0 -0
- package/dist/commands/apply.d.ts +12 -0
- package/dist/commands/apply.js +274 -0
- package/dist/commands/browser.js +2 -2
- package/dist/commands/cloud.js +32 -2
- package/dist/commands/doctor.js +4 -1
- package/dist/commands/exec.js +149 -77
- package/dist/commands/feed.d.ts +4 -0
- package/dist/commands/feed.js +52 -19
- package/dist/commands/hosts.js +44 -6
- package/dist/commands/lease.d.ts +23 -0
- package/dist/commands/lease.js +201 -0
- package/dist/commands/mailboxes.d.ts +20 -0
- package/dist/commands/mailboxes.js +390 -0
- package/dist/commands/mcp.js +55 -5
- package/dist/commands/monitors.d.ts +12 -0
- package/dist/commands/monitors.js +740 -0
- package/dist/commands/output.js +2 -2
- package/dist/commands/routines.js +43 -16
- package/dist/commands/secrets.d.ts +16 -0
- package/dist/commands/secrets.js +215 -64
- package/dist/commands/serve.js +31 -0
- package/dist/commands/sessions-export.d.ts +2 -0
- package/dist/commands/sessions-export.js +284 -0
- package/dist/commands/sessions-import.d.ts +2 -0
- package/dist/commands/sessions-import.js +230 -0
- package/dist/commands/sessions.d.ts +16 -0
- package/dist/commands/sessions.js +40 -6
- package/dist/commands/ssh.js +143 -5
- package/dist/commands/usage.d.ts +2 -0
- package/dist/commands/usage.js +7 -2
- package/dist/commands/versions.js +7 -3
- package/dist/commands/view.d.ts +27 -1
- package/dist/commands/view.js +32 -9
- package/dist/commands/webhook.js +10 -2
- package/dist/index.js +35 -14
- package/dist/lib/agents.d.ts +36 -0
- package/dist/lib/agents.js +80 -20
- package/dist/lib/auto-dispatch-provider.js +7 -2
- package/dist/lib/auto-dispatch.d.ts +3 -0
- package/dist/lib/auto-dispatch.js +3 -0
- package/dist/lib/browser/chrome.js +2 -2
- package/dist/lib/browser/drivers/ssh.js +19 -2
- package/dist/lib/cloud/antigravity.js +2 -2
- package/dist/lib/cloud/host.d.ts +59 -0
- package/dist/lib/cloud/host.js +224 -0
- package/dist/lib/cloud/registry.js +4 -0
- package/dist/lib/cloud/types.d.ts +6 -4
- package/dist/lib/comms-render.d.ts +37 -0
- package/dist/lib/comms-render.js +89 -0
- package/dist/lib/computer-rpc.js +3 -1
- package/dist/lib/crabbox/cli.d.ts +72 -0
- package/dist/lib/crabbox/cli.js +162 -9
- package/dist/lib/crabbox/runtimes.d.ts +13 -0
- package/dist/lib/crabbox/runtimes.js +35 -2
- package/dist/lib/daemon.d.ts +20 -4
- package/dist/lib/daemon.js +68 -20
- package/dist/lib/devices/fleet.d.ts +3 -2
- package/dist/lib/devices/fleet.js +9 -0
- package/dist/lib/devices/health.d.ts +77 -0
- package/dist/lib/devices/health.js +186 -0
- package/dist/lib/devices/registry.d.ts +15 -0
- package/dist/lib/devices/registry.js +9 -0
- package/dist/lib/exec.d.ts +19 -2
- package/dist/lib/exec.js +41 -13
- package/dist/lib/fleet/apply.d.ts +63 -0
- package/dist/lib/fleet/apply.js +214 -0
- package/dist/lib/fleet/auth-sync.d.ts +67 -0
- package/dist/lib/fleet/auth-sync.js +142 -0
- package/dist/lib/fleet/manifest.d.ts +29 -0
- package/dist/lib/fleet/manifest.js +127 -0
- package/dist/lib/fleet/types.d.ts +129 -0
- package/dist/lib/fleet/types.js +13 -0
- package/dist/lib/git.d.ts +27 -0
- package/dist/lib/git.js +34 -2
- package/dist/lib/hosts/dispatch.d.ts +29 -8
- package/dist/lib/hosts/dispatch.js +46 -18
- package/dist/lib/hosts/passthrough.js +2 -0
- package/dist/lib/hosts/providers/devices.d.ts +27 -0
- package/dist/lib/hosts/providers/devices.js +98 -0
- package/dist/lib/hosts/registry.d.ts +10 -16
- package/dist/lib/hosts/registry.js +17 -50
- package/dist/lib/hosts/remote-cmd.d.ts +23 -0
- package/dist/lib/hosts/remote-cmd.js +71 -0
- package/dist/lib/hosts/run-target.d.ts +84 -0
- package/dist/lib/hosts/run-target.js +99 -0
- package/dist/lib/hosts/types.d.ts +23 -5
- package/dist/lib/hosts/types.js +22 -4
- package/dist/lib/linear-autoclose.d.ts +30 -0
- package/dist/lib/linear-autoclose.js +22 -0
- package/dist/lib/mailbox.d.ts +39 -0
- package/dist/lib/mailbox.js +112 -0
- package/dist/lib/mcp.d.ts +27 -1
- package/dist/lib/mcp.js +126 -12
- package/dist/lib/monitors/config.d.ts +161 -0
- package/dist/lib/monitors/config.js +372 -0
- package/dist/lib/monitors/dispatch.d.ts +28 -0
- package/dist/lib/monitors/dispatch.js +91 -0
- package/dist/lib/monitors/engine.d.ts +61 -0
- package/dist/lib/monitors/engine.js +201 -0
- package/dist/lib/monitors/sources/command.d.ts +11 -0
- package/dist/lib/monitors/sources/command.js +31 -0
- package/dist/lib/monitors/sources/device.d.ts +13 -0
- package/dist/lib/monitors/sources/device.js +35 -0
- package/dist/lib/monitors/sources/file.d.ts +14 -0
- package/dist/lib/monitors/sources/file.js +57 -0
- package/dist/lib/monitors/sources/http.d.ts +10 -0
- package/dist/lib/monitors/sources/http.js +34 -0
- package/dist/lib/monitors/sources/index.d.ts +14 -0
- package/dist/lib/monitors/sources/index.js +31 -0
- package/dist/lib/monitors/sources/poll.d.ts +9 -0
- package/dist/lib/monitors/sources/poll.js +9 -0
- package/dist/lib/monitors/sources/types.d.ts +18 -0
- package/dist/lib/monitors/sources/types.js +9 -0
- package/dist/lib/monitors/sources/webhook.d.ts +23 -0
- package/dist/lib/monitors/sources/webhook.js +47 -0
- package/dist/lib/monitors/sources/ws.d.ts +14 -0
- package/dist/lib/monitors/sources/ws.js +45 -0
- package/dist/lib/monitors/state.d.ts +69 -0
- package/dist/lib/monitors/state.js +144 -0
- package/dist/lib/paths.d.ts +13 -0
- package/dist/lib/paths.js +26 -4
- package/dist/lib/platform/exec.d.ts +16 -0
- package/dist/lib/platform/exec.js +17 -0
- package/dist/lib/plugins.js +101 -2
- package/dist/lib/redact.d.ts +14 -1
- package/dist/lib/redact.js +47 -1
- package/dist/lib/remote-agents-json.js +7 -1
- package/dist/lib/rotate.d.ts +6 -3
- package/dist/lib/rotate.js +0 -1
- package/dist/lib/routines.d.ts +37 -2
- package/dist/lib/routines.js +54 -12
- package/dist/lib/runner.d.ts +1 -0
- package/dist/lib/runner.js +348 -13
- package/dist/lib/sandbox.d.ts +9 -1
- package/dist/lib/sandbox.js +11 -2
- package/dist/lib/secrets/agent.d.ts +48 -10
- package/dist/lib/secrets/agent.js +123 -15
- package/dist/lib/secrets/bundles.d.ts +26 -0
- package/dist/lib/secrets/bundles.js +59 -8
- package/dist/lib/secrets/mcp.js +4 -2
- package/dist/lib/secrets/remote.d.ts +17 -0
- package/dist/lib/secrets/remote.js +40 -0
- package/dist/lib/self-update.d.ts +20 -0
- package/dist/lib/self-update.js +54 -1
- package/dist/lib/serve/control.d.ts +95 -0
- package/dist/lib/serve/control.js +260 -0
- package/dist/lib/serve/server.d.ts +35 -1
- package/dist/lib/serve/server.js +106 -76
- package/dist/lib/serve/stream.d.ts +43 -0
- package/dist/lib/serve/stream.js +116 -0
- package/dist/lib/serve/token.d.ts +35 -0
- package/dist/lib/serve/token.js +85 -0
- package/dist/lib/session/bundle.d.ts +164 -0
- package/dist/lib/session/bundle.js +200 -0
- package/dist/lib/session/remote-bundle.d.ts +12 -0
- package/dist/lib/session/remote-bundle.js +61 -0
- package/dist/lib/session/remote-list.js +5 -1
- package/dist/lib/session/state.d.ts +7 -25
- package/dist/lib/session/state.js +16 -6
- package/dist/lib/session/sync/agents.d.ts +54 -6
- package/dist/lib/session/sync/agents.js +0 -0
- package/dist/lib/session/sync/config.js +8 -2
- package/dist/lib/session/sync/manifest.d.ts +14 -3
- package/dist/lib/session/sync/manifest.js +4 -0
- package/dist/lib/session/sync/sync.d.ts +23 -2
- package/dist/lib/session/sync/sync.js +177 -74
- package/dist/lib/session/types.d.ts +30 -0
- package/dist/lib/ssh-tunnel.d.ts +19 -1
- package/dist/lib/ssh-tunnel.js +99 -8
- package/dist/lib/staleness/detectors/subagents.d.ts +5 -0
- package/dist/lib/staleness/detectors/subagents.js +5 -192
- package/dist/lib/staleness/writers/subagents.d.ts +10 -0
- package/dist/lib/staleness/writers/subagents.js +11 -102
- package/dist/lib/startup/command-registry.d.ts +4 -0
- package/dist/lib/startup/command-registry.js +9 -0
- package/dist/lib/state.d.ts +5 -0
- package/dist/lib/state.js +12 -0
- package/dist/lib/subagents-registry.d.ts +85 -0
- package/dist/lib/subagents-registry.js +393 -0
- package/dist/lib/subagents.d.ts +8 -8
- package/dist/lib/subagents.js +32 -663
- package/dist/lib/sync-umbrella.d.ts +1 -0
- package/dist/lib/sync-umbrella.js +14 -3
- package/dist/lib/tmux/session.d.ts +7 -0
- package/dist/lib/tmux/session.js +3 -1
- package/dist/lib/triggers/webhook.d.ts +18 -0
- package/dist/lib/triggers/webhook.js +105 -0
- package/dist/lib/types.d.ts +35 -1
- package/dist/lib/usage.d.ts +42 -3
- package/dist/lib/usage.js +163 -21
- package/dist/lib/versions.js +14 -11
- package/dist/lib/workflows.d.ts +20 -0
- package/dist/lib/workflows.js +24 -0
- package/package.json +2 -1
package/dist/lib/routines.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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. */
|
package/dist/lib/routines.js
CHANGED
|
@@ -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
|
-
|
|
302
|
-
|
|
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
|
-
|
|
305
|
-
errors.push('
|
|
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
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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) {
|
package/dist/lib/runner.d.ts
CHANGED
|
@@ -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;
|