@sma1lboy/rove 0.9.230 → 0.9.231

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 (83) hide show
  1. package/dist/cli/{chunk-ca5g8vdg.js → chunk-079cyb2e.js} +1 -1
  2. package/dist/cli/{chunk-ntfv1dwn.js → chunk-1erdbkyt.js} +1 -1
  3. package/dist/cli/{chunk-hg87p5n8.js → chunk-32mv1yy6.js} +1 -1
  4. package/dist/cli/{chunk-2gk4hw2f.js → chunk-37zse6x1.js} +1 -1
  5. package/dist/cli/{chunk-gjtyxam6.js → chunk-3hz2v172.js} +1 -1
  6. package/dist/cli/{chunk-b1kg21v2.js → chunk-3sg5v7cg.js} +1 -1
  7. package/dist/cli/{chunk-vh5bkm9k.js → chunk-4d54zgc7.js} +1 -1
  8. package/dist/cli/{chunk-cpt1cg44.js → chunk-4hhee3vk.js} +2 -2
  9. package/dist/cli/{chunk-pdx9keeg.js → chunk-4rgy3ccz.js} +1 -1
  10. package/dist/cli/{chunk-k41s39aj.js → chunk-659fk8gs.js} +2 -2
  11. package/dist/cli/{chunk-1ksrew4v.js → chunk-6s5mev2n.js} +1 -1
  12. package/dist/cli/{chunk-4vsrjqz8.js → chunk-76gqd96j.js} +1 -1
  13. package/dist/cli/{chunk-j7gt47dd.js → chunk-7ded3me8.js} +1 -1
  14. package/dist/cli/{chunk-epj4jps9.js → chunk-7gbjyt24.js} +1 -1
  15. package/dist/cli/{chunk-frrjz0dr.js → chunk-7s1kx9ez.js} +1 -1
  16. package/dist/cli/{chunk-sjwre940.js → chunk-8041pnt0.js} +1 -1
  17. package/dist/cli/{chunk-n3a4ffgd.js → chunk-89y20805.js} +1 -1
  18. package/dist/cli/{chunk-3htqngp4.js → chunk-8pa1ph1s.js} +1 -1
  19. package/dist/cli/{chunk-mwf7v41t.js → chunk-8ze8f69d.js} +1 -1
  20. package/dist/cli/{chunk-mv2wxz2h.js → chunk-9jz2z1v9.js} +1 -1
  21. package/dist/cli/{chunk-57q6gykd.js → chunk-9k47xr7m.js} +1 -1
  22. package/dist/cli/{chunk-4m8kfaey.js → chunk-avy6jenq.js} +1 -1
  23. package/dist/cli/{chunk-x93antc5.js → chunk-b127p4wa.js} +1 -1
  24. package/dist/cli/{chunk-fc9bvzds.js → chunk-cfk8ntfc.js} +1 -1
  25. package/dist/cli/chunk-ch0ehc06.js +3 -0
  26. package/dist/cli/{chunk-28wqt1yd.js → chunk-cv1kaq8a.js} +2 -2
  27. package/dist/cli/{chunk-ctn9bd5z.js → chunk-d4kh54nc.js} +1 -1
  28. package/dist/cli/{chunk-5zgrym8y.js → chunk-d9sv5x1j.js} +1 -1
  29. package/dist/cli/{chunk-5fqdbk78.js → chunk-d9trak46.js} +1 -1
  30. package/dist/cli/{chunk-zm2f0d23.js → chunk-dnbh8hsm.js} +1 -1
  31. package/dist/cli/{chunk-3wb64q0p.js → chunk-dq2mh3b3.js} +1 -1
  32. package/dist/cli/{chunk-c46jm1nj.js → chunk-e4a8pvek.js} +1 -1
  33. package/dist/cli/{chunk-nnz4r6p4.js → chunk-egx76ah2.js} +1 -1
  34. package/dist/cli/{chunk-bm1z1zsp.js → chunk-ex1a2djb.js} +1 -1
  35. package/dist/cli/{chunk-857xzvfh.js → chunk-ffvn17at.js} +1 -1
  36. package/dist/cli/{chunk-r84kan7b.js → chunk-gmgsxdrf.js} +1 -1
  37. package/dist/cli/{chunk-ntr5zmav.js → chunk-h4qv19v8.js} +1 -1
  38. package/dist/cli/{chunk-qqkw8v6p.js → chunk-hnfp317x.js} +1 -1
  39. package/dist/cli/{chunk-rhczy26f.js → chunk-j1ms7bdj.js} +3 -3
  40. package/dist/cli/{chunk-sh0amz8z.js → chunk-jdph7s6t.js} +3 -3
  41. package/dist/cli/{chunk-bx2m48tf.js → chunk-jgq6dw3f.js} +1 -1
  42. package/dist/cli/{chunk-9wyr389k.js → chunk-jjt87qcx.js} +8 -8
  43. package/dist/cli/{chunk-ghxhqkey.js → chunk-k8tspshr.js} +1 -1
  44. package/dist/cli/{chunk-q70h7675.js → chunk-kn7g7j09.js} +2 -2
  45. package/dist/cli/{chunk-m9y3ehq9.js → chunk-ma6m37fe.js} +1 -1
  46. package/dist/cli/{chunk-fx127943.js → chunk-md8k7c5w.js} +1 -1
  47. package/dist/cli/{chunk-7sd9m43a.js → chunk-mppda1wq.js} +1 -1
  48. package/dist/cli/{chunk-1arwygap.js → chunk-ngjqajxa.js} +3 -3
  49. package/dist/cli/chunk-nh4wvyz3.js +3 -0
  50. package/dist/cli/chunk-p2c6qka0.js +4 -0
  51. package/dist/cli/{chunk-rdj6ffbz.js → chunk-pd8bnca7.js} +1 -1
  52. package/dist/cli/{chunk-fdf4cx4p.js → chunk-pj1mbjwx.js} +1 -1
  53. package/dist/cli/{chunk-12n1vt01.js → chunk-pvw2y93q.js} +2 -2
  54. package/dist/cli/{chunk-wapcw2dp.js → chunk-q06z22dy.js} +1 -1
  55. package/dist/cli/{chunk-71hnc45w.js → chunk-q2197tc1.js} +1 -1
  56. package/dist/cli/{chunk-d1a1kw0c.js → chunk-s1p650mm.js} +1 -1
  57. package/dist/cli/{chunk-h9gh63kp.js → chunk-t3wwsz29.js} +1 -1
  58. package/dist/cli/{chunk-d0dqgk8f.js → chunk-t5srf5gy.js} +1 -1
  59. package/dist/cli/{chunk-qdf1zd98.js → chunk-tgrzz3pv.js} +1 -1
  60. package/dist/cli/{chunk-1r7fmapn.js → chunk-th3ff61b.js} +1 -1
  61. package/dist/cli/{chunk-wx8s1cxr.js → chunk-tj5a3sfy.js} +1 -1
  62. package/dist/cli/{chunk-3y7qszq1.js → chunk-tndtdhy7.js} +1 -1
  63. package/dist/cli/{chunk-4jgegyt3.js → chunk-vqsrtavd.js} +3 -3
  64. package/dist/cli/{chunk-ggq4vsdv.js → chunk-ww4fbx8h.js} +1 -1
  65. package/dist/cli/{chunk-y5y0sc9a.js → chunk-ynbfqbn9.js} +1 -1
  66. package/dist/cli/{chunk-mr1etb82.js → chunk-z1htxy4a.js} +1 -1
  67. package/dist/cli/{chunk-kemcgh1c.js → chunk-z6yqkkgj.js} +1 -1
  68. package/dist/cli/{chunk-gbqmwpgw.js → chunk-zk7z3b36.js} +1 -1
  69. package/dist/cli/{chunk-7mfjczcz.js → chunk-zwej00t0.js} +1 -1
  70. package/dist/cli/index.js +7 -7
  71. package/dist/cli/kobe.js +1 -1
  72. package/dist/cli/rove.js +1 -1
  73. package/dist/web-ui/assets/{harness-DiS1yHqA.js → harness-C1oE8ZEf.js} +1 -1
  74. package/dist/web-ui/assets/index-DQjknI0o.js +11 -0
  75. package/dist/web-ui/index.html +1 -1
  76. package/dist/web-ui/pty-server.mjs +4 -1
  77. package/dist/web-ui/pty-session-lifecycle.mjs +35 -0
  78. package/package.json +3 -3
  79. package/dist/cli/chunk-59xc6m1q.js +0 -3
  80. package/dist/cli/chunk-chmhmxmc.js +0 -4
  81. package/dist/cli/chunk-xb9b93ts.js +0 -3
  82. package/dist/web-ui/assets/index-DxszcdCE.js +0 -10
  83. /package/dist/cli/{chunk-pdj8kqa1.js → chunk-85q2tgmg.js} +0 -0
@@ -5,7 +5,7 @@
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Rove</title>
8
- <script type="module" crossorigin src="/assets/index-DxszcdCE.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-DQjknI0o.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-D3usUDr4.css">
10
10
  </head>
11
11
  <body>
@@ -6,7 +6,8 @@
6
6
  * PTY is spawned lazily on first attach (launch spec fetched from daemon web
7
7
  * transport by taskId + mode) and kept alive across WebSocket reconnects, so a
8
8
  * page refresh re-attaches to the same process. Closing a tab (POST
9
- * /pty/close) kills its PTY.
9
+ * /pty/close) kills its PTY, and so does no socket re-attaching within the
10
+ * detach grace window. The sidecar exits with its parent process.
10
11
  *
11
12
  * ws /pty?tab=<id>&taskId=<id>&mode=engine|shell&cols=<n>&rows=<n>
12
13
  * POST /pty/close { tab } kill the tab process
@@ -20,6 +21,7 @@ import { allowedHostForBindHost, originAllowed } from "./origin-policy.mjs"
20
21
  import { ptyRequestAuthorized } from "./pty-auth.mjs"
21
22
  import { ptyEnv } from "./pty-env.mjs"
22
23
  import { createScrollback } from "./pty-scrollback.mjs"
24
+ import { watchParent } from "./pty-parent-watch.mjs"
23
25
  import { createPtySessionManager } from "./pty-session-lifecycle.mjs"
24
26
  import { createSpecFetcher } from "./pty-spec.mjs"
25
27
 
@@ -210,3 +212,4 @@ const shutdown = () => {
210
212
  }
211
213
  process.on("SIGINT", shutdown)
212
214
  process.on("SIGTERM", shutdown)
215
+ watchParent({ onGone: shutdown })
@@ -18,6 +18,11 @@ const DEFAULT_SUBMIT_DELAYS = {
18
18
  // session is being actively viewed.
19
19
  const DEFAULT_MAX_SESSIONS = 64
20
20
 
21
+ // The page never POSTs /pty/close when a browser tab just closes, so a session
22
+ // nobody re-attaches to within this window is killed. Long enough to ride out a
23
+ // refresh or a laptop lid, short enough that abandoned TUIs don't pile up.
24
+ const DEFAULT_DETACH_GRACE_MS = 10 * 60 * 1000
25
+
21
26
  // PTY→WebSocket backpressure: a flooding pty (`yes`) outruns a slow browser, so
22
27
  // node buffers the unsent bytes (ws.bufferedAmount) without bound. Pause the pty
23
28
  // once any socket's buffer crosses the high-water mark and resume once every
@@ -68,10 +73,12 @@ export function createPtySessionManager({
68
73
  scrollbackCap,
69
74
  env,
70
75
  setTimeoutFn = setTimeout,
76
+ clearTimeoutFn = clearTimeout,
71
77
  setIntervalFn = setInterval,
72
78
  clearIntervalFn = clearInterval,
73
79
  submitDelays = DEFAULT_SUBMIT_DELAYS,
74
80
  maxSessions = DEFAULT_MAX_SESSIONS,
81
+ detachGraceMs = DEFAULT_DETACH_GRACE_MS,
75
82
  backpressure = DEFAULT_BACKPRESSURE,
76
83
  }) {
77
84
  /** @type {Map<string, { pty: any, scrollback: ReturnType<createScrollback>, sockets: Set<any> }>} */
@@ -110,6 +117,22 @@ export function createPtySessionManager({
110
117
  }
111
118
  }
112
119
 
120
+ /** Start the reap countdown for a session no socket is watching. */
121
+ function armDetachTimer(tabId, entry) {
122
+ if (entry.detachTimer !== null || entry.sockets.size > 0) return
123
+ entry.detachTimer = setTimeoutFn(() => {
124
+ entry.detachTimer = null
125
+ if (sessions.get(tabId) === entry && entry.sockets.size === 0) closeSession(tabId)
126
+ }, detachGraceMs)
127
+ }
128
+
129
+ function clearDetachTimer(entry) {
130
+ if (entry.detachTimer !== null) {
131
+ clearTimeoutFn(entry.detachTimer)
132
+ entry.detachTimer = null
133
+ }
134
+ }
135
+
113
136
  function spawnSession(tabId, spec, cols, rows) {
114
137
  // Enforce the session cap before allocating another process: evict the
115
138
  // oldest unwatched session, or reject when every session is in active use.
@@ -141,6 +164,7 @@ export function createPtySessionManager({
141
164
  sockets: new Set(),
142
165
  paused: false,
143
166
  drainTimer: null,
167
+ detachTimer: null,
144
168
  }
145
169
  pty.onData((data) => {
146
170
  entry.scrollback.push(data)
@@ -154,9 +178,13 @@ export function createPtySessionManager({
154
178
  for (const ws of entry.sockets) {
155
179
  if (ws.readyState === ws.OPEN) ws.close(1000, "engine exited")
156
180
  }
181
+ // After the socket loop: a synchronous close re-arms the reap timer.
182
+ clearDetachTimer(entry)
157
183
  if (sessions.get(tabId) === entry) sessions.delete(tabId)
158
184
  })
159
185
  sessions.set(tabId, entry)
186
+ // A spawn-on-send with no viewer is reaped too; an attach cancels this.
187
+ armDetachTimer(tabId, entry)
160
188
  return entry
161
189
  }
162
190
 
@@ -216,8 +244,12 @@ export function createPtySessionManager({
216
244
 
217
245
  async function attachSocket({ ws, tabId, taskId, mode, cols, rows }) {
218
246
  const entry = await ensureSession(tabId, taskId, mode, cols, rows)
247
+ // The browser can leave during the spawn; its close event already fired,
248
+ // so tracking the socket would pin the session as watched forever.
249
+ if (ws.readyState !== ws.OPEN) return entry
219
250
  const replay = entry.scrollback.length() > 0 ? entry.scrollback.replay() : ""
220
251
  entry.sockets.add(ws)
252
+ clearDetachTimer(entry)
221
253
  if (replay && ws.readyState === ws.OPEN) ws.send(replay)
222
254
  safePty(tabId, entry, (pty) => pty.resize(cols, rows))
223
255
 
@@ -239,6 +271,7 @@ export function createPtySessionManager({
239
271
 
240
272
  ws.on("close", () => {
241
273
  entry.sockets.delete(ws)
274
+ if (sessions.get(tabId) === entry) armDetachTimer(tabId, entry)
242
275
  })
243
276
 
244
277
  return entry
@@ -248,6 +281,7 @@ export function createPtySessionManager({
248
281
  const entry = sessions.get(tabId)
249
282
  if (!entry) return false
250
283
  clearDrainTimer(entry)
284
+ clearDetachTimer(entry)
251
285
  try {
252
286
  entry.pty.kill()
253
287
  } catch {
@@ -275,6 +309,7 @@ export function createPtySessionManager({
275
309
  function shutdown() {
276
310
  for (const entry of sessions.values()) {
277
311
  clearDrainTimer(entry)
312
+ clearDetachTimer(entry)
278
313
  try {
279
314
  entry.pty.kill()
280
315
  } catch {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@sma1lboy/rove",
4
- "version": "0.9.230",
4
+ "version": "0.9.231",
5
5
  "description": "Rove — the agent multiplexer for your terminal. Run coding agents on parallel tasks with isolated worktrees and persistent sessions.",
6
6
  "keywords": [
7
7
  "terminal",
@@ -78,12 +78,12 @@
78
78
  "node-pty": "^1.1.0",
79
79
  "react": "^19.2.8",
80
80
  "smol-toml": "^1.7.1",
81
- "ws": "^8.18.0"
81
+ "ws": "^8.21.3"
82
82
  },
83
83
  "devDependencies": {
84
84
  "@biomejs/biome": "1.9.4",
85
85
  "@sma1lboy/kobe-daemon": "0.7.19",
86
- "@tsconfig/bun": "1.0.10",
86
+ "@tsconfig/bun": "1.0.11",
87
87
  "@types/bun": "1.3.14",
88
88
  "@types/node": "25.6.2",
89
89
  "@types/react": "^19.2.0",
@@ -1,3 +0,0 @@
1
- // @bun
2
- var ROW_TOKEN_TONES=["info","success","warning","error","muted"];function isRowTokenTone(value){return typeof value==="string"&&ROW_TOKEN_TONES.includes(value)}var ROW_TOKEN_MAX_TEXT=24,ROW_TOKEN_MAX_PER_SOURCE=2,ROW_TOKEN_MIN_TTL_MS=1000,ROW_TOKEN_MAX_TTL_MS=3600000,ROW_TOKEN_DEFAULT_TTL_MS=60000;function clampRowTokenTtl(ms){if(ms===void 0||!Number.isFinite(ms))return ROW_TOKEN_DEFAULT_TTL_MS;return Math.min(ROW_TOKEN_MAX_TTL_MS,Math.max(ROW_TOKEN_MIN_TTL_MS,Math.floor(ms)))}function normalizeRowTokenText(text){return text.replace(/\s+/g," ").trim().slice(0,ROW_TOKEN_MAX_TEXT)}class RowTokenStore{bus;now;byTask=new Map;timer;constructor(bus,now=Date.now){this.bus=bus;this.now=now}set(write){let token={source:write.source,key:write.key,text:normalizeRowTokenText(write.text),...write.tone?{tone:write.tone}:{},expiresAt:this.now()+clampRowTokenTtl(write.ttlMs)},live=this.liveTokens(write.taskId).filter((t)=>!(t.source===token.source&&t.key===token.key));live.push(token);let mine=live.filter((t)=>t.source===token.source).sort((a,b)=>a.expiresAt-b.expiresAt),evict=new Set(mine.slice(0,Math.max(0,mine.length-ROW_TOKEN_MAX_PER_SOURCE)));return this.store(write.taskId,live.filter((t)=>!evict.has(t))),token}clear(taskId,source,key){let before=this.liveTokens(taskId),after=before.filter((t)=>t.source!==source||key!==void 0&&t.key!==key);return this.store(taskId,after),after.length!==before.length}clearTask(taskId){if(!this.byTask.delete(taskId))return;this.publish()}snapshot(){let out={};for(let taskId of[...this.byTask.keys()]){let live=this.liveTokens(taskId);if(live.length>0)out[taskId]=live;else this.byTask.delete(taskId)}return out}close(){if(this.timer)clearTimeout(this.timer);this.timer=void 0}liveTokens(taskId){let at=this.now();return(this.byTask.get(taskId)??[]).filter((t)=>t.expiresAt>at)}store(taskId,tokens){if(tokens.length>0)this.byTask.set(taskId,[...tokens]);else this.byTask.delete(taskId);this.publish()}publish(){let tokens=this.snapshot();if(this.bus.publish("task.tokens",{tokens}),this.timer)clearTimeout(this.timer);this.timer=void 0;let next=Number.POSITIVE_INFINITY;for(let list of Object.values(tokens))for(let token of list)next=Math.min(next,token.expiresAt);if(!Number.isFinite(next))return;this.timer=setTimeout(()=>{this.timer=void 0,this.publish()},Math.max(1,next-this.now())),this.timer.unref?.()}}
3
- export{ROW_TOKEN_TONES,isRowTokenTone,ROW_TOKEN_MAX_TEXT,RowTokenStore};
@@ -1,4 +0,0 @@
1
- // @bun
2
- import{engineEntry,identifiableEngineIds}from"./chunk-rhczy26f.js";import{recordSpawn}from"./chunk-40dgv828.js";import{loadStateFile}from"./chunk-zyd6k6ak.js";import{PsProbeUnavailableError}from"./chunk-pxk2c2vj.js";import{__require}from"./chunk-wqfp8d9w.js";import{basename}from"path";var WRAPPERS=new Set(["node","bun","npx","deno","sh","zsh","bash","env","script"]);function binaryName(token){return basename(token).replace(/\.(exe|js|mjs|cjs)$/,"")}function executableNameFromArgv(argv){for(let token of argv.slice(0,8)){if(/^[A-Za-z_][A-Za-z0-9_]*=/.test(token))continue;let name=binaryName(token);if(WRAPPERS.has(name))continue;return name||null}return null}function vendorFromArgv(commandLine){let name=executableNameFromArgv(commandLine.trim().split(/\s+/));if(!name)return null;return identifiableEngineIds().find((v)=>{let entry=engineEntry(v);return entry.defaultCommand[0]===name||entry.processNames?.includes(name)===!0})??null}function parsePsSnapshot(text){let rows=[];for(let line of text.split(`
3
- `)){let m=/^\s*(\d+)\s+(\d+)\s+(\S.*)$/.exec(line);if(m)rows.push({pid:Number(m[1]),ppid:Number(m[2]),args:m[3]})}return rows}function childrenIndex(rows){let kids=new Map;for(let row of rows){let list=kids.get(row.ppid);if(list)list.push(row);else kids.set(row.ppid,[row])}return kids}function hasAncestor(rows,pid,ancestorPid){let parents=new Map(rows.map((r)=>[r.pid,r.ppid])),cur=pid;for(let hops=0;hops<=rows.length;hops++){if(cur===ancestorPid)return!0;let next=parents.get(cur);if(next===void 0||next<=1)return!1;cur=next}return!1}function customEngineBinaries(){let state=loadStateFile(),ids=state.customEngineIds,out=new Map;if(!Array.isArray(ids))return out;for(let id of ids){if(typeof id!=="string"||id.trim().length===0)continue;let command=state[`engineCommand.${id}`],argv=typeof command==="string"&&command.trim().length>0?command.trim().split(/\s+/):[id],name=executableNameFromArgv(argv);if(name)out.set(name,id)}return out}function walkDescendants(rows,rootPid,identify){let kids=childrenIndex(rows),queue=[...kids.get(rootPid)??[]];while(queue.length>0){let row=queue.shift();if(!row)break;let vendor=identify(row.args);if(vendor)return{vendor,argv:row.args,pid:row.pid};queue.push(...kids.get(row.pid)??[])}return null}function foregroundEngineIn(rows,rootPid){let builtin=walkDescendants(rows,rootPid,vendorFromArgv);if(builtin)return builtin;let custom=customEngineBinaries();if(custom.size===0)return null;return walkDescendants(rows,rootPid,(args)=>custom.get(executableNameFromArgv(args.trim().split(/\s+/))??"")??null)}function engineProcessIn(rows,rootPid,extraLaunch){if(foregroundEngineIn(rows,rootPid))return!0;let expected=extraLaunch?executableNameFromArgv(typeof extraLaunch==="string"?[extraLaunch]:extraLaunch):null;if(!expected)return!1;let kids=childrenIndex(rows),queue=[...kids.get(rootPid)??[]];while(queue.length>0){let row=queue.shift();if(!row)break;if(executableNameFromArgv(row.args.trim().split(/\s+/))===expected)return!0;queue.push(...kids.get(row.pid)??[])}return!1}var PS_PROBE_TIMEOUT_MS=5000,bunPsSpawn=()=>{recordSpawn("engine.foregroundWalk",["ps","-A","-o","pid=,ppid=,args="]);let proc=Bun.spawn(["ps","-A","-o","pid=,ppid=,args="],{stdout:"pipe",stderr:"ignore"});return{text:new Response(proc.stdout).text(),kill:()=>proc.kill()}};async function psSnapshotWith(spawn,timeoutMs=PS_PROBE_TIMEOUT_MS){let proc=spawn(),timer;try{let text=await Promise.race([proc.text,new Promise((_resolve,reject)=>{timer=setTimeout(()=>{try{proc.kill()}catch{}reject(new PsProbeUnavailableError(`ps did not answer within ${timeoutMs}ms`))},timeoutMs)})]);if(parsePsSnapshot(text).length===0)throw new PsProbeUnavailableError("ps returned no usable rows");return text}finally{if(timer)clearTimeout(timer)}}var psSnapshot=async(anchors)=>{if(process.platform!=="win32")return psSnapshotWith(bunPsSpawn);let{defaultWinProcessProbe,winProcessSnapshot}=await import("./chunk-kxaqge09.js");return winProcessSnapshot(anchors??[],defaultWinProcessProbe())};async function foregroundEngine(rootPid,snapshot=psSnapshot){try{return foregroundEngineIn(parsePsSnapshot(await snapshot([rootPid])),rootPid)}catch{return null}}
4
- export{vendorFromArgv,parsePsSnapshot,hasAncestor,foregroundEngineIn,engineProcessIn,PS_PROBE_TIMEOUT_MS,psSnapshotWith,psSnapshot,foregroundEngine};
@@ -1,3 +0,0 @@
1
- // @bun
2
- var PLACEHOLDER_TASK_TITLE="(new task)";function sanitizeTaskTitle(title){return title.replace(/[\u0000-\u0020\u007f]+/g," ").trim()}function deriveTitleFromPrompt(prompt){if(typeof prompt!=="string")return"";let collapsed=prompt.replace(/\s+/g," ").trim();if(collapsed.length===0)return"";let points=[...collapsed];if(points.length<=40)return collapsed;return`${points.slice(0,40).join("")}\u2026`}function isPlaceholderDerivedBranch(branch,taskId){let id6=taskId.slice(-6).toLowerCase();if(branch===`rove/new-task-${id6}`||branch===`kobe/new-task-${id6}`)return!0;return/^(?:[^/]+\/)?new-task(?:-\d+)?$/.test(branch)}
3
- export{PLACEHOLDER_TASK_TITLE,sanitizeTaskTitle,deriveTitleFromPrompt,isPlaceholderDerivedBranch};