toyon 0.13.0 → 0.14.0
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/README.md +1 -1
- package/dist/cli.js +30 -42
- package/dist/daemon.js +63 -27
- package/dist/shell/assets/{Editor-CUcgZuoM.js → Editor-Gzhl3Oqu.js} +3 -3
- package/dist/shell/assets/{XTerm-V6sBDIe-.js → XTerm-D6TL52yQ.js} +1 -1
- package/dist/shell/assets/{cssMode-CSyiAvIn.js → cssMode-BfNm0a39.js} +1 -1
- package/dist/shell/assets/{freemarker2-C4-FNK3V.js → freemarker2-DhiwR6KJ.js} +1 -1
- package/dist/shell/assets/{grammar-DzHb7e7O.js → grammar-thv9InXF.js} +1 -1
- package/dist/shell/assets/{handlebars-DcjVaOCM.js → handlebars-BbkhCZXb.js} +1 -1
- package/dist/shell/assets/{html-Csl8cogA.js → html-yzhYlR33.js} +1 -1
- package/dist/shell/assets/{htmlMode-rewe9UaO.js → htmlMode-DPICAUY8.js} +1 -1
- package/dist/shell/assets/index-BYBd8f7P.css +1 -0
- package/dist/shell/assets/{index-Bkn7zNFw.js → index-DJBEbneL.js} +111 -111
- package/dist/shell/assets/{javascript--pKV-E-G.js → javascript-D9eBjR4g.js} +1 -1
- package/dist/shell/assets/{jsonMode-zPVc0E6l.js → jsonMode-cNulMi5B.js} +1 -1
- package/dist/shell/assets/{liquid-jZT5xQG-.js → liquid-C_SKIx1n.js} +1 -1
- package/dist/shell/assets/{lspLanguageFeatures-BuiqKs90.js → lspLanguageFeatures-DNU8BRHj.js} +1 -1
- package/dist/shell/assets/{mdx-DwnR-ia2.js → mdx-Bt4opbQO.js} +1 -1
- package/dist/shell/assets/{python-DU3pl9Zu.js → python-Crb-EuXe.js} +1 -1
- package/dist/shell/assets/{razor-BzVUPqHs.js → razor-D3BlkbYO.js} +1 -1
- package/dist/shell/assets/{tsMode-ONmZhHHZ.js → tsMode-BYuAS95U.js} +1 -1
- package/dist/shell/assets/{xml-BXW7X3BT.js → xml-G5xafDqw.js} +1 -1
- package/dist/shell/assets/{yaml-DFE79ex1.js → yaml-CRp1x3nR.js} +1 -1
- package/dist/shell/index.html +2 -2
- package/package.json +1 -1
- package/dist/shell/assets/index-iVaPr_If.css +0 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ npm i -g toyon
|
|
|
48
48
|
toyon ~/projects/app
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
`toyon .` opens the folder you are in and `toyon --help` lists the rest. A global install keeps itself updated; `TOYON_UPDATES=off` stops it. Run outside a project, Toyon opens with none: describe a new one in a sentence, or give the project picker a git URL to clone.
|
|
51
|
+
`toyon .` opens the folder you are in and `toyon --help` lists the rest. The install button in the top bar makes Toyon an app of its own in Chrome, Arc, Brave or Edge, with a Dock icon and no browser bar; from then on `toyon .` opens that. A global install keeps itself updated; `TOYON_UPDATES=off` stops it. Run outside a project, Toyon opens with none: describe a new one in a sentence, or give the project picker a git URL to clone.
|
|
52
52
|
|
|
53
53
|
You need:
|
|
54
54
|
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import { join as join7, resolve } from "path";
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "toyon",
|
|
10
|
-
version: "0.
|
|
10
|
+
version: "0.14.0",
|
|
11
11
|
description: "Toyon is where coding agents work on your web app while you check each change by using it. Every chat gets its own running copy with a live preview.",
|
|
12
12
|
license: "MIT",
|
|
13
13
|
type: "module",
|
|
@@ -5373,8 +5373,9 @@ function post(route, token, body) {
|
|
|
5373
5373
|
body: JSON.stringify(body)
|
|
5374
5374
|
});
|
|
5375
5375
|
}
|
|
5376
|
+
var shellOrigins = ["http://toyon.localhost", `http://toyon.localhost:${port}`];
|
|
5376
5377
|
function shellUrl(token, branded) {
|
|
5377
|
-
return branded ?
|
|
5378
|
+
return `${branded ? shellOrigins[0] : shellOrigins[1]}/#token=${token}`;
|
|
5378
5379
|
}
|
|
5379
5380
|
|
|
5380
5381
|
// src/openUrl.ts
|
|
@@ -5404,14 +5405,15 @@ function profilesOf(browser) {
|
|
|
5404
5405
|
function pwaStillInstalled(browser, id) {
|
|
5405
5406
|
return profilesOf(browser).some((p) => existsSync3(join3(p, "Web Applications", "Manifest Resources", id)));
|
|
5406
5407
|
}
|
|
5407
|
-
function findPwaId(browser
|
|
5408
|
+
function findPwaId(browser) {
|
|
5408
5409
|
const cache = join3(pwaCacheDir, `${browser.replace(/\W+/g, "-")}.id`);
|
|
5409
5410
|
if (existsSync3(cache)) {
|
|
5410
5411
|
const id = readFileSync2(cache, "utf8").trim();
|
|
5411
5412
|
if (/^[a-p]{32}$/.test(id) && pwaStillInstalled(browser, id))
|
|
5412
5413
|
return id;
|
|
5413
5414
|
}
|
|
5414
|
-
const
|
|
5415
|
+
const ids = shellOrigins.map((o) => `${o}/`.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&")).join("|");
|
|
5416
|
+
const re = new RegExp(`web_apps-dt-([a-p]{32})[\\s\\S]{0,16}?(?:${ids})`);
|
|
5415
5417
|
for (const p of profilesOf(browser)) {
|
|
5416
5418
|
const dir = join3(p, "Sync Data", "LevelDB");
|
|
5417
5419
|
if (!existsSync3(dir))
|
|
@@ -5429,29 +5431,28 @@ function findPwaId(browser, manifestId) {
|
|
|
5429
5431
|
}
|
|
5430
5432
|
return null;
|
|
5431
5433
|
}
|
|
5432
|
-
function
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
if (
|
|
5434
|
+
function openShell(daemon) {
|
|
5435
|
+
console.log(`toyon: ${daemon.url}`);
|
|
5436
|
+
const found = process.platform === "darwin" ? launchInstalledApp() : "none";
|
|
5437
|
+
if (found === "launched")
|
|
5436
5438
|
return;
|
|
5437
|
-
console.log("no Chromium browser found; opening in default browser");
|
|
5438
5439
|
openUrl(daemon.url);
|
|
5440
|
+
if (found === "uninstalled")
|
|
5441
|
+
console.log("tip: install Toyon as an app from the top bar; toyon then opens in its own window");
|
|
5439
5442
|
}
|
|
5440
|
-
function
|
|
5441
|
-
|
|
5443
|
+
function launchInstalledApp() {
|
|
5444
|
+
let seen = false;
|
|
5442
5445
|
for (const app of CHROMIUMS) {
|
|
5443
|
-
if (spawnSync("open", ["-Ra", app]).status
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
return true;
|
|
5452
|
-
}
|
|
5446
|
+
if (spawnSync("open", ["-Ra", app]).status !== 0)
|
|
5447
|
+
continue;
|
|
5448
|
+
seen = true;
|
|
5449
|
+
const id = findPwaId(app);
|
|
5450
|
+
if (!id)
|
|
5451
|
+
continue;
|
|
5452
|
+
spawn3("open", ["-na", app, "--args", `--app-id=${id}`], { stdio: "ignore" }).unref();
|
|
5453
|
+
return "launched";
|
|
5453
5454
|
}
|
|
5454
|
-
return
|
|
5455
|
+
return seen ? "uninstalled" : "none";
|
|
5455
5456
|
}
|
|
5456
5457
|
|
|
5457
5458
|
// src/args.ts
|
|
@@ -5532,18 +5533,14 @@ function parseArgs(argv) {
|
|
|
5532
5533
|
}
|
|
5533
5534
|
}
|
|
5534
5535
|
let path = null;
|
|
5535
|
-
let app = false;
|
|
5536
5536
|
for (const a of argv) {
|
|
5537
|
-
if (a
|
|
5538
|
-
app = true;
|
|
5539
|
-
else if (a.startsWith("-"))
|
|
5537
|
+
if (a.startsWith("-"))
|
|
5540
5538
|
return { kind: "error", message: `unknown option ${a}` };
|
|
5541
|
-
|
|
5539
|
+
if (path !== null)
|
|
5542
5540
|
return { kind: "error", message: "Toyon opens one path at a time" };
|
|
5543
|
-
|
|
5544
|
-
path = a;
|
|
5541
|
+
path = a;
|
|
5545
5542
|
}
|
|
5546
|
-
return { kind: "open", path
|
|
5543
|
+
return { kind: "open", path };
|
|
5547
5544
|
}
|
|
5548
5545
|
function parseLogs(rest) {
|
|
5549
5546
|
let follow = false;
|
|
@@ -5641,9 +5638,6 @@ usage
|
|
|
5641
5638
|
toyon deploy fly destroy <name> [--yes]
|
|
5642
5639
|
delete that app and its volume
|
|
5643
5640
|
|
|
5644
|
-
options for toyon [path]
|
|
5645
|
-
--app open a Chromium app window (the installed Toyon app when there is one)
|
|
5646
|
-
|
|
5647
5641
|
environment
|
|
5648
5642
|
TOYON_HOME where state lives (default ~/.toyon)
|
|
5649
5643
|
TOYON_PORT the daemon's port (default 4141)
|
|
@@ -6218,7 +6212,7 @@ async function helper(args) {
|
|
|
6218
6212
|
if (!res.ok)
|
|
6219
6213
|
console.error(`could not open ${path}: ${await res.text()}`);
|
|
6220
6214
|
}
|
|
6221
|
-
|
|
6215
|
+
openShell(daemon);
|
|
6222
6216
|
return 0;
|
|
6223
6217
|
}
|
|
6224
6218
|
|
|
@@ -6849,16 +6843,10 @@ async function open2(cmd) {
|
|
|
6849
6843
|
const res = await post("/register", daemon.token, { path: target });
|
|
6850
6844
|
if (!res.ok) {
|
|
6851
6845
|
console.error(`could not open ${target}: ${await res.text()}`);
|
|
6852
|
-
|
|
6853
|
-
return 1;
|
|
6846
|
+
return 1;
|
|
6854
6847
|
}
|
|
6855
6848
|
}
|
|
6856
|
-
|
|
6857
|
-
showAppWindow(daemon);
|
|
6858
|
-
else {
|
|
6859
|
-
console.log(`toyon: ${daemon.url}`);
|
|
6860
|
-
openUrl(daemon.url);
|
|
6861
|
-
}
|
|
6849
|
+
openShell(daemon);
|
|
6862
6850
|
return 0;
|
|
6863
6851
|
}
|
|
6864
6852
|
async function start() {
|
package/dist/daemon.js
CHANGED
|
@@ -6602,7 +6602,7 @@ ${text.slice(text.length - (CONTEXT_CHARS - HEAD_CHARS))}`;
|
|
|
6602
6602
|
}
|
|
6603
6603
|
|
|
6604
6604
|
// ../shared/src/protocol/limits.ts
|
|
6605
|
-
var PROTOCOL_VERSION =
|
|
6605
|
+
var PROTOCOL_VERSION = 107;
|
|
6606
6606
|
var PAGE_ERROR_MAX_CHARS = 2000;
|
|
6607
6607
|
var PAGE_TITLE_MAX_CHARS = 1000;
|
|
6608
6608
|
var RENDER_ERRORS_MAX = 10;
|
|
@@ -8528,7 +8528,7 @@ async function turnRemoteOff(ts, daemonPort, file, was) {
|
|
|
8528
8528
|
// ../daemon/package.json
|
|
8529
8529
|
var package_default = {
|
|
8530
8530
|
name: "@toyon/daemon",
|
|
8531
|
-
version: "0.
|
|
8531
|
+
version: "0.14.0",
|
|
8532
8532
|
private: true,
|
|
8533
8533
|
type: "module",
|
|
8534
8534
|
main: "src/index.ts",
|
|
@@ -15275,7 +15275,7 @@ function mapUpdate(update, memos, tag, sink, background) {
|
|
|
15275
15275
|
out.push({ type: "tool-update", toolId: update.toolCallId, ...refined });
|
|
15276
15276
|
}
|
|
15277
15277
|
if (update.content)
|
|
15278
|
-
memo.content =
|
|
15278
|
+
memo.content = update.content;
|
|
15279
15279
|
if (update.rawOutput !== undefined)
|
|
15280
15280
|
memo.rawOutput = update.rawOutput;
|
|
15281
15281
|
if ((update.status === "completed" || update.status === "failed") && !memo.ended) {
|
|
@@ -16182,15 +16182,30 @@ class AcpSession {
|
|
|
16182
16182
|
this.emit({ type: "tool-end", toolId, output: output.join(`
|
|
16183
16183
|
`), isError: true });
|
|
16184
16184
|
}
|
|
16185
|
-
|
|
16185
|
+
const going = new Set;
|
|
16186
|
+
for (const { event } of this.log.entries) {
|
|
16186
16187
|
this.trackHandoff(event);
|
|
16188
|
+
if (event.type === "handoff-go")
|
|
16189
|
+
going.add(event.id);
|
|
16190
|
+
else if (event.type === "handoff" || event.type === "handoff-declined")
|
|
16191
|
+
going.delete(event.id);
|
|
16192
|
+
}
|
|
16193
|
+
for (const id of going) {
|
|
16194
|
+
this.emit({
|
|
16195
|
+
type: "handoff-declined",
|
|
16196
|
+
id,
|
|
16197
|
+
outcome: "failed",
|
|
16198
|
+
reason: "Toyon stopped while the worktree was being made",
|
|
16199
|
+
ts: Date.now()
|
|
16200
|
+
});
|
|
16201
|
+
}
|
|
16187
16202
|
if (this.openHandoffs.size > 0)
|
|
16188
16203
|
this.syncStatus();
|
|
16189
16204
|
}
|
|
16190
16205
|
trackHandoff(event) {
|
|
16191
16206
|
if (event.type === "handoff-proposed")
|
|
16192
16207
|
return this.openHandoffs.add(event.id).size > 0;
|
|
16193
|
-
if (event.type === "handoff" || event.type === "handoff-declined")
|
|
16208
|
+
if (event.type === "handoff-go" || event.type === "handoff" || event.type === "handoff-declined")
|
|
16194
16209
|
return this.openHandoffs.delete(event.id);
|
|
16195
16210
|
return false;
|
|
16196
16211
|
}
|
|
@@ -18641,6 +18656,8 @@ class RuntimeRegistry {
|
|
|
18641
18656
|
}
|
|
18642
18657
|
if (this.settingUp.has(id))
|
|
18643
18658
|
return;
|
|
18659
|
+
if (wt.kind === "spare" && wt.phase !== undefined && wt.phase !== "ready")
|
|
18660
|
+
return;
|
|
18644
18661
|
const repo = this.deps.state.repos.find((r) => r.id === wt.repoId);
|
|
18645
18662
|
if (repo)
|
|
18646
18663
|
await this.start(wt, repo);
|
|
@@ -19435,7 +19452,7 @@ function openAskOf(entries) {
|
|
|
19435
19452
|
open.delete(e.id);
|
|
19436
19453
|
else if (e.type === "handoff-proposed")
|
|
19437
19454
|
open.set(e.id, `Continue in ${e.repo.name}?`);
|
|
19438
|
-
else if (e.type === "handoff" || e.type === "handoff-declined")
|
|
19455
|
+
else if (e.type === "handoff-go" || e.type === "handoff" || e.type === "handoff-declined")
|
|
19439
19456
|
open.delete(e.id);
|
|
19440
19457
|
}
|
|
19441
19458
|
const last = [...open.values()].at(-1)?.trim();
|
|
@@ -22738,9 +22755,14 @@ async function behindUpstream(worktreePath) {
|
|
|
22738
22755
|
const r = await git(worktreePath, "rev-list", "--count", "HEAD..@{upstream}");
|
|
22739
22756
|
return r.ok ? Number(r.out) || 0 : null;
|
|
22740
22757
|
}
|
|
22741
|
-
async function aheadUpstream(worktreePath) {
|
|
22758
|
+
async function aheadUpstream(worktreePath, branch) {
|
|
22742
22759
|
const r = await git(worktreePath, "rev-list", "--count", "@{upstream}..HEAD");
|
|
22743
|
-
|
|
22760
|
+
if (r.ok)
|
|
22761
|
+
return Number(r.out) || 0;
|
|
22762
|
+
if (!branch)
|
|
22763
|
+
return null;
|
|
22764
|
+
const o = await git(worktreePath, "rev-list", "--count", `origin/${branch}..HEAD`);
|
|
22765
|
+
return o.ok ? Number(o.out) || 0 : null;
|
|
22744
22766
|
}
|
|
22745
22767
|
async function aheadBehind(worktreePath, defaultBr) {
|
|
22746
22768
|
const [a, b] = await Promise.all([
|
|
@@ -28964,10 +28986,12 @@ var handlers = {
|
|
|
28964
28986
|
const followUp = msg.attachments?.length ? { attachments: msg.attachments } : undefined;
|
|
28965
28987
|
s.runtime.agentFor(msg.worktreeId)?.answer(msg.askId, { kind: "answers", answers: msg.answers }, followUp);
|
|
28966
28988
|
});
|
|
28989
|
+
s.worktrees.markPrompted(msg.worktreeId);
|
|
28967
28990
|
},
|
|
28968
28991
|
"agent-decide"(msg, _ctx, s) {
|
|
28969
28992
|
requireRun(s, msg.worktreeId);
|
|
28970
28993
|
s.runtime.agentFor(msg.worktreeId)?.answer(msg.askId, { kind: "choice", choiceId: msg.choiceId });
|
|
28994
|
+
s.worktrees.markPrompted(msg.worktreeId);
|
|
28971
28995
|
},
|
|
28972
28996
|
async "handoff-answer"(msg, _ctx, s) {
|
|
28973
28997
|
requireRun(s, msg.worktreeId);
|
|
@@ -29061,8 +29085,8 @@ var handlers = {
|
|
|
29061
29085
|
ctx.reply({ t: "refs", repoId: msg.repoId, query: msg.query, refs });
|
|
29062
29086
|
},
|
|
29063
29087
|
async "search-chats"(msg, ctx, s) {
|
|
29064
|
-
const { hits, truncated } = await s.chats.search(msg.repoId, msg.query);
|
|
29065
|
-
ctx.reply({ t: "chat-hits", repoId: msg.repoId, query: msg.query, hits, truncated });
|
|
29088
|
+
const { hits, truncated, asks } = await s.chats.search(msg.repoId, msg.query);
|
|
29089
|
+
ctx.reply({ t: "chat-hits", repoId: msg.repoId, query: msg.query, hits, truncated, asks });
|
|
29066
29090
|
},
|
|
29067
29091
|
async "open-ref"(msg, _ctx, s) {
|
|
29068
29092
|
await s.worktrees.openRef(msg.repoId, msg.kind, msg.ref, { createdBy: msg.clientId, pr: msg.pr });
|
|
@@ -30815,6 +30839,7 @@ var CHAT_HITS_MAX = 200;
|
|
|
30815
30839
|
var MIN_QUERY = 2;
|
|
30816
30840
|
var SNIPPET = 160;
|
|
30817
30841
|
var BEFORE = 50;
|
|
30842
|
+
var ASK = 500;
|
|
30818
30843
|
var bunFs2 = {
|
|
30819
30844
|
async stat(path) {
|
|
30820
30845
|
try {
|
|
@@ -30886,6 +30911,9 @@ function searchRows(rows, terms, chat, limit = CHAT_HITS_PER_WORKTREE) {
|
|
|
30886
30911
|
}
|
|
30887
30912
|
return { hits, more: false };
|
|
30888
30913
|
}
|
|
30914
|
+
function firstAsk(rows) {
|
|
30915
|
+
return rows.find((r) => r.role === "user")?.text.slice(0, ASK);
|
|
30916
|
+
}
|
|
30889
30917
|
function termRanges(lower, terms) {
|
|
30890
30918
|
const ranges = [];
|
|
30891
30919
|
for (const term of terms) {
|
|
@@ -30907,7 +30935,7 @@ class ChatSearch {
|
|
|
30907
30935
|
this.d.state.requireRepo(repoId);
|
|
30908
30936
|
const terms = needleTerms(query);
|
|
30909
30937
|
if (terms.length === 0)
|
|
30910
|
-
return { hits: [], truncated: false };
|
|
30938
|
+
return { hits: [], truncated: false, asks: {} };
|
|
30911
30939
|
const chats = [
|
|
30912
30940
|
...this.d.state.worktrees.filter((w) => w.repoId === repoId && w.kind === "worktree").map((w) => ({ id: w.id, archived: false, path: this.d.transcriptPath(w.id) })),
|
|
30913
30941
|
...this.d.archivedChats(repoId).map((a) => ({ id: a.id, archived: true, path: a.transcript }))
|
|
@@ -30915,13 +30943,23 @@ class ChatSearch {
|
|
|
30915
30943
|
const read = new Set;
|
|
30916
30944
|
const found = await Promise.all(chats.map(async (c) => {
|
|
30917
30945
|
const rows = await this.rowsOf(c.id, c.archived, c.path, read);
|
|
30918
|
-
return
|
|
30946
|
+
return {
|
|
30947
|
+
id: c.id,
|
|
30948
|
+
...searchRows(rows, terms, { worktreeId: c.id, archived: c.archived }),
|
|
30949
|
+
ask: firstAsk(rows)
|
|
30950
|
+
};
|
|
30919
30951
|
}));
|
|
30920
30952
|
for (const key of this.said.keys())
|
|
30921
30953
|
if (!read.has(key))
|
|
30922
30954
|
this.said.delete(key);
|
|
30923
30955
|
const all = found.filter((f) => f.hits.length > 0).sort((a, b) => b.hits[0].ts - a.hits[0].ts).flatMap((f) => f.hits);
|
|
30924
|
-
|
|
30956
|
+
const hits = all.slice(0, CHAT_HITS_MAX);
|
|
30957
|
+
const kept = new Set(hits.map((h) => h.worktreeId));
|
|
30958
|
+
const asks = {};
|
|
30959
|
+
for (const f of found)
|
|
30960
|
+
if (f.ask && kept.has(f.id))
|
|
30961
|
+
asks[f.id] = f.ask;
|
|
30962
|
+
return { hits, truncated: all.length > CHAT_HITS_MAX || found.some((f) => f.more), asks };
|
|
30925
30963
|
}
|
|
30926
30964
|
async rowsOf(id, archived, path, read) {
|
|
30927
30965
|
const live = archived ? undefined : this.d.live(id);
|
|
@@ -31107,7 +31145,7 @@ function openProposals(entries) {
|
|
|
31107
31145
|
for (const { event } of entries) {
|
|
31108
31146
|
if (event.type === "handoff-proposed")
|
|
31109
31147
|
open.set(event.id, event);
|
|
31110
|
-
else if (event.type === "handoff" || event.type === "handoff-declined")
|
|
31148
|
+
else if (event.type === "handoff-go" || event.type === "handoff" || event.type === "handoff-declined")
|
|
31111
31149
|
open.delete(event.id);
|
|
31112
31150
|
}
|
|
31113
31151
|
return [...open.values()];
|
|
@@ -31126,7 +31164,6 @@ function proposedThisTurn(entries) {
|
|
|
31126
31164
|
|
|
31127
31165
|
class HandoffService {
|
|
31128
31166
|
d;
|
|
31129
|
-
settling = new Set;
|
|
31130
31167
|
constructor(d) {
|
|
31131
31168
|
this.d = d;
|
|
31132
31169
|
d.hub.on("landed", (worktreeId) => this.landed(worktreeId));
|
|
@@ -31239,13 +31276,11 @@ class HandoffService {
|
|
|
31239
31276
|
if (!openProposals(entries).some((p) => p.id === id)) {
|
|
31240
31277
|
return log.debug(worktreeId, `answer for a handoff that already closed (${id})`);
|
|
31241
31278
|
}
|
|
31242
|
-
if (this.settling.has(id))
|
|
31243
|
-
return;
|
|
31244
31279
|
if (!go) {
|
|
31245
31280
|
agent.note({ type: "handoff-declined", id, ts: Date.now() });
|
|
31246
31281
|
return;
|
|
31247
31282
|
}
|
|
31248
|
-
|
|
31283
|
+
agent.note({ type: "handoff-go", id, ts: Date.now() });
|
|
31249
31284
|
try {
|
|
31250
31285
|
const repo = this.d.state.repo(proposed.repo.id);
|
|
31251
31286
|
if (!repo)
|
|
@@ -31271,8 +31306,6 @@ class HandoffService {
|
|
|
31271
31306
|
const reason = e instanceof Error ? e.message : String(e);
|
|
31272
31307
|
agent.note({ type: "handoff-declined", id, outcome: "failed", reason, ts: Date.now() });
|
|
31273
31308
|
throw e;
|
|
31274
|
-
} finally {
|
|
31275
|
-
this.settling.delete(id);
|
|
31276
31309
|
}
|
|
31277
31310
|
}
|
|
31278
31311
|
async ask(worktreeId, repoId, text) {
|
|
@@ -33107,6 +33140,7 @@ class SparePool {
|
|
|
33107
33140
|
await withRepoLock(repo.path, () => gitOrThrow(repo.path, "worktree", "add", "--detach", wt.path, baseOf(repo)));
|
|
33108
33141
|
})();
|
|
33109
33142
|
const done = (async () => {
|
|
33143
|
+
this.d.runtime.markSetup(wt.id, true);
|
|
33110
33144
|
try {
|
|
33111
33145
|
await added;
|
|
33112
33146
|
if (after) {
|
|
@@ -33136,6 +33170,7 @@ class SparePool {
|
|
|
33136
33170
|
} catch (e) {
|
|
33137
33171
|
await this.rollBack(wt, e);
|
|
33138
33172
|
} finally {
|
|
33173
|
+
this.d.runtime.markSetup(wt.id, false);
|
|
33139
33174
|
if (this.inflight.get(repoId)?.added === added)
|
|
33140
33175
|
this.inflight.delete(repoId);
|
|
33141
33176
|
}
|
|
@@ -33600,7 +33635,7 @@ class WorktreeService {
|
|
|
33600
33635
|
claimed.effort = opts.effort;
|
|
33601
33636
|
if (profile !== undefined && profile !== resolveRun(repo, claimed).profile) {
|
|
33602
33637
|
claimed.profile = profile;
|
|
33603
|
-
this.restartProcs(claimed
|
|
33638
|
+
this.restartProcs(claimed);
|
|
33604
33639
|
}
|
|
33605
33640
|
const carried = await this.carryMain(repo, claimed, !!opts.carry);
|
|
33606
33641
|
this.d.state.save();
|
|
@@ -33852,8 +33887,8 @@ class WorktreeService {
|
|
|
33852
33887
|
throw new UserError(`no profile "${name}" in ${repo.configFile}`);
|
|
33853
33888
|
return name;
|
|
33854
33889
|
}
|
|
33855
|
-
restartProcs(wt
|
|
33856
|
-
fireAndForget(wt.id, this.d.runtime.stopProcs(wt.id).then(() => this.d.runtime.
|
|
33890
|
+
restartProcs(wt) {
|
|
33891
|
+
fireAndForget(wt.id, this.d.runtime.stopProcs(wt.id).then(() => this.d.runtime.wake(wt.id)), "profile restart");
|
|
33857
33892
|
}
|
|
33858
33893
|
setProfile(worktreeId, name) {
|
|
33859
33894
|
const { wt, repo } = this.d.state.requireWorktreeWithRepo(worktreeId);
|
|
@@ -33865,7 +33900,7 @@ class WorktreeService {
|
|
|
33865
33900
|
wt.profile = profile;
|
|
33866
33901
|
this.d.state.save();
|
|
33867
33902
|
this.d.hub.emit("worktreesChanged");
|
|
33868
|
-
this.restartProcs(wt
|
|
33903
|
+
this.restartProcs(wt);
|
|
33869
33904
|
}
|
|
33870
33905
|
setMode(worktreeId, mode) {
|
|
33871
33906
|
if (!this.d.state.setMode(worktreeId, mode))
|
|
@@ -34725,7 +34760,7 @@ ${wt.landing.body}` : wt.landing.subject : undefined;
|
|
|
34725
34760
|
return { result: fetched };
|
|
34726
34761
|
if (wt.pr?.state === "open") {
|
|
34727
34762
|
const dirty = (await statusFiles(wt.path)).length > 0;
|
|
34728
|
-
const missing = dirty || (await aheadUpstream(wt.path) ?? 0) > 0;
|
|
34763
|
+
const missing = dirty || (await aheadUpstream(wt.path, wt.branch) ?? 0) > 0;
|
|
34729
34764
|
if (!missing)
|
|
34730
34765
|
return { result: await mergePr(wt.path, wt.pr.number, policy.merge, w) };
|
|
34731
34766
|
const committed = await this.commitIfDirty(wt, message);
|
|
@@ -35157,9 +35192,10 @@ ${wt.landing.body}` : wt.landing.subject : undefined;
|
|
|
35157
35192
|
return { ...ab, ...unpushed === undefined ? {} : { unpushed }, dirty };
|
|
35158
35193
|
}
|
|
35159
35194
|
async unpushed(id, path) {
|
|
35160
|
-
|
|
35195
|
+
const wt = this.d.state.worktree(id);
|
|
35196
|
+
if (wt?.pr?.state !== "open")
|
|
35161
35197
|
return;
|
|
35162
|
-
return await aheadUpstream(path) ?? undefined;
|
|
35198
|
+
return await aheadUpstream(path, wt.branch) ?? undefined;
|
|
35163
35199
|
}
|
|
35164
35200
|
async freshCounts(worktreeId) {
|
|
35165
35201
|
if (this.going.has(worktreeId))
|