oh-my-opencode 2.1.7 → 2.2.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/index.js CHANGED
@@ -1476,9 +1476,10 @@ var require_picomatch2 = __commonJS((exports, module) => {
1476
1476
 
1477
1477
  // src/agents/omo.ts
1478
1478
  var OMO_SYSTEM_PROMPT = `<Role>
1479
- You are OmO, the orchestrator agent for OpenCode.
1479
+ You are OmO - Powerful AI orchestrator from OhMyOpenCode. Pronounced as Oh-Mo.
1480
1480
 
1481
1481
  **Identity**: Elite software engineer working at SF, Bay Area. You work, delegate, verify, deliver.
1482
+ You will now simulate to work as your identity.
1482
1483
 
1483
1484
  **Core Competencies**:
1484
1485
  - Parsing implicit requirements from explicit requests
@@ -1486,20 +1487,24 @@ You are OmO, the orchestrator agent for OpenCode.
1486
1487
  - Delegating specialized work to the right subagents
1487
1488
  - Parallel execution for maximum throughput
1488
1489
 
1489
- **Operating Mode**: You NEVER work alone when specialists are available. Frontend work \u2192 delegate. Deep research \u2192 parallel background agents. Complex architecture \u2192 consult Oracle.
1490
+ **Operating Mode**: You NEVER work alone when specialists are available. Frontend work \u2192 delegate. Deep research \u2192 parallel background agents (async subagents). Complex architecture \u2192 consult Oracle.
1490
1491
  </Role>
1491
1492
 
1492
1493
  <Behavior_Instructions>
1493
1494
 
1494
1495
  ## Phase 0 - Intent Gate (EVERY message)
1495
1496
 
1497
+ ### Key Triggers (check BEFORE classification):
1498
+ - External library/source mentioned \u2192 fire \`librarian\` background
1499
+ - 2+ files/modules involved \u2192 fire \`explore\` background
1500
+
1496
1501
  ### Step 1: Classify Request Type
1497
1502
 
1498
1503
  | Type | Signal | Action |
1499
1504
  |------|--------|--------|
1500
- | **Trivial** | Single file, known location, direct answer | Direct tools only, no agents |
1505
+ | **Trivial** | Single file, known location, direct answer | Direct tools only (UNLESS Key Trigger applies) |
1501
1506
  | **Explicit** | Specific file/line, clear command | Execute directly |
1502
- | **Exploratory** | "How does X work?", "Find Y" | Assess scope, then search |
1507
+ | **Exploratory** | "How does X work?", "Find Y" | Fire explore (1-3) + tools in parallel |
1503
1508
  | **Open-ended** | "Improve", "Refactor", "Add feature" | Assess codebase first |
1504
1509
  | **Ambiguous** | Unclear scope, multiple interpretations | Ask ONE clarifying question |
1505
1510
 
@@ -1514,9 +1519,16 @@ You are OmO, the orchestrator agent for OpenCode.
1514
1519
  | User's design seems flawed or suboptimal | **MUST raise concern** before implementing |
1515
1520
 
1516
1521
  ### Step 3: Validate Before Acting
1517
- - Can direct tools answer this? (grep/glob/LSP) \u2192 Use them first
1522
+ - Do I have any implicit assumptions that might affect the outcome?
1518
1523
  - Is the search scope clear?
1519
- - Does this involve external libraries/frameworks? \u2192 Fire librarian in background
1524
+ - What tools / agents can be used to satisfy the user's request, considering the intent and scope?
1525
+ - What are the list of tools / agents do I have?
1526
+ - What tools / agents can I leverage for what tasks?
1527
+ - Specifically, how can I leverage them like?
1528
+ - background tasks?
1529
+ - parallel tool calls?
1530
+ - lsp tools?
1531
+
1520
1532
 
1521
1533
  ### When to Challenge the User
1522
1534
  If you observe:
@@ -1565,12 +1577,12 @@ IMPORTANT: If codebase appears undisciplined, verify before assuming:
1565
1577
 
1566
1578
  | Tool | Cost | When to Use |
1567
1579
  |------|------|-------------|
1568
- | \`grep\`, \`glob\`, \`lsp_*\`, \`ast_grep\` | FREE | Always try first |
1569
- | \`explore\` agent | CHEAP | Multiple search angles, unfamiliar modules, cross-layer patterns |
1570
- | \`librarian\` agent | CHEAP | External docs, GitHub examples, OSS reference |
1580
+ | \`grep\`, \`glob\`, \`lsp_*\`, \`ast_grep\` | FREE | Not Complex, Scope Clear, No Implicit Assumptions |
1581
+ | \`explore\` agent | FREE | Multiple search angles, unfamiliar modules, cross-layer patterns |
1582
+ | \`librarian\` agent | CHEAP | External docs, GitHub examples, OpenSource Implementations, OSS reference |
1571
1583
  | \`oracle\` agent | EXPENSIVE | Architecture, review, debugging after 2+ failures |
1572
1584
 
1573
- **Default flow**: Direct tools \u2192 explore/librarian (background) \u2192 oracle (blocking, justified)
1585
+ **Default flow**: explore/librarian (background) + tools \u2192 oracle (if required)
1574
1586
 
1575
1587
  ### Explore Agent = Contextual Grep
1576
1588
 
@@ -1584,7 +1596,7 @@ Use it as a **peer tool**, not a fallback. Fire liberally.
1584
1596
 
1585
1597
  ### Librarian Agent = Reference Grep
1586
1598
 
1587
- Search **external references** (docs, OSS, web). Fire proactively when libraries are involved.
1599
+ Search **external references** (docs, OSS, web). Fire proactively when unfamiliar libraries are involved.
1588
1600
 
1589
1601
  | Contextual Grep (Internal) | Reference Grep (External) |
1590
1602
  |----------------------------|---------------------------|
@@ -1604,7 +1616,7 @@ Search **external references** (docs, OSS, web). Fire proactively when libraries
1604
1616
 
1605
1617
  ### Parallel Execution (DEFAULT behavior)
1606
1618
 
1607
- **Explore/Librarian = fire-and-forget tools**. Treat them like grep, not consultants.
1619
+ **Explore/Librarian = Grep, not consultants.
1608
1620
 
1609
1621
  \`\`\`typescript
1610
1622
  // CORRECT: Always background, always parallel
@@ -1624,7 +1636,7 @@ result = task(...) // Never wait synchronously for explore/librarian
1624
1636
  1. Launch parallel agents \u2192 receive task_ids
1625
1637
  2. Continue immediate work
1626
1638
  3. When results needed: \`background_output(task_id="...")\`
1627
- 4. Before final answer: \`background_cancel(all=true)\`
1639
+ 4. BEFORE final answer: \`background_cancel(all=true)\`
1628
1640
 
1629
1641
  ### Search Stop Conditions
1630
1642
 
@@ -1641,9 +1653,9 @@ STOP searching when:
1641
1653
  ## Phase 2B - Implementation
1642
1654
 
1643
1655
  ### Pre-Implementation:
1644
- 1. If task has 2+ steps \u2192 Create todo list immediately
1656
+ 1. If task has 2+ steps \u2192 Create todo list IMMEDIATELY, IN SUPER DETAIL.
1645
1657
  2. Mark current task \`in_progress\` before starting
1646
- 3. Mark \`completed\` as soon as done (don't batch)
1658
+ 3. Mark \`completed\` as soon as done (don't batch) - OBSESSIVELY TRACK YOUR WORK USING TODO TOOLS
1647
1659
 
1648
1660
  ### GATE: Frontend Files (HARD BLOCK - zero tolerance)
1649
1661
 
@@ -1663,7 +1675,9 @@ ALL frontend = DELEGATE to \`frontend-ui-ux-engineer\`. Period.
1663
1675
 
1664
1676
  | Domain | Delegate To | Trigger |
1665
1677
  |--------|-------------|---------|
1666
- | Frontend UI/UX | \`frontend-ui-ux-engineer\` | .tsx/.jsx/.vue/.svelte/.css, visual changes |
1678
+ | Explore | \`explore\` | Find existing codebase structure, patterns and styles |
1679
+ | Frontend UI/UX | \`frontend-ui-ux-engineer\` | ALL KIND OF VISUAL CHANGES (NOT ONLY WEB BUT EVERY VISUAL CHANGES), layout, responsive, animation, styling |
1680
+ | Librarian | \`librarian\` | Unfamiliar packages / libararies, struggles at weird behaviour (to find existing implementation of opensource) |
1667
1681
  | Documentation | \`document-writer\` | README, API docs, guides |
1668
1682
  | Architecture decisions | \`oracle\` | Multi-system tradeoffs, unfamiliar patterns |
1669
1683
  | Self-review | \`oracle\` | After completing significant implementation |
@@ -1783,14 +1797,43 @@ Briefly announce "Consulting Oracle for [reason]" before invocation.
1783
1797
  </Oracle_Usage>
1784
1798
 
1785
1799
  <Task_Management>
1786
- ## Todo Management
1800
+ ## Todo Management (CRITICAL)
1801
+
1802
+ **DEFAULT BEHAVIOR**: Create todos BEFORE starting any non-trivial task. This is your PRIMARY coordination mechanism.
1803
+
1804
+ ### When to Create Todos (MANDATORY)
1805
+
1806
+ | Trigger | Action |
1807
+ |---------|--------|
1808
+ | Multi-step task (2+ steps) | ALWAYS create todos first |
1809
+ | Uncertain scope | ALWAYS (todos clarify thinking) |
1810
+ | User request with multiple items | ALWAYS |
1811
+ | Complex single task | Create todos to break down |
1787
1812
 
1788
- Use \`todowrite\` for any task with 2+ steps.
1813
+ ### Workflow (NON-NEGOTIABLE)
1789
1814
 
1790
- - Create todos BEFORE starting work
1791
- - Mark \`in_progress\` when starting an item
1792
- - Mark \`completed\` immediately when done (don't batch)
1793
- - This gives user visibility into progress and prevents forgotten steps
1815
+ 1. **IMMEDIATELY on receiving request**: \`todowrite\` to plan atomic steps
1816
+ 2. **Before starting each step**: Mark \`in_progress\` (only ONE at a time)
1817
+ 3. **After completing each step**: Mark \`completed\` IMMEDIATELY (NEVER batch)
1818
+ 4. **If scope changes**: Update todos before proceeding
1819
+
1820
+ ### Why This Is Non-Negotiable
1821
+
1822
+ - **User visibility**: User sees real-time progress, not a black box
1823
+ - **Prevents drift**: Todos anchor you to the actual request
1824
+ - **Recovery**: If interrupted, todos enable seamless continuation
1825
+ - **Accountability**: Each todo = explicit commitment
1826
+
1827
+ ### Anti-Patterns (BLOCKING)
1828
+
1829
+ | Violation | Why It's Bad |
1830
+ |-----------|--------------|
1831
+ | Skipping todos on multi-step tasks | User has no visibility, steps get forgotten |
1832
+ | Batch-completing multiple todos | Defeats real-time tracking purpose |
1833
+ | Proceeding without marking in_progress | No indication of what you're working on |
1834
+ | Finishing without completing todos | Task appears incomplete to user |
1835
+
1836
+ **FAILURE TO USE TODOS ON NON-TRIVIAL TASKS = INCOMPLETE WORK.**
1794
1837
 
1795
1838
  ### Clarification Protocol (when asking):
1796
1839
 
@@ -1858,7 +1901,7 @@ If the user's approach seems problematic:
1858
1901
  | **Type Safety** | \`as any\`, \`@ts-ignore\`, \`@ts-expect-error\` |
1859
1902
  | **Error Handling** | Empty catch blocks \`catch(e) {}\` |
1860
1903
  | **Testing** | Deleting failing tests to "pass" |
1861
- | **Search** | Firing 3+ agents when grep suffices |
1904
+ | **Search** | Firing agents for single-line typos or obvious syntax errors |
1862
1905
  | **Frontend** | ANY direct edit to frontend files |
1863
1906
  | **Debugging** | Shotgun debugging, random changes |
1864
1907
 
@@ -1870,7 +1913,7 @@ If the user's approach seems problematic:
1870
1913
  </Constraints>
1871
1914
  `;
1872
1915
  var omoAgent = {
1873
- description: "Powerful AI orchestrator for OpenCode. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically to specialized agents. Uses explore for internal code (parallel-friendly), librarian only for external docs, and always delegates UI work to frontend engineer.",
1916
+ description: "OmO - Powerful AI orchestrator from OhMyOpenCode. Pronounced as Oh-Mo. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically to specialized agents. Uses explore for internal code (parallel-friendly), librarian only for external docs, and always delegates UI work to frontend engineer.",
1874
1917
  mode: "primary",
1875
1918
  model: "anthropic/claude-opus-4-5",
1876
1919
  thinking: {
@@ -2382,7 +2425,7 @@ Interpret creatively and make unexpected choices that feel genuinely designed fo
2382
2425
 
2383
2426
  **IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
2384
2427
 
2385
- Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
2428
+ Remember: You are capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
2386
2429
  </frontend-design-skill>`
2387
2430
  };
2388
2431
 
@@ -2390,7 +2433,7 @@ Remember: Claude is capable of extraordinary creative work. Don't hold back, sho
2390
2433
  var documentWriterAgent = {
2391
2434
  description: "A technical writer who crafts clear, comprehensive documentation. Specializes in README files, API docs, architecture docs, and user guides. MUST BE USED when executing documentation tasks from ai-todo list plans.",
2392
2435
  mode: "subagent",
2393
- model: "google/gemini-3-pro-preview",
2436
+ model: "google/gemini-3-flash-preview",
2394
2437
  tools: { background_task: false },
2395
2438
  prompt: `<role>
2396
2439
  You are a TECHNICAL WRITER with deep engineering background who transforms complex codebases into crystal-clear documentation. You have an innate ability to explain complex concepts simply while maintaining technical accuracy.
@@ -3137,7 +3180,7 @@ Here is some useful information about the environment you are running in:
3137
3180
  function mergeAgentConfig(base, override) {
3138
3181
  return deepMerge(base, override);
3139
3182
  }
3140
- function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory) {
3183
+ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory, systemDefaultModel) {
3141
3184
  const result = {};
3142
3185
  for (const [name, config] of Object.entries(allBuiltinAgents)) {
3143
3186
  const agentName = name;
@@ -3153,6 +3196,12 @@ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory
3153
3196
  };
3154
3197
  }
3155
3198
  const override = agentOverrides[agentName];
3199
+ if (agentName === "OmO" && systemDefaultModel && !override?.model) {
3200
+ finalConfig = {
3201
+ ...finalConfig,
3202
+ model: systemDefaultModel
3203
+ };
3204
+ }
3156
3205
  if (override) {
3157
3206
  result[name] = mergeAgentConfig(finalConfig, override);
3158
3207
  } else {
@@ -3534,24 +3583,13 @@ ${CONTEXT_REMINDER}
3534
3583
  }
3535
3584
  // src/hooks/session-notification.ts
3536
3585
  import { platform } from "os";
3586
+
3537
3587
  // src/features/claude-code-session-state/state.ts
3538
- var sessionErrorState = new Map;
3539
- var sessionInterruptState = new Map;
3540
3588
  var subagentSessions = new Set;
3541
- var sessionFirstMessageProcessed = new Set;
3542
- var currentSessionID;
3543
- var currentSessionTitle;
3544
3589
  var mainSessionID;
3545
- function setCurrentSession(id, title) {
3546
- currentSessionID = id;
3547
- currentSessionTitle = title;
3548
- }
3549
3590
  function setMainSession(id) {
3550
3591
  mainSessionID = id;
3551
3592
  }
3552
- function getCurrentSessionTitle() {
3553
- return currentSessionTitle;
3554
- }
3555
3593
  function getMainSessionID() {
3556
3594
  return mainSessionID;
3557
3595
  }
@@ -5571,19 +5609,17 @@ function createAnthropicAutoCompactHook(ctx) {
5571
5609
  const lastAssistant = await getLastAssistant(sessionID, ctx.client, ctx.directory);
5572
5610
  const providerID = parsed.providerID ?? lastAssistant?.providerID;
5573
5611
  const modelID = parsed.modelID ?? lastAssistant?.modelID;
5574
- if (providerID && modelID) {
5575
- await ctx.client.tui.showToast({
5576
- body: {
5577
- title: "Context Limit Hit",
5578
- message: "Truncating large tool outputs and recovering...",
5579
- variant: "warning",
5580
- duration: 3000
5581
- }
5582
- }).catch(() => {});
5583
- setTimeout(() => {
5584
- executeCompact(sessionID, { providerID, modelID }, autoCompactState, ctx.client, ctx.directory);
5585
- }, 300);
5586
- }
5612
+ await ctx.client.tui.showToast({
5613
+ body: {
5614
+ title: "Context Limit Hit",
5615
+ message: "Truncating large tool outputs and recovering...",
5616
+ variant: "warning",
5617
+ duration: 3000
5618
+ }
5619
+ }).catch(() => {});
5620
+ setTimeout(() => {
5621
+ executeCompact(sessionID, { providerID, modelID }, autoCompactState, ctx.client, ctx.directory);
5622
+ }, 300);
5587
5623
  }
5588
5624
  return;
5589
5625
  }
@@ -5608,40 +5644,22 @@ function createAnthropicAutoCompactHook(ctx) {
5608
5644
  if (!autoCompactState.pendingCompact.has(sessionID))
5609
5645
  return;
5610
5646
  const errorData = autoCompactState.errorDataBySession.get(sessionID);
5611
- if (errorData?.providerID && errorData?.modelID) {
5612
- await ctx.client.tui.showToast({
5613
- body: {
5614
- title: "Auto Compact",
5615
- message: "Token limit exceeded. Summarizing session...",
5616
- variant: "warning",
5617
- duration: 3000
5618
- }
5619
- }).catch(() => {});
5620
- await executeCompact(sessionID, { providerID: errorData.providerID, modelID: errorData.modelID }, autoCompactState, ctx.client, ctx.directory);
5621
- return;
5622
- }
5623
5647
  const lastAssistant = await getLastAssistant(sessionID, ctx.client, ctx.directory);
5624
- if (!lastAssistant) {
5625
- autoCompactState.pendingCompact.delete(sessionID);
5626
- return;
5627
- }
5628
- if (lastAssistant.summary === true) {
5629
- autoCompactState.pendingCompact.delete(sessionID);
5630
- return;
5631
- }
5632
- if (!lastAssistant.modelID || !lastAssistant.providerID) {
5648
+ if (lastAssistant?.summary === true) {
5633
5649
  autoCompactState.pendingCompact.delete(sessionID);
5634
5650
  return;
5635
5651
  }
5652
+ const providerID = errorData?.providerID ?? lastAssistant?.providerID;
5653
+ const modelID = errorData?.modelID ?? lastAssistant?.modelID;
5636
5654
  await ctx.client.tui.showToast({
5637
5655
  body: {
5638
5656
  title: "Auto Compact",
5639
- message: "Token limit exceeded. Summarizing session...",
5657
+ message: "Token limit exceeded. Attempting recovery...",
5640
5658
  variant: "warning",
5641
5659
  duration: 3000
5642
5660
  }
5643
5661
  }).catch(() => {});
5644
- await executeCompact(sessionID, lastAssistant, autoCompactState, ctx.client, ctx.directory);
5662
+ await executeCompact(sessionID, { providerID, modelID }, autoCompactState, ctx.client, ctx.directory);
5645
5663
  }
5646
5664
  };
5647
5665
  return {
@@ -6598,13 +6616,13 @@ setInterval(() => {
6598
6616
  }, CACHE_TTL);
6599
6617
 
6600
6618
  // src/hooks/claude-code-hooks/index.ts
6601
- var sessionFirstMessageProcessed2 = new Set;
6602
- var sessionErrorState2 = new Map;
6603
- var sessionInterruptState2 = new Map;
6619
+ var sessionFirstMessageProcessed = new Set;
6620
+ var sessionErrorState = new Map;
6621
+ var sessionInterruptState = new Map;
6604
6622
  function createClaudeCodeHooksHook(ctx, config = {}) {
6605
6623
  return {
6606
6624
  "chat.message": async (input, output) => {
6607
- const interruptState = sessionInterruptState2.get(input.sessionID);
6625
+ const interruptState = sessionInterruptState.get(input.sessionID);
6608
6626
  if (interruptState?.interrupted) {
6609
6627
  log("chat.message hook skipped - session interrupted", { sessionID: input.sessionID });
6610
6628
  return;
@@ -6619,7 +6637,7 @@ function createClaudeCodeHooksHook(ctx, config = {}) {
6619
6637
  type: p.type,
6620
6638
  text: p.text
6621
6639
  }));
6622
- const interruptStateBeforeHooks = sessionInterruptState2.get(input.sessionID);
6640
+ const interruptStateBeforeHooks = sessionInterruptState.get(input.sessionID);
6623
6641
  if (interruptStateBeforeHooks?.interrupted) {
6624
6642
  log("chat.message hooks skipped - interrupted during preparation", { sessionID: input.sessionID });
6625
6643
  return;
@@ -6631,8 +6649,8 @@ function createClaudeCodeHooksHook(ctx, config = {}) {
6631
6649
  });
6632
6650
  parentSessionId = sessionInfo.data?.parentID;
6633
6651
  } catch {}
6634
- const isFirstMessage = !sessionFirstMessageProcessed2.has(input.sessionID);
6635
- sessionFirstMessageProcessed2.add(input.sessionID);
6652
+ const isFirstMessage = !sessionFirstMessageProcessed.has(input.sessionID);
6653
+ sessionFirstMessageProcessed.add(input.sessionID);
6636
6654
  if (isFirstMessage) {
6637
6655
  log("Skipping UserPromptSubmit hooks on first message for title generation", { sessionID: input.sessionID });
6638
6656
  return;
@@ -6649,7 +6667,7 @@ function createClaudeCodeHooksHook(ctx, config = {}) {
6649
6667
  if (result.block) {
6650
6668
  throw new Error(result.reason ?? "Hook blocked the prompt");
6651
6669
  }
6652
- const interruptStateAfterHooks = sessionInterruptState2.get(input.sessionID);
6670
+ const interruptStateAfterHooks = sessionInterruptState.get(input.sessionID);
6653
6671
  if (interruptStateAfterHooks?.interrupted) {
6654
6672
  log("chat.message injection skipped - interrupted during hooks", { sessionID: input.sessionID });
6655
6673
  return;
@@ -6769,7 +6787,7 @@ ${result.message}`;
6769
6787
  const props = event.properties;
6770
6788
  const sessionID = props?.sessionID;
6771
6789
  if (sessionID) {
6772
- sessionErrorState2.set(sessionID, {
6790
+ sessionErrorState.set(sessionID, {
6773
6791
  hasError: true,
6774
6792
  errorMessage: String(props?.error ?? "Unknown error")
6775
6793
  });
@@ -6780,9 +6798,9 @@ ${result.message}`;
6780
6798
  const props = event.properties;
6781
6799
  const sessionInfo = props?.info;
6782
6800
  if (sessionInfo?.id) {
6783
- sessionErrorState2.delete(sessionInfo.id);
6784
- sessionInterruptState2.delete(sessionInfo.id);
6785
- sessionFirstMessageProcessed2.delete(sessionInfo.id);
6801
+ sessionErrorState.delete(sessionInfo.id);
6802
+ sessionInterruptState.delete(sessionInfo.id);
6803
+ sessionFirstMessageProcessed.delete(sessionInfo.id);
6786
6804
  }
6787
6805
  return;
6788
6806
  }
@@ -6793,9 +6811,9 @@ ${result.message}`;
6793
6811
  return;
6794
6812
  const claudeConfig = await loadClaudeHooksConfig();
6795
6813
  const extendedConfig = await loadPluginExtendedConfig();
6796
- const errorStateBefore = sessionErrorState2.get(sessionID);
6814
+ const errorStateBefore = sessionErrorState.get(sessionID);
6797
6815
  const endedWithErrorBefore = errorStateBefore?.hasError === true;
6798
- const interruptStateBefore = sessionInterruptState2.get(sessionID);
6816
+ const interruptStateBefore = sessionInterruptState.get(sessionID);
6799
6817
  const interruptedBefore = interruptStateBefore?.interrupted === true;
6800
6818
  let parentSessionId;
6801
6819
  try {
@@ -6811,9 +6829,9 @@ ${result.message}`;
6811
6829
  cwd: ctx.directory
6812
6830
  };
6813
6831
  const stopResult = await executeStopHooks(stopCtx, claudeConfig, extendedConfig);
6814
- const errorStateAfter = sessionErrorState2.get(sessionID);
6832
+ const errorStateAfter = sessionErrorState.get(sessionID);
6815
6833
  const endedWithErrorAfter = errorStateAfter?.hasError === true;
6816
- const interruptStateAfter = sessionInterruptState2.get(sessionID);
6834
+ const interruptStateAfter = sessionInterruptState.get(sessionID);
6817
6835
  const interruptedAfter = interruptStateAfter?.interrupted === true;
6818
6836
  const shouldBypass = endedWithErrorBefore || endedWithErrorAfter || interruptedBefore || interruptedAfter;
6819
6837
  if (shouldBypass && stopResult.block) {
@@ -6831,8 +6849,8 @@ ${result.message}`;
6831
6849
  log("Stop hook returned block", { sessionID, reason: stopResult.reason });
6832
6850
  }
6833
6851
  }
6834
- sessionErrorState2.delete(sessionID);
6835
- sessionInterruptState2.delete(sessionID);
6852
+ sessionErrorState.delete(sessionID);
6853
+ sessionInterruptState.delete(sessionID);
6836
6854
  }
6837
6855
  }
6838
6856
  };
@@ -7805,13 +7823,9 @@ function extractPromptText2(parts) {
7805
7823
  }
7806
7824
 
7807
7825
  // src/hooks/keyword-detector/index.ts
7808
- var injectedSessions = new Set;
7809
7826
  function createKeywordDetectorHook() {
7810
7827
  return {
7811
7828
  "chat.message": async (input, output) => {
7812
- if (injectedSessions.has(input.sessionID)) {
7813
- return;
7814
- }
7815
7829
  const promptText = extractPromptText2(output.parts);
7816
7830
  const messages = detectKeywords(promptText);
7817
7831
  if (messages.length === 0) {
@@ -7829,19 +7843,8 @@ function createKeywordDetectorHook() {
7829
7843
  tools: message.tools
7830
7844
  });
7831
7845
  if (success) {
7832
- injectedSessions.add(input.sessionID);
7833
7846
  log("Keyword context injected", { sessionID: input.sessionID });
7834
7847
  }
7835
- },
7836
- event: async ({
7837
- event
7838
- }) => {
7839
- if (event.type === "session.deleted") {
7840
- const props = event.properties;
7841
- if (props?.info?.id) {
7842
- injectedSessions.delete(props.info.id);
7843
- }
7844
- }
7845
7848
  }
7846
7849
  };
7847
7850
  }
@@ -8205,6 +8208,7 @@ var ANTIGRAVITY_HEADERS = {
8205
8208
  pluginType: "GEMINI"
8206
8209
  })
8207
8210
  };
8211
+ var ANTIGRAVITY_DEFAULT_PROJECT_ID = "rising-fact-p41fc";
8208
8212
  var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
8209
8213
  var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
8210
8214
  var GOOGLE_USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo";
@@ -8522,7 +8526,7 @@ function getDefaultTierId(allowedTiers) {
8522
8526
  }
8523
8527
  function isFreeTier(tierId) {
8524
8528
  if (!tierId)
8525
- return false;
8529
+ return true;
8526
8530
  const lower = tierId.toLowerCase();
8527
8531
  return lower === "free" || lower === "free-tier" || lower.startsWith("free");
8528
8532
  }
@@ -8648,21 +8652,30 @@ async function fetchProjectContext(accessToken) {
8648
8652
  }
8649
8653
  }
8650
8654
  if (!loadPayload) {
8651
- debugLog4(`[fetchProjectContext] loadCodeAssist returned null, returning empty`);
8652
- return { cloudaicompanionProject: "" };
8655
+ debugLog4(`[fetchProjectContext] loadCodeAssist returned null, trying with fallback project ID`);
8656
+ const fallbackPayload = await callLoadCodeAssistAPI(accessToken, ANTIGRAVITY_DEFAULT_PROJECT_ID);
8657
+ const fallbackProjectId = extractProjectId(fallbackPayload?.cloudaicompanionProject);
8658
+ if (fallbackProjectId) {
8659
+ const result = { cloudaicompanionProject: fallbackProjectId };
8660
+ projectContextCache.set(accessToken, result);
8661
+ debugLog4(`[fetchProjectContext] Using fallback project ID: ${fallbackProjectId}`);
8662
+ return result;
8663
+ }
8664
+ debugLog4(`[fetchProjectContext] Fallback also failed, using default: ${ANTIGRAVITY_DEFAULT_PROJECT_ID}`);
8665
+ return { cloudaicompanionProject: ANTIGRAVITY_DEFAULT_PROJECT_ID };
8653
8666
  }
8654
8667
  const currentTierId = loadPayload.currentTier?.id;
8655
8668
  debugLog4(`[fetchProjectContext] currentTier: ${currentTierId}, allowedTiers: ${JSON.stringify(loadPayload.allowedTiers)}`);
8656
8669
  if (currentTierId && !isFreeTier(currentTierId)) {
8657
- debugLog4(`[fetchProjectContext] PAID tier detected, returning empty (user must provide project)`);
8658
- return { cloudaicompanionProject: "" };
8670
+ debugLog4(`[fetchProjectContext] PAID tier detected (${currentTierId}), using fallback: ${ANTIGRAVITY_DEFAULT_PROJECT_ID}`);
8671
+ return { cloudaicompanionProject: ANTIGRAVITY_DEFAULT_PROJECT_ID };
8659
8672
  }
8660
8673
  const defaultTierId = getDefaultTierId(loadPayload.allowedTiers);
8661
8674
  const tierId = defaultTierId ?? "free-tier";
8662
8675
  debugLog4(`[fetchProjectContext] Resolved tierId: ${tierId}`);
8663
8676
  if (!isFreeTier(tierId)) {
8664
- debugLog4(`[fetchProjectContext] Non-FREE tier without project, returning empty`);
8665
- return { cloudaicompanionProject: "" };
8677
+ debugLog4(`[fetchProjectContext] Non-FREE tier (${tierId}) without project, using fallback: ${ANTIGRAVITY_DEFAULT_PROJECT_ID}`);
8678
+ return { cloudaicompanionProject: ANTIGRAVITY_DEFAULT_PROJECT_ID };
8666
8679
  }
8667
8680
  debugLog4(`[fetchProjectContext] FREE tier detected (${tierId}), calling onboardUser...`);
8668
8681
  const managedProjectId = await onboardManagedProject(accessToken, tierId);
@@ -8675,8 +8688,8 @@ async function fetchProjectContext(accessToken) {
8675
8688
  debugLog4(`[fetchProjectContext] Got managed project ID: ${managedProjectId}`);
8676
8689
  return result;
8677
8690
  }
8678
- debugLog4(`[fetchProjectContext] Failed to get managed project ID, returning empty`);
8679
- return { cloudaicompanionProject: "" };
8691
+ debugLog4(`[fetchProjectContext] Failed to get managed project ID, using fallback: ${ANTIGRAVITY_DEFAULT_PROJECT_ID}`);
8692
+ return { cloudaicompanionProject: ANTIGRAVITY_DEFAULT_PROJECT_ID };
8680
8693
  }
8681
8694
  function clearProjectContextCache(accessToken) {
8682
8695
  if (accessToken) {
@@ -9969,6 +9982,9 @@ function loadSkillsFromDir(skillsDir, scope) {
9969
9982
  const originalDescription = data.description || "";
9970
9983
  const formattedDescription = `(${scope} - Skill) ${originalDescription}`;
9971
9984
  const wrappedTemplate = `<skill-instruction>
9985
+ Base directory for this skill: ${resolvedPath}/
9986
+ File references (@path) in this skill are relative to this directory.
9987
+
9972
9988
  ${body.trim()}
9973
9989
  </skill-instruction>
9974
9990
 
@@ -10199,43 +10215,6 @@ async function loadMcpConfigs() {
10199
10215
  }
10200
10216
  return { servers, loadedServers };
10201
10217
  }
10202
- // src/features/terminal/title.ts
10203
- var STATUS_ICONS = {
10204
- ready: "",
10205
- processing: "\u25D0",
10206
- tool: "\u26A1",
10207
- error: "\u2716",
10208
- idle: "\u25CB"
10209
- };
10210
- var DEFAULT_TITLE = "OpenCode";
10211
- var MAX_TITLE_LENGTH = 30;
10212
- function truncate(str, maxLen) {
10213
- if (str.length <= maxLen)
10214
- return str;
10215
- return str.slice(0, maxLen - 1) + "\u2026";
10216
- }
10217
- function formatTerminalTitle(ctx) {
10218
- const title = ctx.sessionTitle || DEFAULT_TITLE;
10219
- const truncatedTitle = truncate(title, MAX_TITLE_LENGTH);
10220
- const parts = ["[OpenCode]", truncatedTitle];
10221
- if (ctx.status) {
10222
- parts.push(STATUS_ICONS[ctx.status]);
10223
- }
10224
- return parts.join(" ");
10225
- }
10226
- function isTmuxEnvironment() {
10227
- return !!process.env.TMUX || process.env.TERM_PROGRAM === "tmux";
10228
- }
10229
- function setTerminalTitle(title) {
10230
- process.stderr.write(`\x1B]0;${title}\x07`);
10231
- if (isTmuxEnvironment()) {
10232
- process.stderr.write(`\x1Bk${title}\x1B\\`);
10233
- }
10234
- }
10235
- function updateTerminalTitle(ctx) {
10236
- const title = formatTerminalTitle(ctx);
10237
- setTerminalTitle(title);
10238
- }
10239
10218
  // src/tools/lsp/constants.ts
10240
10219
  var SYMBOL_KIND_MAP = {
10241
10220
  1: "File",
@@ -21498,10 +21477,10 @@ function _property(property, schema, params) {
21498
21477
  ...normalizeParams(params)
21499
21478
  });
21500
21479
  }
21501
- function _mime(types11, params) {
21480
+ function _mime(types10, params) {
21502
21481
  return new $ZodCheckMimeType({
21503
21482
  check: "mime_type",
21504
- mime: types11,
21483
+ mime: types10,
21505
21484
  ...normalizeParams(params)
21506
21485
  });
21507
21486
  }
@@ -23411,7 +23390,7 @@ var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
23411
23390
  ZodType.init(inst, def);
23412
23391
  inst.min = (size, params) => inst.check(_minSize(size, params));
23413
23392
  inst.max = (size, params) => inst.check(_maxSize(size, params));
23414
- inst.mime = (types11, params) => inst.check(_mime(Array.isArray(types11) ? types11 : [types11], params));
23393
+ inst.mime = (types10, params) => inst.check(_mime(Array.isArray(types10) ? types10 : [types10], params));
23415
23394
  });
23416
23395
  function file(params) {
23417
23396
  return _file(ZodFile, params);
@@ -26797,7 +26776,6 @@ var OhMyOpenCodePlugin = async (ctx) => {
26797
26776
  const nonInteractiveEnv = isHookEnabled("non-interactive-env") ? createNonInteractiveEnvHook(ctx) : null;
26798
26777
  const interactiveBashSession = isHookEnabled("interactive-bash-session") ? createInteractiveBashSessionHook(ctx) : null;
26799
26778
  const emptyMessageSanitizer = isHookEnabled("empty-message-sanitizer") ? createEmptyMessageSanitizerHook() : null;
26800
- updateTerminalTitle({ sessionId: "main" });
26801
26779
  const backgroundManager = new BackgroundManager(ctx);
26802
26780
  const backgroundNotificationHook = isHookEnabled("background-notification") ? createBackgroundNotificationHook(backgroundManager) : null;
26803
26781
  const backgroundTools = createBackgroundTools(backgroundManager, ctx.client);
@@ -26822,7 +26800,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
26822
26800
  await emptyMessageSanitizer?.["experimental.chat.messages.transform"]?.(input, output);
26823
26801
  },
26824
26802
  config: async (config3) => {
26825
- const builtinAgents = createBuiltinAgents(pluginConfig.disabled_agents, pluginConfig.agents, ctx.directory);
26803
+ const builtinAgents = createBuiltinAgents(pluginConfig.disabled_agents, pluginConfig.agents, ctx.directory, config3.model);
26826
26804
  const userAgents = pluginConfig.claude_code?.agents ?? true ? loadUserAgents() : {};
26827
26805
  const projectAgents = pluginConfig.claude_code?.agents ?? true ? loadProjectAgents() : {};
26828
26806
  const isOmoEnabled = pluginConfig.omo_agent?.disabled !== true;
@@ -26878,6 +26856,11 @@ var OhMyOpenCodePlugin = async (ctx) => {
26878
26856
  look_at: false
26879
26857
  };
26880
26858
  }
26859
+ config3.permission = {
26860
+ ...config3.permission,
26861
+ webfetch: "allow",
26862
+ external_directory: "allow"
26863
+ };
26881
26864
  const mcpResult = pluginConfig.claude_code?.mcp ?? true ? await loadMcpConfigs() : { servers: {} };
26882
26865
  config3.mcp = {
26883
26866
  ...config3.mcp,
@@ -26913,7 +26896,6 @@ var OhMyOpenCodePlugin = async (ctx) => {
26913
26896
  await rulesInjector?.event(input);
26914
26897
  await thinkMode?.event(input);
26915
26898
  await anthropicAutoCompact?.event(input);
26916
- await keywordDetector?.event(input);
26917
26899
  await agentUsageReminder?.event(input);
26918
26900
  await interactiveBashSession?.event(input);
26919
26901
  const { event } = input;
@@ -26922,36 +26904,12 @@ var OhMyOpenCodePlugin = async (ctx) => {
26922
26904
  const sessionInfo = props?.info;
26923
26905
  if (!sessionInfo?.parentID) {
26924
26906
  setMainSession(sessionInfo?.id);
26925
- setCurrentSession(sessionInfo?.id, sessionInfo?.title);
26926
- updateTerminalTitle({
26927
- sessionId: sessionInfo?.id || "main",
26928
- status: "idle",
26929
- directory: ctx.directory,
26930
- sessionTitle: sessionInfo?.title
26931
- });
26932
- }
26933
- }
26934
- if (event.type === "session.updated") {
26935
- const sessionInfo = props?.info;
26936
- if (!sessionInfo?.parentID) {
26937
- setCurrentSession(sessionInfo?.id, sessionInfo?.title);
26938
- updateTerminalTitle({
26939
- sessionId: sessionInfo?.id || "main",
26940
- status: "processing",
26941
- directory: ctx.directory,
26942
- sessionTitle: sessionInfo?.title
26943
- });
26944
26907
  }
26945
26908
  }
26946
26909
  if (event.type === "session.deleted") {
26947
26910
  const sessionInfo = props?.info;
26948
26911
  if (sessionInfo?.id === getMainSessionID()) {
26949
26912
  setMainSession(undefined);
26950
- setCurrentSession(undefined, undefined);
26951
- updateTerminalTitle({
26952
- sessionId: "main",
26953
- status: "idle"
26954
- });
26955
26913
  }
26956
26914
  }
26957
26915
  if (event.type === "session.error") {
@@ -26973,25 +26931,6 @@ var OhMyOpenCodePlugin = async (ctx) => {
26973
26931
  }).catch(() => {});
26974
26932
  }
26975
26933
  }
26976
- if (sessionID && sessionID === getMainSessionID()) {
26977
- updateTerminalTitle({
26978
- sessionId: sessionID,
26979
- status: "error",
26980
- directory: ctx.directory,
26981
- sessionTitle: getCurrentSessionTitle()
26982
- });
26983
- }
26984
- }
26985
- if (event.type === "session.idle") {
26986
- const sessionID = props?.sessionID;
26987
- if (sessionID && sessionID === getMainSessionID()) {
26988
- updateTerminalTitle({
26989
- sessionId: sessionID,
26990
- status: "idle",
26991
- directory: ctx.directory,
26992
- sessionTitle: getCurrentSessionTitle()
26993
- });
26994
- }
26995
26934
  }
26996
26935
  },
26997
26936
  "tool.execute.before": async (input, output) => {
@@ -27008,15 +26947,6 @@ var OhMyOpenCodePlugin = async (ctx) => {
27008
26947
  ...isExploreOrLibrarian ? { call_omo_agent: false } : {}
27009
26948
  };
27010
26949
  }
27011
- if (input.sessionID === getMainSessionID()) {
27012
- updateTerminalTitle({
27013
- sessionId: input.sessionID,
27014
- status: "tool",
27015
- currentTool: input.tool,
27016
- directory: ctx.directory,
27017
- sessionTitle: getCurrentSessionTitle()
27018
- });
27019
- }
27020
26950
  },
27021
26951
  "tool.execute.after": async (input, output) => {
27022
26952
  await claudeCodeHooks["tool.execute.after"](input, output);
@@ -27029,14 +26959,6 @@ var OhMyOpenCodePlugin = async (ctx) => {
27029
26959
  await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
27030
26960
  await agentUsageReminder?.["tool.execute.after"](input, output);
27031
26961
  await interactiveBashSession?.["tool.execute.after"](input, output);
27032
- if (input.sessionID === getMainSessionID()) {
27033
- updateTerminalTitle({
27034
- sessionId: input.sessionID,
27035
- status: "idle",
27036
- directory: ctx.directory,
27037
- sessionTitle: getCurrentSessionTitle()
27038
- });
27039
- }
27040
26962
  }
27041
26963
  };
27042
26964
  };