Skip to content

Commit 7544386

Browse files
authored
Agents and Claude (#2735)
1 parent 1e6592b commit 7544386

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

AGENTS.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# AGENTS: vip-cli
2+
3+
Guide for future agents working on this codebase. Focus on traps, cross-cutting constraints, and how to avoid breaking prod while refactoring or migrating the CLI parser.
4+
5+
## Repo Orientation
6+
- Entrypoints live in `src/bin` (one file per CLI command) and are compiled to `dist/**`. Do not edit `dist`; rebuild via `npm run build` before publishing.
7+
- Shared logic sits under `src/lib`; GraphQL command wrappers in `src/commands`; fixtures/tests in `__fixtures__` and `__tests__` (E2E lives in `__tests__/devenv-e2e`).
8+
- Config required at runtime: `config/config.publish.json` (or `config.local.json` in dev). Missing files cause a hard exit.
9+
- 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.
10+
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.
13+
- 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.
14+
- `_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).
15+
- 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.
16+
- Global flags injected everywhere: `--help/--version/--debug`. `--debug` enables `debug` namespaces (`*` when boolean). `update-notifier` runs after validation unless `NODE_ENV=test`.
17+
- 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`.
18+
- Caveat: `_opts` is shared. Instantiating multiple command runners in one process (tests, composite commands) can leak settings—avoid or refactor.
19+
20+
## Build, Test, Tooling
21+
- `npm test` runs lint + type-check + jest; slow. Use `npm run jest` to skip lint/tsc when iterating. `NODE_ENV=test` also suppresses the update-notifier network call in `src/lib/cli/command.js`.
22+
- E2E dev-env tests (`npm run test:e2e:dev-env`) require Docker + Lando and will mutate the host; they are excluded from the default test script.
23+
- GraphQL types are generated from a private `schema.gql` (`codegen.ts`). To regenerate you need that schema plus `npm run typescript:codegen:*`; do not hand-edit `src/graphqlTypes.d.ts` or `*.generated.d.ts` files.
24+
- go-search-replace binaries are needed for some runtime paths and tests; fixtures live in `__fixtures__/search-replace-binaries`. Without them certain commands/tests will fail silently or skip.
25+
- Postinstall runs `helpers/check-version.js` and will exit if Node is outside the engine range; keep the local version aligned.
26+
27+
## CLI Architecture
28+
- 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+
- `appContext`/`envContext`/`childEnvContext` prompt or validate app/env via GraphQL (uses `appQuery` + optional fragments). Child env forbids production.
31+
- `requiredArgs` forces positional arg count; `wildcardCommand` relaxes subcommand validation; `format` auto-adds `--format` and postformats output.
32+
- `requireConfirm` + `--force` gate destructive actions with `enquirer` confirmations; tests should set `skipConfirmPrompt` or pass `--force`.
33+
- 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+
36+
## Auth & Session Flow
37+
- 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`.
38+
- Login flow: prints banner, opens `https://dashboard.wpvip.com/me/cli/token` via `open`, prompts for token with `enquirer`, decodes and validates JWT, stores it (`Token.set()`), de-anonymizes analytics via `aliasUser`, then re-enters command dispatch. Errors (expired/malformed) exit with guidance and telemetry events.
39+
- Token storage is per-`API_HOST`: service name changes with host, so switching to staging/local uses a different stored token.
40+
- Downstream commands assume valid auth. The Apollo client exits on 401 unless constructed with `silenceAuthErrors`/`exitOnError=false`.
41+
42+
## API/GraphQL Layer
43+
- `src/lib/api.ts` builds an Apollo client with `ErrorLink` that prints GraphQL errors and calls `process.exit(1)` by default. Use `disableGlobalGraphQLErrorHandling()` in tests to keep errors throwable.
44+
- Retry logic only retries queries (not mutations) and stops after 5 attempts; ECONNREFUSED triggers retry, 4xx (except 429) does not. Be careful when wrapping mutations—errors will not retry.
45+
- On 401, the client prints a custom message and exits; ensure authenticated tests stub the network or set `silenceAuthErrors`/`exitOnError=false` when constructing the client.
46+
47+
## Dev-Env Subsystem (High Blast Radius)
48+
- Implemented under `src/lib/dev-environment/**`; shells out to Lando and Docker, renders templates from `assets/dev-env.*.ejs`, and writes to per-environment folders inside `xdgData()/vip-cli` (overridden by `XDG_DATA_HOME`). Running these commands mutates local docker networks and may fetch WP/PHP version metadata from GitHub constants.
49+
- Proxy helpers live in `src/lib/http/proxy-*`; dev-env code constructs agents automatically using `VIP_PROXY`/`SOCKS_PROXY`/`HTTP_PROXY`/`VIP_USE_SYSTEM_PROXY`. Unexpected proxies can break downloads—clear those env vars when debugging.
50+
- Avoid invoking dev-env logic in unit tests unless you mock `lando`, filesystem, and network; the E2E suite covers the real paths.
51+
52+
## Import/Export/Sync Commands (high validation)
53+
- Heavy validators live in `src/lib/site-import/**` and `src/lib/validations/**`. `vip import sql` enforces file name rules, extension checks, size caps (`SQL_IMPORT_FILE_SIZE_LIMIT*`), and detects multisite; it may upload to S3 via `src/lib/client-file-uploader.ts` (expects readable file or URL and optional MD5). These paths also emit analytics; use `NODE_ENV=test` and stubs to avoid network.
54+
- Sync/backup/snapshot commands rely on GraphQL fields like `syncPreview` and environment metadata; `command.js` will prompt for app/env selection via GraphQL if not provided.
55+
- These commands stack multiple prompts (confirm, reload manifest, error-log download); in headless runs pass `--force` and other flags to skip interaction.
56+
57+
## Data Paths & Temp Files
58+
- Temporary working dirs are created with `makeTempDir()` and cleaned up on normal exit only. Crashes may leave artifacts under the system tmp folder.
59+
- Persistent data (tokens, analytics UUID, dev-env state, caches) lands in Configstore or under `xdgData()`; clean those if you hit unexplained state issues.
60+
61+
## Release & Packaging
62+
- `prepare` runs `npm run clean && npm run build`; npm package bins point to `dist/**`. Always rebuild before publishing so dist matches src.
63+
- `helpers/prepublishOnly.js` enforces branch `trunk` for `npm publish --tag latest` and optionally reruns `npm test`. Release flows expect a clean node version that satisfies `engines.node`.
64+
65+
## Common Pitfalls Checklist
66+
- Running CLI without a token opens a browser (`open`) and waits for interactive input—pass `--help` or set `WPVIP_DEPLOY_TOKEN` in automation.
67+
- Forgetting `--app/--env` or alias when a command expects them triggers extra GraphQL lookups and prompts; in headless contexts set `_opts.appContext=false` or supply explicit flags.
68+
- Analytics + update-notifier will reach the public internet unless `DO_NOT_TRACK=1` and `NODE_ENV=test` are set.
69+
- Babel pathing relies on relative `__dirname` from transpiled files; when moving files adjust import paths with the compiled layout in mind.
70+
- 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.
71+
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.

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# CLAUDE
2+
3+
For guidance on working in this repo, traps, and migration notes, see `AGENTS.md`.

0 commit comments

Comments
 (0)