(_toolCallId, params)
| 290 | "Copy a concrete starter/source asset into the current workspace. kind: one of the keys in <userData>/templates/scaffolds/manifest.json (device-frame / browser / app-shell / dev-mockup / ui-primitive / background / surface / deck / report / design-system / landing). destPath: workspace-relative path. Example: scaffold({kind: 'iphone-16-pro-frame', destPath: 'frames/iphone.jsx'}). The tool preserves the source extension.", |
| 291 | parameters: ScaffoldParams, |
| 292 | async execute(_toolCallId, params): Promise<AgentToolResult<ScaffoldDetails>> { |
| 293 | const workspaceRoot = getWorkspaceRoot(); |
| 294 | if (!workspaceRoot) { |
| 295 | const reason = 'no workspace attached to this session'; |
| 296 | return { |
| 297 | content: [{ type: 'text', text: `scaffold failed: ${reason}` }], |
| 298 | details: { ok: false, reason }, |
| 299 | }; |
| 300 | } |
| 301 | const scaffoldsRoot = getScaffoldsRoot(); |
| 302 | if (!scaffoldsRoot) { |
| 303 | const reason = 'scaffolds directory not configured for this session'; |
| 304 | return { |
| 305 | content: [{ type: 'text', text: `scaffold failed: ${reason}` }], |
| 306 | details: { ok: false, reason }, |
| 307 | }; |
| 308 | } |
| 309 | const result = await runScaffold({ |
| 310 | kind: params.kind, |
| 311 | destPath: params.destPath, |
| 312 | workspaceRoot, |
| 313 | scaffoldsRoot, |
| 314 | }); |
| 315 | if (result.ok && result.written && typeof result.bytes === 'number') { |
| 316 | const suffix = result.normalizedEditmode ? ' (normalized legacy EDITMODE block)' : ''; |
| 317 | const destPath = result.destPath ?? params.destPath; |
| 318 | const adjusted = |
| 319 | result.requestedDestPath !== undefined |
| 320 | ? ` (destPath adjusted from ${params.destPath})` |
| 321 | : ''; |
| 322 | const details: Extract<ScaffoldDetails, { ok: true }> = { |
| 323 | ok: true, |
| 324 | kind: params.kind, |
| 325 | destPath, |
| 326 | ...(result.requestedDestPath !== undefined |
| 327 | ? { requestedDestPath: result.requestedDestPath } |
| 328 | : {}), |
| 329 | written: result.written, |
| 330 | bytes: result.bytes, |
| 331 | ...(result.normalizedEditmode ? { normalizedEditmode: true } : {}), |
| 332 | }; |
| 333 | if (opts.onScaffolded) { |
| 334 | await opts.onScaffolded(details); |
| 335 | } |
| 336 | return { |
| 337 | content: [ |
| 338 | { |
| 339 | type: 'text', |
| 340 | text: `Scaffolded ${params.kind} -> ${destPath} (${result.bytes} bytes)${suffix}${adjusted}`, |
| 341 | }, |
| 342 | ], |
| 343 | details, |
| 344 | }; |
| 345 | } |
| 346 | const reason = result.reason ?? 'unknown error'; |
| 347 | return { |
| 348 | content: [{ type: 'text', text: `scaffold failed: ${reason}` }], |
| 349 | details: { |
nothing calls this directly
no test coverage detected