@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.
- package/dist/cli/{chunk-ca5g8vdg.js → chunk-079cyb2e.js} +1 -1
- package/dist/cli/{chunk-ntfv1dwn.js → chunk-1erdbkyt.js} +1 -1
- package/dist/cli/{chunk-hg87p5n8.js → chunk-32mv1yy6.js} +1 -1
- package/dist/cli/{chunk-2gk4hw2f.js → chunk-37zse6x1.js} +1 -1
- package/dist/cli/{chunk-gjtyxam6.js → chunk-3hz2v172.js} +1 -1
- package/dist/cli/{chunk-b1kg21v2.js → chunk-3sg5v7cg.js} +1 -1
- package/dist/cli/{chunk-vh5bkm9k.js → chunk-4d54zgc7.js} +1 -1
- package/dist/cli/{chunk-cpt1cg44.js → chunk-4hhee3vk.js} +2 -2
- package/dist/cli/{chunk-pdx9keeg.js → chunk-4rgy3ccz.js} +1 -1
- package/dist/cli/{chunk-k41s39aj.js → chunk-659fk8gs.js} +2 -2
- package/dist/cli/{chunk-1ksrew4v.js → chunk-6s5mev2n.js} +1 -1
- package/dist/cli/{chunk-4vsrjqz8.js → chunk-76gqd96j.js} +1 -1
- package/dist/cli/{chunk-j7gt47dd.js → chunk-7ded3me8.js} +1 -1
- package/dist/cli/{chunk-epj4jps9.js → chunk-7gbjyt24.js} +1 -1
- package/dist/cli/{chunk-frrjz0dr.js → chunk-7s1kx9ez.js} +1 -1
- package/dist/cli/{chunk-sjwre940.js → chunk-8041pnt0.js} +1 -1
- package/dist/cli/{chunk-n3a4ffgd.js → chunk-89y20805.js} +1 -1
- package/dist/cli/{chunk-3htqngp4.js → chunk-8pa1ph1s.js} +1 -1
- package/dist/cli/{chunk-mwf7v41t.js → chunk-8ze8f69d.js} +1 -1
- package/dist/cli/{chunk-mv2wxz2h.js → chunk-9jz2z1v9.js} +1 -1
- package/dist/cli/{chunk-57q6gykd.js → chunk-9k47xr7m.js} +1 -1
- package/dist/cli/{chunk-4m8kfaey.js → chunk-avy6jenq.js} +1 -1
- package/dist/cli/{chunk-x93antc5.js → chunk-b127p4wa.js} +1 -1
- package/dist/cli/{chunk-fc9bvzds.js → chunk-cfk8ntfc.js} +1 -1
- package/dist/cli/chunk-ch0ehc06.js +3 -0
- package/dist/cli/{chunk-28wqt1yd.js → chunk-cv1kaq8a.js} +2 -2
- package/dist/cli/{chunk-ctn9bd5z.js → chunk-d4kh54nc.js} +1 -1
- package/dist/cli/{chunk-5zgrym8y.js → chunk-d9sv5x1j.js} +1 -1
- package/dist/cli/{chunk-5fqdbk78.js → chunk-d9trak46.js} +1 -1
- package/dist/cli/{chunk-zm2f0d23.js → chunk-dnbh8hsm.js} +1 -1
- package/dist/cli/{chunk-3wb64q0p.js → chunk-dq2mh3b3.js} +1 -1
- package/dist/cli/{chunk-c46jm1nj.js → chunk-e4a8pvek.js} +1 -1
- package/dist/cli/{chunk-nnz4r6p4.js → chunk-egx76ah2.js} +1 -1
- package/dist/cli/{chunk-bm1z1zsp.js → chunk-ex1a2djb.js} +1 -1
- package/dist/cli/{chunk-857xzvfh.js → chunk-ffvn17at.js} +1 -1
- package/dist/cli/{chunk-r84kan7b.js → chunk-gmgsxdrf.js} +1 -1
- package/dist/cli/{chunk-ntr5zmav.js → chunk-h4qv19v8.js} +1 -1
- package/dist/cli/{chunk-qqkw8v6p.js → chunk-hnfp317x.js} +1 -1
- package/dist/cli/{chunk-rhczy26f.js → chunk-j1ms7bdj.js} +3 -3
- package/dist/cli/{chunk-sh0amz8z.js → chunk-jdph7s6t.js} +3 -3
- package/dist/cli/{chunk-bx2m48tf.js → chunk-jgq6dw3f.js} +1 -1
- package/dist/cli/{chunk-9wyr389k.js → chunk-jjt87qcx.js} +8 -8
- package/dist/cli/{chunk-ghxhqkey.js → chunk-k8tspshr.js} +1 -1
- package/dist/cli/{chunk-q70h7675.js → chunk-kn7g7j09.js} +2 -2
- package/dist/cli/{chunk-m9y3ehq9.js → chunk-ma6m37fe.js} +1 -1
- package/dist/cli/{chunk-fx127943.js → chunk-md8k7c5w.js} +1 -1
- package/dist/cli/{chunk-7sd9m43a.js → chunk-mppda1wq.js} +1 -1
- package/dist/cli/{chunk-1arwygap.js → chunk-ngjqajxa.js} +3 -3
- package/dist/cli/chunk-nh4wvyz3.js +3 -0
- package/dist/cli/chunk-p2c6qka0.js +4 -0
- package/dist/cli/{chunk-rdj6ffbz.js → chunk-pd8bnca7.js} +1 -1
- package/dist/cli/{chunk-fdf4cx4p.js → chunk-pj1mbjwx.js} +1 -1
- package/dist/cli/{chunk-12n1vt01.js → chunk-pvw2y93q.js} +2 -2
- package/dist/cli/{chunk-wapcw2dp.js → chunk-q06z22dy.js} +1 -1
- package/dist/cli/{chunk-71hnc45w.js → chunk-q2197tc1.js} +1 -1
- package/dist/cli/{chunk-d1a1kw0c.js → chunk-s1p650mm.js} +1 -1
- package/dist/cli/{chunk-h9gh63kp.js → chunk-t3wwsz29.js} +1 -1
- package/dist/cli/{chunk-d0dqgk8f.js → chunk-t5srf5gy.js} +1 -1
- package/dist/cli/{chunk-qdf1zd98.js → chunk-tgrzz3pv.js} +1 -1
- package/dist/cli/{chunk-1r7fmapn.js → chunk-th3ff61b.js} +1 -1
- package/dist/cli/{chunk-wx8s1cxr.js → chunk-tj5a3sfy.js} +1 -1
- package/dist/cli/{chunk-3y7qszq1.js → chunk-tndtdhy7.js} +1 -1
- package/dist/cli/{chunk-4jgegyt3.js → chunk-vqsrtavd.js} +3 -3
- package/dist/cli/{chunk-ggq4vsdv.js → chunk-ww4fbx8h.js} +1 -1
- package/dist/cli/{chunk-y5y0sc9a.js → chunk-ynbfqbn9.js} +1 -1
- package/dist/cli/{chunk-mr1etb82.js → chunk-z1htxy4a.js} +1 -1
- package/dist/cli/{chunk-kemcgh1c.js → chunk-z6yqkkgj.js} +1 -1
- package/dist/cli/{chunk-gbqmwpgw.js → chunk-zk7z3b36.js} +1 -1
- package/dist/cli/{chunk-7mfjczcz.js → chunk-zwej00t0.js} +1 -1
- package/dist/cli/index.js +7 -7
- package/dist/cli/kobe.js +1 -1
- package/dist/cli/rove.js +1 -1
- package/dist/web-ui/assets/{harness-DiS1yHqA.js → harness-C1oE8ZEf.js} +1 -1
- package/dist/web-ui/assets/index-DQjknI0o.js +11 -0
- package/dist/web-ui/index.html +1 -1
- package/dist/web-ui/pty-server.mjs +4 -1
- package/dist/web-ui/pty-session-lifecycle.mjs +35 -0
- package/package.json +3 -3
- package/dist/cli/chunk-59xc6m1q.js +0 -3
- package/dist/cli/chunk-chmhmxmc.js +0 -4
- package/dist/cli/chunk-xb9b93ts.js +0 -3
- package/dist/web-ui/assets/index-DxszcdCE.js +0 -10
- /package/dist/cli/{chunk-pdj8kqa1.js → chunk-85q2tgmg.js} +0 -0
package/dist/web-ui/index.html
CHANGED
|
@@ -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-
|
|
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.
|
|
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.
|
|
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.
|
|
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};
|