Claude-native starter kit that bootstraps multi-agent team infrastructure for any project. Clone once, install as a global skill, run /kit-install in any project directory. Includes: - 3-tier profile system (minimal/standard/full: 3-12 agents) - 16 agent archetype templates with personality spectrum - 18 skill templates using domain-action naming convention - Stakeholder persona panel for workshops and PR reviews - SQLite ticketing DB with CLI tools (config-based DB paths) - Decision tracking, sprint lifecycle, workshop orchestration - Multi-git-host support (GitHub, Gitea, GitLab) - /kit-update skill for syncing with source repo evolution - Naming theme support for agent identity/flavor - Smoke tests for all three profile tiers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
159 lines
4.7 KiB
Python
Executable File
159 lines
4.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
SQLite Connector — mini MCP for ticket management.
|
|
|
|
Usage:
|
|
python3 sqlite_connector.py init
|
|
python3 sqlite_connector.py query "SELECT * FROM tickets"
|
|
python3 sqlite_connector.py execute "UPDATE tickets SET status='done' WHERE id=1"
|
|
python3 sqlite_connector.py --help
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sqlite3
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Paths
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
CONFIG_PATH = SCRIPT_DIR / "config.json"
|
|
SCHEMA_PATH = SCRIPT_DIR.parent / "schema.sql"
|
|
|
|
|
|
def load_config():
|
|
"""Load config.json."""
|
|
with open(CONFIG_PATH, "r") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def resolve_db_path():
|
|
"""Resolve database path from environment or config."""
|
|
env_path = os.environ.get("PROJECT_DB")
|
|
if env_path:
|
|
return Path(env_path).resolve()
|
|
cfg = load_config()
|
|
db_name = cfg.get("db_name", "project.db")
|
|
db_location = cfg.get("db_location", "parent")
|
|
if db_location == "parent":
|
|
return (SCRIPT_DIR / ".." / ".." / ".." / db_name).resolve()
|
|
elif db_location == "local":
|
|
return (SCRIPT_DIR / ".." / ".." / db_name).resolve()
|
|
else:
|
|
return Path(db_location).resolve() / db_name
|
|
|
|
|
|
def get_connection():
|
|
"""Return an sqlite3 connection with WAL mode and foreign keys enabled."""
|
|
db_path = resolve_db_path()
|
|
conn = sqlite3.connect(str(db_path))
|
|
conn.execute("PRAGMA journal_mode=WAL;")
|
|
conn.execute("PRAGMA foreign_keys=ON;")
|
|
conn.row_factory = sqlite3.Row
|
|
return conn
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Commands
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def cmd_init():
|
|
"""Initialise the database from schema.sql."""
|
|
if not SCHEMA_PATH.exists():
|
|
return {"ok": False, "error": f"Schema file not found: {SCHEMA_PATH}"}
|
|
|
|
schema_sql = SCHEMA_PATH.read_text()
|
|
conn = get_connection()
|
|
try:
|
|
conn.executescript(schema_sql)
|
|
conn.commit()
|
|
return {"ok": True, "message": f"Database initialised at {resolve_db_path()}"}
|
|
except sqlite3.Error as exc:
|
|
return {"ok": False, "error": str(exc)}
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
def cmd_query(sql):
|
|
"""Run a SELECT query and return results as a JSON array of objects."""
|
|
conn = get_connection()
|
|
try:
|
|
cursor = conn.execute(sql)
|
|
columns = [desc[0] for desc in cursor.description] if cursor.description else []
|
|
rows = [dict(zip(columns, row)) for row in cursor.fetchall()]
|
|
return {"ok": True, "count": len(rows), "rows": rows}
|
|
except sqlite3.Error as exc:
|
|
return {"ok": False, "error": str(exc)}
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
def cmd_execute(sql):
|
|
"""Run an INSERT/UPDATE/DELETE and return affected row count."""
|
|
conn = get_connection()
|
|
try:
|
|
cursor = conn.execute(sql)
|
|
conn.commit()
|
|
return {
|
|
"ok": True,
|
|
"affected_rows": cursor.rowcount,
|
|
"last_id": cursor.lastrowid,
|
|
}
|
|
except sqlite3.Error as exc:
|
|
return {"ok": False, "error": str(exc)}
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# CLI
|
|
# ---------------------------------------------------------------------------
|
|
|
|
HELP_TEXT = """\
|
|
SQLite Connector
|
|
|
|
Usage:
|
|
sqlite_connector.py init Create/update database from schema.sql
|
|
sqlite_connector.py query "<SQL>" Run a SELECT and return JSON rows
|
|
sqlite_connector.py execute "<SQL>" Run INSERT/UPDATE/DELETE, return affected rows
|
|
sqlite_connector.py --help Show this help message
|
|
|
|
All output is JSON on stdout. Errors also use JSON with {{"ok": false, "error": "..."}}.
|
|
|
|
Config: {config}
|
|
Schema: {schema}
|
|
""".format(config=CONFIG_PATH, schema=SCHEMA_PATH)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2 or sys.argv[1] in ("--help", "-h", "help"):
|
|
print(HELP_TEXT)
|
|
sys.exit(0)
|
|
|
|
cmd = sys.argv[1]
|
|
|
|
if cmd == "init":
|
|
result = cmd_init()
|
|
elif cmd == "query":
|
|
if len(sys.argv) < 3:
|
|
result = {"ok": False, "error": "query requires a SQL string argument"}
|
|
else:
|
|
result = cmd_query(sys.argv[2])
|
|
elif cmd == "execute":
|
|
if len(sys.argv) < 3:
|
|
result = {"ok": False, "error": "execute requires a SQL string argument"}
|
|
else:
|
|
result = cmd_execute(sys.argv[2])
|
|
else:
|
|
result = {"ok": False, "error": f"Unknown command: {cmd}. Use --help for usage."}
|
|
|
|
print(json.dumps(result, indent=2))
|
|
sys.exit(0 if result.get("ok") else 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|