Skip to content

Fix: describe what --file_type actually selects in the CLI help - #358

Open
AmaadMartin wants to merge 1 commit into
mainfrom
fix/cli-bundle-file-type-help-text
Open

Fix: describe what --file_type actually selects in the CLI help#358
AmaadMartin wants to merge 1 commit into
mainfrom
fix/cli-bundle-file-type-help-text

Conversation

@AmaadMartin

@AmaadMartin AmaadMartin commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):
    No existing issue.
  2. Or, if no issue exists, describe the change:
    Problem: AGENT_FILE_MODULE_TYPE in dev/src/cli/cli.ts shipped the placeholder description 'Optional. ', so --file_type rendered with no information at all:
  --file_type <string>             Optional.  (choices: "cjs", "esm")

The option is a shared Option instance registered on six command surfaces (adk web, adk api_server, adk run, adk deploy cloud_run, adk deploy agent_engine, adk deploy reasoning_engine), so the empty description appears six times. There is no other user-facing documentation for this flag in the repo — the help string is the documentation — so nothing tells a reader what picking cjs over esm actually changes.

Solution: Replace the placeholder with the behaviour read off the implementation, not invented:

  • The value becomes esbuild's output format (dev/src/utils/agent_loader.ts, AgentFile.load()), and selects the emitted file's extension through FILE_MODULE_TYPE_EXTENSION_MAPcjs.cjs, esm.mjs.
  • When the flag is omitted, getFileModuleType() infers the format from the agent file extension (.cjs/.cts → cjs, .mjs/.mts → esm) and otherwise from the nearest package.json "type" field via getTypeFromPackageJson().

This is a pure help-text change with no behavioural change. The flag spelling --file_type <string> is unchanged, it still has no default, and argChoices is untouched — so parsing and the values handed to agent_loader are byte-identical. The description deliberately does not repeat the cjs/esm list, because commander (v14, per dev/package.json) appends (choices: "cjs", "esm") itself from argChoices; that auto-append was verified against the rendered help rather than assumed, and is pinned by a test assertion.

Before (adk web --help):

  --compile [boolean]              Optional. Whether to compile ts agent file to
                                   js before execution (default: true)
  --bundle [boolean]               Optional. Whether to compile ts agent file to
                                   js before execution (default: true)
  --file_type <string>             Optional.  (choices: "cjs", "esm")
  --a2a [boolean]                  Optional. Whether to enable A2A for web/api
                                   server. Default: false (default: false)

After (adk web --help):

  --compile [boolean]              Optional. Whether to compile ts agent file to
                                   js before execution (default: true)
  --bundle [boolean]               Optional. Whether to compile ts agent file to
                                   js before execution (default: true)
  --file_type <string>             Optional. The module format of the compiled
                                   agent file: cjs emits CommonJS to a .cjs
                                   file, esm emits an ES module to a .mjs file.
                                   If not set, the format is detected from the
                                   agent file extension and the nearest
                                   package.json "type" field. (choices: "cjs",
                                   "esm")
  --a2a [boolean]                  Optional. Whether to enable A2A for web/api
                                   server. Default: false (default: false)

Scope note — --bundle is deliberately NOT touched here. The original task also covered --bundle, whose description is a verbatim copy of --compile's. A collision check found that is already fixed by a live PR, and that a second live PR is actively changing what the flag means:

Testing Plan

Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
Unit Tests:
[x] I have added or updated unit tests for my change.
[x] All unit tests pass locally.

New describe('option help text') block in dev/test/cli/cli_test.ts. No existing test was edited, reordered, skipped or deleted — the block is purely additive and sits after describe('command: version'). It drives it.each over all six command surfaces, reads cmd.helpInformation(), and asserts the --file_type entry:

  1. is no longer the bare placeholder (/^--file_type <string> Optional\. \(choices/);
  2. names both emitted extensions (.cjs, .mjs);
  3. still carries commander's auto-appended (choices: "cjs", "esm"), pinning that argChoices survives and is not duplicated in the description.

Assertions run against a whitespace-normalized slice of the rendered help so they do not break when commander re-wraps columns, and the slice is scoped to the --file_type entry so a match cannot be satisfied by some other option's text. The help is deliberately not snapshotted — a full snapshot would turn every unrelated option addition into a failure.

$ npm test -- dev/test/cli/cli_test.ts
 ✓ |unit:dev| dev/test/cli/cli_test.ts (27 tests) 59ms
 Test Files  1 passed (1)
      Tests  27 passed (27)

Proof the tests can fail (mutation testing). Each new test was run against mutated source and confirmed to FAIL:

  • Mutation 1 — revert the fix (restore new Option('--file_type <string>', 'Optional. ')): all 6 new tests fail.
    AssertionError: expected '--file_type <string> Optional. (choic…' not to match /^--file_type <string> Optional\. \(ch…/
    - Expected: /^--file_type <string> Optional\. \(choices/
    + Received: "--file_type <string> Optional. (choices: \"cjs\", \"esm\")"
          Tests  6 failed | 21 passed (27)
    
  • Mutation 2 — non-placeholder but uninformative description ('Optional. The module format.'), to prove the content assertions are not dead weight: all 6 fail.
    AssertionError: expected '--file_type <string> Optional. The mo…' to contain '.cjs'
    Received: "--file_type <string> Optional. The module format. (choices: \"cjs\", \"esm\")"
    
  • Mutation 3 — delete AGENT_FILE_MODULE_TYPE.argChoices = [...], to prove the choices assertion is live: all 6 fail.
    AssertionError: expected '--file_type <string> Optional. The mo…' to contain '(choices: "cjs", "esm")'
          Tests  6 failed | 21 passed (27)
    

Coverage: the change is two string literals inside createProgram(), which the existing beforeEach already executes, so line/branch coverage of the changed code is 100% by construction. No suppressions of any kind were added (@ts-expect-error, @ts-ignore, eslint-disable, any, as never, coverage-ignore): the pre-PR grep over git diff main -U0 returns zero hits. npm run ts:check reports 313 errors in 53 files both with and without this diff — an identical, pre-existing repo-wide condition in the test tree (already being addressed by separate PRs); this change introduces none of them and none are in the two touched files.

Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.

npm install
npm run build
node dev/dist/esm/cli_entrypoint.js web --help
node dev/dist/esm/cli_entrypoint.js api_server --help
node dev/dist/esm/cli_entrypoint.js run --help
node dev/dist/esm/cli_entrypoint.js deploy cloud_run --help
node dev/dist/esm/cli_entrypoint.js deploy agent_engine --help
node dev/dist/esm/cli_entrypoint.js deploy reasoning_engine --help

Confirm on each surface that the --file_type line reads as in the "After" block above, that it still shows (choices: "cjs", "esm") and still shows no (default: ...), and that no other option line changed. Ran locally on the pushed commit; all six render correctly.

Other local validation on the pushed commit: npm run build (clean), npm run lint (clean, exit 0), npx prettier --check on both touched files (clean).

Checklist

[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.

CI

All checks green: run-tests on ubuntu-latest, macos-latest and windows-latest all pass.

The first windows-latest run failed on two tests in tests/integration/tools/run_skill_script_tool_test.ts ("successfully executes a real Python skill script" and "successfully executes a real PowerShell skill script"), both Error: Test timed out in 5000ms. while spawning a real Python/PowerShell subprocess. That is unrelated to this diff, which touches only dev/src/cli/cli.ts and dev/test/cli/cli_test.ts and cannot affect subprocess spawn latency; the same job passes on sibling PRs, and it passed on re-run with no code change (8m50s vs the 7m41s failing run — a slow-runner flake, not a real failure). Queued separately as a timeout-hardening follow-up rather than papered over here.

The --file_type option shipped the placeholder description 'Optional. ',
so `adk web --help` (and five other command surfaces that share the
option) rendered only "Optional.  (choices: \"cjs\", \"esm\")". Nothing
told the reader what picking cjs over esm actually changes.

Replace it with the behaviour read off AgentFile.load(): the value
becomes esbuild's output `format` and selects the emitted extension via
FILE_MODULE_TYPE_EXTENSION_MAP (cjs -> .cjs, esm -> .mjs), and when the
flag is omitted getFileModuleType() infers it from the agent file
extension and the nearest package.json "type" field.

Pure help-text change: the flag spelling, the absence of a default, and
argChoices are all untouched, so parsing and the values handed to
agent_loader are identical. Commander still appends the choices list
itself, so it is not duplicated in the description.

Add a regression pin over all six command surfaces asserting the entry is
no longer the bare placeholder, that it names both emitted extensions,
and that commander still renders the choices list.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant