Skip to content

Commit ce6a987

Browse files
committed
Migrate all commands
1 parent 61f1ee9 commit ce6a987

File tree

8 files changed

+251
-465
lines changed

8 files changed

+251
-465
lines changed

AGENTS.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ Guide for future agents working on this codebase. Focus on traps, cross-cutting
88
- Config required at runtime: `config/config.publish.json` (or `config.local.json` in dev). Missing files cause a hard exit.
99
- Babel (not tsc) performs builds; target is Node 18 in `babel.config.js` even though `package.json#engines.node` is 20+. Be cautious using very new Node APIs unless polyfilled.
1010

11-
## Command Anatomy (current `args` DSL)
12-
- Every bin uses `command()` from `src/lib/cli/command.js`. It mutates the `args` package: `_opts` is module-scoped, and `args.argv` is replaced to add async parsing, validation, telemetry, and app/env lookup before your handler runs.
11+
## Command Anatomy (current Commander compatibility layer)
12+
- Every bin uses `command()` from `src/lib/cli/command.js`. It wraps `commander` and keeps the legacy handler contract while preserving app/env context resolution, confirmations, telemetry, and output formatting.
1313
- Call shape: `command(opts).option(...).command(...sub...).example(...).argv(process.argv, handler)`. `handler` receives `(subArgsArray, optionsObject)` where `subArgsArray` are positional args (alias removed) and `optionsObject` holds flags plus resolved `app`/`env` when requested.
1414
- `_opts` knobs: `appContext`/`envContext`/`childEnvContext` run GraphQL lookups (using `appQuery` + optional fragments) and interactive prompts when `--app/--env` are missing; `childEnvContext` forbids production. `requiredArgs` enforces positional count; `wildcardCommand` disables subcommand validation. `format` adds `--format` defaulting to table and postprocesses handler results; `requireConfirm` + `--force` gates destructive paths with `enquirer` prompts; `skipConfirmPrompt` bypasses the prompt (used in tests).
1515
- Alias handling happens before parsing: `@app` or `@app.env` is stripped from `argv` in `envAlias.ts` (only before `--`) and populates `options.app/options.env`. Using both alias and `--app/--env` exits with an error.
1616
- Global flags injected everywhere: `--help/--version/--debug`. `--debug` enables `debug` namespaces (`*` when boolean). `update-notifier` runs after validation unless `NODE_ENV=test`.
17+
- Nested subcommands are dispatched by the wrapper to sibling bin scripts (`vip-config` -> `vip-config-envvar` -> `vip-config-envvar-set`) using local `dist/bin` paths when available.
1718
- Output contract: if handler returns `{header,data}` it prints header as key/value then formats `data`; if it returns an array it strips `__typename` and formats; returning `undefined` skips printing. Formatting uses `formatData` with `table|csv|json`.
1819
- Caveat: `_opts` is shared. Instantiating multiple command runners in one process (tests, composite commands) can leak settings—avoid or refactor.
1920

@@ -26,12 +27,12 @@ Guide for future agents working on this codebase. Focus on traps, cross-cutting
2627

2728
## CLI Architecture
2829
- Root executable is `src/bin/vip.js`. It triggers login unless one of: `--help/-h`, `--version/-v`, `logout`, `dev-env` without env args, or `WPVIP_DEPLOY_TOKEN` is set for deploy. Automation that lacks a token should pass `--help` or set `WPVIP_DEPLOY_TOKEN` to avoid interactive prompts that call `open`.
29-
- Command wiring happens through `src/lib/cli/command.js`, a thin wrapper around `args` with custom validation and telemetry. Options in `_opts` control behavior:
30+
- Command wiring happens through `src/lib/cli/command.js`, a `commander`-backed compatibility wrapper with custom validation and telemetry. Options in `_opts` control behavior:
3031
- `appContext`/`envContext`/`childEnvContext` prompt or validate app/env via GraphQL (uses `appQuery` + optional fragments). Child env forbids production.
3132
- `requiredArgs` forces positional arg count; `wildcardCommand` relaxes subcommand validation; `format` auto-adds `--format` and postformats output.
3233
- `requireConfirm` + `--force` gate destructive actions with `enquirer` confirmations; tests should set `skipConfirmPrompt` or pass `--force`.
3334
- Environment aliases like `@app.env` are parsed in `src/lib/cli/envAlias.ts`; aliases are stripped from argv and populate `--app/--env`. Using both alias and explicit flags is rejected.
34-
- `args.argv` is monkey-patched to add the above behavior; avoid invoking multiple command instances in the same process unless you understand the shared `_opts` state.
35+
- Subcommand chaining now happens in the wrapper itself (instead of `args`), so behavior changes here impact the entire CLI tree.
3536

3637
## Auth & Session Flow
3738
- Auth is centralized in `src/bin/vip.js`. It loads a JWT from keychain (`Token.get()`), checks `id/iat/exp`, and considers the CLI “logged in” when valid. A missing/invalid token triggers an interactive login unless the argv contains help/version/logout, a `dev-env` call without env, or a deploy using `WPVIP_DEPLOY_TOKEN`.
@@ -69,12 +70,7 @@ Guide for future agents working on this codebase. Focus on traps, cross-cutting
6970
- Babel pathing relies on relative `__dirname` from transpiled files; when moving files adjust import paths with the compiled layout in mind.
7071
- TypeScript is type-checked separately from the build; Babel will happily emit code that fails `tsc`, so keep `npm run check-types` in the loop during refactors.
7172

72-
## Migration off `args` (e.g., to Commander)
73-
- Preserve pre-parse alias stripping and the “only consider args before `--`” rule in `parseEnvAliasFromArgv`. Reject mixed alias + `--app/--env`.
74-
- Reimplement `_opts` behaviors: GraphQL app/env lookup plus prompts, production ban for child envs, positional validation, wildcard subcommand allowance, `--format` processing, `requireConfirm` + `--force`, and module-specific confirmation payloads (import-sql, sync, import-media).
75-
- Maintain global flags and side effects: help/version/debug on every subcommand; update-notifier (or intentionally suppress); `debug` namespace toggling.
76-
- Keep telemetry hooks (`trackEvent`, `trackEventWithEnv`, `makeCommandTracker`) and the login-time `aliasUser` de-anonymization.
77-
- Match handler contracts: handler args `(subArgs, options)`; output formatting expectations (array or `{header,data}`); `__typename` stripping.
78-
- Respect exit semantics: uncaught exceptions routed to `exit.withError`; GraphQL errors call `process.exit(1)` unless explicitly disabled; 401 auth errors exit with guidance.
79-
- Watch shared state: current implementation mutates a global; ensure new parser avoids cross-command bleeding when multiple command instances run in-process (tests/CLI wrappers).
80-
- Login guardrails in `vip.js` let certain commands bypass auth; preserve equivalent shortcuts or add explicit non-interactive flags for CI.
73+
## Commander Migration Status
74+
- Core parser migration is active in `src/lib/cli/command.js`; command bins using this wrapper run on Commander semantics.
75+
- High-risk parity points still worth verifying during further cleanup: help text formatting parity, boolean option edge cases, and deeply nested subcommand/alias combinations.
76+
- Keep alias stripping behavior (`parseEnvAliasFromArgv`), `_opts` contracts, and telemetry hooks stable while iterating.

npm-shrinkwrap.json

Lines changed: 0 additions & 114 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@
142142
"@automattic/vip-search-replace": "^2.0.0",
143143
"@json2csv/plainjs": "^7.0.3",
144144
"@wwa/single-line-log": "^1.1.4",
145-
"args": "5.0.3",
146145
"chalk": "^5.6.2",
147146
"check-disk-space": "3.4.0",
148147
"cli-columns": "^4.0.0",

src/bin/vip-logout.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22

3-
import { command } from '../lib/cli/command-commander';
3+
import command from '../lib/cli/command';
44
import logout from '../lib/logout';
55

66
void command( { usage: 'vip logout' } )

src/bin/vip-whoami.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { Me } from '../graphqlTypes';
44
import { getCurrentUserInfo } from '../lib/api/user';
5-
import { command } from '../lib/cli/command-commander';
5+
import command from '../lib/cli/command';
66
import * as exit from '../lib/cli/exit';
77
import { trackEvent } from '../lib/tracker';
88

src/bin/vip.js

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@
33
import '../lib/node-version-check';
44

55
import chalk from 'chalk';
6-
import { Command } from 'commander';
76
import debugLib from 'debug';
87
import { prompt } from 'enquirer';
98

10-
import pkg from '../../package.json';
9+
import command, { containsAppEnvArgument } from '../lib/cli/command';
1110
import config from '../lib/cli/config';
12-
import { parseEnvAliasFromArgv } from '../lib/cli/envAlias';
1311
import Token from '../lib/token';
1412
import { aliasUser, trackEvent } from '../lib/tracker';
1513

@@ -27,29 +25,8 @@ const tokenURL = 'https://dashboard.wpvip.com/me/cli/token';
2725
const customDeployToken = process.env.WPVIP_DEPLOY_TOKEN;
2826

2927
const runCmd = async function () {
30-
const cmd = new Command();
28+
const cmd = command();
3129
cmd
32-
.name( 'vip' )
33-
.version(
34-
pkg.version,
35-
'-v, --version',
36-
'Retrieve the version number of VIP-CLI currently installed on the local machine.'
37-
)
38-
.helpOption(
39-
'-h, --help',
40-
'Retrieve a description, examples, and available options for a (sub)command.'
41-
)
42-
.option(
43-
'-d, --debug [namespaces]',
44-
'Generate verbose output during command execution to help identify or fix errors or bugs.',
45-
value => {
46-
const namespaces = value || '*';
47-
debugLib.enable( namespaces );
48-
process.env.DEBUG = namespaces;
49-
50-
return value || true;
51-
}
52-
)
5330
.command( 'logout', 'Log out the current authenticated VIP-CLI user.' )
5431
.command(
5532
'app',
@@ -72,7 +49,7 @@ const runCmd = async function () {
7249
.command( 'whoami', 'Retrieve details about the current authenticated VIP-CLI user.' )
7350
.command( 'wp', 'Execute a WP-CLI command against an environment.' );
7451

75-
await cmd.parseAsync( process.argv );
52+
await cmd.argv( process.argv );
7653
};
7754

7855
/**
@@ -84,18 +61,6 @@ function doesArgvHaveAtLeastOneParam( argv, params ) {
8461
return argv.some( arg => params.includes( arg ) );
8562
}
8663

87-
/**
88-
* @param {string[]} argv
89-
* @returns {boolean}
90-
*/
91-
function containsAppEnvArgument( argv ) {
92-
const parsedAlias = parseEnvAliasFromArgv( argv );
93-
94-
return Boolean(
95-
parsedAlias.app || parsedAlias.env || argv.includes( '--app' ) || argv.includes( '--env' )
96-
);
97-
}
98-
9964
const rootCmd = async function () {
10065
let token = await Token.get();
10166

0 commit comments

Comments
 (0)