mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-22 05:25:08 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68ddbe17c5 |
+4
-48
@@ -30,7 +30,7 @@
|
||||
import { createServer } from "node:http";
|
||||
import { spawn, execFileSync } from "node:child_process";
|
||||
import { randomUUID, timingSafeEqual } from "node:crypto";
|
||||
import { readFileSync, readdirSync, accessSync, existsSync, constants } from "node:fs";
|
||||
import { readFileSync, accessSync, existsSync, constants } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { dirname, join } from "node:path";
|
||||
import { homedir } from "node:os";
|
||||
@@ -41,48 +41,8 @@ const _pkg = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8"));
|
||||
const modelsConfig = JSON.parse(readFileSync(join(__dirname, "models.json"), "utf8"));
|
||||
|
||||
// ── Resolve claude binary ───────────────────────────────────────────────
|
||||
// Priority: CLAUDE_BIN env > well-known paths > nvm/fnm/asdf user-local
|
||||
// installs > which lookup. Fail-fast if not found — never start with an
|
||||
// unresolvable binary.
|
||||
function _listVersionDirs(parent) {
|
||||
try { return readdirSync(parent); } catch { return []; }
|
||||
}
|
||||
function _collectNodeManagerCandidates(home) {
|
||||
if (!home) return [];
|
||||
const out = [];
|
||||
|
||||
// nvm: $HOME/.nvm/versions/node/<version>/bin/claude
|
||||
const nvmRoot = join(home, ".nvm/versions/node");
|
||||
for (const v of _listVersionDirs(nvmRoot)) {
|
||||
out.push(join(nvmRoot, v, "bin/claude"));
|
||||
}
|
||||
// nvm default alias: resolve $HOME/.nvm/aliases/default if it points to a version
|
||||
try {
|
||||
const aliasFile = join(home, ".nvm/aliases/default");
|
||||
const aliasVer = readFileSync(aliasFile, "utf8").trim();
|
||||
if (aliasVer) {
|
||||
const direct = join(nvmRoot, aliasVer, "bin/claude");
|
||||
if (!out.includes(direct)) out.unshift(direct);
|
||||
}
|
||||
} catch {}
|
||||
|
||||
// fnm: $HOME/.fnm/node-versions/<version>/installation/bin/claude
|
||||
const fnmRoot = join(home, ".fnm/node-versions");
|
||||
for (const v of _listVersionDirs(fnmRoot)) {
|
||||
out.push(join(fnmRoot, v, "installation/bin/claude"));
|
||||
}
|
||||
|
||||
// asdf: $HOME/.asdf/installs/nodejs/<version>/bin/claude
|
||||
const asdfRoot = join(home, ".asdf/installs/nodejs");
|
||||
for (const v of _listVersionDirs(asdfRoot)) {
|
||||
out.push(join(asdfRoot, v, "bin/claude"));
|
||||
}
|
||||
|
||||
// npm prefix-relocated: $HOME/.npm-global/bin/claude
|
||||
out.push(join(home, ".npm-global/bin/claude"));
|
||||
|
||||
return out;
|
||||
}
|
||||
// Priority: CLAUDE_BIN env > well-known paths > which lookup
|
||||
// Fail-fast if not found — never start with an unresolvable binary.
|
||||
function resolveClaude() {
|
||||
if (process.env.CLAUDE_BIN) {
|
||||
try {
|
||||
@@ -94,13 +54,11 @@ function resolveClaude() {
|
||||
}
|
||||
}
|
||||
|
||||
const home = process.env.HOME || "";
|
||||
const candidates = [
|
||||
"/opt/homebrew/bin/claude",
|
||||
"/usr/local/bin/claude",
|
||||
"/usr/bin/claude",
|
||||
join(home, ".local/bin/claude"),
|
||||
..._collectNodeManagerCandidates(home),
|
||||
join(process.env.HOME || "", ".local/bin/claude"),
|
||||
];
|
||||
for (const p of candidates) {
|
||||
try { accessSync(p, constants.X_OK); console.warn(`[init] CLAUDE_BIN not set, resolved to ${p}`); return p; } catch {}
|
||||
@@ -114,8 +72,6 @@ function resolveClaude() {
|
||||
console.error(
|
||||
"FATAL: claude binary not found.\n" +
|
||||
" Set CLAUDE_BIN=/path/to/claude or ensure claude is in PATH.\n" +
|
||||
" Hint: if you use nvm/fnm/asdf, set CLAUDE_BIN to the absolute path\n" +
|
||||
" shown by `which claude` in your interactive shell.\n" +
|
||||
" Checked: " + candidates.join(", ")
|
||||
);
|
||||
process.exit(1);
|
||||
|
||||
@@ -39,6 +39,29 @@ const PROVIDER_NAME = opt("provider-name", "claude-local");
|
||||
const BIND_ADDRESS = opt("bind", "127.0.0.1");
|
||||
const AUTH_MODE_CONFIG = opt("auth-mode", "none");
|
||||
|
||||
// ── Service-env injection: CLAUDE_BIN, OCP_ADMIN_KEY, PROXY_ANONYMOUS_KEY ──
|
||||
// These are read from the user's shell env at install time and written into
|
||||
// the service unit (plist / systemd) so the daemon picks them up on boot.
|
||||
|
||||
// CLAUDE_BIN — detect at install time; omit if not found (server.mjs fallback)
|
||||
let CLAUDE_BIN_INJECT = null;
|
||||
if (process.env.CLAUDE_BIN) {
|
||||
CLAUDE_BIN_INJECT = process.env.CLAUDE_BIN;
|
||||
} else {
|
||||
try {
|
||||
const detected = execSync("which claude 2>/dev/null", { encoding: "utf-8" }).trim();
|
||||
if (detected && existsSync(detected)) {
|
||||
CLAUDE_BIN_INJECT = detected;
|
||||
}
|
||||
} catch { /* which not available or claude not on PATH — omit */ }
|
||||
}
|
||||
|
||||
// OCP_ADMIN_KEY — omit entirely when empty/unset; don't write empty string
|
||||
const OCP_ADMIN_KEY_INJECT = process.env.OCP_ADMIN_KEY || null;
|
||||
|
||||
// PROXY_ANONYMOUS_KEY — same pattern
|
||||
const PROXY_ANON_KEY_INJECT = process.env.PROXY_ANONYMOUS_KEY || null;
|
||||
|
||||
// ── Models: derived from models.json (single source of truth) ──────────
|
||||
const modelsConfig = JSON.parse(readFileSync(join(__dirname, "models.json"), "utf-8"));
|
||||
|
||||
@@ -286,6 +309,29 @@ banner.push(`╚═════════════════════
|
||||
console.log("\n" + banner.join("\n") + "\n");
|
||||
|
||||
// ── Step 7: Install auto-start on boot ──────────────────────────────────
|
||||
|
||||
// Log service-env injection plan (shown in both dry-run and live mode)
|
||||
console.log("\n🔧 Service unit env vars to inject:\n");
|
||||
if (CLAUDE_BIN_INJECT) {
|
||||
log(`CLAUDE_BIN: ${CLAUDE_BIN_INJECT}`);
|
||||
} else {
|
||||
log(`CLAUDE_BIN: (not found — server.mjs will auto-detect at runtime)`);
|
||||
}
|
||||
if (OCP_ADMIN_KEY_INJECT) {
|
||||
log(`OCP_ADMIN_KEY: injected (length: ${OCP_ADMIN_KEY_INJECT.length})`);
|
||||
} else {
|
||||
log(`OCP_ADMIN_KEY: (unset — admin endpoints disabled)`);
|
||||
}
|
||||
if (PROXY_ANON_KEY_INJECT) {
|
||||
log(`PROXY_ANONYMOUS_KEY: injected (set)`);
|
||||
} else {
|
||||
log(`PROXY_ANONYMOUS_KEY: (unset — anonymous access disabled)`);
|
||||
}
|
||||
|
||||
if (DRY_RUN) {
|
||||
console.log("\n [dry-run] would write service unit with above env vars\n");
|
||||
}
|
||||
|
||||
if (!DRY_RUN) {
|
||||
console.log("\n🔄 Installing auto-start on login...\n");
|
||||
|
||||
@@ -358,7 +404,13 @@ if (!DRY_RUN) {
|
||||
<key>CLAUDE_BIND</key>
|
||||
<string>${BIND_ADDRESS}</string>
|
||||
<key>CLAUDE_AUTH_MODE</key>
|
||||
<string>${AUTH_MODE_CONFIG}</string>
|
||||
<string>${AUTH_MODE_CONFIG}</string>${CLAUDE_BIN_INJECT ? `
|
||||
<key>CLAUDE_BIN</key>
|
||||
<string>${CLAUDE_BIN_INJECT}</string>` : ""}${OCP_ADMIN_KEY_INJECT ? `
|
||||
<key>OCP_ADMIN_KEY</key>
|
||||
<string>${OCP_ADMIN_KEY_INJECT}</string>` : ""}${PROXY_ANON_KEY_INJECT ? `
|
||||
<key>PROXY_ANONYMOUS_KEY</key>
|
||||
<string>${PROXY_ANON_KEY_INJECT}</string>` : ""}
|
||||
</dict>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
@@ -396,7 +448,7 @@ After=network.target
|
||||
ExecStart=${nodeBin} ${serverPath}
|
||||
Environment=CLAUDE_PROXY_PORT=${PORT}
|
||||
Environment=CLAUDE_BIND=${BIND_ADDRESS}
|
||||
Environment=CLAUDE_AUTH_MODE=${AUTH_MODE_CONFIG}
|
||||
Environment=CLAUDE_AUTH_MODE=${AUTH_MODE_CONFIG}${CLAUDE_BIN_INJECT ? `\nEnvironment=CLAUDE_BIN=${CLAUDE_BIN_INJECT}` : ""}${OCP_ADMIN_KEY_INJECT ? `\nEnvironment=OCP_ADMIN_KEY=${OCP_ADMIN_KEY_INJECT}` : ""}${PROXY_ANON_KEY_INJECT ? `\nEnvironment=PROXY_ANONYMOUS_KEY=${PROXY_ANON_KEY_INJECT}` : ""}
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
StandardOutput=append:${logPath}
|
||||
|
||||
Reference in New Issue
Block a user