@tickernelz/paperclip-pro-mcp-server 2026.926.1 → 2026.926.3

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 (61) hide show
  1. package/README.md +23 -2
  2. package/dist/board-surface.d.ts +11 -0
  3. package/dist/board-surface.d.ts.map +1 -0
  4. package/dist/board-surface.js +96 -0
  5. package/dist/board-surface.js.map +1 -0
  6. package/dist/board-surface.test.d.ts +2 -0
  7. package/dist/board-surface.test.d.ts.map +1 -0
  8. package/dist/board-surface.test.js +216 -0
  9. package/dist/board-surface.test.js.map +1 -0
  10. package/dist/catalog.d.ts +16 -1
  11. package/dist/catalog.d.ts.map +1 -1
  12. package/dist/catalog.js +69 -13
  13. package/dist/catalog.js.map +1 -1
  14. package/dist/config.d.ts +1 -0
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/config.js +4 -2
  17. package/dist/config.js.map +1 -1
  18. package/dist/config.test.d.ts +2 -0
  19. package/dist/config.test.d.ts.map +1 -0
  20. package/dist/config.test.js +66 -0
  21. package/dist/config.test.js.map +1 -0
  22. package/dist/format.d.ts +3 -0
  23. package/dist/format.d.ts.map +1 -1
  24. package/dist/format.js +33 -10
  25. package/dist/format.js.map +1 -1
  26. package/dist/format.test.d.ts +2 -0
  27. package/dist/format.test.d.ts.map +1 -0
  28. package/dist/format.test.js +86 -0
  29. package/dist/format.test.js.map +1 -0
  30. package/dist/generated/api-tools.json +2970 -1136
  31. package/dist/generated/shared-tool-notes.json +14 -0
  32. package/dist/generated-tools.d.ts +2 -0
  33. package/dist/generated-tools.d.ts.map +1 -1
  34. package/dist/generated-tools.js +12 -2
  35. package/dist/generated-tools.js.map +1 -1
  36. package/dist/generated-tools.test.js +8 -7
  37. package/dist/generated-tools.test.js.map +1 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +8 -2
  40. package/dist/index.js.map +1 -1
  41. package/dist/pagination.test.d.ts +2 -0
  42. package/dist/pagination.test.d.ts.map +1 -0
  43. package/dist/pagination.test.js +61 -0
  44. package/dist/pagination.test.js.map +1 -0
  45. package/dist/route-body-schemas.d.ts +40 -0
  46. package/dist/route-body-schemas.d.ts.map +1 -0
  47. package/dist/route-body-schemas.js +296 -0
  48. package/dist/route-body-schemas.js.map +1 -0
  49. package/dist/route-contract.test.d.ts +2 -0
  50. package/dist/route-contract.test.d.ts.map +1 -0
  51. package/dist/route-contract.test.js +255 -0
  52. package/dist/route-contract.test.js.map +1 -0
  53. package/dist/tool-overrides.js +1 -1
  54. package/dist/tool-overrides.js.map +1 -1
  55. package/dist/tools.d.ts +2 -0
  56. package/dist/tools.d.ts.map +1 -1
  57. package/dist/tools.js +9 -2
  58. package/dist/tools.js.map +1 -1
  59. package/dist/tools.test.js +34 -1
  60. package/dist/tools.test.js.map +1 -1
  61. package/package.json +6 -2
package/README.md CHANGED
@@ -23,7 +23,10 @@ Inside an active heartbeat, Paperclip also injects `PAPERCLIP_RUNTIME_TOOLS_*` v
23
23
 
24
24
  The tool surface is generated from the server's OpenAPI registry, so it tracks the API. Two independent filters decide what a client sees:
25
25
 
26
- - **Toolset.** `core` is the default: the curated hand-written tools plus the everyday generated ones (61 tools, ~94 KB of `tools/list` JSON). `extended` adds the rest of the generated surface (all toolsets, management role: 715 tools, ~537 KB). Select with `PAPERCLIP_MCP_TOOLSETS=core,extended` or `--toolsets core,extended`; the CLI flag wins, an empty or unknown value falls back to `core`.
26
+ - **Toolset.** `core` is the default: the curated hand-written tools plus the everyday generated ones (61 tools, ~36 KB of `tools/list` JSON, ~9k tokens). `extended` is a **superset of `core`**, not a sibling: selecting it registers `core` plus the rest of the generated surface (442 tools, ~210 KB; an agent carrying company authority also sees the board-authority tools, 719 tools, ~344 KB). `all` is the same union of everything. Select with `PAPERCLIP_MCP_TOOLSETS=core,extended` or `--toolsets core,extended`; the CLI flag wins, an empty or unknown value falls back to `core`. Requesting `extended` alone therefore never drops a core-only tool such as `paperclipCreateChildIssue` or the watchdog pair.
27
+ - **Names.** Generated tool names are capped at 40 characters (`NAME_LENGTH_LIMIT` in `scripts/generate-mcp-tools.ts`) because a host that truncates an over-long name cannot call the truncated form. An over-long name is shortened by dropping redundant path words, then by a deterministic six-hex path digest, so a name is stable across regenerations.
28
+ - **Parameter names.** A bare `{id}` or `{key}` path placeholder is renamed after the resource segment that precedes it (`/issues/{id}` becomes `issueId`, `/cases/{key}` becomes `caseId`), so a caller never has to guess which `id` a tool wants. The rename is internal: the request path substitution and the wire path are unchanged.
29
+ - **Shared description text.** Statements a route repeats on every one of its operations are lifted out of the per-tool descriptions into `src/generated/shared-tool-notes.json`, surfaced once through `sharedToolNotes()` on the MCP `initialize` result. Each tool description keeps only what is specific to that operation.
27
30
  - **Authority.** Every generated tool carries `authority`: `agent` for routes an ordinary agent key can call, `board` for routes whose handler asserts board authority (the deciding guard and its `file:line` are recorded in `src/generated/api-tools.json`). Board-authority tools are registered only when the caller has a management role, taken from `PAPERCLIP_AGENT_ROLE` or, when that is unset, from `GET /api/agents/me` at startup.
28
31
 
29
32
  Instance-admin, auth/setup/cli-auth, protocol/websocket and credential-reveal routes are excluded for everyone; `src/generated/excluded-operations.json` records each excluded operation with its reason and guard evidence.
@@ -56,15 +59,33 @@ The Paperclip server hosts the same tool surface at `POST /api/mcp/paperclip`, s
56
59
 
57
60
  - Authentication is the REST API's: `Authorization: Bearer <run agent key>` plus `X-Paperclip-Run-Id`. Only agent actors are accepted; a board actor gets `403`, a missing credential `401`.
58
61
  - `companyId` and `agentId` come from the authenticated agent, never from a request header, and board-authority tools are exposed only when that agent's `agentAuthorityCapabilities` include company-level authority.
59
- - Toolsets come from `?toolsets=core,extended`; absent, empty or unknown values fall back to `core`.
62
+ - Toolsets come from `?toolsets=core,extended`; absent, empty or unknown values fall back to `core`, and `extended` implies `core` rather than replacing it.
60
63
  - Each `tools/call` re-enters the REST API over the server's own loopback address with the caller's bearer token, so every route guard, record rule and audit hook runs exactly as it does for a direct API call.
61
64
 
62
65
  Tool definitions are built once per process and per (toolset, authority) variant; the `tools/list` payload is memoized with them.
63
66
 
67
+ ## Error contract
68
+
69
+ A `tools/call` that fails is still a JSON-RPC success with a `result`, but the result carries the MCP error flag so a host cannot mistake it for data:
70
+
71
+ - **`isError: true`** on every failure path: an API rejection (`PaperclipApiError`), a bad argument (zod validation), and any other thrown value. A successful call omits the field.
72
+ - **`_meta["paperclip/httpStatus"]`** carries the original HTTP status when the failure came from the API, so a host can tell a `403` from a `500` without parsing the text. It is absent for argument and unknown failures.
73
+ - **Argument failures are flattened to one line per problem**, `issueId: expected string, received undefined`, instead of a stringified JSON array inside a JSON string. API failures keep the structured `{ error, status, method, path, body }` text payload.
74
+
75
+ ```json
76
+ {
77
+ "content": [{ "type": "text", "text": "GET /issues/X failed with 403: Board access required" }],
78
+ "isError": true,
79
+ "_meta": { "paperclip/httpStatus": 403 }
80
+ }
81
+ ```
82
+
64
83
  ## Tool Surface
65
84
 
66
85
  Curated tools keep their names and behaviour: the run-scoped `connections_search` and `connection_request`, the issue/comment/document/approval/workspace helpers (`paperclipMe`, `paperclipInboxLite`, `paperclipListIssues`, `paperclipCheckoutIssue`, `paperclipGetHeartbeatContext`, `paperclipUpdateIssue`, `paperclipAddComment`, `paperclipUpsertIssueDocument`, `paperclipGetIssueWorkspaceRuntime`, `paperclipApprovalDecision`, and the rest), and the `paperclipApiRequest` escape hatch.
67
86
 
87
+ `paperclipListIssues` returns at most `limit` issues and defaults to **25**, not the route's 500, so one call cannot pull the whole board into context. It accepts `limit` (max 1000), `offset`, `view: "compact"`, `updatedSince`, `sortField`, `sortDir` and `includeConversations`, alongside the existing filters. Raise `limit` explicitly when a complete listing is genuinely needed.
88
+
68
89
  Everything else is generated from the OpenAPI registry into `src/generated/api-tools.json`, one tool per operation, with a zod input schema built from its path parameters, query parameters and JSON body, `companyId` filled from `PAPERCLIP_COMPANY_ID` when the route is company-scoped, and MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`).
69
90
 
70
91
  `paperclipApiRequest` is limited to paths under `/api` and JSON bodies. It is
@@ -0,0 +1,11 @@
1
+ import type { GeneratedToolSpec } from "./generated-tools.js";
2
+ export declare const AGENT_ADMITTING_GUARDS: Readonly<Record<string, true>>;
3
+ export declare const BOARD_ONLY_GUARDS: Readonly<Record<string, true>>;
4
+ export declare const ACTOR_NEUTRAL_GUARDS: Readonly<Record<string, true>>;
5
+ export declare function classifiedGuards(): string[];
6
+ export type BoardSurfaceContext = {
7
+ capabilities: readonly string[];
8
+ permissionKeys: ReadonlySet<string>;
9
+ };
10
+ export declare function boardToolAdvertised(spec: Pick<GeneratedToolSpec, "authority" | "authorityCapability" | "authoritySource" | "guards" | "permissions">, context: BoardSurfaceContext): boolean;
11
+ //# sourceMappingURL=board-surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-surface.d.ts","sourceRoot":"","sources":["../src/board-surface.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAmBjE,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CA2B5D,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAiB/D,CAAC;AAEF,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAM3C;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACrC,CAAC;AAWF,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,IAAI,CACR,iBAAiB,EACjB,WAAW,GAAG,qBAAqB,GAAG,iBAAiB,GAAG,QAAQ,GAAG,aAAa,CACnF,EACD,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAUT"}
@@ -0,0 +1,96 @@
1
+ import { AGENT_MEMBER_AUTHORITY_PERMISSION_KEYS } from "@tickernelz/paperclip-pro-shared";
2
+ export const AGENT_ADMITTING_GUARDS = {
3
+ assertBoardCanManageAgentsForCompany: true,
4
+ assertBoardOrAgent: true,
5
+ assertBoardOrAgentAuthority: true,
6
+ assertBoardOrgOrAgentAuthority: true,
7
+ assertCanGenerateOpenClawInvitePrompt: true,
8
+ assertCanReadConfigurations: true,
9
+ assertCanResolveProposal: true,
10
+ assertCompanyAccess: true,
11
+ assertCompanyPermission: true,
12
+ assertIssueThreadInteractionWithdrawalAllowed: true,
13
+ assertIssueWriteInfluenceAllowed: true,
14
+ assertPendingReviewInteractionVerdictAllowed: true,
15
+ assertSameCompanyCeoAgentOrBoard: true,
16
+ assertScopedApiAuth: true,
17
+ assertSuggestedTaskEffectsAllowed: true,
18
+ hasAgentAuthority: true,
19
+ hasCompanyAccess: true,
20
+ requirePluginConfigCompanyId: true,
21
+ };
22
+ export const BOARD_ONLY_GUARDS = {
23
+ assertAgentAuditPermission: true,
24
+ assertAiConnectionCreateAccess: true,
25
+ assertBoard: true,
26
+ assertBoardAnyToolPermission: true,
27
+ assertBoardMutationAccess: true,
28
+ assertBoardOrgAccess: true,
29
+ assertBoardPermission: true,
30
+ assertCanAccessInstanceEnvironments: true,
31
+ assertCanManageCompanyMember: true,
32
+ assertCanManageInstanceSettings: true,
33
+ assertCanReadInstanceEnvironments: true,
34
+ assertConnectionManager: true,
35
+ assertEndpointAccess: true,
36
+ assertEndpointManagementAccess: true,
37
+ assertIdentityLinkAccess: true,
38
+ assertImportTargetAccess: true,
39
+ assertInstanceAdmin: true,
40
+ assertLocalOperator: true,
41
+ assertPluginBridgeScope: true,
42
+ assertToolAppMutationAccess: true,
43
+ assertToolConnectionAccess: true,
44
+ assertToolConnectionConfigureAccess: true,
45
+ assertToolsAdmin: true,
46
+ assertToolsRuntimeManage: true,
47
+ requireBoardUser: true,
48
+ requireBoardUserId: true,
49
+ };
50
+ export const ACTOR_NEUTRAL_GUARDS = {
51
+ assertAccessAdminVisible: true,
52
+ assertAdapterCodeInstallAllowed: true,
53
+ assertAdapterManagementVisible: true,
54
+ assertAuthenticated: true,
55
+ assertCanTestAsAgent: true,
56
+ assertCompanyScopeReadAllowed: true,
57
+ assertEnvironmentSelectionForCompany: true,
58
+ assertLocalLoginAvailable: true,
59
+ assertNoHiddenSettingChanges: true,
60
+ assertPluginManagementVisible: true,
61
+ assertQueueMutationTarget: true,
62
+ assertRuntimeManageAllowed: true,
63
+ getActorInfo: true,
64
+ requireEnabled: true,
65
+ requireImportTransferRun: true,
66
+ requireLocalFolderDeclaration: true,
67
+ };
68
+ export function classifiedGuards() {
69
+ return [
70
+ ...Object.keys(AGENT_ADMITTING_GUARDS),
71
+ ...Object.keys(BOARD_ONLY_GUARDS),
72
+ ...Object.keys(ACTOR_NEUTRAL_GUARDS),
73
+ ].sort();
74
+ }
75
+ const IMPLICIT_MEMBER_PERMISSION_KEYS = new Set(AGENT_MEMBER_AUTHORITY_PERMISSION_KEYS);
76
+ function permissionHeld(key, context) {
77
+ if (context.permissionKeys.has(key))
78
+ return true;
79
+ return IMPLICIT_MEMBER_PERMISSION_KEYS.has(key) && context.capabilities.includes("company:members");
80
+ }
81
+ export function boardToolAdvertised(spec, context) {
82
+ if (spec.authority !== "board")
83
+ return true;
84
+ if (spec.authoritySource === "handler")
85
+ return false;
86
+ if (spec.guards.some((guard) => BOARD_ONLY_GUARDS[guard] === true))
87
+ return false;
88
+ if (!spec.guards.some((guard) => AGENT_ADMITTING_GUARDS[guard] === true))
89
+ return false;
90
+ const capability = spec.authorityCapability;
91
+ if (capability !== null && capability !== undefined && !context.capabilities.includes(capability)) {
92
+ return false;
93
+ }
94
+ return spec.permissions.every((key) => permissionHeld(key, context));
95
+ }
96
+ //# sourceMappingURL=board-surface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-surface.js","sourceRoot":"","sources":["../src/board-surface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=board-surface.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-surface.test.d.ts","sourceRoot":"","sources":["../src/board-surface.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,216 @@
1
+ import { readFileSync, readdirSync } from "node:fs";
2
+ import { describe, expect, it } from "vitest";
3
+ import { AGENT_MEMBER_AUTHORITY_PERMISSION_KEYS, agentAuthorityCapabilities, } from "@tickernelz/paperclip-pro-shared";
4
+ import { ACTOR_NEUTRAL_GUARDS, AGENT_ADMITTING_GUARDS, BOARD_ONLY_GUARDS, boardToolAdvertised, classifiedGuards, } from "./board-surface.js";
5
+ import { generatedToolSpecs } from "./generated-tools.js";
6
+ const GUARD_DIRS = [
7
+ new URL("../../../server/src/routes/", import.meta.url),
8
+ new URL("../../../server/src/services/", import.meta.url),
9
+ ];
10
+ function routeSource() {
11
+ return GUARD_DIRS.flatMap((dir) => readdirSync(dir)
12
+ .filter((name) => name.endsWith(".ts") && !name.endsWith(".test.ts"))
13
+ .map((name) => readFileSync(new URL(name, dir), "utf8"))).join("\n");
14
+ }
15
+ const CEO = {
16
+ capabilities: agentAuthorityCapabilities("ceo"),
17
+ permissionKeys: new Set(),
18
+ };
19
+ function probeOnlyBoardSpecs() {
20
+ return generatedToolSpecs().filter((spec) => spec.authority === "board" && (spec.boardGuard ?? "").startsWith("probe:"));
21
+ }
22
+ function grantsAdmitActor(spec, context) {
23
+ if (spec.guards.some((guard) => BOARD_ONLY_GUARDS[guard] === true))
24
+ return false;
25
+ if (!spec.guards.some((guard) => AGENT_ADMITTING_GUARDS[guard] === true))
26
+ return false;
27
+ const capability = spec.authorityCapability;
28
+ if (capability != null && !context.capabilities.includes(capability))
29
+ return false;
30
+ return spec.permissions.every((key) => context.permissionKeys.has(key) ||
31
+ (AGENT_MEMBER_AUTHORITY_PERMISSION_KEYS.includes(key) &&
32
+ context.capabilities.includes("company:members")));
33
+ }
34
+ function actorHoldingEverything(spec) {
35
+ return {
36
+ capabilities: spec.authorityCapability == null
37
+ ? CEO.capabilities
38
+ : [...CEO.capabilities, spec.authorityCapability],
39
+ permissionKeys: new Set(spec.permissions),
40
+ };
41
+ }
42
+ describe("board surface classification", () => {
43
+ it("classifies every guard that can decide whether a board tool is advertised", () => {
44
+ const classified = new Set(classifiedGuards());
45
+ const seen = new Set();
46
+ for (const spec of generatedToolSpecs()) {
47
+ if (spec.authority !== "board")
48
+ continue;
49
+ for (const guard of spec.guards) {
50
+ if (!classified.has(guard))
51
+ seen.add(guard);
52
+ }
53
+ }
54
+ expect([...seen].sort()).toEqual([]);
55
+ });
56
+ it("names guards that exist in the route source", () => {
57
+ const source = routeSource();
58
+ const missing = classifiedGuards().filter((guard) => !source.includes(`function ${guard}(`) && !source.includes(`const ${guard} =`));
59
+ expect(missing).toEqual([]);
60
+ });
61
+ it("classifies each guard exactly once", () => {
62
+ const groups = [
63
+ Object.keys(AGENT_ADMITTING_GUARDS),
64
+ Object.keys(BOARD_ONLY_GUARDS),
65
+ Object.keys(ACTOR_NEUTRAL_GUARDS),
66
+ ];
67
+ const all = groups.flat();
68
+ expect(new Set(all).size).toBe(all.length);
69
+ });
70
+ it("records only capabilities the agent authority list can grant", () => {
71
+ const source = readFileSync(new URL("../../../packages/shared/src/agent-authority.ts", import.meta.url), "utf8");
72
+ for (const spec of generatedToolSpecs()) {
73
+ if (spec.authorityCapability === null)
74
+ continue;
75
+ expect(source).toContain(`"${spec.authorityCapability}"`);
76
+ }
77
+ });
78
+ it("records a capability only where the handler asserts an authority guard", () => {
79
+ const authorityGuards = [
80
+ "assertAgentAuthority",
81
+ "assertBoardOrAgentAuthority",
82
+ "assertBoardOrgOrAgentAuthority",
83
+ ];
84
+ for (const spec of generatedToolSpecs()) {
85
+ if (spec.authorityCapability === null)
86
+ continue;
87
+ expect(spec.guards.some((guard) => authorityGuards.includes(guard))).toBe(true);
88
+ }
89
+ });
90
+ });
91
+ describe("boardToolAdvertised", () => {
92
+ const spec = (overrides) => ({
93
+ operationId: "GET /api/x",
94
+ authority: "board",
95
+ authorityCapability: null,
96
+ authoritySource: "default",
97
+ guards: [],
98
+ permissions: [],
99
+ boardGuard: null,
100
+ ...overrides,
101
+ });
102
+ it("advertises non-board tools regardless of grants", () => {
103
+ expect(boardToolAdvertised(spec({ authority: "agent" }), { capabilities: [], permissionKeys: new Set() })).toBe(true);
104
+ });
105
+ it("withholds a board tool whose handler asserts a board-only guard", () => {
106
+ expect(boardToolAdvertised(spec({
107
+ authoritySource: "handler",
108
+ guards: ["assertBoard"],
109
+ boardGuard: "assertBoard@chat-channels.ts:1",
110
+ }), CEO)).toBe(false);
111
+ });
112
+ it("withholds a board tool whose handler guards no agent past, even with a granting capability", () => {
113
+ expect(boardToolAdvertised(spec({
114
+ authoritySource: "handler",
115
+ guards: ["assertSameCompanyCeoAgentOrBoard"],
116
+ authorityCapability: "company:settings",
117
+ boardGuard: "assertSameCompanyCeoAgentOrBoard@export.ts:1",
118
+ }), CEO)).toBe(false);
119
+ });
120
+ it("withholds a board tool that no agent-admitting guard reaches", () => {
121
+ expect(boardToolAdvertised(spec({ guards: ["assertAuthenticated"] }), CEO)).toBe(false);
122
+ });
123
+ it("advertises a board tool the agent authority guard reaches", () => {
124
+ expect(boardToolAdvertised(spec({ guards: ["assertBoardOrAgentAuthority"] }), CEO)).toBe(true);
125
+ });
126
+ it("withholds a board tool whose recorded capability the actor lacks", () => {
127
+ const tool = spec({ guards: ["assertBoardOrAgentAuthority"], authorityCapability: "company:agents" });
128
+ expect(boardToolAdvertised(tool, CEO)).toBe(true);
129
+ expect(boardToolAdvertised(tool, {
130
+ capabilities: ["work:read", "work:issues", "work:routines"],
131
+ permissionKeys: new Set(),
132
+ })).toBe(false);
133
+ });
134
+ it("withholds a board tool whose permission key the actor lacks", () => {
135
+ const tool = spec({ guards: ["assertCompanyPermission"], permissions: ["users:manage_permissions"] });
136
+ expect(boardToolAdvertised(tool, {
137
+ capabilities: CEO.capabilities,
138
+ permissionKeys: new Set(["users:manage_permissions"]),
139
+ })).toBe(true);
140
+ expect(boardToolAdvertised(tool, { capabilities: CEO.capabilities, permissionKeys: new Set() })).toBe(false);
141
+ });
142
+ it("honours the implicit member grant the permission guard really allows", () => {
143
+ const tool = spec({ guards: ["assertCompanyPermission"], permissions: ["users:invite"] });
144
+ expect(boardToolAdvertised(tool, CEO)).toBe(true);
145
+ expect(boardToolAdvertised(tool, {
146
+ capabilities: CEO.capabilities.filter((capability) => capability !== "company:members"),
147
+ permissionKeys: new Set(),
148
+ })).toBe(false);
149
+ });
150
+ it("keeps the implicit member keys in step with the shared list", () => {
151
+ expect([...AGENT_MEMBER_AUTHORITY_PERMISSION_KEYS]).toContain("users:invite");
152
+ });
153
+ });
154
+ describe("probe-derived board evidence", () => {
155
+ it("records the probe reason as evidence about the probe actor, never as a board guard", () => {
156
+ for (const spec of probeOnlyBoardSpecs()) {
157
+ expect(spec.authoritySource).toBe("probe");
158
+ expect(spec.boardGuard).toMatch(/^probe:/);
159
+ }
160
+ });
161
+ it("advertises a ceo the export-fidelity tool a ceo agent really reaches", () => {
162
+ const spec = generatedToolSpecs().find((entry) => entry.name === "paperclipGetExportFidelity");
163
+ expect(spec).toBeDefined();
164
+ expect(spec.guards).toContain("assertSameCompanyCeoAgentOrBoard");
165
+ expect(boardToolAdvertised(spec, CEO)).toBe(true);
166
+ });
167
+ it("keeps a probe-only tool that no agent-admitting guard reaches hidden", () => {
168
+ const spec = generatedToolSpecs().find((entry) => entry.name === "paperclipListIssueFeedbackTraces");
169
+ expect(spec).toBeDefined();
170
+ expect(spec.boardGuard).toMatch(/^probe:/);
171
+ expect(spec.guards).toEqual([]);
172
+ expect(boardToolAdvertised(spec, CEO)).toBe(false);
173
+ });
174
+ it("decides every probe-only board tool from its recorded guards alone", () => {
175
+ const specs = probeOnlyBoardSpecs();
176
+ expect(specs.length).toBe(19);
177
+ for (const spec of specs) {
178
+ const actor = actorHoldingEverything(spec);
179
+ expect(boardToolAdvertised(spec, actor), spec.name).toBe(grantsAdmitActor(spec, actor));
180
+ }
181
+ });
182
+ it("advertises exactly the probe-only board tools a ceo really reaches", () => {
183
+ const advertised = probeOnlyBoardSpecs()
184
+ .filter((spec) => boardToolAdvertised(spec, CEO))
185
+ .map((spec) => spec.name)
186
+ .sort();
187
+ expect(advertised).toEqual([
188
+ "paperclipGetExportFidelity",
189
+ "paperclipGetUserMeInboxAgentPolicy",
190
+ "paperclipListAgentConfigurations",
191
+ ]);
192
+ });
193
+ });
194
+ describe("board pruning effect", () => {
195
+ it("drops the bulk of the board-authority surface for a ceo actor", () => {
196
+ const board = generatedToolSpecs().filter((spec) => spec.authority === "board");
197
+ const advertised = board.filter((spec) => boardToolAdvertised(spec, CEO));
198
+ expect(board.length).toBeGreaterThan(250);
199
+ expect(advertised.length).toBeLessThan(40);
200
+ const before = JSON.stringify(board).length;
201
+ const after = JSON.stringify(advertised).length;
202
+ expect(after / before).toBeLessThan(0.15);
203
+ });
204
+ it("grows the ceo listing by exactly the probe-only tools its own guards admit", () => {
205
+ const board = generatedToolSpecs().filter((spec) => spec.authority === "board");
206
+ const advertised = board.filter((spec) => boardToolAdvertised(spec, CEO));
207
+ const fromProbe = advertised.filter((spec) => (spec.boardGuard ?? "").startsWith("probe:"));
208
+ const fromRegistry = advertised.filter((spec) => spec.authoritySource === "registry");
209
+ expect(advertised.length).toBe(fromProbe.length + fromRegistry.length);
210
+ expect(fromProbe.map((spec) => spec.name).sort()).toEqual(probeOnlyBoardSpecs()
211
+ .filter((spec) => grantsAdmitActor(spec, CEO))
212
+ .map((spec) => spec.name)
213
+ .sort());
214
+ });
215
+ });
216
+ //# sourceMappingURL=board-surface.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-surface.test.js","sourceRoot":"","sources":["../src/board-surface.test.ts"],"names":[],"mappings":"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"}
package/dist/catalog.d.ts CHANGED
@@ -1,9 +1,12 @@
1
+ import { type BoardSurfaceContext } from "./board-surface.js";
1
2
  import type { PaperclipApiClient } from "./client.js";
2
3
  import { type JsonSchemaObject } from "./lean-schema.js";
3
4
  import type { ToolsetName } from "./tool-overrides.js";
4
5
  import { type ToolAnnotations, type ToolDefinition } from "./tools.js";
5
6
  export { PaperclipApiClient } from "./client.js";
6
7
  export { hasManagementAuthority, parseToolsets } from "./config.js";
8
+ export { ACTOR_NEUTRAL_GUARDS, AGENT_ADMITTING_GUARDS, BOARD_ONLY_GUARDS, boardToolAdvertised, classifiedGuards, } from "./board-surface.js";
9
+ export type { BoardSurfaceContext } from "./board-surface.js";
7
10
  export type { ToolsetName } from "./tool-overrides.js";
8
11
  export type { ToolDefinition } from "./tools.js";
9
12
  export type ToolListing = {
@@ -13,9 +16,21 @@ export type ToolListing = {
13
16
  inputSchema: JsonSchemaObject;
14
17
  annotations?: ToolAnnotations;
15
18
  }>;
19
+ nextCursor?: string;
20
+ };
21
+ export declare const DEFAULT_PAGE_SIZE = 1000;
22
+ export declare class InvalidCursorError extends Error {
23
+ constructor(cursor: string);
24
+ }
25
+ export declare function resolvePageSize(env?: NodeJS.ProcessEnv): number;
26
+ export declare function paginateListing(listing: ToolListing, cursor: string | null | undefined, pageSize: number): ToolListing;
27
+ export type CatalogOptions = {
28
+ boardSurface?: BoardSurfaceContext;
29
+ cursor?: string | null;
30
+ pageSize?: number;
16
31
  };
17
32
  /** Tool definitions bound to one caller, sharing schema and listing work per variant. */
18
- export declare function paperclipToolCatalog(client: PaperclipApiClient, toolsets: ReadonlyArray<ToolsetName>, management: boolean): {
33
+ export declare function paperclipToolCatalog(client: PaperclipApiClient, toolsets: ReadonlyArray<ToolsetName>, management: boolean, options?: CatalogOptions): {
19
34
  definitions: ToolDefinition[];
20
35
  listing: ToolListing;
21
36
  };
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAE9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,gBAAgB,CAAC;QAC9B,WAAW,CAAC,EAAE,eAAe,CAAC;KAC/B,CAAC,CAAC;CACJ,CAAC;AAIF,yFAAyF;AACzF,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,aAAa,CAAC,WAAW,CAAC,EACpC,UAAU,EAAE,OAAO,GAClB;IAAE,WAAW,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAuBzD"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAyB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAE9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,gBAAgB,CAAC;QAC9B,WAAW,CAAC,EAAE,eAAe,CAAC;KAC/B,CAAC,CAAC;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,MAAM,EAAE,MAAM,EAGzB;CACF;AAED,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAG5E;AAYD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,QAAQ,EAAE,MAAM,GACf,WAAW,CAQb;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAyBF,yFAAyF;AACzF,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,aAAa,CAAC,WAAW,CAAC,EACpC,UAAU,EAAE,OAAO,EACnB,OAAO,GAAE,cAAmB,GAC3B;IAAE,WAAW,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CA+BzD"}
package/dist/catalog.js CHANGED
@@ -1,29 +1,85 @@
1
1
  import { z } from "zod";
2
+ import { boardToolAdvertised } from "./board-surface.js";
3
+ import { expandToolsetUnion } from "./config.js";
2
4
  import { bindGeneratedTools, prepareGeneratedTools } from "./generated-tools.js";
3
5
  import { leanJsonSchema } from "./lean-schema.js";
4
6
  import { createToolDefinitions } from "./tools.js";
5
7
  export { PaperclipApiClient } from "./client.js";
6
8
  export { hasManagementAuthority, parseToolsets } from "./config.js";
9
+ export { ACTOR_NEUTRAL_GUARDS, AGENT_ADMITTING_GUARDS, BOARD_ONLY_GUARDS, boardToolAdvertised, classifiedGuards, } from "./board-surface.js";
10
+ export const DEFAULT_PAGE_SIZE = 1000;
11
+ export class InvalidCursorError extends Error {
12
+ constructor(cursor) {
13
+ super(`Invalid tools/list cursor: ${cursor}`);
14
+ this.name = "InvalidCursorError";
15
+ }
16
+ }
17
+ export function resolvePageSize(env = process.env) {
18
+ const parsed = Number.parseInt(env.PAPERCLIP_MCP_PAGE_SIZE?.trim() ?? "", 10);
19
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : DEFAULT_PAGE_SIZE;
20
+ }
21
+ function encodeCursor(offset) {
22
+ return Buffer.from(String(offset), "utf8").toString("base64url");
23
+ }
24
+ function decodeCursor(cursor) {
25
+ const decoded = Buffer.from(cursor, "base64url").toString("utf8");
26
+ if (!/^\d+$/.test(decoded))
27
+ throw new InvalidCursorError(cursor);
28
+ return Number.parseInt(decoded, 10);
29
+ }
30
+ export function paginateListing(listing, cursor, pageSize) {
31
+ const offset = cursor ? decodeCursor(cursor) : 0;
32
+ if (offset > listing.tools.length)
33
+ throw new InvalidCursorError(cursor ?? "");
34
+ const tools = listing.tools.slice(offset, offset + pageSize);
35
+ const nextOffset = offset + tools.length;
36
+ return nextOffset < listing.tools.length
37
+ ? { tools, nextCursor: encodeCursor(nextOffset) }
38
+ : { tools };
39
+ }
7
40
  const listings = new Map();
41
+ function listingKey(toolsets, management, surface) {
42
+ const base = `${[...toolsets].sort().join(",")}|${management ? "management" : "agent"}`;
43
+ if (!management || !surface)
44
+ return base;
45
+ return `${base}|${[...surface.capabilities].sort().join(",")}|${[...surface.permissionKeys].sort().join(",")}`;
46
+ }
47
+ function toListingEntries(definitions) {
48
+ return definitions.map((tool) => ({
49
+ name: tool.name,
50
+ description: tool.description,
51
+ inputSchema: leanJsonSchema(z.toJSONSchema(tool.schema, { target: "draft-7", io: "input" })),
52
+ ...(tool.annotations ? { annotations: tool.annotations } : {}),
53
+ }));
54
+ }
8
55
  /** Tool definitions bound to one caller, sharing schema and listing work per variant. */
9
- export function paperclipToolCatalog(client, toolsets, management) {
56
+ export function paperclipToolCatalog(client, toolsets, management, options = {}) {
57
+ const selected = expandToolsetUnion(toolsets);
10
58
  const curated = createToolDefinitions(client);
11
59
  const curatedNames = new Set(curated.map((tool) => tool.name));
12
- const generated = bindGeneratedTools(prepareGeneratedTools(toolsets, management), client).filter((tool) => !curatedNames.has(tool.name));
13
- const definitions = [...curated, ...generated];
14
- const key = `${[...toolsets].sort().join(",")}|${management ? "management" : "agent"}`;
60
+ const prepared = prepareGeneratedTools(selected, management);
61
+ const definitions = [
62
+ ...curated,
63
+ ...bindGeneratedTools(prepared, client).filter((tool) => !curatedNames.has(tool.name)),
64
+ ];
65
+ const key = listingKey(selected, management, options.boardSurface);
15
66
  let listing = listings.get(key);
16
67
  if (!listing) {
17
- listing = {
18
- tools: definitions.map((tool) => ({
19
- name: tool.name,
20
- description: tool.description,
21
- inputSchema: leanJsonSchema(z.toJSONSchema(tool.schema, { target: "draft-7", io: "input" })),
22
- ...(tool.annotations ? { annotations: tool.annotations } : {}),
23
- })),
24
- };
68
+ const surface = management ? options.boardSurface : undefined;
69
+ const advertisedNames = surface
70
+ ? new Set(prepared
71
+ .filter(({ spec }) => boardToolAdvertised(spec, surface))
72
+ .map(({ spec }) => spec.name))
73
+ : null;
74
+ const visible = advertisedNames
75
+ ? definitions.filter((tool) => curatedNames.has(tool.name) || advertisedNames.has(tool.name))
76
+ : definitions;
77
+ listing = { tools: toListingEntries(visible) };
25
78
  listings.set(key, listing);
26
79
  }
27
- return { definitions, listing };
80
+ return {
81
+ definitions,
82
+ listing: paginateListing(listing, options.cursor, options.pageSize ?? resolvePageSize()),
83
+ };
28
84
  }
29
85
  //# sourceMappingURL=catalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,cAAc,EAAyB,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAA6C,MAAM,YAAY,CAAC;AAE9F,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAapE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;AAEhD,yFAAyF;AACzF,MAAM,UAAU,oBAAoB,CAClC,MAA0B,EAC1B,QAAoC,EACpC,UAAmB;IAEnB,MAAM,OAAO,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,kBAAkB,CAAC,qBAAqB,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,CAC9F,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CACvC,CAAC;IACF,MAAM,WAAW,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,SAAS,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IACvF,IAAI,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,GAAG;YACR,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAChC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,WAAW,EAAE,cAAc,CACzB,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAC5C;gBACrB,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/D,CAAC,CAAC;SACJ,CAAC;QACF,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -11,6 +11,7 @@ export interface PaperclipMcpConfig {
11
11
  export declare const MANAGEMENT_ROLES: Record<string, true>;
12
12
  export declare function hasManagementAuthority(role: string | null | undefined): boolean;
13
13
  export declare const TOOLSET_NAMES: ToolsetName[];
14
+ export declare function expandToolsetUnion(selected: ReadonlyArray<ToolsetName>): ToolsetName[];
14
15
  export declare function parseToolsets(requested: string | null | undefined): ToolsetName[];
15
16
  export declare function resolveToolsets(env?: NodeJS.ProcessEnv, argv?: string[]): ToolsetName[];
16
17
  export declare function normalizeApiUrl(apiUrl: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAA8B,CAAC;AAEjF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE/E;AAED,eAAO,MAAM,aAAa,EAAE,WAAW,EAAyB,CAAC;AAEjE,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,EAAE,CAQjF;AAED,wBAAgB,eAAe,CAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,GAAE,MAAM,EAA0B,GACrC,WAAW,EAAE,CAaf;AAUD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,kBAAkB,CAmB1F"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAA8B,CAAC;AAEjF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE/E;AAED,eAAO,MAAM,aAAa,EAAE,WAAW,EAAyB,CAAC;AAEjE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,WAAW,EAAE,CAEtF;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,EAAE,CASjF;AAED,wBAAgB,eAAe,CAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,GAAE,MAAM,EAA0B,GACrC,WAAW,EAAE,CAaf;AAUD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,kBAAkB,CAmB1F"}
package/dist/config.js CHANGED
@@ -3,6 +3,9 @@ export function hasManagementAuthority(role) {
3
3
  return typeof role === "string" && MANAGEMENT_ROLES[role.trim().toLowerCase()] === true;
4
4
  }
5
5
  export const TOOLSET_NAMES = ["core", "extended"];
6
+ export function expandToolsetUnion(selected) {
7
+ return selected.includes("extended") ? [...TOOLSET_NAMES] : ["core"];
8
+ }
6
9
  export function parseToolsets(requested) {
7
10
  const requestedNames = (requested ?? "")
8
11
  .split(",")
@@ -10,8 +13,7 @@ export function parseToolsets(requested) {
10
13
  .filter(Boolean);
11
14
  if (requestedNames.includes("all"))
12
15
  return [...TOOLSET_NAMES];
13
- const selected = TOOLSET_NAMES.filter((name) => requestedNames.includes(name));
14
- return selected.length > 0 ? selected : ["core"];
16
+ return expandToolsetUnion(TOOLSET_NAMES.filter((name) => requestedNames.includes(name)));
15
17
  }
16
18
  export function resolveToolsets(env = process.env, argv = process.argv.slice(2)) {
17
19
  const flagIndex = argv.indexOf("--toolsets");