From d0bd86f9f820e04895420eaf5c7e4de4eaa4c73d Mon Sep 17 00:00:00 2001 From: Cory Rylan Date: Fri, 18 Sep 2026 23:24:15 -0500 Subject: [PATCH] feat(pi): pi extension Signed-off-by: Cory Rylan --- .github/workflows/ci.yml | 2 + AGENTS.md | 2 + NOTICE.md | 54 +- README.md | 1 + commitlint.config.js | 1 + knip.config.js | 17 + package.json | 9 + pnpm-lock.yaml | 1050 ++++++++++++++++- pnpm-workspace.yaml | 14 + projects/internals/ci/coverage-projects.js | 1 + projects/internals/metadata/package.json | 3 + .../metadata/src/tasks/projects.utils.ts | 1 + .../metadata/src/tasks/tests.utils.test.ts | 1 + .../metadata/src/tasks/tests.utils.ts | 1 + .../internals/tools/src/api/service.test.ts | 30 +- projects/internals/tools/src/api/service.ts | 27 +- .../internals/tools/src/playground/service.ts | 4 +- .../internals/tools/src/project/starters.ts | 2 +- projects/pi/CHANGELOG.md | 1 + projects/pi/DEVELOPMENT.md | 19 + projects/pi/NOTICE.md | 101 ++ projects/pi/README.md | 89 ++ projects/pi/eslint.config.js | 12 + projects/pi/package.json | 223 ++++ projects/pi/src/auto-validation.test.ts | 294 +++++ projects/pi/src/auto-validation.ts | 205 ++++ projects/pi/src/index.test.ts | 25 + projects/pi/src/index.ts | 24 + projects/pi/src/logging.ts | 13 + projects/pi/src/package.test.ts | 90 ++ projects/pi/src/renderers.test.ts | 118 ++ projects/pi/src/renderers.ts | 97 ++ projects/pi/src/results.test.ts | 81 ++ projects/pi/src/results.ts | 77 ++ projects/pi/src/schema.test.ts | 128 ++ projects/pi/src/schema.ts | 93 ++ projects/pi/src/scripts/write-resources.ts | 127 ++ projects/pi/src/tools.test.ts | 131 ++ projects/pi/src/tools.ts | 108 ++ projects/pi/tsconfig.json | 23 + projects/pi/tsconfig.lib.json | 7 + projects/pi/vite.config.ts | 8 + projects/pi/vitest.config.ts | 18 + .../static/images/integrations/nextjs.svg | 2 +- .../public/static/images/integrations/pi.svg | 1 + projects/site/src/_11ty/layouts/common.js | 2 + .../site/src/_11ty/shortcodes/svg-logo.js | 49 +- .../site/src/docs/changelog/index.11tydata.js | 8 + projects/site/src/docs/integrations/pi.md | 80 ++ projects/site/src/index.11tydata.js | 8 + projects/site/src/index.md | 7 +- projects/site/src/index.test.lighthouse.ts | 10 +- 52 files changed, 3402 insertions(+), 97 deletions(-) create mode 100644 projects/pi/CHANGELOG.md create mode 100644 projects/pi/DEVELOPMENT.md create mode 100644 projects/pi/NOTICE.md create mode 100644 projects/pi/README.md create mode 100644 projects/pi/eslint.config.js create mode 100644 projects/pi/package.json create mode 100644 projects/pi/src/auto-validation.test.ts create mode 100644 projects/pi/src/auto-validation.ts create mode 100644 projects/pi/src/index.test.ts create mode 100644 projects/pi/src/index.ts create mode 100644 projects/pi/src/logging.ts create mode 100644 projects/pi/src/package.test.ts create mode 100644 projects/pi/src/renderers.test.ts create mode 100644 projects/pi/src/renderers.ts create mode 100644 projects/pi/src/results.test.ts create mode 100644 projects/pi/src/results.ts create mode 100644 projects/pi/src/schema.test.ts create mode 100644 projects/pi/src/schema.ts create mode 100644 projects/pi/src/scripts/write-resources.ts create mode 100644 projects/pi/src/tools.test.ts create mode 100644 projects/pi/src/tools.ts create mode 100644 projects/pi/tsconfig.json create mode 100644 projects/pi/tsconfig.lib.json create mode 100644 projects/pi/vite.config.ts create mode 100644 projects/pi/vitest.config.ts create mode 100644 projects/site/public/static/images/integrations/pi.svg create mode 100644 projects/site/src/docs/integrations/pi.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 341139264b..9fbbe2b17d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,6 +79,8 @@ jobs: projects/media/package.json projects/monaco/dist projects/monaco/package.json + projects/pi/dist + projects/pi/package.json projects/pages/dist projects/plot/dist projects/plot/package.json diff --git a/AGENTS.md b/AGENTS.md index fc7498e9cb..eed47d4d26 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -117,6 +117,7 @@ The repository contains a top-level workspace with individual project directorie - `/projects/lint` - Elements lint configurations and custom rules - `/projects/monaco` - Monaco editor integration - `/projects/pages` - GitHub Pages deployment project +- `/projects/pi` - Native Pi extension and Elements agent tools - `/projects/site` - Documentation site (11ty) - `/projects/internals` - Internal tooling (vite configs, eslint, patterns, metadata) @@ -238,6 +239,7 @@ git commit -m "chore(docs): update component examples" - `media` - Media playback UI components (`/projects/media`) - `monaco` - Monaco editor integration (`/projects/monaco`) - `pages` - GitHub Pages deployment project (`/projects/pages`) +- `pi` - Native Pi extension (`/projects/pi`) - `ci` - Build/CI tooling (`/projects/internals`) ### Prose Linting (Vale) diff --git a/NOTICE.md b/NOTICE.md index d1b583c056..ae412bf621 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -31,24 +31,45 @@ This product includes the following bundled third-party software: - @modelcontextprotocol/server v2.0.0 [MIT] (used by: @nvidia-elements/cli) Copyright: Anthropic, PBC (https://anthropic.com) -- adm-zip v0.6.1 [MIT] (used by: @nvidia-elements/cli) +- @pnpm/catalogs.config v0.1.0 [MIT] (used by: @nvidia-elements/pi) + Copyright: Unknown + +- @pnpm/exportable-manifest v7.0.3 [MIT] (used by: @nvidia-elements/pi) + Copyright: Unknown + +- @pnpm/read-project-manifest v6.0.6 [MIT] (used by: @nvidia-elements/pi) + Copyright: Unknown + +- @pnpm/workspace.read-manifest v2.2.0 [MIT] (used by: @nvidia-elements/pi) + Copyright: Unknown + +- adm-zip v0.6.1 [MIT] (used by: @nvidia-elements/cli, @nvidia-elements/pi) Copyright: Nasca Iacob (https://github.com/cthackers) -- archiver v8.0.0 [MIT] (used by: @nvidia-elements/cli) +- archiver v8.0.0 [MIT] (used by: @nvidia-elements/cli, @nvidia-elements/pi) Copyright: Chris Talkington (http://christalkington.com/) -- eslint v10.10.0 [MIT] (used by: @nvidia-elements/cli) +- eslint v10.10.0 [MIT] (used by: @nvidia-elements/cli, @nvidia-elements/pi) Copyright: Nicholas C. Zakas -- fast-glob v3.3.3 [MIT] (used by: @nvidia-elements/cli) +- fast-glob v3.3.3 [MIT] (used by: @nvidia-elements/cli, @nvidia-elements/pi) Copyright: Denis Malinochkin (https://mrmlnc.com) +- fflate v0.8.3 [MIT] (used by: @nvidia-elements/pi) + Copyright: Arjun Barrett + - highlight.js v11.12.0 [BSD-3-Clause] (used by: @nvidia-elements/code) Copyright: Josh Goebel +- html-format v1.1.7 [MIT] (used by: @nvidia-elements/pi) + Copyright: Mohamed Akram + - ignore v7.0.8 [MIT] (used by: @nvidia-elements/cli) Copyright: kael +- ignore v7.0.6 [MIT] (used by: @nvidia-elements/pi) + Copyright: kael + - lit v3.3.3 [BSD-3-Clause] (used by: @nvidia-elements/code, @nvidia-elements/core, @nvidia-elements/markdown, @nvidia-elements/media, @nvidia-elements/monaco, @nvidia-elements/plot, @nvidia-elements/scene) Copyright: Google LLC @@ -64,7 +85,7 @@ This product includes the following bundled third-party software: - marked-terminal v7.3.0 [MIT] (used by: @nvidia-elements/cli) Copyright: Mikael Brevik -- minisearch v7.2.0 [MIT] (used by: @nvidia-elements/lint) +- minisearch v7.2.0 [MIT] (used by: @nvidia-elements/lint, @nvidia-elements/pi) Copyright: Luca Ongaro - monaco-editor v0.55.1 [MIT] (used by: @nvidia-elements/monaco) @@ -73,16 +94,25 @@ This product includes the following bundled third-party software: - open v11.0.2 [MIT] (used by: @nvidia-elements/cli) Copyright: Sindre Sorhus (https://sindresorhus.com) +- open v11.0.0 [MIT] (used by: @nvidia-elements/pi) + Copyright: Sindre Sorhus (https://sindresorhus.com) + - ora v9.4.1 [MIT] (used by: @nvidia-elements/cli) Copyright: Sindre Sorhus (https://sindresorhus.com) -- publint v0.3.24 [MIT] (used by: @nvidia-elements/cli) +- publint v0.3.24 [MIT] (used by: @nvidia-elements/cli, @nvidia-elements/pi) Copyright: Bjorn Lu +- sanitize-html v2.17.7 [MIT] (used by: @nvidia-elements/pi) + Copyright: Apostrophe Technologies, Inc. + +- ts-morph v28.0.0 [MIT] (used by: @nvidia-elements/pi) + Copyright: David Sherret + - yargs v18.1.0 [MIT] (used by: @nvidia-elements/cli) Copyright: Unknown -- zod v4.5.4 [MIT] (used by: @nvidia-elements/cli) +- zod v4.5.4 [MIT] (used by: @nvidia-elements/cli, @nvidia-elements/pi) Copyright: Colin McDonnell ============================================================================== @@ -318,19 +348,29 @@ The following bundled components are provided under the MIT license: @inquirer/prompts v8.7.2 - Copyright Simon Boudrias @modelcontextprotocol/ext-apps v1.7.5 - Copyright Olivier Chafik @modelcontextprotocol/server v2.0.0 - Copyright Anthropic, PBC (https://anthropic.com) +@pnpm/catalogs.config v0.1.0 - Copyright Unknown +@pnpm/exportable-manifest v7.0.3 - Copyright Unknown +@pnpm/read-project-manifest v6.0.6 - Copyright Unknown +@pnpm/workspace.read-manifest v2.2.0 - Copyright Unknown adm-zip v0.6.1 - Copyright Nasca Iacob (https://github.com/cthackers) archiver v8.0.0 - Copyright Chris Talkington (http://christalkington.com/) eslint v10.10.0 - Copyright Nicholas C. Zakas fast-glob v3.3.3 - Copyright Denis Malinochkin (https://mrmlnc.com) +fflate v0.8.3 - Copyright Arjun Barrett +html-format v1.1.7 - Copyright Mohamed Akram ignore v7.0.8 - Copyright kael +ignore v7.0.6 - Copyright kael markdown-it v15.0.1 - Copyright Unknown marked v18.0.14 - Copyright Christopher Jeffrey marked-terminal v7.3.0 - Copyright Mikael Brevik minisearch v7.2.0 - Copyright Luca Ongaro monaco-editor v0.55.1 - Copyright Microsoft Corporation open v11.0.2 - Copyright Sindre Sorhus (https://sindresorhus.com) +open v11.0.0 - Copyright Sindre Sorhus (https://sindresorhus.com) ora v9.4.1 - Copyright Sindre Sorhus (https://sindresorhus.com) publint v0.3.24 - Copyright Bjorn Lu +sanitize-html v2.17.7 - Copyright Apostrophe Technologies, Inc. +ts-morph v28.0.0 - Copyright David Sherret yargs v18.1.0 - Copyright Unknown zod v4.5.4 - Copyright Colin McDonnell diff --git a/README.md b/README.md index 2558ea85f5..cd8f0082f9 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ git commit -a -s -m "fix(core): disable multi-select" | `media` | `/projects/media` | | `monaco` | `/projects/monaco` | | `pages` | `/projects/pages` | +| `pi` | `/projects/pi` | | `starters` | `/projects/starters` | | `styles` | `/projects/styles` | | `themes` | `/projects/themes` | diff --git a/commitlint.config.js b/commitlint.config.js index 74bc1f4e7d..3e5b47dc95 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -26,6 +26,7 @@ export default { 'core', 'pages', 'playground', + 'pi', 'plot', 'styles', 'themes', diff --git a/knip.config.js b/knip.config.js index fb2e195948..a6633c6821 100644 --- a/knip.config.js +++ b/knip.config.js @@ -188,6 +188,23 @@ export default { entry: [...PROJECT_FILES], project: [...PROJECT_FILES] }, + 'projects/pi': { + entry: [...PACKAGE_FILES, ...SOURCE_INDEX, ...TEST_ENTRIES, ...VITE_CONFIGS, ...VITEST_CONFIGS], + project: [...PROJECT_FILES, ...SOURCE_FILES], + ignoreDependencies: [ + '@nvidia-elements/themes', // Required by the externalized @nvidia-elements/lint runtime. + '@pnpm/catalogs.config', + '@pnpm/exportable-manifest', + '@pnpm/read-project-manifest', + '@pnpm/workspace.read-manifest', + 'fast-glob', + 'fflate', + 'html-format', + 'ignore', + 'sanitize-html', + 'zod' + ] + }, 'projects/plot': { entry: [ ...PACKAGE_FILES, diff --git a/package.json b/package.json index 0cfc680d9c..ef08eff398 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "./projects/media:ci", "./projects/monaco:ci", "./projects/pages:ci", + "./projects/pi:ci", "./projects/plot:ci", "./projects/scene:ci", "./projects/site:ci", @@ -169,6 +170,7 @@ "release:markdown", "release:media", "release:monaco", + "release:pi", "release:styles" ] }, @@ -230,6 +232,12 @@ "release:labs-forms" ] }, + "release:pi": { + "command": "cd projects/pi && HUSKY=0 pnpm exec semantic-release", + "dependencies": [ + "release:lint" + ] + }, "release:styles": { "command": "cd projects/styles && HUSKY=0 pnpm exec semantic-release", "dependencies": [ @@ -280,6 +288,7 @@ "lint:fix": { "command": "prettier --config prettier.config.js --write .", "dependencies": [ + "./projects/pi:lint:fix", "./projects/code:lint:fix", "./projects/create:lint:fix", "./projects/core:lint:fix", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4c4bd6d98..65750c3e77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -176,6 +176,12 @@ catalogs: '@custom-elements-manifest/analyzer': specifier: 0.11.0 version: 0.11.0 + '@earendil-works/pi-coding-agent': + specifier: 0.99.1 + version: 0.99.1 + '@earendil-works/pi-tui': + specifier: 0.99.1 + version: 0.99.1 '@eslint/css': specifier: 2.0.0 version: 2.0.0 @@ -302,6 +308,9 @@ catalogs: ts-morph: specifier: 28.0.0 version: 28.0.0 + typebox: + specifier: 1.3.7 + version: 1.3.7 typescript: specifier: 6.0.3 version: 6.0.3 @@ -462,7 +471,7 @@ importers: version: 8.7.2(@types/node@26.5.0) '@modelcontextprotocol/ext-apps': specifier: 'catalog:' - version: 1.7.5(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.5.4) + version: 1.7.5(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.5.4) '@modelcontextprotocol/server': specifier: 'catalog:' version: 2.0.0 @@ -1392,6 +1401,100 @@ importers: specifier: 'catalog:' version: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0) + projects/pi: + dependencies: + '@nvidia-elements/lint': + specifier: workspace:^ + version: link:../lint + '@nvidia-elements/themes': + specifier: workspace:^ + version: link:../themes + '@pnpm/catalogs.config': + specifier: 0.1.0 + version: 0.1.0 + '@pnpm/exportable-manifest': + specifier: 7.0.3 + version: 7.0.3 + '@pnpm/read-project-manifest': + specifier: 6.0.6 + version: 6.0.6 + '@pnpm/workspace.read-manifest': + specifier: 2.2.0 + version: 2.2.0 + adm-zip: + specifier: 'catalog:' + version: 0.6.1 + archiver: + specifier: 8.0.0 + version: 8.0.0 + eslint: + specifier: 10.10.0 + version: 10.10.0(jiti@2.7.0)(supports-color@10.2.2) + fast-glob: + specifier: 'catalog:' + version: 3.3.3 + fflate: + specifier: 0.8.3 + version: 0.8.3 + html-format: + specifier: 1.1.7 + version: 1.1.7 + ignore: + specifier: 7.0.6 + version: 7.0.6 + minisearch: + specifier: 7.2.0 + version: 7.2.0 + open: + specifier: 11.0.0 + version: 11.0.0 + publint: + specifier: 'catalog:' + version: 0.3.24 + sanitize-html: + specifier: 2.17.7 + version: 2.17.7 + ts-morph: + specifier: 'catalog:' + version: 28.0.0 + zod: + specifier: 'catalog:' + version: 4.5.4 + devDependencies: + '@earendil-works/pi-coding-agent': + specifier: 'catalog:' + version: 0.99.1(@aws-sdk/credential-provider-node@3.972.83)(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(@smithy/signature-v4@5.7.3)(supports-color@10.2.2)(ws@8.21.3)(zod@4.5.4) + '@earendil-works/pi-tui': + specifier: 'catalog:' + version: 0.99.1 + '@internals/eslint': + specifier: workspace:* + version: link:../internals/eslint + '@internals/tools': + specifier: workspace:* + version: link:../internals/tools + '@internals/vite': + specifier: workspace:* + version: link:../internals/vite + '@types/node': + specifier: 'catalog:' + version: 26.5.0 + '@vitest/coverage-istanbul': + specifier: 'catalog:' + version: 5.0.0(vitest@5.0.0) + typebox: + specifier: 'catalog:' + version: 1.3.7 + typescript: + specifier: 'catalog:' + version: 6.0.3 + vite: + specifier: 'catalog:' + version: 8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0) + vitest: + specifier: 'catalog:' + version: 5.0.0(@opentelemetry/api@1.9.1)(@types/node@26.5.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-istanbul@5.0.0)(@vitest/ui@5.0.0)(jsdom@30.0.1)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)) + projects/plot: dependencies: '@nvidia-elements/core': @@ -2178,7 +2281,7 @@ importers: version: link:../../themes nuxt: specifier: 4.5.2 - version: 4.5.2(b859f4e8cb62fae0e3decfe5293f8478) + version: 4.5.2(b7188d0d9ad0b8052c818020062c5583) vue: specifier: 3.5.42 version: 3.5.42(typescript@6.0.3) @@ -2771,6 +2874,15 @@ packages: '@angular/platform-browser': 22.1.7 rxjs: ^6.5.3 || ^7.4.0 + '@anthropic-ai/sdk@0.124.0': + resolution: {integrity: sha512-cN5O8i9UVxHeOQAzj/XjshWXG8KiibJDw9OGpH2Z/eR3n/RBxdoLxDJOcfqAJWvjaMDFfHTBADU04hWRJVkDyA==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + '@asamuzakjp/css-color@6.0.7': resolution: {integrity: sha512-vC/bk1Lz7Tn/EfU9/apOTBk80/8dyGyWMowPoV1tJ52muDGsDqt2HPT2klrFUiY60MQmQv9q8yIht15JnBgDGw==} engines: {node: ^22.13.0 || >=24.0.0} @@ -2779,6 +2891,86 @@ packages: resolution: {integrity: sha512-93Z1N+BQNXysodoicpOIyNh2drHfz/CTf9nnT0FEx72GJcIiwgydD7tGAr78j41LsYn3hlRn+LdGPuBLn1Bl8Q==} engines: {node: ^22.13.0 || >=24.0.0} + '@aws-sdk/client-bedrock-runtime@3.1127.0': + resolution: {integrity: sha512-IDl/lrPb90aH+pZFHGNDmgH9nAUQj5PlZH1sJ3w7RikctyjHSnY3oNjZhrLoaBoQn/rNK0zsP6OHEqEhj2tdLA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.978.0': + resolution: {integrity: sha512-2yX9LUmxPklVjSGTb8dfnWRJSiFQ3TeH2nn7G1mdKHTfnabzF0+gfrS8rYfLWmZrQ8A3mEcxMJjRc51dL5KWaA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.71': + resolution: {integrity: sha512-JN+JHruYZw3GUZB8YGAlDk4wTDPOEAEEdEzj5nS0xodWR4smzHsN7PnK2j6IeOsDIj2aqua5DSbhXl9Gtf90FQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.73': + resolution: {integrity: sha512-uyYYnJOnlis8uQzaYGPd7N1JoioCoNpXgnkXYixsWJXHXgXyYi8WXJSDfofxJeWfQIGWLe2Nwyq60Uc7MZdVOg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.973.16': + resolution: {integrity: sha512-i++ly+0Uxa+u3ebSSyr0S/3CFhFJDxCXT3+Zj+mW2bXenEx5bKGCdTIKFu39SgXBNhWDjex/8cXUx9MUTMCrTw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.78': + resolution: {integrity: sha512-eUtswnXu0+Ii9ieRK+0L7aPFV3Z/dnW2VntJzjBP9xs8s+8p5nBNuymIXtXwZ+5r5+XJP3e32nMkuZ/r0HozEA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.83': + resolution: {integrity: sha512-jdso7ejzfRnatxMUZK4S/U6KbaDPCvfIV4XL+IQAPFDBt5rj5Fq595euqlK8Le4lNCMFR9oUpt+1l0aMgaayOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.71': + resolution: {integrity: sha512-lYmXJa4gvq4xN1lrT5NiP5vIYYKcGWAdj8y+8o6dlcateB5eF3Dn8DtmjjHKfMBrTPAMr2pebIiX/UOj8c1/UA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.973.15': + resolution: {integrity: sha512-6Jhcf4v0pSFdjk1EW2kvzuEBKD+UZ2uNcHUIglKKLndD20YhvkL2kdmDOV5/j4mYuWWwe/a1FQ1aomU86/Cg5Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.77': + resolution: {integrity: sha512-uylIQSUWpfLuH2LovxEEfwzJGM/SabLOfLMg6YXu/E8jJEKUdpdILCVCQCdFvHyu/7dLJOHPMfrSwduxO56NkQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.34': + resolution: {integrity: sha512-cTeVzpu1xEAkryTZBYhGwnQ6gOGyp8ZYZvmn0Sg/nI/ABmy/CRHHxPDJDUi9PxwxUtGGaatvfRUB3FCgT/rSWw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.29': + resolution: {integrity: sha512-dlRzHCgyB8W6hLuDC5pcT5q+ziPt00n4QGgGBE17ucLVU4zMa6lsbuUdQ2Pm75Z5VA8GF+R/+SgrRcaTdIzSIQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.53': + resolution: {integrity: sha512-bIrDaMENQmYRBHntOiOheqkiw5+fhKW4Lqb+mS1uqF0VwvdWI22fW2HFgWrng66CmYd+4k8ePlpj38sEfTuMLQ==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.45': + resolution: {integrity: sha512-mooq9Q+jLa18VoM7HouczmslZU60iiB0aKc/Ztnq/luIL1ud0z4DnYprLR/ZO1gp331S9tJctM1HZr7u6YKBXQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.46': + resolution: {integrity: sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1127.0': + resolution: {integrity: sha512-Dv2TMWBshJ+tF6ahs2Sy5bh4Iabsd4GAQqVvE9XZmYmnoaVbpS2QKIKE/HRacc7bTtbjEEvP+laGzHvHlf1CiQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1129.0': + resolution: {integrity: sha512-Sbl3rpzQdsG4ZK2zh0JWUYyZPKKorJlVOddA2T0DVbKJFrsW8J6wgnslxxUH04+WaBMr4A1HzJZvZX0xUvkniA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.974.5': + resolution: {integrity: sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.40': + resolution: {integrity: sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.3.0': + resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -3242,6 +3434,40 @@ packages: '@dxup/unimport@0.1.2': resolution: {integrity: sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==} + '@earendil-works/chord@0.99.1': + resolution: {integrity: sha512-4xyn0IBzJ+Xu/iOGi2hjXJGAR61QEhEWZsIqTDqr+GmItdquYwBO5jYFnqGiBaTqlY12/EpM7QHoEKSHbyvOug==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-agent-core@0.99.1': + resolution: {integrity: sha512-zywvWnj5FujeuFI/x/CJHwwxhcLIQgjqseTA+bQgX4O8gJTcgjRd/I8SZnQDqJvxC9QcV12ujiGLviv6EgwcCg==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-ai@0.99.1': + resolution: {integrity: sha512-4nV9JKc94iPX8bwdGPc2nTuVPKIPsffhnp3WoN9NYCNqbtoOF8LhYcIs/+Sn/alroqJK/5QRu6/Z6Ck+n0hyBA==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-codemode@0.99.1': + resolution: {integrity: sha512-oh8TMsBI3SWTN3xTQtX8u5n+BKhnVXcFagroWumfn6/WWfBnDYL/LmeQtjLb83WRTb9rcu+ZdK8rFa4vggvCJg==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-coding-agent@0.99.1': + resolution: {integrity: sha512-cWUrTOqA5M73cOYMgsh9PlhDrsBhavd+n5kVY6F7BGbGl1RjqCteVCoeVMVqhngoGACVDyw1tbLjajL8l9jrHg==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-mcp@0.99.1': + resolution: {integrity: sha512-YCFGPkmDzLwQuIzwfbP6Vuk/g/ukKpZhwTpbcfzomuI1Fkiu6hHRkOGwAqsO3G8cTkZWkM8vmOkFJjStQNC4qA==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-telemetry@0.99.1': + resolution: {integrity: sha512-9PBPjGk+TXRtuMianpqBbHBpYpyKusESF6rwdmgD0WTZSTUQXhcKEO0hAINRLuSwy4V7yPvXV+EVV0ONY7mbpQ==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-tui@0.99.1': + resolution: {integrity: sha512-gZp0Guat96Fr1AuC/xqVz5B2lulZakp/PxD1lXx3lSgBdjiqmwYhJbcQ0HRrGAfy0WtMGn9b05RJr5qJf7oIuw==} + engines: {node: '>=22.19.0'} + '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -3528,6 +3754,15 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + '@google/genai@2.21.0': + resolution: {integrity: sha512-+PDtco2/Z0ONdzCGekCoCT+O1VJS9xJQNN4XzQpXG/t3El/SWWMkCWlFRO1KmivOHPa4Q0VjUYu1HBKCZ/v33Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + '@gwhitney/detect-indent@7.0.1': resolution: {integrity: sha512-7bQW+gkKa2kKZPeJf6+c6gFK9ARxQfn+FKy9ScTBppyKRWH2KzsmweXUoklqeEiHiNVWaeP5csIdsNq6w7QhzA==} engines: {node: '>=12.20'} @@ -4349,6 +4584,16 @@ packages: '@cfworker/json-schema': optional: true + '@modelcontextprotocol/sdk@1.31.0': + resolution: {integrity: sha512-UvTMgnNlnIBO/22ob2RcVGDlcvOslQs8T59+FTGdA0L27a39fdGF/EDETNtDVK4DZGpwomlsYpRdA8UXcVL/pw==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@modelcontextprotocol/server@2.0.0': resolution: {integrity: sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==} engines: {node: '>=20'} @@ -5782,6 +6027,33 @@ packages: peerDependencies: '@opentelemetry/api': ^1.8 + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + '@publint/pack@0.1.7': resolution: {integrity: sha512-4EDEmvxWtgsCnnVeBvtFIFZtUhPPt1+bA9JrSwU4Sa//6oKtzCSlGGXYJr44OD9aGISymbieJ4mCKHUygUDU+g==} engines: {node: '>=18'} @@ -6469,6 +6741,9 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.0.0 '@opentelemetry/semantic-conventions': ^1.34.0 + '@silvia-odwyer/photon-node@0.3.4': + resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + '@simple-git/args-pathspec@1.0.3': resolution: {integrity: sha512-ngJMaHlsWDTfjyq9F3VIQ8b7NXbBLq5j9i5bJ6XLYtD6qlDXT7fdKY2KscWWUF8t18xx052Y/PUO1K1TRc9yKA==} @@ -6514,6 +6789,30 @@ packages: resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==} engines: {node: '>=12'} + '@smithy/core@3.34.1': + resolution: {integrity: sha512-dLcOUxz8YCv1RZUMKq6GbyUf95pLbrqh34bPvpCZ1+CByFF31BEAFewZjsGCnVsZTKdThNENfGyAgk2TJqVwSw==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.5.2': + resolution: {integrity: sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.8.0': + resolution: {integrity: sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.12.1': + resolution: {integrity: sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.7.3': + resolution: {integrity: sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.18.0': + resolution: {integrity: sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==} + engines: {node: '>=18.0.0'} + '@solid-devtools/debugger@0.28.1': resolution: {integrity: sha512-6qIUI6VYkXoRnL8oF5bvh2KgH71qlJ18hNw/mwSyY6v48eb80ZR48/5PDXufUa3q+MBSuYa1uqTMwLewpay9eg==} peerDependencies: @@ -6582,6 +6881,9 @@ packages: '@speed-highlight/core@1.2.15': resolution: {integrity: sha512-BMq1K3DsElxDWawkX6eLg9+CKJrTVGCBAWVuHXVUV2u0s2711qiChLSId6ikYPfxhdYocLNt3wWwSvDiTvFabw==} + '@stablelib/base64@1.0.1': + resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -6723,6 +7025,9 @@ packages: '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@types/shimmer@1.2.0': resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} @@ -7767,6 +8072,9 @@ packages: bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -7790,6 +8098,9 @@ packages: bottleneck@2.19.5: resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + brace-expansion@1.1.14: resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} @@ -7816,6 +8127,9 @@ packages: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -7902,6 +8216,10 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chalk@6.0.0: + resolution: {integrity: sha512-2uNTXIuTTxk7ciZgAU1BQcgnchcG0xXnrs6jzkQfj9SsRa9M2s5zE8WT96hS6KmG4MzWHSrvH43DF1m4XRkrFg==} + engines: {node: '>=22'} + change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} @@ -8723,6 +9041,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -9127,6 +9448,9 @@ packages: resolution: {integrity: sha512-99jPl8JkCSCa4VlboNU1XuL98ijm74Pm9CGo6H4BoMVoVh1uhguQcvwLgXDT8Vkl2qj/UEQ0J9gD8beHjTFk1w==} hasBin: true + fast-sha256@1.3.0: + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + fast-string-truncated-width@3.0.3: resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} @@ -9319,6 +9643,14 @@ packages: fzf@0.5.2: resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} + gaxios@7.3.1: + resolution: {integrity: sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} @@ -9338,6 +9670,10 @@ packages: resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -9449,6 +9785,14 @@ packages: globjoin@0.1.4: resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + google-auth-library@10.9.1: + resolution: {integrity: sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -9463,6 +9807,10 @@ packages: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} + grok-mermaid@0.2.3: + resolution: {integrity: sha512-/4KopAbsjvuRP9MdPtlDjOHUmUVEohOX73JNcsWpzAtFxh+bq5+Dhb6gzvRieLDwIPQIR3/vy8V1NNTuz4Zsmg==} + engines: {node: '>=18'} + gzip-size@7.0.0: resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -9567,6 +9915,10 @@ packages: resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} engines: {node: ^20.17.0 || >=22.9.0} + hosted-git-info@9.0.3: + resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} + engines: {node: ^20.17.0 || >=22.9.0} + html-encoding-sniffer@3.0.0: resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} engines: {node: '>=12'} @@ -10138,12 +10490,19 @@ packages: engines: {node: '>=6'} hasBin: true + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -10178,6 +10537,12 @@ packages: resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} engines: {node: '>=8'} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + kapsule@1.16.3: resolution: {integrity: sha512-4+5mNNf4vZDSwPhKprKwz3330iisPrb08JyMgbsdFrimBCKNHecua/WBwvVg3n7vwx0C1ARjfhwIpbrbd9n5wg==} engines: {node: '>=12'} @@ -10442,9 +10807,6 @@ packages: lit-html@3.3.3: resolution: {integrity: sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==} - lit@3.3.2: - resolution: {integrity: sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==} - lit@3.3.3: resolution: {integrity: sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==} @@ -10532,6 +10894,9 @@ packages: resolution: {integrity: sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg==} engines: {node: '>=22'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -10616,6 +10981,11 @@ packages: engines: {node: '>= 18'} hasBin: true + marked@18.0.11: + resolution: {integrity: sha512-HnslJfsZkRPBDJRHvVtAaWlZHEpSu7u8LgQuJCELjRKuWR+hpq4A7sLq3p8HaI9ypVoXDXxV34CsQJEe1+J5Aw==} + engines: {node: '>= 20'} + hasBin: true + marked@18.0.14: resolution: {integrity: sha512-mBHK6FBHuBAlhgRe88w9F0O1AbwwXJUcQibUbC/QcdTbVGAD7aWza+xt3N6oT/jCZx3/OMeS+8rnuiHZcQ9s7A==} engines: {node: '>= 20'} @@ -10835,6 +11205,10 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} @@ -11268,6 +11642,30 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} + openai@7.19.0: + resolution: {integrity: sha512-MX2s3u2L5racTO0CC/SWpCOasJQBCJrqLKXK+l82cAhdeF8mPMBEe/gxMm0ZFa2xpKpOFLRjxv5afYEZbBXmbQ==} + engines: {node: '>=22.0.0'} + peerDependencies: + '@aws-sdk/credential-provider-node': '>=3.972.0 <4' + '@smithy/hash-node': '>=4.3.0 <5' + '@smithy/signature-v4': '>=5.4.0 <6' + undici: '>=5 <9' + ws: ^8.21.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@aws-sdk/credential-provider-node': + optional: true + '@smithy/hash-node': + optional: true + '@smithy/signature-v4': + optional: true + undici: + optional: true + ws: + optional: true + zod: + optional: true + opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true @@ -11359,6 +11757,10 @@ packages: resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==} engines: {node: '>=12'} + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + p-timeout@6.1.4: resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} engines: {node: '>=14.16'} @@ -11454,6 +11856,9 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} @@ -12242,6 +12647,10 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protobufjs@7.6.6: + resolution: {integrity: sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -12302,6 +12711,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quickjs-wasi@3.6.2: + resolution: {integrity: sha512-FCqGtGOrMgzUiIrMNMA2YnsOxCNwo31dzqXvclXUC6xeT35NJLKXQJsvbeCTjvoFAwZgEAPg8U6+KAPDGXn8Mg==} + radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} @@ -12470,6 +12882,10 @@ packages: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -12920,6 +13336,9 @@ packages: standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + standardwebhooks@1.1.1: + resolution: {integrity: sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==} + statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} @@ -13367,6 +13786,9 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -13416,6 +13838,12 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} + typebox@1.3.27: + resolution: {integrity: sha512-zu+jc1pcy4UiNThxikUr36f0Rybk9PEeCg/NE6adeWr/SKsdNO4EzZHYRDlv2YCVAfj3Odq3dESSo/jNyoBXzA==} + + typebox@1.3.7: + resolution: {integrity: sha512-meKuifc33Pccx0O6PdIzYMq3Og8zvP4TIi/a+Bw3AEMZMxOD0+RHGQvpglEe6Zdy3wZ8nqn/j95h8LUZLk/6Hg==} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -13537,6 +13965,10 @@ packages: resolution: {integrity: sha512-YQ3WlbqjYMmNpdvDH64jAgLjxuAR9+649calDWhbshYaeQGO2bR4nI94ORJmwI3J9YhoKQnpyGOK+0zlWS5N5Q==} engines: {node: '>=22.19.0'} + undici@8.10.2: + resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} + engines: {node: '>=22.19.0'} + unenv@2.0.0-rc.24: resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} @@ -14739,6 +15171,13 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 + '@anthropic-ai/sdk@0.124.0(zod@4.5.4)': + dependencies: + json-schema-to-ts: 3.1.1 + standardwebhooks: 1.1.1 + optionalDependencies: + zod: 4.5.4 + '@asamuzakjp/css-color@6.0.7': dependencies: '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) @@ -14754,7 +15193,189 @@ snapshots: is-potential-custom-element-name: 1.0.1 lru-cache: 11.5.2 - '@babel/code-frame@7.29.0': + '@aws-sdk/client-bedrock-runtime@3.1127.0': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/credential-provider-node': 3.972.83 + '@aws-sdk/eventstream-handler-node': 3.972.34 + '@aws-sdk/middleware-eventstream': 3.972.29 + '@aws-sdk/middleware-websocket': 3.972.53 + '@aws-sdk/token-providers': 3.1127.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.978.0': + dependencies: + '@aws-sdk/types': 3.974.5 + '@aws-sdk/xml-builder': 3.972.40 + '@aws/lambda-invoke-store': 0.3.0 + '@smithy/core': 3.34.1 + '@smithy/signature-v4': 5.7.3 + '@smithy/types': 4.18.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.71': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.73': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.973.16': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/credential-provider-env': 3.972.71 + '@aws-sdk/credential-provider-http': 3.972.73 + '@aws-sdk/credential-provider-login': 3.972.78 + '@aws-sdk/credential-provider-process': 3.972.71 + '@aws-sdk/credential-provider-sso': 3.973.15 + '@aws-sdk/credential-provider-web-identity': 3.972.77 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.78': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.83': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.71 + '@aws-sdk/credential-provider-http': 3.972.73 + '@aws-sdk/credential-provider-ini': 3.973.16 + '@aws-sdk/credential-provider-process': 3.972.71 + '@aws-sdk/credential-provider-sso': 3.973.15 + '@aws-sdk/credential-provider-web-identity': 3.972.77 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/credential-provider-imds': 4.5.2 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.71': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.973.15': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/token-providers': 3.1129.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.77': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.34': + dependencies: + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.29': + dependencies: + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.53': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/signature-v4': 5.7.3 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.45': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/signature-v4-multi-region': 3.996.46 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/fetch-http-handler': 5.8.0 + '@smithy/node-http-handler': 4.12.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.46': + dependencies: + '@aws-sdk/types': 3.974.5 + '@smithy/signature-v4': 5.7.3 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1127.0': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1129.0': + dependencies: + '@aws-sdk/core': 3.978.0 + '@aws-sdk/nested-clients': 3.997.45 + '@aws-sdk/types': 3.974.5 + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.974.5': + dependencies: + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.40': + dependencies: + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.3.0': {} + + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 @@ -15304,11 +15925,11 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' - '@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3))': + '@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3))': dependencies: birpc: 4.0.0 destr: 2.0.5 - devframe: 0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3) + devframe: 0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3) nostics: 1.2.0 pathe: 2.0.3 perfect-debounce: 2.1.0 @@ -15316,14 +15937,14 @@ snapshots: zigpty: 0.2.1 optional: true - '@devframes/json-render@0.7.14(@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)))(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3))': + '@devframes/json-render@0.7.14(@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)))(devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3))': dependencies: '@json-render/core': 0.19.0(zod@4.5.4) - devframe: 0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3) + devframe: 0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3) nostics: 1.2.0 zod: 4.5.4 optionalDependencies: - '@devframes/hub': 0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)) + '@devframes/hub': 0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)) optional: true '@dxup/nuxt@0.5.10(esbuild@0.28.2)(magicast@0.5.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': @@ -15352,6 +15973,108 @@ snapshots: '@dxup/unimport@0.1.2': {} + '@earendil-works/chord@0.99.1': + dependencies: + esbuild: 0.28.2 + + '@earendil-works/pi-agent-core@0.99.1(@aws-sdk/credential-provider-node@3.972.83)(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(@smithy/signature-v4@5.7.3)(supports-color@10.2.2)(undici@8.10.2)(ws@8.21.3)(zod@4.5.4)': + dependencies: + '@earendil-works/chord': 0.99.1 + '@earendil-works/pi-ai': 0.99.1(@aws-sdk/credential-provider-node@3.972.83)(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(@smithy/signature-v4@5.7.3)(supports-color@10.2.2)(undici@8.10.2)(ws@8.21.3)(zod@4.5.4) + '@earendil-works/pi-telemetry': 0.99.1 + diff: 8.0.4 + ignore: 7.0.8 + typebox: 1.3.27 + yaml: 2.9.0 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - '@modelcontextprotocol/sdk' + - '@smithy/hash-node' + - '@smithy/signature-v4' + - bufferutil + - kerberos + - supports-color + - undici + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-ai@0.99.1(@aws-sdk/credential-provider-node@3.972.83)(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(@smithy/signature-v4@5.7.3)(supports-color@10.2.2)(undici@8.10.2)(ws@8.21.3)(zod@4.5.4)': + dependencies: + '@anthropic-ai/sdk': 0.124.0(zod@4.5.4) + '@aws-sdk/client-bedrock-runtime': 3.1127.0 + '@earendil-works/pi-telemetry': 0.99.1 + '@google/genai': 2.21.0(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(supports-color@10.2.2) + '@smithy/node-http-handler': 4.12.1 + http-proxy-agent: 9.1.0(supports-color@10.2.2) + https-proxy-agent: 9.1.0(supports-color@10.2.2) + openai: 7.19.0(@aws-sdk/credential-provider-node@3.972.83)(@smithy/signature-v4@5.7.3)(undici@8.10.2)(ws@8.21.3)(zod@4.5.4) + partial-json: 0.1.7 + typebox: 1.3.27 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - '@modelcontextprotocol/sdk' + - '@smithy/hash-node' + - '@smithy/signature-v4' + - bufferutil + - kerberos + - supports-color + - undici + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-codemode@0.99.1': + dependencies: + quickjs-wasi: 3.6.2 + + '@earendil-works/pi-coding-agent@0.99.1(@aws-sdk/credential-provider-node@3.972.83)(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(@smithy/signature-v4@5.7.3)(supports-color@10.2.2)(ws@8.21.3)(zod@4.5.4)': + dependencies: + '@earendil-works/chord': 0.99.1 + '@earendil-works/pi-agent-core': 0.99.1(@aws-sdk/credential-provider-node@3.972.83)(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(@smithy/signature-v4@5.7.3)(supports-color@10.2.2)(undici@8.10.2)(ws@8.21.3)(zod@4.5.4) + '@earendil-works/pi-ai': 0.99.1(@aws-sdk/credential-provider-node@3.972.83)(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(@smithy/signature-v4@5.7.3)(supports-color@10.2.2)(undici@8.10.2)(ws@8.21.3)(zod@4.5.4) + '@earendil-works/pi-codemode': 0.99.1 + '@earendil-works/pi-mcp': 0.99.1 + '@earendil-works/pi-tui': 0.99.1 + '@silvia-odwyer/photon-node': 0.3.4 + chalk: 6.0.0 + cross-spawn: 7.0.6 + diff: 8.0.4 + grok-mermaid: 0.2.3 + highlight.js: 10.7.3 + hosted-git-info: 9.0.3 + ignore: 7.0.8 + jiti: 2.7.0 + minimatch: 10.2.6 + proper-lockfile: 4.1.2 + quickjs-wasi: 3.6.2 + semver: 7.8.5 + typebox: 1.3.27 + undici: 8.10.2 + yaml: 2.9.0 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-node' + - '@modelcontextprotocol/sdk' + - '@smithy/hash-node' + - '@smithy/signature-v4' + - bufferutil + - kerberos + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-mcp@0.99.1': + dependencies: + cross-spawn: 7.0.6 + + '@earendil-works/pi-telemetry@0.99.1': {} + + '@earendil-works/pi-tui@0.99.1': + dependencies: + get-east-asian-width: 1.6.0 + marked: 18.0.11 + '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 @@ -15598,6 +16321,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@google/genai@2.21.0(@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4))(supports-color@10.2.2)': + dependencies: + google-auth-library: 10.9.1(supports-color@10.2.2) + p-retry: 4.6.2 + protobufjs: 7.6.6 + ws: 8.21.3 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.30.0(supports-color@10.2.2)(zod@4.5.4) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@gwhitney/detect-indent@7.0.1': {} '@harperfast/extended-iterable@1.0.3': @@ -16253,7 +16989,7 @@ snapshots: '@lit-labs/scoped-registry-mixin@1.0.4': dependencies: '@lit/reactive-element': 2.1.2 - lit: 3.3.2 + lit: 3.3.3 optional: true '@lit-labs/ssr-client@1.1.8': @@ -16295,7 +17031,7 @@ snapshots: '@lit/reactive-element': 2.1.2 '@parse5/tools': 0.3.0 enhanced-resolve: 5.21.3 - lit: 3.3.2 + lit: 3.3.3 lit-element: 4.2.2 lit-html: 3.3.2 node-fetch: 3.3.2 @@ -16305,7 +17041,7 @@ snapshots: '@lit-labs/virtualizer@2.1.1': dependencies: - lit: 3.3.2 + lit: 3.3.3 tslib: 2.8.1 '@lit/reactive-element@2.1.2': @@ -16359,6 +17095,15 @@ snapshots: react: 19.2.8 react-dom: 19.2.8(react@19.2.8) + '@modelcontextprotocol/ext-apps@1.7.5(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(zod@4.5.4)': + dependencies: + '@modelcontextprotocol/sdk': 1.31.0(supports-color@10.2.2)(zod@4.5.4) + '@standard-schema/spec': 1.1.0 + zod: 4.5.4 + optionalDependencies: + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + '@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.14) @@ -16381,6 +17126,29 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.5.4)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.14) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.8 + express: 5.2.1(supports-color@10.2.2) + express-rate-limit: 8.3.2(express@5.2.1(supports-color@10.2.2)) + hono: 4.12.14 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.5.4 + zod-to-json-schema: 3.25.2(zod@4.5.4) + transitivePeerDependencies: + - supports-color + optional: true + '@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.14) @@ -16403,6 +17171,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.14) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.8 + express: 5.2.1(supports-color@10.2.2) + express-rate-limit: 8.3.2(express@5.2.1(supports-color@10.2.2)) + hono: 4.12.14 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.5.4 + zod-to-json-schema: 3.25.2(zod@4.5.4) + transitivePeerDependencies: + - supports-color + '@modelcontextprotocol/server@2.0.0': dependencies: '@modelcontextprotocol/core': 2.0.0 @@ -16784,11 +17574,11 @@ snapshots: - rolldown - unplugin - '@nuxt/nitro-server@4.5.2(1bca1e92e44267d58f2891ed00760292)': + '@nuxt/nitro-server@4.5.2(79520c11e62053107a7c042625f39eeb)': dependencies: '@nuxt/devalue': 2.0.2 '@nuxt/kit': 4.5.2(magic-string@1.1.0)(magicast@0.5.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))) - '@unhead/vue': 3.4.0(@oxc-project/types@0.147.0)(@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)))(esbuild@0.28.2)(lightningcss@1.33.0)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@unhead/vue': 3.4.0(@oxc-project/types@0.147.0)(@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)))(esbuild@0.28.2)(lightningcss@1.33.0)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) '@vue/shared': 3.5.42 consola: 3.4.2 defu: 6.1.7 @@ -16803,7 +17593,7 @@ snapshots: mocked-exports: 0.1.1 nitropack: 2.13.4(oxc-parser@0.147.0)(rolldown@1.2.6)(srvx@0.11.22)(supports-color@10.2.2)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) nostics: 1.2.0 - nuxt: 4.5.2(b859f4e8cb62fae0e3decfe5293f8478) + nuxt: 4.5.2(b7188d0d9ad0b8052c818020062c5583) nypm: 0.6.9 ohash: 2.0.11 pathe: 2.0.3 @@ -16887,7 +17677,7 @@ snapshots: rc9: 3.0.1 std-env: 4.2.0 - '@nuxt/vite-builder@4.5.2(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@26.5.0)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0)(supports-color@10.2.2))(magic-string@1.1.0)(magicast@0.5.4)(meow@14.1.0)(nuxt@4.5.2(b859f4e8cb62fae0e3decfe5293f8478))(optionator@0.9.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.6)(rollup@4.60.4))(rollup@4.60.4)(sass@1.101.0)(stylelint@17.14.1(supports-color@10.2.2)(typescript@6.0.3))(sugarss@5.0.1(postcss@8.5.26))(supports-color@10.2.2)(terser@5.48.0)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))(yaml@2.9.0)': + '@nuxt/vite-builder@4.5.2(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@26.5.0)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0)(supports-color@10.2.2))(magic-string@1.1.0)(magicast@0.5.4)(meow@14.1.0)(nuxt@4.5.2(b7188d0d9ad0b8052c818020062c5583))(optionator@0.9.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.6)(rollup@4.60.4))(rollup@4.60.4)(sass@1.101.0)(stylelint@17.14.1(supports-color@10.2.2)(typescript@6.0.3))(sugarss@5.0.1(postcss@8.5.26))(supports-color@10.2.2)(terser@5.48.0)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))(yaml@2.9.0)': dependencies: '@nuxt/kit': 4.5.2(magic-string@1.1.0)(magicast@0.5.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))) '@vitejs/plugin-vue': 6.0.8(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) @@ -16905,7 +17695,7 @@ snapshots: knitwork: 1.3.0 mlly: 1.8.2 mocked-exports: 0.1.1 - nuxt: 4.5.2(b859f4e8cb62fae0e3decfe5293f8478) + nuxt: 4.5.2(b7188d0d9ad0b8052c818020062c5583) nypm: 0.6.9 pathe: 2.0.3 pkg-types: 2.3.1 @@ -17818,6 +18608,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + '@publint/pack@0.1.7': dependencies: tinyexec: 1.3.0 @@ -18354,6 +19164,8 @@ snapshots: '@opentelemetry/semantic-conventions': 1.40.0 '@sentry/core': 9.47.1 + '@silvia-odwyer/photon-node@0.3.4': {} + '@simple-git/args-pathspec@1.0.3': {} '@simple-git/argv-parser@1.1.1': @@ -18387,6 +19199,39 @@ snapshots: dependencies: escape-string-regexp: 5.0.0 + '@smithy/core@3.34.1': + dependencies: + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.5.2': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.8.0': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.12.1': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.7.3': + dependencies: + '@smithy/core': 3.34.1 + '@smithy/types': 4.18.0 + tslib: 2.8.1 + + '@smithy/types@4.18.0': + dependencies: + tslib: 2.8.1 + '@solid-devtools/debugger@0.28.1(solid-js@1.9.15)': dependencies: '@nothing-but/utils': 0.17.0 @@ -18480,6 +19325,8 @@ snapshots: '@speed-highlight/core@1.2.15': {} + '@stablelib/base64@1.0.1': {} + '@standard-schema/spec@1.1.0': {} '@sveltejs/acorn-typescript@1.0.13(acorn@8.18.0)': @@ -18638,6 +19485,8 @@ snapshots: '@types/resolve@1.20.2': {} + '@types/retry@0.12.0': {} + '@types/shimmer@1.2.0': {} '@types/tedious@4.0.14': @@ -18874,14 +19723,14 @@ snapshots: '@typescript/typescript-win32-x64@7.0.2': optional: true - '@unhead/bundler@3.4.0(647b4a5ee774dd2b39edc23fdccae441)': + '@unhead/bundler@3.4.0(1c099aeb0aebef5466a8f4a374c966b3)': dependencies: magic-string: 1.2.3 oxc-walker: 1.1.1(@oxc-project/types@0.147.0)(oxc-parser@0.147.0)(rolldown@1.2.6) unhead: 3.4.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) optionalDependencies: - '@vitejs/devtools-kit': 0.4.9(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)) + '@vitejs/devtools-kit': 0.4.9(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)) esbuild: 0.28.2 lightningcss: 1.33.0 oxc-parser: 0.147.0 @@ -18896,9 +19745,9 @@ snapshots: - rollup - unloader - '@unhead/vue@3.4.0(@oxc-project/types@0.147.0)(@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)))(esbuild@0.28.2)(lightningcss@1.33.0)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': + '@unhead/vue@3.4.0(@oxc-project/types@0.147.0)(@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)))(esbuild@0.28.2)(lightningcss@1.33.0)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))': dependencies: - '@unhead/bundler': 3.4.0(647b4a5ee774dd2b39edc23fdccae441) + '@unhead/bundler': 3.4.0(1c099aeb0aebef5466a8f4a374c966b3) hookable: 6.1.1 unhead: 3.4.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) unplugin: 3.3.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) @@ -18944,11 +19793,11 @@ snapshots: - rollup - supports-color - '@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))': + '@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))': dependencies: - '@devframes/hub': 0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)) - '@devframes/json-render': 0.7.14(@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)))(devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)) - devframe: 0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3) + '@devframes/hub': 0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)) + '@devframes/json-render': 0.7.14(@devframes/hub@0.7.14(devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)))(devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)) + devframe: 0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3) local-pkg: 1.2.1 mlly: 1.8.2 nostics: 1.2.0 @@ -19893,6 +20742,8 @@ snapshots: dependencies: require-from-string: 2.0.2 + bignumber.js@9.3.1: {} + binary-extensions@2.3.0: {} bindings@1.5.0: @@ -19921,6 +20772,8 @@ snapshots: bottleneck@2.19.5: {} + bowser@2.14.1: {} + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 @@ -19950,6 +20803,8 @@ snapshots: buffer-crc32@1.0.0: {} + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} buffer@6.0.3: @@ -20062,6 +20917,8 @@ snapshots: chalk@5.6.2: {} + chalk@6.0.0: {} + change-case@5.4.4: {} char-regex@1.0.2: {} @@ -20784,7 +21641,7 @@ snapshots: devalue@5.8.1: {} - devframe@0.7.14(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3): + devframe@0.7.14(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3): dependencies: '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(typescript@6.0.3)) birpc: 4.0.0 @@ -20797,7 +21654,7 @@ snapshots: ufo: 1.6.4 valibot: 1.4.2(typescript@6.0.3) optionalDependencies: - '@modelcontextprotocol/sdk': 1.30.1(supports-color@10.2.2)(zod@4.5.4) + '@modelcontextprotocol/sdk': 1.31.0(supports-color@10.2.2)(zod@4.5.4) transitivePeerDependencies: - srvx - typescript @@ -20929,6 +21786,10 @@ snapshots: eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + ee-first@1.1.1: {} ejs@3.1.10: @@ -21482,6 +22343,8 @@ snapshots: dependencies: cac: 7.0.0 + fast-sha256@1.3.0: {} + fast-string-truncated-width@3.0.3: {} fast-string-width@3.0.2: @@ -21670,6 +22533,22 @@ snapshots: fzf@0.5.2: {} + gaxios@7.3.1(supports-color@10.2.2): + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2(supports-color@10.2.2): + dependencies: + gaxios: 7.3.1(supports-color@10.2.2) + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + generator-function@2.0.1: {} generic-names@4.0.0: @@ -21682,6 +22561,8 @@ snapshots: get-east-asian-width@1.5.0: {} + get-east-asian-width@1.6.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -21827,6 +22708,19 @@ snapshots: globjoin@0.1.4: {} + google-auth-library@10.9.1(supports-color@10.2.2): + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.3.1(supports-color@10.2.2) + gcp-metadata: 8.1.2(supports-color@10.2.2) + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + gopd@1.2.0: {} graceful-fs@4.2.10: {} @@ -21840,6 +22734,8 @@ snapshots: section-matter: 1.0.0 strip-bom-string: 1.0.0 + grok-mermaid@0.2.3: {} + gzip-size@7.0.0: dependencies: duplexer: 0.1.2 @@ -21933,6 +22829,10 @@ snapshots: dependencies: lru-cache: 11.3.5 + hosted-git-info@9.0.3: + dependencies: + lru-cache: 11.5.2 + html-encoding-sniffer@3.0.0: dependencies: whatwg-encoding: 2.0.0 @@ -22519,10 +23419,19 @@ snapshots: jsesc@3.1.0: {} + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + json-parse-better-errors@1.0.2: {} json-parse-even-better-errors@2.3.1: {} + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.2 + ts-algebra: 2.0.0 + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -22549,6 +23458,17 @@ snapshots: junk@3.1.0: {} + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + kapsule@1.16.3: dependencies: lodash-es: 4.18.1 @@ -22825,7 +23745,7 @@ snapshots: dependencies: '@lit-labs/ssr-dom-shim': 1.6.0 '@lit/reactive-element': 2.1.2 - lit-html: 3.3.2 + lit-html: 3.3.3 lit-html@3.3.2: dependencies: @@ -22835,17 +23755,11 @@ snapshots: dependencies: '@types/trusted-types': 2.0.7 - lit@3.3.2: - dependencies: - '@lit/reactive-element': 2.1.2 - lit-element: 4.2.2 - lit-html: 3.3.2 - lit@3.3.3: dependencies: '@lit/reactive-element': 2.1.2 lit-element: 4.2.2 - lit-html: 3.3.2 + lit-html: 3.3.3 lmdb@3.5.6: dependencies: @@ -22937,6 +23851,8 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 10.0.0 + long@5.3.2: {} + longest-streak@3.1.0: {} lookup-closest-locale@6.2.0: {} @@ -23039,6 +23955,8 @@ snapshots: marked@15.0.12: {} + marked@18.0.11: {} + marked@18.0.14: {} marky@1.3.0: {} @@ -23433,6 +24351,10 @@ snapshots: dependencies: brace-expansion: 5.0.9 + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.9 + minimatch@3.1.5: dependencies: brace-expansion: 1.1.14 @@ -23789,17 +24711,17 @@ snapshots: optionalDependencies: chokidar: 3.6.0 - nuxt@4.5.2(b859f4e8cb62fae0e3decfe5293f8478): + nuxt@4.5.2(b7188d0d9ad0b8052c818020062c5583): dependencies: '@dxup/nuxt': 0.5.10(esbuild@0.28.2)(magicast@0.5.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) '@nuxt/cli': 3.37.0(@nuxt/schema@4.5.2)(commander@14.0.3)(magicast@0.5.4)(supports-color@10.2.2) '@nuxt/devtools': 3.4.2(db0@0.3.4)(ioredis@5.10.1(supports-color@10.2.2))(magic-string@1.1.0)(oxc-parser@0.147.0)(rolldown@1.2.6)(supports-color@10.2.2)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)))(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) '@nuxt/kit': 4.5.2(magic-string@1.1.0)(magicast@0.5.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))) - '@nuxt/nitro-server': 4.5.2(1bca1e92e44267d58f2891ed00760292) + '@nuxt/nitro-server': 4.5.2(79520c11e62053107a7c042625f39eeb) '@nuxt/schema': 4.5.2 '@nuxt/telemetry': 2.8.0(@nuxt/kit@4.5.2(magic-string@1.1.0)(magicast@0.5.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(unplugin@3.3.0(esbuild@0.28.2)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)))) - '@nuxt/vite-builder': 4.5.2(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@26.5.0)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0)(supports-color@10.2.2))(magic-string@1.1.0)(magicast@0.5.4)(meow@14.1.0)(nuxt@4.5.2(b859f4e8cb62fae0e3decfe5293f8478))(optionator@0.9.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.6)(rollup@4.60.4))(rollup@4.60.4)(sass@1.101.0)(stylelint@17.14.1(supports-color@10.2.2)(typescript@6.0.3))(sugarss@5.0.1(postcss@8.5.26))(supports-color@10.2.2)(terser@5.48.0)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))(yaml@2.9.0) - '@unhead/vue': 3.4.0(@oxc-project/types@0.147.0)(@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.30.1(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)))(esbuild@0.28.2)(lightningcss@1.33.0)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) + '@nuxt/vite-builder': 4.5.2(@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0(supports-color@10.2.2)))(@types/node@26.5.0)(esbuild@0.28.2)(eslint@10.10.0(jiti@2.7.0)(supports-color@10.2.2))(magic-string@1.1.0)(magicast@0.5.4)(meow@14.1.0)(nuxt@4.5.2(b7188d0d9ad0b8052c818020062c5583))(optionator@0.9.4)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup-plugin-visualizer@7.0.1(rolldown@1.2.6)(rollup@4.60.4))(rollup@4.60.4)(sass@1.101.0)(stylelint@17.14.1(supports-color@10.2.2)(typescript@6.0.3))(sugarss@5.0.1(postcss@8.5.26))(supports-color@10.2.2)(terser@5.48.0)(typescript@6.0.3)(vue-tsc@3.3.11(typescript@6.0.3))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3))(yaml@2.9.0) + '@unhead/vue': 3.4.0(@oxc-project/types@0.147.0)(@vitejs/devtools-kit@0.4.9(@modelcontextprotocol/sdk@1.31.0(supports-color@10.2.2)(zod@4.5.4))(srvx@0.11.22)(typescript@6.0.3)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0)))(esbuild@0.28.2)(lightningcss@1.33.0)(oxc-parser@0.147.0)(rolldown@1.2.6)(rollup@4.60.4)(vite@8.2.2(@types/node@26.5.0)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.26))(terser@5.48.0)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.106.2(clean-css@5.3.3)(cssnano@8.0.2(postcss@8.5.26))(csso@5.0.5)(esbuild@0.28.2)(html-minifier-terser@7.2.0)(lightningcss@1.33.0)(postcss@8.5.26)(uglify-js@3.19.3)) '@vue/shared': 3.5.40 chokidar: 5.0.0 compatx: 0.2.0 @@ -24042,6 +24964,14 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openai@7.19.0(@aws-sdk/credential-provider-node@3.972.83)(@smithy/signature-v4@5.7.3)(undici@8.10.2)(ws@8.21.3)(zod@4.5.4): + optionalDependencies: + '@aws-sdk/credential-provider-node': 3.972.83 + '@smithy/signature-v4': 5.7.3 + undici: 8.10.2 + ws: 8.21.3 + zod: 4.5.4 + opener@1.5.2: {} optionator@0.9.4: @@ -24234,6 +25164,11 @@ snapshots: p-reduce@3.0.0: {} + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + p-timeout@6.1.4: {} p-try@1.0.0: {} @@ -24351,6 +25286,8 @@ snapshots: parseurl@1.3.3: {} + partial-json@0.1.7: {} + pascal-case@3.1.2: dependencies: no-case: 3.0.4 @@ -25054,6 +25991,20 @@ snapshots: proto-list@1.2.4: {} + protobufjs@7.6.6: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 26.5.0 + long: 5.3.2 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -25125,6 +26076,8 @@ snapshots: queue-microtask@1.2.3: {} + quickjs-wasi@3.6.2: {} + radix3@1.1.2: {} range-parser@1.2.1: {} @@ -25340,6 +26293,8 @@ snapshots: retry@0.12.0: {} + retry@0.13.1: {} + reusify@1.1.0: {} robots-parser@3.0.1: {} @@ -25956,6 +26911,11 @@ snapshots: standard-as-callback@2.1.0: {} + standardwebhooks@1.1.1: + dependencies: + '@stablelib/base64': 1.0.1 + fast-sha256: 1.3.0 + statuses@2.0.2: {} std-env@4.2.0: {} @@ -26478,6 +27438,8 @@ snapshots: trough@2.2.0: {} + ts-algebra@2.0.0: {} + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: typescript: 6.0.3 @@ -26525,6 +27487,10 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.2 + typebox@1.3.27: {} + + typebox@1.3.7: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -26657,6 +27623,8 @@ snapshots: undici@8.10.1: {} + undici@8.10.2: {} + unenv@2.0.0-rc.24: dependencies: pathe: 2.0.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0ebfa8011c..6bcfe9d995 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -30,6 +30,7 @@ packages: - projects/monaco - projects/pages - projects/create + - projects/pi - projects/core - projects/forms - projects/plot @@ -81,6 +82,8 @@ catalog: '@11ty/eleventy-plugin-syntaxhighlight': 5.0.2 '@11ty/eleventy-plugin-vite': 8.0.0 '@custom-elements-manifest/analyzer': 0.11.0 + '@earendil-works/pi-coding-agent': 0.99.1 + '@earendil-works/pi-tui': 0.99.1 '@eslint/css': 2.0.0 '@eslint/js': 10.0.1 '@eslint/json': 2.1.0 @@ -125,6 +128,7 @@ catalog: stylelint: 17.14.1 stylelint-config-standard: 40.0.0 ts-morph: 28.0.0 + typebox: 1.3.7 typescript: 6.0.3 typescript-7: npm:typescript@7.0.2 typescript-eslint: 8.60.0 @@ -143,9 +147,19 @@ minimumReleaseAgeExclude: - vite - vitest - '@google/design.md@0.4.0' + - '@earendil-works/chord@0.99.1' + - '@earendil-works/pi-agent-core@0.99.1' + - '@earendil-works/pi-ai@0.99.1' + - '@earendil-works/pi-codemode@0.99.1' + - '@earendil-works/pi-coding-agent@0.99.1' + - '@earendil-works/pi-mcp@0.99.1' + - '@earendil-works/pi-telemetry@0.99.1' + - '@earendil-works/pi-tui@0.99.1' allowBuilds: + '@google/genai': false '@modelcontextprotocol/ext-apps': true + protobufjs: false '@bundled-es-modules/glob': true '@parcel/watcher': true bun: true diff --git a/projects/internals/ci/coverage-projects.js b/projects/internals/ci/coverage-projects.js index 5a8f4cfdc8..b73bd65cbf 100644 --- a/projects/internals/ci/coverage-projects.js +++ b/projects/internals/ci/coverage-projects.js @@ -7,6 +7,7 @@ export const COVERAGE_PROJECTS = [ { name: '@nvidia-elements/markdown', dir: 'markdown' }, { name: '@nvidia-elements/media', dir: 'media' }, { name: '@nvidia-elements/monaco', dir: 'monaco' }, + { name: '@nvidia-elements/pi', dir: 'pi' }, { name: '@nvidia-elements/plot', dir: 'plot' }, { name: '@nvidia-elements/scene', dir: 'scene' }, { name: '@internals/metadata', dir: 'internals/metadata' }, diff --git a/projects/internals/metadata/package.json b/projects/internals/metadata/package.json index 047b6502ef..99980efbe7 100644 --- a/projects/internals/metadata/package.json +++ b/projects/internals/metadata/package.json @@ -200,6 +200,9 @@ "../../monaco/package.json", "../../monaco/README.md", "../../monaco/CHANGELOG.md", + "../../pi/package.json", + "../../pi/README.md", + "../../pi/CHANGELOG.md", "../../patterns/package.json", "../../patterns/README.md", "../../patterns/CHANGELOG.md" diff --git a/projects/internals/metadata/src/tasks/projects.utils.ts b/projects/internals/metadata/src/tasks/projects.utils.ts index cbdf3ac8c5..f9cbfb5591 100644 --- a/projects/internals/metadata/src/tasks/projects.utils.ts +++ b/projects/internals/metadata/src/tasks/projects.utils.ts @@ -47,6 +47,7 @@ export function getProjects(): { created: string; data: Project[] } { '../../../../markdown', '../../../../media', '../../../../monaco', + '../../../../pi', '../../../../internals/metadata', '../../../../internals/patterns' ]; diff --git a/projects/internals/metadata/src/tasks/tests.utils.test.ts b/projects/internals/metadata/src/tasks/tests.utils.test.ts index 03c16707c4..da960e4680 100644 --- a/projects/internals/metadata/src/tasks/tests.utils.test.ts +++ b/projects/internals/metadata/src/tasks/tests.utils.test.ts @@ -325,6 +325,7 @@ describe('generateTestSummary', () => { '@nvidia-elements/markdown', '@nvidia-elements/media', '@nvidia-elements/monaco', + '@nvidia-elements/pi', '@internals/metadata', '@internals/patterns', '@internals/tools' diff --git a/projects/internals/metadata/src/tasks/tests.utils.ts b/projects/internals/metadata/src/tasks/tests.utils.ts index 5cbb4051e7..1cb4ac6ce8 100644 --- a/projects/internals/metadata/src/tasks/tests.utils.ts +++ b/projects/internals/metadata/src/tasks/tests.utils.ts @@ -103,6 +103,7 @@ export async function generateTestSummary(): Promise { '@nvidia-elements/markdown': await getTestReport('@nvidia-elements/markdown', '../../../../markdown'), '@nvidia-elements/media': await getTestReport('@nvidia-elements/media', '../../../../media'), '@nvidia-elements/monaco': await getTestReport('@nvidia-elements/monaco', '../../../../monaco'), + '@nvidia-elements/pi': await getTestReport('@nvidia-elements/pi', '../../../../pi'), '@internals/metadata': await getTestReport('@internals/metadata', '../../../../internals/metadata'), '@internals/patterns': await getTestReport('@internals/patterns', '../../../../internals/patterns'), '@internals/tools': await getTestReport('@internals/tools', '../../../../internals/tools') diff --git a/projects/internals/tools/src/api/service.test.ts b/projects/internals/tools/src/api/service.test.ts index 39c899fdf1..3f3a6f833c 100644 --- a/projects/internals/tools/src/api/service.test.ts +++ b/projects/internals/tools/src/api/service.test.ts @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +import { mkdtemp, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; import { describe, expect, it } from 'vitest'; import type { Attribute, Element } from '@internals/metadata'; import type { ToolMethod } from '../internal/tools.js'; @@ -172,12 +175,16 @@ describe('ApiService', () => { describe('validate', () => { it('should have correct metadata', () => { - expect((ApiService.validate as ToolMethod).metadata.command).toBe('validate'); - expect((ApiService.validate as ToolMethod).metadata.inputSchema?.properties?.paths).toBeDefined(); - expect((ApiService.validate as ToolMethod).metadata.inputSchema?.properties?.template).toBeDefined(); - expect((ApiService.validate as ToolMethod).metadata.inputSchema?.properties?.stdin).toBeUndefined(); - expect((ApiService.validate as ToolMethod).metadata.inputSchema?.properties?.fix).toBeUndefined(); - expect((ApiService.validate as ToolMethod).metadata.cli).toMatchObject({ + const metadata = (ApiService.validate as ToolMethod).metadata; + expect(metadata.command).toBe('validate'); + expect(metadata.inputSchema?.properties).toMatchObject({ + paths: expect.any(Object), + template: expect.any(Object), + cwd: expect.any(Object) + }); + expect(metadata.inputSchema?.properties).not.toHaveProperty('stdin'); + expect(metadata.inputSchema?.properties).not.toHaveProperty('fix'); + expect(metadata.cli).toMatchObject({ exclude: ['template'], properties: { stdin: { type: 'boolean' }, fix: { type: 'boolean' } }, positionals: { paths: { optional: true, variadic: true } } @@ -203,6 +210,17 @@ describe('ApiService', () => { expect((result as { diagnostics: unknown[] }).diagnostics).toHaveLength(1); }); + it('should resolve path inputs from the provided working directory', async () => { + const directory = await mkdtemp(join(tmpdir(), 'elements-api-service-')); + try { + await writeFile(join(directory, 'page.html'), 'Save'); + const result = await ApiService.validate({ paths: ['page.html'], cwd: directory, format: 'json' }); + expect(result).toMatchObject({ summary: { files: 1 } }); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); + it('should default supplied content to HTML', async () => { const result = await ApiService.validate({ template: '', format: 'json' }); expect(result).toMatchObject({ ok: false, summary: { files: 1 } }); diff --git a/projects/internals/tools/src/api/service.ts b/projects/internals/tools/src/api/service.ts index ec1282daf6..cafe46aa03 100644 --- a/projects/internals/tools/src/api/service.ts +++ b/projects/internals/tools/src/api/service.ts @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +import { cwd as getCwd } from 'node:process'; import { ApiService as MetadataApiService, type Attribute, type Element } from '@internals/metadata'; import { getContextAPIs, getContextTokens, searchContextAPIs, type PartialAPIResult } from './utils.js'; import { @@ -253,6 +254,11 @@ export class ApiService { type: 'number', description: 'Maximum number of diagnostics returned. Summary counts remain complete.', default: 100 + }, + cwd: { + type: 'string', + description: 'Provide the current working directory.', + default: getCwd() } }, additionalProperties: false @@ -274,7 +280,8 @@ export class ApiService { filename, format = 'markdown', maxDiagnostics, - fix = false + fix = false, + cwd = getCwd() }: { paths?: string[]; template?: string; @@ -283,8 +290,9 @@ export class ApiService { format?: 'markdown' | 'json'; maxDiagnostics?: number; fix?: boolean; + cwd?: string; }): Promise { - const result = await validateApiRequest({ paths, template, lang, filename, maxDiagnostics, fix }); + const result = await validateApiRequest({ paths, template, lang, filename, maxDiagnostics, fix, cwd }); return format === 'json' ? result : formatValidationResult(result); } @@ -415,7 +423,8 @@ async function validateApiRequest({ lang, filename, maxDiagnostics, - fix + fix, + cwd }: { paths?: string[]; template?: string; @@ -423,11 +432,12 @@ async function validateApiRequest({ filename?: string; maxDiagnostics?: number; fix: boolean; + cwd: string; }): Promise { - const request = { paths, template, lang, filename, fix }; + const request = { paths, template, lang, filename, fix, cwd }; assertValidationRequest(request); const inputs = await getValidationInputs(request); - return validate(inputs, { maxDiagnostics, fix }); + return validate(inputs, { cwd, maxDiagnostics, fix }); } type ValidationRequest = { @@ -436,6 +446,7 @@ type ValidationRequest = { lang?: ValidationLanguage; filename?: string; fix: boolean; + cwd: string; }; function assertValidationRequest(request: ValidationRequest): void { @@ -452,12 +463,12 @@ function assertTemplateLanguage({ template, lang, filename }: ValidationRequest) if (lang === 'json' && !filename) throw new Error('filename is required when checking JSON content.'); } -async function getValidationInputs({ paths, template, lang, filename }: ValidationRequest) { - if (paths?.length) return readValidationPaths(paths); +async function getValidationInputs({ paths, template, lang, filename, cwd }: ValidationRequest) { + if (paths?.length) return readValidationPaths(paths, cwd); const inputLanguage = lang ?? 'html'; return [ { - filename: validateVirtualFilename(filename ?? `stdin.${inputLanguage}`), + filename: validateVirtualFilename(filename ?? `stdin.${inputLanguage}`, cwd), source: template!, lang: inputLanguage } diff --git a/projects/internals/tools/src/playground/service.ts b/projects/internals/tools/src/playground/service.ts index 15ea61bab2..3f2c5e2c94 100644 --- a/projects/internals/tools/src/playground/service.ts +++ b/projects/internals/tools/src/playground/service.ts @@ -10,7 +10,7 @@ import { playgroundTypes, resolveTemplate } from './utils.js'; -import { service, tool, ToolError } from '../internal/tools.js'; +import { service, tool, ToolError, ToolSupport } from '../internal/tools.js'; import { ELEMENTS_ENV_ICON } from '../internal/utils.js'; import { eslintSchema } from '../internal/schema.js'; @@ -25,6 +25,7 @@ export interface PlaygroundOptions { @service() export class PlaygroundService { @tool({ + support: ToolSupport.MCP | ToolSupport.CLI, summary: 'Validates HTML templates specifically for playground examples.', description: 'Validates HTML templates specifically for playground examples. Includes Elements API checks with additional constraints to prevent common mistakes when generating standalone demos and playgrounds. Use this before calling playground_create.', @@ -67,6 +68,7 @@ export class PlaygroundService { } @tool({ + support: ToolSupport.MCP | ToolSupport.CLI, summary: 'Create a shareable playground URL from an HTML template.', description: 'Create a shareable playground URL from an HTML template. Returns URL if valid. Lint failures return a tool error. Tip: Use playground_validate first to check for issues.', diff --git a/projects/internals/tools/src/project/starters.ts b/projects/internals/tools/src/project/starters.ts index 0b0946f308..2c576feb87 100644 --- a/projects/internals/tools/src/project/starters.ts +++ b/projects/internals/tools/src/project/starters.ts @@ -12,7 +12,6 @@ import { readWorkspaceManifest } from '@pnpm/workspace.read-manifest'; import { getCatalogsFromWorkspaceManifest } from '@pnpm/catalogs.config'; import { createExportableManifest } from '@pnpm/exportable-manifest'; import { readProjectManifestOnly } from '@pnpm/read-project-manifest'; -import { ZipArchive } from 'archiver'; import AdmZip from 'adm-zip'; import { isCommandAvailable, getNPMClient } from '../internal/node.js'; import type { Report } from '../internal/types.js'; @@ -202,6 +201,7 @@ export async function archiveStarter(projectDir: string, outDir: string) { /* istanbul ignore next -- @preserve */ async function zipProject(outDir: string) { + const { ZipArchive } = await import('archiver'); const output = createWriteStream(`${outDir}.zip`); output.on('error', err => console.error('Error writing to zip file:', err)); diff --git a/projects/pi/CHANGELOG.md b/projects/pi/CHANGELOG.md new file mode 100644 index 0000000000..825c32f0d0 --- /dev/null +++ b/projects/pi/CHANGELOG.md @@ -0,0 +1 @@ +# Changelog diff --git a/projects/pi/DEVELOPMENT.md b/projects/pi/DEVELOPMENT.md new file mode 100644 index 0000000000..6abf8b6c33 --- /dev/null +++ b/projects/pi/DEVELOPMENT.md @@ -0,0 +1,19 @@ +# Development + +| Command | Description | +| ------------------------ | ------------------------------------------------ | +| `pnpm run build` | Build the extension, skill, and workflow prompts | +| `pnpm run lint` | Lint source and build scripts | +| `pnpm run test` | Run unit and package contract tests | +| `pnpm run test:coverage` | Run unit tests with coverage | +| `pnpm run ci` | Run the complete project CI pipeline | + +Test the built package in Pi: + +```shell +mise exec -- pi -e . + +mise exec -- pi -e . --tools nvidia_elements_api_list -p 'Call nvidia_elements_api_list and report the available component names.' + +mise exec -- pi -e . --no-elements-auto-validate +``` diff --git a/projects/pi/NOTICE.md b/projects/pi/NOTICE.md new file mode 100644 index 0000000000..af3b3ae42d --- /dev/null +++ b/projects/pi/NOTICE.md @@ -0,0 +1,101 @@ +NOTICE + +Elements - NVIDIA Elements Design System +Copyright 2024-2026 NVIDIA Corporation + +This project includes the following bundled third-party software: + +- @pnpm/catalogs.config v0.1.0 [MIT] + Copyright: Unknown + +- @pnpm/exportable-manifest v7.0.3 [MIT] + Copyright: Unknown + +- @pnpm/read-project-manifest v6.0.6 [MIT] + Copyright: Unknown + +- @pnpm/workspace.read-manifest v2.2.0 [MIT] + Copyright: Unknown + +- adm-zip v0.6.1 [MIT] + Copyright: Nasca Iacob (https://github.com/cthackers) + +- archiver v8.0.0 [MIT] + Copyright: Chris Talkington (http://christalkington.com/) + +- eslint v10.10.0 [MIT] + Copyright: Nicholas C. Zakas + +- fast-glob v3.3.3 [MIT] + Copyright: Denis Malinochkin (https://mrmlnc.com) + +- fflate v0.8.3 [MIT] + Copyright: Arjun Barrett + +- html-format v1.1.7 [MIT] + Copyright: Mohamed Akram + +- ignore v7.0.6 [MIT] + Copyright: kael + +- minisearch v7.2.0 [MIT] + Copyright: Luca Ongaro + +- open v11.0.0 [MIT] + Copyright: Sindre Sorhus (https://sindresorhus.com) + +- publint v0.3.24 [MIT] + Copyright: Bjorn Lu + +- sanitize-html v2.17.7 [MIT] + Copyright: Apostrophe Technologies, Inc. + +- ts-morph v28.0.0 [MIT] + Copyright: David Sherret + +- zod v4.5.4 [MIT] + Copyright: Colin McDonnell + +============================================================================== +MIT +============================================================================== + +The following bundled components are provided under the MIT license: + +@pnpm/catalogs.config v0.1.0 - Copyright Unknown +@pnpm/exportable-manifest v7.0.3 - Copyright Unknown +@pnpm/read-project-manifest v6.0.6 - Copyright Unknown +@pnpm/workspace.read-manifest v2.2.0 - Copyright Unknown +adm-zip v0.6.1 - Copyright Nasca Iacob (https://github.com/cthackers) +archiver v8.0.0 - Copyright Chris Talkington (http://christalkington.com/) +eslint v10.10.0 - Copyright Nicholas C. Zakas +fast-glob v3.3.3 - Copyright Denis Malinochkin (https://mrmlnc.com) +fflate v0.8.3 - Copyright Arjun Barrett +html-format v1.1.7 - Copyright Mohamed Akram +ignore v7.0.6 - Copyright kael +minisearch v7.2.0 - Copyright Luca Ongaro +open v11.0.0 - Copyright Sindre Sorhus (https://sindresorhus.com) +publint v0.3.24 - Copyright Bjorn Lu +sanitize-html v2.17.7 - Copyright Apostrophe Technologies, Inc. +ts-morph v28.0.0 - Copyright David Sherret +zod v4.5.4 - Copyright Colin McDonnell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +For license details, see: MIT: https://opensource.org/licenses/MIT diff --git a/projects/pi/README.md b/projects/pi/README.md new file mode 100644 index 0000000000..3a932cf792 --- /dev/null +++ b/projects/pi/README.md @@ -0,0 +1,89 @@ +# @nvidia-elements/pi + +Native [Pi](https://pi.dev) extension for the NVIDIA Elements Design System. It provides structured Elements API discovery, examples, design tokens, icons, package information, project checks, and template validation directly to Pi agents. + +## Install + +Install globally for every Pi project: + +```shell +pi install npm:@nvidia-elements/pi +``` + +Install for the current project: + +```shell +pi install -l npm:@nvidia-elements/pi +``` + +The package declares its Pi-specific `elements-pi` skill and workflow prompts as native Pi package resources. The distinct name lets it coexist with a project or global `elements` skill. + +Use the skill command to load the complete Elements workflow explicitly: + +```text +/skill:elements-pi +``` + +## Workflow prompts + +| Command | Workflow | +| --- | --- | +| `/elements-artifact` | Create a standalone Elements HTML artifact. | +| `/elements-doctor` | Check an Elements development setup. | +| `/elements-create-project` | Create an Elements starter project. | +| `/elements-migrate` | Migrate deprecated Elements packages and APIs. | + +Each command accepts an optional request, such as `/elements-artifact create a settings page`. + +## Tools + +| Tool | Description | +| --- | --- | +| `nvidia_elements_api_list` | List Elements components and attribute APIs. | +| `nvidia_elements_api_get` | Get component or attribute API documentation. | +| `nvidia_elements_api_validate` | Check HTML and JSON with Elements lint rules. | +| `nvidia_elements_api_imports_get` | Get ESM imports for an Elements template. | +| `nvidia_elements_api_tokens_list` | List semantic design tokens. | +| `nvidia_elements_api_icons_list` | List icon names. | +| `nvidia_elements_examples_list` | List known patterns and examples. | +| `nvidia_elements_examples_get` | Get a complete example template. | +| `nvidia_elements_packages_list` | List current Elements package versions. | +| `nvidia_elements_packages_get` | Get package integration details. | +| `nvidia_elements_packages_changelogs_get` | Get package changelog entries. | +| `nvidia_elements_project_validate` | Check Elements project configuration. | + +The `nvidia_elements_` prefix identifies this package's tools and reduces naming conflicts with other Pi packages. + +Pi exposes these tools directly and makes them available to `codemode` scripts. Direct calls return readable text. `codemode` calls receive `{ status, message, result }`; use `format: "json"` on tools that support it when a script needs structured data. + +## Automatic validation + +Automatic validation runs by default after Pi edits supported HTML files. Turn it off when starting Pi: + +```shell +pi --no-elements-auto-validate +``` + +You can manage it for the current session: + +```text +/elements-auto-validate off +/elements-auto-validate on +/elements-auto-validate status +``` + +When enabled, the extension runs Elements validation after successful Pi `edit` and `write` calls for `.html` and `.htm` files. It appends the validation summary and diagnostics to the tool result. When `codemode` calls those tools, the extension also adds the validation result to the parent `codemode` result so the agent sees it even if the script omits the nested tool output. + +## Manage + +```shell +pi update npm:@nvidia-elements/pi +pi remove npm:@nvidia-elements/pi +pi config +``` + +Pi extensions execute with the user's system permissions. Install packages only from trusted sources and use Pi project trust for project-local resources. + +## Related packages + +Use [`@nvidia-elements/cli`](https://www.npmjs.com/package/@nvidia-elements/cli) for interactive shell commands, project creation, project setup, and MCP integrations. This package invokes the same internal Elements tools directly through Pi's extension API; it does not start the CLI or an MCP server. diff --git a/projects/pi/eslint.config.js b/projects/pi/eslint.config.js new file mode 100644 index 0000000000..3564e08159 --- /dev/null +++ b/projects/pi/eslint.config.js @@ -0,0 +1,12 @@ +import { nodeTypescriptConfig } from '@internals/eslint'; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...nodeTypescriptConfig, + { + files: ['src/tools.ts'], + rules: { + 'max-params': 'off' + } + } +]; diff --git a/projects/pi/package.json b/projects/pi/package.json new file mode 100644 index 0000000000..91e23acd94 --- /dev/null +++ b/projects/pi/package.json @@ -0,0 +1,223 @@ +{ + "name": "@nvidia-elements/pi", + "version": "0.0.4", + "release": { + "extends": "../../release.config.js" + }, + "description": "Native Pi extension for NVIDIA Elements tools, validation, API discovery, examples, and agent guidance.", + "keywords": [ + "nvidia", + "elements", + "pi-package", + "coding-agent", + "design-system", + "web-components" + ], + "homepage": "https://NVIDIA.github.io/elements/", + "repository": { + "type": "git", + "url": "git+https://github.com/NVIDIA/elements.git", + "directory": "projects/pi" + }, + "type": "module", + "sideEffects": false, + "pi": { + "extensions": [ + "./dist/index.js" + ], + "skills": [ + "./dist/skills" + ], + "prompts": [ + "./dist/prompts" + ] + }, + "files": [ + "README.md", + "CHANGELOG.md", + "NOTICE.md", + "package.json", + "dist/**/*.js", + "dist/index.d.ts", + "dist/prompts/**/*", + "dist/skills/**/*" + ], + "exports": { + "./package.json": "./package.json", + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./index.js": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "scripts": { + "ci": "wireit", + "build": "wireit", + "build:watch": "wireit", + "lint": "wireit", + "test": "wireit", + "test:watch": "wireit", + "test:coverage": "wireit" + }, + "dependencies": { + "@nvidia-elements/lint": "workspace:^", + "@nvidia-elements/themes": "workspace:^", + "@pnpm/catalogs.config": "0.1.0", + "@pnpm/exportable-manifest": "7.0.3", + "@pnpm/read-project-manifest": "6.0.6", + "@pnpm/workspace.read-manifest": "2.2.0", + "adm-zip": "catalog:", + "archiver": "8.0.0", + "eslint": "catalog:", + "fast-glob": "catalog:", + "fflate": "0.8.3", + "html-format": "1.1.7", + "ignore": "7.0.6", + "minisearch": "7.2.0", + "open": "11.0.0", + "publint": "catalog:", + "sanitize-html": "2.17.7", + "ts-morph": "catalog:", + "zod": "catalog:" + }, + "peerDependencies": { + "@earendil-works/pi-coding-agent": "*", + "@earendil-works/pi-tui": "*", + "typebox": "*" + }, + "devDependencies": { + "@earendil-works/pi-coding-agent": "catalog:", + "@earendil-works/pi-tui": "catalog:", + "@internals/eslint": "workspace:*", + "@internals/tools": "workspace:*", + "@internals/vite": "workspace:*", + "@types/node": "catalog:", + "@vitest/coverage-istanbul": "catalog:", + "publint": "catalog:", + "typebox": "catalog:", + "typescript": "catalog:", + "vite": "catalog:", + "vitest": "catalog:" + }, + "wireit": { + "ci": { + "dependencies": [ + "lint", + "build", + "publint", + "test:coverage" + ] + }, + "publint": { + "dependencies": [ + "build" + ], + "command": "publint", + "files": [ + "package.json" + ], + "output": [] + }, + "build": { + "command": "NODE_ENV=production vite build && node src/scripts/write-resources.ts", + "files": [ + "../internals/tools/dist/**/*.js", + "src/scripts/write-resources.ts", + "src/**", + "!src/**/*.test.ts", + "package.json", + "tsconfig.json", + "tsconfig.lib.json", + "vite.config.ts" + ], + "output": [ + "dist/**" + ], + "dependencies": [ + "../internals/vite:ci", + { + "script": "../internals/tools:build", + "cascade": false + } + ] + }, + "build:watch": { + "command": "vite build --watch", + "service": true, + "dependencies": [ + "build" + ] + }, + "lint": { + "command": "eslint -c ./eslint.config.js --color --cache --cache-location .eslintcache/", + "files": [ + "src/**/*.ts", + "eslint.config.js" + ], + "output": [], + "dependencies": [ + "../internals/eslint:ci", + "../lint:build" + ] + }, + "lint:fix": { + "command": "eslint -c ./eslint.config.js --fix", + "dependencies": [ + "../internals/eslint:ci", + "../lint:build" + ] + }, + "test": { + "command": "vitest run", + "files": [ + "dist/**/*.js", + "dist/**/*.md", + "src/**/*.test.ts", + "tsconfig.json", + "vitest.config.ts" + ], + "output": [], + "dependencies": [ + "../internals/vite:ci", + { + "script": "build", + "cascade": false + } + ] + }, + "test:watch": { + "command": "vitest --watch", + "service": true + }, + "test:coverage": { + "command": "vitest run --coverage", + "files": [ + "dist/**/*.js", + "dist/**/*.md", + "src/**/*.test.ts", + "tsconfig.json", + "vitest.config.ts" + ], + "output": [ + "coverage/unit/**" + ], + "dependencies": [ + "../internals/vite:ci", + { + "script": "build", + "cascade": false + } + ], + "env": { + "NODE_ENV": "production" + } + } + }, + "publishConfig": { + "provenance": true + }, + "license": "Apache-2.0" +} diff --git a/projects/pi/src/auto-validation.test.ts b/projects/pi/src/auto-validation.test.ts new file mode 100644 index 0000000000..9127620fee --- /dev/null +++ b/projects/pi/src/auto-validation.test.ts @@ -0,0 +1,294 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import type { + ExtensionAPI, + ExtensionCommandContext, + ExtensionContext, + ToolResultEvent +} from '@earendil-works/pi-coding-agent'; +import type { ManagedToolMethod, ToolOutput } from '@internals/tools'; +import { registerElementsAutoValidation } from './auto-validation.js'; + +interface ToolResultPatch { + content?: ToolResultEvent['content']; +} + +function createValidationTool(handler: () => Promise): ManagedToolMethod { + const tool = handler as ManagedToolMethod; + tool.metadata = { + name: 'validate', + title: 'API Validate', + command: 'api.validate', + toolName: 'api_validate', + summary: 'Validate HTML.', + support: 0 + }; + return tool; +} + +function createHarness(flagDisabled = false) { + const handlers = new Map unknown>(); + const commands = new Map Promise>(); + const notify = vi.fn(); + const pi = { + getFlag: vi.fn(() => flagDisabled), + on: vi.fn((event: string, handler: (...args: unknown[]) => unknown) => handlers.set(event, handler)), + registerCommand: vi.fn( + (name: string, command: { handler: (args: string, ctx: ExtensionCommandContext) => Promise }) => + commands.set(name, command.handler) + ), + registerFlag: vi.fn() + } as unknown as ExtensionAPI; + const context = { + cwd: '/project', + signal: undefined, + ui: { notify } + } as unknown as ExtensionContext; + return { commands, context, handlers, notify, pi }; +} + +function writeEvent(path: string, isError = false): ToolResultEvent { + return { + type: 'tool_result', + toolCallId: 'write-call', + toolName: 'write', + input: { path, content: '' }, + content: [{ type: 'text', text: 'Wrote file.' }], + details: undefined, + isError + }; +} + +describe('Elements automatic validation', () => { + let info: ReturnType; + let warn: ReturnType; + + beforeEach(() => { + info = vi.spyOn(console, 'info').mockImplementation(() => undefined); + warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined); + }); + + afterEach(() => { + info.mockRestore(); + warn.mockRestore(); + }); + + it('should use the bundled validation tool by default', () => { + const harness = createHarness(); + expect(() => registerElementsAutoValidation(harness.pi)).not.toThrow(); + }); + + it('should register an opt-out flag and command', () => { + const harness = createHarness(); + const validationTool = createValidationTool(async () => ({ status: 'complete' })); + registerElementsAutoValidation(harness.pi, { validationTool }); + expect(harness.pi.registerFlag).toHaveBeenCalledWith('no-elements-auto-validate', { + description: 'Disable automatic Elements validation after HTML edit and write tool calls.', + type: 'boolean', + default: false + }); + expect(harness.pi.registerCommand).toHaveBeenCalledWith( + 'elements-auto-validate', + expect.objectContaining({ description: expect.any(String), handler: expect.any(Function) }) + ); + }); + + it('should append validation after successful HTML writes by default', async () => { + const harness = createHarness(); + const validationTool = vi.fn(async () => ({ + status: 'complete' as const, + result: '## Validation passed\n\n1 file, 0 errors, 0 warnings' + })) as unknown as ManagedToolMethod; + validationTool.metadata = createValidationTool(async () => ({ status: 'complete' })).metadata; + registerElementsAutoValidation(harness.pi, { validationTool }); + await harness.handlers.get('session_start')?.({ type: 'session_start', reason: 'startup' }, harness.context); + const result = (await harness.handlers.get('tool_result')?.( + writeEvent('page.html'), + harness.context + )) as ToolResultPatch; + expect(validationTool).toHaveBeenCalledWith({ paths: ['page.html'], format: 'markdown', cwd: '/project' }); + expect(result.content).toEqual([ + { type: 'text', text: 'Wrote file.' }, + { + type: 'text', + text: 'Elements automatic validation:\n\n## Validation passed\n\n1 file, 0 errors, 0 warnings' + } + ]); + }); + + it('should surface nested write validation in the parent tool result', async () => { + const harness = createHarness(); + const validationTool = createValidationTool(async () => ({ + status: 'complete', + result: '1 file, 1 error, 0 warnings' + })); + registerElementsAutoValidation(harness.pi, { validationTool }); + const handler = harness.handlers.get('tool_result'); + const nestedResult = (await handler?.( + { ...writeEvent('page.html'), toolCallId: 'codemode-call/1', parentToolCallId: 'codemode-call' }, + harness.context + )) as ToolResultPatch; + expect(nestedResult.content?.at(-1)).toEqual({ + type: 'text', + text: 'Elements automatic validation:\n\n1 file, 1 error, 0 warnings' + }); + + const parentEvent: ToolResultEvent = { + type: 'tool_result', + toolCallId: 'codemode-call', + toolName: 'codemode', + input: { code: 'await tools.write(...)' }, + content: [{ type: 'text', text: 'Wrote page.html' }], + details: undefined, + isError: false + }; + const parentResult = (await handler?.(parentEvent, harness.context)) as ToolResultPatch; + expect(parentResult.content).toEqual([ + { type: 'text', text: 'Wrote page.html' }, + { type: 'text', text: 'Elements automatic validation:\n\n1 file, 1 error, 0 warnings' } + ]); + expect(await handler?.(parentEvent, harness.context)).toBeUndefined(); + }); + + it('should avoid repeating validation already surfaced by a Codemode script', async () => { + const harness = createHarness(); + const validationTool = createValidationTool(async () => ({ status: 'complete', result: 'No errors' })); + registerElementsAutoValidation(harness.pi, { validationTool }); + const handler = harness.handlers.get('tool_result'); + const nestedResult = (await handler?.( + { ...writeEvent('page.html'), parentToolCallId: 'codemode-call' }, + harness.context + )) as ToolResultPatch; + const parentEvent: ToolResultEvent = { + type: 'tool_result', + toolCallId: 'codemode-call', + toolName: 'codemode', + input: {}, + content: nestedResult.content ?? [], + details: undefined, + isError: false + }; + expect(await handler?.(parentEvent, harness.context)).toBeUndefined(); + }); + + it('should honor the disable flag and ignore failed or non-HTML writes', async () => { + const harness = createHarness(true); + const validationTool = vi.fn(async () => ({ + status: 'complete' as const + })) as unknown as ManagedToolMethod; + validationTool.metadata = createValidationTool(async () => ({ status: 'complete' })).metadata; + registerElementsAutoValidation(harness.pi, { validationTool }); + const handler = harness.handlers.get('tool_result'); + await harness.handlers.get('session_start')?.({ type: 'session_start', reason: 'startup' }, harness.context); + await handler?.(writeEvent('page.html'), harness.context); + await harness.commands.get('elements-auto-validate')?.('on', harness.context as ExtensionCommandContext); + await handler?.(writeEvent('package.json'), harness.context); + await handler?.(writeEvent('page.html', true), harness.context); + expect(validationTool).not.toHaveBeenCalled(); + expect(info).toHaveBeenCalledWith( + expect.objectContaining({ + event: 'elements.auto_validation.tool_result', + decision: 'skipped_disabled' + }) + ); + expect(info).toHaveBeenCalledWith( + expect.objectContaining({ + event: 'elements.auto_validation.tool_result', + decision: 'skipped_ineligible_path' + }) + ); + }); + + it('should toggle validation for the current session', async () => { + const harness = createHarness(); + const validationTool = createValidationTool(async () => ({ status: 'complete' })); + registerElementsAutoValidation(harness.pi, { validationTool }); + const command = harness.commands.get('elements-auto-validate'); + await command?.('on', harness.context as ExtensionCommandContext); + expect(harness.notify).toHaveBeenLastCalledWith('Elements automatic validation enabled.'); + await command?.('status', harness.context as ExtensionCommandContext); + expect(harness.notify).toHaveBeenLastCalledWith('Elements automatic validation is enabled.'); + await command?.('off', harness.context as ExtensionCommandContext); + expect(harness.notify).toHaveBeenLastCalledWith('Elements automatic validation disabled.'); + expect(info).toHaveBeenCalledWith({ + event: 'elements.auto_validation.enabled_changed', + source: 'command', + enabled: false + }); + await command?.('invalid', harness.context as ExtensionCommandContext); + expect(harness.notify).toHaveBeenLastCalledWith('Use /elements-auto-validate [on|off|status].', 'warning'); + await command?.('', harness.context as ExtensionCommandContext); + expect(harness.notify).toHaveBeenLastCalledWith('Elements automatic validation enabled.'); + await command?.('', harness.context as ExtensionCommandContext); + expect(harness.notify).toHaveBeenLastCalledWith('Elements automatic validation disabled.'); + await command?.('status', harness.context as ExtensionCommandContext); + expect(harness.notify).toHaveBeenLastCalledWith('Elements automatic validation is disabled.'); + await harness.handlers.get('session_start')?.({ type: 'session_start', reason: 'startup' }, harness.context); + }); + + it('should report validation execution errors without failing the write result', async () => { + const harness = createHarness(); + const validationTool = createValidationTool(async () => ({ status: 'error' })); + registerElementsAutoValidation(harness.pi, { validationTool }); + await harness.handlers.get('session_start')?.({ type: 'session_start', reason: 'startup' }, harness.context); + const result = (await harness.handlers.get('tool_result')?.( + writeEvent('page.htm'), + harness.context + )) as ToolResultPatch; + expect(result.content?.at(-1)).toEqual({ + type: 'text', + text: 'Elements automatic validation could not run: Unknown error' + }); + }); + + it('should preserve write results when validation rejects', async () => { + const harness = createHarness(); + const validationTool = createValidationTool(async () => { + throw new Error('/private/project/page.html failed'); + }); + registerElementsAutoValidation(harness.pi, { validationTool }); + const result = (await harness.handlers.get('tool_result')?.( + writeEvent('/private/project/page.html'), + harness.context + )) as ToolResultPatch; + expect(result.content).toEqual([ + { type: 'text', text: 'Wrote file.' }, + { type: 'text', text: 'Elements automatic validation could not run.' } + ]); + expect(warn).toHaveBeenCalledWith({ + event: 'elements.auto_validation.validation_failed', + toolName: 'write', + toolCallId: 'write-call' + }); + }); + + it('should format structured validation output after edits', async () => { + const harness = createHarness(); + const validationTool = createValidationTool(async () => ({ + status: 'complete', + result: { ok: true } + })); + registerElementsAutoValidation(harness.pi, { validationTool }); + await harness.handlers.get('session_start')?.({ type: 'session_start', reason: 'startup' }, harness.context); + const result = (await harness.handlers.get('tool_result')?.( + { + ...writeEvent('/private/project/page.html'), + toolName: 'edit', + details: { diff: '', patch: '' } + }, + harness.context + )) as ToolResultPatch; + expect(result.content?.at(-1)).toEqual({ + type: 'text', + text: 'Elements automatic validation:\n\n{\n "ok": true\n}' + }); + expect(info).toHaveBeenCalledWith({ + event: 'elements.auto_validation.tool_result', + decision: 'sent_for_validation', + toolName: 'edit', + toolCallId: 'write-call' + }); + }); +}); diff --git a/projects/pi/src/auto-validation.ts b/projects/pi/src/auto-validation.ts new file mode 100644 index 0000000000..7094f25119 --- /dev/null +++ b/projects/pi/src/auto-validation.ts @@ -0,0 +1,205 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { extname } from 'node:path'; +import { + isEditToolResult, + isWriteToolResult, + type ExtensionAPI, + type ExtensionContext, + type ToolResultEvent +} from '@earendil-works/pi-coding-agent'; +import type { ManagedToolMethod, ToolOutput } from '@internals/tools'; +import { piLogger } from './logging.js'; +import { getPiTools } from './tools.js'; + +const commandName = 'elements-auto-validate'; +const disableFlagName = `no-${commandName}`; + +interface AutoValidationOptions { + validationTool?: ManagedToolMethod; +} + +interface AutoValidationState { + enabled: boolean; + validationTool: ManagedToolMethod; + pendingByParentId: Map; +} + +type AutoValidationDecision = 'skipped_disabled' | 'skipped_ineligible_path' | 'sent_for_validation'; + +function getValidationTool(options: AutoValidationOptions): ManagedToolMethod { + const validationTool = options.validationTool ?? getPiTools().find(tool => tool.metadata.toolName === 'api_validate'); + if (!validationTool) throw new Error('Elements validation tool not found.'); + return validationTool; +} + +function getEditedHtmlPath(event: ToolResultEvent): string | undefined { + if (event.isError || (!isEditToolResult(event) && !isWriteToolResult(event))) return undefined; + const path = event.input.path; + if (typeof path !== 'string' || !['.htm', '.html'].includes(extname(path).toLowerCase())) return undefined; + return path; +} + +function getParentToolCallId(event: ToolResultEvent): string | undefined { + return 'parentToolCallId' in event && typeof event.parentToolCallId === 'string' ? event.parentToolCallId : undefined; +} + +function formatValidationOutput(output: ToolOutput): string { + if (output.status === 'error') + return `Elements automatic validation could not run: ${output.message ?? 'Unknown error'}`; + const result = output.result; + const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2); + return `Elements automatic validation:\n\n${text ?? output.message ?? 'Complete'}`; +} + +function updateAutoValidation(args: string, enabled: boolean, ctx: ExtensionContext): boolean { + const value = args.trim().toLowerCase(); + if (value === 'status') { + ctx.ui.notify(`Elements automatic validation is ${enabled ? 'enabled' : 'disabled'}.`); + return enabled; + } + if (value && value !== 'on' && value !== 'off') { + ctx.ui.notify(`Use /${commandName} [on|off|status].`, 'warning'); + return enabled; + } + const nextEnabled = value === 'on' || (value === '' && !enabled); + ctx.ui.notify(`Elements automatic validation ${nextEnabled ? 'enabled' : 'disabled'}.`); + return nextEnabled; +} + +function logEnabledChange(source: 'command' | 'session_start', enabled: boolean, reason?: string): void { + piLogger.info({ + event: 'elements.auto_validation.enabled_changed', + source, + ...(reason ? { reason } : {}), + enabled + }); +} + +function logToolResultDecision(event: ToolResultEvent, decision: AutoValidationDecision): void { + piLogger.info({ + event: 'elements.auto_validation.tool_result', + decision, + toolName: event.toolName, + toolCallId: event.toolCallId + }); +} + +function getValidationFailureMessage(event: ToolResultEvent): string { + piLogger.warn({ + event: 'elements.auto_validation.validation_failed', + toolName: event.toolName, + toolCallId: event.toolCallId + }); + return 'Elements automatic validation could not run.'; +} + +function appendValidation( + event: ToolResultEvent, + text: string, + pendingByParentId: Map +): { content: ToolResultEvent['content'] } { + const parentId = getParentToolCallId(event); + if (parentId) { + const pending = pendingByParentId.get(parentId) ?? []; + pending.push(text); + pendingByParentId.set(parentId, pending); + } + return { content: [...event.content, { type: 'text', text }] }; +} + +function getParentValidation( + event: ToolResultEvent, + pendingByParentId: Map +): { content: ToolResultEvent['content'] } | undefined { + const pending = pendingByParentId.get(event.toolCallId); + if (!pending) return; + pendingByParentId.delete(event.toolCallId); + if (event.toolName !== 'codemode') return; + const existingText = event.content + .filter(content => content.type === 'text') + .map(content => content.text) + .join('\n'); + const missing = pending.filter(result => !existingText.includes(result)); + if (missing.length === 0) return; + return { content: [...event.content, ...missing.map(text => ({ type: 'text' as const, text }))] }; +} + +async function handleToolResult( + event: ToolResultEvent, + ctx: ExtensionContext, + state: AutoValidationState +): Promise<{ content: ToolResultEvent['content'] } | undefined> { + const parentValidation = getParentValidation(event, state.pendingByParentId); + if (parentValidation) return parentValidation; + if (!state.enabled) { + logToolResultDecision(event, 'skipped_disabled'); + return; + } + const path = getEditedHtmlPath(event); + if (!path) { + logToolResultDecision(event, 'skipped_ineligible_path'); + return; + } + logToolResultDecision(event, 'sent_for_validation'); + try { + const output = await state.validationTool({ paths: [path], format: 'markdown', cwd: ctx.cwd }); + return appendValidation(event, formatValidationOutput(output), state.pendingByParentId); + } catch { + return appendValidation(event, getValidationFailureMessage(event), state.pendingByParentId); + } +} + +/** + * Registers automatic Elements validation with Pi. + * + * The registration adds the `--no-elements-auto-validate` flag, the + * `/elements-auto-validate` session command, and session and tool-result hooks. By default, the + * bundled validation tool runs with Markdown output. Callers can provide a compatible validation + * tool through `options.validationTool`, primarily for integration and testing. + * + * Successful Pi `edit` and `write` results for paths ending in `.html` or `.htm`, matched without + * regard to case, run validation from the current extension working directory. The hook appends a + * formatted validation result to the existing tool-result content. For nested calls, it also + * appends the result to the parent tool's output so Codemode scripts cannot silently discard it. + * Disabled validation, failed tool calls, other tools, and unsupported paths leave the result unchanged. + * + * @param pi - Pi's extension API, used to register the flag, command, and event hooks. + * @param options - Optional validation tool override. + * @returns Nothing. + */ +export function registerElementsAutoValidation(pi: ExtensionAPI, options: AutoValidationOptions = {}): void { + const state: AutoValidationState = { + enabled: true, + validationTool: getValidationTool(options), + pendingByParentId: new Map() + }; + + pi.registerFlag(disableFlagName, { + description: 'Disable automatic Elements validation after HTML edit and write tool calls.', + type: 'boolean', + default: false + }); + + pi.on('session_start', event => { + state.pendingByParentId.clear(); + const nextEnabled = pi.getFlag(disableFlagName) !== true; + if (nextEnabled !== state.enabled) logEnabledChange('session_start', nextEnabled, event.reason); + state.enabled = nextEnabled; + }); + + pi.on('agent_end', () => state.pendingByParentId.clear()); + pi.on('session_shutdown', () => state.pendingByParentId.clear()); + + pi.registerCommand(commandName, { + description: 'Toggle automatic Elements validation after HTML edits.', + handler: async (args, ctx) => { + const nextEnabled = updateAutoValidation(args, state.enabled, ctx); + if (nextEnabled !== state.enabled) logEnabledChange('command', nextEnabled); + state.enabled = nextEnabled; + } + }); + + pi.on('tool_result', (event, ctx) => handleToolResult(event, ctx, state)); +} diff --git a/projects/pi/src/index.test.ts b/projects/pi/src/index.test.ts new file mode 100644 index 0000000000..9976f489f1 --- /dev/null +++ b/projects/pi/src/index.test.ts @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it, vi } from 'vitest'; +import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'; +import elementsExtension, { VERSION } from './index.js'; + +vi.mock('./auto-validation.js', () => ({ registerElementsAutoValidation: vi.fn() })); +vi.mock('./tools.js', () => ({ registerElementsTools: vi.fn() })); + +describe('@nvidia-elements/pi', () => { + it('should export a release version placeholder', () => { + expect(VERSION).toBe('0.0.0'); + }); + + it('should initialize the Pi adapter', async () => { + const { registerElementsAutoValidation } = await import('./auto-validation.js'); + const { registerElementsTools } = await import('./tools.js'); + const pi = {} as ExtensionAPI; + elementsExtension(pi); + expect(process.env.ELEMENTS_ENV).toBe('pi'); + expect(registerElementsTools).toHaveBeenCalledWith(pi); + expect(registerElementsAutoValidation).toHaveBeenCalledWith(pi); + }); +}); diff --git a/projects/pi/src/index.ts b/projects/pi/src/index.ts new file mode 100644 index 0000000000..33537bbc83 --- /dev/null +++ b/projects/pi/src/index.ts @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'; +import { registerElementsAutoValidation } from './auto-validation.js'; +import { registerElementsTools } from './tools.js'; + +export const VERSION = '0.0.0'; + +/** + * Initializes the NVIDIA Elements Pi extension. + * + * Sets the Elements runtime environment to `pi`, registers the Elements tools, and enables the + * automatic-validation flag, command, and event hooks. Automatic validation uses its default + * options and runs after eligible HTML edit and write results. + * + * @param pi - Pi's extension API used for tool, flag, command, and event registration. + * @returns Nothing. + */ +export default function elementsExtension(pi: ExtensionAPI): void { + process.env.ELEMENTS_ENV = 'pi'; + registerElementsTools(pi); + registerElementsAutoValidation(pi); +} diff --git a/projects/pi/src/logging.ts b/projects/pi/src/logging.ts new file mode 100644 index 0000000000..56d628f374 --- /dev/null +++ b/projects/pi/src/logging.ts @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +type PiLogEntry = Readonly<{ event: string } & Record>; + +export const piLogger = { + info(entry: PiLogEntry): void { + console.info(entry); + }, + warn(entry: PiLogEntry): void { + console.warn(entry); + } +}; diff --git a/projects/pi/src/package.test.ts b/projects/pi/src/package.test.ts new file mode 100644 index 0000000000..79cb40fbeb --- /dev/null +++ b/projects/pi/src/package.test.ts @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { access, readFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { describe, expect, it, vi } from 'vitest'; +import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'; +import piPackage from '../package.json' with { type: 'json' }; +import toolsPackage from '../../internals/tools/package.json' with { type: 'json' }; +import lintPackage from '../../lint/package.json' with { type: 'json' }; + +describe('@nvidia-elements/pi package', () => { + it('should declare runtime dependencies and host-provided peers', async () => { + expect(piPackage.dependencies).toMatchObject(toolsPackage.dependencies); + const extension = await readFile(resolve('dist/index.js'), 'utf8'); + for (const name of ['@earendil-works/pi-coding-agent', '@earendil-works/pi-tui', 'typebox']) { + expect(extension).toContain(`from "${name}"`); + expect(piPackage.peerDependencies).toHaveProperty(name, '*'); + expect(piPackage.dependencies).not.toHaveProperty(name); + } + for (const name of Object.keys(lintPackage.peerDependencies)) { + expect(piPackage.dependencies).toHaveProperty(name); + } + }); + + it('should not publish internal packages as dependencies', () => { + expect(Object.keys(piPackage.dependencies).some(name => name.startsWith('@internals/'))).toBe(false); + }); + + it('should expose the built extension and native package resources', async () => { + await expect(access(resolve('dist/index.js'))).resolves.toBeUndefined(); + await expect(access(resolve('dist/skills/elements-pi/SKILL.md'))).resolves.toBeUndefined(); + await expect(access(resolve('dist/skills/elements/SKILL.md'))).rejects.toThrow(); + const skill = await readFile(resolve('dist/skills/elements-pi/SKILL.md'), 'utf8'); + expect(skill).toContain('name: "elements-pi"'); + expect(skill).toContain('## Native Elements tools in Pi'); + expect(skill).toContain('When a project or global `elements` skill is also available'); + expect(skill).toContain('`nvidia_elements_api_get`'); + expect(skill).not.toContain('## Elements CLI, MCP & Context'); + await expect(access(resolve('dist/skills/elements-pi/references/artifact.md'))).resolves.toBeUndefined(); + await expect(access(resolve('dist/skills/elements-pi/references/integration.md'))).resolves.toBeUndefined(); + await expect(access(resolve('dist/skills/elements-pi/references/migration.md'))).resolves.toBeUndefined(); + const doctor = await readFile(resolve('dist/skills/elements-pi/references/doctor.md'), 'utf8'); + expect(doctor).toContain('# Elements Pi Doctor / Setup Check'); + expect(doctor).toContain('/skill:elements-pi'); + expect(doctor).not.toContain('## MCP Checks'); + for (const prompt of ['artifact', 'doctor', 'create-project', 'migrate']) { + await expect(access(resolve(`dist/prompts/elements-${prompt}.md`))).resolves.toBeUndefined(); + } + await expect(readFile(resolve('dist/prompts/elements-migrate.md'), 'utf8')).resolves.toContain( + 'nvidia_elements_api_get' + ); + expect(piPackage.pi.skills).toEqual(['./dist/skills']); + expect(piPackage.pi.prompts).toEqual(['./dist/prompts']); + }); + + it('should not eagerly load project archive dependencies', async () => { + const extension = await readFile(resolve('dist/index.js'), 'utf8'); + expect(extension).not.toMatch(/import\s+(?:[^;]*from\s+)?["']archiver["']/); + }); + + it('should register the Elements tools from the built extension', async () => { + const { default: elementsExtension } = await import('../dist/index.js'); + const registerTool = vi.fn(); + const pi = { + getFlag: vi.fn(() => false), + on: vi.fn(), + registerCommand: vi.fn(), + registerFlag: vi.fn(), + registerTool + } as unknown as ExtensionAPI; + + elementsExtension(pi); + + expect(registerTool.mock.calls.map(([tool]) => tool.name)).toEqual([ + 'nvidia_elements_api_list', + 'nvidia_elements_api_get', + 'nvidia_elements_api_validate', + 'nvidia_elements_api_imports_get', + 'nvidia_elements_api_tokens_list', + 'nvidia_elements_api_icons_list', + 'nvidia_elements_examples_list', + 'nvidia_elements_examples_get', + 'nvidia_elements_project_validate', + 'nvidia_elements_packages_list', + 'nvidia_elements_packages_get', + 'nvidia_elements_packages_changelogs_get' + ]); + }); +}); diff --git a/projects/pi/src/renderers.test.ts b/projects/pi/src/renderers.test.ts new file mode 100644 index 0000000000..4b5cd86a72 --- /dev/null +++ b/projects/pi/src/renderers.test.ts @@ -0,0 +1,118 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it } from 'vitest'; +import type { ToolDefinition } from '@earendil-works/pi-coding-agent'; +import type { TSchema } from 'typebox'; +import type { ElementsToolDetails } from './results.js'; +import { renderProjectValidationResult, renderValidationResult } from './renderers.js'; + +type Renderer = NonNullable['renderResult']>; +type Theme = Parameters[2]; +type Context = Parameters[3]; + +const theme = { + fg: (_color: string, text: string) => text +} as Theme; +const context = {} as Context; + +function render(component: ReturnType): string { + return component.render(120).join('\n'); +} + +describe('Elements Pi renderers', () => { + it('should render structured validation summaries', () => { + const component = renderValidationResult( + { + content: [{ type: 'text', text: 'details' }], + details: { toolName: 'nvidia_elements_api_validate', result: { summary: { files: 2, errors: 1, warnings: 3 } } } + }, + { expanded: false, isPartial: false }, + theme, + context + ); + expect(render(component)).toContain('1 error · 3 warnings · 2 files'); + }); + + it('should render markdown validation summaries and expanded output', () => { + const component = renderValidationResult( + { + content: [{ type: 'text', text: '2 files, 0 errors, 1 warnings\nwarning details' }], + details: { toolName: 'nvidia_elements_api_validate' } + }, + { expanded: true, isPartial: false }, + theme, + context + ); + expect(render(component)).toContain('0 errors · 1 warning · 2 files'); + expect(render(component)).toContain('warning details'); + }); + + it('should render successful validation summaries', () => { + const component = renderValidationResult( + { + content: [{ type: 'text', text: '1 file, 0 errors, 0 warnings' }], + details: { toolName: 'nvidia_elements_api_validate', result: { summary: { files: 1, errors: 0, warnings: 0 } } } + }, + { expanded: false, isPartial: false }, + theme, + context + ); + expect(render(component)).toContain('0 errors · 0 warnings · 1 file'); + }); + + it('should render validation progress and raw fallback', () => { + const partial = renderValidationResult( + { content: [], details: { toolName: 'nvidia_elements_api_validate' } }, + { expanded: false, isPartial: true }, + theme, + context + ); + const fallback = renderValidationResult( + { content: [{ type: 'text', text: 'unknown' }], details: { toolName: 'nvidia_elements_api_validate' } }, + { expanded: false, isPartial: false }, + theme, + context + ); + expect(render(partial)).toContain('Validating'); + expect(render(fallback)).toContain('unknown'); + }); + + it('should render project health summaries', () => { + const component = renderProjectValidationResult( + { + content: [{ type: 'text', text: 'report' }], + details: { + toolName: 'nvidia_elements_project_validate', + result: { + dependencies: { status: 'success', message: 'Dependencies valid' }, + versions: { status: 'warning', message: 'Update available' }, + config: { status: 'danger', message: 'Config invalid' } + } + } + }, + { expanded: true, isPartial: false }, + theme, + context + ); + expect(render(component)).toContain('1 passed · 1 warning · 1 failed'); + expect(render(component)).toContain('Config invalid'); + }); + + it('should render project progress and raw fallback', () => { + const partial = renderProjectValidationResult( + { content: [], details: { toolName: 'nvidia_elements_project_validate' } }, + { expanded: false, isPartial: true }, + theme, + context + ); + const fallback = renderProjectValidationResult( + { content: [{ type: 'text', text: 'unknown' }], details: { toolName: 'nvidia_elements_project_validate' } }, + { expanded: false, isPartial: false }, + theme, + context + ); + expect(render(partial)).toContain('Checking'); + expect(render(fallback)).toContain('unknown'); + }); +}); diff --git a/projects/pi/src/renderers.ts b/projects/pi/src/renderers.ts new file mode 100644 index 0000000000..dc6d8393e9 --- /dev/null +++ b/projects/pi/src/renderers.ts @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import type { ToolDefinition } from '@earendil-works/pi-coding-agent'; +import { Text } from '@earendil-works/pi-tui'; +import type { TSchema } from 'typebox'; +import type { ElementsToolDetails } from './results.js'; + +type ResultRenderer = NonNullable['renderResult']>; + +interface ValidationSummary { + files: number; + errors: number; + warnings: number; +} + +interface ReportCheck { + status?: string; + message?: string; +} + +function formatCount(count: number, name: string): string { + return `${count} ${name}${count === 1 ? '' : 's'}`; +} + +function getTextContent(result: Parameters[0]): string { + const content = result.content[0]; + return content?.type === 'text' ? content.text : ''; +} + +function isValidationSummary(value: unknown): value is ValidationSummary { + if (typeof value !== 'object' || value === null) return false; + return ( + 'files' in value && + 'errors' in value && + 'warnings' in value && + typeof value.files === 'number' && + typeof value.errors === 'number' && + typeof value.warnings === 'number' + ); +} + +function getStructuredValidationSummary(value: unknown): ValidationSummary | undefined { + if (typeof value !== 'object' || value === null || !('summary' in value)) return undefined; + return isValidationSummary(value.summary) ? value.summary : undefined; +} + +function getValidationSummary(result: Parameters[0]): ValidationSummary | undefined { + const structuredSummary = getStructuredValidationSummary(result.details?.result); + if (structuredSummary) return structuredSummary; + const match = getTextContent(result).match(/(\d+) files?, (\d+) errors?, (\d+) warnings?/); + if (!match) return undefined; + return { files: Number(match[1]), errors: Number(match[2]), warnings: Number(match[3]) }; +} + +function getReportChecks(result: Parameters[0]): ReportCheck[] { + const value = result.details?.result; + if (typeof value !== 'object' || value === null || Array.isArray(value)) return []; + return Object.values(value).filter( + (check): check is ReportCheck => typeof check === 'object' && check !== null && !Array.isArray(check) + ); +} + +function renderExpandedText(text: string, expanded: boolean, theme: Parameters[2]): string { + if (!expanded || !text) return ''; + return `\n${theme.fg('dim', text)}`; +} + +export const renderValidationResult: ResultRenderer = (result, { expanded, isPartial }, theme) => { + if (isPartial) return new Text(theme.fg('warning', 'Validating Elements template…'), 0, 0); + const summary = getValidationSummary(result); + if (!summary) return new Text(getTextContent(result), 0, 0); + const color = summary.errors > 0 ? 'error' : summary.warnings > 0 ? 'warning' : 'success'; + const label = [ + formatCount(summary.errors, 'error'), + formatCount(summary.warnings, 'warning'), + formatCount(summary.files, 'file') + ].join(' · '); + const text = `${theme.fg(color, label)}${renderExpandedText(getTextContent(result), expanded, theme)}`; + return new Text(text, 0, 0); +}; + +export const renderProjectValidationResult: ResultRenderer = (result, { expanded, isPartial }, theme) => { + if (isPartial) return new Text(theme.fg('warning', 'Checking Elements project…'), 0, 0); + const checks = getReportChecks(result); + if (checks.length === 0) return new Text(getTextContent(result), 0, 0); + const failed = checks.filter(check => check.status === 'danger').length; + const warnings = checks.filter(check => check.status === 'warning').length; + const passed = checks.length - failed - warnings; + const color = failed > 0 ? 'error' : warnings > 0 ? 'warning' : 'success'; + const summary = theme.fg( + color, + `${formatCount(passed, 'passed')} · ${formatCount(warnings, 'warning')} · ${formatCount(failed, 'failed')}` + ); + const details = checks.map(check => `${check.status ?? 'unknown'}: ${check.message ?? ''}`).join('\n'); + return new Text(`${summary}${renderExpandedText(details, expanded, theme)}`, 0, 0); +}; diff --git a/projects/pi/src/results.test.ts b/projects/pi/src/results.test.ts new file mode 100644 index 0000000000..23876ad3b1 --- /dev/null +++ b/projects/pi/src/results.test.ts @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { readFile, rm, stat } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { afterEach, describe, expect, it } from 'vitest'; +import { createElementsToolResult, getElementsToolError } from './results.js'; + +const outputDirectories = new Set(); + +describe('Elements tool results', () => { + afterEach(async () => { + await Promise.all([...outputDirectories].map(path => rm(path, { recursive: true, force: true }))); + outputDirectories.clear(); + }); + + it('should return string results', async () => { + const result = await createElementsToolResult('call', 'nvidia_elements_api_get', { + status: 'complete', + result: 'Documentation' + }); + expect(result.content).toEqual([{ type: 'text', text: 'Documentation' }]); + expect(result.details.result).toBe('Documentation'); + expect(result.structuredContent).toEqual({ status: 'complete', result: 'Documentation' }); + }); + + it('should format structured results', async () => { + const result = await createElementsToolResult('call', 'nvidia_elements_api_get', { + status: 'complete', + result: { name: 'nve-button', optional: undefined } + }); + expect(result.content[0]).toEqual({ type: 'text', text: '{\n "name": "nve-button"\n}' }); + expect(result.structuredContent).toEqual({ status: 'complete', result: { name: 'nve-button' } }); + }); + + it('should use the completion message when result is absent', async () => { + const result = await createElementsToolResult('call', 'nvidia_elements_api_get', { + status: 'complete', + message: 'Done' + }); + expect(result.content[0]).toEqual({ type: 'text', text: 'Done' }); + }); + + it('should truncate large output and save the complete value', async () => { + const output = Array.from({ length: 2100 }, (_, index) => `line ${index}`).join('\n'); + const result = await createElementsToolResult('call:unsafe', 'nvidia_elements_api_list', { + status: 'complete', + result: output + }); + const outputPath = result.details.truncation?.outputPath; + const outputDirectory = dirname(outputPath!); + outputDirectories.add(outputDirectory); + expect(outputPath).toContain('call_unsafe.txt'); + expect(outputDirectory.startsWith(join(tmpdir(), 'nvidia-elements-pi-'))).toBe(true); + expect(result.details.result).toBeUndefined(); + expect(result.structuredContent).toEqual({ status: 'complete', result: output }); + expect(result.content[0]?.type === 'text' ? result.content[0].text : '').toContain('Output truncated'); + await expect(readFile(outputPath!, 'utf8')).resolves.toBe(output); + await expect(stat(outputDirectory).then(value => value.mode & 0o777)).resolves.toBe(0o700); + await expect(stat(outputPath!).then(value => value.mode & 0o777)).resolves.toBe(0o600); + + const secondResult = await createElementsToolResult('call:unsafe', 'nvidia_elements_api_list', { + status: 'complete', + result: output + }); + const secondOutputDirectory = dirname(secondResult.details.truncation!.outputPath); + outputDirectories.add(secondOutputDirectory); + expect(secondOutputDirectory).not.toBe(outputDirectory); + }); + + it('should create errors with structured context', () => { + const error = getElementsToolError({ status: 'error', message: 'Invalid', result: { field: 'name' } }); + expect(error.message).toContain('Invalid'); + expect(error.message).toContain('"field": "name"'); + }); + + it('should provide a fallback error message', () => { + expect(getElementsToolError({ status: 'error' }).message).toBe('Elements tool failed.'); + }); +}); diff --git a/projects/pi/src/results.ts b/projects/pi/src/results.ts new file mode 100644 index 0000000000..668d90cbb5 --- /dev/null +++ b/projects/pi/src/results.ts @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { mkdtemp, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { + DEFAULT_MAX_BYTES, + DEFAULT_MAX_LINES, + formatSize, + truncateHead, + type AgentToolResult +} from '@earendil-works/pi-coding-agent'; +import type { ToolOutput } from '@internals/tools'; + +export interface ElementsToolDetails { + toolName: string; + result?: unknown; + truncation?: { + outputPath: string; + totalBytes: number; + totalLines: number; + }; +} + +function toStructuredContent(output: ToolOutput): NonNullable { + // A JSON round trip removes undefined fields and satisfies Pi's JSON value contract. + return JSON.parse(JSON.stringify(output)) as NonNullable; +} + +function formatResult(result: unknown, message?: string): string { + if (typeof result === 'string') return result; + if (result !== undefined) return JSON.stringify(result, null, 2); + return message || 'Complete'; +} + +async function writeFullOutput(toolCallId: string, output: string): Promise { + const outputDirectory = await mkdtemp(join(tmpdir(), 'nvidia-elements-pi-')); + const outputPath = join(outputDirectory, `${toolCallId.replaceAll(/[^a-zA-Z0-9_-]/g, '_')}.txt`); + await writeFile(outputPath, output, { encoding: 'utf8', mode: 0o600 }); + return outputPath; +} + +export function getElementsToolError(output: ToolOutput): Error { + const result = output.result === undefined ? '' : `\n\n${formatResult(output.result)}`; + return new Error(`${output.message || 'Elements tool failed.'}${result}`); +} + +export async function createElementsToolResult( + toolCallId: string, + toolName: string, + output: ToolOutput +): Promise> { + const text = formatResult(output.result, output.message); + const truncation = truncateHead(text, { maxBytes: DEFAULT_MAX_BYTES, maxLines: DEFAULT_MAX_LINES }); + const structuredContent = toStructuredContent(output); + + if (!truncation.truncated) { + return { + content: [{ type: 'text', text }], + details: { toolName, result: output.result }, + structuredContent + }; + } + + const outputPath = await writeFullOutput(toolCallId, text); + const notice = `\n\n[Output truncated to ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}). Full output saved to: ${outputPath}]`; + + return { + content: [{ type: 'text', text: `${truncation.content}${notice}` }], + details: { + toolName, + truncation: { outputPath, totalBytes: truncation.totalBytes, totalLines: truncation.totalLines } + }, + structuredContent + }; +} diff --git a/projects/pi/src/schema.test.ts b/projects/pi/src/schema.test.ts new file mode 100644 index 0000000000..b3de6231e1 --- /dev/null +++ b/projects/pi/src/schema.test.ts @@ -0,0 +1,128 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it } from 'vitest'; +import type { Schema } from '@internals/tools'; +import { applyPiToolInputDefaults, createPiToolOutputSchema, createPiToolParameters } from './schema.js'; + +describe('Pi tool schema adapter', () => { + it('should wrap shared output schemas for structured Pi results', () => { + expect(createPiToolOutputSchema({ type: 'array', items: { type: 'string' } })).toEqual({ + type: 'object', + properties: { + status: { type: 'string', enum: ['complete', 'error'] }, + message: { type: 'string' }, + result: { type: 'array', items: { type: 'string' } } + }, + required: ['status'], + additionalProperties: false + }); + }); + + it('should create an empty object schema for tools without input', () => { + expect(createPiToolParameters()).toEqual({ type: 'object', properties: {}, additionalProperties: false }); + }); + + it('should preserve standard JSON Schema fields', () => { + const schema: Schema = { + type: 'object', + properties: { + names: { + type: 'array', + description: 'Names', + items: { type: 'string', enum: ['a', 'b'] }, + minItems: 1, + maxItems: 2 + }, + value: { oneOf: [{ type: 'string' }, { type: 'number' }] } + }, + patternProperties: { '^x-': { type: 'string' } }, + required: ['names'], + additionalProperties: false + }; + + expect(createPiToolParameters(schema)).toEqual({ + type: 'object', + properties: { + names: { + type: 'array', + description: 'Names', + items: { type: 'string', enum: ['a', 'b'] }, + minItems: 1, + maxItems: 2 + }, + value: { oneOf: [{ type: 'string' }, { type: 'number' }] } + }, + patternProperties: { '^x-': { type: 'string' } }, + required: ['names'], + additionalProperties: false + }); + }); + + it('should remove adapter-specific schema fields', () => { + const schema: Schema = { + type: 'object', + properties: { + cwd: { type: 'string', default: '/stale' }, + template: { type: 'string', defaultTemplate: '', service: true }, + mode: { type: 'string', enum: ['a'], enumNames: ['A'] } + } + }; + + expect(createPiToolParameters(schema)).toEqual({ + type: 'object', + properties: { + cwd: { type: 'string' }, + template: { type: 'string', default: '' }, + mode: { type: 'string', enum: ['a'] } + } + }); + }); + + it('should apply defaults and current working directory without mutating input', () => { + const schema: Schema = { + type: 'object', + properties: { + cwd: { type: 'string', default: '/stale' }, + format: { type: 'string', default: 'markdown' }, + nested: { + type: 'object', + properties: { enabled: { type: 'boolean', default: true } } + }, + values: { type: 'array', items: { type: 'object', properties: { count: { type: 'number', default: 1 } } } } + } + }; + const input = { values: [{}] }; + + expect(applyPiToolInputDefaults(input, schema, '/project')).toEqual({ + cwd: '/project', + format: 'markdown', + nested: { enabled: true }, + values: [{ count: 1 }] + }); + expect(input).toEqual({ values: [{}] }); + }); + + it('should preserve additional input properties', () => { + const schema: Schema = { type: 'object', additionalProperties: true }; + expect(applyPiToolInputDefaults({ custom: 'value' }, schema, '/project')).toEqual({ custom: 'value' }); + }); + + it('should preserve explicit values', () => { + const schema: Schema = { + type: 'object', + properties: { cwd: { type: 'string', default: '/stale' }, format: { type: 'string', default: 'markdown' } } + }; + expect(applyPiToolInputDefaults({ cwd: '/other', format: 'json' }, schema, '/project')).toEqual({ + cwd: '/other', + format: 'json' + }); + }); + + it('should copy input for tools without schemas', () => { + const input = { value: 'test' }; + const result = applyPiToolInputDefaults(input, undefined, '/project'); + expect(result).toEqual(input); + expect(result).not.toBe(input); + }); +}); diff --git a/projects/pi/src/schema.ts b/projects/pi/src/schema.ts new file mode 100644 index 0000000000..adcabec9ec --- /dev/null +++ b/projects/pi/src/schema.ts @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import type { Schema, ToolOutput } from '@internals/tools'; +import { Type, type TUnsafe } from 'typebox'; + +type PiToolInput = Record; +type SchemaEntry = [string, unknown]; + +interface ApplyDefaultOptions { + value: unknown; + schema: Schema; + cwd: string; + propertyName?: string; +} + +function getDefinedEntries(entries: SchemaEntry[]): SchemaEntry[] { + return entries.filter((entry): entry is SchemaEntry => entry[1] !== undefined); +} + +function sanitizeProperties(properties: Schema['properties']): Record | undefined { + if (!properties) return undefined; + return Object.fromEntries( + Object.entries(properties).map(([propertyName, propertySchema]) => [ + propertyName, + sanitizeSchema(propertySchema, propertyName) + ]) + ); +} + +function sanitizeSchema(schema: Schema, propertyName?: string): Record { + const defaultValue = propertyName === 'cwd' ? undefined : (schema.default ?? schema.defaultTemplate); + return Object.fromEntries( + getDefinedEntries([ + ['type', schema.type], + ['description', schema.description], + ['default', defaultValue === undefined ? undefined : structuredClone(defaultValue)], + ['enum', schema.enum ? [...schema.enum] : undefined], + ['minItems', schema.minItems], + ['maxItems', schema.maxItems], + ['oneOf', schema.oneOf?.map(item => sanitizeSchema(item))], + ['properties', sanitizeProperties(schema.properties)], + ['patternProperties', sanitizeProperties(schema.patternProperties)], + ['additionalProperties', schema.additionalProperties], + ['items', schema.items ? sanitizeSchema(schema.items) : undefined], + ['required', schema.required ? [...schema.required] : undefined] + ]) + ); +} + +function applyObjectDefaults(value: unknown, schema: Schema, cwd: string): PiToolInput { + const input = typeof value === 'object' && value !== null && !Array.isArray(value) ? (value as PiToolInput) : {}; + const properties = Object.fromEntries( + Object.entries(schema.properties ?? {}).flatMap(([name, propertySchema]) => { + const propertyValue = applyValueDefaults({ value: input[name], schema: propertySchema, cwd, propertyName: name }); + return propertyValue === undefined ? [] : [[name, propertyValue]]; + }) + ); + return { ...input, ...properties }; +} + +function applyValueDefaults({ value, schema, cwd, propertyName }: ApplyDefaultOptions): unknown { + const defaultValue = propertyName === 'cwd' ? cwd : (schema.default ?? schema.defaultTemplate); + const resolvedValue = value ?? (defaultValue === undefined ? undefined : structuredClone(defaultValue)); + if (schema.type === 'object') return applyObjectDefaults(resolvedValue, schema, cwd); + if (schema.type === 'array' && schema.items && Array.isArray(resolvedValue)) { + return resolvedValue.map(item => applyValueDefaults({ value: item, schema: schema.items!, cwd })); + } + return resolvedValue; +} + +export function createPiToolParameters(schema?: Schema): TUnsafe { + const sanitized = schema ? sanitizeSchema(schema) : { type: 'object', properties: {}, additionalProperties: false }; + return Type.Unsafe(sanitized); +} + +export function createPiToolOutputSchema(schema?: Schema): TUnsafe { + return Type.Unsafe({ + type: 'object', + properties: { + status: { type: 'string', enum: ['complete', 'error'] }, + message: { type: 'string' }, + result: schema ? sanitizeSchema(schema) : {} + }, + required: ['status'], + additionalProperties: false + }); +} + +export function applyPiToolInputDefaults(input: PiToolInput, schema: Schema | undefined, cwd: string): PiToolInput { + if (!schema) return { ...input }; + return applyValueDefaults({ value: input, schema, cwd }) as PiToolInput; +} diff --git a/projects/pi/src/scripts/write-resources.ts b/projects/pi/src/scripts/write-resources.ts new file mode 100644 index 0000000000..c5624c4e26 --- /dev/null +++ b/projects/pi/src/scripts/write-resources.ts @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { mkdir, writeFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; +import { prompts, skills, writeSkillDirectory, type Prompt, type Skill } from '@internals/tools/skills'; + +const piToolsContext = ` +## Native Elements tools in Pi + +Use the native tools installed by \`@nvidia-elements/pi\` for Elements discovery and validation. Do not invoke the Elements CLI or configure MCP for capabilities listed here. + +When a project or global \`elements\` skill is also available, use its design guidance and these Pi-specific instructions for tool selection. + +- \`nvidia_elements_api_list\`: List components and attribute APIs. +- \`nvidia_elements_api_get\`: Get component or attribute documentation. +- \`nvidia_elements_examples_list\` and \`nvidia_elements_examples_get\`: Find and retrieve patterns and examples. +- \`nvidia_elements_api_imports_get\`: Determine ESM imports for a template. +- \`nvidia_elements_api_validate\`: Check HTML or JSON content and files. +- \`nvidia_elements_api_tokens_list\` and \`nvidia_elements_api_icons_list\`: Find design tokens and icons. +- \`nvidia_elements_packages_list\`, \`nvidia_elements_packages_get\`, and \`nvidia_elements_packages_changelogs_get\`: Inspect package integration and releases. +- \`nvidia_elements_project_validate\`: Check an Elements project. + +Use Pi's built-in file tools to read, edit, and write project files. Project creation, project setup, and playground publication are not exposed as native tools; use the Elements CLI only when one of those operations is explicitly needed. +`; + +const piToolNames = new Map([ + ['nve packages.changelogs.get', 'nvidia_elements_packages_changelogs_get'], + ['nve api.imports.get', 'nvidia_elements_api_imports_get'], + ['nve api.tokens.list', 'nvidia_elements_api_tokens_list'], + ['nve project.validate', 'nvidia_elements_project_validate'], + ['nve packages.list', 'nvidia_elements_packages_list'], + ['nve packages.get', 'nvidia_elements_packages_get'], + ['nve examples.list', 'nvidia_elements_examples_list'], + ['nve examples.get', 'nvidia_elements_examples_get'], + ['nve api.validate page.html', 'nvidia_elements_api_validate with paths: ["page.html"]'], + ['nve api.validate --stdin', 'nvidia_elements_api_validate with template content'], + ["nve api.validate 'src/**/*.html'", 'nvidia_elements_api_validate with paths: ["src/**/*.html"]'], + ['nve api.validate', 'nvidia_elements_api_validate'], + ['nve api.list', 'nvidia_elements_api_list'], + ['nve api.get', 'nvidia_elements_api_get'] +]); + +const piDoctorContext = [ + '# Elements Pi Doctor / Setup Check', + '', + 'Check the native Elements Pi integration:', + '', + '1. Call `nvidia_elements_api_list` to confirm that the extension tools are available.', + '2. Call `nvidia_elements_project_validate` for an application or library in the current working directory.', + '3. Confirm that `/skill:elements-pi` and the `/elements-*` workflow prompts are discoverable.', + '4. Report actionable project diagnostics. Do not inspect or configure MCP unless the user explicitly asks for a separate MCP integration.' +].join('\n'); + +function adaptContextForPi(context: string): string { + let adapted = context; + for (const [command, toolName] of piToolNames) adapted = adapted.replaceAll(command, toolName); + return adapted + .replaceAll('via the Elements MCP or Elements CLI', 'with the native Elements Pi tools') + .replaceAll('via the Elements MCP or the canonical CLI path', 'with the native Elements Pi tools') + .replaceAll(' and configure the MCP server', '') + .replaceAll('# or use the MCP Tool\nproject_setup', '# project setup is available through the Elements CLI in Pi'); +} + +function replaceToolsContextForPi(context: string): string { + const toolsHeading = '## Elements CLI, MCP & Context'; + const nextHeading = '## Authoring Guidelines & Frontend Tasks'; + const toolsStart = context.indexOf(toolsHeading); + const toolsEnd = context.indexOf(nextHeading, toolsStart + toolsHeading.length); + if (toolsStart === -1 || toolsEnd === -1) { + throw new Error('Elements skill tools context not found.'); + } + return `${context.slice(0, toolsStart)}${piToolsContext.trim()}\n\n${context.slice(toolsEnd)}`; +} + +function adaptSkillForPi(skill: Skill): Skill { + const skillMarkdown = skill.files['SKILL.md']; + if (!skillMarkdown) throw new Error('Elements skill must include SKILL.md.'); + if (!skill.files['references/doctor.md']) throw new Error('Elements skill must include its doctor reference.'); + + const name = 'elements-pi'; + const title = 'NVIDIA Elements in Pi (nve)'; + const description = skill.description.replace('Use this skill by default', 'Use this skill in Pi'); + const files = Object.fromEntries( + Object.entries(skill.files).map(([filePath, context]) => [filePath, adaptContextForPi(context)]) + ); + files['SKILL.md'] = adaptContextForPi(replaceToolsContextForPi(skillMarkdown)) + .replace(`name: ${JSON.stringify(skill.name)}`, `name: ${JSON.stringify(name)}`) + .replace(`description: ${JSON.stringify(skill.description)}`, `description: ${JSON.stringify(description)}`) + .replace(`title: ${JSON.stringify(skill.title)}`, `title: ${JSON.stringify(title)}`); + files['references/doctor.md'] = `${piDoctorContext}\n`; + return { ...skill, name, title, description, files }; +} + +function getPromptBody(prompt: Prompt): string { + if (prompt.name === 'doctor') return piDoctorContext; + return prompt + .handler({}) + .messages.map(message => message.content.text) + .join('\n\n'); +} + +function formatPromptMarkdown(prompt: Prompt): string { + const body = getPromptBody(prompt); + return `--- +description: ${JSON.stringify(prompt.description)} +argument-hint: "[request]" +--- + +${adaptContextForPi(body).trim()} + +User request: \${ARGUMENTS:-Apply this workflow to the current project.} +`; +} + +const elementsSkill = skills.find(skill => skill.name === 'elements'); +if (!elementsSkill) throw new Error('Elements skill not found.'); + +const skillOutputPath = resolve('dist/skills/elements-pi'); +const promptOutputPath = resolve('dist/prompts'); +await mkdir(promptOutputPath, { recursive: true }); +await Promise.all([ + writeSkillDirectory(skillOutputPath, adaptSkillForPi(elementsSkill)), + ...prompts.map(prompt => + writeFile(resolve(promptOutputPath, `elements-${prompt.name}.md`), formatPromptMarkdown(prompt), 'utf8') + ) +]); diff --git a/projects/pi/src/tools.test.ts b/projects/pi/src/tools.test.ts new file mode 100644 index 0000000000..32b66addd9 --- /dev/null +++ b/projects/pi/src/tools.test.ts @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it, vi } from 'vitest'; +import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent'; +import type { ManagedToolMethod, ToolOutput } from '@internals/tools'; +import { createPiToolDefinition, getPiTools, registerElementsTools } from './tools.js'; + +function createManagedTool( + handler: (input: Record) => Promise +): ManagedToolMethod { + const tool = handler as ManagedToolMethod; + tool.metadata = { + name: 'get', + title: 'API Get', + command: 'api.get', + toolName: 'api_get', + summary: 'Get API details.', + support: 0, + outputSchema: { type: 'object', properties: { ok: { type: 'boolean' } } }, + inputSchema: { + type: 'object', + properties: { + cwd: { type: 'string', default: '/stale' }, + format: { type: 'string', default: 'markdown' } + } + } + }; + return tool; +} + +const context = { cwd: '/project' } as ExtensionContext; + +describe('Elements Pi tools', () => { + it('should expose the exact namespaced catalog', () => { + expect(getPiTools().map(tool => `nvidia_elements_${tool.metadata.toolName}`)).toEqual([ + 'nvidia_elements_api_list', + 'nvidia_elements_api_get', + 'nvidia_elements_api_validate', + 'nvidia_elements_api_imports_get', + 'nvidia_elements_api_tokens_list', + 'nvidia_elements_api_icons_list', + 'nvidia_elements_examples_list', + 'nvidia_elements_examples_get', + 'nvidia_elements_project_validate', + 'nvidia_elements_packages_list', + 'nvidia_elements_packages_get', + 'nvidia_elements_packages_changelogs_get' + ]); + }); + + it('should create a namespaced definition with guidance', () => { + const definition = createPiToolDefinition(createManagedTool(async () => ({ status: 'complete' }))); + expect(definition.name).toBe('nvidia_elements_api_get'); + expect(definition.label).toBe('API Get'); + expect(definition.promptGuidelines).toContain( + 'Use nvidia_elements_api_get before authoring or changing any nve-* API usage.' + ); + expect(definition.outputSchema).toMatchObject({ + properties: { result: { type: 'object', properties: { ok: { type: 'boolean' } } } } + }); + expect(definition.annotations).toEqual({ + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, + openWorldHint: false + }); + }); + + it('should apply defaults and forward progress', async () => { + const handler = vi.fn(async (_input: Record) => ({ + status: 'complete' as const, + result: { ok: true } + })); + const definition = createPiToolDefinition(createManagedTool(handler)); + const onUpdate = vi.fn(); + const result = await definition.execute('call', {}, undefined, onUpdate, context); + const input = handler.mock.calls[0]?.[0]; + expect(input).toMatchObject({ cwd: '/project', format: 'markdown' }); + expect(input?.onProgress).toBeTypeOf('function'); + const onProgress = input?.onProgress; + if (typeof onProgress === 'function') onProgress('Loading'); + expect(onUpdate).toHaveBeenCalledWith({ + content: [{ type: 'text', text: 'Loading' }], + details: { toolName: 'nvidia_elements_api_get' } + }); + expect(result.details.result).toEqual({ ok: true }); + expect(result).toMatchObject({ structuredContent: { status: 'complete', result: { ok: true } } }); + }); + + it('should preserve explicit working directories', async () => { + const handler = vi.fn(async () => ({ status: 'complete' as const })); + const definition = createPiToolDefinition(createManagedTool(handler)); + await definition.execute('call', { cwd: '/other' }, undefined, undefined, context); + expect(handler).toHaveBeenCalledWith(expect.objectContaining({ cwd: '/other' })); + }); + + it('should translate managed tool errors into Pi errors', async () => { + const definition = createPiToolDefinition( + createManagedTool(async () => ({ status: 'error', message: 'Unknown component', result: { ok: false } })) + ); + await expect(definition.execute('call', {}, undefined, undefined, context)).rejects.toThrow('Unknown component'); + }); + + it('should identify project validation as reaching the package registry', () => { + const tool = createManagedTool(async () => ({ status: 'complete' })); + tool.metadata.toolName = 'project_validate'; + expect(createPiToolDefinition(tool).annotations.openWorldHint).toBe(true); + }); + + it('should register every supported tool', () => { + const registerTool = vi.fn(); + registerElementsTools({ registerTool } as unknown as ExtensionAPI); + expect(registerTool).toHaveBeenCalledTimes(12); + }); + + it('should warn and continue when registration fails', () => { + const registerTool = vi.fn(() => { + throw new Error('duplicate'); + }); + const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined); + registerElementsTools({ registerTool } as unknown as ExtensionAPI); + expect(warn).toHaveBeenCalledTimes(12); + expect(warn).toHaveBeenNthCalledWith(1, { + event: 'elements.tool.registration_failed', + toolName: 'api_list', + error: expect.any(Error) + }); + warn.mockRestore(); + }); +}); diff --git a/projects/pi/src/tools.ts b/projects/pi/src/tools.ts new file mode 100644 index 0000000000..a013563120 --- /dev/null +++ b/projects/pi/src/tools.ts @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import type { ExtensionAPI, ToolDefinition } from '@earendil-works/pi-coding-agent'; +import { tools, type ManagedToolMethod, type ToolOutput } from '@internals/tools'; +import type { TUnsafe } from 'typebox'; +import { piLogger } from './logging.js'; +import { renderProjectValidationResult, renderValidationResult } from './renderers.js'; +import { createElementsToolResult, getElementsToolError, type ElementsToolDetails } from './results.js'; +import { applyPiToolInputDefaults, createPiToolOutputSchema, createPiToolParameters } from './schema.js'; + +type PiToolInput = Record; +type PiToolDefinition = ToolDefinition, ElementsToolDetails> & { + outputSchema: TUnsafe; + annotations: NonNullable['metadata']['annotations']>; +}; + +const piToolNames = [ + 'api_list', + 'api_get', + 'api_validate', + 'api_imports_get', + 'api_tokens_list', + 'api_icons_list', + 'examples_list', + 'examples_get', + 'project_validate', + 'packages_list', + 'packages_get', + 'packages_changelogs_get' +] as const; + +const promptMetadata: Record> = { + api_get: { + promptSnippet: 'Look up NVIDIA Elements component and attribute APIs', + promptGuidelines: ['Use nvidia_elements_api_get before authoring or changing any nve-* API usage.'] + }, + api_validate: { + promptSnippet: 'Validate NVIDIA Elements HTML and JSON content', + promptGuidelines: ['Use nvidia_elements_api_validate after editing HTML that uses nve-* APIs.'] + }, + examples_list: { + promptSnippet: 'Browse NVIDIA Elements patterns and examples' + }, + examples_get: { + promptSnippet: 'Retrieve a known NVIDIA Elements example' + } +}; + +function getRenderer(toolName: string): Pick { + if (toolName === 'api_validate') return { renderResult: renderValidationResult }; + if (toolName === 'project_validate') return { renderResult: renderProjectValidationResult }; + return {}; +} + +export function getPiTools(): ManagedToolMethod[] { + const toolsByName = new Map(tools.map(tool => [tool.metadata.toolName, tool])); + return piToolNames.map(toolName => { + const tool = toolsByName.get(toolName); + if (!tool) throw new Error(`Elements tool not found: ${toolName}`); + return tool; + }); +} + +export function createPiToolDefinition(tool: ManagedToolMethod): PiToolDefinition { + const toolName = `nvidia_elements_${tool.metadata.toolName}`; + return { + name: toolName, + label: tool.metadata.title, + description: tool.metadata.description ?? tool.metadata.summary, + parameters: createPiToolParameters(tool.metadata.inputSchema), + outputSchema: createPiToolOutputSchema(tool.metadata.outputSchema), + annotations: { + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, + openWorldHint: tool.metadata.toolName === 'project_validate', + ...tool.metadata.annotations + }, + ...promptMetadata[tool.metadata.toolName], + ...getRenderer(tool.metadata.toolName), + async execute(toolCallId, params, _signal, onUpdate, ctx) { + const input = applyPiToolInputDefaults(params, tool.metadata.inputSchema, ctx.cwd); + if (onUpdate) { + input.onProgress = (message: string) => { + onUpdate({ content: [{ type: 'text', text: message }], details: { toolName } }); + }; + } + const output = await tool(input); + if (output.status === 'error') throw getElementsToolError(output); + return createElementsToolResult(toolCallId, toolName, output); + } + }; +} + +export function registerElementsTools(pi: ExtensionAPI): void { + getPiTools().forEach(tool => { + try { + pi.registerTool(createPiToolDefinition(tool)); + } catch (error) { + piLogger.warn({ + event: 'elements.tool.registration_failed', + toolName: tool.metadata.toolName, + error + }); + } + }); +} diff --git a/projects/pi/tsconfig.json b/projects/pi/tsconfig.json new file mode 100644 index 0000000000..475d436930 --- /dev/null +++ b/projects/pi/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "noUncheckedSideEffectImports": true, + "skipLibCheck": true, + "module": "esnext", + "target": "es2022", + "lib": ["es2022", "dom"], + "types": ["node"], + "typeRoots": ["./node_modules/@types"], + "declaration": true, + "emitDeclarationOnly": true, + "outDir": "dist/", + "rootDir": "./", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true + }, + "include": ["src/**/*.ts"] +} diff --git a/projects/pi/tsconfig.lib.json b/projects/pi/tsconfig.lib.json new file mode 100644 index 0000000000..c371734773 --- /dev/null +++ b/projects/pi/tsconfig.lib.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "./src" + }, + "exclude": ["**/*.test.ts", "src/scripts/**"] +} diff --git a/projects/pi/vite.config.ts b/projects/pi/vite.config.ts new file mode 100644 index 0000000000..1c9bfe9005 --- /dev/null +++ b/projects/pi/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite'; +import { libraryNodeBuildConfig } from '@internals/vite'; + +export default defineConfig(() => { + const output = libraryNodeBuildConfig.build?.rolldownOptions?.output?.[0]; + if (output) output.preserveModules = false; + return libraryNodeBuildConfig; +}); diff --git a/projects/pi/vitest.config.ts b/projects/pi/vitest.config.ts new file mode 100644 index 0000000000..86cf91121c --- /dev/null +++ b/projects/pi/vitest.config.ts @@ -0,0 +1,18 @@ +import { mergeConfig } from 'vitest/config'; +import { libraryNodeTestConfig } from '@internals/vite/configs/test.node.js'; + +export default mergeConfig(libraryNodeTestConfig, { + root: import.meta.dirname, + test: { + include: ['./src/**/*.test.ts'], + coverage: { + exclude: ['src/scripts/**'], + thresholds: { + lines: 90, + branches: 90, + functions: 90, + statements: 90 + } + } + } +}); diff --git a/projects/site/public/static/images/integrations/nextjs.svg b/projects/site/public/static/images/integrations/nextjs.svg index e5514e92ed..66a6910b99 100644 --- a/projects/site/public/static/images/integrations/nextjs.svg +++ b/projects/site/public/static/images/integrations/nextjs.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/projects/site/public/static/images/integrations/pi.svg b/projects/site/public/static/images/integrations/pi.svg new file mode 100644 index 0000000000..10bd3e5790 --- /dev/null +++ b/projects/site/public/static/images/integrations/pi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/site/src/_11ty/layouts/common.js b/projects/site/src/_11ty/layouts/common.js index ae76333485..e7d0e118c3 100644 --- a/projects/site/src/_11ty/layouts/common.js +++ b/projects/site/src/_11ty/layouts/common.js @@ -164,6 +164,7 @@ export const renderDocsNav = data => /* html */ ` MCP Skills Lint + GitHub @@ -183,6 +184,7 @@ export const renderDocsNav = data => /* html */ ` MCP Apps NextJS Nuxt + Pi Preact React SolidJS diff --git a/projects/site/src/_11ty/shortcodes/svg-logo.js b/projects/site/src/_11ty/shortcodes/svg-logo.js index 3a28703cca..758173b5bd 100644 --- a/projects/site/src/_11ty/shortcodes/svg-logo.js +++ b/projects/site/src/_11ty/shortcodes/svg-logo.js @@ -12,28 +12,29 @@ export function svgLogoShortcode(name, size) { } const svgs = { - gitlab: ``, - figma: ``, - slack: ``, - chrome: ``, - claude: ``, - codex: ``, - cursor: ``, - eleventy: ``, - javascript: ``, - angular: ``, - vue: ``, - react: ``, - lit: ``, - preact: ``, - solidjs: ``, - svelte: ``, - nextjs: ``, - nuxt: ``, - typescript: ``, - go: ``, - htmx: ``, - hugo: ``, - sphinx: ``, - w3c: `` + gitlab: ``, + figma: ``, + slack: ``, + chrome: ``, + claude: ``, + codex: ``, + cursor: ``, + eleventy: ``, + javascript: ``, + angular: ``, + vue: ``, + react: ``, + lit: ``, + preact: ``, + sphinx: ``, + solidjs: ``, + svelte: ``, + nextjs: ``, + nuxt: ``, + pi: ``, + typescript: ``, + go: ``, + htmx: ``, + hugo: ``, + w3c: `` }; diff --git a/projects/site/src/docs/changelog/index.11tydata.js b/projects/site/src/docs/changelog/index.11tydata.js index c4fefcb702..0d69e3ddd3 100644 --- a/projects/site/src/docs/changelog/index.11tydata.js +++ b/projects/site/src/docs/changelog/index.11tydata.js @@ -14,6 +14,7 @@ const labsCli = projects.find(p => p.name === '@nvidia-elements/cli'); const labsLint = projects.find(p => p.name === '@nvidia-elements/lint'); const labsForms = projects.find(p => p.name === '@nvidia-elements/forms'); const labsMarkdown = projects.find(p => p.name === '@nvidia-elements/markdown'); +const pi = projects.find(p => p.name === '@nvidia-elements/pi'); // https://www.11ty.dev/docs/data-js/ export default [ @@ -86,5 +87,12 @@ export default [ version: labsMarkdown?.version, changelog: labsMarkdown?.changelog, description: labsMarkdown?.description + }, + { + title: '@nvidia-elements/pi', + permalink: '/pi/', + version: pi?.version, + changelog: pi?.changelog, + description: pi?.description } ]; diff --git a/projects/site/src/docs/integrations/pi.md b/projects/site/src/docs/integrations/pi.md new file mode 100644 index 0000000000..b3d1b25115 --- /dev/null +++ b/projects/site/src/docs/integrations/pi.md @@ -0,0 +1,80 @@ +--- +{ + title: 'Pi Agent', + description: 'Install native NVIDIA Elements tools and guidance for Pi Agents.', + layout: 'docs.11ty.js' +} +--- + +# {{ title }} + +[`@nvidia-elements/pi`](https://www.npmjs.com/package/@nvidia-elements/pi) gives [Pi](https://pi.dev) agents native access to Elements API documentation, examples, design tokens, icons, package information, project checks, and template validation. Pi can also use our Skills and CLI directly without requiring the extension. + +## Install + +Install the package globally for every Pi project: + +```shell +pi install npm:@nvidia-elements/pi +``` + +Install it only for the current project: + +```shell +pi install -l npm:@nvidia-elements/pi +``` + +Pi loads the extension, the Pi-specific `elements-pi` skill, and workflow prompts as native package resources. The skill can coexist with a project or global `elements` skill. + +## Use + +Ask Pi to create, edit, review, or debug an Elements interface. The agent can look up `nve-*` APIs and examples before authoring HTML, then check the result with `nvidia_elements_api_validate`. + +Pi exposes the Elements tools directly and makes them available to `codemode` scripts. `codemode` calls receive `{ status, message, result }`; tools with a `format` option can return structured data with `format: "json"`. + +Use the skill command to load the complete Elements workflow explicitly: + +```shell +/skill:elements-pi +``` + +You do not need MCP configuration or a separate CLI process. Use the [Elements CLI](/docs/cli/) when you need interactive shell commands, project creation, project setup, or MCP integrations. + +### Use workflow prompts + +The package provides these prompt-template commands: + +- `/elements-artifact`: Create a standalone Elements HTML artifact. +- `/elements-doctor`: Check an Elements development setup. +- `/elements-create-project`: Create an Elements starter project. +- `/elements-migrate`: Migrate deprecated Elements packages and APIs. + +Add an optional request after a command, such as `/elements-artifact create a settings page`. + +### Manage automatic validation + +Automatic validation runs by default after Pi edits supported HTML files. Turn it off when starting Pi: + +```shell +pi --no-elements-auto-validate +``` + +You can manage it for the current session: + +```shell +/elements-auto-validate off +/elements-auto-validate on +/elements-auto-validate status +``` + +When enabled, the extension checks `.html` and `.htm` files after successful Pi `edit` and `write` calls. It appends the validation summary and diagnostics to the tool result, including the parent result when `codemode` calls either tool. + +## Manage + +```shell +pi update npm:@nvidia-elements/pi +pi remove npm:@nvidia-elements/pi +pi config +``` + +Pi extensions run with your system permissions. Review package sources before installation and use Pi project trust for project-local packages and resources. diff --git a/projects/site/src/index.11tydata.js b/projects/site/src/index.11tydata.js index a0e24ab56d..e41c8fc4d7 100644 --- a/projects/site/src/index.11tydata.js +++ b/projects/site/src/index.11tydata.js @@ -211,6 +211,14 @@ const integrations = { documentation: 'https://nuxt.com/', playgroundURL: null }, + pi: { + href: '/docs/integrations/pi/', + icon: 'pi.svg', + title: 'Pi', + logo: 'pi', + description: 'Give Pi agents native Elements tools and guidance.', + documentation: 'https://pi.dev' + }, preact: { href: '/docs/integrations/preact/', icon: 'preact.svg', diff --git a/projects/site/src/index.md b/projects/site/src/index.md index 795d6af3ae..dd4a939c35 100644 --- a/projects/site/src/index.md +++ b/projects/site/src/index.md @@ -69,13 +69,14 @@
Install
CLI
MCP
-
{% svg-logo 'cursor' %}Cursor
-
{% svg-logo 'codex' %}Codex
-
{% svg-logo 'claude' %}Claude
GitHub
npm
SKILL.md
DESIGN.md
+
{% svg-logo 'pi' %}Pi
+
{% svg-logo 'cursor' %}Cursor
+
{% svg-logo 'codex' %}Codex
+
{% svg-logo 'claude' %}Claude
diff --git a/projects/site/src/index.test.lighthouse.ts b/projects/site/src/index.test.lighthouse.ts index ae73885c51..cae435f8d7 100644 --- a/projects/site/src/index.test.lighthouse.ts +++ b/projects/site/src/index.test.lighthouse.ts @@ -109,7 +109,7 @@ describe('lighthouse', { concurrent: false }, () => { expect(scores.accessibility).toBeGreaterThanOrEqual(100); expect(scores.bestPractices).toBeGreaterThanOrEqual(96); expect(scores.seo).toBeGreaterThanOrEqual(100); - expect(scores.payload.js).toBeLessThan(160); + expect(scores.payload.js).toBeLessThan(161); expect(scores.payload.js).toBeGreaterThanOrEqual(1); expect(scores.payload.css).toBe(0); // css should be 0 as we inline all css }); @@ -131,7 +131,7 @@ describe('lighthouse', { concurrent: false }, () => { expect(scores.accessibility).toBeGreaterThanOrEqual(90); expect(scores.bestPractices).toBeGreaterThanOrEqual(90); expect(scores.seo).toBeGreaterThanOrEqual(90); - expect(scores.payload.js).toBeLessThan(101); + expect(scores.payload.js).toBeLessThan(103); expect(scores.payload.js).toBeGreaterThanOrEqual(1); expect(scores.payload.css).toBeLessThan(0.5); }); @@ -142,7 +142,7 @@ describe('lighthouse', { concurrent: false }, () => { expect(scores.accessibility).toBeGreaterThanOrEqual(95); expect(scores.bestPractices).toBeGreaterThanOrEqual(90); expect(scores.seo).toBeGreaterThanOrEqual(90); - expect(scores.payload.js).toBeLessThan(167); + expect(scores.payload.js).toBeLessThan(169); expect(scores.payload.js).toBeGreaterThanOrEqual(1); expect(scores.payload.css).toBe(0); }); @@ -153,7 +153,7 @@ describe('lighthouse', { concurrent: false }, () => { expect(scores.accessibility).toBeGreaterThanOrEqual(100); expect(scores.bestPractices).toBeGreaterThanOrEqual(90); expect(scores.seo).toBeGreaterThanOrEqual(90); - expect(scores.payload.js).toBeLessThan(155); + expect(scores.payload.js).toBeLessThan(156); expect(scores.payload.js).toBeGreaterThanOrEqual(1); expect(scores.payload.css).toBe(0); }); @@ -164,7 +164,7 @@ describe('lighthouse', { concurrent: false }, () => { expect(scores.accessibility).toBeGreaterThanOrEqual(100); expect(scores.bestPractices).toBeGreaterThanOrEqual(90); expect(scores.seo).toBeGreaterThanOrEqual(90); - expect(scores.payload.js).toBeLessThan(155); + expect(scores.payload.js).toBeLessThan(157); expect(scores.payload.js).toBeGreaterThanOrEqual(1); expect(scores.payload.css).toBe(0); });