feat(atmn): scaffold the atmn-nightly cli package - #3222
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
| const path = findConfigPath({ dirs }); | ||
| if (!path) throw new ConfigNotFoundError(dirs); | ||
|
|
||
| const module = await import(pathToFileURL(path).href); |
There was a problem hiding this comment.
Native import breaks TypeScript configs
When a user runs atmn-nightly push on the supported Node 20 runtime with the standard autumn.config.ts, this native import() cannot load the TypeScript file without a loader, causing the command to exit before reading the catalog configuration.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/atmn-nightly/src/config/loadConfig.ts
Line: 45
Comment:
**Native import breaks TypeScript configs**
When a user runs `atmn-nightly push` on the supported Node 20 runtime with the standard `autumn.config.ts`, this native `import()` cannot load the TypeScript file without a loader, causing the command to exit before reading the catalog configuration.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 13858610d4
ℹ️ 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".
| const path = findConfigPath({ dirs }); | ||
| if (!path) throw new ConfigNotFoundError(dirs); | ||
|
|
||
| const module = await import(pathToFileURL(path).href); |
There was a problem hiding this comment.
Use a loader that supports TypeScript on Node 20
When this package runs on an advertised Node 20 runtime (engines.node is >=20), native import() cannot load .ts files. Because findConfigPath prefers autumn.config.ts, push fails with ERR_UNKNOWN_FILE_EXTENSION before reading the standard config; use a TypeScript-aware loader such as the jiti mechanism in the existing atmn config loader, or raise the minimum Node version.
Useful? React with 👍 / 👎.
| cwd?: string; | ||
| } = {}): RepoLayout => { | ||
| const packageRoot = nearestPackageDir({ from: cwd }) ?? cwd; | ||
| const repoRoot = gitToplevel({ cwd }) ?? packageRoot; |
There was a problem hiding this comment.
Search ancestor packages when Git metadata is unavailable
When the CLI runs in a nested workspace without .git metadata, such as an unpacked source tree or Docker build context, this fallback makes the nearest package directory both packageRoot and repoRoot. A parent workspace manifest and its root-level config or environment files are therefore never discovered, despite RepoLayout promising the outermost package directory as the fallback; walk the remaining ancestors and retain the outermost package/workspace root.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
9 issues found across 12 files
Confidence score: 2/5
packages/atmn-nightly/src/config/loadConfig.tsuses a native TypeScript import that throwsERR_UNKNOWN_FILE_EXTENSIONon Node 20, preventing packaged CLI startup before configuration loads — use the existing TypeScript-aware loader or an equivalent Node-compatible approach.packages/atmn-nightly/src/cli.tsrelies onimport.meta.main, which is not a Node 20 entrypoint guard, so the advertised runtime may never launch the CLI — replace it with a Node-compatible entrypoint check.packages/atmn-nightly/src/repo/findRepoRoot.tscan select the wrong workspace root outside Git and can loop indefinitely for relativecwdvalues, affecting nested-workspace discovery — resolvecwdfirst and walk package ancestors to the outermost valid root.- The remaining packaging setup needs cleanup:
packages/atmn-nightly/bun.config.tsmay resolve bundle paths from the caller’s working directory,package.jsonpoints tests at a missingtest/directory and includes unusedchalk, andtsconfig.jsonlacks the declared Node type dependency — validate builds and test execution from the repository root and align dependencies/scripts.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/atmn-nightly/src/config/loadConfig.ts">
<violation number="1" location="packages/atmn-nightly/src/config/loadConfig.ts:13">
P3: When no config exists, this message is inaccurate because `findConfigPath` also accepts `autumn.config.js`. Mention both filenames so users understand the supported alternatives.</violation>
<violation number="2" location="packages/atmn-nightly/src/config/loadConfig.ts:45">
P1: When the packaged CLI runs on supported Node 20, this native import throws `ERR_UNKNOWN_FILE_EXTENSION` before loading any `autumn.config.ts`. Use a TypeScript-aware loader, as the existing `atmn` loader does, or compile the config before importing it.</violation>
</file>
<file name="packages/atmn-nightly/package.json">
<violation number="1" location="packages/atmn-nightly/package.json:22">
P3: The `test` script runs `bun test test`, but this package has no `test/` directory (only `src/` exists). The command therefore matches no tests, so CI either fails or silently runs an empty suite. Point it at an existing path or remove it until real tests exist; at minimum add the `test` directory referenced by the script and by `tsconfig.json`'s `include` array.</violation>
<violation number="2" location="packages/atmn-nightly/package.json:30">
P3: `chalk` is listed in dependencies but never imported anywhere in this package. The `bun.config.ts` bundle only includes imported modules, so chalk is unused and just bloats installs. Remove it, or add the import if it is meant to be used.</violation>
</file>
<file name="packages/atmn-nightly/bun.config.ts">
<violation number="1" location="packages/atmn-nightly/bun.config.ts:3">
P3: `Bun.file("./package.json")`, the `entrypoints`, and `outdir` all resolve relative to the process working directory, not to this config file. Running `bun packages/atmn-nightly/bun.config.ts` from the repo root (or any directory other than the package root) makes `Bun.file("./package.json").json()` throw before the build starts, with no clear message. Resolve paths from `import.meta.dir` (Bun supports it) so the build works regardless of where it is invoked.</violation>
</file>
<file name="packages/atmn-nightly/src/repo/findRepoRoot.ts">
<violation number="1" location="packages/atmn-nightly/src/repo/findRepoRoot.ts:64">
P2: When callers pass a relative `cwd`, `nearestPackageDir` gets an empty `parse` root and can loop forever at `.`. Normalize `cwd` with `resolve` before both probes so returned roots remain consistent.</violation>
<violation number="2" location="packages/atmn-nightly/src/repo/findRepoRoot.ts:65">
P2: Outside a Git worktree, this fallback makes `repoRoot` equal the nearest package instead of the outermost package ancestor. Walk package ancestors for the non-Git fallback so nested workspaces still detect their root and load root-level files.</violation>
</file>
<file name="packages/atmn-nightly/src/cli.ts">
<violation number="1" location="packages/atmn-nightly/src/cli.ts:76">
P1: The packaged CLI does not start under its advertised Node runtime because `import.meta.main` is not a Node 20 entrypoint guard. Replace this with a Node-compatible `process.argv[1]`/`fileURLToPath(import.meta.url)` comparison, or invoke `run()` unconditionally from the bundled entrypoint.</violation>
</file>
<file name="packages/atmn-nightly/tsconfig.json">
<violation number="1" location="packages/atmn-nightly/tsconfig.json:15">
P3: The `tsconfig.json` sets `"types": ["bun", "node"]` and the CLI sources import Node builtins (`node:path`, `node:fs`, `node:url`, `node:child_process`), but `package.json` only declares `@types/bun` in devDependencies — `@types/node` is not declared. The `tsgo --build --noEmit` check therefore relies on `@types/node` being hoisted from sibling workspace packages instead of being an explicit dependency. Declare `@types/node` (as the `atmn` package it scaffolds from does) or drop `"node"` from `types`.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| const path = findConfigPath({ dirs }); | ||
| if (!path) throw new ConfigNotFoundError(dirs); | ||
|
|
||
| const module = await import(pathToFileURL(path).href); |
There was a problem hiding this comment.
P1: When the packaged CLI runs on supported Node 20, this native import throws ERR_UNKNOWN_FILE_EXTENSION before loading any autumn.config.ts. Use a TypeScript-aware loader, as the existing atmn loader does, or compile the config before importing it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/src/config/loadConfig.ts, line 45:
<comment>When the packaged CLI runs on supported Node 20, this native import throws `ERR_UNKNOWN_FILE_EXTENSION` before loading any `autumn.config.ts`. Use a TypeScript-aware loader, as the existing `atmn` loader does, or compile the config before importing it.</comment>
<file context>
@@ -0,0 +1,55 @@
+ const path = findConfigPath({ dirs });
+ if (!path) throw new ConfigNotFoundError(dirs);
+
+ const module = await import(pathToFileURL(path).href);
+ const wire = module.default;
+
</file context>
| await buildProgram().parseAsync(normalizeVersionFlag({ argv })); | ||
| }; | ||
|
|
||
| if (import.meta.main) { |
There was a problem hiding this comment.
P1: The packaged CLI does not start under its advertised Node runtime because import.meta.main is not a Node 20 entrypoint guard. Replace this with a Node-compatible process.argv[1]/fileURLToPath(import.meta.url) comparison, or invoke run() unconditionally from the bundled entrypoint.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/src/cli.ts, line 76:
<comment>The packaged CLI does not start under its advertised Node runtime because `import.meta.main` is not a Node 20 entrypoint guard. Replace this with a Node-compatible `process.argv[1]`/`fileURLToPath(import.meta.url)` comparison, or invoke `run()` unconditionally from the bundled entrypoint.</comment>
<file context>
@@ -0,0 +1,82 @@
+ await buildProgram().parseAsync(normalizeVersionFlag({ argv }));
+};
+
+if (import.meta.main) {
+ run({ argv: process.argv }).catch((error: unknown) => {
+ const message = error instanceof Error ? error.message : String(error);
</file context>
| cwd?: string; | ||
| } = {}): RepoLayout => { | ||
| const packageRoot = nearestPackageDir({ from: cwd }) ?? cwd; | ||
| const repoRoot = gitToplevel({ cwd }) ?? packageRoot; |
There was a problem hiding this comment.
P2: Outside a Git worktree, this fallback makes repoRoot equal the nearest package instead of the outermost package ancestor. Walk package ancestors for the non-Git fallback so nested workspaces still detect their root and load root-level files.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/src/repo/findRepoRoot.ts, line 65:
<comment>Outside a Git worktree, this fallback makes `repoRoot` equal the nearest package instead of the outermost package ancestor. Walk package ancestors for the non-Git fallback so nested workspaces still detect their root and load root-level files.</comment>
<file context>
@@ -0,0 +1,76 @@
+ cwd?: string;
+} = {}): RepoLayout => {
+ const packageRoot = nearestPackageDir({ from: cwd }) ?? cwd;
+ const repoRoot = gitToplevel({ cwd }) ?? packageRoot;
+
+ const hasMarker =
</file context>
| }: { | ||
| cwd?: string; | ||
| } = {}): RepoLayout => { | ||
| const packageRoot = nearestPackageDir({ from: cwd }) ?? cwd; |
There was a problem hiding this comment.
P2: When callers pass a relative cwd, nearestPackageDir gets an empty parse root and can loop forever at .. Normalize cwd with resolve before both probes so returned roots remain consistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/src/repo/findRepoRoot.ts, line 64:
<comment>When callers pass a relative `cwd`, `nearestPackageDir` gets an empty `parse` root and can loop forever at `.`. Normalize `cwd` with `resolve` before both probes so returned roots remain consistent.</comment>
<file context>
@@ -0,0 +1,76 @@
+}: {
+ cwd?: string;
+} = {}): RepoLayout => {
+ const packageRoot = nearestPackageDir({ from: cwd }) ?? cwd;
+ const repoRoot = gitToplevel({ cwd }) ?? packageRoot;
+
</file context>
| export class ConfigNotFoundError extends Error { | ||
| constructor(searched: string[]) { | ||
| super( | ||
| `No autumn.config.ts found. Looked in:\n${searched |
There was a problem hiding this comment.
P3: When no config exists, this message is inaccurate because findConfigPath also accepts autumn.config.js. Mention both filenames so users understand the supported alternatives.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/src/config/loadConfig.ts, line 13:
<comment>When no config exists, this message is inaccurate because `findConfigPath` also accepts `autumn.config.js`. Mention both filenames so users understand the supported alternatives.</comment>
<file context>
@@ -0,0 +1,55 @@
+export class ConfigNotFoundError extends Error {
+ constructor(searched: string[]) {
+ super(
+ `No autumn.config.ts found. Looked in:\n${searched
+ .map((path) => ` ${path}`)
+ .join("\n")}\n\nRun \`atmn-nightly pull\` to scaffold one.`,
</file context>
| "README.md" | ||
| ], | ||
| "dependencies": { | ||
| "chalk": "5.6.2", |
There was a problem hiding this comment.
P3: chalk is listed in dependencies but never imported anywhere in this package. The bun.config.ts bundle only includes imported modules, so chalk is unused and just bloats installs. Remove it, or add the import if it is meant to be used.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/package.json, line 30:
<comment>`chalk` is listed in dependencies but never imported anywhere in this package. The `bun.config.ts` bundle only includes imported modules, so chalk is unused and just bloats installs. Remove it, or add the import if it is meant to be used.</comment>
<file context>
@@ -0,0 +1,37 @@
+ "README.md"
+ ],
+ "dependencies": {
+ "chalk": "5.6.2",
+ "commander": "14.0.3",
+ "dotenv": "16.6.1"
</file context>
| @@ -0,0 +1,19 @@ | |||
| import * as Bun from "bun"; | |||
|
|
|||
| const packageJson = await Bun.file("./package.json").json(); | |||
There was a problem hiding this comment.
P3: Bun.file("./package.json"), the entrypoints, and outdir all resolve relative to the process working directory, not to this config file. Running bun packages/atmn-nightly/bun.config.ts from the repo root (or any directory other than the package root) makes Bun.file("./package.json").json() throw before the build starts, with no clear message. Resolve paths from import.meta.dir (Bun supports it) so the build works regardless of where it is invoked.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/bun.config.ts, line 3:
<comment>`Bun.file("./package.json")`, the `entrypoints`, and `outdir` all resolve relative to the process working directory, not to this config file. Running `bun packages/atmn-nightly/bun.config.ts` from the repo root (or any directory other than the package root) makes `Bun.file("./package.json").json()` throw before the build starts, with no clear message. Resolve paths from `import.meta.dir` (Bun supports it) so the build works regardless of where it is invoked.</comment>
<file context>
@@ -0,0 +1,19 @@
+import * as Bun from "bun";
+
+const packageJson = await Bun.file("./package.json").json();
+const version: string = packageJson.version;
+
</file context>
| "scripts": { | ||
| "ts": "bunx tsgo --build --noEmit", | ||
| "build": "bun run bun.config.ts", | ||
| "test": "bun test test" |
There was a problem hiding this comment.
P3: The test script runs bun test test, but this package has no test/ directory (only src/ exists). The command therefore matches no tests, so CI either fails or silently runs an empty suite. Point it at an existing path or remove it until real tests exist; at minimum add the test directory referenced by the script and by tsconfig.json's include array.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/package.json, line 22:
<comment>The `test` script runs `bun test test`, but this package has no `test/` directory (only `src/` exists). The command therefore matches no tests, so CI either fails or silently runs an empty suite. Point it at an existing path or remove it until real tests exist; at minimum add the `test` directory referenced by the script and by `tsconfig.json`'s `include` array.</comment>
<file context>
@@ -0,0 +1,37 @@
+ "scripts": {
+ "ts": "bunx tsgo --build --noEmit",
+ "build": "bun run bun.config.ts",
+ "test": "bun test test"
+ },
+ "files": [
</file context>
| "forceConsistentCasingInFileNames": true, | ||
| "noUnusedLocals": false, | ||
| "noUnusedParameters": false, | ||
| "types": ["bun", "node"], |
There was a problem hiding this comment.
P3: The tsconfig.json sets "types": ["bun", "node"] and the CLI sources import Node builtins (node:path, node:fs, node:url, node:child_process), but package.json only declares @types/bun in devDependencies — @types/node is not declared. The tsgo --build --noEmit check therefore relies on @types/node being hoisted from sibling workspace packages instead of being an explicit dependency. Declare @types/node (as the atmn package it scaffolds from does) or drop "node" from types.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/atmn-nightly/tsconfig.json, line 15:
<comment>The `tsconfig.json` sets `"types": ["bun", "node"]` and the CLI sources import Node builtins (`node:path`, `node:fs`, `node:url`, `node:child_process`), but `package.json` only declares `@types/bun` in devDependencies — `@types/node` is not declared. The `tsgo --build --noEmit` check therefore relies on `@types/node` being hoisted from sibling workspace packages instead of being an explicit dependency. Declare `@types/node` (as the `atmn` package it scaffolds from does) or drop `"node"` from `types`.</comment>
<file context>
@@ -0,0 +1,26 @@
+ "forceConsistentCasingInFileNames": true,
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
+ "types": ["bun", "node"],
+ "paths": {
+ "@autumn/shared": ["../../shared/index.ts"],
</file context>
1385861 to
31fddac
Compare
Scaffolds
packages/atmn-nightly— the ground-up CLI rewrite. Published to npm asatmn-nightly; cutover toatmnis a rename plus deletingpackages/atmn, which is why it is a new directory rather than a rewrite in place. v2 keeps working and keeps publishing throughout.No behaviour beyond the command tree —
pushdeliberately goes as far as loading your config and then stops, so the pieces underneath it are live code rather than untested scaffolding.What runs
--helpprints a generated command tree;login,push,pull,sandbox createare registered with their flags.-V,-vand--versionall printatmn-nightly v3.0.0-nightly.1. Commander only treats-Vas version and rejects a lone-v, so argv is normalised before parsing — one line, no custom parser.-yd,-dy,-y -dand--yes --dry-runall parse the same. Unknown flags error rather than crash.pushwith no config exits 1 with the directories it searched, not a stack trace.Pieces
src/cli.ts-vnormalisersrc/config/loadConfig.tsautumn.config.tsin-process — the seam a future--config-jsonslots intosrc/env/loadEnv.ts.env.localthen.env, never overridingprocess.env, so injected secrets keep prioritysrc/repo/findRepoRoot.tsturbo.json/pnpm-workspace.yaml/workspacesprobessrc/version.tsBuilt with
Bun.build, targeting node. Building with Bun keeps the build ~11ms; targeting node meansnpx atmn-nightlyworks without users installing Bun.Registration
A new workspace needs four places, not one, and missing any of them breaks CI rather than failing locally:
package.jsonworkspaces.packagespackage.jsontsscript — the turbo filter list is explicit per packagedocker/Dockerfile—--frozen-lockfileneeds every manifest present, and the file says so in a commentknip.json— alongsidepackages/atmnbun installand a full-repobun tsare both clean.Not here yet
opentui, because nothing needs rendering until there is output to render — it lands with pull's picker. And
@ast-grep/napi, which arrives with pull's fixture surgery.Summary by cubic
Scaffolds
atmn-nightly, the v3 CLI that will becomeatmnat 3.0.0, without changing the existing v2 package. Registers it across workspace, type-checking, Docker, lockfile, and Knip configuration.CLI foundation
login,push,pull, andsandbox create.pushdiscovers repository roots, loads.env.localand.envwithout overridingprocess.env, and importsautumn.config.tsor.jsbefore stopping until its implementation lands.-v,-V, and--version, plus environment, confirmation, and dry-run flags.Written for commit 31fddac. Summary will update on new commits.
Greptile Summary
The PR scaffolds the Node-targeted
atmn-nightlyCLI package while keeping the existing CLI intact.login,push,pull, andsandbox createcommand tree with environment, confirmation, and dry-run flags.Confidence Score: 4/5
The PR is not yet safe to merge because the supported
pushpath cannot load the standard TypeScript configuration when the published CLI runs on Node.The CLI discovers
autumn.config.tsfirst and passes it to native Node dynamic import, but the published Node-targeted package includes no TypeScript loader, so configuration loading still fails beforepushcan proceed.Files Needing Attention: packages/atmn-nightly/src/config/loadConfig.ts and packages/atmn-nightly/package.json
Important Files Changed
.env.localand.envwhile preserving values already present in the process environment.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD User[CLI user] --> CLI[atmn-nightly command tree] CLI --> Login[login] CLI --> Push[push] CLI --> Pull[pull] CLI --> Sandbox[sandbox create] Push --> Repo[Discover repository layout] Repo --> Env[Load environment files] Env --> Config[Discover and import config]Reviews (2): Last reviewed commit: "feat: 🎸 scaffold the atmn nightly cli p..." | Re-trigger Greptile