pattern-mcp 0.11.0 → 0.12.1
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 +35 -5
- package/dist/index.js +7 -0
- package/dist/init-enforcement.js +69 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,10 +15,13 @@ design reference.
|
|
|
15
15
|
|
|
16
16
|
[Website](https://usepattern.sh) · [npm](https://www.npmjs.com/package/pattern-mcp) · [Report an issue](https://github.com/donaldrichard19-LVD/pattern-mcp/issues/new/choose)
|
|
17
17
|
|
|
18
|
-
**Current release: v0.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
**Current release: v0.12.0** — When you run `npx pattern-mcp` for the
|
|
19
|
+
first time, Pattern now shows the optional enforcement boundary
|
|
20
|
+
alongside the telemetry notice. This boundary includes a `PreToolUse`
|
|
21
|
+
hook and a matching CI check. Together, they can require a decision for
|
|
22
|
+
each new component instead of only recording it. See
|
|
23
|
+
[Enforcement boundary: hook + CI gate](#enforcement-boundary-hook--ci-gate)
|
|
24
|
+
for more details.
|
|
22
25
|
|
|
23
26
|
<details>
|
|
24
27
|
<summary><strong>Contents</strong> (click to expand)</summary>
|
|
@@ -1636,6 +1639,31 @@ Run non-interactively with `--yes` (accepts every safe default; branch
|
|
|
1636
1639
|
protection is never auto-confirmed even then -- it's the one step that
|
|
1637
1640
|
reaches outside your local filesystem into real, shared GitHub config).
|
|
1638
1641
|
|
|
1642
|
+
**You don't have to find this section to learn this exists.** Every
|
|
1643
|
+
`npx pattern-mcp` run surfaces it at the same first-run moment as the
|
|
1644
|
+
[telemetry notice](#telemetry):
|
|
1645
|
+
|
|
1646
|
+
- **Always**, in every context, including when a real MCP client has
|
|
1647
|
+
spawned this as a subprocess: a one-time, non-blocking stderr mention
|
|
1648
|
+
that the enforcement boundary exists and the command above sets it up.
|
|
1649
|
+
Same "prints once, gated by a marker file" discipline as the telemetry
|
|
1650
|
+
notice -- tracked at `~/.pattern/enforcement_notice_shown`
|
|
1651
|
+
(`PATTERN_ENFORCEMENT_NOTICE_PATH` to override), never repeats after
|
|
1652
|
+
that regardless of whether you act on it.
|
|
1653
|
+
- **Only when stdin is a real terminal** (`process.stdin.isTTY`) --
|
|
1654
|
+
meaning a human ran `npx pattern-mcp` bare in their own shell, never
|
|
1655
|
+
true for a real MCP client's spawned subprocess -- it also offers a
|
|
1656
|
+
genuine interactive prompt right there: *"Set it up now?"* A yes runs
|
|
1657
|
+
the exact same `init` flow described above. The same JSON-RPC-channel
|
|
1658
|
+
constraint that rules out an interactive telemetry prompt (see
|
|
1659
|
+
[Telemetry](#telemetry)) applies here too, which is why this only ever
|
|
1660
|
+
asks when nothing is piping protocol messages into stdin to begin
|
|
1661
|
+
with.
|
|
1662
|
+
|
|
1663
|
+
Set `PATTERN_NO_ENFORCEMENT_NOTICE` to suppress both halves. See
|
|
1664
|
+
`offerEnforcementSetupOnce` in `src/init-enforcement.ts` for the
|
|
1665
|
+
implementation.
|
|
1666
|
+
|
|
1639
1667
|
**Or set it up by hand**, two pieces, neither installed automatically:
|
|
1640
1668
|
|
|
1641
1669
|
- **`.claude/settings.json`** wired to run `npx --yes
|
|
@@ -1772,7 +1800,9 @@ whether you act on it. There's no interactive y/n prompt: Pattern's stdin
|
|
|
1772
1800
|
is the MCP JSON-RPC channel the client uses to talk to it, so blocking on
|
|
1773
1801
|
stdin for a keypress would fight the protocol handshake instead of
|
|
1774
1802
|
showing a dialog -- a stderr notice is the safe equivalent for a stdio
|
|
1775
|
-
MCP server.
|
|
1803
|
+
MCP server. The same first-run moment also surfaces the enforcement
|
|
1804
|
+
boundary, with the same constraint handled the same way -- see
|
|
1805
|
+
[Enforcement boundary: hook + CI gate](#enforcement-boundary-hook--ci-gate).
|
|
1776
1806
|
|
|
1777
1807
|
**Why it exists.** Three things about real usage can't be answered from
|
|
1778
1808
|
this repo alone: whether people actually come back and use Pattern on a
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ import { homedir } from "node:os";
|
|
|
38
38
|
import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
39
39
|
import { fileURLToPath } from "node:url";
|
|
40
40
|
import { captureApiError, captureRecommendation, getClient as getPostHogClient, installId, printTelemetryNoticeOnce, shutdownTelemetry, TELEMETRY_ENABLED, } from "./telemetry.js";
|
|
41
|
+
import { offerEnforcementSetupOnce } from "./init-enforcement.js";
|
|
41
42
|
export const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
|
|
42
43
|
// Only required for org-scoped keys (not tied to one workspace); unset for
|
|
43
44
|
// legacy workspace-scoped keys, which don't need it.
|
|
@@ -3864,6 +3865,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3864
3865
|
});
|
|
3865
3866
|
async function main() {
|
|
3866
3867
|
printTelemetryNoticeOnce();
|
|
3868
|
+
// Piggybacks on this same first-run moment (Option B, see
|
|
3869
|
+
// init-enforcement.ts) -- always prints a one-time, non-blocking mention;
|
|
3870
|
+
// only prompts interactively when stdin is a real TTY, never when a real
|
|
3871
|
+
// MCP client has piped stdio into this process for JSON-RPC. Always
|
|
3872
|
+
// returns before the transport below claims stdin.
|
|
3873
|
+
await offerEnforcementSetupOnce(PROJECT_ROOT);
|
|
3867
3874
|
const transport = new StdioServerTransport();
|
|
3868
3875
|
await server.connect(transport);
|
|
3869
3876
|
// Best-effort telemetry drain on clean shutdown -- no-op when telemetry
|
package/dist/init-enforcement.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// post_ledger_provenance_to_github.
|
|
13
13
|
import { execFileSync } from "node:child_process";
|
|
14
14
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { homedir } from "node:os";
|
|
15
16
|
import { dirname, join } from "node:path";
|
|
16
17
|
import { fileURLToPath } from "node:url";
|
|
17
18
|
import { createInterface } from "node:readline";
|
|
@@ -314,3 +315,71 @@ export async function runInit(root, options) {
|
|
|
314
315
|
}
|
|
315
316
|
console.log("\nDone. Review the changes with `git status` / `git diff`, then commit when ready.");
|
|
316
317
|
}
|
|
318
|
+
// Option B from BACKLOG.md's "Enforcement boundary setup" entry: piggyback
|
|
319
|
+
// on the moment someone's already setting Pattern up, rather than leaving
|
|
320
|
+
// enforcement as something only the README mentions. Called once from
|
|
321
|
+
// index.ts's main(), right alongside printTelemetryNoticeOnce, before the
|
|
322
|
+
// stdio transport connects.
|
|
323
|
+
//
|
|
324
|
+
// The literal original phrasing of this option ("extend the first-run
|
|
325
|
+
// notice into a [y/N] prompt") turns out not to be safely buildable as
|
|
326
|
+
// written: stdin is the live JSON-RPC channel a real MCP client uses to
|
|
327
|
+
// talk to this process (see telemetry.ts's printTelemetryNoticeOnce for
|
|
328
|
+
// the same constraint, stated first). Blocking it on a keypress here would
|
|
329
|
+
// fight the protocol handshake, not show a dialog. So this does two
|
|
330
|
+
// different things depending on how stdin is actually connected:
|
|
331
|
+
//
|
|
332
|
+
// - Always (any context, including a real client subprocess): print a
|
|
333
|
+
// one-time, non-blocking mention that the enforcement boundary exists
|
|
334
|
+
// and how to set it up. Same "print once, gated by a marker file"
|
|
335
|
+
// pattern as the telemetry notice, deliberately a separate marker/
|
|
336
|
+
// message so the two stay independently legible in a terminal.
|
|
337
|
+
// - Only when process.stdin.isTTY is true -- which a real MCP client's
|
|
338
|
+
// spawned subprocess never has, since it always pipes stdio to speak
|
|
339
|
+
// JSON-RPC over it, but a human running `npx pattern-mcp` bare in
|
|
340
|
+
// their own terminal does -- also offer a real interactive prompt,
|
|
341
|
+
// reusing runInit itself rather than duplicating its logic.
|
|
342
|
+
const ENFORCEMENT_NOTICE_PATH = process.env.PATTERN_ENFORCEMENT_NOTICE_PATH ?? join(homedir(), ".pattern", "enforcement_notice_shown");
|
|
343
|
+
export async function offerEnforcementSetupOnce(root) {
|
|
344
|
+
if (process.env.PATTERN_NO_ENFORCEMENT_NOTICE)
|
|
345
|
+
return;
|
|
346
|
+
try {
|
|
347
|
+
readFileSync(ENFORCEMENT_NOTICE_PATH, "utf8");
|
|
348
|
+
return; // Already shown -- never repeat, same discipline as the telemetry notice.
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
// No marker yet -- fall through and show it.
|
|
352
|
+
}
|
|
353
|
+
console.error([
|
|
354
|
+
"",
|
|
355
|
+
"Pattern -- enforcement boundary available (this will not print again)",
|
|
356
|
+
"By default, Pattern is something the calling agent chooses to use.",
|
|
357
|
+
"An opt-in hook + CI check can require it instead: run `npx pattern-check-gate init`",
|
|
358
|
+
"in your repo to set it up.",
|
|
359
|
+
"Full details: https://github.com/donaldrichard19-LVD/pattern-mcp#enforcement-boundary-hook--ci-gate",
|
|
360
|
+
"",
|
|
361
|
+
].join("\n"));
|
|
362
|
+
try {
|
|
363
|
+
mkdirSync(dirname(ENFORCEMENT_NOTICE_PATH), { recursive: true });
|
|
364
|
+
writeFileSync(ENFORCEMENT_NOTICE_PATH, new Date().toISOString(), "utf8");
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// Couldn't persist the marker -- worst case this prints again next
|
|
368
|
+
// run. Never blocks startup over it, same as the telemetry notice.
|
|
369
|
+
}
|
|
370
|
+
if (!process.stdin.isTTY)
|
|
371
|
+
return;
|
|
372
|
+
try {
|
|
373
|
+
const setUpNow = await confirm("Set it up now?", { yes: false }, false);
|
|
374
|
+
if (setUpNow) {
|
|
375
|
+
await runInit(root, { yes: false }); // closes the shared readline itself, in its own finally block
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
// closeRl() is safe to call even if runInit already closed it (checks
|
|
380
|
+
// rl?.close() and no-ops on null) -- this just guarantees stdin is
|
|
381
|
+
// always released back before main() connects the stdio transport,
|
|
382
|
+
// whether the answer was no or runInit already cleaned up after itself.
|
|
383
|
+
closeRl();
|
|
384
|
+
}
|
|
385
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pattern-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "MCP server that turns your design guidance into a checkable process -- evaluates UI components from external libraries (shadcn/ui, 21st.dev, ReUI) or your own registered design system against a requirements checklist, then tells the agent whether to reuse an existing component or build one from a concrete design reference.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|