@bli-cockpit/cli 0.2.268 → 0.2.269

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.
@@ -21,7 +21,7 @@ export async function runCockpitCli(argv, io) {
21
21
  }
22
22
 
23
23
  if (command === "--version" || command === "-V" || command === "version") {
24
- writeLine(io?.stdout ?? process.stdout, "0.2.268");
24
+ writeLine(io?.stdout ?? process.stdout, "0.2.269");
25
25
  return 0;
26
26
  }
27
27
 
@@ -14,17 +14,19 @@
14
14
  * every assistant line, holding no content.
15
15
  * - `toolUseResult` fields that repeat the tool_result or the tool input (claude-tool-results.ts).
16
16
  * - Attachment bookkeeping (claude-attachments.ts).
17
+ * - A thinking block's encrypted `signature`, replaced by a marker with its length (BLI-23334).
17
18
  *
18
19
  * Unknown shapes pass through untouched.
19
20
  */
20
21
  import { slimAttachmentLine, slimStopHookSummary } from "./claude-attachments.js";
21
22
  import { rememberToolInputs, slimToolUseResult, } from "./claude-tool-results.js";
22
- import { isJsonObject, stripKey } from "./slim-support.js";
23
+ import { dropCiphertext, isJsonObject, stripKey } from "./slim-support.js";
23
24
  export function newClaudeSlimState() {
24
25
  return { toolInputs: new Map() };
25
26
  }
26
27
  export function slimClaudeRecord(record, state, seen, edits) {
27
28
  stripKey(record, "wireToolInputs", "wireToolInputs", edits);
29
+ dropThinkingSignatures(record["message"], edits);
28
30
  switch (record["type"]) {
29
31
  case "assistant": {
30
32
  rememberToolInputs(record, state.toolInputs);
@@ -45,4 +47,20 @@ export function slimClaudeRecord(record, state, seen, edits) {
45
47
  default:
46
48
  return;
47
49
  }
50
+ }
51
+ /**
52
+ * BLI-23334: a thinking block's `signature` is a base64 blob Anthropic signs the block with; it
53
+ * compresses to about 75 percent and nothing in Tower reads it. The block, its `thinking` text and
54
+ * every other key stay. Assistant lines and `api-request-blob` lines carry the same blocks, so the
55
+ * rule keys on `message.content[]`, not on the line type. `redacted_thinking.data` is not touched:
56
+ * that block has no readable text, its data is all it is.
57
+ */
58
+ function dropThinkingSignatures(message, edits) {
59
+ if (!isJsonObject(message) || !Array.isArray(message["content"]))
60
+ return;
61
+ for (const block of message["content"]) {
62
+ if (isJsonObject(block) && block["type"] === "thinking") {
63
+ dropCiphertext(block, "signature", "claude.thinking.signature", edits);
64
+ }
65
+ }
48
66
  }
@@ -8,7 +8,20 @@
8
8
  * Guardian history and task_complete messages deduplicate only against earlier
9
9
  * response items; a copy appearing first is retained.
10
10
  */
11
- import { SLIM_COPY_MIN_CHARS, canonicalText, contentHash, isJsonObject, isSlimRef, slimRefFor, stripKey, } from "./slim-support.js";
11
+ import { SLIM_COPY_MIN_CHARS, canonicalText, contentHash, dropCiphertext, isJsonObject, isSlimRef, slimRefFor, stripKey, } from "./slim-support.js";
12
+ /**
13
+ * BLI-23334: `encrypted_content` on a reasoning or compaction item is ciphertext only OpenAI can
14
+ * read (it compresses to about 75 percent). It becomes a marker with its length; the item and its
15
+ * readable `summary` stay. Exactly two places carry it: a `response_item` payload of those types,
16
+ * and the same item types inside a `compacted` line's `replacement_history`. No other key and no
17
+ * other item type is touched, so nothing outside this contract can lose a field.
18
+ */
19
+ const CIPHERTEXT_ITEM_TYPES = new Set(["reasoning", "compaction"]);
20
+ function dropItemCiphertext(item, edits) {
21
+ if (isJsonObject(item) && typeof item["type"] === "string" && CIPHERTEXT_ITEM_TYPES.has(item["type"])) {
22
+ dropCiphertext(item, "encrypted_content", "codex.encrypted_content", edits);
23
+ }
24
+ }
12
25
  /** Strings from `response_item` lines remembered for comparison. Past this, new strings are not added. */
13
26
  const MAX_REMEMBERED_STRINGS = 300_000;
14
27
  /** Item types whose event copy is a pure repeat of a `response_item`. */
@@ -23,6 +36,7 @@ export function slimCodexRecord(record, state, seen, edits) {
23
36
  switch (record["type"]) {
24
37
  case "response_item":
25
38
  rememberLongStrings(payload, state, 0);
39
+ dropItemCiphertext(payload, edits);
26
40
  stripKey(payload, "internal_chat_message_metadata_passthrough", "codex.response_item.passthrough", edits);
27
41
  if (payload["type"] === "message" && payload["role"] === "developer") {
28
42
  seen.dedupeKey(payload, "content", "codex.developer_message.repeat", edits);
@@ -39,6 +53,10 @@ export function slimCodexRecord(record, state, seen, edits) {
39
53
  return;
40
54
  }
41
55
  case "compacted": {
56
+ const history = payload["replacement_history"];
57
+ if (Array.isArray(history))
58
+ for (const item of history)
59
+ dropItemCiphertext(item, edits);
42
60
  // guardian_history re-saves earlier turns; replacement_history is kept whole (part of it is found nowhere else).
43
61
  const guardian = payload["guardian_history"];
44
62
  if (Array.isArray(guardian))
@@ -58,6 +58,28 @@ export function stripKey(holder, key, rule, edits) {
58
58
  delete holder[key];
59
59
  return true;
60
60
  }
61
+ /** What an encrypted value becomes (BLI-23334): `[encrypted signature dropped, 1624 chars]`. Idempotent, prefix-stable. */
62
+ const CIPHERTEXT_MARKER_START = "[encrypted signature dropped, ";
63
+ export function ciphertextMarker(chars) {
64
+ return `${CIPHERTEXT_MARKER_START}${chars} chars]`;
65
+ }
66
+ /**
67
+ * Replace `holder[key]`, an opaque encrypted string nothing downstream can read (a Claude thinking
68
+ * `signature`, a Codex `encrypted_content`), with a marker that keeps its length. The surrounding
69
+ * block and its readable text are never touched. Shorter than its own marker, or already a marker,
70
+ * means no change.
71
+ */
72
+ export function dropCiphertext(holder, key, rule, edits) {
73
+ const value = holder[key];
74
+ if (typeof value !== "string" || value.startsWith(CIPHERTEXT_MARKER_START))
75
+ return false;
76
+ const marker = ciphertextMarker(value.length);
77
+ if (value.length <= marker.length)
78
+ return false;
79
+ holder[key] = marker;
80
+ edits.strip(rule, value.length - marker.length);
81
+ return true;
82
+ }
61
83
  /**
62
84
  * The one copy per transcript. The first time a block is seen it stays in the line; every time
63
85
  * after, the block is replaced by `{"slim_ref":"sha256:<16 hex>"}` naming the earlier copy. The
@@ -36,7 +36,7 @@ import { LineEdits, SeenBlocks, isJsonObject } from "./slim-support.js";
36
36
  * once, which is intended: the stored bytes are no longer what the new rules would produce.
37
37
  * `slim-rules-version.test.ts` fails when a rule changes without this moving.
38
38
  */
39
- export const SLIM_RULES_VERSION = "slim-rules.v1";
39
+ export const SLIM_RULES_VERSION = "slim-rules.v2";
40
40
  /** The text an image marker starts with; a line carrying one is a modified line (an image became a marker). */
41
41
  const IMAGE_MARKER_START = "[image sha256:";
42
42
  export function createSlimmer(kind, rulesForTests) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/cli",
3
- "version": "0.2.268",
3
+ "version": "0.2.269",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,9 +27,9 @@
27
27
  "test": "node dist/cli.js --help && node ../../scripts/assert-public-cli-routing.mjs && node ../../scripts/assert-public-cli-verb-help.mjs && node ../../scripts/assert-public-cli-surface-doors.mjs && node ../../scripts/assert-public-cli-runtime-files.mjs && node ../../scripts/assert-public-cli-exit-contract.mjs && node ../../scripts/assert-public-cli-no-fleet-posts.mjs && node ../../scripts/assert-public-cli-doctor-json.mjs && node ../../scripts/assert-public-package-pack.mjs --workspace=@bli-cockpit/cli"
28
28
  },
29
29
  "dependencies": {
30
- "@bli-cockpit/memory-mcp": "0.1.79",
31
- "@bli-cockpit/mcp": "0.1.163",
32
- "@bli-cockpit/telemetry-core": "0.1.86"
30
+ "@bli-cockpit/memory-mcp": "0.1.80",
31
+ "@bli-cockpit/mcp": "0.1.164",
32
+ "@bli-cockpit/telemetry-core": "0.1.87"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",