pipebrain-mcp 0.33.0 → 0.34.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/README.md +1 -1
- package/dist/main.js +15 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ at each launch.
|
|
|
32
32
|
|
|
33
33
|
| Variable | Meaning |
|
|
34
34
|
| --- | --- |
|
|
35
|
-
| `PIPEBRAIN_TOKEN` | Your `pbt_…` API token (Settings → Organization → API tokens).
|
|
35
|
+
| `PIPEBRAIN_TOKEN` | Your `pbt_…` API token (Settings → Organization → API tokens). |
|
|
36
36
|
| `PIPEBRAIN_API_URL` | API base URL, e.g. `https://api.pipebrain.dev`. Required — there is no default, so a session can always tell which environment it is bound to. |
|
|
37
37
|
|
|
38
38
|
Secret VALUES never cross this server: the secrets tools return metadata only, and there
|
package/dist/main.js
CHANGED
|
@@ -476,21 +476,14 @@ function apiBindingLabel(apiBaseUrl) {
|
|
|
476
476
|
var DOCTRINE = "# Pipebrain doctrine\n\nHow an agent works inside Pipebrain. These rules ship with the product and read the same in every organization, because each exists where disagreeing breaks something the product guarantees rather than merely changing house style.\n\nHow your organization *writes* is its own text, edited in Settings, and follows this document under a heading naming each scope.\n\n## Decisions are yours; escalate on consequence\n\nInside an approved requirement you choose the design, the libraries, the structure, and the sequencing. Do not ask, report, or seek ratification for the choice. Escalate on consequence, not uncertainty: a choice that changes what a user sees, costs money, or contradicts an approved requirement is filed as a question with the options you propose; everything else you decide and carry on. A technical choice worth keeping is a decision record, never a paragraph.\n\n## Every loose end has one destination, and none of them is prose\n\nAnything you notice that is not the work in front of you goes to exactly one of three places: a question, when the operator has to choose; a new issue at triage, when it is real work outside this item's scope; or nowhere. Nowhere is the default, and the right outcome whenever knowing the thing would change nothing anyone does. Never open a section called notes, caveats, observations, things to know, or next steps in a body or a comment. Filing is the report: an item recorded and then repeated in prose asks the operator to triage it twice.\n\n## A decision you need is filed as a question, never written into a body\n\nAn open decision belongs in a question on the issue, filed with `ask_questions`, carrying the options you propose. It does not belong in a body \u2014 not under a heading, and not in a field. A decision written into prose prompts nobody and records no answer, so the operator has no place to make it and a later session cannot tell whether it ever was. Retract one your own work has since settled, so nothing asks the operator to decide something nobody waits on.\n\n## Search before you create\n\nLook for the existing record before adding one. A duplicate splits one thing's history across two identifiers, and the split is permanent \u2014 nothing merges them afterward.\n\n## Link by key; never paste another record's text\n\nReference a requirement, a decision, or an issue by its key, with its title on first mention. Never paste its text into a body. The source changes and the copy does not, and the stale copy is what gets built.\n\n## Cross-cutting requirements arrive on their own\n\nThey bind every epic automatically and come back with a work-item read, at their latest approved revision. Never restate them in a body and never add them as explicit requirement links. An explicit link pins a document at an approved revision, which is a different act.\n\n## Verification modes follow what can be driven\n\nBefore assigning a mode, establish what this project can drive end to end: a 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, including behavior shown in an interface wherever such a harness exists. What qualifies it is the evaluator's own run, never the existence of a test the implementer wrote.\n\nMark `manual` only when the verdict needs a person's judgment. A criterion you cannot describe as drivable is usually worded too vaguely: reword it against the observable rather than fall back to a person. A `manual` criterion carries instructions for whoever checks it by hand, written for someone who has not seen the code or the conversation that produced it.\n\nA manual criterion carrying no recorded artifact is the human gate working as designed rather than a coverage gap, so it is neither a finding nor weaker than one carrying evidence.\n\n## The bar for filing a bug\n\nFile a bug only when the observed behavior breaks an approved requirement or a defined acceptance criterion, and name which one before you file. Failing that, it is not a bug: 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 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.\n\n## A decision record is written once\n\nIt states what was decided and why, at the time it was decided, and is not edited as understanding moves. A superseding record replaces it, and the chain of the two is the account of how the thinking changed \u2014 which an edited record destroys. Read the existing records before re-opening a settled question.\n\n## A secret value never travels in a tool call\n\nNo tool here returns one, and that is deliberate rather than an omission to be fixed. Nor should you put one in: a value typed into a tool call is in the transcript before the server can encrypt it, so it is already disclosed and the only remedy left is rotation. Set values with the command-line tool, from a file or on standard input, and inject them at run time rather than reading them into context.\n\n## Setting an instruction replaces the whole body\n\nThere is no partial update. Writing an instruction stores exactly the body you supply and discards everything that was there, so a partial write destroys the rest of the text. The procedure is: read the live value, compose the complete replacement, write it, then read the live value again to confirm what landed.\n\nWhat you are reading now is a snapshot taken when this session started, and so are the tool descriptions. An edit reaches the next session, never this one, so reading the text back after a write shows the pre-edit value. An agent that reports a diff of what it just wrote has read the snapshot instead of the record.\n";
|
|
477
477
|
|
|
478
478
|
// ../../libs/agent-shared/dist/resolve-agent-env.js
|
|
479
|
-
function pick(env,
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
return { value: fromPrimary, source: primary };
|
|
483
|
-
}
|
|
484
|
-
const fromLegacy = env[legacy];
|
|
485
|
-
if (fromLegacy !== void 0 && fromLegacy !== "") {
|
|
486
|
-
return { value: fromLegacy, source: legacy };
|
|
487
|
-
}
|
|
488
|
-
return void 0;
|
|
479
|
+
function pick(env, name) {
|
|
480
|
+
const value = env[name];
|
|
481
|
+
return value !== void 0 && value !== "" ? { value, source: name } : void 0;
|
|
489
482
|
}
|
|
490
483
|
function resolveAgentEnv(env) {
|
|
491
484
|
return {
|
|
492
|
-
apiUrl: pick(env, "PIPEBRAIN_API_URL"
|
|
493
|
-
token: pick(env, "PIPEBRAIN_TOKEN"
|
|
485
|
+
apiUrl: pick(env, "PIPEBRAIN_API_URL"),
|
|
486
|
+
token: pick(env, "PIPEBRAIN_TOKEN")
|
|
494
487
|
};
|
|
495
488
|
}
|
|
496
489
|
|
|
@@ -15087,9 +15080,9 @@ var widgetOriginSchema = external_exports.string().trim().transform((raw) => raw
|
|
|
15087
15080
|
});
|
|
15088
15081
|
var emailSchema = external_exports.email({ message: "enter a valid email address" });
|
|
15089
15082
|
var passwordSchema = external_exports.string().min(8, { message: "password must be at least 8 characters" }).max(128, { message: "password must be at most 128 characters" });
|
|
15090
|
-
var ACCEPTED_TOKEN_PREFIXES = ["pbt_"
|
|
15083
|
+
var ACCEPTED_TOKEN_PREFIXES = ["pbt_"];
|
|
15091
15084
|
var tokenPrefixSchema = external_exports.string().regex(new RegExp(`^(?:${ACCEPTED_TOKEN_PREFIXES.join("|")})[0-9A-Za-z]{4}$`), {
|
|
15092
|
-
message: "token prefix must be `pbt_`
|
|
15085
|
+
message: "token prefix must be `pbt_` followed by 4 base62 characters"
|
|
15093
15086
|
});
|
|
15094
15087
|
var SECRET_NAME_RE = /^[A-Z_][A-Z0-9_]*$/;
|
|
15095
15088
|
var secretNameSchema = external_exports.string().regex(SECRET_NAME_RE, {
|
|
@@ -16996,11 +16989,6 @@ ${body}`);
|
|
|
16996
16989
|
}
|
|
16997
16990
|
|
|
16998
16991
|
// ../../libs/mcp-server/dist/server.js
|
|
16999
|
-
var SUCCESSOR_NOTICE = "NOTICE \u2014 this server is the FINAL release of the `@fvcsolutions/pipeline-mcp` package. The server moved to `pipebrain-mcp` on npmjs.org (public, no registry auth), and the CLI moved to `pipebrain-cli`, which provides the `ppb` command in place of `pipeline`. Re-register through the team bootstrap, or: `claude mcp add pipebrain -s user -e PIPEBRAIN_API_URL=https://api.pipebrain.dev -e 'PIPEBRAIN_TOKEN=${PIPEBRAIN_TOKEN}' -- npx -y pipebrain-mcp@latest`. Tell the operator; this build still works and will not be updated again.\n\n";
|
|
17000
|
-
function successorNotice() {
|
|
17001
|
-
const armed = process.env.PIPELINE_MCP_SUCCESSOR_NOTICE;
|
|
17002
|
-
return armed === void 0 || armed === "" ? "" : SUCCESSOR_NOTICE;
|
|
17003
|
-
}
|
|
17004
16992
|
function machineNotice() {
|
|
17005
16993
|
try {
|
|
17006
16994
|
return agentConfigNotice(agentConfigStatus(agentConfigDir()));
|
|
@@ -17080,7 +17068,7 @@ function createMcpServer(client2, apiBaseUrl, orgInstructions2 = /* @__PURE__ */
|
|
|
17080
17068
|
// rather than passed in, because the fact is about the filesystem this process is
|
|
17081
17069
|
// running on and there is no caller better placed to know it; a read failure
|
|
17082
17070
|
// degrades to silence, since a session must not fail to start over an installer.
|
|
17083
|
-
instructions: composeIndex(
|
|
17071
|
+
instructions: composeIndex(banner, machineNotice())
|
|
17084
17072
|
});
|
|
17085
17073
|
server2.registerTool("list_projects", {
|
|
17086
17074
|
description: "List all projects with their key, environments, milestones (token, label, active), and open-issue counts \u2014 the project switcher and workflow entry point (\xA77).",
|
|
@@ -17555,14 +17543,14 @@ var apiTokenSchema2 = external_exports.string().min(1).superRefine((value, ctx)
|
|
|
17555
17543
|
if (!isAcceptedTokenShape(value)) {
|
|
17556
17544
|
ctx.addIssue({
|
|
17557
17545
|
code: "custom",
|
|
17558
|
-
message: "is not a Pipebrain API token \u2014 expected `pbt_\u2026` (
|
|
17546
|
+
message: "is not a Pipebrain API token \u2014 expected `pbt_\u2026` (value withheld). Mint one under Settings \u2192 Organization \u2192 API tokens."
|
|
17559
17547
|
});
|
|
17560
17548
|
}
|
|
17561
17549
|
});
|
|
17562
|
-
function validate(schema, resolved,
|
|
17550
|
+
function validate(schema, resolved, name, issues, variables) {
|
|
17563
17551
|
if (resolved === void 0) {
|
|
17564
|
-
issues.push(`${
|
|
17565
|
-
variables.push(
|
|
17552
|
+
issues.push(`${name}: is not set`);
|
|
17553
|
+
variables.push(name);
|
|
17566
17554
|
return void 0;
|
|
17567
17555
|
}
|
|
17568
17556
|
const result = schema.safeParse(resolved.value);
|
|
@@ -17580,8 +17568,8 @@ function loadMcpConfig() {
|
|
|
17580
17568
|
const resolved = resolveAgentEnv(process.env);
|
|
17581
17569
|
const issues = [];
|
|
17582
17570
|
const variables = [];
|
|
17583
|
-
const apiUrl = validate(external_exports.url(), resolved.apiUrl, "PIPEBRAIN_API_URL",
|
|
17584
|
-
const token = validate(apiTokenSchema2, resolved.token, "PIPEBRAIN_TOKEN",
|
|
17571
|
+
const apiUrl = validate(external_exports.url(), resolved.apiUrl, "PIPEBRAIN_API_URL", issues, variables);
|
|
17572
|
+
const token = validate(apiTokenSchema2, resolved.token, "PIPEBRAIN_TOKEN", issues, variables);
|
|
17585
17573
|
if (apiUrl === void 0 || token === void 0) {
|
|
17586
17574
|
throw new EnvValidationError(issues, variables);
|
|
17587
17575
|
}
|
|
@@ -17589,7 +17577,7 @@ function loadMcpConfig() {
|
|
|
17589
17577
|
}
|
|
17590
17578
|
|
|
17591
17579
|
// src/version.ts
|
|
17592
|
-
var VERSION = "0.
|
|
17580
|
+
var VERSION = "0.34.0";
|
|
17593
17581
|
|
|
17594
17582
|
// src/main.ts
|
|
17595
17583
|
var config2 = loadMcpConfig();
|
|
@@ -17604,8 +17592,6 @@ var server = createMcpServer(client, config2.apiUrl, orgInstructions, {
|
|
|
17604
17592
|
});
|
|
17605
17593
|
var transport = new StdioServerTransport();
|
|
17606
17594
|
await server.connect(transport);
|
|
17607
|
-
var notice = successorNotice();
|
|
17608
|
-
if (notice !== "") process.stderr.write(notice);
|
|
17609
17595
|
process.stderr.write(
|
|
17610
17596
|
`pipebrain mcp connected \u2014 ${apiBindingLabel(config2.apiUrl)} API base ${config2.apiUrl}
|
|
17611
17597
|
`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pipebrain-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Pipebrain MCP server for Claude Code and Claude Desktop \u2014 issues, requirements, content, assets, and metadata-only secrets over the Pipebrain API.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|