@dougbots/avenor-opencode 0.10.4 → 0.12.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.
Files changed (2) hide show
  1. package/dist/index.js +85 -1
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { tool } from "@opencode-ai/plugin";
2
2
  import * as crypto from "node:crypto";
3
- import { Supervisor, THINKING_LEVELS, answerPermissionTool, createRunSnapshot, dial, eventsTool, extractEventText, followUpTool, inspectTool, observeRun, resultTool, shutdownTool, spawnTool, statusTool, validateSpawnSelection, workflowCompleteTool, workflowEventsTool, workflowGateTool, workflowInspectTool, workflowStatusTool, workflowWaitTool } from "@dougbots/avenor-core";
3
+ import { Supervisor, THINKING_LEVELS, answerPermissionTool, createRunSnapshot, dial, eventsTool, extractEventText, followUpTool, inspectTool, observeRun, resultTool, shutdownTool, spawnTool, statusTool, validateSpawnSelection, workflowCompleteTool, workflowControllerStatusTool, workflowEventsTool, workflowGateTool, workflowInspectTool, workflowReadyTool, workflowStatusTool, workflowWaitTool } from "@dougbots/avenor-core";
4
4
  //#region src/render.ts
5
5
  const FINAL_OUTPUT_CHARS$1 = 1500;
6
6
  const SCALAR_CHARS = 240;
@@ -408,6 +408,69 @@ function formatShutdownOutput(args, result) {
408
408
  }
409
409
  };
410
410
  }
411
+ function controllerLeaderLine(leader) {
412
+ if (!leader) return "Leader: none";
413
+ const owner = leader.is_this_process === true ? "this process" : `other owner (${scalar(leader.owner_id)})`;
414
+ const expires = selectedOptional(leader, "expires_at");
415
+ return `Leader: ${owner}${expires ? ` — lease expires ${expires}` : ""}`;
416
+ }
417
+ function controllerListRow(controller) {
418
+ const leader = asRecord(controller.leader);
419
+ const owner = leader ? leader.is_this_process === true ? "this process" : `other owner (${scalar(leader.owner_id)})` : "none";
420
+ return `${selected(controller, "controller_id")} — ${selected(controller, "desired_state")} — leader: ${owner}`;
421
+ }
422
+ function controllerStatusLines(details, args) {
423
+ const status = asRecord(details);
424
+ if (!status || !stringValue(status.controller_id) || !stringValue(status.desired_state)) return void 0;
425
+ const controllerId = selected(status, "controller_id", args.controller_id);
426
+ const desiredState = selected(status, "desired_state");
427
+ const inflight = numberValue(status.inflight) ?? 0;
428
+ const maxInflight = numberValue(status.max_inflight);
429
+ const blocked = asRecord(status.capacity_blocked);
430
+ const blockedDetail = blocked ? selectedOptional(blocked, "detail") : void 0;
431
+ const lines = [`Controller: ${controllerId} — ${desiredState}`, controllerLeaderLine(asRecord(status.leader))];
432
+ const candidates = numberValue(status.candidate_count);
433
+ if (candidates !== void 0) lines.push(`Candidates: ${candidates} (advisory)`);
434
+ lines.push(`In-flight: ${inflight}${maxInflight !== void 0 ? ` of ${maxInflight}` : ""}`);
435
+ const lastReconcile = selectedOptional(status, "last_reconcile");
436
+ if (lastReconcile) lines.push(`Last reconcile: ${lastReconcile}`);
437
+ if (blocked) lines.push(`Capacity blocked: ${selected(blocked, "source")}${blockedDetail ? ` — ${blockedDetail}` : ""}`);
438
+ const nextPoll = selectedOptional(status, "next_poll_at");
439
+ if (nextPoll) lines.push(`Next external poll: ${nextPoll}`);
440
+ lines.push(desiredState === "disabled" ? `Guidance: Run \`avenor workflow controller enable ${controllerId}\` to start dispatch and polling.` : `Guidance: Call avenor_workflow_controller_status without controller_id to review all controllers.`);
441
+ return lines;
442
+ }
443
+ function controllerListLines(details) {
444
+ const result = asRecord(details);
445
+ if (!result || !Array.isArray(result.controllers) || result.controllers.some((controller) => !asRecord(controller))) return void 0;
446
+ const controllers = result.controllers.map((controller) => controller);
447
+ if (controllers.length === 0) return ["No workflow controllers configured."];
448
+ return [
449
+ `Workflow controllers — ${controllers.length}`,
450
+ ...controllers.slice(0, STATUS_ROWS).map(controllerListRow),
451
+ ...controllers.length > STATUS_ROWS ? [itemMarker(controllers.length - STATUS_ROWS)] : []
452
+ ];
453
+ }
454
+ function formatWorkflowControllerStatusOutput(args, result) {
455
+ const status = asRecord(result);
456
+ const statusLines = controllerStatusLines(result, args);
457
+ if (statusLines) return {
458
+ title: `Workflow controller ${selected(status, "controller_id", args.controller_id)}`,
459
+ output: output(statusLines, "workflow controller status"),
460
+ metadata: { ...result }
461
+ };
462
+ const listLines = controllerListLines(result);
463
+ if (listLines) return {
464
+ title: `Avenor workflow controllers — ${Array.isArray(status?.controllers) ? status.controllers.length : 0}`,
465
+ output: output(listLines, "workflow controller list"),
466
+ metadata: { ...result }
467
+ };
468
+ return {
469
+ title: "Avenor workflow controllers",
470
+ output: output(void 0, "workflow controller status"),
471
+ metadata: { ...result }
472
+ };
473
+ }
411
474
  //#endregion
412
475
  //#region src/plugin.ts
413
476
  const TERMINAL_STATUSES = new Set([
@@ -1268,6 +1331,27 @@ const AvenorPlugin = async (ctx) => {
1268
1331
  output: JSON.stringify(result, null, 2)
1269
1332
  };
1270
1333
  }
1334
+ }),
1335
+ avenor_workflow_controller_status: tool({
1336
+ description: "Show workflow controller status. With controller_id, returns that controller's full status; without it, lists all controllers with summary state. Create, enable, and disable are CLI-only (avenor workflow controller ...).",
1337
+ args: {
1338
+ controller_id: tool.schema.string().optional().describe("Controller ID; omit to list all controllers"),
1339
+ supervisor_id: tool.schema.string().optional().describe("Supervisor ID for multi-supervisor mode")
1340
+ },
1341
+ async execute(args, _context) {
1342
+ const details = { ...await workflowControllerStatusTool({
1343
+ controllerId: args.controller_id,
1344
+ supervisorId: args.supervisor_id
1345
+ }) };
1346
+ if (args.controller_id) try {
1347
+ const ready = await workflowReadyTool({
1348
+ controllerId: args.controller_id,
1349
+ supervisorId: args.supervisor_id
1350
+ });
1351
+ if (Array.isArray(ready.candidates)) details.candidate_count = ready.candidates.length;
1352
+ } catch {}
1353
+ return formatWorkflowControllerStatusOutput(args, details);
1354
+ }
1271
1355
  })
1272
1356
  }
1273
1357
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dougbots/avenor-opencode",
3
- "version": "0.10.4",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  "dev": "tsdown --watch"
28
28
  },
29
29
  "dependencies": {
30
- "@dougbots/avenor-core": "^0.10.4"
30
+ "@dougbots/avenor-core": "^0.12.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@opencode-ai/plugin": "1.15.3"