contextly 0.1.4__tar.gz → 1.0.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.
- contextly-1.0.0/PKG-INFO +161 -0
- contextly-1.0.0/README.md +139 -0
- contextly-1.0.0/contextly/__init__.py +1 -0
- contextly-1.0.0/contextly/commands/__init__.py +1 -0
- contextly-1.0.0/contextly/commands/analyze.py +49 -0
- contextly-1.0.0/contextly/commands/discover.py +51 -0
- contextly-1.0.0/contextly/commands/export.py +42 -0
- contextly-1.0.0/contextly/commands/init.py +24 -0
- contextly-1.0.0/contextly/commands/inspect.py +39 -0
- contextly-1.0.0/contextly/commands/learn.py +61 -0
- contextly-1.0.0/contextly/commands/memory.py +47 -0
- contextly-1.0.0/contextly/commands/pack.py +57 -0
- contextly-1.0.0/contextly/core/__init__.py +1 -0
- contextly-1.0.0/contextly/core/analyzer/__init__.py +1 -0
- contextly-1.0.0/contextly/core/analyzer/engine.py +53 -0
- contextly-1.0.0/contextly/core/discovery/__init__.py +1 -0
- contextly-1.0.0/contextly/core/discovery/engine.py +22 -0
- contextly-1.0.0/contextly/core/exporter/__init__.py +1 -0
- contextly-1.0.0/contextly/core/exporter/engine.py +68 -0
- contextly-1.0.0/contextly/core/initializer/__init__.py +1 -0
- contextly-1.0.0/contextly/core/initializer/engine.py +49 -0
- contextly-1.0.0/contextly/core/inspector/__init__.py +1 -0
- contextly-1.0.0/contextly/core/inspector/engine.py +28 -0
- contextly-1.0.0/contextly/core/learner/__init__.py +1 -0
- contextly-1.0.0/contextly/core/learner/engine.py +34 -0
- contextly-1.0.0/contextly/core/memory/__init__.py +1 -0
- contextly-1.0.0/contextly/core/memory/engine.py +70 -0
- contextly-1.0.0/contextly/core/packer/__init__.py +1 -0
- contextly-1.0.0/contextly/core/packer/engine.py +84 -0
- contextly-1.0.0/contextly/generators/__init__.py +1 -0
- contextly-1.0.0/contextly/generators/base.py +63 -0
- contextly-1.0.0/contextly/generators/chatgpt.py +63 -0
- contextly-1.0.0/contextly/generators/claude.py +69 -0
- contextly-1.0.0/contextly/main.py +42 -0
- contextly-1.0.0/contextly/scanners/__init__.py +4 -0
- contextly-1.0.0/contextly/scanners/base.py +28 -0
- contextly-1.0.0/contextly/scanners/dependencies.py +91 -0
- contextly-1.0.0/contextly/scanners/framework.py +53 -0
- contextly-1.0.0/contextly/scanners/language.py +51 -0
- contextly-1.0.0/contextly/scanners/patterns.py +79 -0
- contextly-1.0.0/contextly/types/__init__.py +1 -0
- contextly-1.0.0/contextly/types/models.py +42 -0
- contextly-1.0.0/contextly/utils/__init__.py +1 -0
- contextly-1.0.0/contextly/utils/console.py +3 -0
- contextly-1.0.0/contextly/utils/exceptions.py +15 -0
- contextly-1.0.0/contextly/utils/ignore.py +74 -0
- contextly-1.0.0/contextly/utils/validation.py +26 -0
- contextly-1.0.0/contextly.egg-info/PKG-INFO +161 -0
- contextly-1.0.0/contextly.egg-info/SOURCES.txt +68 -0
- contextly-1.0.0/contextly.egg-info/dependency_links.txt +1 -0
- contextly-1.0.0/contextly.egg-info/entry_points.txt +2 -0
- contextly-1.0.0/contextly.egg-info/requires.txt +12 -0
- contextly-1.0.0/contextly.egg-info/top_level.txt +1 -0
- contextly-1.0.0/pyproject.toml +37 -0
- contextly-1.0.0/setup.cfg +4 -0
- contextly-1.0.0/tests/test_analyze.py +111 -0
- contextly-1.0.0/tests/test_core.py +77 -0
- contextly-1.0.0/tests/test_discover.py +110 -0
- contextly-1.0.0/tests/test_export.py +132 -0
- contextly-1.0.0/tests/test_generators.py +147 -0
- contextly-1.0.0/tests/test_init.py +42 -0
- contextly-1.0.0/tests/test_inspect.py +100 -0
- contextly-1.0.0/tests/test_learn.py +126 -0
- contextly-1.0.0/tests/test_memory.py +103 -0
- contextly-1.0.0/tests/test_pack.py +162 -0
- contextly-1.0.0/tests/test_scanner_base.py +22 -0
- contextly-1.0.0/tests/test_scanner_dependencies.py +163 -0
- contextly-1.0.0/tests/test_scanner_framework.py +40 -0
- contextly-1.0.0/tests/test_scanner_language.py +64 -0
- contextly-1.0.0/tests/test_scanner_patterns.py +50 -0
- contextly-0.1.4/.gitignore +0 -42
- contextly-0.1.4/LICENSE +0 -21
- contextly-0.1.4/PKG-INFO +0 -209
- contextly-0.1.4/README.md +0 -150
- contextly-0.1.4/pyproject.toml +0 -110
- contextly-0.1.4/src/contextly/__init__.py +0 -5
- contextly-0.1.4/src/contextly/app.py +0 -111
- contextly-0.1.4/src/contextly/cli.py +0 -201
- contextly-0.1.4/src/contextly/core/analyzer.py +0 -118
- contextly-0.1.4/src/contextly/core/embeddings.py +0 -129
- contextly-0.1.4/src/contextly/core/sync.py +0 -66
- contextly-0.1.4/src/contextly/llm/__init__.py +0 -13
- contextly-0.1.4/src/contextly/llm/base.py +0 -19
- contextly-0.1.4/src/contextly/llm/manager.py +0 -126
- contextly-0.1.4/src/contextly/llm/models.py +0 -213
- contextly-0.1.4/src/contextly/llm/ollama.py +0 -73
- contextly-0.1.4/src/contextly/llm/openai.py +0 -41
- contextly-0.1.4/src/contextly/parsers/base.py +0 -39
- contextly-0.1.4/src/contextly/parsers/config.py +0 -79
- contextly-0.1.4/src/contextly/parsers/javascript.py +0 -122
- contextly-0.1.4/src/contextly/parsers/python.py +0 -60
- contextly-0.1.4/tests/test_core.py +0 -156
contextly-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: contextly
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The ultimate context-engineering workspace CLI for LLMs.
|
|
5
|
+
Author: Contextly Team
|
|
6
|
+
Project-URL: Homepage, https://github.com/vutikurishanmukha9/Contextly
|
|
7
|
+
Project-URL: Repository, https://github.com/vutikurishanmukha9/Contextly.git
|
|
8
|
+
Project-URL: Changelog, https://github.com/vutikurishanmukha9/Contextly/blob/main/cli/CHANGELOG.md
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: typer>=0.12.0
|
|
12
|
+
Requires-Dist: rich>=13.7.0
|
|
13
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
14
|
+
Requires-Dist: pydantic>=2.0.0
|
|
15
|
+
Requires-Dist: pathspec>=0.12.0
|
|
16
|
+
Requires-Dist: pyperclip>=1.8.2
|
|
17
|
+
Requires-Dist: tomli>=2.0.1
|
|
18
|
+
Requires-Dist: tiktoken>=0.7.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
22
|
+
|
|
23
|
+
# Context-Ly
|
|
24
|
+
|
|
25
|
+
**Imagine trying to hire a new employee, but instead of giving them an employee handbook, a map of the office, and a list of company rules, you just dump 10,000 loose papers on their desk and say, "figure it out."**
|
|
26
|
+
|
|
27
|
+
That is how most people use AI today. They dump raw files into ChatGPT or Claude and hope for the best. The AI gets confused, makes mistakes, and wastes time.
|
|
28
|
+
|
|
29
|
+
**Context-Ly fixes this.**
|
|
30
|
+
|
|
31
|
+
Context-Ly is a tool that automatically reads your project, figures out your unwritten rules, maps out how everything is connected, and packages it perfectly for AI. When you use Context-Ly, the AI instantly understands your project exactly like a senior engineer would—saving you hours of typing, explaining, and correcting.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Overview
|
|
36
|
+
|
|
37
|
+
Modern AI applications often suffer from "token waste" - providing either too little context (requiring repeated clarifications) or too much irrelevant context (diluting the model's focus). Context-Ly solves this by introducing a structured methodology for building context packs.
|
|
38
|
+
|
|
39
|
+
The application sits between the user's raw thoughts and the AI model, enforcing best practices in prompt engineering through an intuitive interface and a real-time heuristic scoring engine.
|
|
40
|
+
|
|
41
|
+
## Core Features
|
|
42
|
+
|
|
43
|
+
### 1. Context Builder
|
|
44
|
+
The Context Builder allows users to break down their prompts into distinct, manageable blocks:
|
|
45
|
+
- **Goal**: The primary objective or task (What does success look like?).
|
|
46
|
+
- **Background**: Necessary prerequisite information for the model.
|
|
47
|
+
- **Constraints**: Strict boundaries, desired tone, and format restrictions.
|
|
48
|
+
- **Examples**: Few-shot examples, gold standards, or anti-examples to guide the model.
|
|
49
|
+
- **Files**: Supporting reference materials such as code snippets or documentation.
|
|
50
|
+
|
|
51
|
+
### 2. Real-Time Context Scoring
|
|
52
|
+
Every context pack is graded algorithmically before it touches an LLM. The scoring engine evaluates the context across four axes:
|
|
53
|
+
- **Relevance**: Analyzes the word overlap ratio between the Goal block and all supporting blocks to ensure every token serves the primary objective.
|
|
54
|
+
- **Completeness**: Verifies the presence of necessary structural components (e.g., heavily penalizing the absence of a defined Goal or Constraints).
|
|
55
|
+
- **Redundancy**: Utilizes Jaccard similarity to detect and penalize repetitive information across different blocks.
|
|
56
|
+
- **Clarity**: Evaluates sentence complexity (penalizing average sentence lengths over 25 words) and detects the excessive use of ambiguous pronouns ("it", "that", "those").
|
|
57
|
+
|
|
58
|
+
### 3. Prompt Generator
|
|
59
|
+
The generator compiles the active context blocks into a clean, markdown-structured system prompt. It clearly separates the permanent system context (Audience, Tech Stack, Output Style) from the temporary task context, ensuring the output is perfectly formatted for direct integration into tools like ChatGPT, Claude, or API requests.
|
|
60
|
+
|
|
61
|
+
## Technical Architecture
|
|
62
|
+
|
|
63
|
+
The application is designed with strict separation of concerns, ensuring that the core business logic remains framework-agnostic.
|
|
64
|
+
|
|
65
|
+
- **Frontend Framework**: React with TanStack Start
|
|
66
|
+
- **Styling**: Tailwind CSS and Radix UI (Shadcn components)
|
|
67
|
+
- **State Management**: Zustand with `localStorage` persistence module
|
|
68
|
+
- **Core Engine**: Pure TypeScript logic (`scoring.ts` and `prompt-generator.ts`) completely decoupled from the DOM and React ecosystem, ensuring straightforward migration to alternative interfaces (such as a CLI) in the future.
|
|
69
|
+
|
|
70
|
+
## Local Development
|
|
71
|
+
|
|
72
|
+
The web application resides entirely within the `frontend` directory.
|
|
73
|
+
|
|
74
|
+
### Prerequisites
|
|
75
|
+
- Node.js (v20 or higher recommended)
|
|
76
|
+
- npm
|
|
77
|
+
|
|
78
|
+
### Installation
|
|
79
|
+
|
|
80
|
+
1. Clone the repository and navigate to the frontend directory:
|
|
81
|
+
```bash
|
|
82
|
+
cd frontend
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
2. Install the project dependencies:
|
|
86
|
+
```bash
|
|
87
|
+
npm install
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
3. Start the development server:
|
|
91
|
+
```bash
|
|
92
|
+
npm run dev
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
4. Open your browser and navigate to the provided local address (typically `http://localhost:5173`).
|
|
96
|
+
|
|
97
|
+
## Project Structure
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
frontend/
|
|
101
|
+
├── src/
|
|
102
|
+
│ ├── components/ # Reusable UI components (AppShell, Canvas, Optimizer)
|
|
103
|
+
│ ├── lib/
|
|
104
|
+
│ │ ├── prompt-generator.ts # Logic for formatting the final markdown prompt
|
|
105
|
+
│ │ ├── scoring.ts # Heuristic mathematical scoring engine
|
|
106
|
+
│ │ └── store.ts # Zustand state management and persistence
|
|
107
|
+
│ └── routes/ # TanStack Start routing layer
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Context-Ly CLI: The Intelligence Layer
|
|
111
|
+
|
|
112
|
+
The true value of Context-Ly lies in its command-line interface, which transforms the tool from a simple prompt formatter into a persistent **Context Memory Layer** for your entire repository.
|
|
113
|
+
|
|
114
|
+
The CLI acts as a static analysis tool that discovers team conventions, evaluates repository complexity, and generates highly-optimized, token-efficient system prompts (`PROJECT_CONTEXT.md`) tailored to your exact stack.
|
|
115
|
+
|
|
116
|
+
### Setup
|
|
117
|
+
|
|
118
|
+
To begin using the CLI, activate the Python virtual environment located in the `cli` directory:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
cd cli
|
|
122
|
+
.\venv\Scripts\activate
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Commands
|
|
126
|
+
|
|
127
|
+
#### 1. `contextly init`
|
|
128
|
+
Initializes Context-as-Code in the current directory. It creates a `.contextly` configuration folder and sets up your environment.
|
|
129
|
+
|
|
130
|
+
#### 2. `contextly analyze`
|
|
131
|
+
The ultimate context generator. This command automatically:
|
|
132
|
+
- Reads your `README.md`.
|
|
133
|
+
- Scans your entire project tree to build an ASCII architecture map.
|
|
134
|
+
- Inspects your dependencies to determine your language and framework (e.g. TypeScript, React).
|
|
135
|
+
- Pulls in both manually saved rules and statically inferred conventions.
|
|
136
|
+
- Merges everything into a massive, LLM-ready system prompt named `PROJECT_CONTEXT.md`.
|
|
137
|
+
|
|
138
|
+
#### 3. `contextly discover`
|
|
139
|
+
Runs the Pattern Discovery Engine. It statically analyzes the codebase using dependency heuristics and file-tree structures to figure out your team's unwritten conventions (e.g. "Uses Zustand", "Uses TailwindCSS", "Service Layer Hint").
|
|
140
|
+
|
|
141
|
+
#### 4. `contextly learn --auto`
|
|
142
|
+
The interactive gatekeeper to the True Memory Engine. It triggers the Discovery Engine and interactively asks if you want to save the discovered conventions:
|
|
143
|
+
```text
|
|
144
|
+
Save convention: TailwindCSS (Uses TailwindCSS for styling.)? [y/N]
|
|
145
|
+
```
|
|
146
|
+
Confirmed conventions are saved permanently to `.contextly/memory/rules.yaml`.
|
|
147
|
+
|
|
148
|
+
#### 5. `contextly memory`
|
|
149
|
+
Trust requires visibility. Use this command to inspect all rules and conventions that have been permanently saved to the project's memory.
|
|
150
|
+
|
|
151
|
+
#### 6. `contextly pack <dir>`
|
|
152
|
+
Bundles a specific directory (e.g., `src/components`) into an LLM-ready Context Pack. It reads all files, counts their tokens, and bundles them into `.contextly/packs/` so you can effortlessly copy-paste large portions of your codebase into an LLM without clutter.
|
|
153
|
+
|
|
154
|
+
#### 7. `contextly inspect`
|
|
155
|
+
Performs a deep-dive analysis on your repository complexity, warning you about excessively large files that will act as "Token Hogs" and consume too much context window.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Changelog
|
|
160
|
+
|
|
161
|
+
For all release notes and version history, please see the [CHANGELOG.md](CHANGELOG.md).
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Context-Ly
|
|
2
|
+
|
|
3
|
+
**Imagine trying to hire a new employee, but instead of giving them an employee handbook, a map of the office, and a list of company rules, you just dump 10,000 loose papers on their desk and say, "figure it out."**
|
|
4
|
+
|
|
5
|
+
That is how most people use AI today. They dump raw files into ChatGPT or Claude and hope for the best. The AI gets confused, makes mistakes, and wastes time.
|
|
6
|
+
|
|
7
|
+
**Context-Ly fixes this.**
|
|
8
|
+
|
|
9
|
+
Context-Ly is a tool that automatically reads your project, figures out your unwritten rules, maps out how everything is connected, and packages it perfectly for AI. When you use Context-Ly, the AI instantly understands your project exactly like a senior engineer would—saving you hours of typing, explaining, and correcting.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
Modern AI applications often suffer from "token waste" - providing either too little context (requiring repeated clarifications) or too much irrelevant context (diluting the model's focus). Context-Ly solves this by introducing a structured methodology for building context packs.
|
|
16
|
+
|
|
17
|
+
The application sits between the user's raw thoughts and the AI model, enforcing best practices in prompt engineering through an intuitive interface and a real-time heuristic scoring engine.
|
|
18
|
+
|
|
19
|
+
## Core Features
|
|
20
|
+
|
|
21
|
+
### 1. Context Builder
|
|
22
|
+
The Context Builder allows users to break down their prompts into distinct, manageable blocks:
|
|
23
|
+
- **Goal**: The primary objective or task (What does success look like?).
|
|
24
|
+
- **Background**: Necessary prerequisite information for the model.
|
|
25
|
+
- **Constraints**: Strict boundaries, desired tone, and format restrictions.
|
|
26
|
+
- **Examples**: Few-shot examples, gold standards, or anti-examples to guide the model.
|
|
27
|
+
- **Files**: Supporting reference materials such as code snippets or documentation.
|
|
28
|
+
|
|
29
|
+
### 2. Real-Time Context Scoring
|
|
30
|
+
Every context pack is graded algorithmically before it touches an LLM. The scoring engine evaluates the context across four axes:
|
|
31
|
+
- **Relevance**: Analyzes the word overlap ratio between the Goal block and all supporting blocks to ensure every token serves the primary objective.
|
|
32
|
+
- **Completeness**: Verifies the presence of necessary structural components (e.g., heavily penalizing the absence of a defined Goal or Constraints).
|
|
33
|
+
- **Redundancy**: Utilizes Jaccard similarity to detect and penalize repetitive information across different blocks.
|
|
34
|
+
- **Clarity**: Evaluates sentence complexity (penalizing average sentence lengths over 25 words) and detects the excessive use of ambiguous pronouns ("it", "that", "those").
|
|
35
|
+
|
|
36
|
+
### 3. Prompt Generator
|
|
37
|
+
The generator compiles the active context blocks into a clean, markdown-structured system prompt. It clearly separates the permanent system context (Audience, Tech Stack, Output Style) from the temporary task context, ensuring the output is perfectly formatted for direct integration into tools like ChatGPT, Claude, or API requests.
|
|
38
|
+
|
|
39
|
+
## Technical Architecture
|
|
40
|
+
|
|
41
|
+
The application is designed with strict separation of concerns, ensuring that the core business logic remains framework-agnostic.
|
|
42
|
+
|
|
43
|
+
- **Frontend Framework**: React with TanStack Start
|
|
44
|
+
- **Styling**: Tailwind CSS and Radix UI (Shadcn components)
|
|
45
|
+
- **State Management**: Zustand with `localStorage` persistence module
|
|
46
|
+
- **Core Engine**: Pure TypeScript logic (`scoring.ts` and `prompt-generator.ts`) completely decoupled from the DOM and React ecosystem, ensuring straightforward migration to alternative interfaces (such as a CLI) in the future.
|
|
47
|
+
|
|
48
|
+
## Local Development
|
|
49
|
+
|
|
50
|
+
The web application resides entirely within the `frontend` directory.
|
|
51
|
+
|
|
52
|
+
### Prerequisites
|
|
53
|
+
- Node.js (v20 or higher recommended)
|
|
54
|
+
- npm
|
|
55
|
+
|
|
56
|
+
### Installation
|
|
57
|
+
|
|
58
|
+
1. Clone the repository and navigate to the frontend directory:
|
|
59
|
+
```bash
|
|
60
|
+
cd frontend
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
2. Install the project dependencies:
|
|
64
|
+
```bash
|
|
65
|
+
npm install
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
3. Start the development server:
|
|
69
|
+
```bash
|
|
70
|
+
npm run dev
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
4. Open your browser and navigate to the provided local address (typically `http://localhost:5173`).
|
|
74
|
+
|
|
75
|
+
## Project Structure
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
frontend/
|
|
79
|
+
├── src/
|
|
80
|
+
│ ├── components/ # Reusable UI components (AppShell, Canvas, Optimizer)
|
|
81
|
+
│ ├── lib/
|
|
82
|
+
│ │ ├── prompt-generator.ts # Logic for formatting the final markdown prompt
|
|
83
|
+
│ │ ├── scoring.ts # Heuristic mathematical scoring engine
|
|
84
|
+
│ │ └── store.ts # Zustand state management and persistence
|
|
85
|
+
│ └── routes/ # TanStack Start routing layer
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Context-Ly CLI: The Intelligence Layer
|
|
89
|
+
|
|
90
|
+
The true value of Context-Ly lies in its command-line interface, which transforms the tool from a simple prompt formatter into a persistent **Context Memory Layer** for your entire repository.
|
|
91
|
+
|
|
92
|
+
The CLI acts as a static analysis tool that discovers team conventions, evaluates repository complexity, and generates highly-optimized, token-efficient system prompts (`PROJECT_CONTEXT.md`) tailored to your exact stack.
|
|
93
|
+
|
|
94
|
+
### Setup
|
|
95
|
+
|
|
96
|
+
To begin using the CLI, activate the Python virtual environment located in the `cli` directory:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
cd cli
|
|
100
|
+
.\venv\Scripts\activate
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Commands
|
|
104
|
+
|
|
105
|
+
#### 1. `contextly init`
|
|
106
|
+
Initializes Context-as-Code in the current directory. It creates a `.contextly` configuration folder and sets up your environment.
|
|
107
|
+
|
|
108
|
+
#### 2. `contextly analyze`
|
|
109
|
+
The ultimate context generator. This command automatically:
|
|
110
|
+
- Reads your `README.md`.
|
|
111
|
+
- Scans your entire project tree to build an ASCII architecture map.
|
|
112
|
+
- Inspects your dependencies to determine your language and framework (e.g. TypeScript, React).
|
|
113
|
+
- Pulls in both manually saved rules and statically inferred conventions.
|
|
114
|
+
- Merges everything into a massive, LLM-ready system prompt named `PROJECT_CONTEXT.md`.
|
|
115
|
+
|
|
116
|
+
#### 3. `contextly discover`
|
|
117
|
+
Runs the Pattern Discovery Engine. It statically analyzes the codebase using dependency heuristics and file-tree structures to figure out your team's unwritten conventions (e.g. "Uses Zustand", "Uses TailwindCSS", "Service Layer Hint").
|
|
118
|
+
|
|
119
|
+
#### 4. `contextly learn --auto`
|
|
120
|
+
The interactive gatekeeper to the True Memory Engine. It triggers the Discovery Engine and interactively asks if you want to save the discovered conventions:
|
|
121
|
+
```text
|
|
122
|
+
Save convention: TailwindCSS (Uses TailwindCSS for styling.)? [y/N]
|
|
123
|
+
```
|
|
124
|
+
Confirmed conventions are saved permanently to `.contextly/memory/rules.yaml`.
|
|
125
|
+
|
|
126
|
+
#### 5. `contextly memory`
|
|
127
|
+
Trust requires visibility. Use this command to inspect all rules and conventions that have been permanently saved to the project's memory.
|
|
128
|
+
|
|
129
|
+
#### 6. `contextly pack <dir>`
|
|
130
|
+
Bundles a specific directory (e.g., `src/components`) into an LLM-ready Context Pack. It reads all files, counts their tokens, and bundles them into `.contextly/packs/` so you can effortlessly copy-paste large portions of your codebase into an LLM without clutter.
|
|
131
|
+
|
|
132
|
+
#### 7. `contextly inspect`
|
|
133
|
+
Performs a deep-dive analysis on your repository complexity, warning you about excessively large files that will act as "Token Hogs" and consume too much context window.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Changelog
|
|
138
|
+
|
|
139
|
+
For all release notes and version history, please see the [CHANGELOG.md](CHANGELOG.md).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Contextly CLI Package
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Init commands
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from ..utils.console import console
|
|
6
|
+
from ..scanners.base import ScannerError
|
|
7
|
+
from ..utils.exceptions import ContextlyError
|
|
8
|
+
from ..core.analyzer.engine import AnalyzerEngine
|
|
9
|
+
|
|
10
|
+
def analyze_cmd(model: str = typer.Option("chatgpt", "--model", "-m", help="Target LLM format ('chatgpt' or 'claude')")):
|
|
11
|
+
"""Automatically analyze and map the repository"""
|
|
12
|
+
root_dir = Path.cwd()
|
|
13
|
+
engine = AnalyzerEngine(root_dir)
|
|
14
|
+
|
|
15
|
+
with console.status("[bold blue]Scanning repository intelligence (Max Level)...", spinner="dots"):
|
|
16
|
+
try:
|
|
17
|
+
intelligence = engine.analyze(model)
|
|
18
|
+
except ScannerError as e:
|
|
19
|
+
console.print(f"\n[bold red]Scanner Error:[/bold red] {e}")
|
|
20
|
+
raise typer.Exit(1)
|
|
21
|
+
except ContextlyError as e:
|
|
22
|
+
console.print(f"\n[bold red]Context-Ly Error:[/bold red] {e}")
|
|
23
|
+
raise typer.Exit(1)
|
|
24
|
+
except Exception as e:
|
|
25
|
+
console.print(f"\n[bold red]Unexpected Error:[/bold red] {e}")
|
|
26
|
+
raise typer.Exit(1)
|
|
27
|
+
|
|
28
|
+
console.print("\n[bold green][OK][/bold green] Repository scan complete!\n")
|
|
29
|
+
|
|
30
|
+
table = Table(title="Repository Intelligence (Max Level)", show_header=False, box=None)
|
|
31
|
+
table.add_column("Category", style="cyan", justify="right")
|
|
32
|
+
table.add_column("Value", style="magenta")
|
|
33
|
+
|
|
34
|
+
table.add_row("Primary Language", f"[bold]{intelligence.language.primary}[/bold]")
|
|
35
|
+
table.add_row("Frontend Framework", intelligence.frameworks.frontend)
|
|
36
|
+
table.add_row("Backend/Tooling", intelligence.frameworks.backend)
|
|
37
|
+
|
|
38
|
+
npm_count = len(intelligence.dependencies.npm)
|
|
39
|
+
py_count = len(intelligence.dependencies.python)
|
|
40
|
+
|
|
41
|
+
if npm_count > 0:
|
|
42
|
+
table.add_row("NPM Dependencies", str(npm_count))
|
|
43
|
+
if py_count > 0:
|
|
44
|
+
table.add_row("Python Dependencies", str(py_count))
|
|
45
|
+
|
|
46
|
+
console.print(table)
|
|
47
|
+
console.print()
|
|
48
|
+
console.print(f"[dim]Generated advanced PROJECT_CONTEXT.md ({model.lower()} format) in current directory.[/dim]")
|
|
49
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import typer
|
|
3
|
+
|
|
4
|
+
from ..utils.console import console
|
|
5
|
+
from ..core.discovery.engine import DiscoveryEngine
|
|
6
|
+
from ..scanners.base import ScannerError
|
|
7
|
+
from ..utils.exceptions import ValidationError, ContextlyError
|
|
8
|
+
from ..utils.validation import require_contextly_initialized
|
|
9
|
+
|
|
10
|
+
def discover_cmd():
|
|
11
|
+
"""Statically analyze the repository to discover architectural patterns and conventions"""
|
|
12
|
+
root_dir = Path.cwd()
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
require_contextly_initialized(root_dir)
|
|
16
|
+
except ValidationError as e:
|
|
17
|
+
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
18
|
+
raise typer.Exit(code=1)
|
|
19
|
+
|
|
20
|
+
engine = DiscoveryEngine(root_dir)
|
|
21
|
+
|
|
22
|
+
with console.status("[bold blue]Running Pattern Discovery Engine...", spinner="dots"):
|
|
23
|
+
try:
|
|
24
|
+
patterns_result = engine.discover()
|
|
25
|
+
except ScannerError as e:
|
|
26
|
+
console.print(f"\n[bold red]Scanner Error:[/bold red] {e}")
|
|
27
|
+
raise typer.Exit(code=1)
|
|
28
|
+
except ContextlyError as e:
|
|
29
|
+
console.print(f"\n[bold red]Context-Ly Error:[/bold red] {e}")
|
|
30
|
+
raise typer.Exit(code=1)
|
|
31
|
+
|
|
32
|
+
console.print("[bold green][OK][/bold green] Pattern Discovery Complete:\n")
|
|
33
|
+
|
|
34
|
+
if not patterns_result.patterns:
|
|
35
|
+
console.print("[yellow]No recognizable architectural patterns or conventions discovered.[/yellow]")
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
# Group by category
|
|
39
|
+
categories = {}
|
|
40
|
+
for p in patterns_result.patterns:
|
|
41
|
+
if p.category not in categories:
|
|
42
|
+
categories[p.category] = []
|
|
43
|
+
categories[p.category].append(p)
|
|
44
|
+
|
|
45
|
+
for category, patterns in sorted(categories.items()):
|
|
46
|
+
console.print(f"[bold cyan]{category}:[/bold cyan]")
|
|
47
|
+
# Sort by confidence descending (High -> Medium -> Low)
|
|
48
|
+
sorted_patterns = sorted(patterns, key=lambda p: {"high": 0, "medium": 1, "low": 2}.get(p.confidence.lower(), 3))
|
|
49
|
+
for p in sorted_patterns:
|
|
50
|
+
console.print(f" [green]\\[OK][/green] [bold]{p.name}[/bold] ({p.description})")
|
|
51
|
+
console.print()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from ..utils.console import console
|
|
4
|
+
from ..core.exporter.engine import ExporterEngine
|
|
5
|
+
from ..utils.validation import require_contextly_initialized
|
|
6
|
+
from ..utils.exceptions import ValidationError, ContextlyError
|
|
7
|
+
|
|
8
|
+
def export_cmd(
|
|
9
|
+
pack_name: str = typer.Argument(..., help="The name of the context pack to export (e.g., 'frontend')")
|
|
10
|
+
):
|
|
11
|
+
"""Fuses intelligence and context packs, copying the result to your clipboard."""
|
|
12
|
+
root_dir = Path.cwd()
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
require_contextly_initialized(root_dir)
|
|
16
|
+
except ValidationError as e:
|
|
17
|
+
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
18
|
+
raise typer.Exit(code=1)
|
|
19
|
+
|
|
20
|
+
engine = ExporterEngine(root_dir)
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
export_path, clipboard_success = engine.export(pack_name)
|
|
24
|
+
except ContextlyError as e:
|
|
25
|
+
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
26
|
+
raise typer.Exit(code=1)
|
|
27
|
+
|
|
28
|
+
if clipboard_success:
|
|
29
|
+
clipboard_status = "[green]Successfully copied to clipboard![/green]"
|
|
30
|
+
else:
|
|
31
|
+
clipboard_status = "[yellow]Could not copy to clipboard. The export file was saved successfully.[/yellow]"
|
|
32
|
+
|
|
33
|
+
console.print(f"\n[bold green][OK][/bold green] Export Generation Complete!")
|
|
34
|
+
console.print(f" - [cyan]Intelligence:[/cyan] PROJECT_CONTEXT.md")
|
|
35
|
+
console.print(f" - [cyan]Context Pack:[/cyan] {pack_name}")
|
|
36
|
+
console.print(f" - [cyan]Local Export:[/cyan] {export_path.relative_to(root_dir)}")
|
|
37
|
+
console.print(f"\n{clipboard_status}")
|
|
38
|
+
if clipboard_success:
|
|
39
|
+
console.print("\nYou can now paste the contents directly into Claude or ChatGPT.")
|
|
40
|
+
else:
|
|
41
|
+
console.print("\nOpen the local export file to copy the contents manually.")
|
|
42
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from ..utils.console import console
|
|
4
|
+
from ..core.initializer.engine import InitEngine
|
|
5
|
+
from ..utils.exceptions import ContextlyError
|
|
6
|
+
|
|
7
|
+
def init_cmd():
|
|
8
|
+
"""Initialize Context-as-Code in the current directory"""
|
|
9
|
+
root_dir = Path.cwd()
|
|
10
|
+
engine = InitEngine(root_dir)
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
success = engine.initialize()
|
|
14
|
+
if not success:
|
|
15
|
+
console.print("[yellow]Contextly is already initialized in this repository.[/yellow]")
|
|
16
|
+
return
|
|
17
|
+
|
|
18
|
+
console.print("[bold green][OK][/bold green] Contextly initialized successfully!")
|
|
19
|
+
console.print(f"Created configuration at [cyan].contextly/config.yaml[/cyan]")
|
|
20
|
+
console.print("Edit this file to define your Context-as-Code rules.")
|
|
21
|
+
|
|
22
|
+
except ContextlyError as e:
|
|
23
|
+
console.print(f"[bold red]Error initializing Contextly:[/bold red] {str(e)}")
|
|
24
|
+
raise typer.Exit(code=1)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from ..utils.console import console
|
|
4
|
+
from ..utils.exceptions import ValidationError
|
|
5
|
+
from ..utils.validation import require_directory_exists
|
|
6
|
+
from ..core.inspector.engine import InspectorEngine
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
def inspect_cmd():
|
|
10
|
+
"""Deep dive into repository complexity and structure"""
|
|
11
|
+
try:
|
|
12
|
+
root_dir = require_directory_exists(str(Path.cwd()))
|
|
13
|
+
except ValidationError as e:
|
|
14
|
+
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
15
|
+
raise typer.Exit(code=1)
|
|
16
|
+
|
|
17
|
+
engine = InspectorEngine(root_dir)
|
|
18
|
+
|
|
19
|
+
with console.status("[bold blue]Inspecting repository file tree...", spinner="bouncingBar"):
|
|
20
|
+
file_sizes = engine.inspect()
|
|
21
|
+
|
|
22
|
+
console.print("\n[bold green][OK][/bold green] Inspection complete!\n")
|
|
23
|
+
|
|
24
|
+
table = Table(title="Top 5 Largest Files (Potential Token Hogs)")
|
|
25
|
+
table.add_column("Size (KB)", justify="right", style="cyan")
|
|
26
|
+
table.add_column("File Path", style="magenta")
|
|
27
|
+
|
|
28
|
+
for size, path in file_sizes[:5]:
|
|
29
|
+
rel_path = path.relative_to(root_dir)
|
|
30
|
+
kb_size = size / 1024
|
|
31
|
+
|
|
32
|
+
# Highlight massive files that shouldn't go to LLMs
|
|
33
|
+
style = "red" if kb_size > 100 else "yellow" if kb_size > 50 else "white"
|
|
34
|
+
|
|
35
|
+
table.add_row(f"{kb_size:.1f}", f"[{style}]{rel_path}[/{style}]")
|
|
36
|
+
|
|
37
|
+
console.print(table)
|
|
38
|
+
console.print("\n[dim]Tip: Files over 50KB (yellow) or 100KB (red) consume massive LLM context windows. Keep them out of your Context Packs if possible.[/dim]\n")
|
|
39
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from rich.prompt import Confirm
|
|
4
|
+
from ..utils.console import console
|
|
5
|
+
from ..core.learner.engine import LearnEngine
|
|
6
|
+
from ..scanners.base import ScannerError
|
|
7
|
+
from ..utils.exceptions import ValidationError, ContextlyError
|
|
8
|
+
from ..utils.validation import require_contextly_initialized
|
|
9
|
+
|
|
10
|
+
def learn_cmd(
|
|
11
|
+
auto: bool = typer.Option(False, "--auto", help="Automatically discover and interactively learn conventions.")
|
|
12
|
+
):
|
|
13
|
+
"""Teach Context-Ly new conventions, or use --auto to discover them."""
|
|
14
|
+
root_dir = Path.cwd()
|
|
15
|
+
try:
|
|
16
|
+
require_contextly_initialized(root_dir)
|
|
17
|
+
except ValidationError as e:
|
|
18
|
+
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
19
|
+
raise typer.Exit(code=1)
|
|
20
|
+
|
|
21
|
+
engine = LearnEngine(root_dir)
|
|
22
|
+
|
|
23
|
+
if not auto:
|
|
24
|
+
console.print("[yellow]Manual learning is currently disabled in favor of automated discovery.[/yellow]")
|
|
25
|
+
console.print("Please use [bold cyan]contextly learn --auto[/bold cyan]")
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
with console.status("[bold blue]Running Pattern Discovery Engine...", spinner="dots"):
|
|
29
|
+
try:
|
|
30
|
+
sorted_patterns = engine.discover_conventions()
|
|
31
|
+
except ScannerError as e:
|
|
32
|
+
console.print(f"\n[bold red]Scanner Error:[/bold red] {e}")
|
|
33
|
+
raise typer.Exit(code=1)
|
|
34
|
+
except ContextlyError as e:
|
|
35
|
+
console.print(f"\n[bold red]Context-Ly Error:[/bold red] {e}")
|
|
36
|
+
raise typer.Exit(code=1)
|
|
37
|
+
|
|
38
|
+
if not sorted_patterns:
|
|
39
|
+
console.print("[yellow]No new recognizable conventions discovered to learn.[/yellow]")
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
console.print("\n[bold green]Discovered Conventions:[/bold green]\n")
|
|
43
|
+
|
|
44
|
+
saved_count = 0
|
|
45
|
+
for p in sorted_patterns:
|
|
46
|
+
if Confirm.ask(f"Save convention: [cyan]{p.name}[/cyan] ({p.description})?"):
|
|
47
|
+
added = engine.save_convention(p)
|
|
48
|
+
if added:
|
|
49
|
+
saved_count += 1
|
|
50
|
+
console.print(f" [green]\\[OK][/green] Saved to memory.")
|
|
51
|
+
else:
|
|
52
|
+
console.print(f" [dim]Skipped (Already in memory).[/dim]")
|
|
53
|
+
else:
|
|
54
|
+
console.print(f" [dim]Skipped.[/dim]")
|
|
55
|
+
|
|
56
|
+
if saved_count > 0:
|
|
57
|
+
console.print(f"\n[bold green][OK][/bold green] Successfully saved {saved_count} rules to persistent memory!")
|
|
58
|
+
console.print("Run [bold cyan]contextly memory[/bold cyan] to view them.")
|
|
59
|
+
else:
|
|
60
|
+
console.print("\n[dim]No new rules were saved.[/dim]")
|
|
61
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from rich.table import Table
|
|
3
|
+
from ..utils.console import console
|
|
4
|
+
from ..core.memory import MemoryEngine
|
|
5
|
+
from ..utils.exceptions import ValidationError
|
|
6
|
+
from ..utils.validation import require_contextly_initialized
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
def memory_cmd():
|
|
10
|
+
"""Inspect the persistently stored team memory and conventions."""
|
|
11
|
+
root_dir = Path.cwd()
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
require_contextly_initialized(root_dir)
|
|
15
|
+
except ValidationError as e:
|
|
16
|
+
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
17
|
+
raise typer.Exit(code=1)
|
|
18
|
+
|
|
19
|
+
engine = MemoryEngine(root_dir)
|
|
20
|
+
|
|
21
|
+
memory = engine.load_memory()
|
|
22
|
+
|
|
23
|
+
if not memory.rules:
|
|
24
|
+
console.print("[yellow]Context-Ly memory is currently empty.[/yellow]")
|
|
25
|
+
console.print("Run [bold cyan]contextly learn --auto[/bold cyan] to discover and save team conventions.")
|
|
26
|
+
return
|
|
27
|
+
|
|
28
|
+
console.print(f"[bold green]Stored Memory[/bold green] (Found {len(memory.rules)} rules)\n")
|
|
29
|
+
|
|
30
|
+
# Group by category
|
|
31
|
+
categories = {}
|
|
32
|
+
for rule in memory.rules:
|
|
33
|
+
if rule.category not in categories:
|
|
34
|
+
categories[rule.category] = []
|
|
35
|
+
categories[rule.category].append(rule)
|
|
36
|
+
|
|
37
|
+
for category, rules in sorted(categories.items()):
|
|
38
|
+
console.print(f"[bold cyan]{category}[/bold cyan]")
|
|
39
|
+
# Sort by confidence descending (High -> Medium -> Low)
|
|
40
|
+
sorted_rules = sorted(rules, key=lambda r: {"high": 0, "medium": 1, "low": 2}.get(r.confidence.lower(), 3))
|
|
41
|
+
for rule in sorted_rules:
|
|
42
|
+
source_tag = f"[dim]({rule.source})[/dim]"
|
|
43
|
+
conf_color = "green" if rule.confidence.lower() == "high" else "yellow"
|
|
44
|
+
conf_tag = f"[{conf_color}][{rule.confidence}][/{conf_color}]"
|
|
45
|
+
|
|
46
|
+
console.print(f" - [dim]\\[{rule.id}][/dim] {rule.rule} {conf_tag} {source_tag}")
|
|
47
|
+
console.print()
|