@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.
Files changed (66) hide show
  1. package/dist/agent-attention-notification.d.ts +2 -0
  2. package/dist/agent-attention-notification.js +2 -1
  3. package/dist/agent-deep-link.d.ts +8 -0
  4. package/dist/agent-deep-link.js +49 -0
  5. package/dist/agent-labels.js +4 -4
  6. package/dist/agent-personalities.d.ts +2 -2
  7. package/dist/agent-personalities.js +17 -17
  8. package/dist/agent-teams.d.ts +4 -4
  9. package/dist/agent-teams.js +5 -5
  10. package/dist/agent-types.d.ts +12 -10
  11. package/dist/agent-types.js +1 -1
  12. package/dist/artifacts/rpc-schemas.js +4 -4
  13. package/dist/artifacts/types.js +3 -3
  14. package/dist/binary-frames/file-transfer.d.ts +1 -0
  15. package/dist/binary-frames/file-transfer.js +1 -0
  16. package/dist/browser-automation/rpc-schemas.js +1 -1
  17. package/dist/client-capabilities.d.ts +3 -0
  18. package/dist/client-capabilities.js +9 -0
  19. package/dist/daemon-endpoints.d.ts +1 -1
  20. package/dist/default-personalities.js +11 -11
  21. package/dist/effort.d.ts +1 -1
  22. package/dist/effort.js +2 -2
  23. package/dist/forge-manifest.d.ts +66 -0
  24. package/dist/forge-manifest.js +92 -0
  25. package/dist/generated/validation/ws-outbound.aot.js +77653 -51519
  26. package/dist/git-hosting.js +3 -3
  27. package/dist/git-remote.d.ts +17 -0
  28. package/dist/git-remote.js +23 -2
  29. package/dist/judge-verdict.d.ts +1 -1
  30. package/dist/judge-verdict.js +2 -2
  31. package/dist/messages.d.ts +10634 -135
  32. package/dist/messages.js +1744 -193
  33. package/dist/model-tiers.d.ts +3 -3
  34. package/dist/model-tiers.js +4 -4
  35. package/dist/observed-subagent-title.d.ts +2 -2
  36. package/dist/observed-subagent-title.js +4 -4
  37. package/dist/orchestration.d.ts +3 -3
  38. package/dist/orchestration.js +32 -32
  39. package/dist/otto-config-schema.d.ts +21 -0
  40. package/dist/otto-config-schema.js +23 -1
  41. package/dist/provider-config.d.ts +92 -3
  42. package/dist/provider-config.js +58 -6
  43. package/dist/provider-manifest.d.ts +11 -1
  44. package/dist/provider-manifest.js +53 -5
  45. package/dist/schedule/cadence.d.ts +6 -0
  46. package/dist/schedule/cadence.js +28 -0
  47. package/dist/schedule/rpc-schemas.d.ts +4 -4
  48. package/dist/schedule/rpc-schemas.js +1 -1
  49. package/dist/schedule/types.d.ts +1 -1
  50. package/dist/schedule/types.js +3 -3
  51. package/dist/tool-call-display.d.ts +1 -1
  52. package/dist/tool-call-display.js +3 -3
  53. package/dist/tool-name-normalization.d.ts +2 -2
  54. package/dist/tool-name-normalization.js +2 -2
  55. package/dist/validation/ws-outbound-schema-metadata.d.ts +1950 -52
  56. package/dist/widgets/bridge.d.ts +5 -5
  57. package/dist/widgets/bridge.js +5 -5
  58. package/dist/widgets/document.d.ts +1 -1
  59. package/dist/widgets/document.js +4 -4
  60. package/dist/widgets/icons.d.ts +1 -1
  61. package/dist/widgets/icons.js +1 -1
  62. package/dist/widgets/theme.d.ts +2 -2
  63. package/dist/widgets/theme.js +2 -2
  64. package/dist/widgets/types.d.ts +5 -5
  65. package/dist/widgets/types.js +5 -5
  66. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { AgentProviderSchema } from "./provider-manifest.js";
2
+ import { AgentProviderSchema, OTTO_BRAIN_PROVIDER_ID } from "./provider-manifest.js";
3
3
  const ProviderCommandDefaultSchema = z.object({
4
4
  mode: z.literal("default"),
5
5
  });
@@ -38,7 +38,7 @@ export const ProviderProfileModelSchema = z.object({
38
38
  * Coarse categories for Otto's agent-facing tool catalog. Providers that receive
39
39
  * Otto tools natively (see the openai-compat provider) can be scoped to a subset
40
40
  * of these groups; omitting the selection means all groups. Kept deliberately
41
- * coarse users pick groups, not individual tools.
41
+ * coarse - users pick groups, not individual tools.
42
42
  */
43
43
  export const OTTO_TOOL_GROUPS = [
44
44
  "preview",
@@ -97,7 +97,7 @@ const McpSseServerConfigSchema = z.object({
97
97
  /**
98
98
  * Canonical MCP server config. Shared by AgentSessionConfig (per-agent servers
99
99
  * sent at create time) and ProviderOverride (provider-level servers in the
100
- * daemon config). stdio entries execute arbitrary commands as the daemon user
100
+ * daemon config). stdio entries execute arbitrary commands as the daemon user -
101
101
  * both sources sit behind existing trust boundaries (daemon-side config file,
102
102
  * authenticated agent-create RPC).
103
103
  */
@@ -106,6 +106,50 @@ export const McpServerConfigSchema = z.discriminatedUnion("type", [
106
106
  McpHttpServerConfigSchema,
107
107
  McpSseServerConfigSchema,
108
108
  ]);
109
+ /**
110
+ * OAuth tokens held for a connector whose MCP server authenticates over OAuth
111
+ * 2.1 (the "log in, don't paste a token" path). Mirrors the SDK's OAuthTokens
112
+ * shape. Secret-bearing, so it is host-owned like every other credential in
113
+ * daemon config and is redacted before the config is sent to a client.
114
+ *
115
+ * `expiresAt` is absolute epoch MILLISECONDS, not the `expires_in` duration the
116
+ * token endpoint returns: a duration is only meaningful next to the instant it
117
+ * was issued, and that instant is not on the wire.
118
+ */
119
+ export const ConnectorOAuthTokensSchema = z.object({
120
+ accessToken: z.string().min(1),
121
+ tokenType: z.string().optional(),
122
+ refreshToken: z.string().optional(),
123
+ scope: z.string().optional(),
124
+ expiresAt: z.number().optional(),
125
+ });
126
+ /**
127
+ * The OAuth client identity this daemon registered with a connector's
128
+ * authorization server, kept so a second login reuses the registration instead
129
+ * of re-running dynamic client registration. Keyed alongside the redirect URI it
130
+ * was registered against: if the loopback port moves, the registration is stale
131
+ * and must be redone.
132
+ */
133
+ export const ConnectorOAuthClientSchema = z.object({
134
+ clientId: z.string().min(1),
135
+ clientSecret: z.string().optional(),
136
+ redirectUri: z.string().min(1),
137
+ });
138
+ /**
139
+ * Everything the daemon persists about a connector's authorization. Absent means
140
+ * the connector either needs no credential or carries a static token in its
141
+ * transport (env var for stdio, Authorization header for http/sse) - this block
142
+ * is only for the interactive OAuth path.
143
+ */
144
+ export const ConnectorAuthStateSchema = z.object({
145
+ kind: z.literal("oauth"),
146
+ tokens: ConnectorOAuthTokensSchema.optional(),
147
+ client: ConnectorOAuthClientSchema.optional(),
148
+ /** Account label shown in the UI once connected (email / workspace name). */
149
+ account: z.string().optional(),
150
+ /** Epoch ms of the last successful authorization; drives "Connected on ...". */
151
+ authorizedAt: z.number().optional(),
152
+ });
109
153
  /**
110
154
  * Per-workspace state for a connector, keyed by workspace cwd in
111
155
  * ConnectorConfig.workspaces. Phase 1 leaves this inert (the daemon does not
@@ -136,6 +180,11 @@ export const ConnectorConfigSchema = z.object({
136
180
  enabled: z.boolean().optional(),
137
181
  /** Tool names (unqualified, as the server reports them) withheld from the model. */
138
182
  disabledTools: z.array(z.string()).optional(),
183
+ /**
184
+ * OAuth authorization state, when this connector logs in rather than taking a
185
+ * pasted token. Optional so every existing connector parses unchanged.
186
+ */
187
+ auth: ConnectorAuthStateSchema.optional(),
139
188
  /** Per-workspace activation keyed by workspace cwd. Phase 2; inert today. */
140
189
  workspaces: z.record(z.string(), ConnectorWorkspaceStateSchema).optional(),
141
190
  /** Display ordering in the UI; lower sorts first. */
@@ -165,7 +214,7 @@ export const COMPACTION_THRESHOLD_PERCENTS = [50, 60, 70, 80, 90];
165
214
  /**
166
215
  * Max model→tool→model rounds per turn for providers whose tool loop the
167
216
  * daemon owns (openai-compat). The turn stops with an error after this many
168
- * rounds without a final answer a runaway-loop safety valve, most often hit
217
+ * rounds without a final answer - a runaway-loop safety valve, most often hit
169
218
  * by smaller local models that keep calling tools instead of converging.
170
219
  * Bounds keep the setting a sane guard rail rather than an off switch.
171
220
  */
@@ -233,10 +282,13 @@ const PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]*$/;
233
282
  export const ProviderOverridesSchema = z
234
283
  .record(z.string(), ProviderOverrideSchema)
235
284
  .superRefine((providers, ctx) => {
236
- const builtinProviderIdSet = new Set(BUILTIN_PROVIDER_IDS);
285
+ // otto-brain is builtin (endpoint comes from brain settings, not
286
+ // extends/label) but not a valid `extends` target for a custom provider,
287
+ // so it's added only here rather than to BUILTIN_PROVIDER_IDS itself.
288
+ const builtinProviderIdSet = new Set([...BUILTIN_PROVIDER_IDS, OTTO_BRAIN_PROVIDER_ID]);
237
289
  // "acp" spawns a generic ACP agent process; "openai-compatible" is served
238
290
  // natively by the daemon against an OpenAI-compatible HTTP endpoint
239
- // (LM Studio, Ollama, vLLM, ...) no external binary involved.
291
+ // (LM Studio, Ollama, vLLM, ...) - no external binary involved.
240
292
  const validExtendsValues = new Set([
241
293
  ...BUILTIN_PROVIDER_IDS,
242
294
  "acp",
@@ -8,6 +8,7 @@ export interface AgentModeVisuals {
8
8
  }
9
9
  export type AgentProviderModeDefinition = Omit<AgentMode, "icon" | "colorTier"> & AgentModeVisuals & {
10
10
  isUnattended?: boolean;
11
+ selectsModel?: boolean;
11
12
  userSelectable?: boolean;
12
13
  };
13
14
  export interface AgentProviderDefinition {
@@ -23,6 +24,15 @@ export interface AgentProviderDefinition {
23
24
  defaultModel?: string;
24
25
  };
25
26
  }
27
+ export declare const OMP_MODES: AgentProviderModeDefinition[];
28
+ /**
29
+ * The daemon's built-in local AI host (see the definition below). Exported so
30
+ * other protocol/server/client code can recognize this id without repeating
31
+ * the string literal - notably ProviderOverridesSchema's builtin-provider
32
+ * check in provider-config.ts, which otherwise requires `extends`/`label` on
33
+ * any `providers.otto-brain` config entry.
34
+ */
35
+ export declare const OTTO_BRAIN_PROVIDER_ID = "otto-brain";
26
36
  export declare const AGENT_PROVIDER_DEFINITIONS: AgentProviderDefinition[];
27
37
  export declare const DEV_AGENT_PROVIDER_DEFINITIONS: AgentProviderDefinition[];
28
38
  export declare function getAgentProviderDefinition(provider: string, definitions?: AgentProviderDefinition[]): AgentProviderDefinition;
@@ -33,7 +43,7 @@ export declare function isValidAgentProvider(value: string, validIds?: Iterable<
33
43
  export declare function getUnattendedModeId(provider: string, definitions?: AgentProviderDefinition[]): string | undefined;
34
44
  /**
35
45
  * Whether a user may pick this mode themselves. False only for modes explicitly
36
- * flagged `userSelectable: false` in the static manifest (Claude "dontAsk") a
46
+ * flagged `userSelectable: false` in the static manifest (Claude "dontAsk") - a
37
47
  * system-assigned mode that agents can run in but no one selects by hand. Unknown
38
48
  * modes (dynamic/ACP, custom providers) default to selectable. The flag is a
39
49
  * static property of the mode, so this always consults the built-in manifest
@@ -27,11 +27,15 @@ const CLAUDE_MODES = [
27
27
  description: "Uses a model classifier to review permission prompts automatically",
28
28
  icon: "LocalPolice",
29
29
  colorTier: "moderate",
30
+ // Auto also lets the CLI pick the model per turn. Codex's unrelated "auto"
31
+ // mode is a permission level only, which is exactly why this is a flag and
32
+ // not a check on the mode id.
33
+ selectsModel: true,
30
34
  },
31
35
  {
32
36
  id: "dontAsk",
33
37
  label: "Don't Ask",
34
- description: "Runs without prompting actions not pre-approved are denied",
38
+ description: "Runs without prompting; actions not pre-approved are denied",
35
39
  // Guarded unattended mode: more dangerous than acceptEdits (edits only) but
36
40
  // safer than bypass (deny-by-default vs. run-everything), so it sits at the
37
41
  // "moderate" tier alongside Auto.
@@ -39,7 +43,7 @@ const CLAUDE_MODES = [
39
43
  colorTier: "moderate",
40
44
  isUnattended: true,
41
45
  // System-assigned only: the coercion target for unattended runs and for Auto
42
- // on models that can't run it (Haiku). Users never pick it it's hidden from
46
+ // on models that can't run it (Haiku). Users never pick it - it's hidden from
43
47
  // mode dropdowns and locks the control when it's an agent's active mode.
44
48
  userSelectable: false,
45
49
  },
@@ -127,7 +131,7 @@ const MOCK_LOAD_TEST_MODES = [
127
131
  {
128
132
  id: "dontAsk",
129
133
  label: "Don't Ask",
130
- description: "Runs without prompting actions not pre-approved are denied",
134
+ description: "Runs without prompting; actions not pre-approved are denied",
131
135
  icon: "ShieldCheck",
132
136
  colorTier: "moderate",
133
137
  // Dev-only mirror of Claude's guarded unattended mode so deterministic E2E
@@ -147,6 +151,38 @@ const MOCK_SLOW_MODES = [
147
151
  colorTier: "dangerous",
148
152
  },
149
153
  ];
154
+ export const OMP_MODES = [
155
+ {
156
+ id: "full",
157
+ label: "Full Access",
158
+ description: "Launches OMP with yolo approval mode so tools run without prompts.",
159
+ icon: "ShieldOff",
160
+ colorTier: "dangerous",
161
+ isUnattended: true,
162
+ },
163
+ {
164
+ id: "write",
165
+ label: "Write Approval",
166
+ description: "Launches OMP with write approval mode: reads are free, writes require approval.",
167
+ icon: "ShieldAlert",
168
+ colorTier: "moderate",
169
+ },
170
+ {
171
+ id: "ask",
172
+ label: "Always Ask",
173
+ description: "Launches OMP with always-ask approval mode for write and exec tools.",
174
+ icon: "ShieldCheck",
175
+ colorTier: "safe",
176
+ },
177
+ ];
178
+ /**
179
+ * The daemon's built-in local AI host (see the definition below). Exported so
180
+ * other protocol/server/client code can recognize this id without repeating
181
+ * the string literal - notably ProviderOverridesSchema's builtin-provider
182
+ * check in provider-config.ts, which otherwise requires `extends`/`label` on
183
+ * any `providers.otto-brain` config entry.
184
+ */
185
+ export const OTTO_BRAIN_PROVIDER_ID = "otto-brain";
150
186
  export const AGENT_PROVIDER_DEFINITIONS = [
151
187
  {
152
188
  id: "claude",
@@ -202,7 +238,19 @@ export const AGENT_PROVIDER_DEFINITIONS = [
202
238
  label: "OMP",
203
239
  description: "Pi-compatible coding agent distributed as Oh My Pi",
204
240
  enabledByDefault: false,
205
- defaultModeId: null,
241
+ defaultModeId: "ask",
242
+ modes: OMP_MODES,
243
+ },
244
+ {
245
+ // The daemon's own local AI host. Built in rather than a catalog-installed
246
+ // OpenAI-compatible profile: its endpoint and credential come from the
247
+ // brain settings (Settings -> Host -> Otto Brain), never from per-provider
248
+ // URL/API-key fields. Modes are empty here for the same reason every
249
+ // openai-compat provider's are: the client reports them at catalog time.
250
+ id: OTTO_BRAIN_PROVIDER_ID,
251
+ label: "Otto Brain",
252
+ description: "Otto's built-in local AI host. Serves your local models over an OpenAI-compatible endpoint, no external server required.",
253
+ defaultModeId: "default",
206
254
  modes: [],
207
255
  },
208
256
  ];
@@ -247,7 +295,7 @@ export function getUnattendedModeId(provider, definitions = [
247
295
  }
248
296
  /**
249
297
  * Whether a user may pick this mode themselves. False only for modes explicitly
250
- * flagged `userSelectable: false` in the static manifest (Claude "dontAsk") a
298
+ * flagged `userSelectable: false` in the static manifest (Claude "dontAsk") - a
251
299
  * system-assigned mode that agents can run in but no one selects by hand. Unknown
252
300
  * modes (dynamic/ACP, custom providers) default to selectable. The flag is a
253
301
  * static property of the mode, so this always consults the built-in manifest
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Convert an exact rolling interval to an equivalent five-field cron cadence.
3
+ * Returns null when cron's calendar boundaries would change the interval.
4
+ */
5
+ export declare function everyMsToFiveFieldCron(everyMs: number): string | null;
6
+ //# sourceMappingURL=cadence.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Convert an exact rolling interval to an equivalent five-field cron cadence.
3
+ * Returns null when cron's calendar boundaries would change the interval.
4
+ */
5
+ export function everyMsToFiveFieldCron(everyMs) {
6
+ const minutes = everyMs / 60000;
7
+ if (!Number.isInteger(minutes) || minutes <= 0) {
8
+ return null;
9
+ }
10
+ if (minutes < 60 && 60 % minutes === 0) {
11
+ return `*/${minutes} * * * *`;
12
+ }
13
+ if (minutes === 60) {
14
+ return "0 * * * *";
15
+ }
16
+ if (minutes % 60 !== 0) {
17
+ return null;
18
+ }
19
+ const hours = minutes / 60;
20
+ if (hours < 24 && 24 % hours === 0) {
21
+ return `0 */${hours} * * *`;
22
+ }
23
+ if (hours === 24) {
24
+ return "0 0 * * *";
25
+ }
26
+ return null;
27
+ }
28
+ //# sourceMappingURL=cadence.js.map
@@ -129,6 +129,7 @@ export declare const ScheduleCreateResponseSchema: z.ZodObject<{
129
129
  }>;
130
130
  createdAt: z.ZodString;
131
131
  updatedAt: z.ZodString;
132
+ expiresAt: z.ZodNullable<z.ZodString>;
132
133
  cadence: z.ZodDiscriminatedUnion<[z.ZodObject<{
133
134
  type: z.ZodLiteral<"every">;
134
135
  everyMs: z.ZodNumber;
@@ -179,7 +180,6 @@ export declare const ScheduleCreateResponseSchema: z.ZodObject<{
179
180
  lastRunProvider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
180
181
  lastRunModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
181
182
  pausedAt: z.ZodNullable<z.ZodString>;
182
- expiresAt: z.ZodNullable<z.ZodString>;
183
183
  maxRuns: z.ZodNullable<z.ZodNumber>;
184
184
  }, z.core.$strip>>;
185
185
  error: z.ZodNullable<z.ZodString>;
@@ -200,6 +200,7 @@ export declare const ScheduleListResponseSchema: z.ZodObject<{
200
200
  }>;
201
201
  createdAt: z.ZodString;
202
202
  updatedAt: z.ZodString;
203
+ expiresAt: z.ZodNullable<z.ZodString>;
203
204
  cadence: z.ZodDiscriminatedUnion<[z.ZodObject<{
204
205
  type: z.ZodLiteral<"every">;
205
206
  everyMs: z.ZodNumber;
@@ -250,7 +251,6 @@ export declare const ScheduleListResponseSchema: z.ZodObject<{
250
251
  lastRunProvider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
251
252
  lastRunModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
252
253
  pausedAt: z.ZodNullable<z.ZodString>;
253
- expiresAt: z.ZodNullable<z.ZodString>;
254
254
  maxRuns: z.ZodNullable<z.ZodNumber>;
255
255
  }, z.core.$strip>>;
256
256
  error: z.ZodNullable<z.ZodString>;
@@ -385,6 +385,7 @@ export declare const SchedulePauseResponseSchema: z.ZodObject<{
385
385
  }>;
386
386
  createdAt: z.ZodString;
387
387
  updatedAt: z.ZodString;
388
+ expiresAt: z.ZodNullable<z.ZodString>;
388
389
  cadence: z.ZodDiscriminatedUnion<[z.ZodObject<{
389
390
  type: z.ZodLiteral<"every">;
390
391
  everyMs: z.ZodNumber;
@@ -435,7 +436,6 @@ export declare const SchedulePauseResponseSchema: z.ZodObject<{
435
436
  lastRunProvider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
436
437
  lastRunModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
437
438
  pausedAt: z.ZodNullable<z.ZodString>;
438
- expiresAt: z.ZodNullable<z.ZodString>;
439
439
  maxRuns: z.ZodNullable<z.ZodNumber>;
440
440
  }, z.core.$strip>>;
441
441
  error: z.ZodNullable<z.ZodString>;
@@ -456,6 +456,7 @@ export declare const ScheduleResumeResponseSchema: z.ZodObject<{
456
456
  }>;
457
457
  createdAt: z.ZodString;
458
458
  updatedAt: z.ZodString;
459
+ expiresAt: z.ZodNullable<z.ZodString>;
459
460
  cadence: z.ZodDiscriminatedUnion<[z.ZodObject<{
460
461
  type: z.ZodLiteral<"every">;
461
462
  everyMs: z.ZodNumber;
@@ -506,7 +507,6 @@ export declare const ScheduleResumeResponseSchema: z.ZodObject<{
506
507
  lastRunProvider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
507
508
  lastRunModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
508
509
  pausedAt: z.ZodNullable<z.ZodString>;
509
- expiresAt: z.ZodNullable<z.ZodString>;
510
510
  maxRuns: z.ZodNullable<z.ZodNumber>;
511
511
  }, z.core.$strip>>;
512
512
  error: z.ZodNullable<z.ZodString>;
@@ -62,7 +62,7 @@ export const ScheduleRunOnceRequestSchema = z.object({
62
62
  });
63
63
  const ScheduleUpdateNewAgentConfigSchema = z.object({
64
64
  provider: z.string().trim().min(1).optional(),
65
- // Personality binding by name or the "@team-scheduler" sentinel. Explicit
65
+ // Personality binding by name - or the "@team-scheduler" sentinel. Explicit
66
66
  // null clears a stored binding; omission leaves it untouched.
67
67
  personality: z.string().trim().min(1).nullable().optional(),
68
68
  model: z.string().trim().min(1).nullable().optional(),
@@ -159,6 +159,7 @@ export declare const ScheduleSummarySchema: z.ZodObject<{
159
159
  }>;
160
160
  createdAt: z.ZodString;
161
161
  updatedAt: z.ZodString;
162
+ expiresAt: z.ZodNullable<z.ZodString>;
162
163
  cadence: z.ZodDiscriminatedUnion<[z.ZodObject<{
163
164
  type: z.ZodLiteral<"every">;
164
165
  everyMs: z.ZodNumber;
@@ -209,7 +210,6 @@ export declare const ScheduleSummarySchema: z.ZodObject<{
209
210
  lastRunProvider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
210
211
  lastRunModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
211
212
  pausedAt: z.ZodNullable<z.ZodString>;
212
- expiresAt: z.ZodNullable<z.ZodString>;
213
213
  maxRuns: z.ZodNullable<z.ZodNumber>;
214
214
  }, z.core.$strip>;
215
215
  export type ScheduleSummary = z.infer<typeof ScheduleSummarySchema>;
@@ -24,7 +24,7 @@ export const ScheduleTargetSchema = z.discriminatedUnion("type", [
24
24
  cwd: z.string().trim().min(1),
25
25
  // Optional Agent Personality binding (by name). When set, each run
26
26
  // re-resolves the personality against the run cwd and hard-fails if it is
27
- // unavailable so schedule runs pick up personality edits between runs.
27
+ // unavailable - so schedule runs pick up personality edits between runs.
28
28
  personality: z.string().trim().min(1).optional(),
29
29
  modeId: z.string().trim().min(1).optional(),
30
30
  model: z.string().trim().min(1).optional(),
@@ -57,7 +57,7 @@ export const ScheduleRunSchema = z.object({
57
57
  status: z.enum(["running", "succeeded", "failed"]),
58
58
  agentId: z.guid().nullable(),
59
59
  workspaceId: z.string().nullable().optional(),
60
- // Who actually executed this run the resolved personality (if any),
60
+ // Who actually executed this run - the resolved personality (if any),
61
61
  // provider, and model. Stamped when the run starts (so a failed run still
62
62
  // records its executor). Optional for back-compat: runs written before these
63
63
  // fields existed omit them.
@@ -80,7 +80,7 @@ export const StoredScheduleSchema = z.object({
80
80
  lastRunAt: z.string().nullable(),
81
81
  lastRunStatus: z.enum(["succeeded", "failed"]).nullable().optional(),
82
82
  lastRunError: z.string().nullable().optional(),
83
- // Executor of the most recent run mirrors the run-level fields above so the
83
+ // Executor of the most recent run - mirrors the run-level fields above so the
84
84
  // schedule card can show "who ran it last" (personality · provider · model)
85
85
  // without loading the full run history (ScheduleSummary omits `runs`).
86
86
  // Optional for back-compat: schedules that never ran, or predate these
@@ -12,7 +12,7 @@ export interface ToolCallDisplayModel {
12
12
  * shows a tool/action name without a full timeline item to run through
13
13
  * {@link buildToolCallDisplayModel} (the visualizer's action labels, sub-agent
14
14
  * activity rows). Strips the MCP/Otto namespace, consults the known-tool
15
- * registry, then title-cases as a fallback so "mcp__otto__spawn_task",
15
+ * registry, then title-cases as a fallback - so "mcp__otto__spawn_task",
16
16
  * "otto.spawn_task", and a bare "spawn_task" all render as "Spawn Task".
17
17
  */
18
18
  export declare function getToolDisplayName(name: string): string;
@@ -6,7 +6,7 @@ function isRecord(value) {
6
6
  function readString(value) {
7
7
  return typeof value === "string" && value.length > 0 ? value : undefined;
8
8
  }
9
- // Curated display names the registry of tools we explicitly "know about".
9
+ // Curated display names - the registry of tools we explicitly "know about".
10
10
  // Keyed by the lowercased leaf name (transport namespace already stripped).
11
11
  //
12
12
  // Only tools whose bare id does NOT title-case cleanly on its own need an entry
@@ -15,7 +15,7 @@ function readString(value) {
15
15
  // camelCase ("WebSearch") names are handled by the algorithmic humanizer below
16
16
  // and do NOT need listing.
17
17
  //
18
- // Anything not here falls through to the humanizer and still renders readably
18
+ // Anything not here falls through to the humanizer and still renders readably -
19
19
  // so an unmapped tool shows up looking slightly generic (e.g. a stray provider
20
20
  // tool), which is the cue to add it here. Extend this map to teach Otto a tool.
21
21
  const KNOWN_TOOL_DISPLAY_NAMES = {
@@ -66,7 +66,7 @@ function humanizeToolName(name) {
66
66
  * shows a tool/action name without a full timeline item to run through
67
67
  * {@link buildToolCallDisplayModel} (the visualizer's action labels, sub-agent
68
68
  * activity rows). Strips the MCP/Otto namespace, consults the known-tool
69
- * registry, then title-cases as a fallback so "mcp__otto__spawn_task",
69
+ * registry, then title-cases as a fallback - so "mcp__otto__spawn_task",
70
70
  * "otto.spawn_task", and a bare "spawn_task" all render as "Spawn Task".
71
71
  */
72
72
  export function getToolDisplayName(name) {
@@ -10,13 +10,13 @@ export declare function getOttoToolLeafName(name: string): string | null;
10
10
  *
11
11
  * Tools hosted over MCP arrive namespaced as `mcp__<server>__<tool>` (Claude
12
12
  * Code format). The `mcp__<server>__` part is transport plumbing that means
13
- * nothing to a reader "Create Issue", not "mcp__linear__create_issue". This
13
+ * nothing to a reader - "Create Issue", not "mcp__linear__create_issue". This
14
14
  * generalizes {@link getOttoToolLeafName} to ANY server so every MCP tool reads
15
15
  * cleanly, not just Otto's own.
16
16
  *
17
17
  * Returns `null` when the name carries no `mcp__…__` namespace, so callers keep
18
18
  * plain tool names (`Read`, `bash`) and dotted/other forms untouched. Case is
19
- * preserved MCP tool ids are already snake_case and callers humanize after.
19
+ * preserved - MCP tool ids are already snake_case and callers humanize after.
20
20
  * `speak` is never treated as namespaced (it renders as a chat bubble, not an
21
21
  * action row).
22
22
  */
@@ -74,13 +74,13 @@ export function getOttoToolLeafName(name) {
74
74
  *
75
75
  * Tools hosted over MCP arrive namespaced as `mcp__<server>__<tool>` (Claude
76
76
  * Code format). The `mcp__<server>__` part is transport plumbing that means
77
- * nothing to a reader "Create Issue", not "mcp__linear__create_issue". This
77
+ * nothing to a reader - "Create Issue", not "mcp__linear__create_issue". This
78
78
  * generalizes {@link getOttoToolLeafName} to ANY server so every MCP tool reads
79
79
  * cleanly, not just Otto's own.
80
80
  *
81
81
  * Returns `null` when the name carries no `mcp__…__` namespace, so callers keep
82
82
  * plain tool names (`Read`, `bash`) and dotted/other forms untouched. Case is
83
- * preserved MCP tool ids are already snake_case and callers humanize after.
83
+ * preserved - MCP tool ids are already snake_case and callers humanize after.
84
84
  * `speak` is never treated as namespaced (it renders as a chat bubble, not an
85
85
  * action row).
86
86
  */