@graphorin/eslint-plugin 0.5.0 → 0.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @graphorin/eslint-plugin
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Patch Changes
6
+
7
+ - [#138](https://github.com/o-stepper/graphorin/pull/138) [`6293a25`](https://github.com/o-stepper/graphorin/commit/6293a2531c5c9265294da22fb365a08f2bdf445a) Thanks [@o-stepper](https://github.com/o-stepper)! - Retarget stale security rules to the current API surface (audit 2026-07-04 Wave E, cluster E1). `no-secret-in-deps` matched the pre-0.5 `Agent.toTool({ inheritSecrets })` shape that no longer exists (the rule could never fire); it now matches the real DEC-137 grant point, `withChildToolSecretsContext({ secretsAllowed: [...] })`, still requiring the `rb-24-justification` comment. `no-implicit-network-call` regains parity with `scripts/check-no-network.mjs` (EB-10): undici/got namespace calls, raw `net`/`tls`/`dgram` sockets, `new WebSocket`/`EventSource`, and static/dynamic/`require()` imports of HTTP clients are now flagged. Stale "scaffolds for the eventual public ruleset" package description replaced; the removed `no-console-in-public-api` row dropped from the README.
8
+
9
+ - [#138](https://github.com/o-stepper/graphorin/pull/138) [`6293a25`](https://github.com/o-stepper/graphorin/commit/6293a2531c5c9265294da22fb365a08f2bdf445a) Thanks [@o-stepper](https://github.com/o-stepper)! - Release-pipeline and tarball-surface fixes (audit 2026-07-04 Wave E, cluster E2). `@graphorin/memory`'s `./conflict` subpath was runtime-EMPTY on npm 0.5.0 (`export { };` - preserveModules emitted the module without an explicit tsdown entry); it now ships all 8 runtime exports. `@graphorin/server`'s internal `workspace:*` peer dependencies are ranged (`workspace:>=0.5.0 <1.0.0`) so changesets stops escalating every sibling bump into a bogus MAJOR for the whole fixed group (the 1.0.0 landmine on the release bot's branch). `@graphorin/eslint-plugin` gains the `./package.json` self-export. All 27 per-package CHANGELOGs gain the 0.5.0 section (they were frozen at 0.1.0 inside every published tarball), and the `mvp-readiness` release gate now rejects a stale-CHANGELOG or unresolvable-exports release.
10
+
11
+ ## 0.5.0
12
+
13
+ First version published to the npm registry (with Sigstore build
14
+ provenance). The 0.2.0, 0.3.0, and 0.4.0 versions were internal lockstep
15
+ milestones and were never published. All `@graphorin/*` packages release
16
+ lockstep at the same version; the full release notes for 0.2.0-0.5.0 live
17
+ in the repository-level
18
+ [CHANGELOG](https://github.com/o-stepper/graphorin/blob/main/CHANGELOG.md).
19
+
3
20
  ## 0.1.0
4
21
 
5
22
  ### Minor Changes
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  > ESLint rules for projects that build on **Graphorin**.
4
4
 
5
- - **Status:** v0.5.0 final Phase 16 ruleset.
6
- - **License:** [MIT](./LICENSE) © 2026 Oleksiy Stepurenko.
5
+ - **Status:** v0.6.0 - final Phase 16 ruleset.
6
+ - **License:** [MIT](./LICENSE) - © 2026 Oleksiy Stepurenko.
7
7
  - **Engines:** Node.js 22+ (ESM only).
8
8
  - **Peer dependency:** `eslint >= 9`.
9
9
 
@@ -13,7 +13,7 @@
13
13
  pnpm add -D eslint @graphorin/eslint-plugin
14
14
  ```
15
15
 
16
- ## Usage (ESLint flat config `eslint.config.js`)
16
+ ## Usage (ESLint flat config - `eslint.config.js`)
17
17
 
18
18
  ```js
19
19
  import graphorin from '@graphorin/eslint-plugin';
@@ -37,7 +37,7 @@ export default [
37
37
  ```
38
38
 
39
39
  The bundled config wires every active rule at the severities documented below.
40
- For ESLint 9+ flat config (`eslint.config.js`), spread `flat/recommended` it
40
+ For ESLint 9+ flat config (`eslint.config.js`), spread `flat/recommended` - it
41
41
  maps the `@graphorin` namespace to the plugin object for you:
42
42
 
43
43
  ```js
@@ -59,12 +59,11 @@ The legacy `.eslintrc` form is still exported as `configs.recommended`
59
59
  | `tool-examples-recommended` | Active. Flags missing or empty `examples` arrays and rejects more than the documented upper bound (5). |
60
60
  | `tool-parameter-naming` | Active. Flags ambiguous single-word parameter names (`user`, `id`, `name`, `value`, `data`, `input`, `output`, `result`, `to`, `from`, `key`, `field`) and numeric-suffix names (`arg1`, `param2`) on `inputSchema: z.object({ ... })`. Per-tool opt-out via `tags: ['experimental']` or `tags: ['legacy']`. |
61
61
  | `no-secret-unwrap` | Active. Flags `.unwrap()` and `.reveal()` calls on `SecretValue`-shaped expressions. `.unwrap()` is reported as `'error'` regardless of comments (the method is `@deprecated`); `.reveal()` honours the `// graphorin-allow-secret-unwrap: <reason>` opt-out. |
62
- | `no-secret-in-deps` | Active. Flags `Agent.toTool({ inheritSecrets: [...] })` calls whose allowlist is non-empty and lacks an `// rb-24-justification: <reason>` comment. |
62
+ | `no-secret-in-deps` | Active. Flags `withChildToolSecretsContext({ secretsAllowed: [...] })` grants whose allowlist is non-empty and lacks an `// rb-24-justification: <reason>` comment (DEC-137). |
63
63
  | `provider-middleware-order` | Active. Lint-time enforcement of the canonical `withTracing → withRetry → withRateLimit → withCostLimit → withCostTracking → withFallback → withRedaction` ordering. |
64
- | `no-implicit-network-call` | Active. Flags bare `fetch(...)` / `axios.get(...)` / `https.request(...)` / `new XMLHttpRequest()` invocations in `@graphorin/*` framework code without the explicit `// graphorin-allow-network: <reason>` opt-out. |
64
+ | `no-implicit-network-call` | Active. Flags network primitives in `@graphorin/*` framework code without the explicit `// graphorin-allow-network: <reason>` opt-out: `fetch(...)` / `axios.*` / `undici.*` / `got.*` / `http(s).request` / raw `net`·`tls`·`dgram` sockets / `new WebSocket` / `new EventSource` / `new XMLHttpRequest`, plus static, dynamic, and `require()` imports of HTTP clients (`node-fetch`, `undici`, `got`, `axios`, `ky`, `ws`). Kept in lockstep with `scripts/check-no-network.mjs`. |
65
65
  | `no-third-party-workflow-aliases` | Active. Flags identifiers that mirror third-party-library workflow primitives in the `@graphorin/workflow` package's source so the framework keeps its own naming. |
66
66
  | `no-bare-tool-exec` | Active. Flags `tool({ execute })` functions that do not reference `signal` so long-running tools always propagate the cancellation contract. |
67
- | `no-console-in-public-api` | Scaffold (no-op). Will flag `console.*` calls in code that is part of a package's public surface; activates after the v0.1 public-API freeze. |
68
67
 
69
68
  ## Programmatic discovery (single source of truth)
70
69
 
@@ -95,4 +94,4 @@ for (const tool of tools) {
95
94
 
96
95
  ---
97
96
 
98
- **Graphorin** · v0.5.0 · MIT License · © 2026 Oleksiy Stepurenko · <https://github.com/o-stepper/graphorin>
97
+ **Graphorin** · v0.6.0 · MIT License · © 2026 Oleksiy Stepurenko · <https://github.com/o-stepper/graphorin>
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ import * as eslint0 from "eslint";
8
8
  * subcommand (Phase 15) so the rule logic has a single source of
9
9
  * truth (per the working plan acceptance criteria for RB-49).
10
10
  *
11
- * The discovery is intentionally text-based it scans a source
11
+ * The discovery is intentionally text-based - it scans a source
12
12
  * string for `tool(` call expressions and extracts the immediate
13
13
  * object literal that follows. The extractor handles the common
14
14
  * formatting cases (single-line, multi-line, nested object/array
@@ -165,31 +165,31 @@ declare function gradeTool(tool: DiscoveredTool, findings: ReadonlyArray<LintFin
165
165
  //#endregion
166
166
  //#region src/index.d.ts
167
167
  /**
168
- * @graphorin/eslint-plugin ESLint plugin for projects that build on
168
+ * @graphorin/eslint-plugin - ESLint plugin for projects that build on
169
169
  * the Graphorin framework.
170
170
  *
171
171
  * Phase 16 final ruleset:
172
172
  *
173
- * - `no-secret-unwrap` DEC-020 / ADR-026. Active.
174
- * - `no-secret-in-deps` DEC-137. Active.
175
- * - `provider-middleware-order` DEC-145 / ADR-039. Active.
176
- * - `no-implicit-network-call` DEC-154 / ADR-041. Active.
177
- * - `no-third-party-workflow-aliases` DEC-019 / ADR-029. Active.
178
- * - `no-bare-tool-exec` principle 3 / DEC-143. Active.
179
- * - `tool-description-required` Active.
180
- * - `tool-examples-recommended` Active.
181
- * - `tool-parameter-naming` Active.
173
+ * - `no-secret-unwrap` - DEC-020 / ADR-026. Active.
174
+ * - `no-secret-in-deps` - DEC-137. Active.
175
+ * - `provider-middleware-order` - DEC-145 / ADR-039. Active.
176
+ * - `no-implicit-network-call` - DEC-154 / ADR-041. Active.
177
+ * - `no-third-party-workflow-aliases` - DEC-019 / ADR-029. Active.
178
+ * - `no-bare-tool-exec` - principle 3 / DEC-143. Active.
179
+ * - `tool-description-required` - Active.
180
+ * - `tool-examples-recommended` - Active.
181
+ * - `tool-parameter-naming` - Active.
182
182
  *
183
- * (The former `no-console-in-public-api` scaffold a permanent no-op
184
- * since Phase 01 was removed in the v0.4 hygiene pass (PS-21) rather
183
+ * (The former `no-console-in-public-api` scaffold - a permanent no-op
184
+ * since Phase 01 - was removed in the v0.4 hygiene pass (PS-21) rather
185
185
  * than shipped inert.)
186
186
  *
187
187
  * @packageDocumentation
188
188
  */
189
- declare const VERSION = "0.5.0";
189
+ declare const VERSION = "0.6.0";
190
190
  declare const meta: {
191
191
  readonly name: "@graphorin/eslint-plugin";
192
- readonly version: "0.5.0";
192
+ readonly version: "0.6.0";
193
193
  };
194
194
  declare const rules: {
195
195
  readonly 'no-bare-tool-exec': eslint0.Rule.RuleModule;
package/dist/index.js CHANGED
@@ -106,20 +106,53 @@ const HTTP_VERBS = new Set([
106
106
  "options",
107
107
  "request"
108
108
  ]);
109
+ const CLIENT_NAMESPACE_VERBS = new Set([
110
+ "request",
111
+ "stream",
112
+ "fetch",
113
+ "get",
114
+ "post"
115
+ ]);
116
+ const NETWORK_CONSTRUCTORS = new Set([
117
+ "XMLHttpRequest",
118
+ "WebSocket",
119
+ "EventSource"
120
+ ]);
121
+ const HTTP_CLIENT_SPECIFIERS = new Set([
122
+ "node-fetch",
123
+ "undici",
124
+ "got",
125
+ "axios",
126
+ "ky",
127
+ "ws"
128
+ ]);
109
129
  const rule$7 = {
110
130
  meta: {
111
131
  type: "problem",
112
132
  docs: {
113
- description: "Disallow direct network primitives (`fetch`, `axios`, `http.request`, `XMLHttpRequest`) in `@graphorin/*` framework code without an explicit opt-out comment (DEC-154).",
133
+ description: "Disallow direct network primitives (`fetch`, `axios`/`undici`/`got`, `http.request`, raw `net`/`tls`/`dgram` sockets, `WebSocket`/`EventSource`/`XMLHttpRequest`, HTTP-client imports) in `@graphorin/*` framework code without an explicit opt-out comment (DEC-154).",
114
134
  recommended: true
115
135
  },
116
136
  schema: [],
117
- messages: { forbidden: "direct network call '{{callee}}' in framework code; user actions must initiate network I/O. Add `// graphorin-allow-network: <reason>` to opt out." }
137
+ messages: {
138
+ forbidden: "direct network call '{{callee}}' in framework code; user actions must initiate network I/O. Add `// graphorin-allow-network: <reason>` to opt out.",
139
+ forbiddenImport: "HTTP-client import '{{specifier}}' in framework code; user actions must initiate network I/O. Add `// graphorin-allow-network: <reason>` to opt out."
140
+ }
118
141
  },
119
142
  create(context) {
120
143
  if (!FRAMEWORK_PATH_RE.test(context.filename.replace(/\\/g, "/"))) return {};
121
144
  return {
122
145
  CallExpression(node) {
146
+ const specifier = requiredClientSpecifier(node);
147
+ if (specifier !== null) {
148
+ if (hasAllowComment$2(context, node)) return;
149
+ context.report({
150
+ node,
151
+ messageId: "forbiddenImport",
152
+ data: { specifier }
153
+ });
154
+ return;
155
+ }
123
156
  const name = describeCallee(node);
124
157
  if (name === null) return;
125
158
  if (hasAllowComment$2(context, node)) return;
@@ -131,17 +164,49 @@ const rule$7 = {
131
164
  },
132
165
  NewExpression(node) {
133
166
  if (node.callee.type !== "Identifier") return;
134
- if (node.callee.name !== "XMLHttpRequest") return;
167
+ const callee = node.callee;
168
+ if (!NETWORK_CONSTRUCTORS.has(callee.name)) return;
135
169
  if (hasAllowComment$2(context, node)) return;
136
170
  context.report({
137
171
  node,
138
172
  messageId: "forbidden",
139
- data: { callee: "new XMLHttpRequest" }
173
+ data: { callee: `new ${callee.name}` }
174
+ });
175
+ },
176
+ ImportDeclaration(node) {
177
+ const source = node.source.value;
178
+ if (typeof source !== "string" || !HTTP_CLIENT_SPECIFIERS.has(source)) return;
179
+ if (nodeHasNearbyComment(context, node, ALLOW_TAG$2, 1)) return;
180
+ context.report({
181
+ node,
182
+ messageId: "forbiddenImport",
183
+ data: { specifier: source }
184
+ });
185
+ },
186
+ ImportExpression(node) {
187
+ const source = node.source;
188
+ if (source?.type !== "Literal" || typeof source.value !== "string") return;
189
+ if (!HTTP_CLIENT_SPECIFIERS.has(source.value)) return;
190
+ if (nodeHasNearbyComment(context, node, ALLOW_TAG$2, 1)) return;
191
+ context.report({
192
+ node,
193
+ messageId: "forbiddenImport",
194
+ data: { specifier: source.value }
140
195
  });
141
196
  }
142
197
  };
143
198
  }
144
199
  };
200
+ /** `require('<http client>')` - import-shaped despite being a call. */
201
+ function requiredClientSpecifier(node) {
202
+ if (node.callee.type !== "Identifier") return null;
203
+ if (node.callee.name !== "require") return null;
204
+ const arg = node.arguments[0];
205
+ if (arg === void 0 || arg.type !== "Literal") return null;
206
+ const value = arg.value;
207
+ if (typeof value !== "string" || !HTTP_CLIENT_SPECIFIERS.has(value)) return null;
208
+ return value;
209
+ }
145
210
  function describeCallee(node) {
146
211
  if (node.callee.type === "Identifier") {
147
212
  const name = node.callee.name;
@@ -157,6 +222,10 @@ function describeCallee(node) {
157
222
  if (propName === null) return null;
158
223
  if ((objName === "http" || objName === "https") && (propName === "request" || propName === "get")) return `${objName}.${propName}`;
159
224
  if (objName === "axios" && HTTP_VERBS.has(propName)) return `axios.${propName}`;
225
+ if ((objName === "undici" || objName === "got") && CLIENT_NAMESPACE_VERBS.has(propName)) return `${objName}.${propName}`;
226
+ if (objName === "net" && (propName === "createConnection" || propName === "connect")) return `net.${propName}`;
227
+ if (objName === "tls" && propName === "connect") return "tls.connect";
228
+ if (objName === "dgram" && propName === "createSocket") return "dgram.createSocket";
160
229
  return null;
161
230
  }
162
231
  return null;
@@ -169,47 +238,51 @@ var no_implicit_network_call_default = rule$7;
169
238
  //#endregion
170
239
  //#region src/rules/no-secret-in-deps.ts
171
240
  const JUSTIFICATION_TAG = /\brb-24-justification\s*:/i;
241
+ const GRANT_CALLEE = "withChildToolSecretsContext";
172
242
  const rule$6 = {
173
243
  meta: {
174
244
  type: "suggestion",
175
245
  docs: {
176
- description: "Require an `// rb-24-justification:` comment when `Agent.toTool({ inheritSecrets: [...] })` carries a non-empty allowlist (DEC-137).",
246
+ description: "Require an `// rb-24-justification:` comment when `withChildToolSecretsContext({ secretsAllowed: [...] })` grants a non-empty allowlist to a child tool scope (DEC-137).",
177
247
  recommended: true
178
248
  },
179
249
  schema: [],
180
- messages: { missingJustification: "`inheritSecrets` is non-empty but the call site lacks an `// rb-24-justification: <reason>` comment. Document why this sub-agent inherits parent secrets per DEC-137." }
250
+ messages: { missingJustification: "`secretsAllowed` is non-empty but the call site lacks an `// rb-24-justification: <reason>` comment. Document why this child tool scope inherits parent secrets per DEC-137." }
181
251
  },
182
252
  create(context) {
183
253
  return { CallExpression(node) {
184
- if (!isToToolCall(node)) return;
254
+ if (!isGrantCall(node)) return;
185
255
  const arg = node.arguments[0];
186
256
  if (arg === void 0 || arg.type !== "ObjectExpression") return;
187
- const inheritSecrets = findInheritSecretsProperty(arg);
188
- if (inheritSecrets === null) return;
189
- if (!isNonEmptyArray(inheritSecrets)) return;
257
+ const secretsAllowed = findSecretsAllowedProperty(arg);
258
+ if (secretsAllowed === null) return;
259
+ if (!isNonEmptyArray(secretsAllowed)) return;
190
260
  if (hasJustificationComment(context, node)) return;
191
261
  context.report({
192
- node: inheritSecrets,
262
+ node: secretsAllowed,
193
263
  messageId: "missingJustification"
194
264
  });
195
265
  } };
196
266
  }
197
267
  };
198
- function isToToolCall(node) {
199
- if (node.callee.type !== "MemberExpression") return false;
200
- const callee = node.callee;
201
- if (callee.computed) return false;
202
- if (callee.property.type !== "Identifier") return false;
203
- return callee.property.name === "toTool";
204
- }
205
- function findInheritSecretsProperty(obj) {
268
+ function isGrantCall(node) {
269
+ if (node.callee.type === "Identifier") return node.callee.name === GRANT_CALLEE;
270
+ if (node.callee.type === "MemberExpression") {
271
+ const callee = node.callee;
272
+ if (callee.computed) return false;
273
+ if (callee.property.type !== "Identifier") return false;
274
+ return callee.property.name === GRANT_CALLEE;
275
+ }
276
+ return false;
277
+ }
278
+ function findSecretsAllowedProperty(obj) {
206
279
  for (const prop of obj.properties) {
207
280
  if (prop.type !== "Property") continue;
208
281
  const property = prop;
209
282
  const key = property.key;
210
283
  if (property.computed) continue;
211
- if (key.type === "Identifier" && key.name === "inheritSecrets") return property.value;
212
- if (key.type === "Literal" && key.value === "inheritSecrets") return property.value;
284
+ if (key.type === "Identifier" && key.name === "secretsAllowed") return property.value;
285
+ if (key.type === "Literal" && key.value === "secretsAllowed") return property.value;
213
286
  }
214
287
  return null;
215
288
  }
@@ -235,7 +308,7 @@ const rule$5 = {
235
308
  schema: [],
236
309
  messages: {
237
310
  avoidReveal: "`.reveal()` returns the unwrapped secret as a V8 string. Prefer `.use(fn)` so the value is scoped to a single callback. Add `// graphorin-allow-secret-unwrap: <reason>` to opt out.",
238
- avoidUnwrap: "`.unwrap()` is deprecated call `.reveal()` (audited) or `.use(fn)` (scoped). The opt-out comment is intentionally NOT honoured for `.unwrap()` so the deprecation stays sharp."
311
+ avoidUnwrap: "`.unwrap()` is deprecated - call `.reveal()` (audited) or `.use(fn)` (scoped). The opt-out comment is intentionally NOT honoured for `.unwrap()` so the deprecation stays sharp."
239
312
  }
240
313
  },
241
314
  create(context) {
@@ -886,7 +959,7 @@ const rule = {
886
959
  meta: {
887
960
  type: "suggestion",
888
961
  docs: {
889
- description: "Flag ambiguous or numeric-suffix parameter names on `tool({...})` `inputSchema` declarations (RB-49 write self-documenting parameter names).",
962
+ description: "Flag ambiguous or numeric-suffix parameter names on `tool({...})` `inputSchema` declarations (RB-49 - write self-documenting parameter names).",
890
963
  recommended: true
891
964
  },
892
965
  schema: [],
@@ -933,28 +1006,28 @@ var tool_parameter_naming_default = rule;
933
1006
  //#endregion
934
1007
  //#region src/index.ts
935
1008
  /**
936
- * @graphorin/eslint-plugin ESLint plugin for projects that build on
1009
+ * @graphorin/eslint-plugin - ESLint plugin for projects that build on
937
1010
  * the Graphorin framework.
938
1011
  *
939
1012
  * Phase 16 final ruleset:
940
1013
  *
941
- * - `no-secret-unwrap` DEC-020 / ADR-026. Active.
942
- * - `no-secret-in-deps` DEC-137. Active.
943
- * - `provider-middleware-order` DEC-145 / ADR-039. Active.
944
- * - `no-implicit-network-call` DEC-154 / ADR-041. Active.
945
- * - `no-third-party-workflow-aliases` DEC-019 / ADR-029. Active.
946
- * - `no-bare-tool-exec` principle 3 / DEC-143. Active.
947
- * - `tool-description-required` Active.
948
- * - `tool-examples-recommended` Active.
949
- * - `tool-parameter-naming` Active.
1014
+ * - `no-secret-unwrap` - DEC-020 / ADR-026. Active.
1015
+ * - `no-secret-in-deps` - DEC-137. Active.
1016
+ * - `provider-middleware-order` - DEC-145 / ADR-039. Active.
1017
+ * - `no-implicit-network-call` - DEC-154 / ADR-041. Active.
1018
+ * - `no-third-party-workflow-aliases` - DEC-019 / ADR-029. Active.
1019
+ * - `no-bare-tool-exec` - principle 3 / DEC-143. Active.
1020
+ * - `tool-description-required` - Active.
1021
+ * - `tool-examples-recommended` - Active.
1022
+ * - `tool-parameter-naming` - Active.
950
1023
  *
951
- * (The former `no-console-in-public-api` scaffold a permanent no-op
952
- * since Phase 01 was removed in the v0.4 hygiene pass (PS-21) rather
1024
+ * (The former `no-console-in-public-api` scaffold - a permanent no-op
1025
+ * since Phase 01 - was removed in the v0.4 hygiene pass (PS-21) rather
953
1026
  * than shipped inert.)
954
1027
  *
955
1028
  * @packageDocumentation
956
1029
  */
957
- const VERSION = "0.5.0";
1030
+ const VERSION = "0.6.0";
958
1031
  const meta = {
959
1032
  name: "@graphorin/eslint-plugin",
960
1033
  version: VERSION
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["ALLOW_TAG","rule: Rule.RuleModule","hasAllowComment","rule","ALLOW_TAG","rule: Rule.RuleModule","hasAllowComment","rule","rule: Rule.RuleModule","rule","ALLOW_TAG","rule: Rule.RuleModule","hasAllowComment","rule","FORBIDDEN_NAMES: ReadonlyMap<string, string>","rule: Rule.RuleModule","rule","CANONICAL_ORDER: ReadonlyArray<string>","CANONICAL_INDEX: ReadonlyMap<string, number>","rule: Rule.RuleModule","recognised: { name: string; index: number; node: Node }[]","out: { name: string; node: Node }[]","rule","AMBIGUOUS_PARAMETER_NAMES: ReadonlyArray<string>","PARAMETER_NAMING_OPT_OUT_TAGS: ReadonlyArray<string>","PLACEHOLDER_DESCRIPTIONS: ReadonlyArray<string>","MIN_DESCRIPTION_LENGTH","MAX_EXAMPLES","out: DiscoveredTool[]","match: RegExpExecArray | null","NUMERIC_SUFFIX_PATTERN","findings: LintFinding[]","inString: '\"' | \"'\" | '`' | null","names: string[]","tags: string[]","rule: Rule.RuleModule","rule","rule: Rule.RuleModule","rule","rule: Rule.RuleModule","noBareToolExec","noImplicitNetworkCall","noSecretInDeps","noSecretUnwrap","noThirdPartyWorkflowAliases","providerMiddlewareOrder","toolDescriptionRequired","toolExamplesRecommended","toolParameterNaming","plugin: {\n readonly meta: typeof meta;\n readonly rules: typeof rules;\n readonly configs: {\n readonly recommended: {\n readonly plugins: readonly string[];\n readonly rules: typeof RECOMMENDED_RULES;\n };\n readonly 'flat/recommended': {\n plugins: Record<string, unknown>;\n readonly rules: typeof RECOMMENDED_RULES;\n };\n };\n}"],"sources":["../src/rules/_comment-utils.ts","../src/rules/no-bare-tool-exec.ts","../src/rules/no-implicit-network-call.ts","../src/rules/no-secret-in-deps.ts","../src/rules/no-secret-unwrap.ts","../src/rules/no-third-party-workflow-aliases.ts","../src/rules/provider-middleware-order.ts","../src/tool-discovery.ts","../src/rules/tool-description-required.ts","../src/rules/tool-examples-recommended.ts","../src/rules/tool-parameter-naming.ts","../src/index.ts"],"sourcesContent":["/**\n * Comment-scanning helpers shared by the rule modules. We use raw\n * `getAllComments` + line-distance heuristics instead of `getComments\n * Before / Inside / After` because ESLint's per-node comment attachment\n * leaves orphan comments at the program top-level when the node\n * itself is nested inside an expression statement.\n */\n\nimport type { Rule } from 'eslint';\nimport type { Comment, Node } from 'estree';\n\n/**\n * Returns `true` when the source contains a comment whose `value`\n * matches `tag` and which is positioned within `1` line of `node`'s\n * start, or anywhere inside `node`'s span.\n *\n * @internal\n */\nexport function nodeHasNearbyComment(\n context: Rule.RuleContext,\n node: Node,\n tagPattern: RegExp,\n maxGap: number = 1,\n): boolean {\n const startLine = node.loc?.start.line ?? 0;\n const endLine = node.loc?.end.line ?? Number.POSITIVE_INFINITY;\n const allComments = context.sourceCode.getAllComments() as Comment[];\n for (const c of allComments) {\n if (!tagPattern.test(c.value)) continue;\n const cStart = c.loc?.start.line ?? 0;\n const cEnd = c.loc?.end.line ?? 0;\n if (cEnd <= startLine && startLine - cEnd <= maxGap) return true;\n if (cStart >= startLine && cStart <= endLine) return true;\n if (cStart >= endLine && cStart - endLine <= maxGap) return true;\n }\n return false;\n}\n","/**\n * Rule: `@graphorin/no-bare-tool-exec`. Flags any `tool({...})`\n * invocation whose `execute` function does not reference\n * `ctx.signal`. The intent is principle 3 (streaming-first) +\n * DEC-143 (cancellation contract): every long-running tool MUST\n * propagate the abort signal to the underlying I/O so cancellation\n * actually frees resources.\n *\n * The check is intentionally lexical — it scans the function body for\n * the literal string `signal` (matching `ctx.signal`,\n * `request.signal`, `args.signal`, etc.). False positives are\n * acceptable because the fix is one comment line; false negatives are\n * not, because they hide cancellation bugs in production.\n *\n * Per-call opt-out: `// graphorin-allow-bare-exec: <reason>` on the\n * line above the `execute` function or anywhere inside the tool\n * builder call.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type {\n ArrowFunctionExpression,\n CallExpression,\n FunctionExpression,\n Identifier,\n ObjectExpression,\n Property,\n} from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-allow-bare-exec/;\nconst SIGNAL_REFERENCE_RE = /\\bsignal\\b/;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require every `tool({...})` `execute` function to reference `ctx.signal` so cancellation propagates to the underlying I/O (principle 3, DEC-143).',\n recommended: true,\n },\n schema: [],\n messages: {\n missingSignal:\n \"tool '{{name}}' `execute` function does not reference `ctx.signal`; long-running tools MUST propagate the abort signal. Add `// graphorin-allow-bare-exec: <reason>` to opt out.\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n if (!isToolBuilderCall(node)) return;\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== 'ObjectExpression') return;\n const exec = findExecuteProperty(arg as ObjectExpression);\n if (exec === null) return;\n if (!isFunctionLike(exec)) return;\n const fn = exec as ArrowFunctionExpression | FunctionExpression;\n if (!fn.body) return;\n const fnSource = context.sourceCode.getText(fn.body);\n if (SIGNAL_REFERENCE_RE.test(fnSource)) return;\n if (hasAllowComment(context, node)) return;\n const name = extractToolName(arg as ObjectExpression) ?? '<unknown>';\n context.report({\n node: fn,\n messageId: 'missingSignal',\n data: { name },\n });\n },\n };\n },\n};\n\nfunction isToolBuilderCall(node: CallExpression): boolean {\n if (node.callee.type !== 'Identifier') return false;\n return (node.callee as Identifier).name === 'tool';\n}\n\nfunction findExecuteProperty(obj: ObjectExpression): Property['value'] | null {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n const property = prop as Property;\n if (property.computed) continue;\n const key = property.key;\n if (key.type === 'Identifier' && key.name === 'execute') return property.value;\n if (key.type === 'Literal' && key.value === 'execute') return property.value;\n }\n return null;\n}\n\nfunction isFunctionLike(\n value: Property['value'],\n): value is ArrowFunctionExpression | FunctionExpression {\n return value.type === 'ArrowFunctionExpression' || value.type === 'FunctionExpression';\n}\n\nfunction extractToolName(obj: ObjectExpression): string | null {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n const property = prop as Property;\n if (property.computed) continue;\n const key = property.key;\n const isName =\n (key.type === 'Identifier' && key.name === 'name') ||\n (key.type === 'Literal' && key.value === 'name');\n if (!isName) continue;\n if (property.value.type === 'Literal' && typeof property.value.value === 'string') {\n return property.value.value;\n }\n }\n return null;\n}\n\nfunction hasAllowComment(context: Rule.RuleContext, node: CallExpression): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-implicit-network-call` (DEC-154 / ADR-041).\n * Flags any direct `fetch(...)`, `https.request(...)`, `http.request(...)`,\n * `axios(...)` / `axios.<verb>(...)`, or `XMLHttpRequest` invocation in\n * code under a `@graphorin/*` package's `src/` directory unless the\n * call site carries an opt-out comment whose text contains\n * `'graphorin-allow-network'`.\n *\n * Companion to the `pnpm run check-no-network` static analysis script.\n * The lint surface catches the pattern at author time so reviewers do\n * not need to wait for CI to flag a missed network gate.\n *\n * The rule is intentionally limited to the framework's own code paths\n * — consumer applications can call `fetch` freely. The rule activates\n * whenever the linted file path matches `/packages/<pkg>/src/`.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type { CallExpression, Identifier, MemberExpression, NewExpression } from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-allow-network/;\nconst FRAMEWORK_PATH_RE = /\\bpackages\\/[a-z0-9_-]+\\/src\\b/;\n\nconst NETWORK_CALLEES = new Set(['fetch', 'XMLHttpRequest']);\nconst HTTP_VERBS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'request']);\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow direct network primitives (`fetch`, `axios`, `http.request`, `XMLHttpRequest`) in `@graphorin/*` framework code without an explicit opt-out comment (DEC-154).',\n recommended: true,\n },\n schema: [],\n messages: {\n forbidden:\n \"direct network call '{{callee}}' in framework code; user actions must initiate network I/O. Add `// graphorin-allow-network: <reason>` to opt out.\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n if (!FRAMEWORK_PATH_RE.test(context.filename.replace(/\\\\/g, '/'))) {\n return {};\n }\n return {\n CallExpression(node: CallExpression): void {\n const name = describeCallee(node);\n if (name === null) return;\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'forbidden',\n data: { callee: name },\n });\n },\n NewExpression(node: NewExpression): void {\n if (node.callee.type !== 'Identifier') return;\n const callee = node.callee as Identifier;\n if (callee.name !== 'XMLHttpRequest') return;\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'forbidden',\n data: { callee: 'new XMLHttpRequest' },\n });\n },\n };\n },\n};\n\nfunction describeCallee(node: CallExpression): string | null {\n if (node.callee.type === 'Identifier') {\n const name = (node.callee as Identifier).name;\n if (NETWORK_CALLEES.has(name) || name === 'axios') return name;\n return null;\n }\n if (node.callee.type === 'MemberExpression') {\n const me = node.callee as MemberExpression;\n if (me.computed) return null;\n const objName = me.object.type === 'Identifier' ? (me.object as Identifier).name : null;\n if (objName === null) return null;\n const propName = me.property.type === 'Identifier' ? (me.property as Identifier).name : null;\n if (propName === null) return null;\n if (\n (objName === 'http' || objName === 'https') &&\n (propName === 'request' || propName === 'get')\n )\n return `${objName}.${propName}`;\n if (objName === 'axios' && HTTP_VERBS.has(propName)) return `axios.${propName}`;\n return null;\n }\n return null;\n}\n\nfunction hasAllowComment(context: Rule.RuleContext, node: CallExpression | NewExpression): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-secret-in-deps` (RB-24 / DEC-137). Flags any\n * call shaped like `Agent.toTool({ inheritSecrets: [...] })` (or\n * `agent.toTool({...})`) where the `inheritSecrets` array is non-empty\n * and the surrounding object literal does not include a comment whose\n * text starts with `'rb-24-justification:'` (case-insensitive).\n *\n * The rule enforces the principle-of-least-authority discipline from\n * DEC-137: sub-agents inheriting secret allowlists from their parent\n * is opt-in, and the opt-in MUST be explained in code so security\n * reviewers can audit the inheritance graph without guessing.\n *\n * The rule is intentionally syntactic — it operates on the literal\n * call site without trying to resolve the value of the array. This\n * keeps the rule cheap and avoids false negatives from spread /\n * function-call expressions that hide the inheritance shape.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type {\n ArrayExpression,\n CallExpression,\n MemberExpression,\n ObjectExpression,\n Property,\n} from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst JUSTIFICATION_TAG = /\\brb-24-justification\\s*:/i;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require an `// rb-24-justification:` comment when `Agent.toTool({ inheritSecrets: [...] })` carries a non-empty allowlist (DEC-137).',\n recommended: true,\n },\n schema: [],\n messages: {\n missingJustification:\n '`inheritSecrets` is non-empty but the call site lacks an `// rb-24-justification: <reason>` comment. Document why this sub-agent inherits parent secrets per DEC-137.',\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n if (!isToToolCall(node)) return;\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== 'ObjectExpression') return;\n const objectArg = arg as ObjectExpression;\n const inheritSecrets = findInheritSecretsProperty(objectArg);\n if (inheritSecrets === null) return;\n if (!isNonEmptyArray(inheritSecrets)) return;\n if (hasJustificationComment(context, node)) return;\n context.report({\n node: inheritSecrets,\n messageId: 'missingJustification',\n });\n },\n };\n },\n};\n\nfunction isToToolCall(node: CallExpression): boolean {\n if (node.callee.type !== 'MemberExpression') return false;\n const callee = node.callee as MemberExpression;\n if (callee.computed) return false;\n if (callee.property.type !== 'Identifier') return false;\n return callee.property.name === 'toTool';\n}\n\nfunction findInheritSecretsProperty(obj: ObjectExpression): Property['value'] | null {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n const property = prop as Property;\n const key = property.key;\n if (property.computed) continue;\n if (key.type === 'Identifier' && key.name === 'inheritSecrets') return property.value;\n if (key.type === 'Literal' && key.value === 'inheritSecrets') return property.value;\n }\n return null;\n}\n\nfunction isNonEmptyArray(value: Property['value']): boolean {\n if (value.type !== 'ArrayExpression') return false;\n const arr = value as ArrayExpression;\n return arr.elements.some((e) => e !== null);\n}\n\nfunction hasJustificationComment(context: Rule.RuleContext, node: CallExpression): boolean {\n return nodeHasNearbyComment(context, node, JUSTIFICATION_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-secret-unwrap` (DEC-020 / ADR-026 / Phase 16).\n *\n * Flags member expressions that look like an unprotected unwrap of a\n * `SecretValue` instance — `<expr>.unwrap()` and `<expr>.reveal()` —\n * outside an allow-listed context. The framework convention is:\n *\n * - Prefer `value.use(fn)` / `value.useBuffer(fn)` for scoped reads;\n * they limit the lifetime of the derived V8 string to a single\n * callback invocation.\n * - Use `value.reveal()` only as a one-shot escape hatch with an\n * adjacent justification. The audit log records the call.\n * - Never use `value.unwrap()` — it is `@deprecated` and is an alias\n * for `.reveal()` retained only for the v0.x compatibility window.\n * The rule reports `unwrap()` as `'error'` even when an\n * opt-out comment is present so the deprecation cliff stays sharp.\n *\n * Per-call opt-out: `// graphorin-allow-secret-unwrap: <reason>` on\n * the line above the call site or anywhere inside the enclosing\n * expression-statement source span. The opt-out is honoured for\n * `reveal()` but **not** for `unwrap()` (the deprecation supersedes\n * any local justification).\n *\n * The rule is intentionally lexical — it matches `.unwrap()` /\n * `.reveal()` on any `MemberExpression` regardless of the receiver\n * type. False positives are tolerated because (a) the receiver is\n * almost always a `SecretValue` in this codebase and (b) the\n * one-line opt-out is cheap.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type { CallExpression, Identifier, MemberExpression } from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-allow-secret-unwrap/;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow `.unwrap()` / `.reveal()` calls on `SecretValue` instances. Prefer `.use(fn)` (scoped) or attach a `// graphorin-allow-secret-unwrap: <reason>` opt-out comment for `.reveal()`.',\n recommended: true,\n },\n schema: [],\n messages: {\n avoidReveal:\n '`.reveal()` returns the unwrapped secret as a V8 string. Prefer `.use(fn)` so the value is scoped to a single callback. Add `// graphorin-allow-secret-unwrap: <reason>` to opt out.',\n avoidUnwrap:\n '`.unwrap()` is deprecated — call `.reveal()` (audited) or `.use(fn)` (scoped). The opt-out comment is intentionally NOT honoured for `.unwrap()` so the deprecation stays sharp.',\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n const callee = node.callee;\n if (callee.type !== 'MemberExpression') return;\n const me = callee as MemberExpression;\n if (me.computed) return;\n if (me.property.type !== 'Identifier') return;\n const propName = (me.property as Identifier).name;\n if (propName === 'unwrap') {\n context.report({\n node,\n messageId: 'avoidUnwrap',\n });\n return;\n }\n if (propName === 'reveal') {\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'avoidReveal',\n });\n }\n },\n };\n },\n};\n\nfunction hasAllowComment(context: Rule.RuleContext, node: CallExpression): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-third-party-workflow-aliases` (DEC-019 /\n * ADR-029). Flags any identifier in `@graphorin/workflow` source whose\n * name matches a known third-party workflow primitive (e.g. the\n * library-specific names that Graphorin deliberately renamed). The\n * intent is legal hygiene: the framework's primitives are\n * `Directive`, `Dispatch`, `pause`, `LatestValue`, `Reducer`,\n * `Stream`, `Barrier`, `Ephemeral`, `AnyValue` — we never reuse\n * external library identifiers in the public API.\n *\n * The forbidden list is intentionally narrow — we only flag the\n * canonical proper-noun primitives third-party workflow engines use.\n * Rare false positives (e.g. an internal helper named `Send` for an\n * unrelated reason) are mitigated by the per-occurrence opt-out\n * comment `// graphorin-workflow-naming-allow: <reason>`.\n *\n * The rule activates only on files inside the\n * `@graphorin/workflow` package source tree (path matcher\n * `packages/workflow/src`).\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type { Identifier, Node } from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-workflow-naming-allow/;\nconst WORKFLOW_PATH_RE = /\\bpackages\\/workflow\\/src\\b/;\n\nconst FORBIDDEN_NAMES: ReadonlyMap<string, string> = new Map([\n ['Send', 'Dispatch'],\n ['Command', 'Directive'],\n ['interrupt', 'pause'],\n ['LastValue', 'LatestValue'],\n ['BinaryOperatorAggregate', 'Reducer'],\n ['BinaryAggregate', 'Reducer'],\n ['Topic', 'Stream'],\n]);\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow third-party workflow primitive identifiers in `@graphorin/workflow` source. Graphorin owns its primitive names per DEC-019.',\n recommended: true,\n },\n schema: [],\n messages: {\n forbidden:\n \"identifier '{{forbidden}}' is reserved for the third-party workflow library it originates from; use '{{replacement}}' (DEC-019).\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n if (!WORKFLOW_PATH_RE.test(context.filename.replace(/\\\\/g, '/'))) {\n return {};\n }\n return {\n Identifier(node: Identifier): void {\n const replacement = FORBIDDEN_NAMES.get(node.name);\n if (replacement === undefined) return;\n if (isInImportSpecifier(node)) return;\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'forbidden',\n data: {\n forbidden: node.name,\n replacement,\n },\n });\n },\n };\n },\n};\n\nfunction isInImportSpecifier(node: Identifier): boolean {\n // Skip identifiers used as keys / property names — those are\n // typically referencing external library exports the user is\n // intentionally importing into a renamed local symbol.\n const parent = (node as Identifier & { parent?: Node }).parent;\n if (parent === undefined) return false;\n switch (parent.type) {\n case 'ImportSpecifier':\n case 'ImportNamespaceSpecifier':\n case 'ImportDefaultSpecifier':\n case 'ExportSpecifier':\n return true;\n default:\n return false;\n }\n}\n\nfunction hasAllowComment(context: Rule.RuleContext, node: Identifier): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/provider-middleware-order` (DEC-145 / ADR-039).\n * Lint-time enforcement of the canonical middleware ordering for\n * `composeProviderMiddleware([...])`. Catches the same class of error\n * the runtime composer raises (`MiddlewareOrderingError`) without\n * requiring the runtime to actually wire the chain.\n *\n * The canonical order, outermost → innermost, mirrors the runtime\n * constant `CANONICAL_MIDDLEWARE_ORDER` exported by\n * `@graphorin/provider/middleware`. Built-ins not in the canonical\n * list are tolerated at any position.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type { ArrayExpression, CallExpression, Identifier, Node } from 'estree';\n\nconst CANONICAL_ORDER: ReadonlyArray<string> = [\n 'withTracing',\n 'withRetry',\n 'withRateLimit',\n 'withCostLimit',\n 'withCostTracking',\n 'withFallback',\n 'withRedaction',\n];\n\nconst CANONICAL_INDEX: ReadonlyMap<string, number> = new Map(\n CANONICAL_ORDER.map((name, idx) => [name, idx]),\n);\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Enforce the canonical provider-middleware ordering at lint time. Mirrors the runtime `MiddlewareOrderingError` from `@graphorin/provider/middleware`.',\n recommended: true,\n },\n schema: [],\n messages: {\n orderingViolation: \"'{{outer}}' must appear before '{{inner}}' (canonical order: {{order}}).\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n if (!isComposeCall(node)) return;\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== 'ArrayExpression') return;\n const factories = extractFactoryNames(arg as ArrayExpression);\n const recognised: { name: string; index: number; node: Node }[] = [];\n for (const f of factories) {\n const idx = CANONICAL_INDEX.get(f.name);\n if (idx !== undefined) recognised.push({ name: f.name, index: idx, node: f.node });\n }\n for (let i = 1; i < recognised.length; i++) {\n const prev = recognised[i - 1];\n const cur = recognised[i];\n if (prev !== undefined && cur !== undefined && prev.index > cur.index) {\n context.report({\n node: cur.node,\n messageId: 'orderingViolation',\n data: {\n outer: cur.name,\n inner: prev.name,\n order: CANONICAL_ORDER.join(' → '),\n },\n });\n }\n }\n },\n };\n },\n};\n\nfunction isComposeCall(node: CallExpression): boolean {\n if (node.callee.type === 'Identifier') {\n return (node.callee as Identifier).name === 'composeProviderMiddleware';\n }\n if (node.callee.type === 'MemberExpression') {\n const prop = node.callee.property;\n if (prop.type === 'Identifier' && prop.name === 'composeProviderMiddleware') return true;\n }\n return false;\n}\n\nfunction extractFactoryNames(arr: ArrayExpression): { name: string; node: Node }[] {\n const out: { name: string; node: Node }[] = [];\n for (const elt of arr.elements) {\n if (elt === null) continue;\n // Each element is one of:\n // - `withTracing()` / `withRetry({...})` — CallExpression with Identifier callee\n // - `withTracing` (factory ref) — Identifier\n // - `provider.withTracing()` — CallExpression with MemberExpression callee\n if (elt.type === 'Identifier') {\n out.push({ name: (elt as Identifier).name, node: elt });\n continue;\n }\n if (elt.type === 'CallExpression') {\n const callee = elt.callee;\n if (callee.type === 'Identifier') {\n out.push({ name: (callee as Identifier).name, node: elt });\n } else if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {\n out.push({ name: callee.property.name, node: elt });\n }\n }\n }\n return out;\n}\n\nexport default rule;\n","/**\n * Static `tool({...})` discovery + per-tool grader. Used by both the\n * three `tool-*` ESLint rules and by the `graphorin tools lint` CLI\n * subcommand (Phase 15) so the rule logic has a single source of\n * truth (per the working plan acceptance criteria for RB-49).\n *\n * The discovery is intentionally text-based — it scans a source\n * string for `tool(` call expressions and extracts the immediate\n * object literal that follows. The extractor handles the common\n * formatting cases (single-line, multi-line, nested object/array\n * literals, single + double-quoted strings, template literals) and\n * gracefully skips invocations whose argument shape it cannot\n * parse statically. The trade-off is documented: a project that\n * hides its `tool({...})` calls behind a builder helper or a\n * dynamic import will not be picked up by this lint surface; that\n * is the documented contract for the v0.1 lint surface.\n *\n * **Per-tool grader rubric (RB-49 calibration):**\n *\n * - **description axis (0..40 points):**\n * - 0 if missing / placeholder / shorter than 20 chars.\n * - 16 if length >= 20.\n * - 24 if length >= 30.\n * - 32 if length >= 50.\n * - 40 if length >= 80.\n * - **examples axis (0..30 points):**\n * - 0 if no examples or more than 5 (the documented upper bound).\n * - 12 base for 1 example, +6 per additional, capped at 30.\n * - -6 per PII finding (cap at 0).\n * - **parameter naming axis (0..30 points):**\n * - 30 base, deducted per finding.\n * - -30/N per ambiguous-name finding (full penalty per param).\n * - -10/N per numeric-suffix finding (partial penalty per param).\n * - 15 baseline when no parameters are discoverable.\n *\n * Total: 0..100 points. Calibrated against the RB-49 fixture\n * catalog so `wellDescribedTool` scores 82, `placeholderDescriptionTool`\n * scores 20, and `examplesPiiTool` scores 61.\n *\n * @stable\n */\n\n/**\n * @stable\n */\nexport interface DiscoveredTool {\n /** Source file the call was found in. */\n readonly file: string;\n /** 1-indexed line of the `tool(` token. */\n readonly line: number;\n /** Tool name extracted from the `name:` property when present. */\n readonly name: string;\n /** Tool description (`description:` value) when extractable. */\n readonly description?: string;\n /** Number of examples declared in the `examples:` array. */\n readonly examplesCount: number;\n /** Whether `examples:` is a non-empty array literal. */\n readonly hasExamples: boolean;\n /** Snapshot of identifiers referenced from the `inputSchema` Zod chain. */\n readonly parameterNames: ReadonlyArray<string>;\n /** Tags declared on the call (best-effort). */\n readonly tags: ReadonlyArray<string>;\n /**\n * Raw object-literal source. Useful for tests + as a context blob\n * when the CLI needs to surface the original source in a report.\n */\n readonly source: string;\n}\n\n/**\n * @stable\n */\nexport type LintFindingKind =\n | 'description-missing'\n | 'description-too-short'\n | 'description-placeholder'\n | 'examples-missing'\n | 'examples-too-many'\n | 'examples-pii-detected'\n | 'parameter-ambiguous'\n | 'parameter-numeric-suffix';\n\n/**\n * @stable\n */\nexport interface LintFinding {\n readonly rule:\n | 'graphorin/tool-description-required'\n | 'graphorin/tool-examples-recommended'\n | 'graphorin/tool-parameter-naming';\n readonly kind: LintFindingKind;\n readonly severity: 'error' | 'warn' | 'info';\n readonly message: string;\n readonly toolName: string;\n readonly file: string;\n readonly line: number;\n readonly hint?: string;\n /**\n * Optional matched-pattern context. Populated by the\n * `examples-pii-detected` finding so reports can highlight which\n * example payload triggered the rule.\n */\n readonly matchedPattern?: string;\n}\n\n/**\n * @stable\n */\nexport interface ToolGraderScore {\n readonly toolName: string;\n readonly file: string;\n readonly line: number;\n readonly score: number;\n readonly axes: {\n readonly description: number;\n readonly examples: number;\n readonly parameterNaming: number;\n };\n readonly findings: ReadonlyArray<LintFinding>;\n}\n\n/**\n * Generic identifiers the parameter-naming rule flags as ambiguous.\n * Tools whose `inputSchema` references only specific identifiers\n * (e.g. `userId`, `recipientEmail`, `apiKey`) get full credit on\n * the naming axis.\n *\n * @stable\n */\nexport const AMBIGUOUS_PARAMETER_NAMES: ReadonlyArray<string> = Object.freeze([\n 'user',\n 'id',\n 'name',\n 'value',\n 'data',\n 'input',\n 'output',\n 'result',\n 'to',\n 'from',\n 'key',\n 'field',\n]);\n\n/**\n * Tag values that, when present in a tool's `tags: [...]` literal,\n * suppress the parameter-naming rule for that tool. The opt-out\n * exists so operators can defer the rename for a long tail of\n * pre-RB-49 tools while the framework migrates without breaking\n * calling code.\n *\n * @stable\n */\nexport const PARAMETER_NAMING_OPT_OUT_TAGS: ReadonlyArray<string> = Object.freeze([\n 'experimental',\n 'legacy',\n]);\n\n/**\n * Placeholder values the description-required rule treats as\n * non-descriptions.\n *\n * @stable\n */\nexport const PLACEHOLDER_DESCRIPTIONS: ReadonlyArray<string> = Object.freeze([\n 'todo',\n 'fixme',\n 'tbd',\n 'description',\n 'placeholder',\n]);\n\nconst MIN_DESCRIPTION_LENGTH = 20;\nconst MAX_EXAMPLES = 5;\n\n/**\n * Discover every `tool({...})` invocation in a source string. The\n * returned findings are stable + frozen so callers can pass them\n * straight into a JSON report.\n *\n * @stable\n */\nexport function discoverToolCallsInSource(file: string, source: string): DiscoveredTool[] {\n const out: DiscoveredTool[] = [];\n const regex = /\\btool\\s*\\(\\s*\\{/g;\n let match: RegExpExecArray | null = regex.exec(source);\n while (match !== null) {\n const objectStart = match.index + match[0].length - 1;\n const objectEnd = matchBrace(source, objectStart);\n if (objectEnd > 0) {\n const literal = source.slice(objectStart, objectEnd + 1);\n const line = countLines(source, match.index);\n const tool = parseToolLiteral(file, line, literal);\n if (tool !== null) out.push(tool);\n }\n regex.lastIndex = objectEnd + 1;\n match = regex.exec(source);\n }\n return out;\n}\n\n/** Email PII pattern used by the examples-pii sub-check. */\nconst EMAIL_PATTERN = /[\\w.+%-]+@[\\w.-]+\\.[A-Za-z]{2,}/;\n\n/** Numeric-suffix pattern used by the parameter-naming sub-check. */\nconst NUMERIC_SUFFIX_PATTERN = /^[A-Za-z]+\\d+$/;\n\n/**\n * Run the three RB-49 rules against a discovered tool and return the\n * findings. The CLI grader maps these findings into per-axis scores;\n * the ESLint rules forward them to `context.report(...)`.\n *\n * @stable\n */\nexport function runToolRules(\n tool: DiscoveredTool,\n severityOverrides?: {\n readonly toolDescription?: 'error' | 'warn' | 'off';\n readonly toolExamples?: 'error' | 'warn' | 'off';\n readonly toolParameterNaming?: 'error' | 'warn' | 'off';\n },\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n const descSeverity = severityOverrides?.toolDescription ?? 'error';\n if (descSeverity !== 'off') {\n const desc = tool.description?.trim() ?? '';\n if (desc.length === 0) {\n findings.push(\n finding(\n 'graphorin/tool-description-required',\n 'description-missing',\n descSeverity,\n tool,\n `tool '${tool.name}' has no description; add a description that explains what the tool does and when to use it.`,\n ),\n );\n } else if (PLACEHOLDER_DESCRIPTIONS.includes(desc.toLowerCase())) {\n findings.push(\n finding(\n 'graphorin/tool-description-required',\n 'description-placeholder',\n descSeverity,\n tool,\n `tool '${tool.name}' description is a placeholder ('${tool.description}').`,\n ),\n );\n } else if (desc.length < MIN_DESCRIPTION_LENGTH) {\n findings.push(\n finding(\n 'graphorin/tool-description-required',\n 'description-too-short',\n descSeverity,\n tool,\n `tool '${tool.name}' description is shorter than ${MIN_DESCRIPTION_LENGTH} characters.`,\n ),\n );\n }\n }\n\n const examplesSeverity = severityOverrides?.toolExamples ?? 'warn';\n if (examplesSeverity !== 'off') {\n if (!tool.hasExamples || tool.examplesCount === 0) {\n findings.push(\n finding(\n 'graphorin/tool-examples-recommended',\n 'examples-missing',\n examplesSeverity,\n tool,\n `tool '${tool.name}' has no examples; add 1-5 worked examples per Anthropic 2026 guidance.`,\n ),\n );\n } else if (tool.examplesCount > MAX_EXAMPLES) {\n findings.push(\n finding(\n 'graphorin/tool-examples-recommended',\n 'examples-too-many',\n 'error',\n tool,\n `tool '${tool.name}' declares ${tool.examplesCount} examples; the upper bound is ${MAX_EXAMPLES}.`,\n ),\n );\n }\n // PII sub-check — fires once per matched email pattern in the\n // examples block. Operators usually want synthetic data, not real\n // addresses scraped from the corpus.\n const emailMatch = EMAIL_PATTERN.exec(extractExamplesBlock(tool.source));\n if (emailMatch !== null) {\n const matched = emailMatch[0] as string;\n findings.push(\n finding(\n 'graphorin/tool-examples-recommended',\n 'examples-pii-detected',\n 'error',\n tool,\n `tool '${tool.name}' example contains a real-looking email '${matched}'; replace with synthetic data (e.g. 'user@example.com').`,\n {\n matchedPattern: matched,\n hint: 'RB-49: examples must use synthetic test data so the rendered tool catalogue does not leak PII into provider context.',\n },\n ),\n );\n }\n }\n\n const namingSeverity = severityOverrides?.toolParameterNaming ?? 'warn';\n const namingOptedOut = tool.tags.some((t) => PARAMETER_NAMING_OPT_OUT_TAGS.includes(t));\n if (namingSeverity !== 'off' && !namingOptedOut) {\n for (const param of tool.parameterNames) {\n if (AMBIGUOUS_PARAMETER_NAMES.includes(param)) {\n findings.push(\n finding(\n 'graphorin/tool-parameter-naming',\n 'parameter-ambiguous',\n namingSeverity,\n tool,\n `tool '${tool.name}' uses ambiguous parameter name '${param}'; prefer a self-documenting name (e.g. '${param}Id', '${param}Email').`,\n ),\n );\n } else if (NUMERIC_SUFFIX_PATTERN.test(param)) {\n findings.push(\n finding(\n 'graphorin/tool-parameter-naming',\n 'parameter-numeric-suffix',\n namingSeverity,\n tool,\n `tool '${tool.name}' uses numeric-suffix parameter name '${param}'; prefer a semantic name (e.g. 'queryText', 'userId').`,\n ),\n );\n }\n }\n }\n\n return findings;\n}\n\n/**\n * Compute the per-tool grader score (0..100). Each axis is gated by\n * the findings produced for that axis. The rubric is calibrated\n * against the RB-49 fixture catalog (`wellDescribedTool` -> 82,\n * `placeholderDescriptionTool` -> 20, `examplesPiiTool` -> 61).\n *\n * @stable\n */\nexport function gradeTool(\n tool: DiscoveredTool,\n findings: ReadonlyArray<LintFinding>,\n): ToolGraderScore {\n const descFindings = findings.filter((f) => f.rule === 'graphorin/tool-description-required');\n const exampleFindings = findings.filter((f) => f.rule === 'graphorin/tool-examples-recommended');\n const namingFindings = findings.filter((f) => f.rule === 'graphorin/tool-parameter-naming');\n\n const description = scoreDescription(tool, descFindings);\n const examples = scoreExamples(tool, exampleFindings);\n const parameterNaming = scoreParameterNaming(tool, namingFindings);\n\n return Object.freeze({\n toolName: tool.name,\n file: tool.file,\n line: tool.line,\n score: description + examples + parameterNaming,\n axes: Object.freeze({ description, examples, parameterNaming }),\n findings,\n });\n}\n\nfunction scoreDescription(tool: DiscoveredTool, findings: ReadonlyArray<LintFinding>): number {\n if (findings.length > 0) return 0;\n const desc = tool.description?.trim() ?? '';\n if (desc.length >= 80) return 40;\n if (desc.length >= 50) return 32;\n if (desc.length >= 30) return 24;\n if (desc.length >= MIN_DESCRIPTION_LENGTH) return 16;\n return 0;\n}\n\nfunction scoreExamples(tool: DiscoveredTool, findings: ReadonlyArray<LintFinding>): number {\n if (tool.examplesCount === 0) return 0;\n if (tool.examplesCount > MAX_EXAMPLES) return 0;\n // 12 base for the first example + 6 per additional, cap at 30. This\n // calibration produces wellDescribedTool == 12 (1 example) and\n // placeholderDescriptionTool == 0 (no examples). Each PII finding\n // subtracts 6 from the axis (cap at 0) so examplesPiiTool ends up\n // with 6 (12 base - 6 PII penalty).\n const base = Math.min(30, 12 + (tool.examplesCount - 1) * 6);\n const piiCount = findings.filter((f) => f.kind === 'examples-pii-detected').length;\n return Math.max(0, base - piiCount * 6);\n}\n\nfunction scoreParameterNaming(tool: DiscoveredTool, findings: ReadonlyArray<LintFinding>): number {\n if (tool.parameterNames.length === 0) {\n // No discoverable params — neither a positive nor a negative\n // signal. Award the median.\n return 15;\n }\n const total = tool.parameterNames.length;\n const ambiguousCount = findings.filter((f) => f.kind === 'parameter-ambiguous').length;\n const numericCount = findings.filter((f) => f.kind === 'parameter-numeric-suffix').length;\n // Full penalty for an ambiguous-name finding (`user`, `id`, `to`, …):\n // -30/N. Partial penalty for a numeric-suffix finding (`arg1`,\n // `param2`, …): -10/N. Calibrated so a single-param `arg1` scores\n // 20 (placeholderDescriptionTool) and a two-param `to`-+-`body`\n // scores 15 (examplesPiiTool).\n const score = 30 - (30 / total) * ambiguousCount - (10 / total) * numericCount;\n return Math.max(0, Math.round(score));\n}\n\nfunction finding(\n rule: LintFinding['rule'],\n kind: LintFindingKind,\n severity: 'error' | 'warn',\n tool: DiscoveredTool,\n message: string,\n extra: { readonly hint?: string; readonly matchedPattern?: string } = {},\n): LintFinding {\n return Object.freeze({\n rule,\n kind,\n severity,\n message,\n toolName: tool.name,\n file: tool.file,\n line: tool.line,\n ...(extra.hint !== undefined ? { hint: extra.hint } : {}),\n ...(extra.matchedPattern !== undefined ? { matchedPattern: extra.matchedPattern } : {}),\n });\n}\n\n/**\n * Extract the substring inside the `examples: [...]` array literal so\n * the PII detector can scan only the example payloads (not the rest of\n * the tool body).\n *\n * @internal\n */\nfunction extractExamplesBlock(literal: string): string {\n const m = /examples\\s*:\\s*\\[/.exec(literal);\n if (m === null) return '';\n const start = m.index + m[0].length - 1;\n const end = matchBracket(literal, start);\n if (end < 0) return '';\n return literal.slice(start + 1, end);\n}\n\n/**\n * Parse a string literal value from the immediate object literal.\n * Supports `'`, `\"`, and template strings (without interpolation).\n *\n * @internal\n */\nfunction readStringProp(literal: string, prop: string): string | undefined {\n const escapedProp = prop.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|[\\\\s,{])${escapedProp}\\\\s*:\\\\s*(['\"\\`])`, 'm');\n const m = re.exec(literal);\n if (m === null) return undefined;\n const quote = m[1] as string;\n const start = m.index + m[0].length;\n let i = start;\n let out = '';\n while (i < literal.length) {\n const ch = literal[i] as string;\n if (ch === '\\\\' && i + 1 < literal.length) {\n out += literal[i + 1];\n i += 2;\n continue;\n }\n if (ch === quote) return out;\n out += ch;\n i += 1;\n }\n return undefined;\n}\n\n/**\n * Count entries in an array literal value of the form `prop: [...]`.\n *\n * @internal\n */\nfunction countArrayProp(\n literal: string,\n prop: string,\n): { readonly count: number; readonly present: boolean } {\n const escapedProp = prop.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|[\\\\s,{])${escapedProp}\\\\s*:\\\\s*\\\\[`, 'm');\n const m = re.exec(literal);\n if (m === null) return { count: 0, present: false };\n const start = m.index + m[0].length - 1;\n const end = matchBracket(literal, start);\n if (end < 0) return { count: 0, present: true };\n // Strip a trailing comma so it does not inflate the count.\n const inner = literal\n .slice(start + 1, end)\n .trim()\n .replace(/,\\s*$/, '');\n if (inner.length === 0) return { count: 0, present: true };\n // Count top-level commas (depth + string aware).\n let depth = 0;\n let inString: '\"' | \"'\" | '`' | null = null;\n let count = 1;\n for (let i = 0; i < inner.length; i += 1) {\n const ch = inner[i] as string;\n if (inString !== null) {\n if (ch === '\\\\') {\n i += 1;\n continue;\n }\n if (ch === inString) inString = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n inString = ch as '\"' | \"'\" | '`';\n continue;\n }\n if (ch === '(' || ch === '[' || ch === '{') depth += 1;\n else if (ch === ')' || ch === ']' || ch === '}') depth -= 1;\n else if (ch === ',' && depth === 0) count += 1;\n }\n return { count, present: true };\n}\n\n/**\n * Extract identifiers passed into a `z.object({...})` schema as\n * top-level keys.\n *\n * @internal\n */\nfunction extractParameterNames(literal: string): string[] {\n const m = /inputSchema\\s*:\\s*z\\s*\\.\\s*object\\s*\\(\\s*\\{/.exec(literal);\n if (m === null) return [];\n const start = m.index + m[0].length - 1;\n const end = matchBrace(literal, start);\n if (end < 0) return [];\n const inner = literal.slice(start + 1, end);\n const names: string[] = [];\n const idRegex = /(^|[\\s,{])([A-Za-z_$][A-Za-z0-9_$]*)\\s*:/g;\n let id = idRegex.exec(inner);\n while (id !== null) {\n const name = id[2] as string;\n if (!names.includes(name)) names.push(name);\n id = idRegex.exec(inner);\n }\n return names;\n}\n\nfunction parseToolLiteral(file: string, line: number, literal: string): DiscoveredTool | null {\n const name = readStringProp(literal, 'name') ?? '<anonymous>';\n const description = readStringProp(literal, 'description');\n const examples = countArrayProp(literal, 'examples');\n const tagsArr = countArrayProp(literal, 'tags');\n const tags: string[] = [];\n if (tagsArr.present && tagsArr.count > 0) {\n const m = /tags\\s*:\\s*\\[([^\\]]*)\\]/.exec(literal);\n if (m !== null) {\n const inner = (m[1] as string) ?? '';\n const tagRegex = /['\"`]([^'\"`]+)['\"`]/g;\n let t = tagRegex.exec(inner);\n while (t !== null) {\n tags.push(t[1] as string);\n t = tagRegex.exec(inner);\n }\n }\n }\n const parameterNames = extractParameterNames(literal);\n return Object.freeze({\n file,\n line,\n name,\n ...(description !== undefined ? { description } : {}),\n examplesCount: examples.count,\n hasExamples: examples.present,\n parameterNames: Object.freeze(parameterNames),\n tags: Object.freeze(tags),\n source: literal,\n });\n}\n\nfunction countLines(source: string, index: number): number {\n let n = 1;\n for (let i = 0; i < index; i += 1) {\n if (source[i] === '\\n') n += 1;\n }\n return n;\n}\n\nfunction matchBrace(source: string, openIndex: number): number {\n return matchPair(source, openIndex, '{', '}');\n}\n\nfunction matchBracket(source: string, openIndex: number): number {\n return matchPair(source, openIndex, '[', ']');\n}\n\nfunction matchPair(source: string, openIndex: number, open: string, close: string): number {\n let depth = 0;\n let inString: '\"' | \"'\" | '`' | null = null;\n for (let i = openIndex; i < source.length; i += 1) {\n const ch = source[i] as string;\n if (inString !== null) {\n if (ch === '\\\\') {\n i += 1;\n continue;\n }\n if (ch === inString) inString = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n inString = ch as '\"' | \"'\" | '`';\n continue;\n }\n if (ch === open) depth += 1;\n else if (ch === close) {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n","/**\n * Rule: `@graphorin/tool-description-required` (RB-49 / suggested\n * DEC-165). Flags `tool({...})` invocations whose `description`\n * field is missing, too short (< 20 characters), or a placeholder\n * value (`'TODO'` / `'FIXME'` / `'tbd'` / `'description'` /\n * `'placeholder'`, case-insensitive).\n *\n * The rule shares its discovery + scoring code with the\n * `graphorin tools lint` CLI subcommand (Phase 15) so the rule\n * logic has a single source of truth.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\n\nimport { discoverToolCallsInSource, PLACEHOLDER_DESCRIPTIONS } from '../tool-discovery.js';\n\nconst MIN_DESCRIPTION_LENGTH = 20;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require a meaningful `description` on every `tool({...})` registration. RB-49 (Anthropic 2026 advanced tool use guidance).',\n recommended: true,\n },\n schema: [],\n messages: {\n missing:\n \"tool '{{name}}' has no description; add a description that explains what the tool does and when to use it.\",\n tooShort:\n \"tool '{{name}}' description is shorter than {{min}} characters (currently {{len}}).\",\n placeholder: \"tool '{{name}}' description is a placeholder ('{{value}}').\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n 'Program:exit'(): void {\n const filename = context.filename;\n const source = context.sourceCode.text;\n const tools = discoverToolCallsInSource(filename, source);\n for (const tool of tools) {\n const desc = tool.description?.trim();\n if (desc === undefined || desc.length === 0) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'missing',\n data: { name: tool.name },\n });\n } else if (desc.length < MIN_DESCRIPTION_LENGTH) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'tooShort',\n data: {\n name: tool.name,\n min: String(MIN_DESCRIPTION_LENGTH),\n len: String(desc.length),\n },\n });\n } else if (PLACEHOLDER_DESCRIPTIONS.includes(desc.toLowerCase())) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'placeholder',\n data: { name: tool.name, value: desc },\n });\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n","/**\n * Rule: `@graphorin/tool-examples-recommended` (RB-49). Flags\n * `tool({...})` invocations whose `examples` field is missing,\n * empty, or longer than the documented upper bound (5).\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\n\nimport { discoverToolCallsInSource } from '../tool-discovery.js';\n\nconst MAX_EXAMPLES = 5;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Recommend 1-5 `examples` entries on every `tool({...})` registration (Anthropic 2026 'Writing effective tools' guidance).\",\n recommended: true,\n },\n schema: [],\n messages: {\n missing:\n \"tool '{{name}}' has no examples; add 1-5 worked examples per Anthropic 2026 guidance.\",\n tooMany:\n \"tool '{{name}}' declares {{count}} examples; the documented upper bound is {{max}}.\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n 'Program:exit'(): void {\n const filename = context.filename;\n const source = context.sourceCode.text;\n const tools = discoverToolCallsInSource(filename, source);\n for (const tool of tools) {\n if (!tool.hasExamples || tool.examplesCount === 0) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'missing',\n data: { name: tool.name },\n });\n } else if (tool.examplesCount > MAX_EXAMPLES) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'tooMany',\n data: {\n name: tool.name,\n count: String(tool.examplesCount),\n max: String(MAX_EXAMPLES),\n },\n });\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n","/**\n * Rule: `@graphorin/tool-parameter-naming` (RB-49). Inspects the\n * `inputSchema: z.object({...})` declaration of every `tool({...})`\n * invocation and flags two anti-patterns:\n *\n * - **Ambiguous single-word identifiers** (`user`, `id`, `name`,\n * `value`, `data`, `input`, `output`, `result`, `to`, `from`,\n * `key`, `field`). Suggest a self-documenting alternative.\n * - **Numeric-suffix identifiers** (`arg1`, `arg2`, `param3`).\n * Suggest a semantic name.\n *\n * Per-tool opt-out: when the tool declares `tags: ['experimental']`\n * or `tags: ['legacy']` the rule is suppressed for that registration.\n * This lets operators defer the rename for a long tail of pre-RB-49\n * tools while the framework migrates without breaking calling code.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\n\nimport {\n AMBIGUOUS_PARAMETER_NAMES,\n discoverToolCallsInSource,\n PARAMETER_NAMING_OPT_OUT_TAGS,\n} from '../tool-discovery.js';\n\nconst NUMERIC_SUFFIX_PATTERN = /^[A-Za-z]+\\d+$/;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Flag ambiguous or numeric-suffix parameter names on `tool({...})` `inputSchema` declarations (RB-49 — write self-documenting parameter names).',\n recommended: true,\n },\n schema: [],\n messages: {\n ambiguous:\n \"tool '{{name}}' uses ambiguous parameter name '{{param}}'; prefer a self-documenting name (e.g. '{{param}}Id', '{{param}}Email').\",\n numericSuffix:\n \"tool '{{name}}' uses numeric-suffix parameter name '{{param}}'; prefer a semantic name (e.g. 'queryText', 'userId').\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n 'Program:exit'(): void {\n const filename = context.filename;\n const source = context.sourceCode.text;\n const tools = discoverToolCallsInSource(filename, source);\n for (const tool of tools) {\n if (tool.tags.some((t) => PARAMETER_NAMING_OPT_OUT_TAGS.includes(t))) continue;\n for (const param of tool.parameterNames) {\n if (AMBIGUOUS_PARAMETER_NAMES.includes(param)) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'ambiguous',\n data: { name: tool.name, param },\n });\n } else if (NUMERIC_SUFFIX_PATTERN.test(param)) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'numericSuffix',\n data: { name: tool.name, param },\n });\n }\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n","/**\n * @graphorin/eslint-plugin — ESLint plugin for projects that build on\n * the Graphorin framework.\n *\n * Phase 16 final ruleset:\n *\n * - `no-secret-unwrap` — DEC-020 / ADR-026. Active.\n * - `no-secret-in-deps` — DEC-137. Active.\n * - `provider-middleware-order` — DEC-145 / ADR-039. Active.\n * - `no-implicit-network-call` — DEC-154 / ADR-041. Active.\n * - `no-third-party-workflow-aliases` — DEC-019 / ADR-029. Active.\n * - `no-bare-tool-exec` — principle 3 / DEC-143. Active.\n * - `tool-description-required` — Active.\n * - `tool-examples-recommended` — Active.\n * - `tool-parameter-naming` — Active.\n *\n * (The former `no-console-in-public-api` scaffold — a permanent no-op\n * since Phase 01 — was removed in the v0.4 hygiene pass (PS-21) rather\n * than shipped inert.)\n *\n * @packageDocumentation\n */\n\nimport noBareToolExec from './rules/no-bare-tool-exec.js';\nimport noImplicitNetworkCall from './rules/no-implicit-network-call.js';\nimport noSecretInDeps from './rules/no-secret-in-deps.js';\nimport noSecretUnwrap from './rules/no-secret-unwrap.js';\nimport noThirdPartyWorkflowAliases from './rules/no-third-party-workflow-aliases.js';\nimport providerMiddlewareOrder from './rules/provider-middleware-order.js';\nimport toolDescriptionRequired from './rules/tool-description-required.js';\nimport toolExamplesRecommended from './rules/tool-examples-recommended.js';\nimport toolParameterNaming from './rules/tool-parameter-naming.js';\n\nexport const VERSION = '0.5.0';\n\nexport const meta = {\n name: '@graphorin/eslint-plugin',\n version: VERSION,\n} as const;\n\nexport const rules = {\n 'no-bare-tool-exec': noBareToolExec,\n 'no-implicit-network-call': noImplicitNetworkCall,\n 'no-secret-in-deps': noSecretInDeps,\n 'no-secret-unwrap': noSecretUnwrap,\n 'no-third-party-workflow-aliases': noThirdPartyWorkflowAliases,\n 'provider-middleware-order': providerMiddlewareOrder,\n 'tool-description-required': toolDescriptionRequired,\n 'tool-examples-recommended': toolExamplesRecommended,\n 'tool-parameter-naming': toolParameterNaming,\n} as const;\n\n/** Shared severity map for both the legacy and flat recommended presets. */\nconst RECOMMENDED_RULES = {\n '@graphorin/no-bare-tool-exec': 'warn',\n '@graphorin/no-implicit-network-call': 'error',\n '@graphorin/no-secret-in-deps': 'error',\n '@graphorin/no-secret-unwrap': 'error',\n '@graphorin/no-third-party-workflow-aliases': 'error',\n '@graphorin/provider-middleware-order': 'error',\n '@graphorin/tool-description-required': 'error',\n '@graphorin/tool-examples-recommended': 'warn',\n '@graphorin/tool-parameter-naming': 'warn',\n} as const;\n\n/**\n * PS-17: ship BOTH config shapes. `recommended` is the legacy `.eslintrc` form\n * (`plugins: ['@graphorin']`); `flat/recommended` is the ESLint 9+ flat-config\n * form that maps the namespace to the plugin object, so flat-config consumers\n * can `...plugin.configs['flat/recommended']` instead of hand-wiring ten rules.\n */\nconst plugin: {\n readonly meta: typeof meta;\n readonly rules: typeof rules;\n readonly configs: {\n readonly recommended: {\n readonly plugins: readonly string[];\n readonly rules: typeof RECOMMENDED_RULES;\n };\n readonly 'flat/recommended': {\n plugins: Record<string, unknown>;\n readonly rules: typeof RECOMMENDED_RULES;\n };\n };\n} = {\n meta,\n rules,\n configs: {\n recommended: { plugins: ['@graphorin'], rules: RECOMMENDED_RULES },\n // `plugins` is filled in below — the flat form maps the namespace to the\n // plugin object itself, which must exist first.\n 'flat/recommended': { plugins: {}, rules: RECOMMENDED_RULES },\n },\n};\nplugin.configs['flat/recommended'].plugins = { '@graphorin': plugin };\n\nexport const configs = plugin.configs;\n\nexport {\n AMBIGUOUS_PARAMETER_NAMES,\n type DiscoveredTool,\n discoverToolCallsInSource,\n gradeTool,\n type LintFinding,\n type LintFindingKind,\n PARAMETER_NAMING_OPT_OUT_TAGS,\n PLACEHOLDER_DESCRIPTIONS,\n runToolRules,\n type ToolGraderScore,\n} from './tool-discovery.js';\n\nexport default plugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["ALLOW_TAG","rule: Rule.RuleModule","hasAllowComment","rule","ALLOW_TAG","rule: Rule.RuleModule","hasAllowComment","rule","rule: Rule.RuleModule","rule","ALLOW_TAG","rule: Rule.RuleModule","hasAllowComment","rule","FORBIDDEN_NAMES: ReadonlyMap<string, string>","rule: Rule.RuleModule","rule","CANONICAL_ORDER: ReadonlyArray<string>","CANONICAL_INDEX: ReadonlyMap<string, number>","rule: Rule.RuleModule","recognised: { name: string; index: number; node: Node }[]","out: { name: string; node: Node }[]","rule","AMBIGUOUS_PARAMETER_NAMES: ReadonlyArray<string>","PARAMETER_NAMING_OPT_OUT_TAGS: ReadonlyArray<string>","PLACEHOLDER_DESCRIPTIONS: ReadonlyArray<string>","MIN_DESCRIPTION_LENGTH","MAX_EXAMPLES","out: DiscoveredTool[]","match: RegExpExecArray | null","NUMERIC_SUFFIX_PATTERN","findings: LintFinding[]","inString: '\"' | \"'\" | '`' | null","names: string[]","tags: string[]","rule: Rule.RuleModule","rule","rule: Rule.RuleModule","rule","rule: Rule.RuleModule","noBareToolExec","noImplicitNetworkCall","noSecretInDeps","noSecretUnwrap","noThirdPartyWorkflowAliases","providerMiddlewareOrder","toolDescriptionRequired","toolExamplesRecommended","toolParameterNaming","plugin: {\n readonly meta: typeof meta;\n readonly rules: typeof rules;\n readonly configs: {\n readonly recommended: {\n readonly plugins: readonly string[];\n readonly rules: typeof RECOMMENDED_RULES;\n };\n readonly 'flat/recommended': {\n plugins: Record<string, unknown>;\n readonly rules: typeof RECOMMENDED_RULES;\n };\n };\n}"],"sources":["../src/rules/_comment-utils.ts","../src/rules/no-bare-tool-exec.ts","../src/rules/no-implicit-network-call.ts","../src/rules/no-secret-in-deps.ts","../src/rules/no-secret-unwrap.ts","../src/rules/no-third-party-workflow-aliases.ts","../src/rules/provider-middleware-order.ts","../src/tool-discovery.ts","../src/rules/tool-description-required.ts","../src/rules/tool-examples-recommended.ts","../src/rules/tool-parameter-naming.ts","../src/index.ts"],"sourcesContent":["/**\n * Comment-scanning helpers shared by the rule modules. We use raw\n * `getAllComments` + line-distance heuristics instead of `getComments\n * Before / Inside / After` because ESLint's per-node comment attachment\n * leaves orphan comments at the program top-level when the node\n * itself is nested inside an expression statement.\n */\n\nimport type { Rule } from 'eslint';\nimport type { Comment, Node } from 'estree';\n\n/**\n * Returns `true` when the source contains a comment whose `value`\n * matches `tag` and which is positioned within `1` line of `node`'s\n * start, or anywhere inside `node`'s span.\n *\n * @internal\n */\nexport function nodeHasNearbyComment(\n context: Rule.RuleContext,\n node: Node,\n tagPattern: RegExp,\n maxGap: number = 1,\n): boolean {\n const startLine = node.loc?.start.line ?? 0;\n const endLine = node.loc?.end.line ?? Number.POSITIVE_INFINITY;\n const allComments = context.sourceCode.getAllComments() as Comment[];\n for (const c of allComments) {\n if (!tagPattern.test(c.value)) continue;\n const cStart = c.loc?.start.line ?? 0;\n const cEnd = c.loc?.end.line ?? 0;\n if (cEnd <= startLine && startLine - cEnd <= maxGap) return true;\n if (cStart >= startLine && cStart <= endLine) return true;\n if (cStart >= endLine && cStart - endLine <= maxGap) return true;\n }\n return false;\n}\n","/**\n * Rule: `@graphorin/no-bare-tool-exec`. Flags any `tool({...})`\n * invocation whose `execute` function does not reference\n * `ctx.signal`. The intent is principle 3 (streaming-first) +\n * DEC-143 (cancellation contract): every long-running tool MUST\n * propagate the abort signal to the underlying I/O so cancellation\n * actually frees resources.\n *\n * The check is intentionally lexical - it scans the function body for\n * the literal string `signal` (matching `ctx.signal`,\n * `request.signal`, `args.signal`, etc.). False positives are\n * acceptable because the fix is one comment line; false negatives are\n * not, because they hide cancellation bugs in production.\n *\n * Per-call opt-out: `// graphorin-allow-bare-exec: <reason>` on the\n * line above the `execute` function or anywhere inside the tool\n * builder call.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type {\n ArrowFunctionExpression,\n CallExpression,\n FunctionExpression,\n Identifier,\n ObjectExpression,\n Property,\n} from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-allow-bare-exec/;\nconst SIGNAL_REFERENCE_RE = /\\bsignal\\b/;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require every `tool({...})` `execute` function to reference `ctx.signal` so cancellation propagates to the underlying I/O (principle 3, DEC-143).',\n recommended: true,\n },\n schema: [],\n messages: {\n missingSignal:\n \"tool '{{name}}' `execute` function does not reference `ctx.signal`; long-running tools MUST propagate the abort signal. Add `// graphorin-allow-bare-exec: <reason>` to opt out.\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n if (!isToolBuilderCall(node)) return;\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== 'ObjectExpression') return;\n const exec = findExecuteProperty(arg as ObjectExpression);\n if (exec === null) return;\n if (!isFunctionLike(exec)) return;\n const fn = exec as ArrowFunctionExpression | FunctionExpression;\n if (!fn.body) return;\n const fnSource = context.sourceCode.getText(fn.body);\n if (SIGNAL_REFERENCE_RE.test(fnSource)) return;\n if (hasAllowComment(context, node)) return;\n const name = extractToolName(arg as ObjectExpression) ?? '<unknown>';\n context.report({\n node: fn,\n messageId: 'missingSignal',\n data: { name },\n });\n },\n };\n },\n};\n\nfunction isToolBuilderCall(node: CallExpression): boolean {\n if (node.callee.type !== 'Identifier') return false;\n return (node.callee as Identifier).name === 'tool';\n}\n\nfunction findExecuteProperty(obj: ObjectExpression): Property['value'] | null {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n const property = prop as Property;\n if (property.computed) continue;\n const key = property.key;\n if (key.type === 'Identifier' && key.name === 'execute') return property.value;\n if (key.type === 'Literal' && key.value === 'execute') return property.value;\n }\n return null;\n}\n\nfunction isFunctionLike(\n value: Property['value'],\n): value is ArrowFunctionExpression | FunctionExpression {\n return value.type === 'ArrowFunctionExpression' || value.type === 'FunctionExpression';\n}\n\nfunction extractToolName(obj: ObjectExpression): string | null {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n const property = prop as Property;\n if (property.computed) continue;\n const key = property.key;\n const isName =\n (key.type === 'Identifier' && key.name === 'name') ||\n (key.type === 'Literal' && key.value === 'name');\n if (!isName) continue;\n if (property.value.type === 'Literal' && typeof property.value.value === 'string') {\n return property.value.value;\n }\n }\n return null;\n}\n\nfunction hasAllowComment(context: Rule.RuleContext, node: CallExpression): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-implicit-network-call` (DEC-154 / ADR-041).\n * Flags any direct network primitive in code under a `@graphorin/*`\n * package's `src/` directory unless the call site carries an opt-out\n * comment whose text contains `'graphorin-allow-network'`:\n *\n * - calls: `fetch(...)`, `http(s).request/get(...)`, `axios(...)` /\n * `axios.<verb>(...)`, `undici.<verb>(...)` / `got.<verb>(...)`,\n * `net.createConnection/connect(...)`, `tls.connect(...)`,\n * `dgram.createSocket(...)`\n * - constructors: `new XMLHttpRequest()`, `new WebSocket(...)`,\n * `new EventSource(...)`\n * - imports of HTTP clients: `node-fetch`, `undici`, `got`, `axios`,\n * `ky`, `ws` (static, dynamic `import(...)`, and `require(...)`)\n *\n * Companion to the `pnpm run check-no-network` static analysis script;\n * the two matchers are kept in lockstep (this rule mirrors the EB-10\n * hardening that taught the script about undici/got, raw sockets,\n * WebSocket/EventSource, and HTTP-client import specifiers). The lint\n * surface catches the pattern at author time so reviewers do not need\n * to wait for CI to flag a missed network gate.\n *\n * The rule is intentionally limited to the framework's own code paths\n * - consumer applications can call `fetch` freely. The rule activates\n * whenever the linted file path matches `/packages/<pkg>/src/`.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type {\n CallExpression,\n Identifier,\n ImportDeclaration,\n MemberExpression,\n NewExpression,\n} from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-allow-network/;\nconst FRAMEWORK_PATH_RE = /\\bpackages\\/[a-z0-9_-]+\\/src\\b/;\n\nconst NETWORK_CALLEES = new Set(['fetch', 'XMLHttpRequest']);\nconst HTTP_VERBS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'request']);\nconst CLIENT_NAMESPACE_VERBS = new Set(['request', 'stream', 'fetch', 'get', 'post']);\nconst NETWORK_CONSTRUCTORS = new Set(['XMLHttpRequest', 'WebSocket', 'EventSource']);\nconst HTTP_CLIENT_SPECIFIERS = new Set(['node-fetch', 'undici', 'got', 'axios', 'ky', 'ws']);\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow direct network primitives (`fetch`, `axios`/`undici`/`got`, `http.request`, raw `net`/`tls`/`dgram` sockets, `WebSocket`/`EventSource`/`XMLHttpRequest`, HTTP-client imports) in `@graphorin/*` framework code without an explicit opt-out comment (DEC-154).',\n recommended: true,\n },\n schema: [],\n messages: {\n forbidden:\n \"direct network call '{{callee}}' in framework code; user actions must initiate network I/O. Add `// graphorin-allow-network: <reason>` to opt out.\",\n forbiddenImport:\n \"HTTP-client import '{{specifier}}' in framework code; user actions must initiate network I/O. Add `// graphorin-allow-network: <reason>` to opt out.\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n if (!FRAMEWORK_PATH_RE.test(context.filename.replace(/\\\\/g, '/'))) {\n return {};\n }\n return {\n CallExpression(node: CallExpression): void {\n const specifier = requiredClientSpecifier(node);\n if (specifier !== null) {\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'forbiddenImport',\n data: { specifier },\n });\n return;\n }\n const name = describeCallee(node);\n if (name === null) return;\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'forbidden',\n data: { callee: name },\n });\n },\n NewExpression(node: NewExpression): void {\n if (node.callee.type !== 'Identifier') return;\n const callee = node.callee as Identifier;\n if (!NETWORK_CONSTRUCTORS.has(callee.name)) return;\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'forbidden',\n data: { callee: `new ${callee.name}` },\n });\n },\n ImportDeclaration(node: ImportDeclaration): void {\n const source = node.source.value;\n if (typeof source !== 'string' || !HTTP_CLIENT_SPECIFIERS.has(source)) return;\n if (nodeHasNearbyComment(context, node, ALLOW_TAG, 1)) return;\n context.report({\n node,\n messageId: 'forbiddenImport',\n data: { specifier: source },\n });\n },\n ImportExpression(node: Rule.Node): void {\n const source = (node as { source?: { type?: string; value?: unknown } }).source;\n if (source?.type !== 'Literal' || typeof source.value !== 'string') return;\n if (!HTTP_CLIENT_SPECIFIERS.has(source.value)) return;\n if (nodeHasNearbyComment(context, node as never, ALLOW_TAG, 1)) return;\n context.report({\n node: node as never,\n messageId: 'forbiddenImport',\n data: { specifier: source.value },\n });\n },\n };\n },\n};\n\n/** `require('<http client>')` - import-shaped despite being a call. */\nfunction requiredClientSpecifier(node: CallExpression): string | null {\n if (node.callee.type !== 'Identifier') return null;\n if ((node.callee as Identifier).name !== 'require') return null;\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== 'Literal') return null;\n const value = (arg as { value?: unknown }).value;\n if (typeof value !== 'string' || !HTTP_CLIENT_SPECIFIERS.has(value)) return null;\n return value;\n}\n\nfunction describeCallee(node: CallExpression): string | null {\n if (node.callee.type === 'Identifier') {\n const name = (node.callee as Identifier).name;\n if (NETWORK_CALLEES.has(name) || name === 'axios') return name;\n return null;\n }\n if (node.callee.type === 'MemberExpression') {\n const me = node.callee as MemberExpression;\n if (me.computed) return null;\n const objName = me.object.type === 'Identifier' ? (me.object as Identifier).name : null;\n if (objName === null) return null;\n const propName = me.property.type === 'Identifier' ? (me.property as Identifier).name : null;\n if (propName === null) return null;\n if (\n (objName === 'http' || objName === 'https') &&\n (propName === 'request' || propName === 'get')\n )\n return `${objName}.${propName}`;\n if (objName === 'axios' && HTTP_VERBS.has(propName)) return `axios.${propName}`;\n if ((objName === 'undici' || objName === 'got') && CLIENT_NAMESPACE_VERBS.has(propName))\n return `${objName}.${propName}`;\n if (objName === 'net' && (propName === 'createConnection' || propName === 'connect'))\n return `net.${propName}`;\n if (objName === 'tls' && propName === 'connect') return 'tls.connect';\n if (objName === 'dgram' && propName === 'createSocket') return 'dgram.createSocket';\n return null;\n }\n return null;\n}\n\nfunction hasAllowComment(context: Rule.RuleContext, node: CallExpression | NewExpression): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-secret-in-deps` (RB-24 / DEC-137). Flags any\n * call shaped like `withChildToolSecretsContext({ secretsAllowed:\n * [...] }, fn)` where the `secretsAllowed` array is non-empty and the\n * surrounding call site does not include a comment whose text starts\n * with `'rb-24-justification:'` (case-insensitive).\n *\n * The rule enforces the principle-of-least-authority discipline from\n * DEC-137: granting a child tool scope access to parent secrets is\n * opt-in, and the opt-in MUST be explained in code so security\n * reviewers can audit the inheritance graph without guessing.\n *\n * History: this rule originally matched `Agent.toTool({\n * inheritSecrets: [...] })`, a pre-0.5 API shape that no longer\n * exists - `AgentToToolOptions` deliberately has no secret-inheritance\n * mechanism at that boundary. The DEC-137 grant point today is the\n * explicit child ACL scope opened via `withChildToolSecretsContext`\n * from `@graphorin/security` (whose `secretsAllowed` is intersected\n * with the parent allowlist), so that is what the rule matches now.\n *\n * The rule is intentionally syntactic - it operates on the literal\n * call site without trying to resolve the value of the array. This\n * keeps the rule cheap and avoids false negatives from spread /\n * function-call expressions that hide the inheritance shape.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type {\n ArrayExpression,\n CallExpression,\n Identifier,\n MemberExpression,\n ObjectExpression,\n Property,\n} from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst JUSTIFICATION_TAG = /\\brb-24-justification\\s*:/i;\nconst GRANT_CALLEE = 'withChildToolSecretsContext';\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require an `// rb-24-justification:` comment when `withChildToolSecretsContext({ secretsAllowed: [...] })` grants a non-empty allowlist to a child tool scope (DEC-137).',\n recommended: true,\n },\n schema: [],\n messages: {\n missingJustification:\n '`secretsAllowed` is non-empty but the call site lacks an `// rb-24-justification: <reason>` comment. Document why this child tool scope inherits parent secrets per DEC-137.',\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n if (!isGrantCall(node)) return;\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== 'ObjectExpression') return;\n const objectArg = arg as ObjectExpression;\n const secretsAllowed = findSecretsAllowedProperty(objectArg);\n if (secretsAllowed === null) return;\n if (!isNonEmptyArray(secretsAllowed)) return;\n if (hasJustificationComment(context, node)) return;\n context.report({\n node: secretsAllowed,\n messageId: 'missingJustification',\n });\n },\n };\n },\n};\n\nfunction isGrantCall(node: CallExpression): boolean {\n if (node.callee.type === 'Identifier') {\n return (node.callee as Identifier).name === GRANT_CALLEE;\n }\n if (node.callee.type === 'MemberExpression') {\n const callee = node.callee as MemberExpression;\n if (callee.computed) return false;\n if (callee.property.type !== 'Identifier') return false;\n return callee.property.name === GRANT_CALLEE;\n }\n return false;\n}\n\nfunction findSecretsAllowedProperty(obj: ObjectExpression): Property['value'] | null {\n for (const prop of obj.properties) {\n if (prop.type !== 'Property') continue;\n const property = prop as Property;\n const key = property.key;\n if (property.computed) continue;\n if (key.type === 'Identifier' && key.name === 'secretsAllowed') return property.value;\n if (key.type === 'Literal' && key.value === 'secretsAllowed') return property.value;\n }\n return null;\n}\n\nfunction isNonEmptyArray(value: Property['value']): boolean {\n if (value.type !== 'ArrayExpression') return false;\n const arr = value as ArrayExpression;\n return arr.elements.some((e) => e !== null);\n}\n\nfunction hasJustificationComment(context: Rule.RuleContext, node: CallExpression): boolean {\n return nodeHasNearbyComment(context, node, JUSTIFICATION_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-secret-unwrap` (DEC-020 / ADR-026 / Phase 16).\n *\n * Flags member expressions that look like an unprotected unwrap of a\n * `SecretValue` instance - `<expr>.unwrap()` and `<expr>.reveal()` -\n * outside an allow-listed context. The framework convention is:\n *\n * - Prefer `value.use(fn)` / `value.useBuffer(fn)` for scoped reads;\n * they limit the lifetime of the derived V8 string to a single\n * callback invocation.\n * - Use `value.reveal()` only as a one-shot escape hatch with an\n * adjacent justification. The audit log records the call.\n * - Never use `value.unwrap()` - it is `@deprecated` and is an alias\n * for `.reveal()` retained only for the v0.x compatibility window.\n * The rule reports `unwrap()` as `'error'` even when an\n * opt-out comment is present so the deprecation cliff stays sharp.\n *\n * Per-call opt-out: `// graphorin-allow-secret-unwrap: <reason>` on\n * the line above the call site or anywhere inside the enclosing\n * expression-statement source span. The opt-out is honoured for\n * `reveal()` but **not** for `unwrap()` (the deprecation supersedes\n * any local justification).\n *\n * The rule is intentionally lexical - it matches `.unwrap()` /\n * `.reveal()` on any `MemberExpression` regardless of the receiver\n * type. False positives are tolerated because (a) the receiver is\n * almost always a `SecretValue` in this codebase and (b) the\n * one-line opt-out is cheap.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type { CallExpression, Identifier, MemberExpression } from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-allow-secret-unwrap/;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow `.unwrap()` / `.reveal()` calls on `SecretValue` instances. Prefer `.use(fn)` (scoped) or attach a `// graphorin-allow-secret-unwrap: <reason>` opt-out comment for `.reveal()`.',\n recommended: true,\n },\n schema: [],\n messages: {\n avoidReveal:\n '`.reveal()` returns the unwrapped secret as a V8 string. Prefer `.use(fn)` so the value is scoped to a single callback. Add `// graphorin-allow-secret-unwrap: <reason>` to opt out.',\n avoidUnwrap:\n '`.unwrap()` is deprecated - call `.reveal()` (audited) or `.use(fn)` (scoped). The opt-out comment is intentionally NOT honoured for `.unwrap()` so the deprecation stays sharp.',\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n const callee = node.callee;\n if (callee.type !== 'MemberExpression') return;\n const me = callee as MemberExpression;\n if (me.computed) return;\n if (me.property.type !== 'Identifier') return;\n const propName = (me.property as Identifier).name;\n if (propName === 'unwrap') {\n context.report({\n node,\n messageId: 'avoidUnwrap',\n });\n return;\n }\n if (propName === 'reveal') {\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'avoidReveal',\n });\n }\n },\n };\n },\n};\n\nfunction hasAllowComment(context: Rule.RuleContext, node: CallExpression): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/no-third-party-workflow-aliases` (DEC-019 /\n * ADR-029). Flags any identifier in `@graphorin/workflow` source whose\n * name matches a known third-party workflow primitive (e.g. the\n * library-specific names that Graphorin deliberately renamed). The\n * intent is legal hygiene: the framework's primitives are\n * `Directive`, `Dispatch`, `pause`, `LatestValue`, `Reducer`,\n * `Stream`, `Barrier`, `Ephemeral`, `AnyValue` - we never reuse\n * external library identifiers in the public API.\n *\n * The forbidden list is intentionally narrow - we only flag the\n * canonical proper-noun primitives third-party workflow engines use.\n * Rare false positives (e.g. an internal helper named `Send` for an\n * unrelated reason) are mitigated by the per-occurrence opt-out\n * comment `// graphorin-workflow-naming-allow: <reason>`.\n *\n * The rule activates only on files inside the\n * `@graphorin/workflow` package source tree (path matcher\n * `packages/workflow/src`).\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type { Identifier, Node } from 'estree';\n\nimport { nodeHasNearbyComment } from './_comment-utils.js';\n\nconst ALLOW_TAG = /graphorin-workflow-naming-allow/;\nconst WORKFLOW_PATH_RE = /\\bpackages\\/workflow\\/src\\b/;\n\nconst FORBIDDEN_NAMES: ReadonlyMap<string, string> = new Map([\n ['Send', 'Dispatch'],\n ['Command', 'Directive'],\n ['interrupt', 'pause'],\n ['LastValue', 'LatestValue'],\n ['BinaryOperatorAggregate', 'Reducer'],\n ['BinaryAggregate', 'Reducer'],\n ['Topic', 'Stream'],\n]);\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow third-party workflow primitive identifiers in `@graphorin/workflow` source. Graphorin owns its primitive names per DEC-019.',\n recommended: true,\n },\n schema: [],\n messages: {\n forbidden:\n \"identifier '{{forbidden}}' is reserved for the third-party workflow library it originates from; use '{{replacement}}' (DEC-019).\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n if (!WORKFLOW_PATH_RE.test(context.filename.replace(/\\\\/g, '/'))) {\n return {};\n }\n return {\n Identifier(node: Identifier): void {\n const replacement = FORBIDDEN_NAMES.get(node.name);\n if (replacement === undefined) return;\n if (isInImportSpecifier(node)) return;\n if (hasAllowComment(context, node)) return;\n context.report({\n node,\n messageId: 'forbidden',\n data: {\n forbidden: node.name,\n replacement,\n },\n });\n },\n };\n },\n};\n\nfunction isInImportSpecifier(node: Identifier): boolean {\n // Skip identifiers used as keys / property names - those are\n // typically referencing external library exports the user is\n // intentionally importing into a renamed local symbol.\n const parent = (node as Identifier & { parent?: Node }).parent;\n if (parent === undefined) return false;\n switch (parent.type) {\n case 'ImportSpecifier':\n case 'ImportNamespaceSpecifier':\n case 'ImportDefaultSpecifier':\n case 'ExportSpecifier':\n return true;\n default:\n return false;\n }\n}\n\nfunction hasAllowComment(context: Rule.RuleContext, node: Identifier): boolean {\n return nodeHasNearbyComment(context, node, ALLOW_TAG, 1);\n}\n\nexport default rule;\n","/**\n * Rule: `@graphorin/provider-middleware-order` (DEC-145 / ADR-039).\n * Lint-time enforcement of the canonical middleware ordering for\n * `composeProviderMiddleware([...])`. Catches the same class of error\n * the runtime composer raises (`MiddlewareOrderingError`) without\n * requiring the runtime to actually wire the chain.\n *\n * The canonical order, outermost → innermost, mirrors the runtime\n * constant `CANONICAL_MIDDLEWARE_ORDER` exported by\n * `@graphorin/provider/middleware`. Built-ins not in the canonical\n * list are tolerated at any position.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\nimport type { ArrayExpression, CallExpression, Identifier, Node } from 'estree';\n\nconst CANONICAL_ORDER: ReadonlyArray<string> = [\n 'withTracing',\n 'withRetry',\n 'withRateLimit',\n 'withCostLimit',\n 'withCostTracking',\n 'withFallback',\n 'withRedaction',\n];\n\nconst CANONICAL_INDEX: ReadonlyMap<string, number> = new Map(\n CANONICAL_ORDER.map((name, idx) => [name, idx]),\n);\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Enforce the canonical provider-middleware ordering at lint time. Mirrors the runtime `MiddlewareOrderingError` from `@graphorin/provider/middleware`.',\n recommended: true,\n },\n schema: [],\n messages: {\n orderingViolation: \"'{{outer}}' must appear before '{{inner}}' (canonical order: {{order}}).\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n CallExpression(node: CallExpression): void {\n if (!isComposeCall(node)) return;\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== 'ArrayExpression') return;\n const factories = extractFactoryNames(arg as ArrayExpression);\n const recognised: { name: string; index: number; node: Node }[] = [];\n for (const f of factories) {\n const idx = CANONICAL_INDEX.get(f.name);\n if (idx !== undefined) recognised.push({ name: f.name, index: idx, node: f.node });\n }\n for (let i = 1; i < recognised.length; i++) {\n const prev = recognised[i - 1];\n const cur = recognised[i];\n if (prev !== undefined && cur !== undefined && prev.index > cur.index) {\n context.report({\n node: cur.node,\n messageId: 'orderingViolation',\n data: {\n outer: cur.name,\n inner: prev.name,\n order: CANONICAL_ORDER.join(' → '),\n },\n });\n }\n }\n },\n };\n },\n};\n\nfunction isComposeCall(node: CallExpression): boolean {\n if (node.callee.type === 'Identifier') {\n return (node.callee as Identifier).name === 'composeProviderMiddleware';\n }\n if (node.callee.type === 'MemberExpression') {\n const prop = node.callee.property;\n if (prop.type === 'Identifier' && prop.name === 'composeProviderMiddleware') return true;\n }\n return false;\n}\n\nfunction extractFactoryNames(arr: ArrayExpression): { name: string; node: Node }[] {\n const out: { name: string; node: Node }[] = [];\n for (const elt of arr.elements) {\n if (elt === null) continue;\n // Each element is one of:\n // - `withTracing()` / `withRetry({...})` - CallExpression with Identifier callee\n // - `withTracing` (factory ref) - Identifier\n // - `provider.withTracing()` - CallExpression with MemberExpression callee\n if (elt.type === 'Identifier') {\n out.push({ name: (elt as Identifier).name, node: elt });\n continue;\n }\n if (elt.type === 'CallExpression') {\n const callee = elt.callee;\n if (callee.type === 'Identifier') {\n out.push({ name: (callee as Identifier).name, node: elt });\n } else if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {\n out.push({ name: callee.property.name, node: elt });\n }\n }\n }\n return out;\n}\n\nexport default rule;\n","/**\n * Static `tool({...})` discovery + per-tool grader. Used by both the\n * three `tool-*` ESLint rules and by the `graphorin tools lint` CLI\n * subcommand (Phase 15) so the rule logic has a single source of\n * truth (per the working plan acceptance criteria for RB-49).\n *\n * The discovery is intentionally text-based - it scans a source\n * string for `tool(` call expressions and extracts the immediate\n * object literal that follows. The extractor handles the common\n * formatting cases (single-line, multi-line, nested object/array\n * literals, single + double-quoted strings, template literals) and\n * gracefully skips invocations whose argument shape it cannot\n * parse statically. The trade-off is documented: a project that\n * hides its `tool({...})` calls behind a builder helper or a\n * dynamic import will not be picked up by this lint surface; that\n * is the documented contract for the v0.1 lint surface.\n *\n * **Per-tool grader rubric (RB-49 calibration):**\n *\n * - **description axis (0..40 points):**\n * - 0 if missing / placeholder / shorter than 20 chars.\n * - 16 if length >= 20.\n * - 24 if length >= 30.\n * - 32 if length >= 50.\n * - 40 if length >= 80.\n * - **examples axis (0..30 points):**\n * - 0 if no examples or more than 5 (the documented upper bound).\n * - 12 base for 1 example, +6 per additional, capped at 30.\n * - -6 per PII finding (cap at 0).\n * - **parameter naming axis (0..30 points):**\n * - 30 base, deducted per finding.\n * - -30/N per ambiguous-name finding (full penalty per param).\n * - -10/N per numeric-suffix finding (partial penalty per param).\n * - 15 baseline when no parameters are discoverable.\n *\n * Total: 0..100 points. Calibrated against the RB-49 fixture\n * catalog so `wellDescribedTool` scores 82, `placeholderDescriptionTool`\n * scores 20, and `examplesPiiTool` scores 61.\n *\n * @stable\n */\n\n/**\n * @stable\n */\nexport interface DiscoveredTool {\n /** Source file the call was found in. */\n readonly file: string;\n /** 1-indexed line of the `tool(` token. */\n readonly line: number;\n /** Tool name extracted from the `name:` property when present. */\n readonly name: string;\n /** Tool description (`description:` value) when extractable. */\n readonly description?: string;\n /** Number of examples declared in the `examples:` array. */\n readonly examplesCount: number;\n /** Whether `examples:` is a non-empty array literal. */\n readonly hasExamples: boolean;\n /** Snapshot of identifiers referenced from the `inputSchema` Zod chain. */\n readonly parameterNames: ReadonlyArray<string>;\n /** Tags declared on the call (best-effort). */\n readonly tags: ReadonlyArray<string>;\n /**\n * Raw object-literal source. Useful for tests + as a context blob\n * when the CLI needs to surface the original source in a report.\n */\n readonly source: string;\n}\n\n/**\n * @stable\n */\nexport type LintFindingKind =\n | 'description-missing'\n | 'description-too-short'\n | 'description-placeholder'\n | 'examples-missing'\n | 'examples-too-many'\n | 'examples-pii-detected'\n | 'parameter-ambiguous'\n | 'parameter-numeric-suffix';\n\n/**\n * @stable\n */\nexport interface LintFinding {\n readonly rule:\n | 'graphorin/tool-description-required'\n | 'graphorin/tool-examples-recommended'\n | 'graphorin/tool-parameter-naming';\n readonly kind: LintFindingKind;\n readonly severity: 'error' | 'warn' | 'info';\n readonly message: string;\n readonly toolName: string;\n readonly file: string;\n readonly line: number;\n readonly hint?: string;\n /**\n * Optional matched-pattern context. Populated by the\n * `examples-pii-detected` finding so reports can highlight which\n * example payload triggered the rule.\n */\n readonly matchedPattern?: string;\n}\n\n/**\n * @stable\n */\nexport interface ToolGraderScore {\n readonly toolName: string;\n readonly file: string;\n readonly line: number;\n readonly score: number;\n readonly axes: {\n readonly description: number;\n readonly examples: number;\n readonly parameterNaming: number;\n };\n readonly findings: ReadonlyArray<LintFinding>;\n}\n\n/**\n * Generic identifiers the parameter-naming rule flags as ambiguous.\n * Tools whose `inputSchema` references only specific identifiers\n * (e.g. `userId`, `recipientEmail`, `apiKey`) get full credit on\n * the naming axis.\n *\n * @stable\n */\nexport const AMBIGUOUS_PARAMETER_NAMES: ReadonlyArray<string> = Object.freeze([\n 'user',\n 'id',\n 'name',\n 'value',\n 'data',\n 'input',\n 'output',\n 'result',\n 'to',\n 'from',\n 'key',\n 'field',\n]);\n\n/**\n * Tag values that, when present in a tool's `tags: [...]` literal,\n * suppress the parameter-naming rule for that tool. The opt-out\n * exists so operators can defer the rename for a long tail of\n * pre-RB-49 tools while the framework migrates without breaking\n * calling code.\n *\n * @stable\n */\nexport const PARAMETER_NAMING_OPT_OUT_TAGS: ReadonlyArray<string> = Object.freeze([\n 'experimental',\n 'legacy',\n]);\n\n/**\n * Placeholder values the description-required rule treats as\n * non-descriptions.\n *\n * @stable\n */\nexport const PLACEHOLDER_DESCRIPTIONS: ReadonlyArray<string> = Object.freeze([\n 'todo',\n 'fixme',\n 'tbd',\n 'description',\n 'placeholder',\n]);\n\nconst MIN_DESCRIPTION_LENGTH = 20;\nconst MAX_EXAMPLES = 5;\n\n/**\n * Discover every `tool({...})` invocation in a source string. The\n * returned findings are stable + frozen so callers can pass them\n * straight into a JSON report.\n *\n * @stable\n */\nexport function discoverToolCallsInSource(file: string, source: string): DiscoveredTool[] {\n const out: DiscoveredTool[] = [];\n const regex = /\\btool\\s*\\(\\s*\\{/g;\n let match: RegExpExecArray | null = regex.exec(source);\n while (match !== null) {\n const objectStart = match.index + match[0].length - 1;\n const objectEnd = matchBrace(source, objectStart);\n if (objectEnd > 0) {\n const literal = source.slice(objectStart, objectEnd + 1);\n const line = countLines(source, match.index);\n const tool = parseToolLiteral(file, line, literal);\n if (tool !== null) out.push(tool);\n }\n regex.lastIndex = objectEnd + 1;\n match = regex.exec(source);\n }\n return out;\n}\n\n/** Email PII pattern used by the examples-pii sub-check. */\nconst EMAIL_PATTERN = /[\\w.+%-]+@[\\w.-]+\\.[A-Za-z]{2,}/;\n\n/** Numeric-suffix pattern used by the parameter-naming sub-check. */\nconst NUMERIC_SUFFIX_PATTERN = /^[A-Za-z]+\\d+$/;\n\n/**\n * Run the three RB-49 rules against a discovered tool and return the\n * findings. The CLI grader maps these findings into per-axis scores;\n * the ESLint rules forward them to `context.report(...)`.\n *\n * @stable\n */\nexport function runToolRules(\n tool: DiscoveredTool,\n severityOverrides?: {\n readonly toolDescription?: 'error' | 'warn' | 'off';\n readonly toolExamples?: 'error' | 'warn' | 'off';\n readonly toolParameterNaming?: 'error' | 'warn' | 'off';\n },\n): LintFinding[] {\n const findings: LintFinding[] = [];\n\n const descSeverity = severityOverrides?.toolDescription ?? 'error';\n if (descSeverity !== 'off') {\n const desc = tool.description?.trim() ?? '';\n if (desc.length === 0) {\n findings.push(\n finding(\n 'graphorin/tool-description-required',\n 'description-missing',\n descSeverity,\n tool,\n `tool '${tool.name}' has no description; add a description that explains what the tool does and when to use it.`,\n ),\n );\n } else if (PLACEHOLDER_DESCRIPTIONS.includes(desc.toLowerCase())) {\n findings.push(\n finding(\n 'graphorin/tool-description-required',\n 'description-placeholder',\n descSeverity,\n tool,\n `tool '${tool.name}' description is a placeholder ('${tool.description}').`,\n ),\n );\n } else if (desc.length < MIN_DESCRIPTION_LENGTH) {\n findings.push(\n finding(\n 'graphorin/tool-description-required',\n 'description-too-short',\n descSeverity,\n tool,\n `tool '${tool.name}' description is shorter than ${MIN_DESCRIPTION_LENGTH} characters.`,\n ),\n );\n }\n }\n\n const examplesSeverity = severityOverrides?.toolExamples ?? 'warn';\n if (examplesSeverity !== 'off') {\n if (!tool.hasExamples || tool.examplesCount === 0) {\n findings.push(\n finding(\n 'graphorin/tool-examples-recommended',\n 'examples-missing',\n examplesSeverity,\n tool,\n `tool '${tool.name}' has no examples; add 1-5 worked examples per Anthropic 2026 guidance.`,\n ),\n );\n } else if (tool.examplesCount > MAX_EXAMPLES) {\n findings.push(\n finding(\n 'graphorin/tool-examples-recommended',\n 'examples-too-many',\n 'error',\n tool,\n `tool '${tool.name}' declares ${tool.examplesCount} examples; the upper bound is ${MAX_EXAMPLES}.`,\n ),\n );\n }\n // PII sub-check - fires once per matched email pattern in the\n // examples block. Operators usually want synthetic data, not real\n // addresses scraped from the corpus.\n const emailMatch = EMAIL_PATTERN.exec(extractExamplesBlock(tool.source));\n if (emailMatch !== null) {\n const matched = emailMatch[0] as string;\n findings.push(\n finding(\n 'graphorin/tool-examples-recommended',\n 'examples-pii-detected',\n 'error',\n tool,\n `tool '${tool.name}' example contains a real-looking email '${matched}'; replace with synthetic data (e.g. 'user@example.com').`,\n {\n matchedPattern: matched,\n hint: 'RB-49: examples must use synthetic test data so the rendered tool catalogue does not leak PII into provider context.',\n },\n ),\n );\n }\n }\n\n const namingSeverity = severityOverrides?.toolParameterNaming ?? 'warn';\n const namingOptedOut = tool.tags.some((t) => PARAMETER_NAMING_OPT_OUT_TAGS.includes(t));\n if (namingSeverity !== 'off' && !namingOptedOut) {\n for (const param of tool.parameterNames) {\n if (AMBIGUOUS_PARAMETER_NAMES.includes(param)) {\n findings.push(\n finding(\n 'graphorin/tool-parameter-naming',\n 'parameter-ambiguous',\n namingSeverity,\n tool,\n `tool '${tool.name}' uses ambiguous parameter name '${param}'; prefer a self-documenting name (e.g. '${param}Id', '${param}Email').`,\n ),\n );\n } else if (NUMERIC_SUFFIX_PATTERN.test(param)) {\n findings.push(\n finding(\n 'graphorin/tool-parameter-naming',\n 'parameter-numeric-suffix',\n namingSeverity,\n tool,\n `tool '${tool.name}' uses numeric-suffix parameter name '${param}'; prefer a semantic name (e.g. 'queryText', 'userId').`,\n ),\n );\n }\n }\n }\n\n return findings;\n}\n\n/**\n * Compute the per-tool grader score (0..100). Each axis is gated by\n * the findings produced for that axis. The rubric is calibrated\n * against the RB-49 fixture catalog (`wellDescribedTool` -> 82,\n * `placeholderDescriptionTool` -> 20, `examplesPiiTool` -> 61).\n *\n * @stable\n */\nexport function gradeTool(\n tool: DiscoveredTool,\n findings: ReadonlyArray<LintFinding>,\n): ToolGraderScore {\n const descFindings = findings.filter((f) => f.rule === 'graphorin/tool-description-required');\n const exampleFindings = findings.filter((f) => f.rule === 'graphorin/tool-examples-recommended');\n const namingFindings = findings.filter((f) => f.rule === 'graphorin/tool-parameter-naming');\n\n const description = scoreDescription(tool, descFindings);\n const examples = scoreExamples(tool, exampleFindings);\n const parameterNaming = scoreParameterNaming(tool, namingFindings);\n\n return Object.freeze({\n toolName: tool.name,\n file: tool.file,\n line: tool.line,\n score: description + examples + parameterNaming,\n axes: Object.freeze({ description, examples, parameterNaming }),\n findings,\n });\n}\n\nfunction scoreDescription(tool: DiscoveredTool, findings: ReadonlyArray<LintFinding>): number {\n if (findings.length > 0) return 0;\n const desc = tool.description?.trim() ?? '';\n if (desc.length >= 80) return 40;\n if (desc.length >= 50) return 32;\n if (desc.length >= 30) return 24;\n if (desc.length >= MIN_DESCRIPTION_LENGTH) return 16;\n return 0;\n}\n\nfunction scoreExamples(tool: DiscoveredTool, findings: ReadonlyArray<LintFinding>): number {\n if (tool.examplesCount === 0) return 0;\n if (tool.examplesCount > MAX_EXAMPLES) return 0;\n // 12 base for the first example + 6 per additional, cap at 30. This\n // calibration produces wellDescribedTool == 12 (1 example) and\n // placeholderDescriptionTool == 0 (no examples). Each PII finding\n // subtracts 6 from the axis (cap at 0) so examplesPiiTool ends up\n // with 6 (12 base - 6 PII penalty).\n const base = Math.min(30, 12 + (tool.examplesCount - 1) * 6);\n const piiCount = findings.filter((f) => f.kind === 'examples-pii-detected').length;\n return Math.max(0, base - piiCount * 6);\n}\n\nfunction scoreParameterNaming(tool: DiscoveredTool, findings: ReadonlyArray<LintFinding>): number {\n if (tool.parameterNames.length === 0) {\n // No discoverable params - neither a positive nor a negative\n // signal. Award the median.\n return 15;\n }\n const total = tool.parameterNames.length;\n const ambiguousCount = findings.filter((f) => f.kind === 'parameter-ambiguous').length;\n const numericCount = findings.filter((f) => f.kind === 'parameter-numeric-suffix').length;\n // Full penalty for an ambiguous-name finding (`user`, `id`, `to`, …):\n // -30/N. Partial penalty for a numeric-suffix finding (`arg1`,\n // `param2`, …): -10/N. Calibrated so a single-param `arg1` scores\n // 20 (placeholderDescriptionTool) and a two-param `to`-+-`body`\n // scores 15 (examplesPiiTool).\n const score = 30 - (30 / total) * ambiguousCount - (10 / total) * numericCount;\n return Math.max(0, Math.round(score));\n}\n\nfunction finding(\n rule: LintFinding['rule'],\n kind: LintFindingKind,\n severity: 'error' | 'warn',\n tool: DiscoveredTool,\n message: string,\n extra: { readonly hint?: string; readonly matchedPattern?: string } = {},\n): LintFinding {\n return Object.freeze({\n rule,\n kind,\n severity,\n message,\n toolName: tool.name,\n file: tool.file,\n line: tool.line,\n ...(extra.hint !== undefined ? { hint: extra.hint } : {}),\n ...(extra.matchedPattern !== undefined ? { matchedPattern: extra.matchedPattern } : {}),\n });\n}\n\n/**\n * Extract the substring inside the `examples: [...]` array literal so\n * the PII detector can scan only the example payloads (not the rest of\n * the tool body).\n *\n * @internal\n */\nfunction extractExamplesBlock(literal: string): string {\n const m = /examples\\s*:\\s*\\[/.exec(literal);\n if (m === null) return '';\n const start = m.index + m[0].length - 1;\n const end = matchBracket(literal, start);\n if (end < 0) return '';\n return literal.slice(start + 1, end);\n}\n\n/**\n * Parse a string literal value from the immediate object literal.\n * Supports `'`, `\"`, and template strings (without interpolation).\n *\n * @internal\n */\nfunction readStringProp(literal: string, prop: string): string | undefined {\n const escapedProp = prop.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|[\\\\s,{])${escapedProp}\\\\s*:\\\\s*(['\"\\`])`, 'm');\n const m = re.exec(literal);\n if (m === null) return undefined;\n const quote = m[1] as string;\n const start = m.index + m[0].length;\n let i = start;\n let out = '';\n while (i < literal.length) {\n const ch = literal[i] as string;\n if (ch === '\\\\' && i + 1 < literal.length) {\n out += literal[i + 1];\n i += 2;\n continue;\n }\n if (ch === quote) return out;\n out += ch;\n i += 1;\n }\n return undefined;\n}\n\n/**\n * Count entries in an array literal value of the form `prop: [...]`.\n *\n * @internal\n */\nfunction countArrayProp(\n literal: string,\n prop: string,\n): { readonly count: number; readonly present: boolean } {\n const escapedProp = prop.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const re = new RegExp(`(?:^|[\\\\s,{])${escapedProp}\\\\s*:\\\\s*\\\\[`, 'm');\n const m = re.exec(literal);\n if (m === null) return { count: 0, present: false };\n const start = m.index + m[0].length - 1;\n const end = matchBracket(literal, start);\n if (end < 0) return { count: 0, present: true };\n // Strip a trailing comma so it does not inflate the count.\n const inner = literal\n .slice(start + 1, end)\n .trim()\n .replace(/,\\s*$/, '');\n if (inner.length === 0) return { count: 0, present: true };\n // Count top-level commas (depth + string aware).\n let depth = 0;\n let inString: '\"' | \"'\" | '`' | null = null;\n let count = 1;\n for (let i = 0; i < inner.length; i += 1) {\n const ch = inner[i] as string;\n if (inString !== null) {\n if (ch === '\\\\') {\n i += 1;\n continue;\n }\n if (ch === inString) inString = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n inString = ch as '\"' | \"'\" | '`';\n continue;\n }\n if (ch === '(' || ch === '[' || ch === '{') depth += 1;\n else if (ch === ')' || ch === ']' || ch === '}') depth -= 1;\n else if (ch === ',' && depth === 0) count += 1;\n }\n return { count, present: true };\n}\n\n/**\n * Extract identifiers passed into a `z.object({...})` schema as\n * top-level keys.\n *\n * @internal\n */\nfunction extractParameterNames(literal: string): string[] {\n const m = /inputSchema\\s*:\\s*z\\s*\\.\\s*object\\s*\\(\\s*\\{/.exec(literal);\n if (m === null) return [];\n const start = m.index + m[0].length - 1;\n const end = matchBrace(literal, start);\n if (end < 0) return [];\n const inner = literal.slice(start + 1, end);\n const names: string[] = [];\n const idRegex = /(^|[\\s,{])([A-Za-z_$][A-Za-z0-9_$]*)\\s*:/g;\n let id = idRegex.exec(inner);\n while (id !== null) {\n const name = id[2] as string;\n if (!names.includes(name)) names.push(name);\n id = idRegex.exec(inner);\n }\n return names;\n}\n\nfunction parseToolLiteral(file: string, line: number, literal: string): DiscoveredTool | null {\n const name = readStringProp(literal, 'name') ?? '<anonymous>';\n const description = readStringProp(literal, 'description');\n const examples = countArrayProp(literal, 'examples');\n const tagsArr = countArrayProp(literal, 'tags');\n const tags: string[] = [];\n if (tagsArr.present && tagsArr.count > 0) {\n const m = /tags\\s*:\\s*\\[([^\\]]*)\\]/.exec(literal);\n if (m !== null) {\n const inner = (m[1] as string) ?? '';\n const tagRegex = /['\"`]([^'\"`]+)['\"`]/g;\n let t = tagRegex.exec(inner);\n while (t !== null) {\n tags.push(t[1] as string);\n t = tagRegex.exec(inner);\n }\n }\n }\n const parameterNames = extractParameterNames(literal);\n return Object.freeze({\n file,\n line,\n name,\n ...(description !== undefined ? { description } : {}),\n examplesCount: examples.count,\n hasExamples: examples.present,\n parameterNames: Object.freeze(parameterNames),\n tags: Object.freeze(tags),\n source: literal,\n });\n}\n\nfunction countLines(source: string, index: number): number {\n let n = 1;\n for (let i = 0; i < index; i += 1) {\n if (source[i] === '\\n') n += 1;\n }\n return n;\n}\n\nfunction matchBrace(source: string, openIndex: number): number {\n return matchPair(source, openIndex, '{', '}');\n}\n\nfunction matchBracket(source: string, openIndex: number): number {\n return matchPair(source, openIndex, '[', ']');\n}\n\nfunction matchPair(source: string, openIndex: number, open: string, close: string): number {\n let depth = 0;\n let inString: '\"' | \"'\" | '`' | null = null;\n for (let i = openIndex; i < source.length; i += 1) {\n const ch = source[i] as string;\n if (inString !== null) {\n if (ch === '\\\\') {\n i += 1;\n continue;\n }\n if (ch === inString) inString = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n inString = ch as '\"' | \"'\" | '`';\n continue;\n }\n if (ch === open) depth += 1;\n else if (ch === close) {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n}\n","/**\n * Rule: `@graphorin/tool-description-required` (RB-49 / suggested\n * DEC-165). Flags `tool({...})` invocations whose `description`\n * field is missing, too short (< 20 characters), or a placeholder\n * value (`'TODO'` / `'FIXME'` / `'tbd'` / `'description'` /\n * `'placeholder'`, case-insensitive).\n *\n * The rule shares its discovery + scoring code with the\n * `graphorin tools lint` CLI subcommand (Phase 15) so the rule\n * logic has a single source of truth.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\n\nimport { discoverToolCallsInSource, PLACEHOLDER_DESCRIPTIONS } from '../tool-discovery.js';\n\nconst MIN_DESCRIPTION_LENGTH = 20;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require a meaningful `description` on every `tool({...})` registration. RB-49 (Anthropic 2026 advanced tool use guidance).',\n recommended: true,\n },\n schema: [],\n messages: {\n missing:\n \"tool '{{name}}' has no description; add a description that explains what the tool does and when to use it.\",\n tooShort:\n \"tool '{{name}}' description is shorter than {{min}} characters (currently {{len}}).\",\n placeholder: \"tool '{{name}}' description is a placeholder ('{{value}}').\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n 'Program:exit'(): void {\n const filename = context.filename;\n const source = context.sourceCode.text;\n const tools = discoverToolCallsInSource(filename, source);\n for (const tool of tools) {\n const desc = tool.description?.trim();\n if (desc === undefined || desc.length === 0) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'missing',\n data: { name: tool.name },\n });\n } else if (desc.length < MIN_DESCRIPTION_LENGTH) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'tooShort',\n data: {\n name: tool.name,\n min: String(MIN_DESCRIPTION_LENGTH),\n len: String(desc.length),\n },\n });\n } else if (PLACEHOLDER_DESCRIPTIONS.includes(desc.toLowerCase())) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'placeholder',\n data: { name: tool.name, value: desc },\n });\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n","/**\n * Rule: `@graphorin/tool-examples-recommended` (RB-49). Flags\n * `tool({...})` invocations whose `examples` field is missing,\n * empty, or longer than the documented upper bound (5).\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\n\nimport { discoverToolCallsInSource } from '../tool-discovery.js';\n\nconst MAX_EXAMPLES = 5;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Recommend 1-5 `examples` entries on every `tool({...})` registration (Anthropic 2026 'Writing effective tools' guidance).\",\n recommended: true,\n },\n schema: [],\n messages: {\n missing:\n \"tool '{{name}}' has no examples; add 1-5 worked examples per Anthropic 2026 guidance.\",\n tooMany:\n \"tool '{{name}}' declares {{count}} examples; the documented upper bound is {{max}}.\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n 'Program:exit'(): void {\n const filename = context.filename;\n const source = context.sourceCode.text;\n const tools = discoverToolCallsInSource(filename, source);\n for (const tool of tools) {\n if (!tool.hasExamples || tool.examplesCount === 0) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'missing',\n data: { name: tool.name },\n });\n } else if (tool.examplesCount > MAX_EXAMPLES) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'tooMany',\n data: {\n name: tool.name,\n count: String(tool.examplesCount),\n max: String(MAX_EXAMPLES),\n },\n });\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n","/**\n * Rule: `@graphorin/tool-parameter-naming` (RB-49). Inspects the\n * `inputSchema: z.object({...})` declaration of every `tool({...})`\n * invocation and flags two anti-patterns:\n *\n * - **Ambiguous single-word identifiers** (`user`, `id`, `name`,\n * `value`, `data`, `input`, `output`, `result`, `to`, `from`,\n * `key`, `field`). Suggest a self-documenting alternative.\n * - **Numeric-suffix identifiers** (`arg1`, `arg2`, `param3`).\n * Suggest a semantic name.\n *\n * Per-tool opt-out: when the tool declares `tags: ['experimental']`\n * or `tags: ['legacy']` the rule is suppressed for that registration.\n * This lets operators defer the rename for a long tail of pre-RB-49\n * tools while the framework migrates without breaking calling code.\n *\n * @packageDocumentation\n */\n\nimport type { Rule } from 'eslint';\n\nimport {\n AMBIGUOUS_PARAMETER_NAMES,\n discoverToolCallsInSource,\n PARAMETER_NAMING_OPT_OUT_TAGS,\n} from '../tool-discovery.js';\n\nconst NUMERIC_SUFFIX_PATTERN = /^[A-Za-z]+\\d+$/;\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Flag ambiguous or numeric-suffix parameter names on `tool({...})` `inputSchema` declarations (RB-49 - write self-documenting parameter names).',\n recommended: true,\n },\n schema: [],\n messages: {\n ambiguous:\n \"tool '{{name}}' uses ambiguous parameter name '{{param}}'; prefer a self-documenting name (e.g. '{{param}}Id', '{{param}}Email').\",\n numericSuffix:\n \"tool '{{name}}' uses numeric-suffix parameter name '{{param}}'; prefer a semantic name (e.g. 'queryText', 'userId').\",\n },\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n return {\n 'Program:exit'(): void {\n const filename = context.filename;\n const source = context.sourceCode.text;\n const tools = discoverToolCallsInSource(filename, source);\n for (const tool of tools) {\n if (tool.tags.some((t) => PARAMETER_NAMING_OPT_OUT_TAGS.includes(t))) continue;\n for (const param of tool.parameterNames) {\n if (AMBIGUOUS_PARAMETER_NAMES.includes(param)) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'ambiguous',\n data: { name: tool.name, param },\n });\n } else if (NUMERIC_SUFFIX_PATTERN.test(param)) {\n context.report({\n loc: { line: tool.line, column: 0 },\n messageId: 'numericSuffix',\n data: { name: tool.name, param },\n });\n }\n }\n }\n },\n };\n },\n};\n\nexport default rule;\n","/**\n * @graphorin/eslint-plugin - ESLint plugin for projects that build on\n * the Graphorin framework.\n *\n * Phase 16 final ruleset:\n *\n * - `no-secret-unwrap` - DEC-020 / ADR-026. Active.\n * - `no-secret-in-deps` - DEC-137. Active.\n * - `provider-middleware-order` - DEC-145 / ADR-039. Active.\n * - `no-implicit-network-call` - DEC-154 / ADR-041. Active.\n * - `no-third-party-workflow-aliases` - DEC-019 / ADR-029. Active.\n * - `no-bare-tool-exec` - principle 3 / DEC-143. Active.\n * - `tool-description-required` - Active.\n * - `tool-examples-recommended` - Active.\n * - `tool-parameter-naming` - Active.\n *\n * (The former `no-console-in-public-api` scaffold - a permanent no-op\n * since Phase 01 - was removed in the v0.4 hygiene pass (PS-21) rather\n * than shipped inert.)\n *\n * @packageDocumentation\n */\n\nimport noBareToolExec from './rules/no-bare-tool-exec.js';\nimport noImplicitNetworkCall from './rules/no-implicit-network-call.js';\nimport noSecretInDeps from './rules/no-secret-in-deps.js';\nimport noSecretUnwrap from './rules/no-secret-unwrap.js';\nimport noThirdPartyWorkflowAliases from './rules/no-third-party-workflow-aliases.js';\nimport providerMiddlewareOrder from './rules/provider-middleware-order.js';\nimport toolDescriptionRequired from './rules/tool-description-required.js';\nimport toolExamplesRecommended from './rules/tool-examples-recommended.js';\nimport toolParameterNaming from './rules/tool-parameter-naming.js';\n\nexport const VERSION = '0.6.0';\n\nexport const meta = {\n name: '@graphorin/eslint-plugin',\n version: VERSION,\n} as const;\n\nexport const rules = {\n 'no-bare-tool-exec': noBareToolExec,\n 'no-implicit-network-call': noImplicitNetworkCall,\n 'no-secret-in-deps': noSecretInDeps,\n 'no-secret-unwrap': noSecretUnwrap,\n 'no-third-party-workflow-aliases': noThirdPartyWorkflowAliases,\n 'provider-middleware-order': providerMiddlewareOrder,\n 'tool-description-required': toolDescriptionRequired,\n 'tool-examples-recommended': toolExamplesRecommended,\n 'tool-parameter-naming': toolParameterNaming,\n} as const;\n\n/** Shared severity map for both the legacy and flat recommended presets. */\nconst RECOMMENDED_RULES = {\n '@graphorin/no-bare-tool-exec': 'warn',\n '@graphorin/no-implicit-network-call': 'error',\n '@graphorin/no-secret-in-deps': 'error',\n '@graphorin/no-secret-unwrap': 'error',\n '@graphorin/no-third-party-workflow-aliases': 'error',\n '@graphorin/provider-middleware-order': 'error',\n '@graphorin/tool-description-required': 'error',\n '@graphorin/tool-examples-recommended': 'warn',\n '@graphorin/tool-parameter-naming': 'warn',\n} as const;\n\n/**\n * PS-17: ship BOTH config shapes. `recommended` is the legacy `.eslintrc` form\n * (`plugins: ['@graphorin']`); `flat/recommended` is the ESLint 9+ flat-config\n * form that maps the namespace to the plugin object, so flat-config consumers\n * can `...plugin.configs['flat/recommended']` instead of hand-wiring ten rules.\n */\nconst plugin: {\n readonly meta: typeof meta;\n readonly rules: typeof rules;\n readonly configs: {\n readonly recommended: {\n readonly plugins: readonly string[];\n readonly rules: typeof RECOMMENDED_RULES;\n };\n readonly 'flat/recommended': {\n plugins: Record<string, unknown>;\n readonly rules: typeof RECOMMENDED_RULES;\n };\n };\n} = {\n meta,\n rules,\n configs: {\n recommended: { plugins: ['@graphorin'], rules: RECOMMENDED_RULES },\n // `plugins` is filled in below - the flat form maps the namespace to the\n // plugin object itself, which must exist first.\n 'flat/recommended': { plugins: {}, rules: RECOMMENDED_RULES },\n },\n};\nplugin.configs['flat/recommended'].plugins = { '@graphorin': plugin };\n\nexport const configs = plugin.configs;\n\nexport {\n AMBIGUOUS_PARAMETER_NAMES,\n type DiscoveredTool,\n discoverToolCallsInSource,\n gradeTool,\n type LintFinding,\n type LintFindingKind,\n PARAMETER_NAMING_OPT_OUT_TAGS,\n PLACEHOLDER_DESCRIPTIONS,\n runToolRules,\n type ToolGraderScore,\n} from './tool-discovery.js';\n\nexport default plugin;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@graphorin/eslint-plugin",
3
- "version": "0.5.0",
4
- "description": "ESLint plugin for projects that build on Graphorin. Ships scaffolds for the eventual public ruleset; full implementations land in later releases.",
3
+ "version": "0.6.0",
4
+ "description": "ESLint plugin for projects that build on Graphorin. Ships nine active rules: tool-definition quality (descriptions, examples, parameter naming), secret-handling discipline (no-secret-unwrap, no-secret-in-deps), network hygiene (no-implicit-network-call), provider middleware ordering, tool cancellation propagation, and workflow naming.",
5
5
  "license": "MIT",
6
6
  "author": "Oleksiy Stepurenko",
7
7
  "homepage": "https://github.com/o-stepper/graphorin/tree/main/packages/eslint-plugin",
@@ -30,7 +30,8 @@
30
30
  ".": {
31
31
  "types": "./dist/index.d.ts",
32
32
  "import": "./dist/index.js"
33
- }
33
+ },
34
+ "./package.json": "./package.json"
34
35
  },
35
36
  "files": [
36
37
  "dist",