@code-yeongyu/senpi 2026.11.2-1 → 2026.11.2-2

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 (67) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/bundle/chunks/{chunk-AMCDEC5A.js → chunk-B2LRAXQU.js} +2 -2
  3. package/dist/bundle/chunks/{chunk-D22YF34L.js → chunk-CQ3G57HE.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-ZUVGFXCS.js → chunk-FVYWSBX3.js} +3 -3
  5. package/dist/bundle/chunks/{chunk-665UPAKG.js → chunk-H3BTMIH5.js} +6 -6
  6. package/dist/bundle/chunks/{chunk-KEJWNCLN.js → chunk-HUSQY3ID.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-IBV4OVXQ.js → chunk-N6OHYIJR.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-XZR4J6HM.js → chunk-PP52OWBB.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-XVQISKHL.js → chunk-QV2IEA3B.js} +4 -4
  10. package/dist/bundle/chunks/{chunk-2V6BR24J.js → chunk-VEWJSPOZ.js} +1 -1
  11. package/dist/bundle/chunks/{cli-main-REFQSP6S.js → cli-main-6ZI4QO2Z.js} +1 -1
  12. package/dist/bundle/chunks/{host-command-Y3ZT6YLD.js → host-command-O3ALG2O3.js} +1 -1
  13. package/dist/bundle/chunks/{host-lifecycle-VW73K4WA.js → host-lifecycle-SGTVODHB.js} +1 -1
  14. package/dist/bundle/chunks/host-lifecycle.js +5 -5
  15. package/dist/bundle/chunks/{host-session-command-YDEUZBTX.js → host-session-command-4WRR5JSB.js} +1 -1
  16. package/dist/bundle/chunks/{interactive-mode-UZXPNJ4V.js → interactive-mode-TF7R35GK.js} +1 -1
  17. package/dist/bundle/chunks/{main-O5G75MYS.js → main-XLUYSOXP.js} +1 -1
  18. package/dist/bundle/chunks/{multi-session-host-AZKJYA2X.js → multi-session-host-CADYC2BS.js} +4 -3
  19. package/dist/bundle/chunks/{package-manager-cli-2YDUGJNR.js → package-manager-cli-I62KMIWK.js} +1 -1
  20. package/dist/bundle/chunks/{rpc-mode-KZD5HZNI.js → rpc-mode-T5GVMUBQ.js} +1 -1
  21. package/dist/bundle/chunks/{schedule-command-7LSJAINZ.js → schedule-command-YXGRN5CM.js} +1 -1
  22. package/dist/bundle/chunks/{session-control-endpoint-BG2KQ6MJ.js → session-control-endpoint-PREVS5UO.js} +1 -1
  23. package/dist/bundle/chunks/session-worker.js +63 -62
  24. package/dist/bundle/cli.js +2 -2
  25. package/dist/bundle/host-supervisor.js +5 -5
  26. package/dist/bundle/index.js +1 -1
  27. package/dist/bundle/rpc-entry.js +1 -1
  28. package/dist/bundle/runtime-manifest.json +1 -1
  29. package/dist/core/session-recovery-identity.d.ts +12 -1
  30. package/dist/modes/rpc/compact-call-fold.d.ts +3 -1
  31. package/dist/modes/rpc/compact-call-fold.js +17 -6
  32. package/dist/modes/rpc/compact-call-identity.d.ts +13 -0
  33. package/dist/modes/rpc/compact-call-identity.js +30 -0
  34. package/dist/modes/rpc/compact-call-model.d.ts +14 -0
  35. package/dist/modes/rpc/compact-call-model.js +4 -0
  36. package/dist/modes/rpc/compact-call-table.d.ts +9 -0
  37. package/dist/modes/rpc/compact-call-table.js +20 -0
  38. package/dist/modes/rpc/compact-catalog-settled.d.ts +5 -0
  39. package/dist/modes/rpc/compact-catalog-settled.js +9 -2
  40. package/dist/modes/rpc/compact-lane-current.d.ts +2 -0
  41. package/dist/modes/rpc/compact-lane-current.js +4 -0
  42. package/dist/modes/rpc/compact-message-identity.d.ts +74 -0
  43. package/dist/modes/rpc/compact-message-identity.js +101 -0
  44. package/dist/modes/rpc/compact-session-calls.d.ts +5 -4
  45. package/dist/modes/rpc/compact-session-calls.js +13 -8
  46. package/dist/modes/rpc/compact-session-state.d.ts +2 -0
  47. package/dist/modes/rpc/compact-session-state.js +4 -0
  48. package/dist/modes/rpc/compact-settled-messages.d.ts +12 -4
  49. package/dist/modes/rpc/compact-settled-messages.js +18 -10
  50. package/dist/modes/rpc/connection-handler.js +1 -1
  51. package/dist/modes/rpc/connection-question-bridge.d.ts +2 -1
  52. package/dist/modes/rpc/connection-question-bridge.js +3 -1
  53. package/dist/modes/rpc/host-lifecycle-proxy.d.ts +9 -0
  54. package/dist/modes/rpc/host-lifecycle-proxy.js +29 -7
  55. package/dist/modes/rpc/rpc-question-types.d.ts +2 -0
  56. package/dist/modes/rpc/session-acceptance-compact.d.ts +17 -7
  57. package/dist/modes/rpc/session-acceptance-compact.js +20 -8
  58. package/dist/modes/rpc/session-acceptance-lane.d.ts +5 -0
  59. package/dist/modes/rpc/session-acceptance-lane.js +12 -11
  60. package/dist/modes/rpc/session-event-writer-destinations.d.ts +2 -1
  61. package/dist/modes/rpc/session-event-writer-destinations.js +24 -9
  62. package/dist/utils/version-check.js +9 -3
  63. package/docs/engine-socket/fixtures/admission-routes/i-live-identity.json +716 -0
  64. package/docs/engine-socket/fixtures/admission-routes/index.json +3 -1
  65. package/docs/engine-socket/fixtures/admission-routes/j-live-call-identity.json +1020 -0
  66. package/docs/rpc.md +66 -0
  67. package/package.json +6 -6
@@ -8,6 +8,7 @@ import { SessionEventWriterRecovery } from "./session-event-writer-recovery.js";
8
8
  import { isCorrelatedReply } from "./socket-peer-recovery.js";
9
9
  import { materializerLine } from "./compact-materializer-line.js";
10
10
  import { declarationReply } from "./compact-negotiation.js";
11
+ import { unvouchedCall } from "./compact-call-identity.js";
11
12
  /** A record's legacy line, encoded on first use: a record no legacy destination needs never builds it (RULING-81 X06). */
12
13
  export class RecordLine {
13
14
  constructor(record, encoded) {
@@ -39,15 +40,16 @@ export class SessionEventWriterDestinations extends SessionEventWriterRecovery {
39
40
  const placeholder = new RecordLine(redacted, placeholderLine);
40
41
  if (!isTargeted && !this.fanout.acceptance.has(sessionId))
41
42
  this.fanout.rememberSnapshot(sessionId, tagged, line.text, placeholderLine);
43
+ const copies = new Map();
42
44
  for (const target of targets) {
43
45
  if (target !== undefined && !this.fanout.get(target))
44
46
  continue;
45
47
  const registered = target === undefined ? undefined : this.fanout.get(target);
46
48
  const wants = placeholderLine !== undefined && this.fanout.connectionHas(target, MEDIA_PLACEHOLDERS_CAPABILITY);
47
49
  if (registered && target !== undefined) {
48
- const out = this.eventLine(target, sessionId, wants ? redacted : tagged, wants ? placeholder : line);
50
+ const out = this.eventLine(target, sessionId, wants ? redacted : tagged, wants ? placeholder : line, copies);
49
51
  const keyed = !out.atomic && compactDelta(tagged) !== undefined && tagged.message !== null;
50
- registered.actor.enqueue(out.line, keyed ? MESSAGE_KEY : undefined, out.undelivered, keyed ? serializeJsonLine(demoteToDeltaOnly(tagged)) : undefined, isCorrelatedReply(tagged), mirrors.includes(target)
52
+ registered.actor.enqueue(out.line, keyed ? MESSAGE_KEY : undefined, out.undelivered, keyed ? serializeJsonLine(demoteToDeltaOnly(out.record ?? tagged)) : undefined, isCorrelatedReply(tagged), mirrors.includes(target)
51
53
  ? undefined
52
54
  : this.fanout.attachmentOf(target, sessionId, isTargeted, record.type), current);
53
55
  }
@@ -60,9 +62,10 @@ export class SessionEventWriterDestinations extends SessionEventWriterRecovery {
60
62
  * holds this lane-owned session, becomes an `eventLease` envelope at the record's accepted sequence, its content
61
63
  * staged from the line another destination built or else streamed from the record (never one legacy line); every
62
64
  * other destination gets the legacy line. Past the peer's lease bound, or when the record cannot be staged, the peer
63
- * gets a typed refusal and its connection closes (fail closed, like a plain peer's overflow).
65
+ * gets a typed refusal and its connection closes (fail closed, like a plain peer's overflow). A stamped copy is
66
+ * built once per delivery (`copies`), so every compact peer leases the same staged text.
64
67
  */
65
- eventLine(target, sessionId, record, line) {
68
+ eventLine(target, sessionId, record, line, copies) {
66
69
  const reply = declarationReply(record, this.compactSelection(target));
67
70
  if (reply !== undefined && reply !== record)
68
71
  return { line: serializeJsonLine(reply) };
@@ -81,17 +84,28 @@ export class SessionEventWriterDestinations extends SessionEventWriterRecovery {
81
84
  return { line: line.text };
82
85
  if (!this.fanout.connectionHas(target, COMPACT_EVENTS_CAPABILITY))
83
86
  return { line: line.text };
84
- const materializer = materializerLine(this.fanout, this.required, target, sessionId, record);
87
+ // RULING-120 (#5331): only this compact peer's copy carries the ids the settled overlay pages for its message;
88
+ // RULING-123 (#5346): and a live call record's snapshot key, or `callUnknown` when the lane vouched for none.
89
+ let copy = copies.get(record);
90
+ if (!copy) {
91
+ const identity = lane.identities.of(record.type, lane.acceptedSequence) ?? unvouchedCall(record);
92
+ const stamped = identity ? { ...record, ...identity } : record;
93
+ copy = { stamped, line: identity ? new RecordLine(stamped) : line };
94
+ copies.set(record, copy);
95
+ }
96
+ const { stamped, line: stampedLine } = copy;
97
+ const identity = stamped !== record;
98
+ const materializer = materializerLine(this.fanout, this.required, target, sessionId, stamped);
85
99
  if (materializer)
86
100
  return materializer;
87
- const built = line.built;
88
- const size = built === undefined ? jsonSize(record) : { bytes: Buffer.byteLength(built) - 1, units: built.length - 1 };
101
+ const built = stampedLine.built;
102
+ const size = built === undefined ? jsonSize(stamped) : { bytes: Buffer.byteLength(built) - 1, units: built.length - 1 };
89
103
  if (size.bytes + 1 <= COMPACT_RECORD_MAX_BYTES)
90
- return { line: line.text };
104
+ return { line: stampedLine.text, ...(identity ? { record: stamped } : {}) };
91
105
  const at = { sessionEpoch: lane.sessionEpoch, sequence: lane.acceptedSequence };
92
106
  const routes = this.ordinaryRoute(target, sessionId)?.routes ?? [];
93
107
  const owner = routes[0] ?? admissionId;
94
- const minted = events.mint({ socketEpoch, sessionId, admissionId: owner }, at, record, built ?? size);
108
+ const minted = events.mint({ socketEpoch, sessionId, admissionId: owner }, at, stamped, built ?? size);
95
109
  if (minted.ok) {
96
110
  const { id } = minted.value;
97
111
  const held = events.claim({ socketEpoch, sessionId }, id, owner);
@@ -100,6 +114,7 @@ export class SessionEventWriterDestinations extends SessionEventWriterRecovery {
100
114
  held.value.admissions.add(route);
101
115
  return {
102
116
  line: serializeJsonLine({ type: Reflect.get(record, "type"), sessionId, eventLease: minted.value }),
117
+ ...(identity ? { record: stamped } : {}),
103
118
  // The lease lives only if its envelope is written: every drop path of the socket actor ends it unseen.
104
119
  undelivered: (written) => {
105
120
  if (!written)
@@ -22,7 +22,9 @@ export function readAvailableVersion(payload, channel) {
22
22
  const DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;
23
23
  const RELEASE_CHANGELOG_BASE_URL = "https://github.com/code-yeongyu/senpi/blob";
24
24
  const RELEASE_CHANGELOG_PATH = "packages/coding-agent/CHANGELOG.md";
25
- const SENPI_CALVER_PATTERN = /^(\d{4})\.(\d{1,2})\.(\d{1,2})(?:-([2-9]\d*))?$/;
25
+ // Month and day may be zero-padded (`2026.11.02-1` as stamped in package.json) or not (npm's normalized
26
+ // `2026.11.2-1`); a `-1` revision is the same release as the bare date.
27
+ const SENPI_CALVER_PATTERN = /^(\d{4})\.(\d{1,2})\.(\d{1,2})(?:-([1-9]\d*))?$/;
26
28
  function parseSenpiCalVer(version) {
27
29
  const match = SENPI_CALVER_PATTERN.exec(version);
28
30
  if (!match) {
@@ -30,6 +32,10 @@ function parseSenpiCalVer(version) {
30
32
  }
31
33
  return [Number(match[1]), Number(match[2]), Number(match[3]), Number(match[4] ?? 1)];
32
34
  }
35
+ /** Unpadded form semver accepts, used when a CalVer version is compared with a plain semver version. */
36
+ function canonicalCalVer([year, month, day, revision]) {
37
+ return revision > 1 ? `${year}.${month}.${day}-${revision}` : `${year}.${month}.${day}`;
38
+ }
33
39
  /** Include useful errno details hidden behind Node's generic "fetch failed" error. */
34
40
  export function formatVersionCheckError(error) {
35
41
  const rootMessage = error instanceof Error && error.message ? error.message : String(error);
@@ -58,8 +64,8 @@ export function comparePackageVersions(leftVersion, rightVersion) {
58
64
  }
59
65
  return 0;
60
66
  }
61
- const left = valid(leftTrimmed);
62
- const right = valid(rightTrimmed);
67
+ const left = valid(leftCalVer ? canonicalCalVer(leftCalVer) : leftTrimmed);
68
+ const right = valid(rightCalVer ? canonicalCalVer(rightCalVer) : rightTrimmed);
63
69
  if (!left || !right) {
64
70
  return undefined;
65
71
  }