@astrosheep/keiyaku 4.5.26 → 4.5.27

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 (78) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +5 -4
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +16 -14
  3. package/build/src/akuma/akuma-errors.d.ts +6 -0
  4. package/build/src/akuma/akuma-errors.js +11 -0
  5. package/build/src/akuma/akuma-handle.d.ts +53 -1
  6. package/build/src/akuma/akuma-handle.js +75 -7
  7. package/build/src/akuma/akuma-instance.js +6 -22
  8. package/build/src/akuma/akuma-probe.d.ts +20 -1
  9. package/build/src/akuma/akuma-probe.js +20 -3
  10. package/build/src/akuma/akuma.d.ts +12 -0
  11. package/build/src/akuma/allowed.d.ts +2 -1
  12. package/build/src/akuma/allowed.js +9 -4
  13. package/build/src/akuma/archetype.js +3 -3
  14. package/build/src/akuma/body.js +8 -3
  15. package/build/src/akuma/fleet-execution.d.ts +6 -1
  16. package/build/src/akuma/fleet-execution.js +44 -0
  17. package/build/src/akuma/fleet-observation.d.ts +238 -0
  18. package/build/src/akuma/fleet-observation.js +13 -0
  19. package/build/src/akuma/fleet-owner-port.d.ts +12 -0
  20. package/build/src/akuma/fleet-owner-port.js +46 -0
  21. package/build/src/akuma/fleet-request.d.ts +55 -4
  22. package/build/src/akuma/fleet-request.js +101 -6
  23. package/build/src/akuma/heart/index.d.ts +1 -0
  24. package/build/src/akuma/heart/index.js +4 -1
  25. package/build/src/akuma/heart/rows.d.ts +1 -0
  26. package/build/src/akuma/heart/rows.js +8 -0
  27. package/build/src/akuma/heart/soul.js +2 -2
  28. package/build/src/akuma/projection.d.ts +36 -0
  29. package/build/src/akuma/projection.js +2 -1
  30. package/build/src/akuma/provider.d.ts +14 -0
  31. package/build/src/akuma/provider.js +66 -4
  32. package/build/src/akuma/providers/acp/events.js +16 -8
  33. package/build/src/akuma/providers/claude/events.js +5 -7
  34. package/build/src/akuma/providers/opencode-sdk/events.js +9 -5
  35. package/build/src/akuma/providers/pi/events.js +4 -3
  36. package/build/src/akuma/request-lifecycle.js +10 -1
  37. package/build/src/akuma-body.js +1 -33
  38. package/build/src/cli/commands/akuma-invoke.d.ts +8 -0
  39. package/build/src/cli/commands/akuma-invoke.js +58 -6
  40. package/build/src/cli/commands/akuma.d.ts +1 -0
  41. package/build/src/cli/commands/akuma.js +10 -15
  42. package/build/src/cli/commands/contract-help.js +8 -5
  43. package/build/src/cli/render/akuma-activity.d.ts +7 -1
  44. package/build/src/cli/render/akuma-activity.js +158 -49
  45. package/build/src/cli/render/akuma-tool.d.ts +5 -0
  46. package/build/src/cli/render/akuma-tool.js +118 -14
  47. package/build/src/cli/render/akuma.d.ts +3 -1
  48. package/build/src/cli/render/akuma.js +34 -2
  49. package/build/src/cli/render/catalog.js +2 -3
  50. package/build/src/cli/render/contract-observation.d.ts +1 -0
  51. package/build/src/cli/render/contract-observation.js +20 -1
  52. package/build/src/cli/render/contract.js +4 -4
  53. package/build/src/cli/render/execution-progress.d.ts +1 -0
  54. package/build/src/cli/render/execution-progress.js +77 -3
  55. package/build/src/cli/render/kanshi.js +5 -19
  56. package/build/src/cli/render/terminal.js +3 -1
  57. package/build/src/cli/runtime.d.ts +6 -0
  58. package/build/src/cli/runtime.js +35 -17
  59. package/build/src/core/facts/offer.d.ts +1 -2
  60. package/build/src/core/verbs/abandon.js +1 -1
  61. package/build/src/core/verbs/amend.js +1 -1
  62. package/build/src/core/verbs/arc.js +1 -1
  63. package/build/src/core/verbs/attestation.js +1 -1
  64. package/build/src/core/verbs/bind.js +1 -1
  65. package/build/src/core/verbs/deliver.js +1 -1
  66. package/build/src/core/verbs/placement.js +1 -1
  67. package/build/src/core/verbs/reintegrate.js +1 -1
  68. package/build/src/git/admission.js +18 -7
  69. package/build/src/identity/coordinates.js +1 -1
  70. package/build/src/library/address.d.ts +33 -3
  71. package/build/src/library/address.js +89 -28
  72. package/build/src/library/composition.d.ts +12 -0
  73. package/build/src/library/fleet.d.ts +11 -1
  74. package/build/src/library/fleet.js +138 -48
  75. package/build/src/library/keiyaku.d.ts +12 -0
  76. package/build/src/plugin/public.d.ts +2 -0
  77. package/build/src/runtime/proc/windows-launch.exe +0 -0
  78. package/package.json +1 -1
@@ -1,10 +1,10 @@
1
1
  import { akumaIdSchema } from "./akuma.js";
2
2
  import { requestBodyCommand } from "./request-rendezvous.js";
3
3
  import { eraseRequestCommand, } from "./request-wire.js";
4
- import { fleetResultSchemas, isKillResult, isTellResult, isWaitResult, } from "./fleet-observation.js";
4
+ import { fleetResultSchemas, isKillResult, isTellResult, isTellWaitResult, isWaitResult, } from "./fleet-observation.js";
5
5
  import { z } from "zod";
6
6
  import { schemaJsonText } from "./schema.js";
7
- import { AkumaDecodeError } from "./akuma-errors.js";
7
+ import { AkumaDecodeError, AkumaNotBornError, AkumaObservationError } from "./akuma-errors.js";
8
8
  const nonblankTextSchema = z.string().refine((value) => value.trim() !== "");
9
9
  const fleetTargetsSchema = z
10
10
  .array(akumaIdSchema)
@@ -39,6 +39,17 @@ const tellAnswerRequestSchema = z
39
39
  })
40
40
  .strict()
41
41
  .transform((request) => ({ action: "akuma.tell-answer", ...request }));
42
+ const tellWaitRequestSchema = z
43
+ .object({
44
+ target: akumaIdSchema,
45
+ body: z.string(),
46
+ timeoutMs: z.number().int().nonnegative(),
47
+ schemaJson: nonblankTextSchema.optional(),
48
+ initiator: nonblankTextSchema.optional(),
49
+ interrupt: z.boolean().optional(),
50
+ })
51
+ .strict()
52
+ .transform((request) => ({ action: "akuma.tell-wait", ...request }));
42
53
  const killRequestSchema = z
43
54
  .object({ targets: fleetTargetsSchema })
44
55
  .strict()
@@ -47,12 +58,49 @@ const waitServiceSchema = z.object({ action: z.literal("akuma.wait") }).strict()
47
58
  const tellServiceSchema = z
48
59
  .object({ action: z.literal("akuma.tell"), target: akumaIdSchema, tellId: nonblankTextSchema })
49
60
  .strict();
61
+ const tellWaitServiceSchema = z
62
+ .object({ action: z.literal("akuma.tell-wait"), target: akumaIdSchema, tellId: nonblankTextSchema })
63
+ .strict();
50
64
  const killServiceSchema = z
51
65
  .object({
52
66
  action: z.literal("akuma.kill"),
53
67
  results: z.array(z.object({ id: akumaIdSchema, evidence: fleetResultSchemas.killEvidence }).strict()),
54
68
  })
55
69
  .strict();
70
+ /**
71
+ * A forwarded Fleet request leaves selection and observation to the parent, so
72
+ * the parent's typed refusal is the only evidence the child can classify on.
73
+ * Transporting it is the codec's own duty: an unencoded failure reaches the
74
+ * caller as an anonymous request error and loses the identity it names.
75
+ *
76
+ * The transport voids a begun request only when the encoded failure proves no
77
+ * product effect. A refused selection or an unreadable observation never
78
+ * reached an action, so Fleet proves that through the same refusal envelope
79
+ * the Contract codec uses; a genuinely failed action stays unencoded and
80
+ * keeps its existing anonymous classification.
81
+ */
82
+ const fleetRefusalSchema = z.union([
83
+ z.object({ kind: z.literal("akuma-not-born"), id: akumaIdSchema }).strict(),
84
+ z.object({ kind: z.literal("akuma-observation"), id: akumaIdSchema, diagnostic: z.string() }).strict(),
85
+ ]);
86
+ const fleetLiveFailureSchema = z.object({ kind: z.literal("refused"), failure: fleetRefusalSchema }).strict();
87
+ export function encodeFleetLiveFailure(error) {
88
+ const failure = error instanceof AkumaNotBornError
89
+ ? { kind: "akuma-not-born", id: error.id }
90
+ : error instanceof AkumaObservationError
91
+ ? { kind: "akuma-observation", id: error.id, diagnostic: error.diagnostic }
92
+ : null;
93
+ return failure === null ? null : { kind: "refused", failure };
94
+ }
95
+ export function decodeFleetLiveFailure(value) {
96
+ const parsed = fleetLiveFailureSchema.safeParse(value);
97
+ if (!parsed.success)
98
+ return null;
99
+ const failure = parsed.data.failure;
100
+ return failure.kind === "akuma-not-born"
101
+ ? new AkumaNotBornError(failure.id)
102
+ : new AkumaObservationError(failure.id, failure.diagnostic);
103
+ }
56
104
  function decodeFleetRequest(action, value) {
57
105
  const schema = action === "akuma.wait"
58
106
  ? waitRequestSchema
@@ -60,7 +108,9 @@ function decodeFleetRequest(action, value) {
60
108
  ? tellRequestSchema
61
109
  : action === "akuma.tell-answer"
62
110
  ? tellAnswerRequestSchema
63
- : killRequestSchema;
111
+ : action === "akuma.tell-wait"
112
+ ? tellWaitRequestSchema
113
+ : killRequestSchema;
64
114
  const parsed = schema.safeParse(value);
65
115
  return parsed.success ? parsed.data : null;
66
116
  }
@@ -69,7 +119,9 @@ function decodeFleetService(action, value) {
69
119
  ? waitServiceSchema
70
120
  : action === "akuma.tell" || action === "akuma.tell-answer"
71
121
  ? tellServiceSchema
72
- : killServiceSchema;
122
+ : action === "akuma.tell-wait"
123
+ ? tellWaitServiceSchema
124
+ : killServiceSchema;
73
125
  const parsed = schema.safeParse(value);
74
126
  if (!parsed.success)
75
127
  throw new Error("malformed stored Fleet service evidence");
@@ -82,7 +134,9 @@ function decodedFleetResult(action, value) {
82
134
  ? fleetResultSchemas.wait
83
135
  : action === "akuma.tell"
84
136
  ? fleetResultSchemas.tell
85
- : fleetResultSchemas.kill;
137
+ : action === "akuma.tell-wait"
138
+ ? fleetResultSchemas.tellWait
139
+ : fleetResultSchemas.kill;
86
140
  const parsed = schema.safeParse(value);
87
141
  if (!parsed.success)
88
142
  throw new Error(`Akuma body request returned an invalid live result for ${action}`);
@@ -100,9 +154,12 @@ export function fleetRequestProtocol(action) {
100
154
  decodeRequest: (payload) => decodeFleetRequest(action, payload),
101
155
  encodeResult: (result) => result,
102
156
  decodeResult: (result) => decodedFleetResult(action, result),
157
+ encodeFailure: encodeFleetLiveFailure,
158
+ decodeFailure: decodeFleetLiveFailure,
103
159
  decodeReference: (reference) => decodeFleetService(action, reference),
104
160
  isPermitted: (allowed) => action === "akuma.wait" ||
105
- ((action === "akuma.tell" || action === "akuma.tell-answer") && allowed.includes("akuma.tell")) ||
161
+ ((action === "akuma.tell" || action === "akuma.tell-answer" || action === "akuma.tell-wait") &&
162
+ allowed.includes("akuma.tell")) ||
106
163
  (action === "akuma.kill" && allowed.includes("akuma.kill")),
107
164
  };
108
165
  }
@@ -148,6 +205,24 @@ export function fleetRequestCommand(action, port) {
148
205
  service: { action: "akuma.tell", target: request.target, tellId: facts.id },
149
206
  };
150
207
  }
208
+ if (request.action === "akuma.tell-wait") {
209
+ if (port.tellWait === undefined)
210
+ throw new Error("bounded Tell Fleet port is unavailable");
211
+ return {
212
+ result: await port.tellWait({
213
+ target: request.target,
214
+ body: request.body,
215
+ tellId: facts.id,
216
+ recordedAt: facts.admittedAt,
217
+ timeoutMs: request.timeoutMs,
218
+ ...(request.schemaJson === undefined ? {} : { schemaJson: request.schemaJson }),
219
+ ...(request.initiator === undefined ? {} : { initiator: request.initiator }),
220
+ ...(request.interrupt === undefined ? {} : { interrupt: request.interrupt }),
221
+ signal: facts.signal,
222
+ }),
223
+ service: { action: request.action, target: request.target, tellId: facts.id },
224
+ };
225
+ }
151
226
  const result = await port.kill({ targets: request.targets, signal: facts.signal });
152
227
  if ("result" in result)
153
228
  return { result: result.result, service: { action: request.action, results: result.service } };
@@ -163,6 +238,7 @@ export function fleetRequestCommands(port) {
163
238
  "akuma.wait": eraseRequestCommand(fleetRequestCommand("akuma.wait", port)),
164
239
  "akuma.tell": eraseRequestCommand(fleetRequestCommand("akuma.tell", port)),
165
240
  "akuma.tell-answer": eraseRequestCommand(fleetRequestCommand("akuma.tell-answer", port)),
241
+ "akuma.tell-wait": eraseRequestCommand(fleetRequestCommand("akuma.tell-wait", port)),
166
242
  "akuma.kill": eraseRequestCommand(fleetRequestCommand("akuma.kill", port)),
167
243
  };
168
244
  }
@@ -195,6 +271,8 @@ function forwardedFleetCommandResult(response, action) {
195
271
  return response.result;
196
272
  if (action === "akuma.tell" && isTellResult(response.result))
197
273
  return response.result;
274
+ if (action === "akuma.tell-wait" && isTellWaitResult(response.result))
275
+ return response.result;
198
276
  if (action === "akuma.kill" && isKillResult(response.result))
199
277
  return response.result;
200
278
  throw new Error(`transport integrity: request Fleet ${action} returned an invalid live result`);
@@ -229,6 +307,23 @@ export async function requestForwardedFleetTell(input) {
229
307
  });
230
308
  return forwardedFleetCommandResult(response, "akuma.tell");
231
309
  }
310
+ export async function requestForwardedFleetTellWait(input) {
311
+ const response = await requestBodyCommand({
312
+ directory: input.directory,
313
+ command: fleetRequestProtocol("akuma.tell-wait"),
314
+ value: {
315
+ action: "akuma.tell-wait",
316
+ target: input.target,
317
+ body: input.body,
318
+ timeoutMs: input.timeoutMs,
319
+ ...(input.schema === undefined ? {} : { schemaJson: schemaJsonText(input.schema) }),
320
+ ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
321
+ ...(input.interrupt === undefined ? {} : { interrupt: input.interrupt }),
322
+ },
323
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
324
+ });
325
+ return forwardedFleetCommandResult(response, "akuma.tell-wait");
326
+ }
232
327
  export async function requestForwardedFleetKill(input) {
233
328
  const response = await requestBodyCommand({
234
329
  directory: input.directory,
@@ -94,6 +94,7 @@ export declare function failOpenBoundTurns(paths: AkumaPaths, input: Readonly<{
94
94
  completedAt: string;
95
95
  }>): Promise<readonly number[]>;
96
96
  export declare function readTurn(paths: AkumaPaths, sequence: number): Promise<TurnFact | null>;
97
+ export declare function readLatestTurnForBody(paths: AkumaPaths, bodySequence: number): Promise<TurnFact | null>;
97
98
  export declare function endTurn(paths: AkumaPaths, input: Readonly<{
98
99
  turnSequence: number;
99
100
  outcome: TurnOutcome;
@@ -1,5 +1,5 @@
1
1
  import { parsePublicHistoryId } from "../identity.js";
2
- import { answeredTurnFact, endBodyFact, finishBodyFact, deleteStopControl, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertKillFact, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, lastAnsweredTurnFact, pauseFact, sessionFactForCoordinate, stopFact, turnFact, } from "./rows.js";
2
+ import { answeredTurnFact, endBodyFact, finishBodyFact, deleteStopControl, insertActivityFact, insertTurnEndFact, insertTurnStartFact, insertPauseControl, insertKillFact, insertSessionFact, insertStopControl, killFactForBody, latestBodyFact, latestKillFact, latestSessionFact, latestTurnFactForBody, lastAnsweredTurnFact, pauseFact, sessionFactForCoordinate, stopFact, turnFact, } from "./rows.js";
3
3
  import { insertTellDeliveryFact, dispositionSnapshotProven, insertTellBindingFact, insertTellDispositionSnapshot, insertTellFact, insertTellReceiptFact, insertUndeliveredTellReceipts, latestOpenTellDisposition, openBoundTurns, openTellDispositionIds, pendingTellFacts, hasPendingTell, resolveTellDispositionSnapshot, tellDispositionResolved, tellFact, tellIdsForFence, } from "./tells.js";
4
4
  import { activityFactSlice, statusFacts, lastActivityAt as readLastActivityAt, pruneActivityFacts, } from "./timeline.js";
5
5
  import { isHeartAbsent, readSealFromLeash, withHeartTransaction, withReadOnlyHeart } from "./storage.js";
@@ -264,6 +264,9 @@ export async function failOpenBoundTurns(paths, input) {
264
264
  export async function readTurn(paths, sequence) {
265
265
  return await withReadOnlyHeart(paths, (heart) => turnFact(heart, sequence));
266
266
  }
267
+ export async function readLatestTurnForBody(paths, bodySequence) {
268
+ return await withReadOnlyHeart(paths, (heart) => latestTurnFactForBody(heart, bodySequence));
269
+ }
267
270
  export async function endTurn(paths, input) {
268
271
  return await withHeartTransaction(paths, (heart) => {
269
272
  const fact = insertTurnEndFact(heart, { kind: "turn-end", ...input });
@@ -122,4 +122,5 @@ export declare function latestKillFact(database: DatabaseSync): KillFact | null;
122
122
  export declare function killFactForBody(database: DatabaseSync, bodySequence: number): KillFact | null;
123
123
  export declare function lastAnsweredTurnFact(database: DatabaseSync): TurnFact | null;
124
124
  export declare function answeredTurnFact(database: DatabaseSync, turnSequence: number): TurnFact | null;
125
+ export declare function latestTurnFactForBody(database: DatabaseSync, bodySequence: number): TurnFact | null;
125
126
  export declare function turnFact(database: DatabaseSync, turnSequence: number): TurnFact | null;
@@ -299,6 +299,14 @@ export function answeredTurnFact(database, turnSequence) {
299
299
  .get(turnSequence);
300
300
  return row === undefined ? null : decodeTurnRow(row);
301
301
  }
302
+ export function latestTurnFactForBody(database, bodySequence) {
303
+ const row = database
304
+ .prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome, history_id,
305
+ session_json, answer, answer_json, schema_json, initiator, diagnostic, completed_at
306
+ FROM turns WHERE body_sequence = ? ORDER BY sequence DESC LIMIT 1`)
307
+ .get(bodySequence);
308
+ return row === undefined ? null : decodeTurnRow(row);
309
+ }
302
310
  export function turnFact(database, turnSequence) {
303
311
  const row = database
304
312
  .prepare(`SELECT sequence, body_sequence, started_at, end_sequence, outcome, history_id,
@@ -1,6 +1,6 @@
1
1
  import { parseAkuId } from "../identity.js";
2
2
  import { decodeProviderOptions, decodeProviderRecipe, decodeReadonlyRestraint } from "../provider-recipe.js";
3
- import { effectiveAllowedActions } from "../allowed.js";
3
+ import { historicalAllowedActions } from "../allowed.js";
4
4
  function record(value) {
5
5
  return value !== null && typeof value === "object" && !Array.isArray(value)
6
6
  ? value
@@ -68,7 +68,7 @@ function validateSoul(value) {
68
68
  ...(restraint === undefined ? {} : { readonly: restraint }),
69
69
  cwd: nonblank(soul.cwd, "cwd"),
70
70
  origin: decodeOrigin(soul.origin),
71
- allowed: effectiveAllowedActions(soul.allowed),
71
+ allowed: historicalAllowedActions(soul.allowed),
72
72
  createdAt: nonblank(soul.createdAt, "createdAt"),
73
73
  };
74
74
  }
@@ -122,6 +122,10 @@ declare const activeToolRowSchema: z.ZodObject<{
122
122
  }, z.core.$strict>, z.ZodObject<{
123
123
  kind: z.ZodLiteral<"other">;
124
124
  display: z.ZodString;
125
+ input: z.ZodOptional<z.ZodObject<{
126
+ json: z.ZodString;
127
+ truncated: z.ZodBoolean;
128
+ }, z.core.$strict>>;
125
129
  }, z.core.$strict>]>;
126
130
  state: z.ZodLiteral<"active">;
127
131
  truncated: z.ZodOptional<z.ZodLiteral<true>>;
@@ -170,6 +174,10 @@ declare const completedToolRowSchema: z.ZodObject<{
170
174
  }, z.core.$strict>, z.ZodObject<{
171
175
  kind: z.ZodLiteral<"other">;
172
176
  display: z.ZodString;
177
+ input: z.ZodOptional<z.ZodObject<{
178
+ json: z.ZodString;
179
+ truncated: z.ZodBoolean;
180
+ }, z.core.$strict>>;
173
181
  }, z.core.$strict>]>;
174
182
  state: z.ZodObject<{
175
183
  status: z.ZodEnum<{
@@ -223,6 +231,10 @@ declare const unsettledToolRowSchema: z.ZodObject<{
223
231
  }, z.core.$strict>, z.ZodObject<{
224
232
  kind: z.ZodLiteral<"other">;
225
233
  display: z.ZodString;
234
+ input: z.ZodOptional<z.ZodObject<{
235
+ json: z.ZodString;
236
+ truncated: z.ZodBoolean;
237
+ }, z.core.$strict>>;
226
238
  }, z.core.$strict>]>;
227
239
  state: z.ZodLiteral<"unsettled">;
228
240
  truncated: z.ZodOptional<z.ZodLiteral<true>>;
@@ -328,6 +340,10 @@ declare const openSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
328
340
  }, z.core.$strict>, z.ZodObject<{
329
341
  kind: z.ZodLiteral<"other">;
330
342
  display: z.ZodString;
343
+ input: z.ZodOptional<z.ZodObject<{
344
+ json: z.ZodString;
345
+ truncated: z.ZodBoolean;
346
+ }, z.core.$strict>>;
331
347
  }, z.core.$strict>]>;
332
348
  state: z.ZodLiteral<"active">;
333
349
  truncated: z.ZodOptional<z.ZodLiteral<true>>;
@@ -375,6 +391,10 @@ declare const openSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
375
391
  }, z.core.$strict>, z.ZodObject<{
376
392
  kind: z.ZodLiteral<"other">;
377
393
  display: z.ZodString;
394
+ input: z.ZodOptional<z.ZodObject<{
395
+ json: z.ZodString;
396
+ truncated: z.ZodBoolean;
397
+ }, z.core.$strict>>;
378
398
  }, z.core.$strict>]>;
379
399
  state: z.ZodObject<{
380
400
  status: z.ZodEnum<{
@@ -489,6 +509,10 @@ declare const idleSnapshotRowSchema: z.ZodUnion<readonly [z.ZodUnion<readonly [z
489
509
  }, z.core.$strict>, z.ZodObject<{
490
510
  kind: z.ZodLiteral<"other">;
491
511
  display: z.ZodString;
512
+ input: z.ZodOptional<z.ZodObject<{
513
+ json: z.ZodString;
514
+ truncated: z.ZodBoolean;
515
+ }, z.core.$strict>>;
492
516
  }, z.core.$strict>]>;
493
517
  state: z.ZodObject<{
494
518
  status: z.ZodEnum<{
@@ -673,6 +697,10 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
673
697
  }, z.core.$strict>, z.ZodObject<{
674
698
  kind: z.ZodLiteral<"other">;
675
699
  display: z.ZodString;
700
+ input: z.ZodOptional<z.ZodObject<{
701
+ json: z.ZodString;
702
+ truncated: z.ZodBoolean;
703
+ }, z.core.$strict>>;
676
704
  }, z.core.$strict>]>;
677
705
  state: z.ZodLiteral<"active">;
678
706
  truncated: z.ZodOptional<z.ZodLiteral<true>>;
@@ -720,6 +748,10 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
720
748
  }, z.core.$strict>, z.ZodObject<{
721
749
  kind: z.ZodLiteral<"other">;
722
750
  display: z.ZodString;
751
+ input: z.ZodOptional<z.ZodObject<{
752
+ json: z.ZodString;
753
+ truncated: z.ZodBoolean;
754
+ }, z.core.$strict>>;
723
755
  }, z.core.$strict>]>;
724
756
  state: z.ZodObject<{
725
757
  status: z.ZodEnum<{
@@ -875,6 +907,10 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
875
907
  }, z.core.$strict>, z.ZodObject<{
876
908
  kind: z.ZodLiteral<"other">;
877
909
  display: z.ZodString;
910
+ input: z.ZodOptional<z.ZodObject<{
911
+ json: z.ZodString;
912
+ truncated: z.ZodBoolean;
913
+ }, z.core.$strict>>;
878
914
  }, z.core.$strict>]>;
879
915
  state: z.ZodObject<{
880
916
  status: z.ZodEnum<{
@@ -13,6 +13,7 @@ const fileChangeSchema = z
13
13
  diffstat: diffstatSchema.optional(),
14
14
  })
15
15
  .strict();
16
+ const toolInputSchema = z.object({ json: z.string(), truncated: z.boolean() }).strict();
16
17
  const toolCallSchema = z.union([
17
18
  z.object({ kind: z.literal("run"), command: z.string() }).strict(),
18
19
  z
@@ -33,7 +34,7 @@ const toolCallSchema = z.union([
33
34
  })
34
35
  .strict(),
35
36
  z.object({ kind: z.literal("fileChange"), changes: z.array(fileChangeSchema).readonly() }).strict(),
36
- z.object({ kind: z.literal("other"), display: z.string() }).strict(),
37
+ z.object({ kind: z.literal("other"), display: z.string(), input: toolInputSchema.optional() }).strict(),
37
38
  ]);
38
39
  const toolResultSchema = z
39
40
  .object({ status: z.enum(["ok", "error"]), message: z.string().optional(), exitCode: z.number().int().optional() })
@@ -6,6 +6,10 @@ export declare const AGENT_EVENT_TEXT_LIMIT = 16384;
6
6
  export declare const AGENT_THOUGHT_TEXT_LIMIT = 4000;
7
7
  export declare const AGENT_EVENT_QUEUE_LIMIT = 256;
8
8
  export type SearchScope = "content" | "files" | "web";
9
+ export type ToolInput = Readonly<{
10
+ json: string;
11
+ truncated: boolean;
12
+ }>;
9
13
  export type ToolCall = Readonly<{
10
14
  kind: "run";
11
15
  command: string;
@@ -33,6 +37,7 @@ export type ToolCall = Readonly<{
33
37
  }> | Readonly<{
34
38
  kind: "other";
35
39
  display: string;
40
+ input?: ToolInput;
36
41
  }>;
37
42
  export type ToolResult = Readonly<{
38
43
  status: "ok" | "error";
@@ -75,6 +80,15 @@ export type AgentEvent = Readonly<{
75
80
  export { decodeResumeCoordinate, encodeResumeCoordinate };
76
81
  export declare function decodeAgentEvent(value: unknown): AgentEvent;
77
82
  export declare function encodeAgentEvent(event: AgentEvent): unknown;
83
+ /**
84
+ * Admit only a compact JSON view of structured tool invocation input. This
85
+ * deliberately receives adapter start evidence, never result or delta bodies.
86
+ */
87
+ export declare function boundedToolInput(input: unknown): ToolInput | undefined;
88
+ /** Build one generic call from the provider's structured invocation evidence. */
89
+ export declare function otherToolCall(display: string, input?: unknown): Extract<ToolCall, {
90
+ kind: "other";
91
+ }>;
78
92
  export declare function boundedEventText(value: string): string;
79
93
  export declare function boundedThoughtText(value: string): string;
80
94
  export declare function noteEvent(note: string): Extract<AgentEvent, {
@@ -107,8 +107,19 @@ function decodeFileChangeCall(call) {
107
107
  const changes = call.changes.map(decodeFileChangeMember);
108
108
  return changes.every((change) => change !== null) ? { kind: "fileChange", changes } : null;
109
109
  }
110
+ function decodeToolInput(value) {
111
+ if (value === undefined)
112
+ return undefined;
113
+ const input = object(value);
114
+ if (input === null || typeof input.json !== "string" || typeof input.truncated !== "boolean")
115
+ return null;
116
+ return { json: input.json, truncated: input.truncated };
117
+ }
110
118
  function decodeOtherCall(call) {
111
- return typeof call.display === "string" ? { kind: "other", display: call.display } : null;
119
+ if (typeof call.display !== "string")
120
+ return null;
121
+ const input = decodeToolInput(call.input);
122
+ return input === null ? null : { kind: "other", display: call.display, ...(input === undefined ? {} : { input }) };
112
123
  }
113
124
  function decodeToolCall(value) {
114
125
  const call = object(value);
@@ -242,11 +253,22 @@ function boundedToolCall(call) {
242
253
  },
243
254
  truncated: call.changes.some((change) => change.path.length > AGENT_EVENT_TEXT_LIMIT),
244
255
  };
245
- case "other":
256
+ case "other": {
257
+ const input = call.input;
258
+ const display = boundedEventText(call.display);
259
+ const bounded = input === undefined ? undefined : boundedToolInputJson(input.json);
246
260
  return {
247
- value: { kind: call.kind, display: boundedEventText(call.display) },
248
- truncated: call.display.length > AGENT_EVENT_TEXT_LIMIT,
261
+ value: {
262
+ kind: call.kind,
263
+ display,
264
+ ...(bounded === undefined || input === undefined
265
+ ? {}
266
+ : { input: { json: bounded.value, truncated: input.truncated || bounded.truncated } }),
267
+ },
268
+ truncated: call.display.length > AGENT_EVENT_TEXT_LIMIT ||
269
+ (input !== undefined && (input.truncated || bounded?.truncated === true)),
249
270
  };
271
+ }
250
272
  default:
251
273
  return call;
252
274
  }
@@ -302,6 +324,46 @@ export function encodeAgentEvent(event) {
302
324
  return event;
303
325
  }
304
326
  }
327
+ /**
328
+ * Admit only a compact JSON view of structured tool invocation input. This
329
+ * deliberately receives adapter start evidence, never result or delta bodies.
330
+ */
331
+ export function boundedToolInput(input) {
332
+ if (input === undefined)
333
+ return undefined;
334
+ let json;
335
+ try {
336
+ const encoded = JSON.stringify(input);
337
+ if (encoded === undefined)
338
+ return undefined;
339
+ json = encoded;
340
+ }
341
+ catch {
342
+ return undefined;
343
+ }
344
+ const bounded = boundedToolInputJson(json);
345
+ return { json: bounded.value, truncated: bounded.truncated };
346
+ }
347
+ /** Build one generic call from the provider's structured invocation evidence. */
348
+ export function otherToolCall(display, input) {
349
+ const preview = boundedToolInput(input);
350
+ return { kind: "other", display, ...(preview === undefined ? {} : { input: preview }) };
351
+ }
352
+ function boundedToolInputJson(value) {
353
+ if (new TextEncoder().encode(value).length <= AGENT_EVENT_TEXT_LIMIT)
354
+ return { value, truncated: false };
355
+ let bytes = 0;
356
+ let prefix = "";
357
+ const encoder = new TextEncoder();
358
+ for (const codePoint of value) {
359
+ const length = encoder.encode(codePoint).length;
360
+ if (bytes + length > AGENT_EVENT_TEXT_LIMIT)
361
+ break;
362
+ prefix += codePoint;
363
+ bytes += length;
364
+ }
365
+ return { value: prefix, truncated: true };
366
+ }
305
367
  export function boundedEventText(value) {
306
368
  return value.slice(0, AGENT_EVENT_TEXT_LIMIT);
307
369
  }
@@ -1,4 +1,4 @@
1
- import { noteEvent, unknownEvent } from "../../provider.js";
1
+ import { noteEvent, otherToolCall, unknownEvent } from "../../provider.js";
2
2
  export const EMPTY_ACP_EVENT_STATE = Object.freeze({
3
3
  answer: "",
4
4
  assistantMessageId: null,
@@ -38,8 +38,8 @@ function object(value) {
38
38
  function positiveLine(value) {
39
39
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
40
40
  }
41
- function otherCall(name) {
42
- return { kind: "other", display: name };
41
+ function otherCall(name, input) {
42
+ return otherToolCall(name, input);
43
43
  }
44
44
  function locationFact(locations) {
45
45
  if (locations === null || locations === undefined)
@@ -57,7 +57,7 @@ function standardCall(update, name) {
57
57
  const location = locationFact(update.locations);
58
58
  if (update.kind === "read") {
59
59
  return location.path === undefined
60
- ? otherCall(name)
60
+ ? otherCall(name, update.rawInput)
61
61
  : {
62
62
  kind: "read",
63
63
  path: location.path,
@@ -67,12 +67,12 @@ function standardCall(update, name) {
67
67
  const input = object(update.rawInput);
68
68
  if (update.kind === "execute") {
69
69
  const command = nonblank(input?.command);
70
- return command === undefined ? otherCall(name) : { kind: "run", command };
70
+ return command === undefined ? otherCall(name, update.rawInput) : { kind: "run", command };
71
71
  }
72
72
  if (update.kind === "search") {
73
73
  const query = nonblank(input?.query);
74
74
  if (query === undefined)
75
- return otherCall(name);
75
+ return otherCall(name, update.rawInput);
76
76
  const path = nonblank(input?.path);
77
77
  const glob = nonblank(input?.glob);
78
78
  const scope = input?.scope;
@@ -85,7 +85,7 @@ function standardCall(update, name) {
85
85
  ...(glob === undefined ? {} : { glob }),
86
86
  };
87
87
  }
88
- return otherCall(name);
88
+ return otherCall(name, update.rawInput);
89
89
  }
90
90
  function strongest(previous, next) {
91
91
  if (previous === undefined || previous.kind === "other")
@@ -96,7 +96,15 @@ function observeTool(update, previous, interpret) {
96
96
  const name = nonblank(update.name) ?? nonblank(update.title) ?? previous?.name ?? "ACP tool";
97
97
  const standard = standardCall(update, name);
98
98
  const dialect = standard.kind === "other" ? interpret?.(update) : undefined;
99
- return { name, call: strongest(previous?.call, dialect ?? standard) };
99
+ const call = strongest(previous?.call, dialect ?? standard);
100
+ if (call.kind !== "other")
101
+ return { name, call };
102
+ // The correlated start's admitted preview is authority: a later update never
103
+ // overwrites it, empty or not, while a start without one adopts first supplied evidence.
104
+ const started = previous?.call.kind === "other" ? previous.call.input : undefined;
105
+ const supplied = standard.kind === "other" ? standard.input : undefined;
106
+ const input = started ?? supplied;
107
+ return { name, call: input === undefined ? call : { kind: "other", display: call.display, input } };
100
108
  }
101
109
  export function mapAcpUpdate(update, previous, interpret) {
102
110
  switch (update.sessionUpdate) {
@@ -1,4 +1,4 @@
1
- import { noteEvent, unknownEvent } from "../../provider.js";
1
+ import { noteEvent, otherToolCall, unknownEvent } from "../../provider.js";
2
2
  export const CLAUDE_MESSAGE_DISPOSITIONS = {
3
3
  assistant: "assistant",
4
4
  auth_status: "auth",
@@ -104,11 +104,11 @@ const CLAUDE_SYSTEM_NOTES = {
104
104
  task_updated: (message) => `Task ${nonblank(message.task_id) ?? "unknown"} updated`,
105
105
  worker_shutting_down: (message) => `Worker stopping: ${nonblank(message.reason) ?? "unknown reason"}`,
106
106
  };
107
- function runCall(name, value) {
107
+ function runCall(name, value, input) {
108
108
  if (name !== "Bash")
109
109
  return undefined;
110
110
  const command = nonblank(value.command);
111
- return command === undefined ? { kind: "other", display: name } : { kind: "run", command };
111
+ return command === undefined ? otherToolCall(name, input) : { kind: "run", command };
112
112
  }
113
113
  function readCall(name, path, value) {
114
114
  return name === "Read" && path !== undefined ? { kind: "read", path, ...readRange(value) } : undefined;
@@ -192,13 +192,11 @@ function structuredFileChange(name, result) {
192
192
  }
193
193
  function toolCall(name, input) {
194
194
  const value = object(input) ?? {};
195
- const run = runCall(name, value);
195
+ const run = runCall(name, value, input);
196
196
  if (run !== undefined)
197
197
  return run;
198
198
  const path = startedPath(name, value);
199
- return (readCall(name, path, value) ??
200
- searchCall(name, value) ??
201
- fileChangeCall(name, path) ?? { kind: "other", display: name });
199
+ return (readCall(name, path, value) ?? searchCall(name, value) ?? fileChangeCall(name, path) ?? otherToolCall(name, input));
202
200
  }
203
201
  function assistantEvents(message, events, state) {
204
202
  if (message.aborted === true)
@@ -1,4 +1,4 @@
1
- import { noteEvent } from "../../provider.js";
1
+ import { noteEvent, otherToolCall } from "../../provider.js";
2
2
  export const OPENCODE_EVENT_DISPOSITIONS = {
3
3
  "server.instance.disposed": "dropped",
4
4
  "installation.updated": "dropped",
@@ -115,6 +115,10 @@ function strongerCall(previous, next) {
115
115
  return previous;
116
116
  if (previous?.kind === "fileChange" && next.kind !== "fileChange")
117
117
  return previous;
118
+ // The correlated start's admitted preview is authority: a later update never
119
+ // overwrites it, empty or conflicting, while a start without one adopts supplied evidence.
120
+ if (next.kind === "other" && previous?.kind === "other" && previous.input !== undefined)
121
+ return { ...next, input: previous.input };
118
122
  return next;
119
123
  }
120
124
  function runCall(name, value) {
@@ -163,12 +167,12 @@ function callFor(name, input, metadata) {
163
167
  if (lower === "grep" || lower === "glob" || lower === "search")
164
168
  return searchCall(lower, value);
165
169
  if (lower === "edit")
166
- return editCall(value, meta) ?? { kind: "other", display: name };
170
+ return editCall(value, meta) ?? otherToolCall(name, input);
167
171
  if (lower === "write")
168
- return writeCall(value, meta) ?? { kind: "other", display: name };
172
+ return writeCall(value, meta) ?? otherToolCall(name, input);
169
173
  if (lower === "apply_patch")
170
- return applyPatchCall(meta) ?? { kind: "other", display: name };
171
- return { kind: "other", display: name };
174
+ return applyPatchCall(meta) ?? otherToolCall(name, input);
175
+ return otherToolCall(name, input);
172
176
  }
173
177
  function belongs(part, state) {
174
178
  return state.sessionId === undefined || part.sessionID === state.sessionId;
@@ -1,4 +1,4 @@
1
- import { noteEvent, unknownEvent } from "../../provider.js";
1
+ import { noteEvent, otherToolCall, unknownEvent } from "../../provider.js";
2
2
  import { diffstatFromUnifiedPatch } from "../unified-patch.js";
3
3
  export const PI_EVENT_DISPOSITIONS = {
4
4
  agent_end: "drop",
@@ -112,7 +112,8 @@ function toolCall(name, args) {
112
112
  return (runCall(name, value) ??
113
113
  readCall(name, value) ??
114
114
  searchCall(name, value) ??
115
- fileChangeCall(name, value) ?? { kind: "other", display: name });
115
+ fileChangeCall(name, value) ??
116
+ otherToolCall(name, args));
116
117
  }
117
118
  function translateNote(event) {
118
119
  if (event.type === "compaction_end")
@@ -129,7 +130,7 @@ function translateToolEnd(event, state) {
129
130
  const started = state.tools.get(event.toolCallId);
130
131
  state.tools.delete(event.toolCallId);
131
132
  const name = started?.name ?? event.toolName;
132
- const call = started?.call ?? { kind: "other", display: name };
133
+ const call = started?.call ?? otherToolCall(name);
133
134
  return [
134
135
  {
135
136
  type: "tool",