Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5b98935
feat: add auto-review skill — post-implementation sidecar code review
ellisjr Mar 12, 2026
6c385fa
feat: add auto-unblock skill — sidecar brainstorming when stuck debug…
ellisjr Mar 12, 2026
9043a0d
feat: add auto-security skill — pre-commit sidecar security scan
ellisjr Mar 12, 2026
34aba52
fix: postinstall copies auto-skill subdirectories
ellisjr Mar 12, 2026
020a285
fix: derive AUTO_SKILLS dynamically from filesystem
ellisjr Mar 12, 2026
e4f257b
feat: add auto-bmad-method-check skill — sidecar review of BMAD artif…
ellisjr Mar 12, 2026
5165ae2
fix: address ChatGPT review findings for auto-bmad-method-check
ellisjr Mar 12, 2026
d0da1db
fix: address CodeRabbit nitpicks — code fence tags and defensive try-…
ellisjr Mar 12, 2026
f01b2bf
feat: add auto-skills section to main SKILL.md + invocation research
ellisjr Mar 12, 2026
2cf9967
feat: make auto-skills user-invocable via top-level installation
ellisjr Mar 12, 2026
e0b284b
docs: update auto-skill invocation research with completed work
ellisjr Mar 12, 2026
66f937d
chore: remove internal research doc from PR
ellisjr Mar 12, 2026
464de21
fix: remove blank line breaking markdown table in bmad-workflow.md
ellisjr Mar 12, 2026
4212dcc
feat: add activity-monitoring hooks for auto-skill triggers (Phase 1)
ellisjr Mar 12, 2026
e89f7ee
fix: address code review findings in activity-monitoring hooks
ellisjr Mar 12, 2026
54b85a3
fix: address sub-threshold code review findings
ellisjr Mar 12, 2026
efd18f4
fix: address all code review findings in activity-monitoring hooks
ellisjr Mar 12, 2026
c5231eb
fix: address sidecar review findings from Gemini Pro and Codex
ellisjr Mar 13, 2026
cb4e059
fix: address CodeRabbit review findings across security, bugs, and tests
ellisjr Mar 13, 2026
75a10de
fix: address CodeRabbit PR review comments
ellisjr Mar 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ module.exports = {
{
// CLI output files use console.log for user-facing output (not logging)
// These display results to the user, not debug info
files: ['src/sidecar/read.js', 'src/sidecar/session-utils.js'],
files: ['src/sidecar/read.js', 'src/sidecar/session-utils.js', 'src/cli-handlers.js'],
rules: {
'no-console': 'off'
}
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ jobs:
run: |
# Find previous tag
PREV_TAG=$(git tag --sort=-version:refname | grep -v "^${TAG_NAME}$" | head -1)

if [ -z "$PREV_TAG" ]; then
echo "No previous tag found. Skipping Claude-generated release notes."
exit 0
fi

echo "Generating notes for ${PREV_TAG}..${TAG_NAME}"

# Build context: commit log + diff stat + actual diff (truncated)
Expand Down Expand Up @@ -90,7 +96,7 @@ jobs:
role: "user",
content: ("Here are the commits from " + $prev_tag + " to " + $tag + ":\n\n" + $commits + "\n\nDiff stat:\n" + $diffstat + "\n\nActual diff (truncated):\n" + $diff + "\n\nChangelog link: https://github.com/" + $repo + "/compare/" + $prev_tag + "..." + $tag + "\n\n" + $prompt)
}]
}' | curl -s https://api.anthropic.com/v1/messages \
}' | curl -s --connect-timeout 10 --max-time 60 https://api.anthropic.com/v1/messages \
-H "content-type: application/json" \
-H "x-api-key: ${ANTHROPIC_API_KEY}" \
-H "anthropic-version: 2023-06-01" \
Expand Down
2 changes: 1 addition & 1 deletion .husky/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ if [ -n "$HEAD_SHA" ] && [ "$HEAD_SHA" = "$CACHED_SHA" ]; then
echo "Tests already passed for $HEAD_SHA — skipping."
else
echo "Running full test suite (unit + integration) before push..."
npm run test:all
npm run test:all || exit 1
fi

echo "Checking for dependency vulnerabilities..."
Expand Down
98 changes: 51 additions & 47 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ src/
│ ├── api-key-store.js # Maps provider IDs to environment variable names
│ ├── api-key-validation.js # Validation endpoints per provider
│ ├── auth-json.js # Known provider IDs that map to sidecar's PROVIDER_ENV_MAP
│ ├── auto-skills-config.js # Valid auto-skill names (keys in autoSkills config)
│ ├── config.js # Default model alias map — short names to full OpenRouter model identifiers
│ ├── logger.js # Structured Logger Module
│ ├── mcp-discovery.js # MCP Discovery - Discovers MCP servers from parent LLM configuration
Expand All @@ -116,6 +117,7 @@ src/
│ ├── updater.js # @type {import('update-notifier').UpdateNotifier|null}
│ └── validators.js # * Provider to API key mapping
├── cli-handlers.js # CLI Command Handlers
├── cli-usage.js # Commands section of usage text
├── cli.js # * Default values per spec §4.1
├── conflict.js # File Conflict Detection Module
├── context-compression.js # Context Compression Module
Expand Down Expand Up @@ -163,7 +165,8 @@ scripts/
├── generate-icon.js # Generate app icon PNG from SVG source.
├── integration-test.sh
├── list-models.js
├── postinstall.js # Install skill file to ~/.claude/skills/sidecar/
├── postinstall.js # Install skill files to ~/.claude/skills/
├── preuninstall.js # Pre-uninstall script for claude-sidecar
├── test-tools.sh
├── validate-docs.js # * Main entry point.
├── validate-thinking.js
Expand All @@ -190,51 +193,53 @@ evals/
<!-- AUTO:modules -->
| Module | Purpose | Key Exports |
|--------|---------|-------------|
| `cli-handlers.js` | CLI Command Handlers | `handleSetup()`, `handleAbort()`, `handleUpdate()`, `handleMcp()` |
| `cli.js` | * Default values per spec §4.1 | `parseArgs()`, `validateStartArgs()`, `getUsage()`, `DEFAULTS()` |
| `conflict.js` | File Conflict Detection Module | `detectConflicts()`, `formatConflictWarning()` |
| `context-compression.js` | Context Compression Module | `compressContext()`, `estimateTokenCount()`, `buildPreamble()`, `DEFAULT_TOKEN_LIMIT()` |
| `context.js` | Context Filtering Module | `filterContext()`, `parseDuration()`, `estimateTokens()`, `takeLastNTurns()` |
| `drift.js` | Context Drift Detection Module | `calculateDrift()`, `formatDriftWarning()`, `countTurnsSince()`, `isDriftSignificant()` |
| `environment.js` | Environment Detection Module | `inferClient()`, `getSessionRoot()`, `detectEnvironment()`, `VALID_CLIENTS()` |
| `headless.js` | * Default timeout: 15 minutes per spec §6.2 | `runHeadless()`, `waitForServer()`, `extractSummary()`, `formatFoldOutput()`, `DEFAULT_TIMEOUT()` |
| `index.js` | Claude Sidecar - Main Module | `APIs()`, `startSidecar()`, `listSidecars()`, `resumeSidecar()`, `continueSidecar()` |
| `jsonl-parser.js` | JSONL Parser | `parseJSONLLine()`, `readJSONL()`, `extractTimestamp()`, `formatMessage()`, `formatContext()` |
| `mcp-server.js` | @module mcp-server — Sidecar MCP Server (stdio transport) | `handlers()`, `startMcpServer()`, `getProjectDir()` |
| `mcp-tools.js` | Zod pattern for safe task IDs (alphanumeric, hyphens, underscores only) | `getTools()`, `getGuideText()`, `safeTaskId()`, `safeModel()` |
| `opencode-client.js` | OpenCode SDK Client Wrapper | `parseModelString()`, `createClient()`, `createSession()`, `createChildSession()`, `sendPrompt()` |
| `prompt-builder.js` | System Prompt Builder | `buildSystemPrompt()`, `buildPrompts()`, `buildEnvironmentSection()`, `getSummaryTemplate()`, `SUMMARY_TEMPLATE()` |
| `session-manager.js` | * Session status constants | `createSession()`, `updateSession()`, `getSession()`, `saveConversation()`, `saveSummary()` |
| `session.js` | Session Resolver | `encodeProjectPath()`, `decodeProjectPath()`, `getSessionDirectory()`, `getSessionId()`, `resolveSession()` |
| `prompts/cowork-agent-prompt.js` | Cowork Agent Prompt | `buildCoworkAgentPrompt()` |
| `sidecar/context-builder.js` | Context Builder Module | `buildContext()`, `parseDuration()`, `resolveSessionFile()`, `applyContextFilters()`, `findCoworkSession()` |
| `sidecar/continue.js` | Load previous session data (metadata, summary, conversation) | `loadPreviousSession()`, `buildContinuationContext()`, `createContinueSessionMetadata()`, `continueSidecar()` |
| `sidecar/crash-handler.js` | Crash Handler - Updates metadata to 'error' on uncaught exceptions | `installCrashHandler()` |
| `sidecar/interactive.js` | Check if Electron is available (lazy loading guard) | `getElectronPath()`, `checkElectronAvailable()`, `buildElectronEnv()`, `handleElectronProcess()`, `runInteractive()` |
| `sidecar/progress.js` | Lifecycle stage labels | `readProgress()`, `writeProgress()`, `extractLatest()`, `computeLastActivity()`, `STAGE_LABELS()` |
| `sidecar/read.js` | Sidecar Read Operations Module | `formatAge()`, `listSidecars()`, `readSidecar()` |
| `sidecar/resume.js` | Load session metadata from session directory | `loadSessionMetadata()`, `loadInitialContext()`, `checkFileDrift()`, `buildDriftWarning()`, `buildResumeUserMessage()` |
| `sidecar/session-utils.js` | Standard heartbeat interval in milliseconds | `HEARTBEAT_INTERVAL()`, `SessionPaths()`, `saveInitialContext()`, `finalizeSession()`, `outputSummary()` |
| `sidecar/setup-window.js` | Setup Window Launcher | `launchSetupWindow()` |
| `sidecar/setup.js` | Sidecar Setup Wizard | `addAlias()`, `createDefaultConfig()`, `detectApiKeys()`, `runInteractiveSetup()`, `runReadlineSetup()` |
| `sidecar/start.js` | Generate a unique 8-character hex task ID | `generateTaskId()`, `createSessionMetadata()`, `buildMcpConfig()`, `checkElectronAvailable()`, `runInteractive()` |
| `utils/agent-mapping.js` | * All OpenCode native agent names (lowercase) | `PRIMARY_AGENTS()`, `OPENCODE_AGENTS()`, `HEADLESS_SAFE_AGENTS()`, `mapAgentToOpenCode()`, `isValidAgent()` |
| `utils/alias-resolver.js` | Alias Resolver Utilities | `applyDirectApiFallback()`, `autoRepairAlias()` |
| `utils/api-key-store.js` | Maps provider IDs to environment variable names | `getEnvPath()`, `readApiKeys()`, `readApiKeyHints()`, `readApiKeyValues()`, `saveApiKey()` |
| `utils/api-key-validation.js` | Validation endpoints per provider | `validateApiKey()`, `validateOpenRouterKey()`, `VALIDATION_ENDPOINTS()` |
| `utils/auth-json.js` | Known provider IDs that map to sidecar's PROVIDER_ENV_MAP | `readAuthJsonKeys()`, `importFromAuthJson()`, `checkAuthJson()`, `removeFromAuthJson()`, `AUTH_JSON_PATH()` |
| `utils/config.js` | Default model alias map — short names to full OpenRouter model identifiers | `getConfigDir()`, `getConfigPath()`, `loadConfig()`, `saveConfig()`, `getDefaultAliases()` |
| `utils/logger.js` | Structured Logger Module | `logger()`, `LOG_LEVELS()` |
| `utils/mcp-discovery.js` | MCP Discovery - Discovers MCP servers from parent LLM configuration | `discoverParentMcps()`, `discoverClaudeCodeMcps()`, `discoverCoworkMcps()`, `normalizeMcpJson()` |
| `utils/mcp-validators.js` | MCP Validators | `validateMcpSpec()`, `validateMcpConfigFile()` |
| `utils/model-fetcher.js` | Hardcoded Anthropic models (no public listing endpoint) | `fetchModelsFromProvider()`, `fetchAllModels()`, `groupModelsByFamily()`, `ANTHROPIC_MODELS()`, `PROVIDER_FAMILY_NAMES()` |
| `utils/model-validator.js` | Alias-to-search-term mapping for filtering provider model lists | `validateDirectModel()`, `filterRelevantModels()`, `normalizeModelId()` |
| `utils/path-setup.js` | Ensures that the project's node_modules/.bin directory is included in the PATH. | `ensureNodeModulesBinInPath()` |
| `utils/server-setup.js` | Server Setup Utilities | `DEFAULT_PORT()`, `isPortInUse()`, `getPortPid()`, `killPortProcess()`, `ensurePortAvailable()` |
| `utils/start-helpers.js` | Start Command Helpers | `resolveModelFromArgs()`, `validateFallbackModel()` |
| `utils/thinking-validators.js` | Thinking Level Validators | `MODEL_THINKING_SUPPORT()`, `getSupportedThinkingLevels()`, `validateThinkingLevel()` |
| `utils/updater.js` | @type {import('update-notifier').UpdateNotifier|null} | `initUpdateCheck()`, `getUpdateInfo()`, `notifyUpdate()`, `performUpdate()` |
| `utils/validators.js` | * Provider to API key mapping | `VALID_AGENT_MODES()`, `PROVIDER_KEY_MAP()`, `MODEL_THINKING_SUPPORT()`, `TASK_ID_PATTERN()`, `validateTaskId()` |
| `cli-handlers.js` | CLI Command Handlers | `handleSetup`, `handleAbort`, `handleUpdate`, `handleMcp`, `handleAutoSkills` |
| `cli-usage.js` | Commands section of usage text | `getUsage` |
| `cli.js` | * Default values per spec §4.1 | `parseArgs`, `validateStartArgs`, `getUsage`, `DEFAULTS` |
| `conflict.js` | File Conflict Detection Module | `detectConflicts`, `formatConflictWarning` |
| `context-compression.js` | Context Compression Module | `compressContext`, `estimateTokenCount`, `buildPreamble`, `DEFAULT_TOKEN_LIMIT` |
| `context.js` | Context Filtering Module | `filterContext`, `parseDuration`, `estimateTokens`, `takeLastNTurns` |
| `drift.js` | Context Drift Detection Module | `calculateDrift`, `formatDriftWarning`, `countTurnsSince`, `isDriftSignificant` |
| `environment.js` | Environment Detection Module | `inferClient`, `getSessionRoot`, `detectEnvironment`, `VALID_CLIENTS` |
| `headless.js` | * Default timeout: 15 minutes per spec §6.2 | `runHeadless`, `waitForServer`, `extractSummary`, `formatFoldOutput`, `DEFAULT_TIMEOUT` |
| `index.js` | Claude Sidecar - Main Module | `APIs`, `startSidecar`, `listSidecars`, `resumeSidecar`, `continueSidecar` |
| `jsonl-parser.js` | JSONL Parser | `parseJSONLLine`, `readJSONL`, `extractTimestamp`, `formatMessage`, `formatContext` |
| `mcp-server.js` | @module mcp-server — Sidecar MCP Server (stdio transport) | `handlers`, `startMcpServer`, `getProjectDir` |
| `mcp-tools.js` | Zod pattern for safe task IDs (alphanumeric, hyphens, underscores only) | `getTools`, `getGuideText`, `safeTaskId`, `safeModel` |
| `opencode-client.js` | OpenCode SDK Client Wrapper | `parseModelString`, `createClient`, `createSession`, `createChildSession`, `sendPrompt` |
| `prompt-builder.js` | System Prompt Builder | `buildSystemPrompt`, `buildPrompts`, `buildEnvironmentSection`, `getSummaryTemplate`, `SUMMARY_TEMPLATE` |
| `session-manager.js` | * Session status constants | `createSession`, `updateSession`, `getSession`, `saveConversation`, `saveSummary` |
| `session.js` | Session Resolver | `encodeProjectPath`, `decodeProjectPath`, `getSessionDirectory`, `getSessionId`, `resolveSession` |
| `prompts/cowork-agent-prompt.js` | Cowork Agent Prompt | `buildCoworkAgentPrompt` |
| `sidecar/context-builder.js` | Context Builder Module | `buildContext`, `parseDuration`, `resolveSessionFile`, `applyContextFilters`, `findCoworkSession` |
| `sidecar/continue.js` | Load previous session data (metadata, summary, conversation) | `loadPreviousSession`, `buildContinuationContext`, `createContinueSessionMetadata`, `continueSidecar` |
| `sidecar/crash-handler.js` | Crash Handler - Updates metadata to 'error' on uncaught exceptions | `installCrashHandler` |
| `sidecar/interactive.js` | Check if Electron is available (lazy loading guard) | `getElectronPath`, `checkElectronAvailable`, `buildElectronEnv`, `handleElectronProcess`, `runInteractive` |
| `sidecar/progress.js` | Lifecycle stage labels | `readProgress`, `writeProgress`, `extractLatest`, `computeLastActivity`, `STAGE_LABELS` |
| `sidecar/read.js` | Sidecar Read Operations Module | `formatAge`, `listSidecars`, `readSidecar` |
| `sidecar/resume.js` | Load session metadata from session directory | `loadSessionMetadata`, `loadInitialContext`, `checkFileDrift`, `buildDriftWarning`, `buildResumeUserMessage` |
| `sidecar/session-utils.js` | Standard heartbeat interval in milliseconds | `HEARTBEAT_INTERVAL`, `SessionPaths`, `saveInitialContext`, `finalizeSession`, `outputSummary` |
| `sidecar/setup-window.js` | Setup Window Launcher | `launchSetupWindow` |
| `sidecar/setup.js` | Sidecar Setup Wizard | `addAlias`, `createDefaultConfig`, `detectApiKeys`, `runInteractiveSetup`, `runReadlineSetup` |
| `sidecar/start.js` | Generate a unique 8-character hex task ID | `generateTaskId`, `createSessionMetadata`, `buildMcpConfig`, `checkElectronAvailable`, `runInteractive` |
| `utils/agent-mapping.js` | * All OpenCode native agent names (lowercase) | `PRIMARY_AGENTS`, `OPENCODE_AGENTS`, `HEADLESS_SAFE_AGENTS`, `mapAgentToOpenCode`, `isValidAgent` |
| `utils/alias-resolver.js` | Alias Resolver Utilities | `applyDirectApiFallback`, `autoRepairAlias` |
| `utils/api-key-store.js` | Maps provider IDs to environment variable names | `getEnvPath`, `readApiKeys`, `readApiKeyHints`, `readApiKeyValues`, `saveApiKey` |
| `utils/api-key-validation.js` | Validation endpoints per provider | `validateApiKey`, `validateOpenRouterKey`, `VALIDATION_ENDPOINTS` |
| `utils/auth-json.js` | Known provider IDs that map to sidecar's PROVIDER_ENV_MAP | `readAuthJsonKeys`, `importFromAuthJson`, `checkAuthJson`, `removeFromAuthJson`, `AUTH_JSON_PATH` |
| `utils/auto-skills-config.js` | Valid auto-skill names (keys in autoSkills config) | `VALID_SKILL_NAMES`, `SKILL_LABELS`, `getAutoSkillsConfig`, `isSkillEnabled`, `isMonitoringEnabled` |
| `utils/config.js` | Default model alias map — short names to full OpenRouter model identifiers | `getConfigDir`, `getConfigPath`, `loadConfig`, `saveConfig`, `getDefaultAliases` |
| `utils/logger.js` | Structured Logger Module | `logger`, `LOG_LEVELS` |
| `utils/mcp-discovery.js` | MCP Discovery - Discovers MCP servers from parent LLM configuration | `discoverParentMcps`, `discoverClaudeCodeMcps`, `discoverCoworkMcps`, `normalizeMcpJson` |
| `utils/mcp-validators.js` | MCP Validators | `validateMcpSpec`, `validateMcpConfigFile` |
| `utils/model-fetcher.js` | Hardcoded Anthropic models (no public listing endpoint) | `fetchModelsFromProvider`, `fetchAllModels`, `groupModelsByFamily`, `ANTHROPIC_MODELS`, `PROVIDER_FAMILY_NAMES` |
| `utils/model-validator.js` | Alias-to-search-term mapping for filtering provider model lists | `validateDirectModel`, `filterRelevantModels`, `normalizeModelId` |
| `utils/path-setup.js` | Ensures that the project's node_modules/.bin directory is included in the PATH. | `ensureNodeModulesBinInPath` |
| `utils/server-setup.js` | Server Setup Utilities | `DEFAULT_PORT`, `isPortInUse`, `getPortPid`, `killPortProcess`, `ensurePortAvailable` |
| `utils/start-helpers.js` | Start Command Helpers | `resolveModelFromArgs`, `validateFallbackModel` |
| `utils/thinking-validators.js` | Thinking Level Validators | `MODEL_THINKING_SUPPORT`, `getSupportedThinkingLevels`, `validateThinkingLevel` |
| `utils/updater.js` | @type {import('update-notifier').UpdateNotifier|null} | `initUpdateCheck`, `getUpdateInfo`, `notifyUpdate`, `performUpdate` |
| `utils/validators.js` | * Provider to API key mapping | `VALID_AGENT_MODES`, `PROVIDER_KEY_MAP`, `MODEL_THINKING_SUPPORT`, `TASK_ID_PATTERN`, `validateTaskId` |
<!-- /AUTO:modules -->

---
Expand Down Expand Up @@ -369,4 +374,3 @@ GEMINI.md and AGENTS.md are symlinks to CLAUDE.md -- no sync needed.
- [docs/electron-testing.md](docs/electron-testing.md) - CDP patterns
- [docs/jsdoc-setup.md](docs/jsdoc-setup.md) - JSDoc, `.d.ts` generation
- [evals/README.md](evals/README.md) - Agentic eval system
- [docs/plans/index.md](docs/plans/index.md) - Design plans
5 changes: 4 additions & 1 deletion bin/sidecar.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ if (process.env.GEMINI_API_KEY && !process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
const { parseArgs, validateStartArgs, getUsage } = require('../src/cli');
const { validateTaskId } = require('../src/utils/validators');
const { resolveModelFromArgs, validateFallbackModel } = require('../src/utils/start-helpers');
const { handleSetup, handleAbort, handleUpdate, handleMcp } = require('../src/cli-handlers');
const { handleSetup, handleAbort, handleUpdate, handleMcp, handleAutoSkills } = require('../src/cli-handlers');

const VERSION = require('../package.json').version;

Expand Down Expand Up @@ -103,6 +103,9 @@ async function main() {
case 'update':
await handleUpdate();
break;
case 'auto-skills':
await handleAutoSkills(args);
break;
default:
console.error(`Unknown command: ${command}`);
console.log(getUsage());
Expand Down
Loading