waterbox 0.1.0-alpha.2 → 0.1.0-alpha.3
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/README.md +15 -8
- package/dist/waterbox.js +202 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,22 +23,24 @@ npx waterbox status
|
|
|
23
23
|
npx waterbox logout
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Interactive setup stores only the provider credential in the native keyring
|
|
27
|
-
|
|
26
|
+
Interactive setup stores only the provider credential in the native keyring on
|
|
27
|
+
macOS and Windows. Linux uses `~/.waterbox/credentials.json` with a `0700`
|
|
28
|
+
directory and `0600` file. Non-secret settings are written atomically to
|
|
29
|
+
`~/.waterbox/config.json` using
|
|
28
30
|
the exact official direct-provider endpoints `https://ascii.dev/api/box/v1` and
|
|
29
31
|
`https://api.vercel.com/`; hosted Waterbox is pinned to `https://api.waterbox.ai/`.
|
|
30
32
|
Interactive setup shows hosted Waterbox only when its public capability document
|
|
31
|
-
advertises availability. Existing hosted
|
|
33
|
+
advertises availability. Existing hosted persisted configuration and explicit
|
|
32
34
|
`WATERBOX_PROVIDER=waterbox` environment configuration remain valid independently.
|
|
33
35
|
`FORCE_DISPLAY_WATERBOX=1` is a development/debug override that shows it without
|
|
34
36
|
fetching capabilities.
|
|
35
|
-
Status never prints credentials
|
|
36
|
-
|
|
37
|
+
Status never prints credentials and identifies the active credential backend.
|
|
38
|
+
Logout removes local settings and all three stored credentials but does not alter remote resources or
|
|
37
39
|
the SQLite resource registry.
|
|
38
40
|
|
|
39
|
-
For
|
|
40
|
-
configuration in the MCP client's
|
|
41
|
-
secrets in command arguments:
|
|
41
|
+
For containers, automation, or systems where user-readable file storage is not
|
|
42
|
+
appropriate, place a complete provider configuration in the MCP client's
|
|
43
|
+
environment/secret facility. Do not put secrets in command arguments:
|
|
42
44
|
|
|
43
45
|
```text
|
|
44
46
|
Waterbox: WATERBOX_PROVIDER=waterbox, WATERBOX_API_KEY=<client-managed secret>
|
|
@@ -54,6 +56,11 @@ endpoints are supported only when the complete provider
|
|
|
54
56
|
selection and credentials come from process environment. Environment and
|
|
55
57
|
persisted sources are never mixed. `.env` is never loaded implicitly.
|
|
56
58
|
|
|
59
|
+
Linux credentials are plaintext at rest and protected by filesystem ownership
|
|
60
|
+
and permissions. Same-user processes, root, and backups may read them. Linux
|
|
61
|
+
users upgrading from alpha.2 should rerun `npx waterbox setup`; native-keyring
|
|
62
|
+
entries are not migrated automatically.
|
|
63
|
+
|
|
57
64
|
An unconfigured server remains connected and returns setup guidance from all
|
|
58
65
|
tools before filesystem, SQLite, artifact, or provider I/O.
|
|
59
66
|
|
package/dist/waterbox.js
CHANGED
|
@@ -2007,11 +2007,11 @@ var require_codegen = __commonJS({
|
|
|
2007
2007
|
const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
|
|
2008
2008
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
2009
2009
|
}
|
|
2010
|
-
optimizeNames(names,
|
|
2010
|
+
optimizeNames(names, constants3) {
|
|
2011
2011
|
if (!names[this.name.str])
|
|
2012
2012
|
return;
|
|
2013
2013
|
if (this.rhs)
|
|
2014
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
2014
|
+
this.rhs = optimizeExpr(this.rhs, names, constants3);
|
|
2015
2015
|
return this;
|
|
2016
2016
|
}
|
|
2017
2017
|
get names() {
|
|
@@ -2028,10 +2028,10 @@ var require_codegen = __commonJS({
|
|
|
2028
2028
|
render({ _n }) {
|
|
2029
2029
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
2030
2030
|
}
|
|
2031
|
-
optimizeNames(names,
|
|
2031
|
+
optimizeNames(names, constants3) {
|
|
2032
2032
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
2033
2033
|
return;
|
|
2034
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
2034
|
+
this.rhs = optimizeExpr(this.rhs, names, constants3);
|
|
2035
2035
|
return this;
|
|
2036
2036
|
}
|
|
2037
2037
|
get names() {
|
|
@@ -2092,8 +2092,8 @@ var require_codegen = __commonJS({
|
|
|
2092
2092
|
optimizeNodes() {
|
|
2093
2093
|
return `${this.code}` ? this : void 0;
|
|
2094
2094
|
}
|
|
2095
|
-
optimizeNames(names,
|
|
2096
|
-
this.code = optimizeExpr(this.code, names,
|
|
2095
|
+
optimizeNames(names, constants3) {
|
|
2096
|
+
this.code = optimizeExpr(this.code, names, constants3);
|
|
2097
2097
|
return this;
|
|
2098
2098
|
}
|
|
2099
2099
|
get names() {
|
|
@@ -2122,12 +2122,12 @@ var require_codegen = __commonJS({
|
|
|
2122
2122
|
}
|
|
2123
2123
|
return nodes.length > 0 ? this : void 0;
|
|
2124
2124
|
}
|
|
2125
|
-
optimizeNames(names,
|
|
2125
|
+
optimizeNames(names, constants3) {
|
|
2126
2126
|
const { nodes } = this;
|
|
2127
2127
|
let i = nodes.length;
|
|
2128
2128
|
while (i--) {
|
|
2129
2129
|
const n = nodes[i];
|
|
2130
|
-
if (n.optimizeNames(names,
|
|
2130
|
+
if (n.optimizeNames(names, constants3))
|
|
2131
2131
|
continue;
|
|
2132
2132
|
subtractNames(names, n.names);
|
|
2133
2133
|
nodes.splice(i, 1);
|
|
@@ -2180,12 +2180,12 @@ var require_codegen = __commonJS({
|
|
|
2180
2180
|
return void 0;
|
|
2181
2181
|
return this;
|
|
2182
2182
|
}
|
|
2183
|
-
optimizeNames(names,
|
|
2183
|
+
optimizeNames(names, constants3) {
|
|
2184
2184
|
var _a;
|
|
2185
|
-
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
2186
|
-
if (!(super.optimizeNames(names,
|
|
2185
|
+
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants3);
|
|
2186
|
+
if (!(super.optimizeNames(names, constants3) || this.else))
|
|
2187
2187
|
return;
|
|
2188
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
2188
|
+
this.condition = optimizeExpr(this.condition, names, constants3);
|
|
2189
2189
|
return this;
|
|
2190
2190
|
}
|
|
2191
2191
|
get names() {
|
|
@@ -2208,10 +2208,10 @@ var require_codegen = __commonJS({
|
|
|
2208
2208
|
render(opts2) {
|
|
2209
2209
|
return `for(${this.iteration})` + super.render(opts2);
|
|
2210
2210
|
}
|
|
2211
|
-
optimizeNames(names,
|
|
2212
|
-
if (!super.optimizeNames(names,
|
|
2211
|
+
optimizeNames(names, constants3) {
|
|
2212
|
+
if (!super.optimizeNames(names, constants3))
|
|
2213
2213
|
return;
|
|
2214
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
2214
|
+
this.iteration = optimizeExpr(this.iteration, names, constants3);
|
|
2215
2215
|
return this;
|
|
2216
2216
|
}
|
|
2217
2217
|
get names() {
|
|
@@ -2247,10 +2247,10 @@ var require_codegen = __commonJS({
|
|
|
2247
2247
|
render(opts2) {
|
|
2248
2248
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts2);
|
|
2249
2249
|
}
|
|
2250
|
-
optimizeNames(names,
|
|
2251
|
-
if (!super.optimizeNames(names,
|
|
2250
|
+
optimizeNames(names, constants3) {
|
|
2251
|
+
if (!super.optimizeNames(names, constants3))
|
|
2252
2252
|
return;
|
|
2253
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
2253
|
+
this.iterable = optimizeExpr(this.iterable, names, constants3);
|
|
2254
2254
|
return this;
|
|
2255
2255
|
}
|
|
2256
2256
|
get names() {
|
|
@@ -2292,11 +2292,11 @@ var require_codegen = __commonJS({
|
|
|
2292
2292
|
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
|
|
2293
2293
|
return this;
|
|
2294
2294
|
}
|
|
2295
|
-
optimizeNames(names,
|
|
2295
|
+
optimizeNames(names, constants3) {
|
|
2296
2296
|
var _a, _b;
|
|
2297
|
-
super.optimizeNames(names,
|
|
2298
|
-
(_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
2299
|
-
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names,
|
|
2297
|
+
super.optimizeNames(names, constants3);
|
|
2298
|
+
(_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants3);
|
|
2299
|
+
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants3);
|
|
2300
2300
|
return this;
|
|
2301
2301
|
}
|
|
2302
2302
|
get names() {
|
|
@@ -2597,7 +2597,7 @@ var require_codegen = __commonJS({
|
|
|
2597
2597
|
function addExprNames(names, from) {
|
|
2598
2598
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
2599
2599
|
}
|
|
2600
|
-
function optimizeExpr(expr, names,
|
|
2600
|
+
function optimizeExpr(expr, names, constants3) {
|
|
2601
2601
|
if (expr instanceof code_1.Name)
|
|
2602
2602
|
return replaceName(expr);
|
|
2603
2603
|
if (!canOptimize(expr))
|
|
@@ -2612,14 +2612,14 @@ var require_codegen = __commonJS({
|
|
|
2612
2612
|
return items;
|
|
2613
2613
|
}, []));
|
|
2614
2614
|
function replaceName(n) {
|
|
2615
|
-
const c =
|
|
2615
|
+
const c = constants3[n.str];
|
|
2616
2616
|
if (c === void 0 || names[n.str] !== 1)
|
|
2617
2617
|
return n;
|
|
2618
2618
|
delete names[n.str];
|
|
2619
2619
|
return c;
|
|
2620
2620
|
}
|
|
2621
2621
|
function canOptimize(e) {
|
|
2622
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
2622
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants3[c.str] !== void 0);
|
|
2623
2623
|
}
|
|
2624
2624
|
}
|
|
2625
2625
|
function subtractNames(names, from) {
|
|
@@ -49971,7 +49971,7 @@ function snapshotName(accountId, snapshotId) {
|
|
|
49971
49971
|
const digest2 = createHash2("sha256").update(accountId).update("\0").update(snapshotId).digest("hex").slice(0, 32);
|
|
49972
49972
|
return `waterbox-${hint}-${digest2}`;
|
|
49973
49973
|
}
|
|
49974
|
-
var PACKAGE_VERSION = "0.1.0-alpha.
|
|
49974
|
+
var PACKAGE_VERSION = "0.1.0-alpha.2";
|
|
49975
49975
|
var SystemBoxProviderClock = class {
|
|
49976
49976
|
now() {
|
|
49977
49977
|
return /* @__PURE__ */ new Date();
|
|
@@ -51913,7 +51913,7 @@ async function createEmbeddedApiBackend(config3, overrides = {}) {
|
|
|
51913
51913
|
}
|
|
51914
51914
|
async function createConfiguredEmbeddedApiBackend(configuration, artifactLocation, diagnostic) {
|
|
51915
51915
|
validateConfiguredMcpBackend(configuration);
|
|
51916
|
-
const artifact = await loadSandboxRuntimeArtifact(artifactLocation, "0.1.0-alpha.
|
|
51916
|
+
const artifact = await loadSandboxRuntimeArtifact(artifactLocation, "0.1.0-alpha.3");
|
|
51917
51917
|
return createEmbeddedApiBackend({ sqlitePath: configuration.sqlitePath, accountId: "local", provider: { ...configuration.provider, runtimeArtifact: artifact }, ...diagnostic === void 0 ? {} : { diagnostic } });
|
|
51918
51918
|
}
|
|
51919
51919
|
function validateBaseConfiguration(config3, identityResolver) {
|
|
@@ -52026,7 +52026,8 @@ function positiveNumber(value) {
|
|
|
52026
52026
|
}
|
|
52027
52027
|
|
|
52028
52028
|
// packages/mcp/src/onboarding.ts
|
|
52029
|
-
import {
|
|
52029
|
+
import { constants } from "node:fs";
|
|
52030
|
+
import { chmod, lstat, mkdir as mkdir2, open, readFile as readFile2, rename, rm, writeFile } from "node:fs/promises";
|
|
52030
52031
|
import { homedir as homedir2 } from "node:os";
|
|
52031
52032
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
52032
52033
|
var KEYRING_SERVICE = "waterbox";
|
|
@@ -52038,6 +52039,7 @@ var CAPABILITY_TIMEOUT_MS = 2e3;
|
|
|
52038
52039
|
var MAX_CAPABILITY_BYTES = 16 * 1024;
|
|
52039
52040
|
var accounts = { waterbox: "api-key", box: "box-api-key", vercel: "vercel-token" };
|
|
52040
52041
|
var MAX_CONFIG_BYTES = 64 * 1024;
|
|
52042
|
+
var MAX_CREDENTIAL_BYTES = 64 * 1024;
|
|
52041
52043
|
var setupGuidance = "Waterbox MCP is not configured. Run npx waterbox setup, then restart the MCP client. Environment-only setup is also supported: set WATERBOX_PROVIDER and the selected provider's variables (Waterbox: WATERBOX_API_KEY; Box: BOX_API_KEY, WATERBOX_AUTO_STOP; Vercel: VERCEL_TOKEN, VERCEL_TEAM_ID, VERCEL_PROJECT_ID, WATERBOX_AUTO_STOP). Do not provide credentials in chat or tool arguments.";
|
|
52042
52044
|
var OnboardingError = class extends Error {
|
|
52043
52045
|
constructor(message = setupGuidance) {
|
|
@@ -52096,6 +52098,7 @@ function configStorage(home = homedir2()) {
|
|
|
52096
52098
|
}
|
|
52097
52099
|
function nativeCredentialStore() {
|
|
52098
52100
|
return {
|
|
52101
|
+
backend: "keyring",
|
|
52099
52102
|
async get(provider) {
|
|
52100
52103
|
const { AsyncEntry } = await import("@napi-rs/keyring");
|
|
52101
52104
|
const value = await new AsyncEntry(KEYRING_SERVICE, accounts[provider]).getPassword();
|
|
@@ -52112,6 +52115,145 @@ function nativeCredentialStore() {
|
|
|
52112
52115
|
}
|
|
52113
52116
|
};
|
|
52114
52117
|
}
|
|
52118
|
+
var credentialDocumentSchema = external_exports.object({ version: external_exports.literal(1), credentials: external_exports.object({ waterbox: external_exports.string().optional(), box: external_exports.string().optional(), vercel: external_exports.string().optional() }).strict() }).strict();
|
|
52119
|
+
var credentialQueues = /* @__PURE__ */ new Map();
|
|
52120
|
+
function fileCredentialStore(home = homedir2()) {
|
|
52121
|
+
const path = join3(home, ".waterbox", "credentials.json");
|
|
52122
|
+
const unavailable = () => new OnboardingError("Waterbox credential storage is unavailable. Run npx waterbox setup or use environment-only configuration.");
|
|
52123
|
+
const queued = async (operation) => {
|
|
52124
|
+
const prior = credentialQueues.get(path) ?? Promise.resolve();
|
|
52125
|
+
let release;
|
|
52126
|
+
const current = new Promise((resolve) => {
|
|
52127
|
+
release = resolve;
|
|
52128
|
+
});
|
|
52129
|
+
const waiting = prior.then(() => current, () => current);
|
|
52130
|
+
credentialQueues.set(path, waiting);
|
|
52131
|
+
await prior.catch(() => {
|
|
52132
|
+
});
|
|
52133
|
+
try {
|
|
52134
|
+
return await operation();
|
|
52135
|
+
} finally {
|
|
52136
|
+
release();
|
|
52137
|
+
if (credentialQueues.get(path) === waiting) credentialQueues.delete(path);
|
|
52138
|
+
}
|
|
52139
|
+
};
|
|
52140
|
+
const readDocument = async () => {
|
|
52141
|
+
try {
|
|
52142
|
+
const directory = await lstat(dirname2(path));
|
|
52143
|
+
if (directory.isSymbolicLink() || !directory.isDirectory() || (directory.mode & 511) !== 448 || !ownedByCurrentUser(directory.uid)) throw unavailable();
|
|
52144
|
+
const file3 = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
52145
|
+
let value;
|
|
52146
|
+
try {
|
|
52147
|
+
const metadata = await file3.stat();
|
|
52148
|
+
if (!metadata.isFile() || metadata.nlink !== 1 || metadata.size > MAX_CREDENTIAL_BYTES || (metadata.mode & 511) !== 384 || !ownedByCurrentUser(metadata.uid)) throw unavailable();
|
|
52149
|
+
const bytes = Buffer.alloc(metadata.size + 1);
|
|
52150
|
+
let size = 0;
|
|
52151
|
+
while (size < bytes.length) {
|
|
52152
|
+
const result = await file3.read(bytes, size, bytes.length - size, size);
|
|
52153
|
+
if (result.bytesRead === 0) break;
|
|
52154
|
+
size += result.bytesRead;
|
|
52155
|
+
}
|
|
52156
|
+
if (size !== metadata.size) throw unavailable();
|
|
52157
|
+
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
52158
|
+
} catch {
|
|
52159
|
+
throw unavailable();
|
|
52160
|
+
} finally {
|
|
52161
|
+
await file3.close();
|
|
52162
|
+
}
|
|
52163
|
+
const parsed = credentialDocumentSchema.safeParse(value);
|
|
52164
|
+
if (!parsed.success) throw unavailable();
|
|
52165
|
+
for (const secret of Object.values(parsed.data.credentials)) try {
|
|
52166
|
+
providerCredential(secret);
|
|
52167
|
+
} catch {
|
|
52168
|
+
throw unavailable();
|
|
52169
|
+
}
|
|
52170
|
+
return parsed.data;
|
|
52171
|
+
} catch (error47) {
|
|
52172
|
+
if (error47.code === "ENOENT") return void 0;
|
|
52173
|
+
if (error47 instanceof OnboardingError) throw error47;
|
|
52174
|
+
throw unavailable();
|
|
52175
|
+
}
|
|
52176
|
+
};
|
|
52177
|
+
const syncDirectory = async () => {
|
|
52178
|
+
try {
|
|
52179
|
+
const directory = await open(dirname2(path), "r");
|
|
52180
|
+
try {
|
|
52181
|
+
await directory.sync();
|
|
52182
|
+
} finally {
|
|
52183
|
+
await directory.close();
|
|
52184
|
+
}
|
|
52185
|
+
} catch (error47) {
|
|
52186
|
+
if (!["EINVAL", "ENOTSUP", "EPERM", "EISDIR"].includes(error47.code ?? "")) throw error47;
|
|
52187
|
+
}
|
|
52188
|
+
};
|
|
52189
|
+
const writeDocument = async (document) => {
|
|
52190
|
+
const directoryPath = dirname2(path);
|
|
52191
|
+
try {
|
|
52192
|
+
await mkdir2(directoryPath, { recursive: true, mode: 448 });
|
|
52193
|
+
const directory = await lstat(directoryPath);
|
|
52194
|
+
if (directory.isSymbolicLink() || !directory.isDirectory() || !ownedByCurrentUser(directory.uid)) throw unavailable();
|
|
52195
|
+
await chmod(directoryPath, 448);
|
|
52196
|
+
try {
|
|
52197
|
+
const existing = await lstat(path);
|
|
52198
|
+
if (existing.isSymbolicLink() || !existing.isFile()) throw unavailable();
|
|
52199
|
+
} catch (error47) {
|
|
52200
|
+
if (error47.code !== "ENOENT") throw error47;
|
|
52201
|
+
}
|
|
52202
|
+
const temporary = `${path}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
52203
|
+
try {
|
|
52204
|
+
await writeFile(temporary, JSON.stringify(document), { encoding: "utf8", mode: 384, flag: "wx" });
|
|
52205
|
+
await chmod(temporary, 384);
|
|
52206
|
+
const file3 = await open(temporary, "r");
|
|
52207
|
+
try {
|
|
52208
|
+
await file3.sync();
|
|
52209
|
+
} finally {
|
|
52210
|
+
await file3.close();
|
|
52211
|
+
}
|
|
52212
|
+
await rename(temporary, path);
|
|
52213
|
+
await syncDirectory();
|
|
52214
|
+
} catch (error47) {
|
|
52215
|
+
await rm(temporary, { force: true }).catch(() => {
|
|
52216
|
+
});
|
|
52217
|
+
throw error47;
|
|
52218
|
+
}
|
|
52219
|
+
} catch (error47) {
|
|
52220
|
+
if (error47 instanceof OnboardingError) throw error47;
|
|
52221
|
+
throw unavailable();
|
|
52222
|
+
}
|
|
52223
|
+
};
|
|
52224
|
+
return {
|
|
52225
|
+
backend: "file",
|
|
52226
|
+
async get(provider) {
|
|
52227
|
+
return queued(async () => (await readDocument())?.credentials[provider]);
|
|
52228
|
+
},
|
|
52229
|
+
async set(provider, secret) {
|
|
52230
|
+
const accepted = providerCredential(secret);
|
|
52231
|
+
await queued(async () => {
|
|
52232
|
+
const document = await readDocument() ?? { version: 1, credentials: {} };
|
|
52233
|
+
document.credentials[provider] = accepted;
|
|
52234
|
+
await writeDocument(document);
|
|
52235
|
+
});
|
|
52236
|
+
},
|
|
52237
|
+
async delete(provider) {
|
|
52238
|
+
return queued(async () => {
|
|
52239
|
+
const document = await readDocument();
|
|
52240
|
+
if (!document || document.credentials[provider] === void 0) return false;
|
|
52241
|
+
delete document.credentials[provider];
|
|
52242
|
+
if (Object.keys(document.credentials).length === 0) {
|
|
52243
|
+
await rm(path);
|
|
52244
|
+
await syncDirectory();
|
|
52245
|
+
} else await writeDocument(document);
|
|
52246
|
+
return true;
|
|
52247
|
+
});
|
|
52248
|
+
}
|
|
52249
|
+
};
|
|
52250
|
+
}
|
|
52251
|
+
function defaultCredentialStore(home, platform = process.platform) {
|
|
52252
|
+
return platform === "linux" ? fileCredentialStore(home) : nativeCredentialStore();
|
|
52253
|
+
}
|
|
52254
|
+
function ownedByCurrentUser(uid) {
|
|
52255
|
+
return process.getuid === void 0 || uid === process.getuid();
|
|
52256
|
+
}
|
|
52115
52257
|
async function loadPersisted(storage) {
|
|
52116
52258
|
let raw2;
|
|
52117
52259
|
try {
|
|
@@ -52162,7 +52304,7 @@ async function resolvedEnvironment(environment, storage, credentials) {
|
|
|
52162
52304
|
const settings = config3.vercel;
|
|
52163
52305
|
Object.assign(resolved, { VERCEL_TOKEN: secret, VERCEL_API_ORIGIN: settings.apiOrigin, VERCEL_TEAM_ID: settings.teamId, VERCEL_PROJECT_ID: settings.projectId, VERCEL_POLL_INTERVAL_MS: String(settings.pollIntervalMs), VERCEL_POLL_TIMEOUT_MS: String(settings.pollTimeoutMs), VERCEL_REQUEST_TIMEOUT_MS: String(settings.requestTimeoutMs), WATERBOX_AUTO_STOP: automaticStopEnvironmentValue(settings.automaticStopMs) });
|
|
52164
52306
|
}
|
|
52165
|
-
return { environment: resolved, source: "keyring", provider: config3.provider };
|
|
52307
|
+
return { environment: resolved, source: credentials.backend ?? "keyring", provider: config3.provider };
|
|
52166
52308
|
}
|
|
52167
52309
|
var automaticStopGuidance = "How often should a sandbox be automatically stopped?\n\nImportant: a stopped sandbox is automatically resumed by the next coding operation. This is not a limit on total sandbox runtime or spending.\n\nThis is a safety mechanism that limits wasted compute if the agent does not stop a sandbox when finished. Agents are instructed to stop unused sandboxes, but this is not enforced.\n\nA short duration, such as 40m, minimizes wasted compute but may interrupt long-running commands. For long workflows, consider 6h or more. Provider limits apply, so check your plan's maximum execution time.";
|
|
52168
52310
|
async function setup(storage, credentials, prompts, dependencies = {}) {
|
|
@@ -52324,8 +52466,16 @@ async function logout(storage, credentials) {
|
|
|
52324
52466
|
} catch {
|
|
52325
52467
|
throw new OnboardingError("Waterbox logout could not read local configuration or credentials; no changes were made.");
|
|
52326
52468
|
}
|
|
52327
|
-
|
|
52328
|
-
const
|
|
52469
|
+
let deletionFailed = false;
|
|
52470
|
+
for (const provider of Object.keys(prior)) {
|
|
52471
|
+
try {
|
|
52472
|
+
const deleted = await credentials.delete(provider);
|
|
52473
|
+
if (!deleted && prior[provider] !== void 0) deletionFailed = true;
|
|
52474
|
+
} catch {
|
|
52475
|
+
deletionFailed = true;
|
|
52476
|
+
break;
|
|
52477
|
+
}
|
|
52478
|
+
}
|
|
52329
52479
|
if (deletionFailed) {
|
|
52330
52480
|
const restored = await restore(credentials, prior);
|
|
52331
52481
|
throw new OnboardingError(`Waterbox logout could not remove all credentials${restored ? "; rollback was confirmed" : "; rollback could not be confirmed"}.`);
|
|
@@ -52387,12 +52537,17 @@ async function credentialSnapshot(credentials) {
|
|
|
52387
52537
|
return { waterbox: await credentials.get("waterbox") ?? void 0, box: await credentials.get("box") ?? void 0, vercel: await credentials.get("vercel") ?? void 0 };
|
|
52388
52538
|
}
|
|
52389
52539
|
async function restore(credentials, prior, providers = Object.keys(prior), requireDeletionConfirmation = []) {
|
|
52390
|
-
|
|
52391
|
-
|
|
52392
|
-
|
|
52393
|
-
|
|
52394
|
-
|
|
52395
|
-
|
|
52540
|
+
let restored = true;
|
|
52541
|
+
for (const provider of providers) try {
|
|
52542
|
+
if (prior[provider] !== void 0) await credentials.set(provider, prior[provider]);
|
|
52543
|
+
else {
|
|
52544
|
+
const deleted = await credentials.delete(provider);
|
|
52545
|
+
if (!deleted && requireDeletionConfirmation.includes(provider)) throw new Error("credential deletion was not confirmed");
|
|
52546
|
+
}
|
|
52547
|
+
} catch {
|
|
52548
|
+
restored = false;
|
|
52549
|
+
}
|
|
52550
|
+
return restored;
|
|
52396
52551
|
}
|
|
52397
52552
|
async function restoreRawConfig(storage, raw2) {
|
|
52398
52553
|
try {
|
|
@@ -52413,7 +52568,7 @@ var McpConfigurationError = class extends Error {
|
|
|
52413
52568
|
};
|
|
52414
52569
|
async function parseMcpConfig(environment = process.env, homeDirectory, dependencies = {}) {
|
|
52415
52570
|
try {
|
|
52416
|
-
const resolved = await resolvedEnvironment(environment, dependencies.storage ?? configStorage(homeDirectory), dependencies.credentials ??
|
|
52571
|
+
const resolved = await resolvedEnvironment(environment, dependencies.storage ?? configStorage(homeDirectory), dependencies.credentials ?? defaultCredentialStore(homeDirectory));
|
|
52417
52572
|
if (resolved.provider === "waterbox") {
|
|
52418
52573
|
try {
|
|
52419
52574
|
return { provider: { type: "waterbox", apiKey: providerCredential(resolved.environment.WATERBOX_API_KEY) } };
|
|
@@ -57913,8 +58068,8 @@ var Server = class extends Protocol {
|
|
|
57913
58068
|
var instructions = "Waterbox gives agents the ability to create, manage, and command isolated sandboxes.\n\nUse Waterbox when instructed by the user or when additional isolated compute would be useful, such as avoiding pressure on the local machine or running parallel work without workspace conflicts.\n\nWaterbox tools fall into two groups:\n\n- **Daily workflow:** create a sandbox, operate on it, then stop it.\n- **Reusable setup utilities:** list and create snapshots to avoid repeating environment setup.\n\n**Core workflow**\n\n1. Create a sandbox as the execution environment for your work.\n2. Use the filesystem and command tools to work inside the sandbox.\n3. When the task is complete and all material outcomes expected outside the sandbox have been exported or otherwise preserved, stop the sandbox to avoid unnecessary compute costs. Do not stop it merely because a conversational turn has ended while work remains active.\n\nSandbox filesystem state is resumable, but retention is provider-dependent. Neither sandboxes nor snapshots are definitive storage. Export material outcomes when the task is complete.\n\n**Reusable setup pattern**\n\nWhen you detect repeated setup work or dependencies, consider creating a snapshot so future sandboxes can start from a prepared environment. Give snapshots clear names and descriptions, and preserve reusable dependencies, tools, CLIs, and other environment preparation. Keep task-specific work in source control or another definitive external store so snapshots do not seed future work with stale project state.";
|
|
57914
58069
|
|
|
57915
58070
|
// packages/mcp/src/secure-transfer.ts
|
|
57916
|
-
import { constants } from "node:fs";
|
|
57917
|
-
import { open, stat } from "node:fs/promises";
|
|
58071
|
+
import { constants as constants2 } from "node:fs";
|
|
58072
|
+
import { open as open2, stat } from "node:fs/promises";
|
|
57918
58073
|
async function sendFileSecurely(client, input, context) {
|
|
57919
58074
|
context.signal.throwIfAborted();
|
|
57920
58075
|
const plaintext = await readLocalFile(input.sourcePath, context.signal);
|
|
@@ -57927,10 +58082,10 @@ async function sendFileSecurely(client, input, context) {
|
|
|
57927
58082
|
async function readLocalFile(path, signal, overrides = {}) {
|
|
57928
58083
|
signal.throwIfAborted();
|
|
57929
58084
|
const statFile = overrides.stat ?? stat;
|
|
57930
|
-
const openFile = overrides.open ??
|
|
58085
|
+
const openFile = overrides.open ?? open2;
|
|
57931
58086
|
const initial = await statFile(path);
|
|
57932
58087
|
if (!initial.isFile()) throw new Error("Local source must be a regular file");
|
|
57933
|
-
let handle = await openFile(path,
|
|
58088
|
+
let handle = await openFile(path, constants2.O_RDONLY);
|
|
57934
58089
|
let bytes;
|
|
57935
58090
|
let transferred = false;
|
|
57936
58091
|
try {
|
|
@@ -57990,7 +58145,7 @@ var tools = [
|
|
|
57990
58145
|
tool("bash", "Runs unrestricted bash as root in the specified Waterbox sandbox, never on the local machine. The default working directory is the sandbox workspace.", ARGUMENT_SCHEMAS.bash, BashToolResultSchema)
|
|
57991
58146
|
];
|
|
57992
58147
|
function createWaterboxMcpServer(client, options = {}) {
|
|
57993
|
-
const server = new Server({ name: "waterbox", version: "0.1.0-alpha.
|
|
58148
|
+
const server = new Server({ name: "waterbox", version: "0.1.0-alpha.3" }, { capabilities: { tools: {} }, instructions });
|
|
57994
58149
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
57995
58150
|
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
57996
58151
|
try {
|
|
@@ -58139,7 +58294,7 @@ var standardPrompts = {
|
|
|
58139
58294
|
};
|
|
58140
58295
|
async function runCli(arguments_, dependencies = {}) {
|
|
58141
58296
|
const write = dependencies.write ?? ((line) => console.log(line)), error47 = dependencies.error ?? ((line) => console.error(line));
|
|
58142
|
-
const storage = dependencies.storage ?? configStorage(), credentials = dependencies.credentials ??
|
|
58297
|
+
const storage = dependencies.storage ?? configStorage(dependencies.homeDirectory), credentials = dependencies.credentials ?? defaultCredentialStore(dependencies.homeDirectory, dependencies.platform);
|
|
58143
58298
|
if (arguments_.length !== 1 || !["setup", "status", "logout"].includes(arguments_[0] ?? "")) {
|
|
58144
58299
|
error47("Usage: waterbox [setup|status|logout]. Run without arguments to start the MCP server.");
|
|
58145
58300
|
return 2;
|
|
@@ -58165,15 +58320,15 @@ async function runCli(arguments_, dependencies = {}) {
|
|
|
58165
58320
|
}
|
|
58166
58321
|
const state3 = await credentialState(config3.provider, credentials);
|
|
58167
58322
|
if (state3 === "available") await parseMcpConfig(environment, void 0, { storage, credentials });
|
|
58168
|
-
write(`Waterbox status: provider ${config3.provider};
|
|
58323
|
+
write(`Waterbox status: provider ${config3.provider}; configuration file; credential ${credentials.backend ?? "keyring"} ${state3}.${state3 === "available" ? "" : ` Environment fallback: WATERBOX_PROVIDER=${config3.provider} and ${credentialVariable(config3.provider)}.`}`);
|
|
58169
58324
|
if (state3 !== "available") return 1;
|
|
58170
58325
|
return 0;
|
|
58171
58326
|
}
|
|
58172
|
-
const parsed = await parseMcpConfig(environment,
|
|
58327
|
+
const parsed = await parseMcpConfig(environment, dependencies.homeDirectory, { storage, credentials });
|
|
58173
58328
|
const provider = parsed.provider.type === "waterbox" ? "waterbox" : parsed.provider.configuration.provider.kind;
|
|
58174
58329
|
const source = environment.WATERBOX_PROVIDER === void 0 ? "keyring" : "environment";
|
|
58175
58330
|
const state2 = source === "keyring" ? await credentialState(provider, credentials) : "available";
|
|
58176
|
-
write(`Waterbox status: provider ${provider}; configuration ${source}; credential ${state2}.`);
|
|
58331
|
+
write(`Waterbox status: provider ${provider}; configuration ${source}; credential ${source === "environment" ? "environment" : credentials.backend ?? "keyring"} ${state2}.`);
|
|
58177
58332
|
return 0;
|
|
58178
58333
|
} catch (caught) {
|
|
58179
58334
|
error47(caught instanceof OnboardingError || caught instanceof McpConfigurationError ? caught.message : "Waterbox command failed");
|