@clwnd/opencode 0.4.3 → 0.5.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 +57 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -283,10 +283,19 @@ var { btoa, atob } = globalThis;
283
283
 
284
284
  // provider.ts
285
285
  var MCP_PREFIX = "mcp__clwnd__";
286
+ var TOOL_NAME_MAP = {
287
+ WebFetch: "webfetch",
288
+ WebSearch: "websearch",
289
+ TodoWrite: "todowrite",
290
+ AskUserQuestion: "question",
291
+ Task: "task",
292
+ Skill: "skill"
293
+ };
286
294
  function mapToolName(name14) {
287
295
  if (name14.startsWith(MCP_PREFIX)) return name14.slice(MCP_PREFIX.length);
288
- return name14;
296
+ return TOOL_NAME_MAP[name14] ?? name14;
289
297
  }
298
+ var BROKERED_TOOLS = /* @__PURE__ */ new Set(["webfetch", "websearch", "todowrite"]);
290
299
  var INPUT_FIELD_MAP = {
291
300
  read: { file_path: "filePath" },
292
301
  edit: { file_path: "filePath", old_string: "oldString", new_string: "newString", replace_all: "replaceAll" },
@@ -300,6 +309,21 @@ var INPUT_FIELD_MAP = {
300
309
  };
301
310
  function mapToolInput(toolName, input) {
302
311
  const ocName = mapToolName(toolName);
312
+ if (ocName === "todowrite") {
313
+ try {
314
+ const parsed = JSON.parse(input);
315
+ if (parsed.todos && Array.isArray(parsed.todos)) {
316
+ parsed.todos = parsed.todos.map((t) => ({
317
+ content: t.content ?? "",
318
+ status: t.status ?? "pending",
319
+ priority: t.priority ?? "medium"
320
+ }));
321
+ }
322
+ return JSON.stringify(parsed);
323
+ } catch {
324
+ return input;
325
+ }
326
+ }
303
327
  const fieldMap = INPUT_FIELD_MAP[ocName];
304
328
  if (!fieldMap || Object.keys(fieldMap).length === 0) return input;
305
329
  try {
@@ -347,6 +371,25 @@ function isAuxiliaryCall(opts) {
347
371
  const hasTools = Array.isArray(opts.tools) && opts.tools.length > 0;
348
372
  return !hasTools;
349
373
  }
374
+ var OC_TO_MCP = {
375
+ read: "read",
376
+ edit: "edit",
377
+ write: "write",
378
+ bash: "bash",
379
+ glob: "glob",
380
+ grep: "grep",
381
+ apply_patch: "edit",
382
+ webfetch: "webfetch"
383
+ };
384
+ function deriveAllowedTools(opts) {
385
+ if (!Array.isArray(opts.tools)) return ["read", "edit", "write", "bash", "glob", "grep"];
386
+ const ocTools = new Set(opts.tools.map((t) => t.name));
387
+ const allowed = [];
388
+ for (const [ocName, mcpName] of Object.entries(OC_TO_MCP)) {
389
+ if (ocTools.has(ocName)) allowed.push(mcpName);
390
+ }
391
+ return [...new Set(allowed)];
392
+ }
350
393
  function extractText(prompt) {
351
394
  for (let i = prompt.length - 1; i >= 0; i--) {
352
395
  const m = prompt[i];
@@ -416,6 +459,7 @@ var ClwndModel = class {
416
459
  const warnings = [];
417
460
  const cwd = this.config.cwd ?? process.cwd();
418
461
  const permissions = isTitle ? [] : await getSessionPermissions(this.config.client, sid);
462
+ const allowedTools = isTitle ? [] : deriveAllowedTools(opts);
419
463
  let reasoning = "";
420
464
  let responseText = "";
421
465
  const toolCalls = [];
@@ -435,7 +479,8 @@ var ClwndModel = class {
435
479
  modelId: this.modelId,
436
480
  text,
437
481
  systemPrompt,
438
- permissions
482
+ permissions,
483
+ allowedTools
439
484
  }).then(async (resp) => {
440
485
  if (!resp.body) {
441
486
  abort();
@@ -540,6 +585,7 @@ var ClwndModel = class {
540
585
  const self = this;
541
586
  const toolInputAccum = /* @__PURE__ */ new Map();
542
587
  const permissions = isTitle ? [] : await getSessionPermissions(this.config.client, sid);
588
+ const allowedTools = isTitle ? [] : deriveAllowedTools(opts);
543
589
  const stream = new ReadableStream({
544
590
  async start(controller) {
545
591
  const textId = generateId();
@@ -548,6 +594,7 @@ var ClwndModel = class {
548
594
  let reader = null;
549
595
  let textStarted = false;
550
596
  let reasoningStarted = false;
597
+ const brokeredCallIds = /* @__PURE__ */ new Set();
551
598
  function emit(part) {
552
599
  if (done) return;
553
600
  try {
@@ -580,7 +627,8 @@ var ClwndModel = class {
580
627
  modelId: self.modelId,
581
628
  text,
582
629
  systemPrompt,
583
- permissions
630
+ permissions,
631
+ allowedTools
584
632
  });
585
633
  } catch (e) {
586
634
  emit({ type: "error", error: new Error(String(e)) });
@@ -653,16 +701,19 @@ var ClwndModel = class {
653
701
  } else {
654
702
  rawInput = "{}";
655
703
  }
704
+ const isBrokered = BROKERED_TOOLS.has(ocToolName);
705
+ if (isBrokered) brokeredCallIds.add(msg.toolCallId);
656
706
  emit({
657
707
  type: "tool-call",
658
708
  toolCallId: msg.toolCallId,
659
709
  toolName: ocToolName,
660
710
  input: rawInput,
661
- providerExecuted: true
711
+ providerExecuted: !isBrokered
662
712
  });
663
713
  }
664
714
  if (ct === "tool_result" && (msg.toolCallId || msg.toolUseId)) {
665
715
  const callId = msg.toolCallId ?? msg.toolUseId;
716
+ if (brokeredCallIds.has(callId)) continue;
666
717
  const raw = msg.result ?? "";
667
718
  const { output, title, metadata } = parseToolResult(typeof raw === "string" ? raw : JSON.stringify(raw));
668
719
  emit({
@@ -684,9 +735,10 @@ var ClwndModel = class {
684
735
  const cacheRead = u?.cache_read_input_tokens ?? 0;
685
736
  const cacheWrite = u?.cache_creation_input_tokens ?? 0;
686
737
  const inputBase = u?.input_tokens ?? u?.inputTokens ?? 0;
738
+ const fr = brokeredCallIds.size > 0 ? "tool-calls" : msg.finishReason ?? "stop";
687
739
  emit({
688
740
  type: "finish",
689
- finishReason: msg.finishReason ?? "stop",
741
+ finishReason: fr,
690
742
  usage: {
691
743
  inputTokens: inputBase + cacheRead + cacheWrite,
692
744
  outputTokens: u?.output_tokens ?? u?.outputTokens,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clwnd/opencode",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "clwnd for opencode",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",