@agentdeck/bridge 1.0.5 → 1.0.6
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/assets/fm-helper/agentdeck-fm-helper +0 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +84 -10
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/device-voice-reply.d.ts +1 -10
- package/dist/device-voice-reply.d.ts.map +1 -1
- package/dist/device-voice-reply.js +4 -33
- package/dist/device-voice-reply.js.map +1 -1
- package/dist/foundation-models-helper.d.ts.map +1 -1
- package/dist/foundation-models-helper.js +59 -22
- package/dist/foundation-models-helper.js.map +1 -1
- package/dist/openclaw-session.d.ts +6 -0
- package/dist/openclaw-session.d.ts.map +1 -1
- package/dist/openclaw-session.js +7 -1
- package/dist/openclaw-session.js.map +1 -1
- package/fm-helper/Info.plist +27 -0
- package/package.json +1 -1
- package/scripts/build-fm-helper.mjs +35 -3
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon-server.d.ts","sourceRoot":"","sources":["../src/daemon-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,UAAU,EAA8B,MAAM,kBAAkB,CAAC;AAmF1E,OAAO,EAA8D,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA6P/G;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC5C,YAAY,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,OAAO,CAST;AAkBD,iBAAS,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,SAAS,GAAG,IAAI,CA+C1E;AAYD,iBAAS,yBAAyB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAStD;AAED,iBAAS,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAsBlE;AA6ED,gBAAgB;AAChB,wBAAgB,uBAAuB,CAAC,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKzH;AACD,gBAAgB;AAChB,wBAAgB,wBAAwB,IAAI,IAAI,CAS/C;AACD,gBAAgB;AAChB,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC;AAEF,iBAAe,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA8F3H;AAoHD,iEAAiE;AACjE,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAsBtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EACnH,KAAK,EAAE,CAAC,GACP,CAAC,CAWH;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,aAAa,GAAG,WAAW,GAAG,UAAU,GAAG,aAAa,CAAA;CAAE,CAa3F;AAID,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiHD,wBAAsB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"daemon-server.d.ts","sourceRoot":"","sources":["../src/daemon-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,UAAU,EAA8B,MAAM,kBAAkB,CAAC;AAmF1E,OAAO,EAA8D,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA6P/G;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC5C,YAAY,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,OAAO,CAST;AAkBD,iBAAS,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,SAAS,GAAG,IAAI,CA+C1E;AAYD,iBAAS,yBAAyB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAStD;AAED,iBAAS,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAsBlE;AA6ED,gBAAgB;AAChB,wBAAgB,uBAAuB,CAAC,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKzH;AACD,gBAAgB;AAChB,wBAAgB,wBAAwB,IAAI,IAAI,CAS/C;AACD,gBAAgB;AAChB,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC;AAEF,iBAAe,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA8F3H;AAoHD,iEAAiE;AACjE,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAsBtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EACnH,KAAK,EAAE,CAAC,GACP,CAAC,CAWH;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,aAAa,GAAG,WAAW,GAAG,UAAU,GAAG,aAAa,CAAA;CAAE,CAa3F;AAID,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAiHD,wBAAsB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuwHpE"}
|
package/dist/daemon-server.js
CHANGED
|
@@ -64,7 +64,7 @@ import { FallbackTaskTimeline } from './fallback-task-timeline.js';
|
|
|
64
64
|
import { handleApmeRequest } from './apme/http.js';
|
|
65
65
|
import { readModelFromTranscript } from './apme/claude-transcript-reader.js';
|
|
66
66
|
import { transcriptTimelineForSession, lastAssistantTextFromTranscript, lastAssistantTextForSession, } from './session-transcript-timeline.js';
|
|
67
|
-
import { DeviceVoiceReplyRouter, speakableReply, pcmFromWav, } from './device-voice-reply.js';
|
|
67
|
+
import { DeviceVoiceReplyRouter, speakableReply, spokenDigest, pcmFromWav, } from './device-voice-reply.js';
|
|
68
68
|
import { rawSessionId } from '@agentdeck/shared';
|
|
69
69
|
import { lastAgentMessageFromCodexRollout } from './codex-rollout-response.js';
|
|
70
70
|
import { callFoundationModelsHelper } from './foundation-models-helper.js';
|
|
@@ -75,7 +75,7 @@ import { getConnectedAdbDevices, hasAdb, getAdbDeviceCount } from './adb-reverse
|
|
|
75
75
|
import { getPixooDeviceDetails, pixooDeviceCount } from './pixoo/pixoo-bridge.js';
|
|
76
76
|
import { loadTimeboxDevices } from './timebox/timebox-settings.js';
|
|
77
77
|
import { getLanIp, stripUnsafeText, cleanRawText, prepareMarkdownDetail, normalizeCommandPrompt, formatDurationSec } from '@agentdeck/shared';
|
|
78
|
-
import { injectOpenClawSession } from './openclaw-session.js';
|
|
78
|
+
import { injectOpenClawSession, OPENCLAW_SESSION_ID } from './openclaw-session.js';
|
|
79
79
|
import { buildCardFeed, buildGlance, applyOutboxDecisions, FeedPullTracker, formatFeedPull, normalizeClientIp, parsePullTelemetry, } from './card-feed.js';
|
|
80
80
|
import { threadModule } from './card-modules.js';
|
|
81
81
|
import { AutonomousPocketEngine, createAutonomousPocketModules, parsePocketAutonomyConfig, } from './pocket-autonomy.js';
|
|
@@ -983,6 +983,22 @@ export async function startDaemon(opts) {
|
|
|
983
983
|
// `gatewaySessionState` / `gatewayModelName` dedicated fields.
|
|
984
984
|
let gatewaySessionState = 'idle';
|
|
985
985
|
let gatewayModelName;
|
|
986
|
+
/**
|
|
987
|
+
* Snapshot for an `openclaw` state event: the global machine with the
|
|
988
|
+
* Gateway-local model pinned back on.
|
|
989
|
+
*
|
|
990
|
+
* The Gateway's `model_info` no longer writes `core.stateMachine` (see the
|
|
991
|
+
* parser branch): that machine is fed by every observed Claude/Codex/OpenCode
|
|
992
|
+
* hook, and the hub stamps its broadcasts with the user's focused session —
|
|
993
|
+
* so a model written there by a *different* agent is read as the focused
|
|
994
|
+
* session's own. That is how `GLM-5.2 (1M)` appeared as the model of a Claude
|
|
995
|
+
* session on both decks. Keeping the model out of the shared slot means the
|
|
996
|
+
* Gateway's own events have to carry it explicitly, which is what this does.
|
|
997
|
+
*/
|
|
998
|
+
const gatewaySnapshot = (base) => ({
|
|
999
|
+
...(base ?? core.stateMachine.getSnapshot()),
|
|
1000
|
+
modelName: gatewayModelName ?? null,
|
|
1001
|
+
});
|
|
986
1002
|
// Wi-Fi WebSocket e-ink panels (XTeink X3/X4 CrossPoint fork) self-register
|
|
987
1003
|
// their device roster via `client_register{clientType:"eink-device"}` — the
|
|
988
1004
|
// same volunteer model as the Stream Deck plugin. This handler lived ONLY in
|
|
@@ -2475,6 +2491,24 @@ export async function startDaemon(opts) {
|
|
|
2475
2491
|
core.wireDisplayMonitor();
|
|
2476
2492
|
let lastStateEvent = null;
|
|
2477
2493
|
let userFocusedSessionId = null;
|
|
2494
|
+
/**
|
|
2495
|
+
* Stamp the focused session onto a hub `state_update`.
|
|
2496
|
+
*
|
|
2497
|
+
* This field carries two jobs, and both are load-bearing, which is why it
|
|
2498
|
+
* cannot simply be narrowed:
|
|
2499
|
+
* - attribution: `buildStateEvent` sets no `sessionId` at all, so a
|
|
2500
|
+
* hook-observed session's AWAITING_PERMISSION options reach the decks
|
|
2501
|
+
* attributed only by this field (see session-deck-awaiting tests).
|
|
2502
|
+
* - focus ack: the Apple app toggles creature focus against it and needs it
|
|
2503
|
+
* even for a session that emits nothing of its own.
|
|
2504
|
+
*
|
|
2505
|
+
* The consequence is a standing invariant on the payload: whatever rides along
|
|
2506
|
+
* here is read as the focused session's own. So nothing may write a *different*
|
|
2507
|
+
* agent's per-session field into `core.stateMachine` — the Gateway's model went
|
|
2508
|
+
* in and came out as a Claude session's model. Gateway-specific state lives in
|
|
2509
|
+
* `gatewaySessionState` / `gatewayModelName` and is re-attached by
|
|
2510
|
+
* `gatewaySnapshot()`.
|
|
2511
|
+
*/
|
|
2478
2512
|
const attachFocusedSessionId = (event) => {
|
|
2479
2513
|
if (event.type !== 'state_update')
|
|
2480
2514
|
return event;
|
|
@@ -2483,6 +2517,28 @@ export async function startDaemon(opts) {
|
|
|
2483
2517
|
focusedSessionId: userFocusedSessionId ?? '',
|
|
2484
2518
|
};
|
|
2485
2519
|
};
|
|
2520
|
+
/**
|
|
2521
|
+
* Stamp a *Gateway-specific* state event — one whose payload really is the
|
|
2522
|
+
* Gateway's (its parser events, its connection transitions), as opposed to the
|
|
2523
|
+
* hub broadcasts above that merely get labelled `openclaw` while the Gateway is
|
|
2524
|
+
* alive.
|
|
2525
|
+
*
|
|
2526
|
+
* These name their own row (`sessionId`), which is the honest attribution and
|
|
2527
|
+
* the reason a client never has to guess: an event carrying the Gateway's model
|
|
2528
|
+
* now says so. The focus ack rides only when the Gateway IS the focused row —
|
|
2529
|
+
* otherwise this event would claim to describe a Claude session, which is
|
|
2530
|
+
* precisely how `GLM-5.2 (1M)` became that session's model on both decks. The
|
|
2531
|
+
* ack still reaches the Apple app through every hub broadcast.
|
|
2532
|
+
*/
|
|
2533
|
+
const attachGatewayEvent = (event) => {
|
|
2534
|
+
if (event.type !== 'state_update')
|
|
2535
|
+
return event;
|
|
2536
|
+
return {
|
|
2537
|
+
...event,
|
|
2538
|
+
sessionId: OPENCLAW_SESSION_ID,
|
|
2539
|
+
focusedSessionId: userFocusedSessionId === OPENCLAW_SESSION_ID ? OPENCLAW_SESSION_ID : '',
|
|
2540
|
+
};
|
|
2541
|
+
};
|
|
2486
2542
|
const broadcastFocusedState = () => {
|
|
2487
2543
|
const gwAlive = gatewayAdapter?.isAlive() ?? false;
|
|
2488
2544
|
const stateEvent = attachFocusedSessionId(core.buildStateEvent({
|
|
@@ -2932,7 +2988,14 @@ export async function startDaemon(opts) {
|
|
|
2932
2988
|
core.stateMachine.handleHookEvent('SessionEnd', {});
|
|
2933
2989
|
break;
|
|
2934
2990
|
case 'parser':
|
|
2935
|
-
|
|
2991
|
+
// `model_info` is deliberately NOT forwarded: the global machine holds
|
|
2992
|
+
// one modelName for the whole hub, fed by every observed hook session,
|
|
2993
|
+
// and its broadcasts are stamped with the user's focused session — so a
|
|
2994
|
+
// model written here by the Gateway is read as that session's own
|
|
2995
|
+
// (GLM on a Claude row). It lives in `gatewayModelName` instead, and
|
|
2996
|
+
// `gatewaySnapshot()` puts it back on the Gateway's own events.
|
|
2997
|
+
if (evt.event !== 'model_info')
|
|
2998
|
+
core.stateMachine.handleParserEvent(evt.event, evt.data);
|
|
2936
2999
|
// Gateway-local activity state for the virtual session row (mirror of
|
|
2937
3000
|
// Swift `gatewaySessionState`). Kept separate from the global
|
|
2938
3001
|
// `core.stateMachine` above so the OpenClaw row reflects only the
|
|
@@ -2961,10 +3024,10 @@ export async function startDaemon(opts) {
|
|
|
2961
3024
|
if (models) {
|
|
2962
3025
|
core.cachedModelCatalog = models;
|
|
2963
3026
|
const snap = core.stateMachine.getSnapshot();
|
|
2964
|
-
const stateEvent =
|
|
3027
|
+
const stateEvent = attachGatewayEvent(core.buildStateEvent({
|
|
2965
3028
|
agentType: 'openclaw',
|
|
2966
3029
|
agentCapabilities: OPENCLAW_CAPABILITIES,
|
|
2967
|
-
snapshot: snap,
|
|
3030
|
+
snapshot: gatewaySnapshot(snap),
|
|
2968
3031
|
}));
|
|
2969
3032
|
lastStateEvent = stateEvent;
|
|
2970
3033
|
core.broadcast(stateEvent);
|
|
@@ -3017,10 +3080,10 @@ export async function startDaemon(opts) {
|
|
|
3017
3080
|
}
|
|
3018
3081
|
// Force full state broadcast
|
|
3019
3082
|
const snap = core.stateMachine.getSnapshot();
|
|
3020
|
-
const gwStateEvent =
|
|
3083
|
+
const gwStateEvent = attachGatewayEvent(core.buildStateEvent({
|
|
3021
3084
|
agentType: 'openclaw',
|
|
3022
3085
|
agentCapabilities: OPENCLAW_CAPABILITIES,
|
|
3023
|
-
snapshot: snap,
|
|
3086
|
+
snapshot: gatewaySnapshot(snap),
|
|
3024
3087
|
}));
|
|
3025
3088
|
lastStateEvent = gwStateEvent;
|
|
3026
3089
|
core.wsServer.broadcast(gwStateEvent);
|
|
@@ -3434,10 +3497,10 @@ export async function startDaemon(opts) {
|
|
|
3434
3497
|
if (target === 'openclaw' && gatewayAdapter?.isAlive()) {
|
|
3435
3498
|
// Force broadcast OpenClaw state to all clients
|
|
3436
3499
|
const snap = core.stateMachine.getSnapshot();
|
|
3437
|
-
const gwStateEvent =
|
|
3500
|
+
const gwStateEvent = attachGatewayEvent(core.buildStateEvent({
|
|
3438
3501
|
agentType: 'openclaw',
|
|
3439
3502
|
agentCapabilities: OPENCLAW_CAPABILITIES,
|
|
3440
|
-
snapshot: snap,
|
|
3503
|
+
snapshot: gatewaySnapshot(snap),
|
|
3441
3504
|
}));
|
|
3442
3505
|
lastStateEvent = gwStateEvent;
|
|
3443
3506
|
core.wsServer.broadcast(gwStateEvent);
|
|
@@ -3799,7 +3862,18 @@ export async function startDaemon(opts) {
|
|
|
3799
3862
|
const voiceCfg = loadDaemonSettings().voice;
|
|
3800
3863
|
if (voiceCfg?.speakReplies === false)
|
|
3801
3864
|
return; // opt-out, default on
|
|
3802
|
-
|
|
3865
|
+
// Speech gets the lead, not the transcript: an explicit summary line if the
|
|
3866
|
+
// answer has one, else its first sentence. The full answer is already on the
|
|
3867
|
+
// screen the user is sitting at, where it can be skimmed — read aloud it is
|
|
3868
|
+
// a minute of monologue nobody can skip. `voice.speakFullReply` opts back in.
|
|
3869
|
+
const full = voiceCfg?.speakFullReply === true;
|
|
3870
|
+
const spoken = spokenDigest(text, { full });
|
|
3871
|
+
if (!full) {
|
|
3872
|
+
const readable = speakableReply(text, Number.MAX_SAFE_INTEGER);
|
|
3873
|
+
if (spoken && readable.length > spoken.length) {
|
|
3874
|
+
log(`[agentdeck] voice: reply digested ${readable.length} -> ${spoken.length} chars`);
|
|
3875
|
+
}
|
|
3876
|
+
}
|
|
3803
3877
|
if (!spoken) {
|
|
3804
3878
|
// A code-only answer has nothing worth reading aloud; say that instead of
|
|
3805
3879
|
// spelling out punctuation, so the user still knows the turn finished.
|