@code-yeongyu/senpi 2026.10.26-2 → 2026.10.27-1

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 (61) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/bundle/chunks/{chunk-PPECSSWX.js → chunk-6CJC6JY4.js} +1 -1
  3. package/dist/bundle/chunks/chunk-NXQFBAUI.js +2 -0
  4. package/dist/bundle/chunks/{chunk-ESNSRUW4.js → chunk-P5E4EVQF.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-I2WFLKZ2.js → chunk-Q2A2V6NT.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-JPGT64RV.js → chunk-TV3UI63P.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-TQ67PB7U.js → chunk-TWHF52G6.js} +3 -3
  8. package/dist/bundle/chunks/chunk-ZAS4NBVK.js +410 -0
  9. package/dist/bundle/chunks/{chunk-RPW3XQW3.js → chunk-ZXIAVLJV.js} +75 -75
  10. package/dist/bundle/chunks/{cli-main-Q2GA53XM.js → cli-main-36FRZ7ZB.js} +1 -1
  11. package/dist/bundle/chunks/client-CBDPMWZJ.js +2 -0
  12. package/dist/bundle/chunks/{dispatch-5R3TYAYB.js → dispatch-W5PENPZM.js} +1 -1
  13. package/dist/bundle/chunks/{interactive-mode-5DEKY3YW.js → interactive-mode-5S7NNV2Z.js} +1 -1
  14. package/dist/bundle/chunks/{multi-session-host-OPR5VBFO.js → multi-session-host-E3OPE6HJ.js} +1 -1
  15. package/dist/bundle/chunks/{package-manager-cli-W55E3LHP.js → package-manager-cli-3XO456VE.js} +1 -1
  16. package/dist/bundle/chunks/protocol-GLNWYI5G.js +2 -0
  17. package/dist/bundle/chunks/{rpc-mode-IDUJTSYS.js → rpc-mode-GLWKLTMA.js} +1 -1
  18. package/dist/bundle/chunks/{session-control-endpoint-LMZH5JLH.js → session-control-endpoint-KLE2X4RR.js} +1 -1
  19. package/dist/bundle/chunks/session-worker.js +102 -102
  20. package/dist/bundle/cli.js +2 -2
  21. package/dist/bundle/index.js +1 -1
  22. package/dist/bundle/rpc-entry.js +1 -1
  23. package/dist/bundle/runtime-manifest.json +1 -1
  24. package/dist/core/extensions/builtin/anthropic-subscription/account-context.d.ts +15 -0
  25. package/dist/core/extensions/builtin/anthropic-subscription/account-context.js +53 -0
  26. package/dist/core/extensions/builtin/anthropic-subscription/auth-attempt.d.ts +3 -0
  27. package/dist/core/extensions/builtin/anthropic-subscription/auth-attempt.js +26 -9
  28. package/dist/core/extensions/builtin/anthropic-subscription/auth-lane-boundary.d.ts +16 -0
  29. package/dist/core/extensions/builtin/anthropic-subscription/auth-lane-boundary.js +27 -0
  30. package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.d.ts +2 -13
  31. package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.js +3 -26
  32. package/dist/core/extensions/builtin/anthropic-subscription/errors.js +3 -2
  33. package/dist/core/extensions/builtin/anthropic-subscription/guidance.d.ts +6 -1
  34. package/dist/core/extensions/builtin/anthropic-subscription/guidance.js +1 -1
  35. package/dist/core/extensions/builtin/anthropic-subscription/stream-guidance.js +13 -2
  36. package/dist/core/extensions/builtin/mcp/modern/consent-queue.js +1 -0
  37. package/dist/core/extensions/builtin/mcp/modern/request.js +3 -2
  38. package/dist/core/extensions/builtin/mcp/sdk.lazy.d.ts +2 -0
  39. package/dist/core/extensions/builtin/mcp/sdk.lazy.js +2 -0
  40. package/dist/core/extensions/builtin/mcp/transport-sdk.js +12 -1
  41. package/dist/modes/interactive/interactive-mode.d.ts +2 -1
  42. package/dist/modes/interactive/interactive-mode.js +2 -1
  43. package/dist/modes/rpc/compact-commit-dependencies.d.ts +13 -0
  44. package/dist/modes/rpc/compact-commit-dependencies.js +48 -0
  45. package/dist/modes/rpc/compact-content-index.d.ts +1 -2
  46. package/dist/modes/rpc/compact-content-index.js +12 -23
  47. package/dist/modes/rpc/compact-content-store.d.ts +6 -2
  48. package/dist/modes/rpc/compact-content-store.js +40 -7
  49. package/dist/modes/rpc/compact-read-lease.d.ts +15 -0
  50. package/dist/modes/rpc/compact-read-lease.js +40 -0
  51. package/dist/modes/rpc/compact-session-state.d.ts +7 -28
  52. package/dist/modes/rpc/compact-session-state.js +58 -31
  53. package/dist/modes/rpc/compact-spool-storage.d.ts +5 -0
  54. package/dist/modes/rpc/compact-spool-storage.js +33 -0
  55. package/dist/modes/rpc/compact-text-roots.d.ts +22 -0
  56. package/dist/modes/rpc/compact-text-roots.js +138 -0
  57. package/dist/modes/rpc/compact-text-view.d.ts +22 -0
  58. package/dist/modes/rpc/compact-text-view.js +16 -0
  59. package/package.json +6 -6
  60. package/dist/bundle/chunks/chunk-2XF6W6F6.js +0 -410
  61. package/dist/bundle/chunks/client-LOS6GSEW.js +0 -2
@@ -1,4 +1,6 @@
1
1
  import { CompactContentIndex } from "./compact-content-index.js";
2
+ import { CompactReadError, CompactReadLease } from "./compact-read-lease.js";
3
+ import { readCompactBlocks } from "./compact-text-view.js";
2
4
  import { COMPACT_LEAF_CODE_UNITS, CompactContentStore, } from "./compact-content-store.js";
3
5
  import { CompactTransitionError, } from "./compact-transition.js";
4
6
  const byContentIndex = ([a], [b]) => a - b;
@@ -7,14 +9,17 @@ export class CompactSessionState {
7
9
  this.active = new Map();
8
10
  this.sequence = 0;
9
11
  this.frozenTailBytes = 0;
12
+ this.cuts = new WeakMap();
10
13
  this.store = new CompactContentStore(options);
11
- const leavesOf = (row) => row.blocks.flatMap((block) => block.leaves);
14
+ const leavesOf = (row) => row.blocks.map((block) => block.root);
12
15
  this.settled = new CompactContentIndex(this.store, leavesOf, options.compactAboveRows ?? 128);
13
16
  }
14
17
  get acceptedSequence() {
15
18
  return this.sequence;
16
19
  }
17
20
  accept(transition) {
21
+ if (transition.type !== "message_remove")
22
+ this.store.assertReadable();
18
23
  switch (transition.type) {
19
24
  case "block_start":
20
25
  this.start(transition);
@@ -35,28 +40,56 @@ export class CompactSessionState {
35
40
  return ++this.sequence;
36
41
  }
37
42
  freeze() {
43
+ this.store.assertReadable();
38
44
  const active = new Map();
39
45
  for (const [messageId, blocks] of this.active)
40
46
  active.set(messageId, this.seal(blocks, false));
41
47
  for (const blocks of active.values())
42
48
  this.pin(blocks, 1);
43
- return { sequence: this.sequence, active, settled: this.settled.freeze() };
49
+ const frozen = { sequence: this.sequence, active, settled: this.settled.freeze() };
50
+ this.cuts.set(frozen, new CompactReadLease(() => {
51
+ for (const blocks of frozen.active.values())
52
+ this.pin(blocks, -1);
53
+ this.settled.release(frozen.settled);
54
+ }));
55
+ return frozen;
44
56
  }
45
57
  release(frozen) {
46
- for (const blocks of frozen.active.values())
47
- this.pin(blocks, -1);
48
- this.settled.release(frozen.settled);
58
+ this.cutLease(frozen).release();
49
59
  }
50
60
  /** Rejects with the storage error when committed content is gone; never returns empty content for it. */
51
61
  async read(frozen) {
52
- const messages = [];
53
- for (const [messageId, row] of await this.settled.entries(frozen.settled)) {
54
- messages.push({ messageId, persistence: row.persistence, blocks: await this.texts(row.blocks) });
55
- }
56
- for (const [messageId, blocks] of frozen.active) {
57
- messages.push({ messageId, persistence: undefined, blocks: await this.texts(blocks) });
58
- }
59
- return { sequence: frozen.sequence, messages };
62
+ const lease = this.cutLease(frozen);
63
+ const valid = () => {
64
+ lease.assert();
65
+ this.store.assertReadable();
66
+ };
67
+ valid();
68
+ return lease.run(async () => {
69
+ const messages = [];
70
+ for (const [messageId, row] of await this.settled.entries(frozen.settled)) {
71
+ messages.push({
72
+ messageId,
73
+ persistence: row.persistence,
74
+ blocks: await readCompactBlocks(this.store.text, row.blocks, valid),
75
+ });
76
+ }
77
+ for (const [messageId, blocks] of frozen.active) {
78
+ messages.push({
79
+ messageId,
80
+ persistence: undefined,
81
+ blocks: await readCompactBlocks(this.store.text, blocks, valid),
82
+ });
83
+ }
84
+ valid();
85
+ return { sequence: frozen.sequence, messages };
86
+ });
87
+ }
88
+ cutLease(frozen) {
89
+ const lease = this.cuts.get(frozen);
90
+ if (!lease)
91
+ throw new CompactReadError("ownership");
92
+ return lease;
60
93
  }
61
94
  storageStatus() {
62
95
  let residentTailBytes = 0;
@@ -73,6 +106,9 @@ export class CompactSessionState {
73
106
  residentTailBytes,
74
107
  frozenTailBytes: this.frozenTailBytes,
75
108
  hotWitnessBytes,
109
+ residentTextNodes: this.store.text.residentNodes,
110
+ // Fixed accounting charge for node headers, two edges and pending dependency bookkeeping.
111
+ residentTextIndexBytes: this.store.text.residentNodes * 192,
76
112
  };
77
113
  }
78
114
  idle() {
@@ -90,7 +126,7 @@ export class CompactSessionState {
90
126
  throw new CompactTransitionError("invalid_coverage", `${covered} of ${t.seed.length} seed code units`);
91
127
  }
92
128
  const emitted = covered > 0 ? 0 : t.seed.length;
93
- const block = { kind: t.kind, leaves: [], tail: "", units: 0, emitted, covered, witness: "" };
129
+ const block = { kind: t.kind, root: 0, tail: "", units: 0, emitted, covered, witness: "" };
94
130
  block.witness = t.seed.slice(0, covered);
95
131
  this.append(block, t.seed);
96
132
  const blocks = this.active.get(t.messageId) ?? new Map();
@@ -116,8 +152,8 @@ export class CompactSessionState {
116
152
  block.witness = "";
117
153
  }
118
154
  replace(block, text) {
119
- for (const id of block.leaves.splice(0))
120
- this.store.adjust(id, -1, 0);
155
+ this.store.adjust(block.root, -1, 0);
156
+ block.root = 0;
121
157
  block.tail = "";
122
158
  block.units = 0;
123
159
  block.covered = 0;
@@ -130,8 +166,7 @@ export class CompactSessionState {
130
166
  if (blocks) {
131
167
  this.settled.set(messageId, { persistence, blocks: this.seal(blocks, true) });
132
168
  for (const block of blocks.values())
133
- for (const id of block.leaves)
134
- this.store.adjust(id, -1, 0);
169
+ this.store.adjust(block.root, -1, 0);
135
170
  this.active.delete(messageId);
136
171
  }
137
172
  else if (this.settled.has(messageId)) {
@@ -147,8 +182,7 @@ export class CompactSessionState {
147
182
  if (!blocks && !settled)
148
183
  throw new CompactTransitionError("unknown_message", messageId);
149
184
  for (const block of blocks?.values() ?? [])
150
- for (const id of block.leaves)
151
- this.store.adjust(id, -1, 0);
185
+ this.store.adjust(block.root, -1, 0);
152
186
  this.active.delete(messageId);
153
187
  if (settled)
154
188
  this.settled.delete(messageId);
@@ -164,7 +198,7 @@ export class CompactSessionState {
164
198
  let rest = text;
165
199
  while (block.tail.length + rest.length >= COMPACT_LEAF_CODE_UNITS) {
166
200
  const take = COMPACT_LEAF_CODE_UNITS - block.tail.length;
167
- block.leaves.push(this.store.createLeaf(block.tail + rest.slice(0, take)));
201
+ block.root = this.store.text.append(block.root, block.tail + rest.slice(0, take));
168
202
  block.tail = "";
169
203
  rest = rest.slice(take);
170
204
  }
@@ -174,24 +208,17 @@ export class CompactSessionState {
174
208
  seal(blocks, settle) {
175
209
  return [...blocks].sort(byContentIndex).map(([contentIndex, block]) => {
176
210
  if (settle && block.tail.length > 0) {
177
- block.leaves.push(this.store.createLeaf(block.tail));
211
+ block.root = this.store.text.append(block.root, block.tail);
178
212
  block.tail = "";
179
213
  }
180
- return { contentIndex, kind: block.kind, leaves: [...block.leaves], tail: block.tail };
214
+ return { contentIndex, kind: block.kind, root: block.root, tail: block.tail };
181
215
  });
182
216
  }
183
217
  pin(blocks, delta) {
184
218
  for (const block of blocks) {
185
219
  this.frozenTailBytes += delta * block.tail.length * 2;
186
- for (const id of block.leaves)
187
- this.store.adjust(id, 0, delta);
220
+ this.store.adjust(block.root, 0, delta);
188
221
  }
189
222
  }
190
- async texts(blocks) {
191
- return Promise.all(blocks.map(async ({ contentIndex, kind, leaves, tail }) => {
192
- const parts = await Promise.all(leaves.map((id) => this.store.readLeaf(id)));
193
- return { contentIndex, kind, text: parts.join("") + tail };
194
- }));
195
- }
196
223
  }
197
224
  //# sourceMappingURL=compact-session-state.js.map
@@ -20,6 +20,10 @@ export declare abstract class CompactSpoolStorage {
20
20
  protected pendingIoCopyBytes: number;
21
21
  protected spillBytesWritten: number;
22
22
  protected reclaimDebtBytes: number;
23
+ private reads;
24
+ private reading;
25
+ assertReadable(): void;
26
+ beginRead(): () => void;
23
27
  constructor(dir: string, io: CompactStorageIo);
24
28
  /** Resolves once every queued storage job, including the ones they queued, has completed. */
25
29
  idle(): Promise<void>;
@@ -30,6 +34,7 @@ export declare abstract class CompactSpoolStorage {
30
34
  retire(): Promise<void>;
31
35
  /** Reads a committed file and rejects a missing, unreadable or short one. */
32
36
  readFile(path: string, bytes: number, operation: CompactStorageOperation): Promise<Buffer>;
37
+ private readCommittedFile;
33
38
  /** Writes one new spool file; undefined means the write failed and was reported (a spill write also halts spilling). */
34
39
  writeFile(data: Buffer, operation: CompactStorageOperation, retainedInMemoryBytes: number): Promise<string | undefined>;
35
40
  /**
@@ -1,4 +1,5 @@
1
1
  import { join } from "node:path";
2
+ import { CompactReadError } from "./compact-read-lease.js";
2
3
  import { createSpoolDir, removeSpoolDir } from "./compact-spool-dir.js";
3
4
  import { CompactStorageReadError, describeCause, } from "./compact-storage-io.js";
4
5
  /**
@@ -10,6 +11,25 @@ export const RECLAIM_WORK_ALLOWANCE_BYTES = 1024 * 1024;
10
11
  const RECLAIM_RETRY_DELAYS_MS = [100, 400, 1_600, 6_400, 25_600];
11
12
  const FAILURE_HISTORY = 32;
12
13
  export class CompactSpoolStorage {
14
+ assertReadable() {
15
+ if (this.retired)
16
+ throw new CompactReadError("retired");
17
+ }
18
+ beginRead() {
19
+ this.assertReadable();
20
+ this.reads++;
21
+ this.reading ??= Promise.withResolvers();
22
+ let done = false;
23
+ return () => {
24
+ if (done)
25
+ return;
26
+ done = true;
27
+ if (--this.reads === 0) {
28
+ this.reading?.resolve();
29
+ this.reading = undefined;
30
+ }
31
+ };
32
+ }
13
33
  constructor(dir, io) {
14
34
  this.failures = [];
15
35
  this.nextFile = 1;
@@ -21,6 +41,7 @@ export class CompactSpoolStorage {
21
41
  this.pendingIoCopyBytes = 0;
22
42
  this.spillBytesWritten = 0;
23
43
  this.reclaimDebtBytes = 0;
44
+ this.reads = 0;
24
45
  this.dir = dir;
25
46
  this.io = io;
26
47
  }
@@ -35,6 +56,7 @@ export class CompactSpoolStorage {
35
56
  */
36
57
  async retire() {
37
58
  this.retired = true;
59
+ await this.reading?.promise;
38
60
  await this.idle();
39
61
  const token = this.spoolToken;
40
62
  this.spoolToken = undefined;
@@ -43,6 +65,17 @@ export class CompactSpoolStorage {
43
65
  }
44
66
  /** Reads a committed file and rejects a missing, unreadable or short one. */
45
67
  async readFile(path, bytes, operation) {
68
+ const done = this.beginRead();
69
+ try {
70
+ const result = await this.readCommittedFile(path, bytes, operation);
71
+ this.assertReadable();
72
+ return result;
73
+ }
74
+ finally {
75
+ done();
76
+ }
77
+ }
78
+ async readCommittedFile(path, bytes, operation) {
46
79
  let data;
47
80
  try {
48
81
  data = await this.io.readFile(path);
@@ -0,0 +1,22 @@
1
+ import { type CompactContentStore, type LeafId } from "./compact-content-store.ts";
2
+ /** Persistent append tree: positive refs are leaves, negative refs are nodes, zero is empty. */
3
+ export declare class CompactTextRoots {
4
+ private readonly nodes;
5
+ private readonly pending;
6
+ private readonly store;
7
+ private next;
8
+ constructor(store: CompactContentStore);
9
+ get residentNodes(): number;
10
+ units(id: LeafId): number;
11
+ isCommitted(id: LeafId): boolean;
12
+ /** Transfers one live root and one newly owned bounded leaf into the new root. */
13
+ append(root: LeafId, text: string): LeafId;
14
+ adjust(id: LeafId, live: number, pins: number): void;
15
+ /** Bounded UTF-16 result and bounded leaf/tail count, checked before any I/O. */
16
+ read(root: LeafId, tail: string, offset: number, units: number, maxLeaves?: number, valid?: () => void): Promise<string>;
17
+ private node;
18
+ private appendLeaf;
19
+ private height;
20
+ private join;
21
+ }
22
+ //# sourceMappingURL=compact-text-roots.d.ts.map
@@ -0,0 +1,138 @@
1
+ import { CompactCommitDependencies } from "./compact-commit-dependencies.js";
2
+ import { COMPACT_LEAF_CODE_UNITS } from "./compact-content-store.js";
3
+ import { CompactReadError } from "./compact-read-lease.js";
4
+ /** Persistent append tree: positive refs are leaves, negative refs are nodes, zero is empty. */
5
+ export class CompactTextRoots {
6
+ constructor(store) {
7
+ this.nodes = new Map();
8
+ this.next = -1;
9
+ this.store = store;
10
+ this.pending = new CompactCommitDependencies(store, (id) => store.committed(id));
11
+ }
12
+ get residentNodes() {
13
+ return this.nodes.size;
14
+ }
15
+ units(id) {
16
+ return id === 0 ? 0 : id > 0 ? this.store.leafUnits(id) : this.node(id).units;
17
+ }
18
+ isCommitted(id) {
19
+ return this.nodes.has(id) && !this.pending.has(id);
20
+ }
21
+ /** Transfers one live root and one newly owned bounded leaf into the new root. */
22
+ append(root, text) {
23
+ this.units(root);
24
+ const leaf = this.store.createLeaf(text);
25
+ if (root === 0)
26
+ return leaf;
27
+ const result = this.appendLeaf(root, leaf);
28
+ this.store.adjust(root, -1, 0);
29
+ this.store.adjust(leaf, -1, 0);
30
+ return result;
31
+ }
32
+ adjust(id, live, pins) {
33
+ const node = this.node(id);
34
+ const beforeLive = Number(node.live > 0);
35
+ const beforePin = Number(node.live === 0 && node.pins > 0);
36
+ if (node.live + live < 0 || node.pins + pins < 0)
37
+ throw new CompactReadError("ownership");
38
+ node.live += live;
39
+ node.pins += pins;
40
+ const liveChange = Number(node.live > 0) - beforeLive;
41
+ const pinChange = Number(node.live === 0 && node.pins > 0) - beforePin;
42
+ // Extra cuts on a live subtree do not visit children. Only category transitions propagate.
43
+ if (liveChange || pinChange) {
44
+ this.store.adjust(node.left, liveChange, pinChange);
45
+ this.store.adjust(node.right, liveChange, pinChange);
46
+ }
47
+ if (node.live === 0 && node.pins === 0) {
48
+ this.pending.delete(id);
49
+ this.nodes.delete(id);
50
+ }
51
+ }
52
+ /** Bounded UTF-16 result and bounded leaf/tail count, checked before any I/O. */
53
+ async read(root, tail, offset, units, maxLeaves = 2, valid = () => this.store.assertReadable()) {
54
+ this.store.assertReadable();
55
+ valid();
56
+ const length = this.units(root);
57
+ if (!Number.isSafeInteger(offset) ||
58
+ !Number.isSafeInteger(units) ||
59
+ offset < 0 ||
60
+ units < 0 ||
61
+ offset + units > length + tail.length)
62
+ throw new CompactReadError("range");
63
+ if (units > COMPACT_LEAF_CODE_UNITS)
64
+ throw new CompactReadError("size_limit");
65
+ if (!Number.isSafeInteger(maxLeaves) || maxLeaves < 1 || maxLeaves > 2)
66
+ throw new CompactReadError("count_limit");
67
+ const selected = [];
68
+ const visit = (id, start, end) => {
69
+ if (start >= end || id === 0)
70
+ return;
71
+ if (id > 0) {
72
+ if (selected.length === maxLeaves)
73
+ throw new CompactReadError("count_limit");
74
+ selected.push({ id, offset: start, units: end - start });
75
+ }
76
+ else {
77
+ const node = this.node(id);
78
+ const leftUnits = this.units(node.left);
79
+ visit(node.left, start, Math.min(end, leftUnits));
80
+ visit(node.right, Math.max(0, start - leftUnits), end - leftUnits);
81
+ }
82
+ };
83
+ visit(root, offset, Math.min(length, offset + units));
84
+ const tailUnits = units === 0 ? 0 : Math.max(0, offset + units - Math.max(offset, length));
85
+ if (selected.length + Number(tailUnits > 0) > maxLeaves)
86
+ throw new CompactReadError("count_limit");
87
+ this.store.adjust(root, 0, 1);
88
+ const done = this.store.beginRead();
89
+ try {
90
+ let result = "";
91
+ for (const part of selected) {
92
+ const text = await this.store.readLeaf(part.id);
93
+ valid();
94
+ result += text.slice(part.offset, part.offset + part.units);
95
+ }
96
+ valid();
97
+ return result + tail.slice(Math.max(0, offset - length), Math.max(0, offset - length) + tailUnits);
98
+ }
99
+ finally {
100
+ this.store.adjust(root, 0, -1);
101
+ done();
102
+ }
103
+ }
104
+ node(id) {
105
+ const node = this.nodes.get(id);
106
+ if (!node)
107
+ throw new CompactReadError("ownership");
108
+ return node;
109
+ }
110
+ appendLeaf(root, leaf) {
111
+ const node = this.nodes.get(root);
112
+ if (!node || this.height(node.left) === this.height(node.right))
113
+ return this.join(root, leaf);
114
+ const right = this.appendLeaf(node.right, leaf);
115
+ const result = this.join(node.left, right);
116
+ this.store.adjust(right, -1, 0);
117
+ return result;
118
+ }
119
+ height(id) {
120
+ return id > 0 ? 0 : this.node(id).height;
121
+ }
122
+ join(left, right) {
123
+ const id = this.next--;
124
+ this.nodes.set(id, {
125
+ left,
126
+ right,
127
+ units: this.units(left) + this.units(right),
128
+ height: 1 + Math.max(this.height(left), this.height(right)),
129
+ live: 1,
130
+ pins: 0,
131
+ });
132
+ this.store.adjust(left, 1, 0);
133
+ this.store.adjust(right, 1, 0);
134
+ this.pending.set(id, [left, right]);
135
+ return id;
136
+ }
137
+ }
138
+ //# sourceMappingURL=compact-text-roots.js.map
@@ -0,0 +1,22 @@
1
+ import { type LeafId } from "./compact-content-store.ts";
2
+ import type { CompactTextRoots } from "./compact-text-roots.ts";
3
+ import type { CompactBlockKind, CompactPersistence } from "./compact-transition.ts";
4
+ export interface FrozenBlock {
5
+ readonly contentIndex: number;
6
+ readonly kind: CompactBlockKind;
7
+ readonly root: LeafId;
8
+ /** A cut shares the immutable tail (under one leaf), not a new leaf for each freeze. */
9
+ readonly tail: string;
10
+ }
11
+ export interface CompactMessageView {
12
+ readonly messageId: string;
13
+ readonly persistence: CompactPersistence | undefined;
14
+ readonly blocks: readonly {
15
+ readonly contentIndex: number;
16
+ readonly kind: CompactBlockKind;
17
+ readonly text: string;
18
+ }[];
19
+ }
20
+ /** Compatibility assembly only; each underlying range is bounded, the resulting legacy view is not. */
21
+ export declare function readCompactBlocks(texts: CompactTextRoots, blocks: readonly FrozenBlock[], valid: () => void): Promise<CompactMessageView["blocks"]>;
22
+ //# sourceMappingURL=compact-text-view.d.ts.map
@@ -0,0 +1,16 @@
1
+ import { COMPACT_LEAF_CODE_UNITS } from "./compact-content-store.js";
2
+ /** Compatibility assembly only; each underlying range is bounded, the resulting legacy view is not. */
3
+ export async function readCompactBlocks(texts, blocks, valid) {
4
+ const result = [];
5
+ for (const { contentIndex, kind, root, tail } of blocks) {
6
+ valid();
7
+ const length = texts.units(root) + tail.length;
8
+ let text = "";
9
+ for (let offset = 0; offset < length; offset += COMPACT_LEAF_CODE_UNITS) {
10
+ text += await texts.read(root, tail, offset, Math.min(COMPACT_LEAF_CODE_UNITS, length - offset), 2, valid);
11
+ }
12
+ result.push({ contentIndex, kind, text });
13
+ }
14
+ return result;
15
+ }
16
+ //# sourceMappingURL=compact-text-view.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi",
3
- "version": "2026.10.26-2",
3
+ "version": "2026.10.27-1",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -71,9 +71,9 @@
71
71
  },
72
72
  "dependencies": {
73
73
  "@earendil-works/chord": "0.99.1",
74
- "@earendil-works/pi-agent-core": "npm:@code-yeongyu/senpi-agent-core@2026.10.26-2",
75
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.26-2",
76
- "@earendil-works/pi-tui": "npm:@code-yeongyu/senpi-tui@2026.10.26-2",
74
+ "@earendil-works/pi-agent-core": "npm:@code-yeongyu/senpi-agent-core@2026.10.27-1",
75
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.10.27-1",
76
+ "@earendil-works/pi-tui": "npm:@code-yeongyu/senpi-tui@2026.10.27-1",
77
77
  "@silvia-odwyer/photon-node": "0.3.4",
78
78
  "ajv": "8.20.0",
79
79
  "chalk": "6.0.0",
@@ -93,8 +93,8 @@
93
93
  "yaml": "2.9.1",
94
94
  "@anthropic-ai/claude-agent-sdk": "0.3.306",
95
95
  "@anthropic-ai/sdk": "0.127.0",
96
- "@code-yeongyu/senpi-codemode": "2026.10.26-2",
97
- "@earendil-works/pi-pty": "npm:@code-yeongyu/senpi-pty@2026.10.26-2",
96
+ "@code-yeongyu/senpi-codemode": "2026.10.27-1",
97
+ "@earendil-works/pi-pty": "npm:@code-yeongyu/senpi-pty@2026.10.27-1",
98
98
  "@modelcontextprotocol/sdk": "1.32.1",
99
99
  "@mozilla/readability": "0.6.0",
100
100
  "linkedom": "0.18.13",