agentic-compaction 0.0.1

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.
@@ -0,0 +1,52 @@
1
+ # Orchestration Protocol
2
+
3
+ **MANDATORY: Process BEFORE any tool usage.**
4
+
5
+ ## 1. CLASSIFY TASK
6
+
7
+ | Signal Words | Workflow |
8
+ |--------------|----------|
9
+ | build, create, add, implement, new | `feature.md` |
10
+ | fix, broken, error, crash, bug | `bugfix.md` |
11
+ | clean up, improve, restructure, rename | `refactor.md` |
12
+ | slow, optimize, performance, speed | `performance.md` |
13
+ | review, check, PR, merge | `review.md` |
14
+ | PR description, pull request title | `pr.md` |
15
+ | document, README, explain | `docs.md` |
16
+ | complex, multi-step, plan | `todo.md` |
17
+
18
+ **Complexity:** 1-2 ops = simple | 3+ ops = complex (add `todo.md`)
19
+ **Technology:** React (`.jsx`/`.tsx`, hooks) → `workflows/react/` | Other → `workflows/`
20
+
21
+ ### Selection
22
+ - **Clear match:** Proceed to binding
23
+ - **Ambiguous:** Use `AskUserQuestion` (header: "Workflow", options: relevant workflows)
24
+ - **No match:** Ask user to clarify
25
+
26
+ ## 2. BINDING (required before ANY tool use)
27
+
28
+ ```
29
+ ORCHESTRATION_BINDING:
30
+ - Task: [description]
31
+ - Workflow: [path]
32
+ - Complexity: [simple/complex]
33
+ ```
34
+
35
+ ## 3. EXEMPT TASKS
36
+
37
+ Requires ALL: single file, 1-2 ops, zero architecture impact, obvious correctness.
38
+
39
+ ```
40
+ ORCHESTRATION_BINDING:
41
+ - Task: [description]
42
+ - Classification: EXEMPT
43
+ ```
44
+
45
+ ## 4. COMPLETION
46
+
47
+ ```
48
+ ORCHESTRATION_COMPLETE:
49
+ - Task: [description]
50
+ - Workflow: [used]
51
+ - Files: [modified]
52
+ ```
@@ -0,0 +1,32 @@
1
+ # React Bugfix Workflow
2
+
3
+ ## 1. Reproduce
4
+
5
+ - Confirm bug exists | find minimal repro
6
+ - Check Strict Mode behavior
7
+ - Answer: Expected vs actual? React 18 concurrent issue?
8
+
9
+ ## 2. Locate Root Cause
10
+
11
+ | Common React 18 Issues |
12
+ |------------------------|
13
+ | Effects missing cleanup |
14
+ | Stale closures in effects |
15
+ | Concurrent rendering race conditions |
16
+ | Automatic batching changes |
17
+
18
+ ## 3. Fix
19
+
20
+ - Keep changes within affected feature folder
21
+ - Add cleanup: `return () => controller.abort()`
22
+ - Fix stale closures with proper deps
23
+
24
+ ## 4. Verify
25
+
26
+ - Confirm fix | test with Strict Mode
27
+ - Add regression test
28
+
29
+ ## Constraints
30
+
31
+ - Smallest fix only | NO refactoring
32
+ - NO barrel exports | note other issues separately
@@ -0,0 +1,59 @@
1
+ # React Documentation Workflow
2
+
3
+ > Document architecture correctly. See orchestration.md for patterns.
4
+
5
+ ## Before Writing
6
+
7
+ MUST answer:
8
+ - Who is the audience?
9
+ - What should they be able to do after reading?
10
+ - What existing docs need to stay in sync?
11
+
12
+ ## Process
13
+
14
+ ### 1. Understand the Subject
15
+ - Read the code being documented
16
+ - Try it yourself if possible
17
+ - Identify non-obvious behavior or gotchas
18
+
19
+ ### 2. Check Existing Docs
20
+ - Find related documentation
21
+ - Identify what's missing or outdated
22
+ - Note the existing style and format
23
+
24
+ ### 3. Write
25
+
26
+ Adapt this template as needed:
27
+
28
+ ```markdown
29
+ # {Name}
30
+
31
+ Brief description.
32
+
33
+ ## Location
34
+ `features/{feature}/components/{Name}/{Name}.tsx`
35
+
36
+ ## Import
37
+ import { Name } from '@/features/{feature}/components/{Name}/{Name}'
38
+
39
+ ## Usage
40
+ <Name prop="value" />
41
+
42
+ ## Props/Parameters (if applicable)
43
+ | Name | Type | Required | Description |
44
+ |------|------|----------|-------------|
45
+
46
+ ## Related
47
+ - Links to related components/hooks
48
+ ```
49
+
50
+ ### 4. Validate
51
+ - Code examples actually work
52
+ - Import paths are direct (not barrel)
53
+ - Links are valid
54
+
55
+ ## Constraints
56
+
57
+ - MUST explain why, not just what
58
+ - MUST show direct import paths in examples
59
+ - MUST update related docs to stay consistent
@@ -0,0 +1,37 @@
1
+ # React Feature Workflow
2
+
3
+ ## 1. Architecture
4
+
5
+ **IF not specified:** Use `AskUserQuestion` (header: "Architecture")
6
+
7
+ | Architecture | Structure |
8
+ |--------------|-----------|
9
+ | Feature-driven | `features/{name}/components\|hooks\|utils/` |
10
+ | Flat feature-driven | `features/{name}/` flat files |
11
+ | Atomic design | `atoms\|molecules\|organisms\|templates/` |
12
+
13
+ **IF project has patterns:** Follow existing, skip question.
14
+
15
+ ## 2. Context
16
+
17
+ - Read related code, identify target folder
18
+ - Check similar implementations, reusable hooks/utils
19
+ - Answer: What problem? Minimal version? Which folder?
20
+
21
+ ## 3. Implement
22
+
23
+ **Components:** Function only | `useState`/`useReducer` for local state
24
+ **Hooks:** Extract logic | `hooks/{feature}/{name}.ts` | descriptive names
25
+ **State:** Lift only as needed | composition over prop drilling
26
+
27
+ ## 4. Validate
28
+
29
+ - Run tests for regressions
30
+ - Add tests for new code
31
+ - Test loading/error states
32
+ - Remove debug code
33
+
34
+ ## Constraints
35
+
36
+ - NO `index.ts`/`index.tsx` | import from file directly
37
+ - Match existing style | no extra features
@@ -0,0 +1,59 @@
1
+ # React Performance Workflow
2
+
3
+ > Architecture rules: See orchestration.md. Violations block merge.
4
+
5
+ ## Before Coding
6
+
7
+ MUST answer:
8
+ - What is the specific performance problem?
9
+ - How will I measure improvement?
10
+ - Is this a real bottleneck or premature optimization?
11
+
12
+ ## Process
13
+
14
+ ### 1. Measure First
15
+ - Profile with React DevTools Profiler
16
+ - Identify components that re-render unnecessarily
17
+ - Check bundle size with build analyzer
18
+ - Measure actual user-facing metrics (not just hunches)
19
+
20
+ ### 2. Identify Root Cause
21
+
22
+ **Common issues:**
23
+ - Components re-rendering when props haven't changed
24
+ - Expensive calculations on every render
25
+ - Large bundle from unused dependencies
26
+ - Missing code splitting on routes
27
+
28
+ ### 3. Optimize
29
+
30
+ **Prevent unnecessary re-renders:**
31
+ ```tsx
32
+ // Memoize components that receive stable props
33
+ const MemoizedList = memo(List)
34
+
35
+ // Memoize callbacks passed to children
36
+ const handleClick = useCallback(() => {
37
+ doSomething(id)
38
+ }, [id])
39
+
40
+ // Memoize expensive derived values
41
+ const sorted = useMemo(() => sortItems(items), [items])
42
+ ```
43
+
44
+ **Reduce bundle size:**
45
+ - Lazy load routes with `React.lazy` + `Suspense`
46
+ - Replace heavy libraries with lighter alternatives
47
+ - Use tree-shakeable imports
48
+
49
+ ### 4. Verify
50
+ - Re-profile to confirm improvement
51
+ - Ensure no regressions in functionality
52
+ - Document the optimization and why it helped
53
+
54
+ ## Constraints
55
+
56
+ - NEVER optimize without measuring first
57
+ - NEVER add memo/useMemo/useCallback everywhere "just in case"
58
+ - MUST prove the optimization helps with real measurements
59
+ - Keep optimizations minimal and targeted
@@ -0,0 +1,19 @@
1
+ # Pull Request Workflow
2
+
3
+ ## Process
4
+
5
+ 1. Read diff (current branch vs main/master)
6
+ 2. Analyze changes
7
+ 3. Output title + description
8
+
9
+ ## Output
10
+
11
+ ```
12
+ PR Title: <imperative mood>
13
+ Description: <2-3 sentences: what + why>
14
+ ```
15
+
16
+ ## Constraints
17
+
18
+ - Imperative mood ("Add" not "Added") | mention breaking changes
19
+ - Output only | NO branch/push/remote PR creation
@@ -0,0 +1,32 @@
1
+ # React Refactor Workflow
2
+
3
+ ## 1. Safety Net
4
+
5
+ - Run tests | add if coverage insufficient
6
+ - Answer: What improvement? How verify unchanged behavior?
7
+
8
+ ## 2. Plan
9
+
10
+ - Map imports/dependencies | identify all callers
11
+ - Break into small, safe steps
12
+
13
+ ## 3. Execute
14
+
15
+ One change type at a time | run tests after each:
16
+
17
+ | Change Types |
18
+ |--------------|
19
+ | Rename files to match folders |
20
+ | Barrel → direct imports |
21
+ | Extract logic into hooks |
22
+ | Split large components |
23
+
24
+ ## 4. Validate
25
+
26
+ - All tests pass | no `index.ts`/`index.tsx`
27
+ - Entry points match folder names
28
+
29
+ ## Constraints
30
+
31
+ - Structure only, NOT behavior | NO bug fixes
32
+ - One change type at a time | note issues separately
@@ -0,0 +1,46 @@
1
+ # React Code Review Workflow
2
+
3
+ ## 1. Understand
4
+
5
+ - Read PR description | review diff scope
6
+ - Answer: What is the goal? What files changed?
7
+
8
+ ## 2. Architecture Checklist
9
+
10
+ | Check | Rule |
11
+ |-------|------|
12
+ | Barrels | No `index.ts`/`index.tsx` |
13
+ | Entry files | Match folder names (`Button/Button.tsx`) |
14
+ | Imports | Direct, not barrel |
15
+ | Colocation | Component + hooks + types + tests together |
16
+ | Placement | Correct feature folder |
17
+
18
+ ## 3. React Patterns Checklist
19
+
20
+ | Check | Rule |
21
+ |-------|------|
22
+ | Components | Function only, no class |
23
+ | Hooks | No conditionals, proper deps |
24
+ | Effects | Cleanup where needed |
25
+ | Memory | No leaks (subscriptions, timers) |
26
+ | States | Loading + error handled |
27
+
28
+ ## 4. Code Quality Checklist
29
+
30
+ | Check | Rule |
31
+ |-------|------|
32
+ | Debug | No console.log/debugger |
33
+ | Imports | No unused |
34
+ | Types | No unjustified `any` |
35
+ | Tests | Cover new functionality |
36
+ | Scope | No unrelated changes |
37
+
38
+ ## 5. Feedback
39
+
40
+ - **Blocking:** Must fix (bugs, architecture violations)
41
+ - **Suggestion:** Improvements | **Question:** Clarification
42
+
43
+ ## Constraints
44
+
45
+ - NO approval with violations | must understand code
46
+ - Specific + actionable | suggest fixes, not just problems
@@ -0,0 +1,5 @@
1
+ # ORCHESTRATION.md
2
+
3
+ ## Orchestration
4
+
5
+ For complex tasks, refer to .orchestration/orchestration.md for available workflows.
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # codebase-compact
2
+
3
+ Walks a project directory, parses JS/TS/Python files, and outputs a compact structural skeleton of the entire codebase. Designed for feeding project context into LLM prompts with minimal token usage.
4
+
5
+ Typical compaction rate: **~95%** token reduction.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g codebase-compact
11
+ ```
12
+
13
+ Or run directly from the repo:
14
+
15
+ ```bash
16
+ node src/cli.js /path/to/project
17
+ ```
18
+
19
+ ## CLI Usage
20
+
21
+ ```bash
22
+ codebase-compact [path] [options]
23
+ ```
24
+
25
+ **Options:**
26
+
27
+ | Flag | Description |
28
+ |------|-------------|
29
+ | `--json` | Save output as JSON (includes stats) |
30
+ | `--help`, `-h` | Show help |
31
+
32
+ If no path is given, it defaults to the current directory.
33
+
34
+ Output is saved to the target directory as `compacted_<project>_<date>.md`.
35
+
36
+ **Example:**
37
+
38
+ ```bash
39
+ $ codebase-compact ~/projects/my-app
40
+
41
+ Saved to /home/user/projects/my-app/compacted_my-app_2026-02-12_15-30-00.md
42
+
43
+ Files: 96
44
+ Project tokens: 106.9K
45
+ Compacted tokens: 5.9K
46
+ Compaction rate: 94.4%
47
+ ```
48
+
49
+ ## Library Usage
50
+
51
+ ```js
52
+ import { compactProject, compactFile } from 'codebase-compact';
53
+
54
+ // Compact an entire directory
55
+ const { output, stats } = compactProject('/path/to/project');
56
+ console.log(output);
57
+ console.log(stats); // { files, rawTokens, compactedTokens }
58
+
59
+ // Compact a single file
60
+ const { skeleton, formatted } = compactFile('app.tsx', sourceCode);
61
+ ```
62
+
63
+ ## Output Format
64
+
65
+ Each file is rendered as a markdown heading followed by its structural skeleton:
66
+
67
+ ```
68
+ ## src/components/App.jsx
69
+ imports: 3 ext, ./hooks/useAuth, ./api/client
70
+ exports: App*
71
+ components: App:12
72
+ fn: handleSubmit:24, validate:40
73
+ hooks: useState(2), useEffect([user]):18, useAuth
74
+ ```
75
+
76
+ The skeleton captures:
77
+ - **Imports** (local paths shown, externals counted)
78
+ - **Exports** (default marked with `*`)
79
+ - **Components** (PascalCase functions, HOC-wrapped)
80
+ - **Functions** (with line numbers)
81
+ - **Hooks** (counts, useEffect deps, custom hooks)
82
+ - **Classes, interfaces, types** (TS)
83
+ - **Python**: imports, classes (with bases/decorators), functions, constants
84
+
85
+ ## Supported Languages
86
+
87
+ | Language | Parser | Extensions |
88
+ |----------|--------|------------|
89
+ | JavaScript | `@babel/parser` | `.js`, `.jsx`, `.mjs`, `.cjs` |
90
+ | TypeScript | `@babel/parser` | `.ts`, `.tsx`, `.mts`, `.cts` |
91
+ | Python | Regex-based (zero deps) | `.py` |
92
+
93
+ ## Skipped Directories
94
+
95
+ `node_modules`, `dist`, `.git`, `target`, `build`, `.next`, `.turbo`, `out`, `coverage`, `.cache`, `__pycache__`, `.venv`, `venv`, `.idea`, `.vscode`, and any dotfile directories.
96
+
97
+ ## Project Structure
98
+
99
+ ```
100
+ src/
101
+ cli.js # CLI entry point
102
+ index.js # Library API: compactProject, compactFile
103
+ walker.js # Recursive directory walker with filtering
104
+ formatter.js # Output formatting + token estimation
105
+ parsers/
106
+ babel.js # JS/TS parsing via Babel AST
107
+ python.js # Python parsing via regex (top-level only)
108
+ ```
109
+
110
+ ## Tests
111
+
112
+ ```bash
113
+ npm test
114
+ ```
115
+
116
+ ## License
117
+
118
+ MIT
@@ -0,0 +1,34 @@
1
+ ## src/cli.js
2
+ imports: 2 ext, ./index.js, ./formatter.js
3
+ fn: getDateStamp:8, pad:10
4
+ ## src/formatter.js
5
+ imports: ./parsers/python.js, ./parsers/babel.js, ./parsers/python.js
6
+ exports: estimateTokens, formatTokenCount, formatOutput
7
+ fn: estimateTokens:5, formatTokenCount:10, formatOutput:16
8
+ ## src/index.js
9
+ imports: 1 ext, ./walker.js, ./formatter.js, ./parsers/babel.js, ./parsers/python.js
10
+ exports: isBabelParseable, isPythonParseable, estimateTokens, formatTokenCount, compactFile, compactProject
11
+ fn: compactFile:17, compactProject:38
12
+ ## src/parsers/babel.js
13
+ imports: 2 ext
14
+ exports: isBabelParseable, extractSignatures, extractSkeleton, formatSignaturesForPrompt, formatSkeletonForPrompt
15
+ fn: isBabelParseable:9, isPascalCase:13, getReactHOCInfo:17, isCreateContext:52, extractDependencyArray:69, getParamsString:97, getTypeName:123, getReturnType:141, extractSignatures:146, extractSkeleton:242, formatSignaturesForPrompt:402, formatSkeletonForPrompt:407
16
+ ## src/parsers/python.js
17
+ exports: isPythonParseable, extractSkeleton, formatSkeletonForPrompt
18
+ fn: isPythonParseable:3, extractSkeleton:14, formatSkeletonForPrompt:148
19
+ ## src/walker.js
20
+ imports: 2 ext, ./parsers/babel.js, ./parsers/python.js
21
+ exports: collectFiles
22
+ fn: collectFiles:24, SKIP_DIRS_OR_DOT:48, isParseable:52
23
+ ## test/fixtures/sample.js
24
+ imports: 1 ext, ./api
25
+ exports: MyComponent, MyComponent*
26
+ components: MyComponent:6
27
+ fn: helper:16
28
+ hooks: useState(1), useEffect([id]):9
29
+ ## test/fixtures/sample.py
30
+ imports: 4 ext
31
+ classes: BaseProcessor:9, Config @dataclass (BaseProcessor):13
32
+ fn: process_data:17, fetch_remote:20, @app.route api_handler:24
33
+ ## test/test.js
34
+ imports: 5 ext, ../src/index.js, ../src/parsers/babel.js, ../src/parsers/python.js, ../src/walker.js
@@ -0,0 +1,34 @@
1
+ ## src/cli.js
2
+ imports: 2 ext, ./index.js, ./formatter.js
3
+ fn: getDateStamp:8, pad:10
4
+ ## src/formatter.js
5
+ imports: ./parsers/python.js, ./parsers/babel.js, ./parsers/python.js
6
+ exports: estimateTokens, formatTokenCount, formatOutput
7
+ fn: estimateTokens:5, formatTokenCount:10, formatOutput:16
8
+ ## src/index.js
9
+ imports: 1 ext, ./walker.js, ./formatter.js, ./parsers/babel.js, ./parsers/python.js
10
+ exports: isBabelParseable, isPythonParseable, estimateTokens, formatTokenCount, compactFile, compactProject
11
+ fn: compactFile:17, compactProject:38
12
+ ## src/parsers/babel.js
13
+ imports: 2 ext
14
+ exports: isBabelParseable, extractSignatures, extractSkeleton, formatSignaturesForPrompt, formatSkeletonForPrompt
15
+ fn: isBabelParseable:9, isPascalCase:13, getReactHOCInfo:17, isCreateContext:52, extractDependencyArray:69, getParamsString:97, getTypeName:123, getReturnType:141, extractSignatures:146, extractSkeleton:242, formatSignaturesForPrompt:402, formatSkeletonForPrompt:407
16
+ ## src/parsers/python.js
17
+ exports: isPythonParseable, extractSkeleton, formatSkeletonForPrompt
18
+ fn: isPythonParseable:3, extractSkeleton:14, formatSkeletonForPrompt:148
19
+ ## src/walker.js
20
+ imports: 2 ext, ./parsers/babel.js, ./parsers/python.js
21
+ exports: collectFiles
22
+ fn: collectFiles:24, SKIP_DIRS_OR_DOT:48, isParseable:52
23
+ ## test/fixtures/sample.js
24
+ imports: 1 ext, ./api
25
+ exports: MyComponent, MyComponent*
26
+ components: MyComponent:6
27
+ fn: helper:16
28
+ hooks: useState(1), useEffect([id]):9
29
+ ## test/fixtures/sample.py
30
+ imports: 4 ext
31
+ classes: BaseProcessor:9, Config @dataclass (BaseProcessor):13
32
+ fn: process_data:17, fetch_remote:20, @app.route api_handler:24
33
+ ## test/test.js
34
+ imports: 5 ext, ../src/index.js, ../src/parsers/babel.js, ../src/parsers/python.js, ../src/walker.js
@@ -0,0 +1,34 @@
1
+ ## src/cli.js
2
+ imports: 2 ext, ./index.js, ./formatter.js
3
+ fn: getDateStamp:8, pad:10
4
+ ## src/formatter.js
5
+ imports: ./parsers/python.js, ./parsers/babel.js, ./parsers/python.js
6
+ exports: estimateTokens, formatTokenCount, formatOutput
7
+ fn: estimateTokens:5, formatTokenCount:10, formatOutput:16
8
+ ## src/index.js
9
+ imports: 1 ext, ./walker.js, ./formatter.js, ./parsers/babel.js, ./parsers/python.js
10
+ exports: isBabelParseable, isPythonParseable, estimateTokens, formatTokenCount, compactFile, compactProject
11
+ fn: compactFile:17, compactProject:38
12
+ ## src/parsers/babel.js
13
+ imports: 2 ext
14
+ exports: isBabelParseable, extractSignatures, extractSkeleton, formatSignaturesForPrompt, formatSkeletonForPrompt
15
+ fn: isBabelParseable:9, isPascalCase:13, getReactHOCInfo:17, isCreateContext:52, extractDependencyArray:69, getParamsString:97, getTypeName:123, getReturnType:141, extractSignatures:146, extractSkeleton:242, formatSignaturesForPrompt:402, formatSkeletonForPrompt:407
16
+ ## src/parsers/python.js
17
+ exports: isPythonParseable, extractSkeleton, formatSkeletonForPrompt
18
+ fn: isPythonParseable:3, extractSkeleton:14, formatSkeletonForPrompt:148
19
+ ## src/walker.js
20
+ imports: 2 ext, ./parsers/babel.js, ./parsers/python.js
21
+ exports: collectFiles
22
+ fn: collectFiles:24, SKIP_DIRS_OR_DOT:48, isParseable:52
23
+ ## test/fixtures/sample.js
24
+ imports: 1 ext, ./api
25
+ exports: MyComponent, MyComponent*
26
+ components: MyComponent:6
27
+ fn: helper:16
28
+ hooks: useState(1), useEffect([id]):9
29
+ ## test/fixtures/sample.py
30
+ imports: 4 ext
31
+ classes: BaseProcessor:9, Config @dataclass (BaseProcessor):13
32
+ fn: process_data:17, fetch_remote:20, @app.route api_handler:24
33
+ ## test/test.js
34
+ imports: 5 ext, ../src/index.js, ../src/parsers/babel.js, ../src/parsers/python.js, ../src/walker.js
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "agentic-compaction",
3
+ "version": "0.0.1",
4
+ "description": "Walk a project directory and output a compact structural skeleton of the entire codebase",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "bin": {
8
+ "codebase-compact": "./src/cli.js"
9
+ },
10
+ "scripts": {
11
+ "test": "node --test test/"
12
+ },
13
+ "keywords": [
14
+ "codebase",
15
+ "compact",
16
+ "skeleton",
17
+ "parser",
18
+ "ast"
19
+ ],
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "@babel/parser": "^7.24.0",
23
+ "@babel/traverse": "^7.24.0"
24
+ }
25
+ }
package/src/cli.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { resolve, join, basename } from 'path';
4
+ import { writeFileSync } from 'fs';
5
+ import { compactProject } from './index.js';
6
+ import { formatTokenCount } from './formatter.js';
7
+
8
+ function getDateStamp() {
9
+ const now = new Date();
10
+ const pad = (n) => String(n).padStart(2, '0');
11
+ return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
12
+ }
13
+
14
+ const args = process.argv.slice(2);
15
+
16
+ let targetPath = process.cwd();
17
+ let jsonOutput = false;
18
+
19
+ for (let i = 0; i < args.length; i++) {
20
+ const arg = args[i];
21
+ if (arg === '--json') {
22
+ jsonOutput = true;
23
+ } else if (arg === '--help' || arg === '-h') {
24
+ console.log(`Usage: codebase-compact [path] [options]
25
+
26
+ Options:
27
+ --json Output as JSON instead of text
28
+ --help, -h Show this help message
29
+
30
+ Output is saved to compacted_<name>_<date>.md in the target directory.`);
31
+ process.exit(0);
32
+ } else if (!arg.startsWith('-')) {
33
+ targetPath = arg;
34
+ }
35
+ }
36
+
37
+ targetPath = resolve(targetPath);
38
+
39
+ const { output, stats } = compactProject(targetPath);
40
+
41
+ const dirName = basename(targetPath);
42
+ const filename = `compacted_${dirName}_${getDateStamp()}.md`;
43
+ const outputPath = join(targetPath, filename);
44
+
45
+ if (jsonOutput) {
46
+ writeFileSync(outputPath, JSON.stringify({ output, stats }, null, 2));
47
+ } else {
48
+ writeFileSync(outputPath, output);
49
+ }
50
+
51
+ const compactionRate = stats.rawTokens > 0
52
+ ? ((1 - stats.compactedTokens / stats.rawTokens) * 100).toFixed(1)
53
+ : '0';
54
+
55
+ console.log(`\nSaved to ${outputPath}\n`);
56
+ console.log(` Files: ${stats.files}`);
57
+ console.log(` Project tokens: ${formatTokenCount(stats.rawTokens)}`);
58
+ console.log(` Compacted tokens: ${formatTokenCount(stats.compactedTokens)}`);
59
+ console.log(` Compaction rate: ${compactionRate}%`);
@@ -0,0 +1,33 @@
1
+ import { isPythonParseable } from './parsers/python.js';
2
+ import { formatSkeletonForPrompt as formatBabelSkeleton } from './parsers/babel.js';
3
+ import { formatSkeletonForPrompt as formatPythonSkeleton } from './parsers/python.js';
4
+
5
+ export const estimateTokens = (text) => {
6
+ if (!text) return 0;
7
+ return Math.ceil(text.length / 4);
8
+ };
9
+
10
+ export const formatTokenCount = (count) => {
11
+ if (count >= 1000000) return `${(count / 1000000).toFixed(1)}M`;
12
+ if (count >= 1000) return `${(count / 1000).toFixed(1)}K`;
13
+ return count.toString();
14
+ };
15
+
16
+ export function formatOutput(results) {
17
+ const lines = [];
18
+
19
+ results.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
20
+
21
+ for (const result of results) {
22
+ lines.push(`## ${result.relativePath}`);
23
+
24
+ if (result.skeleton) {
25
+ const output = isPythonParseable(result.relativePath)
26
+ ? formatPythonSkeleton(result.skeleton)
27
+ : formatBabelSkeleton(result.skeleton);
28
+ if (output) lines.push(output);
29
+ }
30
+ }
31
+
32
+ return lines.join('\n');
33
+ }