@phnx-labs/agents-cli 1.20.34 → 1.20.36
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 +113 -0
- package/LICENSE +185 -21
- package/README.md +13 -5
- package/dist/commands/audit.d.ts +14 -0
- package/dist/commands/audit.js +68 -0
- package/dist/commands/browser.js +82 -8
- package/dist/commands/check.d.ts +15 -0
- package/dist/commands/check.js +84 -0
- package/dist/commands/cloud.js +143 -3
- package/dist/commands/computer-actions.d.ts +15 -0
- package/dist/commands/computer-actions.js +120 -22
- package/dist/commands/computer.js +81 -0
- package/dist/commands/cost.js +17 -12
- package/dist/commands/daemon.js +4 -1
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +54 -97
- package/dist/commands/events.d.ts +16 -0
- package/dist/commands/events.js +173 -0
- package/dist/commands/exec.d.ts +19 -0
- package/dist/commands/exec.js +283 -12
- package/dist/commands/hosts.js +37 -29
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.js +62 -16
- package/dist/commands/lock.d.ts +12 -0
- package/dist/commands/lock.js +70 -0
- package/dist/commands/logs.d.ts +17 -0
- package/dist/commands/logs.js +139 -0
- package/dist/commands/message.d.ts +15 -0
- package/dist/commands/message.js +56 -0
- package/dist/commands/models.d.ts +3 -0
- package/dist/commands/models.js +27 -8
- package/dist/commands/permissions.js +9 -2
- package/dist/commands/repo.d.ts +34 -0
- package/dist/commands/repo.js +243 -65
- package/dist/commands/resource-view.d.ts +20 -0
- package/dist/commands/resource-view.js +90 -28
- package/dist/commands/routines.js +101 -5
- package/dist/commands/secrets-migrate.js +106 -57
- package/dist/commands/secrets.d.ts +31 -18
- package/dist/commands/secrets.js +196 -91
- package/dist/commands/serve.d.ts +10 -0
- package/dist/commands/serve.js +37 -0
- package/dist/commands/sessions-inject.d.ts +14 -0
- package/dist/commands/sessions-inject.js +111 -0
- package/dist/commands/sessions-picker.d.ts +2 -0
- package/dist/commands/sessions-picker.js +24 -3
- package/dist/commands/sessions-resume.d.ts +2 -0
- package/dist/commands/sessions-resume.js +221 -0
- package/dist/commands/sessions-tail.d.ts +10 -0
- package/dist/commands/sessions-tail.js +11 -0
- package/dist/commands/sessions.d.ts +143 -1
- package/dist/commands/sessions.js +628 -80
- package/dist/commands/setup.js +4 -2
- package/dist/commands/sync.d.ts +3 -1
- package/dist/commands/sync.js +156 -4
- package/dist/commands/teams.js +217 -0
- package/dist/commands/versions.js +2 -4
- package/dist/commands/view.d.ts +3 -0
- package/dist/commands/view.js +19 -8
- package/dist/commands/wallet.d.ts +6 -0
- package/dist/commands/wallet.js +22 -5
- package/dist/commands/watchdog.d.ts +18 -0
- package/dist/commands/watchdog.js +238 -0
- package/dist/index.js +82 -32
- package/dist/lib/agents.js +30 -9
- package/dist/lib/audit/log.d.ts +92 -0
- package/dist/lib/audit/log.js +177 -0
- package/dist/lib/auto-pull.js +2 -1
- package/dist/lib/browser/cdp.js +5 -1
- package/dist/lib/browser/chrome.d.ts +10 -0
- package/dist/lib/browser/chrome.js +18 -7
- package/dist/lib/browser/drivers/ssh.d.ts +8 -0
- package/dist/lib/browser/drivers/ssh.js +77 -16
- package/dist/lib/browser/har.d.ts +84 -0
- package/dist/lib/browser/har.js +77 -0
- package/dist/lib/browser/ipc.d.ts +3 -0
- package/dist/lib/browser/ipc.js +37 -12
- package/dist/lib/browser/profiles.d.ts +1 -1
- package/dist/lib/browser/profiles.js +8 -10
- package/dist/lib/browser/refs.d.ts +65 -0
- package/dist/lib/browser/refs.js +73 -1
- package/dist/lib/browser/runtime-state.js +1 -0
- package/dist/lib/browser/service.d.ts +38 -2
- package/dist/lib/browser/service.js +183 -23
- package/dist/lib/browser/types.d.ts +14 -1
- package/dist/lib/budget/live-cloud.d.ts +42 -0
- package/dist/lib/budget/live-cloud.js +79 -0
- package/dist/lib/budget/live-team.d.ts +31 -0
- package/dist/lib/budget/live-team.js +115 -0
- package/dist/lib/cloud/codex.js +4 -0
- package/dist/lib/cloud/rush.d.ts +12 -1
- package/dist/lib/cloud/rush.js +13 -3
- package/dist/lib/cloud/types.d.ts +9 -0
- package/dist/lib/computer/dispatch.d.ts +8 -0
- package/dist/lib/computer/dispatch.js +125 -0
- package/dist/lib/computer/loop.d.ts +62 -0
- package/dist/lib/computer/loop.js +98 -0
- package/dist/lib/computer/model.d.ts +44 -0
- package/dist/lib/computer/model.js +157 -0
- package/dist/lib/concurrency.d.ts +19 -0
- package/dist/lib/concurrency.js +33 -0
- package/dist/lib/daemon.d.ts +92 -0
- package/dist/lib/daemon.js +222 -18
- package/dist/lib/devices/connect.d.ts +3 -2
- package/dist/lib/devices/connect.js +5 -3
- package/dist/lib/devices/registry.d.ts +7 -0
- package/dist/lib/devices/registry.js +24 -0
- package/dist/lib/devices/tailscale.js +1 -1
- package/dist/lib/drift.d.ts +52 -0
- package/dist/lib/drift.js +112 -0
- package/dist/lib/events.d.ts +10 -3
- package/dist/lib/events.js +101 -24
- package/dist/lib/exec.d.ts +17 -0
- package/dist/lib/exec.js +100 -12
- package/dist/lib/git.d.ts +27 -0
- package/dist/lib/git.js +56 -1
- package/dist/lib/hooks/cache.d.ts +6 -0
- package/dist/lib/hooks/cache.js +54 -12
- package/dist/lib/hooks.d.ts +27 -0
- package/dist/lib/hooks.js +135 -10
- package/dist/lib/hosts/dispatch.d.ts +15 -0
- package/dist/lib/hosts/dispatch.js +45 -13
- package/dist/lib/hosts/logs.d.ts +16 -0
- package/dist/lib/hosts/logs.js +74 -0
- package/dist/lib/hosts/option.js +1 -1
- package/dist/lib/hosts/passthrough.js +3 -1
- package/dist/lib/hosts/progress.d.ts +66 -0
- package/dist/lib/hosts/progress.js +125 -17
- package/dist/lib/hosts/ready.d.ts +51 -7
- package/dist/lib/hosts/ready.js +98 -25
- package/dist/lib/hosts/reconcile.d.ts +53 -0
- package/dist/lib/hosts/reconcile.js +81 -0
- package/dist/lib/hosts/registry.d.ts +19 -2
- package/dist/lib/hosts/registry.js +58 -2
- package/dist/lib/hosts/remote-cmd.d.ts +62 -1
- package/dist/lib/hosts/remote-cmd.js +70 -1
- package/dist/lib/hosts/remote-os.d.ts +17 -0
- package/dist/lib/hosts/remote-os.js +30 -0
- package/dist/lib/hosts/session-index.d.ts +34 -0
- package/dist/lib/hosts/session-index.js +56 -0
- package/dist/lib/hosts/tasks.d.ts +22 -0
- package/dist/lib/hosts/tasks.js +29 -0
- package/dist/lib/lock.d.ts +93 -0
- package/dist/lib/lock.js +207 -0
- package/dist/lib/loop.js +16 -1
- package/dist/lib/machine-id.d.ts +21 -0
- package/dist/lib/machine-id.js +26 -0
- package/dist/lib/mailbox-target.d.ts +36 -0
- package/dist/lib/mailbox-target.js +45 -0
- package/dist/lib/mailbox.d.ts +47 -0
- package/dist/lib/mailbox.js +194 -0
- package/dist/lib/mcp.d.ts +5 -0
- package/dist/lib/mcp.js +24 -8
- package/dist/lib/migrate.d.ts +19 -0
- package/dist/lib/migrate.js +134 -26
- package/dist/lib/overdue.js +3 -0
- package/dist/lib/permissions.d.ts +4 -0
- package/dist/lib/permissions.js +35 -0
- package/dist/lib/picker.d.ts +26 -0
- package/dist/lib/picker.js +127 -0
- package/dist/lib/platform/exec.d.ts +46 -0
- package/dist/lib/platform/exec.js +74 -0
- package/dist/lib/platform/process.d.ts +31 -0
- package/dist/lib/platform/process.js +34 -1
- package/dist/lib/platform/winpath.js +2 -0
- package/dist/lib/plugin-marketplace.d.ts +30 -0
- package/dist/lib/plugin-marketplace.js +215 -2
- package/dist/lib/plugins.d.ts +5 -0
- package/dist/lib/plugins.js +61 -10
- package/dist/lib/profiles.d.ts +25 -0
- package/dist/lib/profiles.js +22 -6
- package/dist/lib/pty-client.js +2 -1
- package/dist/lib/rotate.d.ts +61 -0
- package/dist/lib/rotate.js +52 -0
- package/dist/lib/routines.d.ts +40 -2
- package/dist/lib/routines.js +66 -8
- package/dist/lib/runner.d.ts +11 -2
- package/dist/lib/runner.js +49 -7
- package/dist/lib/scheduler.js +6 -1
- package/dist/lib/secrets/bundles.d.ts +60 -4
- package/dist/lib/secrets/bundles.js +131 -12
- package/dist/lib/secrets/filestore.d.ts +3 -0
- package/dist/lib/secrets/filestore.js +42 -16
- package/dist/lib/secrets/index.d.ts +43 -2
- package/dist/lib/secrets/index.js +102 -3
- package/dist/lib/secrets/mcp.d.ts +93 -0
- package/dist/lib/secrets/mcp.js +205 -0
- package/dist/lib/secrets/remote.js +12 -5
- package/dist/lib/secrets/sync.js +83 -4
- package/dist/lib/secrets/windows.js +14 -3
- package/dist/lib/serve/data.d.ts +81 -0
- package/dist/lib/serve/data.js +91 -0
- package/dist/lib/serve/page.d.ts +7 -0
- package/dist/lib/serve/page.js +140 -0
- package/dist/lib/serve/server.d.ts +46 -0
- package/dist/lib/serve/server.js +115 -0
- package/dist/lib/session/active.d.ts +61 -0
- package/dist/lib/session/active.js +196 -17
- package/dist/lib/session/discover.d.ts +37 -0
- package/dist/lib/session/discover.js +204 -27
- package/dist/lib/session/inject.d.ts +18 -0
- package/dist/lib/session/inject.js +21 -0
- package/dist/lib/session/parse.d.ts +6 -0
- package/dist/lib/session/parse.js +286 -2
- package/dist/lib/session/pid-registry.d.ts +22 -0
- package/dist/lib/session/pid-registry.js +104 -0
- package/dist/lib/session/provenance.d.ts +14 -2
- package/dist/lib/session/provenance.js +39 -8
- package/dist/lib/session/remote-active.d.ts +26 -0
- package/dist/lib/session/remote-active.js +153 -0
- package/dist/lib/session/remote-list.d.ts +51 -0
- package/dist/lib/session/remote-list.js +213 -0
- package/dist/lib/session/remote.d.ts +7 -1
- package/dist/lib/session/remote.js +18 -8
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/sync/config.d.ts +1 -7
- package/dist/lib/session/sync/config.js +4 -11
- package/dist/lib/session/types.d.ts +18 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +44 -6
- package/dist/lib/shims.js +143 -57
- package/dist/lib/ssh-exec.d.ts +26 -3
- package/dist/lib/ssh-exec.js +47 -3
- package/dist/lib/ssh-tunnel.d.ts +24 -5
- package/dist/lib/ssh-tunnel.js +62 -63
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +8 -0
- package/dist/lib/startup/command-registry.js +17 -1
- package/dist/lib/state.d.ts +13 -0
- package/dist/lib/state.js +103 -9
- package/dist/lib/sync-umbrella.d.ts +14 -7
- package/dist/lib/sync-umbrella.js +17 -9
- package/dist/lib/teams/forEach.d.ts +110 -0
- package/dist/lib/teams/forEach.js +186 -0
- package/dist/lib/teams/index.d.ts +1 -0
- package/dist/lib/teams/index.js +1 -0
- package/dist/lib/teams/pr-watch.d.ts +226 -0
- package/dist/lib/teams/pr-watch.js +371 -0
- package/dist/lib/teams/registry.js +25 -9
- package/dist/lib/teams/supervisor.d.ts +14 -1
- package/dist/lib/teams/supervisor.js +19 -0
- package/dist/lib/teams/worktree.d.ts +9 -0
- package/dist/lib/teams/worktree.js +32 -0
- package/dist/lib/terminal/backends/ghostty.d.ts +6 -0
- package/dist/lib/terminal/backends/ghostty.js +69 -0
- package/dist/lib/terminal/backends/index.d.ts +19 -0
- package/dist/lib/terminal/backends/index.js +31 -0
- package/dist/lib/terminal/backends/iterm.d.ts +6 -0
- package/dist/lib/terminal/backends/iterm.js +62 -0
- package/dist/lib/terminal/backends/tmux.d.ts +14 -0
- package/dist/lib/terminal/backends/tmux.js +23 -0
- package/dist/lib/terminal/backends/vscodium-agent.d.ts +31 -0
- package/dist/lib/terminal/backends/vscodium-agent.js +72 -0
- package/dist/lib/terminal/engine.d.ts +39 -0
- package/dist/lib/terminal/engine.js +54 -0
- package/dist/lib/terminal/index.d.ts +17 -0
- package/dist/lib/terminal/index.js +8 -0
- package/dist/lib/terminal/inject.d.ts +204 -0
- package/dist/lib/terminal/inject.js +247 -0
- package/dist/lib/terminal/policy.d.ts +11 -0
- package/dist/lib/terminal/policy.js +11 -0
- package/dist/lib/terminal/quote.d.ts +11 -0
- package/dist/lib/terminal/quote.js +13 -0
- package/dist/lib/terminal/resolve.d.ts +64 -0
- package/dist/lib/terminal/resolve.js +90 -0
- package/dist/lib/terminal/shell.d.ts +6 -0
- package/dist/lib/terminal/shell.js +23 -0
- package/dist/lib/terminal/transport.d.ts +15 -0
- package/dist/lib/terminal/transport.js +40 -0
- package/dist/lib/terminal/types.d.ts +59 -0
- package/dist/lib/terminal/types.js +13 -0
- package/dist/lib/triggers/webhook.d.ts +85 -0
- package/dist/lib/triggers/webhook.js +141 -0
- package/dist/lib/types.d.ts +7 -0
- package/dist/lib/versions.d.ts +30 -3
- package/dist/lib/versions.js +129 -18
- package/dist/lib/watchdog/index.d.ts +3 -0
- package/dist/lib/watchdog/index.js +5 -0
- package/dist/lib/watchdog/read.d.ts +35 -0
- package/dist/lib/watchdog/read.js +149 -0
- package/dist/lib/watchdog/runner.d.ts +127 -0
- package/dist/lib/watchdog/runner.js +322 -0
- package/dist/lib/watchdog/watchdog.d.ts +40 -0
- package/dist/lib/watchdog/watchdog.js +166 -0
- package/dist/lib/watchdog/watchdogTail.d.ts +5 -0
- package/dist/lib/watchdog/watchdogTail.js +154 -0
- package/dist/lib/whats-new.d.ts +9 -0
- package/dist/lib/whats-new.js +35 -0
- package/dist/lib/workflows.d.ts +166 -0
- package/dist/lib/workflows.js +193 -0
- package/package.json +5 -4
package/dist/lib/workflows.js
CHANGED
|
@@ -11,6 +11,13 @@ import * as yaml from 'yaml';
|
|
|
11
11
|
import { capableAgents } from './capabilities.js';
|
|
12
12
|
import { getProjectAgentsDir, getSystemWorkflowsDir, getUserWorkflowsDir, getTrashWorkflowsDir, getEnabledExtraRepos, } from './state.js';
|
|
13
13
|
import { listInstalledVersions, getVersionHomePath } from './versions.js';
|
|
14
|
+
/**
|
|
15
|
+
* Hard upper bound on items a single `for_each` expands, absent an explicit
|
|
16
|
+
* `max_items`. A guard against a runaway producer spawning unbounded teammates
|
|
17
|
+
* (acceptance criterion in issue #343). Anthropic's Dynamic Workflows cap at
|
|
18
|
+
* 1000; we default lower and let authors raise it deliberately.
|
|
19
|
+
*/
|
|
20
|
+
export const DEFAULT_FOR_EACH_CAP = 256;
|
|
14
21
|
/** Parse WORKFLOW.md frontmatter from a workflow directory. Returns null if invalid. */
|
|
15
22
|
export function parseWorkflowFrontmatter(workflowDir) {
|
|
16
23
|
const workflowMdPath = path.join(workflowDir, 'WORKFLOW.md');
|
|
@@ -42,6 +49,7 @@ export function parseWorkflowFrontmatter(workflowDir) {
|
|
|
42
49
|
allowedAgents: asStringArray(parsed.allowedAgents),
|
|
43
50
|
secrets: asStringArray(parsed.secrets),
|
|
44
51
|
loop: parseLoopBlock(parsed.loop),
|
|
52
|
+
forEach: parseForEachBlock(parsed.for_each),
|
|
45
53
|
};
|
|
46
54
|
}
|
|
47
55
|
catch {
|
|
@@ -83,6 +91,152 @@ export function parseLoopBlock(v) {
|
|
|
83
91
|
out.interval = raw.interval;
|
|
84
92
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
85
93
|
}
|
|
94
|
+
/** A finite positive integer, or undefined. Shared guard for count-like fields. */
|
|
95
|
+
function asPosInt(v) {
|
|
96
|
+
return typeof v === 'number' && Number.isFinite(v) && Number.isInteger(v) && v > 0
|
|
97
|
+
? v
|
|
98
|
+
: undefined;
|
|
99
|
+
}
|
|
100
|
+
/** A non-empty trimmed string, or undefined. */
|
|
101
|
+
function asNonEmptyString(v) {
|
|
102
|
+
return typeof v === 'string' && v.trim().length > 0 ? v : undefined;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Defensively coerce a frontmatter `verify:` sub-block into a ForEachVerifySpec.
|
|
106
|
+
*
|
|
107
|
+
* Requires an `agent`; drops the whole block otherwise (a verify panel with no
|
|
108
|
+
* skeptic is meaningless). `votes` defaults to 1 (a single confirmation) and
|
|
109
|
+
* `keep_if` to `majority`; both are validated against their allowed shapes.
|
|
110
|
+
*/
|
|
111
|
+
export function parseVerifyBlock(v) {
|
|
112
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
113
|
+
return undefined;
|
|
114
|
+
const raw = v;
|
|
115
|
+
const agent = asNonEmptyString(raw.agent);
|
|
116
|
+
if (!agent)
|
|
117
|
+
return undefined;
|
|
118
|
+
const keepIf = raw.keep_if;
|
|
119
|
+
const out = {
|
|
120
|
+
agent,
|
|
121
|
+
votes: asPosInt(raw.votes) ?? 1,
|
|
122
|
+
keep_if: keepIf === 'all' || keepIf === 'any' || keepIf === 'majority'
|
|
123
|
+
? keepIf
|
|
124
|
+
: 'majority',
|
|
125
|
+
};
|
|
126
|
+
const prompt = asNonEmptyString(raw.prompt);
|
|
127
|
+
if (prompt)
|
|
128
|
+
out.prompt = prompt;
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Defensively coerce a frontmatter `for_each:` block into a ForEachSpec (issue
|
|
133
|
+
* #343). Mirrors `parseLoopBlock`'s discipline: a block missing the two
|
|
134
|
+
* load-bearing fields (`agent` + `prompt`) drops to undefined rather than
|
|
135
|
+
* passing a half-formed spec to the expander. Optional numeric/verify fields
|
|
136
|
+
* are individually validated and dropped when malformed.
|
|
137
|
+
*/
|
|
138
|
+
export function parseForEachBlock(v) {
|
|
139
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
140
|
+
return undefined;
|
|
141
|
+
const raw = v;
|
|
142
|
+
const agent = asNonEmptyString(raw.agent);
|
|
143
|
+
const prompt = asNonEmptyString(raw.prompt);
|
|
144
|
+
if (!agent || !prompt)
|
|
145
|
+
return undefined;
|
|
146
|
+
const out = { agent, prompt };
|
|
147
|
+
const produce = asNonEmptyString(raw.produce);
|
|
148
|
+
if (produce)
|
|
149
|
+
out.produce = produce;
|
|
150
|
+
// `for_each: ${step}` references a prior step's list. Accept either the
|
|
151
|
+
// snake-case `for_each` key or an explicit `items_ref`.
|
|
152
|
+
const itemsRef = asNonEmptyString(raw.for_each) ?? asNonEmptyString(raw.items_ref);
|
|
153
|
+
if (itemsRef)
|
|
154
|
+
out.itemsRef = itemsRef;
|
|
155
|
+
const name = asNonEmptyString(raw.name);
|
|
156
|
+
if (name)
|
|
157
|
+
out.name = name;
|
|
158
|
+
const concurrency = asPosInt(raw.concurrency);
|
|
159
|
+
if (concurrency)
|
|
160
|
+
out.concurrency = concurrency;
|
|
161
|
+
const maxItems = asPosInt(raw.max_items);
|
|
162
|
+
if (maxItems)
|
|
163
|
+
out.max_items = maxItems;
|
|
164
|
+
const verify = parseVerifyBlock(raw.verify);
|
|
165
|
+
if (verify)
|
|
166
|
+
out.verify = verify;
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Substitute `{{item}}` / `{{index}}` (and 1-based `{{n}}`) in a prompt
|
|
171
|
+
* template. Unknown `{{...}}` tokens are left intact so a template can carry
|
|
172
|
+
* placeholders the caller resolves elsewhere.
|
|
173
|
+
*/
|
|
174
|
+
export function renderForEachTemplate(template, item, index) {
|
|
175
|
+
return template
|
|
176
|
+
.replace(/\{\{\s*item\s*\}\}/g, item)
|
|
177
|
+
.replace(/\{\{\s*index\s*\}\}/g, String(index))
|
|
178
|
+
.replace(/\{\{\s*n\s*\}\}/g, String(index + 1));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Expand a `for_each` spec against a producer's output into concrete teammate
|
|
182
|
+
* descriptors (issue #343) — the heart of the declarative fan-out.
|
|
183
|
+
*
|
|
184
|
+
* Pure and deterministic: no I/O, no spawning. `src/lib/teams/forEach.ts`
|
|
185
|
+
* feeds the result to `AgentManager.spawn`, staging each descriptor into the
|
|
186
|
+
* supervisor's existing mid-flight-add path — so this reuses the dynamic-DAG
|
|
187
|
+
* substrate rather than introducing a new engine.
|
|
188
|
+
*
|
|
189
|
+
* For N produced items (capped at `spec.max_items` / `DEFAULT_FOR_EACH_CAP`):
|
|
190
|
+
* - one `stage` teammate per item, depending on `producerName` if given;
|
|
191
|
+
* - when `verify` is set, `votes` `verify` teammates per item, each
|
|
192
|
+
* depending on that item's stage teammate.
|
|
193
|
+
*
|
|
194
|
+
* Names are unique (`<base>-<n>` and `<base>-<n>-verify-<v>`) so `--after`
|
|
195
|
+
* linkage and the teams cycle check carry over unchanged.
|
|
196
|
+
*/
|
|
197
|
+
export function expandForEach(spec, items, opts = {}) {
|
|
198
|
+
const cap = spec.max_items ?? DEFAULT_FOR_EACH_CAP;
|
|
199
|
+
const producedCount = items.length;
|
|
200
|
+
const used = items.slice(0, cap);
|
|
201
|
+
const base = spec.name ?? 'item';
|
|
202
|
+
const teammates = [];
|
|
203
|
+
used.forEach((item, itemIndex) => {
|
|
204
|
+
const stageName = `${base}-${itemIndex + 1}`;
|
|
205
|
+
teammates.push({
|
|
206
|
+
role: 'stage',
|
|
207
|
+
name: stageName,
|
|
208
|
+
agentType: spec.agent,
|
|
209
|
+
prompt: renderForEachTemplate(spec.prompt, item, itemIndex),
|
|
210
|
+
after: opts.producerName ? [opts.producerName] : [],
|
|
211
|
+
item,
|
|
212
|
+
itemIndex,
|
|
213
|
+
});
|
|
214
|
+
if (spec.verify) {
|
|
215
|
+
const verifyPrompt = spec.verify.prompt ?? spec.prompt;
|
|
216
|
+
for (let vote = 1; vote <= spec.verify.votes; vote++) {
|
|
217
|
+
teammates.push({
|
|
218
|
+
role: 'verify',
|
|
219
|
+
name: `${stageName}-verify-${vote}`,
|
|
220
|
+
agentType: spec.verify.agent,
|
|
221
|
+
prompt: renderForEachTemplate(verifyPrompt, item, itemIndex),
|
|
222
|
+
after: [stageName],
|
|
223
|
+
item,
|
|
224
|
+
itemIndex,
|
|
225
|
+
vote,
|
|
226
|
+
votes: spec.verify.votes,
|
|
227
|
+
keep_if: spec.verify.keep_if,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
return {
|
|
233
|
+
teammates,
|
|
234
|
+
producedCount,
|
|
235
|
+
usedCount: used.length,
|
|
236
|
+
truncated: producedCount - used.length,
|
|
237
|
+
cap,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
86
240
|
/**
|
|
87
241
|
* Decide which subagent .md stems a workflow may use, given the discovered
|
|
88
242
|
* subagent files and the parsed `allowedAgents` frontmatter. This is the
|
|
@@ -110,6 +264,45 @@ export function resolveAllowedSubagents(available, allowedAgents) {
|
|
|
110
264
|
missing: allowedAgents.filter(a => !present.has(a)),
|
|
111
265
|
};
|
|
112
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Prune stale workflow-managed subagent files from the shared per-agent agents
|
|
269
|
+
* dir before a scoped run writes the permitted set (issue #401, follow-up to
|
|
270
|
+
* #324). A prior *unrestricted* run of a workflow copies every subagent
|
|
271
|
+
* definition into the shared `~/.claude/agents/` dir; a later run that declares
|
|
272
|
+
* `allowedAgents:` copies only the permitted ones but never removes the
|
|
273
|
+
* leftovers — so an unlisted subagent stays on disk and remains dispatchable,
|
|
274
|
+
* silently defeating the fail-closed scope.
|
|
275
|
+
*
|
|
276
|
+
* Fail-closed fix (mirrors how `cleanupWorkflowMcpConfig` only tears down what
|
|
277
|
+
* the workflow itself created): remove any file that (a) belongs to THIS
|
|
278
|
+
* workflow's subagents/ — matched by filename, i.e. the workflow-managed
|
|
279
|
+
* universe — and (b) is NOT in the permitted set. A user's own hand-placed
|
|
280
|
+
* subagent shares no name with a workflow subagent file, so it is never
|
|
281
|
+
* touched. Permitted files are left in place; the caller (re)copies them.
|
|
282
|
+
*
|
|
283
|
+
* `workflowSubagentFiles` are the .md filenames in the workflow's subagents/
|
|
284
|
+
* dir (e.g. `security.md`); `allowedStems` are the permitted stems from
|
|
285
|
+
* `resolveAllowedSubagents`. Returns the filenames actually removed.
|
|
286
|
+
*/
|
|
287
|
+
export function pruneStaleWorkflowSubagents(sharedAgentsDir, workflowSubagentFiles, allowedStems) {
|
|
288
|
+
if (!fs.existsSync(sharedAgentsDir))
|
|
289
|
+
return [];
|
|
290
|
+
const allow = new Set(allowedStems);
|
|
291
|
+
const pruned = [];
|
|
292
|
+
for (const file of workflowSubagentFiles) {
|
|
293
|
+
if (!file.endsWith('.md'))
|
|
294
|
+
continue;
|
|
295
|
+
const stem = file.replace(/\.md$/, '');
|
|
296
|
+
if (allow.has(stem))
|
|
297
|
+
continue; // permitted → the copy step will (re)write it
|
|
298
|
+
const target = path.join(sharedAgentsDir, file);
|
|
299
|
+
if (fs.existsSync(target)) {
|
|
300
|
+
fs.rmSync(target, { force: true });
|
|
301
|
+
pruned.push(file);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return pruned;
|
|
305
|
+
}
|
|
113
306
|
/** Count subagent .md files in a workflow's subagents/ directory. */
|
|
114
307
|
export function countWorkflowSubagents(workflowDir) {
|
|
115
308
|
const subagentsDir = path.join(workflowDir, 'subagents');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.36",
|
|
4
4
|
"description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "tsc && rm -rf 'dist/lib/secrets/AgentsKeychain.app' 'dist/lib/secrets/Agents CLI.app' 'dist/lib/menubar/MenubarHelper.app' && ([ \"$(uname)\" = \"Darwin\" ] && cp -R 'bin/Agents CLI.app' 'dist/lib/secrets/Agents CLI.app' || true) && ([ \"$(uname)\" = \"Darwin\" ] && [ -d 'bin/MenubarHelper.app' ] && mkdir -p 'dist/lib/menubar' && cp -R 'bin/MenubarHelper.app' 'dist/lib/menubar/MenubarHelper.app' || true)",
|
|
48
48
|
"build:bin": "scripts/build-bin.sh",
|
|
49
|
+
"prepare": "npm run build",
|
|
49
50
|
"prepack": "scripts/verify-keychain-helper.sh && scripts/verify-menubar-helper.sh",
|
|
50
51
|
"postinstall": "node scripts/postinstall.js",
|
|
51
52
|
"dev": "tsx src/index.ts",
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
"multi-agent"
|
|
73
74
|
],
|
|
74
75
|
"author": "Phoenix Labs",
|
|
75
|
-
"license": "
|
|
76
|
+
"license": "Apache-2.0",
|
|
76
77
|
"engines": {
|
|
77
78
|
"node": ">=22.5.0",
|
|
78
79
|
"npm": ">=9"
|
|
@@ -102,8 +103,8 @@
|
|
|
102
103
|
"devDependencies": {
|
|
103
104
|
"@types/diff": "8.0.0",
|
|
104
105
|
"@types/marked-terminal": "6.1.1",
|
|
105
|
-
"@types/node": "
|
|
106
|
-
"tsx": "4.
|
|
106
|
+
"@types/node": "26.1.0",
|
|
107
|
+
"tsx": "4.23.0",
|
|
107
108
|
"typescript": "6.0.3",
|
|
108
109
|
"vitest": "4.1.9"
|
|
109
110
|
}
|