@maudecode/talaria-web-contracts 1.19.0 → 1.20.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/context-detail.d.ts +75 -0
  2. package/dist/context-detail.js +18 -0
  3. package/dist/context-detail.js.map +1 -0
  4. package/dist/gateway-session.d.ts +253 -7
  5. package/dist/gateway-session.js +63 -3
  6. package/dist/gateway-session.js.map +1 -1
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/router.d.ts +1398 -191
  11. package/dist/routes/automation.d.ts +9 -7
  12. package/dist/routes/automation.js +1 -1
  13. package/dist/routes/automation.js.map +1 -1
  14. package/dist/routes/chat.d.ts +303 -40
  15. package/dist/routes/chat.js +4 -3
  16. package/dist/routes/chat.js.map +1 -1
  17. package/dist/routes/core.d.ts +4 -4
  18. package/dist/routes/git.d.ts +9 -0
  19. package/dist/routes/git.js +6 -1
  20. package/dist/routes/git.js.map +1 -1
  21. package/dist/routes/raw.js +9 -5
  22. package/dist/routes/raw.js.map +1 -1
  23. package/dist/routes/sessions.d.ts +921 -124
  24. package/dist/routes/sessions.js +6 -0
  25. package/dist/routes/sessions.js.map +1 -1
  26. package/dist/routes/settings.d.ts +29 -13
  27. package/dist/routes/settings.js +3 -2
  28. package/dist/routes/settings.js.map +1 -1
  29. package/dist/routes/tools.d.ts +314 -30
  30. package/dist/routes/tools.js +14 -4
  31. package/dist/routes/tools.js.map +1 -1
  32. package/dist/routes/workspaces.d.ts +4 -4
  33. package/dist/sidecar/methods.d.ts +816 -19
  34. package/dist/sidecar/methods.js +2 -2
  35. package/dist/sidecar/methods.js.map +1 -1
  36. package/dist/sidecar/namespaces.d.ts +959 -28
  37. package/dist/sidecar/namespaces.js +101 -14
  38. package/dist/sidecar/namespaces.js.map +1 -1
  39. package/dist/sidecar/rpc.d.ts +1 -0
  40. package/dist/sidecar/rpc.js +2 -0
  41. package/dist/sidecar/rpc.js.map +1 -1
  42. package/dist/sidecar/runtime.d.ts +13 -0
  43. package/dist/sidecar/runtime.js +9 -0
  44. package/dist/sidecar/runtime.js.map +1 -1
  45. package/dist/sidecar/version.d.ts +1 -1
  46. package/dist/sidecar/version.js +1 -1
  47. package/dist/sse.d.ts +83 -12
  48. package/dist/sse.js +8 -2
  49. package/dist/sse.js.map +1 -1
  50. package/dist/views.d.ts +584 -103
  51. package/dist/views.js +54 -11
  52. package/dist/views.js.map +1 -1
  53. package/fixtures/sidecar/aux.json +8 -0
  54. package/fixtures/sidecar/chat.json +14 -0
  55. package/fixtures/sidecar/checkpoints.json +7 -2
  56. package/fixtures/sidecar/context-detail.json +77 -0
  57. package/fixtures/sidecar/cron.json +3 -1
  58. package/fixtures/sidecar/dashboard_plugins.json +59 -0
  59. package/fixtures/sidecar/gateway.json +163 -0
  60. package/fixtures/sidecar/plugin-catalog.json +4 -0
  61. package/fixtures/sidecar/plugins.json +56 -1
  62. package/fixtures/sidecar/process.json +32 -0
  63. package/fixtures/sidecar/rpc.json +4 -0
  64. package/fixtures/sidecar/runtime.json +3 -3
  65. package/fixtures/sidecar/state_db.json +10 -0
  66. package/package.json +1 -1
@@ -1,7 +1,8 @@
1
+ import { ContextDetailSchema } from '../context-detail.js';
1
2
  import { z } from 'zod';
2
3
  import { ProviderPhaseSchema } from '../run-status.js';
3
4
  import { SpeedTierSchema } from '../speed.js';
4
- import { GatewaySessionParamsSchema, GatewaySessionResultSchema } from '../gateway-session.js';
5
+ import { GatewayClarifyBatchSchema, GatewayCreateParamsSchema, GatewaySessionParamsSchema, GatewaySessionResultSchema } from '../gateway-session.js';
5
6
  /** Warnings and wording come from the Agent's selection guard registry, including future guard kinds. */
6
7
  export const ModelSelectionWarningSchema = z.object({ kind: z.string(), title: z.string(), model: z.string(), provider: z.string(), message: z.string() });
7
8
  /** Shared param shapes. */
@@ -71,37 +72,84 @@ export const PluginSettingFieldSchema = z.object({
71
72
  key: z.string(), type: z.enum(['string', 'number', 'boolean', 'enum', 'json', 'secret']), label: z.string(), description: z.string(), required: z.boolean(),
72
73
  choices: z.array(z.string()).optional(), default: Json.optional(), value: Json.optional(), env: z.string().optional(), has_value: z.boolean().optional(),
73
74
  });
75
+ /** Persistence succeeded; this separately describes application to live plugin MCP connections. */
76
+ export const PluginRuntimeApplicationSchema = z.enum(['applied', 'restart_required', 'unknown']);
77
+ /** TAL-1276: one OAuth client a plugin manifest declares, its grant's state as `hermes auth status` maps it, and the hosts the code is approved at and exchanged at. */
78
+ export const PluginOAuthStateSchema = z.enum(['signed_in', 'sign_in_needed', 'revoked', 'logged_out']);
79
+ export const PluginOAuthClientSchema = z.object({ id: z.string(), state: PluginOAuthStateSchema, authorize_host: z.string(), token_host: z.string() });
80
+ export const PluginUpdateResultSchema = z.discriminatedUnion('status', [
81
+ z.object({ key: z.string(), status: z.literal('updated') }),
82
+ z.object({ key: z.string(), status: z.literal('needs_consent'), verdict: z.literal('caution'), findings: z.string(), consent_token: z.string().min(1) }),
83
+ z.object({ key: z.string(), status: z.literal('blocked'), verdict: z.string(), findings: z.string() }),
84
+ ]);
85
+ export const PluginCatalogQuerySchema = z.object({ query: z.string().trim().max(200).default(''), offset: z.coerce.number().int().min(0).max(10000).default(0), limit: z.coerce.number().int().min(1).max(50).default(20) });
86
+ export const PluginInstallInputSchema = z.object({ name: z.string().regex(/^[a-z0-9_-]{1,64}$/), consent_token: z.string().min(1).max(128).optional() });
87
+ export const PluginCatalogSchema = z.object({ supported: z.boolean(), read_only: z.boolean().optional(), entries: z.array(z.object({
88
+ name: z.string(), title: z.string(), description: z.string(), repo: z.string(), sha: z.string(), tier: z.string(), category: z.string(),
89
+ requirements: z.array(z.string()), installed_key: z.string().nullable(), installed_sha: z.string().nullable(), can_install: z.boolean(), refusal: z.string().nullable(),
90
+ })), total: z.number().int().nonnegative(), next_offset: z.number().int().nullable() });
91
+ export const PluginInstallResultSchema = z.discriminatedUnion('status', [
92
+ z.object({ name: z.string(), key: z.string(), status: z.literal('installed'), enabled: z.literal(false) }),
93
+ z.object({ name: z.string(), status: z.literal('needs_consent'), findings: z.string(), consent_token: z.string() }),
94
+ z.object({ name: z.string(), status: z.literal('blocked'), findings: z.string() }),
95
+ ]);
74
96
  export const PluginProviderSchema = z.object({ name: z.string(), display_name: z.string(), auth_type: z.string(), setup: z.enum(['ready', 'missing_cli', 'needs_setup', 'not_loaded', 'unavailable']) });
97
+ /** Profile-owned Agent dashboards use Web protocol panels; native Desktop bundles need migration. */
98
+ export const AgentDashboardPluginSchema = z.object({
99
+ name: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/), label: z.string().max(80), version: z.string().max(40), description: z.string().max(300),
100
+ enabled: z.boolean(), panel: z.string().nullable(), has_api: z.boolean(),
101
+ });
102
+ export const AgentDashboardResponseSchema = z.object({ status: z.number().int().min(200).max(599), body: z.string(), content_type: z.string() });
103
+ const DashboardNameParams = ProfileHomeParams.extend({ name: z.string() });
75
104
  /** A skill bundle: `/<name>` loads its `skill_count` skills in one message (TAL-265). */
76
105
  export const CommandBundleSchema = z.object({ name: z.string(), description: z.string(), skill_count: z.number().int(), source: z.literal('bundle') });
77
106
  /** `message` is the user message that loads the bundle's skills; members not installed or disabled are in `missing_skills` or left out. */
78
107
  export const CommandBundleInvocationSchema = z.object({ name: z.string(), source: z.literal('bundle'), message: z.string(), loaded_skills: z.array(z.string()), missing_skills: z.array(z.string()) });
79
108
  export const COMMANDS_METHODS = {
80
109
  'commands.registry': { params: ProfileHomeParams, result: z.object({ commands: z.array(CommandSchema) }) },
81
- /** With `session_id`, a plugin command runs under that chat's session binding and `workspace` (TAL-904). */
110
+ /**
111
+ * With `session_id`, a plugin command runs under that chat's session binding and `workspace` (TAL-904) and receives the session
112
+ * as its handler declares it; every recognised command fires the Agent's `pre_command` hook with that session (TAL-1267).
113
+ */
82
114
  'commands.exec': { params: ProfileHomeParams.extend({ command: z.string().min(1), session_id: z.string().min(1).optional(), workspace: z.string().optional() }), result: z.object({ output: z.string(), source: z.enum(['agent', 'plugin']) }) },
83
115
  /**
84
116
  * `/<prompt built-in> [args]` as the turn text (`message`) the Agent's builder writes for the session's profile, workspace and toolsets.
85
117
  * `name` is the built-in's canonical name, null when the command is not one; `message` is null when this Agent has no builder for it.
86
- * A failing builder errors `prompt_expand_failed`.
118
+ * A failing builder errors `prompt_expand_failed`. Every built-in fires the Agent's `pre_command` hook with `session_id` (TAL-1279).
87
119
  */
88
- 'commands.expand_prompt': { params: ProfileHomeParams.extend({ command: z.string().min(1), workspace: z.string(), enabled_toolsets: z.array(z.string()).nullable() }), result: z.object({ name: z.string().nullable(), message: z.string().nullable() }) },
120
+ 'commands.expand_prompt': { params: ProfileHomeParams.extend({ command: z.string().min(1), session_id: z.string().min(1).optional(), workspace: z.string(), enabled_toolsets: z.array(z.string()).nullable() }), result: z.object({ name: z.string().nullable(), message: z.string().nullable() }) },
89
121
  'commands.bundles': { params: ProfileHomeParams, result: z.object({ bundles: z.array(CommandBundleSchema) }) },
90
122
  'commands.bundle_resolve': { params: ProfileHomeParams.extend({ command: z.string().min(1) }), result: CommandBundleInvocationSchema },
91
123
  'commands.moa_preset': { params: ProfileHomeParams.extend({ preset: z.string().nullable().optional() }), result: z.object({ moa: Loose }) },
124
+ 'plugins.dashboard_list': { params: ProfileHomeParams, result: z.object({ supported: z.boolean(), plugins: z.array(AgentDashboardPluginSchema) }) },
125
+ 'plugins.dashboard_toggle': { params: DashboardNameParams.extend({ enabled: z.boolean() }), result: z.object({ ok: z.literal(true) }) },
126
+ 'plugins.dashboard_asset': { params: DashboardNameParams.extend({ path: z.string() }), result: AgentDashboardResponseSchema },
127
+ /** Buffered HTTP only. Cancellation abandons the result; the Agent has no handler-cancel operation. */
128
+ 'plugins.dashboard_request': { params: DashboardNameParams.extend({ path: z.string(), method: z.string(), query: z.string(), headers: z.record(z.string(), z.string()), body: z.string(), authenticated: z.boolean(), websocket: z.boolean() }), result: AgentDashboardResponseSchema },
92
129
  'plugins.providers': { params: ProfileHomeParams, result: z.object({ providers: z.array(PluginProviderSchema) }) },
93
- 'plugins.list': { params: ProfileHomeParams.extend({ selected_providers: z.record(z.string(), z.string()).optional() }), result: z.object({ plugins: z.array(z.object({ name: z.string(), key: z.string(), version: z.string(), description: z.string(), enabled: z.boolean(), kind: z.string(), activation: z.string(), hooks: z.array(z.string()), is_active_provider: z.boolean().optional() })), supported_hooks: z.array(z.string()) }) },
130
+ 'plugins.list': { params: ProfileHomeParams.extend({ selected_providers: z.record(z.string(), z.string()).optional() }), result: z.object({ plugins: z.array(z.object({ name: z.string(), key: z.string(), version: z.string(), description: z.string(), enabled: z.boolean(), kind: z.string(), activation: z.string(), hooks: z.array(z.string()), is_active_provider: z.boolean().optional(), update_available: z.boolean().optional(), latest_revision: z.string().optional() })), supported_hooks: z.array(z.string()) }) },
131
+ 'plugins.catalog': { params: ProfileHomeParams.extend(PluginCatalogQuerySchema.shape), result: PluginCatalogSchema },
132
+ 'plugins.install': { params: ProfileHomeParams.extend(PluginInstallInputSchema.shape), result: PluginInstallResultSchema },
133
+ 'plugins.update': { params: ProfileHomeParams.extend({ key: z.string().min(1), accept_caution: z.boolean().optional(), consent_token: z.string().min(1).max(128).optional() }), result: PluginUpdateResultSchema },
94
134
  /** TAL-820: each profile's `plugins.isolation` and installed third-party plugin count, read without loading a plugin. */
95
135
  'plugins.isolation': { params: BaseHomeParams, result: z.object({ profiles: z.array(z.object({ name: z.string(), isolation: z.enum(['in_process', 'host']), third_party_plugins: z.number().int() })) }) },
96
136
  /** TAL-806: plugins whose manifest declares settings; `supported` is false on an Agent without `hermes_cli.plugins_settings`. */
97
137
  'plugins.settings': { params: ProfileHomeParams, result: z.object({ supported: z.boolean(), plugins: z.array(z.object({ key: z.string(), fields: z.array(PluginSettingFieldSchema) })) }) },
138
+ /**
139
+ * TAL-1276: plugins whose manifest declares OAuth clients (Agent v0.22.3+), each client's sign-in state as
140
+ * `hermes auth status <plugin>:<id>` reports it, and the hosts the CLI names before signing in: the code is approved
141
+ * at `authorize_host` and exchanged at `token_host`. `supported` is false on an Agent without the plugin OAuth helpers.
142
+ */
143
+ 'plugins.oauth_status': { params: ProfileHomeParams, result: z.object({ supported: z.boolean(), plugins: z.array(z.object({ key: z.string(), clients: z.array(PluginOAuthClientSchema) })) }) },
144
+ /** TAL-1276: `hermes auth logout <plugin>:<id>`; `removed` is false when no grant was stored. Errors `oauth_unsupported` on older Agents. */
145
+ 'plugins.oauth_logout': { params: ProfileHomeParams.extend({ key: z.string().min(1), id: z.string().min(1) }), result: z.object({ key: z.string(), id: z.string(), removed: z.boolean() }) },
98
146
  /**
99
147
  * TAL-806: write non-secret `values` through the Agent's locked plugin-state writer and return the refreshed fields.
100
148
  * An undeclared key, a secret or a type mismatch is invalid params; a managed install or key errors `plugin_settings_managed`.
101
149
  * `secret_envs` (secret key → `.env` name the caller wrote) is checked against the current manifest before anything is
102
150
  * written; a key that is no longer a secret stored under that name errors `plugin_settings_changed`.
103
151
  */
104
- 'plugins.settings_save': { params: ProfileHomeParams.extend({ key: z.string().min(1), values: z.record(z.string(), Json), secret_envs: z.record(z.string(), z.string()).optional() }), result: z.object({ key: z.string(), written: z.array(z.string()), fields: z.array(PluginSettingFieldSchema) }) },
152
+ 'plugins.settings_save': { params: ProfileHomeParams.extend({ key: z.string().min(1), values: z.record(z.string(), Json), secret_envs: z.record(z.string(), z.string()).optional() }), result: z.object({ key: z.string(), written: z.array(z.string()), fields: z.array(PluginSettingFieldSchema), runtime_application: PluginRuntimeApplicationSchema.optional() }) },
105
153
  };
106
154
  // ── kanban ─────────────────────────────────────────────────────────────
107
155
  const Board = ProfileHomeParams.extend({ board: z.string().nullable().optional() });
@@ -166,6 +214,12 @@ export const STATE_DB_METHODS = {
166
214
  'state_db.delete_cli_session': { params: Session.extend({ include_compression_lineage: z.boolean().optional() }), result: Ok.extend({ refused: SessionDeleteRefusedSchema.optional(), deleted_ids: z.array(z.string().min(1)).optional() }) },
167
215
  /** TAL-258: append one row through the Agent's `SessionDB.append_message` (bumps `message_count`); `ok` is false without a state.db. */
168
216
  'state_db.append_message': { params: Session.extend({ role: z.string().min(1), content: z.string(), tool_name: z.string().nullable().optional(), timestamp: z.number().nullable().optional() }), result: Ok },
217
+ /**
218
+ * TAL-1274: the Agent's low-disk session auto-prune question for the profile (Agent v0.22.3 `hermes_cli.prune_advisor`), as the
219
+ * Agent's own `lines` naming `/autoprune on|off|later`; null while the Agent would not ask (disk not low, `sessions.auto_prune`
220
+ * set, or snoozed) or has no advisor. May measure state.db, which takes seconds on a large store.
221
+ */
222
+ 'state_db.prune_advice': { params: ProfileHomeParams, result: z.object({ advice: z.object({ lines: z.array(z.string()).min(1) }).nullable() }) },
169
223
  };
170
224
  // ── profiles ───────────────────────────────────────────────────────────
171
225
  /** TAL-213: the profile's canonical Bot Chat (its session titled exactly "Bot Chat") and that chat's live compression tip. */
@@ -312,7 +366,7 @@ export const CRON_METHODS = {
312
366
  'cron.history': { params: CronJob.extend({ offset: z.number().int().optional(), limit: z.number().int().optional() }), result: z.object({ job_id: z.string(), runs: z.array(z.object({ filename: z.string(), size: z.number().int(), modified: z.number(), usage: CronUsageSchema })), total: z.number().int(), offset: z.number().int() }) },
313
367
  'cron.run_detail': { params: CronJob.extend({ filename: z.string().min(1) }), result: z.object({ job_id: z.string(), filename: z.string(), content: z.string(), snippet: z.string(), usage: CronUsageSchema }) },
314
368
  'cron.output': { params: CronJob.extend({ limit: z.number().int().optional() }), result: z.object({ job_id: z.string(), outputs: z.array(z.object({ filename: z.string(), content: z.string() })) }) },
315
- 'cron.delivery_options': { params: z.object({}), result: z.object({ platforms: z.array(z.object({ value: z.string(), label: z.string() })) }) },
369
+ 'cron.delivery_options': { params: ProfileHomeParams, result: z.object({ platforms: z.array(z.object({ value: z.string(), label: z.string() })) }) },
316
370
  };
317
371
  // ── providers / models ─────────────────────────────────────────────────
318
372
  /**
@@ -339,14 +393,21 @@ export const PROVIDERS_METHODS = {
339
393
  * `oauth.start` answers the code to show; a sidecar thread polls the provider and writes the credential through the
340
394
  * Agent's own auth store. A flow belongs to the profile home that started it: poll and cancel from another home do not
341
395
  * find it. `error` is the Agent's reason for a flow that ended without a credential.
396
+ *
397
+ * TAL-1276: provider `plugin:<key>:<id>` is the browser sign-in of a plugin-declared OAuth client. Its start has no
398
+ * `user_code`; `verification_url` is the authorize link, `redirect_uri` the loopback address the browser is sent back
399
+ * to, and `authorize_host`/`token_host` the hosts the code goes to. It finishes when that redirect reaches the sidecar's
400
+ * listener or through `oauth.submit_redirect` with the address the browser showed (`oauth_redirect_invalid` for any
401
+ * other address, `oauth_flow_ended` once the flow ended).
342
402
  */
343
403
  export const OAuthFlowStatusSchema = z.enum(['pending', 'approved', 'denied', 'expired', 'cancelled', 'error']);
344
404
  const OAuthFlow = z.object({ flow_id: z.string(), provider: z.string(), status: OAuthFlowStatusSchema, error: z.string().nullable() });
345
405
  const OAuthFlowParams = ProfileHomeParams.extend({ flow_id: z.string().min(1) });
346
406
  export const OAUTH_METHODS = {
347
- 'oauth.start': { params: ProfileHomeParams.extend({ provider: z.string().min(1) }), result: z.object({ flow_id: z.string(), provider: z.string(), status: z.literal('pending'), user_code: z.string(), verification_url: z.string(), expires_in: z.number().int(), interval: z.number().int() }) },
407
+ 'oauth.start': { params: ProfileHomeParams.extend({ provider: z.string().min(1) }), result: z.object({ flow_id: z.string(), provider: z.string(), status: z.literal('pending'), user_code: z.string().optional(), verification_url: z.string(), expires_in: z.number().int(), interval: z.number().int(), redirect_uri: z.string().optional(), authorize_host: z.string().optional(), token_host: z.string().optional() }) },
348
408
  'oauth.poll': { params: OAuthFlowParams, result: OAuthFlow },
349
409
  'oauth.cancel': { params: OAuthFlowParams, result: OAuthFlow },
410
+ 'oauth.submit_redirect': { params: OAuthFlowParams.extend({ url: z.string().min(1) }), result: OAuthFlow },
350
411
  };
351
412
  // ── aux / text / process / usage / gateway ─────────────────────────────
352
413
  export const AuxUsageSchema = z.object({ prompt_tokens: z.number().int().optional(), completion_tokens: z.number().int().optional(), total_tokens: z.number().int().optional() });
@@ -420,6 +481,7 @@ export const PROCESS_METHODS = {
420
481
  /** Hands back a claim the busy target never admitted, without spending one of the Agent's delivery attempts. */
421
482
  'process.defer_delivery': { params: ProfileHomeParams.extend({ event: Loose, claim_id: z.string() }), result: Ok },
422
483
  'process.format_notification': { params: z.object({ event: Loose }), result: z.object({ text: z.string() }) },
484
+ 'process.stop': { params: ProfileHomeParams.extend({ session_id: z.string().min(1), process_id: z.string().min(1) }), result: z.object({ outcome: z.enum(['stopped', 'not_running', 'not_found']) }) },
423
485
  'process.list': { params: ProfileHomeParams, result: z.object({ sessions: z.array(Loose) }) },
424
486
  /** TAL-372: the Agent's view of these WebUI sessions' background work: ledger delegations (with live status) and notified processes. */
425
487
  'process.background_list': {
@@ -490,6 +552,12 @@ export const CONFIG_METHODS = {
490
552
  };
491
553
  export const WORKTREE_METHODS = {
492
554
  'worktree.create': { params: ProfileHomeParams.extend({ repo_root: z.string().min(1) }), result: z.object({ path: z.string(), branch: z.string(), repo_root: z.string(), base: z.string().nullable() }) },
555
+ /**
556
+ * TAL-1254: relock Talaria's worktrees for this sidecar (`hermes pid=<pid>`) so the Agent's worktree sweep reads them as
557
+ * live. `foreign_lock`: a lock that is not a `hermes pid=` one holds the tree and stays. A tree this sidecar does not
558
+ * hold yet (a running process's `hermes pid=` lock, or a git failure) is absent from `results`; the caller retries it.
559
+ */
560
+ 'worktree.retain': { params: z.object({ paths: z.array(z.string().min(1)) }), result: z.object({ results: z.record(z.string(), z.enum(['retained', 'missing', 'foreign_lock'])) }) },
493
561
  };
494
562
  /** TAL-913: a workspace's checkpoints, read and restored through the Agent's `CheckpointManager`; `store` is its shared git store. */
495
563
  const CheckpointTarget = ProfileHomeParams.extend({ workspace: z.string().min(1) });
@@ -498,7 +566,14 @@ export const CHECKPOINTS_METHODS = {
498
566
  'checkpoints.list': { params: CheckpointTarget, result: z.object({ checkpoints: z.array(AgentCheckpointSchema), store: z.string() }) },
499
567
  /** `diff` is `git diff <checkpoint> --cached` over the workspace: `a/` is the checkpoint, `b/` the files now. */
500
568
  'checkpoints.diff': { params: CheckpointTarget.extend({ checkpoint: z.string().min(1) }), result: z.object({ stat: z.string(), diff: z.string() }) },
501
- 'checkpoints.restore': { params: CheckpointTarget.extend({ checkpoint: z.string().min(1) }), result: z.object({ restored_to: z.string(), reason: z.string() }) },
569
+ /**
570
+ * Safe unless `all` (TAL-1260): only files still as the Agent last wrote them are reverted, and `kept_user_edits` names the
571
+ * hand-edited ones left in place. `restored_files` is what a safe restore acted on; null when the whole tree was checked out.
572
+ */
573
+ 'checkpoints.restore': {
574
+ params: CheckpointTarget.extend({ checkpoint: z.string().min(1), all: z.boolean().optional() }),
575
+ result: z.object({ restored_to: z.string(), reason: z.string(), restored_files: z.array(z.string()).nullable(), kept_user_edits: z.array(z.string()), skipped_oversize: z.array(z.string()), failed_deletes: z.array(z.string()) }),
576
+ },
502
577
  };
503
578
  // ── chat / approval / clarify ──────────────────────────────────────────
504
579
  export const ChatUsageSchema = z.object({ prompt_tokens: z.number().int(), completion_tokens: z.number().int(), cache_read_tokens: z.number().int(), cache_write_tokens: z.number().int(), estimated_cost_usd: z.number().nullable() });
@@ -540,6 +615,7 @@ export const ChatStreamSchema = z.discriminatedUnion('event', [
540
615
  /** TAL-397: the Agent's session counters, before the content frame that follows a change. */
541
616
  z.object({ event: z.literal('usage'), data: ChatUsageSchema }),
542
617
  z.object({ event: z.literal('tool'), data: ToolFrame }),
618
+ z.object({ event: z.literal('tool_progress'), data: z.object({ tool_call_id: z.string(), message: z.string().nullable().optional(), progress: z.number().nullable().optional(), total: z.number().nullable().optional(), percent: z.number().nullable().optional() }) }),
543
619
  z.object({ event: z.literal('tool_complete'), data: ToolFrame }),
544
620
  z.object({ event: z.literal('approval'), data: Loose }),
545
621
  z.object({ event: z.literal('clarify'), data: Loose }),
@@ -628,9 +704,12 @@ export const CHAT_METHODS = {
628
704
  commit_token: z.string().nullable(),
629
705
  }),
630
706
  },
707
+ /** TAL-1333: safe metadata from the existing matching resident Agent, never a new Agent. */
708
+ 'chat.context_detail': { params: ProfileHomeParams.extend({ session_id: z.string().min(1), model: z.string().nullable(), model_provider: z.string().nullable(), workspace: z.string().nullable() }), result: ContextDetailSchema },
631
709
  /** TAL-255: second phase of `chat.compress`; `finalized: false` when the token is unknown or already expired. */
632
710
  'chat.compress_finalize': { params: z.object({ commit_token: z.string().min(1), committed: z.boolean() }), result: z.object({ finalized: z.boolean() }) },
633
- 'chat.finalize_session': { params: ProfileHomeParams.extend({ session_id: z.string().min(1), reason: z.enum(['clear', 'delete']) }), result: z.object({ messages: z.array(z.string()) }) },
711
+ /** Archive only emits on_session_delete for the committed local transition; it never closes the Agent session. */
712
+ 'chat.finalize_session': { params: ProfileHomeParams.extend({ session_id: z.string().min(1), reason: z.enum(['clear', 'delete', 'archive']), lineage: z.array(z.string().min(1)).max(10_000).optional() }), result: z.object({ messages: z.array(z.string()) }) },
634
713
  'chat.evict_agent': { params: z.object({ session_id: z.string().min(1), clear_session: z.boolean().optional() }), result: z.object({ evicted: z.boolean() }) },
635
714
  'chat.commit_memory': { params: ProfileHomeParams.extend({ session_id: z.string().min(1) }), result: z.object({ committed: z.boolean() }) },
636
715
  /**
@@ -653,18 +732,26 @@ export const CHAT_METHODS = {
653
732
  'approval.set_yolo': { params: z.object({ session_id: z.string().min(1), enabled: z.boolean() }), result: z.object({ yolo_enabled: z.boolean(), released: z.number().int() }) },
654
733
  'clarify.respond': { params: z.object({ stream_id: z.string().optional(), session_id: z.string().optional(), clarify_id: z.string().optional(), response: z.string() }), result: z.object({ ok: z.boolean(), clarify_id: z.string().optional() }) },
655
734
  };
656
- const GatewayActionParams = ProfileHomeParams.extend({ cli_profile: z.string().nullable().optional(), quick_timeout_seconds: z.number().optional(), background_wait_seconds: z.number().optional() });
735
+ const GatewayActionParams = ProfileHomeParams.extend({ interrupt: z.boolean().optional(), cli_profile: z.string().nullable().optional(), quick_timeout_seconds: z.number().optional(), background_wait_seconds: z.number().optional() });
657
736
  /**
658
737
  * A lifecycle run of `hermes --profile <name> gateway <action>` for the profile at `profile_home` (TAL-894). `busy` means another
659
- * action holds the lock; `timed_out` marks a child killed after `background_wait_seconds` (a restart defaults to the Agent CLI's own
738
+ * action holds the lock; `busy_live_work` is an Agent live-work refusal. `interrupt` explicitly consents to interruption.
739
+ * `timed_out` marks a child killed after `background_wait_seconds` (a restart defaults to the Agent CLI's own
660
740
  * restart budget plus 30 s) or cancelled. `detail` is CLI output, never shown to a browser; `reason` is the Agent's first error line of a
661
741
  * failed run (TAL-884), the one line the server shows.
662
742
  */
663
- const GatewayActionResult = z.object({ status: z.enum(['completed', 'failed', 'busy']), message: z.string(), detail: z.string().optional(), returncode: z.number().int().optional(), reason: z.string().optional(), timed_out: z.boolean().optional() });
743
+ const GatewayActionResult = z.object({ status: z.enum(['completed', 'failed', 'busy', 'busy_live_work']), message: z.string(), detail: z.string().optional(), returncode: z.number().int().optional(), reason: z.string().optional(), timed_out: z.boolean().optional() });
664
744
  const GatewayActionStream = z.discriminatedUnion('event', [z.object({ event: z.literal('progress'), data: z.object({ phase: z.enum(['started', 'draining']) }) })]);
665
745
  export const GATEWAY_ACTIONS = ['start', 'stop', 'restart'];
666
746
  export const GATEWAY_METHODS = {
667
- 'gateway.session': { params: GatewaySessionParamsSchema, result: GatewaySessionResultSchema, stream: z.object({ event: z.enum(['snapshot', 'event']), data: Loose }) },
747
+ 'gateway.session': { params: GatewaySessionParamsSchema, result: GatewaySessionResultSchema, stream: z.discriminatedUnion('event', [
748
+ z.object({ event: z.literal('snapshot'), data: GatewaySessionResultSchema.extend({ replaying: z.boolean().optional() }) }),
749
+ z.object({ event: z.literal('event'), data: Loose }),
750
+ z.object({ event: z.literal('replay_complete'), data: z.object({}) }),
751
+ z.object({ event: z.literal('clarify_batch'), data: GatewayClarifyBatchSchema }),
752
+ z.object({ event: z.literal('restarting'), data: z.object({ restarting: z.literal(true) }) }),
753
+ ]) },
754
+ 'gateway.create': { params: GatewayCreateParamsSchema, result: GatewaySessionResultSchema },
668
755
  'gateway.control': { params: GatewayActionParams.extend({ action: z.enum(GATEWAY_ACTIONS) }), result: GatewayActionResult, stream: GatewayActionStream },
669
756
  'gateway.restart': { params: GatewayActionParams, result: GatewayActionResult, stream: GatewayActionStream },
670
757
  /** TAL-805: the gateway mode of the profile `name` at `profile_home`; the root profile (`is_default`) is the host itself. */