@otto-code/protocol 0.7.5 → 0.8.0
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/dist/agent-attention-notification.d.ts +2 -0
- package/dist/agent-attention-notification.js +2 -1
- package/dist/agent-deep-link.d.ts +8 -0
- package/dist/agent-deep-link.js +49 -0
- package/dist/agent-labels.js +4 -4
- package/dist/agent-personalities.d.ts +2 -2
- package/dist/agent-personalities.js +17 -17
- package/dist/agent-teams.d.ts +4 -4
- package/dist/agent-teams.js +5 -5
- package/dist/agent-types.d.ts +12 -10
- package/dist/agent-types.js +1 -1
- package/dist/artifacts/rpc-schemas.js +4 -4
- package/dist/artifacts/types.js +3 -3
- package/dist/binary-frames/file-transfer.d.ts +1 -0
- package/dist/binary-frames/file-transfer.js +1 -0
- package/dist/browser-automation/rpc-schemas.js +1 -1
- package/dist/client-capabilities.d.ts +3 -0
- package/dist/client-capabilities.js +9 -0
- package/dist/daemon-endpoints.d.ts +1 -1
- package/dist/default-personalities.js +11 -11
- package/dist/effort.d.ts +1 -1
- package/dist/effort.js +2 -2
- package/dist/forge-manifest.d.ts +66 -0
- package/dist/forge-manifest.js +92 -0
- package/dist/generated/validation/ws-outbound.aot.js +77653 -51519
- package/dist/git-hosting.js +3 -3
- package/dist/git-remote.d.ts +17 -0
- package/dist/git-remote.js +23 -2
- package/dist/judge-verdict.d.ts +1 -1
- package/dist/judge-verdict.js +2 -2
- package/dist/messages.d.ts +10634 -135
- package/dist/messages.js +1744 -193
- package/dist/model-tiers.d.ts +3 -3
- package/dist/model-tiers.js +4 -4
- package/dist/observed-subagent-title.d.ts +2 -2
- package/dist/observed-subagent-title.js +4 -4
- package/dist/orchestration.d.ts +3 -3
- package/dist/orchestration.js +32 -32
- package/dist/otto-config-schema.d.ts +21 -0
- package/dist/otto-config-schema.js +23 -1
- package/dist/provider-config.d.ts +92 -3
- package/dist/provider-config.js +58 -6
- package/dist/provider-manifest.d.ts +11 -1
- package/dist/provider-manifest.js +53 -5
- package/dist/schedule/cadence.d.ts +6 -0
- package/dist/schedule/cadence.js +28 -0
- package/dist/schedule/rpc-schemas.d.ts +4 -4
- package/dist/schedule/rpc-schemas.js +1 -1
- package/dist/schedule/types.d.ts +1 -1
- package/dist/schedule/types.js +3 -3
- package/dist/tool-call-display.d.ts +1 -1
- package/dist/tool-call-display.js +3 -3
- package/dist/tool-name-normalization.d.ts +2 -2
- package/dist/tool-name-normalization.js +2 -2
- package/dist/validation/ws-outbound-schema-metadata.d.ts +1950 -52
- package/dist/widgets/bridge.d.ts +5 -5
- package/dist/widgets/bridge.js +5 -5
- package/dist/widgets/document.d.ts +1 -1
- package/dist/widgets/document.js +4 -4
- package/dist/widgets/icons.d.ts +1 -1
- package/dist/widgets/icons.js +1 -1
- package/dist/widgets/theme.d.ts +2 -2
- package/dist/widgets/theme.js +2 -2
- package/dist/widgets/types.d.ts +5 -5
- package/dist/widgets/types.js +5 -5
- package/package.json +1 -1
package/dist/messages.js
CHANGED
|
@@ -51,7 +51,7 @@ const MutableMetadataGenerationConfigSchema = z
|
|
|
51
51
|
// true preserves today's behavior. Read by the generation path (WP-B).
|
|
52
52
|
enabled: z.boolean().default(true),
|
|
53
53
|
// When true, metadata generation prefers a role-matched Writer personality
|
|
54
|
-
// over the cheap default tier. Default false
|
|
54
|
+
// over the cheap default tier. Default false - cheap-tier routing is the
|
|
55
55
|
// default. Read by the generation routing (WP-B).
|
|
56
56
|
preferWriterPersonalities: z.boolean().default(false),
|
|
57
57
|
})
|
|
@@ -97,11 +97,11 @@ const MutableBrowserToolsConfigSchema = z
|
|
|
97
97
|
.passthrough();
|
|
98
98
|
/**
|
|
99
99
|
* Language-server code intelligence, host-scoped because the servers are processes
|
|
100
|
-
* on the daemon's machine
|
|
100
|
+
* on the daemon's machine - they follow the host, not the client.
|
|
101
101
|
*
|
|
102
102
|
* `enabled` defaults **on** and that is safe: nothing spawns until a
|
|
103
103
|
* code-intelligence action needs a language in a workspace, so an unused language
|
|
104
|
-
* costs nothing. What the switch guarantees is that off means off
|
|
104
|
+
* costs nothing. What the switch guarantees is that off means off - no server
|
|
105
105
|
* spawns for any workspace, and the ctags index still serves the outline and the
|
|
106
106
|
* fuzzy finder.
|
|
107
107
|
*
|
|
@@ -121,16 +121,16 @@ const MutableLspConfigSchema = z
|
|
|
121
121
|
})
|
|
122
122
|
.passthrough();
|
|
123
123
|
/**
|
|
124
|
-
* "Microsoft .NET Solution Management"
|
|
124
|
+
* "Microsoft .NET Solution Management" - the Solution view's own switch.
|
|
125
125
|
*
|
|
126
126
|
* **A sibling of `lsp`, not a member of it.** Turning C# code intelligence off does not turn
|
|
127
127
|
* this off and vice versa: they are independent capabilities that happen to share a language,
|
|
128
128
|
* and nesting this inside the LSP settings object would imply exactly the coupling that
|
|
129
|
-
* decision rejects. (It would also be wrong on the facts
|
|
129
|
+
* decision rejects. (It would also be wrong on the facts - LSP has no project-structure
|
|
130
130
|
* request, so nothing here rides on a language server.)
|
|
131
131
|
*
|
|
132
132
|
* Defaults **off**: the feature spawns a process and evaluates MSBuild. Disabled is genuinely
|
|
133
|
-
* off, not merely hidden
|
|
133
|
+
* off, not merely hidden - no discovery walk, no `.sln` read, no `.csproj` parse, no sidecar,
|
|
134
134
|
* no cache, no watcher, and no view switcher. The daemon reads this before scheduling any work,
|
|
135
135
|
* so a disabled feature costs exactly one boolean check.
|
|
136
136
|
*/
|
|
@@ -214,26 +214,26 @@ export const MutableGitHostingConfigSchema = z
|
|
|
214
214
|
.passthrough();
|
|
215
215
|
// Canonical personality roles, in display order. Kept as an exported const so
|
|
216
216
|
// the daemon and app share one vocabulary, but the wire schema stores roles as
|
|
217
|
-
// plain strings (below)
|
|
217
|
+
// plain strings (below) - adding a role later must never break an older peer's
|
|
218
218
|
// parsing. Consumers filter incoming role arrays to this known set. The retired
|
|
219
219
|
// "worker" role is mapped to "coder" on the way in (see LEGACY_ROLE_ALIASES in
|
|
220
220
|
// agent-personalities.ts) so personalities persisted before the split keep their
|
|
221
221
|
// role rather than silently losing it.
|
|
222
222
|
export const PERSONALITY_ROLES = [
|
|
223
|
-
// Surfaces
|
|
223
|
+
// Surfaces - the interactive / host-facing entry points.
|
|
224
224
|
"chatter",
|
|
225
225
|
"artificer",
|
|
226
226
|
"scheduler",
|
|
227
|
-
// Thinking workers
|
|
227
|
+
// Thinking workers - read-only, return structured findings, never edit.
|
|
228
228
|
"researcher",
|
|
229
229
|
"planner",
|
|
230
230
|
"judger",
|
|
231
231
|
"advisor",
|
|
232
|
-
// Making workers
|
|
232
|
+
// Making workers - produce code, design, or short text.
|
|
233
233
|
"coder",
|
|
234
234
|
"designer",
|
|
235
235
|
"writer",
|
|
236
|
-
// Conductor
|
|
236
|
+
// Conductor - the sole role whose whole job is planning and driving a team.
|
|
237
237
|
"orchestrator",
|
|
238
238
|
];
|
|
239
239
|
// Two glow colors for the personality's thinking spinner (BlobLoader glowA/glowB).
|
|
@@ -243,8 +243,8 @@ const AgentPersonalitySpinnerSchema = z
|
|
|
243
243
|
glowB: z.string().min(1),
|
|
244
244
|
})
|
|
245
245
|
.passthrough();
|
|
246
|
-
// A TTS voice for the personality's spoken identity. Stored self-describing
|
|
247
|
-
// provider + model + voice name
|
|
246
|
+
// A TTS voice for the personality's spoken identity. Stored self-describing -
|
|
247
|
+
// provider + model + voice name - because voice names are namespaced per TTS
|
|
248
248
|
// engine/model (the same speaker index maps to different names across models),
|
|
249
249
|
// so a bare name is ambiguous across hosts. All plain strings (like the speech
|
|
250
250
|
// config) for forward-compat. This is a soft binding: an unavailable voice
|
|
@@ -258,17 +258,17 @@ const AgentPersonalityVoiceSchema = z
|
|
|
258
258
|
})
|
|
259
259
|
.passthrough();
|
|
260
260
|
// The Visualizer lifecycle moments a personality voice-cue line can belong to.
|
|
261
|
-
// Protocol owns this vocabulary
|
|
261
|
+
// Protocol owns this vocabulary - the daemon's cue generator, the personality
|
|
262
262
|
// editor, and the Visualizer playback hook all import it from here.
|
|
263
263
|
// "waiting" is the parent's turn ending while its observed sub-agents are still
|
|
264
264
|
// running; it DEFERS "done" rather than replacing it (see docs/visualizer.md).
|
|
265
265
|
export const CUE_MOMENTS = ["join", "thinking", "waiting", "done"];
|
|
266
266
|
// Pre-generated (and user-editable) spoken "voice cue" lines for the personality
|
|
267
|
-
//
|
|
267
|
+
// - a few short variations for each Visualizer moment (its node joins the graph,
|
|
268
268
|
// first starts thinking, finishes its turn but waits on sub-agents, completes).
|
|
269
269
|
// Stored on the personality so they're deterministic and hand-tunable in the
|
|
270
270
|
// editor; the Visualizer reads them directly (no runtime generation). All groups
|
|
271
|
-
// optional/loose
|
|
271
|
+
// optional/loose - a personality may have none, or only some (personalities
|
|
272
272
|
// authored before "waiting" existed simply stay silent for that moment).
|
|
273
273
|
// See docs/visualizer.md "Voice cues".
|
|
274
274
|
const AgentPersonalityVoiceCuesSchema = z
|
|
@@ -326,7 +326,7 @@ const MutableAgentPersonalitiesConfigPatchSchema = z
|
|
|
326
326
|
})
|
|
327
327
|
.passthrough();
|
|
328
328
|
// A team's avatar. v1 ships only `color` (hex, validated at the editor like
|
|
329
|
-
// spinner colors); `imageId` is reserved for the future themed avatar set
|
|
329
|
+
// spinner colors); `imageId` is reserved for the future themed avatar set -
|
|
330
330
|
// when present it wins over color, and color stays the fallback so an old
|
|
331
331
|
// client that doesn't know `imageId` keeps rendering the swatch. Plain
|
|
332
332
|
// strings for forward compat.
|
|
@@ -340,7 +340,7 @@ const AgentTeamAvatarSchema = z
|
|
|
340
340
|
// template: which personalities are on deck, plus a shared team prompt stacked
|
|
341
341
|
// directly ahead of the member's personality prompt at spawn. `id` is the
|
|
342
342
|
// stable identity everything binds to; `name` is a freely-renamable label.
|
|
343
|
-
// `memberIds` bind personality ids (order = display order)
|
|
343
|
+
// `memberIds` bind personality ids (order = display order) - an entry pointing
|
|
344
344
|
// at a deleted personality is tolerated and ignored everywhere, then pruned on
|
|
345
345
|
// the next save of that team. Membership is many-to-many.
|
|
346
346
|
export const AgentTeamSchema = z
|
|
@@ -376,7 +376,7 @@ export const ModelTierSchema = z.enum(["deep", "standard", "fast"]);
|
|
|
376
376
|
// A user's explicit tier tag for one model of one provider. The daemon stamps
|
|
377
377
|
// `model.tier` at ingest, preferring a matching override here over inference
|
|
378
378
|
// (see model-tiers.ts). Stored as an array (not a nested record) so a patch
|
|
379
|
-
// replaces it wholesale
|
|
379
|
+
// replaces it wholesale - that's how a tag gets cleared, since deep-merge can't
|
|
380
380
|
// delete a record key.
|
|
381
381
|
export const ModelTierOverrideSchema = z
|
|
382
382
|
.object({
|
|
@@ -390,13 +390,13 @@ export const ModelTierOverrideSchema = z
|
|
|
390
390
|
// pick instead of re-typing the key. Entries are scoped by the connection
|
|
391
391
|
// env-var pair they belong to (OPENAI_BASE_URL/OPENAI_API_KEY vs
|
|
392
392
|
// ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN), which is exactly what the provider
|
|
393
|
-
// settings sheet keys its dropdown off
|
|
393
|
+
// settings sheet keys its dropdown off - so every openai-compatible provider
|
|
394
394
|
// entry on the host shares one pool, and Claude-compatible entries share
|
|
395
395
|
// another. Deliberately `z.string()` rather than an enum: a future env-var
|
|
396
396
|
// family must not make old entries unparseable.
|
|
397
397
|
export const SavedProviderEndpointSchema = z
|
|
398
398
|
.object({
|
|
399
|
-
/** Stable identity, `${baseUrlKey}::${baseUrl}`
|
|
399
|
+
/** Stable identity, `${baseUrlKey}::${baseUrl}` - dedupes on re-save. */
|
|
400
400
|
id: z.string().min(1),
|
|
401
401
|
baseUrlKey: z.string().min(1),
|
|
402
402
|
apiKeyKey: z.string().min(1),
|
|
@@ -431,6 +431,12 @@ export const MutableBrainRemoteConfigSchema = z
|
|
|
431
431
|
secure: z.boolean().default(false),
|
|
432
432
|
// Secret: masked with DAEMON_CONFIG_SECRET_SENTINEL on the way out.
|
|
433
433
|
authToken: z.string().nullable().default(null),
|
|
434
|
+
// SHA-256 fingerprint of the remote brain's TLS certificate (openssl's
|
|
435
|
+
// "AB:CD:..." form; colons optional). When set, the daemon pins HTTPS
|
|
436
|
+
// connections to exactly this certificate instead of the system trust
|
|
437
|
+
// store - required for a brain serving tls.mode=self-signed. When null,
|
|
438
|
+
// the certificate must validate against the system trust store.
|
|
439
|
+
certFingerprint: z.string().nullable().default(null),
|
|
434
440
|
})
|
|
435
441
|
.passthrough();
|
|
436
442
|
export const MutableBrainConfigSchema = z
|
|
@@ -446,6 +452,7 @@ export const MutableBrainConfigSchema = z
|
|
|
446
452
|
port: 1234,
|
|
447
453
|
secure: false,
|
|
448
454
|
authToken: null,
|
|
455
|
+
certFingerprint: null,
|
|
449
456
|
}),
|
|
450
457
|
listen: z
|
|
451
458
|
.object({
|
|
@@ -477,13 +484,13 @@ export const MutableBrainConfigSchema = z
|
|
|
477
484
|
}),
|
|
478
485
|
})
|
|
479
486
|
.passthrough();
|
|
480
|
-
// The brain PATCH schema
|
|
487
|
+
// The brain PATCH schema - deliberately NOT `MutableBrainConfigSchema.partial()`.
|
|
481
488
|
// Every field of the full schema carries a `.default()` (so an old daemon's
|
|
482
489
|
// half-written config still parses as a well-formed OFF section), and Zod keeps
|
|
483
490
|
// those defaults through `.partial()`: `MutableBrainConfigSchema.partial().parse(
|
|
484
491
|
// { allowRemoteConfig: true })` expands to the FULL object with every other field
|
|
485
492
|
// defaulted. The daemon deep-merges the parsed patch over the stored config, so a
|
|
486
|
-
// single-field patch would silently reset the entire brain block to defaults
|
|
493
|
+
// single-field patch would silently reset the entire brain block to defaults -
|
|
487
494
|
// turning sharing off (host back to loopback), wiping the auth token, and
|
|
488
495
|
// disabling the server. Mirroring the shape WITHOUT defaults keeps an omitted
|
|
489
496
|
// field omitted, so the deep-merge preserves it. Every level is deep-partial so a
|
|
@@ -507,6 +514,7 @@ const MutableBrainRemotePatchSchema = z
|
|
|
507
514
|
port: z.number().int(),
|
|
508
515
|
secure: z.boolean(),
|
|
509
516
|
authToken: z.string().nullable(),
|
|
517
|
+
certFingerprint: z.string().nullable(),
|
|
510
518
|
})
|
|
511
519
|
.partial()
|
|
512
520
|
.passthrough();
|
|
@@ -538,7 +546,7 @@ export const DEFAULT_MUTABLE_BRAIN_CONFIG = {
|
|
|
538
546
|
enabled: false,
|
|
539
547
|
autoStart: false,
|
|
540
548
|
mode: "local",
|
|
541
|
-
remote: { host: "", port: 1234, secure: false, authToken: null },
|
|
549
|
+
remote: { host: "", port: 1234, secure: false, authToken: null, certFingerprint: null },
|
|
542
550
|
listen: { host: "127.0.0.1", port: 1234 },
|
|
543
551
|
defaultModel: null,
|
|
544
552
|
lockModel: false,
|
|
@@ -567,7 +575,7 @@ export const MutableDaemonConfigSchema = z
|
|
|
567
575
|
toolGroups: z.array(z.enum(OTTO_TOOL_GROUPS)).optional(),
|
|
568
576
|
})
|
|
569
577
|
.passthrough(),
|
|
570
|
-
// Defaults off, matching the daemon's own resolution
|
|
578
|
+
// Defaults off, matching the daemon's own resolution - browser tools are an
|
|
571
579
|
// explicit opt-in, so an omitted section must never read as on.
|
|
572
580
|
browserTools: MutableBrowserToolsConfigSchema.default({ enabled: false }),
|
|
573
581
|
// Daemon-wide agent behavior toggles (Claude-tier capabilities). Defaults to
|
|
@@ -659,11 +667,12 @@ export const MutableDaemonConfigPatchSchema = z
|
|
|
659
667
|
// Gated by server_info features.agentBehaviorToggles; patches deep-merge.
|
|
660
668
|
agentBehaviors: MutableAgentBehaviorsConfigSchema.partial().optional(),
|
|
661
669
|
// A null entry removes the provider's config entirely (custom provider
|
|
662
|
-
// uninstall). Gated by server_info features.providerRemove
|
|
670
|
+
// uninstall). Gated by server_info features.providerRemove - old daemons
|
|
663
671
|
// reject null values.
|
|
664
672
|
providers: z
|
|
665
673
|
.record(z.string(), MutableDaemonProviderConfigSchema.partial().passthrough().nullable())
|
|
666
674
|
.optional(),
|
|
675
|
+
removeProviders: z.array(z.string().min(1)).optional(),
|
|
667
676
|
metadataGeneration: MutableMetadataGenerationConfigSchema.partial().optional(),
|
|
668
677
|
autoArchiveAfterMerge: z.boolean().optional(),
|
|
669
678
|
// Gated by server_info features.hideMergeIntoBaseSetting.
|
|
@@ -745,7 +754,7 @@ export const AgentRateLimitInfoSchema = z.object({
|
|
|
745
754
|
// does not report it (Claude only includes it near the limit).
|
|
746
755
|
utilizationPercent: z.number().optional(),
|
|
747
756
|
// Provider-reported window identifier, e.g. "five_hour" | "seven_day".
|
|
748
|
-
// Open set
|
|
757
|
+
// Open set - display code falls back to a generic label for unknown values.
|
|
749
758
|
limitType: z.string().optional(),
|
|
750
759
|
// ISO 8601 timestamp when the window resets.
|
|
751
760
|
resetsAt: z.string().optional(),
|
|
@@ -796,6 +805,7 @@ export const ProviderSnapshotEntrySchema = z.object({
|
|
|
796
805
|
provider: AgentProviderSchema,
|
|
797
806
|
status: ProviderStatusSchema,
|
|
798
807
|
enabled: z.boolean().optional().default(true),
|
|
808
|
+
source: z.enum(["builtin", "custom"]).optional(),
|
|
799
809
|
error: z.string().optional(),
|
|
800
810
|
models: z.array(AgentModelDefinitionSchema).optional(),
|
|
801
811
|
modes: z.array(AgentModeSchema).optional(),
|
|
@@ -848,7 +858,7 @@ const AgentUsageSchema = z.object({
|
|
|
848
858
|
// Provider-graded context breakdown for the visualizer ring/bar; absent ⇒
|
|
849
859
|
// occupancy only (pre-composition behavior). See ContextComposition.
|
|
850
860
|
contextComposition: ContextCompositionSchema.optional(),
|
|
851
|
-
// The provider's own labelled split
|
|
861
|
+
// The provider's own labelled split - same accounting as
|
|
852
862
|
// `agent.context.get_usage`, pushed on the snapshot. Preferred over
|
|
853
863
|
// contextComposition; absent ⇒ fall back to the estimate, then to occupancy.
|
|
854
864
|
contextCategories: z.array(AgentContextCategorySchema).optional(),
|
|
@@ -1069,6 +1079,7 @@ export const AgentTimelineItemPayloadSchema = z.union([
|
|
|
1069
1079
|
type: z.literal("user_message"),
|
|
1070
1080
|
text: z.string(),
|
|
1071
1081
|
messageId: z.string().optional(),
|
|
1082
|
+
clientMessageId: z.string().optional(),
|
|
1072
1083
|
}),
|
|
1073
1084
|
z.object({
|
|
1074
1085
|
type: z.literal("assistant_message"),
|
|
@@ -1095,7 +1106,9 @@ export const AgentTimelineItemPayloadSchema = z.union([
|
|
|
1095
1106
|
type: z.literal("compaction"),
|
|
1096
1107
|
// COMPAT(compactionFailedStatus): "failed" added in v0.4.3. Clients older
|
|
1097
1108
|
// than that drop the whole timeline event on parse and keep showing the
|
|
1098
|
-
// loading row
|
|
1109
|
+
// loading row - exactly their pre-"failed" behavior, so no gate is needed.
|
|
1110
|
+
// Nothing to remove: this tag records why the enum could be widened without
|
|
1111
|
+
// a shim, so it has no cleanup date by design.
|
|
1099
1112
|
status: z.enum(["loading", "completed", "failed"]),
|
|
1100
1113
|
trigger: z.enum(["auto", "manual"]).optional(),
|
|
1101
1114
|
preTokens: z.number().optional(),
|
|
@@ -1157,6 +1170,7 @@ export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
|
|
|
1157
1170
|
body: z.string(),
|
|
1158
1171
|
data: z.object({
|
|
1159
1172
|
serverId: z.string(),
|
|
1173
|
+
workspaceId: z.string().optional(),
|
|
1160
1174
|
agentId: z.string(),
|
|
1161
1175
|
reason: z.enum(["finished", "error", "permission"]),
|
|
1162
1176
|
}),
|
|
@@ -1199,7 +1213,7 @@ const AgentRuntimeInfoSchema = z.object({
|
|
|
1199
1213
|
/**
|
|
1200
1214
|
* One message parked for delivery as an agent's NEXT turn (`delivery: "queue"`).
|
|
1201
1215
|
* The daemon owns the queue; this is the read-only projection the Queue track
|
|
1202
|
-
* renders. Declared above AgentSnapshotPayloadSchema
|
|
1216
|
+
* renders. Declared above AgentSnapshotPayloadSchema - zod-aot emits schemas in
|
|
1203
1217
|
* source order, so a forward reference is a build-time ReferenceError.
|
|
1204
1218
|
*/
|
|
1205
1219
|
export const QueuedAgentMessagePayloadSchema = z.object({
|
|
@@ -1211,14 +1225,14 @@ export const QueuedAgentMessagePayloadSchema = z.object({
|
|
|
1211
1225
|
/**
|
|
1212
1226
|
* Who parked the message. Absent (from an older daemon) or "user" is a normal
|
|
1213
1227
|
* user turn; "system" marks a system-injected entry (a chat mention, a
|
|
1214
|
-
* scheduled fire) that the daemon's drain never merges into a user turn
|
|
1228
|
+
* scheduled fire) that the daemon's drain never merges into a user turn - the
|
|
1215
1229
|
* client must likewise exclude it from "Send all".
|
|
1216
1230
|
*/
|
|
1217
1231
|
source: z.enum(["user", "system"]).optional(),
|
|
1218
1232
|
});
|
|
1219
1233
|
/**
|
|
1220
1234
|
* An agent's LIFETIME SPEND, kept as the real token split plus the provider's
|
|
1221
|
-
* own cost
|
|
1235
|
+
* own cost - the raw material for "what did this chat cost".
|
|
1222
1236
|
*
|
|
1223
1237
|
* Deliberately distinct from context-window occupancy (`agent.context.get_usage`
|
|
1224
1238
|
* and `lastUsage.contextWindow*`), which answers "how full am I" and shares no
|
|
@@ -1227,12 +1241,12 @@ export const QueuedAgentMessagePayloadSchema = z.object({
|
|
|
1227
1241
|
*
|
|
1228
1242
|
* `costUsd` is only ever a provider's OWN reported cost, already de-inflated so
|
|
1229
1243
|
* a parent never carries what its sub-agents reported. It is NEVER derived from
|
|
1230
|
-
* a $/M rate table
|
|
1244
|
+
* a $/M rate table - a rate keyed off a model id misprices a gateway serving
|
|
1231
1245
|
* that model at its own prices (docs/subagent-accounting.md, pricing invariant).
|
|
1232
1246
|
* `costCoverage` says how far it can be trusted, so a surface can show a floor
|
|
1233
1247
|
* or an honest blank rather than a confident wrong figure.
|
|
1234
1248
|
*
|
|
1235
|
-
* Declared above AgentSnapshotPayloadSchema
|
|
1249
|
+
* Declared above AgentSnapshotPayloadSchema - zod-aot emits schemas in source
|
|
1236
1250
|
* order, so a forward reference is a build-time ReferenceError.
|
|
1237
1251
|
*/
|
|
1238
1252
|
export const AgentCumulativeUsageSchema = z.object({
|
|
@@ -1243,9 +1257,9 @@ export const AgentCumulativeUsageSchema = z.object({
|
|
|
1243
1257
|
/** Provider-reported cost booked so far. Absent ⇒ nothing was priceable. */
|
|
1244
1258
|
costUsd: z.number().optional(),
|
|
1245
1259
|
/**
|
|
1246
|
-
* `complete`
|
|
1247
|
-
* `partial`
|
|
1248
|
-
* one. `none`
|
|
1260
|
+
* `complete` - every token-bearing turn was priced; `costUsd` is the total.
|
|
1261
|
+
* `partial` - some turns were unpriced; `costUsd` is a FLOOR, present it as
|
|
1262
|
+
* one. `none` - nothing priceable; show tokens and a blank, never an estimate.
|
|
1249
1263
|
*/
|
|
1250
1264
|
costCoverage: z.enum(["complete", "partial", "none"]).optional(),
|
|
1251
1265
|
});
|
|
@@ -1270,7 +1284,7 @@ export const AgentSnapshotPayloadSchema = z.object({
|
|
|
1270
1284
|
runtimeInfo: AgentRuntimeInfoSchema.optional(),
|
|
1271
1285
|
lastUsage: AgentUsageSchema.optional(),
|
|
1272
1286
|
// Honest cumulative token total (Σ across the whole run) from the provider,
|
|
1273
|
-
// for the subagents-track cost readout
|
|
1287
|
+
// for the subagents-track cost readout - the only currency that works for
|
|
1274
1288
|
// cost-less local models. Observed subagents source it from the provider's
|
|
1275
1289
|
// per-task usage.total_tokens (already cumulative-per-subagent). Purely
|
|
1276
1290
|
// additive; absent ⇒ no readout. Old clients ignore it.
|
|
@@ -1287,16 +1301,18 @@ export const AgentSnapshotPayloadSchema = z.object({
|
|
|
1287
1301
|
cumulativeUsage: AgentCumulativeUsageSchema.optional(),
|
|
1288
1302
|
// Liveness signals for the sub-agents track: how much work this agent has done
|
|
1289
1303
|
// (`toolUseCount`, cumulative and monotonic) and what it is doing right now
|
|
1290
|
-
// (`currentTool`, the latest tool name, cleared once the agent is terminal
|
|
1304
|
+
// (`currentTool`, the latest tool name, cleared once the agent is terminal -
|
|
1291
1305
|
// a finished agent isn't "running Bash"). Both are purely additive optional
|
|
1292
1306
|
// leaves: a provider that can't report them leaves them absent and the row
|
|
1293
1307
|
// omits the readout rather than showing a wrong value.
|
|
1294
|
-
// COMPAT(subagentLiveness): added in v0.6.7
|
|
1308
|
+
// COMPAT(subagentLiveness): added in v0.6.7, drop the optional gate when the
|
|
1309
|
+
// floor is >= v0.6.7. Old clients ignore both fields and show the row without
|
|
1310
|
+
// its liveness readouts, which is their pre-v0.6.7 behaviour.
|
|
1295
1311
|
// See docs/chat-lifecycle.md (the subagents track).
|
|
1296
1312
|
toolUseCount: z.number().optional(),
|
|
1297
1313
|
currentTool: z.string().optional(),
|
|
1298
1314
|
// Messages parked for delivery as this agent's NEXT turn (delivery: "queue").
|
|
1299
|
-
// Daemon-owned and ephemeral
|
|
1315
|
+
// Daemon-owned and ephemeral - the composer's Queue track renders straight
|
|
1300
1316
|
// from this. Absent/empty ⇒ nothing queued; old clients ignore it.
|
|
1301
1317
|
// COMPAT(steerQueue): added in v0.6.8, drop the gate when floor >= v0.6.8.
|
|
1302
1318
|
queuedMessages: z.array(QueuedAgentMessagePayloadSchema).optional(),
|
|
@@ -1309,7 +1325,7 @@ export const AgentSnapshotPayloadSchema = z.object({
|
|
|
1309
1325
|
archivedAt: z.string().nullable().optional(),
|
|
1310
1326
|
providerUnavailable: z.boolean().optional(),
|
|
1311
1327
|
// Attendability. "observed" marks a provider-managed subagent (Claude Task /
|
|
1312
|
-
// ultracode fan-out) that the user can watch but not prompt or reconfigure
|
|
1328
|
+
// ultracode fan-out) that the user can watch but not prompt or reconfigure -
|
|
1313
1329
|
// the daemon refuses attended operations and the client renders it read-only.
|
|
1314
1330
|
// COMPAT(observedSubagents): added in v0.4.3; absent ⇒ "attended". Drop the
|
|
1315
1331
|
// gate when daemon floor >= v0.4.3. See projects/observed-subagents/observed-subagents.md.
|
|
@@ -1419,7 +1435,7 @@ export const CloseItemsRequestMessageSchema = z.object({
|
|
|
1419
1435
|
// OpenCode sessions) is deliberately left in place: Otto never created it,
|
|
1420
1436
|
// another tool still reads it, and silently deleting another tool's state is not
|
|
1421
1437
|
// ours to do. There is intentionally **no** opt-in flag for provider data on the
|
|
1422
|
-
// wire
|
|
1438
|
+
// wire - the UI discloses what stays behind instead. See docs/chat-lifecycle.md.
|
|
1423
1439
|
// Gated by server_info.features.historyDelete.
|
|
1424
1440
|
export const HistoryAgentsClearArchivedRequestSchema = z.object({
|
|
1425
1441
|
type: z.literal("history.agents.clear_archived.request"),
|
|
@@ -1433,7 +1449,7 @@ export const HistoryAgentsClearArchivedRequestSchema = z.object({
|
|
|
1433
1449
|
export const HistoryAgentsClearArchivedResponseSchema = z.object({
|
|
1434
1450
|
type: z.literal("history.agents.clear_archived.response"),
|
|
1435
1451
|
payload: z.object({
|
|
1436
|
-
// How many archived records the cutoff selected
|
|
1452
|
+
// How many archived records the cutoff selected - the number the confirm
|
|
1437
1453
|
// dialog quotes back after a dry run.
|
|
1438
1454
|
matched: z.number().int().nonnegative(),
|
|
1439
1455
|
deleted: z.number().int().nonnegative(),
|
|
@@ -1490,7 +1506,7 @@ export const AttachmentsImagesClearRequestSchema = z.object({
|
|
|
1490
1506
|
olderThanDays: z.number().int().min(0).default(0),
|
|
1491
1507
|
// Safe by default: a request that omits the flag previews instead of deleting.
|
|
1492
1508
|
// The client always sends it explicitly. Same contract as
|
|
1493
|
-
// history.agents.clear_archived, and for the same reason
|
|
1509
|
+
// history.agents.clear_archived, and for the same reason - the client cannot
|
|
1494
1510
|
// enumerate the set, and there is no undo.
|
|
1495
1511
|
dryRun: z.boolean().default(true),
|
|
1496
1512
|
requestId: z.string(),
|
|
@@ -1511,6 +1527,27 @@ export const AttachmentsImagesClearResponseSchema = z.object({
|
|
|
1511
1527
|
// server_info.features.brainControl (lifecycle) and features.brainStatus
|
|
1512
1528
|
// (evals). Live status streaming (subscribe_brain_status + brain_status_changed)
|
|
1513
1529
|
// is added alongside its client/daemon consumers.
|
|
1530
|
+
/**
|
|
1531
|
+
* What the brain on the far side can actually serve. Passthrough so it can grow.
|
|
1532
|
+
*
|
|
1533
|
+
* Declared here rather than beside the Brain Console RPCs below because
|
|
1534
|
+
* BrainHostStatusSchema carries it, and a zod const must be initialised before
|
|
1535
|
+
* the schema that references it (see docs on the AOT validator's declaration
|
|
1536
|
+
* ordering). Moving it back down produces a module-evaluation TDZ error.
|
|
1537
|
+
*/
|
|
1538
|
+
export const BrainCapabilitiesSchema = z
|
|
1539
|
+
.object({
|
|
1540
|
+
profiles: z.boolean().default(false),
|
|
1541
|
+
budget: z.boolean().default(false),
|
|
1542
|
+
logs: z.boolean().default(false),
|
|
1543
|
+
delete: z.boolean().default(false),
|
|
1544
|
+
load: z.boolean().default(false),
|
|
1545
|
+
resources: z.boolean().default(false),
|
|
1546
|
+
inventory: z.boolean().default(false),
|
|
1547
|
+
/** Whether writes are permitted right now (the brain's allowRemoteConfig). */
|
|
1548
|
+
writable: z.boolean().default(false),
|
|
1549
|
+
})
|
|
1550
|
+
.passthrough();
|
|
1514
1551
|
// The brain's host status, as the daemon derives it: liveness plus the fields
|
|
1515
1552
|
// proxied from the brain's own `/__host/status`. Passthrough on the opaque
|
|
1516
1553
|
// sub-objects so the brain can evolve them without a protocol bump.
|
|
@@ -1533,6 +1570,64 @@ export const BrainHostStatusSchema = z
|
|
|
1533
1570
|
telemetry: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
1534
1571
|
scheduler: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
1535
1572
|
recent: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
1573
|
+
/**
|
|
1574
|
+
* What the brain on the far side can serve. Carried here rather than fetched
|
|
1575
|
+
* from /__host/capabilities so the client gets it with the status it is
|
|
1576
|
+
* already polling, and so it cannot go stale when the owner toggles remote
|
|
1577
|
+
* configuration. Null from a brain that predates the management API.
|
|
1578
|
+
*/
|
|
1579
|
+
capabilities: BrainCapabilitiesSchema.nullable().optional(),
|
|
1580
|
+
/** Live CPU/RAM/GPU/slot telemetry, only when the request asked for it. */
|
|
1581
|
+
resources: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
1582
|
+
/** How many log lines the brain currently holds, for the Logs tab. */
|
|
1583
|
+
logLineCount: z.number().nullable().optional(),
|
|
1584
|
+
/**
|
|
1585
|
+
* Which long-running op currently owns the brain, if any. Cheap to carry:
|
|
1586
|
+
* the brain reads it from a small file beside its pid file, so this rides on
|
|
1587
|
+
* the liveness poll rather than needing `resources: true`.
|
|
1588
|
+
*
|
|
1589
|
+
* `kind` is a plain string, not an enum: the brain may grow ops this client
|
|
1590
|
+
* has never heard of, and the protocol contract forbids narrowing a field
|
|
1591
|
+
* later. Unknown kinds fall through to the ordinary busy states.
|
|
1592
|
+
*/
|
|
1593
|
+
activity: z
|
|
1594
|
+
.object({
|
|
1595
|
+
kind: z.string(),
|
|
1596
|
+
target: z.string().nullable().optional(),
|
|
1597
|
+
/** Completion in [0,1], for ops that can measure it. */
|
|
1598
|
+
progress: z.number().nullable().optional(),
|
|
1599
|
+
startedAt: z.string().nullable().optional(),
|
|
1600
|
+
})
|
|
1601
|
+
.passthrough()
|
|
1602
|
+
.nullable()
|
|
1603
|
+
.optional(),
|
|
1604
|
+
/**
|
|
1605
|
+
* Whether any in-flight completion is currently mid-reasoning: reasoning
|
|
1606
|
+
* deltas have arrived and no content has yet. Also on the liveness poll,
|
|
1607
|
+
* because it is one boolean the router already knows.
|
|
1608
|
+
*/
|
|
1609
|
+
reasoning: z.boolean().nullable().optional(),
|
|
1610
|
+
/**
|
|
1611
|
+
* Slot occupancy split by phase, so a client can tell a prompt being
|
|
1612
|
+
* ingested from a model that has started answering. Rides here rather than
|
|
1613
|
+
* inside `resources` on purpose: `resources` costs an `nvidia-smi` spawn and
|
|
1614
|
+
* is off by default, and this is the half the status rail needs every poll.
|
|
1615
|
+
*/
|
|
1616
|
+
slots: z
|
|
1617
|
+
.object({
|
|
1618
|
+
total: z.number().nullable().optional(),
|
|
1619
|
+
busy: z.number().nullable().optional(),
|
|
1620
|
+
idle: z.number().nullable().optional(),
|
|
1621
|
+
prefill: z.number().nullable().optional(),
|
|
1622
|
+
decode: z.number().nullable().optional(),
|
|
1623
|
+
})
|
|
1624
|
+
.passthrough()
|
|
1625
|
+
.nullable()
|
|
1626
|
+
.optional(),
|
|
1627
|
+
/** Jobs the scheduler is holding because no slot is free, or a swap is mid-flight. */
|
|
1628
|
+
queued: z.number().nullable().optional(),
|
|
1629
|
+
/** Whether the daemon reached the brain on its last probe. */
|
|
1630
|
+
reachable: z.boolean().nullable().optional(),
|
|
1536
1631
|
})
|
|
1537
1632
|
.passthrough();
|
|
1538
1633
|
const BrainHostStatusResultSchema = z.object({
|
|
@@ -1542,6 +1637,13 @@ const BrainHostStatusResultSchema = z.object({
|
|
|
1542
1637
|
});
|
|
1543
1638
|
export const BrainHostStatusRequestSchema = z.object({
|
|
1544
1639
|
type: z.literal("brain.host.status.request"),
|
|
1640
|
+
/**
|
|
1641
|
+
* Ask for live CPU/RAM/GPU/slot telemetry alongside the status. Off by default
|
|
1642
|
+
* on purpose: it costs an `nvidia-smi` spawn plus a /slots round trip on the
|
|
1643
|
+
* brain, and this RPC is also the liveness poll. Only a surface actually
|
|
1644
|
+
* rendering the numbers should turn it on.
|
|
1645
|
+
*/
|
|
1646
|
+
resources: z.boolean().default(false),
|
|
1545
1647
|
requestId: z.string(),
|
|
1546
1648
|
});
|
|
1547
1649
|
export const BrainHostStatusResponseSchema = z.object({
|
|
@@ -1779,7 +1881,7 @@ const BrainJobsResultSchema = z.object({
|
|
|
1779
1881
|
error: z.string().nullable(),
|
|
1780
1882
|
requestId: z.string(),
|
|
1781
1883
|
});
|
|
1782
|
-
// Installed models
|
|
1884
|
+
// Installed models - `otto-brain scan`.
|
|
1783
1885
|
export const BrainModelsScanRequestSchema = z.object({
|
|
1784
1886
|
type: z.literal("brain.models.scan.request"),
|
|
1785
1887
|
requestId: z.string(),
|
|
@@ -1792,7 +1894,7 @@ export const BrainModelsScanResponseSchema = z.object({
|
|
|
1792
1894
|
requestId: z.string(),
|
|
1793
1895
|
}),
|
|
1794
1896
|
});
|
|
1795
|
-
// Downloadable catalog
|
|
1897
|
+
// Downloadable catalog - `otto-brain catalog`.
|
|
1796
1898
|
export const BrainCatalogListRequestSchema = z.object({
|
|
1797
1899
|
type: z.literal("brain.catalog.list.request"),
|
|
1798
1900
|
requestId: z.string(),
|
|
@@ -1805,7 +1907,7 @@ export const BrainCatalogListResponseSchema = z.object({
|
|
|
1805
1907
|
requestId: z.string(),
|
|
1806
1908
|
}),
|
|
1807
1909
|
});
|
|
1808
|
-
// Installed runtimes
|
|
1910
|
+
// Installed runtimes - `otto-brain runtime list`.
|
|
1809
1911
|
export const BrainRuntimeListRequestSchema = z.object({
|
|
1810
1912
|
type: z.literal("brain.runtime.list.request"),
|
|
1811
1913
|
requestId: z.string(),
|
|
@@ -1818,7 +1920,7 @@ export const BrainRuntimeListResponseSchema = z.object({
|
|
|
1818
1920
|
requestId: z.string(),
|
|
1819
1921
|
}),
|
|
1820
1922
|
});
|
|
1821
|
-
// Download a catalog model
|
|
1923
|
+
// Download a catalog model - starts a `pull` job.
|
|
1822
1924
|
export const BrainModelsPullRequestSchema = z.object({
|
|
1823
1925
|
type: z.literal("brain.models.pull.request"),
|
|
1824
1926
|
// Catalog id or name fragment.
|
|
@@ -1829,7 +1931,7 @@ export const BrainModelsPullResponseSchema = z.object({
|
|
|
1829
1931
|
type: z.literal("brain.models.pull.response"),
|
|
1830
1932
|
payload: BrainJobResultSchema,
|
|
1831
1933
|
});
|
|
1832
|
-
// Install a llama.cpp runtime
|
|
1934
|
+
// Install a llama.cpp runtime - starts a `runtime-install` job.
|
|
1833
1935
|
export const BrainRuntimeInstallRequestSchema = z.object({
|
|
1834
1936
|
type: z.literal("brain.runtime.install.request"),
|
|
1835
1937
|
// Optional llama.cpp release build tag; null = the brain's default.
|
|
@@ -1840,7 +1942,7 @@ export const BrainRuntimeInstallResponseSchema = z.object({
|
|
|
1840
1942
|
type: z.literal("brain.runtime.install.response"),
|
|
1841
1943
|
payload: BrainJobResultSchema,
|
|
1842
1944
|
});
|
|
1843
|
-
// Measure real KV bytes/token for a model
|
|
1945
|
+
// Measure real KV bytes/token for a model - starts a `calibrate` job. Needs a
|
|
1844
1946
|
// runtime + GPU; refused with a helpful error otherwise.
|
|
1845
1947
|
export const BrainCalibrateRequestSchema = z.object({
|
|
1846
1948
|
type: z.literal("brain.calibrate.request"),
|
|
@@ -1851,7 +1953,7 @@ export const BrainCalibrateResponseSchema = z.object({
|
|
|
1851
1953
|
type: z.literal("brain.calibrate.response"),
|
|
1852
1954
|
payload: BrainJobResultSchema,
|
|
1853
1955
|
});
|
|
1854
|
-
// Find the best reasoning budget for a model
|
|
1956
|
+
// Find the best reasoning budget for a model - starts a `sweep` job.
|
|
1855
1957
|
export const BrainSweepRequestSchema = z.object({
|
|
1856
1958
|
type: z.literal("brain.sweep.request"),
|
|
1857
1959
|
model: z.string(),
|
|
@@ -1861,7 +1963,7 @@ export const BrainSweepResponseSchema = z.object({
|
|
|
1861
1963
|
type: z.literal("brain.sweep.response"),
|
|
1862
1964
|
payload: BrainJobResultSchema,
|
|
1863
1965
|
});
|
|
1864
|
-
// Run the agentic-coding benchmark
|
|
1966
|
+
// Run the agentic-coding benchmark - starts a `bench` job. `model` is an
|
|
1865
1967
|
// optional comma list of name fragments; null lets the brain pick.
|
|
1866
1968
|
export const BrainBenchRequestSchema = z.object({
|
|
1867
1969
|
type: z.literal("brain.bench.request"),
|
|
@@ -1908,7 +2010,7 @@ export const BrainHfSearchResultSchema = z
|
|
|
1908
2010
|
installed: z.boolean().default(false),
|
|
1909
2011
|
})
|
|
1910
2012
|
.passthrough();
|
|
1911
|
-
// One downloadable quantization of a repo
|
|
2013
|
+
// One downloadable quantization of a repo - `otto-brain add <repo> --list-quants`.
|
|
1912
2014
|
export const BrainRepoQuantSchema = z
|
|
1913
2015
|
.object({
|
|
1914
2016
|
quant: z.string().default(""),
|
|
@@ -1919,7 +2021,7 @@ export const BrainRepoQuantSchema = z
|
|
|
1919
2021
|
installed: z.boolean().default(false),
|
|
1920
2022
|
})
|
|
1921
2023
|
.passthrough();
|
|
1922
|
-
// Search Hugging Face for GGUF models
|
|
2024
|
+
// Search Hugging Face for GGUF models - `otto-brain search <query>`.
|
|
1923
2025
|
export const BrainHfSearchRequestSchema = z.object({
|
|
1924
2026
|
type: z.literal("brain.hf.search.request"),
|
|
1925
2027
|
query: z.string(),
|
|
@@ -1934,7 +2036,7 @@ export const BrainHfSearchResponseSchema = z.object({
|
|
|
1934
2036
|
requestId: z.string(),
|
|
1935
2037
|
}),
|
|
1936
2038
|
});
|
|
1937
|
-
// List the quantizations a repo offers
|
|
2039
|
+
// List the quantizations a repo offers - `otto-brain add <repo> --list-quants`.
|
|
1938
2040
|
export const BrainHfQuantsRequestSchema = z.object({
|
|
1939
2041
|
type: z.literal("brain.hf.quants.request"),
|
|
1940
2042
|
repo: z.string(),
|
|
@@ -1948,7 +2050,7 @@ export const BrainHfQuantsResponseSchema = z.object({
|
|
|
1948
2050
|
requestId: z.string(),
|
|
1949
2051
|
}),
|
|
1950
2052
|
});
|
|
1951
|
-
// Download a chosen quant of an arbitrary HF repo
|
|
2053
|
+
// Download a chosen quant of an arbitrary HF repo - starts a `pull` job.
|
|
1952
2054
|
export const BrainModelsAddRequestSchema = z.object({
|
|
1953
2055
|
type: z.literal("brain.models.add.request"),
|
|
1954
2056
|
repo: z.string(),
|
|
@@ -1959,6 +2061,283 @@ export const BrainModelsAddResponseSchema = z.object({
|
|
|
1959
2061
|
type: z.literal("brain.models.add.response"),
|
|
1960
2062
|
payload: BrainJobResultSchema,
|
|
1961
2063
|
});
|
|
2064
|
+
// --- Brain Console: the management API, proxied ---------------------------
|
|
2065
|
+
// Unlike the job RPCs above (which shell out to `otto-brain <verb> --json` and
|
|
2066
|
+
// are therefore local-only), these proxy the brain's own `/__host/*` HTTP API.
|
|
2067
|
+
// The daemon already resolves that endpoint by mode, so a local child and a
|
|
2068
|
+
// remote brain are reached by the same code with no branch on either side.
|
|
2069
|
+
// All gated by server_info.features.brainConsole.
|
|
2070
|
+
//
|
|
2071
|
+
// Two versions matter and they move independently: the daemon (does it know how
|
|
2072
|
+
// to proxy?) and the brain (does it serve it?). features.brainConsole answers
|
|
2073
|
+
// the first; `capabilities` on brain.host.status answers the second. A brain too
|
|
2074
|
+
// old for a capability is reported honestly rather than reimplemented.
|
|
2075
|
+
/**
|
|
2076
|
+
* A model's hosting profile. Passthrough because the brain persists more than it
|
|
2077
|
+
* exposes for editing (batchSize, extraArgs, the reasoning-budget message) and
|
|
2078
|
+
* those must survive a round trip untouched rather than being dropped here.
|
|
2079
|
+
*/
|
|
2080
|
+
export const BrainProfileSchema = z
|
|
2081
|
+
.object({
|
|
2082
|
+
contextSize: z.number().default(0),
|
|
2083
|
+
cacheTypeK: z.string().default(""),
|
|
2084
|
+
cacheTypeV: z.string().default(""),
|
|
2085
|
+
flashAttention: z.boolean().default(true),
|
|
2086
|
+
gpuLayers: z.number().default(0),
|
|
2087
|
+
vision: z.boolean().default(false),
|
|
2088
|
+
reasoningBudget: z.number().default(0),
|
|
2089
|
+
parallelSlots: z.number().default(1),
|
|
2090
|
+
})
|
|
2091
|
+
.passthrough();
|
|
2092
|
+
/** One editable field, as the brain describes it, so the editor cannot drift. */
|
|
2093
|
+
export const BrainProfileFieldSchema = z
|
|
2094
|
+
.object({
|
|
2095
|
+
key: z.string(),
|
|
2096
|
+
label: z.string().default(""),
|
|
2097
|
+
kind: z.string().default("number"),
|
|
2098
|
+
step: z.number().nullable().optional(),
|
|
2099
|
+
min: z.number().nullable().optional(),
|
|
2100
|
+
max: z.number().nullable().optional(),
|
|
2101
|
+
options: z.array(z.union([z.string(), z.number()])).default([]),
|
|
2102
|
+
optionLabels: z.array(z.string()).default([]),
|
|
2103
|
+
available: z.boolean().default(true),
|
|
2104
|
+
unavailableReason: z.string().nullable().optional(),
|
|
2105
|
+
})
|
|
2106
|
+
.passthrough();
|
|
2107
|
+
/** A note on a field. `blocksStart` means this combination cannot load at all. */
|
|
2108
|
+
export const BrainProfileWarningSchema = z
|
|
2109
|
+
.object({
|
|
2110
|
+
field: z.string().nullable().default(null),
|
|
2111
|
+
severity: z.string().default("info"),
|
|
2112
|
+
message: z.string().default(""),
|
|
2113
|
+
blocksStart: z.boolean().default(false),
|
|
2114
|
+
})
|
|
2115
|
+
.passthrough();
|
|
2116
|
+
/**
|
|
2117
|
+
* Where the KV bytes/token figure came from. `inherited` means it was measured
|
|
2118
|
+
* on a relative with the same attention geometry and rescaled, which the UI must
|
|
2119
|
+
* never present as measured on this file.
|
|
2120
|
+
*/
|
|
2121
|
+
export const BrainCalibrationInfoSchema = z
|
|
2122
|
+
.object({
|
|
2123
|
+
state: z.string().default("unknown"),
|
|
2124
|
+
kvBytesPerToken: z.number().nullable().default(null),
|
|
2125
|
+
measuredAt: z.string().nullable().default(null),
|
|
2126
|
+
measuredOn: z.string().nullable().default(null),
|
|
2127
|
+
})
|
|
2128
|
+
.passthrough();
|
|
2129
|
+
/** The VRAM breakdown for a profile. Raw bytes; the client formats at the edge. */
|
|
2130
|
+
export const BrainBudgetSchema = z
|
|
2131
|
+
.object({
|
|
2132
|
+
weightsBytes: z.number().default(0),
|
|
2133
|
+
mmprojBytes: z.number().default(0),
|
|
2134
|
+
kvBytes: z.number().default(0),
|
|
2135
|
+
overheadBytes: z.number().default(0),
|
|
2136
|
+
totalBytes: z.number().default(0),
|
|
2137
|
+
usableBytes: z.number().default(0),
|
|
2138
|
+
totalVramBytes: z.number().default(0),
|
|
2139
|
+
reserveBytes: z.number().default(0),
|
|
2140
|
+
kvBytesPerToken: z.number().default(0),
|
|
2141
|
+
source: z.string().default("unknown"),
|
|
2142
|
+
theoreticalKvBytesPerToken: z.number().nullable().default(null),
|
|
2143
|
+
fits: z.boolean().default(false),
|
|
2144
|
+
headroomBytes: z.number().default(0),
|
|
2145
|
+
utilization: z.number().default(0),
|
|
2146
|
+
})
|
|
2147
|
+
.passthrough();
|
|
2148
|
+
/** A model's benchmark standing, joined onto its inventory row. */
|
|
2149
|
+
export const BrainModelScoreSchema = z
|
|
2150
|
+
.object({
|
|
2151
|
+
id: z.string().nullable().default(null),
|
|
2152
|
+
displayName: z.string().default(""),
|
|
2153
|
+
overall: z.number().default(0),
|
|
2154
|
+
runs: z.number().default(0),
|
|
2155
|
+
std: z.number().default(0),
|
|
2156
|
+
grade: z.string().default(""),
|
|
2157
|
+
rank: z.number().nullable().optional(),
|
|
2158
|
+
})
|
|
2159
|
+
.passthrough();
|
|
2160
|
+
/**
|
|
2161
|
+
* One installed model with everything the Models tab shows, joined by the brain.
|
|
2162
|
+
* The client must not have to correlate the scan, the metadata and the rankings
|
|
2163
|
+
* itself: they key on different things and only the brain knows the file layout.
|
|
2164
|
+
*/
|
|
2165
|
+
export const BrainInventoryModelSchema = z
|
|
2166
|
+
.object({
|
|
2167
|
+
id: z.string(),
|
|
2168
|
+
displayName: z.string().default(""),
|
|
2169
|
+
publisher: z.string().nullable().default(null),
|
|
2170
|
+
quant: z.string().nullable().default(null),
|
|
2171
|
+
sizeBytes: z.number().default(0),
|
|
2172
|
+
mmprojBytes: z.number().default(0),
|
|
2173
|
+
origin: z.string().nullable().default(null),
|
|
2174
|
+
arch: z.string().nullable().default(null),
|
|
2175
|
+
contextLength: z.number().nullable().default(null),
|
|
2176
|
+
blockCount: z.number().nullable().default(null),
|
|
2177
|
+
headCountKv: z.number().nullable().default(null),
|
|
2178
|
+
hasProjector: z.boolean().default(false),
|
|
2179
|
+
reasoning: z.boolean().default(false),
|
|
2180
|
+
mtp: z.boolean().default(false),
|
|
2181
|
+
distilled: z.boolean().default(false),
|
|
2182
|
+
useCases: z.array(z.string()).default([]),
|
|
2183
|
+
tier: z.string().nullable().default(null),
|
|
2184
|
+
profile: BrainProfileSchema.nullable().default(null),
|
|
2185
|
+
calibration: BrainCalibrationInfoSchema.nullable().default(null),
|
|
2186
|
+
budget: BrainBudgetSchema.nullable().default(null),
|
|
2187
|
+
maxContextThatFits: z.number().nullable().default(null),
|
|
2188
|
+
score: BrainModelScoreSchema.nullable().default(null),
|
|
2189
|
+
state: z.string().default("not-loaded"),
|
|
2190
|
+
warnings: z.array(BrainProfileWarningSchema).default([]),
|
|
2191
|
+
})
|
|
2192
|
+
.passthrough();
|
|
2193
|
+
export const BrainDiskUsageSchema = z
|
|
2194
|
+
.object({
|
|
2195
|
+
freeBytes: z.number().default(0),
|
|
2196
|
+
totalBytes: z.number().default(0),
|
|
2197
|
+
modelBytes: z.number().default(0),
|
|
2198
|
+
})
|
|
2199
|
+
.passthrough();
|
|
2200
|
+
// The joined inventory - GET /__host/models.
|
|
2201
|
+
export const BrainModelsInventoryRequestSchema = z.object({
|
|
2202
|
+
type: z.literal("brain.models.inventory.request"),
|
|
2203
|
+
requestId: z.string(),
|
|
2204
|
+
});
|
|
2205
|
+
export const BrainModelsInventoryResponseSchema = z.object({
|
|
2206
|
+
type: z.literal("brain.models.inventory.response"),
|
|
2207
|
+
payload: z.object({
|
|
2208
|
+
models: z.array(BrainInventoryModelSchema).default([]),
|
|
2209
|
+
disk: BrainDiskUsageSchema.nullable().default(null),
|
|
2210
|
+
error: z.string().nullable(),
|
|
2211
|
+
requestId: z.string(),
|
|
2212
|
+
}),
|
|
2213
|
+
});
|
|
2214
|
+
// Read a model's profile plus the descriptors an editor renders from.
|
|
2215
|
+
export const BrainModelProfileGetRequestSchema = z.object({
|
|
2216
|
+
type: z.literal("brain.model.profile.get.request"),
|
|
2217
|
+
modelId: z.string(),
|
|
2218
|
+
requestId: z.string(),
|
|
2219
|
+
});
|
|
2220
|
+
export const BrainModelProfileGetResponseSchema = z.object({
|
|
2221
|
+
type: z.literal("brain.model.profile.get.response"),
|
|
2222
|
+
payload: z.object({
|
|
2223
|
+
profile: BrainProfileSchema.nullable().default(null),
|
|
2224
|
+
fields: z.array(BrainProfileFieldSchema).default([]),
|
|
2225
|
+
warnings: z.array(BrainProfileWarningSchema).default([]),
|
|
2226
|
+
calibration: BrainCalibrationInfoSchema.nullable().default(null),
|
|
2227
|
+
error: z.string().nullable(),
|
|
2228
|
+
requestId: z.string(),
|
|
2229
|
+
}),
|
|
2230
|
+
});
|
|
2231
|
+
// Write the editable fields. `patch` carries only the eight the brain accepts;
|
|
2232
|
+
// anything else is ignored there rather than rejected, so an older client that
|
|
2233
|
+
// sends a field a newer brain dropped still succeeds.
|
|
2234
|
+
export const BrainModelProfileSetRequestSchema = z.object({
|
|
2235
|
+
type: z.literal("brain.model.profile.set.request"),
|
|
2236
|
+
modelId: z.string(),
|
|
2237
|
+
patch: z.record(z.string(), z.unknown()),
|
|
2238
|
+
requestId: z.string(),
|
|
2239
|
+
});
|
|
2240
|
+
export const BrainModelProfileSetResponseSchema = z.object({
|
|
2241
|
+
type: z.literal("brain.model.profile.set.response"),
|
|
2242
|
+
payload: z.object({
|
|
2243
|
+
profile: BrainProfileSchema.nullable().default(null),
|
|
2244
|
+
/** Human-readable notes about anything clamped or ignored. */
|
|
2245
|
+
adjustments: z.array(z.string()).default([]),
|
|
2246
|
+
warnings: z.array(BrainProfileWarningSchema).default([]),
|
|
2247
|
+
calibration: BrainCalibrationInfoSchema.nullable().default(null),
|
|
2248
|
+
budget: BrainBudgetSchema.nullable().default(null),
|
|
2249
|
+
maxContextThatFits: z.number().nullable().default(null),
|
|
2250
|
+
/** True when the edited model is the resident one, so a restart applies it. */
|
|
2251
|
+
requiresRestart: z.boolean().default(false),
|
|
2252
|
+
error: z.string().nullable(),
|
|
2253
|
+
requestId: z.string(),
|
|
2254
|
+
}),
|
|
2255
|
+
});
|
|
2256
|
+
// The budget for a hypothetical profile - GET /__host/model/budget. `overrides`
|
|
2257
|
+
// are string-encoded field values so the UI can preview a budget while a control
|
|
2258
|
+
// is mid-drag, without persisting a value the user is scrubbing past.
|
|
2259
|
+
export const BrainModelBudgetGetRequestSchema = z.object({
|
|
2260
|
+
type: z.literal("brain.model.budget.get.request"),
|
|
2261
|
+
modelId: z.string(),
|
|
2262
|
+
overrides: z.record(z.string(), z.string()).default({}),
|
|
2263
|
+
requestId: z.string(),
|
|
2264
|
+
});
|
|
2265
|
+
export const BrainModelBudgetGetResponseSchema = z.object({
|
|
2266
|
+
type: z.literal("brain.model.budget.get.response"),
|
|
2267
|
+
payload: z.object({
|
|
2268
|
+
profile: BrainProfileSchema.nullable().default(null),
|
|
2269
|
+
budget: BrainBudgetSchema.nullable().default(null),
|
|
2270
|
+
maxContextThatFits: z.number().nullable().default(null),
|
|
2271
|
+
gpu: z.record(z.string(), z.unknown()).nullable().default(null),
|
|
2272
|
+
warnings: z.array(BrainProfileWarningSchema).default([]),
|
|
2273
|
+
error: z.string().nullable(),
|
|
2274
|
+
requestId: z.string(),
|
|
2275
|
+
}),
|
|
2276
|
+
});
|
|
2277
|
+
// Load a model into the running brain. Distinct from brain.host.start, which
|
|
2278
|
+
// restarts the daemon's child and has no remote equivalent.
|
|
2279
|
+
export const BrainModelLoadRequestSchema = z.object({
|
|
2280
|
+
type: z.literal("brain.model.load.request"),
|
|
2281
|
+
modelId: z.string(),
|
|
2282
|
+
requestId: z.string(),
|
|
2283
|
+
});
|
|
2284
|
+
export const BrainModelLoadResponseSchema = z.object({
|
|
2285
|
+
type: z.literal("brain.model.load.response"),
|
|
2286
|
+
payload: z.object({
|
|
2287
|
+
status: BrainHostStatusSchema.nullable().default(null),
|
|
2288
|
+
/** The profile actually used: the brain clamps context to fit VRAM. */
|
|
2289
|
+
profile: BrainProfileSchema.nullable().default(null),
|
|
2290
|
+
error: z.string().nullable(),
|
|
2291
|
+
requestId: z.string(),
|
|
2292
|
+
}),
|
|
2293
|
+
});
|
|
2294
|
+
export const BrainModelUnloadRequestSchema = z.object({
|
|
2295
|
+
type: z.literal("brain.model.unload.request"),
|
|
2296
|
+
requestId: z.string(),
|
|
2297
|
+
});
|
|
2298
|
+
export const BrainModelUnloadResponseSchema = z.object({
|
|
2299
|
+
type: z.literal("brain.model.unload.response"),
|
|
2300
|
+
payload: z.object({
|
|
2301
|
+
status: BrainHostStatusSchema.nullable().default(null),
|
|
2302
|
+
error: z.string().nullable(),
|
|
2303
|
+
requestId: z.string(),
|
|
2304
|
+
}),
|
|
2305
|
+
});
|
|
2306
|
+
// Delete a model's files. The brain refuses while that model is loaded.
|
|
2307
|
+
export const BrainModelDeleteRequestSchema = z.object({
|
|
2308
|
+
type: z.literal("brain.model.delete.request"),
|
|
2309
|
+
modelId: z.string(),
|
|
2310
|
+
requestId: z.string(),
|
|
2311
|
+
});
|
|
2312
|
+
export const BrainModelDeleteResponseSchema = z.object({
|
|
2313
|
+
type: z.literal("brain.model.delete.response"),
|
|
2314
|
+
payload: z.object({
|
|
2315
|
+
deleted: z.array(z.string()).default([]),
|
|
2316
|
+
freedBytes: z.number().default(0),
|
|
2317
|
+
includesProjector: z.boolean().default(false),
|
|
2318
|
+
/** How many models remain after the re-scan. */
|
|
2319
|
+
remaining: z.number().default(0),
|
|
2320
|
+
error: z.string().nullable(),
|
|
2321
|
+
requestId: z.string(),
|
|
2322
|
+
}),
|
|
2323
|
+
});
|
|
2324
|
+
// Tail the brain's llama-server log.
|
|
2325
|
+
export const BrainLogsTailRequestSchema = z.object({
|
|
2326
|
+
type: z.literal("brain.logs.tail.request"),
|
|
2327
|
+
limit: z.number().nullable().default(null),
|
|
2328
|
+
requestId: z.string(),
|
|
2329
|
+
});
|
|
2330
|
+
export const BrainLogsTailResponseSchema = z.object({
|
|
2331
|
+
type: z.literal("brain.logs.tail.response"),
|
|
2332
|
+
payload: z.object({
|
|
2333
|
+
lines: z.array(z.string()).default([]),
|
|
2334
|
+
total: z.number().default(0),
|
|
2335
|
+
state: z.string().nullable().default(null),
|
|
2336
|
+
command: z.string().nullable().default(null),
|
|
2337
|
+
error: z.string().nullable(),
|
|
2338
|
+
requestId: z.string(),
|
|
2339
|
+
}),
|
|
2340
|
+
});
|
|
1962
2341
|
export const ProjectRenameRequestSchema = z.object({
|
|
1963
2342
|
type: z.literal("project.rename.request"),
|
|
1964
2343
|
projectId: z.string(),
|
|
@@ -2002,6 +2381,22 @@ export const WorkspaceTitleSetRequestSchema = z.object({
|
|
|
2002
2381
|
title: z.string().nullable(),
|
|
2003
2382
|
requestId: z.string(),
|
|
2004
2383
|
});
|
|
2384
|
+
export const WorkspacePinSetRequestSchema = z.object({
|
|
2385
|
+
type: z.literal("workspace.pin.set.request"),
|
|
2386
|
+
workspaceId: z.string(),
|
|
2387
|
+
pinned: z.boolean(),
|
|
2388
|
+
requestId: z.string(),
|
|
2389
|
+
});
|
|
2390
|
+
export const WorkspaceRecoveryInspectRequestSchema = z.object({
|
|
2391
|
+
type: z.literal("workspace.recovery.inspect.request"),
|
|
2392
|
+
workspaceId: z.string(),
|
|
2393
|
+
requestId: z.string(),
|
|
2394
|
+
});
|
|
2395
|
+
export const WorkspaceRecoveryRestoreRequestSchema = z.object({
|
|
2396
|
+
type: z.literal("workspace.recovery.restore.request"),
|
|
2397
|
+
workspaceId: z.string(),
|
|
2398
|
+
requestId: z.string(),
|
|
2399
|
+
});
|
|
2005
2400
|
export const SetVoiceModeMessageSchema = z.object({
|
|
2006
2401
|
type: z.literal("set_voice_mode"),
|
|
2007
2402
|
enabled: z.boolean(),
|
|
@@ -2018,6 +2413,18 @@ export const GitHubPrAttachmentSchema = z.object({
|
|
|
2018
2413
|
baseRefName: z.string().nullable().optional(),
|
|
2019
2414
|
headRefName: z.string().nullable().optional(),
|
|
2020
2415
|
});
|
|
2416
|
+
export const ForgeChangeRequestAttachmentSchema = z.object({
|
|
2417
|
+
type: z.literal("forge_change_request"),
|
|
2418
|
+
mimeType: z.literal("application/otto-forge-change-request"),
|
|
2419
|
+
forge: z.string().optional().default("github"),
|
|
2420
|
+
number: z.number().int().positive(),
|
|
2421
|
+
title: z.string(),
|
|
2422
|
+
url: z.string(),
|
|
2423
|
+
body: z.string().nullable().optional(),
|
|
2424
|
+
projectPath: z.string().optional(),
|
|
2425
|
+
baseRefName: z.string().nullable().optional(),
|
|
2426
|
+
headRefName: z.string().nullable().optional(),
|
|
2427
|
+
});
|
|
2021
2428
|
export const GitHubIssueAttachmentSchema = z.object({
|
|
2022
2429
|
type: z.literal("github_issue"),
|
|
2023
2430
|
mimeType: z.literal("application/github-issue"),
|
|
@@ -2026,10 +2433,13 @@ export const GitHubIssueAttachmentSchema = z.object({
|
|
|
2026
2433
|
url: z.string(),
|
|
2027
2434
|
body: z.string().nullable().optional(),
|
|
2028
2435
|
});
|
|
2029
|
-
//
|
|
2030
|
-
//
|
|
2031
|
-
//
|
|
2032
|
-
// client sends
|
|
2436
|
+
// COMPAT(hostingAttachments): added in v0.7.6, remove after 2027-02-01.
|
|
2437
|
+
// These were the provider-neutral successors to github_pr/github_issue. The
|
|
2438
|
+
// forge merge replaced them with forge_change_request/forge_issue, so no
|
|
2439
|
+
// current client sends them - they stay accepted (protocol contract) purely so
|
|
2440
|
+
// a client from before that merge can still attach a PR or an issue. The
|
|
2441
|
+
// daemon renders them at
|
|
2442
|
+
// server/src/server/agent/prompt-attachments.ts; retire both halves together.
|
|
2033
2443
|
export const HostingPrAttachmentSchema = z.object({
|
|
2034
2444
|
type: z.literal("hosting_pr"),
|
|
2035
2445
|
mimeType: z.literal("application/otto-hosting-pr"),
|
|
@@ -2050,6 +2460,16 @@ export const HostingIssueAttachmentSchema = z.object({
|
|
|
2050
2460
|
url: z.string(),
|
|
2051
2461
|
body: z.string().nullable().optional(),
|
|
2052
2462
|
});
|
|
2463
|
+
export const ForgeIssueAttachmentSchema = z.object({
|
|
2464
|
+
type: z.literal("forge_issue"),
|
|
2465
|
+
mimeType: z.literal("application/otto-forge-issue"),
|
|
2466
|
+
forge: z.string().optional().default("github"),
|
|
2467
|
+
number: z.number().int().positive(),
|
|
2468
|
+
title: z.string(),
|
|
2469
|
+
url: z.string(),
|
|
2470
|
+
body: z.string().nullable().optional(),
|
|
2471
|
+
projectPath: z.string().optional(),
|
|
2472
|
+
});
|
|
2053
2473
|
export const TextAttachmentSchema = z
|
|
2054
2474
|
.object({
|
|
2055
2475
|
type: z.literal("text"),
|
|
@@ -2096,6 +2516,8 @@ export const UploadedFileAttachmentSchema = z.object({
|
|
|
2096
2516
|
path: z.string(),
|
|
2097
2517
|
});
|
|
2098
2518
|
export const AgentAttachmentSchema = z.discriminatedUnion("type", [
|
|
2519
|
+
ForgeChangeRequestAttachmentSchema,
|
|
2520
|
+
ForgeIssueAttachmentSchema,
|
|
2099
2521
|
GitHubPrAttachmentSchema,
|
|
2100
2522
|
GitHubIssueAttachmentSchema,
|
|
2101
2523
|
HostingPrAttachmentSchema,
|
|
@@ -2118,6 +2540,12 @@ function normalizeAgentAttachments(input) {
|
|
|
2118
2540
|
return normalized;
|
|
2119
2541
|
}
|
|
2120
2542
|
const AgentAttachmentsSchema = z.unknown().transform(normalizeAgentAttachments).optional();
|
|
2543
|
+
export const ChangeRequestCheckoutSourceSchema = z.object({
|
|
2544
|
+
kind: z.literal("change_request"),
|
|
2545
|
+
forge: z.string().optional(),
|
|
2546
|
+
number: z.number().int().positive(),
|
|
2547
|
+
projectPath: z.string().optional(),
|
|
2548
|
+
});
|
|
2121
2549
|
const ImageAttachmentSchema = z.object({
|
|
2122
2550
|
data: z.string(), // base64 encoded image
|
|
2123
2551
|
mimeType: z.string(), // e.g., "image/jpeg", "image/png"
|
|
@@ -2192,6 +2620,10 @@ export const FetchWorkspacesRequestMessageSchema = z.object({
|
|
|
2192
2620
|
})
|
|
2193
2621
|
.optional(),
|
|
2194
2622
|
});
|
|
2623
|
+
export const ProjectListRequestMessageSchema = z.object({
|
|
2624
|
+
type: z.literal("project.list.request"),
|
|
2625
|
+
requestId: z.string(),
|
|
2626
|
+
});
|
|
2195
2627
|
export const FetchAgentHistoryRequestMessageSchema = z.object({
|
|
2196
2628
|
type: z.literal("fetch_agent_history_request"),
|
|
2197
2629
|
requestId: z.string(),
|
|
@@ -2289,6 +2721,21 @@ export const DaemonGetPairingOfferRequestSchema = z.object({
|
|
|
2289
2721
|
type: z.literal("daemon.get_pairing_offer.request"),
|
|
2290
2722
|
requestId: z.string(),
|
|
2291
2723
|
});
|
|
2724
|
+
export const HubManagementDaemonConnectRequestSchema = z.object({
|
|
2725
|
+
type: z.literal("hub.management.daemon.connect.request"),
|
|
2726
|
+
requestId: z.string(),
|
|
2727
|
+
hubUrl: z.string(),
|
|
2728
|
+
token: z.string(),
|
|
2729
|
+
});
|
|
2730
|
+
export const HubManagementDaemonGetStatusRequestSchema = z.object({
|
|
2731
|
+
type: z.literal("hub.management.daemon.get_status.request"),
|
|
2732
|
+
requestId: z.string(),
|
|
2733
|
+
});
|
|
2734
|
+
export const HubManagementDaemonDisconnectRequestSchema = z.object({
|
|
2735
|
+
type: z.literal("hub.management.daemon.disconnect.request"),
|
|
2736
|
+
requestId: z.string(),
|
|
2737
|
+
force: z.boolean().optional(),
|
|
2738
|
+
});
|
|
2292
2739
|
export const DiagnosticsRequestSchema = z.object({
|
|
2293
2740
|
type: z.literal("diagnostics.request"),
|
|
2294
2741
|
requestId: z.string(),
|
|
@@ -2302,11 +2749,11 @@ export const SetDaemonConfigRequestMessageSchema = z.object({
|
|
|
2302
2749
|
requestId: z.string(),
|
|
2303
2750
|
config: MutableDaemonConfigPatchSchema,
|
|
2304
2751
|
});
|
|
2305
|
-
// Connectors
|
|
2752
|
+
// Connectors - MCP servers surfaced as named, toggle-able integrations. The
|
|
2306
2753
|
// registry itself (add/remove/enable/disable a connector or an individual tool)
|
|
2307
2754
|
// lives in daemon config and is edited via set_daemon_config's `connectors`
|
|
2308
2755
|
// patch. The one thing config can't answer is what tools a connector actually
|
|
2309
|
-
// exposes, which needs a live connect + listTools
|
|
2756
|
+
// exposes, which needs a live connect + listTools - that is this RPC. Gated by
|
|
2310
2757
|
// features.connectors.
|
|
2311
2758
|
export const ConnectorsListToolsRequestSchema = z.object({
|
|
2312
2759
|
type: z.literal("connectors.list_tools.request"),
|
|
@@ -2329,6 +2776,61 @@ export const ConnectorsListToolsResponseSchema = z.object({
|
|
|
2329
2776
|
requestId: z.string(),
|
|
2330
2777
|
}),
|
|
2331
2778
|
});
|
|
2779
|
+
// Connector OAuth - the "sign in" path for connectors whose MCP server
|
|
2780
|
+
// authenticates by login rather than by a pasted token. Three steps, because a
|
|
2781
|
+
// login is not a request/response: the client asks to authorize, the daemon
|
|
2782
|
+
// answers with a URL to open (or "already authorized"), and the actual result
|
|
2783
|
+
// arrives later as a pushed status once the user finishes in their browser.
|
|
2784
|
+
// Gated by features.connectorOauth.
|
|
2785
|
+
export const ConnectorsOauthAuthorizeRequestSchema = z.object({
|
|
2786
|
+
type: z.literal("connectors.oauth.authorize.request"),
|
|
2787
|
+
requestId: z.string(),
|
|
2788
|
+
connectorId: z.string(),
|
|
2789
|
+
/** Scopes to request, when the catalog entry names them. */
|
|
2790
|
+
scope: z.string().optional(),
|
|
2791
|
+
});
|
|
2792
|
+
export const ConnectorsOauthAuthorizeResponseSchema = z.object({
|
|
2793
|
+
type: z.literal("connectors.oauth.authorize.response"),
|
|
2794
|
+
payload: z.object({
|
|
2795
|
+
connectorId: z.string(),
|
|
2796
|
+
/**
|
|
2797
|
+
* Present when the user must sign in: the client opens this URL. Absent when
|
|
2798
|
+
* the daemon already held a usable authorization, in which case status is
|
|
2799
|
+
* "authorized" and there is nothing to open.
|
|
2800
|
+
*/
|
|
2801
|
+
authorizationUrl: z.string().nullable().default(null),
|
|
2802
|
+
status: z.enum(["redirect", "authorized", "error"]).default("error"),
|
|
2803
|
+
error: z.string().nullable().default(null),
|
|
2804
|
+
requestId: z.string(),
|
|
2805
|
+
}),
|
|
2806
|
+
});
|
|
2807
|
+
export const ConnectorsOauthDisconnectRequestSchema = z.object({
|
|
2808
|
+
type: z.literal("connectors.oauth.disconnect.request"),
|
|
2809
|
+
requestId: z.string(),
|
|
2810
|
+
connectorId: z.string(),
|
|
2811
|
+
});
|
|
2812
|
+
export const ConnectorsOauthDisconnectResponseSchema = z.object({
|
|
2813
|
+
type: z.literal("connectors.oauth.disconnect.response"),
|
|
2814
|
+
payload: z.object({
|
|
2815
|
+
connectorId: z.string(),
|
|
2816
|
+
requestId: z.string(),
|
|
2817
|
+
}),
|
|
2818
|
+
});
|
|
2819
|
+
/**
|
|
2820
|
+
* Pushed when an in-flight authorization settles. Not correlated to a requestId:
|
|
2821
|
+
* the browser round-trip outlives the request that started it, and more than one
|
|
2822
|
+
* client may be watching the same connector.
|
|
2823
|
+
*/
|
|
2824
|
+
export const ConnectorsOauthStatusMessageSchema = z.object({
|
|
2825
|
+
type: z.literal("connectors.oauth.status"),
|
|
2826
|
+
payload: z.object({
|
|
2827
|
+
connectorId: z.string(),
|
|
2828
|
+
status: z.enum(["connected", "failed"]),
|
|
2829
|
+
/** Account label to show once connected, when the server reveals one. */
|
|
2830
|
+
account: z.string().nullable().default(null),
|
|
2831
|
+
error: z.string().nullable().default(null),
|
|
2832
|
+
}),
|
|
2833
|
+
});
|
|
2332
2834
|
export const SpeechSettingsGetOptionsRequestSchema = z.object({
|
|
2333
2835
|
type: z.literal("speech.settings.get_options.request"),
|
|
2334
2836
|
requestId: z.string(),
|
|
@@ -2352,8 +2854,8 @@ export const SpeechTtsPreviewRequestSchema = z.object({
|
|
|
2352
2854
|
.optional(),
|
|
2353
2855
|
});
|
|
2354
2856
|
// Read a full assistant message aloud on demand (the per-message playback
|
|
2355
|
-
// button). Unlike the preview RPC
|
|
2356
|
-
// returns one buffered clip
|
|
2857
|
+
// button). Unlike the preview RPC - which truncates to a short sample and
|
|
2858
|
+
// returns one buffered clip - this synthesizes the ENTIRE text and streams it
|
|
2357
2859
|
// back as `audio_output` chunks (isVoiceMode: false), one group per sentence, so
|
|
2358
2860
|
// playback starts after the first sentence instead of the whole message.
|
|
2359
2861
|
// `voice` (optional) is the speaking agent's personality voice, resolved on the
|
|
@@ -2382,8 +2884,8 @@ export const SpeechTtsSpeakCancelRequestSchema = z.object({
|
|
|
2382
2884
|
});
|
|
2383
2885
|
// COMPAT(visualizerVoiceCues): added in v0.6.3; gate lives in
|
|
2384
2886
|
// features.visualizerVoiceCues. Author short spoken "cue" lines for a
|
|
2385
|
-
// personality
|
|
2386
|
-
// (join / thinking / done)
|
|
2887
|
+
// personality - a handful of variations each for three Visualizer moments
|
|
2888
|
+
// (join / thinking / done) - via the Writer mini-task chain, flavored by the
|
|
2387
2889
|
// persona's `name` + `prompt`. The persona is passed inline (not a stored id)
|
|
2388
2890
|
// so the personality editor can generate for an unsaved draft too; the result
|
|
2389
2891
|
// is stored on the personality (`voiceCues`) and edited there, so this is an
|
|
@@ -2477,6 +2979,9 @@ const GitSetupOptionsSchema = z.object({
|
|
|
2477
2979
|
worktreeSlug: z.string().optional(),
|
|
2478
2980
|
refName: z.string().min(1).optional(),
|
|
2479
2981
|
action: z.enum(["branch-off", "checkout"]).optional(),
|
|
2982
|
+
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
|
|
2983
|
+
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
|
|
2984
|
+
// clients send checkoutSource.
|
|
2480
2985
|
githubPrNumber: z.number().int().positive().optional(),
|
|
2481
2986
|
});
|
|
2482
2987
|
export const CreateAgentWorktreeTargetSchema = z.discriminatedUnion("mode", [
|
|
@@ -2499,12 +3004,15 @@ export const CreateAgentRequestMessageSchema = z.object({
|
|
|
2499
3004
|
config: AgentSessionConfigSchema,
|
|
2500
3005
|
// Optional personality id. When present the daemon resolves the personality
|
|
2501
3006
|
// against this cwd's provider snapshot and snapshots its identity (spinner,
|
|
2502
|
-
// voice, prompt) onto the agent
|
|
3007
|
+
// voice, prompt) onto the agent - the brain (provider/model/mode/effort) still
|
|
2503
3008
|
// comes from `config`, so hand-deviations in the picker keep the identity.
|
|
2504
3009
|
// COMPAT(agentPersonalities): added in v0.5.0; gate lives in features.agentPersonalities.
|
|
2505
3010
|
personality: z.string().optional(),
|
|
2506
3011
|
env: z.record(z.string(), z.string()).optional(),
|
|
2507
3012
|
workspaceId: z.string().optional(),
|
|
3013
|
+
// Optional caller context lets managed CLI invocations use the same daemon-owned
|
|
3014
|
+
// workspace and parentage policy as agent-scoped MCP creation.
|
|
3015
|
+
callerAgentId: z.string().optional(),
|
|
2508
3016
|
worktreeName: z.string().optional(),
|
|
2509
3017
|
initialPrompt: z.string().optional(),
|
|
2510
3018
|
clientMessageId: z.string().optional(),
|
|
@@ -2553,7 +3061,7 @@ export const ProviderUsageListRequestMessageSchema = z.object({
|
|
|
2553
3061
|
type: z.literal("provider.usage.list.request"),
|
|
2554
3062
|
requestId: z.string(),
|
|
2555
3063
|
});
|
|
2556
|
-
// Daemon-wide "fun stats" counters
|
|
3064
|
+
// Daemon-wide "fun stats" counters - see docs/data-model.md ActivityStatsStore.
|
|
2557
3065
|
// Every field defaults to 0 so old and new daemons/clients stay compatible as
|
|
2558
3066
|
// counters are added later.
|
|
2559
3067
|
export const ActivityCountersSchema = z.object({
|
|
@@ -2572,7 +3080,7 @@ export const ActivityCountersSchema = z.object({
|
|
|
2572
3080
|
// Usage & cost accounting (WP-G). Additive/defaulted like every counter above,
|
|
2573
3081
|
// so old daemons emit 0 and old clients drop the unknown leaves. "In"/"Out"
|
|
2574
3082
|
// are token totals; *CostMicroUsd are integer micro-USD (usd*1e6) to stay
|
|
2575
|
-
// summable
|
|
3083
|
+
// summable - populated only for turns reporting a real provider cost (Claude).
|
|
2576
3084
|
// The client detects whether the daemon actually populates these via
|
|
2577
3085
|
// features.usageCostCategories (see below).
|
|
2578
3086
|
costMicroUsd: z.number().default(0),
|
|
@@ -2605,10 +3113,10 @@ export const StatsActivityGetResponseMessageSchema = z.object({
|
|
|
2605
3113
|
allTime: ActivityCountersSchema,
|
|
2606
3114
|
}),
|
|
2607
3115
|
});
|
|
2608
|
-
// Daemon-wide "activity counters moved" ping
|
|
3116
|
+
// Daemon-wide "activity counters moved" ping - broadcast to every client,
|
|
2609
3117
|
// coalesced at the daemon (at most once every few seconds) so bursts of
|
|
2610
3118
|
// increments don't get chatty. Carries no payload: clients re-fetch the
|
|
2611
|
-
// rollups via stats.activity.get. Purely additive
|
|
3119
|
+
// rollups via stats.activity.get. Purely additive - old clients drop the
|
|
2612
3120
|
// unknown type with a warning, and against old daemons (which never send it)
|
|
2613
3121
|
// the stats screen degrades to today's focus/manual refresh. Rides the
|
|
2614
3122
|
// existing activityStats capability; no new feature flag needed because no
|
|
@@ -2616,12 +3124,12 @@ export const StatsActivityGetResponseMessageSchema = z.object({
|
|
|
2616
3124
|
export const ActivityStatsChangedSchema = z.object({
|
|
2617
3125
|
type: z.literal("activity_stats_changed"),
|
|
2618
3126
|
});
|
|
2619
|
-
// One itemized row of the usage ledger
|
|
3127
|
+
// One itemized row of the usage ledger - a single token/cost-bearing activity
|
|
2620
3128
|
// (a chat turn, a sub-agent turn, or a background generation). The aggregate
|
|
2621
3129
|
// ActivityCounters above are the rollup of this same event stream; the ledger is
|
|
2622
3130
|
// the scrollable detail behind the tiles (usage-ledger project). `kind` and
|
|
2623
3131
|
// `provider` are plain strings (not enums) so an OLD client still parses a NEW
|
|
2624
|
-
// daemon that emits a kind it hasn't heard of
|
|
3132
|
+
// daemon that emits a kind it hasn't heard of - it renders it generically rather
|
|
2625
3133
|
// than failing the whole message. All token/cost leaves default to 0.
|
|
2626
3134
|
export const UsageEventSchema = z.object({
|
|
2627
3135
|
/** Stable unique id for the row (daemon-generated). */
|
|
@@ -2657,20 +3165,20 @@ export const UsageEventSchema = z.object({
|
|
|
2657
3165
|
/**
|
|
2658
3166
|
* How many model round-trips this row aggregates. A chat row is one query, but
|
|
2659
3167
|
* a sub-agent row covers a whole delegated task that internally ran many
|
|
2660
|
-
* rounds
|
|
3168
|
+
* rounds - and each round re-reads the growing context, so `cachedTokensIn` is
|
|
2661
3169
|
* cumulative cache-READS, not a cache size. Surfacing the count is what makes a
|
|
2662
3170
|
* large cached figure legible instead of looking like a bug. Absent when the
|
|
2663
3171
|
* provider doesn't report it.
|
|
2664
3172
|
*/
|
|
2665
3173
|
rounds: z.number().optional(),
|
|
2666
3174
|
/**
|
|
2667
|
-
* Sub-agent rows only
|
|
3175
|
+
* Sub-agent rows only - the spawn-tree identity that lets the Log group rows
|
|
2668
3176
|
* the way a human reads the run (chat turn → its sub-agents → their
|
|
2669
3177
|
* sub-agents) instead of by settle time, which async sub-agents crossing turn
|
|
2670
3178
|
* boundaries makes wrong. `startedAt` is when the sub-agent was first
|
|
2671
3179
|
* observed (epoch ms; a row belongs to the turn that spawned it, not the turn
|
|
2672
3180
|
* it happened to settle in), `subagentKey` is its stable observed key, and
|
|
2673
|
-
* `parentSubagentKey` is the spawning sub-agent's key
|
|
3181
|
+
* `parentSubagentKey` is the spawning sub-agent's key - absent for depth-1
|
|
2674
3182
|
* sub-agents spawned by the chat itself.
|
|
2675
3183
|
*/
|
|
2676
3184
|
startedAt: z.number().optional(),
|
|
@@ -2696,7 +3204,7 @@ export const UsageLogGetResponseMessageSchema = z.object({
|
|
|
2696
3204
|
}),
|
|
2697
3205
|
});
|
|
2698
3206
|
// Wipe every daemon-wide usage counter AND the itemized usage ledger back to
|
|
2699
|
-
// zero
|
|
3207
|
+
// zero - the "Reset" action on the Metrics screen. One RPC clears both sinks
|
|
2700
3208
|
// (the day-bucketed ActivityStatsStore and the UsageLogStore) so the tiles and
|
|
2701
3209
|
// the Log tab start fresh together. Gated behind features.statsReset so an old
|
|
2702
3210
|
// daemon (no handler) never receives a request the client thinks it can send.
|
|
@@ -2776,9 +3284,29 @@ export const FetchAgentTimelineRequestMessageSchema = z.object({
|
|
|
2776
3284
|
// Default should be projected for app timeline loading.
|
|
2777
3285
|
projection: z.enum(["projected", "canonical"]).optional(),
|
|
2778
3286
|
});
|
|
3287
|
+
export const ProviderSubagentListRequestMessageSchema = z.object({
|
|
3288
|
+
type: z.literal("agent.provider_subagents.list.request"),
|
|
3289
|
+
parentAgentId: z.string(),
|
|
3290
|
+
requestId: z.string(),
|
|
3291
|
+
});
|
|
3292
|
+
export const ProviderSubagentTimelineRequestMessageSchema = z.object({
|
|
3293
|
+
type: z.literal("agent.provider_subagents.timeline.get.request"),
|
|
3294
|
+
parentAgentId: z.string(),
|
|
3295
|
+
subagentId: z.string(),
|
|
3296
|
+
requestId: z.string(),
|
|
3297
|
+
direction: z.enum(["tail", "before", "after"]).optional(),
|
|
3298
|
+
cursor: AgentTimelineCursorSchema.optional(),
|
|
3299
|
+
limit: z.number().int().nonnegative().optional(),
|
|
3300
|
+
});
|
|
3301
|
+
export const SetAgentTimelineSubscriptionRequestMessageSchema = z.object({
|
|
3302
|
+
type: z.literal("agent.timeline.set_subscription.request"),
|
|
3303
|
+
agentIds: z.array(z.string()),
|
|
3304
|
+
requestId: z.string(),
|
|
3305
|
+
});
|
|
2779
3306
|
export const AgentForkContextRequestMessageSchema = z.object({
|
|
2780
3307
|
type: z.literal("agent.fork_context.request"),
|
|
2781
3308
|
agentId: z.string(),
|
|
3309
|
+
boundaryCursor: AgentTimelineCursorSchema.optional(),
|
|
2782
3310
|
boundaryMessageId: z.string().optional(),
|
|
2783
3311
|
requestId: z.string(),
|
|
2784
3312
|
});
|
|
@@ -2874,7 +3402,7 @@ export const AgentSubagentStopResponseMessageSchema = z.object({
|
|
|
2874
3402
|
payload: AgentActionResponsePayloadSchema,
|
|
2875
3403
|
});
|
|
2876
3404
|
// A background shell task launched by a provider's own Bash tool (Claude:
|
|
2877
|
-
// run_in_background). Not an agent, not a subagent
|
|
3405
|
+
// run_in_background). Not an agent, not a subagent - a plain shell process
|
|
2878
3406
|
// the daemon tracks for the parent agent's Background Tasks track.
|
|
2879
3407
|
// COMPAT(backgroundShellTasks): added in v0.5.3, drop the gate when daemon floor >= v0.5.3.
|
|
2880
3408
|
export const BackgroundShellTaskInfoSchema = z.object({
|
|
@@ -2890,7 +3418,7 @@ export const BackgroundShellTaskInfoSchema = z.object({
|
|
|
2890
3418
|
archivedAt: z.string().optional(),
|
|
2891
3419
|
});
|
|
2892
3420
|
// Pushed with the full current set of background shell tasks for a parent
|
|
2893
|
-
// agent whenever any of them changes (start/progress/settle/clear)
|
|
3421
|
+
// agent whenever any of them changes (start/progress/settle/clear) - same
|
|
2894
3422
|
// full-list reconciliation shape as TerminalsChangedSchema.
|
|
2895
3423
|
export const BackgroundShellTasksChangedSchema = z.object({
|
|
2896
3424
|
type: z.literal("background_shell_tasks_changed"),
|
|
@@ -2926,7 +3454,7 @@ export const AgentBackgroundTaskClearResponseMessageSchema = z.object({
|
|
|
2926
3454
|
// A suggested task an agent surfaced via the `spawn_task` tool (Claude Desktop
|
|
2927
3455
|
// parity). Renders as a chip in the parent agent's session; the user starts it
|
|
2928
3456
|
// (new worktree / local / this session) or dismisses it. The `prompt` is
|
|
2929
|
-
// deliberately NOT part of this wire shape
|
|
3457
|
+
// deliberately NOT part of this wire shape - it stays server-side and is only
|
|
2930
3458
|
// used when the task is started ("not shown directly" in Claude Desktop).
|
|
2931
3459
|
// COMPAT(suggestedTasks): added in v0.5.6, drop the gate when daemon floor >= v0.5.6.
|
|
2932
3460
|
export const SuggestedTaskStateSchema = z.enum(["pending", "started", "dismissed"]);
|
|
@@ -2941,7 +3469,7 @@ export const SuggestedTaskInfoSchema = z.object({
|
|
|
2941
3469
|
updatedAt: z.string(),
|
|
2942
3470
|
});
|
|
2943
3471
|
// Pushed with the full current set of pending suggested tasks for a parent
|
|
2944
|
-
// agent whenever any of them changes (spawn/start/dismiss)
|
|
3472
|
+
// agent whenever any of them changes (spawn/start/dismiss) - same full-list
|
|
2945
3473
|
// reconciliation shape as BackgroundShellTasksChangedSchema.
|
|
2946
3474
|
export const SuggestedTasksChangedSchema = z.object({
|
|
2947
3475
|
type: z.literal("suggested_tasks_changed"),
|
|
@@ -2950,7 +3478,7 @@ export const SuggestedTasksChangedSchema = z.object({
|
|
|
2950
3478
|
tasks: z.array(SuggestedTaskInfoSchema),
|
|
2951
3479
|
}),
|
|
2952
3480
|
});
|
|
2953
|
-
// Context Management
|
|
3481
|
+
// Context Management - the daemon's accounting of everything a provider sends
|
|
2954
3482
|
// before the user types (see docs/context-management.md).
|
|
2955
3483
|
//
|
|
2956
3484
|
// Two distinctions carry the whole feature and must not be collapsed on the
|
|
@@ -3011,7 +3539,7 @@ export const ContextFindingSchema = z.object({
|
|
|
3011
3539
|
range: ContextRangeSchema.optional(),
|
|
3012
3540
|
relatedNodeIds: z.array(z.string()).optional(),
|
|
3013
3541
|
// The node this finding is about. Redundant while the finding sits on its
|
|
3014
|
-
// node, load-bearing once the report flattens them all into one list
|
|
3542
|
+
// node, load-bearing once the report flattens them all into one list - that
|
|
3015
3543
|
// list is the "Issues" tab, and without this a row cannot say where it came
|
|
3016
3544
|
// from or take you there.
|
|
3017
3545
|
nodeId: z.string().optional(),
|
|
@@ -3022,9 +3550,9 @@ export const ContextFindingSchema = z.object({
|
|
|
3022
3550
|
// rather than dropping a cursor at the top of it.
|
|
3023
3551
|
lineEnd: z.number().optional(),
|
|
3024
3552
|
// True for kinds a mechanical delete can resolve on its own (dead links, a
|
|
3025
|
-
// duplicate block)
|
|
3553
|
+
// duplicate block) - false/absent for kinds that need judgment (which side
|
|
3026
3554
|
// of an import cycle to cut, how to split an oversized entry). Computed
|
|
3027
|
-
// server-side, once, in `locateFinding`
|
|
3555
|
+
// server-side, once, in `locateFinding` - the only place that knows the kind
|
|
3028
3556
|
// vocabulary, so the fix-all button never has to guess.
|
|
3029
3557
|
fixable: z.boolean().optional(),
|
|
3030
3558
|
// The exact text at `range` when the file was scanned. `context.findings.fix`
|
|
@@ -3048,7 +3576,7 @@ export const ContextNodeSchema = z.object({
|
|
|
3048
3576
|
});
|
|
3049
3577
|
export const ContextEdgeSchema = z.object({
|
|
3050
3578
|
fromNodeId: z.string(),
|
|
3051
|
-
// Null when the target could not be resolved
|
|
3579
|
+
// Null when the target could not be resolved - pairs with a dead_* finding.
|
|
3052
3580
|
toNodeId: z.string().nullable(),
|
|
3053
3581
|
kind: z.enum(["import", "reference"]),
|
|
3054
3582
|
rawTarget: z.string(),
|
|
@@ -3069,7 +3597,7 @@ export const ContextCategoryTotalSchema = z.object({
|
|
|
3069
3597
|
export const ContextReportSchema = z.object({
|
|
3070
3598
|
workspaceId: z.string(),
|
|
3071
3599
|
provider: z.string(),
|
|
3072
|
-
// The window the report was evaluated against
|
|
3600
|
+
// The window the report was evaluated against - from the active model, or
|
|
3073
3601
|
// the client's what-if picker. Severity is meaningless without it.
|
|
3074
3602
|
windowTokens: z.number(),
|
|
3075
3603
|
scannedAt: z.string(),
|
|
@@ -3126,7 +3654,7 @@ export const ContextReportGetResponseMessageSchema = z.object({
|
|
|
3126
3654
|
}),
|
|
3127
3655
|
});
|
|
3128
3656
|
// One readable block of the assembled prompt. `text` is absent exactly when
|
|
3129
|
-
// `visibility` is "not_visible"
|
|
3657
|
+
// `visibility` is "not_visible" - the provider composes that part internally and
|
|
3130
3658
|
// Otto has nothing to show, which the section states rather than hides.
|
|
3131
3659
|
export const ContextPromptSectionSchema = z.object({
|
|
3132
3660
|
category: ContextCategorySchema,
|
|
@@ -3149,8 +3677,8 @@ export const ContextPromptPreviewGetRequestMessageSchema = z.object({
|
|
|
3149
3677
|
provider: z.string().optional(),
|
|
3150
3678
|
windowTokens: z.number().optional(),
|
|
3151
3679
|
personalityId: z.string().optional(),
|
|
3152
|
-
// Assemble only this category. The tab reads one section at a time
|
|
3153
|
-
// clicked a row in the tree
|
|
3680
|
+
// Assemble only this category. The tab reads one section at a time - the user
|
|
3681
|
+
// clicked a row in the tree - and assembling the rest would re-read every
|
|
3154
3682
|
// context file on disk to build text nobody asked to see. Omitted means all,
|
|
3155
3683
|
// which is what an older client sends.
|
|
3156
3684
|
category: ContextCategorySchema.optional(),
|
|
@@ -3168,7 +3696,7 @@ export const ContextEdgeConvertRequestMessageSchema = z.object({
|
|
|
3168
3696
|
type: z.literal("context.edge.convert.request"),
|
|
3169
3697
|
requestId: z.string(),
|
|
3170
3698
|
workspaceId: z.string(),
|
|
3171
|
-
// The parent file holding the reference
|
|
3699
|
+
// The parent file holding the reference - its `ContextNode.path`, not its
|
|
3172
3700
|
// id: ids are case-folded on Windows and are not safe to write through.
|
|
3173
3701
|
filePath: z.string(),
|
|
3174
3702
|
rawTarget: z.string(),
|
|
@@ -3183,7 +3711,7 @@ export const ContextEdgeConvertResponseMessageSchema = z.object({
|
|
|
3183
3711
|
error: z.string().optional(),
|
|
3184
3712
|
}),
|
|
3185
3713
|
});
|
|
3186
|
-
// Deletes every mechanically-fixable finding's range in one pass
|
|
3714
|
+
// Deletes every mechanically-fixable finding's range in one pass - the
|
|
3187
3715
|
// "Fix all" button in the Issues tab. Each item names the file, the range the
|
|
3188
3716
|
// scan flagged, and the snippet expected there; a file that changed since the
|
|
3189
3717
|
// scan is skipped rather than corrupted (charter §7.5).
|
|
@@ -3207,7 +3735,7 @@ export const ContextFindingsFixResponseMessageSchema = z.object({
|
|
|
3207
3735
|
}),
|
|
3208
3736
|
});
|
|
3209
3737
|
// ---------------------------------------------------------------------------
|
|
3210
|
-
// Personality memory
|
|
3738
|
+
// Personality memory - the lessons a named personality accrues across sessions.
|
|
3211
3739
|
// See docs/agent-personalities.md § Memory.
|
|
3212
3740
|
// ---------------------------------------------------------------------------
|
|
3213
3741
|
// Plain strings on the wire, like personality roles and effort levels, so the
|
|
@@ -3250,7 +3778,7 @@ export const PersonalityMemoryListResponseMessageSchema = z.object({
|
|
|
3250
3778
|
personalityName: z.string(),
|
|
3251
3779
|
/** Whether this personality is accruing (the `memoryEnabled` switch). */
|
|
3252
3780
|
enabled: z.boolean(),
|
|
3253
|
-
/** Every stored entry, including other projects'
|
|
3781
|
+
/** Every stored entry, including other projects' - the UI shows them all. */
|
|
3254
3782
|
entries: z.array(PersonalityMemoryEntrySchema),
|
|
3255
3783
|
// The EXACT text the daemon would inject for `projectRoot`, not a
|
|
3256
3784
|
// reconstruction. Memory is only trustworthy if it is inspectable, and the
|
|
@@ -3318,7 +3846,7 @@ export const PersonalityMemoryTransferResponseMessageSchema = z.object({
|
|
|
3318
3846
|
}),
|
|
3319
3847
|
});
|
|
3320
3848
|
// Per-personality lesson counts. Its own RPC over its own file, mirroring
|
|
3321
|
-
// agentPersonalities.get_stats
|
|
3849
|
+
// agentPersonalities.get_stats - counts must not ride the daemon-config
|
|
3322
3850
|
// broadcast, or every recorded lesson would fan a config change to every client.
|
|
3323
3851
|
export const PersonalityMemoryStatsRequestMessageSchema = z.object({
|
|
3324
3852
|
type: z.literal("personality.memory.stats.request"),
|
|
@@ -3342,14 +3870,14 @@ const SuggestedTaskActionResponsePayloadSchema = z.object({
|
|
|
3342
3870
|
failed: z.number(),
|
|
3343
3871
|
error: z.string().nullable(),
|
|
3344
3872
|
});
|
|
3345
|
-
// Start one or more suggested tasks, applying the SAME mode to each
|
|
3873
|
+
// Start one or more suggested tasks, applying the SAME mode to each - no
|
|
3346
3874
|
// combining. Four modes, only `subagent` links the new agent to the parent:
|
|
3347
3875
|
// - `new_chat`: a fresh independent agent in its own tab, same repo/cwd, NO
|
|
3348
|
-
// parent link
|
|
3876
|
+
// parent link - survives the parent's cancel/archive.
|
|
3349
3877
|
// - `subagent`: a bound child agent that shows in the parent's Subagents
|
|
3350
3878
|
// track and archive-cascades with it.
|
|
3351
3879
|
// - `worktree`: an independent agent on a new git worktree (auto branch-off),
|
|
3352
|
-
// isolated workspace
|
|
3880
|
+
// isolated workspace - also unlinked from the parent.
|
|
3353
3881
|
// - `in_session`: steers the parent agent with the task prompt (no new agent).
|
|
3354
3882
|
// The daemon resolves the parent agent's brain (provider/model/personality) so a
|
|
3355
3883
|
// started task continues the suggesting agent.
|
|
@@ -3382,8 +3910,8 @@ export const TasksSuggestedDismissResponseMessageSchema = z.object({
|
|
|
3382
3910
|
});
|
|
3383
3911
|
// Switch a running agent to an Agent Personality (or clear with null). The
|
|
3384
3912
|
// daemon re-resolves the id against the roster + the agent's cwd provider
|
|
3385
|
-
// snapshot and applies the full personality live
|
|
3386
|
-
// (name/spinner), and brain (model/mode/effort)
|
|
3913
|
+
// snapshot and applies the full personality live - system prompt, identity
|
|
3914
|
+
// (name/spinner), and brain (model/mode/effort) - restarting the provider query
|
|
3387
3915
|
// so the new prompt takes effect on the next turn. Providers that cannot apply
|
|
3388
3916
|
// a prompt mid-session reject. COMPAT(setAgentPersonality): added in v0.5.0;
|
|
3389
3917
|
// gate lives in features.setAgentPersonality.
|
|
@@ -3498,6 +4026,48 @@ export const AgentWorkspaceTransferResponseMessageSchema = z.object({
|
|
|
3498
4026
|
type: z.literal("agent.workspace.transfer.response"),
|
|
3499
4027
|
payload: AgentWorkspaceTransferResponsePayloadSchema,
|
|
3500
4028
|
});
|
|
4029
|
+
export const WorkspacePinSetResponsePayloadSchema = z.object({
|
|
4030
|
+
requestId: z.string(),
|
|
4031
|
+
workspaceId: z.string(),
|
|
4032
|
+
accepted: z.boolean(),
|
|
4033
|
+
pinnedAt: z.string().nullable(),
|
|
4034
|
+
error: z.string().nullable(),
|
|
4035
|
+
});
|
|
4036
|
+
export const WorkspacePinSetResponseSchema = z.object({
|
|
4037
|
+
type: z.literal("workspace.pin.set.response"),
|
|
4038
|
+
payload: WorkspacePinSetResponsePayloadSchema,
|
|
4039
|
+
});
|
|
4040
|
+
export const WorkspaceRecoveryStateSchema = z.discriminatedUnion("kind", [
|
|
4041
|
+
z.object({
|
|
4042
|
+
kind: z.literal("recoverable"),
|
|
4043
|
+
workspaceId: z.string(),
|
|
4044
|
+
workspaceName: z.string(),
|
|
4045
|
+
action: z.string(),
|
|
4046
|
+
branch: z.string().nullable(),
|
|
4047
|
+
}),
|
|
4048
|
+
z.object({
|
|
4049
|
+
kind: z.literal("unavailable"),
|
|
4050
|
+
workspaceId: z.string(),
|
|
4051
|
+
reason: z.string(),
|
|
4052
|
+
message: z.string(),
|
|
4053
|
+
}),
|
|
4054
|
+
]);
|
|
4055
|
+
export const WorkspaceRecoveryInspectResponseSchema = z.object({
|
|
4056
|
+
type: z.literal("workspace.recovery.inspect.response"),
|
|
4057
|
+
payload: z.object({
|
|
4058
|
+
requestId: z.string(),
|
|
4059
|
+
state: WorkspaceRecoveryStateSchema,
|
|
4060
|
+
}),
|
|
4061
|
+
});
|
|
4062
|
+
export const WorkspaceRecoveryRestoreResponseSchema = z.object({
|
|
4063
|
+
type: z.literal("workspace.recovery.restore.response"),
|
|
4064
|
+
payload: z.object({
|
|
4065
|
+
requestId: z.string(),
|
|
4066
|
+
workspaceId: z.string(),
|
|
4067
|
+
accepted: z.boolean(),
|
|
4068
|
+
error: z.string().nullable(),
|
|
4069
|
+
}),
|
|
4070
|
+
});
|
|
3501
4071
|
export const SetVoiceModeResponseMessageSchema = z.object({
|
|
3502
4072
|
type: z.literal("set_voice_mode_response"),
|
|
3503
4073
|
payload: z.object({
|
|
@@ -3659,7 +4229,7 @@ export const RunsClearResponseSchema = z.object({
|
|
|
3659
4229
|
requestId: z.string(),
|
|
3660
4230
|
}),
|
|
3661
4231
|
});
|
|
3662
|
-
// Delete one run by id. Terminal (done/failed/canceled) and draft runs only
|
|
4232
|
+
// Delete one run by id. Terminal (done/failed/canceled) and draft runs only -
|
|
3663
4233
|
// deleting an active run is refused so a cleanup click can't silently orphan
|
|
3664
4234
|
// running agents; cancel it first. Gated by server_info.features.runsDelete.
|
|
3665
4235
|
export const RunsDeleteRequestSchema = z.object({
|
|
@@ -3671,7 +4241,7 @@ export const RunsDeleteResponseSchema = z.object({
|
|
|
3671
4241
|
type: z.literal("runs.delete.response"),
|
|
3672
4242
|
payload: z.object({
|
|
3673
4243
|
// The deleted id, or absent when nothing was deleted (unknown or still
|
|
3674
|
-
// active)
|
|
4244
|
+
// active) - `error` then carries why.
|
|
3675
4245
|
runId: z.string().optional(),
|
|
3676
4246
|
error: z.string().optional(),
|
|
3677
4247
|
requestId: z.string(),
|
|
@@ -3786,11 +4356,11 @@ export const RunsTemplatesChangedNotificationSchema = z.object({
|
|
|
3786
4356
|
}),
|
|
3787
4357
|
});
|
|
3788
4358
|
// Start (or draft) a user-initiated orchestration from the New Orchestration
|
|
3789
|
-
// dialog. `flavor` is an open vocabulary: "ai" (prompt-and-go
|
|
4359
|
+
// dialog. `flavor` is an open vocabulary: "ai" (prompt-and-go - the daemon
|
|
3790
4360
|
// spawns an orchestrator agent that declares its own plan via start_run) or
|
|
3791
|
-
// "graph" (deterministic
|
|
4361
|
+
// "graph" (deterministic - the daemon executes `graphId` with `graphInputs`).
|
|
3792
4362
|
// `draft: true` creates the record without executing (the designer flow);
|
|
3793
|
-
// `runId` executes an existing draft in place
|
|
4363
|
+
// `runId` executes an existing draft in place - or, with `draft: true`, re-saves
|
|
3794
4364
|
// that draft in place (Edit Orchestration).
|
|
3795
4365
|
export const RunsStartRequestSchema = z.object({
|
|
3796
4366
|
type: z.literal("runs.start.request"),
|
|
@@ -3842,7 +4412,7 @@ export const CheckoutGitCommitRequestSchema = z.object({
|
|
|
3842
4412
|
});
|
|
3843
4413
|
// Resolve which agent the daemon would use to author a commit message for this
|
|
3844
4414
|
// checkout (the "writer" role) so the client can name it in a confirmation
|
|
3845
|
-
// before running the AI-authored commit. A pure query
|
|
4415
|
+
// before running the AI-authored commit. A pure query - it never commits. Gated
|
|
3846
4416
|
// by server_info.features.checkoutGitCommitAgent.
|
|
3847
4417
|
export const CheckoutGitCommitAgentRequestSchema = z.object({
|
|
3848
4418
|
type: z.literal("checkout.git.commit_agent.request"),
|
|
@@ -3894,8 +4464,8 @@ export const CheckoutGitFileCommitDiffRequestSchema = z.object({
|
|
|
3894
4464
|
ignoreWhitespace: z.boolean().optional(),
|
|
3895
4465
|
requestId: z.string(),
|
|
3896
4466
|
});
|
|
3897
|
-
// One page of blame. Always paged
|
|
3898
|
-
// daemon
|
|
4467
|
+
// One page of blame. Always paged - blaming a large file whole would block the
|
|
4468
|
+
// daemon - so the client walks the file a page at a time.
|
|
3899
4469
|
export const CheckoutGitFileBlameRequestSchema = z.object({
|
|
3900
4470
|
type: z.literal("checkout.git.get_file_blame.request"),
|
|
3901
4471
|
cwd: z.string(),
|
|
@@ -3958,6 +4528,15 @@ export const CheckoutPrMergeRequestSchema = z.object({
|
|
|
3958
4528
|
mergeMethod: z.enum(["merge", "squash", "rebase"]),
|
|
3959
4529
|
requestId: z.string(),
|
|
3960
4530
|
});
|
|
4531
|
+
export const CheckoutForgeSetAutoMergeRequestSchema = z.object({
|
|
4532
|
+
type: z.literal("checkout.forge.set_auto_merge.request"),
|
|
4533
|
+
cwd: z.string(),
|
|
4534
|
+
enabled: z.boolean(),
|
|
4535
|
+
mergeMethod: z.enum(["merge", "squash", "rebase"]).optional(),
|
|
4536
|
+
requestId: z.string(),
|
|
4537
|
+
});
|
|
4538
|
+
// COMPAT(githubAutoMergeRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
4539
|
+
// all supported clients use checkout.forge.set_auto_merge.*.
|
|
3961
4540
|
export const CheckoutGithubSetAutoMergeRequestSchema = z.object({
|
|
3962
4541
|
type: z.literal("checkout.github.set_auto_merge.request"),
|
|
3963
4542
|
cwd: z.string(),
|
|
@@ -3965,16 +4544,63 @@ export const CheckoutGithubSetAutoMergeRequestSchema = z.object({
|
|
|
3965
4544
|
mergeMethod: z.enum(["merge", "squash", "rebase"]).optional(),
|
|
3966
4545
|
requestId: z.string(),
|
|
3967
4546
|
});
|
|
4547
|
+
const CheckoutCommitFileSchema = z.object({
|
|
4548
|
+
path: z.string(),
|
|
4549
|
+
additions: z.number(),
|
|
4550
|
+
deletions: z.number(),
|
|
4551
|
+
status: z.enum(["added", "modified", "deleted", "renamed"]).optional(),
|
|
4552
|
+
});
|
|
4553
|
+
const CheckoutCommitSchema = z.object({
|
|
4554
|
+
sha: z.string(),
|
|
4555
|
+
shortSha: z.string(),
|
|
4556
|
+
subject: z.string(),
|
|
4557
|
+
authorName: z.string(),
|
|
4558
|
+
authorDate: z.string(), // ISO 8601
|
|
4559
|
+
isOnRemote: z.boolean(), // false = local-only (unpushed)
|
|
4560
|
+
// COMPAT(commitBaseClassification): added in v0.2.0, remove optional after 2027-01-23.
|
|
4561
|
+
isOnBase: z.boolean().optional(),
|
|
4562
|
+
files: z.array(CheckoutCommitFileSchema),
|
|
4563
|
+
});
|
|
4564
|
+
export const CheckoutCommitsListRequestSchema = z.object({
|
|
4565
|
+
type: z.literal("checkout.commits.list.request"),
|
|
4566
|
+
cwd: z.string(),
|
|
4567
|
+
requestId: z.string(),
|
|
4568
|
+
});
|
|
4569
|
+
export const CheckoutCommitFileDiffRequestSchema = z.object({
|
|
4570
|
+
type: z.literal("checkout.commits.file_diff.request"),
|
|
4571
|
+
cwd: z.string(),
|
|
4572
|
+
sha: z.string(),
|
|
4573
|
+
path: z.string(),
|
|
4574
|
+
requestId: z.string(),
|
|
4575
|
+
});
|
|
3968
4576
|
const GitHubRepoSegmentSchema = z.string().regex(/^[A-Za-z0-9._-]+$/);
|
|
3969
|
-
|
|
3970
|
-
type: z.literal("checkout.github.get_check_details.request"),
|
|
4577
|
+
const CheckoutCheckDetailsRequestPayloadSchema = z.object({
|
|
3971
4578
|
cwd: z.string(),
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
4579
|
+
// GitHub addresses check runs by owner/name. GitLab resolves the project from
|
|
4580
|
+
// cwd and omits these GitHub-only single-segment fields.
|
|
4581
|
+
repoOwner: GitHubRepoSegmentSchema.optional(),
|
|
4582
|
+
repoName: GitHubRepoSegmentSchema.optional(),
|
|
4583
|
+
// Permanently optional: a check addressed only by workflowRunId (Gitea
|
|
4584
|
+
// Actions runs carry no check-run id) is fetchable. Callers send at least one
|
|
4585
|
+
// of checkRunId/workflowRunId; the gated forge RPC only reaches daemons that
|
|
4586
|
+
// understand this.
|
|
4587
|
+
checkRunId: z.number().int().positive().optional(),
|
|
3975
4588
|
workflowRunId: z.number().int().positive().optional(),
|
|
4589
|
+
// Permanent forge-routing field, optional because only some forges need it:
|
|
4590
|
+
// GitLab routes check details to the MR's head pipeline; Gitea-family adapters
|
|
4591
|
+
// resolve the PR head SHA by number, including after merge/close. GitHub
|
|
4592
|
+
// ignores it.
|
|
4593
|
+
changeRequestNumber: z.number().int().positive().optional(),
|
|
3976
4594
|
requestId: z.string(),
|
|
3977
4595
|
});
|
|
4596
|
+
export const CheckoutForgeGetCheckDetailsRequestSchema = CheckoutCheckDetailsRequestPayloadSchema.extend({
|
|
4597
|
+
type: z.literal("checkout.forge.get_check_details.request"),
|
|
4598
|
+
});
|
|
4599
|
+
// COMPAT(githubCheckDetailsRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
4600
|
+
// all supported clients use checkout.forge.get_check_details.*.
|
|
4601
|
+
export const CheckoutGithubGetCheckDetailsRequestSchema = CheckoutCheckDetailsRequestPayloadSchema.extend({
|
|
4602
|
+
type: z.literal("checkout.github.get_check_details.request"),
|
|
4603
|
+
});
|
|
3978
4604
|
export const CheckoutPrStatusRequestSchema = z.object({
|
|
3979
4605
|
type: z.literal("checkout_pr_status_request"),
|
|
3980
4606
|
cwd: z.string(),
|
|
@@ -4063,17 +4689,41 @@ export const BranchSuggestionsRequestSchema = z.object({
|
|
|
4063
4689
|
});
|
|
4064
4690
|
export const GitHubSearchItemSchema = z.object({
|
|
4065
4691
|
kind: z.enum(["issue", "pr"]),
|
|
4692
|
+
forge: z.string().optional(),
|
|
4066
4693
|
number: z.number(),
|
|
4067
4694
|
title: z.string(),
|
|
4068
4695
|
url: z.string(),
|
|
4069
4696
|
state: z.string(),
|
|
4070
4697
|
body: z.string().nullable(),
|
|
4071
4698
|
labels: z.array(z.string()),
|
|
4699
|
+
projectPath: z.string().optional(),
|
|
4072
4700
|
baseRefName: z.string().nullable().optional(),
|
|
4073
4701
|
headRefName: z.string().nullable().optional(),
|
|
4074
4702
|
updatedAt: z.string().optional(),
|
|
4075
4703
|
});
|
|
4076
|
-
export const
|
|
4704
|
+
export const ForgeSearchItemSchema = GitHubSearchItemSchema.extend({
|
|
4705
|
+
kind: z.enum(["issue", "change_request"]),
|
|
4706
|
+
});
|
|
4707
|
+
// COMPAT(githubSearchKind): added in v0.1.106, remove with the legacy
|
|
4708
|
+
// github_search_request RPC after 2026-12-28.
|
|
4709
|
+
export const ForgeSearchKindSchema = z.enum([
|
|
4710
|
+
"issue",
|
|
4711
|
+
"change_request",
|
|
4712
|
+
"github-issue",
|
|
4713
|
+
"github-pr",
|
|
4714
|
+
"pr",
|
|
4715
|
+
]);
|
|
4716
|
+
export const GitHubSearchKindSchema = ForgeSearchKindSchema;
|
|
4717
|
+
export const ForgeSearchRequestSchema = z.object({
|
|
4718
|
+
type: z.literal("forge.search.request"),
|
|
4719
|
+
cwd: z.string(),
|
|
4720
|
+
query: z.string(),
|
|
4721
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
4722
|
+
kinds: z.array(ForgeSearchKindSchema).optional(),
|
|
4723
|
+
requestId: z.string(),
|
|
4724
|
+
});
|
|
4725
|
+
// COMPAT(githubSearchRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
4726
|
+
// clients use forge.search.*.
|
|
4077
4727
|
export const GitHubSearchRequestSchema = z.object({
|
|
4078
4728
|
type: z.literal("github_search_request"),
|
|
4079
4729
|
cwd: z.string(),
|
|
@@ -4094,7 +4744,7 @@ export const HostingSearchRequestSchema = z.object({
|
|
|
4094
4744
|
kinds: z.array(HostingSearchKindSchema).optional(),
|
|
4095
4745
|
requestId: z.string(),
|
|
4096
4746
|
});
|
|
4097
|
-
// Reports whether a host-level provider's credentials are valid
|
|
4747
|
+
// Reports whether a host-level provider's credentials are valid - drives the
|
|
4098
4748
|
// connection-status row in the host Git providers settings section.
|
|
4099
4749
|
export const HostingAuthStatusRequestSchema = z.object({
|
|
4100
4750
|
type: z.literal("hosting.auth_status.request"),
|
|
@@ -4154,6 +4804,9 @@ export const CreateOttoWorktreeRequestSchema = z.object({
|
|
|
4154
4804
|
firstAgentContext: FirstAgentContextSchema.optional(),
|
|
4155
4805
|
refName: z.string().min(1).optional(),
|
|
4156
4806
|
action: z.enum(["branch-off", "checkout"]).optional(),
|
|
4807
|
+
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
|
|
4808
|
+
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
|
|
4809
|
+
// clients send checkoutSource: { kind: "change_request", forge, number }.
|
|
4157
4810
|
githubPrNumber: z.number().int().positive().optional(),
|
|
4158
4811
|
requestId: z.string(),
|
|
4159
4812
|
});
|
|
@@ -4181,6 +4834,8 @@ export const OpenProjectRequestSchema = z.object({
|
|
|
4181
4834
|
cwd: z.string(),
|
|
4182
4835
|
requestId: z.string(),
|
|
4183
4836
|
});
|
|
4837
|
+
// Smallest shorthand repo path is "a/b": owner, slash, repository.
|
|
4838
|
+
const MIN_REPOSITORY_PATH_LENGTH = 3;
|
|
4184
4839
|
export const ProjectAddRequestSchema = z.object({
|
|
4185
4840
|
type: z.literal("project.add.request"),
|
|
4186
4841
|
cwd: z.string(),
|
|
@@ -4192,10 +4847,10 @@ export const ProjectAddRequestSchema = z.object({
|
|
|
4192
4847
|
// from a remote), optionally create that remote on a connected hosting
|
|
4193
4848
|
// provider, then register the result as a project. One RPC rather than a
|
|
4194
4849
|
// client-driven sequence so a half-finished project can never be left behind by
|
|
4195
|
-
// a dropped socket
|
|
4850
|
+
// a dropped socket - the daemon owns the whole transaction.
|
|
4196
4851
|
// COMPAT(projectScaffold): added in v0.6.9. Gated by server_info.features.projectScaffold.
|
|
4197
4852
|
// Built-in .gitignore starters. Deliberately a short list of the ecosystems Otto
|
|
4198
|
-
// itself works in
|
|
4853
|
+
// itself works in - this is a convenience, not a mirror of github/gitignore. The
|
|
4199
4854
|
// wire field stays an open string so a newer daemon can add one without an older
|
|
4200
4855
|
// client's validator rejecting the message.
|
|
4201
4856
|
export const PROJECT_SCAFFOLD_GITIGNORE_TEMPLATE_IDS = [
|
|
@@ -4276,12 +4931,41 @@ export const HostingListOwnersRequestSchema = z.object({
|
|
|
4276
4931
|
provider: GitHostingProviderIdWireSchema,
|
|
4277
4932
|
requestId: z.string(),
|
|
4278
4933
|
});
|
|
4934
|
+
export const ProjectCreateDirectoryRequestSchema = z.object({
|
|
4935
|
+
type: z.literal("project.create_directory.request"),
|
|
4936
|
+
parentPath: z.string(),
|
|
4937
|
+
name: z.string(),
|
|
4938
|
+
requestId: z.string(),
|
|
4939
|
+
});
|
|
4940
|
+
export const GithubRepositorySchema = z.object({
|
|
4941
|
+
id: z.string().min(1),
|
|
4942
|
+
name: z.string().min(1),
|
|
4943
|
+
nameWithOwner: z.string().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
4944
|
+
description: z.string().nullable(),
|
|
4945
|
+
visibility: z.enum(["public", "private", "internal"]),
|
|
4946
|
+
updatedAt: z.string(),
|
|
4947
|
+
cloneUrl: z.string().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
4948
|
+
});
|
|
4949
|
+
export const WorkspaceGithubSearchRepositoriesRequestSchema = z.object({
|
|
4950
|
+
type: z.literal("workspace.github.search_repositories.request"),
|
|
4951
|
+
query: z.string(),
|
|
4952
|
+
limit: z.number().int().min(1).max(50).optional(),
|
|
4953
|
+
requestId: z.string(),
|
|
4954
|
+
});
|
|
4955
|
+
export const ProjectGithubCloneProtocolSchema = z.enum(["https", "ssh"]);
|
|
4956
|
+
export const ProjectGithubCloneRequestSchema = z.object({
|
|
4957
|
+
type: z.literal("project.github.clone.request"),
|
|
4958
|
+
repo: z.string().trim().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
4959
|
+
cloneProtocol: ProjectGithubCloneProtocolSchema.optional(),
|
|
4960
|
+
targetDirectory: z.string().trim().min(1),
|
|
4961
|
+
requestId: z.string(),
|
|
4962
|
+
});
|
|
4279
4963
|
export const ArchiveWorkspaceRequestSchema = z.object({
|
|
4280
4964
|
type: z.literal("archive_workspace_request"),
|
|
4281
4965
|
workspaceId: z.string(),
|
|
4282
4966
|
requestId: z.string(),
|
|
4283
4967
|
// COMPAT(worktreeArchiveBranchCleanup): added in v0.6.7, drop the optional
|
|
4284
|
-
// gate when daemon floor >= v0.6.7. Absent means "keep"
|
|
4968
|
+
// gate when daemon floor >= v0.6.7. Absent means "keep" - the leftover local
|
|
4285
4969
|
// branch is never touched (old-client behavior). "delete" asks the daemon to
|
|
4286
4970
|
// remove the worktree's local branch after the backing directory is torn down
|
|
4287
4971
|
// (only when this was the last reference to it and the branch is not checked
|
|
@@ -4303,7 +4987,7 @@ export const WorkspaceArchivePreflightRequestSchema = z.object({
|
|
|
4303
4987
|
// record the answer, and it has to look like one or a wrong guess reads as a bug in the diff.
|
|
4304
4988
|
// COMPAT(checkoutDiffBaseAnyRepo): added in v0.7.4.
|
|
4305
4989
|
export const CheckoutBaseSourceSchema = z.enum(["user", "inferred", "worktree", "default"]);
|
|
4306
|
-
// Repoint a worktree-backed workspace's base branch
|
|
4990
|
+
// Repoint a worktree-backed workspace's base branch - what the Changes view diffs
|
|
4307
4991
|
// against, and what merge-into-base and PR creation target. On a stacked branch the
|
|
4308
4992
|
// useful base is the parent branch, not the repo default, the same way a forge PR
|
|
4309
4993
|
// carries an explicit base. A null baseRef resets to the repository default branch.
|
|
@@ -4313,7 +4997,7 @@ export const WorktreeBaseRefSetRequestSchema = z.object({
|
|
|
4313
4997
|
requestId: z.string(),
|
|
4314
4998
|
workspaceId: z.string(),
|
|
4315
4999
|
// Branch name; null resets to the default branch. An `origin/` prefix is meaningful and is
|
|
4316
|
-
// kept
|
|
5000
|
+
// kept - `main` and `origin/main` are different comparisons whenever the two have drifted.
|
|
4317
5001
|
baseRef: z.string().nullable(),
|
|
4318
5002
|
// Forget the remembered base and detect the branch's parent again, ignoring `baseRef`.
|
|
4319
5003
|
// The escape hatch for a wrong guess: parent detection is a heuristic over a graph that does
|
|
@@ -4350,6 +5034,11 @@ export const WorkspaceCreateRequestSchema = z.object({
|
|
|
4350
5034
|
// the repository default.
|
|
4351
5035
|
refName: z.string().min(1).optional(),
|
|
4352
5036
|
baseBranch: z.string().optional(),
|
|
5037
|
+
// New branch name for branch-off. The worktree path may use a different slug.
|
|
5038
|
+
branchName: z.string().min(1).optional(),
|
|
5039
|
+
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
|
|
5040
|
+
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
|
|
5041
|
+
// clients send checkoutSource.
|
|
4353
5042
|
githubPrNumber: z.number().int().positive().optional(),
|
|
4354
5043
|
worktreeSlug: z.string().optional(),
|
|
4355
5044
|
}),
|
|
@@ -4439,6 +5128,7 @@ const FileExplorerFileSchema = z.object({
|
|
|
4439
5128
|
// inline JSON read path only); old daemons omit both fields.
|
|
4440
5129
|
eol: FileEolSchema.optional(),
|
|
4441
5130
|
hash: z.string().optional(),
|
|
5131
|
+
revision: z.string().optional(),
|
|
4442
5132
|
});
|
|
4443
5133
|
const FileExplorerDirectorySchema = z.object({
|
|
4444
5134
|
path: z.string(),
|
|
@@ -4452,6 +5142,103 @@ export const FileExplorerRequestSchema = z.object({
|
|
|
4452
5142
|
requestId: z.string(),
|
|
4453
5143
|
acceptBinary: z.boolean().optional(),
|
|
4454
5144
|
});
|
|
5145
|
+
export const FileVersionSchema = z.discriminatedUnion("status", [
|
|
5146
|
+
z.object({
|
|
5147
|
+
status: z.literal("ready"),
|
|
5148
|
+
cwd: z.string(),
|
|
5149
|
+
path: z.string(),
|
|
5150
|
+
size: z.number().int().nonnegative(),
|
|
5151
|
+
modifiedAt: z.string(),
|
|
5152
|
+
revision: z.string().optional(),
|
|
5153
|
+
}),
|
|
5154
|
+
z.object({
|
|
5155
|
+
status: z.literal("missing"),
|
|
5156
|
+
cwd: z.string(),
|
|
5157
|
+
path: z.string(),
|
|
5158
|
+
}),
|
|
5159
|
+
z.object({
|
|
5160
|
+
status: z.literal("error"),
|
|
5161
|
+
cwd: z.string(),
|
|
5162
|
+
path: z.string(),
|
|
5163
|
+
error: z.string(),
|
|
5164
|
+
}),
|
|
5165
|
+
]);
|
|
5166
|
+
export const FileSubscribeRequestSchema = z.object({
|
|
5167
|
+
type: z.literal("fs.file.subscribe.request"),
|
|
5168
|
+
cwd: z.string(),
|
|
5169
|
+
path: z.string(),
|
|
5170
|
+
subscriptionId: z.string(),
|
|
5171
|
+
requestId: z.string(),
|
|
5172
|
+
});
|
|
5173
|
+
export const FileUnsubscribeRequestSchema = z.object({
|
|
5174
|
+
type: z.literal("fs.file.unsubscribe.request"),
|
|
5175
|
+
subscriptionId: z.string(),
|
|
5176
|
+
requestId: z.string(),
|
|
5177
|
+
});
|
|
5178
|
+
export const FsFileWriteRequestSchema = z.object({
|
|
5179
|
+
type: z.literal("fs.file.write.request"),
|
|
5180
|
+
cwd: z.string(),
|
|
5181
|
+
path: z.string(),
|
|
5182
|
+
content: z.string(),
|
|
5183
|
+
expectedModifiedAt: z.string(),
|
|
5184
|
+
expectedRevision: z.string().optional(),
|
|
5185
|
+
requestId: z.string(),
|
|
5186
|
+
});
|
|
5187
|
+
/**
|
|
5188
|
+
* Write bytes to a workspace file.
|
|
5189
|
+
*
|
|
5190
|
+
* The counterpart to `fs.file.write`, which is text only: it LF-normalizes,
|
|
5191
|
+
* re-applies the file's detected EOL, and outright refuses to overwrite a file
|
|
5192
|
+
* whose current bytes look binary. None of that can carry a PDF, an image or
|
|
5193
|
+
* any other generated artifact, so those go through here instead - the bytes
|
|
5194
|
+
* land verbatim.
|
|
5195
|
+
*
|
|
5196
|
+
* Deliberately not a conditional write. Callers are producing a generated file
|
|
5197
|
+
* from a source they already hold, so there is no "the file changed under you"
|
|
5198
|
+
* to reconcile: either the caller means to replace what is there or it does
|
|
5199
|
+
* not, and `overwrite` says which. Keeping that explicit is what stops this
|
|
5200
|
+
* from being a clobber-any-path primitive.
|
|
5201
|
+
*
|
|
5202
|
+
* Workspace-bounded, like the create/delete/rename surface and unlike
|
|
5203
|
+
* `file.write`. `file.write` is unbounded because a tab may edit a file the
|
|
5204
|
+
* user opened from anywhere; putting new bytes at an arbitrary path on the host
|
|
5205
|
+
* is a different power and does not need to be that wide.
|
|
5206
|
+
*
|
|
5207
|
+
* The bytes themselves do not ride in this message. They follow it as
|
|
5208
|
+
* `FileTransfer` binary frames correlated on `requestId` - FileBegin, then
|
|
5209
|
+
* FileChunk, then FileEnd - the same transport `file.upload` uses. This request
|
|
5210
|
+
* is the metadata half: where the bytes go and how many of them to expect.
|
|
5211
|
+
* Everything here writes multi-megabyte files (a printed PDF, a dropped image),
|
|
5212
|
+
* and base64 in a JSON message costs a third again on the wire plus the whole
|
|
5213
|
+
* encoded string allocated on both sides and walked by the validator.
|
|
5214
|
+
*/
|
|
5215
|
+
export const FsFileWriteBinaryRequestSchema = z.object({
|
|
5216
|
+
type: z.literal("fs.file.write_binary.request"),
|
|
5217
|
+
cwd: z.string(),
|
|
5218
|
+
path: z.string(),
|
|
5219
|
+
/**
|
|
5220
|
+
* Byte length of the payload to follow. The daemon refuses a transfer that
|
|
5221
|
+
* overruns it and refuses one that ends short, so a truncated stream fails
|
|
5222
|
+
* loudly instead of landing a half file. Optional only because the base64
|
|
5223
|
+
* form below predates it and carries its own length.
|
|
5224
|
+
*/
|
|
5225
|
+
size: z.number().int().nonnegative().optional(),
|
|
5226
|
+
/**
|
|
5227
|
+
* base64. Decoded and written as-is: no EOL translation, no re-encoding.
|
|
5228
|
+
*
|
|
5229
|
+
* COMPAT(binaryWriteBase64): added in v0.7.6, drop this field and its daemon
|
|
5230
|
+
* branch on 2027-02-02. Superseded by `size` plus file-transfer frames. The
|
|
5231
|
+
* daemon still reads it - a field we stopped sending is not a field we stop
|
|
5232
|
+
* accepting - and picks the branch from which of the two is present.
|
|
5233
|
+
*/
|
|
5234
|
+
contentBase64: z.string().optional(),
|
|
5235
|
+
/**
|
|
5236
|
+
* Replace an existing file. Absent (the default) an existing target comes
|
|
5237
|
+
* back as `exists` and nothing is written.
|
|
5238
|
+
*/
|
|
5239
|
+
overwrite: z.boolean().optional(),
|
|
5240
|
+
requestId: z.string(),
|
|
5241
|
+
});
|
|
4455
5242
|
export const ProjectIconRequestSchema = z.object({
|
|
4456
5243
|
type: z.literal("project_icon_request"),
|
|
4457
5244
|
cwd: z.string(),
|
|
@@ -4474,7 +5261,7 @@ export const FileUploadRequestSchema = z.object({
|
|
|
4474
5261
|
/**
|
|
4475
5262
|
* Text-editor save. A conditional write: the request carries the client's
|
|
4476
5263
|
* last-known file identity and the daemon refuses to clobber content it did
|
|
4477
|
-
* not hand out
|
|
5264
|
+
* not hand out - a mismatch comes back as a typed conflict, never a write.
|
|
4478
5265
|
*/
|
|
4479
5266
|
export const FileWriteRequestSchema = z.object({
|
|
4480
5267
|
type: z.literal("file.write.request"),
|
|
@@ -4512,7 +5299,7 @@ export const FileCreateRequestSchema = z.object({
|
|
|
4512
5299
|
requestId: z.string(),
|
|
4513
5300
|
});
|
|
4514
5301
|
/**
|
|
4515
|
-
* Permanent delete
|
|
5302
|
+
* Permanent delete - an unlink, not a move to the OS trash. The daemon may be
|
|
4516
5303
|
* headless, remote, or inside WSL, where there is no reliable trash to move to;
|
|
4517
5304
|
* a "deleted" file that silently stayed on disk in one environment and vanished
|
|
4518
5305
|
* in another would be worse than either. The client's confirmation says so.
|
|
@@ -4528,7 +5315,7 @@ export const FileDeleteRequestSchema = z.object({
|
|
|
4528
5315
|
requestId: z.string(),
|
|
4529
5316
|
});
|
|
4530
5317
|
/**
|
|
4531
|
-
* Rename and move are the same operation
|
|
5318
|
+
* Rename and move are the same operation - a move is a rename whose new path
|
|
4532
5319
|
* has a different parent. Never clobbers: an occupied destination comes back as
|
|
4533
5320
|
* `exists` and nothing moves. There is no overwrite flag on purpose, so this
|
|
4534
5321
|
* RPC cannot destroy a file the user did not name.
|
|
@@ -4541,7 +5328,7 @@ export const FileRenameRequestSchema = z.object({
|
|
|
4541
5328
|
requestId: z.string(),
|
|
4542
5329
|
});
|
|
4543
5330
|
/**
|
|
4544
|
-
* Refine
|
|
5331
|
+
* Refine - an AI rewrite the user reviews as a diff before anything is written.
|
|
4545
5332
|
* This RPC only *proposes*: it reads nothing from disk and writes nothing. The
|
|
4546
5333
|
* accepted result goes back through `file.write.request` like any other save,
|
|
4547
5334
|
* so the conditional-write precondition still guards it.
|
|
@@ -4569,7 +5356,7 @@ export const FileRefineReferenceSchema = z.object({
|
|
|
4569
5356
|
});
|
|
4570
5357
|
export const FileRefineRequestSchema = z.object({
|
|
4571
5358
|
type: z.literal("file.refine.request"),
|
|
4572
|
-
// Provider resolution only
|
|
5359
|
+
// Provider resolution only - which workspace's mini-task chain runs this.
|
|
4573
5360
|
// Documents are NOT read from disk here; they travel on the wire.
|
|
4574
5361
|
cwd: z.string(),
|
|
4575
5362
|
// What the model may rewrite. The blast radius of the whole request: a file
|
|
@@ -4690,7 +5477,7 @@ export const CodeRenamePreviewRequestSchema = z.object({
|
|
|
4690
5477
|
*
|
|
4691
5478
|
* The client sends back only the `planId` it was shown; the daemon recomputes the plan and
|
|
4692
5479
|
* refuses unless the identity matches. A request that carried its own edit list would be a
|
|
4693
|
-
* remote arbitrary-write primitive wearing a rename's name
|
|
5480
|
+
* remote arbitrary-write primitive wearing a rename's name - any client could post any text
|
|
4694
5481
|
* at any path. This shape makes the daemon's own language server the sole author of what
|
|
4695
5482
|
* gets written, and the plan id the proof that the user saw it.
|
|
4696
5483
|
*/
|
|
@@ -4706,7 +5493,7 @@ export const CodeRenameApplyRequestSchema = z.object({
|
|
|
4706
5493
|
requestId: z.string(),
|
|
4707
5494
|
});
|
|
4708
5495
|
/**
|
|
4709
|
-
* Undo a run. Carries only the run's id
|
|
5496
|
+
* Undo a run. Carries only the run's id - the daemon holds the before-images.
|
|
4710
5497
|
*
|
|
4711
5498
|
* Declared here, with the other inbound rename schemas, rather than beside its response
|
|
4712
5499
|
* further down: `SessionInboundMessageSchema` is a top-level const, so a schema it names
|
|
@@ -4750,8 +5537,8 @@ export const LspServerStopRequestSchema = z.object({
|
|
|
4750
5537
|
* as the build system sees it rather than as the filesystem lays it out.
|
|
4751
5538
|
*
|
|
4752
5539
|
* **Independent of the LSP family above, despite sharing the `code.` domain.** There is no
|
|
4753
|
-
* project-structure request in the Language Server Protocol
|
|
4754
|
-
* that does not exist
|
|
5540
|
+
* project-structure request in the Language Server Protocol - not one Otto has yet to wire, one
|
|
5541
|
+
* that does not exist - so this subsystem builds its own model through Microsoft's solution
|
|
4755
5542
|
* libraries. Turning C# code intelligence off does not turn this off, and vice versa.
|
|
4756
5543
|
*
|
|
4757
5544
|
* Discovery is separate from loading on purpose: `list` decides whether the switcher appears at
|
|
@@ -4767,7 +5554,7 @@ export const CodeSolutionListRequestSchema = z.object({
|
|
|
4767
5554
|
});
|
|
4768
5555
|
/**
|
|
4769
5556
|
* One solution's organisation: folders, the projects inside them, and the configurations. No file
|
|
4770
|
-
* membership
|
|
5557
|
+
* membership - that is `load_project`, paid per project on expand, because evaluating fifty
|
|
4771
5558
|
* projects to render a collapsed tree is the cost this design exists to avoid.
|
|
4772
5559
|
*/
|
|
4773
5560
|
export const CodeSolutionGetTreeRequestSchema = z.object({
|
|
@@ -4779,7 +5566,7 @@ export const CodeSolutionGetTreeRequestSchema = z.object({
|
|
|
4779
5566
|
});
|
|
4780
5567
|
/**
|
|
4781
5568
|
* One project's evaluated file membership. `solutionPath` scopes the sidecar instance so two
|
|
4782
|
-
* solutions in one repo never share a warm `ProjectCollection`
|
|
5569
|
+
* solutions in one repo never share a warm `ProjectCollection` - and so Phase 4 has the selection
|
|
4783
5570
|
* it needs for `--solution`.
|
|
4784
5571
|
*/
|
|
4785
5572
|
export const CodeSolutionLoadProjectRequestSchema = z.object({
|
|
@@ -4817,7 +5604,7 @@ const FileReplaceMatchSchema = z.object({
|
|
|
4817
5604
|
});
|
|
4818
5605
|
/**
|
|
4819
5606
|
* Preview-first project replace. Each file carries the hash the preview was
|
|
4820
|
-
* built against
|
|
5607
|
+
* built against - files changed since are skipped and reported, never
|
|
4821
5608
|
* corrupted. The replacement string is literal (no capture references in v1).
|
|
4822
5609
|
*/
|
|
4823
5610
|
export const FileReplaceRequestSchema = z.object({
|
|
@@ -4901,6 +5688,16 @@ export const CreateTerminalRequestSchema = z.object({
|
|
|
4901
5688
|
agentId: z.string().optional(),
|
|
4902
5689
|
command: z.string().optional(),
|
|
4903
5690
|
args: z.array(z.string()).optional(),
|
|
5691
|
+
// Initial PTY size. Added in v0.1.107; the app no longer sends it (the estimate cache that fed
|
|
5692
|
+
// it was removed - the pane-focus resize claim sizes the PTY instead). Kept and honored
|
|
5693
|
+
// permanently: released v0.1.107 clients still send it, and programmatic callers may pass an
|
|
5694
|
+
// exact size. Daemons without it start at 80x24 and the first resize corrects that.
|
|
5695
|
+
size: z
|
|
5696
|
+
.object({
|
|
5697
|
+
rows: z.number().int().positive(),
|
|
5698
|
+
cols: z.number().int().positive(),
|
|
5699
|
+
})
|
|
5700
|
+
.optional(),
|
|
4904
5701
|
requestId: z.string(),
|
|
4905
5702
|
});
|
|
4906
5703
|
export const RenameTerminalRequestSchema = z.object({
|
|
@@ -4915,6 +5712,31 @@ export const StartWorkspaceScriptRequestSchema = z.object({
|
|
|
4915
5712
|
scriptName: z.string(),
|
|
4916
5713
|
requestId: z.string(),
|
|
4917
5714
|
});
|
|
5715
|
+
export const WorkspaceScriptListRequestSchema = z.object({
|
|
5716
|
+
type: z.literal("workspace.script.list.request"),
|
|
5717
|
+
workspaceId: z.string(),
|
|
5718
|
+
requestId: z.string(),
|
|
5719
|
+
/**
|
|
5720
|
+
* Also return the Scripts the workspace's own project files declare
|
|
5721
|
+
* (`package.json` scripts, and later Makefile targets, .NET launch profiles),
|
|
5722
|
+
* each tagged with the `source` it came from. Off by default so a client that
|
|
5723
|
+
* predates discovery gets exactly the otto.json list it asked for.
|
|
5724
|
+
* COMPAT(workspaceScriptDiscovery): added in v0.7.6.
|
|
5725
|
+
*/
|
|
5726
|
+
includeDiscovered: z.boolean().optional().default(false),
|
|
5727
|
+
});
|
|
5728
|
+
export const WorkspaceScriptStartRequestSchema = z.object({
|
|
5729
|
+
type: z.literal("workspace.script.start.request"),
|
|
5730
|
+
workspaceId: z.string(),
|
|
5731
|
+
scriptName: z.string(),
|
|
5732
|
+
requestId: z.string(),
|
|
5733
|
+
});
|
|
5734
|
+
export const WorkspaceScriptStopRequestSchema = z.object({
|
|
5735
|
+
type: z.literal("workspace.script.stop.request"),
|
|
5736
|
+
workspaceId: z.string(),
|
|
5737
|
+
scriptName: z.string(),
|
|
5738
|
+
requestId: z.string(),
|
|
5739
|
+
});
|
|
4918
5740
|
export const SubscribeTerminalRequestSchema = z.object({
|
|
4919
5741
|
type: z.literal("subscribe_terminal_request"),
|
|
4920
5742
|
terminalId: z.string(),
|
|
@@ -4957,15 +5779,39 @@ export const KillTerminalRequestSchema = z.object({
|
|
|
4957
5779
|
terminalId: z.string(),
|
|
4958
5780
|
requestId: z.string(),
|
|
4959
5781
|
});
|
|
4960
|
-
export const CaptureTerminalRequestSchema = z.object({
|
|
4961
|
-
type: z.literal("capture_terminal_request"),
|
|
4962
|
-
terminalId: z.string(),
|
|
4963
|
-
start: z.number().int().optional(),
|
|
4964
|
-
end: z.number().int().optional(),
|
|
4965
|
-
stripAnsi: z.boolean().default(true),
|
|
5782
|
+
export const CaptureTerminalRequestSchema = z.object({
|
|
5783
|
+
type: z.literal("capture_terminal_request"),
|
|
5784
|
+
terminalId: z.string(),
|
|
5785
|
+
start: z.number().int().optional(),
|
|
5786
|
+
end: z.number().int().optional(),
|
|
5787
|
+
stripAnsi: z.boolean().default(true),
|
|
5788
|
+
requestId: z.string(),
|
|
5789
|
+
});
|
|
5790
|
+
export const HubExecutionAgentCreateRequestSchema = z.object({
|
|
5791
|
+
type: z.literal("hub.execution.agent.create.request"),
|
|
5792
|
+
requestId: z.string(),
|
|
5793
|
+
executionId: z.string(),
|
|
5794
|
+
provider: z.string(),
|
|
5795
|
+
cwd: z.string(),
|
|
5796
|
+
prompt: z.string(),
|
|
5797
|
+
workspaceId: z.string().optional(),
|
|
5798
|
+
model: z.string().optional(),
|
|
5799
|
+
modeId: z.string().optional(),
|
|
5800
|
+
thinkingOptionId: z.string().optional(),
|
|
5801
|
+
featureValues: z.record(z.string(), z.unknown()).optional(),
|
|
5802
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
5803
|
+
worktree: CreateAgentWorktreeTargetSchema.optional(),
|
|
5804
|
+
});
|
|
5805
|
+
export const HubExecutionControlActionSchema = z.enum(["interrupt", "archive"]);
|
|
5806
|
+
export const HubExecutionControlRequestSchema = z.object({
|
|
5807
|
+
type: z.literal("hub.execution.control.request"),
|
|
4966
5808
|
requestId: z.string(),
|
|
5809
|
+
executionId: z.string(),
|
|
5810
|
+
action: HubExecutionControlActionSchema,
|
|
4967
5811
|
});
|
|
4968
5812
|
export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
5813
|
+
HubExecutionAgentCreateRequestSchema,
|
|
5814
|
+
HubExecutionControlRequestSchema,
|
|
4969
5815
|
BrowserAutomationExecuteResponseSchema,
|
|
4970
5816
|
VoiceAudioChunkMessageSchema,
|
|
4971
5817
|
AbortRequestMessageSchema,
|
|
@@ -4974,6 +5820,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
4974
5820
|
FetchAgentHistoryRequestMessageSchema,
|
|
4975
5821
|
FetchRecentProviderSessionsRequestMessageSchema,
|
|
4976
5822
|
FetchWorkspacesRequestMessageSchema,
|
|
5823
|
+
ProjectListRequestMessageSchema,
|
|
4977
5824
|
FetchAgentRequestMessageSchema,
|
|
4978
5825
|
DeleteAgentRequestMessageSchema,
|
|
4979
5826
|
ArchiveAgentRequestMessageSchema,
|
|
@@ -5003,6 +5850,14 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5003
5850
|
BrainHfSearchRequestSchema,
|
|
5004
5851
|
BrainHfQuantsRequestSchema,
|
|
5005
5852
|
BrainModelsAddRequestSchema,
|
|
5853
|
+
BrainModelsInventoryRequestSchema,
|
|
5854
|
+
BrainModelProfileGetRequestSchema,
|
|
5855
|
+
BrainModelProfileSetRequestSchema,
|
|
5856
|
+
BrainModelBudgetGetRequestSchema,
|
|
5857
|
+
BrainModelLoadRequestSchema,
|
|
5858
|
+
BrainModelUnloadRequestSchema,
|
|
5859
|
+
BrainModelDeleteRequestSchema,
|
|
5860
|
+
BrainLogsTailRequestSchema,
|
|
5006
5861
|
UpdateAgentRequestMessageSchema,
|
|
5007
5862
|
ProjectRenameRequestSchema,
|
|
5008
5863
|
ProjectRemoveRequestSchema,
|
|
@@ -5010,15 +5865,23 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5010
5865
|
ProjectLinksSetRequestSchema,
|
|
5011
5866
|
ProjectLinksUnsetRequestSchema,
|
|
5012
5867
|
WorkspaceTitleSetRequestSchema,
|
|
5868
|
+
WorkspacePinSetRequestSchema,
|
|
5869
|
+
WorkspaceRecoveryInspectRequestSchema,
|
|
5870
|
+
WorkspaceRecoveryRestoreRequestSchema,
|
|
5013
5871
|
SetVoiceModeMessageSchema,
|
|
5014
5872
|
SendAgentMessageRequestSchema,
|
|
5015
5873
|
WaitForFinishRequestSchema,
|
|
5016
5874
|
DaemonGetStatusRequestSchema,
|
|
5017
5875
|
DaemonGetPairingOfferRequestSchema,
|
|
5876
|
+
HubManagementDaemonConnectRequestSchema,
|
|
5877
|
+
HubManagementDaemonGetStatusRequestSchema,
|
|
5878
|
+
HubManagementDaemonDisconnectRequestSchema,
|
|
5018
5879
|
DiagnosticsRequestSchema,
|
|
5019
5880
|
GetDaemonConfigRequestMessageSchema,
|
|
5020
5881
|
SetDaemonConfigRequestMessageSchema,
|
|
5021
5882
|
ConnectorsListToolsRequestSchema,
|
|
5883
|
+
ConnectorsOauthAuthorizeRequestSchema,
|
|
5884
|
+
ConnectorsOauthDisconnectRequestSchema,
|
|
5022
5885
|
SpeechSettingsGetOptionsRequestSchema,
|
|
5023
5886
|
SpeechTtsPreviewRequestSchema,
|
|
5024
5887
|
SpeechTtsSpeakRequestSchema,
|
|
@@ -5061,6 +5924,9 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5061
5924
|
RestartServerRequestMessageSchema,
|
|
5062
5925
|
DaemonUpdateRequestMessageSchema,
|
|
5063
5926
|
FetchAgentTimelineRequestMessageSchema,
|
|
5927
|
+
ProviderSubagentListRequestMessageSchema,
|
|
5928
|
+
ProviderSubagentTimelineRequestMessageSchema,
|
|
5929
|
+
SetAgentTimelineSubscriptionRequestMessageSchema,
|
|
5064
5930
|
AgentForkContextRequestMessageSchema,
|
|
5065
5931
|
SetAgentModeRequestMessageSchema,
|
|
5066
5932
|
SetAgentModelRequestMessageSchema,
|
|
@@ -5110,7 +5976,11 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5110
5976
|
CheckoutRefreshRequestSchema,
|
|
5111
5977
|
CheckoutPrCreateRequestSchema,
|
|
5112
5978
|
CheckoutPrMergeRequestSchema,
|
|
5979
|
+
CheckoutForgeSetAutoMergeRequestSchema,
|
|
5113
5980
|
CheckoutGithubSetAutoMergeRequestSchema,
|
|
5981
|
+
CheckoutCommitsListRequestSchema,
|
|
5982
|
+
CheckoutCommitFileDiffRequestSchema,
|
|
5983
|
+
CheckoutForgeGetCheckDetailsRequestSchema,
|
|
5114
5984
|
CheckoutGithubGetCheckDetailsRequestSchema,
|
|
5115
5985
|
PreviewListConfigRequestSchema,
|
|
5116
5986
|
PreviewStartRequestSchema,
|
|
@@ -5125,6 +5995,7 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5125
5995
|
StashListRequestSchema,
|
|
5126
5996
|
ValidateBranchRequestSchema,
|
|
5127
5997
|
BranchSuggestionsRequestSchema,
|
|
5998
|
+
ForgeSearchRequestSchema,
|
|
5128
5999
|
GitHubSearchRequestSchema,
|
|
5129
6000
|
HostingSearchRequestSchema,
|
|
5130
6001
|
HostingAuthStatusRequestSchema,
|
|
@@ -5140,6 +6011,9 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5140
6011
|
ProjectScaffoldRequestSchema,
|
|
5141
6012
|
HostingListRepositoriesRequestSchema,
|
|
5142
6013
|
HostingListOwnersRequestSchema,
|
|
6014
|
+
ProjectCreateDirectoryRequestSchema,
|
|
6015
|
+
WorkspaceGithubSearchRepositoriesRequestSchema,
|
|
6016
|
+
ProjectGithubCloneRequestSchema,
|
|
5143
6017
|
ArchiveWorkspaceRequestSchema,
|
|
5144
6018
|
WorkspaceArchivePreflightRequestSchema,
|
|
5145
6019
|
WorktreeBaseRefSetRequestSchema,
|
|
@@ -5148,6 +6022,10 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5148
6022
|
WorkspaceCreateRequestSchema,
|
|
5149
6023
|
WorkspaceClearAttentionRequestSchema,
|
|
5150
6024
|
FileExplorerRequestSchema,
|
|
6025
|
+
FileSubscribeRequestSchema,
|
|
6026
|
+
FileUnsubscribeRequestSchema,
|
|
6027
|
+
FsFileWriteRequestSchema,
|
|
6028
|
+
FsFileWriteBinaryRequestSchema,
|
|
5151
6029
|
ProjectIconRequestSchema,
|
|
5152
6030
|
FileDownloadTokenRequestSchema,
|
|
5153
6031
|
FileUploadRequestSchema,
|
|
@@ -5187,6 +6065,9 @@ export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
5187
6065
|
CreateTerminalRequestSchema,
|
|
5188
6066
|
RenameTerminalRequestSchema,
|
|
5189
6067
|
StartWorkspaceScriptRequestSchema,
|
|
6068
|
+
WorkspaceScriptListRequestSchema,
|
|
6069
|
+
WorkspaceScriptStartRequestSchema,
|
|
6070
|
+
WorkspaceScriptStopRequestSchema,
|
|
5190
6071
|
SubscribeTerminalRequestSchema,
|
|
5191
6072
|
UnsubscribeTerminalRequestSchema,
|
|
5192
6073
|
TerminalInputSchema,
|
|
@@ -5361,14 +6242,23 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5361
6242
|
serverId: z.string().trim().min(1),
|
|
5362
6243
|
hostname: ServerInfoHostnameSchema.optional(),
|
|
5363
6244
|
version: ServerInfoVersionSchema.optional(),
|
|
6245
|
+
// COMPAT(desktopManaged): added in v0.1.X, remove optional parsing after 2027-01-16.
|
|
6246
|
+
desktopManaged: z.boolean().optional(),
|
|
5364
6247
|
capabilities: ServerCapabilitiesFromUnknownSchema.optional(),
|
|
5365
6248
|
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
|
|
5366
6249
|
features: z
|
|
5367
6250
|
.object({
|
|
5368
6251
|
providersSnapshot: z.boolean().optional(),
|
|
6252
|
+
// COMPAT(checkoutForgeSetAutoMerge): added in v0.1.106, remove old
|
|
6253
|
+
// checkoutGithubSetAutoMerge fallback after 2026-12-28.
|
|
6254
|
+
checkoutForgeSetAutoMerge: z.boolean().optional(),
|
|
5369
6255
|
checkoutGithubSetAutoMerge: z.boolean().optional(),
|
|
5370
6256
|
// COMPAT(githubCheckDetails): added in v0.1.92, remove gate after 2026-12-08.
|
|
5371
6257
|
githubCheckDetails: z.boolean().optional(),
|
|
6258
|
+
// COMPAT(forgeCheckDetails): added in v0.1.106, remove githubCheckDetails fallback after 2026-12-28.
|
|
6259
|
+
forgeCheckDetails: z.boolean().optional(),
|
|
6260
|
+
// COMPAT(forgeSearch): added in v0.1.106, remove github_search fallback after 2026-12-28.
|
|
6261
|
+
forgeSearch: z.boolean().optional(),
|
|
5372
6262
|
// COMPAT(daemonStatusRpc): added in v0.1.76, remove gate after 2026-11-18.
|
|
5373
6263
|
daemonStatusRpc: z.boolean().optional(),
|
|
5374
6264
|
// COMPAT(terminalRestoreModes): added in v0.1.81, remove gate after 2026-11-23.
|
|
@@ -5391,10 +6281,16 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5391
6281
|
projectScaffold: z.boolean().optional(),
|
|
5392
6282
|
// COMPAT(worktreeRestore): added in v0.1.97, drop the gate when floor >= v0.1.97
|
|
5393
6283
|
worktreeRestore: z.boolean().optional(),
|
|
6284
|
+
// COMPAT(workspaceRecovery): added in v0.1.105, remove after 2027-01-11 once daemon floor >= v0.1.105.
|
|
6285
|
+
workspaceRecovery: z.boolean().optional(),
|
|
6286
|
+
// COMPAT(workspaceFileEditing): added in v0.2.0, remove after 2027-01-18 once daemon floor >= v0.2.0.
|
|
6287
|
+
workspaceFileEditing: z.boolean().optional(),
|
|
5394
6288
|
// COMPAT(providerUsageList): added in v0.1.98, drop the gate when daemon floor >= v0.1.98.
|
|
5395
6289
|
providerUsageList: z.boolean().optional(),
|
|
5396
6290
|
// COMPAT(agentDetach): added in v0.1.98, remove gate after 2026-12-19 once daemon floor >= v0.1.98.
|
|
5397
6291
|
agentDetach: z.boolean().optional(),
|
|
6292
|
+
// COMPAT(agentThinkingUpdate): added in v0.2.4, remove gate after 2027-01-28.
|
|
6293
|
+
agentThinkingUpdate: z.boolean().optional(),
|
|
5398
6294
|
// COMPAT(daemonDiagnostics): added in v0.1.100, remove gate after 2026-12-25 once daemon floor >= v0.1.100.
|
|
5399
6295
|
daemonDiagnostics: z.boolean().optional(),
|
|
5400
6296
|
// COMPAT(daemonSelfUpdate): added in v0.1.93, remove gate after 2026-12-13.
|
|
@@ -5434,6 +6330,16 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5434
6330
|
// Without it the Brain "Models" section hides the Hugging Face search box.
|
|
5435
6331
|
// COMPAT(brainHfSearch): added in v0.7.5, remove gate after 2026-07-30 once daemon floor >= v0.7.5.
|
|
5436
6332
|
brainHfSearch: z.boolean().optional(),
|
|
6333
|
+
// Daemon proxies the brain's own /__host/* management API: the joined
|
|
6334
|
+
// model inventory, per-model profiles, the VRAM budget, load/unload,
|
|
6335
|
+
// delete, and the log tail. Unlike brainManage (which shells out to the
|
|
6336
|
+
// CLI and is therefore local-only) these work against a remote brain too.
|
|
6337
|
+
// Without it the Brain page is not offered at all. Which of those the
|
|
6338
|
+
// brain on the far side actually serves is a separate question, answered
|
|
6339
|
+
// by `capabilities` on brain.host.status, because the daemon and the
|
|
6340
|
+
// brain version independently.
|
|
6341
|
+
// COMPAT(brainConsole): added in v0.7.7, drop the gate when daemon floor >= v0.7.7.
|
|
6342
|
+
brainConsole: z.boolean().optional(),
|
|
5437
6343
|
// COMPAT(agentForkContext): added in v0.1.102, remove gate after 2026-12-28.
|
|
5438
6344
|
agentForkContext: z.boolean().optional(),
|
|
5439
6345
|
// COMPAT(providerRemove): added in v0.1.105, drop the gate when daemon floor >= v0.1.105.
|
|
@@ -5456,7 +6362,7 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5456
6362
|
// Daemon owns a per-agent queue of steering messages, accepts
|
|
5457
6363
|
// `delivery: "queue"` on send, reports `queuedMessages` on the agent
|
|
5458
6364
|
// snapshot, and serves agent.queue.remove/clear. Without it the
|
|
5459
|
-
// composer keeps its own local queue
|
|
6365
|
+
// composer keeps its own local queue - that is the pre-existing
|
|
5460
6366
|
// behavior, not a degraded build of this feature.
|
|
5461
6367
|
steerQueue: z.boolean().optional(),
|
|
5462
6368
|
// Daemon serves agent.queue.reorder. Separate from `steerQueue`
|
|
@@ -5467,33 +6373,43 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5467
6373
|
// Daemon reports `cumulativeUsage` (the lifetime in/cached/out split
|
|
5468
6374
|
// plus its own booked cost) on every agent snapshot, so a chat's total
|
|
5469
6375
|
// spend can be summed and priced honestly. Without it the client shows
|
|
5470
|
-
// token totals only and no cost
|
|
6376
|
+
// token totals only and no cost - NOT an estimated cost, which is the
|
|
5471
6377
|
// behavior this feature exists to remove.
|
|
5472
6378
|
// COMPAT(cumulativeUsage): added in v0.7.0, drop the gate when daemon floor >= v0.7.0.
|
|
5473
6379
|
cumulativeUsage: z.boolean().optional(),
|
|
5474
6380
|
// Daemon can resolve and evaluate the provider's context graph, serve
|
|
5475
6381
|
// context.report.* and push context_report_changed. Without it the
|
|
5476
6382
|
// client hides both the Context Management tab and the composer
|
|
5477
|
-
// warning entirely
|
|
6383
|
+
// warning entirely - there is no degraded client-side fallback, since
|
|
5478
6384
|
// only the daemon can see the files a provider loads.
|
|
5479
6385
|
// COMPAT(contextManagement): added in v0.6.5, drop the gate when daemon floor >= v0.6.5.
|
|
5480
6386
|
contextManagement: z.boolean().optional(),
|
|
5481
6387
|
// COMPAT(textEditor): added in v0.4.4, drop the gate when daemon floor >= v0.4.4.
|
|
5482
6388
|
textEditor: z.boolean().optional(),
|
|
5483
|
-
// Refine
|
|
6389
|
+
// Refine - the daemon can turn a pinned document plus an instruction
|
|
5484
6390
|
// into a proposed rewrite (`file.refine.*`). Without it the Refine
|
|
5485
6391
|
// entry is absent: there is no client-side substitute for a model, and
|
|
5486
6392
|
// a degraded "open a chat instead" path is exactly the unreviewed edit
|
|
5487
6393
|
// Refine exists to replace.
|
|
5488
6394
|
// COMPAT(refine): added in v0.6.9, drop the gate when daemon floor >= v0.6.9.
|
|
5489
6395
|
refine: z.boolean().optional(),
|
|
5490
|
-
// Personality memory
|
|
6396
|
+
// Personality memory - the daemon stores per-personality lessons, injects
|
|
5491
6397
|
// them at spawn, and serves personality.memory.*. Without it the client
|
|
5492
6398
|
// hides the Memory tab, the accrual indicator and the transfer-on-delete
|
|
5493
6399
|
// choice: storage is daemon-side by definition, so there is nothing a
|
|
5494
6400
|
// client-side fallback could read.
|
|
5495
6401
|
// COMPAT(personalityMemory): added in v0.7.0, drop the gate when daemon floor >= v0.7.0.
|
|
5496
6402
|
personalityMemory: z.boolean().optional(),
|
|
6403
|
+
// Script discovery - the daemon scans a workspace for the Scripts its
|
|
6404
|
+
// project files already declare (package.json scripts, and later
|
|
6405
|
+
// Makefile targets, .NET launch profiles) and serves them from
|
|
6406
|
+
// `workspace.script.list` with `includeDiscovered`. Without it the
|
|
6407
|
+
// Scripts dropdown shows only what otto.json declares, which is the
|
|
6408
|
+
// pre-existing behavior and not a degraded build of this feature: only
|
|
6409
|
+
// the daemon can read the workspace's files, so there is no client-side
|
|
6410
|
+
// scan to fall back to.
|
|
6411
|
+
// COMPAT(workspaceScriptDiscovery): added in v0.7.6, drop the gate when daemon floor >= v0.7.6.
|
|
6412
|
+
workspaceScriptDiscovery: z.boolean().optional(),
|
|
5497
6413
|
// COMPAT(projectSearch): added in v0.4.4, drop the gate when daemon floor >= v0.4.4.
|
|
5498
6414
|
projectSearch: z.boolean().optional(),
|
|
5499
6415
|
// COMPAT(codeIndex): added in v0.4.4, drop the gate when daemon floor >= v0.4.4.
|
|
@@ -5510,11 +6426,11 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5510
6426
|
// flag the client says to update the host rather than showing an empty screen.
|
|
5511
6427
|
// COMPAT(lspHostServers): added in v0.7.3, drop the gate when daemon floor >= v0.7.3.
|
|
5512
6428
|
lspHostServers: z.boolean().optional(),
|
|
5513
|
-
// The Solution view
|
|
6429
|
+
// The Solution view - the daemon can discover solutions and serve
|
|
5514
6430
|
// `code.solution.*`. Deliberately NOT implied by `lsp`: there is no
|
|
5515
6431
|
// project-structure request in LSP, so this subsystem is independent of
|
|
5516
6432
|
// language servers and of the C# row's on/off state. Without the flag the
|
|
5517
|
-
// client never shows the view switcher and never asks
|
|
6433
|
+
// client never shows the view switcher and never asks - there is no
|
|
5518
6434
|
// client-side substitute for reading a solution, and a hand-parsed
|
|
5519
6435
|
// half-tree is exactly the mistake this design exists to avoid.
|
|
5520
6436
|
// COMPAT(solutionView): added in v0.6.8, drop the gate when daemon floor >= v0.6.8.
|
|
@@ -5549,7 +6465,7 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5549
6465
|
// COMPAT(checkoutGitLog): added in v0.5.1, drop the gate when daemon floor >= v0.5.1.
|
|
5550
6466
|
checkoutGitLog: z.boolean().optional(),
|
|
5551
6467
|
// Local-git file investigation: history, per-commit diff, blame, origin
|
|
5552
|
-
// commit
|
|
6468
|
+
// commit - for a whole file or a line range. No forge connection needed
|
|
5553
6469
|
// and no per-provider rollout; it is git, so every provider gets it at
|
|
5554
6470
|
// once.
|
|
5555
6471
|
// COMPAT(checkoutGitFileHistory): added in v0.6.6, drop the gate when daemon floor >= v0.6.6.
|
|
@@ -5558,19 +6474,19 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5558
6474
|
// archiving (workspace.archive.preflight.*) and delete it as part of the
|
|
5559
6475
|
// archive (archive_workspace_request.branchDisposition). Without it the
|
|
5560
6476
|
// client archives the worktree exactly as before and never offers to
|
|
5561
|
-
// remove the branch
|
|
6477
|
+
// remove the branch - no degraded client-side branch detection exists.
|
|
5562
6478
|
// COMPAT(worktreeArchiveBranchCleanup): added in v0.6.7, drop the gate when daemon floor >= v0.6.7.
|
|
5563
6479
|
worktreeArchiveBranchCleanup: z.boolean().optional(),
|
|
5564
6480
|
// COMPAT(worktreeReattach): added in v0.6.7, drop the gate when daemon floor >= v0.6.7.
|
|
5565
6481
|
worktreeReattach: z.boolean().optional(),
|
|
5566
6482
|
// Set when the daemon can repoint a worktree's stored base branch
|
|
5567
6483
|
// (worktree.baseRef.set.*). Without it the client renders the base as a
|
|
5568
|
-
// read-only "vs <base>" label
|
|
6484
|
+
// read-only "vs <base>" label - there is no client-side override, since only
|
|
5569
6485
|
// the daemon can write the worktree's metadata.
|
|
5570
6486
|
// COMPAT(worktreeDiffBase): added in v0.6.8, drop the gate when daemon floor >= v0.6.8.
|
|
5571
6487
|
worktreeDiffBase: z.boolean().optional(),
|
|
5572
6488
|
// Set when the daemon stores the diff base *per branch*, which is what lets any git
|
|
5573
|
-
// checkout repoint it rather than only an Otto worktree
|
|
6489
|
+
// checkout repoint it rather than only an Otto worktree - a plain checkout's gitdir is
|
|
5574
6490
|
// shared by every branch in it, so a single stored base would bleed across branch
|
|
5575
6491
|
// switches. Also gates parent-branch detection, the `origin/`-qualified pin, and the
|
|
5576
6492
|
// re-detect action. Without it the client keeps the worktree-only picker.
|
|
@@ -5626,24 +6542,30 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5626
6542
|
// cap) shows "Update the host" instead of a knob that does nothing.
|
|
5627
6543
|
openaiCompatMaxToolRounds: z.boolean().optional(),
|
|
5628
6544
|
// COMPAT(mcpToolGroups): added in v0.6.4, drop the gate when daemon floor >= v0.6.4.
|
|
5629
|
-
// Set when the daemon honors `mcp.toolGroups`
|
|
6545
|
+
// Set when the daemon honors `mcp.toolGroups` - per-group gating of the
|
|
5630
6546
|
// Otto tool catalog on the MCP (Claude) path. Old daemons register every
|
|
5631
6547
|
// group regardless, so the client hides the categorized section instead
|
|
5632
6548
|
// of showing category switches that do nothing.
|
|
5633
6549
|
mcpToolGroups: z.boolean().optional(),
|
|
5634
6550
|
// COMPAT(connectors): added in v0.7.5, drop the gate when daemon floor >= v0.7.5.
|
|
5635
|
-
// Set when the daemon persists and honors `connectors`
|
|
6551
|
+
// Set when the daemon persists and honors `connectors` - MCP servers
|
|
5636
6552
|
// surfaced as named, toggle-able integrations with per-tool disable,
|
|
5637
6553
|
// enforced today on the openai-compat path. Old daemons ignore the
|
|
5638
6554
|
// section, so the client hides the Connectors settings entirely.
|
|
5639
6555
|
connectors: z.boolean().optional(),
|
|
6556
|
+
// COMPAT(connectorOauth): added in v0.7.7, drop the gate when daemon floor >= v0.7.7.
|
|
6557
|
+
// Set when the daemon can run the OAuth authorization-code flow for a
|
|
6558
|
+
// connector and attach the resulting token to its MCP transport. Old
|
|
6559
|
+
// daemons have no broker and no way to hold a token, so the client hides
|
|
6560
|
+
// Connect / Disconnect and offers only the paste-a-token connectors.
|
|
6561
|
+
connectorOauth: z.boolean().optional(),
|
|
5640
6562
|
// COMPAT(agentBehaviorToggles): added in v0.6.4, drop the gate when daemon floor >= v0.6.4.
|
|
5641
6563
|
// Set when the daemon persists `agentBehaviors.*` (promptSuggestions,
|
|
5642
6564
|
// agentProgressSummaries, notifyOnFinishDefault). The reads are wired by
|
|
5643
6565
|
// Claude-tier providers (WP-E); the client gates the toggle cards on this.
|
|
5644
6566
|
agentBehaviorToggles: z.boolean().optional(),
|
|
5645
6567
|
// COMPAT(todoReminders): added in v0.7.5, drop the gate when daemon floor >= v0.7.5.
|
|
5646
|
-
// Set when the daemon acts on `agentBehaviors.{todoNudge,todoReconcileOnIdle}`
|
|
6568
|
+
// Set when the daemon acts on `agentBehaviors.{todoNudge,todoReconcileOnIdle}` -
|
|
5647
6569
|
// the provider-agnostic stale-todo nudge (next turn) and idle reconcile pass.
|
|
5648
6570
|
// The client gates the task-list toggle cards on this so an old daemon never
|
|
5649
6571
|
// shows switches that do nothing.
|
|
@@ -5674,20 +6596,27 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5674
6596
|
// the existing `delete_agent_request`, and in bulk via
|
|
5675
6597
|
// `history.agents.clear_archived`. Archive has always been a soft delete
|
|
5676
6598
|
// with no counterpart; this is the counterpart. Deleting removes Otto's
|
|
5677
|
-
// record only
|
|
6599
|
+
// record only - provider transcripts are never touched (see the
|
|
5678
6600
|
// clear_archived schema). The client hides both affordances when this is
|
|
5679
6601
|
// absent rather than shipping a degraded path.
|
|
5680
6602
|
historyDelete: z.boolean().optional(),
|
|
5681
6603
|
// COMPAT(fileMutations): added in v0.7.0, drop the gate when daemon floor >= v0.7.0.
|
|
5682
6604
|
// Set when the daemon serves `file.create`, `file.delete` and
|
|
5683
|
-
// `file.rename`
|
|
6605
|
+
// `file.rename` - creating, removing and moving entries, as opposed to
|
|
5684
6606
|
// `file.write`, which only changes what is inside an existing file.
|
|
5685
6607
|
// There is no client-side substitute (the client never touches the
|
|
5686
6608
|
// filesystem), so an old daemon simply does not get the menu items.
|
|
5687
6609
|
fileMutations: z.boolean().optional(),
|
|
6610
|
+
// COMPAT(binaryFileWrite): added in v0.7.6, drop the gate when daemon
|
|
6611
|
+
// floor >= v0.7.6. Set when the daemon serves
|
|
6612
|
+
// `fs.file.write_binary` - bytes to a workspace path, as opposed to
|
|
6613
|
+
// `fs.file.write`, which is text and refuses binary targets outright.
|
|
6614
|
+
// The client cannot write a workspace file itself on any platform, so
|
|
6615
|
+
// an old daemon simply does not offer the exports that produce bytes.
|
|
6616
|
+
binaryFileWrite: z.boolean().optional(),
|
|
5688
6617
|
// COMPAT(attachmentStorage): added in v0.7.1, drop the gate when daemon floor >= v0.7.1.
|
|
5689
6618
|
// Set when the daemon serves `attachments.images.get_stats` and
|
|
5690
|
-
// `attachments.images.clear`
|
|
6619
|
+
// `attachments.images.clear` - the readout and reclaim for the images it
|
|
5691
6620
|
// materializes on the agent's behalf. The client has no way to size or
|
|
5692
6621
|
// clear a directory on the host, so an old daemon simply does not get
|
|
5693
6622
|
// the daemon half of the Storage section; the app-side preview cache row
|
|
@@ -5695,10 +6624,44 @@ export const ServerInfoStatusPayloadSchema = z
|
|
|
5695
6624
|
attachmentStorage: z.boolean().optional(),
|
|
5696
6625
|
// COMPAT(agentWorkspaceTransfer): added in v0.7.4, drop the gate when
|
|
5697
6626
|
// daemon floor >= v0.7.4. Set when the daemon serves
|
|
5698
|
-
// `agent.workspace.transfer`
|
|
6627
|
+
// `agent.workspace.transfer` - moving a chat to another workspace over
|
|
5699
6628
|
// the same directory. The client cannot restamp ownership itself (it is
|
|
5700
6629
|
// daemon state), so an old daemon simply does not get the menu item.
|
|
5701
6630
|
agentWorkspaceTransfer: z.boolean().optional(),
|
|
6631
|
+
// COMPAT(agentForkContextCursor): added in v0.1.108, remove gate after 2027-01-14.
|
|
6632
|
+
agentForkContextCursor: z.boolean().optional(),
|
|
6633
|
+
// COMPAT(providerSubagents): added in v0.1.107, remove gate after 2027-01-12.
|
|
6634
|
+
providerSubagents: z.boolean().optional(),
|
|
6635
|
+
// COMPAT(workspacePinning): added in v0.1.107, remove gate after 2027-01-12.
|
|
6636
|
+
workspacePinning: z.boolean().optional(),
|
|
6637
|
+
// COMPAT(hubRelationship): added in v0.1.X, drop the gate when floor >= v0.1.X.
|
|
6638
|
+
hubRelationship: z.boolean().optional(),
|
|
6639
|
+
// COMPAT(projectGithubClone): added in v0.1.108, remove gate after 2027-01-15.
|
|
6640
|
+
projectGithubClone: z.boolean().optional(),
|
|
6641
|
+
// COMPAT(workspaceGithubRepositorySearch): added in v0.1.108, remove gate after 2027-01-15.
|
|
6642
|
+
workspaceGithubRepositorySearch: z.boolean().optional(),
|
|
6643
|
+
// COMPAT(projectCreateDirectory): added in v0.1.108, remove gate after 2027-01-15.
|
|
6644
|
+
projectCreateDirectory: z.boolean().optional(),
|
|
6645
|
+
// COMPAT(projectList): added in v0.2.4, drop the gate when floor >= v0.2.4.
|
|
6646
|
+
projectList: z.boolean().optional(),
|
|
6647
|
+
// COMPAT(commitsList): added in v0.1.110, remove gate after 2027-01-16.
|
|
6648
|
+
commitsList: z.boolean().optional(),
|
|
6649
|
+
// COMPAT(commitBaseClassification): added in v0.2.0, remove gate after 2027-01-23.
|
|
6650
|
+
commitBaseClassification: z.boolean().optional(),
|
|
6651
|
+
// COMPAT(providerRemoval): added in v0.1.105, drop the gate when floor >= v0.1.105.
|
|
6652
|
+
providerRemoval: z.boolean().optional(),
|
|
6653
|
+
// COMPAT(importSessionWorkspaceTarget): added in v0.1.110, remove gate after 2027-01-16.
|
|
6654
|
+
importSessionWorkspaceTarget: z.boolean().optional(),
|
|
6655
|
+
// COMPAT(forgeProviders): added in v0.1.106, drop the gate when daemon floor >= v0.1.106.
|
|
6656
|
+
// Daemon advertises pluggable non-GitHub forge support (the forge registry);
|
|
6657
|
+
// the client gates non-GitHub setup UI on it.
|
|
6658
|
+
forgeProviders: z.boolean().optional(),
|
|
6659
|
+
// COMPAT(selectiveAgentTimeline): added in v0.1.106, remove after 2027-01-12.
|
|
6660
|
+
selectiveAgentTimeline: z.boolean().optional(),
|
|
6661
|
+
// COMPAT(stableProjectIdentity): added in v0.1.109, remove gate after 2027-01-15.
|
|
6662
|
+
stableProjectIdentity: z.boolean().optional(),
|
|
6663
|
+
// COMPAT(workspaceScriptManagement): added in v0.1.105, remove gate after 2027-01-10.
|
|
6664
|
+
workspaceScriptManagement: z.boolean().optional(),
|
|
5702
6665
|
})
|
|
5703
6666
|
.optional(),
|
|
5704
6667
|
})
|
|
@@ -5787,7 +6750,7 @@ export const DaemonConfigChangedStatusPayloadSchema = z
|
|
|
5787
6750
|
* spinner, so an idempotent snapshot cannot drift out of sync the way a missed
|
|
5788
6751
|
* transition would.
|
|
5789
6752
|
*
|
|
5790
|
-
* Separate from the workspace status bucket on purpose
|
|
6753
|
+
* Separate from the workspace status bucket on purpose - indexing is not the workspace
|
|
5791
6754
|
* "working", and folding it in would mislabel a quiet workspace as busy with agent work.
|
|
5792
6755
|
*/
|
|
5793
6756
|
export const LspActivityChangedStatusPayloadSchema = z
|
|
@@ -5810,11 +6773,11 @@ export const CodeDiagnosticSchema = z.object({
|
|
|
5810
6773
|
endColumn: z.number().int().positive(),
|
|
5811
6774
|
severity: CodeDiagnosticSeveritySchema,
|
|
5812
6775
|
message: z.string(),
|
|
5813
|
-
/** Who says so
|
|
6776
|
+
/** Who says so - `ts`, `pyright`, a linter behind the server. */
|
|
5814
6777
|
source: z.string().optional(),
|
|
5815
6778
|
/** The server's own code for the rule or error, e.g. TypeScript's `2345`. */
|
|
5816
6779
|
code: z.string().optional(),
|
|
5817
|
-
/** Documentation for that rule, when the server offers one
|
|
6780
|
+
/** Documentation for that rule, when the server offers one - oxlint does. */
|
|
5818
6781
|
codeHref: z.string().optional(),
|
|
5819
6782
|
/** Which registry row published it, so two servers on one file stay attributable. */
|
|
5820
6783
|
serverId: z.string().optional(),
|
|
@@ -5825,7 +6788,7 @@ export const CodeDiagnosticSchema = z.object({
|
|
|
5825
6788
|
* This is the one part of code intelligence that is not request/response:
|
|
5826
6789
|
* `textDocument/publishDiagnostics` arrives whenever the server has recomputed, which is
|
|
5827
6790
|
* whenever it feels like it. So it is a status broadcast, and the payload is the document's
|
|
5828
|
-
* **whole** current set
|
|
6791
|
+
* **whole** current set - never a delta. A missed delta would leave a stale squiggle on a
|
|
5829
6792
|
* line the user already fixed, and an idempotent snapshot cannot drift.
|
|
5830
6793
|
*
|
|
5831
6794
|
* Only documents a client has synced produce these. A server may know about every file in
|
|
@@ -5918,8 +6881,50 @@ export const ProjectPlacementPayloadSchema = z.object({
|
|
|
5918
6881
|
});
|
|
5919
6882
|
export const WorkspaceScriptLifecycleSchema = z.enum(["running", "stopped"]);
|
|
5920
6883
|
export const WorkspaceScriptHealthSchema = z.enum(["healthy", "unhealthy"]);
|
|
6884
|
+
export const WorkspaceScriptSourcePayloadSchema = z.object({
|
|
6885
|
+
/** Stable provider id; also the prefix of every `scriptName` it produces. */
|
|
6886
|
+
id: z.string(),
|
|
6887
|
+
/** The tool half of the dropdown's group header, e.g. "npm" or "pnpm". */
|
|
6888
|
+
label: z.string(),
|
|
6889
|
+
/**
|
|
6890
|
+
* Repo-relative file the script was read from, e.g. "package.json".
|
|
6891
|
+
*
|
|
6892
|
+
* Plain-optional rather than defaulted, matching `label` and `command` on the
|
|
6893
|
+
* payload: absent means unknown. A discovery run knows the file, but the
|
|
6894
|
+
* descriptor's orphan path recovers a source from a qualified runtime name
|
|
6895
|
+
* alone (`npm:dev`) and has no discovery behind it to ask. A `.default(null)`
|
|
6896
|
+
* here would make the field required on the output type and force that path
|
|
6897
|
+
* to invent an answer it does not have.
|
|
6898
|
+
*/
|
|
6899
|
+
file: z.string().nullable().optional(),
|
|
6900
|
+
});
|
|
5921
6901
|
export const WorkspaceScriptPayloadSchema = z.object({
|
|
6902
|
+
/**
|
|
6903
|
+
* The launch/stop key, unique within a workspace. Otto's own otto.json
|
|
6904
|
+
* scripts use their bare name; a discovered one is qualified by its source
|
|
6905
|
+
* ("npm:build") so two sources offering "build" cannot collide in the
|
|
6906
|
+
* runtime store or the service-proxy hostname.
|
|
6907
|
+
*/
|
|
5922
6908
|
scriptName: z.string(),
|
|
6909
|
+
/**
|
|
6910
|
+
* What to show instead of `scriptName` - the name the project itself uses.
|
|
6911
|
+
* COMPAT(workspaceScriptDiscovery): added in v0.7.6; absent ⇒ show `scriptName`.
|
|
6912
|
+
*/
|
|
6913
|
+
label: z.string().optional(),
|
|
6914
|
+
/**
|
|
6915
|
+
* Where this Script came from. Absent ⇒ declared in otto.json, which is the
|
|
6916
|
+
* only kind that existed before discovery and the only kind that may own a
|
|
6917
|
+
* service-proxy route.
|
|
6918
|
+
* COMPAT(workspaceScriptDiscovery): added in v0.7.6.
|
|
6919
|
+
*/
|
|
6920
|
+
source: WorkspaceScriptSourcePayloadSchema.optional(),
|
|
6921
|
+
/**
|
|
6922
|
+
* The command the Script runs, for the row's subtitle. Left plain-optional
|
|
6923
|
+
* rather than defaulted so an existing payload that never carried a command
|
|
6924
|
+
* stays valid without gaining a field it has no answer for.
|
|
6925
|
+
* COMPAT(workspaceScriptDiscovery): added in v0.7.6; absent ⇒ no subtitle.
|
|
6926
|
+
*/
|
|
6927
|
+
command: z.string().nullable().optional(),
|
|
5923
6928
|
type: z.enum(["script", "service"]).optional().default("service"),
|
|
5924
6929
|
hostname: z.string(),
|
|
5925
6930
|
port: z.number().int().positive().nullable(),
|
|
@@ -6003,7 +7008,9 @@ export const WorkspaceDescriptorPayloadSchema = z
|
|
|
6003
7008
|
projectRootPath: z.string(),
|
|
6004
7009
|
workspaceDirectory: z.string().optional(),
|
|
6005
7010
|
projectKind: z.enum(["git", "non_git", "directory"]),
|
|
6006
|
-
// COMPAT(workspaces): keep legacy directory workspace kind parseable.
|
|
7011
|
+
// COMPAT(workspaces): keep the legacy "directory" workspace kind parseable.
|
|
7012
|
+
// Persisted registries still carry it and there is no migration, so this
|
|
7013
|
+
// stays until a migration retires the kind rather than expiring on a date.
|
|
6007
7014
|
workspaceKind: z.enum(["directory", "local_checkout", "checkout", "worktree"]),
|
|
6008
7015
|
name: z.string(),
|
|
6009
7016
|
// COMPAT(workspaceTitles): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
|
|
@@ -6012,6 +7019,8 @@ export const WorkspaceDescriptorPayloadSchema = z
|
|
|
6012
7019
|
// its input and offer a "reset to branch name" action. Null means the name
|
|
6013
7020
|
// is derived from the branch/directory.
|
|
6014
7021
|
title: z.string().nullable().optional(),
|
|
7022
|
+
// COMPAT(workspacePinning): added in v0.1.107, remove optional after 2027-01-12.
|
|
7023
|
+
pinnedAt: z.string().nullable().optional(),
|
|
6015
7024
|
archivingAt: z.string().nullable().optional().default(null),
|
|
6016
7025
|
status: WorkspaceStateBucketSchema,
|
|
6017
7026
|
// Best-effort workspace status entry timestamp. Old daemons omit the
|
|
@@ -6033,6 +7042,10 @@ export const WorkspaceDescriptorPayloadSchema = z
|
|
|
6033
7042
|
scripts: z.array(WorkspaceScriptPayloadSchema).default([]),
|
|
6034
7043
|
gitRuntime: WorkspaceGitRuntimePayloadSchema,
|
|
6035
7044
|
githubRuntime: WorkspaceGitHubRuntimePayloadSchema,
|
|
7045
|
+
// COMPAT(forge): added in v0.1.106, remove after 2026-12-27. The forge resolved
|
|
7046
|
+
// for this workspace, so the sidebar/hover-card render the right brand mark.
|
|
7047
|
+
// Old daemons omit it; absent means the client falls back to GitHub.
|
|
7048
|
+
forge: z.string().optional(),
|
|
6036
7049
|
project: ProjectPlacementPayloadSchema.optional(),
|
|
6037
7050
|
})
|
|
6038
7051
|
.transform((workspace) => ({
|
|
@@ -6124,6 +7137,8 @@ export const FetchRecentProviderSessionsResponseMessageSchema = z.object({
|
|
|
6124
7137
|
// workspace is archived.
|
|
6125
7138
|
export const WorkspaceProjectDescriptorPayloadSchema = z.object({
|
|
6126
7139
|
projectId: z.string(),
|
|
7140
|
+
// COMPAT(projectKey): added in v0.2.4 on 2026-07-28; remove optional after 2027-01-28.
|
|
7141
|
+
projectKey: z.string().optional(),
|
|
6127
7142
|
projectDisplayName: z.string(),
|
|
6128
7143
|
projectCustomName: z.string().nullable().optional(),
|
|
6129
7144
|
projectRootPath: z.string(),
|
|
@@ -6171,7 +7186,7 @@ export const WorkspaceUpdateMessageSchema = z.object({
|
|
|
6171
7186
|
});
|
|
6172
7187
|
// A project's own metadata changed (today: the user renamed it). The workspace
|
|
6173
7188
|
// channel can only carry a project's name inside its workspaces' descriptors, so
|
|
6174
|
-
// a project with no active workspaces had no live channel at all
|
|
7189
|
+
// a project with no active workspaces had no live channel at all - its name only
|
|
6175
7190
|
// refreshed on the next full workspace fetch. This is the project-level channel:
|
|
6176
7191
|
// it fires whether or not the project currently has workspaces, and the daemon
|
|
6177
7192
|
// fans it out to every connected session because project metadata is host-global.
|
|
@@ -6185,6 +7200,20 @@ export const ProjectUpdatedNotificationSchema = z.object({
|
|
|
6185
7200
|
hasActiveWorkspaces: z.boolean(),
|
|
6186
7201
|
}),
|
|
6187
7202
|
});
|
|
7203
|
+
export const ProjectUpdateMessageSchema = z.object({
|
|
7204
|
+
type: z.literal("project.update"),
|
|
7205
|
+
payload: z.discriminatedUnion("kind", [
|
|
7206
|
+
z.object({ kind: z.literal("upsert"), project: WorkspaceProjectDescriptorPayloadSchema }),
|
|
7207
|
+
z.object({ kind: z.literal("remove"), projectId: z.string() }),
|
|
7208
|
+
]),
|
|
7209
|
+
});
|
|
7210
|
+
export const ProjectListResponseMessageSchema = z.object({
|
|
7211
|
+
type: z.literal("project.list.response"),
|
|
7212
|
+
payload: z.object({
|
|
7213
|
+
requestId: z.string(),
|
|
7214
|
+
projects: z.array(WorkspaceProjectDescriptorPayloadSchema),
|
|
7215
|
+
}),
|
|
7216
|
+
});
|
|
6188
7217
|
export const ScriptStatusUpdateMessageSchema = z.object({
|
|
6189
7218
|
type: z.literal("script_status_update"),
|
|
6190
7219
|
payload: z.object({
|
|
@@ -6238,7 +7267,7 @@ export const ProjectScaffoldResponseSchema = z.object({
|
|
|
6238
7267
|
type: z.literal("project.scaffold.response"),
|
|
6239
7268
|
payload: z.object({
|
|
6240
7269
|
requestId: z.string(),
|
|
6241
|
-
// Registered project on success. Null whenever any step failed
|
|
7270
|
+
// Registered project on success. Null whenever any step failed - the
|
|
6242
7271
|
// daemon does not register a half-built directory.
|
|
6243
7272
|
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
|
|
6244
7273
|
// Absolute path of the created directory. Non-null even on a late failure
|
|
@@ -6316,6 +7345,70 @@ export const HostingListOwnersResponseSchema = z.object({
|
|
|
6316
7345
|
error: z.string().nullable(),
|
|
6317
7346
|
}),
|
|
6318
7347
|
});
|
|
7348
|
+
export const ProjectCreateDirectoryErrorCodeSchema = z.enum([
|
|
7349
|
+
"invalid_name",
|
|
7350
|
+
"parent_directory_not_found",
|
|
7351
|
+
"directory_exists",
|
|
7352
|
+
"permission_denied",
|
|
7353
|
+
"registration_failed",
|
|
7354
|
+
"filesystem_error",
|
|
7355
|
+
]);
|
|
7356
|
+
export const ProjectCreateDirectoryResponseSchema = z.object({
|
|
7357
|
+
type: z.literal("project.create_directory.response"),
|
|
7358
|
+
payload: z.object({
|
|
7359
|
+
requestId: z.string(),
|
|
7360
|
+
directoryPath: z.string().nullable(),
|
|
7361
|
+
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
|
|
7362
|
+
error: z.string().nullable(),
|
|
7363
|
+
// Error codes are open-ended on the wire so older clients can still parse
|
|
7364
|
+
// responses after a newer daemon learns another failure reason.
|
|
7365
|
+
errorCode: z.string().nullable(),
|
|
7366
|
+
}),
|
|
7367
|
+
});
|
|
7368
|
+
export const WorkspaceGithubSearchRepositoriesResponseSchema = z.object({
|
|
7369
|
+
type: z.literal("workspace.github.search_repositories.response"),
|
|
7370
|
+
payload: z.discriminatedUnion("status", [
|
|
7371
|
+
z.object({
|
|
7372
|
+
status: z.literal("success"),
|
|
7373
|
+
requestId: z.string(),
|
|
7374
|
+
repositories: z.array(GithubRepositorySchema),
|
|
7375
|
+
available: z.literal(true),
|
|
7376
|
+
error: z.null(),
|
|
7377
|
+
}),
|
|
7378
|
+
z.object({
|
|
7379
|
+
status: z.literal("unavailable"),
|
|
7380
|
+
requestId: z.string(),
|
|
7381
|
+
repositories: z.array(GithubRepositorySchema),
|
|
7382
|
+
reason: z.literal("gh_missing"),
|
|
7383
|
+
available: z.literal(false),
|
|
7384
|
+
error: z.string(),
|
|
7385
|
+
}),
|
|
7386
|
+
z.object({
|
|
7387
|
+
status: z.literal("unauthenticated"),
|
|
7388
|
+
requestId: z.string(),
|
|
7389
|
+
repositories: z.array(GithubRepositorySchema),
|
|
7390
|
+
available: z.literal(false),
|
|
7391
|
+
error: z.string(),
|
|
7392
|
+
}),
|
|
7393
|
+
z.object({
|
|
7394
|
+
status: z.literal("error"),
|
|
7395
|
+
requestId: z.string(),
|
|
7396
|
+
repositories: z.array(GithubRepositorySchema),
|
|
7397
|
+
available: z.literal(true),
|
|
7398
|
+
error: z.string(),
|
|
7399
|
+
}),
|
|
7400
|
+
]),
|
|
7401
|
+
});
|
|
7402
|
+
export const ProjectGithubCloneResponseSchema = z.object({
|
|
7403
|
+
type: z.literal("project.github.clone.response"),
|
|
7404
|
+
payload: z.object({
|
|
7405
|
+
requestId: z.string(),
|
|
7406
|
+
repo: z.string().trim().min(MIN_REPOSITORY_PATH_LENGTH),
|
|
7407
|
+
checkoutPath: z.string().nullable(),
|
|
7408
|
+
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
|
|
7409
|
+
error: z.string().nullable(),
|
|
7410
|
+
}),
|
|
7411
|
+
});
|
|
6319
7412
|
export const StartWorkspaceScriptResponseMessageSchema = z.object({
|
|
6320
7413
|
type: z.literal("start_workspace_script_response"),
|
|
6321
7414
|
payload: z.object({
|
|
@@ -6326,6 +7419,26 @@ export const StartWorkspaceScriptResponseMessageSchema = z.object({
|
|
|
6326
7419
|
error: z.string().nullable(),
|
|
6327
7420
|
}),
|
|
6328
7421
|
});
|
|
7422
|
+
const WorkspaceScriptOperationPayloadSchema = z.object({
|
|
7423
|
+
requestId: z.string(),
|
|
7424
|
+
workspaceId: z.string(),
|
|
7425
|
+
scriptName: z.string().optional(),
|
|
7426
|
+
script: WorkspaceScriptPayloadSchema.nullable().optional(),
|
|
7427
|
+
scripts: z.array(WorkspaceScriptPayloadSchema).optional(),
|
|
7428
|
+
error: z.string().nullable(),
|
|
7429
|
+
});
|
|
7430
|
+
export const WorkspaceScriptListResponseMessageSchema = z.object({
|
|
7431
|
+
type: z.literal("workspace.script.list.response"),
|
|
7432
|
+
payload: WorkspaceScriptOperationPayloadSchema,
|
|
7433
|
+
});
|
|
7434
|
+
export const WorkspaceScriptStartResponseMessageSchema = z.object({
|
|
7435
|
+
type: z.literal("workspace.script.start.response"),
|
|
7436
|
+
payload: WorkspaceScriptOperationPayloadSchema,
|
|
7437
|
+
});
|
|
7438
|
+
export const WorkspaceScriptStopResponseMessageSchema = z.object({
|
|
7439
|
+
type: z.literal("workspace.script.stop.response"),
|
|
7440
|
+
payload: WorkspaceScriptOperationPayloadSchema,
|
|
7441
|
+
});
|
|
6329
7442
|
// COMPAT(desktopEditorBridge): added in v0.1.88, remove after 2026-12-03 once old clients no longer parse daemon editor RPC responses.
|
|
6330
7443
|
export const LegacyListAvailableEditorsResponseMessageSchema = z.object({
|
|
6331
7444
|
type: z.literal("list_available_editors_response"),
|
|
@@ -6363,7 +7476,7 @@ export const ArchiveWorkspaceResponseMessageSchema = z.object({
|
|
|
6363
7476
|
// the workspace is archived. See WorkspaceArchivePreflightRequestSchema.
|
|
6364
7477
|
export const WorktreeArchiveBranchDetectionSchema = z.object({
|
|
6365
7478
|
// True only for Otto-owned worktrees whose branch we can offer to delete.
|
|
6366
|
-
// False for local checkouts, plain directories, and non-owned worktrees
|
|
7479
|
+
// False for local checkouts, plain directories, and non-owned worktrees - the
|
|
6367
7480
|
// client then skips the branch-cleanup UI entirely.
|
|
6368
7481
|
isOttoWorktree: z.boolean(),
|
|
6369
7482
|
// The local branch checked out in the worktree, or null when detached/unknown.
|
|
@@ -6373,7 +7486,7 @@ export const WorktreeArchiveBranchDetectionSchema = z.object({
|
|
|
6373
7486
|
mergeState: z.enum(["merged", "unmerged", "unknown"]),
|
|
6374
7487
|
// Commits on the branch not contained in the base ref; null when unknown.
|
|
6375
7488
|
unmergedCommitCount: z.number().int().nonnegative().nullable(),
|
|
6376
|
-
// A matching origin/<branch> exists
|
|
7489
|
+
// A matching origin/<branch> exists - deleting the local branch keeps the
|
|
6377
7490
|
// remote copy. Purely informational for the confirmation copy.
|
|
6378
7491
|
hasRemoteBranch: z.boolean(),
|
|
6379
7492
|
// The branch is checked out in another worktree too, so git will refuse to
|
|
@@ -6490,6 +7603,106 @@ export const FetchAgentTimelineResponseMessageSchema = z.object({
|
|
|
6490
7603
|
error: z.string().nullable(),
|
|
6491
7604
|
}),
|
|
6492
7605
|
});
|
|
7606
|
+
export const ProviderSubagentDescriptorPayloadSchema = z.object({
|
|
7607
|
+
id: z.string(),
|
|
7608
|
+
parentAgentId: z.string(),
|
|
7609
|
+
provider: AgentProviderSchema,
|
|
7610
|
+
title: z.string().nullable(),
|
|
7611
|
+
description: z.string().nullable(),
|
|
7612
|
+
status: z.enum(["running", "completed", "failed", "canceled"]),
|
|
7613
|
+
createdAt: z.string(),
|
|
7614
|
+
updatedAt: z.string(),
|
|
7615
|
+
toolCallId: z.string().nullable(),
|
|
7616
|
+
cwd: z.string().nullable().optional(),
|
|
7617
|
+
});
|
|
7618
|
+
export const ProviderSubagentListResponseMessageSchema = z.object({
|
|
7619
|
+
type: z.literal("agent.provider_subagents.list.response"),
|
|
7620
|
+
payload: z.object({
|
|
7621
|
+
requestId: z.string(),
|
|
7622
|
+
parentAgentId: z.string(),
|
|
7623
|
+
subagents: z.array(ProviderSubagentDescriptorPayloadSchema),
|
|
7624
|
+
error: z.string().nullable(),
|
|
7625
|
+
}),
|
|
7626
|
+
});
|
|
7627
|
+
export const ProviderSubagentTimelineResponseMessageSchema = z.object({
|
|
7628
|
+
type: z.literal("agent.provider_subagents.timeline.get.response"),
|
|
7629
|
+
payload: z.object({
|
|
7630
|
+
requestId: z.string(),
|
|
7631
|
+
parentAgentId: z.string(),
|
|
7632
|
+
subagentId: z.string(),
|
|
7633
|
+
provider: AgentProviderSchema.nullable(),
|
|
7634
|
+
direction: z.enum(["tail", "before", "after"]),
|
|
7635
|
+
epoch: z.string(),
|
|
7636
|
+
reset: z.boolean(),
|
|
7637
|
+
staleCursor: z.boolean(),
|
|
7638
|
+
gap: z.boolean(),
|
|
7639
|
+
window: z.object({
|
|
7640
|
+
minSeq: z.number().int().nonnegative(),
|
|
7641
|
+
maxSeq: z.number().int().nonnegative(),
|
|
7642
|
+
nextSeq: z.number().int().nonnegative(),
|
|
7643
|
+
}),
|
|
7644
|
+
hasOlder: z.boolean(),
|
|
7645
|
+
hasNewer: z.boolean(),
|
|
7646
|
+
rows: z.array(z.object({
|
|
7647
|
+
item: AgentTimelineItemPayloadSchema,
|
|
7648
|
+
timestamp: z.string(),
|
|
7649
|
+
seq: z.number().int().nonnegative(),
|
|
7650
|
+
})),
|
|
7651
|
+
error: z.string().nullable(),
|
|
7652
|
+
}),
|
|
7653
|
+
});
|
|
7654
|
+
export const ProviderSubagentUpdateMessageSchema = z.object({
|
|
7655
|
+
type: z.literal("agent.provider_subagents.update"),
|
|
7656
|
+
payload: z.discriminatedUnion("kind", [
|
|
7657
|
+
z.object({
|
|
7658
|
+
kind: z.literal("upsert"),
|
|
7659
|
+
subagent: ProviderSubagentDescriptorPayloadSchema,
|
|
7660
|
+
}),
|
|
7661
|
+
z.object({
|
|
7662
|
+
kind: z.literal("timeline"),
|
|
7663
|
+
parentAgentId: z.string(),
|
|
7664
|
+
subagentId: z.string(),
|
|
7665
|
+
provider: AgentProviderSchema,
|
|
7666
|
+
item: AgentTimelineItemPayloadSchema,
|
|
7667
|
+
timestamp: z.string(),
|
|
7668
|
+
seq: z.number().int().nonnegative(),
|
|
7669
|
+
epoch: z.string(),
|
|
7670
|
+
}),
|
|
7671
|
+
z.object({
|
|
7672
|
+
kind: z.literal("remove"),
|
|
7673
|
+
parentAgentId: z.string(),
|
|
7674
|
+
subagentId: z.string(),
|
|
7675
|
+
}),
|
|
7676
|
+
]),
|
|
7677
|
+
});
|
|
7678
|
+
export const SetAgentTimelineSubscriptionResponseMessageSchema = z.object({
|
|
7679
|
+
type: z.literal("agent.timeline.set_subscription.response"),
|
|
7680
|
+
payload: z.object({
|
|
7681
|
+
agentIds: z.array(z.string()),
|
|
7682
|
+
requestId: z.string(),
|
|
7683
|
+
}),
|
|
7684
|
+
});
|
|
7685
|
+
export const AgentAttentionRequiredMessageSchema = z.object({
|
|
7686
|
+
type: z.literal("agent_attention_required"),
|
|
7687
|
+
payload: z.object({
|
|
7688
|
+
agentId: z.string(),
|
|
7689
|
+
reason: z.enum(["finished", "error", "permission"]),
|
|
7690
|
+
timestamp: z.string(),
|
|
7691
|
+
shouldNotify: z.boolean(),
|
|
7692
|
+
notification: z
|
|
7693
|
+
.object({
|
|
7694
|
+
title: z.string(),
|
|
7695
|
+
body: z.string(),
|
|
7696
|
+
data: z.object({
|
|
7697
|
+
serverId: z.string(),
|
|
7698
|
+
workspaceId: z.string().optional(),
|
|
7699
|
+
agentId: z.string(),
|
|
7700
|
+
reason: z.enum(["finished", "error", "permission"]),
|
|
7701
|
+
}),
|
|
7702
|
+
})
|
|
7703
|
+
.optional(),
|
|
7704
|
+
}),
|
|
7705
|
+
});
|
|
6493
7706
|
export const AgentForkContextResponseMessageSchema = z.object({
|
|
6494
7707
|
type: z.literal("agent.fork_context.response"),
|
|
6495
7708
|
payload: z.object({
|
|
@@ -6498,6 +7711,7 @@ export const AgentForkContextResponseMessageSchema = z.object({
|
|
|
6498
7711
|
attachment: TextAttachmentSchema.nullable(),
|
|
6499
7712
|
itemCount: z.number().int().nonnegative(),
|
|
6500
7713
|
boundaryMessageId: z.string().nullable(),
|
|
7714
|
+
boundaryCursor: AgentTimelineCursorSchema.nullable().optional(),
|
|
6501
7715
|
error: z.string().nullable(),
|
|
6502
7716
|
}),
|
|
6503
7717
|
});
|
|
@@ -6509,7 +7723,7 @@ export const AgentQueueRemoveResponseMessageSchema = z.object({
|
|
|
6509
7723
|
/**
|
|
6510
7724
|
* The removed message's text, handed back so the composer can put it back
|
|
6511
7725
|
* in the box for editing or re-send it right away. Null when the id was
|
|
6512
|
-
* already gone
|
|
7726
|
+
* already gone - the turn drained it while the tap was in flight.
|
|
6513
7727
|
* Attachments are not echoed: the client that queued the message keeps its
|
|
6514
7728
|
* own local copy keyed by `id` (see the composer's queued-attachment
|
|
6515
7729
|
* sidecar), and a client that never queued it has nothing to restore.
|
|
@@ -6558,6 +7772,7 @@ export const CancelAgentResponseMessageSchema = z.object({
|
|
|
6558
7772
|
// can say "nothing to stop" instead of silently no-oping. Purely additive;
|
|
6559
7773
|
// absent ⇒ unknown (old daemon). See docs/agent-lifecycle.md (Item 2).
|
|
6560
7774
|
cancelled: z.boolean().optional(),
|
|
7775
|
+
error: z.string().nullable().optional(),
|
|
6561
7776
|
}),
|
|
6562
7777
|
});
|
|
6563
7778
|
export const ClearAgentAttentionResponseMessageSchema = z.object({
|
|
@@ -6603,7 +7818,7 @@ export const SendAgentMessageResponseMessageSchema = z.object({
|
|
|
6603
7818
|
error: z.string().nullable(),
|
|
6604
7819
|
// Set when the message was parked for the next turn rather than dispatched
|
|
6605
7820
|
// (`delivery: "queue"` against a busy agent). `queuedMessageId` is the
|
|
6606
|
-
// entry's id in `AgentSnapshotPayload.queuedMessages`
|
|
7821
|
+
// entry's id in `AgentSnapshotPayload.queuedMessages` - the key the sender
|
|
6607
7822
|
// uses to find its own entry again. Absent ⇒ dispatched now (or old daemon).
|
|
6608
7823
|
// COMPAT(steerQueue): added in v0.6.8, drop the gate when floor >= v0.6.8.
|
|
6609
7824
|
queued: z.boolean().optional(),
|
|
@@ -6766,6 +7981,37 @@ export const DaemonGetStatusResponseSchema = z.object({
|
|
|
6766
7981
|
})
|
|
6767
7982
|
.passthrough(),
|
|
6768
7983
|
});
|
|
7984
|
+
export const HubRelationshipStatusSchema = z.object({
|
|
7985
|
+
state: z.enum([
|
|
7986
|
+
"not_connected",
|
|
7987
|
+
"connecting",
|
|
7988
|
+
"connected",
|
|
7989
|
+
"reconnecting",
|
|
7990
|
+
"disconnecting",
|
|
7991
|
+
"revoked",
|
|
7992
|
+
]),
|
|
7993
|
+
daemonId: z.string().nullable(),
|
|
7994
|
+
hubOrigin: z.string().nullable(),
|
|
7995
|
+
scopes: z.array(z.string()),
|
|
7996
|
+
connectedAt: z.string().nullable(),
|
|
7997
|
+
lastError: z.string().nullable(),
|
|
7998
|
+
});
|
|
7999
|
+
export const HubManagementDaemonConnectResponseSchema = z.object({
|
|
8000
|
+
type: z.literal("hub.management.daemon.connect.response"),
|
|
8001
|
+
payload: z.object({ requestId: z.string(), status: HubRelationshipStatusSchema }),
|
|
8002
|
+
});
|
|
8003
|
+
export const HubManagementDaemonGetStatusResponseSchema = z.object({
|
|
8004
|
+
type: z.literal("hub.management.daemon.get_status.response"),
|
|
8005
|
+
payload: z.object({ requestId: z.string(), status: HubRelationshipStatusSchema }),
|
|
8006
|
+
});
|
|
8007
|
+
export const HubManagementDaemonDisconnectResponseSchema = z.object({
|
|
8008
|
+
type: z.literal("hub.management.daemon.disconnect.response"),
|
|
8009
|
+
payload: z.object({
|
|
8010
|
+
requestId: z.string(),
|
|
8011
|
+
status: HubRelationshipStatusSchema,
|
|
8012
|
+
warning: z.string().optional(),
|
|
8013
|
+
}),
|
|
8014
|
+
});
|
|
6769
8015
|
export const DaemonGetPairingOfferResponseSchema = z.object({
|
|
6770
8016
|
type: z.literal("daemon.get_pairing_offer.response"),
|
|
6771
8017
|
payload: z
|
|
@@ -6979,8 +8225,7 @@ const CheckoutPrGithubRepositoryPolicySchema = z
|
|
|
6979
8225
|
rebaseMergeAllowed: false,
|
|
6980
8226
|
viewerDefaultMergeMethod: null,
|
|
6981
8227
|
});
|
|
6982
|
-
const
|
|
6983
|
-
.object({
|
|
8228
|
+
const CheckoutPrGithubStatusObjectSchema = z.object({
|
|
6984
8229
|
mergeStateStatus: z.string().nullable().optional().default(null),
|
|
6985
8230
|
autoMergeRequest: CheckoutPrGithubAutoMergeRequestSchema,
|
|
6986
8231
|
viewerCanEnableAutoMerge: z.boolean().optional().default(false),
|
|
@@ -6990,9 +8235,23 @@ const CheckoutPrGithubStatusSchema = z
|
|
|
6990
8235
|
repository: CheckoutPrGithubRepositoryPolicySchema,
|
|
6991
8236
|
isMergeQueueEnabled: z.boolean().optional().default(false),
|
|
6992
8237
|
isInMergeQueue: z.boolean().optional().default(false),
|
|
6993
|
-
})
|
|
6994
|
-
|
|
8238
|
+
});
|
|
8239
|
+
const CheckoutPrGithubStatusSchema = CheckoutPrGithubStatusObjectSchema.optional();
|
|
8240
|
+
// The open facts envelope for forge-specific PR facts. Permanent - non-GitHub
|
|
8241
|
+
// forges deliver their native facts through it. The transitional piece is the
|
|
8242
|
+
// `github` mirror above, which stays populated for clients predating this
|
|
8243
|
+
// envelope; see COMPAT(forgeSpecific) in status-projection.ts for the shim.
|
|
8244
|
+
//
|
|
8245
|
+
// NOTE: `forgeSpecific.forge` is a FACTS-FAMILY tag, not the workspace brand id.
|
|
8246
|
+
// The whole Gitea family (gitea, forgejo, codeberg) emits `forge: "gitea"` here
|
|
8247
|
+
// because they share one facts shape, while the top-level `forge` above carries
|
|
8248
|
+
// the specific brand. Validation of family-specific payloads happens at runtime
|
|
8249
|
+
// in the consumer that knows that forge family.
|
|
8250
|
+
const CheckoutPrForgeSpecificSchema = z.unknown().optional();
|
|
6995
8251
|
export const CheckoutPrStatusSchema = z.object({
|
|
8252
|
+
// COMPAT(forge): added in v0.1.106, remove the default after 2026-12-27 once daemon floor >= v0.1.106.
|
|
8253
|
+
forge: z.string().optional().default("github"),
|
|
8254
|
+
projectPath: z.string().optional(),
|
|
6996
8255
|
number: z.number().optional(),
|
|
6997
8256
|
url: z.string(),
|
|
6998
8257
|
title: z.string(),
|
|
@@ -7025,6 +8284,14 @@ export const CheckoutPrStatusSchema = z.object({
|
|
|
7025
8284
|
github: CheckoutPrGithubStatusSchema,
|
|
7026
8285
|
// Provider-neutral per-PR hosting facts. Absent from old daemons; for
|
|
7027
8286
|
// GitHub projects both this and the legacy `github` field are populated.
|
|
8287
|
+
//
|
|
8288
|
+
// NOT a shim, and deliberately untagged: this does not collapse into `forge`.
|
|
8289
|
+
// Otto registers every hosting provider into the forge registry under the
|
|
8290
|
+
// forge id `github`, which is the provider-routing facade rather than the gh
|
|
8291
|
+
// CLI (bootstrap.ts, `createGitHostingResolver`). So `forge` reads "github"
|
|
8292
|
+
// for a Bitbucket workspace and only `hosting.provider` carries the truth.
|
|
8293
|
+
// The two disagree by design; a reader wanting the real provider must use
|
|
8294
|
+
// this field.
|
|
7028
8295
|
hosting: z
|
|
7029
8296
|
.object({
|
|
7030
8297
|
provider: GitHostingProviderIdWireSchema,
|
|
@@ -7038,7 +8305,9 @@ export const CheckoutPrStatusSchema = z.object({
|
|
|
7038
8305
|
.optional(),
|
|
7039
8306
|
})
|
|
7040
8307
|
.optional(),
|
|
8308
|
+
forgeSpecific: CheckoutPrForgeSpecificSchema,
|
|
7041
8309
|
});
|
|
8310
|
+
export const ForgeAuthStateSchema = z.unknown().optional();
|
|
7042
8311
|
const CheckoutPrStatusPayloadSchema = z.object({
|
|
7043
8312
|
cwd: z.string(),
|
|
7044
8313
|
status: CheckoutPrStatusSchema.nullable(),
|
|
@@ -7048,6 +8317,9 @@ const CheckoutPrStatusPayloadSchema = z.object({
|
|
|
7048
8317
|
githubFeaturesEnabled: z.boolean(),
|
|
7049
8318
|
// Provider-neutral enablement. Present even when status is null so clients
|
|
7050
8319
|
// can drive search/create-PR affordances for the workspace's provider.
|
|
8320
|
+
// Permanent for the same reason as the `hosting` block on the PR status
|
|
8321
|
+
// schema above: `forge` is a routing-facade id and cannot answer "which
|
|
8322
|
+
// provider is this really".
|
|
7051
8323
|
hosting: z
|
|
7052
8324
|
.object({
|
|
7053
8325
|
provider: GitHostingProviderIdWireSchema,
|
|
@@ -7055,6 +8327,13 @@ const CheckoutPrStatusPayloadSchema = z.object({
|
|
|
7055
8327
|
capabilities: GitHostingCapabilitiesSchema.optional(),
|
|
7056
8328
|
})
|
|
7057
8329
|
.optional(),
|
|
8330
|
+
// COMPAT(forgeAuthState): added in v0.1.106, remove after 2026-12-27. Optional richer
|
|
8331
|
+
// signal that supersedes githubFeaturesEnabled. The legacy boolean stays for old clients
|
|
8332
|
+
// and may remain true for non-auth error payloads so old clients still show the error.
|
|
8333
|
+
// Drop the boolean once the daemon floor >= v0.1.106.
|
|
8334
|
+
authState: ForgeAuthStateSchema,
|
|
8335
|
+
// COMPAT(forge): added in v0.1.106, remove the default after 2026-12-27 once daemon floor >= v0.1.106.
|
|
8336
|
+
forge: z.string().optional().default("github"),
|
|
7058
8337
|
error: CheckoutErrorSchema.nullable(),
|
|
7059
8338
|
requestId: z.string(),
|
|
7060
8339
|
});
|
|
@@ -7082,6 +8361,8 @@ const CheckoutDiffSubscriptionPayloadSchema = z.object({
|
|
|
7082
8361
|
cwd: z.string(),
|
|
7083
8362
|
files: z.array(ParsedDiffFileSchema),
|
|
7084
8363
|
error: CheckoutErrorSchema.nullable(),
|
|
8364
|
+
// COMPAT(diffTooLarge): added in v0.2.4, keep optional until the daemon floor is v0.2.4.
|
|
8365
|
+
diffTooLarge: z.boolean().optional(),
|
|
7085
8366
|
});
|
|
7086
8367
|
export const SubscribeCheckoutDiffResponseSchema = z.object({
|
|
7087
8368
|
type: z.literal("subscribe_checkout_diff_response"),
|
|
@@ -7232,7 +8513,7 @@ export const GitFileHistoryEntrySchema = z.object({
|
|
|
7232
8513
|
authoredAt: z.number(),
|
|
7233
8514
|
committerName: z.string(),
|
|
7234
8515
|
committedAt: z.number(),
|
|
7235
|
-
// The file's name at this commit
|
|
8516
|
+
// The file's name at this commit - differs from the requested path across a
|
|
7236
8517
|
// rename. Diff requests must echo this one back, not the current name.
|
|
7237
8518
|
path: z.string(),
|
|
7238
8519
|
previousPath: z.string().optional(),
|
|
@@ -7263,7 +8544,7 @@ export const CheckoutGitFileCommitDiffResponseSchema = z.object({
|
|
|
7263
8544
|
diff: z.string(),
|
|
7264
8545
|
// Highlighted/parsed form of the same diff, when it parsed cleanly.
|
|
7265
8546
|
structured: z.array(ParsedDiffFileSchema).optional(),
|
|
7266
|
-
// The file's previous revision
|
|
8547
|
+
// The file's previous revision - the diff's left-hand side, and the honest
|
|
7267
8548
|
// label for it. Absent when this revision created the file.
|
|
7268
8549
|
previousSha: z.string().optional(),
|
|
7269
8550
|
previousPath: z.string().optional(),
|
|
@@ -7378,6 +8659,18 @@ export const CheckoutPrMergeResponseSchema = z.object({
|
|
|
7378
8659
|
requestId: z.string(),
|
|
7379
8660
|
}),
|
|
7380
8661
|
});
|
|
8662
|
+
export const CheckoutForgeSetAutoMergeResponseSchema = z.object({
|
|
8663
|
+
type: z.literal("checkout.forge.set_auto_merge.response"),
|
|
8664
|
+
payload: z.object({
|
|
8665
|
+
cwd: z.string(),
|
|
8666
|
+
enabled: z.boolean(),
|
|
8667
|
+
success: z.boolean(),
|
|
8668
|
+
error: CheckoutErrorSchema.nullable(),
|
|
8669
|
+
requestId: z.string(),
|
|
8670
|
+
}),
|
|
8671
|
+
});
|
|
8672
|
+
// COMPAT(githubAutoMergeRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
8673
|
+
// all supported clients use checkout.forge.set_auto_merge.*.
|
|
7381
8674
|
export const CheckoutGithubSetAutoMergeResponseSchema = z.object({
|
|
7382
8675
|
type: z.literal("checkout.github.set_auto_merge.response"),
|
|
7383
8676
|
payload: z.object({
|
|
@@ -7454,6 +8747,29 @@ export const PreviewStopResponseSchema = z.object({
|
|
|
7454
8747
|
requestId: z.string(),
|
|
7455
8748
|
}),
|
|
7456
8749
|
});
|
|
8750
|
+
export const CheckoutCommitsListResponseSchema = z.object({
|
|
8751
|
+
type: z.literal("checkout.commits.list.response"),
|
|
8752
|
+
payload: z.object({
|
|
8753
|
+
cwd: z.string(),
|
|
8754
|
+
baseRef: z.string().nullable(),
|
|
8755
|
+
commits: z.array(CheckoutCommitSchema),
|
|
8756
|
+
error: CheckoutErrorSchema.nullable(),
|
|
8757
|
+
requestId: z.string(),
|
|
8758
|
+
}),
|
|
8759
|
+
});
|
|
8760
|
+
export const CheckoutCommitFileDiffResponseSchema = z.object({
|
|
8761
|
+
type: z.literal("checkout.commits.file_diff.response"),
|
|
8762
|
+
payload: z.object({
|
|
8763
|
+
cwd: z.string(),
|
|
8764
|
+
sha: z.string(),
|
|
8765
|
+
path: z.string(),
|
|
8766
|
+
// null when the file is absent from the commit or carries no textual diff
|
|
8767
|
+
// (e.g. binary-only changes).
|
|
8768
|
+
file: ParsedDiffFileSchema.nullable(),
|
|
8769
|
+
error: CheckoutErrorSchema.nullable(),
|
|
8770
|
+
requestId: z.string(),
|
|
8771
|
+
}),
|
|
8772
|
+
});
|
|
7457
8773
|
const CheckoutGithubCheckAnnotationSchema = z.object({
|
|
7458
8774
|
path: z.string().optional(),
|
|
7459
8775
|
startLine: z.number().optional(),
|
|
@@ -7472,6 +8788,31 @@ const CheckoutGithubCheckJobSchema = z.object({
|
|
|
7472
8788
|
logTail: z.string().optional(),
|
|
7473
8789
|
logTruncated: z.boolean().optional(),
|
|
7474
8790
|
});
|
|
8791
|
+
// Statuses stay open strings so future forge values cannot break parsing.
|
|
8792
|
+
const CheckoutPipelineJobSchema = z.object({
|
|
8793
|
+
id: z.number(),
|
|
8794
|
+
name: z.string(),
|
|
8795
|
+
stage: z.string(),
|
|
8796
|
+
status: z.string(),
|
|
8797
|
+
rawStatus: z.string(),
|
|
8798
|
+
url: z.string().nullable().optional().default(null),
|
|
8799
|
+
allowFailure: z.boolean().optional().default(false),
|
|
8800
|
+
durationSeconds: z.number().nullable().optional().default(null),
|
|
8801
|
+
});
|
|
8802
|
+
const CheckoutPipelineStageSchema = z.object({
|
|
8803
|
+
name: z.string(),
|
|
8804
|
+
status: z.string(),
|
|
8805
|
+
jobs: z.array(CheckoutPipelineJobSchema).optional().default([]),
|
|
8806
|
+
});
|
|
8807
|
+
const CheckoutPipelineSchema = z.object({
|
|
8808
|
+
id: z.number(),
|
|
8809
|
+
status: z.string(),
|
|
8810
|
+
rawStatus: z.string(),
|
|
8811
|
+
url: z.string().nullable().optional().default(null),
|
|
8812
|
+
ref: z.string().nullable().optional().default(null),
|
|
8813
|
+
sha: z.string().nullable().optional().default(null),
|
|
8814
|
+
stages: z.array(CheckoutPipelineStageSchema).optional().default([]),
|
|
8815
|
+
});
|
|
7475
8816
|
export const CheckoutGithubCheckDetailsSchema = z.object({
|
|
7476
8817
|
checkRunId: z.number(),
|
|
7477
8818
|
workflowRunId: z.number().nullable().optional(),
|
|
@@ -7491,13 +8832,28 @@ export const CheckoutGithubCheckDetailsSchema = z.object({
|
|
|
7491
8832
|
annotations: z.array(CheckoutGithubCheckAnnotationSchema).optional().default([]),
|
|
7492
8833
|
failedJobs: z.array(CheckoutGithubCheckJobSchema).optional().default([]),
|
|
7493
8834
|
truncated: z.boolean().optional().default(false),
|
|
8835
|
+
// No default: server CheckDetails keeps this optional and GitHub leaves it absent.
|
|
8836
|
+
pipeline: CheckoutPipelineSchema.nullable().optional(),
|
|
7494
8837
|
});
|
|
8838
|
+
export const CheckoutCheckDetailsSchema = CheckoutGithubCheckDetailsSchema;
|
|
8839
|
+
export const CheckoutForgeGetCheckDetailsResponseSchema = z.object({
|
|
8840
|
+
type: z.literal("checkout.forge.get_check_details.response"),
|
|
8841
|
+
payload: z.object({
|
|
8842
|
+
cwd: z.string(),
|
|
8843
|
+
success: z.boolean(),
|
|
8844
|
+
details: CheckoutCheckDetailsSchema.nullable().optional().default(null),
|
|
8845
|
+
error: CheckoutErrorSchema.nullable(),
|
|
8846
|
+
requestId: z.string(),
|
|
8847
|
+
}),
|
|
8848
|
+
});
|
|
8849
|
+
// COMPAT(githubCheckDetailsRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
8850
|
+
// all supported clients use checkout.forge.get_check_details.*.
|
|
7495
8851
|
export const CheckoutGithubGetCheckDetailsResponseSchema = z.object({
|
|
7496
8852
|
type: z.literal("checkout.github.get_check_details.response"),
|
|
7497
8853
|
payload: z.object({
|
|
7498
8854
|
cwd: z.string(),
|
|
7499
8855
|
success: z.boolean(),
|
|
7500
|
-
details:
|
|
8856
|
+
details: CheckoutCheckDetailsSchema.nullable().optional().default(null),
|
|
7501
8857
|
error: CheckoutErrorSchema.nullable(),
|
|
7502
8858
|
requestId: z.string(),
|
|
7503
8859
|
}),
|
|
@@ -7557,6 +8913,16 @@ const PullRequestTimelineCommentItemSchema = z.object({
|
|
|
7557
8913
|
// threads under their parent review. Absent on issue comments and on
|
|
7558
8914
|
// timelines from daemons that predate the field.
|
|
7559
8915
|
reviewId: z.string().optional(),
|
|
8916
|
+
// Forge-neutral discussion/thread id this comment belongs to, independent of a
|
|
8917
|
+
// file position. GitLab maps its discussion id here so general (non-file)
|
|
8918
|
+
// reply chains group into one thread; file-position threads also carry it.
|
|
8919
|
+
// Absent on standalone comments and on timelines from daemons that predate it.
|
|
8920
|
+
threadId: z.string().optional(),
|
|
8921
|
+
// Forge-neutral resolution state for a thread that has no file position, e.g. a
|
|
8922
|
+
// GitLab general (non-file) discussion that is resolvable. File-position threads
|
|
8923
|
+
// carry their resolution under `location.isResolved` instead. Absent on ordinary
|
|
8924
|
+
// comments, on forges that expose no thread resolution, and on older timelines.
|
|
8925
|
+
threadIsResolved: z.boolean().optional(),
|
|
7560
8926
|
location: z
|
|
7561
8927
|
.object({
|
|
7562
8928
|
path: z.string(),
|
|
@@ -7592,6 +8958,10 @@ export const PullRequestTimelineResponseSchema = z.object({
|
|
|
7592
8958
|
error: PullRequestTimelineErrorSchema.nullable().optional().default(null),
|
|
7593
8959
|
requestId: z.string().optional().default(""),
|
|
7594
8960
|
githubFeaturesEnabled: z.boolean().optional().default(true),
|
|
8961
|
+
// COMPAT(forgeAuthState): added in v0.1.106, remove after 2026-12-27. Optional richer
|
|
8962
|
+
// signal that supersedes githubFeaturesEnabled, mirroring CheckoutPrStatusPayloadSchema.
|
|
8963
|
+
// Drop the boolean once the daemon floor >= v0.1.106.
|
|
8964
|
+
authState: ForgeAuthStateSchema,
|
|
7595
8965
|
})
|
|
7596
8966
|
.optional()
|
|
7597
8967
|
.prefault({}),
|
|
@@ -7681,14 +9051,29 @@ export const BranchSuggestionsResponseSchema = z.object({
|
|
|
7681
9051
|
requestId: z.string(),
|
|
7682
9052
|
}),
|
|
7683
9053
|
});
|
|
9054
|
+
const ForgeSearchResponsePayloadSchema = z.object({
|
|
9055
|
+
items: z.array(z.unknown()),
|
|
9056
|
+
authState: z.unknown().optional(),
|
|
9057
|
+
error: z.string().nullable(),
|
|
9058
|
+
requestId: z.string(),
|
|
9059
|
+
});
|
|
9060
|
+
const GitHubSearchResponsePayloadSchema = z.object({
|
|
9061
|
+
items: z.array(z.unknown()),
|
|
9062
|
+
featuresEnabled: z.boolean().optional(),
|
|
9063
|
+
authState: z.unknown().optional(),
|
|
9064
|
+
githubFeaturesEnabled: z.boolean().optional(),
|
|
9065
|
+
error: z.string().nullable(),
|
|
9066
|
+
requestId: z.string(),
|
|
9067
|
+
});
|
|
9068
|
+
export const ForgeSearchResponseSchema = z.object({
|
|
9069
|
+
type: z.literal("forge.search.response"),
|
|
9070
|
+
payload: ForgeSearchResponsePayloadSchema,
|
|
9071
|
+
});
|
|
9072
|
+
// COMPAT(githubSearchRpc): added in v0.1.106, remove after 2026-12-28 once
|
|
9073
|
+
// clients use forge.search.*.
|
|
7684
9074
|
export const GitHubSearchResponseSchema = z.object({
|
|
7685
9075
|
type: z.literal("github_search_response"),
|
|
7686
|
-
payload:
|
|
7687
|
-
items: z.array(GitHubSearchItemSchema),
|
|
7688
|
-
githubFeaturesEnabled: z.boolean(),
|
|
7689
|
-
error: z.string().nullable(),
|
|
7690
|
-
requestId: z.string(),
|
|
7691
|
-
}),
|
|
9076
|
+
payload: GitHubSearchResponsePayloadSchema,
|
|
7692
9077
|
});
|
|
7693
9078
|
export const HostingSearchResponseSchema = z.object({
|
|
7694
9079
|
type: z.literal("hosting.search.response"),
|
|
@@ -7769,6 +9154,64 @@ export const FileExplorerResponseSchema = z.object({
|
|
|
7769
9154
|
requestId: z.string(),
|
|
7770
9155
|
}),
|
|
7771
9156
|
});
|
|
9157
|
+
export const FileSubscribeResponseSchema = z.object({
|
|
9158
|
+
type: z.literal("fs.file.subscribe.response"),
|
|
9159
|
+
payload: z.object({
|
|
9160
|
+
subscriptionId: z.string(),
|
|
9161
|
+
initial: FileVersionSchema,
|
|
9162
|
+
requestId: z.string(),
|
|
9163
|
+
}),
|
|
9164
|
+
});
|
|
9165
|
+
export const FileUnsubscribeResponseSchema = z.object({
|
|
9166
|
+
type: z.literal("fs.file.unsubscribe.response"),
|
|
9167
|
+
payload: z.object({
|
|
9168
|
+
subscriptionId: z.string(),
|
|
9169
|
+
requestId: z.string(),
|
|
9170
|
+
}),
|
|
9171
|
+
});
|
|
9172
|
+
export const FsFileWriteResultSchema = z.discriminatedUnion("status", [
|
|
9173
|
+
z.object({
|
|
9174
|
+
status: z.literal("written"),
|
|
9175
|
+
modifiedAt: z.string(),
|
|
9176
|
+
size: z.number(),
|
|
9177
|
+
revision: z.string().optional(),
|
|
9178
|
+
}),
|
|
9179
|
+
z.object({ status: z.literal("conflict"), version: FileVersionSchema }),
|
|
9180
|
+
z.object({ status: z.literal("error"), error: z.string() }),
|
|
9181
|
+
]);
|
|
9182
|
+
export const FsFileWriteResponseSchema = z.object({
|
|
9183
|
+
type: z.literal("fs.file.write.response"),
|
|
9184
|
+
payload: z.object({
|
|
9185
|
+
result: FsFileWriteResultSchema,
|
|
9186
|
+
requestId: z.string(),
|
|
9187
|
+
}),
|
|
9188
|
+
});
|
|
9189
|
+
export const FsFileWriteBinaryResultSchema = z.discriminatedUnion("status", [
|
|
9190
|
+
z.object({
|
|
9191
|
+
status: z.literal("written"),
|
|
9192
|
+
modifiedAt: z.string(),
|
|
9193
|
+
size: z.number(),
|
|
9194
|
+
}),
|
|
9195
|
+
// The target is already there and the request did not ask to replace it.
|
|
9196
|
+
z.object({ status: z.literal("exists") }),
|
|
9197
|
+
z.object({ status: z.literal("error"), error: z.string() }),
|
|
9198
|
+
]);
|
|
9199
|
+
export const FsFileWriteBinaryResponseSchema = z.object({
|
|
9200
|
+
type: z.literal("fs.file.write_binary.response"),
|
|
9201
|
+
payload: z.object({
|
|
9202
|
+
cwd: z.string(),
|
|
9203
|
+
path: z.string(),
|
|
9204
|
+
result: FsFileWriteBinaryResultSchema,
|
|
9205
|
+
requestId: z.string(),
|
|
9206
|
+
}),
|
|
9207
|
+
});
|
|
9208
|
+
export const FileUpdateSchema = z.object({
|
|
9209
|
+
type: z.literal("fs.file.update"),
|
|
9210
|
+
payload: z.object({
|
|
9211
|
+
subscriptionId: z.string(),
|
|
9212
|
+
version: FileVersionSchema,
|
|
9213
|
+
}),
|
|
9214
|
+
});
|
|
7772
9215
|
const ProjectIconSchema = z.object({
|
|
7773
9216
|
data: z.string(),
|
|
7774
9217
|
mimeType: z.string(),
|
|
@@ -7865,7 +9308,7 @@ export const FileCreateResponseSchema = z.object({
|
|
|
7865
9308
|
});
|
|
7866
9309
|
/**
|
|
7867
9310
|
* Delete outcome. `not_empty` means the target is a directory with children and
|
|
7868
|
-
* the request did not set `recursive`
|
|
9311
|
+
* the request did not set `recursive` - nothing was removed, and the client can
|
|
7869
9312
|
* re-ask with the stronger confirmation.
|
|
7870
9313
|
*/
|
|
7871
9314
|
export const FileDeleteResultSchema = z.discriminatedUnion("status", [
|
|
@@ -7998,7 +9441,7 @@ export const CodeDefinitionLocationSchema = z.object({
|
|
|
7998
9441
|
/**
|
|
7999
9442
|
* Which registry row answered (`typescript`, `csharp`, …). The multi-hit picker
|
|
8000
9443
|
* shows it, so a user looking at two candidates can tell whether a language server
|
|
8001
|
-
* resolved them or the name index guessed
|
|
9444
|
+
* resolved them or the name index guessed - which changes how much to trust the
|
|
8002
9445
|
* list. Absent from old daemons.
|
|
8003
9446
|
*/
|
|
8004
9447
|
serverId: z.string().optional(),
|
|
@@ -8006,7 +9449,7 @@ export const CodeDefinitionLocationSchema = z.object({
|
|
|
8006
9449
|
/**
|
|
8007
9450
|
* Three-valued on purpose. `unavailable` (no server for this language on the host) and
|
|
8008
9451
|
* `indexing` (the server is up but still building its project model) are different
|
|
8009
|
-
* answers to the user, and neither is "not found"
|
|
9452
|
+
* answers to the user, and neither is "not found" - reporting either as an empty
|
|
8010
9453
|
* result is how a working feature reads as broken.
|
|
8011
9454
|
*/
|
|
8012
9455
|
export const CodeDefinitionStatusSchema = z.enum(["ok", "indexing", "unavailable"]);
|
|
@@ -8081,7 +9524,7 @@ export const CodeRenameEditSchema = z.object({
|
|
|
8081
9524
|
newText: z.string(),
|
|
8082
9525
|
/**
|
|
8083
9526
|
* The text this edit expects to replace. Carried so the dry run can show what is being
|
|
8084
|
-
* changed rather than only what it becomes
|
|
9527
|
+
* changed rather than only what it becomes - and, on the daemon side, so the run can tell
|
|
8085
9528
|
* that a file moved under the plan. For a rename this is always one identifier.
|
|
8086
9529
|
*/
|
|
8087
9530
|
oldText: z.string().default(""),
|
|
@@ -8117,7 +9560,7 @@ export const CodeRenamePreviewResponseSchema = z.object({
|
|
|
8117
9560
|
* workspace. Collapsing them into one failure is how "nothing happened" becomes unexplainable.
|
|
8118
9561
|
*/
|
|
8119
9562
|
/**
|
|
8120
|
-
* Whether the run HAPPENED
|
|
9563
|
+
* Whether the run HAPPENED - deliberately not whether everything applied.
|
|
8121
9564
|
*
|
|
8122
9565
|
* A run where two of fourteen edits no longer fit is still a run that took place, and the
|
|
8123
9566
|
* twelve that landed are real. Collapsing that into a failure would hide them, and hiding a
|
|
@@ -8234,7 +9677,7 @@ export const LspServerStopResponseSchema = z.object({
|
|
|
8234
9677
|
export const SolutionFormatSchema = z.enum(["sln", "slnx"]);
|
|
8235
9678
|
/** One solution a workspace contains. Enough to populate the switcher's picker, nothing more. */
|
|
8236
9679
|
export const SolutionRefSchema = z.object({
|
|
8237
|
-
/** Workspace-relative, forward slashes
|
|
9680
|
+
/** Workspace-relative, forward slashes - the identity used by every later request. */
|
|
8238
9681
|
path: z.string(),
|
|
8239
9682
|
/** File name without the extension, which is what a .NET developer calls the solution. */
|
|
8240
9683
|
name: z.string(),
|
|
@@ -8247,7 +9690,7 @@ export const CodeSolutionListResponseSchema = z.object({
|
|
|
8247
9690
|
/**
|
|
8248
9691
|
* Empty means the switcher never appears and the Files tab behaves exactly as it does today.
|
|
8249
9692
|
* That is also what a disabled feature, a host with no .NET SDK, and a workspace with no
|
|
8250
|
-
* solution all return
|
|
9693
|
+
* solution all return - the client has one silent case to handle, not four.
|
|
8251
9694
|
*/
|
|
8252
9695
|
solutions: z.array(SolutionRefSchema),
|
|
8253
9696
|
error: z.string().nullable(),
|
|
@@ -8277,8 +9720,8 @@ export const SolutionTreeProjectSchema = z.object({
|
|
|
8277
9720
|
*/
|
|
8278
9721
|
path: z.string(),
|
|
8279
9722
|
/**
|
|
8280
|
-
* A project the solution names outside the workspace root. Shown and opened like any other
|
|
8281
|
-
* the solution file is the authority naming it, so this is not free browsing
|
|
9723
|
+
* A project the solution names outside the workspace root. Shown and opened like any other -
|
|
9724
|
+
* the solution file is the authority naming it, so this is not free browsing - but editing one
|
|
8282
9725
|
* warns, and it is absent from every git surface. See docs/solution-view.md.
|
|
8283
9726
|
*/
|
|
8284
9727
|
outsideWorkspace: z.boolean(),
|
|
@@ -8296,7 +9739,7 @@ export const CodeSolutionGetTreeResponseSchema = z.object({
|
|
|
8296
9739
|
format: SolutionFormatSchema.default("sln"),
|
|
8297
9740
|
folders: z.array(SolutionTreeFolderSchema),
|
|
8298
9741
|
projects: z.array(SolutionTreeProjectSchema),
|
|
8299
|
-
/** Solution configurations and platforms
|
|
9742
|
+
/** Solution configurations and platforms - first-class .NET concepts no CLI surfaces. */
|
|
8300
9743
|
buildTypes: z.array(z.string()),
|
|
8301
9744
|
platforms: z.array(z.string()),
|
|
8302
9745
|
error: z.string().nullable(),
|
|
@@ -8333,7 +9776,7 @@ export const SolutionProjectNodeSchema = z.discriminatedUnion("kind", [
|
|
|
8333
9776
|
name: z.string(),
|
|
8334
9777
|
path: z.string(),
|
|
8335
9778
|
outsideWorkspace: z.boolean(),
|
|
8336
|
-
/** `Compile`, `Content`, `EmbeddedResource`, …
|
|
9779
|
+
/** `Compile`, `Content`, `EmbeddedResource`, … - MSBuild's own item type. */
|
|
8337
9780
|
itemType: z.string(),
|
|
8338
9781
|
isImplicit: z.boolean(),
|
|
8339
9782
|
}),
|
|
@@ -8389,7 +9832,7 @@ export const FileSearchResultEventSchema = z.object({
|
|
|
8389
9832
|
cwd: z.string(),
|
|
8390
9833
|
searchId: z.string(),
|
|
8391
9834
|
path: z.string(),
|
|
8392
|
-
/** File content hash at match time
|
|
9835
|
+
/** File content hash at match time - the replace precondition. */
|
|
8393
9836
|
hash: z.string(),
|
|
8394
9837
|
matches: z.array(FileSearchMatchSchema),
|
|
8395
9838
|
}),
|
|
@@ -8759,7 +10202,72 @@ export const DaemonUpdateProgressMessageSchema = z.object({
|
|
|
8759
10202
|
phase: z.enum(["starting", "downloading", "installing", "complete"]),
|
|
8760
10203
|
}),
|
|
8761
10204
|
});
|
|
10205
|
+
export const HubExecutionAgentCreateResponseSchema = z.object({
|
|
10206
|
+
type: z.literal("hub.execution.agent.create.response"),
|
|
10207
|
+
payload: z.object({
|
|
10208
|
+
requestId: z.string(),
|
|
10209
|
+
executionId: z.string(),
|
|
10210
|
+
agentId: z.string().nullable(),
|
|
10211
|
+
agent: AgentSnapshotPayloadSchema.nullable(),
|
|
10212
|
+
success: z.boolean(),
|
|
10213
|
+
error: z.string().nullable(),
|
|
10214
|
+
}),
|
|
10215
|
+
});
|
|
10216
|
+
export const HubExecutionControlResponseSchema = z.object({
|
|
10217
|
+
type: z.literal("hub.execution.control.response"),
|
|
10218
|
+
payload: z.object({
|
|
10219
|
+
requestId: z.string(),
|
|
10220
|
+
executionId: z.string(),
|
|
10221
|
+
action: HubExecutionControlActionSchema,
|
|
10222
|
+
success: z.boolean(),
|
|
10223
|
+
error: z.string().nullable(),
|
|
10224
|
+
}),
|
|
10225
|
+
});
|
|
10226
|
+
export const HubExecutionAgentUpdateSchema = z.object({
|
|
10227
|
+
type: z.literal("hub.execution.agent.update"),
|
|
10228
|
+
payload: z.object({
|
|
10229
|
+
executionId: z.string(),
|
|
10230
|
+
agentId: z.string(),
|
|
10231
|
+
agent: AgentSnapshotPayloadSchema,
|
|
10232
|
+
}),
|
|
10233
|
+
});
|
|
10234
|
+
export const HubExecutionAgentStreamSchema = z.object({
|
|
10235
|
+
type: z.literal("hub.execution.agent.stream"),
|
|
10236
|
+
payload: z.object({
|
|
10237
|
+
executionId: z.string(),
|
|
10238
|
+
agentId: z.string(),
|
|
10239
|
+
event: AgentStreamEventPayloadSchema,
|
|
10240
|
+
}),
|
|
10241
|
+
});
|
|
10242
|
+
export const HubExecutionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
10243
|
+
HubExecutionAgentCreateResponseSchema,
|
|
10244
|
+
HubExecutionControlResponseSchema,
|
|
10245
|
+
HubExecutionAgentUpdateSchema,
|
|
10246
|
+
HubExecutionAgentStreamSchema,
|
|
10247
|
+
]);
|
|
10248
|
+
export class HubMessageCorrelationError extends Error {
|
|
10249
|
+
constructor(messageType) {
|
|
10250
|
+
super(`Hub message ${messageType} has mismatched agent correlation`);
|
|
10251
|
+
this.name = "HubMessageCorrelationError";
|
|
10252
|
+
}
|
|
10253
|
+
}
|
|
10254
|
+
export function parseHubExecutionOutboundMessage(value) {
|
|
10255
|
+
const message = HubExecutionOutboundMessageSchema.parse(value);
|
|
10256
|
+
const payload = message.payload;
|
|
10257
|
+
if ("agent" in payload &&
|
|
10258
|
+
payload.agent !== null &&
|
|
10259
|
+
"agentId" in payload &&
|
|
10260
|
+
payload.agentId !== null &&
|
|
10261
|
+
payload.agent.id !== payload.agentId) {
|
|
10262
|
+
throw new HubMessageCorrelationError(message.type);
|
|
10263
|
+
}
|
|
10264
|
+
return message;
|
|
10265
|
+
}
|
|
8762
10266
|
export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
10267
|
+
HubExecutionAgentCreateResponseSchema,
|
|
10268
|
+
HubExecutionControlResponseSchema,
|
|
10269
|
+
HubExecutionAgentUpdateSchema,
|
|
10270
|
+
HubExecutionAgentStreamSchema,
|
|
8763
10271
|
BrowserAutomationExecuteRequestSchema,
|
|
8764
10272
|
ActivityLogMessageSchema,
|
|
8765
10273
|
AssistantChunkMessageSchema,
|
|
@@ -8778,6 +10286,8 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8778
10286
|
ArtifactUpdateMessageSchema,
|
|
8779
10287
|
AgentUpdateMessageSchema,
|
|
8780
10288
|
WorkspaceUpdateMessageSchema,
|
|
10289
|
+
ProjectUpdateMessageSchema,
|
|
10290
|
+
ProjectListResponseMessageSchema,
|
|
8781
10291
|
ScriptStatusUpdateMessageSchema,
|
|
8782
10292
|
WorkspaceSetupProgressMessageSchema,
|
|
8783
10293
|
WorkspaceSetupStatusResponseMessageSchema,
|
|
@@ -8790,8 +10300,14 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8790
10300
|
ProjectAddResponseSchema,
|
|
8791
10301
|
ProjectScaffoldResponseSchema,
|
|
8792
10302
|
ProjectScaffoldProgressSchema,
|
|
10303
|
+
ProjectCreateDirectoryResponseSchema,
|
|
8793
10304
|
OpenProjectResponseMessageSchema,
|
|
10305
|
+
WorkspaceGithubSearchRepositoriesResponseSchema,
|
|
10306
|
+
ProjectGithubCloneResponseSchema,
|
|
8794
10307
|
StartWorkspaceScriptResponseMessageSchema,
|
|
10308
|
+
WorkspaceScriptListResponseMessageSchema,
|
|
10309
|
+
WorkspaceScriptStartResponseMessageSchema,
|
|
10310
|
+
WorkspaceScriptStopResponseMessageSchema,
|
|
8795
10311
|
LegacyListAvailableEditorsResponseMessageSchema,
|
|
8796
10312
|
LegacyOpenInEditorResponseMessageSchema,
|
|
8797
10313
|
ArchiveWorkspaceResponseMessageSchema,
|
|
@@ -8801,6 +10317,11 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8801
10317
|
WorktreeReattachResponseSchema,
|
|
8802
10318
|
FetchAgentResponseMessageSchema,
|
|
8803
10319
|
FetchAgentTimelineResponseMessageSchema,
|
|
10320
|
+
ProviderSubagentListResponseMessageSchema,
|
|
10321
|
+
ProviderSubagentTimelineResponseMessageSchema,
|
|
10322
|
+
ProviderSubagentUpdateMessageSchema,
|
|
10323
|
+
SetAgentTimelineSubscriptionResponseMessageSchema,
|
|
10324
|
+
AgentAttentionRequiredMessageSchema,
|
|
8804
10325
|
AgentForkContextResponseMessageSchema,
|
|
8805
10326
|
CancelAgentResponseMessageSchema,
|
|
8806
10327
|
ClearAgentAttentionResponseMessageSchema,
|
|
@@ -8810,10 +10331,16 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8810
10331
|
SetVoiceModeResponseMessageSchema,
|
|
8811
10332
|
DaemonGetStatusResponseSchema,
|
|
8812
10333
|
DaemonGetPairingOfferResponseSchema,
|
|
10334
|
+
HubManagementDaemonConnectResponseSchema,
|
|
10335
|
+
HubManagementDaemonGetStatusResponseSchema,
|
|
10336
|
+
HubManagementDaemonDisconnectResponseSchema,
|
|
8813
10337
|
DiagnosticsResponseSchema,
|
|
8814
10338
|
GetDaemonConfigResponseMessageSchema,
|
|
8815
10339
|
SetDaemonConfigResponseMessageSchema,
|
|
8816
10340
|
ConnectorsListToolsResponseSchema,
|
|
10341
|
+
ConnectorsOauthAuthorizeResponseSchema,
|
|
10342
|
+
ConnectorsOauthDisconnectResponseSchema,
|
|
10343
|
+
ConnectorsOauthStatusMessageSchema,
|
|
8817
10344
|
SpeechSettingsGetOptionsResponseSchema,
|
|
8818
10345
|
SpeechTtsPreviewResponseSchema,
|
|
8819
10346
|
SpeechTtsSpeakResponseSchema,
|
|
@@ -8851,6 +10378,9 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8851
10378
|
ProjectLinksUnsetResponseSchema,
|
|
8852
10379
|
ProjectLinksChangedSchema,
|
|
8853
10380
|
WorkspaceTitleSetResponseSchema,
|
|
10381
|
+
WorkspacePinSetResponseSchema,
|
|
10382
|
+
WorkspaceRecoveryInspectResponseSchema,
|
|
10383
|
+
WorkspaceRecoveryRestoreResponseSchema,
|
|
8854
10384
|
WaitForFinishResponseMessageSchema,
|
|
8855
10385
|
AgentPermissionRequestMessageSchema,
|
|
8856
10386
|
AgentPermissionResolvedMessageSchema,
|
|
@@ -8880,6 +10410,14 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8880
10410
|
BrainHfSearchResponseSchema,
|
|
8881
10411
|
BrainHfQuantsResponseSchema,
|
|
8882
10412
|
BrainModelsAddResponseSchema,
|
|
10413
|
+
BrainModelsInventoryResponseSchema,
|
|
10414
|
+
BrainModelProfileGetResponseSchema,
|
|
10415
|
+
BrainModelProfileSetResponseSchema,
|
|
10416
|
+
BrainModelBudgetGetResponseSchema,
|
|
10417
|
+
BrainModelLoadResponseSchema,
|
|
10418
|
+
BrainModelUnloadResponseSchema,
|
|
10419
|
+
BrainModelDeleteResponseSchema,
|
|
10420
|
+
BrainLogsTailResponseSchema,
|
|
8883
10421
|
AgentArchivedMessageSchema,
|
|
8884
10422
|
CloseItemsResponseSchema,
|
|
8885
10423
|
CheckoutStatusResponseSchema,
|
|
@@ -8919,7 +10457,11 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8919
10457
|
CheckoutRefreshResponseSchema,
|
|
8920
10458
|
CheckoutPrCreateResponseSchema,
|
|
8921
10459
|
CheckoutPrMergeResponseSchema,
|
|
10460
|
+
CheckoutForgeSetAutoMergeResponseSchema,
|
|
8922
10461
|
CheckoutGithubSetAutoMergeResponseSchema,
|
|
10462
|
+
CheckoutCommitsListResponseSchema,
|
|
10463
|
+
CheckoutCommitFileDiffResponseSchema,
|
|
10464
|
+
CheckoutForgeGetCheckDetailsResponseSchema,
|
|
8923
10465
|
CheckoutGithubGetCheckDetailsResponseSchema,
|
|
8924
10466
|
PreviewListConfigResponseSchema,
|
|
8925
10467
|
PreviewStartResponseSchema,
|
|
@@ -8934,6 +10476,7 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8934
10476
|
StashListResponseSchema,
|
|
8935
10477
|
ValidateBranchResponseSchema,
|
|
8936
10478
|
BranchSuggestionsResponseSchema,
|
|
10479
|
+
ForgeSearchResponseSchema,
|
|
8937
10480
|
GitHubSearchResponseSchema,
|
|
8938
10481
|
HostingSearchResponseSchema,
|
|
8939
10482
|
HostingAuthStatusResponseSchema,
|
|
@@ -8944,6 +10487,11 @@ export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
8944
10487
|
OttoWorktreeArchiveResponseSchema,
|
|
8945
10488
|
CreateOttoWorktreeResponseSchema,
|
|
8946
10489
|
FileExplorerResponseSchema,
|
|
10490
|
+
FileSubscribeResponseSchema,
|
|
10491
|
+
FileUnsubscribeResponseSchema,
|
|
10492
|
+
FsFileWriteResponseSchema,
|
|
10493
|
+
FsFileWriteBinaryResponseSchema,
|
|
10494
|
+
FileUpdateSchema,
|
|
8947
10495
|
ProjectIconResponseSchema,
|
|
8948
10496
|
FileDownloadTokenResponseSchema,
|
|
8949
10497
|
FileUploadResponseSchema,
|
|
@@ -9063,8 +10611,11 @@ export const WSHelloMessageSchema = z.object({
|
|
|
9063
10611
|
voice: z.boolean().optional(),
|
|
9064
10612
|
pushNotifications: z.boolean().optional(),
|
|
9065
10613
|
[CLIENT_CAPS.reasoningMergeEnum]: z.boolean().optional(),
|
|
10614
|
+
[CLIENT_CAPS.selectiveAgentTimeline]: z.boolean().optional(),
|
|
9066
10615
|
[CLIENT_CAPS.customModeIcons]: z.boolean().optional(),
|
|
9067
10616
|
[CLIENT_CAPS.terminalReflowableSnapshot]: z.boolean().optional(),
|
|
10617
|
+
[CLIENT_CAPS.providerSubagents]: z.boolean().optional(),
|
|
10618
|
+
[CLIENT_CAPS.projectUpdates]: z.boolean().optional(),
|
|
9068
10619
|
[CLIENT_CAPS.browserHost]: BrowserAutomationHostCapabilitySchema.optional(),
|
|
9069
10620
|
})
|
|
9070
10621
|
.passthrough()
|