oh-my-opencode 2.5.2 → 2.5.3
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 +50 -15
- package/README.ko.md +49 -14
- package/README.md +50 -15
- package/README.zh-cn.md +50 -15
- package/dist/agents/build-prompt.d.ts +31 -0
- package/dist/cli/index.js +1663 -1
- package/dist/cli/run/completion.d.ts +2 -0
- package/dist/cli/run/completion.test.d.ts +1 -0
- package/dist/cli/run/events.d.ts +7 -0
- package/dist/cli/run/events.test.d.ts +1 -0
- package/dist/cli/run/index.d.ts +2 -0
- package/dist/cli/run/runner.d.ts +2 -0
- package/dist/cli/run/types.d.ts +45 -0
- package/dist/config/schema.d.ts +105 -2
- package/dist/index.js +848 -285
- package/dist/shared/data-path.d.ts +15 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/tools/index.d.ts +52 -0
- package/dist/tools/session-manager/constants.d.ts +11 -0
- package/dist/tools/session-manager/index.d.ts +3 -0
- package/dist/tools/session-manager/storage.d.ts +8 -0
- package/dist/tools/session-manager/storage.test.d.ts +1 -0
- package/dist/tools/session-manager/tools.d.ts +52 -0
- package/dist/tools/session-manager/tools.test.d.ts +1 -0
- package/dist/tools/session-manager/types.d.ts +71 -0
- package/dist/tools/session-manager/utils.d.ts +11 -0
- package/dist/tools/session-manager/utils.test.d.ts +1 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -222,8 +222,8 @@ var require_utils = __commonJS((exports) => {
|
|
|
222
222
|
}
|
|
223
223
|
return output;
|
|
224
224
|
};
|
|
225
|
-
exports.basename = (
|
|
226
|
-
const segs =
|
|
225
|
+
exports.basename = (path5, { windows } = {}) => {
|
|
226
|
+
const segs = path5.split(windows ? /[\\/]/ : "/");
|
|
227
227
|
const last = segs[segs.length - 1];
|
|
228
228
|
if (last === "") {
|
|
229
229
|
return segs[segs.length - 2];
|
|
@@ -3269,6 +3269,18 @@ function getUserConfigDir() {
|
|
|
3269
3269
|
}
|
|
3270
3270
|
return process.env.XDG_CONFIG_HOME || path2.join(os2.homedir(), ".config");
|
|
3271
3271
|
}
|
|
3272
|
+
// src/shared/data-path.ts
|
|
3273
|
+
import * as path3 from "path";
|
|
3274
|
+
import * as os3 from "os";
|
|
3275
|
+
function getDataDir() {
|
|
3276
|
+
if (process.platform === "win32") {
|
|
3277
|
+
return process.env.LOCALAPPDATA ?? path3.join(os3.homedir(), "AppData", "Local");
|
|
3278
|
+
}
|
|
3279
|
+
return process.env.XDG_DATA_HOME ?? path3.join(os3.homedir(), ".local", "share");
|
|
3280
|
+
}
|
|
3281
|
+
function getOpenCodeStorageDir() {
|
|
3282
|
+
return path3.join(getDataDir(), "opencode", "storage");
|
|
3283
|
+
}
|
|
3272
3284
|
// src/shared/config-errors.ts
|
|
3273
3285
|
var configLoadErrors = [];
|
|
3274
3286
|
function getConfigLoadErrors() {
|
|
@@ -3356,7 +3368,7 @@ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory
|
|
|
3356
3368
|
}
|
|
3357
3369
|
// src/hooks/todo-continuation-enforcer.ts
|
|
3358
3370
|
import { existsSync as existsSync5, readdirSync as readdirSync2 } from "fs";
|
|
3359
|
-
import { join as
|
|
3371
|
+
import { join as join7 } from "path";
|
|
3360
3372
|
|
|
3361
3373
|
// src/features/claude-code-session-state/state.ts
|
|
3362
3374
|
var subagentSessions = new Set;
|
|
@@ -3369,15 +3381,13 @@ function getMainSessionID() {
|
|
|
3369
3381
|
}
|
|
3370
3382
|
// src/features/hook-message-injector/injector.ts
|
|
3371
3383
|
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync2, readdirSync, writeFileSync } from "fs";
|
|
3372
|
-
import { join as
|
|
3384
|
+
import { join as join6 } from "path";
|
|
3373
3385
|
|
|
3374
3386
|
// src/features/hook-message-injector/constants.ts
|
|
3375
|
-
import { join as
|
|
3376
|
-
|
|
3377
|
-
var
|
|
3378
|
-
var
|
|
3379
|
-
var MESSAGE_STORAGE = join4(OPENCODE_STORAGE, "message");
|
|
3380
|
-
var PART_STORAGE = join4(OPENCODE_STORAGE, "part");
|
|
3387
|
+
import { join as join5 } from "path";
|
|
3388
|
+
var OPENCODE_STORAGE = getOpenCodeStorageDir();
|
|
3389
|
+
var MESSAGE_STORAGE = join5(OPENCODE_STORAGE, "message");
|
|
3390
|
+
var PART_STORAGE = join5(OPENCODE_STORAGE, "part");
|
|
3381
3391
|
|
|
3382
3392
|
// src/features/hook-message-injector/injector.ts
|
|
3383
3393
|
function findNearestMessageWithFields(messageDir) {
|
|
@@ -3385,7 +3395,7 @@ function findNearestMessageWithFields(messageDir) {
|
|
|
3385
3395
|
const files = readdirSync(messageDir).filter((f) => f.endsWith(".json")).sort().reverse();
|
|
3386
3396
|
for (const file of files) {
|
|
3387
3397
|
try {
|
|
3388
|
-
const content = readFileSync2(
|
|
3398
|
+
const content = readFileSync2(join6(messageDir, file), "utf-8");
|
|
3389
3399
|
const msg = JSON.parse(content);
|
|
3390
3400
|
if (msg.agent && msg.model?.providerID && msg.model?.modelID) {
|
|
3391
3401
|
return msg;
|
|
@@ -3413,12 +3423,12 @@ function getOrCreateMessageDir(sessionID) {
|
|
|
3413
3423
|
if (!existsSync4(MESSAGE_STORAGE)) {
|
|
3414
3424
|
mkdirSync(MESSAGE_STORAGE, { recursive: true });
|
|
3415
3425
|
}
|
|
3416
|
-
const directPath =
|
|
3426
|
+
const directPath = join6(MESSAGE_STORAGE, sessionID);
|
|
3417
3427
|
if (existsSync4(directPath)) {
|
|
3418
3428
|
return directPath;
|
|
3419
3429
|
}
|
|
3420
3430
|
for (const dir of readdirSync(MESSAGE_STORAGE)) {
|
|
3421
|
-
const sessionPath =
|
|
3431
|
+
const sessionPath = join6(MESSAGE_STORAGE, dir, sessionID);
|
|
3422
3432
|
if (existsSync4(sessionPath)) {
|
|
3423
3433
|
return sessionPath;
|
|
3424
3434
|
}
|
|
@@ -3472,12 +3482,12 @@ function injectHookMessage(sessionID, hookContent, originalMessage) {
|
|
|
3472
3482
|
sessionID
|
|
3473
3483
|
};
|
|
3474
3484
|
try {
|
|
3475
|
-
writeFileSync(
|
|
3476
|
-
const partDir =
|
|
3485
|
+
writeFileSync(join6(messageDir, `${messageID}.json`), JSON.stringify(messageMeta, null, 2));
|
|
3486
|
+
const partDir = join6(PART_STORAGE, messageID);
|
|
3477
3487
|
if (!existsSync4(partDir)) {
|
|
3478
3488
|
mkdirSync(partDir, { recursive: true });
|
|
3479
3489
|
}
|
|
3480
|
-
writeFileSync(
|
|
3490
|
+
writeFileSync(join6(partDir, `${partID}.json`), JSON.stringify(textPart, null, 2));
|
|
3481
3491
|
return true;
|
|
3482
3492
|
} catch {
|
|
3483
3493
|
return false;
|
|
@@ -3512,11 +3522,11 @@ Incomplete tasks remain in your todo list. Continue working on the next pending
|
|
|
3512
3522
|
function getMessageDir(sessionID) {
|
|
3513
3523
|
if (!existsSync5(MESSAGE_STORAGE))
|
|
3514
3524
|
return null;
|
|
3515
|
-
const directPath =
|
|
3525
|
+
const directPath = join7(MESSAGE_STORAGE, sessionID);
|
|
3516
3526
|
if (existsSync5(directPath))
|
|
3517
3527
|
return directPath;
|
|
3518
3528
|
for (const dir of readdirSync2(MESSAGE_STORAGE)) {
|
|
3519
|
-
const sessionPath =
|
|
3529
|
+
const sessionPath = join7(MESSAGE_STORAGE, dir, sessionID);
|
|
3520
3530
|
if (existsSync5(sessionPath))
|
|
3521
3531
|
return sessionPath;
|
|
3522
3532
|
}
|
|
@@ -3723,7 +3733,8 @@ function createTodoContinuationEnforcer(ctx, options = {}) {
|
|
|
3723
3733
|
}
|
|
3724
3734
|
if (sessionID && role === "assistant" && finish) {
|
|
3725
3735
|
remindedSessions.delete(sessionID);
|
|
3726
|
-
|
|
3736
|
+
preemptivelyInjectedSessions.delete(sessionID);
|
|
3737
|
+
log(`[${HOOK_NAME}] Cleared reminded/preemptive state on assistant finish`, { sessionID });
|
|
3727
3738
|
const isTerminalFinish = finish && !["tool-calls", "unknown"].includes(finish);
|
|
3728
3739
|
if (isTerminalFinish && isNonInteractive()) {
|
|
3729
3740
|
log(`[${HOOK_NAME}] Terminal finish in non-interactive mode`, { sessionID, finish });
|
|
@@ -4090,24 +4101,24 @@ function createSessionNotification(ctx, config = {}) {
|
|
|
4090
4101
|
}
|
|
4091
4102
|
// src/hooks/session-recovery/storage.ts
|
|
4092
4103
|
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4093
|
-
import { join as
|
|
4104
|
+
import { join as join9 } from "path";
|
|
4094
4105
|
|
|
4095
4106
|
// src/hooks/session-recovery/constants.ts
|
|
4096
|
-
import { join as
|
|
4107
|
+
import { join as join8 } from "path";
|
|
4097
4108
|
|
|
4098
4109
|
// node_modules/xdg-basedir/index.js
|
|
4099
|
-
import
|
|
4100
|
-
import
|
|
4101
|
-
var homeDirectory =
|
|
4110
|
+
import os4 from "os";
|
|
4111
|
+
import path4 from "path";
|
|
4112
|
+
var homeDirectory = os4.homedir();
|
|
4102
4113
|
var { env } = process;
|
|
4103
|
-
var
|
|
4104
|
-
var xdgConfig = env.XDG_CONFIG_HOME || (homeDirectory ?
|
|
4105
|
-
var xdgState = env.XDG_STATE_HOME || (homeDirectory ?
|
|
4106
|
-
var xdgCache = env.XDG_CACHE_HOME || (homeDirectory ?
|
|
4114
|
+
var xdgData = env.XDG_DATA_HOME || (homeDirectory ? path4.join(homeDirectory, ".local", "share") : undefined);
|
|
4115
|
+
var xdgConfig = env.XDG_CONFIG_HOME || (homeDirectory ? path4.join(homeDirectory, ".config") : undefined);
|
|
4116
|
+
var xdgState = env.XDG_STATE_HOME || (homeDirectory ? path4.join(homeDirectory, ".local", "state") : undefined);
|
|
4117
|
+
var xdgCache = env.XDG_CACHE_HOME || (homeDirectory ? path4.join(homeDirectory, ".cache") : undefined);
|
|
4107
4118
|
var xdgRuntime = env.XDG_RUNTIME_DIR || undefined;
|
|
4108
4119
|
var xdgDataDirectories = (env.XDG_DATA_DIRS || "/usr/local/share/:/usr/share/").split(":");
|
|
4109
|
-
if (
|
|
4110
|
-
xdgDataDirectories.unshift(
|
|
4120
|
+
if (xdgData) {
|
|
4121
|
+
xdgDataDirectories.unshift(xdgData);
|
|
4111
4122
|
}
|
|
4112
4123
|
var xdgConfigDirectories = (env.XDG_CONFIG_DIRS || "/etc/xdg").split(":");
|
|
4113
4124
|
if (xdgConfig) {
|
|
@@ -4115,9 +4126,9 @@ if (xdgConfig) {
|
|
|
4115
4126
|
}
|
|
4116
4127
|
|
|
4117
4128
|
// src/hooks/session-recovery/constants.ts
|
|
4118
|
-
var OPENCODE_STORAGE2 =
|
|
4119
|
-
var MESSAGE_STORAGE2 =
|
|
4120
|
-
var PART_STORAGE2 =
|
|
4129
|
+
var OPENCODE_STORAGE2 = join8(xdgData ?? "", "opencode", "storage");
|
|
4130
|
+
var MESSAGE_STORAGE2 = join8(OPENCODE_STORAGE2, "message");
|
|
4131
|
+
var PART_STORAGE2 = join8(OPENCODE_STORAGE2, "part");
|
|
4121
4132
|
var THINKING_TYPES = new Set(["thinking", "redacted_thinking", "reasoning"]);
|
|
4122
4133
|
var META_TYPES = new Set(["step-start", "step-finish"]);
|
|
4123
4134
|
var CONTENT_TYPES = new Set(["text", "tool", "tool_use", "tool_result"]);
|
|
@@ -4131,12 +4142,12 @@ function generatePartId2() {
|
|
|
4131
4142
|
function getMessageDir2(sessionID) {
|
|
4132
4143
|
if (!existsSync6(MESSAGE_STORAGE2))
|
|
4133
4144
|
return "";
|
|
4134
|
-
const directPath =
|
|
4145
|
+
const directPath = join9(MESSAGE_STORAGE2, sessionID);
|
|
4135
4146
|
if (existsSync6(directPath)) {
|
|
4136
4147
|
return directPath;
|
|
4137
4148
|
}
|
|
4138
4149
|
for (const dir of readdirSync3(MESSAGE_STORAGE2)) {
|
|
4139
|
-
const sessionPath =
|
|
4150
|
+
const sessionPath = join9(MESSAGE_STORAGE2, dir, sessionID);
|
|
4140
4151
|
if (existsSync6(sessionPath)) {
|
|
4141
4152
|
return sessionPath;
|
|
4142
4153
|
}
|
|
@@ -4152,7 +4163,7 @@ function readMessages(sessionID) {
|
|
|
4152
4163
|
if (!file.endsWith(".json"))
|
|
4153
4164
|
continue;
|
|
4154
4165
|
try {
|
|
4155
|
-
const content = readFileSync3(
|
|
4166
|
+
const content = readFileSync3(join9(messageDir, file), "utf-8");
|
|
4156
4167
|
messages.push(JSON.parse(content));
|
|
4157
4168
|
} catch {
|
|
4158
4169
|
continue;
|
|
@@ -4167,7 +4178,7 @@ function readMessages(sessionID) {
|
|
|
4167
4178
|
});
|
|
4168
4179
|
}
|
|
4169
4180
|
function readParts(messageID) {
|
|
4170
|
-
const partDir =
|
|
4181
|
+
const partDir = join9(PART_STORAGE2, messageID);
|
|
4171
4182
|
if (!existsSync6(partDir))
|
|
4172
4183
|
return [];
|
|
4173
4184
|
const parts = [];
|
|
@@ -4175,7 +4186,7 @@ function readParts(messageID) {
|
|
|
4175
4186
|
if (!file.endsWith(".json"))
|
|
4176
4187
|
continue;
|
|
4177
4188
|
try {
|
|
4178
|
-
const content = readFileSync3(
|
|
4189
|
+
const content = readFileSync3(join9(partDir, file), "utf-8");
|
|
4179
4190
|
parts.push(JSON.parse(content));
|
|
4180
4191
|
} catch {
|
|
4181
4192
|
continue;
|
|
@@ -4205,7 +4216,7 @@ function messageHasContent(messageID) {
|
|
|
4205
4216
|
return parts.some(hasContent);
|
|
4206
4217
|
}
|
|
4207
4218
|
function injectTextPart(sessionID, messageID, text) {
|
|
4208
|
-
const partDir =
|
|
4219
|
+
const partDir = join9(PART_STORAGE2, messageID);
|
|
4209
4220
|
if (!existsSync6(partDir)) {
|
|
4210
4221
|
mkdirSync2(partDir, { recursive: true });
|
|
4211
4222
|
}
|
|
@@ -4219,7 +4230,7 @@ function injectTextPart(sessionID, messageID, text) {
|
|
|
4219
4230
|
synthetic: true
|
|
4220
4231
|
};
|
|
4221
4232
|
try {
|
|
4222
|
-
writeFileSync2(
|
|
4233
|
+
writeFileSync2(join9(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
|
|
4223
4234
|
return true;
|
|
4224
4235
|
} catch {
|
|
4225
4236
|
return false;
|
|
@@ -4282,7 +4293,7 @@ function findMessagesWithOrphanThinking(sessionID) {
|
|
|
4282
4293
|
return result;
|
|
4283
4294
|
}
|
|
4284
4295
|
function prependThinkingPart(sessionID, messageID) {
|
|
4285
|
-
const partDir =
|
|
4296
|
+
const partDir = join9(PART_STORAGE2, messageID);
|
|
4286
4297
|
if (!existsSync6(partDir)) {
|
|
4287
4298
|
mkdirSync2(partDir, { recursive: true });
|
|
4288
4299
|
}
|
|
@@ -4296,14 +4307,14 @@ function prependThinkingPart(sessionID, messageID) {
|
|
|
4296
4307
|
synthetic: true
|
|
4297
4308
|
};
|
|
4298
4309
|
try {
|
|
4299
|
-
writeFileSync2(
|
|
4310
|
+
writeFileSync2(join9(partDir, `${partId}.json`), JSON.stringify(part, null, 2));
|
|
4300
4311
|
return true;
|
|
4301
4312
|
} catch {
|
|
4302
4313
|
return false;
|
|
4303
4314
|
}
|
|
4304
4315
|
}
|
|
4305
4316
|
function stripThinkingParts(messageID) {
|
|
4306
|
-
const partDir =
|
|
4317
|
+
const partDir = join9(PART_STORAGE2, messageID);
|
|
4307
4318
|
if (!existsSync6(partDir))
|
|
4308
4319
|
return false;
|
|
4309
4320
|
let anyRemoved = false;
|
|
@@ -4311,7 +4322,7 @@ function stripThinkingParts(messageID) {
|
|
|
4311
4322
|
if (!file.endsWith(".json"))
|
|
4312
4323
|
continue;
|
|
4313
4324
|
try {
|
|
4314
|
-
const filePath =
|
|
4325
|
+
const filePath = join9(partDir, file);
|
|
4315
4326
|
const content = readFileSync3(filePath, "utf-8");
|
|
4316
4327
|
const part = JSON.parse(content);
|
|
4317
4328
|
if (THINKING_TYPES.has(part.type)) {
|
|
@@ -4325,7 +4336,7 @@ function stripThinkingParts(messageID) {
|
|
|
4325
4336
|
return anyRemoved;
|
|
4326
4337
|
}
|
|
4327
4338
|
function replaceEmptyTextParts(messageID, replacementText) {
|
|
4328
|
-
const partDir =
|
|
4339
|
+
const partDir = join9(PART_STORAGE2, messageID);
|
|
4329
4340
|
if (!existsSync6(partDir))
|
|
4330
4341
|
return false;
|
|
4331
4342
|
let anyReplaced = false;
|
|
@@ -4333,7 +4344,7 @@ function replaceEmptyTextParts(messageID, replacementText) {
|
|
|
4333
4344
|
if (!file.endsWith(".json"))
|
|
4334
4345
|
continue;
|
|
4335
4346
|
try {
|
|
4336
|
-
const filePath =
|
|
4347
|
+
const filePath = join9(partDir, file);
|
|
4337
4348
|
const content = readFileSync3(filePath, "utf-8");
|
|
4338
4349
|
const part = JSON.parse(content);
|
|
4339
4350
|
if (part.type === "text") {
|
|
@@ -4610,7 +4621,7 @@ function createSessionRecoveryHook(ctx, options) {
|
|
|
4610
4621
|
// src/hooks/comment-checker/cli.ts
|
|
4611
4622
|
var {spawn: spawn3 } = globalThis.Bun;
|
|
4612
4623
|
import { createRequire as createRequire2 } from "module";
|
|
4613
|
-
import { dirname, join as
|
|
4624
|
+
import { dirname, join as join11 } from "path";
|
|
4614
4625
|
import { existsSync as existsSync8 } from "fs";
|
|
4615
4626
|
import * as fs3 from "fs";
|
|
4616
4627
|
import { tmpdir as tmpdir3 } from "os";
|
|
@@ -4618,11 +4629,11 @@ import { tmpdir as tmpdir3 } from "os";
|
|
|
4618
4629
|
// src/hooks/comment-checker/downloader.ts
|
|
4619
4630
|
var {spawn: spawn2 } = globalThis.Bun;
|
|
4620
4631
|
import { existsSync as existsSync7, mkdirSync as mkdirSync3, chmodSync, unlinkSync as unlinkSync2, appendFileSync as appendFileSync2 } from "fs";
|
|
4621
|
-
import { join as
|
|
4632
|
+
import { join as join10 } from "path";
|
|
4622
4633
|
import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
|
|
4623
4634
|
import { createRequire } from "module";
|
|
4624
4635
|
var DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1";
|
|
4625
|
-
var DEBUG_FILE =
|
|
4636
|
+
var DEBUG_FILE = join10(tmpdir2(), "comment-checker-debug.log");
|
|
4626
4637
|
function debugLog(...args) {
|
|
4627
4638
|
if (DEBUG) {
|
|
4628
4639
|
const msg = `[${new Date().toISOString()}] [comment-checker:downloader] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
@@ -4640,14 +4651,14 @@ var PLATFORM_MAP = {
|
|
|
4640
4651
|
};
|
|
4641
4652
|
function getCacheDir() {
|
|
4642
4653
|
const xdgCache2 = process.env.XDG_CACHE_HOME;
|
|
4643
|
-
const base = xdgCache2 ||
|
|
4644
|
-
return
|
|
4654
|
+
const base = xdgCache2 || join10(homedir4(), ".cache");
|
|
4655
|
+
return join10(base, "oh-my-opencode", "bin");
|
|
4645
4656
|
}
|
|
4646
4657
|
function getBinaryName() {
|
|
4647
4658
|
return process.platform === "win32" ? "comment-checker.exe" : "comment-checker";
|
|
4648
4659
|
}
|
|
4649
4660
|
function getCachedBinaryPath() {
|
|
4650
|
-
const binaryPath =
|
|
4661
|
+
const binaryPath = join10(getCacheDir(), getBinaryName());
|
|
4651
4662
|
return existsSync7(binaryPath) ? binaryPath : null;
|
|
4652
4663
|
}
|
|
4653
4664
|
function getPackageVersion() {
|
|
@@ -4695,14 +4706,14 @@ async function downloadCommentChecker() {
|
|
|
4695
4706
|
}
|
|
4696
4707
|
const cacheDir = getCacheDir();
|
|
4697
4708
|
const binaryName = getBinaryName();
|
|
4698
|
-
const binaryPath =
|
|
4709
|
+
const binaryPath = join10(cacheDir, binaryName);
|
|
4699
4710
|
if (existsSync7(binaryPath)) {
|
|
4700
4711
|
debugLog("Binary already cached at:", binaryPath);
|
|
4701
4712
|
return binaryPath;
|
|
4702
4713
|
}
|
|
4703
4714
|
const version = getPackageVersion();
|
|
4704
|
-
const { os:
|
|
4705
|
-
const assetName = `comment-checker_v${version}_${
|
|
4715
|
+
const { os: os5, arch, ext } = platformInfo;
|
|
4716
|
+
const assetName = `comment-checker_v${version}_${os5}_${arch}.${ext}`;
|
|
4706
4717
|
const downloadUrl = `https://github.com/${REPO}/releases/download/v${version}/${assetName}`;
|
|
4707
4718
|
debugLog(`Downloading from: ${downloadUrl}`);
|
|
4708
4719
|
console.log(`[oh-my-opencode] Downloading comment-checker binary...`);
|
|
@@ -4714,7 +4725,7 @@ async function downloadCommentChecker() {
|
|
|
4714
4725
|
if (!response.ok) {
|
|
4715
4726
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
4716
4727
|
}
|
|
4717
|
-
const archivePath =
|
|
4728
|
+
const archivePath = join10(cacheDir, assetName);
|
|
4718
4729
|
const arrayBuffer = await response.arrayBuffer();
|
|
4719
4730
|
await Bun.write(archivePath, arrayBuffer);
|
|
4720
4731
|
debugLog(`Downloaded archive to: ${archivePath}`);
|
|
@@ -4750,7 +4761,7 @@ async function ensureCommentCheckerBinary() {
|
|
|
4750
4761
|
|
|
4751
4762
|
// src/hooks/comment-checker/cli.ts
|
|
4752
4763
|
var DEBUG2 = process.env.COMMENT_CHECKER_DEBUG === "1";
|
|
4753
|
-
var DEBUG_FILE2 =
|
|
4764
|
+
var DEBUG_FILE2 = join11(tmpdir3(), "comment-checker-debug.log");
|
|
4754
4765
|
function debugLog2(...args) {
|
|
4755
4766
|
if (DEBUG2) {
|
|
4756
4767
|
const msg = `[${new Date().toISOString()}] [comment-checker:cli] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
@@ -4767,7 +4778,7 @@ function findCommentCheckerPathSync() {
|
|
|
4767
4778
|
const require2 = createRequire2(import.meta.url);
|
|
4768
4779
|
const cliPkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
|
|
4769
4780
|
const cliDir = dirname(cliPkgPath);
|
|
4770
|
-
const binaryPath =
|
|
4781
|
+
const binaryPath = join11(cliDir, "bin", binaryName);
|
|
4771
4782
|
if (existsSync8(binaryPath)) {
|
|
4772
4783
|
debugLog2("found binary in main package:", binaryPath);
|
|
4773
4784
|
return binaryPath;
|
|
@@ -4814,8 +4825,8 @@ async function getCommentCheckerPath() {
|
|
|
4814
4825
|
function startBackgroundInit() {
|
|
4815
4826
|
if (!initPromise) {
|
|
4816
4827
|
initPromise = getCommentCheckerPath();
|
|
4817
|
-
initPromise.then((
|
|
4818
|
-
debugLog2("background init complete:",
|
|
4828
|
+
initPromise.then((path5) => {
|
|
4829
|
+
debugLog2("background init complete:", path5 || "no binary");
|
|
4819
4830
|
}).catch((err) => {
|
|
4820
4831
|
debugLog2("background init error:", err);
|
|
4821
4832
|
});
|
|
@@ -4864,9 +4875,9 @@ async function runCommentChecker(input, cliPath) {
|
|
|
4864
4875
|
import * as fs4 from "fs";
|
|
4865
4876
|
import { existsSync as existsSync9 } from "fs";
|
|
4866
4877
|
import { tmpdir as tmpdir4 } from "os";
|
|
4867
|
-
import { join as
|
|
4878
|
+
import { join as join12 } from "path";
|
|
4868
4879
|
var DEBUG3 = process.env.COMMENT_CHECKER_DEBUG === "1";
|
|
4869
|
-
var DEBUG_FILE3 =
|
|
4880
|
+
var DEBUG_FILE3 = join12(tmpdir4(), "comment-checker-debug.log");
|
|
4870
4881
|
function debugLog3(...args) {
|
|
4871
4882
|
if (DEBUG3) {
|
|
4872
4883
|
const msg = `[${new Date().toISOString()}] [comment-checker:hook] ${args.map((a) => typeof a === "object" ? JSON.stringify(a, null, 2) : String(a)).join(" ")}
|
|
@@ -4890,8 +4901,8 @@ function createCommentCheckerHooks() {
|
|
|
4890
4901
|
debugLog3("createCommentCheckerHooks called");
|
|
4891
4902
|
startBackgroundInit();
|
|
4892
4903
|
cliPathPromise = getCommentCheckerPath();
|
|
4893
|
-
cliPathPromise.then((
|
|
4894
|
-
debugLog3("CLI path resolved:",
|
|
4904
|
+
cliPathPromise.then((path5) => {
|
|
4905
|
+
debugLog3("CLI path resolved:", path5 || "disabled (no binary)");
|
|
4895
4906
|
}).catch((err) => {
|
|
4896
4907
|
debugLog3("CLI path resolution error:", err);
|
|
4897
4908
|
});
|
|
@@ -4998,7 +5009,7 @@ var TRUNCATABLE_TOOLS = [
|
|
|
4998
5009
|
];
|
|
4999
5010
|
function createToolOutputTruncatorHook(ctx, options) {
|
|
5000
5011
|
const truncator = createDynamicTruncator(ctx);
|
|
5001
|
-
const truncateAll = options?.experimental?.truncate_all_tool_outputs ??
|
|
5012
|
+
const truncateAll = options?.experimental?.truncate_all_tool_outputs ?? true;
|
|
5002
5013
|
const toolExecuteAfter = async (input, output) => {
|
|
5003
5014
|
if (!truncateAll && !TRUNCATABLE_TOOLS.includes(input.tool))
|
|
5004
5015
|
return;
|
|
@@ -5015,7 +5026,7 @@ function createToolOutputTruncatorHook(ctx, options) {
|
|
|
5015
5026
|
}
|
|
5016
5027
|
// src/hooks/directory-agents-injector/index.ts
|
|
5017
5028
|
import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
|
|
5018
|
-
import { dirname as dirname2, join as
|
|
5029
|
+
import { dirname as dirname2, join as join15, resolve as resolve2 } from "path";
|
|
5019
5030
|
|
|
5020
5031
|
// src/hooks/directory-agents-injector/storage.ts
|
|
5021
5032
|
import {
|
|
@@ -5025,17 +5036,17 @@ import {
|
|
|
5025
5036
|
writeFileSync as writeFileSync3,
|
|
5026
5037
|
unlinkSync as unlinkSync3
|
|
5027
5038
|
} from "fs";
|
|
5028
|
-
import { join as
|
|
5039
|
+
import { join as join14 } from "path";
|
|
5029
5040
|
|
|
5030
5041
|
// src/hooks/directory-agents-injector/constants.ts
|
|
5031
|
-
import { join as
|
|
5032
|
-
var OPENCODE_STORAGE3 =
|
|
5033
|
-
var AGENTS_INJECTOR_STORAGE =
|
|
5042
|
+
import { join as join13 } from "path";
|
|
5043
|
+
var OPENCODE_STORAGE3 = join13(xdgData ?? "", "opencode", "storage");
|
|
5044
|
+
var AGENTS_INJECTOR_STORAGE = join13(OPENCODE_STORAGE3, "directory-agents");
|
|
5034
5045
|
var AGENTS_FILENAME = "AGENTS.md";
|
|
5035
5046
|
|
|
5036
5047
|
// src/hooks/directory-agents-injector/storage.ts
|
|
5037
5048
|
function getStoragePath(sessionID) {
|
|
5038
|
-
return
|
|
5049
|
+
return join14(AGENTS_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
5039
5050
|
}
|
|
5040
5051
|
function loadInjectedPaths(sessionID) {
|
|
5041
5052
|
const filePath = getStoragePath(sessionID);
|
|
@@ -5077,18 +5088,18 @@ function createDirectoryAgentsInjectorHook(ctx) {
|
|
|
5077
5088
|
}
|
|
5078
5089
|
return sessionCaches.get(sessionID);
|
|
5079
5090
|
}
|
|
5080
|
-
function resolveFilePath2(
|
|
5081
|
-
if (!
|
|
5091
|
+
function resolveFilePath2(path5) {
|
|
5092
|
+
if (!path5)
|
|
5082
5093
|
return null;
|
|
5083
|
-
if (
|
|
5084
|
-
return
|
|
5085
|
-
return resolve2(ctx.directory,
|
|
5094
|
+
if (path5.startsWith("/"))
|
|
5095
|
+
return path5;
|
|
5096
|
+
return resolve2(ctx.directory, path5);
|
|
5086
5097
|
}
|
|
5087
5098
|
function findAgentsMdUp(startDir) {
|
|
5088
5099
|
const found = [];
|
|
5089
5100
|
let current = startDir;
|
|
5090
5101
|
while (true) {
|
|
5091
|
-
const agentsPath =
|
|
5102
|
+
const agentsPath = join15(current, AGENTS_FILENAME);
|
|
5092
5103
|
if (existsSync11(agentsPath)) {
|
|
5093
5104
|
found.push(agentsPath);
|
|
5094
5105
|
}
|
|
@@ -5182,7 +5193,7 @@ ${content}`;
|
|
|
5182
5193
|
}
|
|
5183
5194
|
// src/hooks/directory-readme-injector/index.ts
|
|
5184
5195
|
import { existsSync as existsSync13, readFileSync as readFileSync7 } from "fs";
|
|
5185
|
-
import { dirname as dirname3, join as
|
|
5196
|
+
import { dirname as dirname3, join as join18, resolve as resolve3 } from "path";
|
|
5186
5197
|
|
|
5187
5198
|
// src/hooks/directory-readme-injector/storage.ts
|
|
5188
5199
|
import {
|
|
@@ -5192,17 +5203,17 @@ import {
|
|
|
5192
5203
|
writeFileSync as writeFileSync4,
|
|
5193
5204
|
unlinkSync as unlinkSync4
|
|
5194
5205
|
} from "fs";
|
|
5195
|
-
import { join as
|
|
5206
|
+
import { join as join17 } from "path";
|
|
5196
5207
|
|
|
5197
5208
|
// src/hooks/directory-readme-injector/constants.ts
|
|
5198
|
-
import { join as
|
|
5199
|
-
var OPENCODE_STORAGE4 =
|
|
5200
|
-
var README_INJECTOR_STORAGE =
|
|
5209
|
+
import { join as join16 } from "path";
|
|
5210
|
+
var OPENCODE_STORAGE4 = join16(xdgData ?? "", "opencode", "storage");
|
|
5211
|
+
var README_INJECTOR_STORAGE = join16(OPENCODE_STORAGE4, "directory-readme");
|
|
5201
5212
|
var README_FILENAME = "README.md";
|
|
5202
5213
|
|
|
5203
5214
|
// src/hooks/directory-readme-injector/storage.ts
|
|
5204
5215
|
function getStoragePath2(sessionID) {
|
|
5205
|
-
return
|
|
5216
|
+
return join17(README_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
5206
5217
|
}
|
|
5207
5218
|
function loadInjectedPaths2(sessionID) {
|
|
5208
5219
|
const filePath = getStoragePath2(sessionID);
|
|
@@ -5244,18 +5255,18 @@ function createDirectoryReadmeInjectorHook(ctx) {
|
|
|
5244
5255
|
}
|
|
5245
5256
|
return sessionCaches.get(sessionID);
|
|
5246
5257
|
}
|
|
5247
|
-
function resolveFilePath2(
|
|
5248
|
-
if (!
|
|
5258
|
+
function resolveFilePath2(path5) {
|
|
5259
|
+
if (!path5)
|
|
5249
5260
|
return null;
|
|
5250
|
-
if (
|
|
5251
|
-
return
|
|
5252
|
-
return resolve3(ctx.directory,
|
|
5261
|
+
if (path5.startsWith("/"))
|
|
5262
|
+
return path5;
|
|
5263
|
+
return resolve3(ctx.directory, path5);
|
|
5253
5264
|
}
|
|
5254
5265
|
function findReadmeMdUp(startDir) {
|
|
5255
5266
|
const found = [];
|
|
5256
5267
|
let current = startDir;
|
|
5257
5268
|
while (true) {
|
|
5258
|
-
const readmePath =
|
|
5269
|
+
const readmePath = join18(current, README_FILENAME);
|
|
5259
5270
|
if (existsSync13(readmePath)) {
|
|
5260
5271
|
found.push(readmePath);
|
|
5261
5272
|
}
|
|
@@ -5553,26 +5564,26 @@ var TRUNCATE_CONFIG = {
|
|
|
5553
5564
|
// src/hooks/anthropic-auto-compact/storage.ts
|
|
5554
5565
|
import { existsSync as existsSync14, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
5555
5566
|
import { homedir as homedir5 } from "os";
|
|
5556
|
-
import { join as
|
|
5557
|
-
var OPENCODE_STORAGE5 =
|
|
5567
|
+
import { join as join19 } from "path";
|
|
5568
|
+
var OPENCODE_STORAGE5 = join19(xdgData ?? "", "opencode", "storage");
|
|
5558
5569
|
if (process.platform === "darwin" && !existsSync14(OPENCODE_STORAGE5)) {
|
|
5559
|
-
const localShare =
|
|
5570
|
+
const localShare = join19(homedir5(), ".local", "share", "opencode", "storage");
|
|
5560
5571
|
if (existsSync14(localShare)) {
|
|
5561
5572
|
OPENCODE_STORAGE5 = localShare;
|
|
5562
5573
|
}
|
|
5563
5574
|
}
|
|
5564
|
-
var MESSAGE_STORAGE3 =
|
|
5565
|
-
var PART_STORAGE3 =
|
|
5575
|
+
var MESSAGE_STORAGE3 = join19(OPENCODE_STORAGE5, "message");
|
|
5576
|
+
var PART_STORAGE3 = join19(OPENCODE_STORAGE5, "part");
|
|
5566
5577
|
var TRUNCATION_MESSAGE = "[TOOL RESULT TRUNCATED - Context limit exceeded. Original output was too large and has been truncated to recover the session. Please re-run this tool if you need the full output.]";
|
|
5567
5578
|
function getMessageDir3(sessionID) {
|
|
5568
5579
|
if (!existsSync14(MESSAGE_STORAGE3))
|
|
5569
5580
|
return "";
|
|
5570
|
-
const directPath =
|
|
5581
|
+
const directPath = join19(MESSAGE_STORAGE3, sessionID);
|
|
5571
5582
|
if (existsSync14(directPath)) {
|
|
5572
5583
|
return directPath;
|
|
5573
5584
|
}
|
|
5574
5585
|
for (const dir of readdirSync4(MESSAGE_STORAGE3)) {
|
|
5575
|
-
const sessionPath =
|
|
5586
|
+
const sessionPath = join19(MESSAGE_STORAGE3, dir, sessionID);
|
|
5576
5587
|
if (existsSync14(sessionPath)) {
|
|
5577
5588
|
return sessionPath;
|
|
5578
5589
|
}
|
|
@@ -5596,14 +5607,14 @@ function findToolResultsBySize(sessionID) {
|
|
|
5596
5607
|
const messageIds = getMessageIds(sessionID);
|
|
5597
5608
|
const results = [];
|
|
5598
5609
|
for (const messageID of messageIds) {
|
|
5599
|
-
const partDir =
|
|
5610
|
+
const partDir = join19(PART_STORAGE3, messageID);
|
|
5600
5611
|
if (!existsSync14(partDir))
|
|
5601
5612
|
continue;
|
|
5602
5613
|
for (const file of readdirSync4(partDir)) {
|
|
5603
5614
|
if (!file.endsWith(".json"))
|
|
5604
5615
|
continue;
|
|
5605
5616
|
try {
|
|
5606
|
-
const partPath =
|
|
5617
|
+
const partPath = join19(partDir, file);
|
|
5607
5618
|
const content = readFileSync8(partPath, "utf-8");
|
|
5608
5619
|
const part = JSON.parse(content);
|
|
5609
5620
|
if (part.type === "tool" && part.state?.output && !part.truncated) {
|
|
@@ -6211,7 +6222,7 @@ function createAnthropicAutoCompactHook(ctx, options) {
|
|
|
6211
6222
|
}
|
|
6212
6223
|
// src/hooks/preemptive-compaction/index.ts
|
|
6213
6224
|
import { existsSync as existsSync15, readdirSync as readdirSync5 } from "fs";
|
|
6214
|
-
import { join as
|
|
6225
|
+
import { join as join20 } from "path";
|
|
6215
6226
|
|
|
6216
6227
|
// src/hooks/preemptive-compaction/constants.ts
|
|
6217
6228
|
var DEFAULT_THRESHOLD = 0.85;
|
|
@@ -6227,11 +6238,11 @@ function isSupportedModel(modelID) {
|
|
|
6227
6238
|
function getMessageDir4(sessionID) {
|
|
6228
6239
|
if (!existsSync15(MESSAGE_STORAGE))
|
|
6229
6240
|
return null;
|
|
6230
|
-
const directPath =
|
|
6241
|
+
const directPath = join20(MESSAGE_STORAGE, sessionID);
|
|
6231
6242
|
if (existsSync15(directPath))
|
|
6232
6243
|
return directPath;
|
|
6233
6244
|
for (const dir of readdirSync5(MESSAGE_STORAGE)) {
|
|
6234
|
-
const sessionPath =
|
|
6245
|
+
const sessionPath = join20(MESSAGE_STORAGE, dir, sessionID);
|
|
6235
6246
|
if (existsSync15(sessionPath))
|
|
6236
6247
|
return sessionPath;
|
|
6237
6248
|
}
|
|
@@ -6717,7 +6728,7 @@ function createThinkModeHook() {
|
|
|
6717
6728
|
}
|
|
6718
6729
|
// src/hooks/claude-code-hooks/config.ts
|
|
6719
6730
|
import { homedir as homedir6 } from "os";
|
|
6720
|
-
import { join as
|
|
6731
|
+
import { join as join21 } from "path";
|
|
6721
6732
|
import { existsSync as existsSync16 } from "fs";
|
|
6722
6733
|
function normalizeHookMatcher(raw) {
|
|
6723
6734
|
return {
|
|
@@ -6744,9 +6755,9 @@ function normalizeHooksConfig(raw) {
|
|
|
6744
6755
|
function getClaudeSettingsPaths(customPath) {
|
|
6745
6756
|
const home = homedir6();
|
|
6746
6757
|
const paths = [
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6758
|
+
join21(home, ".claude", "settings.json"),
|
|
6759
|
+
join21(process.cwd(), ".claude", "settings.json"),
|
|
6760
|
+
join21(process.cwd(), ".claude", "settings.local.json")
|
|
6750
6761
|
];
|
|
6751
6762
|
if (customPath && existsSync16(customPath)) {
|
|
6752
6763
|
paths.unshift(customPath);
|
|
@@ -6792,20 +6803,20 @@ async function loadClaudeHooksConfig(customSettingsPath) {
|
|
|
6792
6803
|
// src/hooks/claude-code-hooks/config-loader.ts
|
|
6793
6804
|
import { existsSync as existsSync17 } from "fs";
|
|
6794
6805
|
import { homedir as homedir7 } from "os";
|
|
6795
|
-
import { join as
|
|
6796
|
-
var USER_CONFIG_PATH =
|
|
6806
|
+
import { join as join22 } from "path";
|
|
6807
|
+
var USER_CONFIG_PATH = join22(homedir7(), ".config", "opencode", "opencode-cc-plugin.json");
|
|
6797
6808
|
function getProjectConfigPath() {
|
|
6798
|
-
return
|
|
6809
|
+
return join22(process.cwd(), ".opencode", "opencode-cc-plugin.json");
|
|
6799
6810
|
}
|
|
6800
|
-
async function loadConfigFromPath(
|
|
6801
|
-
if (!existsSync17(
|
|
6811
|
+
async function loadConfigFromPath(path5) {
|
|
6812
|
+
if (!existsSync17(path5)) {
|
|
6802
6813
|
return null;
|
|
6803
6814
|
}
|
|
6804
6815
|
try {
|
|
6805
|
-
const content = await Bun.file(
|
|
6816
|
+
const content = await Bun.file(path5).text();
|
|
6806
6817
|
return JSON.parse(content);
|
|
6807
6818
|
} catch (error) {
|
|
6808
|
-
log("Failed to load config", { path:
|
|
6819
|
+
log("Failed to load config", { path: path5, error });
|
|
6809
6820
|
return null;
|
|
6810
6821
|
}
|
|
6811
6822
|
}
|
|
@@ -6978,13 +6989,13 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
|
|
|
6978
6989
|
}
|
|
6979
6990
|
|
|
6980
6991
|
// src/hooks/claude-code-hooks/transcript.ts
|
|
6981
|
-
import { join as
|
|
6992
|
+
import { join as join23 } from "path";
|
|
6982
6993
|
import { mkdirSync as mkdirSync6, appendFileSync as appendFileSync5, existsSync as existsSync18, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5 } from "fs";
|
|
6983
6994
|
import { homedir as homedir8, tmpdir as tmpdir5 } from "os";
|
|
6984
6995
|
import { randomUUID } from "crypto";
|
|
6985
|
-
var TRANSCRIPT_DIR =
|
|
6996
|
+
var TRANSCRIPT_DIR = join23(homedir8(), ".claude", "transcripts");
|
|
6986
6997
|
function getTranscriptPath(sessionId) {
|
|
6987
|
-
return
|
|
6998
|
+
return join23(TRANSCRIPT_DIR, `${sessionId}.jsonl`);
|
|
6988
6999
|
}
|
|
6989
7000
|
function ensureTranscriptDir() {
|
|
6990
7001
|
if (!existsSync18(TRANSCRIPT_DIR)) {
|
|
@@ -6993,10 +7004,10 @@ function ensureTranscriptDir() {
|
|
|
6993
7004
|
}
|
|
6994
7005
|
function appendTranscriptEntry(sessionId, entry) {
|
|
6995
7006
|
ensureTranscriptDir();
|
|
6996
|
-
const
|
|
7007
|
+
const path5 = getTranscriptPath(sessionId);
|
|
6997
7008
|
const line = JSON.stringify(entry) + `
|
|
6998
7009
|
`;
|
|
6999
|
-
appendFileSync5(
|
|
7010
|
+
appendFileSync5(path5, line);
|
|
7000
7011
|
}
|
|
7001
7012
|
function recordToolUse(sessionId, toolName, toolInput) {
|
|
7002
7013
|
appendTranscriptEntry(sessionId, {
|
|
@@ -7074,7 +7085,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
7074
7085
|
}
|
|
7075
7086
|
};
|
|
7076
7087
|
entries.push(JSON.stringify(currentEntry));
|
|
7077
|
-
const tempPath =
|
|
7088
|
+
const tempPath = join23(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
|
|
7078
7089
|
writeFileSync6(tempPath, entries.join(`
|
|
7079
7090
|
`) + `
|
|
7080
7091
|
`);
|
|
@@ -7094,7 +7105,7 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
7094
7105
|
]
|
|
7095
7106
|
}
|
|
7096
7107
|
};
|
|
7097
|
-
const tempPath =
|
|
7108
|
+
const tempPath = join23(tmpdir5(), `opencode-transcript-${sessionId}-${randomUUID()}.jsonl`);
|
|
7098
7109
|
writeFileSync6(tempPath, JSON.stringify(currentEntry) + `
|
|
7099
7110
|
`);
|
|
7100
7111
|
return tempPath;
|
|
@@ -7103,11 +7114,11 @@ async function buildTranscriptFromSession(client, sessionId, directory, currentT
|
|
|
7103
7114
|
}
|
|
7104
7115
|
}
|
|
7105
7116
|
}
|
|
7106
|
-
function deleteTempTranscript(
|
|
7107
|
-
if (!
|
|
7117
|
+
function deleteTempTranscript(path5) {
|
|
7118
|
+
if (!path5)
|
|
7108
7119
|
return;
|
|
7109
7120
|
try {
|
|
7110
|
-
unlinkSync5(
|
|
7121
|
+
unlinkSync5(path5);
|
|
7111
7122
|
} catch {}
|
|
7112
7123
|
}
|
|
7113
7124
|
|
|
@@ -7306,11 +7317,11 @@ ${USER_PROMPT_SUBMIT_TAG_CLOSE}`);
|
|
|
7306
7317
|
}
|
|
7307
7318
|
|
|
7308
7319
|
// src/hooks/claude-code-hooks/todo.ts
|
|
7309
|
-
import { join as
|
|
7320
|
+
import { join as join24 } from "path";
|
|
7310
7321
|
import { homedir as homedir9 } from "os";
|
|
7311
|
-
var TODO_DIR =
|
|
7322
|
+
var TODO_DIR = join24(homedir9(), ".claude", "todos");
|
|
7312
7323
|
function getTodoPath(sessionId) {
|
|
7313
|
-
return
|
|
7324
|
+
return join24(TODO_DIR, `${sessionId}-agent-${sessionId}.json`);
|
|
7314
7325
|
}
|
|
7315
7326
|
|
|
7316
7327
|
// src/hooks/claude-code-hooks/stop.ts
|
|
@@ -7745,12 +7756,12 @@ import {
|
|
|
7745
7756
|
realpathSync,
|
|
7746
7757
|
statSync as statSync2
|
|
7747
7758
|
} from "fs";
|
|
7748
|
-
import { dirname as dirname4, join as
|
|
7759
|
+
import { dirname as dirname4, join as join26, relative } from "path";
|
|
7749
7760
|
|
|
7750
7761
|
// src/hooks/rules-injector/constants.ts
|
|
7751
|
-
import { join as
|
|
7752
|
-
var OPENCODE_STORAGE6 =
|
|
7753
|
-
var RULES_INJECTOR_STORAGE =
|
|
7762
|
+
import { join as join25 } from "path";
|
|
7763
|
+
var OPENCODE_STORAGE6 = join25(xdgData ?? "", "opencode", "storage");
|
|
7764
|
+
var RULES_INJECTOR_STORAGE = join25(OPENCODE_STORAGE6, "rules-injector");
|
|
7754
7765
|
var PROJECT_MARKERS = [
|
|
7755
7766
|
".git",
|
|
7756
7767
|
"pyproject.toml",
|
|
@@ -7777,7 +7788,7 @@ function findProjectRoot(startPath) {
|
|
|
7777
7788
|
}
|
|
7778
7789
|
while (true) {
|
|
7779
7790
|
for (const marker of PROJECT_MARKERS) {
|
|
7780
|
-
const markerPath =
|
|
7791
|
+
const markerPath = join26(current, marker);
|
|
7781
7792
|
if (existsSync19(markerPath)) {
|
|
7782
7793
|
return current;
|
|
7783
7794
|
}
|
|
@@ -7795,7 +7806,7 @@ function findRuleFilesRecursive(dir, results) {
|
|
|
7795
7806
|
try {
|
|
7796
7807
|
const entries = readdirSync6(dir, { withFileTypes: true });
|
|
7797
7808
|
for (const entry of entries) {
|
|
7798
|
-
const fullPath =
|
|
7809
|
+
const fullPath = join26(dir, entry.name);
|
|
7799
7810
|
if (entry.isDirectory()) {
|
|
7800
7811
|
findRuleFilesRecursive(fullPath, results);
|
|
7801
7812
|
} else if (entry.isFile()) {
|
|
@@ -7821,7 +7832,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
|
|
|
7821
7832
|
let distance = 0;
|
|
7822
7833
|
while (true) {
|
|
7823
7834
|
for (const [parent, subdir] of PROJECT_RULE_SUBDIRS) {
|
|
7824
|
-
const ruleDir =
|
|
7835
|
+
const ruleDir = join26(currentDir, parent, subdir);
|
|
7825
7836
|
const files = [];
|
|
7826
7837
|
findRuleFilesRecursive(ruleDir, files);
|
|
7827
7838
|
for (const filePath of files) {
|
|
@@ -7845,7 +7856,7 @@ function findRuleFiles(projectRoot, homeDir, currentFile) {
|
|
|
7845
7856
|
currentDir = parentDir;
|
|
7846
7857
|
distance++;
|
|
7847
7858
|
}
|
|
7848
|
-
const userRuleDir =
|
|
7859
|
+
const userRuleDir = join26(homeDir, USER_RULE_DIR);
|
|
7849
7860
|
const userFiles = [];
|
|
7850
7861
|
findRuleFilesRecursive(userRuleDir, userFiles);
|
|
7851
7862
|
for (const filePath of userFiles) {
|
|
@@ -8040,9 +8051,9 @@ import {
|
|
|
8040
8051
|
writeFileSync as writeFileSync7,
|
|
8041
8052
|
unlinkSync as unlinkSync6
|
|
8042
8053
|
} from "fs";
|
|
8043
|
-
import { join as
|
|
8054
|
+
import { join as join27 } from "path";
|
|
8044
8055
|
function getStoragePath3(sessionID) {
|
|
8045
|
-
return
|
|
8056
|
+
return join27(RULES_INJECTOR_STORAGE, `${sessionID}.json`);
|
|
8046
8057
|
}
|
|
8047
8058
|
function loadInjectedRules(sessionID) {
|
|
8048
8059
|
const filePath = getStoragePath3(sessionID);
|
|
@@ -8089,12 +8100,12 @@ function createRulesInjectorHook(ctx) {
|
|
|
8089
8100
|
}
|
|
8090
8101
|
return sessionCaches.get(sessionID);
|
|
8091
8102
|
}
|
|
8092
|
-
function resolveFilePath2(
|
|
8093
|
-
if (!
|
|
8103
|
+
function resolveFilePath2(path5) {
|
|
8104
|
+
if (!path5)
|
|
8094
8105
|
return null;
|
|
8095
|
-
if (
|
|
8096
|
-
return
|
|
8097
|
-
return resolve4(ctx.directory,
|
|
8106
|
+
if (path5.startsWith("/"))
|
|
8107
|
+
return path5;
|
|
8108
|
+
return resolve4(ctx.directory, path5);
|
|
8098
8109
|
}
|
|
8099
8110
|
function processFilePathForInjection(filePath, sessionID, output) {
|
|
8100
8111
|
const resolved = resolveFilePath2(filePath);
|
|
@@ -8213,33 +8224,33 @@ function createBackgroundNotificationHook(manager) {
|
|
|
8213
8224
|
}
|
|
8214
8225
|
// src/hooks/auto-update-checker/checker.ts
|
|
8215
8226
|
import * as fs5 from "fs";
|
|
8216
|
-
import * as
|
|
8227
|
+
import * as path6 from "path";
|
|
8217
8228
|
import { fileURLToPath } from "url";
|
|
8218
8229
|
|
|
8219
8230
|
// src/hooks/auto-update-checker/constants.ts
|
|
8220
|
-
import * as
|
|
8221
|
-
import * as
|
|
8231
|
+
import * as path5 from "path";
|
|
8232
|
+
import * as os5 from "os";
|
|
8222
8233
|
var PACKAGE_NAME = "oh-my-opencode";
|
|
8223
8234
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`;
|
|
8224
8235
|
var NPM_FETCH_TIMEOUT = 5000;
|
|
8225
8236
|
function getCacheDir2() {
|
|
8226
8237
|
if (process.platform === "win32") {
|
|
8227
|
-
return
|
|
8238
|
+
return path5.join(process.env.LOCALAPPDATA ?? os5.homedir(), "opencode");
|
|
8228
8239
|
}
|
|
8229
|
-
return
|
|
8240
|
+
return path5.join(os5.homedir(), ".cache", "opencode");
|
|
8230
8241
|
}
|
|
8231
8242
|
var CACHE_DIR = getCacheDir2();
|
|
8232
|
-
var VERSION_FILE =
|
|
8233
|
-
var INSTALLED_PACKAGE_JSON =
|
|
8243
|
+
var VERSION_FILE = path5.join(CACHE_DIR, "version");
|
|
8244
|
+
var INSTALLED_PACKAGE_JSON = path5.join(CACHE_DIR, "node_modules", PACKAGE_NAME, "package.json");
|
|
8234
8245
|
function getUserConfigDir2() {
|
|
8235
8246
|
if (process.platform === "win32") {
|
|
8236
|
-
return process.env.APPDATA ??
|
|
8247
|
+
return process.env.APPDATA ?? path5.join(os5.homedir(), "AppData", "Roaming");
|
|
8237
8248
|
}
|
|
8238
|
-
return process.env.XDG_CONFIG_HOME ??
|
|
8249
|
+
return process.env.XDG_CONFIG_HOME ?? path5.join(os5.homedir(), ".config");
|
|
8239
8250
|
}
|
|
8240
8251
|
var USER_CONFIG_DIR = getUserConfigDir2();
|
|
8241
|
-
var USER_OPENCODE_CONFIG =
|
|
8242
|
-
var USER_OPENCODE_CONFIG_JSONC =
|
|
8252
|
+
var USER_OPENCODE_CONFIG = path5.join(USER_CONFIG_DIR, "opencode", "opencode.json");
|
|
8253
|
+
var USER_OPENCODE_CONFIG_JSONC = path5.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
|
|
8243
8254
|
|
|
8244
8255
|
// src/hooks/auto-update-checker/checker.ts
|
|
8245
8256
|
function stripJsonComments(json) {
|
|
@@ -8247,8 +8258,8 @@ function stripJsonComments(json) {
|
|
|
8247
8258
|
}
|
|
8248
8259
|
function getConfigPaths(directory) {
|
|
8249
8260
|
return [
|
|
8250
|
-
|
|
8251
|
-
|
|
8261
|
+
path6.join(directory, ".opencode", "opencode.json"),
|
|
8262
|
+
path6.join(directory, ".opencode", "opencode.jsonc"),
|
|
8252
8263
|
USER_OPENCODE_CONFIG,
|
|
8253
8264
|
USER_OPENCODE_CONFIG_JSONC
|
|
8254
8265
|
];
|
|
@@ -8279,9 +8290,9 @@ function getLocalDevPath(directory) {
|
|
|
8279
8290
|
function findPackageJsonUp(startPath) {
|
|
8280
8291
|
try {
|
|
8281
8292
|
const stat = fs5.statSync(startPath);
|
|
8282
|
-
let dir = stat.isDirectory() ? startPath :
|
|
8293
|
+
let dir = stat.isDirectory() ? startPath : path6.dirname(startPath);
|
|
8283
8294
|
for (let i = 0;i < 10; i++) {
|
|
8284
|
-
const pkgPath =
|
|
8295
|
+
const pkgPath = path6.join(dir, "package.json");
|
|
8285
8296
|
if (fs5.existsSync(pkgPath)) {
|
|
8286
8297
|
try {
|
|
8287
8298
|
const content = fs5.readFileSync(pkgPath, "utf-8");
|
|
@@ -8290,7 +8301,7 @@ function findPackageJsonUp(startPath) {
|
|
|
8290
8301
|
return pkgPath;
|
|
8291
8302
|
} catch {}
|
|
8292
8303
|
}
|
|
8293
|
-
const parent =
|
|
8304
|
+
const parent = path6.dirname(dir);
|
|
8294
8305
|
if (parent === dir)
|
|
8295
8306
|
break;
|
|
8296
8307
|
dir = parent;
|
|
@@ -8347,7 +8358,7 @@ function getCachedVersion() {
|
|
|
8347
8358
|
}
|
|
8348
8359
|
} catch {}
|
|
8349
8360
|
try {
|
|
8350
|
-
const currentDir =
|
|
8361
|
+
const currentDir = path6.dirname(fileURLToPath(import.meta.url));
|
|
8351
8362
|
const pkgPath = findPackageJsonUp(currentDir);
|
|
8352
8363
|
if (pkgPath) {
|
|
8353
8364
|
const content = fs5.readFileSync(pkgPath, "utf-8");
|
|
@@ -8423,12 +8434,12 @@ async function getLatestVersion() {
|
|
|
8423
8434
|
|
|
8424
8435
|
// src/hooks/auto-update-checker/cache.ts
|
|
8425
8436
|
import * as fs6 from "fs";
|
|
8426
|
-
import * as
|
|
8437
|
+
import * as path7 from "path";
|
|
8427
8438
|
function stripTrailingCommas(json) {
|
|
8428
8439
|
return json.replace(/,(\s*[}\]])/g, "$1");
|
|
8429
8440
|
}
|
|
8430
8441
|
function removeFromBunLock(packageName) {
|
|
8431
|
-
const lockPath =
|
|
8442
|
+
const lockPath = path7.join(CACHE_DIR, "bun.lock");
|
|
8432
8443
|
if (!fs6.existsSync(lockPath))
|
|
8433
8444
|
return false;
|
|
8434
8445
|
try {
|
|
@@ -8454,8 +8465,8 @@ function removeFromBunLock(packageName) {
|
|
|
8454
8465
|
}
|
|
8455
8466
|
function invalidatePackage(packageName = PACKAGE_NAME) {
|
|
8456
8467
|
try {
|
|
8457
|
-
const pkgDir =
|
|
8458
|
-
const pkgJsonPath =
|
|
8468
|
+
const pkgDir = path7.join(CACHE_DIR, "node_modules", packageName);
|
|
8469
|
+
const pkgJsonPath = path7.join(CACHE_DIR, "package.json");
|
|
8459
8470
|
let packageRemoved = false;
|
|
8460
8471
|
let dependencyRemoved = false;
|
|
8461
8472
|
let lockRemoved = false;
|
|
@@ -8649,12 +8660,12 @@ import {
|
|
|
8649
8660
|
writeFileSync as writeFileSync10,
|
|
8650
8661
|
unlinkSync as unlinkSync7
|
|
8651
8662
|
} from "fs";
|
|
8652
|
-
import { join as
|
|
8663
|
+
import { join as join32 } from "path";
|
|
8653
8664
|
|
|
8654
8665
|
// src/hooks/agent-usage-reminder/constants.ts
|
|
8655
|
-
import { join as
|
|
8656
|
-
var OPENCODE_STORAGE7 =
|
|
8657
|
-
var AGENT_USAGE_REMINDER_STORAGE =
|
|
8666
|
+
import { join as join31 } from "path";
|
|
8667
|
+
var OPENCODE_STORAGE7 = join31(xdgData ?? "", "opencode", "storage");
|
|
8668
|
+
var AGENT_USAGE_REMINDER_STORAGE = join31(OPENCODE_STORAGE7, "agent-usage-reminder");
|
|
8658
8669
|
var TARGET_TOOLS = new Set([
|
|
8659
8670
|
"grep",
|
|
8660
8671
|
"safe_grep",
|
|
@@ -8699,7 +8710,7 @@ ALWAYS prefer: Multiple parallel background_task calls > Direct tool calls
|
|
|
8699
8710
|
|
|
8700
8711
|
// src/hooks/agent-usage-reminder/storage.ts
|
|
8701
8712
|
function getStoragePath4(sessionID) {
|
|
8702
|
-
return
|
|
8713
|
+
return join32(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
|
|
8703
8714
|
}
|
|
8704
8715
|
function loadAgentUsageState(sessionID) {
|
|
8705
8716
|
const filePath = getStoragePath4(sessionID);
|
|
@@ -9021,12 +9032,12 @@ import {
|
|
|
9021
9032
|
writeFileSync as writeFileSync11,
|
|
9022
9033
|
unlinkSync as unlinkSync8
|
|
9023
9034
|
} from "fs";
|
|
9024
|
-
import { join as
|
|
9035
|
+
import { join as join34 } from "path";
|
|
9025
9036
|
|
|
9026
9037
|
// src/hooks/interactive-bash-session/constants.ts
|
|
9027
|
-
import { join as
|
|
9028
|
-
var OPENCODE_STORAGE8 =
|
|
9029
|
-
var INTERACTIVE_BASH_SESSION_STORAGE =
|
|
9038
|
+
import { join as join33 } from "path";
|
|
9039
|
+
var OPENCODE_STORAGE8 = join33(xdgData ?? "", "opencode", "storage");
|
|
9040
|
+
var INTERACTIVE_BASH_SESSION_STORAGE = join33(OPENCODE_STORAGE8, "interactive-bash-session");
|
|
9030
9041
|
var OMO_SESSION_PREFIX = "omo-";
|
|
9031
9042
|
function buildSessionReminderMessage(sessions) {
|
|
9032
9043
|
if (sessions.length === 0)
|
|
@@ -9038,7 +9049,7 @@ function buildSessionReminderMessage(sessions) {
|
|
|
9038
9049
|
|
|
9039
9050
|
// src/hooks/interactive-bash-session/storage.ts
|
|
9040
9051
|
function getStoragePath5(sessionID) {
|
|
9041
|
-
return
|
|
9052
|
+
return join34(INTERACTIVE_BASH_SESSION_STORAGE, `${sessionID}.json`);
|
|
9042
9053
|
}
|
|
9043
9054
|
function loadInteractiveBashSessionState(sessionID) {
|
|
9044
9055
|
const filePath = getStoragePath5(sessionID);
|
|
@@ -11016,7 +11027,7 @@ async function createGoogleAntigravityAuthPlugin({
|
|
|
11016
11027
|
// src/features/claude-code-command-loader/loader.ts
|
|
11017
11028
|
import { existsSync as existsSync25, readdirSync as readdirSync7, readFileSync as readFileSync15 } from "fs";
|
|
11018
11029
|
import { homedir as homedir12 } from "os";
|
|
11019
|
-
import { join as
|
|
11030
|
+
import { join as join35, basename } from "path";
|
|
11020
11031
|
function loadCommandsFromDir(commandsDir, scope) {
|
|
11021
11032
|
if (!existsSync25(commandsDir)) {
|
|
11022
11033
|
return [];
|
|
@@ -11026,7 +11037,7 @@ function loadCommandsFromDir(commandsDir, scope) {
|
|
|
11026
11037
|
for (const entry of entries) {
|
|
11027
11038
|
if (!isMarkdownFile(entry))
|
|
11028
11039
|
continue;
|
|
11029
|
-
const commandPath =
|
|
11040
|
+
const commandPath = join35(commandsDir, entry.name);
|
|
11030
11041
|
const commandName = basename(entry.name, ".md");
|
|
11031
11042
|
try {
|
|
11032
11043
|
const content = readFileSync15(commandPath, "utf-8");
|
|
@@ -11069,29 +11080,29 @@ function commandsToRecord(commands) {
|
|
|
11069
11080
|
return result;
|
|
11070
11081
|
}
|
|
11071
11082
|
function loadUserCommands() {
|
|
11072
|
-
const userCommandsDir =
|
|
11083
|
+
const userCommandsDir = join35(homedir12(), ".claude", "commands");
|
|
11073
11084
|
const commands = loadCommandsFromDir(userCommandsDir, "user");
|
|
11074
11085
|
return commandsToRecord(commands);
|
|
11075
11086
|
}
|
|
11076
11087
|
function loadProjectCommands() {
|
|
11077
|
-
const projectCommandsDir =
|
|
11088
|
+
const projectCommandsDir = join35(process.cwd(), ".claude", "commands");
|
|
11078
11089
|
const commands = loadCommandsFromDir(projectCommandsDir, "project");
|
|
11079
11090
|
return commandsToRecord(commands);
|
|
11080
11091
|
}
|
|
11081
11092
|
function loadOpencodeGlobalCommands() {
|
|
11082
|
-
const opencodeCommandsDir =
|
|
11093
|
+
const opencodeCommandsDir = join35(homedir12(), ".config", "opencode", "command");
|
|
11083
11094
|
const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
|
|
11084
11095
|
return commandsToRecord(commands);
|
|
11085
11096
|
}
|
|
11086
11097
|
function loadOpencodeProjectCommands() {
|
|
11087
|
-
const opencodeProjectDir =
|
|
11098
|
+
const opencodeProjectDir = join35(process.cwd(), ".opencode", "command");
|
|
11088
11099
|
const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
|
|
11089
11100
|
return commandsToRecord(commands);
|
|
11090
11101
|
}
|
|
11091
11102
|
// src/features/claude-code-skill-loader/loader.ts
|
|
11092
11103
|
import { existsSync as existsSync26, readdirSync as readdirSync8, readFileSync as readFileSync16 } from "fs";
|
|
11093
11104
|
import { homedir as homedir13 } from "os";
|
|
11094
|
-
import { join as
|
|
11105
|
+
import { join as join36 } from "path";
|
|
11095
11106
|
function loadSkillsFromDir(skillsDir, scope) {
|
|
11096
11107
|
if (!existsSync26(skillsDir)) {
|
|
11097
11108
|
return [];
|
|
@@ -11101,11 +11112,11 @@ function loadSkillsFromDir(skillsDir, scope) {
|
|
|
11101
11112
|
for (const entry of entries) {
|
|
11102
11113
|
if (entry.name.startsWith("."))
|
|
11103
11114
|
continue;
|
|
11104
|
-
const skillPath =
|
|
11115
|
+
const skillPath = join36(skillsDir, entry.name);
|
|
11105
11116
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
11106
11117
|
continue;
|
|
11107
11118
|
const resolvedPath = resolveSymlink(skillPath);
|
|
11108
|
-
const skillMdPath =
|
|
11119
|
+
const skillMdPath = join36(resolvedPath, "SKILL.md");
|
|
11109
11120
|
if (!existsSync26(skillMdPath))
|
|
11110
11121
|
continue;
|
|
11111
11122
|
try {
|
|
@@ -11143,7 +11154,7 @@ $ARGUMENTS
|
|
|
11143
11154
|
return skills;
|
|
11144
11155
|
}
|
|
11145
11156
|
function loadUserSkillsAsCommands() {
|
|
11146
|
-
const userSkillsDir =
|
|
11157
|
+
const userSkillsDir = join36(homedir13(), ".claude", "skills");
|
|
11147
11158
|
const skills = loadSkillsFromDir(userSkillsDir, "user");
|
|
11148
11159
|
return skills.reduce((acc, skill) => {
|
|
11149
11160
|
acc[skill.name] = skill.definition;
|
|
@@ -11151,7 +11162,7 @@ function loadUserSkillsAsCommands() {
|
|
|
11151
11162
|
}, {});
|
|
11152
11163
|
}
|
|
11153
11164
|
function loadProjectSkillsAsCommands() {
|
|
11154
|
-
const projectSkillsDir =
|
|
11165
|
+
const projectSkillsDir = join36(process.cwd(), ".claude", "skills");
|
|
11155
11166
|
const skills = loadSkillsFromDir(projectSkillsDir, "project");
|
|
11156
11167
|
return skills.reduce((acc, skill) => {
|
|
11157
11168
|
acc[skill.name] = skill.definition;
|
|
@@ -11161,7 +11172,7 @@ function loadProjectSkillsAsCommands() {
|
|
|
11161
11172
|
// src/features/claude-code-agent-loader/loader.ts
|
|
11162
11173
|
import { existsSync as existsSync27, readdirSync as readdirSync9, readFileSync as readFileSync17 } from "fs";
|
|
11163
11174
|
import { homedir as homedir14 } from "os";
|
|
11164
|
-
import { join as
|
|
11175
|
+
import { join as join37, basename as basename2 } from "path";
|
|
11165
11176
|
function parseToolsConfig(toolsStr) {
|
|
11166
11177
|
if (!toolsStr)
|
|
11167
11178
|
return;
|
|
@@ -11183,7 +11194,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
11183
11194
|
for (const entry of entries) {
|
|
11184
11195
|
if (!isMarkdownFile(entry))
|
|
11185
11196
|
continue;
|
|
11186
|
-
const agentPath =
|
|
11197
|
+
const agentPath = join37(agentsDir, entry.name);
|
|
11187
11198
|
const agentName = basename2(entry.name, ".md");
|
|
11188
11199
|
try {
|
|
11189
11200
|
const content = readFileSync17(agentPath, "utf-8");
|
|
@@ -11213,7 +11224,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
11213
11224
|
return agents;
|
|
11214
11225
|
}
|
|
11215
11226
|
function loadUserAgents() {
|
|
11216
|
-
const userAgentsDir =
|
|
11227
|
+
const userAgentsDir = join37(homedir14(), ".claude", "agents");
|
|
11217
11228
|
const agents = loadAgentsFromDir(userAgentsDir, "user");
|
|
11218
11229
|
const result = {};
|
|
11219
11230
|
for (const agent of agents) {
|
|
@@ -11222,7 +11233,7 @@ function loadUserAgents() {
|
|
|
11222
11233
|
return result;
|
|
11223
11234
|
}
|
|
11224
11235
|
function loadProjectAgents() {
|
|
11225
|
-
const projectAgentsDir =
|
|
11236
|
+
const projectAgentsDir = join37(process.cwd(), ".claude", "agents");
|
|
11226
11237
|
const agents = loadAgentsFromDir(projectAgentsDir, "project");
|
|
11227
11238
|
const result = {};
|
|
11228
11239
|
for (const agent of agents) {
|
|
@@ -11233,7 +11244,7 @@ function loadProjectAgents() {
|
|
|
11233
11244
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
11234
11245
|
import { existsSync as existsSync28 } from "fs";
|
|
11235
11246
|
import { homedir as homedir15 } from "os";
|
|
11236
|
-
import { join as
|
|
11247
|
+
import { join as join38 } from "path";
|
|
11237
11248
|
|
|
11238
11249
|
// src/features/claude-code-mcp-loader/env-expander.ts
|
|
11239
11250
|
function expandEnvVars(value) {
|
|
@@ -11302,9 +11313,9 @@ function getMcpConfigPaths() {
|
|
|
11302
11313
|
const home = homedir15();
|
|
11303
11314
|
const cwd = process.cwd();
|
|
11304
11315
|
return [
|
|
11305
|
-
{ path:
|
|
11306
|
-
{ path:
|
|
11307
|
-
{ path:
|
|
11316
|
+
{ path: join38(home, ".claude", ".mcp.json"), scope: "user" },
|
|
11317
|
+
{ path: join38(cwd, ".mcp.json"), scope: "project" },
|
|
11318
|
+
{ path: join38(cwd, ".claude", ".mcp.json"), scope: "local" }
|
|
11308
11319
|
];
|
|
11309
11320
|
}
|
|
11310
11321
|
async function loadMcpConfigFile(filePath) {
|
|
@@ -11323,13 +11334,13 @@ async function loadMcpConfigs() {
|
|
|
11323
11334
|
const servers = {};
|
|
11324
11335
|
const loadedServers = [];
|
|
11325
11336
|
const paths = getMcpConfigPaths();
|
|
11326
|
-
for (const { path:
|
|
11327
|
-
const config = await loadMcpConfigFile(
|
|
11337
|
+
for (const { path: path8, scope } of paths) {
|
|
11338
|
+
const config = await loadMcpConfigFile(path8);
|
|
11328
11339
|
if (!config?.mcpServers)
|
|
11329
11340
|
continue;
|
|
11330
11341
|
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
11331
11342
|
if (serverConfig.disabled) {
|
|
11332
|
-
log(`Skipping disabled MCP server "${name}"`, { path:
|
|
11343
|
+
log(`Skipping disabled MCP server "${name}"`, { path: path8 });
|
|
11333
11344
|
continue;
|
|
11334
11345
|
}
|
|
11335
11346
|
try {
|
|
@@ -11340,7 +11351,7 @@ async function loadMcpConfigs() {
|
|
|
11340
11351
|
loadedServers.splice(existingIndex, 1);
|
|
11341
11352
|
}
|
|
11342
11353
|
loadedServers.push({ name, scope, config: transformed });
|
|
11343
|
-
log(`Loaded MCP server "${name}" from ${scope}`, { path:
|
|
11354
|
+
log(`Loaded MCP server "${name}" from ${scope}`, { path: path8 });
|
|
11344
11355
|
} catch (error) {
|
|
11345
11356
|
log(`Failed to transform MCP server "${name}"`, error);
|
|
11346
11357
|
}
|
|
@@ -11644,13 +11655,13 @@ var EXT_TO_LANG = {
|
|
|
11644
11655
|
};
|
|
11645
11656
|
// src/tools/lsp/config.ts
|
|
11646
11657
|
import { existsSync as existsSync29, readFileSync as readFileSync18 } from "fs";
|
|
11647
|
-
import { join as
|
|
11658
|
+
import { join as join39 } from "path";
|
|
11648
11659
|
import { homedir as homedir16 } from "os";
|
|
11649
|
-
function loadJsonFile(
|
|
11650
|
-
if (!existsSync29(
|
|
11660
|
+
function loadJsonFile(path8) {
|
|
11661
|
+
if (!existsSync29(path8))
|
|
11651
11662
|
return null;
|
|
11652
11663
|
try {
|
|
11653
|
-
return JSON.parse(readFileSync18(
|
|
11664
|
+
return JSON.parse(readFileSync18(path8, "utf-8"));
|
|
11654
11665
|
} catch {
|
|
11655
11666
|
return null;
|
|
11656
11667
|
}
|
|
@@ -11658,9 +11669,9 @@ function loadJsonFile(path7) {
|
|
|
11658
11669
|
function getConfigPaths2() {
|
|
11659
11670
|
const cwd = process.cwd();
|
|
11660
11671
|
return {
|
|
11661
|
-
project:
|
|
11662
|
-
user:
|
|
11663
|
-
opencode:
|
|
11672
|
+
project: join39(cwd, ".opencode", "oh-my-opencode.json"),
|
|
11673
|
+
user: join39(homedir16(), ".config", "opencode", "oh-my-opencode.json"),
|
|
11674
|
+
opencode: join39(homedir16(), ".config", "opencode", "opencode.json")
|
|
11664
11675
|
};
|
|
11665
11676
|
}
|
|
11666
11677
|
function loadAllConfigs() {
|
|
@@ -11756,18 +11767,18 @@ function isServerInstalled(command) {
|
|
|
11756
11767
|
const pathSeparator = isWindows2 ? ";" : ":";
|
|
11757
11768
|
const paths = pathEnv.split(pathSeparator);
|
|
11758
11769
|
for (const p of paths) {
|
|
11759
|
-
if (existsSync29(
|
|
11770
|
+
if (existsSync29(join39(p, cmd)) || existsSync29(join39(p, cmd + ext))) {
|
|
11760
11771
|
return true;
|
|
11761
11772
|
}
|
|
11762
11773
|
}
|
|
11763
11774
|
const cwd = process.cwd();
|
|
11764
11775
|
const additionalPaths = [
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11776
|
+
join39(cwd, "node_modules", ".bin", cmd),
|
|
11777
|
+
join39(cwd, "node_modules", ".bin", cmd + ext),
|
|
11778
|
+
join39(homedir16(), ".config", "opencode", "bin", cmd),
|
|
11779
|
+
join39(homedir16(), ".config", "opencode", "bin", cmd + ext),
|
|
11780
|
+
join39(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd),
|
|
11781
|
+
join39(homedir16(), ".config", "opencode", "node_modules", ".bin", cmd + ext)
|
|
11771
11782
|
];
|
|
11772
11783
|
for (const p of additionalPaths) {
|
|
11773
11784
|
if (existsSync29(p)) {
|
|
@@ -13379,10 +13390,10 @@ function mergeDefs(...defs) {
|
|
|
13379
13390
|
function cloneDef(schema) {
|
|
13380
13391
|
return mergeDefs(schema._zod.def);
|
|
13381
13392
|
}
|
|
13382
|
-
function getElementAtPath(obj,
|
|
13383
|
-
if (!
|
|
13393
|
+
function getElementAtPath(obj, path8) {
|
|
13394
|
+
if (!path8)
|
|
13384
13395
|
return obj;
|
|
13385
|
-
return
|
|
13396
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
13386
13397
|
}
|
|
13387
13398
|
function promiseAllObject(promisesObj) {
|
|
13388
13399
|
const keys = Object.keys(promisesObj);
|
|
@@ -13741,11 +13752,11 @@ function aborted(x, startIndex = 0) {
|
|
|
13741
13752
|
}
|
|
13742
13753
|
return false;
|
|
13743
13754
|
}
|
|
13744
|
-
function prefixIssues(
|
|
13755
|
+
function prefixIssues(path8, issues) {
|
|
13745
13756
|
return issues.map((iss) => {
|
|
13746
13757
|
var _a;
|
|
13747
13758
|
(_a = iss).path ?? (_a.path = []);
|
|
13748
|
-
iss.path.unshift(
|
|
13759
|
+
iss.path.unshift(path8);
|
|
13749
13760
|
return iss;
|
|
13750
13761
|
});
|
|
13751
13762
|
}
|
|
@@ -13913,7 +13924,7 @@ function treeifyError(error, _mapper) {
|
|
|
13913
13924
|
return issue2.message;
|
|
13914
13925
|
};
|
|
13915
13926
|
const result = { errors: [] };
|
|
13916
|
-
const processError = (error2,
|
|
13927
|
+
const processError = (error2, path8 = []) => {
|
|
13917
13928
|
var _a, _b;
|
|
13918
13929
|
for (const issue2 of error2.issues) {
|
|
13919
13930
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -13923,7 +13934,7 @@ function treeifyError(error, _mapper) {
|
|
|
13923
13934
|
} else if (issue2.code === "invalid_element") {
|
|
13924
13935
|
processError({ issues: issue2.issues }, issue2.path);
|
|
13925
13936
|
} else {
|
|
13926
|
-
const fullpath = [...
|
|
13937
|
+
const fullpath = [...path8, ...issue2.path];
|
|
13927
13938
|
if (fullpath.length === 0) {
|
|
13928
13939
|
result.errors.push(mapper(issue2));
|
|
13929
13940
|
continue;
|
|
@@ -13955,8 +13966,8 @@ function treeifyError(error, _mapper) {
|
|
|
13955
13966
|
}
|
|
13956
13967
|
function toDotPath(_path) {
|
|
13957
13968
|
const segs = [];
|
|
13958
|
-
const
|
|
13959
|
-
for (const seg of
|
|
13969
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
13970
|
+
for (const seg of path8) {
|
|
13960
13971
|
if (typeof seg === "number")
|
|
13961
13972
|
segs.push(`[${seg}]`);
|
|
13962
13973
|
else if (typeof seg === "symbol")
|
|
@@ -25299,13 +25310,13 @@ var lsp_code_action_resolve = tool({
|
|
|
25299
25310
|
});
|
|
25300
25311
|
// src/tools/ast-grep/constants.ts
|
|
25301
25312
|
import { createRequire as createRequire4 } from "module";
|
|
25302
|
-
import { dirname as dirname6, join as
|
|
25313
|
+
import { dirname as dirname6, join as join41 } from "path";
|
|
25303
25314
|
import { existsSync as existsSync32, statSync as statSync4 } from "fs";
|
|
25304
25315
|
|
|
25305
25316
|
// src/tools/ast-grep/downloader.ts
|
|
25306
25317
|
var {spawn: spawn5 } = globalThis.Bun;
|
|
25307
25318
|
import { existsSync as existsSync31, mkdirSync as mkdirSync10, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
|
|
25308
|
-
import { join as
|
|
25319
|
+
import { join as join40 } from "path";
|
|
25309
25320
|
import { homedir as homedir17 } from "os";
|
|
25310
25321
|
import { createRequire as createRequire3 } from "module";
|
|
25311
25322
|
var REPO2 = "ast-grep/ast-grep";
|
|
@@ -25331,18 +25342,18 @@ var PLATFORM_MAP2 = {
|
|
|
25331
25342
|
function getCacheDir3() {
|
|
25332
25343
|
if (process.platform === "win32") {
|
|
25333
25344
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
25334
|
-
const base2 = localAppData ||
|
|
25335
|
-
return
|
|
25345
|
+
const base2 = localAppData || join40(homedir17(), "AppData", "Local");
|
|
25346
|
+
return join40(base2, "oh-my-opencode", "bin");
|
|
25336
25347
|
}
|
|
25337
25348
|
const xdgCache2 = process.env.XDG_CACHE_HOME;
|
|
25338
|
-
const base = xdgCache2 ||
|
|
25339
|
-
return
|
|
25349
|
+
const base = xdgCache2 || join40(homedir17(), ".cache");
|
|
25350
|
+
return join40(base, "oh-my-opencode", "bin");
|
|
25340
25351
|
}
|
|
25341
25352
|
function getBinaryName3() {
|
|
25342
25353
|
return process.platform === "win32" ? "sg.exe" : "sg";
|
|
25343
25354
|
}
|
|
25344
25355
|
function getCachedBinaryPath2() {
|
|
25345
|
-
const binaryPath =
|
|
25356
|
+
const binaryPath = join40(getCacheDir3(), getBinaryName3());
|
|
25346
25357
|
return existsSync31(binaryPath) ? binaryPath : null;
|
|
25347
25358
|
}
|
|
25348
25359
|
async function extractZip2(archivePath, destDir) {
|
|
@@ -25369,12 +25380,12 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
25369
25380
|
}
|
|
25370
25381
|
const cacheDir = getCacheDir3();
|
|
25371
25382
|
const binaryName = getBinaryName3();
|
|
25372
|
-
const binaryPath =
|
|
25383
|
+
const binaryPath = join40(cacheDir, binaryName);
|
|
25373
25384
|
if (existsSync31(binaryPath)) {
|
|
25374
25385
|
return binaryPath;
|
|
25375
25386
|
}
|
|
25376
|
-
const { arch, os:
|
|
25377
|
-
const assetName = `app-${arch}-${
|
|
25387
|
+
const { arch, os: os6 } = platformInfo;
|
|
25388
|
+
const assetName = `app-${arch}-${os6}.zip`;
|
|
25378
25389
|
const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
|
|
25379
25390
|
console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
|
|
25380
25391
|
try {
|
|
@@ -25385,7 +25396,7 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
25385
25396
|
if (!response2.ok) {
|
|
25386
25397
|
throw new Error(`HTTP ${response2.status}: ${response2.statusText}`);
|
|
25387
25398
|
}
|
|
25388
|
-
const archivePath =
|
|
25399
|
+
const archivePath = join40(cacheDir, assetName);
|
|
25389
25400
|
const arrayBuffer = await response2.arrayBuffer();
|
|
25390
25401
|
await Bun.write(archivePath, arrayBuffer);
|
|
25391
25402
|
await extractZip2(archivePath, cacheDir);
|
|
@@ -25443,7 +25454,7 @@ function findSgCliPathSync() {
|
|
|
25443
25454
|
const require2 = createRequire4(import.meta.url);
|
|
25444
25455
|
const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
|
|
25445
25456
|
const cliDir = dirname6(cliPkgPath);
|
|
25446
|
-
const sgPath =
|
|
25457
|
+
const sgPath = join41(cliDir, binaryName);
|
|
25447
25458
|
if (existsSync32(sgPath) && isValidBinary(sgPath)) {
|
|
25448
25459
|
return sgPath;
|
|
25449
25460
|
}
|
|
@@ -25455,7 +25466,7 @@ function findSgCliPathSync() {
|
|
|
25455
25466
|
const pkgPath = require2.resolve(`${platformPkg}/package.json`);
|
|
25456
25467
|
const pkgDir = dirname6(pkgPath);
|
|
25457
25468
|
const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
25458
|
-
const binaryPath =
|
|
25469
|
+
const binaryPath = join41(pkgDir, astGrepName);
|
|
25459
25470
|
if (existsSync32(binaryPath) && isValidBinary(binaryPath)) {
|
|
25460
25471
|
return binaryPath;
|
|
25461
25472
|
}
|
|
@@ -25463,9 +25474,9 @@ function findSgCliPathSync() {
|
|
|
25463
25474
|
}
|
|
25464
25475
|
if (process.platform === "darwin") {
|
|
25465
25476
|
const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
|
|
25466
|
-
for (const
|
|
25467
|
-
if (existsSync32(
|
|
25468
|
-
return
|
|
25477
|
+
for (const path8 of homebrewPaths) {
|
|
25478
|
+
if (existsSync32(path8) && isValidBinary(path8)) {
|
|
25479
|
+
return path8;
|
|
25469
25480
|
}
|
|
25470
25481
|
}
|
|
25471
25482
|
}
|
|
@@ -25483,8 +25494,8 @@ function getSgCliPath() {
|
|
|
25483
25494
|
}
|
|
25484
25495
|
return "sg";
|
|
25485
25496
|
}
|
|
25486
|
-
function setSgCliPath(
|
|
25487
|
-
resolvedCliPath2 =
|
|
25497
|
+
function setSgCliPath(path8) {
|
|
25498
|
+
resolvedCliPath2 = path8;
|
|
25488
25499
|
}
|
|
25489
25500
|
var SG_CLI_PATH = getSgCliPath();
|
|
25490
25501
|
var CLI_LANGUAGES = [
|
|
@@ -25831,19 +25842,19 @@ var {spawn: spawn7 } = globalThis.Bun;
|
|
|
25831
25842
|
|
|
25832
25843
|
// src/tools/grep/constants.ts
|
|
25833
25844
|
import { existsSync as existsSync35 } from "fs";
|
|
25834
|
-
import { join as
|
|
25845
|
+
import { join as join43, dirname as dirname7 } from "path";
|
|
25835
25846
|
import { spawnSync } from "child_process";
|
|
25836
25847
|
|
|
25837
25848
|
// src/tools/grep/downloader.ts
|
|
25838
25849
|
import { existsSync as existsSync34, mkdirSync as mkdirSync11, chmodSync as chmodSync3, unlinkSync as unlinkSync10, readdirSync as readdirSync10 } from "fs";
|
|
25839
|
-
import { join as
|
|
25850
|
+
import { join as join42 } from "path";
|
|
25840
25851
|
function getInstallDir() {
|
|
25841
25852
|
const homeDir = process.env.HOME || process.env.USERPROFILE || ".";
|
|
25842
|
-
return
|
|
25853
|
+
return join42(homeDir, ".cache", "oh-my-opencode", "bin");
|
|
25843
25854
|
}
|
|
25844
25855
|
function getRgPath() {
|
|
25845
25856
|
const isWindows2 = process.platform === "win32";
|
|
25846
|
-
return
|
|
25857
|
+
return join42(getInstallDir(), isWindows2 ? "rg.exe" : "rg");
|
|
25847
25858
|
}
|
|
25848
25859
|
function getInstalledRipgrepPath() {
|
|
25849
25860
|
const rgPath = getRgPath();
|
|
@@ -25870,10 +25881,10 @@ function getOpenCodeBundledRg() {
|
|
|
25870
25881
|
const isWindows2 = process.platform === "win32";
|
|
25871
25882
|
const rgName = isWindows2 ? "rg.exe" : "rg";
|
|
25872
25883
|
const candidates = [
|
|
25873
|
-
|
|
25874
|
-
|
|
25875
|
-
|
|
25876
|
-
|
|
25884
|
+
join43(execDir, rgName),
|
|
25885
|
+
join43(execDir, "bin", rgName),
|
|
25886
|
+
join43(execDir, "..", "bin", rgName),
|
|
25887
|
+
join43(execDir, "..", "libexec", rgName)
|
|
25877
25888
|
];
|
|
25878
25889
|
for (const candidate of candidates) {
|
|
25879
25890
|
if (existsSync35(candidate)) {
|
|
@@ -26281,7 +26292,7 @@ var glob = tool({
|
|
|
26281
26292
|
// src/tools/slashcommand/tools.ts
|
|
26282
26293
|
import { existsSync as existsSync36, readdirSync as readdirSync11, readFileSync as readFileSync21 } from "fs";
|
|
26283
26294
|
import { homedir as homedir18 } from "os";
|
|
26284
|
-
import { join as
|
|
26295
|
+
import { join as join44, basename as basename3, dirname as dirname8 } from "path";
|
|
26285
26296
|
function discoverCommandsFromDir(commandsDir, scope) {
|
|
26286
26297
|
if (!existsSync36(commandsDir)) {
|
|
26287
26298
|
return [];
|
|
@@ -26291,7 +26302,7 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
26291
26302
|
for (const entry of entries) {
|
|
26292
26303
|
if (!isMarkdownFile(entry))
|
|
26293
26304
|
continue;
|
|
26294
|
-
const commandPath =
|
|
26305
|
+
const commandPath = join44(commandsDir, entry.name);
|
|
26295
26306
|
const commandName = basename3(entry.name, ".md");
|
|
26296
26307
|
try {
|
|
26297
26308
|
const content = readFileSync21(commandPath, "utf-8");
|
|
@@ -26319,10 +26330,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
26319
26330
|
return commands;
|
|
26320
26331
|
}
|
|
26321
26332
|
function discoverCommandsSync() {
|
|
26322
|
-
const userCommandsDir =
|
|
26323
|
-
const projectCommandsDir =
|
|
26324
|
-
const opencodeGlobalDir =
|
|
26325
|
-
const opencodeProjectDir =
|
|
26333
|
+
const userCommandsDir = join44(homedir18(), ".claude", "commands");
|
|
26334
|
+
const projectCommandsDir = join44(process.cwd(), ".claude", "commands");
|
|
26335
|
+
const opencodeGlobalDir = join44(homedir18(), ".config", "opencode", "command");
|
|
26336
|
+
const opencodeProjectDir = join44(process.cwd(), ".opencode", "command");
|
|
26326
26337
|
const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
|
|
26327
26338
|
const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
|
|
26328
26339
|
const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
|
|
@@ -26445,6 +26456,484 @@ Provide a command name to execute.`;
|
|
|
26445
26456
|
Try a different command name.`;
|
|
26446
26457
|
}
|
|
26447
26458
|
});
|
|
26459
|
+
// src/tools/session-manager/constants.ts
|
|
26460
|
+
import { join as join45 } from "path";
|
|
26461
|
+
import { homedir as homedir19 } from "os";
|
|
26462
|
+
var OPENCODE_STORAGE9 = getOpenCodeStorageDir();
|
|
26463
|
+
var MESSAGE_STORAGE4 = join45(OPENCODE_STORAGE9, "message");
|
|
26464
|
+
var PART_STORAGE4 = join45(OPENCODE_STORAGE9, "part");
|
|
26465
|
+
var TODO_DIR2 = join45(homedir19(), ".claude", "todos");
|
|
26466
|
+
var TRANSCRIPT_DIR2 = join45(homedir19(), ".claude", "transcripts");
|
|
26467
|
+
var SESSION_LIST_DESCRIPTION = `List all OpenCode sessions with optional filtering.
|
|
26468
|
+
|
|
26469
|
+
Returns a list of available session IDs with metadata including message count, date range, and agents used.
|
|
26470
|
+
|
|
26471
|
+
Arguments:
|
|
26472
|
+
- limit (optional): Maximum number of sessions to return
|
|
26473
|
+
- from_date (optional): Filter sessions from this date (ISO 8601 format)
|
|
26474
|
+
- to_date (optional): Filter sessions until this date (ISO 8601 format)
|
|
26475
|
+
|
|
26476
|
+
Example output:
|
|
26477
|
+
| Session ID | Messages | First | Last | Agents |
|
|
26478
|
+
|------------|----------|-------|------|--------|
|
|
26479
|
+
| ses_abc123 | 45 | 2025-12-20 | 2025-12-24 | build, oracle |
|
|
26480
|
+
| ses_def456 | 12 | 2025-12-19 | 2025-12-19 | build |`;
|
|
26481
|
+
var SESSION_READ_DESCRIPTION = `Read messages and history from an OpenCode session.
|
|
26482
|
+
|
|
26483
|
+
Returns a formatted view of session messages with role, timestamp, and content. Optionally includes todos and transcript data.
|
|
26484
|
+
|
|
26485
|
+
Arguments:
|
|
26486
|
+
- session_id (required): Session ID to read
|
|
26487
|
+
- include_todos (optional): Include todo list if available (default: false)
|
|
26488
|
+
- include_transcript (optional): Include transcript log if available (default: false)
|
|
26489
|
+
- limit (optional): Maximum number of messages to return (default: all)
|
|
26490
|
+
|
|
26491
|
+
Example output:
|
|
26492
|
+
Session: ses_abc123
|
|
26493
|
+
Messages: 45
|
|
26494
|
+
Date Range: 2025-12-20 to 2025-12-24
|
|
26495
|
+
|
|
26496
|
+
[Message 1] user (2025-12-20 10:30:00)
|
|
26497
|
+
Hello, can you help me with...
|
|
26498
|
+
|
|
26499
|
+
[Message 2] assistant (2025-12-20 10:30:15)
|
|
26500
|
+
Of course! Let me help you with...`;
|
|
26501
|
+
var SESSION_SEARCH_DESCRIPTION = `Search for content within OpenCode session messages.
|
|
26502
|
+
|
|
26503
|
+
Performs full-text search across session messages and returns matching excerpts with context.
|
|
26504
|
+
|
|
26505
|
+
Arguments:
|
|
26506
|
+
- query (required): Search query string
|
|
26507
|
+
- session_id (optional): Search within specific session only (default: all sessions)
|
|
26508
|
+
- case_sensitive (optional): Case-sensitive search (default: false)
|
|
26509
|
+
- limit (optional): Maximum number of results to return (default: 20)
|
|
26510
|
+
|
|
26511
|
+
Example output:
|
|
26512
|
+
Found 3 matches across 2 sessions:
|
|
26513
|
+
|
|
26514
|
+
[ses_abc123] Message msg_001 (user)
|
|
26515
|
+
...implement the **session manager** tool...
|
|
26516
|
+
|
|
26517
|
+
[ses_abc123] Message msg_005 (assistant)
|
|
26518
|
+
...I'll create a **session manager** with full search...
|
|
26519
|
+
|
|
26520
|
+
[ses_def456] Message msg_012 (user)
|
|
26521
|
+
...use the **session manager** to find...`;
|
|
26522
|
+
var SESSION_INFO_DESCRIPTION = `Get metadata and statistics about an OpenCode session.
|
|
26523
|
+
|
|
26524
|
+
Returns detailed information about a session including message count, date range, agents used, and available data sources.
|
|
26525
|
+
|
|
26526
|
+
Arguments:
|
|
26527
|
+
- session_id (required): Session ID to inspect
|
|
26528
|
+
|
|
26529
|
+
Example output:
|
|
26530
|
+
Session ID: ses_abc123
|
|
26531
|
+
Messages: 45
|
|
26532
|
+
Date Range: 2025-12-20 10:30:00 to 2025-12-24 15:45:30
|
|
26533
|
+
Duration: 4 days, 5 hours
|
|
26534
|
+
Agents Used: build, oracle, librarian
|
|
26535
|
+
Has Todos: Yes (12 items, 8 completed)
|
|
26536
|
+
Has Transcript: Yes (234 entries)`;
|
|
26537
|
+
|
|
26538
|
+
// src/tools/session-manager/storage.ts
|
|
26539
|
+
import { existsSync as existsSync37, readdirSync as readdirSync12, readFileSync as readFileSync22 } from "fs";
|
|
26540
|
+
import { join as join46 } from "path";
|
|
26541
|
+
function getAllSessions() {
|
|
26542
|
+
if (!existsSync37(MESSAGE_STORAGE4))
|
|
26543
|
+
return [];
|
|
26544
|
+
const sessions = [];
|
|
26545
|
+
function scanDirectory(dir) {
|
|
26546
|
+
try {
|
|
26547
|
+
for (const entry of readdirSync12(dir, { withFileTypes: true })) {
|
|
26548
|
+
if (entry.isDirectory()) {
|
|
26549
|
+
const sessionPath = join46(dir, entry.name);
|
|
26550
|
+
const files = readdirSync12(sessionPath);
|
|
26551
|
+
if (files.some((f) => f.endsWith(".json"))) {
|
|
26552
|
+
sessions.push(entry.name);
|
|
26553
|
+
} else {
|
|
26554
|
+
scanDirectory(sessionPath);
|
|
26555
|
+
}
|
|
26556
|
+
}
|
|
26557
|
+
}
|
|
26558
|
+
} catch {
|
|
26559
|
+
return;
|
|
26560
|
+
}
|
|
26561
|
+
}
|
|
26562
|
+
scanDirectory(MESSAGE_STORAGE4);
|
|
26563
|
+
return [...new Set(sessions)];
|
|
26564
|
+
}
|
|
26565
|
+
function getMessageDir5(sessionID) {
|
|
26566
|
+
if (!existsSync37(MESSAGE_STORAGE4))
|
|
26567
|
+
return "";
|
|
26568
|
+
const directPath = join46(MESSAGE_STORAGE4, sessionID);
|
|
26569
|
+
if (existsSync37(directPath)) {
|
|
26570
|
+
return directPath;
|
|
26571
|
+
}
|
|
26572
|
+
for (const dir of readdirSync12(MESSAGE_STORAGE4)) {
|
|
26573
|
+
const sessionPath = join46(MESSAGE_STORAGE4, dir, sessionID);
|
|
26574
|
+
if (existsSync37(sessionPath)) {
|
|
26575
|
+
return sessionPath;
|
|
26576
|
+
}
|
|
26577
|
+
}
|
|
26578
|
+
return "";
|
|
26579
|
+
}
|
|
26580
|
+
function sessionExists(sessionID) {
|
|
26581
|
+
return getMessageDir5(sessionID) !== "";
|
|
26582
|
+
}
|
|
26583
|
+
function readSessionMessages(sessionID) {
|
|
26584
|
+
const messageDir = getMessageDir5(sessionID);
|
|
26585
|
+
if (!messageDir || !existsSync37(messageDir))
|
|
26586
|
+
return [];
|
|
26587
|
+
const messages = [];
|
|
26588
|
+
for (const file2 of readdirSync12(messageDir)) {
|
|
26589
|
+
if (!file2.endsWith(".json"))
|
|
26590
|
+
continue;
|
|
26591
|
+
try {
|
|
26592
|
+
const content = readFileSync22(join46(messageDir, file2), "utf-8");
|
|
26593
|
+
const meta = JSON.parse(content);
|
|
26594
|
+
const parts = readParts2(meta.id);
|
|
26595
|
+
messages.push({
|
|
26596
|
+
id: meta.id,
|
|
26597
|
+
role: meta.role,
|
|
26598
|
+
agent: meta.agent,
|
|
26599
|
+
time: meta.time,
|
|
26600
|
+
parts
|
|
26601
|
+
});
|
|
26602
|
+
} catch {
|
|
26603
|
+
continue;
|
|
26604
|
+
}
|
|
26605
|
+
}
|
|
26606
|
+
return messages.sort((a, b) => {
|
|
26607
|
+
const aTime = a.time?.created ?? 0;
|
|
26608
|
+
const bTime = b.time?.created ?? 0;
|
|
26609
|
+
if (aTime !== bTime)
|
|
26610
|
+
return aTime - bTime;
|
|
26611
|
+
return a.id.localeCompare(b.id);
|
|
26612
|
+
});
|
|
26613
|
+
}
|
|
26614
|
+
function readParts2(messageID) {
|
|
26615
|
+
const partDir = join46(PART_STORAGE4, messageID);
|
|
26616
|
+
if (!existsSync37(partDir))
|
|
26617
|
+
return [];
|
|
26618
|
+
const parts = [];
|
|
26619
|
+
for (const file2 of readdirSync12(partDir)) {
|
|
26620
|
+
if (!file2.endsWith(".json"))
|
|
26621
|
+
continue;
|
|
26622
|
+
try {
|
|
26623
|
+
const content = readFileSync22(join46(partDir, file2), "utf-8");
|
|
26624
|
+
parts.push(JSON.parse(content));
|
|
26625
|
+
} catch {
|
|
26626
|
+
continue;
|
|
26627
|
+
}
|
|
26628
|
+
}
|
|
26629
|
+
return parts.sort((a, b) => a.id.localeCompare(b.id));
|
|
26630
|
+
}
|
|
26631
|
+
function readSessionTodos(sessionID) {
|
|
26632
|
+
if (!existsSync37(TODO_DIR2))
|
|
26633
|
+
return [];
|
|
26634
|
+
const todoFiles = readdirSync12(TODO_DIR2).filter((f) => f.includes(sessionID) && f.endsWith(".json"));
|
|
26635
|
+
for (const file2 of todoFiles) {
|
|
26636
|
+
try {
|
|
26637
|
+
const content = readFileSync22(join46(TODO_DIR2, file2), "utf-8");
|
|
26638
|
+
const data = JSON.parse(content);
|
|
26639
|
+
if (Array.isArray(data)) {
|
|
26640
|
+
return data.map((item) => ({
|
|
26641
|
+
id: item.id || "",
|
|
26642
|
+
content: item.content || "",
|
|
26643
|
+
status: item.status || "pending",
|
|
26644
|
+
priority: item.priority
|
|
26645
|
+
}));
|
|
26646
|
+
}
|
|
26647
|
+
} catch {
|
|
26648
|
+
continue;
|
|
26649
|
+
}
|
|
26650
|
+
}
|
|
26651
|
+
return [];
|
|
26652
|
+
}
|
|
26653
|
+
function readSessionTranscript(sessionID) {
|
|
26654
|
+
if (!existsSync37(TRANSCRIPT_DIR2))
|
|
26655
|
+
return 0;
|
|
26656
|
+
const transcriptFile = join46(TRANSCRIPT_DIR2, `${sessionID}.jsonl`);
|
|
26657
|
+
if (!existsSync37(transcriptFile))
|
|
26658
|
+
return 0;
|
|
26659
|
+
try {
|
|
26660
|
+
const content = readFileSync22(transcriptFile, "utf-8");
|
|
26661
|
+
return content.trim().split(`
|
|
26662
|
+
`).filter(Boolean).length;
|
|
26663
|
+
} catch {
|
|
26664
|
+
return 0;
|
|
26665
|
+
}
|
|
26666
|
+
}
|
|
26667
|
+
function getSessionInfo(sessionID) {
|
|
26668
|
+
const messages = readSessionMessages(sessionID);
|
|
26669
|
+
if (messages.length === 0)
|
|
26670
|
+
return null;
|
|
26671
|
+
const agentsUsed = new Set;
|
|
26672
|
+
let firstMessage;
|
|
26673
|
+
let lastMessage;
|
|
26674
|
+
for (const msg of messages) {
|
|
26675
|
+
if (msg.agent)
|
|
26676
|
+
agentsUsed.add(msg.agent);
|
|
26677
|
+
if (msg.time?.created) {
|
|
26678
|
+
const date5 = new Date(msg.time.created);
|
|
26679
|
+
if (!firstMessage || date5 < firstMessage)
|
|
26680
|
+
firstMessage = date5;
|
|
26681
|
+
if (!lastMessage || date5 > lastMessage)
|
|
26682
|
+
lastMessage = date5;
|
|
26683
|
+
}
|
|
26684
|
+
}
|
|
26685
|
+
const todos = readSessionTodos(sessionID);
|
|
26686
|
+
const transcriptEntries = readSessionTranscript(sessionID);
|
|
26687
|
+
return {
|
|
26688
|
+
id: sessionID,
|
|
26689
|
+
message_count: messages.length,
|
|
26690
|
+
first_message: firstMessage,
|
|
26691
|
+
last_message: lastMessage,
|
|
26692
|
+
agents_used: Array.from(agentsUsed),
|
|
26693
|
+
has_todos: todos.length > 0,
|
|
26694
|
+
has_transcript: transcriptEntries > 0,
|
|
26695
|
+
todos,
|
|
26696
|
+
transcript_entries: transcriptEntries
|
|
26697
|
+
};
|
|
26698
|
+
}
|
|
26699
|
+
|
|
26700
|
+
// src/tools/session-manager/utils.ts
|
|
26701
|
+
function formatSessionList(sessionIDs) {
|
|
26702
|
+
if (sessionIDs.length === 0) {
|
|
26703
|
+
return "No sessions found.";
|
|
26704
|
+
}
|
|
26705
|
+
const infos = sessionIDs.map((id) => getSessionInfo(id)).filter((info) => info !== null);
|
|
26706
|
+
if (infos.length === 0) {
|
|
26707
|
+
return "No valid sessions found.";
|
|
26708
|
+
}
|
|
26709
|
+
const headers = ["Session ID", "Messages", "First", "Last", "Agents"];
|
|
26710
|
+
const rows = infos.map((info) => [
|
|
26711
|
+
info.id,
|
|
26712
|
+
info.message_count.toString(),
|
|
26713
|
+
info.first_message?.toISOString().split("T")[0] ?? "N/A",
|
|
26714
|
+
info.last_message?.toISOString().split("T")[0] ?? "N/A",
|
|
26715
|
+
info.agents_used.join(", ") || "none"
|
|
26716
|
+
]);
|
|
26717
|
+
const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => r[i].length)));
|
|
26718
|
+
const formatRow = (cells) => {
|
|
26719
|
+
return "| " + cells.map((cell, i) => cell.padEnd(colWidths[i])).join(" | ").trim() + " |";
|
|
26720
|
+
};
|
|
26721
|
+
const separator = "|" + colWidths.map((w) => "-".repeat(w + 2)).join("|") + "|";
|
|
26722
|
+
return [formatRow(headers), separator, ...rows.map(formatRow)].join(`
|
|
26723
|
+
`);
|
|
26724
|
+
}
|
|
26725
|
+
function formatSessionMessages(messages, includeTodos, todos) {
|
|
26726
|
+
if (messages.length === 0) {
|
|
26727
|
+
return "No messages found in this session.";
|
|
26728
|
+
}
|
|
26729
|
+
const lines = [];
|
|
26730
|
+
for (const msg of messages) {
|
|
26731
|
+
const timestamp = msg.time?.created ? new Date(msg.time.created).toISOString() : "Unknown time";
|
|
26732
|
+
const agent = msg.agent ? ` (${msg.agent})` : "";
|
|
26733
|
+
lines.push(`
|
|
26734
|
+
[${msg.role}${agent}] ${timestamp}`);
|
|
26735
|
+
for (const part of msg.parts) {
|
|
26736
|
+
if (part.type === "text" && part.text) {
|
|
26737
|
+
lines.push(part.text.trim());
|
|
26738
|
+
} else if (part.type === "thinking" && part.thinking) {
|
|
26739
|
+
lines.push(`[thinking] ${part.thinking.substring(0, 200)}...`);
|
|
26740
|
+
} else if ((part.type === "tool_use" || part.type === "tool") && part.tool) {
|
|
26741
|
+
const input = part.input ? JSON.stringify(part.input).substring(0, 100) : "";
|
|
26742
|
+
lines.push(`[tool: ${part.tool}] ${input}`);
|
|
26743
|
+
} else if (part.type === "tool_result") {
|
|
26744
|
+
const output = part.output ? part.output.substring(0, 200) : "";
|
|
26745
|
+
lines.push(`[tool result] ${output}...`);
|
|
26746
|
+
}
|
|
26747
|
+
}
|
|
26748
|
+
}
|
|
26749
|
+
if (includeTodos && todos && todos.length > 0) {
|
|
26750
|
+
lines.push(`
|
|
26751
|
+
|
|
26752
|
+
=== Todos ===`);
|
|
26753
|
+
for (const todo of todos) {
|
|
26754
|
+
const status = todo.status === "completed" ? "\u2713" : todo.status === "in_progress" ? "\u2192" : "\u25CB";
|
|
26755
|
+
lines.push(`${status} [${todo.status}] ${todo.content}`);
|
|
26756
|
+
}
|
|
26757
|
+
}
|
|
26758
|
+
return lines.join(`
|
|
26759
|
+
`);
|
|
26760
|
+
}
|
|
26761
|
+
function formatSessionInfo(info) {
|
|
26762
|
+
const lines = [
|
|
26763
|
+
`Session ID: ${info.id}`,
|
|
26764
|
+
`Messages: ${info.message_count}`,
|
|
26765
|
+
`Date Range: ${info.first_message?.toISOString() ?? "N/A"} to ${info.last_message?.toISOString() ?? "N/A"}`,
|
|
26766
|
+
`Agents Used: ${info.agents_used.join(", ") || "none"}`,
|
|
26767
|
+
`Has Todos: ${info.has_todos ? `Yes (${info.todos?.length ?? 0} items)` : "No"}`,
|
|
26768
|
+
`Has Transcript: ${info.has_transcript ? `Yes (${info.transcript_entries} entries)` : "No"}`
|
|
26769
|
+
];
|
|
26770
|
+
if (info.first_message && info.last_message) {
|
|
26771
|
+
const duration3 = info.last_message.getTime() - info.first_message.getTime();
|
|
26772
|
+
const days = Math.floor(duration3 / (1000 * 60 * 60 * 24));
|
|
26773
|
+
const hours = Math.floor(duration3 % (1000 * 60 * 60 * 24) / (1000 * 60 * 60));
|
|
26774
|
+
if (days > 0 || hours > 0) {
|
|
26775
|
+
lines.push(`Duration: ${days} days, ${hours} hours`);
|
|
26776
|
+
}
|
|
26777
|
+
}
|
|
26778
|
+
return lines.join(`
|
|
26779
|
+
`);
|
|
26780
|
+
}
|
|
26781
|
+
function formatSearchResults(results) {
|
|
26782
|
+
if (results.length === 0) {
|
|
26783
|
+
return "No matches found.";
|
|
26784
|
+
}
|
|
26785
|
+
const lines = [`Found ${results.length} matches:
|
|
26786
|
+
`];
|
|
26787
|
+
for (const result of results) {
|
|
26788
|
+
const timestamp = result.timestamp ? new Date(result.timestamp).toISOString() : "";
|
|
26789
|
+
lines.push(`[${result.session_id}] ${result.message_id} (${result.role}) ${timestamp}`);
|
|
26790
|
+
lines.push(` ${result.excerpt}`);
|
|
26791
|
+
lines.push(` Matches: ${result.match_count}
|
|
26792
|
+
`);
|
|
26793
|
+
}
|
|
26794
|
+
return lines.join(`
|
|
26795
|
+
`);
|
|
26796
|
+
}
|
|
26797
|
+
function filterSessionsByDate(sessionIDs, fromDate, toDate) {
|
|
26798
|
+
if (!fromDate && !toDate)
|
|
26799
|
+
return sessionIDs;
|
|
26800
|
+
const from = fromDate ? new Date(fromDate) : null;
|
|
26801
|
+
const to = toDate ? new Date(toDate) : null;
|
|
26802
|
+
return sessionIDs.filter((id) => {
|
|
26803
|
+
const info = getSessionInfo(id);
|
|
26804
|
+
if (!info || !info.last_message)
|
|
26805
|
+
return false;
|
|
26806
|
+
if (from && info.last_message < from)
|
|
26807
|
+
return false;
|
|
26808
|
+
if (to && info.last_message > to)
|
|
26809
|
+
return false;
|
|
26810
|
+
return true;
|
|
26811
|
+
});
|
|
26812
|
+
}
|
|
26813
|
+
function searchInSession(sessionID, query, caseSensitive = false) {
|
|
26814
|
+
const messages = readSessionMessages(sessionID);
|
|
26815
|
+
const results = [];
|
|
26816
|
+
const searchQuery = caseSensitive ? query : query.toLowerCase();
|
|
26817
|
+
for (const msg of messages) {
|
|
26818
|
+
let matchCount = 0;
|
|
26819
|
+
let excerpts = [];
|
|
26820
|
+
for (const part of msg.parts) {
|
|
26821
|
+
if (part.type === "text" && part.text) {
|
|
26822
|
+
const text = caseSensitive ? part.text : part.text.toLowerCase();
|
|
26823
|
+
const matches = text.split(searchQuery).length - 1;
|
|
26824
|
+
if (matches > 0) {
|
|
26825
|
+
matchCount += matches;
|
|
26826
|
+
const index = text.indexOf(searchQuery);
|
|
26827
|
+
if (index !== -1) {
|
|
26828
|
+
const start = Math.max(0, index - 50);
|
|
26829
|
+
const end = Math.min(text.length, index + searchQuery.length + 50);
|
|
26830
|
+
let excerpt = part.text.substring(start, end);
|
|
26831
|
+
if (start > 0)
|
|
26832
|
+
excerpt = "..." + excerpt;
|
|
26833
|
+
if (end < text.length)
|
|
26834
|
+
excerpt = excerpt + "...";
|
|
26835
|
+
excerpts.push(excerpt);
|
|
26836
|
+
}
|
|
26837
|
+
}
|
|
26838
|
+
}
|
|
26839
|
+
}
|
|
26840
|
+
if (matchCount > 0) {
|
|
26841
|
+
results.push({
|
|
26842
|
+
session_id: sessionID,
|
|
26843
|
+
message_id: msg.id,
|
|
26844
|
+
role: msg.role,
|
|
26845
|
+
excerpt: excerpts[0] || "",
|
|
26846
|
+
match_count: matchCount,
|
|
26847
|
+
timestamp: msg.time?.created
|
|
26848
|
+
});
|
|
26849
|
+
}
|
|
26850
|
+
}
|
|
26851
|
+
return results;
|
|
26852
|
+
}
|
|
26853
|
+
|
|
26854
|
+
// src/tools/session-manager/tools.ts
|
|
26855
|
+
var session_list = tool({
|
|
26856
|
+
description: SESSION_LIST_DESCRIPTION,
|
|
26857
|
+
args: {
|
|
26858
|
+
limit: tool.schema.number().optional().describe("Maximum number of sessions to return"),
|
|
26859
|
+
from_date: tool.schema.string().optional().describe("Filter sessions from this date (ISO 8601 format)"),
|
|
26860
|
+
to_date: tool.schema.string().optional().describe("Filter sessions until this date (ISO 8601 format)")
|
|
26861
|
+
},
|
|
26862
|
+
execute: async (args, _context) => {
|
|
26863
|
+
try {
|
|
26864
|
+
let sessions = getAllSessions();
|
|
26865
|
+
if (args.from_date || args.to_date) {
|
|
26866
|
+
sessions = filterSessionsByDate(sessions, args.from_date, args.to_date);
|
|
26867
|
+
}
|
|
26868
|
+
if (args.limit && args.limit > 0) {
|
|
26869
|
+
sessions = sessions.slice(0, args.limit);
|
|
26870
|
+
}
|
|
26871
|
+
return formatSessionList(sessions);
|
|
26872
|
+
} catch (e) {
|
|
26873
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
26874
|
+
}
|
|
26875
|
+
}
|
|
26876
|
+
});
|
|
26877
|
+
var session_read = tool({
|
|
26878
|
+
description: SESSION_READ_DESCRIPTION,
|
|
26879
|
+
args: {
|
|
26880
|
+
session_id: tool.schema.string().describe("Session ID to read"),
|
|
26881
|
+
include_todos: tool.schema.boolean().optional().describe("Include todo list if available (default: false)"),
|
|
26882
|
+
include_transcript: tool.schema.boolean().optional().describe("Include transcript log if available (default: false)"),
|
|
26883
|
+
limit: tool.schema.number().optional().describe("Maximum number of messages to return (default: all)")
|
|
26884
|
+
},
|
|
26885
|
+
execute: async (args, _context) => {
|
|
26886
|
+
try {
|
|
26887
|
+
if (!sessionExists(args.session_id)) {
|
|
26888
|
+
return `Session not found: ${args.session_id}`;
|
|
26889
|
+
}
|
|
26890
|
+
let messages = readSessionMessages(args.session_id);
|
|
26891
|
+
if (args.limit && args.limit > 0) {
|
|
26892
|
+
messages = messages.slice(0, args.limit);
|
|
26893
|
+
}
|
|
26894
|
+
const todos = args.include_todos ? readSessionTodos(args.session_id) : undefined;
|
|
26895
|
+
return formatSessionMessages(messages, args.include_todos, todos);
|
|
26896
|
+
} catch (e) {
|
|
26897
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
26898
|
+
}
|
|
26899
|
+
}
|
|
26900
|
+
});
|
|
26901
|
+
var session_search = tool({
|
|
26902
|
+
description: SESSION_SEARCH_DESCRIPTION,
|
|
26903
|
+
args: {
|
|
26904
|
+
query: tool.schema.string().describe("Search query string"),
|
|
26905
|
+
session_id: tool.schema.string().optional().describe("Search within specific session only (default: all sessions)"),
|
|
26906
|
+
case_sensitive: tool.schema.boolean().optional().describe("Case-sensitive search (default: false)"),
|
|
26907
|
+
limit: tool.schema.number().optional().describe("Maximum number of results to return (default: 20)")
|
|
26908
|
+
},
|
|
26909
|
+
execute: async (args, _context) => {
|
|
26910
|
+
try {
|
|
26911
|
+
const sessions = args.session_id ? [args.session_id] : getAllSessions();
|
|
26912
|
+
const allResults = sessions.flatMap((sid) => searchInSession(sid, args.query, args.case_sensitive));
|
|
26913
|
+
const limited = args.limit && args.limit > 0 ? allResults.slice(0, args.limit) : allResults.slice(0, 20);
|
|
26914
|
+
return formatSearchResults(limited);
|
|
26915
|
+
} catch (e) {
|
|
26916
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
26917
|
+
}
|
|
26918
|
+
}
|
|
26919
|
+
});
|
|
26920
|
+
var session_info = tool({
|
|
26921
|
+
description: SESSION_INFO_DESCRIPTION,
|
|
26922
|
+
args: {
|
|
26923
|
+
session_id: tool.schema.string().describe("Session ID to inspect")
|
|
26924
|
+
},
|
|
26925
|
+
execute: async (args, _context) => {
|
|
26926
|
+
try {
|
|
26927
|
+
const info = getSessionInfo(args.session_id);
|
|
26928
|
+
if (!info) {
|
|
26929
|
+
return `Session not found: ${args.session_id}`;
|
|
26930
|
+
}
|
|
26931
|
+
return formatSessionInfo(info);
|
|
26932
|
+
} catch (e) {
|
|
26933
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
26934
|
+
}
|
|
26935
|
+
}
|
|
26936
|
+
});
|
|
26448
26937
|
// src/tools/interactive-bash/constants.ts
|
|
26449
26938
|
var DEFAULT_TIMEOUT_MS4 = 60000;
|
|
26450
26939
|
var BLOCKED_TMUX_SUBCOMMANDS = [
|
|
@@ -26478,12 +26967,12 @@ async function findTmuxPath() {
|
|
|
26478
26967
|
return null;
|
|
26479
26968
|
}
|
|
26480
26969
|
const stdout = await new Response(proc.stdout).text();
|
|
26481
|
-
const
|
|
26970
|
+
const path8 = stdout.trim().split(`
|
|
26482
26971
|
`)[0];
|
|
26483
|
-
if (!
|
|
26972
|
+
if (!path8) {
|
|
26484
26973
|
return null;
|
|
26485
26974
|
}
|
|
26486
|
-
const verifyProc = spawn9([
|
|
26975
|
+
const verifyProc = spawn9([path8, "-V"], {
|
|
26487
26976
|
stdout: "pipe",
|
|
26488
26977
|
stderr: "pipe"
|
|
26489
26978
|
});
|
|
@@ -26491,7 +26980,7 @@ async function findTmuxPath() {
|
|
|
26491
26980
|
if (verifyExitCode !== 0) {
|
|
26492
26981
|
return null;
|
|
26493
26982
|
}
|
|
26494
|
-
return
|
|
26983
|
+
return path8;
|
|
26495
26984
|
} catch {
|
|
26496
26985
|
return null;
|
|
26497
26986
|
}
|
|
@@ -26504,9 +26993,9 @@ async function getTmuxPath() {
|
|
|
26504
26993
|
return initPromise3;
|
|
26505
26994
|
}
|
|
26506
26995
|
initPromise3 = (async () => {
|
|
26507
|
-
const
|
|
26508
|
-
tmuxPath =
|
|
26509
|
-
return
|
|
26996
|
+
const path8 = await findTmuxPath();
|
|
26997
|
+
tmuxPath = path8;
|
|
26998
|
+
return path8;
|
|
26510
26999
|
})();
|
|
26511
27000
|
return initPromise3;
|
|
26512
27001
|
}
|
|
@@ -27145,20 +27634,24 @@ var builtinTools = {
|
|
|
27145
27634
|
ast_grep_replace,
|
|
27146
27635
|
grep,
|
|
27147
27636
|
glob,
|
|
27148
|
-
slashcommand
|
|
27637
|
+
slashcommand,
|
|
27638
|
+
session_list,
|
|
27639
|
+
session_read,
|
|
27640
|
+
session_search,
|
|
27641
|
+
session_info
|
|
27149
27642
|
};
|
|
27150
27643
|
// src/features/background-agent/manager.ts
|
|
27151
|
-
import { existsSync as
|
|
27152
|
-
import { join as
|
|
27153
|
-
function
|
|
27154
|
-
if (!
|
|
27644
|
+
import { existsSync as existsSync38, readdirSync as readdirSync13 } from "fs";
|
|
27645
|
+
import { join as join47 } from "path";
|
|
27646
|
+
function getMessageDir6(sessionID) {
|
|
27647
|
+
if (!existsSync38(MESSAGE_STORAGE))
|
|
27155
27648
|
return null;
|
|
27156
|
-
const directPath =
|
|
27157
|
-
if (
|
|
27649
|
+
const directPath = join47(MESSAGE_STORAGE, sessionID);
|
|
27650
|
+
if (existsSync38(directPath))
|
|
27158
27651
|
return directPath;
|
|
27159
|
-
for (const dir of
|
|
27160
|
-
const sessionPath =
|
|
27161
|
-
if (
|
|
27652
|
+
for (const dir of readdirSync13(MESSAGE_STORAGE)) {
|
|
27653
|
+
const sessionPath = join47(MESSAGE_STORAGE, dir, sessionID);
|
|
27654
|
+
if (existsSync38(sessionPath))
|
|
27162
27655
|
return sessionPath;
|
|
27163
27656
|
}
|
|
27164
27657
|
return null;
|
|
@@ -27394,7 +27887,7 @@ class BackgroundManager {
|
|
|
27394
27887
|
log("[background-agent] Sending notification to parent session:", { parentSessionID: task.parentSessionID });
|
|
27395
27888
|
setTimeout(async () => {
|
|
27396
27889
|
try {
|
|
27397
|
-
const messageDir =
|
|
27890
|
+
const messageDir = getMessageDir6(task.parentSessionID);
|
|
27398
27891
|
const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
|
|
27399
27892
|
await this.client.session.prompt({
|
|
27400
27893
|
path: { id: task.parentSessionID },
|
|
@@ -27562,6 +28055,7 @@ var OverridableAgentNameSchema = exports_external.enum([
|
|
|
27562
28055
|
"build",
|
|
27563
28056
|
"plan",
|
|
27564
28057
|
"Sisyphus",
|
|
28058
|
+
"Builder-Sisyphus",
|
|
27565
28059
|
"Planner-Sisyphus",
|
|
27566
28060
|
"oracle",
|
|
27567
28061
|
"librarian",
|
|
@@ -27610,6 +28104,7 @@ var AgentOverridesSchema = exports_external.object({
|
|
|
27610
28104
|
build: AgentOverrideConfigSchema.optional(),
|
|
27611
28105
|
plan: AgentOverrideConfigSchema.optional(),
|
|
27612
28106
|
Sisyphus: AgentOverrideConfigSchema.optional(),
|
|
28107
|
+
"Builder-Sisyphus": AgentOverrideConfigSchema.optional(),
|
|
27613
28108
|
"Planner-Sisyphus": AgentOverrideConfigSchema.optional(),
|
|
27614
28109
|
oracle: AgentOverrideConfigSchema.optional(),
|
|
27615
28110
|
librarian: AgentOverrideConfigSchema.optional(),
|
|
@@ -27626,14 +28121,18 @@ var ClaudeCodeConfigSchema = exports_external.object({
|
|
|
27626
28121
|
hooks: exports_external.boolean().optional()
|
|
27627
28122
|
});
|
|
27628
28123
|
var SisyphusAgentConfigSchema = exports_external.object({
|
|
27629
|
-
disabled: exports_external.boolean().optional()
|
|
28124
|
+
disabled: exports_external.boolean().optional(),
|
|
28125
|
+
builder_enabled: exports_external.boolean().optional(),
|
|
28126
|
+
planner_enabled: exports_external.boolean().optional(),
|
|
28127
|
+
replace_build: exports_external.boolean().optional(),
|
|
28128
|
+
replace_plan: exports_external.boolean().optional()
|
|
27630
28129
|
});
|
|
27631
28130
|
var ExperimentalConfigSchema = exports_external.object({
|
|
27632
28131
|
aggressive_truncation: exports_external.boolean().optional(),
|
|
27633
28132
|
auto_resume: exports_external.boolean().optional(),
|
|
27634
28133
|
preemptive_compaction: exports_external.boolean().optional(),
|
|
27635
28134
|
preemptive_compaction_threshold: exports_external.number().min(0.5).max(0.95).optional(),
|
|
27636
|
-
truncate_all_tool_outputs: exports_external.boolean().
|
|
28135
|
+
truncate_all_tool_outputs: exports_external.boolean().default(true)
|
|
27637
28136
|
});
|
|
27638
28137
|
var OhMyOpenCodeConfigSchema = exports_external.object({
|
|
27639
28138
|
$schema: exports_external.string().optional(),
|
|
@@ -27718,9 +28217,53 @@ var PLAN_PERMISSION = {
|
|
|
27718
28217
|
webfetch: "allow"
|
|
27719
28218
|
};
|
|
27720
28219
|
|
|
28220
|
+
// src/agents/build-prompt.ts
|
|
28221
|
+
var BUILD_SYSTEM_PROMPT = `<system-reminder>
|
|
28222
|
+
# Build Mode - System Reminder
|
|
28223
|
+
|
|
28224
|
+
BUILD MODE ACTIVE - you are in EXECUTION phase. Your responsibility is to:
|
|
28225
|
+
- Implement features and make code changes
|
|
28226
|
+
- Execute commands and run tests
|
|
28227
|
+
- Fix bugs and refactor code
|
|
28228
|
+
- Deploy and build systems
|
|
28229
|
+
- Make all necessary file modifications
|
|
28230
|
+
|
|
28231
|
+
You have FULL permissions to edit files, run commands, and make system changes.
|
|
28232
|
+
This is the implementation phase - execute decisively and thoroughly.
|
|
28233
|
+
|
|
28234
|
+
---
|
|
28235
|
+
|
|
28236
|
+
## Responsibility
|
|
28237
|
+
|
|
28238
|
+
Your current responsibility is to implement, build, and execute. You should:
|
|
28239
|
+
- Write and modify code to accomplish the user's goals
|
|
28240
|
+
- Run tests and builds to verify your changes
|
|
28241
|
+
- Fix errors and issues that arise
|
|
28242
|
+
- Use all available tools to complete the task efficiently
|
|
28243
|
+
- Delegate to specialized agents when appropriate for better results
|
|
28244
|
+
|
|
28245
|
+
**NOTE:** You should ask the user for clarification when requirements are ambiguous,
|
|
28246
|
+
but once the path is clear, execute confidently. The goal is to deliver working,
|
|
28247
|
+
tested, production-ready solutions.
|
|
28248
|
+
|
|
28249
|
+
---
|
|
28250
|
+
|
|
28251
|
+
## Important
|
|
28252
|
+
|
|
28253
|
+
The user wants you to execute and implement. You SHOULD make edits, run necessary
|
|
28254
|
+
tools, and make changes to accomplish the task. Use your full capabilities to
|
|
28255
|
+
deliver excellent results.
|
|
28256
|
+
</system-reminder>
|
|
28257
|
+
`;
|
|
28258
|
+
var BUILD_PERMISSION = {
|
|
28259
|
+
edit: "ask",
|
|
28260
|
+
bash: "ask",
|
|
28261
|
+
webfetch: "allow"
|
|
28262
|
+
};
|
|
28263
|
+
|
|
27721
28264
|
// src/index.ts
|
|
27722
28265
|
import * as fs7 from "fs";
|
|
27723
|
-
import * as
|
|
28266
|
+
import * as path8 from "path";
|
|
27724
28267
|
var AGENT_NAME_MAP = {
|
|
27725
28268
|
omo: "Sisyphus",
|
|
27726
28269
|
OmO: "Sisyphus",
|
|
@@ -27823,8 +28366,8 @@ function mergeConfigs(base, override) {
|
|
|
27823
28366
|
};
|
|
27824
28367
|
}
|
|
27825
28368
|
function loadPluginConfig(directory) {
|
|
27826
|
-
const userConfigPath =
|
|
27827
|
-
const projectConfigPath =
|
|
28369
|
+
const userConfigPath = path8.join(getUserConfigDir(), "opencode", "oh-my-opencode.json");
|
|
28370
|
+
const projectConfigPath = path8.join(directory, ".opencode", "oh-my-opencode.json");
|
|
27828
28371
|
let config3 = loadConfigFromPath2(userConfigPath) ?? {};
|
|
27829
28372
|
const projectConfig = loadConfigFromPath2(projectConfigPath);
|
|
27830
28373
|
if (projectConfig) {
|
|
@@ -27934,26 +28477,46 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
27934
28477
|
const userAgents = pluginConfig.claude_code?.agents ?? true ? loadUserAgents() : {};
|
|
27935
28478
|
const projectAgents = pluginConfig.claude_code?.agents ?? true ? loadProjectAgents() : {};
|
|
27936
28479
|
const isSisyphusEnabled = pluginConfig.sisyphus_agent?.disabled !== true;
|
|
28480
|
+
const builderEnabled = pluginConfig.sisyphus_agent?.builder_enabled ?? false;
|
|
28481
|
+
const plannerEnabled = pluginConfig.sisyphus_agent?.planner_enabled ?? true;
|
|
28482
|
+
const replaceBuild = pluginConfig.sisyphus_agent?.replace_build ?? true;
|
|
28483
|
+
const replacePlan = pluginConfig.sisyphus_agent?.replace_plan ?? true;
|
|
27937
28484
|
if (isSisyphusEnabled && builtinAgents.Sisyphus) {
|
|
27938
|
-
const
|
|
27939
|
-
|
|
27940
|
-
const plannerSisyphusBase = {
|
|
27941
|
-
...planConfigWithoutName,
|
|
27942
|
-
prompt: PLAN_SYSTEM_PROMPT,
|
|
27943
|
-
permission: PLAN_PERMISSION,
|
|
27944
|
-
description: `${config3.agent?.plan?.description ?? "Plan agent"} (OhMyOpenCode version)`,
|
|
27945
|
-
color: config3.agent?.plan?.color ?? "#6495ED"
|
|
28485
|
+
const agentConfig = {
|
|
28486
|
+
Sisyphus: builtinAgents.Sisyphus
|
|
27946
28487
|
};
|
|
27947
|
-
|
|
28488
|
+
if (builderEnabled) {
|
|
28489
|
+
const { name: _buildName, ...buildConfigWithoutName } = config3.agent?.build ?? {};
|
|
28490
|
+
const builderSisyphusOverride = pluginConfig.agents?.["Builder-Sisyphus"];
|
|
28491
|
+
const builderSisyphusBase = {
|
|
28492
|
+
...buildConfigWithoutName,
|
|
28493
|
+
prompt: BUILD_SYSTEM_PROMPT,
|
|
28494
|
+
permission: BUILD_PERMISSION,
|
|
28495
|
+
description: `${config3.agent?.build?.description ?? "Build agent"} (OhMyOpenCode version)`,
|
|
28496
|
+
color: config3.agent?.build?.color ?? "#32CD32"
|
|
28497
|
+
};
|
|
28498
|
+
agentConfig["Builder-Sisyphus"] = builderSisyphusOverride ? { ...builderSisyphusBase, ...builderSisyphusOverride } : builderSisyphusBase;
|
|
28499
|
+
}
|
|
28500
|
+
if (plannerEnabled) {
|
|
28501
|
+
const { name: _planName, ...planConfigWithoutName } = config3.agent?.plan ?? {};
|
|
28502
|
+
const plannerSisyphusOverride = pluginConfig.agents?.["Planner-Sisyphus"];
|
|
28503
|
+
const plannerSisyphusBase = {
|
|
28504
|
+
...planConfigWithoutName,
|
|
28505
|
+
prompt: PLAN_SYSTEM_PROMPT,
|
|
28506
|
+
permission: PLAN_PERMISSION,
|
|
28507
|
+
description: `${config3.agent?.plan?.description ?? "Plan agent"} (OhMyOpenCode version)`,
|
|
28508
|
+
color: config3.agent?.plan?.color ?? "#6495ED"
|
|
28509
|
+
};
|
|
28510
|
+
agentConfig["Planner-Sisyphus"] = plannerSisyphusOverride ? { ...plannerSisyphusBase, ...plannerSisyphusOverride } : plannerSisyphusBase;
|
|
28511
|
+
}
|
|
27948
28512
|
config3.agent = {
|
|
27949
|
-
|
|
27950
|
-
"Planner-Sisyphus": plannerSisyphusConfig,
|
|
28513
|
+
...agentConfig,
|
|
27951
28514
|
...Object.fromEntries(Object.entries(builtinAgents).filter(([k]) => k !== "Sisyphus")),
|
|
27952
28515
|
...userAgents,
|
|
27953
28516
|
...projectAgents,
|
|
27954
28517
|
...config3.agent,
|
|
27955
|
-
build: { ...config3.agent?.build, mode: "subagent" },
|
|
27956
|
-
plan: { ...config3.agent?.plan, mode: "subagent" }
|
|
28518
|
+
...replaceBuild ? { build: { ...config3.agent?.build, mode: "subagent" } } : {},
|
|
28519
|
+
...replacePlan ? { plan: { ...config3.agent?.plan, mode: "subagent" } } : {}
|
|
27957
28520
|
};
|
|
27958
28521
|
} else {
|
|
27959
28522
|
config3.agent = {
|