pipebrain-mcp 0.21.0 → 0.23.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 (2) hide show
  1. package/dist/main.js +51 -3
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -15252,6 +15252,12 @@ var issueSchema = external_exports.object({
15252
15252
  statusChangedAt: external_exports.iso.datetime({ offset: true }),
15253
15253
  deletedAt: external_exports.iso.datetime({ offset: true }).nullable()
15254
15254
  });
15255
+ var criterionFiledBugSchema = external_exports.object({
15256
+ id: uuidSchema,
15257
+ displayId: external_exports.string().min(1),
15258
+ title: external_exports.string().min(1),
15259
+ status: issueStatusSchema
15260
+ });
15255
15261
  var criterionSchema = external_exports.object({
15256
15262
  id: uuidSchema,
15257
15263
  displayId: external_exports.string().min(1),
@@ -15272,6 +15278,12 @@ var criterionSchema = external_exports.object({
15272
15278
  stateSetBy: uuidSchema.nullable(),
15273
15279
  stateSetAt: external_exports.iso.datetime({ offset: true }).nullable(),
15274
15280
  stateViaTokenId: uuidSchema.nullable(),
15281
+ // Every bug ever filed against this criterion (PIPE-272), oldest first. ALWAYS
15282
+ // present, `[]` when none — a client must never have to tell "no bug was filed"
15283
+ // from "a payload that omits the key". Terminal bugs stay listed: a bug's own
15284
+ // lifecycle says nothing about whether it was FILED, and a row that stopped naming
15285
+ // its bug the moment the bug was finished would start inviting a duplicate.
15286
+ filedBugs: external_exports.array(criterionFiledBugSchema),
15275
15287
  createdAt: external_exports.iso.datetime({ offset: true }),
15276
15288
  updatedAt: external_exports.iso.datetime({ offset: true }),
15277
15289
  deletedAt: external_exports.iso.datetime({ offset: true }).nullable()
@@ -15598,7 +15610,12 @@ var createIssueInputSchema = external_exports.strictObject({
15598
15610
  // Content-deliverable links (Content module) — mirrors requirementLinks; pins
15599
15611
  // each at the deliverable's CURRENT (latest) revision. Promotion sets this.
15600
15612
  deliverableLinks: external_exports.array(deliverableRefSchema).optional(),
15601
- criteria: external_exports.array(criterionInputSchema).optional()
15613
+ criteria: external_exports.array(criterionInputSchema).optional(),
15614
+ // The acceptance criterion this bug was filed against (PIPE-272). Records on the
15615
+ // BUG which row sent someone to file it, so that row can name the bug instead of
15616
+ // offering to file another. Server-refused on any type but `bug`
15617
+ // (`criterion_requires_bug`) and on a criterion outside the caller's org.
15618
+ criterionId: uuidSchema.optional()
15602
15619
  });
15603
15620
  var promoteFeedbackInputSchema = external_exports.strictObject({
15604
15621
  type: external_exports.enum(["epic", "task"]),
@@ -15640,6 +15657,12 @@ var setStatusInputSchema = external_exports.strictObject({
15640
15657
  issue: issueRefSchema,
15641
15658
  status: issueStatusSchema
15642
15659
  });
15660
+ var getWorkContextInputSchema = external_exports.strictObject({
15661
+ issue: issueRefSchema.optional(),
15662
+ project: projectRefSchema.optional()
15663
+ }).refine((v) => v.issue === void 0 !== (v.project === void 0), {
15664
+ message: "pass exactly one of `issue` or `project` \u2014 an issue names its own project, and passing neither names nothing to read"
15665
+ });
15643
15666
  var claimInputSchema = external_exports.strictObject({
15644
15667
  issue: issueRefSchema
15645
15668
  });
@@ -16563,6 +16586,22 @@ var ApiClient = class _ApiClient {
16563
16586
  const query = filter?.mine === true ? { mine: "1" } : void 0;
16564
16587
  return this.requestList("GET", "/api/v1/waiting", { query });
16565
16588
  }
16589
+ // --- the working-context pack ----------------------------------------------
16590
+ /**
16591
+ * Everything a session needs before it starts work, in ONE read (PIPE-86): the
16592
+ * item, the documents that bind it AT THE REVISION IT WAS SPECIFIED AGAINST, the
16593
+ * project's cross-cutting requirements and the release being worked — or, given a
16594
+ * project, the work available to pick up instead.
16595
+ *
16596
+ * ONE method for two routes because they are two forms of one pack, decided by
16597
+ * which of `issue`/`project` is named — exactly one of them, as
16598
+ * `getWorkContextInputSchema` requires. The API assembles the pack and this computes
16599
+ * nothing of its own, so the browser, the command line and the agent read the same
16600
+ * answer.
16601
+ */
16602
+ getWorkContext(input) {
16603
+ return input.issue !== void 0 ? this.request("GET", `/api/v1/issues/${enc(input.issue)}/work-context`) : this.request("GET", `/api/v1/projects/${enc(input.project)}/work-context`);
16604
+ }
16566
16605
  // --- secrets ---------------------------------------------------------------
16567
16606
  // Metadata only: no method here returns a secret VALUE (the reveal plane is a
16568
16607
  // separate surface). Every response type is a `*View` with no `value` field.
@@ -16960,6 +16999,15 @@ Every loose end has one destination, and none of them is prose. Anything you not
16960
16999
  // makes that comparable at a glance.
16961
17000
  run(async () => ({ items: await client2.listWaiting() }))
16962
17001
  ));
17002
+ registerTool("get_work_context", {
17003
+ description: "Everything a session needs before it starts work, in ONE read \u2014 assembled by the API and returned verbatim. Addressed by `issue` OR by `project`, never both and never neither: an issue names its own project, so the pair is refused rather than resolved for you (\xA77). Given an ISSUE: that issue\u2019s full detail \u2014 the same payload `get_issue` returns \u2014 PLUS the BODY TEXT of every requirement it links, AT THE REVISION THE LINK IS PINNED AT. That text is the round trip this removes: `get_issue` names which documents bind the work and at which revision, never what they SAY, so a session that has read the issue still owes one fetch per link \u2014 and the one it skips leaves it building against rules it never read. Comments come CAPPED at the newest `commentLimit`, with `commentCount` \u2014 the issue\u2019s TRUE total \u2014 beside them, so a shortened list reads AS shortened rather than as the whole history; read the issue directly for the rest. Given a PROJECT: `available`, the work a session could START right now. It EXCLUDES finished and abandoned work (`done`, `killed`), work another person has claimed, and anything blocked \u2014 the status guard would refuse to start that, and offering work that cannot be started is offering a refusal. Your OWN claims stay, and so does unscheduled work carrying no milestone. The item form carries no `available`; the project form carries no item. BOTH forms also carry the project half: the release currently being worked (the active milestone) and the project\u2019s cross-cutting requirements WITH their text \u2014 they bind every epic automatically, and each is otherwise a separate call a session can simply forget to make. READ-ONLY \u2014 this claims nothing, moves nothing and writes nothing.",
17004
+ // The WHOLE domain schema rather than its `.shape`: the exactly-one-of rule is a
17005
+ // refinement on the OBJECT, and a raw shape drops it — the SDK validates against
17006
+ // what it is handed, so the shape alone would quietly accept both arguments and
17007
+ // neither. Handing it the schema lets its refusal reach the caller verbatim,
17008
+ // naming the two arguments it refused rather than a reworded stand-in.
17009
+ inputSchema: getWorkContextInputSchema
17010
+ }, (args) => run(() => client2.getWorkContext(args)));
16963
17011
  registerTool("create_milestone", {
16964
17012
  description: "Create a milestone on a project. `token` is the short ref issues point at via their `milestone` field (e.g. `M1`) and is unique per project (a duplicate is rejected); `label` is its display name (e.g. `Feature Verification`). Optional `position` orders it (0-based, defaults to last); optional `active` marks it the current milestone \u2014 AT MOST ONE milestone per project is active, so `active: true` transactionally DEMOTES the previously active one rather than failing. Returns the created milestone (\xA77).",
16965
17013
  inputSchema: {
@@ -17050,7 +17098,7 @@ Every loose end has one destination, and none of them is prose. Anything you not
17050
17098
  inputSchema: { issue: issueRefSchema }
17051
17099
  }, (args) => run(() => client2.getIssue(args.issue)));
17052
17100
  registerTool("create_issue", {
17053
- description: 'Create an issue (epic/task/bug/feedback). Omitted status defaults to triage (still subject to \xA76 guards); omitted environment resolves explicit \u2192 parent\u2019s environment \u2192 project default (prod). Optional parent (self/cycle rejected), priority, milestone, requirement_links (pins each at its approved revision; a target with no approved revision is rejected), deliverable_links (content deliverables like DWB-C3/bsky \u2014 pins each at its current revision; the promotion path), and ordered {text, verification, howTo} criteria (\xA77). A `status` other than `triage` or `killed` REQUIRES `milestone` (PIPE-R10 rule 9): work past triage belongs to a release, and the create is refused (`milestone_required`) without one. Search before you create: `list_issues` takes a `text` filter \u2014 run it on the distinctive nouns first. Sessions do not see each other, so a duplicate is invisible until someone finds both; on a near match, comment or amend the existing record rather than filing again. The bar for filing a bug: file `type: bug` only when the observed behavior breaks an approved requirement or a defined acceptance criterion, and name which one before you file. If you cannot name one, this is not a bug \u2014 code you find unclear, an edge case nobody specified, a performance number nobody set, and anything you would phrase as "this could be better" are opinions about the product, so file each as `type: feedback`, or not at all. The bar exists because a queue holding both real defects and unshared taste has to be read entirely before any of it can be trusted. Link another record by key plus title on first mention; never paste its text into a body \u2014 the source changes, the copy does not, and a stale copy gets built. A decision you need from the operator is filed as a question via `ask_questions`, never written as an "Open questions" heading inside a body \u2014 a heading prompts nobody and records no answer, so a later session cannot tell whether the decision was made. Before assigning any verification mode, establish what this project can drive end to end \u2014 an end-to-end test harness and the command that runs it. A criterion is `auto` when an evaluator can drive the input and read the result against the running system, which includes behavior shown in the interface wherever such a harness exists; the mode follows from what can be driven, not from where the behavior appears. What qualifies a criterion as `auto` is the evaluator\u2019s own run, never the existence of a test the implementer wrote. Mark `manual` only when the verdict needs a person\u2019s judgment; a criterion you cannot describe as drivable is usually worded too vaguely, so reword it against the observable rather than fall back to a person. A `manual` criterion must also carry `howTo` \u2014 one or two sentences, not an essay, saying where to look, what to do, and what counts as passing for whoever checks it by hand. Writing or changing one without it is refused (`how_to_required`); so is supplying it on an `auto` criterion, which a machine checks. Criteria live on epics only: a task cannot carry a criteria list and instead states in its own body what would count as done. Cross-cutting requirements bind every epic automatically and arrive with `get_issue` \u2014 never restate them in a body and never add them to `requirement_links`; an explicit link pins the linked document\u2019s approved revision.',
17101
+ description: 'Create an issue (epic/task/bug/feedback). Omitted status defaults to triage (still subject to \xA76 guards); omitted environment resolves explicit \u2192 parent\u2019s environment \u2192 project default (prod). Optional parent (self/cycle rejected), priority, milestone, requirement_links (pins each at its approved revision; a target with no approved revision is rejected), deliverable_links (content deliverables like DWB-C3/bsky \u2014 pins each at its current revision; the promotion path), and ordered {text, verification, howTo} criteria (\xA77). A `status` other than `triage` or `killed` REQUIRES `milestone` (PIPE-R10 rule 9): work past triage belongs to a release, and the create is refused (`milestone_required`) without one. Search before you create: `list_issues` takes a `text` filter \u2014 run it on the distinctive nouns first. Sessions do not see each other, so a duplicate is invisible until someone finds both; on a near match, comment or amend the existing record rather than filing again. The bar for filing a bug: file `type: bug` only when the observed behavior breaks an approved requirement or a defined acceptance criterion, and name which one before you file. If you cannot name one, this is not a bug \u2014 code you find unclear, an edge case nobody specified, a performance number nobody set, and anything you would phrase as "this could be better" are opinions about the product, so file each as `type: feedback`, or not at all. The bar exists because a queue holding both real defects and unshared taste has to be read entirely before any of it can be trusted. When the criterion you named is an acceptance criterion, pass its uuid as `criterionId` and the bug records which criterion it was filed against \u2014 the criterion then names the bug (it arrives as `filedBugs` on every criteria read) instead of inviting the next reader to file it again. Bugs only: any other type naming a criterion is refused (`criterion_requires_bug`). Link another record by key plus title on first mention; never paste its text into a body \u2014 the source changes, the copy does not, and a stale copy gets built. A decision you need from the operator is filed as a question via `ask_questions`, never written as an "Open questions" heading inside a body \u2014 a heading prompts nobody and records no answer, so a later session cannot tell whether the decision was made. Before assigning any verification mode, establish what this project can drive end to end \u2014 an end-to-end test harness and the command that runs it. A criterion is `auto` when an evaluator can drive the input and read the result against the running system, which includes behavior shown in the interface wherever such a harness exists; the mode follows from what can be driven, not from where the behavior appears. What qualifies a criterion as `auto` is the evaluator\u2019s own run, never the existence of a test the implementer wrote. Mark `manual` only when the verdict needs a person\u2019s judgment; a criterion you cannot describe as drivable is usually worded too vaguely, so reword it against the observable rather than fall back to a person. A `manual` criterion must also carry `howTo` \u2014 one or two sentences, not an essay, saying where to look, what to do, and what counts as passing for whoever checks it by hand. Writing or changing one without it is refused (`how_to_required`); so is supplying it on an `auto` criterion, which a machine checks. Criteria live on epics only: a task cannot carry a criteria list and instead states in its own body what would count as done. Cross-cutting requirements bind every epic automatically and arrive with `get_issue` \u2014 never restate them in a body and never add them to `requirement_links`; an explicit link pins the linked document\u2019s approved revision.',
17054
17102
  inputSchema: createIssueInputSchema.shape
17055
17103
  }, (args) => run(() => client2.createIssue(args)));
17056
17104
  registerTool("promote_feedback", {
@@ -17376,7 +17424,7 @@ function loadMcpConfig() {
17376
17424
  }
17377
17425
 
17378
17426
  // src/version.ts
17379
- var VERSION = "0.21.0";
17427
+ var VERSION = "0.23.0";
17380
17428
 
17381
17429
  // src/main.ts
17382
17430
  var config2 = loadMcpConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipebrain-mcp",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "Pipebrain MCP server for Claude Code and Claude Desktop — issues, requirements, content, assets, and metadata-only secrets over the Pipebrain API.",
5
5
  "type": "module",
6
6
  "license": "MIT",