ponzu 1.71.1 → 1.71.2

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 (2) hide show
  1. package/dist/index.js +195 -95
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6978,7 +6978,7 @@ var require_dist = __commonJS(function(exports, module) {
6978
6978
  // apps/cli/src/index.ts
6979
6979
  import { existsSync as existsSync13 } from "fs";
6980
6980
  import { networkInterfaces } from "os";
6981
- import { dirname as dirname12, isAbsolute as isAbsolute4, join as join20, resolve as resolve5 } from "path";
6981
+ import { dirname as dirname13, isAbsolute as isAbsolute4, join as join21, resolve as resolve5 } from "path";
6982
6982
  import { fileURLToPath as fileURLToPath2 } from "url";
6983
6983
  import { parseArgs } from "util";
6984
6984
 
@@ -33328,7 +33328,7 @@ When to watch: whenever the person might react to the work on the canvas. That's
33328
33328
 
33329
33329
  Watching doesn't cut you off from chat. A message the person types reaches you as soon as the current wait returns, within a minute. To tell them something (here's the link, which option you'd pick), write it in chat, then keep watching.
33330
33330
 
33331
- 1. listen: wait_for_activity with the cursor from your last call. Start with types comment.created, comment.replied, comment.edited, file.changed. An edit replaces what the comment asks; work from the new text. If the wait says Ponzu restarted or lost track, it lists the open threads waiting on you instead: work through those, then carry on with the cursor it gives. The wait hears from every file you've worked in this session and names the file for any event outside the one you passed: pass that file when you act on it.
33331
+ 1. listen: wait_for_activity with the cursor from your last call. Start with types comment.created, comment.replied, comment.edited, file.changed. An edit replaces what the comment asks; work from the new text. If the wait says Ponzu restarted or lost track, it lists the open threads waiting on you instead: work through those, then carry on with the cursor it gives. If it says Ponzu stopped and isn't back yet, nothing was checked: wait again with the cursor it gives, as Ponzu is most likely restarting into an update. The wait hears from every file you've worked in this session and names the file for any event outside the one you passed: pass that file when you act on it.
33332
33332
  2. triage each comment:
33333
33333
  - change ("make this bigger", "try blue"): do it.
33334
33334
  - question ("why this font?"): reply with an answer, leave it open.
@@ -33542,7 +33542,7 @@ var listenTools = [
33542
33542
  title: "Wait for activity",
33543
33543
  group: "listen",
33544
33544
  readOnly: true,
33545
- description: "Watch the canvas. Call this instead of ending your turn whenever the person might react to your work there: after you put something up for review, or while you design together. Calling it again and again is the loop (get_guide('watch')). Long-polls for what people do in the canvas: new comments and replies, edits made in a text editor, other agents' changes, in this file and the others you've worked in this session, saying which file each is in. Returns immediately if anything happened after `since`; otherwise waits up to `timeout` seconds. Pass back the returned cursor next time so nothing is missed. If Ponzu restarted or lost track since then, it returns at once with the open threads waiting on you. The person's chat messages still reach you between waits.",
33545
+ description: "Watch the canvas. Call this instead of ending your turn whenever the person might react to your work there: after you put something up for review, or while you design together. Calling it again and again is the loop (get_guide('watch')). Long-polls for what people do in the canvas: new comments and replies, edits made in a text editor, other agents' changes, in this file and the others you've worked in this session, saying which file each is in. Returns immediately if anything happened after `since`; otherwise waits up to `timeout` seconds. Pass back the returned cursor next time so nothing is missed. If Ponzu restarts during the wait, the wait carries on once it's back. If it restarted or lost track before you waited, it returns at once with the open threads waiting on you: handle those, then keep watching with the cursor it gives. The person's chat messages still reach you between waits.",
33546
33546
  input: {
33547
33547
  file: fileArg,
33548
33548
  since: number2().int().min(0).optional().describe("Cursor from the last call. Omit to start from now."),
@@ -33571,7 +33571,7 @@ var listenTools = [
33571
33571
  const waiting = waitingText(files, all);
33572
33572
  return {
33573
33573
  text: `${GAP_NOTE[gap]} ${waiting.text}
33574
- Wait again with cursor=${next}.`,
33574
+ Keep watching: wait again with cursor=${next}.`,
33575
33575
  data: { cursor: next, events: [], gap, waiting: waiting.ids },
33576
33576
  metrics: { cursor: gap, events: 0, scope_files: files.length }
33577
33577
  };
@@ -36773,6 +36773,7 @@ data:
36773
36773
 
36774
36774
  // packages/mcp/src/index.ts
36775
36775
  var FILES_META = "ponzu.design/files";
36776
+ var WAIT_META = "ponzu.design/wait";
36776
36777
  function clientKind(name = "") {
36777
36778
  const n = name.toLowerCase();
36778
36779
  if (n.includes("claude"))
@@ -36841,7 +36842,7 @@ function createMcpServer(ws, opts = {}) {
36841
36842
  destructiveHint: def.destructive ?? false,
36842
36843
  openWorldHint: false
36843
36844
  }
36844
- }, async (args, extra) => toMcp(await runTool(def, args, { ws, caller: getCaller(), signal: extra.signal, session }), session));
36845
+ }, async (args, extra) => toMcp(await runTool(def, args, { ws, caller: getCaller(), signal: extra.signal, session }), session, def.name));
36845
36846
  }
36846
36847
  for (const [topic, text] of Object.entries(GUIDES)) {
36847
36848
  server.registerResource(`guide-${topic}`, `ponzu://guide/${topic}`, { title: `Ponzu guide: ${topic}`, mimeType: "text/markdown" }, async (uri) => ({ contents: [{ uri: uri.href, mimeType: "text/markdown", text }] }));
@@ -36880,13 +36881,19 @@ Read get_guide('basics'). Write the brief and your direction to a note, set toke
36880
36881
  }));
36881
36882
  return server;
36882
36883
  }
36883
- function toMcp(r, session) {
36884
+ function toMcp(r, session, tool) {
36884
36885
  const content = [];
36885
36886
  for (const img of r.images ?? [])
36886
36887
  content.push({ type: "image", data: img.data, mimeType: img.mime });
36887
36888
  content.push({ type: "text", text: r.text });
36888
- const files = session.files?.length ? { _meta: { [FILES_META]: session.files } } : {};
36889
- return { content, isError: r.isError, ...files };
36889
+ const meta = {};
36890
+ if (session.files?.length)
36891
+ meta[FILES_META] = session.files;
36892
+ if (tool === "wait_for_activity" && r.data) {
36893
+ const { cursor, gap, waiting } = r.data;
36894
+ meta[WAIT_META] = { cursor, ...gap ? { gap, waiting: waiting?.length ?? 0 } : {} };
36895
+ }
36896
+ return { content, isError: r.isError, ...Object.keys(meta).length ? { _meta: meta } : {} };
36890
36897
  }
36891
36898
  function createHttpHandler(ws, opts = {}) {
36892
36899
  const sessions = new Map;
@@ -37085,6 +37092,7 @@ function onBodyDone(res, done) {
37085
37092
 
37086
37093
  // packages/mcp/src/bridge.ts
37087
37094
  var CALL_TIMEOUT = 15 * 60000;
37095
+ var RESTART_GRACE = 1e4;
37088
37096
  var readOnly = new Set(tools.filter((t) => t.readOnly).map((t) => t.name));
37089
37097
  async function serveBridge(opts, transport = new StdioServerTransport) {
37090
37098
  const server = new Server({ name: opts.name ?? "ponzu", version: opts.version ?? "0.1.0", title: "Ponzu" }, {
@@ -37214,19 +37222,70 @@ async function serveBridge(opts, transport = new StdioServerTransport) {
37214
37222
  return fn(await localClient(), extra.signal);
37215
37223
  }
37216
37224
  };
37217
- server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
37218
- const name = req.params.name;
37219
- const args = req.params.arguments ?? {};
37220
- const params = { ...req.params, arguments: opts.mapArgs ? opts.mapArgs(name, args) : args };
37221
- const options = { signal: extra.signal, timeout: CALL_TIMEOUT };
37225
+ const hostBack = async (until, signal) => {
37226
+ const giveUp = Math.min(until, Date.now() + (opts.restartGrace ?? RESTART_GRACE));
37227
+ while (!signal.aborted) {
37228
+ if (await opts.findHost(false).catch(() => null))
37229
+ return true;
37230
+ if (Date.now() >= giveUp)
37231
+ return false;
37232
+ await new Promise((r) => setTimeout(r, 250));
37233
+ }
37234
+ return false;
37235
+ };
37236
+ const waitThrough = async (params, signal) => {
37237
+ const { since, timeout } = params.arguments ?? {};
37238
+ const deadline = Date.now() + (typeof timeout === "number" ? timeout : 60) * 1000;
37239
+ const left = () => Math.max(0, Math.ceil((deadline - Date.now()) / 1000));
37240
+ const withArgs = (more) => ({
37241
+ ...params,
37242
+ arguments: { ...params.arguments, ...more }
37243
+ });
37244
+ let cutOff = false;
37245
+ const result = await call(params, signal, async () => {
37246
+ cutOff = true;
37247
+ if (!await hostBack(deadline, signal) && Date.now() >= deadline)
37248
+ return null;
37249
+ return withArgs({ timeout: left() });
37250
+ });
37251
+ if (!result) {
37252
+ const again = typeof since === "number" ? `Wait again with cursor=${since}` : "Wait again";
37253
+ return {
37254
+ content: [
37255
+ {
37256
+ type: "text",
37257
+ text: `Ponzu stopped while you waited and isn't back yet, so nothing was checked. ${again}: it's most likely restarting into an update.`
37258
+ }
37259
+ ]
37260
+ };
37261
+ }
37262
+ const wait = result._meta?.[WAIT_META];
37263
+ if (!cutOff || wait?.gap !== "restart" || wait.waiting || !left())
37264
+ return result;
37265
+ const again = await call(withArgs({ since: wait.cursor, timeout: left() }), signal);
37266
+ const first = again.content.findIndex((c) => c.type === "text");
37267
+ return {
37268
+ ...again,
37269
+ content: again.content.map((c, i) => i === first && c.type === "text" ? {
37270
+ ...c,
37271
+ text: `Ponzu restarted while you waited, with nothing waiting on you.
37272
+ ${c.text}`
37273
+ } : c)
37274
+ };
37275
+ };
37276
+ const call = async (params, signal, cutOff) => {
37277
+ const name = params.name;
37278
+ let sent = params;
37279
+ let ridden = cutOff;
37280
+ const options = { signal, timeout: CALL_TIMEOUT };
37222
37281
  for (let attempt = 0;attempt < 2; attempt++) {
37223
37282
  const client = await hostClient();
37224
37283
  if (!client)
37225
37284
  break;
37226
37285
  try {
37227
- return remember(await using(client, () => client.request({ method: "tools/call", params }, CallToolResultSchema, options)));
37286
+ return remember(await using(client, () => client.request({ method: "tools/call", params: sent }, CallToolResultSchema, options)));
37228
37287
  } catch (err) {
37229
- if (extra.signal.aborted || err instanceof McpError && err.code !== ErrorCode.ConnectionClosed)
37288
+ if (signal.aborted || err instanceof McpError && err.code !== ErrorCode.ConnectionClosed)
37230
37289
  throw err;
37231
37290
  await dropHost(client);
37232
37291
  if (!neverArrived(err) && !readOnly.has(name)) {
@@ -37240,10 +37299,27 @@ async function serveBridge(opts, transport = new StdioServerTransport) {
37240
37299
  isError: true
37241
37300
  };
37242
37301
  }
37302
+ if (ridden && !neverArrived(err)) {
37303
+ const next = await ridden();
37304
+ if (!next)
37305
+ return null;
37306
+ sent = next;
37307
+ ridden = undefined;
37308
+ }
37243
37309
  }
37244
37310
  }
37311
+ if (sent !== params)
37312
+ return null;
37245
37313
  await opts.prepareLocal?.();
37246
- return remember(await (await localClient()).request({ method: "tools/call", params }, CallToolResultSchema, options));
37314
+ return remember(await (await localClient()).request({ method: "tools/call", params: sent }, CallToolResultSchema, options));
37315
+ };
37316
+ server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
37317
+ const name = req.params.name;
37318
+ const args = req.params.arguments ?? {};
37319
+ const params = { ...req.params, arguments: opts.mapArgs ? opts.mapArgs(name, args) : args };
37320
+ if (name === "wait_for_activity")
37321
+ return waitThrough(params, extra.signal);
37322
+ return await call(params, extra.signal);
37247
37323
  });
37248
37324
  server.setRequestHandler(ListToolsRequestSchema, (req, extra) => list((c, signal) => c.listTools(req.params, { signal }))(req, extra));
37249
37325
  server.setRequestHandler(ListResourcesRequestSchema, (req, extra) => list((c, signal) => c.listResources(req.params, { signal }))(req, extra));
@@ -47640,7 +47716,7 @@ function remoteUpdater(endpoint, token) {
47640
47716
  // apps/cli/package.json
47641
47717
  var package_default = {
47642
47718
  name: "ponzu",
47643
- version: "1.71.1",
47719
+ version: "1.71.2",
47644
47720
  description: "The open source canvas your agent draws on in HTML and CSS.",
47645
47721
  type: "module",
47646
47722
  license: "MIT",
@@ -47663,17 +47739,40 @@ var package_default = {
47663
47739
 
47664
47740
  // apps/cli/src/host.ts
47665
47741
  import { spawn as spawn6 } from "child_process";
47666
- import { existsSync as existsSync9, readFileSync as readFileSync2, statSync as statSync3 } from "fs";
47742
+ import { existsSync as existsSync9, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
47667
47743
  import { chmod, copyFile, mkdir as mkdir11, rename as rename9, rm as rm5, utimes as utimes3, writeFile as writeFile9 } from "fs/promises";
47744
+ import { homedir as homedir6 } from "os";
47745
+ import { dirname as dirname7, join as join15, posix, win32 } from "path";
47746
+
47747
+ // packages/server/src/updating.ts
47748
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, rmSync, writeFileSync } from "fs";
47668
47749
  import { homedir as homedir5 } from "os";
47669
- import { dirname as dirname6, join as join14, posix, win32 } from "path";
47670
- var ponzuHome = () => process.env.PONZU_HOME ?? join14(homedir5(), ".ponzu");
47671
- var hostFile = () => join14(ponzuHome(), "host.json");
47750
+ import { dirname as dirname6, join as join14 } from "path";
47751
+ var UPDATING_WITHIN = 2 * 60000;
47752
+ var updatingFile = () => join14(process.env.PONZU_HOME ?? join14(homedir5(), ".ponzu"), "updating.json");
47753
+ function read() {
47754
+ try {
47755
+ const u = JSON.parse(readFileSync2(updatingFile(), "utf8"));
47756
+ if (typeof u.from !== "string" || typeof u.to !== "string" || typeof u.at !== "number")
47757
+ return null;
47758
+ return { from: u.from, to: u.to, at: u.at, ...u.told ? { told: true } : {} };
47759
+ } catch {
47760
+ return null;
47761
+ }
47762
+ }
47763
+ function updating(now = Date.now()) {
47764
+ const u = read();
47765
+ return u && now - u.at < UPDATING_WITHIN ? u : null;
47766
+ }
47767
+
47768
+ // apps/cli/src/host.ts
47769
+ var ponzuHome = () => process.env.PONZU_HOME ?? join15(homedir6(), ".ponzu");
47770
+ var hostFile = () => join15(ponzuHome(), "host.json");
47672
47771
  async function announceHost(url, opts = {}) {
47673
47772
  if (!opts.takeOver && await runningHost())
47674
47773
  return async () => {};
47675
47774
  const path = hostFile();
47676
- await mkdir11(dirname6(path), { recursive: true });
47775
+ await mkdir11(dirname7(path), { recursive: true });
47677
47776
  const me = { url, mcp: `${url}/mcp`, pid: process.pid };
47678
47777
  await writeFile9(path, `${JSON.stringify(me)}
47679
47778
  `);
@@ -47684,7 +47783,7 @@ async function announceHost(url, opts = {}) {
47684
47783
  }
47685
47784
  function readHost() {
47686
47785
  try {
47687
- return JSON.parse(readFileSync2(hostFile(), "utf8"));
47786
+ return JSON.parse(readFileSync3(hostFile(), "utf8"));
47688
47787
  } catch {
47689
47788
  return null;
47690
47789
  }
@@ -47703,11 +47802,11 @@ async function runningHost() {
47703
47802
  }
47704
47803
  var SERVER = "Contents/Resources/server/ponzu";
47705
47804
  var pathFor = (os) => os === "win32" ? win32 : posix;
47706
- var appImageServer = () => join14(ponzuHome(), "app/ponzu");
47707
- var appImageRecord = () => join14(ponzuHome(), "app/appimage");
47805
+ var appImageServer = () => join15(ponzuHome(), "app/ponzu");
47806
+ var appImageRecord = () => join15(ponzuHome(), "app/appimage");
47708
47807
  function recordedAppImage() {
47709
47808
  try {
47710
- const path = readFileSync2(appImageRecord(), "utf8").trim();
47809
+ const path = readFileSync3(appImageRecord(), "utf8").trim();
47711
47810
  return path && existsSync9(path) ? path : null;
47712
47811
  } catch {
47713
47812
  return null;
@@ -47722,7 +47821,7 @@ function isFolder(app) {
47722
47821
  }
47723
47822
  function appServer(app, os = process.platform) {
47724
47823
  if (os === "darwin")
47725
- return join14(app, SERVER);
47824
+ return join15(app, SERVER);
47726
47825
  const path = pathFor(os);
47727
47826
  if (os === "linux" && !isFolder(app))
47728
47827
  return appImageServer();
@@ -47755,7 +47854,7 @@ function ownBundle(execPath = process.execPath, os = process.platform, env = pro
47755
47854
  }
47756
47855
  function installedApps(os = process.platform, env = process.env) {
47757
47856
  if (os === "darwin")
47758
- return ["/Applications/Ponzu.app", join14(homedir5(), "Applications/Ponzu.app")];
47857
+ return ["/Applications/Ponzu.app", join15(homedir6(), "Applications/Ponzu.app")];
47759
47858
  if (os === "win32") {
47760
47859
  return [
47761
47860
  env.LOCALAPPDATA && win32.join(env.LOCALAPPDATA, "Programs", "ponzu"),
@@ -47788,7 +47887,7 @@ async function adoptAppImage(execPath = process.execPath, os = process.platform,
47788
47887
  const from = statSync3(execPath);
47789
47888
  const to = statSync3(copy, { throwIfNoEntry: false });
47790
47889
  if (!to || to.size !== from.size || Math.trunc(to.mtimeMs) !== Math.trunc(from.mtimeMs)) {
47791
- await mkdir11(dirname6(copy), { recursive: true });
47890
+ await mkdir11(dirname7(copy), { recursive: true });
47792
47891
  const temp = `${copy}.${process.pid}`;
47793
47892
  await copyFile(execPath, temp);
47794
47893
  await chmod(temp, 493);
@@ -47803,7 +47902,7 @@ async function adoptAppImage(execPath = process.execPath, os = process.platform,
47803
47902
  async function launchApp(app, timeoutMs = 30000) {
47804
47903
  const deadline = Date.now() + timeoutMs;
47805
47904
  for (let tick = 0;Date.now() < deadline; tick++) {
47806
- if (tick % 40 === 0)
47905
+ if (tick % 40 === 0 && !updating())
47807
47906
  startApp(app);
47808
47907
  const url = await runningHost();
47809
47908
  if (url)
@@ -47852,7 +47951,7 @@ async function findHost(launch) {
47852
47951
  lastFailed = Date.now();
47853
47952
  return url;
47854
47953
  }
47855
- var shimPath = (os = process.platform) => join14(ponzuHome(), os === "win32" ? "bin/ponzu.cmd" : "bin/ponzu");
47954
+ var shimPath = (os = process.platform) => join15(ponzuHome(), os === "win32" ? "bin/ponzu.cmd" : "bin/ponzu");
47856
47955
  function shimScript(app, os = process.platform) {
47857
47956
  if (os === "win32") {
47858
47957
  const candidates = [
@@ -47897,7 +47996,7 @@ exit 1
47897
47996
  }
47898
47997
  async function writeShim(app) {
47899
47998
  const path = shimPath();
47900
- await mkdir11(dirname6(path), { recursive: true });
47999
+ await mkdir11(dirname7(path), { recursive: true });
47901
48000
  await writeFile9(path, shimScript(app));
47902
48001
  await chmod(path, 493);
47903
48002
  return path;
@@ -47905,28 +48004,28 @@ async function writeShim(app) {
47905
48004
 
47906
48005
  // apps/cli/src/install.ts
47907
48006
  import { spawnSync as spawnSync2 } from "child_process";
47908
- import { existsSync as existsSync11, readFileSync as readFileSync4 } from "fs";
48007
+ import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
47909
48008
  import { mkdir as mkdir13, writeFile as writeFile11 } from "fs/promises";
47910
- import { homedir as homedir7 } from "os";
47911
- import { delimiter as delimiter2, dirname as dirname8, join as join16 } from "path";
48009
+ import { homedir as homedir8 } from "os";
48010
+ import { delimiter as delimiter2, dirname as dirname9, join as join17 } from "path";
47912
48011
 
47913
48012
  // apps/cli/src/command.ts
47914
48013
  import { spawnSync } from "child_process";
47915
- import { accessSync, constants, existsSync as existsSync10, lstatSync, readFileSync as readFileSync3, realpathSync as realpathSync3 } from "fs";
48014
+ import { accessSync, constants, existsSync as existsSync10, lstatSync, readFileSync as readFileSync4, realpathSync as realpathSync3 } from "fs";
47916
48015
  import { mkdir as mkdir12, symlink, writeFile as writeFile10 } from "fs/promises";
47917
- import { homedir as homedir6 } from "os";
47918
- import { delimiter, dirname as dirname7, join as join15 } from "path";
47919
- function commandDirs(home = homedir6()) {
47920
- return [join15(home, ".local/bin"), join15(home, "bin"), "/usr/local/bin"];
48016
+ import { homedir as homedir7 } from "os";
48017
+ import { delimiter, dirname as dirname8, join as join16 } from "path";
48018
+ function commandDirs(home = homedir7()) {
48019
+ return [join16(home, ".local/bin"), join16(home, "bin"), "/usr/local/bin"];
47921
48020
  }
47922
- var stateFile = () => join15(ponzuHome(), "command.json");
48021
+ var stateFile = () => join16(ponzuHome(), "command.json");
47923
48022
  async function linkCommand(shim, opts) {
47924
48023
  const say = (s) => {
47925
48024
  if (!opts.auto)
47926
48025
  console.log(s);
47927
48026
  };
47928
48027
  if (process.platform === "win32")
47929
- return addToUserPath(dirname7(shim), opts.auto, say);
48028
+ return addToUserPath(dirname8(shim), opts.auto, say);
47930
48029
  const found = Bun.which("ponzu", { PATH: opts.path.join(delimiter) });
47931
48030
  const app = found && opensApp(found) ? found : null;
47932
48031
  if (found && !app) {
@@ -47937,16 +48036,16 @@ async function linkCommand(shim, opts) {
47937
48036
  const state = readState();
47938
48037
  if (opts.auto && state.linked)
47939
48038
  return;
47940
- const before = app ? opts.path.indexOf(dirname7(app)) : -1;
48039
+ const before = app ? opts.path.indexOf(dirname8(app)) : -1;
47941
48040
  const dir = commandDirs(opts.home).find((d) => {
47942
48041
  const at = opts.path.indexOf(d);
47943
48042
  return at >= 0 && (before < 0 || at < before) && canLink(d, opts.home);
47944
48043
  });
47945
48044
  if (!dir) {
47946
- say(process.platform === "darwin" ? `To run ponzu from a terminal, add ${dirname7(shim)} to your PATH, or choose Install Terminal Command in Ponzu's app menu.` : `To run ponzu from a terminal, add ${dirname7(shim)} to your PATH.`);
48045
+ say(process.platform === "darwin" ? `To run ponzu from a terminal, add ${dirname8(shim)} to your PATH, or choose Install Terminal Command in Ponzu's app menu.` : `To run ponzu from a terminal, add ${dirname8(shim)} to your PATH.`);
47947
48046
  return;
47948
48047
  }
47949
- const link = join15(dir, "ponzu");
48048
+ const link = join16(dir, "ponzu");
47950
48049
  try {
47951
48050
  await mkdir12(dir, { recursive: true });
47952
48051
  await symlink(shim, link);
@@ -47954,7 +48053,7 @@ async function linkCommand(shim, opts) {
47954
48053
  say(`Couldn't link ponzu into ${dir}.`);
47955
48054
  return;
47956
48055
  }
47957
- await mkdir12(dirname7(stateFile()), { recursive: true });
48056
+ await mkdir12(dirname8(stateFile()), { recursive: true });
47958
48057
  await writeFile10(stateFile(), `${JSON.stringify({ linked: link }, null, 2)}
47959
48058
  `);
47960
48059
  say(`Linked ${link}, so ponzu runs from a terminal.`);
@@ -47993,21 +48092,21 @@ async function addToUserPath(dir, auto, say) {
47993
48092
  return;
47994
48093
  if (userPath(dir, true) !== "added")
47995
48094
  return say(`Couldn't add ${dir} to your PATH. Add it yourself to run ponzu from a terminal.`);
47996
- await mkdir12(dirname7(stateFile()), { recursive: true });
48095
+ await mkdir12(dirname8(stateFile()), { recursive: true });
47997
48096
  await writeFile10(stateFile(), `${JSON.stringify({ linked: dir }, null, 2)}
47998
48097
  `);
47999
48098
  say(`Added ${dir} to your PATH. Open a new terminal and run ponzu.`);
48000
48099
  }
48001
48100
  function readState() {
48002
48101
  try {
48003
- return JSON.parse(readFileSync3(stateFile(), "utf8"));
48102
+ return JSON.parse(readFileSync4(stateFile(), "utf8"));
48004
48103
  } catch {
48005
48104
  return {};
48006
48105
  }
48007
48106
  }
48008
- function canLink(dir, home = homedir6()) {
48107
+ function canLink(dir, home = homedir7()) {
48009
48108
  try {
48010
- lstatSync(join15(dir, "ponzu"));
48109
+ lstatSync(join16(dir, "ponzu"));
48011
48110
  return false;
48012
48111
  } catch {}
48013
48112
  if (!existsSync10(dir))
@@ -48021,7 +48120,7 @@ function canLink(dir, home = homedir6()) {
48021
48120
  }
48022
48121
  function opensApp(file) {
48023
48122
  try {
48024
- return existsSync10(join15(dirname7(realpathSync3(file)), "resources/server/ponzu"));
48123
+ return existsSync10(join16(dirname8(realpathSync3(file)), "resources/server/ponzu"));
48025
48124
  } catch {
48026
48125
  return false;
48027
48126
  }
@@ -48041,7 +48140,7 @@ var AGENTS = [
48041
48140
  label: "Claude Code",
48042
48141
  detect: () => Boolean(which("claude")),
48043
48142
  current: () => {
48044
- const config = readJson(join16(homedir7(), ".claude.json"));
48143
+ const config = readJson(join17(homedir8(), ".claude.json"));
48045
48144
  return toEntry(config?.mcpServers?.ponzu);
48046
48145
  },
48047
48146
  register(entry) {
@@ -48091,7 +48190,7 @@ var AGENTS = [
48091
48190
  {
48092
48191
  id: "cursor",
48093
48192
  label: "Cursor",
48094
- detect: () => existsSync11(join16(homedir7(), ".cursor")),
48193
+ detect: () => existsSync11(join17(homedir8(), ".cursor")),
48095
48194
  current: () => {
48096
48195
  const config = readJson(cursorConfig());
48097
48196
  return toEntry(config?.mcpServers?.ponzu);
@@ -48109,7 +48208,7 @@ var AGENTS = [
48109
48208
  config = parsed;
48110
48209
  }
48111
48210
  config.mcpServers = { ...config.mcpServers, ponzu: entry };
48112
- await mkdir13(dirname8(path), { recursive: true });
48211
+ await mkdir13(dirname9(path), { recursive: true });
48113
48212
  await writeFile11(path, `${JSON.stringify(config, null, 2)}
48114
48213
  `);
48115
48214
  return true;
@@ -48178,7 +48277,7 @@ function agentStatus() {
48178
48277
  }
48179
48278
  function codexConfigured() {
48180
48279
  try {
48181
- return /^\[mcp_servers\.ponzu\]/m.test(readFileSync4(join16(process.env.CODEX_HOME ?? join16(homedir7(), ".codex"), "config.toml"), "utf8"));
48280
+ return /^\[mcp_servers\.ponzu\]/m.test(readFileSync5(join17(process.env.CODEX_HOME ?? join17(homedir8(), ".codex"), "config.toml"), "utf8"));
48182
48281
  } catch {
48183
48282
  return false;
48184
48283
  }
@@ -48222,22 +48321,22 @@ function shouldAutoRegister(current, setUpBefore) {
48222
48321
  function isLegacy(e) {
48223
48322
  return "url" in e && /^http:\/\/(127\.0\.0\.1|localhost):7777\/mcp\/?$/.test(e.url);
48224
48323
  }
48225
- var doneFile = () => join16(ponzuHome(), "agents.json");
48324
+ var doneFile = () => join17(ponzuHome(), "agents.json");
48226
48325
  function readDone() {
48227
48326
  const raw = readJson(doneFile());
48228
48327
  return new Set(raw?.configured ?? []);
48229
48328
  }
48230
48329
  async function writeDone(done) {
48231
- await mkdir13(dirname8(doneFile()), { recursive: true });
48330
+ await mkdir13(dirname9(doneFile()), { recursive: true });
48232
48331
  await writeFile11(doneFile(), `${JSON.stringify({ configured: [...done].sort() }, null, 2)}
48233
48332
  `);
48234
48333
  }
48235
48334
  function cursorConfig() {
48236
- return join16(homedir7(), ".cursor", "mcp.json");
48335
+ return join17(homedir8(), ".cursor", "mcp.json");
48237
48336
  }
48238
48337
  function readJson(path) {
48239
48338
  try {
48240
- return JSON.parse(readFileSync4(path, "utf8"));
48339
+ return JSON.parse(readFileSync5(path, "utf8"));
48241
48340
  } catch {
48242
48341
  return null;
48243
48342
  }
@@ -48246,13 +48345,13 @@ var searchPath;
48246
48345
  function agentPath() {
48247
48346
  if (searchPath !== undefined)
48248
48347
  return searchPath;
48249
- const home = homedir7();
48348
+ const home = homedir8();
48250
48349
  const dirs = [
48251
48350
  ...(process.env.PATH ?? "").split(delimiter2),
48252
- join16(home, ".local/bin"),
48253
- join16(home, ".claude/local"),
48254
- join16(home, ".bun/bin"),
48255
- join16(home, ".npm-global/bin"),
48351
+ join17(home, ".local/bin"),
48352
+ join17(home, ".claude/local"),
48353
+ join17(home, ".bun/bin"),
48354
+ join17(home, ".npm-global/bin"),
48256
48355
  "/opt/homebrew/bin",
48257
48356
  "/usr/local/bin",
48258
48357
  ...loginPath()
@@ -48312,13 +48411,13 @@ function run(cmd, quiet = false) {
48312
48411
  // apps/cli/src/source.ts
48313
48412
  import { createHash as createHash5 } from "crypto";
48314
48413
  import { existsSync as existsSync12 } from "fs";
48315
- import { dirname as dirname9, join as join17, sep as sep4 } from "path";
48414
+ import { dirname as dirname10, join as join18, sep as sep4 } from "path";
48316
48415
  import { fileURLToPath } from "url";
48317
48416
  function sourceCheckout(file = fileURLToPath(import.meta.url)) {
48318
48417
  if (file.startsWith("/$bunfs/") || file.split(sep4).includes("node_modules"))
48319
48418
  return null;
48320
- for (let dir = dirname9(file);dir !== dirname9(dir); dir = dirname9(dir))
48321
- if (existsSync12(join17(dir, ".git")))
48419
+ for (let dir = dirname10(file);dir !== dirname10(dir); dir = dirname10(dir))
48420
+ if (existsSync12(join18(dir, ".git")))
48322
48421
  return dir;
48323
48422
  return null;
48324
48423
  }
@@ -48356,13 +48455,13 @@ function firstFree(ports, hostname) {
48356
48455
 
48357
48456
  // apps/cli/src/telemetry.ts
48358
48457
  import { createHash as createHash6, randomUUID } from "crypto";
48359
- import { readFileSync as readFileSync5 } from "fs";
48458
+ import { readFileSync as readFileSync6 } from "fs";
48360
48459
  import { mkdir as mkdir14, rename as rename10, writeFile as writeFile12 } from "fs/promises";
48361
48460
  import { arch, platform as platform2 } from "os";
48362
- import { dirname as dirname11, join as join18 } from "path";
48461
+ import { dirname as dirname12, join as join19 } from "path";
48363
48462
 
48364
48463
  // node_modules/.bun/posthog-node@5.56.2/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
48365
- import { dirname as dirname10, posix as posix2, sep as sep5 } from "path";
48464
+ import { dirname as dirname11, posix as posix2, sep as sep5 } from "path";
48366
48465
  function createModulerModifier() {
48367
48466
  const getModuleFromFileName = createGetModuleFromFilename();
48368
48467
  return async (frames) => {
@@ -48371,7 +48470,7 @@ function createModulerModifier() {
48371
48470
  return frames;
48372
48471
  };
48373
48472
  }
48374
- function createGetModuleFromFilename(basePath = process.argv[1] ? dirname10(process.argv[1]) : process.cwd(), isWindows = sep5 === "\\") {
48473
+ function createGetModuleFromFilename(basePath = process.argv[1] ? dirname11(process.argv[1]) : process.cwd(), isWindows = sep5 === "\\") {
48375
48474
  const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
48376
48475
  return (filename) => {
48377
48476
  if (!filename)
@@ -57651,17 +57750,17 @@ var CATEGORY = {
57651
57750
  praise: "Praise",
57652
57751
  other: "Other"
57653
57752
  };
57654
- var settingsFile = () => join18(ponzuHome(), "telemetry.json");
57753
+ var settingsFile = () => join19(ponzuHome(), "telemetry.json");
57655
57754
  function readSettings() {
57656
57755
  try {
57657
- return JSON.parse(readFileSync5(settingsFile(), "utf8"));
57756
+ return JSON.parse(readFileSync6(settingsFile(), "utf8"));
57658
57757
  } catch (err) {
57659
57758
  return err.code === "ENOENT" ? {} : null;
57660
57759
  }
57661
57760
  }
57662
57761
  async function writeSettings(settings) {
57663
57762
  const path = settingsFile();
57664
- await mkdir14(dirname11(path), { recursive: true });
57763
+ await mkdir14(dirname12(path), { recursive: true });
57665
57764
  const tmp = `${path}.${process.pid}.tmp`;
57666
57765
  await writeFile12(tmp, `${JSON.stringify(settings, null, 2)}
57667
57766
  `);
@@ -57837,14 +57936,14 @@ async function telemetryCommand(arg = "status") {
57837
57936
  // apps/cli/src/wake.ts
57838
57937
  import { dlopen, FFIType, ptr } from "bun:ffi";
57839
57938
  import { spawnSync as spawnSync3 } from "child_process";
57840
- import { fstatSync, readFileSync as readFileSync6 } from "fs";
57939
+ import { fstatSync, readFileSync as readFileSync7 } from "fs";
57841
57940
  import { mkdir as mkdir15, rm as rm6, writeFile as writeFile13 } from "fs/promises";
57842
- import { homedir as homedir8 } from "os";
57843
- import { join as join19 } from "path";
57941
+ import { homedir as homedir9 } from "os";
57942
+ import { join as join20 } from "path";
57844
57943
  var WAKE_LABEL = "design.ponzu.app.wake";
57845
57944
  var WAKE_PORT = 7778;
57846
- var agentsDir = () => process.env.PONZU_LAUNCH_AGENTS ?? join19(homedir8(), "Library/LaunchAgents");
57847
- var wakePlistPath = () => join19(agentsDir(), `${WAKE_LABEL}.plist`);
57945
+ var agentsDir = () => process.env.PONZU_LAUNCH_AGENTS ?? join20(homedir9(), "Library/LaunchAgents");
57946
+ var wakePlistPath = () => join20(agentsDir(), `${WAKE_LABEL}.plist`);
57848
57947
  var xml = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
57849
57948
  function wakePlist(program, port = WAKE_PORT) {
57850
57949
  return `<?xml version="1.0" encoding="UTF-8"?>
@@ -57886,7 +57985,7 @@ async function installWake(program, run = launchctl) {
57886
57985
  const plist = wakePlist(program);
57887
57986
  let current = null;
57888
57987
  try {
57889
- current = readFileSync6(path, "utf8");
57988
+ current = readFileSync7(path, "utf8");
57890
57989
  } catch {}
57891
57990
  if (current === plist && run(["print", `${domain()}/${WAKE_LABEL}`]))
57892
57991
  return false;
@@ -57900,7 +57999,7 @@ async function uninstallWake(run = launchctl) {
57900
57999
  run(["bootout", `${domain()}/${WAKE_LABEL}`]);
57901
58000
  await rm6(wakePlistPath(), { force: true });
57902
58001
  }
57903
- var systemdDir = () => process.env.PONZU_SYSTEMD_USER ?? join19(process.env.XDG_CONFIG_HOME || join19(homedir8(), ".config"), "systemd/user");
58002
+ var systemdDir = () => process.env.PONZU_SYSTEMD_USER ?? join20(process.env.XDG_CONFIG_HOME || join20(homedir9(), ".config"), "systemd/user");
57904
58003
  var WAKE_SOCKET = "ponzu-wake.socket";
57905
58004
  var WAKE_SERVICE = "ponzu-wake@.service";
57906
58005
  var systemdWord = (s) => `"${s.replace(/[\\"]/g, "\\$&").replace(/%/g, "%%").replace(/\$/g, "$$$$")}"`;
@@ -57934,7 +58033,7 @@ async function installSystemdWake(program, run = systemctl) {
57934
58033
  const units = wakeUnits(program);
57935
58034
  const current = Object.entries(units).every(([name, text]) => {
57936
58035
  try {
57937
- return readFileSync6(join19(systemdDir(), name), "utf8") === text;
58036
+ return readFileSync7(join20(systemdDir(), name), "utf8") === text;
57938
58037
  } catch {
57939
58038
  return false;
57940
58039
  }
@@ -57943,7 +58042,7 @@ async function installSystemdWake(program, run = systemctl) {
57943
58042
  return false;
57944
58043
  await mkdir15(systemdDir(), { recursive: true });
57945
58044
  for (const [name, text] of Object.entries(units))
57946
- await writeFile13(join19(systemdDir(), name), text);
58045
+ await writeFile13(join20(systemdDir(), name), text);
57947
58046
  run(["daemon-reload"]);
57948
58047
  run(["enable", WAKE_SOCKET]);
57949
58048
  run(["restart", WAKE_SOCKET]);
@@ -57952,7 +58051,7 @@ async function installSystemdWake(program, run = systemctl) {
57952
58051
  async function uninstallSystemdWake(run = systemctl) {
57953
58052
  run(["disable", "--now", WAKE_SOCKET]);
57954
58053
  for (const name of [WAKE_SOCKET, WAKE_SERVICE])
57955
- await rm6(join19(systemdDir(), name), { force: true });
58054
+ await rm6(join20(systemdDir(), name), { force: true });
57956
58055
  run(["daemon-reload"]);
57957
58056
  }
57958
58057
  function peerKind(ip) {
@@ -58117,7 +58216,7 @@ function lsofPeer() {
58117
58216
 
58118
58217
  // apps/cli/src/index.ts
58119
58218
  var VERSION2 = package_default.version;
58120
- var here = dirname12(fileURLToPath2(import.meta.url));
58219
+ var here = dirname13(fileURLToPath2(import.meta.url));
58121
58220
  var HELP = `Ponzu ${VERSION2}: the open source canvas your agent draws on in HTML and CSS.
58122
58221
 
58123
58222
  Usage
@@ -58242,7 +58341,7 @@ async function openWorkspace(files, log) {
58242
58341
  const paths = files.length ? files.map((f) => resolve5(f)) : await findDesigns(process.cwd());
58243
58342
  const named = [];
58244
58343
  for (const p of paths) {
58245
- if (!existsSync13(join20(p, "design.json")) && existsSync13(p) === false && files.length) {
58344
+ if (!existsSync13(join21(p, "design.json")) && existsSync13(p) === false && files.length) {
58246
58345
  log(`Creating ${p}`);
58247
58346
  }
58248
58347
  const { key } = await ws.open(p);
@@ -58254,7 +58353,8 @@ async function openWorkspace(files, log) {
58254
58353
  telemetry?.capture("host started", {
58255
58354
  launched_by: process.env.PONZU_LAUNCHED_BY ?? "person",
58256
58355
  designs: ws.designs().length,
58257
- renderer: Boolean(renderer)
58356
+ renderer: Boolean(renderer),
58357
+ ...process.env.PONZU_UPDATE ? { update: process.env.PONZU_UPDATE } : {}
58258
58358
  });
58259
58359
  return { ws, telemetry, named };
58260
58360
  }
@@ -58268,14 +58368,14 @@ async function runServe(files, o) {
58268
58368
  root: process.cwd(),
58269
58369
  tailnet: o.tailnet,
58270
58370
  tailnetPort: 7777,
58271
- dbFile: join20(ponzuHome(), "ponzu.db"),
58272
- stateFile: join20(ponzuHome(), "catalog.json"),
58371
+ dbFile: join21(ponzuHome(), "ponzu.db"),
58372
+ stateFile: join21(ponzuHome(), "catalog.json"),
58273
58373
  spotlight: process.env.PONZU_SPOTLIGHT === "0" ? false : undefined,
58274
58374
  agents: async () => agents(),
58275
58375
  suggest: {
58276
58376
  bin: (agent) => agentCli(agent),
58277
58377
  env: agentEnv(),
58278
- file: join20(ponzuHome(), "suggestions.json")
58378
+ file: join21(ponzuHome(), "suggestions.json")
58279
58379
  },
58280
58380
  opened: named,
58281
58381
  version: VERSION2,
@@ -58382,7 +58482,7 @@ function absolutePaths(args, cwd) {
58382
58482
  }
58383
58483
  async function runInit(target = "design/untitled.design") {
58384
58484
  const path = resolve5(target.endsWith(".design") ? target : `${target}.design`);
58385
- if (existsSync13(join20(path, "design.json"))) {
58485
+ if (existsSync13(join21(path, "design.json"))) {
58386
58486
  console.error(`${path} already exists.`);
58387
58487
  process.exit(1);
58388
58488
  }
@@ -58404,11 +58504,11 @@ Next: ponzu serve ${target}`);
58404
58504
  }
58405
58505
  function findStudio() {
58406
58506
  const candidates = [
58407
- join20(here, "../studio"),
58408
- join20(here, "../../studio/dist"),
58409
- join20(here, "../../../apps/studio/dist")
58507
+ join21(here, "../studio"),
58508
+ join21(here, "../../studio/dist"),
58509
+ join21(here, "../../../apps/studio/dist")
58410
58510
  ];
58411
- return candidates.find((c) => existsSync13(join20(c, "index.html")));
58511
+ return candidates.find((c) => existsSync13(join21(c, "index.html")));
58412
58512
  }
58413
58513
  function lanAddresses() {
58414
58514
  const out = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ponzu",
3
- "version": "1.71.1",
3
+ "version": "1.71.2",
4
4
  "description": "The open source canvas your agent draws on in HTML and CSS.",
5
5
  "license": "MIT",
6
6
  "type": "module",