@ycodium-ai/agent-fake 0.2.3074 → 0.2.3078
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/README.md +8 -2
- package/dist/index.js +174 -44
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -82,12 +82,18 @@ then that text. A whole-string placeholder preserves types; interpolation JSON-s
|
|
|
82
82
|
non-strings. Unresolved references skip that call and reply
|
|
83
83
|
`mcp-send <tool> failed: unresolved placeholder <placeholder>`, then continue.
|
|
84
84
|
|
|
85
|
+
Calls, `wait` and `waitFor` accept an optional `server` alongside `tool` (for example,
|
|
86
|
+
`{ "server": "ycodium-home", "tool": "work_list_items" }`); it selects the named HTTP server
|
|
87
|
+
from `startSession.mcpServers`, defaults to the built-in server, and gives tool events the
|
|
88
|
+
`mcp__<server>__<tool>` prefix (`mcp__ycodium__<tool>` by default). Clients are reused within
|
|
89
|
+
the session and closed when it ends; events and replies use server names and redact server URLs.
|
|
90
|
+
|
|
85
91
|
A `wait` polls `tools/list` on that MCP server every 250 ms for the tool name or its
|
|
86
|
-
`
|
|
92
|
+
`mcp__<server>__` prefix, defaulting to a 30000 ms timeout. It replies
|
|
87
93
|
`mcp-send wait <tool>: ready` or `mcp-send wait <tool> failed: timeout`, then continues, with no
|
|
88
94
|
tool items. A `waitFor`, such as
|
|
89
95
|
`{ "waitFor": { "tool": "message_inbox_peek", "path": "items", "atLeast": 2 } }`, calls that tool
|
|
90
|
-
with
|
|
96
|
+
with its optional `arguments` (none by default; placeholders are not resolved there) every 250 ms on one session until the value at the dot `path` of its result is
|
|
91
97
|
an array at least `atLeast` long, or a number at least `atLeast`; a tool error counts as not yet.
|
|
92
98
|
Point it only at read-only tools, since every poll is a real call. It also defaults to 30000 ms,
|
|
93
99
|
replies `mcp-send waitFor <tool> <path> >= <atLeast>: ready` or `… failed: timeout`, emits no tool
|
package/dist/index.js
CHANGED
|
@@ -469,8 +469,8 @@ async function callMcpTool(input) {
|
|
|
469
469
|
return session.request("tools/call", { name: input.name, arguments: input.arguments });
|
|
470
470
|
}
|
|
471
471
|
async function openMcpSession(input) {
|
|
472
|
-
const post = async (headers, body) => {
|
|
473
|
-
|
|
472
|
+
const post = async (headers, body, signal = input.signal) => {
|
|
473
|
+
signal?.throwIfAborted();
|
|
474
474
|
const response = await input.fetch(input.server.transport.url, {
|
|
475
475
|
method: "POST",
|
|
476
476
|
headers: {
|
|
@@ -479,14 +479,18 @@ async function openMcpSession(input) {
|
|
|
479
479
|
...headers
|
|
480
480
|
},
|
|
481
481
|
body: JSON.stringify({ jsonrpc: "2.0", ...body }),
|
|
482
|
-
...
|
|
482
|
+
...signal === void 0 ? {} : { signal }
|
|
483
483
|
});
|
|
484
484
|
const text = await response.text();
|
|
485
485
|
if (!response.ok)
|
|
486
486
|
throw new Error(
|
|
487
|
-
`MCP ${String(body.method)} failed: HTTP ${response.status} ${text.slice(0, 200)}`
|
|
487
|
+
`MCP ${String(body.method)} failed: HTTP ${response.status} ${text.replaceAll(input.server.transport.url, input.server.name).slice(0, 200)}`
|
|
488
488
|
);
|
|
489
|
-
|
|
489
|
+
try {
|
|
490
|
+
return { response, message: parseMessage(text) };
|
|
491
|
+
} catch {
|
|
492
|
+
throw new Error(`MCP ${String(body.method)} failed: invalid response`);
|
|
493
|
+
}
|
|
490
494
|
};
|
|
491
495
|
const base = { ...input.server.transport.headers };
|
|
492
496
|
const initialized = await post(base, {
|
|
@@ -504,16 +508,36 @@ async function openMcpSession(input) {
|
|
|
504
508
|
"mcp-protocol-version": PROTOCOL_VERSION,
|
|
505
509
|
...sessionId === null ? {} : { "mcp-session-id": sessionId }
|
|
506
510
|
};
|
|
507
|
-
|
|
511
|
+
let closed = false;
|
|
512
|
+
const close = async () => {
|
|
513
|
+
if (closed) return;
|
|
514
|
+
closed = true;
|
|
515
|
+
if (sessionId === null) return;
|
|
516
|
+
const response = await input.fetch(input.server.transport.url, {
|
|
517
|
+
method: "DELETE",
|
|
518
|
+
headers: session,
|
|
519
|
+
signal: AbortSignal.timeout(1e3)
|
|
520
|
+
});
|
|
521
|
+
await response.body?.cancel();
|
|
522
|
+
};
|
|
523
|
+
try {
|
|
524
|
+
await post(session, { method: "notifications/initialized" });
|
|
525
|
+
} catch (error) {
|
|
526
|
+
await close().catch(() => {
|
|
527
|
+
});
|
|
528
|
+
throw error;
|
|
529
|
+
}
|
|
508
530
|
let nextId = 2;
|
|
509
531
|
return {
|
|
510
|
-
request: async (method, params) => {
|
|
511
|
-
|
|
532
|
+
request: async (method, params, signal) => {
|
|
533
|
+
if (closed) throw new Error("MCP session closed");
|
|
534
|
+
const called = await post(session, { id: nextId++, method, params }, signal);
|
|
512
535
|
const label = method === "tools/call" ? `tools/call ${String(params.name)}` : method;
|
|
513
536
|
if (called.message?.error !== void 0)
|
|
514
537
|
throw new Error(`MCP ${label} failed: ${called.message.error.message ?? "error"}`);
|
|
515
538
|
return called.message?.result;
|
|
516
|
-
}
|
|
539
|
+
},
|
|
540
|
+
close
|
|
517
541
|
};
|
|
518
542
|
}
|
|
519
543
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -571,6 +595,66 @@ function hold(ms, signal) {
|
|
|
571
595
|
});
|
|
572
596
|
}
|
|
573
597
|
|
|
598
|
+
// src/playbookMcp.ts
|
|
599
|
+
function redactMcpUrls(value, servers) {
|
|
600
|
+
if (typeof value === "string") {
|
|
601
|
+
let text = value;
|
|
602
|
+
for (const server of servers ?? []) {
|
|
603
|
+
if (server.transport.type !== "stdio")
|
|
604
|
+
text = text.replaceAll(server.transport.url, server.name);
|
|
605
|
+
}
|
|
606
|
+
return text;
|
|
607
|
+
}
|
|
608
|
+
if (Array.isArray(value)) return value.map((entry) => redactMcpUrls(entry, servers));
|
|
609
|
+
if (typeof value === "object" && value !== null)
|
|
610
|
+
return Object.fromEntries(
|
|
611
|
+
Object.entries(value).map(([key, entry]) => [
|
|
612
|
+
redactMcpUrls(key, servers),
|
|
613
|
+
redactMcpUrls(entry, servers)
|
|
614
|
+
])
|
|
615
|
+
);
|
|
616
|
+
return value;
|
|
617
|
+
}
|
|
618
|
+
function createPlaybookMcp(input) {
|
|
619
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
620
|
+
const lifetime = new AbortController();
|
|
621
|
+
const serverFor = (name) => name === void 0 ? builtinMcpServer(input.servers) : input.servers?.find((server) => server.name === name) ?? null;
|
|
622
|
+
return {
|
|
623
|
+
missing: (name) => serverFor(name) === null ? name === void 0 ? "Error: no MCP server was handed to this session" : `no MCP server ${name}` : void 0,
|
|
624
|
+
request: async (name, method, params, signal) => {
|
|
625
|
+
const server = serverFor(name);
|
|
626
|
+
if (server === null) throw new Error("MCP server missing");
|
|
627
|
+
if (server.transport.type !== "http")
|
|
628
|
+
throw new Error(`unsupported MCP transport ${server.transport.type} for ${server.name}`);
|
|
629
|
+
const requestSignal = AbortSignal.any([lifetime.signal, signal]);
|
|
630
|
+
requestSignal.throwIfAborted();
|
|
631
|
+
let pending = sessions.get(server.name);
|
|
632
|
+
if (pending === void 0) {
|
|
633
|
+
pending = openMcpSession({
|
|
634
|
+
fetch: input.fetch,
|
|
635
|
+
server: { ...server, transport: { ...server.transport, type: "http" } },
|
|
636
|
+
signal: requestSignal
|
|
637
|
+
});
|
|
638
|
+
sessions.set(server.name, pending);
|
|
639
|
+
const opening = pending;
|
|
640
|
+
void pending.catch(() => {
|
|
641
|
+
if (sessions.get(server.name) === opening) sessions.delete(server.name);
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
const session = await pending;
|
|
645
|
+
requestSignal.throwIfAborted();
|
|
646
|
+
return session.request(method, params, requestSignal);
|
|
647
|
+
},
|
|
648
|
+
close: async () => {
|
|
649
|
+
lifetime.abort();
|
|
650
|
+
await Promise.allSettled(
|
|
651
|
+
[...sessions.values()].map(async (pending) => (await pending).close())
|
|
652
|
+
);
|
|
653
|
+
sessions.clear();
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
574
658
|
// src/playbook.ts
|
|
575
659
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
576
660
|
var isName = (value) => typeof value === "string" && value.length > 0;
|
|
@@ -584,25 +668,43 @@ function parseStep(value) {
|
|
|
584
668
|
if (Object.hasOwn(value, "wait")) {
|
|
585
669
|
const wait = value.wait;
|
|
586
670
|
if (!onlyKeys(value, ["wait"]) || !isRecord2(wait) || !isName(wait.tool)) return null;
|
|
587
|
-
if (!onlyKeys(wait, ["tool", "timeoutMs"])
|
|
671
|
+
if (!onlyKeys(wait, ["server", "tool", "timeoutMs"]) || wait.server !== void 0 && !isName(wait.server))
|
|
672
|
+
return null;
|
|
588
673
|
const timeoutMs = parseTimeout(wait.timeoutMs);
|
|
589
|
-
return timeoutMs === null ? null : {
|
|
674
|
+
return timeoutMs === null ? null : {
|
|
675
|
+
wait: {
|
|
676
|
+
tool: wait.tool,
|
|
677
|
+
timeoutMs,
|
|
678
|
+
...wait.server === void 0 ? {} : { server: wait.server }
|
|
679
|
+
}
|
|
680
|
+
};
|
|
590
681
|
}
|
|
591
682
|
if (Object.hasOwn(value, "waitFor")) {
|
|
592
683
|
const wait = value.waitFor;
|
|
593
684
|
if (!onlyKeys(value, ["waitFor"]) || !isRecord2(wait) || !isName(wait.tool)) return null;
|
|
594
|
-
if (!onlyKeys(wait, ["tool", "path", "atLeast", "timeoutMs"]) || !isName(wait.path))
|
|
685
|
+
if (!onlyKeys(wait, ["server", "tool", "arguments", "path", "atLeast", "timeoutMs"]) || !isName(wait.path) || wait.arguments !== void 0 && !isRecord2(wait.arguments) || wait.server !== void 0 && !isName(wait.server))
|
|
595
686
|
return null;
|
|
596
687
|
if (typeof wait.atLeast !== "number" || !Number.isInteger(wait.atLeast) || wait.atLeast < 0)
|
|
597
688
|
return null;
|
|
598
689
|
const timeoutMs = parseTimeout(wait.timeoutMs);
|
|
599
|
-
return timeoutMs === null ? null : {
|
|
690
|
+
return timeoutMs === null ? null : {
|
|
691
|
+
waitFor: {
|
|
692
|
+
tool: wait.tool,
|
|
693
|
+
path: wait.path,
|
|
694
|
+
atLeast: wait.atLeast,
|
|
695
|
+
timeoutMs,
|
|
696
|
+
...wait.server === void 0 ? {} : { server: wait.server },
|
|
697
|
+
...wait.arguments === void 0 ? {} : { arguments: wait.arguments }
|
|
698
|
+
}
|
|
699
|
+
};
|
|
600
700
|
}
|
|
601
|
-
if (!onlyKeys(value, ["id", "tool", "arguments"]) || !isName(value.tool)
|
|
701
|
+
if (!onlyKeys(value, ["id", "server", "tool", "arguments"]) || !isName(value.tool) || value.server !== void 0 && !isName(value.server))
|
|
702
|
+
return null;
|
|
602
703
|
if (value.id !== void 0 && typeof value.id !== "string") return null;
|
|
603
704
|
if (value.arguments !== void 0 && !isRecord2(value.arguments)) return null;
|
|
604
705
|
return {
|
|
605
706
|
tool: value.tool,
|
|
707
|
+
...value.server === void 0 ? {} : { server: value.server },
|
|
606
708
|
...value.id === void 0 ? {} : { id: value.id },
|
|
607
709
|
...value.arguments === void 0 ? {} : { arguments: value.arguments }
|
|
608
710
|
};
|
|
@@ -753,7 +855,6 @@ function stepResult(result) {
|
|
|
753
855
|
}
|
|
754
856
|
}
|
|
755
857
|
async function poll(timeoutMs, input, ready) {
|
|
756
|
-
const server = builtinMcpServer(input.mcpServers);
|
|
757
858
|
const deadline = Date.now() + timeoutMs;
|
|
758
859
|
const controller = new AbortController();
|
|
759
860
|
const abort = () => controller.abort();
|
|
@@ -761,20 +862,12 @@ async function poll(timeoutMs, input, ready) {
|
|
|
761
862
|
if (input.signal.aborted) abort();
|
|
762
863
|
const timer = setTimeout(abort, timeoutMs);
|
|
763
864
|
try {
|
|
764
|
-
let session;
|
|
765
865
|
while (!controller.signal.aborted && Date.now() < deadline) {
|
|
766
866
|
try {
|
|
767
|
-
|
|
768
|
-
session ??= await openMcpSession({
|
|
769
|
-
fetch: input.fetch,
|
|
770
|
-
server,
|
|
771
|
-
signal: controller.signal
|
|
772
|
-
});
|
|
773
|
-
const done = session !== void 0 && await ready(session);
|
|
867
|
+
const done = await ready(controller.signal);
|
|
774
868
|
if (controller.signal.aborted || Date.now() >= deadline) return false;
|
|
775
869
|
if (done) return true;
|
|
776
870
|
} catch {
|
|
777
|
-
session = void 0;
|
|
778
871
|
if (controller.signal.aborted) return false;
|
|
779
872
|
}
|
|
780
873
|
await hold(Math.min(250, Math.max(0, deadline - Date.now())), controller.signal);
|
|
@@ -785,20 +878,25 @@ async function poll(timeoutMs, input, ready) {
|
|
|
785
878
|
input.signal.removeEventListener("abort", abort);
|
|
786
879
|
}
|
|
787
880
|
}
|
|
788
|
-
var waitForTool = (step, input) => poll(step.wait.timeoutMs, input, async (
|
|
789
|
-
const listed = await
|
|
881
|
+
var waitForTool = (step, input, clients) => poll(step.wait.timeoutMs, input, async (signal) => {
|
|
882
|
+
const listed = await clients.request(step.wait.server, "tools/list", {}, signal);
|
|
790
883
|
return isRecord2(listed) && Array.isArray(listed.tools) && listed.tools.some(
|
|
791
|
-
(tool) => isRecord2(tool) && (tool.name === step.wait.tool || tool.name === `
|
|
884
|
+
(tool) => isRecord2(tool) && (tool.name === step.wait.tool || tool.name === `mcp__${step.wait.server ?? "ycodium"}__${step.wait.tool}`)
|
|
792
885
|
);
|
|
793
886
|
});
|
|
794
|
-
var waitForCount = (step, input) => poll(step.waitFor.timeoutMs, input, async (
|
|
795
|
-
const called = await
|
|
887
|
+
var waitForCount = (step, input, clients) => poll(step.waitFor.timeoutMs, input, async (signal) => {
|
|
888
|
+
const called = await clients.request(
|
|
889
|
+
step.waitFor.server,
|
|
890
|
+
"tools/call",
|
|
891
|
+
{ name: step.waitFor.tool, arguments: step.waitFor.arguments ?? {} },
|
|
892
|
+
signal
|
|
893
|
+
);
|
|
796
894
|
if (isRecord2(called) && called.isError === true) return false;
|
|
797
895
|
const value = valueAt(stepResult(called), step.waitFor.path.split("."));
|
|
798
896
|
const count = Array.isArray(value) ? value.length : value;
|
|
799
897
|
return typeof count === "number" && count >= step.waitFor.atLeast;
|
|
800
898
|
});
|
|
801
|
-
async function runCall(step, playback, input) {
|
|
899
|
+
async function runCall(step, playback, input, clients) {
|
|
802
900
|
let args = step.arguments ?? {};
|
|
803
901
|
let failure;
|
|
804
902
|
try {
|
|
@@ -806,22 +904,20 @@ async function runCall(step, playback, input) {
|
|
|
806
904
|
} catch (error) {
|
|
807
905
|
failure = error instanceof UnresolvedPlaceholder ? error.message : String(error);
|
|
808
906
|
}
|
|
809
|
-
const toolName = `
|
|
907
|
+
const toolName = `mcp__${step.server ?? "ycodium"}__${step.tool}`;
|
|
810
908
|
const extra = { turnId: input.turnId, itemId: input.nextItemId() };
|
|
811
909
|
const payload = { itemType: "mcp_tool_call", title: toolName, data: { toolName, input: args } };
|
|
812
910
|
input.emit("item.started", input.threadId, { ...payload, status: "inProgress" }, extra);
|
|
813
911
|
let result;
|
|
912
|
+
failure ??= clients.missing(step.server);
|
|
814
913
|
if (failure === void 0) {
|
|
815
914
|
try {
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
arguments: args,
|
|
823
|
-
signal: input.signal
|
|
824
|
-
});
|
|
915
|
+
result = await clients.request(
|
|
916
|
+
step.server,
|
|
917
|
+
"tools/call",
|
|
918
|
+
{ name: step.tool, arguments: args },
|
|
919
|
+
input.signal
|
|
920
|
+
);
|
|
825
921
|
} catch (error) {
|
|
826
922
|
failure = String(error);
|
|
827
923
|
}
|
|
@@ -850,11 +946,22 @@ function createPlaybookRunner(input) {
|
|
|
850
946
|
const titles = /* @__PURE__ */ new Map();
|
|
851
947
|
const claimed = /* @__PURE__ */ new Set();
|
|
852
948
|
const sessions = /* @__PURE__ */ new Map();
|
|
949
|
+
const clients = /* @__PURE__ */ new Map();
|
|
853
950
|
let loaded;
|
|
854
951
|
return {
|
|
855
952
|
startSession: (session) => {
|
|
856
953
|
titles.set(session.threadId, session.title);
|
|
857
954
|
},
|
|
955
|
+
stopSession: async (threadId) => {
|
|
956
|
+
const opened = clients.get(threadId);
|
|
957
|
+
clients.delete(threadId);
|
|
958
|
+
await opened?.close();
|
|
959
|
+
},
|
|
960
|
+
dispose: async () => {
|
|
961
|
+
const opened = [...clients.values()];
|
|
962
|
+
clients.clear();
|
|
963
|
+
await Promise.all(opened.map((client) => client.close()));
|
|
964
|
+
},
|
|
858
965
|
runTurn: async (turn) => {
|
|
859
966
|
if (turn.signal.aborted) return "";
|
|
860
967
|
loaded ??= NodeFSP.readFile(path, "utf8").then(
|
|
@@ -882,25 +989,46 @@ function createPlaybookRunner(input) {
|
|
|
882
989
|
const batch = playback.line?.turns[playback.cursor];
|
|
883
990
|
if (batch === void 0) return null;
|
|
884
991
|
playback.cursor += 1;
|
|
992
|
+
let opened = clients.get(turn.threadId);
|
|
993
|
+
if (opened === void 0) {
|
|
994
|
+
opened = createPlaybookMcp({ fetch: turn.fetch, servers: turn.mcpServers });
|
|
995
|
+
clients.set(turn.threadId, opened);
|
|
996
|
+
}
|
|
997
|
+
const safeTurn = {
|
|
998
|
+
...turn,
|
|
999
|
+
emit: (...args) => {
|
|
1000
|
+
turn.emit(args[0], args[1], redactMcpUrls(args[2], turn.mcpServers), args[3]);
|
|
1001
|
+
}
|
|
1002
|
+
};
|
|
885
1003
|
const lines = [];
|
|
886
1004
|
for (const step of batch) {
|
|
887
1005
|
if (turn.signal.aborted) break;
|
|
888
1006
|
if ("wait" in step) {
|
|
889
|
-
const
|
|
1007
|
+
const missing = opened.missing(step.wait.server);
|
|
1008
|
+
if (step.wait.server !== void 0 && missing !== void 0) {
|
|
1009
|
+
lines.push(`mcp-send ${step.wait.tool} failed: ${missing}`);
|
|
1010
|
+
continue;
|
|
1011
|
+
}
|
|
1012
|
+
const ready = await waitForTool(step, safeTurn, opened);
|
|
890
1013
|
if (turn.signal.aborted) break;
|
|
891
1014
|
lines.push(`mcp-send wait ${step.wait.tool}${ready ? ": ready" : " failed: timeout"}`);
|
|
892
1015
|
} else if ("waitFor" in step) {
|
|
893
|
-
const
|
|
1016
|
+
const missing = opened.missing(step.waitFor.server);
|
|
1017
|
+
if (step.waitFor.server !== void 0 && missing !== void 0) {
|
|
1018
|
+
lines.push(`mcp-send ${step.waitFor.tool} failed: ${missing}`);
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
const ready = await waitForCount(step, safeTurn, opened);
|
|
894
1022
|
if (turn.signal.aborted) break;
|
|
895
1023
|
const { tool, path: path2, atLeast } = step.waitFor;
|
|
896
1024
|
lines.push(
|
|
897
1025
|
`mcp-send waitFor ${tool} ${path2} >= ${String(atLeast)}${ready ? ": ready" : " failed: timeout"}`
|
|
898
1026
|
);
|
|
899
1027
|
} else {
|
|
900
|
-
lines.push(await runCall(step, playback,
|
|
1028
|
+
lines.push(await runCall(step, playback, safeTurn, opened));
|
|
901
1029
|
}
|
|
902
1030
|
}
|
|
903
|
-
return lines.join("\n");
|
|
1031
|
+
return redactMcpUrls(lines.join("\n"), turn.mcpServers);
|
|
904
1032
|
}
|
|
905
1033
|
};
|
|
906
1034
|
}
|
|
@@ -1489,6 +1617,7 @@ var createFakeInstance = (config, host) => {
|
|
|
1489
1617
|
stopSession: async (threadId) => {
|
|
1490
1618
|
inflight.get(threadId)?.abort();
|
|
1491
1619
|
threads.delete(threadId);
|
|
1620
|
+
await playbook?.stopSession(threadId);
|
|
1492
1621
|
},
|
|
1493
1622
|
readThread: async (threadId) => {
|
|
1494
1623
|
const booked = requireThread(threadId);
|
|
@@ -1503,6 +1632,7 @@ var createFakeInstance = (config, host) => {
|
|
|
1503
1632
|
for (const settle of pendingDecisions.values()) settle("cancel");
|
|
1504
1633
|
pendingDecisions.clear();
|
|
1505
1634
|
threads.clear();
|
|
1635
|
+
await playbook?.dispose();
|
|
1506
1636
|
events.close();
|
|
1507
1637
|
}
|
|
1508
1638
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-fake",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3078",
|
|
4
4
|
"description": "Minimal fake executor for plugin authors and host orchestration tests.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"@types/node": "24.12.4",
|
|
22
22
|
"esbuild": "0.28.1",
|
|
23
23
|
"vite-plus": "0.2.2",
|
|
24
|
-
"
|
|
25
|
-
"ycodium-
|
|
24
|
+
"ycodium-executor-testing": "0.0.0",
|
|
25
|
+
"@ycodium-ai/plugin-api": "0.2.3078"
|
|
26
26
|
},
|
|
27
27
|
"ycodium": {
|
|
28
28
|
"plugin": "./dist/index.js",
|