@zeroroot-ai/zerocool 0.8.0 → 0.9.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.
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
1
3
  import { decodeToolInput } from "@zeroroot-ai/sdk";
2
4
  export const HTTP_PROBE_TIMEOUT_MS = 15_000;
3
5
  /** Perform the probe. Exported separately from the handler so it is testable without a work item. */
package/dist/index.d.ts CHANGED
@@ -20,11 +20,17 @@ import type { Plugin } from "@opencode-ai/plugin";
20
20
  * - checks in as a Gibson component (Capability Grant + RegisterComponent + heartbeat),
21
21
  * - starts a local OpenAI-compatible shim over the harness,
22
22
  * - auto-registers a zero-config `gibson` provider via the `config` hook (#6),
23
- * - emits findings into the tenant World (#7),
24
- * - reads the tenant knowledge graph (#8),
25
- * - exposes Gibson tools and plugins as opencode tools (#9),
26
- * - delegates to other agents and drives missions (#10),
27
- * - enrolls produced artifacts into the fleet (#11).
23
+ * - reads the tenant knowledge graph and injects an ambient block (#8).
24
+ *
25
+ * THE TOOLS ARE NOT HERE. Every Gibson tool — findings, knowledge, delegation,
26
+ * componentize, and one per RPC of every SDK service — comes from the Gibson
27
+ * MCP server, which this plugin registers in opencode's own `mcp` block
28
+ * (ADR-0008). opencode spawns it, so the tools reach the model the same way
29
+ * they reach Claude Code, Cursor and the rest, and a new SDK release adds
30
+ * tools with no change here.
31
+ *
32
+ * What is left is what only a plugin can do: the model provider, the ambient
33
+ * knowledge injection, and the session id.
28
34
  *
29
35
  * The plugin fails open throughout. A coding agent that cannot reach its
30
36
  * platform must still be a working coding agent, so every platform failure
package/dist/index.js CHANGED
@@ -1,13 +1,12 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
1
3
  import { connectGibson, startCompletionsShim } from "@zeroroot-ai/sdk";
2
4
  import { existsSync } from "node:fs";
3
5
  import { homedir } from "node:os";
4
6
  import { join } from "node:path";
5
- import { componentizeTool, enrollComponentTool } from "./componentize.js";
6
- import { delegationTools } from "./delegate.js";
7
- import { buildGibsonTools } from "./gibson-tools.js";
8
- import { ambientKnowledge, recallTool } from "./knowledge.js";
7
+ import { ambientKnowledge } from "./knowledge.js";
9
8
  import { selectKnowledgeSource } from "./knowledge-source.js";
10
- import { gibsonFindingsBackend, localFindingsBackend, submitFindingTool, } from "./findings.js";
9
+ import { gibsonMcpServer } from "./mcp-config.js";
11
10
  /**
12
11
  * @zeroroot-ai/zerocool — the main Gibson plugin.
13
12
  *
@@ -29,11 +28,17 @@ import { gibsonFindingsBackend, localFindingsBackend, submitFindingTool, } from
29
28
  * - checks in as a Gibson component (Capability Grant + RegisterComponent + heartbeat),
30
29
  * - starts a local OpenAI-compatible shim over the harness,
31
30
  * - auto-registers a zero-config `gibson` provider via the `config` hook (#6),
32
- * - emits findings into the tenant World (#7),
33
- * - reads the tenant knowledge graph (#8),
34
- * - exposes Gibson tools and plugins as opencode tools (#9),
35
- * - delegates to other agents and drives missions (#10),
36
- * - enrolls produced artifacts into the fleet (#11).
31
+ * - reads the tenant knowledge graph and injects an ambient block (#8).
32
+ *
33
+ * THE TOOLS ARE NOT HERE. Every Gibson tool — findings, knowledge, delegation,
34
+ * componentize, and one per RPC of every SDK service — comes from the Gibson
35
+ * MCP server, which this plugin registers in opencode's own `mcp` block
36
+ * (ADR-0008). opencode spawns it, so the tools reach the model the same way
37
+ * they reach Claude Code, Cursor and the rest, and a new SDK release adds
38
+ * tools with no change here.
39
+ *
40
+ * What is left is what only a plugin can do: the model provider, the ambient
41
+ * knowledge injection, and the session id.
37
42
  *
38
43
  * The plugin fails open throughout. A coding agent that cannot reach its
39
44
  * platform must still be a working coding agent, so every platform failure
@@ -57,12 +62,11 @@ export const GibsonPlugin = async () => {
57
62
  // the operator to keep a spent credential in their environment forever.
58
63
  const checkedIn = existsSync(hostKeyPath);
59
64
  const bootstrapToken = checkedIn ? undefined : process.env.GIBSON_BOOTSTRAP_TOKEN;
60
- // Standalone: findings go to a local log, and componentize still works —
61
- // producing a manifest needs no platform.
62
- const standaloneTools = () => ({
63
- submit_finding: submitFindingTool(localFindingsBackend(process.env.ZEROCOOL_FINDINGS_LOG ?? join(homedir(), ".zerocool", "findings.jsonl")), context),
64
- gibson_componentize: componentizeTool(),
65
- });
65
+ // Standalone: the MCP server still runs. It decides its own posture from
66
+ // what is present, reports it through gibson_status, and offers the tools
67
+ // that need no platform. A coding agent that cannot reach Gibson is still a
68
+ // working coding agent.
69
+ const standalone = () => ({ config: async (config) => addMcpServer(config) });
66
70
  // Standalone unless we can authenticate: a platform URL plus either a token
67
71
  // for the first check-in or an already-registered host key.
68
72
  if (!platformURL || (!bootstrapToken && !checkedIn)) {
@@ -72,7 +76,7 @@ export const GibsonPlugin = async () => {
72
76
  "GIBSON_BOOTSTRAP_TOKEN=<one-time token>. After that the host key at " +
73
77
  `${hostKeyPath} is enough — you can drop the token.`);
74
78
  }
75
- return { tool: standaloneTools() };
79
+ return standalone();
76
80
  }
77
81
  let session;
78
82
  let shim;
@@ -102,34 +106,19 @@ export const GibsonPlugin = async () => {
102
106
  // Fail open to standalone: a coding agent must still work if the platform is unreachable.
103
107
  console.error(`[zerocool] Gibson connect failed; continuing standalone: ${e.message}`);
104
108
  await shim?.close();
105
- return { tool: standaloneTools() };
109
+ return standalone();
106
110
  }
107
111
  const shimUrl = shim.url;
108
112
  const live = session;
109
- // Tool discovery runs once at load — opencode reads the `tool` hook as a
110
- // static object, so a tool registered mid-session would never reach the model.
111
113
  // Which grant this process reads the knowledge graph with. A dispatched run
112
114
  // reads as the TASK; an interactive one keeps the component grant. Chosen once
113
115
  // here so nothing downstream has to ask.
114
- const { knowledge, scope: knowledgeScope } = selectKnowledgeSource(live);
116
+ const { knowledge, scope: knowledgeScope, stop: stopKnowledge } = selectKnowledgeSource(live);
115
117
  console.error(`[zerocool] knowledge reads use the ${knowledgeScope} grant`);
116
- const gibson = await buildGibsonTools(live);
117
- if (gibson.note)
118
- console.error(`[zerocool] Gibson tool discovery: ${gibson.note}`);
119
- else
120
- console.error(`[zerocool] ${gibson.discovered} Gibson tool(s) registered`);
121
- const tools = {
122
- submit_finding: submitFindingTool(gibsonFindingsBackend(live), context),
123
- recall: recallTool(knowledge),
124
- gibson_componentize: componentizeTool(),
125
- gibson_enroll_component: enrollComponentTool(live),
126
- ...gibson.tools,
127
- ...delegationTools(live),
128
- };
129
118
  const injectKnowledge = ambientKnowledge(knowledge, process.env.ZEROCOOL_AMBIENT_QUERY ?? "prior findings and security facts for this codebase");
130
119
  return {
131
- tool: tools,
132
- // Zero-config LLM: inject the Gibson provider at config-load time (#6).
120
+ // Zero-config LLM, and the one tool surface: inject both at config-load
121
+ // time (#6, ADR-0008).
133
122
  //
134
123
  // `shimUrl` is always live here, and that is a type-level guarantee rather
135
124
  // than a timing assumption: `Plugin` returns `Promise<Hooks>`, so opencode
@@ -146,22 +135,33 @@ export const GibsonPlugin = async () => {
146
135
  options: { baseURL: shimUrl, apiKey: "gibson" },
147
136
  };
148
137
  }
138
+ addMcpServer(config);
149
139
  },
150
140
  // Ambient knowledge (#8): one cached GraphRAG lookup per session, injected
151
141
  // into the system prompt from the second turn on.
152
142
  "experimental.chat.system.transform": injectKnowledge,
153
- // Track the session so findings carry provenance (#7). This hook does not
154
- // emit findings: a file edit is not a security finding, and inventing one
155
- // would fill the tenant graph with noise a human then has to triage.
143
+ // Track the session id, which the ambient block and any local state key
144
+ // off. This hook emits nothing: a file edit is not a security finding, and
145
+ // inventing one would fill the tenant graph with noise a human must triage.
156
146
  event: async ({ event }) => {
157
147
  const sessionID = event.properties?.sessionID;
158
148
  if (sessionID)
159
149
  context.sessionID = sessionID;
160
150
  },
161
151
  dispose: async () => {
152
+ // A task-scoped source holds a grant-renewal timer. Leaving it running
153
+ // would keep renewing a grant for a session that has ended.
154
+ stopKnowledge();
162
155
  session?.stop();
163
156
  await shim?.close();
164
157
  },
165
158
  };
166
159
  };
160
+ /** Register the Gibson MCP server in opencode's own `mcp` block. */
161
+ function addMcpServer(config) {
162
+ const cfg = config;
163
+ cfg.mcp = cfg.mcp ?? {};
164
+ if (!cfg.mcp.gibson)
165
+ cfg.mcp.gibson = gibsonMcpServer();
166
+ }
167
167
  export default GibsonPlugin;
@@ -1,12 +1,35 @@
1
- import { type GibsonSession, type KnowledgeSource } from "@zeroroot-ai/sdk";
1
+ import { type GibsonSession, type KnowledgeSource, type OpenTaskHarnessOptions, type TaskHarness } from "@zeroroot-ai/sdk";
2
+ /** The chosen knowledge source, and the way to release what it opened. */
3
+ export interface SelectedKnowledge {
4
+ knowledge: KnowledgeSource;
5
+ scope: "task" | "component";
6
+ /**
7
+ * Release the task harness. Safe to call on either scope, and safe to call
8
+ * twice. A component-scoped run opens nothing, so this does nothing.
9
+ */
10
+ stop: () => void;
11
+ }
12
+ /** Seams, so a test can read what a dispatched run actually sends. */
13
+ export interface KnowledgeSourceDeps {
14
+ /** Opens the task harness. Defaults to `openTaskHarness` on the dispatch grant. */
15
+ openHarness?: (opts: OpenTaskHarnessOptions) => TaskHarness;
16
+ }
2
17
  /**
3
18
  * Pick the grant this process should read the knowledge graph with.
4
19
  *
5
20
  * A DISPATCHED run must read as the TASK, not as the component. gibson mints a
6
- * per-dispatch capability grant and `zerocool-agent` passes it to the child as
7
- * GIBSON_CALLBACK_ENDPOINT / GIBSON_CALLBACK_TOKEN. Reading with the component's
8
- * own grant instead is broader authority than the dispatch intended and leaves
9
- * no per-task attribution on anything the run reads — the gap ADR-0006 recorded.
21
+ * per-dispatch capability grant, and the driver passes it to this opencode
22
+ * child as GIBSON_CALLBACK_ENDPOINT / GIBSON_CALLBACK_TOKEN. Reading with the
23
+ * component's own grant instead is broader authority than the dispatch
24
+ * intended and leaves no per-task attribution on anything the run reads — the
25
+ * gap ADR-0006 recorded.
26
+ *
27
+ * THESE TWO NAMES ARE THE CHILD CONTRACT, NOT THE LAUNCHER CONTRACT. The
28
+ * launcher writes GIBSON_CG_JWT and GIBSON_AGENT_TASK_B64 into the sandbox,
29
+ * and `readSandboxDispatch` in `@zeroroot-ai/sdk` is the one reader of those
30
+ * (see `dispatch.ts`). This module runs one process further down, inside
31
+ * opencode, whose environment `dispatchChildEnv` writes. It never sees the
32
+ * launch environment, so it reads the child names and nothing else.
10
33
  *
11
34
  * An INTERACTIVE run has no callback seam and keeps the component grant, which
12
35
  * is correct: a human started it, and there is no task to scope to.
@@ -14,8 +37,10 @@ import { type GibsonSession, type KnowledgeSource } from "@zeroroot-ai/sdk";
14
37
  * A dispatch that carries an endpoint but no token FAILS rather than falling
15
38
  * back. Falling back is how the gap reappears silently, and a caller who wanted
16
39
  * task-scoped reads would get component-scoped ones without being told.
40
+ *
41
+ * `openTaskHarness` derives the `ContextInfo` every callback RPC carries from
42
+ * the grant's own claims, so a task-scoped read reaches the daemon naming the
43
+ * mission it belongs to. It also renews the grant on a timer, which is why the
44
+ * caller must {@link SelectedKnowledge.stop} the source when the session ends.
17
45
  */
18
- export declare function selectKnowledgeSource(session: GibsonSession): {
19
- knowledge: KnowledgeSource;
20
- scope: "task" | "component";
21
- };
46
+ export declare function selectKnowledgeSource(session: GibsonSession, deps?: KnowledgeSourceDeps): SelectedKnowledge;
@@ -1,12 +1,22 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
1
3
  import { componentKnowledge, openTaskHarness, taskKnowledge, } from "@zeroroot-ai/sdk";
2
4
  /**
3
5
  * Pick the grant this process should read the knowledge graph with.
4
6
  *
5
7
  * A DISPATCHED run must read as the TASK, not as the component. gibson mints a
6
- * per-dispatch capability grant and `zerocool-agent` passes it to the child as
7
- * GIBSON_CALLBACK_ENDPOINT / GIBSON_CALLBACK_TOKEN. Reading with the component's
8
- * own grant instead is broader authority than the dispatch intended and leaves
9
- * no per-task attribution on anything the run reads — the gap ADR-0006 recorded.
8
+ * per-dispatch capability grant, and the driver passes it to this opencode
9
+ * child as GIBSON_CALLBACK_ENDPOINT / GIBSON_CALLBACK_TOKEN. Reading with the
10
+ * component's own grant instead is broader authority than the dispatch
11
+ * intended and leaves no per-task attribution on anything the run reads — the
12
+ * gap ADR-0006 recorded.
13
+ *
14
+ * THESE TWO NAMES ARE THE CHILD CONTRACT, NOT THE LAUNCHER CONTRACT. The
15
+ * launcher writes GIBSON_CG_JWT and GIBSON_AGENT_TASK_B64 into the sandbox,
16
+ * and `readSandboxDispatch` in `@zeroroot-ai/sdk` is the one reader of those
17
+ * (see `dispatch.ts`). This module runs one process further down, inside
18
+ * opencode, whose environment `dispatchChildEnv` writes. It never sees the
19
+ * launch environment, so it reads the child names and nothing else.
10
20
  *
11
21
  * An INTERACTIVE run has no callback seam and keeps the component grant, which
12
22
  * is correct: a human started it, and there is no task to scope to.
@@ -14,25 +24,36 @@ import { componentKnowledge, openTaskHarness, taskKnowledge, } from "@zeroroot-a
14
24
  * A dispatch that carries an endpoint but no token FAILS rather than falling
15
25
  * back. Falling back is how the gap reappears silently, and a caller who wanted
16
26
  * task-scoped reads would get component-scoped ones without being told.
27
+ *
28
+ * `openTaskHarness` derives the `ContextInfo` every callback RPC carries from
29
+ * the grant's own claims, so a task-scoped read reaches the daemon naming the
30
+ * mission it belongs to. It also renews the grant on a timer, which is why the
31
+ * caller must {@link SelectedKnowledge.stop} the source when the session ends.
17
32
  */
18
- export function selectKnowledgeSource(session) {
33
+ export function selectKnowledgeSource(session, deps = {}) {
19
34
  const endpoint = process.env.GIBSON_CALLBACK_ENDPOINT;
20
35
  const token = process.env.GIBSON_CALLBACK_TOKEN;
21
36
  if (!endpoint) {
22
- return { knowledge: componentKnowledge(session.clients.component), scope: "component" };
37
+ return {
38
+ knowledge: componentKnowledge(session.clients.component),
39
+ scope: "component",
40
+ stop: () => { },
41
+ };
23
42
  }
24
43
  if (!token) {
25
44
  throw new Error("GIBSON_CALLBACK_ENDPOINT is set but GIBSON_CALLBACK_TOKEN is not. A dispatched run " +
26
45
  "must read with its task grant; falling back to the component grant would silently " +
27
46
  "widen this run's authority.");
28
47
  }
48
+ const harness = (deps.openHarness ?? openTaskHarness)({
49
+ endpoint,
50
+ token,
51
+ // A local or kind daemon may serve the callback listener without TLS.
52
+ insecure: process.env.GIBSON_CALLBACK_INSECURE === "1",
53
+ });
29
54
  return {
30
- knowledge: taskKnowledge(openTaskHarness({
31
- endpoint,
32
- token,
33
- // A local or kind daemon may serve the callback listener without TLS.
34
- insecure: process.env.GIBSON_CALLBACK_INSECURE === "1",
35
- })),
55
+ knowledge: taskKnowledge(harness),
36
56
  scope: "task",
57
+ stop: () => harness.stop(),
37
58
  };
38
59
  }
@@ -1,13 +1,4 @@
1
- import type { ToolDefinition } from "@opencode-ai/plugin";
2
1
  import { type KnowledgeSource } from "@zeroroot-ai/sdk";
3
- export declare function recallTool(knowledge: KnowledgeSource): ToolDefinition;
4
- /**
5
- * Per-session ambient knowledge for the system prompt.
6
- *
7
- * Returns a transform that injects a short context block once a session has
8
- * produced one. The lookup is fired once and cached, so a session pays for at
9
- * most one GraphRAG query no matter how many turns it runs.
10
- */
11
2
  export declare function ambientKnowledge(knowledge: KnowledgeSource, seedQuery: string): (input: {
12
3
  sessionID?: string;
13
4
  }, output: {
package/dist/knowledge.js CHANGED
@@ -1,5 +1,6 @@
1
- import { tool } from "@opencode-ai/plugin";
2
- import { formatKnowledgeForPrompt, isSeamUnavailable, } from "@zeroroot-ai/sdk";
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
3
+ import { formatKnowledgeForPrompt, } from "@zeroroot-ai/sdk";
3
4
  /**
4
5
  * Knowledge — read the tenant graph so the agent sharpens across runs
5
6
  * (zerocool-plugins#8).
@@ -22,57 +23,6 @@ import { formatKnowledgeForPrompt, isSeamUnavailable, } from "@zeroroot-ai/sdk";
22
23
  */
23
24
  /** How many hits the ambient block injects. Kept small — it is prompt overhead. */
24
25
  const AMBIENT_LIMIT = 5;
25
- export function recallTool(knowledge) {
26
- const z = tool.schema;
27
- return tool({
28
- description: "Search this tenant's Gibson knowledge graph for prior findings, targets and " +
29
- "security facts recorded by earlier runs. Use it before starting work on an " +
30
- "unfamiliar area, or to check whether an issue was already reported.",
31
- args: {
32
- query: z.string().describe("What to look for, in natural language."),
33
- limit: z.number().min(1).max(50).optional().describe("Maximum hits to return. Defaults to 10."),
34
- node_types: z
35
- .array(z.string())
36
- .optional()
37
- .describe('Restrict to node types, e.g. ["finding"] or ["host", "technique"].'),
38
- },
39
- async execute(args) {
40
- let hits;
41
- try {
42
- hits = await knowledge.query({
43
- text: args.query,
44
- topK: args.limit ?? 10,
45
- ...(args.node_types ? { nodeTypes: args.node_types } : {}),
46
- });
47
- }
48
- catch (e) {
49
- if (isSeamUnavailable(e)) {
50
- return {
51
- title: "recall unavailable",
52
- output: "The Gibson knowledge graph is not available on this daemon: the GraphRAG " +
53
- "seam is not wired (gibson#1186). Continue without prior context.",
54
- };
55
- }
56
- throw e;
57
- }
58
- if (hits.length === 0) {
59
- return { title: "no matches", output: `Nothing in the tenant graph matches "${args.query}".` };
60
- }
61
- return {
62
- title: `${hits.length} match${hits.length === 1 ? "" : "es"}`,
63
- output: formatKnowledgeForPrompt(hits),
64
- metadata: { hit_count: hits.length, node_types: [...new Set(hits.map((h) => h.type))] },
65
- };
66
- },
67
- });
68
- }
69
- /**
70
- * Per-session ambient knowledge for the system prompt.
71
- *
72
- * Returns a transform that injects a short context block once a session has
73
- * produced one. The lookup is fired once and cached, so a session pays for at
74
- * most one GraphRAG query no matter how many turns it runs.
75
- */
76
26
  export function ambientKnowledge(knowledge, seedQuery) {
77
27
  const cache = new Map();
78
28
  const inFlight = new Map();
@@ -0,0 +1,20 @@
1
+ /**
2
+ * How opencode reaches the Gibson MCP server (ADR-0008, slice A7).
3
+ *
4
+ * opencode spawns a local MCP server from its `mcp` block, the same way every
5
+ * other host does from its own config file. The plugin writes that entry in
6
+ * the `config` hook, so a user configures nothing.
7
+ *
8
+ * The command is the published package, not a path inside this plugin: the
9
+ * server is shared by every host and released on the SDK train, so pinning it
10
+ * to whatever this plugin happens to bundle would freeze the tool set.
11
+ */
12
+ export declare const GIBSON_MCP_PACKAGE = "@zeroroot-ai/gibson-mcp@latest";
13
+ export interface OpencodeMcpLocal {
14
+ type: "local";
15
+ command: string[];
16
+ enabled: boolean;
17
+ environment?: Record<string, string>;
18
+ }
19
+ /** The `mcp.gibson` entry. `environment` carries nothing secret. */
20
+ export declare function gibsonMcpServer(env?: NodeJS.ProcessEnv): OpencodeMcpLocal;
@@ -0,0 +1,31 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
3
+ /**
4
+ * How opencode reaches the Gibson MCP server (ADR-0008, slice A7).
5
+ *
6
+ * opencode spawns a local MCP server from its `mcp` block, the same way every
7
+ * other host does from its own config file. The plugin writes that entry in
8
+ * the `config` hook, so a user configures nothing.
9
+ *
10
+ * The command is the published package, not a path inside this plugin: the
11
+ * server is shared by every host and released on the SDK train, so pinning it
12
+ * to whatever this plugin happens to bundle would freeze the tool set.
13
+ */
14
+ export const GIBSON_MCP_PACKAGE = "@zeroroot-ai/gibson-mcp@latest";
15
+ /** The `mcp.gibson` entry. `environment` carries nothing secret. */
16
+ export function gibsonMcpServer(env = process.env) {
17
+ const environment = {};
18
+ // Addressing only. The server does its own check-in, and a grant is never
19
+ // written into a config file.
20
+ for (const name of ["GIBSON_PLATFORM_URL", "GIBSON_DAEMON_URL", "GIBSON_TARGET_ID", "GIBSON_CA_CERT"]) {
21
+ const value = env[name];
22
+ if (value)
23
+ environment[name] = value;
24
+ }
25
+ return {
26
+ type: "local",
27
+ command: ["npx", "--yes", "--package", GIBSON_MCP_PACKAGE, "gibson-mcp", "--transport", "stdio"],
28
+ enabled: true,
29
+ ...(Object.keys(environment).length > 0 ? { environment } : {}),
30
+ };
31
+ }
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
1
3
  import { spawn } from "node:child_process";
2
4
  /** Parse the NDJSON `opencode run --format json` writes to stdout. */
3
5
  export function parseOpencodeEvents(stdout) {
package/dist/semgrep.js CHANGED
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
1
3
  import { spawn } from "node:child_process";
2
4
  import { fileURLToPath } from "node:url";
3
5
  /**
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Elastic-2.0
3
+ // Copyright 2026 Zero Root AI
2
4
  /**
3
5
  * zerocool-agent — run zerocool headless as a daemon-driven `kind=agent`.
4
6
  *
package/dist/serve.js CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Elastic-2.0
3
+ // Copyright 2026 Zero Root AI
2
4
  /**
3
5
  * zerocool-serve — run zerocool headless as a dispatched fleet component.
4
6
  *
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
1
3
  import { newFinding } from "@zeroroot-ai/sdk";
2
4
  import { readFile } from "node:fs/promises";
3
5
  import { join } from "node:path";
package/dist/watch.js CHANGED
@@ -1,3 +1,5 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright 2026 Zero Root AI
1
3
  import { buildCreateMissionRequest, remember, taskKnowledge } from "@zeroroot-ai/sdk";
2
4
  import { TRIGGER_STATUS } from "./gitlab.js";
3
5
  /**
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@zeroroot-ai/zerocool",
3
- "version": "0.8.0",
4
- "description": "opencode plugin: Gibson platform integration (zerocool). Zero-config LLM, tools, findings, knowledge, delegate/missions.",
5
- "license": "MIT",
3
+ "version": "0.9.1",
4
+ "description": "opencode host adapter for Gibson (zerocool): zero-config LLM through the harness, ambient knowledge, and the Gibson MCP server registered for you. The tools come from @zeroroot-ai/gibson-mcp.",
5
+ "license": "Elastic-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/zeroroot-ai/zerocool-plugins.git",
@@ -23,13 +23,13 @@
23
23
  "test": "tsc -p tsconfig.test.json && node --test \"dist-test/**/*.test.js\""
24
24
  },
25
25
  "dependencies": {
26
- "@zeroroot-ai/sdk": "^0.11.0"
26
+ "@zeroroot-ai/sdk": "^0.12.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@opencode-ai/plugin": "*"
30
30
  },
31
31
  "devDependencies": {
32
- "@opencode-ai/plugin": "^1.18.11"
32
+ "@opencode-ai/plugin": "^1.18.27"
33
33
  },
34
34
  "bin": {
35
35
  "zerocool-serve": "dist/serve.js",
@@ -1,10 +0,0 @@
1
- import type { ToolDefinition } from "@opencode-ai/plugin";
2
- import { type GibsonSession } from "@zeroroot-ai/sdk";
3
- /**
4
- * Write a validated component manifest to disk. Available with or without a
5
- * Gibson session — the manifest is the artifact a build pipeline needs, and
6
- * producing it must not require a platform connection.
7
- */
8
- export declare function componentizeTool(): ToolDefinition;
9
- /** Register a produced artifact with the tenant registry. */
10
- export declare function enrollComponentTool(session: GibsonSession): ToolDefinition;