@phnx-labs/agents-cli 1.22.25 → 1.22.26
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 +183 -0
- package/README.md +17 -2
- package/dist/bin/agents +0 -0
- package/dist/browser.js +14 -4
- package/dist/commands/apply.js +52 -8
- package/dist/commands/browser.js +35 -0
- package/dist/commands/doctor.js +8 -0
- package/dist/commands/insights.d.ts +25 -19
- package/dist/commands/insights.js +107 -33
- package/dist/commands/reconnect.d.ts +46 -0
- package/dist/commands/reconnect.js +109 -0
- package/dist/commands/routines.js +2 -2
- package/dist/commands/secrets.d.ts +2 -8
- package/dist/commands/secrets.js +29 -105
- package/dist/commands/sessions.js +4 -0
- package/dist/commands/setup-secrets.d.ts +1 -0
- package/dist/commands/setup-secrets.js +1 -1
- package/dist/commands/setup.d.ts +26 -3
- package/dist/commands/setup.js +105 -46
- package/dist/commands/teams.d.ts +6 -0
- package/dist/commands/teams.js +43 -0
- package/dist/commands/trends.d.ts +8 -0
- package/dist/commands/trends.js +10 -156
- package/dist/index.js +1 -1
- package/dist/lib/agents.d.ts +11 -0
- package/dist/lib/agents.js +29 -2
- package/dist/lib/analytics/dashboard.d.ts +10 -6
- package/dist/lib/analytics/dashboard.js +6 -4
- package/dist/lib/analytics/mix-commands.d.ts +53 -0
- package/dist/lib/analytics/mix-commands.js +229 -0
- package/dist/lib/analytics/recipes.d.ts +19 -14
- package/dist/lib/analytics/recipes.js +4 -2
- package/dist/lib/browser/ipc.d.ts +26 -0
- package/dist/lib/browser/ipc.js +139 -24
- package/dist/lib/browser/profiles.d.ts +11 -0
- package/dist/lib/browser/profiles.js +1 -1
- package/dist/lib/browser/stream.d.ts +14 -0
- package/dist/lib/browser/stream.js +71 -0
- package/dist/lib/channels/owner-sink.d.ts +27 -0
- package/dist/lib/channels/owner-sink.js +93 -0
- package/dist/lib/devices/doctor-findings.d.ts +7 -1
- package/dist/lib/devices/doctor-findings.js +33 -1
- package/dist/lib/fleet/apply.d.ts +59 -3
- package/dist/lib/fleet/apply.js +183 -6
- package/dist/lib/fleet/types.d.ts +21 -2
- package/dist/lib/hooks/cache.js +15 -0
- package/dist/lib/hosts/passthrough.d.ts +23 -0
- package/dist/lib/hosts/passthrough.js +45 -0
- package/dist/lib/hosts/ready.d.ts +2 -0
- package/dist/lib/hosts/ready.js +10 -1
- package/dist/lib/hosts/reconnect.d.ts +14 -12
- package/dist/lib/hosts/reconnect.js +41 -40
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/routines.js +14 -2
- package/dist/lib/runner.d.ts +0 -3
- package/dist/lib/runner.js +1 -14
- 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/secrets/push.d.ts +94 -0
- package/dist/lib/secrets/push.js +145 -0
- package/dist/lib/secrets/reaper.d.ts +15 -1
- package/dist/lib/secrets/reaper.js +30 -3
- package/dist/lib/session/db.d.ts +21 -3
- package/dist/lib/session/db.js +221 -13
- package/dist/lib/session/discover.d.ts +1 -0
- package/dist/lib/session/discover.js +115 -19
- package/dist/lib/session/insights.d.ts +18 -0
- package/dist/lib/session/insights.js +143 -1
- package/dist/lib/session/tool-index.js +133 -22
- package/dist/lib/session/tool-store.d.ts +26 -2
- package/dist/lib/session/tool-store.js +36 -17
- package/dist/lib/ssh-exec.js +8 -2
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +4 -0
- package/dist/lib/teams/agents.d.ts +13 -0
- package/dist/lib/teams/agents.js +75 -7
- package/dist/lib/teams/placement-probe.d.ts +21 -0
- package/dist/lib/teams/placement-probe.js +135 -0
- package/dist/lib/teams/scheduler.d.ts +74 -1
- package/dist/lib/teams/scheduler.js +187 -10
- package/package.json +1 -1
|
@@ -57,6 +57,7 @@ import { registerSessionsFavoriteCommand } from './sessions-favorite.js';
|
|
|
57
57
|
import { isFavorite, listFavorites } from '../lib/session/favorites.js';
|
|
58
58
|
import { registerGoCommand } from './go.js';
|
|
59
59
|
import { registerFocusCommand } from './focus.js';
|
|
60
|
+
import { registerReconnectCommand } from './reconnect.js';
|
|
60
61
|
import { registerDetachCommand } from './detach.js';
|
|
61
62
|
import { registerAttachCommand } from './attach.js';
|
|
62
63
|
import { registerSessionsInjectCommand } from './sessions-inject.js';
|
|
@@ -66,6 +67,7 @@ import { registerSessionsImportCommand } from './sessions-import.js';
|
|
|
66
67
|
import { registerSessionsMigrateCommand, registerSessionsMigrationsCommand } from './sessions-migrate.js';
|
|
67
68
|
import { registerSessionsBackfillCommand } from './sessions-backfill.js';
|
|
68
69
|
import { registerSessionsStatsCommand } from './sessions-stats.js';
|
|
70
|
+
import { registerSessionsInsightsCommand } from './insights.js';
|
|
69
71
|
import { registerSessionsOptimizeCommand } from './sessions-optimize.js';
|
|
70
72
|
import { runBrowserSessions } from '../lib/browser/sessions-list.js';
|
|
71
73
|
import { countToolProgramOccurrences, parseToolProgramCountClause, readToolIndexCoverage, searchToolCalls, TOOL_QUERY_MAX_CLAUSE_BYTES, TOOL_QUERY_MAX_CLAUSES, TOOL_QUERY_MAX_RESULT_SESSIONS, serializeToolSearchEnvelope, toolSearchRemoteReceiveBudget, } from '../lib/session/tool-index.js';
|
|
@@ -4082,6 +4084,7 @@ export function registerSessionsCommands(program) {
|
|
|
4082
4084
|
registerSessionsFavoriteCommand(sessionsCmd);
|
|
4083
4085
|
registerGoCommand(sessionsCmd);
|
|
4084
4086
|
registerFocusCommand(sessionsCmd);
|
|
4087
|
+
registerReconnectCommand(sessionsCmd);
|
|
4085
4088
|
registerDetachCommand(sessionsCmd);
|
|
4086
4089
|
registerAttachCommand(sessionsCmd);
|
|
4087
4090
|
registerSessionsInjectCommand(sessionsCmd);
|
|
@@ -4092,6 +4095,7 @@ export function registerSessionsCommands(program) {
|
|
|
4092
4095
|
registerSessionsMigrationsCommand(sessionsCmd);
|
|
4093
4096
|
registerSessionsBackfillCommand(sessionsCmd);
|
|
4094
4097
|
registerSessionsStatsCommand(sessionsCmd);
|
|
4098
|
+
registerSessionsInsightsCommand(sessionsCmd);
|
|
4095
4099
|
registerSessionsOptimizeCommand(sessionsCmd);
|
|
4096
4100
|
// Observe-umbrella alias (Phase 3): roster → sessions --active.
|
|
4097
4101
|
registerSessionsObserveAliases(program);
|
|
@@ -15,6 +15,7 @@ interface SetupSecretsOptions {
|
|
|
15
15
|
iUnderstand?: boolean;
|
|
16
16
|
force?: boolean;
|
|
17
17
|
}
|
|
18
|
+
export declare function setupSecretsPrefsPath(): string;
|
|
18
19
|
/** The wizard's `--policy` shares the canonical parser with `agents secrets
|
|
19
20
|
* policy`, so it accepts `hold` (and the `daily`/`session` aliases) rather than
|
|
20
21
|
* carrying its own copy that knows only the retired vocabulary. `parsePolicyOpt`
|
|
@@ -15,7 +15,7 @@ import { parsePolicyOpt } from './secrets.js';
|
|
|
15
15
|
function defaultBackendForPlatform(platform = process.platform) {
|
|
16
16
|
return platform === 'darwin' ? 'keychain' : 'file';
|
|
17
17
|
}
|
|
18
|
-
function setupSecretsPrefsPath() {
|
|
18
|
+
export function setupSecretsPrefsPath() {
|
|
19
19
|
return path.join(getHistoryDir(), 'setup', 'secrets.json');
|
|
20
20
|
}
|
|
21
21
|
function parseBackend(raw) {
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
* ~/.agents/.system/ and installs agent CLIs with resource syncing.
|
|
6
6
|
*/
|
|
7
7
|
import type { Command } from 'commander';
|
|
8
|
-
|
|
9
|
-
export declare function runSetup(program: Command, options?: {
|
|
8
|
+
interface RunSetupOptions {
|
|
10
9
|
force?: boolean;
|
|
11
10
|
suppressFooter?: boolean;
|
|
12
11
|
systemRepo?: boolean;
|
|
13
|
-
|
|
12
|
+
runHub?: () => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/** First-run setup. Clones ~/.agents/.system/ from the system repo if needed. */
|
|
15
|
+
export declare function runSetup(program: Command, options?: RunSetupOptions): Promise<void>;
|
|
14
16
|
/**
|
|
15
17
|
* Ensure the system repo exists before running a command that needs it.
|
|
16
18
|
* If ~/.agents/.system/ is not a git repo AND we're in an interactive TTY,
|
|
@@ -18,5 +20,26 @@ export declare function runSetup(program: Command, options?: {
|
|
|
18
20
|
* error and exit.
|
|
19
21
|
*/
|
|
20
22
|
export declare function ensureInitialized(program: Command): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Interactive "what else do you want to set up?" menu shown after the bare
|
|
25
|
+
* `agents setup` finishes on a TTY. Each pick runs that capability's guided
|
|
26
|
+
* wizard. Never throws — a cancel or an optional wizard's error just skips the
|
|
27
|
+
* rest and lets core setup complete.
|
|
28
|
+
*/
|
|
29
|
+
export type SetupPhase = 'browser' | 'computer' | 'share' | 'secrets' | 'fleet' | 'watchdog' | 'preferences';
|
|
30
|
+
export type SetupStatusState = 'ready' | 'missing' | 'n/a';
|
|
31
|
+
export interface SetupStatusRow {
|
|
32
|
+
phase: 'core' | SetupPhase;
|
|
33
|
+
state: SetupStatusState;
|
|
34
|
+
detail: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function getSetupStatus(): Promise<SetupStatusRow[]>;
|
|
37
|
+
export declare function renderSetupStatus(rows: SetupStatusRow[]): void;
|
|
38
|
+
export declare function runSetupHub(deps?: {
|
|
39
|
+
interactive?: boolean;
|
|
40
|
+
selectPhase?: (rows: SetupStatusRow[]) => Promise<SetupPhase | 'exit'>;
|
|
41
|
+
runPhase?: (phase: SetupPhase) => Promise<void>;
|
|
42
|
+
}): Promise<void>;
|
|
21
43
|
/** Register the `agents setup` command and its capability subcommands. */
|
|
22
44
|
export declare function registerSetupCommand(program: Command): void;
|
|
45
|
+
export {};
|
package/dist/commands/setup.js
CHANGED
|
@@ -26,6 +26,13 @@ import { registerSetupSecretsCommand } from './setup-secrets.js';
|
|
|
26
26
|
import { registerSetupFleetCommand } from './setup-fleet.js';
|
|
27
27
|
import { registerSetupWatchdogCommand, runWatchdogSetupWizard } from './setup-watchdog.js';
|
|
28
28
|
import { runPreferencesStep } from './setup-preferences.js';
|
|
29
|
+
import { getConfiguredDefaultProfileName, getProfile, isProfileLaunchableHere, DEFAULT_BROWSER_PROFILE_NAME } from '../lib/browser/profiles.js';
|
|
30
|
+
import { listInstalledBrowsers } from '../lib/browser/chrome.js';
|
|
31
|
+
import { probeComputerTrust } from './computer.js';
|
|
32
|
+
import { readShareConfig } from '../lib/share/config.js';
|
|
33
|
+
import { loadDevices } from '../lib/devices/registry.js';
|
|
34
|
+
import { getConfigValue } from '../lib/device-config.js';
|
|
35
|
+
import { setupSecretsPrefsPath } from './setup-secrets.js';
|
|
29
36
|
const HOME = os.homedir();
|
|
30
37
|
/**
|
|
31
38
|
* Import an existing unmanaged agent installation into agents-cli.
|
|
@@ -70,9 +77,9 @@ export async function runSetup(program, options = {}) {
|
|
|
70
77
|
const agentsDir = getAgentsDir();
|
|
71
78
|
const alreadyConfigured = isGitRepo(agentsDir);
|
|
72
79
|
if (alreadyConfigured && !options.force) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
if (options.suppressFooter)
|
|
81
|
+
return;
|
|
82
|
+
await (options.runHub ?? runSetupHub)();
|
|
76
83
|
return;
|
|
77
84
|
}
|
|
78
85
|
// Detect existing installations BEFORE cloning (they won't exist after if we import)
|
|
@@ -193,11 +200,7 @@ export async function runSetup(program, options = {}) {
|
|
|
193
200
|
// Fresh-machine hub: offer to set up the optional capabilities that need their
|
|
194
201
|
// own guided flow. TTY-only and fully opt-in — a non-interactive `agents setup`
|
|
195
202
|
// stops at the system-repo bootstrap above, unchanged.
|
|
196
|
-
await runSetupHub();
|
|
197
|
-
// Preferences step: the two questions that keep agents off the wrong machine —
|
|
198
|
-
// which box you sit at (interactive host) and which browser agents drive here.
|
|
199
|
-
// TTY-only, skippable, and writes the same keys as `agents devices …`.
|
|
200
|
-
await runPreferencesStep();
|
|
203
|
+
await (options.runHub ?? runSetupHub)();
|
|
201
204
|
console.log(chalk.bold('\nSetup complete. Try:'));
|
|
202
205
|
console.log(chalk.cyan(' agents view ') + chalk.gray(' # see what\'s installed'));
|
|
203
206
|
console.log(chalk.cyan(' agents run <agent> "hello" ') + chalk.gray(' # run an agent'));
|
|
@@ -229,42 +232,88 @@ export async function ensureInitialized(program) {
|
|
|
229
232
|
}
|
|
230
233
|
await runSetup(program, { suppressFooter: true });
|
|
231
234
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
235
|
+
export async function getSetupStatus() {
|
|
236
|
+
const configuredBrowserProfile = getConfiguredDefaultProfileName();
|
|
237
|
+
const browserProfile = await getProfile(configuredBrowserProfile ?? DEFAULT_BROWSER_PROFILE_NAME);
|
|
238
|
+
const browserReady = browserProfile !== null && isProfileLaunchableHere(browserProfile);
|
|
239
|
+
const installedBrowsers = listInstalledBrowsers();
|
|
240
|
+
const computerState = process.platform === 'darwin' ? (await probeComputerTrust() ? 'ready' : 'missing') : 'n/a';
|
|
241
|
+
const devices = await loadDevices();
|
|
242
|
+
const coreReady = isGitRepo(getAgentsDir());
|
|
243
|
+
const secretsReady = fs.existsSync(setupSecretsPrefsPath());
|
|
244
|
+
const shareConfig = readShareConfig();
|
|
245
|
+
const watchdogEnabled = getConfigValue('watchdog.enabled').value === true;
|
|
246
|
+
const interactiveHost = getConfigValue('interactive.host').value;
|
|
247
|
+
const defaultBrowser = getConfigValue('browser.profile').value;
|
|
248
|
+
return [
|
|
249
|
+
{ phase: 'core', state: coreReady ? 'ready' : 'missing', detail: coreReady ? 'system repo ready' : 'system repo missing' },
|
|
250
|
+
{ phase: 'browser', state: browserReady ? 'ready' : 'missing', detail: browserReady ? `profile ${browserProfile.name}` : browserProfile ? `profile ${browserProfile.name} cannot launch here` : installedBrowsers.length ? 'no default profile' : 'no supported browser found' },
|
|
251
|
+
{ phase: 'computer', state: computerState, detail: computerState === 'ready' ? 'helper trusted' : computerState === 'n/a' ? 'macOS local setup only' : 'helper not running or not trusted' },
|
|
252
|
+
{ phase: 'secrets', state: secretsReady ? 'ready' : 'missing', detail: secretsReady ? 'defaults chosen' : 'defaults not chosen' },
|
|
253
|
+
{ phase: 'fleet', state: Object.keys(devices).length ? 'ready' : 'missing', detail: Object.keys(devices).length ? `${Object.keys(devices).length} device${Object.keys(devices).length === 1 ? '' : 's'} registered` : 'no devices registered' },
|
|
254
|
+
{ phase: 'share', state: shareConfig ? 'ready' : 'missing', detail: shareConfig?.baseUrl ?? 'endpoint not configured' },
|
|
255
|
+
{ phase: 'watchdog', state: watchdogEnabled ? 'ready' : 'missing', detail: watchdogEnabled ? 'enabled on this device' : 'disabled on this device' },
|
|
256
|
+
{ phase: 'preferences', state: interactiveHost || defaultBrowser ? 'ready' : 'missing', detail: [interactiveHost && `host ${interactiveHost}`, defaultBrowser && `browser ${defaultBrowser}`].filter(Boolean).join(' · ') || 'interactive host and browser unset' },
|
|
257
|
+
];
|
|
258
|
+
}
|
|
259
|
+
export function renderSetupStatus(rows) {
|
|
260
|
+
console.log(chalk.bold('\nagents setup — onboarding\n'));
|
|
261
|
+
for (const row of rows) {
|
|
262
|
+
const marker = row.state === 'ready' ? chalk.green('[x]') : row.state === 'n/a' ? chalk.gray('[-]') : chalk.yellow('[ ]');
|
|
263
|
+
const label = row.phase[0].toUpperCase() + row.phase.slice(1);
|
|
264
|
+
console.log(` ${marker} ${label.padEnd(12)} ${chalk.gray(row.detail)}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async function runSetupPhase(phase) {
|
|
268
|
+
if (phase === 'browser')
|
|
269
|
+
await runBrowserWizard();
|
|
270
|
+
else if (phase === 'computer')
|
|
271
|
+
await runComputerWizard();
|
|
272
|
+
else if (phase === 'share')
|
|
273
|
+
await runShareWizard();
|
|
274
|
+
else if (phase === 'secrets')
|
|
275
|
+
await import('./setup-secrets.js').then((m) => m.runSecretsSetupWizard());
|
|
276
|
+
else if (phase === 'fleet')
|
|
277
|
+
await import('./setup-fleet.js').then((m) => m.runFleetSetupWizard());
|
|
278
|
+
else if (phase === 'watchdog')
|
|
279
|
+
await runWatchdogSetupWizard();
|
|
280
|
+
else
|
|
281
|
+
await runPreferencesStep();
|
|
282
|
+
}
|
|
283
|
+
export async function runSetupHub(deps = {}) {
|
|
284
|
+
const interactive = deps.interactive ?? isInteractiveTerminal();
|
|
285
|
+
if (!interactive) {
|
|
286
|
+
const rows = await getSetupStatus();
|
|
287
|
+
renderSetupStatus(rows);
|
|
288
|
+
if (rows.some((row) => row.state === 'missing'))
|
|
289
|
+
process.exitCode = 1;
|
|
240
290
|
return;
|
|
291
|
+
}
|
|
241
292
|
try {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
{
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
293
|
+
while (true) {
|
|
294
|
+
const rows = await getSetupStatus();
|
|
295
|
+
renderSetupStatus(rows);
|
|
296
|
+
let pick;
|
|
297
|
+
if (deps.selectPhase) {
|
|
298
|
+
pick = await deps.selectPhase(rows);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
const { select } = await import('@inquirer/prompts');
|
|
302
|
+
pick = await select({
|
|
303
|
+
message: 'Choose a phase to configure',
|
|
304
|
+
choices: [
|
|
305
|
+
...rows.filter((row) => row.phase !== 'core' && row.state !== 'n/a').map((row) => ({
|
|
306
|
+
name: `${row.state === 'ready' ? '[x]' : '[ ]'} ${row.phase.padEnd(12)} ${row.detail}`,
|
|
307
|
+
value: row.phase,
|
|
308
|
+
})),
|
|
309
|
+
{ name: 'Exit setup', value: 'exit' },
|
|
310
|
+
],
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (pick === 'exit')
|
|
314
|
+
return;
|
|
255
315
|
console.log();
|
|
256
|
-
|
|
257
|
-
await runBrowserWizard();
|
|
258
|
-
else if (pick === 'computer')
|
|
259
|
-
await runComputerWizard();
|
|
260
|
-
else if (pick === 'share')
|
|
261
|
-
await runShareWizard();
|
|
262
|
-
else if (pick === 'secrets')
|
|
263
|
-
await import('./setup-secrets.js').then((m) => m.runSecretsSetupWizard());
|
|
264
|
-
else if (pick === 'fleet')
|
|
265
|
-
await import('./setup-fleet.js').then((m) => m.runFleetSetupWizard());
|
|
266
|
-
else if (pick === 'watchdog')
|
|
267
|
-
await runWatchdogSetupWizard();
|
|
316
|
+
await (deps.runPhase ?? runSetupPhase)(pick);
|
|
268
317
|
}
|
|
269
318
|
}
|
|
270
319
|
catch (err) {
|
|
@@ -277,7 +326,7 @@ async function runSetupHub() {
|
|
|
277
326
|
export function registerSetupCommand(program) {
|
|
278
327
|
const setupCmd = program
|
|
279
328
|
.command('setup')
|
|
280
|
-
.description('
|
|
329
|
+
.description('Set up agents-cli, or re-open the capability onboarding hub.')
|
|
281
330
|
.option('-f, --force', 'Re-run setup even if ~/.agents/.system/ already exists (use with caution)')
|
|
282
331
|
.option('--no-system-repo', 'Skip cloning the system repo (you must populate ~/.agents/.system/ yourself)');
|
|
283
332
|
// Capability subcommands: `agents setup browser|computer|share|mine|secrets|fleet`.
|
|
@@ -288,6 +337,18 @@ export function registerSetupCommand(program) {
|
|
|
288
337
|
registerSetupSecretsCommand(setupCmd);
|
|
289
338
|
registerSetupFleetCommand(setupCmd);
|
|
290
339
|
registerSetupWatchdogCommand(setupCmd);
|
|
340
|
+
setupCmd.command('status')
|
|
341
|
+
.description('Show setup readiness for core, browser, computer, secrets, fleet, share, watchdog, and preferences.')
|
|
342
|
+
.option('--json', 'print machine-readable JSON')
|
|
343
|
+
.action(async (options) => {
|
|
344
|
+
const rows = await getSetupStatus();
|
|
345
|
+
if (options.json)
|
|
346
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
347
|
+
else
|
|
348
|
+
renderSetupStatus(rows);
|
|
349
|
+
if (rows.some((row) => row.state === 'missing'))
|
|
350
|
+
process.exitCode = 1;
|
|
351
|
+
});
|
|
291
352
|
setHelpSections(setupCmd, {
|
|
292
353
|
examples: `
|
|
293
354
|
# First-time setup (clones the system repo into ~/.agents/.system/)
|
|
@@ -308,10 +369,8 @@ export function registerSetupCommand(program) {
|
|
|
308
369
|
What it does:
|
|
309
370
|
1. Clones the system repo into ~/.agents/.system/
|
|
310
371
|
2. Imports any unmanaged agent installations it finds
|
|
311
|
-
3.
|
|
312
|
-
4.
|
|
313
|
-
and which browser agents drive here — both skippable, both the same
|
|
314
|
-
keys 'agents devices set-interactive' / 'browser profiles set-default' write
|
|
372
|
+
3. Opens a re-runnable capability menu with live ready/missing status
|
|
373
|
+
4. Delegates each selection to its existing setup wizard
|
|
315
374
|
|
|
316
375
|
Capability setup can also be run any time on its own:
|
|
317
376
|
agents setup browser # detect a browser + create the default profile
|
package/dist/commands/teams.d.ts
CHANGED
|
@@ -34,6 +34,12 @@ export interface TeamListAgentSnapshot {
|
|
|
34
34
|
cloud_provider: string | null;
|
|
35
35
|
pr_url: string | null;
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* One-line operator nudge after `teams start`: teammates are briefed to post
|
|
39
|
+
* IMPORTANT milestones to the feed (RUSH-2250), and this is how to watch them.
|
|
40
|
+
* Print-only — no engine behavior.
|
|
41
|
+
*/
|
|
42
|
+
export declare function printFeedHint(team: string): void;
|
|
37
43
|
/** Where `teams message`/`teams resume` routes a follow-up, by teammate status. */
|
|
38
44
|
export type TeamMessageRoute = {
|
|
39
45
|
kind: 'steer';
|
package/dist/commands/teams.js
CHANGED
|
@@ -153,6 +153,18 @@ function fullName(type, version) {
|
|
|
153
153
|
const name = AGENT_NAMES[type];
|
|
154
154
|
return version ? `${name} ${version}` : name;
|
|
155
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* One-line operator nudge after `teams start`: teammates are briefed to post
|
|
158
|
+
* IMPORTANT milestones to the feed (RUSH-2250), and this is how to watch them.
|
|
159
|
+
* Print-only — no engine behavior.
|
|
160
|
+
*/
|
|
161
|
+
export function printFeedHint(team) {
|
|
162
|
+
console.log(chalk.gray('Tip: teammates post IMPORTANT milestones to the feed (') +
|
|
163
|
+
chalk.cyan('agents feed timeline') +
|
|
164
|
+
chalk.gray('); watch team progress with ') +
|
|
165
|
+
chalk.cyan(`agents teams status ${team}`) +
|
|
166
|
+
chalk.gray('.'));
|
|
167
|
+
}
|
|
156
168
|
/**
|
|
157
169
|
* Resolve a teammate spec to its execution target.
|
|
158
170
|
*
|
|
@@ -365,6 +377,8 @@ async function runOneWave(mgr, team, json) {
|
|
|
365
377
|
console.log(` ${chalk.blue(h)} ${chalk.gray('after')} ${a.after.join(', ')}`);
|
|
366
378
|
}
|
|
367
379
|
}
|
|
380
|
+
if (launched.length > 0)
|
|
381
|
+
printFeedHint(team);
|
|
368
382
|
}
|
|
369
383
|
/**
|
|
370
384
|
* Path to the pr-watch dedupe-state file for a team. Persists the set of
|
|
@@ -1766,11 +1780,40 @@ export function registerTeamsCommands(program) {
|
|
|
1766
1780
|
await warnUnsignedTeammates(mgr, team);
|
|
1767
1781
|
await warnThrottledTeammates(mgr, team);
|
|
1768
1782
|
}
|
|
1783
|
+
// Health-/harness-aware pre-flight (RUSH-2002): if the team declares a
|
|
1784
|
+
// device pool and no device in it can run a pending teammate's agent, fail
|
|
1785
|
+
// loud here rather than launching a wave that strands teammates pending.
|
|
1786
|
+
// --force downgrades it to a warning so the user can still try.
|
|
1787
|
+
const placementError = await mgr.preflightPlacement(team);
|
|
1788
|
+
if (placementError) {
|
|
1789
|
+
if (isJsonMode(opts)) {
|
|
1790
|
+
console.log(JSON.stringify({
|
|
1791
|
+
team,
|
|
1792
|
+
error: 'no-viable-device',
|
|
1793
|
+
message: placementError.message,
|
|
1794
|
+
excluded: placementError.excluded,
|
|
1795
|
+
}));
|
|
1796
|
+
if (!opts.force) {
|
|
1797
|
+
process.exitCode = 1;
|
|
1798
|
+
return;
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
else if (opts.force) {
|
|
1802
|
+
console.error(chalk.yellow(`⚠ ${placementError.message}\n Continuing anyway (--force).`));
|
|
1803
|
+
}
|
|
1804
|
+
else {
|
|
1805
|
+
console.error(chalk.red(placementError.message));
|
|
1806
|
+
process.exitCode = 1;
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1769
1810
|
emit('teams.start', { module: 'teams', team, watch: Boolean(opts.watch) });
|
|
1770
1811
|
if (!opts.watch) {
|
|
1771
1812
|
await runOneWave(mgr, team, Boolean(opts.json));
|
|
1772
1813
|
return;
|
|
1773
1814
|
}
|
|
1815
|
+
if (!isJsonMode(opts))
|
|
1816
|
+
printFeedHint(team);
|
|
1774
1817
|
const intervalMs = Math.max(1000, Number.parseInt(opts.interval, 10) * 1000 || 8000);
|
|
1775
1818
|
const maxWaves = Math.max(1, Number.parseInt(opts.maxWaves, 10) || 1000);
|
|
1776
1819
|
const json = isJsonMode(opts);
|
|
@@ -1,2 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deprecated top-level spelling of the counter-mix tree.
|
|
3
|
+
*
|
|
4
|
+
* Implementation lives under `agents insights mix` (see
|
|
5
|
+
* `lib/analytics/mix-commands.ts`). This file only registers the thin alias so
|
|
6
|
+
* old scripts and agent briefs keep working while printing one deprecation line
|
|
7
|
+
* — no second recipe implementation.
|
|
8
|
+
*/
|
|
1
9
|
import type { Command } from 'commander';
|
|
2
10
|
export declare function registerTrendsCommand(program: Command): void;
|
package/dist/commands/trends.js
CHANGED
|
@@ -1,158 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
function parseLimit(raw, fallback) {
|
|
11
|
-
const n = parseInt(raw ?? String(fallback), 10);
|
|
12
|
-
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
13
|
-
}
|
|
14
|
-
function printSection(section) {
|
|
15
|
-
console.log(chalk.bold(section.title));
|
|
16
|
-
if (section.rows.length === 0) {
|
|
17
|
-
console.log(chalk.gray(' (no data)'));
|
|
18
|
-
console.log();
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
const keys = Object.keys(section.rows[0]);
|
|
22
|
-
const widths = keys.map((k) => Math.max(k.length, ...section.rows.map((r) => String(r[k] ?? '').length), 4));
|
|
23
|
-
const pad = (s, w) => (s.length >= w ? s.slice(0, w) : s + ' '.repeat(w - s.length));
|
|
24
|
-
console.log(chalk.gray(keys.map((k, i) => pad(k.toUpperCase(), widths[i])).join(' ')));
|
|
25
|
-
for (const row of section.rows) {
|
|
26
|
-
console.log(keys.map((k, i) => pad(String(row[k] ?? ''), widths[i])).join(' '));
|
|
27
|
-
}
|
|
28
|
-
console.log();
|
|
29
|
-
}
|
|
30
|
-
function renderDashboard(days, asJson) {
|
|
31
|
-
const dash = buildTrendsDashboard({ days });
|
|
32
|
-
if (asJson) {
|
|
33
|
-
console.log(JSON.stringify(dash, null, 2));
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
console.log(chalk.bold(`agents trends — last ${dash.window.days} days`));
|
|
37
|
-
console.log(chalk.gray(`compute ${dash.durationMs}ms · usage ${usageDbPath()}`));
|
|
38
|
-
console.log();
|
|
39
|
-
if (dash.sections.length === 0) {
|
|
40
|
-
console.log(chalk.gray('No session or usage data in this window yet.'));
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
for (const section of dash.sections)
|
|
44
|
-
printSection(section);
|
|
45
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Deprecated top-level spelling of the counter-mix tree.
|
|
3
|
+
*
|
|
4
|
+
* Implementation lives under `agents insights mix` (see
|
|
5
|
+
* `lib/analytics/mix-commands.ts`). This file only registers the thin alias so
|
|
6
|
+
* old scripts and agent briefs keep working while printing one deprecation line
|
|
7
|
+
* — no second recipe implementation.
|
|
8
|
+
*/
|
|
9
|
+
import { registerDeprecatedTrendsAlias } from '../lib/analytics/mix-commands.js';
|
|
46
10
|
export function registerTrendsCommand(program) {
|
|
47
|
-
|
|
48
|
-
.command('trends')
|
|
49
|
-
.description('Usage analytics — harness/model mix, token ratios, resource frequency')
|
|
50
|
-
.option('--days <n>', 'Days of history to include', '7')
|
|
51
|
-
.option('--json', 'Emit JSON instead of tables')
|
|
52
|
-
.action(function summary() {
|
|
53
|
-
const opts = this.opts();
|
|
54
|
-
renderDashboard(parseDays(opts.days), Boolean(opts.json));
|
|
55
|
-
});
|
|
56
|
-
setHelpSections(trends, {
|
|
57
|
-
examples: `
|
|
58
|
-
# Auto recipe dashboard (7d)
|
|
59
|
-
agents trends
|
|
60
|
-
|
|
61
|
-
# Last 30 days
|
|
62
|
-
agents trends --days 30
|
|
63
|
-
|
|
64
|
-
# One recipe as JSON
|
|
65
|
-
agents trends harness-mix --json
|
|
66
|
-
|
|
67
|
-
# Raw usage events
|
|
68
|
-
agents trends query --kind secret --days 7
|
|
69
|
-
|
|
70
|
-
# List baked recipe ids
|
|
71
|
-
agents trends recipes
|
|
72
|
-
`,
|
|
73
|
-
notes: `
|
|
74
|
-
Session recipes read sessions.db; resource recipes read ~/.agents/.history/analytics/usage.db.
|
|
75
|
-
Empty recipes are skipped on the default dashboard.
|
|
76
|
-
Quota / rate-limits remain on \`agents usage\`; latency on \`agents perf\`.
|
|
77
|
-
`,
|
|
78
|
-
});
|
|
79
|
-
trends.command('recipes')
|
|
80
|
-
.description('List baked recipe ids')
|
|
81
|
-
.option('--json', 'Emit JSON')
|
|
82
|
-
.action((opts) => {
|
|
83
|
-
const list = listRecipes();
|
|
84
|
-
if (opts.json) {
|
|
85
|
-
console.log(JSON.stringify(list, null, 2));
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
for (const r of list) {
|
|
89
|
-
console.log(`${r.id.padEnd(22)} ${r.store.padEnd(10)} ${r.title}`);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
trends.command('query')
|
|
93
|
-
.description('Raw usage-event query')
|
|
94
|
-
.option('--kind <kind>', `One of: ${USAGE_KINDS.join(', ')}`)
|
|
95
|
-
.option('--name <name>', 'Resource name filter')
|
|
96
|
-
.option('--event <event>', 'Event name filter')
|
|
97
|
-
.option('--days <n>', 'Days of history', '7')
|
|
98
|
-
.option('--limit <n>', 'Max rows', '40')
|
|
99
|
-
.option('--json', 'Emit JSON')
|
|
100
|
-
.action((opts) => {
|
|
101
|
-
const win = trendsWindow(parseDays(opts.days));
|
|
102
|
-
const kind = opts.kind && USAGE_KINDS.includes(opts.kind)
|
|
103
|
-
? opts.kind
|
|
104
|
-
: undefined;
|
|
105
|
-
if (opts.kind && !kind) {
|
|
106
|
-
console.error(`Unknown kind '${opts.kind}'. Expected: ${USAGE_KINDS.join(', ')}`);
|
|
107
|
-
process.exitCode = 1;
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const rows = queryUsage({
|
|
111
|
-
kind,
|
|
112
|
-
name: opts.name,
|
|
113
|
-
event: opts.event,
|
|
114
|
-
sinceIso: win.sinceIso,
|
|
115
|
-
limit: parseLimit(opts.limit, 40),
|
|
116
|
-
});
|
|
117
|
-
if (opts.json) {
|
|
118
|
-
console.log(JSON.stringify({ window: win, rows }, null, 2));
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
if (rows.length === 0) {
|
|
122
|
-
console.log(chalk.gray('No usage events.'));
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
printSection({
|
|
126
|
-
id: 'query',
|
|
127
|
-
title: 'Usage events',
|
|
128
|
-
rows: rows.map((r) => ({
|
|
129
|
-
ts: r.ts,
|
|
130
|
-
kind: r.kind,
|
|
131
|
-
name: r.name,
|
|
132
|
-
event: r.event,
|
|
133
|
-
agent: r.agent,
|
|
134
|
-
})),
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
for (const id of RECIPE_IDS) {
|
|
138
|
-
trends.command(id)
|
|
139
|
-
.description(`Recipe: ${id}`)
|
|
140
|
-
.option('--days <n>', 'Days of history', '7')
|
|
141
|
-
.option('--json', 'Emit JSON')
|
|
142
|
-
.action(function recipeAction() {
|
|
143
|
-
const parent = this.parent?.opts?.();
|
|
144
|
-
const opts = { ...parent, ...this.opts() };
|
|
145
|
-
const win = trendsWindow(parseDays(opts.days));
|
|
146
|
-
const section = runRecipe(id, win);
|
|
147
|
-
if (opts.json) {
|
|
148
|
-
console.log(JSON.stringify({ window: win, section }, null, 2));
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
if (section.empty) {
|
|
152
|
-
console.log(chalk.gray(`No data for recipe '${id}' in the last ${win.days} days.`));
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
printSection(section);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
11
|
+
registerDeprecatedTrendsAlias(program);
|
|
158
12
|
}
|
package/dist/index.js
CHANGED
|
@@ -327,7 +327,7 @@ Credentials and profiles:
|
|
|
327
327
|
Diagnostics:
|
|
328
328
|
doctor [agent[@version]] Diagnose CLI availability, sync status, and resource divergence; --check for the CI drift gate
|
|
329
329
|
usage [agent] Show rate-limit and quota usage per agent
|
|
330
|
-
insights How
|
|
330
|
+
insights How work looks — behaviour (default) or counter mix (insights mix)
|
|
331
331
|
perf Latency rollups (hooks, commands, runs) from the disposable perf warehouse
|
|
332
332
|
|
|
333
333
|
Config sync:
|
package/dist/lib/agents.d.ts
CHANGED
|
@@ -34,6 +34,17 @@ export declare function findInPath(command: string): string | null;
|
|
|
34
34
|
export declare const AGENTS: Record<AgentId, AgentConfig>;
|
|
35
35
|
/** All current and legacy agent IDs derived from the AGENTS registry. */
|
|
36
36
|
export declare const ALL_AGENT_IDS: AgentId[];
|
|
37
|
+
/**
|
|
38
|
+
* CLI command templates per agent for daemon-fired routine jobs, with
|
|
39
|
+
* {prompt} as a placeholder. Lives here (not runner.ts) so routines.ts can
|
|
40
|
+
* import ROUTINE_AGENT_IDS for schedule-time validation without a circular
|
|
41
|
+
* import (runner.ts already imports from routines.ts).
|
|
42
|
+
*/
|
|
43
|
+
export declare const ROUTINE_AGENT_COMMANDS: Record<string, string[]>;
|
|
44
|
+
/** Agents the routine daemon can actually run when firing locally, derived
|
|
45
|
+
* from the command table above so the `--agent` help and validateJob's
|
|
46
|
+
* schedule-time check can never drift from it. */
|
|
47
|
+
export declare const ROUTINE_AGENT_IDS: readonly string[];
|
|
37
48
|
/** Agents retained only for legacy reads, not install/import/sync targets. */
|
|
38
49
|
export declare const HARD_DEPRECATED_AGENT_IDS: AgentId[];
|
|
39
50
|
/** Agents that can receive managed installs, imports, and resource sync writes. */
|
package/dist/lib/agents.js
CHANGED
|
@@ -384,14 +384,22 @@ export const AGENTS = {
|
|
|
384
384
|
instructionsFile: 'workspace/AGENTS.md', // Primary memory file (also has SOUL.md, IDENTITY.md, etc.)
|
|
385
385
|
format: 'markdown',
|
|
386
386
|
variableSyntax: '{{ARGUMENTS}}',
|
|
387
|
-
|
|
387
|
+
// hooks: NOT supported. OpenClaw only exposes a fixed set of internal,
|
|
388
|
+
// named hooks (e.g. `boot-md`, which runs BOOT.md on gateway restart) —
|
|
389
|
+
// there is no general event->shell-command registration surface (no
|
|
390
|
+
// PreToolUse/PostToolUse/UserPromptSubmit equivalent an agents-cli
|
|
391
|
+
// hooks.yaml manifest could target). registerHooksToSettings has no
|
|
392
|
+
// `openclaw` case and silently no-ops (RUSH-2122: capability claimed
|
|
393
|
+
// hooks:true with zero hooks ever installed). Flip back to `true` only
|
|
394
|
+
// alongside a real registerHooksForOpenClaw implementation.
|
|
395
|
+
supportsHooks: false,
|
|
388
396
|
// allowlist: maps blanket (whole-tool) rules to ~/.openclaw/openclaw.json
|
|
389
397
|
// tools.alsoAllow (allow) / tools.deny (deny). OpenClaw gates at tool
|
|
390
398
|
// granularity only, so sub-command/path/domain patterns are skipped.
|
|
391
399
|
// OpenClaw is self-updating (no pinned since), so `true` is correct.
|
|
392
400
|
// Workflows sync as Lobster `.lobster` files under `.openclaw/workflows/`;
|
|
393
401
|
// the Lobster tool runs them by receiving the file path as `pipeline`.
|
|
394
|
-
capabilities: { hooks:
|
|
402
|
+
capabilities: { hooks: false, mcp: true, mcpHttp: false, mcpHeaders: false, allowlist: true, skills: true, commands: false, plugins: true, subagents: true, rules: { file: 'workspace/AGENTS.md' }, workflows: true, memory: true, modes: ['plan', 'edit', 'skip'], interactiveRepl: true },
|
|
395
403
|
},
|
|
396
404
|
copilot: {
|
|
397
405
|
id: 'copilot',
|
|
@@ -884,6 +892,25 @@ export const AGENTS = {
|
|
|
884
892
|
};
|
|
885
893
|
/** All current and legacy agent IDs derived from the AGENTS registry. */
|
|
886
894
|
export const ALL_AGENT_IDS = Object.keys(AGENTS);
|
|
895
|
+
/**
|
|
896
|
+
* CLI command templates per agent for daemon-fired routine jobs, with
|
|
897
|
+
* {prompt} as a placeholder. Lives here (not runner.ts) so routines.ts can
|
|
898
|
+
* import ROUTINE_AGENT_IDS for schedule-time validation without a circular
|
|
899
|
+
* import (runner.ts already imports from routines.ts).
|
|
900
|
+
*/
|
|
901
|
+
export const ROUTINE_AGENT_COMMANDS = {
|
|
902
|
+
claude: ['claude', '-p', '--verbose', '{prompt}', '--output-format', 'stream-json', '--permission-mode', 'plan'],
|
|
903
|
+
codex: ['codex', 'exec', '{prompt}', '--json'],
|
|
904
|
+
gemini: ['gemini', '{prompt}', '--output-format', 'stream-json'],
|
|
905
|
+
cursor: ['cursor-agent', '-p', '{prompt}', '--output-format', 'stream-json'],
|
|
906
|
+
kimi: ['kimi', '--prompt', '{prompt}', '--output-format', 'stream-json'],
|
|
907
|
+
droid: ['droid', 'exec', '{prompt}', '-o', 'stream-json'],
|
|
908
|
+
muse: ['muse', 'exec', '{prompt}', '--json'],
|
|
909
|
+
};
|
|
910
|
+
/** Agents the routine daemon can actually run when firing locally, derived
|
|
911
|
+
* from the command table above so the `--agent` help and validateJob's
|
|
912
|
+
* schedule-time check can never drift from it. */
|
|
913
|
+
export const ROUTINE_AGENT_IDS = Object.freeze(Object.keys(ROUTINE_AGENT_COMMANDS));
|
|
887
914
|
/** Agents retained only for legacy reads, not install/import/sync targets. */
|
|
888
915
|
export const HARD_DEPRECATED_AGENT_IDS = ALL_AGENT_IDS.filter((id) => AGENTS[id].deprecated?.hard);
|
|
889
916
|
/** Agents that can receive managed installs, imports, and resource sync writes. */
|