@dylanpiercey/work 0.0.146 → 0.0.148

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 (80) hide show
  1. package/dist/_Bv4lCw13.js +2 -0
  2. package/dist/{_OZ9nLhXp.js → _DGEhqy7E.js} +69 -17
  3. package/dist/index.mjs +5943 -5731
  4. package/dist/public/assets/{_Bkg2RxMC.js → _B5AO_PK0.js} +4 -4
  5. package/dist/public/assets/_B5AO_PK0.js.br +0 -0
  6. package/dist/public/assets/_B6-AL2IW.js +1 -0
  7. package/dist/public/assets/_B6e0REjB.js +1 -0
  8. package/dist/public/assets/_BDPeW18V.js +1 -0
  9. package/dist/public/assets/_BLa6qQRI.js +1 -0
  10. package/dist/public/assets/_BLa6qQRI.js.br +0 -0
  11. package/dist/public/assets/_BUi3ZmzD.js +1 -0
  12. package/dist/public/assets/_BbmkxODJ.js +1 -0
  13. package/dist/public/assets/_Bh3PoiE1.js +1 -0
  14. package/dist/public/assets/_C-adqHHO.js +1 -0
  15. package/dist/public/assets/_C8kBw58V.js +1 -0
  16. package/dist/public/assets/_CAlPmNE1.js +1 -0
  17. package/dist/public/assets/_CC71bXNs.js +1 -0
  18. package/dist/public/assets/_CLcMxLyh.js +1 -0
  19. package/dist/public/assets/_C_zibmPN.js +1 -0
  20. package/dist/public/assets/_Cqr7mL5Y.js +1 -0
  21. package/dist/public/assets/_D5_AQNJN.js +1 -0
  22. package/dist/public/assets/_DDrwkoeT.js +1 -0
  23. package/dist/public/assets/_DhFH3piZ.js +1 -0
  24. package/dist/public/assets/_DtSBLUpQ.js +1 -0
  25. package/dist/public/assets/_DzRW5uyZ.js +1 -0
  26. package/dist/public/assets/{_BJq6B3f8.js → _WKZUfa9i.js} +20 -20
  27. package/dist/public/assets/_WKZUfa9i.js.br +0 -0
  28. package/dist/public/assets/_pBok7Jmw.js +1 -0
  29. package/dist/public/assets/app-page-C84CTqGX.css +1 -0
  30. package/dist/public/assets/app-page-C84CTqGX.css.br +0 -0
  31. package/dist/public/assets/diff-view-C3OrqoXk.css +1 -0
  32. package/dist/public/assets/diff-view-C3OrqoXk.css.br +0 -0
  33. package/dist/public/assets/diff-view-C_km5-JP.js +2 -0
  34. package/dist/public/assets/icon-arrow-down-DqH6wYIn.css +1 -0
  35. package/dist/public/assets/icon-arrow-down-DqH6wYIn.css.br +0 -0
  36. package/dist/public/assets/new-B2aqg9wv.js +1 -0
  37. package/dist/public/assets/settings-B2aqg9wv.js +1 -0
  38. package/dist/public/assets/w-B2aqg9wv.js +1 -0
  39. package/dist/public/assets/w._-B2aqg9wv.js +1 -0
  40. package/dist/public/assets/w._-CpTBl6kw.js +1 -0
  41. package/lib/setup/doctor.d.mts +1 -1
  42. package/lib/setup/doctor.mjs +32 -5
  43. package/package.json +1 -1
  44. package/scripts/migrate.mjs +1 -1
  45. package/dist/_CCA0c-I0.js +0 -2
  46. package/dist/public/assets/_2f6GkTCF.js +0 -1
  47. package/dist/public/assets/_BJq6B3f8.js.br +0 -0
  48. package/dist/public/assets/_BRiyTqqx.js +0 -1
  49. package/dist/public/assets/_BXJd6h5q.js +0 -1
  50. package/dist/public/assets/_Bc7wOUYH.js +0 -1
  51. package/dist/public/assets/_Bkg2RxMC.js.br +0 -0
  52. package/dist/public/assets/_BnihlWIp.js +0 -1
  53. package/dist/public/assets/_C-wKjwXX.js +0 -1
  54. package/dist/public/assets/_C408Iqy7.js +0 -1
  55. package/dist/public/assets/_CVunWnOY.js +0 -1
  56. package/dist/public/assets/_CeK9LJkw.js +0 -1
  57. package/dist/public/assets/_CgfKx3kO.js +0 -1
  58. package/dist/public/assets/_DCCIL6WI.js +0 -1
  59. package/dist/public/assets/_DQDxPXHD.js +0 -1
  60. package/dist/public/assets/_DRLjyh60.js +0 -1
  61. package/dist/public/assets/_DlE-V9GA.js +0 -1
  62. package/dist/public/assets/_DzgxFeeE.js +0 -1
  63. package/dist/public/assets/_Xp-Chjfv.js +0 -1
  64. package/dist/public/assets/_b6v9fOcC.js +0 -1
  65. package/dist/public/assets/_oalV3UwK.js +0 -1
  66. package/dist/public/assets/_oalV3UwK.js.br +0 -0
  67. package/dist/public/assets/_vQM4oRsw.js +0 -1
  68. package/dist/public/assets/_xiuhy85t.js +0 -1
  69. package/dist/public/assets/app-page-IRq6b-Ob.css +0 -1
  70. package/dist/public/assets/app-page-IRq6b-Ob.css.br +0 -0
  71. package/dist/public/assets/diff-view-6-VC0hOC.css +0 -1
  72. package/dist/public/assets/diff-view-6-VC0hOC.css.br +0 -0
  73. package/dist/public/assets/diff-view-CHN5eqyz.js +0 -2
  74. package/dist/public/assets/icon-arrow-down-Dcmmz4Cl.css +0 -1
  75. package/dist/public/assets/icon-arrow-down-Dcmmz4Cl.css.br +0 -0
  76. package/dist/public/assets/new-BpPnfh6F.js +0 -1
  77. package/dist/public/assets/settings-BpPnfh6F.js +0 -1
  78. package/dist/public/assets/w-BpPnfh6F.js +0 -1
  79. package/dist/public/assets/w._-B5NuNac4.js +0 -1
  80. package/dist/public/assets/w._-BpPnfh6F.js +0 -1
@@ -0,0 +1,2 @@
1
+ import { m as notifySessionsChanged } from "./_DGEhqy7E.js";
2
+ export { notifySessionsChanged };
@@ -426,6 +426,20 @@ function setupPath(base = process.env.PATH || "") {
426
426
  const seen = /* @__PURE__ */ new Set();
427
427
  return [...base.split(path.delimiter), ...extra].filter((p) => p && !seen.has(p) && seen.add(p)).join(path.delimiter);
428
428
  }
429
+ /** setupPath() split once per PATH value: `which` runs for every tool on
430
+ * every probe and rebuilt the list each time. */
431
+ var dirsFor = {
432
+ base: void 0,
433
+ dirs: []
434
+ };
435
+ function setupDirs() {
436
+ const base = process.env.PATH || "";
437
+ if (dirsFor.base !== base) dirsFor = {
438
+ base,
439
+ dirs: setupPath(base).split(path.delimiter)
440
+ };
441
+ return dirsFor.dirs;
442
+ }
429
443
  /** `~/…` for anything under the home directory — every path here is for
430
444
  * display (Settings rows, `work doctor`), never re-used to exec. */
431
445
  function tilde(p) {
@@ -434,7 +448,7 @@ function tilde(p) {
434
448
  }
435
449
  /** Absolute path of `bin` on setupPath(), or null. */
436
450
  function which(bin) {
437
- for (const dir of setupPath().split(path.delimiter)) {
451
+ for (const dir of setupDirs()) {
438
452
  const full = path.join(dir, bin);
439
453
  try {
440
454
  if (fs.statSync(full).isFile()) return full;
@@ -500,14 +514,29 @@ function ghKnownHosts() {
500
514
  }
501
515
  return [...text.matchAll(/^([A-Za-z0-9.-]+):\s*$/gm)].map((m) => m[1]);
502
516
  }
517
+ /** Agent scan memo. Every app page render, skills scan and session
518
+ * create asks; the answer only moves when something is installed, and
519
+ * the doctor probe (which every install runs) refreshes it. */
520
+ var AGENTS_MEMO_MS = 3e4;
521
+ var agentsMemo = null;
503
522
  /**
504
523
  * Every agent CLI instance on PATH, per family: the plain binary and any
505
524
  * numeric-suffixed siblings (`claude1`, `cursor-agent2`). Sync — a PATH
506
525
  * scan is cheap and the boot handler needs it without awaiting. First hit
507
- * on PATH wins per name, like the shell.
526
+ * on PATH wins per name, like the shell. `fresh` rescans regardless of
527
+ * the memo.
508
528
  */
509
- function discoverAgents() {
510
- const dirs = setupPath().split(path.delimiter);
529
+ function discoverAgents(fresh = false) {
530
+ if (!fresh && agentsMemo && Date.now() - agentsMemo.at < AGENTS_MEMO_MS) return agentsMemo.value;
531
+ const value = scanAgents();
532
+ agentsMemo = {
533
+ at: Date.now(),
534
+ value
535
+ };
536
+ return value;
537
+ }
538
+ function scanAgents() {
539
+ const dirs = setupDirs();
511
540
  const seenDirs = /* @__PURE__ */ new Set();
512
541
  const seen = /* @__PURE__ */ new Map();
513
542
  for (const dir of dirs) {
@@ -614,7 +643,7 @@ async function doctor(opts = {}) {
614
643
  mise: t.mise
615
644
  };
616
645
  });
617
- const agents = discoverAgents();
646
+ const agents = discoverAgents(true);
618
647
  const missing = [];
619
648
  for (const t of tools) if (t.required && !t.installed) missing.push(t.id);
620
649
  if (!github.some((h) => h.authed)) missing.push("github-auth");
@@ -798,9 +827,15 @@ function shared(fn, ttlMs) {
798
827
  //#region src/server/events.ts
799
828
  var listeners = /* @__PURE__ */ new Set();
800
829
  function publish(type, data) {
830
+ publishJson(type, data === void 0 ? void 0 : JSON.stringify(data), data);
831
+ }
832
+ /** Publish with the payload already serialized (a producer that had to
833
+ * stringify it anyway, e.g. for change detection, hands the string in). */
834
+ function publishJson(type, dataJson, data) {
801
835
  const event = {
802
836
  type,
803
- data
837
+ data,
838
+ frame: dataJson === void 0 ? JSON.stringify({ type }) : `{"type":${JSON.stringify(type)},"data":${dataJson}}`
804
839
  };
805
840
  for (const listener of [...listeners]) try {
806
841
  listener(event);
@@ -6689,7 +6724,7 @@ function publishChange(sessionId) {
6689
6724
  const row = get("SELECT workspace_id FROM sessions WHERE id = ?", sessionId);
6690
6725
  if (row?.workspace_id) {
6691
6726
  const workspaceId = row.workspace_id;
6692
- import("./_CCA0c-I0.js").then((m) => m.notifySessionsChanged(workspaceId));
6727
+ import("./_Bv4lCw13.js").then((m) => m.notifySessionsChanged(workspaceId));
6693
6728
  return;
6694
6729
  }
6695
6730
  publish("sessions.changed");
@@ -8216,6 +8251,7 @@ async function disposeSession(id) {
8216
8251
  "-t",
8217
8252
  tmuxName(id)
8218
8253
  ]).catch(() => {});
8254
+ forgetPanes();
8219
8255
  clearTmuxStarted(id);
8220
8256
  clearAgentPhase(id);
8221
8257
  db.prepare("DELETE FROM sessions WHERE id = ?").run(id);
@@ -8234,9 +8270,18 @@ function tmuxWasStarted(id) {
8234
8270
  function clearTmuxStarted(id) {
8235
8271
  tmuxStarted.delete(id);
8236
8272
  }
8237
- /** SSE payload: session rows + live tmux/hook state so clients don't refetch. */
8273
+ /** SSE payload: session rows + live tmux/hook state so clients don't refetch.
8274
+ * Coalesced per workspace: a turn boundary lands as a burst of phase
8275
+ * transitions (hook, then scrape), and each one cost a list-panes spawn
8276
+ * and a broadcast for a list that came out the same. */
8277
+ var EMIT_DEBOUNCE_MS = 50;
8278
+ var pendingEmits = /* @__PURE__ */ new Map();
8238
8279
  function notifySessionsChanged(workspaceId) {
8239
- emitSessionsChanged(workspaceId);
8280
+ clearTimeout(pendingEmits.get(workspaceId));
8281
+ pendingEmits.set(workspaceId, setTimeout(() => {
8282
+ pendingEmits.delete(workspaceId);
8283
+ emitSessionsChanged(workspaceId);
8284
+ }, EMIT_DEBOUNCE_MS));
8240
8285
  }
8241
8286
  async function emitSessionsChanged(workspaceId) {
8242
8287
  try {
@@ -8321,13 +8366,20 @@ async function panePids() {
8321
8366
  return new Set((await listPanes() || []).map((p) => p.pid));
8322
8367
  }
8323
8368
  /** Every tmux pane, one `list-panes` for everyone who wants one: session
8324
- * state, pane pids and the activity scraper all ask within the same tick,
8325
- * and a field costs tmux nothing while a spawn costs ~10 ms on macOS. No
8326
- * reuse window — a kill-session followed by a state read must see the
8327
- * pane gone — only concurrent callers share the spawn. Null when tmux did
8328
- * not answer (server down, transient failure): callers that clear state
8329
- * on "no panes" must not clear it on "no answer". */
8330
- var listPanes = shared(listPanesNow, 0);
8369
+ * state, pane pids, the activity scraper and every phase transition ask
8370
+ * within a short span, and a field costs tmux nothing while a spawn costs
8371
+ * ~10 ms on macOS. The reuse window sits well under the scraper's 2 s
8372
+ * cadence; the one reader that must not see a stale answer — a
8373
+ * kill-session followed by a state read — drops the window with
8374
+ * `forgetPanes`. Null when tmux did not answer (server down, transient
8375
+ * failure): callers that clear state on "no panes" must not clear it on
8376
+ * "no answer". */
8377
+ var PANES_REUSE_MS = 400;
8378
+ var panesShared = shared(listPanesNow, PANES_REUSE_MS);
8379
+ var listPanes = () => panesShared();
8380
+ function forgetPanes() {
8381
+ panesShared = shared(listPanesNow, PANES_REUSE_MS);
8382
+ }
8331
8383
  async function listPanesNow() {
8332
8384
  const out = await tmux([
8333
8385
  "list-panes",
@@ -8639,4 +8691,4 @@ function sleep(ms) {
8639
8691
  return new Promise((resolve) => setTimeout(resolve, ms));
8640
8692
  }
8641
8693
  //#endregion
8642
- export { getSetting as $, setAgentPhase as A, pushPublicKey as B, blankRow as C, run$1 as Ct, agentLabel as D, agentFromCommand as E, iconSvg as F, subscriberJoins as G, publish as H, manifest as I, withLock as J, shared as K, normalizeAccent as L, setSessionViewers as M, ACCENT_RE as N, agentMeta as O, getInstance as P, enabledAgents as Q, setInstance as R, reportsWorking as S, git as St, agentFamily as T, config as Tt, subscribe as U, saveSubscription as V, subscriberCount as W, allPrefs as X, agentChoices as Y, disabledAgents as Z, sessionStates as _, db as _t, ensureTmuxServer as a, doctor as at, AGENTS as b, TMUX_SOCKET as bt, killWorkspaceSessions as c, miseVersions as ct, markTmuxStarted as d, DEFAULT_GITHUB_HOST as dt, preferredAgent as et, newSessionArgs as f, TOOLS as ft, sendToSession as g, all as gt, renameSession as h, toolById as ht, disposeSessions as i, discoverAgents as it, setScrapedPhase as j, clearAgentPhase as k, listPanes as l, setupPath as lt, panePids as m, agentLabel$1 as mt, clearTmuxStarted as n, setPref as nt, getSession as o, ghKnownHosts as ot, notifySessionsChanged as p, agentById as pt, swr as q, createSession as r, setSetting as rt, killSession as s, miseInstalls as st, cleanEnv as t, setDisabledAgents as tt, listSessions as u, which as ut, tmuxName as v, get as vt, agentBadge as w, tmux as wt, readHookPayload as x, gh as xt, tmuxWasStarted as y, workspacePath as yt, deleteSubscription as z };
8694
+ export { disabledAgents as $, clearAgentPhase as A, deleteSubscription as B, reportsWorking as C, gh as Ct, agentFromCommand as D, config as Dt, agentFamily as E, tmux as Et, getInstance as F, subscribe as G, saveSubscription as H, iconSvg as I, shared as J, subscriberCount as K, manifest as L, setScrapedPhase as M, setSessionViewers as N, agentLabel as O, ACCENT_RE as P, allPrefs as Q, normalizeAccent as R, readHookPayload as S, TMUX_SOCKET as St, agentBadge as T, run$1 as Tt, publish as U, pushPublicKey as V, publishJson as W, withLock as X, swr as Y, agentChoices as Z, sendToSession as _, toolById as _t, ensureTmuxServer as a, setSetting as at, tmuxWasStarted as b, get as bt, killSession as c, ghKnownHosts as ct, listSessions as d, setupPath as dt, enabledAgents as et, markTmuxStarted as f, which as ft, renameSession as g, agentLabel$1 as gt, panePids as h, agentById as ht, disposeSessions as i, setPref as it, setAgentPhase as j, agentMeta as k, killWorkspaceSessions as l, miseInstalls as lt, notifySessionsChanged as m, TOOLS as mt, clearTmuxStarted as n, preferredAgent as nt, forgetPanes as o, discoverAgents as ot, newSessionArgs as p, DEFAULT_GITHUB_HOST as pt, subscriberJoins as q, createSession as r, setDisabledAgents as rt, getSession as s, doctor as st, cleanEnv as t, getSetting as tt, listPanes as u, miseVersions as ut, sessionStates as v, all as vt, blankRow as w, git as wt, AGENTS as x, workspacePath as xt, tmuxName as y, db as yt, setInstance as z };