@maudecode/talaria-web-contracts 1.17.2 → 1.18.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 (62) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/openapi.js +5 -1
  5. package/dist/openapi.js.map +1 -1
  6. package/dist/router.d.ts +3555 -1107
  7. package/dist/routes/automation.d.ts +26 -1
  8. package/dist/routes/automation.js +2 -1
  9. package/dist/routes/automation.js.map +1 -1
  10. package/dist/routes/chat.d.ts +1164 -16
  11. package/dist/routes/chat.js +5 -3
  12. package/dist/routes/chat.js.map +1 -1
  13. package/dist/routes/core.d.ts +11 -0
  14. package/dist/routes/core.js +3 -0
  15. package/dist/routes/core.js.map +1 -1
  16. package/dist/routes/git.d.ts +76 -1
  17. package/dist/routes/git.js +13 -3
  18. package/dist/routes/git.js.map +1 -1
  19. package/dist/routes/raw.d.ts +3 -1
  20. package/dist/routes/raw.js +29 -5
  21. package/dist/routes/raw.js.map +1 -1
  22. package/dist/routes/sessions.d.ts +2807 -581
  23. package/dist/routes/sessions.js +58 -1
  24. package/dist/routes/sessions.js.map +1 -1
  25. package/dist/routes/settings.d.ts +31 -0
  26. package/dist/routes/tools.d.ts +356 -15
  27. package/dist/routes/tools.js +22 -3
  28. package/dist/routes/tools.js.map +1 -1
  29. package/dist/routes/workspaces.d.ts +82 -0
  30. package/dist/routes/workspaces.js +18 -1
  31. package/dist/routes/workspaces.js.map +1 -1
  32. package/dist/sidecar/methods.d.ts +133 -0
  33. package/dist/sidecar/methods.js +2 -1
  34. package/dist/sidecar/methods.js.map +1 -1
  35. package/dist/sidecar/namespaces.d.ts +177 -0
  36. package/dist/sidecar/namespaces.js +36 -3
  37. package/dist/sidecar/namespaces.js.map +1 -1
  38. package/dist/sidecar/version.d.ts +1 -1
  39. package/dist/sidecar/version.js +1 -1
  40. package/dist/sse.d.ts +37 -10
  41. package/dist/sse.js +1 -2
  42. package/dist/sse.js.map +1 -1
  43. package/dist/theme.d.ts +10 -0
  44. package/dist/theme.js +10 -0
  45. package/dist/theme.js.map +1 -0
  46. package/dist/views.d.ts +808 -37
  47. package/dist/views.js +110 -11
  48. package/dist/views.js.map +1 -1
  49. package/fixtures/sidecar/checkpoints.json +50 -0
  50. package/fixtures/sidecar/commands.json +55 -4
  51. package/fixtures/sidecar/cron.json +38 -55
  52. package/fixtures/sidecar/goals.json +6 -6
  53. package/fixtures/sidecar/kanban.json +92 -91
  54. package/fixtures/sidecar/plugins.json +171 -172
  55. package/fixtures/sidecar/profiles.json +10 -2
  56. package/fixtures/sidecar/providers.json +25 -12
  57. package/fixtures/sidecar/rpc.json +15 -0
  58. package/fixtures/sidecar/runtime.json +22 -29
  59. package/fixtures/sidecar/state_db.json +15 -0
  60. package/fixtures/sidecar/text.json +2 -2
  61. package/fixtures/sidecar/usage.json +10 -10
  62. package/package.json +1 -1
package/dist/views.js CHANGED
@@ -5,6 +5,7 @@
5
5
  * that must survive a round trip (documented passthrough).
6
6
  */
7
7
  import { z } from 'zod';
8
+ import { CanonicalBotChatSchema } from './sidecar/namespaces.js';
8
9
  const Json = z.unknown();
9
10
  export const NullableString = z.string().nullable();
10
11
  export const NullableNumber = z.number().nullable();
@@ -17,12 +18,26 @@ export const AttachmentSchema = z.looseObject({
17
18
  });
18
19
  /** The server's display class for a tool call: clients map it to an icon and localized verb, and never classify names themselves. */
19
20
  export const ToolKindSchema = z.enum(['shell', 'read', 'list', 'search', 'web', 'write', 'skill', 'memory', 'delegate', 'unknown']);
21
+ /**
22
+ * TAL-604: one row of a unified diff hunk as the server parsed it. `text` is the raw line, its `+` / `-` / space prefix kept;
23
+ * `old_line` / `new_line` number it on each side (null on the side it is absent from, and on a `\ No newline` marker).
24
+ */
25
+ export const DiffLineSchema = z.object({ kind: z.enum(['addition', 'deletion', 'context']), old_line: z.number().int().nullable(), new_line: z.number().int().nullable(), text: z.string() });
26
+ /**
27
+ * TAL-604: one hunk of a unified diff: its `@@` `header`, the first old and new line numbers, the last new line it covers
28
+ * (`new_end`, at least `new_start`), its added and removed line counts, and its lines. A diff without `@@` headers yields
29
+ * one hunk per file with an empty `header` and null numbers.
30
+ */
31
+ export const DiffHunkSchema = z.object({
32
+ header: z.string(), old_start: z.number().int().nullable(), new_start: z.number().int().nullable(), new_end: z.number().int().nullable(),
33
+ additions: z.number().int(), deletions: z.number().int(), lines: z.array(DiffLineSchema),
34
+ });
20
35
  /**
21
36
  * TAL-448: a completed file-edit call's change, from its result's unified diff: `added` / `removed` count the whole diff's
22
- * lines (file headers excluded); `diff` is the redacted diff, capped at 400 lines, with `truncated` when cut. Absent on a
23
- * call whose result has no diff.
37
+ * lines (file headers excluded); `diff` is the redacted diff, capped at 400 lines, with `truncated` when cut, and `hunks`
38
+ * that diff parsed (TAL-604). Absent on a call whose result has no diff.
24
39
  */
25
- export const ToolEditDiffSchema = z.object({ added: z.number().int(), removed: z.number().int(), diff: z.string(), truncated: z.boolean() });
40
+ export const ToolEditDiffSchema = z.object({ added: z.number().int(), removed: z.number().int(), diff: z.string(), truncated: z.boolean(), hunks: z.array(DiffHunkSchema) });
26
41
  /** Server-derived display fields every tool call carries: the kind, and the redacted first-line label of its main argument (`''` when none; omitted on a live frame with none, which keeps its start frame's target), and a file edit's `edit_diff`. */
27
42
  export const ToolDisplayFields = { kind: ToolKindSchema.optional(), target: z.string().optional(), edit_diff: ToolEditDiffSchema.optional() };
28
43
  /**
@@ -115,6 +130,14 @@ export const MessageSchema = z.looseObject({
115
130
  provider_details: Json.optional(), provider_details_label: z.string().optional(), recovery_control: Json.optional(), _anchor_activity_scene: ActivitySceneSchema.optional(),
116
131
  /** The turn this row belongs to; the server stamps every row it sends, so clients group turns by equality alone. */
117
132
  _turn_id: z.string().optional(),
133
+ /** On a turn's last assistant row: seconds the turn ran. */
134
+ _turnDuration: z.number().optional(),
135
+ /** On a turn's last assistant row: output tokens per second, when the turn reported usage. */
136
+ _turnTps: z.number().optional(),
137
+ /** Epoch seconds the row was written; `timestamp` when absent. */
138
+ _ts: z.number().optional(),
139
+ /** Reasoning titles an older Web stored on the row, in order. */
140
+ reasoning_titles: z.array(z.string()).optional(),
118
141
  /** The running turn's prompt, which the turn's settlement replaces with its persisted row. */
119
142
  _active_turn_user: z.boolean().optional(),
120
143
  /** A consumed steer at its causal place in the turn: display-only, never model history. A steer only the Agent recorded has no timing. */
@@ -162,6 +185,12 @@ export const MessageSchema = z.looseObject({
162
185
  _background_reply: z.boolean().optional(),
163
186
  /** TAL-460: that reply is only a silence marker; clients show the update's lines and nothing of this turn's reply. */
164
187
  _background_silent: z.boolean().optional(),
188
+ /**
189
+ * TAL-600: how clients show the row, on every row the server sends: `row` on its own, `in_scene` only inside its turn's
190
+ * activity scene (a tool result or a consumed steer), `hidden` not at all (a silent background reply, or a row with
191
+ * nothing to show).
192
+ */
193
+ _display: z.enum(['row', 'hidden', 'in_scene']).optional(),
165
194
  });
166
195
  export const ComposerDraftSchema = z.looseObject({ text: z.string().optional(), files: z.array(Json).optional() });
167
196
  /**
@@ -212,6 +241,8 @@ export const CompressionReferenceSchema = z.object({
212
241
  text: z.string(),
213
242
  after_message_index: z.number().int().nonnegative().nullable().describe('The full-transcript index of the row the card follows; null puts it above the transcript.'),
214
243
  });
244
+ /** TAL-454: the chat a `/branch` copied, with its redacted title. */
245
+ export const BranchedFromSchema = z.object({ session_id: SessionIdSchema, title: z.string() });
215
246
  /** Full session record from `GET /api/session` and mutations returning `session`. */
216
247
  export const SessionSchema = z.looseObject({
217
248
  session_id: SessionIdSchema, title: z.string(), workspace: z.string().optional(), created_workspace: z.string().nullable().optional(), model: NullableString.optional(), model_provider: NullableString.optional(),
@@ -223,6 +254,7 @@ export const SessionSchema = z.looseObject({
223
254
  pending_user_message: NullableString.optional(), pending_attachments: z.array(AttachmentSchema).optional(), pending_started_at: NullableNumber.optional(), pending_user_source: NullableString.optional(),
224
255
  context_length: NullableNumber.optional(), threshold_tokens: NullableNumber.optional(), last_prompt_tokens: NullableNumber.optional(), post_compression_context_tokens_estimate: NullableNumber.optional(), ...ContextUsageFields,
225
256
  enabled_toolsets: z.array(z.string()).nullable().optional(), composer_draft: ComposerDraftSchema.optional(), is_cli_session: z.boolean().optional(), source_kind: SourceKindSchema, is_messaging_session: IsMessagingSessionSchema, sort_ts: SortTsSchema, read_only: ReadOnlySchema, can_branch: CanBranchSchema, can_pin: CanPinSchema, can_archive: CanArchiveSchema, can_delete: CanDeleteSchema, can_duplicate: CanDuplicateSchema, source_tag: NullableString.optional(),
257
+ can_compress: z.boolean().optional().describe('TAL-614: a manual compression would start now: writable, no running turn, and at least four model-history messages. Only the full session detail carries it; absent means no.'),
226
258
  source_label: NullableString.optional(), session_source: NullableString.optional(), raw_source: NullableString.optional(), parent_session_id: NullableString.optional(), worktree_path: NullableString.optional(),
227
259
  worktree_branch: NullableString.optional(), worktree_repo_root: NullableString.optional(), share_token: NullableString.optional(), share_url: NullableString.optional(), share_created_at: NullableNumber.optional(), manual_title: z.boolean().optional(),
228
260
  compression_anchor_summary: NullableString.optional(), compression_recovery: z.record(z.string(), Json).optional(), recommended_recovery_action: NullableString.optional(), compression_recovery_action: NullableString.optional(),
@@ -237,6 +269,7 @@ export const SessionSchema = z.looseObject({
237
269
  assistant_name: z.string().optional(),
238
270
  workspace_name: WorkspaceNameSchema,
239
271
  compression_reference: CompressionReferenceSchema.nullable().optional(),
272
+ branched_from: BranchedFromSchema.nullable().optional().describe('TAL-454: the chat this one was branched from while it still loads (archived included); null for a compression continuation, a deleted or missing parent, and every other chat.'),
240
273
  });
241
274
  export const SessionEnvelopeSchema = z.looseObject({ session: SessionSchema });
242
275
  /** Sidebar row from `GET /api/sessions`. */
@@ -333,8 +366,6 @@ export const MAX_CHAT_ATTACHMENTS = 20;
333
366
  export const UploadResponseSchema = z.looseObject({ filename: z.string(), path: z.string(), size: z.number(), mime: z.string(), is_image: z.boolean().optional(), rollback_token: z.string().optional(), named_in_prompt: z.boolean().optional(), max_attachments_per_message: z.number().int().positive().optional() });
334
367
  export const GoalViewSchema = z.looseObject({ text: z.string().optional(), state: z.string().optional(), status: z.string().optional(), turns: z.number().optional(), max_turns: z.number().optional(), reason: z.string().optional() });
335
368
  export const GoalResponseSchema = z.looseObject({ ok: z.boolean().optional(), action: z.string().optional(), goal: GoalViewSchema.nullable().optional(), message: z.string().optional(), message_key: z.string().optional(), stream_id: z.string().optional(), status: z.string().optional(), reason: z.string().optional() });
336
- export const BackgroundResultSchema = z.looseObject({ id: z.string().optional(), task_id: z.string().optional(), status: z.string().optional(), title: z.string().optional(), summary: z.string().optional(), prompt: z.string().optional(), answer: NullableString.optional(), error: z.string().optional(), completed_at: z.number().nullable().optional() });
337
- export const BackgroundStatusSchema = z.looseObject({ results: z.array(BackgroundResultSchema) });
338
369
  /**
339
370
  * TAL-372: one piece of background work a session owns, the same record for every client, reload and restart.
340
371
  * - `task_id` is stable: the delegation unit's id, the process id, or the `/background` task id.
@@ -403,6 +434,10 @@ export const SettingsSchema = z.looseObject({
403
434
  export const ProfileSchema = z.looseObject({
404
435
  name: z.string(), path: z.string().optional(), is_active: z.boolean().optional(), is_default: z.boolean().optional(), model: NullableString.optional(), provider: NullableString.optional(), skill_count: z.number().optional(),
405
436
  total_skills: z.number().optional(), enabled_skills: z.number().optional(), gateway_running: z.boolean().optional(), has_env: z.boolean().optional(), visible: z.boolean().optional(),
437
+ /** TAL-213: Bot Mode identity from `profile.yaml` (the bot's roster title, else the profile's display name), one bounded printable line each. */
438
+ display_name: z.string().optional(), description: z.string().optional(), has_avatar: z.boolean().optional(),
439
+ /** TAL-213: present only when the profile has a canonical Bot Chat; clients open `tip_session_id` after switching to the profile. */
440
+ canonical_session: CanonicalBotChatSchema.nullable().optional(),
406
441
  });
407
442
  export const ProfilesSchema = z.looseObject({ profiles: z.array(ProfileSchema), active: z.string(), single_profile_mode: z.boolean().optional() });
408
443
  export const ActiveProfileSchema = z.looseObject({ name: z.string(), path: z.string().optional(), is_default: z.boolean().optional(), default_workspace: NullableString.optional() });
@@ -413,10 +448,18 @@ export const ReasoningStatusSchema = z.looseObject({ show_reasoning: z.boolean()
413
448
  export const ModelEntrySchema = z.looseObject({ id: z.string(), label: z.string().optional(), provider: z.string().optional(), provider_id: z.string().optional(), bare_id: z.string().optional(), supports_fast_tier: z.boolean().optional() });
414
449
  export const ModelGroupSchema = z.looseObject({ provider: z.string(), provider_id: z.string().optional(), models: z.array(ModelEntrySchema), extra_models: z.array(ModelEntrySchema).optional() });
415
450
  export const ModelsSchema = z.looseObject({ active_provider: NullableString.optional(), default_model: z.string().optional(), default_provider_id: NullableString.optional(), default_bare_id: z.string().optional(), default_option_id: NullableString.optional(), groups: z.array(ModelGroupSchema), aliases: z.record(z.string(), Json).optional(), configured_model_badges: z.record(z.string(), Json).optional() });
416
- /** `has_key` reports a credential; `configured` (TAL-570) is the row's setup status, which a keyless Ollama or LM Studio endpoint also meets. */
451
+ /** TAL-603: where a card's credential comes from; `other` is a source the server cannot name, shown as its raw `key_source`. */
452
+ export const KeySourceKindSchema = z.enum(['env', 'oauth', 'config', 'pool', 'plugin', 'other']);
453
+ /**
454
+ * `has_key` reports a credential; `configured` (TAL-570) is the row's setup status, which a keyless Ollama or LM Studio endpoint also meets.
455
+ * TAL-603: `is_active` marks the active provider's card; `key_source_kind` is the key badge (`null` without a credential);
456
+ * `models_total` is the catalog size, never below `models.length`. `is_active` and `key_source_kind` are absent from older servers.
457
+ * TAL-641: `removable` marks a key Remove would clear: a built-in, not self-hosted, provider whose only key is its own profile `.env` variable.
458
+ */
417
459
  export const ProviderSchema = z.looseObject({
418
460
  id: z.string(), display_name: z.string().optional(), has_key: z.boolean().optional(), configured: z.boolean().optional(), configurable: z.boolean().optional(), is_oauth: z.boolean().optional(), is_plugin_provider: z.boolean().optional(), is_self_hosted: z.boolean().optional(),
419
461
  is_custom: z.boolean().optional(), key_source: z.string().optional(), base_url: NullableString.optional(), auth_error: NullableString.optional(), env_var: NullableString.optional(), models: z.array(ModelEntrySchema).optional(), models_total: z.number().optional(),
462
+ is_active: z.boolean().optional(), key_source_kind: KeySourceKindSchema.nullable().optional(), removable: z.boolean().optional(),
420
463
  });
421
464
  export const ProvidersSchema = z.looseObject({ providers: z.array(ProviderSchema), active_provider: NullableString.optional() });
422
465
  export const QuotaLevelSchema = z.enum(['healthy', 'warning', 'critical', 'stale', 'unavailable']);
@@ -521,11 +564,16 @@ export const FileContentSchema = z.looseObject({
521
564
  preview: FilePreviewKindSchema.optional(), table: z.array(z.array(z.string())).optional(), table_truncated: z.boolean().optional(),
522
565
  preview_url: z.string().optional(),
523
566
  });
524
- export const GitInfoSchema = z.looseObject({ git: z.looseObject({ is_git: z.boolean().optional(), branch: NullableString.optional(), dirty: z.number().optional(), modified: z.number().optional(), untracked: z.number().optional(), ahead: z.number().optional(), behind: z.number().optional() }).nullable().optional() });
567
+ const GitBadgeSchema = z.looseObject({ is_git: z.boolean().optional(), branch: NullableString.optional(), dirty: z.number().optional(), modified: z.number().optional(), untracked: z.number().optional(), ahead: z.number().optional(), behind: z.number().optional() });
568
+ export const GitInfoSchema = z.looseObject({ git: GitBadgeSchema.nullable().optional() });
525
569
  // ── tools ────────────────────────────────────────────────────────────────
526
570
  export const SkillSchema = z.looseObject({ name: z.string(), description: NullableString.optional(), category: NullableString.optional(), disabled: z.boolean().optional() });
527
571
  export const SkillsSchema = z.looseObject({ skills: z.array(SkillSchema), categories: z.array(Json).optional() });
528
- export const SkillContentSchema = z.looseObject({ name: z.string().optional(), content: z.string().optional(), path: z.string().optional(), success: z.boolean().optional(), message: z.string().optional(), ok: z.boolean().optional() });
572
+ /**
573
+ * `linked_files` groups the skill directory's files by folder (`references`, `templates`, ...); open one with `?file=`.
574
+ * A linked file that is not UTF-8 text carries `binary: true` and its `size` instead of `content`.
575
+ */
576
+ export const SkillContentSchema = z.looseObject({ name: z.string().optional(), content: z.string().optional(), path: z.string().optional(), linked_files: z.record(z.string(), z.array(z.string())).optional(), binary: z.literal(true).optional(), size: z.number().optional(), success: z.boolean().optional(), message: z.string().optional(), ok: z.boolean().optional() });
529
577
  export const SkillsUsageSchema = z.looseObject({ usage: z.record(z.string(), z.looseObject({ use_count: z.number().optional(), view_count: z.number().optional(), patch_count: z.number().optional() })), skill_names: z.array(z.string()).optional(), total_invocations: z.number().optional(), unique_skills_used: z.number().optional() });
530
578
  export const MemorySchema = z.looseObject({
531
579
  memory: z.string(), user: z.string(), soul: z.string(), project_context: z.string().optional(), memory_path: z.string().optional(), user_path: z.string().optional(), soul_path: z.string().optional(), project_context_path: z.string().optional(),
@@ -557,6 +605,28 @@ export const InsightsSchema = z.looseObject({
557
605
  models: z.array(z.looseObject({ model: z.string().optional(), sessions: z.number().optional(), tokens: z.number().optional(), cost: z.number().optional() })).optional(),
558
606
  });
559
607
  export const DashboardStatusSchema = z.looseObject({ running: z.boolean(), enabled: z.string().optional(), url: z.string().optional(), browser_url: z.string().optional(), host: z.string().optional(), port: z.number().int().optional(), version: z.string().optional(), error: z.string().optional() });
608
+ /**
609
+ * Gateway status for the Settings banner (TAL-266). `running` and `configured` come from the Agent health probe; when it
610
+ * is inconclusive, stale running metadata or known gateway sessions mark the gateway configured. `platforms` are the
611
+ * messaging platforms of known gateway sessions; `last_active` is the gateway session index's ISO mtime while running, else "".
612
+ */
613
+ export const GatewayStatusSchema = z.object({
614
+ running: z.boolean(), configured: z.boolean(), platforms: z.array(z.object({ name: z.string(), label: z.string() })), last_active: z.string(), session_count: z.number().int(),
615
+ health: z.object({ state: NullableString, reason: NullableString, gateway_state: NullableString }),
616
+ });
617
+ export const GatewayActionSchema = z.object({ ok: z.literal(true), action: z.enum(['start', 'stop', 'restart']), message: z.string(), status: GatewayStatusSchema });
618
+ export const DashboardConfigSchema = z.object({ enabled: z.enum(['auto', 'always', 'never']), url: z.string() });
619
+ /**
620
+ * Project OS dashboard for a repo found from the last workspace or the `board`'s default workdir (TAL-266). Every field is
621
+ * null or empty when the profile has no local workspace I/O or no repo is found. `onboarding.active` means the docs came
622
+ * from the repo root's `PROJECT.md`/`PLAN.md`/`STATUS.md` instead of `docs/project-os/`.
623
+ */
624
+ export const ProjectOsDashboardSchema = z.object({
625
+ workspace: NullableString, repo_root: NullableString, selected_board_slug: NullableString.optional(), git: GitBadgeSchema.nullable(),
626
+ docs: z.object({ project: FileContentSchema.nullable(), plan: FileContentSchema.nullable(), status: FileContentSchema.nullable(), blocker_resolver: FileContentSchema.nullable() }).partial(),
627
+ handoff: z.record(z.string(), Json).nullable(), active: z.record(z.string(), Json).nullable(), heartbeat: z.record(z.string(), Json).nullable(),
628
+ onboarding: z.looseObject({ active: z.boolean(), doc_source: z.enum(['project-os', 'root']) }).optional(), goal_summary: z.string(),
629
+ });
560
630
  export const AgentHealthSchema = z.looseObject({ alive: z.boolean().nullable().optional(), checked_at: z.string().optional(), details: z.looseObject({ state: z.string().optional(), reason: z.string().optional() }).optional(), gateway_chat: z.looseObject({ enabled: z.boolean().optional(), backend: z.string().optional(), base_url_configured: z.boolean().optional(), api_key_configured: z.boolean().optional() }).optional(), error: z.string().optional() });
561
631
  export const SystemHealthSchema = z.looseObject({
562
632
  available: z.boolean().optional(), status: z.string().optional(), checked_at: z.string().optional(), cpu: Json.nullable().optional(), memory: Json.nullable().optional(), disk: z.looseObject({ percent: z.number().optional(), total_bytes: z.number().optional(), used_bytes: z.number().optional() }).nullable().optional(),
@@ -569,9 +639,18 @@ export const UpdateTargetSchema = z.looseObject({ name: z.string().optional(), c
569
639
  installed_unverified: z.boolean().describe('`release_ready` only: the installed revision sits on no release tag.'),
570
640
  manual_link: z.boolean().describe('Show the manual-install (releases) link.'),
571
641
  target_version: z.string().nullable().describe('The version the update path leads to, when one is shown.'),
642
+ summary_available: z.boolean().describe('TAL-759: offer "Summarize with AI" for this target (`release_ready` or `commits_behind`).'),
572
643
  });
573
644
  export const UpdatesCheckSchema = z.looseObject({ disabled: z.boolean().optional(), cached: z.boolean().optional(), channel: z.string().optional(), agent_channel: z.enum(['stable', 'experimental']).optional(), checked_at: z.number().optional(), include_agent: z.boolean().optional(), webui: UpdateTargetSchema.nullable().optional(), agent: UpdateTargetSchema.nullable().optional() });
574
- export const UpdatesSummarySchema = z.looseObject({ summary: z.string().optional(), text: z.string().optional(), ok: z.boolean().optional(), error: z.string().optional(), diff_links: z.array(Json).optional() });
645
+ export const UpdatesSummarySchema = z.object({
646
+ ok: z.boolean(), target: z.enum(['webui', 'agent']), summary: z.string(),
647
+ current_version: z.string().nullable().describe('The installed version this summary starts from.'),
648
+ target_version: z.string().nullable().describe('The version this summary leads to, when the update names one.'),
649
+ summary_sections: z.array(z.object({ title: z.string(), items: z.array(z.string()) })).describe('Display-ready headed bullet lists; empty when nothing is pending.'),
650
+ generated_by: z.enum(['llm', 'fallback', 'none']).describe('`fallback` when no model answered; `none` when the target has no pending update to summarize.'),
651
+ source: z.enum(['release_notes', 'commits', 'none']).describe('Stable targets summarize the release notes they install; commit-tracking targets, or unreadable notes, use commit subjects.'),
652
+ cached: z.boolean(),
653
+ });
575
654
  export const UpdateApplySchema = z.looseObject({ ok: z.boolean().optional(), status: z.string().optional(), error: z.string().optional(), message: z.string().optional(), lock: Json.optional(), confirmation_required: z.boolean().optional(), candidate_revision: z.string().optional(), supported_revision: z.string().optional(), supported_version: z.string().optional(), agent_channel: z.enum(['stable', 'experimental']).optional(), notification_id: z.uuid().optional(), channel_switch: z.boolean().optional(), backup_dir: z.string().nullable().optional(), backup_failed: z.boolean().optional(), stash_conflict: z.boolean().optional() });
576
655
  export const UpdateNotificationPhaseSchema = z.enum(['applying', 'awaiting_confirmation', 'restarting', 'succeeded', 'blocked', 'failed', 'unknown']);
577
656
  export const UpdateNotificationActionSchema = z.object({
@@ -637,6 +716,18 @@ export const McpServerSchema = z.looseObject({ name: z.string(), id: z.string().
637
716
  export const McpServersSchema = z.looseObject({ servers: z.array(McpServerSchema), health_pending: z.boolean().optional(), reload_required: z.boolean().optional(), toggle_supported: z.boolean().optional() });
638
717
  export const McpToolsSchema = z.looseObject({ tools: z.array(z.looseObject({ name: z.string().optional(), server: z.string().optional(), description: z.string().optional() })), total: z.number().int().optional(), source: z.string().optional(), inventory_scope: z.string().optional(), unavailable_servers: z.array(z.string()).optional() });
639
718
  export const NotesSourcesSchema = z.looseObject({ enabled: z.boolean().optional(), sources: z.array(Json).optional(), source: z.string().optional(), inventory_scope: z.string().optional(), recent_ai_notes: z.array(Json).optional(), attach_supported: z.boolean().optional(), automatic_recall_unchanged: z.boolean().optional() });
719
+ /** Joplin search hit: bounded, redacted display text and a snippet around the query; `updated_time` is Joplin's raw value. */
720
+ export const NoteSearchResultSchema = z.object({ id: z.string(), title: z.string(), snippet: z.string(), parent_id: z.string(), updated_time: Json, source: z.literal('joplin') });
721
+ export const NotesSearchSchema = z.object({ source: z.literal('joplin'), query: z.string(), results: z.array(NoteSearchResultSchema) });
722
+ /** One Joplin note for preview: `body` is cut at 50,000 characters (with a notice) and redacted. */
723
+ export const NoteItemSchema = z.object({ source: z.literal('joplin'), note: z.object({ id: z.string(), title: z.string(), body: z.string(), parent_id: z.string(), updated_time: Json, created_time: Json, source: z.literal('joplin') }) });
724
+ /** LLM wiki summary: counts and timestamps only, never page bodies or the wiki path. `error` names the exception type when `status` is `error`. */
725
+ export const WikiStatusSchema = z.object({
726
+ available: z.boolean(), enabled: z.boolean(), status: z.enum(['missing', 'not_directory', 'ready', 'empty', 'error']), entry_count: z.number().int(), page_count: z.number().int(), raw_source_count: z.number().int(),
727
+ last_updated: z.string().nullable(), last_writer: z.string(), path_configured: z.boolean(), path_source: z.string(), toggle_available: z.literal(false), toggle_reason: z.string(), docs_url: z.string(), error: z.string().optional(),
728
+ });
729
+ export const WikiBrowseSchema = z.object({ pages: z.array(z.object({ name: z.string(), path: z.string(), size: z.number().int(), mtime: z.number().int() })) });
730
+ export const WikiPageSchema = z.object({ content: z.string(), path: z.string() });
640
731
  export const TodoItemSchema = z.looseObject({ id: z.union([z.string(), z.number()]).optional(), text: z.string().optional(), content: z.string().optional(), title: z.string().optional(), status: z.string().optional(), done: z.boolean().optional(), completed: z.boolean().optional() });
641
732
  export const TodoStateSchema = z.looseObject({ session_id: z.string().optional(), todos: z.array(TodoItemSchema).optional(), summary: z.record(z.string(), z.unknown()).optional(), version: z.number().optional(), ts: z.number().optional(), source: z.string().optional(), description: z.string().optional(), pending_count: z.number().optional() });
642
733
  // ── onboarding ───────────────────────────────────────────────────────────
@@ -674,8 +765,15 @@ export const CronJobViewSchema = z.looseObject({
674
765
  context_from: z.union([z.array(z.string()), z.string(), z.null()]).optional(), reasoning_effort: NullableString.optional(), toast_notifications: z.boolean().optional(), running: z.boolean().optional(),
675
766
  /** Server-derived (TAL-296): the job's status, whether it needs attention, and whether its primary action is Resume. Live runs overlay it. */
676
767
  derived_state: CronDerivedStateSchema.optional(), needs_attention: z.boolean().optional(), resumable: z.boolean().optional(),
768
+ /** Server-derived (TAL-599): a known cause clients explain in the needs-attention banner. */
769
+ attention_hint: z.enum(['croniter_missing']).nullable(),
770
+ });
771
+ export const CronsSchema = z.looseObject({
772
+ jobs: z.array(CronJobViewSchema),
773
+ /** TAL-601: `jobs` arrive in display order (running first, then soonest next run, none last, then name); clients keep it. Absent from older servers. */
774
+ ordered: z.boolean().optional(),
775
+ active_profile: z.string().optional(), all_profiles: z.boolean().optional(), other_profile_count: z.number().optional(), cron_unavailable: z.boolean().optional(),
677
776
  });
678
- export const CronsSchema = z.looseObject({ jobs: z.array(CronJobViewSchema), active_profile: z.string().optional(), all_profiles: z.boolean().optional(), other_profile_count: z.number().optional(), cron_unavailable: z.boolean().optional() });
679
777
  export const CronContextSourcesSchema = z.object({ profile: z.string(), sources: z.array(z.object({ job_id: z.string(), label: z.string(), selectable: z.boolean() })) });
680
778
  /** `GET /api/crons/recent` row: one job's latest completion, ordered and classified by the server. */
681
779
  export const CronRecentCompletionSchema = z.object({
@@ -687,7 +785,8 @@ export const CronMutationSchema = z.looseObject({ ok: z.boolean().optional(), jo
687
785
  export const CronRunUsageSchema = z.looseObject({ input_tokens: NullableNumber.optional(), output_tokens: NullableNumber.optional(), total_tokens: NullableNumber.optional(), estimated_cost_usd: NullableNumber.optional(), duration_seconds: NullableNumber.optional(), model: z.string().optional(), provider: z.string().optional() });
688
786
  export const CronRunSummarySchema = z.looseObject({ filename: z.string(), size: z.number(), modified: z.number(), usage: CronRunUsageSchema.optional() });
689
787
  export const CronHistorySchema = z.looseObject({ job_id: z.string().optional(), runs: z.array(CronRunSummarySchema), total: z.number().optional(), offset: z.number().optional() });
690
- export const CronRunSchema = z.looseObject({ content: z.string().optional(), snippet: z.string().optional(), usage: CronRunUsageSchema.optional(), error: z.string().optional() });
788
+ /** `response` is server-extracted (TAL-599): the agent's reply after the run file's `## Response` heading, else the whole text. */
789
+ export const CronRunSchema = z.looseObject({ content: z.string().optional(), snippet: z.string().optional(), response: z.string().optional(), usage: CronRunUsageSchema.optional(), error: z.string().optional() });
691
790
  export const CronStatusSchema = z.looseObject({ running: z.union([z.boolean(), z.record(z.string(), z.number())]).optional() });
692
791
  /** Card actions the server offers for a task's current status (TAL-557); clients show exactly these. `move_to` lists the statuses a Move may target, in display order. */
693
792
  export const KanbanTaskActionsSchema = z.object({ block: z.boolean(), unblock: z.boolean(), complete: z.boolean(), archive: z.boolean(), move_to: z.array(z.string()) });