🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@shadowob/connector

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@shadowob/connector - npm Package Compare versions

Comparing version
1.1.60
to
1.1.61
+632
dist/chunk-XCXCPSCG.js
// src/buddy-collaboration-guidance.ts
var BUDDY_COLLABORATION_SYSTEM_PROMPT = [
"Shadow Buddy collaboration rules:",
"- Treat a Buddy collaboration as a bounded IM conversation, not an open-ended work session.",
"- Speak only when you add a distinct useful point. If another Buddy already covered it, stay brief or stay silent.",
"- If you only agree, use a structured Shadow reaction action when available; otherwise stay silent instead of posting acknowledgement text.",
"- Later collaboration turns may be routed into a Shadow thread by the platform. Do not announce thread routing yourself.",
"- Match the density of the triggering message. Short chat gets a short reply; long analysis requires an explicit user pull.",
"- For Shadow Inbox task status changes, use the mounted shadowob CLI. The CLI consumes server-delivered task policy after status updates.",
"- Do not run tools, create memories, create skills, write files, promote tasks, or run demos unless a human explicitly asks for current action.",
"- Keep runtime logs, tool progress, memory updates, skill views, and self-improvement reviews private. Do not post them as chat messages.",
"- If the user says to stop, stay quiet, not implement, or just discuss, stop the action chain immediately."
].join("\n");
// src/cc-connect-fork.ts
var CC_CONNECT_FORK_REPO = "buggyblues/cc-connect";
var CC_CONNECT_FORK_REF = "8289423fa21e744e5fe625cba57b2c6c3c5c17ea";
var CC_CONNECT_FORK_SHORT_REF = CC_CONNECT_FORK_REF.slice(0, 7);
var CC_CONNECT_FORK_DOCS_URL = `https://github.com/${CC_CONNECT_FORK_REPO}/blob/main/docs/shadowob.md`;
// src/model-provider.ts
function normalizeConnectorModelProvider(provider) {
const baseUrl = provider?.baseUrl?.trim();
const apiKey = provider?.apiKey?.trim();
const openAIBaseUrl = provider?.openAIBaseUrl?.trim() || baseUrl;
const openAIApiKey = provider?.openAIApiKey?.trim() || apiKey;
const anthropicBaseUrl = provider?.anthropicBaseUrl?.trim();
const anthropicApiKey = provider?.anthropicApiKey?.trim();
const model = provider?.model?.trim();
if ((!openAIBaseUrl || !openAIApiKey) && (!anthropicBaseUrl || !anthropicApiKey)) return null;
if (!model) return null;
return {
id: provider?.id?.trim() || "shadow-official",
label: provider?.label?.trim() || "Shadow official LLM proxy",
baseUrl: openAIBaseUrl || anthropicBaseUrl,
apiKey: openAIApiKey || anthropicApiKey,
...openAIBaseUrl ? { openAIBaseUrl } : {},
...openAIApiKey ? { openAIApiKey } : {},
...anthropicBaseUrl ? { anthropicBaseUrl } : {},
...anthropicApiKey ? { anthropicApiKey } : {},
model
};
}
function connectorModelProviderEndpoint(provider, style) {
if (!provider) return null;
const baseUrl = style === "anthropic" ? provider.anthropicBaseUrl?.trim() || provider.baseUrl?.trim() : provider.openAIBaseUrl?.trim() || provider.baseUrl?.trim();
const apiKey = style === "anthropic" ? provider.anthropicApiKey?.trim() || provider.apiKey?.trim() : provider.openAIApiKey?.trim() || provider.apiKey?.trim();
return baseUrl && apiKey ? { baseUrl, apiKey } : null;
}
function ccConnectModelRef(agentType, providerId, model) {
if (agentType !== "opencode") return model;
return model.startsWith(`${providerId}/`) ? model : `${providerId}/${model}`;
}
// src/runtime-catalog.ts
var HERMES_INSTALL_SCRIPT = "curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-setup --non-interactive --skip-browser";
var HERMES_LINUX_INSTALL_SCRIPT = [
`sh -c 'set -e; if ! command -v xz >/dev/null 2>&1; then if [ "$(id -u)" -eq 0 ]; then SUDO=""; elif command -v sudo >/dev/null 2>&1; then SUDO="sudo"; else echo "Hermes Agent installer requires xz; install xz-utils/xz and retry." >&2; exit 1; fi; if command -v apt-get >/dev/null 2>&1; then $SUDO apt-get update && $SUDO apt-get install -y xz-utils; elif command -v apk >/dev/null 2>&1; then $SUDO apk add --no-cache xz; elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y xz; elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y xz; elif command -v pacman >/dev/null 2>&1; then $SUDO pacman -Sy --noconfirm xz; else echo "Hermes Agent installer requires xz; install xz-utils/xz and retry." >&2; exit 1; fi; fi; curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-setup --non-interactive --skip-browser'`
];
var CONNECTOR_RUNTIME_CATALOG = [
{
id: "openclaw",
label: "OpenClaw",
kind: "openclaw",
command: "openclaw",
iconId: "openclaw",
install: {
// Docs: https://docs.openclaw.ai/install/index
commands: {
darwin: ["curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard"],
linux: ["curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard"],
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard"'
],
default: ["curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard"]
},
helpUrl: "https://docs.openclaw.ai/install/index"
}
},
{
id: "hermes",
label: "Hermes Agent",
kind: "cli",
command: "hermes",
iconId: "hermes",
install: {
// Docs: https://hermes-agent.nousresearch.com/docs/getting-started/installation/
// Native Windows details: https://hermes-agent.nousresearch.com/docs/user-guide/windows-native
commands: {
darwin: [HERMES_INSTALL_SCRIPT],
linux: HERMES_LINUX_INSTALL_SCRIPT,
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "iex (irm https://hermes-agent.nousresearch.com/install.ps1)"'
],
default: ["pipx install hermes-agent"]
},
helpUrl: "https://hermes-agent.nousresearch.com/docs/getting-started/installation"
}
},
{
id: "claude-code",
label: "Claude Code",
kind: "cli",
command: "claude",
iconId: "claude-code",
install: {
// Docs: https://code.claude.com/docs/en/setup
commands: {
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://claude.ai/install.ps1 | iex"'
],
darwin: ["curl -fsSL https://claude.ai/install.sh | bash"],
linux: ["curl -fsSL https://claude.ai/install.sh | bash"],
default: ["npm install -g @anthropic-ai/claude-code"]
},
helpUrl: "https://code.claude.com/docs/en/installation"
}
},
{
id: "codex",
label: "Codex CLI",
kind: "cli",
command: "codex",
iconId: "codex",
install: {
// Docs: https://developers.openai.com/codex/cli
commands: {
default: ["npm install -g @openai/codex"]
},
helpUrl: "https://help.openai.com/en/articles/11096431-openai-codex-cli-getting-started"
}
},
{
id: "opencode",
label: "OpenCode",
kind: "cli",
command: "opencode",
iconId: "opencode",
install: {
// Docs: https://opencode.ai/docs/
commands: {
darwin: ["curl -fsSL https://opencode.ai/install | bash"],
linux: ["curl -fsSL https://opencode.ai/install | bash"],
win32: ["npm install -g opencode-ai"],
default: ["npm install -g opencode-ai"]
},
helpUrl: "https://opencli.co/cli/opencode"
}
},
{
id: "cursor",
label: "Cursor CLI",
kind: "cli",
command: "cursor-agent",
commands: ["cursor-agent", "cursor"],
iconId: "cursor",
install: {
// Docs: https://docs.cursor.com/en/cli/installation
// Cursor documents Windows through WSL; the connector creates a Windows .cmd wrapper after install.
commands: {
default: ["curl https://cursor.com/install -fsS | bash"],
win32: [
`powershell -NoProfile -ExecutionPolicy Bypass -Command "wsl.exe bash -lc 'curl https://cursor.com/install -fsS | bash'"`
]
},
helpUrl: "https://docs.cursor.com/en/cli/installation"
}
},
{
id: "kimi",
label: "Kimi Code",
kind: "cli",
command: "kimi",
iconId: "kimi",
install: {
// Docs: https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html
commands: {
darwin: ["curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash"],
linux: ["curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash"],
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://code.kimi.com/kimi-code/install.ps1 | iex"'
]
},
helpUrl: "https://www.kimi.com/code/docs/en/"
}
},
{
id: "copilot",
label: "GitHub Copilot CLI",
kind: "cli",
command: "copilot",
iconId: "copilot",
install: {
// Docs: https://docs.github.com/copilot/how-tos/copilot-cli/install-copilot-cli
commands: {
darwin: ["brew install copilot-cli", "curl -fsSL https://gh.io/copilot-install | bash"],
linux: ["brew install copilot-cli", "curl -fsSL https://gh.io/copilot-install | bash"],
win32: ["winget install GitHub.Copilot", "npm install -g @github/copilot"]
},
helpUrl: "https://docs.github.com/en/copilot/how-tos/copilot-cli/install-copilot-cli"
}
},
{
id: "antigravity",
label: "Antigravity CLI",
kind: "cli",
command: "agy",
commands: ["agy", "antigravity"],
iconId: "antigravity",
install: {
// Docs: https://antigravity.google/download
commands: {
darwin: ["curl -fsSL https://antigravity.google/cli/install.sh | bash"],
linux: ["curl -fsSL https://antigravity.google/cli/install.sh | bash"],
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://antigravity.google/cli/install.ps1 | iex"'
]
},
helpUrl: "https://www.antigravity.google/product/antigravity-cli"
}
}
];
function connectorRuntimeCatalog() {
return CONNECTOR_RUNTIME_CATALOG.map((entry) => ({ ...entry }));
}
function connectorRuntimeById(runtimeId) {
if (!runtimeId) return null;
return CONNECTOR_RUNTIME_CATALOG.find((entry) => entry.id === runtimeId) ?? null;
}
function currentRuntimePlatform() {
return typeof process !== "undefined" && process.platform ? process.platform : "default";
}
function connectorRuntimeInstallCommands(runtimeId, targetPlatform = currentRuntimePlatform()) {
const runtime = connectorRuntimeById(runtimeId);
if (!runtime) return [];
const commands = runtime.install.commands;
return commands?.[targetPlatform] ?? commands?.default ?? [];
}
function connectorRuntimeInstallCommand(runtimeId, targetPlatform = currentRuntimePlatform()) {
return connectorRuntimeInstallCommands(runtimeId, targetPlatform)[0] ?? null;
}
// src/index.ts
var DEFAULT_SERVER_URL = "https://shadowob.com";
var DEFAULT_WORK_DIR = ".";
var DEFAULT_PROJECT_NAME = "shadow-buddy";
var DEFAULT_CC_AGENT = "codex";
var shellQuote = (value) => {
if (!value) return "''";
return `'${value.replace(/'/g, `'\\''`)}'`;
};
var normalizeServerUrl = (value) => {
const trimmed = value.trim() || DEFAULT_SERVER_URL;
return trimmed.endsWith("/api") ? trimmed.slice(0, -4) : trimmed.replace(/\/$/, "");
};
var tokenOrPlaceholder = (token) => token.trim() || "<BUDDY_TOKEN>";
function tomlMultilineString(value) {
return `"""${value.replace(/"""/g, '\\"\\"\\"')}"""`;
}
function modelProviderEnvLines(provider) {
if (!provider) return [];
const openAI = connectorModelProviderEndpoint(provider, "openai");
const anthropic = connectorModelProviderEndpoint(provider, "anthropic");
return [
...openAI ? [
`OPENAI_COMPATIBLE_BASE_URL=${shellQuote(openAI.baseUrl)}`,
`OPENAI_COMPATIBLE_API_KEY=${shellQuote(openAI.apiKey)}`,
`OPENAI_COMPATIBLE_MODEL_ID=${shellQuote(provider.model)}`
] : [],
...anthropic ? [
`ANTHROPIC_COMPATIBLE_BASE_URL=${shellQuote(anthropic.baseUrl)}`,
`ANTHROPIC_COMPATIBLE_API_KEY=${shellQuote(anthropic.apiKey)}`,
`ANTHROPIC_COMPATIBLE_MODEL_ID=${shellQuote(provider.model)}`
] : [],
`SHADOWOB_MODEL_PROVIDER_ID=${shellQuote(provider.id ?? "shadow-official")}`
];
}
function modelProviderCapabilities(provider, capabilities) {
return provider ? [...capabilities, "officialModelProvider"] : capabilities;
}
function buildOpenClawPlan(input) {
const token = tokenOrPlaceholder(input.token);
const serverUrl = normalizeServerUrl(input.serverUrl);
const modelProvider = normalizeConnectorModelProvider(input.modelProvider);
const openAIProvider = connectorModelProviderEndpoint(modelProvider, "openai");
const jsonConfig = JSON.stringify(
{
channels: {
shadowob: {
token,
serverUrl
}
},
...modelProvider && openAIProvider ? {
models: {
mode: "merge",
pricing: { enabled: false },
providers: {
[modelProvider.id ?? "shadow-official"]: {
api: "openai-completions",
apiKey: "${env:OPENAI_COMPATIBLE_API_KEY}",
baseUrl: openAIProvider.baseUrl,
request: { allowPrivateNetwork: true },
models: [{ id: modelProvider.model, name: modelProvider.model }]
}
}
}
} : {}
},
null,
2
);
const commands = [
{
label: "Install plugin",
command: "openclaw plugins install @shadowob/openclaw-shadowob"
},
{
label: "Set Buddy token",
command: `openclaw config set channels.shadowob.token ${shellQuote(token)}`
},
{
label: "Set Shadow server URL",
command: `openclaw config set channels.shadowob.serverUrl ${shellQuote(serverUrl)}`
},
{
label: "Restart gateway",
command: "openclaw gateway restart"
}
];
const quickCommand = commands.map((item) => item.command).join(" && ");
const connectCommand = [
"npx @shadowob/connector@latest connect",
"--target openclaw",
`--server-url ${shellQuote(serverUrl)}`,
`--token ${shellQuote(token)}`
].join(" ");
return {
target: "openclaw",
title: "OpenClaw",
summary: "Install the Shadow channel plugin, Shadow CLI bin/skills, and a Buddy CLI profile for OpenClaw.",
connectCommand,
quickCommand,
commands,
configBlocks: [{ label: "~/.openclaw/openclaw.json", language: "json", content: jsonConfig }],
aiPrompt: [
"Configure this Shadow Buddy in OpenClaw.",
"",
`Shadow server URL: ${serverUrl}`,
`Buddy token: ${token}`,
"",
`Preferred one-line setup: ${connectCommand}`,
"The connector installs/configures the Shadow CLI, official Shadow skill files, and the Buddy profile before applying the OpenClaw channel config.",
modelProvider ? `It also configures ${modelProvider.label ?? "Shadow official LLM proxy"} as an OpenAI-compatible model provider (${modelProvider.model}).` : "",
"",
"Run these steps in order:",
...commands.map((item, index) => `${index + 1}. ${item.command}`),
"",
"Confirm each step and then verify the gateway is running."
].join("\n"),
docsUrl: "/product/index.html",
capabilities: modelProviderCapabilities(modelProvider, [
"channelMessages",
"dms",
"threads",
"mentions",
"attachments",
"images",
"interactive",
"slashCommands",
"onlineStatus",
"typing",
"activityStatus",
"reactions",
"editDelete",
"statusChecks",
"usageCosts",
"multiAgentBinding",
"shadowCliLogin",
"notifications",
"officialSkills",
"cronTasks"
])
};
}
function buildHermesPlan(input) {
const token = tokenOrPlaceholder(input.token);
const serverUrl = normalizeServerUrl(input.serverUrl);
const modelProvider = normalizeConnectorModelProvider(input.modelProvider);
const openAIProvider = connectorModelProviderEndpoint(modelProvider, "openai");
const envBlock = [
`SHADOWOB_SERVER_URL=${shellQuote(serverUrl)}`,
`SHADOWOB_TOKEN=${shellQuote(token)}`,
"SHADOWOB_ALLOW_ALL_USERS=true",
"SHADOWOB_HEARTBEAT_INTERVAL_SECONDS=30",
...modelProviderEnvLines(modelProvider)
].join("\n");
const yamlConfig = [
"plugins:",
" enabled:",
" - shadowob",
"",
"platforms:",
" shadowob:",
" enabled: true",
` token: "${token}"`,
" extra:",
` base_url: "${serverUrl}"`,
" mention_only: false",
" rest_only: false",
" catchup_minutes: 0",
" download_media: true",
" slash_commands: []",
...modelProvider && openAIProvider ? [
"",
"model:",
` default: "${modelProvider.model}"`,
` provider: "${modelProvider.id ?? "shadow-official"}"`,
"",
"custom_providers:",
` - name: "${modelProvider.id ?? "shadow-official"}"`,
` base_url: "${openAIProvider.baseUrl}"`,
" key_env: OPENAI_COMPATIBLE_API_KEY",
` model: "${modelProvider.model}"`
] : []
].join("\n");
const commands = [
{
label: "Copy plugin directory",
command: "mkdir -p ~/.hermes/plugins && cp -R ./packages/connector/hermes-shadowob-plugin ~/.hermes/plugins/shadowob"
},
{
label: "Install plugin dependencies",
command: "python -m pip install -r ~/.hermes/plugins/shadowob/requirements.txt"
},
{
label: "Enable plugin",
command: "hermes plugins enable shadowob"
},
{
label: "Start gateway",
command: "hermes gateway"
}
];
const connectCommand = [
"npx @shadowob/connector@latest connect",
"--target hermes",
`--server-url ${shellQuote(serverUrl)}`,
`--token ${shellQuote(token)}`
].join(" ");
return {
target: "hermes",
title: "Hermes Agent",
summary: "Install the ShadowOB Hermes platform plugin, Shadow CLI bin/skills, and a Buddy CLI profile.",
connectCommand,
quickCommand: commands.map((item) => item.command).join(" && "),
commands,
configBlocks: [
{ label: "~/.hermes/.env", language: "bash", content: envBlock },
{ label: "~/.hermes/config.yaml", language: "yaml", content: yamlConfig }
],
aiPrompt: [
"Configure this Shadow Buddy in Hermes Agent.",
"",
`Shadow server URL: ${serverUrl}`,
`Buddy token: ${token}`,
"",
`Preferred one-line setup: ${connectCommand}`,
"The connector installs/configures the Shadow CLI, official Shadow skill files, and the Buddy profile before writing Hermes config. The plugin resolves the Buddy agent id and channel policy from Shadow at runtime.",
modelProvider && openAIProvider ? `It also configures Hermes custom model endpoint ${openAIProvider.baseUrl} with model ${modelProvider.model}.` : ""
].join("\n"),
docsUrl: "https://hermes-agent.nousresearch.com/docs/user-guide/messaging",
capabilities: modelProviderCapabilities(modelProvider, [
"channelMessages",
"dms",
"threads",
"attachments",
"images",
"interactive",
"slashCommands",
"onlineStatus",
"typing",
"activityStatus",
"cronDelivery",
"statusChecks",
"usageCosts",
"shadowCliLogin",
"notifications",
"officialSkills"
])
};
}
function buildCcConnectPlan(input) {
const token = tokenOrPlaceholder(input.token);
const serverUrl = normalizeServerUrl(input.serverUrl);
const projectName = input.projectName?.trim() || DEFAULT_PROJECT_NAME;
const workDir = input.workDir?.trim() || DEFAULT_WORK_DIR;
const agentType = input.agentType?.trim() || DEFAULT_CC_AGENT;
const modelProvider = normalizeConnectorModelProvider(input.modelProvider);
const providerEndpoint = connectorModelProviderEndpoint(
modelProvider,
agentType === "claudecode" ? "anthropic" : "openai"
);
const providerId = modelProvider?.id ?? "shadow-official";
const providerModel = modelProvider ? ccConnectModelRef(agentType, providerId, modelProvider.model) : null;
const tomlConfig = [
'language = "zh"',
"",
"[[projects]]",
`name = "${projectName}"`,
"",
"[projects.agent]",
`type = "${agentType}"`,
"",
"[projects.agent.options]",
`work_dir = "${workDir}"`,
`system_prompt = ${tomlMultilineString(BUDDY_COLLABORATION_SYSTEM_PROMPT)}`,
...modelProvider && providerEndpoint ? [
`provider = "${providerId}"`,
`model = "${providerModel}"`,
"",
"[[projects.agent.providers]]",
`name = "${providerId}"`,
`api_key = "${providerEndpoint.apiKey}"`,
`base_url = "${providerEndpoint.baseUrl}"`,
`model = "${providerModel}"`,
"",
"[[projects.agent.providers.models]]",
`model = "${providerModel}"`
] : [],
"",
"[projects.display]",
'mode = "quiet"',
"thinking_messages = false",
"tool_messages = false",
"",
"[[projects.platforms]]",
'type = "shadowob"',
"",
"[projects.platforms.options]",
`token = "${token}"`,
`server_url = "${serverUrl}"`,
'allow_from = "*"',
"listen_dms = true",
"share_session_in_channel = false",
'progress_style = "compact"'
].join("\n");
const connectCommand = [
"npx @shadowob/connector@latest connect",
"--target cc-connect",
`--server-url ${shellQuote(serverUrl)}`,
`--token ${shellQuote(token)}`,
`--work-dir ${shellQuote(workDir)}`,
`--project-name ${shellQuote(projectName)}`,
`--agent-type ${shellQuote(agentType)}`
].join(" ");
const installCommand = `${connectCommand} --install`;
const startCommand = `${connectCommand} --install --start`;
const commands = [
{
label: "Install ShadowOB cc-connect fork",
command: installCommand
},
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
{
label: "Edit config",
command: "$EDITOR ~/.cc-connect/config.toml"
},
{ label: "Start ShadowOB cc-connect fork", command: startCommand }
];
return {
target: "cc-connect",
title: "cc-connect",
summary: `Use ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF} with ShadowOB Socket.IO support, Shadow CLI bin/skills, and a Buddy CLI profile.`,
connectCommand: startCommand,
quickCommand: startCommand,
commands,
configBlocks: [{ label: "~/.cc-connect/config.toml", language: "toml", content: tomlConfig }],
aiPrompt: [
"Configure this Shadow Buddy in cc-connect.",
"",
`Shadow server URL: ${serverUrl}`,
`Buddy token: ${token}`,
`Project work_dir: ${workDir}`,
`Agent type: ${agentType}`,
"",
`Preferred one-line setup: ${startCommand}`,
`Install ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF}, install/configure the Shadow CLI and official Shadow skill files, add the TOML platform block, and start cc-connect.`,
"Inbox task status hooks are handled by the installed Shadow CLI skill and server-delivered cliPolicy; cc-connect does not implement hook execution in its runtime prompt.",
"The generated config injects Shadow Buddy collaboration rules into the agent system prompt and sets cc-connect display mode to quiet so internal tool/progress events do not spill into Shadow channels.",
modelProvider ? `Configure ${modelProvider.label ?? "Shadow official LLM proxy"} as provider ${modelProvider.id ?? "shadow-official"} for ${agentType}.` : ""
].join("\n"),
docsUrl: CC_CONNECT_FORK_DOCS_URL,
capabilities: modelProviderCapabilities(modelProvider, [
"channelMessages",
"dms",
"attachments",
"images",
"interactive",
"slashCommands",
"typing",
"streamingPreviews",
"forms",
"statusChecks",
"usageCosts",
"multiAgentBinding",
"shadowCliLogin",
"notifications"
])
};
}
function createConnectorPlan(input) {
if (input.target === "openclaw") return buildOpenClawPlan(input);
if (input.target === "hermes") return buildHermesPlan(input);
if (input.target === "cc-connect") return buildCcConnectPlan(input);
throw new Error(`Unsupported connector target: ${String(input.target)}`);
}
function createConnectorPlans(input) {
return ["openclaw", "hermes", "cc-connect"].map(
(target) => createConnectorPlan({ ...input, target })
);
}
export {
CONNECTOR_RUNTIME_CATALOG,
connectorRuntimeCatalog,
connectorRuntimeById,
connectorRuntimeInstallCommands,
connectorRuntimeInstallCommand,
createConnectorPlan,
createConnectorPlans
};
+5
-5

@@ -307,3 +307,3 @@ "use strict";

] : [],
`SHADOW_MODEL_PROVIDER_ID=${shellQuote(provider.id ?? "shadow-official")}`
`SHADOWOB_MODEL_PROVIDER_ID=${shellQuote(provider.id ?? "shadow-official")}`
];

@@ -425,6 +425,6 @@ }

const envBlock = [
`SHADOW_BASE_URL=${shellQuote(serverUrl)}`,
`SHADOW_TOKEN=${shellQuote(token)}`,
"SHADOW_ALLOW_ALL_USERS=true",
"SHADOW_HEARTBEAT_INTERVAL_SECONDS=30",
`SHADOWOB_SERVER_URL=${shellQuote(serverUrl)}`,
`SHADOWOB_TOKEN=${shellQuote(token)}`,
"SHADOWOB_ALLOW_ALL_USERS=true",
"SHADOWOB_HEARTBEAT_INTERVAL_SECONDS=30",
...modelProviderEnvLines(modelProvider)

@@ -431,0 +431,0 @@ ].join("\n");

@@ -9,3 +9,3 @@ import {

createConnectorPlans
} from "./chunk-DQGW3WRU.js";
} from "./chunk-XCXCPSCG.js";
export {

@@ -12,0 +12,0 @@ CONNECTOR_RUNTIME_CATALOG,

@@ -307,3 +307,3 @@ "use strict";

] : [],
`SHADOW_MODEL_PROVIDER_ID=${shellQuote(provider.id ?? "shadow-official")}`
`SHADOWOB_MODEL_PROVIDER_ID=${shellQuote(provider.id ?? "shadow-official")}`
];

@@ -425,6 +425,6 @@ }

const envBlock = [
`SHADOW_BASE_URL=${shellQuote(serverUrl)}`,
`SHADOW_TOKEN=${shellQuote(token)}`,
"SHADOW_ALLOW_ALL_USERS=true",
"SHADOW_HEARTBEAT_INTERVAL_SECONDS=30",
`SHADOWOB_SERVER_URL=${shellQuote(serverUrl)}`,
`SHADOWOB_TOKEN=${shellQuote(token)}`,
"SHADOWOB_ALLOW_ALL_USERS=true",
"SHADOWOB_HEARTBEAT_INTERVAL_SECONDS=30",
...modelProviderEnvLines(modelProvider)

@@ -431,0 +431,0 @@ ].join("\n");

@@ -9,3 +9,3 @@ import {

createConnectorPlans
} from "./chunk-DQGW3WRU.js";
} from "./chunk-XCXCPSCG.js";
export {

@@ -12,0 +12,0 @@ CONNECTOR_RUNTIME_CATALOG,

@@ -46,3 +46,3 @@ "use strict";

var import_node_path = require("path");
var CONNECTOR_MANAGED_NODE_VERSION = process.env.SHADOW_CONNECTOR_NODE_VERSION?.trim() || "22.16.0";
var CONNECTOR_MANAGED_NODE_VERSION = process.env.SHADOWOB_CONNECTOR_NODE_VERSION?.trim() || "22.16.0";
var PATH_KEY = process.platform === "win32" ? "Path" : "PATH";

@@ -56,3 +56,3 @@ var loginShellPath;

function connectorHome() {
const override = process.env.SHADOW_CONNECTOR_HOME?.trim();
const override = process.env.SHADOWOB_CONNECTOR_HOME?.trim();
return override ? expandHome(override) : (0, import_node_path.resolve)((0, import_node_os.homedir)(), ".shadowob/connector");

@@ -87,3 +87,3 @@ }

function readLoginShellPath() {
if (process.env.SHADOW_CONNECTOR_SKIP_LOGIN_SHELL === "1") return [];
if (process.env.SHADOWOB_CONNECTOR_SKIP_LOGIN_SHELL === "1") return [];
if (loginShellPath !== void 0) return splitPath(loginShellPath ?? "");

@@ -179,3 +179,3 @@ const shells = dedupePaths(

...env,
SHADOW_CONNECTOR_HOME: connectorHome(),
SHADOWOB_CONNECTOR_HOME: connectorHome(),
NPM_CONFIG_PREFIX: nodeGlobalRoot(),

@@ -455,3 +455,3 @@ npm_config_prefix: nodeGlobalRoot()

function opencodeUrl(options) {
const value = options.opencodeUrl ?? options.env?.SHADOW_CONNECTOR_OPENCODE_URL ?? options.env?.OPENCODE_SERVER_URL ?? DEFAULT_OPENCODE_URL;
const value = options.opencodeUrl ?? options.env?.SHADOWOB_CONNECTOR_OPENCODE_URL ?? options.env?.OPENCODE_SERVER_URL ?? DEFAULT_OPENCODE_URL;
return value.replace(/\/+$/, "");

@@ -458,0 +458,0 @@ }

@@ -31,3 +31,3 @@ // src/runtime-sessions.ts

import { dirname, resolve, sep } from "path";
var CONNECTOR_MANAGED_NODE_VERSION = process.env.SHADOW_CONNECTOR_NODE_VERSION?.trim() || "22.16.0";
var CONNECTOR_MANAGED_NODE_VERSION = process.env.SHADOWOB_CONNECTOR_NODE_VERSION?.trim() || "22.16.0";
var PATH_KEY = process.platform === "win32" ? "Path" : "PATH";

@@ -41,3 +41,3 @@ var loginShellPath;

function connectorHome() {
const override = process.env.SHADOW_CONNECTOR_HOME?.trim();
const override = process.env.SHADOWOB_CONNECTOR_HOME?.trim();
return override ? expandHome(override) : resolve(homedir(), ".shadowob/connector");

@@ -72,3 +72,3 @@ }

function readLoginShellPath() {
if (process.env.SHADOW_CONNECTOR_SKIP_LOGIN_SHELL === "1") return [];
if (process.env.SHADOWOB_CONNECTOR_SKIP_LOGIN_SHELL === "1") return [];
if (loginShellPath !== void 0) return splitPath(loginShellPath ?? "");

@@ -164,3 +164,3 @@ const shells = dedupePaths(

...env,
SHADOW_CONNECTOR_HOME: connectorHome(),
SHADOWOB_CONNECTOR_HOME: connectorHome(),
NPM_CONFIG_PREFIX: nodeGlobalRoot(),

@@ -440,3 +440,3 @@ npm_config_prefix: nodeGlobalRoot()

function opencodeUrl(options) {
const value = options.opencodeUrl ?? options.env?.SHADOW_CONNECTOR_OPENCODE_URL ?? options.env?.OPENCODE_SERVER_URL ?? DEFAULT_OPENCODE_URL;
const value = options.opencodeUrl ?? options.env?.SHADOWOB_CONNECTOR_OPENCODE_URL ?? options.env?.OPENCODE_SERVER_URL ?? DEFAULT_OPENCODE_URL;
return value.replace(/\/+$/, "");

@@ -443,0 +443,0 @@ }

@@ -8,7 +8,7 @@ name: shadowob

requires_env:
- name: SHADOW_BASE_URL
- name: SHADOWOB_SERVER_URL
description: "Shadow server base URL, for example https://shadowob.example.com"
prompt: "Shadow base URL"
password: false
- name: SHADOW_TOKEN
- name: SHADOWOB_TOKEN
description: "Shadow bot/user access token"

@@ -18,69 +18,69 @@ prompt: "Shadow access token"

optional_env:
- name: SHADOW_CHANNEL_IDS
- name: SHADOWOB_CHANNEL_IDS
description: "Advanced override: comma-separated channel IDs to join. Normally omitted because Shadow policy is discovered dynamically."
prompt: "Shadow channel IDs"
password: false
- name: SHADOW_HOME_CHANNEL
- name: SHADOWOB_HOME_CHANNEL
description: "Default Shadow channel ID used by cron/send_message delivery."
prompt: "Shadow home channel"
password: false
- name: SHADOW_AGENT_ID
- name: SHADOWOB_AGENT_ID
description: "Advanced override: Shadow Buddy agent ID. Normally resolved from /api/auth/me."
prompt: "Shadow Buddy agent ID"
password: false
- name: SHADOW_HEARTBEAT_INTERVAL_SECONDS
- name: SHADOWOB_HEARTBEAT_INTERVAL_SECONDS
description: "Agent heartbeat interval in seconds. Defaults to 30."
prompt: "Heartbeat interval"
password: false
- name: SHADOW_SLASH_COMMANDS_JSON
- name: SHADOWOB_SLASH_COMMANDS_JSON
description: "JSON array of slash command definitions to register on startup."
prompt: "Slash commands JSON"
password: false
- name: SHADOW_SERVER_IDS
- name: SHADOWOB_SERVER_IDS
description: "Advanced override: comma-separated server IDs/slugs to discover manually."
prompt: "Shadow server IDs"
password: false
- name: SHADOW_AUTO_DISCOVER_CHANNELS
- name: SHADOWOB_AUTO_DISCOVER_CHANNELS
description: "Advanced override: true/false. Discover accessible server channels without the Buddy remote policy."
prompt: "Auto-discover channels?"
password: false
- name: SHADOW_ALLOWED_USERS
- name: SHADOWOB_ALLOWED_USERS
description: "Comma-separated allowed Shadow user IDs/usernames for Hermes gateway authorization."
prompt: "Allowed Shadow users"
password: false
- name: SHADOW_ALLOW_ALL_USERS
- name: SHADOWOB_ALLOW_ALL_USERS
description: "true/false. Allow all Shadow users."
prompt: "Allow all Shadow users?"
password: false
- name: SHADOW_BOT_USER_ID
- name: SHADOWOB_BUDDY_USER_ID
description: "Optional bot user ID. If omitted, adapter calls /api/auth/me."
prompt: "Shadow bot user ID"
password: false
- name: SHADOW_BOT_USERNAME
- name: SHADOWOB_BUDDY_USERNAME
description: "Optional bot username for mention-only filtering."
prompt: "Shadow bot username"
password: false
- name: SHADOW_MENTION_ONLY
- name: SHADOWOB_MENTION_ONLY
description: "true/false. In group channels, only process messages that mention the bot."
prompt: "Mention-only mode?"
password: false
- name: SHADOW_REPLY_TO_BOTS
- name: SHADOWOB_REPLY_TO_BUDDIES
description: "true/false. Process messages authored by other bot users. Defaults false."
prompt: "Reply to bot users?"
password: false
- name: SHADOW_REST_ONLY
- name: SHADOWOB_REST_ONLY
description: "true/false. Use REST polling instead of Socket.IO."
prompt: "REST-only mode?"
password: false
- name: SHADOW_POLL_INTERVAL_SECONDS
- name: SHADOWOB_POLL_INTERVAL_SECONDS
description: "REST polling interval in seconds. Defaults to 3."
prompt: "Poll interval"
password: false
- name: SHADOW_CATCHUP_MINUTES
- name: SHADOWOB_CATCHUP_MINUTES
description: "On startup, process recent messages newer than this window. Defaults to 0."
prompt: "Catch-up minutes"
password: false
- name: SHADOW_DOWNLOAD_MEDIA
- name: SHADOWOB_DOWNLOAD_MEDIA
description: "true/false. Download inbound attachments into Hermes cache. Defaults true."
prompt: "Download media?"
password: false

@@ -20,5 +20,5 @@ # Hermes Shadow/OpenClaw Buddy Platform Plugin

- Dynamic channel and policy discovery through `/api/agents/:id/config`
- Optional slash command registration and slash-command prompt handling through `SHADOW_SLASH_COMMANDS_JSON`
- Optional slash command registration and slash-command prompt handling through `SHADOWOB_SLASH_COMMANDS_JSON`
- Interactive component sends via Shadow message metadata and interactive response forwarding to Hermes
- Cron/send_message standalone delivery through `SHADOW_HOME_CHANNEL`
- Cron/send_message standalone delivery through `SHADOWOB_HOME_CHANNEL`

@@ -66,4 +66,4 @@ It deliberately does not implement the whole Shadow product surface. Workspace, commerce, wallet, cloud sandbox, marketplace, OAuth and dashboard stats should be added as Hermes tools or an MCP server, not as platform-adapter logic.

```bash
export SHADOW_BASE_URL="https://your-shadow.example.com"
export SHADOW_TOKEN="shadow_access_token"
export SHADOWOB_SERVER_URL="https://your-shadow.example.com"
export SHADOWOB_TOKEN="shadow_access_token"
```

@@ -74,6 +74,6 @@

```bash
export SHADOW_HEARTBEAT_INTERVAL_SECONDS=30
export SHADOWOB_HEARTBEAT_INTERVAL_SECONDS=30
# Optional slash commands registered at startup
export SHADOW_SLASH_COMMANDS_JSON='[{"name":"audit","description":"Run an audit"}]'
export SHADOWOB_SLASH_COMMANDS_JSON='[{"name":"audit","description":"Run an audit"}]'
```

@@ -84,19 +84,19 @@

```bash
export SHADOW_ALLOWED_USERS="user_id_or_username_1,user_id_or_username_2"
export SHADOW_ALLOW_ALL_USERS=false
export SHADOW_BOT_USER_ID="bot_user_id" # optional; otherwise /api/auth/me is called
export SHADOW_BOT_USERNAME="bot_username" # optional; used by mention-only filter
export SHADOW_MENTION_ONLY=false # group/channel messages require @bot when true
export SHADOW_REPLY_TO_BOTS=false # loop guard
export SHADOW_REST_ONLY=false # true disables Socket.IO and uses polling
export SHADOW_POLL_INTERVAL_SECONDS=3
export SHADOW_CATCHUP_MINUTES=0 # set >0 to process recent messages on startup
export SHADOW_DOWNLOAD_MEDIA=true
export SHADOWOB_ALLOWED_USERS="user_id_or_username_1,user_id_or_username_2"
export SHADOWOB_ALLOW_ALL_USERS=false
export SHADOWOB_BUDDY_USER_ID="bot_user_id" # optional; otherwise /api/auth/me is called
export SHADOWOB_BUDDY_USERNAME="bot_username" # optional; used by mention-only filter
export SHADOWOB_MENTION_ONLY=false # group/channel messages require @bot when true
export SHADOWOB_REPLY_TO_BUDDIES=false # loop guard
export SHADOWOB_REST_ONLY=false # true disables Socket.IO and uses polling
export SHADOWOB_POLL_INTERVAL_SECONDS=3
export SHADOWOB_CATCHUP_MINUTES=0 # set >0 to process recent messages on startup
export SHADOWOB_DOWNLOAD_MEDIA=true
# Advanced compatibility overrides; normally leave these unset so Shadow policy drives routing.
export SHADOW_CHANNEL_IDS="channel_id_1,channel_id_2"
export SHADOW_HOME_CHANNEL="channel_id_1"
export SHADOW_AGENT_ID="agent_id_1"
export SHADOW_SERVER_IDS="server_id_or_slug_1,server_id_or_slug_2"
export SHADOW_AUTO_DISCOVER_CHANNELS=true
export SHADOWOB_CHANNEL_IDS="channel_id_1,channel_id_2"
export SHADOWOB_HOME_CHANNEL="channel_id_1"
export SHADOWOB_AGENT_ID="agent_id_1"
export SHADOWOB_SERVER_IDS="server_id_or_slug_1,server_id_or_slug_2"
export SHADOWOB_AUTO_DISCOVER_CHANNELS=true
```

@@ -114,5 +114,5 @@

enabled: true
token: "${SHADOW_TOKEN}"
token: "${SHADOWOB_TOKEN}"
extra:
base_url: "${SHADOW_BASE_URL}"
base_url: "${SHADOWOB_SERVER_URL}"
slash_commands:

@@ -119,0 +119,0 @@ - name: "audit"

@@ -571,3 +571,3 @@ """Minimal async Shadow SDK used by the Hermes Shadow platform plugin.

"python-socketio is required for Shadow realtime mode. "
"Install requirements.txt or set SHADOW_REST_ONLY=true."
"Install requirements.txt or set SHADOWOB_REST_ONLY=true."
) from exc

@@ -574,0 +574,0 @@

{
"name": "@shadowob/connector",
"version": "1.1.60",
"version": "1.1.61",
"description": "Shadow connector helpers for OpenClaw, Hermes Agent, and cc-connect",

@@ -75,3 +75,3 @@ "type": "module",

"yaml": "^2.8.4",
"@shadowob/shared": "1.1.60"
"@shadowob/shared": "1.1.61"
},

@@ -78,0 +78,0 @@ "scripts": {

@@ -5,3 +5,3 @@ # Shadow Connector

The package exports pure plan builders for legacy app UIs and a `shadowob-connector` CLI for terminal setup.
The package exports pure plan builders for app UIs and a `shadowob-connector` CLI for terminal setup.

@@ -169,6 +169,6 @@ ## CLI

```bash
export SHADOW_BASE_URL="https://shadowob.com"
export SHADOW_TOKEN="buddy-token"
export SHADOW_HEARTBEAT_INTERVAL_SECONDS=30
export SHADOW_SLASH_COMMANDS_JSON='[]'
export SHADOWOB_SERVER_URL="https://shadowob.com"
export SHADOWOB_TOKEN="buddy-token"
export SHADOWOB_HEARTBEAT_INTERVAL_SECONDS=30
export SHADOWOB_SLASH_COMMANDS_JSON='[]'
```

@@ -175,0 +175,0 @@

import type { ShadowServerAppTokenIntrospection } from './types.js'
export function shadowServerUrl() {
return (process.env.SHADOW_SERVER_URL ?? 'http://localhost:3002').replace(/\/$/, '')
return (process.env.SHADOWOB_SERVER_URL ?? 'http://localhost:3002').replace(/\/$/, '')
}

@@ -6,0 +6,0 @@

@@ -6,5 +6,5 @@ import manifestJson from '../shadow-app.local.json' with { type: 'json' }

const publicBaseUrl = (
process.env.SHADOW_APP_PUBLIC_BASE_URL ?? `http://localhost:${port}`
process.env.SHADOWOB_APP_PUBLIC_BASE_URL ?? `http://localhost:${port}`
).replace(/\/$/, '')
const apiBaseUrl = (process.env.SHADOW_APP_API_BASE_URL ?? publicBaseUrl).replace(/\/$/, '')
const apiBaseUrl = (process.env.SHADOWOB_APP_API_BASE_URL ?? publicBaseUrl).replace(/\/$/, '')
return {

@@ -11,0 +11,0 @@ ...manifestJson,

@@ -22,6 +22,6 @@ # Runtime, Publish, And Backup

Target declarative publish contract. Before using it, verify that the runtime CLI exposes this command with `shadowob cloud app --help`; if it is absent, do not invent an external tunnel or publish path.
Target declarative publish contract. Before using it, verify that the runtime CLI exposes this command with `shadowob app --help`; if it is absent, do not invent an external tunnel or publish path.
```bash
shadowob cloud app publish \
shadowob app publish \
--port "<port>" \

@@ -34,3 +34,3 @@ --manifest-file ./shadow-app.local.json \

Create or keep the App source under `$SHADOW_WORKSPACE`, `/workspace`, `/state`, `/tmp`, or the
Create or keep the App source under `$SHADOWOB_WORKSPACE`, `/workspace`, `/state`, `/tmp`, or the
standard Cloud runner home `/home/shadow`. `--source-path` and `--state-paths` must be absolute

@@ -40,6 +40,6 @@ runtime paths under one of those roots.

Cloud runtimes auto-detect the current deployment and agent from
`SHADOW_CLOUD_DEPLOYMENT_ID` and `AGENT_ID`/`SHADOW_CLOUD_AGENT_ID`. Inside an Inbox task or
`SHADOWOB_CLOUD_DEPLOYMENT_ID` and `SHADOWOB_AGENT_ID`. Inside an Inbox task or
current channel, the CLI infers the target server from the task/channel context. Pass `--deployment`,
`--agent`, or `--server` explicitly only when working outside the managed runtime context. Do not
treat `SHADOW_SERVER_IDS` as a publish target; it is only a list of servers the runtime may observe.
treat `SHADOWOB_SERVER_IDS` as a publish target; it is only a list of servers the runtime may observe.

@@ -53,3 +53,3 @@ Before publishing, keep the App service running without blocking the task shell:

When a scaffold does not provide `start:background`, use an equivalent `nohup ... &` command and write `.shadow-app.pid`. Do not run foreground server commands such as `pnpm start` or `node src/server.js` as the final tool call. A blocked shell prevents `shadowob cloud app publish`, backup creation, Inbox completion, and update tasks from running.
When a scaffold does not provide `start:background`, use an equivalent `nohup ... &` command and write `.shadow-app.pid`. Do not run foreground server commands such as `pnpm start` or `node src/server.js` as the final tool call. A blocked shell prevents `shadowob app publish`, backup creation, Inbox completion, and update tasks from running.

@@ -59,3 +59,3 @@ For dynamic expose from inside a runtime, write desired state to:

```text
$SHADOW_EXPOSURE_CONFIG
$SHADOWOB_EXPOSURE_CONFIG
```

@@ -89,3 +89,3 @@

Removing an entry from `desired.json` closes that dynamic exposure after sidecar reconcile. Dynamic expose only creates a controlled route; installing into a server must still use `shadowob cloud app publish` or the explicit App install/defaults/grant commands.
Removing an entry from `desired.json` closes that dynamic exposure after sidecar reconcile. Dynamic expose only creates a controlled route; installing into a server must still use `shadowob app publish` or the explicit App install/defaults/grant commands.

@@ -95,3 +95,3 @@ Useful lifecycle commands:

```bash
shadowob cloud app expose \
shadowob app expose \
--id "<app-key>" \

@@ -105,6 +105,6 @@ --port "<port>" \

shadowob cloud app status --app-key "<app-key>" --json
shadowob cloud app backup --app-key "<app-key>" --json
shadowob cloud app restore --app-key "<app-key>" --backup "<backup-set-id>" --json
shadowob cloud app unpublish --app-key "<app-key>" --json
shadowob app status --app-key "<app-key>" --json
shadowob app backup --app-key "<app-key>" --json
shadowob app restore --app-key "<app-key>" --backup "<backup-set-id>" --json
shadowob app unpublish --app-key "<app-key>" --json
```

@@ -176,2 +176,2 @@

- Do not run ad hoc tunnel clients, allocate public domains, or expose arbitrary private URLs from inside the container.
- If `shadowob cloud app publish` returns 401/403 or any other error, mark the Inbox task failed with the exact blocker. Do not report the App as published or completed until the publish command returns success.
- If `shadowob app publish` returns 401/403 or any other error, mark the Inbox task failed with the exact blocker. Do not report the App as published or completed until the publish command returns success.

@@ -54,3 +54,3 @@ # Scaffold

6. Run local preview through `shadowob app preview --manifest-file`.
7. For Cloud runtime publish, keep the project under `$SHADOW_WORKSPACE`, `/workspace`, or `/home/shadow`, then run `PORT=<port> pnpm start:background` and verify `/health` with `curl`.
7. For Cloud runtime publish, keep the project under `$SHADOWOB_WORKSPACE`, `/workspace`, or `/home/shadow`, then run `PORT=<port> pnpm start:background` and verify `/health` with `curl`.
8. Publish only after state paths and backup policy are declared.

@@ -57,0 +57,0 @@

@@ -22,3 +22,3 @@ ---

- Use `shadow.app/1` manifests, stable `appKey` values, stable command names, and explicit `permission`, `action`, and `dataClass` on every command.
- Buddies must operate installed Apps through `shadowob app discover`, `shadowob app skills`, and `shadowob app call`; never hand a Buddy raw HTTP routes, app tokens, or legacy shared secrets.
- Buddies must operate installed Apps through `shadowob app discover`, `shadowob app skills`, and `shadowob app call`; never hand a Buddy raw HTTP routes, app tokens, or shared secrets.
- For local development, install with `--manifest-file`; production manifests, iframe URLs, API URLs, icon URLs, and OAuth redirect URIs must be stable HTTPS origins.

@@ -25,0 +25,0 @@ - Never publish public `http://<ip>:<port>` origins in a manifest. If a proxy forwards to a private host, keep the private address out of the public manifest.

@@ -347,21 +347,2 @@ ---

```bash
# Legacy workspace apps
shadowob apps list <server-id> --json
# Get app
shadowob apps get <app-id> --json
# Create/Update/Delete
shadowob apps create <server-id> --name <name> --type <url|workspace|static> [--source-url <url>] [--description <desc>] [--settings <json>] --json
shadowob apps update <app-id> [--name <name>] [--description <desc>] [--source-url <url>] [--settings <json>] --json
shadowob apps delete <app-id>
# Publish from workspace
shadowob apps publish <server-id> --folder-id <id> [--name <name>] [--description <desc>] --json
# Download source
shadowob apps download <app-id> [--output <path>]
```
## Notifications

@@ -368,0 +349,0 @@

// src/buddy-collaboration-guidance.ts
var BUDDY_COLLABORATION_SYSTEM_PROMPT = [
"Shadow Buddy collaboration rules:",
"- Treat a Buddy collaboration as a bounded IM conversation, not an open-ended work session.",
"- Speak only when you add a distinct useful point. If another Buddy already covered it, stay brief or stay silent.",
"- If you only agree, use a structured Shadow reaction action when available; otherwise stay silent instead of posting acknowledgement text.",
"- Later collaboration turns may be routed into a Shadow thread by the platform. Do not announce thread routing yourself.",
"- Match the density of the triggering message. Short chat gets a short reply; long analysis requires an explicit user pull.",
"- For Shadow Inbox task status changes, use the mounted shadowob CLI. The CLI consumes server-delivered task policy after status updates.",
"- Do not run tools, create memories, create skills, write files, promote tasks, or run demos unless a human explicitly asks for current action.",
"- Keep runtime logs, tool progress, memory updates, skill views, and self-improvement reviews private. Do not post them as chat messages.",
"- If the user says to stop, stay quiet, not implement, or just discuss, stop the action chain immediately."
].join("\n");
// src/cc-connect-fork.ts
var CC_CONNECT_FORK_REPO = "buggyblues/cc-connect";
var CC_CONNECT_FORK_REF = "8289423fa21e744e5fe625cba57b2c6c3c5c17ea";
var CC_CONNECT_FORK_SHORT_REF = CC_CONNECT_FORK_REF.slice(0, 7);
var CC_CONNECT_FORK_DOCS_URL = `https://github.com/${CC_CONNECT_FORK_REPO}/blob/main/docs/shadowob.md`;
// src/model-provider.ts
function normalizeConnectorModelProvider(provider) {
const baseUrl = provider?.baseUrl?.trim();
const apiKey = provider?.apiKey?.trim();
const openAIBaseUrl = provider?.openAIBaseUrl?.trim() || baseUrl;
const openAIApiKey = provider?.openAIApiKey?.trim() || apiKey;
const anthropicBaseUrl = provider?.anthropicBaseUrl?.trim();
const anthropicApiKey = provider?.anthropicApiKey?.trim();
const model = provider?.model?.trim();
if ((!openAIBaseUrl || !openAIApiKey) && (!anthropicBaseUrl || !anthropicApiKey)) return null;
if (!model) return null;
return {
id: provider?.id?.trim() || "shadow-official",
label: provider?.label?.trim() || "Shadow official LLM proxy",
baseUrl: openAIBaseUrl || anthropicBaseUrl,
apiKey: openAIApiKey || anthropicApiKey,
...openAIBaseUrl ? { openAIBaseUrl } : {},
...openAIApiKey ? { openAIApiKey } : {},
...anthropicBaseUrl ? { anthropicBaseUrl } : {},
...anthropicApiKey ? { anthropicApiKey } : {},
model
};
}
function connectorModelProviderEndpoint(provider, style) {
if (!provider) return null;
const baseUrl = style === "anthropic" ? provider.anthropicBaseUrl?.trim() || provider.baseUrl?.trim() : provider.openAIBaseUrl?.trim() || provider.baseUrl?.trim();
const apiKey = style === "anthropic" ? provider.anthropicApiKey?.trim() || provider.apiKey?.trim() : provider.openAIApiKey?.trim() || provider.apiKey?.trim();
return baseUrl && apiKey ? { baseUrl, apiKey } : null;
}
function ccConnectModelRef(agentType, providerId, model) {
if (agentType !== "opencode") return model;
return model.startsWith(`${providerId}/`) ? model : `${providerId}/${model}`;
}
// src/runtime-catalog.ts
var HERMES_INSTALL_SCRIPT = "curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-setup --non-interactive --skip-browser";
var HERMES_LINUX_INSTALL_SCRIPT = [
`sh -c 'set -e; if ! command -v xz >/dev/null 2>&1; then if [ "$(id -u)" -eq 0 ]; then SUDO=""; elif command -v sudo >/dev/null 2>&1; then SUDO="sudo"; else echo "Hermes Agent installer requires xz; install xz-utils/xz and retry." >&2; exit 1; fi; if command -v apt-get >/dev/null 2>&1; then $SUDO apt-get update && $SUDO apt-get install -y xz-utils; elif command -v apk >/dev/null 2>&1; then $SUDO apk add --no-cache xz; elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y xz; elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y xz; elif command -v pacman >/dev/null 2>&1; then $SUDO pacman -Sy --noconfirm xz; else echo "Hermes Agent installer requires xz; install xz-utils/xz and retry." >&2; exit 1; fi; fi; curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash -s -- --skip-setup --non-interactive --skip-browser'`
];
var CONNECTOR_RUNTIME_CATALOG = [
{
id: "openclaw",
label: "OpenClaw",
kind: "openclaw",
command: "openclaw",
iconId: "openclaw",
install: {
// Docs: https://docs.openclaw.ai/install/index
commands: {
darwin: ["curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard"],
linux: ["curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard"],
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "& ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard"'
],
default: ["curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard"]
},
helpUrl: "https://docs.openclaw.ai/install/index"
}
},
{
id: "hermes",
label: "Hermes Agent",
kind: "cli",
command: "hermes",
iconId: "hermes",
install: {
// Docs: https://hermes-agent.nousresearch.com/docs/getting-started/installation/
// Native Windows details: https://hermes-agent.nousresearch.com/docs/user-guide/windows-native
commands: {
darwin: [HERMES_INSTALL_SCRIPT],
linux: HERMES_LINUX_INSTALL_SCRIPT,
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "iex (irm https://hermes-agent.nousresearch.com/install.ps1)"'
],
default: ["pipx install hermes-agent"]
},
helpUrl: "https://hermes-agent.nousresearch.com/docs/getting-started/installation"
}
},
{
id: "claude-code",
label: "Claude Code",
kind: "cli",
command: "claude",
iconId: "claude-code",
install: {
// Docs: https://code.claude.com/docs/en/setup
commands: {
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://claude.ai/install.ps1 | iex"'
],
darwin: ["curl -fsSL https://claude.ai/install.sh | bash"],
linux: ["curl -fsSL https://claude.ai/install.sh | bash"],
default: ["npm install -g @anthropic-ai/claude-code"]
},
helpUrl: "https://code.claude.com/docs/en/installation"
}
},
{
id: "codex",
label: "Codex CLI",
kind: "cli",
command: "codex",
iconId: "codex",
install: {
// Docs: https://developers.openai.com/codex/cli
commands: {
default: ["npm install -g @openai/codex"]
},
helpUrl: "https://help.openai.com/en/articles/11096431-openai-codex-cli-getting-started"
}
},
{
id: "opencode",
label: "OpenCode",
kind: "cli",
command: "opencode",
iconId: "opencode",
install: {
// Docs: https://opencode.ai/docs/
commands: {
darwin: ["curl -fsSL https://opencode.ai/install | bash"],
linux: ["curl -fsSL https://opencode.ai/install | bash"],
win32: ["npm install -g opencode-ai"],
default: ["npm install -g opencode-ai"]
},
helpUrl: "https://opencli.co/cli/opencode"
}
},
{
id: "cursor",
label: "Cursor CLI",
kind: "cli",
command: "cursor-agent",
commands: ["cursor-agent", "cursor"],
iconId: "cursor",
install: {
// Docs: https://docs.cursor.com/en/cli/installation
// Cursor documents Windows through WSL; the connector creates a Windows .cmd wrapper after install.
commands: {
default: ["curl https://cursor.com/install -fsS | bash"],
win32: [
`powershell -NoProfile -ExecutionPolicy Bypass -Command "wsl.exe bash -lc 'curl https://cursor.com/install -fsS | bash'"`
]
},
helpUrl: "https://docs.cursor.com/en/cli/installation"
}
},
{
id: "kimi",
label: "Kimi Code",
kind: "cli",
command: "kimi",
iconId: "kimi",
install: {
// Docs: https://www.kimi.com/code/docs/en/kimi-code-cli/getting-started.html
commands: {
darwin: ["curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash"],
linux: ["curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash"],
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://code.kimi.com/kimi-code/install.ps1 | iex"'
]
},
helpUrl: "https://www.kimi.com/code/docs/en/"
}
},
{
id: "copilot",
label: "GitHub Copilot CLI",
kind: "cli",
command: "copilot",
iconId: "copilot",
install: {
// Docs: https://docs.github.com/copilot/how-tos/copilot-cli/install-copilot-cli
commands: {
darwin: ["brew install copilot-cli", "curl -fsSL https://gh.io/copilot-install | bash"],
linux: ["brew install copilot-cli", "curl -fsSL https://gh.io/copilot-install | bash"],
win32: ["winget install GitHub.Copilot", "npm install -g @github/copilot"]
},
helpUrl: "https://docs.github.com/en/copilot/how-tos/copilot-cli/install-copilot-cli"
}
},
{
id: "antigravity",
label: "Antigravity CLI",
kind: "cli",
command: "agy",
commands: ["agy", "antigravity"],
iconId: "antigravity",
install: {
// Docs: https://antigravity.google/download
commands: {
darwin: ["curl -fsSL https://antigravity.google/cli/install.sh | bash"],
linux: ["curl -fsSL https://antigravity.google/cli/install.sh | bash"],
win32: [
'powershell -NoProfile -ExecutionPolicy Bypass -Command "irm https://antigravity.google/cli/install.ps1 | iex"'
]
},
helpUrl: "https://www.antigravity.google/product/antigravity-cli"
}
}
];
function connectorRuntimeCatalog() {
return CONNECTOR_RUNTIME_CATALOG.map((entry) => ({ ...entry }));
}
function connectorRuntimeById(runtimeId) {
if (!runtimeId) return null;
return CONNECTOR_RUNTIME_CATALOG.find((entry) => entry.id === runtimeId) ?? null;
}
function currentRuntimePlatform() {
return typeof process !== "undefined" && process.platform ? process.platform : "default";
}
function connectorRuntimeInstallCommands(runtimeId, targetPlatform = currentRuntimePlatform()) {
const runtime = connectorRuntimeById(runtimeId);
if (!runtime) return [];
const commands = runtime.install.commands;
return commands?.[targetPlatform] ?? commands?.default ?? [];
}
function connectorRuntimeInstallCommand(runtimeId, targetPlatform = currentRuntimePlatform()) {
return connectorRuntimeInstallCommands(runtimeId, targetPlatform)[0] ?? null;
}
// src/index.ts
var DEFAULT_SERVER_URL = "https://shadowob.com";
var DEFAULT_WORK_DIR = ".";
var DEFAULT_PROJECT_NAME = "shadow-buddy";
var DEFAULT_CC_AGENT = "codex";
var shellQuote = (value) => {
if (!value) return "''";
return `'${value.replace(/'/g, `'\\''`)}'`;
};
var normalizeServerUrl = (value) => {
const trimmed = value.trim() || DEFAULT_SERVER_URL;
return trimmed.endsWith("/api") ? trimmed.slice(0, -4) : trimmed.replace(/\/$/, "");
};
var tokenOrPlaceholder = (token) => token.trim() || "<BUDDY_TOKEN>";
function tomlMultilineString(value) {
return `"""${value.replace(/"""/g, '\\"\\"\\"')}"""`;
}
function modelProviderEnvLines(provider) {
if (!provider) return [];
const openAI = connectorModelProviderEndpoint(provider, "openai");
const anthropic = connectorModelProviderEndpoint(provider, "anthropic");
return [
...openAI ? [
`OPENAI_COMPATIBLE_BASE_URL=${shellQuote(openAI.baseUrl)}`,
`OPENAI_COMPATIBLE_API_KEY=${shellQuote(openAI.apiKey)}`,
`OPENAI_COMPATIBLE_MODEL_ID=${shellQuote(provider.model)}`
] : [],
...anthropic ? [
`ANTHROPIC_COMPATIBLE_BASE_URL=${shellQuote(anthropic.baseUrl)}`,
`ANTHROPIC_COMPATIBLE_API_KEY=${shellQuote(anthropic.apiKey)}`,
`ANTHROPIC_COMPATIBLE_MODEL_ID=${shellQuote(provider.model)}`
] : [],
`SHADOW_MODEL_PROVIDER_ID=${shellQuote(provider.id ?? "shadow-official")}`
];
}
function modelProviderCapabilities(provider, capabilities) {
return provider ? [...capabilities, "officialModelProvider"] : capabilities;
}
function buildOpenClawPlan(input) {
const token = tokenOrPlaceholder(input.token);
const serverUrl = normalizeServerUrl(input.serverUrl);
const modelProvider = normalizeConnectorModelProvider(input.modelProvider);
const openAIProvider = connectorModelProviderEndpoint(modelProvider, "openai");
const jsonConfig = JSON.stringify(
{
channels: {
shadowob: {
token,
serverUrl
}
},
...modelProvider && openAIProvider ? {
models: {
mode: "merge",
pricing: { enabled: false },
providers: {
[modelProvider.id ?? "shadow-official"]: {
api: "openai-completions",
apiKey: "${env:OPENAI_COMPATIBLE_API_KEY}",
baseUrl: openAIProvider.baseUrl,
request: { allowPrivateNetwork: true },
models: [{ id: modelProvider.model, name: modelProvider.model }]
}
}
}
} : {}
},
null,
2
);
const commands = [
{
label: "Install plugin",
command: "openclaw plugins install @shadowob/openclaw-shadowob"
},
{
label: "Set Buddy token",
command: `openclaw config set channels.shadowob.token ${shellQuote(token)}`
},
{
label: "Set Shadow server URL",
command: `openclaw config set channels.shadowob.serverUrl ${shellQuote(serverUrl)}`
},
{
label: "Restart gateway",
command: "openclaw gateway restart"
}
];
const quickCommand = commands.map((item) => item.command).join(" && ");
const connectCommand = [
"npx @shadowob/connector@latest connect",
"--target openclaw",
`--server-url ${shellQuote(serverUrl)}`,
`--token ${shellQuote(token)}`
].join(" ");
return {
target: "openclaw",
title: "OpenClaw",
summary: "Install the Shadow channel plugin, Shadow CLI bin/skills, and a Buddy CLI profile for OpenClaw.",
connectCommand,
quickCommand,
commands,
configBlocks: [{ label: "~/.openclaw/openclaw.json", language: "json", content: jsonConfig }],
aiPrompt: [
"Configure this Shadow Buddy in OpenClaw.",
"",
`Shadow server URL: ${serverUrl}`,
`Buddy token: ${token}`,
"",
`Preferred one-line setup: ${connectCommand}`,
"The connector installs/configures the Shadow CLI, official Shadow skill files, and the Buddy profile before applying the OpenClaw channel config.",
modelProvider ? `It also configures ${modelProvider.label ?? "Shadow official LLM proxy"} as an OpenAI-compatible model provider (${modelProvider.model}).` : "",
"",
"Run these steps in order:",
...commands.map((item, index) => `${index + 1}. ${item.command}`),
"",
"Confirm each step and then verify the gateway is running."
].join("\n"),
docsUrl: "/product/index.html",
capabilities: modelProviderCapabilities(modelProvider, [
"channelMessages",
"dms",
"threads",
"mentions",
"attachments",
"images",
"interactive",
"slashCommands",
"onlineStatus",
"typing",
"activityStatus",
"reactions",
"editDelete",
"statusChecks",
"usageCosts",
"multiAgentBinding",
"shadowCliLogin",
"notifications",
"officialSkills",
"cronTasks"
])
};
}
function buildHermesPlan(input) {
const token = tokenOrPlaceholder(input.token);
const serverUrl = normalizeServerUrl(input.serverUrl);
const modelProvider = normalizeConnectorModelProvider(input.modelProvider);
const openAIProvider = connectorModelProviderEndpoint(modelProvider, "openai");
const envBlock = [
`SHADOW_BASE_URL=${shellQuote(serverUrl)}`,
`SHADOW_TOKEN=${shellQuote(token)}`,
"SHADOW_ALLOW_ALL_USERS=true",
"SHADOW_HEARTBEAT_INTERVAL_SECONDS=30",
...modelProviderEnvLines(modelProvider)
].join("\n");
const yamlConfig = [
"plugins:",
" enabled:",
" - shadowob",
"",
"platforms:",
" shadowob:",
" enabled: true",
` token: "${token}"`,
" extra:",
` base_url: "${serverUrl}"`,
" mention_only: false",
" rest_only: false",
" catchup_minutes: 0",
" download_media: true",
" slash_commands: []",
...modelProvider && openAIProvider ? [
"",
"model:",
` default: "${modelProvider.model}"`,
` provider: "${modelProvider.id ?? "shadow-official"}"`,
"",
"custom_providers:",
` - name: "${modelProvider.id ?? "shadow-official"}"`,
` base_url: "${openAIProvider.baseUrl}"`,
" key_env: OPENAI_COMPATIBLE_API_KEY",
` model: "${modelProvider.model}"`
] : []
].join("\n");
const commands = [
{
label: "Copy plugin directory",
command: "mkdir -p ~/.hermes/plugins && cp -R ./packages/connector/hermes-shadowob-plugin ~/.hermes/plugins/shadowob"
},
{
label: "Install plugin dependencies",
command: "python -m pip install -r ~/.hermes/plugins/shadowob/requirements.txt"
},
{
label: "Enable plugin",
command: "hermes plugins enable shadowob"
},
{
label: "Start gateway",
command: "hermes gateway"
}
];
const connectCommand = [
"npx @shadowob/connector@latest connect",
"--target hermes",
`--server-url ${shellQuote(serverUrl)}`,
`--token ${shellQuote(token)}`
].join(" ");
return {
target: "hermes",
title: "Hermes Agent",
summary: "Install the ShadowOB Hermes platform plugin, Shadow CLI bin/skills, and a Buddy CLI profile.",
connectCommand,
quickCommand: commands.map((item) => item.command).join(" && "),
commands,
configBlocks: [
{ label: "~/.hermes/.env", language: "bash", content: envBlock },
{ label: "~/.hermes/config.yaml", language: "yaml", content: yamlConfig }
],
aiPrompt: [
"Configure this Shadow Buddy in Hermes Agent.",
"",
`Shadow server URL: ${serverUrl}`,
`Buddy token: ${token}`,
"",
`Preferred one-line setup: ${connectCommand}`,
"The connector installs/configures the Shadow CLI, official Shadow skill files, and the Buddy profile before writing Hermes config. The plugin resolves the Buddy agent id and channel policy from Shadow at runtime.",
modelProvider && openAIProvider ? `It also configures Hermes custom model endpoint ${openAIProvider.baseUrl} with model ${modelProvider.model}.` : ""
].join("\n"),
docsUrl: "https://hermes-agent.nousresearch.com/docs/user-guide/messaging",
capabilities: modelProviderCapabilities(modelProvider, [
"channelMessages",
"dms",
"threads",
"attachments",
"images",
"interactive",
"slashCommands",
"onlineStatus",
"typing",
"activityStatus",
"cronDelivery",
"statusChecks",
"usageCosts",
"shadowCliLogin",
"notifications",
"officialSkills"
])
};
}
function buildCcConnectPlan(input) {
const token = tokenOrPlaceholder(input.token);
const serverUrl = normalizeServerUrl(input.serverUrl);
const projectName = input.projectName?.trim() || DEFAULT_PROJECT_NAME;
const workDir = input.workDir?.trim() || DEFAULT_WORK_DIR;
const agentType = input.agentType?.trim() || DEFAULT_CC_AGENT;
const modelProvider = normalizeConnectorModelProvider(input.modelProvider);
const providerEndpoint = connectorModelProviderEndpoint(
modelProvider,
agentType === "claudecode" ? "anthropic" : "openai"
);
const providerId = modelProvider?.id ?? "shadow-official";
const providerModel = modelProvider ? ccConnectModelRef(agentType, providerId, modelProvider.model) : null;
const tomlConfig = [
'language = "zh"',
"",
"[[projects]]",
`name = "${projectName}"`,
"",
"[projects.agent]",
`type = "${agentType}"`,
"",
"[projects.agent.options]",
`work_dir = "${workDir}"`,
`system_prompt = ${tomlMultilineString(BUDDY_COLLABORATION_SYSTEM_PROMPT)}`,
...modelProvider && providerEndpoint ? [
`provider = "${providerId}"`,
`model = "${providerModel}"`,
"",
"[[projects.agent.providers]]",
`name = "${providerId}"`,
`api_key = "${providerEndpoint.apiKey}"`,
`base_url = "${providerEndpoint.baseUrl}"`,
`model = "${providerModel}"`,
"",
"[[projects.agent.providers.models]]",
`model = "${providerModel}"`
] : [],
"",
"[projects.display]",
'mode = "quiet"',
"thinking_messages = false",
"tool_messages = false",
"",
"[[projects.platforms]]",
'type = "shadowob"',
"",
"[projects.platforms.options]",
`token = "${token}"`,
`server_url = "${serverUrl}"`,
'allow_from = "*"',
"listen_dms = true",
"share_session_in_channel = false",
'progress_style = "compact"'
].join("\n");
const connectCommand = [
"npx @shadowob/connector@latest connect",
"--target cc-connect",
`--server-url ${shellQuote(serverUrl)}`,
`--token ${shellQuote(token)}`,
`--work-dir ${shellQuote(workDir)}`,
`--project-name ${shellQuote(projectName)}`,
`--agent-type ${shellQuote(agentType)}`
].join(" ");
const installCommand = `${connectCommand} --install`;
const startCommand = `${connectCommand} --install --start`;
const commands = [
{
label: "Install ShadowOB cc-connect fork",
command: installCommand
},
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
{
label: "Edit config",
command: "$EDITOR ~/.cc-connect/config.toml"
},
{ label: "Start ShadowOB cc-connect fork", command: startCommand }
];
return {
target: "cc-connect",
title: "cc-connect",
summary: `Use ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF} with ShadowOB Socket.IO support, Shadow CLI bin/skills, and a Buddy CLI profile.`,
connectCommand: startCommand,
quickCommand: startCommand,
commands,
configBlocks: [{ label: "~/.cc-connect/config.toml", language: "toml", content: tomlConfig }],
aiPrompt: [
"Configure this Shadow Buddy in cc-connect.",
"",
`Shadow server URL: ${serverUrl}`,
`Buddy token: ${token}`,
`Project work_dir: ${workDir}`,
`Agent type: ${agentType}`,
"",
`Preferred one-line setup: ${startCommand}`,
`Install ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF}, install/configure the Shadow CLI and official Shadow skill files, add the TOML platform block, and start cc-connect.`,
"Inbox task status hooks are handled by the installed Shadow CLI skill and server-delivered cliPolicy; cc-connect does not implement hook execution in its runtime prompt.",
"The generated config injects Shadow Buddy collaboration rules into the agent system prompt and sets cc-connect display mode to quiet so internal tool/progress events do not spill into Shadow channels.",
modelProvider ? `Configure ${modelProvider.label ?? "Shadow official LLM proxy"} as provider ${modelProvider.id ?? "shadow-official"} for ${agentType}.` : ""
].join("\n"),
docsUrl: CC_CONNECT_FORK_DOCS_URL,
capabilities: modelProviderCapabilities(modelProvider, [
"channelMessages",
"dms",
"attachments",
"images",
"interactive",
"slashCommands",
"typing",
"streamingPreviews",
"forms",
"statusChecks",
"usageCosts",
"multiAgentBinding",
"shadowCliLogin",
"notifications"
])
};
}
function createConnectorPlan(input) {
if (input.target === "openclaw") return buildOpenClawPlan(input);
if (input.target === "hermes") return buildHermesPlan(input);
if (input.target === "cc-connect") return buildCcConnectPlan(input);
throw new Error(`Unsupported connector target: ${String(input.target)}`);
}
function createConnectorPlans(input) {
return ["openclaw", "hermes", "cc-connect"].map(
(target) => createConnectorPlan({ ...input, target })
);
}
export {
CONNECTOR_RUNTIME_CATALOG,
connectorRuntimeCatalog,
connectorRuntimeById,
connectorRuntimeInstallCommands,
connectorRuntimeInstallCommand,
createConnectorPlan,
createConnectorPlans
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display