oh-my-opencode 0.1.25 → 0.1.26

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/README.ko.md CHANGED
@@ -151,12 +151,22 @@ OpenCode 는 아주 확장가능하고 아주 커스터마이저블합니다.
151
151
  - **frontend-ui-ux-engineer** (`google/gemini-3-pro-preview`): 개발자로 전향한 디자이너라는 설정을 갖고 있습니다. 멋진 UI를 만듭니다. 아름답고 창의적인 UI 코드를 생성하는 데 탁월한 Gemini를 사용합니다.
152
152
  - **document-writer** (`google/gemini-3-pro-preview`): 기술 문서 전문가라는 설정을 갖고 있습니다. Gemini 는 문학가입니다. 글을 기가막히게 씁니다.
153
153
 
154
+ 각 에이전트는 메인 에이전트가 알아서 호출하지만, 명시적으로 요청할 수도 있습니다:
155
+
156
+ ```
157
+ @oracle 한테 이 부분 설계 고민하고서 아키텍쳐 제안을 부탁해줘
158
+ @librarian 한테 이 부분 어떻게 구현돼있길래 자꾸 안에서 동작이 바뀌는지 알려달라고 해줘
159
+ @explore 한테 이 기능 정책 알려달라고 해줘
160
+ ```
161
+
154
162
  에이전트의 모델, 프롬프트, 권한은 `oh-my-opencode.json`에서 커스텀할 수 있습니다. 자세한 내용은 [설정](#설정)을 참고하세요.
155
163
 
156
164
  ### Tools
157
165
 
158
166
  #### 내장 LSP Tools
159
167
 
168
+ 당신이 에디터에서 사용하는 그 기능을 다른 에이전트들은 사용하지 못합니다. Oh My OpenCode 는 당신만의 그 도구를 LLM Agent 에게 쥐어줍니다. 리팩토링하고, 탐색하고, 분석하는 모든 작업을 OpenCode 의 설정값을 그대로 사용하여 지원합니다.
169
+
160
170
  [OpenCode 는 LSP 를 제공하지만](https://opencode.ai/docs/lsp/), 오로지 분석용으로만 제공합니다. 탐색과 리팩토링을 위한 도구는 OpenCode 와 동일한 스펙과 설정으로 Oh My OpenCode 가 제공합니다.
161
171
 
162
172
  - **lsp_hover**: 위치의 타입 정보, 문서, 시그니처 가져오기
package/README.md CHANGED
@@ -146,12 +146,22 @@ I believe in the right tool for the job. For your wallet's sake, use CLIProxyAPI
146
146
  - **frontend-ui-ux-engineer** (`google/gemini-3-pro-preview`): A designer turned developer. Creates stunning UIs. Uses Gemini because its creativity and UI code generation are superior.
147
147
  - **document-writer** (`google/gemini-3-pro-preview`): A technical writing expert. Gemini is a wordsmith; it writes prose that flows naturally.
148
148
 
149
+ Each agent is automatically invoked by the main agent, but you can also explicitly request them:
150
+
151
+ ```
152
+ @oracle Please think through the design of this part and suggest an architecture.
153
+ @librarian Tell me how this is implemented — why does the behavior keep changing internally?
154
+ @explore Tell me about the policy for this feature.
155
+ ```
156
+
149
157
  Agent models, prompts, and permissions can be customized via `oh-my-opencode.json`. See [Configuration](#configuration) for details.
150
158
 
151
159
  ### Tools
152
160
 
153
161
  #### Built-in LSP Tools
154
162
 
163
+ The features you use in your editor—other agents cannot access them. Oh My OpenCode hands those very tools to your LLM Agent. Refactoring, navigation, and analysis are all supported using the same OpenCode configuration.
164
+
155
165
  [OpenCode provides LSP](https://opencode.ai/docs/lsp/), but only for analysis. Oh My OpenCode equips you with navigation and refactoring tools matching the same specification.
156
166
 
157
167
  - **lsp_hover**: Get type info, docs, signatures at position
@@ -0,0 +1,12 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ export declare function createGrepOutputTruncatorHook(ctx: PluginInput): {
3
+ "tool.execute.after": (input: {
4
+ tool: string;
5
+ sessionID: string;
6
+ callID: string;
7
+ }, output: {
8
+ title: string;
9
+ output: string;
10
+ metadata: unknown;
11
+ }) => Promise<void>;
12
+ };
@@ -3,3 +3,5 @@ export { createContextWindowMonitorHook } from "./context-window-monitor";
3
3
  export { createSessionNotification } from "./session-notification";
4
4
  export { createSessionRecoveryHook } from "./session-recovery";
5
5
  export { createCommentCheckerHooks } from "./comment-checker";
6
+ export { createGrepOutputTruncatorHook } from "./grep-output-truncator";
7
+ export { createPulseMonitorHook } from "./pulse-monitor";
@@ -0,0 +1,10 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ export declare function createPulseMonitorHook(ctx: PluginInput): {
3
+ event: (input: {
4
+ event: any;
5
+ }) => Promise<void>;
6
+ "tool.execute.before": () => Promise<void>;
7
+ "tool.execute.after": (input: {
8
+ sessionID: string;
9
+ }) => Promise<void>;
10
+ };
package/dist/index.js CHANGED
@@ -602,18 +602,13 @@ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}) {
602
602
  return result;
603
603
  }
604
604
  // src/hooks/todo-continuation-enforcer.ts
605
- var CONTINUATION_PROMPT = `[SYSTEM REMINDER - TODO ENFORCEMENT]
605
+ var CONTINUATION_PROMPT = `[SYSTEM REMINDER - TODO CONTINUATION]
606
606
 
607
- Your todo list is NOT complete. There are still incomplete tasks remaining.
607
+ Incomplete tasks remain in your todo list. Continue working on the next pending task.
608
608
 
609
- CRITICAL INSTRUCTION:
610
- - You MUST NOT stop working until ALL todos are marked as completed
611
- - Continue working on the next pending task immediately
612
- - Work honestly and diligently to finish every task
613
- - Do NOT ask for permission to continue - just proceed with the work
614
- - Mark each task as completed as soon as you finish it
615
-
616
- Resume your work NOW.`;
609
+ - Proceed without asking for permission
610
+ - Mark each task complete when finished
611
+ - Do not stop until all tasks are done`;
617
612
  function detectInterrupt(error) {
618
613
  if (!error)
619
614
  return false;
@@ -694,7 +689,7 @@ function createTodoContinuationEnforcer(ctx) {
694
689
  type: "text",
695
690
  text: `${CONTINUATION_PROMPT}
696
691
 
697
- [Status: ${incomplete.length}/${todos.length} tasks remaining]`
692
+ [Status: ${todos.length - incomplete.length}/${todos.length} completed, ${incomplete.length} remaining]`
698
693
  }
699
694
  ]
700
695
  },
@@ -1566,6 +1561,208 @@ ${result.message}`;
1566
1561
  debugLog3("CLI: no comments detected");
1567
1562
  }
1568
1563
  }
1564
+ // src/hooks/grep-output-truncator.ts
1565
+ var ANTHROPIC_ACTUAL_LIMIT2 = 200000;
1566
+ var CHARS_PER_TOKEN_ESTIMATE = 4;
1567
+ var TARGET_MAX_TOKENS = 50000;
1568
+ function estimateTokens(text) {
1569
+ return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);
1570
+ }
1571
+ function truncateToTokenLimit(output, maxTokens) {
1572
+ const currentTokens = estimateTokens(output);
1573
+ if (currentTokens <= maxTokens) {
1574
+ return { result: output, truncated: false };
1575
+ }
1576
+ const lines = output.split(`
1577
+ `);
1578
+ if (lines.length <= 3) {
1579
+ const maxChars = maxTokens * CHARS_PER_TOKEN_ESTIMATE;
1580
+ return {
1581
+ result: output.slice(0, maxChars) + `
1582
+
1583
+ [Output truncated due to context window limit]`,
1584
+ truncated: true
1585
+ };
1586
+ }
1587
+ const headerLines = lines.slice(0, 3);
1588
+ const contentLines = lines.slice(3);
1589
+ const headerText = headerLines.join(`
1590
+ `);
1591
+ const headerTokens = estimateTokens(headerText);
1592
+ const availableTokens = maxTokens - headerTokens - 50;
1593
+ if (availableTokens <= 0) {
1594
+ return {
1595
+ result: headerText + `
1596
+
1597
+ [Content truncated due to context window limit]`,
1598
+ truncated: true
1599
+ };
1600
+ }
1601
+ let resultLines = [];
1602
+ let currentTokenCount = 0;
1603
+ for (const line of contentLines) {
1604
+ const lineTokens = estimateTokens(line + `
1605
+ `);
1606
+ if (currentTokenCount + lineTokens > availableTokens) {
1607
+ break;
1608
+ }
1609
+ resultLines.push(line);
1610
+ currentTokenCount += lineTokens;
1611
+ }
1612
+ const truncatedContent = [...headerLines, ...resultLines].join(`
1613
+ `);
1614
+ const removedCount = contentLines.length - resultLines.length;
1615
+ return {
1616
+ result: truncatedContent + `
1617
+
1618
+ [${removedCount} more lines truncated due to context window limit]`,
1619
+ truncated: true
1620
+ };
1621
+ }
1622
+ function createGrepOutputTruncatorHook(ctx) {
1623
+ const GREP_TOOLS = ["safe_grep", "Grep"];
1624
+ const toolExecuteAfter = async (input, output) => {
1625
+ if (!GREP_TOOLS.includes(input.tool))
1626
+ return;
1627
+ const { sessionID } = input;
1628
+ try {
1629
+ const response = await ctx.client.session.messages({
1630
+ path: { id: sessionID }
1631
+ });
1632
+ const messages = response.data ?? response;
1633
+ const assistantMessages = messages.filter((m) => m.info.role === "assistant").map((m) => m.info);
1634
+ if (assistantMessages.length === 0)
1635
+ return;
1636
+ const totalInputTokens = assistantMessages.reduce((sum, m) => {
1637
+ const inputTokens = m.tokens?.input ?? 0;
1638
+ const cacheReadTokens = m.tokens?.cache?.read ?? 0;
1639
+ return sum + inputTokens + cacheReadTokens;
1640
+ }, 0);
1641
+ const remainingTokens = ANTHROPIC_ACTUAL_LIMIT2 - totalInputTokens;
1642
+ const maxOutputTokens = Math.min(remainingTokens * 0.5, TARGET_MAX_TOKENS);
1643
+ if (maxOutputTokens <= 0) {
1644
+ output.output = "[Output suppressed - context window exhausted]";
1645
+ return;
1646
+ }
1647
+ const { result, truncated } = truncateToTokenLimit(output.output, maxOutputTokens);
1648
+ if (truncated) {
1649
+ output.output = result;
1650
+ }
1651
+ } catch {}
1652
+ };
1653
+ return {
1654
+ "tool.execute.after": toolExecuteAfter
1655
+ };
1656
+ }
1657
+ // src/hooks/pulse-monitor.ts
1658
+ function createPulseMonitorHook(ctx) {
1659
+ const STANDARD_TIMEOUT = 5 * 60 * 1000;
1660
+ const THINKING_TIMEOUT = 5 * 60 * 1000;
1661
+ const CHECK_INTERVAL = 5 * 1000;
1662
+ let lastHeartbeat = Date.now();
1663
+ let isMonitoring = false;
1664
+ let currentSessionID = null;
1665
+ let monitorTimer = null;
1666
+ let isThinking = false;
1667
+ const startMonitoring = (sessionID) => {
1668
+ if (currentSessionID !== sessionID) {
1669
+ currentSessionID = sessionID;
1670
+ isThinking = false;
1671
+ }
1672
+ lastHeartbeat = Date.now();
1673
+ if (!isMonitoring) {
1674
+ isMonitoring = true;
1675
+ if (monitorTimer)
1676
+ clearInterval(monitorTimer);
1677
+ monitorTimer = setInterval(async () => {
1678
+ if (!isMonitoring || !currentSessionID)
1679
+ return;
1680
+ const timeSinceLastHeartbeat = Date.now() - lastHeartbeat;
1681
+ const currentTimeout = isThinking ? THINKING_TIMEOUT : STANDARD_TIMEOUT;
1682
+ if (timeSinceLastHeartbeat > currentTimeout) {
1683
+ await recoverStalledSession(currentSessionID, timeSinceLastHeartbeat, isThinking);
1684
+ }
1685
+ }, CHECK_INTERVAL);
1686
+ }
1687
+ };
1688
+ const stopMonitoring = () => {
1689
+ isMonitoring = false;
1690
+ if (monitorTimer) {
1691
+ clearInterval(monitorTimer);
1692
+ monitorTimer = null;
1693
+ }
1694
+ };
1695
+ const updateHeartbeat = (isThinkingUpdate) => {
1696
+ if (isMonitoring) {
1697
+ lastHeartbeat = Date.now();
1698
+ if (isThinkingUpdate !== undefined) {
1699
+ isThinking = isThinkingUpdate;
1700
+ }
1701
+ }
1702
+ };
1703
+ const recoverStalledSession = async (sessionID, stalledDuration, wasThinking) => {
1704
+ stopMonitoring();
1705
+ try {
1706
+ const durationSec = Math.round(stalledDuration / 1000);
1707
+ const typeStr = wasThinking ? "Thinking" : "Standard";
1708
+ await ctx.client.tui.showToast({
1709
+ body: {
1710
+ title: "Pulse Monitor: Cardiac Arrest",
1711
+ message: `Session stalled (${typeStr}) for ${durationSec}s. Defibrillating...`,
1712
+ variant: "error",
1713
+ duration: 5000
1714
+ }
1715
+ }).catch(() => {});
1716
+ await ctx.client.session.abort({ path: { id: sessionID } }).catch(() => {});
1717
+ await new Promise((resolve) => setTimeout(resolve, 1500));
1718
+ await ctx.client.session.prompt({
1719
+ path: { id: sessionID },
1720
+ body: { parts: [{ type: "text", text: "The connection was unstable and stalled. Please continue from where you left off." }] },
1721
+ query: { directory: ctx.directory }
1722
+ });
1723
+ startMonitoring(sessionID);
1724
+ } catch (err) {
1725
+ console.error("[PulseMonitor] Recovery failed:", err);
1726
+ stopMonitoring();
1727
+ }
1728
+ };
1729
+ return {
1730
+ event: async (input) => {
1731
+ const { event } = input;
1732
+ const props = event.properties;
1733
+ if (event.type === "session.updated" || event.type === "message.part.updated") {
1734
+ const sessionID = props?.info?.id || props?.sessionID;
1735
+ if (sessionID) {
1736
+ if (!isMonitoring)
1737
+ startMonitoring(sessionID);
1738
+ let thinkingUpdate = undefined;
1739
+ if (event.type === "message.part.updated") {
1740
+ const part = props?.part;
1741
+ if (part) {
1742
+ const THINKING_TYPES2 = ["thinking", "redacted_thinking", "reasoning"];
1743
+ if (THINKING_TYPES2.includes(part.type)) {
1744
+ thinkingUpdate = true;
1745
+ } else if (part.type === "text" || part.type === "tool_use") {
1746
+ thinkingUpdate = false;
1747
+ }
1748
+ }
1749
+ }
1750
+ updateHeartbeat(thinkingUpdate);
1751
+ }
1752
+ } else if (event.type === "session.idle" || event.type === "session.error" || event.type === "session.stopped") {
1753
+ stopMonitoring();
1754
+ }
1755
+ },
1756
+ "tool.execute.before": async () => {
1757
+ stopMonitoring();
1758
+ },
1759
+ "tool.execute.after": async (input) => {
1760
+ if (input.sessionID) {
1761
+ startMonitoring(input.sessionID);
1762
+ }
1763
+ }
1764
+ };
1765
+ }
1569
1766
  // src/features/terminal/title.ts
1570
1767
  var STATUS_ICONS = {
1571
1768
  ready: "",
@@ -1774,7 +1971,21 @@ var EXT_TO_LANG = {
1774
1971
  ".svelte": "svelte",
1775
1972
  ".astro": "astro",
1776
1973
  ".yaml": "yaml",
1777
- ".yml": "yaml"
1974
+ ".yml": "yaml",
1975
+ ".json": "json",
1976
+ ".jsonc": "jsonc",
1977
+ ".html": "html",
1978
+ ".htm": "html",
1979
+ ".css": "css",
1980
+ ".scss": "scss",
1981
+ ".less": "less",
1982
+ ".sh": "shellscript",
1983
+ ".bash": "shellscript",
1984
+ ".zsh": "shellscript",
1985
+ ".fish": "fish",
1986
+ ".md": "markdown",
1987
+ ".tf": "terraform",
1988
+ ".tfvars": "terraform"
1778
1989
  };
1779
1990
  // src/tools/lsp/config.ts
1780
1991
  import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
@@ -2067,6 +2278,7 @@ class LSPClient {
2067
2278
  openedFiles = new Set;
2068
2279
  stderrBuffer = [];
2069
2280
  processExited = false;
2281
+ diagnosticsStore = new Map;
2070
2282
  constructor(root, server) {
2071
2283
  this.root = root;
2072
2284
  this.server = server;
@@ -2191,7 +2403,11 @@ stderr: ${stderr}` : ""));
2191
2403
  this.buffer = this.buffer.slice(end);
2192
2404
  try {
2193
2405
  const msg = JSON.parse(content);
2194
- if ("id" in msg && "method" in msg) {
2406
+ if ("method" in msg && !("id" in msg)) {
2407
+ if (msg.method === "textDocument/publishDiagnostics" && msg.params?.uri) {
2408
+ this.diagnosticsStore.set(msg.params.uri, msg.params.diagnostics ?? []);
2409
+ }
2410
+ } else if ("id" in msg && "method" in msg) {
2195
2411
  this.handleServerRequest(msg.id, msg.method, msg.params);
2196
2412
  } else if ("id" in msg && this.pending.has(msg.id)) {
2197
2413
  const handler = this.pending.get(msg.id);
@@ -2253,9 +2469,15 @@ ${msg}`);
2253
2469
  \r
2254
2470
  ${msg}`);
2255
2471
  }
2256
- handleServerRequest(id, method, _params) {
2472
+ handleServerRequest(id, method, params) {
2257
2473
  if (method === "workspace/configuration") {
2258
- this.respond(id, [{}]);
2474
+ const items = params?.items ?? [];
2475
+ const result = items.map((item) => {
2476
+ if (item.section === "json")
2477
+ return { validate: { enable: true } };
2478
+ return {};
2479
+ });
2480
+ this.respond(id, result);
2259
2481
  } else if (method === "client/registerCapability") {
2260
2482
  this.respond(id, null);
2261
2483
  } else if (method === "window/workDoneProgress/create") {
@@ -2317,7 +2539,9 @@ ${msg}`);
2317
2539
  ...this.server.initialization
2318
2540
  });
2319
2541
  this.notify("initialized");
2320
- this.notify("workspace/didChangeConfiguration", { settings: {} });
2542
+ this.notify("workspace/didChangeConfiguration", {
2543
+ settings: { json: { validate: { enable: true } } }
2544
+ });
2321
2545
  await new Promise((r) => setTimeout(r, 300));
2322
2546
  }
2323
2547
  async openFile(filePath) {
@@ -2375,11 +2599,18 @@ ${msg}`);
2375
2599
  }
2376
2600
  async diagnostics(filePath) {
2377
2601
  const absPath = resolve(filePath);
2602
+ const uri = `file://${absPath}`;
2378
2603
  await this.openFile(absPath);
2379
2604
  await new Promise((r) => setTimeout(r, 500));
2380
- return this.send("textDocument/diagnostic", {
2381
- textDocument: { uri: `file://${absPath}` }
2382
- });
2605
+ try {
2606
+ const result = await this.send("textDocument/diagnostic", {
2607
+ textDocument: { uri }
2608
+ });
2609
+ if (result && typeof result === "object" && "items" in result) {
2610
+ return result;
2611
+ }
2612
+ } catch {}
2613
+ return { items: this.diagnosticsStore.get(uri) ?? [] };
2383
2614
  }
2384
2615
  async prepareRename(filePath, line, character) {
2385
2616
  const absPath = resolve(filePath);
@@ -2427,6 +2658,7 @@ ${msg}`);
2427
2658
  this.proc?.kill();
2428
2659
  this.proc = null;
2429
2660
  this.processExited = true;
2661
+ this.diagnosticsStore.clear();
2430
2662
  }
2431
2663
  }
2432
2664
  // src/tools/lsp/utils.ts
@@ -16495,7 +16727,9 @@ var OhMyOpenCodePlugin = async (ctx) => {
16495
16727
  const todoContinuationEnforcer = createTodoContinuationEnforcer(ctx);
16496
16728
  const contextWindowMonitor = createContextWindowMonitorHook(ctx);
16497
16729
  const sessionRecovery = createSessionRecoveryHook(ctx);
16730
+ const pulseMonitor = createPulseMonitorHook(ctx);
16498
16731
  const commentChecker = createCommentCheckerHooks();
16732
+ const grepOutputTruncator = createGrepOutputTruncatorHook(ctx);
16499
16733
  updateTerminalTitle({ sessionId: "main" });
16500
16734
  const pluginConfig = loadPluginConfig(ctx.directory);
16501
16735
  let mainSessionID;
@@ -16521,6 +16755,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
16521
16755
  event: async (input) => {
16522
16756
  await todoContinuationEnforcer(input);
16523
16757
  await contextWindowMonitor.event(input);
16758
+ await pulseMonitor.event(input);
16524
16759
  const { event } = input;
16525
16760
  const props = event.properties;
16526
16761
  if (event.type === "session.created") {
@@ -16603,6 +16838,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
16603
16838
  }
16604
16839
  },
16605
16840
  "tool.execute.before": async (input, output) => {
16841
+ await pulseMonitor["tool.execute.before"]();
16606
16842
  await commentChecker["tool.execute.before"](input, output);
16607
16843
  if (input.sessionID === mainSessionID) {
16608
16844
  updateTerminalTitle({
@@ -16615,6 +16851,8 @@ var OhMyOpenCodePlugin = async (ctx) => {
16615
16851
  }
16616
16852
  },
16617
16853
  "tool.execute.after": async (input, output) => {
16854
+ await pulseMonitor["tool.execute.after"](input);
16855
+ await grepOutputTruncator["tool.execute.after"](input, output);
16618
16856
  await contextWindowMonitor["tool.execute.after"](input, output);
16619
16857
  await commentChecker["tool.execute.after"](input, output);
16620
16858
  if (input.sessionID === mainSessionID) {
@@ -20,11 +20,11 @@ export declare const builtinTools: {
20
20
  swift: "swift";
21
21
  elixir: "elixir";
22
22
  yaml: "yaml";
23
- bash: "bash";
23
+ json: "json";
24
+ html: "html";
24
25
  css: "css";
26
+ bash: "bash";
25
27
  haskell: "haskell";
26
- html: "html";
27
- json: "json";
28
28
  kotlin: "kotlin";
29
29
  nix: "nix";
30
30
  scala: "scala";
@@ -37,7 +37,7 @@ export declare const builtinTools: {
37
37
  };
38
38
  execute(args: {
39
39
  pattern: string;
40
- lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "bash" | "css" | "haskell" | "html" | "json" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
40
+ lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "json" | "html" | "css" | "bash" | "haskell" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
41
41
  paths?: string[] | undefined;
42
42
  globs?: string[] | undefined;
43
43
  context?: number | undefined;
@@ -64,11 +64,11 @@ export declare const builtinTools: {
64
64
  swift: "swift";
65
65
  elixir: "elixir";
66
66
  yaml: "yaml";
67
- bash: "bash";
67
+ json: "json";
68
+ html: "html";
68
69
  css: "css";
70
+ bash: "bash";
69
71
  haskell: "haskell";
70
- html: "html";
71
- json: "json";
72
72
  kotlin: "kotlin";
73
73
  nix: "nix";
74
74
  scala: "scala";
@@ -82,7 +82,7 @@ export declare const builtinTools: {
82
82
  execute(args: {
83
83
  pattern: string;
84
84
  rewrite: string;
85
- lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "bash" | "css" | "haskell" | "html" | "json" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
85
+ lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "json" | "html" | "css" | "bash" | "haskell" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
86
86
  paths?: string[] | undefined;
87
87
  globs?: string[] | undefined;
88
88
  dryRun?: boolean | undefined;
@@ -18,11 +18,11 @@ export declare const ast_grep_search: {
18
18
  swift: "swift";
19
19
  elixir: "elixir";
20
20
  yaml: "yaml";
21
- bash: "bash";
21
+ json: "json";
22
+ html: "html";
22
23
  css: "css";
24
+ bash: "bash";
23
25
  haskell: "haskell";
24
- html: "html";
25
- json: "json";
26
26
  kotlin: "kotlin";
27
27
  nix: "nix";
28
28
  scala: "scala";
@@ -35,7 +35,7 @@ export declare const ast_grep_search: {
35
35
  };
36
36
  execute(args: {
37
37
  pattern: string;
38
- lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "bash" | "css" | "haskell" | "html" | "json" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
38
+ lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "json" | "html" | "css" | "bash" | "haskell" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
39
39
  paths?: string[] | undefined;
40
40
  globs?: string[] | undefined;
41
41
  context?: number | undefined;
@@ -62,11 +62,11 @@ export declare const ast_grep_replace: {
62
62
  swift: "swift";
63
63
  elixir: "elixir";
64
64
  yaml: "yaml";
65
- bash: "bash";
65
+ json: "json";
66
+ html: "html";
66
67
  css: "css";
68
+ bash: "bash";
67
69
  haskell: "haskell";
68
- html: "html";
69
- json: "json";
70
70
  kotlin: "kotlin";
71
71
  nix: "nix";
72
72
  scala: "scala";
@@ -80,7 +80,7 @@ export declare const ast_grep_replace: {
80
80
  execute(args: {
81
81
  pattern: string;
82
82
  rewrite: string;
83
- lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "bash" | "css" | "haskell" | "html" | "json" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
83
+ lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "json" | "html" | "css" | "bash" | "haskell" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
84
84
  paths?: string[] | undefined;
85
85
  globs?: string[] | undefined;
86
86
  dryRun?: boolean | undefined;
@@ -98,8 +98,8 @@ export declare const ast_grep_analyze: {
98
98
  lang: import("zod").ZodEnum<{
99
99
  typescript: "typescript";
100
100
  javascript: "javascript";
101
- css: "css";
102
101
  html: "html";
102
+ css: "css";
103
103
  tsx: "tsx";
104
104
  }>;
105
105
  pattern: import("zod").ZodOptional<import("zod").ZodString>;
@@ -107,7 +107,7 @@ export declare const ast_grep_analyze: {
107
107
  };
108
108
  execute(args: {
109
109
  code: string;
110
- lang: "typescript" | "javascript" | "css" | "html" | "tsx";
110
+ lang: "typescript" | "javascript" | "html" | "css" | "tsx";
111
111
  pattern?: string | undefined;
112
112
  extractMetaVars?: boolean | undefined;
113
113
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
@@ -119,8 +119,8 @@ export declare const ast_grep_transform: {
119
119
  lang: import("zod").ZodEnum<{
120
120
  typescript: "typescript";
121
121
  javascript: "javascript";
122
- css: "css";
123
122
  html: "html";
123
+ css: "css";
124
124
  tsx: "tsx";
125
125
  }>;
126
126
  pattern: import("zod").ZodString;
@@ -128,7 +128,7 @@ export declare const ast_grep_transform: {
128
128
  };
129
129
  execute(args: {
130
130
  code: string;
131
- lang: "typescript" | "javascript" | "css" | "html" | "tsx";
131
+ lang: "typescript" | "javascript" | "html" | "css" | "tsx";
132
132
  pattern: string;
133
133
  rewrite: string;
134
134
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
@@ -171,11 +171,11 @@ export declare const builtinTools: {
171
171
  swift: "swift";
172
172
  elixir: "elixir";
173
173
  yaml: "yaml";
174
- bash: "bash";
174
+ json: "json";
175
+ html: "html";
175
176
  css: "css";
177
+ bash: "bash";
176
178
  haskell: "haskell";
177
- html: "html";
178
- json: "json";
179
179
  kotlin: "kotlin";
180
180
  nix: "nix";
181
181
  scala: "scala";
@@ -188,7 +188,7 @@ export declare const builtinTools: {
188
188
  };
189
189
  execute(args: {
190
190
  pattern: string;
191
- lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "bash" | "css" | "haskell" | "html" | "json" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
191
+ lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "json" | "html" | "css" | "bash" | "haskell" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
192
192
  paths?: string[] | undefined;
193
193
  globs?: string[] | undefined;
194
194
  context?: number | undefined;
@@ -215,11 +215,11 @@ export declare const builtinTools: {
215
215
  swift: "swift";
216
216
  elixir: "elixir";
217
217
  yaml: "yaml";
218
- bash: "bash";
218
+ json: "json";
219
+ html: "html";
219
220
  css: "css";
221
+ bash: "bash";
220
222
  haskell: "haskell";
221
- html: "html";
222
- json: "json";
223
223
  kotlin: "kotlin";
224
224
  nix: "nix";
225
225
  scala: "scala";
@@ -233,7 +233,7 @@ export declare const builtinTools: {
233
233
  execute(args: {
234
234
  pattern: string;
235
235
  rewrite: string;
236
- lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "bash" | "css" | "haskell" | "html" | "json" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
236
+ lang: "typescript" | "csharp" | "rust" | "php" | "python" | "javascript" | "go" | "c" | "cpp" | "java" | "ruby" | "lua" | "swift" | "elixir" | "yaml" | "json" | "html" | "css" | "bash" | "haskell" | "kotlin" | "nix" | "scala" | "solidity" | "tsx";
237
237
  paths?: string[] | undefined;
238
238
  globs?: string[] | undefined;
239
239
  dryRun?: boolean | undefined;
@@ -1,4 +1,5 @@
1
1
  import type { ResolvedServer } from "./config";
2
+ import type { Diagnostic } from "./types";
2
3
  declare class LSPServerManager {
3
4
  private static instance;
4
5
  private clients;
@@ -26,6 +27,7 @@ export declare class LSPClient {
26
27
  private openedFiles;
27
28
  private stderrBuffer;
28
29
  private processExited;
30
+ private diagnosticsStore;
29
31
  constructor(root: string, server: ResolvedServer);
30
32
  start(): Promise<void>;
31
33
  private startReading;
@@ -44,7 +46,9 @@ export declare class LSPClient {
44
46
  references(filePath: string, line: number, character: number, includeDeclaration?: boolean): Promise<unknown>;
45
47
  documentSymbols(filePath: string): Promise<unknown>;
46
48
  workspaceSymbols(query: string): Promise<unknown>;
47
- diagnostics(filePath: string): Promise<unknown>;
49
+ diagnostics(filePath: string): Promise<{
50
+ items: Diagnostic[];
51
+ }>;
48
52
  prepareRename(filePath: string, line: number, character: number): Promise<unknown>;
49
53
  rename(filePath: string, line: number, character: number, newName: string): Promise<unknown>;
50
54
  codeAction(filePath: string, startLine: number, startChar: number, endLine: number, endChar: number, only?: string[]): Promise<unknown>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
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",