Skip to content

feat(miner): add a gittensory-miner init --interactive first-run onboarding wizard - #5621

Merged
JSONbored merged 2 commits into
JSONbored:mainfrom
joaovictor712:feat/miner-init-wizard
Jul 13, 2026
Merged

feat(miner): add a gittensory-miner init --interactive first-run onboarding wizard#5621
JSONbored merged 2 commits into
JSONbored:mainfrom
joaovictor712:feat/miner-init-wizard

Conversation

@joaovictor712

Copy link
Copy Markdown
Contributor

Summary

  • gittensory-miner init previously only created an empty state dir with no guided setup — first-time
    operators had to hand-author a .env referencing GITHUB_TOKEN and MINER_CODING_AGENT_PROVIDER with no
    prompts and no validation until a later doctor run or a failed live attempt.
  • Added packages/gittensory-miner/lib/init-wizard.js (+ .d.ts), wired behind a new opt-in
    gittensory-miner init --interactive flag:
    • Prompts for GITHUB_TOKEN with masked, never-echoed input; an empty answer is rejected and re-prompted.
    • Prompts for an optional coding-agent provider from a menu sourced directly from the engine's own
      CODING_AGENT_DRIVER_NAMES (noop/claude-cli/codex-cli/agent-sdk) — so the choices can never drift
      from what the driver factory actually resolves. Pressing Enter skips provider selection entirely
      (leaves MINER_CODING_AGENT_PROVIDER unwritten, deferring to whatever default the CLI already resolves) —
      distinct from explicitly choosing the noop entry.
    • If a provider was selected, prompts for that provider's companion vars (model override, timeout), sourced
      from the same CODING_AGENT_DRIVER_CONFIG_ENV map the real driver factory reads — each individually
      skippable with Enter.
    • Writes the collected values to a starter .env in the miner state dir (mode 0600), then automatically
      reruns the existing offline doctor checks (status.js's runDoctor) against the collected values so the
      operator sees pass/fail immediately.
  • Masked input is implemented by overriding readline's own output-write hook to render * instead of the
    typed characters while readline still does its normal cooked-mode line editing (Enter/Backspace work exactly
    as with a plain prompt) — no raw-mode byte handling and no new dependency. input/output streams are
    parameters (defaulting to real stdio) purely so tests drive the exact same code path with fake streams
    instead of a real terminal — this let me write a REGRESSION test proving the raw secret literally never
    appears anywhere in the captured output stream, not just that a mocked prompt function was called correctly.
  • --interactive makes no network calls of its own beyond what doctor already makes (none — it's
    offline by contract). Non-interactive init invocations are completely untouched (the existing runInit in
    laptop-init.js is not modified at all; the new dispatch lives one layer up, in bin/gittensory-miner.js,
    so there is zero risk of behavior drift on the default path).

Fixes #5176

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves (e.g. Closes #123) — a linked open issue is required for every contributor PR.

Validation

  • git diff --check
  • npm run actionlint
  • npm run typecheck
  • npm run test:coverage locally — packages/gittensory-miner/lib/**/*.js is in this repo's codecov/patch gate; targeted coverage run (--coverage.include scoped to init-wizard.js): 100% statements, 100% branches, 100% functions, 100% lines.
  • npm run test:workers
  • npm run build:mcp
  • npm run test:mcp-pack
  • npm run build:miner
  • npm run test:miner-pack
  • npm run ui:openapi:check
  • npm run ui:lint
  • npm run ui:typecheck
  • npm run ui:build
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

Ran the full local gate: npm run test:ci (0 failures) and npm audit --audit-level=moderate (0 vulnerabilities), both clean on the final commit. Also directly ran the exact FORBIDDEN_PATH/FORBIDDEN_CONTENT regexes from scripts/check-miner-package.mjs/scripts/forbidden-content.mjs against every new/touched file — zero matches. npm run build:miner was extended with node --check lib/init-wizard.js, and confirmed the file packs correctly via npm run test:miner-pack.

New test/unit/miner-init-wizard.test.ts (17 tests): renderWizardEnvFile/resolveWizardEnvFilePath pure-function tests; promptProviderSelection covering skip-on-empty, re-prompt-on-invalid-then-valid, and that every menu entry is drawn from the live CODING_AGENT_DRIVER_NAMES list; promptCompanionVars covering a provider with vars, one without (noop), and a defensive unknown-provider default; full runInteractiveInit orchestration tests asserting the written .env file's exact content and 0600 mode, laptop-state initialization, a token-required re-prompt-on-empty path, provider + companion-var entries written correctly with the skipped var omitted, the "(already existed)" branch on a second run, and — the key invariant — that the raw GITHUB_TOKEN value never appears anywhere in anything written to the terminal, including the final doctor summary; direct tests of the real createWizardIo terminal adapter driven over fake TTY-like streams (not mocked away), including a REGRESSION test proving masked input never writes the raw secret to the output stream at the byte level; and a lightweight e2e test spawning the real bin/gittensory-miner.js init --interactive confirming the CLI actually dispatches to the wizard's distinct prompt path.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests. — no auth/session/CORS surface touched, but since this collects a credential (GITHUB_TOKEN) interactively, the REGRESSION test described above directly verifies it is never echoed/logged, including at the byte level in the real terminal-output stream.
  • API/OpenAPI/MCP behavior is updated and tested where needed. — no public API/OpenAPI/MCP surface touched; this is a new local CLI flag only.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. — N/A, no UI surface.
  • Visible UI changes include a UI Evidence section below. — N/A, see below.
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. — updated README.md and DEPLOYMENT.md with a short mention of the new flag, and lib/cli.js's --help text.

UI Evidence

N/A — this is a local terminal CLI feature (one new flag) with no visible UI surface. No screenshots apply.

Notes

  • Deliberately did NOT modify runInit/laptop-init.js at all — the --interactive dispatch lives in
    bin/gittensory-miner.js, one layer above, so the non-interactive path's byte-for-byte-unchanged requirement
    is satisfied by construction rather than by a test asserting it after the fact.
  • Deliberately did NOT add prompts for CLAUDE_CODE_OAUTH_TOKEN/codex auth.json — those already have their
    own dedicated CLI auth flows (claude setup-token, codex auth) outside this wizard's scope; the issue's own
    scope is credential-and-provider-only (GITHUB_TOKEN + provider + provider config), not a port of those flows.
  • Verified empirically (before writing the implementation) that Node's readline masking trick works correctly
    over non-TTY fake streams — this is what made the real terminal adapter itself directly unit-testable rather
    than an untested "trust it" branch, and is what the REGRESSION test above exercises.

@joaovictor712
joaovictor712 requested a review from JSONbored as a code owner July 13, 2026 11:10
mkdirSync(stateDir, { recursive: true, mode: 0o700 });
const envFilePath = resolveWizardEnvFilePath(env);
writeFileSync(envFilePath, renderWizardEnvFile(entries));
chmodSync(envFilePath, 0o600);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: .env file written with default permissions before chmodSync restricts access

.env created with default umask permissions before chmodSync locks it down.

Pass { mode: 0o600 } to writeFileSync to create the file with secure permissions atomically.

AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.

<file name="packages/gittensory-miner/lib/init-wizard.js">
<violation number="1" location="packages/gittensory-miner/lib/init-wizard.js:95">
<priority>P2</priority>
<title>.env file written with default permissions before chmodSync restricts access</title>
<evidence>writeFileSync(envFilePath, renderWizardEnvFile(entries)); followed by chmodSync(envFilePath, 0o600); creates the credential file with the process&apos;s default umask permissions, leaving a small but exploitable window where other users or processes could read the freshly written GITHUB_TOKEN.</evidence>
<recommendation>Pass { mode: 0o600 } as the third argument to writeFileSync so the file is created atomically with restrictive permissions, eliminating the TOCTOU race condition.</recommendation>
</violation>
</file>

@superagent-security superagent-security Bot added the pr:flagged PR flagged for review by security analysis. label Jul 13, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@superagent-security superagent-security Bot removed the pr:flagged PR flagged for review by security analysis. label Jul 13, 2026
…arding wizard

First-time operators had to hand-author a .env with GITHUB_TOKEN and
MINER_CODING_AGENT_PROVIDER with no prompts and no validation until a later
doctor run or a failed live attempt.

Adds packages/gittensory-miner/lib/init-wizard.js, wired behind a new
`init --interactive` flag: prompts for GITHUB_TOKEN with masked, never-echoed
input, an optional coding-agent provider from the same CODING_AGENT_DRIVER_NAMES
menu the driver factory resolves, and that provider's skippable model/timeout
companion vars. Writes the collected values to a starter .env in the state
dir, then reruns the existing offline doctor checks so the operator sees
pass/fail immediately. Non-interactive init is untouched; no new network
calls are introduced.
writeFileSync created the file at the default umask permissions for an
instant before the follow-up chmodSync locked it down to 0600, briefly
exposing the collected GITHUB_TOKEN in cleartext to any other local reader.
Passing { mode: 0o600 } to writeFileSync closes that window for a newly
created file; chmodSync still runs afterward to correct the mode on a
pre-existing file from an earlier run.
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.02%. Comparing base (6553b54) to head (a112be8).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5621   +/-   ##
=======================================
  Coverage   95.01%   95.02%           
=======================================
  Files         575      576    +1     
  Lines       45738    45797   +59     
  Branches    14661    14661           
=======================================
+ Hits        43459    43518   +59     
  Misses       1528     1528           
  Partials      751      751           
Flag Coverage Δ
shard-1 43.84% <0.00%> (-0.14%) ⬇️
shard-2 35.69% <0.00%> (+0.09%) ⬆️
shard-3 32.16% <0.00%> (-0.14%) ⬇️
shard-4 30.83% <0.00%> (-1.75%) ⬇️
shard-5 32.53% <0.00%> (+0.75%) ⬆️
shard-6 44.77% <100.00%> (+0.70%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/gittensory-miner/lib/cli.js 100.00% <ø> (ø)
packages/gittensory-miner/lib/init-wizard.js 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 13, 2026
@loopover-orb

loopover-orb Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-13 12:07:10 UTC

8 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
Adds an opt-in `init --interactive` wizard that prompts for GITHUB_TOKEN (masked via a readline output-hook trick) and an optional coding-agent provider sourced from the engine's own driver-name/config-env maps, writes a starter .env (0600), initializes laptop state, and reruns the existing offline doctor. The design correctly avoids hand-duplicated provider lists by importing from `@​loopover/engine`, and the masking approach is a reasonable no-dependency solution with tests verifying the raw secret never hits the output stream. This closes issue #5176 and is well-targeted, narrow operator-facing tooling with strong test coverage of the new module's branches.

Nits — 5 non-blocking
  • packages/gittensory-miner/lib/init-wizard.js: the 0o700/0o600 file-mode literals could be named constants for clarity, though the inline comments already explain intent.
  • init-wizard.js's `promptRequiredMasked` retry loop plus nested provider/companion-var prompting pushes control-flow depth up; consider extracting the retry loop's body if it grows further.
  • The e2e CLI test relies on Node tearing down an unsettled top-level await when no stdin is piped — this is a slightly fragile test technique (depends on process-exit timing) though it does verify routing as intended.
  • README/DEPLOYMENT docs updates are clear and accurate relative to the new flag's behavior.
  • Consider extracting the 0o600/0o700 literals into named constants (e.g. `STATE_DIR_MODE`, `ENV_FILE_MODE`) in init-wizard.js for readability.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #5176
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 1885 registered-repo PR(s), 1242 merged, 49 issue(s).
Contributor context ✅ Confirmed Gittensor contributor galuis116; Gittensor profile; 1885 PR(s), 49 issue(s).
Gate result ✅ Passing No configured blocker found.
Improvement ✅ Minor risk: clean · value: minor — Code changes are accompanied by test evidence.
Review context
  • Author: galuis116
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: JavaScript, Python, Dart, TypeScript, HTML, MDX, Rust, C++
  • Official Gittensor activity: 1885 PR(s), 49 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
[BETA] Chat with Gittensory

Ask Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @gittensory ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @gittensory chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @gittensory mention with a real question is routed to the closest matching read-only command automatically -- no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 13, 2026
@JSONbored
JSONbored merged commit c5815f4 into JSONbored:main Jul 13, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add gittensory-miner init --interactive first-run onboarding wizard

2 participants