@otto-code/client 0.8.19 → 0.9.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.
@@ -253,6 +253,35 @@ function unwrapBrainJob(payload) {
253
253
  // A repo clone can take minutes on a large history, so it gets its own budget
254
254
  // rather than the default request timeout.
255
255
  const PROJECT_GITHUB_CLONE_TIMEOUT_MS = 5 * 60 * 1000;
256
+ function buildWorkflowStartRequest(input) {
257
+ return {
258
+ flavor: input.flavor,
259
+ cwd: input.cwd,
260
+ ...(input.workspaceId !== undefined ? { workspaceId: input.workspaceId } : {}),
261
+ ...(input.title !== undefined ? { title: input.title } : {}),
262
+ ...(input.description !== undefined ? { description: input.description } : {}),
263
+ ...(input.orchestratorPersonalityId !== undefined
264
+ ? { orchestratorPersonalityId: input.orchestratorPersonalityId }
265
+ : {}),
266
+ ...(input.orchestratorProvider !== undefined
267
+ ? { orchestratorProvider: input.orchestratorProvider }
268
+ : {}),
269
+ ...(input.orchestratorModel !== undefined
270
+ ? { orchestratorModel: input.orchestratorModel }
271
+ : {}),
272
+ ...(input.orchestratorThinkingOptionId !== undefined
273
+ ? { orchestratorThinkingOptionId: input.orchestratorThinkingOptionId }
274
+ : {}),
275
+ ...(input.prompt !== undefined ? { prompt: input.prompt } : {}),
276
+ ...(input.graphId !== undefined ? { graphId: input.graphId } : {}),
277
+ ...(input.graphInputs !== undefined ? { graphInputs: input.graphInputs } : {}),
278
+ ...(input.startConfirmationToken !== undefined
279
+ ? { startConfirmationToken: input.startConfirmationToken }
280
+ : {}),
281
+ ...(input.draft !== undefined ? { draft: input.draft } : {}),
282
+ ...(input.runId !== undefined ? { runId: input.runId } : {}),
283
+ };
284
+ }
256
285
  export class DaemonClient {
257
286
  constructor(config) {
258
287
  this.config = config;
@@ -1061,6 +1090,7 @@ export class DaemonClient {
1061
1090
  ...(options?.sort ? { sort: options.sort } : {}),
1062
1091
  ...(options?.page ? { page: options.page } : {}),
1063
1092
  ...(options?.subscribe ? { subscribe: options.subscribe } : {}),
1093
+ ...(options?.sync ? { sync: options.sync } : {}),
1064
1094
  });
1065
1095
  return this.sendRequest({
1066
1096
  requestId: resolvedRequestId,
@@ -1143,6 +1173,7 @@ export class DaemonClient {
1143
1173
  ...(options?.sort ? { sort: options.sort } : {}),
1144
1174
  ...(options?.page ? { page: options.page } : {}),
1145
1175
  ...(options?.subscribe ? { subscribe: options.subscribe } : {}),
1176
+ ...(options?.sync ? { sync: options.sync } : {}),
1146
1177
  });
1147
1178
  return this.sendRequest({
1148
1179
  requestId: resolvedRequestId,
@@ -1159,6 +1190,74 @@ export class DaemonClient {
1159
1190
  },
1160
1191
  });
1161
1192
  }
1193
+ listWorkspaceLabels(options) {
1194
+ return this.sendNamespacedCorrelatedSessionRequest({
1195
+ requestId: options.requestId,
1196
+ message: {
1197
+ type: "workspace.label.list.request",
1198
+ subscribe: { subscriptionId: options.subscriptionId },
1199
+ ...(options.sync ? { sync: options.sync } : {}),
1200
+ },
1201
+ });
1202
+ }
1203
+ setWorkspaceLabel(options) {
1204
+ return this.sendNamespacedCorrelatedSessionRequest({
1205
+ requestId: options.requestId,
1206
+ message: {
1207
+ type: "workspace.label.assignment.set.request",
1208
+ workspaceId: options.workspaceId,
1209
+ label: options.label,
1210
+ assigned: options.assigned,
1211
+ },
1212
+ });
1213
+ }
1214
+ updateWorkspaceLabel(options) {
1215
+ return this.sendNamespacedCorrelatedSessionRequest({
1216
+ requestId: options.requestId,
1217
+ message: {
1218
+ type: "workspace.label.update.request",
1219
+ name: options.name,
1220
+ ...(options.newName === undefined ? {} : { newName: options.newName }),
1221
+ ...(options.color === undefined ? {} : { color: options.color }),
1222
+ },
1223
+ });
1224
+ }
1225
+ deleteWorkspaceLabel(options) {
1226
+ return this.sendNamespacedCorrelatedSessionRequest({
1227
+ requestId: options.requestId,
1228
+ message: { type: "workspace.label.delete.request", name: options.name },
1229
+ });
1230
+ }
1231
+ inspectWorkspaceLabelDelete(options) {
1232
+ return this.sendNamespacedCorrelatedSessionRequest({
1233
+ requestId: options.requestId,
1234
+ message: {
1235
+ type: "workspace.label.delete.inspect.request",
1236
+ name: options.name,
1237
+ },
1238
+ });
1239
+ }
1240
+ async listProjects(options) {
1241
+ const requestId = typeof options === "string" ? options : options?.requestId;
1242
+ const resolvedRequestId = this.createRequestId(requestId);
1243
+ const message = SessionInboundMessageSchema.parse({
1244
+ type: "project.list.request",
1245
+ requestId: resolvedRequestId,
1246
+ ...(typeof options === "object" && options.sync ? { sync: options.sync } : {}),
1247
+ });
1248
+ return this.sendRequest({
1249
+ requestId: resolvedRequestId,
1250
+ message,
1251
+ options: { skipQueue: true },
1252
+ select: (msg) => {
1253
+ if (msg.type !== "project.list.response")
1254
+ return null;
1255
+ if (msg.payload.requestId !== resolvedRequestId)
1256
+ return null;
1257
+ return msg.payload;
1258
+ },
1259
+ });
1260
+ }
1162
1261
  async openProject(cwd, requestId) {
1163
1262
  return this.sendCorrelatedSessionRequest({
1164
1263
  requestId,
@@ -1419,6 +1518,9 @@ export class DaemonClient {
1419
1518
  ...(options.personality ? { personality: options.personality } : {}),
1420
1519
  ...(options.env ? { env: options.env } : {}),
1421
1520
  ...(options.workspaceId !== undefined ? { workspaceId: options.workspaceId } : {}),
1521
+ ...(options.architecturalViewDraft
1522
+ ? { architecturalViewDraft: options.architecturalViewDraft }
1523
+ : {}),
1422
1524
  ...(options.callerAgentId !== undefined ? { callerAgentId: options.callerAgentId } : {}),
1423
1525
  ...(options.initialPrompt ? { initialPrompt: options.initialPrompt } : {}),
1424
1526
  ...(options.clientMessageId ? { clientMessageId: options.clientMessageId } : {}),
@@ -1703,6 +1805,26 @@ export class DaemonClient {
1703
1805
  });
1704
1806
  return payload.graphs;
1705
1807
  }
1808
+ /** List saved Workflow Graphs for one project, never the legacy host library. */
1809
+ async listProjectWorkflowGraphs(cwd) {
1810
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1811
+ message: { type: "workflows.graphs.list.request", cwd },
1812
+ });
1813
+ if (payload.error !== undefined) {
1814
+ throw new Error(payload.error);
1815
+ }
1816
+ return payload.graphs;
1817
+ }
1818
+ /** Persist a Graph in the selected project Workflow store. */
1819
+ async saveProjectWorkflowGraph(cwd, graph) {
1820
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1821
+ message: { type: "workflows.graph.save.request", cwd, graph },
1822
+ });
1823
+ if (payload.error !== undefined || payload.graph === undefined) {
1824
+ throw new Error(payload.error ?? "Project Workflow Graph save rejected");
1825
+ }
1826
+ return payload.graph;
1827
+ }
1706
1828
  /** Orchestration: upsert a graph template. Returns the persisted graph. */
1707
1829
  async saveOrchestrationGraph(graph) {
1708
1830
  const payload = await this.sendNamespacedCorrelatedSessionRequest({
@@ -1723,6 +1845,22 @@ export class DaemonClient {
1723
1845
  }
1724
1846
  return payload.deleted;
1725
1847
  }
1848
+ async exportWorkflowGraph(graphId) {
1849
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1850
+ message: { type: "workflows.graph.export.request", graphId },
1851
+ });
1852
+ if (!payload.export)
1853
+ throw new Error(payload.error ?? "Graph export rejected");
1854
+ return payload.export;
1855
+ }
1856
+ async importWorkflowGraph(input) {
1857
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1858
+ message: { type: "workflows.graph.import.request", ...input },
1859
+ });
1860
+ if (!payload.result)
1861
+ throw new Error(payload.error ?? "Graph import rejected");
1862
+ return payload.result;
1863
+ }
1726
1864
  /** Orchestration: list the host's reusable prompt templates and snippets. */
1727
1865
  async listPromptTemplates() {
1728
1866
  const payload = await this.sendNamespacedCorrelatedSessionRequest({
@@ -1730,6 +1868,32 @@ export class DaemonClient {
1730
1868
  });
1731
1869
  return payload.templates;
1732
1870
  }
1871
+ async listProjectWorkflowTemplates(cwd) {
1872
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1873
+ message: { type: "workflows.templates.list.request", cwd },
1874
+ });
1875
+ if (payload.error !== undefined)
1876
+ throw new Error(payload.error);
1877
+ return payload.templates;
1878
+ }
1879
+ async saveProjectWorkflowTemplate(cwd, template) {
1880
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1881
+ message: { type: "workflows.template.save.request", cwd, template },
1882
+ });
1883
+ if (payload.error !== undefined || payload.template === undefined) {
1884
+ throw new Error(payload.error ?? "Project Workflow template save rejected");
1885
+ }
1886
+ return payload.template;
1887
+ }
1888
+ async transferProjectWorkflowRecord(input) {
1889
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1890
+ message: { type: "workflows.storage.transfer.request", ...input },
1891
+ });
1892
+ if (payload.error !== undefined || payload.receipt === undefined) {
1893
+ throw new Error(payload.error ?? "Project Workflow transfer rejected");
1894
+ }
1895
+ return payload.receipt;
1896
+ }
1733
1897
  /** Orchestration: upsert a prompt template. Returns the persisted template. */
1734
1898
  async savePromptTemplate(template) {
1735
1899
  const payload = await this.sendNamespacedCorrelatedSessionRequest({
@@ -1751,37 +1915,20 @@ export class DaemonClient {
1751
1915
  return payload.deleted;
1752
1916
  }
1753
1917
  /**
1754
- * Orchestration: start (or draft) a user-initiated orchestration. Returns the
1755
- * run id (graph flavor) and the orchestrator chat's agent id to navigate to.
1918
+ * Workflow: start (or draft) a user-initiated Workflow. Returns the workflow
1919
+ * id (graph flavor) and the orchestrator chat's agent id to navigate to.
1756
1920
  */
1757
- async startOrchestration(input) {
1758
- const payload = await this.sendNamespacedCorrelatedSessionRequest({
1759
- message: {
1760
- type: "runs.start.request",
1761
- flavor: input.flavor,
1762
- cwd: input.cwd,
1763
- ...(input.workspaceId !== undefined ? { workspaceId: input.workspaceId } : {}),
1764
- ...(input.title !== undefined ? { title: input.title } : {}),
1765
- ...(input.description !== undefined ? { description: input.description } : {}),
1766
- ...(input.orchestratorPersonalityId !== undefined
1767
- ? { orchestratorPersonalityId: input.orchestratorPersonalityId }
1768
- : {}),
1769
- ...(input.orchestratorProvider !== undefined
1770
- ? { orchestratorProvider: input.orchestratorProvider }
1771
- : {}),
1772
- ...(input.orchestratorModel !== undefined
1773
- ? { orchestratorModel: input.orchestratorModel }
1774
- : {}),
1775
- ...(input.orchestratorThinkingOptionId !== undefined
1776
- ? { orchestratorThinkingOptionId: input.orchestratorThinkingOptionId }
1777
- : {}),
1778
- ...(input.prompt !== undefined ? { prompt: input.prompt } : {}),
1779
- ...(input.graphId !== undefined ? { graphId: input.graphId } : {}),
1780
- ...(input.graphInputs !== undefined ? { graphInputs: input.graphInputs } : {}),
1781
- ...(input.draft !== undefined ? { draft: input.draft } : {}),
1782
- ...(input.runId !== undefined ? { runId: input.runId } : {}),
1783
- },
1784
- });
1921
+ async startWorkflow(input) {
1922
+ const request = buildWorkflowStartRequest(input);
1923
+ // COMPAT(runsStartRpc): retain the established request against older
1924
+ // daemons until the legacy pair retires after 2027-02-28.
1925
+ const payload = this.lastServerInfoMessage?.features?.workflowStartRpc === true
1926
+ ? await this.sendNamespacedCorrelatedSessionRequest({
1927
+ message: { type: "workflows.start.request", ...request },
1928
+ })
1929
+ : await this.sendNamespacedCorrelatedSessionRequest({
1930
+ message: { type: "runs.start.request", ...request },
1931
+ });
1785
1932
  if (payload.error !== undefined) {
1786
1933
  throw new Error(payload.error);
1787
1934
  }
@@ -1789,8 +1936,19 @@ export class DaemonClient {
1789
1936
  ...(payload.runId !== undefined ? { runId: payload.runId } : {}),
1790
1937
  ...(payload.agentId !== undefined ? { agentId: payload.agentId } : {}),
1791
1938
  ...(payload.workspaceId !== undefined ? { workspaceId: payload.workspaceId } : {}),
1939
+ ...(payload.confirmation !== undefined ? { confirmation: payload.confirmation } : {}),
1940
+ ...(payload.confirmationToken !== undefined
1941
+ ? { confirmationToken: payload.confirmationToken }
1942
+ : {}),
1792
1943
  };
1793
1944
  }
1945
+ /** Answer a daemon-owned AI Workflow start confirmation. */
1946
+ async respondToWorkflowStartConfirmation(input) {
1947
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
1948
+ message: { type: "workflows.start_confirmation.respond.request", ...input },
1949
+ });
1950
+ return payload.accepted;
1951
+ }
1794
1952
  async updateAgent(agentId, updates) {
1795
1953
  const requestId = this.createRequestId();
1796
1954
  const message = SessionInboundMessageSchema.parse({
@@ -2213,25 +2371,6 @@ export class DaemonClient {
2213
2371
  }
2214
2372
  return { baseRef: payload.baseRef, commits: payload.commits };
2215
2373
  }
2216
- async listProjects(requestId) {
2217
- const resolvedRequestId = this.createRequestId(requestId);
2218
- const message = SessionInboundMessageSchema.parse({
2219
- type: "project.list.request",
2220
- requestId: resolvedRequestId,
2221
- });
2222
- return this.sendRequest({
2223
- requestId: resolvedRequestId,
2224
- message,
2225
- options: { skipQueue: true },
2226
- select: (msg) => {
2227
- if (msg.type !== "project.list.response")
2228
- return null;
2229
- if (msg.payload.requestId !== resolvedRequestId)
2230
- return null;
2231
- return msg.payload;
2232
- },
2233
- });
2234
- }
2235
2374
  onAgentAttentionRequired(handler) {
2236
2375
  const unsubscribeLegacy = this.on("agent_stream", (message) => {
2237
2376
  if (message.payload.event.type !== "attention_required") {
@@ -2443,6 +2582,7 @@ export class DaemonClient {
2443
2582
  agentId,
2444
2583
  text,
2445
2584
  ...(messageId ? { messageId } : {}),
2585
+ ...(options?.activeTurnBehavior ? { activeTurnBehavior: options.activeTurnBehavior } : {}),
2446
2586
  ...(options?.images ? { images: options.images } : {}),
2447
2587
  ...(options?.attachments ? { attachments: options.attachments } : {}),
2448
2588
  ...(options?.delivery ? { delivery: options.delivery } : {}),
@@ -3709,7 +3849,7 @@ export class DaemonClient {
3709
3849
  // ============================================================================
3710
3850
  // File Explorer
3711
3851
  // ============================================================================
3712
- async requestFileExplorer(cwd, path, mode, requestId, acceptBinary = false) {
3852
+ async requestFileExplorer(cwd, path, mode, requestId, acceptBinary = false, maxBytes) {
3713
3853
  return this.sendCorrelatedSessionRequest({
3714
3854
  requestId,
3715
3855
  message: {
@@ -3718,6 +3858,7 @@ export class DaemonClient {
3718
3858
  path,
3719
3859
  mode,
3720
3860
  ...(acceptBinary ? { acceptBinary: true } : {}),
3861
+ ...(maxBytes ? { maxBytes } : {}),
3721
3862
  },
3722
3863
  responseType: "file_explorer_response",
3723
3864
  });
@@ -3732,11 +3873,11 @@ export class DaemonClient {
3732
3873
  }
3733
3874
  return payload.directory;
3734
3875
  }
3735
- async readFile(cwd, path, requestId) {
3876
+ async readFile(cwd, path, requestId, maxBytes) {
3736
3877
  const resolvedRequestId = this.createRequestId(requestId);
3737
- this.pendingBinaryFileReads.set(resolvedRequestId, { cwd, path });
3878
+ this.pendingBinaryFileReads.set(resolvedRequestId, { cwd, path, maxBytes });
3738
3879
  try {
3739
- const payload = await this.requestFileExplorer(cwd, path, "file", resolvedRequestId, true);
3880
+ const payload = await this.requestFileExplorer(cwd, path, "file", resolvedRequestId, true, maxBytes);
3740
3881
  if (payload.error) {
3741
3882
  throw new Error(payload.error);
3742
3883
  }
@@ -4610,6 +4751,37 @@ export class DaemonClient {
4610
4751
  timeout: options?.timeout,
4611
4752
  });
4612
4753
  }
4754
+ async reloadDaemonConfig(requestId) {
4755
+ this.requireDaemonConfigReloadSupport();
4756
+ return this.sendNamespacedCorrelatedSessionRequest({
4757
+ requestId,
4758
+ message: { type: "daemon.config.reload.request" },
4759
+ });
4760
+ }
4761
+ async connectHub(hubUrl, token, requestId) {
4762
+ this.requireHubRelationshipSupport();
4763
+ return this.sendCorrelatedSessionRequest({
4764
+ requestId,
4765
+ message: { type: "hub.management.daemon.connect.request", hubUrl, token },
4766
+ responseType: "hub.management.daemon.connect.response",
4767
+ });
4768
+ }
4769
+ async getHubStatus(requestId) {
4770
+ this.requireHubRelationshipSupport();
4771
+ return this.sendCorrelatedSessionRequest({
4772
+ requestId,
4773
+ message: { type: "hub.management.daemon.get_status.request" },
4774
+ responseType: "hub.management.daemon.get_status.response",
4775
+ });
4776
+ }
4777
+ async disconnectHub(force = false, requestId) {
4778
+ this.requireHubRelationshipSupport();
4779
+ return this.sendCorrelatedSessionRequest({
4780
+ requestId,
4781
+ message: { type: "hub.management.daemon.disconnect.request", force },
4782
+ responseType: "hub.management.daemon.disconnect.response",
4783
+ });
4784
+ }
4613
4785
  async getDaemonPairingOffer(options) {
4614
4786
  return this.sendCorrelatedSessionRequest({
4615
4787
  requestId: options?.requestId,
@@ -5549,6 +5721,135 @@ export class DaemonClient {
5549
5721
  response,
5550
5722
  });
5551
5723
  }
5724
+ async getPluginCatalog() {
5725
+ const requestId = this.createRequestId();
5726
+ const payload = await this.sendCorrelatedSessionRequest({
5727
+ requestId,
5728
+ message: { type: "plugin.catalog.get.request", requestId },
5729
+ responseType: "plugin.catalog.get.response",
5730
+ });
5731
+ return payload.plugins;
5732
+ }
5733
+ async listPlugins() {
5734
+ const requestId = this.createRequestId();
5735
+ const payload = await this.sendCorrelatedSessionRequest({
5736
+ requestId,
5737
+ message: { type: "plugin.list.request", requestId },
5738
+ responseType: "plugin.list.response",
5739
+ });
5740
+ return payload.plugins;
5741
+ }
5742
+ async getPluginLogs(pluginId) {
5743
+ const requestId = this.createRequestId();
5744
+ const payload = await this.sendCorrelatedSessionRequest({
5745
+ requestId,
5746
+ message: { type: "plugin.logs.get.request", requestId, pluginId },
5747
+ responseType: "plugin.logs.get.response",
5748
+ });
5749
+ return payload.entries;
5750
+ }
5751
+ async getAgentSkillsStatus() {
5752
+ const requestId = this.createRequestId();
5753
+ return this.sendCorrelatedSessionRequest({
5754
+ message: { type: "agent.skills.get_status.request", requestId },
5755
+ responseType: "agent.skills.get_status.response",
5756
+ });
5757
+ }
5758
+ async reconcileAgentSkills() {
5759
+ const requestId = this.createRequestId();
5760
+ return this.sendCorrelatedSessionRequest({
5761
+ message: { type: "agent.skills.reconcile.request", requestId },
5762
+ responseType: "agent.skills.reconcile.response",
5763
+ });
5764
+ }
5765
+ async uninstallAgentSkills() {
5766
+ const requestId = this.createRequestId();
5767
+ return this.sendCorrelatedSessionRequest({
5768
+ message: { type: "agent.skills.uninstall.request", requestId },
5769
+ responseType: "agent.skills.uninstall.response",
5770
+ });
5771
+ }
5772
+ async saveAgentSkillsSelection(selection, confirmedRemovals) {
5773
+ const requestId = this.createRequestId();
5774
+ return this.sendCorrelatedSessionRequest({
5775
+ message: {
5776
+ type: "agent.skills.save_selection.request",
5777
+ requestId,
5778
+ selection,
5779
+ ...(confirmedRemovals ? { confirmedRemovals: [...confirmedRemovals] } : {}),
5780
+ },
5781
+ responseType: "agent.skills.save_selection.response",
5782
+ });
5783
+ }
5784
+ async importLegacyAgentSkillsSelection(selection) {
5785
+ const requestId = this.createRequestId();
5786
+ return this.sendCorrelatedSessionRequest({
5787
+ message: {
5788
+ type: "agent.skills.import_legacy_selection.request",
5789
+ requestId,
5790
+ selection,
5791
+ },
5792
+ responseType: "agent.skills.import_legacy_selection.response",
5793
+ });
5794
+ }
5795
+ async installDirectoryPlugin(path, id) {
5796
+ const requestId = this.createRequestId();
5797
+ const payload = await this.sendCorrelatedSessionRequest({
5798
+ requestId,
5799
+ message: { type: "plugin.directory.install.request", requestId, path, ...(id ? { id } : {}) },
5800
+ responseType: "plugin.directory.install.response",
5801
+ });
5802
+ return payload.plugin;
5803
+ }
5804
+ async inspectDirectoryPlugin(path) {
5805
+ const requestId = this.createRequestId();
5806
+ return this.sendCorrelatedSessionRequest({
5807
+ requestId,
5808
+ message: { type: "plugin.directory.inspect.request", requestId, path },
5809
+ responseType: "plugin.directory.inspect.response",
5810
+ });
5811
+ }
5812
+ async reloadPlugin(pluginId) {
5813
+ return this.managePlugin("reload", pluginId);
5814
+ }
5815
+ async enablePlugin(pluginId) {
5816
+ return this.managePlugin("enable", pluginId);
5817
+ }
5818
+ async disablePlugin(pluginId) {
5819
+ return this.managePlugin("disable", pluginId);
5820
+ }
5821
+ async removePlugin(pluginId) {
5822
+ const requestId = this.createRequestId();
5823
+ await this.sendCorrelatedSessionRequest({
5824
+ requestId,
5825
+ message: { type: "plugin.remove.request", requestId, pluginId },
5826
+ responseType: "plugin.remove.response",
5827
+ });
5828
+ }
5829
+ async managePlugin(action, pluginId) {
5830
+ const requestId = this.createRequestId();
5831
+ const payload = await this.sendCorrelatedSessionRequest({
5832
+ requestId,
5833
+ message: { type: `plugin.${action}.request`, requestId, pluginId },
5834
+ responseType: `plugin.${action}.response`,
5835
+ });
5836
+ return payload.plugin;
5837
+ }
5838
+ async invokePluginRpc(pluginId, method, input) {
5839
+ const requestId = this.createRequestId();
5840
+ const payload = await this.sendCorrelatedSessionRequest({
5841
+ requestId,
5842
+ message: {
5843
+ type: "plugin.rpc.invoke.request",
5844
+ requestId,
5845
+ pluginId,
5846
+ method,
5847
+ input,
5848
+ },
5849
+ responseType: "plugin.rpc.invoke.response",
5850
+ });
5851
+ return payload.output;
5852
+ }
5552
5853
  async respondToPermissionAndWait(agentId, requestId, response, timeout = 15000) {
5553
5854
  const message = SessionInboundMessageSchema.parse({
5554
5855
  type: "agent_permission_response",
@@ -5974,6 +6275,32 @@ export class DaemonClient {
5974
6275
  responseType: "artifact.list.response",
5975
6276
  });
5976
6277
  }
6278
+ async setProjectArtifactStoreLocation(input) {
6279
+ const payload = await this.sendCorrelatedSessionRequest({
6280
+ requestId: input.requestId,
6281
+ message: {
6282
+ type: "project.artifact.store.set.request",
6283
+ projectId: input.projectId,
6284
+ location: input.location,
6285
+ },
6286
+ responseType: "project.artifact.store.set.response",
6287
+ });
6288
+ if (!payload.accepted)
6289
+ throw new Error(payload.error ?? "Artifact storage update rejected");
6290
+ }
6291
+ /** Requires server_info.features.categoryStorageResolver for Workflows. */
6292
+ async setProjectWorkflowStoreLocation(input) {
6293
+ const payload = await this.sendNamespacedCorrelatedSessionRequest({
6294
+ requestId: input.requestId,
6295
+ message: {
6296
+ type: "project.workflow.store.set.request",
6297
+ projectId: input.projectId,
6298
+ location: input.location,
6299
+ },
6300
+ });
6301
+ if (!payload.accepted)
6302
+ throw new Error(payload.error ?? "Workflow storage update rejected");
6303
+ }
5977
6304
  async artifactCreate(options) {
5978
6305
  return this.sendCorrelatedSessionRequest({
5979
6306
  requestId: options.requestId,
@@ -6062,6 +6389,151 @@ export class DaemonClient {
6062
6389
  responseType: "artifact.get-content.response",
6063
6390
  });
6064
6391
  }
6392
+ async artifactRepair(options) {
6393
+ return this.sendCorrelatedSessionRequest({
6394
+ requestId: options.requestId,
6395
+ message: {
6396
+ type: "artifact.repair.request",
6397
+ artifactId: options.artifactId,
6398
+ },
6399
+ responseType: "artifact.repair.response",
6400
+ });
6401
+ }
6402
+ async artifactGetData(options) {
6403
+ return this.sendCorrelatedSessionRequest({
6404
+ requestId: options.requestId,
6405
+ message: {
6406
+ type: "artifact.data.get.request",
6407
+ artifactId: options.artifactId,
6408
+ },
6409
+ responseType: "artifact.data.get.response",
6410
+ });
6411
+ }
6412
+ async artifactUpdateData(options) {
6413
+ return this.sendCorrelatedSessionRequest({
6414
+ requestId: options.requestId,
6415
+ message: {
6416
+ type: "artifact.data.update.request",
6417
+ artifactId: options.artifactId,
6418
+ data: options.data,
6419
+ },
6420
+ responseType: "artifact.data.update.response",
6421
+ });
6422
+ }
6423
+ async artifactMoveStore(options) {
6424
+ return this.sendCorrelatedSessionRequest({
6425
+ requestId: options.requestId,
6426
+ message: {
6427
+ type: "artifact.store.move.request",
6428
+ artifactId: options.artifactId,
6429
+ destination: options.destination,
6430
+ },
6431
+ responseType: "artifact.store.move.response",
6432
+ });
6433
+ }
6434
+ async deliverArchitecturalView(options) {
6435
+ return this.sendCorrelatedSessionRequest({
6436
+ requestId: options.requestId,
6437
+ message: {
6438
+ type: "architectural-views.deliver.request",
6439
+ workspaceId: options.workspaceId,
6440
+ viewId: options.viewId,
6441
+ title: options.title,
6442
+ knowledgeReferences: options.knowledgeReferences,
6443
+ sourcePath: options.sourcePath,
6444
+ ...(options.quality ? { quality: options.quality } : {}),
6445
+ },
6446
+ responseType: "architectural-views.deliver.response",
6447
+ });
6448
+ }
6449
+ async listArchitecturalViews(options) {
6450
+ return this.sendCorrelatedSessionRequest({
6451
+ requestId: options.requestId,
6452
+ message: {
6453
+ type: "architectural-views.list.request",
6454
+ workspaceId: options.workspaceId,
6455
+ ...(options.knowledgeReference ? { knowledgeReference: options.knowledgeReference } : {}),
6456
+ },
6457
+ responseType: "architectural-views.list.response",
6458
+ });
6459
+ }
6460
+ async getArchitecturalViewContent(options) {
6461
+ return this.sendCorrelatedSessionRequest({
6462
+ requestId: options.requestId,
6463
+ message: {
6464
+ type: "architectural-views.get-content.request",
6465
+ workspaceId: options.workspaceId,
6466
+ viewId: options.viewId,
6467
+ },
6468
+ responseType: "architectural-views.get-content.response",
6469
+ });
6470
+ }
6471
+ async createArchitecturalViewDraft(options) {
6472
+ return this.sendCorrelatedSessionRequest({
6473
+ requestId: options.requestId,
6474
+ message: {
6475
+ type: "architectural-views.draft.create.request",
6476
+ workspaceId: options.workspaceId,
6477
+ viewId: options.viewId,
6478
+ draftId: options.draftId,
6479
+ title: options.title,
6480
+ knowledgeReferences: options.knowledgeReferences,
6481
+ ...(options.sourcePath ? { sourcePath: options.sourcePath } : {}),
6482
+ ...(options.quality ? { quality: options.quality } : {}),
6483
+ },
6484
+ responseType: "architectural-views.draft.create.response",
6485
+ });
6486
+ }
6487
+ async publishArchitecturalViewDraft(options) {
6488
+ return this.sendCorrelatedSessionRequest({
6489
+ requestId: options.requestId,
6490
+ message: {
6491
+ type: "architectural-views.draft.publish.request",
6492
+ workspaceId: options.workspaceId,
6493
+ viewId: options.viewId,
6494
+ draftId: options.draftId,
6495
+ },
6496
+ responseType: "architectural-views.draft.publish.response",
6497
+ });
6498
+ }
6499
+ async updateArchitecturalViewDraft(options) {
6500
+ return this.sendCorrelatedSessionRequest({
6501
+ requestId: options.requestId,
6502
+ message: {
6503
+ type: "architectural-views.draft.update.request",
6504
+ workspaceId: options.workspaceId,
6505
+ viewId: options.viewId,
6506
+ draftId: options.draftId,
6507
+ sourcePath: options.sourcePath,
6508
+ ...(options.quality ? { quality: options.quality } : {}),
6509
+ },
6510
+ responseType: "architectural-views.draft.update.response",
6511
+ });
6512
+ }
6513
+ async discardArchitecturalViewDraft(options) {
6514
+ return this.sendCorrelatedSessionRequest({
6515
+ requestId: options.requestId,
6516
+ message: {
6517
+ type: "architectural-views.draft.discard.request",
6518
+ workspaceId: options.workspaceId,
6519
+ viewId: options.viewId,
6520
+ draftId: options.draftId,
6521
+ },
6522
+ responseType: "architectural-views.draft.discard.response",
6523
+ });
6524
+ }
6525
+ async getArchitecturalViewDraftContent(options) {
6526
+ return this.sendCorrelatedSessionRequest({
6527
+ requestId: options.requestId,
6528
+ message: {
6529
+ type: "architectural-views.draft.get-content.request",
6530
+ workspaceId: options.workspaceId,
6531
+ viewId: options.viewId,
6532
+ draftId: options.draftId,
6533
+ },
6534
+ responseType: "architectural-views.draft.get-content.response",
6535
+ });
6536
+ }
6065
6537
  onTerminalStreamEvent(handler) {
6066
6538
  return this.terminalStreams.onEvent(handler);
6067
6539
  }
@@ -6110,6 +6582,12 @@ export class DaemonClient {
6110
6582
  getInboundDispatchTimings(sinceMs) {
6111
6583
  return this.runtimeMetrics?.getInboundDispatchTimings(sinceMs) ?? [];
6112
6584
  }
6585
+ requireDaemonConfigReloadSupport() {
6586
+ // COMPAT(daemonConfigReload): added in v0.4.0, remove gate after 2027-02-14.
6587
+ if (this.lastServerInfoMessage?.features?.daemonConfigReload !== true) {
6588
+ throw new Error("Update the host to reload daemon configuration.");
6589
+ }
6590
+ }
6113
6591
  resolveTransportUrlForAttempt() {
6114
6592
  return this.config.url;
6115
6593
  }
@@ -6346,9 +6824,31 @@ export class DaemonClient {
6346
6824
  return;
6347
6825
  }
6348
6826
  if (frame.opcode === FileTransferOpcode.FileChunk) {
6827
+ // COMPAT(fileReadByteBudget): added in v0.5.0, remove after 2027-02-21 once daemon floor >= v0.5.0.
6828
+ // Old daemons stream despite maxBytes; discard before client-side accumulation.
6829
+ if (transfer.maxBytes && transfer.size > transfer.maxBytes) {
6830
+ return;
6831
+ }
6349
6832
  transfer.chunks.push(frame.payload);
6350
6833
  return;
6351
6834
  }
6835
+ // COMPAT(fileReadByteBudget): added in v0.5.0, remove after 2027-02-21 once daemon floor >= v0.5.0.
6836
+ if (transfer.maxBytes && transfer.size > transfer.maxBytes) {
6837
+ this.activeBinaryFileTransfers.delete(frame.requestId);
6838
+ this.handleSessionMessage({
6839
+ type: "file_explorer_response",
6840
+ payload: {
6841
+ cwd: transfer.cwd,
6842
+ path: transfer.path,
6843
+ mode: "file",
6844
+ directory: null,
6845
+ file: null,
6846
+ error: "File is too large to display",
6847
+ requestId: frame.requestId,
6848
+ },
6849
+ });
6850
+ return;
6851
+ }
6352
6852
  const bytes = concatByteChunks(transfer.chunks, transfer.size);
6353
6853
  this.activeBinaryFileTransfers.delete(frame.requestId);
6354
6854
  this.completedBinaryFileReads.set(frame.requestId, {
@@ -6752,30 +7252,6 @@ export class DaemonClient {
6752
7252
  responseType: "workspace.script.stop.response",
6753
7253
  });
6754
7254
  }
6755
- async connectHub(hubUrl, token, requestId) {
6756
- this.requireHubRelationshipSupport();
6757
- return this.sendCorrelatedSessionRequest({
6758
- requestId,
6759
- message: { type: "hub.management.daemon.connect.request", hubUrl, token },
6760
- responseType: "hub.management.daemon.connect.response",
6761
- });
6762
- }
6763
- async getHubStatus(requestId) {
6764
- this.requireHubRelationshipSupport();
6765
- return this.sendCorrelatedSessionRequest({
6766
- requestId,
6767
- message: { type: "hub.management.daemon.get_status.request" },
6768
- responseType: "hub.management.daemon.get_status.response",
6769
- });
6770
- }
6771
- async disconnectHub(force = false, requestId) {
6772
- this.requireHubRelationshipSupport();
6773
- return this.sendCorrelatedSessionRequest({
6774
- requestId,
6775
- message: { type: "hub.management.daemon.disconnect.request", force },
6776
- responseType: "hub.management.daemon.disconnect.response",
6777
- });
6778
- }
6779
7255
  requireHubRelationshipSupport() {
6780
7256
  // COMPAT(hubRelationship): added in v0.2.5, drop the gate when floor >= v0.2.5.
6781
7257
  if (this.lastServerInfoMessage?.features?.hubRelationship !== true) {