8 Commits
Author SHA1 Message Date
214ee3dd2e feat(skills): add local skill CLI support (#1162)
* Add inspectable local skill CLI support

OpenClaude Skill Hub needs the runtime repo to treat project skills as first-class local assets before registry installation exists. This wires native .openclaude skill directories into discovery, preserves .claude compatibility, and adds list/show subcommands so users can inspect resolved local skills.

Constraint: Keep registry install, website catalog, and community governance out of this first runtime slice.

Rejected: Replace the existing skills loader wholesale | the repo already has working bundled, plugin, MCP, dynamic, and legacy command skill paths.

Confidence: medium

Scope-risk: moderate

Directive: Keep .claude skill loading compatible while .openclaude adoption rolls out.

Tested: bun test src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node dist/cli.mjs --bare skills list

Tested: node dist/cli.mjs --bare skills show debug

Tested: git diff --check

* Add local skill validation and removal

Skill Hub needs local package hygiene before registry install can be safe. This adds validation for SKILL.md directories and local removal for project or user skills without introducing remote registry behavior yet.

Constraint: Registry install and update flows are still out of scope for this slice.

Rejected: Implement install first | install needs the same validation and local removal semantics to avoid copying unsafe or unmanageable skill folders.

Confidence: medium

Scope-risk: moderate

Directive: Keep validation conservative; loosen individual checks only with explicit registry policy coverage.

Tested: bun test src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node dist/cli.mjs skills validate .openclaude/skills/demo-skill

Tested: node dist/cli.mjs skills list

Tested: node dist/cli.mjs skills show demo-skill

Tested: node dist/cli.mjs skills remove demo-skill

Tested: git diff --check

* Suppress startup banner for skills CLI

Skills management commands are meant to be script-friendly inspection operations. Printing the interactive startup screen before the list/show/validate output makes the command noisy and hard to read.

Constraint: Keep the interactive startup screen for normal OpenClaude sessions.

Confidence: high

Scope-risk: narrow

Tested: bun run build

Tested: node dist/cli.mjs skills list

Tested: git diff --check

* Make skills list readable for daily CLI use

The default skills list output was a metadata-heavy dump, which made bundled and local skills difficult to scan. This changes the human formatter to an aligned table with wrapped descriptions while keeping machine-readable metadata behind --json.

Constraint: Default list output must stay compact and human-readable while JSON remains script-friendly.

Rejected: Keep version and trust columns in the default table | those fields add noise and remain available through --json/show.

Confidence: high

Scope-risk: narrow

Directive: Keep the default list formatter focused on scanability; add metadata to --json or detail commands instead of widening the daily table.

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node dist/cli.mjs skills list

Tested: node dist/cli.mjs skills list --json

* Stabilize skills tests under CI

The PR introduced skills tests that passed in focused runs but failed under the full GitHub Actions Bun test job. The formatter test now uses bun:test consistently, and skill directory tests explicitly restore the setting-source state they rely on.

Constraint: CI runs the full Bun suite, so tests must avoid node:test interop and shared setting-source leakage.

Confidence: medium

Scope-risk: narrow

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: git diff --check

Not-tested: Full local bun test still has unrelated provider/OAuth failures on this machine.

* Isolate user skill precedence test state

The full CI suite can mutate process-wide config state while this test is running, so the user-vs-project precedence assertion now runs in a child Bun process with its own CLAUDE_CONFIG_DIR.

Constraint: getSkillDirCommands reads global config/env state, so this precedence test needs process isolation under the full suite.

Confidence: medium

Scope-risk: narrow

Tested: bun test src/skills/loadSkillsDir.test.ts src/cli/handlers/skills.test.ts src/commands.test.ts

Tested: git diff --check

* Stabilize conversation arc perf checks

The CI runner was failing the conversation arc benchmarks because they used shared persisted knowledge graph state and strict wall-clock thresholds. The tests now isolate graph storage in a temporary config directory and keep only coarse regression limits suitable for noisy shared runners.

Constraint: GitHub Actions shared runners can have variable storage/indexing latency.

Rejected: Remove the benchmark coverage entirely | the tests still provide useful regression signals when isolated and coarse-grained.

Confidence: medium

Scope-risk: narrow

Directive: Keep performance tests isolated from persisted user/project graph state.

Tested: bun test src/utils/conversationArc.perf.test.ts src/skills/loadSkillsDir.test.ts src/cli/handlers/skills.test.ts src/commands.test.ts

Tested: bun run smoke

* Let users install skills from registries and local sources

The skill hub CLI could list, inspect, validate, and remove local skills, but it had no supported install path. This adds a project/global install command that accepts local directories, raw SKILL.md files or URLs, and registry IDs with checksum validation when registry metadata provides one.

Constraint: The companion openclaude-skills repository currently publishes SKILL.md files without riskLevel metadata, so validation keeps riskLevel optional while preserving required identity/source fields.

Rejected: Require the external skills repository to be cloned into openclaude | install should work from registry metadata or explicit local paths without coupling the repos.

Confidence: high

Scope-risk: moderate

Directive: Keep --json/list behavior machine-compatible; install output should remain human-readable and validation should not reject normal security-review prose.

Tested: bun test src/cli/handlers/skillsInstall.test.ts src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: bun run smoke

* Stabilize skills install tests in the full suite

The install tests used shared console and cwd globals, which passed in isolation but raced with unrelated test files under Bun's full parallel suite. This makes the tests assert on installed files directly and injects the project directory into the handler for deterministic test isolation.

Constraint: The CLI still resolves project installs from the runtime cwd; projectDir is only used by direct handler tests.

Confidence: high

Scope-risk: narrow

Tested: bun test src/cli/handlers/skillsInstall.test.ts src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: bun run smoke

* Keep skills install coverage in the existing skills suite

The new standalone install test file changed Bun's parallel test scheduling and exposed unrelated global-state races in CI. Moving the coverage into the existing skills handler test file keeps the install behavior covered without adding another parallel test unit.

Constraint: Some existing tests mutate cwd/config globals under full-suite parallelism.

Confidence: medium

Scope-risk: narrow

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: git diff --check

* Harden skill install paths before validation

The install path used registry or SKILL.md names to create temporary and target directories before validation rejected unsafe names. This validates the install name before path construction, keeps the temp root as an explicit cleanup target, and resolves install targets under the selected skills root before copy or force removal.

Constraint: Registry and raw SKILL.md sources are untrusted until validation completes.

Rejected: Rely on validateSkillPath after temp construction | unsafe names can affect filesystem paths before validation runs.

Confidence: high

Scope-risk: narrow

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: bun run smoke

Tested: git diff --check

* Hide bundled skills from human skills list

The default skills list is meant for skills users can inspect and manage in the current environment. Bundled skills remain available internally and in JSON metadata, but the human table now omits bundled rows and removes the Source column.

Constraint: --json remains machine-readable with full source metadata.

Confidence: high

Scope-risk: narrow

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node dist/cli.mjs skills list

Tested: node dist/cli.mjs skills list --json

Tested: git diff --check

Tested: bun run smoke

* Include home dir in config cache key

Tests can mock homedir while leaving CLAUDE_CONFIG_DIR unset, so caching only by the env override can leak a temporary .openclaude root into later config/profile tests. Include homedir in the memoization key so config path resolution follows both inputs.

Constraint: Keep getClaudeConfigHomeDir memoized for hot callers.

Confidence: high

Scope-risk: narrow

Tested: bun test --max-concurrency=1 src/utils/openclaudePaths.test.ts src/utils/providerProfile.test.ts src/utils/knowledgeGraph.stress.test.ts tests/sdk/sdk-context-isolation.test.ts

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node dist/cli.mjs skills list

Tested: bun run smoke

Tested: git diff --check

* Hide bundled skills from public skills commands

Bundled skills are internal helpers, so the public skills CLI should only expose installed skills that users can inspect or manage. Filter bundled skills from JSON output and command lookups, and use a generic not-found response for hidden bundled names.

Constraint: Installed project and user skills remain listed, inspectable, removable, and available in JSON.

Confidence: high

Scope-risk: narrow

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node dist/cli.mjs skills list --json

Tested: node dist/cli.mjs skills show batch

Tested: node dist/cli.mjs skills remove batch

Tested: bun run smoke

Tested: git diff --check

* Stop config path leaks across tests

The full PR check can load config-path helpers after tests have mocked homedir or changed global session state. Explicit CLAUDE_CONFIG_DIR now bypasses the default-home memoization cache, and SDK contexts now treat sessionProjectDir: null as an intentional context value instead of falling back to stale global state.

Constraint: Keep default config-home resolution memoized for hot callers.

Confidence: high

Scope-risk: narrow

Tested: bun test --max-concurrency=1 src/utils/openclaudePaths.test.ts src/utils/providerProfile.test.ts src/utils/knowledgeGraph.stress.test.ts tests/sdk/sdk-context-isolation.test.ts

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: bun run smoke

Tested: git diff --check

* Stabilize config-sensitive tests in CI

The PR check showed provider profile tests sharing process.env/CWD-sensitive state and a knowledge graph stress test assuming a fixed config-root persistence path. Mark the profile tests that mutate global process state as non-concurrent and assert the corrupted Orama rename relative to the actual persistence path under test.

Constraint: Production behavior is unchanged; this only tightens test isolation.

Confidence: high

Scope-risk: narrow

Tested: bun test --max-concurrency=1 src/utils/openclaudePaths.test.ts src/utils/providerProfile.test.ts src/utils/knowledgeGraph.stress.test.ts tests/sdk/sdk-context-isolation.test.ts

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: git diff --check

* Explain skill remove scope mismatches

Removing a user-global skill without --global looked like a missing skill even though skills list showed it. Detect when the requested skill exists in the other local scope and print the exact removal command hint while keeping bundled/internal skills hidden as generic not found.

Constraint: Bundled skills remain hidden from public skills commands.

Confidence: high

Scope-risk: narrow

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node dist/cli.mjs skills remove pr-review

Tested: node dist/cli.mjs skills remove batch

Tested: bun run smoke

Tested: git diff --check

* Clarify empty skills list state

The public skills list now hides bundled/internal skills, so an empty result means there are no installed user or project skills. Use clearer copy to avoid implying internal skills do not exist.

Constraint: Bundled skills remain hidden from public skills commands.

Confidence: high

Scope-risk: narrow

Tested: bun test src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: node /home/anaxy/Projects/openclaude/dist/cli.mjs skills list from empty temp project

Tested: bun run smoke

Tested: git diff --check

* fix(skills): preserve namespaced local installs

* Keep skills CLI independent of provider startup

Skills management commands need to work when provider configuration is broken, because they are local/script-friendly maintenance commands. Route skills subcommands before provider profile hydration and validation, including supported leading global flags such as --bare.

Constraint: Provider startup validation must still run for normal interactive and provider-backed commands.

Rejected: Import full main.tsx for the skills fast path | that loads optional bundled Chrome modules and re-couples the local skills path to interactive startup.

Confidence: high

Scope-risk: narrow

Tested: bun test src/entrypoints/cli.skills.test.ts src/cli/handlers/skills.test.ts src/skills/loadSkillsDir.test.ts src/commands.test.ts

Tested: bun run build

Tested: CLAUDE_CODE_USE_OPENAI=1 OPENAI_BASE_URL=https://api.openai.com/v1 OPENAI_API_KEY= node dist/cli.mjs skills list

Tested: CLAUDE_CODE_USE_OPENAI=1 OPENAI_BASE_URL=https://api.openai.com/v1 OPENAI_API_KEY= node dist/cli.mjs --bare skills list

Tested: bun run smoke

Tested: git diff --check

* Preserve reviewed skill install hardening after rebase

Rebasing PR #1162 onto current main flattened an earlier merge commit that carried reviewed Skill Hub hardening and regression coverage. This restores those final-tree changes as a normal linear commit so the rebased PR keeps the same behavior reviewers approved without retaining merge commits or mainline noise.

Constraint: Keep the PR branch linear for maintainer review while preserving the reviewed final tree from the conflict-resolved integration branch.

Rejected: Push the plain rebase result | it would drop registry sha256/version/trust metadata handling and associated tests from the reviewed PR state.

Confidence: high

Scope-risk: narrow

Directive: Do not remove the registry sha256 requirement or install-path regression tests without another security review.

Tested: final tree compared against fix-pr-1162-conflicts before verification

* Fix skills CLI review follow-ups

* Fix skills CLI review findings

* Address skills CLI review follow-ups

* Fix skills tests under bare-mode CI state

* Clear bare argv in skills tests

* Harden skills remove and loader tests

* Pin cwd state in skills remove test

* Use explicit project dir for skills removal

* Avoid skill remove test name collision

* Use fs abstraction for skills removal

* fix skills CLI review findings

* Fix skills CLI startup bypass and test isolation

* Fix skills CLI review findings

* Fix remaining skills CLI review findings

* Fix skills CLI review findings

---------

Co-authored-by: OpenClaude Worker 3 <worker-3@openclaude.local>
Co-authored-by: jatmn <the@jat.mn>
2026-07-06 11:08:17 +08:00
1aabe261db feat(bughunter): make /bughunter public + add /bughunter-security & /bughunter-perf with robust fallback prompts (#1621)
* feat(bughunter): split into /bughunter, /bughunter-security, /bughunter-perf

Replace the single /bughunter command with three siblings that share a
common prefix:

  /bughunter          — general bug hunt (existing prompt, untouched)
  /bughunter-security — OWASP-aligned, exploit-driven, confidence ≥ 8
  /bughunter-perf     — hot-path complexity, sync I/O, leaks, N+1

Both new subcommands are prompt commands built with
createMovedToPluginCommand so they migrate to the bughunter marketplace
plugin unchanged once it ships. While the marketplace is private they
inline the full audit prompt (frontmatter + !`git ...` blocks) just like
the existing /bughunter.

All three stay in the public COMMANDS list (not INTERNAL_ONLY_COMMANDS)
so non-ant users can invoke them. clearCommandMemoizationCaches() now
also flushes the zero-arg COMMANDS() and builtInCommandNames() memos so
tests can switch USER_TYPE mid-run without poisoning the cache.

Adds regression tests in src/commands.test.ts covering:
  - bughunter stays public for non-ant users
  - bughunter-security and bughunter-perf are in the public list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore(bughunter): remove orphan index.js after .js → .ts rename

The bughunter command directory was renamed from a single .js file to
index.ts in the previous commit, but git tracked them as separate paths
so the old .js was left in the tree. Drop it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(bughunter): enhance fallback prompts for robustness in non-git environments

- Add graceful error handling to all git commands in fallback prompts (|| echo fallbacks)
- Add explicit non-git fallback guidance in Phase 1 for all three commands
- /bughunter: search for entry points, core business logic, recently modified files
- /bughunter-security: search for auth/middleware, validation, DB, config, upload code
- /bughunter-perf: search for handlers, loops, data access, serialization, build configs
- Improve context labels to clarify git context may be empty

* fix(bughunter): address CodeRabbit feedback

- Fix test isolation: restore USER_TYPE/IS_DEMO env vars in finally blocks
- Add non-git fallback test cases for all three bughunter commands
- Fix bash pipeline issue: replace if/then/else subshells with simple git commands + static fallback text in template
- Fix output format contradiction: remove LOW confidence from scoring (Phase 3 drops LOW, so scoring only includes Critical/Medium)

* fix(test): correct case and prefix in git fallback assertions for bughunter-security and bughunter-perf tests

* fix(test): add missing opening parenthesis in bughunter test assertions

* fix(bughunter): complete non-git fallback and propagate allowedTools

- Fix git commands in all three prompts to always succeed with fallback text (using || echo)
- Modify createMovedToPluginCommand to accept allowedTools parameter
- Add allowedTools to all three bughunter commands so slash-command turn grants declared tools
- Parse allowed-tools from frontmatter at command creation time

* fix(bughunter): complete non-git fallback and allowedTools propagation

- Fix git commands in prompts to always succeed with fallback text (using || echo)
- Modify createMovedToPluginCommand to accept allowedTools parameter
- Add allowedTools to all three bughunter commands so slash-command turn grants declared tools
- Fix RECENTLY COMMITTED FILES command to avoid command substitution (permission check rejects )
- Update tests to accept shell tool's '(Bash completed with no output)' for empty results
- Use runWithCwdOverride and additionalWorkingDirectories for proper test isolation

* fix(bughunter): prevent shell injection via user-provided args

The user-provided scope was interpolated into the prompt template BEFORE
executeShellCommandsInPrompt() ran, so any !command or ```! block
syntax in the args would be interpreted and executed as shell commands.

Fix: parse frontmatter from the raw template and run shell execution first
(with {{ARGS}} still in place — inert to shell patterns), then replace
{{ARGS}} with the user scope on the processed output. This ensures args
are never fed through the shell command parser.

* refactor(bughunter): use createGetAppStateWithAllowedTools helper

Replaces duplicate inline getAppState overrides across all three bughunter
commands (bughunter, bughunter-security, bughunter-perf) with the shared
helper from src/utils/forkedAgent.ts. This:
- Eliminates ~30 lines of duplicated permission context modification
- Merges allowedTools with existing alwaysAllowRules.command (vs overwrite)

* fix(bughunter): address jatmn review - String.replace special patterns + test isolation

- Replace '{{ARGS}}' with a replacer function () => scope instead of
  the plain string 'scope'. JavaScript's String.replace treats $&, $',
  $', , 32855 specially even in string replacements, so a scope like
  'src/auth $&' would render as 'src/auth {{ARGS}}' instead of literal
  text. The replacer function bypasses all special patterns.

- Restore USER_TYPE and IS_DEMO env vars in the injection regression
  test's finally block, matching the isolation pattern used by all other
  bughunter tests.

* fix(bughunter): make fallback prompt generation work on Windows

Wrap executeShellCommandsInPrompt() in a try/catch in all three bughunter
commands. On platforms where bash is unavailable (e.g. Windows without Git
Bash), the bash-specific shell syntax (2>/dev/null, | head -N) would cause
executeShellCommandsInPrompt to throw MalformedCommandError, preventing the
prompt from being generated at all.

The catch handler replaces the !`command` inline patterns with a static
placeholder, allowing the LLM to still receive the full audit instructions
and non-git search strategies in Phase 1.

* fix(bughunter-perf): remove Low severity contradiction

The summary line included Low: L but Phase 3 drops non-measurable findings
and exclusions remove micro-optimizations. Low findings (measurable but
not user-visible) would never survive the filter, so remove Low from the
severity categories and summary line.

fix(bughunter-security): align log-forging exclusion with A9 criteria

Exclusion #11 blocked all log spoofing/forging, but A9 says to flag
log injection when it enables audit-trail forgery. Narrowed the exclusion
to allow concrete audit-trail attacks through while still excluding
generic non-exploitable logging suggestions.

* fix(bughunter-security): tighten log-forging exclusion threshold

Reword exclusion #11 to require concrete evidence of a log-entry or
structured-field forgery path, not merely unsanitized user input.

* fix(bughunter): preserve fallback text on Windows/no-bash path

Replace generic '(Shell execution unavailable)' placeholder with a regex
that extracts the || echo "..." fallback text from each shell command.
This ensures the prompt shows meaningful messages like
'(If empty: not a git repository or git unavailable)' even when bash is
unavailable (e.g. Windows without Git Bash), matching what Linux users see
from working shell execution.

Also make injection test assertion platform-agnostic — accept either bash
output or the static echo fallback text.

* refactor(test): extract duplicate mockContext into createMockToolContext helper

The three non-git fallback tests each had an identical ~42-line mockContext
object. Moved it to a shared createMockToolContext(cwd, commands) helper
and a FULL_GIT_COMMANDS constant. Also updated the injection test to use
the same helper. Net -89 lines.

* fix(createMovedToPluginCommand): only grant allowedTools when fallback prompt runs

The ant (USER_TYPE === 'ant') branch returns a plugin-install notice that
doesn't need Read/Glob/Grep/Bash tools, but allowedTools was statically
attached to the command object. This caused processSlashCommand to grant
turn-scoped permissions for tools that were never used.

Changed to a getter that returns undefined in the ant branch, so the
plugin-install notice runs without unnecessary tool permissions.

* fix(bughunter): simplify shell commands to single git commands, narrow catch to surface interruptions

* fix(bughunter): surface permission-denied/aborted shell preprocessing, fix Windows cleanup

* fix(dragDropPaths.test): resolve package.json relative to test file, not process.cwd()

* fix(commands.test): restore original cwd in rmRetry, guarantee env/cache cleanup on rm failure

* fix(bughunter): bound diff to 400 lines, swap HEAD~10 for git log -10

Address both P2 reviewer findings on feat/bughunter-command-v3-new.

(1) Fresh-repo HEAD~10 lookup stripped every snippet. In a one-commit
    repo, `git diff --name-only HEAD~10..HEAD --diff-filter=AM` exits
    128 (HEAD~10 doesn't resolve). The shell-execution catch then ran
    the outer "strip all snippets" fallback, leaving git status /
    diff --cached / diff HEAD empty even though those commands would
    have produced useful context. Switched to `git log -10 --name-only
    --diff-filter=AM`, which works at any history depth and yields the
    same file list. Applied to bughunter, bughunter-security, and
    bughunter-perf.

(2) Diff cap removed in 73d0bcb. The prompt label still advertised
    "first 400 lines" but the snippet was just `git diff HEAD -- .`,
    and a 900-line diff was injected verbatim. Added a new `lineLimits`
    option to `executeShellCommandsInPrompt` that bounds output by
    command prefix. The cap is applied to stdout *before*
    processToolResultBlock, so the persistence + empty-content guard
    flows run once on the bounded payload, and large diffs no longer
    hit the 30k Bash result cap and spill into the prompt. Each
    bughunter command passes
    `{ lineLimits: { 'git diff HEAD -- .': 400 } }`. Allowed-tools
    frontmatter is unchanged — no compound `| head -400` that the
    permission parser might reject.

Tests:
- `executeShellCommandsInPrompt applies per-prefix line limits` +
  `does not truncate below the cap` (new unit tests in
  promptShellExecution.test.ts).
- `bughunter keeps git context populated in a fresh single-commit
  repo` (regression for finding 1, uses real one-commit git repo).
- `bughunter diff block is bounded to 400 lines` (regression for
  finding 2, builds 1000-line diff and asserts ≤400 lines).
- `FULL_GIT_COMMANDS` and the injection test now include
  `git log -10 --name-only --diff-filter=AM` in place of the
  removed HEAD~10 form.

* fix(bughunter): keep recent-files path-only, cover all three siblings

Two review follow-ups on the previous P2 commit.

(P3) `git log -10 --name-only` defaulted to --pretty=fuller, so the
"RECENTLY COMMITTED FILES" block injected commit hash, author, date,
and message lines into the prompt under a files-only heading — that
extra metadata crowded out the scoped file list the command was
trying to provide. Added `--pretty=format:` to suppress the commit
header on all three commands (bughunter, bughunter-security,
bughunter-perf). Verified locally: the previous form emitted ~7
header lines per commit; the new form emits just the file paths.

(P2) The fresh-repo and 400-line cap regression tests only exercised
/bughunter, so a sibling could regress back to the old shallow-history
failure or lose the diff cap without this suite failing. Parameterized
both tests over {bughunter, bughunter-security, bughunter-perf} via a
BUGHUNTER_SIBLINGS const; each command now runs both regressions in
its own tmp dir (six new test cases total). Typecheck clean, 27
tests pass.

* fix(promptShellExecution): granular snippet fallback, restore rich error for other callers

- Add granularFallback option to executeShellCommandsInPrompt. When
  enabled, a failing shell snippet is blanked in place and the rest of
  the snippets keep their output. Permission denials and interrupted
  ShellError still rethrow as MalformedCommandError, never swallowed.
- Restore the formatted MalformedCommandError wrapping in the default
  path. Previously a no-op that rethrew the raw ShellError, which made
  processSlashCommand render only 'ShellError: Shell command failed'
  for /commit, /security-review, /commit-push-pr, loaded skills, and
  plugin commands. Now includes the failing pattern and formatted
  stdout/stderr.
- /bughunter, /bughunter-security, /bughunter-perf opt into
  granularFallback and drop the catch-and-strip-all pattern. A failing
  'git log -10' on a zero-commit repo no longer discards git status
  output.
- Tests cover per-snippet blanking, default-path rich error wrapping,
  and that permission denials still surface under granularFallback.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(promptShellExecution): preserve trailing newline in applyLineLimit truncation

---------

Co-authored-by: Gravirei <gravirei@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-17 11:04:01 +08:00
89d05317b6 feat: add Vietnamese i18n for slash command descriptions (#1431)
* feat: add Vietnamese i18n support for slash command descriptions

Add a simple i18n helper that reads the `language` setting from config
to display localized skill descriptions. Currently supports English
(default) and Vietnamese.

To switch to Vietnamese, set in ~/.claude/settings.json:
  { "language": "vietnamese" }

Co-Authored-By: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>

* feat(i18n): add Vietnamese translations for all 85 command descriptions

- Fix detectLocale() to read ~/.claude/settings.json directly via
  readFileSync instead of broken require('../../utils/config.js')
- Add commandDescVi translation map with 85 Vietnamese descriptions
- Export translateCommandDescription() for use in command rendering
- Modify formatDescriptionWithSource() to translate descriptions
  when language is set to "vietnamese"
- Bump version to 0.15.1

* fix: add prepare script for git-based installs

When installing via `npm install -g git+https://...`, npm runs the
`prepare` script automatically. This ensures the CLI is built from
source during installation.

Requires Bun to be installed globally.

Co-Authored-By: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>

* fix(i18n): read locale from merged settings

* feat(i18n): translate all prompt-type commands + add env validation + node version files

## Changes

### 1. Fix prompt-type command translations (src/commands.ts)
- `formatDescriptionWithSource()` now calls `translateCommandDescription()` for ALL command types
- Previously only translated `builtin`/`mcp` source commands
- Now translates: workflow, plugin, bundled, and default cases
- Fixes: /review, /insights, and other prompt-type commands now display Vietnamese

### 2. Add missing Vietnamese translations (src/skills/bundled/i18n.ts)
Added 17 new command translations:
- /btw: "Đặt câu hỏi nhanh bên lề mà không làm gián đoạn cuộc hội thoại chính"
- /compact: "Xóa lịch sử hội thoại nhưng giữ tóm tắt trong ngữ cảnh"
- /auto-fix: "Cấu hình tự động sửa: chạy lint/test sau khi AI chỉnh sửa"
- /bridge-kick: "Chèn trạng thái lỗi bridge để kiểm thử khôi phục thủ công"
- /review: "Hoàn thành đánh giá bảo mật cho các thay đổi đang chờ trên nhánh hiện tại"
- +12 more commands

### 3. Add Zod env validation at startup (src/utils/envValidation.ts)
- New file: validates critical env vars using Zod at startup
- Crashes immediately if invalid (instead of wasting time)
- Validated vars: ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, CLAUDE_CONFIG_DIR, HTTP_PROXY, HTTPS_PROXY, NODE_EXTRA_CA_CERTS
- Integrated into src/entrypoints/init.ts

### 4. Add node version files
- .nvmrc: Node 22
- .node-version: Node 22
- Matches Dockerfile (node:22-slim) and package.json engines (>=22.0.0)

## Test Results
- 3007 pass, 11 fail (all in changeDetector.test.ts - pre-existing, unrelated to i18n)

Co-Authored-By: OpenClaude <noreply@openclaude.ai>

* fix: restore validateBoundedIntEnvVar in envValidation.ts

* Localize bundled skills descriptions at read time

* fix(i18n): localize slash command suggestions

Search rendered localized command descriptions and rebuild the Fuse index when language-sensitive text changes.

Preserve Unicode letters and numbers for Vietnamese slash queries, localize the remaining requested command descriptions, and keep exact slash command submission from following a stale highlighted suggestion.

Tests: bun test src/commands.test.ts; bun test src/utils/suggestions/commandSuggestions.test.ts; bun test src/utils/envValidation.test.ts

Thanks to @jatmn for the patient review and guidance.

* fix(i18n): tighten slash command localization scope

* fix(i18n): centralize localization and preserve external metadata

* fix(commands): scope localized descriptions to OpenClaude-owned commands

* fix(i18n): read session language before initial settings

* fix(i18n): prefer whenToUse localization keys

---------

Co-authored-by: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>
Co-authored-by: OpenClaude <noreply@openclaude.ai>
Co-authored-by: lht3003-rgb <lht3003-rgb@users.noreply.github.com>
2026-06-12 22:24:50 +08:00
chioarubandGitHub 132539ff79 fix(build): restore /dream slash command in bundled CLI (#1399)
Scope missing-module stubs for relative imports to the importer file so the unmirrored KAIROS dream skill stub no longer replaces the real /dream command module during bundling.
2026-05-31 06:37:05 +08:00
chioarubandGitHub 0aff8de24f feat(diagnostics): show request payload size breakdown (#1237)
* feat(diagnostics): show request payload size breakdown

* fix(diagnostics): clarify request-size estimate semantics
2026-05-23 13:03:12 +08:00
JATMNandGitHub cf33f03755 fix: hide missing-module slash command stubs (#1136)
Prevent generated missing-module noop functions from entering the built-in command registry.

Add a runtime isCommand guard in src/types/command.ts and apply it when building the COMMANDS() list so bare noopN tree-shaking stubs are excluded before they can appear in slash-command autocomplete.

Add focused tests covering rejection of noop-style stubs and acceptance of valid command objects.

Refs Gitlawb/openclaude#1132.
2026-05-13 08:53:01 +08:00
chioarubandGitHub 677d29ffd4 feat(lsp): add first-class code intelligence setup (#950)
* feat(lsp): add plugin candidate discovery

* feat(lsp): add first-class setup command

* fix(lsp): add bounded filesystem extension fallback

* fix(lsp): repair official marketplace recommendations
2026-05-02 08:35:38 +08:00
dhenuhandGitHub 3d1979ff06 fix(help): prevent /help tab crash from undefined descriptions (#732)
- Guard formatDescriptionWithSource() so missing command descriptions become ''
- Harden truncate helpers to accept undefined text/path safely
- Add regression tests covering undefined input cases
2026-04-19 06:38:44 +08:00