Skip to content

Add Terminal49 TypeScript CLI (production-ready) - #310

Merged
dodeja merged 11 commits into
mainfrom
cursor/cli-production-ready-c38e
Aug 14, 2026
Merged

Add Terminal49 TypeScript CLI (production-ready)#310
dodeja merged 11 commits into
mainfrom
cursor/cli-production-ready-c38e

Conversation

@dodeja

@dodejadodeja commented Aug 1, 2026

Copy link
Copy Markdown
Member

Summary

Production-ready follow-up to #223. Rebases the TypeScript CLI onto current main, fixes the remaining Codex review blockers, and wires @terminal49/cli into release automation.

  • Add sdks/typescript-sdk-cli (t49 / @terminal49/cli@0.1.0) on shared action() / listAction() helpers
  • Expand @terminal49/sdk with the resource surface the CLI needs (webhooks, vessels, ports, terminals, parties, metro areas, custom fields, container map/custom fields/demurrage, shipment custom fields) plus mapper re-exports
  • Keep MCP eval CI from main and add a cli CI job
  • FixsetCustomField POST body to OpenAPI shape (data.attributes.api_slug / value)
  • Fix--format raw no longer stripped by a loose { data } envelope check (branded cliEnvelope)
  • Sanitize fixtures, switch live capture script to npm (was pnpm)
  • Add release-please package + publish_typescript_cli.yml; bump CLI’s SDK dep when the SDK releases

Supersedes conflicted #223 (codex/update-typescript-sdk-cli-current).

Release order after merge

  1. Merge this PR
  2. Let release-please open/publish the SDK bump first (new surface is not on npm @terminal49/sdk@0.3.1)
  3. Then publish CLI0.1.0 (depends on the new SDK version)

Verification

  • Local + CI green: sdk / cli / mcp (Node 20/22/24)
  • npm run test --workspace @terminal49/sdk -- --run — 106 passed
  • npm run test --workspace @terminal49/cli — 22 passed
  • npm run test --workspace @terminal49/mcp -- --run — 149 passed
  • node sdks/typescript-sdk-cli/dist/bin/t49.js --version0.1.0

Review notes

Addresses outstanding Codex comments on #223:

  • custom-field attributes payload
  • raw JSON:API envelope unwrap
  • plus rebase / CI merge with MCP eval
Open in WebOpen in Cursor

View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Greptile Summary

The PR adds a production TypeScript CLI, expands the SDK resource surface it consumes, and wires both packages into CI and release automation.

  • Adds command registration, configuration, formatting, pagination, error handling, and tests for @terminal49/cli.
  • Adds SDK methods for webhooks, vessels, ports, terminals, parties, custom fields, and additional container and shipment operations.
  • Adds CLI CI, release-please configuration, generated SDK reference updates, and an npm publish workflow.

Confidence Score: 4/5

The release configuration should be fixed before merging because the next SDK bump can leave the CLI workspace lockfile inconsistent and block CLI CI and publication.

The SDK release now edits the CLI's SDK dependency, while both CLI CI and publishing consume a root lockfile whose matching workspace dependency is not included in release-please's updates.

Files Needing Attention: .release-please-config.json and package-lock.json

Important Files Changed

FilenameOverview
sdks/typescript-sdk-cli/src/commands/action.tsIntroduces shared command execution, global-option resolution, pagination envelopes, and all-page streaming.
sdks/typescript-sdk/src/client.tsExpands the public client with resource-specific methods and manager facades required by the CLI.
.release-please-config.jsonAdds CLI release configuration but leaves the root lockfile's CLI SDK dependency outside the SDK bump synchronization.
.github/workflows/publish_typescript_cli.ymlAdds guarded npm publication for CLI releases, but its root npm ci is exposed to the release-generated lockfile drift.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
User[t49 CLI user] --> CLI["@terminal49/cli"]
CLI --> SDK["@terminal49/sdk"]
SDK --> API[Terminal49 API]
RP[release-please] --> SDKManifest[SDK package version]
RP --> CLIManifest[CLI SDK dependency]
CLIManifest --> Lockfile[Root package-lock.json]
Lockfile --> CI[CLI CI and publish npm ci]
CI --> NPM[npm registry]
Loading

Fix all with Greploop

Fix All in CodexFix All in Claude Code

Prompt To Fix All With AI
### Issue 1
.release-please-config.json:34-38
**CLI lockfile dependency stays stale**
When release-please bumps the SDK, this entry updates the CLI package's `@terminal49/sdk` dependency without updating the corresponding CLI workspace dependency in the root lockfile. The subsequent root-level `npm ci` used by CLI CI and publishing rejects the inconsistent manifest and lockfile, preventing the CLI from building or publishing.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "chore(cli): add release-please package a..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used (3)

dodejaand others added 11 commits August 1, 2026 00:56
The SDK moved to 0.3.0 on main while this branch was open. The CLI's
package.json still pinned ^0.2.0, so npm installed a separate published
copy instead of resolving the in-repo workspace package, hiding the new
resource surface (webhooks, vessels, ports, custom fields, etc.) from
the CLI's type checker. Regenerate package-lock.json accordingly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- config.ts: `config list`, `clear`, `auth-status`, and `client-check`
were wired as `async (command: Command) => ...`, but Commander calls
zero-positional-arg actions as `(options, command)`. The first
runtime argument was the parsed options object, not the Command, so
`command.optsWithGlobals()` threw. Add the missing options parameter
and read globals off the real command argument.
- custom-field-options.ts: `get <definition-id> <option-id>` had the
same bug — missing the options parameter before `command`, so
`command` was actually the options object and `optsWithGlobals()`
threw on every call.
- config.ts (root config module): when `XDG_CONFIG_HOME` is set, nest
the config file under a `terminal49/` subdirectory instead of writing
`config.json` directly at the XDG root, avoiding collisions with
other apps' config files.
- containers.ts (SDK): `demurrage()` read `data.data.attributes`
assuming a raw JSON:API document, but `this.get()` honors the
manager's configured default format. Force `format: 'raw'` so the
fields are populated regardless of client format configuration.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Exposes client/mappers (mapTrackingRequest, etc.) from the package entry
so the CLI can normalize create/infer responses to mapped output.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Public repo: sanitize captured API fixtures (synthetic company names,
fake UUIDs/container/BOL numbers with referential consistency) and delete
the committed live table renders (used by no test). Gitignore the table
fixture dir and coverage output so live captures cannot be re-committed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…avior bugs
Collapse the per-command formatter/client/error boilerplate into one typed
action()/listAction() helper, eliminating the drift it caused. Fixes:
- --fields now projects list rows ({items:[...]}) instead of returning {}
- usage errors exit 2 with the JSON envelope; NetworkError->9, AuthError->3
- drop filter flags the API silently ignores (--carrier/--port/--status/
--updated-after); add supported --number/--tracking-stopped; map
tracking-requests --status to filter[status]
- honor global --format everywhere, incl. create/infer (mapped/raw/both)
- --type override now beats SDK inference
- single strict JSON payload parser (errors on non-object; supports '-' stdin)
- config: reject unknown keys (exit 2), redact token, surface corrupt files
- richer 't49 commands --json' metadata (args, required, choices, globals)
- expose SDK coverage: --all iteration, --account-id, --timeout, --include
- table output: per-command columns + key-value detail panel
Remove dead surface (--quiet/--verbose/--no-color, polling/pagination utils).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix main/types to dist/src, add exports map, publishConfig.access, LICENSE,
repository metadata, engines>=20. Migrate lint/format from Biome to
oxlint/oxfmt (matching the SDK), drop the unused chalk dependency and
regenerate the root lockfile, strengthen prepublishOnly, and add a cli job
to CI that builds the SDK first then builds/tests/lints the CLI.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align container/shipment setCustomField POST bodies with the OpenAPI
schema so CLI set-custom-field calls are accepted by the API.
Co-authored-by: Akshay Dodeja <dodeja@gmail.com>
Brand list envelopes explicitly, keep --format raw intact (included/
links/meta), switch fixture capture to npm, and pin the workspace SDK
dependency to 0.3.1.
Co-authored-by: Akshay Dodeja <dodeja@gmail.com>
Wire @terminal49/cli into release automation and bump its SDK
dependency when the SDK releases.
Co-authored-by: Akshay Dodeja <dodeja@gmail.com>
@vercel

vercelBot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
apiReadyReadyPreviewAug 1, 2026 1:00am

Request Review

@mintlify

mintlifyBot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

ProjectStatusPreviewUpdated (UTC)
terminal49🟢 ReadyView PreviewAug 1, 2026, 2:10 AM

Comment on lines +34 to 38
"type": "json",
"path": "sdks/typescript-sdk-cli/package.json",
"jsonpath": "$.dependencies['@terminal49/sdk']"
}
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1CLI lockfile dependency stays stale

When release-please bumps the SDK, this entry updates the CLI package's @terminal49/sdk dependency without updating the corresponding CLI workspace dependency in the root lockfile. The subsequent root-level npm ci used by CLI CI and publishing rejects the inconsistent manifest and lockfile, preventing the CLI from building or publishing.

Knowledge Base Used:Repo Tooling and CI

Prompt To Fix With AI
This is a comment left during a code review.
Path: .release-please-config.json
Line: 34-38
Comment:
**CLI lockfile dependency stays stale**
When release-please bumps the SDK, this entry updates the CLI package's `@terminal49/sdk` dependency without updating the corresponding CLI workspace dependency in the root lockfile. The subsequent root-level `npm ci` used by CLI CI and publishing rejects the inconsistent manifest and lockfile, preventing the CLI from building or publishing.
**Knowledge Base Used:**[Repo Tooling and CI](https://app.greptile.com/terminal49/-/custom-context/knowledge-base/terminal49/api/-/docs/repo-tooling-ci.md)---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in CodexFix in Claude Code

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:35cb5b7f3f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

run_json() {
local out="$1"
shift
run_dev "$@" --json > "$API_FIXTURES/$out"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Scrub live responses before writing fixtures

When this script runs with a real account token, run_json writes the complete API response—including customer names, reference numbers, and resource identifiers—directly into a tracked fixture directory. The comment and final reminder do not perform sanitization, so a routine fixture refresh can accidentally publish customer data; scrub deterministically before writing or capture outside the worktree and validate before copying.

AGENTS.md reference: AGENTS.md:L3-L3

Useful? React with 👍 / 👎.

Comment on lines +33 to +36
{
"type": "json",
"path": "sdks/typescript-sdk-cli/package.json",
"jsonpath": "$.dependencies['@terminal49/sdk']"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the root lock dependency during SDK releases

When Release Please bumps the SDK, this updater changes the CLI's exact @terminal49/sdk dependency but does not update the corresponding dependency under packages['sdks/typescript-sdk-cli'] in the authoritative root lockfile. The resulting release PR and CLI publish tag run root npm ci, which rejects the package/lock mismatch before building; add an adjacent root-lock extra-files updater for that dependency.

AGENTS.md reference: AGENTS.md:L11-L11

Useful? React with 👍 / 👎.

Comment on lines +40 to +44
"sdks/typescript-sdk-cli": {
"package-name": "@terminal49/cli",
"release-type": "node",
"changelog-path": "CHANGELOG.md",
"bump-minor-pre-major": true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Update the root lock version during CLI releases

When Release Please increments the CLI package version, this package configuration has no updater for package-lock.json's packages['sdks/typescript-sdk-cli'].version. Because the publish workflow checks out that tag and runs root npm ci, every such CLI release will fail on the stale workspace version before it reaches npm publish; include the root lock entry in extra-files.

AGENTS.md reference: AGENTS.md:L11-L11

Useful? React with 👍 / 👎.

format: ResponseFormat | undefined,
mapper: Mapper,
): unknown {
if (!format || format === 'raw') return raw;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor the configured format for tracking outputs

For tracking-requests create, infer, create-from-infer, and track without an explicit --format, createClient resolves the configured/default format to mapped, but these helpers receive only globals.format; undefined is therefore treated as raw. The raw-only SDK create/infer methods consequently emit JSON:API documents despite the CLI's mapped default, and a configured defaultFormat: both is also ignored; pass the effective resolved format into this formatter.

Useful? React with 👍 / 👎.

Comment on lines +17 to +19
if (format === 'both') return { raw, mapped: client.deserialize(raw) };
if (format === 'raw') return raw;
return client.deserialize(raw);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor the configured format for search output

When a user sets defaultFormat to raw or both in the CLI config and runs t49 search without --format, this helper receives undefined rather than the format resolved by createClient and always deserializes the response. Thus the documented persistent format setting has no effect on search output; use the effective configured format instead of interpreting a missing flag as mapped.

Useful? React with 👍 / 👎.

@dodeja
dodeja merged commit 9607056 into mainAug 14, 2026
23 of 24 checks passed
Sign up for freeto 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.

2 participants

@dodeja@cursoragent