cto-ai-cli 3.0.0 → 3.0.2
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 +10 -10
- package/package.json +2 -1
- package/dist/govern/index.d.ts +0 -261
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
## Try it now (zero install)
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npx cto-
|
|
11
|
+
npx cto-ai-cli
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
That's it. Run it on any project. You'll see something like this:
|
|
@@ -33,7 +33,7 @@ That's it. Run it on any project. You'll see something like this:
|
|
|
33
33
|
Scanned in 11.7s · 177 files · 340K tokens
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
Run `npx cto-
|
|
36
|
+
Run `npx cto-ai-cli --benchmark` to see how CTO compares to naive (alphabetical) and random file selection.
|
|
37
37
|
|
|
38
38
|
No data leaves your machine. No API keys. MIT licensed.
|
|
39
39
|
|
|
@@ -77,10 +77,10 @@ Without type definitions, the AI invents interfaces — wrong property names, wr
|
|
|
77
77
|
### Option 1: Quick score (no install)
|
|
78
78
|
|
|
79
79
|
```bash
|
|
80
|
-
npx cto-
|
|
81
|
-
npx cto-
|
|
82
|
-
npx cto-
|
|
83
|
-
npx cto-
|
|
80
|
+
npx cto-ai-cli # Score your project
|
|
81
|
+
npx cto-ai-cli ./my-project # Score a specific project
|
|
82
|
+
npx cto-ai-cli --benchmark # Compare CTO vs naive vs random
|
|
83
|
+
npx cto-ai-cli --json # Machine-readable output (for CI)
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
### Option 2: Full install
|
|
@@ -132,7 +132,7 @@ CTO doesn't use AI for selection. It uses dependency analysis, risk modeling, an
|
|
|
132
132
|
|
|
133
133
|
## Real numbers
|
|
134
134
|
|
|
135
|
-
We ran CTO on three open-source projects. No cherry-picking — you can reproduce these with `npx cto-
|
|
135
|
+
We ran CTO on three open-source projects. No cherry-picking — you can reproduce these with `npx cto-ai-cli --benchmark`.
|
|
136
136
|
|
|
137
137
|
| Project | Files | Score | What CTO does |
|
|
138
138
|
|---------|-------|-------|---------------|
|
|
@@ -201,14 +201,14 @@ Without these files, the AI has to guess the shape of `AnalyzedFile`, `ContextSe
|
|
|
201
201
|
|
|
202
202
|
| Use case | How |
|
|
203
203
|
|----------|-----|
|
|
204
|
-
| **Score your project** | `npx cto-
|
|
205
|
-
| **Compare strategies** | `npx cto-
|
|
204
|
+
| **Score your project** | `npx cto-ai-cli` |
|
|
205
|
+
| **Compare strategies** | `npx cto-ai-cli --benchmark` |
|
|
206
206
|
| **Get optimized context for a task** | `cto2 interact "your task"` |
|
|
207
207
|
| **PR-focused context** | `cto2 interact --pr "review this PR"` |
|
|
208
208
|
| **Use in your AI editor** | Add MCP server (see setup above) |
|
|
209
209
|
| **Use in CI/CD** | GitHub Action posts score on every PR |
|
|
210
210
|
| **Use as an API** | `cto2-api` starts an HTTP server |
|
|
211
|
-
| **JSON output (scripting)** | `npx cto-
|
|
211
|
+
| **JSON output (scripting)** | `npx cto-ai-cli --json` |
|
|
212
212
|
|
|
213
213
|
---
|
|
214
214
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cto-ai-cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Your AI is reading too much code. CTO analyzes your project and selects the optimal files for AI context — saving tokens, improving output quality, and ensuring type definitions are included.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
+
"cto-ai-cli": "dist/cli/score.js",
|
|
7
8
|
"cto": "dist/cli/index.js",
|
|
8
9
|
"cto2": "dist/cli/v2/index.js",
|
|
9
10
|
"cto-mcp": "dist/mcp/index.js",
|
package/dist/govern/index.d.ts
DELETED
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
interface AuditEntry {
|
|
2
|
-
id: string;
|
|
3
|
-
timestamp: Date;
|
|
4
|
-
action: AuditAction;
|
|
5
|
-
user: string;
|
|
6
|
-
projectPath: string;
|
|
7
|
-
contextHash?: string;
|
|
8
|
-
filesIncluded?: number;
|
|
9
|
-
filesExcluded?: number;
|
|
10
|
-
tokensUsed?: number;
|
|
11
|
-
coverageScore?: number;
|
|
12
|
-
riskScore?: number;
|
|
13
|
-
model?: string;
|
|
14
|
-
estimatedCost?: number;
|
|
15
|
-
integrityHash: string;
|
|
16
|
-
details: Record<string, unknown>;
|
|
17
|
-
}
|
|
18
|
-
type AuditAction = 'init' | 'analyze' | 'interact' | 'snapshot-create' | 'snapshot-verify' | 'policy-change' | 'secret-detected' | 'integrity-check';
|
|
19
|
-
interface PolicySet {
|
|
20
|
-
version: string;
|
|
21
|
-
name: string;
|
|
22
|
-
rules: PolicyRule[];
|
|
23
|
-
}
|
|
24
|
-
interface PolicyRule {
|
|
25
|
-
id: string;
|
|
26
|
-
type: PolicyRuleType;
|
|
27
|
-
pattern?: string;
|
|
28
|
-
threshold?: number;
|
|
29
|
-
category?: string;
|
|
30
|
-
reason: string;
|
|
31
|
-
enabled: boolean;
|
|
32
|
-
}
|
|
33
|
-
type PolicyRuleType = 'include-always' | 'exclude-always' | 'budget-limit' | 'coverage-minimum' | 'risk-maximum' | 'secret-block';
|
|
34
|
-
interface PolicyValidation {
|
|
35
|
-
passed: boolean;
|
|
36
|
-
violations: PolicyViolation[];
|
|
37
|
-
warnings: PolicyWarning[];
|
|
38
|
-
}
|
|
39
|
-
interface PolicyViolation {
|
|
40
|
-
rule: PolicyRule;
|
|
41
|
-
message: string;
|
|
42
|
-
severity: 'error' | 'warning';
|
|
43
|
-
}
|
|
44
|
-
interface PolicyWarning {
|
|
45
|
-
rule: PolicyRule;
|
|
46
|
-
message: string;
|
|
47
|
-
currentValue: number;
|
|
48
|
-
threshold: number;
|
|
49
|
-
}
|
|
50
|
-
interface ContextSnapshot {
|
|
51
|
-
id: string;
|
|
52
|
-
name: string;
|
|
53
|
-
createdAt: Date;
|
|
54
|
-
hash: string;
|
|
55
|
-
projectHash: string;
|
|
56
|
-
analysisHash: string;
|
|
57
|
-
selectionHash: string;
|
|
58
|
-
files: SnapshotFile[];
|
|
59
|
-
totalTokens: number;
|
|
60
|
-
coverageScore: number;
|
|
61
|
-
riskScore: number;
|
|
62
|
-
metadata: Record<string, unknown>;
|
|
63
|
-
}
|
|
64
|
-
interface SnapshotFile {
|
|
65
|
-
relativePath: string;
|
|
66
|
-
hash: string;
|
|
67
|
-
tokens: number;
|
|
68
|
-
pruneLevel: string;
|
|
69
|
-
}
|
|
70
|
-
interface SnapshotVerification {
|
|
71
|
-
valid: boolean;
|
|
72
|
-
snapshotId: string;
|
|
73
|
-
filesChecked: number;
|
|
74
|
-
filesMatched: number;
|
|
75
|
-
filesMissing: string[];
|
|
76
|
-
filesChanged: string[];
|
|
77
|
-
integrityOk: boolean;
|
|
78
|
-
}
|
|
79
|
-
interface SecretFinding {
|
|
80
|
-
type: SecretType;
|
|
81
|
-
file: string;
|
|
82
|
-
line: number;
|
|
83
|
-
match: string;
|
|
84
|
-
redacted: string;
|
|
85
|
-
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
86
|
-
}
|
|
87
|
-
type SecretType = 'api-key' | 'aws-key' | 'private-key' | 'password' | 'token' | 'connection-string' | 'env-variable' | 'custom';
|
|
88
|
-
interface IntegrityManifest {
|
|
89
|
-
version: string;
|
|
90
|
-
createdAt: Date;
|
|
91
|
-
entries: IntegrityEntry[];
|
|
92
|
-
}
|
|
93
|
-
interface IntegrityEntry {
|
|
94
|
-
filePath: string;
|
|
95
|
-
hash: string;
|
|
96
|
-
size: number;
|
|
97
|
-
createdAt: Date;
|
|
98
|
-
type: 'snapshot' | 'audit' | 'config' | 'policy';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
declare function logAudit(action: AuditAction, projectPath: string, details?: Record<string, unknown>): Promise<AuditEntry>;
|
|
102
|
-
declare function getAuditEntries(options?: {
|
|
103
|
-
projectPath?: string;
|
|
104
|
-
action?: AuditAction;
|
|
105
|
-
since?: Date;
|
|
106
|
-
limit?: number;
|
|
107
|
-
}): Promise<AuditEntry[]>;
|
|
108
|
-
declare function verifyAuditEntry(entry: AuditEntry): boolean;
|
|
109
|
-
declare function verifyAuditIntegrity(): Promise<{
|
|
110
|
-
totalEntries: number;
|
|
111
|
-
validEntries: number;
|
|
112
|
-
invalidEntries: AuditEntry[];
|
|
113
|
-
}>;
|
|
114
|
-
declare function purgeOldAuditEntries(retentionDays: number): Promise<number>;
|
|
115
|
-
|
|
116
|
-
declare function scanContentForSecrets(content: string, filePath: string, customPatterns?: string[]): SecretFinding[];
|
|
117
|
-
declare function scanFileForSecrets(filePath: string, projectPath: string, customPatterns?: string[]): Promise<SecretFinding[]>;
|
|
118
|
-
declare function scanProjectForSecrets(projectPath: string, filePaths: string[], customPatterns?: string[]): Promise<SecretFinding[]>;
|
|
119
|
-
declare function sanitizeContent(content: string, customPatterns?: string[]): string;
|
|
120
|
-
|
|
121
|
-
interface AnalyzedFile {
|
|
122
|
-
path: string;
|
|
123
|
-
relativePath: string;
|
|
124
|
-
extension: string;
|
|
125
|
-
size: number;
|
|
126
|
-
tokens: number;
|
|
127
|
-
lines: number;
|
|
128
|
-
lastModified: Date;
|
|
129
|
-
kind: FileKind;
|
|
130
|
-
imports: string[];
|
|
131
|
-
importedBy: string[];
|
|
132
|
-
isHub: boolean;
|
|
133
|
-
complexity: number;
|
|
134
|
-
riskScore: number;
|
|
135
|
-
riskFactors: RiskFactor[];
|
|
136
|
-
exclusionImpact: ExclusionImpact;
|
|
137
|
-
}
|
|
138
|
-
type FileKind = 'source' | 'type' | 'test' | 'config' | 'entry' | 'asset';
|
|
139
|
-
type ExclusionImpact = 'critical' | 'high' | 'medium' | 'low' | 'none';
|
|
140
|
-
interface ProjectAnalysis {
|
|
141
|
-
projectPath: string;
|
|
142
|
-
projectName: string;
|
|
143
|
-
analyzedAt: Date;
|
|
144
|
-
hash: string;
|
|
145
|
-
files: AnalyzedFile[];
|
|
146
|
-
totalFiles: number;
|
|
147
|
-
totalTokens: number;
|
|
148
|
-
graph: ProjectGraph;
|
|
149
|
-
riskProfile: RiskProfile;
|
|
150
|
-
stack: string[];
|
|
151
|
-
tokenMethod: 'chars4' | 'tiktoken';
|
|
152
|
-
}
|
|
153
|
-
interface ProjectGraph {
|
|
154
|
-
nodes: string[];
|
|
155
|
-
edges: GraphEdge[];
|
|
156
|
-
hubs: HubNode[];
|
|
157
|
-
leaves: string[];
|
|
158
|
-
orphans: string[];
|
|
159
|
-
clusters: FileCluster[];
|
|
160
|
-
}
|
|
161
|
-
interface GraphEdge {
|
|
162
|
-
from: string;
|
|
163
|
-
to: string;
|
|
164
|
-
type: 'import' | 'export' | 're-export';
|
|
165
|
-
}
|
|
166
|
-
interface HubNode {
|
|
167
|
-
relativePath: string;
|
|
168
|
-
dependents: number;
|
|
169
|
-
dependencies: number;
|
|
170
|
-
score: number;
|
|
171
|
-
}
|
|
172
|
-
interface FileCluster {
|
|
173
|
-
id: string;
|
|
174
|
-
name: string;
|
|
175
|
-
files: string[];
|
|
176
|
-
totalTokens: number;
|
|
177
|
-
internalEdges: number;
|
|
178
|
-
externalEdges: number;
|
|
179
|
-
cohesion: number;
|
|
180
|
-
}
|
|
181
|
-
interface RiskProfile {
|
|
182
|
-
distribution: {
|
|
183
|
-
critical: number;
|
|
184
|
-
high: number;
|
|
185
|
-
medium: number;
|
|
186
|
-
low: number;
|
|
187
|
-
};
|
|
188
|
-
topRiskFiles: AnalyzedFile[];
|
|
189
|
-
overallComplexity: number;
|
|
190
|
-
}
|
|
191
|
-
interface RiskFactor {
|
|
192
|
-
type: RiskFactorType;
|
|
193
|
-
score: number;
|
|
194
|
-
weight: number;
|
|
195
|
-
detail: string;
|
|
196
|
-
}
|
|
197
|
-
type RiskFactorType = 'hub' | 'type-provider' | 'complexity' | 'recency' | 'config' | 'churn';
|
|
198
|
-
interface CoverageResult {
|
|
199
|
-
score: number;
|
|
200
|
-
relevantFiles: string[];
|
|
201
|
-
includedRelevant: string[];
|
|
202
|
-
missingRelevant: string[];
|
|
203
|
-
missingCritical: string[];
|
|
204
|
-
explanation: string;
|
|
205
|
-
}
|
|
206
|
-
interface ContextSelection {
|
|
207
|
-
files: SelectedFile[];
|
|
208
|
-
totalTokens: number;
|
|
209
|
-
budget: number;
|
|
210
|
-
usedPercent: number;
|
|
211
|
-
coverage: CoverageResult;
|
|
212
|
-
riskScore: number;
|
|
213
|
-
deterministic: boolean;
|
|
214
|
-
hash: string;
|
|
215
|
-
decisions: SelectionDecision[];
|
|
216
|
-
}
|
|
217
|
-
interface SelectedFile {
|
|
218
|
-
relativePath: string;
|
|
219
|
-
tokens: number;
|
|
220
|
-
originalTokens: number;
|
|
221
|
-
pruneLevel: PruneLevel;
|
|
222
|
-
riskScore: number;
|
|
223
|
-
reason: string;
|
|
224
|
-
}
|
|
225
|
-
type PruneLevel = 'full' | 'signatures' | 'skeleton' | 'excluded';
|
|
226
|
-
interface SelectionDecision {
|
|
227
|
-
file: string;
|
|
228
|
-
action: 'include-full' | 'include-signatures' | 'include-skeleton' | 'exclude';
|
|
229
|
-
reason: string;
|
|
230
|
-
alternatives?: string;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
declare const DEFAULT_POLICY: PolicySet;
|
|
234
|
-
declare function validateSelection(selection: ContextSelection, policies: PolicySet, allFiles?: AnalyzedFile[]): PolicyValidation;
|
|
235
|
-
declare function addRule(policies: PolicySet, rule: PolicyRule): PolicySet;
|
|
236
|
-
declare function removeRule(policies: PolicySet, ruleId: string): PolicySet;
|
|
237
|
-
declare function toggleRule(policies: PolicySet, ruleId: string, enabled: boolean): PolicySet;
|
|
238
|
-
|
|
239
|
-
declare function createSnapshot(name: string, analysis: ProjectAnalysis, selection: ContextSelection, metadata?: Record<string, unknown>): ContextSnapshot;
|
|
240
|
-
declare function verifySnapshot(snapshot: ContextSnapshot, currentAnalysis: ProjectAnalysis, currentSelection: ContextSelection): Promise<SnapshotVerification>;
|
|
241
|
-
declare function compareSnapshots(older: ContextSnapshot, newer: ContextSnapshot): {
|
|
242
|
-
added: string[];
|
|
243
|
-
removed: string[];
|
|
244
|
-
changed: string[];
|
|
245
|
-
tokenDelta: number;
|
|
246
|
-
coverageDelta: number;
|
|
247
|
-
riskDelta: number;
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
declare function hashContent(content: Buffer | string): string;
|
|
251
|
-
declare function hashFile(filePath: string): Promise<string | null>;
|
|
252
|
-
declare function buildManifest(projectDir: string): Promise<IntegrityManifest>;
|
|
253
|
-
declare function verifyManifest(manifest: IntegrityManifest): Promise<{
|
|
254
|
-
totalFiles: number;
|
|
255
|
-
validFiles: number;
|
|
256
|
-
invalidFiles: string[];
|
|
257
|
-
missingFiles: string[];
|
|
258
|
-
}>;
|
|
259
|
-
declare function securePermissions(dirPath: string): Promise<number>;
|
|
260
|
-
|
|
261
|
-
export { DEFAULT_POLICY, addRule, buildManifest, compareSnapshots, createSnapshot, getAuditEntries, hashContent, hashFile, logAudit, purgeOldAuditEntries, removeRule, sanitizeContent, scanContentForSecrets, scanFileForSecrets, scanProjectForSecrets, securePermissions, toggleRule, validateSelection, verifyAuditEntry, verifyAuditIntegrity, verifyManifest, verifySnapshot };
|