@dungle-scrubs/harness-cli-normalizer 0.6.5 → 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.
Files changed (44) hide show
  1. package/README.md +23 -8
  2. package/dist/cli/help.d.ts +1 -1
  3. package/dist/cli/help.d.ts.map +1 -1
  4. package/dist/cli/help.js +5 -2
  5. package/dist/cli/help.js.map +1 -1
  6. package/dist/cli/inspect-context.js +4 -6
  7. package/dist/cli/inspect-context.js.map +1 -1
  8. package/dist/cli/inspect-session.js +1 -1
  9. package/dist/cli/inspect-session.js.map +1 -1
  10. package/dist/cli/inspect.d.ts.map +1 -1
  11. package/dist/cli/inspect.js +3 -2
  12. package/dist/cli/inspect.js.map +1 -1
  13. package/dist/cli/runtime-compatibility.d.ts +4 -3
  14. package/dist/cli/runtime-compatibility.d.ts.map +1 -1
  15. package/dist/cli/runtime-compatibility.js +4 -3
  16. package/dist/cli/runtime-compatibility.js.map +1 -1
  17. package/dist/execution/context-inspection.d.ts +1 -1
  18. package/dist/execution/context-inspection.d.ts.map +1 -1
  19. package/dist/execution/context-inspection.js +28 -30
  20. package/dist/execution/context-inspection.js.map +1 -1
  21. package/dist/execution/lines.d.ts +2 -1
  22. package/dist/execution/lines.d.ts.map +1 -1
  23. package/dist/execution/lines.js +4 -1
  24. package/dist/execution/lines.js.map +1 -1
  25. package/dist/interpretation/context-inspection.d.ts +8 -0
  26. package/dist/interpretation/context-inspection.d.ts.map +1 -1
  27. package/dist/interpretation/context-inspection.js +55 -5
  28. package/dist/interpretation/context-inspection.js.map +1 -1
  29. package/dist/knowledge/claude-code.d.ts.map +1 -1
  30. package/dist/knowledge/claude-code.js +5 -1
  31. package/dist/knowledge/claude-code.js.map +1 -1
  32. package/dist/knowledge/descriptor.d.ts +11 -3
  33. package/dist/knowledge/descriptor.d.ts.map +1 -1
  34. package/package.json +1 -1
  35. package/src/cli/help.ts +5 -2
  36. package/src/cli/inspect-context.ts +4 -8
  37. package/src/cli/inspect-session.ts +1 -1
  38. package/src/cli/inspect.ts +3 -2
  39. package/src/cli/runtime-compatibility.ts +10 -4
  40. package/src/execution/context-inspection.ts +35 -30
  41. package/src/execution/lines.ts +5 -1
  42. package/src/interpretation/context-inspection.ts +73 -4
  43. package/src/knowledge/claude-code.ts +5 -1
  44. package/src/knowledge/descriptor.ts +11 -3
@@ -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: ["verified native context adapter without native passthrough"],
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
- if (frame === null || Array.isArray(decoded)) return null;
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 (response.subtype !== "success") {
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,7 +152,10 @@ export const claudeCode: HarnessDescriptor = deepFreeze({
151
152
  object: "context_window",
152
153
  usedPctField: "used_percentage",
153
154
  },
154
- nativeContextManagement: null,
155
+ nativeContextManagement: {
156
+ kind: "native-session-auto-compaction",
157
+ modes: ["headless-turn"],
158
+ },
155
159
  contextInspection: {
156
160
  kind: "claude-control-v1",
157
161
  flags: [...STREAM_INPUT_FLAGS, "--no-session-persistence", "--replay-user-messages"],
@@ -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,16 +462,18 @@ export interface HarnessDescriptor {
456
462
  readonly object: string;
457
463
  readonly usedPctField: string;
458
464
  } | null;
459
- /** Disposable native context accounting, verified at verifiedAgainst.
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;
466
- /** Native context handling at verifiedAgainst; not a preflight count. */
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. */
467
475
  readonly nativeContextManagement: {
468
- readonly kind: "auto-compaction";
476
+ readonly kind: "auto-compaction" | "native-session-auto-compaction";
469
477
  readonly modes: readonly HarnessMode[];
470
478
  } | null;
471
479
  /** Resume-most-recent support (codex --last), or null. The race it opens