@zeph-to/cli 1.15.3 → 1.17.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/dist/listener.d.ts +11 -0
- package/dist/listener.d.ts.map +1 -1
- package/dist/listener.js +71 -8
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/zeph-hook.d.ts.map +1 -1
- package/dist/zeph-hook.js +31 -0
- package/package.json +1 -1
package/dist/listener.d.ts
CHANGED
|
@@ -45,6 +45,13 @@ export declare const AUTH_FAILURE_CODES: ReadonlySet<number>;
|
|
|
45
45
|
export declare const checkRateLimit: (session: string, now?: number) => boolean;
|
|
46
46
|
/** Read the foreground command in the named tmux session's active pane. */
|
|
47
47
|
export declare const paneCurrentCommand: (session: string) => string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Translate a phone-supplied key list to tmux tokens. Returns null if ANY
|
|
50
|
+
* key is unknown — a partial injection (some keys land, one is dropped)
|
|
51
|
+
* leaves the pane in a worse mid-state than none, so the whole batch is
|
|
52
|
+
* rejected.
|
|
53
|
+
*/
|
|
54
|
+
export declare const resolveKeys: (keys: string[]) => string[] | null;
|
|
48
55
|
/**
|
|
49
56
|
* Mark the cached socket as no longer trustworthy — call this when a
|
|
50
57
|
* tmux command fails against the cached path. The next findTmuxSocket()
|
|
@@ -186,12 +193,16 @@ interface PushItem {
|
|
|
186
193
|
isEncrypted?: boolean;
|
|
187
194
|
/** Set when type='agent.command' — tmux session name to inject into. */
|
|
188
195
|
agentSessionName?: string;
|
|
196
|
+
/** Named keys (Esc/arrows/Enter) to inject instead of body text —
|
|
197
|
+
* drives full-screen modals the phone can't escape with text. */
|
|
198
|
+
keys?: string[];
|
|
189
199
|
/** Optional image/file attachments (agent.command only, plaintext). */
|
|
190
200
|
files?: PushFileAttachment[];
|
|
191
201
|
}
|
|
192
202
|
interface HandlePushDeps {
|
|
193
203
|
paneCommand?: (session: string) => string | null;
|
|
194
204
|
inject?: (session: string, text: string) => boolean;
|
|
205
|
+
sendKeys?: (session: string, tokens: string[]) => boolean;
|
|
195
206
|
rateLimit?: (session: string) => boolean;
|
|
196
207
|
now?: () => number;
|
|
197
208
|
/** Injectable for tests; defaults to the REST-backed downloader. */
|
package/dist/listener.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACzG,OAAO,EAAiD,KAAK,UAAU,EAA4C,MAAM,kBAAkB,CAAC;AA4B5I,UAAU,YAAY;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAYD,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAA+B,CAAC;AAenF,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,MAAK,MAAmB,KAAG,OAgB1E,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,IAO7D,CAAC;
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../src/listener.ts"],"names":[],"mappings":"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"}
|
package/dist/listener.js
CHANGED
|
@@ -25,7 +25,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
25
25
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
26
26
|
};
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.handleListener = exports.computeListenerDeviceId = exports.computeBackoff = exports.handlePush = exports.gcAttachments = exports.setAttachmentContext = exports.collectSessions = exports.collectSessionsVerbose = exports.handleScreenRequest = exports.collectWatchHits = exports.resetPatternWatches = exports.setPatternWatches = exports.deriveSessionState = exports.resetSessionStates = exports.detectRemoteAgent = exports.parseSessionName = exports.invalidateTmuxSocketCache = exports.paneCurrentCommand = exports.checkRateLimit = exports.AUTH_FAILURE_CODES = void 0;
|
|
28
|
+
exports.handleListener = exports.computeListenerDeviceId = exports.computeBackoff = exports.handlePush = exports.gcAttachments = exports.setAttachmentContext = exports.collectSessions = exports.collectSessionsVerbose = exports.handleScreenRequest = exports.collectWatchHits = exports.resetPatternWatches = exports.setPatternWatches = exports.deriveSessionState = exports.resetSessionStates = exports.detectRemoteAgent = exports.parseSessionName = exports.invalidateTmuxSocketCache = exports.resolveKeys = exports.paneCurrentCommand = exports.checkRateLimit = exports.AUTH_FAILURE_CODES = void 0;
|
|
29
29
|
const child_process_1 = require("child_process");
|
|
30
30
|
const crypto_1 = require("crypto");
|
|
31
31
|
const fs_1 = require("fs");
|
|
@@ -120,6 +120,45 @@ const injectKeys = (session, text) => {
|
|
|
120
120
|
const b = (0, child_process_1.spawnSync)('tmux', tmuxArgs(['send-keys', '-t', session, 'Enter']), { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
121
121
|
return b.status === 0;
|
|
122
122
|
};
|
|
123
|
+
// Named keys the phone may inject to drive a full-screen Claude Code pane
|
|
124
|
+
// (a `/usage` modal captures text input — only a real Escape/arrow gets out).
|
|
125
|
+
// Maps a lowercase wire name to the exact tmux key token. Whitelist-ONLY:
|
|
126
|
+
// anything outside this map is refused so a compromised sender can't smuggle
|
|
127
|
+
// `C-c`, `M-x`, or a shell command through send-keys' key-name syntax.
|
|
128
|
+
const ALLOWED_KEYS = {
|
|
129
|
+
escape: 'Escape',
|
|
130
|
+
up: 'Up',
|
|
131
|
+
down: 'Down',
|
|
132
|
+
left: 'Left',
|
|
133
|
+
right: 'Right',
|
|
134
|
+
enter: 'Enter',
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Translate a phone-supplied key list to tmux tokens. Returns null if ANY
|
|
138
|
+
* key is unknown — a partial injection (some keys land, one is dropped)
|
|
139
|
+
* leaves the pane in a worse mid-state than none, so the whole batch is
|
|
140
|
+
* rejected.
|
|
141
|
+
*/
|
|
142
|
+
const resolveKeys = (keys) => {
|
|
143
|
+
const out = [];
|
|
144
|
+
for (const k of keys) {
|
|
145
|
+
const token = ALLOWED_KEYS[k.toLowerCase().trim()];
|
|
146
|
+
if (!token)
|
|
147
|
+
return null;
|
|
148
|
+
out.push(token);
|
|
149
|
+
}
|
|
150
|
+
return out.length ? out : null;
|
|
151
|
+
};
|
|
152
|
+
exports.resolveKeys = resolveKeys;
|
|
153
|
+
/**
|
|
154
|
+
* Send named keys as keys (NOT `-l`), so tmux interprets Escape/Up/Enter as
|
|
155
|
+
* key presses rather than literal text. One send-keys call carries the
|
|
156
|
+
* whole sequence in order.
|
|
157
|
+
*/
|
|
158
|
+
const injectNamedKeys = (session, tokens) => {
|
|
159
|
+
const r = (0, child_process_1.spawnSync)('tmux', tmuxArgs(['send-keys', '-t', session, ...tokens]), { stdio: ['ignore', 'ignore', 'pipe'] });
|
|
160
|
+
return r.status === 0;
|
|
161
|
+
};
|
|
123
162
|
const stamp = () => new Date().toISOString().slice(11, 19);
|
|
124
163
|
const log = (msg) => console.log(`[${stamp()}] ${msg}`);
|
|
125
164
|
// ─── tmux socket discovery ──────────────────────────────────────────
|
|
@@ -717,11 +756,7 @@ exports.collectSessions = collectSessions;
|
|
|
717
756
|
* the structured `agent.command` push type and the legacy `@<session>`
|
|
718
757
|
* prefix path route through here so the defense layers can't diverge.
|
|
719
758
|
*/
|
|
720
|
-
const
|
|
721
|
-
if (!text) {
|
|
722
|
-
log(`! ${session}: empty text — drop`);
|
|
723
|
-
return false;
|
|
724
|
-
}
|
|
759
|
+
const passesInjectGuards = (session, deps) => {
|
|
725
760
|
const cmd = (deps.paneCommand ?? exports.paneCurrentCommand)(session);
|
|
726
761
|
if (cmd === null) {
|
|
727
762
|
log(`! ${session}: no such tmux session — drop`);
|
|
@@ -731,16 +766,33 @@ const tryInject = (session, text, deps) => {
|
|
|
731
766
|
log(`! ${session}: pane is at shell (${cmd}) — refusing (would be RCE)`);
|
|
732
767
|
return false;
|
|
733
768
|
}
|
|
734
|
-
|
|
735
|
-
if (!allowed) {
|
|
769
|
+
if (!(deps.rateLimit ?? exports.checkRateLimit)(session)) {
|
|
736
770
|
log(`! ${session}: rate-limited — drop`);
|
|
737
771
|
return false;
|
|
738
772
|
}
|
|
773
|
+
return true;
|
|
774
|
+
};
|
|
775
|
+
const tryInject = (session, text, deps) => {
|
|
776
|
+
if (!text) {
|
|
777
|
+
log(`! ${session}: empty text — drop`);
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
if (!passesInjectGuards(session, deps))
|
|
781
|
+
return false;
|
|
739
782
|
const ok = (deps.inject ?? injectKeys)(session, text);
|
|
740
783
|
const preview = text.length > 60 ? text.slice(0, 60) + '…' : text;
|
|
741
784
|
log(`${ok ? '→' : '✗'} ${session}: ${preview}`);
|
|
742
785
|
return ok;
|
|
743
786
|
};
|
|
787
|
+
/** Key-event sibling of tryInject: same pane/shell/rate guards, but sends
|
|
788
|
+
* named keys instead of literal text + Enter. */
|
|
789
|
+
const tryInjectKeys = (session, tokens, deps) => {
|
|
790
|
+
if (!passesInjectGuards(session, deps))
|
|
791
|
+
return false;
|
|
792
|
+
const ok = (deps.sendKeys ?? injectNamedKeys)(session, tokens);
|
|
793
|
+
log(`${ok ? '⌨' : '✗'} ${session}: [${tokens.join(' ')}]`);
|
|
794
|
+
return ok;
|
|
795
|
+
};
|
|
744
796
|
// ─── Attachment download (agent.command files[]) ────────────────────
|
|
745
797
|
const ATTACHMENTS_DIR = (0, path_1.join)((0, os_1.homedir)(), '.zeph', 'attachments');
|
|
746
798
|
const DEFAULT_API_BASE = 'https://api.zeph.to/v1';
|
|
@@ -876,6 +928,17 @@ const handlePush = async (push, deps = {}) => {
|
|
|
876
928
|
}
|
|
877
929
|
if (push.type !== 'agent.command' || !push.agentSessionName)
|
|
878
930
|
return false;
|
|
931
|
+
// Key event (Esc / arrows / Enter) — no body, no attachments. Lets the
|
|
932
|
+
// phone escape a full-screen modal (e.g. after `/usage`) that swallows
|
|
933
|
+
// text input.
|
|
934
|
+
if (push.keys?.length) {
|
|
935
|
+
const tokens = (0, exports.resolveKeys)(push.keys);
|
|
936
|
+
if (!tokens) {
|
|
937
|
+
log(`! ${push.agentSessionName}: unknown key(s) [${push.keys.join(' ')}] — drop`);
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
return tryInjectKeys(push.agentSessionName, tokens, deps);
|
|
941
|
+
}
|
|
879
942
|
// Download any attachments BEFORE injecting so the agent can read the
|
|
880
943
|
// local paths immediately. A download-phase failure is isolated: the
|
|
881
944
|
// body text still injects so the command itself isn't blocked.
|
package/dist/types.d.ts
CHANGED
|
@@ -11,6 +11,11 @@ export interface NotifyPayload {
|
|
|
11
11
|
priority?: 'low' | 'normal' | 'high' | 'urgent';
|
|
12
12
|
targetDeviceId?: string;
|
|
13
13
|
sessionId?: string;
|
|
14
|
+
/** Stable agent-session grouping so a hook/notify joins the agent chat:
|
|
15
|
+
* the listener device (per-host) + tmux session name. Auto-filled by
|
|
16
|
+
* ZephHook.notify when running inside a tmux agent session. */
|
|
17
|
+
agentDeviceId?: string;
|
|
18
|
+
agentSessionName?: string;
|
|
14
19
|
}
|
|
15
20
|
export interface NotifyResult {
|
|
16
21
|
pushId: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACzC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACzC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;oEAEgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;CACxD;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH"}
|
package/dist/zeph-hook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zeph-hook.d.ts","sourceRoot":"","sources":["../src/zeph-hook.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"zeph-hook.d.ts","sourceRoot":"","sources":["../src/zeph-hook.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAY,gBAAgB,EAAE,gBAAgB,EAAoB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAkCxL,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,OAAO,EAAE,WAAW;YASlB,YAAY;IAYpB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;YAmC7C,cAAc;IAsDtB,aAAa,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAK7G,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrF,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAmB9C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAKlD,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;YAK/B,OAAO;IAiCrB,OAAO,CAAC,UAAU;CASnB"}
|
package/dist/zeph-hook.js
CHANGED
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ZephHook = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const node_os_1 = require("node:os");
|
|
6
|
+
const node_child_process_1 = require("node:child_process");
|
|
4
7
|
const errors_js_1 = require("./errors.js");
|
|
5
8
|
const crypto_js_1 = require("./crypto.js");
|
|
6
9
|
const DEFAULT_BASE_URL = 'https://api.zeph.to/v1';
|
|
7
10
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
8
11
|
const BODY_FILE_THRESHOLD = 512;
|
|
9
12
|
const PREVIEW_LENGTH = 200;
|
|
13
|
+
/**
|
|
14
|
+
* Stable agent-session grouping when running inside a tmux agent session, so a
|
|
15
|
+
* hook/notify (e.g. the Stop-hook recap) files under the same session key as
|
|
16
|
+
* the listener's pushes — surviving Claude session-UUID rotation. The device id
|
|
17
|
+
* MUST match cli `computeListenerDeviceId` (`dev_listener_<sha8(hostname)>`).
|
|
18
|
+
*/
|
|
19
|
+
const agentSessionContext = () => {
|
|
20
|
+
if (!process.env.TMUX)
|
|
21
|
+
return null;
|
|
22
|
+
let name;
|
|
23
|
+
try {
|
|
24
|
+
name = (0, node_child_process_1.execFileSync)('tmux', ['display-message', '-p', '#S'], { encoding: 'utf-8' }).trim();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (!name)
|
|
30
|
+
return null;
|
|
31
|
+
const h = (0, node_crypto_1.createHash)('sha256').update((0, node_os_1.hostname)()).digest('hex').slice(0, 8);
|
|
32
|
+
return { agentDeviceId: `dev_listener_${h}`, agentSessionName: name };
|
|
33
|
+
};
|
|
10
34
|
const inferMimeType = (fileName) => {
|
|
11
35
|
const ext = fileName.split('.').pop()?.toLowerCase();
|
|
12
36
|
const map = { md: 'text/markdown', txt: 'text/plain', json: 'application/json' };
|
|
@@ -39,6 +63,13 @@ class ZephHook {
|
|
|
39
63
|
}
|
|
40
64
|
}
|
|
41
65
|
async notify(payload) {
|
|
66
|
+
// Attach the stable session key when in a tmux agent session so the push
|
|
67
|
+
// joins the agent chat. Merged into `payload` here so both the inline and
|
|
68
|
+
// file-upload (notifyWithFile) paths — which each spread `...payload` —
|
|
69
|
+
// carry it. Explicit caller values win.
|
|
70
|
+
const agentCtx = agentSessionContext();
|
|
71
|
+
if (agentCtx)
|
|
72
|
+
payload = { ...agentCtx, ...payload };
|
|
42
73
|
const canEncrypt = await this.ensureCrypto();
|
|
43
74
|
const body = payload.body;
|
|
44
75
|
const bodyBytes = body ? new TextEncoder().encode(body).byteLength : 0;
|