@code-yeongyu/senpi 2026.11.2-3 → 2026.11.3-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 (169) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/bundle/chunks/{anthropic-messages-WUPLDYD6.js → anthropic-messages-AFWQB3KN.js} +1 -1
  3. package/dist/bundle/chunks/{args-AOI4NEA6.js → args-O3WS4WCO.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-O4GRBX4R.js → chunk-3WJ2DE2G.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-LMIETUPG.js → chunk-4BF4FLT6.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-T5ZJ2Q4O.js → chunk-4SENPCEA.js} +1 -1
  7. package/dist/bundle/chunks/chunk-5DZD623T.js +448 -0
  8. package/dist/bundle/chunks/{chunk-TXOR5BQL.js → chunk-6BSMXZKQ.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-VRWJJMHO.js → chunk-7565XQAU.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-IWM5QRAE.js → chunk-7KLEFHSU.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-FO56LSUK.js → chunk-BNIZP4OS.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-L3V65XW7.js → chunk-CJWSQ6CK.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-QLTQ3UUI.js → chunk-DAPBNRN5.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-GIY7PGOH.js → chunk-DPBPO5OU.js} +1 -1
  15. package/dist/bundle/chunks/chunk-ESQBKTNG.js +2 -0
  16. package/dist/bundle/chunks/{chunk-N4TSAHRL.js → chunk-EVTTLPIY.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-NYXXKS6D.js → chunk-F4OHTL2K.js} +3 -2
  18. package/dist/bundle/chunks/{chunk-TVMW2SUP.js → chunk-FJ2UCBOA.js} +2 -2
  19. package/dist/bundle/chunks/{chunk-KVPRQ5KN.js → chunk-FLM6GZPT.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-P4AT7SBE.js → chunk-HBCNDC53.js} +1 -1
  21. package/dist/bundle/chunks/chunk-MOH5HOHX.js +2 -0
  22. package/dist/bundle/chunks/{chunk-7FUO655J.js → chunk-MOOFLKLI.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-IHOQR7TU.js → chunk-PX7FF5LE.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-QAM6AXA2.js → chunk-QTQ3ES2S.js} +12 -9
  25. package/dist/bundle/chunks/{chunk-FJSJUVQQ.js → chunk-TOOB6OLG.js} +3 -3
  26. package/dist/bundle/chunks/{chunk-662SCMTH.js → chunk-VPDQ6MOL.js} +1 -1
  27. package/dist/bundle/chunks/{chunk-BW4YXS7X.js → chunk-WCRNJYHO.js} +1 -1
  28. package/dist/bundle/chunks/{chunk-ZSVWKOAJ.js → chunk-ZNLCKKF6.js} +170 -226
  29. package/dist/bundle/chunks/{cli-main-534A3WSC.js → cli-main-XM5FWY3Z.js} +1 -1
  30. package/dist/bundle/chunks/{credential-accounts-OAK2E5O2.js → credential-accounts-YZYSKA7X.js} +1 -1
  31. package/dist/bundle/chunks/{health-write-EB4CPHXN.js → health-write-45CX64T2.js} +1 -1
  32. package/dist/bundle/chunks/{help-fast-path-U2PSNNWO.js → help-fast-path-3EDGRKQM.js} +1 -1
  33. package/dist/bundle/chunks/{host-command-WJIMRBGN.js → host-command-PZ4VYQIW.js} +1 -1
  34. package/dist/bundle/chunks/{host-session-command-PWVPQ2OV.js → host-session-command-OJFARE5Q.js} +1 -1
  35. package/dist/bundle/chunks/{interactive-mode-NPHFDPGH.js → interactive-mode-7JSJVVIS.js} +1 -1
  36. package/dist/bundle/chunks/{login-health-7G2DZVOV.js → login-health-YOPTYRTU.js} +1 -1
  37. package/dist/bundle/chunks/{main-I6FJAFUP.js → main-3YGJ2O4I.js} +1 -1
  38. package/dist/bundle/chunks/{multi-session-host-7E26R5JF.js → multi-session-host-N2RQ7JSZ.js} +4 -4
  39. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  40. package/dist/bundle/chunks/{openai-codex-responses-VNBMMIL3.js → openai-codex-responses-YTWLG4OL.js} +1 -1
  41. package/dist/bundle/chunks/{openai-completions-JLR32APM.js → openai-completions-TIFDYHZL.js} +1 -1
  42. package/dist/bundle/chunks/{openai-images-LEBNERSM.js → openai-images-OAEMY4RG.js} +1 -1
  43. package/dist/bundle/chunks/{openai-responses-JCDUNMHA.js → openai-responses-L35NIG5Y.js} +1 -1
  44. package/dist/bundle/chunks/{package-manager-cli-CBSDV36M.js → package-manager-cli-JPNA27E5.js} +1 -1
  45. package/dist/bundle/chunks/{role-LP6LVNCY.js → role-45Y7PQFC.js} +1 -1
  46. package/dist/bundle/chunks/{rotation-stream-ZDCNHIBE.js → rotation-stream-WXWJKJZN.js} +1 -1
  47. package/dist/bundle/chunks/{rpc-mode-GBBTN2WP.js → rpc-mode-Z7MN2ZWA.js} +1 -1
  48. package/dist/bundle/chunks/{run-attached-tui-PVLUHHJX.js → run-attached-tui-TI6MELEI.js} +1 -1
  49. package/dist/bundle/chunks/{schedule-command-W45NYTTK.js → schedule-command-OZ5ESMIT.js} +1 -1
  50. package/dist/bundle/chunks/{session-control-endpoint-LFLUNALC.js → session-control-endpoint-5YKBYJOO.js} +1 -1
  51. package/dist/bundle/chunks/{session-picker-OZUINLD7.js → session-picker-CMRV72VA.js} +1 -1
  52. package/dist/bundle/chunks/session-worker.js +324 -376
  53. package/dist/bundle/chunks/{state-store-SZARKD36.js → state-store-Q47AYMRI.js} +1 -1
  54. package/dist/bundle/cli.js +2 -2
  55. package/dist/bundle/index.js +1 -1
  56. package/dist/bundle/rpc-entry.js +1 -1
  57. package/dist/bundle/runtime-manifest.json +1 -1
  58. package/dist/core/agent-session.d.ts +8 -0
  59. package/dist/core/agent-session.js +68 -60
  60. package/dist/core/credential-pool/classify.d.ts +3 -2
  61. package/dist/core/credential-pool/classify.js +10 -3
  62. package/dist/core/dynamic-prompt/build.d.ts +2 -1
  63. package/dist/core/dynamic-prompt/build.js +1 -2
  64. package/dist/core/dynamic-prompt/handoff.d.ts +1 -1
  65. package/dist/core/dynamic-prompt/handoff.js +9 -9
  66. package/dist/core/dynamic-prompt/identity.js +1 -1
  67. package/dist/core/dynamic-prompt/intent-gate.d.ts +1 -1
  68. package/dist/core/dynamic-prompt/intent-gate.js +8 -8
  69. package/dist/core/dynamic-prompt/policies.d.ts +1 -1
  70. package/dist/core/dynamic-prompt/policies.js +5 -7
  71. package/dist/core/dynamic-prompt/style.js +5 -5
  72. package/dist/core/dynamic-prompt/tool-section.d.ts +5 -0
  73. package/dist/core/dynamic-prompt/tool-section.js +8 -6
  74. package/dist/core/dynamic-prompt/verification.d.ts +6 -6
  75. package/dist/core/dynamic-prompt/verification.js +12 -12
  76. package/dist/core/dynamic-prompt/working-task.d.ts +1 -1
  77. package/dist/core/dynamic-prompt/working-task.js +3 -3
  78. package/dist/core/dynamic-prompt/workstation.js +1 -1
  79. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.d.ts +13 -0
  80. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.js +64 -2
  81. package/dist/core/extensions/builtin/anthropic-subscription/session-stream.js +5 -1
  82. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.d.ts +7 -0
  83. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.js +28 -1
  84. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.d.ts +2 -0
  85. package/dist/core/extensions/builtin/bash-timeout/index.d.ts +1 -1
  86. package/dist/core/extensions/builtin/bash-timeout/index.js +3 -28
  87. package/dist/core/extensions/builtin/bash-timeout/timeout.d.ts +0 -11
  88. package/dist/core/extensions/builtin/bash-timeout/timeout.js +0 -11
  89. package/dist/core/extensions/builtin/imagegen/index.d.ts +0 -1
  90. package/dist/core/extensions/builtin/imagegen/index.js +0 -11
  91. package/dist/core/extensions/builtin/prompt-preset/execution-tooling.d.ts +5 -5
  92. package/dist/core/extensions/builtin/prompt-preset/execution-tooling.js +5 -5
  93. package/dist/core/extensions/builtin/prompt-preset/glm-5.d.ts +1 -1
  94. package/dist/core/extensions/builtin/prompt-preset/glm-5.js +1 -1
  95. package/dist/core/extensions/builtin/terminal/extension.js +8 -1
  96. package/dist/core/extensions/builtin/terminal/notify.js +9 -3
  97. package/dist/core/extensions/builtin/terminal/prompt.d.ts +7 -1
  98. package/dist/core/extensions/builtin/terminal/prompt.js +27 -60
  99. package/dist/core/extensions/builtin/terminal/tools/bash.js +10 -2
  100. package/dist/core/extensions/builtin/todotools/normalize.d.ts +20 -3
  101. package/dist/core/extensions/builtin/todotools/normalize.js +251 -5
  102. package/dist/core/extensions/builtin/todotools/prompt.d.ts +2 -2
  103. package/dist/core/extensions/builtin/todotools/prompt.js +5 -5
  104. package/dist/core/extensions/builtin/todotools/tools/todo.js +9 -8
  105. package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +0 -5
  106. package/dist/core/extensions/builtin/websearch/index.js +9 -4
  107. package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts +2 -0
  108. package/dist/core/extensions/builtin/websearch/websearch/tool.js +3 -1
  109. package/dist/core/model-runtime.js +1 -1
  110. package/dist/core/provider-failure.d.ts +6 -0
  111. package/dist/core/provider-failure.js +6 -2
  112. package/dist/core/retry-fallback/exhaustion.d.ts +18 -0
  113. package/dist/core/retry-fallback/exhaustion.js +20 -0
  114. package/dist/core/system-prompt.js +1 -1
  115. package/dist/core/tools/bash.d.ts +3 -1
  116. package/dist/core/tools/bash.js +14 -4
  117. package/dist/core/tools/edit.d.ts +1 -1
  118. package/dist/core/tools/edit.js +1 -6
  119. package/dist/core/tools/grep/index.js +2 -3
  120. package/dist/core/tools/powershell.d.ts +1 -1
  121. package/dist/core/tools/powershell.js +1 -1
  122. package/dist/core/tools/read.d.ts +1 -1
  123. package/dist/core/tools/read.js +1 -1
  124. package/dist/core/tools/write.d.ts +1 -1
  125. package/dist/core/tools/write.js +1 -1
  126. package/dist/engine-trust/shell-trust.d.ts +36 -0
  127. package/dist/engine-trust/shell-trust.js +44 -0
  128. package/dist/engine-trust/transport-failure.d.ts +12 -0
  129. package/dist/engine-trust/transport-failure.js +48 -0
  130. package/dist/modes/interactive/interactive-mode.js +9 -3
  131. package/dist/modes/print-mode.js +2 -1
  132. package/dist/modes/rpc/compact-catalog-families.d.ts +5 -2
  133. package/dist/modes/rpc/compact-catalog-families.js +5 -2
  134. package/dist/modes/rpc/compact-catalog-registry.d.ts +9 -1
  135. package/dist/modes/rpc/compact-catalog-registry.js +9 -2
  136. package/dist/modes/rpc/compact-recovery-manifest-kinds.d.ts +17 -0
  137. package/dist/modes/rpc/compact-recovery-manifest-kinds.js +21 -0
  138. package/dist/modes/rpc/compact-recovery-manifest-shape.d.ts +7 -0
  139. package/dist/modes/rpc/compact-recovery-manifest.js +11 -3
  140. package/dist/modes/rpc/compact-socket-commands.js +6 -0
  141. package/dist/modes/rpc/connection-handler.js +21 -5
  142. package/dist/modes/rpc/connection-question-bridge.d.ts +3 -1
  143. package/dist/modes/rpc/connection-question-bridge.js +4 -1
  144. package/dist/modes/rpc/connection-roles.d.ts +8 -0
  145. package/dist/modes/rpc/connection-roles.js +18 -0
  146. package/dist/modes/rpc/method-classes-schema-session.d.ts +4 -0
  147. package/dist/modes/rpc/method-classes-schema-session.js +1 -0
  148. package/dist/modes/rpc/method-classes-schema.d.ts +4 -0
  149. package/dist/modes/rpc/protocol-identity.js +2 -0
  150. package/dist/modes/rpc/remote-origin.d.ts +31 -0
  151. package/dist/modes/rpc/remote-origin.js +58 -0
  152. package/dist/modes/rpc/rpc-protocol-info-types.d.ts +8 -0
  153. package/dist/modes/rpc/rpc-question-types.d.ts +7 -0
  154. package/dist/modes/rpc/rpc-question-types.js +0 -3
  155. package/dist/modes/rpc/rpc-session-command-types.d.ts +3 -0
  156. package/dist/modes/rpc/session-registry.js +12 -3
  157. package/dist/modes/rpc/session-worker-client.js +2 -0
  158. package/dist/modes/rpc/session-worker-protocol.d.ts +3 -0
  159. package/dist/modes/rpc/session-worker.js +2 -0
  160. package/docs/engine-socket/fixtures/admission-routes/c-baseline.json +3 -3
  161. package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
  162. package/docs/engine-socket/fixtures/admission-routes/i-reset-stream.json +3 -3
  163. package/docs/engine-socket/fixtures/recovery-manifest/index.json +32 -0
  164. package/docs/engine-socket/fixtures/recovery-manifest/one-partial-family.json +118 -0
  165. package/docs/rpc.md +93 -3
  166. package/package.json +6 -6
  167. package/dist/bundle/chunks/chunk-7UC4W2T2.js +0 -2
  168. package/dist/bundle/chunks/chunk-R23WXN4L.js +0 -448
  169. package/dist/bundle/chunks/chunk-W5NLCRB3.js +0 -2
@@ -1,3 +1,4 @@
1
+ import { type RpcRemoteOrigin } from "./remote-origin.ts";
1
2
  /**
2
3
  * Connection roles (senpi#3811): the capabilities that say who a connection speaks for, which is what
3
4
  * authority checks read. A role belongs to one connection, never to a session: a shared host serves every
@@ -16,12 +17,19 @@ export declare function roleConnection(connectionId: string | undefined): string
16
17
  export declare const CONNECTION_ROLE_FIXED = "connection_role_fixed: interactive_user and task_parent cannot change after they are declared";
17
18
  export declare class ConnectionRoles {
18
19
  private readonly declared;
20
+ private readonly origins;
19
21
  /** Records the roles a `set_client_info` carries; false when this connection already declared other roles. */
20
22
  declare(connectionId: string, capabilities: readonly string[]): boolean;
21
23
  /** The roles this connection explicitly declared, or undefined while it has declared none (no id = a stdio client). */
22
24
  rolesOf(connectionId: string | undefined): readonly string[] | undefined;
23
25
  /** Takes a declaration made elsewhere (the host, for a worker isolate) unless this connection already declared. */
24
26
  adopt(connectionId: string, roles: readonly string[]): void;
27
+ /** Whether `origin` may be declared for this connection: none yet, or the same one again (senpi#5475). */
28
+ acceptsOrigin(connectionId: string, origin: RpcRemoteOrigin): boolean;
29
+ /** Records the remote device a connection speaks for; call only after `acceptsOrigin` allowed it. */
30
+ declareOrigin(connectionId: string, origin: RpcRemoteOrigin): void;
31
+ /** The remote device this connection declared it speaks for, or undefined for a local connection. */
32
+ originOf(connectionId: string | undefined): RpcRemoteOrigin | undefined;
25
33
  has(connectionId: string | undefined, role: string): boolean;
26
34
  release(connectionId: string): void;
27
35
  /** Forgets every connection, for a worker isolate whose session ends. */
@@ -1,4 +1,5 @@
1
1
  import { INTERACTIVE_USER_CAPABILITY, TASK_PARENT_CAPABILITY } from "./custom-capability.js";
2
+ import { sameRemoteOrigin } from "./remote-origin.js";
2
3
  /**
3
4
  * Connection roles (senpi#3811): the capabilities that say who a connection speaks for, which is what
4
5
  * authority checks read. A role belongs to one connection, never to a session: a shared host serves every
@@ -20,6 +21,7 @@ export const CONNECTION_ROLE_FIXED = "connection_role_fixed: interactive_user an
20
21
  export class ConnectionRoles {
21
22
  constructor() {
22
23
  this.declared = new Map();
24
+ this.origins = new Map();
23
25
  }
24
26
  /** Records the roles a `set_client_info` carries; false when this connection already declared other roles. */
25
27
  declare(connectionId, capabilities) {
@@ -39,15 +41,31 @@ export class ConnectionRoles {
39
41
  if (!this.declared.has(connectionId))
40
42
  this.declared.set(connectionId, [...roles]);
41
43
  }
44
+ /** Whether `origin` may be declared for this connection: none yet, or the same one again (senpi#5475). */
45
+ acceptsOrigin(connectionId, origin) {
46
+ const prior = this.origins.get(connectionId);
47
+ return prior === undefined || sameRemoteOrigin(prior, origin);
48
+ }
49
+ /** Records the remote device a connection speaks for; call only after `acceptsOrigin` allowed it. */
50
+ declareOrigin(connectionId, origin) {
51
+ if (this.acceptsOrigin(connectionId, origin))
52
+ this.origins.set(connectionId, origin);
53
+ }
54
+ /** The remote device this connection declared it speaks for, or undefined for a local connection. */
55
+ originOf(connectionId) {
56
+ return this.origins.get(roleConnection(connectionId));
57
+ }
42
58
  has(connectionId, role) {
43
59
  return this.declared.get(roleConnection(connectionId))?.includes(role) ?? false;
44
60
  }
45
61
  release(connectionId) {
46
62
  this.declared.delete(connectionId);
63
+ this.origins.delete(connectionId);
47
64
  }
48
65
  /** Forgets every connection, for a worker isolate whose session ends. */
49
66
  clear() {
50
67
  this.declared.clear();
68
+ this.origins.clear();
51
69
  }
52
70
  }
53
71
  //# sourceMappingURL=connection-roles.js.map
@@ -923,6 +923,10 @@ export declare const SESSION_RECORD_SCHEMAS: {
923
923
  } & {
924
924
  readonly width: Type.TInteger;
925
925
  readonly capabilities: Type.TOptional<Type.TArray<Type.TString>>;
926
+ readonly remoteOrigin: Type.TOptional<Type.TObject<{
927
+ deviceId: Type.TString;
928
+ deviceName: Type.TOptional<Type.TString>;
929
+ }>>;
926
930
  }>;
927
931
  };
928
932
  //# sourceMappingURL=method-classes-schema-session.d.ts.map
@@ -198,6 +198,7 @@ const SURFACE_AND_ACCOUNT_SCHEMAS = {
198
198
  set_client_info: session("set_client_info", {
199
199
  width: Type.Integer({ minimum: 1, maximum: 100_000 }),
200
200
  capabilities: Opt(Strings),
201
+ remoteOrigin: Opt(Type.Object({ deviceId: Id, deviceName: OptId }, { additionalProperties: false })),
201
202
  }),
202
203
  };
203
204
  export const SESSION_RECORD_SCHEMAS = {
@@ -1268,6 +1268,10 @@ export declare const RPC_INBOUND_SCHEMAS: {
1268
1268
  } & {
1269
1269
  readonly width: import("typebox").TInteger;
1270
1270
  readonly capabilities: import("typebox").TOptional<import("typebox").TArray<import("typebox").TString>>;
1271
+ readonly remoteOrigin: import("typebox").TOptional<import("typebox").TObject<{
1272
+ deviceId: import("typebox").TString;
1273
+ deviceName: import("typebox").TOptional<import("typebox").TString>;
1274
+ }>>;
1271
1275
  }>;
1272
1276
  };
1273
1277
  export type RpcInboundValidation = {
@@ -19,6 +19,7 @@ import { parseArgs, resolveSessionRuntime } from "../../cli/args.js";
19
19
  import { getAgentDir } from "../../config.js";
20
20
  import { engineBuildIdentity } from "../../core/engine-build-identity.js";
21
21
  import { HOST_GENERATION_ENV, HOST_INSTANCE_ID_ENV } from "./host-identity-env.js";
22
+ import { RPC_METHOD_CLASSES_DIGEST, RPC_METHOD_CLASSES_VERSION } from "./method-classes.js";
22
23
  export { HOST_GENERATION_ENV, HOST_INSTANCE_ID_ENV };
23
24
  /** Identity of THIS host process, fixed for its lifetime. */
24
25
  const INSTANCE_ID = resolveInstanceId(process.env[HOST_INSTANCE_ID_ENV]);
@@ -69,6 +70,7 @@ export function protocolIdentity(agentDir = resolve(getAgentDir())) {
69
70
  engineOrdinal: build.ordinal,
70
71
  launch_profile: cachedProfile,
71
72
  agentDir,
73
+ method_classes: { version: RPC_METHOD_CLASSES_VERSION, digest: RPC_METHOD_CLASSES_DIGEST },
72
74
  };
73
75
  }
74
76
  //# sourceMappingURL=protocol-identity.js.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The remote device a connection speaks for (senpi#5475, omo-relay-daemon#184 P5).
3
+ *
4
+ * A relay forwarder opens one engine connection per remote sender and declares, through its own
5
+ * `set_client_info`, which device that connection speaks for. Every dialog a command of that connection raises
6
+ * then carries the value as `remoteOrigin`, so the host's desktop and TUI can label it "Requested from <device>".
7
+ * A connection that never declared one is local, and its dialogs carry no `remoteOrigin`. The engine copies only
8
+ * this declared value, never a free-form client name. `set_client_info` is `connection_local` in the method-class
9
+ * table, so a forwarded record can never set or change it.
10
+ */
11
+ export interface RpcRemoteOrigin {
12
+ readonly deviceId: string;
13
+ readonly deviceName?: string;
14
+ }
15
+ /**
16
+ * Validates a `set_client_info.remoteOrigin` against what the connection already declared, before anything of the
17
+ * declaration is committed: the origin to record (none when the field is absent), or the refusal to answer.
18
+ */
19
+ export declare function remoteOriginDeclaration(value: unknown, accepts: (origin: RpcRemoteOrigin) => boolean): {
20
+ readonly origin: RpcRemoteOrigin | undefined;
21
+ } | {
22
+ readonly refusal: string;
23
+ };
24
+ export declare function sameRemoteOrigin(a: RpcRemoteOrigin, b: RpcRemoteOrigin): boolean;
25
+ export declare function remoteOriginField(origin: RpcRemoteOrigin | undefined): {
26
+ remoteOrigin?: RpcRemoteOrigin;
27
+ };
28
+ export declare function originField(origin: RpcRemoteOrigin | undefined): {
29
+ origin?: RpcRemoteOrigin;
30
+ };
31
+ //# sourceMappingURL=remote-origin.d.ts.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The remote device a connection speaks for (senpi#5475, omo-relay-daemon#184 P5).
3
+ *
4
+ * A relay forwarder opens one engine connection per remote sender and declares, through its own
5
+ * `set_client_info`, which device that connection speaks for. Every dialog a command of that connection raises
6
+ * then carries the value as `remoteOrigin`, so the host's desktop and TUI can label it "Requested from <device>".
7
+ * A connection that never declared one is local, and its dialogs carry no `remoteOrigin`. The engine copies only
8
+ * this declared value, never a free-form client name. `set_client_info` is `connection_local` in the method-class
9
+ * table, so a forwarded record can never set or change it.
10
+ */
11
+ const MAX_DEVICE_ID_CHARACTERS = 256;
12
+ const MAX_DEVICE_NAME_CHARACTERS = 256;
13
+ const REMOTE_ORIGIN_INVALID = "remote_origin_invalid: remoteOrigin must be { deviceId: non-empty string, deviceName?: non-empty string }";
14
+ const REMOTE_ORIGIN_FIXED = "remote_origin_fixed: a connection's remoteOrigin cannot change after it is declared";
15
+ function boundedText(value, max) {
16
+ return typeof value === "string" && value.length > 0 && value.length <= max;
17
+ }
18
+ /** The declared origin, `undefined` when the field is absent, or `"invalid"` for any other shape. */
19
+ function parseRemoteOrigin(value) {
20
+ if (value === undefined)
21
+ return undefined;
22
+ if (typeof value !== "object" || value === null || Array.isArray(value))
23
+ return "invalid";
24
+ const deviceId = Reflect.get(value, "deviceId");
25
+ const deviceName = Reflect.get(value, "deviceName");
26
+ const keys = Object.keys(value);
27
+ if (keys.some((key) => key !== "deviceId" && key !== "deviceName"))
28
+ return "invalid";
29
+ if (!boundedText(deviceId, MAX_DEVICE_ID_CHARACTERS))
30
+ return "invalid";
31
+ if (deviceName === undefined)
32
+ return { deviceId };
33
+ if (!boundedText(deviceName, MAX_DEVICE_NAME_CHARACTERS))
34
+ return "invalid";
35
+ return { deviceId, deviceName };
36
+ }
37
+ /**
38
+ * Validates a `set_client_info.remoteOrigin` against what the connection already declared, before anything of the
39
+ * declaration is committed: the origin to record (none when the field is absent), or the refusal to answer.
40
+ */
41
+ export function remoteOriginDeclaration(value, accepts) {
42
+ const origin = parseRemoteOrigin(value);
43
+ if (origin === "invalid")
44
+ return { refusal: REMOTE_ORIGIN_INVALID };
45
+ if (origin !== undefined && !accepts(origin))
46
+ return { refusal: REMOTE_ORIGIN_FIXED };
47
+ return { origin };
48
+ }
49
+ export function sameRemoteOrigin(a, b) {
50
+ return a.deviceId === b.deviceId && a.deviceName === b.deviceName;
51
+ }
52
+ export function remoteOriginField(origin) {
53
+ return origin === undefined ? {} : { remoteOrigin: origin };
54
+ }
55
+ export function originField(origin) {
56
+ return origin === undefined ? {} : { origin };
57
+ }
58
+ //# sourceMappingURL=remote-origin.js.map
@@ -33,6 +33,14 @@ export interface RpcProtocolIdentity {
33
33
  readonly launch_profile: RpcLaunchProfile;
34
34
  /** Absolute agent directory this host reads and writes; a handoff from another agent dir is refused. */
35
35
  readonly agentDir: string;
36
+ /**
37
+ * The inbound method-class table this engine runs (`method-classes.ts`): a remote forwarder classifies with its
38
+ * own copy only while that copy's digest equals `digest`.
39
+ */
40
+ readonly method_classes: {
41
+ readonly version: number;
42
+ readonly digest: string;
43
+ };
36
44
  }
37
45
  export interface RpcProtocolInfo extends RpcProtocolIdentity {
38
46
  /** Present only on a public POSIX endpoint's answer to a challenge (wire contract v1.1). */
@@ -1,3 +1,4 @@
1
+ import type { RpcRemoteOrigin } from "./remote-origin.ts";
1
2
  /** One question in an RPC `question` UI request. Matches canonical QuestionRequest.questions. */
2
3
  export type RpcQuestionSpec = {
3
4
  id: string;
@@ -25,6 +26,8 @@ export type RpcQuestionUiRequest = {
25
26
  questions: RpcQuestionSpec[];
26
27
  /** The connection whose command raised the question, or `"agent"` when no connection's command was dispatching. */
27
28
  raisedBy?: string;
29
+ /** The remote device the raising connection speaks for (senpi#5475); absent for a local connection. */
30
+ remoteOrigin?: RpcRemoteOrigin;
28
31
  timeout: number;
29
32
  askedAtMs: number;
30
33
  deadlineAtMs: number;
@@ -35,6 +38,7 @@ export type RpcExtensionUIRequest = {
35
38
  type: "extension_ui_request";
36
39
  id: string;
37
40
  method: "select";
41
+ remoteOrigin?: RpcRemoteOrigin;
38
42
  /** Permanent MCP env grant; only a grant_select presentation may answer. */
39
43
  grantSelect?: boolean;
40
44
  title: string;
@@ -50,10 +54,12 @@ export type RpcExtensionUIRequest = {
50
54
  title: string;
51
55
  message: string;
52
56
  timeout?: number;
57
+ remoteOrigin?: RpcRemoteOrigin;
53
58
  } | {
54
59
  type: "extension_ui_request";
55
60
  id: string;
56
61
  method: "input";
62
+ remoteOrigin?: RpcRemoteOrigin;
57
63
  secret?: boolean;
58
64
  deadlineAtMs?: number;
59
65
  title: string;
@@ -67,6 +73,7 @@ export type RpcExtensionUIRequest = {
67
73
  method: "editor";
68
74
  title: string;
69
75
  prefill?: string;
76
+ remoteOrigin?: RpcRemoteOrigin;
70
77
  } | {
71
78
  type: "extension_ui_request";
72
79
  id: string;
@@ -1,5 +1,2 @@
1
- // ============================================================================
2
- // Extension UI Events (stdout)
3
- // ============================================================================
4
1
  export {};
5
2
  //# sourceMappingURL=rpc-question-types.js.map
@@ -6,6 +6,7 @@ import type { ClientMessageIdentity } from "../../core/client-message-identity.t
6
6
  import type { SessionEntry } from "../../core/session-manager.ts";
7
7
  import type { ToolBarrierSpec } from "../../core/tool-barrier.ts";
8
8
  import type { RpcRecoveryCommand } from "./rpc-recovery-command-types.ts";
9
+ import type { RpcRemoteOrigin } from "./remote-origin.ts";
9
10
  import type { RpcSessionModelEntry } from "./rpc-session-state-types.ts";
10
11
  export type RpcSessionCommand = {
11
12
  id?: string;
@@ -521,6 +522,8 @@ export type RpcSessionCommand = {
521
522
  type: "set_client_info";
522
523
  width: number;
523
524
  capabilities?: string[];
525
+ /** Declared by a relay forwarder for the remote device this connection speaks for (senpi#5475). */
526
+ remoteOrigin?: RpcRemoteOrigin;
524
527
  };
525
528
  /** What `steer`/`follow_up` do on an idle session: queue (default) or start a turn. */
526
529
  export type RpcWhenIdle = "queue" | "start";
@@ -4,7 +4,7 @@ import { createRegistryWarm } from "./host-warm.js";
4
4
  import { refreshesSessionActivity } from "./session-command-activity.js";
5
5
  import { publishedSessionContext } from "./session-context-patch.js";
6
6
  import { attachLiveSession, markPathAttached } from "./session-live-attachment.js";
7
- import { syncRuntimeMetadata } from "./session-registry-claims.js";
7
+ import { beginPendingClaim, syncRuntimeMetadata } from "./session-registry-claims.js";
8
8
  import { openRegistrySession } from "./session-registry-open.js";
9
9
  import { RpcSessionRegistryError, } from "./session-registry-types.js";
10
10
  import { beginSessionClose, closeMarkedSession, closeSession } from "./session-teardown.js";
@@ -44,8 +44,17 @@ export class RpcSessionRegistry {
44
44
  return deleted;
45
45
  },
46
46
  releaseReservation: async (key) => {
47
- await this.options.pathReservations?.release(key);
48
- this.reservations.delete(key);
47
+ // Close may finish at its grace deadline before removal settles. Keep
48
+ // that work visible to reopen even after the closing entry is gone. A failed removal
49
+ // still gives the path back: no entry is left to ever release it later.
50
+ const settle = beginPendingClaim(this.pendingClaims, key);
51
+ try {
52
+ await this.options.pathReservations?.release(key);
53
+ }
54
+ finally {
55
+ this.reservations.delete(key);
56
+ settle();
57
+ }
49
58
  },
50
59
  markDetached: (key) => this.options.pathReservations?.setAttached(key, false),
51
60
  now: () => this.now(),
@@ -5,6 +5,7 @@ import { createWebViewBroker } from "../../core/webview/webview-broker.js";
5
5
  import { workerCapabilities } from "./worker-client-capabilities.js";
6
6
  import { captureAdmissionReply, withAdmissionReply } from "./compact-admission-reply.js";
7
7
  import { roleConnection } from "./connection-roles.js";
8
+ import { originField } from "./remote-origin.js";
8
9
  import { answeredUiRequestId, isGrantSelectRequest, refusedExtensionUiResponse } from "./extension-ui-response.js";
9
10
  import { enqueueLegacyRecord } from "./legacy-record-depth.js";
10
11
  import { SessionAcceptanceLane } from "./session-acceptance-lane.js";
@@ -199,6 +200,7 @@ export class SessionWorkerClient {
199
200
  command,
200
201
  connection,
201
202
  roles: options.connectionRoles?.rolesOf(roleConnection(connection)),
203
+ ...originField(options.connectionRoles?.originOf(connection)),
202
204
  ...(owner === undefined ? {} : { owner }),
203
205
  });
204
206
  },
@@ -1,3 +1,4 @@
1
+ import type { RpcRemoteOrigin } from "./remote-origin.ts";
1
2
  import type { BrowserEngine } from "../../core/browser-engine.ts";
2
3
  import type { McpFormInput, McpFormOutcome } from "../../core/mcp-form-types.ts";
3
4
  import type { RecoveryCarrier } from "../../core/session-recovery-identity.ts";
@@ -96,6 +97,8 @@ export type HostToSessionWorker = {
96
97
  command: object;
97
98
  connection?: string;
98
99
  roles?: readonly string[];
100
+ /** The remote device the connection declared on the host (senpi#5475); the isolate adopts it. */
101
+ origin?: RpcRemoteOrigin;
99
102
  /** The gate the host captured at ingress, before its first await (#4728). */
100
103
  owner?: ExtensionOwnerWire;
101
104
  }
@@ -338,6 +338,8 @@ async function handle(message) {
338
338
  throw new Error("session_closing");
339
339
  if (message.roles !== undefined)
340
340
  connectionRoles.adopt(roleConnection(message.connection), message.roles);
341
+ if (message.origin !== undefined)
342
+ connectionRoles.declareOrigin(roleConnection(message.connection), message.origin);
341
343
  const activeBinding = binding;
342
344
  const run = () => activeBinding.handle(message.command);
343
345
  await workerAdmissionCommand(message, writer, issuedOwners, run);
@@ -43,9 +43,9 @@
43
43
  "hint": "restart_from_catalog",
44
44
  "retryAfterMs": 0
45
45
  },
46
- "length": 1000,
47
- "digest": "131dc6a4a4e49873ce5d5d0330f81816be72c8a12c25dec7d14d4fe2c9cc32e4",
48
- "bytes": "ewAiAGYAbwByAG0AYQB0ACIAOgAiAHMAZQBuAHAAaQAtAHIAZQBjAG8AdgBlAHIAeQAtAG0AYQBuAGkAZgBlAHMAdAAiACwAIgB2AGUAcgBzAGkAbwBuACIAOgAxACwAIgBzAG8AYwBrAGUAdABFAHAAbwBjAGgAIgA6AHsAIgBpAGQAIgA6ACIAcwBvAGMAawBlAHQALQAxACIAfQAsACIAYQBkAG0AaQBzAHMAaQBvAG4ASQBkACIAOgB7ACIAaQBkACIAOgAiAGcAbwBsAGQAZQBuAC0AYQAiAH0ALAAiAHIAbwB1AHQAZQBLAGkAbgBkACIAOgAiAG8AcgBkAGkAbgBhAHIAeQAiACwAIgBzAGUAcwBzAGkAbwBuACIAOgB7ACIAaQBkACIAOgAiAHIAcABjAC0AMQAiAH0ALAAiAHMAZQBzAHMAaQBvAG4ARQBwAG8AYwBoACIAOgB7ACIAaQBkACIAOgAiADAAMAAwADAAMAAwADAAMAAtADAAMAAwADAALQA0ADAAMAAwAC0AOAAwADAAMAAtADAAMAAwADAAMAAwADAAMAAwADAAMAAxACIAfQAsACIAZwBlAG4AZQByAGEAdABpAG8AbgAiADoAMQAsACIAcwBlAHEAdQBlAG4AYwBlACIAOgAwACwAIgBoAGkAcwB0AG8AcgB5AFYAZQByAHMAaQBvAG4AIgA6ADUALAAiAHQAbwBrAGUAbgAiADoAewAiAGkAZAAiADoAIgBzAG8AYwBrAGUAdAAtADEAOgAxACIAfQAsACIAbABlAGEAZgAiADoAewAiAGkAZAAiADoAIgAwADAAMAAwADAAMAAwADEAIgB9ACwAIgBhAGMAdABpAHYAZQBNAGUAcwBzAGEAZwBlACIAOgBuAHUAbABsACwAIgB0AHUAcgBuACIAOgBuAHUAbABsACwAIgBjAGgAZQBjAGsAcABvAGkAbgB0AEQAaQBnAGUAcwB0ACIAOgAiADEAYgBiAGMAYQBkADIAOQAzADIAMABmADIAMAA4ADQANwBhADUAMQA1AGMAYwA4ADUANAAwADYAMwBjAGQAYQAwAGQAZABhAGUAYQAyADAAYwBkAGMAZgBmADQANQBlAGIANgBiADUAZQAwAGUAOQBlAGUAMQA1AGYAYgBkADQAIgAsACIAYwBhAHQAYQBsAG8AZwBSAG8AbwB0ACIAOgAiAGMALQAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAxACIALAAiAGMAYQB0AGEAbABvAGcAUgBvAG8AdABMAGUAbgBnAHQAaAAiADoAMwA5ADQANgB9AA=="
46
+ "length": 1230,
47
+ "digest": "afc0506ef0b5e09ae70818c0b435b2fa633d3536d44f6e357950aad78d0102f9",
48
+ "bytes": "ewAiAGYAbwByAG0AYQB0ACIAOgAiAHMAZQBuAHAAaQAtAHIAZQBjAG8AdgBlAHIAeQAtAG0AYQBuAGkAZgBlAHMAdAAiACwAIgB2AGUAcgBzAGkAbwBuACIAOgAxACwAIgBzAG8AYwBrAGUAdABFAHAAbwBjAGgAIgA6AHsAIgBpAGQAIgA6ACIAcwBvAGMAawBlAHQALQAxACIAfQAsACIAYQBkAG0AaQBzAHMAaQBvAG4ASQBkACIAOgB7ACIAaQBkACIAOgAiAGcAbwBsAGQAZQBuAC0AYQAiAH0ALAAiAHIAbwB1AHQAZQBLAGkAbgBkACIAOgAiAG8AcgBkAGkAbgBhAHIAeQAiACwAIgBzAGUAcwBzAGkAbwBuACIAOgB7ACIAaQBkACIAOgAiAHIAcABjAC0AMQAiAH0ALAAiAHMAZQBzAHMAaQBvAG4ARQBwAG8AYwBoACIAOgB7ACIAaQBkACIAOgAiADAAMAAwADAAMAAwADAAMAAtADAAMAAwADAALQA0ADAAMAAwAC0AOAAwADAAMAAtADAAMAAwADAAMAAwADAAMAAwADAAMAAxACIAfQAsACIAZwBlAG4AZQByAGEAdABpAG8AbgAiADoAMQAsACIAcwBlAHEAdQBlAG4AYwBlACIAOgAwACwAIgBoAGkAcwB0AG8AcgB5AFYAZQByAHMAaQBvAG4AIgA6ADUALAAiAHQAbwBrAGUAbgAiADoAewAiAGkAZAAiADoAIgBzAG8AYwBrAGUAdAAtADEAOgAxACIAfQAsACIAbABlAGEAZgAiADoAewAiAGkAZAAiADoAIgAwADAAMAAwADAAMAAwADEAIgB9ACwAIgBhAGMAdABpAHYAZQBNAGUAcwBzAGEAZwBlACIAOgBuAHUAbABsACwAIgB0AHUAcgBuACIAOgBuAHUAbABsACwAIgBjAGgAZQBjAGsAcABvAGkAbgB0AEQAaQBnAGUAcwB0ACIAOgAiADEAYgBiAGMAYQBkADIAOQAzADIAMABmADIAMAA4ADQANwBhADUAMQA1AGMAYwA4ADUANAAwADYAMwBjAGQAYQAwAGQAZABhAGUAYQAyADAAYwBkAGMAZgBmADQANQBlAGIANgBiADUAZQAwAGUAOQBlAGUAMQA1AGYAYgBkADQAIgAsACIAYwBhAHQAYQBsAG8AZwBSAG8AbwB0ACIAOgAiAGMALQAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAxACIALAAiAGMAYQB0AGEAbABvAGcAUgBvAG8AdABMAGUAbgBnAHQAaAAiADoAMwA5ADQANgAsACIAcgBlAHEAdQBpAHIAZQBkAEsAaQBuAGQAcwAiADoAWwAiAGEAYwB0AGkAdgBlACIALAAiAGMAYQBsAGwAcwAiACwAIgBkAGkAYQBsAG8AZwBzACIALAAiAGkAZABlAG4AdABpAHQAeQAiACwAIgBsAGkAZgBlAGMAeQBjAGwAZQAiACwAIgBvAHAAYQBxAHUAZQAiACwAIgByAHUAbgAiACwAIgBzAGUAdAB0AGwAZQBkACIALAAiAHMAbwB1AHIAYwBlACIALAAiAHQAcgBhAG4AcwBjAHIAaQBwAHQAIgBdAH0A"
49
49
  }
50
50
  }
51
51
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "rpcClientRequests": "{\"type\":\"get_protocol_info\",\"id\":\"rpc-auth-protocol\",\"observe\":true,\"auth\":{\"client_nonce\":\"<public-nonce>\"}}\n{\"type\":\"set_client_info\",\"width\":100,\"capabilities\":[],\"id\":\"req_1\"}\n{\"type\":\"open_session\",\"cwd\":\"<root>/cwd\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"id\":\"req_2\"}\n{\"type\":\"get_entries\",\"sessionId\":\"rpc-1\",\"id\":\"req_3\"}\n{\"type\":\"close_session\",\"sessionId\":\"rpc-1\",\"id\":\"req_4\"}\n",
3
- "rpcClientFrames": "{\"id\":\"rpc-auth-protocol\",\"type\":\"response\",\"command\":\"get_protocol_info\",\"success\":true,\"data\":{\"protocolVersion\":1,\"serverVersion\":\"<server-version>\",\"capabilities\":[\"<capabilities>\"],\"mode\":\"multi\",\"instanceId\":\"<uuid-1>\",\"generation\":0,\"engineVersion\":\"<server-version>\",\"engineOrdinal\":\"<engine-ordinal>\",\"launch_profile\":{\"profile_id\":\"ca7a49435f02009fdda5dac49d29408dcfeb1ab5374353784c5a9def467f5be1\",\"core\":{\"extensions\":[],\"multi_session\":false,\"session_runtime\":\"worker\"}},\"agentDir\":\"<root>/agent\",\"memory_pressure\":false,\"path_identity_resolver\":{\"state\":\"not_started\",\"detail\":null}}}\n{\"id\":\"req_1\",\"type\":\"response\",\"command\":\"set_client_info\",\"success\":true}\n{\"type\":\"queued\",\"for_request\":\"req_2\",\"position\":1,\"in_flight\":0}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-2>\",\"method\":\"setWidget\",\"widgetKey\":\"todo-sidebar\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-3>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-4>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-5>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-6>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-7>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-8>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-9>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-10>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-11>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"entry_appended\",\"entry\":{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-12>\",\"method\":\"setStatus\",\"statusKey\":\"todo-waiting\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-13>\",\"method\":\"setStatus\",\"statusKey\":\"goal\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_opened\",\"sessionId\":\"rpc-1\",\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\"}\n{\"id\":\"req_2\",\"type\":\"response\",\"command\":\"open_session\",\"success\":true,\"data\":{\"sessionId\":\"rpc-1\",\"state\":{\"answeredUiRequests\":[],\"paused\":false,\"pausedNoticeCount\":0,\"holds\":[],\"lifecycle\":{\"state\":\"done\",\"seq\":0,\"epoch\":0,\"epochOrigin\":\"automatic\",\"humanInputRevision\":0,\"selfSettleEligible\":true,\"restoring\":false,\"persisted\":false,\"runPaused\":false,\"since\":\"2026-10-29T00:00:00.000Z\",\"role\":\"root\",\"rootSessionId\":\"<uuid-14>\",\"activityRevision\":{\"instanceId\":\"<uuid-15>\",\"revision\":0},\"waitingOn\":{\"children\":0,\"background\":[],\"human\":[]},\"holds\":[],\"observedAt\":\"2026-10-29T00:00:00.000Z\"},\"pendingQuestions\":[],\"pendingDialogs\":[],\"model\":{\"id\":\"faux-a\",\"name\":\"faux-a\",\"api\":\"faux:fixture\",\"provider\":\"faux\",\"baseUrl\":\"http://localhost:0\",\"reasoning\":false,\"input\":[\"text\",\"image\"],\"cost\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0},\"contextWindow\":128000,\"maxTokens\":16384},\"pendingModelSwitch\":null,\"thinkingLevel\":\"off\",\"thinkingLevelSource\":\"default\",\"sessionModelThinkingLevels\":{\"faux/faux-a\":\"off\"},\"fastMode\":false,\"isStreaming\":false,\"pausedHeldInputCount\":0,\"runPaused\":false,\"pause\":{\"pauseSeq\":0,\"records\":[]},\"isCompacting\":false,\"retryAttempt\":0,\"isBashRunning\":false,\"steeringMode\":\"all\",\"followUpMode\":\"one-at-a-time\",\"sessionFile\":\"<root>/cwd/session.jsonl\",\"sessionId\":\"<uuid-14>\",\"cwd\":\"<root>/cwd\",\"projectTrusted\":false,\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"steering\":[],\"followUp\":[],\"ordered\":[],\"autoCompactionEnabled\":true,\"messageCount\":0,\"pendingMessageCount\":0,\"usageTotals\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0,\"cost\":0},\"contextUsage\":{\"tokens\":0,\"contextWindow\":128000,\"percent\":0},\"favoriteModels\":[],\"scopedModels\":[]}},\"sessionId\":\"rpc-1\"}\n{\"id\":\"req_3\",\"type\":\"response\",\"command\":\"get_entries\",\"success\":true,\"data\":{\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"leafId\":\"<entry-1>\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_closed\",\"sessionId\":\"rpc-1\",\"reason\":\"client_close\"}\n{\"id\":\"req_4\",\"type\":\"response\",\"command\":\"close_session\",\"success\":true,\"data\":{},\"sessionId\":\"rpc-1\"}\n",
3
+ "rpcClientFrames": "{\"id\":\"rpc-auth-protocol\",\"type\":\"response\",\"command\":\"get_protocol_info\",\"success\":true,\"data\":{\"protocolVersion\":1,\"serverVersion\":\"<server-version>\",\"capabilities\":[\"<capabilities>\"],\"mode\":\"multi\",\"instanceId\":\"<uuid-1>\",\"generation\":0,\"engineVersion\":\"<server-version>\",\"engineOrdinal\":\"<engine-ordinal>\",\"launch_profile\":{\"profile_id\":\"ca7a49435f02009fdda5dac49d29408dcfeb1ab5374353784c5a9def467f5be1\",\"core\":{\"extensions\":[],\"multi_session\":false,\"session_runtime\":\"worker\"}},\"agentDir\":\"<root>/agent\",\"method_classes\":{\"version\":1,\"digest\":\"71d6846585dffea212d60019e24296f5cd2882c0e8ff54b4d6e40cef3945b80a\"},\"memory_pressure\":false,\"path_identity_resolver\":{\"state\":\"not_started\",\"detail\":null}}}\n{\"id\":\"req_1\",\"type\":\"response\",\"command\":\"set_client_info\",\"success\":true}\n{\"type\":\"queued\",\"for_request\":\"req_2\",\"position\":1,\"in_flight\":0}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-2>\",\"method\":\"setWidget\",\"widgetKey\":\"todo-sidebar\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-3>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-4>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-5>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-6>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-7>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-8>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-9>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-10>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-11>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"entry_appended\",\"entry\":{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-12>\",\"method\":\"setStatus\",\"statusKey\":\"todo-waiting\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-13>\",\"method\":\"setStatus\",\"statusKey\":\"goal\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_opened\",\"sessionId\":\"rpc-1\",\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\"}\n{\"id\":\"req_2\",\"type\":\"response\",\"command\":\"open_session\",\"success\":true,\"data\":{\"sessionId\":\"rpc-1\",\"state\":{\"answeredUiRequests\":[],\"paused\":false,\"pausedNoticeCount\":0,\"holds\":[],\"lifecycle\":{\"state\":\"done\",\"seq\":0,\"epoch\":0,\"epochOrigin\":\"automatic\",\"humanInputRevision\":0,\"selfSettleEligible\":true,\"restoring\":false,\"persisted\":false,\"runPaused\":false,\"since\":\"2026-10-29T00:00:00.000Z\",\"role\":\"root\",\"rootSessionId\":\"<uuid-14>\",\"activityRevision\":{\"instanceId\":\"<uuid-15>\",\"revision\":0},\"waitingOn\":{\"children\":0,\"background\":[],\"human\":[]},\"holds\":[],\"observedAt\":\"2026-10-29T00:00:00.000Z\"},\"pendingQuestions\":[],\"pendingDialogs\":[],\"model\":{\"id\":\"faux-a\",\"name\":\"faux-a\",\"api\":\"faux:fixture\",\"provider\":\"faux\",\"baseUrl\":\"http://localhost:0\",\"reasoning\":false,\"input\":[\"text\",\"image\"],\"cost\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0},\"contextWindow\":128000,\"maxTokens\":16384},\"pendingModelSwitch\":null,\"thinkingLevel\":\"off\",\"thinkingLevelSource\":\"default\",\"sessionModelThinkingLevels\":{\"faux/faux-a\":\"off\"},\"fastMode\":false,\"isStreaming\":false,\"pausedHeldInputCount\":0,\"runPaused\":false,\"pause\":{\"pauseSeq\":0,\"records\":[]},\"isCompacting\":false,\"retryAttempt\":0,\"isBashRunning\":false,\"steeringMode\":\"all\",\"followUpMode\":\"one-at-a-time\",\"sessionFile\":\"<root>/cwd/session.jsonl\",\"sessionId\":\"<uuid-14>\",\"cwd\":\"<root>/cwd\",\"projectTrusted\":false,\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"steering\":[],\"followUp\":[],\"ordered\":[],\"autoCompactionEnabled\":true,\"messageCount\":0,\"pendingMessageCount\":0,\"usageTotals\":{\"input\":0,\"output\":0,\"cacheRead\":0,\"cacheWrite\":0,\"cost\":0},\"contextUsage\":{\"tokens\":0,\"contextWindow\":128000,\"percent\":0},\"favoriteModels\":[],\"scopedModels\":[]}},\"sessionId\":\"rpc-1\"}\n{\"id\":\"req_3\",\"type\":\"response\",\"command\":\"get_entries\",\"success\":true,\"data\":{\"entries\":[{\"type\":\"model_change\",\"id\":\"<entry-3>\",\"parentId\":null,\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"thinking_level_change\",\"id\":\"<entry-2>\",\"parentId\":\"<entry-3>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\",\"thinkingLevel\":\"off\",\"provider\":\"faux\",\"modelId\":\"faux-a\"},{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"}],\"leafId\":\"<entry-1>\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_closed\",\"sessionId\":\"rpc-1\",\"reason\":\"client_close\"}\n{\"id\":\"req_4\",\"type\":\"response\",\"command\":\"close_session\",\"success\":true,\"data\":{},\"sessionId\":\"rpc-1\"}\n",
4
4
  "subscribeRequests": "{\"type\":\"subscribe_sessions\",\"mirror\":\"all\",\"id\":\"subscriber-1\"}\n{\"type\":\"unsubscribe_sessions\",\"subscriptionId\":\"sub-1\",\"id\":\"subscriber-2\"}\n",
5
5
  "subscribeFrames": "{\"id\":\"subscriber-1\",\"type\":\"response\",\"command\":\"subscribe_sessions\",\"success\":true,\"data\":{\"subscriptionId\":\"sub-1\",\"snapshot\":[],\"seq\":0,\"hostGeneration\":\"0\",\"hostInstanceId\":\"<uuid-1>\"}}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-2>\",\"method\":\"setWidget\",\"widgetKey\":\"todo-sidebar\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-3>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-4>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-5>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-6>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-7>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-8>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-9>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-10>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-11>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"entry_appended\",\"entry\":{\"type\":\"custom\",\"customType\":\"pi-rules.scan\",\"data\":{\"cwd\":\"<root>/cwd\",\"reason\":\"startup\"},\"startupBookkeeping\":true,\"id\":\"<entry-1>\",\"parentId\":\"<entry-2>\",\"timestamp\":\"2026-10-29T00:00:00.000Z\"},\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-12>\",\"method\":\"setStatus\",\"statusKey\":\"todo-waiting\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-13>\",\"method\":\"setStatus\",\"statusKey\":\"goal\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_opened\",\"sessionId\":\"rpc-1\",\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\"}\n{\"type\":\"session_status\",\"subscriptionId\":\"sub-1\",\"seq\":1,\"sessionId\":\"rpc-1\",\"status\":\"idle\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\",\"attachments\":1,\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"model\":{\"provider\":\"faux\",\"id\":\"faux-a\"},\"thinkingLevel\":\"off\",\"pendingQueue\":{\"steering\":0,\"followUp\":0},\"lastChange\":{\"at\":\"2026-10-29T00:00:00.000Z\",\"cause\":\"open\",\"by\":\"client\"}}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-15>\",\"method\":\"setStatus\",\"statusKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-16>\",\"method\":\"setWidget\",\"widgetKey\":\"anthropic-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-17>\",\"method\":\"setStatus\",\"statusKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-18>\",\"method\":\"setWidget\",\"widgetKey\":\"openai-web-search\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-19>\",\"method\":\"setStatus\",\"statusKey\":\"monitors\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-20>\",\"method\":\"setStatus\",\"statusKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-21>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-websearch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-22>\",\"method\":\"setStatus\",\"statusKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-23>\",\"method\":\"setWidget\",\"widgetKey\":\"pi-webfetch\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"extension_ui_request\",\"id\":\"<uuid-24>\",\"method\":\"setStatus\",\"statusKey\":\"loop\",\"sessionId\":\"rpc-1\"}\n{\"type\":\"session_closed\",\"sessionId\":\"rpc-1\",\"reason\":\"client_close\"}\n{\"type\":\"session_status\",\"subscriptionId\":\"sub-1\",\"seq\":2,\"sessionId\":\"rpc-1\",\"status\":\"closed\",\"reason\":\"client_close\",\"kind\":\"interactive\",\"cwd\":\"<root>/cwd\",\"attachments\":1,\"durableSessionId\":\"<uuid-14>\",\"sessionPath\":\"<root>/cwd/session.jsonl\",\"model\":{\"provider\":\"faux\",\"id\":\"faux-a\"},\"thinkingLevel\":\"off\",\"pendingQueue\":{\"steering\":0,\"followUp\":0},\"lastChange\":{\"at\":\"2026-10-29T00:00:00.000Z\",\"cause\":\"close\",\"by\":\"client\"}}\n{\"id\":\"subscriber-2\",\"type\":\"response\",\"command\":\"unsubscribe_sessions\",\"success\":true}\n"
6
6
  }
@@ -96,9 +96,9 @@
96
96
  "hint": "restart_from_catalog",
97
97
  "retryAfterMs": 0
98
98
  },
99
- "length": 1002,
100
- "digest": "da9d59636ee8bfe743c733edef30b3a6f92c420a3c2b77f89807124ec5f50f6e",
101
- "bytes": "ewAiAGYAbwByAG0AYQB0ACIAOgAiAHMAZQBuAHAAaQAtAHIAZQBjAG8AdgBlAHIAeQAtAG0AYQBuAGkAZgBlAHMAdAAiACwAIgB2AGUAcgBzAGkAbwBuACIAOgAxACwAIgBzAG8AYwBrAGUAdABFAHAAbwBjAGgAIgA6AHsAIgBpAGQAIgA6ACIAcwBvAGMAawBlAHQALQAxACIAfQAsACIAYQBkAG0AaQBzAHMAaQBvAG4ASQBkACIAOgB7ACIAaQBkACIAOgAiAGcAbwBsAGQAZQBuAC0AaQAiAH0ALAAiAHIAbwB1AHQAZQBLAGkAbgBkACIAOgAiAG8AcgBkAGkAbgBhAHIAeQAiACwAIgBzAGUAcwBzAGkAbwBuACIAOgB7ACIAaQBkACIAOgAiAHIAcABjAC0AMQAiAH0ALAAiAHMAZQBzAHMAaQBvAG4ARQBwAG8AYwBoACIAOgB7ACIAaQBkACIAOgAiADAAMAAwADAAMAAwADAAMAAtADAAMAAwADAALQA0ADAAMAAwAC0AOAAwADAAMAAtADAAMAAwADAAMAAwADAAMAAwADAAMAAxACIAfQAsACIAZwBlAG4AZQByAGEAdABpAG8AbgAiADoAMgAsACIAcwBlAHEAdQBlAG4AYwBlACIAOgAxADQALAAiAGgAaQBzAHQAbwByAHkAVgBlAHIAcwBpAG8AbgAiADoANgAsACIAdABvAGsAZQBuACIAOgB7ACIAaQBkACIAOgAiAHMAbwBjAGsAZQB0AC0AMQA6ADIAIgB9ACwAIgBsAGUAYQBmACIAOgB7ACIAaQBkACIAOgAiADAAMAAwADAAMAAwADAAMQAiAH0ALAAiAGEAYwB0AGkAdgBlAE0AZQBzAHMAYQBnAGUAIgA6AG4AdQBsAGwALAAiAHQAdQByAG4AIgA6AG4AdQBsAGwALAAiAGMAaABlAGMAawBwAG8AaQBuAHQARABpAGcAZQBzAHQAIgA6ACIAMQBiAGIAYwBhAGQAMgA5ADMAMgAwAGYAMgAwADgANAA3AGEANQAxADUAYwBjADgANQA0ADAANgAzAGMAZABhADAAZABkAGEAZQBhADIAMABjAGQAYwBmAGYANAA1AGUAYgA2AGIANQBlADAAZQA5AGUAZQAxADUAZgBiAGQANAAiACwAIgBjAGEAdABhAGwAbwBnAFIAbwBvAHQAIgA6ACIAYwAtADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADEAIgAsACIAYwBhAHQAYQBsAG8AZwBSAG8AbwB0AEwAZQBuAGcAdABoACIAOgA0ADUAMAAyAH0A"
99
+ "length": 1232,
100
+ "digest": "d78530753a0e52e3f73d2a204dc0cd2b77656535adb7b14da8b8176d53eac997",
101
+ "bytes": "ewAiAGYAbwByAG0AYQB0ACIAOgAiAHMAZQBuAHAAaQAtAHIAZQBjAG8AdgBlAHIAeQAtAG0AYQBuAGkAZgBlAHMAdAAiACwAIgB2AGUAcgBzAGkAbwBuACIAOgAxACwAIgBzAG8AYwBrAGUAdABFAHAAbwBjAGgAIgA6AHsAIgBpAGQAIgA6ACIAcwBvAGMAawBlAHQALQAxACIAfQAsACIAYQBkAG0AaQBzAHMAaQBvAG4ASQBkACIAOgB7ACIAaQBkACIAOgAiAGcAbwBsAGQAZQBuAC0AaQAiAH0ALAAiAHIAbwB1AHQAZQBLAGkAbgBkACIAOgAiAG8AcgBkAGkAbgBhAHIAeQAiACwAIgBzAGUAcwBzAGkAbwBuACIAOgB7ACIAaQBkACIAOgAiAHIAcABjAC0AMQAiAH0ALAAiAHMAZQBzAHMAaQBvAG4ARQBwAG8AYwBoACIAOgB7ACIAaQBkACIAOgAiADAAMAAwADAAMAAwADAAMAAtADAAMAAwADAALQA0ADAAMAAwAC0AOAAwADAAMAAtADAAMAAwADAAMAAwADAAMAAwADAAMAAxACIAfQAsACIAZwBlAG4AZQByAGEAdABpAG8AbgAiADoAMgAsACIAcwBlAHEAdQBlAG4AYwBlACIAOgAxADQALAAiAGgAaQBzAHQAbwByAHkAVgBlAHIAcwBpAG8AbgAiADoANgAsACIAdABvAGsAZQBuACIAOgB7ACIAaQBkACIAOgAiAHMAbwBjAGsAZQB0AC0AMQA6ADIAIgB9ACwAIgBsAGUAYQBmACIAOgB7ACIAaQBkACIAOgAiADAAMAAwADAAMAAwADAAMQAiAH0ALAAiAGEAYwB0AGkAdgBlAE0AZQBzAHMAYQBnAGUAIgA6AG4AdQBsAGwALAAiAHQAdQByAG4AIgA6AG4AdQBsAGwALAAiAGMAaABlAGMAawBwAG8AaQBuAHQARABpAGcAZQBzAHQAIgA6ACIAMQBiAGIAYwBhAGQAMgA5ADMAMgAwAGYAMgAwADgANAA3AGEANQAxADUAYwBjADgANQA0ADAANgAzAGMAZABhADAAZABkAGEAZQBhADIAMABjAGQAYwBmAGYANAA1AGUAYgA2AGIANQBlADAAZQA5AGUAZQAxADUAZgBiAGQANAAiACwAIgBjAGEAdABhAGwAbwBnAFIAbwBvAHQAIgA6ACIAYwAtADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADEAIgAsACIAYwBhAHQAYQBsAG8AZwBSAG8AbwB0AEwAZQBuAGcAdABoACIAOgA0ADUAMAAyACwAIgByAGUAcQB1AGkAcgBlAGQASwBpAG4AZABzACIAOgBbACIAYQBjAHQAaQB2AGUAIgAsACIAYwBhAGwAbABzACIALAAiAGQAaQBhAGwAbwBnAHMAIgAsACIAaQBkAGUAbgB0AGkAdAB5ACIALAAiAGwAaQBmAGUAYwB5AGMAbABlACIALAAiAG8AcABhAHEAdQBlACIALAAiAHIAdQBuACIALAAiAHMAZQB0AHQAbABlAGQAIgAsACIAcwBvAHUAcgBjAGUAIgAsACIAdAByAGEAbgBzAGMAcgBpAHAAdAAiAF0AfQA="
102
102
  }
103
103
  },
104
104
  "refusals": {
@@ -0,0 +1,32 @@
1
+ {
2
+ "contract": "CONTRACT-r6",
3
+ "section": "B1",
4
+ "rulings": [
5
+ "RULING-60",
6
+ "RULING-61",
7
+ "RULING-67",
8
+ "RULING-128"
9
+ ],
10
+ "requiredKindsRule": "manifest.requiredKinds is the sorted (code-unit order), de-duplicated list of the catalog families this cut's root requires: its complete families only, partial ones excluded by the engine. The same list is the requiredKinds of the cut's families/families registry component, inside the content checkpointDigest covers.",
11
+ "clientRules": [
12
+ "Read requiredKinds verbatim; never derive it from a built-in family list.",
13
+ "A manifest without requiredKinds (an older engine) is refused as manifest_missing_required_kinds, never opened from a built-in list.",
14
+ "A kind the client does not know is refused as manifest_unknown_required_kind, never ignored.",
15
+ "A list that differs from the complete families of the digest-verified families/families component is refused as manifest_required_kinds_mismatch."
16
+ ],
17
+ "normalization": "Random epoch ids become 00000000-0000-4000-8000-<n> and every 64-hex digest a stable alias, in order of first appearance; every other byte is the engine's.",
18
+ "regenerate": "SENPI_WRITE_RECOVERY_GOLDENS=1 npx vitest run test/suite/regressions/5397-required-kinds-golden.test.ts (packages/coding-agent, senpi repository)",
19
+ "cases": [
20
+ {
21
+ "caseId": "one-partial-family",
22
+ "file": "one-partial-family.json",
23
+ "kind": "manifest",
24
+ "contractIds": [
25
+ "R4.B1",
26
+ "RULING-61",
27
+ "RULING-67",
28
+ "RULING-128"
29
+ ]
30
+ }
31
+ ]
32
+ }
@@ -0,0 +1,118 @@
1
+ {
2
+ "caseId": "one-partial-family",
3
+ "kind": "manifest",
4
+ "contractIds": [
5
+ "R4.B1",
6
+ "RULING-61",
7
+ "RULING-67",
8
+ "RULING-128"
9
+ ],
10
+ "description": "A cut whose identity family is partial (one client correlation refused at the protocol depth limit): requiredKinds lists the nine complete families in code-unit order and leaves identity out; the cut's families/families registry carries the same list.",
11
+ "expected": {
12
+ "manifest": {
13
+ "format": "senpi-recovery-manifest",
14
+ "version": 1,
15
+ "socketEpoch": {
16
+ "id": "socket-1"
17
+ },
18
+ "admissionId": {
19
+ "id": "attach-1"
20
+ },
21
+ "routeKind": "ordinary",
22
+ "session": {
23
+ "id": "s"
24
+ },
25
+ "sessionEpoch": {
26
+ "id": "00000000-0000-4000-8000-000000000001"
27
+ },
28
+ "generation": 1,
29
+ "sequence": 3,
30
+ "historyVersion": 0,
31
+ "token": {
32
+ "id": "socket-1:1"
33
+ },
34
+ "leaf": null,
35
+ "activeMessage": {
36
+ "id": "message-1"
37
+ },
38
+ "turn": {
39
+ "id": "00000000-0000-4000-8000-000000000002"
40
+ },
41
+ "checkpointDigest": "1bbcad29320f20847a515cc854063cda0ddaea20cdcff45eb6b5e0e9ee15fbd4",
42
+ "catalogRoot": "c-0000000000000001",
43
+ "catalogRootLength": 2830,
44
+ "requiredKinds": [
45
+ "active",
46
+ "calls",
47
+ "dialogs",
48
+ "lifecycle",
49
+ "opaque",
50
+ "run",
51
+ "settled",
52
+ "source",
53
+ "transcript"
54
+ ]
55
+ },
56
+ "families": {
57
+ "format": "senpi-recovery-families",
58
+ "version": 1,
59
+ "families": [
60
+ {
61
+ "family": "transcript",
62
+ "producer": "complete"
63
+ },
64
+ {
65
+ "family": "run",
66
+ "producer": "complete"
67
+ },
68
+ {
69
+ "family": "lifecycle",
70
+ "producer": "complete"
71
+ },
72
+ {
73
+ "family": "dialogs",
74
+ "producer": "complete"
75
+ },
76
+ {
77
+ "family": "opaque",
78
+ "producer": "complete"
79
+ },
80
+ {
81
+ "family": "active",
82
+ "producer": "complete"
83
+ },
84
+ {
85
+ "family": "calls",
86
+ "producer": "complete"
87
+ },
88
+ {
89
+ "family": "settled",
90
+ "producer": "complete"
91
+ },
92
+ {
93
+ "family": "identity",
94
+ "producer": "partial"
95
+ },
96
+ {
97
+ "family": "source",
98
+ "producer": "complete"
99
+ }
100
+ ],
101
+ "requiredKinds": [
102
+ "active",
103
+ "calls",
104
+ "dialogs",
105
+ "lifecycle",
106
+ "opaque",
107
+ "run",
108
+ "settled",
109
+ "source",
110
+ "transcript"
111
+ ],
112
+ "assembly": "incomplete",
113
+ "incomplete": [
114
+ "identity"
115
+ ]
116
+ }
117
+ }
118
+ }