feat(cli): add ci-setup wizard for shared team MCP server onboarding#2102
feat(cli): add ci-setup wizard for shared team MCP server onboarding#2102MCKRUZ wants to merge 21 commits into
Conversation
Adds `gitnexus ci-setup` — a new command that detects the current repo
environment and generates all artifacts needed to run GitNexus as a shared,
CI/CD-maintained MCP server:
- GitHub Actions workflow (push + PR triggers, node 22, artifact upload)
- Azure DevOps pipeline YAML (with commercial-use notice)
- Docker Compose service using the published ghcr.io image (port 4747)
- `--auth token`: Caddy reverse-proxy sidecar enforces GITNEXUS_TOKEN
(gitnexus is internal-only; the proxy publishes port 4748)
- `--auth none`: direct port 4747 with a no-auth warning banner
- Azure Container App deploy script (az CLI)
- Claude Code HTTP MCP snippet (.claude/gitnexus-mcp-snippet.json)
- GITNEXUS.md onboarding doc with decision log and next steps
Key design decisions:
- Corrects three errors in the original spec: serve port is 4747 (not 4848),
health endpoint is /api/health (not /health), and GITNEXUS_TOKEN provides
no auth in the server itself — real auth requires the Caddy proxy layer.
- Adds @inquirer/prompts (v8, ESM-native) for TTY arrow-key prompts; all
flags work non-interactively for CI/scripted use.
- Default mode is --dry-run (preview only); --apply writes with per-file
confirmation; --yes skips confirmations for scripted runs.
- Idempotent: second --apply run skips files that are byte-identical.
- 36 passing unit tests covering templates (pure functions, js-yaml parse
validation) and command behavior (real-fs-in-tempdir, vitest pattern).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@MCKRUZ is attempting to deploy a commit to the NexusCore Team on Vercel. A member of the Team first needs to authorize it. |
|
@MCKRUZ Thanks so much, this looks great!! @magyargergo this is a cool concept, lmk your thoughts on it when you get a chance |
|
I just shared this with @abhigyanpatwari because i like this idea too. I think we should proceed with this. :) |
|
@MCKRUZ Great idea! We really like this PR and will proceed with it. |
✨ PR AutofixFound fixable formatting / unused-import issues across 22 changed lines. Comment |
CI Report❌ Some checks failed Pipeline Status
Test Results
✅ All 11934 tests passed 54 test(s) skipped — expand for details
Code CoverageTests
📋 View full run · Generated by CI |
magyargergo
left a comment
There was a problem hiding this comment.
Tri-review: PR #2102 — gitnexus ci-setup wizard
Methods: GitNexus swarm (Claude) · Compound-Engineering personas (Claude, including a DevOps/SRE persona per request) · Codex (the one independent, non-Claude engine — ran live). Engine breakdown: 5 substantive Claude lanes + Codex, plus first-hand CI-log verification by the coordinator. Two GitNexus lanes (risk, test/CI) ended mid-investigation; their domains are covered by the CI-log evidence and the other lanes. Claude-lane agreement is consistent, not independent — only Codex is a different engine, so the strongest signals below are "Codex + a Claude lane." This is an automated multi-tool digest; verify before acting.
🔴 CI is red — all three failures are caused by this PR
Verified from the run logs; Codex independently confirmed the mechanisms.
quality / lint(blocking):console.erroratci-setup.ts:38violates the repo'sno-consolerule ('no-console': ['error', { allow: ['log'] }],eslint.config.mjs:110). It's the single lint error. → inlinetests / ubuntu / coverage(blocking): the 1 failed test istest/unit/cli-index-help.test.ts("localizes every registered CLI command…") — the newci-setupcommand + 8 options are registered with literal English strings but never added to the CLI i18n bundle, so zh-CN--helprenders them in English. → inlinequality / format: prettier fails on 3 new files (ci-setup.ts,ci-setup/prompts.ts,test/unit/ci-setup.test.ts) — runprettier --write.
Headline finding (strong: Codex + 4 Claude lanes + coordinator code-read)
ci-setup --port <non-4747> generates a dead deployment. serve reads its port only from the CLI flag (serve.ts:29 — never process.env.PORT), the production image hardcodes serve --host 0.0.0.0 --port 4747 (Dockerfile.cli:80), and the generated compose never overrides command:. So the container always listens on 4747 while the healthcheck (curl …:${opts.port}/api/health) and the Caddy target (gitnexus:${opts.port}) point at the chosen port. Token mode: container never becomes healthy → the proxy's depends_on: condition: service_healthy never starts. No-auth mode: the published port forwards to nothing. The default (4747) works only by coincidence; the --port flag is a foot-gun. → inline
Also worth fixing
- Generated GitHub Actions workflow hygiene (Codex + DevOps + reliability + security) —
npx gitnexus@latestis non-reproducible / a supply-chain surface; no top-levelpermissions:(least privilege); noconcurrency:(the repo enforces a concurrency convention); notimeout-minutes; actions float on@v4while the repo SHA-pins (v6/v7). → inline --portis never validated (correctness + adversarial; coordinator-verified) —parseInt('abc')→NaN, andNaN ?? 4747→NaN(nullish coalescing doesn't catch NaN), so--port abctemplates a literalNaN;--port 65535→ proxy port 65536 (invalid). → inlineGITNEXUS.mdoverstates the CI behavior (Codex + adversarial + DevOps, P1) — it claims the skills/index are "committed to the repository … automatically" (templates.ts:452), but the generated workflow has nogit commit/push step.- The "stays fresh via CI" loop is never wired (Codex + adversarial + DevOps, P1) — the workflow only uploads
.gitnexus/as a 30-day artifact; nothing delivers it to the server's persistent volume. (The adversarial lane also notesGITNEXUS_HOMEis the registry dir, not the per-repo graph at<repo>/.gitnexus, which is mounted:ro.) Either generate a deploy step or correct the doc. - Azure ACA deploy script (Codex + reliability + adversarial + DevOps) — default
STORAGE_ACCOUNT="gitnexusstorage"is globally unique across Azure (almost certainly taken →az storage account createfails underset -e); not idempotent on re-run;STORAGE_KEYpassed as a CLI arg (process-list / log exposure);--ingress internalmay make the server unreachable by external MCP clients. The reliability lane flagged theaz containerapp create --volume-* / --mount-pathflags as possibly invalid forcreate(needsupdate/YAML) — unverified; test the ACA path end-to-end before relying on it. - MCP snippet is JSONC in a
.jsonfile (Codex + DevOps + security, P2) —.claude/gitnexus-mcp-snippet.jsonopens with//comments → invalid JSON for any strict parser. Rename to.jsoncor emit comment-free JSON. (No auto-loader consumes the path, so impact is limited to manual/tool parsing.) detectprobe hardcodes 4747 (Codex + correctness + DevOps, P3) —detect.ts:135/ci-setup.ts:54ignore--port; cosmetic, but reinforces the false impression that--portworks.- Cleartext bearer token over HTTP (DevOps, P2) — fine on localhost, risky for a server reachable beyond the host; document/generate TLS.
- Non-TTY overwrite prompt (correctness/adversarial, P2/P3) —
--applywithout--yeson a repo with a differing existing file calls inquirerconfirm()in a non-TTY context → lands inresult.errors; mirror the TTY guard already used for the select prompts.
✅ Validated — credit where due
- The Caddy token gate fails CLOSED — confirmed independently by Codex + the security lane + the DevOps lane (refuting the adversarial lane's fail-open suspicion):
handlesorts before the barerespondcatch-all, the header matcher is exact-match, and compose's${GITNEXUS_TOKEN:?…}blocks startup on an empty token. Minor residual: running the standalone Caddyfile (outside compose) with an emptyGITNEXUS_TOKENwould matchBearer— a defense-in-depth nit, not a default-path bug. - The command scaffolding (dry-run default, idempotent identical-file skip, per-file error capture, safe non-TTY select defaults) is well-built and tested; the correctness lane explicitly refuted the redundant-nested-
if, scan-cap, and fallback-default suspicions as non-bugs.
Test-coverage gaps
Unit tests assert YAML parseability + string-contains, not semantics — nothing catches the --port breakage, the NaN port, the missing permissions:/concurrency:, or validates the Caddyfile/compose against the real image's port contract.
CI status: lint / format / ubuntu coverage failing (all PR-caused, above); Vercel = deploy-auth (not code); everything else green.
Automated tri-review (GitNexus swarm + CE personas + Codex). Treat findings as leads to verify, not verdicts.
|
@MCKRUZ Left some comments, and please let me know what you think |
- console.error → console.log (ESLint no-console) - Add i18n keys for ci-setup command + all 9 options in en.ts, zh-CN.ts, help-i18n.ts; add ['ci-setup'] to allHelpCommands in cli-index-help test - Container port hardcoded to 4747 (image CMD is not overridable); --port now controls host binding only; fixes dead deployments with non-4747 ports - Guard non-TTY overwrite prompt with process.stdin.isTTY check - Add port range validation (1–65534) with clear error message - Fix ACA --target-port to 4747 (container port, not host) - Add permissions/concurrency/timeout-minutes to generated GHA workflow - Fix GITNEXUS.md false claim about skills being auto-committed - Strip // comments from MCP snippet (invalid JSON); use _comment/_note keys - All 48 unit tests passing; prettier check clean Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….test.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@MCKRUZ Can you please resolve the merge conflicts? 🙏 |
|
Yup I’ll try to get to that todayOn Jun 11, 2026, at 10:41 AM, Gergő Magyar ***@***.***> wrote:magyargergo left a comment (abhigyanpatwari/GitNexus#2102)
@MCKRUZ Can you please resolve the merge conflicts? 🙏
—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Resolve conflicts in the CLI i18n/registration files where main's new `uninstall` command collided with this branch's `ci-setup` command — keep both in src/cli/index.ts, help-i18n.ts, i18n/en.ts, and i18n/zh-CN.ts. Picks up main's grammar-build consolidation (single build-tree-sitter-grammars.cjs), busboy upload-ingest, and the isDeleted/cfgSideChannel scope-resolution additions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@magyargergo Merge conflicts resolved — merged latest Verified locally before pushing: Minor heads-up: |
magyargergo
left a comment
There was a problem hiding this comment.
Tri-review: PR #2102 — gitnexus ci-setup wizard (re-review @ 8666342b)
Engines: 7 Claude reviewer lanes — GitNexus swarm (risk, test/CI, security-boundary) + Compound-Engineering personas (correctness, adversarial, reliability, maintainability). Codex did not return findings this run (it evaporated), so this is an all-Claude, multi-persona review — lane agreement below is consistent across personas, not independent cross-engine confirmation. Each inline finding was verified first-hand by the coordinator (1 reproduced, rest code-read). Automated digest — verify before acting.
Re-review of a moving head. A prior tri-review (2026-06-09 @
b2bc2dc2) is on this PR. Since then the author fixed the CI failures + the port contract, andorigin/mainwas merged in (→8666342b). The prior CI-failure findings are resolved (verified locally). The items below are what remains open or is newly surfaced.
✅ Validated / fixed — credit where due
- Prior 3 CI failures are fixed, verified locally on
8666342b: ESLint clean (no-console satisfied — usesconsole.log), Prettier clean,tscclean, and theci-setup+cli-index-helpunit tests pass (50).--portis now validated (isNaN/<1/>65534→ exit). - Container port contract is now self-consistent (the correctness lane refuted the old "dead deployment" bug): the container always listens on internal
4747; only the host/proxy port derives from--port. Healthcheck, Caddy target, and the no-auth mapping all agree. - Caddy token gate fails CLOSED on the compose path:
respond 401catch-all, exact header match,gitnexusservice unpublished, and${GITNEXUS_TOKEN:?…}blocks startup on an empty token. No template injection (enum/int-validated inputs); the MCP snippet is valid JSON (_comment/_notekeys, not//); non-TTY overwrite is guarded;@inquirer/promptsis lazy-loaded (no CLI startup cost).
🔴 Headline (P1) — the "stays fresh via CI" value prop is unwired
The generated CI runs analyze --skills then upload-artifact .gitnexus/ (30-day retention). The generated server reads a persistent volume (gitnexus-data:/data/gitnexus) with the repo mounted :ro. No generated artifact connects the two — no download-artifact, no server-side analyze, no registry population. A team that follows GITNEXUS.md verbatim gets a shared server that serves an empty/initial index indefinitely, with no loud failure. GITNEXUS.md admits the gap in prose — "updated when the volume-sharing mechanism (rsync, artifact download, or live-mount) delivers a fresh index" (templates.ts:467) — but the wizard generates none of those three mechanisms, and the printed "Next steps" (ci-setup.ts) never mention populating the server volume — so the weak doc disclosure does not save a user who follows the wizard exactly. (risk + adversarial + reliability lanes.) → inline
Also open (P2)
- Interactive wizard silently skips 2 of its 4 questions (correctness; coordinator-reproduced) —
--auth/--branch-strategyare given commander defaults (index.ts:61-62), sopartial.*is always set andpromptAuth()/promptBranchStrategy()atprompts.ts:21,23are unreachable dead code;--ci/--deployhave no default and DO prompt. A TTY user can never choosenone/main-onlyexcept via flags — defeating the purpose of the interactive wizard. → inline - No enum validation on
--ci/--deploy/--auth/--branch-strategy(correctness + maintainability) — raw strings areas-cast (ci-setup.ts:59-69); only--portis validated.--auth toekn(typo) silently falls through to the no-auth compose (insecure);--ci githubactionswrites no CI file and renders| undefined |in GITNEXUS.md. → inline - Cleartext bearer token over HTTP (security + risk) — Caddy listens on a bare
:${proxyPort}(plain HTTP,templates.ts:208) and every generated MCP URL ishttp://; no TLS anywhere. For a "shared, network-reachable" server, the token + all queries traverse the network unencrypted. → inline - ACA deploy script fails first-run and is non-idempotent (reliability + adversarial + security) — default
STORAGE_ACCOUNT="gitnexusstorage"(templates.ts:243) must be globally unique across Azure → almost certainly taken →az storage account createaborts underset -eafter the resource group was already created; noshow||createguards. AlsoSTORAGE_KEYon the CLI (process-list exposure),--ingress internal(printed FQDN unreachable by external MCP clients), and a misleading "enable Easy Auth" comment (Easy Auth/AAD ≠GITNEXUS_TOKENenforcement). It's a "review and run" script, but the default path fails. → inline - GITNEXUS.md doc-accuracy (adversarial + reliability + risk) — "stale-index PRs are blocked at CI" (
templates.ts:464) is false (the step only checks[ -f .gitnexus/meta.json ], whichanalyzejust regenerated); and "skill files … are written into the repository by the CI workflow" (:455) contradicts its own next sentence, whilepermissions: contents: read(:28) would 403 that push. → inline
Lower priority (P3 / body-only)
- Magic-number duplication (maintainability): container
4747×5 intemplates.ts, proxyopts.port+1×6, imageghcr.io/abhigyanpatwari/gitnexus:latest×3 — no constants. Values are currently consistent (correctness-verified), so this is debt, not a live bug. detect.ts:135probes a hardcoded4747before--portis known, so the "Port 4747: available" line is wrong/irrelevant when--portdiffers (display-only).npx gitnexus@latestin both generated workflows is unpinned (a bad publish breaks every consumer's CI). Acceptable as an onboarding default; pinning to the wizard's own version is safer.- Hardening: no-auth compose binds
0.0.0.0(suggest a127.0.0.1:default); a standalone Caddyfile run without compose has no empty-token guard (the compose path is safe);unset STORAGE_KEYafter use;authCommentis injected as# ${authComment}where it already begins with#→ cosmetic# #double-hash in the ACA script.
Test-coverage gaps
Tests assert file-writing + YAML-parseability + string-contains, not semantics. Nothing covers: the port-contract invariant at the --port 65534 boundary; the dead-prompt TTY path; invalid-enum rejection; bash -n on the generated ACA script; or that GITNEXUS.md claims match the generated workflow.
CI status: the lint/format/test jobs did not re-trigger on the fork merge head (0 check-runs) — only Vercel ran (deploy-auth failure, not code). Locally verified green (above). Re-running the unit-test job on this head is advisable before merge.
Bottom line: mechanically solid (lint/format/tsc/tests green, port contract fixed, token gate fails closed), but not yet production-ready: the P1 makes the feature's central promise silently non-functional, and the interactive-wizard P2 breaks the primary UX path. Most items are template/doc fixes, not redesigns.
Automated multi-lane (all-Claude this run) digest — treat findings as leads to verify, not verdicts.
The `--auth` and `--branch-strategy` commander options carried default
values ('token'/'pr-scoped'), so the parsed options object always
populated them. ci-setup.ts then always set partial.auth/branchStrategy,
which made promptAuth()/promptBranchStrategy() in resolveOptions
unreachable dead code — the interactive wizard silently asked only 2 of
its 4 questions and a TTY user could never choose none/main-only.
Drop the commander defaults (like --ci/--deploy, which have none and do
prompt); resolveOptions still supplies the token/pr-scoped fallbacks for
non-TTY/CI runs, so non-interactive behavior is unchanged. The resolved
default is now surfaced in the i18n help descriptions instead of the
auto-appended commander "(default: …)" annotation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
--ci/--deploy/--auth/--branch-strategy were cast straight from the raw commander string (`as AuthMode`, etc.) with no validation — only --port was checked. A typo like `--auth toekn` is not 'token', so the templates fell through to the *no-auth* compose, silently producing an unauthenticated, port-published deployment the user believed was token-gated; `--ci githubactions` wrote no CI file and rendered a literal `| undefined |` in GITNEXUS.md. Add a requireEnum() helper (exact, case-sensitive membership; no trim/lowercase normalization so `NONE` exits rather than degrading to the insecure path) called inside each existing option guard, so an omitted flag still resolves via the prompt/fallback while an explicitly-passed invalid value exits non-zero. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
detectEnvironment ran checkPortAvailable(4747) eagerly, before options were parsed, and the result was printed as a hardcoded "Port 4747: available" line — wrong/irrelevant whenever the user passed a different --port. Export checkPortAvailable, drop the eager hardcoded probe (and the now-unused portAvailable field from DetectResult), and probe resolved.port after option resolution, reporting the actual port. This also removes a latent real-socket bind on 4747 from the default unit-test path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The container-internal port (4747 ×5), the image reference (×3), and the Caddy proxy-port arithmetic (opts.port + 1 ×5) were duplicated across the generated artifacts, so the port contract could drift if one site was updated and others missed. Hoist CONTAINER_PORT and GITNEXUS_IMAGE constants and a caddyProxyPort() helper. Generated output is byte-identical (existing template tests pass unchanged). buildMcpSnippet's auth-conditional display port (opts.port+1 for token, opts.port for no-auth) is intentionally left as-is — it is not the Caddy proxy port. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The generated CI uploads .gitnexus/ as a workflow artifact, but nothing delivers it to the running server's persistent volume — yet GITNEXUS.md claimed the volume is "updated when the volume-sharing mechanism (rsync, artifact download, or live-mount) delivers a fresh index", naming three mechanisms the wizard never generates. A team following the doc verbatim gets a server serving an empty/stale index forever, with no loud failure. Replace that prose with an explicit "the wizard does not automate index delivery — it is a required operator step" statement plus a commented, target-matched, copy-adaptable example: for Docker, an on-server scheduled re-index (or `docker compose cp` of the downloaded artifact); for Azure Container App, `az storage file upload-batch` to the mounted file share. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two generated-doc claims were false: - "stale-index PRs are blocked at CI" — the step only checks that .gitnexus/meta.json exists, which the preceding analyze just regenerated, so it never detects staleness and blocks nothing. Reword to say it only fails when analyze produced no output, and rename the step from "Check index staleness" to "Verify index was produced" in both the GitHub Actions and Azure pipeline templates. - "skill files are written into the repository by the CI workflow" — the workflow runs with `permissions: contents: read` and has no commit step, so the files are discarded with the runner. State plainly they are not auto-committed and that persisting them needs a commit step plus `contents: write`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ersion Generated automation used `npx gitnexus@latest`, which silently pulls whatever was last published — a non-reproducible single point of failure for every consumer's CI. Read the wizard's own version from gitnexus/package.json (the setup.ts MCP_PINNED_REF pattern; read in ci-setup.ts where ../../package.json resolves correctly, threaded via CiSetupOptions to avoid a generateFiles signature churn) and pin the GitHub Actions + Azure pipeline analyze steps and the persisted Cursor stdio MCP launch to `gitnexus@<version>`. The human-facing manual re-index commands in GITNEXUS.md intentionally stay `@latest`, matching setup.ts's "READMEs may use latest, persisted configs are pinned" rule. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- No-auth docker-compose now publishes via ${GITNEXUS_HOST:-127.0.0.1} so
it binds loopback by default (not 0.0.0.0) and is not exposed by
accident; operators set GITNEXUS_HOST to an interface IP / 0.0.0.0 for
LAN access. The container healthcheck keeps localhost (it curls its own
loopback, so it must not use GITNEXUS_HOST).
- Caddyfile gains TLS guidance (the proxy is plain HTTP, so the bearer
token is cleartext — use a hostname for Caddy auto-HTTPS or terminate
TLS upstream) and a standalone empty-token warning (compose already
enforces a non-empty GITNEXUS_TOKEN via ${GITNEXUS_TOKEN:?...}).
- GITNEXUS.md (token mode) warns the bearer token travels in cleartext
and to put the server behind TLS before exposing it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ACA deploy script: - Default STORAGE_ACCOUNT was the global literal "gitnexusstorage", which is almost certainly taken (Azure storage names are globally unique) and aborts the script under `set -e` after the resource group was created. Randomize the first-run default and document setting a fixed name for repeatable deploys. - Make it idempotent: guard each create with `show >/dev/null || create` for the storage account, file share, environment, and container app. - `unset STORAGE_KEY` after registering it (it was passed on the CLI). - Stop claiming Azure Easy Auth enforces GITNEXUS_TOKEN — it doesn't; document that --ingress internal is a VNet boundary and token enforcement needs a proxy sidecar. Connection guidance (KTD-8): buildMcpSnippet and the GITNEXUS.md connect section branched only on auth, so for `--deploy azure-container-app --auth token` they advertised a Caddy proxy port (port+1) that does not exist for ACA and a bearer header ACA never checks. Make them deploy-aware via mcpServerUrl(): ACA → https://<FQDN>/api/mcp with an internal-ingress caveat and no bearer header; Docker is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
authComment lines already begin with `#`, but the injection site prefixed another `# `, producing `# # Auth: …` in the generated bash script. Inject the comment block without the extra prefix so each line is single-hashed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cross-cutting coverage the per-fix tests don't provide: - bash -n syntax check on the generated ACA deploy script (catches a template regression that produces invalid shell before an operator runs it; skipped where bash is unavailable). - --port upper-boundary: proxy port follows --port (65534 -> 65535) in the Caddyfile and MCP snippet, and a base --port of 65535 is rejected (its proxy port would exceed the valid range). - doc/workflow version consistency: workflows + Cursor config pin the same version while the manual re-index commands intentionally stay @latest. - GITNEXUS.md claims match the workflow (no "blocked at CI" / no "volume-sharing mechanism" overselling). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
gitnexus ci-setupcommand that generates all artifacts needed to run GitNexus as a shared, CI/CD-maintained MCP server for a teamWhy @inquirer/prompts (new dependency)
This command's primary value is the interactive onboarding UX — arrow-key menus that guide a developer through 4 decision points before generating files. The existing dep tree has no TTY prompt library (
commanderhandles flags only).@inquirer/promptsv8 is the ESM-native, actively maintained successor toinquirer; it has no native modules, adds ~400 KB to the install, and ships its own TypeScript declarations. All prompts are TTY-gated (process.stdin.isTTY) and the command is fully non-interactive via flags — the dep is purely additive.Corrections to the original spec
The original design doc contained three factual errors about the codebase. These are corrected here:
serveport 4848servedefaults to 4747; 4848 iseval-serversrc/cli/serve.ts:29,src/cli/index.ts:264GET /healthGET /api/healthsrc/server/api.ts:852GITNEXUS_TOKENauth env varsrc/server/grepThe
--auth tokenmode generates a Caddy reverse-proxy sidecar that genuinely enforces a bearer token in front ofgitnexus(which stays on the internal Docker network and is never published).--auth nonepublishes port 4747 directly with a warning banner.Test plan
gitnexus ci-setup --dry-runprints all artifact contents, writes nothinggitnexus ci-setup --apply --yeswrites all expected files--apply --yesrun skips all files (exists, identical)--auth noneomits Caddyfile and proxy service, shows no-auth banner--ci both --deploy bothgenerates all 6 artifact filesvitest run test/unit/ci-setup*.test.ts— 36 tests pass🤖 Generated with Claude Code