mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-21 21:15:09 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
983ad4f18b |
@@ -12,7 +12,7 @@
|
||||
* 4. Creates start.sh for easy launch
|
||||
* 5. Optionally starts the proxy
|
||||
*/
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs";
|
||||
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from "node:fs";
|
||||
import { execSync } from "node:child_process";
|
||||
import { join, dirname } from "node:path";
|
||||
import { homedir } from "node:os";
|
||||
@@ -107,106 +107,112 @@ try {
|
||||
warn("Make sure you're logged in: claude login");
|
||||
}
|
||||
|
||||
// Check openclaw config
|
||||
if (!existsSync(CONFIG_PATH)) fail(`OpenClaw config not found at ${CONFIG_PATH}`);
|
||||
log(`OpenClaw config: ${CONFIG_PATH}`);
|
||||
// Check openclaw config (optional — OCP runs standalone without OpenClaw)
|
||||
const OPENCLAW_PRESENT = existsSync(CONFIG_PATH);
|
||||
if (OPENCLAW_PRESENT) {
|
||||
log(`OpenClaw config: ${CONFIG_PATH}`);
|
||||
} else {
|
||||
warn(`OpenClaw not detected at ${CONFIG_PATH} — skipping OpenClaw integration.`);
|
||||
warn(`To register OCP with OpenClaw later, install OpenClaw and re-run \`node setup.mjs\`,`);
|
||||
warn(`or run \`ocp update\` if OpenClaw is installed afterward.`);
|
||||
}
|
||||
|
||||
// ── Step 2: Patch openclaw.json ─────────────────────────────────────────
|
||||
console.log("\n📝 Configuring OpenClaw...\n");
|
||||
if (OPENCLAW_PRESENT) {
|
||||
console.log("\n📝 Configuring OpenClaw...\n");
|
||||
|
||||
const config = readJSON(CONFIG_PATH);
|
||||
const config = readJSON(CONFIG_PATH);
|
||||
|
||||
// Ensure models.providers exists
|
||||
if (!config.models) config.models = {};
|
||||
if (!config.models.providers) config.models.providers = {};
|
||||
// Ensure models.providers exists
|
||||
if (!config.models) config.models = {};
|
||||
if (!config.models.providers) config.models.providers = {};
|
||||
|
||||
// Add/update claude-local provider
|
||||
config.models.providers[PROVIDER_NAME] = {
|
||||
baseUrl: `http://127.0.0.1:${PORT}/v1`,
|
||||
api: "openai-completions",
|
||||
authHeader: false,
|
||||
models: MODELS,
|
||||
};
|
||||
log(`Provider "${PROVIDER_NAME}" → http://127.0.0.1:${PORT}/v1`);
|
||||
// Add/update claude-local provider
|
||||
config.models.providers[PROVIDER_NAME] = {
|
||||
baseUrl: `http://127.0.0.1:${PORT}/v1`,
|
||||
api: "openai-completions",
|
||||
authHeader: false,
|
||||
models: MODELS,
|
||||
};
|
||||
log(`Provider "${PROVIDER_NAME}" → http://127.0.0.1:${PORT}/v1`);
|
||||
|
||||
// Ensure auth profile in config
|
||||
if (!config.auth) config.auth = {};
|
||||
if (!config.auth.profiles) config.auth.profiles = {};
|
||||
config.auth.profiles[`${PROVIDER_NAME}:default`] = {
|
||||
provider: PROVIDER_NAME,
|
||||
mode: "api_key",
|
||||
};
|
||||
log(`Auth profile "${PROVIDER_NAME}:default" registered`);
|
||||
// Ensure auth profile in config
|
||||
if (!config.auth) config.auth = {};
|
||||
if (!config.auth.profiles) config.auth.profiles = {};
|
||||
config.auth.profiles[`${PROVIDER_NAME}:default`] = {
|
||||
provider: PROVIDER_NAME,
|
||||
mode: "api_key",
|
||||
};
|
||||
log(`Auth profile "${PROVIDER_NAME}:default" registered`);
|
||||
|
||||
// Add models to agents.defaults.models
|
||||
if (!config.agents) config.agents = {};
|
||||
if (!config.agents.defaults) config.agents.defaults = {};
|
||||
if (!config.agents.defaults.models) config.agents.defaults.models = {};
|
||||
for (const [key, val] of Object.entries(MODEL_ALIASES)) {
|
||||
config.agents.defaults.models[key] = val;
|
||||
}
|
||||
log(`Model aliases added to agents.defaults.models`);
|
||||
|
||||
// Set idleTimeoutSeconds to 0 — critical for Claude tool-use.
|
||||
// When Claude calls tools (Bash, Read, etc.), the token stream pauses for 30-120s.
|
||||
// OpenClaw's default idleTimeoutSeconds (60s) kills the connection mid-tool-call,
|
||||
// causing exit 143 (SIGTERM) and stuck sessions. Setting to 0 disables the idle timer.
|
||||
if (!config.agents.defaults.llm) config.agents.defaults.llm = {};
|
||||
if (config.agents.defaults.llm.idleTimeoutSeconds === undefined ||
|
||||
config.agents.defaults.llm.idleTimeoutSeconds > 0) {
|
||||
config.agents.defaults.llm.idleTimeoutSeconds = 0;
|
||||
log(`Set agents.defaults.llm.idleTimeoutSeconds = 0 (prevents tool-call timeouts)`);
|
||||
} else {
|
||||
log(`idleTimeoutSeconds already configured: ${config.agents.defaults.llm.idleTimeoutSeconds}`);
|
||||
}
|
||||
|
||||
writeJSON(CONFIG_PATH, config);
|
||||
log(`Config saved`);
|
||||
|
||||
// ── Step 3: Patch auth-profiles.json ────────────────────────────────────
|
||||
console.log("\n🔑 Configuring auth profiles...\n");
|
||||
|
||||
// Find all agent auth-profiles.json files
|
||||
const agentsDir = join(OPENCLAW_DIR, "agents");
|
||||
const agentDirs = existsSync(agentsDir)
|
||||
? readdirSync(agentsDir).filter((d) => {
|
||||
const ap = join(agentsDir, d, "agent", "auth-profiles.json");
|
||||
return existsSync(ap);
|
||||
})
|
||||
: [];
|
||||
|
||||
import { readdirSync } from "node:fs";
|
||||
|
||||
for (const agentId of agentDirs) {
|
||||
const apPath = join(agentsDir, agentId, "agent", "auth-profiles.json");
|
||||
try {
|
||||
const ap = readJSON(apPath);
|
||||
if (!ap.profiles) ap.profiles = {};
|
||||
|
||||
// Add claude-local profile if missing
|
||||
if (!ap.profiles[`${PROVIDER_NAME}:default`]) {
|
||||
ap.profiles[`${PROVIDER_NAME}:default`] = {
|
||||
type: "api_key",
|
||||
provider: PROVIDER_NAME,
|
||||
key: "local-proxy-no-auth",
|
||||
};
|
||||
}
|
||||
|
||||
// Add to lastGood if missing
|
||||
if (!ap.lastGood) ap.lastGood = {};
|
||||
if (!ap.lastGood[PROVIDER_NAME]) {
|
||||
ap.lastGood[PROVIDER_NAME] = `${PROVIDER_NAME}:default`;
|
||||
}
|
||||
|
||||
writeJSON(apPath, ap);
|
||||
log(`Agent "${agentId}" auth profile updated`);
|
||||
} catch (e) {
|
||||
warn(`Skipped agent "${agentId}": ${e.message}`);
|
||||
// Add models to agents.defaults.models
|
||||
if (!config.agents) config.agents = {};
|
||||
if (!config.agents.defaults) config.agents.defaults = {};
|
||||
if (!config.agents.defaults.models) config.agents.defaults.models = {};
|
||||
for (const [key, val] of Object.entries(MODEL_ALIASES)) {
|
||||
config.agents.defaults.models[key] = val;
|
||||
}
|
||||
}
|
||||
log(`Model aliases added to agents.defaults.models`);
|
||||
|
||||
if (agentDirs.length === 0) {
|
||||
warn("No agent auth-profiles.json found — you may need to restart the gateway first");
|
||||
// Set idleTimeoutSeconds to 0 — critical for Claude tool-use.
|
||||
// When Claude calls tools (Bash, Read, etc.), the token stream pauses for 30-120s.
|
||||
// OpenClaw's default idleTimeoutSeconds (60s) kills the connection mid-tool-call,
|
||||
// causing exit 143 (SIGTERM) and stuck sessions. Setting to 0 disables the idle timer.
|
||||
if (!config.agents.defaults.llm) config.agents.defaults.llm = {};
|
||||
if (config.agents.defaults.llm.idleTimeoutSeconds === undefined ||
|
||||
config.agents.defaults.llm.idleTimeoutSeconds > 0) {
|
||||
config.agents.defaults.llm.idleTimeoutSeconds = 0;
|
||||
log(`Set agents.defaults.llm.idleTimeoutSeconds = 0 (prevents tool-call timeouts)`);
|
||||
} else {
|
||||
log(`idleTimeoutSeconds already configured: ${config.agents.defaults.llm.idleTimeoutSeconds}`);
|
||||
}
|
||||
|
||||
writeJSON(CONFIG_PATH, config);
|
||||
log(`Config saved`);
|
||||
|
||||
// ── Step 3: Patch auth-profiles.json ────────────────────────────────────
|
||||
console.log("\n🔑 Configuring auth profiles...\n");
|
||||
|
||||
// Find all agent auth-profiles.json files
|
||||
const agentsDir = join(OPENCLAW_DIR, "agents");
|
||||
const agentDirs = existsSync(agentsDir)
|
||||
? readdirSync(agentsDir).filter((d) => {
|
||||
const ap = join(agentsDir, d, "agent", "auth-profiles.json");
|
||||
return existsSync(ap);
|
||||
})
|
||||
: [];
|
||||
|
||||
for (const agentId of agentDirs) {
|
||||
const apPath = join(agentsDir, agentId, "agent", "auth-profiles.json");
|
||||
try {
|
||||
const ap = readJSON(apPath);
|
||||
if (!ap.profiles) ap.profiles = {};
|
||||
|
||||
// Add claude-local profile if missing
|
||||
if (!ap.profiles[`${PROVIDER_NAME}:default`]) {
|
||||
ap.profiles[`${PROVIDER_NAME}:default`] = {
|
||||
type: "api_key",
|
||||
provider: PROVIDER_NAME,
|
||||
key: "local-proxy-no-auth",
|
||||
};
|
||||
}
|
||||
|
||||
// Add to lastGood if missing
|
||||
if (!ap.lastGood) ap.lastGood = {};
|
||||
if (!ap.lastGood[PROVIDER_NAME]) {
|
||||
ap.lastGood[PROVIDER_NAME] = `${PROVIDER_NAME}:default`;
|
||||
}
|
||||
|
||||
writeJSON(apPath, ap);
|
||||
log(`Agent "${agentId}" auth profile updated`);
|
||||
} catch (e) {
|
||||
warn(`Skipped agent "${agentId}": ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (agentDirs.length === 0) {
|
||||
warn("No agent auth-profiles.json found — you may need to restart the gateway first");
|
||||
}
|
||||
}
|
||||
|
||||
// ── Step 4: Create start.sh ─────────────────────────────────────────────
|
||||
@@ -238,31 +244,46 @@ if (!DRY_RUN) {
|
||||
log(`Launcher: ${startPath}`);
|
||||
|
||||
// ── Step 5: Summary ─────────────────────────────────────────────────────
|
||||
console.log(`
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ Setup complete! ║
|
||||
╠══════════════════════════════════════════════════════════════╣
|
||||
║ ║
|
||||
║ Provider: ${PROVIDER_NAME.padEnd(44)}║
|
||||
║ Port: ${String(PORT).padEnd(44)}║
|
||||
║ Models: ${`see models.json (${MODELS.length} available)`.padEnd(44)}║
|
||||
║ Default: ${DEFAULT_MODEL_ID.padEnd(44)}║
|
||||
║ ║
|
||||
║ Start proxy: ║
|
||||
║ bash ${startPath.replace(HOME, "~").padEnd(50)}║
|
||||
║ ║
|
||||
║ Or directly: ║
|
||||
║ node ${serverPath.replace(HOME, "~").padEnd(49)}║
|
||||
║ ║
|
||||
║ Set as default model in openclaw.json: ║
|
||||
║ agents.defaults.model.primary = ║
|
||||
║ "${PROVIDER_NAME}/${DEFAULT_MODEL_ID}"${" ".repeat(Math.max(0, 30 - PROVIDER_NAME.length - DEFAULT_MODEL_ID.length))}║
|
||||
║ ║
|
||||
║ Then restart gateway: ║
|
||||
║ openclaw gateway restart ║
|
||||
║ ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
`);
|
||||
const banner = [
|
||||
`╔══════════════════════════════════════════════════════════════╗`,
|
||||
`║ Setup complete! ║`,
|
||||
`╠══════════════════════════════════════════════════════════════╣`,
|
||||
`║ ║`,
|
||||
`║ Provider: ${PROVIDER_NAME.padEnd(44)}║`,
|
||||
`║ Port: ${String(PORT).padEnd(44)}║`,
|
||||
`║ Models: ${`see models.json (${MODELS.length} available)`.padEnd(44)}║`,
|
||||
`║ Default: ${DEFAULT_MODEL_ID.padEnd(44)}║`,
|
||||
`║ ║`,
|
||||
`║ Start proxy: ║`,
|
||||
`║ bash ${startPath.replace(HOME, "~").padEnd(50)}║`,
|
||||
`║ ║`,
|
||||
`║ Or directly: ║`,
|
||||
`║ node ${serverPath.replace(HOME, "~").padEnd(49)}║`,
|
||||
`║ ║`,
|
||||
];
|
||||
if (OPENCLAW_PRESENT) {
|
||||
banner.push(
|
||||
`║ Set as default model in openclaw.json: ║`,
|
||||
`║ agents.defaults.model.primary = ║`,
|
||||
`║ "${PROVIDER_NAME}/${DEFAULT_MODEL_ID}"${" ".repeat(Math.max(0, 30 - PROVIDER_NAME.length - DEFAULT_MODEL_ID.length))}║`,
|
||||
`║ ║`,
|
||||
`║ Then restart gateway: ║`,
|
||||
`║ openclaw gateway restart ║`,
|
||||
`║ ║`,
|
||||
);
|
||||
} else {
|
||||
banner.push(
|
||||
`║ OpenClaw not detected — running in standalone mode. ║`,
|
||||
`║ Point your IDE (Cline / Cursor / Continue / OpenCode / ║`,
|
||||
`║ Aider / OpenClaw) at: ║`,
|
||||
`║ http://${BIND_ADDRESS}:${String(PORT)}/v1${" ".repeat(Math.max(0, 47 - BIND_ADDRESS.length - String(PORT).length))}║`,
|
||||
`║ ║`,
|
||||
`║ See README § "Client Setup" for per-IDE instructions. ║`,
|
||||
`║ ║`,
|
||||
);
|
||||
}
|
||||
banner.push(`╚══════════════════════════════════════════════════════════════╝`);
|
||||
console.log("\n" + banner.join("\n") + "\n");
|
||||
|
||||
// ── Step 6: Optionally start ────────────────────────────────────────────
|
||||
if (!SKIP_START && !DRY_RUN) {
|
||||
|
||||
Reference in New Issue
Block a user