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
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AgentKind, SessionIR, SessionRef } from '../ir/types.js';
|
|
2
|
+
export interface DiscoverOptions {
|
|
3
|
+
project?: string;
|
|
4
|
+
anyProject?: boolean;
|
|
5
|
+
agents?: AgentKind[];
|
|
6
|
+
}
|
|
7
|
+
/** Every session every adapter can see, newest first. */
|
|
8
|
+
export declare function listSessions(options?: DiscoverOptions): Promise<SessionRef[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Turn a reference into exactly one session, or explain why it is not exactly
|
|
11
|
+
* one. A prefix that matches several sessions is a question for the human, not
|
|
12
|
+
* something to guess at — the wrong session means a handoff for the wrong work.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveSession(reference: string, options?: DiscoverOptions): Promise<SessionRef>;
|
|
15
|
+
export declare class AmbiguousError extends Error {
|
|
16
|
+
readonly reference: string;
|
|
17
|
+
readonly candidates: SessionRef[];
|
|
18
|
+
readonly exitCode = 3;
|
|
19
|
+
constructor(reference: string, candidates: SessionRef[]);
|
|
20
|
+
}
|
|
21
|
+
/** Read a resolved session into the canonical IR. */
|
|
22
|
+
export declare function readSession(ref: SessionRef, options?: {
|
|
23
|
+
includeSidechains?: boolean;
|
|
24
|
+
}): Promise<SessionIR>;
|
|
25
|
+
/**
|
|
26
|
+
* Subsequence scoring, highest first.
|
|
27
|
+
*
|
|
28
|
+
* A dependency-free fuzzy matcher: every character of the query must appear in
|
|
29
|
+
* order, and consecutive matches and matches at word boundaries score higher.
|
|
30
|
+
* It is enough to find a session by a fragment of its first message, which is
|
|
31
|
+
* the only search anyone actually performs here.
|
|
32
|
+
*/
|
|
33
|
+
export declare function fuzzyScore(query: string, target: string): number;
|
|
34
|
+
/** Search sessions by anything cheaply knowable, without parsing them fully. */
|
|
35
|
+
export declare function findSessions(query: string, options?: DiscoverOptions): Promise<Array<{
|
|
36
|
+
ref: SessionRef;
|
|
37
|
+
score: number;
|
|
38
|
+
snippet?: string;
|
|
39
|
+
}>>;
|
|
40
|
+
export { parseReference, UsageError } from './reference.js';
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { adapters } from '../adapters/index.js';
|
|
2
|
+
import { parseReference, UsageError } from './reference.js';
|
|
3
|
+
/** Every session every adapter can see, newest first. */
|
|
4
|
+
export async function listSessions(options = {}) {
|
|
5
|
+
const chosen = adapters().filter((a) => !options.agents || options.agents.includes(a.kind));
|
|
6
|
+
const all = [];
|
|
7
|
+
for (const adapter of chosen) {
|
|
8
|
+
if (!adapter.available())
|
|
9
|
+
continue;
|
|
10
|
+
const refs = await adapter.list({
|
|
11
|
+
...(options.project ? { project: options.project } : {}),
|
|
12
|
+
...(options.anyProject ? { anyProject: options.anyProject } : {}),
|
|
13
|
+
});
|
|
14
|
+
all.push(...refs);
|
|
15
|
+
}
|
|
16
|
+
return all.sort((a, b) => b.mtime - a.mtime);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Turn a reference into exactly one session, or explain why it is not exactly
|
|
20
|
+
* one. A prefix that matches several sessions is a question for the human, not
|
|
21
|
+
* something to guess at — the wrong session means a handoff for the wrong work.
|
|
22
|
+
*/
|
|
23
|
+
export async function resolveSession(reference, options = {}) {
|
|
24
|
+
const parsed = parseReference(reference);
|
|
25
|
+
if (parsed.path) {
|
|
26
|
+
return {
|
|
27
|
+
agent: parsed.agent ?? 'generic',
|
|
28
|
+
id: parsed.selector,
|
|
29
|
+
path: parsed.path,
|
|
30
|
+
mtime: Date.now(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const candidates = (await listSessions(options)).filter((ref) => !parsed.agent || ref.agent === parsed.agent);
|
|
34
|
+
if (candidates.length === 0) {
|
|
35
|
+
throw new UsageError(`no sessions found${parsed.agent ? ` for ${parsed.agent}` : ''}. Run \`ccompactor doctor\`.`);
|
|
36
|
+
}
|
|
37
|
+
if (parsed.selector === 'last')
|
|
38
|
+
return candidates[0];
|
|
39
|
+
const exact = candidates.find((ref) => ref.id === parsed.selector);
|
|
40
|
+
if (exact)
|
|
41
|
+
return exact;
|
|
42
|
+
const matches = candidates.filter((ref) => ref.id.startsWith(parsed.selector));
|
|
43
|
+
if (matches.length === 0) {
|
|
44
|
+
throw new UsageError(`no session matches \`${parsed.selector}\``);
|
|
45
|
+
}
|
|
46
|
+
if (matches.length > 1) {
|
|
47
|
+
throw new AmbiguousError(parsed.selector, matches);
|
|
48
|
+
}
|
|
49
|
+
return matches[0];
|
|
50
|
+
}
|
|
51
|
+
export class AmbiguousError extends Error {
|
|
52
|
+
reference;
|
|
53
|
+
candidates;
|
|
54
|
+
exitCode = 3;
|
|
55
|
+
constructor(reference, candidates) {
|
|
56
|
+
super(`\`${reference}\` matched ${candidates.length} sessions`);
|
|
57
|
+
this.reference = reference;
|
|
58
|
+
this.candidates = candidates;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Read a resolved session into the canonical IR. */
|
|
62
|
+
export async function readSession(ref, options = {}) {
|
|
63
|
+
const adapter = adapters().find((a) => a.kind === ref.agent);
|
|
64
|
+
if (!adapter) {
|
|
65
|
+
throw new UsageError(`no adapter for agent \`${ref.agent}\``);
|
|
66
|
+
}
|
|
67
|
+
return adapter.read(ref, options);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Subsequence scoring, highest first.
|
|
71
|
+
*
|
|
72
|
+
* A dependency-free fuzzy matcher: every character of the query must appear in
|
|
73
|
+
* order, and consecutive matches and matches at word boundaries score higher.
|
|
74
|
+
* It is enough to find a session by a fragment of its first message, which is
|
|
75
|
+
* the only search anyone actually performs here.
|
|
76
|
+
*/
|
|
77
|
+
export function fuzzyScore(query, target) {
|
|
78
|
+
if (query.length === 0)
|
|
79
|
+
return 1;
|
|
80
|
+
const q = query.toLowerCase();
|
|
81
|
+
const t = target.toLowerCase();
|
|
82
|
+
let score = 0;
|
|
83
|
+
let cursor = 0;
|
|
84
|
+
let streak = 0;
|
|
85
|
+
for (const char of q) {
|
|
86
|
+
const found = t.indexOf(char, cursor);
|
|
87
|
+
if (found === -1)
|
|
88
|
+
return 0;
|
|
89
|
+
streak = found === cursor ? streak + 1 : 0;
|
|
90
|
+
score += 1 + streak;
|
|
91
|
+
// A match right after a separator is the start of a word, which is what
|
|
92
|
+
// someone typing an abbreviation means.
|
|
93
|
+
if (found === 0 || /[\s/_.:-]/.test(t[found - 1] ?? ''))
|
|
94
|
+
score += 2;
|
|
95
|
+
cursor = found + 1;
|
|
96
|
+
}
|
|
97
|
+
return score;
|
|
98
|
+
}
|
|
99
|
+
/** Search sessions by anything cheaply knowable, without parsing them fully. */
|
|
100
|
+
export async function findSessions(query, options = {}) {
|
|
101
|
+
const refs = await listSessions(options);
|
|
102
|
+
const hits = [];
|
|
103
|
+
for (const ref of refs) {
|
|
104
|
+
const haystack = [ref.id, ref.title ?? '', ref.projectPath ?? '', ref.path].join(' ');
|
|
105
|
+
let score = fuzzyScore(query, haystack);
|
|
106
|
+
// The first human turn is the session's real title far more often than
|
|
107
|
+
// anything the provider recorded, so it is worth a header read.
|
|
108
|
+
if (score === 0 && ref.bytes !== undefined && ref.bytes < 64 * 1024 * 1024) {
|
|
109
|
+
const snippet = await firstHumanTurn(ref);
|
|
110
|
+
if (snippet) {
|
|
111
|
+
const snippetScore = fuzzyScore(query, snippet);
|
|
112
|
+
if (snippetScore > 0) {
|
|
113
|
+
hits.push({ ref, score: snippetScore, snippet });
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (score > 0)
|
|
119
|
+
hits.push({ ref, score });
|
|
120
|
+
}
|
|
121
|
+
return hits.sort((a, b) => b.score - a.score || b.ref.mtime - a.ref.mtime);
|
|
122
|
+
}
|
|
123
|
+
async function firstHumanTurn(ref) {
|
|
124
|
+
const { createReadStream } = await import('node:fs');
|
|
125
|
+
const { createInterface } = await import('node:readline');
|
|
126
|
+
const stream = createReadStream(ref.path, { encoding: 'utf8' });
|
|
127
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
128
|
+
try {
|
|
129
|
+
for await (const line of rl) {
|
|
130
|
+
try {
|
|
131
|
+
const raw = JSON.parse(line);
|
|
132
|
+
if (raw.type !== 'user' || raw.isMeta)
|
|
133
|
+
continue;
|
|
134
|
+
const text = plainText(raw.message?.content);
|
|
135
|
+
if (text && text.trim().length > 0)
|
|
136
|
+
return text.slice(0, 400);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
rl.close();
|
|
145
|
+
stream.close();
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
function plainText(content) {
|
|
150
|
+
if (typeof content === 'string')
|
|
151
|
+
return content;
|
|
152
|
+
if (!Array.isArray(content))
|
|
153
|
+
return undefined;
|
|
154
|
+
for (const block of content) {
|
|
155
|
+
if (typeof block === 'object' && block !== null) {
|
|
156
|
+
const b = block;
|
|
157
|
+
if (b['type'] === 'text' && typeof b['text'] === 'string')
|
|
158
|
+
return b['text'];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
export { parseReference, UsageError } from './reference.js';
|
|
164
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/discover/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AgentKind } from '../ir/types.js';
|
|
2
|
+
export interface ParsedReference {
|
|
3
|
+
/** Undefined when the reference did not name an agent. */
|
|
4
|
+
agent?: AgentKind;
|
|
5
|
+
/** A session id, an id prefix, or `last`. */
|
|
6
|
+
selector: string;
|
|
7
|
+
/** Set when the reference was a filesystem path rather than a store lookup. */
|
|
8
|
+
path?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parse a session reference.
|
|
12
|
+
*
|
|
13
|
+
* Accepts `claude:7c1e8f82`, `codex:last`, a bare `last`, and a path to a
|
|
14
|
+
* transcript on disk. A path is accepted because the answer to "which session"
|
|
15
|
+
* is often "this file", and refusing it would make the tool unusable in a
|
|
16
|
+
* script that already knows the path.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseReference(text: string): ParsedReference;
|
|
19
|
+
export declare class UsageError extends Error {
|
|
20
|
+
readonly exitCode = 2;
|
|
21
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
const KNOWN = ['claude', 'openclaude', 'codex', 'pi', 'opencode', 'deepseek', 'generic'];
|
|
3
|
+
/**
|
|
4
|
+
* Parse a session reference.
|
|
5
|
+
*
|
|
6
|
+
* Accepts `claude:7c1e8f82`, `codex:last`, a bare `last`, and a path to a
|
|
7
|
+
* transcript on disk. A path is accepted because the answer to "which session"
|
|
8
|
+
* is often "this file", and refusing it would make the tool unusable in a
|
|
9
|
+
* script that already knows the path.
|
|
10
|
+
*/
|
|
11
|
+
export function parseReference(text) {
|
|
12
|
+
const trimmed = text.trim();
|
|
13
|
+
if (trimmed.length === 0)
|
|
14
|
+
throw new UsageError('empty session reference');
|
|
15
|
+
if (trimmed.includes('/') || trimmed.endsWith('.jsonl') || trimmed.endsWith('.jsonl.zst')) {
|
|
16
|
+
return { agent: inferFromPath(trimmed), selector: basename(trimmed).replace(/\.jsonl(\.zst)?$/, ''), path: trimmed };
|
|
17
|
+
}
|
|
18
|
+
const colon = trimmed.indexOf(':');
|
|
19
|
+
if (colon === -1) {
|
|
20
|
+
return { selector: trimmed };
|
|
21
|
+
}
|
|
22
|
+
const head = trimmed.slice(0, colon);
|
|
23
|
+
const rest = trimmed.slice(colon + 1);
|
|
24
|
+
if (!KNOWN.includes(head)) {
|
|
25
|
+
throw new UsageError(`unknown agent \`${head}\` (expected one of ${KNOWN.join(', ')})`);
|
|
26
|
+
}
|
|
27
|
+
if (rest.length === 0)
|
|
28
|
+
throw new UsageError(`\`${trimmed}\` names an agent but no session`);
|
|
29
|
+
return { agent: head, selector: rest };
|
|
30
|
+
}
|
|
31
|
+
/** A path in a Claude store is a Claude session; anything else is a guess. */
|
|
32
|
+
function inferFromPath(path) {
|
|
33
|
+
if (path.includes('/.claude/'))
|
|
34
|
+
return 'claude';
|
|
35
|
+
if (path.includes('/.codex/'))
|
|
36
|
+
return 'codex';
|
|
37
|
+
if (path.includes('/.pi/'))
|
|
38
|
+
return 'pi';
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
export class UsageError extends Error {
|
|
42
|
+
exitCode = 2;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../../src/discover/reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAYpC,MAAM,KAAK,GAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC,CAAA;AAErG;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAC3B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,yBAAyB,CAAC,CAAA;IAEzE,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC1F,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;IACtH,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAClC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;IAC9B,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAA;IACrC,IAAI,CAAE,KAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,UAAU,CAClB,mBAAmB,IAAI,uBAAuB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAClE,CAAA;IACH,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,KAAK,OAAO,kCAAkC,CAAC,CAAA;IAC3F,OAAO,EAAE,KAAK,EAAE,IAAiB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;AACrD,CAAC;AAED,8EAA8E;AAC9E,SAAS,aAAa,CAAC,IAAY;IACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAAE,OAAO,QAAQ,CAAA;IAC/C,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,OAAO,CAAA;IAC7C,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAA;IACvC,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,QAAQ,GAAG,CAAC,CAAA;CACtB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SessionRef } from './ir/types.js';
|
|
2
|
+
import { type DiscoverOptions } from './discover/index.js';
|
|
3
|
+
import { type Ledgers } from './ledgers/index.js';
|
|
4
|
+
import { type Constraint } from './triage.js';
|
|
5
|
+
import { type Rendered } from './artifact/render.js';
|
|
6
|
+
import { type Selection } from './llm/index.js';
|
|
7
|
+
export interface ExtractOptions extends DiscoverOptions {
|
|
8
|
+
outDir?: string;
|
|
9
|
+
llm?: Selection;
|
|
10
|
+
focus?: string;
|
|
11
|
+
instructions?: string;
|
|
12
|
+
/** Write nothing; return what would be written. */
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface Extraction {
|
|
16
|
+
ref: SessionRef;
|
|
17
|
+
ledgers: Ledgers;
|
|
18
|
+
constraints: Constraint[];
|
|
19
|
+
rendered: Rendered;
|
|
20
|
+
engine: string;
|
|
21
|
+
llm: string;
|
|
22
|
+
/** Absolute paths written, empty on a dry run. */
|
|
23
|
+
written: string[];
|
|
24
|
+
elapsedMs: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function extractSession(reference: string, options?: ExtractOptions, progress?: (stage: string, message: string) => void): Promise<Extraction>;
|
package/dist/extract.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The extraction pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately a straight line: resolve, read, ledger, triage, optionally
|
|
5
|
+
* summarise, render, write. Each stage is a pure function over the previous
|
|
6
|
+
* one's output, so the whole thing is testable without a filesystem, a network,
|
|
7
|
+
* or a terminal.
|
|
8
|
+
*/
|
|
9
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { readSession, resolveSession } from './discover/index.js';
|
|
12
|
+
import { buildLedgers } from './ledgers/index.js';
|
|
13
|
+
import { extractConstraints } from './triage.js';
|
|
14
|
+
import { render } from './artifact/render.js';
|
|
15
|
+
import { build, resolveAuto, selectionLabel } from './llm/index.js';
|
|
16
|
+
import { summarise } from './compact/engine.js';
|
|
17
|
+
import { redact, summarize } from './redact.js';
|
|
18
|
+
export async function extractSession(reference, options = {}, progress = () => { }) {
|
|
19
|
+
const started = Date.now();
|
|
20
|
+
const ref = await resolveSession(reference, options);
|
|
21
|
+
progress('resolve', `${ref.agent}:${ref.id} → ${ref.path}`);
|
|
22
|
+
const ir = await readSession(ref, { includeSidechains: false });
|
|
23
|
+
progress('parse', `${ir.messages.length} message(s), ${ir.compactBoundaries.length} compact boundary(ies), ${ir.diagnostics.length} diagnostic(s)`);
|
|
24
|
+
const ledgers = buildLedgers(ir);
|
|
25
|
+
progress('ledgers', `${ledgers.files.length} files, ${ledgers.commands.length} commands, ${ledgers.errors.length} error signatures`);
|
|
26
|
+
const constraints = extractConstraints(ir);
|
|
27
|
+
progress('triage', `${constraints.length} standing instruction(s)`);
|
|
28
|
+
const selection = options.llm ?? resolveAuto();
|
|
29
|
+
let summary;
|
|
30
|
+
let engine = 'deterministic';
|
|
31
|
+
if (selection.kind !== 'none') {
|
|
32
|
+
const backend = build(selection);
|
|
33
|
+
if (backend) {
|
|
34
|
+
progress('summary', `asking ${selectionLabel(selection)} for the continuation summary`);
|
|
35
|
+
const produced = await summarise({ ir, ledgers, constraints }, backend, options);
|
|
36
|
+
summary = produced;
|
|
37
|
+
engine = selectionLabel(selection);
|
|
38
|
+
progress('summary', `${produced.length} characters returned`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
progress('summary', 'skipped: --llm none. The deterministic artifact is still complete.');
|
|
43
|
+
}
|
|
44
|
+
const compactInput = {};
|
|
45
|
+
const rendered = render({
|
|
46
|
+
ir,
|
|
47
|
+
ledgers,
|
|
48
|
+
constraints,
|
|
49
|
+
engine,
|
|
50
|
+
...(summary ? { summary } : {}),
|
|
51
|
+
...(options.focus ? { focus: options.focus } : {}),
|
|
52
|
+
});
|
|
53
|
+
// Redacted again on the way out. Two passes over the same text is not
|
|
54
|
+
// redundancy: the first stops a secret reaching a provider, the second stops
|
|
55
|
+
// one reaching the disk, and they fail independently.
|
|
56
|
+
const markdown = redact(rendered.markdown);
|
|
57
|
+
const json = JSON.parse(redact(JSON.stringify(rendered.json)).text);
|
|
58
|
+
rendered.markdown = markdown.text;
|
|
59
|
+
rendered.json = json;
|
|
60
|
+
const redactionCounts = { ...markdown.counts, ...(compactInput.redactionCounts ?? {}) };
|
|
61
|
+
if (Object.keys(redactionCounts).length > 0) {
|
|
62
|
+
rendered.json['redaction'] = { counts: redactionCounts, summary: summarize(redactionCounts) };
|
|
63
|
+
progress('redact', `replaced ${summarize(redactionCounts)}`);
|
|
64
|
+
}
|
|
65
|
+
const written = [];
|
|
66
|
+
if (!options.dryRun) {
|
|
67
|
+
const outDir = options.outDir ?? '.ccompactor';
|
|
68
|
+
await mkdir(outDir, { recursive: true });
|
|
69
|
+
const write = async (name, body) => {
|
|
70
|
+
const path = join(outDir, name);
|
|
71
|
+
await writeFile(path, body, 'utf8');
|
|
72
|
+
written.push(path);
|
|
73
|
+
};
|
|
74
|
+
await write('handoff.md', rendered.markdown);
|
|
75
|
+
await write('handoff.json', `${JSON.stringify(rendered.json, null, 2)}\n`);
|
|
76
|
+
await write('ledgers.json', `${JSON.stringify(ledgers, null, 2)}\n`);
|
|
77
|
+
await write('provenance.json', `${JSON.stringify({
|
|
78
|
+
schema: 'ccompactor.provenance/v1',
|
|
79
|
+
source: ref.path,
|
|
80
|
+
events: ir.messages.length,
|
|
81
|
+
constraints: constraints.map((c) => ({ evt: c.evt, text: c.text })),
|
|
82
|
+
}, null, 2)}\n`);
|
|
83
|
+
await write('state.json', `${JSON.stringify({
|
|
84
|
+
schema: 'ccompactor.state/v1',
|
|
85
|
+
engine,
|
|
86
|
+
constraintsFound: constraints.length,
|
|
87
|
+
redaction: redactionCounts,
|
|
88
|
+
diagnostics: ir.diagnostics,
|
|
89
|
+
}, null, 2)}\n`);
|
|
90
|
+
progress('write', written.join(', '));
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
ref,
|
|
94
|
+
ledgers,
|
|
95
|
+
constraints,
|
|
96
|
+
rendered,
|
|
97
|
+
engine,
|
|
98
|
+
llm: selectionLabel(selection),
|
|
99
|
+
written,
|
|
100
|
+
elapsedMs: Date.now() - started,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type Target = 'claude' | 'openclaude' | 'codex' | 'pi' | 'generic';
|
|
2
|
+
export interface Launch {
|
|
3
|
+
target: Target;
|
|
4
|
+
program: string;
|
|
5
|
+
argv: string[];
|
|
6
|
+
/** What to tell the human when the target cannot take a file directly. */
|
|
7
|
+
note?: string;
|
|
8
|
+
display: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function plan(target: Target, artifactPath: string, cwd: string): Launch;
|
|
11
|
+
/** Which targets actually exist on this machine. */
|
|
12
|
+
export declare function installed(): Target[];
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Launching a target agent with the handoff preloaded.
|
|
3
|
+
*
|
|
4
|
+
* The mechanism is an instruction plus a file path, never an injection into
|
|
5
|
+
* another tool's database. Flags here were verified against installed versions
|
|
6
|
+
* rather than assumed, because a wrong flag is a spawn that silently drops the
|
|
7
|
+
* context — the one failure this command exists to prevent.
|
|
8
|
+
*
|
|
9
|
+
* Verified: claude 2.1.268 `--append-system-prompt-file`, pi 0.85.1
|
|
10
|
+
* `--append-system-prompt`. Codex has no equivalent, so it gets a pointer and
|
|
11
|
+
* the instruction to read it first.
|
|
12
|
+
*/
|
|
13
|
+
import { resolve } from 'node:path';
|
|
14
|
+
import * as childProcess from 'node:child_process';
|
|
15
|
+
export function plan(target, artifactPath, cwd) {
|
|
16
|
+
const path = resolve(artifactPath);
|
|
17
|
+
const instruction = `Read ${path} first. It is a handoff from an earlier session on this project; build on that work rather than re-deriving it, and treat its "Hard constraints" as binding.`;
|
|
18
|
+
switch (target) {
|
|
19
|
+
case 'claude':
|
|
20
|
+
case 'openclaude':
|
|
21
|
+
return {
|
|
22
|
+
target,
|
|
23
|
+
program: target === 'claude' ? 'claude' : 'openclaude',
|
|
24
|
+
argv: ['--append-system-prompt-file', path],
|
|
25
|
+
display: `${target} --append-system-prompt-file ${path}`,
|
|
26
|
+
};
|
|
27
|
+
case 'pi':
|
|
28
|
+
return {
|
|
29
|
+
target,
|
|
30
|
+
program: 'pi',
|
|
31
|
+
argv: ['--append-system-prompt', path],
|
|
32
|
+
display: `pi --append-system-prompt ${path}`,
|
|
33
|
+
};
|
|
34
|
+
case 'codex':
|
|
35
|
+
return {
|
|
36
|
+
target,
|
|
37
|
+
program: 'codex',
|
|
38
|
+
argv: [instruction],
|
|
39
|
+
note: 'codex has no --append-system-prompt; it is given the instruction as its opening prompt',
|
|
40
|
+
display: `codex "${instruction}"`,
|
|
41
|
+
};
|
|
42
|
+
default:
|
|
43
|
+
return {
|
|
44
|
+
target: 'generic',
|
|
45
|
+
program: '',
|
|
46
|
+
argv: [],
|
|
47
|
+
note: instruction,
|
|
48
|
+
display: instruction,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Which targets actually exist on this machine. */
|
|
53
|
+
export function installed() {
|
|
54
|
+
const { execFileSync } = childProcess;
|
|
55
|
+
const found = [];
|
|
56
|
+
for (const target of ['claude', 'codex', 'pi']) {
|
|
57
|
+
try {
|
|
58
|
+
execFileSync('which', [target], { stdio: 'ignore' });
|
|
59
|
+
found.push(target);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return found;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handoff/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAA;AAalD,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,YAAoB,EAAE,GAAW;IACpE,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAClC,MAAM,WAAW,GAAG,QAAQ,IAAI,8JAA8J,CAAA;IAE9L,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ,CAAC;QACd,KAAK,YAAY;YACf,OAAO;gBACL,MAAM;gBACN,OAAO,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY;gBACtD,IAAI,EAAE,CAAC,6BAA6B,EAAE,IAAI,CAAC;gBAC3C,OAAO,EAAE,GAAG,MAAM,gCAAgC,IAAI,EAAE;aACzD,CAAA;QACH,KAAK,IAAI;YACP,OAAO;gBACL,MAAM;gBACN,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,CAAC,wBAAwB,EAAE,IAAI,CAAC;gBACtC,OAAO,EAAE,6BAA6B,IAAI,EAAE;aAC7C,CAAA;QACH,KAAK,OAAO;YACV,OAAO;gBACL,MAAM;gBACN,OAAO,EAAE,OAAO;gBAChB,IAAI,EAAE,CAAC,WAAW,CAAC;gBACnB,IAAI,EAAE,wFAAwF;gBAC9F,OAAO,EAAE,UAAU,WAAW,GAAG;aAClC,CAAA;QACH;YACE,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,EAAE;gBACX,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,WAAW;aACrB,CAAA;IACL,CAAC;AACH,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,SAAS;IACvB,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,CAAA;IACrC,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,MAAM,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAU,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,YAAY,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;YACpD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token estimation.
|
|
3
|
+
*
|
|
4
|
+
* Four bytes per token, the same approximation sctxx uses and for the same
|
|
5
|
+
* reason: every budget in the tool is an order-of-magnitude decision, and a
|
|
6
|
+
* tokeniser dependency costs more than it improves that. It is stated as an
|
|
7
|
+
* estimate everywhere it is shown, never as a measurement.
|
|
8
|
+
*/
|
|
9
|
+
export declare function approxTokens(text: string): number;
|
|
10
|
+
export declare function approxBytes(tokens: number): number;
|
|
11
|
+
/** Middle-truncate to a token budget, keeping a head and a tail. */
|
|
12
|
+
export declare function truncateMiddle(text: string, maxTokens: number, marker?: string): string;
|
|
13
|
+
/** Hard-wrap a long line so a terminal can show a path without it vanishing. */
|
|
14
|
+
export declare function wrapHard(text: string, width: number): string[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token estimation.
|
|
3
|
+
*
|
|
4
|
+
* Four bytes per token, the same approximation sctxx uses and for the same
|
|
5
|
+
* reason: every budget in the tool is an order-of-magnitude decision, and a
|
|
6
|
+
* tokeniser dependency costs more than it improves that. It is stated as an
|
|
7
|
+
* estimate everywhere it is shown, never as a measurement.
|
|
8
|
+
*/
|
|
9
|
+
const BYTES_PER_TOKEN = 4;
|
|
10
|
+
export function approxTokens(text) {
|
|
11
|
+
return Math.ceil(text.length / BYTES_PER_TOKEN);
|
|
12
|
+
}
|
|
13
|
+
export function approxBytes(tokens) {
|
|
14
|
+
return tokens * BYTES_PER_TOKEN;
|
|
15
|
+
}
|
|
16
|
+
/** Middle-truncate to a token budget, keeping a head and a tail. */
|
|
17
|
+
export function truncateMiddle(text, maxTokens, marker = ' … ') {
|
|
18
|
+
const max = approxBytes(maxTokens);
|
|
19
|
+
if (text.length <= max)
|
|
20
|
+
return text;
|
|
21
|
+
if (max <= marker.length + 2)
|
|
22
|
+
return marker.trim();
|
|
23
|
+
const left = Math.floor((max - marker.length) / 2);
|
|
24
|
+
const right = max - marker.length - left;
|
|
25
|
+
return text.slice(0, left) + marker + text.slice(text.length - right);
|
|
26
|
+
}
|
|
27
|
+
/** Hard-wrap a long line so a terminal can show a path without it vanishing. */
|
|
28
|
+
export function wrapHard(text, width) {
|
|
29
|
+
if (width <= 0)
|
|
30
|
+
return [text];
|
|
31
|
+
const out = [];
|
|
32
|
+
for (let i = 0; i < text.length; i += width)
|
|
33
|
+
out.push(text.slice(i, i + width));
|
|
34
|
+
return out.length > 0 ? out : [''];
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/ir/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,eAAe,GAAG,CAAC,CAAA;AAEzB,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,MAAM,GAAG,eAAe,CAAA;AACjC,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,SAAiB,EAAE,MAAM,GAAG,KAAK;IAC5E,MAAM,GAAG,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;IAClC,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,IAAI,CAAA;IACnC,IAAI,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,IAAI,EAAE,CAAA;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IAClD,MAAM,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,IAAI,CAAA;IACxC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAA;AACvE,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,KAAa;IAClD,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7B,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,KAAK;QAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAA;IAC/E,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
export type AgentKind = 'claude' | 'openclaude' | 'codex' | 'pi' | 'opencode' | 'deepseek' | 'generic';
|
|
12
|
+
/** A session as discovered, before it is parsed. Cheap to produce. */
|
|
13
|
+
export interface SessionRef {
|
|
14
|
+
agent: AgentKind;
|
|
15
|
+
/** Native id: a uuid for Claude, a rollout id for Codex, a filename stem for Pi. */
|
|
16
|
+
id: string;
|
|
17
|
+
/** Absolute path to the transcript on disk. */
|
|
18
|
+
path: string;
|
|
19
|
+
/** The project the session belongs to, when the store encodes one. */
|
|
20
|
+
projectPath?: string;
|
|
21
|
+
/** Modification time in epoch milliseconds. */
|
|
22
|
+
mtime: number;
|
|
23
|
+
/** Human label, when the format carries one. */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** Cheap size estimate, from stat or a head parse. */
|
|
26
|
+
bytes?: number;
|
|
27
|
+
eventCount?: number;
|
|
28
|
+
approxTokens?: number;
|
|
29
|
+
/** Session files that belong to this session but are not the main transcript. */
|
|
30
|
+
siblings?: string[];
|
|
31
|
+
}
|
|
32
|
+
export type Role = 'user' | 'assistant' | 'system' | 'tool' | 'attachment';
|
|
33
|
+
/** One normalised event. `eventIndex` is the provenance handle. */
|
|
34
|
+
export interface IRMessage {
|
|
35
|
+
/** Provider uuid when the format has one; otherwise synthesised from index. */
|
|
36
|
+
uuid: string;
|
|
37
|
+
parentUuid?: string;
|
|
38
|
+
role: Role;
|
|
39
|
+
timestamp?: string;
|
|
40
|
+
text?: string;
|
|
41
|
+
toolName?: string;
|
|
42
|
+
toolUseId?: string;
|
|
43
|
+
/** The tool's arguments. The ledgers are built from these, not from prose. */
|
|
44
|
+
toolInput?: unknown;
|
|
45
|
+
toolResult?: unknown;
|
|
46
|
+
/** Harness-injected rather than typed by the human. Never treated as intent. */
|
|
47
|
+
isMeta?: boolean;
|
|
48
|
+
/** True when the human actually typed this. The only source of user intent. */
|
|
49
|
+
isHumanTurn?: boolean;
|
|
50
|
+
/** Provider said this event failed. */
|
|
51
|
+
isError?: boolean;
|
|
52
|
+
/** The original parsed record, for `expand` and for provenance. */
|
|
53
|
+
raw?: unknown;
|
|
54
|
+
/** Stable index in the source transcript. Never reassigned. */
|
|
55
|
+
eventIndex: number;
|
|
56
|
+
}
|
|
57
|
+
export interface SessionIR {
|
|
58
|
+
ref: SessionRef;
|
|
59
|
+
messages: IRMessage[];
|
|
60
|
+
/** Event indices where the provider compacted. Everything before one is already summarised. */
|
|
61
|
+
compactBoundaries: number[];
|
|
62
|
+
/** Provider-reported facts worth carrying: cwd, branch, model, versions. */
|
|
63
|
+
metadata: Record<string, unknown>;
|
|
64
|
+
/** Malformed lines, so a bad adapter is diagnosable rather than silent. */
|
|
65
|
+
diagnostics: Diagnostic[];
|
|
66
|
+
}
|
|
67
|
+
export interface Diagnostic {
|
|
68
|
+
line: number;
|
|
69
|
+
message: string;
|
|
70
|
+
}
|
|
71
|
+
/** `evt 12` or `evt 12–19`. The artifact's only pointer syntax. */
|
|
72
|
+
export declare function evtLabel(from: number, to?: number): string;
|
|
73
|
+
/**
|
|
74
|
+
* The transcript content after the last compact boundary, plus everything when
|
|
75
|
+
* there is none. A provider compaction already summarised what came before, so
|
|
76
|
+
* re-reading it means summarising a summary.
|
|
77
|
+
*/
|
|
78
|
+
export declare function afterLastBoundary(ir: SessionIR): IRMessage[];
|
|
79
|
+
/** Events the human actually typed. Intent lives here and nowhere else. */
|
|
80
|
+
export declare function humanTurns(ir: SessionIR): IRMessage[];
|
|
81
|
+
/** Cwd recorded by the provider, if any. */
|
|
82
|
+
export declare function sessionCwd(ir: SessionIR): string | undefined;
|