oh-my-opencode 2.12.0 → 2.12.1

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/cli/index.js CHANGED
@@ -2657,7 +2657,7 @@ var require_napi = __commonJS((exports, module) => {
2657
2657
  var require_package = __commonJS((exports, module) => {
2658
2658
  module.exports = {
2659
2659
  name: "oh-my-opencode",
2660
- version: "2.11.0",
2660
+ version: "2.12.0",
2661
2661
  description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
2662
2662
  main: "dist/index.js",
2663
2663
  types: "dist/index.d.ts",
@@ -22575,7 +22575,8 @@ var HookNameSchema = exports_external.enum([
22575
22575
  "preemptive-compaction",
22576
22576
  "compaction-context-injector",
22577
22577
  "claude-code-hooks",
22578
- "auto-slash-command"
22578
+ "auto-slash-command",
22579
+ "edit-error-recovery"
22579
22580
  ]);
22580
22581
  var BuiltinCommandNameSchema = exports_external.enum([
22581
22582
  "init-deep"
@@ -61,6 +61,7 @@ export declare const HookNameSchema: z.ZodEnum<{
61
61
  "compaction-context-injector": "compaction-context-injector";
62
62
  "claude-code-hooks": "claude-code-hooks";
63
63
  "auto-slash-command": "auto-slash-command";
64
+ "edit-error-recovery": "edit-error-recovery";
64
65
  }>;
65
66
  export declare const BuiltinCommandNameSchema: z.ZodEnum<{
66
67
  "init-deep": "init-deep";
@@ -816,6 +817,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
816
817
  "compaction-context-injector": "compaction-context-injector";
817
818
  "claude-code-hooks": "claude-code-hooks";
818
819
  "auto-slash-command": "auto-slash-command";
820
+ "edit-error-recovery": "edit-error-recovery";
819
821
  }>>>;
820
822
  disabled_commands: z.ZodOptional<z.ZodArray<z.ZodEnum<{
821
823
  "init-deep": "init-deep";
@@ -35,6 +35,7 @@ export declare class BackgroundManager {
35
35
  private notifyParentSession;
36
36
  private formatDuration;
37
37
  private hasRunningTasks;
38
+ private pruneStaleTasksAndNotifications;
38
39
  private pollRunningTasks;
39
40
  }
40
41
  export {};
@@ -0,0 +1,31 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ /**
3
+ * Known Edit tool error patterns that indicate the AI made a mistake
4
+ */
5
+ export declare const EDIT_ERROR_PATTERNS: readonly ["oldString and newString must be different", "oldString not found", "oldString found multiple times"];
6
+ /**
7
+ * System reminder injected when Edit tool fails due to AI mistake
8
+ * Short, direct, and commanding - forces immediate corrective action
9
+ */
10
+ export declare const EDIT_ERROR_REMINDER = "\n[EDIT ERROR - IMMEDIATE ACTION REQUIRED]\n\nYou made an Edit mistake. STOP and do this NOW:\n\n1. READ the file immediately to see its ACTUAL current state\n2. VERIFY what the content really looks like (your assumption was wrong)\n3. APOLOGIZE briefly to the user for the error\n4. CONTINUE with corrected action based on the real file content\n\nDO NOT attempt another edit until you've read and verified the file state.\n";
11
+ /**
12
+ * Detects Edit tool errors caused by AI mistakes and injects a recovery reminder
13
+ *
14
+ * This hook catches common Edit tool failures:
15
+ * - oldString and newString must be different (trying to "edit" to same content)
16
+ * - oldString not found (wrong assumption about file content)
17
+ * - oldString found multiple times (ambiguous match, need more context)
18
+ *
19
+ * @see https://github.com/sst/opencode/issues/4718
20
+ */
21
+ export declare function createEditErrorRecoveryHook(_ctx: PluginInput): {
22
+ "tool.execute.after": (input: {
23
+ tool: string;
24
+ sessionID: string;
25
+ callID: string;
26
+ }, output: {
27
+ title: string;
28
+ output: string;
29
+ metadata: unknown;
30
+ }) => Promise<void>;
31
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -23,3 +23,4 @@ export { createEmptyMessageSanitizerHook } from "./empty-message-sanitizer";
23
23
  export { createThinkingBlockValidatorHook } from "./thinking-block-validator";
24
24
  export { createRalphLoopHook, type RalphLoopHook } from "./ralph-loop";
25
25
  export { createAutoSlashCommandHook } from "./auto-slash-command";
26
+ export { createEditErrorRecoveryHook } from "./edit-error-recovery";
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js CHANGED
@@ -8557,6 +8557,7 @@ Incomplete tasks remain in your todo list. Continue working on the next pending
8557
8557
  - Do not stop until all tasks are done`;
8558
8558
  var COUNTDOWN_SECONDS = 2;
8559
8559
  var TOAST_DURATION_MS = 900;
8560
+ var COUNTDOWN_GRACE_PERIOD_MS = 500;
8560
8561
  function getMessageDir(sessionID) {
8561
8562
  if (!existsSync2(MESSAGE_STORAGE))
8562
8563
  return null;
@@ -8616,6 +8617,7 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
8616
8617
  clearInterval(state2.countdownInterval);
8617
8618
  state2.countdownInterval = undefined;
8618
8619
  }
8620
+ state2.countdownStartedAt = undefined;
8619
8621
  }
8620
8622
  function cleanup(sessionID) {
8621
8623
  cancelCountdown(sessionID);
@@ -8705,6 +8707,7 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
8705
8707
  cancelCountdown(sessionID);
8706
8708
  let secondsRemaining = COUNTDOWN_SECONDS;
8707
8709
  showCountdownToast(secondsRemaining, incompleteCount);
8710
+ state2.countdownStartedAt = Date.now();
8708
8711
  state2.countdownInterval = setInterval(() => {
8709
8712
  secondsRemaining--;
8710
8713
  if (secondsRemaining > 0) {
@@ -8788,6 +8791,13 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
8788
8791
  state2.lastEventWasAbortError = false;
8789
8792
  }
8790
8793
  if (role === "user") {
8794
+ if (state2?.countdownStartedAt) {
8795
+ const elapsed = Date.now() - state2.countdownStartedAt;
8796
+ if (elapsed < COUNTDOWN_GRACE_PERIOD_MS) {
8797
+ log(`[${HOOK_NAME}] Ignoring user message in grace period`, { sessionID, elapsed });
8798
+ return;
8799
+ }
8800
+ }
8791
8801
  cancelCountdown(sessionID);
8792
8802
  log(`[${HOOK_NAME}] User message: cleared abort state`, { sessionID });
8793
8803
  }
@@ -11844,7 +11854,7 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
11844
11854
  setTimeout(async () => {
11845
11855
  try {
11846
11856
  await client.session.prompt_async({
11847
- path: { sessionID },
11857
+ path: { id: sessionID },
11848
11858
  body: { parts: [{ type: "text", text: "Continue" }] },
11849
11859
  query: { directory }
11850
11860
  });
@@ -11910,7 +11920,7 @@ async function executeCompact(sessionID, msg, autoCompactState, client, director
11910
11920
  setTimeout(async () => {
11911
11921
  try {
11912
11922
  await client.session.prompt_async({
11913
- path: { sessionID },
11923
+ path: { id: sessionID },
11914
11924
  body: { parts: [{ type: "text", text: "Continue" }] },
11915
11925
  query: { directory }
11916
11926
  });
@@ -19039,6 +19049,17 @@ function detectBannedCommand(command) {
19039
19049
  }
19040
19050
  return;
19041
19051
  }
19052
+ function shellEscape(value) {
19053
+ if (value === "")
19054
+ return "''";
19055
+ if (/[^a-zA-Z0-9_\-.:\/]/.test(value)) {
19056
+ return `'${value.replace(/'/g, "'\\''")}'`;
19057
+ }
19058
+ return value;
19059
+ }
19060
+ function buildEnvPrefix(env) {
19061
+ return Object.entries(env).map(([key, value]) => `${key}=${shellEscape(value)}`).join(" \\\n");
19062
+ }
19042
19063
  function createNonInteractiveEnvHook(_ctx) {
19043
19064
  return {
19044
19065
  "tool.execute.before": async (input, output) => {
@@ -19049,18 +19070,19 @@ function createNonInteractiveEnvHook(_ctx) {
19049
19070
  if (!command) {
19050
19071
  return;
19051
19072
  }
19052
- output.args.env = {
19053
- ...process.env,
19054
- ...output.args.env,
19055
- ...NON_INTERACTIVE_ENV
19056
- };
19057
19073
  const bannedCmd = detectBannedCommand(command);
19058
19074
  if (bannedCmd) {
19059
19075
  output.message = `\u26A0\uFE0F Warning: '${bannedCmd}' is an interactive command that may hang in non-interactive environments.`;
19060
19076
  }
19061
- log(`[${HOOK_NAME2}] Set non-interactive environment variables`, {
19077
+ const isGitCommand = /\bgit\b/.test(command);
19078
+ if (!isGitCommand) {
19079
+ return;
19080
+ }
19081
+ const envPrefix = buildEnvPrefix(NON_INTERACTIVE_ENV);
19082
+ output.args.command = `${envPrefix} ${command}`;
19083
+ log(`[${HOOK_NAME2}] Prepended non-interactive env vars to git command`, {
19062
19084
  sessionID: input.sessionID,
19063
- env: NON_INTERACTIVE_ENV
19085
+ envPrefix
19064
19086
  });
19065
19087
  }
19066
19088
  };
@@ -19828,7 +19850,7 @@ function extractPromptText3(parts) {
19828
19850
 
19829
19851
  // src/hooks/auto-slash-command/executor.ts
19830
19852
  import { existsSync as existsSync35, readdirSync as readdirSync12, readFileSync as readFileSync24 } from "fs";
19831
- import { join as join43, basename as basename2, dirname as dirname9 } from "path";
19853
+ import { join as join43, basename as basename2, dirname as dirname8 } from "path";
19832
19854
  import { homedir as homedir13 } from "os";
19833
19855
  // src/features/opencode-skill-loader/loader.ts
19834
19856
  import { existsSync as existsSync33, readdirSync as readdirSync11, readFileSync as readFileSync22 } from "fs";
@@ -20030,7 +20052,7 @@ function discoverOpencodeProjectSkills() {
20030
20052
  }
20031
20053
  // src/features/opencode-skill-loader/merger.ts
20032
20054
  import { readFileSync as readFileSync23, existsSync as existsSync34 } from "fs";
20033
- import { dirname as dirname8, resolve as resolve5, isAbsolute as isAbsolute2 } from "path";
20055
+ import { dirname as dirname7, resolve as resolve5, isAbsolute as isAbsolute2 } from "path";
20034
20056
  import { homedir as homedir12 } from "os";
20035
20057
  var SCOPE_PRIORITY = {
20036
20058
  builtin: 1,
@@ -20103,7 +20125,7 @@ function configEntryToLoaded(name, entry, configDir) {
20103
20125
  return null;
20104
20126
  }
20105
20127
  const description = entry.description || fileMetadata.description || "";
20106
- const resolvedPath = entry.from ? dirname8(resolveFilePath2(entry.from, configDir)) : configDir || process.cwd();
20128
+ const resolvedPath = entry.from ? dirname7(resolveFilePath2(entry.from, configDir)) : configDir || process.cwd();
20107
20129
  const wrappedTemplate = `<skill-instruction>
20108
20130
  Base directory for this skill: ${resolvedPath}/
20109
20131
  File references (@path) in this skill are relative to this directory.
@@ -20333,7 +20355,7 @@ async function formatCommandTemplate(cmd, args) {
20333
20355
  `);
20334
20356
  sections.push(`## Command Instructions
20335
20357
  `);
20336
- const commandDir = cmd.path ? dirname9(cmd.path) : process.cwd();
20358
+ const commandDir = cmd.path ? dirname8(cmd.path) : process.cwd();
20337
20359
  const withFileRefs = await resolveFileReferencesInText(cmd.content || "", commandDir);
20338
20360
  const resolvedContent = await resolveCommandsInText(withFileRefs);
20339
20361
  sections.push(resolvedContent.trim());
@@ -20424,6 +20446,38 @@ ${AUTO_SLASH_COMMAND_TAG_CLOSE}`;
20424
20446
  }
20425
20447
  };
20426
20448
  }
20449
+ // src/hooks/edit-error-recovery/index.ts
20450
+ var EDIT_ERROR_PATTERNS = [
20451
+ "oldString and newString must be different",
20452
+ "oldString not found",
20453
+ "oldString found multiple times"
20454
+ ];
20455
+ var EDIT_ERROR_REMINDER = `
20456
+ [EDIT ERROR - IMMEDIATE ACTION REQUIRED]
20457
+
20458
+ You made an Edit mistake. STOP and do this NOW:
20459
+
20460
+ 1. READ the file immediately to see its ACTUAL current state
20461
+ 2. VERIFY what the content really looks like (your assumption was wrong)
20462
+ 3. APOLOGIZE briefly to the user for the error
20463
+ 4. CONTINUE with corrected action based on the real file content
20464
+
20465
+ DO NOT attempt another edit until you've read and verified the file state.
20466
+ `;
20467
+ function createEditErrorRecoveryHook(_ctx) {
20468
+ return {
20469
+ "tool.execute.after": async (input, output) => {
20470
+ if (input.tool.toLowerCase() !== "edit")
20471
+ return;
20472
+ const outputLower = output.output.toLowerCase();
20473
+ const hasEditError = EDIT_ERROR_PATTERNS.some((pattern) => outputLower.includes(pattern.toLowerCase()));
20474
+ if (hasEditError) {
20475
+ output.output += `
20476
+ ${EDIT_ERROR_REMINDER}`;
20477
+ }
20478
+ }
20479
+ };
20480
+ }
20427
20481
  // src/auth/antigravity/constants.ts
20428
20482
  var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
20429
20483
  var ANTIGRAVITY_CLIENT_SECRET = "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";
@@ -36458,7 +36512,7 @@ var lsp_code_action_resolve = tool({
36458
36512
  });
36459
36513
  // src/tools/ast-grep/constants.ts
36460
36514
  import { createRequire as createRequire4 } from "module";
36461
- import { dirname as dirname10, join as join47 } from "path";
36515
+ import { dirname as dirname9, join as join47 } from "path";
36462
36516
  import { existsSync as existsSync40, statSync as statSync4 } from "fs";
36463
36517
 
36464
36518
  // src/tools/ast-grep/downloader.ts
@@ -36601,7 +36655,7 @@ function findSgCliPathSync() {
36601
36655
  try {
36602
36656
  const require2 = createRequire4(import.meta.url);
36603
36657
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
36604
- const cliDir = dirname10(cliPkgPath);
36658
+ const cliDir = dirname9(cliPkgPath);
36605
36659
  const sgPath = join47(cliDir, binaryName);
36606
36660
  if (existsSync40(sgPath) && isValidBinary(sgPath)) {
36607
36661
  return sgPath;
@@ -36612,7 +36666,7 @@ function findSgCliPathSync() {
36612
36666
  try {
36613
36667
  const require2 = createRequire4(import.meta.url);
36614
36668
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
36615
- const pkgDir = dirname10(pkgPath);
36669
+ const pkgDir = dirname9(pkgPath);
36616
36670
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
36617
36671
  const binaryPath = join47(pkgDir, astGrepName);
36618
36672
  if (existsSync40(binaryPath) && isValidBinary(binaryPath)) {
@@ -36989,7 +37043,7 @@ var {spawn: spawn9 } = globalThis.Bun;
36989
37043
 
36990
37044
  // src/tools/grep/constants.ts
36991
37045
  import { existsSync as existsSync43 } from "fs";
36992
- import { join as join49, dirname as dirname11 } from "path";
37046
+ import { join as join49, dirname as dirname10 } from "path";
36993
37047
  import { spawnSync } from "child_process";
36994
37048
 
36995
37049
  // src/tools/grep/downloader.ts
@@ -37154,7 +37208,7 @@ function findExecutable(name) {
37154
37208
  }
37155
37209
  function getOpenCodeBundledRg() {
37156
37210
  const execPath = process.execPath;
37157
- const execDir = dirname11(execPath);
37211
+ const execDir = dirname10(execPath);
37158
37212
  const isWindows2 = process.platform === "win32";
37159
37213
  const rgName = isWindows2 ? "rg.exe" : "rg";
37160
37214
  const candidates = [
@@ -37619,7 +37673,7 @@ var glob = tool({
37619
37673
  });
37620
37674
  // src/tools/slashcommand/tools.ts
37621
37675
  import { existsSync as existsSync44, readdirSync as readdirSync14, readFileSync as readFileSync29 } from "fs";
37622
- import { join as join50, basename as basename3, dirname as dirname12 } from "path";
37676
+ import { join as join50, basename as basename3, dirname as dirname11 } from "path";
37623
37677
  function discoverCommandsFromDir2(commandsDir, scope) {
37624
37678
  if (!existsSync44(commandsDir)) {
37625
37679
  return [];
@@ -37725,7 +37779,7 @@ async function formatLoadedCommand(cmd) {
37725
37779
  `);
37726
37780
  sections.push(`## Command Instructions
37727
37781
  `);
37728
- const commandDir = cmd.path ? dirname12(cmd.path) : process.cwd();
37782
+ const commandDir = cmd.path ? dirname11(cmd.path) : process.cwd();
37729
37783
  const withFileRefs = await resolveFileReferencesInText(cmd.content || "", commandDir);
37730
37784
  const resolvedContent = await resolveCommandsInText(withFileRefs);
37731
37785
  sections.push(resolvedContent.trim());
@@ -38511,7 +38565,7 @@ var TOOL_DESCRIPTION_PREFIX = `Load a skill to get detailed instructions for a s
38511
38565
  Skills provide specialized knowledge and step-by-step guidance.
38512
38566
  Use this when a task matches an available skill's description.`;
38513
38567
  // src/tools/skill/tools.ts
38514
- import { dirname as dirname13 } from "path";
38568
+ import { dirname as dirname12 } from "path";
38515
38569
  import { readFileSync as readFileSync30 } from "fs";
38516
38570
  function loadedSkillToInfo(skill) {
38517
38571
  return {
@@ -38633,7 +38687,7 @@ function createSkillTool(options = {}) {
38633
38687
  throw new Error(`Skill "${args.name}" not found. Available skills: ${available || "none"}`);
38634
38688
  }
38635
38689
  const body = extractSkillBody(skill);
38636
- const dir = skill.path ? dirname13(skill.path) : skill.resolvedPath || process.cwd();
38690
+ const dir = skill.path ? dirname12(skill.path) : skill.resolvedPath || process.cwd();
38637
38691
  const output = [
38638
38692
  `## Skill: ${skill.name}`,
38639
38693
  "",
@@ -39405,6 +39459,7 @@ var builtinTools = {
39405
39459
  // src/features/background-agent/manager.ts
39406
39460
  import { existsSync as existsSync47, readdirSync as readdirSync17 } from "fs";
39407
39461
  import { join as join54 } from "path";
39462
+ var TASK_TTL_MS = 30 * 60 * 1000;
39408
39463
  function getMessageDir11(sessionID) {
39409
39464
  if (!existsSync47(MESSAGE_STORAGE))
39410
39465
  return null;
@@ -39670,11 +39725,11 @@ class BackgroundManager {
39670
39725
  },
39671
39726
  query: { directory: this.directory }
39672
39727
  });
39673
- this.clearNotificationsForTask(taskId);
39674
39728
  log("[background-agent] Successfully sent prompt to parent session:", { parentSessionID: task.parentSessionID });
39675
39729
  } catch (error45) {
39676
39730
  log("[background-agent] prompt failed:", String(error45));
39677
39731
  } finally {
39732
+ this.clearNotificationsForTask(taskId);
39678
39733
  this.tasks.delete(taskId);
39679
39734
  log("[background-agent] Removed completed task from memory:", taskId);
39680
39735
  }
@@ -39699,7 +39754,38 @@ class BackgroundManager {
39699
39754
  }
39700
39755
  return false;
39701
39756
  }
39757
+ pruneStaleTasksAndNotifications() {
39758
+ const now = Date.now();
39759
+ for (const [taskId, task] of this.tasks.entries()) {
39760
+ const age = now - task.startedAt.getTime();
39761
+ if (age > TASK_TTL_MS) {
39762
+ log("[background-agent] Pruning stale task:", { taskId, age: Math.round(age / 1000) + "s" });
39763
+ task.status = "error";
39764
+ task.error = "Task timed out after 30 minutes";
39765
+ task.completedAt = new Date;
39766
+ this.clearNotificationsForTask(taskId);
39767
+ this.tasks.delete(taskId);
39768
+ subagentSessions.delete(task.sessionID);
39769
+ }
39770
+ }
39771
+ for (const [sessionID, notifications] of this.notifications.entries()) {
39772
+ if (notifications.length === 0) {
39773
+ this.notifications.delete(sessionID);
39774
+ continue;
39775
+ }
39776
+ const validNotifications = notifications.filter((task) => {
39777
+ const age = now - task.startedAt.getTime();
39778
+ return age <= TASK_TTL_MS;
39779
+ });
39780
+ if (validNotifications.length === 0) {
39781
+ this.notifications.delete(sessionID);
39782
+ } else if (validNotifications.length !== notifications.length) {
39783
+ this.notifications.set(sessionID, validNotifications);
39784
+ }
39785
+ }
39786
+ }
39702
39787
  async pollRunningTasks() {
39788
+ this.pruneStaleTasksAndNotifications();
39703
39789
  const statusResult = await this.client.session.status();
39704
39790
  const allStatuses = statusResult.data ?? {};
39705
39791
  for (const task of this.tasks.values()) {
@@ -42511,7 +42597,8 @@ var HookNameSchema = exports_external.enum([
42511
42597
  "preemptive-compaction",
42512
42598
  "compaction-context-injector",
42513
42599
  "claude-code-hooks",
42514
- "auto-slash-command"
42600
+ "auto-slash-command",
42601
+ "edit-error-recovery"
42515
42602
  ]);
42516
42603
  var BuiltinCommandNameSchema = exports_external.enum([
42517
42604
  "init-deep"
@@ -45646,6 +45733,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
45646
45733
  const thinkingBlockValidator = isHookEnabled("thinking-block-validator") ? createThinkingBlockValidatorHook() : null;
45647
45734
  const ralphLoop = isHookEnabled("ralph-loop") ? createRalphLoopHook(ctx, { config: pluginConfig.ralph_loop }) : null;
45648
45735
  const autoSlashCommand = isHookEnabled("auto-slash-command") ? createAutoSlashCommandHook() : null;
45736
+ const editErrorRecovery = isHookEnabled("edit-error-recovery") ? createEditErrorRecoveryHook(ctx) : null;
45649
45737
  const backgroundManager = new BackgroundManager(ctx);
45650
45738
  const todoContinuationEnforcer = isHookEnabled("todo-continuation-enforcer") ? createTodoContinuationEnforcer(ctx, { backgroundManager }) : null;
45651
45739
  if (sessionRecovery && todoContinuationEnforcer) {
@@ -45840,6 +45928,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
45840
45928
  await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
45841
45929
  await agentUsageReminder?.["tool.execute.after"](input, output);
45842
45930
  await interactiveBashSession?.["tool.execute.after"](input, output);
45931
+ await editErrorRecovery?.["tool.execute.after"](input, output);
45843
45932
  }
45844
45933
  };
45845
45934
  };
@@ -2,4 +2,4 @@ import type { AnalyzeResult, SgResult } from "./types";
2
2
  export declare function formatSearchResult(result: SgResult): string;
3
3
  export declare function formatReplaceResult(result: SgResult, isDryRun: boolean): string;
4
4
  export declare function formatAnalyzeResult(results: AnalyzeResult[], extractedMetaVars: boolean): string;
5
- export declare function formatTransformResult(original: string, transformed: string, editCount: number): string;
5
+ export declare function formatTransformResult(_original: string, transformed: string, editCount: number): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "2.12.0",
3
+ "version": "2.12.1",
4
4
  "description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",