@zeroroot-ai/zerocool 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -59,7 +59,7 @@
59
59
  * {@link dispatchChildEnv} — that is the opencode plugin's own contract, fed from
60
60
  * the grant the SDK read.
61
61
  */
62
- import { type AgentOutcome, type SandboxDispatch, type TaskHarness } from "@zeroroot-ai/sdk";
62
+ import { parkAfterResult, Watcher, type AgentOutcome, type SandboxDispatch, type TaskHarness } from "@zeroroot-ai/sdk";
63
63
  import { type FindingsBackend } from "./findings.js";
64
64
  import { type FindingSource, type FindingStatusWriter, type FixPlanner, type Workspace } from "./fix.js";
65
65
  import { type GitLabClient, type GitLabWriter } from "./gitlab.js";
@@ -315,3 +315,21 @@ export declare function harnessCredential(harness: TaskHarness): (name: string)
315
315
  * carries it.
316
316
  */
317
317
  export declare function formatTerminalResult(outcome: AgentOutcome): string;
318
+ /** Seams of {@link runForkableDispatch}. */
319
+ export interface ForkableDispatchDeps extends DispatchDeps {
320
+ /** Made at process start, before a fork can happen. */
321
+ watcher: Watcher;
322
+ /** Called with the outcome of each run, before a park. */
323
+ onOutcome?: (outcome: AgentOutcome) => void;
324
+ /** Test seams. */
325
+ runOnce?: typeof runDispatch;
326
+ park?: typeof parkAfterResult;
327
+ }
328
+ /**
329
+ * Run the dispatch, and run the task of a fork when this run is forked (D74).
330
+ * A fork source (`GIBSON_FORKABLE=1`) parks after a passing result. The
331
+ * parent returns at the end of the park. A fork claims its own dispatch once
332
+ * and runs that task, and the outcome of the fork is returned. A failed run
333
+ * does not park.
334
+ */
335
+ export declare function runForkableDispatch(ctx: DispatchContext, env: NodeJS.ProcessEnv, deps: ForkableDispatchDeps): Promise<AgentOutcome>;
package/dist/dispatch.js CHANGED
@@ -61,7 +61,7 @@
61
61
  * {@link dispatchChildEnv} — that is the opencode plugin's own contract, fed from
62
62
  * the grant the SDK read.
63
63
  */
64
- import { observe, readSandboxDispatch, sandboxHarness, taskKnowledge, } from "@zeroroot-ai/sdk";
64
+ import { observe, parkAfterResult, readSandboxDispatch, sandboxHarness, Watcher, taskKnowledge, } from "@zeroroot-ai/sdk";
65
65
  import { join } from "node:path";
66
66
  import { taskFindingsBackend } from "./findings.js";
67
67
  import { harnessFindingSource, harnessFindingStatus, runFix, } from "./fix.js";
@@ -543,7 +543,34 @@ export function formatTerminalResult(outcome) {
543
543
  metadata: outcome.metadata ?? {},
544
544
  });
545
545
  }
546
+ /**
547
+ * Run the dispatch, and run the task of a fork when this run is forked (D74).
548
+ * A fork source (`GIBSON_FORKABLE=1`) parks after a passing result. The
549
+ * parent returns at the end of the park. A fork claims its own dispatch once
550
+ * and runs that task, and the outcome of the fork is returned. A failed run
551
+ * does not park.
552
+ */
553
+ export async function runForkableDispatch(ctx, env, deps) {
554
+ const runOnce = deps.runOnce ?? runDispatch;
555
+ const parkFor = deps.park ?? parkAfterResult;
556
+ let current = ctx;
557
+ let launch = env;
558
+ for (;;) {
559
+ const outcome = await runOnce(current, deps);
560
+ deps.onOutcome?.(outcome);
561
+ if (outcome.success === false)
562
+ return outcome;
563
+ const next = await parkFor(launch, deps.watcher, { insecure: current.insecure });
564
+ if (!next)
565
+ return outcome;
566
+ console.error("[zerocool-dispatch] this process is a fork: running the task of the fork");
567
+ launch = next;
568
+ current = readDispatchContext(next);
569
+ }
570
+ }
546
571
  async function main() {
572
+ // Made before any run, so a fork of this process sees its new sandbox id (D74).
573
+ const watcher = Watcher.create();
547
574
  let ctx;
548
575
  try {
549
576
  ctx = readDispatchContext(process.env);
@@ -560,13 +587,16 @@ async function main() {
560
587
  console.error(`[zerocool-dispatch] run mission=${ctx.missionRunId || "-"} agent=${ctx.agentRunId || "-"} ` +
561
588
  `workspace=${ctx.workspace}; callbacks use the per-dispatch grant`);
562
589
  try {
563
- const outcome = await runDispatch(ctx, {
590
+ await runForkableDispatch(ctx, process.env, {
591
+ watcher,
564
592
  // Forward every opencode event to our stdout, live, for the console stream.
565
593
  onEvent: (line) => process.stdout.write(`${line}\n`),
594
+ onOutcome: (outcome) => {
595
+ process.stdout.write(`${formatTerminalResult(outcome)}\n`);
596
+ console.error(`[zerocool-dispatch] done reason=${outcome.metadata?.finish_reason ?? "-"} ` +
597
+ `tokens=${outcome.metadata?.tokens_total ?? "-"}`);
598
+ },
566
599
  });
567
- process.stdout.write(`${formatTerminalResult(outcome)}\n`);
568
- console.error(`[zerocool-dispatch] done reason=${outcome.metadata?.finish_reason ?? "-"} ` +
569
- `tokens=${outcome.metadata?.tokens_total ?? "-"}`);
570
600
  process.exit(0);
571
601
  }
572
602
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroroot-ai/zerocool",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
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
5
  "license": "Elastic-2.0",
6
6
  "repository": {
@@ -23,7 +23,7 @@
23
23
  "test": "tsc -p tsconfig.test.json && node --test \"dist-test/**/*.test.js\""
24
24
  },
25
25
  "dependencies": {
26
- "@zeroroot-ai/sdk": "^0.13.0"
26
+ "@zeroroot-ai/sdk": "^0.16.0"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@opencode-ai/plugin": "*"