@geminixiang/mikan 1.0.0-beta.77 → 1.0.0-beta.78
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/CHANGELOG.md +19 -0
- package/dist/adapters/web/login/oauth.d.ts.map +1 -1
- package/dist/adapters/web/login/oauth.js +3 -2
- package/dist/adapters/web/login/oauth.js.map +1 -1
- package/dist/adapters/web/login/portal.js +3 -2
- package/dist/adapters/web/login/portal.js.map +1 -1
- package/dist/cli/boot.d.ts.map +1 -1
- package/dist/cli/boot.js +3 -1
- package/dist/cli/boot.js.map +1 -1
- package/dist/cli/sandbox.d.ts +3 -0
- package/dist/cli/sandbox.d.ts.map +1 -0
- package/dist/cli/sandbox.js +79 -0
- package/dist/cli/sandbox.js.map +1 -0
- package/dist/cli/types.d.ts +2 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/types.js.map +1 -1
- package/dist/harness/index.d.ts +4 -0
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +4 -0
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/mcp-result.d.ts +20 -0
- package/dist/harness/mcp-result.d.ts.map +1 -0
- package/dist/harness/mcp-result.js +171 -0
- package/dist/harness/mcp-result.js.map +1 -0
- package/dist/harness/mcp.d.ts.map +1 -1
- package/dist/harness/mcp.js +7 -32
- package/dist/harness/mcp.js.map +1 -1
- package/dist/harness/presenter.d.ts +1 -0
- package/dist/harness/presenter.d.ts.map +1 -1
- package/dist/harness/presenter.js +1 -1
- package/dist/harness/presenter.js.map +1 -1
- package/dist/harness/prompt.js +1 -1
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +8 -3
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/tools/pi-tools.d.ts +1 -0
- package/dist/harness/tools/pi-tools.d.ts.map +1 -1
- package/dist/harness/tools/pi-tools.js +1 -1
- package/dist/harness/tools/pi-tools.js.map +1 -1
- package/dist/harness/types.d.ts +1 -1
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/main.js +7 -5
- package/dist/main.js.map +1 -1
- package/dist/memory-capture/index.d.ts +16 -0
- package/dist/memory-capture/index.d.ts.map +1 -0
- package/dist/memory-capture/index.js +194 -0
- package/dist/memory-capture/index.js.map +1 -0
- package/dist/memory-capture/types.d.ts +27 -0
- package/dist/memory-capture/types.d.ts.map +1 -0
- package/dist/memory-capture/types.js.map +1 -0
- package/dist/observability/types.d.ts +1 -1
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/observability/types.js.map +1 -1
- package/dist/office/index.d.ts.map +1 -1
- package/dist/office/index.js +2 -1
- package/dist/office/index.js.map +1 -1
- package/dist/office/projection.d.ts.map +1 -1
- package/dist/office/projection.js +5 -4
- package/dist/office/projection.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +16 -59
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +2 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +2 -1
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +21 -14
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +2 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/layout.d.ts +7 -0
- package/dist/sandbox/layout.d.ts.map +1 -0
- package/dist/sandbox/layout.js +13 -0
- package/dist/sandbox/layout.js.map +1 -0
- package/dist/sandbox/provisioner.d.ts +24 -4
- package/dist/sandbox/provisioner.d.ts.map +1 -1
- package/dist/sandbox/provisioner.js +210 -20
- package/dist/sandbox/provisioner.js.map +1 -1
- package/dist/sessions/session-store.d.ts +1 -1
- package/dist/sessions/session-store.d.ts.map +1 -1
- package/dist/sessions/store.d.ts +0 -1
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +0 -31
- package/dist/sessions/store.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +7 -6
- package/dist/vault/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/dream/index.d.ts +0 -20
- package/dist/dream/index.d.ts.map +0 -1
- package/dist/dream/index.js +0 -262
- package/dist/dream/index.js.map +0 -1
- package/dist/dream/types.d.ts +0 -30
- package/dist/dream/types.d.ts.map +0 -1
- package/dist/dream/types.js.map +0 -1
- /package/dist/{dream → memory-capture}/types.js +0 -0
package/dist/cli/boot.js
CHANGED
|
@@ -2,7 +2,7 @@ import { join, resolve } from "node:path";
|
|
|
2
2
|
import { envSummaryLines } from "../env-manifest.js";
|
|
3
3
|
import { parseSandboxArg } from "../sandbox/index.js";
|
|
4
4
|
import { cliCommand, defaultStateDir, nonEmptyValue, resolveStateDir } from "./arg-grammar.js";
|
|
5
|
-
const SUBCOMMANDS = ["office", "sessions", "env"];
|
|
5
|
+
const SUBCOMMANDS = ["office", "sessions", "sandbox", "env"];
|
|
6
6
|
function bootCommand() {
|
|
7
7
|
return cliCommand("mikan")
|
|
8
8
|
.description("Multi-platform chat agent daemon")
|
|
@@ -46,6 +46,7 @@ function subcommandPlan(args) {
|
|
|
46
46
|
mode,
|
|
47
47
|
...(mode === "office" ? { officeArgs: args.slice(1) } : {}),
|
|
48
48
|
...(mode === "sessions" ? { sessionsArgs: args.slice(1) } : {}),
|
|
49
|
+
...(mode === "sandbox" ? { sandboxArgs: args.slice(1) } : {}),
|
|
49
50
|
stateDir,
|
|
50
51
|
workingDir: join(stateDir, "workspace"),
|
|
51
52
|
workingDirExplicit: false,
|
|
@@ -69,6 +70,7 @@ export function helpText() {
|
|
|
69
70
|
Commands:
|
|
70
71
|
mikan office <list|claim|migrate-openconnector|migrate-events|migrate-door-policy> Inspect offices, claim legacy directories, migrate legacy state.
|
|
71
72
|
mikan sessions migrate Migrate legacy sessions (stop the daemon first).
|
|
73
|
+
mikan sandbox <status|diff|migrate> --image <image> Inspect and upgrade image:* sandboxes (stop the daemon before migrate).
|
|
72
74
|
mikan env Show environment-variable inventory.
|
|
73
75
|
mikan onboard Interactive first-run setup.
|
|
74
76
|
|
package/dist/cli/boot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boot.js","sourceRoot":"","sources":["../../src/cli/boot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAI/F,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"boot.js","sourceRoot":"","sources":["../../src/cli/boot.ts"],"names":[],"mappings":"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","sourcesContent":["import { join, resolve } from \"node:path\";\nimport { envSummaryLines } from \"../env-manifest.js\";\nimport { parseSandboxArg } from \"../sandbox/index.js\";\nimport type { BootPlan } from \"./types.js\";\nimport { cliCommand, defaultStateDir, nonEmptyValue, resolveStateDir } from \"./arg-grammar.js\";\n\nexport type { BootPlan } from \"./types.js\";\n\nconst SUBCOMMANDS = [\"office\", \"sessions\", \"sandbox\", \"env\"] as const;\n\ninterface BootOptions {\n stateDir?: string;\n sandbox?: string;\n download?: string;\n help?: boolean;\n version?: boolean;\n onboard?: boolean;\n}\n\nfunction bootCommand() {\n return cliCommand(\"mikan\")\n .description(\"Multi-platform chat agent daemon\")\n .helpOption(false)\n .argument(\"[working-directory...]\", \"Workspace directory (default: <state-dir>/workspace)\")\n .option(\"--state-dir <dir>\", \"State directory (default: ~/.mikan)\", nonEmptyValue)\n .option(\n \"--sandbox <spec>\",\n \"host | container:<name> | image:<image[:tag]> | cloudflare:<id>\",\n nonEmptyValue,\n )\n .option(\"--download <channel>\", \"Dump a Slack channel's history, then exit\", nonEmptyValue)\n .option(\"--onboard\", \"Interactive first-run setup (also: mikan onboard)\")\n .option(\"-v, --version\", \"Print version\")\n .option(\"-V\", \"Print version\")\n .option(\"-h, --help\", \"Show help\");\n}\n\nexport function resolveBoot(args: string[] = process.argv.slice(2)): BootPlan {\n const routed = subcommandPlan(args);\n if (routed) return routed;\n\n const command = bootCommand();\n command.parse(args, { from: \"user\" });\n const options = command.opts<BootOptions & { V?: boolean }>();\n const onboardFirst = args[0] === \"onboard\";\n const workingDirArg = (onboardFirst ? command.args.slice(1) : command.args).at(-1);\n const downloadChannel = options.download;\n const sandboxArg = options.sandbox;\n const stateDir = resolveStateDir(args);\n return {\n mode: bootMode({ ...options, version: options.version || options.V }, onboardFirst),\n stateDir,\n workingDir: workingDirArg ? resolve(workingDirArg) : join(stateDir, \"workspace\"),\n workingDirExplicit: workingDirArg !== undefined,\n sandbox: sandboxArg === undefined ? { type: \"host\" } : parseSandboxArg(sandboxArg),\n downloadChannel,\n };\n}\n\nfunction subcommandPlan(args: string[]): BootPlan | undefined {\n const mode = SUBCOMMANDS.find((name) => name === args[0]);\n if (!mode) return undefined;\n const stateDir = defaultStateDir();\n return {\n mode,\n ...(mode === \"office\" ? { officeArgs: args.slice(1) } : {}),\n ...(mode === \"sessions\" ? { sessionsArgs: args.slice(1) } : {}),\n ...(mode === \"sandbox\" ? { sandboxArgs: args.slice(1) } : {}),\n stateDir,\n workingDir: join(stateDir, \"workspace\"),\n workingDirExplicit: false,\n sandbox: { type: \"host\" },\n };\n}\n\nfunction bootMode(options: BootOptions, onboardFirst: boolean): BootPlan[\"mode\"] {\n if (options.help) return \"help\";\n if (options.version) return \"version\";\n if (onboardFirst || options.onboard) return \"onboard\";\n if (options.download) return \"download\";\n return \"run\";\n}\n\nexport function helpText(): string {\n return (\n bootCommand().helpInformation() +\n `\nCommands:\n mikan office <list|claim|migrate-openconnector|migrate-events|migrate-door-policy> Inspect offices, claim legacy directories, migrate legacy state.\n mikan sessions migrate Migrate legacy sessions (stop the daemon first).\n mikan sandbox <status|diff|migrate> --image <image> Inspect and upgrade image:* sandboxes (stop the daemon before migrate).\n mikan env Show environment-variable inventory.\n mikan onboard Interactive first-run setup.\n\nEnvironment (platform tokens select which chat adapters start):\n${envSummaryLines().join(\"\\n\")}\nRun mikan env for the full inventory.`\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/cli/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAOnE,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EAAE,EACd,aAAa,GAAE,CAAC,KAAK,EAAE,MAAM,KAAK,sBACC,GAClC,OAAO,CAAC,MAAM,CAAC,CAmCjB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { DockerContainerManager } from "../sandbox/provisioner.js";
|
|
2
|
+
import { cliCommand, commandExitCode, nonEmptyValue } from "./arg-grammar.js";
|
|
3
|
+
export async function runSandboxCommand(argv, createManager = (image) => new DockerContainerManager(image)) {
|
|
4
|
+
const command = cliCommand("mikan sandbox")
|
|
5
|
+
.description("Inspect and upgrade managed image:* sandbox containers")
|
|
6
|
+
.requiredOption("--image <image>", "The image the daemon runs with (image:<image>)", nonEmptyValue);
|
|
7
|
+
let result = 1;
|
|
8
|
+
const manager = () => createManager(command.opts().image ?? "");
|
|
9
|
+
command
|
|
10
|
+
.command("status")
|
|
11
|
+
.description("List managed containers with home-volume and image-drift state")
|
|
12
|
+
.action(async () => {
|
|
13
|
+
result = await printStatus(manager());
|
|
14
|
+
});
|
|
15
|
+
command
|
|
16
|
+
.command("diff <containerKey>")
|
|
17
|
+
.description("Show system changes outside /root that an upgrade will discard")
|
|
18
|
+
.action(async (containerKey) => {
|
|
19
|
+
result = await printSystemChanges(manager(), containerKey);
|
|
20
|
+
});
|
|
21
|
+
command
|
|
22
|
+
.command("migrate <containerKeys...>")
|
|
23
|
+
.description("Move legacy containers onto a home volume and the current image")
|
|
24
|
+
.action(async (containerKeys) => {
|
|
25
|
+
result = await migrateContainers(manager(), containerKeys);
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
await command.parseAsync(argv, { from: "user" });
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return commandExitCode(error, command);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function printStatus(manager) {
|
|
36
|
+
const entries = await manager.inventory();
|
|
37
|
+
if (entries.length === 0) {
|
|
38
|
+
console.log("No managed sandbox containers.");
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const state = entry.running ? "running" : "stopped";
|
|
43
|
+
const layout = entry.homeVolume ? "home-volume" : "legacy";
|
|
44
|
+
const image = entry.imageStale ? "stale-image" : "current-image";
|
|
45
|
+
console.log(`${entry.containerKey ?? entry.containerName}\t${state}\t${layout}\t${image}`);
|
|
46
|
+
}
|
|
47
|
+
const legacy = entries.filter((entry) => !entry.homeVolume).length;
|
|
48
|
+
const stale = entries.filter((entry) => entry.homeVolume && entry.imageStale).length;
|
|
49
|
+
console.log(`${entries.length} container(s): ${legacy} legacy (run \`mikan sandbox migrate\`), ${stale} home-volume on a stale image (replaced on next start after idle stop).`);
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
async function printSystemChanges(manager, containerKey) {
|
|
53
|
+
const changes = await manager.systemChanges(DockerContainerManager.containerName(containerKey));
|
|
54
|
+
if (changes.length === 0) {
|
|
55
|
+
console.log("No system changes outside /root and /workspace.");
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
for (const line of changes)
|
|
59
|
+
console.log(line);
|
|
60
|
+
console.log(`${changes.length} path(s) outside /root will be discarded by an upgrade.`);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
async function migrateContainers(manager, containerKeys) {
|
|
64
|
+
let failed = 0;
|
|
65
|
+
for (const containerKey of containerKeys) {
|
|
66
|
+
try {
|
|
67
|
+
const outcome = await manager.migrateToHomeVolume(containerKey);
|
|
68
|
+
console.log(`${containerKey}\t${outcome}`);
|
|
69
|
+
if (outcome === "missing")
|
|
70
|
+
failed++;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
failed++;
|
|
74
|
+
console.error(`${containerKey}\tfailed\t${error instanceof Error ? error.message : error}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return failed === 0 ? 0 : 1;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/cli/sandbox.ts"],"names":[],"mappings":"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","sourcesContent":["import { DockerContainerManager } from \"../sandbox/provisioner.js\";\nimport { cliCommand, commandExitCode, nonEmptyValue } from \"./arg-grammar.js\";\n\ninterface SandboxCommandOptions {\n image?: string;\n}\n\nexport async function runSandboxCommand(\n argv: string[],\n createManager: (image: string) => DockerContainerManager = (image) =>\n new DockerContainerManager(image),\n): Promise<number> {\n const command = cliCommand(\"mikan sandbox\")\n .description(\"Inspect and upgrade managed image:* sandbox containers\")\n .requiredOption(\n \"--image <image>\",\n \"The image the daemon runs with (image:<image>)\",\n nonEmptyValue,\n );\n let result = 1;\n const manager = (): DockerContainerManager =>\n createManager(command.opts<SandboxCommandOptions>().image ?? \"\");\n command\n .command(\"status\")\n .description(\"List managed containers with home-volume and image-drift state\")\n .action(async () => {\n result = await printStatus(manager());\n });\n command\n .command(\"diff <containerKey>\")\n .description(\"Show system changes outside /root that an upgrade will discard\")\n .action(async (containerKey: string) => {\n result = await printSystemChanges(manager(), containerKey);\n });\n command\n .command(\"migrate <containerKeys...>\")\n .description(\"Move legacy containers onto a home volume and the current image\")\n .action(async (containerKeys: string[]) => {\n result = await migrateContainers(manager(), containerKeys);\n });\n try {\n await command.parseAsync(argv, { from: \"user\" });\n return result;\n } catch (error) {\n return commandExitCode(error, command);\n }\n}\n\nasync function printStatus(manager: DockerContainerManager): Promise<number> {\n const entries = await manager.inventory();\n if (entries.length === 0) {\n console.log(\"No managed sandbox containers.\");\n return 0;\n }\n for (const entry of entries) {\n const state = entry.running ? \"running\" : \"stopped\";\n const layout = entry.homeVolume ? \"home-volume\" : \"legacy\";\n const image = entry.imageStale ? \"stale-image\" : \"current-image\";\n console.log(`${entry.containerKey ?? entry.containerName}\\t${state}\\t${layout}\\t${image}`);\n }\n const legacy = entries.filter((entry) => !entry.homeVolume).length;\n const stale = entries.filter((entry) => entry.homeVolume && entry.imageStale).length;\n console.log(\n `${entries.length} container(s): ${legacy} legacy (run \\`mikan sandbox migrate\\`), ${stale} home-volume on a stale image (replaced on next start after idle stop).`,\n );\n return 0;\n}\n\nasync function printSystemChanges(\n manager: DockerContainerManager,\n containerKey: string,\n): Promise<number> {\n const changes = await manager.systemChanges(DockerContainerManager.containerName(containerKey));\n if (changes.length === 0) {\n console.log(\"No system changes outside /root and /workspace.\");\n return 0;\n }\n for (const line of changes) console.log(line);\n console.log(`${changes.length} path(s) outside /root will be discarded by an upgrade.`);\n return 0;\n}\n\nasync function migrateContainers(\n manager: DockerContainerManager,\n containerKeys: readonly string[],\n): Promise<number> {\n let failed = 0;\n for (const containerKey of containerKeys) {\n try {\n const outcome = await manager.migrateToHomeVolume(containerKey);\n console.log(`${containerKey}\\t${outcome}`);\n if (outcome === \"missing\") failed++;\n } catch (error) {\n failed++;\n console.error(`${containerKey}\\tfailed\\t${error instanceof Error ? error.message : error}`);\n }\n }\n return failed === 0 ? 0 : 1;\n}\n"]}
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -8,9 +8,10 @@ export interface OnboardIo {
|
|
|
8
8
|
close(): void;
|
|
9
9
|
}
|
|
10
10
|
export interface BootPlan {
|
|
11
|
-
mode: "office" | "sessions" | "env" | "help" | "version" | "onboard" | "download" | "run";
|
|
11
|
+
mode: "office" | "sessions" | "sandbox" | "env" | "help" | "version" | "onboard" | "download" | "run";
|
|
12
12
|
officeArgs?: string[];
|
|
13
13
|
sessionsArgs?: string[];
|
|
14
|
+
sandboxArgs?: string[];
|
|
14
15
|
stateDir: string;
|
|
15
16
|
workingDir: string;
|
|
16
17
|
workingDirExplicit: boolean;
|
package/dist/cli/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EACA,QAAQ,GACR,UAAU,GACV,SAAS,GACT,KAAK,GACL,MAAM,GACN,SAAS,GACT,SAAS,GACT,UAAU,GACV,KAAK,CAAC;IACV,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,OAAO,EAAE,aAAa,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
|
package/dist/cli/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { SandboxConfig } from \"../sandbox/types.js\";\n\nexport interface OnboardIo {\n ask(query: string): Promise<string>;\n askSecret(query: string): Promise<string>;\n select(query: string, labels: string[]): Promise<number>;\n confirm(query: string): Promise<boolean>;\n print(line: string): void;\n close(): void;\n}\n\nexport interface BootPlan {\n mode
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { SandboxConfig } from \"../sandbox/types.js\";\n\nexport interface OnboardIo {\n ask(query: string): Promise<string>;\n askSecret(query: string): Promise<string>;\n select(query: string, labels: string[]): Promise<number>;\n confirm(query: string): Promise<boolean>;\n print(line: string): void;\n close(): void;\n}\n\nexport interface BootPlan {\n mode:\n | \"office\"\n | \"sessions\"\n | \"sandbox\"\n | \"env\"\n | \"help\"\n | \"version\"\n | \"onboard\"\n | \"download\"\n | \"run\";\n officeArgs?: string[];\n sessionsArgs?: string[];\n sandboxArgs?: string[];\n stateDir: string;\n workingDir: string;\n workingDirExplicit: boolean;\n sandbox: SandboxConfig;\n downloadChannel?: string;\n}\n"]}
|
package/dist/harness/index.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ export { SessionStore } from "../sessions/session-store.js";
|
|
|
6
6
|
export type { SessionContext, SessionEntry, SessionHeader, SessionMessageEntry, } from "../sessions/types.js";
|
|
7
7
|
export { CURRENT_SESSION_VERSION } from "../sessions/types.js";
|
|
8
8
|
export { MikanAgentSession } from "./session.js";
|
|
9
|
+
export { runSubagent } from "./subagent.js";
|
|
10
|
+
export { resolveTriggerAttribution } from "./prompt.js";
|
|
11
|
+
export { isEventTriggerAttribution } from "./presenter.js";
|
|
12
|
+
export { redactSecrets } from "./tools/secret-redaction.js";
|
|
9
13
|
export type { CompactionReason, HarnessEvent, HarnessEventListener, MikanAgentSessionOptions, } from "./types.js";
|
|
10
14
|
export { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter, validateSkill, } from "./skills.js";
|
|
11
15
|
export type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from "./types.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/harness/index.js
CHANGED
|
@@ -4,6 +4,10 @@ export { JEV_MODEL_ID, JevNotConfiguredError, JevRequestError, evaluateWithJev,
|
|
|
4
4
|
export { SessionStore } from "../sessions/session-store.js";
|
|
5
5
|
export { CURRENT_SESSION_VERSION } from "../sessions/types.js";
|
|
6
6
|
export { MikanAgentSession } from "./session.js";
|
|
7
|
+
export { runSubagent } from "./subagent.js";
|
|
8
|
+
export { resolveTriggerAttribution } from "./prompt.js";
|
|
9
|
+
export { isEventTriggerAttribution } from "./presenter.js";
|
|
10
|
+
export { redactSecrets } from "./tools/secret-redaction.js";
|
|
7
11
|
export { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter, validateSkill, } from "./skills.js";
|
|
8
12
|
export { loadSubagentProfiles } from "./subagent-profiles.js";
|
|
9
13
|
export { DEFAULT_BUDGET_SETTINGS, DEFAULT_EVENT_BUDGET, DEFAULT_RETRY_SETTINGS, resolveHarnessSettings, } from "./session.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,GAOhB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAO5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,GAOhB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAO5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAO5D,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAcN,MAAM,YAAY,CAAC","sourcesContent":["export {\n DEFAULT_HTTP_IDLE_TIMEOUT_MS,\n configureHttpDispatcher,\n parseHttpIdleTimeoutMs,\n} from \"./http.js\";\nexport { MikanModels, defaultModelsJsonPath } from \"./models.js\";\nexport type { CreateMikanModelsOptions } from \"./types.js\";\nexport {\n JEV_MODEL_ID,\n JevNotConfiguredError,\n JevRequestError,\n evaluateWithJev,\n type EvaluateWithJevOptions,\n type JevAnswer,\n type JevEntry,\n type JevQuestion,\n type JevQuestions,\n type JevResult,\n} from \"./jev.js\";\nexport { SessionStore } from \"../sessions/session-store.js\";\nexport type {\n SessionContext,\n SessionEntry,\n SessionHeader,\n SessionMessageEntry,\n} from \"../sessions/types.js\";\nexport { CURRENT_SESSION_VERSION } from \"../sessions/types.js\";\nexport { MikanAgentSession } from \"./session.js\";\nexport { runSubagent } from \"./subagent.js\";\nexport { resolveTriggerAttribution } from \"./prompt.js\";\nexport { isEventTriggerAttribution } from \"./presenter.js\";\nexport { redactSecrets } from \"./tools/secret-redaction.js\";\nexport type {\n CompactionReason,\n HarnessEvent,\n HarnessEventListener,\n MikanAgentSessionOptions,\n} from \"./types.js\";\nexport {\n formatSkillsForPrompt,\n loadSkillsFromDir,\n parseFrontmatter,\n validateSkill,\n} from \"./skills.js\";\nexport type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from \"./types.js\";\nexport { loadSubagentProfiles } from \"./subagent-profiles.js\";\nexport type { LoadSubagentProfilesResult, SubagentProfileDiagnostic } from \"./types.js\";\nexport {\n DEFAULT_BUDGET_SETTINGS,\n DEFAULT_EVENT_BUDGET,\n DEFAULT_RETRY_SETTINGS,\n resolveHarnessSettings,\n type CompactionSettings,\n} from \"./session.js\";\nexport type { BudgetSettings, HarnessSettings, RetrySettings } from \"./types.js\";\nexport {\n type SubagentModelSpec,\n type SubagentProfile,\n type SubagentParentContext,\n type SubagentRunBudget,\n type SubagentRunOutput,\n type SubagentRunRequest,\n type SubagentRunResult,\n type SubagentRunStatus,\n type SubagentUsage,\n type SubagentUsageSink,\n type BranchSummaryEntry,\n type CompactionEntry,\n type CustomEntry,\n} from \"./types.js\";\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
|
|
2
|
+
import { type AgentToolResult, type Context, type ExecutionEnv } from "@earendil-works/pi-agent-core";
|
|
3
|
+
export interface McpTextLimits {
|
|
4
|
+
maxBytes: number;
|
|
5
|
+
maxLines: number;
|
|
6
|
+
}
|
|
7
|
+
export interface BoundedMcpText {
|
|
8
|
+
text: string;
|
|
9
|
+
truncated: boolean;
|
|
10
|
+
digest?: true;
|
|
11
|
+
}
|
|
12
|
+
export interface McpCallResult {
|
|
13
|
+
content?: unknown;
|
|
14
|
+
structuredContent?: unknown;
|
|
15
|
+
isError?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function mcpResultContent(result: McpCallResult): (TextContent | ImageContent)[];
|
|
18
|
+
export declare function boundMcpText(text: string, limits: McpTextLimits): BoundedMcpText;
|
|
19
|
+
export declare function guardMcpToolResult(result: McpCallResult, env: ExecutionEnv, context: Context): Promise<AgentToolResult<undefined>>;
|
|
20
|
+
//# sourceMappingURL=mcp-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-result.d.ts","sourceRoot":"","sources":["../../src/harness/mcp-result.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,YAAY,EAClB,MAAM,+BAA+B,CAAC;AAGvC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,IAAI,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAiED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAStF;AAsDD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,cAAc,CAehF;AAoCD,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,YAAY,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAkBrC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, } from "@earendil-works/pi-agent-core";
|
|
3
|
+
import { redactSecrets } from "./tools/secret-redaction.js";
|
|
4
|
+
const SPILL_DIR = [".mikan", "mcp-output"];
|
|
5
|
+
const NOTICE_RESERVE_BYTES = 640;
|
|
6
|
+
const NOTICE_RESERVE_LINES = 4;
|
|
7
|
+
const RESULT_LIMITS = {
|
|
8
|
+
maxBytes: DEFAULT_MAX_BYTES - NOTICE_RESERVE_BYTES,
|
|
9
|
+
maxLines: DEFAULT_MAX_LINES - NOTICE_RESERVE_LINES,
|
|
10
|
+
};
|
|
11
|
+
const DIGEST_LEVELS = [
|
|
12
|
+
{ stringChars: 200, arrayItems: 3, depth: 6 },
|
|
13
|
+
{ stringChars: 80, arrayItems: 2, depth: 4 },
|
|
14
|
+
{ stringChars: 40, arrayItems: 1, depth: 3 },
|
|
15
|
+
{ stringChars: 16, arrayItems: 1, depth: 2 },
|
|
16
|
+
];
|
|
17
|
+
function isRecord(value) {
|
|
18
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
function stringField(block, key) {
|
|
21
|
+
const value = block[key];
|
|
22
|
+
return typeof value === "string" ? value : undefined;
|
|
23
|
+
}
|
|
24
|
+
function describeResource(resource) {
|
|
25
|
+
const uri = stringField(resource, "uri") ?? "(no URI)";
|
|
26
|
+
const text = stringField(resource, "text");
|
|
27
|
+
if (text !== undefined)
|
|
28
|
+
return `[Resource: ${uri}]\n${text}`;
|
|
29
|
+
const blob = stringField(resource, "blob");
|
|
30
|
+
const mimeType = stringField(resource, "mimeType") ?? "unknown type";
|
|
31
|
+
const size = blob === undefined ? "no content" : `${Buffer.byteLength(blob, "base64")} bytes`;
|
|
32
|
+
return `[Resource: ${uri} (${mimeType}, ${size}, binary content omitted)]`;
|
|
33
|
+
}
|
|
34
|
+
function blockContent(block) {
|
|
35
|
+
const text = stringField(block, "text");
|
|
36
|
+
if (block.type === "text" && text !== undefined)
|
|
37
|
+
return { type: "text", text };
|
|
38
|
+
const data = stringField(block, "data");
|
|
39
|
+
const mimeType = stringField(block, "mimeType");
|
|
40
|
+
if (block.type === "image" && data !== undefined && mimeType !== undefined) {
|
|
41
|
+
return { type: "image", data, mimeType };
|
|
42
|
+
}
|
|
43
|
+
if (block.type === "resource" && isRecord(block.resource)) {
|
|
44
|
+
return { type: "text", text: describeResource(block.resource) };
|
|
45
|
+
}
|
|
46
|
+
if (block.type === "resource_link") {
|
|
47
|
+
const uri = stringField(block, "uri") ?? "(no URI)";
|
|
48
|
+
return { type: "text", text: `[Resource link: ${stringField(block, "name") ?? uri}] ${uri}` };
|
|
49
|
+
}
|
|
50
|
+
if (block.type === "audio") {
|
|
51
|
+
return { type: "text", text: `[Audio content omitted: ${mimeType ?? "audio/*"}]` };
|
|
52
|
+
}
|
|
53
|
+
return { type: "text", text: JSON.stringify(block) };
|
|
54
|
+
}
|
|
55
|
+
export function mcpResultContent(result) {
|
|
56
|
+
const blocks = (Array.isArray(result.content) ? result.content : [])
|
|
57
|
+
.filter(isRecord)
|
|
58
|
+
.map(blockContent);
|
|
59
|
+
if (blocks.length > 0)
|
|
60
|
+
return blocks;
|
|
61
|
+
if (result.structuredContent !== undefined && result.structuredContent !== null) {
|
|
62
|
+
return [{ type: "text", text: JSON.stringify(result.structuredContent) }];
|
|
63
|
+
}
|
|
64
|
+
return [{ type: "text", text: "(empty result)" }];
|
|
65
|
+
}
|
|
66
|
+
function parseJson(text) {
|
|
67
|
+
const trimmed = text.trimStart();
|
|
68
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("["))
|
|
69
|
+
return undefined;
|
|
70
|
+
try {
|
|
71
|
+
return { value: JSON.parse(text) };
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function digest(value, level, depth = 0) {
|
|
78
|
+
if (typeof value === "string") {
|
|
79
|
+
return value.length <= level.stringChars
|
|
80
|
+
? value
|
|
81
|
+
: `${value.slice(0, level.stringChars)}…[+${value.length - level.stringChars} chars]`;
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(value)) {
|
|
84
|
+
if (depth >= level.depth)
|
|
85
|
+
return `[…${value.length} items]`;
|
|
86
|
+
const kept = value.slice(0, level.arrayItems).map((item) => digest(item, level, depth + 1));
|
|
87
|
+
const hidden = value.length - kept.length;
|
|
88
|
+
return hidden > 0 ? [...kept, `…[+${hidden} more items]`] : kept;
|
|
89
|
+
}
|
|
90
|
+
if (isRecord(value)) {
|
|
91
|
+
if (depth >= level.depth)
|
|
92
|
+
return `{…${Object.keys(value).length} keys}`;
|
|
93
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, digest(item, level, depth + 1)]));
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
function fits(text, limits) {
|
|
98
|
+
return (Buffer.byteLength(text, "utf8") <= limits.maxBytes && text.split("\n").length <= limits.maxLines);
|
|
99
|
+
}
|
|
100
|
+
function sliceToBytes(text, maxBytes) {
|
|
101
|
+
const buffer = Buffer.from(text, "utf8");
|
|
102
|
+
if (buffer.length <= maxBytes)
|
|
103
|
+
return text;
|
|
104
|
+
let end = Math.max(0, maxBytes);
|
|
105
|
+
while (end > 0 && (buffer[end] & 0xc0) === 0x80)
|
|
106
|
+
end--;
|
|
107
|
+
return buffer.subarray(0, end).toString("utf8");
|
|
108
|
+
}
|
|
109
|
+
function headTruncate(text, limits) {
|
|
110
|
+
const truncation = truncateHead(text, limits);
|
|
111
|
+
return truncation.firstLineExceedsLimit
|
|
112
|
+
? sliceToBytes(text, limits.maxBytes)
|
|
113
|
+
: truncation.content;
|
|
114
|
+
}
|
|
115
|
+
export function boundMcpText(text, limits) {
|
|
116
|
+
const parsed = parseJson(text);
|
|
117
|
+
if (!parsed) {
|
|
118
|
+
return fits(text, limits)
|
|
119
|
+
? { text, truncated: false }
|
|
120
|
+
: { text: headTruncate(text, limits), truncated: true };
|
|
121
|
+
}
|
|
122
|
+
const compact = JSON.stringify(parsed.value);
|
|
123
|
+
if (fits(compact, limits))
|
|
124
|
+
return { text: compact, truncated: false };
|
|
125
|
+
for (const level of DIGEST_LEVELS) {
|
|
126
|
+
const digested = JSON.stringify(digest(parsed.value, level));
|
|
127
|
+
if (fits(digested, limits))
|
|
128
|
+
return { text: digested, truncated: true, digest: true };
|
|
129
|
+
}
|
|
130
|
+
const smallest = JSON.stringify(digest(parsed.value, DIGEST_LEVELS.at(-1)));
|
|
131
|
+
return { text: sliceToBytes(smallest, limits.maxBytes), truncated: true, digest: true };
|
|
132
|
+
}
|
|
133
|
+
function compactMcpText(text) {
|
|
134
|
+
const parsed = parseJson(text);
|
|
135
|
+
return parsed ? JSON.stringify(parsed.value) : text;
|
|
136
|
+
}
|
|
137
|
+
async function spillFullResult(env, text, extension, context) {
|
|
138
|
+
const path = await env.joinPath([env.cwd, ...SPILL_DIR, `${randomBytes(8).toString("hex")}.${extension}`], context);
|
|
139
|
+
if (!path.ok)
|
|
140
|
+
return undefined;
|
|
141
|
+
const written = await env.writeFile(path.value, redactSecrets(text), context);
|
|
142
|
+
return written.ok ? path.value : undefined;
|
|
143
|
+
}
|
|
144
|
+
function truncationNotice(bounded, totalBytes, spillPath) {
|
|
145
|
+
const view = bounded.digest
|
|
146
|
+
? `an abbreviated view of ${formatSize(totalBytes)}: long strings, arrays, and deep nesting are shortened; keys, counts, and pagination fields are kept`
|
|
147
|
+
: `the beginning of ${formatSize(totalBytes)}`;
|
|
148
|
+
const full = spillPath
|
|
149
|
+
? `Full result: ${spillPath} — use read with offset/limit or grep to inspect it`
|
|
150
|
+
: "The full result could not be saved";
|
|
151
|
+
return `[MCP result truncated: showing ${view}. ${full}, or re-query with filters or smaller pages.]`;
|
|
152
|
+
}
|
|
153
|
+
export async function guardMcpToolResult(result, env, context) {
|
|
154
|
+
const blocks = mcpResultContent(result).map((block) => block.type === "text" ? Object.assign(block, { text: compactMcpText(block.text) }) : block);
|
|
155
|
+
const texts = blocks.filter((block) => block.type === "text");
|
|
156
|
+
const images = blocks.filter((block) => block.type === "image");
|
|
157
|
+
const combined = texts.map((block) => block.text).join("\n");
|
|
158
|
+
if (result.isError) {
|
|
159
|
+
throw new Error(boundMcpText(combined, RESULT_LIMITS).text || "MCP tool call failed");
|
|
160
|
+
}
|
|
161
|
+
if (fits(combined, RESULT_LIMITS))
|
|
162
|
+
return { content: blocks, details: undefined };
|
|
163
|
+
const bounded = boundMcpText(combined, RESULT_LIMITS);
|
|
164
|
+
const spillPath = await spillFullResult(env, combined, bounded.digest ? "json" : "txt", context);
|
|
165
|
+
const notice = truncationNotice(bounded, Buffer.byteLength(combined, "utf8"), spillPath);
|
|
166
|
+
return {
|
|
167
|
+
content: [{ type: "text", text: `${bounded.text}\n\n${notice}` }, ...images],
|
|
168
|
+
details: undefined,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=mcp-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-result.js","sourceRoot":"","sources":["../../src/harness/mcp-result.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport {\n DEFAULT_MAX_BYTES,\n DEFAULT_MAX_LINES,\n formatSize,\n truncateHead,\n type AgentToolResult,\n type Context,\n type ExecutionEnv,\n} from \"@earendil-works/pi-agent-core\";\nimport { redactSecrets } from \"./tools/secret-redaction.js\";\n\nexport interface McpTextLimits {\n maxBytes: number;\n maxLines: number;\n}\n\nexport interface BoundedMcpText {\n text: string;\n truncated: boolean;\n digest?: true;\n}\n\nexport interface McpCallResult {\n content?: unknown;\n structuredContent?: unknown;\n isError?: boolean;\n}\n\nconst SPILL_DIR = [\".mikan\", \"mcp-output\"];\nconst NOTICE_RESERVE_BYTES = 640;\nconst NOTICE_RESERVE_LINES = 4;\nconst RESULT_LIMITS: McpTextLimits = {\n maxBytes: DEFAULT_MAX_BYTES - NOTICE_RESERVE_BYTES,\n maxLines: DEFAULT_MAX_LINES - NOTICE_RESERVE_LINES,\n};\n\ninterface DigestLevel {\n stringChars: number;\n arrayItems: number;\n depth: number;\n}\n\nconst DIGEST_LEVELS: readonly DigestLevel[] = [\n { stringChars: 200, arrayItems: 3, depth: 6 },\n { stringChars: 80, arrayItems: 2, depth: 4 },\n { stringChars: 40, arrayItems: 1, depth: 3 },\n { stringChars: 16, arrayItems: 1, depth: 2 },\n];\n\ntype RawBlock = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is RawBlock {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringField(block: RawBlock, key: string): string | undefined {\n const value = block[key];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction describeResource(resource: RawBlock): string {\n const uri = stringField(resource, \"uri\") ?? \"(no URI)\";\n const text = stringField(resource, \"text\");\n if (text !== undefined) return `[Resource: ${uri}]\\n${text}`;\n const blob = stringField(resource, \"blob\");\n const mimeType = stringField(resource, \"mimeType\") ?? \"unknown type\";\n const size = blob === undefined ? \"no content\" : `${Buffer.byteLength(blob, \"base64\")} bytes`;\n return `[Resource: ${uri} (${mimeType}, ${size}, binary content omitted)]`;\n}\n\nfunction blockContent(block: RawBlock): TextContent | ImageContent {\n const text = stringField(block, \"text\");\n if (block.type === \"text\" && text !== undefined) return { type: \"text\", text };\n const data = stringField(block, \"data\");\n const mimeType = stringField(block, \"mimeType\");\n if (block.type === \"image\" && data !== undefined && mimeType !== undefined) {\n return { type: \"image\", data, mimeType };\n }\n if (block.type === \"resource\" && isRecord(block.resource)) {\n return { type: \"text\", text: describeResource(block.resource) };\n }\n if (block.type === \"resource_link\") {\n const uri = stringField(block, \"uri\") ?? \"(no URI)\";\n return { type: \"text\", text: `[Resource link: ${stringField(block, \"name\") ?? uri}] ${uri}` };\n }\n if (block.type === \"audio\") {\n return { type: \"text\", text: `[Audio content omitted: ${mimeType ?? \"audio/*\"}]` };\n }\n return { type: \"text\", text: JSON.stringify(block) };\n}\n\nexport function mcpResultContent(result: McpCallResult): (TextContent | ImageContent)[] {\n const blocks = (Array.isArray(result.content) ? result.content : [])\n .filter(isRecord)\n .map(blockContent);\n if (blocks.length > 0) return blocks;\n if (result.structuredContent !== undefined && result.structuredContent !== null) {\n return [{ type: \"text\", text: JSON.stringify(result.structuredContent) }];\n }\n return [{ type: \"text\", text: \"(empty result)\" }];\n}\n\nfunction parseJson(text: string): { value: unknown } | undefined {\n const trimmed = text.trimStart();\n if (!trimmed.startsWith(\"{\") && !trimmed.startsWith(\"[\")) return undefined;\n try {\n return { value: JSON.parse(text) };\n } catch {\n return undefined;\n }\n}\n\nfunction digest(value: unknown, level: DigestLevel, depth = 0): unknown {\n if (typeof value === \"string\") {\n return value.length <= level.stringChars\n ? value\n : `${value.slice(0, level.stringChars)}…[+${value.length - level.stringChars} chars]`;\n }\n if (Array.isArray(value)) {\n if (depth >= level.depth) return `[…${value.length} items]`;\n const kept = value.slice(0, level.arrayItems).map((item) => digest(item, level, depth + 1));\n const hidden = value.length - kept.length;\n return hidden > 0 ? [...kept, `…[+${hidden} more items]`] : kept;\n }\n if (isRecord(value)) {\n if (depth >= level.depth) return `{…${Object.keys(value).length} keys}`;\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [key, digest(item, level, depth + 1)]),\n );\n }\n return value;\n}\n\nfunction fits(text: string, limits: McpTextLimits): boolean {\n return (\n Buffer.byteLength(text, \"utf8\") <= limits.maxBytes && text.split(\"\\n\").length <= limits.maxLines\n );\n}\n\nfunction sliceToBytes(text: string, maxBytes: number): string {\n const buffer = Buffer.from(text, \"utf8\");\n if (buffer.length <= maxBytes) return text;\n let end = Math.max(0, maxBytes);\n while (end > 0 && (buffer[end]! & 0xc0) === 0x80) end--;\n return buffer.subarray(0, end).toString(\"utf8\");\n}\n\nfunction headTruncate(text: string, limits: McpTextLimits): string {\n const truncation = truncateHead(text, limits);\n return truncation.firstLineExceedsLimit\n ? sliceToBytes(text, limits.maxBytes)\n : truncation.content;\n}\n\nexport function boundMcpText(text: string, limits: McpTextLimits): BoundedMcpText {\n const parsed = parseJson(text);\n if (!parsed) {\n return fits(text, limits)\n ? { text, truncated: false }\n : { text: headTruncate(text, limits), truncated: true };\n }\n const compact = JSON.stringify(parsed.value);\n if (fits(compact, limits)) return { text: compact, truncated: false };\n for (const level of DIGEST_LEVELS) {\n const digested = JSON.stringify(digest(parsed.value, level));\n if (fits(digested, limits)) return { text: digested, truncated: true, digest: true };\n }\n const smallest = JSON.stringify(digest(parsed.value, DIGEST_LEVELS.at(-1)!));\n return { text: sliceToBytes(smallest, limits.maxBytes), truncated: true, digest: true };\n}\n\nfunction compactMcpText(text: string): string {\n const parsed = parseJson(text);\n return parsed ? JSON.stringify(parsed.value) : text;\n}\n\nasync function spillFullResult(\n env: ExecutionEnv,\n text: string,\n extension: \"json\" | \"txt\",\n context: Context,\n): Promise<string | undefined> {\n const path = await env.joinPath(\n [env.cwd, ...SPILL_DIR, `${randomBytes(8).toString(\"hex\")}.${extension}`],\n context,\n );\n if (!path.ok) return undefined;\n const written = await env.writeFile(path.value, redactSecrets(text), context);\n return written.ok ? path.value : undefined;\n}\n\nfunction truncationNotice(\n bounded: BoundedMcpText,\n totalBytes: number,\n spillPath: string | undefined,\n): string {\n const view = bounded.digest\n ? `an abbreviated view of ${formatSize(totalBytes)}: long strings, arrays, and deep nesting are shortened; keys, counts, and pagination fields are kept`\n : `the beginning of ${formatSize(totalBytes)}`;\n const full = spillPath\n ? `Full result: ${spillPath} — use read with offset/limit or grep to inspect it`\n : \"The full result could not be saved\";\n return `[MCP result truncated: showing ${view}. ${full}, or re-query with filters or smaller pages.]`;\n}\n\nexport async function guardMcpToolResult(\n result: McpCallResult,\n env: ExecutionEnv,\n context: Context,\n): Promise<AgentToolResult<undefined>> {\n const blocks = mcpResultContent(result).map((block) =>\n block.type === \"text\" ? Object.assign(block, { text: compactMcpText(block.text) }) : block,\n );\n const texts = blocks.filter((block): block is TextContent => block.type === \"text\");\n const images = blocks.filter((block): block is ImageContent => block.type === \"image\");\n const combined = texts.map((block) => block.text).join(\"\\n\");\n if (result.isError) {\n throw new Error(boundMcpText(combined, RESULT_LIMITS).text || \"MCP tool call failed\");\n }\n if (fits(combined, RESULT_LIMITS)) return { content: blocks, details: undefined };\n const bounded = boundMcpText(combined, RESULT_LIMITS);\n const spillPath = await spillFullResult(env, combined, bounded.digest ? \"json\" : \"txt\", context);\n const notice = truncationNotice(bounded, Buffer.byteLength(combined, \"utf8\"), spillPath);\n return {\n content: [{ type: \"text\", text: `${bounded.text}\\n\\n${notice}` }, ...images],\n details: undefined,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/harness/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAEf,oBAAoB,EACpB,cAAc,EACf,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/harness/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAEf,oBAAoB,EACpB,cAAc,EACf,MAAM,YAAY,CAAC;AAgBpB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GAC/D;IAAE,OAAO,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAM3C,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CAwC5E;AAMD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOhD;AAmCD,wBAAgB,cAAc,IAAI,SAAS,SAAS,EAAE,CAErD;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAE/D;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,eAAe,CA2BjB;AACD,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAuEjD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,oBAAoB,EAAE,GAAG,MAAM,CAOxF;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EACxC,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,cAAc,CAAC,CA2CzB"}
|
package/dist/harness/mcp.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
2
|
import { StdioClientTransport, getDefaultEnvironment, } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
3
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
|
+
import { guardMcpToolResult } from "./mcp-result.js";
|
|
5
|
+
import { tagHarnessTool } from "./tools/pi-tools.js";
|
|
4
6
|
import * as log from "../log.js";
|
|
5
7
|
const SERVER_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
|
|
6
8
|
export function isValidMcpServerName(name) {
|
|
@@ -157,34 +159,6 @@ function buildTransport(name, config) {
|
|
|
157
159
|
}
|
|
158
160
|
throw new Error(`server "${name}" sets neither command nor url`);
|
|
159
161
|
}
|
|
160
|
-
function toAgentToolResult(result) {
|
|
161
|
-
const parts = Array.isArray(result.content) ? result.content : [];
|
|
162
|
-
const content = [];
|
|
163
|
-
for (const part of parts) {
|
|
164
|
-
if (part && typeof part === "object" && "type" in part) {
|
|
165
|
-
if (part.type === "text" && typeof part.text === "string") {
|
|
166
|
-
content.push({ type: "text", text: part.text });
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
if (part.type === "image" &&
|
|
170
|
-
typeof part.data === "string" &&
|
|
171
|
-
typeof part.mimeType === "string") {
|
|
172
|
-
const image = part;
|
|
173
|
-
content.push({ type: "image", data: image.data, mimeType: image.mimeType });
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
content.push({ type: "text", text: JSON.stringify(part) });
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (content.length === 0) {
|
|
180
|
-
content.push({ type: "text", text: "(empty result)" });
|
|
181
|
-
}
|
|
182
|
-
const text = content.map((c) => (c.type === "text" ? c.text : "")).join("\n");
|
|
183
|
-
if (result.isError) {
|
|
184
|
-
throw new Error(text || "MCP tool call failed");
|
|
185
|
-
}
|
|
186
|
-
return { content, details: undefined };
|
|
187
|
-
}
|
|
188
162
|
async function connectServer(name, config, signal) {
|
|
189
163
|
const client = new Client({ name: "mikan", version: "1.0.0" });
|
|
190
164
|
const transport = buildTransport(name, config);
|
|
@@ -197,14 +171,15 @@ async function connectServer(name, config, signal) {
|
|
|
197
171
|
timeout: CONNECT_TIMEOUT_MS,
|
|
198
172
|
...(signal ? { signal } : {}),
|
|
199
173
|
});
|
|
200
|
-
const tools = listed.tools.map((mcpTool) => ({
|
|
174
|
+
const tools = listed.tools.map((mcpTool) => tagHarnessTool({
|
|
201
175
|
name: `mcp__${name}__${mcpTool.name}`,
|
|
202
176
|
label: `${name}: ${mcpTool.name}`,
|
|
203
177
|
description: mcpTool.description ?? `${mcpTool.name} (MCP server "${name}")`,
|
|
204
178
|
parameters: mcpTool.inputSchema,
|
|
205
|
-
execute: async (
|
|
206
|
-
const
|
|
207
|
-
|
|
179
|
+
execute: async (...args) => {
|
|
180
|
+
const [, params, , toolContext, , context] = args;
|
|
181
|
+
const result = await client.callTool({ name: mcpTool.name, arguments: params }, undefined, { timeout: CALL_TIMEOUT_MS, signal: context.abortSignal });
|
|
182
|
+
return guardMcpToolResult(result, toolContext.env, context);
|
|
208
183
|
},
|
|
209
184
|
}));
|
|
210
185
|
const instructions = client.getInstructions()?.trim();
|