@phnx-labs/agents-cli 1.22.42 → 1.22.44
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 +149 -0
- package/README.md +15 -13
- package/dist/bootstrap.js +33 -13
- package/dist/cli/command-registry.d.ts +0 -8
- package/dist/cli/command-registry.js +1 -25
- package/dist/commands/alias.d.ts +7 -4
- package/dist/commands/alias.js +33 -8
- package/dist/commands/apply.d.ts +7 -10
- package/dist/commands/apply.js +15 -35
- package/dist/commands/artifacts.js +4 -5
- package/dist/commands/audit.d.ts +6 -6
- package/dist/commands/audit.js +12 -12
- package/dist/commands/auth.js +14 -6
- package/dist/commands/beta.d.ts +7 -1
- package/dist/commands/beta.js +16 -9
- package/dist/commands/commands.js +1 -1
- package/dist/commands/computer.js +20 -6
- package/dist/commands/daemon.js +1 -1
- package/dist/commands/doctor.d.ts +4 -2
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/events.d.ts +2 -2
- package/dist/commands/events.js +6 -5
- package/dist/commands/exec.d.ts +1 -1
- package/dist/commands/exec.js +11 -6
- package/dist/commands/factory.d.ts +1 -1
- package/dist/commands/feed.js +1 -30
- package/dist/commands/fleet-capture.d.ts +1 -1
- package/dist/commands/fleet-capture.js +4 -5
- package/dist/commands/harness.js +4 -52
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/insights.d.ts +1 -1
- package/dist/commands/insights.js +3 -2
- package/dist/commands/menubar.js +58 -1
- package/dist/commands/monitors.js +1 -1
- package/dist/commands/org.d.ts +5 -0
- package/dist/commands/org.js +83 -29
- package/dist/commands/output.js +2 -2
- package/dist/commands/profiles.js +2 -2
- package/dist/commands/prune.js +5 -4
- package/dist/commands/routines.js +43 -25
- package/dist/commands/routines.test-fixture.d.ts +86 -0
- package/dist/commands/routines.test-fixture.js +345 -0
- package/dist/commands/sessions-picker.js +124 -122
- package/dist/commands/sessions.test-fixture.d.ts +24 -0
- package/dist/commands/sessions.test-fixture.js +224 -0
- package/dist/commands/setup.js +9 -1
- package/dist/commands/share.d.ts +9 -10
- package/dist/commands/share.js +68 -50
- package/dist/commands/skills.js +1 -1
- package/dist/commands/snapshot.d.ts +1 -1
- package/dist/commands/snapshot.js +4 -4
- package/dist/commands/ssh.js +15 -62
- package/dist/commands/status.d.ts +4 -2
- package/dist/commands/status.js +10 -7
- package/dist/commands/subagents.js +1 -1
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +29 -2
- package/dist/commands/view.js +11 -2
- package/dist/commands/webhook.js +1 -1
- package/dist/lib/accounting/rotate.d.ts +5 -3
- package/dist/lib/accounting/rotate.js +36 -7
- package/dist/lib/accounting/usage.d.ts +18 -4
- package/dist/lib/accounting/usage.js +138 -27
- package/dist/lib/agent-spec/agents.d.ts +7 -7
- package/dist/lib/agent-spec/agents.js +15 -15
- package/dist/lib/analytics/mix-commands.d.ts +6 -28
- package/dist/lib/analytics/mix-commands.js +14 -40
- package/dist/lib/audit/log.d.ts +2 -2
- package/dist/lib/audit/log.js +2 -2
- package/dist/lib/beta.js +1 -1
- package/dist/lib/browser/domain-skills.d.ts +26 -6
- package/dist/lib/browser/domain-skills.js +81 -43
- package/dist/lib/cloud/rush.d.ts +0 -15
- package/dist/lib/cloud/rush.js +0 -35
- package/dist/lib/crabbox/runtimes.d.ts +6 -2
- package/dist/lib/crabbox/runtimes.js +21 -5
- package/dist/lib/daemon/daemon.js +97 -58
- package/dist/lib/daemon/daemon.test-fixture.d.ts +24 -0
- package/dist/lib/daemon/daemon.test-fixture.js +71 -0
- package/dist/lib/daemon/runner.d.ts +18 -1
- package/dist/lib/daemon/runner.js +105 -11
- package/dist/lib/daemon-ticks.d.ts +38 -1
- package/dist/lib/daemon-ticks.js +52 -5
- package/dist/lib/device-config.js +1 -2
- package/dist/lib/devices/discovery-policy.d.ts +3 -3
- package/dist/lib/devices/discovery-policy.js +3 -3
- package/dist/lib/devices/doctor-findings.js +1 -1
- package/dist/lib/devices/fleet.d.ts +4 -8
- package/dist/lib/devices/fleet.js +3 -15
- package/dist/lib/devices/health-report.js +4 -4
- package/dist/lib/devices/pool.d.ts +0 -6
- package/dist/lib/devices/pool.js +0 -6
- package/dist/lib/devices/registry.d.ts +0 -15
- package/dist/lib/devices/registry.js +0 -9
- package/dist/lib/devices/stats-cache.d.ts +12 -0
- package/dist/lib/devices/stats-cache.js +24 -5
- package/dist/lib/drift-sync.d.ts +1 -1
- package/dist/lib/drift-sync.js +2 -2
- package/dist/lib/drift.d.ts +1 -1
- package/dist/lib/exec.js +13 -3
- package/dist/lib/fleet/capture.d.ts +1 -1
- package/dist/lib/fleet/manifest.js +1 -1
- package/dist/lib/fleet/remote-login.d.ts +2 -2
- package/dist/lib/fleet/remote-login.js +3 -4
- package/dist/lib/format.d.ts +9 -0
- package/dist/lib/format.js +16 -0
- package/dist/lib/github/pr-mergeable.d.ts +49 -0
- package/dist/lib/github/pr-mergeable.js +157 -0
- package/dist/lib/github/pr-verdict.d.ts +67 -0
- package/dist/lib/github/pr-verdict.js +72 -0
- package/dist/lib/harness/adapter.d.ts +6 -5
- package/dist/lib/hosts/dispatch.d.ts +2 -0
- package/dist/lib/hosts/dispatch.js +8 -1
- package/dist/lib/hosts/passthrough.d.ts +10 -0
- package/dist/lib/hosts/passthrough.js +28 -7
- package/dist/lib/hosts/providers/devices.js +1 -13
- package/dist/lib/hosts/ready.d.ts +12 -3
- package/dist/lib/hosts/ready.js +27 -12
- package/dist/lib/hosts/registry.d.ts +4 -5
- package/dist/lib/hosts/registry.js +3 -7
- package/dist/lib/hosts/session-index.js +1 -1
- package/dist/lib/installations/shims.js +1 -1
- package/dist/lib/installations/versions.d.ts +40 -0
- package/dist/lib/installations/versions.js +78 -4
- 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/menubar/install-menubar.d.ts +109 -0
- package/dist/lib/menubar/install-menubar.js +218 -12
- package/dist/lib/monitors/config.d.ts +2 -2
- package/dist/lib/monitors/config.js +3 -2
- package/dist/lib/origin-machine.d.ts +18 -0
- package/dist/lib/origin-machine.js +34 -0
- package/dist/lib/perf/db.js +1 -1
- package/dist/lib/perf/spool.js +1 -1
- package/dist/lib/prix-account.d.ts +2 -1
- package/dist/lib/prix-account.js +2 -1
- package/dist/lib/profiles.d.ts +7 -0
- package/dist/lib/profiles.js +26 -1
- package/dist/lib/remote-agents-json.js +1 -7
- package/dist/lib/routines-placement.d.ts +1 -1
- package/dist/lib/routines-placement.js +1 -1
- package/dist/lib/sandbox.d.ts +24 -0
- package/dist/lib/sandbox.js +101 -0
- package/dist/lib/scheduling/routines.d.ts +18 -9
- package/dist/lib/scheduling/routines.js +16 -8
- 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/agent.js +9 -1
- package/dist/lib/secrets/index.js +1 -1
- package/dist/lib/secrets/list-filter.js +1 -1
- package/dist/lib/service-manifest.d.ts +20 -0
- package/dist/lib/service-manifest.js +34 -0
- package/dist/lib/session/active.d.ts +4 -16
- package/dist/lib/session/active.js +2 -6
- package/dist/lib/session/cloud.js +1 -1
- package/dist/lib/session/db.d.ts +13 -98
- package/dist/lib/session/db.js +5 -12
- package/dist/lib/session/discover.d.ts +5 -81
- package/dist/lib/session/discover.js +5 -5
- package/dist/lib/session/fork.js +1 -1
- package/dist/lib/session/live-metadata.js +1 -1
- package/dist/lib/session/origin-machine.d.ts +1 -18
- package/dist/lib/session/origin-machine.js +4 -34
- package/dist/lib/session/relative-time.d.ts +1 -44
- package/dist/lib/session/relative-time.js +4 -120
- package/dist/lib/session/remote/remote-bundle.d.ts +12 -0
- package/dist/lib/session/remote/remote-bundle.js +61 -0
- package/dist/lib/session/remote/remote-list.d.ts +148 -0
- package/dist/lib/session/remote/remote-list.js +607 -0
- package/dist/lib/session/remote/remote.d.ts +132 -0
- package/dist/lib/session/remote/remote.js +314 -0
- package/dist/lib/session/remote/watch.d.ts +101 -0
- package/dist/lib/session/remote/watch.js +241 -0
- package/dist/lib/session/remote-bundle.d.ts +1 -12
- package/dist/lib/session/remote-bundle.js +3 -61
- package/dist/lib/session/remote-list.d.ts +1 -148
- package/dist/lib/session/remote-list.js +3 -607
- package/dist/lib/session/remote.d.ts +1 -132
- package/dist/lib/session/remote.js +3 -314
- package/dist/lib/session/short-id.d.ts +1 -17
- package/dist/lib/session/short-id.js +4 -20
- package/dist/lib/session/watch.d.ts +1 -101
- package/dist/lib/session/watch.js +3 -242
- package/dist/lib/session/width.d.ts +1 -29
- package/dist/lib/session/width.js +4 -101
- package/dist/lib/share/config.d.ts +12 -2
- package/dist/lib/share/config.js +47 -11
- package/dist/lib/share/delete.js +1 -1
- package/dist/lib/share/publish.js +1 -1
- package/dist/lib/share/worker-template.js +2 -2
- package/dist/lib/smart-launch.d.ts +4 -4
- package/dist/lib/smart-launch.js +8 -18
- package/dist/lib/snapshot.d.ts +2 -2
- package/dist/lib/snapshot.js +1 -1
- package/dist/lib/staleness/index.d.ts +3 -1
- package/dist/lib/staleness/index.js +21 -1
- package/dist/lib/staleness/types.d.ts +11 -0
- package/dist/lib/staleness/writers/commands.js +13 -4
- package/dist/lib/staleness/writers/hooks.js +3 -1
- package/dist/lib/staleness/writers/mcp.d.ts +0 -7
- package/dist/lib/staleness/writers/mcp.js +16 -1
- package/dist/lib/staleness/writers/rules.js +1 -1
- package/dist/lib/staleness/writers/skills.js +3 -1
- package/dist/lib/staleness/writers/subagents.d.ts +0 -9
- package/dist/lib/staleness/writers/subagents.js +18 -1
- package/dist/lib/staleness/writers/types.d.ts +10 -0
- package/dist/lib/startup/command-registry.d.ts +10 -1
- package/dist/lib/startup/command-registry.js +26 -7
- package/dist/lib/startup/root-command.d.ts +18 -1
- package/dist/lib/startup/root-command.js +18 -1
- package/dist/lib/state.js +7 -0
- package/dist/lib/teams/placement-probe.js +28 -13
- package/dist/lib/teams/scheduler.d.ts +3 -1
- package/dist/lib/teams/scheduler.js +1 -1
- package/dist/lib/text/relative-time.d.ts +44 -0
- package/dist/lib/text/relative-time.js +120 -0
- package/dist/lib/text/short-id.d.ts +17 -0
- package/dist/lib/text/short-id.js +20 -0
- package/dist/lib/text/width.d.ts +29 -0
- package/dist/lib/text/width.js +101 -0
- package/dist/lib/triggers/handlers.d.ts +7 -0
- package/dist/lib/triggers/handlers.js +8 -0
- package/dist/lib/triggers/webhook.d.ts +1 -0
- package/dist/lib/triggers/webhook.js +2 -1
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/view-types.d.ts +7 -0
- package/package.json +2 -3
- package/dist/bin/agents +0 -0
- package/dist/commands/serve.d.ts +0 -10
- package/dist/commands/serve.js +0 -68
- package/dist/commands/tickets.d.ts +0 -2
- package/dist/commands/tickets.js +0 -43
- package/dist/commands/trends.d.ts +0 -10
- package/dist/commands/trends.js +0 -12
- 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/observe-aliases.d.ts +0 -30
- package/dist/lib/observe-aliases.js +0 -38
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/serve/control.d.ts +0 -95
- package/dist/lib/serve/control.js +0 -260
- package/dist/lib/serve/data.d.ts +0 -81
- package/dist/lib/serve/data.js +0 -91
- package/dist/lib/serve/page.d.ts +0 -7
- package/dist/lib/serve/page.js +0 -140
- package/dist/lib/serve/server.d.ts +0 -80
- package/dist/lib/serve/server.js +0 -145
- package/dist/lib/serve/stream.d.ts +0 -43
- package/dist/lib/serve/stream.js +0 -116
- package/dist/lib/serve/token.d.ts +0 -35
- package/dist/lib/serve/token.js +0 -85
- package/dist/lib/tickets/list.d.ts +0 -53
- package/dist/lib/tickets/list.js +0 -153
|
@@ -386,7 +386,7 @@ export function buildPreview(session) {
|
|
|
386
386
|
const header = formatHeader(safe, events);
|
|
387
387
|
const body = parseError
|
|
388
388
|
? ' ' + chalk.red(`Failed to parse session: ${parseError}`)
|
|
389
|
-
: formatCompactPreview(digest, safe);
|
|
389
|
+
: formatCompactPreview(digest, safe, events);
|
|
390
390
|
const output = [header, '', body].filter(Boolean).join('\n');
|
|
391
391
|
previewCache.set(cacheKey, output);
|
|
392
392
|
return output;
|
|
@@ -398,8 +398,6 @@ const DOT = chalk.gray(' · ');
|
|
|
398
398
|
function formatHeader(session, events) {
|
|
399
399
|
const model = extractModel(events) || session.model;
|
|
400
400
|
const { createdAgo, lastActiveAgo, duration } = extractTiming(session, events);
|
|
401
|
-
const totalMessages = session.messageCount ?? countMessages(events);
|
|
402
|
-
const totalTokens = session.tokenCount;
|
|
403
401
|
// Line 1: Agent v version · shortId · model · account
|
|
404
402
|
const line1 = [];
|
|
405
403
|
line1.push(chalk.gray(`${displayAgent(session.agent)}${session.version ? ` v${session.version}` : ''}`));
|
|
@@ -429,18 +427,6 @@ function formatHeader(session, events) {
|
|
|
429
427
|
line2.push(chalk.gray('last active ') + chalk.white(lastActiveAgo + ' ago'));
|
|
430
428
|
if (duration)
|
|
431
429
|
line2.push(chalk.gray('lasted ') + chalk.white(duration));
|
|
432
|
-
// Line 3: N msgs · T tokens · [label ·] uuid
|
|
433
|
-
const line3 = [];
|
|
434
|
-
if (totalMessages !== undefined) {
|
|
435
|
-
line3.push(chalk.bold.white(String(totalMessages)) + chalk.gray(` msg${totalMessages === 1 ? '' : 's'}`));
|
|
436
|
-
}
|
|
437
|
-
if (totalTokens !== undefined) {
|
|
438
|
-
line3.push(chalk.bold.white(formatTokens(totalTokens)) + chalk.gray(' tokens'));
|
|
439
|
-
}
|
|
440
|
-
if (session.filePath)
|
|
441
|
-
line3.push(chalk.gray(linkPath(session.filePath, session.id)));
|
|
442
|
-
else
|
|
443
|
-
line3.push(chalk.gray(session.id));
|
|
444
430
|
// Line 4: ticket + PR — clickable when a URL is resolvable (OSC 8 hyperlink),
|
|
445
431
|
// plain text otherwise. Only rendered when the session carries either.
|
|
446
432
|
const line4 = [];
|
|
@@ -467,7 +453,6 @@ function formatHeader(session, events) {
|
|
|
467
453
|
...titleLines,
|
|
468
454
|
line1.join(DOT),
|
|
469
455
|
line2.join(DOT),
|
|
470
|
-
line3.join(DOT),
|
|
471
456
|
...(line4.length ? [line4.join(DOT)] : []),
|
|
472
457
|
].join('\n');
|
|
473
458
|
}
|
|
@@ -512,24 +497,20 @@ export function formatTeamLineage(session) {
|
|
|
512
497
|
}
|
|
513
498
|
function formatMetaOnlyBody(session) {
|
|
514
499
|
const lines = [];
|
|
500
|
+
const termWidth = process.stdout.columns || 80;
|
|
501
|
+
const valueWidth = termWidth - VERB_GUTTER - 5;
|
|
502
|
+
// Same verb-led rows as the digest body (RUSH-2757), from SessionMeta alone.
|
|
515
503
|
if (session.topic) {
|
|
516
|
-
lines.push(
|
|
517
|
-
}
|
|
518
|
-
const teamLine = formatTeamLineage(session);
|
|
519
|
-
if (teamLine) {
|
|
520
|
-
lines.push(chalk.cyan('Team: ') + teamLine);
|
|
504
|
+
lines.push(verbLabel('Asked') + chalk.white(`"${truncate(session.topic.trim(), valueWidth)}"`));
|
|
521
505
|
}
|
|
522
506
|
const compact = formatTodoCompact(session.todos);
|
|
523
|
-
|
|
524
|
-
|
|
507
|
+
const teamLine = formatTeamLineage(session);
|
|
508
|
+
const doing = [compact ? chalk.white(compact) : '', teamLine].filter(Boolean);
|
|
509
|
+
if (doing.length) {
|
|
510
|
+
lines.push(verbLabel('Doing') + doing.join(DOT));
|
|
525
511
|
}
|
|
526
|
-
const termWidth = process.stdout.columns || 80;
|
|
527
512
|
for (const l of session.todos?.items?.length ? renderTodos(session.todos.items, termWidth) : []) {
|
|
528
|
-
lines.push(l);
|
|
529
|
-
}
|
|
530
|
-
const dirs = session.recentDirectoriesTouched?.slice(0, DIRS_TOUCHED_MAX) ?? [];
|
|
531
|
-
if (dirs.length) {
|
|
532
|
-
lines.push(chalk.cyan('Dirs: ') + chalk.white(dirs.join(chalk.gray(' · '))));
|
|
513
|
+
lines.push(' ' + l);
|
|
533
514
|
}
|
|
534
515
|
// `plan` is the whole ExitPlanMode markdown, not a path — summarize it. The
|
|
535
516
|
// pane is height-clamped anyway, so pasting the blob would just push every
|
|
@@ -537,10 +518,24 @@ function formatMetaOnlyBody(session) {
|
|
|
537
518
|
const planLines = session.plan?.trim() ? session.plan.trim().split('\n') : [];
|
|
538
519
|
if (planLines.length) {
|
|
539
520
|
const head = truncate(planLines[0].replace(/^#+\s*/, ''), termWidth - 20);
|
|
540
|
-
lines.push(
|
|
521
|
+
lines.push(verbLabel('Made') + chalk.white(head) + chalk.gray(` · plan, ${planLines.length} lines`));
|
|
541
522
|
}
|
|
542
|
-
|
|
543
|
-
|
|
523
|
+
const cost = [];
|
|
524
|
+
if (session.messageCount !== undefined) {
|
|
525
|
+
cost.push(chalk.white(String(session.messageCount)) + chalk.gray(` msg${session.messageCount === 1 ? '' : 's'}`));
|
|
526
|
+
}
|
|
527
|
+
if (session.tokenCount !== undefined) {
|
|
528
|
+
cost.push(chalk.white(formatTokens(session.tokenCount)) + chalk.gray(' tokens'));
|
|
529
|
+
}
|
|
530
|
+
if (cost.length) {
|
|
531
|
+
lines.push(verbLabel('Cost') + cost.join(DOT));
|
|
532
|
+
}
|
|
533
|
+
const dirs = session.recentDirectoriesTouched?.slice(0, DIRS_TOUCHED_MAX) ?? [];
|
|
534
|
+
const details = [
|
|
535
|
+
session.filePath ? chalk.gray(linkPath(session.filePath, session.id.slice(0, 8))) : chalk.gray(session.id.slice(0, 8)),
|
|
536
|
+
...dirs.map(d => chalk.gray(d)),
|
|
537
|
+
];
|
|
538
|
+
lines.push(verbLabel('Details ▸') + joinWidthCapped(details, valueWidth));
|
|
544
539
|
return lines.map(l => ' ' + l).join('\n');
|
|
545
540
|
}
|
|
546
541
|
function extractModel(events) {
|
|
@@ -720,45 +715,42 @@ export function buildSessionPreviewDigest(events, session) {
|
|
|
720
715
|
test: detectTestResult(events),
|
|
721
716
|
};
|
|
722
717
|
}
|
|
723
|
-
|
|
718
|
+
// Verb-led row gutter (RUSH-2757): every row label pads to this width so the
|
|
719
|
+
// values align into one scannable column. 'Details ▸' is the widest label.
|
|
720
|
+
const VERB_GUTTER = 9;
|
|
721
|
+
function verbLabel(v) {
|
|
722
|
+
return chalk.cyan(v.padEnd(VERB_GUTTER)) + ' ';
|
|
723
|
+
}
|
|
724
|
+
function formatCompactPreview(digest, session, events) {
|
|
724
725
|
const { firstUser, lastAssistant, filesRead, toolCalls, planFile, todos, subAgentCount, toolTags, changes: chg, dirs, repos, artifacts, skills, plugins, hooks, links, errorCount, firstError, toolHistogram: hist, test, } = digest;
|
|
725
726
|
const lines = [];
|
|
726
727
|
const termWidth = process.stdout.columns || 80;
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
728
|
+
const valueWidth = termWidth - VERB_GUTTER - 5;
|
|
729
|
+
// Asked — the originating user prompt (first non-system user turn), quoted.
|
|
730
|
+
const asked = firstUser
|
|
731
|
+
? (extractSessionTopic(firstUser) || cleanSessionPrompt(firstUser).split('\n').find(l => l.trim()) || '')
|
|
732
|
+
: (session.topic && !isSyntheticUserMessage(session.topic) ? session.topic : '');
|
|
733
|
+
if (asked.trim()) {
|
|
734
|
+
lines.push(verbLabel('Asked') + chalk.white(`"${truncate(asked.trim(), valueWidth)}"`));
|
|
733
735
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
}
|
|
737
|
-
// Compact checklist: ✓done/total · current step (RUSH-2045).
|
|
736
|
+
// Doing — the work in motion: checklist progress (RUSH-2045), team lineage,
|
|
737
|
+
// sub-agent fan-out. The full checklist renders indented beneath.
|
|
738
738
|
const compact = formatTodoCompact(todos);
|
|
739
|
-
if (compact) {
|
|
740
|
-
lines.push(chalk.cyan('Todos: ') + chalk.white(compact));
|
|
741
|
-
}
|
|
742
|
-
const todosRendered = todos?.items?.length ? renderTodos(todos.items, termWidth) : [];
|
|
743
|
-
if (todosRendered.length > 0) {
|
|
744
|
-
for (const l of todosRendered)
|
|
745
|
-
lines.push(' ' + l);
|
|
746
|
-
}
|
|
747
|
-
// Recent activity = directories touched (not raw tool calls). Prefer a
|
|
748
|
-
// parser-supplied dirsTouched when present; else derive from event paths.
|
|
749
|
-
// Width-capped: a long Dirs line used to wrap and swamp the whole pane.
|
|
750
|
-
if (dirs.length) {
|
|
751
|
-
lines.push(chalk.cyan('Dirs: ') + joinWidthCapped(dirs, termWidth - 12));
|
|
752
|
-
}
|
|
753
|
-
// Repos worked in (basename of each `.git` root under the touched paths).
|
|
754
|
-
if (repos.length) {
|
|
755
|
-
lines.push(chalk.cyan('Repos: ') + chalk.white(repos.slice(0, 4).join(chalk.gray(' · '))));
|
|
756
|
-
}
|
|
757
739
|
const teamLine = formatTeamLineage(session);
|
|
758
|
-
|
|
759
|
-
|
|
740
|
+
const doing = [
|
|
741
|
+
compact ? chalk.white(compact) : '',
|
|
742
|
+
teamLine,
|
|
743
|
+
subAgentCount ? chalk.gray(`${subAgentCount} sub-agent${subAgentCount === 1 ? '' : 's'}`) : '',
|
|
744
|
+
].filter(Boolean);
|
|
745
|
+
if (doing.length) {
|
|
746
|
+
lines.push(verbLabel('Doing') + doing.join(DOT));
|
|
760
747
|
}
|
|
761
|
-
const
|
|
748
|
+
const todosRendered = todos?.items?.length ? renderTodos(todos.items, termWidth) : [];
|
|
749
|
+
for (const l of todosRendered)
|
|
750
|
+
lines.push(' ' + l);
|
|
751
|
+
// Made — what the session produced: file deltas, reads, artifacts (named +
|
|
752
|
+
// clickable), the plan file, and the PR when the session carries one.
|
|
753
|
+
const made = [];
|
|
762
754
|
const changed = chg.created + chg.modified + chg.deleted;
|
|
763
755
|
if (changed) {
|
|
764
756
|
const parts = [
|
|
@@ -766,71 +758,61 @@ function formatCompactPreview(digest, session) {
|
|
|
766
758
|
chg.modified ? chalk.yellow(`~${chg.modified}`) : '',
|
|
767
759
|
chg.deleted ? chalk.red(`−${chg.deleted}`) : '',
|
|
768
760
|
].filter(Boolean).join(' ');
|
|
769
|
-
|
|
761
|
+
made.push(`${parts} ${chalk.gray('changed')}`);
|
|
770
762
|
}
|
|
771
763
|
if (filesRead)
|
|
772
|
-
|
|
773
|
-
if (toolCalls)
|
|
774
|
-
activity.push(chalk.gray(`${toolCalls} tool${toolCalls === 1 ? '' : 's'}`));
|
|
775
|
-
if (activity.length) {
|
|
776
|
-
lines.push(chalk.cyan('Changes: ') + activity.join(chalk.gray(' · ')));
|
|
777
|
-
}
|
|
778
|
-
// Documents the session produced (`.agents/artifacts|plans|reports`, other
|
|
779
|
-
// *.md/*.html creations) — the files a human browses later, named + clickable.
|
|
764
|
+
made.push(chalk.gray(`${filesRead} read`));
|
|
780
765
|
if (artifacts.length) {
|
|
781
|
-
const shown = artifacts.slice(0,
|
|
782
|
-
const more = artifacts.length >
|
|
783
|
-
|
|
784
|
-
}
|
|
785
|
-
// Skills invoked (plugin skills included — they ride the same Skill tool).
|
|
786
|
-
if (skills.length) {
|
|
787
|
-
const shown = skills.slice(0, 5).map(s => chalk.white(s.name) + (s.count > 1 ? chalk.gray(` ×${s.count}`) : ''));
|
|
788
|
-
const more = skills.length > 5 ? chalk.gray(` · +${skills.length - 5} more`) : '';
|
|
789
|
-
lines.push(chalk.cyan('Skills: ') + shown.join(chalk.gray(' · ')) + more);
|
|
766
|
+
const shown = artifacts.slice(0, 2).map(a => linkPath(a.path, a.basename));
|
|
767
|
+
const more = artifacts.length > 2 ? chalk.gray(` +${artifacts.length - 2}`) : '';
|
|
768
|
+
made.push(shown.join(chalk.gray(' · ')) + more);
|
|
790
769
|
}
|
|
791
|
-
if (
|
|
792
|
-
|
|
770
|
+
if (planFile) {
|
|
771
|
+
made.push(chalk.white(linkPath(planFile, planFile.split('/').pop() || planFile)));
|
|
793
772
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
const shown = hooks.slice(0, 4).map(h => chalk.white(h.name) + (h.count > 1 ? chalk.gray(` ×${h.count}`) : '') + (h.failed ? chalk.red(` (${h.failed} failed)`) : ''));
|
|
797
|
-
const more = hooks.length > 4 ? chalk.gray(` · +${hooks.length - 4} more`) : '';
|
|
798
|
-
lines.push(chalk.cyan('Hooks: ') + shown.join(chalk.gray(' · ')) + more);
|
|
773
|
+
if (session.prUrl) {
|
|
774
|
+
made.push(chalk.blue(linkUrl(session.prUrl, session.prNumber ? `PR#${session.prNumber}` : 'PR')));
|
|
799
775
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
const shown = links.slice(0, 5).map(l => chalk.blue(linkUrl(l.url, l.label)));
|
|
803
|
-
const more = links.length > 5 ? chalk.gray(` · +${links.length - 5} more`) : '';
|
|
804
|
-
lines.push(chalk.cyan('Links: ') + shown.join(chalk.gray(' · ')) + more);
|
|
776
|
+
if (made.length) {
|
|
777
|
+
lines.push(verbLabel('Made') + made.join(DOT));
|
|
805
778
|
}
|
|
806
|
-
//
|
|
779
|
+
// Health — error tally + the last test/build verdict; absent when both clean.
|
|
780
|
+
const health = [];
|
|
807
781
|
if (errorCount) {
|
|
808
|
-
|
|
809
|
-
}
|
|
810
|
-
const metadata = [
|
|
811
|
-
...toolTags,
|
|
812
|
-
subAgentCount ? `${subAgentCount} sub-agent${subAgentCount === 1 ? '' : 's'}` : '',
|
|
813
|
-
].filter(Boolean);
|
|
814
|
-
if (metadata.length) {
|
|
815
|
-
lines.push(chalk.cyan('Meta: ') + chalk.gray(metadata.join(' · ')));
|
|
816
|
-
}
|
|
817
|
-
// Tool mix (top 4) — what kind of work this was.
|
|
818
|
-
if (hist.length) {
|
|
819
|
-
lines.push(chalk.cyan('Tools: ') + chalk.gray(hist.map(h => `${h.tool} ${h.count}`).join(' · ')));
|
|
782
|
+
health.push(chalk.red(`${errorCount} failure${errorCount === 1 ? '' : 's'}`) + chalk.gray(` — first: ${firstError || 'unknown'}`));
|
|
820
783
|
}
|
|
821
|
-
// Last test/build verdict.
|
|
822
784
|
if (test?.ok) {
|
|
823
785
|
const bits = [
|
|
824
786
|
test.passed !== undefined ? chalk.green(`${test.passed} pass`) : '',
|
|
825
787
|
test.failed ? chalk.red(`${test.failed} fail`) : '',
|
|
826
788
|
].filter(Boolean).join(chalk.gray(' · '));
|
|
827
789
|
const mark = test.failed ? chalk.red('✗') : chalk.green('✓');
|
|
828
|
-
|
|
790
|
+
health.push(`${mark} ${test.runner}${bits ? ' ' + bits : ''}`);
|
|
829
791
|
}
|
|
830
|
-
if (
|
|
831
|
-
|
|
832
|
-
|
|
792
|
+
if (health.length) {
|
|
793
|
+
lines.push(verbLabel('Health') + health.join(DOT));
|
|
794
|
+
}
|
|
795
|
+
// Cost — volume: messages, tokens (moved here from the header's old line 3),
|
|
796
|
+
// and the top of the tool mix.
|
|
797
|
+
const totalMessages = session.messageCount ?? (events ? countMessages(events) : undefined);
|
|
798
|
+
const cost = [];
|
|
799
|
+
if (totalMessages !== undefined) {
|
|
800
|
+
cost.push(chalk.white(String(totalMessages)) + chalk.gray(` msg${totalMessages === 1 ? '' : 's'}`));
|
|
801
|
+
}
|
|
802
|
+
if (session.tokenCount !== undefined) {
|
|
803
|
+
cost.push(chalk.white(formatTokens(session.tokenCount)) + chalk.gray(' tokens'));
|
|
804
|
+
}
|
|
805
|
+
if (hist.length) {
|
|
806
|
+
cost.push(chalk.gray(hist.map(h => `${h.tool} ${h.count}`).join(' · ')));
|
|
833
807
|
}
|
|
808
|
+
else if (toolCalls) {
|
|
809
|
+
cost.push(chalk.gray(`${toolCalls} tool${toolCalls === 1 ? '' : 's'}`));
|
|
810
|
+
}
|
|
811
|
+
if (cost.length) {
|
|
812
|
+
lines.push(verbLabel('Cost') + cost.join(DOT));
|
|
813
|
+
}
|
|
814
|
+
// Latest — the agent's last message, full and wrapped to the pane (the densest
|
|
815
|
+
// line in the preview; parts 1-2 of RUSH-2757 made it wrap instead of clip).
|
|
834
816
|
if (lastAssistant) {
|
|
835
817
|
const maxLines = todosRendered.length > 0 || compact ? LAST_RESPONSE_MAX_LINES_WITH_TODOS : LAST_RESPONSE_MAX_LINES;
|
|
836
818
|
// Content sits at column 4 (outer body indent + the ' ' prefix below), so
|
|
@@ -838,14 +820,28 @@ function formatCompactPreview(digest, session) {
|
|
|
838
820
|
const rendered = renderLastResponse(lastAssistant, maxLines, terminalWidth() - 4);
|
|
839
821
|
if (rendered.length > 0) {
|
|
840
822
|
lines.push('');
|
|
841
|
-
lines.push(chalk.cyan('
|
|
823
|
+
lines.push(chalk.cyan('Latest'));
|
|
842
824
|
for (const l of rendered)
|
|
843
825
|
lines.push(' ' + l);
|
|
844
826
|
}
|
|
845
827
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
828
|
+
// Details ▸ — the folded long tail: session id, skills, plugins, hooks, links,
|
|
829
|
+
// dirs, repos, capability tags. One width-capped line instead of seven labeled
|
|
830
|
+
// rows (a long tail used to wrap and swamp the whole pane); links stay
|
|
831
|
+
// clickable (OSC 8), hook failures stay red. Full lists go to the cap — it is
|
|
832
|
+
// the ONLY bounding, so its `… +N more` tail accounts for every hidden item
|
|
833
|
+
// (pre-slicing here made overflow vanish with no trace).
|
|
834
|
+
const details = [
|
|
835
|
+
session.filePath ? chalk.gray(linkPath(session.filePath, session.id.slice(0, 8))) : chalk.gray(session.id.slice(0, 8)),
|
|
836
|
+
...skills.map(s => chalk.white(s.name) + (s.count > 1 ? chalk.gray(` ×${s.count}`) : '')),
|
|
837
|
+
...plugins.map(p => chalk.white(p)),
|
|
838
|
+
...hooks.map(h => chalk.white(h.name) + (h.failed ? chalk.red(` (${h.failed} failed)`) : '')),
|
|
839
|
+
...links.map(l => chalk.blue(linkUrl(l.url, l.label))),
|
|
840
|
+
...dirs.map(d => chalk.gray(d)),
|
|
841
|
+
...repos.map(r => chalk.gray(r)),
|
|
842
|
+
...toolTags.map(t => chalk.gray(t)),
|
|
843
|
+
];
|
|
844
|
+
lines.push(verbLabel('Details ▸') + joinWidthCapped(details, valueWidth));
|
|
849
845
|
return lines.map(l => ' ' + l).join('\n');
|
|
850
846
|
}
|
|
851
847
|
function classifySessionTool(tool, command) {
|
|
@@ -928,20 +924,26 @@ const SLUG_WORKTREE_RE = /--agents-worktrees-(.+)$/;
|
|
|
928
924
|
* Join display tokens with ` · `, stopping before the line exceeds `maxWidth`
|
|
929
925
|
* and appending `… +N more` for the rest. Keeps the Dirs line on one row.
|
|
930
926
|
*/
|
|
927
|
+
/**
|
|
928
|
+
* Join pre-styled items with ` · ` up to a visible width, then `… +N more`.
|
|
929
|
+
* Width is measured ANSI-aware (stringWidth), so colored / OSC 8-linked items
|
|
930
|
+
* are not miscounted; items arrive already styled and are not recolored.
|
|
931
|
+
*/
|
|
931
932
|
function joinWidthCapped(items, maxWidth) {
|
|
932
|
-
const sep = ' · ';
|
|
933
933
|
let out = '';
|
|
934
|
+
let width = 0;
|
|
934
935
|
let shown = 0;
|
|
935
936
|
for (const item of items) {
|
|
936
|
-
const
|
|
937
|
-
|
|
937
|
+
const itemWidth = stringWidth(item);
|
|
938
|
+
const nextWidth = shown === 0 ? itemWidth : width + 3 + itemWidth;
|
|
939
|
+
if (shown > 0 && nextWidth > maxWidth)
|
|
938
940
|
break;
|
|
939
|
-
out =
|
|
941
|
+
out = shown === 0 ? item : out + DOT + item;
|
|
942
|
+
width = nextWidth;
|
|
940
943
|
shown++;
|
|
941
944
|
}
|
|
942
945
|
const remaining = items.length - shown;
|
|
943
|
-
|
|
944
|
-
return chalk.white(out) + (suffix ? chalk.gray(suffix) : '');
|
|
946
|
+
return out + (remaining > 0 ? chalk.gray(` … +${remaining} more`) : '');
|
|
945
947
|
}
|
|
946
948
|
/** Relativize a file path to its parent dir, short enough for one preview line. */
|
|
947
949
|
export function relativizeDir(filePath, cwd) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe } from 'vitest';
|
|
2
|
+
/**
|
|
3
|
+
* Shared fixture for the sessions.*.test.ts suite slices (RUSH-2819).
|
|
4
|
+
*
|
|
5
|
+
* sessions.test.ts was one 2,600-line file measured at 172s — the single
|
|
6
|
+
* slowest file in CI, serializing an entire fork while every other selected
|
|
7
|
+
* file finished. The suite is split into topical slices so vitest's per-file
|
|
8
|
+
* fork parallelism can spread the subprocess-heavy tests across workers; the
|
|
9
|
+
* helpers each slice shares live here.
|
|
10
|
+
*/
|
|
11
|
+
export declare const describeLive: typeof describe.skip;
|
|
12
|
+
export declare const repoRoot: string;
|
|
13
|
+
export declare const cliEntry: string;
|
|
14
|
+
export declare const tsxLoaderUrl: string;
|
|
15
|
+
export declare function writeUpdateCache(tempHome: string): void;
|
|
16
|
+
export declare function writeClaudeSession(tempHome: string, projectKey: string, sessionId: string, cwd: string, content: string, timestamp: string): void;
|
|
17
|
+
export declare function writeCodexSession(tempHome: string, sessionId: string, cwd: string, prompt: string, timestamp: string): void;
|
|
18
|
+
export declare function writeGeminiSession(tempHome: string, sessionId: string, cwd: string, prompt: string, timestamp: string, version?: string): void;
|
|
19
|
+
export declare function writeOpenClawSetup(tempHome: string, version?: string): string;
|
|
20
|
+
export declare function runAgents(args: string[], cwd: string, home: string, envOverrides?: Record<string, string>): import("node:child_process").SpawnSyncReturns<string>;
|
|
21
|
+
export declare function outputOf(result: {
|
|
22
|
+
stdout: string;
|
|
23
|
+
stderr: string;
|
|
24
|
+
}): string;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { describe } from 'vitest';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
import { spawnSync } from 'child_process';
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
7
|
+
import { pathToFileURL } from 'node:url';
|
|
8
|
+
/**
|
|
9
|
+
* Shared fixture for the sessions.*.test.ts suite slices (RUSH-2819).
|
|
10
|
+
*
|
|
11
|
+
* sessions.test.ts was one 2,600-line file measured at 172s — the single
|
|
12
|
+
* slowest file in CI, serializing an entire fork while every other selected
|
|
13
|
+
* file finished. The suite is split into topical slices so vitest's per-file
|
|
14
|
+
* fork parallelism can spread the subprocess-heavy tests across workers; the
|
|
15
|
+
* helpers each slice shares live here.
|
|
16
|
+
*/
|
|
17
|
+
// win32: Claude projects path joins absolute cwd with colons (RUSH-2215).
|
|
18
|
+
export const describeLive = process.platform === 'win32' ? describe.skip : describe;
|
|
19
|
+
export const repoRoot = process.cwd();
|
|
20
|
+
export const cliEntry = path.join(repoRoot, 'src', 'index.ts');
|
|
21
|
+
// Run the CLI as `node --import <tsx loader> src/index.ts`: spawning `node`
|
|
22
|
+
// (always on PATH, no .cmd shell launcher) with the tsx ESM loader resolved to
|
|
23
|
+
// an absolute file URL keeps tsx loadable regardless of the spawn cwd (which we
|
|
24
|
+
// point at the project dir). Avoids both the Windows `tsx.cmd`-needs-a-shell
|
|
25
|
+
// problem and shell:true arg-concatenation (which would split multi-word query
|
|
26
|
+
// args like "prompt text").
|
|
27
|
+
export const tsxLoaderUrl = pathToFileURL(createRequire(import.meta.url).resolve('tsx')).href;
|
|
28
|
+
export function writeUpdateCache(tempHome) {
|
|
29
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf-8'));
|
|
30
|
+
fs.mkdirSync(path.join(tempHome, '.agents', '.cache'), { recursive: true });
|
|
31
|
+
fs.writeFileSync(path.join(tempHome, '.agents', '.cache', '.update-check'), JSON.stringify({ lastCheck: Date.now(), latestVersion: packageJson.version }), 'utf-8');
|
|
32
|
+
// ensureInitialized() checks for ~/.agents/.system/.git to confirm setup.
|
|
33
|
+
fs.mkdirSync(path.join(tempHome, '.agents', '.system', '.git'), { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
export function writeClaudeSession(tempHome, projectKey, sessionId, cwd, content, timestamp) {
|
|
36
|
+
fs.mkdirSync(cwd, { recursive: true });
|
|
37
|
+
const sessionsDir = path.join(tempHome, '.claude', 'projects', projectKey);
|
|
38
|
+
fs.mkdirSync(sessionsDir, { recursive: true });
|
|
39
|
+
fs.writeFileSync(path.join(sessionsDir, `${sessionId}.jsonl`), JSON.stringify({
|
|
40
|
+
type: 'user',
|
|
41
|
+
timestamp,
|
|
42
|
+
cwd,
|
|
43
|
+
sessionId,
|
|
44
|
+
version: '2.1.110',
|
|
45
|
+
gitBranch: 'main',
|
|
46
|
+
message: { role: 'user', content },
|
|
47
|
+
}) + '\n', 'utf-8');
|
|
48
|
+
}
|
|
49
|
+
export function writeCodexSession(tempHome, sessionId, cwd, prompt, timestamp) {
|
|
50
|
+
fs.mkdirSync(cwd, { recursive: true });
|
|
51
|
+
const sessionsDir = path.join(tempHome, '.codex', 'sessions', '2026', '04', '17');
|
|
52
|
+
fs.mkdirSync(sessionsDir, { recursive: true });
|
|
53
|
+
const filePath = path.join(sessionsDir, `rollout-${timestamp.replace(/[:.]/g, '-')}-${sessionId}.jsonl`);
|
|
54
|
+
const lines = [
|
|
55
|
+
JSON.stringify({
|
|
56
|
+
timestamp,
|
|
57
|
+
type: 'session_meta',
|
|
58
|
+
payload: {
|
|
59
|
+
id: sessionId,
|
|
60
|
+
timestamp,
|
|
61
|
+
cwd,
|
|
62
|
+
originator: 'codex_cli_rs',
|
|
63
|
+
cli_version: '0.113.0',
|
|
64
|
+
source: 'cli',
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
JSON.stringify({
|
|
68
|
+
timestamp,
|
|
69
|
+
type: 'response_item',
|
|
70
|
+
payload: {
|
|
71
|
+
type: 'message',
|
|
72
|
+
role: 'developer',
|
|
73
|
+
content: [{ type: 'input_text', text: '<permissions instructions>\nFilesystem sandboxing.\n</permissions instructions>' }],
|
|
74
|
+
},
|
|
75
|
+
}),
|
|
76
|
+
JSON.stringify({
|
|
77
|
+
timestamp,
|
|
78
|
+
type: 'response_item',
|
|
79
|
+
payload: {
|
|
80
|
+
type: 'message',
|
|
81
|
+
role: 'user',
|
|
82
|
+
content: [{ type: 'input_text', text: '<environment_context>\n <cwd>/tmp/project</cwd>\n <shell>zsh</shell>\n</environment_context>' }],
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
JSON.stringify({
|
|
86
|
+
timestamp,
|
|
87
|
+
type: 'response_item',
|
|
88
|
+
payload: {
|
|
89
|
+
type: 'message',
|
|
90
|
+
role: 'user',
|
|
91
|
+
content: [{ type: 'input_text', text: '<collaboration_mode># Collaboration Mode: Default\n</collaboration_mode>' }],
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
JSON.stringify({
|
|
95
|
+
timestamp,
|
|
96
|
+
type: 'response_item',
|
|
97
|
+
payload: {
|
|
98
|
+
type: 'message',
|
|
99
|
+
role: 'user',
|
|
100
|
+
content: [{ type: 'input_text', text: '# AGENTS.md instructions for /tmp/project\n\n<INSTRUCTIONS>\nDo work.\n</INSTRUCTIONS>' }],
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
JSON.stringify({
|
|
104
|
+
timestamp,
|
|
105
|
+
type: 'response_item',
|
|
106
|
+
payload: {
|
|
107
|
+
type: 'message',
|
|
108
|
+
role: 'user',
|
|
109
|
+
content: [{ type: 'input_text', text: prompt }],
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
JSON.stringify({
|
|
113
|
+
timestamp,
|
|
114
|
+
type: 'response_item',
|
|
115
|
+
payload: {
|
|
116
|
+
type: 'message',
|
|
117
|
+
role: 'assistant',
|
|
118
|
+
content: [{ type: 'output_text', text: 'Looking into it now.' }],
|
|
119
|
+
},
|
|
120
|
+
}),
|
|
121
|
+
];
|
|
122
|
+
fs.writeFileSync(filePath, lines.join('\n') + '\n', 'utf-8');
|
|
123
|
+
}
|
|
124
|
+
export function writeGeminiSession(tempHome, sessionId, cwd, prompt, timestamp, version = '0.29.5') {
|
|
125
|
+
const versionHome = path.join(tempHome, '.agents', '.history', 'versions', 'gemini', version, 'home');
|
|
126
|
+
const geminiHome = path.join(versionHome, '.gemini');
|
|
127
|
+
const projectHash = crypto.createHash('sha256').update(cwd).digest('hex');
|
|
128
|
+
const chatsDir = path.join(geminiHome, 'tmp', projectHash, 'chats');
|
|
129
|
+
fs.mkdirSync(cwd, { recursive: true });
|
|
130
|
+
fs.mkdirSync(chatsDir, { recursive: true });
|
|
131
|
+
fs.mkdirSync(path.dirname(path.join(tempHome, '.gemini')), { recursive: true });
|
|
132
|
+
const activeGeminiHome = path.join(tempHome, '.gemini');
|
|
133
|
+
if (!fs.existsSync(activeGeminiHome)) {
|
|
134
|
+
fs.symlinkSync(geminiHome, activeGeminiHome);
|
|
135
|
+
}
|
|
136
|
+
fs.writeFileSync(path.join(geminiHome, 'projects.json'), JSON.stringify({ projects: [cwd] }), 'utf-8');
|
|
137
|
+
fs.writeFileSync(path.join(chatsDir, `session-${timestamp.replace(/[:.]/g, '-')}-${sessionId.slice(0, 8)}.json`), JSON.stringify({
|
|
138
|
+
sessionId,
|
|
139
|
+
projectHash,
|
|
140
|
+
startTime: timestamp,
|
|
141
|
+
lastUpdated: timestamp,
|
|
142
|
+
messages: [
|
|
143
|
+
{
|
|
144
|
+
id: `${sessionId}-user`,
|
|
145
|
+
timestamp,
|
|
146
|
+
type: 'user',
|
|
147
|
+
content: [{ text: prompt }],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: `${sessionId}-assistant`,
|
|
151
|
+
timestamp,
|
|
152
|
+
type: 'gemini',
|
|
153
|
+
content: 'Investigating now.',
|
|
154
|
+
model: 'gemini-3-flash-preview',
|
|
155
|
+
tokens: { total: 1234 },
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
}, null, 2), 'utf-8');
|
|
159
|
+
}
|
|
160
|
+
export function writeOpenClawSetup(tempHome, version = '2026.3.8') {
|
|
161
|
+
const managedHome = path.join(tempHome, '.agents', '.history', 'versions', 'openclaw', version, 'home', '.openclaw');
|
|
162
|
+
fs.mkdirSync(managedHome, { recursive: true });
|
|
163
|
+
const activeHome = path.join(tempHome, '.openclaw');
|
|
164
|
+
fs.mkdirSync(path.dirname(activeHome), { recursive: true });
|
|
165
|
+
if (!fs.existsSync(activeHome)) {
|
|
166
|
+
fs.symlinkSync(managedHome, activeHome);
|
|
167
|
+
}
|
|
168
|
+
const managedWorkspace = path.join(managedHome, 'sergey');
|
|
169
|
+
fs.mkdirSync(managedWorkspace, { recursive: true });
|
|
170
|
+
fs.writeFileSync(path.join(managedHome, 'openclaw.json'), JSON.stringify({
|
|
171
|
+
agents: {
|
|
172
|
+
list: [
|
|
173
|
+
{ id: 'sergey', workspace: path.join(activeHome, 'sergey') },
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
}, null, 2), 'utf-8');
|
|
177
|
+
const binDir = path.join(tempHome, 'bin');
|
|
178
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
179
|
+
const openclawBin = path.join(binDir, 'openclaw');
|
|
180
|
+
fs.writeFileSync(openclawBin, `#!/bin/sh
|
|
181
|
+
if [ "$1" = "--version" ]; then
|
|
182
|
+
echo "openclaw/${version}"
|
|
183
|
+
exit 0
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
if [ "$1" = "channels" ] && [ "$2" = "status" ]; then
|
|
187
|
+
echo "- Telegram sergey (Sergey): enabled, configured, running, out:2h ago, mode:polling, token:config"
|
|
188
|
+
exit 0
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
if [ "$1" = "cron" ] && [ "$2" = "list" ]; then
|
|
192
|
+
echo "ID NAME SCHEDULE NEXT LAST STATUS TARGET AGENT MODEL"
|
|
193
|
+
echo "12345678-1234-1234-1234-123456789abc sergey-hourly cron */30 * * * * in 7h 48m ago ok isolated sergey -"
|
|
194
|
+
exit 0
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
exit 1
|
|
198
|
+
`, 'utf-8');
|
|
199
|
+
fs.chmodSync(openclawBin, 0o755);
|
|
200
|
+
return path.join(activeHome, 'sergey');
|
|
201
|
+
}
|
|
202
|
+
export function runAgents(args, cwd, home, envOverrides = {}) {
|
|
203
|
+
return spawnSync('node', ['--import', tsxLoaderUrl, cliEntry, ...args], {
|
|
204
|
+
cwd,
|
|
205
|
+
env: {
|
|
206
|
+
...process.env,
|
|
207
|
+
HOME: home,
|
|
208
|
+
// os.homedir() (used via homeDir() in discovery) reads USERPROFILE on
|
|
209
|
+
// Windows and ignores HOME, so set both to redirect the home to tempHome.
|
|
210
|
+
USERPROFILE: home,
|
|
211
|
+
PATH: `${path.join(home, 'bin')}${path.delimiter}${process.env.PATH || ''}`,
|
|
212
|
+
// Some fixtures place files at $HOME/.agents/versions/<agent>/<ver>/ as
|
|
213
|
+
// legacy / synthetic state. The bootstrap-time migration would otherwise
|
|
214
|
+
// move those into ~/.agents-system/, breaking workspace-scoped lookups.
|
|
215
|
+
AGENTS_SKIP_MIGRATION: '1',
|
|
216
|
+
NODE_NO_WARNINGS: '1',
|
|
217
|
+
...envOverrides,
|
|
218
|
+
},
|
|
219
|
+
encoding: 'utf-8',
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
export function outputOf(result) {
|
|
223
|
+
return `${result.stdout}${result.stderr}`;
|
|
224
|
+
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -25,6 +25,8 @@ import { registerSetupMineCommand } from './setup-mine.js';
|
|
|
25
25
|
import { registerSetupSecretsCommand } from './setup-secrets.js';
|
|
26
26
|
import { registerSetupFleetCommand } from './setup-fleet.js';
|
|
27
27
|
import { registerSetupWatchdogCommand, runWatchdogSetupWizard } from './setup-watchdog.js';
|
|
28
|
+
import { registerAliasCommand } from './alias.js';
|
|
29
|
+
import { registerBetaCommands } from './beta.js';
|
|
28
30
|
import { runPreferencesStep } from './setup-preferences.js';
|
|
29
31
|
import { getConfiguredDefaultProfileName, getProfile, getAutoDetectedProfile, isProfileLaunchableHere } from '../lib/browser/profiles.js';
|
|
30
32
|
import { listInstalledBrowsers } from '../lib/browser/chrome.js';
|
|
@@ -362,7 +364,7 @@ export function registerSetupCommand(program) {
|
|
|
362
364
|
.description('Set up agents-cli, or re-open the capability onboarding hub.')
|
|
363
365
|
.option('-f, --force', 'Re-run setup even if ~/.agents/.system/ already exists (use with caution)')
|
|
364
366
|
.option('--no-system-repo', 'Skip cloning the system repo (you must populate ~/.agents/.system/ yourself)');
|
|
365
|
-
// Capability subcommands: `agents setup browser|computer|mine|secrets|fleet`.
|
|
367
|
+
// Capability subcommands: `agents setup browser|computer|mine|secrets|fleet|alias|beta`.
|
|
366
368
|
// Share/artifact publishing is set up by `agents artifacts setup` (RUSH-2580);
|
|
367
369
|
// the hub below still offers it as a phase via runShareWizard.
|
|
368
370
|
registerSetupBrowserCommand(setupCmd);
|
|
@@ -371,6 +373,8 @@ export function registerSetupCommand(program) {
|
|
|
371
373
|
registerSetupSecretsCommand(setupCmd);
|
|
372
374
|
registerSetupFleetCommand(setupCmd);
|
|
373
375
|
registerSetupWatchdogCommand(setupCmd);
|
|
376
|
+
registerAliasCommand(setupCmd);
|
|
377
|
+
registerBetaCommands(setupCmd);
|
|
374
378
|
setupCmd.command('status')
|
|
375
379
|
.description('Show setup readiness for core, browser, computer, secrets, fleet, share, watchdog, and preferences.')
|
|
376
380
|
.option('--json', 'print machine-readable JSON')
|
|
@@ -397,6 +401,8 @@ export function registerSetupCommand(program) {
|
|
|
397
401
|
agents setup secrets
|
|
398
402
|
agents setup fleet
|
|
399
403
|
agents setup watchdog
|
|
404
|
+
agents setup alias add teams
|
|
405
|
+
agents setup beta enable factory
|
|
400
406
|
`,
|
|
401
407
|
notes: `
|
|
402
408
|
What it does:
|
|
@@ -412,6 +418,8 @@ export function registerSetupCommand(program) {
|
|
|
412
418
|
agents setup secrets # choose secrets backend/policy defaults + import
|
|
413
419
|
agents setup fleet # discover Tailscale devices + configure SSH access
|
|
414
420
|
agents setup watchdog # choose which devices run the daemon watchdog pass
|
|
421
|
+
agents setup alias add teams # PATH shorthand: teams runs agents teams
|
|
422
|
+
agents setup beta enable factory # opt into preview features
|
|
415
423
|
|
|
416
424
|
To install CLIs from agents.yaml and sync resources into version homes:
|
|
417
425
|
agents sync --local -y
|