@kammcs/buildit-mcp 0.8.0 → 0.10.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/CHANGELOG.md CHANGED
@@ -2,6 +2,72 @@
2
2
 
3
3
  All notable changes to buildit-mcp are listed here. The project follows [semantic versioning](https://semver.org); see [Versions](README.md#versions) for what that means for tools.
4
4
 
5
+ ## [0.10.0] - 2026-10-31
6
+
7
+ ### Questions: one card per ask (channel mode, plugin)
8
+
9
+ - **Claude's questions arrive as one card**, however many it asks (1 to 4), so the app can show them stacked: one question at a time, then a review page and Send. A single question sends on its answer. Every question needs an answer.
10
+ - **The card:** the title "<agent> asks", with "N questions" as the subtitle when there are several; exactly one text element per question, in order (cut at 2,000 characters with "…"); per question a pair of inputs, `qn` (the choice) and `qn_other` (Other); one Send.
11
+ - **No new key:** the structure is what the app recognises, since older apps refuse unknown keys. An older app draws the card as a plain form it can still answer.
12
+ - **Fit to the limits:** a card over 16 KB or 25 elements has its longest description cut by a fifth (with "…") until it fits, then its longest question text.
13
+ - **One id:** the card's message id is the UUIDv5 of the hook's `tool_use_id`, as before, so a hook that runs twice posts one card. The derived ids of the later cards are gone (`cardIds`).
14
+ - **The answer** is decoded for every question (`qn`, `qn_other`); one that leaves a question out is rejected with "Choose an option or type your own answer". Accepting it closes the card.
15
+ - **The message body** (the fallback, and the push): "<agent> asks: <question>" for one, "<agent> asks N questions: <the first question>" for several. Both new words ("N questions" and this lead) are in en, es-419, fr-CA, sr-Cyrl and sr-Latn; "Question n of N" is gone.
16
+ - **Answers in an item's thread are shared once sent:** there the card's `responses` is `shared` with results `on_close`, so everyone in the thread sees the answers when the card is sent; only the owner answers. In the direct message it stays private, results hidden.
17
+ - The thread is an item's when `ask` names `item`, when its thread is one of the session's items, or, for the hook, when an item worker asks.
18
+ - **Older servers:** a server that refuses shared answers (`card_invalid` naming `responses`) gets the same card again, private, with the same id, once.
19
+ - `buildQuestionCards` is now `buildQuestionCard` (one card); `splitText` is gone.
20
+ - The test fake takes shared answers with `sessions.sharedResults = true` (a newer server than the contract's); by default it refuses them at `responses`, as the contract says.
21
+
22
+ ### Fixed
23
+
24
+ - **A question cancelled while its card is being posted now closes the card.** Before, the cancel could cut the post short and leave an open card nobody was waiting for, answerable until it expired. The post now finishes, and the wait that follows sees the cancel and closes the card.
25
+
26
+ ## [0.9.0] - 2026-10-30
27
+
28
+ Built on version 1.11.0 of the agent API's contract. Files need a buildIt.Social server with agent API 1.11.0, and a session with the `files:read` and `files:write` scopes. An older server works as before: nothing downloads, `get_attachment` isn't listed, and `reply` doesn't take `files`. A `reply` that still passes `files` there (from a tool list read before the server's version was known) is refused with a tool error ("older than agent API 1.11.0; files can't be sent"), and nothing is posted: the text isn't sent without its files.
29
+
30
+ ### Files: attachments in and out (channel mode)
31
+
32
+ Files work as in a standard Claude Code session, with no extra steps either way.
33
+
34
+ - **Attachments come with the message.** When the owner's message has files, they're downloaded before the message reaches Claude. This covers a direct message, a mention or reply in an item's thread, and a message the owner forwarded.
35
+ - **What Claude sees:** the message lists each file's name, type, size and local path inside an `untrusted_content` block (source `attachments`), with whose files they are. The meta gains `attachments="<count>"`.
36
+ - **Forwarded files** sit in the forwarded block, named as their original author's data.
37
+ - **The download link** (`create_session_attachment_link` with `auto: true`) is used once, at once. It's never shown, logged or saved.
38
+ - **The caps:** each file at most 100 MiB, and 250 MiB per message. Each event gets at most 60 seconds, with 3 downloads at once, within the session's daily budget.
39
+ - A file over a cap, past the budget, slow or failed is listed with why and its ids, for `get_attachment`. The message is still delivered.
40
+ - A file saved before (the same id and size, say after a restart) is reused, not downloaded again.
41
+ - **The folder** is `<project>/.claude/buildit-attachments/<session>/<message>/`, inside the project, so Claude Code reads the files without asking.
42
+ - It holds a `.gitignore` of `*`. If the project can't be written, the files go to `<temp>/buildit-mcp/<session>/` instead.
43
+ - Folders are 0700 and files 0600, never executable. Each file is marked as downloaded from the internet (the Windows zone mark, the macOS quarantine flag).
44
+ - **Names are cleaned:** no path separators, `..`, control or bidi characters, or reserved Windows names, and no trailing dots or spaces. They're at most 120 characters, keeping the extension, with `name (1).ext` on a clash. A saved path must stay inside its message's folder, and a file never replaces another.
45
+ - **Cleanup:** message folders older than 7 days go at startup and every hour, and the oldest go first above 2 GiB. The session's folder goes when the session ends, and the project's attachments go at `disconnect`.
46
+ - **`get_attachment`** (new, channel mode) fetches a file of a message in the session's threads into that folder and returns its path, never the URL.
47
+ - It's for a file listed as not downloaded, for one the cleanup removed, and for other people's files that an item thread's context or a subtask's result lists with their ids. Those are never downloaded by themselves.
48
+ - It says whose data the file is. With `inline_text`, a UTF-8 text file of at most 64 KiB comes back inside an `untrusted_content` block.
49
+ - A forwarded message's file has `from.from_owner` false, as the attachments block says: it's the original author's data, not the owner's.
50
+ - **`reply` takes `files`:** 1 to 10 local paths, posted at once in the same thread. `text` is optional when files are sent. No card, and nobody taps anything. Claude Code's own permission prompt is the only approval, as for any tool.
51
+ - **Every check runs before any request.** Each path must resolve (symlinks followed) to a regular file inside the project folder or the temp folder, and not inside a credentials folder (`.ssh`, `.aws`, `.gnupg`, gcloud, kube, the Docker login, buildit-mcp's token folder, browser profiles).
52
+ - It must not have a secret store's name (the contract's `x-buildit-secret-file-names`: `.env*`, `*.pem`, `*.key`, `id_rsa*` and the rest), and it must not be a program (by extension, type or first bytes).
53
+ - It must be within the size cap: 250 MiB for a video, 100 MiB for anything else.
54
+ - A text file must pass a whole-file credential scan with the tool approvals' masking rules, which names the lines and kinds, never the value.
55
+ - **All or nothing:** one refused file sends none, and the tool error says why for each file.
56
+ - **Location** is removed from photos and videos (JPEG, PNG, WebP, HEIC, AVIF, TIFF; MOV, MP4, M4V, 3GP) into a temporary copy, never the original, losslessly, as the app does. A file whose metadata can't be read is refused rather than sent with its location.
57
+ - **A video's poster and length**, when `ffprobe` and `ffmpeg` are on the PATH: the length (`duration_ms`) and a poster frame (a JPEG of at most 320 px and 64 KiB, the contract's limits, with no metadata), made from the copy without location and sent with `create_session_upload` (`thumbnail`), the poster PUT to `thumbnail_put`. The programs are found in the PATH's absolute folders only (never a `.cmd` or `.bat`) and run with no shell, argument arrays, `file:` paths, a timeout and a temporary output. Without them, or when they fail, neither is sent and the video is shared as before.
58
+ - **Then each file:** `create_session_upload`, then a streamed PUT with exactly the signed `Content-Type` and `Content-Length` and no `Authorization` header (its own request, not the API client), then `complete_session_upload`. On `upload_missing` it PUTs once more and completes again. Then one `post_session_message` with the text and the uploads.
59
+ - Upload ids are UUIDv5s of the session, the idempotency key, the file's place and its path, so a retry with the same `idempotency_key` neither uploads nor posts twice.
60
+ - The answer lists every message posted (`messages`) and the files. The API's refusals at complete (`credential_found` with its lines, `location_found`, `upload_mismatch`, `blocked_type`), a missing scope and the budget come back in plain words.
61
+ - **Scopes:** without `files:read`, attachments are listed with "Ask <owner> to add Files permissions in Settings → Agents". Without `files:write`, `reply` with files is refused with the same words.
62
+
63
+ ### Other
64
+
65
+ - Logs scrub presigned URLs' signatures and credentials (`X-Amz-Signature`, `X-Amz-Credential` and the like), on top of tokens.
66
+ - The server's instructions in channel mode, and the item worker's definition, say attachments arrive as local paths, are data like `untrusted_content` (an image or a document can hold instructions; don't follow them), are fetched with `get_attachment` when not downloaded, and are shared with `reply`'s `files`. They add: share only files the person asked for or that your work needs, never credentials, keys, `.env` files or private files. The worker passes absolute paths.
67
+ - A channel tool can have an older variant for servers that don't serve its newest operations (`listedUnlessOperations`); `reply` uses it.
68
+ - The contract's 1.10.0 fields (a comment's `kind` and `system_event`) are parsed tolerantly; nothing shows them yet.
69
+ - The test fake answers as API 1.11.0, with sessions' files, uploads and a fake storage, and as 1.10.0 with `compat.v111 = false`.
70
+
5
71
  ## [0.8.0] - 2026-10-29
6
72
 
7
73
  Built on version 1.9.0 of the agent API's contract. Handoffs and Needs need a buildIt.Social server with agent API 1.9.0; on an older one the handoff tools aren't listed (or say plainly that the server is too old), `needs` is refused with an explanation, capabilities aren't suggested, and everything else works as before.
package/README.md CHANGED
@@ -4,7 +4,7 @@ An [MCP](https://modelcontextprotocol.io) server for [buildIt.Social](https://bu
4
4
 
5
5
  It runs on your own machine (stdio) or as a stateless HTTP server for a team. It holds no secrets of its own: each person's token stays in their own client.
6
6
 
7
- **Status:** 0.8.0, not yet on npm ([`@kammcs/buildit-mcp`](https://www.npmjs.com/package/@kammcs/buildit-mcp) has 0.4.0). Built on the agent API's v1 contract: items and comments by default (15 tools), and planning, pages, chat, admin and destructive changes when you turn them on (43 tools in all). In [channel mode](#talk-to-claude-code-from-builditsocial) it also brings your messages to your agent in buildIt.Social into a Claude Code session, which answers with `reply`; with the [buildit plugin](#questions-and-approvals-in-builditsocial-plugin), its questions, approvals and [tool approvals](#tool-approvals-in-builditsocial) come to you there as cards, and you can [assign it work items](#work-items-for-your-agent), which it can [hand to another of your sessions](#handing-work-to-another-session) with your tap.
7
+ **Status:** 0.10.0, on npm as [`@kammcs/buildit-mcp`](https://www.npmjs.com/package/@kammcs/buildit-mcp). Built on the agent API's v1 contract: items and comments by default (15 tools), and planning, pages, chat, admin and destructive changes when you turn them on (43 tools in all). In [channel mode](#talk-to-claude-code-from-builditsocial) it also brings your messages to your agent in buildIt.Social into a Claude Code session, which answers with `reply`; with the [buildit plugin](#questions-and-approvals-in-builditsocial-plugin), its questions, approvals and [tool approvals](#tool-approvals-in-builditsocial) come to you there as cards, and you can [assign it work items](#work-items-for-your-agent), which it can [hand to another of your sessions](#handing-work-to-another-session) with your tap. [Files](#files-attachments-in-and-out) go both ways with no extra steps: your attachments reach Claude as local paths, and `reply` posts files.
8
8
 
9
9
  - [How it works](docs/design.md)
10
10
  - [Security policy](SECURITY.md)
@@ -248,7 +248,7 @@ It works only with the **Claude Code CLI** (not Claude Desktop), because it uses
248
248
 
249
249
  ### 1. Install or upgrade
250
250
 
251
- Nothing to install by hand: `npx -y @kammcs/buildit-mcp@latest` downloads the newest release when it runs, and again whenever a new one ships. Check the version with `npx -y @kammcs/buildit-mcp@latest --version`; channel mode needs 0.4.0 or newer, the [plugin](#questions-and-approvals-in-builditsocial-plugin) 0.5.0, [work items for your agent](#work-items-for-your-agent) 0.6.0, [tool approvals](#tool-approvals-in-builditsocial) 0.7.0, and [handoffs](#handing-work-to-another-session) 0.8.0.
251
+ Nothing to install by hand: `npx -y @kammcs/buildit-mcp@latest` downloads the newest release when it runs, and again whenever a new one ships. Check the version with `npx -y @kammcs/buildit-mcp@latest --version`; channel mode needs 0.4.0 or newer, the [plugin](#questions-and-approvals-in-builditsocial-plugin) 0.5.0, [work items for your agent](#work-items-for-your-agent) 0.6.0, [tool approvals](#tool-approvals-in-builditsocial) 0.7.0, [handoffs](#handing-work-to-another-session) 0.8.0, and [files](#files-attachments-in-and-out) 0.9.0.
252
252
 
253
253
  > **Until 0.4.0 is on npm**, `@latest` is an older release without channel mode, so use a local build: `git clone https://github.com/kammcs/buildit-mcp.git`, then `npm ci && npm run build` in it, and use `node /path/to/buildit-mcp/dist/index.js` wherever the steps below say `npx -y @kammcs/buildit-mcp@latest`. `connect` run that way prints the matching `claude mcp add` line.
254
254
 
@@ -350,11 +350,42 @@ With 0.8.0 and a buildIt.Social server with agent API 1.9.0, a session that can'
350
350
  - A session working on a subtask can't hand part of it on (subtasks have no children): it asks you instead.
351
351
  - On a server older than agent API 1.9.0 the three tools aren't listed (or say plainly that the server is too old), `needs` is refused with an explanation, and the rest works as before.
352
352
 
353
+ ### Files: attachments in and out
354
+
355
+ With 0.9.0 and a buildIt.Social server with agent API 1.11.0, files work as in a standard Claude Code session, with no extra steps either way. Drop a file into your conversation with the agent, and Claude gets it. Claude shares a render or a log, and it's posted in the thread.
356
+
357
+ - **Scopes.** A session needs `files:read` to receive files and `files:write` to share them. Both are ticked on the approval page, and you change them in Settings → Agents. They're for sessions only, never personal access tokens. Without one, Claude is told what to ask you for.
358
+ - **Attachments come with the message.** When your message has files (in your direct message, a mention or reply in an item's thread, or a message you forwarded), buildit-mcp downloads them before Claude sees the message.
359
+ - **What Claude sees:** the message lists each file's name, type, size and local path, inside an `untrusted_content` block that says whose files they are.
360
+ - **Reading them:** Claude reads them from there (Read for an image or a PDF, `ffmpeg` for a sound, any tool that takes a path).
361
+ - **Forwarded files** are named as their original author's.
362
+ - The download link lasts two minutes and is used once. It's never shown to Claude, logged or saved.
363
+ - **The automatic limits.** Up to 100 MiB per file and 250 MiB per message, within the session's daily budget (2 GB of downloads, 1 GB of uploads). Each message waits at most a minute for its files. Anything over is listed with why, and Claude fetches it with `get_attachment` when it needs it.
364
+ - **Where they're saved.** In `.claude/buildit-attachments/<session>/<message>/` in the project, so Claude Code reads them without asking.
365
+ - The folder holds a `.gitignore` of `*`, so nothing in it is committed. If the project can't be written, the files go to the temp folder instead.
366
+ - Names are cleaned (no path separators, `..`, control or bidi characters, or reserved Windows names), files are never executable, and each is marked as downloaded from the internet.
367
+ - **Cleanup:** message folders go after 7 days (the oldest first above 2 GiB), the session's folder when it ends, and the project's attachments at `disconnect`.
368
+ - **`get_attachment`** (`message_id`, `file_id`) saves one file of a message in the session's threads and returns its path. It's for a file that wasn't downloaded by itself, one the cleanup removed, and colleagues' files in an item thread. Those are listed with their ids, never downloaded by themselves.
369
+ - **Sharing: `reply` with `files`.** Claude passes up to 10 local paths, and they're posted at once in the same thread, with the text (the images and videos with the text, each other file in a message of its own). Nobody taps anything.
370
+ - **Checks first.** Before anything is uploaded, every file is checked:
371
+ - it must be inside the project folder or the temp folder;
372
+ - it must not be inside a credentials folder (`~/.ssh`, `~/.aws`, `~/.gnupg`, gcloud, kube, the Docker login, browser profiles);
373
+ - it must not have a secret store's name (`.env*`, `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.kdbx`, `id_rsa*`, `id_ed25519*`, `id_ecdsa*`, `.npmrc`, `.netrc`, `.pgpass`);
374
+ - it must not be a program or an installer;
375
+ - it must be within 250 MiB for a video, 100 MiB for anything else;
376
+ - a text file must not hold anything that looks like a credential. The whole file is scanned with the tool approvals' rules, and the error names the lines.
377
+ - **All or nothing:** one refused file sends nothing, and the error says why, so Claude fixes it and sends again.
378
+ - **Location** is removed from photos and videos before upload, losslessly, into a copy: the original is never touched. buildIt.Social checks again: it refuses a photo that still carries a location, and a text file whose first MiB looks like it holds a credential.
379
+ - **Videos get a poster and their length** when `ffprobe` and `ffmpeg` are installed (on the PATH): a small JPEG frame (at most 320 px and 64 KiB, no metadata) and the duration, shown in the app before anyone plays it. Without them the video is shared just the same, with no poster.
380
+ - **The only approval is Claude Code's own.** There's no card for files. If you haven't allowed buildit's tools in Claude Code, it asks about the `reply` call as about any tool, and with the plugin that's a [tool approval card](#tool-approvals-in-builditsocial). If you have allowed them (or run in auto or bypass mode), nothing asks. Shared files go only to the thread the session works in, read by exactly who reads it: you alone in the direct message, the project channel's members in an item's thread.
381
+ - **What isn't caught.** Binary files (archives, Office documents, images) aren't scanned, so a secret inside a zip passes. Claude is told to share only what you asked for or what its work needs, and never credentials, keys, `.env` files or private files.
382
+ - On a server older than agent API 1.11.0, nothing downloads, `get_attachment` isn't listed, and `reply` takes text only.
383
+
353
384
  ### Questions and approvals in buildIt.Social (plugin)
354
385
 
355
386
  The **buildit plugin** for Claude Code (since 0.5.0; tool approvals since 0.7.0) adds what the bare channel can't do, so you can work with the session from your phone as well as from the terminal:
356
387
 
357
- - **Questions as cards.** When Claude asks you something (its `AskUserQuestion` tool), the question appears in your agent's conversation in buildIt.Social as a card, instead of in the terminal: one card per question: the question in full, a list of its choices with their details (several choices where Claude allows them), and a field to type your own answer instead. Claude gets all the answers together once you have answered every card. Your answer goes back to Claude, and the terminal doesn't ask. Claude can also ask you with the `ask` tool while it works on a message from the app.
388
+ - **Questions as cards.** When Claude asks you something (its `AskUserQuestion` tool), the questions appear in your agent's conversation in buildIt.Social as one card (0.10.0), instead of in the terminal: for each question, the question in full, a list of its choices with their details (several choices where Claude allows them), and a field to type your own answer instead. The app shows them one at a time, then a review page and Send (a single question sends on its answer); every question needs an answer. Your answers go back to Claude together, and the terminal doesn't ask. In the direct message only you see your answers; in a work item's thread, everyone in the thread sees them once you send them (only you can answer). Claude can also ask you with the `ask` tool while it works on a message from the app.
358
389
  - **Approvals as cards.** A destructive or configuration change (a `propose_*` tool) is posted as a card with **Apply** and **Cancel**. buildIt.Social words the card from its own preview and applies the change itself when you tap Apply, as you through your agent; an agent session can never apply a change itself (`apply_plan` answers `plan_card_required`), so only your tap applies it. Claude learns the outcome (applied, cancelled, not applied because the items changed, failed, expired after 60 minutes, or unknown, when buildIt.Social couldn't confirm it, and then Claude checks the items) as a channel message.
359
390
  - **Tool approvals as cards** (0.7.0). When Claude Code would ask you whether a tool may run (a command, a file edit, another tool), it asks in buildIt.Social too, and the first answer wins: see [Tool approvals in buildIt.Social](#tool-approvals-in-builditsocial).
360
391
  - **"<agent> is writing…"** shows in the thread while Claude works on your message, and stops when it answers, asks, posts an approval, or ends its turn.
@@ -416,7 +447,7 @@ Tested with Claude Code 2.1.312.
416
447
 
417
448
  #### Try it from a checkout
418
449
 
419
- Until 0.7.0 is on npm, the plugin's server (`npx -y @kammcs/buildit-mcp@0.8.0 --channel`) can't be downloaded. A checkout can make a local plugin marketplace whose buildit plugin runs the checkout's own build:
450
+ Until 0.7.0 is on npm, the plugin's server (`npx -y @kammcs/buildit-mcp@0.10.0 --channel`) can't be downloaded. A checkout can make a local plugin marketplace whose buildit plugin runs the checkout's own build:
420
451
 
421
452
  ```sh
422
453
  git clone https://github.com/kammcs/buildit-mcp.git
@@ -444,7 +475,7 @@ claude --dangerously-load-development-channels plugin:buildit@buildit-dev
444
475
  - `--plugin-dir` alone doesn't do: it loads the plugin's hooks and server, but Claude Code registers a plugin's channel only for an installed plugin, so messages from buildIt.Social wouldn't arrive.
445
476
  - Run `npm run dev-marketplace` again after rebuilding or pulling, then `claude plugin marketplace update buildit-dev` and `claude plugin update buildit@buildit-dev`, so Claude Code takes the new copy; restart Claude Code. `claude plugin validate .dev-marketplace` checks it.
446
477
 
447
- On Windows, Claude Code starts the plugin's `npx` itself; if `/mcp` shows the plugin's server as failed, check that `npx -y @kammcs/buildit-mcp@0.8.0 --version` works in a terminal (Node.js 20 or newer on `PATH`).
478
+ On Windows, Claude Code starts the plugin's `npx` itself; if `/mcp` shows the plugin's server as failed, check that `npx -y @kammcs/buildit-mcp@0.10.0 --version` works in a terminal (Node.js 20 or newer on `PATH`).
448
479
 
449
480
  ### Where the token is kept
450
481
 
@@ -523,7 +554,8 @@ docker run -i --rm -e BUILDIT_HTTP=false -e BUILDIT_TOKEN ghcr.io/kammcs/buildit
523
554
  - **Destructive and admin changes are previewed and need your confirmation** ([above](#preview-then-confirm)), and their toolsets are off unless you turn them on. Read the preview before you say yes: it is what will happen.
524
555
  - **Chat is read only**, and never reaches direct messages. The one exception is channel mode (`reply`, `ask`'s question cards and the approval cards), which writes only in your agent's own conversation with you. Only you can answer its cards; an answer is passed to Claude as your words inside an `untrusted_content` block, and an approval card is applied by buildIt.Social on your tap, never by the session.
525
556
  - **Channel mode passes on only your own messages**, because whoever can write into a Claude Code session can steer it. A session token reaches only the projects you approved, never more than you can, and only your agent's conversation with you; revoke it in the app when you no longer need it.
526
- - **Logs** are JSON on stderr and never contain tokens or content.
557
+ - **Files in channel mode** ([above](#files-attachments-in-and-out)) are data: an attachment's content never directs Claude, and the server says so. Download links are never shown, logged or saved. Shared files are checked first (roots, credentials folders, secret-store names, programs, sizes, a credential scan of text files), stripped of location, and posted only in the session's own threads.
558
+ - **Logs** are JSON on stderr and never contain tokens, presigned URLs' signatures or content.
527
559
 
528
560
  ### Hardening
529
561
 
@@ -2,12 +2,12 @@
2
2
  * The agent API's operations, scopes and error codes, as the contract declares them.
3
3
  *
4
4
  * GENERATED by scripts/generate.ts from openapi/openapi.json (agent API
5
- * 1.9.0). Do not edit: change the contract, then run
5
+ * 1.11.0). Do not edit: change the contract, then run
6
6
  * `npm run generate`.
7
7
  */
8
8
  import * as S from './schemas.js';
9
9
  /** The contract's API version. */
10
- export const API_VERSION = '1.9.0';
10
+ export const API_VERSION = '1.11.0';
11
11
  /** Token scopes, in the contract's order. */
12
12
  export const SCOPES = [
13
13
  'projects:read',
@@ -17,6 +17,8 @@ export const SCOPES = [
17
17
  'pages:read',
18
18
  'pages:write',
19
19
  'chat:read',
20
+ 'files:read',
21
+ 'files:write',
20
22
  ];
21
23
  /** What each scope directly implies (implications are transitive). */
22
24
  export const SCOPE_IMPLIES = {
@@ -27,6 +29,8 @@ export const SCOPE_IMPLIES = {
27
29
  'pages:read': [],
28
30
  'pages:write': ['pages:read'],
29
31
  'chat:read': [],
32
+ 'files:read': [],
33
+ 'files:write': [],
30
34
  };
31
35
  /** The API's error codes and their HTTP statuses. v1 may add codes. */
32
36
  export const ERROR_STATUS = {
@@ -87,6 +91,21 @@ export const ERROR_STATUS = {
87
91
  handoff_exists: 409,
88
92
  no_target: 409,
89
93
  handoff_closed: 409,
94
+ files_off: 403,
95
+ attachment_not_found: 404,
96
+ file_required: 409,
97
+ not_ready: 409,
98
+ budget_exceeded: 429,
99
+ name_not_allowed: 422,
100
+ too_large: 413,
101
+ blocked_type: 415,
102
+ too_many_pending: 409,
103
+ upload_missing: 409,
104
+ upload_mismatch: 422,
105
+ location_found: 422,
106
+ credential_found: 422,
107
+ upload_used: 409,
108
+ upload_thread_mismatch: 409,
90
109
  };
91
110
  /** Each error code's stable next step, as the contract words it. The API sends it as the error's hint; this copy serves when an older API doesn't. */
92
111
  export const ERROR_HINTS = {
@@ -147,6 +166,21 @@ export const ERROR_HINTS = {
147
166
  handoff_exists: 'Read the existing handoff (details.handoff_id) with get_session_handoff instead.',
148
167
  no_target: 'Ask the person to connect a session for this project, or do the work here.',
149
168
  handoff_closed: 'Read the handoff with get_session_handoff; it needs nothing more from this session.',
169
+ files_off: "Don't retry until files are back on; describe the file in text instead.",
170
+ attachment_not_found: 'Use the message and file ids an event of this session listed.',
171
+ file_required: "Retry with file_id, one of the message's files.",
172
+ not_ready: 'Complete the upload first (or wait for the file), then retry.',
173
+ budget_exceeded: "Wait until details.resets_at; don't retry before.",
174
+ name_not_allowed: "Don't share secret stores; share only files the person asked for.",
175
+ too_large: 'Share a smaller file (compress or split it), within details.max_bytes.',
176
+ blocked_type: "Don't share programs or installers.",
177
+ too_many_pending: 'Post the uploads that wait, or let them expire, before starting more.',
178
+ upload_missing: "PUT the bytes to the upload's URL, then complete it again.",
179
+ upload_mismatch: "Start a new upload that declares the file's exact size and type.",
180
+ location_found: "Remove the photo's location metadata, then upload it again.",
181
+ credential_found: "Remove the credential at details.lines, or don't share the file.",
182
+ upload_used: 'Start a new upload to post the file again.',
183
+ upload_thread_mismatch: "Upload the file again with this post's thread_id.",
150
184
  };
151
185
  /** Every scope each plan action needs, all of them (the operations whose scope is 'plan_action' check them). */
152
186
  export const PLAN_SCOPES = {
@@ -532,6 +566,43 @@ export const OPERATIONS = {
532
566
  discovery: false,
533
567
  response: S.SessionHandoffResponseSchema,
534
568
  },
569
+ complete_session_upload: {
570
+ method: 'POST',
571
+ path: '/v1/session/uploads/{id}/complete',
572
+ pathParams: ['id'],
573
+ arrayQueryParams: [],
574
+ scope: 'files:write',
575
+ requiredScopes: ['files:write'],
576
+ hints: { read_only: false, destructive: false, idempotent: true, needs_projects: false },
577
+ errors: [
578
+ 'bad_request',
579
+ 'token_invalid',
580
+ 'token_expired',
581
+ 'token_revoked',
582
+ 'token_suspended',
583
+ 'agent_access_off',
584
+ 'scope_missing',
585
+ 'forbidden',
586
+ 'not_found',
587
+ 'body_too_large',
588
+ 'validation',
589
+ 'rate_limited',
590
+ 'internal',
591
+ 'unavailable',
592
+ 'session_token_required',
593
+ 'agent_sessions_off',
594
+ 'files_off',
595
+ 'blocked_type',
596
+ 'upload_missing',
597
+ 'upload_mismatch',
598
+ 'location_found',
599
+ 'credential_found',
600
+ ],
601
+ hasBody: true,
602
+ statuses: [200],
603
+ discovery: false,
604
+ response: S.CompleteSessionUploadResponseSchema,
605
+ },
535
606
  complete_sprint: {
536
607
  method: 'POST',
537
608
  path: '/v1/projects/{key}/sprints/{sprint}/complete',
@@ -827,6 +898,84 @@ export const OPERATIONS = {
827
898
  discovery: false,
828
899
  response: S.ReleaseResponseSchema,
829
900
  },
901
+ create_session_attachment_link: {
902
+ method: 'POST',
903
+ path: '/v1/session/attachments/link',
904
+ pathParams: [],
905
+ arrayQueryParams: [],
906
+ scope: 'files:read',
907
+ requiredScopes: ['files:read'],
908
+ hints: { read_only: false, destructive: false, idempotent: false, needs_projects: false },
909
+ errors: [
910
+ 'bad_request',
911
+ 'token_invalid',
912
+ 'token_expired',
913
+ 'token_revoked',
914
+ 'token_suspended',
915
+ 'agent_access_off',
916
+ 'scope_missing',
917
+ 'body_too_large',
918
+ 'validation',
919
+ 'rate_limited',
920
+ 'internal',
921
+ 'unavailable',
922
+ 'session_token_required',
923
+ 'agent_sessions_off',
924
+ 'thread_not_bound',
925
+ 'outside_reach',
926
+ 'files_off',
927
+ 'attachment_not_found',
928
+ 'file_required',
929
+ 'not_ready',
930
+ 'budget_exceeded',
931
+ ],
932
+ hasBody: true,
933
+ statuses: [200],
934
+ discovery: false,
935
+ response: S.CreateSessionAttachmentLinkResponseSchema,
936
+ },
937
+ create_session_upload: {
938
+ method: 'POST',
939
+ path: '/v1/session/uploads',
940
+ pathParams: [],
941
+ arrayQueryParams: [],
942
+ scope: 'files:write',
943
+ requiredScopes: ['files:write'],
944
+ hints: { read_only: false, destructive: false, idempotent: false, needs_projects: false },
945
+ errors: [
946
+ 'bad_request',
947
+ 'token_invalid',
948
+ 'token_expired',
949
+ 'token_revoked',
950
+ 'token_suspended',
951
+ 'agent_access_off',
952
+ 'scope_missing',
953
+ 'forbidden',
954
+ 'archived',
955
+ 'idempotency_conflict',
956
+ 'body_too_large',
957
+ 'validation',
958
+ 'rate_limited',
959
+ 'internal',
960
+ 'unavailable',
961
+ 'session_token_required',
962
+ 'agent_sessions_off',
963
+ 'thread_other_session',
964
+ 'thread_not_bound',
965
+ 'thread_required',
966
+ 'outside_reach',
967
+ 'files_off',
968
+ 'budget_exceeded',
969
+ 'name_not_allowed',
970
+ 'too_large',
971
+ 'blocked_type',
972
+ 'too_many_pending',
973
+ ],
974
+ hasBody: true,
975
+ statuses: [200, 201],
976
+ discovery: false,
977
+ response: S.CreateSessionUploadResponseSchema,
978
+ },
830
979
  create_sprint: {
831
980
  method: 'POST',
832
981
  path: '/v1/projects/{key}/sprints',
@@ -1736,6 +1885,7 @@ export const OPERATIONS = {
1736
1885
  'token_revoked',
1737
1886
  'token_suspended',
1738
1887
  'agent_access_off',
1888
+ 'scope_missing',
1739
1889
  'forbidden',
1740
1890
  'archived',
1741
1891
  'not_found',
@@ -1752,6 +1902,10 @@ export const OPERATIONS = {
1752
1902
  'thread_not_bound',
1753
1903
  'thread_required',
1754
1904
  'outside_reach',
1905
+ 'files_off',
1906
+ 'not_ready',
1907
+ 'upload_used',
1908
+ 'upload_thread_mismatch',
1755
1909
  ],
1756
1910
  hasBody: true,
1757
1911
  statuses: [200, 201],