@khalilgharbaoui/opencode-claude-code-plugin 0.18.3 → 0.20.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.
package/dist/index.d.ts CHANGED
@@ -87,7 +87,7 @@ type OpenCodeConfig = {
87
87
  * Bus events surface to plugins. Shape mirrors what opencode core publishes
88
88
  * via `GlobalBus.emit("event", { directory, payload: { type, properties } })`
89
89
  * but kept loose since opencode adds events over time and this plugin only
90
- * reacts to a small subset (currently just `global.disposed`).
90
+ * reacts to a small subset (currently just `session.deleted`).
91
91
  */
92
92
  type OpenCodeEvent = {
93
93
  type?: string;
@@ -186,9 +186,9 @@ interface ClaudeCodeConfig {
186
186
  /**
187
187
  * Route `ExitPlanMode` through opencode's native `question` tool so plan
188
188
  * approval is a real form instead of a "(yes/no)" line the operator has to
189
- * answer in prose. Off by default: opencode's question form is currently
190
- * broken upstream, so enabling this trades a working text prompt for a
191
- * silent hang. See the plan-mode gotcha in AGENTS.md.
189
+ * answer in prose. Off by default because it cannot currently fire: headless
190
+ * `--print` is not offered an `ExitPlanMode` tool at all, and this bridge
191
+ * keys on that tool call. See the plan-mode gotcha in AGENTS.md.
192
192
  */
193
193
  planModeQuestion?: boolean;
194
194
  webSearch?: WebSearchRouting;
@@ -202,6 +202,8 @@ interface ClaudeCodeConfig {
202
202
  idleProcessTimeoutMs?: number;
203
203
  /** Stage opencode skills as a `--plugin-dir` so Claude's Skill tool can run them. */
204
204
  bridgeOpencodeSkills?: boolean;
205
+ /** Append a one-line cost / duration / cache footer to each finished turn. */
206
+ turnStats?: boolean;
205
207
  logging?: LoggingConfig;
206
208
  }
207
209
  interface LoggingConfig {
@@ -336,13 +338,17 @@ interface ClaudeCodeProviderSettings {
336
338
  * receives a timeout error.
337
339
  *
338
340
  * Defaults (used when a tool is absent here): `bash`/`edit`/`write`/
339
- * `webfetch` → 10 min (matches Claude CLI's Bash ceiling); `task` →
340
- * 60 min (subagents routinely run 20–40 min); `question` → 30 min
341
- * (operator AFK). Setting a key here replaces the default for that tool.
341
+ * `webfetch` → 10 min (matches Claude CLI's Bash ceiling); `task` and
342
+ * `task_batch` → no deadline (the call waits for the subagent; abandoned
343
+ * calls are released by aborts, the next user turn, and the process going
344
+ * away); `question` → 30 min (operator AFK). A positive value here replaces
345
+ * the default for that tool, `0` disables its deadline, and a negative or
346
+ * non-finite value is ignored.
342
347
  *
343
348
  * For `bash` specifically the call's own `input.timeout` is honoured on
344
349
  * top: the effective deadline is `max(resolved, input.timeout)`, so a
345
- * long build the caller explicitly asked to run is never undercut.
350
+ * long build the caller explicitly asked to run is never undercut, and a
351
+ * positive `input.timeout` restores a deadline that `bash: 0` disabled.
346
352
  */
347
353
  proxyToolTimeoutMs?: Record<string, number>;
348
354
  /**
@@ -355,11 +361,15 @@ interface ClaudeCodeProviderSettings {
355
361
  * real form; the answer is fed back to the CLI as the `tool_result` for
356
362
  * the original `ExitPlanMode` call, which is what unlocks plan mode.
357
363
  *
358
- * Two reasons it is opt-in. opencode's `question` form does not currently
359
- * render (upstream anomalyco/opencode#36604), so an enabled bridge hangs
360
- * the turn until the operator interrupts; and older opencode builds have
361
- * no `question` registry entry at all, in which case the plugin silently
362
- * keeps the text path. See the plan-mode gotcha in AGENTS.md.
364
+ * Opt-in, and currently dormant. The delivery surface works: opencode's
365
+ * `question` form renders and round-trips (verified 2026-09-06, correcting
366
+ * an earlier claim here that it was broken upstream). What does not work is
367
+ * the trigger: headless `--print` does not offer the model an
368
+ * `ExitPlanMode` tool, measured on CLI 2.1.258, so the bridge has nothing
369
+ * to key on and the text path is what you get. Older opencode builds also
370
+ * have no `question` registry entry, in which case the plugin silently
371
+ * keeps the text path. Re-run the probes in AGENTS.md on a newer CLI before
372
+ * assuming the bridge is reachable.
363
373
  */
364
374
  planModeQuestion?: boolean;
365
375
  /**
@@ -375,21 +385,40 @@ interface ClaudeCodeProviderSettings {
375
385
  ignoreAnthropicApiKey?: boolean;
376
386
  /**
377
387
  * Kill a retained headless Claude worker after this many milliseconds of
378
- * inactivity following a completed turn. Starting another turn cancels the
379
- * timer, and the Claude session id is retained for a transparent resume.
380
- * Omit or set to 0 to keep workers until LRU eviction. Interactive transport
381
- * is excluded because it does not currently guarantee session-id resume.
388
+ * inactivity following a completed turn. Off unless set. The timer
389
+ * starts when a turn completes (not at spawn), starting another turn cancels
390
+ * it, a worker found mid-turn when it fires is left alone and re-timed, and
391
+ * the Claude session id is retained for a transparent resume. Omit or set 0
392
+ * to keep workers until LRU eviction (16 processes). Interactive transport is
393
+ * excluded because it does not currently guarantee session-id resume.
382
394
  */
383
395
  idleProcessTimeoutMs?: number;
384
396
  /**
385
397
  * Expose your opencode skills (`.opencode/skills`, `~/.config/opencode/skills`)
386
398
  * to Claude Code's native Skill tool by staging them as a session-scoped
387
- * `--plugin-dir`. Off by default: every bridged skill is also listed in the
388
- * system prompt opencode already forwards, so a large skill set is paid for
389
- * twice per turn. Turn it on when the model tries `Skill("<name>")` and gets
390
- * `Unknown skill`. No-op on CLIs without `--plugin-dir`.
399
+ * `--plugin-dir`, so a `Skill("<name>")` call for a skill opencode advertises
400
+ * does not fail with `Unknown skill`. Off by default: every bridged skill
401
+ * is also listed in the system prompt opencode forwards, so a large skill
402
+ * set costs prompt tokens twice per turn. When on it applies to the
403
+ * headless, interactive and direct `doGenerate` spawns alike; compaction
404
+ * never loads it, and the bundled configuration skill is staged either way.
405
+ * No-op on CLIs without `--plugin-dir`.
391
406
  */
392
407
  bridgeOpencodeSkills?: boolean;
408
+ /**
409
+ * Append one compact line to the end of every finished (non-compaction,
410
+ * non-error) turn with what that turn cost: dollars, wall duration, how many
411
+ * internal CLI turns it took, and input / output / cache-read / cache-write
412
+ * tokens. It is rendered as its own text part led by `▌ **stats:**` and is
413
+ * stripped again from any transcript rebuilt for the CLI, so the model never
414
+ * reads its own accounting.
415
+ *
416
+ * Off by default, because a cost line under every reply is a preference.
417
+ * The same numbers are logged at INFO regardless of this setting, and
418
+ * `total_cost_usd`, `duration_ms`, `usage`, `modelUsage` and
419
+ * `permission_denials` always reach `providerMetadata`.
420
+ */
421
+ turnStats?: boolean;
393
422
  /**
394
423
  * Routing for Claude's built-in `WebSearch` tool.
395
424
  *
@@ -510,8 +539,22 @@ interface ClaudeStreamMessage {
510
539
  text?: string;
511
540
  }>;
512
541
  thinking?: string;
542
+ /** On a `tool_result` block: the CLI-executed tool failed. */
543
+ is_error?: boolean;
513
544
  }>;
514
545
  };
546
+ apiKeySource?: string;
547
+ permissionMode?: string;
548
+ model?: string;
549
+ claude_code_version?: string;
550
+ tools?: string[];
551
+ mcp_servers?: Array<{
552
+ name?: string;
553
+ status?: string;
554
+ }>;
555
+ compact_metadata?: Record<string, unknown>;
556
+ compactMetadata?: Record<string, unknown>;
557
+ rate_limit_info?: Record<string, unknown>;
515
558
  tool?: {
516
559
  name?: string;
517
560
  id?: string;
@@ -533,6 +576,24 @@ interface ClaudeStreamMessage {
533
576
  result?: string;
534
577
  is_error?: boolean;
535
578
  num_turns?: number;
579
+ stop_reason?: string | null;
580
+ /**
581
+ * Per-model totals on `result`, keyed by model id: `inputTokens`,
582
+ * `outputTokens`, `cacheReadInputTokens`, `cacheCreationInputTokens`,
583
+ * `webSearchRequests`, `costUSD`. All numeric, which is what makes it safe
584
+ * to forward whole into `providerMetadata`.
585
+ */
586
+ modelUsage?: Record<string, Record<string, number>>;
587
+ /**
588
+ * Tool calls the CLI's permission layer refused during the turn. Each entry
589
+ * also carries a `tool_input` on the wire; it is deliberately not declared
590
+ * here, because it can be a whole file's contents and must not be copied
591
+ * into provider metadata.
592
+ */
593
+ permission_denials?: Array<{
594
+ tool_name?: string;
595
+ tool_use_id?: string;
596
+ }>;
536
597
  usage?: {
537
598
  input_tokens?: number;
538
599
  output_tokens?: number;
@@ -768,6 +829,17 @@ declare const DEFAULT_PROXY_TOOL_NAMES: string[];
768
829
  * so a user-defined command keeps opencode's normal behaviour end to end.
769
830
  */
770
831
  declare function registerSideQuestionCommand(config: OpenCodeConfig): boolean;
832
+ /**
833
+ * Registers `/claude-code-doctor` unless the user defined their own command of
834
+ * that name. Unlike `/btw` there is no hook to guard: the command is a plain
835
+ * template and the language model answers the message it produces, so leaving
836
+ * a user definition alone here is the whole guard.
837
+ *
838
+ * The name carries no slash. opencode invokes a command as `/<key>` and takes
839
+ * everything after the first space as `$ARGUMENTS`, so `claude-code doctor`
840
+ * would be the command `claude-code` with the argument `doctor`.
841
+ */
842
+ declare function registerDoctorCommand(config: OpenCodeConfig): boolean;
771
843
  declare function _resetPlanModeWarningForTests(): void;
772
844
  declare function warnIfPlanModeCannotExit(permissionMode: string | undefined): void;
773
845
  declare function createClaudeCode(settings?: ClaudeCodeProviderSettings): ClaudeCodeProvider;
@@ -783,9 +855,15 @@ declare function configModelsForProvider(providerModels: OpenCodeProvider["model
783
855
  * diagnostics never report another provider's options.
784
856
  */
785
857
  declare function claudeCodeProviders(providers: Record<string, DiagnosticsProviderEntry> | undefined): Record<string, DiagnosticsProviderEntry>;
858
+ /**
859
+ * The opencode session id a `session.deleted` bus event names, or undefined
860
+ * for any other event. opencode publishes `{ type, properties: { info } }`
861
+ * under `payload`, and the deleted session's own record is `properties.info`.
862
+ */
863
+ declare function extractDeletedSessionId(event: OpenCodeEvent | undefined): string | undefined;
786
864
  declare const _default: {
787
865
  id: string;
788
866
  server: OpenCodePlugin;
789
867
  };
790
868
 
791
- export { type AgentRecord, type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, DEFAULT_PROXY_TOOL_NAMES, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, _resetPlanModeWarningForTests, bridgeOpencodeMcp, claudeCodeProviders, configModelsForProvider, createClaudeCode, _default as default, defaultModels, getAgentRegistry, getDefaultSubagentModel, registerSideQuestionCommand, resolveAgentModel, warnIfPlanModeCannotExit };
869
+ export { type AgentRecord, type ClaudeCodeConfig, ClaudeCodeLanguageModel, type ClaudeCodeProvider, type ClaudeCodeProviderSettings, type ClaudeStreamMessage, DEFAULT_PROXY_TOOL_NAMES, type OpenCodeHooks, type OpenCodeModel, type OpenCodePlugin, _resetPlanModeWarningForTests, bridgeOpencodeMcp, claudeCodeProviders, configModelsForProvider, createClaudeCode, _default as default, defaultModels, extractDeletedSessionId, getAgentRegistry, getDefaultSubagentModel, registerDoctorCommand, registerSideQuestionCommand, resolveAgentModel, warnIfPlanModeCannotExit };