@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.
Files changed (68) hide show
  1. package/README.md +266 -0
  2. package/dist/commands/analyze.d.ts +6 -0
  3. package/dist/commands/analyze.d.ts.map +1 -0
  4. package/dist/commands/analyze.js +216 -0
  5. package/dist/commands/export.d.ts +6 -0
  6. package/dist/commands/export.d.ts.map +1 -0
  7. package/dist/commands/export.js +64 -0
  8. package/dist/commands/init.d.ts +7 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +173 -0
  11. package/dist/commands/scope.d.ts +2 -0
  12. package/dist/commands/scope.d.ts.map +1 -0
  13. package/dist/commands/scope.js +124 -0
  14. package/dist/commands/status.d.ts +2 -0
  15. package/dist/commands/status.d.ts.map +1 -0
  16. package/dist/commands/status.js +100 -0
  17. package/dist/commands/sync.d.ts +6 -0
  18. package/dist/commands/sync.d.ts.map +1 -0
  19. package/dist/commands/sync.js +83 -0
  20. package/dist/context/builder.d.ts +19 -0
  21. package/dist/context/builder.d.ts.map +1 -0
  22. package/dist/context/builder.js +143 -0
  23. package/dist/gaps/detector.d.ts +10 -0
  24. package/dist/gaps/detector.d.ts.map +1 -0
  25. package/dist/gaps/detector.js +139 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +48 -0
  29. package/dist/resolver/urlFetcher.d.ts +9 -0
  30. package/dist/resolver/urlFetcher.d.ts.map +1 -0
  31. package/dist/resolver/urlFetcher.js +134 -0
  32. package/dist/scanner/dependencies.d.ts +14 -0
  33. package/dist/scanner/dependencies.d.ts.map +1 -0
  34. package/dist/scanner/dependencies.js +199 -0
  35. package/dist/scanner/fileContent.d.ts +8 -0
  36. package/dist/scanner/fileContent.d.ts.map +1 -0
  37. package/dist/scanner/fileContent.js +133 -0
  38. package/dist/scanner/fileTree.d.ts +2 -0
  39. package/dist/scanner/fileTree.d.ts.map +1 -0
  40. package/dist/scanner/fileTree.js +152 -0
  41. package/dist/scanner/gitContext.d.ts +19 -0
  42. package/dist/scanner/gitContext.d.ts.map +1 -0
  43. package/dist/scanner/gitContext.js +60 -0
  44. package/dist/scope/autoScope.d.ts +2 -0
  45. package/dist/scope/autoScope.d.ts.map +1 -0
  46. package/dist/scope/autoScope.js +226 -0
  47. package/dist/scope/config.d.ts +10 -0
  48. package/dist/scope/config.d.ts.map +1 -0
  49. package/dist/scope/config.js +71 -0
  50. package/index.js +2 -0
  51. package/package.json +37 -0
  52. package/src/commands/analyze.ts +201 -0
  53. package/src/commands/export.ts +33 -0
  54. package/src/commands/init.ts +174 -0
  55. package/src/commands/scope.ts +77 -0
  56. package/src/commands/status.ts +67 -0
  57. package/src/commands/sync.ts +51 -0
  58. package/src/context/builder.ts +178 -0
  59. package/src/gaps/detector.ts +131 -0
  60. package/src/index.ts +54 -0
  61. package/src/resolver/urlFetcher.ts +119 -0
  62. package/src/scanner/dependencies.ts +196 -0
  63. package/src/scanner/fileContent.ts +121 -0
  64. package/src/scanner/fileTree.ts +149 -0
  65. package/src/scanner/gitContext.ts +74 -0
  66. package/src/scope/autoScope.ts +182 -0
  67. package/src/scope/config.ts +39 -0
  68. 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,6 @@
1
+ interface AnalyzeOptions {
2
+ model: string;
3
+ }
4
+ export declare function analyzeCommand(options: AnalyzeOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=analyze.d.ts.map
@@ -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,6 @@
1
+ interface ExportOptions {
2
+ format: string;
3
+ }
4
+ export declare function exportCommand(options: ExportOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=export.d.ts.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,7 @@
1
+ interface InitOptions {
2
+ path: string;
3
+ maxFileSize?: number;
4
+ }
5
+ export declare function initCommand(options: InitOptions): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=init.d.ts.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"}