From a2597ba9ff3ce3069802e6470f4f9032e907f2b8 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:32:38 +0900 Subject: [PATCH 01/25] refactor: migrate CI workflow jobs to use reusable workflows --- .github/workflows/ci.yml | 78 +++++----------------------------------- 1 file changed, 8 insertions(+), 70 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a5eed0..d50951a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,87 +15,29 @@ permissions: jobs: test: - name: Test (${{ matrix.os }}, Node ${{ matrix.node }}) - runs-on: ${{ matrix.os }} - timeout-minutes: 15 - strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] node: ['20.x', '22.x'] - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js ${{ matrix.node }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node }} - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Run Tests - run: npm test - env: - GEMINI_CODE_PACKAGE_MANAGER: npm - - - name: Debug Info - if: failure() - run: | - echo "Node version: $(node -v)" - echo "NPM version: $(npm -v)" - ls -R tests + uses: ./.github/workflows/reusable-test.yml + with: + os: ${{ matrix.os }} + node-version: ${{ matrix.node }} + package-manager: 'npm' validate: - name: Validate Components - runs-on: ubuntu-latest - timeout-minutes: 5 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.x' - - - name: Debug Working Directory - run: | - pwd - ls -F - ls -F scripts/ci/ - - - name: Validate agents - run: node scripts/ci/validate-agents.js - - - name: Validate hooks - run: node scripts/ci/validate-hooks.js - - - name: Validate commands - run: node scripts/ci/validate-commands.js - - - name: Validate skills - run: node scripts/ci/validate-skills.js + uses: ./.github/workflows/reusable-validate.yml + with: + node-version: '22.x' security: name: Security Scan runs-on: ubuntu-latest timeout-minutes: 5 - steps: - name: Checkout uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22.x' - - name: Run npm audit run: npm audit --audit-level=high @@ -103,19 +45,15 @@ jobs: name: Lint runs-on: ubuntu-latest timeout-minutes: 5 - steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '22.x' cache: 'npm' - - name: Install dependencies run: npm ci - - name: Run ESLint run: npm run lint From 5d7b8a70121c443a4aaa5bbdd47071917312f21f Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:33:22 +0900 Subject: [PATCH 02/25] chore: remove rule validation step from reusable workflow --- .github/workflows/reusable-validate.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/reusable-validate.yml b/.github/workflows/reusable-validate.yml index 1d0da8f..1c0adfb 100644 --- a/.github/workflows/reusable-validate.yml +++ b/.github/workflows/reusable-validate.yml @@ -35,6 +35,3 @@ jobs: - name: Validate skills run: node scripts/ci/validate-skills.js - - - name: Validate rules - run: node scripts/ci/validate-rules.js From 01e68cd70685c5866ec7c050859bdd8060e1084e Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:33:34 +0900 Subject: [PATCH 03/25] ci: add read permissions to reusable test workflow --- .github/workflows/reusable-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml index 7919ff0..bcebe82 100644 --- a/.github/workflows/reusable-test.yml +++ b/.github/workflows/reusable-test.yml @@ -1,5 +1,8 @@ name: Reusable Test Workflow +permissions: + contents: read + on: workflow_call: inputs: From 671a20e59f2ac35e20a8a31d8b8f779787014463 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:33:44 +0900 Subject: [PATCH 04/25] chore: pin pnpm and bun setup actions to specific commit hashes --- .github/workflows/reusable-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml index bcebe82..8ad7cc8 100644 --- a/.github/workflows/reusable-test.yml +++ b/.github/workflows/reusable-test.yml @@ -39,13 +39,13 @@ jobs: - name: Setup pnpm if: inputs.package-manager == 'pnpm' - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: version: latest - name: Setup Bun if: inputs.package-manager == 'bun' - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - name: Get npm cache directory if: inputs.package-manager == 'npm' From 2edeb41dd57dfda6aa6a24f78df6e822b7373096 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:34:03 +0900 Subject: [PATCH 05/25] chore: pin action-gh-release to specific commit hash and remove redundant GITHUB_TOKEN env var --- .github/workflows/release.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2394221..956e5f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -103,10 +103,8 @@ jobs: fs.writeFileSync('RELEASE_NOTES.md', changelog); - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 with: tag_name: ${{ github.ref_name }} name: ${{ github.ref_name }} body_path: RELEASE_NOTES.md - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From f8d81bae2513fd4e8751cee69635d18efde8224f Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:34:10 +0900 Subject: [PATCH 06/25] chore: remove redundant npm ci step and pin stale action to specific hash --- .github/workflows/maintenance.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/maintenance.yml b/.github/workflows/maintenance.yml index 5d30084..67ebc7a 100644 --- a/.github/workflows/maintenance.yml +++ b/.github/workflows/maintenance.yml @@ -33,7 +33,6 @@ jobs: - name: Run security audit run: | if [ -f package-lock.json ]; then - npm ci npm audit --audit-level=high else echo "No package-lock.json found; skipping npm audit" @@ -43,7 +42,7 @@ jobs: name: Stale Issues/PRs runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9 with: stale-issue-message: 'This issue is stale due to inactivity.' stale-pr-message: 'This PR is stale due to inactivity.' From d2ebe62783fe636526efdcaa4e2906fc2d2dd241 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:34:25 +0900 Subject: [PATCH 07/25] chore: remove reusable release workflow configuration --- .github/workflows/reusable-release.yml | 59 -------------------------- 1 file changed, 59 deletions(-) delete mode 100644 .github/workflows/reusable-release.yml diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml deleted file mode 100644 index b711991..0000000 --- a/.github/workflows/reusable-release.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Reusable Release Workflow - -on: - workflow_call: - inputs: - tag: - description: 'Version tag (e.g., v1.0.0)' - required: true - type: string - generate-notes: - description: 'Auto-generate release notes' - required: false - type: boolean - default: true - -permissions: - contents: write - -jobs: - release: - name: Create Release - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Validate version tag - run: | - if ! [[ "${{ inputs.tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Invalid version tag format. Expected vX.Y.Z" - exit 1 - fi - - - name: Generate changelog - id: changelog - run: | - PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") - if [ -z "$PREV_TAG" ]; then - COMMITS=$(git log --pretty=format:"- %s" HEAD) - else - COMMITS=$(git log --pretty=format:"- %s" ${PREV_TAG}..HEAD) - fi - # Use unique delimiter to prevent truncation if commit messages contain EOF - DELIMITER="COMMITS_END_$(date +%s)" - echo "commits<<${DELIMITER}" >> $GITHUB_OUTPUT - echo "$COMMITS" >> $GITHUB_OUTPUT - echo "${DELIMITER}" >> $GITHUB_OUTPUT - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ inputs.tag }} - body: | - ## Changes - ${{ steps.changelog.outputs.commits }} - generate_release_notes: ${{ inputs.generate-notes }} From 7f619556c50c43b7f8e8db003daad879498c9e72 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:37:11 +0900 Subject: [PATCH 08/25] chore: rename .claude directory references to .gemini across command configuration files --- commands/claw.toml | 2 +- commands/e2e.toml | 2 +- commands/evolve.toml | 12 ++++++------ commands/instinct-export.toml | 2 +- commands/instinct-import.toml | 6 +++--- commands/instinct-status.toml | 6 +++--- commands/learn-eval.toml | 4 ++-- commands/learn.toml | 4 ++-- commands/multi-backend.toml | 16 ++++++++-------- commands/multi-execute.toml | 18 +++++++++--------- commands/multi-frontend.toml | 16 ++++++++-------- commands/multi-plan.toml | 14 +++++++------- commands/multi-workflow.toml | 10 +++++----- commands/plan.toml | 2 +- commands/projects.toml | 4 ++-- commands/promote.toml | 4 ++-- commands/prune.toml | 2 +- commands/resume-session.toml | 14 +++++++------- commands/save-session.toml | 8 ++++---- commands/sessions.toml | 8 ++++---- commands/setup-pm.toml | 4 ++-- commands/tdd.toml | 4 ++-- 22 files changed, 81 insertions(+), 81 deletions(-) diff --git a/commands/claw.toml b/commands/claw.toml index e5e2a41..3729479 100644 --- a/commands/claw.toml +++ b/commands/claw.toml @@ -48,7 +48,7 @@ exit Quit ## Notes - NanoClaw remains zero-dependency. -- Sessions are stored at `~/.claude/claw/.md`. +- Sessions are stored at `~/.gemini/claw/.md`. - Compaction keeps the most recent turns and writes a compaction header. - Export supports markdown, JSON turns, and plain text. diff --git a/commands/e2e.toml b/commands/e2e.toml index a58f2c5..2759bfd 100644 --- a/commands/e2e.toml +++ b/commands/e2e.toml @@ -336,7 +336,7 @@ For PMX, prioritize these E2E tests: ## Related Agents This command invokes the `e2e-runner` agent located at: -`~/.claude/agents/e2e-runner.md` +`~/.gemini/agents/e2e-runner.md` ## Quick Commands diff --git a/commands/evolve.toml b/commands/evolve.toml index f84e9c5..6a9435b 100644 --- a/commands/evolve.toml +++ b/commands/evolve.toml @@ -13,7 +13,7 @@ python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cl Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): ```bash -python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py evolve [--generate] +python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py evolve [--generate] ``` Analyzes instincts and clusters related ones into higher-level structures: @@ -74,7 +74,7 @@ Example: ## What to Do -1. Read all instincts from `~/.claude/homunculus/instincts/` +1. Read all instincts from `~/.gemini/homunculus/instincts/` 2. Group instincts by: - Domain similarity - Trigger pattern overlap @@ -82,7 +82,7 @@ Example: 3. For each cluster of 3+ related instincts: - Determine evolution type (command/skill/agent) - Generate the appropriate file - - Save to `~/.claude/homunculus/evolved/{commands,skills,agents}/` + - Save to `~/.gemini/homunculus/evolved/{commands,skills,agents}/` 4. Link evolved structure back to source instincts ## Output Format @@ -100,7 +100,7 @@ Confidence: 85% (based on 12 observations) Would create: /new-table command Files: - - ~/.claude/homunculus/evolved/commands/new-table.md + - ~/.gemini/homunculus/evolved/commands/new-table.md ## Cluster 2: Functional Code Style Instincts: prefer-functional, use-immutable, avoid-classes, pure-functions @@ -109,7 +109,7 @@ Confidence: 78% (based on 8 observations) Would create: functional-patterns skill Files: - - ~/.claude/homunculus/evolved/skills/functional-patterns.md + - ~/.gemini/homunculus/evolved/skills/functional-patterns.md ## Cluster 3: Debugging Process Instincts: debug-check-logs, debug-isolate, debug-reproduce, debug-verify @@ -118,7 +118,7 @@ Confidence: 72% (based on 6 observations) Would create: debugger agent Files: - - ~/.claude/homunculus/evolved/agents/debugger.md + - ~/.gemini/homunculus/evolved/agents/debugger.md --- Run `/evolve --execute` to create these files. diff --git a/commands/instinct-export.toml b/commands/instinct-export.toml index f2b317d..957fa9b 100644 --- a/commands/instinct-export.toml +++ b/commands/instinct-export.toml @@ -18,7 +18,7 @@ Exports instincts to a shareable format. Perfect for: ## What to Do -1. Read instincts from `~/.claude/homunculus/instincts/personal/` +1. Read instincts from `~/.gemini/homunculus/instincts/personal/` 2. Filter based on flags 3. Strip sensitive information: - Remove session IDs diff --git a/commands/instinct-import.toml b/commands/instinct-import.toml index c4009bc..87fdb7a 100644 --- a/commands/instinct-import.toml +++ b/commands/instinct-import.toml @@ -13,7 +13,7 @@ python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cl Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): ```bash -python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py import +python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py import ``` Import instincts from: @@ -36,7 +36,7 @@ Import instincts from: 2. Parse and validate the format 3. Check for duplicates with existing instincts 4. Merge or add new instincts -5. Save to `~/.claude/homunculus/instincts/inherited/` +5. Save to `~/.gemini/homunculus/instincts/inherited/` ## Import Process @@ -132,7 +132,7 @@ Added: 8 instincts Updated: 1 instinct Skipped: 3 instincts (2 duplicates, 1 conflict) -New instincts saved to: ~/.claude/homunculus/instincts/inherited/ +New instincts saved to: ~/.gemini/homunculus/instincts/inherited/ Run /instinct-status to see all instincts. ``` diff --git a/commands/instinct-status.toml b/commands/instinct-status.toml index 3584383..c1f3277 100644 --- a/commands/instinct-status.toml +++ b/commands/instinct-status.toml @@ -15,7 +15,7 @@ python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cl Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation), use: ```bash -python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py status +python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py status ``` ## Usage @@ -28,8 +28,8 @@ python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py status ## What to Do -1. Read all instinct files from `~/.claude/homunculus/instincts/personal/` -2. Read inherited instincts from `~/.claude/homunculus/instincts/inherited/` +1. Read all instinct files from `~/.gemini/homunculus/instincts/personal/` +2. Read inherited instincts from `~/.gemini/homunculus/instincts/inherited/` 3. Display them grouped by domain with confidence bars ## Output Format diff --git a/commands/learn-eval.toml b/commands/learn-eval.toml index 320d8f9..806183a 100644 --- a/commands/learn-eval.toml +++ b/commands/learn-eval.toml @@ -24,7 +24,7 @@ Look for: 3. **Determine save location:** - Ask: "Would this pattern be useful in a different project?" - - **Global** (`~/.claude/skills/learned/`): Generic patterns usable across 2+ projects (bash compatibility, LLM API behavior, debugging techniques, etc.) + - **Global** (`~/.gemini/skills/learned/`): Generic patterns usable across 2+ projects (bash compatibility, LLM API behavior, debugging techniques, etc.) - **Project** (`.claude/skills/learned/` in current project): Project-specific knowledge (quirks of a particular config file, project-specific architecture decisions, etc.) - When in doubt, choose Global (moving Global → Project is easier than the reverse) @@ -59,7 +59,7 @@ origin: auto-extracted Execute **all** of the following before evaluating the draft: - - [ ] Grep `~/.claude/skills/` and relevant project `.claude/skills/` files by keyword to check for content overlap + - [ ] Grep `~/.gemini/skills/` and relevant project `.claude/skills/` files by keyword to check for content overlap - [ ] Check MEMORY.md (both project and global) for overlap - [ ] Consider whether appending to an existing skill would suffice - [ ] Confirm this is a reusable pattern, not a one-off fix diff --git a/commands/learn.toml b/commands/learn.toml index f6cc9a6..81d9821 100644 --- a/commands/learn.toml +++ b/commands/learn.toml @@ -35,7 +35,7 @@ Look for: ## Output Format -Create a skill file at `~/.claude/skills/learned/[pattern-name].md`: +Create a skill file at `~/.gemini/skills/learned/[pattern-name].md`: ```markdown # [Descriptive Pattern Name] @@ -62,7 +62,7 @@ Create a skill file at `~/.claude/skills/learned/[pattern-name].md`: 2. Identify the most valuable/reusable insight 3. Draft the skill file 4. Ask user to confirm before saving -5. Save to `~/.claude/skills/learned/` +5. Save to `~/.gemini/skills/learned/` ## Notes diff --git a/commands/multi-backend.toml b/commands/multi-backend.toml index 66a3bfb..5362896 100644 --- a/commands/multi-backend.toml +++ b/commands/multi-backend.toml @@ -34,7 +34,7 @@ You are the **Backend Orchestrator**, coordinating multi-model collaboration for ``` # New session call Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend codex - \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend codex - \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -49,7 +49,7 @@ EOF", # Resume session call Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend codex resume - \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend codex resume - \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -67,9 +67,9 @@ EOF", | Phase | Codex | |-------|-------| -| Analysis | `~/.claude/.ccg/prompts/codex/analyzer.md` | -| Planning | `~/.claude/.ccg/prompts/codex/architect.md` | -| Review | `~/.claude/.ccg/prompts/codex/reviewer.md` | +| Analysis | `~/.gemini/.ccg/prompts/codex/analyzer.md` | +| Planning | `~/.gemini/.ccg/prompts/codex/architect.md` | +| Review | `~/.gemini/.ccg/prompts/codex/reviewer.md` | **Session Reuse**: Each call returns `SESSION_ID: xxx`, use `resume xxx` for subsequent phases. Save `CODEX_SESSION` in Phase 2, use `resume` in Phases 3 and 5. @@ -101,7 +101,7 @@ EOF", `[Mode: Ideation]` - Codex-led analysis **MUST call Codex** (follow call specification above): -- ROLE_FILE: `~/.claude/.ccg/prompts/codex/analyzer.md` +- ROLE_FILE: `~/.gemini/.ccg/prompts/codex/analyzer.md` - Requirement: Enhanced requirement (or $ARGUMENTS if not enhanced) - Context: Project context from Phase 1 - OUTPUT: Technical feasibility analysis, recommended solutions (at least 2), risk assessment @@ -115,7 +115,7 @@ Output solutions (at least 2), wait for user selection. `[Mode: Plan]` - Codex-led planning **MUST call Codex** (use `resume ` to reuse session): -- ROLE_FILE: `~/.claude/.ccg/prompts/codex/architect.md` +- ROLE_FILE: `~/.gemini/.ccg/prompts/codex/architect.md` - Requirement: User's selected solution - Context: Analysis results from Phase 2 - OUTPUT: File structure, function/class design, dependency relationships @@ -135,7 +135,7 @@ Claude synthesizes plan, save to `.claude/plan/task-name.md` after user approval `[Mode: Optimize]` - Codex-led review **MUST call Codex** (follow call specification above): -- ROLE_FILE: `~/.claude/.ccg/prompts/codex/reviewer.md` +- ROLE_FILE: `~/.gemini/.ccg/prompts/codex/reviewer.md` - Requirement: Review the following backend code changes - Context: git diff or code content - OUTPUT: Security, performance, error handling, API compliance issues list diff --git a/commands/multi-execute.toml b/commands/multi-execute.toml index 8a19c05..4ce8948 100644 --- a/commands/multi-execute.toml +++ b/commands/multi-execute.toml @@ -25,7 +25,7 @@ $ARGUMENTS ``` # Resume session call (recommended) - Implementation Prototype Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}resume - \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}resume - \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -40,7 +40,7 @@ EOF", # New session call - Implementation Prototype Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}- \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}- \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -58,7 +58,7 @@ EOF", ``` Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}resume - \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}resume - \"$PWD\" <<'EOF' ROLE_FILE: Scope: Audit the final code changes. @@ -86,8 +86,8 @@ EOF", | Phase | Codex | Gemini | |-------|-------|--------| -| Implementation | `~/.claude/.ccg/prompts/codex/architect.md` | `~/.claude/.ccg/prompts/gemini/frontend.md` | -| Review | `~/.claude/.ccg/prompts/codex/reviewer.md` | `~/.claude/.ccg/prompts/gemini/reviewer.md` | +| Implementation | `~/.gemini/.ccg/prompts/codex/architect.md` | `~/.gemini/.ccg/prompts/gemini/frontend.md` | +| Review | `~/.gemini/.ccg/prompts/codex/reviewer.md` | `~/.gemini/.ccg/prompts/gemini/reviewer.md` | **Session Reuse**: If `/ccg:plan` provided SESSION_ID, use `resume ` to reuse context. @@ -177,7 +177,7 @@ mcp__ace-tool__search_context({ **Limit**: Context < 32k tokens -1. Call Gemini (use `~/.claude/.ccg/prompts/gemini/frontend.md`) +1. Call Gemini (use `~/.gemini/.ccg/prompts/gemini/frontend.md`) 2. Input: Plan content + retrieved context + target files 3. OUTPUT: `Unified Diff Patch ONLY. Strictly prohibit any actual modifications.` 4. **Gemini is frontend design authority, its CSS/React/Vue prototype is the final visual baseline** @@ -186,7 +186,7 @@ mcp__ace-tool__search_context({ #### Route B: Backend/Logic/Algorithms → Codex -1. Call Codex (use `~/.claude/.ccg/prompts/codex/architect.md`) +1. Call Codex (use `~/.gemini/.ccg/prompts/codex/architect.md`) 2. Input: Plan content + retrieved context + target files 3. OUTPUT: `Unified Diff Patch ONLY. Strictly prohibit any actual modifications.` 4. **Codex is backend logic authority, leverage its logical reasoning and debug capabilities** @@ -247,12 +247,12 @@ mcp__ace-tool__search_context({ **After changes take effect, MUST immediately parallel call** Codex and Gemini for Code Review: 1. **Codex Review** (`run_in_background: true`): - - ROLE_FILE: `~/.claude/.ccg/prompts/codex/reviewer.md` + - ROLE_FILE: `~/.gemini/.ccg/prompts/codex/reviewer.md` - Input: Changed Diff + target files - Focus: Security, performance, error handling, logic correctness 2. **Gemini Review** (`run_in_background: true`): - - ROLE_FILE: `~/.claude/.ccg/prompts/gemini/reviewer.md` + - ROLE_FILE: `~/.gemini/.ccg/prompts/gemini/reviewer.md` - Input: Changed Diff + target files - Focus: Accessibility, design consistency, user experience diff --git a/commands/multi-frontend.toml b/commands/multi-frontend.toml index aa1143f..da1e043 100644 --- a/commands/multi-frontend.toml +++ b/commands/multi-frontend.toml @@ -34,7 +34,7 @@ You are the **Frontend Orchestrator**, coordinating multi-model collaboration fo ``` # New session call Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend gemini --gemini-model gemini-3-pro-preview - \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend gemini --gemini-model gemini-3-pro-preview - \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -49,7 +49,7 @@ EOF", # Resume session call Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend gemini --gemini-model gemini-3-pro-preview resume - \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend gemini --gemini-model gemini-3-pro-preview resume - \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -67,9 +67,9 @@ EOF", | Phase | Gemini | |-------|--------| -| Analysis | `~/.claude/.ccg/prompts/gemini/analyzer.md` | -| Planning | `~/.claude/.ccg/prompts/gemini/architect.md` | -| Review | `~/.claude/.ccg/prompts/gemini/reviewer.md` | +| Analysis | `~/.gemini/.ccg/prompts/gemini/analyzer.md` | +| Planning | `~/.gemini/.ccg/prompts/gemini/architect.md` | +| Review | `~/.gemini/.ccg/prompts/gemini/reviewer.md` | **Session Reuse**: Each call returns `SESSION_ID: xxx`, use `resume xxx` for subsequent phases. Save `GEMINI_SESSION` in Phase 2, use `resume` in Phases 3 and 5. @@ -101,7 +101,7 @@ EOF", `[Mode: Ideation]` - Gemini-led analysis **MUST call Gemini** (follow call specification above): -- ROLE_FILE: `~/.claude/.ccg/prompts/gemini/analyzer.md` +- ROLE_FILE: `~/.gemini/.ccg/prompts/gemini/analyzer.md` - Requirement: Enhanced requirement (or $ARGUMENTS if not enhanced) - Context: Project context from Phase 1 - OUTPUT: UI feasibility analysis, recommended solutions (at least 2), UX evaluation @@ -115,7 +115,7 @@ Output solutions (at least 2), wait for user selection. `[Mode: Plan]` - Gemini-led planning **MUST call Gemini** (use `resume ` to reuse session): -- ROLE_FILE: `~/.claude/.ccg/prompts/gemini/architect.md` +- ROLE_FILE: `~/.gemini/.ccg/prompts/gemini/architect.md` - Requirement: User's selected solution - Context: Analysis results from Phase 2 - OUTPUT: Component structure, UI flow, styling approach @@ -135,7 +135,7 @@ Claude synthesizes plan, save to `.claude/plan/task-name.md` after user approval `[Mode: Optimize]` - Gemini-led review **MUST call Gemini** (follow call specification above): -- ROLE_FILE: `~/.claude/.ccg/prompts/gemini/reviewer.md` +- ROLE_FILE: `~/.gemini/.ccg/prompts/gemini/reviewer.md` - Requirement: Review the following frontend code changes - Context: git diff or code content - OUTPUT: Accessibility, responsiveness, performance, design consistency issues list diff --git a/commands/multi-plan.toml b/commands/multi-plan.toml index a67f997..c38db02 100644 --- a/commands/multi-plan.toml +++ b/commands/multi-plan.toml @@ -24,7 +24,7 @@ $ARGUMENTS ``` Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}- \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}- \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -45,8 +45,8 @@ EOF", | Phase | Codex | Gemini | |-------|-------|--------| -| Analysis | `~/.claude/.ccg/prompts/codex/analyzer.md` | `~/.claude/.ccg/prompts/gemini/analyzer.md` | -| Planning | `~/.claude/.ccg/prompts/codex/architect.md` | `~/.claude/.ccg/prompts/gemini/architect.md` | +| Analysis | `~/.gemini/.ccg/prompts/codex/analyzer.md` | `~/.gemini/.ccg/prompts/gemini/analyzer.md` | +| Planning | `~/.gemini/.ccg/prompts/codex/architect.md` | `~/.gemini/.ccg/prompts/gemini/architect.md` | **Session Reuse**: Each call returns `SESSION_ID: xxx` (typically output by wrapper), **MUST save** for subsequent `/ccg:execute` use. @@ -129,12 +129,12 @@ mcp__ace-tool__search_context({ Distribute **original requirement** (without preset opinions) to both models: 1. **Codex Backend Analysis**: - - ROLE_FILE: `~/.claude/.ccg/prompts/codex/analyzer.md` + - ROLE_FILE: `~/.gemini/.ccg/prompts/codex/analyzer.md` - Focus: Technical feasibility, architecture impact, performance considerations, potential risks - OUTPUT: Multi-perspective solutions + pros/cons analysis 2. **Gemini Frontend Analysis**: - - ROLE_FILE: `~/.claude/.ccg/prompts/gemini/analyzer.md` + - ROLE_FILE: `~/.gemini/.ccg/prompts/gemini/analyzer.md` - Focus: UI/UX impact, user experience, visual design - OUTPUT: Multi-perspective solutions + pros/cons analysis @@ -154,11 +154,11 @@ Integrate perspectives and iterate for optimization: To reduce risk of omissions in Claude's synthesized plan, can parallel have both models output "plan drafts" (still **NOT allowed** to modify files): 1. **Codex Plan Draft** (Backend authority): - - ROLE_FILE: `~/.claude/.ccg/prompts/codex/architect.md` + - ROLE_FILE: `~/.gemini/.ccg/prompts/codex/architect.md` - OUTPUT: Step-by-step plan + pseudo-code (focus: data flow/edge cases/error handling/test strategy) 2. **Gemini Plan Draft** (Frontend authority): - - ROLE_FILE: `~/.claude/.ccg/prompts/gemini/architect.md` + - ROLE_FILE: `~/.gemini/.ccg/prompts/gemini/architect.md` - OUTPUT: Step-by-step plan + pseudo-code (focus: information architecture/interaction/accessibility/visual consistency) Wait for both models' complete results with `TaskOutput`, record key differences in their suggestions. diff --git a/commands/multi-workflow.toml b/commands/multi-workflow.toml index 37d7da1..bdb30a4 100644 --- a/commands/multi-workflow.toml +++ b/commands/multi-workflow.toml @@ -38,7 +38,7 @@ You are the **Orchestrator**, coordinating a multi-model collaborative system (R ``` # New session call Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}- \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}- \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -53,7 +53,7 @@ EOF", # Resume session call Bash({ - command: "~/.claude/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}resume - \"$PWD\" <<'EOF' + command: "~/.gemini/bin/codeagent-wrapper {{LITE_MODE_FLAG}}--backend {{GEMINI_MODEL_FLAG}}resume - \"$PWD\" <<'EOF' ROLE_FILE: Requirement: @@ -74,9 +74,9 @@ EOF", | Phase | Codex | Gemini | |-------|-------|--------| -| Analysis | `~/.claude/.ccg/prompts/codex/analyzer.md` | `~/.claude/.ccg/prompts/gemini/analyzer.md` | -| Planning | `~/.claude/.ccg/prompts/codex/architect.md` | `~/.claude/.ccg/prompts/gemini/architect.md` | -| Review | `~/.claude/.ccg/prompts/codex/reviewer.md` | `~/.claude/.ccg/prompts/gemini/reviewer.md` | +| Analysis | `~/.gemini/.ccg/prompts/codex/analyzer.md` | `~/.gemini/.ccg/prompts/gemini/analyzer.md` | +| Planning | `~/.gemini/.ccg/prompts/codex/architect.md` | `~/.gemini/.ccg/prompts/gemini/architect.md` | +| Review | `~/.gemini/.ccg/prompts/codex/reviewer.md` | `~/.gemini/.ccg/prompts/gemini/reviewer.md` | **Session Reuse**: Each call returns `SESSION_ID: xxx`, use `resume xxx` subcommand for subsequent phases (note: `resume`, not `--resume`). diff --git a/commands/plan.toml b/commands/plan.toml index 4fde8c5..89b9206 100644 --- a/commands/plan.toml +++ b/commands/plan.toml @@ -108,5 +108,5 @@ After planning: ## Related Agents This command invokes the `planner` agent located at: -`~/.claude/agents/planner.md` +`~/.gemini/agents/planner.md` ''' diff --git a/commands/projects.toml b/commands/projects.toml index 26c52e7..dcc2f22 100644 --- a/commands/projects.toml +++ b/commands/projects.toml @@ -21,7 +21,7 @@ python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cl Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): ```bash -python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py projects +python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py projects ``` ## Usage @@ -32,7 +32,7 @@ python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py projects ## What to Do -1. Read `~/.claude/homunculus/projects.json` +1. Read `~/.gemini/homunculus/projects.json` 2. For each project, display: - Project name, id, root, remote - Personal and inherited instinct counts diff --git a/commands/promote.toml b/commands/promote.toml index f573ec7..5f7e7c9 100644 --- a/commands/promote.toml +++ b/commands/promote.toml @@ -21,7 +21,7 @@ python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cl Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): ```bash -python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py promote [instinct-id] [--force] [--dry-run] +python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py promote [instinct-id] [--force] [--dry-run] ``` ## Usage @@ -40,6 +40,6 @@ python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py promote 3. Otherwise, find cross-project candidates that: - Appear in at least 2 projects - Meet confidence threshold -4. Write promoted instincts to `~/.claude/homunculus/instincts/personal/` with `scope: global` +4. Write promoted instincts to `~/.gemini/homunculus/instincts/personal/` with `scope: global` ''' diff --git a/commands/prune.toml b/commands/prune.toml index 706442a..c08c7fa 100644 --- a/commands/prune.toml +++ b/commands/prune.toml @@ -21,7 +21,7 @@ python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cl Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): ```bash -python3 ~/.claude/skills/continuous-learning-v2/scripts/instinct-cli.py prune +python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py prune ``` ## Usage diff --git a/commands/resume-session.toml b/commands/resume-session.toml index 03b17ef..4e49f03 100644 --- a/commands/resume-session.toml +++ b/commands/resume-session.toml @@ -1,7 +1,7 @@ description = 'Resume Session Command' prompt = ''' --- -description: Load the most recent session file from ~/.claude/sessions/ and resume work with full context from where the last session ended. +description: Load the most recent session file from ~/.gemini/sessions/ and resume work with full context from where the last session ended. --- # Resume Session Command @@ -19,10 +19,10 @@ This command is the counterpart to `/save-session`. ## Usage ``` -/resume-session # loads most recent file in ~/.claude/sessions/ +/resume-session # loads most recent file in ~/.gemini/sessions/ /resume-session 2024-01-15 # loads most recent session for that date -/resume-session ~/.claude/sessions/2024-01-15-session.tmp # loads a specific legacy-format file -/resume-session ~/.claude/sessions/2024-01-15-abc123de-session.tmp # loads a current short-id session file +/resume-session ~/.gemini/sessions/2024-01-15-session.tmp # loads a specific legacy-format file +/resume-session ~/.gemini/sessions/2024-01-15-abc123de-session.tmp # loads a current short-id session file ``` ## Process @@ -31,18 +31,18 @@ This command is the counterpart to `/save-session`. If no argument provided: -1. Check `~/.claude/sessions/` +1. Check `~/.gemini/sessions/` 2. Pick the most recently modified `*-session.tmp` file 3. If the folder does not exist or has no matching files, tell the user: ``` - No session files found in ~/.claude/sessions/ + No session files found in ~/.gemini/sessions/ Run /save-session at the end of a session to create one. ``` Then stop. If an argument is provided: -- If it looks like a date (`YYYY-MM-DD`), search `~/.claude/sessions/` for files matching +- If it looks like a date (`YYYY-MM-DD`), search `~/.gemini/sessions/` for files matching `YYYY-MM-DD-session.tmp` (legacy format) or `YYYY-MM-DD--session.tmp` (current format) and load the most recently modified variant for that date - If it looks like a file path, read that file directly diff --git a/commands/save-session.toml b/commands/save-session.toml index aa14472..2c78ccc 100644 --- a/commands/save-session.toml +++ b/commands/save-session.toml @@ -1,7 +1,7 @@ description = 'Save Session Command' prompt = ''' --- -description: Save current session state to a dated file in ~/.claude/sessions/ so work can be resumed in a future session with full context. +description: Save current session state to a dated file in ~/.gemini/sessions/ so work can be resumed in a future session with full context. --- # Save Session Command @@ -31,12 +31,12 @@ Before writing the file, collect: Create the canonical sessions folder in the user's Claude home directory: ```bash -mkdir -p ~/.claude/sessions +mkdir -p ~/.gemini/sessions ``` ### Step 3: Write the session file -Create `~/.claude/sessions/YYYY-MM-DD--session.tmp`, using today's actual date and a short-id that satisfies the rules enforced by `SESSION_FILENAME_REGEX` in `session-manager.js`: +Create `~/.gemini/sessions/YYYY-MM-DD--session.tmp`, using today's actual date and a short-id that satisfies the rules enforced by `SESSION_FILENAME_REGEX` in `session-manager.js`: - Allowed characters: lowercase `a-z`, digits `0-9`, hyphens `-` - Minimum length: 8 characters @@ -273,7 +273,7 @@ Then test with Postman — the response should include a `Set-Cookie` header. - The "What Did NOT Work" section is the most critical — future sessions will blindly retry failed approaches without it - If the user asks to save mid-session (not just at the end), save what's known so far and mark in-progress items clearly - The file is meant to be read by Claude at the start of the next session via `/resume-session` -- Use the canonical global session store: `~/.claude/sessions/` +- Use the canonical global session store: `~/.gemini/sessions/` - Prefer the short-id filename form (`YYYY-MM-DD--session.tmp`) for any new session file ''' diff --git a/commands/sessions.toml b/commands/sessions.toml index 60d5900..0c83052 100644 --- a/commands/sessions.toml +++ b/commands/sessions.toml @@ -6,7 +6,7 @@ description: Manage Claude Code session history, aliases, and session metadata. # Sessions Command -Manage Claude Code session history - list, load, alias, and edit sessions stored in `~/.claude/sessions/`. +Manage Claude Code session history - list, load, alias, and edit sessions stored in `~/.gemini/sessions/`. ## Usage @@ -91,7 +91,7 @@ const size = sm.getSessionSize(session.sessionPath); const aliases = aa.getAliasesForSession(session.filename); console.log('Session: ' + session.filename); -console.log('Path: ~/.claude/sessions/' + session.filename); +console.log('Path: ~/.gemini/sessions/' + session.filename); console.log(''); console.log('Statistics:'); console.log(' Lines: ' + stats.lineCount); @@ -329,8 +329,8 @@ $ARGUMENTS: ## Notes -- Sessions are stored as markdown files in `~/.claude/sessions/` -- Aliases are stored in `~/.claude/session-aliases.json` +- Sessions are stored as markdown files in `~/.gemini/sessions/` +- Aliases are stored in `~/.gemini/session-aliases.json` - Session IDs can be shortened (first 4-8 characters usually unique enough) - Use aliases for frequently referenced sessions diff --git a/commands/setup-pm.toml b/commands/setup-pm.toml index fb559a1..766db66 100644 --- a/commands/setup-pm.toml +++ b/commands/setup-pm.toml @@ -28,14 +28,14 @@ When determining which package manager to use, the following order is checked: 2. **Project config**: `.claude/package-manager.json` 3. **package.json**: `packageManager` field 4. **Lock file**: Presence of package-lock.json, yarn.lock, pnpm-lock.yaml, or bun.lockb -5. **Global config**: `~/.claude/package-manager.json` +5. **Global config**: `~/.gemini/package-manager.json` 6. **Fallback**: First available package manager (pnpm > bun > yarn > npm) ## Configuration Files ### Global Configuration ```json -// ~/.claude/package-manager.json +// ~/.gemini/package-manager.json { "packageManager": "pnpm" } diff --git a/commands/tdd.toml b/commands/tdd.toml index 9431fc9..b18e4bf 100644 --- a/commands/tdd.toml +++ b/commands/tdd.toml @@ -318,8 +318,8 @@ Never skip the RED phase. Never write code before tests. ## Related Agents This command invokes the `tdd-guide` agent located at: -`~/.claude/agents/tdd-guide.md` +`~/.gemini/agents/tdd-guide.md` And can reference the `tdd-workflow` skill at: -`~/.claude/skills/tdd-workflow/` +`~/.gemini/skills/tdd-workflow/` ''' From 46a9fd4a1ad1a25c7ccfeaaaa509386e0458509c Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:37:21 +0900 Subject: [PATCH 09/25] chore: update file paths from ~/.claude/ to ~/.gemini/ across all skill documentation and scripts --- skills/autonomous-loops/SKILL.md | 2 +- skills/blueprint/SKILL.md | 2 +- skills/canary-watch/SKILL.md | 2 +- skills/rules-distill/SKILL.md | 4 ++-- skills/rules-distill/scripts/scan-rules.sh | 2 +- skills/rules-distill/scripts/scan-skills.sh | 2 +- skills/safety-guard/SKILL.md | 2 +- skills/search-first/SKILL.md | 4 ++-- skills/skill-comply/SKILL.md | 4 ++-- skills/skill-stocktake/SKILL.md | 22 ++++++++++---------- skills/skill-stocktake/scripts/quick-diff.sh | 2 +- skills/skill-stocktake/scripts/scan.sh | 2 +- skills/team-builder/SKILL.md | 2 +- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/skills/autonomous-loops/SKILL.md b/skills/autonomous-loops/SKILL.md index d6f4557..f4c6682 100644 --- a/skills/autonomous-loops/SKILL.md +++ b/skills/autonomous-loops/SKILL.md @@ -120,7 +120,7 @@ CLAW_SESSION=my-project CLAW_SKILLS=tdd-workflow,security-review node scripts/cl ### How It Works -1. Loads conversation history from `~/.claude/claw/{session}.md` +1. Loads conversation history from `~/.gemini/claw/{session}.md` 2. Each user message is sent to `claude -p` with full history as context 3. Responses are appended to the session file (Markdown-as-database) 4. Sessions persist across restarts diff --git a/skills/blueprint/SKILL.md b/skills/blueprint/SKILL.md index 1851c9a..eef1963 100644 --- a/skills/blueprint/SKILL.md +++ b/skills/blueprint/SKILL.md @@ -93,7 +93,7 @@ git checkout # pin to a specific reviewed commit ### Vendored standalone install -If you are vendoring only this skill outside the full ECC install, copy the reviewed file from the ECC repository into `~/.claude/skills/blueprint/SKILL.md`. Vendored copies do not have a git remote, so update them by re-copying the file from a reviewed ECC commit rather than running `git pull`. +If you are vendoring only this skill outside the full ECC install, copy the reviewed file from the ECC repository into `~/.gemini/skills/blueprint/SKILL.md`. Vendored copies do not have a git remote, so update them by re-copying the file from a reviewed ECC commit rather than running `git pull`. ## Requirements diff --git a/skills/canary-watch/SKILL.md b/skills/canary-watch/SKILL.md index 88ff5d6..1415e16 100644 --- a/skills/canary-watch/SKILL.md +++ b/skills/canary-watch/SKILL.md @@ -65,7 +65,7 @@ info: # log only When a critical threshold is crossed: - Desktop notification (macOS/Linux) - Optional: Slack/Discord webhook -- Log to `~/.claude/canary-watch.log` +- Log to `~/.gemini/canary-watch.log` ## Output diff --git a/skills/rules-distill/SKILL.md b/skills/rules-distill/SKILL.md index 8e50342..4fbd647 100644 --- a/skills/rules-distill/SKILL.md +++ b/skills/rules-distill/SKILL.md @@ -25,13 +25,13 @@ The rules distillation process follows three phases: #### 1a. Collect skill inventory ```bash -bash ~/.claude/skills/rules-distill/scripts/scan-skills.sh +bash ~/.gemini/skills/rules-distill/scripts/scan-skills.sh ``` #### 1b. Collect rules index ```bash -bash ~/.claude/skills/rules-distill/scripts/scan-rules.sh +bash ~/.gemini/skills/rules-distill/scripts/scan-rules.sh ``` #### 1c. Present to user diff --git a/skills/rules-distill/scripts/scan-rules.sh b/skills/rules-distill/scripts/scan-rules.sh index ff011bc..b00c361 100755 --- a/skills/rules-distill/scripts/scan-rules.sh +++ b/skills/rules-distill/scripts/scan-rules.sh @@ -4,7 +4,7 @@ # Output: JSON to stdout # # Environment: -# RULES_DISTILL_DIR Override ~/.claude/rules (for testing only) +# RULES_DISTILL_DIR Override ~/.gemini/rules (for testing only) set -euo pipefail diff --git a/skills/rules-distill/scripts/scan-skills.sh b/skills/rules-distill/scripts/scan-skills.sh index 1c49cd9..b1e3c93 100755 --- a/skills/rules-distill/scripts/scan-skills.sh +++ b/skills/rules-distill/scripts/scan-skills.sh @@ -7,7 +7,7 @@ # script always picks up project-level skills without relying on the caller. # # Environment: -# RULES_DISTILL_GLOBAL_DIR Override ~/.claude/skills (for testing only; +# RULES_DISTILL_GLOBAL_DIR Override ~/.gemini/skills (for testing only; # do not set in production — intended for bats tests) # RULES_DISTILL_PROJECT_DIR Override project dir detection (for testing only) diff --git a/skills/safety-guard/SKILL.md b/skills/safety-guard/SKILL.md index 6b347c0..817f45f 100644 --- a/skills/safety-guard/SKILL.md +++ b/skills/safety-guard/SKILL.md @@ -66,4 +66,4 @@ Uses PreToolUse hooks to intercept Bash, Write, Edit, and MultiEdit tool calls. - Enable by default for `codex -a never` sessions - Pair with observability risk scoring in ECC 2.0 -- Logs all blocked actions to `~/.claude/safety-guard.log` +- Logs all blocked actions to `~/.gemini/safety-guard.log` diff --git a/skills/search-first/SKILL.md b/skills/search-first/SKILL.md index 73dcedd..5e6ac1a 100644 --- a/skills/search-first/SKILL.md +++ b/skills/search-first/SKILL.md @@ -63,8 +63,8 @@ Before writing a utility or adding functionality, mentally run through: 0. Does this already exist in the repo? → `rg` through relevant modules/tests first 1. Is this a common problem? → Search npm/PyPI -2. Is there an MCP for this? → Check `~/.claude/settings.json` and search -3. Is there a skill for this? → Check `~/.claude/skills/` +2. Is there an MCP for this? → Check `~/.gemini/settings.json` and search +3. Is there a skill for this? → Check `~/.gemini/skills/` 4. Is there a GitHub implementation/template? → Run GitHub code search for maintained OSS before writing net-new code ### Full Mode (agent) diff --git a/skills/skill-comply/SKILL.md b/skills/skill-comply/SKILL.md index ea4b4a5..0995dc0 100644 --- a/skills/skill-comply/SKILL.md +++ b/skills/skill-comply/SKILL.md @@ -32,10 +32,10 @@ Measures whether coding agents actually follow skills, rules, or agent definitio ```bash # Full run -uv run python -m scripts.run ~/.claude/rules/common/testing.md +uv run python -m scripts.run ~/.gemini/rules/common/testing.md # Dry run (no cost, spec + scenarios only) -uv run python -m scripts.run --dry-run ~/.claude/skills/search-first/SKILL.md +uv run python -m scripts.run --dry-run ~/.gemini/skills/search-first/SKILL.md # Custom models uv run python -m scripts.run --gen-model haiku --model sonnet diff --git a/skills/skill-stocktake/SKILL.md b/skills/skill-stocktake/SKILL.md index 7ae77c2..306e5cb 100644 --- a/skills/skill-stocktake/SKILL.md +++ b/skills/skill-stocktake/SKILL.md @@ -13,7 +13,7 @@ The command targets the following paths **relative to the directory where it is | Path | Description | |------|-------------| -| `~/.claude/skills/` | Global skills (all projects) | +| `~/.gemini/skills/` | Global skills (all projects) | | `{cwd}/.claude/skills/` | Project-level skills (if the directory exists) | **At the start of Phase 1, the command explicitly lists which paths were found and scanned.** @@ -36,28 +36,28 @@ If the project has no `.claude/skills/` directory, only global skills and comman | Quick Scan | `results.json` exists (default) | 5–10 min | | Full Stocktake | `results.json` absent, or `/skill-stocktake full` | 20–30 min | -**Results cache:** `~/.claude/skills/skill-stocktake/results.json` +**Results cache:** `~/.gemini/skills/skill-stocktake/results.json` ## Quick Scan Flow Re-evaluate only skills that have changed since the last run (5–10 min). -1. Read `~/.claude/skills/skill-stocktake/results.json` -2. Run: `bash ~/.claude/skills/skill-stocktake/scripts/quick-diff.sh \ - ~/.claude/skills/skill-stocktake/results.json` +1. Read `~/.gemini/skills/skill-stocktake/results.json` +2. Run: `bash ~/.gemini/skills/skill-stocktake/scripts/quick-diff.sh \ + ~/.gemini/skills/skill-stocktake/results.json` (Project dir is auto-detected from `$PWD/.claude/skills`; pass it explicitly only if needed) 3. If output is `[]`: report "No changes since last run." and stop 4. Re-evaluate only those changed files using the same Phase 2 criteria 5. Carry forward unchanged skills from previous results 6. Output only the diff -7. Run: `bash ~/.claude/skills/skill-stocktake/scripts/save-results.sh \ - ~/.claude/skills/skill-stocktake/results.json <<< "$EVAL_RESULTS"` +7. Run: `bash ~/.gemini/skills/skill-stocktake/scripts/save-results.sh \ + ~/.gemini/skills/skill-stocktake/results.json <<< "$EVAL_RESULTS"` ## Full Stocktake Flow ### Phase 1 — Inventory -Run: `bash ~/.claude/skills/skill-stocktake/scripts/scan.sh` +Run: `bash ~/.gemini/skills/skill-stocktake/scripts/scan.sh` The script enumerates skill files, extracts frontmatter, and collects UTC mtimes. Project dir is auto-detected from `$PWD/.claude/skills`; pass it explicitly only if needed. @@ -65,7 +65,7 @@ Present the scan summary and inventory table from the script output: ``` Scanning: - ✓ ~/.claude/skills/ (17 files) + ✓ ~/.gemini/skills/ (17 files) ✗ {cwd}/.claude/skills/ (not found — global skills only) ``` @@ -161,7 +161,7 @@ Evaluation is **holistic AI judgment** — not a numeric rubric. Guiding dimensi ## Results File Schema -`~/.claude/skills/skill-stocktake/results.json`: +`~/.gemini/skills/skill-stocktake/results.json`: **`evaluated_at`**: Must be set to the actual UTC time of evaluation completion. Obtain via Bash: `date -u +%Y-%m-%dT%H:%M:%SZ`. Never use a date-only approximation like `T00:00:00Z`. @@ -177,7 +177,7 @@ Obtain via Bash: `date -u +%Y-%m-%dT%H:%M:%SZ`. Never use a date-only approximat }, "skills": { "skill-name": { - "path": "~/.claude/skills/skill-name/SKILL.md", + "path": "~/.gemini/skills/skill-name/SKILL.md", "verdict": "Keep", "reason": "Concrete, actionable, unique value for X workflow", "mtime": "2026-01-15T08:30:00Z" diff --git a/skills/skill-stocktake/scripts/quick-diff.sh b/skills/skill-stocktake/scripts/quick-diff.sh index c145100..a63ad93 100755 --- a/skills/skill-stocktake/scripts/quick-diff.sh +++ b/skills/skill-stocktake/scripts/quick-diff.sh @@ -7,7 +7,7 @@ # script always picks up project-level skills without relying on the caller. # # Environment: -# SKILL_STOCKTAKE_GLOBAL_DIR Override ~/.claude/skills (for testing only; +# SKILL_STOCKTAKE_GLOBAL_DIR Override ~/.gemini/skills (for testing only; # do not set in production — intended for bats tests) # SKILL_STOCKTAKE_PROJECT_DIR Override project dir detection (for testing only) diff --git a/skills/skill-stocktake/scripts/scan.sh b/skills/skill-stocktake/scripts/scan.sh index 5f1d12d..428efa5 100755 --- a/skills/skill-stocktake/scripts/scan.sh +++ b/skills/skill-stocktake/scripts/scan.sh @@ -7,7 +7,7 @@ # script always picks up project-level skills without relying on the caller. # # Environment: -# SKILL_STOCKTAKE_GLOBAL_DIR Override ~/.claude/skills (for testing only; +# SKILL_STOCKTAKE_GLOBAL_DIR Override ~/.gemini/skills (for testing only; # do not set in production — intended for bats tests) # SKILL_STOCKTAKE_PROJECT_DIR Override project dir detection (for testing only) diff --git a/skills/team-builder/SKILL.md b/skills/team-builder/SKILL.md index 811a6e2..a0635c0 100644 --- a/skills/team-builder/SKILL.md +++ b/skills/team-builder/SKILL.md @@ -50,7 +50,7 @@ agents/ Agent directories are probed in order and results are merged: 1. `./agents/**/*.md` + `./agents/*.md` — project-local agents (both depths) -2. `~/.claude/agents/**/*.md` + `~/.claude/agents/*.md` — global agents (both depths) +2. `~/.gemini/agents/**/*.md` + `~/.gemini/agents/*.md` — global agents (both depths) Results from all locations are merged and deduplicated by agent name. Project-local agents take precedence over global agents with the same name. A custom path can be used instead if the user specifies one. From 211a28bf9499b4daf508b487996eb9262bc7279b Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:38:22 +0900 Subject: [PATCH 10/25] feat: add descriptive summaries to command configuration files --- commands/checkpoint.toml | 2 +- commands/code-review.toml | 2 +- commands/eval.toml | 2 +- commands/learn.toml | 2 +- commands/pm2.toml | 2 +- commands/verify.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/commands/checkpoint.toml b/commands/checkpoint.toml index 08ca2a7..34eefa2 100644 --- a/commands/checkpoint.toml +++ b/commands/checkpoint.toml @@ -1,4 +1,4 @@ -description = "" +description = "Create or verify a workflow checkpoint" prompt = ''' # Checkpoint Command diff --git a/commands/code-review.toml b/commands/code-review.toml index 9a3ce01..a607fe3 100644 --- a/commands/code-review.toml +++ b/commands/code-review.toml @@ -1,4 +1,4 @@ -description = "" +description = "Run security and quality review on uncommitted changes" prompt = ''' # Code Review diff --git a/commands/eval.toml b/commands/eval.toml index f5adaac..394ac9e 100644 --- a/commands/eval.toml +++ b/commands/eval.toml @@ -1,4 +1,4 @@ -description = "" +description = "Manage eval-driven development workflow" prompt = ''' # Eval Command diff --git a/commands/learn.toml b/commands/learn.toml index 81d9821..27d3a80 100644 --- a/commands/learn.toml +++ b/commands/learn.toml @@ -1,4 +1,4 @@ -description = "" +description = "Extract reusable patterns from the current session" prompt = ''' # /learn - Extract Reusable Patterns diff --git a/commands/pm2.toml b/commands/pm2.toml index f2ef492..bbf99c5 100644 --- a/commands/pm2.toml +++ b/commands/pm2.toml @@ -1,4 +1,4 @@ -description = "" +description = "Auto-analyze project and generate PM2 service commands" prompt = ''' # PM2 Init diff --git a/commands/verify.toml b/commands/verify.toml index 6e093d0..4ba2854 100644 --- a/commands/verify.toml +++ b/commands/verify.toml @@ -1,4 +1,4 @@ -description = "" +description = "Run comprehensive verification on the codebase" prompt = ''' # Verification Command From 6e07967f4d34f761c00508333953e619f5fbec0e Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:41:49 +0900 Subject: [PATCH 11/25] refactor: rename CLAUDE_PLUGIN_ROOT to GEMINI_EXTENSION_ROOT across documentation and scripts --- commands/evolve.toml | 4 ++-- commands/instinct-import.toml | 4 ++-- commands/instinct-status.toml | 4 ++-- commands/projects.toml | 4 ++-- commands/promote.toml | 4 ++-- commands/prune.toml | 4 ++-- commands/sessions.toml | 20 +++++++++---------- commands/skill-health.toml | 6 +++--- skills/continuous-learning-v2/SKILL.md | 4 ++-- .../continuous-learning-v2/hooks/observe.sh | 6 +++--- workflows/evolve.md | 4 ++-- workflows/instinct-import.md | 4 ++-- workflows/instinct-status.md | 4 ++-- 13 files changed, 36 insertions(+), 36 deletions(-) diff --git a/commands/evolve.toml b/commands/evolve.toml index 6a9435b..ff3e5ac 100644 --- a/commands/evolve.toml +++ b/commands/evolve.toml @@ -7,10 +7,10 @@ prompt = ''' Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" evolve [--generate] +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" evolve [--generate] ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation): ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py evolve [--generate] diff --git a/commands/instinct-import.toml b/commands/instinct-import.toml index 87fdb7a..f3379b4 100644 --- a/commands/instinct-import.toml +++ b/commands/instinct-import.toml @@ -7,10 +7,10 @@ prompt = ''' Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" import [--dry-run] [--force] [--min-confidence 0.7] +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" import [--dry-run] [--force] [--min-confidence 0.7] ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation): ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py import diff --git a/commands/instinct-status.toml b/commands/instinct-status.toml index c1f3277..20ba3e9 100644 --- a/commands/instinct-status.toml +++ b/commands/instinct-status.toml @@ -9,10 +9,10 @@ Shows all learned instincts with their confidence scores, grouped by domain. Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" status +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" status ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation), use: +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation), use: ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py status diff --git a/commands/projects.toml b/commands/projects.toml index dcc2f22..e718a9a 100644 --- a/commands/projects.toml +++ b/commands/projects.toml @@ -15,10 +15,10 @@ List project registry entries and per-project instinct/observation counts for co Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" projects +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" projects ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation): ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py projects diff --git a/commands/promote.toml b/commands/promote.toml index 5f7e7c9..87de26e 100644 --- a/commands/promote.toml +++ b/commands/promote.toml @@ -15,10 +15,10 @@ Promote instincts from project scope to global scope in continuous-learning-v2. Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" promote [instinct-id] [--force] [--dry-run] +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" promote [instinct-id] [--force] [--dry-run] ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation): ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py promote [instinct-id] [--force] [--dry-run] diff --git a/commands/prune.toml b/commands/prune.toml index c08c7fa..452e864 100644 --- a/commands/prune.toml +++ b/commands/prune.toml @@ -15,10 +15,10 @@ Remove expired pending instincts that were auto-generated but never reviewed or Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" prune +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" prune ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation): ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py prune diff --git a/commands/sessions.toml b/commands/sessions.toml index 0c83052..a496024 100644 --- a/commands/sessions.toml +++ b/commands/sessions.toml @@ -31,8 +31,8 @@ Use `/sessions info` when you need operator-surface context for a swarm: branch, **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const path = require('path'); const result = sm.getAllSessions({ limit: 20 }); @@ -72,8 +72,8 @@ Load and display a session's content (by ID or alias). **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const id = process.argv[1]; // First try to resolve as alias @@ -145,8 +145,8 @@ Create a memorable alias for a session. **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const sessionId = process.argv[1]; const aliasName = process.argv[2]; @@ -185,7 +185,7 @@ Delete an existing alias. **Script:** ```bash node -e " -const aa = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const aliasName = process.argv[1]; if (!aliasName) { @@ -214,8 +214,8 @@ Show detailed information about a session. **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const id = process.argv[1]; const resolved = aa.resolveAlias(id); @@ -264,7 +264,7 @@ Show all session aliases. **Script:** ```bash node -e " -const aa = require((()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const aliases = aa.listAliases(); console.log('Session Aliases (' + aliases.length + '):'); diff --git a/commands/skill-health.toml b/commands/skill-health.toml index 3651427..12653fe 100644 --- a/commands/skill-health.toml +++ b/commands/skill-health.toml @@ -15,21 +15,21 @@ Shows a comprehensive health dashboard for all skills in the portfolio with succ Run the skill health CLI in dashboard mode: ```bash -ECC_ROOT="${CLAUDE_PLUGIN_ROOT:-$(node -e "var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(!f.existsSync(p.join(d,q))){try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q))){d=c;break}}}catch(x){}}console.log(d)")}" +ECC_ROOT="${GEMINI_EXTENSION_ROOT:-$(node -e "var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(!f.existsSync(p.join(d,q))){try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q))){d=c;break}}}catch(x){}}console.log(d)")}" node "$ECC_ROOT/scripts/skills-health.js" --dashboard ``` For a specific panel only: ```bash -ECC_ROOT="${CLAUDE_PLUGIN_ROOT:-$(node -e "var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(!f.existsSync(p.join(d,q))){try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q))){d=c;break}}}catch(x){}}console.log(d)")}" +ECC_ROOT="${GEMINI_EXTENSION_ROOT:-$(node -e "var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(!f.existsSync(p.join(d,q))){try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q))){d=c;break}}}catch(x){}}console.log(d)")}" node "$ECC_ROOT/scripts/skills-health.js" --dashboard --panel failures ``` For machine-readable output: ```bash -ECC_ROOT="${CLAUDE_PLUGIN_ROOT:-$(node -e "var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(!f.existsSync(p.join(d,q))){try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q))){d=c;break}}}catch(x){}}console.log(d)")}" +ECC_ROOT="${GEMINI_EXTENSION_ROOT:-$(node -e "var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(!f.existsSync(p.join(d,q))){try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q))){d=c;break}}}catch(x){}}console.log(d)")}" node "$ECC_ROOT/scripts/skills-health.js" --dashboard --json ``` diff --git a/skills/continuous-learning-v2/SKILL.md b/skills/continuous-learning-v2/SKILL.md index 588253c..9d89f14 100644 --- a/skills/continuous-learning-v2/SKILL.md +++ b/skills/continuous-learning-v2/SKILL.md @@ -103,14 +103,14 @@ Add to your `~/.gemini/settings.json`. "matcher": "*", "hooks": [{ "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/hooks/observe.sh pre" + "command": "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/hooks/observe.sh pre" }] }], "PostToolUse": [{ "matcher": "*", "hooks": [{ "type": "command", - "command": "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/hooks/observe.sh post" + "command": "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/hooks/observe.sh post" }] }] } diff --git a/skills/continuous-learning-v2/hooks/observe.sh b/skills/continuous-learning-v2/hooks/observe.sh index 849f58e..b0d2be3 100755 --- a/skills/continuous-learning-v2/hooks/observe.sh +++ b/skills/continuous-learning-v2/hooks/observe.sh @@ -6,16 +6,16 @@ # # Hook config (in ~/.gemini/settings.json): # -# If installed as a plugin, use ${CLAUDE_PLUGIN_ROOT}: +# If installed as a plugin, use ${GEMINI_EXTENSION_ROOT}: # { # "hooks": { # "PreToolUse": [{ # "matcher": "*", -# "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/hooks/observe.sh pre" }] +# "hooks": [{ "type": "command", "command": "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/hooks/observe.sh pre" }] # }], # "PostToolUse": [{ # "matcher": "*", -# "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/hooks/observe.sh post" }] +# "hooks": [{ "type": "command", "command": "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/hooks/observe.sh post" }] # }] # } # } diff --git a/workflows/evolve.md b/workflows/evolve.md index 515a1be..28db3c6 100644 --- a/workflows/evolve.md +++ b/workflows/evolve.md @@ -11,10 +11,10 @@ command: true Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" evolve [--generate] +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" evolve [--generate] ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation): ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py evolve [--generate] diff --git a/workflows/instinct-import.md b/workflows/instinct-import.md index c707b67..6189d66 100644 --- a/workflows/instinct-import.md +++ b/workflows/instinct-import.md @@ -11,10 +11,10 @@ command: true Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" import [--dry-run] [--force] [--min-confidence 0.7] +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" import [--dry-run] [--force] [--min-confidence 0.7] ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation): +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation): ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py import diff --git a/workflows/instinct-status.md b/workflows/instinct-status.md index 6b03388..9427553 100644 --- a/workflows/instinct-status.md +++ b/workflows/instinct-status.md @@ -13,10 +13,10 @@ Shows all learned instincts with their confidence scores, grouped by domain. Run the instinct CLI using the plugin root path: ```bash -python3 "${CLAUDE_PLUGIN_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" status +python3 "${GEMINI_EXTENSION_ROOT}/skills/continuous-learning-v2/scripts/instinct-cli.py" status ``` -Or if `CLAUDE_PLUGIN_ROOT` is not set (manual installation), use: +Or if `GEMINI_EXTENSION_ROOT` is not set (manual installation), use: ```bash python3 ~/.gemini/skills/continuous-learning-v2/scripts/instinct-cli.py status From 5a884ae8d7aaf218c4d55a5499d7e508327be1ac Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:42:17 +0900 Subject: [PATCH 12/25] refactor: rename Claude references to Gemini and update session path configuration in sessions.toml --- commands/sessions.toml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/commands/sessions.toml b/commands/sessions.toml index a496024..5d95166 100644 --- a/commands/sessions.toml +++ b/commands/sessions.toml @@ -1,12 +1,12 @@ description = 'Sessions Command' prompt = ''' --- -description: Manage Claude Code session history, aliases, and session metadata. +description: Manage Gemini Code session history, aliases, and session metadata. --- # Sessions Command -Manage Claude Code session history - list, load, alias, and edit sessions stored in `~/.gemini/sessions/`. +Manage Gemini Code session history - list, load, alias, and edit sessions stored in `~/.gemini/sessions/`. ## Usage @@ -31,8 +31,8 @@ Use `/sessions info` when you need operator-surface context for a swarm: branch, **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const path = require('path'); const result = sm.getAllSessions({ limit: 20 }); @@ -72,8 +72,8 @@ Load and display a session's content (by ID or alias). **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const id = process.argv[1]; // First try to resolve as alias @@ -145,8 +145,8 @@ Create a memorable alias for a session. **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const sessionId = process.argv[1]; const aliasName = process.argv[2]; @@ -185,7 +185,7 @@ Delete an existing alias. **Script:** ```bash node -e " -const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const aliasName = process.argv[1]; if (!aliasName) { @@ -214,8 +214,8 @@ Show detailed information about a session. **Script:** ```bash node -e " -const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); -const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const sm = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-manager'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const id = process.argv[1]; const resolved = aa.resolveAlias(id); @@ -264,7 +264,7 @@ Show all session aliases. **Script:** ```bash node -e " -const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-claude-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); +const aa = require((()=>{var e=process.env.GEMINI_EXTENSION_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.gemini'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;try{var b=p.join(d,'plugins','cache','everything-gemini-code');for(var o of f.readdirSync(b))for(var v of f.readdirSync(p.join(b,o))){var c=p.join(b,o,v);if(f.existsSync(p.join(c,q)))return c}}catch(x){}return d})()+'/scripts/lib/session-aliases'); const aliases = aa.listAliases(); console.log('Session Aliases (' + aliases.length + '):'); From 54d4372850b9064246fe61958c26b8f985b5b900 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:47:34 +0900 Subject: [PATCH 13/25] chore: update project homepage URLs to the new repository location --- commands/skill-create.toml | 2 +- skills/carrier-relationship-management/SKILL.md | 2 +- skills/customs-trade-compliance/SKILL.md | 2 +- skills/energy-procurement/SKILL.md | 2 +- skills/inventory-demand-planning/SKILL.md | 2 +- skills/logistics-exception-management/SKILL.md | 2 +- skills/production-scheduling/SKILL.md | 2 +- skills/quality-nonconformance/SKILL.md | 2 +- skills/returns-reverse-logistics/SKILL.md | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/commands/skill-create.toml b/commands/skill-create.toml index 54125c5..3b30a6a 100644 --- a/commands/skill-create.toml +++ b/commands/skill-create.toml @@ -167,5 +167,5 @@ For advanced features (10k+ commits, team sharing, auto-PRs), use the [Skill Cre --- -*Part of [Everything Claude Code](https://github.com/affaan-m/everything-claude-code)* +*Part of [Everything Claude Code](https://github.com/Jamkris/everything-gemini-code)* ''' diff --git a/skills/carrier-relationship-management/SKILL.md b/skills/carrier-relationship-management/SKILL.md index 3921011..11be22c 100644 --- a/skills/carrier-relationship-management/SKILL.md +++ b/skills/carrier-relationship-management/SKILL.md @@ -9,7 +9,7 @@ description: > carrier performance, or building freight strategies. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos diff --git a/skills/customs-trade-compliance/SKILL.md b/skills/customs-trade-compliance/SKILL.md index 59fde68..96a62e7 100644 --- a/skills/customs-trade-compliance/SKILL.md +++ b/skills/customs-trade-compliance/SKILL.md @@ -10,7 +10,7 @@ description: > duty optimization. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos diff --git a/skills/energy-procurement/SKILL.md b/skills/energy-procurement/SKILL.md index d553121..7e5afc7 100644 --- a/skills/energy-procurement/SKILL.md +++ b/skills/energy-procurement/SKILL.md @@ -10,7 +10,7 @@ description: > demand charges, evaluating PPAs, or developing energy strategies. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos diff --git a/skills/inventory-demand-planning/SKILL.md b/skills/inventory-demand-planning/SKILL.md index fcc33ec..a640709 100644 --- a/skills/inventory-demand-planning/SKILL.md +++ b/skills/inventory-demand-planning/SKILL.md @@ -10,7 +10,7 @@ description: > managing promotions, or optimizing inventory levels. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos diff --git a/skills/logistics-exception-management/SKILL.md b/skills/logistics-exception-management/SKILL.md index a1e29ec..036ad2f 100644 --- a/skills/logistics-exception-management/SKILL.md +++ b/skills/logistics-exception-management/SKILL.md @@ -9,7 +9,7 @@ description: > or carrier disputes. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos diff --git a/skills/production-scheduling/SKILL.md b/skills/production-scheduling/SKILL.md index dbfcf24..79910ce 100644 --- a/skills/production-scheduling/SKILL.md +++ b/skills/production-scheduling/SKILL.md @@ -10,7 +10,7 @@ description: > or balancing manufacturing lines. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos diff --git a/skills/quality-nonconformance/SKILL.md b/skills/quality-nonconformance/SKILL.md index 77f3d80..1cecc77 100644 --- a/skills/quality-nonconformance/SKILL.md +++ b/skills/quality-nonconformance/SKILL.md @@ -10,7 +10,7 @@ description: > managing CAPAs, interpreting SPC data, or handling supplier quality issues. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos diff --git a/skills/returns-reverse-logistics/SKILL.md b/skills/returns-reverse-logistics/SKILL.md index e6bccb1..d421096 100644 --- a/skills/returns-reverse-logistics/SKILL.md +++ b/skills/returns-reverse-logistics/SKILL.md @@ -10,7 +10,7 @@ description: > detection, or warranty claims. license: Apache-2.0 version: 1.0.0 -homepage: https://github.com/affaan-m/everything-claude-code +homepage: https://github.com/Jamkris/everything-gemini-code origin: ECC metadata: author: evos From 4c6362d777bad65399bf504785ff3cff381555b0 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:48:16 +0900 Subject: [PATCH 14/25] chore: update project references from Everything Claude Code to Everything Gemini Code --- commands/skill-create.toml | 2 +- skills/blueprint/SKILL.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/skill-create.toml b/commands/skill-create.toml index 3b30a6a..3c5fa9f 100644 --- a/commands/skill-create.toml +++ b/commands/skill-create.toml @@ -167,5 +167,5 @@ For advanced features (10k+ commits, team sharing, auto-PRs), use the [Skill Cre --- -*Part of [Everything Claude Code](https://github.com/Jamkris/everything-gemini-code)* +*Part of [Everything Gemini Code](https://github.com/Jamkris/everything-gemini-code)* ''' diff --git a/skills/blueprint/SKILL.md b/skills/blueprint/SKILL.md index eef1963..7b68f61 100644 --- a/skills/blueprint/SKILL.md +++ b/skills/blueprint/SKILL.md @@ -85,7 +85,7 @@ test -f skills/blueprint/SKILL.md To update later, review the ECC diff before updating: ```bash -cd /path/to/everything-claude-code +cd /path/to/everything-gemini-code git fetch origin main git log --oneline HEAD..origin/main # review new commits before updating git checkout # pin to a specific reviewed commit From a9d26562b6ce6af417668e59a19b94c16b2135f3 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:55:28 +0900 Subject: [PATCH 15/25] refactor: introduce shared validation library and migrate CI scripts to use standardized validation helpers --- scripts/ci/validate-agents.js | 62 +++---------- scripts/ci/validate-commands.js | 43 +++------ scripts/ci/validate-hooks.js | 157 +++++++++++++------------------- scripts/ci/validate-skills.js | 46 ++-------- scripts/lib/validator.js | 156 +++++++++++++++++++++++++++++++ 5 files changed, 253 insertions(+), 211 deletions(-) create mode 100644 scripts/lib/validator.js diff --git a/scripts/ci/validate-agents.js b/scripts/ci/validate-agents.js index 65af5ed..fa2bb49 100644 --- a/scripts/ci/validate-agents.js +++ b/scripts/ci/validate-agents.js @@ -3,65 +3,25 @@ * Validate agent markdown files have required frontmatter */ -const fs = require('fs'); const path = require('path'); +const { extractFrontmatter, validateFiles } = require('../lib/validator'); -const AGENTS_DIR = path.join(__dirname, '../../agents'); const REQUIRED_FIELDS = ['tools']; -function extractFrontmatter(content) { - // Strip BOM if present (UTF-8 BOM: \uFEFF) - const cleanContent = content.replace(/^\uFEFF/, ''); - // Support both LF and CRLF line endings - const match = cleanContent.match(/^---\r?\n([\s\S]*?)\r?\n---/); - if (!match) return null; - - const frontmatter = {}; - const lines = match[1].split('\n'); - for (const line of lines) { - const colonIdx = line.indexOf(':'); - if (colonIdx > 0) { - const key = line.slice(0, colonIdx).trim(); - const value = line.slice(colonIdx + 1).trim(); - frontmatter[key] = value; - } - } - return frontmatter; -} - -function validateAgents() { - if (!fs.existsSync(AGENTS_DIR)) { - console.log('No agents directory found, skipping validation'); - process.exit(0); - } - - const files = fs.readdirSync(AGENTS_DIR).filter(f => f.endsWith('.md')); - let hasErrors = false; - - for (const file of files) { - const filePath = path.join(AGENTS_DIR, file); - const content = fs.readFileSync(filePath, 'utf-8'); +validateFiles({ + dir: path.join(__dirname, '../../agents'), + label: 'agent', + extension: '.md', + validate(content) { const frontmatter = extractFrontmatter(content); + if (!frontmatter) return ['Missing frontmatter']; - if (!frontmatter) { - console.error(`ERROR: ${file} - Missing frontmatter`); - hasErrors = true; - continue; - } - + const errors = []; for (const field of REQUIRED_FIELDS) { if (!frontmatter[field]) { - console.error(`ERROR: ${file} - Missing required field: ${field}`); - hasErrors = true; + errors.push(`Missing required field: ${field}`); } } + return errors.length > 0 ? errors : null; } - - if (hasErrors) { - process.exit(1); - } - - console.log(`Validated ${files.length} agent files`); -} - -validateAgents(); +}); diff --git a/scripts/ci/validate-commands.js b/scripts/ci/validate-commands.js index 640e4ad..bf9789f 100644 --- a/scripts/ci/validate-commands.js +++ b/scripts/ci/validate-commands.js @@ -1,38 +1,17 @@ #!/usr/bin/env node /** - * Validate command markdown files are non-empty and readable + * Validate command files are non-empty and readable */ -const fs = require('fs'); const path = require('path'); - -const COMMANDS_DIR = path.join(__dirname, '../../commands'); - -function validateCommands() { - if (!fs.existsSync(COMMANDS_DIR)) { - console.log('No commands directory found, skipping validation'); - process.exit(0); - } - - const files = fs.readdirSync(COMMANDS_DIR).filter(f => f.endsWith('.md')); - let hasErrors = false; - - for (const file of files) { - const filePath = path.join(COMMANDS_DIR, file); - const content = fs.readFileSync(filePath, 'utf-8'); - - // Validate the file is non-empty readable markdown - if (content.trim().length === 0) { - console.error(`ERROR: ${file} - Empty command file`); - hasErrors = true; - } - } - - if (hasErrors) { - process.exit(1); +const { validateFiles } = require('../lib/validator'); + +validateFiles({ + dir: path.join(__dirname, '../../commands'), + label: 'command', + extension: '.toml', + validate(content) { + if (content.trim().length === 0) return ['Empty command file']; + return null; } - - console.log(`Validated ${files.length} command files`); -} - -validateCommands(); +}); diff --git a/scripts/ci/validate-hooks.js b/scripts/ci/validate-hooks.js index 97d761a..b2be5df 100644 --- a/scripts/ci/validate-hooks.js +++ b/scripts/ci/validate-hooks.js @@ -3,114 +3,87 @@ * Validate hooks.json schema */ -const fs = require('fs'); const path = require('path'); +const { validateJsonFile } = require('../lib/validator'); -const HOOKS_FILE = path.join(__dirname, '../../hooks/hooks.json'); -const VALID_EVENTS = ['BeforeTool', 'AfterTool', 'BeforeAgent', 'AfterAgent', 'BeforeModel', 'AfterModel', 'SessionStart', 'SessionEnd', 'PreCompress']; +const VALID_EVENTS = [ + 'BeforeTool', 'AfterTool', 'BeforeAgent', 'AfterAgent', + 'BeforeModel', 'AfterModel', 'SessionStart', 'SessionEnd', 'PreCompress' +]; -function validateHooks() { - if (!fs.existsSync(HOOKS_FILE)) { - console.log('No hooks.json found, skipping validation'); - process.exit(0); +function validateHookEntry(hook, prefix) { + const errors = []; + if (!hook.type || typeof hook.type !== 'string') { + errors.push(`${prefix} missing or invalid 'type' field`); } - - let data; - try { - data = JSON.parse(fs.readFileSync(HOOKS_FILE, 'utf-8')); - } catch (e) { - console.error(`ERROR: Invalid JSON in hooks.json: ${e.message}`); - process.exit(1); + if (!hook.command || (typeof hook.command !== 'string' && !Array.isArray(hook.command))) { + errors.push(`${prefix} missing or invalid 'command' field`); } + return errors; +} - // Support both object format { hooks: {...} } and array format - const hooks = data.hooks || data; - let hasErrors = false; - let totalMatchers = 0; - - if (typeof hooks === 'object' && !Array.isArray(hooks)) { - // Object format: { EventType: [matchers] } - for (const [eventType, matchers] of Object.entries(hooks)) { - if (!VALID_EVENTS.includes(eventType)) { - console.error(`ERROR: Invalid event type: ${eventType}`); - hasErrors = true; - continue; +function validateMatchers(matchers, eventType) { + const errors = []; + for (let i = 0; i < matchers.length; i++) { + const matcher = matchers[i]; + if (typeof matcher !== 'object' || matcher === null) { + errors.push(`${eventType}[${i}] is not an object`); + continue; + } + if (!matcher.matcher) { + errors.push(`${eventType}[${i}] missing 'matcher' field`); + } + if (!matcher.hooks || !Array.isArray(matcher.hooks)) { + errors.push(`${eventType}[${i}] missing 'hooks' array`); + } else { + for (let j = 0; j < matcher.hooks.length; j++) { + errors.push(...validateHookEntry(matcher.hooks[j], `${eventType}[${i}].hooks[${j}]`)); } + } + } + return errors; +} - if (!Array.isArray(matchers)) { - console.error(`ERROR: ${eventType} must be an array`); - hasErrors = true; - continue; - } +validateJsonFile({ + file: path.join(__dirname, '../../hooks/hooks.json'), + label: 'hook matchers', + validate(data) { + const hooks = data.hooks || data; + const errors = []; + let count = 0; - for (let i = 0; i < matchers.length; i++) { - const matcher = matchers[i]; - if (typeof matcher !== 'object' || matcher === null) { - console.error(`ERROR: ${eventType}[${i}] is not an object`); - hasErrors = true; + if (typeof hooks === 'object' && !Array.isArray(hooks)) { + for (const [eventType, matchers] of Object.entries(hooks)) { + if (!VALID_EVENTS.includes(eventType)) { + errors.push(`Invalid event type: ${eventType}`); continue; } - if (!matcher.matcher) { - console.error(`ERROR: ${eventType}[${i}] missing 'matcher' field`); - hasErrors = true; - } - if (!matcher.hooks || !Array.isArray(matcher.hooks)) { - console.error(`ERROR: ${eventType}[${i}] missing 'hooks' array`); - hasErrors = true; - } else { - // Validate each hook entry - for (let j = 0; j < matcher.hooks.length; j++) { - const hook = matcher.hooks[j]; - if (!hook.type || typeof hook.type !== 'string') { - console.error(`ERROR: ${eventType}[${i}].hooks[${j}] missing or invalid 'type' field`); - hasErrors = true; - } - if (!hook.command || (typeof hook.command !== 'string' && !Array.isArray(hook.command))) { - console.error(`ERROR: ${eventType}[${i}].hooks[${j}] missing or invalid 'command' field`); - hasErrors = true; - } - } + if (!Array.isArray(matchers)) { + errors.push(`${eventType} must be an array`); + continue; } - totalMatchers++; - } - } - } else if (Array.isArray(hooks)) { - // Array format (legacy) - for (let i = 0; i < hooks.length; i++) { - const hook = hooks[i]; - if (!hook.matcher) { - console.error(`ERROR: Hook ${i} missing 'matcher' field`); - hasErrors = true; + errors.push(...validateMatchers(matchers, eventType)); + count += matchers.length; } - if (!hook.hooks || !Array.isArray(hook.hooks)) { - console.error(`ERROR: Hook ${i} missing 'hooks' array`); - hasErrors = true; - } else { - // Validate each hook entry - for (let j = 0; j < hook.hooks.length; j++) { - const h = hook.hooks[j]; - if (!h.type || typeof h.type !== 'string') { - console.error(`ERROR: Hook ${i}.hooks[${j}] missing or invalid 'type' field`); - hasErrors = true; - } - if (!h.command || (typeof h.command !== 'string' && !Array.isArray(h.command))) { - console.error(`ERROR: Hook ${i}.hooks[${j}] missing or invalid 'command' field`); - hasErrors = true; + } else if (Array.isArray(hooks)) { + for (let i = 0; i < hooks.length; i++) { + const hook = hooks[i]; + if (!hook.matcher) { + errors.push(`Hook ${i} missing 'matcher' field`); + } + if (!hook.hooks || !Array.isArray(hook.hooks)) { + errors.push(`Hook ${i} missing 'hooks' array`); + } else { + for (let j = 0; j < hook.hooks.length; j++) { + errors.push(...validateHookEntry(hook.hooks[j], `Hook ${i}.hooks[${j}]`)); } } + count++; } - totalMatchers++; + } else { + errors.push('hooks.json must be an object or array'); } - } else { - console.error('ERROR: hooks.json must be an object or array'); - process.exit(1); - } - if (hasErrors) { - process.exit(1); + return { errors, count }; } - - console.log(`Validated ${totalMatchers} hook matchers`); -} - -validateHooks(); +}); diff --git a/scripts/ci/validate-skills.js b/scripts/ci/validate-skills.js index 632bd31..066045d 100644 --- a/scripts/ci/validate-skills.js +++ b/scripts/ci/validate-skills.js @@ -5,43 +5,17 @@ const fs = require('fs'); const path = require('path'); +const { validateDirs } = require('../lib/validator'); -const SKILLS_DIR = path.join(__dirname, '../../skills'); - -function validateSkills() { - if (!fs.existsSync(SKILLS_DIR)) { - console.log('No skills directory found, skipping validation'); - process.exit(0); - } - - const entries = fs.readdirSync(SKILLS_DIR, { withFileTypes: true }); - const dirs = entries.filter(e => e.isDirectory()).map(e => e.name); - let hasErrors = false; - let validCount = 0; - - for (const dir of dirs) { - const skillMd = path.join(SKILLS_DIR, dir, 'SKILL.md'); - if (!fs.existsSync(skillMd)) { - console.error(`ERROR: ${dir}/ - Missing SKILL.md`); - hasErrors = true; - continue; - } +validateDirs({ + dir: path.join(__dirname, '../../skills'), + label: 'skill', + validate(dirPath) { + const skillMd = path.join(dirPath, 'SKILL.md'); + if (!fs.existsSync(skillMd)) return ['Missing SKILL.md']; const content = fs.readFileSync(skillMd, 'utf-8'); - if (content.trim().length === 0) { - console.error(`ERROR: ${dir}/SKILL.md - Empty file`); - hasErrors = true; - continue; - } - - validCount++; + if (content.trim().length === 0) return ['SKILL.md is empty']; + return null; } - - if (hasErrors) { - process.exit(1); - } - - console.log(`Validated ${validCount} skill directories`); -} - -validateSkills(); +}); diff --git a/scripts/lib/validator.js b/scripts/lib/validator.js new file mode 100644 index 0000000..08b44fd --- /dev/null +++ b/scripts/lib/validator.js @@ -0,0 +1,156 @@ +#!/usr/bin/env node +/** + * Common validation framework for CI scripts + * + * Provides a reusable pattern for validating project components + * (agents, commands, skills, hooks) with consistent error handling and reporting. + */ + +const fs = require('fs'); +const path = require('path'); + +/** + * Extract YAML frontmatter from markdown content + * Handles BOM and CRLF line endings + * @param {string} content - File content + * @returns {object|null} Parsed frontmatter key-value pairs + */ +function extractFrontmatter(content) { + const cleanContent = content.replace(/^\uFEFF/, ''); + const match = cleanContent.match(/^---\r?\n([\s\S]*?)\r?\n---/); + if (!match) return null; + + const frontmatter = {}; + const lines = match[1].split('\n'); + for (const line of lines) { + const colonIdx = line.indexOf(':'); + if (colonIdx > 0) { + const key = line.slice(0, colonIdx).trim(); + const value = line.slice(colonIdx + 1).trim(); + frontmatter[key] = value; + } + } + return frontmatter; +} + +/** + * Validate a directory of files + * @param {object} config - Validation configuration + * @param {string} config.dir - Directory to validate (absolute path) + * @param {string} config.label - Human-readable label (e.g., "agent", "command") + * @param {string} config.extension - File extension filter (e.g., ".md", ".toml") + * @param {Function} config.validate - Validation function (content, filename) => string[]|null (returns error messages or null) + */ +function validateFiles(config) { + const { dir, label, extension, validate } = config; + + if (!fs.existsSync(dir)) { + console.log(`No ${label}s directory found, skipping validation`); + process.exit(0); + } + + const files = fs.readdirSync(dir).filter(f => f.endsWith(extension)); + let hasErrors = false; + + for (const file of files) { + const filePath = path.join(dir, file); + const content = fs.readFileSync(filePath, 'utf-8'); + const errors = validate(content, file); + + if (errors && errors.length > 0) { + for (const err of errors) { + console.error(`ERROR: ${file} - ${err}`); + } + hasErrors = true; + } + } + + if (hasErrors) { + process.exit(1); + } + + console.log(`Validated ${files.length} ${label} files`); +} + +/** + * Validate a directory of subdirectories + * @param {object} config - Validation configuration + * @param {string} config.dir - Parent directory (absolute path) + * @param {string} config.label - Human-readable label (e.g., "skill") + * @param {Function} config.validate - Validation function (dirPath, dirName) => string[]|null + */ +function validateDirs(config) { + const { dir, label, validate } = config; + + if (!fs.existsSync(dir)) { + console.log(`No ${label}s directory found, skipping validation`); + process.exit(0); + } + + const entries = fs.readdirSync(dir, { withFileTypes: true }); + const dirs = entries.filter(e => e.isDirectory()).map(e => e.name); + let hasErrors = false; + let validCount = 0; + + for (const dirName of dirs) { + const dirPath = path.join(dir, dirName); + const errors = validate(dirPath, dirName); + + if (errors && errors.length > 0) { + for (const err of errors) { + console.error(`ERROR: ${dirName}/ - ${err}`); + } + hasErrors = true; + } else { + validCount++; + } + } + + if (hasErrors) { + process.exit(1); + } + + console.log(`Validated ${validCount} ${label} directories`); +} + +/** + * Validate a single JSON file + * @param {object} config - Validation configuration + * @param {string} config.file - File path (absolute) + * @param {string} config.label - Human-readable label + * @param {Function} config.validate - Validation function (data) => { errors: string[], count: number } + */ +function validateJsonFile(config) { + const { file, label, validate } = config; + + if (!fs.existsSync(file)) { + console.log(`No ${label} found, skipping validation`); + process.exit(0); + } + + let data; + try { + data = JSON.parse(fs.readFileSync(file, 'utf-8')); + } catch (e) { + console.error(`ERROR: Invalid JSON in ${path.basename(file)}: ${e.message}`); + process.exit(1); + } + + const result = validate(data); + + if (result.errors.length > 0) { + for (const err of result.errors) { + console.error(`ERROR: ${err}`); + } + process.exit(1); + } + + console.log(`Validated ${result.count} ${label}`); +} + +module.exports = { + extractFrontmatter, + validateFiles, + validateDirs, + validateJsonFile +}; From 174bb4e313b3271108a92051f5e2bcf6a5d46625 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:56:10 +0900 Subject: [PATCH 16/25] feat: add utility module for standardized hook execution and stdin processing --- scripts/lib/hook-utils.js | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 scripts/lib/hook-utils.js diff --git a/scripts/lib/hook-utils.js b/scripts/lib/hook-utils.js new file mode 100644 index 0000000..41a11d7 --- /dev/null +++ b/scripts/lib/hook-utils.js @@ -0,0 +1,43 @@ +/** + * Common utilities for Gemini CLI hook scripts + * + * Provides the shared async-main wrapper, logging, and + * stdin reading patterns used across all hooks. + */ + +/** + * Run a hook's main function with standard error handling. + * Errors are logged but never block the CLI (always exits 0). + * + * @param {string} name - Hook name for log prefix (e.g., "SessionStart") + * @param {Function} fn - Async function containing hook logic + */ +function runHook(name, fn) { + fn().then(() => { + process.exit(0); + }).catch(err => { + console.error(`[${name}] Error:`, err.message); + process.exit(0); + }); +} + +/** + * Run a stdin-piping hook (reads from stdin, must output to stdout). + * Used by hooks that sit in the tool I/O pipeline (e.g., check-console-log). + * + * @param {string} name - Hook name for log prefix + * @param {Function} fn - Function receiving stdin data string, must call console.log(data) when done + */ +function runStdinHook(name, fn) { + let data = ''; + process.stdin.on('data', chunk => { data += chunk; }); + process.stdin.on('end', () => { + try { + fn(data); + } catch (_error) { + console.log(data); + } + }); +} + +module.exports = { runHook, runStdinHook }; From b4ff96f025b4ce5ec3db1d79c1e3561c9f1c7d3e Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 09:59:06 +0900 Subject: [PATCH 17/25] refactor: migrate all hook scripts to use standardized runHook and runStdinHook utilities --- scripts/hooks/check-console-log.js | 63 ++++++++++++------------------ scripts/hooks/evaluate-session.js | 10 ++--- scripts/hooks/pre-compact.js | 10 ++--- scripts/hooks/session-end.js | 10 ++--- scripts/hooks/session-start.js | 10 ++--- scripts/hooks/suggest-compact.js | 10 ++--- 6 files changed, 39 insertions(+), 74 deletions(-) diff --git a/scripts/hooks/check-console-log.js b/scripts/hooks/check-console-log.js index 9b25fc4..640a321 100755 --- a/scripts/hooks/check-console-log.js +++ b/scripts/hooks/check-console-log.js @@ -2,7 +2,7 @@ /** * Stop Hook: Check for console.log statements in modified files - * + * * This hook runs after each response and checks if any modified * JavaScript/TypeScript files contain console.log statements. * It provides warnings to help developers remember to remove @@ -11,51 +11,36 @@ const { execSync } = require('child_process'); const fs = require('fs'); +const { runStdinHook } = require('../lib/hook-utils'); -let data = ''; +runStdinHook('CheckConsoleLog', (data) => { + try { + execSync('git rev-parse --git-dir', { stdio: 'pipe' }); + } catch { + console.log(data); + return; + } -// Read stdin -process.stdin.on('data', chunk => { - data += chunk; -}); + const files = execSync('git diff --name-only HEAD', { + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'] + }) + .split('\n') + .filter(f => /\.(ts|tsx|js|jsx)$/.test(f) && fs.existsSync(f)); -process.stdin.on('end', () => { - try { - // Check if we're in a git repository - try { - execSync('git rev-parse --git-dir', { stdio: 'pipe' }); - } catch { - // Not in a git repo, just pass through the data - console.log(data); - process.exit(0); - } + let hasConsole = false; - // Get list of modified files - const files = execSync('git diff --name-only HEAD', { - encoding: 'utf8', - stdio: ['pipe', 'pipe', 'pipe'] - }) - .split('\n') - .filter(f => /\.(ts|tsx|js|jsx)$/.test(f) && fs.existsSync(f)); - - let hasConsole = false; - - // Check each file for console.log - for (const file of files) { - const content = fs.readFileSync(file, 'utf8'); - if (content.includes('console.log')) { - console.error(`[Hook] WARNING: console.log found in ${file}`); - hasConsole = true; - } + for (const file of files) { + const content = fs.readFileSync(file, 'utf8'); + if (content.includes('console.log')) { + console.error(`[Hook] WARNING: console.log found in ${file}`); + hasConsole = true; } + } - if (hasConsole) { - console.error('[Hook] Remove console.log statements before committing'); - } - } catch (_error) { - // Silently ignore errors (git might not be available, etc.) + if (hasConsole) { + console.error('[Hook] Remove console.log statements before committing'); } - // Always output the original data console.log(data); }); diff --git a/scripts/hooks/evaluate-session.js b/scripts/hooks/evaluate-session.js index 17c2b23..e74d082 100644 --- a/scripts/hooks/evaluate-session.js +++ b/scripts/hooks/evaluate-session.js @@ -21,7 +21,9 @@ const { log } = require('../lib/utils'); -async function main() { +const { runHook } = require('../lib/hook-utils'); + +runHook('ContinuousLearning', async () => { // Get script directory to find config const scriptDir = __dirname; const configFile = path.join(scriptDir, '..', '..', 'skills', 'continuous-learning', 'config.json'); @@ -69,10 +71,4 @@ async function main() { log(`[ContinuousLearning] Session has ${messageCount} messages - evaluate for extractable patterns`); log(`[ContinuousLearning] Save learned skills to: ${learnedSkillsPath}`); - process.exit(0); -} - -main().catch(err => { - console.error('[ContinuousLearning] Error:', err.message); - process.exit(0); }); diff --git a/scripts/hooks/pre-compact.js b/scripts/hooks/pre-compact.js index 2cb5008..173f13f 100644 --- a/scripts/hooks/pre-compact.js +++ b/scripts/hooks/pre-compact.js @@ -19,7 +19,9 @@ const { log } = require('../lib/utils'); -async function main() { +const { runHook } = require('../lib/hook-utils'); + +runHook('PreCompact', async () => { const sessionsDir = getSessionsDir(); const compactionLog = path.join(sessionsDir, 'compaction-log.txt'); @@ -39,10 +41,4 @@ async function main() { } log('[PreCompact] State saved before compaction'); - process.exit(0); -} - -main().catch(err => { - console.error('[PreCompact] Error:', err.message); - process.exit(0); }); diff --git a/scripts/hooks/session-end.js b/scripts/hooks/session-end.js index fe91bf3..18ba5a3 100644 --- a/scripts/hooks/session-end.js +++ b/scripts/hooks/session-end.js @@ -21,7 +21,9 @@ const { log } = require('../lib/utils'); -async function main() { +const { runHook } = require('../lib/hook-utils'); + +runHook('SessionEnd', async () => { const sessionsDir = getSessionsDir(); const today = getDateString(); const shortId = getSessionIdShort(); @@ -75,10 +77,4 @@ async function main() { log(`[SessionEnd] Created session file: ${sessionFile}`); } - process.exit(0); -} - -main().catch(err => { - console.error('[SessionEnd] Error:', err.message); - process.exit(0); }); diff --git a/scripts/hooks/session-start.js b/scripts/hooks/session-start.js index 907c02c..5ede45f 100644 --- a/scripts/hooks/session-start.js +++ b/scripts/hooks/session-start.js @@ -19,7 +19,9 @@ const { const { getPackageManager, getSelectionPrompt } = require('../lib/package-manager'); const { listAliases } = require('../lib/session-aliases'); -async function main() { +const { runHook } = require('../lib/hook-utils'); + +runHook('SessionStart', async () => { const sessionsDir = getSessionsDir(); const learnedDir = getLearnedSkillsDir(); @@ -141,10 +143,4 @@ async function main() { log(`[SessionStart] Warning: Failed to generate shims: ${err.message}`); } - process.exit(0); -} - -main().catch(err => { - console.error('[SessionStart] Error:', err.message); - process.exit(0); // Don't block on errors }); diff --git a/scripts/hooks/suggest-compact.js b/scripts/hooks/suggest-compact.js index 708e0f5..cb533e4 100644 --- a/scripts/hooks/suggest-compact.js +++ b/scripts/hooks/suggest-compact.js @@ -21,7 +21,9 @@ const { log } = require('../lib/utils'); -async function main() { +const { runHook } = require('../lib/hook-utils'); + +runHook('StrategicCompact', async () => { // Track tool call count (increment in a temp file) // Use a session-specific counter file based on PID from parent process // or session ID from environment @@ -50,10 +52,4 @@ async function main() { log(`[StrategicCompact] ${count} tool calls - good checkpoint for /compact if context is stale`); } - process.exit(0); -} - -main().catch(err => { - console.error('[StrategicCompact] Error:', err.message); - process.exit(0); }); From c32171f162f3a207311110049dd046b10662d996 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:00:47 +0900 Subject: [PATCH 18/25] test: add comprehensive unit tests for session-manager and session-aliases libraries --- tests/lib/session-aliases.test.js | 267 ++++++++++++++++++++++++++++++ tests/lib/session-manager.test.js | 250 ++++++++++++++++++++++++++++ 2 files changed, 517 insertions(+) create mode 100644 tests/lib/session-aliases.test.js create mode 100644 tests/lib/session-manager.test.js diff --git a/tests/lib/session-aliases.test.js b/tests/lib/session-aliases.test.js new file mode 100644 index 0000000..5c12c77 --- /dev/null +++ b/tests/lib/session-aliases.test.js @@ -0,0 +1,267 @@ +/** + * Tests for scripts/lib/session-aliases.js + * + * Run with: node tests/lib/session-aliases.test.js + */ + +const assert = require('assert'); +const path = require('path'); +const fs = require('fs'); +const os = require('os'); + +// We need to mock getGeminiDir to use a temp directory +// Override the env before requiring the module +const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'alias-test-')); +process.env.GEMINI_HOME_OVERRIDE = tmpDir; + +// Monkey-patch utils.getGeminiDir to return our temp dir +const utils = require('../../scripts/lib/utils'); +const originalGetGeminiDir = utils.getGeminiDir; +utils.getGeminiDir = () => tmpDir; + +const aliases = require('../../scripts/lib/session-aliases'); + +function test(name, fn) { + try { + fn(); + console.log(` \u2713 ${name}`); + return true; + } catch (err) { + console.log(` \u2717 ${name}`); + console.log(` Error: ${err.message}`); + return false; + } +} + +function cleanup() { + // Remove the aliases file between tests for isolation + const aliasesPath = aliases.getAliasesPath(); + if (fs.existsSync(aliasesPath)) fs.unlinkSync(aliasesPath); + const bak = aliasesPath + '.bak'; + if (fs.existsSync(bak)) fs.unlinkSync(bak); + const tmp = aliasesPath + '.tmp'; + if (fs.existsSync(tmp)) fs.unlinkSync(tmp); +} + +function runTests() { + console.log('\n=== Testing session-aliases.js ===\n'); + + let passed = 0; + let failed = 0; + + // --- getAliasesPath --- + console.log('getAliasesPath:'); + + if (test('returns path ending with session-aliases.json', () => { + const p = aliases.getAliasesPath(); + assert.ok(p.endsWith('session-aliases.json')); + assert.ok(p.startsWith(tmpDir)); + })) passed++; else failed++; + + // --- loadAliases --- + console.log('\nloadAliases:'); + + cleanup(); + + if (test('returns default structure when no file exists', () => { + const data = aliases.loadAliases(); + assert.ok(data.aliases); + assert.strictEqual(typeof data.aliases, 'object'); + assert.ok(data.version); + assert.ok(data.metadata); + })) passed++; else failed++; + + if (test('handles corrupted JSON gracefully', () => { + fs.writeFileSync(aliases.getAliasesPath(), 'not json!'); + const data = aliases.loadAliases(); + assert.ok(data.aliases); + assert.strictEqual(Object.keys(data.aliases).length, 0); + cleanup(); + })) passed++; else failed++; + + if (test('handles invalid structure gracefully', () => { + fs.writeFileSync(aliases.getAliasesPath(), '{"foo": "bar"}'); + const data = aliases.loadAliases(); + assert.strictEqual(Object.keys(data.aliases).length, 0); + cleanup(); + })) passed++; else failed++; + + // --- setAlias --- + console.log('\nsetAlias:'); + + cleanup(); + + if (test('creates a new alias', () => { + const result = aliases.setAlias('my-session', 'session-file.tmp', 'Test Title'); + assert.strictEqual(result.success, true); + assert.strictEqual(result.isNew, true); + assert.strictEqual(result.alias, 'my-session'); + })) passed++; else failed++; + + if (test('updates an existing alias', () => { + const result = aliases.setAlias('my-session', 'updated-file.tmp'); + assert.strictEqual(result.success, true); + assert.strictEqual(result.isNew, false); + })) passed++; else failed++; + + if (test('rejects empty alias name', () => { + const result = aliases.setAlias('', 'file.tmp'); + assert.strictEqual(result.success, false); + assert.ok(result.error.includes('empty')); + })) passed++; else failed++; + + if (test('rejects invalid characters in alias', () => { + const result = aliases.setAlias('my session!', 'file.tmp'); + assert.strictEqual(result.success, false); + assert.ok(result.error.includes('letters')); + })) passed++; else failed++; + + if (test('rejects reserved alias names', () => { + for (const reserved of ['list', 'help', 'remove', 'delete', 'create', 'set']) { + const result = aliases.setAlias(reserved, 'file.tmp'); + assert.strictEqual(result.success, false, `Should reject '${reserved}'`); + assert.ok(result.error.includes('reserved')); + } + })) passed++; else failed++; + + // --- resolveAlias --- + console.log('\nresolveAlias:'); + + if (test('resolves existing alias', () => { + const resolved = aliases.resolveAlias('my-session'); + assert.ok(resolved); + assert.strictEqual(resolved.sessionPath, 'updated-file.tmp'); + })) passed++; else failed++; + + if (test('returns null for non-existent alias', () => { + assert.strictEqual(aliases.resolveAlias('nope'), null); + })) passed++; else failed++; + + if (test('returns null for invalid alias name', () => { + assert.strictEqual(aliases.resolveAlias('bad name!'), null); + })) passed++; else failed++; + + // --- listAliases --- + console.log('\nlistAliases:'); + + if (test('lists created aliases', () => { + const list = aliases.listAliases(); + assert.ok(Array.isArray(list)); + assert.ok(list.length >= 1); + assert.ok(list.some(a => a.name === 'my-session')); + })) passed++; else failed++; + + if (test('respects limit option', () => { + aliases.setAlias('second-alias', 'second-file.tmp'); + aliases.setAlias('third-alias', 'third-file.tmp'); + const list = aliases.listAliases({ limit: 2 }); + assert.strictEqual(list.length, 2); + })) passed++; else failed++; + + if (test('filters by search term', () => { + const list = aliases.listAliases({ search: 'second' }); + assert.strictEqual(list.length, 1); + assert.strictEqual(list[0].name, 'second-alias'); + })) passed++; else failed++; + + // --- renameAlias --- + console.log('\nrenameAlias:'); + + if (test('renames an alias', () => { + const result = aliases.renameAlias('third-alias', 'renamed-alias'); + assert.strictEqual(result.success, true); + assert.strictEqual(result.newAlias, 'renamed-alias'); + assert.strictEqual(aliases.resolveAlias('third-alias'), null); + assert.ok(aliases.resolveAlias('renamed-alias')); + })) passed++; else failed++; + + if (test('rejects rename to existing alias', () => { + const result = aliases.renameAlias('my-session', 'renamed-alias'); + assert.strictEqual(result.success, false); + assert.ok(result.error.includes('already exists')); + })) passed++; else failed++; + + if (test('rejects rename of non-existent alias', () => { + const result = aliases.renameAlias('nope', 'new-name'); + assert.strictEqual(result.success, false); + })) passed++; else failed++; + + // --- updateAliasTitle --- + console.log('\nupdateAliasTitle:'); + + if (test('updates alias title', () => { + const result = aliases.updateAliasTitle('my-session', 'New Title'); + assert.strictEqual(result.success, true); + const resolved = aliases.resolveAlias('my-session'); + assert.strictEqual(resolved.title, 'New Title'); + })) passed++; else failed++; + + if (test('returns error for non-existent alias', () => { + const result = aliases.updateAliasTitle('nope', 'Title'); + assert.strictEqual(result.success, false); + })) passed++; else failed++; + + // --- deleteAlias --- + console.log('\ndeleteAlias:'); + + if (test('deletes an alias', () => { + const result = aliases.deleteAlias('second-alias'); + assert.strictEqual(result.success, true); + assert.strictEqual(aliases.resolveAlias('second-alias'), null); + })) passed++; else failed++; + + if (test('returns error for non-existent alias', () => { + const result = aliases.deleteAlias('nope'); + assert.strictEqual(result.success, false); + })) passed++; else failed++; + + // --- getAliasesForSession --- + console.log('\ngetAliasesForSession:'); + + if (test('finds aliases for a session path', () => { + const list = aliases.getAliasesForSession('updated-file.tmp'); + assert.ok(list.length >= 1); + assert.ok(list.some(a => a.name === 'my-session')); + })) passed++; else failed++; + + if (test('returns empty array for unknown session', () => { + const list = aliases.getAliasesForSession('unknown-file.tmp'); + assert.strictEqual(list.length, 0); + })) passed++; else failed++; + + // --- resolveSessionAlias --- + console.log('\nresolveSessionAlias:'); + + if (test('resolves alias to session path', () => { + const p = aliases.resolveSessionAlias('my-session'); + assert.strictEqual(p, 'updated-file.tmp'); + })) passed++; else failed++; + + if (test('returns input as-is if not an alias', () => { + const p = aliases.resolveSessionAlias('some-raw-id'); + assert.strictEqual(p, 'some-raw-id'); + })) passed++; else failed++; + + // --- cleanupAliases --- + console.log('\ncleanupAliases:'); + + if (test('removes aliases for non-existent sessions', () => { + const result = aliases.cleanupAliases(() => false); + assert.ok(result.removed > 0); + assert.strictEqual(Object.keys(aliases.loadAliases().aliases).length, 0); + })) passed++; else failed++; + + // Cleanup + utils.getGeminiDir = originalGetGeminiDir; + fs.rmSync(tmpDir, { recursive: true, force: true }); + + // Results + console.log(`\n=== Test Results ===`); + console.log(`Passed: ${passed}`); + console.log(`Failed: ${failed}`); + console.log(`Total: ${passed + failed}`); + + if (failed > 0) process.exit(1); +} + +runTests(); diff --git a/tests/lib/session-manager.test.js b/tests/lib/session-manager.test.js new file mode 100644 index 0000000..1729c50 --- /dev/null +++ b/tests/lib/session-manager.test.js @@ -0,0 +1,250 @@ +/** + * Tests for scripts/lib/session-manager.js + * + * Run with: node tests/lib/session-manager.test.js + */ + +const assert = require('assert'); +const path = require('path'); +const fs = require('fs'); +const os = require('os'); + +const sm = require('../../scripts/lib/session-manager'); + +function test(name, fn) { + try { + fn(); + console.log(` \u2713 ${name}`); + return true; + } catch (err) { + console.log(` \u2717 ${name}`); + console.log(` Error: ${err.message}`); + return false; + } +} + +function createTempDir() { + return fs.mkdtempSync(path.join(os.tmpdir(), 'sm-test-')); +} + +function runTests() { + console.log('\n=== Testing session-manager.js ===\n'); + + let passed = 0; + let failed = 0; + + // --- parseSessionFilename --- + console.log('parseSessionFilename:'); + + if (test('parses new format with short ID', () => { + const result = sm.parseSessionFilename('2026-02-01-a1b2c3d4-session.tmp'); + assert.ok(result); + assert.strictEqual(result.date, '2026-02-01'); + assert.strictEqual(result.shortId, 'a1b2c3d4'); + assert.strictEqual(result.filename, '2026-02-01-a1b2c3d4-session.tmp'); + })) passed++; else failed++; + + if (test('parses old format without short ID', () => { + const result = sm.parseSessionFilename('2026-02-01-session.tmp'); + assert.ok(result); + assert.strictEqual(result.date, '2026-02-01'); + assert.strictEqual(result.shortId, 'no-id'); + })) passed++; else failed++; + + if (test('returns null for invalid filename', () => { + assert.strictEqual(sm.parseSessionFilename('readme.md'), null); + assert.strictEqual(sm.parseSessionFilename(''), null); + assert.strictEqual(sm.parseSessionFilename('2026-13-99-session.tmp'), null); + })) passed++; else failed++; + + if (test('handles long short IDs', () => { + const result = sm.parseSessionFilename('2026-03-15-abcdef0123456789-session.tmp'); + assert.ok(result); + assert.strictEqual(result.shortId, 'abcdef0123456789'); + })) passed++; else failed++; + + if (test('datetime is a valid Date object', () => { + const result = sm.parseSessionFilename('2026-06-15-abc12345-session.tmp'); + assert.ok(result.datetime instanceof Date); + assert.strictEqual(result.datetime.getFullYear(), 2026); + })) passed++; else failed++; + + // --- parseSessionMetadata --- + console.log('\nparseSessionMetadata:'); + + if (test('extracts title from heading', () => { + const meta = sm.parseSessionMetadata('# Session: 2026-02-01\nsome text'); + assert.strictEqual(meta.title, 'Session: 2026-02-01'); + })) passed++; else failed++; + + if (test('extracts date, started, and lastUpdated', () => { + const content = `# Session +**Date:** 2026-03-10 +**Started:** 14:30 +**Last Updated:** 16:45`; + const meta = sm.parseSessionMetadata(content); + assert.strictEqual(meta.date, '2026-03-10'); + assert.strictEqual(meta.started, '14:30'); + assert.strictEqual(meta.lastUpdated, '16:45'); + })) passed++; else failed++; + + if (test('extracts completed items', () => { + const content = `# Session +### Completed +- [x] First task +- [x] Second task +### In Progress`; + const meta = sm.parseSessionMetadata(content); + assert.strictEqual(meta.completed.length, 2); + assert.strictEqual(meta.completed[0], 'First task'); + })) passed++; else failed++; + + if (test('extracts in-progress items', () => { + const content = `# Session +### In Progress +- [ ] Working on this +- [ ] And this +### Notes`; + const meta = sm.parseSessionMetadata(content); + assert.strictEqual(meta.inProgress.length, 2); + assert.strictEqual(meta.inProgress[0], 'Working on this'); + })) passed++; else failed++; + + if (test('returns defaults for null content', () => { + const meta = sm.parseSessionMetadata(null); + assert.strictEqual(meta.title, null); + assert.strictEqual(meta.date, null); + assert.deepStrictEqual(meta.completed, []); + assert.deepStrictEqual(meta.inProgress, []); + })) passed++; else failed++; + + if (test('returns defaults for empty content', () => { + const meta = sm.parseSessionMetadata(''); + assert.strictEqual(meta.title, null); + })) passed++; else failed++; + + // --- getSessionPath --- + console.log('\ngetSessionPath:'); + + if (test('returns path under sessions directory', () => { + const p = sm.getSessionPath('test-session.tmp'); + assert.ok(p.endsWith('test-session.tmp')); + assert.ok(p.includes('sessions')); + })) passed++; else failed++; + + // --- writeSessionContent / getSessionContent / sessionExists --- + console.log('\nFile I/O:'); + + const tmpDir = createTempDir(); + const tmpFile = path.join(tmpDir, 'test-session.tmp'); + + if (test('writeSessionContent writes file', () => { + const result = sm.writeSessionContent(tmpFile, '# Test session'); + assert.strictEqual(result, true); + assert.ok(fs.existsSync(tmpFile)); + })) passed++; else failed++; + + if (test('getSessionContent reads written file', () => { + const content = sm.getSessionContent(tmpFile); + assert.strictEqual(content, '# Test session'); + })) passed++; else failed++; + + if (test('getSessionContent returns null for missing file', () => { + const content = sm.getSessionContent(path.join(tmpDir, 'nope.tmp')); + assert.strictEqual(content, null); + })) passed++; else failed++; + + if (test('sessionExists returns true for existing file', () => { + assert.strictEqual(sm.sessionExists(tmpFile), true); + })) passed++; else failed++; + + if (test('sessionExists returns false for missing file', () => { + assert.strictEqual(sm.sessionExists(path.join(tmpDir, 'nope.tmp')), false); + })) passed++; else failed++; + + // --- appendSessionContent --- + if (test('appendSessionContent appends to file', () => { + sm.appendSessionContent(tmpFile, '\n## Appended'); + const content = sm.getSessionContent(tmpFile); + assert.ok(content.includes('## Appended')); + })) passed++; else failed++; + + // --- deleteSession --- + if (test('deleteSession removes file', () => { + const delFile = path.join(tmpDir, 'del-session.tmp'); + fs.writeFileSync(delFile, 'delete me'); + assert.strictEqual(sm.deleteSession(delFile), true); + assert.strictEqual(fs.existsSync(delFile), false); + })) passed++; else failed++; + + if (test('deleteSession returns false for missing file', () => { + assert.strictEqual(sm.deleteSession(path.join(tmpDir, 'nope.tmp')), false); + })) passed++; else failed++; + + // --- getSessionStats --- + console.log('\ngetSessionStats:'); + + if (test('calculates stats from content', () => { + const statsFile = path.join(tmpDir, 'stats-session.tmp'); + const content = `# Session: Test +**Date:** 2026-01-01 +### Completed +- [x] Done thing +### In Progress +- [ ] Doing thing +- [ ] Another thing`; + fs.writeFileSync(statsFile, content); + const stats = sm.getSessionStats(statsFile); + assert.strictEqual(stats.completedItems, 1); + assert.strictEqual(stats.inProgressItems, 2); + assert.strictEqual(stats.totalItems, 3); + assert.ok(stats.lineCount > 0); + })) passed++; else failed++; + + // --- getSessionTitle --- + console.log('\ngetSessionTitle:'); + + if (test('returns title from content', () => { + const titleFile = path.join(tmpDir, 'title-session.tmp'); + fs.writeFileSync(titleFile, '# My Great Session\nContent here'); + assert.strictEqual(sm.getSessionTitle(titleFile), 'My Great Session'); + })) passed++; else failed++; + + if (test('returns default for missing file', () => { + assert.strictEqual(sm.getSessionTitle(path.join(tmpDir, 'nope.tmp')), 'Untitled Session'); + })) passed++; else failed++; + + // --- getSessionSize --- + console.log('\ngetSessionSize:'); + + if (test('returns human-readable size', () => { + const sizeFile = path.join(tmpDir, 'size-session.tmp'); + fs.writeFileSync(sizeFile, 'x'.repeat(100)); + const size = sm.getSessionSize(sizeFile); + assert.strictEqual(size, '100 B'); + })) passed++; else failed++; + + if (test('returns 0 B for missing file', () => { + assert.strictEqual(sm.getSessionSize(path.join(tmpDir, 'nope.tmp')), '0 B'); + })) passed++; else failed++; + + if (test('formats KB correctly', () => { + const kbFile = path.join(tmpDir, 'kb-session.tmp'); + fs.writeFileSync(kbFile, 'x'.repeat(2048)); + const size = sm.getSessionSize(kbFile); + assert.ok(size.endsWith('KB'), `Expected KB but got: ${size}`); + })) passed++; else failed++; + + // Cleanup + fs.rmSync(tmpDir, { recursive: true, force: true }); + + // Results + console.log(`\n=== Test Results ===`); + console.log(`Passed: ${passed}`); + console.log(`Failed: ${failed}`); + console.log(`Total: ${passed + failed}`); + + if (failed > 0) process.exit(1); +} + +runTests(); From 66b980014d954bc2e92db0cc2e0900e4bb05bb02 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:01:04 +0900 Subject: [PATCH 19/25] test: update invalid session filename test case to use a non-matching string --- tests/lib/session-manager.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/session-manager.test.js b/tests/lib/session-manager.test.js index 1729c50..ce3a6ee 100644 --- a/tests/lib/session-manager.test.js +++ b/tests/lib/session-manager.test.js @@ -54,7 +54,7 @@ function runTests() { if (test('returns null for invalid filename', () => { assert.strictEqual(sm.parseSessionFilename('readme.md'), null); assert.strictEqual(sm.parseSessionFilename(''), null); - assert.strictEqual(sm.parseSessionFilename('2026-13-99-session.tmp'), null); + assert.strictEqual(sm.parseSessionFilename('not-a-session-file'), null); })) passed++; else failed++; if (test('handles long short IDs', () => { From ffabac5f2f18f067c945e9237b4c8ff22e4d728e Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:02:29 +0900 Subject: [PATCH 20/25] test: update test runner to include new test suites and improve output formatting --- tests/run-all.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-all.js b/tests/run-all.js index 3246547..f1f6c92 100644 --- a/tests/run-all.js +++ b/tests/run-all.js @@ -13,6 +13,8 @@ const testsDir = __dirname; const testFiles = [ 'lib/utils.test.js', 'lib/package-manager.test.js', + 'lib/session-manager.test.js', + 'lib/session-aliases.test.js', 'hooks/hooks.test.js' ]; From 90bbbb941025c71da52aca8099e5a026a46f5a95 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:05:06 +0900 Subject: [PATCH 21/25] feat: add YAML frontmatter with name and description metadata to all skill definition files --- skills/benchmark/SKILL.md | 5 +++++ skills/browser-qa/SKILL.md | 5 +++++ skills/canary-watch/SKILL.md | 5 +++++ skills/design-system/SKILL.md | 5 +++++ skills/product-lens/SKILL.md | 5 +++++ skills/project-guidelines-example/SKILL.md | 5 +++++ skills/safety-guard/SKILL.md | 5 +++++ skills/verification-loop/SKILL.md | 5 +++++ 8 files changed, 40 insertions(+) diff --git a/skills/benchmark/SKILL.md b/skills/benchmark/SKILL.md index 51ccce8..d80aec7 100644 --- a/skills/benchmark/SKILL.md +++ b/skills/benchmark/SKILL.md @@ -1,3 +1,8 @@ +--- +name: benchmark +description: Performance baseline measurement and regression detection +--- + # Benchmark — Performance Baseline & Regression Detection ## When to Use diff --git a/skills/browser-qa/SKILL.md b/skills/browser-qa/SKILL.md index d71a006..03d8940 100644 --- a/skills/browser-qa/SKILL.md +++ b/skills/browser-qa/SKILL.md @@ -1,3 +1,8 @@ +--- +name: browser-qa +description: Automated visual testing and browser interaction verification +--- + # Browser QA — Automated Visual Testing & Interaction ## When to Use diff --git a/skills/canary-watch/SKILL.md b/skills/canary-watch/SKILL.md index 1415e16..793842f 100644 --- a/skills/canary-watch/SKILL.md +++ b/skills/canary-watch/SKILL.md @@ -1,3 +1,8 @@ +--- +name: canary-watch +description: Post-deploy monitoring and canary health verification +--- + # Canary Watch — Post-Deploy Monitoring ## When to Use diff --git a/skills/design-system/SKILL.md b/skills/design-system/SKILL.md index 3bf06a4..43cf48f 100644 --- a/skills/design-system/SKILL.md +++ b/skills/design-system/SKILL.md @@ -1,3 +1,8 @@ +--- +name: design-system +description: Generate and audit visual design systems for consistency +--- + # Design System — Generate & Audit Visual Systems ## When to Use diff --git a/skills/product-lens/SKILL.md b/skills/product-lens/SKILL.md index 63ff7b2..802fd3d 100644 --- a/skills/product-lens/SKILL.md +++ b/skills/product-lens/SKILL.md @@ -1,3 +1,8 @@ +--- +name: product-lens +description: Product thinking validation before building features +--- + # Product Lens — Think Before You Build ## When to Use diff --git a/skills/project-guidelines-example/SKILL.md b/skills/project-guidelines-example/SKILL.md index fbc687f..cf02886 100644 --- a/skills/project-guidelines-example/SKILL.md +++ b/skills/project-guidelines-example/SKILL.md @@ -1,3 +1,8 @@ +--- +name: project-guidelines-example +description: Example project-specific skill template for custom guidelines +--- + # Project Guidelines Skill (Example) This is an example of a project-specific skill. Use this as a template for your own projects. diff --git a/skills/safety-guard/SKILL.md b/skills/safety-guard/SKILL.md index 817f45f..4da8558 100644 --- a/skills/safety-guard/SKILL.md +++ b/skills/safety-guard/SKILL.md @@ -1,3 +1,8 @@ +--- +name: safety-guard +description: Prevent destructive operations on production systems +--- + # Safety Guard — Prevent Destructive Operations ## When to Use diff --git a/skills/verification-loop/SKILL.md b/skills/verification-loop/SKILL.md index 53c2a5b..adeccbe 100644 --- a/skills/verification-loop/SKILL.md +++ b/skills/verification-loop/SKILL.md @@ -1,3 +1,8 @@ +--- +name: verification-loop +description: Comprehensive verification system for code changes +--- + # Verification Loop Skill A comprehensive verification system for Gemini CLI sessions. From 68d5ab69e28dd044005ab81b2c094cc6179f22ce Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:05:23 +0900 Subject: [PATCH 22/25] refactor: rename "When to Activate" headers to "When to Use" across all skill documentation files --- skills/agent-eval/SKILL.md | 2 +- skills/ai-regression-testing/SKILL.md | 2 +- skills/android-clean-architecture/SKILL.md | 2 +- skills/api-design/SKILL.md | 2 +- skills/architecture-decision-records/SKILL.md | 2 +- skills/article-writing/SKILL.md | 2 +- skills/claude-api/SKILL.md | 2 +- skills/compose-multiplatform-patterns/SKILL.md | 2 +- skills/configure-ecc/SKILL.md | 2 +- skills/content-engine/SKILL.md | 2 +- skills/content-hash-cache-pattern/SKILL.md | 2 +- skills/cost-aware-llm-pipeline/SKILL.md | 2 +- skills/crosspost/SKILL.md | 2 +- skills/data-scraper-agent/SKILL.md | 2 +- skills/database-migrations/SKILL.md | 2 +- skills/deep-research/SKILL.md | 2 +- skills/deployment-patterns/SKILL.md | 2 +- skills/django-patterns/SKILL.md | 2 +- skills/django-security/SKILL.md | 2 +- skills/django-tdd/SKILL.md | 2 +- skills/dmux-workflows/SKILL.md | 2 +- skills/docker-patterns/SKILL.md | 2 +- skills/exa-search/SKILL.md | 2 +- skills/fal-ai-media/SKILL.md | 2 +- skills/foundation-models-on-device/SKILL.md | 2 +- skills/frontend-slides/SKILL.md | 2 +- skills/golang-patterns/SKILL.md | 2 +- skills/golang-testing/SKILL.md | 2 +- skills/investor-materials/SKILL.md | 2 +- skills/investor-outreach/SKILL.md | 2 +- skills/kotlin-coroutines-flows/SKILL.md | 2 +- skills/kotlin-ktor-patterns/SKILL.md | 2 +- skills/laravel-security/SKILL.md | 2 +- skills/liquid-glass-design/SKILL.md | 2 +- skills/market-research/SKILL.md | 2 +- skills/nuxt4-patterns/SKILL.md | 2 +- skills/perl-patterns/SKILL.md | 2 +- skills/perl-security/SKILL.md | 2 +- skills/perl-testing/SKILL.md | 2 +- skills/postgres-patterns/SKILL.md | 2 +- skills/python-patterns/SKILL.md | 2 +- skills/python-testing/SKILL.md | 2 +- skills/pytorch-patterns/SKILL.md | 2 +- skills/regex-vs-llm-structured-text/SKILL.md | 2 +- skills/santa-method/SKILL.md | 2 +- skills/security-review/SKILL.md | 2 +- skills/security-review/cloud-infrastructure-security.md | 2 +- skills/security-scan/SKILL.md | 2 +- skills/skill-comply/SKILL.md | 2 +- skills/swift-actor-persistence/SKILL.md | 2 +- skills/swift-concurrency-6-2/SKILL.md | 2 +- skills/swift-protocol-di-testing/SKILL.md | 2 +- skills/swiftui-patterns/SKILL.md | 2 +- skills/tdd-workflow/SKILL.md | 2 +- skills/video-editing/SKILL.md | 2 +- skills/x-api/SKILL.md | 2 +- 56 files changed, 56 insertions(+), 56 deletions(-) diff --git a/skills/agent-eval/SKILL.md b/skills/agent-eval/SKILL.md index acfecd9..bf4d59c 100644 --- a/skills/agent-eval/SKILL.md +++ b/skills/agent-eval/SKILL.md @@ -9,7 +9,7 @@ tools: Read, Write, Edit, Bash, Grep, Glob A lightweight CLI tool for comparing coding agents head-to-head on reproducible tasks. Every "which coding agent is best?" comparison runs on vibes — this tool systematizes it. -## When to Activate +## When to Use - Comparing coding agents (Claude Code, Aider, Codex, etc.) on your own codebase - Measuring agent performance before adopting a new tool or model diff --git a/skills/ai-regression-testing/SKILL.md b/skills/ai-regression-testing/SKILL.md index 6dcea16..2ae3b56 100644 --- a/skills/ai-regression-testing/SKILL.md +++ b/skills/ai-regression-testing/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Testing patterns specifically designed for AI-assisted development, where the same model writes code and reviews it — creating systematic blind spots that only automated tests can catch. -## When to Activate +## When to Use - AI agent (Claude Code, Cursor, Codex) has modified API routes or backend logic - A bug was found and fixed — need to prevent re-introduction diff --git a/skills/android-clean-architecture/SKILL.md b/skills/android-clean-architecture/SKILL.md index 1b4963f..f26157a 100644 --- a/skills/android-clean-architecture/SKILL.md +++ b/skills/android-clean-architecture/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Clean Architecture patterns for Android and KMP projects. Covers module boundaries, dependency inversion, UseCase/Repository patterns, and data layer design with Room, SQLDelight, and Ktor. -## When to Activate +## When to Use - Structuring Android or KMP project modules - Implementing UseCases, Repositories, or DataSources diff --git a/skills/api-design/SKILL.md b/skills/api-design/SKILL.md index a45aca0..e699174 100644 --- a/skills/api-design/SKILL.md +++ b/skills/api-design/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Conventions and best practices for designing consistent, developer-friendly REST APIs. -## When to Activate +## When to Use - Designing new API endpoints - Reviewing existing API contracts diff --git a/skills/architecture-decision-records/SKILL.md b/skills/architecture-decision-records/SKILL.md index 54be3ae..499df16 100644 --- a/skills/architecture-decision-records/SKILL.md +++ b/skills/architecture-decision-records/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Capture architectural decisions as they happen during coding sessions. Instead of decisions living only in Slack threads, PR comments, or someone's memory, this skill produces structured ADR documents that live alongside the code. -## When to Activate +## When to Use - User explicitly says "let's record this decision" or "ADR this" - User chooses between significant alternatives (framework, library, pattern, database, API design) diff --git a/skills/article-writing/SKILL.md b/skills/article-writing/SKILL.md index cc4c17a..abc7f23 100644 --- a/skills/article-writing/SKILL.md +++ b/skills/article-writing/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Write long-form content that sounds like a real person or brand, not generic AI output. -## When to Activate +## When to Use - drafting blog posts, essays, launch posts, guides, tutorials, or newsletter issues - turning notes, transcripts, or research into polished articles diff --git a/skills/claude-api/SKILL.md b/skills/claude-api/SKILL.md index 6759e97..a442618 100644 --- a/skills/claude-api/SKILL.md +++ b/skills/claude-api/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Build applications with the Anthropic Claude API and SDKs. -## When to Activate +## When to Use - Building applications that call the Claude API - Code imports `anthropic` (Python) or `@anthropic-ai/sdk` (TypeScript) diff --git a/skills/compose-multiplatform-patterns/SKILL.md b/skills/compose-multiplatform-patterns/SKILL.md index f4caec1..b38a2d3 100644 --- a/skills/compose-multiplatform-patterns/SKILL.md +++ b/skills/compose-multiplatform-patterns/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Patterns for building shared UI across Android, iOS, Desktop, and Web using Compose Multiplatform and Jetpack Compose. Covers state management, navigation, theming, and performance. -## When to Activate +## When to Use - Building Compose UI (Jetpack Compose or Compose Multiplatform) - Managing UI state with ViewModels and Compose state diff --git a/skills/configure-ecc/SKILL.md b/skills/configure-ecc/SKILL.md index b32091b..50945cf 100644 --- a/skills/configure-ecc/SKILL.md +++ b/skills/configure-ecc/SKILL.md @@ -7,7 +7,7 @@ description: Interactive installer for Everything Gemini CLI — guides users th An interactive, step-by-step installation wizard for the Everything Gemini CLI project. Uses `AskUserQuestion` to guide users through selective installation of skills and rules, then verifies correctness and offers optimization. -## When to Activate +## When to Use - User says "configure ecc", "install ecc", "setup everything gemini code", or similar - User wants to selectively install skills or rules from this project diff --git a/skills/content-engine/SKILL.md b/skills/content-engine/SKILL.md index 9398c31..51775c2 100644 --- a/skills/content-engine/SKILL.md +++ b/skills/content-engine/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Turn one idea into strong, platform-native content instead of posting the same thing everywhere. -## When to Activate +## When to Use - writing X posts or threads - drafting LinkedIn posts or launch updates diff --git a/skills/content-hash-cache-pattern/SKILL.md b/skills/content-hash-cache-pattern/SKILL.md index 083ce21..adf8119 100644 --- a/skills/content-hash-cache-pattern/SKILL.md +++ b/skills/content-hash-cache-pattern/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Cache expensive file processing results (PDF parsing, text extraction, image analysis) using SHA-256 content hashes as cache keys. Unlike path-based caching, this approach survives file moves/renames and auto-invalidates when content changes. -## When to Activate +## When to Use - Building file processing pipelines (PDF, images, text extraction) - Processing cost is high and same files are processed repeatedly diff --git a/skills/cost-aware-llm-pipeline/SKILL.md b/skills/cost-aware-llm-pipeline/SKILL.md index c1000fa..f97028a 100644 --- a/skills/cost-aware-llm-pipeline/SKILL.md +++ b/skills/cost-aware-llm-pipeline/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Patterns for controlling LLM API costs while maintaining quality. Combines model routing, budget tracking, retry logic, and prompt caching into a composable pipeline. -## When to Activate +## When to Use - Building applications that call LLM APIs (Claude, GPT, etc.) - Processing batches of items with varying complexity diff --git a/skills/crosspost/SKILL.md b/skills/crosspost/SKILL.md index da07ec8..8a38125 100644 --- a/skills/crosspost/SKILL.md +++ b/skills/crosspost/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Distribute content across multiple social platforms with platform-native adaptation. -## When to Activate +## When to Use - User wants to post content to multiple platforms - Publishing announcements, launches, or updates across social media diff --git a/skills/data-scraper-agent/SKILL.md b/skills/data-scraper-agent/SKILL.md index 72a6548..c770562 100644 --- a/skills/data-scraper-agent/SKILL.md +++ b/skills/data-scraper-agent/SKILL.md @@ -11,7 +11,7 @@ Runs on a schedule, enriches results with a free LLM, stores to a database, and **Stack: Python · Gemini Flash (free) · GitHub Actions (free) · Notion / Sheets / Supabase** -## When to Activate +## When to Use - User wants to scrape or monitor any public website or API - User says "build a bot that checks...", "monitor X for me", "collect data from..." diff --git a/skills/database-migrations/SKILL.md b/skills/database-migrations/SKILL.md index b1562c2..ded302d 100644 --- a/skills/database-migrations/SKILL.md +++ b/skills/database-migrations/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Safe, reversible database schema changes for production systems. -## When to Activate +## When to Use - Creating or altering database tables - Adding/removing columns or indexes diff --git a/skills/deep-research/SKILL.md b/skills/deep-research/SKILL.md index 5a412b7..5c68e44 100644 --- a/skills/deep-research/SKILL.md +++ b/skills/deep-research/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Produce thorough, cited research reports from multiple web sources using firecrawl and exa MCP tools. -## When to Activate +## When to Use - User asks to research any topic in depth - Competitive analysis, technology evaluation, or market sizing diff --git a/skills/deployment-patterns/SKILL.md b/skills/deployment-patterns/SKILL.md index bcccaf9..cab9315 100644 --- a/skills/deployment-patterns/SKILL.md +++ b/skills/deployment-patterns/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Production deployment workflows and CI/CD best practices. -## When to Activate +## When to Use - Setting up CI/CD pipelines - Dockerizing an application diff --git a/skills/django-patterns/SKILL.md b/skills/django-patterns/SKILL.md index 2db064f..8cd2584 100644 --- a/skills/django-patterns/SKILL.md +++ b/skills/django-patterns/SKILL.md @@ -7,7 +7,7 @@ description: Django architecture patterns, REST API design with DRF, ORM best pr Production-grade Django architecture patterns for scalable, maintainable applications. -## When to Activate +## When to Use - Building Django web applications - Designing Django REST Framework APIs diff --git a/skills/django-security/SKILL.md b/skills/django-security/SKILL.md index 9d228af..dc94ae9 100644 --- a/skills/django-security/SKILL.md +++ b/skills/django-security/SKILL.md @@ -7,7 +7,7 @@ description: Django security best practices, authentication, authorization, CSRF Comprehensive security guidelines for Django applications to protect against common vulnerabilities. -## When to Activate +## When to Use - Setting up Django authentication and authorization - Implementing user permissions and roles diff --git a/skills/django-tdd/SKILL.md b/skills/django-tdd/SKILL.md index 7b88405..9f57963 100644 --- a/skills/django-tdd/SKILL.md +++ b/skills/django-tdd/SKILL.md @@ -7,7 +7,7 @@ description: Django testing strategies with pytest-django, TDD methodology, fact Test-driven development for Django applications using pytest, factory_boy, and Django REST Framework. -## When to Activate +## When to Use - Writing new Django applications - Implementing Django REST Framework APIs diff --git a/skills/dmux-workflows/SKILL.md b/skills/dmux-workflows/SKILL.md index b1904f8..19e6e97 100644 --- a/skills/dmux-workflows/SKILL.md +++ b/skills/dmux-workflows/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Orchestrate parallel AI agent sessions using dmux, a tmux pane manager for agent harnesses. -## When to Activate +## When to Use - Running multiple agent sessions in parallel - Coordinating work across Claude Code, Codex, and other harnesses diff --git a/skills/docker-patterns/SKILL.md b/skills/docker-patterns/SKILL.md index c438c4a..fe8b463 100644 --- a/skills/docker-patterns/SKILL.md +++ b/skills/docker-patterns/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Docker and Docker Compose best practices for containerized development. -## When to Activate +## When to Use - Setting up Docker Compose for local development - Designing multi-container architectures diff --git a/skills/exa-search/SKILL.md b/skills/exa-search/SKILL.md index 567dc94..1b6108c 100644 --- a/skills/exa-search/SKILL.md +++ b/skills/exa-search/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Neural search for web content, code, companies, and people via the Exa MCP server. -## When to Activate +## When to Use - User needs current web information or news - Searching for code examples, API docs, or technical references diff --git a/skills/fal-ai-media/SKILL.md b/skills/fal-ai-media/SKILL.md index ffe701d..2f7b039 100644 --- a/skills/fal-ai-media/SKILL.md +++ b/skills/fal-ai-media/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Generate images, videos, and audio using fal.ai models via MCP. -## When to Activate +## When to Use - User wants to generate images from text prompts - Creating videos from text or images diff --git a/skills/foundation-models-on-device/SKILL.md b/skills/foundation-models-on-device/SKILL.md index 2304ca0..af6dbba 100644 --- a/skills/foundation-models-on-device/SKILL.md +++ b/skills/foundation-models-on-device/SKILL.md @@ -7,7 +7,7 @@ description: Apple FoundationModels framework for on-device LLM — text generat Patterns for integrating Apple's on-device language model into apps using the FoundationModels framework. Covers text generation, structured output with `@Generable`, custom tool calling, and snapshot streaming — all running on-device for privacy and offline support. -## When to Activate +## When to Use - Building AI-powered features using Apple Intelligence on-device - Generating or summarizing text without cloud dependency diff --git a/skills/frontend-slides/SKILL.md b/skills/frontend-slides/SKILL.md index 2820d96..e0abd9e 100644 --- a/skills/frontend-slides/SKILL.md +++ b/skills/frontend-slides/SKILL.md @@ -10,7 +10,7 @@ Create zero-dependency, animation-rich HTML presentations that run entirely in t Inspired by the visual exploration approach showcased in work by zarazhangrui (credit: @zarazhangrui). -## When to Activate +## When to Use - Creating a talk deck, pitch deck, workshop deck, or internal presentation - Converting `.ppt` or `.pptx` slides into an HTML presentation diff --git a/skills/golang-patterns/SKILL.md b/skills/golang-patterns/SKILL.md index 86b21a7..b765c67 100644 --- a/skills/golang-patterns/SKILL.md +++ b/skills/golang-patterns/SKILL.md @@ -7,7 +7,7 @@ description: Idiomatic Go patterns, best practices, and conventions for building Idiomatic Go patterns and best practices for building robust, efficient, and maintainable applications. -## When to Activate +## When to Use - Writing new Go code - Reviewing Go code diff --git a/skills/golang-testing/SKILL.md b/skills/golang-testing/SKILL.md index f7d546e..7a283fe 100644 --- a/skills/golang-testing/SKILL.md +++ b/skills/golang-testing/SKILL.md @@ -7,7 +7,7 @@ description: Go testing patterns including table-driven tests, subtests, benchma Comprehensive Go testing patterns for writing reliable, maintainable tests following TDD methodology. -## When to Activate +## When to Use - Writing new Go functions or methods - Adding test coverage to existing code diff --git a/skills/investor-materials/SKILL.md b/skills/investor-materials/SKILL.md index e392706..3f99843 100644 --- a/skills/investor-materials/SKILL.md +++ b/skills/investor-materials/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Build investor-facing materials that are consistent, credible, and easy to defend. -## When to Activate +## When to Use - creating or revising a pitch deck - writing an investor memo or one-pager diff --git a/skills/investor-outreach/SKILL.md b/skills/investor-outreach/SKILL.md index 4fc69f4..0820890 100644 --- a/skills/investor-outreach/SKILL.md +++ b/skills/investor-outreach/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Write investor communication that is short, personalized, and easy to act on. -## When to Activate +## When to Use - writing a cold email to an investor - drafting a warm intro request diff --git a/skills/kotlin-coroutines-flows/SKILL.md b/skills/kotlin-coroutines-flows/SKILL.md index 4108aac..51510d4 100644 --- a/skills/kotlin-coroutines-flows/SKILL.md +++ b/skills/kotlin-coroutines-flows/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Patterns for structured concurrency, Flow-based reactive streams, and coroutine testing in Android and Kotlin Multiplatform projects. -## When to Activate +## When to Use - Writing async code with Kotlin coroutines - Using Flow, StateFlow, or SharedFlow for reactive data diff --git a/skills/kotlin-ktor-patterns/SKILL.md b/skills/kotlin-ktor-patterns/SKILL.md index 10c9522..3055b53 100644 --- a/skills/kotlin-ktor-patterns/SKILL.md +++ b/skills/kotlin-ktor-patterns/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Comprehensive Ktor patterns for building robust, maintainable HTTP servers with Kotlin coroutines. -## When to Activate +## When to Use - Building Ktor HTTP servers - Configuring Ktor plugins (Auth, CORS, ContentNegotiation, StatusPages) diff --git a/skills/laravel-security/SKILL.md b/skills/laravel-security/SKILL.md index 653773c..ee4ec32 100644 --- a/skills/laravel-security/SKILL.md +++ b/skills/laravel-security/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Comprehensive security guidance for Laravel applications to protect against common vulnerabilities. -## When to Activate +## When to Use - Adding authentication or authorization - Handling user input and file uploads diff --git a/skills/liquid-glass-design/SKILL.md b/skills/liquid-glass-design/SKILL.md index 60551c2..79cae12 100644 --- a/skills/liquid-glass-design/SKILL.md +++ b/skills/liquid-glass-design/SKILL.md @@ -7,7 +7,7 @@ description: iOS 26 Liquid Glass design system — dynamic glass material with b Patterns for implementing Apple's Liquid Glass — a dynamic material that blurs content behind it, reflects color and light from surrounding content, and reacts to touch and pointer interactions. Covers SwiftUI, UIKit, and WidgetKit integration. -## When to Activate +## When to Use - Building or updating apps for iOS 26+ with the new design language - Implementing glass-style buttons, cards, toolbars, or containers diff --git a/skills/market-research/SKILL.md b/skills/market-research/SKILL.md index 12ffa03..4df4603 100644 --- a/skills/market-research/SKILL.md +++ b/skills/market-research/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Produce research that supports decisions, not research theater. -## When to Activate +## When to Use - researching a market, category, company, investor, or technology trend - building TAM/SAM/SOM estimates diff --git a/skills/nuxt4-patterns/SKILL.md b/skills/nuxt4-patterns/SKILL.md index 3e7a0b8..73966a3 100644 --- a/skills/nuxt4-patterns/SKILL.md +++ b/skills/nuxt4-patterns/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Use when building or debugging Nuxt 4 apps with SSR, hybrid rendering, route rules, or page-level data fetching. -## When to Activate +## When to Use - Hydration mismatches between server HTML and client state - Route-level rendering decisions such as prerender, SWR, ISR, or client-only sections diff --git a/skills/perl-patterns/SKILL.md b/skills/perl-patterns/SKILL.md index c08d182..b307f3e 100644 --- a/skills/perl-patterns/SKILL.md +++ b/skills/perl-patterns/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Idiomatic Perl 5.36+ patterns and best practices for building robust, maintainable applications. -## When to Activate +## When to Use - Writing new Perl code or modules - Reviewing Perl code for idiom compliance diff --git a/skills/perl-security/SKILL.md b/skills/perl-security/SKILL.md index 679c577..1e82532 100644 --- a/skills/perl-security/SKILL.md +++ b/skills/perl-security/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Comprehensive security guidelines for Perl applications covering input validation, injection prevention, and secure coding practices. -## When to Activate +## When to Use - Handling user input in Perl applications - Building Perl web applications (CGI, Mojolicious, Dancer2, Catalyst) diff --git a/skills/perl-testing/SKILL.md b/skills/perl-testing/SKILL.md index 7029916..6eeea8b 100644 --- a/skills/perl-testing/SKILL.md +++ b/skills/perl-testing/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Comprehensive testing strategies for Perl applications using Test2::V0, Test::More, prove, and TDD methodology. -## When to Activate +## When to Use - Writing new Perl code (follow TDD: red, green, refactor) - Designing test suites for Perl modules or applications diff --git a/skills/postgres-patterns/SKILL.md b/skills/postgres-patterns/SKILL.md index c80ff65..3b9593b 100644 --- a/skills/postgres-patterns/SKILL.md +++ b/skills/postgres-patterns/SKILL.md @@ -7,7 +7,7 @@ description: PostgreSQL database patterns for query optimization, schema design, Quick reference for PostgreSQL best practices. For detailed guidance, use the `database-reviewer` agent. -## When to Activate +## When to Use - Writing SQL queries or migrations - Designing database schemas diff --git a/skills/python-patterns/SKILL.md b/skills/python-patterns/SKILL.md index c86e4d4..2a2e72e 100644 --- a/skills/python-patterns/SKILL.md +++ b/skills/python-patterns/SKILL.md @@ -7,7 +7,7 @@ description: Pythonic idioms, PEP 8 standards, type hints, and best practices fo Idiomatic Python patterns and best practices for building robust, efficient, and maintainable applications. -## When to Activate +## When to Use - Writing new Python code - Reviewing Python code diff --git a/skills/python-testing/SKILL.md b/skills/python-testing/SKILL.md index 8b10024..3a7d982 100644 --- a/skills/python-testing/SKILL.md +++ b/skills/python-testing/SKILL.md @@ -7,7 +7,7 @@ description: Python testing strategies using pytest, TDD methodology, fixtures, Comprehensive testing strategies for Python applications using pytest, TDD methodology, and best practices. -## When to Activate +## When to Use - Writing new Python code (follow TDD: red, green, refactor) - Designing test suites for Python projects diff --git a/skills/pytorch-patterns/SKILL.md b/skills/pytorch-patterns/SKILL.md index 8b56d81..c022933 100644 --- a/skills/pytorch-patterns/SKILL.md +++ b/skills/pytorch-patterns/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Idiomatic PyTorch patterns and best practices for building robust, efficient, and reproducible deep learning applications. -## When to Activate +## When to Use - Writing new PyTorch models or training scripts - Reviewing deep learning code diff --git a/skills/regex-vs-llm-structured-text/SKILL.md b/skills/regex-vs-llm-structured-text/SKILL.md index 900957d..eaf0210 100644 --- a/skills/regex-vs-llm-structured-text/SKILL.md +++ b/skills/regex-vs-llm-structured-text/SKILL.md @@ -8,7 +8,7 @@ origin: ECC A practical decision framework for parsing structured text (quizzes, forms, invoices, documents). The key insight: regex handles 95-98% of cases cheaply and deterministically. Reserve expensive LLM calls for the remaining edge cases. -## When to Activate +## When to Use - Parsing structured text with repeating patterns (questions, forms, tables) - Deciding between regex and LLM for text extraction diff --git a/skills/santa-method/SKILL.md b/skills/santa-method/SKILL.md index 77a9ac8..93332e4 100644 --- a/skills/santa-method/SKILL.md +++ b/skills/santa-method/SKILL.md @@ -10,7 +10,7 @@ Multi-agent adversarial verification framework. Make a list, check it twice. If The core insight: a single agent reviewing its own output shares the same biases, knowledge gaps, and systematic errors that produced the output. Two independent reviewers with no shared context break this failure mode. -## When to Activate +## When to Use Invoke this skill when: - Output will be published, deployed, or consumed by end users diff --git a/skills/security-review/SKILL.md b/skills/security-review/SKILL.md index 26cfaf6..b3ade08 100644 --- a/skills/security-review/SKILL.md +++ b/skills/security-review/SKILL.md @@ -7,7 +7,7 @@ description: Use this skill when adding authentication, handling user input, wor This skill ensures all code follows security best practices and identifies potential vulnerabilities. -## When to Activate +## When to Use - Implementing authentication or authorization - Handling user input or file uploads diff --git a/skills/security-review/cloud-infrastructure-security.md b/skills/security-review/cloud-infrastructure-security.md index 24e9ec2..3c6f457 100644 --- a/skills/security-review/cloud-infrastructure-security.md +++ b/skills/security-review/cloud-infrastructure-security.md @@ -6,7 +6,7 @@ This skill ensures cloud infrastructure, CI/CD pipelines, and deployment configurations follow security best practices and comply with industry standards. -## When to Activate +## When to Use - Deploying applications to cloud platforms (AWS, Vercel, Railway, Cloudflare) - Configuring IAM roles and permissions diff --git a/skills/security-scan/SKILL.md b/skills/security-scan/SKILL.md index dba372e..1603ea0 100644 --- a/skills/security-scan/SKILL.md +++ b/skills/security-scan/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Audit your Claude Code configuration for security issues using [AgentShield](https://github.com/affaan-m/agentshield). -## When to Activate +## When to Use - Setting up a new Claude Code project - After modifying `.claude/settings.json`, `CLAUDE.md`, or MCP configs diff --git a/skills/skill-comply/SKILL.md b/skills/skill-comply/SKILL.md index 0995dc0..577eb45 100644 --- a/skills/skill-comply/SKILL.md +++ b/skills/skill-comply/SKILL.md @@ -21,7 +21,7 @@ Measures whether coding agents actually follow skills, rules, or agent definitio - **Rules** (`rules/common/*.md`): Mandatory rules like testing.md, security.md, git-workflow.md - **Agent definitions** (`agents/*.md`): Whether an agent gets invoked when expected (internal workflow verification not yet supported) -## When to Activate +## When to Use - User runs `/skill-comply ` - User asks "is this rule actually being followed?" diff --git a/skills/swift-actor-persistence/SKILL.md b/skills/swift-actor-persistence/SKILL.md index 3bb573c..c693667 100644 --- a/skills/swift-actor-persistence/SKILL.md +++ b/skills/swift-actor-persistence/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Patterns for building thread-safe data persistence layers using Swift actors. Combines in-memory caching with file-backed storage, leveraging the actor model to eliminate data races at compile time. -## When to Activate +## When to Use - Building a data persistence layer in Swift 5.5+ - Need thread-safe access to shared mutable state diff --git a/skills/swift-concurrency-6-2/SKILL.md b/skills/swift-concurrency-6-2/SKILL.md index d9864cc..f2ca368 100644 --- a/skills/swift-concurrency-6-2/SKILL.md +++ b/skills/swift-concurrency-6-2/SKILL.md @@ -7,7 +7,7 @@ description: Swift 6.2 Approachable Concurrency — single-threaded by default, Patterns for adopting Swift 6.2's concurrency model where code runs single-threaded by default and concurrency is introduced explicitly. Eliminates common data-race errors without sacrificing performance. -## When to Activate +## When to Use - Migrating Swift 5.x or 6.0/6.1 projects to Swift 6.2 - Resolving data-race safety compiler errors diff --git a/skills/swift-protocol-di-testing/SKILL.md b/skills/swift-protocol-di-testing/SKILL.md index 658f78d..8083c9c 100644 --- a/skills/swift-protocol-di-testing/SKILL.md +++ b/skills/swift-protocol-di-testing/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Patterns for making Swift code testable by abstracting external dependencies (file system, network, iCloud) behind small, focused protocols. Enables deterministic tests without I/O. -## When to Activate +## When to Use - Writing Swift code that accesses file system, network, or external APIs - Need to test error handling paths without triggering real failures diff --git a/skills/swiftui-patterns/SKILL.md b/skills/swiftui-patterns/SKILL.md index d0972c3..b98bbe9 100644 --- a/skills/swiftui-patterns/SKILL.md +++ b/skills/swiftui-patterns/SKILL.md @@ -7,7 +7,7 @@ description: SwiftUI architecture patterns, state management with @Observable, v Modern SwiftUI patterns for building declarative, performant user interfaces on Apple platforms. Covers the Observation framework, view composition, type-safe navigation, and performance optimization. -## When to Activate +## When to Use - Building SwiftUI views and managing state (`@State`, `@Observable`, `@Binding`) - Designing navigation flows with `NavigationStack` diff --git a/skills/tdd-workflow/SKILL.md b/skills/tdd-workflow/SKILL.md index e7ae073..08fc0a9 100644 --- a/skills/tdd-workflow/SKILL.md +++ b/skills/tdd-workflow/SKILL.md @@ -7,7 +7,7 @@ description: Use this skill when writing new features, fixing bugs, or refactori This skill ensures all code development follows TDD principles with comprehensive test coverage. -## When to Activate +## When to Use - Writing new features or functionality - Fixing bugs or issues diff --git a/skills/video-editing/SKILL.md b/skills/video-editing/SKILL.md index 7dd6041..e9665eb 100644 --- a/skills/video-editing/SKILL.md +++ b/skills/video-editing/SKILL.md @@ -8,7 +8,7 @@ origin: ECC AI-assisted editing for real footage. Not generation from prompts. Editing existing video fast. -## When to Activate +## When to Use - User wants to edit, cut, or structure video footage - Turning long recordings into short-form content diff --git a/skills/x-api/SKILL.md b/skills/x-api/SKILL.md index 23346c4..4c68076 100644 --- a/skills/x-api/SKILL.md +++ b/skills/x-api/SKILL.md @@ -8,7 +8,7 @@ origin: ECC Programmatic interaction with X (Twitter) for posting, reading, searching, and analytics. -## When to Activate +## When to Use - User wants to post tweets or threads programmatically - Reading timeline, mentions, or user data from X From 2577c972c4b579e57ac0003d8342a9d41306b8b3 Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:09:27 +0900 Subject: [PATCH 23/25] refactor: disable command shim generation for extension installs to prevent namespace conflicts and remove stale shims during setup --- install.sh | 24 ++----- scripts/hooks/session-start.js | 116 +++++++++++++++------------------ 2 files changed, 59 insertions(+), 81 deletions(-) diff --git a/install.sh b/install.sh index ada251e..d9e9db2 100755 --- a/install.sh +++ b/install.sh @@ -90,29 +90,19 @@ install_gemini_cli() { rm -rf "$GEMINI_CLI_DIR/scripts/ci" fi - # Generate command shims for short aliases - echo "Generating command shims (aliases)..." - echo " This allows using short commands like /tdd instead of /everything-gemini-code.tdd" - mkdir -p "$GEMINI_CLI_DIR/commands" - if [ -d "commands" ]; then + # Clean up any stale command shims that would conflict with the extension + echo "Cleaning up stale command shims..." + if [ -d "commands" ] && [ -d "$GEMINI_CLI_DIR/commands" ]; then for cmd_file in commands/*.toml; do target_file="$GEMINI_CLI_DIR/commands/$(basename "$cmd_file")" - # Copy original file - cp "$cmd_file" "$target_file" - - # Replace agent references with namespaced versions - # e.g., @tdd-guide -> @everything-gemini-code.tdd-guide - if [ -d "agents" ]; then - for agent_file in agents/*.md; do - agent_name=$(basename "$agent_file" .md) - perl -i -pe "s/\\@$agent_name/\\@everything-gemini-code.$agent_name/g" "$target_file" - done + if [ -f "$target_file" ]; then + rm -f "$target_file" + echo " Removed stale shim: $(basename "$target_file")" fi - echo " Created shim: $(basename "$target_file")" done fi - echo "Cleanup complete. Global shims updated." + echo "Cleanup complete." echo "" return fi diff --git a/scripts/hooks/session-start.js b/scripts/hooks/session-start.js index 5ede45f..8eca0ae 100644 --- a/scripts/hooks/session-start.js +++ b/scripts/hooks/session-start.js @@ -65,82 +65,70 @@ runHook('SessionStart', async () => { log(getSelectionPrompt()); } - // Ensure command shims exist (for short aliases like /tdd) + // Command shims: only needed for manual installs (no extension). + // When the extension is installed, Gemini CLI loads commands directly + // from the extension directory. Creating shims would cause conflicts + // (every command gets renamed to /everything-gemini-code:xxx and /user.xxx). try { const fs = require('fs'); const path = require('path'); const geminiDir = getGeminiDir(); - const globalCmdDir = path.join(geminiDir, 'commands'); - - // Extension root is ../.. from this script - const extDir = path.resolve(__dirname, '..', '..'); - const extCmdDir = path.join(extDir, 'commands'); - const agentsDir = path.join(extDir, 'agents'); - - if (fs.existsSync(extCmdDir)) { - ensureDir(globalCmdDir); - - const cmdFiles = fs.readdirSync(extCmdDir).filter(f => f.endsWith('.toml')); - - // Get list of agents to replace references - let agentNames = []; - if (fs.existsSync(agentsDir)) { - agentNames = fs.readdirSync(agentsDir) - .filter(f => f.endsWith('.md')) - .map(f => f.replace('.md', '')); - } - - for (const file of cmdFiles) { - const globalFile = path.join(globalCmdDir, file); - let needsUpdate = !fs.existsSync(globalFile); - - // If it exists, check if content matches extension perfectly - // This ensures any updates (syntax fixes, logic changes) are propagated - if (!needsUpdate) { - try { - const globalContent = fs.readFileSync(globalFile, 'utf8'); - const extContent = fs.readFileSync(path.join(extCmdDir, file), 'utf8'); - - // We need to compare potential namespace injection too? - // The shim logic modifies content to inject namespaces. - // So we can't just compare raw texts if we transform it. - - // Let's generate the expected content - let expectedContent = extContent; - for (const agent of agentNames) { - expectedContent = expectedContent.replace( - new RegExp(`@${agent}\\b`, 'g'), - `@everything-gemini-code.${agent}` - ); - } - - if (globalContent !== expectedContent) { - needsUpdate = true; + const extInstalledDir = path.join(geminiDir, 'extensions', 'everything-gemini-code'); + const isExtensionInstall = fs.existsSync(extInstalledDir); + + if (isExtensionInstall) { + // Clean up stale shims from previous installs to avoid conflicts + const globalCmdDir = path.join(geminiDir, 'commands'); + if (fs.existsSync(globalCmdDir)) { + const extDir = path.resolve(__dirname, '..', '..'); + const extCmdDir = path.join(extDir, 'commands'); + if (fs.existsSync(extCmdDir)) { + const extCmds = new Set(fs.readdirSync(extCmdDir).filter(f => f.endsWith('.toml'))); + for (const file of fs.readdirSync(globalCmdDir).filter(f => f.endsWith('.toml'))) { + if (extCmds.has(file)) { + fs.unlinkSync(path.join(globalCmdDir, file)); + log(`[SessionStart] Removed stale shim: ${file}`); } - } catch (_e) { - needsUpdate = true; } } - - if (needsUpdate) { - const content = fs.readFileSync(path.join(extCmdDir, file), 'utf8'); - let newContent = content; - - // Replace @agent-name with @everything-gemini-code.agent-name - for (const agent of agentNames) { - newContent = newContent.replace( - new RegExp(`@${agent}\\b`, 'g'), - `@everything-gemini-code.${agent}` - ); + } + } else { + // Manual install: create shims so short aliases like /tdd work + const globalCmdDir = path.join(geminiDir, 'commands'); + const extDir = path.resolve(__dirname, '..', '..'); + const extCmdDir = path.join(extDir, 'commands'); + const agentsDir = path.join(extDir, 'agents'); + + if (fs.existsSync(extCmdDir)) { + ensureDir(globalCmdDir); + const cmdFiles = fs.readdirSync(extCmdDir).filter(f => f.endsWith('.toml')); + + let agentNames = []; + if (fs.existsSync(agentsDir)) { + agentNames = fs.readdirSync(agentsDir) + .filter(f => f.endsWith('.md')) + .map(f => f.replace('.md', '')); + } + + for (const file of cmdFiles) { + const globalFile = path.join(globalCmdDir, file); + if (!fs.existsSync(globalFile)) { + const content = fs.readFileSync(path.join(extCmdDir, file), 'utf8'); + let newContent = content; + for (const agent of agentNames) { + newContent = newContent.replace( + new RegExp(`@${agent}\\b`, 'g'), + `@everything-gemini-code.${agent}` + ); + } + fs.writeFileSync(globalFile, newContent); + log(`[SessionStart] Created shim: ${file}`); } - - fs.writeFileSync(globalFile, newContent); - log(`[SessionStart] Created/Updated shim: ${file}`); } } } } catch (err) { - log(`[SessionStart] Warning: Failed to generate shims: ${err.message}`); + log(`[SessionStart] Warning: Shim management failed: ${err.message}`); } }); From 6be1e6633ccac9e1c1d9054ac0abd8346f07272d Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:42:46 +0900 Subject: [PATCH 24/25] refactor: rename "When to Use" headers to "Ideal For" across all skill documentation files --- skills/content-hash-cache-pattern/SKILL.md | 2 +- skills/cost-aware-llm-pipeline/SKILL.md | 2 +- skills/foundation-models-on-device/SKILL.md | 2 +- skills/liquid-glass-design/SKILL.md | 2 +- skills/regex-vs-llm-structured-text/SKILL.md | 2 +- skills/swift-actor-persistence/SKILL.md | 2 +- skills/swift-concurrency-6-2/SKILL.md | 2 +- skills/swift-protocol-di-testing/SKILL.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/skills/content-hash-cache-pattern/SKILL.md b/skills/content-hash-cache-pattern/SKILL.md index adf8119..b980bec 100644 --- a/skills/content-hash-cache-pattern/SKILL.md +++ b/skills/content-hash-cache-pattern/SKILL.md @@ -147,7 +147,7 @@ def extract_text(path, *, cache_enabled=False, cache_dir=None): data = dataclasses.asdict(entry) # Use manual serialization instead ``` -## When to Use +## Ideal For - File processing pipelines (PDF parsing, OCR, text extraction, image analysis) - CLI tools that benefit from `--cache/--no-cache` options diff --git a/skills/cost-aware-llm-pipeline/SKILL.md b/skills/cost-aware-llm-pipeline/SKILL.md index f97028a..a469755 100644 --- a/skills/cost-aware-llm-pipeline/SKILL.md +++ b/skills/cost-aware-llm-pipeline/SKILL.md @@ -175,7 +175,7 @@ def process(text: str, config: Config, tracker: CostTracker) -> tuple[Result, Co - Hardcoding model names throughout the codebase (use constants or config) - Ignoring prompt caching for repetitive system prompts -## When to Use +## Ideal For - Any application calling Claude, OpenAI, or similar LLM APIs - Batch processing pipelines where cost adds up quickly diff --git a/skills/foundation-models-on-device/SKILL.md b/skills/foundation-models-on-device/SKILL.md index af6dbba..f12a485 100644 --- a/skills/foundation-models-on-device/SKILL.md +++ b/skills/foundation-models-on-device/SKILL.md @@ -234,7 +234,7 @@ var body: some View { - Building complex multi-step logic in a single prompt — break into multiple focused prompts - Assuming the model is always available — device eligibility and settings vary -## When to Use +## Ideal For - On-device text generation for privacy-sensitive apps - Structured data extraction from user input (forms, natural language commands) diff --git a/skills/liquid-glass-design/SKILL.md b/skills/liquid-glass-design/SKILL.md index 79cae12..828f9e1 100644 --- a/skills/liquid-glass-design/SKILL.md +++ b/skills/liquid-glass-design/SKILL.md @@ -270,7 +270,7 @@ VStack { /* content */ } - Ignoring accented rendering mode in widgets — breaks tinted Home Screen appearance - Using opaque backgrounds behind glass — defeats the translucency effect -## When to Use +## Ideal For - Navigation bars, toolbars, and tab bars with the new iOS 26 design - Floating action buttons and card-style containers diff --git a/skills/regex-vs-llm-structured-text/SKILL.md b/skills/regex-vs-llm-structured-text/SKILL.md index eaf0210..e734b1b 100644 --- a/skills/regex-vs-llm-structured-text/SKILL.md +++ b/skills/regex-vs-llm-structured-text/SKILL.md @@ -211,7 +211,7 @@ From a production quiz parsing pipeline (410 items): - Mutating parsed objects during cleaning/validation steps - Not testing edge cases (malformed input, missing fields, encoding issues) -## When to Use +## Ideal For - Quiz/exam question parsing - Form data extraction diff --git a/skills/swift-actor-persistence/SKILL.md b/skills/swift-actor-persistence/SKILL.md index c693667..e4a19b7 100644 --- a/skills/swift-actor-persistence/SKILL.md +++ b/skills/swift-actor-persistence/SKILL.md @@ -135,7 +135,7 @@ final class QuestionListViewModel { - Forgetting that all actor method calls are `await` — callers must handle async context - Using `nonisolated` to bypass actor isolation (defeats the purpose) -## When to Use +## Ideal For - Local data storage in iOS/macOS apps (user data, settings, cached content) - Offline-first architectures that sync to a server later diff --git a/skills/swift-concurrency-6-2/SKILL.md b/skills/swift-concurrency-6-2/SKILL.md index f2ca368..dc449ed 100644 --- a/skills/swift-concurrency-6-2/SKILL.md +++ b/skills/swift-concurrency-6-2/SKILL.md @@ -207,7 +207,7 @@ To use `@concurrent`: - Fighting the compiler — if it reports a data race, the code has a real concurrency issue - Assuming all async code runs in the background (Swift 6.2 default: stays on calling actor) -## When to Use +## Ideal For - All new Swift 6.2+ projects (Approachable Concurrency is the recommended default) - Migrating existing apps from Swift 5.x or 6.0/6.1 concurrency diff --git a/skills/swift-protocol-di-testing/SKILL.md b/skills/swift-protocol-di-testing/SKILL.md index 8083c9c..11a35b4 100644 --- a/skills/swift-protocol-di-testing/SKILL.md +++ b/skills/swift-protocol-di-testing/SKILL.md @@ -182,7 +182,7 @@ func testReadError() async { - Forgetting `Sendable` conformance when used with actors - Over-engineering: if a type has no external dependencies, it doesn't need a protocol -## When to Use +## Ideal For - Any Swift code that touches file system, network, or external APIs - Testing error handling paths that are hard to trigger in real environments From 7b7aadfab792119b8c893fe4a2f3ff00fedba8ee Mon Sep 17 00:00:00 2001 From: Jamkris Date: Wed, 8 Apr 2026 10:43:08 +0900 Subject: [PATCH 25/25] refactor: improve hook execution reliability and normalize line ending parsing in validator --- scripts/lib/hook-utils.js | 10 ++++++---- scripts/lib/validator.js | 3 +-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/lib/hook-utils.js b/scripts/lib/hook-utils.js index 41a11d7..749cb7f 100644 --- a/scripts/lib/hook-utils.js +++ b/scripts/lib/hook-utils.js @@ -13,7 +13,7 @@ * @param {Function} fn - Async function containing hook logic */ function runHook(name, fn) { - fn().then(() => { + Promise.resolve(fn()).then(() => { process.exit(0); }).catch(err => { console.error(`[${name}] Error:`, err.message); @@ -29,12 +29,14 @@ function runHook(name, fn) { * @param {Function} fn - Function receiving stdin data string, must call console.log(data) when done */ function runStdinHook(name, fn) { - let data = ''; - process.stdin.on('data', chunk => { data += chunk; }); + const chunks = []; + process.stdin.on('data', chunk => { chunks.push(chunk); }); process.stdin.on('end', () => { + const data = Buffer.concat(chunks).toString(); try { fn(data); - } catch (_error) { + } catch (error) { + console.error(`[${name}] Hook failed:`, error.message); console.log(data); } }); diff --git a/scripts/lib/validator.js b/scripts/lib/validator.js index 08b44fd..6dbb5c8 100644 --- a/scripts/lib/validator.js +++ b/scripts/lib/validator.js @@ -1,4 +1,3 @@ -#!/usr/bin/env node /** * Common validation framework for CI scripts * @@ -21,7 +20,7 @@ function extractFrontmatter(content) { if (!match) return null; const frontmatter = {}; - const lines = match[1].split('\n'); + const lines = match[1].split(/\r?\n/); for (const line of lines) { const colonIdx = line.indexOf(':'); if (colonIdx > 0) {