@graphorin/eslint-plugin 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @graphorin/eslint-plugin
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#142](https://github.com/o-stepper/graphorin/pull/142) [`436d6ca`](https://github.com/o-stepper/graphorin/commit/436d6ca5ebbd16df094e915682d3915c279a8430) Thanks [@o-stepper](https://github.com/o-stepper)! - Version constants and version-bearing strings now derive from each package's manifest at build time (`VERSION = pkg.version`; writer ids, client/server info, OTLP framework attributes, build-info metrics interpolate it). No behavioral change at the current version: the rendered strings are byte-identical. A release bump no longer edits source; the new `check-version-consistency` gate fails any reintroduced hardcoded framework version.
|
|
8
|
+
|
|
3
9
|
## 0.6.0
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> ESLint rules for projects that build on **Graphorin**.
|
|
4
4
|
|
|
5
|
-
- **Status:** v0.6.
|
|
5
|
+
- **Status:** v0.6.1 - final Phase 16 ruleset.
|
|
6
6
|
- **License:** [MIT](./LICENSE) - © 2026 Oleksiy Stepurenko.
|
|
7
7
|
- **Engines:** Node.js 22+ (ESM only).
|
|
8
8
|
- **Peer dependency:** `eslint >= 9`.
|
|
@@ -94,4 +94,4 @@ for (const tool of tools) {
|
|
|
94
94
|
|
|
95
95
|
---
|
|
96
96
|
|
|
97
|
-
**Graphorin** · v0.6.
|
|
97
|
+
**Graphorin** · v0.6.1 · MIT License · © 2026 Oleksiy Stepurenko · <https://github.com/o-stepper/graphorin>
|
package/dist/index.d.ts
CHANGED
|
@@ -186,10 +186,10 @@ declare function gradeTool(tool: DiscoveredTool, findings: ReadonlyArray<LintFin
|
|
|
186
186
|
*
|
|
187
187
|
* @packageDocumentation
|
|
188
188
|
*/
|
|
189
|
-
declare const VERSION
|
|
189
|
+
declare const VERSION: string;
|
|
190
190
|
declare const meta: {
|
|
191
191
|
readonly name: "@graphorin/eslint-plugin";
|
|
192
|
-
readonly version:
|
|
192
|
+
readonly version: string;
|
|
193
193
|
};
|
|
194
194
|
declare const rules: {
|
|
195
195
|
readonly 'no-bare-tool-exec': eslint0.Rule.RuleModule;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/tool-discovery.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6CA;AA2BA;AAaA;AAuBA;AAqBA;AAwBA;AAWA;AAkBA;AAgCA;AAkIA;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/tool-discovery.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;AA6CA;AA2BA;AAaA;AAuBA;AAqBA;AAwBA;AAWA;AAkBA;AAgCA;AAkIA;;;;;;;;;ACtTA;AAEA;AAKA;;;;;;;;;;;AAUW;AAaD;;;;;;;AAiCV;;AAhBe,UDpCE,cAAA,CCoCF;EACc;EAAiB,SAAA,IAAA,EAAA,MAAA;;;;;;;;;;;;2BDvBnB;;iBAEV;;;;;;;;;;KAWL,eAAA;;;;UAaK,WAAA;;iBAKA;;;;;;;;;;;;;;;;;UAkBA,eAAA;;;;;;;;;;qBAUI,cAAc;;;;;;;;;;cAWtB,2BAA2B;;;;;;;;;;cAwB3B,+BAA+B;;;;;;;cAW/B,0BAA0B;;;;;;;;iBAkBvB,yBAAA,gCAAyD;;;;;;;;iBAgCzD,YAAA,OACR;;;;IAML;;;;;;;;;iBA2Ha,SAAA,OACR,0BACI,cAAc,eACvB;;;;;;AA9SH;AA2BA;AAaA;AAuBA;AAqBA;AAwBA;AAWA;AAkBA;AAgCA;AAkIA;;;;;;;;;ACtTA;AAEa,cAFA,OAKH,EAAA,MAAA;AAEG,cALA,IAeH,EAAA;;;;cAVG;;;;;;;EAaP,SAAA,2BAUI,yBAAA;EAQJ,SAsBL,2BAAA,yBAAA;EArBuB,SAAA,uBAAA,yBAAA;CACC;;cApBnB,iBA2BS,EAAA;EACc,SAAA,8BAAA,EAAA,MAAA;EAAiB,SAAA,qCAAA,EAAA,OAAA;EAejC,SAAA,8BAAwB,EAAA,OAAA;EAnBR,SAAA,6BAAA,EAAA,OAAA;EAGd,SAAA,4CAAA,EAAA,OAAA;EACc,SAAA,sCAAA,EAAA,OAAA;EAAiB,SAAA,sCAAA,EAAA,OAAA;;;;;;;;;;cAVxC;wBACkB;yBACC;;;;6BAII;;;eAGd;6BACc;;;;cAehB;;;2BAnBgB;;;aAGd;2BACc"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
//#region package.json
|
|
2
|
+
var version = "0.6.1";
|
|
3
|
+
|
|
4
|
+
//#endregion
|
|
1
5
|
//#region src/rules/_comment-utils.ts
|
|
2
6
|
/**
|
|
3
7
|
* Returns `true` when the source contains a comment whose `value`
|
|
@@ -1027,7 +1031,7 @@ var tool_parameter_naming_default = rule;
|
|
|
1027
1031
|
*
|
|
1028
1032
|
* @packageDocumentation
|
|
1029
1033
|
*/
|
|
1030
|
-
const VERSION =
|
|
1034
|
+
const VERSION = version;
|
|
1031
1035
|
const meta = {
|
|
1032
1036
|
name: "@graphorin/eslint-plugin",
|
|
1033
1037
|
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 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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"}
|
|
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","VERSION: string","pkg.version","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":["../package.json","../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 \"name\": \"@graphorin/eslint-plugin\",\n \"version\": \"0.6.1\",\n \"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.\",\n \"license\": \"MIT\",\n \"author\": \"Oleksiy Stepurenko\",\n \"homepage\": \"https://github.com/o-stepper/graphorin/tree/main/packages/eslint-plugin\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/o-stepper/graphorin.git\",\n \"directory\": \"packages/eslint-plugin\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/o-stepper/graphorin/issues\"\n },\n \"keywords\": [\n \"graphorin\",\n \"eslint\",\n \"eslintplugin\",\n \"eslint-plugin\"\n ],\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=22.0.0\"\n },\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit && tsc -p tsconfig.tests.json\",\n \"test\": \"vitest run\",\n \"lint\": \"biome check .\",\n \"clean\": \"rimraf dist .turbo *.tsbuildinfo\"\n },\n \"peerDependencies\": {\n \"eslint\": \">=9.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"eslint\": {\n \"optional\": false\n }\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"provenance\": true\n },\n \"devDependencies\": {\n \"@types/eslint\": \"^9.6.1\",\n \"@types/estree\": \"^1.0.9\",\n \"eslint\": \"^10.3.0\"\n }\n}\n","/**\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 pkg from '../package.json' with { type: 'json' };\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: string = pkg.version;\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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphorin/eslint-plugin",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
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",
|