@node9/proxy 1.24.2 → 1.25.0
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/cli.js +285 -10
- package/dist/cli.mjs +285 -10
- package/dist/dashboard.mjs +8 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6463,6 +6463,122 @@ var init_mcp_pin = __esm({
|
|
|
6463
6463
|
}
|
|
6464
6464
|
});
|
|
6465
6465
|
|
|
6466
|
+
// src/setup-opencode-shim.ts
|
|
6467
|
+
function renderOpencodeShim(input) {
|
|
6468
|
+
const { node9Argv, version: version2 } = input;
|
|
6469
|
+
return `// Auto-generated by \`node9 init\`. Do not edit \u2014 re-run init to upgrade.
|
|
6470
|
+
// NODE9_SHIM_VERSION = "${version2}"
|
|
6471
|
+
//
|
|
6472
|
+
// node9 protection shim for Opencode. Wires three hooks against the
|
|
6473
|
+
// agent's plugin API and shells out to the node9 CLI for verdicts.
|
|
6474
|
+
//
|
|
6475
|
+
// Block by throwing from a hook handler; Opencode's plugin trigger
|
|
6476
|
+
// (packages/opencode/src/plugin/index.ts:273) propagates the error and
|
|
6477
|
+
// halts the tool call.
|
|
6478
|
+
|
|
6479
|
+
const { spawnSync } = require("node:child_process");
|
|
6480
|
+
|
|
6481
|
+
// argv prefix for invoking the node9 CLI. argv[0] is the executable
|
|
6482
|
+
// (either the npm-installed wrapper script or the node binary); the
|
|
6483
|
+
// remaining entries (if any) are passed as the leading args before
|
|
6484
|
+
// the subcommand name (e.g. ["/path/to/dist/cli.js"] for dev mode).
|
|
6485
|
+
const NODE9_ARGV = ${JSON.stringify(node9Argv)};
|
|
6486
|
+
const HOOK_TIMEOUT_MS = 30000;
|
|
6487
|
+
const LOG_TIMEOUT_MS = 5000;
|
|
6488
|
+
|
|
6489
|
+
function parseReason(stdout) {
|
|
6490
|
+
// node9 check emits {decision, reason, message} JSON on stdout when
|
|
6491
|
+
// blocking. Fall back to a generic string if anything goes wrong.
|
|
6492
|
+
try {
|
|
6493
|
+
const v = JSON.parse(stdout || "");
|
|
6494
|
+
return v && (v.reason || v.message);
|
|
6495
|
+
} catch (e) {
|
|
6496
|
+
return null;
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
|
|
6500
|
+
function extractPromptText(parts) {
|
|
6501
|
+
// chat.message gives us parts: Part[]. We only DLP-scan text parts
|
|
6502
|
+
// (image / tool_use parts can't contain pasted secrets in any form
|
|
6503
|
+
// node9's scanner currently recognizes).
|
|
6504
|
+
if (!Array.isArray(parts)) return "";
|
|
6505
|
+
return parts
|
|
6506
|
+
.filter((p) => p && p.type === "text")
|
|
6507
|
+
.map((p) => (p && p.text) || "")
|
|
6508
|
+
.join("\\n");
|
|
6509
|
+
}
|
|
6510
|
+
|
|
6511
|
+
module.exports = {
|
|
6512
|
+
id: "node9",
|
|
6513
|
+
server: async (input) => ({
|
|
6514
|
+
"tool.execute.before": async (ctx, mutable) => {
|
|
6515
|
+
const payload = {
|
|
6516
|
+
hook_event_name: "PreToolUse",
|
|
6517
|
+
tool_name: ctx.tool,
|
|
6518
|
+
tool_input: mutable.args,
|
|
6519
|
+
session_id: ctx.sessionID,
|
|
6520
|
+
cwd: input.directory,
|
|
6521
|
+
meta: { agent: "Opencode" },
|
|
6522
|
+
};
|
|
6523
|
+
const r = spawnSync(NODE9_ARGV[0], [...NODE9_ARGV.slice(1), "check"], {
|
|
6524
|
+
input: JSON.stringify(payload),
|
|
6525
|
+
encoding: "utf-8",
|
|
6526
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
6527
|
+
});
|
|
6528
|
+
if (r.status === 0) return;
|
|
6529
|
+
const reason = parseReason(r.stdout) || "blocked by node9";
|
|
6530
|
+
throw new Error("[node9] " + reason);
|
|
6531
|
+
},
|
|
6532
|
+
|
|
6533
|
+
"tool.execute.after": async (ctx) => {
|
|
6534
|
+
// Fire-and-forget audit log \u2014 failures here must NEVER throw,
|
|
6535
|
+
// or we'd retroactively "block" a tool call that already ran.
|
|
6536
|
+
const payload = {
|
|
6537
|
+
hook_event_name: "PostToolUse",
|
|
6538
|
+
tool_name: ctx.tool,
|
|
6539
|
+
session_id: ctx.sessionID,
|
|
6540
|
+
cwd: input.directory,
|
|
6541
|
+
meta: { agent: "Opencode" },
|
|
6542
|
+
};
|
|
6543
|
+
try {
|
|
6544
|
+
spawnSync(NODE9_ARGV[0], [...NODE9_ARGV.slice(1), "log"], {
|
|
6545
|
+
input: JSON.stringify(payload),
|
|
6546
|
+
encoding: "utf-8",
|
|
6547
|
+
timeout: LOG_TIMEOUT_MS,
|
|
6548
|
+
});
|
|
6549
|
+
} catch (e) {
|
|
6550
|
+
// Swallow: audit log gaps are preferable to crashing the agent.
|
|
6551
|
+
}
|
|
6552
|
+
},
|
|
6553
|
+
|
|
6554
|
+
"chat.message": async (ctx, mutable) => {
|
|
6555
|
+
const prompt = extractPromptText(mutable.parts);
|
|
6556
|
+
if (!prompt) return;
|
|
6557
|
+
const payload = {
|
|
6558
|
+
hook_event_name: "UserPromptSubmit",
|
|
6559
|
+
prompt,
|
|
6560
|
+
session_id: ctx.sessionID,
|
|
6561
|
+
meta: { agent: "Opencode" },
|
|
6562
|
+
};
|
|
6563
|
+
const r = spawnSync(NODE9_ARGV[0], [...NODE9_ARGV.slice(1), "check"], {
|
|
6564
|
+
input: JSON.stringify(payload),
|
|
6565
|
+
encoding: "utf-8",
|
|
6566
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
6567
|
+
});
|
|
6568
|
+
if (r.status === 0) return;
|
|
6569
|
+
const reason = parseReason(r.stdout) || "prompt blocked";
|
|
6570
|
+
throw new Error("[node9] " + reason);
|
|
6571
|
+
},
|
|
6572
|
+
}),
|
|
6573
|
+
};
|
|
6574
|
+
`;
|
|
6575
|
+
}
|
|
6576
|
+
var init_setup_opencode_shim = __esm({
|
|
6577
|
+
"src/setup-opencode-shim.ts"() {
|
|
6578
|
+
"use strict";
|
|
6579
|
+
}
|
|
6580
|
+
});
|
|
6581
|
+
|
|
6466
6582
|
// src/setup.ts
|
|
6467
6583
|
function hasNode9McpServer(servers) {
|
|
6468
6584
|
const entry = servers["node9"];
|
|
@@ -6498,6 +6614,13 @@ function isStaleHookCommand(command) {
|
|
|
6498
6614
|
}
|
|
6499
6615
|
return false;
|
|
6500
6616
|
}
|
|
6617
|
+
function isLegacyHookFormat(command) {
|
|
6618
|
+
if (!command) return false;
|
|
6619
|
+
return command.includes("\\");
|
|
6620
|
+
}
|
|
6621
|
+
function needsRewrite(command) {
|
|
6622
|
+
return isStaleHookCommand(command) || isLegacyHookFormat(command);
|
|
6623
|
+
}
|
|
6501
6624
|
function readJson(filePath) {
|
|
6502
6625
|
try {
|
|
6503
6626
|
if (import_fs13.default.existsSync(filePath)) {
|
|
@@ -6670,7 +6793,7 @@ async function setupClaude() {
|
|
|
6670
6793
|
for (const h of matcher.hooks) {
|
|
6671
6794
|
const cmd = h.command ?? "";
|
|
6672
6795
|
const isNode9 = cmd.includes("node9 check") || cmd.includes("cli.js check");
|
|
6673
|
-
if (isNode9 &&
|
|
6796
|
+
if (isNode9 && needsRewrite(cmd)) {
|
|
6674
6797
|
h.command = fullPathCommand("check");
|
|
6675
6798
|
console.log(import_chalk.default.yellow(" \u{1F527} PreToolUse hook repaired (stale path \u2192 current binary)"));
|
|
6676
6799
|
hooksChanged = true;
|
|
@@ -6696,7 +6819,7 @@ async function setupClaude() {
|
|
|
6696
6819
|
for (const h of matcher.hooks) {
|
|
6697
6820
|
const cmd = h.command ?? "";
|
|
6698
6821
|
const isNode9 = cmd.includes("node9 log") || cmd.includes("cli.js log");
|
|
6699
|
-
if (isNode9 &&
|
|
6822
|
+
if (isNode9 && needsRewrite(cmd)) {
|
|
6700
6823
|
h.command = fullPathCommand("log");
|
|
6701
6824
|
console.log(import_chalk.default.yellow(" \u{1F527} PostToolUse hook repaired (stale path \u2192 current binary)"));
|
|
6702
6825
|
hooksChanged = true;
|
|
@@ -6721,7 +6844,7 @@ async function setupClaude() {
|
|
|
6721
6844
|
for (const matcher of settings.hooks.UserPromptSubmit) {
|
|
6722
6845
|
for (const h of matcher.hooks) {
|
|
6723
6846
|
const cmd = h.command ?? "";
|
|
6724
|
-
if (isNode9Hook(cmd) &&
|
|
6847
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
6725
6848
|
h.command = fullPathCommand("check");
|
|
6726
6849
|
console.log(
|
|
6727
6850
|
import_chalk.default.yellow(" \u{1F527} UserPromptSubmit hook repaired (stale path \u2192 current binary)")
|
|
@@ -6933,7 +7056,8 @@ function detectAgents(homeDir2 = import_os12.default.homedir()) {
|
|
|
6933
7056
|
codex: exists(import_path15.default.join(homeDir2, ".codex")),
|
|
6934
7057
|
windsurf: exists(import_path15.default.join(homeDir2, ".codeium", "windsurf")),
|
|
6935
7058
|
vscode: exists(import_path15.default.join(homeDir2, ".vscode")),
|
|
6936
|
-
claudeDesktop: desktopPath !== null && exists(import_path15.default.dirname(desktopPath))
|
|
7059
|
+
claudeDesktop: desktopPath !== null && exists(import_path15.default.dirname(desktopPath)),
|
|
7060
|
+
opencode: exists(import_path15.default.join(homeDir2, ".config", "opencode"))
|
|
6937
7061
|
};
|
|
6938
7062
|
}
|
|
6939
7063
|
async function setupCursor() {
|
|
@@ -7040,7 +7164,7 @@ async function setupCodex() {
|
|
|
7040
7164
|
} else {
|
|
7041
7165
|
for (const h of existing.hooks) {
|
|
7042
7166
|
const cmd = h.command ?? "";
|
|
7043
|
-
if (isNode9Hook(cmd) &&
|
|
7167
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7044
7168
|
h.command = fullPathCommand("check");
|
|
7045
7169
|
hooksChanged = true;
|
|
7046
7170
|
}
|
|
@@ -7060,7 +7184,7 @@ async function setupCodex() {
|
|
|
7060
7184
|
for (const m of hooksFile.hooks.UserPromptSubmit) {
|
|
7061
7185
|
for (const h of m.hooks) {
|
|
7062
7186
|
const cmd = h.command ?? "";
|
|
7063
|
-
if (isNode9Hook(cmd) &&
|
|
7187
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7064
7188
|
h.command = fullPathCommand("check");
|
|
7065
7189
|
hooksChanged = true;
|
|
7066
7190
|
}
|
|
@@ -7081,7 +7205,7 @@ async function setupCodex() {
|
|
|
7081
7205
|
for (const m of hooksFile.hooks.PostToolUse) {
|
|
7082
7206
|
for (const h of m.hooks) {
|
|
7083
7207
|
const cmd = h.command ?? "";
|
|
7084
|
-
if (isNode9Hook(cmd) &&
|
|
7208
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7085
7209
|
h.command = fullPathCommand("log");
|
|
7086
7210
|
hooksChanged = true;
|
|
7087
7211
|
}
|
|
@@ -7566,6 +7690,127 @@ function teardownClaudeDesktop() {
|
|
|
7566
7690
|
console.log(import_chalk.default.blue(" \u2139\uFE0F No Node9-wrapped MCP servers found in Claude Desktop config"));
|
|
7567
7691
|
}
|
|
7568
7692
|
}
|
|
7693
|
+
function node9ArgvForShim() {
|
|
7694
|
+
if (process.env.NODE9_TESTING === "1") return ["node9"];
|
|
7695
|
+
const nodeExec = process.execPath;
|
|
7696
|
+
const cliScript = process.argv[1];
|
|
7697
|
+
if (cliScript && cliScript.endsWith(".js")) return [nodeExec, cliScript];
|
|
7698
|
+
return [cliScript];
|
|
7699
|
+
}
|
|
7700
|
+
function node9Version() {
|
|
7701
|
+
try {
|
|
7702
|
+
const pkg = JSON.parse(
|
|
7703
|
+
import_fs13.default.readFileSync(import_path15.default.join(__dirname, "..", "package.json"), "utf-8")
|
|
7704
|
+
);
|
|
7705
|
+
return pkg.version ?? "0.0.0";
|
|
7706
|
+
} catch {
|
|
7707
|
+
return "0.0.0";
|
|
7708
|
+
}
|
|
7709
|
+
}
|
|
7710
|
+
async function setupOpencode() {
|
|
7711
|
+
seedMcpPinsIfMissing();
|
|
7712
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7713
|
+
const configDir = import_path15.default.join(homeDir2, ".config", "opencode");
|
|
7714
|
+
const pluginsDir = import_path15.default.join(configDir, "plugins");
|
|
7715
|
+
const configPath = import_path15.default.join(configDir, "opencode.json");
|
|
7716
|
+
const pluginPath = import_path15.default.join(pluginsDir, OPENCODE_PLUGIN_NAME);
|
|
7717
|
+
try {
|
|
7718
|
+
import_fs13.default.mkdirSync(pluginsDir, { recursive: true });
|
|
7719
|
+
} catch (err2) {
|
|
7720
|
+
const code = err2.code;
|
|
7721
|
+
if (code !== "EEXIST") {
|
|
7722
|
+
console.log(import_chalk.default.yellow(` \u26A0\uFE0F Could not create ${pluginsDir}: ${code ?? String(err2)}`));
|
|
7723
|
+
return;
|
|
7724
|
+
}
|
|
7725
|
+
}
|
|
7726
|
+
const shimContent = renderOpencodeShim({
|
|
7727
|
+
node9Argv: node9ArgvForShim(),
|
|
7728
|
+
version: node9Version()
|
|
7729
|
+
});
|
|
7730
|
+
let pluginChanged = false;
|
|
7731
|
+
const existingShim = (() => {
|
|
7732
|
+
try {
|
|
7733
|
+
return import_fs13.default.readFileSync(pluginPath, "utf-8");
|
|
7734
|
+
} catch {
|
|
7735
|
+
return null;
|
|
7736
|
+
}
|
|
7737
|
+
})();
|
|
7738
|
+
if (existingShim !== shimContent) {
|
|
7739
|
+
import_fs13.default.writeFileSync(pluginPath, shimContent);
|
|
7740
|
+
pluginChanged = true;
|
|
7741
|
+
if (existingShim) {
|
|
7742
|
+
console.log(import_chalk.default.yellow(" \u{1F527} Opencode plugin shim updated to current version"));
|
|
7743
|
+
} else {
|
|
7744
|
+
console.log(
|
|
7745
|
+
import_chalk.default.green(" \u2705 Opencode plugin installed \u2192 tool.execute.before / after, chat.message")
|
|
7746
|
+
);
|
|
7747
|
+
}
|
|
7748
|
+
}
|
|
7749
|
+
const config = readJson(configPath) ?? {};
|
|
7750
|
+
const mcp = config.mcp ?? {};
|
|
7751
|
+
let configChanged = false;
|
|
7752
|
+
const desiredCommand = [...node9ArgvForShim(), "mcp-server"];
|
|
7753
|
+
const desiredEntry = {
|
|
7754
|
+
type: "local",
|
|
7755
|
+
command: desiredCommand,
|
|
7756
|
+
enabled: true
|
|
7757
|
+
};
|
|
7758
|
+
const existing = mcp["node9"];
|
|
7759
|
+
const entryMatches = existing && existing.type === "local" && Array.isArray(existing.command) && existing.command.length === desiredCommand.length && existing.command.every((c, i) => c === desiredCommand[i]) && existing.enabled !== false;
|
|
7760
|
+
if (!entryMatches) {
|
|
7761
|
+
mcp["node9"] = desiredEntry;
|
|
7762
|
+
config.mcp = mcp;
|
|
7763
|
+
configChanged = true;
|
|
7764
|
+
if (existing) {
|
|
7765
|
+
console.log(import_chalk.default.yellow(" \u{1F527} Opencode MCP entry updated (node9)"));
|
|
7766
|
+
} else {
|
|
7767
|
+
console.log(import_chalk.default.green(" \u2705 node9 MCP server added \u2192 node9 mcp-server"));
|
|
7768
|
+
}
|
|
7769
|
+
}
|
|
7770
|
+
if (configChanged) writeJson(configPath, config);
|
|
7771
|
+
if (pluginChanged || configChanged) {
|
|
7772
|
+
console.log(import_chalk.default.green.bold("\u{1F6E1}\uFE0F Node9 is now protecting Opencode!"));
|
|
7773
|
+
console.log(import_chalk.default.gray(" Restart Opencode for changes to take effect."));
|
|
7774
|
+
printDaemonTip();
|
|
7775
|
+
} else {
|
|
7776
|
+
console.log(import_chalk.default.blue(" \u2139\uFE0F Node9 is already fully configured for Opencode."));
|
|
7777
|
+
}
|
|
7778
|
+
}
|
|
7779
|
+
function teardownOpencode() {
|
|
7780
|
+
const homeDir2 = import_os12.default.homedir();
|
|
7781
|
+
const configDir = import_path15.default.join(homeDir2, ".config", "opencode");
|
|
7782
|
+
const pluginsDir = import_path15.default.join(configDir, "plugins");
|
|
7783
|
+
const configPath = import_path15.default.join(configDir, "opencode.json");
|
|
7784
|
+
const pluginPath = import_path15.default.join(pluginsDir, OPENCODE_PLUGIN_NAME);
|
|
7785
|
+
try {
|
|
7786
|
+
if (import_fs13.default.existsSync(pluginPath)) {
|
|
7787
|
+
import_fs13.default.unlinkSync(pluginPath);
|
|
7788
|
+
console.log(import_chalk.default.green(" \u2705 Removed node9 plugin from ~/.config/opencode/plugins/"));
|
|
7789
|
+
}
|
|
7790
|
+
} catch (err2) {
|
|
7791
|
+
console.log(import_chalk.default.yellow(` \u26A0\uFE0F Could not remove ${pluginPath}: ${String(err2)}`));
|
|
7792
|
+
}
|
|
7793
|
+
const config = readJson(configPath);
|
|
7794
|
+
if (!config) {
|
|
7795
|
+
console.log(import_chalk.default.blue(" \u2139\uFE0F ~/.config/opencode/opencode.json not found \u2014 nothing to remove"));
|
|
7796
|
+
return;
|
|
7797
|
+
}
|
|
7798
|
+
const mcp = config.mcp ?? {};
|
|
7799
|
+
let changed = false;
|
|
7800
|
+
if (mcp["node9"]) {
|
|
7801
|
+
delete mcp["node9"];
|
|
7802
|
+
changed = true;
|
|
7803
|
+
console.log(
|
|
7804
|
+
import_chalk.default.green(" \u2705 Removed node9 MCP server entry from ~/.config/opencode/opencode.json")
|
|
7805
|
+
);
|
|
7806
|
+
}
|
|
7807
|
+
if (changed) {
|
|
7808
|
+
config.mcp = mcp;
|
|
7809
|
+
writeJson(configPath, config);
|
|
7810
|
+
} else {
|
|
7811
|
+
console.log(import_chalk.default.blue(" \u2139\uFE0F No node9 entries found in ~/.config/opencode/opencode.json"));
|
|
7812
|
+
}
|
|
7813
|
+
}
|
|
7569
7814
|
function getAgentsStatus(homeDir2 = import_os12.default.homedir()) {
|
|
7570
7815
|
const detected = detectAgents(homeDir2);
|
|
7571
7816
|
const claudeWired = (() => {
|
|
@@ -7648,10 +7893,30 @@ function getAgentsStatus(homeDir2 = import_os12.default.homedir()) {
|
|
|
7648
7893
|
return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
|
|
7649
7894
|
})(),
|
|
7650
7895
|
mode: detected.claudeDesktop ? "mcp" : null
|
|
7896
|
+
},
|
|
7897
|
+
{
|
|
7898
|
+
name: "opencode",
|
|
7899
|
+
label: "Opencode",
|
|
7900
|
+
installed: detected.opencode,
|
|
7901
|
+
wired: (() => {
|
|
7902
|
+
const pluginPath = import_path15.default.join(
|
|
7903
|
+
homeDir2,
|
|
7904
|
+
".config",
|
|
7905
|
+
"opencode",
|
|
7906
|
+
"plugins",
|
|
7907
|
+
OPENCODE_PLUGIN_NAME
|
|
7908
|
+
);
|
|
7909
|
+
if (import_fs13.default.existsSync(pluginPath)) return true;
|
|
7910
|
+
const cfg = readJson(
|
|
7911
|
+
import_path15.default.join(homeDir2, ".config", "opencode", "opencode.json")
|
|
7912
|
+
);
|
|
7913
|
+
return !!cfg?.mcp?.["node9"];
|
|
7914
|
+
})(),
|
|
7915
|
+
mode: detected.opencode ? "hooks" : null
|
|
7651
7916
|
}
|
|
7652
7917
|
];
|
|
7653
7918
|
}
|
|
7654
|
-
var import_fs13, import_path15, import_os12, import_chalk, import_prompts, import_smol_toml, NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS;
|
|
7919
|
+
var import_fs13, import_path15, import_os12, import_chalk, import_prompts, import_smol_toml, NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS, OPENCODE_PLUGIN_NAME;
|
|
7655
7920
|
var init_setup = __esm({
|
|
7656
7921
|
"src/setup.ts"() {
|
|
7657
7922
|
"use strict";
|
|
@@ -7662,8 +7927,10 @@ var init_setup = __esm({
|
|
|
7662
7927
|
import_prompts = require("@inquirer/prompts");
|
|
7663
7928
|
import_smol_toml = require("smol-toml");
|
|
7664
7929
|
init_mcp_pin();
|
|
7930
|
+
init_setup_opencode_shim();
|
|
7665
7931
|
NODE9_MCP_SERVER_ENTRY = { command: "node9", args: ["mcp-server"] };
|
|
7666
7932
|
CODEX_PRE_TOOL_MATCHERS = ["^Bash$", "^apply_patch$", "^mcp__.*"];
|
|
7933
|
+
OPENCODE_PLUGIN_NAME = "node9.js";
|
|
7667
7934
|
}
|
|
7668
7935
|
});
|
|
7669
7936
|
|
|
@@ -15965,6 +16232,11 @@ function sanitize2(value) {
|
|
|
15965
16232
|
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
15966
16233
|
}
|
|
15967
16234
|
function detectAiAgent(payload) {
|
|
16235
|
+
const meta = payload.meta;
|
|
16236
|
+
if (meta && typeof meta === "object") {
|
|
16237
|
+
const tagged = meta.agent;
|
|
16238
|
+
if (typeof tagged === "string" && tagged.length > 0) return tagged;
|
|
16239
|
+
}
|
|
15968
16240
|
if (payload.turn_id !== void 0) {
|
|
15969
16241
|
return "Codex";
|
|
15970
16242
|
}
|
|
@@ -18603,6 +18875,7 @@ function registerInitCommand(program2) {
|
|
|
18603
18875
|
else if (agent === "windsurf") await setupWindsurf();
|
|
18604
18876
|
else if (agent === "vscode") await setupVSCode();
|
|
18605
18877
|
else if (agent === "claudeDesktop") await setupClaudeDesktop();
|
|
18878
|
+
else if (agent === "opencode") await setupOpencode();
|
|
18606
18879
|
console.log("");
|
|
18607
18880
|
}
|
|
18608
18881
|
if ((process.platform === "darwin" || process.platform === "linux") && process.stdout.isTTY) {
|
|
@@ -20362,7 +20635,8 @@ var SETUP_FN = {
|
|
|
20362
20635
|
codex: setupCodex,
|
|
20363
20636
|
windsurf: setupWindsurf,
|
|
20364
20637
|
vscode: setupVSCode,
|
|
20365
|
-
claudeDesktop: setupClaudeDesktop
|
|
20638
|
+
claudeDesktop: setupClaudeDesktop,
|
|
20639
|
+
opencode: setupOpencode
|
|
20366
20640
|
};
|
|
20367
20641
|
var TEARDOWN_FN = {
|
|
20368
20642
|
claude: teardownClaude,
|
|
@@ -20371,7 +20645,8 @@ var TEARDOWN_FN = {
|
|
|
20371
20645
|
codex: teardownCodex,
|
|
20372
20646
|
windsurf: teardownWindsurf,
|
|
20373
20647
|
vscode: teardownVSCode,
|
|
20374
|
-
claudeDesktop: teardownClaudeDesktop
|
|
20648
|
+
claudeDesktop: teardownClaudeDesktop,
|
|
20649
|
+
opencode: teardownOpencode
|
|
20375
20650
|
};
|
|
20376
20651
|
var AGENT_NAMES = Object.keys(SETUP_FN);
|
|
20377
20652
|
function registerAgentsCommand(program2) {
|
package/dist/cli.mjs
CHANGED
|
@@ -6438,6 +6438,122 @@ var init_mcp_pin = __esm({
|
|
|
6438
6438
|
}
|
|
6439
6439
|
});
|
|
6440
6440
|
|
|
6441
|
+
// src/setup-opencode-shim.ts
|
|
6442
|
+
function renderOpencodeShim(input) {
|
|
6443
|
+
const { node9Argv, version: version2 } = input;
|
|
6444
|
+
return `// Auto-generated by \`node9 init\`. Do not edit \u2014 re-run init to upgrade.
|
|
6445
|
+
// NODE9_SHIM_VERSION = "${version2}"
|
|
6446
|
+
//
|
|
6447
|
+
// node9 protection shim for Opencode. Wires three hooks against the
|
|
6448
|
+
// agent's plugin API and shells out to the node9 CLI for verdicts.
|
|
6449
|
+
//
|
|
6450
|
+
// Block by throwing from a hook handler; Opencode's plugin trigger
|
|
6451
|
+
// (packages/opencode/src/plugin/index.ts:273) propagates the error and
|
|
6452
|
+
// halts the tool call.
|
|
6453
|
+
|
|
6454
|
+
const { spawnSync } = require("node:child_process");
|
|
6455
|
+
|
|
6456
|
+
// argv prefix for invoking the node9 CLI. argv[0] is the executable
|
|
6457
|
+
// (either the npm-installed wrapper script or the node binary); the
|
|
6458
|
+
// remaining entries (if any) are passed as the leading args before
|
|
6459
|
+
// the subcommand name (e.g. ["/path/to/dist/cli.js"] for dev mode).
|
|
6460
|
+
const NODE9_ARGV = ${JSON.stringify(node9Argv)};
|
|
6461
|
+
const HOOK_TIMEOUT_MS = 30000;
|
|
6462
|
+
const LOG_TIMEOUT_MS = 5000;
|
|
6463
|
+
|
|
6464
|
+
function parseReason(stdout) {
|
|
6465
|
+
// node9 check emits {decision, reason, message} JSON on stdout when
|
|
6466
|
+
// blocking. Fall back to a generic string if anything goes wrong.
|
|
6467
|
+
try {
|
|
6468
|
+
const v = JSON.parse(stdout || "");
|
|
6469
|
+
return v && (v.reason || v.message);
|
|
6470
|
+
} catch (e) {
|
|
6471
|
+
return null;
|
|
6472
|
+
}
|
|
6473
|
+
}
|
|
6474
|
+
|
|
6475
|
+
function extractPromptText(parts) {
|
|
6476
|
+
// chat.message gives us parts: Part[]. We only DLP-scan text parts
|
|
6477
|
+
// (image / tool_use parts can't contain pasted secrets in any form
|
|
6478
|
+
// node9's scanner currently recognizes).
|
|
6479
|
+
if (!Array.isArray(parts)) return "";
|
|
6480
|
+
return parts
|
|
6481
|
+
.filter((p) => p && p.type === "text")
|
|
6482
|
+
.map((p) => (p && p.text) || "")
|
|
6483
|
+
.join("\\n");
|
|
6484
|
+
}
|
|
6485
|
+
|
|
6486
|
+
module.exports = {
|
|
6487
|
+
id: "node9",
|
|
6488
|
+
server: async (input) => ({
|
|
6489
|
+
"tool.execute.before": async (ctx, mutable) => {
|
|
6490
|
+
const payload = {
|
|
6491
|
+
hook_event_name: "PreToolUse",
|
|
6492
|
+
tool_name: ctx.tool,
|
|
6493
|
+
tool_input: mutable.args,
|
|
6494
|
+
session_id: ctx.sessionID,
|
|
6495
|
+
cwd: input.directory,
|
|
6496
|
+
meta: { agent: "Opencode" },
|
|
6497
|
+
};
|
|
6498
|
+
const r = spawnSync(NODE9_ARGV[0], [...NODE9_ARGV.slice(1), "check"], {
|
|
6499
|
+
input: JSON.stringify(payload),
|
|
6500
|
+
encoding: "utf-8",
|
|
6501
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
6502
|
+
});
|
|
6503
|
+
if (r.status === 0) return;
|
|
6504
|
+
const reason = parseReason(r.stdout) || "blocked by node9";
|
|
6505
|
+
throw new Error("[node9] " + reason);
|
|
6506
|
+
},
|
|
6507
|
+
|
|
6508
|
+
"tool.execute.after": async (ctx) => {
|
|
6509
|
+
// Fire-and-forget audit log \u2014 failures here must NEVER throw,
|
|
6510
|
+
// or we'd retroactively "block" a tool call that already ran.
|
|
6511
|
+
const payload = {
|
|
6512
|
+
hook_event_name: "PostToolUse",
|
|
6513
|
+
tool_name: ctx.tool,
|
|
6514
|
+
session_id: ctx.sessionID,
|
|
6515
|
+
cwd: input.directory,
|
|
6516
|
+
meta: { agent: "Opencode" },
|
|
6517
|
+
};
|
|
6518
|
+
try {
|
|
6519
|
+
spawnSync(NODE9_ARGV[0], [...NODE9_ARGV.slice(1), "log"], {
|
|
6520
|
+
input: JSON.stringify(payload),
|
|
6521
|
+
encoding: "utf-8",
|
|
6522
|
+
timeout: LOG_TIMEOUT_MS,
|
|
6523
|
+
});
|
|
6524
|
+
} catch (e) {
|
|
6525
|
+
// Swallow: audit log gaps are preferable to crashing the agent.
|
|
6526
|
+
}
|
|
6527
|
+
},
|
|
6528
|
+
|
|
6529
|
+
"chat.message": async (ctx, mutable) => {
|
|
6530
|
+
const prompt = extractPromptText(mutable.parts);
|
|
6531
|
+
if (!prompt) return;
|
|
6532
|
+
const payload = {
|
|
6533
|
+
hook_event_name: "UserPromptSubmit",
|
|
6534
|
+
prompt,
|
|
6535
|
+
session_id: ctx.sessionID,
|
|
6536
|
+
meta: { agent: "Opencode" },
|
|
6537
|
+
};
|
|
6538
|
+
const r = spawnSync(NODE9_ARGV[0], [...NODE9_ARGV.slice(1), "check"], {
|
|
6539
|
+
input: JSON.stringify(payload),
|
|
6540
|
+
encoding: "utf-8",
|
|
6541
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
6542
|
+
});
|
|
6543
|
+
if (r.status === 0) return;
|
|
6544
|
+
const reason = parseReason(r.stdout) || "prompt blocked";
|
|
6545
|
+
throw new Error("[node9] " + reason);
|
|
6546
|
+
},
|
|
6547
|
+
}),
|
|
6548
|
+
};
|
|
6549
|
+
`;
|
|
6550
|
+
}
|
|
6551
|
+
var init_setup_opencode_shim = __esm({
|
|
6552
|
+
"src/setup-opencode-shim.ts"() {
|
|
6553
|
+
"use strict";
|
|
6554
|
+
}
|
|
6555
|
+
});
|
|
6556
|
+
|
|
6441
6557
|
// src/setup.ts
|
|
6442
6558
|
import fs13 from "fs";
|
|
6443
6559
|
import path15 from "path";
|
|
@@ -6479,6 +6595,13 @@ function isStaleHookCommand(command) {
|
|
|
6479
6595
|
}
|
|
6480
6596
|
return false;
|
|
6481
6597
|
}
|
|
6598
|
+
function isLegacyHookFormat(command) {
|
|
6599
|
+
if (!command) return false;
|
|
6600
|
+
return command.includes("\\");
|
|
6601
|
+
}
|
|
6602
|
+
function needsRewrite(command) {
|
|
6603
|
+
return isStaleHookCommand(command) || isLegacyHookFormat(command);
|
|
6604
|
+
}
|
|
6482
6605
|
function readJson(filePath) {
|
|
6483
6606
|
try {
|
|
6484
6607
|
if (fs13.existsSync(filePath)) {
|
|
@@ -6651,7 +6774,7 @@ async function setupClaude() {
|
|
|
6651
6774
|
for (const h of matcher.hooks) {
|
|
6652
6775
|
const cmd = h.command ?? "";
|
|
6653
6776
|
const isNode9 = cmd.includes("node9 check") || cmd.includes("cli.js check");
|
|
6654
|
-
if (isNode9 &&
|
|
6777
|
+
if (isNode9 && needsRewrite(cmd)) {
|
|
6655
6778
|
h.command = fullPathCommand("check");
|
|
6656
6779
|
console.log(chalk.yellow(" \u{1F527} PreToolUse hook repaired (stale path \u2192 current binary)"));
|
|
6657
6780
|
hooksChanged = true;
|
|
@@ -6677,7 +6800,7 @@ async function setupClaude() {
|
|
|
6677
6800
|
for (const h of matcher.hooks) {
|
|
6678
6801
|
const cmd = h.command ?? "";
|
|
6679
6802
|
const isNode9 = cmd.includes("node9 log") || cmd.includes("cli.js log");
|
|
6680
|
-
if (isNode9 &&
|
|
6803
|
+
if (isNode9 && needsRewrite(cmd)) {
|
|
6681
6804
|
h.command = fullPathCommand("log");
|
|
6682
6805
|
console.log(chalk.yellow(" \u{1F527} PostToolUse hook repaired (stale path \u2192 current binary)"));
|
|
6683
6806
|
hooksChanged = true;
|
|
@@ -6702,7 +6825,7 @@ async function setupClaude() {
|
|
|
6702
6825
|
for (const matcher of settings.hooks.UserPromptSubmit) {
|
|
6703
6826
|
for (const h of matcher.hooks) {
|
|
6704
6827
|
const cmd = h.command ?? "";
|
|
6705
|
-
if (isNode9Hook(cmd) &&
|
|
6828
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
6706
6829
|
h.command = fullPathCommand("check");
|
|
6707
6830
|
console.log(
|
|
6708
6831
|
chalk.yellow(" \u{1F527} UserPromptSubmit hook repaired (stale path \u2192 current binary)")
|
|
@@ -6914,7 +7037,8 @@ function detectAgents(homeDir2 = os12.homedir()) {
|
|
|
6914
7037
|
codex: exists(path15.join(homeDir2, ".codex")),
|
|
6915
7038
|
windsurf: exists(path15.join(homeDir2, ".codeium", "windsurf")),
|
|
6916
7039
|
vscode: exists(path15.join(homeDir2, ".vscode")),
|
|
6917
|
-
claudeDesktop: desktopPath !== null && exists(path15.dirname(desktopPath))
|
|
7040
|
+
claudeDesktop: desktopPath !== null && exists(path15.dirname(desktopPath)),
|
|
7041
|
+
opencode: exists(path15.join(homeDir2, ".config", "opencode"))
|
|
6918
7042
|
};
|
|
6919
7043
|
}
|
|
6920
7044
|
async function setupCursor() {
|
|
@@ -7021,7 +7145,7 @@ async function setupCodex() {
|
|
|
7021
7145
|
} else {
|
|
7022
7146
|
for (const h of existing.hooks) {
|
|
7023
7147
|
const cmd = h.command ?? "";
|
|
7024
|
-
if (isNode9Hook(cmd) &&
|
|
7148
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7025
7149
|
h.command = fullPathCommand("check");
|
|
7026
7150
|
hooksChanged = true;
|
|
7027
7151
|
}
|
|
@@ -7041,7 +7165,7 @@ async function setupCodex() {
|
|
|
7041
7165
|
for (const m of hooksFile.hooks.UserPromptSubmit) {
|
|
7042
7166
|
for (const h of m.hooks) {
|
|
7043
7167
|
const cmd = h.command ?? "";
|
|
7044
|
-
if (isNode9Hook(cmd) &&
|
|
7168
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7045
7169
|
h.command = fullPathCommand("check");
|
|
7046
7170
|
hooksChanged = true;
|
|
7047
7171
|
}
|
|
@@ -7062,7 +7186,7 @@ async function setupCodex() {
|
|
|
7062
7186
|
for (const m of hooksFile.hooks.PostToolUse) {
|
|
7063
7187
|
for (const h of m.hooks) {
|
|
7064
7188
|
const cmd = h.command ?? "";
|
|
7065
|
-
if (isNode9Hook(cmd) &&
|
|
7189
|
+
if (isNode9Hook(cmd) && needsRewrite(cmd)) {
|
|
7066
7190
|
h.command = fullPathCommand("log");
|
|
7067
7191
|
hooksChanged = true;
|
|
7068
7192
|
}
|
|
@@ -7547,6 +7671,127 @@ function teardownClaudeDesktop() {
|
|
|
7547
7671
|
console.log(chalk.blue(" \u2139\uFE0F No Node9-wrapped MCP servers found in Claude Desktop config"));
|
|
7548
7672
|
}
|
|
7549
7673
|
}
|
|
7674
|
+
function node9ArgvForShim() {
|
|
7675
|
+
if (process.env.NODE9_TESTING === "1") return ["node9"];
|
|
7676
|
+
const nodeExec = process.execPath;
|
|
7677
|
+
const cliScript = process.argv[1];
|
|
7678
|
+
if (cliScript && cliScript.endsWith(".js")) return [nodeExec, cliScript];
|
|
7679
|
+
return [cliScript];
|
|
7680
|
+
}
|
|
7681
|
+
function node9Version() {
|
|
7682
|
+
try {
|
|
7683
|
+
const pkg = JSON.parse(
|
|
7684
|
+
fs13.readFileSync(path15.join(__dirname, "..", "package.json"), "utf-8")
|
|
7685
|
+
);
|
|
7686
|
+
return pkg.version ?? "0.0.0";
|
|
7687
|
+
} catch {
|
|
7688
|
+
return "0.0.0";
|
|
7689
|
+
}
|
|
7690
|
+
}
|
|
7691
|
+
async function setupOpencode() {
|
|
7692
|
+
seedMcpPinsIfMissing();
|
|
7693
|
+
const homeDir2 = os12.homedir();
|
|
7694
|
+
const configDir = path15.join(homeDir2, ".config", "opencode");
|
|
7695
|
+
const pluginsDir = path15.join(configDir, "plugins");
|
|
7696
|
+
const configPath = path15.join(configDir, "opencode.json");
|
|
7697
|
+
const pluginPath = path15.join(pluginsDir, OPENCODE_PLUGIN_NAME);
|
|
7698
|
+
try {
|
|
7699
|
+
fs13.mkdirSync(pluginsDir, { recursive: true });
|
|
7700
|
+
} catch (err2) {
|
|
7701
|
+
const code = err2.code;
|
|
7702
|
+
if (code !== "EEXIST") {
|
|
7703
|
+
console.log(chalk.yellow(` \u26A0\uFE0F Could not create ${pluginsDir}: ${code ?? String(err2)}`));
|
|
7704
|
+
return;
|
|
7705
|
+
}
|
|
7706
|
+
}
|
|
7707
|
+
const shimContent = renderOpencodeShim({
|
|
7708
|
+
node9Argv: node9ArgvForShim(),
|
|
7709
|
+
version: node9Version()
|
|
7710
|
+
});
|
|
7711
|
+
let pluginChanged = false;
|
|
7712
|
+
const existingShim = (() => {
|
|
7713
|
+
try {
|
|
7714
|
+
return fs13.readFileSync(pluginPath, "utf-8");
|
|
7715
|
+
} catch {
|
|
7716
|
+
return null;
|
|
7717
|
+
}
|
|
7718
|
+
})();
|
|
7719
|
+
if (existingShim !== shimContent) {
|
|
7720
|
+
fs13.writeFileSync(pluginPath, shimContent);
|
|
7721
|
+
pluginChanged = true;
|
|
7722
|
+
if (existingShim) {
|
|
7723
|
+
console.log(chalk.yellow(" \u{1F527} Opencode plugin shim updated to current version"));
|
|
7724
|
+
} else {
|
|
7725
|
+
console.log(
|
|
7726
|
+
chalk.green(" \u2705 Opencode plugin installed \u2192 tool.execute.before / after, chat.message")
|
|
7727
|
+
);
|
|
7728
|
+
}
|
|
7729
|
+
}
|
|
7730
|
+
const config = readJson(configPath) ?? {};
|
|
7731
|
+
const mcp = config.mcp ?? {};
|
|
7732
|
+
let configChanged = false;
|
|
7733
|
+
const desiredCommand = [...node9ArgvForShim(), "mcp-server"];
|
|
7734
|
+
const desiredEntry = {
|
|
7735
|
+
type: "local",
|
|
7736
|
+
command: desiredCommand,
|
|
7737
|
+
enabled: true
|
|
7738
|
+
};
|
|
7739
|
+
const existing = mcp["node9"];
|
|
7740
|
+
const entryMatches = existing && existing.type === "local" && Array.isArray(existing.command) && existing.command.length === desiredCommand.length && existing.command.every((c, i) => c === desiredCommand[i]) && existing.enabled !== false;
|
|
7741
|
+
if (!entryMatches) {
|
|
7742
|
+
mcp["node9"] = desiredEntry;
|
|
7743
|
+
config.mcp = mcp;
|
|
7744
|
+
configChanged = true;
|
|
7745
|
+
if (existing) {
|
|
7746
|
+
console.log(chalk.yellow(" \u{1F527} Opencode MCP entry updated (node9)"));
|
|
7747
|
+
} else {
|
|
7748
|
+
console.log(chalk.green(" \u2705 node9 MCP server added \u2192 node9 mcp-server"));
|
|
7749
|
+
}
|
|
7750
|
+
}
|
|
7751
|
+
if (configChanged) writeJson(configPath, config);
|
|
7752
|
+
if (pluginChanged || configChanged) {
|
|
7753
|
+
console.log(chalk.green.bold("\u{1F6E1}\uFE0F Node9 is now protecting Opencode!"));
|
|
7754
|
+
console.log(chalk.gray(" Restart Opencode for changes to take effect."));
|
|
7755
|
+
printDaemonTip();
|
|
7756
|
+
} else {
|
|
7757
|
+
console.log(chalk.blue(" \u2139\uFE0F Node9 is already fully configured for Opencode."));
|
|
7758
|
+
}
|
|
7759
|
+
}
|
|
7760
|
+
function teardownOpencode() {
|
|
7761
|
+
const homeDir2 = os12.homedir();
|
|
7762
|
+
const configDir = path15.join(homeDir2, ".config", "opencode");
|
|
7763
|
+
const pluginsDir = path15.join(configDir, "plugins");
|
|
7764
|
+
const configPath = path15.join(configDir, "opencode.json");
|
|
7765
|
+
const pluginPath = path15.join(pluginsDir, OPENCODE_PLUGIN_NAME);
|
|
7766
|
+
try {
|
|
7767
|
+
if (fs13.existsSync(pluginPath)) {
|
|
7768
|
+
fs13.unlinkSync(pluginPath);
|
|
7769
|
+
console.log(chalk.green(" \u2705 Removed node9 plugin from ~/.config/opencode/plugins/"));
|
|
7770
|
+
}
|
|
7771
|
+
} catch (err2) {
|
|
7772
|
+
console.log(chalk.yellow(` \u26A0\uFE0F Could not remove ${pluginPath}: ${String(err2)}`));
|
|
7773
|
+
}
|
|
7774
|
+
const config = readJson(configPath);
|
|
7775
|
+
if (!config) {
|
|
7776
|
+
console.log(chalk.blue(" \u2139\uFE0F ~/.config/opencode/opencode.json not found \u2014 nothing to remove"));
|
|
7777
|
+
return;
|
|
7778
|
+
}
|
|
7779
|
+
const mcp = config.mcp ?? {};
|
|
7780
|
+
let changed = false;
|
|
7781
|
+
if (mcp["node9"]) {
|
|
7782
|
+
delete mcp["node9"];
|
|
7783
|
+
changed = true;
|
|
7784
|
+
console.log(
|
|
7785
|
+
chalk.green(" \u2705 Removed node9 MCP server entry from ~/.config/opencode/opencode.json")
|
|
7786
|
+
);
|
|
7787
|
+
}
|
|
7788
|
+
if (changed) {
|
|
7789
|
+
config.mcp = mcp;
|
|
7790
|
+
writeJson(configPath, config);
|
|
7791
|
+
} else {
|
|
7792
|
+
console.log(chalk.blue(" \u2139\uFE0F No node9 entries found in ~/.config/opencode/opencode.json"));
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7550
7795
|
function getAgentsStatus(homeDir2 = os12.homedir()) {
|
|
7551
7796
|
const detected = detectAgents(homeDir2);
|
|
7552
7797
|
const claudeWired = (() => {
|
|
@@ -7629,16 +7874,38 @@ function getAgentsStatus(homeDir2 = os12.homedir()) {
|
|
|
7629
7874
|
return !!(cfg?.mcpServers && hasNode9McpServer(cfg.mcpServers));
|
|
7630
7875
|
})(),
|
|
7631
7876
|
mode: detected.claudeDesktop ? "mcp" : null
|
|
7877
|
+
},
|
|
7878
|
+
{
|
|
7879
|
+
name: "opencode",
|
|
7880
|
+
label: "Opencode",
|
|
7881
|
+
installed: detected.opencode,
|
|
7882
|
+
wired: (() => {
|
|
7883
|
+
const pluginPath = path15.join(
|
|
7884
|
+
homeDir2,
|
|
7885
|
+
".config",
|
|
7886
|
+
"opencode",
|
|
7887
|
+
"plugins",
|
|
7888
|
+
OPENCODE_PLUGIN_NAME
|
|
7889
|
+
);
|
|
7890
|
+
if (fs13.existsSync(pluginPath)) return true;
|
|
7891
|
+
const cfg = readJson(
|
|
7892
|
+
path15.join(homeDir2, ".config", "opencode", "opencode.json")
|
|
7893
|
+
);
|
|
7894
|
+
return !!cfg?.mcp?.["node9"];
|
|
7895
|
+
})(),
|
|
7896
|
+
mode: detected.opencode ? "hooks" : null
|
|
7632
7897
|
}
|
|
7633
7898
|
];
|
|
7634
7899
|
}
|
|
7635
|
-
var NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS;
|
|
7900
|
+
var NODE9_MCP_SERVER_ENTRY, CODEX_PRE_TOOL_MATCHERS, OPENCODE_PLUGIN_NAME;
|
|
7636
7901
|
var init_setup = __esm({
|
|
7637
7902
|
"src/setup.ts"() {
|
|
7638
7903
|
"use strict";
|
|
7639
7904
|
init_mcp_pin();
|
|
7905
|
+
init_setup_opencode_shim();
|
|
7640
7906
|
NODE9_MCP_SERVER_ENTRY = { command: "node9", args: ["mcp-server"] };
|
|
7641
7907
|
CODEX_PRE_TOOL_MATCHERS = ["^Bash$", "^apply_patch$", "^mcp__.*"];
|
|
7908
|
+
OPENCODE_PLUGIN_NAME = "node9.js";
|
|
7642
7909
|
}
|
|
7643
7910
|
});
|
|
7644
7911
|
|
|
@@ -15937,6 +16204,11 @@ function sanitize2(value) {
|
|
|
15937
16204
|
return value.replace(/[\x00-\x1F\x7F]/g, "");
|
|
15938
16205
|
}
|
|
15939
16206
|
function detectAiAgent(payload) {
|
|
16207
|
+
const meta = payload.meta;
|
|
16208
|
+
if (meta && typeof meta === "object") {
|
|
16209
|
+
const tagged = meta.agent;
|
|
16210
|
+
if (typeof tagged === "string" && tagged.length > 0) return tagged;
|
|
16211
|
+
}
|
|
15940
16212
|
if (payload.turn_id !== void 0) {
|
|
15941
16213
|
return "Codex";
|
|
15942
16214
|
}
|
|
@@ -18575,6 +18847,7 @@ function registerInitCommand(program2) {
|
|
|
18575
18847
|
else if (agent === "windsurf") await setupWindsurf();
|
|
18576
18848
|
else if (agent === "vscode") await setupVSCode();
|
|
18577
18849
|
else if (agent === "claudeDesktop") await setupClaudeDesktop();
|
|
18850
|
+
else if (agent === "opencode") await setupOpencode();
|
|
18578
18851
|
console.log("");
|
|
18579
18852
|
}
|
|
18580
18853
|
if ((process.platform === "darwin" || process.platform === "linux") && process.stdout.isTTY) {
|
|
@@ -20334,7 +20607,8 @@ var SETUP_FN = {
|
|
|
20334
20607
|
codex: setupCodex,
|
|
20335
20608
|
windsurf: setupWindsurf,
|
|
20336
20609
|
vscode: setupVSCode,
|
|
20337
|
-
claudeDesktop: setupClaudeDesktop
|
|
20610
|
+
claudeDesktop: setupClaudeDesktop,
|
|
20611
|
+
opencode: setupOpencode
|
|
20338
20612
|
};
|
|
20339
20613
|
var TEARDOWN_FN = {
|
|
20340
20614
|
claude: teardownClaude,
|
|
@@ -20343,7 +20617,8 @@ var TEARDOWN_FN = {
|
|
|
20343
20617
|
codex: teardownCodex,
|
|
20344
20618
|
windsurf: teardownWindsurf,
|
|
20345
20619
|
vscode: teardownVSCode,
|
|
20346
|
-
claudeDesktop: teardownClaudeDesktop
|
|
20620
|
+
claudeDesktop: teardownClaudeDesktop,
|
|
20621
|
+
opencode: teardownOpencode
|
|
20347
20622
|
};
|
|
20348
20623
|
var AGENT_NAMES = Object.keys(SETUP_FN);
|
|
20349
20624
|
function registerAgentsCommand(program2) {
|
package/dist/dashboard.mjs
CHANGED
|
@@ -3340,6 +3340,13 @@ var init_mcp_pin = __esm({
|
|
|
3340
3340
|
}
|
|
3341
3341
|
});
|
|
3342
3342
|
|
|
3343
|
+
// src/setup-opencode-shim.ts
|
|
3344
|
+
var init_setup_opencode_shim = __esm({
|
|
3345
|
+
"src/setup-opencode-shim.ts"() {
|
|
3346
|
+
"use strict";
|
|
3347
|
+
}
|
|
3348
|
+
});
|
|
3349
|
+
|
|
3343
3350
|
// src/setup.ts
|
|
3344
3351
|
import chalk2 from "chalk";
|
|
3345
3352
|
import { confirm } from "@inquirer/prompts";
|
|
@@ -3348,6 +3355,7 @@ var init_setup = __esm({
|
|
|
3348
3355
|
"src/setup.ts"() {
|
|
3349
3356
|
"use strict";
|
|
3350
3357
|
init_mcp_pin();
|
|
3358
|
+
init_setup_opencode_shim();
|
|
3351
3359
|
}
|
|
3352
3360
|
});
|
|
3353
3361
|
|