@zeroroot-ai/zerocool-claude 0.5.2 → 0.6.1

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.
Files changed (47) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/.mcp.json +1 -1
  3. package/dist/hook-run.js +2 -0
  4. package/dist/hook.js +2 -0
  5. package/dist/index.d.ts +1 -7
  6. package/dist/index.js +8 -8
  7. package/dist/state.d.ts +13 -10
  8. package/dist/state.js +6 -13
  9. package/hooks/hooks.json +4 -4
  10. package/hooks/zerocool-claude-hook.mjs +32 -0
  11. package/package.json +5 -9
  12. package/dist/ambient.d.ts +0 -7
  13. package/dist/ambient.js +0 -18
  14. package/dist/build.d.ts +0 -32
  15. package/dist/build.js +0 -218
  16. package/dist/claude-run.d.ts +0 -46
  17. package/dist/claude-run.js +0 -118
  18. package/dist/cli.d.ts +0 -88
  19. package/dist/cli.js +0 -186
  20. package/dist/config.d.ts +0 -44
  21. package/dist/config.js +0 -53
  22. package/dist/mode.d.ts +0 -32
  23. package/dist/mode.js +0 -21
  24. package/dist/sandbox-run.d.ts +0 -26
  25. package/dist/sandbox-run.js +0 -42
  26. package/dist/sandbox.d.ts +0 -2
  27. package/dist/sandbox.js +0 -30
  28. package/dist/server.d.ts +0 -2
  29. package/dist/server.js +0 -34
  30. package/dist/session.d.ts +0 -34
  31. package/dist/session.js +0 -142
  32. package/dist/tls.d.ts +0 -1
  33. package/dist/tls.js +0 -19
  34. package/dist/tools/componentize.d.ts +0 -18
  35. package/dist/tools/componentize.js +0 -80
  36. package/dist/tools/delegate.d.ts +0 -4
  37. package/dist/tools/delegate.js +0 -108
  38. package/dist/tools/findings.d.ts +0 -24
  39. package/dist/tools/findings.js +0 -104
  40. package/dist/tools/gibson-tools.d.ts +0 -20
  41. package/dist/tools/gibson-tools.js +0 -89
  42. package/dist/tools/memory.d.ts +0 -14
  43. package/dist/tools/memory.js +0 -96
  44. package/dist/tools/result.d.ts +0 -5
  45. package/dist/tools/result.js +0 -8
  46. package/dist/tools/status.d.ts +0 -5
  47. package/dist/tools/status.js +0 -21
package/dist/server.js DELETED
@@ -1,34 +0,0 @@
1
- #!/usr/bin/env node
2
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
- import { buildServer, log } from "./build.js";
4
- import { clearLive, stateDir } from "./state.js";
5
- import { describeGibson } from "./tools/status.js";
6
- /**
7
- * The MCP server bin. This file runs main() unconditionally: npm installs
8
- * bins as symlinks named after the bin (`zerocool-claude-mcp`), so any
9
- * "am I the entry point" check on argv[1] is false there and the process
10
- * exits before it serves anything. Library code lives in build.ts.
11
- */
12
- async function main() {
13
- const cwd = process.cwd();
14
- const surface = await buildServer(process.env, cwd);
15
- const { server } = surface;
16
- log(`[zerocool-claude] ${describeGibson(surface.current()).replaceAll("\n", "; ")}`);
17
- let closing = false;
18
- const close = async () => {
19
- if (closing)
20
- return;
21
- closing = true;
22
- await clearLive(stateDir(process.env), cwd).catch(() => { });
23
- await surface.current().close().catch((e) => log(`[zerocool-claude] close: ${e.message}`));
24
- };
25
- // Claude Code ends the session by closing stdio. The mission ends with it.
26
- process.stdin.on("close", () => void close().finally(() => process.exit(0)));
27
- for (const sig of ["SIGINT", "SIGTERM"])
28
- process.on(sig, () => void close().finally(() => process.exit(0)));
29
- await server.connect(new StdioServerTransport());
30
- }
31
- main().catch((e) => {
32
- log(`[zerocool-claude] fatal: ${e.message}`);
33
- process.exit(1);
34
- });
package/dist/session.d.ts DELETED
@@ -1,34 +0,0 @@
1
- import { connectGibson, startLiveMission, type GibsonSession, type KnowledgeSource, type LiveMission, type MissionOriginator } from "@zeroroot-ai/sdk";
2
- import type { Settings } from "./config.js";
3
- import { type Mode } from "./mode.js";
4
- export { DEFAULT_AGENT_NAME } from "./config.js";
5
- /** Everything the tools need, decided once per connect. */
6
- export interface Gibson {
7
- mode: Mode;
8
- reason: string;
9
- agentName: string;
10
- hostKeyPath: string;
11
- settings: Settings;
12
- session?: GibsonSession;
13
- live?: LiveMission;
14
- knowledge?: KnowledgeSource;
15
- /** Release the mission and the component registration. Idempotent. */
16
- close(): Promise<void>;
17
- }
18
- export interface OpenGibsonOptions {
19
- settings: Settings;
20
- log: (line: string) => void;
21
- /** The process environment, for the sandboxed-dispatch contract. */
22
- env?: NodeJS.ProcessEnv;
23
- /** Test seams. */
24
- connect?: typeof connectGibson;
25
- start?: typeof startLiveMission;
26
- originate?: MissionOriginator;
27
- hostKeyExists?: (path: string) => boolean;
28
- trust?: (path: string) => Promise<void>;
29
- }
30
- /**
31
- * Check in, then make the session a live mission. Fails open at every step:
32
- * a platform failure lands one posture down, never in a refusal to start.
33
- */
34
- export declare function openGibson(opts: OpenGibsonOptions): Promise<Gibson>;
package/dist/session.js DELETED
@@ -1,142 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { componentKnowledge, connectGibson, readSandboxDispatch, sandboxHarness, SANDBOX_ENV, startLiveMission, taskKnowledge, } from "@zeroroot-ai/sdk";
3
- import { submitMission } from "./cli.js";
4
- import { decideMode } from "./mode.js";
5
- import { trustCA } from "./tls.js";
6
- export { DEFAULT_AGENT_NAME } from "./config.js";
7
- /**
8
- * Check in, then make the session a live mission. Fails open at every step:
9
- * a platform failure lands one posture down, never in a refusal to start.
10
- */
11
- export async function openGibson(opts) {
12
- const { settings, log } = opts;
13
- const env = opts.env ?? {};
14
- if (env[SANDBOX_ENV.grant] && env[SANDBOX_ENV.callbackEndpoint]) {
15
- return openSandboxTask(env, settings, log, opts.trust);
16
- }
17
- const { hostKeyPath, agentName } = settings;
18
- const hostKeyExists = (opts.hostKeyExists ?? existsSync)(hostKeyPath);
19
- const decision = decideMode({ platformURL: settings.platformURL, bootstrapToken: settings.bootstrapToken, hostKeyExists, targetId: settings.targetId }, hostKeyPath);
20
- const standalone = (reason) => ({ mode: "standalone", reason, agentName, hostKeyPath, settings, close: async () => { } });
21
- if (decision.mode === "standalone") {
22
- log(`[zerocool-claude] standalone: ${decision.reason}`);
23
- return standalone(decision.reason);
24
- }
25
- if (settings.caCertPath) {
26
- try {
27
- await (opts.trust ?? trustCA)(settings.caCertPath);
28
- }
29
- catch (e) {
30
- log(`[zerocool-claude] CA at ${settings.caCertPath} not loaded: ${e.message}`);
31
- }
32
- }
33
- // The bootstrap token is passed ONLY when no host key exists yet. Replaying a
34
- // one-time token on every start would be rejected (gibson
35
- // capabilitygrant_register.go:134-155).
36
- const bootstrapToken = hostKeyExists ? undefined : settings.bootstrapToken;
37
- let session;
38
- try {
39
- session = await (opts.connect ?? connectGibson)({
40
- platformURL: settings.platformURL,
41
- daemonURL: settings.daemonURL,
42
- bootstrapToken,
43
- hostKeyPath,
44
- agentName,
45
- agentMode: "interactive",
46
- agent: { name: agentName, version: "0.0.0", capabilities: ["code"] },
47
- });
48
- }
49
- catch (e) {
50
- const reason = `Gibson connect failed: ${e.message}`;
51
- log(`[zerocool-claude] ${reason}; continuing standalone`);
52
- return standalone(reason);
53
- }
54
- log(`[zerocool-claude] checked in via ${hostKeyExists ? "the registered host key" : "first check-in"} ` +
55
- `as ${agentName} (component_scope=${session.componentScope})`);
56
- if (!hostKeyExists)
57
- log(`[zerocool-claude] host key written to ${hostKeyPath}; the bootstrap token is spent`);
58
- const component = {
59
- mode: "component",
60
- reason: decision.reason,
61
- agentName,
62
- hostKeyPath,
63
- settings,
64
- session,
65
- knowledge: componentKnowledge(session.clients.component),
66
- close: async () => session.stop(),
67
- };
68
- if (decision.mode === "component") {
69
- log(`[zerocool-claude] component posture: ${decision.reason}`);
70
- return component;
71
- }
72
- let live;
73
- try {
74
- live = await (opts.start ?? startLiveMission)(session, {
75
- agentName,
76
- targetId: settings.targetId,
77
- // The person originates the session mission through the CLI login
78
- // session; the component only claims its dispatch (gibson ADR-0063).
79
- originate: opts.originate ?? ((definition, targetId) => submitMission(definition, targetId)),
80
- harness: { insecure: settings.callbackInsecure },
81
- });
82
- }
83
- catch (e) {
84
- const reason = `live mission failed: ${e.message}`;
85
- log(`[zerocool-claude] ${reason}; continuing as a component`);
86
- return { ...component, reason };
87
- }
88
- log(`[zerocool-claude] live mission ${live.missionId} (work ${live.workId}); reads and writes use the task grant`);
89
- let closed = false;
90
- return {
91
- mode: "live",
92
- reason: "",
93
- agentName,
94
- hostKeyPath,
95
- settings,
96
- session,
97
- live,
98
- knowledge: taskKnowledge(live.harness),
99
- close: async () => {
100
- if (closed)
101
- return;
102
- closed = true;
103
- try {
104
- await live.end({ output: { ended: "session closed" } });
105
- }
106
- finally {
107
- session.stop();
108
- }
109
- },
110
- };
111
- }
112
- /**
113
- * The task posture: this process is a sandboxed dispatch. The launch already
114
- * decided everything; the plugin only opens the task harness from the grant
115
- * and serves the tools that run under it. No host key, no check-in, no
116
- * mission creation, and nothing to fail open to: a sandbox without a
117
- * usable grant has no reason to exist, so this throws.
118
- */
119
- async function openSandboxTask(env, settings, log, trust) {
120
- const d = readSandboxDispatch(env);
121
- if (settings.caCertPath)
122
- await (trust ?? trustCA)(settings.caCertPath).catch((e) => log(`[zerocool-claude] CA not loaded: ${e.message}`));
123
- const harness = sandboxHarness(d, { insecure: settings.callbackInsecure });
124
- const live = {
125
- missionId: d.missionId,
126
- workId: d.missionRunId,
127
- harness,
128
- // The sandbox reports completion by exiting; the launcher owns the node.
129
- end: async () => harness.stop(),
130
- };
131
- log(`[zerocool-claude] task posture: mission ${d.missionId} run ${d.missionRunId}; reads and writes use the dispatch grant`);
132
- return {
133
- mode: "task",
134
- reason: "",
135
- agentName: settings.agentName,
136
- hostKeyPath: settings.hostKeyPath,
137
- settings,
138
- live,
139
- knowledge: taskKnowledge(harness),
140
- close: async () => harness.stop(),
141
- };
142
- }
package/dist/tls.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function trustCA(path: string): Promise<void>;
package/dist/tls.js DELETED
@@ -1,19 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import tls from "node:tls";
3
- /**
4
- * Trust a private CA for every TLS client in this process, at runtime.
5
- *
6
- * A self-hosted Gibson (kind, on-prem) fronts its edge with its own CA. Node
7
- * reads NODE_EXTRA_CA_CERTS only at start, and the connect happens mid-session,
8
- * so the CA is added through `tls.setDefaultCACertificates` (Node 22.15+).
9
- * Both `fetch` (the Capability Grant register call) and the gRPC transports
10
- * use the default CA set, so one call covers all of them.
11
- */
12
- const trusted = new Set();
13
- export async function trustCA(path) {
14
- if (trusted.has(path))
15
- return;
16
- const pem = await readFile(path, "utf8");
17
- tls.setDefaultCACertificates([...tls.getCACertificates("default"), pem]);
18
- trusted.add(path);
19
- }
@@ -1,18 +0,0 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { type ComponentSpec, type GibsonSession } from "@zeroroot-ai/sdk";
3
- type SpecArgs = {
4
- kind: string;
5
- name: string;
6
- version: string;
7
- image?: string;
8
- language?: string;
9
- capabilities?: string[];
10
- methods?: string[];
11
- input_message_type?: string;
12
- output_message_type?: string;
13
- config_schema_json?: string;
14
- };
15
- export declare function toSpec(args: SpecArgs): ComponentSpec;
16
- export declare function registerComponentizeTool(server: McpServer, cwd: string): void;
17
- export declare function registerEnrollTool(server: McpServer, session: GibsonSession): void;
18
- export {};
@@ -1,80 +0,0 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
- import { dirname, resolve } from "node:path";
3
- import { buildComponentManifest, enrollComponent, enrollmentSupported, validateComponentSpec, } from "@zeroroot-ai/sdk";
4
- import { z } from "zod";
5
- import { failure, text } from "./result.js";
6
- /** Componentize and enroll (zerocool-plugins#11): produced artifacts join the fleet. */
7
- const KINDS = ["agent", "tool", "plugin"];
8
- const specSchema = {
9
- kind: z.enum(KINDS).describe("Component kind."),
10
- name: z.string().describe("Component name, as it will appear in the tenant registry."),
11
- version: z.string().describe('Semantic version of the artifact, e.g. "0.1.0".'),
12
- image: z.string().optional().describe("OCI image reference of the built artifact. Required before it can be dispatched."),
13
- language: z.string().optional().describe("Language the artifact is written in, for the catalog."),
14
- capabilities: z.array(z.string()).optional().describe('Agent capabilities. Required when kind is "agent".'),
15
- methods: z.array(z.string()).optional().describe('Plugin method names. Required when kind is "plugin".'),
16
- input_message_type: z.string().optional().describe('Fully-qualified proto input type. Required when kind is "tool".'),
17
- output_message_type: z.string().optional().describe('Fully-qualified proto output type. Required when kind is "tool".'),
18
- config_schema_json: z.string().optional().describe("JSON Schema for a plugin's configuration."),
19
- };
20
- export function toSpec(args) {
21
- const metadata = {};
22
- if (args.image)
23
- metadata.image = args.image;
24
- if (args.language)
25
- metadata.language = args.language;
26
- return {
27
- kind: args.kind,
28
- name: args.name,
29
- version: args.version,
30
- metadata,
31
- ...(args.capabilities ? { capabilities: args.capabilities } : {}),
32
- ...(args.methods ? { methods: args.methods } : {}),
33
- ...(args.input_message_type ? { inputMessageType: args.input_message_type } : {}),
34
- ...(args.output_message_type ? { outputMessageType: args.output_message_type } : {}),
35
- ...(args.config_schema_json ? { configSchemaJson: args.config_schema_json } : {}),
36
- };
37
- }
38
- function invalid(spec, problems) {
39
- return failure("invalid component spec", `This artifact does not satisfy Gibson's ${spec.kind} contract:\n${problems.map((p) => `- ${p}`).join("\n")}`);
40
- }
41
- export function registerComponentizeTool(server, cwd) {
42
- server.registerTool("gibson_componentize", {
43
- description: "Turn a built artifact into a Gibson component manifest and write it to disk. Use this after " +
44
- "building a tool or agent you want to add to the fleet. Validates the artifact against " +
45
- "Gibson's component contract. Does not build or push an image.",
46
- inputSchema: { ...specSchema, path: z.string().optional().describe('Where to write the manifest. Defaults to "gibson-component.json".') },
47
- }, async (args) => {
48
- const spec = toSpec(args);
49
- const problems = validateComponentSpec(spec);
50
- if (problems.length > 0)
51
- return invalid(spec, problems);
52
- const manifest = buildComponentManifest(spec);
53
- const target = resolve(cwd, args.path ?? "gibson-component.json");
54
- await mkdir(dirname(target), { recursive: true });
55
- await writeFile(target, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
56
- const missingImage = spec.metadata?.image
57
- ? ""
58
- : "\n\nNo image reference was given. Build and push an image, then re-run with image=<oci-ref> before you enroll. A component without an image cannot be dispatched.";
59
- return text(`${spec.kind} manifest: ${spec.name}`, `Wrote a valid ${spec.kind} manifest for ${spec.name}@${spec.version} to ${target}.${missingImage}`);
60
- });
61
- }
62
- export function registerEnrollTool(server, session) {
63
- server.registerTool("gibson_enroll_component", {
64
- description: "Register a produced artifact with Gibson so it joins the tenant fleet. Run gibson_componentize first to check the artifact against the component contract.",
65
- inputSchema: specSchema,
66
- }, async (args) => {
67
- const spec = toSpec(args);
68
- const problems = validateComponentSpec(spec);
69
- if (problems.length > 0)
70
- return invalid(spec, problems);
71
- try {
72
- const result = await enrollComponent(session.clients.component, spec);
73
- const { reason } = enrollmentSupported();
74
- return text(`enrolled ${spec.name}`, `Registered ${spec.kind} ${spec.name}@${spec.version} as instance ${result.instanceId}.\n\nNote: ${reason}. It is visible in the tenant registry, but it drops out when heartbeats stop (every ${Math.round(result.heartbeatIntervalMs / 1000)}s) unless the artifact itself runs and checks in.`);
75
- }
76
- catch (e) {
77
- return failure("enroll failed", e.message);
78
- }
79
- });
80
- }
@@ -1,4 +0,0 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { type GibsonSession } from "@zeroroot-ai/sdk";
3
- /** Delegation and missions (zerocool-plugins#10): the network of agents in the tenant. */
4
- export declare function registerDelegationTools(server: McpServer, session: GibsonSession): void;
@@ -1,108 +0,0 @@
1
- import { cancelMission, createMission, delegateToAgent, getMissionResults, getMissionStatus, isSeamUnavailable, listAgents, newTask, runMission, waitMission, } from "@zeroroot-ai/sdk";
2
- import { z } from "zod";
3
- import { failure, text } from "./result.js";
4
- const UNWIRED = "This daemon has no agent delegation or mission management wired (gibson#1186). Complete the work directly instead.";
5
- /** Delegation and missions (zerocool-plugins#10): the network of agents in the tenant. */
6
- export function registerDelegationTools(server, session) {
7
- const component = session.clients.component;
8
- const seam = (e, what) => (isSeamUnavailable(e) ? text(`${what} unavailable`, UNWIRED) : failure(`${what} failed`, e.message));
9
- server.registerTool("gibson_list_agents", {
10
- description: "List the Gibson agents in this tenant that work can be delegated to, with their capabilities and the target types they handle.",
11
- inputSchema: {},
12
- }, async () => {
13
- const { agents, unavailable } = await listAgents(component);
14
- if (unavailable)
15
- return text("delegation unavailable", UNWIRED);
16
- if (agents.length === 0)
17
- return text("no agents", "No agents are registered for this tenant.");
18
- const lines = agents.map((a) => {
19
- const caps = a.capabilities.length > 0 ? `, capabilities: ${a.capabilities.join(", ")}` : "";
20
- const targets = a.targetTypes.length > 0 ? `, targets: ${a.targetTypes.join(", ")}` : "";
21
- return `- ${a.name} (${a.version}) ${a.description}${caps}${targets}`;
22
- });
23
- return text(`${agents.length} agent${agents.length === 1 ? "" : "s"}`, lines.join("\n"));
24
- });
25
- server.registerTool("gibson_delegate", {
26
- description: "Delegate a sub-task to another Gibson agent and wait for its result. Use gibson_list_agents " +
27
- "first to pick an agent whose capabilities match the task.",
28
- inputSchema: {
29
- agent: z.string().describe("Name of the agent to delegate to."),
30
- goal: z.string().describe("What the delegate should accomplish."),
31
- context: z.record(z.string(), z.any()).optional().describe("Target details, prior findings, or other context the delegate needs."),
32
- max_turns: z.number().optional().describe("Cap on the delegate's LLM turns."),
33
- allowed_tools: z.array(z.string()).optional().describe("Restrict the delegate to these tools."),
34
- },
35
- }, async (args) => {
36
- try {
37
- const task = newTask(args.goal, {
38
- ...(args.context ? { Context: args.context } : {}),
39
- ...(args.max_turns || args.allowed_tools
40
- ? { Constraints: { ...(args.max_turns ? { MaxTurns: args.max_turns } : {}), ...(args.allowed_tools ? { AllowedTools: args.allowed_tools } : {}) } }
41
- : {}),
42
- });
43
- const result = await delegateToAgent(component, args.agent, task);
44
- return text(`${args.agent}: ${result.Status}`, JSON.stringify(result, null, 2));
45
- }
46
- catch (e) {
47
- return seam(e, "delegation");
48
- }
49
- });
50
- server.registerTool("gibson_create_mission", {
51
- description: "Create a Gibson mission from a mission definition, bound to a target. The mission is not started. Call gibson_run_mission to queue it.",
52
- inputSchema: {
53
- definition: z.record(z.string(), z.any()).describe("Mission definition object (gibson.mission.v1.MissionDefinition as JSON)."),
54
- target_id: z.string().describe("Identifier of the target the mission runs against."),
55
- opts: z.record(z.string(), z.any()).optional().describe("Optional mission creation options."),
56
- },
57
- }, async (args) => {
58
- try {
59
- const info = await createMission(component, args.definition, args.target_id, args.opts);
60
- return text("mission created", JSON.stringify(info, null, 2));
61
- }
62
- catch (e) {
63
- return seam(e, "create mission");
64
- }
65
- });
66
- server.registerTool("gibson_run_mission", { description: "Queue a created Gibson mission for execution. Returns as soon as it is queued.", inputSchema: { mission_id: z.string().describe("Mission to run.") } }, async (args) => {
67
- try {
68
- await runMission(component, args.mission_id);
69
- return text("queued", `Mission ${args.mission_id} is queued.`);
70
- }
71
- catch (e) {
72
- return seam(e, "run mission");
73
- }
74
- });
75
- server.registerTool("gibson_mission_status", {
76
- description: "Check a Gibson mission's status, or block until it finishes. Use wait=true only when you intend to stop and wait for the result.",
77
- inputSchema: {
78
- mission_id: z.string().describe("Mission to inspect."),
79
- wait: z.boolean().optional().describe("Block until the mission reaches a terminal state."),
80
- timeout_ms: z.number().optional().describe("How long to block when wait is true. Defaults to 5 minutes."),
81
- },
82
- }, async (args) => {
83
- try {
84
- const status = args.wait ? await waitMission(component, args.mission_id, args.timeout_ms) : await getMissionStatus(component, args.mission_id);
85
- return text(`mission ${args.mission_id}`, JSON.stringify(status, null, 2));
86
- }
87
- catch (e) {
88
- return seam(e, "mission status");
89
- }
90
- });
91
- server.registerTool("gibson_mission_results", { description: "Read the final results of a completed Gibson mission.", inputSchema: { mission_id: z.string().describe("Mission whose results to read.") } }, async (args) => {
92
- try {
93
- return text(`results ${args.mission_id}`, JSON.stringify(await getMissionResults(component, args.mission_id), null, 2));
94
- }
95
- catch (e) {
96
- return seam(e, "mission results");
97
- }
98
- });
99
- server.registerTool("gibson_cancel_mission", { description: "Request cancellation of a running Gibson mission.", inputSchema: { mission_id: z.string().describe("Mission to cancel.") } }, async (args) => {
100
- try {
101
- await cancelMission(component, args.mission_id);
102
- return text("cancel requested", `Cancellation of ${args.mission_id} is requested.`);
103
- }
104
- catch (e) {
105
- return seam(e, "cancel mission");
106
- }
107
- });
108
- }
@@ -1,24 +0,0 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { type Finding, type TaskHarness } from "@zeroroot-ai/sdk";
3
- import type { Gibson } from "../session.js";
4
- export interface FindingsBackend {
5
- submit(f: Finding): Promise<string>;
6
- describe(): string;
7
- }
8
- /** Platform backend: the finding lands in the tenant knowledge graph. */
9
- export declare function gibsonFindingsBackend(g: Gibson): FindingsBackend;
10
- /**
11
- * Task backend: the callback service's typed SubmitFinding, under the
12
- * dispatch grant. Fields map from the SDK's JSON finding onto
13
- * gibson.types.v1.Finding; the daemon assigns the id and the mission.
14
- */
15
- export declare function taskFindingsBackend(harness: TaskHarness): FindingsBackend;
16
- /** Standalone backend: an append-only JSONL log. */
17
- export declare function localFindingsBackend(path: string): FindingsBackend;
18
- /**
19
- * Findings: emit what the agent discovers (zerocool-plugins#7). The model
20
- * calls this when it finds something. Nothing here emits on its own: a file
21
- * edit is not a security finding, and inventing one fills the tenant graph
22
- * with noise a person then has to triage.
23
- */
24
- export declare function registerFindingTools(server: McpServer, g: Gibson, backend: FindingsBackend): void;
@@ -1,104 +0,0 @@
1
- import { appendFile, mkdir } from "node:fs/promises";
2
- import { dirname } from "node:path";
3
- import { newFinding, submitFinding } from "@zeroroot-ai/sdk";
4
- import { z } from "zod";
5
- import { failure, text } from "./result.js";
6
- const SEVERITIES = ["critical", "high", "medium", "low", "info"];
7
- /** Platform backend: the finding lands in the tenant knowledge graph. */
8
- export function gibsonFindingsBackend(g) {
9
- const component = g.session.clients.component;
10
- return { submit: (f) => submitFinding(component, f), describe: () => "the tenant Gibson graph" };
11
- }
12
- /**
13
- * Task backend: the callback service's typed SubmitFinding, under the
14
- * dispatch grant. Fields map from the SDK's JSON finding onto
15
- * gibson.types.v1.Finding; the daemon assigns the id and the mission.
16
- */
17
- export function taskFindingsBackend(harness) {
18
- const severity = (s) => ({ critical: 1, high: 2, medium: 3, low: 4, info: 5 })[s] ?? 0;
19
- return {
20
- submit: async (f) => {
21
- const res = await harness.client.submitFinding({
22
- context: harness.context,
23
- finding: {
24
- id: f.id,
25
- missionId: f.mission_id,
26
- agentName: f.agent_name,
27
- title: f.title,
28
- description: f.description,
29
- category: f.category,
30
- severity: severity(f.severity),
31
- confidence: f.confidence,
32
- remediation: f.remediation ?? "",
33
- targetId: f.target_id ?? "",
34
- tags: f.tags ?? [],
35
- evidence: (f.evidence ?? []).map((e) => ({ type: e.type, title: e.title, content: e.content })),
36
- },
37
- });
38
- if (res.error)
39
- throw new Error(`SubmitFinding refused: ${res.error.message}`);
40
- // The callback acknowledges without an id; the finding keeps the one
41
- // newFinding minted, which is what the daemon stored.
42
- return f.id;
43
- },
44
- describe: () => "the tenant Gibson graph (dispatch grant)",
45
- };
46
- }
47
- /** Standalone backend: an append-only JSONL log. */
48
- export function localFindingsBackend(path) {
49
- return {
50
- submit: async (f) => {
51
- await mkdir(dirname(path), { recursive: true });
52
- await appendFile(path, `${JSON.stringify(f)}\n`, "utf8");
53
- return f.id;
54
- },
55
- describe: () => path,
56
- };
57
- }
58
- /**
59
- * Findings: emit what the agent discovers (zerocool-plugins#7). The model
60
- * calls this when it finds something. Nothing here emits on its own: a file
61
- * edit is not a security finding, and inventing one fills the tenant graph
62
- * with noise a person then has to triage.
63
- */
64
- export function registerFindingTools(server, g, backend) {
65
- server.registerTool("submit_finding", {
66
- description: "Record a security finding in the Gibson knowledge graph. Use this when you discover a " +
67
- "real vulnerability, misconfiguration or notable security fact about the target or " +
68
- "codebase. Not for progress updates or general observations.",
69
- inputSchema: {
70
- title: z.string().describe("One-line summary of the finding."),
71
- description: z.string().describe("What the issue is, where it is, and why it matters."),
72
- category: z.string().describe('Type of issue, e.g. "injection", "auth", "secrets-exposure", "misconfiguration".'),
73
- severity: z.enum(SEVERITIES).describe("Impact level of the finding."),
74
- confidence: z.number().min(0).max(1).optional().describe("How certain you are, from 0 to 1. Defaults to 1."),
75
- evidence: z.string().optional().describe("A code excerpt, request/response, or log line."),
76
- remediation: z.string().optional().describe("How to fix or mitigate the issue."),
77
- target_id: z.string().optional().describe("Identifier of the affected target or component."),
78
- tags: z.array(z.string()).optional().describe("Labels for filtering."),
79
- },
80
- }, async (args) => {
81
- const finding = newFinding({
82
- title: args.title,
83
- description: args.description,
84
- category: args.category,
85
- severity: args.severity,
86
- confidence: args.confidence,
87
- missionID: g.live?.missionId ?? "",
88
- agentName: g.agentName,
89
- ...(args.remediation ? { remediation: args.remediation } : {}),
90
- ...(args.target_id ? { targetID: args.target_id } : {}),
91
- ...(args.tags ? { tags: args.tags } : {}),
92
- ...(args.evidence
93
- ? { evidence: [{ type: "text", title: "evidence", content: args.evidence, timestamp: new Date().toISOString() }] }
94
- : {}),
95
- });
96
- try {
97
- const id = await backend.submit(finding);
98
- return text(`${args.severity}: ${args.title}`, `Recorded finding ${id} in ${backend.describe()}.`);
99
- }
100
- catch (e) {
101
- return failure("submit_finding failed", e.message);
102
- }
103
- });
104
- }
@@ -1,20 +0,0 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { type GibsonSession, type GibsonTool } from "@zeroroot-ai/sdk";
3
- /**
4
- * Gibson tools and plugins as MCP tools (zerocool-plugins#9).
5
- *
6
- * Discovered tools register individually, one MCP tool per Gibson tool, named
7
- * `gibson_<tool>`, so the model sees each with its own description. The
8
- * catalog carries no JSON Schema, only a proto message type name, so a wrapper
9
- * takes one free-form `input` object and names the expected type. A generic
10
- * `gibson_call_tool` is always present: discovery is `Unimplemented` on some
11
- * daemons (gibson#1186), and the operator may know a tool by name.
12
- */
13
- export declare function toolKey(name: string): string;
14
- export declare function registerDiscoveredTool(server: McpServer, session: GibsonSession, t: GibsonTool): void;
15
- export interface DiscoveryOutcome {
16
- discovered: number;
17
- note?: string;
18
- }
19
- /** Register the generic tools, then one tool per discovered Gibson tool. */
20
- export declare function registerGibsonTools(server: McpServer, session: GibsonSession): Promise<DiscoveryOutcome>;