jsat 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jsat-0.1.0/.github/workflows/ci.yml +55 -0
- jsat-0.1.0/.github/workflows/publish.yml +38 -0
- jsat-0.1.0/.gitignore +38 -0
- jsat-0.1.0/CHANGELOG.md +59 -0
- jsat-0.1.0/PKG-INFO +209 -0
- jsat-0.1.0/README.md +119 -0
- jsat-0.1.0/jsat/__init__.py +38 -0
- jsat-0.1.0/jsat/_ai/__init__.py +90 -0
- jsat-0.1.0/jsat/_ai/anthropic.py +80 -0
- jsat-0.1.0/jsat/_ai/claude_cli.py +278 -0
- jsat-0.1.0/jsat/_ai/none.py +60 -0
- jsat-0.1.0/jsat/_ai/ollama.py +97 -0
- jsat-0.1.0/jsat/_ai/openai.py +81 -0
- jsat-0.1.0/jsat/_ai/openai_compat.py +107 -0
- jsat-0.1.0/jsat/_cache/__init__.py +17 -0
- jsat-0.1.0/jsat/_cache/disk.py +93 -0
- jsat-0.1.0/jsat/_cache/memory.py +84 -0
- jsat-0.1.0/jsat/_cache/redis.py +139 -0
- jsat-0.1.0/jsat/_config.py +469 -0
- jsat-0.1.0/jsat/_core.py +416 -0
- jsat-0.1.0/jsat/_embed/__init__.py +37 -0
- jsat-0.1.0/jsat/_embed/local.py +53 -0
- jsat-0.1.0/jsat/_embed/none.py +42 -0
- jsat-0.1.0/jsat/_embed/openai.py +61 -0
- jsat-0.1.0/jsat/_exceptions.py +253 -0
- jsat-0.1.0/jsat/_graph/__init__.py +87 -0
- jsat-0.1.0/jsat/_graph/lightgraph.py +140 -0
- jsat-0.1.0/jsat/_graph/neo4j.py +141 -0
- jsat-0.1.0/jsat/_graph/sqlite.py +170 -0
- jsat-0.1.0/jsat/_models.py +233 -0
- jsat-0.1.0/jsat/_parsers/__init__.py +46 -0
- jsat-0.1.0/jsat/_parsers/go.py +135 -0
- jsat-0.1.0/jsat/_parsers/javascript.py +135 -0
- jsat-0.1.0/jsat/_parsers/python.py +149 -0
- jsat-0.1.0/jsat/cli.py +1273 -0
- jsat-0.1.0/jsat/mcp/__init__.py +1 -0
- jsat-0.1.0/jsat/mcp/server.py +194 -0
- jsat-0.1.0/jsat/mcp/tools.py +162 -0
- jsat-0.1.0/jsat/skills/__init__.py +1 -0
- jsat-0.1.0/jsat/skills/clusters.py +44 -0
- jsat-0.1.0/jsat/skills/manifest.py +82 -0
- jsat-0.1.0/jsat/skills/registry.py +81 -0
- jsat-0.1.0/jsat/tools/__init__.py +18 -0
- jsat-0.1.0/jsat/tools/blast_radius.py +127 -0
- jsat-0.1.0/jsat/tools/contract.py +106 -0
- jsat-0.1.0/jsat/tools/export.py +131 -0
- jsat-0.1.0/jsat/tools/feature.py +85 -0
- jsat-0.1.0/jsat/tools/incident.py +136 -0
- jsat-0.1.0/jsat/tools/indexer.py +130 -0
- jsat-0.1.0/jsat/tools/ithinking.py +126 -0
- jsat-0.1.0/jsat/tools/knowledge.py +100 -0
- jsat-0.1.0/jsat/tools/migration.py +128 -0
- jsat-0.1.0/jsat/tools/orchestrator.py +101 -0
- jsat-0.1.0/jsat/tools/query.py +88 -0
- jsat-0.1.0/jsat/tools/review.py +116 -0
- jsat-0.1.0/jsat/tools/security.py +97 -0
- jsat-0.1.0/jsat/tools/shell.py +720 -0
- jsat-0.1.0/jsat/tools/test_helper.py +81 -0
- jsat-0.1.0/pyproject.toml +121 -0
- jsat-0.1.0/tests/__init__.py +0 -0
- jsat-0.1.0/tests/test_blast_radius.py +92 -0
- jsat-0.1.0/tests/test_cache.py +99 -0
- jsat-0.1.0/tests/test_exceptions.py +92 -0
- jsat-0.1.0/tests/test_graph_sqlite.py +118 -0
- jsat-0.1.0/tests/test_incident.py +86 -0
- jsat-0.1.0/tests/test_migration.py +116 -0
- jsat-0.1.0/tests/test_models.py +70 -0
- jsat-0.1.0/tests/test_parsers.py +138 -0
- jsat-0.1.0/tests/test_security.py +82 -0
- jsat-0.1.0/tests/test_skills.py +114 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
run: pip install uv
|
|
26
|
+
|
|
27
|
+
- name: Install jsat (core + standard, no AI backends)
|
|
28
|
+
run: uv pip install --system -e ".[standard]"
|
|
29
|
+
|
|
30
|
+
- name: Run CI-safe tests
|
|
31
|
+
run: pytest -m ci --tb=short -q
|
|
32
|
+
env:
|
|
33
|
+
CI: "true"
|
|
34
|
+
|
|
35
|
+
- name: Coverage report (Python 3.11 only)
|
|
36
|
+
if: matrix.python-version == '3.11'
|
|
37
|
+
run: |
|
|
38
|
+
uv pip install --system coverage
|
|
39
|
+
coverage run -m pytest -m ci -q
|
|
40
|
+
coverage report --fail-under=55
|
|
41
|
+
|
|
42
|
+
lint:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
|
|
47
|
+
- uses: actions/setup-python@v5
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.11"
|
|
50
|
+
|
|
51
|
+
- name: Install ruff
|
|
52
|
+
run: pip install ruff
|
|
53
|
+
|
|
54
|
+
- name: Lint
|
|
55
|
+
run: ruff check jsat/ --select E,F,I --ignore E501,E402
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*" # triggers on: git tag v0.1.0 && git push --tags
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment:
|
|
12
|
+
name: pypi
|
|
13
|
+
url: https://pypi.org/project/jsat/
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write # required for trusted publishing (no token needed!)
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
|
|
25
|
+
- name: Install build tools
|
|
26
|
+
run: pip install build
|
|
27
|
+
|
|
28
|
+
- name: Build
|
|
29
|
+
run: python -m build
|
|
30
|
+
|
|
31
|
+
- name: Publish to PyPI
|
|
32
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
33
|
+
with:
|
|
34
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
35
|
+
# To set the secret:
|
|
36
|
+
# 1. pypi.org → Account Settings → API tokens → Add token (Entire account)
|
|
37
|
+
# 2. GitHub repo → Settings → Secrets and variables → Actions → New secret
|
|
38
|
+
# Name: PYPI_API_TOKEN Value: pypi-AgEI...
|
jsat-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Planning docs (local only — not tracked)
|
|
2
|
+
plan.md
|
|
3
|
+
prompt.md
|
|
4
|
+
|
|
5
|
+
# JSAT — everything lives under .jsat/
|
|
6
|
+
# Exclude runtime artifacts; keep config.yaml committable for team sharing
|
|
7
|
+
.jsat/graph/
|
|
8
|
+
.jsat/vectors/
|
|
9
|
+
.jsat/cache/
|
|
10
|
+
.jsat/system-profile.json
|
|
11
|
+
.jsat/audit.log
|
|
12
|
+
# Legacy root-level config (no longer created)
|
|
13
|
+
.jsat.yaml
|
|
14
|
+
|
|
15
|
+
# Python
|
|
16
|
+
__pycache__/
|
|
17
|
+
*.py[cod]
|
|
18
|
+
*.egg-info/
|
|
19
|
+
dist/
|
|
20
|
+
build/
|
|
21
|
+
.venv/
|
|
22
|
+
venv/
|
|
23
|
+
.env
|
|
24
|
+
*venv/
|
|
25
|
+
|
|
26
|
+
# Node
|
|
27
|
+
node_modules/
|
|
28
|
+
|
|
29
|
+
# Editors
|
|
30
|
+
.DS_Store
|
|
31
|
+
.idea/
|
|
32
|
+
.vscode/
|
|
33
|
+
*.swp
|
|
34
|
+
|
|
35
|
+
# Secrets (never commit)
|
|
36
|
+
*.pem
|
|
37
|
+
*.key
|
|
38
|
+
.env.local
|
jsat-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to JSAT.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.0] — 2026-07-25
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
**Core infrastructure**
|
|
12
|
+
- 27-class exception hierarchy (`JSATError` → `ConfigError`, `IndexError`, `AIError`, `GraphError`, `ProfileError`, `ExportError`, `SkillError`) — all with structured context kwargs
|
|
13
|
+
- All Pydantic v2 models: `JSATConfig`, `SystemProfile`, `IndexResult`, `BlastRadiusReport`, `SecurityReport`, `IncidentReport`, `QueryResult`, `ExportManifest`, and supporting sub-models
|
|
14
|
+
- Config loader with 5-path search order + `CI=true` auto-overrides
|
|
15
|
+
- System auto-detection: RAM, CPU arch (arm64/x86_64), GPU (CUDA/Metal/none), service reachability (Ollama, Neo4j, Qdrant, Redis)
|
|
16
|
+
- Profile presets: `solo`, `team`, `ci`, `raspberry-pi`
|
|
17
|
+
|
|
18
|
+
**JSAT class and CLI**
|
|
19
|
+
- `JSAT` class with fully lazy backend wiring — heavy imports only on first call
|
|
20
|
+
- Typer CLI: `jsat index`, `jsat shell`, `jsat doctor`, `jsat init`, `jsat export`, `jsat import`, `jsat skills list/run`, `jsat version`
|
|
21
|
+
|
|
22
|
+
**Tools (0–14)**
|
|
23
|
+
- Tool 0 — JSAT Shell: interactive REPL with 14 commands, tab completion, session history, Rich output
|
|
24
|
+
- Tool 1 — Directory Indexer: tree-sitter AST parsing (Python, JS/TS, Go), BFS graph population, `INDEX.md` output
|
|
25
|
+
- Tool 2 — Test Intelligence Helper: source-to-test file matching, over-mock detection, behavioral coverage estimate
|
|
26
|
+
- Tool 3 — Feature Helper: graph-context-aware implementation plan generation
|
|
27
|
+
- Tool 4 — Blast Radius Analyzer: BFS traversal with severity classification (breaking/degraded/warning/safe) and Mermaid diagram output
|
|
28
|
+
- Tool 5 — API Contract Validator: OpenAPI/AsyncAPI diff between git branches with compatibility score
|
|
29
|
+
- Tool 6 — Security Review Agent: Semgrep integration (graceful fallback), Shannon entropy secret detection, OWASP severity filtering
|
|
30
|
+
- Tool 7 — Incident Investigation Helper: git history scoring with recency × blast-radius × pattern-match formula
|
|
31
|
+
- Tool 8 — Migration Safety Validator: SQL parsing, lock-type classification, zero-downtime guide generation
|
|
32
|
+
- Tool 9 — Multi-Model Code Review: parallel dispatch, embedding-based deduplication, confidence ranking
|
|
33
|
+
- Tool 10 — Knowledge Base Builder: graph-stored knowledge entries, AI synthesis, stale-flag decay
|
|
34
|
+
- Tool 11 — Multi-Agent Orchestrator: heuristic task decomposition, sequential agent execution, conflict detection
|
|
35
|
+
- Tool 12 — Export / Import System: atomic ZIP export with manifest, graph + artifact restore
|
|
36
|
+
- Tool 13 — Python SDK: `JSAT` class; full sync + async API for all tools
|
|
37
|
+
- Tool 14 — IThinking: 7-phase meta-cognitive wrapper (intent → plan → verify → execute → reflect)
|
|
38
|
+
|
|
39
|
+
**Backends**
|
|
40
|
+
- Graph: SQLite (core, always available), LightGraph (stdlib-only fallback), Neo4j (team extra)
|
|
41
|
+
- Embeddings: NoOp/zero-vector (CI), local Ollama nomic-embed-code, OpenAI text-embedding-3-*
|
|
42
|
+
- Cache: memory LRU, atomic disk JSON, Redis (team extra)
|
|
43
|
+
- AI: NoOp (CI), Ollama (local), Anthropic/Claude, OpenAI, any OpenAI-compatible endpoint
|
|
44
|
+
|
|
45
|
+
**MCP server**
|
|
46
|
+
- JSON-RPC 2.0 stdin/stdout server with 47-tool catalog (JSON Schema per tool)
|
|
47
|
+
- 12 tool categories: Index, Blast Radius, Tests, Security, API Contract, Knowledge, Incident, Migration, Review, Export, Meta, IThinking
|
|
48
|
+
|
|
49
|
+
**Skills system**
|
|
50
|
+
- `SkillsRegistry`: YAML manifest auto-discovery and dispatch
|
|
51
|
+
- `SkillManifest` Pydantic model with `from_yaml()` and `to_mcp_tool()` converters
|
|
52
|
+
- 7 built-in skill clusters: `start-session`, `new-feature`, `pre-merge`, `incident`, `security-release`, `db-schema-change`, `knowledge-maintenance`
|
|
53
|
+
|
|
54
|
+
**Tests**
|
|
55
|
+
- 43+ CI-safe tests (`@pytest.mark.ci`) covering: exceptions, models, caches, SQLite graph, parsers (Python/JS/Go), blast radius, incident scoring, migration analysis, security detection, skills registry
|
|
56
|
+
|
|
57
|
+
**Packaging**
|
|
58
|
+
- `pyproject.toml` with 6 pip extras: `core` (~80MB), `local`, `standard`, `team`, `ci`, `all`
|
|
59
|
+
- GitHub Actions CI: matrix (Python 3.10/3.11/3.12), ruff lint, coverage gate at 55%
|
jsat-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jsat
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: JaySoft AI Tools — open-source codebase intelligence shell and SDK
|
|
5
|
+
Project-URL: Homepage, https://github.com/jsat-project/jsat
|
|
6
|
+
Project-URL: Repository, https://github.com/jsat-project/jsat
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/jsat-project/jsat/issues
|
|
8
|
+
Author-email: JaySoft <iamjpsonkar@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: ai,cli,codebase,intelligence,sdk,static-analysis
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: click>=8
|
|
22
|
+
Requires-Dist: gitpython>=3.1
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: psutil>=5.9
|
|
25
|
+
Requires-Dist: pydantic-settings>=2
|
|
26
|
+
Requires-Dist: pydantic>=2.5
|
|
27
|
+
Requires-Dist: pyyaml>=6
|
|
28
|
+
Requires-Dist: rich>=13
|
|
29
|
+
Requires-Dist: sqlean-py>=0.21.7
|
|
30
|
+
Requires-Dist: structlog>=24
|
|
31
|
+
Requires-Dist: tree-sitter-go>=0.21
|
|
32
|
+
Requires-Dist: tree-sitter-javascript>=0.21
|
|
33
|
+
Requires-Dist: tree-sitter-python>=0.21
|
|
34
|
+
Requires-Dist: tree-sitter>=0.21
|
|
35
|
+
Requires-Dist: typer[all]>=0.12
|
|
36
|
+
Provides-Extra: all
|
|
37
|
+
Requires-Dist: anthropic>=0.30; extra == 'all'
|
|
38
|
+
Requires-Dist: graphiti-core>=0.3; extra == 'all'
|
|
39
|
+
Requires-Dist: jsonschema>=4.20; extra == 'all'
|
|
40
|
+
Requires-Dist: neo4j>=5.15; extra == 'all'
|
|
41
|
+
Requires-Dist: ollama>=0.2; extra == 'all'
|
|
42
|
+
Requires-Dist: openai>=1.35; extra == 'all'
|
|
43
|
+
Requires-Dist: openapi-spec-validator>=0.7; extra == 'all'
|
|
44
|
+
Requires-Dist: prance>=23; extra == 'all'
|
|
45
|
+
Requires-Dist: pygithub>=2; extra == 'all'
|
|
46
|
+
Requires-Dist: qdrant-client>=1.7; extra == 'all'
|
|
47
|
+
Requires-Dist: redis>=5; extra == 'all'
|
|
48
|
+
Requires-Dist: sarif-tools>=0.3; extra == 'all'
|
|
49
|
+
Requires-Dist: semgrep>=1.50; extra == 'all'
|
|
50
|
+
Requires-Dist: tree-sitter-java>=0.21; extra == 'all'
|
|
51
|
+
Requires-Dist: tree-sitter-ruby>=0.21; extra == 'all'
|
|
52
|
+
Requires-Dist: tree-sitter-rust>=0.21; extra == 'all'
|
|
53
|
+
Provides-Extra: anthropic
|
|
54
|
+
Requires-Dist: anthropic>=0.30; extra == 'anthropic'
|
|
55
|
+
Provides-Extra: ci
|
|
56
|
+
Requires-Dist: jsonschema>=4.20; extra == 'ci'
|
|
57
|
+
Requires-Dist: openapi-spec-validator>=0.7; extra == 'ci'
|
|
58
|
+
Requires-Dist: prance>=23; extra == 'ci'
|
|
59
|
+
Requires-Dist: pygithub>=2; extra == 'ci'
|
|
60
|
+
Requires-Dist: sarif-tools>=0.3; extra == 'ci'
|
|
61
|
+
Requires-Dist: semgrep>=1.50; extra == 'ci'
|
|
62
|
+
Requires-Dist: tree-sitter-java>=0.21; extra == 'ci'
|
|
63
|
+
Requires-Dist: tree-sitter-ruby>=0.21; extra == 'ci'
|
|
64
|
+
Requires-Dist: tree-sitter-rust>=0.21; extra == 'ci'
|
|
65
|
+
Provides-Extra: local
|
|
66
|
+
Requires-Dist: ollama>=0.2; extra == 'local'
|
|
67
|
+
Provides-Extra: openai
|
|
68
|
+
Requires-Dist: openai>=1.35; extra == 'openai'
|
|
69
|
+
Provides-Extra: standard
|
|
70
|
+
Requires-Dist: jsonschema>=4.20; extra == 'standard'
|
|
71
|
+
Requires-Dist: openapi-spec-validator>=0.7; extra == 'standard'
|
|
72
|
+
Requires-Dist: prance>=23; extra == 'standard'
|
|
73
|
+
Requires-Dist: semgrep>=1.50; extra == 'standard'
|
|
74
|
+
Requires-Dist: tree-sitter-java>=0.21; extra == 'standard'
|
|
75
|
+
Requires-Dist: tree-sitter-ruby>=0.21; extra == 'standard'
|
|
76
|
+
Requires-Dist: tree-sitter-rust>=0.21; extra == 'standard'
|
|
77
|
+
Provides-Extra: team
|
|
78
|
+
Requires-Dist: graphiti-core>=0.3; extra == 'team'
|
|
79
|
+
Requires-Dist: jsonschema>=4.20; extra == 'team'
|
|
80
|
+
Requires-Dist: neo4j>=5.15; extra == 'team'
|
|
81
|
+
Requires-Dist: openapi-spec-validator>=0.7; extra == 'team'
|
|
82
|
+
Requires-Dist: prance>=23; extra == 'team'
|
|
83
|
+
Requires-Dist: qdrant-client>=1.7; extra == 'team'
|
|
84
|
+
Requires-Dist: redis>=5; extra == 'team'
|
|
85
|
+
Requires-Dist: semgrep>=1.50; extra == 'team'
|
|
86
|
+
Requires-Dist: tree-sitter-java>=0.21; extra == 'team'
|
|
87
|
+
Requires-Dist: tree-sitter-ruby>=0.21; extra == 'team'
|
|
88
|
+
Requires-Dist: tree-sitter-rust>=0.21; extra == 'team'
|
|
89
|
+
Description-Content-Type: text/markdown
|
|
90
|
+
|
|
91
|
+
# JSAT — JaySoft AI Tools
|
|
92
|
+
|
|
93
|
+
> Codebase intelligence shell and SDK. Lightweight by default.
|
|
94
|
+
|
|
95
|
+
[](LICENSE)
|
|
96
|
+
[](https://www.python.org/downloads/)
|
|
97
|
+
[](https://github.com/iamjpsonkar)
|
|
98
|
+
|
|
99
|
+
## What is JSAT?
|
|
100
|
+
|
|
101
|
+
JSAT gives any AI (Claude, Codex, Gemini, or local Ollama) deep, structured understanding of
|
|
102
|
+
your codebase — so you spend less time explaining context and more time shipping.
|
|
103
|
+
|
|
104
|
+
- **Interactive shell** like IPython, but for codebase intelligence
|
|
105
|
+
- **Python SDK** — `from jsat import JSAT`
|
|
106
|
+
- **Works offline** with local Ollama — no API keys required
|
|
107
|
+
- **Lightweight by default** — `pip install jsat` is ~80MB and starts in <800ms
|
|
108
|
+
|
|
109
|
+
## Quick Start
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pip install jsat # core only
|
|
113
|
+
pip install jsat[local] # + Ollama for local AI (recommended)
|
|
114
|
+
|
|
115
|
+
cd your-project/
|
|
116
|
+
jsat init --profile solo # write .jsat.yaml
|
|
117
|
+
jsat index . # build the codebase graph
|
|
118
|
+
jsat # start the shell
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
JSAT Shell v0.1.0
|
|
123
|
+
> what does this project do?
|
|
124
|
+
> which services write to the orders table?
|
|
125
|
+
> blast-radius src/payment/refund.py
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Installation Profiles
|
|
129
|
+
|
|
130
|
+
| Profile | Command | Size | Use case |
|
|
131
|
+
|---------|---------|------|---------|
|
|
132
|
+
| Core | `pip install jsat` | ~80MB | Quick evaluation |
|
|
133
|
+
| Local AI | `pip install jsat[local]` | ~85MB | Solo dev with Ollama |
|
|
134
|
+
| Standard | `pip install jsat[standard]` | ~120MB | Individual engineers |
|
|
135
|
+
| Team | `pip install jsat[team]` | ~200MB | Engineering teams |
|
|
136
|
+
| CI | `pip install jsat[ci]` | ~90MB | CI pipelines (no AI cost) |
|
|
137
|
+
| Full | `pip install jsat[all]` | ~350MB | Power users |
|
|
138
|
+
|
|
139
|
+
## System Auto-Detection
|
|
140
|
+
|
|
141
|
+
JSAT probes your machine on first run and selects the right backends:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
jsat doctor # see what's detected and what to install
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
| Your setup | Graph | Embeddings | Cache |
|
|
148
|
+
|-----------|-------|-----------|-------|
|
|
149
|
+
| Laptop, Ollama running | SQLite | nomic-embed-code (local) | disk |
|
|
150
|
+
| Team server (Neo4j+Qdrant+Redis) | Neo4j | text-embedding-3-small | Redis |
|
|
151
|
+
| ARM (Apple M2, Pi) | SQLite | nomic-embed-code via Metal | disk |
|
|
152
|
+
| CI environment | SQLite | none (skipped) | memory |
|
|
153
|
+
|
|
154
|
+
## Python SDK
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from jsat import JSAT
|
|
158
|
+
|
|
159
|
+
js = JSAT(repo=".")
|
|
160
|
+
js.index()
|
|
161
|
+
|
|
162
|
+
# Natural language query
|
|
163
|
+
result = js.query("what calls the refund endpoint?")
|
|
164
|
+
print(result.answer)
|
|
165
|
+
|
|
166
|
+
# Blast radius — trace impact of a change
|
|
167
|
+
report = js.blast_radius("src/payment/refund.py")
|
|
168
|
+
for impact in report.impacts:
|
|
169
|
+
print(f"{impact.severity}: {impact.node_name}")
|
|
170
|
+
|
|
171
|
+
# Incident investigation
|
|
172
|
+
incident = js.investigate_incident("500 errors on checkout since 14:00")
|
|
173
|
+
for h in incident.hypotheses:
|
|
174
|
+
print(f"Score {h.score}: {h.commit_summary}")
|
|
175
|
+
|
|
176
|
+
# Export for sharing
|
|
177
|
+
js.export("backup.jsat.zip")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## CLI Reference
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
jsat index [PATH] [--branch HEAD] [--force]
|
|
184
|
+
jsat shell
|
|
185
|
+
jsat doctor [--refresh] [--json]
|
|
186
|
+
jsat init --profile solo|team|ci|raspberry-pi
|
|
187
|
+
jsat export OUTPUT
|
|
188
|
+
jsat import ARCHIVE
|
|
189
|
+
jsat skills list
|
|
190
|
+
jsat version
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Architecture
|
|
194
|
+
|
|
195
|
+
JSAT is built around a **graph-native architecture**:
|
|
196
|
+
|
|
197
|
+
- **tree-sitter** for multi-language AST parsing
|
|
198
|
+
- **SQLite** (local) or **Neo4j** (team) for the codebase graph
|
|
199
|
+
- **Ollama** (local) or any cloud LLM for AI features
|
|
200
|
+
- **Lazy loading** — nothing heavy loads until you use it
|
|
201
|
+
|
|
202
|
+
All backends implement ABCs — tools never call backends directly.
|
|
203
|
+
|
|
204
|
+
## Project
|
|
205
|
+
|
|
206
|
+
- **Author:** Jay Prakash Sonkar ([@iamjpsonkar](https://github.com/iamjpsonkar))
|
|
207
|
+
- **Email:** iamjpsonkar@gmail.com
|
|
208
|
+
- **License:** MIT
|
|
209
|
+
- **Specification:** [`plan.md`](plan.md) | **Implementation guide:** [`prompt.md`](prompt.md)
|
jsat-0.1.0/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# JSAT — JaySoft AI Tools
|
|
2
|
+
|
|
3
|
+
> Codebase intelligence shell and SDK. Lightweight by default.
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://www.python.org/downloads/)
|
|
7
|
+
[](https://github.com/iamjpsonkar)
|
|
8
|
+
|
|
9
|
+
## What is JSAT?
|
|
10
|
+
|
|
11
|
+
JSAT gives any AI (Claude, Codex, Gemini, or local Ollama) deep, structured understanding of
|
|
12
|
+
your codebase — so you spend less time explaining context and more time shipping.
|
|
13
|
+
|
|
14
|
+
- **Interactive shell** like IPython, but for codebase intelligence
|
|
15
|
+
- **Python SDK** — `from jsat import JSAT`
|
|
16
|
+
- **Works offline** with local Ollama — no API keys required
|
|
17
|
+
- **Lightweight by default** — `pip install jsat` is ~80MB and starts in <800ms
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install jsat # core only
|
|
23
|
+
pip install jsat[local] # + Ollama for local AI (recommended)
|
|
24
|
+
|
|
25
|
+
cd your-project/
|
|
26
|
+
jsat init --profile solo # write .jsat.yaml
|
|
27
|
+
jsat index . # build the codebase graph
|
|
28
|
+
jsat # start the shell
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
JSAT Shell v0.1.0
|
|
33
|
+
> what does this project do?
|
|
34
|
+
> which services write to the orders table?
|
|
35
|
+
> blast-radius src/payment/refund.py
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Installation Profiles
|
|
39
|
+
|
|
40
|
+
| Profile | Command | Size | Use case |
|
|
41
|
+
|---------|---------|------|---------|
|
|
42
|
+
| Core | `pip install jsat` | ~80MB | Quick evaluation |
|
|
43
|
+
| Local AI | `pip install jsat[local]` | ~85MB | Solo dev with Ollama |
|
|
44
|
+
| Standard | `pip install jsat[standard]` | ~120MB | Individual engineers |
|
|
45
|
+
| Team | `pip install jsat[team]` | ~200MB | Engineering teams |
|
|
46
|
+
| CI | `pip install jsat[ci]` | ~90MB | CI pipelines (no AI cost) |
|
|
47
|
+
| Full | `pip install jsat[all]` | ~350MB | Power users |
|
|
48
|
+
|
|
49
|
+
## System Auto-Detection
|
|
50
|
+
|
|
51
|
+
JSAT probes your machine on first run and selects the right backends:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
jsat doctor # see what's detected and what to install
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
| Your setup | Graph | Embeddings | Cache |
|
|
58
|
+
|-----------|-------|-----------|-------|
|
|
59
|
+
| Laptop, Ollama running | SQLite | nomic-embed-code (local) | disk |
|
|
60
|
+
| Team server (Neo4j+Qdrant+Redis) | Neo4j | text-embedding-3-small | Redis |
|
|
61
|
+
| ARM (Apple M2, Pi) | SQLite | nomic-embed-code via Metal | disk |
|
|
62
|
+
| CI environment | SQLite | none (skipped) | memory |
|
|
63
|
+
|
|
64
|
+
## Python SDK
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from jsat import JSAT
|
|
68
|
+
|
|
69
|
+
js = JSAT(repo=".")
|
|
70
|
+
js.index()
|
|
71
|
+
|
|
72
|
+
# Natural language query
|
|
73
|
+
result = js.query("what calls the refund endpoint?")
|
|
74
|
+
print(result.answer)
|
|
75
|
+
|
|
76
|
+
# Blast radius — trace impact of a change
|
|
77
|
+
report = js.blast_radius("src/payment/refund.py")
|
|
78
|
+
for impact in report.impacts:
|
|
79
|
+
print(f"{impact.severity}: {impact.node_name}")
|
|
80
|
+
|
|
81
|
+
# Incident investigation
|
|
82
|
+
incident = js.investigate_incident("500 errors on checkout since 14:00")
|
|
83
|
+
for h in incident.hypotheses:
|
|
84
|
+
print(f"Score {h.score}: {h.commit_summary}")
|
|
85
|
+
|
|
86
|
+
# Export for sharing
|
|
87
|
+
js.export("backup.jsat.zip")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## CLI Reference
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
jsat index [PATH] [--branch HEAD] [--force]
|
|
94
|
+
jsat shell
|
|
95
|
+
jsat doctor [--refresh] [--json]
|
|
96
|
+
jsat init --profile solo|team|ci|raspberry-pi
|
|
97
|
+
jsat export OUTPUT
|
|
98
|
+
jsat import ARCHIVE
|
|
99
|
+
jsat skills list
|
|
100
|
+
jsat version
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Architecture
|
|
104
|
+
|
|
105
|
+
JSAT is built around a **graph-native architecture**:
|
|
106
|
+
|
|
107
|
+
- **tree-sitter** for multi-language AST parsing
|
|
108
|
+
- **SQLite** (local) or **Neo4j** (team) for the codebase graph
|
|
109
|
+
- **Ollama** (local) or any cloud LLM for AI features
|
|
110
|
+
- **Lazy loading** — nothing heavy loads until you use it
|
|
111
|
+
|
|
112
|
+
All backends implement ABCs — tools never call backends directly.
|
|
113
|
+
|
|
114
|
+
## Project
|
|
115
|
+
|
|
116
|
+
- **Author:** Jay Prakash Sonkar ([@iamjpsonkar](https://github.com/iamjpsonkar))
|
|
117
|
+
- **Email:** iamjpsonkar@gmail.com
|
|
118
|
+
- **License:** MIT
|
|
119
|
+
- **Specification:** [`plan.md`](plan.md) | **Implementation guide:** [`prompt.md`](prompt.md)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
JSAT — JaySoft AI Tools
|
|
3
|
+
Codebase intelligence shell and SDK. Lightweight by default.
|
|
4
|
+
|
|
5
|
+
pip install jsat # core only (~80MB)
|
|
6
|
+
pip install jsat[local] # + Ollama
|
|
7
|
+
pip install jsat[standard] # + analysis tools
|
|
8
|
+
pip install jsat[team] # + Neo4j, Qdrant, Redis
|
|
9
|
+
pip install jsat[all] # everything
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from jsat._core import JSAT
|
|
14
|
+
from jsat._config import load_config
|
|
15
|
+
from jsat._exceptions import (
|
|
16
|
+
JSATError, ConfigError, ConfigFileNotFound, ConfigSchemaError,
|
|
17
|
+
MissingRequiredConfig, IndexError, IndexNotFound, IndexCorrupted,
|
|
18
|
+
IndexOutOfDate, UnsupportedLanguage, AIError, AIProviderError,
|
|
19
|
+
AIRateLimitError, AITimeoutError, AIContextLengthError, AIAuthError,
|
|
20
|
+
GraphError, GraphConnectionError, GraphQueryError, GraphCapacityError,
|
|
21
|
+
ProfileError, ExportError, ExportPermissionError, ImportVersionMismatch,
|
|
22
|
+
ImportCorrupted, SkillError, SkillNotFound, SkillManifestError,
|
|
23
|
+
SkillExecutionError,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__version__ = "0.1.0"
|
|
27
|
+
__author__ = "Jay Prakash Sonkar"
|
|
28
|
+
__email__ = "iamjpsonkar@gmail.com"
|
|
29
|
+
__license__ = "MIT"
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"JSAT",
|
|
33
|
+
"load_config",
|
|
34
|
+
"JSATError",
|
|
35
|
+
"__version__",
|
|
36
|
+
"__author__",
|
|
37
|
+
"__email__",
|
|
38
|
+
]
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""jsat._ai — AIProvider ABC and factory."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from typing import Any, Iterator
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AIProvider(ABC):
|
|
9
|
+
"""Contract all AI/LLM backends must implement."""
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def complete(self, prompt: str, max_tokens: int = 2048, temperature: float = 0.1) -> str: ...
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
async def complete_async(self, prompt: str, max_tokens: int = 2048, temperature: float = 0.1) -> str: ...
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def stream(self, prompt: str, max_tokens: int = 2048) -> Iterator[str]: ...
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def provider_name(self) -> str: ...
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def model_name(self) -> str: ...
|
|
27
|
+
|
|
28
|
+
def is_available(self) -> bool:
|
|
29
|
+
return True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_ai_provider(cfg: Any) -> AIProvider:
|
|
33
|
+
"""Factory: returns the right AIProvider based on cfg.ai.provider."""
|
|
34
|
+
import structlog
|
|
35
|
+
log = structlog.get_logger(__name__)
|
|
36
|
+
|
|
37
|
+
provider_name: str = getattr(getattr(cfg, "ai", None), "provider", "none") or "none"
|
|
38
|
+
log.info("ai_provider_factory", provider=provider_name)
|
|
39
|
+
|
|
40
|
+
if provider_name == "none":
|
|
41
|
+
from jsat._ai.none import NoOpProvider
|
|
42
|
+
return NoOpProvider()
|
|
43
|
+
|
|
44
|
+
if provider_name == "claude_cli":
|
|
45
|
+
from jsat._ai.claude_cli import ClaudeCliProvider
|
|
46
|
+
return ClaudeCliProvider(cfg)
|
|
47
|
+
|
|
48
|
+
if provider_name == "ollama":
|
|
49
|
+
try:
|
|
50
|
+
from jsat._ai.ollama import OllamaProvider
|
|
51
|
+
return OllamaProvider(cfg)
|
|
52
|
+
except ImportError as e:
|
|
53
|
+
_profile_error("ollama", "local", e)
|
|
54
|
+
|
|
55
|
+
if provider_name == "anthropic":
|
|
56
|
+
try:
|
|
57
|
+
from jsat._ai.anthropic import AnthropicProvider # type: ignore[import]
|
|
58
|
+
return AnthropicProvider(cfg)
|
|
59
|
+
except ImportError as e:
|
|
60
|
+
_profile_error("anthropic", "anthropic", e)
|
|
61
|
+
|
|
62
|
+
if provider_name == "openai":
|
|
63
|
+
try:
|
|
64
|
+
from jsat._ai.openai import OpenAIProvider # type: ignore[import]
|
|
65
|
+
return OpenAIProvider(cfg)
|
|
66
|
+
except ImportError as e:
|
|
67
|
+
_profile_error("openai", "openai", e)
|
|
68
|
+
|
|
69
|
+
raise ValueError(
|
|
70
|
+
f"Unknown ai.provider '{provider_name}'. "
|
|
71
|
+
"Valid: none, ollama, anthropic, openai. Run: jsat init --profile solo"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _profile_error(provider: str, extra: str, cause: ImportError) -> None:
|
|
76
|
+
import structlog
|
|
77
|
+
structlog.get_logger(__name__).error(
|
|
78
|
+
"ai_provider_import_failed", provider=provider, extra=extra, error=str(cause)
|
|
79
|
+
)
|
|
80
|
+
try:
|
|
81
|
+
from jsat._exceptions import ProfileError
|
|
82
|
+
raise ProfileError(
|
|
83
|
+
f"AI provider '{provider}' requires jsat[{extra}].\n"
|
|
84
|
+
f"Install: pip install 'jsat[{extra}]'"
|
|
85
|
+
) from cause
|
|
86
|
+
except ImportError:
|
|
87
|
+
raise ImportError(f"Install: pip install 'jsat[{extra}]'") from cause
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
__all__ = ["AIProvider", "get_ai_provider"]
|