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,426 @@
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
+ # Bun can run the current Vite toolchain even when Node is absent from PATH.
23
+ echo "20|Bun $bun_version"
24
+ return 0
25
+ fi
26
+ fi
27
+
28
+ echo "❌ Error: Node.js 18+ or Bun is required to initialize a web artifact." >&2
29
+ return 1
30
+ }
31
+
32
+ function configure_pnpm() {
33
+ if command -v pnpm >/dev/null 2>&1; then
34
+ PNPM_CMD=("pnpm")
35
+ echo "✅ Using pnpm from PATH"
36
+ return 0
37
+ fi
38
+
39
+ if command -v bun >/dev/null 2>&1; then
40
+ PNPM_CMD=("bun" "x" "pnpm@${PNPM_VERSION}")
41
+ echo "✅ Using pnpm via bun x"
42
+ return 0
43
+ fi
44
+
45
+ if command -v npm >/dev/null 2>&1; then
46
+ echo "📦 pnpm not found. Installing pnpm..."
47
+ npm install -g "pnpm@${PNPM_VERSION}"
48
+ PNPM_CMD=("pnpm")
49
+ echo "✅ Using pnpm installed via npm"
50
+ return 0
51
+ fi
52
+
53
+ echo "❌ Error: pnpm is unavailable and no Bun or npm fallback was found." >&2
54
+ return 1
55
+ }
56
+
57
+ function run_pnpm() {
58
+ "${PNPM_CMD[@]}" "$@"
59
+ }
60
+
61
+ function replay_filtered_stderr() {
62
+ local stderr_file="$1"
63
+ while IFS= read -r line; do
64
+ if [[ "$line" == *"/dev/tty"* ]]; then
65
+ continue
66
+ fi
67
+ echo "$line" >&2
68
+ done < "$stderr_file"
69
+ }
70
+
71
+ function run_with_filtered_stderr() {
72
+ local stderr_file
73
+ stderr_file="$(mktemp)"
74
+ if "$@" 2>"$stderr_file"; then
75
+ replay_filtered_stderr "$stderr_file"
76
+ rm -f "$stderr_file"
77
+ return 0
78
+ fi
79
+
80
+ local status=$?
81
+ replay_filtered_stderr "$stderr_file"
82
+ rm -f "$stderr_file"
83
+ return "$status"
84
+ }
85
+
86
+ function run_pnpm_quiet() {
87
+ run_with_filtered_stderr "${PNPM_CMD[@]}" --silent "$@"
88
+ }
89
+
90
+ function run_pnpm_allow_build() {
91
+ local allow_build_args=()
92
+ local package_name
93
+ for package_name in "${ALLOWED_BUILD_PACKAGES[@]}"; do
94
+ allow_build_args+=(--allow-build="$package_name")
95
+ done
96
+ run_with_filtered_stderr "${PNPM_CMD[@]}" --silent "$@" "${allow_build_args[@]}"
97
+ }
98
+
99
+ RUNTIME_INFO="$(detect_runtime_major)"
100
+ NODE_VERSION="${RUNTIME_INFO%%|*}"
101
+ RUNTIME_LABEL="${RUNTIME_INFO#*|}"
102
+
103
+ echo "🔍 Detected runtime: $RUNTIME_LABEL"
104
+
105
+ if [ "$NODE_VERSION" -lt 18 ]; then
106
+ echo "❌ Error: Node.js 18 or higher is required"
107
+ echo " Current runtime: $RUNTIME_LABEL"
108
+ exit 1
109
+ fi
110
+
111
+ if [ "$NODE_VERSION" -ge 20 ]; then
112
+ VITE_VERSION="latest"
113
+ echo "✅ Using Vite latest (runtime equivalent to Node 20+)"
114
+ else
115
+ VITE_VERSION="5.4.11"
116
+ echo "✅ Using Vite $VITE_VERSION (Node 18 compatible)"
117
+ fi
118
+
119
+ # Detect OS and set sed syntax
120
+ if [[ "$OSTYPE" == "darwin"* ]]; then
121
+ SED_INPLACE="sed -i ''"
122
+ else
123
+ SED_INPLACE="sed -i"
124
+ fi
125
+
126
+ declare -a PNPM_CMD
127
+ configure_pnpm
128
+
129
+ # Check if project name is provided
130
+ if [ -z "$1" ]; then
131
+ echo "❌ Usage: ./init-artifact.sh <project-name>"
132
+ exit 1
133
+ fi
134
+
135
+ PROJECT_NAME="$1"
136
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
137
+ COMPONENTS_TARBALL="$SCRIPT_DIR/shadcn-components.tar.gz"
138
+
139
+ # Check if components tarball exists
140
+ if [ ! -f "$COMPONENTS_TARBALL" ]; then
141
+ echo "❌ Error: shadcn-components.tar.gz not found in script directory"
142
+ echo " Expected location: $COMPONENTS_TARBALL"
143
+ exit 1
144
+ fi
145
+
146
+ echo "🚀 Creating new React + Vite project: $PROJECT_NAME"
147
+
148
+ # Create new Vite project (always use latest create-vite, pin vite version later)
149
+ run_pnpm_quiet create vite "$PROJECT_NAME" --template react-ts --no-interactive
150
+
151
+ # Navigate into project directory
152
+ cd "$PROJECT_NAME"
153
+
154
+ node -e "
155
+ const fs = require('fs');
156
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
157
+ pkg.packageManager = 'pnpm@${PNPM_VERSION}';
158
+ fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
159
+ "
160
+
161
+ echo "🧹 Cleaning up Vite template..."
162
+ $SED_INPLACE '/<link rel="icon".*/d' index.html
163
+ $SED_INPLACE 's/<title>.*<\/title>/<title>'"$PROJECT_NAME"'<\/title>/' index.html
164
+
165
+ echo "📦 Installing base dependencies..."
166
+ run_pnpm_quiet install
167
+
168
+ # Pin Vite version for Node 18
169
+ if [ "$NODE_VERSION" -lt 20 ]; then
170
+ echo "📌 Pinning Vite to $VITE_VERSION for Node 18 compatibility..."
171
+ run_pnpm_allow_build add -D vite@"$VITE_VERSION"
172
+ fi
173
+
174
+ echo "📦 Installing Tailwind CSS and dependencies..."
175
+ run_pnpm_allow_build add -D tailwindcss@3.4.1 postcss @types/node tailwindcss-animate parcel @parcel/config-default parcel-resolver-tspaths html-inline
176
+ run_pnpm_quiet add class-variance-authority clsx tailwind-merge lucide-react next-themes
177
+
178
+ echo "⚙️ Creating Tailwind and PostCSS configuration..."
179
+ cat > .postcssrc.json << 'EOF'
180
+ {
181
+ "plugins": {
182
+ "tailwindcss": {}
183
+ }
184
+ }
185
+ EOF
186
+
187
+ echo "📝 Configuring Tailwind with shadcn theme..."
188
+ cat > tailwind.config.js << 'EOF'
189
+ /** @type {import('tailwindcss').Config} */
190
+ module.exports = {
191
+ darkMode: ["class"],
192
+ content: [
193
+ "./index.html",
194
+ "./src/**/*.{js,ts,jsx,tsx}",
195
+ ],
196
+ theme: {
197
+ extend: {
198
+ colors: {
199
+ border: "hsl(var(--border))",
200
+ input: "hsl(var(--input))",
201
+ ring: "hsl(var(--ring))",
202
+ background: "hsl(var(--background))",
203
+ foreground: "hsl(var(--foreground))",
204
+ primary: {
205
+ DEFAULT: "hsl(var(--primary))",
206
+ foreground: "hsl(var(--primary-foreground))",
207
+ },
208
+ secondary: {
209
+ DEFAULT: "hsl(var(--secondary))",
210
+ foreground: "hsl(var(--secondary-foreground))",
211
+ },
212
+ destructive: {
213
+ DEFAULT: "hsl(var(--destructive))",
214
+ foreground: "hsl(var(--destructive-foreground))",
215
+ },
216
+ muted: {
217
+ DEFAULT: "hsl(var(--muted))",
218
+ foreground: "hsl(var(--muted-foreground))",
219
+ },
220
+ accent: {
221
+ DEFAULT: "hsl(var(--accent))",
222
+ foreground: "hsl(var(--accent-foreground))",
223
+ },
224
+ popover: {
225
+ DEFAULT: "hsl(var(--popover))",
226
+ foreground: "hsl(var(--popover-foreground))",
227
+ },
228
+ card: {
229
+ DEFAULT: "hsl(var(--card))",
230
+ foreground: "hsl(var(--card-foreground))",
231
+ },
232
+ },
233
+ borderRadius: {
234
+ lg: "var(--radius)",
235
+ md: "calc(var(--radius) - 2px)",
236
+ sm: "calc(var(--radius) - 4px)",
237
+ },
238
+ keyframes: {
239
+ "accordion-down": {
240
+ from: { height: "0" },
241
+ to: { height: "var(--radix-accordion-content-height)" },
242
+ },
243
+ "accordion-up": {
244
+ from: { height: "var(--radix-accordion-content-height)" },
245
+ to: { height: "0" },
246
+ },
247
+ },
248
+ animation: {
249
+ "accordion-down": "accordion-down 0.2s ease-out",
250
+ "accordion-up": "accordion-up 0.2s ease-out",
251
+ },
252
+ },
253
+ },
254
+ plugins: [require("tailwindcss-animate")],
255
+ }
256
+ EOF
257
+
258
+ # Add Tailwind directives and CSS variables to index.css
259
+ echo "🎨 Adding Tailwind directives and CSS variables..."
260
+ cat > src/index.css << 'EOF'
261
+ @tailwind base;
262
+ @tailwind components;
263
+ @tailwind utilities;
264
+
265
+ @layer base {
266
+ :root {
267
+ --background: 0 0% 100%;
268
+ --foreground: 0 0% 3.9%;
269
+ --card: 0 0% 100%;
270
+ --card-foreground: 0 0% 3.9%;
271
+ --popover: 0 0% 100%;
272
+ --popover-foreground: 0 0% 3.9%;
273
+ --primary: 0 0% 9%;
274
+ --primary-foreground: 0 0% 98%;
275
+ --secondary: 0 0% 96.1%;
276
+ --secondary-foreground: 0 0% 9%;
277
+ --muted: 0 0% 96.1%;
278
+ --muted-foreground: 0 0% 45.1%;
279
+ --accent: 0 0% 96.1%;
280
+ --accent-foreground: 0 0% 9%;
281
+ --destructive: 0 84.2% 60.2%;
282
+ --destructive-foreground: 0 0% 98%;
283
+ --border: 0 0% 89.8%;
284
+ --input: 0 0% 89.8%;
285
+ --ring: 0 0% 3.9%;
286
+ --radius: 0.5rem;
287
+ }
288
+
289
+ .dark {
290
+ --background: 0 0% 3.9%;
291
+ --foreground: 0 0% 98%;
292
+ --card: 0 0% 3.9%;
293
+ --card-foreground: 0 0% 98%;
294
+ --popover: 0 0% 3.9%;
295
+ --popover-foreground: 0 0% 98%;
296
+ --primary: 0 0% 98%;
297
+ --primary-foreground: 0 0% 9%;
298
+ --secondary: 0 0% 14.9%;
299
+ --secondary-foreground: 0 0% 98%;
300
+ --muted: 0 0% 14.9%;
301
+ --muted-foreground: 0 0% 63.9%;
302
+ --accent: 0 0% 14.9%;
303
+ --accent-foreground: 0 0% 98%;
304
+ --destructive: 0 62.8% 30.6%;
305
+ --destructive-foreground: 0 0% 98%;
306
+ --border: 0 0% 14.9%;
307
+ --input: 0 0% 14.9%;
308
+ --ring: 0 0% 83.1%;
309
+ }
310
+ }
311
+
312
+ @layer base {
313
+ * {
314
+ @apply border-border;
315
+ }
316
+ body {
317
+ @apply bg-background text-foreground;
318
+ }
319
+ }
320
+ EOF
321
+
322
+ # Add path aliases to tsconfig.json
323
+ echo "🔧 Adding path aliases to tsconfig.json..."
324
+ node -e "
325
+ const fs = require('fs');
326
+ const config = JSON.parse(fs.readFileSync('tsconfig.json', 'utf8'));
327
+ config.compilerOptions = config.compilerOptions || {};
328
+ config.compilerOptions.baseUrl = '.';
329
+ config.compilerOptions.paths = { '@/*': ['./src/*'] };
330
+ fs.writeFileSync('tsconfig.json', JSON.stringify(config, null, 2));
331
+ "
332
+
333
+ # Add path aliases to tsconfig.app.json
334
+ echo "🔧 Adding path aliases to tsconfig.app.json..."
335
+ node -e "
336
+ const fs = require('fs');
337
+ const path = 'tsconfig.app.json';
338
+ const content = fs.readFileSync(path, 'utf8');
339
+ // Remove comments manually
340
+ const lines = content.split('\n').filter(line => !line.trim().startsWith('//'));
341
+ const jsonContent = lines.join('\n');
342
+ const config = JSON.parse(jsonContent.replace(/\/\*[\s\S]*?\*\//g, '').replace(/,(\s*[}\]])/g, '\$1'));
343
+ config.compilerOptions = config.compilerOptions || {};
344
+ config.compilerOptions.baseUrl = '.';
345
+ config.compilerOptions.paths = { '@/*': ['./src/*'] };
346
+ fs.writeFileSync(path, JSON.stringify(config, null, 2));
347
+ "
348
+
349
+ # Update vite.config.ts
350
+ echo "⚙️ Updating Vite configuration..."
351
+ cat > vite.config.ts << 'EOF'
352
+ import path from "path";
353
+ import react from "@vitejs/plugin-react";
354
+ import { defineConfig } from "vite";
355
+
356
+ export default defineConfig({
357
+ plugins: [react()],
358
+ resolve: {
359
+ alias: {
360
+ "@": path.resolve(__dirname, "./src"),
361
+ },
362
+ },
363
+ });
364
+ EOF
365
+
366
+ echo "🔧 Creating Parcel configuration with path alias support..."
367
+ cat > .parcelrc << 'EOF'
368
+ {
369
+ "extends": "@parcel/config-default",
370
+ "resolvers": ["parcel-resolver-tspaths", "..."]
371
+ }
372
+ EOF
373
+
374
+ # Install all shadcn/ui dependencies
375
+ echo "📦 Installing shadcn/ui dependencies..."
376
+ 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
377
+ run_pnpm_quiet add sonner cmdk vaul embla-carousel-react react-day-picker react-resizable-panels date-fns react-hook-form @hookform/resolvers zod
378
+
379
+ # Extract shadcn components from tarball
380
+ echo "📦 Extracting shadcn/ui components..."
381
+ tar -xzf "$COMPONENTS_TARBALL" -C src/
382
+
383
+ # Create components.json for reference
384
+ echo "📝 Creating components.json config..."
385
+ cat > components.json << 'EOF'
386
+ {
387
+ "$schema": "https://ui.shadcn.com/schema.json",
388
+ "style": "default",
389
+ "rsc": false,
390
+ "tsx": true,
391
+ "tailwind": {
392
+ "config": "tailwind.config.js",
393
+ "css": "src/index.css",
394
+ "baseColor": "slate",
395
+ "cssVariables": true,
396
+ "prefix": ""
397
+ },
398
+ "aliases": {
399
+ "components": "@/components",
400
+ "utils": "@/lib/utils",
401
+ "ui": "@/components/ui",
402
+ "lib": "@/lib",
403
+ "hooks": "@/hooks"
404
+ }
405
+ }
406
+ EOF
407
+
408
+ echo "✅ Setup complete! You can now use Tailwind CSS and shadcn/ui in your project."
409
+ echo ""
410
+ echo "📦 Included components (40+ total):"
411
+ echo " - accordion, alert, aspect-ratio, avatar, badge, breadcrumb"
412
+ echo " - button, calendar, card, carousel, checkbox, collapsible"
413
+ echo " - command, context-menu, dialog, drawer, dropdown-menu"
414
+ echo " - form, hover-card, input, label, menubar, navigation-menu"
415
+ echo " - popover, progress, radio-group, resizable, scroll-area"
416
+ echo " - select, separator, sheet, skeleton, slider, sonner"
417
+ echo " - switch, table, tabs, textarea, toast, toggle, toggle-group, tooltip"
418
+ echo ""
419
+ echo "To start developing:"
420
+ echo " cd $PROJECT_NAME"
421
+ echo " pnpm dev"
422
+ echo ""
423
+ echo "📚 Import components like:"
424
+ echo " import { Button } from '@/components/ui/button'"
425
+ echo " import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'"
426
+ echo " import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'"