@rehpic/vcli 0.1.0-beta.96.1 → 0.1.0-beta.99.4
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/index.js
CHANGED
|
@@ -1462,22 +1462,142 @@ function discoverAttachableSessions() {
|
|
|
1462
1462
|
...discoverClaudeSessions()
|
|
1463
1463
|
]);
|
|
1464
1464
|
}
|
|
1465
|
-
async function
|
|
1465
|
+
async function launchProviderSession(provider, cwd, prompt2, onEvent) {
|
|
1466
1466
|
if (provider === "codex") {
|
|
1467
1467
|
return runCodexAppServerTurn({
|
|
1468
|
+
cwd,
|
|
1469
|
+
prompt: prompt2,
|
|
1470
|
+
launchCommand: "codex app-server",
|
|
1471
|
+
onEvent
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
if (provider === "claude_code") {
|
|
1475
|
+
return runClaudeSdkTurn({
|
|
1476
|
+
cwd,
|
|
1477
|
+
prompt: prompt2,
|
|
1478
|
+
launchCommand: "@anthropic-ai/claude-agent-sdk query()",
|
|
1479
|
+
onEvent
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
return runGenericCliAgentTurn({
|
|
1483
|
+
provider,
|
|
1484
|
+
cwd,
|
|
1485
|
+
prompt: prompt2,
|
|
1486
|
+
launchCommand: genericProviderLaunchCommand(provider),
|
|
1487
|
+
onEvent
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
async function resumeProviderSession(provider, sessionKey, cwd, prompt2, onEvent) {
|
|
1491
|
+
if (provider === "codex") {
|
|
1492
|
+
return runCodexAppServerTurn({
|
|
1493
|
+
cwd,
|
|
1494
|
+
prompt: prompt2,
|
|
1495
|
+
sessionKey,
|
|
1496
|
+
launchCommand: "codex app-server (thread/resume)",
|
|
1497
|
+
onEvent
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
if (provider === "claude_code") {
|
|
1501
|
+
return runClaudeSdkTurn({
|
|
1468
1502
|
cwd,
|
|
1469
1503
|
prompt: prompt2,
|
|
1470
1504
|
sessionKey,
|
|
1471
|
-
launchCommand: "
|
|
1505
|
+
launchCommand: "@anthropic-ai/claude-agent-sdk query(resume)",
|
|
1506
|
+
onEvent
|
|
1472
1507
|
});
|
|
1473
1508
|
}
|
|
1474
|
-
return
|
|
1509
|
+
return runGenericCliAgentTurn({
|
|
1510
|
+
provider,
|
|
1475
1511
|
cwd,
|
|
1476
1512
|
prompt: prompt2,
|
|
1477
1513
|
sessionKey,
|
|
1478
|
-
launchCommand:
|
|
1514
|
+
launchCommand: genericProviderLaunchCommand(provider),
|
|
1515
|
+
onEvent
|
|
1479
1516
|
});
|
|
1480
1517
|
}
|
|
1518
|
+
async function runGenericCliAgentTurn(args) {
|
|
1519
|
+
const command = genericProviderCommand(args.provider);
|
|
1520
|
+
const child = spawn2(command.bin, [...command.args, args.prompt], {
|
|
1521
|
+
cwd: args.cwd,
|
|
1522
|
+
env: { ...process.env },
|
|
1523
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1524
|
+
});
|
|
1525
|
+
let stdout = "";
|
|
1526
|
+
let stderr = "";
|
|
1527
|
+
await Promise.resolve(
|
|
1528
|
+
args.onEvent?.({
|
|
1529
|
+
provider: args.provider,
|
|
1530
|
+
role: "status",
|
|
1531
|
+
text: `Starting ${providerLabel(args.provider)} CLI session`,
|
|
1532
|
+
status: "in_progress"
|
|
1533
|
+
})
|
|
1534
|
+
);
|
|
1535
|
+
child.stdout.on("data", (chunk) => {
|
|
1536
|
+
stdout += chunk.toString();
|
|
1537
|
+
});
|
|
1538
|
+
child.stderr.on("data", (chunk) => {
|
|
1539
|
+
stderr += chunk.toString();
|
|
1540
|
+
});
|
|
1541
|
+
const exit = await new Promise((resolve, reject) => {
|
|
1542
|
+
child.on("error", reject);
|
|
1543
|
+
child.on("close", (code, signal) => resolve({ code, signal }));
|
|
1544
|
+
});
|
|
1545
|
+
if (exit.code && exit.code !== 0) {
|
|
1546
|
+
const message = stderr.trim() || `${providerLabel(args.provider)} exited with code ${exit.code}`;
|
|
1547
|
+
await Promise.resolve(
|
|
1548
|
+
args.onEvent?.({
|
|
1549
|
+
provider: args.provider,
|
|
1550
|
+
role: "error",
|
|
1551
|
+
text: message,
|
|
1552
|
+
title: `${providerLabel(args.provider)} failed`,
|
|
1553
|
+
status: "failed"
|
|
1554
|
+
})
|
|
1555
|
+
);
|
|
1556
|
+
throw new Error(message);
|
|
1557
|
+
}
|
|
1558
|
+
const responseText = stdout.trim();
|
|
1559
|
+
if (responseText) {
|
|
1560
|
+
await Promise.resolve(
|
|
1561
|
+
args.onEvent?.({
|
|
1562
|
+
provider: args.provider,
|
|
1563
|
+
role: "assistant",
|
|
1564
|
+
text: responseText,
|
|
1565
|
+
status: "completed"
|
|
1566
|
+
})
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
return {
|
|
1570
|
+
provider: args.provider,
|
|
1571
|
+
providerLabel: providerLabel(args.provider),
|
|
1572
|
+
sessionKey: args.sessionKey ?? `${args.provider}:${Date.now()}`,
|
|
1573
|
+
cwd: args.cwd,
|
|
1574
|
+
...getGitInfo(args.cwd),
|
|
1575
|
+
title: summarizeTitle(responseText, args.cwd) ?? providerLabel(args.provider),
|
|
1576
|
+
mode: "managed",
|
|
1577
|
+
status: "waiting",
|
|
1578
|
+
supportsInboundMessages: true,
|
|
1579
|
+
responseText,
|
|
1580
|
+
launchCommand: args.launchCommand
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
function genericProviderCommand(provider) {
|
|
1584
|
+
if (provider === "cursor") return { bin: "cursor-agent", args: ["--print"] };
|
|
1585
|
+
if (provider === "copilot") return { bin: "copilot", args: [] };
|
|
1586
|
+
if (provider === "opencode") return { bin: "opencode", args: ["run"] };
|
|
1587
|
+
return { bin: "pi", args: [] };
|
|
1588
|
+
}
|
|
1589
|
+
function genericProviderLaunchCommand(provider) {
|
|
1590
|
+
const command = genericProviderCommand(provider);
|
|
1591
|
+
return [command.bin, ...command.args].join(" ");
|
|
1592
|
+
}
|
|
1593
|
+
function providerLabel(provider) {
|
|
1594
|
+
if (provider === "codex") return "Codex";
|
|
1595
|
+
if (provider === "claude_code") return "Claude";
|
|
1596
|
+
if (provider === "cursor") return "Cursor";
|
|
1597
|
+
if (provider === "copilot") return "GitHub Copilot";
|
|
1598
|
+
if (provider === "opencode") return "OpenCode";
|
|
1599
|
+
return "Pi";
|
|
1600
|
+
}
|
|
1481
1601
|
async function runCodexAppServerTurn(args) {
|
|
1482
1602
|
const child = spawn2("codex", ["app-server"], {
|
|
1483
1603
|
cwd: args.cwd,
|
|
@@ -1488,6 +1608,8 @@ async function runCodexAppServerTurn(args) {
|
|
|
1488
1608
|
let stdoutBuffer = "";
|
|
1489
1609
|
let sessionKey = args.sessionKey;
|
|
1490
1610
|
let finalAssistantText = "";
|
|
1611
|
+
let activeAssistantText = "";
|
|
1612
|
+
const eventWrites = [];
|
|
1491
1613
|
let completed = false;
|
|
1492
1614
|
let nextRequestId = 1;
|
|
1493
1615
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -1503,6 +1625,9 @@ async function runCodexAppServerTurn(args) {
|
|
|
1503
1625
|
reject(error);
|
|
1504
1626
|
};
|
|
1505
1627
|
});
|
|
1628
|
+
const emitEvent = (event) => {
|
|
1629
|
+
eventWrites.push(Promise.resolve(args.onEvent?.(event)));
|
|
1630
|
+
};
|
|
1506
1631
|
child.stdout.on("data", (chunk) => {
|
|
1507
1632
|
stdoutBuffer += chunk.toString();
|
|
1508
1633
|
while (true) {
|
|
@@ -1519,11 +1644,11 @@ async function runCodexAppServerTurn(args) {
|
|
|
1519
1644
|
if (!payload || typeof payload !== "object") {
|
|
1520
1645
|
continue;
|
|
1521
1646
|
}
|
|
1522
|
-
const responseId = payload
|
|
1647
|
+
const responseId = readProperty(payload, "id");
|
|
1523
1648
|
if (typeof responseId === "number" && pending.has(responseId)) {
|
|
1524
1649
|
const entry = pending.get(responseId);
|
|
1525
1650
|
pending.delete(responseId);
|
|
1526
|
-
const errorRecord = asObject(payload
|
|
1651
|
+
const errorRecord = asObject(readProperty(payload, "error"));
|
|
1527
1652
|
if (errorRecord) {
|
|
1528
1653
|
entry.reject(
|
|
1529
1654
|
new Error(
|
|
@@ -1532,11 +1657,11 @@ async function runCodexAppServerTurn(args) {
|
|
|
1532
1657
|
);
|
|
1533
1658
|
continue;
|
|
1534
1659
|
}
|
|
1535
|
-
entry.resolve(payload
|
|
1660
|
+
entry.resolve(readProperty(payload, "result"));
|
|
1536
1661
|
continue;
|
|
1537
1662
|
}
|
|
1538
|
-
const method = asString(payload
|
|
1539
|
-
const params = asObject(payload
|
|
1663
|
+
const method = asString(readProperty(payload, "method"));
|
|
1664
|
+
const params = asObject(readProperty(payload, "params"));
|
|
1540
1665
|
if (!method || !params) {
|
|
1541
1666
|
continue;
|
|
1542
1667
|
}
|
|
@@ -1545,13 +1670,46 @@ async function runCodexAppServerTurn(args) {
|
|
|
1545
1670
|
continue;
|
|
1546
1671
|
}
|
|
1547
1672
|
if (method === "item/agentMessage/delta") {
|
|
1548
|
-
|
|
1673
|
+
const delta = asString(params.delta) ?? "";
|
|
1674
|
+
finalAssistantText += delta;
|
|
1675
|
+
activeAssistantText += delta;
|
|
1549
1676
|
continue;
|
|
1550
1677
|
}
|
|
1551
1678
|
if (method === "item/completed") {
|
|
1552
1679
|
const item = asObject(params.item);
|
|
1553
|
-
|
|
1680
|
+
const itemType = asString(item?.type);
|
|
1681
|
+
if (itemType === "agentMessage") {
|
|
1554
1682
|
finalAssistantText = asString(item?.text) ?? finalAssistantText;
|
|
1683
|
+
const text2 = finalAssistantText || activeAssistantText;
|
|
1684
|
+
if (text2.trim()) {
|
|
1685
|
+
emitEvent({
|
|
1686
|
+
provider: "codex",
|
|
1687
|
+
role: "assistant",
|
|
1688
|
+
text: text2.trim(),
|
|
1689
|
+
status: "completed"
|
|
1690
|
+
});
|
|
1691
|
+
}
|
|
1692
|
+
activeAssistantText = "";
|
|
1693
|
+
} else if (itemType === "reasoning") {
|
|
1694
|
+
const text2 = asString(item?.text) ?? asString(item?.summary);
|
|
1695
|
+
if (text2?.trim()) {
|
|
1696
|
+
emitEvent({
|
|
1697
|
+
provider: "codex",
|
|
1698
|
+
role: "reasoning",
|
|
1699
|
+
text: text2.trim(),
|
|
1700
|
+
status: "completed"
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
} else if (itemType === "toolCall") {
|
|
1704
|
+
const title = asString(item?.title) ?? asString(item?.name) ?? asString(item?.command) ?? "Tool";
|
|
1705
|
+
const text2 = asString(item?.text) ?? asString(item?.output) ?? asString(item?.command) ?? title;
|
|
1706
|
+
emitEvent({
|
|
1707
|
+
provider: "codex",
|
|
1708
|
+
role: "tool",
|
|
1709
|
+
title,
|
|
1710
|
+
text: text2,
|
|
1711
|
+
status: asString(item?.status) === "failed" ? "failed" : "completed"
|
|
1712
|
+
});
|
|
1555
1713
|
}
|
|
1556
1714
|
continue;
|
|
1557
1715
|
}
|
|
@@ -1560,12 +1718,25 @@ async function runCodexAppServerTurn(args) {
|
|
|
1560
1718
|
const status = asString(turn?.status);
|
|
1561
1719
|
if (status === "failed") {
|
|
1562
1720
|
const turnError = asObject(turn?.error);
|
|
1721
|
+
emitEvent({
|
|
1722
|
+
provider: "codex",
|
|
1723
|
+
role: "error",
|
|
1724
|
+
title: "Codex turn failed",
|
|
1725
|
+
text: asString(turnError?.message) ?? "Codex turn failed without an error message",
|
|
1726
|
+
status: "failed"
|
|
1727
|
+
});
|
|
1563
1728
|
failTurn?.(
|
|
1564
1729
|
new Error(
|
|
1565
1730
|
asString(turnError?.message) ?? "Codex turn failed without an error message"
|
|
1566
1731
|
)
|
|
1567
1732
|
);
|
|
1568
1733
|
} else if (status === "interrupted") {
|
|
1734
|
+
emitEvent({
|
|
1735
|
+
provider: "codex",
|
|
1736
|
+
role: "status",
|
|
1737
|
+
text: "Codex turn was interrupted",
|
|
1738
|
+
status: "failed"
|
|
1739
|
+
});
|
|
1569
1740
|
failTurn?.(new Error("Codex turn was interrupted"));
|
|
1570
1741
|
} else {
|
|
1571
1742
|
completeTurn?.();
|
|
@@ -1607,21 +1778,23 @@ async function runCodexAppServerTurn(args) {
|
|
|
1607
1778
|
waitForExit
|
|
1608
1779
|
]);
|
|
1609
1780
|
notify("initialized", {});
|
|
1610
|
-
const threadResult =
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1781
|
+
const threadResult = asObject(
|
|
1782
|
+
await Promise.race([
|
|
1783
|
+
args.sessionKey ? request("thread/resume", {
|
|
1784
|
+
threadId: args.sessionKey,
|
|
1785
|
+
cwd: args.cwd,
|
|
1786
|
+
approvalPolicy: "never",
|
|
1787
|
+
personality: "pragmatic"
|
|
1788
|
+
}) : request("thread/start", {
|
|
1789
|
+
cwd: args.cwd,
|
|
1790
|
+
approvalPolicy: "never",
|
|
1791
|
+
personality: "pragmatic",
|
|
1792
|
+
serviceName: "vector_bridge"
|
|
1793
|
+
}),
|
|
1794
|
+
waitForExit
|
|
1795
|
+
])
|
|
1796
|
+
);
|
|
1797
|
+
sessionKey = asString(asObject(readProperty(threadResult, "thread"))?.id) ?? asString(asObject(readProperty(threadResult, "thread"))?.threadId) ?? sessionKey;
|
|
1625
1798
|
if (!sessionKey) {
|
|
1626
1799
|
throw new Error("Codex app-server did not return a thread id");
|
|
1627
1800
|
}
|
|
@@ -1636,6 +1809,7 @@ async function runCodexAppServerTurn(args) {
|
|
|
1636
1809
|
waitForExit
|
|
1637
1810
|
]);
|
|
1638
1811
|
await Promise.race([turnCompleted, waitForExit]);
|
|
1812
|
+
await Promise.allSettled(eventWrites);
|
|
1639
1813
|
const gitInfo = getGitInfo(args.cwd);
|
|
1640
1814
|
return {
|
|
1641
1815
|
provider: "codex",
|
|
@@ -1684,30 +1858,40 @@ async function runClaudeSdkTurn(args) {
|
|
|
1684
1858
|
if (!message || typeof message !== "object") {
|
|
1685
1859
|
continue;
|
|
1686
1860
|
}
|
|
1687
|
-
sessionKey = asString(message
|
|
1688
|
-
if (message
|
|
1861
|
+
sessionKey = asString(readProperty(message, "session_id")) ?? sessionKey;
|
|
1862
|
+
if (readProperty(message, "type") === "assistant") {
|
|
1689
1863
|
const assistantText = extractClaudeMessageTexts(
|
|
1690
|
-
message
|
|
1864
|
+
readProperty(message, "message")
|
|
1691
1865
|
).join("\n\n").trim();
|
|
1692
1866
|
if (assistantText) {
|
|
1693
1867
|
responseText = assistantText;
|
|
1868
|
+
await args.onEvent?.({
|
|
1869
|
+
provider: "claude_code",
|
|
1870
|
+
role: "assistant",
|
|
1871
|
+
text: assistantText,
|
|
1872
|
+
status: "completed"
|
|
1873
|
+
});
|
|
1694
1874
|
}
|
|
1695
1875
|
continue;
|
|
1696
1876
|
}
|
|
1697
|
-
if (message
|
|
1877
|
+
if (readProperty(message, "type") !== "result") {
|
|
1698
1878
|
continue;
|
|
1699
1879
|
}
|
|
1700
|
-
if (message
|
|
1701
|
-
const resultText = asString(message
|
|
1880
|
+
if (readProperty(message, "subtype") === "success") {
|
|
1881
|
+
const resultText = asString(readProperty(message, "result"));
|
|
1702
1882
|
if (resultText) {
|
|
1703
1883
|
responseText = resultText;
|
|
1884
|
+
await args.onEvent?.({
|
|
1885
|
+
provider: "claude_code",
|
|
1886
|
+
role: "assistant",
|
|
1887
|
+
text: resultText,
|
|
1888
|
+
status: "completed"
|
|
1889
|
+
});
|
|
1704
1890
|
}
|
|
1705
|
-
model = firstObjectKey(
|
|
1706
|
-
message.modelUsage
|
|
1707
|
-
);
|
|
1891
|
+
model = firstObjectKey(readProperty(message, "modelUsage"));
|
|
1708
1892
|
continue;
|
|
1709
1893
|
}
|
|
1710
|
-
const errors = message
|
|
1894
|
+
const errors = readProperty(message, "errors");
|
|
1711
1895
|
const detail = Array.isArray(errors) && errors.length > 0 ? errors.join("\n") : "Claude execution failed";
|
|
1712
1896
|
throw new Error(detail);
|
|
1713
1897
|
}
|
|
@@ -2117,11 +2301,17 @@ function normalizeModelKey(value) {
|
|
|
2117
2301
|
return normalized || void 0;
|
|
2118
2302
|
}
|
|
2119
2303
|
function asObject(value) {
|
|
2120
|
-
return value
|
|
2304
|
+
return isRecord(value) ? value : void 0;
|
|
2305
|
+
}
|
|
2306
|
+
function readProperty(value, key) {
|
|
2307
|
+
return isRecord(value) ? Reflect.get(value, key) : void 0;
|
|
2121
2308
|
}
|
|
2122
2309
|
function asString(value) {
|
|
2123
2310
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2124
2311
|
}
|
|
2312
|
+
function isRecord(value) {
|
|
2313
|
+
return value !== null && typeof value === "object";
|
|
2314
|
+
}
|
|
2125
2315
|
function pushIfPresent(target, value) {
|
|
2126
2316
|
const text2 = asString(value);
|
|
2127
2317
|
if (text2) {
|
|
@@ -2285,11 +2475,13 @@ function getGitInfo(cwd) {
|
|
|
2285
2475
|
const repoRoot = execSync("git rev-parse --show-toplevel", {
|
|
2286
2476
|
encoding: "utf-8",
|
|
2287
2477
|
cwd,
|
|
2478
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2288
2479
|
timeout: 3e3
|
|
2289
2480
|
}).trim();
|
|
2290
2481
|
const branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
2291
2482
|
encoding: "utf-8",
|
|
2292
2483
|
cwd,
|
|
2484
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2293
2485
|
timeout: 3e3
|
|
2294
2486
|
}).trim();
|
|
2295
2487
|
return {
|
|
@@ -2341,6 +2533,8 @@ var BridgeService = class {
|
|
|
2341
2533
|
constructor(config) {
|
|
2342
2534
|
this.timers = [];
|
|
2343
2535
|
this.terminalPeer = null;
|
|
2536
|
+
this.stopping = false;
|
|
2537
|
+
this.runningLoops = /* @__PURE__ */ new Set();
|
|
2344
2538
|
this.deviceLiveActivities = [];
|
|
2345
2539
|
this.config = config;
|
|
2346
2540
|
this.client = new ConvexHttpClient2(config.convexUrl);
|
|
@@ -2366,6 +2560,30 @@ var BridgeService = class {
|
|
|
2366
2560
|
await this.handleCommand(cmd);
|
|
2367
2561
|
}
|
|
2368
2562
|
}
|
|
2563
|
+
scheduleLoop(name, intervalMs, run) {
|
|
2564
|
+
this.timers.push(
|
|
2565
|
+
setInterval(() => {
|
|
2566
|
+
if (this.stopping || this.runningLoops.has(name)) {
|
|
2567
|
+
return;
|
|
2568
|
+
}
|
|
2569
|
+
this.runningLoops.add(name);
|
|
2570
|
+
run().catch((error) => {
|
|
2571
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2572
|
+
console.error(`[${ts2()}] ${name} error:`, message);
|
|
2573
|
+
}).finally(() => {
|
|
2574
|
+
this.runningLoops.delete(name);
|
|
2575
|
+
});
|
|
2576
|
+
}, intervalMs)
|
|
2577
|
+
);
|
|
2578
|
+
}
|
|
2579
|
+
async runStartupStep(label, step) {
|
|
2580
|
+
try {
|
|
2581
|
+
await step();
|
|
2582
|
+
} catch (error) {
|
|
2583
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2584
|
+
console.error(`[${ts2()}] Startup ${label} failed: ${message}`);
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2369
2587
|
async handleCommand(cmd) {
|
|
2370
2588
|
const claimed = await this.client.mutation(
|
|
2371
2589
|
api.agentBridge.bridgePublic.claimCommand,
|
|
@@ -2378,6 +2596,18 @@ var BridgeService = class {
|
|
|
2378
2596
|
if (!claimed) {
|
|
2379
2597
|
return;
|
|
2380
2598
|
}
|
|
2599
|
+
if (cmd.kind === "settings_update" || cmd.kind === "queue_update" || cmd.kind === "approval_response" || cmd.kind === "plan_response" || cmd.kind === "question_response" || cmd.kind === "stop" || cmd.kind === "resume") {
|
|
2600
|
+
try {
|
|
2601
|
+
await this.handleAgentControlCommand(cmd);
|
|
2602
|
+
await this.completeCommand(cmd._id, "delivered");
|
|
2603
|
+
} catch (error) {
|
|
2604
|
+
const message = error instanceof Error ? error.message : "Unknown bridge error";
|
|
2605
|
+
console.error(` ! ${message}`);
|
|
2606
|
+
await this.postCommandError(cmd, message);
|
|
2607
|
+
await this.completeCommand(cmd._id, "failed");
|
|
2608
|
+
}
|
|
2609
|
+
return;
|
|
2610
|
+
}
|
|
2381
2611
|
console.log(` ${cmd.kind}: ${cmd._id}`);
|
|
2382
2612
|
try {
|
|
2383
2613
|
switch (cmd.kind) {
|
|
@@ -2526,20 +2756,20 @@ var BridgeService = class {
|
|
|
2526
2756
|
await this.postAgentMessage(
|
|
2527
2757
|
activity._id,
|
|
2528
2758
|
"status",
|
|
2529
|
-
`Verified ${
|
|
2759
|
+
`Verified ${providerLabel2(attachedSession.process.provider)} in ${activity.tmuxPaneId}`
|
|
2530
2760
|
);
|
|
2531
2761
|
await this.updateLiveActivity(activity._id, {
|
|
2532
2762
|
status: "active",
|
|
2533
|
-
latestSummary: `Verified ${
|
|
2763
|
+
latestSummary: `Verified ${providerLabel2(attachedSession.process.provider)} in ${activity.tmuxPaneId}`,
|
|
2534
2764
|
processId: attachedSession.processId,
|
|
2535
2765
|
title: activity.title
|
|
2536
2766
|
});
|
|
2537
2767
|
}
|
|
2538
2768
|
async refreshWorkSessionTerminal(workSessionId, metadata) {
|
|
2539
|
-
if (!workSessionId
|
|
2769
|
+
if (!workSessionId) {
|
|
2540
2770
|
return;
|
|
2541
2771
|
}
|
|
2542
|
-
const terminalSnapshot = captureTmuxPane(metadata.tmuxPaneId);
|
|
2772
|
+
const terminalSnapshot = metadata.tmuxPaneId ? captureTmuxPane(metadata.tmuxPaneId) : void 0;
|
|
2543
2773
|
await this.client.mutation(
|
|
2544
2774
|
api.agentBridge.bridgePublic.updateWorkSessionTerminal,
|
|
2545
2775
|
{
|
|
@@ -2554,7 +2784,13 @@ var BridgeService = class {
|
|
|
2554
2784
|
repoRoot: metadata.repoRoot,
|
|
2555
2785
|
branch: metadata.branch,
|
|
2556
2786
|
agentProvider: metadata.agentProvider,
|
|
2557
|
-
agentSessionKey: metadata.agentSessionKey
|
|
2787
|
+
agentSessionKey: metadata.agentSessionKey,
|
|
2788
|
+
agentProcessId: metadata.agentProcessId,
|
|
2789
|
+
model: metadata.model,
|
|
2790
|
+
permissionMode: metadata.permissionMode,
|
|
2791
|
+
thinkingLevel: metadata.thinkingLevel,
|
|
2792
|
+
fastMode: metadata.fastMode,
|
|
2793
|
+
contextLength: metadata.contextLength
|
|
2558
2794
|
}
|
|
2559
2795
|
);
|
|
2560
2796
|
}
|
|
@@ -2584,51 +2820,60 @@ var BridgeService = class {
|
|
|
2584
2820
|
);
|
|
2585
2821
|
}
|
|
2586
2822
|
console.log("");
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2823
|
+
process.on("uncaughtException", (error) => {
|
|
2824
|
+
console.error(`[${ts2()}] Uncaught error:`, error.message);
|
|
2825
|
+
});
|
|
2826
|
+
process.on("unhandledRejection", (reason) => {
|
|
2827
|
+
console.error(
|
|
2828
|
+
`[${ts2()}] Unhandled rejection:`,
|
|
2829
|
+
reason instanceof Error ? reason.message : String(reason)
|
|
2830
|
+
);
|
|
2831
|
+
});
|
|
2832
|
+
await this.runStartupStep("heartbeat", () => this.heartbeat());
|
|
2833
|
+
await this.runStartupStep(
|
|
2834
|
+
"process discovery",
|
|
2835
|
+
() => this.reportProcesses()
|
|
2836
|
+
);
|
|
2837
|
+
await this.runStartupStep(
|
|
2838
|
+
"live activity sync",
|
|
2839
|
+
() => this.refreshLiveActivities()
|
|
2840
|
+
);
|
|
2841
|
+
await this.runStartupStep(
|
|
2842
|
+
"terminal snapshot sync",
|
|
2843
|
+
() => this.syncWorkSessionTerminals(this.deviceLiveActivities)
|
|
2844
|
+
);
|
|
2591
2845
|
console.log(`[${ts2()}] Service running. Ctrl+C to stop.
|
|
2592
2846
|
`);
|
|
2593
|
-
this.
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
);
|
|
2598
|
-
}, HEARTBEAT_INTERVAL_MS)
|
|
2847
|
+
this.scheduleLoop(
|
|
2848
|
+
"Heartbeat",
|
|
2849
|
+
HEARTBEAT_INTERVAL_MS,
|
|
2850
|
+
() => this.heartbeat()
|
|
2599
2851
|
);
|
|
2600
|
-
this.
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
);
|
|
2605
|
-
}, COMMAND_POLL_INTERVAL_MS)
|
|
2852
|
+
this.scheduleLoop(
|
|
2853
|
+
"Command poll",
|
|
2854
|
+
COMMAND_POLL_INTERVAL_MS,
|
|
2855
|
+
() => this.pollCommands()
|
|
2606
2856
|
);
|
|
2607
|
-
this.
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
);
|
|
2612
|
-
}, LIVE_ACTIVITY_SYNC_INTERVAL_MS)
|
|
2857
|
+
this.scheduleLoop(
|
|
2858
|
+
"Live activity sync",
|
|
2859
|
+
LIVE_ACTIVITY_SYNC_INTERVAL_MS,
|
|
2860
|
+
() => this.refreshLiveActivities()
|
|
2613
2861
|
);
|
|
2614
|
-
this.
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
);
|
|
2619
|
-
}, PROCESS_DISCOVERY_INTERVAL_MS)
|
|
2862
|
+
this.scheduleLoop(
|
|
2863
|
+
"Discovery",
|
|
2864
|
+
PROCESS_DISCOVERY_INTERVAL_MS,
|
|
2865
|
+
() => this.reportProcesses()
|
|
2620
2866
|
);
|
|
2621
|
-
this.
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
`[${ts2()}] Terminal snapshot refresh error:`,
|
|
2626
|
-
e.message
|
|
2627
|
-
)
|
|
2628
|
-
);
|
|
2629
|
-
}, TERMINAL_SNAPSHOT_REFRESH_INTERVAL_MS)
|
|
2867
|
+
this.scheduleLoop(
|
|
2868
|
+
"Terminal snapshot refresh",
|
|
2869
|
+
TERMINAL_SNAPSHOT_REFRESH_INTERVAL_MS,
|
|
2870
|
+
() => this.syncWorkSessionTerminals(this.deviceLiveActivities)
|
|
2630
2871
|
);
|
|
2631
2872
|
const shutdown = () => {
|
|
2873
|
+
if (this.stopping) {
|
|
2874
|
+
return;
|
|
2875
|
+
}
|
|
2876
|
+
this.stopping = true;
|
|
2632
2877
|
console.log(`
|
|
2633
2878
|
[${ts2()}] Shutting down...`);
|
|
2634
2879
|
for (const t of this.timers) clearInterval(t);
|
|
@@ -2652,15 +2897,16 @@ var BridgeService = class {
|
|
|
2652
2897
|
if (!cmd.liveActivityId) {
|
|
2653
2898
|
throw new Error("Message command is missing liveActivityId");
|
|
2654
2899
|
}
|
|
2655
|
-
const
|
|
2656
|
-
const body = payload?.body?.trim();
|
|
2900
|
+
const body = readPayloadString(cmd.payload, "body")?.trim();
|
|
2657
2901
|
if (!body) {
|
|
2658
2902
|
throw new Error("Message command is missing a body");
|
|
2659
2903
|
}
|
|
2904
|
+
const issueContext = readPayloadValue(cmd.payload, "issueContext");
|
|
2660
2905
|
const process9 = cmd.process;
|
|
2661
2906
|
console.log(` > "${truncateForLog(body)}"`);
|
|
2662
2907
|
if (cmd.workSession?.tmuxPaneId) {
|
|
2663
|
-
|
|
2908
|
+
const terminalInput = cmd.workSession.agentProvider && isBridgeProvider(cmd.workSession.agentProvider) ? buildFollowUpPrompt(body, issueContext) : body;
|
|
2909
|
+
sendTextToTmuxPane(cmd.workSession.tmuxPaneId, terminalInput);
|
|
2664
2910
|
const attachedSession = cmd.workSession.agentProvider && isBridgeProvider(cmd.workSession.agentProvider) ? await this.attachObservedAgentSession(
|
|
2665
2911
|
cmd.workSession.agentProvider,
|
|
2666
2912
|
cmd.workSession.workspacePath ?? cmd.workSession.cwd ?? process9?.cwd
|
|
@@ -2693,13 +2939,17 @@ var BridgeService = class {
|
|
|
2693
2939
|
}
|
|
2694
2940
|
await this.reportProcess({
|
|
2695
2941
|
provider: process9.provider,
|
|
2696
|
-
providerLabel: process9.providerLabel ??
|
|
2942
|
+
providerLabel: process9.providerLabel ?? providerLabel2(process9.provider),
|
|
2697
2943
|
sessionKey: process9.sessionKey,
|
|
2698
2944
|
cwd: process9.cwd,
|
|
2699
2945
|
repoRoot: process9.repoRoot,
|
|
2700
2946
|
branch: process9.branch,
|
|
2701
2947
|
title: process9.title,
|
|
2702
2948
|
model: process9.model,
|
|
2949
|
+
permissionMode: process9.permissionMode,
|
|
2950
|
+
thinkingLevel: process9.thinkingLevel,
|
|
2951
|
+
fastMode: process9.fastMode,
|
|
2952
|
+
contextLength: process9.contextLength,
|
|
2703
2953
|
mode: "managed",
|
|
2704
2954
|
status: "waiting",
|
|
2705
2955
|
supportsInboundMessages: true
|
|
@@ -2709,14 +2959,20 @@ var BridgeService = class {
|
|
|
2709
2959
|
processId: process9._id,
|
|
2710
2960
|
title: cmd.liveActivity?.title ?? process9.title
|
|
2711
2961
|
});
|
|
2962
|
+
const liveActivityId = cmd.liveActivityId;
|
|
2963
|
+
let emittedAssistantEvent = false;
|
|
2712
2964
|
const result = await resumeProviderSession(
|
|
2713
2965
|
process9.provider,
|
|
2714
2966
|
process9.sessionKey,
|
|
2715
2967
|
process9.cwd,
|
|
2716
|
-
body
|
|
2968
|
+
buildFollowUpPrompt(body, issueContext),
|
|
2969
|
+
(event) => {
|
|
2970
|
+
if (event.role === "assistant") emittedAssistantEvent = true;
|
|
2971
|
+
return this.postAgentSessionEvent(liveActivityId, event);
|
|
2972
|
+
}
|
|
2717
2973
|
);
|
|
2718
2974
|
const processId = await this.reportProcess(result);
|
|
2719
|
-
if (result.responseText) {
|
|
2975
|
+
if (result.responseText && !emittedAssistantEvent) {
|
|
2720
2976
|
await this.postAgentMessage(
|
|
2721
2977
|
cmd.liveActivityId,
|
|
2722
2978
|
"assistant",
|
|
@@ -2732,9 +2988,8 @@ var BridgeService = class {
|
|
|
2732
2988
|
});
|
|
2733
2989
|
}
|
|
2734
2990
|
async handleResizeCommand(cmd) {
|
|
2735
|
-
const
|
|
2736
|
-
const
|
|
2737
|
-
const rows = payload?.rows;
|
|
2991
|
+
const cols = readPayloadNumber(cmd.payload, "cols");
|
|
2992
|
+
const rows = readPayloadNumber(cmd.payload, "rows");
|
|
2738
2993
|
const paneId = cmd.workSession?.tmuxPaneId;
|
|
2739
2994
|
if (!paneId || !cols || !rows) {
|
|
2740
2995
|
throw new Error("Resize command missing paneId, cols, or rows");
|
|
@@ -2754,35 +3009,142 @@ var BridgeService = class {
|
|
|
2754
3009
|
});
|
|
2755
3010
|
}
|
|
2756
3011
|
}
|
|
3012
|
+
async handleAgentControlCommand(cmd) {
|
|
3013
|
+
if (!cmd.liveActivityId) {
|
|
3014
|
+
throw new Error(`${cmd.kind} command is missing liveActivityId`);
|
|
3015
|
+
}
|
|
3016
|
+
if (cmd.kind === "settings_update") {
|
|
3017
|
+
await this.postAgentMessage(
|
|
3018
|
+
cmd.liveActivityId,
|
|
3019
|
+
"status",
|
|
3020
|
+
"Updated agent settings"
|
|
3021
|
+
);
|
|
3022
|
+
return;
|
|
3023
|
+
}
|
|
3024
|
+
if (cmd.kind === "queue_update") {
|
|
3025
|
+
await this.postAgentMessage(
|
|
3026
|
+
cmd.liveActivityId,
|
|
3027
|
+
"status",
|
|
3028
|
+
"Updated queued agent messages"
|
|
3029
|
+
);
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
if (cmd.kind === "stop") {
|
|
3033
|
+
await this.updateLiveActivity(cmd.liveActivityId, {
|
|
3034
|
+
status: "paused",
|
|
3035
|
+
latestSummary: "Agent turn stop requested"
|
|
3036
|
+
});
|
|
3037
|
+
await this.postAgentMessage(
|
|
3038
|
+
cmd.liveActivityId,
|
|
3039
|
+
"status",
|
|
3040
|
+
"Stop requested for the local agent session"
|
|
3041
|
+
);
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
3044
|
+
if (cmd.kind === "resume") {
|
|
3045
|
+
await this.updateLiveActivity(cmd.liveActivityId, {
|
|
3046
|
+
status: "active",
|
|
3047
|
+
latestSummary: "Agent session resumed"
|
|
3048
|
+
});
|
|
3049
|
+
return;
|
|
3050
|
+
}
|
|
3051
|
+
const label = cmd.kind === "approval_response" ? "approval" : cmd.kind === "plan_response" ? "plan approval" : "question response";
|
|
3052
|
+
await this.postAgentMessage(
|
|
3053
|
+
cmd.liveActivityId,
|
|
3054
|
+
"status",
|
|
3055
|
+
`Received ${label}; the provider runtime will continue when supported`
|
|
3056
|
+
);
|
|
3057
|
+
}
|
|
2757
3058
|
async handleLaunchCommand(cmd) {
|
|
2758
3059
|
if (!cmd.liveActivityId) {
|
|
2759
3060
|
throw new Error("Launch command is missing liveActivityId");
|
|
2760
3061
|
}
|
|
2761
|
-
const
|
|
2762
|
-
|
|
3062
|
+
const workspacePath = readPayloadString(
|
|
3063
|
+
cmd.payload,
|
|
3064
|
+
"workspacePath"
|
|
3065
|
+
)?.trim();
|
|
2763
3066
|
if (!workspacePath) {
|
|
2764
3067
|
throw new Error("Launch command is missing workspacePath");
|
|
2765
3068
|
}
|
|
2766
|
-
const requestedProvider = payload
|
|
3069
|
+
const requestedProvider = readPayloadAgentProvider(cmd.payload, "provider");
|
|
2767
3070
|
const provider = requestedProvider && isBridgeProvider(requestedProvider) ? requestedProvider : void 0;
|
|
2768
|
-
const issueKey = payload
|
|
2769
|
-
const issueTitle = payload
|
|
2770
|
-
const issueDescription = payload
|
|
3071
|
+
const issueKey = readPayloadString(cmd.payload, "issueKey") ?? cmd.liveActivity?.issueKey ?? "ISSUE";
|
|
3072
|
+
const issueTitle = readPayloadString(cmd.payload, "issueTitle") ?? cmd.liveActivity?.issueTitle ?? "Untitled issue";
|
|
3073
|
+
const issueDescription = readPayloadString(cmd.payload, "issueDescription");
|
|
3074
|
+
const issueContext = readPayloadValue(cmd.payload, "issueContext");
|
|
3075
|
+
const model = readPayloadString(cmd.payload, "model");
|
|
3076
|
+
const permissionMode = readPayloadPermissionMode(
|
|
3077
|
+
cmd.payload,
|
|
3078
|
+
"permissionMode"
|
|
3079
|
+
);
|
|
3080
|
+
const thinkingLevel = readPayloadThinkingLevel(
|
|
3081
|
+
cmd.payload,
|
|
3082
|
+
"thinkingLevel"
|
|
3083
|
+
);
|
|
3084
|
+
const fastMode = readPayloadBoolean(cmd.payload, "fastMode");
|
|
3085
|
+
const contextLength = readPayloadContextLength(
|
|
3086
|
+
cmd.payload,
|
|
3087
|
+
"contextLength"
|
|
3088
|
+
);
|
|
3089
|
+
const initialPrompt = readPayloadString(cmd.payload, "initialPrompt");
|
|
3090
|
+
const delegatedRunId = readPayloadId(
|
|
3091
|
+
cmd.payload,
|
|
3092
|
+
"delegatedRunId"
|
|
3093
|
+
);
|
|
2771
3094
|
const prompt2 = buildLaunchPrompt(
|
|
2772
3095
|
issueKey,
|
|
2773
3096
|
issueTitle,
|
|
2774
3097
|
workspacePath,
|
|
2775
|
-
issueDescription
|
|
3098
|
+
issueDescription,
|
|
3099
|
+
issueContext,
|
|
3100
|
+
initialPrompt
|
|
2776
3101
|
);
|
|
2777
|
-
const launchLabel = provider ?
|
|
3102
|
+
const launchLabel = provider ? providerLabel2(provider) : "shell session";
|
|
2778
3103
|
const workSessionTitle = `${issueKey}: ${issueTitle}`;
|
|
2779
3104
|
await this.updateLiveActivity(cmd.liveActivityId, {
|
|
2780
3105
|
status: "active",
|
|
2781
3106
|
latestSummary: `Launching ${launchLabel} in ${workspacePath}`,
|
|
2782
|
-
delegatedRunId
|
|
3107
|
+
delegatedRunId,
|
|
2783
3108
|
launchStatus: "launching",
|
|
2784
3109
|
title: workSessionTitle
|
|
2785
3110
|
});
|
|
3111
|
+
if (provider) {
|
|
3112
|
+
await this.postAgentMessage(
|
|
3113
|
+
cmd.liveActivityId,
|
|
3114
|
+
"status",
|
|
3115
|
+
`Starting ${launchLabel} session in ${workspacePath}`
|
|
3116
|
+
);
|
|
3117
|
+
const liveActivityId = cmd.liveActivityId;
|
|
3118
|
+
const result = await launchProviderSession(
|
|
3119
|
+
provider,
|
|
3120
|
+
workspacePath,
|
|
3121
|
+
prompt2,
|
|
3122
|
+
(event) => this.postAgentSessionEvent(liveActivityId, event)
|
|
3123
|
+
);
|
|
3124
|
+
const processId = await this.reportProcess(result);
|
|
3125
|
+
await this.refreshWorkSessionTerminal(cmd.workSession?._id, {
|
|
3126
|
+
cwd: workspacePath,
|
|
3127
|
+
repoRoot: result.repoRoot ?? workspacePath,
|
|
3128
|
+
branch: result.branch ?? currentGitBranch(workspacePath),
|
|
3129
|
+
agentProvider: result.provider,
|
|
3130
|
+
agentSessionKey: result.sessionKey,
|
|
3131
|
+
agentProcessId: processId,
|
|
3132
|
+
model,
|
|
3133
|
+
permissionMode,
|
|
3134
|
+
thinkingLevel,
|
|
3135
|
+
fastMode,
|
|
3136
|
+
contextLength
|
|
3137
|
+
});
|
|
3138
|
+
await this.updateLiveActivity(cmd.liveActivityId, {
|
|
3139
|
+
status: "waiting_for_input",
|
|
3140
|
+
latestSummary: summarizeMessage(result.responseText),
|
|
3141
|
+
delegatedRunId,
|
|
3142
|
+
launchStatus: "running",
|
|
3143
|
+
title: workSessionTitle,
|
|
3144
|
+
processId
|
|
3145
|
+
});
|
|
3146
|
+
return;
|
|
3147
|
+
}
|
|
2786
3148
|
const tmuxSession = createTmuxWorkSession({
|
|
2787
3149
|
workspacePath,
|
|
2788
3150
|
issueKey,
|
|
@@ -2797,12 +3159,17 @@ var BridgeService = class {
|
|
|
2797
3159
|
cwd: workspacePath,
|
|
2798
3160
|
repoRoot: workspacePath,
|
|
2799
3161
|
branch: currentGitBranch(workspacePath),
|
|
2800
|
-
agentProvider: provider
|
|
3162
|
+
agentProvider: provider,
|
|
3163
|
+
model,
|
|
3164
|
+
permissionMode,
|
|
3165
|
+
thinkingLevel,
|
|
3166
|
+
fastMode,
|
|
3167
|
+
contextLength
|
|
2801
3168
|
});
|
|
2802
3169
|
await this.updateLiveActivity(cmd.liveActivityId, {
|
|
2803
3170
|
status: "active",
|
|
2804
3171
|
latestSummary: `Running ${launchLabel} in ${tmuxSession.sessionName}`,
|
|
2805
|
-
delegatedRunId
|
|
3172
|
+
delegatedRunId,
|
|
2806
3173
|
launchStatus: "running",
|
|
2807
3174
|
title: workSessionTitle
|
|
2808
3175
|
});
|
|
@@ -2836,7 +3203,7 @@ var BridgeService = class {
|
|
|
2836
3203
|
async reportProcess(process9) {
|
|
2837
3204
|
const {
|
|
2838
3205
|
provider,
|
|
2839
|
-
providerLabel:
|
|
3206
|
+
providerLabel: providerLabel3,
|
|
2840
3207
|
localProcessId,
|
|
2841
3208
|
sessionKey,
|
|
2842
3209
|
cwd,
|
|
@@ -2844,6 +3211,10 @@ var BridgeService = class {
|
|
|
2844
3211
|
branch,
|
|
2845
3212
|
title,
|
|
2846
3213
|
model,
|
|
3214
|
+
permissionMode,
|
|
3215
|
+
thinkingLevel,
|
|
3216
|
+
fastMode,
|
|
3217
|
+
contextLength,
|
|
2847
3218
|
tmuxSessionName,
|
|
2848
3219
|
tmuxWindowName,
|
|
2849
3220
|
tmuxPaneId,
|
|
@@ -2857,7 +3228,7 @@ var BridgeService = class {
|
|
|
2857
3228
|
deviceId: this.config.deviceId,
|
|
2858
3229
|
deviceSecret: this.config.deviceSecret,
|
|
2859
3230
|
provider,
|
|
2860
|
-
providerLabel:
|
|
3231
|
+
providerLabel: providerLabel3,
|
|
2861
3232
|
localProcessId,
|
|
2862
3233
|
sessionKey,
|
|
2863
3234
|
cwd,
|
|
@@ -2865,6 +3236,10 @@ var BridgeService = class {
|
|
|
2865
3236
|
branch,
|
|
2866
3237
|
title,
|
|
2867
3238
|
model,
|
|
3239
|
+
permissionMode,
|
|
3240
|
+
thinkingLevel,
|
|
3241
|
+
fastMode,
|
|
3242
|
+
contextLength,
|
|
2868
3243
|
tmuxSessionName,
|
|
2869
3244
|
tmuxWindowName,
|
|
2870
3245
|
tmuxPaneId,
|
|
@@ -2885,13 +3260,24 @@ var BridgeService = class {
|
|
|
2885
3260
|
}
|
|
2886
3261
|
);
|
|
2887
3262
|
}
|
|
2888
|
-
async postAgentMessage(liveActivityId, role, body) {
|
|
3263
|
+
async postAgentMessage(liveActivityId, role, body, structuredPayload) {
|
|
2889
3264
|
await this.client.mutation(api.agentBridge.bridgePublic.postAgentMessage, {
|
|
2890
3265
|
deviceId: this.config.deviceId,
|
|
2891
3266
|
deviceSecret: this.config.deviceSecret,
|
|
2892
3267
|
liveActivityId,
|
|
2893
3268
|
role,
|
|
2894
|
-
body
|
|
3269
|
+
body,
|
|
3270
|
+
structuredPayload
|
|
3271
|
+
});
|
|
3272
|
+
}
|
|
3273
|
+
async postAgentSessionEvent(liveActivityId, event) {
|
|
3274
|
+
const body = event.text.trim();
|
|
3275
|
+
if (!body) return;
|
|
3276
|
+
await this.postAgentMessage(liveActivityId, event.role, body, {
|
|
3277
|
+
source: "cells_agent_event",
|
|
3278
|
+
provider: event.provider,
|
|
3279
|
+
title: event.title,
|
|
3280
|
+
status: event.status
|
|
2895
3281
|
});
|
|
2896
3282
|
}
|
|
2897
3283
|
async completeCommand(commandId, status) {
|
|
@@ -2904,11 +3290,13 @@ var BridgeService = class {
|
|
|
2904
3290
|
}
|
|
2905
3291
|
async postCommandError(cmd, errorMessage) {
|
|
2906
3292
|
if (cmd.kind === "launch" && cmd.liveActivityId) {
|
|
2907
|
-
const payload = cmd.payload;
|
|
2908
3293
|
await this.updateLiveActivity(cmd.liveActivityId, {
|
|
2909
3294
|
status: "failed",
|
|
2910
3295
|
latestSummary: errorMessage,
|
|
2911
|
-
delegatedRunId:
|
|
3296
|
+
delegatedRunId: readPayloadId(
|
|
3297
|
+
cmd.payload,
|
|
3298
|
+
"delegatedRunId"
|
|
3299
|
+
),
|
|
2912
3300
|
launchStatus: "failed"
|
|
2913
3301
|
});
|
|
2914
3302
|
await this.postAgentMessage(cmd.liveActivityId, "status", errorMessage);
|
|
@@ -3012,6 +3400,7 @@ function currentGitBranch(cwd) {
|
|
|
3012
3400
|
return execSync2("git rev-parse --abbrev-ref HEAD", {
|
|
3013
3401
|
encoding: "utf-8",
|
|
3014
3402
|
cwd,
|
|
3403
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
3015
3404
|
timeout: 3e3
|
|
3016
3405
|
}).trim();
|
|
3017
3406
|
} catch {
|
|
@@ -3022,7 +3411,14 @@ function buildManagedLaunchCommand(provider, prompt2) {
|
|
|
3022
3411
|
if (provider === "codex") {
|
|
3023
3412
|
return `codex --no-alt-screen -a never ${shellQuote(prompt2)}`;
|
|
3024
3413
|
}
|
|
3025
|
-
|
|
3414
|
+
if (provider === "claude_code") {
|
|
3415
|
+
return `claude --permission-mode bypassPermissions --dangerously-skip-permissions ${shellQuote(prompt2)}`;
|
|
3416
|
+
}
|
|
3417
|
+
if (provider === "cursor")
|
|
3418
|
+
return `cursor-agent --print ${shellQuote(prompt2)}`;
|
|
3419
|
+
if (provider === "copilot") return `copilot ${shellQuote(prompt2)}`;
|
|
3420
|
+
if (provider === "opencode") return `opencode run ${shellQuote(prompt2)}`;
|
|
3421
|
+
return `pi ${shellQuote(prompt2)}`;
|
|
3026
3422
|
}
|
|
3027
3423
|
function sanitizeTmuxName(value) {
|
|
3028
3424
|
return value.replace(/[^a-z0-9_-]+/gi, "-").replace(/^-+|-+$/g, "") || "work";
|
|
@@ -3079,11 +3475,18 @@ function persistDeviceKey(deviceKey) {
|
|
|
3079
3475
|
writeFileSync(DEVICE_KEY_FILE, `${deviceKey}
|
|
3080
3476
|
`);
|
|
3081
3477
|
}
|
|
3082
|
-
function buildLaunchPrompt(issueKey, issueTitle, workspacePath, issueDescription) {
|
|
3478
|
+
function buildLaunchPrompt(issueKey, issueTitle, workspacePath, issueDescription, issueContext, initialPrompt) {
|
|
3083
3479
|
const lines = [`You are working on issue ${issueKey}: ${issueTitle}`];
|
|
3084
3480
|
if (issueDescription?.trim()) {
|
|
3085
3481
|
lines.push("", "Issue description:", issueDescription.trim());
|
|
3086
3482
|
}
|
|
3483
|
+
const contextLines = formatIssueContext(issueContext);
|
|
3484
|
+
if (contextLines.length > 0) {
|
|
3485
|
+
lines.push("", "Vector context:", ...contextLines);
|
|
3486
|
+
}
|
|
3487
|
+
if (initialPrompt?.trim()) {
|
|
3488
|
+
lines.push("", "User instruction:", initialPrompt.trim());
|
|
3489
|
+
}
|
|
3087
3490
|
lines.push(
|
|
3088
3491
|
"",
|
|
3089
3492
|
`The repository is at ${workspacePath}.`,
|
|
@@ -3093,6 +3496,90 @@ function buildLaunchPrompt(issueKey, issueTitle, workspacePath, issueDescription
|
|
|
3093
3496
|
);
|
|
3094
3497
|
return lines.join("\n");
|
|
3095
3498
|
}
|
|
3499
|
+
function buildFollowUpPrompt(userMessage, issueContext) {
|
|
3500
|
+
const contextLines = formatIssueContext(issueContext);
|
|
3501
|
+
if (contextLines.length === 0) {
|
|
3502
|
+
return userMessage;
|
|
3503
|
+
}
|
|
3504
|
+
return [
|
|
3505
|
+
"Vector context for the current issue:",
|
|
3506
|
+
...contextLines,
|
|
3507
|
+
"",
|
|
3508
|
+
"User message:",
|
|
3509
|
+
userMessage
|
|
3510
|
+
].join("\n");
|
|
3511
|
+
}
|
|
3512
|
+
function formatIssueContext(issueContext) {
|
|
3513
|
+
const lines = [];
|
|
3514
|
+
const organization = readPayloadValue(issueContext, "organization");
|
|
3515
|
+
const organizationName = readPayloadString(organization, "name");
|
|
3516
|
+
const organizationSlug = readPayloadString(organization, "slug");
|
|
3517
|
+
if (organizationName || organizationSlug) {
|
|
3518
|
+
lines.push(
|
|
3519
|
+
`- Organization: ${[organizationName, organizationSlug ? `(${organizationSlug})` : void 0].filter(Boolean).join(" ")}`
|
|
3520
|
+
);
|
|
3521
|
+
}
|
|
3522
|
+
const team = readPayloadValue(issueContext, "team");
|
|
3523
|
+
const teamName = readPayloadString(team, "name");
|
|
3524
|
+
const teamKey = readPayloadString(team, "key");
|
|
3525
|
+
if (teamName || teamKey) {
|
|
3526
|
+
lines.push(
|
|
3527
|
+
`- Team: ${[teamName, teamKey ? `(${teamKey})` : void 0].filter(Boolean).join(" ")}`
|
|
3528
|
+
);
|
|
3529
|
+
}
|
|
3530
|
+
const project = readPayloadValue(issueContext, "project");
|
|
3531
|
+
const projectName = readPayloadString(project, "name");
|
|
3532
|
+
const projectKey = readPayloadString(project, "key");
|
|
3533
|
+
const projectDescription = readPayloadString(project, "description");
|
|
3534
|
+
if (projectName || projectKey) {
|
|
3535
|
+
lines.push(
|
|
3536
|
+
`- Project: ${[projectName, projectKey ? `(${projectKey})` : void 0].filter(Boolean).join(" ")}`
|
|
3537
|
+
);
|
|
3538
|
+
}
|
|
3539
|
+
if (projectDescription) {
|
|
3540
|
+
lines.push(`- Project description: ${projectDescription}`);
|
|
3541
|
+
}
|
|
3542
|
+
const state = readPayloadValue(issueContext, "state");
|
|
3543
|
+
const stateName = readPayloadString(state, "name");
|
|
3544
|
+
const stateType = readPayloadString(state, "type");
|
|
3545
|
+
if (stateName || stateType) {
|
|
3546
|
+
lines.push(
|
|
3547
|
+
`- State: ${[stateName, stateType ? `(${stateType})` : void 0].filter(Boolean).join(" ")}`
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
const priority = readPayloadString(issueContext, "priority");
|
|
3551
|
+
if (priority) lines.push(`- Priority: ${priority}`);
|
|
3552
|
+
const reporter = readPayloadString(issueContext, "reporter");
|
|
3553
|
+
if (reporter) lines.push(`- Reporter: ${reporter}`);
|
|
3554
|
+
const assignees = readPayloadStringArray(issueContext, "assignees");
|
|
3555
|
+
if (assignees.length > 0) {
|
|
3556
|
+
lines.push(`- Assignees: ${assignees.join(", ")}`);
|
|
3557
|
+
}
|
|
3558
|
+
const labels = readPayloadStringArray(issueContext, "labels");
|
|
3559
|
+
if (labels.length > 0) {
|
|
3560
|
+
lines.push(`- Labels: ${labels.join(", ")}`);
|
|
3561
|
+
}
|
|
3562
|
+
const dates = readPayloadValue(issueContext, "dates");
|
|
3563
|
+
const startDate = readPayloadString(dates, "startDate");
|
|
3564
|
+
const dueDate = readPayloadString(dates, "dueDate");
|
|
3565
|
+
if (startDate || dueDate) {
|
|
3566
|
+
lines.push(
|
|
3567
|
+
`- Dates: ${[startDate ? `start ${startDate}` : void 0, dueDate ? `due ${dueDate}` : void 0].filter(Boolean).join(", ")}`
|
|
3568
|
+
);
|
|
3569
|
+
}
|
|
3570
|
+
const recentComments = readPayloadArray(issueContext, "recentComments");
|
|
3571
|
+
if (recentComments.length > 0) {
|
|
3572
|
+
lines.push("- Recent comments:");
|
|
3573
|
+
for (const comment of recentComments) {
|
|
3574
|
+
const author = readPayloadString(comment, "authorName") ?? "Unknown";
|
|
3575
|
+
const body = readPayloadString(comment, "body");
|
|
3576
|
+
if (body) {
|
|
3577
|
+
lines.push(` - ${author}: ${body}`);
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
return lines;
|
|
3582
|
+
}
|
|
3096
3583
|
function summarizeMessage(message) {
|
|
3097
3584
|
if (!message) {
|
|
3098
3585
|
return void 0;
|
|
@@ -3174,16 +3661,72 @@ function compareLocalSessionRecency(a, b) {
|
|
|
3174
3661
|
function sleep(ms) {
|
|
3175
3662
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3176
3663
|
}
|
|
3664
|
+
function readPayloadValue(payload, key) {
|
|
3665
|
+
return payload !== null && typeof payload === "object" ? Reflect.get(payload, key) : void 0;
|
|
3666
|
+
}
|
|
3667
|
+
function readPayloadString(payload, key) {
|
|
3668
|
+
const value = readPayloadValue(payload, key);
|
|
3669
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
3670
|
+
}
|
|
3671
|
+
function readPayloadNumber(payload, key) {
|
|
3672
|
+
const value = readPayloadValue(payload, key);
|
|
3673
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3674
|
+
}
|
|
3675
|
+
function readPayloadBoolean(payload, key) {
|
|
3676
|
+
const value = readPayloadValue(payload, key);
|
|
3677
|
+
return typeof value === "boolean" ? value : void 0;
|
|
3678
|
+
}
|
|
3679
|
+
function readPayloadPermissionMode(payload, key) {
|
|
3680
|
+
const value = readPayloadValue(payload, key);
|
|
3681
|
+
return value === "plan" || value === "ask" || value === "bypass" ? value : void 0;
|
|
3682
|
+
}
|
|
3683
|
+
function readPayloadThinkingLevel(payload, key) {
|
|
3684
|
+
const value = readPayloadValue(payload, key);
|
|
3685
|
+
return value === "off" || value === "low" || value === "medium" || value === "high" || value === "max" || value === "xhigh" ? value : void 0;
|
|
3686
|
+
}
|
|
3687
|
+
function readPayloadContextLength(payload, key) {
|
|
3688
|
+
const value = readPayloadValue(payload, key);
|
|
3689
|
+
return value === "default" || value === "extended" ? value : void 0;
|
|
3690
|
+
}
|
|
3691
|
+
function readPayloadArray(payload, key) {
|
|
3692
|
+
const value = readPayloadValue(payload, key);
|
|
3693
|
+
return Array.isArray(value) ? value : [];
|
|
3694
|
+
}
|
|
3695
|
+
function readPayloadStringArray(payload, key) {
|
|
3696
|
+
return readPayloadArray(payload, key).filter(
|
|
3697
|
+
(value) => typeof value === "string" && value.trim() !== ""
|
|
3698
|
+
);
|
|
3699
|
+
}
|
|
3700
|
+
function readPayloadId(payload, key) {
|
|
3701
|
+
const value = readPayloadString(payload, key);
|
|
3702
|
+
return value;
|
|
3703
|
+
}
|
|
3704
|
+
function readPayloadAgentProvider(payload, key) {
|
|
3705
|
+
const value = readPayloadValue(payload, key);
|
|
3706
|
+
return value === "codex" || value === "claude_code" || value === "cursor" || value === "copilot" || value === "opencode" || value === "pi" || value === "vector_cli" ? value : void 0;
|
|
3707
|
+
}
|
|
3177
3708
|
function isBridgeProvider(provider) {
|
|
3178
|
-
return provider === "codex" || provider === "claude_code";
|
|
3709
|
+
return provider === "codex" || provider === "claude_code" || provider === "cursor" || provider === "copilot" || provider === "opencode" || provider === "pi";
|
|
3179
3710
|
}
|
|
3180
|
-
function
|
|
3711
|
+
function providerLabel2(provider) {
|
|
3181
3712
|
if (provider === "codex") {
|
|
3182
3713
|
return "Codex";
|
|
3183
3714
|
}
|
|
3184
3715
|
if (provider === "claude_code") {
|
|
3185
3716
|
return "Claude";
|
|
3186
3717
|
}
|
|
3718
|
+
if (provider === "cursor") {
|
|
3719
|
+
return "Cursor";
|
|
3720
|
+
}
|
|
3721
|
+
if (provider === "copilot") {
|
|
3722
|
+
return "GitHub Copilot";
|
|
3723
|
+
}
|
|
3724
|
+
if (provider === "opencode") {
|
|
3725
|
+
return "OpenCode";
|
|
3726
|
+
}
|
|
3727
|
+
if (provider === "pi") {
|
|
3728
|
+
return "Pi";
|
|
3729
|
+
}
|
|
3187
3730
|
return "Vector CLI";
|
|
3188
3731
|
}
|
|
3189
3732
|
function installLaunchAgent(vcliPath) {
|
|
@@ -3401,13 +3944,33 @@ function killExistingMenuBar() {
|
|
|
3401
3944
|
}
|
|
3402
3945
|
}
|
|
3403
3946
|
}
|
|
3947
|
+
function getRunningMenuBarPid() {
|
|
3948
|
+
if (!existsSync3(MENUBAR_PID_FILE)) {
|
|
3949
|
+
return null;
|
|
3950
|
+
}
|
|
3951
|
+
try {
|
|
3952
|
+
const pid = Number(readFileSync2(MENUBAR_PID_FILE, "utf-8").trim());
|
|
3953
|
+
if (Number.isFinite(pid) && pid > 0 && isKnownMenuBarProcess(pid)) {
|
|
3954
|
+
process.kill(pid, 0);
|
|
3955
|
+
return pid;
|
|
3956
|
+
}
|
|
3957
|
+
} catch {
|
|
3958
|
+
}
|
|
3959
|
+
try {
|
|
3960
|
+
unlinkSync(MENUBAR_PID_FILE);
|
|
3961
|
+
} catch {
|
|
3962
|
+
}
|
|
3963
|
+
return null;
|
|
3964
|
+
}
|
|
3404
3965
|
async function launchMenuBar() {
|
|
3405
3966
|
if (platform() !== "darwin") return;
|
|
3406
3967
|
removeLegacyMenuBarLaunchAgent();
|
|
3407
3968
|
const executable = findMenuBarExecutable();
|
|
3408
3969
|
const cliInvocation = getCurrentCliInvocation();
|
|
3409
3970
|
if (!executable || !cliInvocation) return;
|
|
3410
|
-
|
|
3971
|
+
if (getRunningMenuBarPid()) {
|
|
3972
|
+
return;
|
|
3973
|
+
}
|
|
3411
3974
|
try {
|
|
3412
3975
|
const { spawn: spawnChild } = await import("child_process");
|
|
3413
3976
|
const child = spawnChild(executable, [], {
|
|
@@ -5725,7 +6288,7 @@ serviceCommand.command("stop").description("Stop the bridge service").action(()
|
|
|
5725
6288
|
console.log("Bridge is not running.");
|
|
5726
6289
|
}
|
|
5727
6290
|
});
|
|
5728
|
-
serviceCommand.command("status").description("Show bridge service status").action((
|
|
6291
|
+
serviceCommand.command("status").description("Show bridge service status").action(() => {
|
|
5729
6292
|
const status = getBridgeStatus();
|
|
5730
6293
|
if (!status.configured) {
|
|
5731
6294
|
console.log("Bridge not configured. Run: vcli service start");
|
|
@@ -6022,7 +6585,7 @@ program.command("update").description("Update the CLI to the latest version").ac
|
|
|
6022
6585
|
timeout: 12e4
|
|
6023
6586
|
});
|
|
6024
6587
|
s.stop("CLI updated successfully.");
|
|
6025
|
-
} catch
|
|
6588
|
+
} catch {
|
|
6026
6589
|
s.stop("Update failed.");
|
|
6027
6590
|
log.error(`Run manually: ${install.command.join(" ")}`);
|
|
6028
6591
|
return;
|