oh-my-opencode 2.1.0 → 2.1.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/README.ja.md +702 -0
- package/README.ko.md +3 -3
- package/README.md +3 -3
- package/dist/features/background-agent/manager.d.ts +1 -0
- package/dist/hooks/anthropic-auto-compact/index.d.ts +1 -1
- package/dist/hooks/anthropic-auto-compact/types.d.ts +10 -1
- package/dist/index.js +346 -165
- package/dist/tools/interactive-bash/constants.d.ts +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2257,7 +2257,7 @@ var oracleAgent = {
|
|
|
2257
2257
|
temperature: 0.1,
|
|
2258
2258
|
reasoningEffort: "medium",
|
|
2259
2259
|
textVerbosity: "high",
|
|
2260
|
-
tools: { write: false, edit: false,
|
|
2260
|
+
tools: { write: false, edit: false, task: false, background_task: false },
|
|
2261
2261
|
prompt: `You are a strategic technical advisor with deep reasoning capabilities, operating as a specialized consultant within an AI-assisted development environment.
|
|
2262
2262
|
|
|
2263
2263
|
## Context
|
|
@@ -2331,7 +2331,7 @@ var librarianAgent = {
|
|
|
2331
2331
|
mode: "subagent",
|
|
2332
2332
|
model: "anthropic/claude-sonnet-4-5",
|
|
2333
2333
|
temperature: 0.1,
|
|
2334
|
-
tools: { write: false, edit: false,
|
|
2334
|
+
tools: { write: false, edit: false, background_task: false },
|
|
2335
2335
|
prompt: `# THE LIBRARIAN
|
|
2336
2336
|
|
|
2337
2337
|
You are **THE LIBRARIAN**, a specialized open-source codebase understanding agent.
|
|
@@ -2570,7 +2570,7 @@ var exploreAgent = {
|
|
|
2570
2570
|
mode: "subagent",
|
|
2571
2571
|
model: "opencode/grok-code",
|
|
2572
2572
|
temperature: 0.1,
|
|
2573
|
-
tools: { write: false, edit: false,
|
|
2573
|
+
tools: { write: false, edit: false, background_task: false },
|
|
2574
2574
|
prompt: `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
|
|
2575
2575
|
|
|
2576
2576
|
=== CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
|
|
@@ -3119,7 +3119,7 @@ var multimodalLookerAgent = {
|
|
|
3119
3119
|
mode: "subagent",
|
|
3120
3120
|
model: "google/gemini-2.5-flash",
|
|
3121
3121
|
temperature: 0.1,
|
|
3122
|
-
tools: {
|
|
3122
|
+
tools: { write: false, edit: false, bash: false, background_task: false },
|
|
3123
3123
|
prompt: `You interpret media files that cannot be read as plain text.
|
|
3124
3124
|
|
|
3125
3125
|
Your job: examine the attached file and extract ONLY what was requested.
|
|
@@ -3183,7 +3183,11 @@ import { spawn } from "child_process";
|
|
|
3183
3183
|
import { exec } from "child_process";
|
|
3184
3184
|
import { promisify } from "util";
|
|
3185
3185
|
import { existsSync } from "fs";
|
|
3186
|
+
import { homedir } from "os";
|
|
3186
3187
|
var DEFAULT_ZSH_PATHS = ["/bin/zsh", "/usr/bin/zsh", "/usr/local/bin/zsh"];
|
|
3188
|
+
function getHomeDir() {
|
|
3189
|
+
return process.env.HOME || process.env.USERPROFILE || homedir();
|
|
3190
|
+
}
|
|
3187
3191
|
function findZshPath(customZshPath) {
|
|
3188
3192
|
if (customZshPath && existsSync(customZshPath)) {
|
|
3189
3193
|
return customZshPath;
|
|
@@ -3197,7 +3201,7 @@ function findZshPath(customZshPath) {
|
|
|
3197
3201
|
}
|
|
3198
3202
|
var execAsync = promisify(exec);
|
|
3199
3203
|
async function executeHookCommand(command, stdin, cwd, options) {
|
|
3200
|
-
const home =
|
|
3204
|
+
const home = getHomeDir();
|
|
3201
3205
|
let expandedCommand = command.replace(/^~(?=\/|$)/g, home).replace(/\s~(?=\/)/g, ` ${home}`).replace(/\$CLAUDE_PROJECT_DIR/g, cwd).replace(/\$\{CLAUDE_PROJECT_DIR\}/g, cwd);
|
|
3202
3206
|
let finalCommand = expandedCommand;
|
|
3203
3207
|
if (options?.forceZsh) {
|
|
@@ -3692,8 +3696,8 @@ import { join as join4 } from "path";
|
|
|
3692
3696
|
|
|
3693
3697
|
// src/features/hook-message-injector/constants.ts
|
|
3694
3698
|
import { join as join3 } from "path";
|
|
3695
|
-
import { homedir } from "os";
|
|
3696
|
-
var xdgData = process.env.XDG_DATA_HOME || join3(
|
|
3699
|
+
import { homedir as homedir2 } from "os";
|
|
3700
|
+
var xdgData = process.env.XDG_DATA_HOME || join3(homedir2(), ".local", "share");
|
|
3697
3701
|
var OPENCODE_STORAGE = join3(xdgData, "opencode", "storage");
|
|
3698
3702
|
var MESSAGE_STORAGE = join3(OPENCODE_STORAGE, "message");
|
|
3699
3703
|
var PART_STORAGE = join3(OPENCODE_STORAGE, "part");
|
|
@@ -4073,7 +4077,7 @@ async function sendNotification(ctx, p, title, message) {
|
|
|
4073
4077
|
await ctx.$`osascript -e ${'display notification "' + escapedMessage + '" with title "' + escapedTitle + '"'}`;
|
|
4074
4078
|
break;
|
|
4075
4079
|
case "linux":
|
|
4076
|
-
await ctx.$`notify-send ${escapedTitle} ${escapedMessage}`.catch(() => {});
|
|
4080
|
+
await ctx.$`notify-send ${escapedTitle} ${escapedMessage} 2>/dev/null`.catch(() => {});
|
|
4077
4081
|
break;
|
|
4078
4082
|
case "win32":
|
|
4079
4083
|
await ctx.$`powershell -Command ${"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('" + escapedMessage + "', '" + escapedTitle + "')"}`;
|
|
@@ -4086,8 +4090,8 @@ async function playSound(ctx, p, soundPath) {
|
|
|
4086
4090
|
ctx.$`afplay ${soundPath}`.catch(() => {});
|
|
4087
4091
|
break;
|
|
4088
4092
|
case "linux":
|
|
4089
|
-
ctx.$`paplay ${soundPath}`.catch(() => {
|
|
4090
|
-
ctx.$`aplay ${soundPath}`.catch(() => {});
|
|
4093
|
+
ctx.$`paplay ${soundPath} 2>/dev/null`.catch(() => {
|
|
4094
|
+
ctx.$`aplay ${soundPath} 2>/dev/null`.catch(() => {});
|
|
4091
4095
|
});
|
|
4092
4096
|
break;
|
|
4093
4097
|
case "win32":
|
|
@@ -4516,7 +4520,25 @@ function getErrorMessage(error) {
|
|
|
4516
4520
|
if (typeof error === "string")
|
|
4517
4521
|
return error.toLowerCase();
|
|
4518
4522
|
const errorObj = error;
|
|
4519
|
-
|
|
4523
|
+
const paths = [
|
|
4524
|
+
errorObj.data,
|
|
4525
|
+
errorObj.error,
|
|
4526
|
+
errorObj,
|
|
4527
|
+
errorObj.data?.error
|
|
4528
|
+
];
|
|
4529
|
+
for (const obj of paths) {
|
|
4530
|
+
if (obj && typeof obj === "object") {
|
|
4531
|
+
const msg = obj.message;
|
|
4532
|
+
if (typeof msg === "string" && msg.length > 0) {
|
|
4533
|
+
return msg.toLowerCase();
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4536
|
+
}
|
|
4537
|
+
try {
|
|
4538
|
+
return JSON.stringify(error).toLowerCase();
|
|
4539
|
+
} catch {
|
|
4540
|
+
return "";
|
|
4541
|
+
}
|
|
4520
4542
|
}
|
|
4521
4543
|
function extractMessageIndex(error) {
|
|
4522
4544
|
const message = getErrorMessage(error);
|
|
@@ -4534,7 +4556,7 @@ function detectErrorType(error) {
|
|
|
4534
4556
|
if (message.includes("thinking is disabled") && message.includes("cannot contain")) {
|
|
4535
4557
|
return "thinking_disabled_violation";
|
|
4536
4558
|
}
|
|
4537
|
-
if (message.includes("non-empty content") || message.includes("must have non-empty content")) {
|
|
4559
|
+
if (message.includes("non-empty content") || message.includes("must have non-empty content") || message.includes("content") && message.includes("is empty") || message.includes("content field") && message.includes("empty")) {
|
|
4538
4560
|
return "empty_content_message";
|
|
4539
4561
|
}
|
|
4540
4562
|
return null;
|
|
@@ -4727,15 +4749,16 @@ import { createRequire as createRequire2 } from "module";
|
|
|
4727
4749
|
import { dirname, join as join9 } from "path";
|
|
4728
4750
|
import { existsSync as existsSync7 } from "fs";
|
|
4729
4751
|
import * as fs2 from "fs";
|
|
4752
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
4730
4753
|
|
|
4731
4754
|
// src/hooks/comment-checker/downloader.ts
|
|
4732
4755
|
var {spawn: spawn2 } = globalThis.Bun;
|
|
4733
4756
|
import { existsSync as existsSync6, mkdirSync as mkdirSync3, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync2 } from "fs";
|
|
4734
4757
|
import { join as join8 } from "path";
|
|
4735
|
-
import { homedir as
|
|
4758
|
+
import { homedir as homedir3, tmpdir as tmpdir2 } from "os";
|
|
4736
4759
|
import { createRequire } from "module";
|
|
4737
4760
|
var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
|
|
4738
|
-
var DEBUG_FILE = "
|
|
4761
|
+
var DEBUG_FILE = join8(tmpdir2(), "comment-checker-debug.log");
|
|
4739
4762
|
function debugLog(...args) {
|
|
4740
4763
|
if (DEBUG) {
|
|
4741
4764
|
const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
@@ -4753,7 +4776,7 @@ var PLATFORM_MAP = {
|
|
|
4753
4776
|
};
|
|
4754
4777
|
function getCacheDir() {
|
|
4755
4778
|
const xdgCache2 = process.env.XDG_CACHE_HOME;
|
|
4756
|
-
const base = xdgCache2 || join8(
|
|
4779
|
+
const base = xdgCache2 || join8(homedir3(), ".cache");
|
|
4757
4780
|
return join8(base, "oh-my-opencode", "bin");
|
|
4758
4781
|
}
|
|
4759
4782
|
function getBinaryName() {
|
|
@@ -4863,7 +4886,7 @@ async function ensureCommentCheckerBinary() {
|
|
|
4863
4886
|
|
|
4864
4887
|
// src/hooks/comment-checker/cli.ts
|
|
4865
4888
|
var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
|
|
4866
|
-
var DEBUG_FILE2 = "
|
|
4889
|
+
var DEBUG_FILE2 = join9(tmpdir3(), "comment-checker-debug.log");
|
|
4867
4890
|
function debugLog2(...args) {
|
|
4868
4891
|
if (DEBUG2) {
|
|
4869
4892
|
const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
@@ -4976,8 +4999,10 @@ async function runCommentChecker(input, cliPath) {
|
|
|
4976
4999
|
// src/hooks/comment-checker/index.ts
|
|
4977
5000
|
import * as fs3 from "fs";
|
|
4978
5001
|
import { existsSync as existsSync8 } from "fs";
|
|
5002
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
5003
|
+
import { join as join10 } from "path";
|
|
4979
5004
|
var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
|
|
4980
|
-
var DEBUG_FILE3 = "
|
|
5005
|
+
var DEBUG_FILE3 = join10(tmpdir4(), "comment-checker-debug.log");
|
|
4981
5006
|
function debugLog3(...args) {
|
|
4982
5007
|
if (DEBUG3) {
|
|
4983
5008
|
const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
@@ -5123,7 +5148,7 @@ function createToolOutputTruncatorHook(ctx) {
|
|
|
5123
5148
|
}
|
|
5124
5149
|
// src/hooks/directory-agents-injector/index.ts
|
|
5125
5150
|
import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
|
|
5126
|
-
import { dirname as dirname2, join as
|
|
5151
|
+
import { dirname as dirname2, join as join13, resolve as resolve2 } from "path";
|
|
5127
5152
|
|
|
5128
5153
|
// src/hooks/directory-agents-injector/storage.ts
|
|
5129
5154
|
import {
|
|
@@ -5133,17 +5158,17 @@ import {
|
|
|
5133
5158
|
writeFileSync as writeFileSync3,
|
|
5134
5159
|
unlinkSync as unlinkSync3
|
|
5135
5160
|
} from "fs";
|
|
5136
|
-
import { join as
|
|
5161
|
+
import { join as join12 } from "path";
|
|
5137
5162
|
|
|
5138
5163
|
// src/hooks/directory-agents-injector/constants.ts
|
|
5139
|
-
import { join as
|
|
5140
|
-
var OPENCODE_STORAGE3 =
|
|
5141
|
-
var AGENTS_INJECTOR_STORAGE =
|
|
5164
|
+
import { join as join11 } from "path";
|
|
5165
|
+
var OPENCODE_STORAGE3 = join11(xdgData2 ?? "", "opencode", "storage");
|
|
5166
|
+
var AGENTS_INJECTOR_STORAGE = join11(OPENCODE_STORAGE3, "directory-agents");
|
|
5142
5167
|
var AGENTS_FILENAME = "AGENTS.md";
|
|
5143
5168
|
|
|
5144
5169
|
// src/hooks/directory-agents-injector/storage.ts
|
|
5145
5170
|
function getStoragePath(sessionID) {
|
|
5146
|
-
return
|
|
5171
|
+
return join12(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
5147
5172
|
}
|
|
5148
5173
|
function loadInjectedPaths(sessionID) {
|
|
5149
5174
|
const filePath = getStoragePath(sessionID);
|
|
@@ -5195,7 +5220,7 @@ function createDirectoryAgentsInjectorHook(ctx) {
|
|
|
5195
5220
|
const found = [];
|
|
5196
5221
|
let current = startDir;
|
|
5197
5222
|
while (true) {
|
|
5198
|
-
const agentsPath =
|
|
5223
|
+
const agentsPath = join13(current, AGENTS_FILENAME);
|
|
5199
5224
|
if (existsSync10(agentsPath)) {
|
|
5200
5225
|
found.push(agentsPath);
|
|
5201
5226
|
}
|
|
@@ -5264,7 +5289,7 @@ ${content}`;
|
|
|
5264
5289
|
}
|
|
5265
5290
|
// src/hooks/directory-readme-injector/index.ts
|
|
5266
5291
|
import { existsSync as existsSync12, readFileSync as readFileSync7 } from "fs";
|
|
5267
|
-
import { dirname as dirname3, join as
|
|
5292
|
+
import { dirname as dirname3, join as join16, resolve as resolve3 } from "path";
|
|
5268
5293
|
|
|
5269
5294
|
// src/hooks/directory-readme-injector/storage.ts
|
|
5270
5295
|
import {
|
|
@@ -5274,17 +5299,17 @@ import {
|
|
|
5274
5299
|
writeFileSync as writeFileSync4,
|
|
5275
5300
|
unlinkSync as unlinkSync4
|
|
5276
5301
|
} from "fs";
|
|
5277
|
-
import { join as
|
|
5302
|
+
import { join as join15 } from "path";
|
|
5278
5303
|
|
|
5279
5304
|
// src/hooks/directory-readme-injector/constants.ts
|
|
5280
|
-
import { join as
|
|
5281
|
-
var OPENCODE_STORAGE4 =
|
|
5282
|
-
var README_INJECTOR_STORAGE =
|
|
5305
|
+
import { join as join14 } from "path";
|
|
5306
|
+
var OPENCODE_STORAGE4 = join14(xdgData2 ?? "", "opencode", "storage");
|
|
5307
|
+
var README_INJECTOR_STORAGE = join14(OPENCODE_STORAGE4, "directory-readme");
|
|
5283
5308
|
var README_FILENAME = "README.md";
|
|
5284
5309
|
|
|
5285
5310
|
// src/hooks/directory-readme-injector/storage.ts
|
|
5286
5311
|
function getStoragePath2(sessionID) {
|
|
5287
|
-
return
|
|
5312
|
+
return join15(README_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
5288
5313
|
}
|
|
5289
5314
|
function loadInjectedPaths2(sessionID) {
|
|
5290
5315
|
const filePath = getStoragePath2(sessionID);
|
|
@@ -5336,7 +5361,7 @@ function createDirectoryReadmeInjectorHook(ctx) {
|
|
|
5336
5361
|
const found = [];
|
|
5337
5362
|
let current = startDir;
|
|
5338
5363
|
while (true) {
|
|
5339
|
-
const readmePath =
|
|
5364
|
+
const readmePath = join16(current, README_FILENAME);
|
|
5340
5365
|
if (existsSync12(readmePath)) {
|
|
5341
5366
|
found.push(readmePath);
|
|
5342
5367
|
}
|
|
@@ -5565,11 +5590,15 @@ function parseAnthropicTokenLimitError(err) {
|
|
|
5565
5590
|
|
|
5566
5591
|
// src/hooks/anthropic-auto-compact/types.ts
|
|
5567
5592
|
var RETRY_CONFIG = {
|
|
5568
|
-
maxAttempts:
|
|
5593
|
+
maxAttempts: 2,
|
|
5569
5594
|
initialDelayMs: 2000,
|
|
5570
5595
|
backoffFactor: 2,
|
|
5571
5596
|
maxDelayMs: 30000
|
|
5572
5597
|
};
|
|
5598
|
+
var FALLBACK_CONFIG = {
|
|
5599
|
+
maxRevertAttempts: 3,
|
|
5600
|
+
minMessagesRequired: 2
|
|
5601
|
+
};
|
|
5573
5602
|
|
|
5574
5603
|
// src/hooks/anthropic-auto-compact/executor.ts
|
|
5575
5604
|
function calculateRetryDelay(attempt) {
|
|
@@ -5589,6 +5618,92 @@ function getOrCreateRetryState(autoCompactState, sessionID) {
|
|
|
5589
5618
|
}
|
|
5590
5619
|
return state;
|
|
5591
5620
|
}
|
|
5621
|
+
function getOrCreateFallbackState(autoCompactState, sessionID) {
|
|
5622
|
+
let state = autoCompactState.fallbackStateBySession.get(sessionID);
|
|
5623
|
+
if (!state) {
|
|
5624
|
+
state = { revertAttempt: 0 };
|
|
5625
|
+
autoCompactState.fallbackStateBySession.set(sessionID, state);
|
|
5626
|
+
}
|
|
5627
|
+
return state;
|
|
5628
|
+
}
|
|
5629
|
+
async function getLastMessagePair(sessionID, client, directory) {
|
|
5630
|
+
try {
|
|
5631
|
+
const resp = await client.session.messages({
|
|
5632
|
+
path: { id: sessionID },
|
|
5633
|
+
query: { directory }
|
|
5634
|
+
});
|
|
5635
|
+
const data = resp.data;
|
|
5636
|
+
if (!Array.isArray(data) || data.length < FALLBACK_CONFIG.minMessagesRequired) {
|
|
5637
|
+
return null;
|
|
5638
|
+
}
|
|
5639
|
+
const reversed = [...data].reverse();
|
|
5640
|
+
const lastAssistant = reversed.find((m) => {
|
|
5641
|
+
const msg = m;
|
|
5642
|
+
const info = msg.info;
|
|
5643
|
+
return info?.role === "assistant";
|
|
5644
|
+
});
|
|
5645
|
+
const lastUser = reversed.find((m) => {
|
|
5646
|
+
const msg = m;
|
|
5647
|
+
const info = msg.info;
|
|
5648
|
+
return info?.role === "user";
|
|
5649
|
+
});
|
|
5650
|
+
if (!lastUser)
|
|
5651
|
+
return null;
|
|
5652
|
+
const userInfo = lastUser.info;
|
|
5653
|
+
const userMessageID = userInfo?.id;
|
|
5654
|
+
if (!userMessageID)
|
|
5655
|
+
return null;
|
|
5656
|
+
let assistantMessageID;
|
|
5657
|
+
if (lastAssistant) {
|
|
5658
|
+
const assistantInfo = lastAssistant.info;
|
|
5659
|
+
assistantMessageID = assistantInfo?.id;
|
|
5660
|
+
}
|
|
5661
|
+
return { userMessageID, assistantMessageID };
|
|
5662
|
+
} catch {
|
|
5663
|
+
return null;
|
|
5664
|
+
}
|
|
5665
|
+
}
|
|
5666
|
+
async function executeRevertFallback(sessionID, autoCompactState, client, directory) {
|
|
5667
|
+
const fallbackState = getOrCreateFallbackState(autoCompactState, sessionID);
|
|
5668
|
+
if (fallbackState.revertAttempt >= FALLBACK_CONFIG.maxRevertAttempts) {
|
|
5669
|
+
return false;
|
|
5670
|
+
}
|
|
5671
|
+
const pair = await getLastMessagePair(sessionID, client, directory);
|
|
5672
|
+
if (!pair) {
|
|
5673
|
+
return false;
|
|
5674
|
+
}
|
|
5675
|
+
await client.tui.showToast({
|
|
5676
|
+
body: {
|
|
5677
|
+
title: "\u26A0\uFE0F Emergency Recovery",
|
|
5678
|
+
message: `Context too large. Removing last message pair to recover session...`,
|
|
5679
|
+
variant: "warning",
|
|
5680
|
+
duration: 4000
|
|
5681
|
+
}
|
|
5682
|
+
}).catch(() => {});
|
|
5683
|
+
try {
|
|
5684
|
+
if (pair.assistantMessageID) {
|
|
5685
|
+
await client.session.revert({
|
|
5686
|
+
path: { id: sessionID },
|
|
5687
|
+
body: { messageID: pair.assistantMessageID },
|
|
5688
|
+
query: { directory }
|
|
5689
|
+
});
|
|
5690
|
+
}
|
|
5691
|
+
await client.session.revert({
|
|
5692
|
+
path: { id: sessionID },
|
|
5693
|
+
body: { messageID: pair.userMessageID },
|
|
5694
|
+
query: { directory }
|
|
5695
|
+
});
|
|
5696
|
+
fallbackState.revertAttempt++;
|
|
5697
|
+
fallbackState.lastRevertedMessageID = pair.userMessageID;
|
|
5698
|
+
const retryState = autoCompactState.retryStateBySession.get(sessionID);
|
|
5699
|
+
if (retryState) {
|
|
5700
|
+
retryState.attempt = 0;
|
|
5701
|
+
}
|
|
5702
|
+
return true;
|
|
5703
|
+
} catch {
|
|
5704
|
+
return false;
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5592
5707
|
async function getLastAssistant(sessionID, client, directory) {
|
|
5593
5708
|
try {
|
|
5594
5709
|
const resp = await client.session.messages({
|
|
@@ -5615,15 +5730,34 @@ function clearSessionState(autoCompactState, sessionID) {
|
|
|
5615
5730
|
autoCompactState.pendingCompact.delete(sessionID);
|
|
5616
5731
|
autoCompactState.errorDataBySession.delete(sessionID);
|
|
5617
5732
|
autoCompactState.retryStateBySession.delete(sessionID);
|
|
5733
|
+
autoCompactState.fallbackStateBySession.delete(sessionID);
|
|
5618
5734
|
}
|
|
5619
5735
|
async function executeCompact(sessionID, msg, autoCompactState, client, directory) {
|
|
5620
5736
|
const retryState = getOrCreateRetryState(autoCompactState, sessionID);
|
|
5621
5737
|
if (!shouldRetry(retryState)) {
|
|
5738
|
+
const fallbackState = getOrCreateFallbackState(autoCompactState, sessionID);
|
|
5739
|
+
if (fallbackState.revertAttempt < FALLBACK_CONFIG.maxRevertAttempts) {
|
|
5740
|
+
const reverted = await executeRevertFallback(sessionID, autoCompactState, client, directory);
|
|
5741
|
+
if (reverted) {
|
|
5742
|
+
await client.tui.showToast({
|
|
5743
|
+
body: {
|
|
5744
|
+
title: "Recovery Attempt",
|
|
5745
|
+
message: "Message removed. Retrying compaction...",
|
|
5746
|
+
variant: "info",
|
|
5747
|
+
duration: 3000
|
|
5748
|
+
}
|
|
5749
|
+
}).catch(() => {});
|
|
5750
|
+
setTimeout(() => {
|
|
5751
|
+
executeCompact(sessionID, msg, autoCompactState, client, directory);
|
|
5752
|
+
}, 1000);
|
|
5753
|
+
return;
|
|
5754
|
+
}
|
|
5755
|
+
}
|
|
5622
5756
|
clearSessionState(autoCompactState, sessionID);
|
|
5623
5757
|
await client.tui.showToast({
|
|
5624
5758
|
body: {
|
|
5625
5759
|
title: "Auto Compact Failed",
|
|
5626
|
-
message: `Failed after ${RETRY_CONFIG.maxAttempts}
|
|
5760
|
+
message: `Failed after ${RETRY_CONFIG.maxAttempts} retries and ${FALLBACK_CONFIG.maxRevertAttempts} message removals. Please start a new session.`,
|
|
5627
5761
|
variant: "error",
|
|
5628
5762
|
duration: 5000
|
|
5629
5763
|
}
|
|
@@ -5669,7 +5803,8 @@ function createAutoCompactState() {
|
|
|
5669
5803
|
return {
|
|
5670
5804
|
pendingCompact: new Set,
|
|
5671
5805
|
errorDataBySession: new Map,
|
|
5672
|
-
retryStateBySession: new Map
|
|
5806
|
+
retryStateBySession: new Map,
|
|
5807
|
+
fallbackStateBySession: new Map
|
|
5673
5808
|
};
|
|
5674
5809
|
}
|
|
5675
5810
|
function createAnthropicAutoCompactHook(ctx) {
|
|
@@ -5682,6 +5817,7 @@ function createAnthropicAutoCompactHook(ctx) {
|
|
|
5682
5817
|
autoCompactState.pendingCompact.delete(sessionInfo.id);
|
|
5683
5818
|
autoCompactState.errorDataBySession.delete(sessionInfo.id);
|
|
5684
5819
|
autoCompactState.retryStateBySession.delete(sessionInfo.id);
|
|
5820
|
+
autoCompactState.fallbackStateBySession.delete(sessionInfo.id);
|
|
5685
5821
|
}
|
|
5686
5822
|
return;
|
|
5687
5823
|
}
|
|
@@ -6024,8 +6160,8 @@ function createThinkModeHook() {
|
|
|
6024
6160
|
};
|
|
6025
6161
|
}
|
|
6026
6162
|
// src/hooks/claude-code-hooks/config.ts
|
|
6027
|
-
import { homedir as
|
|
6028
|
-
import { join as
|
|
6163
|
+
import { homedir as homedir4 } from "os";
|
|
6164
|
+
import { join as join17 } from "path";
|
|
6029
6165
|
import { existsSync as existsSync13 } from "fs";
|
|
6030
6166
|
function normalizeHookMatcher(raw) {
|
|
6031
6167
|
return {
|
|
@@ -6049,11 +6185,11 @@ function normalizeHooksConfig(raw) {
|
|
|
6049
6185
|
return result;
|
|
6050
6186
|
}
|
|
6051
6187
|
function getClaudeSettingsPaths(customPath) {
|
|
6052
|
-
const home =
|
|
6188
|
+
const home = homedir4();
|
|
6053
6189
|
const paths = [
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6190
|
+
join17(home, ".claude", "settings.json"),
|
|
6191
|
+
join17(process.cwd(), ".claude", "settings.json"),
|
|
6192
|
+
join17(process.cwd(), ".claude", "settings.local.json")
|
|
6057
6193
|
];
|
|
6058
6194
|
if (customPath && existsSync13(customPath)) {
|
|
6059
6195
|
paths.unshift(customPath);
|
|
@@ -6097,11 +6233,11 @@ async function loadClaudeHooksConfig(customSettingsPath) {
|
|
|
6097
6233
|
|
|
6098
6234
|
// src/hooks/claude-code-hooks/config-loader.ts
|
|
6099
6235
|
import { existsSync as existsSync14 } from "fs";
|
|
6100
|
-
import { homedir as
|
|
6101
|
-
import { join as
|
|
6102
|
-
var USER_CONFIG_PATH =
|
|
6236
|
+
import { homedir as homedir5 } from "os";
|
|
6237
|
+
import { join as join18 } from "path";
|
|
6238
|
+
var USER_CONFIG_PATH = join18(homedir5(), ".config", "opencode", "opencode-cc-plugin.json");
|
|
6103
6239
|
function getProjectConfigPath() {
|
|
6104
|
-
return
|
|
6240
|
+
return join18(process.cwd(), ".opencode", "opencode-cc-plugin.json");
|
|
6105
6241
|
}
|
|
6106
6242
|
async function loadConfigFromPath(path3) {
|
|
6107
6243
|
if (!existsSync14(path3)) {
|
|
@@ -6169,8 +6305,9 @@ function isHookCommandDisabled(eventType, command, config) {
|
|
|
6169
6305
|
}
|
|
6170
6306
|
|
|
6171
6307
|
// src/hooks/claude-code-hooks/plugin-config.ts
|
|
6308
|
+
var isWindows = process.platform === "win32";
|
|
6172
6309
|
var DEFAULT_CONFIG = {
|
|
6173
|
-
forceZsh:
|
|
6310
|
+
forceZsh: !isWindows,
|
|
6174
6311
|
zshPath: "/bin/zsh"
|
|
6175
6312
|
};
|
|
6176
6313
|
|
|
@@ -6282,13 +6419,13 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
|
|
|
6282
6419
|
}
|
|
6283
6420
|
|
|
6284
6421
|
// src/hooks/claude-code-hooks/transcript.ts
|
|
6285
|
-
import { join as
|
|
6422
|
+
import { join as join19 } from "path";
|
|
6286
6423
|
import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync15, writeFileSync as writeFileSync5, unlinkSync as unlinkSync5 } from "fs";
|
|
6287
|
-
import { homedir as
|
|
6424
|
+
import { homedir as homedir6, tmpdir as tmpdir5 } from "os";
|
|
6288
6425
|
import { randomUUID } from "crypto";
|
|
6289
|
-
var TRANSCRIPT_DIR =
|
|
6426
|
+
var TRANSCRIPT_DIR = join19(homedir6(), ".claude", "transcripts");
|
|
6290
6427
|
function getTranscriptPath(sessionId) {
|
|
6291
|
-
return
|
|
6428
|
+
return join19(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
|
|
6292
6429
|
}
|
|
6293
6430
|
function ensureTranscriptDir() {
|
|
6294
6431
|
if (!existsSync15(TRANSCRIPT_DIR)) {
|
|
@@ -6378,7 +6515,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
6378
6515
|
}
|
|
6379
6516
|
};
|
|
6380
6517
|
entries.push(JSON.stringify(currentEntry));
|
|
6381
|
-
const tempPath =
|
|
6518
|
+
const tempPath = join19(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
|
|
6382
6519
|
writeFileSync5(tempPath, entries.join(`
|
|
6383
6520
|
`) + `
|
|
6384
6521
|
`);
|
|
@@ -6398,7 +6535,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
6398
6535
|
]
|
|
6399
6536
|
}
|
|
6400
6537
|
};
|
|
6401
|
-
const tempPath =
|
|
6538
|
+
const tempPath = join19(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
|
|
6402
6539
|
writeFileSync5(tempPath, JSON.stringify(currentEntry) + `
|
|
6403
6540
|
`);
|
|
6404
6541
|
return tempPath;
|
|
@@ -6610,11 +6747,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
|
|
|
6610
6747
|
}
|
|
6611
6748
|
|
|
6612
6749
|
// src/hooks/claude-code-hooks/todo.ts
|
|
6613
|
-
import { join as
|
|
6614
|
-
import { homedir as
|
|
6615
|
-
var TODO_DIR =
|
|
6750
|
+
import { join as join20 } from "path";
|
|
6751
|
+
import { homedir as homedir7 } from "os";
|
|
6752
|
+
var TODO_DIR = join20(homedir7(), ".claude", "todos");
|
|
6616
6753
|
function getTodoPath(sessionId) {
|
|
6617
|
-
return
|
|
6754
|
+
return join20(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
|
|
6618
6755
|
}
|
|
6619
6756
|
|
|
6620
6757
|
// src/hooks/claude-code-hooks/stop.ts
|
|
@@ -6946,7 +7083,7 @@ ${result.message}`;
|
|
|
6946
7083
|
}
|
|
6947
7084
|
// src/hooks/rules-injector/index.ts
|
|
6948
7085
|
import { readFileSync as readFileSync9 } from "fs";
|
|
6949
|
-
import { homedir as
|
|
7086
|
+
import { homedir as homedir8 } from "os";
|
|
6950
7087
|
import { relative as relative3, resolve as resolve4 } from "path";
|
|
6951
7088
|
|
|
6952
7089
|
// src/hooks/rules-injector/finder.ts
|
|
@@ -6956,12 +7093,12 @@ import {
|
|
|
6956
7093
|
realpathSync,
|
|
6957
7094
|
statSync as statSync2
|
|
6958
7095
|
} from "fs";
|
|
6959
|
-
import { dirname as dirname4, join as
|
|
7096
|
+
import { dirname as dirname4, join as join22, relative } from "path";
|
|
6960
7097
|
|
|
6961
7098
|
// src/hooks/rules-injector/constants.ts
|
|
6962
|
-
import { join as
|
|
6963
|
-
var OPENCODE_STORAGE5 =
|
|
6964
|
-
var RULES_INJECTOR_STORAGE =
|
|
7099
|
+
import { join as join21 } from "path";
|
|
7100
|
+
var OPENCODE_STORAGE5 = join21(xdgData2 ?? "", "opencode", "storage");
|
|
7101
|
+
var RULES_INJECTOR_STORAGE = join21(OPENCODE_STORAGE5, "rules-injector");
|
|
6965
7102
|
var PROJECT_MARKERS = [
|
|
6966
7103
|
".git",
|
|
6967
7104
|
"pyproject.toml",
|
|
@@ -6988,7 +7125,7 @@ function findProjectRoot(startPath) {
|
|
|
6988
7125
|
}
|
|
6989
7126
|
while (true) {
|
|
6990
7127
|
for (const marker of PROJECT_MARKERS) {
|
|
6991
|
-
const markerPath =
|
|
7128
|
+
const markerPath = join22(current, marker);
|
|
6992
7129
|
if (existsSync16(markerPath)) {
|
|
6993
7130
|
return current;
|
|
6994
7131
|
}
|
|
@@ -7006,7 +7143,7 @@ function findRuleFilesRecursive(dir, results) {
|
|
|
7006
7143
|
try {
|
|
7007
7144
|
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
7008
7145
|
for (const entry of entries) {
|
|
7009
|
-
const fullPath =
|
|
7146
|
+
const fullPath = join22(dir, entry.name);
|
|
7010
7147
|
if (entry.isDirectory()) {
|
|
7011
7148
|
findRuleFilesRecursive(fullPath, results);
|
|
7012
7149
|
} else if (entry.isFile()) {
|
|
@@ -7032,7 +7169,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
|
|
|
7032
7169
|
let distance = 0;
|
|
7033
7170
|
while (true) {
|
|
7034
7171
|
for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
|
|
7035
|
-
const ruleDir =
|
|
7172
|
+
const ruleDir = join22(currentDir, parent, subdir);
|
|
7036
7173
|
const files = [];
|
|
7037
7174
|
findRuleFilesRecursive(ruleDir, files);
|
|
7038
7175
|
for (const filePath of files) {
|
|
@@ -7056,7 +7193,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
|
|
|
7056
7193
|
currentDir = parentDir;
|
|
7057
7194
|
distance++;
|
|
7058
7195
|
}
|
|
7059
|
-
const userRuleDir =
|
|
7196
|
+
const userRuleDir = join22(homeDir, USER_RULE_DIR);
|
|
7060
7197
|
const userFiles = [];
|
|
7061
7198
|
findRuleFilesRecursive(userRuleDir, userFiles);
|
|
7062
7199
|
for (const filePath of userFiles) {
|
|
@@ -7251,9 +7388,9 @@ import {
|
|
|
7251
7388
|
writeFileSync as writeFileSync6,
|
|
7252
7389
|
unlinkSync as unlinkSync6
|
|
7253
7390
|
} from "fs";
|
|
7254
|
-
import { join as
|
|
7391
|
+
import { join as join23 } from "path";
|
|
7255
7392
|
function getStoragePath3(sessionID) {
|
|
7256
|
-
return
|
|
7393
|
+
return join23(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
7257
7394
|
}
|
|
7258
7395
|
function loadInjectedRules(sessionID) {
|
|
7259
7396
|
const filePath = getStoragePath3(sessionID);
|
|
@@ -7314,7 +7451,7 @@ function createRulesInjectorHook(ctx) {
|
|
|
7314
7451
|
return;
|
|
7315
7452
|
const projectRoot = findProjectRoot(filePath);
|
|
7316
7453
|
const cache2 = getSessionCache(input.sessionID);
|
|
7317
|
-
const home =
|
|
7454
|
+
const home = homedir8();
|
|
7318
7455
|
const ruleFileCandidates = findRuleFiles(projectRoot, home, filePath);
|
|
7319
7456
|
const toInject = [];
|
|
7320
7457
|
for (const candidate of ruleFileCandidates) {
|
|
@@ -7692,12 +7829,12 @@ import {
|
|
|
7692
7829
|
writeFileSync as writeFileSync8,
|
|
7693
7830
|
unlinkSync as unlinkSync7
|
|
7694
7831
|
} from "fs";
|
|
7695
|
-
import { join as
|
|
7832
|
+
import { join as join28 } from "path";
|
|
7696
7833
|
|
|
7697
7834
|
// src/hooks/agent-usage-reminder/constants.ts
|
|
7698
|
-
import { join as
|
|
7699
|
-
var OPENCODE_STORAGE6 =
|
|
7700
|
-
var AGENT_USAGE_REMINDER_STORAGE =
|
|
7835
|
+
import { join as join27 } from "path";
|
|
7836
|
+
var OPENCODE_STORAGE6 = join27(xdgData2 ?? "", "opencode", "storage");
|
|
7837
|
+
var AGENT_USAGE_REMINDER_STORAGE = join27(OPENCODE_STORAGE6, "agent-usage-reminder");
|
|
7701
7838
|
var TARGET_TOOLS = new Set([
|
|
7702
7839
|
"grep",
|
|
7703
7840
|
"safe_grep",
|
|
@@ -7742,7 +7879,7 @@ ALWAYS prefer: Multiple parallel background_task calls > Direct tool calls
|
|
|
7742
7879
|
|
|
7743
7880
|
// src/hooks/agent-usage-reminder/storage.ts
|
|
7744
7881
|
function getStoragePath4(sessionID) {
|
|
7745
|
-
return
|
|
7882
|
+
return join28(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
|
|
7746
7883
|
}
|
|
7747
7884
|
function loadAgentUsageState(sessionID) {
|
|
7748
7885
|
const filePath = getStoragePath4(sessionID);
|
|
@@ -7991,12 +8128,12 @@ import {
|
|
|
7991
8128
|
writeFileSync as writeFileSync9,
|
|
7992
8129
|
unlinkSync as unlinkSync8
|
|
7993
8130
|
} from "fs";
|
|
7994
|
-
import { join as
|
|
8131
|
+
import { join as join30 } from "path";
|
|
7995
8132
|
|
|
7996
8133
|
// src/hooks/interactive-bash-session/constants.ts
|
|
7997
|
-
import { join as
|
|
7998
|
-
var OPENCODE_STORAGE7 =
|
|
7999
|
-
var INTERACTIVE_BASH_SESSION_STORAGE =
|
|
8134
|
+
import { join as join29 } from "path";
|
|
8135
|
+
var OPENCODE_STORAGE7 = join29(xdgData2 ?? "", "opencode", "storage");
|
|
8136
|
+
var INTERACTIVE_BASH_SESSION_STORAGE = join29(OPENCODE_STORAGE7, "interactive-bash-session");
|
|
8000
8137
|
var OMO_SESSION_PREFIX = "omo-";
|
|
8001
8138
|
function buildSessionReminderMessage(sessions) {
|
|
8002
8139
|
if (sessions.length === 0)
|
|
@@ -8008,7 +8145,7 @@ function buildSessionReminderMessage(sessions) {
|
|
|
8008
8145
|
|
|
8009
8146
|
// src/hooks/interactive-bash-session/storage.ts
|
|
8010
8147
|
function getStoragePath5(sessionID) {
|
|
8011
|
-
return
|
|
8148
|
+
return join30(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
|
|
8012
8149
|
}
|
|
8013
8150
|
function loadInteractiveBashSessionState(sessionID) {
|
|
8014
8151
|
const filePath = getStoragePath5(sessionID);
|
|
@@ -9782,8 +9919,8 @@ async function createGoogleAntigravityAuthPlugin({
|
|
|
9782
9919
|
}
|
|
9783
9920
|
// src/features/claude-code-command-loader/loader.ts
|
|
9784
9921
|
import { existsSync as existsSync22, readdirSync as readdirSync5, readFileSync as readFileSync14 } from "fs";
|
|
9785
|
-
import { homedir as
|
|
9786
|
-
import { join as
|
|
9922
|
+
import { homedir as homedir10 } from "os";
|
|
9923
|
+
import { join as join31, basename } from "path";
|
|
9787
9924
|
function loadCommandsFromDir(commandsDir, scope) {
|
|
9788
9925
|
if (!existsSync22(commandsDir)) {
|
|
9789
9926
|
return [];
|
|
@@ -9793,7 +9930,7 @@ function loadCommandsFromDir(commandsDir, scope) {
|
|
|
9793
9930
|
for (const entry of entries) {
|
|
9794
9931
|
if (!isMarkdownFile(entry))
|
|
9795
9932
|
continue;
|
|
9796
|
-
const commandPath =
|
|
9933
|
+
const commandPath = join31(commandsDir, entry.name);
|
|
9797
9934
|
const commandName = basename(entry.name, ".md");
|
|
9798
9935
|
try {
|
|
9799
9936
|
const content = readFileSync14(commandPath, "utf-8");
|
|
@@ -9836,29 +9973,29 @@ function commandsToRecord(commands) {
|
|
|
9836
9973
|
return result;
|
|
9837
9974
|
}
|
|
9838
9975
|
function loadUserCommands() {
|
|
9839
|
-
const userCommandsDir =
|
|
9976
|
+
const userCommandsDir = join31(homedir10(), ".claude", "commands");
|
|
9840
9977
|
const commands = loadCommandsFromDir(userCommandsDir, "user");
|
|
9841
9978
|
return commandsToRecord(commands);
|
|
9842
9979
|
}
|
|
9843
9980
|
function loadProjectCommands() {
|
|
9844
|
-
const projectCommandsDir =
|
|
9981
|
+
const projectCommandsDir = join31(process.cwd(), ".claude", "commands");
|
|
9845
9982
|
const commands = loadCommandsFromDir(projectCommandsDir, "project");
|
|
9846
9983
|
return commandsToRecord(commands);
|
|
9847
9984
|
}
|
|
9848
9985
|
function loadOpencodeGlobalCommands() {
|
|
9849
|
-
const opencodeCommandsDir =
|
|
9986
|
+
const opencodeCommandsDir = join31(homedir10(), ".config", "opencode", "command");
|
|
9850
9987
|
const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
|
|
9851
9988
|
return commandsToRecord(commands);
|
|
9852
9989
|
}
|
|
9853
9990
|
function loadOpencodeProjectCommands() {
|
|
9854
|
-
const opencodeProjectDir =
|
|
9991
|
+
const opencodeProjectDir = join31(process.cwd(), ".opencode", "command");
|
|
9855
9992
|
const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
|
|
9856
9993
|
return commandsToRecord(commands);
|
|
9857
9994
|
}
|
|
9858
9995
|
// src/features/claude-code-skill-loader/loader.ts
|
|
9859
9996
|
import { existsSync as existsSync23, readdirSync as readdirSync6, readFileSync as readFileSync15 } from "fs";
|
|
9860
|
-
import { homedir as
|
|
9861
|
-
import { join as
|
|
9997
|
+
import { homedir as homedir11 } from "os";
|
|
9998
|
+
import { join as join32 } from "path";
|
|
9862
9999
|
function loadSkillsFromDir(skillsDir, scope) {
|
|
9863
10000
|
if (!existsSync23(skillsDir)) {
|
|
9864
10001
|
return [];
|
|
@@ -9868,11 +10005,11 @@ function loadSkillsFromDir(skillsDir, scope) {
|
|
|
9868
10005
|
for (const entry of entries) {
|
|
9869
10006
|
if (entry.name.startsWith("."))
|
|
9870
10007
|
continue;
|
|
9871
|
-
const skillPath =
|
|
10008
|
+
const skillPath = join32(skillsDir, entry.name);
|
|
9872
10009
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
9873
10010
|
continue;
|
|
9874
10011
|
const resolvedPath = resolveSymlink(skillPath);
|
|
9875
|
-
const skillMdPath =
|
|
10012
|
+
const skillMdPath = join32(resolvedPath, "SKILL.md");
|
|
9876
10013
|
if (!existsSync23(skillMdPath))
|
|
9877
10014
|
continue;
|
|
9878
10015
|
try {
|
|
@@ -9907,7 +10044,7 @@ $ARGUMENTS
|
|
|
9907
10044
|
return skills;
|
|
9908
10045
|
}
|
|
9909
10046
|
function loadUserSkillsAsCommands() {
|
|
9910
|
-
const userSkillsDir =
|
|
10047
|
+
const userSkillsDir = join32(homedir11(), ".claude", "skills");
|
|
9911
10048
|
const skills = loadSkillsFromDir(userSkillsDir, "user");
|
|
9912
10049
|
return skills.reduce((acc, skill) => {
|
|
9913
10050
|
acc[skill.name] = skill.definition;
|
|
@@ -9915,7 +10052,7 @@ function loadUserSkillsAsCommands() {
|
|
|
9915
10052
|
}, {});
|
|
9916
10053
|
}
|
|
9917
10054
|
function loadProjectSkillsAsCommands() {
|
|
9918
|
-
const projectSkillsDir =
|
|
10055
|
+
const projectSkillsDir = join32(process.cwd(), ".claude", "skills");
|
|
9919
10056
|
const skills = loadSkillsFromDir(projectSkillsDir, "project");
|
|
9920
10057
|
return skills.reduce((acc, skill) => {
|
|
9921
10058
|
acc[skill.name] = skill.definition;
|
|
@@ -9924,8 +10061,8 @@ function loadProjectSkillsAsCommands() {
|
|
|
9924
10061
|
}
|
|
9925
10062
|
// src/features/claude-code-agent-loader/loader.ts
|
|
9926
10063
|
import { existsSync as existsSync24, readdirSync as readdirSync7, readFileSync as readFileSync16 } from "fs";
|
|
9927
|
-
import { homedir as
|
|
9928
|
-
import { join as
|
|
10064
|
+
import { homedir as homedir12 } from "os";
|
|
10065
|
+
import { join as join33, basename as basename2 } from "path";
|
|
9929
10066
|
function parseToolsConfig(toolsStr) {
|
|
9930
10067
|
if (!toolsStr)
|
|
9931
10068
|
return;
|
|
@@ -9947,7 +10084,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
9947
10084
|
for (const entry of entries) {
|
|
9948
10085
|
if (!isMarkdownFile(entry))
|
|
9949
10086
|
continue;
|
|
9950
|
-
const agentPath =
|
|
10087
|
+
const agentPath = join33(agentsDir, entry.name);
|
|
9951
10088
|
const agentName = basename2(entry.name, ".md");
|
|
9952
10089
|
try {
|
|
9953
10090
|
const content = readFileSync16(agentPath, "utf-8");
|
|
@@ -9977,7 +10114,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
9977
10114
|
return agents;
|
|
9978
10115
|
}
|
|
9979
10116
|
function loadUserAgents() {
|
|
9980
|
-
const userAgentsDir =
|
|
10117
|
+
const userAgentsDir = join33(homedir12(), ".claude", "agents");
|
|
9981
10118
|
const agents = loadAgentsFromDir(userAgentsDir, "user");
|
|
9982
10119
|
const result = {};
|
|
9983
10120
|
for (const agent of agents) {
|
|
@@ -9986,7 +10123,7 @@ function loadUserAgents() {
|
|
|
9986
10123
|
return result;
|
|
9987
10124
|
}
|
|
9988
10125
|
function loadProjectAgents() {
|
|
9989
|
-
const projectAgentsDir =
|
|
10126
|
+
const projectAgentsDir = join33(process.cwd(), ".claude", "agents");
|
|
9990
10127
|
const agents = loadAgentsFromDir(projectAgentsDir, "project");
|
|
9991
10128
|
const result = {};
|
|
9992
10129
|
for (const agent of agents) {
|
|
@@ -9996,8 +10133,8 @@ function loadProjectAgents() {
|
|
|
9996
10133
|
}
|
|
9997
10134
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
9998
10135
|
import { existsSync as existsSync25 } from "fs";
|
|
9999
|
-
import { homedir as
|
|
10000
|
-
import { join as
|
|
10136
|
+
import { homedir as homedir13 } from "os";
|
|
10137
|
+
import { join as join34 } from "path";
|
|
10001
10138
|
|
|
10002
10139
|
// src/features/claude-code-mcp-loader/env-expander.ts
|
|
10003
10140
|
function expandEnvVars(value) {
|
|
@@ -10063,12 +10200,12 @@ function transformMcpServer(name, server) {
|
|
|
10063
10200
|
|
|
10064
10201
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
10065
10202
|
function getMcpConfigPaths() {
|
|
10066
|
-
const home =
|
|
10203
|
+
const home = homedir13();
|
|
10067
10204
|
const cwd = process.cwd();
|
|
10068
10205
|
return [
|
|
10069
|
-
{ path:
|
|
10070
|
-
{ path:
|
|
10071
|
-
{ path:
|
|
10206
|
+
{ path: join34(home, ".claude", ".mcp.json"), scope: "user" },
|
|
10207
|
+
{ path: join34(cwd, ".mcp.json"), scope: "project" },
|
|
10208
|
+
{ path: join34(cwd, ".claude", ".mcp.json"), scope: "local" }
|
|
10072
10209
|
];
|
|
10073
10210
|
}
|
|
10074
10211
|
async function loadMcpConfigFile(filePath) {
|
|
@@ -10359,8 +10496,8 @@ var EXT_TO_LANG = {
|
|
|
10359
10496
|
};
|
|
10360
10497
|
// src/tools/lsp/config.ts
|
|
10361
10498
|
import { existsSync as existsSync26, readFileSync as readFileSync17 } from "fs";
|
|
10362
|
-
import { join as
|
|
10363
|
-
import { homedir as
|
|
10499
|
+
import { join as join35 } from "path";
|
|
10500
|
+
import { homedir as homedir14 } from "os";
|
|
10364
10501
|
function loadJsonFile(path6) {
|
|
10365
10502
|
if (!existsSync26(path6))
|
|
10366
10503
|
return null;
|
|
@@ -10373,9 +10510,9 @@ function loadJsonFile(path6) {
|
|
|
10373
10510
|
function getConfigPaths2() {
|
|
10374
10511
|
const cwd = process.cwd();
|
|
10375
10512
|
return {
|
|
10376
|
-
project:
|
|
10377
|
-
user:
|
|
10378
|
-
opencode:
|
|
10513
|
+
project: join35(cwd, ".opencode", "oh-my-opencode.json"),
|
|
10514
|
+
user: join35(homedir14(), ".config", "opencode", "oh-my-opencode.json"),
|
|
10515
|
+
opencode: join35(homedir14(), ".config", "opencode", "opencode.json")
|
|
10379
10516
|
};
|
|
10380
10517
|
}
|
|
10381
10518
|
function loadAllConfigs() {
|
|
@@ -10468,7 +10605,7 @@ function isServerInstalled(command) {
|
|
|
10468
10605
|
const pathEnv = process.env.PATH || "";
|
|
10469
10606
|
const paths = pathEnv.split(":");
|
|
10470
10607
|
for (const p of paths) {
|
|
10471
|
-
if (existsSync26(
|
|
10608
|
+
if (existsSync26(join35(p, cmd))) {
|
|
10472
10609
|
return true;
|
|
10473
10610
|
}
|
|
10474
10611
|
}
|
|
@@ -23967,14 +24104,14 @@ var lsp_code_action_resolve = tool({
|
|
|
23967
24104
|
});
|
|
23968
24105
|
// src/tools/ast-grep/constants.ts
|
|
23969
24106
|
import { createRequire as createRequire4 } from "module";
|
|
23970
|
-
import { dirname as dirname6, join as
|
|
24107
|
+
import { dirname as dirname6, join as join37 } from "path";
|
|
23971
24108
|
import { existsSync as existsSync29, statSync as statSync4 } from "fs";
|
|
23972
24109
|
|
|
23973
24110
|
// src/tools/ast-grep/downloader.ts
|
|
23974
24111
|
var {spawn: spawn5 } = globalThis.Bun;
|
|
23975
24112
|
import { existsSync as existsSync28, mkdirSync as mkdirSync10, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
|
|
23976
|
-
import { join as
|
|
23977
|
-
import { homedir as
|
|
24113
|
+
import { join as join36 } from "path";
|
|
24114
|
+
import { homedir as homedir15 } from "os";
|
|
23978
24115
|
import { createRequire as createRequire3 } from "module";
|
|
23979
24116
|
var REPO2 = "ast-grep/ast-grep";
|
|
23980
24117
|
var DEFAULT_VERSION = "0.40.0";
|
|
@@ -23999,18 +24136,18 @@ var PLATFORM_MAP2 = {
|
|
|
23999
24136
|
function getCacheDir3() {
|
|
24000
24137
|
if (process.platform === "win32") {
|
|
24001
24138
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
24002
|
-
const base2 = localAppData ||
|
|
24003
|
-
return
|
|
24139
|
+
const base2 = localAppData || join36(homedir15(), "AppData", "Local");
|
|
24140
|
+
return join36(base2, "oh-my-opencode", "bin");
|
|
24004
24141
|
}
|
|
24005
24142
|
const xdgCache2 = process.env.XDG_CACHE_HOME;
|
|
24006
|
-
const base = xdgCache2 ||
|
|
24007
|
-
return
|
|
24143
|
+
const base = xdgCache2 || join36(homedir15(), ".cache");
|
|
24144
|
+
return join36(base, "oh-my-opencode", "bin");
|
|
24008
24145
|
}
|
|
24009
24146
|
function getBinaryName3() {
|
|
24010
24147
|
return process.platform === "win32" ? "sg.exe" : "sg";
|
|
24011
24148
|
}
|
|
24012
24149
|
function getCachedBinaryPath2() {
|
|
24013
|
-
const binaryPath =
|
|
24150
|
+
const binaryPath = join36(getCacheDir3(), getBinaryName3());
|
|
24014
24151
|
return existsSync28(binaryPath) ? binaryPath : null;
|
|
24015
24152
|
}
|
|
24016
24153
|
async function extractZip2(archivePath, destDir) {
|
|
@@ -24037,7 +24174,7 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
24037
24174
|
}
|
|
24038
24175
|
const cacheDir = getCacheDir3();
|
|
24039
24176
|
const binaryName = getBinaryName3();
|
|
24040
|
-
const binaryPath =
|
|
24177
|
+
const binaryPath = join36(cacheDir, binaryName);
|
|
24041
24178
|
if (existsSync28(binaryPath)) {
|
|
24042
24179
|
return binaryPath;
|
|
24043
24180
|
}
|
|
@@ -24053,7 +24190,7 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
24053
24190
|
if (!response2.ok) {
|
|
24054
24191
|
throw new Error(`HTTP ${response2.status}: ${response2.statusText}`);
|
|
24055
24192
|
}
|
|
24056
|
-
const archivePath =
|
|
24193
|
+
const archivePath = join36(cacheDir, assetName);
|
|
24057
24194
|
const arrayBuffer = await response2.arrayBuffer();
|
|
24058
24195
|
await Bun.write(archivePath, arrayBuffer);
|
|
24059
24196
|
await extractZip2(archivePath, cacheDir);
|
|
@@ -24111,7 +24248,7 @@ function findSgCliPathSync() {
|
|
|
24111
24248
|
const require2 = createRequire4(import.meta.url);
|
|
24112
24249
|
const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
|
|
24113
24250
|
const cliDir = dirname6(cliPkgPath);
|
|
24114
|
-
const sgPath =
|
|
24251
|
+
const sgPath = join37(cliDir, binaryName);
|
|
24115
24252
|
if (existsSync29(sgPath) && isValidBinary(sgPath)) {
|
|
24116
24253
|
return sgPath;
|
|
24117
24254
|
}
|
|
@@ -24123,7 +24260,7 @@ function findSgCliPathSync() {
|
|
|
24123
24260
|
const pkgPath = require2.resolve(`${platformPkg}/package.json`);
|
|
24124
24261
|
const pkgDir = dirname6(pkgPath);
|
|
24125
24262
|
const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
24126
|
-
const binaryPath =
|
|
24263
|
+
const binaryPath = join37(pkgDir, astGrepName);
|
|
24127
24264
|
if (existsSync29(binaryPath) && isValidBinary(binaryPath)) {
|
|
24128
24265
|
return binaryPath;
|
|
24129
24266
|
}
|
|
@@ -24499,19 +24636,19 @@ var {spawn: spawn7 } = globalThis.Bun;
|
|
|
24499
24636
|
|
|
24500
24637
|
// src/tools/grep/constants.ts
|
|
24501
24638
|
import { existsSync as existsSync32 } from "fs";
|
|
24502
|
-
import { join as
|
|
24639
|
+
import { join as join39, dirname as dirname7 } from "path";
|
|
24503
24640
|
import { spawnSync } from "child_process";
|
|
24504
24641
|
|
|
24505
24642
|
// src/tools/grep/downloader.ts
|
|
24506
24643
|
import { existsSync as existsSync31, mkdirSync as mkdirSync11, chmodSync as chmodSync3, unlinkSync as unlinkSync10, readdirSync as readdirSync8 } from "fs";
|
|
24507
|
-
import { join as
|
|
24644
|
+
import { join as join38 } from "path";
|
|
24508
24645
|
function getInstallDir() {
|
|
24509
24646
|
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
24510
|
-
return
|
|
24647
|
+
return join38(homeDir, ".cache", "oh-my-opencode", "bin");
|
|
24511
24648
|
}
|
|
24512
24649
|
function getRgPath() {
|
|
24513
|
-
const
|
|
24514
|
-
return
|
|
24650
|
+
const isWindows2 = process.platform === "win32";
|
|
24651
|
+
return join38(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
|
|
24515
24652
|
}
|
|
24516
24653
|
function getInstalledRipgrepPath() {
|
|
24517
24654
|
const rgPath = getRgPath();
|
|
@@ -24521,8 +24658,8 @@ function getInstalledRipgrepPath() {
|
|
|
24521
24658
|
// src/tools/grep/constants.ts
|
|
24522
24659
|
var cachedCli = null;
|
|
24523
24660
|
function findExecutable(name) {
|
|
24524
|
-
const
|
|
24525
|
-
const cmd =
|
|
24661
|
+
const isWindows2 = process.platform === "win32";
|
|
24662
|
+
const cmd = isWindows2 ? "where" : "which";
|
|
24526
24663
|
try {
|
|
24527
24664
|
const result = spawnSync(cmd, [name], { encoding: "utf-8", timeout: 5000 });
|
|
24528
24665
|
if (result.status === 0 && result.stdout.trim()) {
|
|
@@ -24535,13 +24672,13 @@ function findExecutable(name) {
|
|
|
24535
24672
|
function getOpenCodeBundledRg() {
|
|
24536
24673
|
const execPath = process.execPath;
|
|
24537
24674
|
const execDir = dirname7(execPath);
|
|
24538
|
-
const
|
|
24539
|
-
const rgName =
|
|
24675
|
+
const isWindows2 = process.platform === "win32";
|
|
24676
|
+
const rgName = isWindows2 ? "rg.exe" : "rg";
|
|
24540
24677
|
const candidates = [
|
|
24541
|
-
|
|
24542
|
-
|
|
24543
|
-
|
|
24544
|
-
|
|
24678
|
+
join39(execDir, rgName),
|
|
24679
|
+
join39(execDir, "bin", rgName),
|
|
24680
|
+
join39(execDir, "..", "bin", rgName),
|
|
24681
|
+
join39(execDir, "..", "libexec", rgName)
|
|
24545
24682
|
];
|
|
24546
24683
|
for (const candidate of candidates) {
|
|
24547
24684
|
if (existsSync32(candidate)) {
|
|
@@ -24948,8 +25085,8 @@ var glob = tool({
|
|
|
24948
25085
|
});
|
|
24949
25086
|
// src/tools/slashcommand/tools.ts
|
|
24950
25087
|
import { existsSync as existsSync33, readdirSync as readdirSync9, readFileSync as readFileSync20 } from "fs";
|
|
24951
|
-
import { homedir as
|
|
24952
|
-
import { join as
|
|
25088
|
+
import { homedir as homedir16 } from "os";
|
|
25089
|
+
import { join as join40, basename as basename3, dirname as dirname8 } from "path";
|
|
24953
25090
|
function discoverCommandsFromDir(commandsDir, scope) {
|
|
24954
25091
|
if (!existsSync33(commandsDir)) {
|
|
24955
25092
|
return [];
|
|
@@ -24959,7 +25096,7 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
24959
25096
|
for (const entry of entries) {
|
|
24960
25097
|
if (!isMarkdownFile(entry))
|
|
24961
25098
|
continue;
|
|
24962
|
-
const commandPath =
|
|
25099
|
+
const commandPath = join40(commandsDir, entry.name);
|
|
24963
25100
|
const commandName = basename3(entry.name, ".md");
|
|
24964
25101
|
try {
|
|
24965
25102
|
const content = readFileSync20(commandPath, "utf-8");
|
|
@@ -24987,10 +25124,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
24987
25124
|
return commands;
|
|
24988
25125
|
}
|
|
24989
25126
|
function discoverCommandsSync() {
|
|
24990
|
-
const userCommandsDir =
|
|
24991
|
-
const projectCommandsDir =
|
|
24992
|
-
const opencodeGlobalDir =
|
|
24993
|
-
const opencodeProjectDir =
|
|
25127
|
+
const userCommandsDir = join40(homedir16(), ".claude", "commands");
|
|
25128
|
+
const projectCommandsDir = join40(process.cwd(), ".claude", "commands");
|
|
25129
|
+
const opencodeGlobalDir = join40(homedir16(), ".config", "opencode", "command");
|
|
25130
|
+
const opencodeProjectDir = join40(process.cwd(), ".opencode", "command");
|
|
24994
25131
|
const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
|
|
24995
25132
|
const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
|
|
24996
25133
|
const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
|
|
@@ -25123,8 +25260,8 @@ var SkillFrontmatterSchema = exports_external.object({
|
|
|
25123
25260
|
});
|
|
25124
25261
|
// src/tools/skill/tools.ts
|
|
25125
25262
|
import { existsSync as existsSync34, readdirSync as readdirSync10, readFileSync as readFileSync21 } from "fs";
|
|
25126
|
-
import { homedir as
|
|
25127
|
-
import { join as
|
|
25263
|
+
import { homedir as homedir17 } from "os";
|
|
25264
|
+
import { join as join41, basename as basename4 } from "path";
|
|
25128
25265
|
function parseSkillFrontmatter(data) {
|
|
25129
25266
|
return {
|
|
25130
25267
|
name: typeof data.name === "string" ? data.name : "",
|
|
@@ -25143,10 +25280,10 @@ function discoverSkillsFromDir(skillsDir, scope) {
|
|
|
25143
25280
|
for (const entry of entries) {
|
|
25144
25281
|
if (entry.name.startsWith("."))
|
|
25145
25282
|
continue;
|
|
25146
|
-
const skillPath =
|
|
25283
|
+
const skillPath = join41(skillsDir, entry.name);
|
|
25147
25284
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
25148
25285
|
const resolvedPath = resolveSymlink(skillPath);
|
|
25149
|
-
const skillMdPath =
|
|
25286
|
+
const skillMdPath = join41(resolvedPath, "SKILL.md");
|
|
25150
25287
|
if (!existsSync34(skillMdPath))
|
|
25151
25288
|
continue;
|
|
25152
25289
|
try {
|
|
@@ -25165,8 +25302,8 @@ function discoverSkillsFromDir(skillsDir, scope) {
|
|
|
25165
25302
|
return skills;
|
|
25166
25303
|
}
|
|
25167
25304
|
function discoverSkillsSync() {
|
|
25168
|
-
const userSkillsDir =
|
|
25169
|
-
const projectSkillsDir =
|
|
25305
|
+
const userSkillsDir = join41(homedir17(), ".claude", "skills");
|
|
25306
|
+
const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
|
|
25170
25307
|
const userSkills = discoverSkillsFromDir(userSkillsDir, "user");
|
|
25171
25308
|
const projectSkills = discoverSkillsFromDir(projectSkillsDir, "project");
|
|
25172
25309
|
return [...projectSkills, ...userSkills];
|
|
@@ -25176,7 +25313,7 @@ var skillListForDescription = availableSkills.map((s) => `- ${s.name}: ${s.descr
|
|
|
25176
25313
|
`);
|
|
25177
25314
|
async function parseSkillMd(skillPath) {
|
|
25178
25315
|
const resolvedPath = resolveSymlink(skillPath);
|
|
25179
|
-
const skillMdPath =
|
|
25316
|
+
const skillMdPath = join41(resolvedPath, "SKILL.md");
|
|
25180
25317
|
if (!existsSync34(skillMdPath)) {
|
|
25181
25318
|
return null;
|
|
25182
25319
|
}
|
|
@@ -25192,9 +25329,9 @@ async function parseSkillMd(skillPath) {
|
|
|
25192
25329
|
allowedTools: frontmatter2["allowed-tools"],
|
|
25193
25330
|
metadata: frontmatter2.metadata
|
|
25194
25331
|
};
|
|
25195
|
-
const referencesDir =
|
|
25196
|
-
const scriptsDir =
|
|
25197
|
-
const assetsDir =
|
|
25332
|
+
const referencesDir = join41(resolvedPath, "references");
|
|
25333
|
+
const scriptsDir = join41(resolvedPath, "scripts");
|
|
25334
|
+
const assetsDir = join41(resolvedPath, "assets");
|
|
25198
25335
|
const references = existsSync34(referencesDir) ? readdirSync10(referencesDir).filter((f) => !f.startsWith(".")) : [];
|
|
25199
25336
|
const scripts = existsSync34(scriptsDir) ? readdirSync10(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
|
|
25200
25337
|
const assets = existsSync34(assetsDir) ? readdirSync10(assetsDir).filter((f) => !f.startsWith(".")) : [];
|
|
@@ -25221,7 +25358,7 @@ async function discoverSkillsFromDirAsync(skillsDir) {
|
|
|
25221
25358
|
for (const entry of entries) {
|
|
25222
25359
|
if (entry.name.startsWith("."))
|
|
25223
25360
|
continue;
|
|
25224
|
-
const skillPath =
|
|
25361
|
+
const skillPath = join41(skillsDir, entry.name);
|
|
25225
25362
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
25226
25363
|
const skillInfo = await parseSkillMd(skillPath);
|
|
25227
25364
|
if (skillInfo) {
|
|
@@ -25232,8 +25369,8 @@ async function discoverSkillsFromDirAsync(skillsDir) {
|
|
|
25232
25369
|
return skills;
|
|
25233
25370
|
}
|
|
25234
25371
|
async function discoverSkills() {
|
|
25235
|
-
const userSkillsDir =
|
|
25236
|
-
const projectSkillsDir =
|
|
25372
|
+
const userSkillsDir = join41(homedir17(), ".claude", "skills");
|
|
25373
|
+
const projectSkillsDir = join41(process.cwd(), ".claude", "skills");
|
|
25237
25374
|
const userSkills = await discoverSkillsFromDirAsync(userSkillsDir);
|
|
25238
25375
|
const projectSkills = await discoverSkillsFromDirAsync(projectSkillsDir);
|
|
25239
25376
|
return [...projectSkills, ...userSkills];
|
|
@@ -25262,7 +25399,7 @@ async function loadSkillWithReferences(skill, includeRefs) {
|
|
|
25262
25399
|
const referencesLoaded = [];
|
|
25263
25400
|
if (includeRefs && skill.references.length > 0) {
|
|
25264
25401
|
for (const ref of skill.references) {
|
|
25265
|
-
const refPath =
|
|
25402
|
+
const refPath = join41(skill.path, "references", ref);
|
|
25266
25403
|
try {
|
|
25267
25404
|
let content = readFileSync21(refPath, "utf-8");
|
|
25268
25405
|
content = await resolveCommandsInText(content);
|
|
@@ -25355,17 +25492,33 @@ Try a different skill name.`;
|
|
|
25355
25492
|
});
|
|
25356
25493
|
// src/tools/interactive-bash/constants.ts
|
|
25357
25494
|
var DEFAULT_TIMEOUT_MS4 = 60000;
|
|
25495
|
+
var BLOCKED_TMUX_SUBCOMMANDS = [
|
|
25496
|
+
"capture-pane",
|
|
25497
|
+
"capturep",
|
|
25498
|
+
"save-buffer",
|
|
25499
|
+
"saveb",
|
|
25500
|
+
"show-buffer",
|
|
25501
|
+
"showb",
|
|
25502
|
+
"pipe-pane",
|
|
25503
|
+
"pipep"
|
|
25504
|
+
];
|
|
25358
25505
|
var INTERACTIVE_BASH_DESCRIPTION = `Execute tmux commands for interactive terminal session management.
|
|
25359
25506
|
|
|
25360
|
-
Use session names following the pattern "omo-{name}" for automatic tracking
|
|
25507
|
+
Use session names following the pattern "omo-{name}" for automatic tracking.
|
|
25508
|
+
|
|
25509
|
+
BLOCKED COMMANDS (use bash tool instead):
|
|
25510
|
+
- capture-pane / capturep: Use bash to read output files or pipe output
|
|
25511
|
+
- save-buffer / saveb: Use bash to save content to files
|
|
25512
|
+
- show-buffer / showb: Use bash to read buffer content
|
|
25513
|
+
- pipe-pane / pipep: Use bash for piping output`;
|
|
25361
25514
|
|
|
25362
25515
|
// src/tools/interactive-bash/utils.ts
|
|
25363
25516
|
var {spawn: spawn9 } = globalThis.Bun;
|
|
25364
25517
|
var tmuxPath = null;
|
|
25365
25518
|
var initPromise3 = null;
|
|
25366
25519
|
async function findTmuxPath() {
|
|
25367
|
-
const
|
|
25368
|
-
const cmd =
|
|
25520
|
+
const isWindows2 = process.platform === "win32";
|
|
25521
|
+
const cmd = isWindows2 ? "where" : "which";
|
|
25369
25522
|
try {
|
|
25370
25523
|
const proc = spawn9([cmd, "tmux"], {
|
|
25371
25524
|
stdout: "pipe",
|
|
@@ -25461,6 +25614,10 @@ var interactive_bash = tool({
|
|
|
25461
25614
|
if (parts.length === 0) {
|
|
25462
25615
|
return "Error: Empty tmux command";
|
|
25463
25616
|
}
|
|
25617
|
+
const subcommand = parts[0].toLowerCase();
|
|
25618
|
+
if (BLOCKED_TMUX_SUBCOMMANDS.includes(subcommand)) {
|
|
25619
|
+
return `Error: '${parts[0]}' is blocked. Use bash tool instead for capturing/printing terminal output.`;
|
|
25620
|
+
}
|
|
25464
25621
|
const proc = Bun.spawn([tmuxPath2, ...parts], {
|
|
25465
25622
|
stdout: "pipe",
|
|
25466
25623
|
stderr: "pipe"
|
|
@@ -26041,15 +26198,15 @@ var builtinTools = {
|
|
|
26041
26198
|
};
|
|
26042
26199
|
// src/features/background-agent/manager.ts
|
|
26043
26200
|
import { existsSync as existsSync35, readdirSync as readdirSync11 } from "fs";
|
|
26044
|
-
import { join as
|
|
26201
|
+
import { join as join42 } from "path";
|
|
26045
26202
|
function getMessageDir3(sessionID) {
|
|
26046
26203
|
if (!existsSync35(MESSAGE_STORAGE))
|
|
26047
26204
|
return null;
|
|
26048
|
-
const directPath =
|
|
26205
|
+
const directPath = join42(MESSAGE_STORAGE, sessionID);
|
|
26049
26206
|
if (existsSync35(directPath))
|
|
26050
26207
|
return directPath;
|
|
26051
26208
|
for (const dir of readdirSync11(MESSAGE_STORAGE)) {
|
|
26052
|
-
const sessionPath =
|
|
26209
|
+
const sessionPath = join42(MESSAGE_STORAGE, dir, sessionID);
|
|
26053
26210
|
if (existsSync35(sessionPath))
|
|
26054
26211
|
return sessionPath;
|
|
26055
26212
|
}
|
|
@@ -26106,7 +26263,6 @@ class BackgroundManager {
|
|
|
26106
26263
|
agent: input.agent,
|
|
26107
26264
|
tools: {
|
|
26108
26265
|
task: false,
|
|
26109
|
-
call_omo_agent: false,
|
|
26110
26266
|
background_task: false
|
|
26111
26267
|
},
|
|
26112
26268
|
parts: [{ type: "text", text: input.prompt }]
|
|
@@ -26149,6 +26305,20 @@ class BackgroundManager {
|
|
|
26149
26305
|
}
|
|
26150
26306
|
return;
|
|
26151
26307
|
}
|
|
26308
|
+
async checkSessionTodos(sessionID) {
|
|
26309
|
+
try {
|
|
26310
|
+
const response2 = await this.client.session.todo({
|
|
26311
|
+
path: { id: sessionID }
|
|
26312
|
+
});
|
|
26313
|
+
const todos = response2.data ?? response2;
|
|
26314
|
+
if (!todos || todos.length === 0)
|
|
26315
|
+
return false;
|
|
26316
|
+
const incomplete = todos.filter((t) => t.status !== "completed" && t.status !== "cancelled");
|
|
26317
|
+
return incomplete.length > 0;
|
|
26318
|
+
} catch {
|
|
26319
|
+
return false;
|
|
26320
|
+
}
|
|
26321
|
+
}
|
|
26152
26322
|
handleEvent(event) {
|
|
26153
26323
|
const props = event.properties;
|
|
26154
26324
|
if (event.type === "message.part.updated") {
|
|
@@ -26180,11 +26350,17 @@ class BackgroundManager {
|
|
|
26180
26350
|
const task = this.findBySession(sessionID);
|
|
26181
26351
|
if (!task || task.status !== "running")
|
|
26182
26352
|
return;
|
|
26183
|
-
|
|
26184
|
-
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
|
|
26353
|
+
this.checkSessionTodos(sessionID).then((hasIncompleteTodos2) => {
|
|
26354
|
+
if (hasIncompleteTodos2) {
|
|
26355
|
+
log("[background-agent] Task has incomplete todos, waiting for todo-continuation:", task.id);
|
|
26356
|
+
return;
|
|
26357
|
+
}
|
|
26358
|
+
task.status = "completed";
|
|
26359
|
+
task.completedAt = new Date;
|
|
26360
|
+
this.markForNotification(task);
|
|
26361
|
+
this.notifyParentSession(task);
|
|
26362
|
+
log("[background-agent] Task completed via session.idle event:", task.id);
|
|
26363
|
+
});
|
|
26188
26364
|
}
|
|
26189
26365
|
if (event.type === "session.deleted") {
|
|
26190
26366
|
const info = props?.info;
|
|
@@ -26304,6 +26480,11 @@ class BackgroundManager {
|
|
|
26304
26480
|
continue;
|
|
26305
26481
|
}
|
|
26306
26482
|
if (sessionStatus.type === "idle") {
|
|
26483
|
+
const hasIncompleteTodos2 = await this.checkSessionTodos(task.sessionID);
|
|
26484
|
+
if (hasIncompleteTodos2) {
|
|
26485
|
+
log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
|
|
26486
|
+
continue;
|
|
26487
|
+
}
|
|
26307
26488
|
task.status = "completed";
|
|
26308
26489
|
task.completedAt = new Date;
|
|
26309
26490
|
this.markForNotification(task);
|