@phnx-labs/agents-cli 1.22.21 → 1.22.23
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 +256 -0
- package/README.md +8 -2
- package/dist/commands/doctor.js +15 -7
- package/dist/commands/exec.js +20 -6
- package/dist/commands/focus.d.ts +76 -4
- package/dist/commands/focus.js +219 -40
- package/dist/commands/fork.d.ts +20 -2
- package/dist/commands/fork.js +91 -64
- package/dist/commands/go.d.ts +25 -0
- package/dist/commands/go.js +63 -2
- package/dist/commands/harness-wizard.d.ts +206 -0
- package/dist/commands/harness-wizard.js +403 -0
- package/dist/commands/harness.d.ts +12 -0
- package/dist/commands/harness.js +97 -101
- package/dist/commands/insights.d.ts +32 -0
- package/dist/commands/insights.js +478 -0
- package/dist/commands/resume.js +10 -3
- package/dist/commands/secrets.js +25 -30
- package/dist/commands/sessions-picker.d.ts +2 -0
- package/dist/commands/sessions-picker.js +1 -0
- package/dist/commands/sessions-resume.d.ts +21 -3
- package/dist/commands/sessions-resume.js +50 -11
- package/dist/commands/sessions.d.ts +81 -5
- package/dist/commands/sessions.js +331 -66
- package/dist/commands/watchdog.js +13 -2
- package/dist/index.js +3 -1
- package/dist/lib/agents.d.ts +1 -1
- package/dist/lib/agents.js +132 -0
- package/dist/lib/codex-policy.d.ts +17 -0
- package/dist/lib/codex-policy.js +48 -0
- package/dist/lib/crabbox/lease.d.ts +25 -0
- package/dist/lib/crabbox/lease.js +62 -0
- package/dist/lib/daemon.js +70 -0
- package/dist/lib/exec.d.ts +4 -0
- package/dist/lib/exec.js +88 -54
- package/dist/lib/feed-broadcast.d.ts +1 -20
- package/dist/lib/feed-broadcast.js +31 -1
- package/dist/lib/hooks.js +12 -2
- package/dist/lib/hosts/passthrough.js +1 -0
- package/dist/lib/mcp.js +44 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +1 -5
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -15
- package/dist/lib/models.d.ts +0 -5
- package/dist/lib/models.js +48 -0
- package/dist/lib/picker.d.ts +45 -0
- package/dist/lib/picker.js +75 -6
- package/dist/lib/plugin-marketplace.js +9 -0
- package/dist/lib/pricing/prices.json +119 -92
- package/dist/lib/pricing/table.js +13 -0
- package/dist/lib/remote-agents-json.d.ts +29 -1
- package/dist/lib/remote-agents-json.js +47 -10
- package/dist/lib/resources/mcp.js +2 -0
- package/dist/lib/resources/permissions.js +3 -0
- package/dist/lib/resources/types.d.ts +2 -1
- package/dist/lib/runner.js +28 -19
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -2
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +1 -13
- package/dist/lib/secrets/index.d.ts +15 -1
- package/dist/lib/secrets/index.js +118 -49
- package/dist/lib/secrets/reaper.d.ts +87 -0
- package/dist/lib/secrets/reaper.js +184 -0
- package/dist/lib/secrets/remote.d.ts +29 -0
- package/dist/lib/secrets/remote.js +37 -1
- package/dist/lib/session/active.d.ts +36 -1
- package/dist/lib/session/active.js +60 -19
- package/dist/lib/session/actor-sidecar.d.ts +14 -0
- package/dist/lib/session/actor-sidecar.js +67 -4
- package/dist/lib/session/db.d.ts +35 -1
- package/dist/lib/session/db.js +132 -1
- package/dist/lib/session/digest.d.ts +3 -0
- package/dist/lib/session/digest.js +3 -3
- package/dist/lib/session/discover.js +168 -0
- package/dist/lib/session/insights.d.ts +126 -0
- package/dist/lib/session/insights.js +330 -0
- package/dist/lib/session/parse.d.ts +29 -2
- package/dist/lib/session/parse.js +111 -5
- package/dist/lib/session/remote-list.d.ts +10 -1
- package/dist/lib/session/remote-list.js +2 -8
- package/dist/lib/session/remote.d.ts +57 -3
- package/dist/lib/session/remote.js +90 -26
- package/dist/lib/session/resume-command.d.ts +6 -0
- package/dist/lib/session/resume-command.js +8 -0
- package/dist/lib/session/session-cache.d.ts +173 -0
- package/dist/lib/session/session-cache.js +399 -0
- package/dist/lib/session/types.d.ts +2 -2
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/session/width.d.ts +1 -1
- package/dist/lib/session/width.js +12 -2
- package/dist/lib/shims.d.ts +2 -2
- package/dist/lib/shims.js +40 -5
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -0
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/usage.d.ts +13 -0
- package/dist/lib/usage.js +254 -3
- package/dist/lib/versions.js +13 -2
- package/package.json +1 -1
- package/dist/bin/agents +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
package/dist/commands/harness.js
CHANGED
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
import chalk from 'chalk';
|
|
14
14
|
import { addProfile, ensureProviderToken, applyFromSecrets } from './profiles.js';
|
|
15
15
|
import { isInteractiveTerminal } from './utils.js';
|
|
16
|
-
import { listProfiles, readProfile, writeProfile, deleteProfile, profileExists, profileHostLabel, profileProviderLabel, profileModelLabel, profileAuthLabel, profileLabel, forkProfile, editProfile, renameProfile, profileFromHostModel, authEnvKeyForHost, getProfilePath, validateProfileName, } from '../lib/profiles.js';
|
|
16
|
+
import { listProfiles, readProfile, writeProfile, deleteProfile, profileExists, profileHostLabel, profileProviderLabel, profileModelLabel, profileAuthLabel, profileLabel, forkProfile, editProfile, renameProfile, profileFromHostModel, authEnvKeyForHost, modelEnvKeyForHost, baseUrlEnvKeyForHost, getProfilePath, validateProfileName, } from '../lib/profiles.js';
|
|
17
17
|
import { listPresets, getPreset } from '../lib/profiles-presets.js';
|
|
18
|
-
import { listBundles } from '../lib/secrets/bundles.js';
|
|
19
18
|
import { AGENTS, ALL_AGENT_IDS, resolveAgentName } from '../lib/agents.js';
|
|
19
|
+
import { runWizardSteps, createSteps, editSteps, defaultWizardIO, } from './harness-wizard.js';
|
|
20
20
|
/** Short capability summary for a native harness — its supported run modes. */
|
|
21
21
|
function nativeModes(id) {
|
|
22
22
|
const modes = AGENTS[id]?.capabilities?.modes ?? [];
|
|
@@ -193,108 +193,93 @@ async function runForkFlow(source, name, opts) {
|
|
|
193
193
|
console.log(chalk.green(`Harness '${name}' forked from ${source}.`));
|
|
194
194
|
console.log(chalk.gray(`Try: agents run ${name} "hello"`));
|
|
195
195
|
}
|
|
196
|
-
/** The first `_MODEL`-suffixed env var in a preset's static env block, if any. */
|
|
197
|
-
function presetModel(preset) {
|
|
198
|
-
return Object.entries(preset.env).find(([k]) => k.endsWith('_MODEL'))?.[1];
|
|
199
|
-
}
|
|
200
196
|
/**
|
|
201
197
|
* Interactive `agents harness add`/`fork` wizard — runs when required info is
|
|
202
|
-
* missing and stdout
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* build an
|
|
198
|
+
* missing and stdin+stdout are a TTY (see {@link forkNeedsWizard}, {@link addNeedsWizard}).
|
|
199
|
+
* Drives the shared step engine ({@link createSteps}) and maps its finished draft
|
|
200
|
+
* back to the same `(source, name, opts)` shape {@link buildFork} accepts via
|
|
201
|
+
* {@link runForkFlow}, so a wizard run and a hand-written fork call build an
|
|
202
|
+
* identical profile.
|
|
206
203
|
*/
|
|
207
|
-
async function
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
baseUrl =
|
|
204
|
+
async function runCreateWizard() {
|
|
205
|
+
const io = await defaultWizardIO();
|
|
206
|
+
const draft = await runWizardSteps(createSteps(), { mode: 'create' }, io);
|
|
207
|
+
return {
|
|
208
|
+
source: draft.source,
|
|
209
|
+
name: draft.name,
|
|
210
|
+
opts: {
|
|
211
|
+
model: draft.model,
|
|
212
|
+
baseUrl: draft.baseUrl,
|
|
213
|
+
authProvider: draft.authProvider,
|
|
214
|
+
fromSecrets: draft.fromSecrets,
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Map a finished edit-wizard draft onto {@link EditOptions}, keeping only the
|
|
220
|
+
* fields the user actually changed from the profile's current values. Unchanged
|
|
221
|
+
* accepts (the wizard pre-fills each prompt with the current value) drop out, so
|
|
222
|
+
* the resulting {@link buildEdit} touches nothing the user left alone — and the
|
|
223
|
+
* "no changes" case is detectable via {@link hasEditFlags}. Base-URL clearing is
|
|
224
|
+
* intentionally not expressed here: the flag path can't clear it either (an empty
|
|
225
|
+
* `--base-url` is a no-op in `forkProfile`), so the wizard matches that until a
|
|
226
|
+
* later subtask adds explicit clearing.
|
|
227
|
+
*/
|
|
228
|
+
export function draftToEditOptions(draft, original) {
|
|
229
|
+
const host = original.host.agent;
|
|
230
|
+
const curModel = original.env[modelEnvKeyForHost(host)];
|
|
231
|
+
const baseKey = baseUrlEnvKeyForHost(host);
|
|
232
|
+
const curBaseUrl = baseKey ? original.env[baseKey] : undefined;
|
|
233
|
+
const curVersion = original.host.version ?? '';
|
|
234
|
+
const curFallback = original.fallback_model ?? '';
|
|
235
|
+
const curDescription = original.description ?? '';
|
|
236
|
+
const opts = {};
|
|
237
|
+
if (draft.model !== undefined && draft.model !== curModel)
|
|
238
|
+
opts.model = draft.model;
|
|
239
|
+
if (draft.baseUrl && draft.baseUrl !== curBaseUrl)
|
|
240
|
+
opts.baseUrl = draft.baseUrl;
|
|
241
|
+
if (draft.authProvider !== undefined)
|
|
242
|
+
opts.authProvider = draft.authProvider;
|
|
243
|
+
if (draft.fromSecrets !== undefined)
|
|
244
|
+
opts.fromSecrets = draft.fromSecrets;
|
|
245
|
+
if (draft.version !== undefined && draft.version !== curVersion)
|
|
246
|
+
opts.version = draft.version;
|
|
247
|
+
if (draft.fallbackModel !== undefined && draft.fallbackModel !== curFallback)
|
|
248
|
+
opts.fallbackModel = draft.fallbackModel;
|
|
249
|
+
if (draft.description !== undefined && draft.description !== curDescription)
|
|
250
|
+
opts.description = draft.description;
|
|
251
|
+
return opts;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Interactive `agents harness edit <name>` wizard — runs when no edit flags were
|
|
255
|
+
* given and stdin+stdout are a TTY. Loads the profile, drives the shared step
|
|
256
|
+
* engine ({@link editSteps}) pre-filled with current values, then persists via the
|
|
257
|
+
* same build+write path as the flag-driven edit. `--key-stdin` is honored for the
|
|
258
|
+
* auth step's key entry. When the user changes nothing, it says so and writes
|
|
259
|
+
* nothing.
|
|
260
|
+
*/
|
|
261
|
+
async function runEditWizard(name, cliOpts) {
|
|
262
|
+
if (!profileExists(name)) {
|
|
263
|
+
throw new Error(`Harness '${name}' not found. Create it first: agents harness add ${name} ...`);
|
|
244
264
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
defaultName = preset.name;
|
|
265
|
+
const original = readProfile(name);
|
|
266
|
+
const io = await defaultWizardIO();
|
|
267
|
+
const draft = await runWizardSteps(editSteps(original), { mode: 'edit', original, host: original.host.agent, name }, io);
|
|
268
|
+
const opts = { ...draftToEditOptions(draft, original), keyStdin: cliOpts.keyStdin };
|
|
269
|
+
if (!hasEditFlags(opts)) {
|
|
270
|
+
console.log(chalk.gray(`No changes made to '${name}'.`));
|
|
271
|
+
return;
|
|
253
272
|
}
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return true;
|
|
261
|
-
}
|
|
262
|
-
catch (err) {
|
|
263
|
-
return err.message;
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
const opts = { model, baseUrl, authProvider };
|
|
268
|
-
if (authProvider) {
|
|
269
|
-
const bundles = listBundles();
|
|
270
|
-
const TYPE_NOW = 'type';
|
|
271
|
-
const FROM_SECRETS = 'secrets';
|
|
272
|
-
const keySource = bundles.length > 0
|
|
273
|
-
? await select({
|
|
274
|
-
message: `How should '${authProvider}' get its key?`,
|
|
275
|
-
choices: [
|
|
276
|
-
{ name: 'Type a key now', value: TYPE_NOW },
|
|
277
|
-
{ name: 'Use an existing agents secrets bundle', value: FROM_SECRETS },
|
|
278
|
-
],
|
|
279
|
-
})
|
|
280
|
-
: TYPE_NOW;
|
|
281
|
-
if (keySource === FROM_SECRETS) {
|
|
282
|
-
const bundleName = await select({
|
|
283
|
-
message: 'Bundle',
|
|
284
|
-
choices: bundles.map((b) => ({
|
|
285
|
-
name: b.description ? `${b.name} ${chalk.gray(b.description)}` : b.name,
|
|
286
|
-
value: b.name,
|
|
287
|
-
})),
|
|
288
|
-
});
|
|
289
|
-
const bundle = bundles.find((b) => b.name === bundleName);
|
|
290
|
-
const keys = Object.keys(bundle.vars);
|
|
291
|
-
const key = keys.length === 1
|
|
292
|
-
? keys[0]
|
|
293
|
-
: await select({ message: 'Key', choices: keys.map((k) => ({ name: k, value: k })) });
|
|
294
|
-
opts.fromSecrets = `${bundleName}:${key}`;
|
|
295
|
-
}
|
|
273
|
+
const edited = buildEdit(name, opts);
|
|
274
|
+
if (opts.fromSecrets) {
|
|
275
|
+
await applyFromSecrets(edited, opts.fromSecrets, opts.authProvider);
|
|
276
|
+
}
|
|
277
|
+
else if (opts.authProvider) {
|
|
278
|
+
await ensureProviderToken(opts.authProvider, undefined, opts.keyStdin);
|
|
296
279
|
}
|
|
297
|
-
|
|
280
|
+
writeProfile(edited);
|
|
281
|
+
console.log(chalk.green(`Harness '${name}' updated.`));
|
|
282
|
+
console.log(chalk.gray(`Model: ${profileModelLabel(edited)}`));
|
|
298
283
|
}
|
|
299
284
|
export function registerHarnessCommands(program) {
|
|
300
285
|
const cmd = program
|
|
@@ -354,7 +339,7 @@ Examples:
|
|
|
354
339
|
if (!isInteractiveTerminal()) {
|
|
355
340
|
throw new Error("'agents harness add' needs --preset or --host + --model (or a name and an interactive terminal for the wizard).");
|
|
356
341
|
}
|
|
357
|
-
const wiz = await
|
|
342
|
+
const wiz = await runCreateWizard();
|
|
358
343
|
await runForkFlow(wiz.source, wiz.name, { ...wiz.opts, force: opts.force, keyStdin: opts.keyStdin });
|
|
359
344
|
return;
|
|
360
345
|
}
|
|
@@ -399,7 +384,7 @@ Examples:
|
|
|
399
384
|
if (!isInteractiveTerminal()) {
|
|
400
385
|
throw new Error("'agents harness fork' needs <source> and <name> (or an interactive terminal for the wizard).");
|
|
401
386
|
}
|
|
402
|
-
const wiz = await
|
|
387
|
+
const wiz = await runCreateWizard();
|
|
403
388
|
await runForkFlow(wiz.source, wiz.name, { ...wiz.opts, force: opts.force, keyStdin: opts.keyStdin });
|
|
404
389
|
return;
|
|
405
390
|
}
|
|
@@ -412,7 +397,7 @@ Examples:
|
|
|
412
397
|
});
|
|
413
398
|
cmd
|
|
414
399
|
.command('edit <name>')
|
|
415
|
-
.description('Edit an existing custom harness in place — model, endpoint, auth, version, description, fallback.')
|
|
400
|
+
.description('Edit an existing custom harness in place — model, endpoint, auth, version, description, fallback. Omit flags in a terminal for the interactive wizard.')
|
|
416
401
|
.option('--model <id>', 'Swap the pinned model')
|
|
417
402
|
.option('--base-url <url>', 'Swap the custom endpoint base URL')
|
|
418
403
|
.option('--auth-provider <provider>', 'Repoint auth at a different provider (keychain-backed)')
|
|
@@ -437,9 +422,20 @@ Examples:
|
|
|
437
422
|
|
|
438
423
|
# Copy a key out of an existing secrets bundle instead of typing it
|
|
439
424
|
agents harness edit corp --from-secrets prod:OPENROUTER_KEY
|
|
425
|
+
|
|
426
|
+
# No flags, in an interactive terminal: a wizard walks each field pre-filled
|
|
427
|
+
agents harness edit deepseek
|
|
440
428
|
`)
|
|
441
429
|
.action(async (name, opts) => {
|
|
442
430
|
try {
|
|
431
|
+
// No edit flags + a real terminal → the interactive wizard, pre-filled
|
|
432
|
+
// with current values. Any flag (or a non-interactive caller) takes the
|
|
433
|
+
// flag path unchanged; a flagless non-interactive call still errors via
|
|
434
|
+
// buildEdit's EDIT_FLAGS_HELP.
|
|
435
|
+
if (!hasEditFlags(opts) && isInteractiveTerminal()) {
|
|
436
|
+
await runEditWizard(name, opts);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
443
439
|
const edited = buildEdit(name, opts);
|
|
444
440
|
if (opts.fromSecrets) {
|
|
445
441
|
await applyFromSecrets(edited, opts.fromSecrets, opts.authProvider);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Insights command — how you actually work, split by the account that did the work.
|
|
3
|
+
*
|
|
4
|
+
* The behavioural sibling of the existing rollups, and deliberately not a duplicate of
|
|
5
|
+
* any of them:
|
|
6
|
+
*
|
|
7
|
+
* agents cost what you spent ($ and duration)
|
|
8
|
+
* agents output what shipped (burn vs PRs and commits)
|
|
9
|
+
* agents usage live quota headroom (rate-limit windows, right now)
|
|
10
|
+
* agents trends aggregate distributions (harness mix, tools-per-session, token ratios)
|
|
11
|
+
* agents sessions browse individual work (search, resume, render)
|
|
12
|
+
* agents insights HOW you work (tools, friction, rhythm, per account)
|
|
13
|
+
*
|
|
14
|
+
* The closest neighbour is `agents trends`, and the boundary is the data path: trends
|
|
15
|
+
* reads counters — `tool_scan_ledger` call counts and the analytics warehouse — to
|
|
16
|
+
* produce distributions ("how many tool calls per session, by harness"). This reads
|
|
17
|
+
* transcript CONTENT through `parseSession` to produce behaviour ("which tools, which
|
|
18
|
+
* languages, where it went wrong, when you were working"), and splits all of it by
|
|
19
|
+
* account, a dimension trends does not have. They overlap in spirit on tool and model
|
|
20
|
+
* mix; they do not read the same store or answer the same question.
|
|
21
|
+
*
|
|
22
|
+
* Modelled on Claude Code's `/insights`, with the difference that motivated it: that
|
|
23
|
+
* command reads one account's directory, while `balanced` rotation sprays sessions
|
|
24
|
+
* across every signed-in account. This reads the whole index and reports the accounts
|
|
25
|
+
* apart — see lib/session/claude-accounts.ts for how a transcript is attributed.
|
|
26
|
+
*
|
|
27
|
+
* The deterministic report makes zero network calls. `--narrative` is opt-in and adds
|
|
28
|
+
* the coaching prose by piping the AGGREGATE (never raw transcripts) through a headless
|
|
29
|
+
* `claude -p`.
|
|
30
|
+
*/
|
|
31
|
+
import type { Command } from 'commander';
|
|
32
|
+
export declare function registerInsightsCommand(program: Command): void;
|