@vibe80/vibe80 0.1.3 → 0.1.7

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 CHANGED
@@ -14,9 +14,8 @@ const monoAuthUrlFile = path.join(
14
14
  );
15
15
  const defaultEnv = {
16
16
  DEPLOYMENT_MODE: "mono_user",
17
- JWT_KEY_PATH: path.join(homeDir, ".vibe80", "jwt.key"),
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";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibe80/vibe80",
3
- "version": "0.1.3",
3
+ "version": "0.1.7",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "server",
@@ -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
@@ -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 jwtKeyPath = process.env.JWT_KEY_PATH || "/var/lib/vibe80/jwt.key";
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 =
@@ -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
- ? path.join(os.homedir(), "vibe80_workspace")
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
- resolved !== homeDir &&
162
- !resolved.startsWith(homeDir + path.sep)
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
- ? path.join(home, workspaceRootName)
42
+ ? monoUserWorkspaceDir
41
43
  : path.join(workspaceRootBase, workspaceId);
42
44
  const sessionsDir = path.join(root, workspaceSessionsDirName);
43
45
  return {
@@ -782,6 +784,105 @@ export const ensureDefaultMonoWorkspace = async () => {
782
784
  }
783
785
  };
784
786
 
787
+ const readEnvValue = (name) =>
788
+ typeof process.env[name] === "string" ? process.env[name].trim() : "";
789
+
790
+ const buildMonoUserProviderOverridesFromEnv = () => {
791
+ const codexApiKey = readEnvValue("CODEX_API_KEY");
792
+ const codexAuthJsonB64Raw = process.env.CODEX_AUTH_JSON_B64;
793
+ const hasCodexAuthJsonB64 = typeof codexAuthJsonB64Raw === "string";
794
+ const codexAuthJsonB64 = hasCodexAuthJsonB64 ? codexAuthJsonB64Raw.trim() : "";
795
+ const claudeApiKey = readEnvValue("CLAUDE_API_KEY");
796
+ const claudeSetupTokenRaw = process.env.CLAUDE_SETUP_TOKEN;
797
+ const hasClaudeSetupToken = typeof claudeSetupTokenRaw === "string";
798
+ const claudeSetupToken = hasClaudeSetupToken ? claudeSetupTokenRaw.trim() : "";
799
+
800
+ const overrides = {};
801
+
802
+ if (codexApiKey && hasCodexAuthJsonB64) {
803
+ console.warn(
804
+ "[warn] Both CODEX_API_KEY and CODEX_AUTH_JSON_B64 are set; using CODEX_AUTH_JSON_B64."
805
+ );
806
+ }
807
+ if (hasCodexAuthJsonB64) {
808
+ if (!codexAuthJsonB64) {
809
+ console.warn(
810
+ "[warn] Invalid CODEX_AUTH_JSON_B64 detected; ignoring codex preprovisioning."
811
+ );
812
+ } else {
813
+ try {
814
+ const decoded = decodeBase64(codexAuthJsonB64);
815
+ validateCodexAuthJson(decoded);
816
+ overrides.codex = {
817
+ enabled: true,
818
+ auth: { type: "auth_json_b64", value: codexAuthJsonB64 },
819
+ };
820
+ } catch {
821
+ console.warn(
822
+ "[warn] Invalid CODEX_AUTH_JSON_B64 detected; ignoring codex preprovisioning."
823
+ );
824
+ }
825
+ }
826
+ } else if (codexApiKey) {
827
+ overrides.codex = {
828
+ enabled: true,
829
+ auth: { type: "api_key", value: codexApiKey },
830
+ };
831
+ }
832
+
833
+ if (claudeApiKey && hasClaudeSetupToken) {
834
+ console.warn(
835
+ "[warn] Both CLAUDE_API_KEY and CLAUDE_SETUP_TOKEN are set; using CLAUDE_SETUP_TOKEN."
836
+ );
837
+ }
838
+ if (hasClaudeSetupToken) {
839
+ if (!claudeSetupToken) {
840
+ console.warn(
841
+ "[warn] Invalid CLAUDE_SETUP_TOKEN detected; ignoring claude preprovisioning."
842
+ );
843
+ } else {
844
+ overrides.claude = {
845
+ enabled: true,
846
+ auth: { type: "setup_token", value: claudeSetupToken },
847
+ };
848
+ }
849
+ } else if (claudeApiKey) {
850
+ overrides.claude = {
851
+ enabled: true,
852
+ auth: { type: "api_key", value: claudeApiKey },
853
+ };
854
+ }
855
+
856
+ return overrides;
857
+ };
858
+
859
+ export const applyMonoUserProviderOverridesFromEnv = async () => {
860
+ if (!isMonoUser) {
861
+ return;
862
+ }
863
+ const overrides = buildMonoUserProviderOverridesFromEnv();
864
+ if (Object.keys(overrides).length === 0) {
865
+ return;
866
+ }
867
+ const workspaceId = "default";
868
+ const existing = await storage.getWorkspace(workspaceId);
869
+ if (!existing) {
870
+ return;
871
+ }
872
+ const mergedProviders = mergeProvidersForUpdate(existing.providers || {}, overrides);
873
+ const ids = await getWorkspaceUserIds(workspaceId);
874
+ await writeWorkspaceProviderAuth(workspaceId, mergedProviders);
875
+ await persistWorkspaceRecord({
876
+ workspaceId,
877
+ providers: mergedProviders,
878
+ ids,
879
+ existing,
880
+ });
881
+ await appendAuditLog(workspaceId, "workspace_providers_preprovisioned_from_env", {
882
+ providers: Object.keys(overrides),
883
+ });
884
+ };
885
+
785
886
  export const createWorkspace = async (providers) => {
786
887
  const validationError = validateProvidersConfig(providers);
787
888
  if (validationError) {
@@ -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 dbPath = process.env.SQLITE_PATH || "/var/lib/vibe80/base.sqlite";
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 });