@geminixiang/mama 0.2.0-beta.3 → 0.2.0-beta.5

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.
Files changed (139) hide show
  1. package/README.md +101 -422
  2. package/dist/adapter.d.ts +9 -0
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +1 -0
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +62 -73
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/discord/context.d.ts.map +1 -1
  10. package/dist/adapters/discord/context.js +9 -2
  11. package/dist/adapters/discord/context.js.map +1 -1
  12. package/dist/adapters/shared.d.ts +48 -0
  13. package/dist/adapters/shared.d.ts.map +1 -1
  14. package/dist/adapters/shared.js +111 -0
  15. package/dist/adapters/shared.js.map +1 -1
  16. package/dist/adapters/slack/bot.d.ts +3 -19
  17. package/dist/adapters/slack/bot.d.ts.map +1 -1
  18. package/dist/adapters/slack/bot.js +58 -188
  19. package/dist/adapters/slack/bot.js.map +1 -1
  20. package/dist/adapters/slack/context.d.ts.map +1 -1
  21. package/dist/adapters/slack/context.js +13 -3
  22. package/dist/adapters/slack/context.js.map +1 -1
  23. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  24. package/dist/adapters/telegram/bot.js +78 -100
  25. package/dist/adapters/telegram/bot.js.map +1 -1
  26. package/dist/adapters/telegram/context.d.ts.map +1 -1
  27. package/dist/adapters/telegram/context.js +9 -2
  28. package/dist/adapters/telegram/context.js.map +1 -1
  29. package/dist/agent.d.ts.map +1 -1
  30. package/dist/agent.js +15 -5
  31. package/dist/agent.js.map +1 -1
  32. package/dist/bindings.d.ts +2 -1
  33. package/dist/bindings.d.ts.map +1 -1
  34. package/dist/bindings.js +3 -2
  35. package/dist/bindings.js.map +1 -1
  36. package/dist/commands/index.d.ts +5 -0
  37. package/dist/commands/index.d.ts.map +1 -0
  38. package/dist/commands/index.js +8 -0
  39. package/dist/commands/index.js.map +1 -0
  40. package/dist/commands/login.d.ts +5 -0
  41. package/dist/commands/login.d.ts.map +1 -0
  42. package/dist/commands/login.js +37 -0
  43. package/dist/commands/login.js.map +1 -0
  44. package/dist/commands/registry.d.ts +7 -0
  45. package/dist/commands/registry.d.ts.map +1 -0
  46. package/dist/commands/registry.js +14 -0
  47. package/dist/commands/registry.js.map +1 -0
  48. package/dist/commands/session-view.d.ts +5 -0
  49. package/dist/commands/session-view.d.ts.map +1 -0
  50. package/dist/commands/session-view.js +38 -0
  51. package/dist/commands/session-view.js.map +1 -0
  52. package/dist/commands/types.d.ts +41 -0
  53. package/dist/commands/types.d.ts.map +1 -0
  54. package/dist/commands/types.js +2 -0
  55. package/dist/commands/types.js.map +1 -0
  56. package/dist/commands/utils.d.ts +5 -0
  57. package/dist/commands/utils.d.ts.map +1 -0
  58. package/dist/commands/utils.js +9 -0
  59. package/dist/commands/utils.js.map +1 -0
  60. package/dist/config.d.ts +4 -4
  61. package/dist/config.d.ts.map +1 -1
  62. package/dist/config.js +37 -42
  63. package/dist/config.js.map +1 -1
  64. package/dist/context.d.ts.map +1 -1
  65. package/dist/context.js +74 -68
  66. package/dist/context.js.map +1 -1
  67. package/dist/execution-resolver.d.ts +6 -3
  68. package/dist/execution-resolver.d.ts.map +1 -1
  69. package/dist/execution-resolver.js +47 -14
  70. package/dist/execution-resolver.js.map +1 -1
  71. package/dist/fs-atomic.d.ts +10 -0
  72. package/dist/fs-atomic.d.ts.map +1 -0
  73. package/dist/fs-atomic.js +45 -0
  74. package/dist/fs-atomic.js.map +1 -0
  75. package/dist/index.d.ts +7 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +4 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/instrument.d.ts.map +1 -1
  80. package/dist/instrument.js +2 -3
  81. package/dist/instrument.js.map +1 -1
  82. package/dist/login/index.d.ts.map +1 -1
  83. package/dist/login/index.js +19 -8
  84. package/dist/login/index.js.map +1 -1
  85. package/dist/login/portal.d.ts.map +1 -1
  86. package/dist/login/portal.js +7 -7
  87. package/dist/login/portal.js.map +1 -1
  88. package/dist/login/session.d.ts +3 -2
  89. package/dist/login/session.d.ts.map +1 -1
  90. package/dist/login/session.js.map +1 -1
  91. package/dist/main.d.ts.map +1 -1
  92. package/dist/main.js +63 -389
  93. package/dist/main.js.map +1 -1
  94. package/dist/provisioner.d.ts +11 -9
  95. package/dist/provisioner.d.ts.map +1 -1
  96. package/dist/provisioner.js +125 -87
  97. package/dist/provisioner.js.map +1 -1
  98. package/dist/runtime/index.d.ts +2 -0
  99. package/dist/runtime/index.d.ts.map +1 -0
  100. package/dist/runtime/index.js +2 -0
  101. package/dist/runtime/index.js.map +1 -0
  102. package/dist/runtime/session-runtime.d.ts +26 -0
  103. package/dist/runtime/session-runtime.d.ts.map +1 -0
  104. package/dist/runtime/session-runtime.js +285 -0
  105. package/dist/runtime/session-runtime.js.map +1 -0
  106. package/dist/sandbox/cloudflare.d.ts +14 -0
  107. package/dist/sandbox/cloudflare.d.ts.map +1 -0
  108. package/dist/sandbox/cloudflare.js +131 -0
  109. package/dist/sandbox/cloudflare.js.map +1 -0
  110. package/dist/sandbox/index.d.ts +6 -4
  111. package/dist/sandbox/index.d.ts.map +1 -1
  112. package/dist/sandbox/index.js +6 -3
  113. package/dist/sandbox/index.js.map +1 -1
  114. package/dist/sandbox/types.d.ts +5 -1
  115. package/dist/sandbox/types.d.ts.map +1 -1
  116. package/dist/sandbox/types.js.map +1 -1
  117. package/dist/session-store.d.ts +5 -1
  118. package/dist/session-store.d.ts.map +1 -1
  119. package/dist/session-store.js +14 -9
  120. package/dist/session-store.js.map +1 -1
  121. package/dist/session-view/portal.d.ts +2 -0
  122. package/dist/session-view/portal.d.ts.map +1 -1
  123. package/dist/session-view/portal.js +45 -7
  124. package/dist/session-view/portal.js.map +1 -1
  125. package/dist/session-view/service.d.ts.map +1 -1
  126. package/dist/session-view/service.js +94 -48
  127. package/dist/session-view/service.js.map +1 -1
  128. package/dist/session-view/store.d.ts +3 -2
  129. package/dist/session-view/store.d.ts.map +1 -1
  130. package/dist/session-view/store.js.map +1 -1
  131. package/dist/vault-routing.d.ts +3 -5
  132. package/dist/vault-routing.d.ts.map +1 -1
  133. package/dist/vault-routing.js +8 -20
  134. package/dist/vault-routing.js.map +1 -1
  135. package/dist/vault.d.ts +7 -5
  136. package/dist/vault.d.ts.map +1 -1
  137. package/dist/vault.js +111 -104
  138. package/dist/vault.js.map +1 -1
  139. package/package.json +7 -9
package/dist/vault.js CHANGED
@@ -1,8 +1,13 @@
1
- import { chmodSync, closeSync, constants as fsConstants, existsSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeSync, } from "fs";
2
- import { randomBytes } from "crypto";
3
- import { basename, dirname, isAbsolute, join, normalize, sep } from "path";
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync } from "fs";
2
+ import { dirname, isAbsolute, join, normalize, sep } from "path";
3
+ import { atomicWritePrivateFile } from "./fs-atomic.js";
4
4
  const PRIVATE_DIR_MODE = 0o700;
5
- const PRIVATE_FILE_MODE = 0o600;
5
+ function sanitizeCloudflareSandboxId(value) {
6
+ return (value
7
+ .toLowerCase()
8
+ .replace(/[^a-z0-9-]+/g, "-")
9
+ .replace(/^-+|-+$/g, "") || "unknown");
10
+ }
6
11
  // ── parseEnvFile ───────────────────────────────────────────────────────────────
7
12
  /**
8
13
  * Parse a KEY=VALUE env file. Supports:
@@ -74,35 +79,52 @@ export class FileVaultManager {
74
79
  for (const [key, entry] of Object.entries(this.config.vaults)) {
75
80
  if (entry.sandbox?.type === "host") {
76
81
  console.error(`vault: "${key}" uses sandbox.type=host, which is blocked for credential isolation. ` +
77
- "Use sandbox.type=image or sandbox.type=firecracker.");
82
+ "Use sandbox.type=image, sandbox.type=firecracker, or sandbox.type=cloudflare.");
78
83
  }
79
84
  if (entry.sandbox?.type === "container" || entry.sandbox?.type === "docker") {
80
85
  console.error(`vault: "${key}" uses sandbox.type=${entry.sandbox.type}, which is blocked for credential isolation. ` +
81
- "Use sandbox.type=image for per-user containers or sandbox.type=firecracker.");
86
+ "Use sandbox.type=image for per-user containers, sandbox.type=firecracker, or sandbox.type=cloudflare.");
82
87
  }
83
88
  }
84
89
  }
85
90
  isEnabled() {
86
- return this.config !== null;
91
+ return this.config !== null || existsSync(this.vaultsDir);
87
92
  }
88
93
  hasEntry(key) {
89
- return !!this.config?.vaults[key];
94
+ return !!this.config?.vaults[key] || existsSync(join(this.vaultsDir, key));
90
95
  }
91
96
  resolve(userId) {
92
97
  const entry = this.config?.vaults[userId];
93
- if (!entry)
98
+ const dir = join(this.vaultsDir, userId);
99
+ if (!entry && !existsSync(dir))
94
100
  return undefined;
95
101
  return this.buildResolved(userId, entry);
96
102
  }
97
103
  getSandboxConfig(userId, baseConfig) {
98
104
  const vault = this.resolve(userId);
99
- if (!vault?.sandboxOverride)
105
+ if (!vault?.sandboxOverride) {
106
+ if (baseConfig.type === "cloudflare") {
107
+ return {
108
+ type: "cloudflare",
109
+ sandboxId: `${baseConfig.sandboxId}-${sanitizeCloudflareSandboxId(userId)}`,
110
+ };
111
+ }
100
112
  return baseConfig;
113
+ }
101
114
  const override = vault.sandboxOverride;
102
115
  if (override.type === "image") {
103
116
  if (baseConfig.type !== "image") {
117
+ if (!override.container) {
118
+ if (baseConfig.type === "cloudflare") {
119
+ return {
120
+ type: "cloudflare",
121
+ sandboxId: `${baseConfig.sandboxId}-${sanitizeCloudflareSandboxId(userId)}`,
122
+ };
123
+ }
124
+ return baseConfig;
125
+ }
104
126
  throw new Error(`vault "${userId}" sets sandbox.type=image, but base sandbox is "${baseConfig.type}". ` +
105
- "Use --sandbox=image:<image> to enable per-user managed containers.");
127
+ "Use --sandbox=image:<image> to enable managed image containers for this vault.");
106
128
  }
107
129
  const container = override.container || `mama-sandbox-${userId}`;
108
130
  return { type: "container", container };
@@ -122,46 +144,58 @@ export class FileVaultManager {
122
144
  sshPort: override.sshPort,
123
145
  };
124
146
  }
147
+ if (override.type === "cloudflare") {
148
+ if (!override.sandboxId)
149
+ return baseConfig;
150
+ if (baseConfig.type !== "cloudflare") {
151
+ throw new Error(`vault "${userId}" sets sandbox.type=cloudflare, but base sandbox is "${baseConfig.type}". ` +
152
+ "Use --sandbox=cloudflare:<sandbox-id> to enable Cloudflare remote execution.");
153
+ }
154
+ return {
155
+ type: "cloudflare",
156
+ sandboxId: override.sandboxId,
157
+ };
158
+ }
125
159
  if (override.type === "host") {
126
160
  throw new Error(`vault "${userId}" uses sandbox.type=host, which is blocked for credential isolation. ` +
127
- "Use sandbox.type=image or sandbox.type=firecracker.");
161
+ "Use sandbox.type=image, sandbox.type=firecracker, or sandbox.type=cloudflare.");
128
162
  }
129
163
  if (override.type === "container" || override.type === "docker") {
130
164
  throw new Error(`vault "${userId}" uses sandbox.type=${override.type}, which is blocked for credential isolation. ` +
131
- "Use sandbox.type=image for per-user containers or sandbox.type=firecracker.");
165
+ "Use sandbox.type=image for per-user containers, sandbox.type=firecracker, or sandbox.type=cloudflare.");
132
166
  }
133
167
  // No type override — return base config unchanged
134
168
  return baseConfig;
135
169
  }
136
170
  list() {
137
- if (!this.config)
138
- return [];
139
- const results = [];
140
- for (const [key, entry] of Object.entries(this.config.vaults)) {
141
- results.push(this.buildResolved(key, entry));
171
+ const keys = new Set();
172
+ for (const key of Object.keys(this.config?.vaults ?? {})) {
173
+ keys.add(key);
174
+ }
175
+ if (existsSync(this.vaultsDir)) {
176
+ for (const entry of readdirSync(this.vaultsDir, { withFileTypes: true })) {
177
+ if (entry.isDirectory())
178
+ keys.add(entry.name);
179
+ }
142
180
  }
143
- return results;
181
+ return Array.from(keys, (key) => this.buildResolved(key, this.config?.vaults[key]));
144
182
  }
145
183
  addEntry(key, entry) {
146
- if (!this.config) {
147
- this.config = { vaults: {} };
148
- }
184
+ const cfg = (this.config ??= { vaults: {} });
149
185
  // Idempotent: skip if already exists
150
- if (this.config.vaults[key])
186
+ if (cfg.vaults[key])
151
187
  return;
152
- this.config.vaults[key] = entry;
188
+ cfg.vaults[key] = entry;
153
189
  this.persistConfig();
154
190
  }
155
191
  ensureImageSandboxEntry(key, entry) {
156
192
  if (entry.sandbox?.type !== "image") {
157
193
  throw new Error(`vault: ensureImageSandboxEntry requires sandbox.type=image for "${key}"`);
158
194
  }
159
- if (!this.config) {
160
- this.config = { vaults: {} };
161
- }
162
- const existing = this.config.vaults[key];
195
+ const cfg = (this.config ??= { vaults: {} });
196
+ const existing = cfg.vaults[key];
163
197
  if (!existing) {
164
- this.config.vaults[key] = entry;
198
+ cfg.vaults[key] = entry;
165
199
  this.persistConfig();
166
200
  return;
167
201
  }
@@ -176,19 +210,9 @@ export class FileVaultManager {
176
210
  nextEntry = { ...nextEntry, sandbox: entry.sandbox };
177
211
  changed = true;
178
212
  }
179
- else if (existingSandbox.type === "image" &&
180
- !existingSandbox.container &&
181
- entry.sandbox.container) {
182
- nextEntry = {
183
- ...nextEntry,
184
- sandbox: { ...existingSandbox, container: entry.sandbox.container },
185
- };
186
- changed = true;
187
- }
188
- if (!changed) {
213
+ if (!changed)
189
214
  return;
190
- }
191
- this.config.vaults[key] = nextEntry;
215
+ cfg.vaults[key] = nextEntry;
192
216
  this.persistConfig();
193
217
  }
194
218
  upsertEnv(key, env) {
@@ -208,8 +232,7 @@ export class FileVaultManager {
208
232
  }
209
233
  upsertFile(key, relativePath, content, targetPath) {
210
234
  const normalizedPath = normalizeVaultRelativePath(relativePath);
211
- const normalizedTarget = normalizeVaultTargetPath(targetPath);
212
- if (!normalizedPath || (targetPath !== undefined && !normalizedTarget)) {
235
+ if (!normalizedPath || (targetPath !== undefined && !normalizeVaultTargetPath(targetPath))) {
213
236
  throw new Error(`vault: invalid relative secret file path for "${key}": ${relativePath}`);
214
237
  }
215
238
  const dir = join(this.vaultsDir, key);
@@ -220,7 +243,6 @@ export class FileVaultManager {
220
243
  if (parentDir !== dir)
221
244
  ensurePrivateDir(parentDir);
222
245
  atomicWritePrivateFile(filePath, content);
223
- this.ensureMountEntry(key, normalizedPath, normalizedTarget);
224
246
  }
225
247
  // ── private ────────────────────────────────────────────────────────────────
226
248
  persistConfig() {
@@ -256,31 +278,20 @@ export class FileVaultManager {
256
278
  return null;
257
279
  }
258
280
  }
259
- ensureMountEntry(key, relativePath, targetPath) {
260
- if (!this.config?.vaults[key]) {
261
- throw new Error(`vault: cannot add mount "${relativePath}" for missing entry "${key}"`);
262
- }
263
- const existing = this.config.vaults[key];
264
- const mounts = existing.mounts ?? [];
265
- if (mounts.some((mount) => typeof mount === "string"
266
- ? mount === relativePath && !targetPath
267
- : mount.source === relativePath && mount.target === targetPath)) {
268
- return;
269
- }
270
- this.config.vaults[key] = {
271
- ...existing,
272
- mounts: [...mounts, targetPath ? { source: relativePath, target: targetPath } : relativePath],
273
- };
274
- this.persistConfig();
275
- }
276
281
  buildResolved(key, entry) {
277
282
  const dir = join(this.vaultsDir, key);
278
- const mounts = (entry.mounts ?? [])
283
+ const inferredMounts = this.inferMountsFromDir(dir);
284
+ const configuredMounts = (entry?.mounts ?? [])
279
285
  .map((mount) => this.resolveMountEntry(dir, mount))
280
286
  .filter((mount) => mount !== undefined);
287
+ const mountsByTarget = new Map();
288
+ for (const mount of inferredMounts)
289
+ mountsByTarget.set(mount.target, mount);
290
+ for (const mount of configuredMounts)
291
+ mountsByTarget.set(mount.target, mount);
281
292
  let env = {};
282
293
  const envPath = join(dir, "env");
283
- if (entry.envFile !== false && existsSync(envPath)) {
294
+ if ((entry?.envFile ?? true) && existsSync(envPath)) {
284
295
  try {
285
296
  env = parseEnvFile(readFileSync(envPath, "utf-8"));
286
297
  }
@@ -290,13 +301,29 @@ export class FileVaultManager {
290
301
  }
291
302
  return {
292
303
  userId: key,
293
- displayName: entry.displayName,
304
+ displayName: entry?.displayName ?? key,
294
305
  dir,
295
- mounts,
306
+ mounts: [...mountsByTarget.values()],
296
307
  env,
297
- sandboxOverride: entry.sandbox,
308
+ sandboxOverride: entry?.sandbox,
298
309
  };
299
310
  }
311
+ inferMountsFromDir(dir) {
312
+ if (!existsSync(dir)) {
313
+ return [];
314
+ }
315
+ const mounts = [];
316
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
317
+ if (entry.name === "env")
318
+ continue;
319
+ const source = join(dir, entry.name);
320
+ const target = inferredVaultTargetPath(entry.name);
321
+ if (!target)
322
+ continue;
323
+ mounts.push({ source, target });
324
+ }
325
+ return mounts;
326
+ }
300
327
  resolveMountEntry(dir, mount) {
301
328
  if (typeof mount === "string") {
302
329
  const normalizedSource = normalizeVaultRelativePath(mount);
@@ -323,44 +350,6 @@ function ensurePrivateDir(path) {
323
350
  mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });
324
351
  chmodSync(path, PRIVATE_DIR_MODE);
325
352
  }
326
- /**
327
- * Write `content` to `targetPath` with mode 0600, even when `targetPath`
328
- * already exists. Uses O_CREAT|O_EXCL on a temp sibling (so the kernel
329
- * guarantees permissions at creation, not after a racy chmod) and then
330
- * rename(2) into place for atomicity. Readers never see a torn write.
331
- */
332
- function atomicWritePrivateFile(targetPath, content) {
333
- const dir = dirname(targetPath);
334
- const tmpPath = join(dir, `.${basename(targetPath)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
335
- const fd = openSync(tmpPath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, PRIVATE_FILE_MODE);
336
- try {
337
- writeSync(fd, content);
338
- }
339
- catch (err) {
340
- try {
341
- unlinkSync(tmpPath);
342
- }
343
- catch {
344
- // ignore — original error is more informative
345
- }
346
- throw err;
347
- }
348
- finally {
349
- closeSync(fd);
350
- }
351
- try {
352
- renameSync(tmpPath, targetPath);
353
- }
354
- catch (err) {
355
- try {
356
- unlinkSync(tmpPath);
357
- }
358
- catch {
359
- // ignore
360
- }
361
- throw err;
362
- }
363
- }
364
353
  function normalizeVaultRelativePath(relativePath) {
365
354
  const trimmed = relativePath.trim();
366
355
  if (!trimmed || isAbsolute(trimmed))
@@ -386,4 +375,22 @@ export function defaultVaultTargetPath(relativePath) {
386
375
  const normalized = normalizeVaultRelativePath(relativePath) ?? relativePath.replace(/^\/+/, "");
387
376
  return `/root/${normalized}`;
388
377
  }
378
+ function inferredVaultTargetPath(relativePath) {
379
+ const normalized = normalizeVaultRelativePath(relativePath);
380
+ if (!normalized)
381
+ return undefined;
382
+ if (normalized === "gws.json") {
383
+ return "/root/.config/gws/credentials.json";
384
+ }
385
+ if (normalized === ".ssh" || normalized.startsWith(".ssh/")) {
386
+ return "/root/.ssh";
387
+ }
388
+ if (normalized === ".kube" || normalized.startsWith(".kube/")) {
389
+ return "/root/.kube";
390
+ }
391
+ if (normalized === ".config/gh" || normalized.startsWith(".config/gh/")) {
392
+ return "/root/.config/gh";
393
+ }
394
+ return defaultVaultTargetPath(normalized);
395
+ }
389
396
  //# sourceMappingURL=vault.js.map
package/dist/vault.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n chmodSync,\n closeSync,\n constants as fsConstants,\n existsSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n unlinkSync,\n writeSync,\n} from \"fs\";\nimport { randomBytes } from \"crypto\";\nimport { basename, dirname, isAbsolute, join, normalize, sep } from \"path\";\nimport type { SandboxConfig } from \"./sandbox.js\";\n\nconst PRIVATE_DIR_MODE = 0o700;\nconst PRIVATE_FILE_MODE = 0o600;\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\n/** Shape of workspace/vaults/vault.json */\nexport interface VaultConfig {\n vaults: Record<string, VaultEntry>;\n}\n\n/** Per-user vault mount entry in vault.json */\nexport interface VaultMountEntry {\n source: string;\n target?: string;\n}\n\n/** Per-user vault entry in vault.json */\nexport interface VaultEntry {\n displayName: string;\n platform?: \"slack\" | \"discord\" | \"telegram\";\n /** Subdirs/files in vault dir to mount into sandbox (e.g. [\".gcloud\", \".ssh\", \".kube\"]) */\n mounts?: Array<string | VaultMountEntry>;\n /** Whether to load env file as environment variables (default: true if env file exists) */\n envFile?: boolean;\n /** Per-user sandbox config override */\n sandbox?: {\n type?: \"image\" | \"firecracker\" | \"host\" | \"container\" | \"docker\";\n container?: string;\n image?: string;\n vmId?: string;\n sshUser?: string;\n sshPort?: number;\n };\n}\n\nexport interface ResolvedVaultMount {\n source: string;\n target: string;\n}\n\n/** Resolved vault ready for use at runtime */\nexport interface ResolvedVault {\n userId: string;\n displayName: string;\n /** Absolute path to vault directory */\n dir: string;\n /** Absolute mount specs */\n mounts: ResolvedVaultMount[];\n /** Parsed from env file */\n env: Record<string, string>;\n sandboxOverride?: VaultEntry[\"sandbox\"];\n}\n\nexport interface VaultManager {\n /** Return true when vault.json contains this exact key. */\n hasEntry(key: string): boolean;\n /** Resolve vault for a user; returns undefined when no entry exists. */\n resolve(userId: string): ResolvedVault | undefined;\n /** Get sandbox config with credential injection for a user */\n getSandboxConfig(userId: string, baseConfig: SandboxConfig): SandboxConfig;\n /** List all configured vaults */\n list(): ResolvedVault[];\n /** Re-read vault.json without restart */\n reload(): void;\n /** Check if vault system is enabled (vault.json exists) */\n isEnabled(): boolean;\n /**\n * Add a vault entry and persist to disk.\n * No-op if the key already exists (idempotent).\n */\n addEntry(key: string, entry: VaultEntry): void;\n /**\n * Ensure a vault entry has image sandbox metadata.\n * Creates the entry when missing and upgrades existing entries that lack sandbox.type.\n */\n ensureImageSandboxEntry(key: string, entry: VaultEntry): void;\n /** Merge environment variables into vaults/<key>/env and persist them to disk. */\n upsertEnv(key: string, env: Record<string, string>): void;\n /** Write a private file into vaults/<key>/ and ensure it is mounted into the sandbox. */\n upsertFile(key: string, relativePath: string, content: string, targetPath?: string): void;\n}\n\n// ── parseEnvFile ───────────────────────────────────────────────────────────────\n\n/**\n * Parse a KEY=VALUE env file. Supports:\n * - Lines starting with # are comments\n * - Empty lines are skipped\n * - Values can be quoted with single or double quotes (quotes are stripped)\n * - No variable expansion\n * - The value is everything after the first `=` to end of line (no inline comments)\n */\nexport function parseEnvFile(content: string): Record<string, string> {\n const env: Record<string, string> = {};\n const lines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex === -1) continue;\n\n const key = trimmed.slice(0, eqIndex).trim();\n if (!key) continue;\n\n let value = trimmed.slice(eqIndex + 1);\n\n // Strip matching quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n env[key] = value;\n }\n\n return env;\n}\n\n// ── FileVaultManager ───────────────────────────────────────────────────────────\n\nexport class FileVaultManager implements VaultManager {\n private config: VaultConfig | null = null;\n private readonly vaultsDir: string;\n private readonly configPath: string;\n\n constructor(stateDir: string) {\n this.vaultsDir = join(stateDir, \"vaults\");\n this.configPath = join(this.vaultsDir, \"vault.json\");\n this.reload();\n }\n\n reload(): void {\n if (!existsSync(this.configPath)) {\n this.config = null;\n return;\n }\n\n try {\n const raw = readFileSync(this.configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n !parsed.vaults ||\n typeof parsed.vaults !== \"object\"\n ) {\n console.error(`vault: malformed vault.json — expected { vaults: { ... } }`);\n this.config = null;\n return;\n }\n\n this.config = parsed as VaultConfig;\n this.warnUnsupportedSandboxTypes();\n } catch (err) {\n console.error(`vault: failed to read ${this.configPath}:`, err);\n this.config = null;\n }\n }\n\n /** Warn for legacy or insecure vault sandbox overrides that are no longer allowed. */\n private warnUnsupportedSandboxTypes(): void {\n if (!this.config) return;\n for (const [key, entry] of Object.entries(this.config.vaults)) {\n if (entry.sandbox?.type === \"host\") {\n console.error(\n `vault: \"${key}\" uses sandbox.type=host, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image or sandbox.type=firecracker.\",\n );\n }\n if (entry.sandbox?.type === \"container\" || entry.sandbox?.type === \"docker\") {\n console.error(\n `vault: \"${key}\" uses sandbox.type=${entry.sandbox.type}, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image for per-user containers or sandbox.type=firecracker.\",\n );\n }\n }\n }\n\n isEnabled(): boolean {\n return this.config !== null;\n }\n\n hasEntry(key: string): boolean {\n return !!this.config?.vaults[key];\n }\n\n resolve(userId: string): ResolvedVault | undefined {\n const entry = this.config?.vaults[userId];\n if (!entry) return undefined;\n return this.buildResolved(userId, entry);\n }\n\n getSandboxConfig(userId: string, baseConfig: SandboxConfig): SandboxConfig {\n const vault = this.resolve(userId);\n if (!vault?.sandboxOverride) return baseConfig;\n\n const override = vault.sandboxOverride;\n\n if (override.type === \"image\") {\n if (baseConfig.type !== \"image\") {\n throw new Error(\n `vault \"${userId}\" sets sandbox.type=image, but base sandbox is \"${baseConfig.type}\". ` +\n \"Use --sandbox=image:<image> to enable per-user managed containers.\",\n );\n }\n const container = override.container || `mama-sandbox-${userId}`;\n return { type: \"container\", container };\n }\n\n if (override.type === \"firecracker\") {\n if (!override.vmId) return baseConfig;\n if (baseConfig.type !== \"firecracker\") {\n throw new Error(\n `vault \"${userId}\" sets sandbox.type=firecracker, but base sandbox is \"${baseConfig.type}\". ` +\n \"Use --sandbox=firecracker:<vm-id>:<host-path> so /workspace stays mapped to the real workspace.\",\n );\n }\n return {\n type: \"firecracker\",\n vmId: override.vmId,\n hostPath: baseConfig.hostPath,\n sshUser: override.sshUser,\n sshPort: override.sshPort,\n };\n }\n\n if (override.type === \"host\") {\n throw new Error(\n `vault \"${userId}\" uses sandbox.type=host, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image or sandbox.type=firecracker.\",\n );\n }\n\n if (override.type === \"container\" || override.type === \"docker\") {\n throw new Error(\n `vault \"${userId}\" uses sandbox.type=${override.type}, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image for per-user containers or sandbox.type=firecracker.\",\n );\n }\n\n // No type override — return base config unchanged\n return baseConfig;\n }\n\n list(): ResolvedVault[] {\n if (!this.config) return [];\n\n const results: ResolvedVault[] = [];\n for (const [key, entry] of Object.entries(this.config.vaults)) {\n results.push(this.buildResolved(key, entry));\n }\n return results;\n }\n\n addEntry(key: string, entry: VaultEntry): void {\n if (!this.config) {\n this.config = { vaults: {} };\n }\n // Idempotent: skip if already exists\n if (this.config.vaults[key]) return;\n this.config.vaults[key] = entry;\n this.persistConfig();\n }\n\n ensureImageSandboxEntry(key: string, entry: VaultEntry): void {\n if (entry.sandbox?.type !== \"image\") {\n throw new Error(`vault: ensureImageSandboxEntry requires sandbox.type=image for \"${key}\"`);\n }\n\n if (!this.config) {\n this.config = { vaults: {} };\n }\n\n const existing = this.config.vaults[key];\n if (!existing) {\n this.config.vaults[key] = entry;\n this.persistConfig();\n return;\n }\n\n let nextEntry = existing;\n let changed = false;\n\n if (!existing.platform && entry.platform) {\n nextEntry = { ...nextEntry, platform: entry.platform };\n changed = true;\n }\n\n const existingSandbox = existing.sandbox;\n if (!existingSandbox?.type) {\n nextEntry = { ...nextEntry, sandbox: entry.sandbox };\n changed = true;\n } else if (\n existingSandbox.type === \"image\" &&\n !existingSandbox.container &&\n entry.sandbox.container\n ) {\n nextEntry = {\n ...nextEntry,\n sandbox: { ...existingSandbox, container: entry.sandbox.container },\n };\n changed = true;\n }\n\n if (!changed) {\n return;\n }\n\n this.config.vaults[key] = nextEntry;\n this.persistConfig();\n }\n\n upsertEnv(key: string, env: Record<string, string>): void {\n const dir = join(this.vaultsDir, key);\n const envPath = join(dir, \"env\");\n ensurePrivateDir(this.vaultsDir);\n ensurePrivateDir(dir);\n const existing = existsSync(envPath)\n ? parseEnvFile(readFileSync(envPath, \"utf-8\"))\n : ({} as Record<string, string>);\n const merged = { ...existing, ...env };\n const content =\n Object.entries(merged)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([envKey, value]) => `${envKey}=${value}`)\n .join(\"\\n\") + \"\\n\";\n atomicWritePrivateFile(envPath, content);\n }\n\n upsertFile(key: string, relativePath: string, content: string, targetPath?: string): void {\n const normalizedPath = normalizeVaultRelativePath(relativePath);\n const normalizedTarget = normalizeVaultTargetPath(targetPath);\n if (!normalizedPath || (targetPath !== undefined && !normalizedTarget)) {\n throw new Error(`vault: invalid relative secret file path for \"${key}\": ${relativePath}`);\n }\n\n const dir = join(this.vaultsDir, key);\n const filePath = join(dir, normalizedPath);\n\n ensurePrivateDir(this.vaultsDir);\n ensurePrivateDir(dir);\n const parentDir = dirname(filePath);\n if (parentDir !== dir) ensurePrivateDir(parentDir);\n atomicWritePrivateFile(filePath, content);\n this.ensureMountEntry(key, normalizedPath, normalizedTarget);\n }\n\n // ── private ────────────────────────────────────────────────────────────────\n\n private persistConfig(): void {\n ensurePrivateDir(this.vaultsDir);\n\n // Preserve concurrent external edits: pull in any entries that appear on\n // disk but not in our in-memory view, so a background edit (e.g. another\n // admin adding a user) is not silently dropped by the next upsert here.\n // Individual field edits still follow last-writer-wins per key.\n const onDisk = this.readConfigFromDisk();\n if (onDisk && this.config) {\n for (const [key, entry] of Object.entries(onDisk.vaults)) {\n if (!(key in this.config.vaults)) {\n this.config.vaults[key] = entry;\n }\n }\n }\n\n atomicWritePrivateFile(this.configPath, JSON.stringify(this.config, null, 2) + \"\\n\");\n }\n\n private readConfigFromDisk(): VaultConfig | null {\n if (!existsSync(this.configPath)) return null;\n try {\n const parsed = JSON.parse(readFileSync(this.configPath, \"utf-8\"));\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n !parsed.vaults ||\n typeof parsed.vaults !== \"object\"\n ) {\n return null;\n }\n return parsed as VaultConfig;\n } catch {\n return null;\n }\n }\n\n private ensureMountEntry(key: string, relativePath: string, targetPath?: string): void {\n if (!this.config?.vaults[key]) {\n throw new Error(`vault: cannot add mount \"${relativePath}\" for missing entry \"${key}\"`);\n }\n\n const existing = this.config.vaults[key];\n const mounts = existing.mounts ?? [];\n if (\n mounts.some((mount) =>\n typeof mount === \"string\"\n ? mount === relativePath && !targetPath\n : mount.source === relativePath && mount.target === targetPath,\n )\n ) {\n return;\n }\n\n this.config.vaults[key] = {\n ...existing,\n mounts: [...mounts, targetPath ? { source: relativePath, target: targetPath } : relativePath],\n };\n this.persistConfig();\n }\n\n private buildResolved(key: string, entry: VaultEntry): ResolvedVault {\n const dir = join(this.vaultsDir, key);\n\n const mounts = (entry.mounts ?? [])\n .map((mount) => this.resolveMountEntry(dir, mount))\n .filter((mount): mount is ResolvedVaultMount => mount !== undefined);\n\n let env: Record<string, string> = {};\n const envPath = join(dir, \"env\");\n if (entry.envFile !== false && existsSync(envPath)) {\n try {\n env = parseEnvFile(readFileSync(envPath, \"utf-8\"));\n } catch (err) {\n console.error(`vault: failed to parse env file for \"${key}\":`, err);\n }\n }\n\n return {\n userId: key,\n displayName: entry.displayName,\n dir,\n mounts,\n env,\n sandboxOverride: entry.sandbox,\n };\n }\n\n private resolveMountEntry(\n dir: string,\n mount: string | VaultMountEntry,\n ): ResolvedVaultMount | undefined {\n if (typeof mount === \"string\") {\n const normalizedSource = normalizeVaultRelativePath(mount);\n if (!normalizedSource) return undefined;\n return {\n source: join(dir, normalizedSource),\n target: defaultVaultTargetPath(normalizedSource),\n };\n }\n\n if (!mount || typeof mount !== \"object\") return undefined;\n const normalizedSource = normalizeVaultRelativePath(mount.source);\n if (!normalizedSource) return undefined;\n const normalizedTarget = normalizeVaultTargetPath(mount.target);\n return {\n source: join(dir, normalizedSource),\n target: normalizedTarget ?? defaultVaultTargetPath(normalizedSource),\n };\n }\n}\n\nfunction ensurePrivateDir(path: string): void {\n mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });\n chmodSync(path, PRIVATE_DIR_MODE);\n}\n\n/**\n * Write `content` to `targetPath` with mode 0600, even when `targetPath`\n * already exists. Uses O_CREAT|O_EXCL on a temp sibling (so the kernel\n * guarantees permissions at creation, not after a racy chmod) and then\n * rename(2) into place for atomicity. Readers never see a torn write.\n */\nfunction atomicWritePrivateFile(targetPath: string, content: string): void {\n const dir = dirname(targetPath);\n const tmpPath = join(\n dir,\n `.${basename(targetPath)}.${process.pid}.${randomBytes(8).toString(\"hex\")}.tmp`,\n );\n const fd = openSync(\n tmpPath,\n fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,\n PRIVATE_FILE_MODE,\n );\n try {\n writeSync(fd, content);\n } catch (err) {\n try {\n unlinkSync(tmpPath);\n } catch {\n // ignore — original error is more informative\n }\n throw err;\n } finally {\n closeSync(fd);\n }\n try {\n renameSync(tmpPath, targetPath);\n } catch (err) {\n try {\n unlinkSync(tmpPath);\n } catch {\n // ignore\n }\n throw err;\n }\n}\n\nfunction normalizeVaultRelativePath(relativePath: string): string | undefined {\n const trimmed = relativePath.trim();\n if (!trimmed || isAbsolute(trimmed)) return undefined;\n\n const normalized = normalize(trimmed).split(sep).join(\"/\");\n if (!normalized || normalized === \".\" || normalized === \"..\" || normalized.startsWith(\"../\")) {\n return undefined;\n }\n return normalized;\n}\n\nfunction normalizeVaultTargetPath(targetPath?: string): string | undefined {\n if (targetPath === undefined) {\n return undefined;\n }\n\n const trimmed = targetPath.trim();\n if (!trimmed || !trimmed.startsWith(\"/\")) {\n return undefined;\n }\n\n const normalized = normalize(trimmed).split(sep).join(\"/\");\n return normalized.startsWith(\"/\") ? normalized : undefined;\n}\n\nexport function defaultVaultTargetPath(relativePath: string): string {\n const normalized = normalizeVaultRelativePath(relativePath) ?? relativePath.replace(/^\\/+/, \"\");\n return `/root/${normalized}`;\n}\n"]}
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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","sourcesContent":["import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync } from \"fs\";\nimport { dirname, isAbsolute, join, normalize, sep } from \"path\";\nimport type { PlatformName } from \"./adapter.js\";\nimport type { SandboxConfig } from \"./sandbox.js\";\nimport { atomicWritePrivateFile } from \"./fs-atomic.js\";\n\nconst PRIVATE_DIR_MODE = 0o700;\n\nfunction sanitizeCloudflareSandboxId(value: string): string {\n return (\n value\n .toLowerCase()\n .replace(/[^a-z0-9-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\") || \"unknown\"\n );\n}\n\n// ── Types ──────────────────────────────────────────────────────────────────────\n\n/** Shape of workspace/vaults/vault.json */\nexport interface VaultConfig {\n vaults: Record<string, VaultEntry>;\n}\n\n/** Per-user vault mount entry in vault.json */\nexport interface VaultMountEntry {\n source: string;\n target?: string;\n}\n\n/** Per-user vault entry in vault.json */\nexport interface VaultEntry {\n displayName: string;\n platform?: PlatformName;\n /** Subdirs/files in vault dir to mount into sandbox (e.g. [\".gcloud\", \".ssh\", \".kube\"]) */\n mounts?: Array<string | VaultMountEntry>;\n /** Whether to load env file as environment variables (default: true if env file exists) */\n envFile?: boolean;\n /** Per-user sandbox config override */\n sandbox?: {\n type?: \"image\" | \"firecracker\" | \"cloudflare\" | \"host\" | \"container\" | \"docker\";\n container?: string;\n image?: string;\n vmId?: string;\n sandboxId?: string;\n sshUser?: string;\n sshPort?: number;\n };\n}\n\nexport interface ResolvedVaultMount {\n source: string;\n target: string;\n}\n\n/** Resolved vault ready for use at runtime */\nexport interface ResolvedVault {\n userId: string;\n displayName: string;\n /** Absolute path to vault directory */\n dir: string;\n /** Absolute mount specs */\n mounts: ResolvedVaultMount[];\n /** Parsed from env file */\n env: Record<string, string>;\n sandboxOverride?: VaultEntry[\"sandbox\"];\n}\n\nexport interface VaultManager {\n /** Return true when a vault entry or vault directory exists for this exact key. */\n hasEntry(key: string): boolean;\n /** Resolve vault for a user; returns undefined when no entry exists. */\n resolve(userId: string): ResolvedVault | undefined;\n /** Get sandbox config with credential injection for a user */\n getSandboxConfig(userId: string, baseConfig: SandboxConfig): SandboxConfig;\n /** List all configured vaults */\n list(): ResolvedVault[];\n /** Re-read vault.json without restart */\n reload(): void;\n /** Check if vault system metadata is enabled (vault.json exists) */\n isEnabled(): boolean;\n /**\n * Add a vault entry and persist to disk.\n * No-op if the key already exists (idempotent).\n */\n addEntry(key: string, entry: VaultEntry): void;\n /**\n * Ensure a vault entry has image sandbox metadata.\n * Creates the entry when missing and upgrades existing entries that lack sandbox.type.\n */\n ensureImageSandboxEntry(key: string, entry: VaultEntry): void;\n /** Merge environment variables into vaults/<key>/env and persist them to disk. */\n upsertEnv(key: string, env: Record<string, string>): void;\n /** Write a private file into vaults/<key>/ and ensure it is mounted into the sandbox. */\n upsertFile(key: string, relativePath: string, content: string, targetPath?: string): void;\n}\n\n// ── parseEnvFile ───────────────────────────────────────────────────────────────\n\n/**\n * Parse a KEY=VALUE env file. Supports:\n * - Lines starting with # are comments\n * - Empty lines are skipped\n * - Values can be quoted with single or double quotes (quotes are stripped)\n * - No variable expansion\n * - The value is everything after the first `=` to end of line (no inline comments)\n */\nexport function parseEnvFile(content: string): Record<string, string> {\n const env: Record<string, string> = {};\n const lines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex === -1) continue;\n\n const key = trimmed.slice(0, eqIndex).trim();\n if (!key) continue;\n\n let value = trimmed.slice(eqIndex + 1);\n\n // Strip matching quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n env[key] = value;\n }\n\n return env;\n}\n\n// ── FileVaultManager ───────────────────────────────────────────────────────────\n\nexport class FileVaultManager implements VaultManager {\n private config: VaultConfig | null = null;\n private readonly vaultsDir: string;\n private readonly configPath: string;\n\n constructor(stateDir: string) {\n this.vaultsDir = join(stateDir, \"vaults\");\n this.configPath = join(this.vaultsDir, \"vault.json\");\n this.reload();\n }\n\n reload(): void {\n if (!existsSync(this.configPath)) {\n this.config = null;\n return;\n }\n\n try {\n const raw = readFileSync(this.configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n !parsed.vaults ||\n typeof parsed.vaults !== \"object\"\n ) {\n console.error(`vault: malformed vault.json — expected { vaults: { ... } }`);\n this.config = null;\n return;\n }\n\n this.config = parsed as VaultConfig;\n this.warnUnsupportedSandboxTypes();\n } catch (err) {\n console.error(`vault: failed to read ${this.configPath}:`, err);\n this.config = null;\n }\n }\n\n /** Warn for legacy or insecure vault sandbox overrides that are no longer allowed. */\n private warnUnsupportedSandboxTypes(): void {\n if (!this.config) return;\n for (const [key, entry] of Object.entries(this.config.vaults)) {\n if (entry.sandbox?.type === \"host\") {\n console.error(\n `vault: \"${key}\" uses sandbox.type=host, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image, sandbox.type=firecracker, or sandbox.type=cloudflare.\",\n );\n }\n if (entry.sandbox?.type === \"container\" || entry.sandbox?.type === \"docker\") {\n console.error(\n `vault: \"${key}\" uses sandbox.type=${entry.sandbox.type}, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image for per-user containers, sandbox.type=firecracker, or sandbox.type=cloudflare.\",\n );\n }\n }\n }\n\n isEnabled(): boolean {\n return this.config !== null || existsSync(this.vaultsDir);\n }\n\n hasEntry(key: string): boolean {\n return !!this.config?.vaults[key] || existsSync(join(this.vaultsDir, key));\n }\n\n resolve(userId: string): ResolvedVault | undefined {\n const entry = this.config?.vaults[userId];\n const dir = join(this.vaultsDir, userId);\n if (!entry && !existsSync(dir)) return undefined;\n return this.buildResolved(userId, entry);\n }\n\n getSandboxConfig(userId: string, baseConfig: SandboxConfig): SandboxConfig {\n const vault = this.resolve(userId);\n if (!vault?.sandboxOverride) {\n if (baseConfig.type === \"cloudflare\") {\n return {\n type: \"cloudflare\",\n sandboxId: `${baseConfig.sandboxId}-${sanitizeCloudflareSandboxId(userId)}`,\n };\n }\n return baseConfig;\n }\n\n const override = vault.sandboxOverride;\n\n if (override.type === \"image\") {\n if (baseConfig.type !== \"image\") {\n if (!override.container) {\n if (baseConfig.type === \"cloudflare\") {\n return {\n type: \"cloudflare\",\n sandboxId: `${baseConfig.sandboxId}-${sanitizeCloudflareSandboxId(userId)}`,\n };\n }\n return baseConfig;\n }\n throw new Error(\n `vault \"${userId}\" sets sandbox.type=image, but base sandbox is \"${baseConfig.type}\". ` +\n \"Use --sandbox=image:<image> to enable managed image containers for this vault.\",\n );\n }\n const container = override.container || `mama-sandbox-${userId}`;\n return { type: \"container\", container };\n }\n\n if (override.type === \"firecracker\") {\n if (!override.vmId) return baseConfig;\n if (baseConfig.type !== \"firecracker\") {\n throw new Error(\n `vault \"${userId}\" sets sandbox.type=firecracker, but base sandbox is \"${baseConfig.type}\". ` +\n \"Use --sandbox=firecracker:<vm-id>:<host-path> so /workspace stays mapped to the real workspace.\",\n );\n }\n return {\n type: \"firecracker\",\n vmId: override.vmId,\n hostPath: baseConfig.hostPath,\n sshUser: override.sshUser,\n sshPort: override.sshPort,\n };\n }\n\n if (override.type === \"cloudflare\") {\n if (!override.sandboxId) return baseConfig;\n if (baseConfig.type !== \"cloudflare\") {\n throw new Error(\n `vault \"${userId}\" sets sandbox.type=cloudflare, but base sandbox is \"${baseConfig.type}\". ` +\n \"Use --sandbox=cloudflare:<sandbox-id> to enable Cloudflare remote execution.\",\n );\n }\n return {\n type: \"cloudflare\",\n sandboxId: override.sandboxId,\n };\n }\n\n if (override.type === \"host\") {\n throw new Error(\n `vault \"${userId}\" uses sandbox.type=host, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image, sandbox.type=firecracker, or sandbox.type=cloudflare.\",\n );\n }\n\n if (override.type === \"container\" || override.type === \"docker\") {\n throw new Error(\n `vault \"${userId}\" uses sandbox.type=${override.type}, which is blocked for credential isolation. ` +\n \"Use sandbox.type=image for per-user containers, sandbox.type=firecracker, or sandbox.type=cloudflare.\",\n );\n }\n\n // No type override — return base config unchanged\n return baseConfig;\n }\n\n list(): ResolvedVault[] {\n const keys = new Set<string>();\n for (const key of Object.keys(this.config?.vaults ?? {})) {\n keys.add(key);\n }\n if (existsSync(this.vaultsDir)) {\n for (const entry of readdirSync(this.vaultsDir, { withFileTypes: true })) {\n if (entry.isDirectory()) keys.add(entry.name);\n }\n }\n return Array.from(keys, (key) => this.buildResolved(key, this.config?.vaults[key]));\n }\n\n addEntry(key: string, entry: VaultEntry): void {\n const cfg = (this.config ??= { vaults: {} });\n // Idempotent: skip if already exists\n if (cfg.vaults[key]) return;\n cfg.vaults[key] = entry;\n this.persistConfig();\n }\n\n ensureImageSandboxEntry(key: string, entry: VaultEntry): void {\n if (entry.sandbox?.type !== \"image\") {\n throw new Error(`vault: ensureImageSandboxEntry requires sandbox.type=image for \"${key}\"`);\n }\n\n const cfg = (this.config ??= { vaults: {} });\n const existing = cfg.vaults[key];\n if (!existing) {\n cfg.vaults[key] = entry;\n this.persistConfig();\n return;\n }\n\n let nextEntry = existing;\n let changed = false;\n\n if (!existing.platform && entry.platform) {\n nextEntry = { ...nextEntry, platform: entry.platform };\n changed = true;\n }\n\n const existingSandbox = existing.sandbox;\n if (!existingSandbox?.type) {\n nextEntry = { ...nextEntry, sandbox: entry.sandbox };\n changed = true;\n }\n\n if (!changed) return;\n\n cfg.vaults[key] = nextEntry;\n this.persistConfig();\n }\n\n upsertEnv(key: string, env: Record<string, string>): void {\n const dir = join(this.vaultsDir, key);\n const envPath = join(dir, \"env\");\n ensurePrivateDir(this.vaultsDir);\n ensurePrivateDir(dir);\n const existing = existsSync(envPath)\n ? parseEnvFile(readFileSync(envPath, \"utf-8\"))\n : ({} as Record<string, string>);\n const merged = { ...existing, ...env };\n const content =\n Object.entries(merged)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([envKey, value]) => `${envKey}=${value}`)\n .join(\"\\n\") + \"\\n\";\n atomicWritePrivateFile(envPath, content);\n }\n\n upsertFile(key: string, relativePath: string, content: string, targetPath?: string): void {\n const normalizedPath = normalizeVaultRelativePath(relativePath);\n if (!normalizedPath || (targetPath !== undefined && !normalizeVaultTargetPath(targetPath))) {\n throw new Error(`vault: invalid relative secret file path for \"${key}\": ${relativePath}`);\n }\n\n const dir = join(this.vaultsDir, key);\n const filePath = join(dir, normalizedPath);\n\n ensurePrivateDir(this.vaultsDir);\n ensurePrivateDir(dir);\n const parentDir = dirname(filePath);\n if (parentDir !== dir) ensurePrivateDir(parentDir);\n atomicWritePrivateFile(filePath, content);\n }\n\n // ── private ────────────────────────────────────────────────────────────────\n\n private persistConfig(): void {\n ensurePrivateDir(this.vaultsDir);\n\n // Preserve concurrent external edits: pull in any entries that appear on\n // disk but not in our in-memory view, so a background edit (e.g. another\n // admin adding a user) is not silently dropped by the next upsert here.\n // Individual field edits still follow last-writer-wins per key.\n const onDisk = this.readConfigFromDisk();\n if (onDisk && this.config) {\n for (const [key, entry] of Object.entries(onDisk.vaults)) {\n if (!(key in this.config.vaults)) {\n this.config.vaults[key] = entry;\n }\n }\n }\n\n atomicWritePrivateFile(this.configPath, JSON.stringify(this.config, null, 2) + \"\\n\");\n }\n\n private readConfigFromDisk(): VaultConfig | null {\n if (!existsSync(this.configPath)) return null;\n try {\n const parsed = JSON.parse(readFileSync(this.configPath, \"utf-8\"));\n if (\n !parsed ||\n typeof parsed !== \"object\" ||\n !parsed.vaults ||\n typeof parsed.vaults !== \"object\"\n ) {\n return null;\n }\n return parsed as VaultConfig;\n } catch {\n return null;\n }\n }\n\n private buildResolved(key: string, entry?: VaultEntry): ResolvedVault {\n const dir = join(this.vaultsDir, key);\n\n const inferredMounts = this.inferMountsFromDir(dir);\n const configuredMounts = (entry?.mounts ?? [])\n .map((mount) => this.resolveMountEntry(dir, mount))\n .filter((mount): mount is ResolvedVaultMount => mount !== undefined);\n const mountsByTarget = new Map<string, ResolvedVaultMount>();\n for (const mount of inferredMounts) mountsByTarget.set(mount.target, mount);\n for (const mount of configuredMounts) mountsByTarget.set(mount.target, mount);\n\n let env: Record<string, string> = {};\n const envPath = join(dir, \"env\");\n if ((entry?.envFile ?? true) && existsSync(envPath)) {\n try {\n env = parseEnvFile(readFileSync(envPath, \"utf-8\"));\n } catch (err) {\n console.error(`vault: failed to parse env file for \"${key}\":`, err);\n }\n }\n\n return {\n userId: key,\n displayName: entry?.displayName ?? key,\n dir,\n mounts: [...mountsByTarget.values()],\n env,\n sandboxOverride: entry?.sandbox,\n };\n }\n\n private inferMountsFromDir(dir: string): ResolvedVaultMount[] {\n if (!existsSync(dir)) {\n return [];\n }\n\n const mounts: ResolvedVaultMount[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.name === \"env\") continue;\n const source = join(dir, entry.name);\n const target = inferredVaultTargetPath(entry.name);\n if (!target) continue;\n mounts.push({ source, target });\n }\n return mounts;\n }\n\n private resolveMountEntry(\n dir: string,\n mount: string | VaultMountEntry,\n ): ResolvedVaultMount | undefined {\n if (typeof mount === \"string\") {\n const normalizedSource = normalizeVaultRelativePath(mount);\n if (!normalizedSource) return undefined;\n return {\n source: join(dir, normalizedSource),\n target: defaultVaultTargetPath(normalizedSource),\n };\n }\n\n if (!mount || typeof mount !== \"object\") return undefined;\n const normalizedSource = normalizeVaultRelativePath(mount.source);\n if (!normalizedSource) return undefined;\n const normalizedTarget = normalizeVaultTargetPath(mount.target);\n return {\n source: join(dir, normalizedSource),\n target: normalizedTarget ?? defaultVaultTargetPath(normalizedSource),\n };\n }\n}\n\nfunction ensurePrivateDir(path: string): void {\n mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });\n chmodSync(path, PRIVATE_DIR_MODE);\n}\n\nfunction normalizeVaultRelativePath(relativePath: string): string | undefined {\n const trimmed = relativePath.trim();\n if (!trimmed || isAbsolute(trimmed)) return undefined;\n\n const normalized = normalize(trimmed).split(sep).join(\"/\");\n if (!normalized || normalized === \".\" || normalized === \"..\" || normalized.startsWith(\"../\")) {\n return undefined;\n }\n return normalized;\n}\n\nfunction normalizeVaultTargetPath(targetPath?: string): string | undefined {\n if (targetPath === undefined) {\n return undefined;\n }\n\n const trimmed = targetPath.trim();\n if (!trimmed || !trimmed.startsWith(\"/\")) {\n return undefined;\n }\n\n const normalized = normalize(trimmed).split(sep).join(\"/\");\n return normalized.startsWith(\"/\") ? normalized : undefined;\n}\n\nexport function defaultVaultTargetPath(relativePath: string): string {\n const normalized = normalizeVaultRelativePath(relativePath) ?? relativePath.replace(/^\\/+/, \"\");\n return `/root/${normalized}`;\n}\n\nfunction inferredVaultTargetPath(relativePath: string): string | undefined {\n const normalized = normalizeVaultRelativePath(relativePath);\n if (!normalized) return undefined;\n\n if (normalized === \"gws.json\") {\n return \"/root/.config/gws/credentials.json\";\n }\n if (normalized === \".ssh\" || normalized.startsWith(\".ssh/\")) {\n return \"/root/.ssh\";\n }\n if (normalized === \".kube\" || normalized.startsWith(\".kube/\")) {\n return \"/root/.kube\";\n }\n if (normalized === \".config/gh\" || normalized.startsWith(\".config/gh/\")) {\n return \"/root/.config/gh\";\n }\n\n return defaultVaultTargetPath(normalized);\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@geminixiang/mama",
3
- "version": "0.2.0-beta.3",
4
- "description": "Slack bot that delegates messages to the pi coding agent",
3
+ "version": "0.2.0-beta.5",
4
+ "description": "Multi-Agent Mischief Assistant for Slack, Telegram, and Discord",
5
5
  "keywords": [
6
6
  "agent",
7
7
  "ai",
@@ -39,12 +39,11 @@
39
39
  "prepare": "husky"
40
40
  },
41
41
  "dependencies": {
42
- "@anthropic-ai/sandbox-runtime": "^0.0.49",
43
42
  "@google-cloud/logging": "^11.2.1",
44
- "@mariozechner/pi-agent-core": "^0.69.0",
45
- "@mariozechner/pi-ai": "^0.69.0",
46
- "@mariozechner/pi-coding-agent": "^0.69.0",
47
- "@sentry/node": "^10.47.0",
43
+ "@mariozechner/pi-agent-core": "^0.71.1",
44
+ "@mariozechner/pi-ai": "^0.71.1",
45
+ "@mariozechner/pi-coding-agent": "^0.71.1",
46
+ "@sentry/node": "^10.51.0",
48
47
  "@sinclair/typebox": "^0.34.49",
49
48
  "@slack/socket-mode": "^2.0.6",
50
49
  "@slack/web-api": "^7.15.0",
@@ -53,8 +52,7 @@
53
52
  "diff": "^8.0.4",
54
53
  "discord.js": "^14.26.2",
55
54
  "grammy": "^1.42.0",
56
- "pino": "^10.3.1",
57
- "playwright": "^1.59.1"
55
+ "pino": "^10.3.1"
58
56
  },
59
57
  "devDependencies": {
60
58
  "@types/diff": "^8.0.0",