@khalilgharbaoui/opencode-claude-code-plugin 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +96 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15,6 +15,9 @@ var log = {
|
|
|
15
15
|
info(msg, data) {
|
|
16
16
|
if (DEBUG) console.error(fmt("INFO", msg, data));
|
|
17
17
|
},
|
|
18
|
+
notice(msg, data) {
|
|
19
|
+
console.error(fmt("NOTICE", msg, data));
|
|
20
|
+
},
|
|
18
21
|
warn(msg, data) {
|
|
19
22
|
if (DEBUG) console.error(fmt("WARN", msg, data));
|
|
20
23
|
},
|
|
@@ -711,6 +714,7 @@ async function getRuntimeMcpStatus() {
|
|
|
711
714
|
import { spawn } from "child_process";
|
|
712
715
|
import { createInterface } from "readline";
|
|
713
716
|
import { EventEmitter } from "events";
|
|
717
|
+
import { unlink } from "fs/promises";
|
|
714
718
|
var activeProcesses = /* @__PURE__ */ new Map();
|
|
715
719
|
var claudeSessions = /* @__PURE__ */ new Map();
|
|
716
720
|
var MAX_ACTIVE_PROCESSES = 16;
|
|
@@ -751,7 +755,7 @@ function setClaudeSessionId(key, sessionId) {
|
|
|
751
755
|
function deleteClaudeSessionId(key) {
|
|
752
756
|
claudeSessions.delete(key);
|
|
753
757
|
}
|
|
754
|
-
function spawnClaudeProcess(cliPath, cliArgs, cwd, sessionKey2, proxyServer, mcpHash) {
|
|
758
|
+
function spawnClaudeProcess(cliPath, cliArgs, cwd, sessionKey2, proxyServer, mcpHash, systemPromptFile) {
|
|
755
759
|
evictIfNeeded();
|
|
756
760
|
log.info("spawning new claude process", { cliPath, cliArgs, cwd, sessionKey: sessionKey2 });
|
|
757
761
|
const proc = spawn(cliPath, cliArgs, {
|
|
@@ -772,7 +776,8 @@ function spawnClaudeProcess(cliPath, cliArgs, cwd, sessionKey2, proxyServer, mcp
|
|
|
772
776
|
proc,
|
|
773
777
|
lineEmitter,
|
|
774
778
|
proxyServer: proxyServer ?? null,
|
|
775
|
-
mcpHash
|
|
779
|
+
mcpHash,
|
|
780
|
+
systemPromptFile
|
|
776
781
|
};
|
|
777
782
|
activeProcesses.set(sessionKey2, ap);
|
|
778
783
|
proc.on("error", (err) => {
|
|
@@ -781,6 +786,10 @@ function spawnClaudeProcess(cliPath, cliArgs, cwd, sessionKey2, proxyServer, mcp
|
|
|
781
786
|
proc.on("exit", (code, signal) => {
|
|
782
787
|
log.info("claude process exited", { code, signal, sessionKey: sessionKey2 });
|
|
783
788
|
void proxyServer?.close();
|
|
789
|
+
if (systemPromptFile) {
|
|
790
|
+
void unlink(systemPromptFile).catch(() => {
|
|
791
|
+
});
|
|
792
|
+
}
|
|
784
793
|
activeProcesses.delete(sessionKey2);
|
|
785
794
|
if (code !== 0 && code !== null) {
|
|
786
795
|
log.info("process exited with error, clearing session", {
|
|
@@ -812,7 +821,8 @@ function buildCliArgs(opts) {
|
|
|
812
821
|
permissionMode,
|
|
813
822
|
mcpConfig,
|
|
814
823
|
strictMcpConfig,
|
|
815
|
-
disallowedTools
|
|
824
|
+
disallowedTools,
|
|
825
|
+
appendSystemPromptFile
|
|
816
826
|
} = opts;
|
|
817
827
|
const args = [
|
|
818
828
|
"--output-format",
|
|
@@ -846,6 +856,9 @@ function buildCliArgs(opts) {
|
|
|
846
856
|
if (disallowedTools && disallowedTools.length > 0) {
|
|
847
857
|
args.push("--disallowedTools", ...disallowedTools);
|
|
848
858
|
}
|
|
859
|
+
if (appendSystemPromptFile) {
|
|
860
|
+
args.push("--append-system-prompt-file", appendSystemPromptFile);
|
|
861
|
+
}
|
|
849
862
|
if (skipPermissions) {
|
|
850
863
|
args.push("--dangerously-skip-permissions");
|
|
851
864
|
}
|
|
@@ -1243,6 +1256,47 @@ function resolvePendingProxyCall(sessionKey2, result) {
|
|
|
1243
1256
|
}
|
|
1244
1257
|
|
|
1245
1258
|
// src/claude-code-language-model.ts
|
|
1259
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
1260
|
+
import { unlink as unlink2 } from "fs/promises";
|
|
1261
|
+
import { homedir as homedir2, tmpdir as tmpdir3 } from "os";
|
|
1262
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
1263
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
1264
|
+
function readPromptFileIfPresent(path4) {
|
|
1265
|
+
try {
|
|
1266
|
+
const content = readFileSync2(path4, "utf8").trim();
|
|
1267
|
+
return content || void 0;
|
|
1268
|
+
} catch {
|
|
1269
|
+
return void 0;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
function nearestWorkspaceAgentsPrompt(cwd) {
|
|
1273
|
+
let dir = cwd;
|
|
1274
|
+
while (true) {
|
|
1275
|
+
const content = readPromptFileIfPresent(join3(dir, "AGENTS.md"));
|
|
1276
|
+
if (content) return content;
|
|
1277
|
+
const parent = dirname2(dir);
|
|
1278
|
+
if (parent === dir) return void 0;
|
|
1279
|
+
dir = parent;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
function buildAppendedSystemPrompt(cwd) {
|
|
1283
|
+
const parts = [];
|
|
1284
|
+
const configRoot = process.env.XDG_CONFIG_HOME ?? join3(homedir2(), ".config");
|
|
1285
|
+
const globalAgents = readPromptFileIfPresent(join3(configRoot, "opencode", "AGENTS.md"));
|
|
1286
|
+
const workspaceAgents = nearestWorkspaceAgentsPrompt(cwd);
|
|
1287
|
+
if (globalAgents) parts.push(globalAgents);
|
|
1288
|
+
if (workspaceAgents && workspaceAgents !== globalAgents) parts.push(workspaceAgents);
|
|
1289
|
+
const content = parts.join("\n\n");
|
|
1290
|
+
if (!content) return void 0;
|
|
1291
|
+
const path4 = join3(tmpdir3(), `opencode-cc-sys-${randomUUID2()}.md`);
|
|
1292
|
+
try {
|
|
1293
|
+
writeFileSync3(path4, content, "utf8");
|
|
1294
|
+
return path4;
|
|
1295
|
+
} catch (err) {
|
|
1296
|
+
log.warn("failed to write system prompt file", { error: String(err) });
|
|
1297
|
+
return void 0;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1246
1300
|
var ClaudeCodeLanguageModel = class {
|
|
1247
1301
|
specificationVersion = "v3";
|
|
1248
1302
|
modelId;
|
|
@@ -1646,6 +1700,7 @@ var ClaudeCodeLanguageModel = class {
|
|
|
1646
1700
|
reasoningEffort
|
|
1647
1701
|
);
|
|
1648
1702
|
const runtimeStatus = await getRuntimeMcpStatus();
|
|
1703
|
+
const systemPromptFile = buildAppendedSystemPrompt(cwd);
|
|
1649
1704
|
const cliArgs = buildCliArgs({
|
|
1650
1705
|
sessionKey: sk,
|
|
1651
1706
|
skipPermissions: this.config.skipPermissions !== false,
|
|
@@ -1654,7 +1709,8 @@ var ClaudeCodeLanguageModel = class {
|
|
|
1654
1709
|
permissionMode: this.config.permissionMode,
|
|
1655
1710
|
mcpConfig: this.effectiveMcpConfig(cwd, void 0, runtimeStatus).paths,
|
|
1656
1711
|
strictMcpConfig: this.config.strictMcpConfig,
|
|
1657
|
-
disallowedTools: this.config.webSearch === "disabled" ? ["WebSearch"] : void 0
|
|
1712
|
+
disallowedTools: this.config.webSearch === "disabled" ? ["WebSearch"] : void 0,
|
|
1713
|
+
appendSystemPromptFile: systemPromptFile
|
|
1658
1714
|
});
|
|
1659
1715
|
log.info("doGenerate starting", {
|
|
1660
1716
|
cwd,
|
|
@@ -1670,6 +1726,12 @@ var ClaudeCodeLanguageModel = class {
|
|
|
1670
1726
|
env: { ...process.env, TERM: "xterm-256color" },
|
|
1671
1727
|
shell: process.platform === "win32"
|
|
1672
1728
|
});
|
|
1729
|
+
if (systemPromptFile) {
|
|
1730
|
+
proc.on("exit", () => {
|
|
1731
|
+
void unlink2(systemPromptFile).catch(() => {
|
|
1732
|
+
});
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1673
1735
|
const rl = createInterface2({ input: proc.stdout });
|
|
1674
1736
|
let responseText = "";
|
|
1675
1737
|
let thinkingText = "";
|
|
@@ -1968,6 +2030,7 @@ ${plan}
|
|
|
1968
2030
|
proxyServer?.configPath(),
|
|
1969
2031
|
runtimeStatus
|
|
1970
2032
|
);
|
|
2033
|
+
const systemPromptFile = activeProcess ? void 0 : buildAppendedSystemPrompt(cwd);
|
|
1971
2034
|
const cliArgs = buildCliArgs({
|
|
1972
2035
|
sessionKey: sk,
|
|
1973
2036
|
skipPermissions,
|
|
@@ -1975,7 +2038,8 @@ ${plan}
|
|
|
1975
2038
|
permissionMode: self.config.permissionMode,
|
|
1976
2039
|
mcpConfig: mcp.paths,
|
|
1977
2040
|
strictMcpConfig: self.config.strictMcpConfig,
|
|
1978
|
-
disallowedTools: allDisallowed.length > 0 ? allDisallowed : void 0
|
|
2041
|
+
disallowedTools: allDisallowed.length > 0 ? allDisallowed : void 0,
|
|
2042
|
+
appendSystemPromptFile: systemPromptFile
|
|
1979
2043
|
});
|
|
1980
2044
|
if (activeProcess) {
|
|
1981
2045
|
proc = activeProcess.proc;
|
|
@@ -1988,7 +2052,8 @@ ${plan}
|
|
|
1988
2052
|
cwd,
|
|
1989
2053
|
sk,
|
|
1990
2054
|
proxyServer,
|
|
1991
|
-
mcp.bridgedHash
|
|
2055
|
+
mcp.bridgedHash,
|
|
2056
|
+
systemPromptFile
|
|
1992
2057
|
);
|
|
1993
2058
|
proc = ap.proc;
|
|
1994
2059
|
lineEmitter = ap.lineEmitter;
|
|
@@ -2895,13 +2960,13 @@ function titleizeAccount(account) {
|
|
|
2895
2960
|
// src/cleanup-stale.ts
|
|
2896
2961
|
import {
|
|
2897
2962
|
existsSync as existsSync2,
|
|
2898
|
-
readFileSync as
|
|
2963
|
+
readFileSync as readFileSync3,
|
|
2899
2964
|
realpathSync,
|
|
2900
2965
|
rmSync,
|
|
2901
|
-
writeFileSync as
|
|
2966
|
+
writeFileSync as writeFileSync4
|
|
2902
2967
|
} from "fs";
|
|
2903
|
-
import { homedir as
|
|
2904
|
-
import { join as
|
|
2968
|
+
import { homedir as homedir3 } from "os";
|
|
2969
|
+
import { join as join4, resolve as resolve2 } from "path";
|
|
2905
2970
|
import { fileURLToPath } from "url";
|
|
2906
2971
|
var STALE_PACKAGE_NAME = "opencode-claude-code-plugin";
|
|
2907
2972
|
var SUSPECT_DESCRIPTION_TOKEN = "Claude Code";
|
|
@@ -2909,20 +2974,20 @@ var alreadyRan = false;
|
|
|
2909
2974
|
function candidateCacheRoots() {
|
|
2910
2975
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
2911
2976
|
return [
|
|
2912
|
-
xdg ?
|
|
2913
|
-
|
|
2914
|
-
|
|
2977
|
+
xdg ? join4(xdg, "opencode") : null,
|
|
2978
|
+
join4(homedir3(), ".cache", "opencode"),
|
|
2979
|
+
join4(homedir3(), "Library", "Caches", "opencode")
|
|
2915
2980
|
].filter((p) => Boolean(p));
|
|
2916
2981
|
}
|
|
2917
2982
|
function userOpencodeJsonPath() {
|
|
2918
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ??
|
|
2919
|
-
return
|
|
2983
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join4(homedir3(), ".config");
|
|
2984
|
+
return join4(xdgConfig, "opencode", "opencode.json");
|
|
2920
2985
|
}
|
|
2921
2986
|
function userIntendsToUseUnscoped() {
|
|
2922
2987
|
const cfg = userOpencodeJsonPath();
|
|
2923
2988
|
if (!existsSync2(cfg)) return false;
|
|
2924
2989
|
try {
|
|
2925
|
-
const json = JSON.parse(
|
|
2990
|
+
const json = JSON.parse(readFileSync3(cfg, "utf8"));
|
|
2926
2991
|
const plugins = json.plugin;
|
|
2927
2992
|
if (!Array.isArray(plugins)) return false;
|
|
2928
2993
|
return plugins.some(
|
|
@@ -2959,7 +3024,7 @@ function cleanupStaleUnscopedInstall() {
|
|
|
2959
3024
|
}
|
|
2960
3025
|
function cleanupOne(cacheRoot, ourDir) {
|
|
2961
3026
|
if (!existsSync2(cacheRoot)) return;
|
|
2962
|
-
const stalePath =
|
|
3027
|
+
const stalePath = join4(cacheRoot, "node_modules", STALE_PACKAGE_NAME);
|
|
2963
3028
|
if (!existsSync2(stalePath)) return;
|
|
2964
3029
|
let realStalePath = stalePath;
|
|
2965
3030
|
try {
|
|
@@ -2967,11 +3032,11 @@ function cleanupOne(cacheRoot, ourDir) {
|
|
|
2967
3032
|
} catch {
|
|
2968
3033
|
}
|
|
2969
3034
|
if (ourDir && realStalePath === ourDir) return;
|
|
2970
|
-
const pkgJsonPath =
|
|
3035
|
+
const pkgJsonPath = join4(stalePath, "package.json");
|
|
2971
3036
|
if (!existsSync2(pkgJsonPath)) return;
|
|
2972
3037
|
let pkg = {};
|
|
2973
3038
|
try {
|
|
2974
|
-
pkg = JSON.parse(
|
|
3039
|
+
pkg = JSON.parse(readFileSync3(pkgJsonPath, "utf8"));
|
|
2975
3040
|
} catch {
|
|
2976
3041
|
return;
|
|
2977
3042
|
}
|
|
@@ -2987,13 +3052,13 @@ function cleanupOne(cacheRoot, ourDir) {
|
|
|
2987
3052
|
});
|
|
2988
3053
|
return;
|
|
2989
3054
|
}
|
|
2990
|
-
const cachePkgJson =
|
|
3055
|
+
const cachePkgJson = join4(cacheRoot, "package.json");
|
|
2991
3056
|
if (!existsSync2(cachePkgJson)) return;
|
|
2992
3057
|
try {
|
|
2993
|
-
const cfg = JSON.parse(
|
|
3058
|
+
const cfg = JSON.parse(readFileSync3(cachePkgJson, "utf8"));
|
|
2994
3059
|
if (cfg?.dependencies?.[STALE_PACKAGE_NAME]) {
|
|
2995
3060
|
delete cfg.dependencies[STALE_PACKAGE_NAME];
|
|
2996
|
-
|
|
3061
|
+
writeFileSync4(cachePkgJson, JSON.stringify(cfg, null, 2) + "\n");
|
|
2997
3062
|
log.info("cleanup-stale: pruned dep from cache package.json");
|
|
2998
3063
|
}
|
|
2999
3064
|
} catch (err) {
|
|
@@ -3191,12 +3256,20 @@ var server = async (input) => {
|
|
|
3191
3256
|
config: async (config) => {
|
|
3192
3257
|
config.provider ??= {};
|
|
3193
3258
|
const expanded = await expandAccountProviders(config);
|
|
3194
|
-
if (expanded)
|
|
3259
|
+
if (expanded) {
|
|
3260
|
+
const registered = Object.entries(config.provider).filter(([id]) => id === PROVIDER_ID2 || id.startsWith(`${PROVIDER_ID2}-`)).map(([id, p]) => ({ id, name: p?.name ?? id }));
|
|
3261
|
+
log.notice("registered claude-code providers", { providers: registered });
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
3195
3264
|
const existing = config.provider[PROVIDER_ID2];
|
|
3196
3265
|
config.provider[PROVIDER_ID2] = {
|
|
3197
3266
|
...existing,
|
|
3198
3267
|
...await providerConfig(existing)
|
|
3199
3268
|
};
|
|
3269
|
+
log.notice("registered claude-code provider", {
|
|
3270
|
+
id: PROVIDER_ID2,
|
|
3271
|
+
name: config.provider[PROVIDER_ID2]?.name ?? PROVIDER_ID2
|
|
3272
|
+
});
|
|
3200
3273
|
},
|
|
3201
3274
|
// No `event` hook: MCP config drift is detected at turn start by the
|
|
3202
3275
|
// hot-reload check in `claude-code-language-model.ts`, which respawns
|