@noopolis/daimon 0.2.3 → 0.2.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/runtime/grokEngineBrokerTurn.d.ts +2 -0
- package/dist/runtime/grokEngineBrokerTurn.d.ts.map +1 -1
- package/dist/runtime/grokEngineBrokerTurn.js +5 -2
- package/dist/runtime/grokEngineBrokerTurnEnd.d.ts +8 -2
- package/dist/runtime/grokEngineBrokerTurnEnd.d.ts.map +1 -1
- package/dist/runtime/grokEngineBrokerTurnEnd.js +13 -2
- package/dist/runtime/grokWorkerToolProcess.d.ts +34 -0
- package/dist/runtime/grokWorkerToolProcess.d.ts.map +1 -0
- package/dist/runtime/grokWorkerToolProcess.js +78 -0
- package/dist/runtime/productionAgentTools.js +1 -1
- package/package.json +1 -1
|
@@ -58,6 +58,8 @@ export type GrokEngineBrokerTurnDependencies = Readonly<{
|
|
|
58
58
|
runNative(input: NativeBrokerTurn, signal: AbortSignal): Promise<Readonly<NativeBrokerTurnResult>>;
|
|
59
59
|
/** The worker the launcher started for this identity (`/proc` by default); only read when the broker ends a turn itself. */
|
|
60
60
|
observeWorker?(workerUid: number): Promise<GrokWorkerProcess | undefined>;
|
|
61
|
+
/** Whether the worker identity has a live local tool process (default: `grokWorkerToolProcessLive` over `/proc`). */
|
|
62
|
+
observeToolProcess?(workerUid: number): Promise<boolean>;
|
|
61
63
|
/** Overrides the turn-end grace and idle bounds (tests). */
|
|
62
64
|
turnEnd?: GrokBrokerTurnEndTiming;
|
|
63
65
|
/** Whether no live process holds the worker identity (`/proc` by default); polled, bounded, before an aborted turn is sealed. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokEngineBrokerTurn.d.ts","sourceRoot":"","sources":["../../src/runtime/grokEngineBrokerTurn.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,EAEL,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,KAAK,sBAAsB,EACzE,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,KAAK,kCAAkC,EAAE,MAAM,8BAA8B,CAAC;AAMhH,OAAO,EAEL,KAAK,8BAA8B,EAAE,KAAK,uBAAuB,EAClE,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAqD,KAAK,0BAA0B,EAAE,KAAK,8BAA8B,EAA8B,MAAM,iCAAiC,CAAC;AACtM,OAAO,EAA2B,KAAK,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACzJ,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAAmE,KAAK,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AAGvJ,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,OAAO,EAAgK,KAAK,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAClQ,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"grokEngineBrokerTurn.d.ts","sourceRoot":"","sources":["../../src/runtime/grokEngineBrokerTurn.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@ import { finishBrokerTurnWithUsage } from "./grokEngineBrokerMetering.js";
|
|
|
14
14
|
import { GrokBrokerTurnMeter } from "./grokBrokerTurnMeter.js";
|
|
15
15
|
import { awaitGrokWorkerIdentityEmpty, findGrokWorkerProcess, GROK_WORKER_REAP_WAIT_MS, grokWorkerIdentityEmpty, watchGrokBrokerTurnEnd } from "./grokEngineBrokerTurnEnd.js";
|
|
16
16
|
import { GrokWorkerAttestationFailure } from "./grokWorkerAttestation.js";
|
|
17
|
+
import { grokWorkerToolProcessLive, grokWorkerToolProcessSampler } from "./grokWorkerToolProcess.js";
|
|
17
18
|
export class EngineBrokerTurnFailure extends Error {
|
|
18
19
|
code;
|
|
19
20
|
diagnostic;
|
|
@@ -119,12 +120,14 @@ export async function runGrokEngineBrokerTurn(deps, registration, wakeId, prompt
|
|
|
119
120
|
deps.proxy.registerTurn(turnId, { policy: registration.model, meter, clock });
|
|
120
121
|
const capabilityTtlMs = engineBrokerCapabilityTtlMs(limits.timeoutMs);
|
|
121
122
|
const providerCapability = deps.proxy.capabilities.issue(agentId, turnId, capabilityTtlMs), mcpCapability = deps.mcp.register(agentId, turnId, mcpEndpoint, capabilityTtlMs);
|
|
123
|
+
// A shell command Grok runs itself is work the proxy and facade never see.
|
|
124
|
+
const toolProcess = grokWorkerToolProcessSampler(() => (deps.observeToolProcess ?? grokWorkerToolProcessLive)(registration.workerUid));
|
|
122
125
|
watchdog = watchGrokBrokerTurnEnd({
|
|
123
|
-
meter, activity: () => deps.mcp.activity?.(turnId), signal: controller.signal, ...(deps.turnEnd === undefined ? {} : { timing: deps.turnEnd }),
|
|
126
|
+
meter, activity: () => deps.mcp.activity?.(turnId), toolProcess: toolProcess.live, signal: controller.signal, ...(deps.turnEnd === undefined ? {} : { timing: deps.turnEnd }),
|
|
124
127
|
// The worker is read once, as soon as it has made a request — long before
|
|
125
128
|
// anything can end the turn and reap it — so a final reply is never left
|
|
126
129
|
// without the worker that gave it.
|
|
127
|
-
onPoll: () => { if (worker === undefined && meter.snapshot().requests > 0)
|
|
130
|
+
onPoll: () => { toolProcess.poll(); if (worker === undefined && meter.snapshot().requests > 0)
|
|
128
131
|
worker = (deps.observeWorker ?? findGrokWorkerProcess)(registration.workerUid).catch(() => undefined); },
|
|
129
132
|
onFinalReply: () => { worker ??= (deps.observeWorker ?? findGrokWorkerProcess)(registration.workerUid).catch(() => undefined); },
|
|
130
133
|
// An idle stall is a deadline of its own: it trips the meter as a timeout, so it seals like one.
|
|
@@ -30,8 +30,12 @@ import type { GrokBrokerTurnMeter } from "./grokBrokerTurnMeter.js";
|
|
|
30
30
|
* so a model that keeps going is never cut off. Independently, a turn with no
|
|
31
31
|
* model request and no tool call in flight and no activity of either kind for
|
|
32
32
|
* `idleMs` ends as `onEnd("idle")` — the backstop for a worker that stalls
|
|
33
|
-
* without ever answering. Shell tools Grok runs itself
|
|
34
|
-
* the
|
|
33
|
+
* without ever answering. Shell tools Grok runs itself never reach the proxy
|
|
34
|
+
* or the facade, and Grok lets the model give one a timeout of up to ten
|
|
35
|
+
* hours, so a worker with a live tool process (`toolProcess`,
|
|
36
|
+
* `grokWorkerToolProcess.ts`) is working too: it is never idle while one runs,
|
|
37
|
+
* and the quiet clock restarts from the last poll that saw one. The idle bound
|
|
38
|
+
* stays minutes, not seconds, because that observation is a poll.
|
|
35
39
|
*/
|
|
36
40
|
export type GrokBrokerTurnEndTiming = Readonly<{
|
|
37
41
|
finalGraceMs: number;
|
|
@@ -45,6 +49,8 @@ export type GrokBrokerTurnEndReason = "final_reply" | "idle";
|
|
|
45
49
|
export declare function watchGrokBrokerTurnEnd(input: Readonly<{
|
|
46
50
|
meter: Pick<GrokBrokerTurnMeter, "finalReply" | "busy" | "lastActivityAt">;
|
|
47
51
|
activity: () => EngineBrokerMcpActivity | undefined;
|
|
52
|
+
/** Whether the worker has a local tool process alive, as last observed; absent means never observed. */
|
|
53
|
+
toolProcess?: () => boolean;
|
|
48
54
|
onFinalReply: () => void;
|
|
49
55
|
/** Every poll, before any decision: the broker records the worker while it is certainly alive. */
|
|
50
56
|
onPoll?: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grokEngineBrokerTurnEnd.d.ts","sourceRoot":"","sources":["../../src/runtime/grokEngineBrokerTurnEnd.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE
|
|
1
|
+
{"version":3,"file":"grokEngineBrokerTurnEnd.d.ts","sourceRoot":"","sources":["../../src/runtime/grokEngineBrokerTurnEnd.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AACzG,eAAO,MAAM,oBAAoB,EAAE,uBAAqG,CAAC;AACzI,qGAAqG;AACrG,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAC/C,MAAM,MAAM,uBAAuB,GAAG,aAAa,GAAG,MAAM,CAAC;AAE7D,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC;IACrD,KAAK,EAAE,IAAI,CAAC,mBAAmB,EAAE,YAAY,GAAG,MAAM,GAAG,gBAAgB,CAAC,CAAC;IAC3E,QAAQ,EAAE,MAAM,uBAAuB,GAAG,SAAS,CAAC;IACpD,wGAAwG;IACxG,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;IAC5B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,kGAAkG;IAClG,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,6FAA6F;IAC7F,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC,GAAG,QAAQ,CAAC;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,CAAC,CA8B9B;AAED,oJAAoJ;AACpJ,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9E;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAqBnH;AAED,2DAA2D;AAC3D,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAU,EAAE,eAAe,UAAQ,GACvD,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;;;;;;GAOG;AACH,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAA2B,EAAE,MAAM,SAAM,EAAE,QAAQ,SAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAarM"}
|
|
@@ -5,7 +5,7 @@ export const GROK_BROKER_TURN_END = Object.freeze({ finalGraceMs: 15_000, idleMs
|
|
|
5
5
|
export const GROK_WORKER_REAP_WAIT_MS = 10_000;
|
|
6
6
|
export function watchGrokBrokerTurnEnd(input) {
|
|
7
7
|
const timing = input.timing ?? GROK_BROKER_TURN_END, now = input.now ?? Date.now;
|
|
8
|
-
let notified, done = false;
|
|
8
|
+
let notified, done = false, toolSeenAt = 0;
|
|
9
9
|
const check = () => {
|
|
10
10
|
if (done)
|
|
11
11
|
return;
|
|
@@ -32,11 +32,22 @@ export function watchGrokBrokerTurnEnd(input) {
|
|
|
32
32
|
catch {
|
|
33
33
|
activity = undefined;
|
|
34
34
|
}
|
|
35
|
+
let tool = false;
|
|
36
|
+
try {
|
|
37
|
+
tool = input.toolProcess?.() === true;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
tool = false;
|
|
41
|
+
}
|
|
42
|
+
if (tool)
|
|
43
|
+
toolSeenAt = now();
|
|
35
44
|
if (input.meter.busy() || (activity?.inFlight ?? 0) > 0)
|
|
36
45
|
return;
|
|
37
46
|
const quietSince = Math.max(input.meter.lastActivityAt(), activity?.lastActivityAt ?? 0);
|
|
47
|
+
// A tool process defers only the idle verdict. A final reply called no tool, so a child still
|
|
48
|
+
// alive beside it is not the model's work and must not hold a finished worker open.
|
|
38
49
|
const reason = final !== undefined && now() - Math.max(final.at, quietSince) >= timing.finalGraceMs ? "final_reply"
|
|
39
|
-
: now() - quietSince >= timing.idleMs ? "idle" : undefined;
|
|
50
|
+
: now() - Math.max(quietSince, toolSeenAt) >= timing.idleMs ? "idle" : undefined;
|
|
40
51
|
if (reason === undefined)
|
|
41
52
|
return;
|
|
42
53
|
stop();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a Grok worker is running one of its own local tools right now,
|
|
3
|
+
* read-only from `/proc`.
|
|
4
|
+
*
|
|
5
|
+
* The broker sees every model request (the proxy) and every MCP tool call (the
|
|
6
|
+
* facade), but not the tools Grok runs in-process: `run_terminal_command`
|
|
7
|
+
* executes as a child of the worker. Grok 1.0.34 advertises that tool with a
|
|
8
|
+
* model-chosen timeout of up to 36 000 000 ms (default 120 000 ms), so a
|
|
9
|
+
* command the model gave a long timeout is real work the broker cannot see,
|
|
10
|
+
* and the idle watchdog (`grokEngineBrokerTurnEnd.ts`) used to end such a turn
|
|
11
|
+
* as stalled ten minutes in.
|
|
12
|
+
*
|
|
13
|
+
* Every engine process carries the argv the launcher compiled — the outer
|
|
14
|
+
* bubblewrap wrapper Grok re-executes into and the Grok process inside it —
|
|
15
|
+
* so `--output-format streaming-messages-json` marks them. A live (non-zombie)
|
|
16
|
+
* process owned by `uid` whose parent is such an engine process, and which is
|
|
17
|
+
* not one itself, is a tool the worker started and is waiting on. Short-lived
|
|
18
|
+
* helpers count too, which only delays an idle verdict by a poll.
|
|
19
|
+
*
|
|
20
|
+
* An unreadable `/proc` (or one mounted `hidepid`) answers `false`: the
|
|
21
|
+
* watchdog then behaves exactly as it did without this signal.
|
|
22
|
+
*/
|
|
23
|
+
export declare function grokWorkerToolProcessLive(uid: number, procRoot?: string): Promise<boolean>;
|
|
24
|
+
/**
|
|
25
|
+
* The watchdog's poll is synchronous and `/proc` is not, so the turn keeps the
|
|
26
|
+
* last answer: `poll()` starts one read when none is pending, `live()` returns
|
|
27
|
+
* the latest completed one. A failed read answers `false`, as an unreadable
|
|
28
|
+
* `/proc` does.
|
|
29
|
+
*/
|
|
30
|
+
export declare function grokWorkerToolProcessSampler(read: () => Promise<boolean>): Readonly<{
|
|
31
|
+
poll(): void;
|
|
32
|
+
live(): boolean;
|
|
33
|
+
}>;
|
|
34
|
+
//# sourceMappingURL=grokWorkerToolProcess.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grokWorkerToolProcess.d.ts","sourceRoot":"","sources":["../../src/runtime/grokWorkerToolProcess.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBjG;AAQD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC;IAAE,IAAI,IAAI,IAAI,CAAC;IAAC,IAAI,IAAI,OAAO,CAAA;CAAE,CAAC,CAUtH"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a Grok worker is running one of its own local tools right now,
|
|
4
|
+
* read-only from `/proc`.
|
|
5
|
+
*
|
|
6
|
+
* The broker sees every model request (the proxy) and every MCP tool call (the
|
|
7
|
+
* facade), but not the tools Grok runs in-process: `run_terminal_command`
|
|
8
|
+
* executes as a child of the worker. Grok 1.0.34 advertises that tool with a
|
|
9
|
+
* model-chosen timeout of up to 36 000 000 ms (default 120 000 ms), so a
|
|
10
|
+
* command the model gave a long timeout is real work the broker cannot see,
|
|
11
|
+
* and the idle watchdog (`grokEngineBrokerTurnEnd.ts`) used to end such a turn
|
|
12
|
+
* as stalled ten minutes in.
|
|
13
|
+
*
|
|
14
|
+
* Every engine process carries the argv the launcher compiled — the outer
|
|
15
|
+
* bubblewrap wrapper Grok re-executes into and the Grok process inside it —
|
|
16
|
+
* so `--output-format streaming-messages-json` marks them. A live (non-zombie)
|
|
17
|
+
* process owned by `uid` whose parent is such an engine process, and which is
|
|
18
|
+
* not one itself, is a tool the worker started and is waiting on. Short-lived
|
|
19
|
+
* helpers count too, which only delays an idle verdict by a poll.
|
|
20
|
+
*
|
|
21
|
+
* An unreadable `/proc` (or one mounted `hidepid`) answers `false`: the
|
|
22
|
+
* watchdog then behaves exactly as it did without this signal.
|
|
23
|
+
*/
|
|
24
|
+
export async function grokWorkerToolProcessLive(uid, procRoot = "/proc") {
|
|
25
|
+
let entries;
|
|
26
|
+
try {
|
|
27
|
+
entries = await readdir(procRoot);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const owned = new Map();
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
if (!/^\d+$/u.test(entry))
|
|
35
|
+
continue;
|
|
36
|
+
try {
|
|
37
|
+
const status = await readFile(`${procRoot}/${entry}/status`, "utf8");
|
|
38
|
+
if (Number(/^Uid:\s+(\d+)/mu.exec(status)?.[1]) !== uid)
|
|
39
|
+
continue;
|
|
40
|
+
if (/^State:\s+[ZX]/mu.test(status))
|
|
41
|
+
continue;
|
|
42
|
+
const parent = Number(/^PPid:\s+(\d+)/mu.exec(status)?.[1]);
|
|
43
|
+
if (!Number.isSafeInteger(parent))
|
|
44
|
+
continue;
|
|
45
|
+
const argv = (await readFile(`${procRoot}/${entry}/cmdline`, "utf8")).split("\0");
|
|
46
|
+
owned.set(Number(entry), { parent, engine: isGrokEngineArgv(argv) });
|
|
47
|
+
}
|
|
48
|
+
catch { /* a process exiting mid-scan is not part of the answer */ }
|
|
49
|
+
}
|
|
50
|
+
for (const process of owned.values()) {
|
|
51
|
+
if (!process.engine && owned.get(process.parent)?.engine === true)
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
/** The compiled worker argv pair every engine process of a brokered turn carries (`grokBrokerWorkerConfig.ts`). */
|
|
57
|
+
function isGrokEngineArgv(argv) {
|
|
58
|
+
const flag = argv.indexOf("--output-format");
|
|
59
|
+
return flag !== -1 && argv[flag + 1] === "streaming-messages-json";
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The watchdog's poll is synchronous and `/proc` is not, so the turn keeps the
|
|
63
|
+
* last answer: `poll()` starts one read when none is pending, `live()` returns
|
|
64
|
+
* the latest completed one. A failed read answers `false`, as an unreadable
|
|
65
|
+
* `/proc` does.
|
|
66
|
+
*/
|
|
67
|
+
export function grokWorkerToolProcessSampler(read) {
|
|
68
|
+
let live = false, pending = false;
|
|
69
|
+
return {
|
|
70
|
+
poll: () => {
|
|
71
|
+
if (pending)
|
|
72
|
+
return;
|
|
73
|
+
pending = true;
|
|
74
|
+
void Promise.resolve().then(read).then((value) => { live = value; }, () => { live = false; }).finally(() => { pending = false; });
|
|
75
|
+
},
|
|
76
|
+
live: () => live
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -226,7 +226,7 @@ function moltnetTool(agent, wakeContext) {
|
|
|
226
226
|
}
|
|
227
227
|
async function connect(agent, server) {
|
|
228
228
|
taskClockChildEnvironment(server.env);
|
|
229
|
-
const client = new Client({ name: "daimon-production", version: "0.2.
|
|
229
|
+
const client = new Client({ name: "daimon-production", version: "0.2.4" });
|
|
230
230
|
const headers = server.authSecretEnv === undefined ? {} : { authorization: `Bearer ${requiredSecret(server.authSecretEnv)}` };
|
|
231
231
|
const transport = server.transport === "stdio"
|
|
232
232
|
? new StdioClientTransport({ command: server.command, args: [...server.args], env: stringEnvironment(readyTaskClockEnvironment({ ...server.env, ...cliChildEnvironment([], agent.runtimeHomePath, { executablePath: server.command }) })) })
|