@fusionkit/cli 0.1.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/cli.d.ts +8 -0
- package/dist/cli.js +34 -0
- package/dist/commands/ensemble-gateway.d.ts +2 -0
- package/dist/commands/ensemble-gateway.js +114 -0
- package/dist/commands/ensemble-records.d.ts +33 -0
- package/dist/commands/ensemble-records.js +207 -0
- package/dist/commands/ensemble.d.ts +2 -0
- package/dist/commands/ensemble.js +254 -0
- package/dist/commands/fusion.d.ts +2 -0
- package/dist/commands/fusion.js +112 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +24 -0
- package/dist/commands/lifecycle.d.ts +2 -0
- package/dist/commands/lifecycle.js +124 -0
- package/dist/commands/local.d.ts +2 -0
- package/dist/commands/local.js +25 -0
- package/dist/commands/plane.d.ts +2 -0
- package/dist/commands/plane.js +30 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +149 -0
- package/dist/commands/runner.d.ts +2 -0
- package/dist/commands/runner.js +33 -0
- package/dist/commands/secrets.d.ts +2 -0
- package/dist/commands/secrets.js +21 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.js +69 -0
- package/dist/fusion-quickstart.d.ts +182 -0
- package/dist/fusion-quickstart.js +673 -0
- package/dist/gateway.d.ts +63 -0
- package/dist/gateway.js +304 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +28 -0
- package/dist/local.d.ts +40 -0
- package/dist/local.js +144 -0
- package/dist/render.d.ts +7 -0
- package/dist/render.js +131 -0
- package/dist/shared/errors.d.ts +6 -0
- package/dist/shared/errors.js +9 -0
- package/dist/shared/options.d.ts +24 -0
- package/dist/shared/options.js +106 -0
- package/dist/shared/plane.d.ts +13 -0
- package/dist/shared/plane.js +46 -0
- package/dist/shared/preflight.d.ts +15 -0
- package/dist/shared/preflight.js +48 -0
- package/dist/shared/proc.d.ts +41 -0
- package/dist/shared/proc.js +122 -0
- package/dist/test/cli.test.d.ts +1 -0
- package/dist/test/cli.test.js +867 -0
- package/dist/test/e2e.test.d.ts +1 -0
- package/dist/test/e2e.test.js +250 -0
- package/dist/test/fusion-quickstart.test.d.ts +1 -0
- package/dist/test/fusion-quickstart.test.js +189 -0
- package/dist/test/gateway-e2e.test.d.ts +1 -0
- package/dist/test/gateway-e2e.test.js +606 -0
- package/dist/test/handoff.test.d.ts +1 -0
- package/dist/test/handoff.test.js +212 -0
- package/dist/test/local.test.d.ts +1 -0
- package/dist/test/local.test.js +39 -0
- package/dist/test/proc.test.d.ts +1 -0
- package/dist/test/proc.test.js +22 -0
- package/package.json +48 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { after, before, test } from "node:test";
|
|
5
|
+
import { agents, branch, handoff, localFirst, reviewStrategies, targets } from "@fusionkit/handoff";
|
|
6
|
+
import { hashCanonical, PolicyDeniedError, verifyReceiptBundle } from "@fusionkit/protocol";
|
|
7
|
+
import { git, makeRepo, startStack } from "@fusionkit/testkit";
|
|
8
|
+
const SECRET_VALUE = "handoff-secret-value-9876";
|
|
9
|
+
const POOL = "eng-prod";
|
|
10
|
+
let stack;
|
|
11
|
+
let repoDir;
|
|
12
|
+
let h;
|
|
13
|
+
before(async () => {
|
|
14
|
+
stack = await startStack({
|
|
15
|
+
pool: POOL,
|
|
16
|
+
policy: (policy) => {
|
|
17
|
+
policy.agents.allow = ["mock"];
|
|
18
|
+
policy.secrets.releasable = [
|
|
19
|
+
{ name: "MOCK_SECRET", scope: "handoff-test", pools: [POOL] }
|
|
20
|
+
];
|
|
21
|
+
},
|
|
22
|
+
secrets: { MOCK_SECRET: SECRET_VALUE }
|
|
23
|
+
});
|
|
24
|
+
repoDir = makeRepo({
|
|
25
|
+
files: { "README.md": "# handoff fixture\n", "src.txt": "original\n" }
|
|
26
|
+
});
|
|
27
|
+
h = handoff({
|
|
28
|
+
workspace: repoDir,
|
|
29
|
+
plane: { url: stack.planeUrl, adminToken: stack.adminToken },
|
|
30
|
+
actor: { kind: "human", id: "handoff-tester" },
|
|
31
|
+
agent: agents.mock(),
|
|
32
|
+
policy: localFirst({ allowPools: [POOL], maxParallelRuns: 3 }),
|
|
33
|
+
secrets: ["MOCK_SECRET"]
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
after(async () => {
|
|
37
|
+
await stack.stop();
|
|
38
|
+
rmSync(repoDir, { recursive: true, force: true });
|
|
39
|
+
});
|
|
40
|
+
test("dry run discloses the continuation and moves nothing", async () => {
|
|
41
|
+
const { report, envelope, decision } = await h.dryRun(targets.pool(POOL), {
|
|
42
|
+
task: "dry probe",
|
|
43
|
+
reason: "what would move?"
|
|
44
|
+
});
|
|
45
|
+
assert.equal(decision.decision, "continue");
|
|
46
|
+
assert.equal(report.dryRun, true);
|
|
47
|
+
assert.ok(report.continuation);
|
|
48
|
+
assert.equal(report.continuation.checkpointId, envelope.checkpoint.checkpointId);
|
|
49
|
+
assert.equal(report.continuation.envelopeHash, hashCanonical(envelope));
|
|
50
|
+
assert.deepEqual(report.secrets.map((s) => s.name), ["MOCK_SECRET"]);
|
|
51
|
+
const { runs } = await stack.client.listRuns();
|
|
52
|
+
assert.equal(runs.length, 0, "dry run must not create a run");
|
|
53
|
+
});
|
|
54
|
+
test("continueIn hands local work to a governed runner with full provenance", async () => {
|
|
55
|
+
writeFileSync(join(repoDir, "src.txt"), "locally modified before handoff\n");
|
|
56
|
+
const transcript = "user: please finish this refactor\nagent: continuing in eng-prod";
|
|
57
|
+
const run = await h.continueIn(targets.pool(POOL), {
|
|
58
|
+
task: "continue the refactor and touch files",
|
|
59
|
+
reason: "local machine is going offline",
|
|
60
|
+
transcript
|
|
61
|
+
});
|
|
62
|
+
assert.match(run.runId, /^run_/);
|
|
63
|
+
assert.equal(run.envelope.target.pool, POOL);
|
|
64
|
+
assert.equal(run.envelope.checkpoint.tier, "workspace");
|
|
65
|
+
assert.ok(run.envelope.checkpoint.semantic?.transcriptHash);
|
|
66
|
+
// The envelope itself is stored content-addressed on the plane.
|
|
67
|
+
const envelopeBlob = await stack.client.getBlob(run.envelopeHash);
|
|
68
|
+
const storedEnvelope = JSON.parse(envelopeBlob.toString("utf8"));
|
|
69
|
+
assert.equal(hashCanonical(storedEnvelope), run.envelopeHash);
|
|
70
|
+
assert.equal(storedEnvelope.envelopeId, run.envelope.envelopeId);
|
|
71
|
+
// The transcript moved as semantic state, content-addressed.
|
|
72
|
+
const transcriptHash = run.envelope.checkpoint.semantic?.transcriptHash ?? "";
|
|
73
|
+
const storedTranscript = await stack.client.getBlob(transcriptHash);
|
|
74
|
+
assert.equal(storedTranscript.toString("utf8"), transcript);
|
|
75
|
+
// Execute on the runner and wait for the terminal state.
|
|
76
|
+
assert.equal(await stack.runOnce(), run.runId);
|
|
77
|
+
const outcome = await run.wait({ timeoutMs: 30_000 });
|
|
78
|
+
assert.equal(outcome.status, "completed");
|
|
79
|
+
// The signed contract pins the envelope hash; the chain records the checkpoint.
|
|
80
|
+
const bundle = await run.receipt();
|
|
81
|
+
assert.ok(bundle.contract.continuation);
|
|
82
|
+
assert.equal(bundle.contract.continuation.envelopeHash, run.envelopeHash);
|
|
83
|
+
assert.equal(bundle.contract.continuation.checkpointId, run.envelope.checkpoint.checkpointId);
|
|
84
|
+
assert.ok(bundle.events.some((e) => e.event.type === "checkpoint.created" &&
|
|
85
|
+
e.event.checkpointId === run.envelope.checkpoint.checkpointId));
|
|
86
|
+
// Offline verification still holds, and the secret value never leaked.
|
|
87
|
+
const verification = verifyReceiptBundle(bundle);
|
|
88
|
+
assert.deepEqual(verification.problems, []);
|
|
89
|
+
assert.deepEqual(bundle.receipt.secretsReleased.map((s) => s.name), ["MOCK_SECRET"]);
|
|
90
|
+
assert.ok(!JSON.stringify(bundle).includes(SECRET_VALUE));
|
|
91
|
+
assert.ok(!JSON.stringify(run.envelope).includes(SECRET_VALUE));
|
|
92
|
+
// Pull the results back. The run's output diff is computed against the
|
|
93
|
+
// contract base ref and includes our pre-handoff dirty edit; discard the
|
|
94
|
+
// local copy of that edit so the clean fast path applies.
|
|
95
|
+
git(repoDir, ["checkout", "--", "."]);
|
|
96
|
+
const pulled = await run.pull();
|
|
97
|
+
assert.equal(pulled.mode, "applied");
|
|
98
|
+
const agentOutput = readFileSync(join(repoDir, "MOCK_AGENT.md"), "utf8");
|
|
99
|
+
assert.ok(agentOutput.includes("continue the refactor"));
|
|
100
|
+
// The local trace explains the whole continuation.
|
|
101
|
+
const types = h.trace().map((event) => event.type);
|
|
102
|
+
assert.ok(types.includes("checkpoint.created"));
|
|
103
|
+
assert.ok(types.includes("continuation.planned"));
|
|
104
|
+
assert.ok(types.includes("envelope.created"));
|
|
105
|
+
assert.ok(types.includes("run.requested"));
|
|
106
|
+
assert.ok(types.includes("run.terminal"));
|
|
107
|
+
assert.ok(types.includes("results.pulled"));
|
|
108
|
+
});
|
|
109
|
+
test("parallel fan-out shares one checkpoint and review picks a winner", async () => {
|
|
110
|
+
git(repoDir, ["add", "-A"]);
|
|
111
|
+
git(repoDir, ["commit", "--quiet", "-m", "absorb first continuation"]);
|
|
112
|
+
const runs = await h.parallel([
|
|
113
|
+
"attempt one: smallest safe fix",
|
|
114
|
+
"attempt two: compatibility-preserving refactor",
|
|
115
|
+
"attempt three: aggressive cleanup with much more verbose output"
|
|
116
|
+
], targets.pool(POOL), { reason: "explore three strategies" });
|
|
117
|
+
assert.equal(runs.length, 3);
|
|
118
|
+
const checkpointIds = new Set(runs.map((run) => run.envelope.checkpoint.checkpointId));
|
|
119
|
+
assert.equal(checkpointIds.size, 1, "fan-out must share one checkpoint");
|
|
120
|
+
assert.equal(new Set(runs.map((run) => run.runId)).size, 3);
|
|
121
|
+
for (let i = 0; i < runs.length; i++) {
|
|
122
|
+
assert.ok(await stack.runOnce(), "runner must process each attempt");
|
|
123
|
+
}
|
|
124
|
+
for (const run of runs) {
|
|
125
|
+
const outcome = await run.wait({ timeoutMs: 30_000 });
|
|
126
|
+
assert.equal(outcome.status, "completed");
|
|
127
|
+
}
|
|
128
|
+
const review = await h.review(runs, { choose: reviewStrategies.smallestDiff() });
|
|
129
|
+
assert.equal(review.candidates.length, 3);
|
|
130
|
+
assert.ok(review.reason.includes("smallest output diff"));
|
|
131
|
+
assert.ok(runs.some((run) => run.runId === review.chosen.run.runId));
|
|
132
|
+
// Diverge the local workspace, then pull: isolation lands on a branch.
|
|
133
|
+
writeFileSync(join(repoDir, "local-edit.txt"), "concurrent local work\n");
|
|
134
|
+
git(repoDir, ["add", "-A"]);
|
|
135
|
+
git(repoDir, ["commit", "--quiet", "-m", "diverge"]);
|
|
136
|
+
const pulled = await review.chosen.run.pull();
|
|
137
|
+
assert.equal(pulled.mode, "branch");
|
|
138
|
+
const first = await h.review(runs, { choose: reviewStrategies.firstCompleted() });
|
|
139
|
+
assert.ok(first.reason.includes("first attempt to complete"));
|
|
140
|
+
});
|
|
141
|
+
test("stream, branch isolation, scorecards, and checkpoint lineage", async () => {
|
|
142
|
+
const run = await h.continueIn(targets.pool(POOL), {
|
|
143
|
+
task: "produce output for the streaming test",
|
|
144
|
+
reason: "exercise the live stream",
|
|
145
|
+
isolate: branch()
|
|
146
|
+
});
|
|
147
|
+
// ContinueResult parity: tier, explanation, and panel deep links.
|
|
148
|
+
assert.equal(run.tier, "workspace");
|
|
149
|
+
assert.ok(run.explanation.includes(`pool "${POOL}" is allowed`));
|
|
150
|
+
assert.ok(run.url.endsWith(`/ui/#/runs/${run.runId}`));
|
|
151
|
+
assert.ok(run.auditUrl.endsWith(`/v1/runs/${run.runId}/bundle`));
|
|
152
|
+
// Consume the live stream while the runner processes the run.
|
|
153
|
+
const consumer = (async () => {
|
|
154
|
+
const events = [];
|
|
155
|
+
for await (const event of h.stream([run], { timeoutMs: 60_000 })) {
|
|
156
|
+
events.push(event);
|
|
157
|
+
}
|
|
158
|
+
return events;
|
|
159
|
+
})();
|
|
160
|
+
assert.equal(await stack.runOnce(), run.runId);
|
|
161
|
+
const events = await consumer;
|
|
162
|
+
const types = events.map((event) => event.type);
|
|
163
|
+
assert.ok(types.includes("run.status"));
|
|
164
|
+
assert.ok(types.includes("run.event"));
|
|
165
|
+
assert.ok(types.includes("artifact.ready"));
|
|
166
|
+
const terminal = events.find((event) => event.type === "run.terminal");
|
|
167
|
+
assert.ok(terminal && terminal.type === "run.terminal");
|
|
168
|
+
assert.equal(terminal.status, "completed");
|
|
169
|
+
// branch() isolation: results land on a branch even from a clean tree.
|
|
170
|
+
const pulled = await run.pull();
|
|
171
|
+
assert.equal(pulled.mode, "branch");
|
|
172
|
+
// Scorecards: evidence-derived comparison data.
|
|
173
|
+
const review = await h.review([run], {
|
|
174
|
+
choose: reviewStrategies.testsPassSmallestDiff()
|
|
175
|
+
});
|
|
176
|
+
assert.equal(review.chosen.scorecard.exitCode, 0);
|
|
177
|
+
assert.ok(review.chosen.scorecard.filesChanged >= 1);
|
|
178
|
+
assert.ok(review.chosen.scorecard.durationMs >= 0);
|
|
179
|
+
assert.equal(review.chosen.scorecard.secretsReleased, 1);
|
|
180
|
+
assert.ok(review.reason.includes("harness exited 0"));
|
|
181
|
+
// Checkpoint lineage: each checkpoint descends from the previous one.
|
|
182
|
+
const checkpoints = h.checkpoints();
|
|
183
|
+
assert.ok(checkpoints.length >= 2);
|
|
184
|
+
const last = checkpoints.at(-1);
|
|
185
|
+
const previous = checkpoints.at(-2);
|
|
186
|
+
assert.ok(last && previous);
|
|
187
|
+
assert.equal(last.parent, previous.checkpointId);
|
|
188
|
+
});
|
|
189
|
+
test("continuation policy fails closed before anything moves", async () => {
|
|
190
|
+
await assert.rejects(() => h.continueIn(targets.pool("untrusted-pool"), { task: "exfiltrate" }), (error) => {
|
|
191
|
+
assert.ok(error instanceof PolicyDeniedError);
|
|
192
|
+
assert.ok(error.reasons.some((r) => r.includes("untrusted-pool")));
|
|
193
|
+
return true;
|
|
194
|
+
});
|
|
195
|
+
const denied = h
|
|
196
|
+
.trace()
|
|
197
|
+
.filter((e) => e.type === "continuation.planned" && e.decision === "deny");
|
|
198
|
+
assert.ok(denied.length >= 1, "the denial must be visible in the trace");
|
|
199
|
+
});
|
|
200
|
+
test("plane org policy independently denies disallowed agents", async () => {
|
|
201
|
+
const rogue = handoff({
|
|
202
|
+
workspace: repoDir,
|
|
203
|
+
plane: { url: stack.planeUrl, adminToken: stack.adminToken },
|
|
204
|
+
agent: agents.codex(),
|
|
205
|
+
policy: localFirst()
|
|
206
|
+
});
|
|
207
|
+
await assert.rejects(() => rogue.continueIn(targets.pool(POOL), { task: "use a disallowed agent" }), (error) => {
|
|
208
|
+
assert.ok(error instanceof Error);
|
|
209
|
+
assert.match(error.message, /not allowed/);
|
|
210
|
+
return true;
|
|
211
|
+
});
|
|
212
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { claudeEnv, codexConfigToml, cursorInstructions, opencodeConfig, opencodeModelArg } from "../local.js";
|
|
4
|
+
/**
|
|
5
|
+
* M4 coverage: the pure shim builders for `warrant local`. The spawn/exec path
|
|
6
|
+
* needs the real vendor binaries and is exercised manually, not in CI.
|
|
7
|
+
*/
|
|
8
|
+
test("claudeEnv points Claude Code at the gateway's Anthropic surface", () => {
|
|
9
|
+
const env = claudeEnv("http://127.0.0.1:9000", "tok");
|
|
10
|
+
assert.equal(env.ANTHROPIC_BASE_URL, "http://127.0.0.1:9000");
|
|
11
|
+
assert.equal(env.ANTHROPIC_AUTH_TOKEN, "tok");
|
|
12
|
+
assert.equal(env.CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY, "1");
|
|
13
|
+
});
|
|
14
|
+
test("claudeEnv falls back to a placeholder auth token", () => {
|
|
15
|
+
const env = claudeEnv("http://127.0.0.1:9000");
|
|
16
|
+
assert.equal(env.ANTHROPIC_AUTH_TOKEN, "warrant-local");
|
|
17
|
+
});
|
|
18
|
+
test("codexConfigToml declares a Responses provider at the gateway", () => {
|
|
19
|
+
const toml = codexConfigToml("http://127.0.0.1:9000", "local-model");
|
|
20
|
+
assert.ok(toml.includes('model = "local-model"'));
|
|
21
|
+
assert.ok(toml.includes("[model_providers.warrant-local]"));
|
|
22
|
+
assert.ok(toml.includes('base_url = "http://127.0.0.1:9000/v1"'));
|
|
23
|
+
assert.ok(toml.includes('wire_api = "responses"'));
|
|
24
|
+
assert.ok(toml.includes("requires_openai_auth = false"));
|
|
25
|
+
});
|
|
26
|
+
test("opencodeConfig registers an OpenAI-compatible provider", () => {
|
|
27
|
+
const config = opencodeConfig("http://127.0.0.1:9000", "local-model");
|
|
28
|
+
const provider = config.provider["warrant-local"];
|
|
29
|
+
assert.equal(provider?.npm, "@ai-sdk/openai-compatible");
|
|
30
|
+
assert.equal(provider?.options.baseURL, "http://127.0.0.1:9000/v1");
|
|
31
|
+
assert.ok("local-model" in (provider?.models ?? {}));
|
|
32
|
+
assert.equal(opencodeModelArg("local-model"), "warrant-local/local-model");
|
|
33
|
+
});
|
|
34
|
+
test("cursorInstructions surfaces the public URL and plan-mode caveat", () => {
|
|
35
|
+
const text = cursorInstructions("https://abc.example", "local-model");
|
|
36
|
+
assert.ok(text.includes("https://abc.example/v1"));
|
|
37
|
+
assert.ok(text.includes("local-model"));
|
|
38
|
+
assert.ok(text.toLowerCase().includes("plan"));
|
|
39
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { freePort, spawnLogged, spawnTool, waitForHttp } from "../shared/proc.js";
|
|
4
|
+
const MISSING_BINARY = "warrant-definitely-not-a-real-binary-xyz";
|
|
5
|
+
test("freePort returns a usable ephemeral port", async () => {
|
|
6
|
+
const port = await freePort();
|
|
7
|
+
assert.ok(Number.isInteger(port) && port > 0);
|
|
8
|
+
});
|
|
9
|
+
test("spawnTool resolves with the child's exit code", async () => {
|
|
10
|
+
assert.equal(await spawnTool(process.execPath, ["-e", "process.exit(3)"], {}), 3);
|
|
11
|
+
});
|
|
12
|
+
test("spawnTool rejects instead of crashing when the binary is missing", async () => {
|
|
13
|
+
await assert.rejects(() => spawnTool(MISSING_BINARY, [], {}));
|
|
14
|
+
});
|
|
15
|
+
test("waitForHttp surfaces a missing-binary spawn error with a clear message", async () => {
|
|
16
|
+
const proc = spawnLogged(MISSING_BINARY, ["serve"]);
|
|
17
|
+
await assert.rejects(() => waitForHttp("http://127.0.0.1:1/", proc, { timeoutMs: 2000, label: "ghost service" }), /ghost service failed to start/);
|
|
18
|
+
});
|
|
19
|
+
test("waitForHttp reports when the child exits before becoming ready", async () => {
|
|
20
|
+
const proc = spawnLogged(process.execPath, ["-e", "process.exit(1)"]);
|
|
21
|
+
await assert.rejects(() => waitForHttp("http://127.0.0.1:1/", proc, { timeoutMs: 3000, label: "shortlived" }), /exited|failed to start/);
|
|
22
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fusionkit/cli",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/velum-labs/handoffkit.git",
|
|
8
|
+
"directory": "packages/cli"
|
|
9
|
+
},
|
|
10
|
+
"description": "fusionkit — real model fusion behind your coding agent (codex, claude, cursor).",
|
|
11
|
+
"license": "UNLICENSED",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"bin": {
|
|
14
|
+
"fusionkit": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./render": {
|
|
22
|
+
"types": "./dist/render.d.ts",
|
|
23
|
+
"default": "./dist/render.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"registry": "https://registry.npmjs.org",
|
|
31
|
+
"access": "public",
|
|
32
|
+
"provenance": true
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"commander": "14.0.3",
|
|
36
|
+
"@fusionkit/handoff": "0.1.0",
|
|
37
|
+
"@fusionkit/model-gateway": "0.1.0",
|
|
38
|
+
"@fusionkit/runner": "0.1.0",
|
|
39
|
+
"@fusionkit/plane": "0.1.0",
|
|
40
|
+
"@fusionkit/ensemble": "0.1.0",
|
|
41
|
+
"@fusionkit/protocol": "0.1.0",
|
|
42
|
+
"@fusionkit/workspace": "0.1.0",
|
|
43
|
+
"@fusionkit/sdk": "0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@fusionkit/testkit": "0.1.0"
|
|
47
|
+
}
|
|
48
|
+
}
|