@cliperhq/cliper 1.0.0
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.
- package/README.md +266 -0
- package/dist/commands/analyze.d.ts +6 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +216 -0
- package/dist/commands/export.d.ts +6 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +64 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +173 -0
- package/dist/commands/scope.d.ts +2 -0
- package/dist/commands/scope.d.ts.map +1 -0
- package/dist/commands/scope.js +124 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +100 -0
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +83 -0
- package/dist/context/builder.d.ts +19 -0
- package/dist/context/builder.d.ts.map +1 -0
- package/dist/context/builder.js +143 -0
- package/dist/gaps/detector.d.ts +10 -0
- package/dist/gaps/detector.d.ts.map +1 -0
- package/dist/gaps/detector.js +139 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/resolver/urlFetcher.d.ts +9 -0
- package/dist/resolver/urlFetcher.d.ts.map +1 -0
- package/dist/resolver/urlFetcher.js +134 -0
- package/dist/scanner/dependencies.d.ts +14 -0
- package/dist/scanner/dependencies.d.ts.map +1 -0
- package/dist/scanner/dependencies.js +199 -0
- package/dist/scanner/fileContent.d.ts +8 -0
- package/dist/scanner/fileContent.d.ts.map +1 -0
- package/dist/scanner/fileContent.js +133 -0
- package/dist/scanner/fileTree.d.ts +2 -0
- package/dist/scanner/fileTree.d.ts.map +1 -0
- package/dist/scanner/fileTree.js +152 -0
- package/dist/scanner/gitContext.d.ts +19 -0
- package/dist/scanner/gitContext.d.ts.map +1 -0
- package/dist/scanner/gitContext.js +60 -0
- package/dist/scope/autoScope.d.ts +2 -0
- package/dist/scope/autoScope.d.ts.map +1 -0
- package/dist/scope/autoScope.js +226 -0
- package/dist/scope/config.d.ts +10 -0
- package/dist/scope/config.d.ts.map +1 -0
- package/dist/scope/config.js +71 -0
- package/index.js +2 -0
- package/package.json +37 -0
- package/src/commands/analyze.ts +201 -0
- package/src/commands/export.ts +33 -0
- package/src/commands/init.ts +174 -0
- package/src/commands/scope.ts +77 -0
- package/src/commands/status.ts +67 -0
- package/src/commands/sync.ts +51 -0
- package/src/context/builder.ts +178 -0
- package/src/gaps/detector.ts +131 -0
- package/src/index.ts +54 -0
- package/src/resolver/urlFetcher.ts +119 -0
- package/src/scanner/dependencies.ts +196 -0
- package/src/scanner/fileContent.ts +121 -0
- package/src/scanner/fileTree.ts +149 -0
- package/src/scanner/gitContext.ts +74 -0
- package/src/scope/autoScope.ts +182 -0
- package/src/scope/config.ts +39 -0
- package/tsconfig.json +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# Cliper
|
|
2
|
+
|
|
3
|
+
> Generate rich, AI-ready context documents from your codebase — always fresh, always scoped, always honest about what it doesn't know.
|
|
4
|
+
|
|
5
|
+
**npm:** `@cliperhq/cliper` | **CLI:** `cliper` | **Version:** 1.0.0
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is Cliper?
|
|
10
|
+
|
|
11
|
+
Every time you start an AI coding session, you waste time re-explaining your project — pasting file contents, describing structure, warning the AI about legacy decisions, and hoping it doesn't miss something critical.
|
|
12
|
+
|
|
13
|
+
Cliper eliminates that tax entirely.
|
|
14
|
+
|
|
15
|
+
One command. Your AI has full, accurate, scoped context. You go straight to building.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
### Option A — npx (recommended, no install needed)
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx @cliperhq/cliper init
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
npx always pulls the latest version and leaves zero footprint in your project.
|
|
28
|
+
|
|
29
|
+
### Option B — Global install
|
|
30
|
+
|
|
31
|
+
Install once, use in any project:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g @cliperhq/cliper
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Option C — Shell alias (best of both worlds)
|
|
38
|
+
|
|
39
|
+
Add to your `~/.zshrc` or `~/.bashrc`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
alias cliper="npx @cliperhq/cliper"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Then reload:
|
|
46
|
+
```bash
|
|
47
|
+
source ~/.zshrc
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> **Never run `npm install @cliperhq/cliper` inside your project directory.** This installs Cliper as a project dependency and pollutes your `node_modules`. Always use npx or a global install.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Go into any project
|
|
58
|
+
cd your-project
|
|
59
|
+
|
|
60
|
+
# Generate your first context document
|
|
61
|
+
cliper init
|
|
62
|
+
|
|
63
|
+
# Copy to clipboard and paste into Claude or ChatGPT
|
|
64
|
+
cliper export | pbcopy # macOS
|
|
65
|
+
cliper export | xclip # Linux
|
|
66
|
+
|
|
67
|
+
# Generate an AI-optimized prompt (requires API key)
|
|
68
|
+
export ANTHROPIC_API_KEY=your_key
|
|
69
|
+
cliper analyze --model claude
|
|
70
|
+
|
|
71
|
+
# Or for ChatGPT
|
|
72
|
+
export OPENAI_API_KEY=your_key
|
|
73
|
+
cliper analyze --model chatgpt
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## What Gets Generated
|
|
79
|
+
|
|
80
|
+
Cliper scans your project and produces `.cliper/context.md` containing:
|
|
81
|
+
|
|
82
|
+
### Annotated Folder Structure
|
|
83
|
+
Not a raw `tree` dump — an annotated, scoped view showing what's active, what's watched, and when files were last modified.
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
your-project/
|
|
87
|
+
├── src/
|
|
88
|
+
│ ├── payments/ ← ACTIVE SCOPE
|
|
89
|
+
│ │ ├── refund.ts ← modified 2h ago
|
|
90
|
+
│ │ └── processor.ts ← modified 3d ago
|
|
91
|
+
│ └── auth/ ← out of scope (3 files, last touched 3 weeks ago)
|
|
92
|
+
├── config/ ← WATCHED
|
|
93
|
+
└── [14 other directories — out of scope]
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Git Context
|
|
97
|
+
Branch, recent commits, uncommitted changes — so the AI knows exactly where you are in the development timeline.
|
|
98
|
+
|
|
99
|
+
### Dependency Map
|
|
100
|
+
What imports what across your scoped files, entry points, and all external packages used. Supports TypeScript, JavaScript, Rust, and Python.
|
|
101
|
+
|
|
102
|
+
### Key File Contents
|
|
103
|
+
Full source of scoped files, prioritized by language and recency, with a configurable size limit.
|
|
104
|
+
|
|
105
|
+
### Blocked Reference Resolution
|
|
106
|
+
READMEs often link to external docs the AI can't access (robots.txt blocks, private pages). Cliper fetches them locally and inlines the content directly into the context doc. No broken links, no missing context.
|
|
107
|
+
|
|
108
|
+
### Gap Detection
|
|
109
|
+
What you forgot to tell the AI — undocumented functions, missing `.env` vars, TODO/FIXME comments, implicit dependencies. Surfaced before your session starts.
|
|
110
|
+
|
|
111
|
+
### AI-Optimized Prompts
|
|
112
|
+
`cliper analyze` takes the raw context doc and uses AI to reformat it into a model-specific prompt — tuned for how Claude reasons vs how ChatGPT processes structured input.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## CLI Reference
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Initialize — scan project and generate context document
|
|
120
|
+
cliper init
|
|
121
|
+
cliper init --max-file-size 200 # increase file size limit (default: 50KB)
|
|
122
|
+
|
|
123
|
+
# Sync — refresh stale sections after changes
|
|
124
|
+
cliper sync
|
|
125
|
+
cliper sync --watch # auto-refresh on every git commit
|
|
126
|
+
|
|
127
|
+
# Scope — control what gets included
|
|
128
|
+
cliper scope add src/payments/ # add directory to active scope
|
|
129
|
+
cliper scope watch config/db.ts # add file to persistent watch list
|
|
130
|
+
cliper scope remove src/payments/ # remove from scope
|
|
131
|
+
cliper scope list # show current scope
|
|
132
|
+
|
|
133
|
+
# Status — check freshness and current state
|
|
134
|
+
cliper status
|
|
135
|
+
|
|
136
|
+
# Export — print context doc to stdout
|
|
137
|
+
cliper export # markdown format
|
|
138
|
+
cliper export --format txt # plain text
|
|
139
|
+
|
|
140
|
+
# Analyze — generate AI-optimized prompt from context doc
|
|
141
|
+
cliper analyze --model claude # optimized for Claude
|
|
142
|
+
cliper analyze --model chatgpt # optimized for ChatGPT
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Language Support
|
|
148
|
+
|
|
149
|
+
Cliper auto-detects your project type and scopes intelligently:
|
|
150
|
+
|
|
151
|
+
| Language | Auto-detected from | Source dirs included |
|
|
152
|
+
|---|---|---|
|
|
153
|
+
| **Rust** | `Cargo.toml` | All workspace member `src/` dirs |
|
|
154
|
+
| **TypeScript / JavaScript** | `package.json` | `src/`, `packages/`, `apps/`, `libs/` |
|
|
155
|
+
| **Python** | `pyproject.toml` / `requirements.txt` | `src/`, dirs with `__init__.py` |
|
|
156
|
+
| **Go** | `go.mod` | `internal/`, `pkg/`, `cmd/` |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## How to Use with AI Models
|
|
161
|
+
|
|
162
|
+
After running `cliper init`:
|
|
163
|
+
|
|
164
|
+
**Option 1 — Copy and paste**
|
|
165
|
+
```bash
|
|
166
|
+
cliper export | pbcopy # macOS — then paste as first message
|
|
167
|
+
cliper export | xclip # Linux
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Option 2 — Use the optimized prompt**
|
|
171
|
+
```bash
|
|
172
|
+
cliper analyze --model claude
|
|
173
|
+
cat .cliper/prompt-claude.md | pbcopy
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Option 3 — Reference the file directly**
|
|
177
|
+
Some tools (Cursor, Claude Projects) can reference files directly. Point them at `.cliper/context.md`.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Project Architecture
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
src/
|
|
185
|
+
├── commands/
|
|
186
|
+
│ ├── init.ts # cliper init — full project scan
|
|
187
|
+
│ ├── sync.ts # cliper sync — incremental refresh
|
|
188
|
+
│ ├── scope.ts # cliper scope — manage active scope
|
|
189
|
+
│ ├── status.ts # cliper status — freshness report
|
|
190
|
+
│ ├── export.ts # cliper export — output context doc
|
|
191
|
+
│ └── analyze.ts # cliper analyze — AI-optimized prompt generation
|
|
192
|
+
├── scanner/
|
|
193
|
+
│ ├── fileTree.ts # annotated folder structure
|
|
194
|
+
│ ├── fileContent.ts # scoped file extraction with token cap
|
|
195
|
+
│ ├── gitContext.ts # branch, commits, uncommitted changes
|
|
196
|
+
│ └── dependencies.ts # import/dependency map (TS, JS, Rust, Python)
|
|
197
|
+
├── resolver/
|
|
198
|
+
│ └── urlFetcher.ts # fetch and inline blocked external references
|
|
199
|
+
├── gaps/
|
|
200
|
+
│ └── detector.ts # undocumented patterns, missing env vars, TODOs
|
|
201
|
+
├── context/
|
|
202
|
+
│ └── builder.ts # assembles the final context.md
|
|
203
|
+
└── scope/
|
|
204
|
+
├── config.ts # persists scope config in .cliper/
|
|
205
|
+
└── autoScope.ts # language-aware auto-scoping from git activity
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## What Cliper Creates in Your Project
|
|
211
|
+
|
|
212
|
+
Running `cliper init` adds the following to your project:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
.cliper/
|
|
216
|
+
├── context.md # the context document — commit this
|
|
217
|
+
├── scope.json # your scope config — commit this
|
|
218
|
+
├── prompt-claude.md # generated prompt (cliper analyze) — gitignored
|
|
219
|
+
├── prompt-gpt.md # generated prompt (cliper analyze) — gitignored
|
|
220
|
+
└── cache/ # locally fetched URL content — gitignored
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Cliper also automatically adds `node_modules/`, `package-lock.json`, and `.cliper/cache/` to your `.gitignore` — and removes them from git tracking if they were accidentally staged.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Roadmap
|
|
228
|
+
|
|
229
|
+
**Shipped**
|
|
230
|
+
- ✅ Language-aware auto-scoping (Rust, Node, Python, Go)
|
|
231
|
+
- ✅ Annotated folder structure with freshness timestamps
|
|
232
|
+
- ✅ Git-aware context (branch, commits, uncommitted changes)
|
|
233
|
+
- ✅ Dependency map (TS/JS/Rust/Python)
|
|
234
|
+
- ✅ Blocked URL resolution and inlining
|
|
235
|
+
- ✅ Gap detection (TODOs, missing env vars, undocumented functions)
|
|
236
|
+
- ✅ AI-optimized prompt generation (Claude + ChatGPT)
|
|
237
|
+
- ✅ `--max-file-size` flag for large files
|
|
238
|
+
- ✅ Auto-managed `.gitignore`
|
|
239
|
+
|
|
240
|
+
**Coming Soon**
|
|
241
|
+
- ⬜ `cliper push` — sync context to the Cliper web dashboard
|
|
242
|
+
- ⬜ Web dashboard — visual representation of your codebase context
|
|
243
|
+
- ⬜ Project history — track how your codebase evolves over time
|
|
244
|
+
- ⬜ Team sharing — shared context annotations committed to git
|
|
245
|
+
- ⬜ VS Code extension — one-click context copy from the editor
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Contributing
|
|
250
|
+
|
|
251
|
+
Cliper is early and actively developed. If you're a developer who feels the pain of re-explaining your project to AI every session, contributions are very welcome.
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
git clone https://github.com/bristinwild/cliper
|
|
255
|
+
cd cliper
|
|
256
|
+
npm install
|
|
257
|
+
npm run dev
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Open an issue before submitting large PRs so we can align on direction.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
ISC © bristinwild
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAQA,UAAU,cAAc;IACpB,KAAK,EAAE,MAAM,CAAC;CACjB;AA2HD,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE3E"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.analyzeCommand = analyzeCommand;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const ora_1 = __importDefault(require("ora"));
|
|
44
|
+
const config_1 = require("../scope/config");
|
|
45
|
+
const CLAUDE_SYSTEM = `You are an expert software architect analyzing a codebase context document.
|
|
46
|
+
Your job is to transform raw codebase data into a highly optimized prompt for a Claude AI coding session.
|
|
47
|
+
|
|
48
|
+
Claude thinks best when given:
|
|
49
|
+
- Clear project narrative (what it is, why it exists)
|
|
50
|
+
- Explicit constraints and existing decisions to respect
|
|
51
|
+
- The specific area of focus with surrounding context
|
|
52
|
+
- What NOT to change or break
|
|
53
|
+
- Open questions or uncertainties the developer has
|
|
54
|
+
|
|
55
|
+
Your output must be a ready-to-paste prompt. No preamble. No explanation. Just the prompt itself.`;
|
|
56
|
+
const CHATGPT_SYSTEM = `You are an expert software architect analyzing a codebase context document.
|
|
57
|
+
Your job is to transform raw codebase data into a highly optimized prompt for a ChatGPT coding session.
|
|
58
|
+
|
|
59
|
+
ChatGPT works best when given:
|
|
60
|
+
- Numbered, structured context sections
|
|
61
|
+
- Explicit file paths and code blocks
|
|
62
|
+
- Clear task definition separated from context
|
|
63
|
+
- Constraints listed as bullet points
|
|
64
|
+
- A direct question or task at the end
|
|
65
|
+
|
|
66
|
+
Your output must be a ready-to-paste prompt. No preamble. No explanation. Just the prompt itself.`;
|
|
67
|
+
const CLAUDE_USER = (contextDoc) => `Here is the raw codebase context document generated by Cliper:
|
|
68
|
+
|
|
69
|
+
<context>
|
|
70
|
+
${contextDoc}
|
|
71
|
+
</context>
|
|
72
|
+
|
|
73
|
+
Transform this into an optimized Claude prompt following these rules:
|
|
74
|
+
|
|
75
|
+
CRITICAL ACCURACY RULES:
|
|
76
|
+
- Never expand acronyms unless the context doc explicitly defines them. If you see "SPEL" and the doc doesn't say what it stands for, write "SPEL" — do not invent an expansion.
|
|
77
|
+
- Never infer what a framework "is based on" from inspiration references. "Inspired by Anchor for Solana" does NOT mean the project runs on Solana.
|
|
78
|
+
- Include ALL macros and annotations found in the source code, not just the most common ones. If you see #[require_admin], include it.
|
|
79
|
+
- If a file was truncated, note that there may be additional macros or patterns not visible.
|
|
80
|
+
|
|
81
|
+
FORMAT RULES:
|
|
82
|
+
1. Opens with a concise project narrative (2-3 sentences max) — only state facts explicitly in the context doc
|
|
83
|
+
2. Summarizes the current branch focus and recent work
|
|
84
|
+
3. Lists key architectural decisions already made that must be respected
|
|
85
|
+
4. Highlights the most important files and their roles
|
|
86
|
+
5. Lists ALL macros/annotations found across all files
|
|
87
|
+
6. Surfaces any detected gaps the developer should be aware of
|
|
88
|
+
7. Ends with: "## What I need help with today:"
|
|
89
|
+
|
|
90
|
+
Make it feel like a natural briefing. Never invent details not present in the context doc.`;
|
|
91
|
+
const CHATGPT_USER = (contextDoc) => `Here is the raw codebase context document generated by Cliper:
|
|
92
|
+
|
|
93
|
+
${contextDoc}
|
|
94
|
+
|
|
95
|
+
Transform this into an optimized chatgpt prompt following these rules:
|
|
96
|
+
|
|
97
|
+
CRITICAL ACCURACY RULES:
|
|
98
|
+
- Never expand acronyms unless the context doc explicitly defines them. If you see "SPEL" and the doc doesn't say what it stands for, write "SPEL" — do not invent an expansion.
|
|
99
|
+
- Never infer what a framework "is based on" from inspiration references. "Inspired by Anchor for Solana" does NOT mean the project runs on Solana.
|
|
100
|
+
- Include ALL macros and annotations found in the source code, not just the most common ones. If you see #[require_admin], include it.
|
|
101
|
+
- If a file was truncated, note that there may be additional macros or patterns not visible.
|
|
102
|
+
|
|
103
|
+
FORMAT RULES:
|
|
104
|
+
1. Starts with "## Project Context" as a header
|
|
105
|
+
2. Uses numbered sections for: Project Overview, Tech Stack, Current Branch & Focus, Key Files, Constraints & Decisions, Known Gaps
|
|
106
|
+
3. Uses bullet points and code blocks for file paths and snippets
|
|
107
|
+
4. Keeps each section concise — no more than 5 bullet points per section
|
|
108
|
+
5. Ends with "## Task:" followed by a blank line for the developer to fill in
|
|
109
|
+
|
|
110
|
+
Format it for maximum clarity and scannability. ChatGPT responds best to structured, explicitly labeled context.`;
|
|
111
|
+
async function callAnthropicAPI(contextDoc) {
|
|
112
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: {
|
|
115
|
+
"Content-Type": "application/json",
|
|
116
|
+
"x-api-key": process.env.ANTHROPIC_API_KEY ?? "",
|
|
117
|
+
"anthropic-version": "2023-06-01",
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
model: "claude-sonnet-4-20250514",
|
|
121
|
+
max_tokens: 2000,
|
|
122
|
+
system: CLAUDE_SYSTEM,
|
|
123
|
+
messages: [{ role: "user", content: CLAUDE_USER(contextDoc) }],
|
|
124
|
+
}),
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
const err = await response.text();
|
|
128
|
+
throw new Error(`Anthropic API error: ${response.status} — ${err}`);
|
|
129
|
+
}
|
|
130
|
+
const data = await response.json();
|
|
131
|
+
return data.content?.[0]?.text ?? "";
|
|
132
|
+
}
|
|
133
|
+
async function callOpenAIAPI(contextDoc) {
|
|
134
|
+
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
135
|
+
method: "POST",
|
|
136
|
+
headers: {
|
|
137
|
+
"Content-Type": "application/json",
|
|
138
|
+
"Authorization": `Bearer ${process.env.OPENAI_API_KEY ?? ""}`,
|
|
139
|
+
},
|
|
140
|
+
body: JSON.stringify({
|
|
141
|
+
model: "gpt-4o",
|
|
142
|
+
max_tokens: 2000,
|
|
143
|
+
messages: [
|
|
144
|
+
{ role: "system", content: CHATGPT_SYSTEM },
|
|
145
|
+
{ role: "user", content: CHATGPT_USER(contextDoc) },
|
|
146
|
+
],
|
|
147
|
+
}),
|
|
148
|
+
});
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
const err = await response.text();
|
|
151
|
+
throw new Error(`OpenAI API error: ${response.status} — ${err}`);
|
|
152
|
+
}
|
|
153
|
+
const data = await response.json();
|
|
154
|
+
return data.choices?.[0]?.message?.content ?? "";
|
|
155
|
+
}
|
|
156
|
+
async function analyzeCommand(options) {
|
|
157
|
+
const projectRoot = process.cwd();
|
|
158
|
+
const cliperDir = (0, config_1.getCliperDir)(projectRoot);
|
|
159
|
+
const contextPath = path.join(cliperDir, "context.md");
|
|
160
|
+
// Check context doc exists
|
|
161
|
+
if (!fs.existsSync(contextPath)) {
|
|
162
|
+
console.error(chalk_1.default.red("\n No context doc found. Run cliper init first.\n"));
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
const contextDoc = fs.readFileSync(contextPath, "utf-8");
|
|
166
|
+
const model = options.model.toLowerCase();
|
|
167
|
+
// Validate model choice
|
|
168
|
+
if (!["claude", "chatgpt"].includes(model)) {
|
|
169
|
+
console.error(chalk_1.default.red(`\n Unknown model: ${options.model}`));
|
|
170
|
+
console.error(chalk_1.default.gray(" Usage: cliper analyze --model claude"));
|
|
171
|
+
console.error(chalk_1.default.gray(" cliper analyze --model chatgpt\n"));
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
// Check API key
|
|
175
|
+
if (model === "claude" && !process.env.ANTHROPIC_API_KEY) {
|
|
176
|
+
console.error(chalk_1.default.red("\n ANTHROPIC_API_KEY not set."));
|
|
177
|
+
console.error(chalk_1.default.gray(" Export it first: export ANTHROPIC_API_KEY=your_key_here\n"));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
if (model === "chatgpt" && !process.env.OPENAI_API_KEY) {
|
|
181
|
+
console.error(chalk_1.default.red("\n OPENAI_API_KEY not set."));
|
|
182
|
+
console.error(chalk_1.default.gray(" Export it first: export OPENAI_API_KEY=your_key_here\n"));
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
console.log(chalk_1.default.bold.cyan(`\n cliper analyze — ${model}\n`));
|
|
186
|
+
const spinner = (0, ora_1.default)(`Analyzing context doc with ${model === "claude" ? "Claude" : "ChatGPT"}...`).start();
|
|
187
|
+
try {
|
|
188
|
+
let prompt;
|
|
189
|
+
if (model === "claude") {
|
|
190
|
+
prompt = await callAnthropicAPI(contextDoc);
|
|
191
|
+
const outputPath = path.join(cliperDir, "prompt-claude.md");
|
|
192
|
+
fs.writeFileSync(outputPath, prompt, "utf-8");
|
|
193
|
+
spinner.succeed(chalk_1.default.green("Claude prompt generated"));
|
|
194
|
+
console.log(chalk_1.default.gray(`\n Saved: ${outputPath}\n`));
|
|
195
|
+
console.log(chalk_1.default.cyan(" Copy to clipboard:"));
|
|
196
|
+
console.log(chalk_1.default.white(" cliper analyze --model claude | pbcopy\n"));
|
|
197
|
+
console.log(chalk_1.default.cyan(" Or open directly:"));
|
|
198
|
+
console.log(chalk_1.default.white(` cat ${outputPath} | pbcopy\n`));
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
prompt = await callOpenAIAPI(contextDoc);
|
|
202
|
+
const outputPath = path.join(cliperDir, "prompt-gpt.md");
|
|
203
|
+
fs.writeFileSync(outputPath, prompt, "utf-8");
|
|
204
|
+
spinner.succeed(chalk_1.default.green("ChatGPT prompt generated"));
|
|
205
|
+
console.log(chalk_1.default.gray(`\n Saved: ${outputPath}\n`));
|
|
206
|
+
console.log(chalk_1.default.cyan(" Copy to clipboard:"));
|
|
207
|
+
console.log(chalk_1.default.white(` cat ${outputPath} | pbcopy\n`));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
spinner.fail(chalk_1.default.red("Analysis failed"));
|
|
212
|
+
console.error(chalk_1.default.red(`\n ${err.message}\n`));
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAKA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBzE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.exportCommand = exportCommand;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
43
|
+
const config_1 = require("../scope/config");
|
|
44
|
+
async function exportCommand(options) {
|
|
45
|
+
const projectRoot = process.cwd();
|
|
46
|
+
const contextPath = path.join((0, config_1.getCliperDir)(projectRoot), "context.md");
|
|
47
|
+
if (!fs.existsSync(contextPath)) {
|
|
48
|
+
console.error(chalk_1.default.red("\n No context doc found. Run cliper init first.\n"));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
let content = fs.readFileSync(contextPath, "utf-8");
|
|
52
|
+
if (options.format === "txt") {
|
|
53
|
+
// Strip markdown formatting for plain text output
|
|
54
|
+
content = content
|
|
55
|
+
.replace(/```[\w]*\n/g, "")
|
|
56
|
+
.replace(/```/g, "")
|
|
57
|
+
.replace(/#{1,6}\s/g, "")
|
|
58
|
+
.replace(/\*\*/g, "")
|
|
59
|
+
.replace(/`/g, "");
|
|
60
|
+
}
|
|
61
|
+
// Write to stdout — designed to be piped
|
|
62
|
+
process.stdout.write(content);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAiBA,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAsJrE"}
|