diff --git a/CLAUDE.md b/CLAUDE.md index 4951bb3..0594c47 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -114,8 +114,8 @@ Skills are invoked with `/skill-name` in Claude Code: | `/tasks` | Create, load, or summarize tasks | "tasks", "list tasks", "add task" | | `/lisa` | Intelligent assistant for memory and tasks | "lisa", "hey lisa" | | `/jira` | Create and manage Jira issues | "jira", "create ticket" | -| `/git` | GitHub and Git workflow helpers | "create pr", "pr checks" | -| `/init-review` | Initial codebase review and summary | First session in a repo | +| `/github` | GitHub/Git workflow helpers, Issues, Projects | "create pr", "github issues", "bump version" | +| `/review` | Initial codebase review and summary | First session in a repo | Skills source: `src/project/.lisa/skills/` Skills deployed to: `.lisa/skills/` diff --git a/package.json b/package.json index 7cf02f3..3bd0014 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,12 @@ "./skills/memory": "./dist/lib/skills/memory/memory.js", "./skills/tasks": "./dist/lib/skills/tasks/tasks.js", "./skills/jira": "./dist/lib/skills/jira/jira.js", - "./skills/git/bump-version": "./dist/lib/skills/git/bump-version.js", + "./skills/github/bump-version": "./dist/lib/skills/github/bump-version.js", "./skills/lisa/storage": "./dist/lib/skills/lisa/storage.js", "./skills/lisa/compile-skills": "./dist/lib/skills/lisa/compile-skills.js", "./skills/prompt": "./dist/lib/skills/prompt/prompt.js", - "./skills/init-review": "./dist/lib/skills/init-review/init-review.js", - "./skills/init-review/ai-enrich": "./dist/lib/skills/init-review/ai-enrich.js" + "./skills/review": "./dist/lib/skills/review/init-review.js", + "./skills/review/ai-enrich": "./dist/lib/skills/review/ai-enrich.js" }, "engines": { "node": ">=18.0.0" diff --git a/scripts/deploy-lisa.js b/scripts/deploy-lisa.js index 4ac1f17..14ad293 100644 --- a/scripts/deploy-lisa.js +++ b/scripts/deploy-lisa.js @@ -441,7 +441,7 @@ async function main() { await fs.ensureDir(claudeSkillsDir); // Create individual symlinks for each Lisa skill (same pattern as OpenCode) - const lisaSkills = ['memory', 'tasks', 'lisa', 'git', 'jira', 'init-review', 'prompt']; + const lisaSkills = ['memory', 'tasks', 'lisa', 'jira', 'review', 'prompt', 'github', 'pr']; for (const skill of lisaSkills) { const skillLink = path.join(claudeSkillsDir, skill); const skillTarget = path.join(targetLisa, 'skills', skill); @@ -481,7 +481,7 @@ async function main() { const opencodeSkillsDir = path.join(targetOpenCode, 'skills'); await fs.ensureDir(opencodeSkillsDir); - const lisaSkills = ['memory', 'tasks', 'lisa', 'git', 'jira', 'init-review', 'prompt']; + const lisaSkills = ['memory', 'tasks', 'lisa', 'jira', 'review', 'prompt', 'github', 'pr']; for (const skill of lisaSkills) { const skillLink = path.join(opencodeSkillsDir, skill); const skillTarget = path.join(targetLisa, 'skills', skill); diff --git a/src/lib/commands/init.ts b/src/lib/commands/init.ts index d33f73a..f5656d6 100644 --- a/src/lib/commands/init.ts +++ b/src/lib/commands/init.ts @@ -480,6 +480,7 @@ export async function initCommand(opts: IInitOptions, services: ICliServices): P if (relativePath.includes('shared') || relativePath.includes('common')) return false; if (relativePath.includes('scripts')) return false; if (basename === 'SKILL.md' || basename === 'SKILL.local.md') return true; + if (basename.endsWith('.txt') || basename.endsWith('.json')) return true; if (basename === 'cache' || basename === '.gitkeep') return true; return fs.statSync(src).isDirectory(); @@ -502,6 +503,10 @@ export async function initCommand(opts: IInitOptions, services: ICliServices): P copies.push(services.templateCopier.copy('.lisa/rules/shared/clean-architecture.md', path.join(rulesDir, 'shared', 'clean-architecture.md'), replacements, force)); copies.push(services.templateCopier.copy('.lisa/rules/shared/code-quality-rules.md', path.join(rulesDir, 'shared', 'code-quality-rules.md'), replacements, force)); copies.push(services.templateCopier.copy('.lisa/rules/shared/testing-principles.md', path.join(rulesDir, 'shared', 'testing-principles.md'), replacements, force)); + copies.push(services.templateCopier.copy('.lisa/rules/shared/git-rules.md', path.join(rulesDir, 'shared', 'git-rules.md'), replacements, force)); + copies.push(services.templateCopier.copy('.lisa/rules/shared/git-rules.local.md', path.join(rulesDir, 'shared', 'git-rules.local.md'), replacements, force)); + copies.push(services.templateCopier.copy('.lisa/rules/shared/memory-rules.md', path.join(rulesDir, 'shared', 'memory-rules.md'), replacements, force)); + copies.push(services.templateCopier.copy('.lisa/rules/shared/task-rules.md', path.join(rulesDir, 'shared', 'task-rules.md'), replacements, force)); copies.push(services.templateCopier.copy('.lisa/rules/typescript/coding-standards.md', path.join(rulesDir, 'typescript', 'coding-standards.md'), replacements, force)); copies.push(services.templateCopier.copy('.lisa/rules/typescript/testing.md', path.join(rulesDir, 'typescript', 'testing.md'), replacements, force)); copies.push(services.templateCopier.copy('.lisa/rules/typescript/typescript-config-guide.md', path.join(rulesDir, 'typescript', 'typescript-config-guide.md'), replacements, force)); @@ -522,7 +527,7 @@ export async function initCommand(opts: IInitOptions, services: ICliServices): P await fs.ensureDir(claudeSkillsDir); - const lisaSkills = ['memory', 'tasks', 'lisa', 'git', 'jira', 'init-review', 'prompt', 'github']; + const lisaSkills = ['memory', 'tasks', 'lisa', 'jira', 'review', 'prompt', 'github', 'pr']; for (const skill of lisaSkills) { const skillLink = path.join(claudeSkillsDir, skill); const skillTarget = path.join(skillsDir, skill); @@ -583,7 +588,7 @@ export async function initCommand(opts: IInitOptions, services: ICliServices): P await fs.ensureDir(opencodeSkillsDir); - const lisaSkills = ['memory', 'tasks', 'lisa', 'git', 'jira', 'init-review', 'prompt']; + const lisaSkills = ['memory', 'tasks', 'lisa', 'jira', 'review', 'prompt', 'github', 'pr']; for (const skill of lisaSkills) { const skillLink = path.join(opencodeSkillsDir, skill); const skillTarget = path.join(skillsDir, skill); diff --git a/src/lib/commands/skills.ts b/src/lib/commands/skills.ts index a2f9de7..0d5657a 100644 --- a/src/lib/commands/skills.ts +++ b/src/lib/commands/skills.ts @@ -2,7 +2,7 @@ * Skill Passthrough Command Module * * Simple passthrough commands that delegate to skill scripts: - * jira, github, prompt, bump-version, init-review, compile-skills + * jira, github, prompt, bump-version, review, compile-skills */ import type {Command} from 'commander'; @@ -50,18 +50,18 @@ export function registerSkillCommands(program: Command): void { .allowUnknownOption() .action(async (_opts, cmd) => { const args = cmd.args || []; - const scriptPath = path.join(__dirname, '..', 'skills', 'git', 'bump-version.js'); + const scriptPath = path.join(__dirname, '..', 'skills', 'github', 'bump-version.js'); await spawnAndWait(scriptPath, args); }); - // Subcommand: lisa init-review + // Subcommand: lisa review program - .command('init-review') + .command('review') .description('Run initial codebase review') .allowUnknownOption() .action(async (_opts, cmd) => { const args = cmd.args || []; - const scriptPath = path.join(__dirname, '..', 'skills', 'init-review', 'init-review.js'); + const scriptPath = path.join(__dirname, '..', 'skills', 'review', 'init-review.js'); await spawnAndWait(scriptPath, args); }); diff --git a/src/lib/scanner/reviewer.ts b/src/lib/scanner/reviewer.ts index f9c812a..1f1bdfc 100644 --- a/src/lib/scanner/reviewer.ts +++ b/src/lib/scanner/reviewer.ts @@ -93,8 +93,8 @@ async function runInitReview(projectPath: string): Promise<{ // Look for init-review script in the project's .lisa folder // or in our dist/project location const possiblePaths = [ - path.join(projectPath, '.lisa', 'skills', 'init-review', 'scripts', 'init-review.js'), - path.join(__dirname, '..', '..', 'project', '.lisa', 'skills', 'init-review', 'scripts', 'init-review.js'), + path.join(projectPath, '.lisa', 'skills', 'review', 'scripts', 'init-review.js'), + path.join(__dirname, '..', '..', 'project', '.lisa', 'skills', 'review', 'scripts', 'init-review.js'), ]; let scriptPath: string | null = null; diff --git a/src/lib/skills/git/bump-version.ts b/src/lib/skills/git/bump-version.ts deleted file mode 100644 index daa67c7..0000000 --- a/src/lib/skills/git/bump-version.ts +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env node -/** - * Version Bump CLI - thin entry point. - * - * Usage: node bump-version.js [major|minor|patch] - * Default: minor - */ - -export {}; - -async function main(): Promise { - const { createVersionService } = await import('../shared/services'); - - const service = createVersionService(); - - try { - const bumpType = service.validateBumpType(process.argv[2] || 'minor'); - const result = service.bump(bumpType); - - console.log(JSON.stringify(result)); - console.error(`Bumped version: ${result.oldVersion} → ${result.newVersion} (${result.bumpType})`); - } catch (err: unknown) { - console.error(`Error: ${err instanceof Error ? err.message : String(err)}`); - process.exit(1); - } -} - -main(); diff --git a/src/lib/skills/github/bump-version.ts b/src/lib/skills/github/bump-version.ts new file mode 100644 index 0000000..4574564 --- /dev/null +++ b/src/lib/skills/github/bump-version.ts @@ -0,0 +1,52 @@ +#!/usr/bin/env node +/** + * Version Bump CLI - thin entry point. + * + * Usage: node bump-version.js [major|minor|patch] + * Default: minor + * + * Set LISA_AUTO_BUMP_VERSION in .lisa/.env to control behavior: + * true — enabled (default) + * false — disabled, skip with message + * patch|minor|major — enabled with that bump type as default + */ + +export {}; + +async function main(): Promise { + const { createVersionService } = await import('../shared/services'); + const { loadEnv } = await import('../shared/utils/env'); + + const env = loadEnv(); + const autoBump = env.raw['LISA_AUTO_BUMP_VERSION'] ?? 'true'; + + // Check if version bumping is disabled + if (autoBump.toLowerCase() === 'false') { + const result = { status: 'skipped', reason: 'LISA_AUTO_BUMP_VERSION is false' }; + console.log(JSON.stringify(result)); + console.error('Version bump skipped (LISA_AUTO_BUMP_VERSION=false)'); + return; + } + + const service = createVersionService(); + + try { + // Resolve bump type: CLI arg > env default > 'minor' + const explicitArg = process.argv[2]; + let defaultType = 'minor'; + if (['major', 'minor', 'patch'].includes(autoBump.toLowerCase())) { + defaultType = autoBump.toLowerCase(); + } + + const bumpType = service.validateBumpType(explicitArg || defaultType); + const result = service.bump(bumpType); + + console.log(JSON.stringify(result)); + console.error(`Bumped version: ${result.oldVersion} → ${result.newVersion} (${result.bumpType})`); + } catch (err: unknown) { + console.error(`Error: ${err instanceof Error ? err.message : String(err)}`); + process.exit(1); + } +} + +main(); diff --git a/src/lib/skills/init-review/ai-enrich.ts b/src/lib/skills/review/ai-enrich.ts similarity index 100% rename from src/lib/skills/init-review/ai-enrich.ts rename to src/lib/skills/review/ai-enrich.ts diff --git a/src/lib/skills/init-review/init-review.ts b/src/lib/skills/review/init-review.ts similarity index 100% rename from src/lib/skills/init-review/init-review.ts rename to src/lib/skills/review/init-review.ts diff --git a/src/project/.lisa/.env.template b/src/project/.lisa/.env.template index ab76654..3a9a9c1 100644 --- a/src/project/.lisa/.env.template +++ b/src/project/.lisa/.env.template @@ -25,3 +25,6 @@ NEO4J_DATABASE=neo4j # LLM API Keys # ANTHROPIC_API_KEY= # OPENAI_API_KEY= + +# Auto version bump on push (true, false, or default bump type: patch|minor|major) +# LISA_AUTO_BUMP_VERSION=true diff --git a/src/project/.lisa/skills/git/SKILL.md b/src/project/.lisa/skills/git/SKILL.md deleted file mode 100644 index abf74c8..0000000 --- a/src/project/.lisa/skills/git/SKILL.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -name: git -description: "GitHub and Git workflow helpers; triggers on 'create pr', 'pr checks', 'retrigger tests', 'bump version', 'push'." ---- - -## Purpose -Model-neutral helper for GitHub and Git workflows including PR management, CI triggers, version bumping, and branch operations. - -## Triggers -Use when the user says: "create a pr", "check pr status", "retrigger tests", "toggle test label", "pr checks", "bump version", "push to remote". - -## How to use - -### Check PR Status -```bash -# View PR checks -gh pr checks --repo - -# View PR details -gh pr view --repo -``` - -### Retrigger CI Tests -When a PR test fails and a fix is pushed, tests don't automatically re-run. Toggle the "TEST" label to trigger: - -```bash -# Remove and re-add TEST label to trigger CI -gh pr edit --repo --remove-label "TEST" -sleep 2 -gh pr edit --repo --add-label "TEST" -``` - -### Check CircleCI Pipeline Status -```bash -# Get latest pipeline for a branch -curl -s -H "Circle-Token: $(cat ~/.circleci/cli.yml | grep token | awk '{print $2}')" \ - "https://circleci.com/api/v2/project/gh///pipeline?branch=" \ - | jq '.items[0] | {number, state, created_at}' - -# Get workflow status for a pipeline -curl -s -H "Circle-Token: $(cat ~/.circleci/cli.yml | grep token | awk '{print $2}')" \ - "https://circleci.com/api/v2/pipeline//workflow" \ - | jq '.items[] | {name, status}' -``` - -### Poll CI Until Completion -```bash -# Poll current branch -lisa pr checks - -# Or use gh CLI directly -gh pr checks --watch -``` - -### Bump Version -Bump the semantic version in package.json before pushing: - -```bash -# Bump minor version (default): 1.2.3 → 1.3.0 -lisa bump-version - -# Bump patch version: 1.2.3 → 1.2.4 -lisa bump-version patch - -# Bump major version: 1.2.3 → 2.0.0 -lisa bump-version major -``` - -Output (JSON to stdout): -```json -{ - "status": "ok", - "bumpType": "minor", - "oldVersion": "1.2.3", - "newVersion": "1.3.0", - "file": "/path/to/package.json" -} -``` - -## Workflow: Push with Version Bump - -**When pushing changes to remote**, bump the version first: - -1. **Bump version** (default: minor): - ```bash - lisa bump-version - ``` - -2. **Commit the version bump**: - ```bash - git add package.json - git commit -m "chore: bump version to $(node -p "require('./package.json').version")" - ``` - -3. **Push to remote**: - ```bash - git push - ``` - -**One-liner for bump + commit + push**: -```bash -lisa bump-version && \ -git add package.json && \ -git commit -m "chore: bump version to $(node -p \"require('./package.json').version\")" && \ -git push -``` - -## Workflow: PR Created - -**When a Pull Request is created**, follow these steps: - -1. **Create the PR** with the TEST label: - ```bash - gh pr create --title "[TICKET-123] - Title" --body "..." --label "TEST" - ``` - -2. **Update Jira tickets** to "Code Review" status (see jira skill) - -3. **Monitor CI** - Check if tests pass: - ```bash - gh pr checks --repo - ``` - -## Workflow: PR Test Failure - -**When CI tests fail on a PR:** - -1. **Identify the failure** - Check CircleCI logs or GitHub checks -2. **Push a fix** - Commit and push the fix to the branch -3. **Retrigger tests** - Toggle the TEST label: - ```bash - gh pr edit --repo --remove-label "TEST" && \ - sleep 2 && \ - gh pr edit --repo --add-label "TEST" - ``` -4. **Monitor** - Watch for the new pipeline to complete - -## I/O Contract (examples) - -### PR Checks -``` -gh pr checks 1266 -Run linter pass 1m28s https://github.com/... -ci/circleci pass 5m12s https://circleci.com/... -``` - -### CircleCI Pipeline Status -```json -{ - "number": 6162, - "state": "created", - "created_at": "2026-01-13T17:27:10.963Z" -} -``` - -### CircleCI Workflow Status -```json -{ - "name": "test", - "status": "running" -} -``` - -## Cross-model checklist -- Claude: Use concise commands; prefer gh CLI for GitHub operations -- Gemini: Explicit commands; avoid model-specific tokens - -## Notes -- Requires `gh` CLI authenticated with GitHub -- Requires CircleCI CLI/token for pipeline status -- TEST label triggers CI workflow via GitHub Actions/CircleCI integration diff --git a/src/project/.lisa/skills/github/SKILL.md b/src/project/.lisa/skills/github/SKILL.md index 7bc0614..0f49401 100644 --- a/src/project/.lisa/skills/github/SKILL.md +++ b/src/project/.lisa/skills/github/SKILL.md @@ -1,11 +1,11 @@ --- name: github -description: "GitHub Issues and Projects v2 management via gh CLI; triggers on 'github', 'create issue', 'list issues', 'github project', 'project board', 'sync tasks'." +description: "GitHub and Git workflow helpers, Issues and Projects v2 management via gh CLI; triggers on 'github', 'create issue', 'list issues', 'github project', 'project board', 'sync tasks', 'create pr', 'pr checks', 'retrigger tests', 'bump version', 'push'." --- ## Purpose -Model-neutral helper to interact with GitHub Issues and Projects v2 using the gh CLI. Supports creating, listing, viewing, closing, and managing issues, managing GitHub Projects v2 boards, and bidirectional sync between Lisa tasks and GitHub Issues. +Model-neutral helper for GitHub and Git workflows including Issues, Projects v2, PR management, CI triggers, and version bumping. Uses the `gh` CLI. ## Triggers @@ -16,6 +16,7 @@ Use when the user says: - "github project", "project board", "kanban" - "add to project", "update project field", "move to column" - "sync tasks with github", "import github issues", "export tasks to github" +- "create a pr", "check pr status", "retrigger tests", "toggle test label", "pr checks", "bump version", "push to remote" ## Configuration @@ -398,18 +399,135 @@ lisa github sync --repo owner/repo lisa github sync --repo owner/repo --dry-run ``` +## Git Workflows + +### Check PR Status +```bash +# View PR checks +gh pr checks --repo + +# View PR details +gh pr view --repo +``` + +### Retrigger CI Tests +When a PR test fails and a fix is pushed, tests don't automatically re-run. Toggle the "TEST" label to trigger: + +```bash +# Remove and re-add TEST label to trigger CI +gh pr edit --repo --remove-label "TEST" +sleep 2 +gh pr edit --repo --add-label "TEST" +``` + +### Check CircleCI Pipeline Status + +**Prerequisites:** Set `CIRCLE_TOKEN` environment variable, or have CircleCI CLI configured at `~/.circleci/cli.yml`. + +```bash +# Get latest pipeline for a branch +curl -s -H "Circle-Token: ${CIRCLE_TOKEN}" \ + "https://circleci.com/api/v2/project/gh///pipeline?branch=" \ + | jq '.items[0] | {number, state, created_at}' + +# Get workflow status for a pipeline +curl -s -H "Circle-Token: ${CIRCLE_TOKEN}" \ + "https://circleci.com/api/v2/pipeline//workflow" \ + | jq '.items[] | {name, status}' +``` + +### Poll CI Until Completion +```bash +# Poll current branch +lisa pr checks + +# Or use gh CLI directly +gh pr checks --watch +``` + +### Bump Version +Bump the semantic version in package.json before pushing: + +```bash +# Bump minor version (default): 1.2.3 → 1.3.0 +lisa bump-version + +# Bump patch version: 1.2.3 → 1.2.4 +lisa bump-version patch + +# Bump major version: 1.2.3 → 2.0.0 +lisa bump-version major +``` + +#### Configuration + +Control version bumping via `LISA_AUTO_BUMP_VERSION` in `.lisa/.env`: + +| Value | Behavior | +|-------|----------| +| `true` (default) | Enabled, defaults to `minor` bump | +| `false` | Disabled, bump commands are skipped | +| `patch` / `minor` / `major` | Enabled with that bump type as the default | + +```bash +# In .lisa/.env: +LISA_AUTO_BUMP_VERSION=false # Disable version bumping +LISA_AUTO_BUMP_VERSION=patch # Default to patch bumps +``` + +A CLI argument always overrides the env default: `lisa bump-version major` bumps major regardless of the env setting. + +### Workflow: Push with Version Bump + +1. **Bump version** (default: minor): + + ```bash + lisa bump-version + ``` + +2. **Commit the version bump**: + + ```bash + git add package.json + git commit -m "chore: bump version to $(node -p "require('./package.json').version")" + ``` + +3. **Push to remote**: + + ```bash + git push + ``` + +### Workflow: PR Test Failure + +1. **Identify the failure** - Check CircleCI logs or GitHub checks +2. **Push a fix** - Commit and push the fix to the branch +3. **Retrigger tests** - Toggle the TEST label: + + ```bash + gh pr edit --repo --remove-label "TEST" && \ + sleep 2 && \ + gh pr edit --repo --add-label "TEST" + ``` +4. **Monitor** - Watch for the new pipeline to complete + ## Cross-model checklist + - Claude: Use JSON output for parsing; concise instructions - Gemini: Explicit commands; minimal formatting - All models: Always include --repo flag; parse JSON responses ## Notes + - Requires `gh` CLI v2.0+ or `GITHUB_TOKEN` environment variable +- Requires CircleCI CLI/token for pipeline status - Projects v2 uses GraphQL API (requires appropriate permissions) - Rate limits apply per GitHub API policies - `--repo` flag is always required (no auto-detection) +- TEST label triggers CI workflow via GitHub Actions/CircleCI integration ## See Also -- `/git` skill for PR creation, CI triggers, version bumping + +- `/pr` skill for PR creation, polling, and review comment workflows - `/jira` skill for Jira integration (similar command structure) - `/tasks` skill for Lisa's internal task management diff --git a/src/project/.lisa/skills/github/pr-description-template.txt b/src/project/.lisa/skills/github/pr-description-template.txt new file mode 100644 index 0000000..e4d694f --- /dev/null +++ b/src/project/.lisa/skills/github/pr-description-template.txt @@ -0,0 +1,8 @@ +## Summary +{{summary}} + +## Test plan +{{test_plan}} + +## Linked Issues +{{linked_issues}} diff --git a/src/project/.lisa/skills/pr/SKILL.md b/src/project/.lisa/skills/pr/SKILL.md index 3be9279..226e85b 100644 --- a/src/project/.lisa/skills/pr/SKILL.md +++ b/src/project/.lisa/skills/pr/SKILL.md @@ -516,5 +516,4 @@ lisa pr poll 50 - All: Neo4j must be running for watch/watching commands (lisa doctor to verify) ## Related Skills -- `/git` - For version bumping, CI retriggers, and other git workflows -- `/github` - For GitHub Issues and Projects operations +- `/github` - For GitHub Issues, Projects, version bumping, and CI retriggers diff --git a/src/project/.lisa/skills/pr/pr-description-template.txt b/src/project/.lisa/skills/pr/pr-description-template.txt new file mode 100644 index 0000000..e4d694f --- /dev/null +++ b/src/project/.lisa/skills/pr/pr-description-template.txt @@ -0,0 +1,8 @@ +## Summary +{{summary}} + +## Test plan +{{test_plan}} + +## Linked Issues +{{linked_issues}} diff --git a/src/project/.lisa/skills/init-review/SKILL.md b/src/project/.lisa/skills/review/SKILL.md similarity index 87% rename from src/project/.lisa/skills/init-review/SKILL.md rename to src/project/.lisa/skills/review/SKILL.md index 7128fbf..a00394e 100644 --- a/src/project/.lisa/skills/init-review/SKILL.md +++ b/src/project/.lisa/skills/review/SKILL.md @@ -1,11 +1,11 @@ -# Init Review Skill +# Review Skill ## Purpose -Automatically analyzes a codebase when Lisa is installed, creating a foundational memory of the project structure, technologies, and patterns. This init review serves as context for all future Claude sessions. +Automatically analyzes a codebase when Lisa is installed, creating a foundational memory of the project structure, technologies, and patterns. This review serves as context for all future Claude sessions. ## Triggers Use when the user says things like: -- "run init review" +- "run review" - "analyze this codebase" - "scan the project" - "what is this project about" @@ -14,7 +14,7 @@ Use when the user says things like: ## How to use ### Automatic (during npm install) -The init review runs automatically when Lisa is installed via `npm install @tonycasey/lisa`. It: +The review runs automatically when Lisa is installed via `npm install @tonycasey/lisa`. It: 1. Detects if the folder is a codebase 2. Runs static analysis (language, framework, structure) 3. Stores result as first memory @@ -22,14 +22,14 @@ The init review runs automatically when Lisa is installed via `npm install @tony ### Manual commands ```bash -# Run init review (or re-run with --force) -lisa init-review run [--force] +# Run review (or re-run with --force) +lisa review run [--force] -# Show current init review -lisa init-review show +# Show current review +lisa review show # Check status (done, enriched, etc.) -lisa init-review status +lisa review status ``` ## I/O contract diff --git a/tests/unit/src/lib/skills/git/bump-version.test.ts b/tests/unit/src/lib/skills/github/bump-version.test.ts similarity index 80% rename from tests/unit/src/lib/skills/git/bump-version.test.ts rename to tests/unit/src/lib/skills/github/bump-version.test.ts index 0afa962..b9f6b7f 100644 --- a/tests/unit/src/lib/skills/git/bump-version.test.ts +++ b/tests/unit/src/lib/skills/github/bump-version.test.ts @@ -13,8 +13,8 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; -// Path to the compiled script (now in dist/lib/skills/) -const SCRIPT_PATH = path.join(process.cwd(), 'dist', 'lib', 'skills', 'git', 'bump-version.js'); +// Path to the compiled script (in dist/lib/skills/github/) +const SCRIPT_PATH = path.join(process.cwd(), 'dist', 'lib', 'skills', 'github', 'bump-version.js'); // Create a temp directory for tests const TEST_DIR = path.join(os.tmpdir(), `lisa-bump-test-${Date.now()}`); @@ -25,13 +25,15 @@ const TEST_DIR = path.join(os.tmpdir(), `lisa-bump-test-${Date.now()}`); async function runBumpScript( args: string[] = [], cwd: string = TEST_DIR, - timeoutMs = 5000 + timeoutMs = 5000, + env: Record = {} ): Promise<{ stdout: string; stderr: string; exitCode: number }> { return new Promise((resolve, reject) => { const child = spawn('node', [SCRIPT_PATH, ...args], { cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: timeoutMs, + env: { ...process.env, ...env }, }); let stdout = ''; @@ -250,6 +252,56 @@ describe('bump-version script', () => { }); }); + describe('LISA_AUTO_BUMP_VERSION', () => { + it('should skip bump when set to false', async () => { + createPackageJson('1.0.0'); + + const result = await runBumpScript([], TEST_DIR, 5000, { + LISA_AUTO_BUMP_VERSION: 'false', + }); + + assert.strictEqual(result.exitCode, 0, 'Should exit with code 0'); + assert.strictEqual(readVersion(), '1.0.0', 'Version should not change'); + + const output = JSON.parse(result.stdout); + assert.strictEqual(output.status, 'skipped'); + assert.ok(result.stderr.includes('skipped'), 'stderr should mention skipped'); + }); + + it('should use env default bump type when set to patch', async () => { + createPackageJson('1.2.3'); + + const result = await runBumpScript([], TEST_DIR, 5000, { + LISA_AUTO_BUMP_VERSION: 'patch', + }); + + assert.strictEqual(result.exitCode, 0); + assert.strictEqual(readVersion(), '1.2.4', 'Should use patch bump from env'); + }); + + it('should allow CLI arg to override env default', async () => { + createPackageJson('1.2.3'); + + const result = await runBumpScript(['major'], TEST_DIR, 5000, { + LISA_AUTO_BUMP_VERSION: 'patch', + }); + + assert.strictEqual(result.exitCode, 0); + assert.strictEqual(readVersion(), '2.0.0', 'CLI arg should override env default'); + }); + + it('should treat unrecognized values as enabled with minor default', async () => { + createPackageJson('1.2.3'); + + const result = await runBumpScript([], TEST_DIR, 5000, { + LISA_AUTO_BUMP_VERSION: 'yes', + }); + + assert.strictEqual(result.exitCode, 0); + assert.strictEqual(readVersion(), '1.3.0', 'Should default to minor bump'); + }); + }); + describe('package.json in parent directory', () => { it('should find package.json in parent directory', async () => { createPackageJson('3.0.0');