Skip to content

fix: init scaffold for new roots + usage-error hints + scanner regex - #156

Merged
LucasSantana-Dev merged 3 commits into
mainfrom
fix/150-152-153-roots-dx
Jul 3, 2026
Merged

fix: init scaffold for new roots + usage-error hints + scanner regex#156
LucasSantana-Dev merged 3 commits into
mainfrom
fix/150-152-153-roots-dx

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

Implements three sharekit issues (#150, #152, #153):

  1. Issue init() doesn't scaffold opencode/ and gjc/ roots; no e2e test for new roots #150: init() now scaffolds opencode/ and gjc/ directories

    • Copies representative configs from source root if present
    • Writes placeholder files with intent comments otherwise
    • Runs secret scanning on copied configs
    • Includes two new integration tests for roots scaffolding
  2. Issue Usage errors should explain <user> = GitHub username hosting a sharekit-profile repo #152: Usage errors clarify what <user> means

    • Added printUserHint() helper with example
    • Applied to update, rollback, uninstall, install/preview/inspect commands
    • Fixed rate-limit message: 5000/hr vs 60/hr unauthenticated
  3. Issue Scanner: Google API key regex only matches exactly 35 chars after AIza #153: Google API key regex widened

    • Changed from exactly 35 chars to 30-40 chars range
    • Added boundary tests (34, 39 detected; 29 not detected)

Test plan

  • ✅ 167 unit & integration tests pass
  • ✅ TypeScript strict mode passes
  • ✅ Prettier formatting clean
  • ✅ New root scaffolding tests validate placeholder and copy paths
  • ✅ Scanner regex boundary tests validate 30-40 char acceptance

Closes #150
Closes #152
Closes #153

Summary by CodeRabbit

  • New Features

    • init now sets up additional config folders for supported tools and copies existing settings when available, falling back to placeholder config files if needed.
    • Missing required arguments now show a clearer GitHub username hint with an example command.
  • Bug Fixes

    • Improved the GitHub rate-limit message with reset timing and authentication guidance.
    • Expanded Google API key detection to catch more valid key lengths.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 48 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e3455fd2-d71d-407a-8c9d-4e334da4f98a

📥 Commits

Reviewing files that changed from the base of the PR and between 051fef0 and a031d6b.

📒 Files selected for processing (2)
  • src/commands.ts
  • test/init.test.ts
📝 Walkthrough

Walkthrough

This PR scaffolds opencode/ and gjc/ directories during profile init() with copy-or-placeholder logic, adds a printUserHint() helper in index.ts invoked when <user> arguments are missing, updates the rate-limit error message, and widens the Google API key detection regex in scanner.ts from a fixed 35-character length to a 30–40 range, all accompanied by corresponding tests.

Changes

init() Scaffolding for opencode/ and gjc/

Layer / File(s) Summary
Scaffold opencode/ and gjc/ in init()
src/commands.ts
init() now creates opencode/ and gjc/ directories, copying the first found file from source root subdirectories or writing placeholder config.json/config.toml; shared/ creation moved to a later step.
Tests for init() scaffolding and plan() mapping
test/init.test.ts, test/plan.test.ts
New tests verify placeholder and copied configs are created correctly by init(), and that plan() maps opencode//gjc/ files to correct destinations via rootsFor().

Usage Error Hints and Rate-Limit Message

Layer / File(s) Summary
printUserHint() helper and rate-limit message
src/index.ts, src/commands.ts
A printUserHint() function explains the expected <user> format and is called in update, rollback, uninstall, and generic dispatch missing-argument paths; search()'s rate-limit error message now includes reset time and authenticated vs unauthenticated limits.

Google API Key Regex Widening

Layer / File(s) Summary
Widen Google API key regex and add boundary tests
src/scanner.ts, test/scan.test.ts
The AIza... detection regex now matches {30,40} characters instead of exactly {35}, with new boundary tests at 29, 34, and 39 characters.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

No sequence diagram generated: changes are localized scaffolding logic, error message text, and a regex adjustment without multi-component orchestration flows.

Related Issues

Related to #150: Adds opencode/ and gjc/ scaffolding in init() with copy-or-placeholder logic and integration-style tests for plan() mapping.
Related to #152: Adds <user> usage hint via printUserHint() and fixes the rate-limit message wording.
Related to #153: Widens the Google API key regex to {30,40} and adds boundary tests.

Suggested labels

enhancement, tests

Suggested reviewers

LucasSantana-Dev

🐰 A rabbit hops through code so neat,
Scaffolds new dirs for configs to meet,
Hints for lost users, a friendly nudge,
Keys widened so scanners won't budge,
Tests all in place — a tidy feat!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the three main changes in the PR.
Linked Issues check ✅ Passed The PR addresses #150, #152, and #153 with the requested scaffolding, usage hints, rate-limit text, regex widening, and tests.
Out of Scope Changes check ✅ Passed The changes stay within the linked objectives and add no unrelated features or refactors.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/150-152-153-roots-dx

Comment @coderabbitai help to get the list of available commands.

…e key regex

- Issue #150: init() now scaffolds opencode/ and gjc/ directories following the cursor pattern
  - Copies config files from source root if present (.config/opencode/, .gjc/)
  - Writes placeholder configs (config.json, config.toml) if source not found
  - Runs scanForSecrets on copied content
  - Adds two new integration tests for new roots scaffolding

- Issue #152: Usage errors now include helpful <user> parameter explanation
  - Added printUserHint() helper function for consistent messaging
  - Updated update, rollback, uninstall, install/preview/inspect commands
  - Updated rate-limit error message: '5000 req/hr' → '5000/hr vs 60/hr unauthenticated'

- Issue #153: Google API key regex widened from {35} to {30,40}
  - Matches keys with 30-40 character suffixes instead of exactly 35
  - Added boundary tests: 34 chars (detected), 39 chars (detected), 29 chars (not detected)

Tests: 167 pass, 0 fail | typecheck: ok | format: ok
Maps profile opencode/ and gjc/ files through rootsFor() to verify
they're correctly planned to ~/.config/opencode/ and ~/.gjc/
destinations respectively. Follows existing plan.test.ts pattern
with injected tmpHome and roots object.
@LucasSantana-Dev
LucasSantana-Dev force-pushed the fix/150-152-153-roots-dx branch from aa5b76c to 051fef0 Compare July 3, 2026 15:19

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/commands.ts (1)

735-787: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate scaffolding logic for opencode/ and gjc/.

The two blocks (opencode at Lines 735-761, gjc at Lines 763-787) are structurally identical apart from variable names, source subpaths, and placeholder filenames/content. Consider extracting a shared helper to reduce duplication and keep future changes (e.g., adding a third root) in one place.

♻️ Suggested refactor
+function scaffoldConfigDir(
+  profileRoot: string,
+  destSubdir: string,
+  sourceDir: string,
+  placeholderName: string,
+  placeholderContent: string,
+  allFindings: Finding[]
+): void {
+  const destDir = path.join(profileRoot, destSubdir);
+  fs.mkdirSync(destDir, { recursive: true });
+  let found = false;
+  if (fs.existsSync(sourceDir)) {
+    for (const file of fs.readdirSync(sourceDir).sort()) {
+      const filePath = path.join(sourceDir, file);
+      if (fs.statSync(filePath).isFile()) {
+        const destFile = path.join(destDir, file);
+        cp(filePath, destFile);
+        console.log(kleur.green(`  + ${tildify(destFile)}`));
+        const content = fs.readFileSync(destFile, 'utf8');
+        allFindings.push(...scanForSecrets(content, tildify(destFile)));
+        found = true;
+        break;
+      }
+    }
+  }
+  if (!found) {
+    const placeholderPath = path.join(destDir, placeholderName);
+    fs.writeFileSync(placeholderPath, placeholderContent);
+    console.log(kleur.green(`  + ${tildify(placeholderPath)} (placeholder)`));
+  }
+}

Then call it twice:

-  // 4. Scaffold opencode/ directory
-  ... (27 lines) ...
-  // 5. Scaffold gjc/ directory
-  ... (24 lines) ...
+  scaffoldConfigDir(profileRoot, 'opencode', path.join(sourceRoot, '.config', 'opencode'), 'config.json', '// opencode configuration\n', allFindings);
+  scaffoldConfigDir(profileRoot, 'gjc', path.join(sourceRoot, '.gjc'), 'config.toml', '# gjc configuration\n', allFindings);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands.ts` around lines 735 - 787, The `opencode/` and `gjc/`
scaffolding blocks in `commands.ts` duplicate the same copy-or-placeholder flow,
so extract that shared logic into a helper and reuse it for both cases. Put the
common directory creation, source scanning, first-file copy, secret scanning,
and placeholder fallback into one function, then call it for the
`sourceOpencodeDir`/`destOpencode` and `sourceGjcDir`/`destGjc` paths with their
respective placeholder filenames and messages. Keep the existing behavior in
`scanForSecrets`, `cp`, and the `opencodeFound`/`gjcFound` handling while
removing the repeated loop structure.
test/scan.test.ts (1)

251-269: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider testing exact boundary values (30 and 40 chars).

Current tests check 34/39 (positive) and 29 (negative), but not the literal edges of the {30,40} range.

♻️ Suggested additional boundary tests
+test('scanForSecrets detects Google API keys with 30 characters (min boundary)', () => {
+  const content = 'google_key = AIza' + 'a'.repeat(30);
+  const findings = scanForSecrets(content);
+  assert(findings.length > 0);
+  assert.equal(findings[0].rule, 'Google API Key');
+});
+
+test('scanForSecrets detects Google API keys with 40 characters (max boundary)', () => {
+  const content = 'google_key = AIza' + 'a'.repeat(40);
+  const findings = scanForSecrets(content);
+  assert(findings.length > 0);
+  assert.equal(findings[0].rule, 'Google API Key');
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/scan.test.ts` around lines 251 - 269, The Google API key boundary
coverage in scanForSecrets is missing the exact edges of the {30,40} range.
Update the tests around scanForSecrets to include cases at the literal minimum
and maximum lengths (30 and 40 characters) in addition to the existing
below-boundary check, using the same Google API Key rule assertions so the
boundary behavior is verified precisely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/commands.ts`:
- Around line 741-754: The config-copy loop in the sourceOpencodeDir handling is
nondeterministic because it breaks after the first regular file returned by
fs.readdirSync, whose order is not guaranteed. Update this logic in the commands
flow to either sort the directory listing before selecting a file or,
preferably, copy all matching config files like the recursive walk() used for
skills so the scaffolded profile is deterministic. Use the existing
opencodeFound, scanForSecrets, and cp flow as the anchor when refactoring.

---

Nitpick comments:
In `@src/commands.ts`:
- Around line 735-787: The `opencode/` and `gjc/` scaffolding blocks in
`commands.ts` duplicate the same copy-or-placeholder flow, so extract that
shared logic into a helper and reuse it for both cases. Put the common directory
creation, source scanning, first-file copy, secret scanning, and placeholder
fallback into one function, then call it for the
`sourceOpencodeDir`/`destOpencode` and `sourceGjcDir`/`destGjc` paths with their
respective placeholder filenames and messages. Keep the existing behavior in
`scanForSecrets`, `cp`, and the `opencodeFound`/`gjcFound` handling while
removing the repeated loop structure.

In `@test/scan.test.ts`:
- Around line 251-269: The Google API key boundary coverage in scanForSecrets is
missing the exact edges of the {30,40} range. Update the tests around
scanForSecrets to include cases at the literal minimum and maximum lengths (30
and 40 characters) in addition to the existing below-boundary check, using the
same Google API Key rule assertions so the boundary behavior is verified
precisely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 918b18b2-3f0f-4a27-8a79-93c1e9fe43c3

📥 Commits

Reviewing files that changed from the base of the PR and between 2498e5e and 051fef0.

📒 Files selected for processing (6)
  • src/commands.ts
  • src/index.ts
  • src/scanner.ts
  • test/init.test.ts
  • test/plan.test.ts
  • test/scan.test.ts

Comment thread src/commands.ts Outdated
@LucasSantana-Dev
LucasSantana-Dev merged commit d35e297 into main Jul 3, 2026
16 checks passed
@LucasSantana-Dev
LucasSantana-Dev deleted the fix/150-152-153-roots-dx branch July 3, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant