@ai-matrx/code-runtime 0.1.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/gate.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gate.ts","../src/gate-lists.json"],"sourcesContent":["/**\n * `@ai-matrx/code-runtime/gate` — THE ONE source gate for stored code.\n *\n * Every writer of stored component code (kind components, tool and emit\n * renderers, Applet files) runs `gate(files)` before the write; a database\n * trigger is the backstop and aidream's `kind_shared.py` is the Python twin.\n * The lists are DATA in `gate-lists.json` (exported as\n * `@ai-matrx/code-runtime/gate-lists.json`) so all three runtimes compare the\n * same bytes; parity tests on each side read this file.\n *\n * Moved here verbatim in behavior from matrx-frontend\n * `features/agent-apps/utils/component-source-gate.ts` (Q82 / B-17, DD-124),\n * widened to multi-file sources: a relative import must name a file in the\n * set, and every finding carries its file and line.\n *\n * WHAT THIS IS NOT: a sandbox. A string check cannot stop every escape, and\n * the runtime stubs shadow bare identifiers only. Real isolation is the\n * sandbox frame (opaque origin, `connect-src 'none'`).\n *\n * Pure: no React, no Babel — safe for servers, workers and write paths.\n */\nimport lists from \"./gate-lists.json\";\nimport type { Finding } from \"./types\";\n\nexport type { Finding } from \"./types\";\n\n/** Every module stored code may import (the documented scope registry). */\nexport const GATE_ALLOWED_IMPORTS: readonly string[] = lists.allowedImports;\n/** Globals stored code may never name as a bare identifier. */\nexport const GATE_BANNED_GLOBALS: readonly string[] = lists.bannedGlobals;\n/** Evaluators banned where called or constructed (`eval(`, `new Function(`). */\nexport const GATE_BANNED_CALLABLES: readonly string[] = lists.bannedCallables;\n/** Names banned as a property read (`window.fetch`, `document.cookie`). */\nexport const GATE_BANNED_MEMBER_ACCESS: readonly string[] = lists.bannedMemberAccess;\n/** Names banned as a method call on any object (`.constructor(`). */\nexport const GATE_BANNED_MEMBER_CALLS: readonly string[] = lists.bannedMemberCalls;\n/** Roots on which bracket access is refused (`window[\"fet\"+\"ch\"]`). */\nexport const GATE_BANNED_COMPUTED_ACCESS: readonly string[] = lists.bannedComputedAccess;\n/** Named syntax rules every runtime implements (`dynamicImport`). */\nexport const GATE_BANNED_SYNTAX: readonly string[] = lists.bannedSyntax;\n\n/** The raw lists, for parity tests and the database trigger's generator. */\nexport const GATE_LISTS = lists;\n\nconst IMPORT_RE = /^\\s*import\\s+(?:[^'\"]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/gm;\nconst EXPORT_FROM_RE = /^\\s*export\\s+(?:\\*|\\{[^}]*\\})\\s+from\\s+['\"]([^'\"]+)['\"]/gm;\nconst DYNAMIC_IMPORT_RE = /(?<![.\\w$])import\\s*\\(/g;\n\nfunction escapeForRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction lineAt(source: string, index: number): number {\n let line = 1;\n for (let i = 0; i < index && i < source.length; i++) {\n if (source.charCodeAt(i) === 10) line++;\n }\n return line;\n}\n\n/** Normalize a relative specifier against the importing file, without extension guessing. */\nexport function resolveRelativePath(fromFile: string, specifier: string): string {\n const base = fromFile.split(\"/\").slice(0, -1);\n for (const part of specifier.split(\"/\")) {\n if (part === \"\" || part === \".\") continue;\n if (part === \"..\") base.pop();\n else base.push(part);\n }\n return base.join(\"/\");\n}\n\nconst RESOLVE_SUFFIXES = [\"\", \".tsx\", \".ts\", \".jsx\", \".js\", \".json\", \"/index.tsx\", \"/index.ts\", \"/index.jsx\", \"/index.js\"];\n\n/** The file in `files` a relative specifier names, or null. */\nexport function resolveRelativeFile(\n files: Readonly<Record<string, string>>,\n fromFile: string,\n specifier: string,\n): string | null {\n const target = resolveRelativePath(fromFile, specifier);\n for (const suffix of RESOLVE_SUFFIXES) {\n const candidate = `${target}${suffix}`;\n if (Object.prototype.hasOwnProperty.call(files, candidate)) return candidate;\n }\n return null;\n}\n\n/** The module paths a source imports, in source order, de-duplicated. */\nexport function importPaths(source: string): string[] {\n const found = new Set<string>();\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source ?? \"\")) !== null) {\n if (match[1]) found.add(match[1]);\n }\n }\n return [...found];\n}\n\nconst ALLOWED_SENTENCE =\n \"Rewrite it using only the documented scope (react, lucide-react, recharts, \" +\n \"@ai-matrx/design-system/controls, @ai-matrx/design-system, @/lib/utils, \" +\n \"@/components/ui/*, @/components/kind-kit/*, CopyButtons/CopyForAiButton, Markdown) \" +\n \"or a file of this component.\";\n\nfunction importFindings(files: Readonly<Record<string, string>>, file: string, source: string): Finding[] {\n const out: Finding[] = [];\n const allowed = new Set(GATE_ALLOWED_IMPORTS);\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source)) !== null) {\n const path = match[1] ?? \"\";\n const line = lineAt(source, match.index + match[0].indexOf(path));\n if (path.startsWith(\"./\") || path.startsWith(\"../\")) {\n if (!resolveRelativeFile(files, file, path)) {\n out.push({\n rule: \"relative-import-missing\",\n file,\n line,\n severity: \"refuse\",\n message: `This file imports \"${path}\", but no file of this component has that name. Add the file or fix the path.`,\n });\n }\n continue;\n }\n if (!allowed.has(path)) {\n out.push({\n rule: \"import-not-allowed\",\n file,\n line,\n severity: \"refuse\",\n message: `This component imports \"${path}\", which is outside the sandbox scope, so it would render as a marked placeholder. ${ALLOWED_SENTENCE}`,\n });\n }\n }\n }\n DYNAMIC_IMPORT_RE.lastIndex = 0;\n const dyn = DYNAMIC_IMPORT_RE.exec(source);\n if (dyn) {\n out.push({\n rule: \"dynamicImport\",\n file,\n line: lineAt(source, dyn.index),\n severity: \"refuse\",\n message:\n \"This component uses a dynamic import(). The in-page compiler has no module loader, so the call would either fail at render or reach code nobody vetted. Import from the scope at the top of the file instead.\",\n });\n }\n return out;\n}\n\nfunction bannedGlobalMessage(name: string): string {\n return (\n `This component uses \"${name}\", which components stored in the database may ` +\n \"not use. They run inside the signed-in page, so anything that reaches the \" +\n \"network, browser storage, or the JavaScript evaluator could read or send \" +\n \"the reader's data. Render what the Shape hands you in props.data and use \" +\n \"a Shape action for anything the component needs from the server.\"\n );\n}\n\nfunction bannedMemberCallMessage(name: string): string {\n return (\n `This component uses \".${name}(\", which components stored in the database ` +\n \"may not use. Calling a value's constructor reaches the JavaScript \" +\n \"evaluator, so it could run code nobody reviewed inside the signed-in \" +\n \"page. Write the logic out directly instead.\"\n );\n}\n\nfunction bannedComputedAccessMessage(name: string): string {\n return (\n `This component uses \"${name}[\", which components stored in the database ` +\n \"may not use. Looking a property up by a computed name hides which \" +\n \"browser capability the component reaches, so no review can tell whether \" +\n `it is safe. Name what you need directly, or use props.data and a Shape ` +\n \"action for anything the component needs from the server.\"\n );\n}\n\nfunction globalFindings(file: string, code: string): Finding[] {\n const out: Finding[] = [];\n const push = (rule: string, re: RegExp, message: string) => {\n const m = re.exec(code);\n if (m) out.push({ rule, file, line: lineAt(code, m.index), severity: \"refuse\", message });\n };\n for (const name of GATE_BANNED_GLOBALS) {\n push(\"bannedGlobal\", new RegExp(`(?<![.\\\\w$])${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_CALLABLES) {\n const e = escapeForRegExp(name);\n push(\"bannedCallable\", new RegExp(`\\\\bnew\\\\s+${e}\\\\s*\\\\(|(?<![.\\\\w$])${e}\\\\s*\\\\(`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_ACCESS) {\n push(\"bannedMemberAccess\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_CALLS) {\n push(\"bannedMemberCall\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\s*\\\\(`), bannedMemberCallMessage(name));\n }\n for (const name of GATE_BANNED_COMPUTED_ACCESS) {\n const e = escapeForRegExp(name);\n push(\"bannedComputedAccess\", new RegExp(`(?<![.\\\\w$])${e}\\\\s*\\\\[|\\\\.\\\\s*${e}\\\\s*\\\\[`), bannedComputedAccessMessage(name));\n }\n return out;\n}\n\n/**\n * THE ONE GATE (CONTRACTS §7). Every finding names its file and line; any\n * `refuse` finding means the code may not be stored. `.html` files and\n * `.json` files are not compiled in the page and are skipped.\n */\nexport function gate(files: Readonly<Record<string, string>>): Finding[] {\n const out: Finding[] = [];\n for (const [file, source] of Object.entries(files)) {\n if (/\\.(html?|json|css|md)$/i.test(file)) continue;\n const code = source ?? \"\";\n out.push(...importFindings(files, file, code), ...globalFindings(file, code));\n }\n return out;\n}\n\n/**\n * The single-body form today's writers call: the first refusing sentence, or\n * null when the source may be stored. `flavor: \"html\"` bodies render in an\n * opaque-origin iframe and are not checked.\n */\nexport function componentSourceGate(source: string, options?: { flavor?: string | null }): string | null {\n if ((options?.flavor ?? \"\").toLowerCase() === \"html\") return null;\n const finding = gate({ \"component.tsx\": source ?? \"\" }).find((f) => f.severity === \"refuse\");\n return finding ? finding.message : null;\n}\n","{\n \"_comment\": [\n \"CANONICAL, MACHINE-READABLE source-gate lists for stored code compiled by @ai-matrx/code-runtime.\",\n \"ONE list per rule, sorted, byte-comparable across runtimes. Three guards keep the copies honest:\",\n \" - src/gate.test.ts asserts allowedImports equals listScopeEntryPaths() sorted\",\n \" (the documented scope registry is the truth);\",\n \" - aidream packages/matrx-ai/tests/test_component_source_gate_parity.py asserts the Python\",\n \" twins in kind_shared.py equal these arrays;\",\n \" - the database trigger's parity test asserts the trigger names every entry of every\",\n \" security list below.\"\n ],\n \"allowedImports\": [\n \"@/applets\",\n \"@/components/Markdown\",\n \"@/components/MarkdownStream\",\n \"@/components/agent-copy/CopyButtons\",\n \"@/components/agent-copy/CopyForAiButton\",\n \"@/components/kind-kit/KindHeaderBar\",\n \"@/components/kind-kit/KindPanel\",\n \"@/components/kind-kit/KindPanelGrid\",\n \"@/components/kind-kit/SortableList\",\n \"@/components/kind-kit/StreamingSkeleton\",\n \"@/components/kind-kit/TagList\",\n \"@/components/mardown\",\n \"@/components/markdown\",\n \"@/components/official/icons/IconResolver\",\n \"@/components/ui/accordion\",\n \"@/components/ui/alert\",\n \"@/components/ui/avatar\",\n \"@/components/ui/badge\",\n \"@/components/ui/button\",\n \"@/components/ui/card\",\n \"@/components/ui/checkbox\",\n \"@/components/ui/collapsible\",\n \"@/components/ui/dialog\",\n \"@/components/ui/dropdown-menu\",\n \"@/components/ui/input\",\n \"@/components/ui/label\",\n \"@/components/ui/popover\",\n \"@/components/ui/progress\",\n \"@/components/ui/radio-group\",\n \"@/components/ui/scroll-area\",\n \"@/components/ui/select\",\n \"@/components/ui/separator\",\n \"@/components/ui/sheet\",\n \"@/components/ui/skeleton\",\n \"@/components/ui/slider\",\n \"@/components/ui/switch\",\n \"@/components/ui/table\",\n \"@/components/ui/tabs\",\n \"@/components/ui/textarea\",\n \"@/components/ui/tooltip\",\n \"@/lib/utils\",\n \"@ai-matrx/applets/react\",\n \"@ai-matrx/design-system\",\n \"@ai-matrx/design-system/controls\",\n \"@ai-matrx/icons\",\n \"@react-three/fiber\",\n \"date-fns\",\n \"lodash\",\n \"lucide-react\",\n \"motion/react\",\n \"react\",\n \"react-katex\",\n \"react-pdf\",\n \"recharts\",\n \"three\",\n \"xlsx\"\n ],\n \"bannedGlobals\": [\n \"EventSource\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"fetch\",\n \"importScripts\",\n \"localStorage\",\n \"sessionStorage\"\n ],\n \"bannedCallables\": [\n \"Function\",\n \"eval\"\n ],\n \"bannedMemberAccess\": [\n \"EventSource\",\n \"Function\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"cookie\",\n \"eval\",\n \"fetch\",\n \"importScripts\",\n \"sendBeacon\"\n ],\n \"bannedMemberCalls\": [\n \"constructor\"\n ],\n \"bannedComputedAccess\": [\n \"globalThis\",\n \"self\",\n \"window\"\n ],\n \"bannedSyntax\": [\n \"dynamicImport\"\n ]\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/gate.ts","../src/gate-lists.json"],"sourcesContent":["/**\n * `@ai-matrx/code-runtime/gate` — THE ONE source gate for stored code.\n *\n * Every writer of stored component code (kind components, tool and emit\n * renderers, Applet files) runs `gate(files)` before the write; a database\n * trigger is the backstop and aidream's `kind_shared.py` is the Python twin.\n * The lists are DATA in `gate-lists.json` (exported as\n * `@ai-matrx/code-runtime/gate-lists.json`) so all three runtimes compare the\n * same bytes; parity tests on each side read this file.\n *\n * Moved here verbatim in behavior from matrx-frontend\n * `features/agent-apps/utils/component-source-gate.ts` (Q82 / B-17, DD-124),\n * widened to multi-file sources: a relative import must name a file in the\n * set, and every finding carries its file and line.\n *\n * WHAT THIS IS NOT: a sandbox. A string check cannot stop every escape, and\n * the runtime stubs shadow bare identifiers only. Real isolation is the\n * sandbox frame (opaque origin, `connect-src 'none'`).\n *\n * Pure: no React, no Babel — safe for servers, workers and write paths.\n */\nimport lists from \"./gate-lists.json\";\nimport type { Finding } from \"./types\";\n\nexport type { Finding } from \"./types\";\n\n/** Every module stored code may import (the documented scope registry). */\nexport const GATE_ALLOWED_IMPORTS: readonly string[] = lists.allowedImports;\n/** Globals stored code may never name as a bare identifier. */\nexport const GATE_BANNED_GLOBALS: readonly string[] = lists.bannedGlobals;\n/** Evaluators banned where called or constructed (`eval(`, `new Function(`). */\nexport const GATE_BANNED_CALLABLES: readonly string[] = lists.bannedCallables;\n/** Names banned as a property read (`window.fetch`, `document.cookie`). */\nexport const GATE_BANNED_MEMBER_ACCESS: readonly string[] = lists.bannedMemberAccess;\n/** Names banned as a method call on any object (`.constructor(`). */\nexport const GATE_BANNED_MEMBER_CALLS: readonly string[] = lists.bannedMemberCalls;\n/** Roots on which bracket access is refused (`window[\"fet\"+\"ch\"]`). */\nexport const GATE_BANNED_COMPUTED_ACCESS: readonly string[] = lists.bannedComputedAccess;\n/** Named syntax rules every runtime implements (`dynamicImport`). */\nexport const GATE_BANNED_SYNTAX: readonly string[] = lists.bannedSyntax;\n\n/** The raw lists, for parity tests and the database trigger's generator. */\nexport const GATE_LISTS = lists;\n\nconst IMPORT_RE = /^\\s*import\\s+(?:[^'\"]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/gm;\nconst EXPORT_FROM_RE = /^\\s*export\\s+(?:\\*|\\{[^}]*\\})\\s+from\\s+['\"]([^'\"]+)['\"]/gm;\nconst DYNAMIC_IMPORT_RE = /(?<![.\\w$])import\\s*\\(/g;\n\nfunction escapeForRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction lineAt(source: string, index: number): number {\n let line = 1;\n for (let i = 0; i < index && i < source.length; i++) {\n if (source.charCodeAt(i) === 10) line++;\n }\n return line;\n}\n\n/** Normalize a relative specifier against the importing file, without extension guessing. */\nexport function resolveRelativePath(fromFile: string, specifier: string): string {\n const base = fromFile.split(\"/\").slice(0, -1);\n for (const part of specifier.split(\"/\")) {\n if (part === \"\" || part === \".\") continue;\n if (part === \"..\") base.pop();\n else base.push(part);\n }\n return base.join(\"/\");\n}\n\nconst RESOLVE_SUFFIXES = [\"\", \".tsx\", \".ts\", \".jsx\", \".js\", \".json\", \"/index.tsx\", \"/index.ts\", \"/index.jsx\", \"/index.js\"];\n\n/** The file in `files` a relative specifier names, or null. */\nexport function resolveRelativeFile(\n files: Readonly<Record<string, string>>,\n fromFile: string,\n specifier: string,\n): string | null {\n const target = resolveRelativePath(fromFile, specifier);\n for (const suffix of RESOLVE_SUFFIXES) {\n const candidate = `${target}${suffix}`;\n if (Object.prototype.hasOwnProperty.call(files, candidate)) return candidate;\n }\n return null;\n}\n\n/** The module paths a source imports, in source order, de-duplicated. */\nexport function importPaths(source: string): string[] {\n const found = new Set<string>();\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source ?? \"\")) !== null) {\n if (match[1]) found.add(match[1]);\n }\n }\n return [...found];\n}\n\nconst ALLOWED_SENTENCE =\n \"Rewrite it using only the documented scope (react, lucide-react, recharts, \" +\n \"@ai-matrx/design-system/controls, @ai-matrx/design-system, @/lib/utils, \" +\n \"@/components/ui/*, @/components/kind-kit/*, CopyButtons/CopyForAiButton, Markdown) \" +\n \"or a file of this component.\";\n\nfunction importFindings(files: Readonly<Record<string, string>>, file: string, source: string): Finding[] {\n const out: Finding[] = [];\n const allowed = new Set(GATE_ALLOWED_IMPORTS);\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source)) !== null) {\n const path = match[1] ?? \"\";\n const line = lineAt(source, match.index + match[0].indexOf(path));\n if (path.startsWith(\"./\") || path.startsWith(\"../\")) {\n if (!resolveRelativeFile(files, file, path)) {\n out.push({\n rule: \"relative-import-missing\",\n file,\n line,\n severity: \"refuse\",\n message: `This file imports \"${path}\", but no file of this component has that name. Add the file or fix the path.`,\n });\n }\n continue;\n }\n if (!allowed.has(path)) {\n out.push({\n rule: \"import-not-allowed\",\n file,\n line,\n severity: \"refuse\",\n message: `This component imports \"${path}\", which is outside the sandbox scope, so it would render as a marked placeholder. ${ALLOWED_SENTENCE}`,\n });\n }\n }\n }\n DYNAMIC_IMPORT_RE.lastIndex = 0;\n const dyn = DYNAMIC_IMPORT_RE.exec(source);\n if (dyn) {\n out.push({\n rule: \"dynamicImport\",\n file,\n line: lineAt(source, dyn.index),\n severity: \"refuse\",\n message:\n \"This component uses a dynamic import(). The in-page compiler has no module loader, so the call would either fail at render or reach code nobody vetted. Import from the scope at the top of the file instead.\",\n });\n }\n return out;\n}\n\nfunction bannedGlobalMessage(name: string): string {\n return (\n `This component uses \"${name}\", which components stored in the database may ` +\n \"not use. They run inside the signed-in page, so anything that reaches the \" +\n \"network, browser storage, or the JavaScript evaluator could read or send \" +\n \"the reader's data. Render what the Shape hands you in props.data and use \" +\n \"a Shape action for anything the component needs from the server.\"\n );\n}\n\nfunction bannedMemberCallMessage(name: string): string {\n return (\n `This component uses \".${name}(\", which components stored in the database ` +\n \"may not use. Calling a value's constructor reaches the JavaScript \" +\n \"evaluator, so it could run code nobody reviewed inside the signed-in \" +\n \"page. Write the logic out directly instead.\"\n );\n}\n\nfunction bannedComputedAccessMessage(name: string): string {\n return (\n `This component uses \"${name}[\", which components stored in the database ` +\n \"may not use. Looking a property up by a computed name hides which \" +\n \"browser capability the component reaches, so no review can tell whether \" +\n `it is safe. Name what you need directly, or use props.data and a Shape ` +\n \"action for anything the component needs from the server.\"\n );\n}\n\nfunction globalFindings(file: string, code: string): Finding[] {\n const out: Finding[] = [];\n const push = (rule: string, re: RegExp, message: string) => {\n const m = re.exec(code);\n if (m) out.push({ rule, file, line: lineAt(code, m.index), severity: \"refuse\", message });\n };\n for (const name of GATE_BANNED_GLOBALS) {\n push(\"bannedGlobal\", new RegExp(`(?<![.\\\\w$])${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_CALLABLES) {\n const e = escapeForRegExp(name);\n push(\"bannedCallable\", new RegExp(`\\\\bnew\\\\s+${e}\\\\s*\\\\(|(?<![.\\\\w$])${e}\\\\s*\\\\(`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_ACCESS) {\n push(\"bannedMemberAccess\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_CALLS) {\n push(\"bannedMemberCall\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\s*\\\\(`), bannedMemberCallMessage(name));\n }\n for (const name of GATE_BANNED_COMPUTED_ACCESS) {\n const e = escapeForRegExp(name);\n push(\"bannedComputedAccess\", new RegExp(`(?<![.\\\\w$])${e}\\\\s*\\\\[|\\\\.\\\\s*${e}\\\\s*\\\\[`), bannedComputedAccessMessage(name));\n }\n return out;\n}\n\n/**\n * THE ONE GATE (CONTRACTS §7). Every finding names its file and line; any\n * `refuse` finding means the code may not be stored. `.html` files and\n * `.json` files are not compiled in the page and are skipped.\n */\nexport function gate(files: Readonly<Record<string, string>>): Finding[] {\n const out: Finding[] = [];\n for (const [file, source] of Object.entries(files)) {\n if (/\\.(html?|json|css|md)$/i.test(file)) continue;\n const code = source ?? \"\";\n out.push(...importFindings(files, file, code), ...globalFindings(file, code));\n }\n return out;\n}\n\n/**\n * The single-body form today's writers call: the first refusing sentence, or\n * null when the source may be stored. `flavor: \"html\"` bodies render in an\n * opaque-origin iframe and are not checked.\n */\nexport function componentSourceGate(source: string, options?: { flavor?: string | null }): string | null {\n if ((options?.flavor ?? \"\").toLowerCase() === \"html\") return null;\n const finding = gate({ \"component.tsx\": source ?? \"\" }).find((f) => f.severity === \"refuse\");\n return finding ? finding.message : null;\n}\n","{\n \"_comment\": [\n \"CANONICAL, MACHINE-READABLE source-gate lists for stored code compiled by @ai-matrx/code-runtime.\",\n \"ONE list per rule, sorted, byte-comparable across runtimes. Three guards keep the copies honest:\",\n \" - src/gate.test.ts asserts allowedImports equals listScopeEntryPaths() sorted\",\n \" (the documented scope registry is the truth);\",\n \" - aidream packages/matrx-ai/tests/test_component_source_gate_parity.py asserts the Python\",\n \" twins in kind_shared.py equal these arrays;\",\n \" - the database trigger's parity test asserts the trigger names every entry of every\",\n \" security list below.\"\n ],\n \"allowedImports\": [\n \"@/applets\",\n \"@/components/Markdown\",\n \"@/components/MarkdownStream\",\n \"@/components/agent-copy/CopyButtons\",\n \"@/components/agent-copy/CopyForAiButton\",\n \"@/components/kind-kit/KindActionButton\",\n \"@/components/kind-kit/KindHeaderBar\",\n \"@/components/kind-kit/KindPanel\",\n \"@/components/kind-kit/KindPanelGrid\",\n \"@/components/kind-kit/SortableList\",\n \"@/components/kind-kit/StreamingSkeleton\",\n \"@/components/kind-kit/TagList\",\n \"@/components/mardown\",\n \"@/components/markdown\",\n \"@/components/official/icons/IconResolver\",\n \"@/components/ui/accordion\",\n \"@/components/ui/alert\",\n \"@/components/ui/avatar\",\n \"@/components/ui/badge\",\n \"@/components/ui/button\",\n \"@/components/ui/card\",\n \"@/components/ui/checkbox\",\n \"@/components/ui/collapsible\",\n \"@/components/ui/dialog\",\n \"@/components/ui/dropdown-menu\",\n \"@/components/ui/input\",\n \"@/components/ui/label\",\n \"@/components/ui/popover\",\n \"@/components/ui/progress\",\n \"@/components/ui/radio-group\",\n \"@/components/ui/scroll-area\",\n \"@/components/ui/select\",\n \"@/components/ui/separator\",\n \"@/components/ui/sheet\",\n \"@/components/ui/skeleton\",\n \"@/components/ui/slider\",\n \"@/components/ui/switch\",\n \"@/components/ui/table\",\n \"@/components/ui/tabs\",\n \"@/components/ui/textarea\",\n \"@/components/ui/tooltip\",\n \"@/lib/utils\",\n \"@ai-matrx/applets/react\",\n \"@ai-matrx/design-system\",\n \"@ai-matrx/design-system/controls\",\n \"@ai-matrx/icons\",\n \"@react-three/fiber\",\n \"date-fns\",\n \"lodash\",\n \"lucide-react\",\n \"motion/react\",\n \"react\",\n \"react-katex\",\n \"react-pdf\",\n \"recharts\",\n \"three\",\n \"xlsx\"\n ],\n \"bannedGlobals\": [\n \"EventSource\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"fetch\",\n \"importScripts\",\n \"localStorage\",\n \"sessionStorage\"\n ],\n \"bannedCallables\": [\n \"Function\",\n \"eval\"\n ],\n \"bannedMemberAccess\": [\n \"EventSource\",\n \"Function\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"cookie\",\n \"eval\",\n \"fetch\",\n \"importScripts\",\n \"sendBeacon\"\n ],\n \"bannedMemberCalls\": [\n \"constructor\"\n ],\n \"bannedComputedAccess\": [\n \"globalThis\",\n \"self\",\n \"window\"\n ],\n \"bannedSyntax\": [\n \"dynamicImport\"\n ]\n}\n"],"mappings":"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","names":[]}
package/dist/gate.js CHANGED
@@ -16,6 +16,7 @@ var gate_lists_default = {
16
16
  "@/components/MarkdownStream",
17
17
  "@/components/agent-copy/CopyButtons",
18
18
  "@/components/agent-copy/CopyForAiButton",
19
+ "@/components/kind-kit/KindActionButton",
19
20
  "@/components/kind-kit/KindHeaderBar",
20
21
  "@/components/kind-kit/KindPanel",
21
22
  "@/components/kind-kit/KindPanelGrid",
package/dist/gate.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gate-lists.json","../src/gate.ts"],"sourcesContent":["{\n \"_comment\": [\n \"CANONICAL, MACHINE-READABLE source-gate lists for stored code compiled by @ai-matrx/code-runtime.\",\n \"ONE list per rule, sorted, byte-comparable across runtimes. Three guards keep the copies honest:\",\n \" - src/gate.test.ts asserts allowedImports equals listScopeEntryPaths() sorted\",\n \" (the documented scope registry is the truth);\",\n \" - aidream packages/matrx-ai/tests/test_component_source_gate_parity.py asserts the Python\",\n \" twins in kind_shared.py equal these arrays;\",\n \" - the database trigger's parity test asserts the trigger names every entry of every\",\n \" security list below.\"\n ],\n \"allowedImports\": [\n \"@/applets\",\n \"@/components/Markdown\",\n \"@/components/MarkdownStream\",\n \"@/components/agent-copy/CopyButtons\",\n \"@/components/agent-copy/CopyForAiButton\",\n \"@/components/kind-kit/KindHeaderBar\",\n \"@/components/kind-kit/KindPanel\",\n \"@/components/kind-kit/KindPanelGrid\",\n \"@/components/kind-kit/SortableList\",\n \"@/components/kind-kit/StreamingSkeleton\",\n \"@/components/kind-kit/TagList\",\n \"@/components/mardown\",\n \"@/components/markdown\",\n \"@/components/official/icons/IconResolver\",\n \"@/components/ui/accordion\",\n \"@/components/ui/alert\",\n \"@/components/ui/avatar\",\n \"@/components/ui/badge\",\n \"@/components/ui/button\",\n \"@/components/ui/card\",\n \"@/components/ui/checkbox\",\n \"@/components/ui/collapsible\",\n \"@/components/ui/dialog\",\n \"@/components/ui/dropdown-menu\",\n \"@/components/ui/input\",\n \"@/components/ui/label\",\n \"@/components/ui/popover\",\n \"@/components/ui/progress\",\n \"@/components/ui/radio-group\",\n \"@/components/ui/scroll-area\",\n \"@/components/ui/select\",\n \"@/components/ui/separator\",\n \"@/components/ui/sheet\",\n \"@/components/ui/skeleton\",\n \"@/components/ui/slider\",\n \"@/components/ui/switch\",\n \"@/components/ui/table\",\n \"@/components/ui/tabs\",\n \"@/components/ui/textarea\",\n \"@/components/ui/tooltip\",\n \"@/lib/utils\",\n \"@ai-matrx/applets/react\",\n \"@ai-matrx/design-system\",\n \"@ai-matrx/design-system/controls\",\n \"@ai-matrx/icons\",\n \"@react-three/fiber\",\n \"date-fns\",\n \"lodash\",\n \"lucide-react\",\n \"motion/react\",\n \"react\",\n \"react-katex\",\n \"react-pdf\",\n \"recharts\",\n \"three\",\n \"xlsx\"\n ],\n \"bannedGlobals\": [\n \"EventSource\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"fetch\",\n \"importScripts\",\n \"localStorage\",\n \"sessionStorage\"\n ],\n \"bannedCallables\": [\n \"Function\",\n \"eval\"\n ],\n \"bannedMemberAccess\": [\n \"EventSource\",\n \"Function\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"cookie\",\n \"eval\",\n \"fetch\",\n \"importScripts\",\n \"sendBeacon\"\n ],\n \"bannedMemberCalls\": [\n \"constructor\"\n ],\n \"bannedComputedAccess\": [\n \"globalThis\",\n \"self\",\n \"window\"\n ],\n \"bannedSyntax\": [\n \"dynamicImport\"\n ]\n}\n","/**\n * `@ai-matrx/code-runtime/gate` — THE ONE source gate for stored code.\n *\n * Every writer of stored component code (kind components, tool and emit\n * renderers, Applet files) runs `gate(files)` before the write; a database\n * trigger is the backstop and aidream's `kind_shared.py` is the Python twin.\n * The lists are DATA in `gate-lists.json` (exported as\n * `@ai-matrx/code-runtime/gate-lists.json`) so all three runtimes compare the\n * same bytes; parity tests on each side read this file.\n *\n * Moved here verbatim in behavior from matrx-frontend\n * `features/agent-apps/utils/component-source-gate.ts` (Q82 / B-17, DD-124),\n * widened to multi-file sources: a relative import must name a file in the\n * set, and every finding carries its file and line.\n *\n * WHAT THIS IS NOT: a sandbox. A string check cannot stop every escape, and\n * the runtime stubs shadow bare identifiers only. Real isolation is the\n * sandbox frame (opaque origin, `connect-src 'none'`).\n *\n * Pure: no React, no Babel — safe for servers, workers and write paths.\n */\nimport lists from \"./gate-lists.json\";\nimport type { Finding } from \"./types\";\n\nexport type { Finding } from \"./types\";\n\n/** Every module stored code may import (the documented scope registry). */\nexport const GATE_ALLOWED_IMPORTS: readonly string[] = lists.allowedImports;\n/** Globals stored code may never name as a bare identifier. */\nexport const GATE_BANNED_GLOBALS: readonly string[] = lists.bannedGlobals;\n/** Evaluators banned where called or constructed (`eval(`, `new Function(`). */\nexport const GATE_BANNED_CALLABLES: readonly string[] = lists.bannedCallables;\n/** Names banned as a property read (`window.fetch`, `document.cookie`). */\nexport const GATE_BANNED_MEMBER_ACCESS: readonly string[] = lists.bannedMemberAccess;\n/** Names banned as a method call on any object (`.constructor(`). */\nexport const GATE_BANNED_MEMBER_CALLS: readonly string[] = lists.bannedMemberCalls;\n/** Roots on which bracket access is refused (`window[\"fet\"+\"ch\"]`). */\nexport const GATE_BANNED_COMPUTED_ACCESS: readonly string[] = lists.bannedComputedAccess;\n/** Named syntax rules every runtime implements (`dynamicImport`). */\nexport const GATE_BANNED_SYNTAX: readonly string[] = lists.bannedSyntax;\n\n/** The raw lists, for parity tests and the database trigger's generator. */\nexport const GATE_LISTS = lists;\n\nconst IMPORT_RE = /^\\s*import\\s+(?:[^'\"]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/gm;\nconst EXPORT_FROM_RE = /^\\s*export\\s+(?:\\*|\\{[^}]*\\})\\s+from\\s+['\"]([^'\"]+)['\"]/gm;\nconst DYNAMIC_IMPORT_RE = /(?<![.\\w$])import\\s*\\(/g;\n\nfunction escapeForRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction lineAt(source: string, index: number): number {\n let line = 1;\n for (let i = 0; i < index && i < source.length; i++) {\n if (source.charCodeAt(i) === 10) line++;\n }\n return line;\n}\n\n/** Normalize a relative specifier against the importing file, without extension guessing. */\nexport function resolveRelativePath(fromFile: string, specifier: string): string {\n const base = fromFile.split(\"/\").slice(0, -1);\n for (const part of specifier.split(\"/\")) {\n if (part === \"\" || part === \".\") continue;\n if (part === \"..\") base.pop();\n else base.push(part);\n }\n return base.join(\"/\");\n}\n\nconst RESOLVE_SUFFIXES = [\"\", \".tsx\", \".ts\", \".jsx\", \".js\", \".json\", \"/index.tsx\", \"/index.ts\", \"/index.jsx\", \"/index.js\"];\n\n/** The file in `files` a relative specifier names, or null. */\nexport function resolveRelativeFile(\n files: Readonly<Record<string, string>>,\n fromFile: string,\n specifier: string,\n): string | null {\n const target = resolveRelativePath(fromFile, specifier);\n for (const suffix of RESOLVE_SUFFIXES) {\n const candidate = `${target}${suffix}`;\n if (Object.prototype.hasOwnProperty.call(files, candidate)) return candidate;\n }\n return null;\n}\n\n/** The module paths a source imports, in source order, de-duplicated. */\nexport function importPaths(source: string): string[] {\n const found = new Set<string>();\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source ?? \"\")) !== null) {\n if (match[1]) found.add(match[1]);\n }\n }\n return [...found];\n}\n\nconst ALLOWED_SENTENCE =\n \"Rewrite it using only the documented scope (react, lucide-react, recharts, \" +\n \"@ai-matrx/design-system/controls, @ai-matrx/design-system, @/lib/utils, \" +\n \"@/components/ui/*, @/components/kind-kit/*, CopyButtons/CopyForAiButton, Markdown) \" +\n \"or a file of this component.\";\n\nfunction importFindings(files: Readonly<Record<string, string>>, file: string, source: string): Finding[] {\n const out: Finding[] = [];\n const allowed = new Set(GATE_ALLOWED_IMPORTS);\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source)) !== null) {\n const path = match[1] ?? \"\";\n const line = lineAt(source, match.index + match[0].indexOf(path));\n if (path.startsWith(\"./\") || path.startsWith(\"../\")) {\n if (!resolveRelativeFile(files, file, path)) {\n out.push({\n rule: \"relative-import-missing\",\n file,\n line,\n severity: \"refuse\",\n message: `This file imports \"${path}\", but no file of this component has that name. Add the file or fix the path.`,\n });\n }\n continue;\n }\n if (!allowed.has(path)) {\n out.push({\n rule: \"import-not-allowed\",\n file,\n line,\n severity: \"refuse\",\n message: `This component imports \"${path}\", which is outside the sandbox scope, so it would render as a marked placeholder. ${ALLOWED_SENTENCE}`,\n });\n }\n }\n }\n DYNAMIC_IMPORT_RE.lastIndex = 0;\n const dyn = DYNAMIC_IMPORT_RE.exec(source);\n if (dyn) {\n out.push({\n rule: \"dynamicImport\",\n file,\n line: lineAt(source, dyn.index),\n severity: \"refuse\",\n message:\n \"This component uses a dynamic import(). The in-page compiler has no module loader, so the call would either fail at render or reach code nobody vetted. Import from the scope at the top of the file instead.\",\n });\n }\n return out;\n}\n\nfunction bannedGlobalMessage(name: string): string {\n return (\n `This component uses \"${name}\", which components stored in the database may ` +\n \"not use. They run inside the signed-in page, so anything that reaches the \" +\n \"network, browser storage, or the JavaScript evaluator could read or send \" +\n \"the reader's data. Render what the Shape hands you in props.data and use \" +\n \"a Shape action for anything the component needs from the server.\"\n );\n}\n\nfunction bannedMemberCallMessage(name: string): string {\n return (\n `This component uses \".${name}(\", which components stored in the database ` +\n \"may not use. Calling a value's constructor reaches the JavaScript \" +\n \"evaluator, so it could run code nobody reviewed inside the signed-in \" +\n \"page. Write the logic out directly instead.\"\n );\n}\n\nfunction bannedComputedAccessMessage(name: string): string {\n return (\n `This component uses \"${name}[\", which components stored in the database ` +\n \"may not use. Looking a property up by a computed name hides which \" +\n \"browser capability the component reaches, so no review can tell whether \" +\n `it is safe. Name what you need directly, or use props.data and a Shape ` +\n \"action for anything the component needs from the server.\"\n );\n}\n\nfunction globalFindings(file: string, code: string): Finding[] {\n const out: Finding[] = [];\n const push = (rule: string, re: RegExp, message: string) => {\n const m = re.exec(code);\n if (m) out.push({ rule, file, line: lineAt(code, m.index), severity: \"refuse\", message });\n };\n for (const name of GATE_BANNED_GLOBALS) {\n push(\"bannedGlobal\", new RegExp(`(?<![.\\\\w$])${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_CALLABLES) {\n const e = escapeForRegExp(name);\n push(\"bannedCallable\", new RegExp(`\\\\bnew\\\\s+${e}\\\\s*\\\\(|(?<![.\\\\w$])${e}\\\\s*\\\\(`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_ACCESS) {\n push(\"bannedMemberAccess\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_CALLS) {\n push(\"bannedMemberCall\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\s*\\\\(`), bannedMemberCallMessage(name));\n }\n for (const name of GATE_BANNED_COMPUTED_ACCESS) {\n const e = escapeForRegExp(name);\n push(\"bannedComputedAccess\", new RegExp(`(?<![.\\\\w$])${e}\\\\s*\\\\[|\\\\.\\\\s*${e}\\\\s*\\\\[`), bannedComputedAccessMessage(name));\n }\n return out;\n}\n\n/**\n * THE ONE GATE (CONTRACTS §7). Every finding names its file and line; any\n * `refuse` finding means the code may not be stored. `.html` files and\n * `.json` files are not compiled in the page and are skipped.\n */\nexport function gate(files: Readonly<Record<string, string>>): Finding[] {\n const out: Finding[] = [];\n for (const [file, source] of Object.entries(files)) {\n if (/\\.(html?|json|css|md)$/i.test(file)) continue;\n const code = source ?? \"\";\n out.push(...importFindings(files, file, code), ...globalFindings(file, code));\n }\n return out;\n}\n\n/**\n * The single-body form today's writers call: the first refusing sentence, or\n * null when the source may be stored. `flavor: \"html\"` bodies render in an\n * opaque-origin iframe and are not checked.\n */\nexport function componentSourceGate(source: string, options?: { flavor?: string | null }): string | null {\n if ((options?.flavor ?? \"\").toLowerCase() === \"html\") return null;\n const finding = gate({ \"component.tsx\": source ?? \"\" }).find((f) => f.severity === \"refuse\");\n return finding ? finding.message : null;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/gate-lists.json","../src/gate.ts"],"sourcesContent":["{\n \"_comment\": [\n \"CANONICAL, MACHINE-READABLE source-gate lists for stored code compiled by @ai-matrx/code-runtime.\",\n \"ONE list per rule, sorted, byte-comparable across runtimes. Three guards keep the copies honest:\",\n \" - src/gate.test.ts asserts allowedImports equals listScopeEntryPaths() sorted\",\n \" (the documented scope registry is the truth);\",\n \" - aidream packages/matrx-ai/tests/test_component_source_gate_parity.py asserts the Python\",\n \" twins in kind_shared.py equal these arrays;\",\n \" - the database trigger's parity test asserts the trigger names every entry of every\",\n \" security list below.\"\n ],\n \"allowedImports\": [\n \"@/applets\",\n \"@/components/Markdown\",\n \"@/components/MarkdownStream\",\n \"@/components/agent-copy/CopyButtons\",\n \"@/components/agent-copy/CopyForAiButton\",\n \"@/components/kind-kit/KindActionButton\",\n \"@/components/kind-kit/KindHeaderBar\",\n \"@/components/kind-kit/KindPanel\",\n \"@/components/kind-kit/KindPanelGrid\",\n \"@/components/kind-kit/SortableList\",\n \"@/components/kind-kit/StreamingSkeleton\",\n \"@/components/kind-kit/TagList\",\n \"@/components/mardown\",\n \"@/components/markdown\",\n \"@/components/official/icons/IconResolver\",\n \"@/components/ui/accordion\",\n \"@/components/ui/alert\",\n \"@/components/ui/avatar\",\n \"@/components/ui/badge\",\n \"@/components/ui/button\",\n \"@/components/ui/card\",\n \"@/components/ui/checkbox\",\n \"@/components/ui/collapsible\",\n \"@/components/ui/dialog\",\n \"@/components/ui/dropdown-menu\",\n \"@/components/ui/input\",\n \"@/components/ui/label\",\n \"@/components/ui/popover\",\n \"@/components/ui/progress\",\n \"@/components/ui/radio-group\",\n \"@/components/ui/scroll-area\",\n \"@/components/ui/select\",\n \"@/components/ui/separator\",\n \"@/components/ui/sheet\",\n \"@/components/ui/skeleton\",\n \"@/components/ui/slider\",\n \"@/components/ui/switch\",\n \"@/components/ui/table\",\n \"@/components/ui/tabs\",\n \"@/components/ui/textarea\",\n \"@/components/ui/tooltip\",\n \"@/lib/utils\",\n \"@ai-matrx/applets/react\",\n \"@ai-matrx/design-system\",\n \"@ai-matrx/design-system/controls\",\n \"@ai-matrx/icons\",\n \"@react-three/fiber\",\n \"date-fns\",\n \"lodash\",\n \"lucide-react\",\n \"motion/react\",\n \"react\",\n \"react-katex\",\n \"react-pdf\",\n \"recharts\",\n \"three\",\n \"xlsx\"\n ],\n \"bannedGlobals\": [\n \"EventSource\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"fetch\",\n \"importScripts\",\n \"localStorage\",\n \"sessionStorage\"\n ],\n \"bannedCallables\": [\n \"Function\",\n \"eval\"\n ],\n \"bannedMemberAccess\": [\n \"EventSource\",\n \"Function\",\n \"WebSocket\",\n \"XMLHttpRequest\",\n \"cookie\",\n \"eval\",\n \"fetch\",\n \"importScripts\",\n \"sendBeacon\"\n ],\n \"bannedMemberCalls\": [\n \"constructor\"\n ],\n \"bannedComputedAccess\": [\n \"globalThis\",\n \"self\",\n \"window\"\n ],\n \"bannedSyntax\": [\n \"dynamicImport\"\n ]\n}\n","/**\n * `@ai-matrx/code-runtime/gate` — THE ONE source gate for stored code.\n *\n * Every writer of stored component code (kind components, tool and emit\n * renderers, Applet files) runs `gate(files)` before the write; a database\n * trigger is the backstop and aidream's `kind_shared.py` is the Python twin.\n * The lists are DATA in `gate-lists.json` (exported as\n * `@ai-matrx/code-runtime/gate-lists.json`) so all three runtimes compare the\n * same bytes; parity tests on each side read this file.\n *\n * Moved here verbatim in behavior from matrx-frontend\n * `features/agent-apps/utils/component-source-gate.ts` (Q82 / B-17, DD-124),\n * widened to multi-file sources: a relative import must name a file in the\n * set, and every finding carries its file and line.\n *\n * WHAT THIS IS NOT: a sandbox. A string check cannot stop every escape, and\n * the runtime stubs shadow bare identifiers only. Real isolation is the\n * sandbox frame (opaque origin, `connect-src 'none'`).\n *\n * Pure: no React, no Babel — safe for servers, workers and write paths.\n */\nimport lists from \"./gate-lists.json\";\nimport type { Finding } from \"./types\";\n\nexport type { Finding } from \"./types\";\n\n/** Every module stored code may import (the documented scope registry). */\nexport const GATE_ALLOWED_IMPORTS: readonly string[] = lists.allowedImports;\n/** Globals stored code may never name as a bare identifier. */\nexport const GATE_BANNED_GLOBALS: readonly string[] = lists.bannedGlobals;\n/** Evaluators banned where called or constructed (`eval(`, `new Function(`). */\nexport const GATE_BANNED_CALLABLES: readonly string[] = lists.bannedCallables;\n/** Names banned as a property read (`window.fetch`, `document.cookie`). */\nexport const GATE_BANNED_MEMBER_ACCESS: readonly string[] = lists.bannedMemberAccess;\n/** Names banned as a method call on any object (`.constructor(`). */\nexport const GATE_BANNED_MEMBER_CALLS: readonly string[] = lists.bannedMemberCalls;\n/** Roots on which bracket access is refused (`window[\"fet\"+\"ch\"]`). */\nexport const GATE_BANNED_COMPUTED_ACCESS: readonly string[] = lists.bannedComputedAccess;\n/** Named syntax rules every runtime implements (`dynamicImport`). */\nexport const GATE_BANNED_SYNTAX: readonly string[] = lists.bannedSyntax;\n\n/** The raw lists, for parity tests and the database trigger's generator. */\nexport const GATE_LISTS = lists;\n\nconst IMPORT_RE = /^\\s*import\\s+(?:[^'\"]*?\\s+from\\s+)?['\"]([^'\"]+)['\"]/gm;\nconst EXPORT_FROM_RE = /^\\s*export\\s+(?:\\*|\\{[^}]*\\})\\s+from\\s+['\"]([^'\"]+)['\"]/gm;\nconst DYNAMIC_IMPORT_RE = /(?<![.\\w$])import\\s*\\(/g;\n\nfunction escapeForRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction lineAt(source: string, index: number): number {\n let line = 1;\n for (let i = 0; i < index && i < source.length; i++) {\n if (source.charCodeAt(i) === 10) line++;\n }\n return line;\n}\n\n/** Normalize a relative specifier against the importing file, without extension guessing. */\nexport function resolveRelativePath(fromFile: string, specifier: string): string {\n const base = fromFile.split(\"/\").slice(0, -1);\n for (const part of specifier.split(\"/\")) {\n if (part === \"\" || part === \".\") continue;\n if (part === \"..\") base.pop();\n else base.push(part);\n }\n return base.join(\"/\");\n}\n\nconst RESOLVE_SUFFIXES = [\"\", \".tsx\", \".ts\", \".jsx\", \".js\", \".json\", \"/index.tsx\", \"/index.ts\", \"/index.jsx\", \"/index.js\"];\n\n/** The file in `files` a relative specifier names, or null. */\nexport function resolveRelativeFile(\n files: Readonly<Record<string, string>>,\n fromFile: string,\n specifier: string,\n): string | null {\n const target = resolveRelativePath(fromFile, specifier);\n for (const suffix of RESOLVE_SUFFIXES) {\n const candidate = `${target}${suffix}`;\n if (Object.prototype.hasOwnProperty.call(files, candidate)) return candidate;\n }\n return null;\n}\n\n/** The module paths a source imports, in source order, de-duplicated. */\nexport function importPaths(source: string): string[] {\n const found = new Set<string>();\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source ?? \"\")) !== null) {\n if (match[1]) found.add(match[1]);\n }\n }\n return [...found];\n}\n\nconst ALLOWED_SENTENCE =\n \"Rewrite it using only the documented scope (react, lucide-react, recharts, \" +\n \"@ai-matrx/design-system/controls, @ai-matrx/design-system, @/lib/utils, \" +\n \"@/components/ui/*, @/components/kind-kit/*, CopyButtons/CopyForAiButton, Markdown) \" +\n \"or a file of this component.\";\n\nfunction importFindings(files: Readonly<Record<string, string>>, file: string, source: string): Finding[] {\n const out: Finding[] = [];\n const allowed = new Set(GATE_ALLOWED_IMPORTS);\n for (const re of [IMPORT_RE, EXPORT_FROM_RE]) {\n re.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(source)) !== null) {\n const path = match[1] ?? \"\";\n const line = lineAt(source, match.index + match[0].indexOf(path));\n if (path.startsWith(\"./\") || path.startsWith(\"../\")) {\n if (!resolveRelativeFile(files, file, path)) {\n out.push({\n rule: \"relative-import-missing\",\n file,\n line,\n severity: \"refuse\",\n message: `This file imports \"${path}\", but no file of this component has that name. Add the file or fix the path.`,\n });\n }\n continue;\n }\n if (!allowed.has(path)) {\n out.push({\n rule: \"import-not-allowed\",\n file,\n line,\n severity: \"refuse\",\n message: `This component imports \"${path}\", which is outside the sandbox scope, so it would render as a marked placeholder. ${ALLOWED_SENTENCE}`,\n });\n }\n }\n }\n DYNAMIC_IMPORT_RE.lastIndex = 0;\n const dyn = DYNAMIC_IMPORT_RE.exec(source);\n if (dyn) {\n out.push({\n rule: \"dynamicImport\",\n file,\n line: lineAt(source, dyn.index),\n severity: \"refuse\",\n message:\n \"This component uses a dynamic import(). The in-page compiler has no module loader, so the call would either fail at render or reach code nobody vetted. Import from the scope at the top of the file instead.\",\n });\n }\n return out;\n}\n\nfunction bannedGlobalMessage(name: string): string {\n return (\n `This component uses \"${name}\", which components stored in the database may ` +\n \"not use. They run inside the signed-in page, so anything that reaches the \" +\n \"network, browser storage, or the JavaScript evaluator could read or send \" +\n \"the reader's data. Render what the Shape hands you in props.data and use \" +\n \"a Shape action for anything the component needs from the server.\"\n );\n}\n\nfunction bannedMemberCallMessage(name: string): string {\n return (\n `This component uses \".${name}(\", which components stored in the database ` +\n \"may not use. Calling a value's constructor reaches the JavaScript \" +\n \"evaluator, so it could run code nobody reviewed inside the signed-in \" +\n \"page. Write the logic out directly instead.\"\n );\n}\n\nfunction bannedComputedAccessMessage(name: string): string {\n return (\n `This component uses \"${name}[\", which components stored in the database ` +\n \"may not use. Looking a property up by a computed name hides which \" +\n \"browser capability the component reaches, so no review can tell whether \" +\n `it is safe. Name what you need directly, or use props.data and a Shape ` +\n \"action for anything the component needs from the server.\"\n );\n}\n\nfunction globalFindings(file: string, code: string): Finding[] {\n const out: Finding[] = [];\n const push = (rule: string, re: RegExp, message: string) => {\n const m = re.exec(code);\n if (m) out.push({ rule, file, line: lineAt(code, m.index), severity: \"refuse\", message });\n };\n for (const name of GATE_BANNED_GLOBALS) {\n push(\"bannedGlobal\", new RegExp(`(?<![.\\\\w$])${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_CALLABLES) {\n const e = escapeForRegExp(name);\n push(\"bannedCallable\", new RegExp(`\\\\bnew\\\\s+${e}\\\\s*\\\\(|(?<![.\\\\w$])${e}\\\\s*\\\\(`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_ACCESS) {\n push(\"bannedMemberAccess\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\b`), bannedGlobalMessage(name));\n }\n for (const name of GATE_BANNED_MEMBER_CALLS) {\n push(\"bannedMemberCall\", new RegExp(`\\\\.\\\\s*${escapeForRegExp(name)}\\\\s*\\\\(`), bannedMemberCallMessage(name));\n }\n for (const name of GATE_BANNED_COMPUTED_ACCESS) {\n const e = escapeForRegExp(name);\n push(\"bannedComputedAccess\", new RegExp(`(?<![.\\\\w$])${e}\\\\s*\\\\[|\\\\.\\\\s*${e}\\\\s*\\\\[`), bannedComputedAccessMessage(name));\n }\n return out;\n}\n\n/**\n * THE ONE GATE (CONTRACTS §7). Every finding names its file and line; any\n * `refuse` finding means the code may not be stored. `.html` files and\n * `.json` files are not compiled in the page and are skipped.\n */\nexport function gate(files: Readonly<Record<string, string>>): Finding[] {\n const out: Finding[] = [];\n for (const [file, source] of Object.entries(files)) {\n if (/\\.(html?|json|css|md)$/i.test(file)) continue;\n const code = source ?? \"\";\n out.push(...importFindings(files, file, code), ...globalFindings(file, code));\n }\n return out;\n}\n\n/**\n * The single-body form today's writers call: the first refusing sentence, or\n * null when the source may be stored. `flavor: \"html\"` bodies render in an\n * opaque-origin iframe and are not checked.\n */\nexport function componentSourceGate(source: string, options?: { flavor?: string | null }): string | null {\n if ((options?.flavor ?? \"\").toLowerCase() === \"html\") return null;\n const finding = gate({ \"component.tsx\": source ?? \"\" }).find((f) => f.severity === \"refuse\");\n return finding ? finding.message : null;\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -78,6 +78,7 @@ var gate_lists_default = {
78
78
  "@/components/MarkdownStream",
79
79
  "@/components/agent-copy/CopyButtons",
80
80
  "@/components/agent-copy/CopyForAiButton",
81
+ "@/components/kind-kit/KindActionButton",
81
82
  "@/components/kind-kit/KindHeaderBar",
82
83
  "@/components/kind-kit/KindPanel",
83
84
  "@/components/kind-kit/KindPanelGrid",
@@ -324,7 +325,7 @@ function markdownAlias(path, description) {
324
325
  return { path, strategy: "named", exportMap: { default: "MarkdownStream" }, core: true, owner: "host", description };
325
326
  }
326
327
  function kindKit(name, exports, description) {
327
- return { path: `@/components/kind-kit/${name}`, strategy: "named", exports, owner: "host", description };
328
+ return { path: `@/components/kind-kit/${name}`, strategy: "named", exports, owner: "package", description };
328
329
  }
329
330
  var SCOPE_ENTRIES = [
330
331
  // ── Core ─────────────────────────────────────────────────────────────────
@@ -337,13 +338,15 @@ var SCOPE_ENTRIES = [
337
338
  { path: "@ai-matrx/design-system/controls", strategy: "spread", core: true, owner: "package", description: "THE controls: Button, Field, SearchField, Select, SegmentedControl, Tabs, Badge, Switch, Textarea, EmptyState\u2026" },
338
339
  { path: "@ai-matrx/design-system", strategy: "spread", owner: "package", description: "Design-system surfaces: Card, Dialog, Popover, Tooltip, Table, Accordion\u2026" },
339
340
  // ── Copy actions ─────────────────────────────────────────────────────────
340
- { path: "@/components/agent-copy/CopyButtons", strategy: "named", exports: ["CopyButtons"], owner: "host", description: "Copy / Copy-for-AI / JSON / Export bar from caller-supplied builders" },
341
+ { path: "@/components/agent-copy/CopyButtons", strategy: "named", exports: ["CopyButtons"], owner: "package", description: "Copy / Copy-for-AI / JSON / Export bar from caller-supplied builders (the kind-kit copy-bar slot: the host's own bar when registered, a plain Copy button otherwise)" },
341
342
  { path: "@/components/agent-copy/CopyForAiButton", strategy: "named", exports: ["CopyForAiButton"], owner: "host", description: "Single Copy-for-AI action" },
342
- // ── kind-kit ─────────────────────────────────────────────────────────────
343
+ // ── kind-kit (@ai-matrx/content-ir-react/kind-kit; hosts register its copy
344
+ // bar and read notices with setKindKitHost) ───────────────────────────
343
345
  kindKit("SortableList", ["SortableList"], "Drag-to-reorder list with arrow fallback and onRemove"),
344
346
  kindKit("KindPanelGrid", ["KindPanelGrid"], "Content-aware auto-fit grid of equal-height panels"),
345
347
  kindKit("KindPanel", ["KindPanel"], "Compact panel: header + overflow menu, subline, body, footer"),
346
348
  kindKit("KindHeaderBar", ["KindHeaderBar"], "Kind title + stats + copy bar"),
349
+ kindKit("KindActionButton", ["KindActionButton"], "Button for the component's runAction prop: busy, optional confirm, inline error"),
347
350
  kindKit("StreamingSkeleton", ["StreamingSkeleton", "useStreamingValue", "streamList", "streamText"], "Streaming skeletons + tolerant partial-value reads"),
348
351
  kindKit("TagList", ["KeywordChip", "TagList"], "Wrapping chips with select, remove, inline edit, add"),
349
352
  // ── Markdown (one renderer, four spellings stored code uses) ─────────────
@@ -432,6 +435,7 @@ var LucideModule = __toESM(require("lucide-react"), 1);
432
435
  var IconsModule = __toESM(require("@ai-matrx/icons"), 1);
433
436
  var DesignSystem = __toESM(require("@ai-matrx/design-system"), 1);
434
437
  var Controls = __toESM(require("@ai-matrx/design-system/controls"), 1);
438
+ var KindKit = __toESM(require("@ai-matrx/content-ir-react/kind-kit"), 1);
435
439
  var STORE_KEY = /* @__PURE__ */ Symbol.for("ai-matrx.code-runtime.modules");
436
440
  function store() {
437
441
  const g = globalThis;
@@ -456,6 +460,9 @@ var LEGACY_UI_MODULE = {
456
460
  TabsListLegacy: ds.TabsList,
457
461
  TabsTriggerLegacy: ds.TabsTrigger
458
462
  };
463
+ var COPY_BUTTONS_MODULE = {
464
+ CopyButtons: (props) => ReactModule.createElement(KindKit.getKindKitHost().CopyButtons, props)
465
+ };
459
466
  function packageLoader(path) {
460
467
  if (path === "react") return () => ReactModule;
461
468
  if (path === "lucide-react") return () => LucideModule;
@@ -464,6 +471,8 @@ function packageLoader(path) {
464
471
  if (path === "@ai-matrx/design-system/controls") return () => Controls;
465
472
  if (path === "@/lib/utils") return () => ({ cn: ds.cn });
466
473
  if (path.startsWith("@/components/ui/")) return () => LEGACY_UI_MODULE;
474
+ if (path.startsWith("@/components/kind-kit/")) return () => KindKit;
475
+ if (path === "@/components/agent-copy/CopyButtons") return () => COPY_BUTTONS_MODULE;
467
476
  if (path === "recharts") return () => import("recharts");
468
477
  return null;
469
478
  }
@@ -724,6 +733,7 @@ function applyToFlatScope(entry, mod, values) {
724
733
  if (entry.strategy === "spread") {
725
734
  for (const key of ownKeys(mod)) {
726
735
  if (key === "default" || key === "__esModule") continue;
736
+ if (key in globalThis) continue;
727
737
  values[key] = mod[key];
728
738
  }
729
739
  return;
@@ -810,7 +820,9 @@ function buildScope(spec) {
810
820
  }
811
821
  function patchMissingJsx(identifiers, state, declared, skip) {
812
822
  for (const identifier of identifiers) {
813
- if (skip.has(identifier) || identifier in state.values || declared.has(identifier)) continue;
823
+ if (identifier in state.values || declared.has(identifier)) continue;
824
+ const providedBySpread = [...state.safeProxyPaths.values()].some(({ keys }) => keys.has(identifier));
825
+ if (skip.has(identifier) && !providedBySpread) continue;
814
826
  let provided = false;
815
827
  for (const [, { proxy, keys }] of state.safeProxyPaths) {
816
828
  if (!keys.has(identifier)) continue;
@@ -878,6 +890,10 @@ function bindImports(mod, allFiles, state) {
878
890
  } catch {
879
891
  present = false;
880
892
  }
893
+ if (!present && state.values[imported] !== void 0) {
894
+ view[imported] = state.values[imported];
895
+ present = true;
896
+ }
881
897
  if (!present) {
882
898
  if (/^[A-Z]/.test(imported)) view[imported] = createUnresolvedImportStandIn(imported, source);
883
899
  recordUnresolved(state, { identifier: imported === local ? local : `${imported} as ${local}`, importPath: source });