@cat-factory/mcp-server 0.22.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { type CatFactoryMcpOptions } from './config.ts';
3
3
  import { type CatFactoryTool } from './tools.generated.ts';
4
4
  /** The npm version, stamped into the SDK's `User-Agent` so a deployment can attribute calls. */
5
- export declare const MCP_SERVER_VERSION = "0.22.0";
5
+ export declare const MCP_SERVER_VERSION = "0.24.0";
6
6
  /** The name this server reports to a host. */
7
7
  export declare const MCP_SERVER_NAME = "cat-factory";
8
8
  export interface CatFactoryMcpServer {
package/dist/server.js CHANGED
@@ -19,7 +19,7 @@ import { CAT_FACTORY_TOOLS } from './tools.generated.js';
19
19
  // has been round-tripped through a second type system, and every gap in that conversion becomes a
20
20
  // tool that misdescribes its own input.
21
21
  /** The npm version, stamped into the SDK's `User-Agent` so a deployment can attribute calls. */
22
- export const MCP_SERVER_VERSION = '0.22.0';
22
+ export const MCP_SERVER_VERSION = '0.24.0';
23
23
  /** The name this server reports to a host. */
24
24
  export const MCP_SERVER_NAME = 'cat-factory';
25
25
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tools.generated.d.ts","sourceRoot":"","sources":["../src/tools.generated.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExD,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAA;IACnB,8FAA8F;IAC9F,QAAQ,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAA;IACrD,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACnC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC5B,oBAAoB,EAAE,KAAK,CAAA;KAC5B,CAAA;IACD;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACpC,CAAA;IACD,kDAAkD;IAClD,MAAM,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACtF;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAyCD,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAk6BtD,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,8BAA8B,EAAE,SAAS,0BAA0B,EAmB/E,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcpE,CAAA"}
1
+ {"version":3,"file":"tools.generated.d.ts","sourceRoot":"","sources":["../src/tools.generated.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExD,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAA;IACZ,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;IACb,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAA;IACnB,8FAA8F;IAC9F,QAAQ,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAA;IACrD,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACnC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QAC5B,oBAAoB,EAAE,KAAK,CAAA;KAC5B,CAAA;IACD;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,QAAQ,CAAA;QACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KACpC,CAAA;IACD,kDAAkD;IAClD,MAAM,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACtF;AAED;;;;;;GAMG;AACH,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAuHD,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAogCtD,CAAA;AAED,wEAAwE;AACxE,eAAO,MAAM,8BAA8B,EAAE,SAAS,0BAA0B,EAmB/E,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAepE,CAAA"}
@@ -15,25 +15,99 @@ function str(args, name) {
15
15
  * parameters to the same level, so "whatever is not a path parameter" would forward a model's
16
16
  * typo as a query parameter the deployment then ignores, and the caller would see a filter that
17
17
  * silently did nothing.
18
+ *
19
+ * Returns the call site's own query type, and CHECKS rather than assumes: a required parameter
20
+ * that `args` omits throws here, the way a missing path parameter already does through
21
+ * `str()`. The tool's `inputSchema` marks the same parameters required, but a host is not
22
+ * obliged to validate against it and the reference server in this package does not, so trusting
23
+ * it made the narrowing a claim about a bag that had just dropped the field the call needs. The
24
+ * failure that produced is the worst kind for a model: a 400 about a parameter it believes it
25
+ * supplied, several turns after the tool description explained it.
26
+ *
27
+ * PRESENCE only. What a value may BE is the deployment's judgement, already stated in the schema
28
+ * the model was given, and its refusal names the field; re-deriving it here would be a second
29
+ * copy of the contract, free to disagree with the first.
18
30
  */
19
- function pick(args, names) {
31
+ function pick(args, params) {
20
32
  const out = {};
21
- for (const name of names) {
22
- if (args[name] !== undefined)
23
- out[name] = args[name];
33
+ for (const param of params) {
34
+ const value = args[param.name];
35
+ if (value === undefined) {
36
+ if (param.required) {
37
+ throw new TypeError(`${param.name} is required`);
38
+ }
39
+ continue;
40
+ }
41
+ out[param.name] = value;
24
42
  }
25
43
  return out;
26
44
  }
27
- const QUERY_JOBS_LIST = ['limit', 'cursor', 'status', 'since'];
28
- const QUERY_TASKS_LIST_BY_SERVICE = ['limit', 'cursor', 'status'];
29
- const QUERY_DEBUG_GET_AGENT_CONTEXT = ['bodyChars', 'bodyOffset'];
30
- const QUERY_DEBUG_GET_LLM_CALL = ['bodyChars', 'bodyOffset', 'view'];
31
- const QUERY_DEBUG_LIST_AGENT_CONTEXT = ['stepIndex', 'limit', 'cursor'];
32
- const QUERY_DEBUG_LIST_LLM_CALLS = ['agentKind', 'phase', 'outcome', 'contains', 'order', 'limit', 'cursor', 'bodyChars'];
33
- const QUERY_DEBUG_LIST_LOGS = ['limit', 'cursor'];
34
- const QUERY_DEBUG_LIST_RUNS = ['status', 'since', 'limit', 'cursor'];
35
- const QUERY_DEBUG_LIST_SEARCH_QUERIES = ['limit', 'cursor'];
36
- const QUERY_DEBUG_LIST_TOOL_CALLS = ['limit', 'cursor', 'jobId', 'order', 'outcome'];
45
+ const QUERY_JOBS_LIST = [
46
+ { name: 'limit', required: false },
47
+ { name: 'cursor', required: false },
48
+ { name: 'status', required: false },
49
+ { name: 'since', required: false },
50
+ ];
51
+ const QUERY_TASKS_LIST_BY_SERVICE = [
52
+ { name: 'limit', required: false },
53
+ { name: 'cursor', required: false },
54
+ { name: 'status', required: false },
55
+ ];
56
+ const QUERY_USAGE_SPEND = [
57
+ { name: 'dimension', required: true },
58
+ { name: 'window', required: false },
59
+ { name: 'limit', required: false },
60
+ ];
61
+ const QUERY_DEBUG_GET_AGENT_CONTEXT = [
62
+ { name: 'bodyChars', required: false },
63
+ { name: 'bodyOffset', required: false },
64
+ ];
65
+ const QUERY_DEBUG_GET_LLM_CALL = [
66
+ { name: 'bodyChars', required: false },
67
+ { name: 'bodyOffset', required: false },
68
+ { name: 'view', required: false },
69
+ ];
70
+ const QUERY_DEBUG_GET_LLM_EXPORT = [
71
+ { name: 'limit', required: false },
72
+ { name: 'order', required: false },
73
+ { name: 'bodyChars', required: false },
74
+ ];
75
+ const QUERY_DEBUG_LIST_AGENT_CONTEXT = [
76
+ { name: 'stepIndex', required: false },
77
+ { name: 'limit', required: false },
78
+ { name: 'cursor', required: false },
79
+ ];
80
+ const QUERY_DEBUG_LIST_LLM_CALLS = [
81
+ { name: 'agentKind', required: false },
82
+ { name: 'phase', required: false },
83
+ { name: 'outcome', required: false },
84
+ { name: 'contains', required: false },
85
+ { name: 'order', required: false },
86
+ { name: 'limit', required: false },
87
+ { name: 'cursor', required: false },
88
+ { name: 'bodyChars', required: false },
89
+ ];
90
+ const QUERY_DEBUG_LIST_LOGS = [
91
+ { name: 'limit', required: false },
92
+ { name: 'cursor', required: false },
93
+ ];
94
+ const QUERY_DEBUG_LIST_RUNS = [
95
+ { name: 'status', required: false },
96
+ { name: 'since', required: false },
97
+ { name: 'limit', required: false },
98
+ { name: 'cursor', required: false },
99
+ ];
100
+ const QUERY_DEBUG_LIST_SEARCH_QUERIES = [
101
+ { name: 'limit', required: false },
102
+ { name: 'cursor', required: false },
103
+ ];
104
+ const QUERY_DEBUG_LIST_TOOL_CALLS = [
105
+ { name: 'limit', required: false },
106
+ { name: 'cursor', required: false },
107
+ { name: 'jobId', required: false },
108
+ { name: 'order', required: false },
109
+ { name: 'outcome', required: false },
110
+ ];
37
111
  /** Every `/api/v1` operation this facade exposes as a tool, in resource-group order. */
38
112
  export const CAT_FACTORY_TOOLS = [
39
113
  {
@@ -81,6 +155,17 @@ export const CAT_FACTORY_TOOLS = [
81
155
  outputSchema: { "type": "object", "properties": { "jobs": { "type": "array", "items": { "type": "object", "properties": { "createdAt": { "type": "number" }, "error": { "anyOf": [{ "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } } }, { "type": "null" }] }, "externalIdentity": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "externalIdentityWithheld": { "type": "boolean" }, "jobId": { "type": "string" }, "pipelineId": { "type": "string" }, "result": { "anyOf": [{ "type": "object", "properties": { "data": { "anyOf": [{}, { "type": "null" }] }, "output": { "type": "string" } } }, { "type": "null" }] }, "status": { "type": "string", "description": "One of: running, succeeded, failed. A newer deployment may report a member not in this list." } } } }, "nextCursor": { "anyOf": [{ "type": "string" }, { "type": "null" }] } } },
82
156
  invoke: (client, args) => client.jobs.list(pick(args, QUERY_JOBS_LIST)),
83
157
  },
158
+ {
159
+ name: 'services_create',
160
+ title: 'Create a service',
161
+ group: 'services',
162
+ operationId: 'createPublicService',
163
+ readOnly: false,
164
+ description: 'Create a service\n\nCreate a board service, optionally backed by a repository from `GET /api/v1/repos`. The repository link is what makes the service runnable: execution resolves a task’s repository by walking up to its enclosing service frame, so a service with none holds tasks and can start none of them. A whole-repo repository that already backs a service in this account is MOUNTED rather than duplicated; a monorepo service must name its subdirectory. The board lays the service out itself: this surface publishes no coordinates. Requires an `admin` key.\n\nCalls `POST /api/v1/services` (operation `createPublicService`).',
165
+ inputSchema: { "type": "object", "properties": { "body": { "type": "object", "properties": { "description": { "type": "string", "maxLength": 2000 }, "repo": { "type": "object", "properties": { "directory": { "type": "string", "maxLength": 400 }, "monorepo": { "type": "boolean" }, "repoId": { "type": "number" } }, "required": ["repoId"] }, "title": { "type": "string", "minLength": 1, "maxLength": 200 }, "type": { "type": "string", "enum": ["service", "frontend", "library", "document"] } }, "description": "The request body." } }, "additionalProperties": false, "required": ["body"] },
166
+ outputSchema: { "type": "object", "properties": { "description": { "type": "string" }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "title": { "type": "string" }, "type": { "type": "string", "description": "One of: frontend, service, library, document, api, database, queue, integration, external, environment. A newer deployment may report a member not in this list." } } },
167
+ invoke: (client, args) => client.services.create(args.body),
168
+ },
84
169
  {
85
170
  name: 'services_list',
86
171
  title: 'List the workspace\'s services',
@@ -92,6 +177,39 @@ export const CAT_FACTORY_TOOLS = [
92
177
  outputSchema: { "type": "object", "properties": { "services": { "type": "array", "items": { "type": "object", "properties": { "description": { "type": "string" }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "title": { "type": "string" }, "type": { "type": "string", "description": "One of: frontend, service, library, document, api, database, queue, integration, external, environment. A newer deployment may report a member not in this list." } } } } } },
93
178
  invoke: (client, args) => client.services.list(),
94
179
  },
180
+ {
181
+ name: 'repos_list',
182
+ title: 'List the repositories a service can be created against',
183
+ group: 'repos',
184
+ operationId: 'listPublicRepos',
185
+ readOnly: true,
186
+ description: 'List the repositories a service can be created against\n\nList the repositories the key’s workspace has connected, each with the service that already backs it (null when nothing does, and always null for a monorepo, which can back several). The discovery half of service creation: the create takes a repoId, and this is where one comes from.\n\nCalls `GET /api/v1/repos` (operation `listPublicRepos`).',
187
+ inputSchema: { "type": "object", "properties": {}, "additionalProperties": false },
188
+ outputSchema: { "type": "object", "properties": { "repos": { "type": "array", "items": { "type": "object", "properties": { "defaultBranch": { "type": "string" }, "linkedElsewhere": { "type": "boolean" }, "monorepo": { "type": "boolean" }, "name": { "type": "string" }, "owner": { "type": "string" }, "private": { "type": "boolean" }, "provider": { "type": "string" }, "repoId": { "type": "number" }, "serviceId": { "anyOf": [{ "type": "string" }, { "type": "null" }] } } } } } },
189
+ invoke: (client, args) => client.repos.list(),
190
+ },
191
+ {
192
+ name: 'tasks_add_dependency',
193
+ title: 'Declare that a task waits for another',
194
+ group: 'tasks',
195
+ operationId: 'addPublicTaskDependency',
196
+ readOnly: false,
197
+ description: 'Declare that a task waits for another\n\nRecord that this task cannot start until `dependsOnTaskId` is done. Both ends must be tasks in this workspace, and an edge that would close a cycle is refused. Idempotent: an edge that already exists is returned as-is rather than toggled off, so a provisioning integration re-running its own setup converges. Pair it with `autoStartDependents` on the BLOCKER (the task patch) to have the chain run itself.\n\nCalls `POST /api/v1/tasks/{taskId}/dependencies` (operation `addPublicTaskDependency`).',
198
+ inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." }, "body": { "type": "object", "properties": { "dependsOnTaskId": { "type": "string", "minLength": 1, "maxLength": 120 } }, "required": ["dependsOnTaskId"], "description": "The request body." } }, "additionalProperties": false, "required": ["taskId", "body"] },
199
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
200
+ invoke: (client, args) => client.tasks.addDependency(str(args, 'taskId'), args.body),
201
+ },
202
+ {
203
+ name: 'tasks_attach_document',
204
+ title: 'Attach a document to a task',
205
+ group: 'tasks',
206
+ operationId: 'attachPublicTaskDocument',
207
+ readOnly: false,
208
+ description: 'Attach a document to a task\n\nAttach a requirements document to a task that already exists, in either of the two forms creation takes: NAME a page in a connected document source, or CARRY the text inline. A task’s spec routinely arrives after the task does, and before this the only way to attach one was to delete the task and file it again, losing the id every stored reference points at, its ticket claim and the documents it already carried. A document a different live task already holds is refused rather than moved.\n\nCalls `POST /api/v1/tasks/{taskId}/documents` (operation `attachPublicTaskDocument`).',
209
+ inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." }, "body": { "type": "object", "properties": { "document": { "anyOf": [{ "type": "object", "properties": { "kind": { "const": "source" }, "ref": { "type": "string", "minLength": 1, "maxLength": 500 }, "source": { "type": "string", "enum": ["confluence", "notion", "github", "figma", "zeplin", "linear"] } }, "required": ["kind", "ref", "source"] }, { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 100000 }, "kind": { "const": "upload" }, "title": { "type": "string", "minLength": 1, "maxLength": 200 } }, "required": ["content", "kind", "title"] }], "description": "Discriminated by `kind` (source | upload)." } }, "required": ["document"], "description": "The request body." } }, "additionalProperties": false, "required": ["taskId", "body"] },
210
+ outputSchema: { "type": "object", "properties": { "excerpt": { "type": "string" }, "externalId": { "type": "string" }, "source": { "type": "string", "description": "One of: confluence, notion, github, figma, zeplin, linear, upload. A newer deployment may report a member not in this list." }, "title": { "type": "string" }, "url": { "type": "string" } } },
211
+ invoke: (client, args) => client.tasks.attachDocument(str(args, 'taskId'), args.body),
212
+ },
95
213
  {
96
214
  name: 'tasks_create',
97
215
  title: 'Create a task under a service',
@@ -100,7 +218,7 @@ export const CAT_FACTORY_TOOLS = [
100
218
  readOnly: false,
101
219
  description: 'Create a task under a service\n\nCreate a task inside a service frame the key’s workspace owns. The task starts in the `planned` state; start it with the start endpoint. Optionally file it FROM a tracker ticket, and/or attach the requirements documents it is to be built against (named in a connected document source, or uploaded inline): the only way to get spec-sized input onto a repository-touching run.\n\nCalls `POST /api/v1/services/{serviceId}/tasks` (operation `createPublicTask`).',
102
220
  inputSchema: { "type": "object", "properties": { "serviceId": { "type": "string", "description": "Path parameter `serviceId`." }, "body": { "type": "object", "properties": { "description": { "type": "string", "maxLength": 2000 }, "documents": { "type": "array", "items": { "anyOf": [{ "type": "object", "properties": { "kind": { "const": "source" }, "ref": { "type": "string", "minLength": 1, "maxLength": 500 }, "source": { "type": "string", "enum": ["confluence", "notion", "github", "figma", "zeplin", "linear"] } }, "required": ["kind", "ref", "source"] }, { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 100000 }, "kind": { "const": "upload" }, "title": { "type": "string", "minLength": 1, "maxLength": 200 } }, "required": ["content", "kind", "title"] }], "description": "Discriminated by `kind` (source | upload)." } }, "fields": { "type": "object", "additionalProperties": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "boolean" }, { "type": "number" }] } }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph. Other values are accepted where the deployment defines them." }, "ticket": { "type": "object", "properties": { "ref": { "type": "string", "minLength": 1, "maxLength": 500 }, "source": { "type": "string", "description": "Usually one of: jira, github, linear, gitlab. Other values are accepted where the deployment defines them." } }, "required": ["ref", "source"] }, "title": { "type": "string", "minLength": 1, "maxLength": 200 } }, "required": ["title"], "description": "The request body." } }, "additionalProperties": false, "required": ["serviceId", "body"] },
103
- outputSchema: { "type": "object", "properties": { "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
221
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
104
222
  invoke: (client, args) => client.tasks.create(str(args, 'serviceId'), args.body),
105
223
  },
106
224
  {
@@ -114,6 +232,16 @@ export const CAT_FACTORY_TOOLS = [
114
232
  inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." } }, "additionalProperties": false, "required": ["taskId"] },
115
233
  invoke: (client, args) => client.tasks.delete(str(args, 'taskId')),
116
234
  },
235
+ {
236
+ name: 'tasks_detach_document',
237
+ title: 'Detach a document from a task',
238
+ group: 'tasks',
239
+ operationId: 'detachPublicTaskDocument',
240
+ readOnly: false,
241
+ description: 'Detach a document from a task\n\nDetach a document, naming it by the `(source, externalId)` pair the list serves. The document itself survives in the workspace, so re-attaching it later costs no re-import. Idempotent: detaching one the task does not hold is a no-op.\n\nCalls `POST /api/v1/tasks/{taskId}/documents/detach` (operation `detachPublicTaskDocument`).',
242
+ inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." }, "body": { "type": "object", "properties": { "externalId": { "type": "string", "minLength": 1, "maxLength": 500 }, "source": { "type": "string", "enum": ["confluence", "notion", "github", "figma", "zeplin", "linear", "upload"] } }, "required": ["externalId", "source"], "description": "The request body." } }, "additionalProperties": false, "required": ["taskId", "body"] },
243
+ invoke: (client, args) => client.tasks.detachDocument(str(args, 'taskId'), args.body),
244
+ },
117
245
  {
118
246
  name: 'tasks_get',
119
247
  title: 'Get a task\'s status',
@@ -122,7 +250,7 @@ export const CAT_FACTORY_TOOLS = [
122
250
  readOnly: true,
123
251
  description: 'Get a task\'s status\n\nRead a task’s current lifecycle status, run progress, run id, and PR URL (once one exists).\n\nCalls `GET /api/v1/tasks/{taskId}` (operation `getPublicTask`).',
124
252
  inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." } }, "additionalProperties": false, "required": ["taskId"] },
125
- outputSchema: { "type": "object", "properties": { "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
253
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
126
254
  invoke: (client, args) => client.tasks.get(str(args, 'taskId')),
127
255
  },
128
256
  {
@@ -133,7 +261,7 @@ export const CAT_FACTORY_TOOLS = [
133
261
  readOnly: true,
134
262
  description: 'Get a task\'s run (rich projection)\n\nRead a task’s run in detail: per-step status/progress/subtasks, the failure kind and message, and the PR (url + branch).\n\nCalls `GET /api/v1/tasks/{taskId}/run` (operation `getPublicRun`).',
135
263
  inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." } }, "additionalProperties": false, "required": ["taskId"] },
136
- outputSchema: { "type": "object", "properties": { "createdAt": { "type": "number" }, "currentStep": { "type": "number" }, "error": { "anyOf": [{ "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } } }, { "type": "null" }] }, "externalIdentity": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "externalIdentityWithheld": { "type": "boolean" }, "pullRequest": { "anyOf": [{ "type": "object", "properties": { "branch": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "url": { "type": "string" } } }, { "type": "null" }] }, "runId": { "type": "string" }, "status": { "type": "string", "description": "One of: running, blocked, paused, done, failed. A newer deployment may report a member not in this list." }, "steps": { "type": "array", "items": { "type": "object", "properties": { "agentKind": { "type": "string" }, "progress": { "type": "number" }, "state": { "type": "string", "description": "One of: pending, working, waiting_decision, done. A newer deployment may report a member not in this list." }, "subtasks": { "anyOf": [{ "type": "object", "properties": { "completed": { "type": "number" }, "inProgress": { "type": "number" }, "total": { "type": "number" } } }, { "type": "null" }] } } } }, "taskId": { "type": "string" } } },
264
+ outputSchema: { "type": "object", "properties": { "createdAt": { "type": "number" }, "currentStep": { "type": "number" }, "error": { "anyOf": [{ "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } } }, { "type": "null" }] }, "externalIdentity": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "externalIdentityWithheld": { "type": "boolean" }, "pullRequest": { "anyOf": [{ "type": "object", "properties": { "branch": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "url": { "type": "string" } } }, { "type": "null" }] }, "runId": { "type": "string" }, "status": { "type": "string", "description": "One of: running, blocked, paused, done, failed. A newer deployment may report a member not in this list." }, "steps": { "type": "array", "items": { "type": "object", "properties": { "agentKind": { "type": "string" }, "data": { "anyOf": [{}, { "type": "null" }] }, "output": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "progress": { "type": "number" }, "state": { "type": "string", "description": "One of: pending, working, waiting_decision, done. A newer deployment may report a member not in this list." }, "subtasks": { "anyOf": [{ "type": "object", "properties": { "completed": { "type": "number" }, "inProgress": { "type": "number" }, "total": { "type": "number" } } }, { "type": "null" }] }, "truncated": { "type": "boolean" } } } }, "taskId": { "type": "string" } } },
137
265
  invoke: (client, args) => client.tasks.getRun(str(args, 'taskId')),
138
266
  },
139
267
  {
@@ -144,9 +272,31 @@ export const CAT_FACTORY_TOOLS = [
144
272
  readOnly: true,
145
273
  description: 'List a service\'s tasks\n\nList every task under a service (the whole subtree — tasks directly under the frame and under its modules).\n\nCalls `GET /api/v1/services/{serviceId}/tasks` (operation `listPublicServiceTasks`).',
146
274
  inputSchema: { "type": "object", "properties": { "serviceId": { "type": "string", "description": "Path parameter `serviceId`." }, "limit": { "type": "integer" }, "cursor": { "type": "string" }, "status": { "type": "string", "enum": ["planned", "ready", "in_progress", "blocked", "pr_ready", "done"] } }, "additionalProperties": false, "required": ["serviceId"] },
147
- outputSchema: { "type": "object", "properties": { "nextCursor": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "tasks": { "type": "array", "items": { "type": "object", "properties": { "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } } } } },
275
+ outputSchema: { "type": "object", "properties": { "nextCursor": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "tasks": { "type": "array", "items": { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } } } } },
148
276
  invoke: (client, args) => client.tasks.listByService(str(args, 'serviceId'), pick(args, QUERY_TASKS_LIST_BY_SERVICE)),
149
277
  },
278
+ {
279
+ name: 'tasks_list_documents',
280
+ title: 'List a task\'s attached documents',
281
+ group: 'tasks',
282
+ operationId: 'listPublicTaskDocuments',
283
+ readOnly: true,
284
+ description: 'List a task\'s attached documents\n\nThe requirements documents attached to the task, in the order the agents read them. Each is identified by the `(source, externalId)` pair the attach and detach calls take.\n\nCalls `GET /api/v1/tasks/{taskId}/documents` (operation `listPublicTaskDocuments`).',
285
+ inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." } }, "additionalProperties": false, "required": ["taskId"] },
286
+ outputSchema: { "type": "object", "properties": { "documents": { "type": "array", "items": { "type": "object", "properties": { "excerpt": { "type": "string" }, "externalId": { "type": "string" }, "source": { "type": "string", "description": "One of: confluence, notion, github, figma, zeplin, linear, upload. A newer deployment may report a member not in this list." }, "title": { "type": "string" }, "url": { "type": "string" } } } } } },
287
+ invoke: (client, args) => client.tasks.listDocuments(str(args, 'taskId')),
288
+ },
289
+ {
290
+ name: 'tasks_remove_dependency',
291
+ title: 'Drop a dependency edge',
292
+ group: 'tasks',
293
+ operationId: 'removePublicTaskDependency',
294
+ readOnly: false,
295
+ description: 'Drop a dependency edge\n\nRemove the ordering between this task and `dependsOnTaskId`. Idempotent: an edge that is not there is a no-op.\n\nCalls `POST /api/v1/tasks/{taskId}/dependencies/remove` (operation `removePublicTaskDependency`).',
296
+ inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." }, "body": { "type": "object", "properties": { "dependsOnTaskId": { "type": "string", "minLength": 1, "maxLength": 120 } }, "required": ["dependsOnTaskId"], "description": "The request body." } }, "additionalProperties": false, "required": ["taskId", "body"] },
297
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
298
+ invoke: (client, args) => client.tasks.removeDependency(str(args, 'taskId'), args.body),
299
+ },
150
300
  {
151
301
  name: 'tasks_retry',
152
302
  title: 'Retry a task\'s failed run',
@@ -156,7 +306,7 @@ export const CAT_FACTORY_TOOLS = [
156
306
  hints: { "destructive": true, "idempotent": false },
157
307
  description: 'Retry a task\'s failed run\n\nRetry a task’s failed run. A task on an individual-usage model cannot be retried through the API (no headless personal-credential unlock).\n\nCalls `POST /api/v1/tasks/{taskId}/retry` (operation `retryPublicTask`).',
158
308
  inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." } }, "additionalProperties": false, "required": ["taskId"] },
159
- outputSchema: { "type": "object", "properties": { "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
309
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
160
310
  invoke: (client, args) => client.tasks.retry(str(args, 'taskId')),
161
311
  },
162
312
  {
@@ -168,7 +318,7 @@ export const CAT_FACTORY_TOOLS = [
168
318
  hints: { "destructive": true, "idempotent": false },
169
319
  description: 'Start (run) a task\n\nStart a task’s pipeline. Uses the request’s pipelineId, else the task’s pinned pipeline. A pipeline that can park on a human decision requires a `decide`-scope key. A task on an individual-usage model cannot be started through the API (no headless personal-credential unlock).\n\nCalls `POST /api/v1/tasks/{taskId}/start` (operation `startPublicTask`).',
170
320
  inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." }, "body": { "type": "object", "properties": { "pipelineId": { "type": "string", "minLength": 1, "maxLength": 120 } }, "description": "The request body." } }, "additionalProperties": false, "required": ["taskId", "body"] },
171
- outputSchema: { "type": "object", "properties": { "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
321
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
172
322
  invoke: (client, args) => client.tasks.start(str(args, 'taskId'), args.body),
173
323
  },
174
324
  {
@@ -179,7 +329,7 @@ export const CAT_FACTORY_TOOLS = [
179
329
  readOnly: false,
180
330
  description: 'Stop a task\'s run\n\nStop a task’s in-flight run. Records a `cancelled` terminal state, leaving the run retryable.\n\nCalls `POST /api/v1/tasks/{taskId}/stop` (operation `stopPublicTask`).',
181
331
  inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." } }, "additionalProperties": false, "required": ["taskId"] },
182
- outputSchema: { "type": "object", "properties": { "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
332
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
183
333
  invoke: (client, args) => client.tasks.stop(str(args, 'taskId')),
184
334
  },
185
335
  {
@@ -189,8 +339,8 @@ export const CAT_FACTORY_TOOLS = [
189
339
  operationId: 'updatePublicTask',
190
340
  readOnly: false,
191
341
  description: 'Edit a task\'s inputs\n\nEdit a task’s human-authored inputs before it runs: its title, its description, and `fields`, the per-case values for its own task type (checked against the descriptors `GET /api/v1/task-types` serves). All are optional. `fields` is MERGED over what the task already carries — a key you send is written, a key you omit keeps its stored value — because this API does not serve the bag back. This is what makes an input the pre-dispatch gate refused repairable: supply the value it named, then recheck the parked run.\n\nCalls `PATCH /api/v1/tasks/{taskId}` (operation `updatePublicTask`).',
192
- inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." }, "body": { "type": "object", "properties": { "description": { "type": "string", "maxLength": 2000 }, "fields": { "type": "object", "additionalProperties": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "boolean" }, { "type": "number" }] } }, "title": { "type": "string", "minLength": 1, "maxLength": 200 } }, "description": "The request body." } }, "additionalProperties": false, "required": ["taskId", "body"] },
193
- outputSchema: { "type": "object", "properties": { "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
342
+ inputSchema: { "type": "object", "properties": { "taskId": { "type": "string", "description": "Path parameter `taskId`." }, "body": { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "description": { "type": "string", "maxLength": 2000 }, "fields": { "type": "object", "additionalProperties": { "anyOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }, { "type": "boolean" }, { "type": "number" }] } }, "title": { "type": "string", "minLength": 1, "maxLength": 200 } }, "description": "The request body." } }, "additionalProperties": false, "required": ["taskId", "body"] },
343
+ outputSchema: { "type": "object", "properties": { "autoStartDependents": { "type": "boolean" }, "dependsOn": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "progress": { "type": "number" }, "pullRequestUrl": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "serviceId": { "type": "string" }, "status": { "type": "string", "description": "One of: planned, ready, in_progress, blocked, pr_ready, done. A newer deployment may report a member not in this list." }, "taskId": { "type": "string" }, "taskType": { "type": "string", "description": "Usually one of: feature, bug, document, spike, review, ralph, recurring. Other values are accepted where the deployment defines them." }, "title": { "type": "string" } } },
194
344
  invoke: (client, args) => client.tasks.update(str(args, 'taskId'), args.body),
195
345
  },
196
346
  {
@@ -339,6 +489,17 @@ export const CAT_FACTORY_TOOLS = [
339
489
  outputSchema: { "type": "object", "properties": { "budget": { "type": "object", "properties": { "costLimit": { "type": "number" }, "costSpent": { "type": "number" }, "exceeded": { "type": "boolean" }, "inputTokens": { "type": "number" }, "outputTokens": { "type": "number" } } }, "currency": { "type": "string" }, "periodStart": { "type": "number" }, "rows": { "type": "array", "items": { "type": "object", "properties": { "billing": { "type": "string", "description": "One of: metered, subscription. A newer deployment may report a member not in this list." }, "calls": { "type": "number" }, "costEstimate": { "type": "number" }, "inputTokens": { "type": "number" }, "model": { "type": "string" }, "outputTokens": { "type": "number" }, "provider": { "type": "string" }, "vendor": { "anyOf": [{ "type": "string" }, { "type": "null" }] } } } } } },
340
490
  invoke: (client, args) => client.usage.get(),
341
491
  },
492
+ {
493
+ name: 'usage_spend',
494
+ title: 'Break the workspace\'s spend down by repository, ticket, run or step kind',
495
+ group: 'usage',
496
+ operationId: 'getPublicSpend',
497
+ readOnly: true,
498
+ description: 'Break the workspace\'s spend down by repository, ticket, run or step kind\n\nGroup the board’s spend over a window (`24h`, `7d`, `30d`, `90d`) by ONE dimension: `repo`, `ticket` and `run` are the cost-attribution axes an organisation budgets against, and `model` / `agentKind` / `service` / `taskType` slice the same money the other ways. `meteredCost` is real money and `subscriptionCost` is the illustrative equivalent-API cost of flat-rate quota usage, so never sum them. The EMPTY `key` is the unattributed bucket, a real slice rather than a dropped row, never dropped from the breakdown. `rows` is the heaviest `limit` slices (default 100, max 500) and `truncated` says when there was a tail, while `totals` aggregates the WHOLE window either way, so a capped answer still reports what the board spent. `source` says which store answered: the short windows scan the live ledger, which resolves a repository or a ticket through today’s links, while the long ones read the durable daily rollup, which froze that attribution while the money was spent and is never pruned. Read `rolledUpThrough` before reporting a quiet quarter, since a rollup that has never run and a board that spent nothing look identical. Workspace-scoped: the account-wide view is not reachable through this surface.\n\nCalls `GET /api/v1/usage/spend` (operation `getPublicSpend`).',
499
+ inputSchema: { "type": "object", "properties": { "dimension": { "type": "string", "enum": ["model", "agentKind", "service", "repo", "taskType", "ticket", "run"] }, "window": { "type": "string", "enum": ["24h", "7d", "30d", "90d"] }, "limit": { "type": "integer" } }, "additionalProperties": false, "required": ["dimension"] },
500
+ outputSchema: { "type": "object", "properties": { "currency": { "type": "string" }, "dimension": { "type": "string", "description": "One of: model, agentKind, service, repo, taskType, ticket, run. A newer deployment may report a member not in this list." }, "generatedAt": { "type": "number" }, "rolledUpThrough": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "rows": { "type": "array", "items": { "type": "object", "properties": { "calls": { "type": "number" }, "inputTokens": { "type": "number" }, "key": { "type": "string" }, "label": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "meteredCost": { "type": "number" }, "outputTokens": { "type": "number" }, "subscriptionCost": { "type": "number" } } } }, "since": { "type": "number" }, "source": { "type": "string", "description": "One of: ledger, daily-rollup. A newer deployment may report a member not in this list." }, "totals": { "type": "object", "properties": { "calls": { "type": "number" }, "inputTokens": { "type": "number" }, "meteredCost": { "type": "number" }, "outputTokens": { "type": "number" }, "subscriptionCost": { "type": "number" } } }, "truncated": { "type": "boolean" }, "window": { "type": "string", "description": "One of: 24h, 7d, 30d, 90d. A newer deployment may report a member not in this list." } } },
501
+ invoke: (client, args) => client.usage.spend(pick(args, QUERY_USAGE_SPEND)),
502
+ },
342
503
  {
343
504
  name: 'me_get',
344
505
  title: 'Describe the calling key',
@@ -823,6 +984,17 @@ export const CAT_FACTORY_TOOLS = [
823
984
  outputSchema: { "type": "object", "properties": { "agentKind": { "type": "string" }, "cacheReadTokens": { "type": "number" }, "cacheWriteTokens": { "type": "number" }, "callId": { "type": "string" }, "completionTokens": { "type": "number" }, "createdAt": { "type": "number" }, "elidedLeadingMessages": { "type": "number" }, "errorMessage": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "finishReason": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "httpStatus": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "messageCount": { "type": "number" }, "model": { "type": "string" }, "ok": { "type": "boolean" }, "outcome": { "type": "string", "description": "One of: ok, warning, error. A newer deployment may report a member not in this list." }, "overheadMs": { "type": "number" }, "phase": { "type": "string" }, "prompt": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "promptMessages": { "anyOf": [{ "type": "array", "items": { "type": "object", "properties": { "content": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "index": { "type": "number" }, "name": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "role": { "type": "string" }, "toolCallId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "toolCalls": { "type": "array", "items": { "type": "object", "properties": { "args": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "name": { "type": "string" } } } } } } }, { "type": "null" }] }, "promptTokens": { "type": "number" }, "provider": { "type": "string" }, "reasoning": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "requestMaxTokens": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "response": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "streaming": { "type": "boolean" }, "toolCount": { "type": "number" }, "totalMs": { "type": "number" }, "totalTokens": { "type": "number" }, "turnIndex": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "upstreamMs": { "type": "number" } } },
824
985
  invoke: (client, args) => client.debug.getLlmCall(str(args, 'callId'), pick(args, QUERY_DEBUG_GET_LLM_CALL)),
825
986
  },
987
+ {
988
+ name: 'debug_get_llm_export',
989
+ title: 'Export a run\'s model activity as one bundle',
990
+ group: 'debug',
991
+ operationId: 'getDebugLlmExport',
992
+ readOnly: true,
993
+ description: 'Export a run\'s model activity as one bundle\n\nThe whole of a run’s model activity as one self-describing document, for handing straight to a model asked why the run truncated, spent or stalled: the SQL rollups (run totals, per agent kind, per phase, with the carry cost that says which slice burdened everything after it) plus a bounded window of the individual calls behind them. The rollups cover EVERY recorded call and do not move with `limit`, so a windowed bundle still reports what the run actually cost; `truncated` says the calls are a window and `order` says which end was kept. Bodies are omitted unless `bodyChars` asks, and the resumable call list is the way to walk a long run whole.\n\nCalls `GET /api/v1/debug/runs/{runId}/llm-export` (operation `getDebugLlmExport`).',
994
+ inputSchema: { "type": "object", "properties": { "runId": { "type": "string", "description": "Path parameter `runId`." }, "limit": { "type": "integer" }, "order": { "type": "string", "enum": ["newest", "oldest"] }, "bodyChars": { "type": "integer" } }, "additionalProperties": false, "required": ["runId"] },
995
+ outputSchema: { "type": "object", "properties": { "available": { "type": "boolean" }, "calls": { "type": "array", "items": { "type": "object", "properties": { "agentKind": { "type": "string" }, "cacheReadTokens": { "type": "number" }, "cacheWriteTokens": { "type": "number" }, "callId": { "type": "string" }, "completionTokens": { "type": "number" }, "createdAt": { "type": "number" }, "elidedLeadingMessages": { "type": "number" }, "errorMessage": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "finishReason": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "httpStatus": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "messageCount": { "type": "number" }, "model": { "type": "string" }, "ok": { "type": "boolean" }, "outcome": { "type": "string", "description": "One of: ok, warning, error. A newer deployment may report a member not in this list." }, "overheadMs": { "type": "number" }, "phase": { "type": "string" }, "prompt": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "promptMessages": { "anyOf": [{ "type": "array", "items": { "type": "object", "properties": { "content": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "index": { "type": "number" }, "name": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "role": { "type": "string" }, "toolCallId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "toolCalls": { "type": "array", "items": { "type": "object", "properties": { "args": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "name": { "type": "string" } } } } } } }, { "type": "null" }] }, "promptTokens": { "type": "number" }, "provider": { "type": "string" }, "reasoning": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "requestMaxTokens": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "response": { "type": "object", "properties": { "chars": { "type": "number" }, "matchOffset": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "offset": { "type": "number" }, "text": { "type": "string" }, "totalChars": { "type": "number" }, "truncated": { "type": "boolean" } } }, "runId": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "streaming": { "type": "boolean" }, "toolCount": { "type": "number" }, "totalMs": { "type": "number" }, "totalTokens": { "type": "number" }, "turnIndex": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "upstreamMs": { "type": "number" } } } }, "generatedAt": { "type": "number" }, "kind": { "type": "string" }, "llm": { "type": "object", "properties": { "byAgentKind": { "type": "array", "items": { "type": "object", "properties": { "agentKind": { "type": "string" }, "cacheHitRate": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "cacheReadTokens": { "type": "number" }, "cacheWriteTokens": { "type": "number" }, "calls": { "type": "number" }, "completionTokens": { "type": "number" }, "costEstimate": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "errors": { "type": "number" }, "maxOutputTokens": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "outputHeadroomRatio": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "overheadMs": { "type": "number" }, "peakCompletionTokens": { "type": "number" }, "promptTokens": { "type": "number" }, "transportOverheadRatio": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "truncatedCalls": { "type": "number" }, "upstreamMs": { "type": "number" }, "warnings": { "type": "number" } } } }, "byPhase": { "type": "array", "items": { "type": "object", "properties": { "cacheHitRate": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "cacheReadTokens": { "type": "number" }, "cacheWriteTokens": { "type": "number" }, "calls": { "type": "number" }, "carryCostShare": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "carryCostTokens": { "type": "number" }, "completionTokens": { "type": "number" }, "costEstimate": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "errors": { "type": "number" }, "overheadMs": { "type": "number" }, "phase": { "type": "string" }, "promptTokens": { "type": "number" }, "truncatedCalls": { "type": "number" }, "upstreamMs": { "type": "number" }, "warnings": { "type": "number" } } } }, "costCurrency": { "anyOf": [{ "type": "string" }, { "type": "null" }] }, "totals": { "type": "object", "properties": { "cacheHitRate": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "cacheReadTokens": { "type": "number" }, "cacheWriteTokens": { "type": "number" }, "calls": { "type": "number" }, "completionTokens": { "type": "number" }, "costEstimate": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "errors": { "type": "number" }, "overheadMs": { "type": "number" }, "promptTokens": { "type": "number" }, "transportOverheadRatio": { "anyOf": [{ "type": "number" }, { "type": "null" }] }, "truncatedCalls": { "type": "number" }, "upstreamMs": { "type": "number" }, "warnings": { "type": "number" } } } } }, "order": { "type": "string", "description": "One of: newest, oldest. A newer deployment may report a member not in this list." }, "runId": { "type": "string" }, "truncated": { "type": "boolean" }, "version": { "type": "number" } } },
996
+ invoke: (client, args) => client.debug.getLlmExport(str(args, 'runId'), pick(args, QUERY_DEBUG_GET_LLM_EXPORT)),
997
+ },
826
998
  {
827
999
  name: 'debug_get_run',
828
1000
  title: 'Get a run\'s diagnostic map',
@@ -930,7 +1102,7 @@ export const CAT_FACTORY_TOOLS = [
930
1102
  readOnly: true,
931
1103
  description: 'List a run\'s captured artifacts\n\nThe binary artifacts the run captured (UI screenshots) plus the reference images they were reviewed against: id, kind, view, content type, exact byte size and content hash. Unpaged: the capture path caps how many one run may store, so the response size is bounded before the request. Fetch the bytes with the blob endpoint.\n\nCalls `GET /api/v1/runs/{runId}/artifacts` (operation `listPublicRunArtifacts`).',
932
1104
  inputSchema: { "type": "object", "properties": { "runId": { "type": "string", "description": "Path parameter `runId`." } }, "additionalProperties": false, "required": ["runId"] },
933
- outputSchema: { "type": "object", "properties": { "artifacts": { "type": "array", "items": { "type": "object", "properties": { "artifactId": { "type": "string" }, "byteSize": { "type": "number" }, "contentType": { "type": "string" }, "createdAt": { "type": "number" }, "hash": { "type": "string" }, "kind": { "type": "string", "description": "One of: screenshot, reference. A newer deployment may report a member not in this list." }, "view": { "anyOf": [{ "type": "string" }, { "type": "null" }] } } } } } },
1105
+ outputSchema: { "type": "object", "properties": { "artifacts": { "type": "array", "items": { "type": "object", "properties": { "artifactId": { "type": "string" }, "byteSize": { "type": "number" }, "contentType": { "type": "string" }, "createdAt": { "type": "number" }, "hash": { "type": "string" }, "kind": { "type": "string", "description": "One of: screenshot, reference. A newer deployment may report a member not in this list." }, "scope": { "type": "string", "description": "One of: run, task. A newer deployment may report a member not in this list." }, "view": { "anyOf": [{ "type": "string" }, { "type": "null" }] } } } } } },
934
1106
  invoke: (client, args) => client.evidence.listArtifacts(str(args, 'runId')),
935
1107
  },
936
1108
  {
@@ -990,16 +1162,17 @@ export const CAT_FACTORY_OMITTED_OPERATIONS = [
990
1162
  /** One line per resource group, for the server's instructions. */
991
1163
  export const CAT_FACTORY_TOOL_GROUPS = {
992
1164
  'jobs': 'Headless jobs (a public, inline pipeline run against a brief): start, poll or stream one.',
993
- 'services': 'The workspace\'s board services the frames tasks are created under.',
994
- 'tasks': 'A board task\'s whole lifecycle: create, edit, start, stop, retry, watch, delete.',
1165
+ 'services': 'The workspace\'s board services, the frames tasks are created under: list them, or create one (optionally backed by a repository).',
1166
+ 'repos': 'The repositories this workspace can back a service with, and which service each already backs: the discovery half of service creation.',
1167
+ 'tasks': 'A board task\'s whole lifecycle: create, edit, start, stop, retry, watch, delete, plus the two relationships that outlive a create: the tasks it waits for, and the requirements documents it is built against.',
995
1168
  'pipelines': 'The pipelines a task can be started with, and whether each is headless-startable.',
996
1169
  'task_types': 'What a task can be created AS in this workspace (the built-in kinds plus the operations the deployment registered), and the fields each one accepts.',
997
1170
  'notifications': 'The workspace\'s human-actionable inbox: list, act on, or dismiss a run tail.',
998
1171
  'webhook': 'The workspace\'s outbound endpoints: register, inspect or remove the receivers that notifications, run-lifecycle events and health alerts are pushed to. The unnamed calls address the `default` endpoint; the named ones let an integration enroll its own receiver, with its own signing secret and filters, beside whatever else is registered.',
999
- 'usage': 'The billing period\'s metered budget position and the per-model breakdown behind it.',
1172
+ 'usage': 'The workspace\'s money, two ways: the billing period\'s metered budget position with the per-model breakdown behind it, and spend over a window sliced by the dimension a budget is kept against (a repository, a tracker ticket, one run).',
1000
1173
  'me': 'What the calling key is and what it may do — the self-check an integration runs at startup.',
1001
1174
  'decisions': 'Every way a run stops for a person: approval gates, review and brainstorm loops, forks, judge verdicts, PR review findings, the human-verdict gates, follow-up triage and the interview gates.',
1002
- 'debug': 'A run\'s recorded telemetry: LLM calls, the context each agent was given, the tool calls it made, infra logs.',
1175
+ 'debug': 'A run\'s recorded telemetry: LLM calls, the context each agent was given, the tool calls it made, infra logs, and the whole model-activity bundle as one document.',
1003
1176
  'evidence': 'What a run proved: the engine\'s verification report, the outcome summary behind it, and the artifacts it captured, bytes included.',
1004
1177
  'keys': 'The workspace\'s own API keys: provision one headlessly, list them, revoke one (and what it minted).',
1005
1178
  };