@phnx-labs/agents-cli 1.22.16 → 1.22.17
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 +12 -0
- package/README.md +10 -1
- package/dist/bin/agents +0 -0
- package/dist/commands/cloud.d.ts +0 -1
- package/dist/commands/cloud.js +19 -185
- package/dist/commands/doctor.js +16 -14
- package/dist/commands/exec.js +57 -5
- package/dist/commands/feed.d.ts +1 -0
- package/dist/commands/feed.js +36 -32
- package/dist/commands/run-cloud.d.ts +26 -0
- package/dist/commands/run-cloud.js +162 -0
- package/dist/commands/versions.js +4 -2
- package/dist/commands/view.js +1 -54
- package/dist/lib/agents.js +4 -2
- package/dist/lib/channels/send.d.ts +3 -3
- package/dist/lib/channels/send.js +13 -18
- package/dist/lib/cloud/dispatch.d.ts +27 -0
- package/dist/lib/cloud/dispatch.js +214 -0
- package/dist/lib/feed-post.d.ts +2 -2
- package/dist/lib/feed-post.js +15 -10
- package/dist/lib/hosts/remote-cmd.js +8 -0
- package/dist/lib/humans.d.ts +3 -2
- package/dist/lib/humans.js +16 -8
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/notify.d.ts +4 -4
- package/dist/lib/notify.js +3 -6
- package/dist/lib/placement.d.ts +8 -4
- package/dist/lib/placement.js +14 -8
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/settings-manifest.js +7 -1
- package/dist/lib/types.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.17
|
|
4
|
+
|
|
5
|
+
- **Codex versions no longer share one account — each keeps its own login.** Installing a new Codex version used to copy the current default version's `.codex/auth.json` into the new version home, so `agents view` reported the same ChatGPT account for every installed Codex and you could never sign two versions into two accounts. The credential is now excluded from settings carry-forward (config, prompts, and rules still carry), matching how Claude omits `.claude.json`. A fresh Codex version installs signed-out; run `codex login` (or `agents run codex --version <v>`) inside it to authenticate that version's own account. Source: `apps/cli/src/lib/settings-manifest.ts`, `apps/cli/src/commands/versions.ts`.
|
|
6
|
+
|
|
7
|
+
- **`agents feed post` now resolves owner delivery and session identity from their canonical indexes (RUSH-2193).** `agents notify` and `channel: owner` consume the normal addressable channel from `humans.yaml`, so the phone destination is no longer duplicated in `agents.yaml`. When a harness leaves `AGENT_SESSION_ID` empty, feed posting joins `AGENT_LAUNCH_ID` to recent activity before requiring `--session`. `agents feed post --help` now states that the default `milestone` is recorded but a sink gated at `minLevel: important` only texts for `--level important`; `--blocked` remains reserved for work that cannot continue. Source: `apps/cli/src/lib/humans.ts`, `apps/cli/src/lib/feed-post.ts`, `apps/cli/src/commands/feed.ts`.
|
|
8
|
+
|
|
9
|
+
- **The macOS menu bar keeps its ACTIVE project accordion open and opens Quick Dispatch without blocking.** Project headers now mutate their session rows inside the existing `NSMenu` tracking session instead of closing the dropdown and attempting a synthetic reopen. `Cmd-Shift-O` prebuilds and focuses its panel before any session-history, attachment scan, thumbnail decode, or Linear-cache work; those sections hydrate asynchronously from warm data. Source: `apps/cli/menubar/Sources/MenubarHelper/{StatusItemController,PromptPanel,AgentsCLI}.swift`, `apps/cli/docs/menubar.md`. (#2051)
|
|
10
|
+
|
|
11
|
+
- **`agents doctor` now accepts symbolic version qualifiers; `agents view` no longer prompts to sync resources.** `agents doctor claude@latest`, `@oldest`, `@pinned`, `@all`, and exact semver qualifiers are resolved through the shared `resolveAgentTargets` engine instead of falling through to a "not installed" error. Bare `agents doctor <agent>` still sweeps all installed versions with `versionExplicit: false` (so `--fix` excludes isolated copies). Separately, the implicit resource-drift scan and interactive sync prompt that ran at the end of `agents view <agent>` have been removed — `view` is read-only and must not mutate version-home state. Source: `apps/cli/src/commands/doctor.ts`, `apps/cli/src/commands/view.ts`. (#2058)
|
|
12
|
+
|
|
13
|
+
- **`agents run <agent> --cloud` — the vendor cloud becomes a run placement.** `--cloud` dispatches the run to the agent's native cloud through the existing provider registry (claude→rush, codex→codex, droid→factory, antigravity→antigravity) — the exact same dispatch as `agents cloud run --agent <agent>`, tracked by `agents cloud list/status/logs/cancel/message`. It sits alongside `--host`/`--device`/`--lease` as the third placement (local, machine, cloud) and is mutually exclusive with them; `--where cloud[:provider]` is the one-door spelling. `--provider` overrides routing; `--repo` (repeatable), `--branch`, and `--cloud-env` refine the task (run's `--env` stays the KEY=VAL passthrough, so the Codex Cloud environment id gets its own flag). Agents without a native cloud (kimi, grok, cursor, opencode, …) fail loud with the capable list unless `--provider` is given, and local-run flags (`--loop`, `--resume`, `--secrets`, `--terminal`, `--cwd`, account strategy, …) are rejected rather than silently dropped. The dispatch core is now shared: `agents cloud run` and `agents run --cloud` both call `src/lib/cloud/dispatch.ts` (`executeCloudDispatch`), so capability checks, the missing-target picker, persistence, streaming, and the budget kill-switch cannot diverge. Source: `apps/cli/src/commands/run-cloud.ts`, `apps/cli/src/lib/cloud/dispatch.ts`, `apps/cli/src/lib/placement.ts`, `apps/cli/src/commands/exec.ts`.
|
|
14
|
+
|
|
3
15
|
## 1.22.16
|
|
4
16
|
|
|
5
17
|
- **Resume exact sessions locally or across the fleet with `agents resume <id>` and `agents run <agent|auto> --resume <id>`.** Full IDs use the local SQLite index before any SSH fan-out; remote owners route to the recorded device and version home. Session metadata now records launch mode alongside harness, version, account, cwd, and machine so strict resume reconstructs the original run. Claude, Codex, Grok, Kimi, Droid, and Cursor use their verified version-specific native resume syntax; `run auto --resume` can select another healthy harness/account and continue through `/continue` when native resume is unavailable. Source: `apps/cli/src/commands/{exec,resume,sessions}.ts`, `apps/cli/src/lib/{exec,session/db}.ts`, `packages/session-tracker/src/hook.sh`.
|
package/README.md
CHANGED
|
@@ -507,6 +507,13 @@ agents logs <id> --full # the full raw transcript / stdout (toke
|
|
|
507
507
|
agents logs <id> -f # re-attach to a running one and follow
|
|
508
508
|
agents view claude --host gpu-box # inspect the remote install
|
|
509
509
|
agents sync --host gpu-box # make the remote machine current
|
|
510
|
+
agents doctor claude # diagnose every installed claude version
|
|
511
|
+
agents doctor claude@latest # diagnose only the newest installed version
|
|
512
|
+
agents doctor claude@oldest # diagnose only the oldest installed version
|
|
513
|
+
agents doctor claude@pinned # diagnose the global-default (pinned) version
|
|
514
|
+
agents doctor claude@all # diagnose all versions, including isolated copies
|
|
515
|
+
agents doctor claude@latest --fix # auto-fix the newest installed version
|
|
516
|
+
agents doctor claude@latest --device mac-mini # diagnose newest claude on mac-mini
|
|
510
517
|
agents doctor --devices # readiness matrix for every registered device
|
|
511
518
|
agents doctor --devices --json # machine-readable fleet readiness
|
|
512
519
|
agents doctor --device mac-mini # same matrix, scoped to one device
|
|
@@ -623,6 +630,8 @@ Four managed backends behind one interface (`agents cloud providers`):
|
|
|
623
630
|
|
|
624
631
|
Auto-routes each `--agent` to its native cloud, or pin the backend with `--provider`. Instead of dispatching now, register a run as an **event trigger** with `--on pull_request` (also `push`, `issue_comment`, `workflow_run`) -- it persists as a trigger-bound routine that fires on the event. `--json` on every subcommand for scripting.
|
|
625
632
|
|
|
633
|
+
The same dispatch is a placement on `agents run`: `agents run claude "fix the flaky e2e" --cloud --repo acme/api` routes through the identical provider registry and tracks in `agents cloud list/status/logs` alike. `--cloud` sits alongside `--host`/`--device`/`--lease` as one of three placements (local, machine, cloud) and is mutually exclusive with them; `--where cloud[:provider]` is the one-door spelling. Agents without a native cloud fail loud unless `--provider` is given.
|
|
634
|
+
|
|
626
635
|
---
|
|
627
636
|
|
|
628
637
|
## Workflows
|
|
@@ -1072,7 +1081,7 @@ The dropdown surfaces a **NEEDS YOU** queue (agents waiting on a question, a pla
|
|
|
1072
1081
|
|
|
1073
1082
|
### Quick-issue bar (⌘⇧O)
|
|
1074
1083
|
|
|
1075
|
-
Press `Cmd-Shift-O` anywhere for a thin capture surface:
|
|
1084
|
+
Press `Cmd-Shift-O` anywhere for a thin capture surface: the prepared text field appears immediately while repo, thumbnail, and ticket rows hydrate in the background. Type a one-line note, `Cmd-V` to paste, and attach one or more recent screenshots (double-click a thumbnail to preview it in full). Submit, and a headless agent picks the right project from your recent sessions, investigates, and files the Linear ticket itself -- you never leave what you were doing.
|
|
1076
1085
|
|
|
1077
1086
|
The bar also lists the **open Linear tickets of the repo you picked**, urgent first. Switching the repo switches the Linear project; typing filters the list, so an existing ticket shows up before you file a duplicate; and clicking a row (or `⌘1`-`⌘5`) dispatches that ticket to the selected agents -- **Run** implements it, **Plan** posts a plan as a ticket comment.
|
|
1078
1087
|
|
package/dist/bin/agents
CHANGED
|
Binary file
|
package/dist/commands/cloud.d.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* All tasks are tracked locally in a SQLite database for cross-provider listing.
|
|
7
7
|
*/
|
|
8
8
|
import type { Command } from 'commander';
|
|
9
|
-
/** Print an error message to stderr and exit. */
|
|
10
9
|
/** Return a chalk color function appropriate for the given task status. */
|
|
11
10
|
export declare function statusColor(status: string): (s: string) => string;
|
|
12
11
|
/** Register the `agents cloud` command tree (run, list, status, logs, cancel, message, providers). */
|
package/dist/commands/cloud.js
CHANGED
|
@@ -1,43 +1,12 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { die, relTime, truncate, isJsonMode } from '../lib/format.js';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import ora from 'ora';
|
|
6
3
|
import { resolveProvider, getAllProviders, getDefaultProviderId } from '../lib/cloud/registry.js';
|
|
7
4
|
import { insertTask, updateTaskStatus, getTaskById, listTasks as listStoredTasks, listActiveTasks } from '../lib/cloud/store.js';
|
|
8
5
|
import { renderStream } from '../lib/cloud/stream.js';
|
|
9
|
-
import {
|
|
6
|
+
import { MAX_IMAGES_PER_DISPATCH } from '../lib/cloud/types.js';
|
|
7
|
+
import { resolveCloudPrompt, executeCloudDispatch } from '../lib/cloud/dispatch.js';
|
|
10
8
|
import { normalizeTriggerEvent, validateTrigger, writeJob, setJobEnabled, jobExists, GITHUB_TRIGGER_EVENTS } from '../lib/routines.js';
|
|
11
9
|
import { emit } from '../lib/events.js';
|
|
12
|
-
import { shareRuntimeEnv } from '../lib/share/config.js';
|
|
13
|
-
/** Map a supported image file extension to its wire mimeType. Rejects anything else. */
|
|
14
|
-
function imageMimeFromPath(file) {
|
|
15
|
-
const ext = path.extname(file).toLowerCase();
|
|
16
|
-
if (ext === '.png')
|
|
17
|
-
return 'image/png';
|
|
18
|
-
if (ext === '.jpg' || ext === '.jpeg')
|
|
19
|
-
return 'image/jpeg';
|
|
20
|
-
if (ext === '.webp')
|
|
21
|
-
return 'image/webp';
|
|
22
|
-
die(`Unsupported image type ${JSON.stringify(ext || file)}. Use .png, .jpg/.jpeg, or .webp.`);
|
|
23
|
-
}
|
|
24
|
-
/** Read one image file into a base64 ImageAttachment, dying with a clear error if it's missing. */
|
|
25
|
-
function readImageAttachment(file) {
|
|
26
|
-
if (!fs.existsSync(file) || !fs.statSync(file).isFile()) {
|
|
27
|
-
die(`Image not found: ${file}`);
|
|
28
|
-
}
|
|
29
|
-
const mimeType = imageMimeFromPath(file);
|
|
30
|
-
return { data: fs.readFileSync(file).toString('base64'), mimeType };
|
|
31
|
-
}
|
|
32
|
-
/** Parse a `--skill <id>` value (`id` or `id@version`) into a SkillRef. */
|
|
33
|
-
function parseSkillRef(raw) {
|
|
34
|
-
const at = raw.lastIndexOf('@');
|
|
35
|
-
if (at > 0) {
|
|
36
|
-
return { id: raw.slice(0, at), version: raw.slice(at + 1) };
|
|
37
|
-
}
|
|
38
|
-
return { id: raw };
|
|
39
|
-
}
|
|
40
|
-
/** Print an error message to stderr and exit. */
|
|
41
10
|
/** Return a chalk color function appropriate for the given task status. */
|
|
42
11
|
export function statusColor(status) {
|
|
43
12
|
switch (status) {
|
|
@@ -52,47 +21,6 @@ export function statusColor(status) {
|
|
|
52
21
|
default: return chalk.white;
|
|
53
22
|
}
|
|
54
23
|
}
|
|
55
|
-
/**
|
|
56
|
-
* After a `MissingTargetError`, try to resolve the target interactively.
|
|
57
|
-
* Returns the chosen id, or undefined when no interactive resolution is
|
|
58
|
-
* possible (non-TTY/JSON, provider can't enumerate, or user cancels) — the
|
|
59
|
-
* caller then prints the error's guidance.
|
|
60
|
-
*
|
|
61
|
-
* Codex has no `listTargets` (no list-environments CLI), so it always returns
|
|
62
|
-
* undefined here and the user sees the `codex cloud` guidance. Factory lists
|
|
63
|
-
* Droid Computers; if listing fails (not signed in) or parses to nothing, we
|
|
64
|
-
* fall back to a free-text prompt so a dispatch is never hard-blocked.
|
|
65
|
-
*/
|
|
66
|
-
async function pickMissingTarget(provider, err, json) {
|
|
67
|
-
if (json || !process.stdout.isTTY)
|
|
68
|
-
return undefined;
|
|
69
|
-
if (!provider.listTargets)
|
|
70
|
-
return undefined;
|
|
71
|
-
const { select, input } = await import('@inquirer/prompts');
|
|
72
|
-
const promptName = err.kind === 'env' ? 'environment' : 'computer';
|
|
73
|
-
let targets;
|
|
74
|
-
try {
|
|
75
|
-
targets = await provider.listTargets();
|
|
76
|
-
}
|
|
77
|
-
catch (listErr) {
|
|
78
|
-
process.stderr.write(chalk.dim(`Could not list ${promptName}s: ${listErr.message}\n`));
|
|
79
|
-
targets = [];
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
if (targets.length > 0) {
|
|
83
|
-
return await select({
|
|
84
|
-
message: `Select a ${promptName}`,
|
|
85
|
-
choices: targets.map((t) => ({ value: t.id, name: t.label ? `${t.id} ${chalk.dim(t.label)}` : t.id })),
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
const typed = (await input({ message: `No ${promptName}s found. Enter a ${promptName} name (blank to cancel):` })).trim();
|
|
89
|
-
return typed || undefined;
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
// User hit Ctrl-C / Esc on the prompt.
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
24
|
/** Register the `agents cloud` command tree (run, list, status, logs, cancel, message, providers). */
|
|
97
25
|
export function registerCloudCommands(program) {
|
|
98
26
|
const cloud = program
|
|
@@ -201,23 +129,16 @@ Examples:
|
|
|
201
129
|
|
|
202
130
|
# Default provider (set in ~/.agents/agents.yaml)
|
|
203
131
|
agents cloud run "refactor auth module" --repo user/repo
|
|
132
|
+
|
|
133
|
+
# Same dispatch as a run placement: agents run <agent> "<task>" --cloud
|
|
204
134
|
`)
|
|
205
135
|
.action(async (positionalPrompt, options) => {
|
|
206
136
|
const json = isJsonMode(options);
|
|
207
137
|
// Resolve prompt: --prompt flag, positional arg, or file
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (fs.existsSync(prompt) && fs.statSync(prompt).isFile()) {
|
|
213
|
-
const filePath = prompt;
|
|
214
|
-
const stat = fs.statSync(filePath);
|
|
215
|
-
const sizeKB = (stat.size / 1024).toFixed(1);
|
|
216
|
-
prompt = fs.readFileSync(filePath, 'utf-8').trim();
|
|
217
|
-
if (process.stderr.isTTY) {
|
|
218
|
-
process.stderr.write(chalk.dim(`Reading prompt from ${filePath} (${sizeKB} KB)\n`));
|
|
219
|
-
}
|
|
220
|
-
}
|
|
138
|
+
const prompt = resolveCloudPrompt(options.prompt || positionalPrompt, {
|
|
139
|
+
json,
|
|
140
|
+
hint: 'agents cloud run "<task>" --repo <owner/repo>',
|
|
141
|
+
});
|
|
221
142
|
// --host names one of YOUR machines as the target — that only means
|
|
222
143
|
// something to the host provider, so it implies --provider host rather
|
|
223
144
|
// than silently riding along to a cloud backend that would ignore it.
|
|
@@ -247,9 +168,6 @@ Examples:
|
|
|
247
168
|
model: options.model,
|
|
248
169
|
providerOptions: {},
|
|
249
170
|
};
|
|
250
|
-
const shareEnv = shareRuntimeEnv();
|
|
251
|
-
if (shareEnv)
|
|
252
|
-
dispatchOptions.env = shareEnv;
|
|
253
171
|
if (options.env)
|
|
254
172
|
dispatchOptions.providerOptions.env = options.env;
|
|
255
173
|
if (options.computer)
|
|
@@ -329,101 +247,17 @@ Examples:
|
|
|
329
247
|
}
|
|
330
248
|
return;
|
|
331
249
|
}
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
dispatchOptions.images = imagePaths.map(readImageAttachment);
|
|
345
|
-
}
|
|
346
|
-
if (skillIds.length > 0) {
|
|
347
|
-
if (!caps.skills)
|
|
348
|
-
die(`${provider.name} does not support ride-along skills.`, 1, { json });
|
|
349
|
-
dispatchOptions.skills = skillIds.map(parseSkillRef);
|
|
350
|
-
}
|
|
351
|
-
// Dispatch. On a missing pre-provisioned target (Codex env / Factory
|
|
352
|
-
// computer), offer an interactive picker instead of a raw error.
|
|
353
|
-
const dispatchOnce = async () => {
|
|
354
|
-
const spinner = ora({ text: `Dispatching to ${provider.name}...`, stream: process.stderr }).start();
|
|
355
|
-
try {
|
|
356
|
-
const t = await provider.dispatch(dispatchOptions);
|
|
357
|
-
spinner.succeed(`Task ${t.id} dispatched to ${provider.name}`);
|
|
358
|
-
return t;
|
|
359
|
-
}
|
|
360
|
-
catch (err) {
|
|
361
|
-
spinner.fail('Dispatch failed');
|
|
362
|
-
throw err;
|
|
363
|
-
}
|
|
364
|
-
};
|
|
365
|
-
let task;
|
|
366
|
-
try {
|
|
367
|
-
task = await dispatchOnce();
|
|
368
|
-
}
|
|
369
|
-
catch (err) {
|
|
370
|
-
if (err instanceof MissingTargetError) {
|
|
371
|
-
const picked = await pickMissingTarget(provider, err, json);
|
|
372
|
-
if (!picked) {
|
|
373
|
-
die(err.guidance ? `${err.message}\n\n${err.guidance}` : err.message, 1, { json });
|
|
374
|
-
}
|
|
375
|
-
dispatchOptions.providerOptions[err.kind] = picked;
|
|
376
|
-
try {
|
|
377
|
-
task = await dispatchOnce();
|
|
378
|
-
}
|
|
379
|
-
catch (err2) {
|
|
380
|
-
die(err2.message, 1, { json });
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
else {
|
|
384
|
-
die(err.message, 1, { json });
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
// Persist locally
|
|
388
|
-
insertTask(task);
|
|
389
|
-
emit('cloud.dispatch', { module: 'cloud', taskId: task.id, agent: task.agent, provider: task.provider, status: task.status });
|
|
390
|
-
if (json) {
|
|
391
|
-
process.stdout.write(JSON.stringify(task) + '\n');
|
|
392
|
-
}
|
|
393
|
-
// Stream output unless --no-follow
|
|
394
|
-
if (options.follow === false)
|
|
395
|
-
return;
|
|
396
|
-
try {
|
|
397
|
-
// Live budget kill-switch (issue #399). Reuses makeLiveSpendWatcher to
|
|
398
|
-
// feed the provider's `usage` events into a shared watcher; on a cap
|
|
399
|
-
// breach we call provider.cancel(task.id) mid-stream. Dormant (returns
|
|
400
|
-
// null) when no caps are configured, so the raw stream flows unchanged.
|
|
401
|
-
const { wrapStreamWithBudgetGate } = await import('../lib/budget/live-cloud.js');
|
|
402
|
-
const gated = wrapStreamWithBudgetGate({
|
|
403
|
-
provider,
|
|
404
|
-
taskId: task.id,
|
|
405
|
-
project: task.repo ?? task.repos?.[0] ?? process.cwd(),
|
|
406
|
-
agent: task.agent ?? 'cloud',
|
|
407
|
-
cwd: process.cwd(),
|
|
408
|
-
});
|
|
409
|
-
const eventSource = gated ? gated.wrap(provider.stream(task.id)) : provider.stream(task.id);
|
|
410
|
-
const result = await renderStream(eventSource, { json });
|
|
411
|
-
updateTaskStatus(task.id, result.status, {
|
|
412
|
-
summary: result.summary,
|
|
413
|
-
prUrl: result.prUrl,
|
|
414
|
-
});
|
|
415
|
-
emit('cloud.complete', { module: 'cloud', taskId: task.id, status: result.status, prUrl: result.prUrl });
|
|
416
|
-
if (gated?.gate.breached()) {
|
|
417
|
-
const b = gated.gate.breach();
|
|
418
|
-
process.stderr.write(`[budget] cap ${b?.cap} exceeded — cancelled cloud task ${task.id}\n`);
|
|
419
|
-
process.exitCode = 7; // Mirrors BUDGET_KILL_EXIT_CODE for CI/headless.
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
catch (err) {
|
|
423
|
-
// Stream disconnect is OK — task keeps running
|
|
424
|
-
process.stderr.write(chalk.dim(`\nStream disconnected. Task ${task.id} continues running.\n`));
|
|
425
|
-
process.stderr.write(chalk.dim(`Check status: agents cloud status ${task.id}\n`));
|
|
426
|
-
}
|
|
250
|
+
// One dispatch path for every cloud surface — lib/cloud/dispatch.ts owns
|
|
251
|
+
// capability checks, the missing-target picker, persistence, streaming,
|
|
252
|
+
// and the budget kill-switch.
|
|
253
|
+
await executeCloudDispatch({
|
|
254
|
+
provider,
|
|
255
|
+
dispatchOptions,
|
|
256
|
+
imagePaths: Array.isArray(options.image) ? options.image : [],
|
|
257
|
+
skillIds: Array.isArray(options.skill) ? options.skill : [],
|
|
258
|
+
follow: options.follow !== false,
|
|
259
|
+
json,
|
|
260
|
+
});
|
|
427
261
|
});
|
|
428
262
|
// ── agents cloud list ─────────────────────────────────────────────────
|
|
429
263
|
cloud
|
package/dist/commands/doctor.js
CHANGED
|
@@ -18,7 +18,8 @@ import { findAmbiguousDevicePins } from '../lib/routines.js';
|
|
|
18
18
|
import chalk from 'chalk';
|
|
19
19
|
import { checkAllClis, collectTeamsDoctorData } from '../lib/teams/agents.js';
|
|
20
20
|
import { AGENTS, ALL_AGENT_IDS, resolveAgentName, formatAgentError, getAccountInfo } from '../lib/agents.js';
|
|
21
|
-
import {
|
|
21
|
+
import { getVersionHomePath, listInstalledVersions, } from '../lib/versions.js';
|
|
22
|
+
import { resolveAgentTargets, AgentSpecError } from '../lib/agent-spec/index.js';
|
|
22
23
|
import { loadManifest, isStale } from '../lib/staleness/index.js';
|
|
23
24
|
import { diffVersionResources, DOCTOR_ALL_KINDS, } from '../lib/doctor-diff.js';
|
|
24
25
|
import { checkVersionHookWiring, inspectDuplicateVersionHooks, registerHooksToSettings } from '../lib/hooks.js';
|
|
@@ -370,29 +371,30 @@ async function runDevicesDoctor(opts) {
|
|
|
370
371
|
function parseTargetArg(arg) {
|
|
371
372
|
const at = arg.indexOf('@');
|
|
372
373
|
const agentPart = at === -1 ? arg : arg.slice(0, at);
|
|
373
|
-
const
|
|
374
|
+
const qualifier = at === -1 ? '' : arg.slice(at + 1);
|
|
374
375
|
const agent = resolveAgentName(agentPart);
|
|
375
376
|
if (!agent)
|
|
376
377
|
return { error: formatAgentError(agentPart) };
|
|
377
|
-
|
|
378
|
+
// No qualifier → non-isolated sweep of every installed version; --fix uses the non-isolated path
|
|
379
|
+
if (!qualifier) {
|
|
378
380
|
const versions = listInstalledVersions(agent);
|
|
379
381
|
if (versions.length === 0)
|
|
380
382
|
return { error: `${AGENTS[agent].name} has no installed versions. Run \`agents add ${agent}@<version>\` first.` };
|
|
381
383
|
return { agent, versions, versionExplicit: false };
|
|
382
384
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
// All explicit qualifiers (@all, @latest, @oldest, @default, @pinned, @x.y.z) → shared resolver
|
|
386
|
+
try {
|
|
387
|
+
const targets = resolveAgentTargets(`${agent}@${qualifier}`, { availableAgents: [agent] });
|
|
388
|
+
const versions = targets.map((t) => t.version).filter((v) => v !== null);
|
|
389
|
+
if (versions.length === 0)
|
|
390
|
+
return { error: `${AGENTS[agent].name} has no installed versions. Run \`agents add ${agent}@<version>\` first.` };
|
|
391
|
+
return { agent, versions, versionExplicit: true };
|
|
388
392
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return { error: `${AGENTS[agent].name}@${versionPart} is not installed. Installed: ${listInstalledVersions(agent).join(', ') || '(none)'}` };
|
|
393
|
+
catch (e) {
|
|
394
|
+
if (e instanceof AgentSpecError)
|
|
395
|
+
return { error: e.message };
|
|
396
|
+
throw e;
|
|
394
397
|
}
|
|
395
|
-
return { agent, versions: [versionPart], versionExplicit: true };
|
|
396
398
|
}
|
|
397
399
|
function parseKindFilter(arg) {
|
|
398
400
|
if (!arg)
|
package/dist/commands/exec.js
CHANGED
|
@@ -553,7 +553,7 @@ export function registerRunCommand(program) {
|
|
|
553
553
|
.option('--budget <tokens>', 'Loop token hard-cap: stop once cumulative tokens reach this (stoppedBy: budget), enforced outside the agent. Loop only.')
|
|
554
554
|
.option('--until <signal>', 'Loop stop condition. `signal` reads <runDir>/loop-signal.json {continue,reason} each iteration; absent or continue:false stops (fail-closed). Loop only.')
|
|
555
555
|
.option('--interval <dur>', 'Loop delay between iterations ("0" back-to-back, "30m" paces). Loop only.')
|
|
556
|
-
.option('--where <spec>', 'Where this run\'s body executes (one placement door): local | device:<name> | auto | lease[:backend]. Expands to --host/--lease. Do not combine with those flags. See docs/00-concepts.md#placement.')
|
|
556
|
+
.option('--where <spec>', 'Where this run\'s body executes (one placement door): local | device:<name> | auto | lease[:backend] | cloud[:provider]. Expands to --host/--lease/--cloud. Do not combine with those flags. See docs/00-concepts.md#placement.')
|
|
557
557
|
.option('--host <name>', 'Offload this run onto another machine over SSH — a device name, registered host, or user@host. Pass "auto" to pick from 14d usage affinity (most-used online device has highest probability). Same as --where device:<name>. See `agents devices`.')
|
|
558
558
|
.option('--device <name>', 'Alias of --host. Pass "auto" for affinity-based device pick (same as --where auto).')
|
|
559
559
|
.option('--remote-cwd <dir>', "Explicit host working directory for --host runs, used VERBATIM (overrides --cwd; usually --cwd suffices — it re-roots a local-home path onto the remote home). Pass a single-quoted '$HOME/…' or a valid remote absolute path; a local ~ expands here and won't exist there (/Users/you vs /home/you).")
|
|
@@ -567,7 +567,12 @@ export function registerRunCommand(program) {
|
|
|
567
567
|
.option('--reuse', 'With --lease, reuse the most-recently-used warm box if one exists (else provision fresh). The scriptable form of the interactive reuse picker.')
|
|
568
568
|
.option('--bare', 'With --lease, skip copying your local ~/.agents setup (skills/hooks/commands/MCP) onto the box.')
|
|
569
569
|
.option('--tailscale', 'Lease the box onto your tailnet (reachable only over Tailscale) rather than a public IP.')
|
|
570
|
-
.option('--no-tailscale', 'Force a public-IP lease even when a reuse context would default to Tailscale.')
|
|
570
|
+
.option('--no-tailscale', 'Force a public-IP lease even when a reuse context would default to Tailscale.')
|
|
571
|
+
.option('--cloud', 'Vendor cloud placement: dispatch to the agent\'s native cloud (claude→rush, codex→codex, droid→factory, antigravity→antigravity) and stream the result. Same dispatch as `agents cloud run --agent <agent>`; tracked by `agents cloud list/status/logs`. Same as --where cloud. Mutually exclusive with --host/--lease and local-run flags.')
|
|
572
|
+
.option('--provider <id>', 'With --cloud: override the agent\'s native cloud provider (rush | codex | factory | antigravity | host).')
|
|
573
|
+
.option('--repo <owner/repo>', 'With --cloud: GitHub repository. Repeatable for multi-repo dispatch (Rush Cloud only).', (val, prev) => [...prev, val], [])
|
|
574
|
+
.option('--branch <name>', 'With --cloud: target git branch.')
|
|
575
|
+
.option('--cloud-env <id>', 'With --cloud: Codex Cloud environment ID (run\'s --env is the KEY=VAL passthrough, so the cloud env id gets its own flag).');
|
|
571
576
|
// `--on` and `--computer` are hidden aliases of `--host` — same behavior.
|
|
572
577
|
runCmd.addOption(new Option('--on <name>', 'Alias of --host.').hideHelp());
|
|
573
578
|
runCmd.addOption(new Option('--computer <name>', 'Alias of --host.').hideHelp());
|
|
@@ -608,6 +613,13 @@ export function registerRunCommand(program) {
|
|
|
608
613
|
agents run claude "…" --where auto # = --device auto
|
|
609
614
|
agents run claude "fix CI" --where lease --mode edit
|
|
610
615
|
|
|
616
|
+
# Vendor cloud placement — the agent's own cloud runs the task and
|
|
617
|
+
# agents cloud list/status/logs tracks it. Fire-and-forget: --no-follow
|
|
618
|
+
agents run claude "fix the flaky e2e" --cloud --repo acme/example
|
|
619
|
+
agents run codex "add parser tests" --cloud --cloud-env env_a1b2c3
|
|
620
|
+
agents run droid "QA the onboarding flow" --cloud --no-follow
|
|
621
|
+
agents run claude "…" --where cloud # same as --cloud
|
|
622
|
+
|
|
611
623
|
# Open the session in a terminal tab — detected from where your sessions
|
|
612
624
|
# already run (Ghostty / iTerm / Terminal.app); force one with a value
|
|
613
625
|
agents run claude --terminal
|
|
@@ -668,6 +680,15 @@ export function registerRunCommand(program) {
|
|
|
668
680
|
|
|
669
681
|
Fallback: --fallback codex,antigravity retries on rate-limit failure via /continue handoff. Each entry accepts @version.
|
|
670
682
|
|
|
683
|
+
Cloud placement: --cloud sends the run to the agent's native vendor cloud
|
|
684
|
+
(claude→rush, codex→codex, droid→factory, antigravity→antigravity) — the
|
|
685
|
+
same dispatch as agents cloud run --agent <agent>, tracked by agents
|
|
686
|
+
cloud list/status/logs/cancel/message. --provider overrides the routing;
|
|
687
|
+
--repo/--branch/--cloud-env refine the task. Agents without a native
|
|
688
|
+
cloud (kimi, grok, cursor, opencode, …) fail loud unless --provider is
|
|
689
|
+
given. --cloud is mutually exclusive with --host/--lease and with
|
|
690
|
+
local-run flags (--loop, --resume, --secrets, --terminal, …).
|
|
691
|
+
|
|
671
692
|
Resume: --resume <id> resolves full IDs locally first, then fleet-wide, and restores the source version/device/mode. Claude, Codex, Grok, Kimi, Droid, and Cursor use version-gated native resume; others replay via /continue. agents resume <id> infers the harness too.
|
|
672
693
|
|
|
673
694
|
Passthrough: everything after -- is forwarded verbatim to the underlying agent CLI.
|
|
@@ -694,6 +715,17 @@ export function registerRunCommand(program) {
|
|
|
694
715
|
// a native flag, not a prompt. Run interactively.
|
|
695
716
|
prompt = undefined;
|
|
696
717
|
}
|
|
718
|
+
// --cloud: vendor cloud placement. Validate BEFORE the terminal handoff
|
|
719
|
+
// and every local dispatch path — flags like --terminal/--loop/--resume
|
|
720
|
+
// belong to the local runner and must error, never ride along silently.
|
|
721
|
+
if (options.cloud || (typeof options.where === 'string' && /^cloud(:|$)/i.test(options.where.trim()))) {
|
|
722
|
+
const { runCloudConflicts } = await import('./run-cloud.js');
|
|
723
|
+
const conflicts = runCloudConflicts(options);
|
|
724
|
+
if (conflicts.length > 0) {
|
|
725
|
+
console.error(chalk.red(`--cloud is a vendor cloud placement; these only apply to local/machine runs: ${conflicts.join(', ')}. Drop them, or drop --cloud.`));
|
|
726
|
+
process.exit(1);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
697
729
|
// --terminal: this process can't host the TUI (a menu-bar click, a script),
|
|
698
730
|
// so hand the run to a real terminal and exit. Resolved from the user's own
|
|
699
731
|
// live sessions, so it opens where they already work. Done before every
|
|
@@ -703,9 +735,9 @@ export function registerRunCommand(program) {
|
|
|
703
735
|
await handleTerminalHandoff(agentSpec, options, prompt);
|
|
704
736
|
return;
|
|
705
737
|
}
|
|
706
|
-
// Placement: --where expands into --host / --lease before any
|
|
707
|
-
// One door for "where does the body run?" — old flags remain
|
|
708
|
-
// See lib/placement.ts and docs/00-concepts.md#placement.
|
|
738
|
+
// Placement: --where expands into --host / --lease / --cloud before any
|
|
739
|
+
// dispatch. One door for "where does the body run?" — old flags remain
|
|
740
|
+
// aliases. See lib/placement.ts and docs/00-concepts.md#placement.
|
|
709
741
|
{
|
|
710
742
|
const { placementFromRunFlags, expandPlacementToRunFlags, PlacementError } = await import('../lib/placement.js');
|
|
711
743
|
try {
|
|
@@ -720,6 +752,10 @@ export function registerRunCommand(program) {
|
|
|
720
752
|
options.lease = expanded.lease;
|
|
721
753
|
if (expanded.box !== undefined)
|
|
722
754
|
options.box = expanded.box;
|
|
755
|
+
if (expanded.cloud !== undefined)
|
|
756
|
+
options.cloud = expanded.cloud;
|
|
757
|
+
if (expanded.provider !== undefined)
|
|
758
|
+
options.provider = expanded.provider;
|
|
723
759
|
// Clear the where flag so remote re-entry (host dispatch) does not
|
|
724
760
|
// re-expand and conflict with the concrete host we just set.
|
|
725
761
|
options.where = undefined;
|
|
@@ -733,6 +769,22 @@ export function registerRunCommand(program) {
|
|
|
733
769
|
throw err;
|
|
734
770
|
}
|
|
735
771
|
}
|
|
772
|
+
// Cloud refinement flags without the placement are a typo, not a no-op.
|
|
773
|
+
if (!options.cloud) {
|
|
774
|
+
const { cloudFlagsWithoutCloud } = await import('./run-cloud.js');
|
|
775
|
+
const stray = cloudFlagsWithoutCloud(options);
|
|
776
|
+
if (stray.length > 0) {
|
|
777
|
+
console.error(chalk.red(`${stray.join(', ')} ${stray.length > 1 ? 'require' : 'requires'} --cloud (vendor cloud placement).`));
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
// --cloud: dispatch through the cloud provider registry and return — the
|
|
782
|
+
// run never touches the local/host/lease paths below.
|
|
783
|
+
if (options.cloud) {
|
|
784
|
+
const { handleRunCloud } = await import('./run-cloud.js');
|
|
785
|
+
await handleRunCloud(agentSpec, prompt, options, command);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
736
788
|
// --notify: post a desktop notification when this run finishes. Armed on
|
|
737
789
|
// process exit so it covers EVERY dispatch path below (local, --host,
|
|
738
790
|
// --lease, the error path) instead of one branch. Only for headless runs
|
package/dist/commands/feed.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { type OpenBlock } from '../lib/feed.js';
|
|
|
20
20
|
import { type OutcomeGroup, type SessionOutcomeHint } from '../lib/feed-outcome.js';
|
|
21
21
|
import { filterBlocksForFeed } from '../lib/ask-classifier.js';
|
|
22
22
|
import { type FeedSessionSignal } from '../lib/feed-ranking.js';
|
|
23
|
+
export declare const FEED_POST_HELP = "\nExamples:\n # Title (subject) + body. Phone broadcasts put title first, body after a\n # blank line, then a \"Sent from agent/session on host\" footer.\n agents feed post --title \"CHANGELOG pushed\" \"Watching CI and mac-mini E2E\"\n agents feed post --title \"Cover ready\" \"render at ./out/cover.png\" --attach ./out/cover.png\n agents feed post --title \"Ready for review\" \"PR opened, waiting on prix-cloud\" --json\n\n # Worth interrupting someone over - reaches sinks gated on minLevel: important:\n agents feed post --title \"npm token expired\" \"Cannot publish the release\" --level important\n\n # Stuck: opens a needs-you block and always broadcasts at important:\n agents feed post --title \"Force-push denied\" \"git-guard blocked PR #1749\" --blocked\n agents feed post --title \"Publish or wait?\" \"npm publish now or after review\" --blocked --option publish --option wait\n agents feed post --title \"Delete preview env?\" \"stale preview still running\" --blocked --default \"leave it\"\n\n # Exhaust self-serve FIRST. A block is for what you genuinely cannot do:\n # a credential only the user holds, a decision only they can make, an\n # approval only they can give. Not \"should I do the obvious next step?\".\n\n # Outside a run, pass the session explicitly:\n agents feed post --title \"Manual note\" \"context for the next agent\" --session 00998b0e-2d15-4d2f-a58b-974a886c9b47\n\nIdentity (session, agent, host, runtime, pid, launchId) is stamped automatically\nand rides the phone footer of feed.broadcast {message}. Domain facts (tickets,\nPRs) are not CLI flags - the ticket is joined from the session index at post\ntime. No em-dashes in title/body - they are scrubbed on the way out.\n\nConfigure where a post is mirrored under feed.broadcast in agents.yaml - see\ndocs/06-observability.md. A milestone is always recorded, but it does not text\nthe owner when the sink has minLevel: important. Add --level important for a\nphone-worthy successful update. Use --blocked only when work cannot continue.\nThe owner destination comes from humans.yaml; do not duplicate it in agents.yaml.\n";
|
|
23
24
|
export declare const FEED_NO_FANOUT_ENV = "AGENTS_FEED_LOCAL";
|
|
24
25
|
/** Right-hand masthead summary: `N blocks · M agents`. */
|
|
25
26
|
export declare function formatFeedMastheadRight(blocks: OpenBlock[]): string;
|
package/dist/commands/feed.js
CHANGED
|
@@ -21,6 +21,40 @@ import { GLYPH, masthead } from '../lib/comms-render.js';
|
|
|
21
21
|
import { discoverSessions } from '../lib/session/discover.js';
|
|
22
22
|
import { resolveProvider } from '../lib/cloud/registry.js';
|
|
23
23
|
import { buildSessionSignals, rankFeedBlocks, synthesizeControlCards, } from '../lib/feed-ranking.js';
|
|
24
|
+
export const FEED_POST_HELP = `
|
|
25
|
+
Examples:
|
|
26
|
+
# Title (subject) + body. Phone broadcasts put title first, body after a
|
|
27
|
+
# blank line, then a "Sent from agent/session on host" footer.
|
|
28
|
+
agents feed post --title "CHANGELOG pushed" "Watching CI and mac-mini E2E"
|
|
29
|
+
agents feed post --title "Cover ready" "render at ./out/cover.png" --attach ./out/cover.png
|
|
30
|
+
agents feed post --title "Ready for review" "PR opened, waiting on prix-cloud" --json
|
|
31
|
+
|
|
32
|
+
# Worth interrupting someone over - reaches sinks gated on minLevel: important:
|
|
33
|
+
agents feed post --title "npm token expired" "Cannot publish the release" --level important
|
|
34
|
+
|
|
35
|
+
# Stuck: opens a needs-you block and always broadcasts at important:
|
|
36
|
+
agents feed post --title "Force-push denied" "git-guard blocked PR #1749" --blocked
|
|
37
|
+
agents feed post --title "Publish or wait?" "npm publish now or after review" --blocked --option publish --option wait
|
|
38
|
+
agents feed post --title "Delete preview env?" "stale preview still running" --blocked --default "leave it"
|
|
39
|
+
|
|
40
|
+
# Exhaust self-serve FIRST. A block is for what you genuinely cannot do:
|
|
41
|
+
# a credential only the user holds, a decision only they can make, an
|
|
42
|
+
# approval only they can give. Not "should I do the obvious next step?".
|
|
43
|
+
|
|
44
|
+
# Outside a run, pass the session explicitly:
|
|
45
|
+
agents feed post --title "Manual note" "context for the next agent" --session 00998b0e-2d15-4d2f-a58b-974a886c9b47
|
|
46
|
+
|
|
47
|
+
Identity (session, agent, host, runtime, pid, launchId) is stamped automatically
|
|
48
|
+
and rides the phone footer of feed.broadcast {message}. Domain facts (tickets,
|
|
49
|
+
PRs) are not CLI flags - the ticket is joined from the session index at post
|
|
50
|
+
time. No em-dashes in title/body - they are scrubbed on the way out.
|
|
51
|
+
|
|
52
|
+
Configure where a post is mirrored under feed.broadcast in agents.yaml - see
|
|
53
|
+
docs/06-observability.md. A milestone is always recorded, but it does not text
|
|
54
|
+
the owner when the sink has minLevel: important. Add --level important for a
|
|
55
|
+
phone-worthy successful update. Use --blocked only when work cannot continue.
|
|
56
|
+
The owner destination comes from humans.yaml; do not duplicate it in agents.yaml.
|
|
57
|
+
`;
|
|
24
58
|
export const FEED_NO_FANOUT_ENV = 'AGENTS_FEED_LOCAL';
|
|
25
59
|
/** Right-hand masthead summary: `N blocks · M agents`. */
|
|
26
60
|
export function formatFeedMastheadRight(blocks) {
|
|
@@ -239,44 +273,14 @@ export function registerFeedCommand(program) {
|
|
|
239
273
|
.description('Post a status update to the fleet activity stream (for agents)')
|
|
240
274
|
.argument('<text...>', 'Body: what just happened (after --title)')
|
|
241
275
|
.requiredOption('--title <title>', 'Short subject, ~4-5 words (phone first line)')
|
|
242
|
-
.option('--session <id>', 'Session id escape hatch (default: auto from env / pid registry)')
|
|
276
|
+
.option('--session <id>', 'Session id escape hatch (default: auto from env / launch activity / pid registry)')
|
|
243
277
|
.option('--attach <path-or-url...>', 'Attach an artifact (local file or URL); repeatable')
|
|
244
278
|
.option('--level <level>', 'How loudly to broadcast: milestone (default) or important. Configured sinks with minLevel: important only fire on the latter.', 'milestone')
|
|
245
279
|
.option('--blocked', 'You are STUCK and need the user. Opens an answerable block and always broadcasts at important - do not also pass --level.')
|
|
246
280
|
.option('--option <label...>', 'With --blocked: an answer the user can pick; repeatable')
|
|
247
281
|
.option('--default <answer>', 'With --blocked: a safe default policy may apply if nobody answers in time')
|
|
248
282
|
.option('--json', 'Emit the written event as JSON')
|
|
249
|
-
.addHelpText('after',
|
|
250
|
-
Examples:
|
|
251
|
-
# Title (subject) + body. Phone broadcasts put title first, body after a
|
|
252
|
-
# blank line, then a "Sent from agent/session on host" footer.
|
|
253
|
-
agents feed post --title "CHANGELOG pushed" "Watching CI and mac-mini E2E"
|
|
254
|
-
agents feed post --title "Cover ready" "render at ./out/cover.png" --attach ./out/cover.png
|
|
255
|
-
agents feed post --title "Ready for review" "PR opened, waiting on prix-cloud" --json
|
|
256
|
-
|
|
257
|
-
# Worth interrupting someone over - reaches sinks gated on minLevel: important:
|
|
258
|
-
agents feed post --title "npm token expired" "Cannot publish the release" --level important
|
|
259
|
-
|
|
260
|
-
# Stuck: opens a needs-you block and always broadcasts at important:
|
|
261
|
-
agents feed post --title "Force-push denied" "git-guard blocked PR #1749" --blocked
|
|
262
|
-
agents feed post --title "Publish or wait?" "npm publish now or after review" --blocked --option publish --option wait
|
|
263
|
-
agents feed post --title "Delete preview env?" "stale preview still running" --blocked --default "leave it"
|
|
264
|
-
|
|
265
|
-
# Exhaust self-serve FIRST. A block is for what you genuinely cannot do:
|
|
266
|
-
# a credential only the user holds, a decision only they can make, an
|
|
267
|
-
# approval only they can give. Not "should I do the obvious next step?".
|
|
268
|
-
|
|
269
|
-
# Outside a run, pass the session explicitly:
|
|
270
|
-
agents feed post --title "Manual note" "context for the next agent" --session 00998b0e-2d15-4d2f-a58b-974a886c9b47
|
|
271
|
-
|
|
272
|
-
Identity (session, agent, host, runtime, pid, launchId) is stamped automatically
|
|
273
|
-
and rides the phone footer of feed.broadcast {message}. Domain facts (tickets,
|
|
274
|
-
PRs) are not CLI flags - the ticket is joined from the session index at post
|
|
275
|
-
time. No em-dashes in title/body - they are scrubbed on the way out.
|
|
276
|
-
|
|
277
|
-
Configure where a post is mirrored under feed.broadcast in agents.yaml - see
|
|
278
|
-
docs/06-observability.md.
|
|
279
|
-
`)
|
|
283
|
+
.addHelpText('after', FEED_POST_HELP)
|
|
280
284
|
.action(async (textParts, opts, cmd) => {
|
|
281
285
|
// Parent `feed` also declares `--json` (for the list view). Commander
|
|
282
286
|
// binds the flag on the parent, so a `feed post … --json` lands on
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import type { CloudProvider } from '../lib/cloud/types.js';
|
|
3
|
+
/** Error type for run --cloud validation failures (exit 1, red message). */
|
|
4
|
+
export declare class RunCloudError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/** Flags the user passed that cannot ride a cloud placement. */
|
|
8
|
+
export declare function runCloudConflicts(options: Record<string, unknown>): string[];
|
|
9
|
+
/** Cloud-only flags passed without the --cloud placement. */
|
|
10
|
+
export declare function cloudFlagsWithoutCloud(options: Record<string, unknown>): string[];
|
|
11
|
+
/** Agents that route to a native cloud provider (the registry's truth). */
|
|
12
|
+
export declare function cloudCapableAgentIds(): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the cloud provider for a run: explicit --provider wins, else the
|
|
15
|
+
* agent's native cloud. An agent with no native cloud fails loud with the
|
|
16
|
+
* capable list — never a silent ride onto the configured default.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveRunCloudProvider(agentId: string, explicitProvider?: string): CloudProvider;
|
|
19
|
+
/** Validate the agent half of `agents run <agent> --cloud` and return the registry id. */
|
|
20
|
+
export declare function resolveRunCloudAgent(agentSpec: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Handle `agents run <agent> [prompt] --cloud`. Validation lives in the
|
|
23
|
+
* exported helpers above (unit-tested); this wires them to the shared
|
|
24
|
+
* dispatch core and dies on any validation failure.
|
|
25
|
+
*/
|
|
26
|
+
export declare function handleRunCloud(agentSpec: string, prompt: string | undefined, options: Record<string, unknown>, command: Command): Promise<void>;
|