@tempo-ai/mcp 0.0.102 → 0.0.103

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createRequire as __tempoCreateRequire } from 'node:module'; const require = __tempoCreateRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-6P4PI7CS.js";
5
+ } from "./chunk-C3J4LFJI.js";
6
6
  import "./chunk-KQNQSVOA.js";
7
7
 
8
8
  // src/bin.ts
@@ -8,7 +8,7 @@ import {
8
8
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
9
9
  import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
10
10
  async function connectAggregate(options) {
11
- const { createTempoAggregate } = await import("./serve-NGUFKD5I.js");
11
+ const { createTempoAggregate } = await import("./serve-P7M4UFJS.js");
12
12
  const handle = await createTempoAggregate(options);
13
13
  const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
14
14
  const client = new Client({ name: "tempo-mcp-cli", version: "0" });
@@ -127,4 +127,4 @@ export {
127
127
  runCall,
128
128
  runTools
129
129
  };
130
- //# sourceMappingURL=call-TNF2AXMX.js.map
130
+ //# sourceMappingURL=call-XYOJSSYR.js.map
@@ -157,7 +157,7 @@ async function run(argv) {
157
157
  process.stderr.write(USAGE);
158
158
  return 1;
159
159
  }
160
- const { runServe } = await import("./serve-NGUFKD5I.js");
160
+ const { runServe } = await import("./serve-P7M4UFJS.js");
161
161
  return await runServe(options);
162
162
  }
163
163
  switch (subcommand) {
@@ -172,11 +172,11 @@ async function run(argv) {
172
172
  return await runToken(rest);
173
173
  }
174
174
  case "tools": {
175
- const { runTools } = await import("./call-TNF2AXMX.js");
175
+ const { runTools } = await import("./call-XYOJSSYR.js");
176
176
  return await runTools(rest);
177
177
  }
178
178
  case "call": {
179
- const { runCall } = await import("./call-TNF2AXMX.js");
179
+ const { runCall } = await import("./call-XYOJSSYR.js");
180
180
  return await runCall(rest);
181
181
  }
182
182
  default:
@@ -195,4 +195,4 @@ async function run(argv) {
195
195
  export {
196
196
  run
197
197
  };
198
- //# sourceMappingURL=chunk-6P4PI7CS.js.map
198
+ //# sourceMappingURL=chunk-C3J4LFJI.js.map
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __tempoCreateRequire } from 'node:module'; const require = __tempoCreateRequire(import.meta.url);
2
2
  import {
3
3
  run
4
- } from "./chunk-6P4PI7CS.js";
4
+ } from "./chunk-C3J4LFJI.js";
5
5
  import "./chunk-KQNQSVOA.js";
6
6
  export {
7
7
  run
@@ -15520,11 +15520,11 @@ scaffolded project.
15520
15520
  | \`scripts.start\` | string | Canvas-host launcher (runs from the tempo root). Prefer a foreground process. Tempo substitutes every literal \`\${PORT}\`, exports the same port as \`TEMPO_PORT\`, and sets \`TEMPO=true\`. |
15521
15521
  | \`scripts.stop\` | string? | Matching teardown for a daemonized/external host. Tempo substitutes \`\${PORT}\` and runs this before signalling the launcher group. Required when \`scripts.start\` exits successfully while the host continues in the background. |
15522
15522
  | \`urls.tempoHost\` | URL string? | Public \`/tempo-host\` URL to probe when stdout cannot describe the reachable boundary (containers, tunnels, remotes). May contain \`\${PORT}\`; e.g. \`http://127.0.0.1:\${PORT}/tempo-host\`. |
15523
- | \`apps\` | array? | \`[{ "appDir"?, "appStart"? }]\` \u2014 one entry per client app; only \`apps[0]\` is active today. \`apps[0].appStart\` is the user's REAL app dev-server command, supervised by Tempo for route storyboards; must contain \`\${PORT}\` (see "Route Storyboards & the app dev command"). Legacy \`scripts.appStart\` / top-level \`appDir\` still read and auto-migrate. |
15523
+ | \`apps\` | array? | \`[{ "appDir"?, "start"?, "url"? }]\` \u2014 one entry per client app; only \`apps[0]\` is active today. \`start\` launches the user's REAL app for route storyboards and may be any foreground command; \`url\` optionally supplies the independent HTTP(S) readiness target and route base. \`\${APP_PORT}\` is an optional allocated-port helper and legacy \`\${PORT}\` remains supported. Legacy \`apps[].appStart\`, \`scripts.appStart\`, and top-level \`appDir\` still read and auto-migrate. |
15524
15524
 
15525
15525
  **Every command in this file runs through the platform shell \u2014 \`cmd.exe\` on
15526
15526
  Windows, not PowerShell.** That applies to \`scripts.install\` and
15527
- \`scripts.start\` exactly as it does to \`appStart\`. Write plain, cross-platform
15527
+ \`scripts.start\` exactly as it does to app \`start\`. Write plain, cross-platform
15528
15528
  invocations; \`&&\` and \`cd\` are fine (cmd supports both). Never use PowerShell
15529
15529
  syntax \u2014 \`if (Test-Path \u2026) { \u2026 } else { \u2026 }\`, \`Test-Path\`, \`$env:FOO\` \u2014 because
15530
15530
  cmd.exe cannot parse it and aborts with "X was unexpected at this time" BEFORE
@@ -15565,8 +15565,10 @@ For Svelte 5, setup is complete only when all applicable items below hold:
15565
15565
  \`tempo/vite.config.ts\`\u2014includes \`tempoVitePlugin()\` and its active Svelte
15566
15566
  preprocessing chain starts with \`tempoSveltePreprocess(...)\`. Preserve all
15567
15567
  existing preprocessors after Tempo's preprocessor.
15568
- 4. Route storyboards additionally have an \`apps[0].appStart\` command containing
15569
- the literal \`\${PORT}\` token. Configure it with \`set_app_dev_command\`.
15568
+ 4. Route storyboards additionally have an \`apps[0].start\` command and should
15569
+ set \`apps[0].url\` when the HTTP(S) liveness target is known. The command
15570
+ may use the optional \`\${APP_PORT}\` helper (legacy \`\${PORT}\` also
15571
+ works). Configure both with \`set_app_dev_command\`.
15570
15572
 
15571
15573
  The official Svelte Vite plugin compiles \`.svelte\` modules; Tempo's Vite
15572
15574
  plugin injects the projection runtime; and Tempo's Svelte preprocessor records
@@ -15918,7 +15920,7 @@ export default function AuthComponentsCanvas() {
15918
15920
 
15919
15921
  Canvases created before the React format use object exports instead of JSX \u2014 \`export const Login: TempoStoryboard = { render: () => <LoginForm />, layout: {\u2026} }\` with a \`TempoCanvasConfig\` default export. Tempo migrates these to the React format automatically when they are opened in the Design tab. If you encounter one, run \`canvas_migrate_to_latest\` on it BEFORE making any edit \u2014 never hand-write legacy declarations, and never mix the two formats in one file.
15920
15922
 
15921
- ### Route Storyboards & the app dev command (\`apps[0].appStart\`)
15923
+ ### Route Storyboards & the app dev config (\`apps[0].start\` / \`url\`)
15922
15924
 
15923
15925
  Route storyboards (\`<RouteStoryboard>\`) load **the user's real app** in the iframe, NOT the canvas sidecar. They need a second supervised process \u2014 the user's actual app dev server \u2014 which Tempo manages from the app dev command in \`tempo.config.json\`, stored canonically on the \`apps[]\` list (one entry per client app; only \`apps[0]\` is active today):
15924
15926
 
@@ -15931,13 +15933,14 @@ Route storyboards (\`<RouteStoryboard>\`) load **the user's real app** in the if
15931
15933
  "apps": [
15932
15934
  {
15933
15935
  "appDir": "client", // app package dir, relative to repo root (omit for autodetect)
15934
- "appStart": "npm run dev -- --port=\${PORT}" // user's real app
15936
+ "start": "npm exec vite --port=\${APP_PORT}", // arbitrary foreground command
15937
+ "url": "http://127.0.0.1:\${APP_PORT}" // optional HTTP(S) liveness target
15935
15938
  }
15936
15939
  ]
15937
15940
  }
15938
15941
  \`\`\`
15939
15942
 
15940
- (Files written by older Tempo versions may still carry the legacy \`scripts.appStart\` / top-level \`appDir\` spelling \u2014 those read fine and auto-migrate to \`apps[]\` the next time the config is written.)
15943
+ (Files written by older Tempo versions may still carry \`apps[].appStart\`, \`scripts.appStart\`, or top-level \`appDir\`. They read normally and migrate to canonical \`apps[].start\` on the next config write.)
15941
15944
 
15942
15945
  **The app's own bundler config MUST include the Tempo annotation plugin.** Route storyboards are served by the user's app dev server (NOT the \`tempo/\` sidecar), so the canvas can only select/edit their elements if THAT server injects the \`data-tempo-*\` annotations \u2014 i.e. the **app's own** framework config carries the Tempo plugin, active under \`TEMPO=true\`. Without it the app still renders in the iframe, but every click collapses to one unmappable root and the user reports *"route storyboard elements are not clickable."* This is separate from the \`tempo/\` sidecar's plugin (\xA74.2) \u2014 both configs need it, for different servers. Add the plugin to the app package (and add \`tempo-sdk\` to the app's deps) per framework:
15943
15946
 
@@ -15990,13 +15993,13 @@ Route storyboards (\`<RouteStoryboard>\`) load **the user's real app** in the if
15990
15993
  };
15991
15994
  \`\`\`
15992
15995
 
15993
- The plugin no-ops unless \`TEMPO=true\` (which the supervisor sets when it runs \`appStart\`), so it is safe to keep in the config permanently.
15996
+ The plugin no-ops unless \`TEMPO=true\` (which the supervisor sets when it runs app \`start\`), so it is safe to keep in the config permanently.
15994
15997
 
15995
15998
  Mechanics:
15996
15999
 
15997
- - The supervisor allocates a free TCP port per workspace, persisted at \`<workspaceRoot>/.tempo/app-devserver.json\` (gitignored, per-worktree).
15998
- - The literal \`\${PORT}\` token in the command is substituted at spawn time, so multiple worktrees of the same project never collide on the same port.
15999
- - The renderer resolves route storyboard URLs to the app server's URL, so \`route: "/dashboard"\` becomes \`http://127.0.0.1:<allocated>/dashboard\` automatically.
16000
+ - The supervisor always allocates a free local TCP port per workspace and persists it at \`<workspaceRoot>/.tempo/app-devserver.json\` (gitignored, per-worktree).
16001
+ - A \`url\` containing \`\${APP_PORT}\` (or legacy \`\${PORT}\`) uses that allocated helper value. A literal URL is an opaque HTTP(S) readiness target and route base: its hostname and port never control local allocation, so it may point through a container, tunnel, or remote machine.
16002
+ - Every literal \`\${APP_PORT}\` or legacy \`\${PORT}\` in app \`start\` and \`url\` is substituted before spawn/probe. The renderer resolves route storyboard paths against the resulting URL.
16000
16003
  - Lifecycle: warm with a 5-minute idle stop \u2014 the supervisor stays alive while a canvas with route storyboards is open and stops 5 minutes after the last canvas closes.
16001
16004
  - While starting, an overlay reads "Starting your app dev server\u2026" on every route storyboard.
16002
16005
 
@@ -16006,16 +16009,29 @@ Mechanics:
16006
16009
 
16007
16010
  | Framework | Command shape |
16008
16011
  |-----------|---------------|
16009
- | Vite | \`<pm> exec vite --port=\${PORT} --strictPort\` (e.g. \`pnpm exec vite \u2026\`, \`npx vite \u2026\`) |
16010
- | Next.js | \`<pm> exec next dev -p \${PORT}\` |
16011
- | Expo (web) | \`npx expo start --web --port \${PORT}\` |
16012
- | CRA / Remix / generic | \`PORT=\${PORT} npm run dev\` |
16012
+ | Vite | \`<pm> exec vite --port=\${APP_PORT} --strictPort\` (e.g. \`pnpm exec vite \u2026\`, \`npx vite \u2026\`) |
16013
+ | Next.js | \`<pm> exec next dev -p \${APP_PORT}\` |
16014
+ | Expo (web) | \`npx expo start --web --port \${APP_PORT}\` |
16015
+ | CRA / Remix / generic | \`PORT=\${APP_PORT} npm run dev\` |
16013
16016
 
16014
- **Invoke the bundler binary directly \u2014 do NOT route the port flag through \`<pm> run dev -- --port=\${PORT}\`.** When the \`dev\` script is a bare \`vite\` (the common case) and the project uses **pnpm**, \`pnpm run dev -- --port=\${PORT}\` forwards the literal \`--\` separator through to Vite, which treats it as a positional arg, ignores \`--port\`, and binds its default 5173 instead of the supervisor's allocated \`\${PORT}\` \u2014 so every route storyboard then points at the wrong server. npm strips the first \`--\` so it happens to work there, but the direct-exec form (\`pnpm exec vite \u2026\` / \`npx vite \u2026\`) is correct under every package manager. (\`--strictPort\` makes the mismatch fail loudly instead of silently falling back.)
16017
+ **When using the allocated helper port, invoke the bundler binary directly \u2014 do NOT route the port flag through \`<pm> run dev -- --port=\${APP_PORT}\`.** When the \`dev\` script is a bare \`vite\` (the common case) and the project uses **pnpm**, that form can forward the literal \`--\` separator through to Vite, which treats it as a positional arg and ignores \`--port\`. The direct-exec form (\`pnpm exec vite \u2026\` / \`npx vite \u2026\`) is correct under every package manager. (\`--strictPort\` makes a mismatch fail loudly.)
16015
16018
 
16016
- The command MUST contain the literal \`\${PORT}\` token. Without it the supervisor would land on the framework's default port and race with sibling workspaces or unrelated processes; the validator refuses commands missing the token.
16019
+ The command is otherwise arbitrary. The allocated helper token is optional, and a configured \`url\` is always the liveness target Tempo probes.
16017
16020
 
16018
- **Keep the command plain and cross-platform \u2014 one invocation, no shell conditionals.** Tempo spawns it through the platform shell (**cmd.exe on Windows**, not PowerShell) and substitutes \`\${PORT}\` to a literal port BEFORE spawning, so a bare \`npm\`/\`node\` command runs identically on cmd.exe and POSIX shells. A leading \`NAME=value\` prefix \u2014 the CRA/Remix shape \`PORT=\${PORT} npm run dev\` \u2014 is also safe on every OS: the supervisor lifts it into the spawn environment instead of handing it to the shell (cmd.exe would otherwise parse \`PORT=3001\` as a program name), and it always sets \`PORT\`/\`TEMPO_APP_PORT\` in the environment regardless. Never use PowerShell syntax \u2014 \`if (Test-Path \u2026) { \u2026 } else { \u2026 }\`, \`Test-Path\`, \`$env:FOO\`, \`Get-\`/\`Set-\` cmdlets \u2014 cmd.exe can't parse it and aborts with "X was unexpected at this time" BEFORE running anything (\`set_app_dev_command\` rejects PowerShell-shaped commands at author time, and the supervisor refuses to spawn one that reaches it via a hand-edited config). Chaining with \`&&\` is fine \u2014 cmd supports it \u2014 but there should be no need for it here. If the app lives in a subdirectory, set \`appDir\` (in \`tempo.config.json\` or via \`set_app_dev_command\`) instead of \`cd\`/\`pushd\`-ing inside the command \u2014 the supervisor runs the command from \`appDir\` for you.
16021
+ **Independent readiness URL.** Use a literal \`url\` whenever the URL Tempo can reach differs from the locally allocated port, including a container, tunnel, or remote machine:
16022
+
16023
+ \`\`\`json
16024
+ {
16025
+ "apps": [{
16026
+ "start": "npm run dev:remote",
16027
+ "url": "https://preview.example.com"
16028
+ }]
16029
+ }
16030
+ \`\`\`
16031
+
16032
+ The supervisor probes \`url\` directly rather than waiting for stdout URL discovery and uses it as the public route base after it responds. The local helper port remains independently allocated and available to \`start\` through \`APP_PORT\`, \`PORT\`, and \`TEMPO_APP_PORT\`, even when the literal URL spells a completely different host or explicit port.
16033
+
16034
+ **Keep the command plain and cross-platform \u2014 one invocation, no shell conditionals.** Tempo spawns it through the platform shell (**cmd.exe on Windows**, not PowerShell) and substitutes \`\${APP_PORT}\` (or legacy \`\${PORT}\`) before spawning. A leading \`NAME=value\` prefix \u2014 for example \`PORT=\${APP_PORT} npm run dev\` \u2014 is also safe on every OS: the supervisor lifts it into the spawn environment instead of handing it to the shell, and it always sets \`APP_PORT\`, \`PORT\`, and \`TEMPO_APP_PORT\` in the environment regardless. Never use PowerShell syntax \u2014 \`if (Test-Path \u2026) { \u2026 } else { \u2026 }\`, \`Test-Path\`, \`$env:FOO\`, \`Get-\`/\`Set-\` cmdlets \u2014 cmd.exe can't parse it and aborts before running anything. If the app lives in a subdirectory, set \`appDir\` instead of changing directories inside the command.
16019
16035
 
16020
16036
  **Driving the lifecycle directly.** Three sibling tools mirror the canvas-sidecar trio: \`check_app_dev_server\` / \`start_app_dev_server\` / \`stop_app_dev_server\` (vs \`check_canvas_devserver\` / \`start_canvas_devserver\` / \`stop_canvas_devserver\`). \`check_app_dev_server\` returns \`{configured, running, phase, port, url, error}\` \u2014 call it first when a route storyboard isn't loading, to disambiguate: \`configured: false\` \u2192 \`set_app_dev_command\`; \`configured: true, running: false\` \u2192 read \`error\`, then \`start_app_dev_server\`; \`running: true\` \u2192 the route itself is the problem, not the supervisor. After editing the app dev command, \`stop_app_dev_server\` then \`start_app_dev_server\` to pick up the new command.
16021
16037
 
@@ -16023,9 +16039,9 @@ The command MUST contain the literal \`\${PORT}\` token. Without it the supervis
16023
16039
 
16024
16040
  **Home canvas.** A project's home canvas (single \`route: "/"\` storyboard) backs the header Run (play) button and the turn-summary "Run app" card \u2014 both open it next to the app's dev-server output. When setting a project up for canvases or route storyboards, ensure one exists: \`canvas_project_init\` seeds it alongside the template canvas; if a \`route: "/"\` canvas already exists, mark it with \`canvas_set_home\` instead of duplicating; otherwise create one with \`canvas_create({ canvas_name: "Home", home: true, storyboards: [{ export_name: "Home", route: "/" }] })\`.
16025
16041
 
16026
- Use the \`set_app_dev_command\` MCP tool to write this \u2014 don't hand-edit \`tempo.config.json\` for it. The tool validates the \`\${PORT}\` invariant and clears any cached supervisor so the next route storyboard load picks up the new command. \`create-canvas\` issues a soft-gate warning in its result when route storyboards are requested but the app dev command is missing \u2014 confirm the command with the user, then call \`set_app_dev_command\`. When you set it, you should also check the app's bundler plugin + \`tempo-sdk\` dep are in place (above), unless you already did.
16042
+ Use the \`set_app_dev_command\` MCP tool to write this \u2014 don't hand-edit \`tempo.config.json\` for it. The tool validates the fields and clears any cached supervisor so the next route storyboard load picks up the new config. \`create-canvas\` issues a soft-gate warning in its result when route storyboards are requested but app start is missing \u2014 confirm the command with the user, then call \`set_app_dev_command\`. When you set it, you should also check the app's bundler plugin + \`tempo-sdk\` dep are in place (above), unless you already did.
16027
16043
 
16028
- Once set, \`appStart\` also appears automatically in the workspace header's Run (play) button under **Org run scripts** as a read-only "App dev server" entry (the default unless the user picks another) \u2014 never add a run script duplicating it, and when the route-storyboard supervisor is already up, point the user at its URL instead of suggesting they also hit play. Other Run-button commands (build, test, \u2026) are DB-backed (org-shared + per-user, per project) \u2014 add them with \`configure_run_script\` (\`tempo-scripts-tools\` MCP), not in this file. The home canvas + app dev command stay in the repo, so once the app runs, suggest committing them so teammates get the app Run entry too.
16044
+ Once set, app \`start\` also appears automatically in the workspace header's Run (play) button under **Org run scripts** as a read-only "App dev server" entry (the default unless the user picks another) \u2014 never add a run script duplicating it, and when the route-storyboard supervisor is already up, point the user at its URL instead of suggesting they also hit play. Other Run-button commands (build, test, \u2026) are DB-backed (org-shared + per-user, per project) \u2014 add them with \`configure_run_script\` (\`tempo-scripts-tools\` MCP), not in this file. The home canvas + app dev config stay in the repo, so once the app runs, suggest committing them so teammates get the app Run entry too.
16029
16045
 
16030
16046
  ### Import Resolution
16031
16047
 
@@ -23705,7 +23721,7 @@ function matchClass(line) {
23705
23721
  if (isShellParseAbortOutput(line)) {
23706
23722
  return {
23707
23723
  class: "shell-dialect-mismatch",
23708
- hint: "The dev command failed to PARSE in the shell (Tempo runs commands through cmd.exe on Windows) \u2014 nothing actually ran. This almost always means the command was written in PowerShell syntax, which cmd.exe cannot parse: `if (...) { ... } else { ... }`, `Test-Path`, `$env:FOO`. Rewrite it as a single, plain, cross-platform invocation with no shell conditionals \u2014 e.g. `npm exec -- next dev -p ${PORT}` or `npm run dev -- --port=${PORT}` (chaining with `&&` is fine; cmd supports it). Tempo substitutes `${PORT}` before spawning, so a bare npm/node command runs identically on cmd.exe and POSIX shells. If you need a conditional, cmd's native form is `if exist package.json (...) else (...)`; if the app lives in a subdirectory, set `appDir` in tempo.config.json instead of `cd`/`pushd`-ing inside the command."
23724
+ hint: "The dev command failed to PARSE in the shell (Tempo runs commands through cmd.exe on Windows) \u2014 nothing actually ran. This almost always means the command was written in PowerShell syntax, which cmd.exe cannot parse: `if (...) { ... } else { ... }`, `Test-Path`, `$env:FOO`. Rewrite it as a single, plain, cross-platform invocation with no shell conditionals \u2014 e.g. `npm exec next dev -p ${APP_PORT}` or simply `npm run dev` when it does not need Tempo's optional allocated helper port (legacy `${PORT}` also works). Chaining with `&&` is fine; cmd supports it. If the app lives in a subdirectory, set `appDir` in tempo.config.json instead of `cd`/`pushd`-ing inside the command."
23709
23725
  };
23710
23726
  }
23711
23727
  if (isDevServerLockConflictOutput(line)) {
@@ -24453,6 +24469,7 @@ var AppDevServer = class _AppDevServer {
24453
24469
  this.hasParentDeathWatchdog = false;
24454
24470
  this.options = {
24455
24471
  command: options.command,
24472
+ url: options.url,
24456
24473
  cwd: path12.resolve(options.cwd),
24457
24474
  workspaceRoot: path12.resolve(options.workspaceRoot),
24458
24475
  urlScrapeTimeoutMs: resolveUrlScrapeTimeout(options.urlScrapeTimeoutMs),
@@ -24713,7 +24730,7 @@ var AppDevServer = class _AppDevServer {
24713
24730
  this.recentOutput = [];
24714
24731
  const dialectIssue = findPowerShellSyntax(this.options.command);
24715
24732
  if (dialectIssue) {
24716
- const error = `The app dev command was rejected before spawn: it contains PowerShell-only syntax (${dialectIssue}), which the shell Tempo runs commands with (cmd.exe on Windows) cannot parse \u2014 nothing was started. Rewrite "appStart" in tempo.config.json as a single plain cross-platform command containing \${PORT} \u2014 e.g. "npm run dev -- --port=\${PORT}" \u2014 and if the app lives in a subdirectory set "appDir" instead of cd/pushd-ing inside the command (chaining with \`&&\` is fine; cmd supports it).`;
24733
+ const error = `The app dev command was rejected before spawn: it contains PowerShell-only syntax (${dialectIssue}), which the shell Tempo runs commands with (cmd.exe on Windows) cannot parse \u2014 nothing was started. Rewrite "apps[0].start" in tempo.config.json as a single plain cross-platform command \u2014 use \${APP_PORT} only if it needs Tempo's allocated helper port \u2014 and if the app lives in a subdirectory set "appDir" instead of cd/pushd-ing inside the command (chaining with \`&&\` is fine; cmd supports it).`;
24717
24734
  devLog("app-devserver:shell-dialect-rejected", {
24718
24735
  command: this.options.command,
24719
24736
  construct: dialectIssue
@@ -24745,6 +24762,7 @@ var AppDevServer = class _AppDevServer {
24745
24762
  const command = lifted.command;
24746
24763
  const env = {
24747
24764
  ...process.env,
24765
+ APP_PORT: String(port),
24748
24766
  PORT: String(port),
24749
24767
  TEMPO_APP_PORT: String(port),
24750
24768
  // Activate the Tempo annotation plugin (tempoVitePlugin /
@@ -24767,6 +24785,7 @@ var AppDevServer = class _AppDevServer {
24767
24785
  Object.assign(env, lifted.env);
24768
24786
  devLog("app-devserver:spawn", {
24769
24787
  command,
24788
+ configuredUrl: this.options.url ?? null,
24770
24789
  liftedEnvKeys: Object.keys(lifted.env),
24771
24790
  cwd: this.options.cwd,
24772
24791
  port
@@ -25028,14 +25047,21 @@ Hint: ${hint.hint}` : ""}`;
25028
25047
  });
25029
25048
  }
25030
25049
  async waitForReady(port, signal) {
25031
- const scrapeDeadline = Date.now() + this.options.urlScrapeTimeoutMs;
25032
- while (!this.detectedBaseUrl && Date.now() < scrapeDeadline) {
25033
- throwIfAppLaunchAborted(signal);
25034
- if (!this.child) return null;
25035
- await sleepForAppLaunch(120, signal);
25036
- }
25037
- const baseUrl = this.detectedBaseUrl ?? `http://${PUBLIC_HOSTNAME}:${port}`;
25038
- const publicUrl = rewriteToPublicHost(baseUrl, port);
25050
+ const configuredUrl = this.options.url ? substituteAppPort(this.options.url, port) : null;
25051
+ if (!configuredUrl) {
25052
+ const scrapeDeadline = Date.now() + this.options.urlScrapeTimeoutMs;
25053
+ while (!this.detectedBaseUrl && Date.now() < scrapeDeadline) {
25054
+ throwIfAppLaunchAborted(signal);
25055
+ if (!this.child) return null;
25056
+ await sleepForAppLaunch(120, signal);
25057
+ }
25058
+ }
25059
+ const baseUrl = configuredUrl ?? this.detectedBaseUrl ?? `http://${PUBLIC_HOSTNAME}:${port}`;
25060
+ const publicUrl = rewriteToPublicHost(
25061
+ baseUrl,
25062
+ port,
25063
+ configuredUrl === null
25064
+ );
25039
25065
  const start = Date.now();
25040
25066
  let lastProgressAt = start;
25041
25067
  while (true) {
@@ -25403,17 +25429,17 @@ function extractServerUrl(text) {
25403
25429
  }
25404
25430
  return null;
25405
25431
  }
25406
- function rewriteToPublicHost(url, fallbackPort) {
25432
+ function rewriteToPublicHost(url, fallbackPort, applyFallbackPort = true) {
25407
25433
  try {
25408
25434
  const parsed = new URL(url);
25409
25435
  if (parsed.hostname === "0.0.0.0" || parsed.hostname === "::") {
25410
25436
  parsed.hostname = PUBLIC_HOSTNAME;
25411
25437
  }
25412
- if (!parsed.port) {
25438
+ if (applyFallbackPort && !parsed.port) {
25413
25439
  parsed.port = String(fallbackPort);
25414
25440
  }
25415
25441
  const normalizedPath = parsed.pathname.replace(/\/+$/, "");
25416
- return `${parsed.origin}${normalizedPath}`;
25442
+ return `${parsed.origin}${normalizedPath}${parsed.search}`;
25417
25443
  } catch {
25418
25444
  return `http://${PUBLIC_HOSTNAME}:${fallbackPort}`;
25419
25445
  }
@@ -25504,7 +25530,7 @@ function waitForWatchdogChildPid(watchdog, timeoutMs = 2e3) {
25504
25530
  });
25505
25531
  }
25506
25532
  function substituteAppPort(command, port) {
25507
- return command.replace(/\$\{PORT\}/g, String(port));
25533
+ return command.replace(/\$\{(?:APP_PORT|PORT)\}/g, String(port));
25508
25534
  }
25509
25535
  async function findFreePort(range) {
25510
25536
  const maxAttempts = 50;
@@ -32291,9 +32317,25 @@ function validateAppStart(value, label = "scripts.appStart") {
32291
32317
  );
32292
32318
  }
32293
32319
  const trimmed2 = value.trim();
32294
- if (!trimmed2.includes("${PORT}")) {
32320
+ return trimmed2;
32321
+ }
32322
+ function validateAppUrl(value, label) {
32323
+ if (value === void 0 || value === null) return void 0;
32324
+ if (typeof value !== "string" || value.trim().length === 0) {
32325
+ throw new Error(
32326
+ `tempo.config.json field "${label}" must be a non-empty string when set`
32327
+ );
32328
+ }
32329
+ const trimmed2 = value.trim();
32330
+ let parsed;
32331
+ try {
32332
+ parsed = new URL(trimmed2.replace(/\$\{(?:APP_PORT|PORT)\}/g, "5173"));
32333
+ } catch {
32334
+ throw new Error(`tempo.config.json field "${label}" must be a valid URL`);
32335
+ }
32336
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
32295
32337
  throw new Error(
32296
- `tempo.config.json field "${label}" must include the literal "\${PORT}" token so the supervisor can inject the allocated port (e.g. "npx vite --port=\${PORT} --strictPort" or "npm exec next dev -- -p \${PORT}")`
32338
+ `tempo.config.json field "${label}" must use the "http:" or "https:" protocol`
32297
32339
  );
32298
32340
  }
32299
32341
  return trimmed2;
@@ -32385,9 +32427,7 @@ function validateApps(value) {
32385
32427
  const seenAppDirs = /* @__PURE__ */ new Set();
32386
32428
  return value.map((entry, i) => {
32387
32429
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
32388
- throw new Error(
32389
- `tempo.config.json field "apps[${i}]" must be an object`
32390
- );
32430
+ throw new Error(`tempo.config.json field "apps[${i}]" must be an object`);
32391
32431
  }
32392
32432
  const raw = entry;
32393
32433
  const appDir = validateAppDir(raw.appDir, `apps[${i}].appDir`);
@@ -32404,19 +32444,36 @@ function validateApps(value) {
32404
32444
  }
32405
32445
  seenAppDirs.add(appDir);
32406
32446
  }
32407
- const appStart = validateAppStart(raw.appStart, `apps[${i}].appStart`);
32447
+ const url = validateAppUrl(raw.url, `apps[${i}].url`);
32448
+ const start = validateAppStart(raw.start, `apps[${i}].start`);
32449
+ const legacyAppStart = validateAppStart(
32450
+ raw.appStart,
32451
+ `apps[${i}].appStart`
32452
+ );
32453
+ if (start !== void 0 && legacyAppStart !== void 0 && start !== legacyAppStart) {
32454
+ throw new Error(
32455
+ `tempo.config.json fields "apps[${i}].start" and legacy "apps[${i}].appStart" disagree \u2014 make them match or drop "appStart"`
32456
+ );
32457
+ }
32458
+ const effectiveStart = start ?? legacyAppStart;
32459
+ if (url !== void 0 && effectiveStart === void 0) {
32460
+ throw new Error(
32461
+ `tempo.config.json field "apps[${i}].url" requires "apps[${i}].start"`
32462
+ );
32463
+ }
32408
32464
  const uiFramework = validateUiFramework(
32409
32465
  raw.uiFramework,
32410
32466
  `apps[${i}].uiFramework`
32411
32467
  );
32412
- if (appDir === void 0 && appStart === void 0 && uiFramework === void 0) {
32468
+ if (appDir === void 0 && effectiveStart === void 0 && url === void 0 && uiFramework === void 0) {
32413
32469
  throw new Error(
32414
- `tempo.config.json field "apps[${i}]" must set "appDir", "appStart", and/or "uiFramework" \u2014 an empty entry encodes nothing`
32470
+ `tempo.config.json field "apps[${i}]" must set "appDir", "start", "url", and/or "uiFramework" \u2014 an empty entry encodes nothing`
32415
32471
  );
32416
32472
  }
32417
32473
  return {
32418
32474
  ...appDir !== void 0 ? { appDir } : {},
32419
- ...appStart !== void 0 ? { appStart } : {},
32475
+ ...effectiveStart !== void 0 ? { start: effectiveStart } : {},
32476
+ ...url !== void 0 ? { url } : {},
32420
32477
  ...uiFramework !== void 0 ? { uiFramework } : {}
32421
32478
  };
32422
32479
  });
@@ -32470,11 +32527,10 @@ function validateTempoConfigFile(value) {
32470
32527
  const setupScript = validateSetupScript(raw.setupScript);
32471
32528
  const runScripts = validateRunScripts(raw.runScripts);
32472
32529
  const appStart = validateAppStart(
32473
- scripts.appStart
32474
- );
32475
- const stop = validateScriptsStop(
32476
- scripts.stop
32530
+ scripts.appStart,
32531
+ "scripts.appStart"
32477
32532
  );
32533
+ const stop = validateScriptsStop(scripts.stop);
32478
32534
  if (apps) {
32479
32535
  const activeApp = apps[0];
32480
32536
  if (appDir !== void 0 && appDir !== activeApp.appDir) {
@@ -32482,9 +32538,9 @@ function validateTempoConfigFile(value) {
32482
32538
  `tempo.config.json fields "appDir" ("${appDir}") and "apps[0].appDir" ("${activeApp.appDir}") disagree \u2014 apps[0] is the active app; make them match or drop the legacy "appDir"`
32483
32539
  );
32484
32540
  }
32485
- if (appStart !== void 0 && appStart !== activeApp.appStart) {
32541
+ if (appStart !== void 0 && appStart !== activeApp.start) {
32486
32542
  throw new Error(
32487
- 'tempo.config.json fields "scripts.appStart" and "apps[0].appStart" disagree \u2014 apps[0] is the active app; make them match or drop the legacy "scripts.appStart"'
32543
+ 'tempo.config.json fields "scripts.appStart" and "apps[0].start" disagree \u2014 apps[0] is the active app; make them match or drop the legacy "scripts.appStart"'
32488
32544
  );
32489
32545
  }
32490
32546
  }
@@ -32495,12 +32551,12 @@ function validateTempoConfigFile(value) {
32495
32551
  normalizedApps = [
32496
32552
  {
32497
32553
  ...appDir !== void 0 ? { appDir } : {},
32498
- ...appStart !== void 0 ? { appStart } : {}
32554
+ ...appStart !== void 0 ? { start: appStart } : {}
32499
32555
  }
32500
32556
  ];
32501
32557
  }
32502
32558
  const activeAppDir = normalizedApps ? normalizedApps[0].appDir : void 0;
32503
- const activeAppStart = normalizedApps ? normalizedApps[0].appStart : void 0;
32559
+ const activeAppStart = normalizedApps ? normalizedApps[0].start : void 0;
32504
32560
  return {
32505
32561
  ...paths ? { paths } : {},
32506
32562
  ...urls ? { urls } : {},
@@ -32790,14 +32846,19 @@ async function resolveTempoConfig(projectRoot) {
32790
32846
  if (config.apps && config.apps.length > 0) {
32791
32847
  apps = config.apps.map((app) => ({
32792
32848
  appDir: app.appDir,
32793
- appStart: app.appStart ?? null,
32849
+ start: app.start ?? null,
32850
+ url: app.url ?? null,
32851
+ appStart: app.start ?? null,
32794
32852
  ...app.uiFramework ? { uiFramework: app.uiFramework } : {}
32795
32853
  }));
32796
32854
  } else {
32855
+ const legacyStart = config.scripts.appStart ?? null;
32797
32856
  apps = [
32798
32857
  {
32799
32858
  ...config.appDir !== void 0 ? { appDir: config.appDir } : {},
32800
- appStart: config.scripts.appStart ?? null
32859
+ start: legacyStart,
32860
+ url: null,
32861
+ appStart: legacyStart
32801
32862
  }
32802
32863
  ];
32803
32864
  }
@@ -32814,6 +32875,7 @@ async function resolveTempoConfig(projectRoot) {
32814
32875
  viteConfigPath: path23.join(tempoRoot, "vite.config.ts"),
32815
32876
  tsconfigPath: path23.join(tempoRoot, "tsconfig.json"),
32816
32877
  tempoHostUrl: config.urls?.tempoHost ?? null,
32878
+ appUrl: activeApp.url,
32817
32879
  scripts: {
32818
32880
  install: config.scripts.install,
32819
32881
  start: config.scripts.start,
@@ -44094,11 +44156,11 @@ function registerTools(server, context) {
44094
44156
  ...output,
44095
44157
  warnings: [
44096
44158
  ...output.warnings ?? [],
44097
- "This canvas contains a route storyboard (`<RouteStoryboard>`) but no app dev command (`apps[0].appStart`) is configured in tempo.config.json. Route iframes will fail to load until you configure the user's real app dev server. Read the project root's package.json `scripts.dev`, pick the right port-injection shape for the framework, and call `set_app_dev_command` (must include the literal `${PORT}` token)."
44159
+ "This canvas contains a route storyboard (`<RouteStoryboard>`) but no app dev command (`apps[0].start`) is configured in tempo.config.json. Route iframes will fail to load until you configure the user's real app dev server. Read the project root's package.json `scripts.dev`, then call `set_app_dev_command` with that foreground command and, when known, its HTTP(S) readiness URL. `${APP_PORT}` is an optional allocated-port helper; legacy `${PORT}` remains supported."
44098
44160
  ],
44099
44161
  app_dev_server: {
44100
44162
  configured: false,
44101
- next_step: "Call set_app_dev_command with a command that includes ${PORT}."
44163
+ next_step: "Call set_app_dev_command with start and, when needed, url."
44102
44164
  }
44103
44165
  },
44104
44166
  null,
@@ -44298,7 +44360,7 @@ function registerTools(server, context) {
44298
44360
  start: scaffoldedConfig.scripts.start
44299
44361
  }
44300
44362
  } : void 0;
44301
- const reviewNotes = "UI source framework is explicit: omission means React. If this is a Svelte 5 app, set apps[0].uiFramework to \"svelte\" in tempo.config.json and rerun canvas_project_init before creating storyboards. That rerun fills the generated sidecar's missing svelte and @sveltejs/vite-plugin-svelte dependencies using starter defaults; it preserves existing sidecar package specs. For a Svelte route storyboard, setup is NOT complete until apps[0].appStart contains the literal ${PORT} token, the app's own package depends on tempo-sdk, and a standalone Svelte/Vite app directly dev-depends on @sveltejs/vite-plugin-svelte. Use set_app_dev_command for appStart. Add only missing app packages, choose versions compatible with its existing Svelte/Vite toolchain, and never replace configured versions with Tempo's starter defaults. The app's own Vite/Svelte config must use tempoVitePlugin() plus tempoSveltePreprocess(...) as the first Svelte preprocessor; the generated tempo/ sidecar config does not affect the separately running app. Preserve any existing Svelte preprocessors after Tempo's. Double-check initial_tempo_config's scripts.install against this repo before moving on. A plain package-manager install (bare `npm install`/`pnpm install`/\u2026 or Tempo's chained `cd .. && \u2026 && cd tempo && \u2026` form) means Tempo's DEFAULT behavior: it installs the project root and tempo/ itself with the detected package manager \u2014 correct for most single-package repos. Write a CUSTOM command instead when the default won't produce importable app code: the app lives in a workspace/monorepo subdirectory (install must run at the workspace root or with the right filter), the app needs postinstall codegen (e.g. `prisma generate`), a private registry needs .npmrc/env, or the repo has a non-standard install. A custom value runs verbatim from tempo/ (cmd.exe-compatible syntax only, cover BOTH roots' dependencies) and Tempo NEVER rewrites it. After editing, run start_canvas_devserver({ force_install: true }).";
44363
+ const reviewNotes = "UI source framework is explicit: omission means React. If this is a Svelte 5 app, set apps[0].uiFramework to \"svelte\" in tempo.config.json and rerun canvas_project_init before creating storyboards. That rerun fills the generated sidecar's missing svelte and @sveltejs/vite-plugin-svelte dependencies using starter defaults; it preserves existing sidecar package specs. For a Svelte route storyboard, setup is NOT complete until apps[0].start is configured, the app's own package depends on tempo-sdk, and a standalone Svelte/Vite app directly dev-depends on @sveltejs/vite-plugin-svelte. Use set_app_dev_command for start and its HTTP(S) readiness URL when known; `${APP_PORT}` is an optional allocated-port helper and legacy `${PORT}` remains supported. Add only missing app packages, choose versions compatible with its existing Svelte/Vite toolchain, and never replace configured versions with Tempo's starter defaults. The app's own Vite/Svelte config must use tempoVitePlugin() plus tempoSveltePreprocess(...) as the first Svelte preprocessor; the generated tempo/ sidecar config does not affect the separately running app. Preserve any existing Svelte preprocessors after Tempo's. Double-check initial_tempo_config's scripts.install against this repo before moving on. A plain package-manager install (bare `npm install`/`pnpm install`/\u2026 or Tempo's chained `cd .. && \u2026 && cd tempo && \u2026` form) means Tempo's DEFAULT behavior: it installs the project root and tempo/ itself with the detected package manager \u2014 correct for most single-package repos. Write a CUSTOM command instead when the default won't produce importable app code: the app lives in a workspace/monorepo subdirectory (install must run at the workspace root or with the right filter), the app needs postinstall codegen (e.g. `prisma generate`), a private registry needs .npmrc/env, or the repo has a non-standard install. A custom value runs verbatim from tempo/ (cmd.exe-compatible syntax only, cover BOTH roots' dependencies) and Tempo NEVER rewrites it. After editing, run start_canvas_devserver({ force_install: true }).";
44302
44364
  return textResult2(
44303
44365
  JSON.stringify(
44304
44366
  {
@@ -44412,27 +44474,44 @@ function registerTools(server, context) {
44412
44474
  );
44413
44475
  server.tool(
44414
44476
  "set_app_dev_command",
44415
- "Configure the app dev command in tempo.config.json \u2014 the command that runs the user's REAL app dev server, stored canonically as `apps[0].appStart` (files with the legacy `scripts.appStart` spelling are still read and auto-migrate to `apps[]` on write). Required for route storyboards (`<RouteStoryboard>`) to load real app pages in the canvas iframe. The command MUST contain the literal `${PORT}` token; the per-workspace supervisor allocates a free port and substitutes it at spawn time, so workspaces never collide. Examples: `npx vite --port=${PORT} --strictPort` (Vite), `npm exec next dev -- -p ${PORT}` (Next), `PORT=${PORT} npm run dev` (CRA/Remix/generic), `npx expo start --web --port ${PORT}` (Expo). Invoke the bundler binary directly rather than `<pm> run dev -- --port=${PORT}` \u2014 pnpm forwards the literal `--` through to Vite, which then ignores the port flag and binds its default. Before calling, read the project root's package.json scripts.dev to learn how the user invokes their app, pick the right port-injection shape for the framework, and confirm with the user. When you set this, you should also check the app's own bundler config wires the Tempo plugin (`tempoVitePlugin()` / `tempoNextjsPlugin()` / `tempoExpoBabelPlugin`) and that `tempo-sdk` is an app dependency \u2014 add it if missing, or route storyboard elements won't be selectable. Keep the command a single plain cross-platform invocation \u2014 Tempo runs it via cmd.exe on Windows, substitutes `${PORT}` before spawn, and lifts a leading `NAME=value` prefix (the CRA/Remix shape) into the spawn environment, so all four example shapes work everywhere; never use PowerShell syntax (`if (Test-Path \u2026) { \u2026 } else { \u2026 }`, `Test-Path`, `$env:FOO`, `Get-`/`Set-` cmdlets) \u2014 cmd.exe cannot parse it, so this tool rejects PowerShell-shaped commands \u2014 and for a subdirectory set `appDir` instead of cd/pushd-ing (`&&` chaining is valid on cmd but shouldn't be needed here). Once set, it surfaces in the workspace header's Run (play) button under \"Org run scripts\" as a read-only \"App dev server\" entry \u2014 don't also add it as a run script. Pass null/empty to clear. Idempotent \u2014 safe to re-run with a revised command.",
44477
+ "Configure the user's REAL app dev server in tempo.config.json, stored canonically as `apps[0].start` plus optional `apps[0].url`. Legacy `apps[0].appStart` and `scripts.appStart` still read and migrate to `start` on write. Required for route storyboards. `start` may be any foreground command. `url`, when set, is only the HTTP(S) readiness target and route base: it is probed as written, never controls local allocation, and may point through a container, tunnel, or remote machine. Tempo exposes its independently allocated helper port through `${APP_PORT}` and still accepts legacy `${PORT}` in app start/URL fields. Invoke commands directly, keep them cross-platform, and use appDir for subdirectory apps. At least one of command/url must be provided; null clears that field. Idempotent.",
44416
44478
  {
44417
44479
  command: z23.string().nullish().describe(
44418
- "The command string. Must include the literal `${PORT}` token. Pass null or an empty string to clear the setting."
44480
+ "The canonical apps[0].start foreground command. It may be arbitrary; use `${APP_PORT}` when the command should consume Tempo's allocated helper port. Legacy `${PORT}` remains supported. Omit to leave unchanged; pass null/empty to clear the app server configuration."
44481
+ ),
44482
+ url: z23.string().nullish().describe(
44483
+ "Optional canonical apps[0].url. This is the HTTP(S) readiness target and route base only. It may contain `${APP_PORT}` (or legacy `${PORT}`) or be any literal reachable HTTP(S) URL, including a container, tunnel, or remote host; it never controls local port allocation. Omit to leave unchanged; pass null/empty to clear only this field."
44419
44484
  ),
44420
44485
  ...appDevServerTargetArgs
44421
44486
  },
44422
- async ({ command, repo_root, app_dir }) => {
44487
+ async ({ command, url, repo_root, app_dir }) => {
44423
44488
  if (!context.appDevServer)
44424
44489
  return unsupportedEnvironmentResult("appDevServer");
44425
- const value = typeof command === "string" && command.trim().length > 0 ? command.trim() : null;
44490
+ if (command === void 0 && url === void 0) {
44491
+ return errorResult9("Provide command and/or url to update.");
44492
+ }
44493
+ const startValue = command === void 0 ? void 0 : typeof command === "string" && command.trim().length > 0 ? command.trim() : null;
44494
+ const urlValue = url === void 0 ? void 0 : typeof url === "string" && url.trim().length > 0 ? url.trim() : null;
44426
44495
  try {
44427
- await context.appDevServer.setCommand(
44428
- value,
44496
+ await context.appDevServer.setConfig(
44497
+ {
44498
+ ...startValue !== void 0 ? { start: startValue } : {},
44499
+ ...urlValue !== void 0 ? { url: urlValue } : {}
44500
+ },
44429
44501
  toAppDevServerTarget({ repo_root, app_dir })
44430
44502
  );
44431
44503
  return textResult2(
44432
44504
  JSON.stringify(
44433
44505
  {
44434
- app_dev_command: value,
44435
- note: value ? "Saved. The supervisor will allocate a port and start the server when a canvas with route storyboards is opened. Before declaring setup complete, verify the app itself depends on tempo-sdk and its own bundler config carries Tempo instrumentation. For standalone Svelte/Vite, add @sveltejs/vite-plugin-svelte only if missing, using a version compatible with the app's existing toolchain; preserve configured versions. Use tempoVitePlugin() plus tempoSveltePreprocess(...) first in the Svelte preprocess chain. tempo/ only configures the sidecar." : "Cleared."
44506
+ // Preserve the original result field for callers that inspect
44507
+ // tool output instead of only the tool arguments.
44508
+ ...startValue !== void 0 ? { app_dev_command: startValue } : {},
44509
+ ...urlValue !== void 0 ? { app_dev_url: urlValue } : {},
44510
+ app_dev_config_update: {
44511
+ ...startValue !== void 0 ? { start: startValue } : {},
44512
+ ...urlValue !== void 0 ? { url: urlValue } : {}
44513
+ },
44514
+ note: startValue === null ? "Cleared." : "Saved. The supervisor allocates the optional local `${APP_PORT}` helper independently (legacy `${PORT}` remains supported); a configured URL is probed exactly as the readiness target and route base. Before declaring setup complete, verify the app depends on tempo-sdk and its own bundler config carries Tempo instrumentation. For standalone Svelte/Vite, add @sveltejs/vite-plugin-svelte only if missing, preserve compatible configured versions, and use tempoVitePlugin() plus tempoSveltePreprocess(...) first in the app's preprocess chain; tempo/ only configures the sidecar."
44436
44515
  },
44437
44516
  null,
44438
44517
  2
@@ -44447,7 +44526,7 @@ function registerTools(server, context) {
44447
44526
  );
44448
44527
  server.tool(
44449
44528
  "check_app_dev_server",
44450
- "Check the per-workspace app dev server (the user's REAL app, supervised via the app dev command in tempo.config.json \u2014 `apps[0].appStart`, legacy `scripts.appStart` also read; used by route storyboards). Returns `{configured, running, phase, port, url, error}`. Use this when a route storyboard isn't rendering to confirm whether the server is up and where (port + url) \u2014 analogous to `check_canvas_devserver` for the canvas sidecar. `configured: false` means the app dev command is unset; call `set_app_dev_command` first. `phase: 'error'` carries the supervisor's stderr in `error` \u2014 the actual failure reason.",
44529
+ "Check the per-workspace app dev server configured by canonical `apps[0].start`/`url` (legacy appStart spellings also read). Returns `{configured, running, phase, port, url, error}`. Use this when a route storyboard isn't rendering. `configured: false` means start is unset; `phase: 'error'` carries the supervisor failure.",
44451
44530
  { ...appDevServerTargetArgs },
44452
44531
  async ({ repo_root, app_dir }) => {
44453
44532
  if (!context.appDevServer)
@@ -44466,7 +44545,7 @@ function registerTools(server, context) {
44466
44545
  );
44467
44546
  server.tool(
44468
44547
  "start_app_dev_server",
44469
- "Start the per-workspace app dev server if it isn't already running. Spawns the configured app dev command (with `${PORT}` substituted to an allocated free port), persists the port assignment under `<workspaceRoot>/.tempo/app-devserver.json`, and HTTP-gates readiness. No-op if already running \u2014 returns the live status. When no app dev command is configured, returns `{configured: false}` and the agent should call `set_app_dev_command` first. Analogous to `start_canvas_devserver` but for the user's real app server, not the canvas sidecar. Use when the renderer-driven warm-on-canvas-mount path isn't enough (e.g. you're driving the canvas headlessly, the user explicitly asked to start it, or the supervisor reports `phase: 'stopped'` after the 5-minute idle-stop).",
44548
+ "Start the per-workspace app dev server if it isn't already running. Spawns canonical `apps[0].start`, substitutes `${APP_PORT}` (or legacy `${PORT}`) in start/url, persists the independently selected local helper port under `<workspaceRoot>/.tempo/app-devserver.json`, and HTTP-gates readiness against the configured URL or detected local URL. A literal URL is probed as written and does not affect local allocation. No-op if already running. When start is unset, returns `{configured: false}`; call `set_app_dev_command` first.",
44470
44549
  { ...appDevServerTargetArgs },
44471
44550
  async ({ repo_root, app_dir }) => {
44472
44551
  if (!context.appDevServer)
@@ -45143,7 +45222,7 @@ function isExternallyExposed(toolName, opts) {
45143
45222
  }
45144
45223
 
45145
45224
  // src/version.ts
45146
- var CLI_VERSION = "0.0.102";
45225
+ var CLI_VERSION = "0.0.103";
45147
45226
 
45148
45227
  // src/canvas-hooks.ts
45149
45228
  var import_pngjs3 = __toESM(require_png(), 1);
@@ -47117,4 +47196,4 @@ export {
47117
47196
  runServe,
47118
47197
  scopeParamsFor
47119
47198
  };
47120
- //# sourceMappingURL=serve-NGUFKD5I.js.map
47199
+ //# sourceMappingURL=serve-P7M4UFJS.js.map