pipebrain-mcp 0.59.3 → 0.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/dist/main.js +7 -493
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # pipebrain-mcp
2
2
 
3
3
  The [Pipebrain](https://pipebrain.dev) MCP server: issues, requirements, decision records,
4
- conventions, prompts, content drafts and deliverables, assets, milestones, metadata-only
5
- secrets, and more of the platform's modules, exposed to Claude Code and Claude Desktop
4
+ conventions, content drafts and deliverables, milestones, metadata-only secrets,
5
+ and more of the platform's modules, exposed to Claude Code and Claude Desktop
6
6
  over stdio.
7
7
 
8
8
  This package is the **server only**. The command line tool is a separate package,
package/dist/main.js CHANGED
@@ -365,8 +365,8 @@ import { join } from "node:path";
365
365
  // ../../libs/agent-shared/dist/agent-config-manifest.js
366
366
  var AGENT_CONFIG_ENTRIES = [
367
367
  { target: "agents/blind-spot-pass.md", sha256: "564751a751f7896e89c67e0d20788aff873e599766a3c30360073ba74e4c6099" },
368
- { target: "agents/code-verifier.md", sha256: "fa2035d4df949fc002b45db228b4d48dcd479c9959b902d6332cddb3348350aa" },
369
- { target: "agents/heavy-implementer.md", sha256: "7d3af78d4241aaa67c283db245dd4065af6e8f55efce54c2f8623c1f83879830" },
368
+ { target: "agents/code-verifier.md", sha256: "64adc28c68cf1e95d50b1ed31e6d8671ac685f9a12055bf5eff15a1d3de32dba" },
369
+ { target: "agents/heavy-implementer.md", sha256: "ab758dc7fe3da32f58b79f1d5869e66382f94aff8a7d704e7a256b6ef9f71c1b" },
370
370
  { target: "agents/issue-header-writer.md", sha256: "185d8c656216bfd755f23391761f172d80e23b0d8a10d58acea0110df91d5c84" },
371
371
  { target: "agents/spec-reviewer.md", sha256: "a46dc637006d1f810081046c57edcd731406727810ccc5e0b1c7d7b9b98be5ef" },
372
372
  { target: "agents/surgical-editor.md", sha256: "c8b7fe2ec8d76c396c0c698f36b0523be430b31e4b73b902409479a52d42ea5c" },
@@ -384,9 +384,9 @@ var AGENT_CONFIG_ENTRIES = [
384
384
  { target: "skills/capture-correction/SKILL.md", sha256: "43155819d172d2cd32474312df6244cc710f23cc76eeb8c0aa77664bd81dd9ca" },
385
385
  { target: "skills/pipebrain-header-pass/SKILL.md", sha256: "ef163f0530def7ba90b1014a47efb98f86e4ba222c6ab4d4c6bfb549dfed10f1" },
386
386
  { target: "skills/pipebrain-secrets/SKILL.md", sha256: "6fa6e648175a4c7e26d392a4bbe7681c42a0604e027c29ca625ab127bc8a7c0b" },
387
- { target: "skills/pipebrain-work-session/SKILL.md", sha256: "b4316a1e017ac40933d3f51b71ba5f4b3cc2129821c3b77fb886856546da5082" },
387
+ { target: "skills/pipebrain-work-session/SKILL.md", sha256: "474e26ffec6ccf12ac24394402aa73f968225a19653c7f9704e3b60f134241d8" },
388
388
  { target: "skills/pipebrain-writing/SKILL.md", sha256: "c3733974aef5d61ed85ce94b37d34d5bb3a9fa3c487fb7a492e7b89c990758fd" },
389
- { target: "skills/pipebrain/SKILL.md", sha256: "71c287f905af2ed9207d4d2829bbb5b2aa51f5abb486210c78a6a65d4da8f5e2" },
389
+ { target: "skills/pipebrain/SKILL.md", sha256: "193c30f695496020359a17340a85f3b95141dc1d35337b3ab9daf7a7ec7bc015" },
390
390
  { target: "skills/requirements-altitude/SKILL.md", sha256: "ffe20eb73fbc73e1fd9bfaec5f9759736a4375dce5fedb015754b135fc12f225" }
391
391
  ];
392
392
 
@@ -432,74 +432,6 @@ function agentConfigNotice(status) {
432
432
  return status === "behind" ? `This machine's shared agent configuration is not the one this build ships \u2014 run \`${UPDATE_COMMAND}\` to see what would change and update it.` : null;
433
433
  }
434
434
 
435
- // ../../libs/agent-shared/dist/asset-transfer.js
436
- import { createHash as createHash2 } from "node:crypto";
437
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
438
- import { basename, extname } from "node:path";
439
- var MIME_BY_EXT = {
440
- ".png": "image/png",
441
- ".jpg": "image/jpeg",
442
- ".jpeg": "image/jpeg",
443
- ".gif": "image/gif",
444
- ".webp": "image/webp",
445
- ".svg": "image/svg+xml",
446
- ".pdf": "application/pdf",
447
- ".txt": "text/plain",
448
- ".md": "text/markdown",
449
- ".json": "application/json",
450
- ".csv": "text/csv",
451
- ".html": "text/html",
452
- ".mp4": "video/mp4",
453
- ".mov": "video/quicktime",
454
- ".zip": "application/zip"
455
- };
456
- function guessContentType(filename) {
457
- return MIME_BY_EXT[extname(filename).toLowerCase()] ?? "application/octet-stream";
458
- }
459
- async function uploadAssetFromPath(client2, apiBaseUrl, input) {
460
- if (!existsSync2(input.path))
461
- throw new Error(`file not found: ${input.path}`);
462
- const bytes = readFileSync2(input.path);
463
- const filename = basename(input.path);
464
- const contentType = input.contentType ?? guessContentType(filename);
465
- const sha256 = createHash2("sha256").update(bytes).digest("hex");
466
- const { asset, uploadUrl } = await client2.createAsset({
467
- project: input.project,
468
- filename,
469
- contentType,
470
- size: bytes.length,
471
- sha256
472
- });
473
- const base = apiBaseUrl.replace(/\/+$/, "");
474
- const target = uploadUrl.startsWith("http") ? uploadUrl : base + uploadUrl;
475
- const put = await fetch(target, {
476
- method: "PUT",
477
- headers: { "content-type": contentType },
478
- body: bytes
479
- });
480
- if (!put.ok) {
481
- throw new Error(`upload PUT failed (${put.status} ${put.statusText}).`);
482
- }
483
- const verified = await client2.completeAsset(asset.id);
484
- if (verified.status !== "active") {
485
- throw new Error(`verification failed (${verified.status}${verified.rejectReason ? `: ${verified.rejectReason}` : ""}).`);
486
- }
487
- return verified;
488
- }
489
- async function downloadAssetToPath(client2, input) {
490
- const asset = await client2.getAsset(input.asset);
491
- if (asset.status !== "active") {
492
- throw new Error(`asset ${input.asset} is ${asset.status}, not active \u2014 no bytes to download.`);
493
- }
494
- const buf = Buffer.from(await client2.downloadAsset(input.asset));
495
- const got = createHash2("sha256").update(buf).digest("hex");
496
- if (got !== asset.sha256) {
497
- throw new Error(`integrity check failed: downloaded sha256 ${got} != recorded ${asset.sha256}.`);
498
- }
499
- writeFileSync(input.path, buf);
500
- return { asset, path: input.path, bytesWritten: buf.length };
501
- }
502
-
503
435
  // ../../libs/agent-shared/dist/binding.js
504
436
  function apiBindingLabel(apiBaseUrl) {
505
437
  return /\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(:|\/|$)/.test(apiBaseUrl) ? "LOCAL dev" : "production/remote";
@@ -15078,17 +15010,6 @@ var inviteRoleSchema = external_exports.enum(["ADMIN", "CONTRIBUTOR"]);
15078
15010
  var requirementLifecycleSchema = external_exports.enum(["draft", "approved", "amended"]);
15079
15011
  var decisionStatusSchema = external_exports.enum(["proposed", "accepted", "superseded"]);
15080
15012
  var platformSchema = external_exports.enum(["bsky", "x", "reddit", "hn", "blog"]);
15081
- var assetStatusSchema = external_exports.enum(["pending", "active", "rejected"]);
15082
- var assetLinkTargetSchema = external_exports.enum([
15083
- "deliverable_revision",
15084
- "content_draft",
15085
- "issue",
15086
- "requirement",
15087
- "chat_message",
15088
- "run",
15089
- "criterion"
15090
- ]);
15091
- var chatEntityTypeSchema = external_exports.enum(["project", "issue", "requirement", "asset"]);
15092
15013
  var instructionScopeSchema = external_exports.enum([
15093
15014
  "general",
15094
15015
  "requirements",
@@ -15101,8 +15022,7 @@ var instructionScopeSchema = external_exports.enum([
15101
15022
  var notificationEventKindSchema = external_exports.enum([
15102
15023
  "question_asked",
15103
15024
  "work_at_verify",
15104
- "feedback_received",
15105
- "chat_message"
15025
+ "feedback_received"
15106
15026
  ]);
15107
15027
  var NOTIFICATION_EVENT_KINDS = notificationEventKindSchema.options;
15108
15028
 
@@ -15144,9 +15064,6 @@ var SECRET_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
15144
15064
  var secretNameSchema = external_exports.string().regex(SECRET_NAME_RE, {
15145
15065
  message: "secret name must be UPPER_SNAKE_CASE: start with A\u2013Z or _, then only A\u2013Z, 0\u20139, or _ (e.g. API_KEY)"
15146
15066
  }).max(128, { message: "secret name must be at most 128 characters" });
15147
- var sha256Schema = external_exports.string().regex(/^[a-fA-F0-9]{64}$/, {
15148
- message: "expected a hex-encoded SHA-256 (64 hex characters)"
15149
- });
15150
15067
  var metadataSchema = external_exports.object({
15151
15068
  system: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
15152
15069
  client: external_exports.record(external_exports.string(), external_exports.unknown()).default({})
@@ -15160,9 +15077,6 @@ var requirementRefSchema = external_exports.string().min(1, {
15160
15077
  var conventionRefSchema = external_exports.string().min(1, {
15161
15078
  message: "convention reference must not be empty \u2014 use a display id (`CONV-3`) or uuid"
15162
15079
  });
15163
- var promptRefSchema = external_exports.string().min(1, {
15164
- message: "prompt reference must not be empty \u2014 use a display id (`PROMPT-3`) or uuid"
15165
- });
15166
15080
  var decisionRefSchema = external_exports.string().min(1, {
15167
15081
  message: "decision reference must not be empty \u2014 use a display id (`DWB-D7`) or uuid"
15168
15082
  });
@@ -15714,29 +15628,6 @@ var conventionApprovalSchema = external_exports.object({
15714
15628
  supersededId: uuidSchema.nullable(),
15715
15629
  createdAt: external_exports.iso.datetime({ offset: true })
15716
15630
  });
15717
- var promptSchema = external_exports.object({
15718
- id: uuidSchema,
15719
- displayId: external_exports.string().min(1),
15720
- orgId: uuidSchema,
15721
- number: positiveIntSchema,
15722
- projectId: uuidSchema.nullable(),
15723
- createdBy: uuidSchema.nullable(),
15724
- createdAt: external_exports.iso.datetime({ offset: true }),
15725
- updatedAt: external_exports.iso.datetime({ offset: true }),
15726
- deletedAt: external_exports.iso.datetime({ offset: true }).nullable()
15727
- });
15728
- var promptRevisionSchema = external_exports.object({
15729
- id: uuidSchema,
15730
- orgId: uuidSchema,
15731
- promptId: uuidSchema,
15732
- revisionNumber: positiveIntSchema,
15733
- title: external_exports.string().min(1),
15734
- body: markdownSchema,
15735
- note: external_exports.string().nullable(),
15736
- createdBy: uuidSchema.nullable(),
15737
- viaTokenId: uuidSchema.nullable(),
15738
- createdAt: external_exports.iso.datetime({ offset: true })
15739
- });
15740
15631
  var issueRequirementLinkSchema = external_exports.object({
15741
15632
  id: uuidSchema,
15742
15633
  orgId: uuidSchema,
@@ -15828,96 +15719,6 @@ var issueDeliverableLinkSchema = external_exports.object({
15828
15719
  createdAt: external_exports.iso.datetime({ offset: true }),
15829
15720
  deletedAt: external_exports.iso.datetime({ offset: true }).nullable()
15830
15721
  });
15831
- var assetSchema = external_exports.object({
15832
- id: uuidSchema,
15833
- // The asset's own identifier (PIPE-362), `ASSET-{n}`: numbered per ORGANISATION, the
15834
- // way prompts are, because an asset may belong to no project and may move between
15835
- // projects — a per-project number would be impossible for one and stale for the other.
15836
- displayId: external_exports.string().min(1),
15837
- orgId: uuidSchema,
15838
- // Null for an ORG-level asset (a chat attachment, PIPE-15): assets were
15839
- // project-scoped until chat introduced org-level files. Project assets keep a
15840
- // uuid; the DB column and every read path (assetToWire) carry the null through.
15841
- projectId: uuidSchema.nullable(),
15842
- filename: external_exports.string().min(1),
15843
- contentType: external_exports.string().min(1),
15844
- size: positiveIntSchema,
15845
- sha256: sha256Schema,
15846
- status: assetStatusSchema,
15847
- // Set only when `status === 'rejected'`: one of object_missing / size_mismatch /
15848
- // digest_mismatch / too_large.
15849
- rejectReason: external_exports.string().nullable(),
15850
- // Whether a server-generated thumbnail object exists for this asset (images only,
15851
- // best-effort at verify). The key itself is internal, like storageKey — the bytes
15852
- // are served through a separate presigned-GET route, never a value field here.
15853
- hasThumbnail: external_exports.boolean(),
15854
- // Count of live (non-soft-deleted) asset_links referencing this asset — derived
15855
- // server-side; 0 when unlinked (and only then is the asset safe to delete).
15856
- linkCount: external_exports.number().int().nonnegative(),
15857
- createdBy: uuidSchema.nullable(),
15858
- createdAt: external_exports.iso.datetime({ offset: true }),
15859
- verifiedAt: external_exports.iso.datetime({ offset: true }).nullable(),
15860
- deletedAt: external_exports.iso.datetime({ offset: true }).nullable()
15861
- });
15862
- var assetLinkSchema = external_exports.object({
15863
- id: uuidSchema,
15864
- orgId: uuidSchema,
15865
- assetId: uuidSchema,
15866
- targetType: assetLinkTargetSchema,
15867
- targetId: uuidSchema,
15868
- createdBy: uuidSchema.nullable(),
15869
- createdAt: external_exports.iso.datetime({ offset: true }),
15870
- deletedAt: external_exports.iso.datetime({ offset: true }).nullable()
15871
- });
15872
- var chatMessageReferenceSchema = external_exports.object({
15873
- id: uuidSchema,
15874
- entityType: chatEntityTypeSchema,
15875
- entityId: uuidSchema,
15876
- revision: positiveIntSchema.nullable(),
15877
- displayId: external_exports.string().nullable(),
15878
- title: external_exports.string().nullable(),
15879
- summary: external_exports.string().nullable().optional(),
15880
- headerStale: external_exports.boolean().optional()
15881
- });
15882
- var chatAttachmentSchema = external_exports.object({
15883
- assetId: uuidSchema,
15884
- linkId: uuidSchema,
15885
- filename: external_exports.string().min(1),
15886
- contentType: external_exports.string().min(1),
15887
- size: positiveIntSchema,
15888
- status: assetStatusSchema,
15889
- hasThumbnail: external_exports.boolean()
15890
- });
15891
- var chatReactionSchema = external_exports.object({
15892
- emoji: external_exports.string().min(1),
15893
- userId: uuidSchema
15894
- });
15895
- var chatMessageSchema = external_exports.object({
15896
- id: uuidSchema,
15897
- seq: positiveIntSchema,
15898
- authorUserId: uuidSchema,
15899
- authorName: external_exports.string(),
15900
- body: markdownSchema,
15901
- createdAt: external_exports.iso.datetime({ offset: true }),
15902
- editedAt: external_exports.iso.datetime({ offset: true }).nullable(),
15903
- references: external_exports.array(chatMessageReferenceSchema),
15904
- attachments: external_exports.array(chatAttachmentSchema),
15905
- reactions: external_exports.array(chatReactionSchema)
15906
- });
15907
- var chatReadStateSchema = external_exports.object({
15908
- userId: uuidSchema,
15909
- userName: external_exports.string(),
15910
- lastReadSeq: nonNegativeIntSchema,
15911
- updatedAt: external_exports.iso.datetime({ offset: true })
15912
- });
15913
- var chatMentionSchema = external_exports.object({
15914
- messageId: uuidSchema,
15915
- seq: positiveIntSchema,
15916
- createdAt: external_exports.iso.datetime({ offset: true }),
15917
- authorUserId: uuidSchema,
15918
- authorName: external_exports.string(),
15919
- excerpt: external_exports.string()
15920
- });
15921
15722
  var statusHistoryEntrySchema = external_exports.object({
15922
15723
  id: uuidSchema,
15923
15724
  orgId: uuidSchema,
@@ -16331,32 +16132,6 @@ var updateConventionInputSchema = external_exports.strictObject({
16331
16132
  var listConventionsFilterSchema = external_exports.strictObject({
16332
16133
  text: external_exports.string().optional()
16333
16134
  });
16334
- var createPromptInputSchema = external_exports.strictObject({
16335
- title: external_exports.string().min(1, { message: "prompt title must not be empty" }),
16336
- body: markdownSchema.min(1, { message: "prompt body must not be empty" }),
16337
- note: external_exports.string().min(1, { message: "note must not be empty \u2014 omit it if there is nothing to record" }).optional(),
16338
- // The OPTIONAL project attachment. Omitted = a prompt that belongs to the organisation
16339
- // and no project, which is the common case for a prompt about how to work.
16340
- project: projectRefSchema.optional()
16341
- });
16342
- var updatePromptInputSchema = external_exports.strictObject({
16343
- prompt: promptRefSchema,
16344
- title: external_exports.string().min(1, { message: "prompt title must not be empty" }).optional(),
16345
- body: markdownSchema.min(1, { message: "prompt body must not be empty" }).optional(),
16346
- note: external_exports.string().min(1, { message: "note must not be empty \u2014 omit it if there is nothing to record" }).optional(),
16347
- // `null` DETACHES the prompt from its project; omitted leaves the attachment alone.
16348
- // Moving the attachment is a record-level change and writes NO revision — the
16349
- // revision chain is the history of the text, and a project move changes no text.
16350
- project: projectRefSchema.nullable().optional()
16351
- }).refine((v) => v.title !== void 0 || v.body !== void 0 || v.project !== void 0, {
16352
- message: "empty edit: supply at least one of `title`, `body`, or `project`"
16353
- });
16354
- var listPromptsFilterSchema = external_exports.strictObject({
16355
- // Filters to prompts attached to this project. Omitted returns EVERY prompt in the
16356
- // organisation, attached or not — the org-wide library is the default view.
16357
- project: projectRefSchema.optional(),
16358
- text: external_exports.string().optional()
16359
- });
16360
16135
  var createDecisionInputSchema = external_exports.strictObject({
16361
16136
  project: projectRefSchema,
16362
16137
  title: external_exports.string().min(1, { message: "decision title must not be empty" }),
@@ -16581,73 +16356,6 @@ var listContentFilterSchema = external_exports.strictObject({
16581
16356
  limit: external_exports.number().int().min(1, { message: "limit must be at least 1" }).max(500, { message: "limit must be at most 500" }).optional(),
16582
16357
  offset: external_exports.number().int().nonnegative().optional()
16583
16358
  });
16584
- var createAssetInputSchema = external_exports.strictObject({
16585
- // Optional since PIPE-15: omit for an ORG-level asset (a chat attachment, stored
16586
- // under `staging/org/{orgId}/…`). A project ref scopes the asset to that project.
16587
- project: projectRefSchema.optional(),
16588
- filename: external_exports.string().min(1, { message: "filename must not be empty" }),
16589
- contentType: external_exports.string().min(1, { message: "content type must not be empty" }),
16590
- size: positiveIntSchema,
16591
- sha256: sha256Schema
16592
- });
16593
- var uploadAssetInputSchema = external_exports.strictObject({
16594
- // Optional since PIPE-15: omit to upload an ORG-level asset (not scoped to any
16595
- // project). A project ref scopes the upload to that project.
16596
- project: projectRefSchema.optional(),
16597
- path: external_exports.string().min(1, { message: "path must not be empty \u2014 give the local file to upload" }),
16598
- contentType: external_exports.string().min(1, { message: "content type must not be empty" }).optional()
16599
- });
16600
- var downloadAssetInputSchema = external_exports.strictObject({
16601
- asset: uuidSchema,
16602
- path: external_exports.string().min(1, { message: "path must not be empty \u2014 give the local file to write" })
16603
- });
16604
- var linkAssetInputSchema = external_exports.strictObject({
16605
- asset: external_exports.string().min(1, { message: "asset reference must not be empty" }),
16606
- targetType: external_exports.enum(["deliverable_revision", "content_draft"]),
16607
- targetId: uuidSchema
16608
- });
16609
- var unlinkAssetInputSchema = external_exports.strictObject({
16610
- linkId: uuidSchema
16611
- });
16612
- var assetCategorySchema = external_exports.enum(["image", "video", "document"]);
16613
- var assetSortSchema = external_exports.enum(["date", "size"]);
16614
- var sortDirSchema = external_exports.enum(["asc", "desc"]);
16615
- var listAssetsFilterSchema = external_exports.strictObject({
16616
- project: projectRefSchema.optional(),
16617
- status: external_exports.array(assetStatusSchema).optional(),
16618
- category: assetCategorySchema.optional(),
16619
- sort: assetSortSchema.optional(),
16620
- dir: sortDirSchema.optional(),
16621
- text: external_exports.string().optional(),
16622
- limit: external_exports.number().int().min(1, { message: "limit must be at least 1" }).max(500, { message: "limit must be at most 500" }).optional(),
16623
- offset: external_exports.number().int().nonnegative().optional()
16624
- });
16625
- var createChatMessageReferenceInputSchema = external_exports.strictObject({
16626
- entityType: chatEntityTypeSchema,
16627
- entityId: uuidSchema,
16628
- // → requirement_revisions.revision_number, an `integer` column (PIPE-149).
16629
- revision: int4Schema.optional()
16630
- });
16631
- var createChatMessageInputSchema = external_exports.strictObject({
16632
- body: external_exports.string().min(1, { message: "message body must not be empty" }).max(8e3, { message: "message body must be at most 8000 characters" }),
16633
- references: external_exports.array(createChatMessageReferenceInputSchema).max(20).optional(),
16634
- assetIds: external_exports.array(uuidSchema).max(10).optional()
16635
- });
16636
- var updateChatMessageInputSchema = external_exports.strictObject({
16637
- body: external_exports.string().min(1, { message: "message body must not be empty" }).max(8e3, { message: "message body must be at most 8000 characters" })
16638
- });
16639
- var addChatReactionInputSchema = external_exports.strictObject({
16640
- emoji: external_exports.string().min(1, { message: "emoji must not be empty" }).max(32, { message: "emoji must be at most 32 characters" })
16641
- });
16642
- var advanceChatReadInputSchema = external_exports.strictObject({
16643
- lastReadSeq: nonNegativeIntSchema
16644
- });
16645
- var listChatMessagesFilterSchema = external_exports.strictObject({
16646
- before: positiveIntSchema.optional(),
16647
- after: positiveIntSchema.optional(),
16648
- limit: external_exports.number().int().min(1, { message: "limit must be at least 1" }).max(200, { message: "limit must be at most 200" }).optional(),
16649
- project: projectRefSchema.optional()
16650
- });
16651
16359
  var setOrgInstructionInputSchema = external_exports.strictObject({
16652
16360
  scope: instructionScopeSchema,
16653
16361
  body: external_exports.string().min(1, { message: "instruction body must not be empty \u2014 clear the scope instead" }).max(4e3, { message: "instruction body must be at most 4000 characters" })
@@ -17129,44 +16837,6 @@ var ApiClient = class _ApiClient {
17129
16837
  body: fields
17130
16838
  });
17131
16839
  }
17132
- // --- prompts (PIPE-196) ----------------------------------------------------
17133
- //
17134
- // FOUR methods, and the absence of a fifth is the design here too: there is deliberately
17135
- // NO `deletePrompt`, and there must not be one. Nothing removes a prompt on any surface
17136
- // — an edit APPENDS a revision, so the text a prompt used to carry stays readable, and a
17137
- // prompt nobody runs any more is one whose newest revision says so. There is no route
17138
- // for such a method to call.
17139
- /**
17140
- * The whole organization's library, filtered by `project` and/or `text`.
17141
- *
17142
- * `requestList`, like every other list on this client, and NOT {@link listConventions}'s
17143
- * named object: the convention response is a bespoke envelope because it carries the
17144
- * delivered count and the threshold that warns about it beside the list — every approved
17145
- * convention rides along on every work-item read. A prompt is delivered to nobody
17146
- * automatically, so there is no second number to carry and the plain §9 `{ items }`
17147
- * envelope is the whole shape. Going through `requestList` is what turns a proxy's
17148
- * malformed 2xx into a typed `invalid_response` here rather than an opaque TypeError at
17149
- * whichever caller first maps the result.
17150
- */
17151
- listPrompts(filter = {}) {
17152
- return this.requestList("GET", "/api/v1/prompts", { query: filter });
17153
- }
17154
- getPrompt(ref) {
17155
- return this.request("GET", `/api/v1/prompts/${enc(ref)}`);
17156
- }
17157
- createPrompt(input) {
17158
- return this.request("POST", "/api/v1/prompts", { body: input });
17159
- }
17160
- /**
17161
- * `title`/`body` APPEND a revision; `note` records why. Supplying none of the three
17162
- * editable fields is an empty edit, refused by the API (400) — a note alone amends
17163
- * nothing.
17164
- */
17165
- updatePrompt(ref, fields) {
17166
- return this.request("PATCH", `/api/v1/prompts/${enc(ref)}`, {
17167
- body: fields
17168
- });
17169
- }
17170
16840
  // --- decision records (PIPE-84) --------------------------------------------
17171
16841
  //
17172
16842
  // Five routes, no DELETE: PIPE-73 made four record kinds deletable and this epic
@@ -17236,107 +16906,6 @@ var ApiClient = class _ApiClient {
17236
16906
  const { contentRef, platform } = splitDeliverableRef(deliverableRef);
17237
16907
  return this.request("POST", `/api/v1/content/${enc(contentRef)}/deliverables/${enc(platform)}/promote`, { body: input });
17238
16908
  }
17239
- // --- assets ----------------------------------------------------------------
17240
- createAsset(input) {
17241
- return this.request("POST", "/api/v1/assets", { body: input });
17242
- }
17243
- completeAsset(id) {
17244
- return this.request("POST", `/api/v1/assets/${enc(id)}/complete`);
17245
- }
17246
- listAssets(filter = {}) {
17247
- return this.requestList("GET", "/api/v1/assets", { query: filter });
17248
- }
17249
- getAsset(id) {
17250
- return this.request("GET", `/api/v1/assets/${enc(id)}`);
17251
- }
17252
- /**
17253
- * The presigned-GET download route (reveal plane) — navigate/fetch with auth; server
17254
- * 302s to S3. Prefixed with `baseUrl` (PIPE-180): relative under the web's
17255
- * same-origin '' base, absolute when the client targets a separate API origin.
17256
- */
17257
- assetDownloadPath(id) {
17258
- return `${this.baseUrl}/api/v1/assets/${enc(id)}/download`;
17259
- }
17260
- /**
17261
- * Fetches an active asset's raw bytes via the download route, following the 302 to
17262
- * the presigned GET (a cross-origin redirect drops the auth header, so S3 gets a
17263
- * clean presigned request). Returns the bytes for a caller to write to a file — the
17264
- * MCP `download_asset` tool and the CLI write to a local path and surface metadata
17265
- * only, so bytes never cross a tool boundary. `active` assets only (409 otherwise).
17266
- */
17267
- async downloadAsset(id) {
17268
- let response;
17269
- try {
17270
- response = await this.fetchImpl(this.buildUrl(`/api/v1/assets/${enc(id)}/download`, void 0), {
17271
- method: "GET",
17272
- headers: this.authHeaders(),
17273
- redirect: "follow",
17274
- signal: AbortSignal.timeout(this.timeoutMs)
17275
- });
17276
- } catch (err) {
17277
- throw toTransportError(err, this.timeoutMs);
17278
- }
17279
- if (!response.ok) {
17280
- const rawText = await response.text();
17281
- throw toApiError(response.status, rawText.length === 0 ? void 0 : safeJsonParse(rawText), rawText);
17282
- }
17283
- return response.arrayBuffer();
17284
- }
17285
- /**
17286
- * The presigned-GET thumbnail route (reveal plane) — an `<img src>` follows the 302;
17287
- * 404 ⇒ no thumbnail. Prefixed with `baseUrl` like {@link assetDownloadPath}.
17288
- */
17289
- assetThumbnailPath(id) {
17290
- return `${this.baseUrl}/api/v1/assets/${enc(id)}/thumbnail`;
17291
- }
17292
- /** Soft-delete an asset — 409 if it still has live references (delete is web/CLI only). */
17293
- deleteAsset(id) {
17294
- return this.request("DELETE", `/api/v1/assets/${enc(id)}`);
17295
- }
17296
- /** The live references TO an asset, resolved to display labels (the asset-detail panel). */
17297
- listAssetLinks(id) {
17298
- return this.requestList("GET", `/api/v1/assets/${enc(id)}/links`);
17299
- }
17300
- linkAsset(input) {
17301
- return this.request("POST", "/api/v1/asset-links", { body: input });
17302
- }
17303
- unlinkAsset(linkId) {
17304
- return this.request("DELETE", `/api/v1/asset-links/${enc(linkId)}`);
17305
- }
17306
- // --- chat ------------------------------------------------------------------
17307
- createChatMessage(input) {
17308
- return this.request("POST", "/api/v1/chat/messages", { body: input });
17309
- }
17310
- /** A page of messages (newest first) + the stream's latest seq. `before`/`after` are exclusive seq bounds. */
17311
- listChatMessages(filter = {}) {
17312
- return this.request("GET", "/api/v1/chat/messages", { query: filter });
17313
- }
17314
- updateChatMessage(id, input) {
17315
- return this.request("PATCH", `/api/v1/chat/messages/${enc(id)}`, { body: input });
17316
- }
17317
- deleteChatMessage(id) {
17318
- return this.request("DELETE", `/api/v1/chat/messages/${enc(id)}`);
17319
- }
17320
- addChatReaction(id, input) {
17321
- return this.request("POST", `/api/v1/chat/messages/${enc(id)}/reactions`, {
17322
- body: input
17323
- });
17324
- }
17325
- removeChatReaction(id, emoji3) {
17326
- return this.request("DELETE", `/api/v1/chat/messages/${enc(id)}/reactions/${enc(emoji3)}`);
17327
- }
17328
- /** Advance the caller's read pointer (server clamps it monotonically). */
17329
- advanceChatRead(input) {
17330
- return this.request("PUT", "/api/v1/chat/read", { body: input });
17331
- }
17332
- /** Every member's read pointer + the stream's latest seq (receipts + unread badge). */
17333
- getChatRead() {
17334
- return this.request("GET", "/api/v1/chat/read");
17335
- }
17336
- /** The live chat messages that mention an entity (backlinks), newest first. */
17337
- getEntityMentions(entityType, entityId) {
17338
- return this.requestList("GET", `/api/v1/entities/${enc(entityType)}/${enc(entityId)}/mentions`);
17339
- }
17340
16909
  // --- projects --------------------------------------------------------------
17341
16910
  createProject(input) {
17342
16911
  return this.request("POST", "/api/v1/projects", { body: input });
@@ -17842,7 +17411,6 @@ function createMcpServer(baseClient, apiBaseUrl, orgInstructions2 = /* @__PURE__
17842
17411
  return createMcpServerWithRegistry(baseClient, apiBaseUrl, orgInstructions2, opts).server;
17843
17412
  }
17844
17413
  function createMcpServerWithRegistry(baseClient, apiBaseUrl, orgInstructions2 = /* @__PURE__ */ new Map(), opts = {}) {
17845
- const surface = opts.surface ?? "local";
17846
17414
  const registry2 = [];
17847
17415
  const scope = new AsyncLocalStorage();
17848
17416
  function client2() {
@@ -18342,33 +17910,6 @@ function createMcpServerWithRegistry(baseClient, apiBaseUrl, orgInstructions2 =
18342
17910
  note: external_exports.string().min(1).optional()
18343
17911
  }
18344
17912
  }, ({ convention, ...fields }) => run(() => client2().updateConvention(convention, fields)));
18345
- registerStrict("list_prompts", {
18346
- description: "List the organization\u2019s prompt library (`PROMPT-{n}`): display id, title, current text, latest revision and any attached project. With no filter this returns the whole library. `project` narrows to the ones attached there \u2014 an attachment says what a prompt is about, not who may run it. `text` matches title and body.",
18347
- inputSchema: listPromptsFilterSchema.shape
18348
- }, (args) => run(() => client2().listPrompts(args), GUIDANCE_POINTER));
18349
- registerStrict("get_prompt", {
18350
- description: "Get one prompt by display id (`PROMPT-{n}`) or uuid: its current text, which is the latest revision, plus every earlier one with who saved it, when and why.",
18351
- inputSchema: { prompt: promptRefSchema }
18352
- }, (args) => run(() => client2().getPrompt(args.prompt), GUIDANCE_POINTER));
18353
- registerStrict("create_prompt", {
18354
- description: "Write a prompt: reusable text held by the organization (`PROMPT-{n}`). `body` is the prompt and must not be empty; `title` names it; `note` says why. Optional `project` records what the prompt is about, not who may use it. Nothing approves or deletes a prompt; later wording is a new revision.",
18355
- inputSchema: createPromptInputSchema.shape
18356
- }, (args) => run(() => client2().createPrompt(args)));
18357
- registerStrict("update_prompt", {
18358
- description: "Amend a prompt. `title` and `body` append a new revision \u2014 nothing is edited in place \u2014 and `note` records why. `project` moves the attachment and `project: null` detaches it; neither writes a revision. Naming none of the three is an empty edit (400). See \u201CHow to write here\u201D in the doctrine `get_work_context` returns.",
18359
- // Inline shape (updatePromptInputSchema is a refine, so it has no `.shape`),
18360
- // mirroring that schema's fields — it is the wording this copy follows, `.min(1)`
18361
- // bounds included, so a caller learns a blank body is refused from the advertised
18362
- // schema rather than from a round trip. The ONE rule this shape cannot state is the
18363
- // empty edit, which lives in the schema's `.refine`; the API enforces it.
18364
- inputSchema: {
18365
- prompt: promptRefSchema,
18366
- title: external_exports.string().min(1).optional(),
18367
- body: markdownSchema.min(1).optional(),
18368
- note: external_exports.string().min(1).optional(),
18369
- project: projectRefSchema.nullable().optional()
18370
- }
18371
- }, ({ prompt, ...fields }) => run(() => client2().updatePrompt(prompt, fields)));
18372
17913
  registerStrict("create_decision", {
18373
17914
  description: "Record one decision as a project-scoped record (`KEY-D{n}`): `title` names it, `body` says what was decided and why. It starts `proposed` and is frozen once accepted; changing it then means a new record plus `supersede_decision`. See \u201CA decision record is written once\u201D in the doctrine `get_work_context` returns.",
18374
17915
  inputSchema: createDecisionInputSchema.shape
@@ -18402,7 +17943,7 @@ function createMcpServerWithRegistry(baseClient, apiBaseUrl, orgInstructions2 =
18402
17943
  inputSchema: listContentFilterSchema.shape
18403
17944
  }, (args) => run(() => client2().listContent(args), GUIDANCE_POINTER));
18404
17945
  registerStrict("get_content", {
18405
- description: "Get a content draft by display id (`KEY-C{n}`) or uuid: its revisions, latest or the `revision` you name, plus every deliverable, linked issue and linked asset.",
17946
+ description: "Get a content draft by display id (`KEY-C{n}`) or uuid: its revisions, latest or the `revision` you name, plus every deliverable and linked issue.",
18406
17947
  inputSchema: { content: contentRefSchema, revision: positiveIntSchema.optional() }
18407
17948
  }, (args) => run(() => client2().getContent(args.content, args.revision), GUIDANCE_POINTER));
18408
17949
  registerStrict("create_content", {
@@ -18451,32 +17992,6 @@ function createMcpServerWithRegistry(baseClient, apiBaseUrl, orgInstructions2 =
18451
17992
  ...refusedIssueHeaderFields
18452
17993
  }
18453
17994
  }, ({ deliverable, ...fields }) => run(() => client2().promoteDeliverable(deliverable, fields)));
18454
- registerStrict("list_assets", {
18455
- description: "List project assets, filtered by status (pending/active/rejected), category (image/video/document) and filename text, sorted by date or size. No bytes cross this result.",
18456
- inputSchema: listAssetsFilterSchema.shape
18457
- }, (args) => run(() => client2().listAssets(args), GUIDANCE_POINTER));
18458
- registerStrict("get_asset", {
18459
- description: "Get an asset\u2019s metadata by uuid: filename, contentType, size, sha256, status and linkCount. No bytes and no URL come back; use `download_asset` or `ppb assets download`.",
18460
- inputSchema: { asset: uuidSchema }
18461
- }, (args) => run(() => client2().getAsset(args.asset), GUIDANCE_POINTER));
18462
- if (surface === "local") {
18463
- registerStrict("upload_asset", {
18464
- description: "Upload a local file as a project asset and activate it. Only the `path` crosses the wire \u2014 never base64 or file contents. `contentType` is guessed from the extension when omitted. Returns the asset metadata; `link_asset` then attaches it to a draft or a deliverable revision.",
18465
- inputSchema: uploadAssetInputSchema.shape
18466
- }, (args) => run(() => uploadAssetFromPath(client2(), apiBaseUrl, args)));
18467
- registerStrict("download_asset", {
18468
- description: "Write an ACTIVE asset\u2019s bytes to a local file at `path`, created or overwritten. Addressed by asset uuid. The bytes are checked against the recorded sha256; the result is metadata and the path.",
18469
- inputSchema: downloadAssetInputSchema.shape
18470
- }, (args) => run(() => downloadAssetToPath(client2(), args)));
18471
- }
18472
- registerStrict("link_asset", {
18473
- description: "Reference an active asset from a `deliverable_revision` (a content_deliverable_revision uuid) or a `content_draft` (a content_draft uuid, copied onto later deliverables). A non-active asset or a cross-project link is rejected.",
18474
- inputSchema: linkAssetInputSchema.shape
18475
- }, (args) => run(() => client2().linkAsset(args)));
18476
- registerStrict("unlink_asset", {
18477
- description: "Remove an asset reference by its link id. This drops the reference only; the asset itself is untouched. A link on a chat message is author-only \u2014 anyone else is refused `not_message_author`. Every other target type any member can remove.",
18478
- inputSchema: unlinkAssetInputSchema.shape
18479
- }, (args) => run(() => client2().unlinkAsset(args.linkId)));
18480
17995
  registerStrict("set_secret", {
18481
17996
  description: "Create a secret or add a new version under a project and environment. Do not send a sensitive value here \u2014 it lands in the chat transcript before the server can encrypt it; use `ppb secrets set` from stdin or `--from-file`. `name` is UPPER_SNAKE_CASE, `environment` is a slug (dev/prod). See \u201CA secret value never travels in a tool call\u201D in the doctrine `get_work_context` returns.",
18482
17997
  inputSchema: {
@@ -18616,7 +18131,7 @@ function loadMcpConfig() {
18616
18131
  }
18617
18132
 
18618
18133
  // src/version.ts
18619
- var VERSION = "0.59.3";
18134
+ var VERSION = "0.61.0";
18620
18135
 
18621
18136
  // src/main.ts
18622
18137
  async function scopedClient(base, org) {
@@ -18640,7 +18155,6 @@ var client = await scopedClient(
18640
18155
  var orgInstructions = await fetchOrgInstructionsSafe(client);
18641
18156
  var server = createMcpServer(client, config2.apiUrl, orgInstructions, {
18642
18157
  version: VERSION,
18643
- surface: "local",
18644
18158
  // The writing rules follow the organization the CALL acts in (PIPE-410). Without this,
18645
18159
  // a `get_work_context` naming another organization returns that organization's work,
18646
18160
  // requirements and conventions under THIS one's rules, in one document, with nothing in
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pipebrain-mcp",
3
- "version": "0.59.3",
4
- "description": "Pipebrain MCP server for Claude Code and Claude Desktop — issues, requirements, decision records, conventions, prompts, content, assets, metadata-only secrets, and more of the platform's modules over the Pipebrain API.",
3
+ "version": "0.61.0",
4
+ "description": "Pipebrain MCP server for Claude Code and Claude Desktop — issues, requirements, decision records, conventions, content, metadata-only secrets, and more of the platform's modules over the Pipebrain API.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "main": "./dist/main.js",