Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
d13c4d4
Update video link and add npm version/license badges
yigitkonur Feb 19, 2026
ebd8a96
chore: release v2.6.7 [skip publish]
github-actions[bot] Feb 19, 2026
288c76f
feat: add Factory Droid CLI support
yigitkonur Feb 19, 2026
059b910
test: add Droid fixtures and expand to 30 conversion paths
yigitkonur Feb 19, 2026
f457a5d
chore: bump to v2.7.0, update docs for Droid support
yigitkonur Feb 19, 2026
631b33a
Merge pull request #1 from yigitkonur/feat/droid-integration
yigitkonur Feb 19, 2026
487d59b
chore: release v2.7.1 [skip publish]
github-actions[bot] Feb 19, 2026
0a91977
feat: add Cursor AI support
Evrim267 Feb 19, 2026
94b80f5
fix: show clear error when only one CLI tool is installed
barisgirismen Feb 19, 2026
3d6943d
Merge pull request #3 from barisgirismen/fix/single-tool-error-message
yigitkonur Feb 20, 2026
0d19404
chore: release v2.7.2 [skip publish]
github-actions[bot] Feb 20, 2026
c34caf8
Merge pull request #2 from Evrim267/feat/cursor-support
yigitkonur Feb 20, 2026
bac655b
chore: release v2.7.3 [skip publish]
github-actions[bot] Feb 20, 2026
3ef8e7f
fix: resolve Cursor slug paths with dot-separated directory names
Evrim267 Feb 20, 2026
96bd8f0
Merge pull request #4 from Evrim267/feat/cursor-support
yigitkonur Feb 20, 2026
4b663e9
chore: release v2.7.4 [skip publish]
github-actions[bot] Feb 20, 2026
48d460d
refactor: introduce adapter registry pattern for extensibility
yigitkonur Feb 20, 2026
f383a76
ci: add beta publish workflow for develop branch
yigitkonur Feb 20, 2026
57ccd55
chore: release v2.7.5 [skip publish]
github-actions[bot] Feb 20, 2026
3a484e3
ci: auto-increment beta version on each develop push
yigitkonur Feb 20, 2026
7004738
fix: align ASCII banner letters to consistent 4-char widths
yigitkonur Feb 20, 2026
1fdc86e
feat: gradient banner with indigo-to-cyan color sweep
yigitkonur Feb 20, 2026
67b0fc0
feat!: v3.0.0 major refactor — typed schemas, library exports, CLI split
yigitkonur Feb 21, 2026
30b9e18
fix(ci): respect major version bumps in beta publish workflow
yigitkonur Feb 21, 2026
55eeb74
feat: add registry-driven cross-tool flag forwarding
yigitkonur Feb 21, 2026
3721b00
Merge branch 'main' into develop (resolve package.json conflict)
yigitkonur Feb 21, 2026
5f1b220
feat!: land v3 refactor on main + registry-driven cross-tool flag for…
yigitkonur Feb 21, 2026
d0babe7
chore: release v3.0.0 [skip publish]
github-actions[bot] Feb 21, 2026
d4a5cb2
feat: smart context display — tool-type-aware data capture and rendering
yigitkonur Feb 23, 2026
06cad63
docs: comprehensive CHANGELOG.md for v3.0.0 and v3.1.0
yigitkonur Feb 23, 2026
29034e7
fix: audit-driven improvements to smart context display
yigitkonur Feb 23, 2026
108a8b7
wip: auto-commit 2026-02-23 05:14:53
yigitkonur Feb 23, 2026
d1560cd
wip: auto-commit 2026-02-23 19:59:54
yigitkonur Feb 24, 2026
4fbe709
wip: auto-commit 2026-02-23 20:32:04
yigitkonur Feb 24, 2026
c14d16a
chore: release v3.0.1 [skip publish]
github-actions[bot] Feb 24, 2026
89013c3
fix: respect tool-specific env vars for session storage paths
yutakobayashidev Feb 25, 2026
fa1a7f4
feat: YAML verbosity config, inspect CLI, fix 10 parsing gaps
yigitkonur Feb 25, 2026
22f14ca
feat: add 7 new agent parsers, refactor existing ones from mnemo insi…
yigitkonur Feb 25, 2026
ecc9847
fix: symlink support in fs-helpers, add test fixtures for all 7 new a…
yigitkonur Feb 25, 2026
2f0606d
fix: audit fixes — zero-token display, config-driven highlights, type…
yigitkonur Feb 25, 2026
fd9ff9c
docs: update README and CLI text for all 14 supported agents
yigitkonur Feb 25, 2026
6b69a37
docs: rewrite README with human voice, reference community PRs
yigitkonur Feb 25, 2026
27f0675
fix: respect tool-specific env vars for session storage paths
yigitkonur Feb 25, 2026
da75a01
Merge pull request #14 from yutakobayashidev/fix/respect-env-var-over…
yigitkonur Feb 25, 2026
dbc8fcf
chore: release v3.0.2 [skip publish]
github-actions[bot] Feb 25, 2026
f577330
chore: bump version to v4.0.0
yigitkonur Feb 25, 2026
b95b96d
fix: address PR review — broken symlinks, cline duplicates, inspect f…
yigitkonur Feb 25, 2026
ce23b13
feat: v4 banner refresh + one-time GitHub star prompt
yigitkonur Feb 25, 2026
11c1676
fix: forward VerbosityConfig to generateHandoffMarkdown in all 14 par…
yigitkonur Feb 25, 2026
cabcdcf
fix: pass VerbosityConfig to SummaryCollector in extractAnthropicTool…
yigitkonur Feb 25, 2026
2c8e647
fix: Cline dedup preserves reasoning messages + Kiro uses birthtime
yigitkonur Feb 25, 2026
cbd7f89
merge: resolve conflicts with origin/main (keep v4.0.0 + env var paths)
yigitkonur Feb 25, 2026
ef21fa9
Merge pull request #15 from yigitkonur/feat/v4-14-agents-env-vars
yigitkonur Feb 25, 2026
e2c568a
test: add fixtures and contexts for all 14 parsers in unit tests
yigitkonur Feb 25, 2026
63437e9
chore: release v4.0.1 [skip publish]
github-actions[bot] Feb 25, 2026
0af43a2
fix: Windows tool detection — use where.exe and shell:true for .cmd s…
yigitkonur Feb 25, 2026
819dab5
chore: release v4.0.2 [skip publish]
github-actions[bot] Feb 25, 2026
cb4c1c8
feat: add Kimi CLI support
Feb 26, 2026
bb7e58c
feat: add dump command for bulk session export
commandlinetips Feb 28, 2026
a2a51c2
docs: add dump command to README
commandlinetips Feb 28, 2026
f3ccafe
fix: address code review feedback for dump command
commandlinetips Feb 28, 2026
50948e1
fix: stop spinner on error + validate --limit input
yigitkonur Mar 2, 2026
7be9ba6
Merge pull request #20 from commandlinetips/main
yigitkonur Mar 2, 2026
ea8b894
docs: add changelog for 4.1.0 + mention session origin in readme
yigitkonur Mar 2, 2026
97117e2
fix: resolve kimi parser consensus issues
yigitkonur Mar 2, 2026
adf049c
fix: address remaining kimi review comments
yigitkonur Mar 2, 2026
bf4317a
Merge pull request #25 from yigitkonur/docs/changelog-session-origin
yigitkonur Mar 2, 2026
06ae8ba
include original session file path in handoff output
yigitkonur Mar 2, 2026
dbf3545
Merge pull request #24 from yigitkonur/feat/session-file-path-in-handoff
yigitkonur Mar 2, 2026
d3989bc
fix: align kimi context extraction with review feedback
yigitkonur Mar 2, 2026
570ac70
chore: add review guidance and greptile config files
yigitkonur Mar 2, 2026
9778fd8
test: add createKimiFixture and use shared kimi fixture context
yigitkonur Mar 2, 2026
52a7521
fix: allow kimi special records without content in schema
yigitkonur Mar 2, 2026
19ce73c
fix: preserve user message when trimming kimi context
yigitkonur Mar 2, 2026
e2be3cb
Merge pull request #19 from skylixone/main
yigitkonur Mar 2, 2026
bab146e
fix: hoist spinner declaration to fix TS2304 scoping error in dump co…
yigitkonur Mar 2, 2026
bdc8155
chore: release v4.0.3 [skip publish]
github-actions[bot] Mar 2, 2026
23eaac1
fix windows cross-tool handoff breaking on cmd.exe (#26)
yigitkonur Mar 2, 2026
806a351
chore: release v4.0.4 [skip publish]
github-actions[bot] Mar 2, 2026
80e4550
feat: add qwen code (qwen-code) as supported tool (#27)
yigitkonur Mar 2, 2026
34dec0f
chore: release v4.0.5 [skip publish]
github-actions[bot] Mar 2, 2026
6244929
fix(qwen-code): correct storage path, tool classification, and gemini…
yigitkonur Mar 2, 2026
6164413
chore: release v4.0.6 [skip publish]
github-actions[bot] Mar 2, 2026
e0b0ccb
fix: detect Antigravity .json files, async IO, recursive search, corr…
yigitkonur Mar 2, 2026
eaab023
Merge pull request #30 from yigitkonur/fix/antigravity-json-extension
yigitkonur Mar 2, 2026
bfa9de0
chore: release v4.0.7 [skip publish]
github-actions[bot] Mar 2, 2026
c527292
fix: env var cache invalidation with dedup and hashed fingerprint (#28)
yigitkonur Mar 2, 2026
6f973e1
fix: opencode cross-tool handoff, gemini resume, and windows spawn sa…
yigitkonur Mar 2, 2026
1f2d89e
fix: restore inline qwen-code type definitions removed by c527292
yigitkonur Mar 2, 2026
8d6279a
chore: release v4.0.8 [skip publish]
github-actions[bot] Mar 2, 2026
9c0834a
fix(qwen-code): address pr #27 review — zod validation, defensive tim…
yigitkonur Mar 2, 2026
9f19b9f
chore: release v4.0.9 [skip publish]
github-actions[bot] Mar 2, 2026
8883907
feat(handoff): add default autonomy flags for more CLIs
yigitkonur Mar 3, 2026
ea64467
feat(cli): add weighted banner tips and tab cycling
yigitkonur Mar 3, 2026
0c2a5c0
fix: address PR review issues in banner and handoff defaults
yigitkonur Mar 3, 2026
6ac7902
fix(handoff): consume approval-mode passthrough for droid/amp/opencode
yigitkonur Mar 3, 2026
fea3f46
fix(handoff): consume approval-mode passthrough for droid/amp/opencode
yigitkonur Mar 3, 2026
360cafd
fix(handoff): remove implicit unsafe defaults and align tests
yigitkonur Mar 3, 2026
468f99f
improve claude handoff parsing and chain behavior
yigitkonur Mar 3, 2026
d1ecc84
fix: make banner ctrl-c cancel cleanly without prompt race
yigitkonur Mar 3, 2026
2a0d4c5
Merge pull request #33 from yigitkonur/feat/handoff-default-flags-mor…
yigitkonur Mar 3, 2026
cf85f73
keep sigint exit code consistent with ctrl-c semantics
yigitkonur Mar 3, 2026
4649bbc
chore: release v4.0.10 [skip publish]
github-actions[bot] Mar 3, 2026
560c8dc
merge: resolve main conflicts for PR #34
yigitkonur Mar 3, 2026
6bc9a02
Merge pull request #34 from yigitkonur/feat/banner-weighted-presets-t…
yigitkonur Mar 3, 2026
b761317
chore: release v4.0.11 [skip publish]
github-actions[bot] Mar 3, 2026
cb5eddd
ci: remove test-quality job from CI workflow
yigitkonur Mar 3, 2026
9427b13
chore: release v4.0.12 [skip publish]
github-actions[bot] Mar 3, 2026
178b7fc
fix: handle Windows drive slugs in Cursor cwd resolution
bazokhan Mar 13, 2026
318d35e
fix: guard drive-letter fallback with IS_WINDOWS to prevent Unix regr…
yigitkonur Mar 18, 2026
8855891
Merge pull request #36 from bazokhan/fix/windows-cursor-cwd-slug
yigitkonur Mar 18, 2026
8cb7463
feat(cursor): support cursor-agent binary fallback for resume flows
erenaslandev Apr 14, 2026
4535b05
fix(cursor): clarify resume command display with agent fallback
erenaslandev Apr 14, 2026
47d8f6e
test(cursor): cover native resume preview fallback display
erenaslandev Apr 14, 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
107 changes: 107 additions & 0 deletions .continues.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# ─────────────────────────────────────────────────────────────────────────────
# .continues.yml — Verbosity configuration for the `continues` CLI
# ─────────────────────────────────────────────────────────────────────────────
#
# Copy this file to one of:
# .continues.yml (in your project root — per-project settings)
# ~/.continues/config.yml (in your home dir — global default)
#
# Or pass explicitly: continues resume <id> --config path/to/config.yml
#
# You only need to include the fields you want to change.
# Everything else inherits from the selected preset.
#
# Available presets:
# minimal — ~2KB output, essentials only
# standard — ~8KB output, good default (this file shows standard values)
# verbose — ~30KB output, rich context for complex tasks
# full — ~unlimited, complete session data
# ─────────────────────────────────────────────────────────────────────────────

# Base preset — all unspecified fields inherit from this preset
preset: standard

# How many recent conversation messages to include in the handoff
recentMessages: 10

# Truncate individual message content after this many characters
maxMessageChars: 500

# ── Shell commands (bash, terminal, exec) ────────────────────────────────────
shell:
maxSamples: 8 # Number of shell invocations to show in detail
stdoutLines: 5 # Lines of stdout to include per command
stderrLines: 5 # Lines of stderr to include per command
maxChars: 2000 # Max characters per shell result block
showCommand: true # Show the command that was run
showExitCode: true # Show the exit code

# ── File reads ───────────────────────────────────────────────────────────────
read:
maxSamples: 20 # Number of file reads to list
maxChars: 0 # Max chars of file content to show (0 = path only)
showLineRange: true # Show line range when available (e.g. "lines 10-50")

# ── File writes (new files) ──────────────────────────────────────────────────
write:
maxSamples: 5 # Number of writes to show in detail
diffLines: 200 # Max diff lines per write
maxChars: 5000 # Max characters for the whole write block

# ── File edits (modifications) ───────────────────────────────────────────────
edit:
maxSamples: 5 # Number of edits to show in detail
diffLines: 200 # Max diff lines per edit
maxChars: 5000 # Max characters for the whole edit block

# ── Grep / search results ───────────────────────────────────────────────────
grep:
maxSamples: 10 # Number of grep/search invocations to show
maxChars: 500 # Max chars per grep result
showPattern: true # Show the search pattern
matchLines: 5 # Number of matching lines to include

# ── MCP tool calls ──────────────────────────────────────────────────────────
mcp:
maxSamplesPerNamespace: 5 # Max samples per MCP namespace
paramChars: 100 # Truncate MCP call parameters after N chars
resultChars: 100 # Truncate MCP call results after N chars
thinkingTools:
extractReasoning: true # Extract reasoning from thinking-style MCP tools
maxReasoningChars: 500 # Max chars of extracted reasoning

# ── Subagent / task dispatches ───────────────────────────────────────────────
task:
maxSamples: 5 # Number of task dispatches to show
includeSubagentResults: true # Include results from subagent completions
subagentResultChars: 500 # Max chars per subagent result
recurseSubagents: false # Recursively expand nested subagent chains

# ── Thinking / reasoning blocks ──────────────────────────────────────────────
thinking:
include: true # Include thinking/reasoning blocks
maxChars: 1000 # Max chars of thinking content
maxHighlights: 5 # Max number of reasoning highlights to extract

# ── Compact summary ─────────────────────────────────────────────────────────
compactSummary:
maxChars: 500 # Max chars for the compact summary section

# ── Pending tasks extraction ────────────────────────────────────────────────
pendingTasks:
extractFromThinking: true # Extract pending tasks from thinking blocks
extractFromSubagents: true # Extract pending tasks from subagent outputs
maxTasks: 10 # Max number of pending tasks to include

# ── Per-agent feature flags ─────────────────────────────────────────────────
agents:
claude:
filterProgressEvents: true # Filter out progress/heartbeat events
parseSubagents: true # Parse subagent dispatches
parseToolResultsDir: true # Parse tool_results directory data
separateHumanFromToolResults: true # Separate human messages from tool results
# Add flags for other agents as needed:
# codex:
# someFlag: true
# gemini:
# someFlag: true
34 changes: 34 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# continues — Code Review Standards

## Read-Only Semantics

- Session data is NEVER modified. Any PR that writes to `~/.claude/`, `~/.codex/`, `~/.copilot/`, `~/.gemini/`, `~/.factory/`, `~/.cursor/`, or `~/.local/share/opencode/` is a critical bug.
- Handoff files (`.continues-handoff.md`) write only to the project's own working directory — never to tool storage paths.

## ESM Conventions

- All local imports must use `.js` extensions, even for `.ts` source files: `import { foo } from './bar.js'`
- Never use `require()` — this is an ESM-only codebase (`"type": "module"` in `package.json`)
- Use `process.exitCode = N` instead of `process.exit(N)` — allows cleanup handlers to run

## Error Handling

- Use typed errors from `src/errors.ts` (`ParseError`, `SessionNotFoundError`, `ToolNotAvailableError`) for user-facing error paths — not bare `throw new Error()`
- Parsers must silently skip malformed session data with `catch {}` — never propagate parse errors to the caller

## Registry Completeness

- Every `SessionSource` member in `src/types/tool-names.ts` must have a registered `ToolAdapter` in `src/parsers/registry.ts`
- The completeness assertion at the bottom of `registry.ts` throws at module load if any adapter is missing — a missing entry crashes the CLI at startup
- Adding a tool to `TOOL_NAMES` without a registry entry is always a bug; changes to `SessionSource` require coordinated updates in the registry, fixtures, and tests

## Code Quality

- Biome handles all formatting and style — do not introduce ESLint, Prettier, or TSLint configs
- No synchronous file I/O (`readFileSync`, `writeFileSync`) in parser code — blocks the event loop when scanning large session directories
- Shared helpers `cleanSummary`, `extractRepoFromCwd`, and `homeDir` live in `src/utils/parser-helpers.ts` — do not duplicate them in individual parsers

## Performance

- Parsers run in parallel via `Promise.allSettled` in the session index builder — a slow parser delays only its own results
- The session index uses a 5-minute TTL cache at `~/.continues/sessions.jsonl` — cache bypasses should be explicitly justified
36 changes: 36 additions & 0 deletions .github/instructions/ci.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
applyTo: ".github/workflows/**/*.{yml,yaml}"
---

# CI Workflow Review Guidelines

## Security

- Pin action versions to at least a named tag (`actions/checkout@v4`); prefer full commit SHA for security-critical actions
- Set `permissions` explicitly on any job that needs elevated access (e.g., `pull-requests: write`) — do not rely on repository-wide defaults
- Never print secret values to logs — use GitHub's secret masking for dynamic secrets

```yaml
# Prefer explicit permissions scoping
permissions:
pull-requests: write
contents: read
```

## Node.js Version Requirements

- Node 22 is the minimum supported version (`engines.node >= 22.0.0` in `package.json`)
- The CI matrix must include at least Node 22 and the latest even-numbered LTS — do not drop below 22
- `node:sqlite` (built-in, Node 22.5+) is used by OpenCode and Crush parsers — do not add third-party SQLite packages

## Package Manager

- Use `pnpm` exclusively — not `npm ci` or `yarn` — to stay consistent with `pnpm-lock.yaml`
- Always run `pnpm install --frozen-lockfile` in CI to prevent accidental lockfile mutations
- Use `pnpm/action-setup@v4` for pnpm setup

## Build and Test Order

- Run `pnpm run build` (TypeScript compile) before `pnpm test` — `tsc` validates type correctness; test failures may be caused by type errors caught at build time
- The `test-quality` job posts a PR comment summarizing test counts and flags source-file changes without corresponding test changes — do not remove this job without an equivalent replacement
- The `test-quality` job should only run on `pull_request` events (not push to `main`)
62 changes: 62 additions & 0 deletions .github/instructions/parsers.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
applyTo: "src/parsers/**/*.ts"
---

# Parser Review Guidelines

## Crash Safety (Critical)

- Parsers MUST NOT throw to the caller — each runs inside `Promise.allSettled` and an uncaught error silently drops that tool's sessions from the index
- Wrap JSON.parse calls and file-read loops in try-catch with an empty catch block to silently skip malformed data

```typescript
// Good — CLI continues if one line is malformed
for (const line of lines) {
try {
const data = JSON.parse(line);
// process...
} catch {
// Skip malformed line silently
}
}

// Bad — one bad line crashes the entire parser
for (const line of lines) {
const data = JSON.parse(line);
}
```

## Required Exports

Each parser file must export exactly two functions:

- `parse<Tool>Sessions(): Promise<UnifiedSession[]>` — file discovery and metadata extraction
- `extract<Tool>Context(session: UnifiedSession, config?: VerbosityConfig): Promise<SessionContext>` — full conversation and tool activity extraction

Both must be registered in `src/parsers/registry.ts` with all `ToolAdapter` fields populated.

## JSONL Streaming

- Stream JSONL with `readline.createInterface` — never `fs.readFileSync` for session files
- Use helpers from `src/utils/jsonl.ts` (`readJsonlFile`, `scanJsonlHead`) when applicable
- Keep only the last ~10 messages in `recentMessages` — do not accumulate the entire conversation

## Tool Summarizer

- Always use `SummaryCollector` from `src/utils/tool-summarizer.ts` — never build `ToolUsageSummary[]` arrays manually
- Call `collector.add(category, summary, filePath?, isWrite?)` for each tool invocation

## Shared Helpers

- Import `cleanSummary`, `extractRepoFromCwd`, `homeDir` from `src/utils/parser-helpers.ts`
- Do not duplicate these utilities in individual parser files

## New Tool Checklist

Adding a new tool requires ALL five of:

1. Parser file `src/parsers/<tool>.ts` exporting both required functions
2. Registry entry in `src/parsers/registry.ts` with all `ToolAdapter` fields
3. Type update in `src/types/tool-names.ts` — add to `SessionSource` union and `TOOL_NAMES` array
4. Fixture factory in `src/__tests__/fixtures/index.ts`
5. Conversion tests in `src/__tests__/unit-conversions.test.ts` for all N-1 paths in each direction
35 changes: 35 additions & 0 deletions .github/instructions/security.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
applyTo: "src/utils/**/*.ts"
---

# Security Review Guidelines — Core Utilities

## Command Injection Prevention (resume.ts)

- External processes must be spawned with `spawn()` and arguments as an **array** — NEVER `exec()` with string interpolation
- Session IDs and file paths from parsed sessions are user-controlled and may contain shell metacharacters (`;`, `|`, `&`, `$`, backticks) — they must always be array elements, never embedded in a shell string

```typescript
// Avoid — command injection if sessionId contains ; or | or $()
exec(`claude --resume ${sessionId}`);

// Prefer — safe regardless of sessionId content
spawn('claude', ['--resume', sessionId], { stdio: 'inherit' });
```

## Forward Flag Security (forward-flags.ts)

- `--dangerously-skip-permissions` (Claude) and `--dangerously-bypass-approvals-and-sandbox` (Codex) must ONLY be set when the source session **explicitly** requested auto-approve behavior
- Flag precedence is security-critical: auto-approve > full-auto > sandbox > ask-for-approval — deviations from this order could grant unintended permissions in the target tool
- Never map a "plan mode" flag or any scheduling flag to auto-approve behavior

## Handoff Output Safety (markdown.ts)

- Do NOT embed secrets, API keys, tokens, or environment variable values in handoff markdown output
- Tool activity summaries (shell command output, file diffs) may contain sensitive data — the verbosity config caps limit exposure; do not bypass these caps
- Home directory paths in handoff output must be tildified (`~/`) using `safePath()` — never expose the full absolute home path

## General

- No hardcoded credentials, API keys, or tokens anywhere in source files
- User-supplied paths (session file paths, `cwd` values) must not be passed to shell execution without sanitization — use `spawn()` with array args only
35 changes: 35 additions & 0 deletions .github/instructions/testing.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
applyTo: "src/__tests__/**/*.ts"
---

# Test Review Guidelines

## Fixture-Based Testing

- Tests must NOT require real session files on the local machine — use fixture factories from `src/__tests__/fixtures/index.ts`
- Each tool has a `create<Tool>Fixture()` factory that creates a temp directory with realistic session data
- Ground fixture schemas in real session file formats — verify field names against actual tool storage before creating fixtures; do not invent schemas

## Conversion Coverage

- `unit-conversions.test.ts` is the primary suite — it must cover all N tools × (N-1) target conversion paths
- Adding a new tool requires: a fixture factory AND conversion tests covering all N-1 directions (as both source and target)
- PRs that add a new parser but do not update `unit-conversions.test.ts` are incomplete

## Test Quality

- Each test asserts ONE behavior — not multiple unrelated assertions bundled into a single test case
- Test names should describe the scenario: `should extract session summary from Claude JSONL`
- Tests must be independent — no shared mutable state between test cases
- Use `beforeAll` / `afterAll` for fixture setup and cleanup (create temp dir → run tests → delete temp dir)

## Regression Tests

- Bug fixes must include a regression test that fails before the fix and passes after
- PRs that modify parser logic without touching any test file should be flagged — the CI `test-quality` job will also flag this

## Performance

- Test timeout is 30 seconds (`vitest.config.ts`) — a test that times out indicates a parser with blocking or synchronous I/O
- Excluded by vitest config: `e2e*`, `real-e2e*`, `stress*`, `injection*`, `parsers.test*` — these require a real environment and are not run in CI
- Node.js 22+ is required; `node:sqlite` built-in is used by OpenCode/Crush fixtures — do not add third-party SQLite deps
46 changes: 46 additions & 0 deletions .github/instructions/typescript.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
applyTo: "**/*.ts"
---

# TypeScript Review Guidelines

## Type Safety

- Avoid `any` — use `unknown` for external data (JSON.parse results, JSONL lines), then narrow with type guards
- Define interfaces for all object shapes that cross module boundaries — not inline object literals
- Use `as const` for literal arrays like `TOOL_NAMES` to get narrower inferred types

```typescript
// Avoid
const parsed = JSON.parse(line) as any;
return parsed.type;

// Prefer
const parsed = JSON.parse(line) as unknown;
if (typeof parsed !== 'object' || parsed === null || !('type' in parsed)) return;
// Narrowed — safe to access (parsed as Record<string, unknown>)
```

## Discriminated Unions

- Use `switch (d.category)` for narrowing `StructuredToolSample` — not `instanceof` checks
- New tool sample types must be added to the `StructuredToolSample` union in `src/types/index.ts`
- The `category` field is the discriminant — never use string-equality checks outside of switch

## Async Patterns

- All file I/O must be async: use `fs.promises.*` not `fs.readFileSync` / `fs.writeFileSync`
- JSONL files must be streamed with `readline.createInterface` — never loaded into memory wholesale
- Avoid blocking the event loop in parsers — they run in parallel via `Promise.allSettled`

## Import Rules

- Local imports must end in `.js`: `import { foo } from './bar.js'` — required for Node.js ESM module resolution
- Never import from `dist/` in source files
- Prefer named exports over default exports for better refactoring support

## Defensive Patterns

- Use optional chaining (`?.`) and nullish coalescing (`??`) for optional fields from parsed session data
- Sessions returned from parsers must be sorted by `updatedAt` descending (newest first)
- Use `process.exitCode = N` over `process.exit(N)` to allow SIGTERM/SIGINT handlers to run
Loading