@dungle-scrubs/harness-cli-normalizer 0.6.4 → 0.6.6
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 +28 -6
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +5 -2
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/inspect-context.js +4 -6
- package/dist/cli/inspect-context.js.map +1 -1
- package/dist/cli/inspect-session.js +1 -1
- package/dist/cli/inspect-session.js.map +1 -1
- package/dist/cli/inspect.d.ts.map +1 -1
- package/dist/cli/inspect.js +9 -2
- package/dist/cli/inspect.js.map +1 -1
- package/dist/cli/runtime-compatibility.d.ts +4 -3
- package/dist/cli/runtime-compatibility.d.ts.map +1 -1
- package/dist/cli/runtime-compatibility.js +4 -3
- package/dist/cli/runtime-compatibility.js.map +1 -1
- package/dist/execution/context-inspection.d.ts +1 -1
- package/dist/execution/context-inspection.d.ts.map +1 -1
- package/dist/execution/context-inspection.js +28 -30
- package/dist/execution/context-inspection.js.map +1 -1
- package/dist/execution/lines.d.ts +2 -1
- package/dist/execution/lines.d.ts.map +1 -1
- package/dist/execution/lines.js +4 -1
- package/dist/execution/lines.js.map +1 -1
- package/dist/interpretation/context-inspection.d.ts +8 -0
- package/dist/interpretation/context-inspection.d.ts.map +1 -1
- package/dist/interpretation/context-inspection.js +55 -5
- package/dist/interpretation/context-inspection.js.map +1 -1
- package/dist/knowledge/claude-code.d.ts.map +1 -1
- package/dist/knowledge/claude-code.js +5 -0
- package/dist/knowledge/claude-code.js.map +1 -1
- package/dist/knowledge/codex.d.ts +2 -3
- package/dist/knowledge/codex.d.ts.map +1 -1
- package/dist/knowledge/codex.js +11 -5
- package/dist/knowledge/codex.js.map +1 -1
- package/dist/knowledge/descriptor.d.ts +14 -1
- package/dist/knowledge/descriptor.d.ts.map +1 -1
- package/dist/knowledge/muse.d.ts.map +1 -1
- package/dist/knowledge/muse.js +1 -0
- package/dist/knowledge/muse.js.map +1 -1
- package/dist/knowledge/pi.d.ts.map +1 -1
- package/dist/knowledge/pi.js +1 -0
- package/dist/knowledge/pi.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/help.ts +5 -2
- package/src/cli/inspect-context.ts +4 -8
- package/src/cli/inspect-session.ts +1 -1
- package/src/cli/inspect.ts +10 -2
- package/src/cli/runtime-compatibility.ts +10 -4
- package/src/execution/context-inspection.ts +35 -30
- package/src/execution/lines.ts +5 -1
- package/src/interpretation/context-inspection.ts +73 -4
- package/src/knowledge/claude-code.ts +5 -0
- package/src/knowledge/codex.ts +11 -5
- package/src/knowledge/descriptor.ts +14 -1
- package/src/knowledge/muse.ts +1 -0
- package/src/knowledge/pi.ts +1 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { ContextInspection } from "../interpretation/context-inspection.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
createContextProbe,
|
|
4
|
+
settledContextInspection,
|
|
5
|
+
} from "../interpretation/context-inspection.js";
|
|
3
6
|
import { detectAuthFailureInLine, detectLimitInLine } from "../interpretation/limits.js";
|
|
4
7
|
import type { HarnessDescriptor } from "../knowledge/descriptor.js";
|
|
5
8
|
|
|
@@ -10,7 +13,7 @@ import { LineBuffer } from "./lines.js";
|
|
|
10
13
|
import { KILL_GRACE_MS, superviseTermination } from "./supervisor.js";
|
|
11
14
|
|
|
12
15
|
export interface ContextInspectionOptions {
|
|
13
|
-
/** Already validated,
|
|
16
|
+
/** Already validated, executable-bound ephemeral argv. The CLI adapter owns
|
|
14
17
|
* no-persistence and fork-on-resume enforcement before this layer runs. */
|
|
15
18
|
readonly argv: readonly string[];
|
|
16
19
|
readonly cwd?: string;
|
|
@@ -53,11 +56,14 @@ export async function inspectContext(
|
|
|
53
56
|
return { status: "unavailable", reason: "transport" };
|
|
54
57
|
}
|
|
55
58
|
let finished = false;
|
|
59
|
+
const outcome: { accounting: ContextInspection } = {
|
|
60
|
+
accounting: { status: "unavailable", reason: "transport" },
|
|
61
|
+
};
|
|
56
62
|
let exited = false;
|
|
57
63
|
let exitCode: number | null = null;
|
|
58
64
|
let nativeFailure: "auth" | "limit" | null = null;
|
|
59
65
|
let disposalTimer: TimerHandle | undefined;
|
|
60
|
-
const result = deferred<
|
|
66
|
+
const result = deferred<void>();
|
|
61
67
|
const stopped = deferred<boolean>();
|
|
62
68
|
const signal = (kind: "SIGTERM" | "SIGKILL"): void => {
|
|
63
69
|
try {
|
|
@@ -68,18 +74,17 @@ export async function inspectContext(
|
|
|
68
74
|
};
|
|
69
75
|
const termination = superviseTermination(deps.clock, signal);
|
|
70
76
|
const finish = (value: ContextInspection): void => {
|
|
77
|
+
if (!finished || (outcome.accounting.status === "available" && value.status === "unavailable"))
|
|
78
|
+
outcome.accounting = value;
|
|
71
79
|
if (finished) return;
|
|
72
80
|
finished = true;
|
|
73
|
-
result.resolve(
|
|
81
|
+
result.resolve();
|
|
74
82
|
try {
|
|
75
83
|
child.stdin?.end();
|
|
76
84
|
} catch {
|
|
77
85
|
/* A broken pipe still needs cleanup. */
|
|
78
86
|
}
|
|
79
|
-
if (exited)
|
|
80
|
-
stopped.resolve(true);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
87
|
+
if (exited) return;
|
|
83
88
|
termination.escalate();
|
|
84
89
|
disposalTimer = deps.clock.setTimeout(() => {
|
|
85
90
|
child.disposeOutput();
|
|
@@ -99,9 +104,9 @@ export async function inspectContext(
|
|
|
99
104
|
}
|
|
100
105
|
};
|
|
101
106
|
const onLine = (line: string): void => {
|
|
102
|
-
if (finished) return;
|
|
107
|
+
if (finished && outcome.accounting.status !== "available") return;
|
|
103
108
|
const action = probe.accept(line);
|
|
104
|
-
if (action?.kind === "send") write(action.line);
|
|
109
|
+
if (action?.kind === "send" && !finished) write(action.line);
|
|
105
110
|
else if (action?.kind === "complete") finish(action.accounting);
|
|
106
111
|
};
|
|
107
112
|
const deadline = deps.clock.setTimeout(
|
|
@@ -111,14 +116,16 @@ export async function inspectContext(
|
|
|
111
116
|
const abort = (): void => finish({ status: "unavailable", reason: "cancelled" });
|
|
112
117
|
options.signal?.addEventListener("abort", abort, { once: true });
|
|
113
118
|
const stdout = (async (): Promise<void> => {
|
|
114
|
-
const lines = new LineBuffer(CONTEXT_TRANSPORT_MAX + 65_536)
|
|
119
|
+
const lines = new LineBuffer(CONTEXT_TRANSPORT_MAX + 65_536, () =>
|
|
120
|
+
finish({ status: "unavailable", reason: "transport-limit" }),
|
|
121
|
+
);
|
|
115
122
|
try {
|
|
116
123
|
for await (const chunk of child.stdout) {
|
|
117
|
-
|
|
124
|
+
for (const line of lines.push(chunk)) onLine(line);
|
|
118
125
|
}
|
|
119
126
|
const tail = lines.flush();
|
|
120
127
|
if (tail !== null) onLine(tail);
|
|
121
|
-
finish({ status: "unavailable", reason: "transport" });
|
|
128
|
+
if (!finished) finish({ status: "unavailable", reason: "transport" });
|
|
122
129
|
} catch {
|
|
123
130
|
finish({ status: "unavailable", reason: "transport" });
|
|
124
131
|
}
|
|
@@ -142,36 +149,34 @@ export async function inspectContext(
|
|
|
142
149
|
void child.exited.then(async (code) => {
|
|
143
150
|
exited = true;
|
|
144
151
|
exitCode = code;
|
|
145
|
-
if (code !== null && code !== 0)
|
|
152
|
+
if (!finished && code !== null && code !== 0)
|
|
153
|
+
finish({ status: "unavailable", reason: "transport" });
|
|
146
154
|
termination.settle();
|
|
147
155
|
if (disposalTimer !== undefined) deps.clock.clearTimeout(disposalTimer);
|
|
148
156
|
// Exit can precede the final bytes reaching the runtime's read buffer.
|
|
149
157
|
// Drain naturally first; inherited pipes get a bounded disposal fallback.
|
|
150
158
|
let drainTimer: TimerHandle | undefined;
|
|
151
|
-
await Promise.race([
|
|
152
|
-
Promise.all([stdout, stderr]),
|
|
153
|
-
new Promise<
|
|
154
|
-
drainTimer = deps.clock.setTimeout(resolve, KILL_GRACE_MS);
|
|
159
|
+
const drained = await Promise.race([
|
|
160
|
+
Promise.all([stdout, stderr]).then(() => true),
|
|
161
|
+
new Promise<boolean>((resolve) => {
|
|
162
|
+
drainTimer = deps.clock.setTimeout(() => resolve(false), KILL_GRACE_MS);
|
|
155
163
|
}),
|
|
156
164
|
]);
|
|
157
165
|
if (drainTimer !== undefined) deps.clock.clearTimeout(drainTimer);
|
|
158
166
|
child.disposeOutput();
|
|
159
|
-
stopped.resolve(
|
|
167
|
+
stopped.resolve(drained);
|
|
160
168
|
});
|
|
161
169
|
write(probe.initial);
|
|
162
170
|
// Abort can arrive during spawn or listener registration.
|
|
163
171
|
if (options.signal?.aborted) abort();
|
|
164
|
-
|
|
172
|
+
await result.promise;
|
|
165
173
|
deps.clock.clearTimeout(deadline);
|
|
166
|
-
options.signal?.removeEventListener("abort", abort);
|
|
167
174
|
const clean = await stopped.promise;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
return value;
|
|
175
|
+
options.signal?.removeEventListener("abort", abort);
|
|
176
|
+
return settledContextInspection({
|
|
177
|
+
accounting: outcome.accounting,
|
|
178
|
+
clean,
|
|
179
|
+
exitCode,
|
|
180
|
+
nativeFailure,
|
|
181
|
+
});
|
|
177
182
|
}
|
package/src/execution/lines.ts
CHANGED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
export const LINE_MAX = 65_536;
|
|
12
12
|
|
|
13
13
|
export class LineBuffer {
|
|
14
|
-
constructor(
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly limit = LINE_MAX,
|
|
16
|
+
private readonly onOverflow?: () => void,
|
|
17
|
+
) {}
|
|
15
18
|
// Per-instance and stateful ({stream:true}): a shared decoder would carry
|
|
16
19
|
// partial-sequence state across two streams and corrupt both.
|
|
17
20
|
private readonly decoder = new TextDecoder();
|
|
@@ -44,6 +47,7 @@ export class LineBuffer {
|
|
|
44
47
|
if (this.pending.length + text.length > this.limit) {
|
|
45
48
|
this.pending = "";
|
|
46
49
|
this.discarding = true;
|
|
50
|
+
this.onOverflow?.();
|
|
47
51
|
} else this.pending += text;
|
|
48
52
|
}
|
|
49
53
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { HarnessDescriptor } from "../knowledge/descriptor.js";
|
|
2
2
|
import type { SpawnArgvOptions } from "./argv.js";
|
|
3
3
|
import { buildSpawnArgv } from "./argv.js";
|
|
4
|
+
import { contentEventsOf } from "./content.js";
|
|
4
5
|
import { ArgvRefusalError } from "./refusal.js";
|
|
5
6
|
import { asRecord } from "./shape.js";
|
|
6
7
|
|
|
@@ -16,7 +17,7 @@ export function buildContextInspectionArgv(
|
|
|
16
17
|
harness: harness.name,
|
|
17
18
|
issue: "invalid-option-value",
|
|
18
19
|
option: "context",
|
|
19
|
-
supported: ["
|
|
20
|
+
supported: ["supported native context adapter without native passthrough"],
|
|
20
21
|
});
|
|
21
22
|
}
|
|
22
23
|
return [
|
|
@@ -74,6 +75,32 @@ export type ContextInspection =
|
|
|
74
75
|
const positive = (value: unknown): value is number =>
|
|
75
76
|
typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
76
77
|
|
|
78
|
+
/** Cleanup and caller interruption take precedence. Otherwise a recognized
|
|
79
|
+
* native failure explains a failed exchange more precisely than its framing. */
|
|
80
|
+
export function settledContextInspection(facts: {
|
|
81
|
+
readonly accounting: ContextInspection;
|
|
82
|
+
readonly clean: boolean;
|
|
83
|
+
readonly exitCode: number | null;
|
|
84
|
+
readonly nativeFailure: "auth" | "limit" | null;
|
|
85
|
+
}): ContextInspection {
|
|
86
|
+
const { accounting, clean, exitCode, nativeFailure } = facts;
|
|
87
|
+
if (!clean) return { status: "unavailable", reason: "cleanup" };
|
|
88
|
+
if (
|
|
89
|
+
accounting.status === "unavailable" &&
|
|
90
|
+
(accounting.reason === "cancelled" || accounting.reason === "timeout")
|
|
91
|
+
)
|
|
92
|
+
return accounting;
|
|
93
|
+
if (nativeFailure !== null) return { status: "unavailable", reason: nativeFailure };
|
|
94
|
+
if (
|
|
95
|
+
accounting.status === "unavailable" &&
|
|
96
|
+
accounting.reason === "transport" &&
|
|
97
|
+
exitCode !== null &&
|
|
98
|
+
exitCode !== 0
|
|
99
|
+
)
|
|
100
|
+
return { status: "unavailable", reason: "native-exit" };
|
|
101
|
+
return accounting;
|
|
102
|
+
}
|
|
103
|
+
|
|
77
104
|
/** Normalize only a complete native response. A window alone says nothing
|
|
78
105
|
* about remaining capacity, and invalid compaction data must not increase it. */
|
|
79
106
|
export function contextInspectionOf(input: unknown): ContextInspection {
|
|
@@ -135,7 +162,6 @@ export function createContextProbe(inputId: string, prompt: string): ContextProb
|
|
|
135
162
|
initial: control(initializeId, { subtype: "initialize", hooks: null }),
|
|
136
163
|
staged,
|
|
137
164
|
accept(line) {
|
|
138
|
-
if (phase === "finished") return null;
|
|
139
165
|
let decoded: unknown;
|
|
140
166
|
try {
|
|
141
167
|
decoded = JSON.parse(line);
|
|
@@ -144,7 +170,46 @@ export function createContextProbe(inputId: string, prompt: string): ContextProb
|
|
|
144
170
|
return { kind: "complete", accounting: { status: "unavailable", reason: "protocol" } };
|
|
145
171
|
}
|
|
146
172
|
const frame = asRecord(decoded);
|
|
147
|
-
|
|
173
|
+
const failure = contentEventsOf("claude", decoded).find(
|
|
174
|
+
(event) => event.kind === "limit" || (event.kind === "error" && event.terminal),
|
|
175
|
+
);
|
|
176
|
+
if (failure) {
|
|
177
|
+
phase = "finished";
|
|
178
|
+
return {
|
|
179
|
+
kind: "complete",
|
|
180
|
+
accounting: {
|
|
181
|
+
status: "unavailable",
|
|
182
|
+
reason: failure.kind === "limit" ? "limit" : "native-exit",
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const content = asRecord(frame?.message)?.content;
|
|
187
|
+
const toolResult =
|
|
188
|
+
frame?.type === "user" &&
|
|
189
|
+
(frame.parent_tool_use_id != null ||
|
|
190
|
+
(Array.isArray(content) &&
|
|
191
|
+
content.some((block) => asRecord(block)?.type === "tool_result")));
|
|
192
|
+
const allowed =
|
|
193
|
+
frame !== null &&
|
|
194
|
+
!Array.isArray(decoded) &&
|
|
195
|
+
!toolResult &&
|
|
196
|
+
(frame.type === "user" ||
|
|
197
|
+
frame.type === "control_response" ||
|
|
198
|
+
frame.type === "command_lifecycle" ||
|
|
199
|
+
(frame.type === "system" &&
|
|
200
|
+
["init", "hook_started", "hook_progress", "hook_response"].includes(
|
|
201
|
+
String(frame.subtype),
|
|
202
|
+
)) ||
|
|
203
|
+
(frame.type === "result" && frame.subtype === "success" && frame.num_turns === 0) ||
|
|
204
|
+
(frame.type === "rate_limit_event" &&
|
|
205
|
+
["allowed", "allowed_warning"].includes(
|
|
206
|
+
String(asRecord(frame.rate_limit_info)?.status),
|
|
207
|
+
)));
|
|
208
|
+
if (!allowed || frame === null) {
|
|
209
|
+
phase = "finished";
|
|
210
|
+
return { kind: "complete", accounting: { status: "unavailable", reason: "protocol" } };
|
|
211
|
+
}
|
|
212
|
+
if (phase === "finished") return null;
|
|
148
213
|
if (phase === "ack" && frame.type === "user" && frame.uuid === inputId) {
|
|
149
214
|
phase = "usage";
|
|
150
215
|
return { kind: "send", line: control(usageId, { subtype: "get_context_usage" }) };
|
|
@@ -154,7 +219,11 @@ export function createContextProbe(inputId: string, prompt: string): ContextProb
|
|
|
154
219
|
return null;
|
|
155
220
|
const expected = phase === "initialize" ? initializeId : phase === "usage" ? usageId : null;
|
|
156
221
|
if (expected === null || response.request_id !== expected) return null;
|
|
157
|
-
if (
|
|
222
|
+
if (
|
|
223
|
+
response.subtype !== "success" ||
|
|
224
|
+
(phase === "initialize" &&
|
|
225
|
+
(asRecord(response.response) === null || Array.isArray(response.response)))
|
|
226
|
+
) {
|
|
158
227
|
phase = "finished";
|
|
159
228
|
return { kind: "complete", accounting: { status: "unavailable", reason: "protocol" } };
|
|
160
229
|
}
|
|
@@ -41,6 +41,7 @@ export const claudeCode: HarnessDescriptor = deepFreeze({
|
|
|
41
41
|
idFlag: "--session-id",
|
|
42
42
|
},
|
|
43
43
|
resume: {
|
|
44
|
+
admission: { kind: "invocation", modes: ["headless-turn"] },
|
|
44
45
|
// A-005: claude resumes are id-stable - the caller-assigned id survives
|
|
45
46
|
// every resume, so there is no rotation handling and forking is only the
|
|
46
47
|
// explicit --fork-session flag (deliberate branching, never a default).
|
|
@@ -151,6 +152,10 @@ export const claudeCode: HarnessDescriptor = deepFreeze({
|
|
|
151
152
|
object: "context_window",
|
|
152
153
|
usedPctField: "used_percentage",
|
|
153
154
|
},
|
|
155
|
+
nativeContextManagement: {
|
|
156
|
+
kind: "native-session-auto-compaction",
|
|
157
|
+
modes: ["headless-turn"],
|
|
158
|
+
},
|
|
154
159
|
contextInspection: {
|
|
155
160
|
kind: "claude-control-v1",
|
|
156
161
|
flags: [...STREAM_INPUT_FLAGS, "--no-session-persistence", "--replay-user-messages"],
|
package/src/knowledge/codex.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The codex descriptor: facts about the `codex` CLI as data, verified
|
|
3
|
-
* against codex-cli 0.
|
|
4
|
-
*
|
|
5
|
-
* vertical slice is green.
|
|
3
|
+
* against codex-cli 0.153.4. Native capability and question recordings
|
|
4
|
+
* live in test/fixtures/codex-0.153.4.
|
|
6
5
|
*/
|
|
7
6
|
import { deepFreeze, type HarnessDescriptor, UUID_SHAPE } from "./descriptor.js";
|
|
8
7
|
import { SHARED_AUTH_MATCHERS, SHARED_LIMIT_MATCHERS } from "./matchers.js";
|
|
@@ -10,7 +9,7 @@ import { SHARED_AUTH_MATCHERS, SHARED_LIMIT_MATCHERS } from "./matchers.js";
|
|
|
10
9
|
export const codexCli: HarnessDescriptor = deepFreeze({
|
|
11
10
|
name: "codex",
|
|
12
11
|
bin: "codex",
|
|
13
|
-
verifiedAgainst: "0.
|
|
12
|
+
verifiedAgainst: "0.153.4",
|
|
14
13
|
versionSource: { kind: "npm", package: "@openai/codex" },
|
|
15
14
|
launch: {
|
|
16
15
|
// exec --json emits structured item events; without --json, identity
|
|
@@ -84,6 +83,8 @@ export const codexCli: HarnessDescriptor = deepFreeze({
|
|
|
84
83
|
},
|
|
85
84
|
contextHook: null,
|
|
86
85
|
contextInspection: null,
|
|
86
|
+
// Codex 0.153.4 core/session/turn.rs runs native automatic compaction.
|
|
87
|
+
nativeContextManagement: { kind: "auto-compaction", modes: ["headless-turn"] },
|
|
87
88
|
// Valid only in the `exec resume` context: `codex exec resume --last`.
|
|
88
89
|
resumeLast: { flag: "--last" },
|
|
89
90
|
// codex exec appends piped stdin as a <stdin> block and can block on an
|
|
@@ -108,7 +109,12 @@ export const codexCli: HarnessDescriptor = deepFreeze({
|
|
|
108
109
|
// records a model id - absence of evidence, not an unset field.
|
|
109
110
|
escalation: {
|
|
110
111
|
supported: true,
|
|
111
|
-
observedOn: {
|
|
112
|
+
observedOn: {
|
|
113
|
+
harness: "codex",
|
|
114
|
+
model: "gpt-6-astra",
|
|
115
|
+
version: "0.153.4",
|
|
116
|
+
date: "2026-09-08",
|
|
117
|
+
},
|
|
112
118
|
},
|
|
113
119
|
turnOptions: {
|
|
114
120
|
// Codex config reference; accepted as an integer on CLI 0.153.4.
|
|
@@ -338,6 +338,12 @@ export interface HarnessDescriptor {
|
|
|
338
338
|
* anywhere else (the v1 first-UUID-wins scar: a UUID inside quoted prompt
|
|
339
339
|
* text was returned as the session id, and resuming it started a stranger). */
|
|
340
340
|
readonly resume: {
|
|
341
|
+
/** Declared invocation support by mode, not proof that a saved session exists.
|
|
342
|
+
* Omitted retains the verification-version admission policy. */
|
|
343
|
+
readonly admission?: {
|
|
344
|
+
readonly kind: "invocation";
|
|
345
|
+
readonly modes: readonly HarnessMode[];
|
|
346
|
+
};
|
|
341
347
|
readonly style: ResumeStyle;
|
|
342
348
|
readonly flag: string;
|
|
343
349
|
readonly aliases: readonly string[];
|
|
@@ -456,13 +462,20 @@ export interface HarnessDescriptor {
|
|
|
456
462
|
readonly object: string;
|
|
457
463
|
readonly usedPctField: string;
|
|
458
464
|
} | null;
|
|
459
|
-
/** Disposable native context accounting
|
|
465
|
+
/** Disposable native context accounting; the exchange validates support.
|
|
460
466
|
* Null is unknown support, never a model-window estimate. */
|
|
461
467
|
readonly contextInspection: {
|
|
462
468
|
readonly flags: readonly string[];
|
|
463
469
|
readonly forkFlag: string;
|
|
464
470
|
readonly kind: "claude-control-v1";
|
|
465
471
|
} | null;
|
|
472
|
+
/** Curated native context handling, not a count or enabled-state observation.
|
|
473
|
+
* Native-session handling covers the native session; callers must prepare
|
|
474
|
+
* imported history. Disabled native compaction is not detected here. */
|
|
475
|
+
readonly nativeContextManagement: {
|
|
476
|
+
readonly kind: "auto-compaction" | "native-session-auto-compaction";
|
|
477
|
+
readonly modes: readonly HarnessMode[];
|
|
478
|
+
} | null;
|
|
466
479
|
/** Resume-most-recent support (codex --last), or null. The race it opens
|
|
467
480
|
* is owned by the corroboration ranking in interpretation. */
|
|
468
481
|
readonly resumeLast: { readonly flag: string } | null;
|
package/src/knowledge/muse.ts
CHANGED