@agentdeck/bridge 1.0.22 → 1.0.24
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/apme/activity-history.d.ts +59 -0
- package/dist/apme/activity-history.d.ts.map +1 -0
- package/dist/apme/activity-history.js +265 -0
- package/dist/apme/activity-history.js.map +1 -0
- package/dist/apme/dashboard-html.d.ts.map +1 -1
- package/dist/apme/dashboard-html.js +40 -6
- package/dist/apme/dashboard-html.js.map +1 -1
- package/dist/apme/http.d.ts +1 -0
- package/dist/apme/http.d.ts.map +1 -1
- package/dist/apme/http.js +9 -0
- package/dist/apme/http.js.map +1 -1
- package/dist/apme/runner.d.ts +20 -0
- package/dist/apme/runner.d.ts.map +1 -1
- package/dist/apme/runner.js +57 -0
- package/dist/apme/runner.js.map +1 -1
- package/dist/apme/settings.d.ts +21 -4
- package/dist/apme/settings.d.ts.map +1 -1
- package/dist/apme/settings.js +29 -5
- package/dist/apme/settings.js.map +1 -1
- package/dist/apme/store.d.ts +7 -0
- package/dist/apme/store.d.ts.map +1 -1
- package/dist/apme/store.js +35 -0
- package/dist/apme/store.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +248 -13
- package/dist/cli.js.map +1 -1
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +100 -4
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon-takeover.d.ts +3 -0
- package/dist/daemon-takeover.d.ts.map +1 -1
- package/dist/daemon-takeover.js +5 -0
- package/dist/daemon-takeover.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/esp32-flash-lease.d.ts +47 -0
- package/dist/esp32-flash-lease.d.ts.map +1 -0
- package/dist/esp32-flash-lease.js +84 -0
- package/dist/esp32-flash-lease.js.map +1 -0
- package/dist/esp32-flash-transport.d.ts +90 -0
- package/dist/esp32-flash-transport.d.ts.map +1 -0
- package/dist/esp32-flash-transport.js +157 -0
- package/dist/esp32-flash-transport.js.map +1 -0
- package/dist/esp32-flash.d.ts +171 -0
- package/dist/esp32-flash.d.ts.map +1 -0
- package/dist/esp32-flash.js +539 -0
- package/dist/esp32-flash.js.map +1 -0
- package/dist/esp32-serial.d.ts +9 -1
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +74 -1
- package/dist/esp32-serial.js.map +1 -1
- package/dist/esptool-js-node.d.ts +17 -0
- package/dist/esptool-js-node.d.ts.map +1 -0
- package/dist/esptool-js-node.js +17 -0
- package/dist/esptool-js-node.js.map +1 -0
- package/dist/review-runner.d.ts.map +1 -1
- package/dist/review-runner.js +27 -9
- package/dist/review-runner.js.map +1 -1
- package/dist/timeline-summarizer.d.ts +7 -2
- package/dist/timeline-summarizer.d.ts.map +1 -1
- package/dist/timeline-summarizer.js +13 -69
- package/dist/timeline-summarizer.js.map +1 -1
- package/package.json +6 -4
package/dist/daemon-server.js
CHANGED
|
@@ -102,7 +102,8 @@ import { codexTurnOutcomeFromRollout, lastAgentMessageFromCodexRollout } from '.
|
|
|
102
102
|
import { callFoundationModelsHelper } from './foundation-models-helper.js';
|
|
103
103
|
import { initModules, stopModules, createDefaultModules, } from './modules/index.js';
|
|
104
104
|
import { bindHostFor, daemonModuleConfigs, describeDaemonPosture, resolveDaemonPosture, } from './network-posture.js';
|
|
105
|
-
import { esp32ConnectionCount, getESP32DeviceInfo, onESP32Message, sendAuthProvisionToAll, sendWifiProvision, sendWifiProvisionToAll, handleESP32Wake, getESP32Ports, getSerialConnectionStatus, getSerialLastError, getSerialReachableBoards } from './esp32-serial.js';
|
|
105
|
+
import { esp32ConnectionCount, getESP32DeviceInfo, onESP32Message, sendAuthProvisionToAll, sendWifiProvision, sendWifiProvisionToAll, handleESP32Wake, getESP32Ports, getSerialConnectionStatus, getSerialLastError, getSerialReachableBoards, releaseESP32SerialPorts } from './esp32-serial.js';
|
|
106
|
+
import { clampLeaseSeconds, clearLease, readLease, writeLease } from './esp32-flash-lease.js';
|
|
106
107
|
import { loadWifiConfig } from './wifi-config.js';
|
|
107
108
|
import { getConnectedAdbDevices, hasAdb, getAdbDeviceCount } from './adb-reverse.js';
|
|
108
109
|
import { getPixooDeviceDetails, pixooDeviceCount } from './pixoo/pixoo-bridge.js';
|
|
@@ -1134,6 +1135,10 @@ export async function startDaemon(opts) {
|
|
|
1134
1135
|
/** Produces live timeline rows for observed Kiro sessions — see the class
|
|
1135
1136
|
* doc for why Kiro needs a producer when hook agents do not. */
|
|
1136
1137
|
const kiroTimelineFeed = new KiroTimelineFeed();
|
|
1138
|
+
/** Kiro has no CLI hooks, so transcript rows also feed APME. These maps are
|
|
1139
|
+
* bounded by the observer's current live set and discarded on disappearance. */
|
|
1140
|
+
const kiroApmeSessions = new Set();
|
|
1141
|
+
const kiroApmeResponseBySession = new Map();
|
|
1137
1142
|
/** Observed Claude sessions whose AskUserQuestion PreToolUse is held open for
|
|
1138
1143
|
* a device answer, keyed by the bare Claude session UUID. Its presence is
|
|
1139
1144
|
* what makes the session's options pressable (`liveAnswerable`) and what
|
|
@@ -1647,6 +1652,62 @@ export async function startDaemon(opts) {
|
|
|
1647
1652
|
}
|
|
1648
1653
|
return;
|
|
1649
1654
|
}
|
|
1655
|
+
// ===== Serial suspend / resume (USB flashing) =====
|
|
1656
|
+
// Both sit BEHIND the normal auth gate — `isAuthorizedHttpRequest()` treats
|
|
1657
|
+
// same-machine as authenticated, which is exactly the audience here, so
|
|
1658
|
+
// this adds no standing unauthenticated route. The one always-on pre-auth
|
|
1659
|
+
// route is still `GET /health`.
|
|
1660
|
+
//
|
|
1661
|
+
// `agentdeck esp32 flash` calls suspend, flashes, and calls resume in a
|
|
1662
|
+
// `finally`. Neither call is load-bearing on its own: expiry is enforced
|
|
1663
|
+
// when the lease is READ, so a CLI that is killed mid-flash recovers with
|
|
1664
|
+
// nothing running.
|
|
1665
|
+
if (req.method === 'POST' && pathname === '/esp32/serial/suspend') {
|
|
1666
|
+
(async () => {
|
|
1667
|
+
const body = await readJsonBody(req);
|
|
1668
|
+
const seconds = clampLeaseSeconds(body.seconds ?? 120);
|
|
1669
|
+
const lease = writeLease({
|
|
1670
|
+
until: Date.now() + seconds * 1000,
|
|
1671
|
+
reason: typeof body.reason === 'string' ? body.reason : 'usb flash',
|
|
1672
|
+
pid: typeof body.pid === 'number' ? body.pid : undefined,
|
|
1673
|
+
board: typeof body.board === 'string' ? body.board : undefined,
|
|
1674
|
+
});
|
|
1675
|
+
// Refusing to OPEN is only half of it — a port this daemon already
|
|
1676
|
+
// holds still blocks the flasher, and two readers on one TTY steal
|
|
1677
|
+
// each other's bytes instead of failing cleanly.
|
|
1678
|
+
const released = releaseESP32SerialPorts(`flash lease (${lease.board ?? 'usb flash'})`);
|
|
1679
|
+
return { ok: true, until: lease.until, seconds, released };
|
|
1680
|
+
})().then((result) => {
|
|
1681
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1682
|
+
res.end(JSON.stringify(result));
|
|
1683
|
+
}).catch((err) => {
|
|
1684
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1685
|
+
res.end(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }));
|
|
1686
|
+
});
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
if (req.method === 'POST' && pathname === '/esp32/serial/resume') {
|
|
1690
|
+
// Idempotent by contract: resuming when nothing is suspended is a
|
|
1691
|
+
// success. The CLI calls this from a `finally`, where it may well run
|
|
1692
|
+
// after the lease has already expired on its own.
|
|
1693
|
+
const was = readLease();
|
|
1694
|
+
clearLease();
|
|
1695
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1696
|
+
res.end(JSON.stringify({ ok: true, wasSuspended: was !== null }));
|
|
1697
|
+
return;
|
|
1698
|
+
}
|
|
1699
|
+
if (req.method === 'GET' && pathname === '/esp32/serial/status') {
|
|
1700
|
+
const lease = readLease();
|
|
1701
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1702
|
+
res.end(JSON.stringify({
|
|
1703
|
+
ok: true,
|
|
1704
|
+
suspended: lease !== null,
|
|
1705
|
+
until: lease?.until,
|
|
1706
|
+
board: lease?.board,
|
|
1707
|
+
ports: getESP32Ports(),
|
|
1708
|
+
}));
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1650
1711
|
if (req.method === 'POST' && pathname === '/esp32/ota') {
|
|
1651
1712
|
(async () => {
|
|
1652
1713
|
const body = await readJsonBody(req);
|
|
@@ -3512,11 +3573,46 @@ export async function startDaemon(opts) {
|
|
|
3512
3573
|
// beside it stays empty. #218 taught the per-session QUERY to read Kiro's
|
|
3513
3574
|
// own transcript; the main timeline is a STREAM, and this is what feeds it.
|
|
3514
3575
|
try {
|
|
3515
|
-
const
|
|
3516
|
-
.filter((s) => typeof s.agentType === 'string' && s.agentType.startsWith('kiro'))
|
|
3517
|
-
|
|
3576
|
+
const observedKiro = passiveSessionObserver.collect([])
|
|
3577
|
+
.filter((s) => typeof s.agentType === 'string' && s.agentType.startsWith('kiro'));
|
|
3578
|
+
const kiroIds = observedKiro.map((s) => s.id);
|
|
3579
|
+
const projectBySession = new Map(observedKiro.map((s) => [rawSessionId(s.id), s.projectName]));
|
|
3580
|
+
const currentSessions = new Set(kiroIds.map(rawSessionId));
|
|
3581
|
+
for (const sessionId of kiroApmeSessions) {
|
|
3582
|
+
if (currentSessions.has(sessionId))
|
|
3583
|
+
continue;
|
|
3584
|
+
apme?.collector.closeRun(sessionId);
|
|
3585
|
+
kiroApmeSessions.delete(sessionId);
|
|
3586
|
+
kiroApmeResponseBySession.delete(sessionId);
|
|
3587
|
+
}
|
|
3518
3588
|
for (const entry of kiroTimelineFeed.pump(kiroIds)) {
|
|
3519
3589
|
core.bridgeTimeline.addEntry(entry);
|
|
3590
|
+
if (!apme || !entry.sessionId)
|
|
3591
|
+
continue;
|
|
3592
|
+
const sessionId = rawSessionId(entry.sessionId);
|
|
3593
|
+
if (entry.type === 'chat_start') {
|
|
3594
|
+
if (!apme.collector.getRunId(sessionId)) {
|
|
3595
|
+
apme.collector.openRun({
|
|
3596
|
+
sessionId,
|
|
3597
|
+
agentType: 'kiro-cli',
|
|
3598
|
+
projectName: projectBySession.get(sessionId) ?? undefined,
|
|
3599
|
+
});
|
|
3600
|
+
}
|
|
3601
|
+
kiroApmeSessions.add(sessionId);
|
|
3602
|
+
kiroApmeResponseBySession.delete(sessionId);
|
|
3603
|
+
apme.collector.ingestHook(sessionId, 'user_prompt_submit', {
|
|
3604
|
+
prompt: entry.detail || entry.raw,
|
|
3605
|
+
agent_type: 'kiro-cli',
|
|
3606
|
+
project_name: projectBySession.get(sessionId),
|
|
3607
|
+
});
|
|
3608
|
+
}
|
|
3609
|
+
else if (entry.type === 'chat_response' && apme.collector.getRunId(sessionId)) {
|
|
3610
|
+
const piece = entry.detail || entry.raw;
|
|
3611
|
+
const response = [kiroApmeResponseBySession.get(sessionId), piece].filter(Boolean).join('\n');
|
|
3612
|
+
kiroApmeResponseBySession.set(sessionId, response);
|
|
3613
|
+
apme.collector.setTurnResponse(sessionId, response);
|
|
3614
|
+
apme.collector.noteTurnStop(sessionId);
|
|
3615
|
+
}
|
|
3520
3616
|
}
|
|
3521
3617
|
}
|
|
3522
3618
|
catch (err) {
|