Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ ACTION: Use Skill tool BEFORE responding
git clone https://github.com/parcadei/Continuous-Claude-v3.git
cd Continuous-Claude-v3/opc

# Run setup wizard (12 steps)
# Run setup wizard (15 steps)
uv run python -m scripts.setup.wizard
```

Expand All @@ -187,7 +187,9 @@ uv run python -m scripts.setup.wizard
| 8 | Install Claude Code integration (32 agents, 109 skills, 30 hooks) |
| 9 | Math features (SymPy, Z3, Pint - optional) |
| 10 | TLDR code analysis tool |
| 11-12 | Diagnostics tools + Loogle (optional) |
| 11 | Code quality CLI - qlty (optional) |
| 12 | AST-based code search - ast-grep (optional) |
| 13-14 | Diagnostics tools + Loogle (optional) |


#### To Uninstall:
Expand Down
137 changes: 123 additions & 14 deletions opc/scripts/setup/wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,13 +517,14 @@ async def run_setup_wizard() -> None:
5. Start Docker stack
6. Run migrations
7. Install Claude Code integration (hooks, skills, rules)
8. Install optional CLI tools (qlty, ast-grep)
"""
console.print(
Panel.fit("[bold]CLAUDE CONTINUITY KIT v3 - SETUP WIZARD[/bold]", border_style="blue")
)

# Step 0: Backup global ~/.claude (safety first)
console.print("\n[bold]Step 0/13: Backing up global Claude configuration...[/bold]")
console.print("\n[bold]Step 0/15: Backing up global Claude configuration...[/bold]")
from scripts.setup.claude_integration import (
backup_global_claude_dir,
get_global_claude_dir,
Expand All @@ -540,7 +541,7 @@ async def run_setup_wizard() -> None:
console.print(" [dim]No existing ~/.claude found (clean install)[/dim]")

# Step 1: Check prerequisites (with installation offers)
console.print("\n[bold]Step 1/13: Checking system requirements...[/bold]")
console.print("\n[bold]Step 1/15: Checking system requirements...[/bold]")
prereqs = await check_prerequisites_with_install_offers()

if prereqs["docker"]:
Expand All @@ -565,7 +566,7 @@ async def run_setup_wizard() -> None:
sys.exit(1)

# Step 2: Database config
console.print("\n[bold]Step 2/13: Database Configuration[/bold]")
console.print("\n[bold]Step 2/15: Database Configuration[/bold]")
console.print(" Choose your database backend:")
console.print(" [bold]docker[/bold] - PostgreSQL in Docker (recommended)")
console.print(" [bold]embedded[/bold] - Embedded PostgreSQL (no Docker needed)")
Expand Down Expand Up @@ -605,29 +606,29 @@ async def run_setup_wizard() -> None:
db_config["mode"] = "docker"

# Step 3: Embedding configuration
console.print("\n[bold]Step 3/13: Embedding Configuration[/bold]")
console.print("\n[bold]Step 3/15: Embedding Configuration[/bold]")
if Confirm.ask("Configure embedding provider?", default=True):
embeddings = await prompt_embedding_config()
else:
embeddings = {"provider": "local"}

# Step 4: API keys
console.print("\n[bold]Step 4/13: API Keys (Optional)[/bold]")
console.print("\n[bold]Step 4/15: API Keys (Optional)[/bold]")
if Confirm.ask("Configure API keys?", default=False):
api_keys = await prompt_api_keys()
else:
api_keys = {"perplexity": "", "nia": "", "braintrust": ""}

# Step 5: Generate .env
console.print("\n[bold]Step 5/13: Generating configuration...[/bold]")
console.print("\n[bold]Step 5/15: Generating configuration...[/bold]")
config = {"database": db_config, "embeddings": embeddings, "api_keys": api_keys}
env_path = Path.cwd() / ".env"
generate_env_file(config, env_path)
console.print(f" [green]OK[/green] Generated {env_path}")

# Step 5: Container stack (Sandbox Infrastructure)
runtime = prereqs.get("container_runtime", "docker")
console.print(f"\n[bold]Step 6/13: Container Stack (Sandbox Infrastructure)[/bold]")
console.print("\n[bold]Step 6/15: Container Stack (Sandbox Infrastructure)[/bold]")
console.print(" The sandbox requires PostgreSQL and Redis for:")
console.print(" - Agent coordination and scheduling")
console.print(" - Build cache and LSP index storage")
Expand Down Expand Up @@ -655,7 +656,7 @@ async def run_setup_wizard() -> None:
console.print(f" You can start manually with: {runtime} compose up -d")

# Step 6: Migrations
console.print("\n[bold]Step 7/13: Database Setup[/bold]")
console.print("\n[bold]Step 7/15: Database Setup[/bold]")
if Confirm.ask("Run database migrations?", default=True):
from scripts.setup.docker_setup import run_migrations, set_container_runtime

Expand All @@ -668,7 +669,7 @@ async def run_setup_wizard() -> None:
console.print(f" [red]ERROR[/red] {result.get('error', 'Unknown error')}")

# Step 7: Claude Code Integration
console.print("\n[bold]Step 8/13: Claude Code Integration[/bold]")
console.print("\n[bold]Step 8/15: Claude Code Integration[/bold]")
from scripts.setup.claude_integration import (
analyze_conflicts,
backup_claude_dir,
Expand Down Expand Up @@ -863,7 +864,7 @@ async def run_setup_wizard() -> None:
console.print(f' export CLAUDE_OPC_DIR="{opc_dir}"')

# Step 8: Math Features (Optional)
console.print("\n[bold]Step 9/13: Math Features (Optional)[/bold]")
console.print("\n[bold]Step 9/15: Math Features (Optional)[/bold]")
console.print(" Math features include:")
console.print(" - SymPy: symbolic algebra, calculus, equation solving")
console.print(" - Z3: SMT solver for constraint satisfaction & proofs")
Expand Down Expand Up @@ -922,7 +923,7 @@ async def run_setup_wizard() -> None:
console.print(" [dim]Install later with: uv sync --extra math[/dim]")

# Step 9: TLDR Code Analysis Tool
console.print("\n[bold]Step 10/13: TLDR Code Analysis Tool[/bold]")
console.print("\n[bold]Step 10/15: TLDR Code Analysis Tool[/bold]")
console.print(" TLDR provides token-efficient code analysis for LLMs:")
console.print(" - 95% token savings vs reading raw files")
console.print(" - 155x faster queries with daemon mode")
Expand Down Expand Up @@ -1080,8 +1081,116 @@ async def run_setup_wizard() -> None:
if strip_tldr_hooks_from_settings(settings_path):
console.print(" [green]OK[/green] TLDR hooks disabled")

# Step 10: Diagnostics Tools (Shift-Left Feedback)
console.print("\n[bold]Step 11/13: Diagnostics Tools (Shift-Left Feedback)[/bold]")
# Step 10b: Code Quality CLI - qlty (Optional)
console.print("\n[bold]Step 11/15: Code Quality CLI (Optional)[/bold]")
console.print(" qlty provides universal code quality checking:")
console.print(" - 70+ linters across 40+ languages")
console.print(" - Auto-fix for common issues")
console.print(" - Powers the /qlty-check skill")
console.print("")

if shutil.which("qlty"):
console.print(" [green]OK[/green] qlty already installed")
elif Confirm.ask("\nInstall qlty?", default=True):
console.print(" Installing qlty...")
import subprocess

try:
result = subprocess.run(
["sh", "-c", "curl -fsSL https://qlty.sh | sh"],
capture_output=True,
text=True,
timeout=120,
)
Comment on lines +1099 to +1104

This comment was marked as outdated.

if result.returncode == 0:
console.print(" [green]OK[/green] qlty installed")
# Verify installation
verify = subprocess.run(
["qlty", "--version"],
capture_output=True,
text=True,
timeout=10,
)
if verify.returncode == 0:
console.print(f" [green]OK[/green] Verified: {verify.stdout.strip()}")
else:
console.print(" [yellow]WARN[/yellow] qlty installed but not on PATH")
else:
console.print(" [yellow]WARN[/yellow] Installation failed")
console.print(" Install manually: curl -fsSL https://qlty.sh | sh")
except subprocess.TimeoutExpired:
console.print(" [yellow]WARN[/yellow] Installation timed out")
console.print(" Install manually: curl -fsSL https://qlty.sh | sh")
except Exception as e:
console.print(f" [red]ERROR[/red] {e}")
else:
console.print(" Skipped qlty installation")
console.print(" [dim]Install later: curl -fsSL https://qlty.sh | sh[/dim]")
Comment on lines +1098 to +1128
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing qlty init and post-install verification per PR objectives.

The PR description states that qlty init should be called on successful install, and the issue requires following the "explain → confirm → install → verify" pattern. Currently, neither happens after qlty installation succeeds.

Proposed fix
             if result.returncode == 0:
                 console.print("  [green]OK[/green] qlty installed")
+
+                # Verify installation
+                verify = subprocess.run(
+                    ["qlty", "--version"],
+                    capture_output=True,
+                    text=True,
+                    timeout=10,
+                )
+                if verify.returncode == 0:
+                    console.print(f"  [green]OK[/green] Verified: {verify.stdout.strip()}")
+                else:
+                    console.print("  [yellow]WARN[/yellow] qlty installed but not on PATH")
+
+                # Initialize qlty in the project
+                console.print("  Running qlty init...")
+                init_result = subprocess.run(
+                    ["qlty", "init"],
+                    capture_output=True,
+                    text=True,
+                    timeout=60,
+                )
+                if init_result.returncode == 0:
+                    console.print("  [green]OK[/green] qlty initialized")
+                else:
+                    console.print("  [yellow]WARN[/yellow] qlty init failed (run manually: qlty init)")
             else:
🤖 Prompt for AI Agents
In `@opc/scripts/setup/wizard.py` around lines 1098 - 1117, After a successful
curl install (the branch where subprocess.run returns 0), invoke the qlty
initialization and a verification command: call "qlty init" (run via
subprocess.run similar to the existing call) and then run a verification command
such as "qlty --version" or another appropriate qlty health/status check; handle
non-zero return codes and exceptions for both calls and log results via
console.print (reuse the same timeout/ capture_output/text pattern), printing an
OK on success or WARN/ERROR with actionable manual instructions on failure.
Ensure you update the success branch that currently prints "OK qlty installed"
to perform these two subprocess.run calls (referencing subprocess.run and
result.returncode) and to surface errors/exceptions just like the existing
install block.


# Step 10c: AST-Grep (Optional)
console.print("\n[bold]Step 12/15: AST-Based Code Search (Optional)[/bold]")
console.print(" ast-grep enables structural code search and refactoring:")
console.print(" - Search by AST patterns, not text")
console.print(" - Language-aware refactoring")
console.print(" - Powers the /ast-grep-find and search-router skills")
console.print("")

if shutil.which("ast-grep") or shutil.which("sg"):
console.print(" [green]OK[/green] ast-grep already installed")
elif Confirm.ask("\nInstall ast-grep?", default=True):
console.print(" Installing ast-grep...")
import subprocess

try:
# Try brew first (macOS), then cargo
if shutil.which("brew"):
result = subprocess.run(
["brew", "install", "ast-grep"],
capture_output=True,
text=True,
timeout=120,
)
elif shutil.which("cargo"):
console.print(" [dim]Using cargo (may take a few minutes)...[/dim]")
result = subprocess.run(
["cargo", "install", "ast-grep", "--locked"],
capture_output=True,
text=True,
timeout=300,
)
else:
console.print(" [yellow]WARN[/yellow] Neither brew nor cargo found")
console.print(" Install manually: https://github.com/ast-grep/ast-grep#installation")
result = None

if result and result.returncode == 0:
console.print(" [green]OK[/green] ast-grep installed")
# Verify installation
sg_cmd = "sg" if shutil.which("sg") else "ast-grep"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The verification check for newly installed tools like ast-grep or qlty fails because the PATH environment variable is not updated within the running script.
Severity: MEDIUM

Suggested Fix

Instead of relying on the process's PATH variable, determine the absolute path to the newly installed binary. For cargo, this is typically ~/.cargo/bin/. Use this absolute path directly when calling subprocess.run() for verification, bypassing the need for shutil.which() or a PATH search.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: opc/scripts/setup/wizard.py#L1169

Potential issue: After installing a tool like `ast-grep` or `qlty` via `cargo` or
`brew`, the verification step fails. This occurs because the installation updates the
shell's `PATH` configuration but not the `PATH` of the currently running Python wizard
process. The script uses `shutil.which()` to find the executable, which searches the
outdated `PATH` and fails. Consequently, the script incorrectly reports that the tool is
"installed but not on PATH", even though the installation was successful and the tool
will be available in new shell sessions.

verify = subprocess.run(
[sg_cmd, "--version"],
capture_output=True,
text=True,
timeout=10,
)
if verify.returncode == 0:
console.print(f" [green]OK[/green] Verified: {verify.stdout.strip()}")
else:
console.print(" [yellow]WARN[/yellow] ast-grep installed but not on PATH")
elif result:
console.print(" [yellow]WARN[/yellow] Installation failed")
console.print(" Install manually: https://github.com/ast-grep/ast-grep#installation")
except subprocess.TimeoutExpired:
console.print(" [yellow]WARN[/yellow] Installation timed out")
console.print(" Install manually: https://github.com/ast-grep/ast-grep#installation")
except Exception as e:
console.print(f" [red]ERROR[/red] {e}")
Comment on lines +1144 to +1187
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing post-install verification for ast-grep, and misleading fallback message.

Two issues:

  1. Like qlty, ast-grep doesn't verify the install succeeded (e.g., sg --version), deviating from the "explain → confirm → install → verify" pattern required by issue #140.

  2. Lines 1158-1159 and 1161-1162: when cargo install fails or times out, the fallback message suggests brew install ast-grep, which is confusing if the user doesn't have brew. Consider a more generic message.

Proposed fix
             if result and result.returncode == 0:
                 console.print("  [green]OK[/green] ast-grep installed")
+
+                # Verify installation
+                sg_cmd = "sg" if shutil.which("sg") else "ast-grep"
+                verify = subprocess.run(
+                    [sg_cmd, "--version"],
+                    capture_output=True,
+                    text=True,
+                    timeout=10,
+                )
+                if verify.returncode == 0:
+                    console.print(f"  [green]OK[/green] Verified: {verify.stdout.strip()}")
+                else:
+                    console.print("  [yellow]WARN[/yellow] ast-grep installed but not on PATH")
             elif result:
                 console.print("  [yellow]WARN[/yellow] Installation failed")
-                console.print("  Install manually: brew install ast-grep")
+                console.print("  Install manually: https://github.com/ast-grep/ast-grep#installation")
         except subprocess.TimeoutExpired:
             console.print("  [yellow]WARN[/yellow] Installation timed out")
-            console.print("  Install manually: brew install ast-grep")
+            console.print("  Install manually: https://github.com/ast-grep/ast-grep#installation")
🤖 Prompt for AI Agents
In `@opc/scripts/setup/wizard.py` around lines 1133 - 1164, The ast-grep install
block (in wizard.py around the ast-grep install logic) must verify the
installation and avoid misleading fallback text: after a successful
subprocess.run that returns 0, run a verification check (e.g.,
subprocess.run(["sg","--version"], capture_output=True, text=True) or check
shutil.which("sg")) and only print "[green]OK[/green] ast-grep installed" if the
verification succeeds; if verification fails, treat it as an installation
failure and print the appropriate failure message. Also replace hardcoded
"Install manually: brew install ast-grep" in the failure and timeout branches
with a generic instruction or a context-aware suggestion (if
shutil.which("brew") is truthy suggest brew, elif shutil.which("cargo") suggest
cargo, else print the upstream install URL
https://github.com/ast-grep/ast-grep#installation) so users without brew aren't
directed to use it.

else:
console.print(" Skipped ast-grep installation")
console.print(" [dim]Install later: https://github.com/ast-grep/ast-grep#installation[/dim]")

# Step 10d: Diagnostics Tools (Shift-Left Feedback)
console.print("\n[bold]Step 13/15: Diagnostics Tools (Shift-Left Feedback)[/bold]")
console.print(" Claude gets immediate type/lint feedback after editing files.")
console.print(" This catches errors before tests run (shift-left).")
console.print("")
Expand Down Expand Up @@ -1119,7 +1228,7 @@ async def run_setup_wizard() -> None:
console.print(" [dim]TypeScript, Go, Rust coming soon.[/dim]")

# Step 11: Loogle (Lean 4 type search for /prove skill)
console.print("\n[bold]Step 12/13: Loogle (Lean 4 Type Search)[/bold]")
console.print("\n[bold]Step 14/15: Loogle (Lean 4 Type Search)[/bold]")
console.print(" Loogle enables type-aware search of Mathlib theorems:")
console.print(" - Used by /prove skill for theorem proving")
console.print(" - Search by type signature (e.g., 'Nontrivial _ ↔ _')")
Expand Down