@vibe80/vibe80 0.1.3 → 0.1.8
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/bin/vibe80.js +15 -3
- package/package.json +1 -1
- package/server/src/claudeClient.js +3 -2
- package/server/src/index.js +28 -1
- package/server/src/middleware/auth.js +8 -1
- package/server/src/routes/worktrees.js +12 -1
- package/server/src/runAs.js +11 -3
- package/server/src/services/workspace.js +182 -7
- package/server/src/storage/sqlite.js +8 -1
package/bin/vibe80.js
CHANGED
|
@@ -14,12 +14,14 @@ const monoAuthUrlFile = path.join(
|
|
|
14
14
|
);
|
|
15
15
|
const defaultEnv = {
|
|
16
16
|
DEPLOYMENT_MODE: "mono_user",
|
|
17
|
-
|
|
17
|
+
VIBE80_DATA_DIRECTORY: path.join(homeDir, ".vibe80"),
|
|
18
18
|
STORAGE_BACKEND: "sqlite",
|
|
19
|
-
SQLITE_PATH: path.join(homeDir, ".vibe80", "data.sqlite"),
|
|
20
19
|
};
|
|
21
20
|
const deploymentMode = process.env.DEPLOYMENT_MODE || defaultEnv.DEPLOYMENT_MODE;
|
|
22
21
|
const serverPort = process.env.PORT || "5179";
|
|
22
|
+
const cliArgs = process.argv.slice(2);
|
|
23
|
+
const enableCodexFromCli = cliArgs.includes("--codex");
|
|
24
|
+
const enableClaudeFromCli = cliArgs.includes("--claude");
|
|
23
25
|
|
|
24
26
|
const spawnProcess = (cmd, args, label, extraEnv = {}) => {
|
|
25
27
|
const child = spawn(cmd, args, {
|
|
@@ -128,11 +130,21 @@ const shutdown = (code = 0) => {
|
|
|
128
130
|
|
|
129
131
|
const startServer = () => {
|
|
130
132
|
unlinkMonoAuthUrlFile();
|
|
133
|
+
const monoProviderEnv = {};
|
|
134
|
+
if (enableCodexFromCli) {
|
|
135
|
+
monoProviderEnv.VIBE80_MONO_ENABLE_CODEX = "true";
|
|
136
|
+
}
|
|
137
|
+
if (enableClaudeFromCli) {
|
|
138
|
+
monoProviderEnv.VIBE80_MONO_ENABLE_CLAUDE = "true";
|
|
139
|
+
}
|
|
131
140
|
server = spawnProcess(
|
|
132
141
|
process.execPath,
|
|
133
142
|
["server/src/index.js"],
|
|
134
143
|
"server",
|
|
135
|
-
{
|
|
144
|
+
{
|
|
145
|
+
VIBE80_MONO_AUTH_URL_FILE: monoAuthUrlFile,
|
|
146
|
+
...monoProviderEnv,
|
|
147
|
+
}
|
|
136
148
|
);
|
|
137
149
|
void maybeOpenMonoAuthUrl();
|
|
138
150
|
|
package/package.json
CHANGED
|
@@ -48,7 +48,7 @@ export class ClaudeCliClient extends EventEmitter {
|
|
|
48
48
|
this.tmpDir = tmpDir || null;
|
|
49
49
|
this.sessionId = sessionId || null;
|
|
50
50
|
this.worktreeId = worktreeId || "main";
|
|
51
|
-
this.ready =
|
|
51
|
+
this.ready = true;
|
|
52
52
|
this.threadId = threadId || null;
|
|
53
53
|
this.pendingForkFromThreadId = forkFromThreadId || null;
|
|
54
54
|
this.modelInfo = null;
|
|
@@ -77,7 +77,6 @@ export class ClaudeCliClient extends EventEmitter {
|
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
79
79
|
this.activeProcess = null;
|
|
80
|
-
this.ready = false;
|
|
81
80
|
const exitPromise = new Promise((resolve) => {
|
|
82
81
|
proc.once("exit", resolve);
|
|
83
82
|
proc.once("close", resolve);
|
|
@@ -223,6 +222,7 @@ export class ClaudeCliClient extends EventEmitter {
|
|
|
223
222
|
cwd: isMonoUser ? this.cwd : undefined,
|
|
224
223
|
});
|
|
225
224
|
this.activeProcess = proc;
|
|
225
|
+
this.ready = false;
|
|
226
226
|
|
|
227
227
|
proc.stdout.setEncoding("utf8");
|
|
228
228
|
proc.stdout.on("data", (chunk) => {
|
|
@@ -264,6 +264,7 @@ export class ClaudeCliClient extends EventEmitter {
|
|
|
264
264
|
if (this.activeProcess === proc) {
|
|
265
265
|
this.activeProcess = null;
|
|
266
266
|
}
|
|
267
|
+
this.ready = true;
|
|
267
268
|
this.#flushLogBuffer("OUT", "stdoutLogBuffer");
|
|
268
269
|
this.#flushLogBuffer("ERR", "stderrLogBuffer");
|
|
269
270
|
this.providerLogger?.close?.();
|
package/server/src/index.js
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
} from "./services/auth.js";
|
|
46
46
|
import {
|
|
47
47
|
ensureDefaultMonoWorkspace,
|
|
48
|
+
applyMonoUserProviderOverridesFromEnv,
|
|
48
49
|
isMonoUser,
|
|
49
50
|
getWorkspacePaths,
|
|
50
51
|
getWorkspaceSshPaths,
|
|
@@ -154,6 +155,7 @@ const sudoPath = process.env.VIBE80_SUDO_PATH || "sudo";
|
|
|
154
155
|
|
|
155
156
|
await storage.init();
|
|
156
157
|
await ensureDefaultMonoWorkspace();
|
|
158
|
+
await applyMonoUserProviderOverridesFromEnv();
|
|
157
159
|
|
|
158
160
|
// ---------------------------------------------------------------------------
|
|
159
161
|
// Middleware pipeline
|
|
@@ -660,9 +662,20 @@ wss.on("connection", (socket, req) => {
|
|
|
660
662
|
return;
|
|
661
663
|
}
|
|
662
664
|
const isMainWorktree = worktreeId === "main";
|
|
663
|
-
|
|
665
|
+
let client = isMainWorktree
|
|
664
666
|
? getActiveClient(session)
|
|
665
667
|
: runtime.worktreeClients.get(worktreeId);
|
|
668
|
+
if (isMainWorktree && !client) {
|
|
669
|
+
const provider = session.activeProvider === "claude" ? "claude" : "codex";
|
|
670
|
+
client = await getOrCreateClient(session, provider);
|
|
671
|
+
if (!client.listenerCount("ready")) {
|
|
672
|
+
if (provider === "claude") {
|
|
673
|
+
attachClaudeEvents(sessionId, client, provider);
|
|
674
|
+
} else {
|
|
675
|
+
attachClientEvents(sessionId, client, provider);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
666
679
|
if (!client?.ready) {
|
|
667
680
|
const label = isMainWorktree
|
|
668
681
|
? getProviderLabel(session)
|
|
@@ -1144,6 +1157,20 @@ wss.on("connection", (socket, req) => {
|
|
|
1144
1157
|
});
|
|
1145
1158
|
});
|
|
1146
1159
|
}
|
|
1160
|
+
} else if (session.activeProvider === "claude") {
|
|
1161
|
+
const client = await getOrCreateClient(session, "claude");
|
|
1162
|
+
if (!client.listenerCount("ready")) {
|
|
1163
|
+
attachClaudeEvents(sessionId, client, "claude");
|
|
1164
|
+
}
|
|
1165
|
+
if (!client.ready && !client.activeProcess) {
|
|
1166
|
+
client.start().catch((error) => {
|
|
1167
|
+
console.error("Failed to restart Claude CLI:", error);
|
|
1168
|
+
broadcastToSession(sessionId, {
|
|
1169
|
+
type: "error",
|
|
1170
|
+
message: "Claude CLI failed to start.",
|
|
1171
|
+
});
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1147
1174
|
}
|
|
1148
1175
|
|
|
1149
1176
|
authenticated = true;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
3
4
|
import path from "path";
|
|
4
5
|
import jwt from "jsonwebtoken";
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
+
const homeDir = process.env.HOME || os.homedir();
|
|
8
|
+
const isMonoUser = process.env.DEPLOYMENT_MODE === "mono_user";
|
|
9
|
+
const defaultDataDirectory = isMonoUser
|
|
10
|
+
? path.join(homeDir, ".vibe80")
|
|
11
|
+
: "/var/lib/vibe80";
|
|
12
|
+
const dataDirectory = process.env.VIBE80_DATA_DIRECTORY || defaultDataDirectory;
|
|
13
|
+
const jwtKeyPath = process.env.JWT_KEY_PATH || path.join(dataDirectory, "jwt.key");
|
|
7
14
|
const jwtIssuer = process.env.JWT_ISSUER || "vibe80";
|
|
8
15
|
const jwtAudience = process.env.JWT_AUDIENCE || "workspace";
|
|
9
16
|
const accessTokenTtlSeconds =
|
|
@@ -430,9 +430,20 @@ export default function worktreeRoutes(deps) {
|
|
|
430
430
|
|
|
431
431
|
const isMainWorktree = worktreeId === "main";
|
|
432
432
|
const runtime = getSessionRuntime(sessionId);
|
|
433
|
-
|
|
433
|
+
let client = isMainWorktree
|
|
434
434
|
? getActiveClient(session)
|
|
435
435
|
: runtime?.worktreeClients?.get(worktreeId);
|
|
436
|
+
if (isMainWorktree && !client) {
|
|
437
|
+
const provider = session.activeProvider === "claude" ? "claude" : "codex";
|
|
438
|
+
client = await getOrCreateClient(session, provider);
|
|
439
|
+
if (!client.listenerCount("ready")) {
|
|
440
|
+
if (provider === "claude") {
|
|
441
|
+
attachClaudeEvents(sessionId, client, provider);
|
|
442
|
+
} else {
|
|
443
|
+
attachClientEvents(sessionId, client, provider);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
436
447
|
if (!client?.ready) {
|
|
437
448
|
const label = isMainWorktree
|
|
438
449
|
? worktree.provider === "claude"
|
package/server/src/runAs.js
CHANGED
|
@@ -8,6 +8,8 @@ const SUDO_PATH = process.env.VIBE80_SUDO_PATH || "sudo";
|
|
|
8
8
|
const DEPLOYMENT_MODE = process.env.DEPLOYMENT_MODE;
|
|
9
9
|
const IS_MONO_USER = DEPLOYMENT_MODE === "mono_user";
|
|
10
10
|
const WORKSPACE_ROOT_DIRECTORY = process.env.WORKSPACE_ROOT_DIRECTORY || "/workspaces";
|
|
11
|
+
const MONO_USER_WORKSPACE_DIR =
|
|
12
|
+
process.env.MONO_USER_WORKSPACE_DIR || path.join(os.homedir(), "vibe80_workspace");
|
|
11
13
|
const ALLOWED_ENV_KEYS = new Set([
|
|
12
14
|
"GIT_SSH_COMMAND",
|
|
13
15
|
"GIT_CONFIG_GLOBAL",
|
|
@@ -151,15 +153,21 @@ export const getWorkspaceHome = (workspaceId) => {
|
|
|
151
153
|
|
|
152
154
|
export const getWorkspaceRoot = (workspaceId) =>
|
|
153
155
|
(IS_MONO_USER
|
|
154
|
-
?
|
|
156
|
+
? MONO_USER_WORKSPACE_DIR
|
|
155
157
|
: path.join(WORKSPACE_ROOT_DIRECTORY, workspaceId));
|
|
156
158
|
|
|
157
159
|
const validateCwd = (workspaceId, cwd) => {
|
|
158
160
|
const resolved = path.resolve(cwd);
|
|
159
161
|
const homeDir = getWorkspaceHome(workspaceId);
|
|
162
|
+
const workspaceRootDir = getWorkspaceRoot(workspaceId);
|
|
163
|
+
const inHome =
|
|
164
|
+
resolved === homeDir || resolved.startsWith(homeDir + path.sep);
|
|
165
|
+
const inWorkspaceRoot =
|
|
166
|
+
resolved === workspaceRootDir ||
|
|
167
|
+
resolved.startsWith(workspaceRootDir + path.sep);
|
|
160
168
|
if (
|
|
161
|
-
|
|
162
|
-
!
|
|
169
|
+
!inHome &&
|
|
170
|
+
!(IS_MONO_USER && inWorkspaceRoot)
|
|
163
171
|
) {
|
|
164
172
|
throw new Error("cwd outside workspace");
|
|
165
173
|
}
|
|
@@ -16,6 +16,8 @@ const isMonoUser = deploymentMode === "mono_user";
|
|
|
16
16
|
const workspaceHomeBase = process.env.WORKSPACE_HOME_BASE || "/home";
|
|
17
17
|
const workspaceRootBase = process.env.WORKSPACE_ROOT_DIRECTORY || "/workspaces";
|
|
18
18
|
const workspaceRootName = "vibe80_workspace";
|
|
19
|
+
const monoUserWorkspaceDir =
|
|
20
|
+
process.env.MONO_USER_WORKSPACE_DIR || path.join(os.homedir(), workspaceRootName);
|
|
19
21
|
const workspaceSessionsDirName = "sessions";
|
|
20
22
|
const rootHelperPath = process.env.VIBE80_ROOT_HELPER || "/usr/local/bin/vibe80-root";
|
|
21
23
|
const sudoPath = process.env.VIBE80_SUDO_PATH || "sudo";
|
|
@@ -37,7 +39,7 @@ const runRootCommand = (args, options = {}) => {
|
|
|
37
39
|
export const getWorkspacePaths = (workspaceId) => {
|
|
38
40
|
const home = isMonoUser ? os.homedir() : path.join(workspaceHomeBase, workspaceId);
|
|
39
41
|
const root = isMonoUser
|
|
40
|
-
?
|
|
42
|
+
? monoUserWorkspaceDir
|
|
41
43
|
: path.join(workspaceRootBase, workspaceId);
|
|
42
44
|
const sessionsDir = path.join(root, workspaceSessionsDirName);
|
|
43
45
|
return {
|
|
@@ -763,14 +765,12 @@ export const ensureDefaultMonoWorkspace = async () => {
|
|
|
763
765
|
return;
|
|
764
766
|
}
|
|
765
767
|
const workspaceId = "default";
|
|
768
|
+
const enabledProviders = getMonoEnabledProvidersFromEnv();
|
|
766
769
|
await ensureWorkspaceDirs(workspaceId);
|
|
767
770
|
const ids = await getWorkspaceUserIds(workspaceId);
|
|
768
771
|
const existing = await storage.getWorkspace(workspaceId);
|
|
769
772
|
if (!existing) {
|
|
770
|
-
const providers = {
|
|
771
|
-
codex: { enabled: true, auth: null },
|
|
772
|
-
claude: { enabled: true, auth: null },
|
|
773
|
-
};
|
|
773
|
+
const providers = applyMonoEnabledProviders({}, enabledProviders);
|
|
774
774
|
await persistWorkspaceRecord({
|
|
775
775
|
workspaceId,
|
|
776
776
|
providers,
|
|
@@ -779,7 +779,177 @@ export const ensureDefaultMonoWorkspace = async () => {
|
|
|
779
779
|
existing: null,
|
|
780
780
|
});
|
|
781
781
|
await appendAuditLog(workspaceId, "workspace_created");
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const providers = applyMonoEnabledProviders(existing.providers || {}, enabledProviders);
|
|
785
|
+
await persistWorkspaceRecord({
|
|
786
|
+
workspaceId,
|
|
787
|
+
providers,
|
|
788
|
+
ids,
|
|
789
|
+
existing,
|
|
790
|
+
});
|
|
791
|
+
await appendAuditLog(workspaceId, "workspace_providers_activation_updated", {
|
|
792
|
+
codexEnabled: providers.codex?.enabled ?? false,
|
|
793
|
+
claudeEnabled: providers.claude?.enabled ?? false,
|
|
794
|
+
});
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
const readEnvValue = (name) =>
|
|
798
|
+
typeof process.env[name] === "string" ? process.env[name].trim() : "";
|
|
799
|
+
|
|
800
|
+
const parseMonoEnableEnv = (name) => {
|
|
801
|
+
const raw = process.env[name];
|
|
802
|
+
if (typeof raw !== "string") {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
const value = raw.trim().toLowerCase();
|
|
806
|
+
if (["1", "true", "yes", "on"].includes(value)) {
|
|
807
|
+
return true;
|
|
808
|
+
}
|
|
809
|
+
if (["0", "false", "no", "off", ""].includes(value)) {
|
|
810
|
+
return false;
|
|
811
|
+
}
|
|
812
|
+
throw new Error(
|
|
813
|
+
`Invalid ${name} value \"${raw}\". Use one of: true/false, 1/0, yes/no, on/off.`
|
|
814
|
+
);
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
const getMonoEnabledProvidersFromEnv = () => {
|
|
818
|
+
const codexEnabled = parseMonoEnableEnv("VIBE80_MONO_ENABLE_CODEX");
|
|
819
|
+
const claudeEnabled = parseMonoEnableEnv("VIBE80_MONO_ENABLE_CLAUDE");
|
|
820
|
+
if (!codexEnabled && !claudeEnabled) {
|
|
821
|
+
throw new Error(
|
|
822
|
+
"In mono_user mode, enable at least one provider via --codex/--claude or VIBE80_MONO_ENABLE_CODEX/VIBE80_MONO_ENABLE_CLAUDE."
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
return { codexEnabled, claudeEnabled };
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
const applyMonoEnabledProviders = (providers = {}, enabledConfig) => {
|
|
829
|
+
const { codexEnabled, claudeEnabled } = enabledConfig;
|
|
830
|
+
const codexPrev = providers?.codex && typeof providers.codex === "object" ? providers.codex : {};
|
|
831
|
+
const claudePrev = providers?.claude && typeof providers.claude === "object" ? providers.claude : {};
|
|
832
|
+
return {
|
|
833
|
+
...providers,
|
|
834
|
+
codex: {
|
|
835
|
+
enabled: Boolean(codexEnabled),
|
|
836
|
+
auth: codexPrev.auth || null,
|
|
837
|
+
},
|
|
838
|
+
claude: {
|
|
839
|
+
enabled: Boolean(claudeEnabled),
|
|
840
|
+
auth: claudePrev.auth || null,
|
|
841
|
+
},
|
|
842
|
+
};
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
const buildMonoUserProviderOverridesFromEnv = () => {
|
|
846
|
+
const codexApiKey = readEnvValue("CODEX_API_KEY");
|
|
847
|
+
const codexAuthJsonB64Raw = process.env.CODEX_AUTH_JSON_B64;
|
|
848
|
+
const hasCodexAuthJsonB64 = typeof codexAuthJsonB64Raw === "string";
|
|
849
|
+
const codexAuthJsonB64 = hasCodexAuthJsonB64 ? codexAuthJsonB64Raw.trim() : "";
|
|
850
|
+
const claudeApiKey = readEnvValue("CLAUDE_API_KEY");
|
|
851
|
+
const claudeSetupTokenRaw = process.env.CLAUDE_SETUP_TOKEN;
|
|
852
|
+
const hasClaudeSetupToken = typeof claudeSetupTokenRaw === "string";
|
|
853
|
+
const claudeSetupToken = hasClaudeSetupToken ? claudeSetupTokenRaw.trim() : "";
|
|
854
|
+
|
|
855
|
+
const overrides = {};
|
|
856
|
+
|
|
857
|
+
if (codexApiKey && hasCodexAuthJsonB64) {
|
|
858
|
+
console.warn(
|
|
859
|
+
"[warn] Both CODEX_API_KEY and CODEX_AUTH_JSON_B64 are set; using CODEX_AUTH_JSON_B64."
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
if (hasCodexAuthJsonB64) {
|
|
863
|
+
if (!codexAuthJsonB64) {
|
|
864
|
+
console.warn(
|
|
865
|
+
"[warn] Invalid CODEX_AUTH_JSON_B64 detected; ignoring codex preprovisioning."
|
|
866
|
+
);
|
|
867
|
+
} else {
|
|
868
|
+
try {
|
|
869
|
+
const decoded = decodeBase64(codexAuthJsonB64);
|
|
870
|
+
validateCodexAuthJson(decoded);
|
|
871
|
+
overrides.codex = {
|
|
872
|
+
auth: { type: "auth_json_b64", value: codexAuthJsonB64 },
|
|
873
|
+
};
|
|
874
|
+
} catch {
|
|
875
|
+
console.warn(
|
|
876
|
+
"[warn] Invalid CODEX_AUTH_JSON_B64 detected; ignoring codex preprovisioning."
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
} else if (codexApiKey) {
|
|
881
|
+
overrides.codex = {
|
|
882
|
+
auth: { type: "api_key", value: codexApiKey },
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (claudeApiKey && hasClaudeSetupToken) {
|
|
887
|
+
console.warn(
|
|
888
|
+
"[warn] Both CLAUDE_API_KEY and CLAUDE_SETUP_TOKEN are set; using CLAUDE_SETUP_TOKEN."
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
if (hasClaudeSetupToken) {
|
|
892
|
+
if (!claudeSetupToken) {
|
|
893
|
+
console.warn(
|
|
894
|
+
"[warn] Invalid CLAUDE_SETUP_TOKEN detected; ignoring claude preprovisioning."
|
|
895
|
+
);
|
|
896
|
+
} else {
|
|
897
|
+
overrides.claude = {
|
|
898
|
+
auth: { type: "setup_token", value: claudeSetupToken },
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
} else if (claudeApiKey) {
|
|
902
|
+
overrides.claude = {
|
|
903
|
+
auth: { type: "api_key", value: claudeApiKey },
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
return overrides;
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
export const applyMonoUserProviderOverridesFromEnv = async () => {
|
|
911
|
+
if (!isMonoUser) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
const overrides = buildMonoUserProviderOverridesFromEnv();
|
|
915
|
+
if (Object.keys(overrides).length === 0) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
const workspaceId = "default";
|
|
919
|
+
const existing = await storage.getWorkspace(workspaceId);
|
|
920
|
+
if (!existing) {
|
|
921
|
+
return;
|
|
782
922
|
}
|
|
923
|
+
const activationConfig = getMonoEnabledProvidersFromEnv();
|
|
924
|
+
const mergedProviders = mergeProvidersForUpdate(existing.providers || {}, {
|
|
925
|
+
...(overrides.codex
|
|
926
|
+
? {
|
|
927
|
+
codex: {
|
|
928
|
+
enabled: activationConfig.codexEnabled,
|
|
929
|
+
auth: overrides.codex.auth,
|
|
930
|
+
},
|
|
931
|
+
}
|
|
932
|
+
: {}),
|
|
933
|
+
...(overrides.claude
|
|
934
|
+
? {
|
|
935
|
+
claude: {
|
|
936
|
+
enabled: activationConfig.claudeEnabled,
|
|
937
|
+
auth: overrides.claude.auth,
|
|
938
|
+
},
|
|
939
|
+
}
|
|
940
|
+
: {}),
|
|
941
|
+
});
|
|
942
|
+
const ids = await getWorkspaceUserIds(workspaceId);
|
|
943
|
+
await writeWorkspaceProviderAuth(workspaceId, mergedProviders);
|
|
944
|
+
await persistWorkspaceRecord({
|
|
945
|
+
workspaceId,
|
|
946
|
+
providers: mergedProviders,
|
|
947
|
+
ids,
|
|
948
|
+
existing,
|
|
949
|
+
});
|
|
950
|
+
await appendAuditLog(workspaceId, "workspace_providers_preprovisioned_from_env", {
|
|
951
|
+
providers: Object.keys(overrides),
|
|
952
|
+
});
|
|
783
953
|
};
|
|
784
954
|
|
|
785
955
|
export const createWorkspace = async (providers) => {
|
|
@@ -790,13 +960,18 @@ export const createWorkspace = async (providers) => {
|
|
|
790
960
|
if (isMonoUser) {
|
|
791
961
|
const workspaceId = "default";
|
|
792
962
|
await ensureWorkspaceDirs(workspaceId);
|
|
963
|
+
const enabledProviders = getMonoEnabledProvidersFromEnv();
|
|
793
964
|
const secret = "default";
|
|
794
965
|
const ids = await getWorkspaceUserIds(workspaceId);
|
|
795
966
|
const existing = await storage.getWorkspace(workspaceId);
|
|
796
|
-
|
|
967
|
+
const providersWithActivation = applyMonoEnabledProviders(
|
|
968
|
+
providers || existing?.providers || {},
|
|
969
|
+
enabledProviders
|
|
970
|
+
);
|
|
971
|
+
await writeWorkspaceProviderAuth(workspaceId, providersWithActivation);
|
|
797
972
|
await persistWorkspaceRecord({
|
|
798
973
|
workspaceId,
|
|
799
|
-
providers,
|
|
974
|
+
providers: providersWithActivation,
|
|
800
975
|
ids,
|
|
801
976
|
workspaceSecretHash: hashWorkspaceSecret(secret),
|
|
802
977
|
existing,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
2
3
|
import path from "path";
|
|
3
4
|
import sqlite3 from "sqlite3";
|
|
4
5
|
|
|
@@ -70,7 +71,13 @@ const all = (db, sql, params = []) =>
|
|
|
70
71
|
});
|
|
71
72
|
|
|
72
73
|
export const createSqliteStorage = () => {
|
|
73
|
-
const
|
|
74
|
+
const homeDir = process.env.HOME || os.homedir();
|
|
75
|
+
const isMonoUser = process.env.DEPLOYMENT_MODE === "mono_user";
|
|
76
|
+
const defaultDataDirectory = isMonoUser
|
|
77
|
+
? path.join(homeDir, ".vibe80")
|
|
78
|
+
: "/var/lib/vibe80";
|
|
79
|
+
const dataDirectory = process.env.VIBE80_DATA_DIRECTORY || defaultDataDirectory;
|
|
80
|
+
const dbPath = process.env.SQLITE_PATH || path.join(dataDirectory, "base.sqlite");
|
|
74
81
|
const resolvedPath = path.resolve(dbPath);
|
|
75
82
|
const dir = path.dirname(resolvedPath);
|
|
76
83
|
fs.mkdirSync(dir, { recursive: true, mode: 0o750 });
|