@sideboard-ai/core 0.1.287 → 0.1.288
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/{abletime-I4RODUKT.js → abletime-4WJUVE64.js} +4 -4
- package/dist/{abletime-4CH2IOX5.js → abletime-VFKYNSJT.js} +4 -4
- package/dist/{abletime-oauth-7OZZ3ABX.js → abletime-oauth-FW24YHYX.js} +3 -3
- package/dist/{abletime-oauth-C2HN2Q6F.js → abletime-oauth-ICMB2XV2.js} +3 -3
- package/dist/{abletime-rest-E4LBRFLM.js → abletime-rest-HFMRTUDT.js} +3 -3
- package/dist/{abletime-rest-WFI2HWBU.js → abletime-rest-OGWC7BC6.js} +3 -3
- package/dist/agents/cursor-runner.js +3 -3
- package/dist/{agents-D3PU4UCP.js → agents-GZLTMGSH.js} +19 -17
- package/dist/{agents-KU4QPB3Y.js → agents-UQMHFZSM.js} +17 -15
- package/dist/{app-settings-EQQZQNYD.js → app-settings-EHMXHNG5.js} +1 -1
- package/dist/{app-settings-NI4X5HW3.js → app-settings-MR2U6AXN.js} +1 -1
- package/dist/{chunk-UFJLNCOF.js → chunk-2N77CLRQ.js} +8 -298
- package/dist/{chunk-YNTXWFXT.js → chunk-36J3IZBS.js} +12 -12
- package/dist/{chunk-IJMUYHPT.js → chunk-3E4NOIXN.js} +3 -3
- package/dist/{chunk-5MGLNVNK.js → chunk-3W5SL5EW.js} +1 -1
- package/dist/{chunk-QPBR5SAL.js → chunk-442O6OXM.js} +25 -127
- package/dist/chunk-4BXRRHDC.js +139 -0
- package/dist/{chunk-RFPMTOV2.js → chunk-4NM72HJZ.js} +5 -5
- package/dist/{chunk-Z3EE3PUZ.js → chunk-6NVQNTJO.js} +10 -300
- package/dist/{chunk-VOIWX5HA.js → chunk-7UUILVMV.js} +1 -1
- package/dist/chunk-AF2DMY3K.js +295 -0
- package/dist/{chunk-5QOLFOAX.js → chunk-AFLNFGGB.js} +1 -1
- package/dist/{chunk-5T4YWFLD.js → chunk-AHH5USEA.js} +2 -2
- package/dist/{chunk-6CVVNAIU.js → chunk-B3BPLPKQ.js} +2 -2
- package/dist/{chunk-ZGAMETNF.js → chunk-DBOFDEQ7.js} +3 -3
- package/dist/{chunk-VQEARG5H.js → chunk-GU6DT6NO.js} +5 -5
- package/dist/{chunk-K5XSTHHP.js → chunk-HNB2HTCV.js} +1 -1
- package/dist/{chunk-KLAQ4G34.js → chunk-IA4MPG7F.js} +3 -3
- package/dist/{chunk-S2OOM7AU.js → chunk-K6IOJI3L.js} +1 -1
- package/dist/{chunk-U6QDXT4K.js → chunk-MIVX7QKI.js} +1 -1
- package/dist/{chunk-WRIMAEF2.js → chunk-MVZO7QZ2.js} +12 -12
- package/dist/{chunk-LS4FFCPL.js → chunk-MYJYINTS.js} +3 -3
- package/dist/{chunk-DEJALWKM.js → chunk-NFPWLDCH.js} +5 -5
- package/dist/chunk-NXXQFLNQ.js +300 -0
- package/dist/chunk-OH4EN323.js +89 -0
- package/dist/chunk-W2KZTDET.js +302 -0
- package/dist/{chunk-L65YT2SC.js → chunk-WQSIUZEB.js} +6 -6
- package/dist/{chunk-LKVP7JCB.js → chunk-WW5XGEMY.js} +33 -313
- package/dist/{chunk-TMM4FEZ5.js → chunk-Y67TBJD5.js} +3 -3
- package/dist/{chunk-XSDCLM3F.js → chunk-YSLCWCMJ.js} +1 -1
- package/dist/{conductor-FOKYVMUE.js → conductor-MCU63Z5U.js} +5 -5
- package/dist/{conductor-KDUL6AMD.js → conductor-ZLYZVIAV.js} +6 -6
- package/dist/{coordinator-prompt-GU5PGLG6.js → coordinator-prompt-KHCXXDRO.js} +3 -3
- package/dist/{coordinator-prompt-YARYX53V.js → coordinator-prompt-UV6THLMD.js} +3 -3
- package/dist/{global-workspace-C5HMC66E.js → global-workspace-AXTSYVAE.js} +3 -3
- package/dist/{global-workspace-SMCPOWE5.js → global-workspace-GDHZSFP6.js} +3 -3
- package/dist/index.cjs +469 -274
- package/dist/index.d.cts +24 -8
- package/dist/index.d.ts +24 -8
- package/dist/index.js +369 -256
- package/dist/mcp/run-stdio.cjs +602 -225
- package/dist/mcp/run-stdio.js +333 -187
- package/dist/optional-cli-6SW4OOX3.js +23 -0
- package/dist/optional-cli-FRUZSZ3U.js +98 -0
- package/dist/{orchestrator-NWKE56BW.js → orchestrator-5ZBHR6BJ.js} +9 -7
- package/dist/{orchestrator-2UAVOXTN.js → orchestrator-SDH6W6ZL.js} +12 -10
- package/dist/{workspaces-DQMDCRB2.js → workspaces-L2UR4KC2.js} +3 -3
- package/dist/{workspaces-KHQ5ETSQ.js → workspaces-Q2R2XGO3.js} +3 -3
- package/dist/{worktree-NKLNVNXX.js → worktree-2GOK4VYT.js} +2 -2
- package/dist/{worktree-YTZC3UQN.js → worktree-YEUTJ7MZ.js} +2 -2
- package/package.json +1 -1
|
@@ -9,16 +9,16 @@ import {
|
|
|
9
9
|
looksLikeSkillBody,
|
|
10
10
|
skillCommandFromBody,
|
|
11
11
|
withEventParentId
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YSLCWCMJ.js";
|
|
13
13
|
import {
|
|
14
14
|
isOrchestratorThread
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-DBOFDEQ7.js";
|
|
16
16
|
import {
|
|
17
17
|
codexUnattendedGitConfigArgs,
|
|
18
18
|
mergeAgentGitAuthEnv,
|
|
19
19
|
resolveAgentGitAuthEnv,
|
|
20
20
|
resolveCodexGitWritableRoots
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HNB2HTCV.js";
|
|
22
22
|
import {
|
|
23
23
|
loadBrightsyConfig
|
|
24
24
|
} from "./chunk-33KDPEK4.js";
|
|
@@ -38,19 +38,15 @@ import {
|
|
|
38
38
|
packagedMcpStdioPath,
|
|
39
39
|
parseCursorRunnerLine,
|
|
40
40
|
resolveNodeLaunch
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-7UUILVMV.js";
|
|
42
42
|
import {
|
|
43
43
|
extractJsonErrorMessage,
|
|
44
44
|
formatUnknownDetail,
|
|
45
45
|
looksLikeAgentFailureMessage,
|
|
46
46
|
looksLikeBrightsyEmptyCompletion
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-MIVX7QKI.js";
|
|
48
48
|
import {
|
|
49
|
-
|
|
50
|
-
isConductorBundledCli,
|
|
51
|
-
resolveCommandBinarySync,
|
|
52
|
-
run,
|
|
53
|
-
withExportedPath
|
|
49
|
+
run
|
|
54
50
|
} from "./chunk-QVN2WOKJ.js";
|
|
55
51
|
import {
|
|
56
52
|
AGENT_RPC_CLAUDE_SDK_SERVER,
|
|
@@ -71,7 +67,7 @@ import {
|
|
|
71
67
|
loadAppSettings,
|
|
72
68
|
resolveAgentExecutable,
|
|
73
69
|
resolveClaudeExecutable
|
|
74
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-36J3IZBS.js";
|
|
75
71
|
import {
|
|
76
72
|
isElectronLikeCommand,
|
|
77
73
|
unwrapStrippedElectronLaunch
|
|
@@ -716,7 +712,8 @@ var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
|
|
|
716
712
|
"mcp__sideboard__create_schedule",
|
|
717
713
|
"mcp__sideboard__update_schedule",
|
|
718
714
|
"mcp__sideboard__delete_schedule",
|
|
719
|
-
"mcp__sideboard__run_schedule"
|
|
715
|
+
"mcp__sideboard__run_schedule",
|
|
716
|
+
"mcp__sideboard__posthog_api"
|
|
720
717
|
];
|
|
721
718
|
var SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS = ["mcp__sideboard__github_*"];
|
|
722
719
|
var SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS = ["mcp__sideboard__linear_*"];
|
|
@@ -1755,7 +1752,7 @@ var claudeAdapter = {
|
|
|
1755
1752
|
);
|
|
1756
1753
|
}
|
|
1757
1754
|
const mode = permissionMode(thread);
|
|
1758
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
1755
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-AXTSYVAE.js");
|
|
1759
1756
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
1760
1757
|
const rpc = worktreeAgentRpc(isOrchestrator);
|
|
1761
1758
|
const injectedServers = await buildInjectedMcpServers({
|
|
@@ -3647,283 +3644,6 @@ async function getClaudePlanUsage(opts = {}) {
|
|
|
3647
3644
|
return inflight;
|
|
3648
3645
|
}
|
|
3649
3646
|
|
|
3650
|
-
// src/agents/install.ts
|
|
3651
|
-
import { existsSync as existsSync11 } from "fs";
|
|
3652
|
-
var SETUP = {
|
|
3653
|
-
claude: {
|
|
3654
|
-
agent: "claude",
|
|
3655
|
-
kind: "cli",
|
|
3656
|
-
summary: "Install the Claude Code CLI, then complete login in a terminal.",
|
|
3657
|
-
docsUrl: "https://code.claude.com/docs/en/install",
|
|
3658
|
-
installCommand: "npm install -g @anthropic-ai/claude-code",
|
|
3659
|
-
loginCommand: "claude auth login",
|
|
3660
|
-
npmPackage: "@anthropic-ai/claude-code",
|
|
3661
|
-
updateArgs: ["update"]
|
|
3662
|
-
},
|
|
3663
|
-
codex: {
|
|
3664
|
-
agent: "codex",
|
|
3665
|
-
kind: "cli",
|
|
3666
|
-
summary: "Install the Codex CLI, then run login in a terminal.",
|
|
3667
|
-
docsUrl: "https://github.com/openai/codex",
|
|
3668
|
-
installCommand: "npm install -g @openai/codex",
|
|
3669
|
-
loginCommand: "codex login",
|
|
3670
|
-
npmPackage: "@openai/codex",
|
|
3671
|
-
updateArgs: ["update"]
|
|
3672
|
-
},
|
|
3673
|
-
opencode: {
|
|
3674
|
-
agent: "opencode",
|
|
3675
|
-
kind: "cli",
|
|
3676
|
-
summary: "Install OpenCode (curl installer or npm), then authenticate providers.",
|
|
3677
|
-
docsUrl: "https://opencode.ai/docs",
|
|
3678
|
-
// Prefer the official installer; npm package name is opencode-ai.
|
|
3679
|
-
installCommand: "curl -fsSL https://opencode.ai/install | bash",
|
|
3680
|
-
loginCommand: "opencode auth login",
|
|
3681
|
-
npmPackage: "opencode-ai@latest",
|
|
3682
|
-
updateArgs: ["upgrade"]
|
|
3683
|
-
},
|
|
3684
|
-
cursor: {
|
|
3685
|
-
agent: "cursor",
|
|
3686
|
-
kind: "cli",
|
|
3687
|
-
summary: "Install (or update) @cursor/sdk with npm \u2014 Sideboard does not pin it in the app. Then add a CURSOR_API_KEY.",
|
|
3688
|
-
docsUrl: "https://www.npmjs.com/package/@cursor/sdk",
|
|
3689
|
-
installCommand: "npm install -g @cursor/sdk",
|
|
3690
|
-
loginCommand: null,
|
|
3691
|
-
npmPackage: "@cursor/sdk"
|
|
3692
|
-
},
|
|
3693
|
-
brightsy: {
|
|
3694
|
-
agent: "brightsy",
|
|
3695
|
-
kind: "cli",
|
|
3696
|
-
summary: "Install (or update) the Brightsy CLI with npm, then run `brightsy login`.",
|
|
3697
|
-
docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
|
|
3698
|
-
installCommand: "npm install -g @brightsy/cli",
|
|
3699
|
-
loginCommand: "brightsy login",
|
|
3700
|
-
npmPackage: "@brightsy/cli"
|
|
3701
|
-
}
|
|
3702
|
-
};
|
|
3703
|
-
var CLI_BIN = {
|
|
3704
|
-
claude: "claude",
|
|
3705
|
-
codex: "codex",
|
|
3706
|
-
opencode: "opencode",
|
|
3707
|
-
brightsy: "brightsy"
|
|
3708
|
-
};
|
|
3709
|
-
function getAgentSetupInfo(agent) {
|
|
3710
|
-
return SETUP[agent];
|
|
3711
|
-
}
|
|
3712
|
-
function listAgentSetupInfo() {
|
|
3713
|
-
return Object.values(SETUP);
|
|
3714
|
-
}
|
|
3715
|
-
var CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
|
|
3716
|
-
"claude",
|
|
3717
|
-
"codex",
|
|
3718
|
-
"opencode",
|
|
3719
|
-
"brightsy"
|
|
3720
|
-
]);
|
|
3721
|
-
function resolveLoginCommand(agent) {
|
|
3722
|
-
const info = getAgentSetupInfo(agent);
|
|
3723
|
-
if (!info.loginCommand) return null;
|
|
3724
|
-
if (!CLI_LOGIN_AGENTS.has(agent)) return info.loginCommand;
|
|
3725
|
-
const exe = resolveAgentExecutable(agent);
|
|
3726
|
-
return info.loginCommand.replace(/^\S+/, exe);
|
|
3727
|
-
}
|
|
3728
|
-
async function prepareTerminalCommand(command) {
|
|
3729
|
-
enrichPathWithNpmGlobalBin();
|
|
3730
|
-
const trimmed = command.trim();
|
|
3731
|
-
if (!trimmed) return trimmed;
|
|
3732
|
-
if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
|
|
3733
|
-
const match = /^(\S+)(\s[\s\S]*)?$/.exec(trimmed);
|
|
3734
|
-
const bin = match?.[1];
|
|
3735
|
-
let whichPath = null;
|
|
3736
|
-
if (bin && !bin.includes("/") && !bin.includes("\\")) {
|
|
3737
|
-
const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
|
|
3738
|
-
whichPath = which.exitCode === 0 ? which.stdout.trim() : null;
|
|
3739
|
-
}
|
|
3740
|
-
const resolved = resolveCommandBinarySync(trimmed, whichPath);
|
|
3741
|
-
return withExportedPath(resolved, process.env.PATH ?? "");
|
|
3742
|
-
}
|
|
3743
|
-
async function openInSystemTerminal(command) {
|
|
3744
|
-
const trimmed = (await prepareTerminalCommand(command)).trim();
|
|
3745
|
-
if (!trimmed) throw new Error("Command is empty");
|
|
3746
|
-
if (process.platform === "darwin") {
|
|
3747
|
-
const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
3748
|
-
const script = `tell application "Terminal" to do script "${escaped}"`;
|
|
3749
|
-
const result = await run("osascript", ["-e", script], { reject: false });
|
|
3750
|
-
if (result.exitCode !== 0) {
|
|
3751
|
-
throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open Terminal");
|
|
3752
|
-
}
|
|
3753
|
-
await run("osascript", ["-e", 'tell application "Terminal" to activate'], {
|
|
3754
|
-
reject: false
|
|
3755
|
-
});
|
|
3756
|
-
return;
|
|
3757
|
-
}
|
|
3758
|
-
if (process.platform === "win32") {
|
|
3759
|
-
const result = await run(
|
|
3760
|
-
"cmd.exe",
|
|
3761
|
-
["/c", "start", "cmd.exe", "/k", trimmed],
|
|
3762
|
-
{ reject: false }
|
|
3763
|
-
);
|
|
3764
|
-
if (result.exitCode !== 0) {
|
|
3765
|
-
throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open cmd");
|
|
3766
|
-
}
|
|
3767
|
-
return;
|
|
3768
|
-
}
|
|
3769
|
-
const candidates = [
|
|
3770
|
-
{ file: "gnome-terminal", args: ["--", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
3771
|
-
{ file: "x-terminal-emulator", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
3772
|
-
{ file: "konsole", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
|
|
3773
|
-
{ file: "xterm", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] }
|
|
3774
|
-
];
|
|
3775
|
-
for (const c of candidates) {
|
|
3776
|
-
const which = await run("which", [c.file], { reject: false });
|
|
3777
|
-
if (which.exitCode !== 0 || !which.stdout.trim()) continue;
|
|
3778
|
-
const result = await run(c.file, c.args, { reject: false });
|
|
3779
|
-
if (result.exitCode === 0) return;
|
|
3780
|
-
}
|
|
3781
|
-
throw new Error(
|
|
3782
|
-
`No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
|
|
3783
|
-
);
|
|
3784
|
-
}
|
|
3785
|
-
async function whichOnPath(bin) {
|
|
3786
|
-
const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
|
|
3787
|
-
if (which.exitCode !== 0) return null;
|
|
3788
|
-
return which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null;
|
|
3789
|
-
}
|
|
3790
|
-
async function installNpmGlobalPackage(opts) {
|
|
3791
|
-
enrichPathWithNpmGlobalBin();
|
|
3792
|
-
const result = await run("npm", ["install", "-g", opts.npmPackage], { reject: false });
|
|
3793
|
-
const ok = result.exitCode === 0;
|
|
3794
|
-
if (!ok) {
|
|
3795
|
-
try {
|
|
3796
|
-
await openInSystemTerminal(opts.installCommand);
|
|
3797
|
-
return {
|
|
3798
|
-
ok: false,
|
|
3799
|
-
openedTerminal: true,
|
|
3800
|
-
command: opts.installCommand,
|
|
3801
|
-
exitCode: result.exitCode,
|
|
3802
|
-
stdout: result.stdout,
|
|
3803
|
-
stderr: result.stderr,
|
|
3804
|
-
message: `npm install failed (exit ${result.exitCode}). Opened Terminal with: ${opts.installCommand}`
|
|
3805
|
-
};
|
|
3806
|
-
} catch {
|
|
3807
|
-
return {
|
|
3808
|
-
ok: false,
|
|
3809
|
-
command: opts.installCommand,
|
|
3810
|
-
exitCode: result.exitCode,
|
|
3811
|
-
stdout: result.stdout,
|
|
3812
|
-
stderr: result.stderr,
|
|
3813
|
-
message: result.stderr.trim() || result.stdout.trim() || `npm install failed (exit ${result.exitCode})`
|
|
3814
|
-
};
|
|
3815
|
-
}
|
|
3816
|
-
}
|
|
3817
|
-
enrichPathWithNpmGlobalBin();
|
|
3818
|
-
const binPath = opts.cliBin ? await whichOnPath(opts.cliBin) : null;
|
|
3819
|
-
return {
|
|
3820
|
-
ok: true,
|
|
3821
|
-
command: opts.installCommand,
|
|
3822
|
-
exitCode: 0,
|
|
3823
|
-
stdout: result.stdout,
|
|
3824
|
-
stderr: result.stderr,
|
|
3825
|
-
// Library-only packages (`@cursor/sdk`) have no CLI to look for.
|
|
3826
|
-
message: !opts.cliBin ? `Installed ${opts.npmPackage}` : binPath ? `Installed ${opts.npmPackage} \u2192 ${binPath}` : `Installed ${opts.npmPackage} (CLI not yet on PATH)`
|
|
3827
|
-
};
|
|
3828
|
-
}
|
|
3829
|
-
async function resolveExistingCli(agent) {
|
|
3830
|
-
if (agent === "cursor") return null;
|
|
3831
|
-
const exe = resolveAgentExecutable(agent);
|
|
3832
|
-
if ((exe.includes("/") || exe.includes("\\")) && existsSync11(exe)) return exe;
|
|
3833
|
-
enrichPathWithNpmGlobalBin();
|
|
3834
|
-
return whichOnPath(CLI_BIN[agent]);
|
|
3835
|
-
}
|
|
3836
|
-
async function runVendorUpdate(existing, updateArgs) {
|
|
3837
|
-
const result = await run(existing, updateArgs, {
|
|
3838
|
-
reject: false,
|
|
3839
|
-
timeoutMs: 12e4
|
|
3840
|
-
});
|
|
3841
|
-
const command = `${existing} ${updateArgs.join(" ")}`;
|
|
3842
|
-
const ok = result.exitCode === 0;
|
|
3843
|
-
const detail = result.stdout.trim() || result.stderr.trim() || `exit ${result.exitCode}`;
|
|
3844
|
-
return {
|
|
3845
|
-
ok,
|
|
3846
|
-
command,
|
|
3847
|
-
exitCode: result.exitCode,
|
|
3848
|
-
stdout: result.stdout,
|
|
3849
|
-
stderr: result.stderr,
|
|
3850
|
-
message: ok ? isConductorBundledCli(existing) ? `Updated Conductor\u2019s CLI at ${existing}. ${detail}` : `Updated ${command}. ${detail}` : `Update failed (${command}): ${detail}`
|
|
3851
|
-
};
|
|
3852
|
-
}
|
|
3853
|
-
function isCurlInstaller(command) {
|
|
3854
|
-
return /curl\s| \|\s*bash/.test(command);
|
|
3855
|
-
}
|
|
3856
|
-
async function installAgent(agent) {
|
|
3857
|
-
const info = getAgentSetupInfo(agent);
|
|
3858
|
-
if (info.kind === "bundled-sdk" || info.kind === "api-key") {
|
|
3859
|
-
return {
|
|
3860
|
-
ok: true,
|
|
3861
|
-
message: info.summary
|
|
3862
|
-
};
|
|
3863
|
-
}
|
|
3864
|
-
if (!info.installCommand) {
|
|
3865
|
-
return { ok: false, message: `No install command for ${agent}` };
|
|
3866
|
-
}
|
|
3867
|
-
const existing = await resolveExistingCli(agent);
|
|
3868
|
-
if (existing && info.updateArgs?.length) {
|
|
3869
|
-
return runVendorUpdate(existing, info.updateArgs);
|
|
3870
|
-
}
|
|
3871
|
-
if (info.npmPackage && !isCurlInstaller(info.installCommand)) {
|
|
3872
|
-
const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
|
|
3873
|
-
return installNpmGlobalPackage({
|
|
3874
|
-
npmPackage: info.npmPackage,
|
|
3875
|
-
installCommand: info.installCommand,
|
|
3876
|
-
cliBin
|
|
3877
|
-
});
|
|
3878
|
-
}
|
|
3879
|
-
await openInSystemTerminal(info.installCommand);
|
|
3880
|
-
return {
|
|
3881
|
-
ok: true,
|
|
3882
|
-
openedTerminal: true,
|
|
3883
|
-
command: info.installCommand,
|
|
3884
|
-
message: `Opened Terminal to run: ${info.installCommand}`
|
|
3885
|
-
};
|
|
3886
|
-
}
|
|
3887
|
-
async function loginAgent(agent) {
|
|
3888
|
-
const info = getAgentSetupInfo(agent);
|
|
3889
|
-
const loginCommand = resolveLoginCommand(agent);
|
|
3890
|
-
if (!loginCommand) {
|
|
3891
|
-
return {
|
|
3892
|
-
ok: true,
|
|
3893
|
-
message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
|
|
3894
|
-
};
|
|
3895
|
-
}
|
|
3896
|
-
const prepared = await prepareTerminalCommand(loginCommand);
|
|
3897
|
-
await openInSystemTerminal(prepared);
|
|
3898
|
-
return {
|
|
3899
|
-
ok: true,
|
|
3900
|
-
openedTerminal: true,
|
|
3901
|
-
command: prepared,
|
|
3902
|
-
message: `Opened Terminal to run: ${prepared}`
|
|
3903
|
-
};
|
|
3904
|
-
}
|
|
3905
|
-
async function loginManagedAccount(accountId) {
|
|
3906
|
-
const { loadAppSettings: loadAppSettings2 } = await import("./app-settings-NI4X5HW3.js");
|
|
3907
|
-
const { loginEnvPrefix } = await import("./managed-accounts-2AK5RIAF.js");
|
|
3908
|
-
const account = loadAppSettings2().accounts.accounts.find((a) => a.id === accountId);
|
|
3909
|
-
if (!account) {
|
|
3910
|
-
return { ok: false, message: `Account not found: ${accountId}` };
|
|
3911
|
-
}
|
|
3912
|
-
const loginCommand = resolveLoginCommand(account.kind);
|
|
3913
|
-
if (!loginCommand) {
|
|
3914
|
-
return { ok: false, message: `No login command for ${account.kind}` };
|
|
3915
|
-
}
|
|
3916
|
-
const prepared = await prepareTerminalCommand(loginCommand);
|
|
3917
|
-
const prefixed = `${loginEnvPrefix(account)} && ${prepared}`;
|
|
3918
|
-
await openInSystemTerminal(prefixed);
|
|
3919
|
-
return {
|
|
3920
|
-
ok: true,
|
|
3921
|
-
openedTerminal: true,
|
|
3922
|
-
command: prefixed,
|
|
3923
|
-
message: `Opened Terminal to run: ${prefixed}`
|
|
3924
|
-
};
|
|
3925
|
-
}
|
|
3926
|
-
|
|
3927
3647
|
// src/agents/index.ts
|
|
3928
3648
|
var adapters = {
|
|
3929
3649
|
claude: claudeAdapter,
|
|
@@ -4018,16 +3738,6 @@ export {
|
|
|
4018
3738
|
formatClaudeUsageOverLimitConfirm,
|
|
4019
3739
|
formatClaudeUsageOverLimitWait,
|
|
4020
3740
|
getClaudePlanUsage,
|
|
4021
|
-
getAgentSetupInfo,
|
|
4022
|
-
listAgentSetupInfo,
|
|
4023
|
-
resolveLoginCommand,
|
|
4024
|
-
prepareTerminalCommand,
|
|
4025
|
-
openInSystemTerminal,
|
|
4026
|
-
whichOnPath,
|
|
4027
|
-
installNpmGlobalPackage,
|
|
4028
|
-
installAgent,
|
|
4029
|
-
loginAgent,
|
|
4030
|
-
loginManagedAccount,
|
|
4031
3741
|
getAdapter,
|
|
4032
3742
|
allAdapters
|
|
4033
3743
|
};
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import {
|
|
2
|
+
httpFetch
|
|
3
|
+
} from "./chunk-JAT3JFOS.js";
|
|
4
|
+
import {
|
|
5
|
+
loadAppSettings,
|
|
6
|
+
saveAppSettings
|
|
7
|
+
} from "./chunk-36J3IZBS.js";
|
|
8
|
+
|
|
9
|
+
// src/integrations/optional-services.ts
|
|
10
|
+
var OPTIONAL_SERVICE_IDS = ["vercel", "supabase", "posthog", "sentry"];
|
|
11
|
+
var OPTIONAL_SERVICES = [
|
|
12
|
+
{
|
|
13
|
+
id: "vercel",
|
|
14
|
+
label: "Vercel",
|
|
15
|
+
hint: "Deploys and project settings. Agents use the `vercel` CLI (`VERCEL_TOKEN`).",
|
|
16
|
+
tokenPlaceholder: "token from vercel.com/account/tokens",
|
|
17
|
+
tokenDocs: "https://vercel.com/account/tokens",
|
|
18
|
+
envKey: "VERCEL_TOKEN",
|
|
19
|
+
cli: "vercel",
|
|
20
|
+
npmPackage: "vercel"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "supabase",
|
|
24
|
+
label: "Supabase",
|
|
25
|
+
hint: "Database and project management. Agents use the `supabase` CLI (`SUPABASE_ACCESS_TOKEN`).",
|
|
26
|
+
tokenPlaceholder: "sbp_\u2026",
|
|
27
|
+
tokenDocs: "https://supabase.com/dashboard/account/tokens",
|
|
28
|
+
envKey: "SUPABASE_ACCESS_TOKEN",
|
|
29
|
+
cli: "supabase",
|
|
30
|
+
npmPackage: "supabase"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "posthog",
|
|
34
|
+
label: "PostHog",
|
|
35
|
+
hint: "Product analytics. Agents call `posthog_api` on the Sideboard MCP server.",
|
|
36
|
+
tokenPlaceholder: "phx_\u2026",
|
|
37
|
+
tokenDocs: "https://app.posthog.com/settings/user-api-keys",
|
|
38
|
+
envKey: "POSTHOG_PERSONAL_API_KEY",
|
|
39
|
+
hostEnvKey: "POSTHOG_HOST",
|
|
40
|
+
defaultHost: "https://us.posthog.com",
|
|
41
|
+
hostPlaceholder: "https://us.posthog.com"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: "sentry",
|
|
45
|
+
label: "Sentry",
|
|
46
|
+
hint: "Error tracking. Agents use `sentry-cli` (`SENTRY_AUTH_TOKEN`).",
|
|
47
|
+
tokenPlaceholder: "sntrys_\u2026 or auth token",
|
|
48
|
+
tokenDocs: "https://sentry.io/settings/account/api/auth-tokens/",
|
|
49
|
+
envKey: "SENTRY_AUTH_TOKEN",
|
|
50
|
+
cli: "sentry-cli",
|
|
51
|
+
npmPackage: "@sentry/cli",
|
|
52
|
+
hostEnvKey: "SENTRY_URL",
|
|
53
|
+
defaultHost: "https://sentry.io",
|
|
54
|
+
hostPlaceholder: "https://sentry.io"
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
function optionalServiceSpec(id) {
|
|
58
|
+
const spec = OPTIONAL_SERVICES.find((s) => s.id === id);
|
|
59
|
+
if (!spec) throw new Error(`Unknown optional service: ${id}`);
|
|
60
|
+
return spec;
|
|
61
|
+
}
|
|
62
|
+
function isOptionalServiceId(value) {
|
|
63
|
+
return typeof value === "string" && OPTIONAL_SERVICE_IDS.includes(value);
|
|
64
|
+
}
|
|
65
|
+
function normalizeServiceOrigin(raw, fallback) {
|
|
66
|
+
const trimmed = raw?.trim() || fallback;
|
|
67
|
+
try {
|
|
68
|
+
const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
|
|
69
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return fallback;
|
|
70
|
+
return `${url.protocol}//${url.host}`;
|
|
71
|
+
} catch {
|
|
72
|
+
return fallback;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function asRecord(value) {
|
|
76
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
77
|
+
}
|
|
78
|
+
function asString(value) {
|
|
79
|
+
return typeof value === "string" ? value.trim() : "";
|
|
80
|
+
}
|
|
81
|
+
function firstString(record, keys) {
|
|
82
|
+
if (!record) return "";
|
|
83
|
+
for (const key of keys) {
|
|
84
|
+
const value = asString(record[key]);
|
|
85
|
+
if (value) return value;
|
|
86
|
+
}
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
async function readJson(res) {
|
|
90
|
+
const text = await res.text();
|
|
91
|
+
if (!text.trim()) return null;
|
|
92
|
+
try {
|
|
93
|
+
return JSON.parse(text);
|
|
94
|
+
} catch {
|
|
95
|
+
return text;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async function authorizedGet(url, token) {
|
|
99
|
+
const res = await httpFetch(url, {
|
|
100
|
+
method: "GET",
|
|
101
|
+
headers: {
|
|
102
|
+
Authorization: `Bearer ${token}`,
|
|
103
|
+
Accept: "application/json"
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const body = await readJson(res);
|
|
107
|
+
if (!res.ok) {
|
|
108
|
+
const record = asRecord(body);
|
|
109
|
+
const message = firstString(record, ["message", "error", "error_description", "detail"]) || (typeof body === "string" ? body.trim().slice(0, 160) : "");
|
|
110
|
+
throw new Error(
|
|
111
|
+
message ? `${res.status}: ${message}` : `Request failed (${res.status})`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return body;
|
|
115
|
+
}
|
|
116
|
+
async function verifyOptionalService(input) {
|
|
117
|
+
const token = input.token.trim();
|
|
118
|
+
if (!token) throw new Error("A token is required");
|
|
119
|
+
const spec = optionalServiceSpec(input.id);
|
|
120
|
+
try {
|
|
121
|
+
if (input.id === "vercel") {
|
|
122
|
+
const body2 = asRecord(await authorizedGet("https://api.vercel.com/v2/user", token));
|
|
123
|
+
const user = asRecord(body2?.user) ?? body2;
|
|
124
|
+
const name2 = firstString(user, ["username", "name", "email"]) || "Vercel user";
|
|
125
|
+
return { viewerName: name2 };
|
|
126
|
+
}
|
|
127
|
+
if (input.id === "supabase") {
|
|
128
|
+
const body2 = await authorizedGet("https://api.supabase.com/v1/organizations", token);
|
|
129
|
+
const list2 = Array.isArray(body2) ? body2 : [];
|
|
130
|
+
const first2 = asRecord(list2[0]);
|
|
131
|
+
const name2 = firstString(first2, ["name", "slug"]) || "Supabase";
|
|
132
|
+
return { viewerName: list2.length > 1 ? `${name2} +${list2.length - 1}` : name2 };
|
|
133
|
+
}
|
|
134
|
+
if (input.id === "posthog") {
|
|
135
|
+
const host2 = normalizeServiceOrigin(input.host, spec.defaultHost ?? "https://us.posthog.com");
|
|
136
|
+
const body2 = asRecord(await authorizedGet(`${host2}/api/users/@me/`, token));
|
|
137
|
+
const name2 = firstString(body2, ["email", "distinct_id"]) || [firstString(body2, ["first_name"]), firstString(body2, ["last_name"])].filter(Boolean).join(" ") || "PostHog user";
|
|
138
|
+
return { viewerName: name2, host: host2 };
|
|
139
|
+
}
|
|
140
|
+
const host = normalizeServiceOrigin(input.host, spec.defaultHost ?? "https://sentry.io");
|
|
141
|
+
const body = await authorizedGet(`${host}/api/0/organizations/`, token);
|
|
142
|
+
const list = Array.isArray(body) ? body : [];
|
|
143
|
+
const first = asRecord(list[0]);
|
|
144
|
+
const name = firstString(first, ["slug", "name"]) || "Sentry";
|
|
145
|
+
return { viewerName: list.length > 1 ? `${name} +${list.length - 1}` : name, host };
|
|
146
|
+
} catch (err) {
|
|
147
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
148
|
+
throw new Error(
|
|
149
|
+
`${spec.label} rejected this token. ${detail} Create a token at ${spec.tokenDocs}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function applyConnection(integrations, id, input) {
|
|
154
|
+
if (id === "vercel") {
|
|
155
|
+
integrations.vercelToken = input.token;
|
|
156
|
+
if (input.viewerName) integrations.vercelViewerName = input.viewerName.slice(0, 120);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (id === "supabase") {
|
|
160
|
+
integrations.supabaseAccessToken = input.token;
|
|
161
|
+
if (input.viewerName) integrations.supabaseViewerName = input.viewerName.slice(0, 120);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (id === "posthog") {
|
|
165
|
+
integrations.posthogPersonalApiKey = input.token;
|
|
166
|
+
if (input.host) integrations.posthogHost = input.host;
|
|
167
|
+
if (input.viewerName) integrations.posthogViewerName = input.viewerName.slice(0, 120);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
integrations.sentryAuthToken = input.token;
|
|
171
|
+
if (input.host) integrations.sentryHost = input.host;
|
|
172
|
+
if (input.viewerName) integrations.sentryViewerName = input.viewerName.slice(0, 120);
|
|
173
|
+
}
|
|
174
|
+
function clearConnection(integrations, id) {
|
|
175
|
+
if (id === "vercel") {
|
|
176
|
+
delete integrations.vercelToken;
|
|
177
|
+
delete integrations.vercelViewerName;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (id === "supabase") {
|
|
181
|
+
delete integrations.supabaseAccessToken;
|
|
182
|
+
delete integrations.supabaseViewerName;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (id === "posthog") {
|
|
186
|
+
delete integrations.posthogPersonalApiKey;
|
|
187
|
+
delete integrations.posthogViewerName;
|
|
188
|
+
delete integrations.posthogHost;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
delete integrations.sentryAuthToken;
|
|
192
|
+
delete integrations.sentryViewerName;
|
|
193
|
+
delete integrations.sentryHost;
|
|
194
|
+
}
|
|
195
|
+
async function connectOptionalService(input) {
|
|
196
|
+
if (!isOptionalServiceId(input.id)) {
|
|
197
|
+
throw new Error("Unknown optional service");
|
|
198
|
+
}
|
|
199
|
+
const verified = await verifyOptionalService(input);
|
|
200
|
+
const current = loadAppSettings();
|
|
201
|
+
const integrations = { ...current.integrations };
|
|
202
|
+
applyConnection(integrations, input.id, {
|
|
203
|
+
token: input.token.trim(),
|
|
204
|
+
host: verified.host,
|
|
205
|
+
viewerName: verified.viewerName
|
|
206
|
+
});
|
|
207
|
+
return saveAppSettings({ ...current, integrations });
|
|
208
|
+
}
|
|
209
|
+
function disconnectOptionalService(id) {
|
|
210
|
+
if (!isOptionalServiceId(id)) {
|
|
211
|
+
throw new Error("Unknown optional service");
|
|
212
|
+
}
|
|
213
|
+
const current = loadAppSettings();
|
|
214
|
+
const integrations = { ...current.integrations };
|
|
215
|
+
clearConnection(integrations, id);
|
|
216
|
+
return saveAppSettings({ ...current, integrations });
|
|
217
|
+
}
|
|
218
|
+
function optionalServiceConnected(id, integrations) {
|
|
219
|
+
if (id === "vercel") return Boolean(integrations.vercelToken?.trim());
|
|
220
|
+
if (id === "supabase") return Boolean(integrations.supabaseAccessToken?.trim());
|
|
221
|
+
if (id === "posthog") return Boolean(integrations.posthogPersonalApiKey?.trim());
|
|
222
|
+
return Boolean(integrations.sentryAuthToken?.trim());
|
|
223
|
+
}
|
|
224
|
+
function connectedOptionalServices(integrations) {
|
|
225
|
+
return OPTIONAL_SERVICES.filter((spec) => optionalServiceConnected(spec.id, integrations));
|
|
226
|
+
}
|
|
227
|
+
function cliPresencePhrase(spec, cli) {
|
|
228
|
+
if (!spec.cli || !cli || !(spec.id in cli)) return "";
|
|
229
|
+
return cli[spec.id] ? " (installed)" : " (not installed \u2014 ask the user to press Install CLI in Settings \u2192 Connectors)";
|
|
230
|
+
}
|
|
231
|
+
function connectorDirectiveLine(spec, cli) {
|
|
232
|
+
const extras = spec.hostEnvKey ? ` / \`${spec.hostEnvKey}\`` : "";
|
|
233
|
+
if (spec.cli) {
|
|
234
|
+
return `- ${spec.label}: use \`${spec.cli}\` (\`${spec.envKey}\`${extras})${cliPresencePhrase(spec, cli)}. Do not add a ${spec.label} MCP.`;
|
|
235
|
+
}
|
|
236
|
+
return `- ${spec.label}: call \`posthog_api\`. Path must start with \`/api/\`. GET is the default. POST \`/api/projects/:id/query/\` or \`/api/environments/:id/query/\` is a read and does not need \`write=true\`. Other POST and PATCH require \`write=true\` only when the user asked to change data. Do not read the API key from the environment. Do not add a ${spec.label} MCP.`;
|
|
237
|
+
}
|
|
238
|
+
function connectorReminderBit(spec, cli) {
|
|
239
|
+
if (!spec.cli) return `${spec.label}: \`posthog_api\``;
|
|
240
|
+
const presence = cliPresencePhrase(spec, cli);
|
|
241
|
+
return `${spec.label}: \`${spec.cli}\`${presence}`;
|
|
242
|
+
}
|
|
243
|
+
function formatOptionalServicesDirective(integrations, cli) {
|
|
244
|
+
const connected = connectedOptionalServices(integrations);
|
|
245
|
+
if (connected.length === 0) return null;
|
|
246
|
+
const cliConnected = connected.some((spec) => spec.cli);
|
|
247
|
+
const lines = [
|
|
248
|
+
cliConnected ? "Optional connectors (connected \u2014 CLI tokens are already in this process env):" : "Optional connectors (connected):",
|
|
249
|
+
...connected.map((spec) => connectorDirectiveLine(spec, cli)),
|
|
250
|
+
cliConnected ? "If a connector MCP is listed but needsAuth or returns unauthorized, do not sign in to that MCP. CLI tokens are already in this process. Do not read a PostHog key from the environment." : "If a connector MCP is listed but needsAuth or returns unauthorized, do not sign in to that MCP. Do not read a PostHog key from the environment.",
|
|
251
|
+
"Do not add a vendor MCP. When a binary is missing, ask the user to press Install CLI in Settings \u2192 Connectors.",
|
|
252
|
+
"When you shell a connector CLI, write bulky output to `.context/cli/` and read a slice."
|
|
253
|
+
];
|
|
254
|
+
return lines.join("\n");
|
|
255
|
+
}
|
|
256
|
+
function formatOptionalServicesReminder(integrations, cli) {
|
|
257
|
+
const connected = connectedOptionalServices(integrations);
|
|
258
|
+
if (connected.length === 0) return null;
|
|
259
|
+
const bits = connected.map((spec) => connectorReminderBit(spec, cli)).join(". ");
|
|
260
|
+
const tokenBit = connected.some((spec) => spec.cli) ? "CLI tokens are already in this process. " : "";
|
|
261
|
+
return `Settings \u2192 Connectors: ${tokenBit}${bits}. If a connector MCP needsAuth or is unauthorized, ignore it and use the CLI or \`posthog_api\`. Do not add vendor MCPs. Do not read a PostHog key from the environment. Shell dumps from those CLIs go in \`.context/cli/\` \u2014 read a slice.`;
|
|
262
|
+
}
|
|
263
|
+
async function connectedCliPresence(integrations) {
|
|
264
|
+
const ids = connectedOptionalServices(integrations).filter((spec) => spec.cli).map((spec) => spec.id);
|
|
265
|
+
if (ids.length === 0) return void 0;
|
|
266
|
+
try {
|
|
267
|
+
const { optionalCliPresence } = await import("./optional-cli-6SW4OOX3.js");
|
|
268
|
+
return await optionalCliPresence(ids);
|
|
269
|
+
} catch {
|
|
270
|
+
return void 0;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
async function formatOptionalServicesDirectiveForTurn(integrations) {
|
|
274
|
+
return formatOptionalServicesDirective(integrations, await connectedCliPresence(integrations));
|
|
275
|
+
}
|
|
276
|
+
async function formatOptionalServicesReminderForTurn(integrations) {
|
|
277
|
+
return formatOptionalServicesReminder(integrations, await connectedCliPresence(integrations));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export {
|
|
281
|
+
OPTIONAL_SERVICE_IDS,
|
|
282
|
+
OPTIONAL_SERVICES,
|
|
283
|
+
optionalServiceSpec,
|
|
284
|
+
isOptionalServiceId,
|
|
285
|
+
normalizeServiceOrigin,
|
|
286
|
+
verifyOptionalService,
|
|
287
|
+
connectOptionalService,
|
|
288
|
+
disconnectOptionalService,
|
|
289
|
+
optionalServiceConnected,
|
|
290
|
+
connectedOptionalServices,
|
|
291
|
+
formatOptionalServicesDirective,
|
|
292
|
+
formatOptionalServicesReminder,
|
|
293
|
+
formatOptionalServicesDirectiveForTurn,
|
|
294
|
+
formatOptionalServicesReminderForTurn
|
|
295
|
+
};
|
|
@@ -272,7 +272,7 @@ function humanizeAgentFailDetail(detail) {
|
|
|
272
272
|
return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
|
|
273
273
|
}
|
|
274
274
|
if (looksLikeCodexMcpError(raw)) {
|
|
275
|
-
return `${raw} \u2014 skip that vendor MCP and continue (PostHog: Settings \u2192 Connectors
|
|
275
|
+
return `${raw} \u2014 skip that vendor MCP and continue (PostHog: Settings \u2192 Connectors and posthog_api).`;
|
|
276
276
|
}
|
|
277
277
|
if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
|
|
278
278
|
lower
|