Skip to content

fix: audit consumer projects from cwd#1014

Merged
affaan-m merged 5 commits intomainfrom
fix/harness-audit-consumer-mode
Mar 30, 2026
Merged

fix: audit consumer projects from cwd#1014
affaan-m merged 5 commits intomainfrom
fix/harness-audit-consumer-mode

Conversation

@affaan-m
Copy link
Copy Markdown
Owner

@affaan-m affaan-m commented Mar 30, 2026

Summary

  • audit the current working directory by default instead of hardcoding the ECC repo root
  • auto-detect ECC repo mode vs consumer-project mode and use a consumer rubric that scores plugin install plus project-local harness signals
  • document the new --root option and add regression coverage for consumer-project execution

Testing

  • node tests/scripts/harness-audit.test.js
  • node scripts/harness-audit.js repo --format json

Fixes #979


Summary by cubic

Audit now runs against the current working directory and auto-detects ECC repo vs consumer projects to apply the right rubric and scorecard, fixing #979. Also hardens CI by improving the Unicode-safety lint and isolating package-manager-dependent tests; use --root to audit another path.

  • New Features

    • Default audit root is CWD; add --root <path> to target a different directory.
    • Auto-detects target mode (repo vs consumer) and applies a consumer rubric for plugin install and project-local signals.
    • JSON/text output include target_mode and root_dir; header prints both.
    • Rubric version bumped to 2026-03-30; docs updated; regression tests added for consumer-project execution.
  • Migration

    • Update any CI or scripts that assumed repo-root auditing to pass --root when auditing another path.
    • If parsing JSON, expect new fields target_mode and root_dir (additive).

Written for commit 0124f6f. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added a --root CLI option to target a custom audit directory
    • Audit now auto-detects repository vs. consumer project and reports target mode
  • Documentation

    • Updated command docs to include --root and bumped rubric version to 2026-03-30
    • Minor formatting improvements across command docs
  • Tests

    • Expanded audit tests for consumer-project scenarios and adjusted expectations
  • Bug Fixes

    • Improved invisible-character and emoji detection/sanitization logic

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools bot commented Mar 30, 2026

Analyzing 5000 commits...

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c7d235af-b096-4529-a043-5eaa77e445e6

📥 Commits

Reviewing files that changed from the base of the PR and between 0cf7738 and 0124f6f.

📒 Files selected for processing (3)
  • tests/hooks/hooks.test.js
  • tests/lib/package-manager.test.js
  • tests/lib/resolve-formatter.test.js

📝 Walkthrough

Walkthrough

Adds a configurable audit root and consumer-aware detection to harness audit: new --root / AUDIT_ROOT option, root-aware helpers, separate repo vs. consumer check sets, report fields for root_dir/target_mode, rubric bumped to 2026-03-30, docs updated, and tests adapted.

Changes

Cohort / File(s) Summary
Docs - harness-audit
\.opencode/commands/harness-audit.md, commands/harness-audit.md
Documented new --root <path> option, clarified default (cwd) and auto-detection of ECC vs consumer, bumped rubric_version to 2026-03-30.
Core Audit Script
scripts/harness-audit.js
Added --root CLI / AUDIT_ROOT; refactored path helpers to accept rootDir; added safeParseJson, hasFileWithExtension, detectTargetMode, findPluginInstall; split checks into getRepoChecks(rootDir) and getConsumerChecks(rootDir); changed buildReport(scope)buildReport(scope, options = {}) to accept options.rootDir; include root_dir and target_mode in reports; updated help/text output and rubric version.
Tests - harness-audit
tests/scripts/harness-audit.test.js
Added temp-dir helpers (createTempDir, cleanup), run() accepts { cwd, homeDir }; updated expectations for rubric_version and target_mode; added consumer-project audit test and adjusted human text header expectation.
CI script - unicode safety
scripts/ci/check-unicode-safety.js
Replaced regex-based invisible-char detection with explicit codepoint checks and collectors; implemented stripDangerousInvisibleChars and collectDangerousInvisibleMatches; refactored emoji regex.
Tests - environment isolation helpers
tests/lib/package-manager.test.js, tests/lib/resolve-formatter.test.js, tests/hooks/hooks.test.js
Added/used withIsolatedHome helper or isolated HOME handling to isolate tests from user/global home; tests now set HOME/USERPROFILE where appropriate.
Tests - codex hooks
tests/scripts/codex-hooks.test.js
Sync test updated to call sync with --update-mcp, tightened assertions to check config.toml for [mcp_servers.context7].
Docs formatting
commands/learn-eval.md, commands/multi-plan.md
Markdown indentation/fencing fixes only (formatting).

Sequence Diagram(s)

sequenceDiagram
  participant User as CLI User
  participant CLI as /harness-audit CLI
  participant Script as harness-audit.js
  participant FS as Filesystem
  participant Plugin as ECC Plugin (~/.claude)

  User->>CLI: run /harness-audit [--root <path>]
  CLI->>Script: invoke with parsed args (rootDir / options)
  Script->>FS: read package.json and filesystem under rootDir
  alt target == "repo"
    Script->>Script: detectTargetMode() => "repo"
    Script->>FS: run getRepoChecks(rootDir)
  else target == "consumer"
    Script->>Plugin: probe plugin install (findPluginInstall)
    Script->>Script: detectTargetMode() => "consumer"
    Script->>FS: run getConsumerChecks(rootDir)
  end
  Script->>Script: buildReport(including root_dir, target_mode, rubric_version)
  Script-->>CLI: output JSON + human-readable summary
  CLI-->>User: display report
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I hopped through roots both near and far,
I sniffed out repo burrows and a consumer's yard,
Split checks with a twitch, and tracked every trail,
Now reports find their home, whether project or mail,
A little audit hop — scored clear and smart! 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes to learn-eval.md and multi-plan.md are formatting cleanups unrelated to audit functionality; changes to codex-hooks.test.js and check-unicode-safety.js appear unrelated to consumer project auditing objectives. Remove or justify the markdown formatting changes in learn-eval.md and multi-plan.md, codex-hooks.test.js updates, and check-unicode-safety.js refactoring as they fall outside the scope of #979.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title clearly summarizes the main change: enabling harness audit to work with consumer projects from the current working directory.
Linked Issues check ✅ Passed Changes fully address issue #979 objectives: auto-detect target mode (repo vs consumer), implement consumer-aware checks, and provide meaningful audit scoring for consumer projects.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/harness-audit-consumer-mode

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools bot commented Mar 30, 2026

Analysis Failed

Not Found - https://docs.github.com/rest/git/refs#get-a-reference

Troubleshooting
Cause Resolution
Large repository Analysis may timeout on repos with extensive history
API rate limits Wait 15 minutes before retrying
Network issues Queue timeout is 15 minutes; retry may succeed
Permissions Verify app has Contents: Read access

Retry: /ecc-tools analyze


Report Issue | ECC Tools

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

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: 1b4597a3d6

ℹ️ 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".

Comment on lines +192 to +195
path.join(rootDir, '.claude', 'plugins', 'everything-claude-code', '.claude-plugin', 'plugin.json'),
path.join(rootDir, '.claude', 'plugins', 'everything-claude-code', 'plugin.json'),
homeDir && path.join(homeDir, '.claude', 'plugins', 'everything-claude-code', '.claude-plugin', 'plugin.json'),
homeDir && path.join(homeDir, '.claude', 'plugins', 'everything-claude-code', 'plugin.json'),
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 Detect all supported ECC plugin install locations

findPluginInstall() only probes two home-directory layouts (~/.claude/plugins/everything-claude-code/...), but the repo’s own resolver (resolveEccRoot in scripts/lib/resolve-ecc-root.js) also treats paths like ~/.claude/plugins/everything-claude-code@everything-claude-code and ~/.claude/plugins/marketplace/everything-claude-code as valid installs. In those common install modes, consumer-plugin-install will be reported as failing even when ECC is correctly installed, which lowers scores and produces misleading remediation advice for consumer projects.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 30, 2026

Greptile Summary

This PR fixes #979 by changing the audit's default root from the hardcoded ECC repo directory to the current working directory, and adding auto-detection of ECC-repo vs consumer-project mode so that a tailored rubric is applied in each case. A new --root <path> CLI flag and AUDIT_ROOT environment variable allow overriding the default. The unicode-safety CI script is refactored to avoid a problematic regex, and several test helpers are updated to use isolated home directories to prevent interference from global developer tooling.

Key changes:

  • scripts/harness-audit.js: Removes REPO_ROOT constant; adds parseArgs --root support, detectTargetMode, findPluginInstall, getConsumerChecks, and getRepoChecks (refactored from the old getChecks). buildReport now emits root_dir and target_mode in its output.
  • scripts/ci/check-unicode-safety.js: Replaces a single Unicode regex (dangerousInvisibleRe) with a codepoint-iterating helper to resolve CI failures; the emojiRe pattern is also made more portable.
  • Tests: New regression test in tests/scripts/harness-audit.test.js scaffolds a consumer project and verifies consumer-mode scoring. withIsolatedHome helpers added to package-manager and resolve-formatter tests; codex-hooks test updated to pass --update-mcp.

One new P2 finding: findPluginInstall reads only process.env.HOME to locate the global plugin install. On Windows (where HOME is often unset and USERPROFILE is the canonical variable), all home-directory candidates are filtered out, so the consumer-plugin-install check silently fails even when ECC is installed. The run helper in the new harness-audit.test.js test follows the same pattern, unlike the withIsolatedHome helpers added elsewhere in this PR which correctly set both HOME and USERPROFILE.

Four issues flagged in the previous review thread (crashing getRepoChecks when package.json is absent, --root silently consuming an adjacent flag, node_modules scanned by hasFileWithExtension, and undocumented AUDIT_ROOT) are not yet addressed.

Confidence Score: 5/5

Safe to merge; the only new finding is a P2 Windows portability gap in findPluginInstall, and all prior thread issues are pre-existing / non-blocking.

The core logic — CWD-default root, detectTargetMode, consumer rubric, --root flag, unicode-safety refactor — is sound. The single new issue found (HOME vs USERPROFILE) is P2 and affects only Windows users of the consumer-plugin-install scoring path. All other new findings are P2 or lower, so per the confidence guidance the score stays at 5.

scripts/harness-audit.js — findPluginInstall (line 372) and the four items from the prior review thread that remain open.

Important Files Changed

Filename Overview
scripts/harness-audit.js Core change: replaces hardcoded REPO_ROOT with CWD-based root, adds --root flag, detectTargetMode, and a full consumer rubric. New findPluginInstall only checks HOME, missing USERPROFILE on Windows (P2). Pre-existing thread issues (getRepoChecks throws without package.json, --root consuming adjacent flag, node_modules scan, AUDIT_ROOT undocumented) remain open.
tests/scripts/harness-audit.test.js Adds a regression test for consumer-project execution with a scaffolded temp dir and isolated HOME. The run helper sets HOME but not USERPROFILE, inconsistent with withIsolatedHome helpers added in the same PR to package-manager and resolve-formatter tests.
scripts/ci/check-unicode-safety.js Replaces the single problematic regex with a codepoint-iterating helper (isDangerousInvisibleCodePoint + collectDangerousInvisibleMatches) to unblock CI; the refactoring is functionally equivalent and correctly handles supplementary-plane characters via index += char.length.
tests/lib/package-manager.test.js Adds withIsolatedHome helper (correctly sets both HOME and USERPROFILE) and wraps the npm default test to avoid interference from global package manager config.
tests/lib/resolve-formatter.test.js Adds withIsolatedHome helper (sets both HOME and USERPROFILE) and wraps biome/prettier npx fallback tests to avoid interference from global formatter installs.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["harness-audit.js main()"] --> B["parseArgs()\n• --root (or AUDIT_ROOT env, or CWD)"]
    B --> C["buildReport(scope, {rootDir})"]
    C --> D["detectTargetMode(rootDir)"]
    D -->|"package.json name == 'everything-claude-code'\nor secondary file heuristic"| E["target_mode = 'repo'"]
    D -->|otherwise| F["target_mode = 'consumer'"]
    E --> G["getRepoChecks(rootDir)\n⚠ throws if package.json missing"]
    F --> H["getConsumerChecks(rootDir)\n• findPluginInstall\n• .claude/ overrides\n• AGENTS.md / CLAUDE.md\n• .mcp.json / settings.json\n• test suite / CI / evals\n• SECURITY.md / .gitignore\n• hook guardrails"]
    G --> I["filter by scope"]
    H --> I
    I --> J["summarizeCategoryScores()"]
    J --> K["Return report\n{scope, root_dir, target_mode,\noverall_score, max_score, checks}"]
    K -->|"--format json"| L["JSON output"]
    K -->|"--format text"| M["Text output\nwith header + top 3 actions"]
Loading

Reviews (3): Last reviewed commit: "test: isolate package-manager dependent ..." | Re-trigger Greptile

scopes: ['repo'],
path: '.claude/memory.md',
description: 'Project memory or durable notes are checked in',
pass: fileExists(rootDir, '.claude/memory.md') || countFiles(rootDir, 'docs/adr', '.md') > 0,
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.

P1 node_modules scanned when searching from repo root

hasFileWithExtension(rootDir, '.', ...) starts the recursive walk at the project root, which means it will descend into node_modules (thousands of files) when the check isn't short-circuited by the earlier conditions. The check only reaches this call when:

  1. packageJson?.scripts?.test is not a string and
  2. countFiles(rootDir, 'tests', '.test.js') returns 0

Any consumer project that has node_modules but no package.json test script and no tests/*.test.js files will trigger a full recursive scan. With a large dependency tree this will easily exceed the 10-second test timeout and degrade the UX significantly.

A simple fix is to limit the search to explicit, bounded directories (e.g. src/, test/, __tests__/) rather than .:

Suggested change
pass: fileExists(rootDir, '.claude/memory.md') || countFiles(rootDir, 'docs/adr', '.md') > 0,
pass: typeof packageJson?.scripts?.test === 'string' || countFiles(rootDir, 'tests', '.test.js') > 0 || hasFileWithExtension(rootDir, 'src', ['.spec.js', '.spec.ts', '.test.ts']) || hasFileWithExtension(rootDir, 'test', ['.spec.js', '.spec.ts', '.test.ts']),

Comment on lines +53 to +56
if (arg === '--root') {
parsed.root = path.resolve(args[index + 1] || process.cwd());
index += 1;
continue;
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 --root silently consumes adjacent flag when no path is given

When --root is provided without a value and the very next token is another flag (e.g. node harness-audit.js --root --format json), args[index + 1] is '--format', which becomes the resolved root path (something like /cwd/--format). index is then incremented to skip '--format', so json lands as a positional scope argument and throws "Invalid scope: json".

The same pre-existing pattern affects --format and --scope, so this is not unique to this PR, but since --root is a new user-facing option it's a good opportunity to add a guard:

Suggested change
if (arg === '--root') {
parsed.root = path.resolve(args[index + 1] || process.cwd());
index += 1;
continue;
if (arg === '--root') {
const next = args[index + 1];
if (!next || next.startsWith('-')) {
throw new Error('--root requires a path argument');
}
parsed.root = path.resolve(next);
index += 1;
continue;
}

scope: 'repo',
format: 'text',
help: false,
root: path.resolve(process.env.AUDIT_ROOT || process.cwd()),
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 AUDIT_ROOT env variable is undocumented

process.env.AUDIT_ROOT is used as a default root override but is not mentioned in the help text (the showHelp function) or in the command markdown files. Users who discover this via the source won't have any official reference for it.

Consider adding a one-liner to showHelp and to the --root documentation in commands/harness-audit.md:

  Env: AUDIT_ROOT=<path>   Alternative to --root for CI/scripting use.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 4 files

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="scripts/harness-audit.js">

<violation number="1" location="scripts/harness-audit.js:53">
P2: Validate that `--root` receives a non-flag value before consuming the next token. Without this guard, `--root --format json` resolves `--format` as a path and shifts `json` into scope parsing.</violation>

<violation number="2" location="scripts/harness-audit.js:190">
P2: `findPluginInstall` only uses `HOME`; when that env var is unset, user-level plugin installs are not detected and `consumer-plugin-install` can fail incorrectly.</violation>

<violation number="3" location="scripts/harness-audit.js:529">
P2: Avoid scanning the entire repository for `*.spec`/`*.test` files; this recursive `'.'` walk can be very slow on large projects.</violation>
</file>

<file name="commands/harness-audit.md">

<violation number="1" location="commands/harness-audit.md:11">
P3: The new `--root` option is documented in Usage/Engine but not in the `Arguments` section, leaving the command docs inconsistent.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +53 to +57
if (arg === '--root') {
parsed.root = path.resolve(args[index + 1] || process.cwd());
index += 1;
continue;
}
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 30, 2026

Choose a reason for hiding this comment

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

P2: Validate that --root receives a non-flag value before consuming the next token. Without this guard, --root --format json resolves --format as a path and shifts json into scope parsing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/harness-audit.js, line 53:

<comment>Validate that `--root` receives a non-flag value before consuming the next token. Without this guard, `--root --format json` resolves `--format` as a path and shifts `json` into scope parsing.</comment>

<file context>
@@ -51,6 +50,12 @@ function parseArgs(argv) {
       continue;
     }
 
+    if (arg === '--root') {
+      parsed.root = path.resolve(args[index + 1] || process.cwd());
+      index += 1;
</file context>
Suggested change
if (arg === '--root') {
parsed.root = path.resolve(args[index + 1] || process.cwd());
index += 1;
continue;
}
if (arg === '--root') {
const next = args[index + 1];
if (!next || next.startsWith('-')) {
throw new Error('--root requires a path argument');
}
parsed.root = path.resolve(next);
index += 1;
continue;
}
Fix with Cubic

scopes: ['repo'],
path: 'tests/',
description: 'The project has an automated test entrypoint',
pass: typeof packageJson?.scripts?.test === 'string' || countFiles(rootDir, 'tests', '.test.js') > 0 || hasFileWithExtension(rootDir, '.', ['.spec.js', '.spec.ts', '.test.ts']),
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 30, 2026

Choose a reason for hiding this comment

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

P2: Avoid scanning the entire repository for *.spec/*.test files; this recursive '.' walk can be very slow on large projects.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/harness-audit.js, line 529:

<comment>Avoid scanning the entire repository for `*.spec`/`*.test` files; this recursive `'.'` walk can be very slow on large projects.</comment>

<file context>
@@ -381,12 +462,136 @@ function getChecks() {
+      scopes: ['repo'],
+      path: 'tests/',
+      description: 'The project has an automated test entrypoint',
+      pass: typeof packageJson?.scripts?.test === 'string' || countFiles(rootDir, 'tests', '.test.js') > 0 || hasFileWithExtension(rootDir, '.', ['.spec.js', '.spec.ts', '.test.ts']),
+      fix: 'Add a test script or checked-in tests so harness recommendations can be verified automatically.',
+    },
</file context>
Suggested change
pass: typeof packageJson?.scripts?.test === 'string' || countFiles(rootDir, 'tests', '.test.js') > 0 || hasFileWithExtension(rootDir, '.', ['.spec.js', '.spec.ts', '.test.ts']),
pass: typeof packageJson?.scripts?.test === 'string' ||
countFiles(rootDir, 'tests', '.test.js') > 0 ||
hasFileWithExtension(rootDir, 'tests', ['.spec.js', '.spec.ts', '.test.ts']) ||
hasFileWithExtension(rootDir, 'src', ['.spec.js', '.spec.ts', '.test.ts']),
Fix with Cubic

}

function findPluginInstall(rootDir) {
const homeDir = process.env.HOME || '';
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 30, 2026

Choose a reason for hiding this comment

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

P2: findPluginInstall only uses HOME; when that env var is unset, user-level plugin installs are not detected and consumer-plugin-install can fail incorrectly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/harness-audit.js, line 190:

<comment>`findPluginInstall` only uses `HOME`; when that env var is unset, user-level plugin installs are not detected and `consumer-plugin-install` can fail incorrectly.</comment>

<file context>
@@ -109,19 +119,90 @@ function countFiles(relativeDir, extension) {
+}
+
+function findPluginInstall(rootDir) {
+  const homeDir = process.env.HOME || '';
+  const candidates = [
+    path.join(rootDir, '.claude', 'plugins', 'everything-claude-code', '.claude-plugin', 'plugin.json'),
</file context>
Suggested change
const homeDir = process.env.HOME || '';
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
Fix with Cubic


- `scope` (optional): `repo` (default), `hooks`, `skills`, `commands`, `agents`
- `--format`: output style (`text` default, `json` for automation)
- `--root`: audit a specific path instead of the current working directory
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 30, 2026

Choose a reason for hiding this comment

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

P3: The new --root option is documented in Usage/Engine but not in the Arguments section, leaving the command docs inconsistent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At commands/harness-audit.md, line 11:

<comment>The new `--root` option is documented in Usage/Engine but not in the `Arguments` section, leaving the command docs inconsistent.</comment>

<file context>
@@ -4,22 +4,23 @@ Run a deterministic repository harness audit and return a prioritized scorecard.
 
 - `scope` (optional): `repo` (default), `hooks`, `skills`, `commands`, `agents`
 - `--format`: output style (`text` default, `json` for automation)
+- `--root`: audit a specific path instead of the current working directory
 
 ## Deterministic Engine
</file context>
Fix with Cubic

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
scripts/harness-audit.js (2)

3-4: ⚠️ Potential issue | 🟠 Major

Use a Windows-safe home directory lookup for plugin detection.

process.env.HOME is often unset on Windows, so consumer-plugin-install will fail there even when ECC is installed. Prefer os.homedir() or at least a HOME/USERPROFILE fallback.

Suggested fix
 const fs = require('fs');
+const os = require('os');
 const path = require('path');
@@
 function findPluginInstall(rootDir) {
-  const homeDir = process.env.HOME || '';
+  const homeDir = process.env.HOME || process.env.USERPROFILE || os.homedir();
   const candidates = [

As per coding guidelines "scripts/**/*.js: Provide cross-platform Node.js utilities supporting Windows, macOS, and Linux in scripts/ directory".

Also applies to: 189-198

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/harness-audit.js` around lines 3 - 4, Replace direct usage of
process.env.HOME with a Windows-safe home lookup: require the os module
(os.homedir()) and use os.homedir() as the primary home directory, falling back
to process.env.USERPROFILE or process.env.HOME if necessary; update all
occurrences including the plugin detection logic (references to process.env.HOME
and any code around lines 189-198 and the consumer-plugin-install check) to use
this new lookup so plugin detection works on Windows, macOS, and Linux.

24-31: ⚠️ Potential issue | 🟠 Major

Validate --root before building the report.

A missing operand (--root / --root=) or a bad --root/AUDIT_ROOT path currently falls through to cwd or an “empty consumer project” score. That makes the new root selection audit the wrong target instead of failing fast.

Suggested fix
+function assertDirectory(rootDir) {
+  if (!fs.existsSync(rootDir) || !fs.statSync(rootDir).isDirectory()) {
+    throw new Error(`Invalid root directory: ${rootDir}`);
+  }
+}
+
 function parseArgs(argv) {
   const args = argv.slice(2);
   const parsed = {
     scope: 'repo',
     format: 'text',
     help: false,
-    root: path.resolve(process.env.AUDIT_ROOT || process.cwd()),
+    root: process.env.AUDIT_ROOT || process.cwd(),
   };
@@
     if (arg === '--root') {
-      parsed.root = path.resolve(args[index + 1] || process.cwd());
+      const value = args[index + 1];
+      if (!value || value.startsWith('-')) {
+        throw new Error('Missing value for --root');
+      }
+      parsed.root = value;
       index += 1;
       continue;
     }
@@
     if (arg.startsWith('--root=')) {
-      parsed.root = path.resolve(arg.slice('--root='.length));
+      const value = arg.slice('--root='.length);
+      if (!value) {
+        throw new Error('Missing value for --root');
+      }
+      parsed.root = value;
       continue;
     }
@@
+  parsed.root = path.resolve(parsed.root);
+  assertDirectory(parsed.root);
+
   return parsed;
 }
@@
 function buildReport(scope, options = {}) {
   const rootDir = path.resolve(options.rootDir || process.cwd());
+  assertDirectory(rootDir);
   const targetMode = options.targetMode || detectTargetMode(rootDir);

As per coding guidelines "Always validate all user input before processing at system boundaries" and "Fail fast with clear error messages when validation fails".

Also applies to: 53-57, 69-72, 81-85, 615-618

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/harness-audit.js` around lines 24 - 31, The parseArgs root resolution
(variable root set via path.resolve(process.env.AUDIT_ROOT || process.cwd()) in
parseArgs) must validate the provided --root/--root= value and AUDIT_ROOT before
proceeding: if the CLI arg is present but empty or the resolved path does not
exist or is not a directory, emit a clear error (console.error / processLogger)
and exit non‑zero (or throw) so the audit fails fast; update parseArgs to detect
an explicit empty --root, check fs.existsSync and fs.statSync.isDirectory for
the resolved root, and apply the same validation wherever root is
constructed/used (the other occurrences you noted) to avoid falling back
silently to cwd or an empty project score.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@commands/harness-audit.md`:
- Around line 7-11: Update the documented CLI contract to reflect consumer mode
and the new --root option: add --root to the $ARGUMENTS block and usage line
(`/harness-audit [scope] [--format text|json] [--root path]`), change the
example header from "Harness Audit (repo):" to be dynamic or indicate consumer
detection (e.g., "Harness Audit (consumer/auto-detected):"), and revise the
score/contract text so "scope=repo" no longer assumes a fixed 70-point maximum
but instead describes the current scoring behavior in consumer mode; mirror all
of these same edits into the .opencode copy so both files remain identical.

In `@scripts/harness-audit.js`:
- Around line 171-186: The detectTargetMode function currently uses presence of
scripts/harness-audit.js, .claude-plugin/plugin.json, agents, and skills to
infer "repo" which wrongly flags consumer repos that vendor those files; update
detectTargetMode to require an authoritative marker or explicit override
instead. Replace or augment the file-existence branch (the block using
fileExists(rootDir, 'scripts/harness-audit.js'), fileExists(rootDir,
'.claude-plugin/plugin.json'), fileExists(rootDir, 'agents'),
fileExists(rootDir, 'skills')) so it only returns 'repo' when a trusted marker
exists (e.g., packageJson.claudeRepo === true or a dedicated marker file like
.claude-repo) or when an explicit override/env var is set; keep the existing
packageJson?.name === 'everything-claude-code' check and use the same symbols
(detectTargetMode, safeParseJson, safeRead, fileExists) to locate and change the
logic. Ensure no plain file-presence heuristic alone determines repo mode.

---

Outside diff comments:
In `@scripts/harness-audit.js`:
- Around line 3-4: Replace direct usage of process.env.HOME with a Windows-safe
home lookup: require the os module (os.homedir()) and use os.homedir() as the
primary home directory, falling back to process.env.USERPROFILE or
process.env.HOME if necessary; update all occurrences including the plugin
detection logic (references to process.env.HOME and any code around lines
189-198 and the consumer-plugin-install check) to use this new lookup so plugin
detection works on Windows, macOS, and Linux.
- Around line 24-31: The parseArgs root resolution (variable root set via
path.resolve(process.env.AUDIT_ROOT || process.cwd()) in parseArgs) must
validate the provided --root/--root= value and AUDIT_ROOT before proceeding: if
the CLI arg is present but empty or the resolved path does not exist or is not a
directory, emit a clear error (console.error / processLogger) and exit non‑zero
(or throw) so the audit fails fast; update parseArgs to detect an explicit empty
--root, check fs.existsSync and fs.statSync.isDirectory for the resolved root,
and apply the same validation wherever root is constructed/used (the other
occurrences you noted) to avoid falling back silently to cwd or an empty project
score.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 611ff0e9-aab0-4ee2-8b16-22d14268a72f

📥 Commits

Reviewing files that changed from the base of the PR and between ded5d82 and 1b4597a.

📒 Files selected for processing (4)
  • .opencode/commands/harness-audit.md
  • commands/harness-audit.md
  • scripts/harness-audit.js
  • tests/scripts/harness-audit.test.js

Comment on lines +7 to +11
`/harness-audit [scope] [--format text|json] [--root path]`

- `scope` (optional): `repo` (default), `hooks`, `skills`, `commands`, `agents`
- `--format`: output style (`text` default, `json` for automation)
- `--root`: audit a specific path instead of the current working directory
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.

⚠️ Potential issue | 🟡 Minor

Finish updating the documented output contract for consumer mode.

The new text introduces --root and consumer-project auto-detection, but the page still reflects the old CLI shape below: the $ARGUMENTS block omits --root, the example header is still Harness Audit (repo):, and the contract still implies scope=repo always means a 70-point max. Please update this file and the .opencode mirror together so the docs match the current output.

Also applies to: 23-36

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@commands/harness-audit.md` around lines 7 - 11, Update the documented CLI
contract to reflect consumer mode and the new --root option: add --root to the
$ARGUMENTS block and usage line (`/harness-audit [scope] [--format text|json]
[--root path]`), change the example header from "Harness Audit (repo):" to be
dynamic or indicate consumer detection (e.g., "Harness Audit
(consumer/auto-detected):"), and revise the score/contract text so "scope=repo"
no longer assumes a fixed 70-point maximum but instead describes the current
scoring behavior in consumer mode; mirror all of these same edits into the
.opencode copy so both files remain identical.

Comment on lines +171 to +186
function detectTargetMode(rootDir) {
const packageJson = safeParseJson(safeRead(rootDir, 'package.json'));
if (packageJson?.name === 'everything-claude-code') {
return 'repo';
}

if (
fileExists(rootDir, 'scripts/harness-audit.js') &&
fileExists(rootDir, '.claude-plugin/plugin.json') &&
fileExists(rootDir, 'agents') &&
fileExists(rootDir, 'skills')
) {
return 'repo';
}

return 'consumer';
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.

⚠️ Potential issue | 🟠 Major

The repo-mode heuristic still matches copied ECC files.

Any consumer repo that vendors scripts/harness-audit.js, .claude-plugin/plugin.json, agents/, and skills/ will be forced back into repo mode. That recreates the copied-files false positive this PR is trying to remove, so mode detection needs to rely on an authoritative repo marker or an explicit override instead of the same file-presence heuristic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/harness-audit.js` around lines 171 - 186, The detectTargetMode
function currently uses presence of scripts/harness-audit.js,
.claude-plugin/plugin.json, agents, and skills to infer "repo" which wrongly
flags consumer repos that vendor those files; update detectTargetMode to require
an authoritative marker or explicit override instead. Replace or augment the
file-existence branch (the block using fileExists(rootDir,
'scripts/harness-audit.js'), fileExists(rootDir, '.claude-plugin/plugin.json'),
fileExists(rootDir, 'agents'), fileExists(rootDir, 'skills')) so it only returns
'repo' when a trusted marker exists (e.g., packageJson.claudeRepo === true or a
dedicated marker file like .claude-repo) or when an explicit override/env var is
set; keep the existing packageJson?.name === 'everything-claude-code' check and
use the same symbols (detectTargetMode, safeParseJson, safeRead, fileExists) to
locate and change the logic. Ensure no plain file-presence heuristic alone
determines repo mode.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools bot commented Mar 30, 2026

Analyzing 5000 commits...

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools bot commented Mar 30, 2026

Analysis Failed

Not Found - https://docs.github.com/rest/git/refs#get-a-reference

Troubleshooting
Cause Resolution
Large repository Analysis may timeout on repos with extensive history
API rate limits Wait 15 minutes before retrying
Network issues Queue timeout is 15 minutes; retry may succeed
Permissions Verify app has Contents: Read access

Retry: /ecc-tools analyze


Report Issue | ECC Tools

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

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 (1)
scripts/ci/check-unicode-safety.js (1)

119-127: Consider using array accumulation for cleaner string building.

String concatenation in a loop creates intermediate strings. While modern V8 optimizes this in many cases, the array + join pattern is more idiomatic for building strings from filtered characters.

♻️ Optional: Array-based approach
 function stripDangerousInvisibleChars(text) {
-  let next = '';
-  for (const char of text) {
-    if (!isDangerousInvisibleCodePoint(char.codePointAt(0))) {
-      next += char;
-    }
-  }
-  return next;
+  const chars = [];
+  for (const char of text) {
+    if (!isDangerousInvisibleCodePoint(char.codePointAt(0))) {
+      chars.push(char);
+    }
+  }
+  return chars.join('');
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/ci/check-unicode-safety.js` around lines 119 - 127, The
stripDangerousInvisibleChars implementation should avoid repeated string
concatenation; instead, collect allowed characters into an array and join at the
end. Replace the current loop in stripDangerousInvisibleChars to push each char
that passes isDangerousInvisibleCodePoint(char.codePointAt(0)) into a local
array (e.g., parts) and return parts.join('') so string building is done via
array accumulation for clarity and performance.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/scripts/codex-hooks.test.js`:
- Around line 121-122: Before running the migration in this test, seed the
legacy header "[mcp_servers.context7-mcp]" into the fixture and after the sync
run assert that the canonical header "[mcp_servers.context7]" exists and the
legacy header is removed; specifically update the setup that writes the fixture
(the code that produces the file at configPath) to include the legacy section,
then replace the single assert.match(syncedConfig,
/^\[mcp_servers\.context7\]$/m) with two checks: one asserting the canonical
header is present (e.g. assert.match(syncedConfig,
/^\[mcp_servers\.context7\]$/m)) and one asserting the legacy header is absent
(e.g. assert.notMatch or
assert.ok(!/^\[mcp_servers\.context7-mcp\]$/m.test(syncedConfig))). Ensure you
refer to the same variables used in the diff (configPath and syncedConfig) when
reading and asserting.

---

Nitpick comments:
In `@scripts/ci/check-unicode-safety.js`:
- Around line 119-127: The stripDangerousInvisibleChars implementation should
avoid repeated string concatenation; instead, collect allowed characters into an
array and join at the end. Replace the current loop in
stripDangerousInvisibleChars to push each char that passes
isDangerousInvisibleCodePoint(char.codePointAt(0)) into a local array (e.g.,
parts) and return parts.join('') so string building is done via array
accumulation for clarity and performance.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 257ad7e1-251c-41ca-b887-7f7b7be7a91e

📥 Commits

Reviewing files that changed from the base of the PR and between 1b4597a and 0cf7738.

📒 Files selected for processing (4)
  • commands/learn-eval.md
  • commands/multi-plan.md
  • scripts/ci/check-unicode-safety.js
  • tests/scripts/codex-hooks.test.js
✅ Files skipped from review due to trivial changes (2)
  • commands/learn-eval.md
  • commands/multi-plan.md

Comment on lines +121 to +122
const syncedConfig = fs.readFileSync(configPath, 'utf8');
assert.match(syncedConfig, /^\[mcp_servers\.context7\]$/m);
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.

⚠️ Potential issue | 🟡 Minor

Strengthen migration assertion to avoid false positives

At Line 122, this can pass even if --update-mcp migration regresses, because the fixture already contains [mcp_servers.context7] before sync. Seed the legacy section ([mcp_servers.context7-mcp]) and assert canonical exists and legacy is removed after Line 119 runs.

Suggested test hardening
-      '[mcp_servers.context7]',
+      '[mcp_servers.context7-mcp]',
       'command = "npx"',
       'args = ["-y", "@upstash/context7-mcp"]',
       const syncedConfig = fs.readFileSync(configPath, 'utf8');
       assert.match(syncedConfig, /^\[mcp_servers\.context7\]$/m);
+      assert.doesNotMatch(syncedConfig, /^\[mcp_servers\.context7-mcp\]$/m);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/scripts/codex-hooks.test.js` around lines 121 - 122, Before running the
migration in this test, seed the legacy header "[mcp_servers.context7-mcp]" into
the fixture and after the sync run assert that the canonical header
"[mcp_servers.context7]" exists and the legacy header is removed; specifically
update the setup that writes the fixture (the code that produces the file at
configPath) to include the legacy section, then replace the single
assert.match(syncedConfig, /^\[mcp_servers\.context7\]$/m) with two checks: one
asserting the canonical header is present (e.g. assert.match(syncedConfig,
/^\[mcp_servers\.context7\]$/m)) and one asserting the legacy header is absent
(e.g. assert.notMatch or
assert.ok(!/^\[mcp_servers\.context7-mcp\]$/m.test(syncedConfig))). Ensure you
refer to the same variables used in the diff (configPath and syncedConfig) when
reading and asserting.

}

function getRepoChecks(rootDir) {
const packageJson = JSON.parse(readText(rootDir, 'package.json'));
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.

P1 getRepoChecks throws when package.json is absent

detectTargetMode has a secondary detection path (checking for scripts/harness-audit.js, .claude-plugin/plugin.json, agents/, and skills/) that can return 'repo' even when no package.json exists. When buildReport then calls getRepoChecks(rootDir), this line throws ENOENT and crashes the process.

In contrast, the new getConsumerChecks uses safeParseJson(safeRead(...)) which never throws. Apply the same safe pattern here:

Suggested change
const packageJson = JSON.parse(readText(rootDir, 'package.json'));
const packageJson = safeParseJson(safeRead(rootDir, 'package.json'));

With this change any subsequent checks that rely on packageJson data would just fail gracefully (returning false for their pass field) rather than crashing the audit run.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools bot commented Mar 30, 2026

Analyzing 5000 commits...

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools bot commented Mar 30, 2026

Analysis Failed

Not Found - https://docs.github.com/rest/git/refs#get-a-reference

Troubleshooting
Cause Resolution
Large repository Analysis may timeout on repos with extensive history
API rate limits Wait 15 minutes before retrying
Network issues Queue timeout is 15 minutes; retry may succeed
Permissions Verify app has Contents: Read access

Retry: /ecc-tools analyze


Report Issue | ECC Tools

@affaan-m affaan-m merged commit b9a01d3 into main Mar 30, 2026
6 of 40 checks passed
Sign up for free to 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.

/harness-audit is not usable for consumer projects

1 participant