Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3b968e0
fix: resolve multiple issues from paradei/Continuous-Claude-v3
Apr 3, 2026
f506739
fix: copy .claude/scripts/ root files during install (issue #154/#155)
Apr 3, 2026
77d3316
fix: add fish shell support and cleanup CLAUDE_OPC_DIR on uninstall
Apr 3, 2026
0284129
fix: resolve skill reference issues (issue #158)
Apr 3, 2026
22db469
feat: add qlty and ast-grep installation steps to wizard (issue #144)
Apr 3, 2026
e2b3c61
feat: add Firecrawl and Morph API keys to wizard (issues #145, #146)
Apr 3, 2026
8e77a89
feat: add PreToolUse:Bash MCP directory guard (PR #160)
Apr 3, 2026
527f0c6
fix: add CLAUDE_CC_DIR export and path fixes for agentica infrastructure
Apr 3, 2026
a8a270e
fix: increase qlty install timeout from 60s to 120s
Apr 3, 2026
c6073cf
fix: remove all timeouts from wizard.py install commands
Apr 3, 2026
6f598a9
fix: increase timeouts to reasonable values for slow operations
Apr 3, 2026
18edf7a
fix: skip Docker stack and migrations for embedded/sqlite modes
Apr 3, 2026
1b2159c
fix: auto-migrate schema for embedded PostgreSQL mode
Apr 3, 2026
17abed3
fix: use venv Python when starting embedded PostgreSQL
Apr 3, 2026
1499a67
fix: add venv site-packages to sys.path for pgserver import
Apr 3, 2026
8bc5715
fix: use subprocess with venv Python to start pgserver
Apr 3, 2026
45de4a9
fix: correct schema path for embedded postgres migration
Apr 3, 2026
8ce2d22
revert: remove auto-migrate for embedded mode
Apr 3, 2026
d993534
fix: update embedded migration message to reflect manual process
Apr 3, 2026
9e96a9b
fix: check if qlty is already installed before attempting install
Apr 3, 2026
2ea2097
fix: also check ~/.qlty/bin for qlty installation
Apr 3, 2026
b67dc8c
fix: check qlty as standalone binary, not uv tool
Apr 3, 2026
190b5f5
fix: use curl install for qlty, not uv tool
Apr 3, 2026
9752c05
fix: add pre-install checks for ast-grep and tldr
Apr 3, 2026
c4309c2
fix: simplify pre-install checks to use shutil.which only
Apr 3, 2026
efa919f
fix: remove unreliable embedding model pre-download
Apr 3, 2026
c51103e
fix: use uv run for tldr model download
Apr 3, 2026
8939195
fix: use shutil.which for tldr executable in model download
Apr 3, 2026
d985fc0
fix: use 'tldr semantic index' instead of 'tldr semantic download-model'
Apr 3, 2026
bf6a43c
fix: use original pre-download code with sys.executable
Apr 3, 2026
5543a73
fix: use uv run python for model download
Apr 3, 2026
ba65f39
docs: update status.py with comprehensive description
Apr 3, 2026
3194843
fix: update status line format with consistent labels
Apr 3, 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 .claude/agents/agentica-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ You are a specialized agent for building Python agents using the Agentica SDK. Y
Before starting, read the SDK skill for full API reference:

```bash
cat $CLAUDE_PROJECT_DIR/.claude/skills/agentica-sdk/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/agentica-sdk/SKILL.md
```

## Step 2: Understand Your Task
Expand Down
4 changes: 2 additions & 2 deletions .claude/agents/braintrust-analyst.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ You are a specialized analysis agent. Your job is to run Braintrust analysis scr
Read the braintrust-analyze skill:

```bash
cat $CLAUDE_PROJECT_DIR/.claude/skills/braintrust-analyze/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/braintrust-analyze/SKILL.md
```

## Step 2: Execute Analysis

Run analysis IMMEDIATELY using Bash tool:

```bash
cd $CLAUDE_PROJECT_DIR && uv run python -m runtime.harness scripts/braintrust_analyze.py --last-session
cd $CLAUDE_OPC_DIR && uv run python -m runtime.harness scripts/braintrust_analyze.py --last-session
```

Other analyses (run as needed):
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/debug-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ You are a specialized debugging agent. Your job is to investigate issues, trace
Before starting, read the debug skill for methodology:

```bash
cat $CLAUDE_PROJECT_DIR/.claude/skills/debug/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/debug/SKILL.md
```

Follow the structure and guidelines from that skill.
Expand Down
10 changes: 5 additions & 5 deletions .claude/agents/memory-extractor.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ You receive:

```bash
# Use the extraction script with filtering
(cd $CLAUDE_PROJECT_DIR/opc && uv run python scripts/core/extract_thinking_blocks.py \
(cd $CLAUDE_OPC_DIR && uv run python scripts/core/extract_thinking_blocks.py \
--jsonl "$JSONL_PATH" \
--filter \
--format json) > /tmp/perception-blocks.json
Expand All @@ -42,7 +42,7 @@ This extracts only thinking blocks containing perception signals (actually, real
### Step 2: Check Stats

```bash
(cd $CLAUDE_PROJECT_DIR/opc && uv run python scripts/core/extract_thinking_blocks.py \
(cd $CLAUDE_OPC_DIR && uv run python scripts/core/extract_thinking_blocks.py \
--jsonl "$JSONL_PATH" \
--stats)
```
Expand Down Expand Up @@ -80,7 +80,7 @@ For each extracted perception change, use the mapped type from Step 3:

```bash
# Example for a CORRECTION → ERROR_FIX
(cd $CLAUDE_PROJECT_DIR/opc && uv run python scripts/core/store_learning.py \
(cd $CLAUDE_OPC_DIR && uv run python scripts/core/store_learning.py \
--session-id "$SESSION_ID" \
--type "ERROR_FIX" \
--context "what this relates to" \
Expand All @@ -90,7 +90,7 @@ For each extracted perception change, use the mapped type from Step 3:
--json)

# Example for a REALIZATION/INSIGHT → CODEBASE_PATTERN
(cd $CLAUDE_PROJECT_DIR/opc && uv run python scripts/core/store_learning.py \
(cd $CLAUDE_OPC_DIR && uv run python scripts/core/store_learning.py \
--session-id "$SESSION_ID" \
--type "CODEBASE_PATTERN" \
--context "what this relates to" \
Expand All @@ -100,7 +100,7 @@ For each extracted perception change, use the mapped type from Step 3:
--json)

# Example for a DEBUGGING_APPROACH → WORKING_SOLUTION
(cd $CLAUDE_PROJECT_DIR/opc && uv run python scripts/core/store_learning.py \
(cd $CLAUDE_OPC_DIR && uv run python scripts/core/store_learning.py \
--session-id "$SESSION_ID" \
--type "WORKING_SOLUTION" \
--context "debugging methodology" \
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/plan-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ You are a specialized planning agent. Your job is to create detailed implementat
Before creating any plan, read the planning skill for methodology and format:

```bash
cat $CLAUDE_PROJECT_DIR/.claude/skills/create_plan/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/create_plan/SKILL.md
```

Follow the structure and guidelines from that skill.
Expand Down
4 changes: 2 additions & 2 deletions .claude/agents/scribe.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ Before creating documentation, read the relevant skills:

```bash
# For handoffs
cat $CLAUDE_PROJECT_DIR/.claude/skills/create_handoff/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/create_handoff/SKILL.md

# For ledger updates
cat $CLAUDE_PROJECT_DIR/.claude/skills/continuity_ledger/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/continuity_ledger/SKILL.md
```

Follow the structure and guidelines from those skills.
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/session-analyst.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ You analyze Claude Code session data from Braintrust and provide insights.
Read the skill file first:

```bash
cat $CLAUDE_PROJECT_DIR/.claude/skills/braintrust-analyze/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/braintrust-analyze/SKILL.md
```

## Step 2: Run Analysis
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/validate-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ You are a specialized validation agent. Your job is to validate a technical plan
Before validating, read the validation skill for methodology and format:

```bash
cat $CLAUDE_PROJECT_DIR/.claude/skills/validate-agent/SKILL.md
cat $CLAUDE_CC_DIR/.claude/skills/validate-agent/SKILL.md
```

Follow the structure and guidelines from that skill.
Expand Down
86 changes: 86 additions & 0 deletions .claude/hooks/dist/mcp-directory-guard.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// src/mcp-directory-guard.ts
import { readFileSync } from "fs";

// src/shared/opc-path.ts
import { existsSync } from "fs";
import { join } from "path";
function getOpcDir() {
const envOpcDir = process.env.CLAUDE_OPC_DIR;
if (envOpcDir && existsSync(envOpcDir)) {
return envOpcDir;
}
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const localOpc = join(projectDir, "opc");
if (existsSync(localOpc)) {
return localOpc;
}
const homeDir = process.env.HOME || process.env.USERPROFILE || "";
if (homeDir) {
const globalClaude = join(homeDir, ".claude");
const globalScripts = join(globalClaude, "scripts", "core");
if (existsSync(globalScripts)) {
return globalClaude;
}
}
return null;
}

// src/mcp-directory-guard.ts
var SCRIPT_PATH_PATTERN = /\bscripts\/(mcp|core)\//;
function buildCdPrefixPattern(opcDir) {
const escapedDir = opcDir ? opcDir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") : "";
const variants = [
"\\$CLAUDE_OPC_DIR",
"\\$\\{CLAUDE_OPC_DIR\\}"
];
if (escapedDir) {
variants.push(escapedDir);
}
return new RegExp(`^\\s*cd\\s+(${variants.join("|")})\\s*&&`);
}
function main() {
let input;
try {
const stdinContent = readFileSync(0, "utf-8");
input = JSON.parse(stdinContent);
} catch {
console.log("{}");
return;
}
if (input.tool_name !== "Bash") {
console.log("{}");
return;
}
const command = input.tool_input?.command;
if (!command) {
console.log("{}");
return;
}
if (!SCRIPT_PATH_PATTERN.test(command)) {
console.log("{}");
return;
}
const opcDir = getOpcDir();
const cdPrefix = buildCdPrefixPattern(opcDir);
if (cdPrefix.test(command)) {
console.log("{}");
return;
}
const dirRef = opcDir || "$CLAUDE_OPC_DIR";
const corrected = `cd ${dirRef} && ${command.trimStart()}`;
const output = {
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: `OPC directory guard: commands referencing scripts/(mcp|core)/ must run from the OPC directory so uv can find pyproject.toml.

Blocked command:
${command.trim()}

Corrected command:
${corrected}`
}
};
console.log(JSON.stringify(output));
}
main();
36 changes: 35 additions & 1 deletion .claude/hooks/dist/session-start-continuity.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// src/session-start-continuity.ts
import * as fs from "fs";
import * as path from "path";
import { execSync } from "child_process";
import * as os from "os";
import { execSync, spawn } from "child_process";
function buildHandoffDirName(sessionName, sessionId) {
const uuidShort = sessionId.replace(/-/g, "").slice(0, 8);
return `${sessionName}-${uuidShort}`;
Expand Down Expand Up @@ -159,9 +160,42 @@ function getUnmarkedHandoffs() {
return [];
}
}
function ensureMemoryDaemon() {
const pidFile = path.join(os.homedir(), ".claude", "memory-daemon.pid");
if (fs.existsSync(pidFile)) {
try {
const pid = parseInt(fs.readFileSync(pidFile, "utf-8").trim(), 10);
process.kill(pid, 0);
return null;
} catch {
fs.unlinkSync(pidFile);
}
}
const possibleLocations = [
path.join(os.homedir(), ".claude", "opc", "scripts", "core", "memory_daemon.py"),
path.join(os.homedir(), ".claude", "scripts", "core", "memory_daemon.py")
];
for (const daemonScript of possibleLocations) {
if (fs.existsSync(daemonScript)) {
try {
const child = spawn("uv", ["run", "python", daemonScript, "start"], {
detached: true,
stdio: "ignore",
cwd: path.dirname(path.dirname(path.dirname(daemonScript)))
});
child.unref();
return "Memory daemon: Started";
} catch (e) {
console.error(`Warning: Failed to start memory daemon: ${e}`);
}
}
}
return null;
}
async function main() {
const input = JSON.parse(await readStdin());
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
ensureMemoryDaemon();
const sessionType = input.source || input.type;
let message = "";
let additionalContext = "";
Expand Down
5 changes: 3 additions & 2 deletions .claude/hooks/dist/tldr-read-enforcer.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// src/tldr-read-enforcer.ts
import { readFileSync as readFileSync2, existsSync as existsSync2, statSync } from "fs";
import { basename, extname } from "path";
import { basename, extname, isAbsolute, join as join2 } from "path";

// src/daemon-client.ts
import { existsSync, readFileSync, writeFileSync, unlinkSync } from "fs";
Expand Down Expand Up @@ -520,7 +520,8 @@ async function main() {
console.log("{}");
return;
}
const filePath = input.tool_input.file_path || "";
const rawFilePath = input.tool_input.file_path || "";
const filePath = isAbsolute(rawFilePath) ? rawFilePath : join2(input.cwd, rawFilePath);
if (!isCodeFile(filePath)) {
console.log("{}");
return;
Expand Down
104 changes: 104 additions & 0 deletions .claude/hooks/src/mcp-directory-guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* PreToolUse:Bash Hook - OPC Script Directory Guard
*
* Prevents running scripts from `scripts/(mcp|core)/` without first
* changing to $CLAUDE_OPC_DIR. When Claude runs these scripts from the
* wrong directory, `uv run` misses `opc/pyproject.toml` and its
* dependencies, causing ModuleNotFoundError.
*
* Detection: any Bash command referencing `scripts/(mcp|core)/` paths
* Allowed: commands prefixed with `cd $CLAUDE_OPC_DIR &&` (or resolved path)
* Denied: returns corrected command in the reason message
*
* Fixes: #148
*/

import { readFileSync } from 'fs';
import { getOpcDir } from './shared/opc-path.js';
import type { PreToolUseInput, PreToolUseHookOutput } from './shared/types.js';

/**
* Pattern matching scripts/(mcp|core)/ references in Bash commands.
* Captures the path for use in the corrected command suggestion.
*/
const SCRIPT_PATH_PATTERN = /\bscripts\/(mcp|core)\//;

/**
* Pattern matching a proper cd prefix to OPC dir.
* Accepts:
* cd $CLAUDE_OPC_DIR &&
* cd ${CLAUDE_OPC_DIR} &&
* cd /resolved/opc/path &&
*/
function buildCdPrefixPattern(opcDir: string | null): RegExp {
const escapedDir = opcDir ? opcDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') : '';
// Match: cd <opc-dir-variant> && (with flexible whitespace)
const variants = [
'\\$CLAUDE_OPC_DIR',
'\\$\\{CLAUDE_OPC_DIR\\}',
];
if (escapedDir) {
variants.push(escapedDir);
}
return new RegExp(`^\\s*cd\\s+(${variants.join('|')})\\s*&&`);
}

function main(): void {
let input: PreToolUseInput;
try {
const stdinContent = readFileSync(0, 'utf-8');
input = JSON.parse(stdinContent) as PreToolUseInput;
} catch {
// Can't read input - allow through
console.log('{}');
return;
}

// Only process Bash tool
if (input.tool_name !== 'Bash') {
console.log('{}');
return;
}

const command = input.tool_input?.command as string;
if (!command) {
console.log('{}');
return;
}

// Check if command references OPC script paths
if (!SCRIPT_PATH_PATTERN.test(command)) {
// No script path reference - allow through
console.log('{}');
return;
}

const opcDir = getOpcDir();
const cdPrefix = buildCdPrefixPattern(opcDir);

// Check if command already has the correct cd prefix
if (cdPrefix.test(command)) {
console.log('{}');
return;
}

// Build corrected command suggestion
const dirRef = opcDir || '$CLAUDE_OPC_DIR';
const corrected = `cd ${dirRef} && ${command.trimStart()}`;

const output: PreToolUseHookOutput = {
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason:
`OPC directory guard: commands referencing scripts/(mcp|core)/ must ` +
`run from the OPC directory so uv can find pyproject.toml.\n\n` +
`Blocked command:\n ${command.trim()}\n\n` +
`Corrected command:\n ${corrected}`,
},
};

console.log(JSON.stringify(output));
}

main();
Loading