@phnx-labs/agents-cli 1.20.22 → 1.20.24
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/dist/commands/cloud.js +126 -6
- package/dist/commands/exec.js +13 -1
- package/dist/index.js +266 -224
- package/dist/lib/cloud/codex.d.ts +1 -0
- package/dist/lib/cloud/codex.js +8 -2
- package/dist/lib/cloud/factory.d.ts +12 -1
- package/dist/lib/cloud/factory.js +58 -3
- package/dist/lib/cloud/types.d.ts +41 -0
- package/dist/lib/cloud/types.js +17 -0
- package/dist/lib/exec.d.ts +2 -0
- package/dist/lib/exec.js +5 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +20 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +115 -0
- package/dist/lib/secrets/agent.d.ts +11 -0
- package/dist/lib/secrets/agent.js +28 -9
- package/dist/lib/startup/command-registry.d.ts +99 -0
- package/dist/lib/startup/command-registry.js +136 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -7,12 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Command } from 'commander';
|
|
9
9
|
import chalk from 'chalk';
|
|
10
|
-
import ora from 'ora';
|
|
11
10
|
import * as fs from 'fs';
|
|
12
11
|
import * as os from 'os';
|
|
13
12
|
import * as path from 'path';
|
|
14
13
|
import { fileURLToPath } from 'url';
|
|
15
|
-
|
|
14
|
+
// `ora`, `@inquirer/prompts`, `./commands/utils.js`, and the agents/versions/shims
|
|
15
|
+
// modules are imported dynamically at their use sites: they are needed only on
|
|
16
|
+
// interactive / update / shim-repair paths, never for fast commands like
|
|
17
|
+
// `--version`, `--help`, or `view`. Keeping them off the module-eval path is
|
|
18
|
+
// what gets cold starts under the target.
|
|
16
19
|
// Force exit on Ctrl+C when no interactive prompt is handling it.
|
|
17
20
|
process.on('SIGINT', () => process.exit(130));
|
|
18
21
|
// Ignore SIGPIPE — prevents exit code 13 crashes in piped environments
|
|
@@ -54,59 +57,12 @@ if (IS_DEV_BUILD) {
|
|
|
54
57
|
if (process.env.AGENTS_CLI_DISABLE_AUTO_UPDATE === undefined)
|
|
55
58
|
process.env.AGENTS_CLI_DISABLE_AUTO_UPDATE = '1';
|
|
56
59
|
}
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
import {
|
|
62
|
-
import { registerFeedbackCommand } from './commands/feedback.js';
|
|
63
|
-
import { registerViewCommand } from './commands/view.js';
|
|
64
|
-
import { registerInspectCommand } from './commands/inspect.js';
|
|
65
|
-
import { registerCommandsCommands } from './commands/commands.js';
|
|
66
|
-
import { registerHooksCommands } from './commands/hooks.js';
|
|
67
|
-
import { registerSkillsCommands } from './commands/skills.js';
|
|
68
|
-
import { registerRulesCommands } from './commands/rules.js';
|
|
69
|
-
import { registerPermissionsCommands } from './commands/permissions.js';
|
|
70
|
-
import { registerMcpCommands } from './commands/mcp.js';
|
|
71
|
-
import { registerCliCommands } from './commands/cli.js';
|
|
72
|
-
import { registerVersionsCommands } from './commands/versions.js';
|
|
73
|
-
import { registerImportCommand } from './commands/import.js';
|
|
74
|
-
import { registerPackagesCommands } from './commands/packages.js';
|
|
75
|
-
import { registerDaemonCommands } from './commands/daemon.js';
|
|
76
|
-
import { registerRoutinesCommands } from './commands/routines.js';
|
|
77
|
-
import { registerRunCommand } from './commands/exec.js';
|
|
78
|
-
import { registerModelsCommand } from './commands/models.js';
|
|
79
|
-
import { registerDefaultsCommands } from './commands/defaults.js';
|
|
80
|
-
import { registerPruneCommand } from './commands/prune.js';
|
|
81
|
-
import { registerTrashCommands, registerRestoreCommand } from './commands/trash.js';
|
|
82
|
-
import { registerDoctorCommand } from './commands/doctor.js';
|
|
83
|
-
import { registerSubagentsCommands } from './commands/subagents.js';
|
|
84
|
-
import { registerPluginsCommands } from './commands/plugins.js';
|
|
85
|
-
import { registerWorkflowsCommands } from './commands/workflows.js';
|
|
86
|
-
import { registerWorktreeCommands } from './commands/worktree.js';
|
|
87
|
-
import { registerSyncCommand } from './commands/sync.js';
|
|
88
|
-
import { registerRefreshRulesCommand } from './commands/refresh-rules.js';
|
|
89
|
-
import { registerDriveCommands } from './commands/drive.js';
|
|
90
|
-
import { registerPtyCommands } from './commands/pty.js';
|
|
91
|
-
import { registerTmuxCommands } from './commands/tmux.js';
|
|
92
|
-
import { registerBrowserCommand } from './commands/browser.js';
|
|
93
|
-
import { registerComputerCommand } from './commands/computer.js';
|
|
94
|
-
import { registerProfilesCommands } from './commands/profiles.js';
|
|
95
|
-
import { registerSecretsCommands } from './commands/secrets.js';
|
|
96
|
-
import { registerWalletCommands } from './commands/wallet.js';
|
|
97
|
-
import { registerHelperCommand } from './commands/helper.js';
|
|
98
|
-
import { registerMenubarCommands } from './commands/menubar.js';
|
|
99
|
-
import { registerFactoryCommands } from './commands/factory.js';
|
|
100
|
-
import { registerUsageCommand } from './commands/usage.js';
|
|
101
|
-
import { registerCostCommand } from './commands/cost.js';
|
|
102
|
-
import { registerBudgetCommand } from './commands/budget.js';
|
|
103
|
-
import { registerAliasCommand } from './commands/alias.js';
|
|
104
|
-
import { registerBetaCommands } from './commands/beta.js';
|
|
60
|
+
// Command registration is lazy: instead of statically importing every command
|
|
61
|
+
// module on each invocation (which loaded the whole ~50-module tree before the
|
|
62
|
+
// first byte of output), the registry maps a command name to a thunk that
|
|
63
|
+
// imports only what that command needs. See src/lib/startup/command-registry.ts.
|
|
64
|
+
import { COMMAND_LOADERS, LAZY_COMMAND_NAMES, loadView, loadInspect, loadFeedback, loadCommands, loadHooks, loadSkills, loadRules, loadPermissions, loadMcp, loadCli, loadSubagents, loadPlugins, loadWorkflows, loadWorktree, loadVersions, loadImport, loadPackages, loadDaemon, loadRoutines, loadRun, loadDefaults, loadModels, loadPrune, loadTrash, loadRestore, loadDoctor, loadProfiles, loadSecrets, loadWallet, loadHelper, loadMenubar, loadBeta, loadSync, loadRefreshRules, loadDrive, loadFactory, loadUsage, loadCost, loadBudget, loadAlias, loadPty, loadTmux, loadBrowser, loadComputer, loadPull, loadPush, loadRepo, loadSetup, } from './lib/startup/command-registry.js';
|
|
105
65
|
import { applyGlobalHelpConventions } from './lib/help.js';
|
|
106
|
-
import { isInteractiveTerminal, isPromptCancelled } from './commands/utils.js';
|
|
107
|
-
import { AGENTS } from './lib/agents.js';
|
|
108
|
-
import { getGlobalDefault, listInstalledVersions } from './lib/versions.js';
|
|
109
|
-
import { addShimsToPath, ensureShimCurrent, ensureVersionedAliasCurrent, getPathShadowingExecutable, getPathSetupInstructions, getShimsDir, isShimsInPath, listAgentsWithInstalledVersions, removeLegacyUserShim, } from './lib/shims.js';
|
|
110
66
|
import { IS_WINDOWS } from './lib/platform/index.js';
|
|
111
67
|
// Transparent shim delegate: the generated Windows `.cmd` shims invoke
|
|
112
68
|
// `agents __shim <agent>[@version] <raw args>`. Intercept here, before commander
|
|
@@ -382,6 +338,9 @@ async function installResolvedPackage(metadata) {
|
|
|
382
338
|
}
|
|
383
339
|
/** Present an interactive upgrade prompt (TTY) or a one-line hint (non-TTY). */
|
|
384
340
|
async function promptUpgrade(latestVersion) {
|
|
341
|
+
const { default: ora } = await import('ora');
|
|
342
|
+
const { confirm, select } = await import('@inquirer/prompts');
|
|
343
|
+
const { isInteractiveTerminal, isPromptCancelled } = await import('./commands/utils.js');
|
|
385
344
|
if (!isInteractiveTerminal()) {
|
|
386
345
|
console.error(chalk.yellow(`Update available: ${VERSION} -> ${latestVersion}. Run: agents upgrade --yes`));
|
|
387
346
|
return;
|
|
@@ -480,6 +439,7 @@ async function checkForUpdates() {
|
|
|
480
439
|
await promptUpgrade(cache.latestVersion);
|
|
481
440
|
}
|
|
482
441
|
catch (err) {
|
|
442
|
+
const { isPromptCancelled } = await import('./commands/utils.js');
|
|
483
443
|
if (isPromptCancelled(err))
|
|
484
444
|
return;
|
|
485
445
|
/* prompt error, ignore */
|
|
@@ -500,6 +460,13 @@ async function maybeBootstrapShimIntegration(requestedCommand, helpOrVersionRequ
|
|
|
500
460
|
if (requestedCommand === 'sync' || requestedCommand === 'refresh-rules') {
|
|
501
461
|
return;
|
|
502
462
|
}
|
|
463
|
+
// Past the documentation/non-TTY guards: only now load the shim + agent
|
|
464
|
+
// tables this interactive repair flow needs, so fast commands never pay for
|
|
465
|
+
// them at module-eval time.
|
|
466
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
467
|
+
const { AGENTS } = await import('./lib/agents.js');
|
|
468
|
+
const { getGlobalDefault, listInstalledVersions } = await import('./lib/versions.js');
|
|
469
|
+
const { addShimsToPath, ensureShimCurrent, ensureVersionedAliasCurrent, getPathShadowingExecutable, getPathSetupInstructions, getShimsDir, isShimsInPath, listAgentsWithInstalledVersions, removeLegacyUserShim, } = await import('./lib/shims.js');
|
|
503
470
|
const installedAgents = listAgentsWithInstalledVersions();
|
|
504
471
|
if (installedAgents.length === 0) {
|
|
505
472
|
return;
|
|
@@ -621,88 +588,50 @@ async function maybeBootstrapShimIntegration(requestedCommand, helpOrVersionRequ
|
|
|
621
588
|
}
|
|
622
589
|
catch { /* best-effort */ }
|
|
623
590
|
}
|
|
624
|
-
//
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
registerModelsCommand(program);
|
|
669
|
-
registerPruneCommand(program);
|
|
670
|
-
registerTrashCommands(program);
|
|
671
|
-
registerRestoreCommand(program);
|
|
672
|
-
registerDoctorCommand(program);
|
|
673
|
-
// Deprecated 'exec' alias for 'run'
|
|
674
|
-
program
|
|
675
|
-
.command('exec', { hidden: true })
|
|
676
|
-
.allowUnknownOption()
|
|
677
|
-
.allowExcessArguments()
|
|
678
|
-
.action(async () => {
|
|
679
|
-
console.log(chalk.yellow('Deprecated: Use "agents run" instead of "agents exec"\n'));
|
|
680
|
-
const args = process.argv.slice(2);
|
|
681
|
-
args[0] = 'run';
|
|
682
|
-
await program.parseAsync(['node', 'agents', ...args]);
|
|
683
|
-
});
|
|
684
|
-
registerProfilesCommands(program);
|
|
685
|
-
registerSecretsCommands(program);
|
|
686
|
-
registerWalletCommands(program);
|
|
687
|
-
registerHelperCommand(program);
|
|
688
|
-
registerMenubarCommands(program);
|
|
689
|
-
registerBetaCommands(program);
|
|
690
|
-
registerSyncCommand(program);
|
|
691
|
-
registerRefreshRulesCommand(program);
|
|
692
|
-
registerDriveCommands(program);
|
|
693
|
-
registerFactoryCommands(program);
|
|
694
|
-
registerUsageCommand(program);
|
|
695
|
-
registerCostCommand(program);
|
|
696
|
-
registerBudgetCommand(program);
|
|
697
|
-
registerAliasCommand(program);
|
|
698
|
-
registerPtyCommands(program);
|
|
699
|
-
registerTmuxCommands(program);
|
|
700
|
-
registerBrowserCommand(program);
|
|
701
|
-
registerComputerCommand(program);
|
|
702
|
-
// Deprecated 'jobs' and 'cron' aliases for 'routines'
|
|
703
|
-
for (const alias of ['jobs', 'cron']) {
|
|
704
|
-
program
|
|
705
|
-
.command(alias, { hidden: true })
|
|
591
|
+
// --- Inline command registrars ----------------------------------------------
|
|
592
|
+
// These commands are defined here rather than in a command module because they
|
|
593
|
+
// close over entry-point-local state (program re-parsing, VERSION, the npm
|
|
594
|
+
// upgrade helpers). The lazy registrar and the all-commands fallback below both
|
|
595
|
+
// call them, so the behavior is identical to the old eager registration.
|
|
596
|
+
/** Deprecated `memory` command — hard error pointing users at `rules`. */
|
|
597
|
+
function registerMemoryCommand(p) {
|
|
598
|
+
p.command('memory', { hidden: true })
|
|
599
|
+
.allowUnknownOption()
|
|
600
|
+
.allowExcessArguments()
|
|
601
|
+
.action(() => {
|
|
602
|
+
console.error(chalk.red('"agents memory" has been renamed to "agents rules".'));
|
|
603
|
+
console.error(chalk.gray('Run "agents rules --help" for usage.\n'));
|
|
604
|
+
process.exit(1);
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
/** Deprecated `perms` alias — re-parses as `permissions`. */
|
|
608
|
+
function registerPermsAliasCommand(p) {
|
|
609
|
+
p.command('perms', { hidden: true })
|
|
610
|
+
.allowUnknownOption()
|
|
611
|
+
.allowExcessArguments()
|
|
612
|
+
.action(async () => {
|
|
613
|
+
console.log(chalk.yellow('Deprecated: Use "agents permissions" instead of "agents perms"\n'));
|
|
614
|
+
// Re-parse with 'permissions' command
|
|
615
|
+
const args = process.argv.slice(2);
|
|
616
|
+
args[0] = 'permissions';
|
|
617
|
+
await program.parseAsync(['node', 'agents', ...args]);
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
/** Deprecated `exec` alias — re-parses as `run`. */
|
|
621
|
+
function registerExecAliasCommand(p) {
|
|
622
|
+
p.command('exec', { hidden: true })
|
|
623
|
+
.allowUnknownOption()
|
|
624
|
+
.allowExcessArguments()
|
|
625
|
+
.action(async () => {
|
|
626
|
+
console.log(chalk.yellow('Deprecated: Use "agents run" instead of "agents exec"\n'));
|
|
627
|
+
const args = process.argv.slice(2);
|
|
628
|
+
args[0] = 'run';
|
|
629
|
+
await program.parseAsync(['node', 'agents', ...args]);
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
/** Deprecated `jobs` / `cron` aliases — re-parse as `routines`. */
|
|
633
|
+
function registerJobsCronAliasCommand(p, alias) {
|
|
634
|
+
p.command(alias, { hidden: true })
|
|
706
635
|
.allowUnknownOption()
|
|
707
636
|
.allowExcessArguments()
|
|
708
637
|
.action(async () => {
|
|
@@ -712,60 +641,166 @@ for (const alias of ['jobs', 'cron']) {
|
|
|
712
641
|
await program.parseAsync(['node', 'agents', ...args]);
|
|
713
642
|
});
|
|
714
643
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
.
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
if (!version && compareVersions(resolvedVersion, VERSION) <= 0) {
|
|
733
|
-
spinner.succeed(`Already ahead of latest (${VERSION} >= ${resolvedVersion})`);
|
|
734
|
-
return;
|
|
735
|
-
}
|
|
736
|
-
const direction = compareVersions(resolvedVersion, VERSION) < 0 ? 'Downgrade' : 'Upgrade';
|
|
737
|
-
spinner.succeed(`Resolved ${NPM_PACKAGE_NAME}@${resolvedVersion}`);
|
|
738
|
-
printResolvedPackage(metadata);
|
|
739
|
-
if (isInteractiveTerminal() && !options.yes) {
|
|
740
|
-
const approved = await confirm({
|
|
741
|
-
message: `Install ${NPM_PACKAGE_NAME}@${resolvedVersion}?`,
|
|
742
|
-
default: false,
|
|
743
|
-
});
|
|
744
|
-
if (!approved) {
|
|
745
|
-
console.log(chalk.gray('Upgrade cancelled'));
|
|
644
|
+
/** Self-upgrade command (`agents upgrade [version]`). */
|
|
645
|
+
function registerUpgradeCommand(p) {
|
|
646
|
+
p.command('upgrade')
|
|
647
|
+
.description('Upgrade agents-cli to the latest version (or a specific [version])')
|
|
648
|
+
.argument('[version]', 'Target version or dist-tag to install (default: latest)')
|
|
649
|
+
.option('-y, --yes', 'Install without an interactive confirmation prompt')
|
|
650
|
+
.action(async (version, options) => {
|
|
651
|
+
const { default: ora } = await import('ora');
|
|
652
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
653
|
+
const { isInteractiveTerminal, isPromptCancelled } = await import('./commands/utils.js');
|
|
654
|
+
const target = version ?? 'latest';
|
|
655
|
+
let spinner = ora(version ? `Resolving ${NPM_PACKAGE_NAME}@${target}...` : 'Checking for updates...').start();
|
|
656
|
+
try {
|
|
657
|
+
const metadata = await fetchNpmPackageMetadata(target);
|
|
658
|
+
const resolvedVersion = metadata.version;
|
|
659
|
+
if (resolvedVersion === VERSION) {
|
|
660
|
+
spinner.succeed(`Already on ${VERSION}`);
|
|
746
661
|
return;
|
|
747
662
|
}
|
|
663
|
+
// For `latest` (no explicit version) skip when already ahead. When a
|
|
664
|
+
// version is named explicitly, honor it even if it's a downgrade.
|
|
665
|
+
if (!version && compareVersions(resolvedVersion, VERSION) <= 0) {
|
|
666
|
+
spinner.succeed(`Already ahead of latest (${VERSION} >= ${resolvedVersion})`);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
const direction = compareVersions(resolvedVersion, VERSION) < 0 ? 'Downgrade' : 'Upgrade';
|
|
670
|
+
spinner.succeed(`Resolved ${NPM_PACKAGE_NAME}@${resolvedVersion}`);
|
|
671
|
+
printResolvedPackage(metadata);
|
|
672
|
+
if (isInteractiveTerminal() && !options.yes) {
|
|
673
|
+
const approved = await confirm({
|
|
674
|
+
message: `Install ${NPM_PACKAGE_NAME}@${resolvedVersion}?`,
|
|
675
|
+
default: false,
|
|
676
|
+
});
|
|
677
|
+
if (!approved) {
|
|
678
|
+
console.log(chalk.gray('Upgrade cancelled'));
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
spinner = ora(`${direction === 'Downgrade' ? 'Downgrading' : 'Upgrading'} ${VERSION} -> ${resolvedVersion}...`).start();
|
|
683
|
+
await installResolvedPackage(metadata);
|
|
684
|
+
spinner.succeed(`${direction}d to ${resolvedVersion}`);
|
|
685
|
+
// Only show the changelog for a genuine upgrade range.
|
|
686
|
+
if (compareVersions(resolvedVersion, VERSION) > 0) {
|
|
687
|
+
await showWhatsNew(VERSION, resolvedVersion);
|
|
688
|
+
}
|
|
748
689
|
}
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
await showWhatsNew(VERSION, resolvedVersion);
|
|
690
|
+
catch (err) {
|
|
691
|
+
if (isPromptCancelled(err))
|
|
692
|
+
return;
|
|
693
|
+
spinner.fail(`Upgrade failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
694
|
+
console.log(chalk.gray(`Run manually: agents upgrade ${version ? version + ' ' : ''}--yes`));
|
|
755
695
|
}
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
// --- Lazy registration orchestration -----------------------------------------
|
|
699
|
+
/** Import a command module via its loader and register it on the program. */
|
|
700
|
+
async function reg(loader) {
|
|
701
|
+
(await loader())(program);
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Register exactly the command(s) the requested top-level name needs.
|
|
705
|
+
* Returns false when the name maps to no known command (typo / unknown) so the
|
|
706
|
+
* caller can fall back to registering everything for spellcheck.
|
|
707
|
+
*
|
|
708
|
+
* Lazy commands (sessions/teams/cloud) are intentionally NOT handled here — they
|
|
709
|
+
* must register after applyGlobalHelpConventions to match main's ordering.
|
|
710
|
+
*/
|
|
711
|
+
async function registerEagerForRequest(name) {
|
|
712
|
+
switch (name) {
|
|
713
|
+
case 'memory':
|
|
714
|
+
registerMemoryCommand(program);
|
|
715
|
+
return true;
|
|
716
|
+
case 'perms':
|
|
717
|
+
// The action re-parses as `permissions`, so that target must exist too.
|
|
718
|
+
registerPermsAliasCommand(program);
|
|
719
|
+
await reg(loadPermissions);
|
|
720
|
+
return true;
|
|
721
|
+
case 'exec':
|
|
722
|
+
registerExecAliasCommand(program);
|
|
723
|
+
await reg(loadRun);
|
|
724
|
+
return true;
|
|
725
|
+
case 'jobs':
|
|
726
|
+
case 'cron':
|
|
727
|
+
registerJobsCronAliasCommand(program, name);
|
|
728
|
+
await reg(loadRoutines);
|
|
729
|
+
return true;
|
|
730
|
+
case 'upgrade':
|
|
731
|
+
registerUpgradeCommand(program);
|
|
732
|
+
return true;
|
|
733
|
+
}
|
|
734
|
+
const loaders = COMMAND_LOADERS[name];
|
|
735
|
+
if (!loaders)
|
|
736
|
+
return false;
|
|
737
|
+
for (const loader of loaders)
|
|
738
|
+
await reg(loader);
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Register every command in the EXACT order main does (old src/index.ts lines
|
|
743
|
+
* 691-844), including the inline deprecated aliases. Used only on the slow paths
|
|
744
|
+
* (unknown command spellcheck, "did you mean" auto-correct) where the full set
|
|
745
|
+
* of names — and their registration order, which breaks ties in the suggestion
|
|
746
|
+
* picker — must match main byte-for-byte.
|
|
747
|
+
*/
|
|
748
|
+
async function registerAllEagerCommands() {
|
|
749
|
+
await reg(loadView);
|
|
750
|
+
await reg(loadInspect);
|
|
751
|
+
await reg(loadFeedback);
|
|
752
|
+
await reg(loadCommands);
|
|
753
|
+
await reg(loadHooks);
|
|
754
|
+
await reg(loadSkills);
|
|
755
|
+
await reg(loadRules);
|
|
756
|
+
registerMemoryCommand(program);
|
|
757
|
+
await reg(loadPermissions);
|
|
758
|
+
registerPermsAliasCommand(program);
|
|
759
|
+
await reg(loadMcp);
|
|
760
|
+
await reg(loadCli);
|
|
761
|
+
await reg(loadSubagents);
|
|
762
|
+
await reg(loadPlugins);
|
|
763
|
+
await reg(loadWorkflows);
|
|
764
|
+
await reg(loadWorktree);
|
|
765
|
+
await reg(loadVersions);
|
|
766
|
+
await reg(loadImport);
|
|
767
|
+
await reg(loadPackages);
|
|
768
|
+
await reg(loadDaemon);
|
|
769
|
+
await reg(loadRoutines);
|
|
770
|
+
await reg(loadRun);
|
|
771
|
+
await reg(loadDefaults);
|
|
772
|
+
await reg(loadModels);
|
|
773
|
+
await reg(loadPrune);
|
|
774
|
+
await reg(loadTrash);
|
|
775
|
+
await reg(loadRestore);
|
|
776
|
+
await reg(loadDoctor);
|
|
777
|
+
registerExecAliasCommand(program);
|
|
778
|
+
await reg(loadProfiles);
|
|
779
|
+
await reg(loadSecrets);
|
|
780
|
+
await reg(loadWallet);
|
|
781
|
+
await reg(loadHelper);
|
|
782
|
+
await reg(loadMenubar);
|
|
783
|
+
await reg(loadBeta);
|
|
784
|
+
await reg(loadSync);
|
|
785
|
+
await reg(loadRefreshRules);
|
|
786
|
+
await reg(loadDrive);
|
|
787
|
+
await reg(loadFactory);
|
|
788
|
+
await reg(loadUsage);
|
|
789
|
+
await reg(loadCost);
|
|
790
|
+
await reg(loadBudget);
|
|
791
|
+
await reg(loadAlias);
|
|
792
|
+
await reg(loadPty);
|
|
793
|
+
await reg(loadTmux);
|
|
794
|
+
await reg(loadBrowser);
|
|
795
|
+
await reg(loadComputer);
|
|
796
|
+
registerJobsCronAliasCommand(program, 'jobs');
|
|
797
|
+
registerJobsCronAliasCommand(program, 'cron');
|
|
798
|
+
registerUpgradeCommand(program);
|
|
799
|
+
await reg(loadPull);
|
|
800
|
+
await reg(loadPush);
|
|
801
|
+
await reg(loadRepo);
|
|
802
|
+
await reg(loadSetup);
|
|
803
|
+
}
|
|
769
804
|
/** Calculate the Levenshtein edit distance between two strings. */
|
|
770
805
|
function levenshtein(a, b) {
|
|
771
806
|
const m = a.length;
|
|
@@ -812,45 +847,54 @@ program.on('command:*', (operands) => {
|
|
|
812
847
|
}
|
|
813
848
|
process.exit(1);
|
|
814
849
|
});
|
|
815
|
-
//
|
|
816
|
-
|
|
817
|
-
//
|
|
818
|
-
// fire-and-forget the next background sync. System repo gets a real fast-forward
|
|
819
|
-
// pull (read-only locally, safe). User repo and extras get fetch-only + a
|
|
820
|
-
// status marker that we'll print on the *next* invocation.
|
|
821
|
-
const { spawnDetachedSync } = await import('./lib/auto-pull.js');
|
|
822
|
-
spawnDetachedSync();
|
|
823
|
-
// First-run experience: no args + no config yet + TTY -> launch interactive setup.
|
|
824
|
-
// Skipped when stdin/stdout isn't a terminal (CI, pipes) or when user passes any args.
|
|
850
|
+
// Parse the invocation shape up front: the first non-flag token is the command,
|
|
851
|
+
// and the doc flags (--version/--help/-h) drive both the registration strategy
|
|
852
|
+
// and whether the update check + background sync run at all.
|
|
825
853
|
const passedArgs = process.argv.slice(2);
|
|
826
854
|
const requestedCommand = passedArgs.find((arg) => !arg.startsWith('-'));
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
const { registerTeamsCommands } = await import('./commands/teams.js');
|
|
841
|
-
registerTeamsCommands(program);
|
|
842
|
-
break;
|
|
843
|
-
}
|
|
844
|
-
case 'cloud': {
|
|
845
|
-
const { registerCloudCommands } = await import('./commands/cloud.js');
|
|
846
|
-
registerCloudCommands(program);
|
|
847
|
-
break;
|
|
848
|
-
}
|
|
849
|
-
default:
|
|
850
|
-
break;
|
|
855
|
+
// Help and version output are pure documentation — they must never gate on
|
|
856
|
+
// setup, otherwise `agents <cmd> --help` becomes useless on a fresh box.
|
|
857
|
+
const helpOrVersionRequested = passedArgs.some((arg) => arg === '--help' || arg === '-h' || arg === '--version' || arg === '-V');
|
|
858
|
+
// Register only the command(s) this invocation actually uses. Lazy commands
|
|
859
|
+
// (sessions/teams/cloud) are handled after applyGlobalHelpConventions below.
|
|
860
|
+
const isLazyRequest = requestedCommand !== undefined && LAZY_COMMAND_NAMES.has(requestedCommand);
|
|
861
|
+
if (requestedCommand !== undefined && !isLazyRequest) {
|
|
862
|
+
const known = await registerEagerForRequest(requestedCommand);
|
|
863
|
+
if (!known) {
|
|
864
|
+
// Unknown top-level command: register the full tree so the "did you mean"
|
|
865
|
+
// spellcheck and edit-distance-1 auto-correct (the command:* handler above)
|
|
866
|
+
// see the same candidate set — and ordering — as main.
|
|
867
|
+
await registerAllEagerCommands();
|
|
851
868
|
}
|
|
852
869
|
}
|
|
853
|
-
|
|
870
|
+
// When requestedCommand is undefined (bare invocation, --version, --help, -h) no
|
|
871
|
+
// command modules are needed: --version is built in and the root help text is a
|
|
872
|
+
// static string.
|
|
873
|
+
// Mirror main: help conventions are applied after the eager command tree and
|
|
874
|
+
// before the lazy commands, so the latter inherit the root's custom help
|
|
875
|
+
// formatter instead of getting the per-command recursive pass.
|
|
876
|
+
applyGlobalHelpConventions(program);
|
|
877
|
+
// Lazy commands pull in the SQLite-backed session/cloud stack; register them
|
|
878
|
+
// only when explicitly requested, keeping lightweight commands off that path.
|
|
879
|
+
if (isLazyRequest) {
|
|
880
|
+
for (const loader of COMMAND_LOADERS[requestedCommand])
|
|
881
|
+
await reg(loader);
|
|
882
|
+
}
|
|
883
|
+
// Pure documentation paths (--version / --help / -h) return immediately: skip
|
|
884
|
+
// the update check (PATH scan + cache read) and the detached background sync
|
|
885
|
+
// (spawns a child process) that every other invocation runs.
|
|
886
|
+
if (!helpOrVersionRequested) {
|
|
887
|
+
// Run update check before parsing so the upgrade notice/prompt precedes output.
|
|
888
|
+
await checkForUpdates();
|
|
889
|
+
// Surface any "behind upstream" notices from the previous detached sync, then
|
|
890
|
+
// fire-and-forget the next background sync. System repo gets a real fast-forward
|
|
891
|
+
// pull (read-only locally, safe). User repo and extras get fetch-only + a
|
|
892
|
+
// status marker that we'll print on the *next* invocation.
|
|
893
|
+
const { spawnDetachedSync } = await import('./lib/auto-pull.js');
|
|
894
|
+
spawnDetachedSync();
|
|
895
|
+
}
|
|
896
|
+
// First-run experience: no args + no config yet + TTY -> launch interactive setup.
|
|
897
|
+
// Skipped when stdin/stdout isn't a terminal (CI, pipes) or when user passes any args.
|
|
854
898
|
const metaFilePath = path.join(getUserAgentsDir(), 'agents.yaml');
|
|
855
899
|
const firstRun = passedArgs.length === 0 &&
|
|
856
900
|
!fs.existsSync(metaFilePath) &&
|
|
@@ -858,6 +902,7 @@ const firstRun = passedArgs.length === 0 &&
|
|
|
858
902
|
process.stdout.isTTY;
|
|
859
903
|
if (firstRun) {
|
|
860
904
|
try {
|
|
905
|
+
const { runSetup } = await import('./commands/setup.js');
|
|
861
906
|
await runSetup(program);
|
|
862
907
|
}
|
|
863
908
|
catch (err) {
|
|
@@ -870,9 +915,6 @@ if (firstRun) {
|
|
|
870
915
|
// Every command requires the system repo to be cloned first. `setup` is the
|
|
871
916
|
// only exemption — it's the command that does the cloning.
|
|
872
917
|
const SETUP_EXEMPT_COMMANDS = new Set(['setup', 'help']);
|
|
873
|
-
// Help and version output are pure documentation — they must never gate on
|
|
874
|
-
// setup, otherwise `agents <cmd> --help` becomes useless on a fresh box.
|
|
875
|
-
const helpOrVersionRequested = passedArgs.some((arg) => arg === '--help' || arg === '-h' || arg === '--version' || arg === '-V');
|
|
876
918
|
// Fold legacy ~/.agents-system/ into ~/.agents/.system/ BEFORE ensureInitialized
|
|
877
919
|
// runs. ensureInitialized checks for .git inside the new path; if the user is
|
|
878
920
|
// upgrading from a layout where .git lives under the legacy path, the check
|
|
@@ -9,6 +9,7 @@ import type { CloudProvider, CloudTask, CloudTaskStatus, CloudEvent, DispatchOpt
|
|
|
9
9
|
export declare class CodexCloudProvider implements CloudProvider {
|
|
10
10
|
id: "codex";
|
|
11
11
|
name: string;
|
|
12
|
+
targetKind: "env";
|
|
12
13
|
private defaultEnv?;
|
|
13
14
|
constructor(config?: {
|
|
14
15
|
env?: string;
|
package/dist/lib/cloud/codex.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { spawn, execFileSync } from 'child_process';
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
|
-
import { resolveDispatchRepos } from './types.js';
|
|
11
|
+
import { resolveDispatchRepos, MissingTargetError } from './types.js';
|
|
12
12
|
import { getShimsDir } from '../state.js';
|
|
13
13
|
const SHIMS_DIR = getShimsDir();
|
|
14
14
|
/** Map a Codex Cloud status string to the canonical CloudTaskStatus enum. */
|
|
@@ -85,6 +85,10 @@ function parseTaskFromText(text) {
|
|
|
85
85
|
export class CodexCloudProvider {
|
|
86
86
|
id = 'codex';
|
|
87
87
|
name = 'Codex Cloud';
|
|
88
|
+
targetKind = 'env';
|
|
89
|
+
// No listTargets: OpenAI ships no non-interactive "list environments"
|
|
90
|
+
// command. `codex cloud exec` requires --env and the help points at the
|
|
91
|
+
// interactive `codex cloud` TUI to browse. So discovery is guidance-only.
|
|
88
92
|
defaultEnv;
|
|
89
93
|
constructor(config) {
|
|
90
94
|
this.defaultEnv = config?.env;
|
|
@@ -107,7 +111,9 @@ export class CodexCloudProvider {
|
|
|
107
111
|
async dispatch(options) {
|
|
108
112
|
const env = options.providerOptions?.env ?? this.defaultEnv;
|
|
109
113
|
if (!env) {
|
|
110
|
-
throw new
|
|
114
|
+
throw new MissingTargetError('env', 'Codex Cloud requires --env <id>.', 'Codex environments are created in the Codex web UI and bundle a repo + setup. ' +
|
|
115
|
+
'Browse yours with `codex cloud` (interactive), then re-run with --env <id> ' +
|
|
116
|
+
'or set a default in ~/.agents/agents.yaml under cloud.providers.codex.env.');
|
|
111
117
|
}
|
|
112
118
|
// Codex envs bundle their own repo list — the repos a task can touch are
|
|
113
119
|
// fixed at env-creation time, not per-dispatch. Passing 2+ repos here is
|