@phnx-labs/agents-cli 1.22.25 → 1.22.27
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 +427 -0
- package/README.md +35 -3
- package/dist/bin/agents +0 -0
- package/dist/browser.js +14 -4
- package/dist/commands/apply.js +52 -8
- package/dist/commands/bench.d.ts +2 -0
- package/dist/commands/bench.js +101 -0
- package/dist/commands/browser.js +35 -0
- package/dist/commands/doctor.js +32 -10
- package/dist/commands/exec.js +17 -16
- package/dist/commands/insights.d.ts +25 -19
- package/dist/commands/insights.js +146 -38
- package/dist/commands/output.js +100 -25
- package/dist/commands/reconnect.d.ts +46 -0
- package/dist/commands/reconnect.js +109 -0
- package/dist/commands/resume.d.ts +11 -0
- package/dist/commands/resume.js +51 -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-picker.js +12 -7
- package/dist/commands/sessions.d.ts +47 -1
- package/dist/commands/sessions.js +349 -37
- 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/ssh.js +184 -11
- package/dist/commands/teams.d.ts +6 -0
- package/dist/commands/teams.js +46 -3
- package/dist/commands/trends.d.ts +8 -0
- package/dist/commands/trends.js +10 -156
- package/dist/index.js +17 -21
- 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/auth-health.d.ts +47 -3
- package/dist/lib/auth-health.js +74 -15
- package/dist/lib/bench/index.d.ts +4 -0
- package/dist/lib/bench/index.js +4 -0
- package/dist/lib/bench/runner.d.ts +16 -0
- package/dist/lib/bench/runner.js +111 -0
- package/dist/lib/bench/schema.d.ts +5 -0
- package/dist/lib/bench/schema.js +91 -0
- package/dist/lib/bench/storage.d.ts +5 -0
- package/dist/lib/bench/storage.js +32 -0
- package/dist/lib/bench/types.d.ts +40 -0
- package/dist/lib/bench/types.js +1 -0
- 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/claude-account-token.d.ts +2 -0
- package/dist/lib/claude-account-token.js +27 -1
- package/dist/lib/crabbox/cli.d.ts +2 -0
- package/dist/lib/crabbox/cli.js +2 -0
- package/dist/lib/crabbox/lease.js +7 -1
- package/dist/lib/daemon.js +20 -0
- package/dist/lib/devices/connect.d.ts +2 -0
- package/dist/lib/devices/connect.js +7 -0
- package/dist/lib/devices/doctor-findings.d.ts +10 -1
- package/dist/lib/devices/doctor-findings.js +47 -1
- package/dist/lib/devices/harness-inventory.d.ts +97 -0
- package/dist/lib/devices/harness-inventory.js +0 -0
- package/dist/lib/devices/registry.d.ts +2 -0
- package/dist/lib/devices/ssh-config.js +3 -0
- package/dist/lib/devices/windows-ssh-enrollment.d.ts +20 -0
- package/dist/lib/devices/windows-ssh-enrollment.js +98 -0
- package/dist/lib/exec.bench.d.ts +1 -0
- package/dist/lib/exec.bench.js +186 -0
- package/dist/lib/exec.js +18 -8
- package/dist/lib/fleet/apply.d.ts +59 -3
- package/dist/lib/fleet/apply.js +191 -12
- package/dist/lib/fleet/remote-login.d.ts +4 -3
- package/dist/lib/fleet/remote-login.js +11 -9
- package/dist/lib/fleet/types.d.ts +21 -2
- package/dist/lib/gemini-settings.d.ts +0 -1
- package/dist/lib/gemini-settings.js +12 -7
- package/dist/lib/hooks/cache.js +15 -0
- package/dist/lib/hooks.d.ts +8 -5
- package/dist/lib/hooks.js +10 -6
- package/dist/lib/hosts/dispatch.js +7 -3
- package/dist/lib/hosts/passthrough.d.ts +45 -0
- package/dist/lib/hosts/passthrough.js +59 -8
- package/dist/lib/hosts/progress.d.ts +2 -1
- package/dist/lib/hosts/progress.js +4 -3
- package/dist/lib/hosts/providers/devices.js +1 -0
- package/dist/lib/hosts/ready.d.ts +6 -2
- package/dist/lib/hosts/ready.js +33 -8
- package/dist/lib/hosts/reconcile.d.ts +1 -1
- package/dist/lib/hosts/reconcile.js +16 -7
- package/dist/lib/hosts/reconnect.d.ts +56 -21
- package/dist/lib/hosts/reconnect.js +128 -71
- package/dist/lib/hosts/registry.d.ts +2 -2
- package/dist/lib/hosts/registry.js +3 -5
- package/dist/lib/hosts/remote-cmd.d.ts +17 -0
- package/dist/lib/hosts/remote-cmd.js +29 -0
- package/dist/lib/hosts/tasks.d.ts +2 -0
- package/dist/lib/hosts/types.d.ts +1 -0
- package/dist/lib/hosts/types.js +3 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +9 -6
- package/dist/lib/menubar/install-menubar.js +20 -9
- package/dist/lib/models.d.ts +30 -1
- package/dist/lib/models.js +42 -144
- package/dist/lib/pricing/cost.d.ts +9 -0
- package/dist/lib/pricing/cost.js +24 -0
- package/dist/lib/pricing/index.d.ts +1 -1
- package/dist/lib/pricing/index.js +1 -1
- package/dist/lib/redact.js +8 -3
- package/dist/lib/remote-agents-json.d.ts +32 -0
- package/dist/lib/remote-agents-json.js +47 -16
- package/dist/lib/resource-profiles.js +1 -2
- package/dist/lib/routine-notify-owner.d.ts +102 -0
- package/dist/lib/routine-notify-owner.js +232 -0
- package/dist/lib/routines.d.ts +10 -0
- package/dist/lib/routines.js +14 -2
- package/dist/lib/runner.d.ts +9 -4
- package/dist/lib/runner.js +182 -30
- package/dist/lib/sandbox.d.ts +0 -2
- package/dist/lib/sandbox.js +2 -19
- 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/agent.js +3 -2
- package/dist/lib/secrets/lease.d.ts +25 -0
- package/dist/lib/secrets/lease.js +44 -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/self-update.d.ts +20 -5
- package/dist/lib/self-update.js +93 -16
- package/dist/lib/session/db.d.ts +38 -3
- package/dist/lib/session/db.js +273 -16
- package/dist/lib/session/discover.d.ts +22 -1
- package/dist/lib/session/discover.js +239 -51
- package/dist/lib/session/insights.d.ts +37 -0
- package/dist/lib/session/insights.js +219 -9
- package/dist/lib/session/recovery.d.ts +17 -1
- package/dist/lib/session/recovery.js +111 -4
- package/dist/lib/session/remote-list.d.ts +10 -9
- package/dist/lib/session/remote-list.js +25 -23
- package/dist/lib/session/resume-owner.d.ts +55 -0
- package/dist/lib/session/resume-owner.js +69 -0
- package/dist/lib/session/team-filter.d.ts +65 -0
- package/dist/lib/session/team-filter.js +98 -3
- 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/session/types.d.ts +33 -0
- package/dist/lib/smart-launch.d.ts +31 -5
- package/dist/lib/smart-launch.js +43 -7
- package/dist/lib/ssh-exec.d.ts +27 -0
- package/dist/lib/ssh-exec.js +42 -3
- package/dist/lib/ssh-tunnel.d.ts +3 -2
- package/dist/lib/ssh-tunnel.js +25 -16
- package/dist/lib/startup/command-registry.d.ts +2 -0
- package/dist/lib/startup/command-registry.js +6 -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/dist/lib/tmux/session.d.ts +8 -0
- package/dist/lib/tmux/session.js +22 -0
- package/dist/lib/types.d.ts +2 -0
- package/package.json +1 -1
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
|
@@ -94,7 +94,7 @@ if (IS_DEV_BUILD) {
|
|
|
94
94
|
// module on each invocation (which loaded the whole ~50-module tree before the
|
|
95
95
|
// first byte of output), the registry maps a command name to a thunk that
|
|
96
96
|
// imports only what that command needs. See src/lib/startup/command-registry.ts.
|
|
97
|
-
import { COMMAND_LOADERS, LAZY_COMMAND_NAMES, loadView, loadInspect, loadFeedback, loadCommands, loadHooks, loadSkills, loadRules, loadMemory, loadPermissions, loadMcp, loadCli, loadSubagents, loadPlugins, loadWorkflows, loadWorktree, loadVersions, loadImport, loadExport, loadPackages, loadRoutines, loadMonitors, loadProjects, loadRun, loadFork, loadDefaults, loadSet, loadModels, loadModes, loadPrune, loadTrash, loadRestore, loadDoctor, loadApply, loadStatus, loadSnapshot, loadProfiles, loadHarness, loadSecrets, loadLogin, loadWallet, loadHelper, loadMenubar, loadBeta, loadSync, loadLock, loadRefreshRules, loadFactory, loadUsage, loadCost, loadInsights, loadPerf, loadTrends, loadOutput, loadBudget, loadAlias, loadMine, loadPty, loadTmux, loadWatchdog, loadBrowser, loadComputer, loadHosts, loadLogs, loadEvents, loadAudit, loadWebhook, loadFunnel, loadHumans, loadSsh, loadPull, loadPush, loadRepo, loadSetup, loadUninstall, loadShare, loadSend, loadFeed, loadMailboxes, } from './lib/startup/command-registry.js';
|
|
97
|
+
import { COMMAND_LOADERS, LAZY_COMMAND_NAMES, loadView, loadInspect, loadFeedback, loadCommands, loadHooks, loadSkills, loadRules, loadMemory, loadPermissions, loadMcp, loadCli, loadSubagents, loadPlugins, loadWorkflows, loadWorktree, loadVersions, loadImport, loadExport, loadPackages, loadRoutines, loadMonitors, loadProjects, loadRun, loadFork, loadDefaults, loadSet, loadModels, loadModes, loadPrune, loadTrash, loadRestore, loadDoctor, loadApply, loadStatus, loadSnapshot, loadProfiles, loadHarness, loadSecrets, loadLogin, loadWallet, loadHelper, loadMenubar, loadBeta, loadSync, loadLock, loadRefreshRules, loadFactory, loadUsage, loadCost, loadInsights, loadPerf, loadTrends, loadOutput, loadBudget, loadAlias, loadMine, loadPty, loadTmux, loadWatchdog, loadBrowser, loadComputer, loadHosts, loadLogs, loadEvents, loadAudit, loadWebhook, loadFunnel, loadHumans, loadSsh, loadPull, loadPush, loadRepo, loadSetup, loadUninstall, loadBench, loadShare, loadSend, loadFeed, loadMailboxes, } from './lib/startup/command-registry.js';
|
|
98
98
|
import { applyGlobalHelpConventions } from './lib/help.js';
|
|
99
99
|
import { renderWhatsNew } from './lib/whats-new.js';
|
|
100
100
|
import { getCliLaunch } from './lib/cli-entry.js';
|
|
@@ -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:
|
|
@@ -392,15 +392,15 @@ async function showWhatsNew(fromVersion, toVersion) {
|
|
|
392
392
|
const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
393
393
|
import { getUpdateCheckPath, getMigratedSentinelPath, getUserAgentsDir, getRuntimeStateDir } from './lib/state.js';
|
|
394
394
|
import { resolveBrandName, disabledCommandsForActiveBrand } from './lib/brand.js';
|
|
395
|
-
import { readUpdateCache, saveUpdateCheck, dismissUpdateVersion, shouldPromptUpgrade, findAgentsCliInstalls, resolveRunningPackageRoot, } from './lib/self-update.js';
|
|
395
|
+
import { readUpdateCache, saveUpdateCheck, dismissUpdateVersion, shouldPromptUpgrade, buildMultiInstallInventory, findAgentsCliInstalls, resolveRunningPackageRoot, } from './lib/self-update.js';
|
|
396
396
|
const UPDATE_CHECK_FILE = getUpdateCheckPath();
|
|
397
397
|
/**
|
|
398
|
-
* Warn once when
|
|
399
|
-
*
|
|
398
|
+
* Warn once when this machine contains a different agents-cli install than the
|
|
399
|
+
* copy that is currently running (or several). Divergent installs
|
|
400
400
|
* are how self-updates "succeed" without changing the command the user types.
|
|
401
|
-
* The warning re-fires only when the set of install roots
|
|
402
|
-
*
|
|
403
|
-
*
|
|
401
|
+
* The warning re-fires only when the set of install roots or their helper-copy
|
|
402
|
+
* safety changes. Dev builds are included because old dev copies can still
|
|
403
|
+
* overwrite the shared macOS helper bundle non-atomically.
|
|
404
404
|
*/
|
|
405
405
|
function maybeWarnMultiInstall() {
|
|
406
406
|
const sentinel = path.join(getRuntimeStateDir(), 'multi-install-warned');
|
|
@@ -414,31 +414,26 @@ function maybeWarnMultiInstall() {
|
|
|
414
414
|
// "/$bunfs" install. This warning is advisory — stay silent instead.
|
|
415
415
|
return;
|
|
416
416
|
}
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
for (const install of findAgentsCliInstalls(process.env.PATH || '')) {
|
|
420
|
-
if (install.version.startsWith('0.0.0-dev'))
|
|
421
|
-
continue;
|
|
422
|
-
if (!byRoot.has(install.packageRoot)) {
|
|
423
|
-
byRoot.set(install.packageRoot, { version: install.version, note: `agents on PATH: ${install.binPath}` });
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
if (byRoot.size < 2) {
|
|
417
|
+
const inventory = buildMultiInstallInventory(runningRoot, VERSION, findAgentsCliInstalls(process.env.PATH || ''));
|
|
418
|
+
if (inventory.length < 2) {
|
|
427
419
|
try {
|
|
428
420
|
fs.unlinkSync(sentinel);
|
|
429
421
|
}
|
|
430
422
|
catch { /* nothing recorded */ }
|
|
431
423
|
return;
|
|
432
424
|
}
|
|
433
|
-
const key =
|
|
425
|
+
const key = inventory
|
|
426
|
+
.map((info) => `${info.packageRoot}\t${info.version}\t${info.note}`)
|
|
427
|
+
.sort()
|
|
428
|
+
.join('\n');
|
|
434
429
|
try {
|
|
435
430
|
if (fs.readFileSync(sentinel, 'utf-8') === key)
|
|
436
431
|
return;
|
|
437
432
|
}
|
|
438
433
|
catch { /* not warned for this set yet */ }
|
|
439
434
|
console.error(chalk.yellow('Multiple agents-cli installs detected:'));
|
|
440
|
-
for (const
|
|
441
|
-
console.error(chalk.gray(` ${
|
|
435
|
+
for (const info of inventory) {
|
|
436
|
+
console.error(chalk.gray(` ${info.packageRoot} ${info.version} (${info.note})`));
|
|
442
437
|
}
|
|
443
438
|
console.error(chalk.gray('Upgrades apply to the running copy. Remove a stale copy with: npm uninstall -g --prefix <prefix> @phnx-labs/agents-cli'));
|
|
444
439
|
try {
|
|
@@ -967,6 +962,7 @@ async function registerAllEagerCommands() {
|
|
|
967
962
|
await reg(loadCost);
|
|
968
963
|
await reg(loadInsights);
|
|
969
964
|
await reg(loadPerf);
|
|
965
|
+
await reg(loadBench);
|
|
970
966
|
await reg(loadTrends);
|
|
971
967
|
await reg(loadOutput);
|
|
972
968
|
await reg(loadBudget);
|
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. */
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { RECIPE_IDS, runRecipe,
|
|
2
|
-
export interface
|
|
3
|
-
window:
|
|
1
|
+
import { RECIPE_IDS, runRecipe, analyticsWindow, type RecipeId, type RecipeSection, type AnalyticsWindow } from './recipes.js';
|
|
2
|
+
export interface MixDashboard {
|
|
3
|
+
window: AnalyticsWindow;
|
|
4
4
|
durationMs: number;
|
|
5
5
|
sections: RecipeSection[];
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
/** @deprecated Use MixDashboard. */
|
|
8
|
+
export type TrendsDashboard = MixDashboard;
|
|
9
|
+
export declare function buildMixDashboard(opts?: {
|
|
8
10
|
days?: number;
|
|
9
11
|
ids?: RecipeId[];
|
|
10
|
-
}):
|
|
11
|
-
|
|
12
|
+
}): MixDashboard;
|
|
13
|
+
/** @deprecated Use buildMixDashboard. */
|
|
14
|
+
export declare const buildTrendsDashboard: typeof buildMixDashboard;
|
|
15
|
+
export { analyticsWindow, analyticsWindow as trendsWindow, runRecipe, RECIPE_IDS, type RecipeId, type RecipeSection, type AnalyticsWindow, };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RECIPE_IDS, runRecipe,
|
|
1
|
+
import { RECIPE_IDS, runRecipe, analyticsWindow, } from './recipes.js';
|
|
2
2
|
const DEFAULT_ORDER = [
|
|
3
3
|
'harness-mix',
|
|
4
4
|
'model-mix',
|
|
@@ -9,9 +9,9 @@ const DEFAULT_ORDER = [
|
|
|
9
9
|
'browser-activity',
|
|
10
10
|
'resource-mix',
|
|
11
11
|
];
|
|
12
|
-
export function
|
|
12
|
+
export function buildMixDashboard(opts = {}) {
|
|
13
13
|
const t0 = Date.now();
|
|
14
|
-
const win =
|
|
14
|
+
const win = analyticsWindow(opts.days ?? 7);
|
|
15
15
|
const ids = opts.ids ?? DEFAULT_ORDER;
|
|
16
16
|
const sections = [];
|
|
17
17
|
for (const id of ids) {
|
|
@@ -28,4 +28,6 @@ export function buildTrendsDashboard(opts = {}) {
|
|
|
28
28
|
sections,
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
/** @deprecated Use buildMixDashboard. */
|
|
32
|
+
export const buildTrendsDashboard = buildMixDashboard;
|
|
33
|
+
export { analyticsWindow, analyticsWindow as trendsWindow, runRecipe, RECIPE_IDS, };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counter / warehouse mix recipes under `agents insights`.
|
|
3
|
+
*
|
|
4
|
+
* These used to live as the top-level `agents trends` tree. That name was a
|
|
5
|
+
* peer of `agents insights` with overlapping "analytics" meaning, so agents and
|
|
6
|
+
* humans kept picking the wrong verb. The cheap counter path (sessions index +
|
|
7
|
+
* usage.db) still exists — it is now `agents insights mix` and the recipe
|
|
8
|
+
* subcommands below. Latency stays on `agents perf`; quota on `agents usage`.
|
|
9
|
+
*
|
|
10
|
+
* `agents trends` remains a thin deprecated alias registered from
|
|
11
|
+
* `commands/trends.ts` that shares this same registration — no second copy of
|
|
12
|
+
* the recipe tree.
|
|
13
|
+
*/
|
|
14
|
+
import type { Command } from 'commander';
|
|
15
|
+
export declare function parseMixDays(raw: string | undefined): number;
|
|
16
|
+
export declare function printMixSection(section: {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
rows: Array<Record<string, string | number | null>>;
|
|
20
|
+
}): void;
|
|
21
|
+
export declare function renderMixDashboard(days: number, asJson: boolean, bannerLabel?: string): void;
|
|
22
|
+
/** One-line deprecation for the retired top-level `agents trends` spelling. */
|
|
23
|
+
export declare function printTrendsDeprecation(): void;
|
|
24
|
+
export interface RegisterMixCommandsOptions {
|
|
25
|
+
/**
|
|
26
|
+
* When true, every action prints the trends deprecation line first. Used only
|
|
27
|
+
* by the thin top-level `agents trends` alias — the real tree under insights
|
|
28
|
+
* never sets this.
|
|
29
|
+
*/
|
|
30
|
+
deprecated?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Banner label for the multi-recipe dashboard (default: agents insights mix).
|
|
33
|
+
* The deprecated alias passes `agents insights mix` still, so callers learn
|
|
34
|
+
* the new name even when they typed trends.
|
|
35
|
+
*/
|
|
36
|
+
dashboardBanner?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Attach counter-mix subcommands to a parent (typically `insights` or the
|
|
40
|
+
* deprecated `trends` alias).
|
|
41
|
+
*
|
|
42
|
+
* Layout:
|
|
43
|
+
* <parent> mix multi-recipe board (default for trends alias)
|
|
44
|
+
* <parent> recipes list recipe ids
|
|
45
|
+
* <parent> query raw usage.db rows
|
|
46
|
+
* <parent> harness-mix|… one baked recipe
|
|
47
|
+
*/
|
|
48
|
+
export declare function registerMixCommands(parent: Command, opts?: RegisterMixCommandsOptions): void;
|
|
49
|
+
/**
|
|
50
|
+
* Thin top-level `agents trends` alias: same mix tree, deprecation on every path,
|
|
51
|
+
* default action = mix board (old `agents trends` with no subcommand).
|
|
52
|
+
*/
|
|
53
|
+
export declare function registerDeprecatedTrendsAlias(program: Command): void;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counter / warehouse mix recipes under `agents insights`.
|
|
3
|
+
*
|
|
4
|
+
* These used to live as the top-level `agents trends` tree. That name was a
|
|
5
|
+
* peer of `agents insights` with overlapping "analytics" meaning, so agents and
|
|
6
|
+
* humans kept picking the wrong verb. The cheap counter path (sessions index +
|
|
7
|
+
* usage.db) still exists — it is now `agents insights mix` and the recipe
|
|
8
|
+
* subcommands below. Latency stays on `agents perf`; quota on `agents usage`.
|
|
9
|
+
*
|
|
10
|
+
* `agents trends` remains a thin deprecated alias registered from
|
|
11
|
+
* `commands/trends.ts` that shares this same registration — no second copy of
|
|
12
|
+
* the recipe tree.
|
|
13
|
+
*/
|
|
14
|
+
import chalk from 'chalk';
|
|
15
|
+
import { setHelpSections } from '../help.js';
|
|
16
|
+
import { buildMixDashboard, analyticsWindow, runRecipe, RECIPE_IDS, } from './dashboard.js';
|
|
17
|
+
import { listRecipes } from './recipes.js';
|
|
18
|
+
import { queryUsage, usageDbPath, USAGE_KINDS } from './usage-db.js';
|
|
19
|
+
export function parseMixDays(raw) {
|
|
20
|
+
const n = parseInt(raw ?? '7', 10);
|
|
21
|
+
return Number.isFinite(n) && n > 0 ? n : 7;
|
|
22
|
+
}
|
|
23
|
+
function parseLimit(raw, fallback) {
|
|
24
|
+
const n = parseInt(raw ?? String(fallback), 10);
|
|
25
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
26
|
+
}
|
|
27
|
+
export function printMixSection(section) {
|
|
28
|
+
console.log(chalk.bold(section.title));
|
|
29
|
+
if (section.rows.length === 0) {
|
|
30
|
+
console.log(chalk.gray(' (no data)'));
|
|
31
|
+
console.log();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const keys = Object.keys(section.rows[0]);
|
|
35
|
+
const widths = keys.map((k) => Math.max(k.length, ...section.rows.map((r) => String(r[k] ?? '').length), 4));
|
|
36
|
+
const pad = (s, w) => (s.length >= w ? s.slice(0, w) : s + ' '.repeat(w - s.length));
|
|
37
|
+
console.log(chalk.gray(keys.map((k, i) => pad(k.toUpperCase(), widths[i])).join(' ')));
|
|
38
|
+
for (const row of section.rows) {
|
|
39
|
+
console.log(keys.map((k, i) => pad(String(row[k] ?? ''), widths[i])).join(' '));
|
|
40
|
+
}
|
|
41
|
+
console.log();
|
|
42
|
+
}
|
|
43
|
+
export function renderMixDashboard(days, asJson, bannerLabel = 'agents insights mix') {
|
|
44
|
+
const dash = buildMixDashboard({ days });
|
|
45
|
+
if (asJson) {
|
|
46
|
+
console.log(JSON.stringify(dash, null, 2));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
console.log(chalk.bold(`${bannerLabel} — last ${dash.window.days} days`));
|
|
50
|
+
console.log(chalk.gray(`compute ${dash.durationMs}ms · usage ${usageDbPath()}`));
|
|
51
|
+
console.log();
|
|
52
|
+
if (dash.sections.length === 0) {
|
|
53
|
+
console.log(chalk.gray('No session or usage data in this window yet.'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
for (const section of dash.sections)
|
|
57
|
+
printMixSection(section);
|
|
58
|
+
}
|
|
59
|
+
/** One-line deprecation for the retired top-level `agents trends` spelling. */
|
|
60
|
+
export function printTrendsDeprecation() {
|
|
61
|
+
console.error(chalk.yellow('agents trends is deprecated — use `agents insights mix` (or `agents insights <recipe>`).'));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Attach counter-mix subcommands to a parent (typically `insights` or the
|
|
65
|
+
* deprecated `trends` alias).
|
|
66
|
+
*
|
|
67
|
+
* Layout:
|
|
68
|
+
* <parent> mix multi-recipe board (default for trends alias)
|
|
69
|
+
* <parent> recipes list recipe ids
|
|
70
|
+
* <parent> query raw usage.db rows
|
|
71
|
+
* <parent> harness-mix|… one baked recipe
|
|
72
|
+
*/
|
|
73
|
+
export function registerMixCommands(parent, opts = {}) {
|
|
74
|
+
const before = () => {
|
|
75
|
+
if (opts.deprecated)
|
|
76
|
+
printTrendsDeprecation();
|
|
77
|
+
};
|
|
78
|
+
const banner = opts.dashboardBanner ?? 'agents insights mix';
|
|
79
|
+
const mix = parent
|
|
80
|
+
.command('mix')
|
|
81
|
+
.description('Counter recipes — harness/model mix, token ratios, resource frequency (sessions index + usage.db)')
|
|
82
|
+
.option('--days <n>', 'Days of history to include', '7')
|
|
83
|
+
.option('--json', 'Emit JSON instead of tables')
|
|
84
|
+
.action(function summary() {
|
|
85
|
+
before();
|
|
86
|
+
const o = this.opts();
|
|
87
|
+
renderMixDashboard(parseMixDays(o.days), Boolean(o.json), banner);
|
|
88
|
+
});
|
|
89
|
+
setHelpSections(mix, {
|
|
90
|
+
examples: `
|
|
91
|
+
# Auto recipe board (7d)
|
|
92
|
+
agents insights mix
|
|
93
|
+
|
|
94
|
+
# Last 30 days
|
|
95
|
+
agents insights mix --days 30
|
|
96
|
+
|
|
97
|
+
# One recipe as JSON
|
|
98
|
+
agents insights harness-mix --json
|
|
99
|
+
|
|
100
|
+
# Raw usage events
|
|
101
|
+
agents insights query --kind secret --days 7
|
|
102
|
+
|
|
103
|
+
# List baked recipe ids
|
|
104
|
+
agents insights recipes
|
|
105
|
+
`,
|
|
106
|
+
notes: `
|
|
107
|
+
Session recipes read sessions.db; resource recipes read ~/.agents/.history/analytics/usage.db.
|
|
108
|
+
Empty recipes are skipped on the default mix board.
|
|
109
|
+
This is the cheap counter path. Behavioural report (transcript content, account split)
|
|
110
|
+
is bare \`agents insights\`. Latency is \`agents perf\`; quota is \`agents usage\`.
|
|
111
|
+
Skill/slash-command popularity is \`agents sessions stats\`.
|
|
112
|
+
`,
|
|
113
|
+
});
|
|
114
|
+
parent.command('recipes')
|
|
115
|
+
.description('List baked mix-recipe ids')
|
|
116
|
+
.option('--json', 'Emit JSON')
|
|
117
|
+
.action((o) => {
|
|
118
|
+
before();
|
|
119
|
+
const list = listRecipes();
|
|
120
|
+
if (o.json) {
|
|
121
|
+
console.log(JSON.stringify(list, null, 2));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
for (const r of list) {
|
|
125
|
+
console.log(`${r.id.padEnd(22)} ${r.store.padEnd(10)} ${r.title}`);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
parent.command('query')
|
|
129
|
+
.description('Raw usage-event query (usage.db)')
|
|
130
|
+
.option('--kind <kind>', `One of: ${USAGE_KINDS.join(', ')}`)
|
|
131
|
+
.option('--name <name>', 'Resource name filter')
|
|
132
|
+
.option('--event <event>', 'Event name filter')
|
|
133
|
+
.option('--days <n>', 'Days of history', '7')
|
|
134
|
+
.option('--limit <n>', 'Max rows', '40')
|
|
135
|
+
.option('--json', 'Emit JSON')
|
|
136
|
+
.action((o) => {
|
|
137
|
+
before();
|
|
138
|
+
const win = analyticsWindow(parseMixDays(o.days));
|
|
139
|
+
const kind = o.kind && USAGE_KINDS.includes(o.kind)
|
|
140
|
+
? o.kind
|
|
141
|
+
: undefined;
|
|
142
|
+
if (o.kind && !kind) {
|
|
143
|
+
console.error(`Unknown kind '${o.kind}'. Expected: ${USAGE_KINDS.join(', ')}`);
|
|
144
|
+
process.exitCode = 1;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const rows = queryUsage({
|
|
148
|
+
kind,
|
|
149
|
+
name: o.name,
|
|
150
|
+
event: o.event,
|
|
151
|
+
sinceIso: win.sinceIso,
|
|
152
|
+
limit: parseLimit(o.limit, 40),
|
|
153
|
+
});
|
|
154
|
+
if (o.json) {
|
|
155
|
+
console.log(JSON.stringify({ window: win, rows }, null, 2));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (rows.length === 0) {
|
|
159
|
+
console.log(chalk.gray('No usage events.'));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
printMixSection({
|
|
163
|
+
id: 'query',
|
|
164
|
+
title: 'Usage events',
|
|
165
|
+
rows: rows.map((r) => ({
|
|
166
|
+
ts: r.ts,
|
|
167
|
+
kind: r.kind,
|
|
168
|
+
name: r.name,
|
|
169
|
+
event: r.event,
|
|
170
|
+
agent: r.agent,
|
|
171
|
+
})),
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
for (const id of RECIPE_IDS) {
|
|
175
|
+
parent.command(id)
|
|
176
|
+
.description(`Mix recipe: ${id}`)
|
|
177
|
+
.option('--days <n>', 'Days of history', '7')
|
|
178
|
+
.option('--json', 'Emit JSON')
|
|
179
|
+
.action(function recipeAction() {
|
|
180
|
+
before();
|
|
181
|
+
const parentOpts = this.parent?.opts?.();
|
|
182
|
+
const o = { ...parentOpts, ...this.opts() };
|
|
183
|
+
const win = analyticsWindow(parseMixDays(o.days));
|
|
184
|
+
const section = runRecipe(id, win);
|
|
185
|
+
if (o.json) {
|
|
186
|
+
console.log(JSON.stringify({ window: win, section }, null, 2));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (section.empty) {
|
|
190
|
+
console.log(chalk.gray(`No data for recipe '${id}' in the last ${win.days} days.`));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
printMixSection(section);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Thin top-level `agents trends` alias: same mix tree, deprecation on every path,
|
|
199
|
+
* default action = mix board (old `agents trends` with no subcommand).
|
|
200
|
+
*/
|
|
201
|
+
export function registerDeprecatedTrendsAlias(program) {
|
|
202
|
+
const trends = program
|
|
203
|
+
.command('trends')
|
|
204
|
+
.description('Deprecated alias of `agents insights mix` — counter recipes over sessions + usage.db')
|
|
205
|
+
.option('--days <n>', 'Days of history to include', '7')
|
|
206
|
+
.option('--json', 'Emit JSON instead of tables')
|
|
207
|
+
.action(function summary() {
|
|
208
|
+
printTrendsDeprecation();
|
|
209
|
+
const o = this.opts();
|
|
210
|
+
renderMixDashboard(parseMixDays(o.days), Boolean(o.json), 'agents insights mix');
|
|
211
|
+
});
|
|
212
|
+
setHelpSections(trends, {
|
|
213
|
+
examples: `
|
|
214
|
+
# Prefer the canonical spelling
|
|
215
|
+
agents insights mix
|
|
216
|
+
|
|
217
|
+
# Still works (prints a deprecation line)
|
|
218
|
+
agents trends
|
|
219
|
+
agents trends harness-mix --json
|
|
220
|
+
`,
|
|
221
|
+
notes: `
|
|
222
|
+
\`agents trends\` is a compatibility alias. New code and agent briefs should use
|
|
223
|
+
\`agents insights mix\` / \`agents insights <recipe>\`. Behavioural report remains
|
|
224
|
+
bare \`agents insights\`. Latency remains \`agents perf\`.
|
|
225
|
+
`,
|
|
226
|
+
});
|
|
227
|
+
// Same subcommands as insights, with deprecation on every fire.
|
|
228
|
+
registerMixCommands(trends, { deprecated: true, dashboardBanner: 'agents insights mix' });
|
|
229
|
+
}
|