@astrosheep/keiyaku 4.5.7 → 4.5.9
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.
- package/README.md +10 -0
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/opencode.js +3 -2
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +12 -11
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +33 -12
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
- package/build/src/akuma/abort.d.ts +2 -1
- package/build/src/akuma/abort.js +6 -23
- package/build/src/akuma/akuma-handle.js +4 -2
- package/build/src/akuma/akuma-observe.d.ts +2 -0
- package/build/src/akuma/akuma-observe.js +1 -0
- package/build/src/akuma/akuma-product.js +9 -7
- package/build/src/akuma/akuma.d.ts +392 -9
- package/build/src/akuma/akuma.js +31 -1
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +1 -0
- package/build/src/akuma/archetype.js +1 -1
- package/build/src/akuma/body.d.ts +8 -5
- package/build/src/akuma/body.js +12 -5
- package/build/src/akuma/call-request.d.ts +80 -0
- package/build/src/akuma/call-request.js +211 -0
- package/build/src/akuma/heart/facts.d.ts +16 -78
- package/build/src/akuma/heart/facts.js +11 -0
- package/build/src/akuma/heart/index.d.ts +3 -2
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/heart/request-authority.d.ts +5 -4
- package/build/src/akuma/heart/request-authority.js +20 -34
- package/build/src/akuma/heart/request-rows.js +12 -23
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +5 -13
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/projection-read.d.ts +1 -0
- package/build/src/akuma/projection-read.js +8 -1
- package/build/src/akuma/projection.d.ts +907 -137
- package/build/src/akuma/projection.js +193 -9
- package/build/src/akuma/provider.d.ts +30 -3
- package/build/src/akuma/provider.js +111 -0
- package/build/src/akuma/providers/acp/core.d.ts +2 -2
- package/build/src/akuma/providers/acp/core.js +13 -6
- package/build/src/akuma/providers/acp/index.js +5 -4
- package/build/src/akuma/providers/claude/events.d.ts +2 -2
- package/build/src/akuma/providers/claude/events.js +16 -3
- package/build/src/akuma/providers/claude/index.d.ts +3 -3
- package/build/src/akuma/providers/claude/index.js +16 -5
- package/build/src/akuma/providers/codex-app-server/events.d.ts +2 -2
- package/build/src/akuma/providers/codex-app-server/events.js +25 -4
- package/build/src/akuma/providers/codex-app-server/index.js +18 -6
- package/build/src/akuma/providers/grok-build/index.js +5 -4
- package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
- package/build/src/akuma/providers/pi/index.js +72 -58
- package/build/src/akuma/request-lifecycle.d.ts +4 -10
- package/build/src/akuma/request-lifecycle.js +7 -5
- package/build/src/akuma/request-rendezvous.d.ts +26 -0
- package/build/src/akuma/request-rendezvous.js +100 -0
- package/build/src/akuma/request-serve.d.ts +6 -66
- package/build/src/akuma/request-serve.js +83 -210
- package/build/src/akuma/request-wire.d.ts +109 -115
- package/build/src/akuma/request-wire.js +63 -318
- package/build/src/akuma/requests.d.ts +19 -47
- package/build/src/akuma/requests.js +51 -107
- package/build/src/akuma/turn-drive.d.ts +5 -3
- package/build/src/akuma/turn-drive.js +39 -11
- package/build/src/akuma-body.d.ts +7 -2
- package/build/src/akuma-body.js +68 -46
- package/build/src/body/amend.js +18 -19
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +2 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
- package/build/src/cli/commands/akuma-invoke.js +17 -9
- package/build/src/cli/commands/akuma.js +8 -8
- package/build/src/cli/commands/contract-invoke.d.ts +3 -2
- package/build/src/cli/commands/contract-invoke.js +42 -30
- package/build/src/cli/commands/contract.d.ts +16 -20
- package/build/src/cli/commands/contract.js +58 -25
- package/build/src/cli/commands/install.d.ts +2 -1
- package/build/src/cli/commands/install.js +3 -2
- package/build/src/cli/commands/task-invoke.d.ts +3 -0
- package/build/src/cli/commands/task-invoke.js +23 -140
- package/build/src/cli/commands/task.js +54 -20
- package/build/src/cli/invoke.js +39 -25
- package/build/src/cli/main.js +2 -1
- package/build/src/cli/parse.d.ts +2 -2
- package/build/src/cli/parse.js +56 -27
- package/build/src/cli/render/akuma-activity.d.ts +3 -0
- package/build/src/cli/render/akuma-activity.js +45 -29
- package/build/src/cli/render/akuma-tool.d.ts +5 -1
- package/build/src/cli/render/akuma.js +4 -8
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/catalog.js +80 -21
- package/build/src/cli/render/contract-observation.d.ts +2 -0
- package/build/src/cli/render/contract-observation.js +11 -0
- package/build/src/cli/render/contract.js +35 -62
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
- package/build/src/cli/render/kanshi-akuma.js +132 -0
- package/build/src/cli/render/kanshi.js +131 -213
- package/build/src/cli/render/receipt.d.ts +1 -2
- package/build/src/cli/render/receipt.js +76 -26
- package/build/src/cli/render/refusal.js +2 -10
- package/build/src/cli/render/region.js +5 -2
- package/build/src/cli/render/settings.d.ts +1 -1
- package/build/src/cli/render/settings.js +27 -8
- package/build/src/cli/render/task.js +22 -5
- package/build/src/cli/render/terminal.d.ts +32 -1
- package/build/src/cli/render/terminal.js +77 -1
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.js +4 -2
- package/build/src/cli/selectors.d.ts +2 -1
- package/build/src/cli/selectors.js +4 -3
- package/build/src/cli/square-edge.js +120 -36
- package/build/src/cli/usage.js +2 -1
- package/build/src/contract-guidance.d.ts +5 -0
- package/build/src/contract-guidance.js +121 -0
- package/build/src/contract-worktree.d.ts +0 -1
- package/build/src/contract-worktree.js +32 -83
- package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
- package/build/src/coordination/sqlite-transaction-lock.js +5 -0
- package/build/src/core/facts/codec.d.ts +2 -0
- package/build/src/core/facts/codec.js +4 -0
- package/build/src/core/verbs/placement.d.ts +6 -1
- package/build/src/core/verbs/placement.js +5 -3
- package/build/src/dispatch/index.d.ts +0 -2
- package/build/src/dispatch/index.js +54 -55
- package/build/src/git/admission.js +2 -2
- package/build/src/git/hooks.d.ts +9 -15
- package/build/src/git/hooks.js +23 -317
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +39 -21
- package/build/src/git/private-state-seat.d.ts +12 -0
- package/build/src/git/private-state-seat.js +39 -0
- package/build/src/git/process.d.ts +6 -0
- package/build/src/git/process.js +26 -11
- package/build/src/git/read-observation.js +29 -20
- package/build/src/git/reconcile.d.ts +13 -1
- package/build/src/git/reconcile.js +70 -11
- package/build/src/git/ref-migration.d.ts +22 -0
- package/build/src/git/ref-migration.js +55 -0
- package/build/src/git/repository.d.ts +10 -6
- package/build/src/git/repository.js +16 -8
- package/build/src/git/target-placement.d.ts +1 -0
- package/build/src/git/target-placement.js +5 -0
- package/build/src/git/tender.d.ts +1 -0
- package/build/src/git/terminal-reconcile.d.ts +1 -1
- package/build/src/git/terminal-reconcile.js +22 -20
- package/build/src/git/workspace.d.ts +14 -0
- package/build/src/git/workspace.js +44 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +16 -16
- package/build/src/kanshi/report.d.ts +2 -2
- package/build/src/library/address.d.ts +9 -3
- package/build/src/library/address.js +3 -2
- package/build/src/library/akuma-creation.d.ts +4 -3
- package/build/src/library/akuma-creation.js +19 -13
- package/build/src/library/audit.d.ts +14 -6
- package/build/src/library/audit.js +13 -23
- package/build/src/library/catalog.d.ts +3 -1
- package/build/src/library/catalog.js +20 -6
- package/build/src/library/composition.d.ts +385 -0
- package/build/src/library/composition.js +28 -0
- package/build/src/library/configuration.js +8 -2
- package/build/src/library/continuation.js +66 -30
- package/build/src/library/contract-bind.js +10 -2
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +102 -0
- package/build/src/library/contract-forwarding-reconciliation-result.js +92 -0
- package/build/src/library/contract-forwarding-result.d.ts +4464 -0
- package/build/src/library/contract-forwarding-result.js +521 -0
- package/build/src/library/contract-forwarding.d.ts +71 -0
- package/build/src/library/contract-forwarding.js +114 -0
- package/build/src/library/contract-handle.d.ts +38 -0
- package/build/src/library/contract-handle.js +314 -0
- package/build/src/library/contract-operations.d.ts +214 -69
- package/build/src/library/contract-operations.js +189 -118
- package/build/src/library/contract-types.d.ts +7 -3
- package/build/src/library/contract.d.ts +21 -34
- package/build/src/library/contract.js +29 -287
- package/build/src/library/fleet-result.d.ts +1580 -0
- package/build/src/library/fleet-result.js +98 -0
- package/build/src/library/fleet.d.ts +112 -54
- package/build/src/library/fleet.js +211 -71
- package/build/src/library/input.d.ts +3 -1
- package/build/src/library/input.js +11 -1
- package/build/src/library/keiyaku.d.ts +388 -20
- package/build/src/library/keiyaku.js +13 -21
- package/build/src/library/mutation.d.ts +3 -3
- package/build/src/library/mutation.js +5 -9
- package/build/src/library/nuke.d.ts +1 -1
- package/build/src/library/nuke.js +4 -3
- package/build/src/library/reconcile.d.ts +4 -0
- package/build/src/library/reconcile.js +2 -0
- package/build/src/library/refusal.d.ts +0 -9
- package/build/src/library/refusal.js +0 -7
- package/build/src/protocol/amend.js +56 -50
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/attempt.js +8 -1
- package/build/src/protocol/completion.js +7 -0
- package/build/src/protocol/deliver.js +6 -2
- package/build/src/protocol/operations.d.ts +4 -1
- package/build/src/protocol/operations.js +5 -2
- package/build/src/protocol/placement.d.ts +1 -0
- package/build/src/protocol/placement.js +52 -38
- package/build/src/protocol/read/observation.d.ts +1 -4
- package/build/src/protocol/read/observation.js +2 -15
- package/build/src/protocol/reintegrate.js +62 -58
- package/build/src/protocol/review.js +5 -0
- package/build/src/protocol/run.js +17 -13
- package/build/src/runtime/proc/run.d.ts +9 -0
- package/build/src/runtime/proc/run.js +51 -4
- package/build/src/runtime/proc/termination.js +26 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -1
- package/build/src/settlement/holder.js +15 -4
- package/build/src/settlement/settle.js +99 -33
- package/build/src/task/board.d.ts +68 -27
- package/build/src/task/board.js +31 -1
- package/build/src/task/catalog.d.ts +4 -0
- package/build/src/task/catalog.js +23 -0
- package/build/src/task/compose-language.js +33 -7
- package/build/src/task/compose-parser.d.ts +1 -1
- package/build/src/task/compose-parser.js +1 -1
- package/build/src/task/compose.js +2 -0
- package/build/src/task/index.d.ts +12 -4
- package/build/src/task/index.js +97 -16
- package/build/src/task/mutation-result.d.ts +923 -0
- package/build/src/task/mutation-result.js +140 -0
- package/build/src/task/mutation.d.ts +552 -28
- package/build/src/task/mutation.js +304 -97
- package/build/src/task/operations.d.ts +1 -4
- package/build/src/task/operations.js +0 -6
- package/build/src/task/public.d.ts +2 -0
- package/build/src/task/public.js +1 -0
- package/build/src/workspace-place.d.ts +7 -2
- package/build/src/workspace-place.js +34 -24
- package/build/src/world.d.ts +1 -0
- package/build/src/world.js +11 -0
- package/package.json +8 -6
- package/build/src/akuma/request-execution.d.ts +0 -8
- package/build/src/akuma/request-execution.js +0 -98
|
@@ -1,4 +1,196 @@
|
|
|
1
|
+
/* eslint-disable max-lines -- Akuma owns one coherent activity projection and strict boundary schema. */
|
|
1
2
|
import { decodeAgentEvent } from "./provider.js";
|
|
3
|
+
import { projectTell } from "./heart/facts.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const nonblankTextSchema = z.string().refine((value) => value.trim() !== "");
|
|
6
|
+
const countSchema = z.number().int().nonnegative();
|
|
7
|
+
const timestampSchema = z.string().refine((value) => Number.isFinite(Date.parse(value)), "expected timestamp");
|
|
8
|
+
const diffstatSchema = z.object({ added: countSchema, removed: countSchema }).strict();
|
|
9
|
+
const fileChangeSchema = z
|
|
10
|
+
.object({
|
|
11
|
+
op: z.enum(["add", "update", "delete", "unspecified"]),
|
|
12
|
+
path: z.string(),
|
|
13
|
+
diffstat: diffstatSchema.optional(),
|
|
14
|
+
})
|
|
15
|
+
.strict();
|
|
16
|
+
const toolCallSchema = z.union([
|
|
17
|
+
z.object({ kind: z.literal("run"), command: z.string() }).strict(),
|
|
18
|
+
z
|
|
19
|
+
.object({
|
|
20
|
+
kind: z.literal("read"),
|
|
21
|
+
path: z.string(),
|
|
22
|
+
offset: countSchema.optional(),
|
|
23
|
+
limit: countSchema.optional(),
|
|
24
|
+
})
|
|
25
|
+
.strict(),
|
|
26
|
+
z
|
|
27
|
+
.object({
|
|
28
|
+
kind: z.literal("search"),
|
|
29
|
+
query: z.string(),
|
|
30
|
+
scope: z.enum(["content", "files", "web"]).optional(),
|
|
31
|
+
path: z.string().optional(),
|
|
32
|
+
glob: z.string().optional(),
|
|
33
|
+
})
|
|
34
|
+
.strict(),
|
|
35
|
+
z.object({ kind: z.literal("fileChange"), changes: z.array(fileChangeSchema).readonly() }).strict(),
|
|
36
|
+
z.object({ kind: z.literal("other"), display: z.string() }).strict(),
|
|
37
|
+
]);
|
|
38
|
+
const toolResultSchema = z
|
|
39
|
+
.object({ status: z.enum(["ok", "error"]), message: z.string().optional(), exitCode: z.number().int().optional() })
|
|
40
|
+
.strict();
|
|
41
|
+
const tellDeliverySchema = z
|
|
42
|
+
.object({
|
|
43
|
+
deliveredAt: timestampSchema,
|
|
44
|
+
route: z.enum(["launch", "live"]),
|
|
45
|
+
turnSequence: countSchema,
|
|
46
|
+
receipt: z.enum(["unavailable", "required"]).optional(),
|
|
47
|
+
})
|
|
48
|
+
.strict()
|
|
49
|
+
.transform(({ receipt, ...delivery }) => (receipt === undefined ? delivery : { ...delivery, receipt }));
|
|
50
|
+
const turnRowSchema = z
|
|
51
|
+
.object({
|
|
52
|
+
kind: z.literal("turn"),
|
|
53
|
+
sequence: countSchema,
|
|
54
|
+
turnSequence: countSchema,
|
|
55
|
+
bodySequence: countSchema,
|
|
56
|
+
at: timestampSchema,
|
|
57
|
+
})
|
|
58
|
+
.strict();
|
|
59
|
+
const callRowSchema = z
|
|
60
|
+
.object({
|
|
61
|
+
kind: z.literal("call"),
|
|
62
|
+
sequence: countSchema,
|
|
63
|
+
turnSequence: countSchema,
|
|
64
|
+
at: timestampSchema,
|
|
65
|
+
text: z.string(),
|
|
66
|
+
})
|
|
67
|
+
.strict();
|
|
68
|
+
const textRowSchema = (kind) => z
|
|
69
|
+
.object({
|
|
70
|
+
kind: z.literal(kind),
|
|
71
|
+
sequence: countSchema,
|
|
72
|
+
turnSequence: countSchema,
|
|
73
|
+
at: timestampSchema,
|
|
74
|
+
text: z.string(),
|
|
75
|
+
truncated: z.literal(true).optional(),
|
|
76
|
+
})
|
|
77
|
+
.strict();
|
|
78
|
+
export const tellRowSchema = z
|
|
79
|
+
.object({
|
|
80
|
+
kind: z.literal("tell"),
|
|
81
|
+
sequence: countSchema,
|
|
82
|
+
at: timestampSchema,
|
|
83
|
+
tellId: nonblankTextSchema,
|
|
84
|
+
text: z.string(),
|
|
85
|
+
state: z.enum(["pending", "told"]),
|
|
86
|
+
deliveries: z.array(tellDeliverySchema).readonly(),
|
|
87
|
+
})
|
|
88
|
+
.strict();
|
|
89
|
+
const outcomeSchema = z.union([
|
|
90
|
+
z.object({ kind: z.literal("answered"), historyId: nonblankTextSchema, answer: z.string() }).strict(),
|
|
91
|
+
z.object({ kind: z.literal("failed"), historyId: nonblankTextSchema, diagnostic: z.string() }).strict(),
|
|
92
|
+
]);
|
|
93
|
+
const outcomeRowSchema = z
|
|
94
|
+
.object({
|
|
95
|
+
kind: z.literal("outcome"),
|
|
96
|
+
sequence: countSchema,
|
|
97
|
+
turnSequence: countSchema,
|
|
98
|
+
at: timestampSchema,
|
|
99
|
+
outcome: outcomeSchema,
|
|
100
|
+
})
|
|
101
|
+
.strict();
|
|
102
|
+
const activeToolRowSchema = z
|
|
103
|
+
.object({
|
|
104
|
+
kind: z.literal("tool"),
|
|
105
|
+
sequence: countSchema,
|
|
106
|
+
turnSequence: countSchema,
|
|
107
|
+
at: timestampSchema,
|
|
108
|
+
name: nonblankTextSchema,
|
|
109
|
+
call: toolCallSchema,
|
|
110
|
+
state: z.literal("active"),
|
|
111
|
+
truncated: z.literal(true).optional(),
|
|
112
|
+
})
|
|
113
|
+
.strict();
|
|
114
|
+
const completedToolRowSchema = z
|
|
115
|
+
.object({
|
|
116
|
+
kind: z.literal("tool"),
|
|
117
|
+
sequence: countSchema,
|
|
118
|
+
turnSequence: countSchema,
|
|
119
|
+
at: timestampSchema,
|
|
120
|
+
completedAt: timestampSchema.optional(),
|
|
121
|
+
durationMs: z.number().finite().nonnegative().optional(),
|
|
122
|
+
name: nonblankTextSchema,
|
|
123
|
+
call: toolCallSchema,
|
|
124
|
+
state: toolResultSchema,
|
|
125
|
+
truncated: z.literal(true).optional(),
|
|
126
|
+
})
|
|
127
|
+
.strict();
|
|
128
|
+
const unsettledToolRowSchema = z
|
|
129
|
+
.object({
|
|
130
|
+
kind: z.literal("tool"),
|
|
131
|
+
sequence: countSchema,
|
|
132
|
+
turnSequence: countSchema,
|
|
133
|
+
at: timestampSchema,
|
|
134
|
+
name: nonblankTextSchema,
|
|
135
|
+
call: toolCallSchema,
|
|
136
|
+
state: z.literal("unsettled"),
|
|
137
|
+
truncated: z.literal(true).optional(),
|
|
138
|
+
})
|
|
139
|
+
.strict();
|
|
140
|
+
const snapshotFactRowSchema = z.union([
|
|
141
|
+
callRowSchema,
|
|
142
|
+
textRowSchema("said"),
|
|
143
|
+
textRowSchema("thought"),
|
|
144
|
+
textRowSchema("note"),
|
|
145
|
+
tellRowSchema,
|
|
146
|
+
]);
|
|
147
|
+
const openSnapshotRowSchema = z.union([snapshotFactRowSchema, activeToolRowSchema, completedToolRowSchema]);
|
|
148
|
+
const idleSnapshotRowSchema = z.union([snapshotFactRowSchema, completedToolRowSchema]);
|
|
149
|
+
const snapshotEntrySchema = (row) => z.union([
|
|
150
|
+
z.object({ kind: z.literal("gap"), count: countSchema }).strict(),
|
|
151
|
+
z.object({ kind: z.literal("row"), row }).strict(),
|
|
152
|
+
]);
|
|
153
|
+
const reportedFileChangeSchema = z
|
|
154
|
+
.object({
|
|
155
|
+
sequence: countSchema,
|
|
156
|
+
at: timestampSchema,
|
|
157
|
+
op: z.enum(["add", "update", "delete", "unspecified"]),
|
|
158
|
+
path: z.string(),
|
|
159
|
+
diffstat: diffstatSchema.optional(),
|
|
160
|
+
})
|
|
161
|
+
.strict();
|
|
162
|
+
const reportedChangeFields = {
|
|
163
|
+
reportedChanges: z.array(reportedFileChangeSchema).readonly(),
|
|
164
|
+
reportedChangesOmitted: countSchema,
|
|
165
|
+
};
|
|
166
|
+
export const activitySnapshotSchema = z.union([
|
|
167
|
+
z
|
|
168
|
+
.object({
|
|
169
|
+
kind: z.literal("unborn"),
|
|
170
|
+
entries: z.tuple([]).readonly(),
|
|
171
|
+
omitted: z.literal(0),
|
|
172
|
+
...reportedChangeFields,
|
|
173
|
+
})
|
|
174
|
+
.strict(),
|
|
175
|
+
z
|
|
176
|
+
.object({
|
|
177
|
+
kind: z.literal("open"),
|
|
178
|
+
turn: turnRowSchema,
|
|
179
|
+
entries: z.array(snapshotEntrySchema(openSnapshotRowSchema)).readonly(),
|
|
180
|
+
omitted: countSchema,
|
|
181
|
+
...reportedChangeFields,
|
|
182
|
+
})
|
|
183
|
+
.strict(),
|
|
184
|
+
z
|
|
185
|
+
.object({
|
|
186
|
+
kind: z.literal("idle"),
|
|
187
|
+
outcome: outcomeRowSchema.optional(),
|
|
188
|
+
entries: z.array(snapshotEntrySchema(idleSnapshotRowSchema)).readonly(),
|
|
189
|
+
omitted: countSchema,
|
|
190
|
+
...reportedChangeFields,
|
|
191
|
+
})
|
|
192
|
+
.strict(),
|
|
193
|
+
]);
|
|
2
194
|
function publicOutcome(turnSequence, outcome) {
|
|
3
195
|
const historyId = `turn/${turnSequence}`;
|
|
4
196
|
return outcome.kind === "answered"
|
|
@@ -207,15 +399,7 @@ export function projectTurns(facts, retained = {
|
|
|
207
399
|
turn.rows.push(row);
|
|
208
400
|
}
|
|
209
401
|
else if (fact.kind === "tell") {
|
|
210
|
-
state.tells.push(
|
|
211
|
-
kind: "tell",
|
|
212
|
-
sequence: fact.sequence,
|
|
213
|
-
at: fact.recordedAt,
|
|
214
|
-
tellId: fact.id,
|
|
215
|
-
text: fact.body,
|
|
216
|
-
state: fact.state,
|
|
217
|
-
deliveries: fact.deliveries,
|
|
218
|
-
});
|
|
402
|
+
state.tells.push(projectTell(fact));
|
|
219
403
|
}
|
|
220
404
|
else {
|
|
221
405
|
projectActivityEvent(state, fact);
|
|
@@ -130,6 +130,33 @@ export type Session = Readonly<{
|
|
|
130
130
|
text: string;
|
|
131
131
|
}>): Promise<TellSubmission>;
|
|
132
132
|
}>;
|
|
133
|
+
/**
|
|
134
|
+
* Synchronous custody for one provider establishment or fork attempt.
|
|
135
|
+
* `closed` is the sole proof that every resource created by the attempt retired.
|
|
136
|
+
*/
|
|
137
|
+
export type ProviderAttempt<Result> = Readonly<{
|
|
138
|
+
result: Promise<Result>;
|
|
139
|
+
closed: Promise<void>;
|
|
140
|
+
abort(): Promise<void>;
|
|
141
|
+
forceDispose(): Promise<void>;
|
|
142
|
+
}>;
|
|
143
|
+
export type AttemptResource = Readonly<{
|
|
144
|
+
/** Resolves only when this physical resource has retired. */
|
|
145
|
+
closed: Promise<void>;
|
|
146
|
+
abort?(): Promise<void>;
|
|
147
|
+
forceDispose(): Promise<void>;
|
|
148
|
+
}>;
|
|
149
|
+
export type AttemptCustody = Readonly<{
|
|
150
|
+
signal: AbortSignal;
|
|
151
|
+
/** Register a resource in the attempt before awaiting further setup work. */
|
|
152
|
+
own(resource: AttemptResource): void;
|
|
153
|
+
}>;
|
|
154
|
+
/**
|
|
155
|
+
* Starts provider work after its caller has received custody. The input signal
|
|
156
|
+
* remains a cancellation notification; this attempt owns its own controller
|
|
157
|
+
* and any resulting native resource controls.
|
|
158
|
+
*/
|
|
159
|
+
export declare function createProviderAttempt<Result>(parentSignal: AbortSignal | undefined, establish: (custody: AttemptCustody) => Promise<Result>): ProviderAttempt<Result>;
|
|
133
160
|
export type DriveInput = Readonly<{
|
|
134
161
|
body: string;
|
|
135
162
|
launchTells: readonly Readonly<{
|
|
@@ -157,18 +184,18 @@ export type ProviderAdapter = Readonly<{
|
|
|
157
184
|
session: ResumeCoordinate;
|
|
158
185
|
at: string;
|
|
159
186
|
cwd: string;
|
|
160
|
-
}>):
|
|
187
|
+
}>): ProviderAttempt<Readonly<{
|
|
161
188
|
session: ResumeCoordinate;
|
|
162
189
|
}>>;
|
|
163
190
|
start(input: DriveInput & Readonly<{
|
|
164
191
|
session: Readonly<{
|
|
165
192
|
kind: "fresh";
|
|
166
193
|
}>;
|
|
167
|
-
}>):
|
|
194
|
+
}>): ProviderAttempt<Session>;
|
|
168
195
|
resume?(input: DriveInput & Readonly<{
|
|
169
196
|
session: Readonly<{
|
|
170
197
|
kind: "resume";
|
|
171
198
|
coordinate: ResumeCoordinate;
|
|
172
199
|
}>;
|
|
173
|
-
}>):
|
|
200
|
+
}>): ProviderAttempt<Session>;
|
|
174
201
|
}>;
|
|
@@ -344,3 +344,114 @@ export class AgentEventChannel {
|
|
|
344
344
|
};
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Starts provider work after its caller has received custody. The input signal
|
|
349
|
+
* remains a cancellation notification; this attempt owns its own controller
|
|
350
|
+
* and any resulting native resource controls.
|
|
351
|
+
*/
|
|
352
|
+
export function createProviderAttempt(parentSignal, establish) {
|
|
353
|
+
const parent = parentSignal ?? new AbortController().signal;
|
|
354
|
+
const controller = new AbortController();
|
|
355
|
+
const resources = [];
|
|
356
|
+
const ownedResources = new Map();
|
|
357
|
+
const cleanupFailures = [];
|
|
358
|
+
const cleanupOperations = [];
|
|
359
|
+
let setupComplete;
|
|
360
|
+
const setupSettled = new Promise((resolve) => {
|
|
361
|
+
setupComplete = resolve;
|
|
362
|
+
});
|
|
363
|
+
let establishmentSettled = false;
|
|
364
|
+
let retiring;
|
|
365
|
+
const remember = (operation, reportFailure) => {
|
|
366
|
+
const observed = operation.catch((error) => {
|
|
367
|
+
if (reportFailure)
|
|
368
|
+
cleanupFailures.push(error);
|
|
369
|
+
});
|
|
370
|
+
cleanupOperations.push(observed);
|
|
371
|
+
return operation;
|
|
372
|
+
};
|
|
373
|
+
const observeBackgroundRetirement = (operation) => {
|
|
374
|
+
void operation.catch(() => undefined);
|
|
375
|
+
};
|
|
376
|
+
const startRetirement = (owned, kind) => {
|
|
377
|
+
if (kind === "abort" && owned.resource.abort === undefined) {
|
|
378
|
+
const force = startRetirement(owned, "forceDispose");
|
|
379
|
+
owned.abort = force;
|
|
380
|
+
return force;
|
|
381
|
+
}
|
|
382
|
+
const existing = owned[kind];
|
|
383
|
+
if (existing !== undefined)
|
|
384
|
+
return existing;
|
|
385
|
+
const graceful = kind === "abort";
|
|
386
|
+
const dispose = graceful ? owned.resource.abort : owned.resource.forceDispose;
|
|
387
|
+
const operation = remember(Promise.resolve().then(() => dispose()), !graceful);
|
|
388
|
+
owned[kind] = operation;
|
|
389
|
+
return operation;
|
|
390
|
+
};
|
|
391
|
+
const retire = (kind) => {
|
|
392
|
+
if (kind === "forceDispose" || retiring === undefined)
|
|
393
|
+
retiring = kind;
|
|
394
|
+
const pending = resources.map((resource) => startRetirement(resource, kind));
|
|
395
|
+
return Promise.all(pending).then(() => undefined);
|
|
396
|
+
};
|
|
397
|
+
const own = (resource) => {
|
|
398
|
+
if (establishmentSettled)
|
|
399
|
+
throw new Error("cannot own a resource after provider establishment settles");
|
|
400
|
+
if (ownedResources.has(resource))
|
|
401
|
+
return;
|
|
402
|
+
const owned = { resource };
|
|
403
|
+
resources.push(owned);
|
|
404
|
+
ownedResources.set(resource, owned);
|
|
405
|
+
void resource.closed.catch((error) => {
|
|
406
|
+
cleanupFailures.push(error);
|
|
407
|
+
});
|
|
408
|
+
if (retiring !== undefined)
|
|
409
|
+
observeBackgroundRetirement(startRetirement(owned, retiring));
|
|
410
|
+
};
|
|
411
|
+
const cancelFromParent = () => {
|
|
412
|
+
if (!controller.signal.aborted)
|
|
413
|
+
controller.abort(parent.reason);
|
|
414
|
+
void retire("abort").catch(() => {
|
|
415
|
+
observeBackgroundRetirement(retire("forceDispose"));
|
|
416
|
+
});
|
|
417
|
+
};
|
|
418
|
+
parent.addEventListener("abort", cancelFromParent, { once: true });
|
|
419
|
+
if (parent.aborted)
|
|
420
|
+
cancelFromParent();
|
|
421
|
+
const result = Promise.resolve()
|
|
422
|
+
.then(() => establish({ signal: controller.signal, own }))
|
|
423
|
+
.catch((error) => {
|
|
424
|
+
if (!controller.signal.aborted)
|
|
425
|
+
observeBackgroundRetirement(retire("forceDispose"));
|
|
426
|
+
throw error;
|
|
427
|
+
})
|
|
428
|
+
.finally(() => {
|
|
429
|
+
establishmentSettled = true;
|
|
430
|
+
parent.removeEventListener("abort", cancelFromParent);
|
|
431
|
+
});
|
|
432
|
+
void result.then(() => setupComplete(), () => setupComplete());
|
|
433
|
+
const closed = (async () => {
|
|
434
|
+
await setupSettled;
|
|
435
|
+
for (;;) {
|
|
436
|
+
const operations = [...cleanupOperations];
|
|
437
|
+
const retired = resources.map((resource) => resource.resource.closed);
|
|
438
|
+
await Promise.allSettled([...operations, ...retired]);
|
|
439
|
+
if (operations.length === cleanupOperations.length)
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
if (cleanupFailures.length > 0)
|
|
443
|
+
throw cleanupFailures[0];
|
|
444
|
+
})();
|
|
445
|
+
void closed.catch(() => undefined);
|
|
446
|
+
const control = async (operation) => {
|
|
447
|
+
if (!controller.signal.aborted)
|
|
448
|
+
controller.abort(new Error("provider attempt retired"));
|
|
449
|
+
await retire(operation);
|
|
450
|
+
};
|
|
451
|
+
return {
|
|
452
|
+
result,
|
|
453
|
+
closed,
|
|
454
|
+
abort: async () => await control("abort"),
|
|
455
|
+
forceDispose: async () => await control("forceDispose"),
|
|
456
|
+
};
|
|
457
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type * as AcpSdk from "@agentclientprotocol/sdk";
|
|
2
2
|
import { spawnStdioProcess } from "../../../runtime/proc/stdio.js";
|
|
3
|
-
import { type ProviderAdapter, type Session } from "../../provider.js";
|
|
3
|
+
import { type AttemptCustody, type ProviderAdapter, type Session } from "../../provider.js";
|
|
4
4
|
import { type AcpToolInterpreter, type AcpToolUpdate } from "./events.js";
|
|
5
5
|
export type { AcpToolInterpreter, AcpToolUpdate };
|
|
6
6
|
export type AcpStartInput = Parameters<ProviderAdapter["start"]>[0] | Parameters<NonNullable<ProviderAdapter["resume"]>>[0];
|
|
@@ -21,4 +21,4 @@ type AcpLaunch = Readonly<{
|
|
|
21
21
|
argv: readonly [string, ...string[]];
|
|
22
22
|
env?: Readonly<Record<string, string>>;
|
|
23
23
|
}>;
|
|
24
|
-
export declare function startAcpSession(launch: AcpLaunch, input: AcpStartInput, dependencies?: AcpDependencies): Promise<AcpLiveSession>;
|
|
24
|
+
export declare function startAcpSession(launch: AcpLaunch, input: AcpStartInput, dependencies?: AcpDependencies, custody?: AttemptCustody): Promise<AcpLiveSession>;
|
|
@@ -149,7 +149,7 @@ function beginAcpPrompt(context, child, turn, sessionId, input) {
|
|
|
149
149
|
},
|
|
150
150
|
};
|
|
151
151
|
}
|
|
152
|
-
export async function startAcpSession(launch, input, dependencies = {}) {
|
|
152
|
+
export async function startAcpSession(launch, input, dependencies = {}, custody) {
|
|
153
153
|
const acp = await import("@agentclientprotocol/sdk");
|
|
154
154
|
const signal = input.signal ?? new AbortController().signal;
|
|
155
155
|
signal.throwIfAborted();
|
|
@@ -162,6 +162,11 @@ export async function startAcpSession(launch, input, dependencies = {}) {
|
|
|
162
162
|
...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
|
|
163
163
|
},
|
|
164
164
|
});
|
|
165
|
+
custody?.own({
|
|
166
|
+
closed: child.exited.then(() => undefined),
|
|
167
|
+
abort: async () => await child.close(true),
|
|
168
|
+
forceDispose: async () => await child.close(true),
|
|
169
|
+
});
|
|
165
170
|
let sessionId;
|
|
166
171
|
let turn;
|
|
167
172
|
const connection = createAcpClient(acp, (notification) => {
|
|
@@ -177,11 +182,13 @@ export async function startAcpSession(launch, input, dependencies = {}) {
|
|
|
177
182
|
}
|
|
178
183
|
catch (error) {
|
|
179
184
|
connection.close(error);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
if (custody === undefined) {
|
|
186
|
+
try {
|
|
187
|
+
await child.close(true);
|
|
188
|
+
}
|
|
189
|
+
catch (cleanup) {
|
|
190
|
+
throw new Error(`${diagnostic(acp, error)}; ACP cleanup failed: ${diagnostic(acp, cleanup)}`, { cause: error });
|
|
191
|
+
}
|
|
185
192
|
}
|
|
186
193
|
turn.events.end();
|
|
187
194
|
throw error;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createProviderAttempt } from "../../provider.js";
|
|
1
2
|
import { decodeAcpConfig } from "./config.js";
|
|
2
3
|
import { startAcpSession } from "./core.js";
|
|
3
4
|
export { decodeAcpConfig } from "./config.js";
|
|
@@ -53,16 +54,16 @@ export function createAcpProvider(execution, dependencies = {}) {
|
|
|
53
54
|
if (execution.executable === undefined)
|
|
54
55
|
throw new TypeError("ACP provider execution requires executable");
|
|
55
56
|
const config = decodeAcpConfig(execution.config);
|
|
56
|
-
const drive = async (input) => {
|
|
57
|
+
const drive = async (input, custody) => {
|
|
57
58
|
const launch = {
|
|
58
59
|
argv: argv(execution, config, input.options),
|
|
59
60
|
...(execution.env === undefined ? {} : { env: execution.env }),
|
|
60
61
|
};
|
|
61
|
-
return (await startAcpSession(launch, input, dependencies)).session;
|
|
62
|
+
return (await startAcpSession(launch, input, dependencies, custody)).session;
|
|
62
63
|
};
|
|
63
64
|
return {
|
|
64
65
|
admitOptions: (options) => optionAdmission(options, config),
|
|
65
|
-
start: async (
|
|
66
|
-
resume: async (
|
|
66
|
+
start: (input) => createProviderAttempt(input.signal, async (custody) => await drive({ ...input, signal: custody.signal }, custody)),
|
|
67
|
+
resume: (input) => createProviderAttempt(input.signal, async (custody) => await drive({ ...input, signal: custody.signal }, custody)),
|
|
67
68
|
};
|
|
68
69
|
}
|
|
@@ -28,8 +28,8 @@ export declare const CLAUDE_SYSTEM_DISPOSITIONS: {
|
|
|
28
28
|
readonly elicitation_complete: "drop";
|
|
29
29
|
readonly files_persisted: "note";
|
|
30
30
|
readonly hook_progress: "drop";
|
|
31
|
-
readonly hook_response: "
|
|
32
|
-
readonly hook_started: "
|
|
31
|
+
readonly hook_response: "hook-response";
|
|
32
|
+
readonly hook_started: "drop";
|
|
33
33
|
readonly informational: "note";
|
|
34
34
|
readonly init: "drop";
|
|
35
35
|
readonly local_command_output: "drop";
|
|
@@ -21,8 +21,8 @@ export const CLAUDE_SYSTEM_DISPOSITIONS = {
|
|
|
21
21
|
elicitation_complete: "drop",
|
|
22
22
|
files_persisted: "note",
|
|
23
23
|
hook_progress: "drop",
|
|
24
|
-
hook_response: "
|
|
25
|
-
hook_started: "
|
|
24
|
+
hook_response: "hook-response",
|
|
25
|
+
hook_started: "drop",
|
|
26
26
|
informational: "note",
|
|
27
27
|
init: "drop",
|
|
28
28
|
local_command_output: "drop",
|
|
@@ -89,7 +89,6 @@ const CLAUDE_SYSTEM_NOTES = {
|
|
|
89
89
|
const failed = Array.isArray(message.failed) ? message.failed.length : 0;
|
|
90
90
|
return failed === 0 ? `Persisted ${files} files` : `Persisted ${files} files; ${failed} failed`;
|
|
91
91
|
},
|
|
92
|
-
hook_started: (message) => `Hook ${nonblank(message.hook_name) ?? "unknown"} started`,
|
|
93
92
|
informational: (message) => nonblank(message.content) ?? "Informational notice",
|
|
94
93
|
mirror_error: (message) => `Transcript mirror warning: ${nonblank(message.error) ?? nonblank(message.message) ?? "unknown error"}`,
|
|
95
94
|
model_refusal_fallback: () => "Model refusal; using fallback",
|
|
@@ -253,6 +252,14 @@ function toolResultEvents(message, events, state) {
|
|
|
253
252
|
});
|
|
254
253
|
}
|
|
255
254
|
}
|
|
255
|
+
function hookResponseNote(value) {
|
|
256
|
+
const outcome = nonblank(value.outcome);
|
|
257
|
+
if (outcome !== "error" && outcome !== "cancelled")
|
|
258
|
+
return undefined;
|
|
259
|
+
const hook = nonblank(value.hook_name) ?? "unknown";
|
|
260
|
+
const exitCode = number(value.exit_code);
|
|
261
|
+
return `Hook ${hook} ${outcome}${exitCode === undefined ? "" : ` (exit ${exitCode})`}`;
|
|
262
|
+
}
|
|
256
263
|
function emitSystemMessage(value, events) {
|
|
257
264
|
const subtype = nonblank(value?.subtype) ?? "unknown";
|
|
258
265
|
if (!Object.hasOwn(CLAUDE_SYSTEM_DISPOSITIONS, subtype)) {
|
|
@@ -262,6 +269,12 @@ function emitSystemMessage(value, events) {
|
|
|
262
269
|
const systemDisposition = CLAUDE_SYSTEM_DISPOSITIONS[subtype];
|
|
263
270
|
if (systemDisposition === "drop")
|
|
264
271
|
return;
|
|
272
|
+
if (systemDisposition === "hook-response") {
|
|
273
|
+
const note = hookResponseNote(value);
|
|
274
|
+
if (note !== undefined)
|
|
275
|
+
events.emit(noteEvent(note));
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
265
278
|
if (systemDisposition === "control-progress" && value?.status !== "api_retry")
|
|
266
279
|
return;
|
|
267
280
|
const note = CLAUDE_SYSTEM_NOTES[subtype];
|
|
@@ -27,18 +27,18 @@ export declare const claudeProvider: Readonly<{
|
|
|
27
27
|
session: ResumeCoordinate;
|
|
28
28
|
at: string;
|
|
29
29
|
cwd: string;
|
|
30
|
-
}>):
|
|
30
|
+
}>): import("../../provider.js").ProviderAttempt<Readonly<{
|
|
31
31
|
session: ResumeCoordinate;
|
|
32
32
|
}>>;
|
|
33
33
|
start(input: import("../../provider.js").DriveInput & Readonly<{
|
|
34
34
|
session: Readonly<{
|
|
35
35
|
kind: "fresh";
|
|
36
36
|
}>;
|
|
37
|
-
}>):
|
|
37
|
+
}>): import("../../provider.js").ProviderAttempt<Session>;
|
|
38
38
|
resume?(input: import("../../provider.js").DriveInput & Readonly<{
|
|
39
39
|
session: Readonly<{
|
|
40
40
|
kind: "resume";
|
|
41
41
|
coordinate: ResumeCoordinate;
|
|
42
42
|
}>;
|
|
43
|
-
}>):
|
|
43
|
+
}>): import("../../provider.js").ProviderAttempt<Session>;
|
|
44
44
|
}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { abortable } from "../../abort.js";
|
|
3
|
-
import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
|
|
3
|
+
import { AKUMA_REQUESTS_ENV, AgentEventChannel, createProviderAttempt, } from "../../provider.js";
|
|
4
4
|
import { emitClaudeMessage } from "./events.js";
|
|
5
5
|
import { claudeUserMessage, createClaudeInput, isClaudeTurnEnded } from "./input.js";
|
|
6
6
|
export { CLAUDE_MESSAGE_DISPOSITIONS, CLAUDE_SYSTEM_DISPOSITIONS } from "./events.js";
|
|
@@ -282,7 +282,7 @@ function observeClaudeQuery(context) {
|
|
|
282
282
|
settleReceipts,
|
|
283
283
|
};
|
|
284
284
|
}
|
|
285
|
-
async function driveClaude(load, execution, drive) {
|
|
285
|
+
async function driveClaude(load, execution, drive, custody) {
|
|
286
286
|
if (drive.session.kind === "resume")
|
|
287
287
|
claudeSessionId(drive.session.coordinate);
|
|
288
288
|
const signal = drive.signal ?? new AbortController().signal;
|
|
@@ -324,6 +324,17 @@ async function driveClaude(load, execution, drive) {
|
|
|
324
324
|
},
|
|
325
325
|
},
|
|
326
326
|
});
|
|
327
|
+
custody.own({
|
|
328
|
+
closed: observed.completion.then(() => undefined),
|
|
329
|
+
abort: async () => {
|
|
330
|
+
shutDown(new Error("Claude query aborted"));
|
|
331
|
+
await observed.completion;
|
|
332
|
+
},
|
|
333
|
+
forceDispose: async () => {
|
|
334
|
+
shutDown(new Error("Claude query force-disposed"));
|
|
335
|
+
await observed.completion;
|
|
336
|
+
},
|
|
337
|
+
});
|
|
327
338
|
if (signal.aborted)
|
|
328
339
|
abortSetup();
|
|
329
340
|
try {
|
|
@@ -356,9 +367,9 @@ export function createClaudeProvider(loadOrExecution = async () => (await import
|
|
|
356
367
|
const selectedExecution = typeof loadOrExecution === "function" ? execution : loadOrExecution;
|
|
357
368
|
return {
|
|
358
369
|
admitOptions: admitClaudeOptions,
|
|
359
|
-
fork: (input) => forkClaude(load, selectedExecution, input),
|
|
360
|
-
start: (input) => driveClaude(load, selectedExecution, input),
|
|
361
|
-
resume: (input) => driveClaude(load, selectedExecution, input),
|
|
370
|
+
fork: (input) => createProviderAttempt(new AbortController().signal, async () => await forkClaude(load, selectedExecution, input)),
|
|
371
|
+
start: (input) => createProviderAttempt(input.signal, async (custody) => await driveClaude(load, selectedExecution, { ...input, signal: custody.signal }, custody)),
|
|
372
|
+
resume: (input) => createProviderAttempt(input.signal, async (custody) => await driveClaude(load, selectedExecution, { ...input, signal: custody.signal }, custody)),
|
|
362
373
|
};
|
|
363
374
|
}
|
|
364
375
|
export const claudeProvider = createClaudeProvider(async () => (await import("@anthropic-ai/claude-agent-sdk")));
|
|
@@ -26,8 +26,8 @@ export declare const CODEX_NOTIFICATION_DISPOSITIONS: {
|
|
|
26
26
|
readonly "fuzzyFileSearch/sessionCompleted": "drop";
|
|
27
27
|
readonly "fuzzyFileSearch/sessionUpdated": "drop";
|
|
28
28
|
readonly guardianWarning: "note";
|
|
29
|
-
readonly "hook/completed": "
|
|
30
|
-
readonly "hook/started": "
|
|
29
|
+
readonly "hook/completed": "hook-completed";
|
|
30
|
+
readonly "hook/started": "drop";
|
|
31
31
|
readonly "item/agentMessage/delta": "drop";
|
|
32
32
|
readonly "item/autoApprovalReview/completed": "note";
|
|
33
33
|
readonly "item/autoApprovalReview/started": "note";
|
|
@@ -15,8 +15,8 @@ export const CODEX_NOTIFICATION_DISPOSITIONS = {
|
|
|
15
15
|
"fuzzyFileSearch/sessionCompleted": "drop",
|
|
16
16
|
"fuzzyFileSearch/sessionUpdated": "drop",
|
|
17
17
|
guardianWarning: "note",
|
|
18
|
-
"hook/completed": "
|
|
19
|
-
"hook/started": "
|
|
18
|
+
"hook/completed": "hook-completed",
|
|
19
|
+
"hook/started": "drop",
|
|
20
20
|
"item/agentMessage/delta": "drop",
|
|
21
21
|
"item/autoApprovalReview/completed": "note",
|
|
22
22
|
"item/autoApprovalReview/started": "note",
|
|
@@ -273,8 +273,6 @@ function notificationAction(method, params) {
|
|
|
273
273
|
return "Filesystem changed";
|
|
274
274
|
case "guardianWarning":
|
|
275
275
|
return `Guardian warning: ${message ?? "action warned"}`;
|
|
276
|
-
case "hook/started":
|
|
277
|
-
return `Hook ${codexText(params.name) ?? codexText(params.hookName) ?? "unknown"} started`;
|
|
278
276
|
case "item/autoApprovalReview/completed":
|
|
279
277
|
return "Action approval review completed";
|
|
280
278
|
case "item/autoApprovalReview/started":
|
|
@@ -299,6 +297,23 @@ function notificationAction(method, params) {
|
|
|
299
297
|
return method;
|
|
300
298
|
}
|
|
301
299
|
}
|
|
300
|
+
function hookCompletionNote(params) {
|
|
301
|
+
const run = codexObject(params.run);
|
|
302
|
+
const status = codexText(run?.status);
|
|
303
|
+
const issue = Array.isArray(run?.entries)
|
|
304
|
+
? run.entries.map(codexObject).find((entry) => {
|
|
305
|
+
const kind = codexText(entry?.kind);
|
|
306
|
+
return kind === "warning" || kind === "error" || kind === "stop";
|
|
307
|
+
})
|
|
308
|
+
: undefined;
|
|
309
|
+
const issueKind = codexText(issue?.kind);
|
|
310
|
+
if (status !== "failed" && status !== "blocked" && status !== "stopped" && issueKind === undefined)
|
|
311
|
+
return undefined;
|
|
312
|
+
const eventName = codexText(run?.eventName) ?? "unknown";
|
|
313
|
+
const label = status === "failed" || status === "blocked" || status === "stopped" ? status : issueKind;
|
|
314
|
+
const diagnostic = codexText(run?.statusMessage) ?? codexText(issue?.text);
|
|
315
|
+
return `Hook ${eventName} ${label}${diagnostic === undefined ? "" : `: ${diagnostic}`}`;
|
|
316
|
+
}
|
|
302
317
|
function observeError(params, state, events) {
|
|
303
318
|
const detail = turnError(params.error) ?? codexText(params.message) ?? "codex app-server error";
|
|
304
319
|
state.error = detail;
|
|
@@ -328,6 +343,12 @@ export function codexNotificationResult(notification, state, events) {
|
|
|
328
343
|
switch (disposition) {
|
|
329
344
|
case "drop":
|
|
330
345
|
return undefined;
|
|
346
|
+
case "hook-completed": {
|
|
347
|
+
const note = hookCompletionNote(params);
|
|
348
|
+
if (note !== undefined)
|
|
349
|
+
events.emit(noteEvent(note));
|
|
350
|
+
return undefined;
|
|
351
|
+
}
|
|
331
352
|
case "note":
|
|
332
353
|
events.emit(noteEvent(notificationAction(method, params)));
|
|
333
354
|
return undefined;
|