@dudousxd/nestjs-agent-opencode 0.2.1 → 0.4.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.
@@ -154,6 +154,7 @@ OpenCodeMcpController = _ts_decorate([
154
154
  // src/mcp.ts
155
155
  var import_node_crypto = require("crypto");
156
156
  var import_nestjs_agent_core3 = require("@dudousxd/nestjs-agent-core");
157
+ var import_genui = require("@dudousxd/nestjs-agent-core/genui");
157
158
  var import_server = require("@modelcontextprotocol/sdk/server/index.js");
158
159
  var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
159
160
  var import_zod_json_schema_compat = require("@modelcontextprotocol/sdk/server/zod-json-schema-compat.js");
@@ -1030,6 +1031,8 @@ ${delta}` : delta;
1030
1031
  }
1031
1032
  const ttlMs = requirement.ttlMs !== void 0 && Number.isFinite(requirement.ttlMs) && requirement.ttlMs > 0 ? Math.floor(requirement.ttlMs) : void 0;
1032
1033
  const expiresAt = ttlMs !== void 0 ? new Date(Date.now() + ttlMs).toISOString() : void 0;
1034
+ const tool = this.a.approvalPresentation?.(action);
1035
+ const confirmation = tool !== void 0 ? (0, import_nestjs_agent_core2.resolveToolConfirmation)(tool.name, args, tool.presentation) : void 0;
1033
1036
  this.segment.calls.push({
1034
1037
  id: req.id,
1035
1038
  name: action,
@@ -1044,6 +1047,9 @@ ${delta}` : delta;
1044
1047
  toolType: "action",
1045
1048
  input: args,
1046
1049
  status: "pending_approval",
1050
+ ...confirmation !== void 0 ? {
1051
+ confirmation
1052
+ } : {},
1047
1053
  runId: this.a.runId,
1048
1054
  approver: requirement.approver,
1049
1055
  ...expiresAt !== void 0 ? {
@@ -1061,6 +1067,9 @@ ${delta}` : delta;
1061
1067
  kind: "approval-requested",
1062
1068
  id: req.id,
1063
1069
  approver: requirement.approver,
1070
+ ...confirmation !== void 0 ? {
1071
+ confirmation
1072
+ } : {},
1064
1073
  ...expiresAt !== void 0 ? {
1065
1074
  expiresAt
1066
1075
  } : {}
@@ -1466,6 +1475,8 @@ var OpenCodeMcpEndpoint2 = class {
1466
1475
  }
1467
1476
  turns;
1468
1477
  tokens;
1478
+ /** Genui telemetry of the UI calls OpenCode makes (its code mode calls tools here, not in the loop). */
1479
+ genui = new import_nestjs_agent_core3.GenuiRunRecorder();
1469
1480
  constructor(turns, tokens) {
1470
1481
  this.turns = turns;
1471
1482
  this.tokens = tokens;
@@ -1597,7 +1608,7 @@ var OpenCodeMcpEndpoint2 = class {
1597
1608
  if (spec.kind === "action" && !await this.turns.spendApproval(turn.runId, name, turn.input)) {
1598
1609
  throw new OpenCodeToolRefusedError(`"${name}" is an action and nobody approved this call; ask for the permission first.`);
1599
1610
  }
1600
- return registry.invoke(name, args ?? {}, {
1611
+ const invoke = /* @__PURE__ */ __name(() => registry.invoke(name, args ?? {}, {
1601
1612
  actor,
1602
1613
  threadId: turn.ctx.threadId,
1603
1614
  runId: turn.runId,
@@ -1614,7 +1625,24 @@ var OpenCodeMcpEndpoint2 = class {
1614
1625
  } : {}
1615
1626
  }, this.turns.rolesPolicyFor(turn.input), allowed !== void 0 ? {
1616
1627
  allowedTools: allowed
1617
- } : {});
1628
+ } : {}), "invoke");
1629
+ return this.genui.track({
1630
+ store: this.turns.store,
1631
+ marker: spec.genui,
1632
+ runId: turn.runId,
1633
+ threadId: turn.ctx.threadId,
1634
+ actorRef: actor.id,
1635
+ ...turn.input.agentName !== void 0 ? {
1636
+ agentName: turn.input.agentName
1637
+ } : {},
1638
+ channel: (0, import_genui.turnChannel)(turn.input.pageContext),
1639
+ modelId: turn.input.model ?? "opencode",
1640
+ call: {
1641
+ id: `mcp:${turn.runId}:${requestId}`,
1642
+ name,
1643
+ input: args ?? {}
1644
+ }
1645
+ }, invoke);
1618
1646
  }
1619
1647
  /** `remember`: one fact, at the actor's own scope only — as the loop serves it. */
1620
1648
  async remember(turn, args) {
@@ -1841,6 +1869,25 @@ var OpenCodeTurns = class {
1841
1869
  get toolsServer() {
1842
1870
  return this.settings.tools?.server ?? "aviary";
1843
1871
  }
1872
+ /** The app tool an OpenCode permission `action` names, and its presentation — `undefined` for a built-in. */
1873
+ presentationOf(action) {
1874
+ if (this.settings.tools === void 0) return void 0;
1875
+ const server = this.toolsServer;
1876
+ for (const prefix of [
1877
+ `${server}.`,
1878
+ `${server}_`
1879
+ ]) {
1880
+ if (!action.startsWith(prefix)) continue;
1881
+ const spec = this.registry.spec(action.slice(prefix.length));
1882
+ if (spec !== void 0) return {
1883
+ name: spec.name,
1884
+ ...spec.presentation !== void 0 ? {
1885
+ presentation: spec.presentation
1886
+ } : {}
1887
+ };
1888
+ }
1889
+ return void 0;
1890
+ }
1844
1891
  /** The roles policy a turn's tools are gated by (the agent's own). */
1845
1892
  rolesPolicyFor(input) {
1846
1893
  return this.deps.forAgent(input.agentName).rolesPolicy;
@@ -2573,6 +2620,9 @@ ${body}
2573
2620
  agentName: input.agentName
2574
2621
  } : {}
2575
2622
  }), "approvalFor"),
2623
+ // An app tool reaches OpenCode as `<server>.<name>` / `<server>_<name>`: its own presentation
2624
+ // words the approval card. OpenCode's built-ins (`bash`, `edit`) have none.
2625
+ approvalPresentation: /* @__PURE__ */ __name((action) => this.presentationOf(action), "approvalPresentation"),
2576
2626
  modelLabel: input.model ?? "opencode",
2577
2627
  priceStep: /* @__PURE__ */ __name((step) => this.priceStep(step), "priceStep"),
2578
2628
  ...spent !== void 0 ? {