ccompactor 0.1.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/LICENSE +21 -0
- package/NOTICE +37 -0
- package/README.md +101 -0
- package/dist/adapters/claude.d.ts +36 -0
- package/dist/adapters/claude.js +361 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +11 -0
- package/dist/adapters/codex.js +218 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/index.d.ts +17 -0
- package/dist/adapters/index.js +19 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/pi.d.ts +16 -0
- package/dist/adapters/pi.js +213 -0
- package/dist/adapters/pi.js.map +1 -0
- package/dist/adapters/types.d.ts +31 -0
- package/dist/adapters/types.js +7 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/artifact/expand.d.ts +23 -0
- package/dist/artifact/expand.js +71 -0
- package/dist/artifact/expand.js.map +1 -0
- package/dist/artifact/render.d.ts +59 -0
- package/dist/artifact/render.js +357 -0
- package/dist/artifact/render.js.map +1 -0
- package/dist/artifact/verify.d.ts +12 -0
- package/dist/artifact/verify.js +48 -0
- package/dist/artifact/verify.js.map +1 -0
- package/dist/bench/index.d.ts +71 -0
- package/dist/bench/index.js +186 -0
- package/dist/bench/index.js.map +1 -0
- package/dist/bench/run.d.ts +17 -0
- package/dist/bench/run.js +187 -0
- package/dist/bench/run.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +322 -0
- package/dist/cli.js.map +1 -0
- package/dist/compact/engine.d.ts +69 -0
- package/dist/compact/engine.js +164 -0
- package/dist/compact/engine.js.map +1 -0
- package/dist/compact/shims.d.ts +24 -0
- package/dist/compact/shims.js +14 -0
- package/dist/compact/shims.js.map +1 -0
- package/dist/discover/index.d.ts +40 -0
- package/dist/discover/index.js +164 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/discover/reference.d.ts +21 -0
- package/dist/discover/reference.js +44 -0
- package/dist/discover/reference.js.map +1 -0
- package/dist/extract.d.ts +26 -0
- package/dist/extract.js +103 -0
- package/dist/extract.js.map +1 -0
- package/dist/handoff/index.d.ts +12 -0
- package/dist/handoff/index.js +67 -0
- package/dist/handoff/index.js.map +1 -0
- package/dist/ir/tokens.d.ts +14 -0
- package/dist/ir/tokens.js +36 -0
- package/dist/ir/tokens.js.map +1 -0
- package/dist/ir/types.d.ts +82 -0
- package/dist/ir/types.js +36 -0
- package/dist/ir/types.js.map +1 -0
- package/dist/ledgers/index.d.ts +66 -0
- package/dist/ledgers/index.js +185 -0
- package/dist/ledgers/index.js.map +1 -0
- package/dist/llm/index.d.ts +43 -0
- package/dist/llm/index.js +143 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/redact.d.ts +39 -0
- package/dist/redact.js +104 -0
- package/dist/redact.js.map +1 -0
- package/dist/skill/index.d.ts +9 -0
- package/dist/skill/index.js +48 -0
- package/dist/skill/index.js.map +1 -0
- package/dist/triage.d.ts +25 -0
- package/dist/triage.js +160 -0
- package/dist/triage.js.map +1 -0
- package/dist/tui/index.d.ts +4 -0
- package/dist/tui/index.js +147 -0
- package/dist/tui/index.js.map +1 -0
- package/package.json +71 -0
- package/skill/SKILL.md +54 -0
package/dist/ir/types.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical internal representation.
|
|
3
|
+
*
|
|
4
|
+
* Every adapter normalises a provider's transcript into these types, and every
|
|
5
|
+
* later stage reads only these types. That is what makes a Codex session and a
|
|
6
|
+
* Claude session the same problem downstream — and it is the only reason adding
|
|
7
|
+
* an agent is a file rather than a fork.
|
|
8
|
+
*
|
|
9
|
+
* Spec: docs/SPEC.md §5.
|
|
10
|
+
*/
|
|
11
|
+
/** `evt 12` or `evt 12–19`. The artifact's only pointer syntax. */
|
|
12
|
+
export function evtLabel(from, to) {
|
|
13
|
+
const end = to ?? from;
|
|
14
|
+
return from === end ? `evt ${from}` : `evt ${from}–${end}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The transcript content after the last compact boundary, plus everything when
|
|
18
|
+
* there is none. A provider compaction already summarised what came before, so
|
|
19
|
+
* re-reading it means summarising a summary.
|
|
20
|
+
*/
|
|
21
|
+
export function afterLastBoundary(ir) {
|
|
22
|
+
const last = ir.compactBoundaries.at(-1);
|
|
23
|
+
if (last === undefined)
|
|
24
|
+
return ir.messages;
|
|
25
|
+
return ir.messages.filter((m) => m.eventIndex >= last);
|
|
26
|
+
}
|
|
27
|
+
/** Events the human actually typed. Intent lives here and nowhere else. */
|
|
28
|
+
export function humanTurns(ir) {
|
|
29
|
+
return ir.messages.filter((m) => m.isHumanTurn && !m.isMeta);
|
|
30
|
+
}
|
|
31
|
+
/** Cwd recorded by the provider, if any. */
|
|
32
|
+
export function sessionCwd(ir) {
|
|
33
|
+
const cwd = ir.metadata['cwd'];
|
|
34
|
+
return typeof cwd === 'string' && cwd.length > 0 ? cwd : undefined;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ir/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA2EH,mEAAmE;AACnE,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,EAAW;IAChD,MAAM,GAAG,GAAG,EAAE,IAAI,IAAI,CAAA;IACtB,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,IAAI,GAAG,EAAE,CAAA;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAa;IAC7C,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IACxC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC,QAAQ,CAAA;IAC1C,OAAO,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAA;AACxD,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,UAAU,CAAC,EAAa;IACtC,OAAO,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAC9D,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,UAAU,CAAC,EAAa;IACtC,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC9B,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AACpE,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic ledgers.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is computed from the transcript without a model. That is the
|
|
5
|
+
* point: a handoff that cannot say which files were touched, which commands
|
|
6
|
+
* failed and what the human actually asked for is not worth the model call that
|
|
7
|
+
* would summarise it, and these facts are cheap and exact.
|
|
8
|
+
*
|
|
9
|
+
* Every record carries the event index it came from, so anything the artifact
|
|
10
|
+
* claims can be pulled back out with `ccompactor expand`.
|
|
11
|
+
*/
|
|
12
|
+
import type { SessionIR } from '../ir/types.js';
|
|
13
|
+
export interface FileRecord {
|
|
14
|
+
path: string;
|
|
15
|
+
edits: number;
|
|
16
|
+
writes: number;
|
|
17
|
+
reads: number;
|
|
18
|
+
firstEvt: number;
|
|
19
|
+
lastEvt: number;
|
|
20
|
+
}
|
|
21
|
+
export interface CommandRecord {
|
|
22
|
+
command: string;
|
|
23
|
+
evt: number;
|
|
24
|
+
exitCode?: number;
|
|
25
|
+
failed: boolean;
|
|
26
|
+
outputHead: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ErrorRecord {
|
|
29
|
+
signature: string;
|
|
30
|
+
evt: number;
|
|
31
|
+
occurrences: number;
|
|
32
|
+
example: string;
|
|
33
|
+
}
|
|
34
|
+
export interface CommitRecord {
|
|
35
|
+
sha: string;
|
|
36
|
+
subject: string;
|
|
37
|
+
evt: number;
|
|
38
|
+
}
|
|
39
|
+
export interface Ledgers {
|
|
40
|
+
files: FileRecord[];
|
|
41
|
+
commands: CommandRecord[];
|
|
42
|
+
errors: ErrorRecord[];
|
|
43
|
+
commits: CommitRecord[];
|
|
44
|
+
userTurns: Array<{
|
|
45
|
+
evt: number;
|
|
46
|
+
text: string;
|
|
47
|
+
}>;
|
|
48
|
+
toolUse: Array<{
|
|
49
|
+
name: string;
|
|
50
|
+
count: number;
|
|
51
|
+
}>;
|
|
52
|
+
counts: {
|
|
53
|
+
messages: number;
|
|
54
|
+
userTurns: number;
|
|
55
|
+
toolCalls: number;
|
|
56
|
+
failedCommands: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export declare function buildLedgers(ir: SessionIR): Ledgers;
|
|
60
|
+
/**
|
|
61
|
+
* A signature is the error's *shape* with the parts that vary per occurrence
|
|
62
|
+
* removed — paths, line numbers, hex ids, counts — so the same failure repeated
|
|
63
|
+
* forty times is one record with a count rather than forty records.
|
|
64
|
+
*/
|
|
65
|
+
export declare function errorSignature(text: string): string;
|
|
66
|
+
export declare function isNoisePath(path: string): boolean;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/** Tools whose argument names a file the session worked on. */
|
|
2
|
+
const FILE_TOOLS = {
|
|
3
|
+
Edit: 'edit',
|
|
4
|
+
MultiEdit: 'edit',
|
|
5
|
+
NotebookEdit: 'edit',
|
|
6
|
+
Write: 'write',
|
|
7
|
+
Read: 'read',
|
|
8
|
+
NotebookRead: 'read',
|
|
9
|
+
};
|
|
10
|
+
const COMMAND_TOOLS = new Set(['Bash', 'BashOutput', 'Shell', 'shell']);
|
|
11
|
+
export function buildLedgers(ir) {
|
|
12
|
+
const files = new Map();
|
|
13
|
+
const commands = [];
|
|
14
|
+
const errors = [];
|
|
15
|
+
const commits = [];
|
|
16
|
+
const userTurns = [];
|
|
17
|
+
const toolCounts = new Map();
|
|
18
|
+
// Tool results are keyed by call id, so a command's outcome attaches to the
|
|
19
|
+
// call that produced it rather than being guessed from proximity.
|
|
20
|
+
const resultFor = new Map();
|
|
21
|
+
for (const message of ir.messages) {
|
|
22
|
+
if (message.role === 'tool' && message.toolUseId)
|
|
23
|
+
resultFor.set(message.toolUseId, message);
|
|
24
|
+
}
|
|
25
|
+
for (const message of ir.messages) {
|
|
26
|
+
if (message.isHumanTurn && message.text) {
|
|
27
|
+
userTurns.push({ evt: message.eventIndex, text: message.text });
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (message.role !== 'assistant' || !message.toolName)
|
|
31
|
+
continue;
|
|
32
|
+
toolCounts.set(message.toolName, (toolCounts.get(message.toolName) ?? 0) + 1);
|
|
33
|
+
const input = asRecord(message.toolInput);
|
|
34
|
+
const result = message.toolUseId ? resultFor.get(message.toolUseId) : undefined;
|
|
35
|
+
const fileKind = FILE_TOOLS[message.toolName];
|
|
36
|
+
if (fileKind) {
|
|
37
|
+
const path = firstString(input, ['file_path', 'path', 'notebook_path']);
|
|
38
|
+
if (path) {
|
|
39
|
+
const record = files.get(path) ?? {
|
|
40
|
+
path,
|
|
41
|
+
edits: 0,
|
|
42
|
+
writes: 0,
|
|
43
|
+
reads: 0,
|
|
44
|
+
firstEvt: message.eventIndex,
|
|
45
|
+
lastEvt: message.eventIndex,
|
|
46
|
+
};
|
|
47
|
+
if (fileKind === 'edit')
|
|
48
|
+
record.edits += 1;
|
|
49
|
+
if (fileKind === 'write')
|
|
50
|
+
record.writes += 1;
|
|
51
|
+
if (fileKind === 'read')
|
|
52
|
+
record.reads += 1;
|
|
53
|
+
record.lastEvt = Math.max(record.lastEvt, message.eventIndex);
|
|
54
|
+
files.set(path, record);
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (COMMAND_TOOLS.has(message.toolName)) {
|
|
59
|
+
const command = firstString(input, ['command', 'cmd']);
|
|
60
|
+
if (!command)
|
|
61
|
+
continue;
|
|
62
|
+
const exitCode = exitCodeOf(result);
|
|
63
|
+
const failed = result?.isError === true || (exitCode !== undefined && exitCode !== 0);
|
|
64
|
+
commands.push({
|
|
65
|
+
command: command.split('\n')[0].slice(0, 300),
|
|
66
|
+
evt: message.eventIndex,
|
|
67
|
+
...(exitCode !== undefined ? { exitCode } : {}),
|
|
68
|
+
failed,
|
|
69
|
+
outputHead: head(result?.text),
|
|
70
|
+
});
|
|
71
|
+
if (failed) {
|
|
72
|
+
errors.push(errorRecord(result?.text ?? command, message.eventIndex, command));
|
|
73
|
+
}
|
|
74
|
+
collectCommit(command, message.eventIndex, commits);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
files: [...files.values()].sort((a, b) => weight(b) - weight(a) || a.path.localeCompare(b.path)),
|
|
79
|
+
commands: commands.sort((a, b) => a.evt - b.evt),
|
|
80
|
+
errors: mergeErrors(errors),
|
|
81
|
+
commits,
|
|
82
|
+
userTurns,
|
|
83
|
+
toolUse: [...toolCounts.entries()]
|
|
84
|
+
.map(([name, count]) => ({ name, count }))
|
|
85
|
+
.sort((a, b) => b.count - a.count || a.name.localeCompare(b.name)),
|
|
86
|
+
counts: {
|
|
87
|
+
messages: ir.messages.length,
|
|
88
|
+
userTurns: userTurns.length,
|
|
89
|
+
toolCalls: [...toolCounts.values()].reduce((a, b) => a + b, 0),
|
|
90
|
+
failedCommands: commands.filter((c) => c.failed).length,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** A file the session wrote to matters more than one it merely read. */
|
|
95
|
+
function weight(file) {
|
|
96
|
+
return file.edits * 3 + file.writes * 3 + file.reads;
|
|
97
|
+
}
|
|
98
|
+
const GIT_COMMIT = /git\s+commit\s+(?:-[a-zA-Z-]+\s+)*(?:-m\s+)?["']([^"']+)["']/;
|
|
99
|
+
function collectCommit(command, evt, out) {
|
|
100
|
+
if (!command.includes('git commit'))
|
|
101
|
+
return;
|
|
102
|
+
const message = GIT_COMMIT.exec(command)?.[1];
|
|
103
|
+
if (message)
|
|
104
|
+
out.push({ sha: '?', subject: message.slice(0, 200), evt });
|
|
105
|
+
}
|
|
106
|
+
function exitCodeOf(result) {
|
|
107
|
+
if (!result)
|
|
108
|
+
return undefined;
|
|
109
|
+
const raw = asRecord(result.raw);
|
|
110
|
+
const toolUseResult = asRecord(raw['toolUseResult']);
|
|
111
|
+
for (const candidate of [toolUseResult['exitCode'], toolUseResult['exit_code']]) {
|
|
112
|
+
if (typeof candidate === 'number')
|
|
113
|
+
return candidate;
|
|
114
|
+
}
|
|
115
|
+
const match = /exit code (\d+)/i.exec(result.text ?? '');
|
|
116
|
+
return match ? Number.parseInt(match[1], 10) : undefined;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A signature is the error's *shape* with the parts that vary per occurrence
|
|
120
|
+
* removed — paths, line numbers, hex ids, counts — so the same failure repeated
|
|
121
|
+
* forty times is one record with a count rather than forty records.
|
|
122
|
+
*/
|
|
123
|
+
export function errorSignature(text) {
|
|
124
|
+
const line = text
|
|
125
|
+
.split('\n')
|
|
126
|
+
.map((l) => l.trim())
|
|
127
|
+
.find((l) => l.length > 0)
|
|
128
|
+
?.slice(0, 200) ?? '';
|
|
129
|
+
return line
|
|
130
|
+
.replace(/0x[0-9a-f]+/gi, '0x…')
|
|
131
|
+
.replace(/\b[0-9a-f]{7,40}\b/gi, '…')
|
|
132
|
+
.replace(/\/[^\s:]+/g, (m) => (m.length > 12 ? `…${m.slice(-12)}` : m))
|
|
133
|
+
.replace(/:\d+:\d+/g, ':N:N')
|
|
134
|
+
.replace(/:\d+/g, ':N')
|
|
135
|
+
.replace(/\b\d{2,}\b/g, 'N')
|
|
136
|
+
.replace(/\s+/g, ' ')
|
|
137
|
+
.trim();
|
|
138
|
+
}
|
|
139
|
+
function errorRecord(text, evt, fallback) {
|
|
140
|
+
const signature = errorSignature(text) || errorSignature(fallback);
|
|
141
|
+
return { signature, evt, occurrences: 1, example: head(text) };
|
|
142
|
+
}
|
|
143
|
+
function mergeErrors(errors) {
|
|
144
|
+
const merged = new Map();
|
|
145
|
+
for (const error of errors) {
|
|
146
|
+
const existing = merged.get(error.signature);
|
|
147
|
+
if (existing) {
|
|
148
|
+
existing.occurrences += 1;
|
|
149
|
+
existing.evt = Math.max(existing.evt, error.evt);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
merged.set(error.signature, { ...error });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return [...merged.values()].sort((a, b) => b.occurrences - a.occurrences || a.signature.localeCompare(b.signature));
|
|
156
|
+
}
|
|
157
|
+
function head(text) {
|
|
158
|
+
if (!text)
|
|
159
|
+
return '';
|
|
160
|
+
return text.split('\n').slice(0, 3).join(' ').trim().slice(0, 200);
|
|
161
|
+
}
|
|
162
|
+
function asRecord(value) {
|
|
163
|
+
return typeof value === 'object' && value !== null ? value : {};
|
|
164
|
+
}
|
|
165
|
+
function firstString(record, keys) {
|
|
166
|
+
for (const key of keys) {
|
|
167
|
+
const value = record[key];
|
|
168
|
+
if (typeof value === 'string' && value.length > 0)
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
/** Paths under these are noise: dependencies, build output, logs, caches. */
|
|
174
|
+
const NOISE = [
|
|
175
|
+
/(^|\/)node_modules\//,
|
|
176
|
+
/(^|\/)\.git\//,
|
|
177
|
+
/(^|\/)dist\//,
|
|
178
|
+
/(^|\/)build\//,
|
|
179
|
+
/\.log$/,
|
|
180
|
+
/(^|\/)\.cache\//,
|
|
181
|
+
];
|
|
182
|
+
export function isNoisePath(path) {
|
|
183
|
+
return NOISE.some((pattern) => pattern.test(path));
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ledgers/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM backends for the summary step.
|
|
3
|
+
*
|
|
4
|
+
* `--llm none` is a first-class mode, not a degraded one: the deterministic
|
|
5
|
+
* artifact is complete for following the evidence, and it costs nothing. The
|
|
6
|
+
* model is what turns evidence into understanding, and everything else works
|
|
7
|
+
* without it.
|
|
8
|
+
*
|
|
9
|
+
* Only `fetch` is used. An SDK per provider is a dependency per provider, and
|
|
10
|
+
* the differences between these APIs are a URL, a header and a JSON shape.
|
|
11
|
+
*/
|
|
12
|
+
export type Selection = {
|
|
13
|
+
kind: 'none';
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'anthropic';
|
|
16
|
+
model: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'openai';
|
|
19
|
+
model: string;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'compat';
|
|
22
|
+
model: string;
|
|
23
|
+
baseUrl: string;
|
|
24
|
+
};
|
|
25
|
+
export interface LlmRequest {
|
|
26
|
+
system: string;
|
|
27
|
+
user: string;
|
|
28
|
+
maxTokens: number;
|
|
29
|
+
}
|
|
30
|
+
export interface LlmResponse {
|
|
31
|
+
text: string;
|
|
32
|
+
inputTokens?: number;
|
|
33
|
+
outputTokens?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface Backend {
|
|
36
|
+
readonly label: string;
|
|
37
|
+
complete(request: LlmRequest): Promise<LlmResponse>;
|
|
38
|
+
}
|
|
39
|
+
export declare function parseSelection(text: string): Selection;
|
|
40
|
+
/** Resolve `auto`: an API key if one is present, otherwise nothing. */
|
|
41
|
+
export declare function resolveAuto(): Selection;
|
|
42
|
+
export declare function selectionLabel(selection: Selection): string;
|
|
43
|
+
export declare function build(selection: Selection): Backend | undefined;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM backends for the summary step.
|
|
3
|
+
*
|
|
4
|
+
* `--llm none` is a first-class mode, not a degraded one: the deterministic
|
|
5
|
+
* artifact is complete for following the evidence, and it costs nothing. The
|
|
6
|
+
* model is what turns evidence into understanding, and everything else works
|
|
7
|
+
* without it.
|
|
8
|
+
*
|
|
9
|
+
* Only `fetch` is used. An SDK per provider is a dependency per provider, and
|
|
10
|
+
* the differences between these APIs are a URL, a header and a JSON shape.
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_MODELS = {
|
|
13
|
+
anthropic: 'claude-sonnet-4-5-20250929',
|
|
14
|
+
openai: 'gpt-4.1-mini',
|
|
15
|
+
compat: 'deepseek-chat',
|
|
16
|
+
};
|
|
17
|
+
export function parseSelection(text) {
|
|
18
|
+
const value = text.trim();
|
|
19
|
+
if (value === 'none')
|
|
20
|
+
return { kind: 'none' };
|
|
21
|
+
// The spec writes these as `api:anthropic`, `api:compat/<model>`. Splitting on
|
|
22
|
+
// `/` before stripping the `api:` prefix makes the provider `api:compat` and
|
|
23
|
+
// every run fail with a message that names the prefix it just failed to strip.
|
|
24
|
+
const bare = value.startsWith('api:') ? value.slice(4) : value;
|
|
25
|
+
const [provider, model] = bare.split('/');
|
|
26
|
+
if (!provider)
|
|
27
|
+
throw new Error(`unknown --llm \`${text}\``);
|
|
28
|
+
if (provider === 'anthropic')
|
|
29
|
+
return { kind: 'anthropic', model: model ?? DEFAULT_MODELS['anthropic'] };
|
|
30
|
+
if (provider === 'openai')
|
|
31
|
+
return { kind: 'openai', model: model ?? DEFAULT_MODELS['openai'] };
|
|
32
|
+
if (provider === 'compat') {
|
|
33
|
+
const baseUrl = process.env['CCOMPACTOR_BASE_URL'];
|
|
34
|
+
if (!baseUrl)
|
|
35
|
+
throw new Error('--llm api:compat needs CCOMPACTOR_BASE_URL');
|
|
36
|
+
return { kind: 'compat', model: model ?? DEFAULT_MODELS['compat'], baseUrl };
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`unknown --llm provider \`${provider}\` (expected none, api:anthropic, api:openai, api:compat/<model>)`);
|
|
39
|
+
}
|
|
40
|
+
/** Resolve `auto`: an API key if one is present, otherwise nothing. */
|
|
41
|
+
export function resolveAuto() {
|
|
42
|
+
const explicit = process.env['CCOMPACTOR_LLM'];
|
|
43
|
+
if (explicit && explicit !== 'auto')
|
|
44
|
+
return parseSelection(explicit);
|
|
45
|
+
if (process.env['ANTHROPIC_API_KEY'])
|
|
46
|
+
return parseSelection('api:anthropic');
|
|
47
|
+
if (process.env['OPENAI_API_KEY'])
|
|
48
|
+
return parseSelection('api:openai');
|
|
49
|
+
if (process.env['CCOMPACTOR_API_KEY'] && process.env['CCOMPACTOR_BASE_URL']) {
|
|
50
|
+
return parseSelection('api:compat');
|
|
51
|
+
}
|
|
52
|
+
return { kind: 'none' };
|
|
53
|
+
}
|
|
54
|
+
export function selectionLabel(selection) {
|
|
55
|
+
return selection.kind === 'none' ? 'none' : `api:${selection.kind}/${selection.model}`;
|
|
56
|
+
}
|
|
57
|
+
export function build(selection) {
|
|
58
|
+
if (selection.kind === 'none')
|
|
59
|
+
return undefined;
|
|
60
|
+
return new HttpBackend(selection);
|
|
61
|
+
}
|
|
62
|
+
class HttpBackend {
|
|
63
|
+
selection;
|
|
64
|
+
label;
|
|
65
|
+
constructor(selection) {
|
|
66
|
+
this.selection = selection;
|
|
67
|
+
this.label = selectionLabel(selection);
|
|
68
|
+
}
|
|
69
|
+
async complete(request) {
|
|
70
|
+
if (this.selection.kind === 'anthropic')
|
|
71
|
+
return this.anthropic(request);
|
|
72
|
+
return this.openaiCompatible(request);
|
|
73
|
+
}
|
|
74
|
+
async anthropic(request) {
|
|
75
|
+
const key = process.env['ANTHROPIC_API_KEY'];
|
|
76
|
+
if (!key)
|
|
77
|
+
throw new Error('ANTHROPIC_API_KEY is not set');
|
|
78
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: {
|
|
81
|
+
'content-type': 'application/json',
|
|
82
|
+
'x-api-key': key,
|
|
83
|
+
'anthropic-version': '2023-06-01',
|
|
84
|
+
},
|
|
85
|
+
body: JSON.stringify({
|
|
86
|
+
model: this.selection.model,
|
|
87
|
+
max_tokens: request.maxTokens,
|
|
88
|
+
system: request.system,
|
|
89
|
+
messages: [{ role: 'user', content: request.user }],
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`anthropic ${response.status}: ${(await response.text()).slice(0, 400)}`);
|
|
94
|
+
}
|
|
95
|
+
const body = (await response.json());
|
|
96
|
+
const text = (body.content ?? [])
|
|
97
|
+
.filter((block) => block.type === 'text')
|
|
98
|
+
.map((block) => block.text ?? '')
|
|
99
|
+
.join('');
|
|
100
|
+
return {
|
|
101
|
+
text,
|
|
102
|
+
...(body.usage?.input_tokens !== undefined ? { inputTokens: body.usage.input_tokens } : {}),
|
|
103
|
+
...(body.usage?.output_tokens !== undefined ? { outputTokens: body.usage.output_tokens } : {}),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async openaiCompatible(request) {
|
|
107
|
+
const selection = this.selection;
|
|
108
|
+
const base = selection.kind === 'compat'
|
|
109
|
+
? selection.baseUrl.replace(/\/$/, '')
|
|
110
|
+
: 'https://api.openai.com';
|
|
111
|
+
const key = selection.kind === 'compat'
|
|
112
|
+
? (process.env['CCOMPACTOR_API_KEY'] ?? '')
|
|
113
|
+
: (process.env['OPENAI_API_KEY'] ?? '');
|
|
114
|
+
const response = await fetch(`${base}/v1/chat/completions`, {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers: {
|
|
117
|
+
'content-type': 'application/json',
|
|
118
|
+
...(key ? { authorization: `Bearer ${key}` } : {}),
|
|
119
|
+
},
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
model: selection.model,
|
|
122
|
+
max_tokens: request.maxTokens,
|
|
123
|
+
temperature: 0,
|
|
124
|
+
messages: [
|
|
125
|
+
{ role: 'system', content: request.system },
|
|
126
|
+
{ role: 'user', content: request.user },
|
|
127
|
+
],
|
|
128
|
+
}),
|
|
129
|
+
});
|
|
130
|
+
if (!response.ok) {
|
|
131
|
+
throw new Error(`${selection.kind} ${response.status}: ${(await response.text()).slice(0, 400)}`);
|
|
132
|
+
}
|
|
133
|
+
const body = (await response.json());
|
|
134
|
+
return {
|
|
135
|
+
text: body.choices?.[0]?.message?.content ?? '',
|
|
136
|
+
...(body.usage?.prompt_tokens !== undefined ? { inputTokens: body.usage.prompt_tokens } : {}),
|
|
137
|
+
...(body.usage?.completion_tokens !== undefined
|
|
138
|
+
? { outputTokens: body.usage.completion_tokens }
|
|
139
|
+
: {}),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"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"}
|
package/dist/redact.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret redaction.
|
|
3
|
+
*
|
|
4
|
+
* A transcript is somebody's working session. It contains the API keys they
|
|
5
|
+
* pasted, the tokens their shell echoed back, and the contents of their `.env`.
|
|
6
|
+
* Two rules follow, and they are not negotiable:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Redact before anything leaves the process.** The LLM path and the rendered
|
|
9
|
+
* artifact both go through here. A redaction that runs after the request has
|
|
10
|
+
* been sent is a redaction that did not happen.
|
|
11
|
+
*
|
|
12
|
+
* 2. **Redact by shape, not by keyword.** A pattern list keyed on the word "key"
|
|
13
|
+
* catches `apiKey = "..."` and misses a bare 40-character token, which is the
|
|
14
|
+
* form that actually leaks. What follows matches the *shapes* secrets take.
|
|
15
|
+
*
|
|
16
|
+
* The replacement is a stable marker rather than a deletion: `[REDACTED:openai]`
|
|
17
|
+
* tells a reader that a value was here and what kind it was, so an artifact with
|
|
18
|
+
* a hole in it is diagnosable instead of merely wrong.
|
|
19
|
+
*/
|
|
20
|
+
interface Rule {
|
|
21
|
+
/** What to call it in the marker. */
|
|
22
|
+
kind: string;
|
|
23
|
+
pattern: RegExp;
|
|
24
|
+
/** Which capture group holds the secret. 0 means the whole match. */
|
|
25
|
+
group?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface RedactionReport {
|
|
28
|
+
text: string;
|
|
29
|
+
/** How many of each kind were replaced. */
|
|
30
|
+
counts: Record<string, number>;
|
|
31
|
+
total: number;
|
|
32
|
+
}
|
|
33
|
+
/** Replace every secret-shaped span in `text` with a named marker. */
|
|
34
|
+
export declare function redact(text: string, rules?: Rule[]): RedactionReport;
|
|
35
|
+
/** Redact every string field of a record, leaving structure intact. */
|
|
36
|
+
export declare function redactValue<T>(value: T): T;
|
|
37
|
+
/** Total secrets replaced, for the artifact header. */
|
|
38
|
+
export declare function summarize(counts: Record<string, number>): string;
|
|
39
|
+
export {};
|
package/dist/redact.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret redaction.
|
|
3
|
+
*
|
|
4
|
+
* A transcript is somebody's working session. It contains the API keys they
|
|
5
|
+
* pasted, the tokens their shell echoed back, and the contents of their `.env`.
|
|
6
|
+
* Two rules follow, and they are not negotiable:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Redact before anything leaves the process.** The LLM path and the rendered
|
|
9
|
+
* artifact both go through here. A redaction that runs after the request has
|
|
10
|
+
* been sent is a redaction that did not happen.
|
|
11
|
+
*
|
|
12
|
+
* 2. **Redact by shape, not by keyword.** A pattern list keyed on the word "key"
|
|
13
|
+
* catches `apiKey = "..."` and misses a bare 40-character token, which is the
|
|
14
|
+
* form that actually leaks. What follows matches the *shapes* secrets take.
|
|
15
|
+
*
|
|
16
|
+
* The replacement is a stable marker rather than a deletion: `[REDACTED:openai]`
|
|
17
|
+
* tells a reader that a value was here and what kind it was, so an artifact with
|
|
18
|
+
* a hole in it is diagnosable instead of merely wrong.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Ordered most specific first. An Anthropic key would also match the generic
|
|
22
|
+
* long-token rule, and naming it correctly is what makes the marker useful.
|
|
23
|
+
*/
|
|
24
|
+
const RULES = [
|
|
25
|
+
{ kind: 'private-key', pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g },
|
|
26
|
+
{ kind: 'anthropic', pattern: /sk-ant-[A-Za-z0-9_-]{16,}/g },
|
|
27
|
+
{ kind: 'openai', pattern: /sk-(?:proj-)?[A-Za-z0-9_-]{20,}/g },
|
|
28
|
+
{ kind: 'github-pat', pattern: /gh[pousr]_[A-Za-z0-9]{20,}/g },
|
|
29
|
+
{ kind: 'aws-key-id', pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g },
|
|
30
|
+
{
|
|
31
|
+
kind: 'aws-secret',
|
|
32
|
+
pattern: /aws_secret_access_key\s*[=:]\s*["']?([A-Za-z0-9/+=]{40})["']?/gi,
|
|
33
|
+
group: 1,
|
|
34
|
+
},
|
|
35
|
+
{ kind: 'google-api', pattern: /AIza[0-9A-Za-z_-]{35}/g },
|
|
36
|
+
{ kind: 'slack', pattern: /xox[abprs]-[A-Za-z0-9-]{10,}/g },
|
|
37
|
+
{ kind: 'npm-token', pattern: /npm_[A-Za-z0-9]{36}/g },
|
|
38
|
+
{ kind: 'pypi-token', pattern: /pypi-[A-Za-z0-9_-]{50,}/g },
|
|
39
|
+
{ kind: 'jwt', pattern: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g },
|
|
40
|
+
{ kind: 'bearer', pattern: /\bBearer\s+([A-Za-z0-9\-._~+/]{20,}=*)/g, group: 1 },
|
|
41
|
+
{
|
|
42
|
+
kind: 'assignment',
|
|
43
|
+
pattern: /\b(?:api[_-]?key|apikey|secret|password|passwd|token|access[_-]?token|client[_-]?secret)\b\s*[=:]\s*["']([^"'\s]{12,})["']/gi,
|
|
44
|
+
group: 1,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
kind: 'env-line',
|
|
48
|
+
pattern: /^([A-Z][A-Z0-9_]{2,}(?:_KEY|_TOKEN|_SECRET|_PASSWORD|_PASSWD))\s*=\s*(.{12,})$/gm,
|
|
49
|
+
group: 2,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Internal placeholders, swapped for the readable marker at the very end.
|
|
54
|
+
*
|
|
55
|
+
* Rules run in sequence, so a marker written by an earlier rule is text that a
|
|
56
|
+
* later rule can match. It did: `OPENAI_API_KEY=sk-proj-…` became
|
|
57
|
+
* `OPENAI_API_KEY=[REDACTED:openai]`, and the env-line rule then redacted the
|
|
58
|
+
* marker, reporting the key under the wrong name. A NUL-delimited sentinel
|
|
59
|
+
* cannot be produced by any rule, so nothing downstream can see it.
|
|
60
|
+
*/
|
|
61
|
+
const SENTINEL = '\u0000';
|
|
62
|
+
/** Replace every secret-shaped span in `text` with a named marker. */
|
|
63
|
+
export function redact(text, rules = RULES) {
|
|
64
|
+
const counts = {};
|
|
65
|
+
let out = text;
|
|
66
|
+
for (const rule of rules) {
|
|
67
|
+
out = out.replace(rule.pattern, (match, ...args) => {
|
|
68
|
+
const captured = rule.group ? args[rule.group - 1] : match;
|
|
69
|
+
if (captured === undefined)
|
|
70
|
+
return match;
|
|
71
|
+
counts[rule.kind] = (counts[rule.kind] ?? 0) + 1;
|
|
72
|
+
const marker = `${SENTINEL}${rule.kind}${SENTINEL}`;
|
|
73
|
+
// Only the captured span is replaced, so the surrounding syntax — a
|
|
74
|
+
// variable name, a header prefix — survives for the reader.
|
|
75
|
+
return rule.group ? match.replace(captured, marker) : marker;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const finished = out.replace(new RegExp(`${SENTINEL}([a-z-]+)${SENTINEL}`, 'g'), (_match, kind) => `[REDACTED:${kind}]`);
|
|
79
|
+
return { text: finished, counts, total: Object.values(counts).reduce((a, b) => a + b, 0) };
|
|
80
|
+
}
|
|
81
|
+
/** Redact every string field of a record, leaving structure intact. */
|
|
82
|
+
export function redactValue(value) {
|
|
83
|
+
if (typeof value === 'string')
|
|
84
|
+
return redact(value).text;
|
|
85
|
+
if (Array.isArray(value))
|
|
86
|
+
return value.map((item) => redactValue(item));
|
|
87
|
+
if (typeof value === 'object' && value !== null) {
|
|
88
|
+
const out = {};
|
|
89
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
90
|
+
// The key itself can be a secret: an env dump keys the token.
|
|
91
|
+
out[redact(key).text] = redactValue(entry);
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
/** Total secrets replaced, for the artifact header. */
|
|
98
|
+
export function summarize(counts) {
|
|
99
|
+
const entries = Object.entries(counts).sort((a, b) => b[1] - a[1]);
|
|
100
|
+
if (entries.length === 0)
|
|
101
|
+
return 'none';
|
|
102
|
+
return entries.map(([kind, count]) => `${kind}×${count}`).join(' ');
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
|