@codetreker/daynight 0.25.4 → 0.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -11
- package/config.example.yml +3 -0
- package/dist/api/client.d.ts +3 -2
- package/dist/api/client.js +10 -6
- package/dist/api/client.js.map +1 -1
- package/dist/api/parse.d.ts +3 -2
- package/dist/api/parse.js +59 -10
- package/dist/api/parse.js.map +1 -1
- package/dist/api/types.d.ts +75 -1
- package/dist/api/worker-mode.d.ts +6 -0
- package/dist/api/worker-mode.js +14 -0
- package/dist/api/worker-mode.js.map +1 -0
- package/dist/cli/commands.js +2 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/commands/controller/command-controls.d.ts +4 -0
- package/dist/commands/controller/command-controls.js +33 -0
- package/dist/commands/controller/command-controls.js.map +1 -0
- package/dist/commands/controller/definition.d.ts +3 -0
- package/dist/commands/controller/definition.js +22 -0
- package/dist/commands/controller/definition.js.map +1 -0
- package/dist/commands/controller/independent.d.ts +3 -0
- package/dist/commands/controller/independent.js +344 -0
- package/dist/commands/controller/independent.js.map +1 -0
- package/dist/commands/controller/index.d.ts +12 -0
- package/dist/commands/controller/index.js +73 -0
- package/dist/commands/controller/index.js.map +1 -0
- package/dist/commands/controller/launch-ticket.d.ts +49 -0
- package/dist/commands/controller/launch-ticket.js +99 -0
- package/dist/commands/controller/launch-ticket.js.map +1 -0
- package/dist/commands/controller/lifecycle-store.d.ts +84 -0
- package/dist/commands/controller/lifecycle-store.js +278 -0
- package/dist/commands/controller/lifecycle-store.js.map +1 -0
- package/dist/commands/controller/local-client.d.ts +44 -0
- package/dist/commands/controller/local-client.js +75 -0
- package/dist/commands/controller/local-client.js.map +1 -0
- package/dist/commands/controller/local-content.d.ts +23 -0
- package/dist/commands/controller/local-content.js +103 -0
- package/dist/commands/controller/local-content.js.map +1 -0
- package/dist/commands/controller/process-proof.d.ts +13 -0
- package/dist/commands/controller/process-proof.js +121 -0
- package/dist/commands/controller/process-proof.js.map +1 -0
- package/dist/commands/controller/providers/claude.d.ts +2 -0
- package/dist/commands/controller/providers/claude.js +470 -0
- package/dist/commands/controller/providers/claude.js.map +1 -0
- package/dist/commands/controller/providers/codex.d.ts +2 -0
- package/dist/commands/controller/providers/codex.js +254 -0
- package/dist/commands/controller/providers/codex.js.map +1 -0
- package/dist/commands/controller/providers/controls-claude.d.ts +26 -0
- package/dist/commands/controller/providers/controls-claude.js +138 -0
- package/dist/commands/controller/providers/controls-claude.js.map +1 -0
- package/dist/commands/controller/providers/controls-codex.d.ts +38 -0
- package/dist/commands/controller/providers/controls-codex.js +199 -0
- package/dist/commands/controller/providers/controls-codex.js.map +1 -0
- package/dist/commands/controller/providers/controls-copilot.d.ts +20 -0
- package/dist/commands/controller/providers/controls-copilot.js +143 -0
- package/dist/commands/controller/providers/controls-copilot.js.map +1 -0
- package/dist/commands/controller/providers/controls.d.ts +21 -0
- package/dist/commands/controller/providers/controls.js +53 -0
- package/dist/commands/controller/providers/controls.js.map +1 -0
- package/dist/commands/controller/providers/copilot-interactions.d.ts +47 -0
- package/dist/commands/controller/providers/copilot-interactions.js +295 -0
- package/dist/commands/controller/providers/copilot-interactions.js.map +1 -0
- package/dist/commands/controller/providers/copilot-projection.d.ts +11 -0
- package/dist/commands/controller/providers/copilot-projection.js +93 -0
- package/dist/commands/controller/providers/copilot-projection.js.map +1 -0
- package/dist/commands/controller/providers/copilot-runtime.d.ts +9 -0
- package/dist/commands/controller/providers/copilot-runtime.js +127 -0
- package/dist/commands/controller/providers/copilot-runtime.js.map +1 -0
- package/dist/commands/controller/providers/copilot.d.ts +2 -0
- package/dist/commands/controller/providers/copilot.js +309 -0
- package/dist/commands/controller/providers/copilot.js.map +1 -0
- package/dist/commands/controller/providers/interactions.d.ts +3 -0
- package/dist/commands/controller/providers/interactions.js +79 -0
- package/dist/commands/controller/providers/interactions.js.map +1 -0
- package/dist/commands/controller/providers/native-rpc.d.ts +28 -0
- package/dist/commands/controller/providers/native-rpc.js +85 -0
- package/dist/commands/controller/providers/native-rpc.js.map +1 -0
- package/dist/commands/controller/providers/projection.d.ts +23 -0
- package/dist/commands/controller/providers/projection.js +99 -0
- package/dist/commands/controller/providers/projection.js.map +1 -0
- package/dist/commands/controller/providers/turns.d.ts +7 -0
- package/dist/commands/controller/providers/turns.js +21 -0
- package/dist/commands/controller/providers/turns.js.map +1 -0
- package/dist/commands/controller/providers/types.d.ts +44 -0
- package/dist/commands/controller/providers/types.js +2 -0
- package/dist/commands/controller/providers/types.js.map +1 -0
- package/dist/commands/controller/recovery.d.ts +6 -0
- package/dist/commands/controller/recovery.js +22 -0
- package/dist/commands/controller/recovery.js.map +1 -0
- package/dist/commands/controller/relay.d.ts +18 -0
- package/dist/commands/controller/relay.js +299 -0
- package/dist/commands/controller/relay.js.map +1 -0
- package/dist/commands/controller/resume.d.ts +18 -0
- package/dist/commands/controller/resume.js +193 -0
- package/dist/commands/controller/resume.js.map +1 -0
- package/dist/commands/controller/runtime.d.ts +5 -0
- package/dist/commands/controller/runtime.js +455 -0
- package/dist/commands/controller/runtime.js.map +1 -0
- package/dist/commands/controller/windows-job.d.ts +3 -0
- package/dist/commands/controller/windows-job.js +59 -0
- package/dist/commands/controller/windows-job.js.map +1 -0
- package/dist/commands/controller/wire-display.d.ts +5 -0
- package/dist/commands/controller/wire-display.js +11 -0
- package/dist/commands/controller/wire-display.js.map +1 -0
- package/dist/commands/skill/skills/using-daynight/SKILL.md +52 -162
- package/dist/commands/skill/skills/using-daynight/references/authorization.md +36 -0
- package/dist/commands/skill/skills/using-daynight/references/autopilot-managed-task.md +77 -193
- package/dist/commands/skill/skills/using-daynight/references/create-task.md +31 -186
- package/dist/commands/skill/skills/using-daynight/references/final-acceptance.md +25 -0
- package/dist/commands/skill/skills/using-daynight/references/goal.md +46 -243
- package/dist/commands/skill/skills/using-daynight/references/handbook.md +37 -294
- package/dist/commands/skill/skills/using-daynight/references/handoff.md +33 -91
- package/dist/commands/skill/skills/using-daynight/references/project-management.md +24 -0
- package/dist/commands/skill/skills/using-daynight/references/run-task.md +18 -59
- package/dist/commands/skill/skills/using-daynight/references/setup.md +16 -0
- package/dist/commands/skill/skills/using-daynight/references/task-content.md +80 -177
- package/dist/commands/skill/skills/using-daynight/references/task-execution.md +34 -126
- package/dist/commands/skill/skills/using-daynight/references/task-management.md +135 -0
- package/dist/commands/skill/skills/using-daynight/references/write-safety.md +34 -0
- package/dist/commands/task/command.js +5 -3
- package/dist/commands/task/command.js.map +1 -1
- package/dist/commands/task/definition.js +4 -2
- package/dist/commands/task/definition.js.map +1 -1
- package/dist/commands/task/rendering.d.ts +1 -0
- package/dist/commands/task/rendering.js +10 -1
- package/dist/commands/task/rendering.js.map +1 -1
- package/dist/commands/worker/backend.d.ts +7 -0
- package/dist/commands/worker/backend.js +7 -0
- package/dist/commands/worker/backend.js.map +1 -0
- package/dist/commands/worker/backends/grant-renewal.d.ts +13 -0
- package/dist/commands/worker/backends/grant-renewal.js +42 -0
- package/dist/commands/worker/backends/grant-renewal.js.map +1 -0
- package/dist/commands/worker/backends/session-api.d.ts +66 -0
- package/dist/commands/worker/backends/session-api.js +84 -0
- package/dist/commands/worker/backends/session-api.js.map +1 -0
- package/dist/commands/worker/backends/web-process.d.ts +79 -0
- package/dist/commands/worker/backends/web-process.js +156 -0
- package/dist/commands/worker/backends/web-process.js.map +1 -0
- package/dist/commands/worker/backends/web-store.d.ts +49 -0
- package/dist/commands/worker/backends/web-store.js +323 -0
- package/dist/commands/worker/backends/web-store.js.map +1 -0
- package/dist/commands/worker/backends/web-types.d.ts +83 -0
- package/dist/commands/worker/backends/web-types.js +3 -0
- package/dist/commands/worker/backends/web-types.js.map +1 -0
- package/dist/commands/worker/backends/web.d.ts +26 -0
- package/dist/commands/worker/backends/web.js +178 -0
- package/dist/commands/worker/backends/web.js.map +1 -0
- package/dist/commands/worker/config.js +12 -5
- package/dist/commands/worker/config.js.map +1 -1
- package/dist/commands/worker/control.d.ts +2 -0
- package/dist/commands/worker/control.js +11 -4
- package/dist/commands/worker/control.js.map +1 -1
- package/dist/commands/worker/coordinator.d.ts +10 -1
- package/dist/commands/worker/coordinator.js +153 -24
- package/dist/commands/worker/coordinator.js.map +1 -1
- package/dist/commands/worker/herdr/agents.js +5 -4
- package/dist/commands/worker/herdr/agents.js.map +1 -1
- package/dist/commands/worker/herdr/arguments.js +9 -4
- package/dist/commands/worker/herdr/arguments.js.map +1 -1
- package/dist/commands/worker/herdr/claude-input.d.ts +2 -0
- package/dist/commands/worker/herdr/claude-input.js +20 -0
- package/dist/commands/worker/herdr/claude-input.js.map +1 -0
- package/dist/commands/worker/herdr/command.d.ts +11 -2
- package/dist/commands/worker/herdr/command.js +23 -8
- package/dist/commands/worker/herdr/command.js.map +1 -1
- package/dist/commands/worker/herdr/instance.d.ts +5 -1
- package/dist/commands/worker/herdr/instance.js +31 -1
- package/dist/commands/worker/herdr/instance.js.map +1 -1
- package/dist/commands/worker/herdr/preflight.d.ts +1 -1
- package/dist/commands/worker/herdr/preflight.js +34 -15
- package/dist/commands/worker/herdr/preflight.js.map +1 -1
- package/dist/commands/worker/herdr/version-probe.d.ts +13 -0
- package/dist/commands/worker/herdr/version-probe.js +21 -0
- package/dist/commands/worker/herdr/version-probe.js.map +1 -0
- package/dist/commands/worker/herdr.js +7 -7
- package/dist/commands/worker/herdr.js.map +1 -1
- package/dist/commands/worker/index.d.ts +2 -0
- package/dist/commands/worker/index.js +1 -1
- package/dist/commands/worker/index.js.map +1 -1
- package/dist/commands/worker/prompts.js +5 -1
- package/dist/commands/worker/prompts.js.map +1 -1
- package/dist/commands/worker/remote.d.ts +3 -1
- package/dist/commands/worker/remote.js +4 -0
- package/dist/commands/worker/remote.js.map +1 -1
- package/dist/commands/worker/reporter.d.ts +14 -0
- package/dist/commands/worker/reporter.js +174 -0
- package/dist/commands/worker/reporter.js.map +1 -0
- package/dist/commands/worker/repositories.js +2 -2
- package/dist/commands/worker/repositories.js.map +1 -1
- package/dist/commands/worker/runtime.d.ts +2 -0
- package/dist/commands/worker/runtime.js +76 -11
- package/dist/commands/worker/runtime.js.map +1 -1
- package/dist/commands/worker/setup-environment.d.ts +2 -1
- package/dist/commands/worker/setup-environment.js +10 -4
- package/dist/commands/worker/setup-environment.js.map +1 -1
- package/dist/commands/worker/setup.js +5 -5
- package/dist/commands/worker/setup.js.map +1 -1
- package/dist/commands/worker/store.d.ts +2 -1
- package/dist/commands/worker/store.js +19 -9
- package/dist/commands/worker/store.js.map +1 -1
- package/dist/commands/worker/telemetry.d.ts +22 -0
- package/dist/commands/worker/telemetry.js +265 -0
- package/dist/commands/worker/telemetry.js.map +1 -0
- package/dist/commands/worker/types.d.ts +4 -1
- package/dist/session/controller-protocol.d.ts +245 -0
- package/dist/session/controller-protocol.js +218 -0
- package/dist/session/controller-protocol.js.map +1 -0
- package/dist/session/controls.d.ts +28 -0
- package/dist/session/controls.js +37 -0
- package/dist/session/controls.js.map +1 -0
- package/dist/session/protocol.d.ts +290 -0
- package/dist/session/protocol.js +307 -0
- package/dist/session/protocol.js.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { type SessionControls } from "./controls.js";
|
|
2
|
+
export declare const SESSION_PROTOCOL: "daynight.session.v1";
|
|
3
|
+
export declare const SESSION_SCHEMA_VERSION: 1;
|
|
4
|
+
export declare const SESSION_PROJECTION_VERSION: 1;
|
|
5
|
+
export type SessionProvider = "codex" | "claude" | "copilot";
|
|
6
|
+
export type DecimalSequence = string;
|
|
7
|
+
export type SessionBinding = {
|
|
8
|
+
readonly claimId: string;
|
|
9
|
+
readonly testExecutionId?: never;
|
|
10
|
+
} | {
|
|
11
|
+
readonly testExecutionId: string;
|
|
12
|
+
readonly claimId?: never;
|
|
13
|
+
};
|
|
14
|
+
export type SessionFence = SessionBinding & {
|
|
15
|
+
readonly sessionId: string;
|
|
16
|
+
readonly executionGeneration: DecimalSequence;
|
|
17
|
+
};
|
|
18
|
+
export type ControllerFence = SessionFence & {
|
|
19
|
+
readonly connectionEpoch: DecimalSequence;
|
|
20
|
+
};
|
|
21
|
+
export type InitialInputState = "not_required" | "not_submitted" | "dispatching" | "provider_accepted" | "confirmed" | "failed" | "unknown";
|
|
22
|
+
export type SessionCapabilities = {
|
|
23
|
+
readonly send: boolean;
|
|
24
|
+
readonly steer: boolean;
|
|
25
|
+
readonly cancel: boolean;
|
|
26
|
+
readonly respond: boolean;
|
|
27
|
+
};
|
|
28
|
+
export type SessionOperations = {
|
|
29
|
+
readonly canSend: boolean;
|
|
30
|
+
readonly canCancel: boolean;
|
|
31
|
+
readonly canRespond: boolean;
|
|
32
|
+
};
|
|
33
|
+
export type SessionSnapshot = ControllerFence & {
|
|
34
|
+
readonly controls?: SessionControls;
|
|
35
|
+
readonly turnStartedAt?: string | null;
|
|
36
|
+
readonly protocol: typeof SESSION_PROTOCOL;
|
|
37
|
+
readonly schemaVersion: typeof SESSION_SCHEMA_VERSION;
|
|
38
|
+
readonly projectionVersion: typeof SESSION_PROJECTION_VERSION;
|
|
39
|
+
readonly identity: ({
|
|
40
|
+
readonly projectId: string;
|
|
41
|
+
readonly taskId: string;
|
|
42
|
+
readonly workerId: string;
|
|
43
|
+
readonly worktreeId: string;
|
|
44
|
+
readonly ownerUserId?: never;
|
|
45
|
+
} | {
|
|
46
|
+
readonly ownerUserId: string;
|
|
47
|
+
readonly projectId?: never;
|
|
48
|
+
readonly taskId?: never;
|
|
49
|
+
readonly workerId?: never;
|
|
50
|
+
readonly worktreeId?: never;
|
|
51
|
+
}) & {
|
|
52
|
+
readonly controllerId: string;
|
|
53
|
+
readonly controllerInstanceId: string;
|
|
54
|
+
readonly agentControlMode: "web";
|
|
55
|
+
readonly provider: SessionProvider;
|
|
56
|
+
readonly nativeSessionId: string | null;
|
|
57
|
+
};
|
|
58
|
+
readonly sessionRevision: DecimalSequence;
|
|
59
|
+
readonly historyEpoch: string;
|
|
60
|
+
readonly lastEventSeq: DecimalSequence;
|
|
61
|
+
readonly lastTimelineSeq: DecimalSequence;
|
|
62
|
+
readonly initialInputState: InitialInputState;
|
|
63
|
+
readonly synchronized: boolean;
|
|
64
|
+
readonly lifecycle: "active" | "draining" | "archived";
|
|
65
|
+
readonly connectionState: "connected" | "disconnected" | "synchronizing";
|
|
66
|
+
readonly activity: "initializing" | "idle" | "working" | "waiting_input" | "stopped" | "unknown";
|
|
67
|
+
readonly currentTurnId: string | null;
|
|
68
|
+
readonly capabilities: SessionCapabilities;
|
|
69
|
+
readonly operations: SessionOperations;
|
|
70
|
+
readonly cleanupInteractionIds?: readonly string[];
|
|
71
|
+
};
|
|
72
|
+
export type TextPart = {
|
|
73
|
+
readonly type: "text";
|
|
74
|
+
readonly text: string;
|
|
75
|
+
};
|
|
76
|
+
export type ResourcePart = {
|
|
77
|
+
readonly type: "resource";
|
|
78
|
+
readonly resourceId: string;
|
|
79
|
+
readonly label: string;
|
|
80
|
+
};
|
|
81
|
+
export type MessagePart = TextPart | ResourcePart;
|
|
82
|
+
export type ApprovalAction = "allow_once" | "allow_session" | "reject";
|
|
83
|
+
export type FormValue = string | number | boolean | readonly string[];
|
|
84
|
+
export type InteractionResponse = {
|
|
85
|
+
readonly kind: "approval";
|
|
86
|
+
readonly action: ApprovalAction;
|
|
87
|
+
} | {
|
|
88
|
+
readonly kind: "question";
|
|
89
|
+
readonly answers: readonly {
|
|
90
|
+
readonly questionId: string;
|
|
91
|
+
readonly optionIds: readonly string[];
|
|
92
|
+
readonly text: string | null;
|
|
93
|
+
}[];
|
|
94
|
+
} | {
|
|
95
|
+
readonly kind: "form";
|
|
96
|
+
readonly values: readonly {
|
|
97
|
+
readonly fieldId: string;
|
|
98
|
+
readonly value: FormValue;
|
|
99
|
+
}[];
|
|
100
|
+
} | {
|
|
101
|
+
readonly kind: "dismiss";
|
|
102
|
+
};
|
|
103
|
+
export type SessionCommand = SessionFence & {
|
|
104
|
+
readonly protocol: typeof SESSION_PROTOCOL;
|
|
105
|
+
readonly requestId: string;
|
|
106
|
+
readonly operationId: string;
|
|
107
|
+
} & ({
|
|
108
|
+
readonly kind: "send_message";
|
|
109
|
+
readonly payload: {
|
|
110
|
+
readonly content: readonly TextPart[];
|
|
111
|
+
readonly expectedTurnId: string | null;
|
|
112
|
+
};
|
|
113
|
+
} | {
|
|
114
|
+
readonly kind: "update_setting";
|
|
115
|
+
readonly payload: {
|
|
116
|
+
readonly settingId: string;
|
|
117
|
+
readonly value: string;
|
|
118
|
+
readonly expectedControlsRevision: string;
|
|
119
|
+
};
|
|
120
|
+
} | {
|
|
121
|
+
readonly kind: "execute_command";
|
|
122
|
+
readonly payload: {
|
|
123
|
+
readonly commandId: string;
|
|
124
|
+
readonly arguments: string;
|
|
125
|
+
readonly expectedControlsRevision: string;
|
|
126
|
+
readonly expectedTurnId: string | null;
|
|
127
|
+
};
|
|
128
|
+
} | {
|
|
129
|
+
readonly kind: "refresh_controls";
|
|
130
|
+
readonly payload: Record<string, never>;
|
|
131
|
+
} | {
|
|
132
|
+
readonly kind: "cancel";
|
|
133
|
+
readonly payload: {
|
|
134
|
+
readonly expectedTurnId: string;
|
|
135
|
+
};
|
|
136
|
+
} | {
|
|
137
|
+
readonly kind: "interaction_response";
|
|
138
|
+
readonly payload: {
|
|
139
|
+
readonly interactionId: string;
|
|
140
|
+
readonly interactionRevision: DecimalSequence;
|
|
141
|
+
readonly submissionId: string;
|
|
142
|
+
readonly response: InteractionResponse;
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
export type OperationState = "accepted" | "offered" | "dispatching" | "provider_accepted" | "confirmed" | "failed" | "rejected" | "expired" | "unknown";
|
|
146
|
+
export type SessionOperation = SessionFence & {
|
|
147
|
+
readonly protocol: typeof SESSION_PROTOCOL;
|
|
148
|
+
readonly operationId: string;
|
|
149
|
+
readonly kind: SessionCommand["kind"];
|
|
150
|
+
readonly state: OperationState;
|
|
151
|
+
readonly providerResult: "started" | "queued" | "handled" | null;
|
|
152
|
+
readonly error: {
|
|
153
|
+
readonly code: string;
|
|
154
|
+
readonly message: string;
|
|
155
|
+
} | null;
|
|
156
|
+
};
|
|
157
|
+
export type SessionResource = {
|
|
158
|
+
readonly resourceId: string;
|
|
159
|
+
readonly status: "pending" | "available" | "failed" | "unavailable";
|
|
160
|
+
readonly name: string;
|
|
161
|
+
readonly mediaType: string | null;
|
|
162
|
+
readonly byteLength: DecimalSequence | null;
|
|
163
|
+
readonly sha256: string | null;
|
|
164
|
+
readonly error: string | null;
|
|
165
|
+
};
|
|
166
|
+
export type InteractionOption = {
|
|
167
|
+
readonly id: string;
|
|
168
|
+
readonly label: string;
|
|
169
|
+
};
|
|
170
|
+
export type FormField = {
|
|
171
|
+
readonly fieldId: string;
|
|
172
|
+
readonly label: string;
|
|
173
|
+
readonly required: boolean;
|
|
174
|
+
} & ({
|
|
175
|
+
readonly type: "text";
|
|
176
|
+
readonly sensitive: boolean;
|
|
177
|
+
} | {
|
|
178
|
+
readonly type: "number";
|
|
179
|
+
readonly min: number | null;
|
|
180
|
+
readonly max: number | null;
|
|
181
|
+
} | {
|
|
182
|
+
readonly type: "boolean";
|
|
183
|
+
} | {
|
|
184
|
+
readonly type: "select" | "multiselect";
|
|
185
|
+
readonly options: readonly InteractionOption[];
|
|
186
|
+
});
|
|
187
|
+
export type SessionInteraction = {
|
|
188
|
+
readonly interactionId: string;
|
|
189
|
+
readonly revision: DecimalSequence;
|
|
190
|
+
readonly state: "pending" | "resolved" | "expired";
|
|
191
|
+
readonly title: string;
|
|
192
|
+
} & ({
|
|
193
|
+
readonly kind: "approval";
|
|
194
|
+
readonly detail: string;
|
|
195
|
+
readonly actions: readonly ApprovalAction[];
|
|
196
|
+
} | {
|
|
197
|
+
readonly kind: "question";
|
|
198
|
+
readonly questions: readonly {
|
|
199
|
+
readonly questionId: string;
|
|
200
|
+
readonly label: string;
|
|
201
|
+
readonly options: readonly InteractionOption[];
|
|
202
|
+
readonly multiple: boolean;
|
|
203
|
+
readonly allowCustom: boolean;
|
|
204
|
+
readonly required: boolean;
|
|
205
|
+
readonly sensitive: boolean;
|
|
206
|
+
}[];
|
|
207
|
+
readonly canDismiss: boolean;
|
|
208
|
+
} | {
|
|
209
|
+
readonly kind: "form";
|
|
210
|
+
readonly fields: readonly FormField[];
|
|
211
|
+
readonly canDismiss: boolean;
|
|
212
|
+
});
|
|
213
|
+
export type TimelineEntry = {
|
|
214
|
+
readonly entryId: string;
|
|
215
|
+
readonly entrySeq: DecimalSequence;
|
|
216
|
+
readonly revision: DecimalSequence;
|
|
217
|
+
} & ({
|
|
218
|
+
readonly kind: "user_message" | "assistant_message";
|
|
219
|
+
readonly content: readonly MessagePart[];
|
|
220
|
+
} | {
|
|
221
|
+
readonly kind: "reasoning";
|
|
222
|
+
readonly text: string;
|
|
223
|
+
} | {
|
|
224
|
+
readonly kind: "tool_call";
|
|
225
|
+
readonly callId: string;
|
|
226
|
+
readonly name: string;
|
|
227
|
+
readonly input: string;
|
|
228
|
+
readonly output: readonly MessagePart[];
|
|
229
|
+
readonly status: "running" | "completed" | "failed";
|
|
230
|
+
readonly truncated: boolean;
|
|
231
|
+
} | {
|
|
232
|
+
readonly kind: "interaction";
|
|
233
|
+
readonly interaction: SessionInteraction;
|
|
234
|
+
} | {
|
|
235
|
+
readonly kind: "error";
|
|
236
|
+
readonly code: string;
|
|
237
|
+
readonly message: string;
|
|
238
|
+
} | {
|
|
239
|
+
readonly kind: "compaction";
|
|
240
|
+
readonly summary: string;
|
|
241
|
+
} | {
|
|
242
|
+
readonly kind: "todo";
|
|
243
|
+
readonly items: readonly {
|
|
244
|
+
readonly id: string;
|
|
245
|
+
readonly text: string;
|
|
246
|
+
readonly status: "pending" | "in_progress" | "completed";
|
|
247
|
+
}[];
|
|
248
|
+
});
|
|
249
|
+
export type SessionEvent = ControllerFence & {
|
|
250
|
+
readonly protocol: typeof SESSION_PROTOCOL;
|
|
251
|
+
readonly eventSeq: DecimalSequence;
|
|
252
|
+
readonly historyEpoch: string;
|
|
253
|
+
} & ({
|
|
254
|
+
readonly kind: "timeline_upsert";
|
|
255
|
+
readonly payload: TimelineEntry;
|
|
256
|
+
} | {
|
|
257
|
+
readonly kind: "snapshot";
|
|
258
|
+
readonly payload: SessionSnapshot;
|
|
259
|
+
} | {
|
|
260
|
+
readonly kind: "operation";
|
|
261
|
+
readonly payload: SessionOperation;
|
|
262
|
+
} | {
|
|
263
|
+
readonly kind: "resource";
|
|
264
|
+
readonly payload: SessionResource;
|
|
265
|
+
} | {
|
|
266
|
+
readonly kind: "gap";
|
|
267
|
+
readonly payload: {
|
|
268
|
+
readonly reason: string;
|
|
269
|
+
readonly cursor: string | null;
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
export declare const sessionBindingKeys: (value: unknown) => readonly string[];
|
|
273
|
+
export declare const sessionBinding: (value: unknown) => SessionBinding;
|
|
274
|
+
export declare const sessionFence: (data: SessionFence) => SessionFence;
|
|
275
|
+
export declare const sessionFenceKey: (data: SessionFence) => string;
|
|
276
|
+
export declare const assertSessionFence: (actual: SessionFence & {
|
|
277
|
+
readonly connectionEpoch?: string;
|
|
278
|
+
}, expected: SessionFence & {
|
|
279
|
+
readonly connectionEpoch?: string;
|
|
280
|
+
}) => void;
|
|
281
|
+
export declare const parseInteractionResponse: (value: unknown) => InteractionResponse;
|
|
282
|
+
export declare const parseSessionCommand: (value: unknown) => SessionCommand;
|
|
283
|
+
export declare const sessionControlKeys: (value: unknown) => string[];
|
|
284
|
+
export declare const parseSessionControlFields: (data: Record<string, unknown>) => Pick<SessionSnapshot, "controls" | "turnStartedAt">;
|
|
285
|
+
export declare const parseSessionSnapshot: (value: unknown) => SessionSnapshot;
|
|
286
|
+
export declare const parseSessionOperation: (value: unknown) => SessionOperation;
|
|
287
|
+
export declare const parseSessionResource: (value: unknown) => SessionResource;
|
|
288
|
+
export declare const parseSessionInteraction: (value: unknown) => SessionInteraction;
|
|
289
|
+
export declare const parseTimelineEntry: (value: unknown) => TimelineEntry;
|
|
290
|
+
export declare const parseSessionEvent: (value: unknown) => SessionEvent;
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { parseSessionControls } from "./controls.js";
|
|
2
|
+
// This wire contract is shared with the browser and must not import Node modules.
|
|
3
|
+
export const SESSION_PROTOCOL = "daynight.session.v1";
|
|
4
|
+
export const SESSION_SCHEMA_VERSION = 1;
|
|
5
|
+
export const SESSION_PROJECTION_VERSION = 1;
|
|
6
|
+
const invalid = () => { throw new Error("Invalid Daynight session protocol value."); };
|
|
7
|
+
const object = (value, keys) => {
|
|
8
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
9
|
+
return invalid();
|
|
10
|
+
const data = value;
|
|
11
|
+
if (Object.keys(data).length !== keys.length || keys.some((key) => !Object.hasOwn(data, key)))
|
|
12
|
+
return invalid();
|
|
13
|
+
return data;
|
|
14
|
+
};
|
|
15
|
+
const textBytes = new TextEncoder();
|
|
16
|
+
const text = (value, allowEmpty = false) => {
|
|
17
|
+
if (typeof value !== "string" || value.length > 1_048_576 || !value.isWellFormed() || value.includes("\0") || (!allowEmpty && !/[^\p{White_Space}]/u.test(value)) || textBytes.encode(value).byteLength > 1_048_576)
|
|
18
|
+
return invalid();
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
const key = (value) => {
|
|
22
|
+
const result = text(value);
|
|
23
|
+
return textBytes.encode(result).byteLength <= 256 ? result : invalid();
|
|
24
|
+
};
|
|
25
|
+
const id = (value) => {
|
|
26
|
+
if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(value))
|
|
27
|
+
return invalid();
|
|
28
|
+
return value;
|
|
29
|
+
};
|
|
30
|
+
const sequence = (value, zero = false) => {
|
|
31
|
+
if (typeof value !== "string" || !/^(0|[1-9][0-9]*)$/.test(value) || value.length > 19 || (!zero && value === "0") || BigInt(value) > 9223372036854775807n)
|
|
32
|
+
return invalid();
|
|
33
|
+
return value;
|
|
34
|
+
};
|
|
35
|
+
const bool = (value) => typeof value === "boolean" ? value : invalid();
|
|
36
|
+
const finite = (value) => typeof value === "number" && Number.isFinite(value) ? value : invalid();
|
|
37
|
+
const oneOf = (value, values) => typeof value === "string" && values.includes(value) ? value : invalid();
|
|
38
|
+
const nullable = (value, parse) => value === null ? null : parse(value);
|
|
39
|
+
const list = (value, parse) => {
|
|
40
|
+
if (!Array.isArray(value) || value.length > 1000)
|
|
41
|
+
return invalid();
|
|
42
|
+
return value.map(parse);
|
|
43
|
+
};
|
|
44
|
+
const unique = (values, identity) => new Set(values.map(identity)).size === values.length ? values : invalid();
|
|
45
|
+
const nonempty = (values) => values.length > 0 ? values : invalid();
|
|
46
|
+
const protocol = (value) => value === SESSION_PROTOCOL ? value : invalid();
|
|
47
|
+
export const sessionBindingKeys = (value) => {
|
|
48
|
+
if (!value || typeof value !== "object" || Object.hasOwn(value, "claimId") === Object.hasOwn(value, "testExecutionId"))
|
|
49
|
+
return invalid();
|
|
50
|
+
return Object.hasOwn(value, "testExecutionId") ? ["testExecutionId"] : ["claimId"];
|
|
51
|
+
};
|
|
52
|
+
export const sessionBinding = (value) => {
|
|
53
|
+
const keys = sessionBindingKeys(value), data = value;
|
|
54
|
+
return keys[0] === "testExecutionId" ? { testExecutionId: id(data.testExecutionId) } : { claimId: id(data.claimId) };
|
|
55
|
+
};
|
|
56
|
+
const fenceKeys = (value) => ["sessionId", ...sessionBindingKeys(value), "executionGeneration"];
|
|
57
|
+
export const sessionFence = (data) => ({ sessionId: id(data.sessionId), ...sessionBinding(data), executionGeneration: sequence(data.executionGeneration) });
|
|
58
|
+
const fence = (data) => sessionFence(data);
|
|
59
|
+
export const sessionFenceKey = (data) => JSON.stringify(sessionFence(data));
|
|
60
|
+
// A connection epoch fences relay traffic; it is not evidence that a native writer stopped.
|
|
61
|
+
export const assertSessionFence = (actual, expected) => {
|
|
62
|
+
if (actual.sessionId !== expected.sessionId || actual.claimId !== expected.claimId || actual.testExecutionId !== expected.testExecutionId || actual.executionGeneration !== expected.executionGeneration || (expected.connectionEpoch !== undefined && actual.connectionEpoch !== expected.connectionEpoch)) {
|
|
63
|
+
throw new Error("Daynight session fence mismatch.");
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const approvalAction = (value) => oneOf(value, ["allow_once", "allow_session", "reject"]);
|
|
67
|
+
const option = (value) => {
|
|
68
|
+
const data = object(value, ["id", "label"]);
|
|
69
|
+
return { id: key(data.id), label: text(data.label) };
|
|
70
|
+
};
|
|
71
|
+
const options = (value) => unique(list(value, option), (item) => item.id);
|
|
72
|
+
export const parseInteractionResponse = (value) => {
|
|
73
|
+
if (typeof value !== "object" || value === null || !("kind" in value))
|
|
74
|
+
return invalid();
|
|
75
|
+
if (value.kind === "dismiss") {
|
|
76
|
+
object(value, ["kind"]);
|
|
77
|
+
return { kind: "dismiss" };
|
|
78
|
+
}
|
|
79
|
+
if (value.kind === "approval") {
|
|
80
|
+
const data = object(value, ["kind", "action"]);
|
|
81
|
+
return { kind: "approval", action: approvalAction(data.action) };
|
|
82
|
+
}
|
|
83
|
+
if (value.kind === "question") {
|
|
84
|
+
const data = object(value, ["kind", "answers"]);
|
|
85
|
+
return { kind: "question", answers: nonempty(unique(list(data.answers, (answer) => {
|
|
86
|
+
const item = object(answer, ["questionId", "optionIds", "text"]);
|
|
87
|
+
return { questionId: key(item.questionId), optionIds: unique(list(item.optionIds, key), (entry) => entry), text: nullable(item.text, (value) => text(value, true)) };
|
|
88
|
+
}), (item) => item.questionId)) };
|
|
89
|
+
}
|
|
90
|
+
if (value.kind === "form") {
|
|
91
|
+
const data = object(value, ["kind", "values"]);
|
|
92
|
+
return { kind: "form", values: unique(list(data.values, (field) => {
|
|
93
|
+
const item = object(field, ["fieldId", "value"]);
|
|
94
|
+
const parsed = typeof item.value === "string" ? text(item.value, true) : typeof item.value === "boolean" ? item.value : typeof item.value === "number" ? finite(item.value) : unique(list(item.value, key), (entry) => entry);
|
|
95
|
+
return { fieldId: key(item.fieldId), value: parsed };
|
|
96
|
+
}), (item) => item.fieldId) };
|
|
97
|
+
}
|
|
98
|
+
return invalid();
|
|
99
|
+
};
|
|
100
|
+
export const parseSessionCommand = (value) => {
|
|
101
|
+
const data = object(value, ["protocol", "requestId", "operationId", ...fenceKeys(value), "kind", "payload"]);
|
|
102
|
+
const requestId = key(data.requestId);
|
|
103
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/.test(requestId))
|
|
104
|
+
return invalid();
|
|
105
|
+
const base = { protocol: protocol(data.protocol), requestId, operationId: id(data.operationId), ...fence(data) };
|
|
106
|
+
if (data.kind === "send_message") {
|
|
107
|
+
const payload = object(data.payload, ["content", "expectedTurnId"]);
|
|
108
|
+
const content = nonempty(list(payload.content, (part) => {
|
|
109
|
+
const item = object(part, ["type", "text"]);
|
|
110
|
+
if (item.type !== "text")
|
|
111
|
+
return invalid();
|
|
112
|
+
return { type: "text", text: text(item.text) };
|
|
113
|
+
}));
|
|
114
|
+
return { ...base, kind: "send_message", payload: { content, expectedTurnId: nullable(payload.expectedTurnId, key) } };
|
|
115
|
+
}
|
|
116
|
+
if (data.kind === "update_setting") {
|
|
117
|
+
const payload = object(data.payload, ["settingId", "value", "expectedControlsRevision"]);
|
|
118
|
+
const value = text(payload.value);
|
|
119
|
+
if (textBytes.encode(value).length > 4096)
|
|
120
|
+
return invalid();
|
|
121
|
+
return { ...base, kind: "update_setting", payload: { settingId: key(payload.settingId), value, expectedControlsRevision: sequence(payload.expectedControlsRevision) } };
|
|
122
|
+
}
|
|
123
|
+
if (data.kind === "execute_command") {
|
|
124
|
+
const payload = object(data.payload, ["commandId", "arguments", "expectedControlsRevision", "expectedTurnId"]);
|
|
125
|
+
return { ...base, kind: "execute_command", payload: { commandId: key(payload.commandId), arguments: text(payload.arguments, true), expectedControlsRevision: sequence(payload.expectedControlsRevision), expectedTurnId: nullable(payload.expectedTurnId, key) } };
|
|
126
|
+
}
|
|
127
|
+
if (data.kind === "refresh_controls") {
|
|
128
|
+
object(data.payload, []);
|
|
129
|
+
return { ...base, kind: "refresh_controls", payload: {} };
|
|
130
|
+
}
|
|
131
|
+
if (data.kind === "cancel") {
|
|
132
|
+
const payload = object(data.payload, ["expectedTurnId"]);
|
|
133
|
+
return { ...base, kind: "cancel", payload: { expectedTurnId: key(payload.expectedTurnId) } };
|
|
134
|
+
}
|
|
135
|
+
if (data.kind === "interaction_response") {
|
|
136
|
+
const payload = object(data.payload, ["interactionId", "interactionRevision", "submissionId", "response"]);
|
|
137
|
+
return { ...base, kind: "interaction_response", payload: { interactionId: id(payload.interactionId), interactionRevision: sequence(payload.interactionRevision), submissionId: id(payload.submissionId), response: parseInteractionResponse(payload.response) } };
|
|
138
|
+
}
|
|
139
|
+
return invalid();
|
|
140
|
+
};
|
|
141
|
+
export const sessionControlKeys = (value) => value && typeof value === "object" ? ["controls", "turnStartedAt"].filter(key => Object.hasOwn(value, key)) : [];
|
|
142
|
+
export const parseSessionControlFields = (data) => {
|
|
143
|
+
const result = {};
|
|
144
|
+
if (Object.hasOwn(data, "controls"))
|
|
145
|
+
result.controls = parseSessionControls(data.controls);
|
|
146
|
+
if (Object.hasOwn(data, "turnStartedAt")) {
|
|
147
|
+
const value = data.turnStartedAt;
|
|
148
|
+
if (value !== null && (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(value) || !Number.isFinite(Date.parse(value)) || new Date(value).toISOString() !== value))
|
|
149
|
+
return invalid();
|
|
150
|
+
result.turnStartedAt = value;
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
};
|
|
154
|
+
export const parseSessionSnapshot = (value) => {
|
|
155
|
+
const data = object(value, ["protocol", "schemaVersion", "projectionVersion", ...fenceKeys(value), ...sessionControlKeys(value), "connectionEpoch", "identity", "sessionRevision", "historyEpoch", "lastEventSeq", "lastTimelineSeq", "initialInputState", "synchronized", "lifecycle", "connectionState", "activity", "currentTurnId", "capabilities", "operations", ...(value && typeof value === "object" && Object.hasOwn(value, "cleanupInteractionIds") ? ["cleanupInteractionIds"] : [])]);
|
|
156
|
+
if (data.schemaVersion !== SESSION_SCHEMA_VERSION || data.projectionVersion !== SESSION_PROJECTION_VERSION)
|
|
157
|
+
return invalid();
|
|
158
|
+
const test = Object.hasOwn(data, "testExecutionId");
|
|
159
|
+
const identity = object(data.identity, [...(test ? ["ownerUserId"] : ["projectId", "taskId", "workerId", "worktreeId"]), "controllerId", "controllerInstanceId", "agentControlMode", "provider", "nativeSessionId"]);
|
|
160
|
+
if (identity.agentControlMode !== "web")
|
|
161
|
+
return invalid();
|
|
162
|
+
const capabilities = object(data.capabilities, ["send", "steer", "cancel", "respond"]);
|
|
163
|
+
const operations = object(data.operations, ["canSend", "canCancel", "canRespond"]);
|
|
164
|
+
const result = {
|
|
165
|
+
...parseSessionControlFields(data),
|
|
166
|
+
...(Object.hasOwn(data, "cleanupInteractionIds") ? { cleanupInteractionIds: unique(list(data.cleanupInteractionIds, id), item => item) } : {}),
|
|
167
|
+
protocol: protocol(data.protocol), schemaVersion: SESSION_SCHEMA_VERSION, projectionVersion: SESSION_PROJECTION_VERSION, ...fence(data), connectionEpoch: sequence(data.connectionEpoch, true),
|
|
168
|
+
identity: { ...(test ? { ownerUserId: id(identity.ownerUserId) } : { projectId: id(identity.projectId), taskId: id(identity.taskId), workerId: id(identity.workerId), worktreeId: id(identity.worktreeId) }), controllerId: id(identity.controllerId), controllerInstanceId: id(identity.controllerInstanceId), agentControlMode: "web", provider: oneOf(identity.provider, ["codex", "claude", "copilot"]), nativeSessionId: nullable(identity.nativeSessionId, key) },
|
|
169
|
+
sessionRevision: sequence(data.sessionRevision), historyEpoch: key(data.historyEpoch), lastEventSeq: sequence(data.lastEventSeq, true), lastTimelineSeq: sequence(data.lastTimelineSeq, true),
|
|
170
|
+
initialInputState: oneOf(data.initialInputState, [...(test ? ["not_required"] : []), "not_submitted", "dispatching", "provider_accepted", "confirmed", "failed", "unknown"]), synchronized: bool(data.synchronized),
|
|
171
|
+
lifecycle: oneOf(data.lifecycle, ["active", "draining", "archived"]), connectionState: oneOf(data.connectionState, ["connected", "disconnected", "synchronizing"]), activity: oneOf(data.activity, ["initializing", "idle", "working", "waiting_input", "stopped", "unknown"]), currentTurnId: nullable(data.currentTurnId, key),
|
|
172
|
+
capabilities: { send: bool(capabilities.send), steer: bool(capabilities.steer), cancel: bool(capabilities.cancel), respond: bool(capabilities.respond) },
|
|
173
|
+
operations: { canSend: bool(operations.canSend), canCancel: bool(operations.canCancel), canRespond: bool(operations.canRespond) },
|
|
174
|
+
};
|
|
175
|
+
// Initial approval callbacks may be actionable before the managed input is accepted.
|
|
176
|
+
const writable = (result.lifecycle === "active" || result.lifecycle === "draining" && !result.operations.canSend && !result.operations.canCancel) && result.connectionState === "connected" && result.synchronized;
|
|
177
|
+
if (result.connectionEpoch === "0" && (result.connectionState === "connected" || result.operations.canSend || result.operations.canCancel || result.operations.canRespond))
|
|
178
|
+
return invalid();
|
|
179
|
+
if ((result.operations.canSend || result.operations.canCancel || result.operations.canRespond) && !writable)
|
|
180
|
+
return invalid();
|
|
181
|
+
if (result.operations.canSend && (!result.capabilities.send || (result.identity.nativeSessionId === null && !(test && result.initialInputState === "not_required" && result.activity === "idle")) || !["not_required", "provider_accepted", "confirmed"].includes(result.initialInputState) || !(result.activity === "idle" || (result.activity === "working" && result.capabilities.steer && result.currentTurnId !== null))))
|
|
182
|
+
return invalid();
|
|
183
|
+
if (result.operations.canCancel && (!result.capabilities.cancel || result.currentTurnId === null))
|
|
184
|
+
return invalid();
|
|
185
|
+
if (result.operations.canRespond && (!result.capabilities.respond || result.lifecycle === "draining" && !result.cleanupInteractionIds?.length))
|
|
186
|
+
return invalid();
|
|
187
|
+
return result;
|
|
188
|
+
};
|
|
189
|
+
export const parseSessionOperation = (value) => {
|
|
190
|
+
const data = object(value, ["protocol", ...fenceKeys(value), "operationId", "kind", "state", "providerResult", "error"]);
|
|
191
|
+
const error = data.error === null ? null : object(data.error, ["code", "message"]);
|
|
192
|
+
return { protocol: protocol(data.protocol), ...fence(data), operationId: id(data.operationId), kind: oneOf(data.kind, ["send_message", "cancel", "interaction_response", "update_setting", "execute_command", "refresh_controls"]), state: oneOf(data.state, ["accepted", "offered", "dispatching", "provider_accepted", "confirmed", "failed", "rejected", "expired", "unknown"]), providerResult: nullable(data.providerResult, (value) => oneOf(value, ["started", "queued", "handled"])), error: error === null ? null : { code: key(error.code), message: text(error.message) } };
|
|
193
|
+
};
|
|
194
|
+
export const parseSessionResource = (value) => {
|
|
195
|
+
const data = object(value, ["resourceId", "status", "name", "mediaType", "byteLength", "sha256", "error"]);
|
|
196
|
+
const result = { resourceId: id(data.resourceId), status: oneOf(data.status, ["pending", "available", "failed", "unavailable"]), name: key(data.name), mediaType: nullable(data.mediaType, key), byteLength: nullable(data.byteLength, (value) => sequence(value, true)), sha256: nullable(data.sha256, key), error: nullable(data.error, text) };
|
|
197
|
+
if (result.sha256 !== null && !/^[a-f0-9]{64}$/.test(result.sha256))
|
|
198
|
+
return invalid();
|
|
199
|
+
if (result.mediaType !== null && !/^[a-zA-Z0-9!#$&^_.+-]+\/[a-zA-Z0-9!#$&^_.+-]+$/.test(result.mediaType))
|
|
200
|
+
return invalid();
|
|
201
|
+
if (result.status === "available" && (result.sha256 === null || result.mediaType === null || result.byteLength === null || result.error !== null))
|
|
202
|
+
return invalid();
|
|
203
|
+
return result;
|
|
204
|
+
};
|
|
205
|
+
const formField = (value) => {
|
|
206
|
+
if (typeof value !== "object" || value === null || !("type" in value))
|
|
207
|
+
return invalid();
|
|
208
|
+
const extra = value.type === "text" ? ["sensitive"] : value.type === "number" ? ["min", "max"] : value.type === "boolean" ? [] : ["options"];
|
|
209
|
+
const data = object(value, ["fieldId", "label", "required", "type", ...extra]);
|
|
210
|
+
const base = { fieldId: key(data.fieldId), label: text(data.label), required: bool(data.required) };
|
|
211
|
+
if (data.type === "text")
|
|
212
|
+
return { ...base, type: "text", sensitive: bool(data.sensitive) };
|
|
213
|
+
if (data.type === "number") {
|
|
214
|
+
const min = nullable(data.min, finite), max = nullable(data.max, finite);
|
|
215
|
+
if (min !== null && max !== null && min > max)
|
|
216
|
+
return invalid();
|
|
217
|
+
return { ...base, type: "number", min, max };
|
|
218
|
+
}
|
|
219
|
+
if (data.type === "boolean")
|
|
220
|
+
return { ...base, type: "boolean" };
|
|
221
|
+
return { ...base, type: oneOf(data.type, ["select", "multiselect"]), options: nonempty(options(data.options)) };
|
|
222
|
+
};
|
|
223
|
+
export const parseSessionInteraction = (value) => {
|
|
224
|
+
if (typeof value !== "object" || value === null || !("kind" in value))
|
|
225
|
+
return invalid();
|
|
226
|
+
const extra = value.kind === "approval" ? ["detail", "actions"] : value.kind === "question" ? ["questions", "canDismiss"] : ["fields", "canDismiss"];
|
|
227
|
+
const data = object(value, ["interactionId", "revision", "state", "title", "kind", ...extra]);
|
|
228
|
+
const base = { interactionId: id(data.interactionId), revision: sequence(data.revision), state: oneOf(data.state, ["pending", "resolved", "expired"]), title: text(data.title) };
|
|
229
|
+
if (data.kind === "approval")
|
|
230
|
+
return { ...base, kind: "approval", detail: text(data.detail, true), actions: nonempty(unique(list(data.actions, approvalAction), (item) => item)) };
|
|
231
|
+
if (data.kind === "question") {
|
|
232
|
+
return { ...base, kind: "question", canDismiss: bool(data.canDismiss), questions: nonempty(unique(list(data.questions, (value) => {
|
|
233
|
+
const item = object(value, ["questionId", "label", "options", "multiple", "allowCustom", "required", "sensitive"]);
|
|
234
|
+
const result = { questionId: key(item.questionId), label: text(item.label), options: options(item.options), multiple: bool(item.multiple), allowCustom: bool(item.allowCustom), required: bool(item.required), sensitive: bool(item.sensitive) };
|
|
235
|
+
if (result.options.length === 0 && !result.allowCustom)
|
|
236
|
+
return invalid();
|
|
237
|
+
return result;
|
|
238
|
+
}), (item) => item.questionId)) };
|
|
239
|
+
}
|
|
240
|
+
if (data.kind === "form")
|
|
241
|
+
return { ...base, kind: "form", canDismiss: bool(data.canDismiss), fields: nonempty(unique(list(data.fields, formField), (item) => item.fieldId)) };
|
|
242
|
+
return invalid();
|
|
243
|
+
};
|
|
244
|
+
const messagePart = (value) => {
|
|
245
|
+
if (typeof value !== "object" || value === null || !("type" in value))
|
|
246
|
+
return invalid();
|
|
247
|
+
if (value.type === "text") {
|
|
248
|
+
const data = object(value, ["type", "text"]);
|
|
249
|
+
return { type: "text", text: text(data.text, true) };
|
|
250
|
+
}
|
|
251
|
+
if (value.type === "resource") {
|
|
252
|
+
const data = object(value, ["type", "resourceId", "label"]);
|
|
253
|
+
return { type: "resource", resourceId: id(data.resourceId), label: text(data.label) };
|
|
254
|
+
}
|
|
255
|
+
return invalid();
|
|
256
|
+
};
|
|
257
|
+
export const parseTimelineEntry = (value) => {
|
|
258
|
+
if (typeof value !== "object" || value === null || !("kind" in value))
|
|
259
|
+
return invalid();
|
|
260
|
+
const common = ["entryId", "entrySeq", "revision", "kind"];
|
|
261
|
+
const extras = {
|
|
262
|
+
user_message: ["content"], assistant_message: ["content"], reasoning: ["text"], tool_call: ["callId", "name", "input", "output", "status", "truncated"],
|
|
263
|
+
interaction: ["interaction"], error: ["code", "message"], compaction: ["summary"], todo: ["items"],
|
|
264
|
+
};
|
|
265
|
+
const kind = oneOf(value.kind, ["user_message", "assistant_message", "reasoning", "tool_call", "interaction", "error", "compaction", "todo"]);
|
|
266
|
+
const data = object(value, [...common, ...extras[kind]]);
|
|
267
|
+
const base = { entryId: id(data.entryId), entrySeq: sequence(data.entrySeq), revision: sequence(data.revision) };
|
|
268
|
+
if (kind === "user_message" || kind === "assistant_message")
|
|
269
|
+
return { ...base, kind, content: list(data.content, messagePart) };
|
|
270
|
+
if (kind === "reasoning")
|
|
271
|
+
return { ...base, kind, text: text(data.text, true) };
|
|
272
|
+
if (kind === "tool_call")
|
|
273
|
+
return { ...base, kind, callId: key(data.callId), name: key(data.name), input: text(data.input, true), output: list(data.output, messagePart), status: oneOf(data.status, ["running", "completed", "failed"]), truncated: bool(data.truncated) };
|
|
274
|
+
if (kind === "interaction")
|
|
275
|
+
return { ...base, kind, interaction: parseSessionInteraction(data.interaction) };
|
|
276
|
+
if (kind === "error")
|
|
277
|
+
return { ...base, kind, code: key(data.code), message: text(data.message) };
|
|
278
|
+
if (kind === "compaction")
|
|
279
|
+
return { ...base, kind, summary: text(data.summary, true) };
|
|
280
|
+
return { ...base, kind: "todo", items: unique(list(data.items, (value) => { const item = object(value, ["id", "text", "status"]); return { id: key(item.id), text: text(item.text), status: oneOf(item.status, ["pending", "in_progress", "completed"]) }; }), (item) => item.id) };
|
|
281
|
+
};
|
|
282
|
+
export const parseSessionEvent = (value) => {
|
|
283
|
+
const data = object(value, ["protocol", ...fenceKeys(value), "connectionEpoch", "eventSeq", "historyEpoch", "kind", "payload"]);
|
|
284
|
+
const base = { protocol: protocol(data.protocol), ...fence(data), connectionEpoch: sequence(data.connectionEpoch, data.kind === "snapshot"), eventSeq: sequence(data.eventSeq), historyEpoch: key(data.historyEpoch) };
|
|
285
|
+
if (data.kind === "timeline_upsert")
|
|
286
|
+
return { ...base, kind: "timeline_upsert", payload: parseTimelineEntry(data.payload) };
|
|
287
|
+
if (data.kind === "snapshot") {
|
|
288
|
+
const payload = parseSessionSnapshot(data.payload);
|
|
289
|
+
assertSessionFence(payload, base);
|
|
290
|
+
if (payload.historyEpoch !== base.historyEpoch)
|
|
291
|
+
return invalid();
|
|
292
|
+
return { ...base, kind: "snapshot", payload };
|
|
293
|
+
}
|
|
294
|
+
if (data.kind === "operation") {
|
|
295
|
+
const payload = parseSessionOperation(data.payload);
|
|
296
|
+
assertSessionFence(payload, fence(data));
|
|
297
|
+
return { ...base, kind: "operation", payload };
|
|
298
|
+
}
|
|
299
|
+
if (data.kind === "resource")
|
|
300
|
+
return { ...base, kind: "resource", payload: parseSessionResource(data.payload) };
|
|
301
|
+
if (data.kind === "gap") {
|
|
302
|
+
const payload = object(data.payload, ["reason", "cursor"]);
|
|
303
|
+
return { ...base, kind: "gap", payload: { reason: text(payload.reason), cursor: nullable(payload.cursor, key) } };
|
|
304
|
+
}
|
|
305
|
+
return invalid();
|
|
306
|
+
};
|
|
307
|
+
//# sourceMappingURL=protocol.js.map
|