pmx-canvas 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/Readme.md +865 -0
  4. package/dist/canvas/global.css +3173 -0
  5. package/dist/canvas/index.js +183 -0
  6. package/dist/json-render/index.css +2 -0
  7. package/dist/json-render/index.js +389 -0
  8. package/dist/types/cli/agent.d.ts +13 -0
  9. package/dist/types/cli/index.d.ts +2 -0
  10. package/dist/types/cli/watch.d.ts +5 -0
  11. package/dist/types/client/App.d.ts +1 -0
  12. package/dist/types/client/canvas/AttentionHistory.d.ts +1 -0
  13. package/dist/types/client/canvas/AttentionToast.d.ts +1 -0
  14. package/dist/types/client/canvas/CanvasNode.d.ts +8 -0
  15. package/dist/types/client/canvas/CanvasViewport.d.ts +8 -0
  16. package/dist/types/client/canvas/CommandPalette.d.ts +4 -0
  17. package/dist/types/client/canvas/ContextMenu.d.ts +24 -0
  18. package/dist/types/client/canvas/ContextPinBar.d.ts +1 -0
  19. package/dist/types/client/canvas/ContextPinHud.d.ts +1 -0
  20. package/dist/types/client/canvas/DockedNode.d.ts +4 -0
  21. package/dist/types/client/canvas/EdgeLayer.d.ts +8 -0
  22. package/dist/types/client/canvas/ExpandedNodeOverlay.d.ts +1 -0
  23. package/dist/types/client/canvas/FocusFieldLayer.d.ts +1 -0
  24. package/dist/types/client/canvas/Minimap.d.ts +23 -0
  25. package/dist/types/client/canvas/SelectionBar.d.ts +1 -0
  26. package/dist/types/client/canvas/ShortcutOverlay.d.ts +3 -0
  27. package/dist/types/client/canvas/SnapshotPanel.d.ts +7 -0
  28. package/dist/types/client/canvas/snap-guides.d.ts +23 -0
  29. package/dist/types/client/canvas/use-node-drag.d.ts +15 -0
  30. package/dist/types/client/canvas/use-node-resize.d.ts +15 -0
  31. package/dist/types/client/canvas/use-pan-zoom.d.ts +16 -0
  32. package/dist/types/client/ext-app/bridge.d.ts +161 -0
  33. package/dist/types/client/icons.d.ts +70 -0
  34. package/dist/types/client/index.d.ts +1 -0
  35. package/dist/types/client/nodes/ContextNode.d.ts +34 -0
  36. package/dist/types/client/nodes/ExtAppFrame.d.ts +18 -0
  37. package/dist/types/client/nodes/FileNode.d.ts +5 -0
  38. package/dist/types/client/nodes/GroupNode.d.ts +6 -0
  39. package/dist/types/client/nodes/ImageNode.d.ts +10 -0
  40. package/dist/types/client/nodes/InlineFormatBar.d.ts +7 -0
  41. package/dist/types/client/nodes/InlineMarkdownEditor.d.ts +14 -0
  42. package/dist/types/client/nodes/LedgerNode.d.ts +4 -0
  43. package/dist/types/client/nodes/MarkdownNode.d.ts +6 -0
  44. package/dist/types/client/nodes/McpAppNode.d.ts +4 -0
  45. package/dist/types/client/nodes/MdFormatBar.d.ts +8 -0
  46. package/dist/types/client/nodes/PromptNode.d.ts +5 -0
  47. package/dist/types/client/nodes/ResponseNode.d.ts +5 -0
  48. package/dist/types/client/nodes/StatusNode.d.ts +4 -0
  49. package/dist/types/client/nodes/StatusSummary.d.ts +4 -0
  50. package/dist/types/client/nodes/TraceNode.d.ts +4 -0
  51. package/dist/types/client/nodes/WebpageNode.d.ts +5 -0
  52. package/dist/types/client/nodes/image-warnings.d.ts +6 -0
  53. package/dist/types/client/nodes/inline-editor-commands.d.ts +11 -0
  54. package/dist/types/client/nodes/md-format.d.ts +25 -0
  55. package/dist/types/client/state/attention-bridge.d.ts +3 -0
  56. package/dist/types/client/state/attention-store.d.ts +25 -0
  57. package/dist/types/client/state/canvas-store.d.ts +74 -0
  58. package/dist/types/client/state/intent-bridge.d.ts +158 -0
  59. package/dist/types/client/state/sse-bridge.d.ts +5 -0
  60. package/dist/types/client/theme/tokens.d.ts +27 -0
  61. package/dist/types/client/types.d.ts +40 -0
  62. package/dist/types/client/utils/ext-app-tool-result.d.ts +1 -0
  63. package/dist/types/client/utils/placement.d.ts +1 -0
  64. package/dist/types/client/utils/platform.d.ts +2 -0
  65. package/dist/types/json-render/catalog.d.ts +815 -0
  66. package/dist/types/json-render/charts/components.d.ts +54 -0
  67. package/dist/types/json-render/charts/definitions.d.ts +103 -0
  68. package/dist/types/json-render/charts/extra-components.d.ts +58 -0
  69. package/dist/types/json-render/charts/extra-definitions.d.ts +181 -0
  70. package/dist/types/json-render/renderer/index.d.ts +16 -0
  71. package/dist/types/json-render/schema.d.ts +46 -0
  72. package/dist/types/json-render/server.d.ts +55 -0
  73. package/dist/types/mcp/server.d.ts +22 -0
  74. package/dist/types/server/agent-context.d.ts +21 -0
  75. package/dist/types/server/artifact-paths.d.ts +3 -0
  76. package/dist/types/server/canvas-operations.d.ts +154 -0
  77. package/dist/types/server/canvas-provenance.d.ts +13 -0
  78. package/dist/types/server/canvas-schema.d.ts +49 -0
  79. package/dist/types/server/canvas-serialization.d.ts +25 -0
  80. package/dist/types/server/canvas-state.d.ts +174 -0
  81. package/dist/types/server/canvas-validation.d.ts +33 -0
  82. package/dist/types/server/chart-template.d.ts +29 -0
  83. package/dist/types/server/code-graph.d.ts +67 -0
  84. package/dist/types/server/context-cards.d.ts +24 -0
  85. package/dist/types/server/diagram-presets.d.ts +28 -0
  86. package/dist/types/server/ext-app-call-registry.d.ts +16 -0
  87. package/dist/types/server/ext-app-tool-result.d.ts +1 -0
  88. package/dist/types/server/file-watcher.d.ts +16 -0
  89. package/dist/types/server/index.d.ts +243 -0
  90. package/dist/types/server/mcp-app-candidate.d.ts +25 -0
  91. package/dist/types/server/mcp-app-host.d.ts +65 -0
  92. package/dist/types/server/mcp-app-runtime.d.ts +47 -0
  93. package/dist/types/server/mutation-history.d.ts +105 -0
  94. package/dist/types/server/placement.d.ts +37 -0
  95. package/dist/types/server/server.d.ts +103 -0
  96. package/dist/types/server/spatial-analysis.d.ts +87 -0
  97. package/dist/types/server/trace-manager.d.ts +48 -0
  98. package/dist/types/server/web-artifacts.d.ts +50 -0
  99. package/dist/types/server/webpage-node.d.ts +25 -0
  100. package/dist/types/shared/auto-arrange.d.ts +29 -0
  101. package/dist/types/shared/ext-app-tool-result.d.ts +9 -0
  102. package/dist/types/shared/placement.d.ts +26 -0
  103. package/dist/types/shared/semantic-attention.d.ts +97 -0
  104. package/package.json +109 -0
  105. package/skills/data-analysis/SKILL.md +324 -0
  106. package/skills/doc-coauthoring/SKILL.md +375 -0
  107. package/skills/frontend-design/SKILL.md +45 -0
  108. package/skills/json-render-codegen/SKILL.md +112 -0
  109. package/skills/json-render-core/SKILL.md +265 -0
  110. package/skills/json-render-ink/SKILL.md +273 -0
  111. package/skills/json-render-mcp/SKILL.md +132 -0
  112. package/skills/json-render-react/SKILL.md +264 -0
  113. package/skills/json-render-shadcn/SKILL.md +159 -0
  114. package/skills/playwright-cli/SKILL.md +67 -0
  115. package/skills/pmx-canvas/SKILL.md +668 -0
  116. package/skills/pmx-canvas/evals/evals.json +186 -0
  117. package/skills/pmx-canvas-testing/SKILL.md +78 -0
  118. package/skills/published-consumer-e2e/SKILL.md +43 -0
  119. package/skills/published-consumer-e2e/scripts/run-published-consumer-e2e.sh +241 -0
  120. package/skills/web-artifacts-builder/SKILL.md +80 -0
  121. package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +167 -0
  122. package/skills/web-artifacts-builder/scripts/init-artifact.sh +425 -0
  123. package/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  124. package/skills/web-design-guidelines/SKILL.md +39 -0
  125. package/src/cli/agent.ts +2144 -0
  126. package/src/cli/index.ts +622 -0
  127. package/src/cli/watch.ts +88 -0
  128. package/src/client/App.tsx +507 -0
  129. package/src/client/canvas/AttentionHistory.tsx +81 -0
  130. package/src/client/canvas/AttentionToast.tsx +19 -0
  131. package/src/client/canvas/CanvasNode.tsx +363 -0
  132. package/src/client/canvas/CanvasViewport.tsx +590 -0
  133. package/src/client/canvas/CommandPalette.tsx +302 -0
  134. package/src/client/canvas/ContextMenu.tsx +601 -0
  135. package/src/client/canvas/ContextPinBar.tsx +25 -0
  136. package/src/client/canvas/ContextPinHud.tsx +22 -0
  137. package/src/client/canvas/DockedNode.tsx +66 -0
  138. package/src/client/canvas/EdgeLayer.tsx +280 -0
  139. package/src/client/canvas/ExpandedNodeOverlay.tsx +260 -0
  140. package/src/client/canvas/FocusFieldLayer.tsx +107 -0
  141. package/src/client/canvas/Minimap.tsx +301 -0
  142. package/src/client/canvas/SelectionBar.tsx +69 -0
  143. package/src/client/canvas/ShortcutOverlay.tsx +69 -0
  144. package/src/client/canvas/SnapshotPanel.tsx +236 -0
  145. package/src/client/canvas/snap-guides.ts +170 -0
  146. package/src/client/canvas/use-node-drag.ts +51 -0
  147. package/src/client/canvas/use-node-resize.ts +59 -0
  148. package/src/client/canvas/use-pan-zoom.ts +191 -0
  149. package/src/client/ext-app/bridge.ts +542 -0
  150. package/src/client/icons.tsx +424 -0
  151. package/src/client/index.tsx +7 -0
  152. package/src/client/nodes/ContextNode.tsx +412 -0
  153. package/src/client/nodes/ExtAppFrame.tsx +509 -0
  154. package/src/client/nodes/FileNode.tsx +256 -0
  155. package/src/client/nodes/GroupNode.tsx +39 -0
  156. package/src/client/nodes/ImageNode.tsx +160 -0
  157. package/src/client/nodes/InlineFormatBar.tsx +169 -0
  158. package/src/client/nodes/InlineMarkdownEditor.tsx +123 -0
  159. package/src/client/nodes/LedgerNode.tsx +37 -0
  160. package/src/client/nodes/MarkdownNode.tsx +359 -0
  161. package/src/client/nodes/McpAppNode.tsx +85 -0
  162. package/src/client/nodes/MdFormatBar.tsx +109 -0
  163. package/src/client/nodes/PromptNode.tsx +597 -0
  164. package/src/client/nodes/ResponseNode.tsx +153 -0
  165. package/src/client/nodes/StatusNode.tsx +84 -0
  166. package/src/client/nodes/StatusSummary.tsx +38 -0
  167. package/src/client/nodes/TraceNode.tsx +120 -0
  168. package/src/client/nodes/WebpageNode.tsx +288 -0
  169. package/src/client/nodes/image-warnings.ts +95 -0
  170. package/src/client/nodes/inline-editor-commands.ts +37 -0
  171. package/src/client/nodes/md-format.ts +206 -0
  172. package/src/client/state/attention-bridge.ts +328 -0
  173. package/src/client/state/attention-store.ts +73 -0
  174. package/src/client/state/canvas-store.ts +631 -0
  175. package/src/client/state/intent-bridge.ts +315 -0
  176. package/src/client/state/sse-bridge.ts +965 -0
  177. package/src/client/theme/global.css +3173 -0
  178. package/src/client/theme/tokens.ts +72 -0
  179. package/src/client/types-shims.d.ts +5 -0
  180. package/src/client/types.ts +81 -0
  181. package/src/client/utils/ext-app-tool-result.ts +4 -0
  182. package/src/client/utils/placement.ts +4 -0
  183. package/src/client/utils/platform.ts +2 -0
  184. package/src/json-render/catalog.ts +256 -0
  185. package/src/json-render/charts/components.tsx +198 -0
  186. package/src/json-render/charts/definitions.ts +81 -0
  187. package/src/json-render/charts/extra-components.tsx +267 -0
  188. package/src/json-render/charts/extra-definitions.ts +145 -0
  189. package/src/json-render/renderer/index.css +174 -0
  190. package/src/json-render/renderer/index.tsx +86 -0
  191. package/src/json-render/schema.ts +62 -0
  192. package/src/json-render/server.ts +597 -0
  193. package/src/mcp/server.ts +1377 -0
  194. package/src/server/agent-context.ts +242 -0
  195. package/src/server/artifact-paths.ts +17 -0
  196. package/src/server/canvas-operations.ts +1279 -0
  197. package/src/server/canvas-provenance.ts +243 -0
  198. package/src/server/canvas-schema.ts +432 -0
  199. package/src/server/canvas-serialization.ts +95 -0
  200. package/src/server/canvas-state.ts +1134 -0
  201. package/src/server/canvas-validation.ts +114 -0
  202. package/src/server/chart-template.ts +449 -0
  203. package/src/server/code-graph.ts +370 -0
  204. package/src/server/context-cards.ts +31 -0
  205. package/src/server/diagram-presets.ts +71 -0
  206. package/src/server/ext-app-call-registry.ts +77 -0
  207. package/src/server/ext-app-tool-result.ts +4 -0
  208. package/src/server/file-watcher.ts +121 -0
  209. package/src/server/index.ts +647 -0
  210. package/src/server/mcp-app-candidate.ts +174 -0
  211. package/src/server/mcp-app-host.ts +814 -0
  212. package/src/server/mcp-app-runtime.ts +459 -0
  213. package/src/server/mutation-history.ts +350 -0
  214. package/src/server/placement.ts +125 -0
  215. package/src/server/server.ts +3846 -0
  216. package/src/server/spatial-analysis.ts +356 -0
  217. package/src/server/trace-manager.ts +333 -0
  218. package/src/server/web-artifacts/scripts/bundle-artifact.sh +167 -0
  219. package/src/server/web-artifacts/scripts/init-artifact.sh +426 -0
  220. package/src/server/web-artifacts/scripts/shadcn-components.tar.gz +0 -0
  221. package/src/server/web-artifacts.ts +442 -0
  222. package/src/server/webpage-node.ts +328 -0
  223. package/src/shared/auto-arrange.ts +439 -0
  224. package/src/shared/ext-app-tool-result.ts +76 -0
  225. package/src/shared/placement.ts +81 -0
  226. package/src/shared/semantic-attention.ts +598 -0
@@ -0,0 +1,167 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ PNPM_VERSION="10.33.0"
5
+ ALLOWED_BUILD_PACKAGES=("@parcel/watcher" "@swc/core" "lmdb" "msgpackr-extract")
6
+
7
+ function configure_pnpm() {
8
+ if command -v pnpm >/dev/null 2>&1; then
9
+ PNPM_CMD=("pnpm")
10
+ echo "✅ Using pnpm from PATH"
11
+ return 0
12
+ fi
13
+
14
+ if command -v bun >/dev/null 2>&1; then
15
+ PNPM_CMD=("bun" "x" "pnpm@${PNPM_VERSION}")
16
+ echo "✅ Using pnpm via bun x"
17
+ return 0
18
+ fi
19
+
20
+ if command -v npm >/dev/null 2>&1; then
21
+ echo "📦 pnpm not found. Installing pnpm..."
22
+ npm install -g "pnpm@${PNPM_VERSION}"
23
+ PNPM_CMD=("pnpm")
24
+ echo "✅ Using pnpm installed via npm"
25
+ return 0
26
+ fi
27
+
28
+ echo "❌ Error: pnpm is unavailable and no Bun or npm fallback was found." >&2
29
+ return 1
30
+ }
31
+
32
+ function run_pnpm() {
33
+ "${PNPM_CMD[@]}" "$@"
34
+ }
35
+
36
+ function run_local_binary() {
37
+ local binary_name="$1"
38
+ shift
39
+ local binary_path="./node_modules/.bin/$binary_name"
40
+ if [ ! -x "$binary_path" ]; then
41
+ echo "❌ Error: Expected local binary at $binary_path" >&2
42
+ exit 1
43
+ fi
44
+ "$binary_path" "$@"
45
+ }
46
+
47
+ function replay_filtered_stderr() {
48
+ local stderr_file="$1"
49
+ while IFS= read -r line; do
50
+ if [[ "$line" == *"/dev/tty"* ]]; then
51
+ continue
52
+ fi
53
+ echo "$line" >&2
54
+ done < "$stderr_file"
55
+ }
56
+
57
+ function run_with_filtered_stderr() {
58
+ local stderr_file
59
+ stderr_file="$(mktemp)"
60
+ if "$@" 2>"$stderr_file"; then
61
+ replay_filtered_stderr "$stderr_file"
62
+ rm -f "$stderr_file"
63
+ return 0
64
+ fi
65
+
66
+ local status=$?
67
+ replay_filtered_stderr "$stderr_file"
68
+ rm -f "$stderr_file"
69
+ return "$status"
70
+ }
71
+
72
+ function run_pnpm_quiet() {
73
+ run_with_filtered_stderr "${PNPM_CMD[@]}" --silent "$@"
74
+ }
75
+
76
+ function run_pnpm_allow_build() {
77
+ local allow_build_args=()
78
+ local package_name
79
+ for package_name in "${ALLOWED_BUILD_PACKAGES[@]}"; do
80
+ allow_build_args+=(--allow-build="$package_name")
81
+ done
82
+ run_with_filtered_stderr "${PNPM_CMD[@]}" --silent "$@" "${allow_build_args[@]}"
83
+ }
84
+
85
+ function package_has_dependency() {
86
+ local package_name="$1"
87
+ node -e '
88
+ const fs = require("fs");
89
+ const packageName = process.argv[1];
90
+ const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
91
+ const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
92
+ process.exit(deps[packageName] ? 0 : 1);
93
+ ' "$package_name"
94
+ }
95
+
96
+ function ensure_bundle_dependencies() {
97
+ local packages=(
98
+ "parcel"
99
+ "@parcel/config-default"
100
+ "parcel-resolver-tspaths"
101
+ "html-inline"
102
+ )
103
+
104
+ for package_name in "${packages[@]}"; do
105
+ if ! package_has_dependency "$package_name"; then
106
+ echo "📦 Installing missing bundling dependencies..."
107
+ run_pnpm_allow_build add -D parcel @parcel/config-default parcel-resolver-tspaths html-inline
108
+ return 0
109
+ fi
110
+ done
111
+
112
+ echo "✅ Reusing existing bundling dependencies"
113
+ }
114
+
115
+ declare -a PNPM_CMD
116
+ configure_pnpm
117
+
118
+ echo "📦 Bundling React app to single HTML artifact..."
119
+
120
+ # Check if we're in a project directory
121
+ if [ ! -f "package.json" ]; then
122
+ echo "❌ Error: No package.json found. Run this script from your project root."
123
+ exit 1
124
+ fi
125
+
126
+ # Check if index.html exists
127
+ if [ ! -f "index.html" ]; then
128
+ echo "❌ Error: No index.html found in project root."
129
+ echo " This script requires an index.html entry point."
130
+ exit 1
131
+ fi
132
+
133
+ # Install bundling dependencies only when missing
134
+ ensure_bundle_dependencies
135
+
136
+ # Create Parcel config with tspaths resolver
137
+ if [ ! -f ".parcelrc" ]; then
138
+ echo "🔧 Creating Parcel configuration with path alias support..."
139
+ cat > .parcelrc << 'EOF'
140
+ {
141
+ "extends": "@parcel/config-default",
142
+ "resolvers": ["parcel-resolver-tspaths", "..."]
143
+ }
144
+ EOF
145
+ fi
146
+
147
+ # Clean previous build
148
+ echo "🧹 Cleaning previous build..."
149
+ rm -rf dist bundle.html
150
+
151
+ # Build with Parcel
152
+ echo "🔨 Building with Parcel..."
153
+ run_with_filtered_stderr run_local_binary parcel build index.html --dist-dir dist --no-source-maps --log-level error
154
+
155
+ # Inline everything into single HTML
156
+ echo "🎯 Inlining all assets into single HTML file..."
157
+ run_with_filtered_stderr run_local_binary html-inline dist/index.html > bundle.html
158
+
159
+ # Get file size
160
+ FILE_SIZE=$(du -h bundle.html | cut -f1)
161
+
162
+ echo ""
163
+ echo "✅ Bundle complete!"
164
+ echo "📄 Output: bundle.html ($FILE_SIZE)"
165
+ echo ""
166
+ echo "You can now open this single HTML file directly in a browser or share it in an artifact-capable client."
167
+ echo "To test locally: open bundle.html in your browser"
@@ -0,0 +1,425 @@
1
+ #!/bin/bash
2
+
3
+ set -euo pipefail
4
+
5
+ PNPM_VERSION="10.33.0"
6
+ ALLOWED_BUILD_PACKAGES=("@parcel/watcher" "@swc/core" "lmdb" "msgpackr-extract")
7
+
8
+ function detect_runtime_major() {
9
+ if command -v node >/dev/null 2>&1; then
10
+ local node_version
11
+ if node_version="$(node --version 2>/dev/null)"; then
12
+ local node_major="${node_version#v}"
13
+ node_major="${node_major%%.*}"
14
+ echo "$node_major|Node.js $node_version"
15
+ return 0
16
+ fi
17
+ fi
18
+
19
+ if command -v bun >/dev/null 2>&1; then
20
+ local bun_version
21
+ if bun_version="$(bun --version 2>/dev/null)"; then
22
+ echo "20|Bun $bun_version"
23
+ return 0
24
+ fi
25
+ fi
26
+
27
+ echo "❌ Error: Node.js 18+ or Bun is required to initialize a web artifact." >&2
28
+ return 1
29
+ }
30
+
31
+ function configure_pnpm() {
32
+ if command -v pnpm >/dev/null 2>&1; then
33
+ PNPM_CMD=("pnpm")
34
+ echo "✅ Using pnpm from PATH"
35
+ return 0
36
+ fi
37
+
38
+ if command -v bun >/dev/null 2>&1; then
39
+ PNPM_CMD=("bun" "x" "pnpm@${PNPM_VERSION}")
40
+ echo "✅ Using pnpm via bun x"
41
+ return 0
42
+ fi
43
+
44
+ if command -v npm >/dev/null 2>&1; then
45
+ echo "📦 pnpm not found. Installing pnpm..."
46
+ npm install -g "pnpm@${PNPM_VERSION}"
47
+ PNPM_CMD=("pnpm")
48
+ echo "✅ Using pnpm installed via npm"
49
+ return 0
50
+ fi
51
+
52
+ echo "❌ Error: pnpm is unavailable and no Bun or npm fallback was found." >&2
53
+ return 1
54
+ }
55
+
56
+ function run_pnpm() {
57
+ "${PNPM_CMD[@]}" "$@"
58
+ }
59
+
60
+ function replay_filtered_stderr() {
61
+ local stderr_file="$1"
62
+ while IFS= read -r line; do
63
+ if [[ "$line" == *"/dev/tty"* ]]; then
64
+ continue
65
+ fi
66
+ echo "$line" >&2
67
+ done < "$stderr_file"
68
+ }
69
+
70
+ function run_with_filtered_stderr() {
71
+ local stderr_file
72
+ stderr_file="$(mktemp)"
73
+ if "$@" 2>"$stderr_file"; then
74
+ replay_filtered_stderr "$stderr_file"
75
+ rm -f "$stderr_file"
76
+ return 0
77
+ fi
78
+
79
+ local status=$?
80
+ replay_filtered_stderr "$stderr_file"
81
+ rm -f "$stderr_file"
82
+ return "$status"
83
+ }
84
+
85
+ function run_pnpm_quiet() {
86
+ run_with_filtered_stderr "${PNPM_CMD[@]}" --silent "$@"
87
+ }
88
+
89
+ function run_pnpm_allow_build() {
90
+ local allow_build_args=()
91
+ local package_name
92
+ for package_name in "${ALLOWED_BUILD_PACKAGES[@]}"; do
93
+ allow_build_args+=(--allow-build="$package_name")
94
+ done
95
+ run_with_filtered_stderr "${PNPM_CMD[@]}" --silent "$@" "${allow_build_args[@]}"
96
+ }
97
+
98
+ RUNTIME_INFO="$(detect_runtime_major)"
99
+ NODE_VERSION="${RUNTIME_INFO%%|*}"
100
+ RUNTIME_LABEL="${RUNTIME_INFO#*|}"
101
+
102
+ echo "🔍 Detected runtime: $RUNTIME_LABEL"
103
+
104
+ if [ "$NODE_VERSION" -lt 18 ]; then
105
+ echo "❌ Error: Node.js 18 or higher is required"
106
+ echo " Current runtime: $RUNTIME_LABEL"
107
+ exit 1
108
+ fi
109
+
110
+ if [ "$NODE_VERSION" -ge 20 ]; then
111
+ VITE_VERSION="latest"
112
+ echo "✅ Using Vite latest (runtime equivalent to Node 20+)"
113
+ else
114
+ VITE_VERSION="5.4.11"
115
+ echo "✅ Using Vite $VITE_VERSION (Node 18 compatible)"
116
+ fi
117
+
118
+ # Detect OS and set sed syntax
119
+ if [[ "$OSTYPE" == "darwin"* ]]; then
120
+ SED_INPLACE="sed -i ''"
121
+ else
122
+ SED_INPLACE="sed -i"
123
+ fi
124
+
125
+ declare -a PNPM_CMD
126
+ configure_pnpm
127
+
128
+ # Check if project name is provided
129
+ if [ -z "$1" ]; then
130
+ echo "❌ Usage: ./init-artifact.sh <project-name>"
131
+ exit 1
132
+ fi
133
+
134
+ PROJECT_NAME="$1"
135
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
136
+ COMPONENTS_TARBALL="$SCRIPT_DIR/shadcn-components.tar.gz"
137
+
138
+ # Check if components tarball exists
139
+ if [ ! -f "$COMPONENTS_TARBALL" ]; then
140
+ echo "❌ Error: shadcn-components.tar.gz not found in script directory"
141
+ echo " Expected location: $COMPONENTS_TARBALL"
142
+ exit 1
143
+ fi
144
+
145
+ echo "🚀 Creating new React + Vite project: $PROJECT_NAME"
146
+
147
+ # Create new Vite project (always use latest create-vite, pin vite version later)
148
+ run_pnpm_quiet create vite "$PROJECT_NAME" --template react-ts --no-interactive
149
+
150
+ # Navigate into project directory
151
+ cd "$PROJECT_NAME"
152
+
153
+ node -e "
154
+ const fs = require('fs');
155
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
156
+ pkg.packageManager = 'pnpm@${PNPM_VERSION}';
157
+ fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
158
+ "
159
+
160
+ echo "🧹 Cleaning up Vite template..."
161
+ $SED_INPLACE '/<link rel="icon".*/d' index.html
162
+ $SED_INPLACE 's/<title>.*<\/title>/<title>'"$PROJECT_NAME"'<\/title>/' index.html
163
+
164
+ echo "📦 Installing base dependencies..."
165
+ run_pnpm_quiet install
166
+
167
+ # Pin Vite version for Node 18
168
+ if [ "$NODE_VERSION" -lt 20 ]; then
169
+ echo "📌 Pinning Vite to $VITE_VERSION for Node 18 compatibility..."
170
+ run_pnpm_allow_build add -D vite@"$VITE_VERSION"
171
+ fi
172
+
173
+ echo "📦 Installing Tailwind CSS and dependencies..."
174
+ run_pnpm_allow_build add -D tailwindcss@3.4.1 postcss @types/node tailwindcss-animate parcel @parcel/config-default parcel-resolver-tspaths html-inline
175
+ run_pnpm_quiet add class-variance-authority clsx tailwind-merge lucide-react next-themes
176
+
177
+ echo "⚙️ Creating Tailwind and PostCSS configuration..."
178
+ cat > .postcssrc.json << 'EOF'
179
+ {
180
+ "plugins": {
181
+ "tailwindcss": {}
182
+ }
183
+ }
184
+ EOF
185
+
186
+ echo "📝 Configuring Tailwind with shadcn theme..."
187
+ cat > tailwind.config.js << 'EOF'
188
+ /** @type {import('tailwindcss').Config} */
189
+ module.exports = {
190
+ darkMode: ["class"],
191
+ content: [
192
+ "./index.html",
193
+ "./src/**/*.{js,ts,jsx,tsx}",
194
+ ],
195
+ theme: {
196
+ extend: {
197
+ colors: {
198
+ border: "hsl(var(--border))",
199
+ input: "hsl(var(--input))",
200
+ ring: "hsl(var(--ring))",
201
+ background: "hsl(var(--background))",
202
+ foreground: "hsl(var(--foreground))",
203
+ primary: {
204
+ DEFAULT: "hsl(var(--primary))",
205
+ foreground: "hsl(var(--primary-foreground))",
206
+ },
207
+ secondary: {
208
+ DEFAULT: "hsl(var(--secondary))",
209
+ foreground: "hsl(var(--secondary-foreground))",
210
+ },
211
+ destructive: {
212
+ DEFAULT: "hsl(var(--destructive))",
213
+ foreground: "hsl(var(--destructive-foreground))",
214
+ },
215
+ muted: {
216
+ DEFAULT: "hsl(var(--muted))",
217
+ foreground: "hsl(var(--muted-foreground))",
218
+ },
219
+ accent: {
220
+ DEFAULT: "hsl(var(--accent))",
221
+ foreground: "hsl(var(--accent-foreground))",
222
+ },
223
+ popover: {
224
+ DEFAULT: "hsl(var(--popover))",
225
+ foreground: "hsl(var(--popover-foreground))",
226
+ },
227
+ card: {
228
+ DEFAULT: "hsl(var(--card))",
229
+ foreground: "hsl(var(--card-foreground))",
230
+ },
231
+ },
232
+ borderRadius: {
233
+ lg: "var(--radius)",
234
+ md: "calc(var(--radius) - 2px)",
235
+ sm: "calc(var(--radius) - 4px)",
236
+ },
237
+ keyframes: {
238
+ "accordion-down": {
239
+ from: { height: "0" },
240
+ to: { height: "var(--radix-accordion-content-height)" },
241
+ },
242
+ "accordion-up": {
243
+ from: { height: "var(--radix-accordion-content-height)" },
244
+ to: { height: "0" },
245
+ },
246
+ },
247
+ animation: {
248
+ "accordion-down": "accordion-down 0.2s ease-out",
249
+ "accordion-up": "accordion-up 0.2s ease-out",
250
+ },
251
+ },
252
+ },
253
+ plugins: [require("tailwindcss-animate")],
254
+ }
255
+ EOF
256
+
257
+ # Add Tailwind directives and CSS variables to index.css
258
+ echo "🎨 Adding Tailwind directives and CSS variables..."
259
+ cat > src/index.css << 'EOF'
260
+ @tailwind base;
261
+ @tailwind components;
262
+ @tailwind utilities;
263
+
264
+ @layer base {
265
+ :root {
266
+ --background: 0 0% 100%;
267
+ --foreground: 0 0% 3.9%;
268
+ --card: 0 0% 100%;
269
+ --card-foreground: 0 0% 3.9%;
270
+ --popover: 0 0% 100%;
271
+ --popover-foreground: 0 0% 3.9%;
272
+ --primary: 0 0% 9%;
273
+ --primary-foreground: 0 0% 98%;
274
+ --secondary: 0 0% 96.1%;
275
+ --secondary-foreground: 0 0% 9%;
276
+ --muted: 0 0% 96.1%;
277
+ --muted-foreground: 0 0% 45.1%;
278
+ --accent: 0 0% 96.1%;
279
+ --accent-foreground: 0 0% 9%;
280
+ --destructive: 0 84.2% 60.2%;
281
+ --destructive-foreground: 0 0% 98%;
282
+ --border: 0 0% 89.8%;
283
+ --input: 0 0% 89.8%;
284
+ --ring: 0 0% 3.9%;
285
+ --radius: 0.5rem;
286
+ }
287
+
288
+ .dark {
289
+ --background: 0 0% 3.9%;
290
+ --foreground: 0 0% 98%;
291
+ --card: 0 0% 3.9%;
292
+ --card-foreground: 0 0% 98%;
293
+ --popover: 0 0% 3.9%;
294
+ --popover-foreground: 0 0% 98%;
295
+ --primary: 0 0% 98%;
296
+ --primary-foreground: 0 0% 9%;
297
+ --secondary: 0 0% 14.9%;
298
+ --secondary-foreground: 0 0% 98%;
299
+ --muted: 0 0% 14.9%;
300
+ --muted-foreground: 0 0% 63.9%;
301
+ --accent: 0 0% 14.9%;
302
+ --accent-foreground: 0 0% 98%;
303
+ --destructive: 0 62.8% 30.6%;
304
+ --destructive-foreground: 0 0% 98%;
305
+ --border: 0 0% 14.9%;
306
+ --input: 0 0% 14.9%;
307
+ --ring: 0 0% 83.1%;
308
+ }
309
+ }
310
+
311
+ @layer base {
312
+ * {
313
+ @apply border-border;
314
+ }
315
+ body {
316
+ @apply bg-background text-foreground;
317
+ }
318
+ }
319
+ EOF
320
+
321
+ # Add path aliases to tsconfig.json
322
+ echo "🔧 Adding path aliases to tsconfig.json..."
323
+ node -e "
324
+ const fs = require('fs');
325
+ const config = JSON.parse(fs.readFileSync('tsconfig.json', 'utf8'));
326
+ config.compilerOptions = config.compilerOptions || {};
327
+ config.compilerOptions.baseUrl = '.';
328
+ config.compilerOptions.paths = { '@/*': ['./src/*'] };
329
+ fs.writeFileSync('tsconfig.json', JSON.stringify(config, null, 2));
330
+ "
331
+
332
+ # Add path aliases to tsconfig.app.json
333
+ echo "🔧 Adding path aliases to tsconfig.app.json..."
334
+ node -e "
335
+ const fs = require('fs');
336
+ const path = 'tsconfig.app.json';
337
+ const content = fs.readFileSync(path, 'utf8');
338
+ // Remove comments manually
339
+ const lines = content.split('\n').filter(line => !line.trim().startsWith('//'));
340
+ const jsonContent = lines.join('\n');
341
+ const config = JSON.parse(jsonContent.replace(/\/\*[\s\S]*?\*\//g, '').replace(/,(\s*[}\]])/g, '\$1'));
342
+ config.compilerOptions = config.compilerOptions || {};
343
+ config.compilerOptions.baseUrl = '.';
344
+ config.compilerOptions.paths = { '@/*': ['./src/*'] };
345
+ fs.writeFileSync(path, JSON.stringify(config, null, 2));
346
+ "
347
+
348
+ # Update vite.config.ts
349
+ echo "⚙️ Updating Vite configuration..."
350
+ cat > vite.config.ts << 'EOF'
351
+ import path from "path";
352
+ import react from "@vitejs/plugin-react";
353
+ import { defineConfig } from "vite";
354
+
355
+ export default defineConfig({
356
+ plugins: [react()],
357
+ resolve: {
358
+ alias: {
359
+ "@": path.resolve(__dirname, "./src"),
360
+ },
361
+ },
362
+ });
363
+ EOF
364
+
365
+ echo "🔧 Creating Parcel configuration with path alias support..."
366
+ cat > .parcelrc << 'EOF'
367
+ {
368
+ "extends": "@parcel/config-default",
369
+ "resolvers": ["parcel-resolver-tspaths", "..."]
370
+ }
371
+ EOF
372
+
373
+ # Install all shadcn/ui dependencies
374
+ echo "📦 Installing shadcn/ui dependencies..."
375
+ run_pnpm_quiet add @radix-ui/react-accordion @radix-ui/react-aspect-ratio @radix-ui/react-avatar @radix-ui/react-checkbox @radix-ui/react-collapsible @radix-ui/react-context-menu @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-hover-card @radix-ui/react-label @radix-ui/react-menubar @radix-ui/react-navigation-menu @radix-ui/react-popover @radix-ui/react-progress @radix-ui/react-radio-group @radix-ui/react-scroll-area @radix-ui/react-select @radix-ui/react-separator @radix-ui/react-slider @radix-ui/react-slot @radix-ui/react-switch @radix-ui/react-tabs @radix-ui/react-toast @radix-ui/react-toggle @radix-ui/react-toggle-group @radix-ui/react-tooltip
376
+ run_pnpm_quiet add sonner cmdk vaul embla-carousel-react react-day-picker react-resizable-panels date-fns react-hook-form @hookform/resolvers zod
377
+
378
+ # Extract shadcn components from tarball
379
+ echo "📦 Extracting shadcn/ui components..."
380
+ tar -xzf "$COMPONENTS_TARBALL" -C src/
381
+
382
+ # Create components.json for reference
383
+ echo "📝 Creating components.json config..."
384
+ cat > components.json << 'EOF'
385
+ {
386
+ "$schema": "https://ui.shadcn.com/schema.json",
387
+ "style": "default",
388
+ "rsc": false,
389
+ "tsx": true,
390
+ "tailwind": {
391
+ "config": "tailwind.config.js",
392
+ "css": "src/index.css",
393
+ "baseColor": "slate",
394
+ "cssVariables": true,
395
+ "prefix": ""
396
+ },
397
+ "aliases": {
398
+ "components": "@/components",
399
+ "utils": "@/lib/utils",
400
+ "ui": "@/components/ui",
401
+ "lib": "@/lib",
402
+ "hooks": "@/hooks"
403
+ }
404
+ }
405
+ EOF
406
+
407
+ echo "✅ Setup complete! You can now use Tailwind CSS and shadcn/ui in your project."
408
+ echo ""
409
+ echo "📦 Included components (40+ total):"
410
+ echo " - accordion, alert, aspect-ratio, avatar, badge, breadcrumb"
411
+ echo " - button, calendar, card, carousel, checkbox, collapsible"
412
+ echo " - command, context-menu, dialog, drawer, dropdown-menu"
413
+ echo " - form, hover-card, input, label, menubar, navigation-menu"
414
+ echo " - popover, progress, radio-group, resizable, scroll-area"
415
+ echo " - select, separator, sheet, skeleton, slider, sonner"
416
+ echo " - switch, table, tabs, textarea, toast, toggle, toggle-group, tooltip"
417
+ echo ""
418
+ echo "To start developing:"
419
+ echo " cd $PROJECT_NAME"
420
+ echo " pnpm dev"
421
+ echo ""
422
+ echo "📚 Import components like:"
423
+ echo " import { Button } from '@/components/ui/button'"
424
+ echo " import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'"
425
+ echo " import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'"
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: web-design-guidelines
3
+ description: Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
4
+ metadata:
5
+ author: vercel
6
+ version: "1.0.0"
7
+ argument-hint: <file-or-pattern>
8
+ ---
9
+
10
+ # Web Interface Guidelines
11
+
12
+ Review files for compliance with Web Interface Guidelines.
13
+
14
+ ## How It Works
15
+
16
+ 1. Fetch the latest guidelines from the source URL below
17
+ 2. Read the specified files (or prompt user for files/pattern)
18
+ 3. Check against all rules in the fetched guidelines
19
+ 4. Output findings in the terse `file:line` format
20
+
21
+ ## Guidelines Source
22
+
23
+ Fetch fresh guidelines before each review:
24
+
25
+ ```
26
+ https://raw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.md
27
+ ```
28
+
29
+ Use WebFetch to retrieve the latest rules. The fetched content contains all the rules and output format instructions.
30
+
31
+ ## Usage
32
+
33
+ When a user provides a file or pattern argument:
34
+ 1. Fetch guidelines from the source URL above
35
+ 2. Read the specified files
36
+ 3. Apply all rules from the fetched guidelines
37
+ 4. Output findings using the format specified in the guidelines
38
+
39
+ If no files specified, ask the user which files to review.