@khalilgharbaoui/opencode-claude-code-plugin 0.2.1 → 0.2.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/dist/index.js +96 -24
- 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;
|
|
@@ -2674,7 +2739,6 @@ function toConfigModel(model) {
|
|
|
2674
2739
|
attachment: model.capabilities.attachment,
|
|
2675
2740
|
tool_call: model.capabilities.toolcall,
|
|
2676
2741
|
modalities: { input: inputMods, output: outputMods },
|
|
2677
|
-
interleaved: model.capabilities.interleaved,
|
|
2678
2742
|
cost: {
|
|
2679
2743
|
input: model.cost.input,
|
|
2680
2744
|
output: model.cost.output,
|
|
@@ -2895,13 +2959,13 @@ function titleizeAccount(account) {
|
|
|
2895
2959
|
// src/cleanup-stale.ts
|
|
2896
2960
|
import {
|
|
2897
2961
|
existsSync as existsSync2,
|
|
2898
|
-
readFileSync as
|
|
2962
|
+
readFileSync as readFileSync3,
|
|
2899
2963
|
realpathSync,
|
|
2900
2964
|
rmSync,
|
|
2901
|
-
writeFileSync as
|
|
2965
|
+
writeFileSync as writeFileSync4
|
|
2902
2966
|
} from "fs";
|
|
2903
|
-
import { homedir as
|
|
2904
|
-
import { join as
|
|
2967
|
+
import { homedir as homedir3 } from "os";
|
|
2968
|
+
import { join as join4, resolve as resolve2 } from "path";
|
|
2905
2969
|
import { fileURLToPath } from "url";
|
|
2906
2970
|
var STALE_PACKAGE_NAME = "opencode-claude-code-plugin";
|
|
2907
2971
|
var SUSPECT_DESCRIPTION_TOKEN = "Claude Code";
|
|
@@ -2909,20 +2973,20 @@ var alreadyRan = false;
|
|
|
2909
2973
|
function candidateCacheRoots() {
|
|
2910
2974
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
2911
2975
|
return [
|
|
2912
|
-
xdg ?
|
|
2913
|
-
|
|
2914
|
-
|
|
2976
|
+
xdg ? join4(xdg, "opencode") : null,
|
|
2977
|
+
join4(homedir3(), ".cache", "opencode"),
|
|
2978
|
+
join4(homedir3(), "Library", "Caches", "opencode")
|
|
2915
2979
|
].filter((p) => Boolean(p));
|
|
2916
2980
|
}
|
|
2917
2981
|
function userOpencodeJsonPath() {
|
|
2918
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ??
|
|
2919
|
-
return
|
|
2982
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join4(homedir3(), ".config");
|
|
2983
|
+
return join4(xdgConfig, "opencode", "opencode.json");
|
|
2920
2984
|
}
|
|
2921
2985
|
function userIntendsToUseUnscoped() {
|
|
2922
2986
|
const cfg = userOpencodeJsonPath();
|
|
2923
2987
|
if (!existsSync2(cfg)) return false;
|
|
2924
2988
|
try {
|
|
2925
|
-
const json = JSON.parse(
|
|
2989
|
+
const json = JSON.parse(readFileSync3(cfg, "utf8"));
|
|
2926
2990
|
const plugins = json.plugin;
|
|
2927
2991
|
if (!Array.isArray(plugins)) return false;
|
|
2928
2992
|
return plugins.some(
|
|
@@ -2959,7 +3023,7 @@ function cleanupStaleUnscopedInstall() {
|
|
|
2959
3023
|
}
|
|
2960
3024
|
function cleanupOne(cacheRoot, ourDir) {
|
|
2961
3025
|
if (!existsSync2(cacheRoot)) return;
|
|
2962
|
-
const stalePath =
|
|
3026
|
+
const stalePath = join4(cacheRoot, "node_modules", STALE_PACKAGE_NAME);
|
|
2963
3027
|
if (!existsSync2(stalePath)) return;
|
|
2964
3028
|
let realStalePath = stalePath;
|
|
2965
3029
|
try {
|
|
@@ -2967,11 +3031,11 @@ function cleanupOne(cacheRoot, ourDir) {
|
|
|
2967
3031
|
} catch {
|
|
2968
3032
|
}
|
|
2969
3033
|
if (ourDir && realStalePath === ourDir) return;
|
|
2970
|
-
const pkgJsonPath =
|
|
3034
|
+
const pkgJsonPath = join4(stalePath, "package.json");
|
|
2971
3035
|
if (!existsSync2(pkgJsonPath)) return;
|
|
2972
3036
|
let pkg = {};
|
|
2973
3037
|
try {
|
|
2974
|
-
pkg = JSON.parse(
|
|
3038
|
+
pkg = JSON.parse(readFileSync3(pkgJsonPath, "utf8"));
|
|
2975
3039
|
} catch {
|
|
2976
3040
|
return;
|
|
2977
3041
|
}
|
|
@@ -2987,13 +3051,13 @@ function cleanupOne(cacheRoot, ourDir) {
|
|
|
2987
3051
|
});
|
|
2988
3052
|
return;
|
|
2989
3053
|
}
|
|
2990
|
-
const cachePkgJson =
|
|
3054
|
+
const cachePkgJson = join4(cacheRoot, "package.json");
|
|
2991
3055
|
if (!existsSync2(cachePkgJson)) return;
|
|
2992
3056
|
try {
|
|
2993
|
-
const cfg = JSON.parse(
|
|
3057
|
+
const cfg = JSON.parse(readFileSync3(cachePkgJson, "utf8"));
|
|
2994
3058
|
if (cfg?.dependencies?.[STALE_PACKAGE_NAME]) {
|
|
2995
3059
|
delete cfg.dependencies[STALE_PACKAGE_NAME];
|
|
2996
|
-
|
|
3060
|
+
writeFileSync4(cachePkgJson, JSON.stringify(cfg, null, 2) + "\n");
|
|
2997
3061
|
log.info("cleanup-stale: pruned dep from cache package.json");
|
|
2998
3062
|
}
|
|
2999
3063
|
} catch (err) {
|
|
@@ -3191,12 +3255,20 @@ var server = async (input) => {
|
|
|
3191
3255
|
config: async (config) => {
|
|
3192
3256
|
config.provider ??= {};
|
|
3193
3257
|
const expanded = await expandAccountProviders(config);
|
|
3194
|
-
if (expanded)
|
|
3258
|
+
if (expanded) {
|
|
3259
|
+
const registered = Object.entries(config.provider).filter(([id]) => id === PROVIDER_ID2 || id.startsWith(`${PROVIDER_ID2}-`)).map(([id, p]) => ({ id, name: p?.name ?? id }));
|
|
3260
|
+
log.notice("registered claude-code providers", { providers: registered });
|
|
3261
|
+
return;
|
|
3262
|
+
}
|
|
3195
3263
|
const existing = config.provider[PROVIDER_ID2];
|
|
3196
3264
|
config.provider[PROVIDER_ID2] = {
|
|
3197
3265
|
...existing,
|
|
3198
3266
|
...await providerConfig(existing)
|
|
3199
3267
|
};
|
|
3268
|
+
log.notice("registered claude-code provider", {
|
|
3269
|
+
id: PROVIDER_ID2,
|
|
3270
|
+
name: config.provider[PROVIDER_ID2]?.name ?? PROVIDER_ID2
|
|
3271
|
+
});
|
|
3200
3272
|
},
|
|
3201
3273
|
// No `event` hook: MCP config drift is detected at turn start by the
|
|
3202
3274
|
// hot-reload check in `claude-code-language-model.ts`, which respawns
|