deepspace 0.5.5 → 0.5.6
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/dist/cli.js +719 -318
- package/dist/cli.js.map +1 -1
- package/features/admin-page/feature.json +3 -1
- package/features/file-attachments/feature.json +3 -1
- package/features/messaging/feature.json +1 -1
- package/features/search-bar/feature.json +6 -5
- package/package.json +1 -1
- package/scripts/add-feature.cjs +174 -36
- package/dist/testing.d.ts +0 -115
package/dist/cli.js
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/cli.ts
|
|
4
4
|
import { defineCommand as defineCommand22, runMain } from "citty";
|
|
5
|
-
import {
|
|
6
|
-
import { readFileSync as
|
|
7
|
-
import { dirname as
|
|
8
|
-
import { fileURLToPath as
|
|
5
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
6
|
+
import { readFileSync as readFileSync17, existsSync as existsSync14 } from "fs";
|
|
7
|
+
import { dirname as dirname5, join as join15 } from "path";
|
|
8
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9
9
|
|
|
10
10
|
// src/cli/lib/cli-errors.ts
|
|
11
11
|
var API_ERROR_HINTS = {
|
|
12
12
|
not_app_owner: "Only the app owner can do this.",
|
|
13
|
-
app_not_found: "App not found. Check the app
|
|
13
|
+
app_not_found: "App not found. Check the app id \u2014 the DEEPSPACE_APP_ID value in wrangler.toml, usually `app_\u2026` (a legacy app's id is its name). List your apps with `deepspace apps`. (`domain` commands take the deployed app *name* instead.)",
|
|
14
14
|
not_app_owner_or_collaborator: "You must be the app owner or a collaborator to do this.",
|
|
15
15
|
test_account_cannot_be_collaborator: "Test accounts cannot be added as collaborators. Use a real DeepSpace account.",
|
|
16
16
|
user_not_found: "No DeepSpace user with that email. They need to log in to DeepSpace at least once (`deepspace login`, or sign in to any app) before they can be referenced by email."
|
|
@@ -25,8 +25,11 @@ ${hint}` : message;
|
|
|
25
25
|
}
|
|
26
26
|
function renderCliError(err) {
|
|
27
27
|
console.error(formatCliError(err));
|
|
28
|
-
if (process.env.DEBUG
|
|
29
|
-
|
|
28
|
+
if (process.env.DEBUG) {
|
|
29
|
+
const { apiPath, status: status3 } = err;
|
|
30
|
+
if (apiPath) console.error(`
|
|
31
|
+
API ${apiPath}${status3 ? ` (${status3})` : ""}`);
|
|
32
|
+
if (err instanceof Error && err.stack) console.error("\n" + err.stack);
|
|
30
33
|
}
|
|
31
34
|
process.exit(1);
|
|
32
35
|
}
|
|
@@ -51,7 +54,7 @@ function wrapCommandErrors(cmd) {
|
|
|
51
54
|
|
|
52
55
|
// src/cli/commands/login.ts
|
|
53
56
|
import { defineCommand } from "citty";
|
|
54
|
-
import { writeFileSync as writeFileSync5, mkdirSync } from "fs";
|
|
57
|
+
import { writeFileSync as writeFileSync5, mkdirSync, readFileSync as readFileSync4 } from "fs";
|
|
55
58
|
import { join as join3 } from "path";
|
|
56
59
|
import { homedir } from "os";
|
|
57
60
|
import { randomBytes, createHash } from "crypto";
|
|
@@ -437,23 +440,56 @@ function parseSecretsUpload(content) {
|
|
|
437
440
|
return out2;
|
|
438
441
|
}
|
|
439
442
|
const out = {};
|
|
440
|
-
|
|
441
|
-
|
|
443
|
+
const lines = trimmed.split(/\r?\n/);
|
|
444
|
+
for (let i = 0; i < lines.length; i++) {
|
|
445
|
+
const line = lines[i].trim();
|
|
442
446
|
if (!line || line.startsWith("#")) continue;
|
|
443
447
|
const eq = line.indexOf("=");
|
|
444
448
|
if (eq <= 0) continue;
|
|
445
449
|
const key = line.slice(0, eq).trim();
|
|
446
450
|
if (!SECRET_NAME_RE.test(key)) continue;
|
|
447
451
|
validateSecretName(key);
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
452
|
+
const raw = line.slice(eq + 1).trim();
|
|
453
|
+
const quote = raw[0] === '"' || raw[0] === "'" ? raw[0] : null;
|
|
454
|
+
let value;
|
|
455
|
+
if (!quote) {
|
|
456
|
+
value = raw;
|
|
457
|
+
} else if (endsWithUnescapedQuote(raw.slice(1), quote)) {
|
|
458
|
+
const inner = raw.slice(1, -1);
|
|
459
|
+
value = quote === '"' ? unescapeDotenv(inner) : inner;
|
|
460
|
+
} else {
|
|
461
|
+
const startLine = i + 1;
|
|
462
|
+
const parts = [raw.slice(1)];
|
|
463
|
+
let closed = false;
|
|
464
|
+
while (++i < lines.length) {
|
|
465
|
+
const cont = lines[i].trimEnd();
|
|
466
|
+
if (endsWithUnescapedQuote(cont, quote)) {
|
|
467
|
+
parts.push(cont.slice(0, -1));
|
|
468
|
+
closed = true;
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
parts.push(lines[i]);
|
|
472
|
+
}
|
|
473
|
+
if (!closed) {
|
|
474
|
+
throw new Error(
|
|
475
|
+
`Unterminated quoted value for "${key}" (opens on line ${startLine}). Close the ${quote === '"' ? "double" : "single"} quote, or escape newlines as \\n on one line.`
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
value = parts.join("\n");
|
|
479
|
+
if (quote === '"') value = unescapeDotenv(value);
|
|
451
480
|
}
|
|
452
481
|
validateSecretValue(key, value);
|
|
453
482
|
out[key] = value;
|
|
454
483
|
}
|
|
455
484
|
return out;
|
|
456
485
|
}
|
|
486
|
+
function endsWithUnescapedQuote(s, q) {
|
|
487
|
+
if (!s.endsWith(q)) return false;
|
|
488
|
+
if (q === "'") return true;
|
|
489
|
+
let backslashes = 0;
|
|
490
|
+
for (let j = s.length - 2; j >= 0 && s[j] === "\\"; j--) backslashes++;
|
|
491
|
+
return backslashes % 2 === 0;
|
|
492
|
+
}
|
|
457
493
|
function unescapeDotenv(v) {
|
|
458
494
|
let out = "";
|
|
459
495
|
for (let i = 0; i < v.length; i++) {
|
|
@@ -1072,19 +1108,38 @@ var login_default = defineCommand({
|
|
|
1072
1108
|
args: {
|
|
1073
1109
|
email: {
|
|
1074
1110
|
type: "string",
|
|
1075
|
-
description: "Email address (non-interactive mode)",
|
|
1111
|
+
description: "Email address (non-interactive mode; or $DEEPSPACE_EMAIL)",
|
|
1076
1112
|
required: false
|
|
1077
1113
|
},
|
|
1078
1114
|
password: {
|
|
1079
1115
|
type: "string",
|
|
1080
|
-
description: "Password (
|
|
1116
|
+
description: "Password (discouraged \u2014 visible in ps/history; prefer --password-stdin or $DEEPSPACE_PASSWORD)",
|
|
1081
1117
|
required: false
|
|
1118
|
+
},
|
|
1119
|
+
"password-stdin": {
|
|
1120
|
+
type: "boolean",
|
|
1121
|
+
description: "Read the password from stdin instead of --password",
|
|
1122
|
+
default: false
|
|
1082
1123
|
}
|
|
1083
1124
|
},
|
|
1084
1125
|
async run({ args }) {
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1126
|
+
const interactive = Boolean(process.stdin.isTTY);
|
|
1127
|
+
const { email, password } = resolveLoginCredentials({
|
|
1128
|
+
emailArg: args.email,
|
|
1129
|
+
passwordArg: args.password,
|
|
1130
|
+
envEmail: interactive ? void 0 : process.env.DEEPSPACE_EMAIL,
|
|
1131
|
+
envPassword: interactive ? void 0 : process.env.DEEPSPACE_PASSWORD,
|
|
1132
|
+
passwordStdin: args["password-stdin"] ? readPasswordFromStdin() : void 0
|
|
1133
|
+
});
|
|
1134
|
+
const passwordIntent = Boolean(args["password-stdin"]) || args.password !== void 0 || password !== void 0;
|
|
1135
|
+
const decision = loginModeDecision({ email, password, passwordIntent });
|
|
1136
|
+
if (decision.mode === "error") {
|
|
1137
|
+
console.error(decision.message);
|
|
1138
|
+
process.exit(1);
|
|
1139
|
+
}
|
|
1140
|
+
if (decision.mode === "password") {
|
|
1141
|
+
console.log(`Signing in as ${email}...`);
|
|
1142
|
+
await doEmailLogin(email, password);
|
|
1088
1143
|
console.log("Logged in");
|
|
1089
1144
|
return;
|
|
1090
1145
|
}
|
|
@@ -1135,6 +1190,34 @@ plans on the web dashboard:
|
|
|
1135
1190
|
p2.outro("Done");
|
|
1136
1191
|
}
|
|
1137
1192
|
});
|
|
1193
|
+
function resolveLoginCredentials(opts) {
|
|
1194
|
+
const email = opts.emailArg || opts.envEmail || void 0;
|
|
1195
|
+
const password = opts.passwordStdin !== void 0 ? opts.passwordStdin : opts.passwordArg || opts.envPassword || void 0;
|
|
1196
|
+
return { email, password };
|
|
1197
|
+
}
|
|
1198
|
+
function loginModeDecision(opts) {
|
|
1199
|
+
if (opts.email && opts.password) return { mode: "password" };
|
|
1200
|
+
if (!opts.passwordIntent) return { mode: "oauth" };
|
|
1201
|
+
if (!opts.email) {
|
|
1202
|
+
return {
|
|
1203
|
+
mode: "error",
|
|
1204
|
+
message: "Non-interactive login needs an email: --email <you@example.com> (or $DEEPSPACE_EMAIL)."
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
return {
|
|
1208
|
+
mode: "error",
|
|
1209
|
+
message: "Non-interactive login needs a non-empty password: --password-stdin, $DEEPSPACE_PASSWORD, or --password."
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
function readPasswordFromStdin() {
|
|
1213
|
+
if (process.stdin.isTTY) {
|
|
1214
|
+
console.error(
|
|
1215
|
+
'--password-stdin expects the password piped on stdin, e.g. `printf %s "$PW" | deepspace login --email you@x.com --password-stdin`.'
|
|
1216
|
+
);
|
|
1217
|
+
process.exit(1);
|
|
1218
|
+
}
|
|
1219
|
+
return readFileSync4(0, "utf-8").replace(/\r?\n$/, "");
|
|
1220
|
+
}
|
|
1138
1221
|
async function pollForCompletion(sessionId, codeVerifier) {
|
|
1139
1222
|
const maxAttempts = 120;
|
|
1140
1223
|
const interval = 5e3;
|
|
@@ -1205,7 +1288,7 @@ async function doEmailLogin(email, password) {
|
|
|
1205
1288
|
|
|
1206
1289
|
// src/cli/commands/logout.ts
|
|
1207
1290
|
import { defineCommand as defineCommand2 } from "citty";
|
|
1208
|
-
import { existsSync as existsSync4, readFileSync as
|
|
1291
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, rmSync as rmSync2 } from "fs";
|
|
1209
1292
|
import { join as join4 } from "path";
|
|
1210
1293
|
import { homedir as homedir2 } from "os";
|
|
1211
1294
|
var AUTH_URL2 = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
|
|
@@ -1218,7 +1301,7 @@ var logout_default = defineCommand2({
|
|
|
1218
1301
|
description: "Sign out and remove cached credentials"
|
|
1219
1302
|
},
|
|
1220
1303
|
async run() {
|
|
1221
|
-
const sessionToken = existsSync4(SESSION_PATH) ?
|
|
1304
|
+
const sessionToken = existsSync4(SESSION_PATH) ? readFileSync5(SESSION_PATH, "utf-8").trim() : null;
|
|
1222
1305
|
if (sessionToken) {
|
|
1223
1306
|
try {
|
|
1224
1307
|
await fetch(`${AUTH_URL2}/api/auth/sign-out`, {
|
|
@@ -1248,11 +1331,11 @@ var logout_default = defineCommand2({
|
|
|
1248
1331
|
|
|
1249
1332
|
// src/cli/commands/dev.ts
|
|
1250
1333
|
import { defineCommand as defineCommand3 } from "citty";
|
|
1251
|
-
import { resolve as resolve4, basename, join as join9 } from "path";
|
|
1334
|
+
import { resolve as resolve4, basename as basename2, join as join9 } from "path";
|
|
1252
1335
|
import spawn from "cross-spawn";
|
|
1253
1336
|
|
|
1254
1337
|
// src/cli/auth.ts
|
|
1255
|
-
import { readFileSync as
|
|
1338
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
1256
1339
|
import { join as join5 } from "path";
|
|
1257
1340
|
import { homedir as homedir3 } from "os";
|
|
1258
1341
|
|
|
@@ -1272,7 +1355,7 @@ var SESSION_PATH2 = join5(DIR2, "session");
|
|
|
1272
1355
|
var TOKEN_PATH2 = join5(DIR2, "token");
|
|
1273
1356
|
async function ensureToken() {
|
|
1274
1357
|
if (existsSync5(TOKEN_PATH2)) {
|
|
1275
|
-
const existing =
|
|
1358
|
+
const existing = readFileSync6(TOKEN_PATH2, "utf-8").trim();
|
|
1276
1359
|
if (isTokenValid(existing)) {
|
|
1277
1360
|
return existing;
|
|
1278
1361
|
}
|
|
@@ -1280,7 +1363,7 @@ async function ensureToken() {
|
|
|
1280
1363
|
if (!existsSync5(SESSION_PATH2)) {
|
|
1281
1364
|
throw new Error("Not logged in. Run `deepspace login` first.");
|
|
1282
1365
|
}
|
|
1283
|
-
const sessionToken =
|
|
1366
|
+
const sessionToken = readFileSync6(SESSION_PATH2, "utf-8").trim();
|
|
1284
1367
|
const token = await exchangeSession(AUTH_URL3, sessionToken);
|
|
1285
1368
|
if (!token) {
|
|
1286
1369
|
throw new Error("Session expired. Run `deepspace login` to re-authenticate.");
|
|
@@ -1301,20 +1384,56 @@ function isTokenValid(jwt) {
|
|
|
1301
1384
|
// src/cli/lib/app-context.ts
|
|
1302
1385
|
import {
|
|
1303
1386
|
existsSync as existsSync6,
|
|
1304
|
-
readFileSync as
|
|
1387
|
+
readFileSync as readFileSync7,
|
|
1305
1388
|
readdirSync,
|
|
1306
1389
|
writeFileSync as writeFileSync7,
|
|
1307
1390
|
mkdirSync as mkdirSync3,
|
|
1308
1391
|
renameSync,
|
|
1309
1392
|
unlinkSync
|
|
1310
1393
|
} from "fs";
|
|
1311
|
-
import { join as join6, resolve as resolve2, dirname, isAbsolute, sep } from "path";
|
|
1394
|
+
import { join as join6, resolve as resolve2, dirname, basename, isAbsolute, sep } from "path";
|
|
1312
1395
|
import { parse as parseToml3 } from "smol-toml";
|
|
1396
|
+
|
|
1397
|
+
// src/cli/lib/api.ts
|
|
1398
|
+
var ApiError = class extends Error {
|
|
1399
|
+
constructor(message, status3, code, apiPath) {
|
|
1400
|
+
super(message);
|
|
1401
|
+
this.status = status3;
|
|
1402
|
+
this.code = code;
|
|
1403
|
+
this.apiPath = apiPath;
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
async function apiFetch(baseUrl, token, path, init) {
|
|
1407
|
+
const res = await fetch(`${baseUrl}${path}`, {
|
|
1408
|
+
...init,
|
|
1409
|
+
headers: {
|
|
1410
|
+
Authorization: `Bearer ${token}`,
|
|
1411
|
+
"Content-Type": "application/json",
|
|
1412
|
+
...init?.headers ?? {}
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
const text2 = await res.text();
|
|
1416
|
+
if (!res.ok) {
|
|
1417
|
+
let msg = text2;
|
|
1418
|
+
let code;
|
|
1419
|
+
try {
|
|
1420
|
+
const body = JSON.parse(text2);
|
|
1421
|
+
msg = body.error ?? text2;
|
|
1422
|
+
code = body.code;
|
|
1423
|
+
} catch {
|
|
1424
|
+
}
|
|
1425
|
+
throw new ApiError(msg || `Request failed (${res.status})`, res.status, code, path);
|
|
1426
|
+
}
|
|
1427
|
+
return text2 ? JSON.parse(text2) : {};
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
// src/cli/lib/app-context.ts
|
|
1431
|
+
var STRICT_APP_ID_RE = /^app_[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
1313
1432
|
function detectAppName(cwd = process.cwd()) {
|
|
1314
1433
|
const wranglerPath = join6(resolve2(cwd), "wrangler.toml");
|
|
1315
1434
|
if (!existsSync6(wranglerPath)) return null;
|
|
1316
1435
|
try {
|
|
1317
|
-
const cfg = parseToml3(
|
|
1436
|
+
const cfg = parseToml3(readFileSync7(wranglerPath, "utf-8"));
|
|
1318
1437
|
return typeof cfg.name === "string" && cfg.name.length > 0 ? cfg.name : null;
|
|
1319
1438
|
} catch (err) {
|
|
1320
1439
|
throw new Error(
|
|
@@ -1363,18 +1482,42 @@ function writeLaunchFile(launchPath, config) {
|
|
|
1363
1482
|
function readLaunchFile(launchPath) {
|
|
1364
1483
|
const empty = { version: "0.0.1", configurations: [] };
|
|
1365
1484
|
if (!existsSync6(launchPath)) return empty;
|
|
1366
|
-
const raw =
|
|
1485
|
+
const raw = readFileSync7(launchPath, "utf-8").trim();
|
|
1367
1486
|
if (!raw) return empty;
|
|
1368
1487
|
const parsed = JSON.parse(raw);
|
|
1369
1488
|
if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.configurations)) return null;
|
|
1370
1489
|
return parsed;
|
|
1371
1490
|
}
|
|
1372
|
-
function writeLaunchConfigIfMissing(appDir, appName, port) {
|
|
1491
|
+
function writeLaunchConfigIfMissing(appDir, appName, port, opts = {}) {
|
|
1373
1492
|
const launchPath = join6(appDir, ".claude", "launch.json");
|
|
1374
1493
|
try {
|
|
1375
1494
|
const config = readLaunchFile(launchPath);
|
|
1376
1495
|
if (!config) return;
|
|
1377
|
-
|
|
1496
|
+
const existing = config.configurations.find((c) => c?.name === appName);
|
|
1497
|
+
if (existing) {
|
|
1498
|
+
if (!opts.updatePort) return;
|
|
1499
|
+
let changed = false;
|
|
1500
|
+
if (Number(existing.port) !== port) {
|
|
1501
|
+
existing.port = port;
|
|
1502
|
+
changed = true;
|
|
1503
|
+
}
|
|
1504
|
+
if (Array.isArray(existing.runtimeArgs)) {
|
|
1505
|
+
const ra = existing.runtimeArgs.map(String);
|
|
1506
|
+
const pi = ra.indexOf("--port");
|
|
1507
|
+
if (pi >= 0 && pi + 1 < ra.length) {
|
|
1508
|
+
if (ra[pi + 1] !== String(port)) {
|
|
1509
|
+
ra[pi + 1] = String(port);
|
|
1510
|
+
changed = true;
|
|
1511
|
+
}
|
|
1512
|
+
} else {
|
|
1513
|
+
ra.push("--port", String(port));
|
|
1514
|
+
changed = true;
|
|
1515
|
+
}
|
|
1516
|
+
if (changed) existing.runtimeArgs = ra;
|
|
1517
|
+
}
|
|
1518
|
+
if (changed) writeLaunchFile(launchPath, config);
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1378
1521
|
config.configurations.push({
|
|
1379
1522
|
name: appName,
|
|
1380
1523
|
runtimeExecutable: "npx",
|
|
@@ -1385,6 +1528,18 @@ function writeLaunchConfigIfMissing(appDir, appName, port) {
|
|
|
1385
1528
|
} catch {
|
|
1386
1529
|
}
|
|
1387
1530
|
}
|
|
1531
|
+
function resolveAppLaunchPort(appDir) {
|
|
1532
|
+
try {
|
|
1533
|
+
const config = readLaunchFile(join6(appDir, ".claude", "launch.json"));
|
|
1534
|
+
if (!config) return null;
|
|
1535
|
+
const appName = detectAppName(appDir) ?? basename(appDir);
|
|
1536
|
+
const entry = config.configurations.find((c) => c?.name === appName) ?? (config.configurations.length === 1 ? config.configurations[0] : void 0);
|
|
1537
|
+
const port = Number(entry?.port);
|
|
1538
|
+
return Number.isInteger(port) && port > 0 ? port : null;
|
|
1539
|
+
} catch {
|
|
1540
|
+
return null;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1388
1543
|
function detectClaudeWorktree(appDir) {
|
|
1389
1544
|
const segments = resolve2(appDir).split(sep);
|
|
1390
1545
|
for (let i = segments.length - 3; i >= 1; i--) {
|
|
@@ -1420,7 +1575,7 @@ function upsertWorktreeLaunchConfig(mainRepoRoot, worktreeName, appDir, opts) {
|
|
|
1420
1575
|
let port = opts.port;
|
|
1421
1576
|
if (opts.probePort) {
|
|
1422
1577
|
const taken = new Set(
|
|
1423
|
-
config.configurations.map((c) => Number(c?.port)).filter((
|
|
1578
|
+
config.configurations.map((c) => Number(c?.port)).filter((p10) => Number.isInteger(p10) && p10 > 0)
|
|
1424
1579
|
);
|
|
1425
1580
|
for (let i = 0; i < WORKTREE_PORT_RANGE && taken.has(port); i++) {
|
|
1426
1581
|
port = WORKTREE_PORT_MIN + (port - WORKTREE_PORT_MIN + 1) % WORKTREE_PORT_RANGE;
|
|
@@ -1473,9 +1628,36 @@ function requireAppIdArg(explicit) {
|
|
|
1473
1628
|
}
|
|
1474
1629
|
return id;
|
|
1475
1630
|
}
|
|
1631
|
+
function matchAppSelector(apps, selector) {
|
|
1632
|
+
const byId = apps.find((a) => a.appId === selector);
|
|
1633
|
+
if (byId) return byId.appId;
|
|
1634
|
+
const byName = apps.find((a) => a.name === selector);
|
|
1635
|
+
if (byName) return byName.appId;
|
|
1636
|
+
return STRICT_APP_ID_RE.test(selector) ? selector : null;
|
|
1637
|
+
}
|
|
1638
|
+
async function resolveAppSelector(deployUrl, token, selector) {
|
|
1639
|
+
if (STRICT_APP_ID_RE.test(selector)) return selector;
|
|
1640
|
+
const { apps } = await apiFetch(deployUrl, token, "/api/apps");
|
|
1641
|
+
const id = matchAppSelector(apps, selector);
|
|
1642
|
+
if (!id) {
|
|
1643
|
+
throw new Error(`No app "${selector}" in your account. Run \`deepspace apps\` to list your apps.`);
|
|
1644
|
+
}
|
|
1645
|
+
return id;
|
|
1646
|
+
}
|
|
1647
|
+
async function resolveAppTarget(deployUrl, token, explicit) {
|
|
1648
|
+
if (explicit) return resolveAppSelector(deployUrl, token, explicit);
|
|
1649
|
+
const appDir = findAppDir();
|
|
1650
|
+
const id = appDir ? readAppId(appDir) : null;
|
|
1651
|
+
if (!id) {
|
|
1652
|
+
throw new Error(
|
|
1653
|
+
"No app id. Run from an app directory whose wrangler.toml carries DEEPSPACE_APP_ID, or pass --app <id or name>."
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
return id;
|
|
1657
|
+
}
|
|
1476
1658
|
|
|
1477
1659
|
// src/cli/lib/install-status.ts
|
|
1478
|
-
import { existsSync as existsSync7, readFileSync as
|
|
1660
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
|
|
1479
1661
|
import { join as join7 } from "path";
|
|
1480
1662
|
function ensureInstallReady(appDir) {
|
|
1481
1663
|
if (existsSync7(join7(appDir, "node_modules", "deepspace", "package.json"))) return;
|
|
@@ -1486,13 +1668,19 @@ function ensureInstallReady(appDir) {
|
|
|
1486
1668
|
const logPath = join7(sentinelDir, "install.log");
|
|
1487
1669
|
if (existsSync7(errPath)) {
|
|
1488
1670
|
console.error("Background install failed:");
|
|
1489
|
-
console.error(
|
|
1671
|
+
console.error(readFileSync8(errPath, "utf-8").trimEnd());
|
|
1490
1672
|
if (existsSync7(logPath)) console.error(`
|
|
1491
1673
|
Full log: ${logPath}`);
|
|
1492
1674
|
console.error("\nRun `npm install` (or `bun install`) manually, then retry.");
|
|
1493
1675
|
process.exit(1);
|
|
1494
1676
|
}
|
|
1495
1677
|
if (existsSync7(startedPath) && !existsSync7(donePath)) {
|
|
1678
|
+
if (!installWorkerAlive(sentinelDir)) {
|
|
1679
|
+
console.error("The background install is no longer running and never finished.");
|
|
1680
|
+
if (existsSync7(logPath)) console.error(`See what happened: ${logPath}`);
|
|
1681
|
+
console.error("Run `npm install` (or `bun install`) manually, then retry.");
|
|
1682
|
+
process.exit(1);
|
|
1683
|
+
}
|
|
1496
1684
|
console.error("Dependencies are still installing in the background.");
|
|
1497
1685
|
if (existsSync7(logPath)) console.error(`Tail progress: tail -f ${logPath}`);
|
|
1498
1686
|
console.error("Retry once it finishes.");
|
|
@@ -1501,6 +1689,18 @@ Full log: ${logPath}`);
|
|
|
1501
1689
|
console.error("Dependencies not installed. Run `npm install` (or `bun install`) first.");
|
|
1502
1690
|
process.exit(1);
|
|
1503
1691
|
}
|
|
1692
|
+
function installWorkerAlive(sentinelDir) {
|
|
1693
|
+
const pidPath = join7(sentinelDir, "install.pid");
|
|
1694
|
+
if (!existsSync7(pidPath)) return true;
|
|
1695
|
+
const pid = Number.parseInt(readFileSync8(pidPath, "utf-8").trim(), 10);
|
|
1696
|
+
if (!Number.isFinite(pid) || pid <= 0) return true;
|
|
1697
|
+
try {
|
|
1698
|
+
process.kill(pid, 0);
|
|
1699
|
+
return true;
|
|
1700
|
+
} catch (err) {
|
|
1701
|
+
return err.code === "EPERM";
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1504
1704
|
|
|
1505
1705
|
// src/cli/lib/preflight.ts
|
|
1506
1706
|
import { execFileSync } from "child_process";
|
|
@@ -1578,7 +1778,16 @@ function removeMacosJunk(dir) {
|
|
|
1578
1778
|
}
|
|
1579
1779
|
|
|
1580
1780
|
// src/cli/lib/port.ts
|
|
1781
|
+
import { createServer } from "net";
|
|
1581
1782
|
var DEFAULT_PORT = 5173;
|
|
1783
|
+
function checkPortAvailable(port, host = "0.0.0.0") {
|
|
1784
|
+
return new Promise((resolve10) => {
|
|
1785
|
+
const srv = createServer();
|
|
1786
|
+
srv.once("error", () => resolve10(false));
|
|
1787
|
+
srv.once("listening", () => srv.close(() => resolve10(true)));
|
|
1788
|
+
srv.listen(port, host);
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1582
1791
|
function resolvePort(arg) {
|
|
1583
1792
|
const raw = arg ?? process.env.DEEPSPACE_PORT;
|
|
1584
1793
|
if (!raw) return DEFAULT_PORT;
|
|
@@ -1605,6 +1814,7 @@ var dev_default = defineCommand3({
|
|
|
1605
1814
|
},
|
|
1606
1815
|
env: {
|
|
1607
1816
|
type: "string",
|
|
1817
|
+
alias: "e",
|
|
1608
1818
|
description: "wrangler.toml [env.<name>] block to run (e.g. --env staging). Applies the env's overrides at build time.",
|
|
1609
1819
|
required: false
|
|
1610
1820
|
},
|
|
@@ -1662,7 +1872,9 @@ var dev_default = defineCommand3({
|
|
|
1662
1872
|
);
|
|
1663
1873
|
}
|
|
1664
1874
|
}
|
|
1665
|
-
writeLaunchConfigIfMissing(appDir, detectAppName(appDir) ??
|
|
1875
|
+
writeLaunchConfigIfMissing(appDir, detectAppName(appDir) ?? basename2(appDir), port, {
|
|
1876
|
+
updatePort: explicitPort
|
|
1877
|
+
});
|
|
1666
1878
|
ensureInstallReady(appDir);
|
|
1667
1879
|
let token;
|
|
1668
1880
|
try {
|
|
@@ -1710,6 +1922,12 @@ var dev_default = defineCommand3({
|
|
|
1710
1922
|
process.exit(1);
|
|
1711
1923
|
}
|
|
1712
1924
|
preflightWindowsWorkerd(appDir);
|
|
1925
|
+
if (!await checkPortAvailable(port)) {
|
|
1926
|
+
console.error(`Port ${port} is already in use.`);
|
|
1927
|
+
const killCmd = port === DEFAULT_PORT ? "deepspace kill" : `deepspace kill --port ${port}`;
|
|
1928
|
+
console.error(`Free it with \`${killCmd}\`, or start on another port: \`deepspace dev --port <other>\`.`);
|
|
1929
|
+
process.exit(1);
|
|
1930
|
+
}
|
|
1713
1931
|
console.log("Starting dev server...\n");
|
|
1714
1932
|
const vite = spawn("npx", ["vite", "--port", String(port), "--strictPort", "--host"], {
|
|
1715
1933
|
cwd: appDir,
|
|
@@ -1732,10 +1950,16 @@ var dev_default = defineCommand3({
|
|
|
1732
1950
|
// src/cli/commands/kill.ts
|
|
1733
1951
|
import { defineCommand as defineCommand4 } from "citty";
|
|
1734
1952
|
import { spawnSync } from "child_process";
|
|
1735
|
-
import { readFileSync as
|
|
1953
|
+
import { readFileSync as readFileSync9, readdirSync as readdirSync3, readlinkSync } from "fs";
|
|
1736
1954
|
import { setTimeout as wait } from "timers/promises";
|
|
1737
1955
|
var SIGTERM_GRACE_MS = 1500;
|
|
1738
1956
|
var IS_WIN = process.platform === "win32";
|
|
1957
|
+
function pickKillPort(opts) {
|
|
1958
|
+
if (opts.explicit != null) return opts.explicit;
|
|
1959
|
+
if (opts.worktree != null) return opts.worktree;
|
|
1960
|
+
if (opts.env != null) return opts.env;
|
|
1961
|
+
return opts.appLaunch ?? DEFAULT_PORT;
|
|
1962
|
+
}
|
|
1739
1963
|
var kill_default = defineCommand4({
|
|
1740
1964
|
meta: {
|
|
1741
1965
|
name: "kill",
|
|
@@ -1754,21 +1978,38 @@ var kill_default = defineCommand4({
|
|
|
1754
1978
|
}
|
|
1755
1979
|
},
|
|
1756
1980
|
async run({ args }) {
|
|
1757
|
-
const
|
|
1981
|
+
const cwd = process.cwd();
|
|
1982
|
+
const port = pickKillPort({
|
|
1983
|
+
explicit: args.port ? resolvePort(args.port) : null,
|
|
1984
|
+
worktree: resolveWorktreePort(cwd),
|
|
1985
|
+
// resolvePort() reads + validates $DEEPSPACE_PORT; only consult it when set.
|
|
1986
|
+
env: process.env.DEEPSPACE_PORT ? resolvePort() : null,
|
|
1987
|
+
appLaunch: resolveAppLaunchPort(findAppDir(cwd) ?? cwd)
|
|
1988
|
+
});
|
|
1758
1989
|
const targets = /* @__PURE__ */ new Set();
|
|
1759
|
-
|
|
1990
|
+
const listeners = enumerateListeners(port);
|
|
1991
|
+
for (const pid of listeners.pids) targets.add(pid);
|
|
1760
1992
|
for (const pid of [...targets]) {
|
|
1761
1993
|
for (const child of childPids(pid)) targets.add(child);
|
|
1762
1994
|
}
|
|
1995
|
+
let swept = false;
|
|
1763
1996
|
if (args.all) {
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1997
|
+
const sweep = sweepByName(["workerd", "wrangler", "vite"]);
|
|
1998
|
+
swept = sweep.swept;
|
|
1999
|
+
for (const pid of sweep.pids) targets.add(pid);
|
|
1767
2000
|
}
|
|
1768
2001
|
if (targets.size === 0) {
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
2002
|
+
const outcome = noTargetsMessage({
|
|
2003
|
+
enumerated: listeners.enumerated,
|
|
2004
|
+
swept,
|
|
2005
|
+
all: args.all,
|
|
2006
|
+
port
|
|
2007
|
+
});
|
|
2008
|
+
if (!outcome.ok) {
|
|
2009
|
+
console.error(outcome.message);
|
|
2010
|
+
process.exit(1);
|
|
2011
|
+
}
|
|
2012
|
+
console.log(outcome.message);
|
|
1772
2013
|
return;
|
|
1773
2014
|
}
|
|
1774
2015
|
for (const pid of targets) {
|
|
@@ -1794,37 +2035,74 @@ var kill_default = defineCommand4({
|
|
|
1794
2035
|
);
|
|
1795
2036
|
process.exit(1);
|
|
1796
2037
|
}
|
|
1797
|
-
|
|
2038
|
+
if (args.all) {
|
|
2039
|
+
console.log(`Killed ${targets.size} process(es) (workerd/wrangler/vite sweep). :${port} is free.`);
|
|
2040
|
+
} else {
|
|
2041
|
+
console.log(`Port ${port} is free.`);
|
|
2042
|
+
}
|
|
1798
2043
|
}
|
|
1799
2044
|
});
|
|
1800
|
-
function
|
|
2045
|
+
function noTargetsMessage(opts) {
|
|
2046
|
+
const { enumerated, swept, all, port } = opts;
|
|
2047
|
+
const couldObserve = enumerated || all && swept;
|
|
2048
|
+
if (!couldObserve) {
|
|
2049
|
+
return {
|
|
2050
|
+
ok: false,
|
|
2051
|
+
message: `Couldn't determine what's running on :${port}: no lsof/pgrep and /proc is unavailable, so nothing was inspected or killed. Install lsof (or procps for pgrep), or find and kill the process manually.`
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
return {
|
|
2055
|
+
ok: true,
|
|
2056
|
+
message: all ? `Nothing listening on :${port} and no stray workerd/wrangler/vite processes found.` : `Nothing listening on :${port}. (Pass --all to sweep stray workerd/wrangler.)`
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
function enumerateListeners(port) {
|
|
1801
2060
|
if (IS_WIN) {
|
|
1802
|
-
|
|
2061
|
+
const r = runPowershellChecked(
|
|
1803
2062
|
`Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess`
|
|
1804
2063
|
);
|
|
2064
|
+
return { pids: r.pids, enumerated: r.ran };
|
|
2065
|
+
}
|
|
2066
|
+
const lsof = runLsof(port);
|
|
2067
|
+
if (lsof.ran) return { pids: lsof.pids, enumerated: true };
|
|
2068
|
+
const proc = listenerPidsViaProc(port);
|
|
2069
|
+
return { pids: proc.pids, enumerated: proc.available };
|
|
2070
|
+
}
|
|
2071
|
+
function listenerPids(port) {
|
|
2072
|
+
return enumerateListeners(port).pids;
|
|
2073
|
+
}
|
|
2074
|
+
function runLsof(port) {
|
|
2075
|
+
try {
|
|
2076
|
+
const r = spawnSync("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"], {
|
|
2077
|
+
encoding: "utf-8"
|
|
2078
|
+
});
|
|
2079
|
+
if (r.error) return { pids: [], ran: false };
|
|
2080
|
+
return { pids: r.status === 0 ? parsePidLines(r.stdout) : [], ran: true };
|
|
2081
|
+
} catch {
|
|
2082
|
+
return { pids: [], ran: false };
|
|
1805
2083
|
}
|
|
1806
|
-
const viaLsof = run(["lsof", "-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"]);
|
|
1807
|
-
if (viaLsof.length) return viaLsof;
|
|
1808
|
-
return listenerPidsViaProc(port);
|
|
1809
2084
|
}
|
|
1810
2085
|
function listenerPidsViaProc(port) {
|
|
2086
|
+
let available = false;
|
|
1811
2087
|
try {
|
|
1812
2088
|
const hexPort = port.toString(16).toUpperCase().padStart(4, "0");
|
|
1813
2089
|
const inodes = /* @__PURE__ */ new Set();
|
|
1814
2090
|
for (const f of ["/proc/net/tcp", "/proc/net/tcp6"]) {
|
|
1815
2091
|
let data;
|
|
1816
2092
|
try {
|
|
1817
|
-
data =
|
|
2093
|
+
data = readFileSync9(f, "utf-8");
|
|
1818
2094
|
} catch {
|
|
1819
2095
|
continue;
|
|
1820
2096
|
}
|
|
2097
|
+
available = true;
|
|
1821
2098
|
for (const line of data.split("\n").slice(1)) {
|
|
1822
2099
|
const cols = line.trim().split(/\s+/);
|
|
1823
2100
|
if (cols[3] !== "0A") continue;
|
|
1824
2101
|
if (cols[1]?.split(":")[1] === hexPort && cols[9]) inodes.add(cols[9]);
|
|
1825
2102
|
}
|
|
1826
2103
|
}
|
|
1827
|
-
if (!
|
|
2104
|
+
if (!available) return { pids: [], available: false };
|
|
2105
|
+
if (!inodes.size) return { pids: [], available: true };
|
|
1828
2106
|
const pids = /* @__PURE__ */ new Set();
|
|
1829
2107
|
for (const pidDir of readdirSync3("/proc")) {
|
|
1830
2108
|
if (!/^\d+$/.test(pidDir)) continue;
|
|
@@ -1848,9 +2126,9 @@ function listenerPidsViaProc(port) {
|
|
|
1848
2126
|
}
|
|
1849
2127
|
}
|
|
1850
2128
|
}
|
|
1851
|
-
return [...pids];
|
|
2129
|
+
return { pids: [...pids], available: true };
|
|
1852
2130
|
} catch {
|
|
1853
|
-
return [];
|
|
2131
|
+
return { pids: [], available };
|
|
1854
2132
|
}
|
|
1855
2133
|
}
|
|
1856
2134
|
function childPids(parentPid) {
|
|
@@ -1861,22 +2139,31 @@ function childPids(parentPid) {
|
|
|
1861
2139
|
}
|
|
1862
2140
|
return run(["pgrep", "-P", String(parentPid)]);
|
|
1863
2141
|
}
|
|
1864
|
-
function
|
|
2142
|
+
function sweepByName(names) {
|
|
1865
2143
|
const all = /* @__PURE__ */ new Set();
|
|
1866
2144
|
if (IS_WIN) {
|
|
1867
2145
|
const orClauses = names.map((n) => `($_.Name -like '*${n}*') -or ($_.CommandLine -like '*${n}*')`).join(" -or ");
|
|
1868
2146
|
const script = `Get-CimInstance Win32_Process | Where-Object { ${orClauses} } | Select-Object -ExpandProperty ProcessId`;
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
}
|
|
1872
|
-
return [...all];
|
|
2147
|
+
const r = runPowershellChecked(script);
|
|
2148
|
+
for (const pid of r.pids) if (pid !== process.pid) all.add(pid);
|
|
2149
|
+
return { pids: [...all], swept: r.ran };
|
|
1873
2150
|
}
|
|
2151
|
+
let swept = false;
|
|
1874
2152
|
for (const name of names) {
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
2153
|
+
const r = runPgrep(["-f", name]);
|
|
2154
|
+
if (r.ran) swept = true;
|
|
2155
|
+
for (const pid of r.pids) if (pid !== process.pid) all.add(pid);
|
|
2156
|
+
}
|
|
2157
|
+
return { pids: [...all], swept };
|
|
2158
|
+
}
|
|
2159
|
+
function runPgrep(pgrepArgs) {
|
|
2160
|
+
try {
|
|
2161
|
+
const r = spawnSync("pgrep", pgrepArgs, { encoding: "utf-8" });
|
|
2162
|
+
if (r.error) return { pids: [], ran: false };
|
|
2163
|
+
return { pids: r.status === 0 ? parsePidLines(r.stdout) : [], ran: r.status === 0 || r.status === 1 };
|
|
2164
|
+
} catch {
|
|
2165
|
+
return { pids: [], ran: false };
|
|
1878
2166
|
}
|
|
1879
|
-
return [...all];
|
|
1880
2167
|
}
|
|
1881
2168
|
function run(cmd) {
|
|
1882
2169
|
try {
|
|
@@ -1888,15 +2175,18 @@ function run(cmd) {
|
|
|
1888
2175
|
}
|
|
1889
2176
|
}
|
|
1890
2177
|
function runPowershell(script) {
|
|
2178
|
+
return runPowershellChecked(script).pids;
|
|
2179
|
+
}
|
|
2180
|
+
function runPowershellChecked(script) {
|
|
1891
2181
|
const exe = pwshOrPowershell();
|
|
1892
2182
|
try {
|
|
1893
2183
|
const r = spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
1894
2184
|
encoding: "utf-8"
|
|
1895
2185
|
});
|
|
1896
|
-
if (r.
|
|
1897
|
-
return parsePidLines(r.stdout);
|
|
2186
|
+
if (r.error) return { pids: [], ran: false };
|
|
2187
|
+
return { pids: r.status === 0 ? parsePidLines(r.stdout) : [], ran: r.status === 0 };
|
|
1898
2188
|
} catch {
|
|
1899
|
-
return [];
|
|
2189
|
+
return { pids: [], ran: false };
|
|
1900
2190
|
}
|
|
1901
2191
|
}
|
|
1902
2192
|
function pwshOrPowershell() {
|
|
@@ -1975,6 +2265,7 @@ var test_default = defineCommand5({
|
|
|
1975
2265
|
},
|
|
1976
2266
|
env: {
|
|
1977
2267
|
type: "string",
|
|
2268
|
+
alias: "e",
|
|
1978
2269
|
description: "wrangler.toml [env.<name>] block to test (uses secrets config <name> by default).",
|
|
1979
2270
|
required: false
|
|
1980
2271
|
}
|
|
@@ -2010,8 +2301,8 @@ var test_default = defineCommand5({
|
|
|
2010
2301
|
token = await ensureToken();
|
|
2011
2302
|
const payload = decodeJwtPayload(token);
|
|
2012
2303
|
ownerId = payload.sub;
|
|
2013
|
-
} catch {
|
|
2014
|
-
console.error(
|
|
2304
|
+
} catch (err) {
|
|
2305
|
+
console.error(err instanceof Error ? err.message : "Not logged in. Run `deepspace login` first.");
|
|
2015
2306
|
process.exit(1);
|
|
2016
2307
|
}
|
|
2017
2308
|
let generatedSecretsCache;
|
|
@@ -2172,7 +2463,7 @@ var screenshot_default = defineCommand6({
|
|
|
2172
2463
|
// src/cli/commands/test-accounts.ts
|
|
2173
2464
|
import { defineCommand as defineCommand7 } from "citty";
|
|
2174
2465
|
import * as p3 from "@clack/prompts";
|
|
2175
|
-
import { readFileSync as
|
|
2466
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
|
|
2176
2467
|
import { join as join10 } from "path";
|
|
2177
2468
|
import { homedir as homedir4 } from "os";
|
|
2178
2469
|
var SESSION_COOKIE2 = "__Secure-better-auth.session_token";
|
|
@@ -2182,7 +2473,7 @@ var ACCOUNTS_PATH = join10(DIR3, "test-accounts.json");
|
|
|
2182
2473
|
function loadAccounts() {
|
|
2183
2474
|
if (!existsSync9(ACCOUNTS_PATH)) return [];
|
|
2184
2475
|
try {
|
|
2185
|
-
return JSON.parse(
|
|
2476
|
+
return JSON.parse(readFileSync10(ACCOUNTS_PATH, "utf-8"));
|
|
2186
2477
|
} catch {
|
|
2187
2478
|
return [];
|
|
2188
2479
|
}
|
|
@@ -2192,7 +2483,7 @@ function saveAccounts(accounts) {
|
|
|
2192
2483
|
writeFileSync8(ACCOUNTS_PATH, JSON.stringify(accounts, null, 2), { mode: 384 });
|
|
2193
2484
|
}
|
|
2194
2485
|
function sessionCookie() {
|
|
2195
|
-
const token =
|
|
2486
|
+
const token = readFileSync10(SESSION_PATH2, "utf-8").trim();
|
|
2196
2487
|
return `${SESSION_COOKIE2}=${encodeURIComponent(token)}`;
|
|
2197
2488
|
}
|
|
2198
2489
|
async function fetchRemoteAccounts() {
|
|
@@ -2462,7 +2753,7 @@ var test_accounts_default = defineCommand7({
|
|
|
2462
2753
|
import { defineCommand as defineCommand8 } from "citty";
|
|
2463
2754
|
import { execSync as execSync2 } from "child_process";
|
|
2464
2755
|
import { randomUUID } from "crypto";
|
|
2465
|
-
import { readFileSync as
|
|
2756
|
+
import { readFileSync as readFileSync11, readdirSync as readdirSync4, existsSync as existsSync10 } from "fs";
|
|
2466
2757
|
import { join as join11, resolve as resolve7, dirname as dirname2 } from "path";
|
|
2467
2758
|
import { pathToFileURL } from "url";
|
|
2468
2759
|
import * as p4 from "@clack/prompts";
|
|
@@ -2519,6 +2810,13 @@ var GROUP_BYTES = (() => {
|
|
|
2519
2810
|
const v = Number.isInteger(raw) && raw > 0 ? raw : 3 * 1024 * 1024;
|
|
2520
2811
|
return Math.min(v, MAX_GROUP_BYTES);
|
|
2521
2812
|
})();
|
|
2813
|
+
function classifyDevVarsSecrets(opts) {
|
|
2814
|
+
const store = new Set(opts.storeSecretNames);
|
|
2815
|
+
const strayKeys = opts.handEditedDevVarKeys.filter((k) => !store.has(k));
|
|
2816
|
+
if (strayKeys.length === 0) return { kind: "ok" };
|
|
2817
|
+
if (opts.storeSecretNames.length === 0 && !opts.allowMissing) return { kind: "block", strayKeys };
|
|
2818
|
+
return { kind: "warn", strayKeys };
|
|
2819
|
+
}
|
|
2522
2820
|
function packAssetGroups(assets, maxBytes) {
|
|
2523
2821
|
const groups = [];
|
|
2524
2822
|
let current = [];
|
|
@@ -2582,6 +2880,7 @@ var deploy_default = defineCommand8({
|
|
|
2582
2880
|
},
|
|
2583
2881
|
env: {
|
|
2584
2882
|
type: "string",
|
|
2883
|
+
alias: "e",
|
|
2585
2884
|
description: "wrangler.toml [env.<name>] block to deploy (e.g. --env staging). Omit to deploy the top-level config.",
|
|
2586
2885
|
required: false
|
|
2587
2886
|
},
|
|
@@ -2589,6 +2888,11 @@ var deploy_default = defineCommand8({
|
|
|
2589
2888
|
type: "boolean",
|
|
2590
2889
|
description: "Confirm that a changed wrangler `name` renames this app (its URL moves; data, secrets, and collaborators travel). Without this flag an interactive prompt asks.",
|
|
2591
2890
|
default: false
|
|
2891
|
+
},
|
|
2892
|
+
"allow-missing-secrets": {
|
|
2893
|
+
type: "boolean",
|
|
2894
|
+
description: "Deploy even though hand-edited .dev.vars secrets are absent from the store (they will NOT be deployed, and any a previous deploy set are dropped).",
|
|
2895
|
+
default: false
|
|
2592
2896
|
}
|
|
2593
2897
|
},
|
|
2594
2898
|
async run({ args }) {
|
|
@@ -2638,7 +2942,7 @@ var deploy_default = defineCommand8({
|
|
|
2638
2942
|
p4.log.info(`Id: ${appId}`);
|
|
2639
2943
|
const readCustomDevVarsAt = (path) => {
|
|
2640
2944
|
if (!existsSync10(path)) return {};
|
|
2641
|
-
const section = extractCustomDevVars(stripGeneratedSecretsCache(
|
|
2945
|
+
const section = extractCustomDevVars(stripGeneratedSecretsCache(readFileSync11(path, "utf-8")));
|
|
2642
2946
|
if (!section) return {};
|
|
2643
2947
|
try {
|
|
2644
2948
|
return parseDevVars(section);
|
|
@@ -2703,13 +3007,13 @@ var deploy_default = defineCommand8({
|
|
|
2703
3007
|
p4.cancel("Build output config not found at .wrangler/deploy/config.json");
|
|
2704
3008
|
process.exit(1);
|
|
2705
3009
|
}
|
|
2706
|
-
const deployConfig = JSON.parse(
|
|
3010
|
+
const deployConfig = JSON.parse(readFileSync11(deployConfigPath, "utf-8"));
|
|
2707
3011
|
const outputWranglerPath = resolve7(dirname2(deployConfigPath), deployConfig.configPath);
|
|
2708
3012
|
if (!existsSync10(outputWranglerPath)) {
|
|
2709
3013
|
p4.cancel(`Output wrangler.json not found at ${outputWranglerPath}`);
|
|
2710
3014
|
process.exit(1);
|
|
2711
3015
|
}
|
|
2712
|
-
const outputConfig = JSON.parse(
|
|
3016
|
+
const outputConfig = JSON.parse(readFileSync11(outputWranglerPath, "utf-8"));
|
|
2713
3017
|
if (outputConfig.name && outputConfig.name !== appName) {
|
|
2714
3018
|
const envHint = envName ? ` (--env ${envName})` : "";
|
|
2715
3019
|
p4.cancel(
|
|
@@ -2731,7 +3035,7 @@ var deploy_default = defineCommand8({
|
|
|
2731
3035
|
s.start("Collecting assets...");
|
|
2732
3036
|
const assets = collectAssets(clientDir);
|
|
2733
3037
|
s.stop(`Collected ${assets.length} assets`);
|
|
2734
|
-
const workerJs =
|
|
3038
|
+
const workerJs = readFileSync11(workerBundlePath, "utf-8");
|
|
2735
3039
|
const doBindings = outputConfig.durable_objects?.bindings;
|
|
2736
3040
|
const sqliteClasses = new Set(
|
|
2737
3041
|
outputConfig.migrations?.flatMap(
|
|
@@ -2765,10 +3069,27 @@ var deploy_default = defineCommand8({
|
|
|
2765
3069
|
});
|
|
2766
3070
|
const userSecrets = linkedSecrets ? { ...linkedSecrets.values } : {};
|
|
2767
3071
|
const handEditedDevVars = linkedSecrets ? localOnlyDevVars : readCustomDevVarsAt(devVarsPath);
|
|
2768
|
-
const
|
|
2769
|
-
|
|
3072
|
+
const secretsDecision = classifyDevVarsSecrets({
|
|
3073
|
+
storeSecretNames: Object.keys(userSecrets),
|
|
3074
|
+
handEditedDevVarKeys: Object.keys(handEditedDevVars),
|
|
3075
|
+
allowMissing: Boolean(args["allow-missing-secrets"])
|
|
3076
|
+
});
|
|
3077
|
+
if (secretsDecision.kind === "block") {
|
|
3078
|
+
const uploadCmd = envName ? `deepspace secrets upload .dev.vars -e ${envName}` : "deepspace secrets upload .dev.vars";
|
|
3079
|
+
const keys = secretsDecision.strayKeys.join(", ");
|
|
3080
|
+
p4.cancel(
|
|
3081
|
+
`Refusing to deploy: the app store has no secrets, but .dev.vars has ${keys}.
|
|
3082
|
+
Deploying now would ship the app with no secrets \u2014 replacing any a previous deploy set (they would be dropped from production).
|
|
3083
|
+
Upload them to the store first:
|
|
3084
|
+
${uploadCmd}
|
|
3085
|
+
then redeploy. (Pass --allow-missing-secrets to deploy without them.)`
|
|
3086
|
+
);
|
|
3087
|
+
process.exit(1);
|
|
3088
|
+
}
|
|
3089
|
+
if (secretsDecision.kind === "warn") {
|
|
3090
|
+
const stray = secretsDecision.strayKeys;
|
|
2770
3091
|
p4.log.warn(
|
|
2771
|
-
`.dev.vars has ${
|
|
3092
|
+
`.dev.vars has ${stray.join(", ")} not in the app store \u2014 ${stray.length === 1 ? "it is" : "they are"} NOT deployed. \`.dev.vars\` is a local dev cache, not deploy config. Move ${stray.length === 1 ? "it" : "them"} into the store with \`deepspace secrets set KEY=value\` (or \`deepspace secrets upload .dev.vars\`), then redeploy.`
|
|
2772
3093
|
);
|
|
2773
3094
|
}
|
|
2774
3095
|
const userSecretNames = Object.keys(userSecrets);
|
|
@@ -2866,6 +3187,7 @@ var deploy_default = defineCommand8({
|
|
|
2866
3187
|
if (userSecretNames.length) {
|
|
2867
3188
|
form.append("userSecrets", JSON.stringify(userSecrets));
|
|
2868
3189
|
}
|
|
3190
|
+
form.append("secretsAuthoritative", "true");
|
|
2869
3191
|
if (extraRoutes.length) {
|
|
2870
3192
|
form.append("extraRunWorkerFirst", JSON.stringify(extraRoutes));
|
|
2871
3193
|
}
|
|
@@ -2895,6 +3217,12 @@ var deploy_default = defineCommand8({
|
|
|
2895
3217
|
let body = await res.json().catch(() => ({}));
|
|
2896
3218
|
if (res.status === 409 && body.code === "rename_required" && !confirmRename) {
|
|
2897
3219
|
s.stop("Rename confirmation needed");
|
|
3220
|
+
if (!process.stdin.isTTY) {
|
|
3221
|
+
await bailDeploy(
|
|
3222
|
+
`This deploy renames the app: ${body.fromHost} \u2192 ${body.toHost}. Confirmation needs an interactive terminal \u2014 re-run with --rename to approve the rename, or \`deepspace init --new-id\` if you meant a separate app.`,
|
|
3223
|
+
null
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
2898
3226
|
const yes = await p4.confirm({
|
|
2899
3227
|
message: `This deploy renames the app: ${body.fromHost} \u2192 ${body.toHost}. The URL changes and the old one stops serving right away; data, secrets, and collaborators travel with it. (Meant a separate app? Run \`deepspace init --new-id\` instead.) Rename?`
|
|
2900
3228
|
});
|
|
@@ -3171,7 +3499,7 @@ function collectAssets(dir) {
|
|
|
3171
3499
|
} else {
|
|
3172
3500
|
assets.push({
|
|
3173
3501
|
path: "/" + rel,
|
|
3174
|
-
contentBase64:
|
|
3502
|
+
contentBase64: readFileSync11(full).toString("base64")
|
|
3175
3503
|
});
|
|
3176
3504
|
}
|
|
3177
3505
|
}
|
|
@@ -3192,7 +3520,7 @@ var undeploy_default = defineCommand9({
|
|
|
3192
3520
|
args: {
|
|
3193
3521
|
name: {
|
|
3194
3522
|
type: "positional",
|
|
3195
|
-
description: "App id to undeploy (reads DEEPSPACE_APP_ID from wrangler.toml if omitted)",
|
|
3523
|
+
description: "App id or subdomain name to undeploy (reads DEEPSPACE_APP_ID from wrangler.toml if omitted)",
|
|
3196
3524
|
required: false
|
|
3197
3525
|
},
|
|
3198
3526
|
env: {
|
|
@@ -3203,18 +3531,6 @@ var undeploy_default = defineCommand9({
|
|
|
3203
3531
|
},
|
|
3204
3532
|
async run({ args }) {
|
|
3205
3533
|
const envName = typeof args.env === "string" && args.env.trim() ? args.env.trim() : void 0;
|
|
3206
|
-
let appId = args.name;
|
|
3207
|
-
if (appId && !APP_ID_RE.test(appId)) {
|
|
3208
|
-
p5.cancel(`"${appId}" is not an app id (app_\u2026). Undeploy targets the id \u2014 run from the app directory, or find it in wrangler.toml.`);
|
|
3209
|
-
process.exit(1);
|
|
3210
|
-
}
|
|
3211
|
-
if (!appId && hasWranglerConfig(process.cwd())) {
|
|
3212
|
-
appId = readAppId(process.cwd(), envName) ?? void 0;
|
|
3213
|
-
}
|
|
3214
|
-
if (!appId) {
|
|
3215
|
-
p5.cancel("Provide an app id or run from a DeepSpace app directory with a DEEPSPACE_APP_ID.");
|
|
3216
|
-
process.exit(1);
|
|
3217
|
-
}
|
|
3218
3534
|
let token;
|
|
3219
3535
|
try {
|
|
3220
3536
|
token = await ensureToken();
|
|
@@ -3222,6 +3538,22 @@ var undeploy_default = defineCommand9({
|
|
|
3222
3538
|
p5.cancel(err instanceof Error ? err.message : String(err));
|
|
3223
3539
|
process.exit(1);
|
|
3224
3540
|
}
|
|
3541
|
+
let appId;
|
|
3542
|
+
const positional = typeof args.name === "string" && args.name.trim() ? args.name.trim() : void 0;
|
|
3543
|
+
if (positional) {
|
|
3544
|
+
try {
|
|
3545
|
+
appId = await resolveAppSelector(DEPLOY_URL4, token, positional);
|
|
3546
|
+
} catch (err) {
|
|
3547
|
+
p5.cancel(err instanceof Error ? err.message : String(err));
|
|
3548
|
+
process.exit(1);
|
|
3549
|
+
}
|
|
3550
|
+
} else if (hasWranglerConfig(process.cwd())) {
|
|
3551
|
+
appId = readAppId(process.cwd(), envName) ?? void 0;
|
|
3552
|
+
}
|
|
3553
|
+
if (!appId) {
|
|
3554
|
+
p5.cancel("Provide an app id or subdomain name, or run from a DeepSpace app directory with a DEEPSPACE_APP_ID.");
|
|
3555
|
+
process.exit(1);
|
|
3556
|
+
}
|
|
3225
3557
|
p5.intro(`Undeploying ${appId}`);
|
|
3226
3558
|
const s = createSpinner();
|
|
3227
3559
|
s.start("Removing...");
|
|
@@ -3258,24 +3590,28 @@ var whoami_default = defineCommand10({
|
|
|
3258
3590
|
}
|
|
3259
3591
|
},
|
|
3260
3592
|
async run({ args }) {
|
|
3593
|
+
const failLoggedOut = (msg) => {
|
|
3594
|
+
if (args.json) console.log(JSON.stringify({ loggedIn: false, error: msg }));
|
|
3595
|
+
else console.error(msg);
|
|
3596
|
+
process.exit(1);
|
|
3597
|
+
};
|
|
3261
3598
|
let jwt;
|
|
3262
3599
|
try {
|
|
3263
3600
|
jwt = await ensureToken();
|
|
3264
3601
|
} catch (err) {
|
|
3265
|
-
|
|
3266
|
-
process.exit(1);
|
|
3602
|
+
failLoggedOut(err instanceof Error ? err.message : "Not logged in. Run `deepspace login` first.");
|
|
3267
3603
|
}
|
|
3268
3604
|
let payload;
|
|
3269
3605
|
try {
|
|
3270
3606
|
payload = decodeJwtPayload(jwt);
|
|
3271
3607
|
} catch {
|
|
3272
|
-
|
|
3273
|
-
process.exit(1);
|
|
3608
|
+
failLoggedOut("Malformed session token. Run `deepspace login` again.");
|
|
3274
3609
|
}
|
|
3275
3610
|
const isTestAccount = !!payload.email?.endsWith("@deepspace.test");
|
|
3276
3611
|
const accountType = isTestAccount ? "test-account" : payload.email ? "developer" : "unknown";
|
|
3277
3612
|
if (args.json) {
|
|
3278
3613
|
console.log(JSON.stringify({
|
|
3614
|
+
loggedIn: true,
|
|
3279
3615
|
name: payload.name ?? null,
|
|
3280
3616
|
email: payload.email ?? null,
|
|
3281
3617
|
userId: payload.sub ?? null,
|
|
@@ -3299,11 +3635,48 @@ var whoami_default = defineCommand10({
|
|
|
3299
3635
|
}
|
|
3300
3636
|
});
|
|
3301
3637
|
|
|
3302
|
-
// src/cli/commands/
|
|
3638
|
+
// src/cli/commands/apps.ts
|
|
3303
3639
|
import { defineCommand as defineCommand11 } from "citty";
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3640
|
+
var DEPLOY_URL5 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
3641
|
+
var apps_default = defineCommand11({
|
|
3642
|
+
meta: {
|
|
3643
|
+
name: "apps",
|
|
3644
|
+
description: "List your apps (deployed and registered)"
|
|
3645
|
+
},
|
|
3646
|
+
args: {
|
|
3647
|
+
json: {
|
|
3648
|
+
type: "boolean",
|
|
3649
|
+
description: "Emit JSON instead of human output",
|
|
3650
|
+
default: false
|
|
3651
|
+
}
|
|
3652
|
+
},
|
|
3653
|
+
async run({ args }) {
|
|
3654
|
+
const token = await ensureToken();
|
|
3655
|
+
const { apps } = await apiFetch(DEPLOY_URL5, token, "/api/apps");
|
|
3656
|
+
if (args.json) {
|
|
3657
|
+
process.stdout.write(JSON.stringify(apps, null, 2) + "\n");
|
|
3658
|
+
return;
|
|
3659
|
+
}
|
|
3660
|
+
if (!apps.length) {
|
|
3661
|
+
console.log("No apps yet. Create one with `npx create-deepspace <name>` and `deepspace deploy`.");
|
|
3662
|
+
return;
|
|
3663
|
+
}
|
|
3664
|
+
const nameWidth = Math.max(4, ...apps.map((a) => (a.name ?? "\u2014").length));
|
|
3665
|
+
const idWidth = Math.max(6, ...apps.map((a) => a.appId.length));
|
|
3666
|
+
console.log(`${"NAME".padEnd(nameWidth)} ${"APP ID".padEnd(idWidth)} URL`);
|
|
3667
|
+
for (const a of apps) {
|
|
3668
|
+
const url = a.url ?? "(not deployed)";
|
|
3669
|
+
console.log(`${(a.name ?? "\u2014").padEnd(nameWidth)} ${a.appId.padEnd(idWidth)} ${url}`);
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3672
|
+
});
|
|
3673
|
+
|
|
3674
|
+
// src/cli/commands/add.ts
|
|
3675
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
3676
|
+
import { existsSync as existsSync11, readFileSync as readFileSync12 } from "fs";
|
|
3677
|
+
import { resolve as resolve8, join as join12, dirname as dirname3 } from "path";
|
|
3678
|
+
import { fileURLToPath } from "url";
|
|
3679
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
3307
3680
|
function findScript(from) {
|
|
3308
3681
|
const inNodeModules = join12(from, "node_modules", "deepspace", "scripts", "add-feature.cjs");
|
|
3309
3682
|
if (existsSync11(inNodeModules)) return inNodeModules;
|
|
@@ -3311,7 +3684,31 @@ function findScript(from) {
|
|
|
3311
3684
|
if (existsSync11(inDotDeepspace)) return inDotDeepspace;
|
|
3312
3685
|
return null;
|
|
3313
3686
|
}
|
|
3314
|
-
|
|
3687
|
+
function runningScript() {
|
|
3688
|
+
const here = dirname3(fileURLToPath(import.meta.url));
|
|
3689
|
+
const script = join12(here, "..", "scripts", "add-feature.cjs");
|
|
3690
|
+
return existsSync11(script) ? script : null;
|
|
3691
|
+
}
|
|
3692
|
+
function isDeepSpaceApp(dir) {
|
|
3693
|
+
if (existsSync11(join12(dir, "wrangler.toml"))) return true;
|
|
3694
|
+
const pkgPath = join12(dir, "package.json");
|
|
3695
|
+
if (!existsSync11(pkgPath)) return false;
|
|
3696
|
+
try {
|
|
3697
|
+
const pkg2 = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
3698
|
+
return Boolean(pkg2.dependencies?.deepspace || pkg2.devDependencies?.deepspace);
|
|
3699
|
+
} catch {
|
|
3700
|
+
return false;
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
function runInstaller(script, passArgs, cwd) {
|
|
3704
|
+
const res = spawnSync5(process.execPath, [script, ...passArgs], { stdio: "inherit", cwd });
|
|
3705
|
+
if (res.error) {
|
|
3706
|
+
console.error(`Could not run the feature installer: ${res.error.message}`);
|
|
3707
|
+
process.exit(1);
|
|
3708
|
+
}
|
|
3709
|
+
process.exit(res.status ?? 1);
|
|
3710
|
+
}
|
|
3711
|
+
var add_default = defineCommand12({
|
|
3315
3712
|
meta: {
|
|
3316
3713
|
name: "add",
|
|
3317
3714
|
description: "Add a feature to your DeepSpace app"
|
|
@@ -3328,6 +3725,11 @@ var add_default = defineCommand11({
|
|
|
3328
3725
|
description: "Show details about a feature",
|
|
3329
3726
|
required: false
|
|
3330
3727
|
},
|
|
3728
|
+
install: {
|
|
3729
|
+
type: "boolean",
|
|
3730
|
+
description: "Run your package manager after adding dependencies",
|
|
3731
|
+
required: false
|
|
3732
|
+
},
|
|
3331
3733
|
feature: {
|
|
3332
3734
|
type: "positional",
|
|
3333
3735
|
description: "Feature to install",
|
|
@@ -3341,6 +3743,27 @@ var add_default = defineCommand11({
|
|
|
3341
3743
|
},
|
|
3342
3744
|
run({ args }) {
|
|
3343
3745
|
const appDir = resolve8(args.dir ?? ".");
|
|
3746
|
+
if (args.list || args.info || !args.feature) {
|
|
3747
|
+
const script2 = runningScript();
|
|
3748
|
+
if (!script2) {
|
|
3749
|
+
console.error("Could not find the deepspace feature catalog.");
|
|
3750
|
+
console.error("Reinstall deepspace (`npm i -g deepspace`) or run inside a DeepSpace app.");
|
|
3751
|
+
process.exit(1);
|
|
3752
|
+
}
|
|
3753
|
+
const passArgs2 = args.list ? ["--list"] : args.info ? ["--info", String(args.info)] : ["--help"];
|
|
3754
|
+
runInstaller(script2, passArgs2, process.cwd());
|
|
3755
|
+
}
|
|
3756
|
+
if (!existsSync11(appDir)) {
|
|
3757
|
+
console.error(`Target directory not found: ${appDir}`);
|
|
3758
|
+
console.error("Create a new app first: deepspace create <name>");
|
|
3759
|
+
process.exit(1);
|
|
3760
|
+
}
|
|
3761
|
+
if (!isDeepSpaceApp(appDir)) {
|
|
3762
|
+
console.error(`Not a DeepSpace app: ${appDir}`);
|
|
3763
|
+
console.error('(no wrangler.toml and no "deepspace" dependency found)');
|
|
3764
|
+
console.error("Create one with: deepspace create <name>");
|
|
3765
|
+
process.exit(1);
|
|
3766
|
+
}
|
|
3344
3767
|
ensureInstallReady(appDir);
|
|
3345
3768
|
const script = findScript(appDir);
|
|
3346
3769
|
if (!script) {
|
|
@@ -3351,136 +3774,14 @@ var add_default = defineCommand11({
|
|
|
3351
3774
|
console.error("Are you in a DeepSpace app directory? Try `npm install` first.");
|
|
3352
3775
|
process.exit(1);
|
|
3353
3776
|
}
|
|
3354
|
-
const passArgs = [];
|
|
3355
|
-
if (args.
|
|
3356
|
-
|
|
3357
|
-
} else if (args.info) {
|
|
3358
|
-
passArgs.push("--info", args.info);
|
|
3359
|
-
} else if (args.feature) {
|
|
3360
|
-
passArgs.push(args.feature, appDir);
|
|
3361
|
-
} else {
|
|
3362
|
-
passArgs.push("--help");
|
|
3363
|
-
}
|
|
3364
|
-
execSync3(`node ${JSON.stringify(script)} ${passArgs.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
3365
|
-
stdio: "inherit",
|
|
3366
|
-
cwd: appDir
|
|
3367
|
-
});
|
|
3368
|
-
}
|
|
3369
|
-
});
|
|
3370
|
-
|
|
3371
|
-
// src/cli/commands/skills.ts
|
|
3372
|
-
import { defineCommand as defineCommand12 } from "citty";
|
|
3373
|
-
import spawn2 from "cross-spawn";
|
|
3374
|
-
import { mkdirSync as mkdirSync5 } from "fs";
|
|
3375
|
-
import { join as join13 } from "path";
|
|
3376
|
-
import { homedir as homedir5 } from "os";
|
|
3377
|
-
var SKILL_REPO = "deepdotspace/deepspace-skill";
|
|
3378
|
-
function runSkillsAdd(extraArgs) {
|
|
3379
|
-
return new Promise((resolve10) => {
|
|
3380
|
-
const child = spawn2(
|
|
3381
|
-
"npx",
|
|
3382
|
-
["-y", "skills@latest", "add", SKILL_REPO, ...extraArgs],
|
|
3383
|
-
{ stdio: "inherit" }
|
|
3384
|
-
);
|
|
3385
|
-
child.on("close", (code) => resolve10(code ?? 1));
|
|
3386
|
-
child.on("error", (err) => {
|
|
3387
|
-
console.error(`Failed to invoke npx: ${err.message}`);
|
|
3388
|
-
console.error("Is Node.js installed and on PATH?");
|
|
3389
|
-
resolve10(1);
|
|
3390
|
-
});
|
|
3391
|
-
});
|
|
3392
|
-
}
|
|
3393
|
-
function precreateClaudeDir(baseDir) {
|
|
3394
|
-
mkdirSync5(join13(baseDir, ".claude"), { recursive: true });
|
|
3395
|
-
}
|
|
3396
|
-
var add = defineCommand12({
|
|
3397
|
-
meta: {
|
|
3398
|
-
name: "add",
|
|
3399
|
-
description: "Install the DeepSpace skill for your coding agent"
|
|
3400
|
-
},
|
|
3401
|
-
args: {
|
|
3402
|
-
global: {
|
|
3403
|
-
type: "boolean",
|
|
3404
|
-
alias: "g",
|
|
3405
|
-
description: "Install globally (~/.agents/skills/) instead of into the current directory",
|
|
3406
|
-
default: false
|
|
3407
|
-
},
|
|
3408
|
-
yes: {
|
|
3409
|
-
type: "boolean",
|
|
3410
|
-
alias: "y",
|
|
3411
|
-
description: "Skip prompts (assume yes for any confirmation)",
|
|
3412
|
-
default: false
|
|
3413
|
-
},
|
|
3414
|
-
agent: {
|
|
3415
|
-
type: "string",
|
|
3416
|
-
description: "Target a single agent (e.g. claude-code, codex, opencode). Default: install for all detected agents.",
|
|
3417
|
-
required: false
|
|
3418
|
-
}
|
|
3419
|
-
},
|
|
3420
|
-
async run({ args }) {
|
|
3421
|
-
const extra = [];
|
|
3422
|
-
if (args.global) extra.push("-g");
|
|
3423
|
-
if (args.yes) extra.push("-y");
|
|
3424
|
-
if (args.agent) extra.push("--agent", args.agent);
|
|
3425
|
-
if (!args.agent || args.agent === "claude-code") {
|
|
3426
|
-
const baseDir = args.global ? homedir5() : process.cwd();
|
|
3427
|
-
try {
|
|
3428
|
-
precreateClaudeDir(baseDir);
|
|
3429
|
-
} catch (err) {
|
|
3430
|
-
console.warn(`
|
|
3431
|
-
Note: could not pre-create .claude/ for Claude Code: ${err instanceof Error ? err.message : String(err)}`);
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
const code = await runSkillsAdd(extra);
|
|
3435
|
-
if (code !== 0) process.exit(code);
|
|
3436
|
-
}
|
|
3437
|
-
});
|
|
3438
|
-
var skills_default = defineCommand12({
|
|
3439
|
-
meta: {
|
|
3440
|
-
name: "skills",
|
|
3441
|
-
description: "Manage the DeepSpace agent skill (Claude Code, Codex, OpenCode, Cursor, ...)"
|
|
3442
|
-
},
|
|
3443
|
-
subCommands: {
|
|
3444
|
-
add
|
|
3777
|
+
const passArgs = [args.feature, appDir];
|
|
3778
|
+
if (args.install) passArgs.push("--install");
|
|
3779
|
+
runInstaller(script, passArgs, appDir);
|
|
3445
3780
|
}
|
|
3446
3781
|
});
|
|
3447
3782
|
|
|
3448
3783
|
// src/cli/commands/domain.ts
|
|
3449
3784
|
import { defineCommand as defineCommand13 } from "citty";
|
|
3450
|
-
|
|
3451
|
-
// src/cli/lib/api.ts
|
|
3452
|
-
var ApiError = class extends Error {
|
|
3453
|
-
constructor(message, status3, code) {
|
|
3454
|
-
super(message);
|
|
3455
|
-
this.status = status3;
|
|
3456
|
-
this.code = code;
|
|
3457
|
-
}
|
|
3458
|
-
};
|
|
3459
|
-
async function apiFetch(baseUrl, token, path, init) {
|
|
3460
|
-
const res = await fetch(`${baseUrl}${path}`, {
|
|
3461
|
-
...init,
|
|
3462
|
-
headers: {
|
|
3463
|
-
Authorization: `Bearer ${token}`,
|
|
3464
|
-
"Content-Type": "application/json",
|
|
3465
|
-
...init?.headers ?? {}
|
|
3466
|
-
}
|
|
3467
|
-
});
|
|
3468
|
-
const text2 = await res.text();
|
|
3469
|
-
if (!res.ok) {
|
|
3470
|
-
let msg = text2;
|
|
3471
|
-
let code;
|
|
3472
|
-
try {
|
|
3473
|
-
const body = JSON.parse(text2);
|
|
3474
|
-
msg = body.error ?? text2;
|
|
3475
|
-
code = body.code;
|
|
3476
|
-
} catch {
|
|
3477
|
-
}
|
|
3478
|
-
throw new ApiError(`API ${path} (${res.status}): ${msg}`, res.status, code);
|
|
3479
|
-
}
|
|
3480
|
-
return text2 ? JSON.parse(text2) : {};
|
|
3481
|
-
}
|
|
3482
|
-
|
|
3483
|
-
// src/cli/commands/domain.ts
|
|
3484
3785
|
var API_URL3 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
3485
3786
|
var api = (token, path, init) => apiFetch(API_URL3, token, path, init);
|
|
3486
3787
|
function scrubInternal(value) {
|
|
@@ -3817,18 +4118,19 @@ function isTestAccountEmail(email) {
|
|
|
3817
4118
|
|
|
3818
4119
|
// src/cli/commands/collaborators.ts
|
|
3819
4120
|
var API_URL4 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
4121
|
+
var DEPLOY_URL6 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
3820
4122
|
function api2(token, path, init) {
|
|
3821
4123
|
return apiFetch(API_URL4, token, path, init);
|
|
3822
4124
|
}
|
|
3823
4125
|
var list3 = defineCommand14({
|
|
3824
4126
|
meta: { name: "list", description: "List collaborators on your app" },
|
|
3825
4127
|
args: {
|
|
3826
|
-
app: { type: "string", alias: "a", description: "App id (defaults to ./wrangler.toml)" },
|
|
4128
|
+
app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" },
|
|
3827
4129
|
json: { type: "boolean", description: "Emit JSON" }
|
|
3828
4130
|
},
|
|
3829
4131
|
async run({ args }) {
|
|
3830
4132
|
const token = await ensureToken();
|
|
3831
|
-
const app =
|
|
4133
|
+
const app = await resolveAppTarget(DEPLOY_URL6, token, args.app);
|
|
3832
4134
|
const { collaborators } = await api2(
|
|
3833
4135
|
token,
|
|
3834
4136
|
`/api/app-collaborators/${encodeURIComponent(app)}`
|
|
@@ -3841,12 +4143,13 @@ var list3 = defineCommand14({
|
|
|
3841
4143
|
console.log(`No collaborators on ${app}. Add one with \`deepspace collaborators add <email>\`.`);
|
|
3842
4144
|
return;
|
|
3843
4145
|
}
|
|
4146
|
+
console.log(`COLLABORATORS ON ${app}`);
|
|
3844
4147
|
for (const c of collaborators) {
|
|
3845
|
-
console.log(
|
|
4148
|
+
console.log(` ${c.emailDisplay}`);
|
|
3846
4149
|
}
|
|
3847
4150
|
}
|
|
3848
4151
|
});
|
|
3849
|
-
var
|
|
4152
|
+
var add = defineCommand14({
|
|
3850
4153
|
meta: { name: "add", description: "Authorize a DeepSpace user to deploy your app" },
|
|
3851
4154
|
args: {
|
|
3852
4155
|
email: {
|
|
@@ -3854,12 +4157,12 @@ var add2 = defineCommand14({
|
|
|
3854
4157
|
description: "Collaborator email (must already be a DeepSpace user)",
|
|
3855
4158
|
required: true
|
|
3856
4159
|
},
|
|
3857
|
-
app: { type: "string", alias: "a", description: "App id (defaults to ./wrangler.toml)" },
|
|
4160
|
+
app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" },
|
|
3858
4161
|
json: { type: "boolean", description: "Emit JSON" }
|
|
3859
4162
|
},
|
|
3860
4163
|
async run({ args }) {
|
|
3861
4164
|
const token = await ensureToken();
|
|
3862
|
-
const app =
|
|
4165
|
+
const app = await resolveAppTarget(DEPLOY_URL6, token, args.app);
|
|
3863
4166
|
if (isTestAccountEmail(args.email)) {
|
|
3864
4167
|
console.error(
|
|
3865
4168
|
"Test accounts (@deepspace.test) cannot be added as collaborators. Use a real DeepSpace account."
|
|
@@ -3882,12 +4185,12 @@ var remove = defineCommand14({
|
|
|
3882
4185
|
meta: { name: "remove", description: "Remove a collaborator from your app" },
|
|
3883
4186
|
args: {
|
|
3884
4187
|
email: { type: "positional", description: "Collaborator email", required: true },
|
|
3885
|
-
app: { type: "string", alias: "a", description: "App id (defaults to ./wrangler.toml)" },
|
|
4188
|
+
app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" },
|
|
3886
4189
|
json: { type: "boolean", description: "Emit JSON" }
|
|
3887
4190
|
},
|
|
3888
4191
|
async run({ args }) {
|
|
3889
4192
|
const token = await ensureToken();
|
|
3890
|
-
const app =
|
|
4193
|
+
const app = await resolveAppTarget(DEPLOY_URL6, token, args.app);
|
|
3891
4194
|
const { collaborators } = await api2(
|
|
3892
4195
|
token,
|
|
3893
4196
|
`/api/app-collaborators/${encodeURIComponent(app)}`
|
|
@@ -3912,28 +4215,57 @@ var remove = defineCommand14({
|
|
|
3912
4215
|
});
|
|
3913
4216
|
var collaborators_default = defineCommand14({
|
|
3914
4217
|
meta: { name: "collaborators", description: "Manage who can deploy your app" },
|
|
3915
|
-
subCommands: { list: list3, add
|
|
4218
|
+
subCommands: { list: list3, add, remove }
|
|
3916
4219
|
});
|
|
3917
4220
|
|
|
3918
4221
|
// src/cli/commands/transfer.ts
|
|
3919
4222
|
import { defineCommand as defineCommand15 } from "citty";
|
|
4223
|
+
import * as p6 from "@clack/prompts";
|
|
3920
4224
|
var API_URL5 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
3921
|
-
var
|
|
4225
|
+
var DEPLOY_URL7 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
3922
4226
|
var offer = defineCommand15({
|
|
3923
4227
|
meta: { name: "offer", description: "Offer this app to another DeepSpace user" },
|
|
3924
4228
|
args: {
|
|
3925
4229
|
email: { type: "positional", description: "Recipient email", required: true },
|
|
3926
|
-
app: { type: "string", alias: "a", description: "App id (defaults to ./wrangler.toml)" }
|
|
4230
|
+
app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" },
|
|
4231
|
+
replace: {
|
|
4232
|
+
type: "boolean",
|
|
4233
|
+
description: "Replace a pending offer to someone else without asking"
|
|
4234
|
+
}
|
|
3927
4235
|
},
|
|
3928
4236
|
async run({ args }) {
|
|
3929
4237
|
const token = await ensureToken();
|
|
3930
|
-
const app =
|
|
4238
|
+
const app = await resolveAppTarget(DEPLOY_URL7, token, args.app);
|
|
4239
|
+
const pending = await apiFetch(
|
|
4240
|
+
API_URL5,
|
|
4241
|
+
token,
|
|
4242
|
+
`/api/app-transfers/${encodeURIComponent(app)}`
|
|
4243
|
+
);
|
|
4244
|
+
const pendingTo = pending.transfer?.toEmailDisplay;
|
|
4245
|
+
if (pendingTo && pendingTo.toLowerCase() !== args.email.trim().toLowerCase() && !args.replace) {
|
|
4246
|
+
if (!process.stdin.isTTY) {
|
|
4247
|
+
console.error(
|
|
4248
|
+
`A pending offer to ${pendingTo} already exists for ${app}. Re-run with --replace to replace it, or \`deepspace transfer cancel\` first.`
|
|
4249
|
+
);
|
|
4250
|
+
process.exit(1);
|
|
4251
|
+
}
|
|
4252
|
+
const yes = await p6.confirm({
|
|
4253
|
+
message: `A pending offer to ${pendingTo} exists \u2014 replace it with ${args.email}?`
|
|
4254
|
+
});
|
|
4255
|
+
if (p6.isCancel(yes) || !yes) {
|
|
4256
|
+
console.log(`Kept the pending offer to ${pendingTo}.`);
|
|
4257
|
+
process.exit(1);
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
3931
4260
|
const { expiresAt } = await apiFetch(
|
|
3932
4261
|
API_URL5,
|
|
3933
4262
|
token,
|
|
3934
4263
|
`/api/app-transfers/${encodeURIComponent(app)}`,
|
|
3935
4264
|
{ method: "POST", body: JSON.stringify({ email: args.email }) }
|
|
3936
4265
|
);
|
|
4266
|
+
if (pendingTo && pendingTo.toLowerCase() !== args.email.trim().toLowerCase()) {
|
|
4267
|
+
console.log(`\u25B2 Replaced the pending offer to ${pendingTo}.`);
|
|
4268
|
+
}
|
|
3937
4269
|
console.log(
|
|
3938
4270
|
`\u2713 Offered ${app} to ${args.email} (expires ${expiresAt}).
|
|
3939
4271
|
They accept with: deepspace transfer accept --app ${app}`
|
|
@@ -3943,11 +4275,11 @@ var offer = defineCommand15({
|
|
|
3943
4275
|
var status2 = defineCommand15({
|
|
3944
4276
|
meta: { name: "status", description: "Show the pending transfer offer, if any" },
|
|
3945
4277
|
args: {
|
|
3946
|
-
app: { type: "string", alias: "a", description: "App id (defaults to ./wrangler.toml)" }
|
|
4278
|
+
app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" }
|
|
3947
4279
|
},
|
|
3948
4280
|
async run({ args }) {
|
|
3949
4281
|
const token = await ensureToken();
|
|
3950
|
-
const app =
|
|
4282
|
+
const app = await resolveAppTarget(DEPLOY_URL7, token, args.app);
|
|
3951
4283
|
const { transfer } = await apiFetch(API_URL5, token, `/api/app-transfers/${encodeURIComponent(app)}`);
|
|
3952
4284
|
if (!transfer) {
|
|
3953
4285
|
console.log(`No pending transfer for ${app}.`);
|
|
@@ -3964,7 +4296,7 @@ var accept = defineCommand15({
|
|
|
3964
4296
|
async run({ args }) {
|
|
3965
4297
|
const token = await ensureToken();
|
|
3966
4298
|
const app = requireAppIdArg(args.app);
|
|
3967
|
-
await apiFetch(
|
|
4299
|
+
await apiFetch(DEPLOY_URL7, token, `/api/apps/${encodeURIComponent(app)}/transfer/accept`, {
|
|
3968
4300
|
method: "POST"
|
|
3969
4301
|
});
|
|
3970
4302
|
console.log(
|
|
@@ -3975,11 +4307,11 @@ var accept = defineCommand15({
|
|
|
3975
4307
|
var cancel4 = defineCommand15({
|
|
3976
4308
|
meta: { name: "cancel", description: "Cancel/decline the pending offer (either party)" },
|
|
3977
4309
|
args: {
|
|
3978
|
-
app: { type: "string", alias: "a", description: "App id (defaults to ./wrangler.toml)" }
|
|
4310
|
+
app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" }
|
|
3979
4311
|
},
|
|
3980
4312
|
async run({ args }) {
|
|
3981
4313
|
const token = await ensureToken();
|
|
3982
|
-
const app =
|
|
4314
|
+
const app = await resolveAppTarget(DEPLOY_URL7, token, args.app);
|
|
3983
4315
|
await apiFetch(API_URL5, token, `/api/app-transfers/${encodeURIComponent(app)}`, { method: "DELETE" });
|
|
3984
4316
|
console.log(`\u2713 Transfer offer for ${app} cancelled.`);
|
|
3985
4317
|
}
|
|
@@ -3993,7 +4325,8 @@ var transfer_default = defineCommand15({
|
|
|
3993
4325
|
import { defineCommand as defineCommand16 } from "citty";
|
|
3994
4326
|
|
|
3995
4327
|
// src/cli/commands/_invoke-impl.ts
|
|
3996
|
-
import { readFileSync as
|
|
4328
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
4329
|
+
import * as p7 from "@clack/prompts";
|
|
3997
4330
|
var API_URL6 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
3998
4331
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
3999
4332
|
function parseTarget(target) {
|
|
@@ -4018,7 +4351,7 @@ function resolveBody(opts) {
|
|
|
4018
4351
|
if (opts.body != null) {
|
|
4019
4352
|
raw = opts.body;
|
|
4020
4353
|
} else if (opts.bodyFile != null) {
|
|
4021
|
-
raw = opts.bodyFile === "-" ?
|
|
4354
|
+
raw = opts.bodyFile === "-" ? readFileSync13(0, "utf-8") : readFileSync13(opts.bodyFile, "utf-8");
|
|
4022
4355
|
} else {
|
|
4023
4356
|
return "{}";
|
|
4024
4357
|
}
|
|
@@ -4052,6 +4385,17 @@ function formatCurrency(value, currency) {
|
|
|
4052
4385
|
if (currency === "USD") return `$${value}`;
|
|
4053
4386
|
return `${value} ${currency}`;
|
|
4054
4387
|
}
|
|
4388
|
+
function billingUnit(model) {
|
|
4389
|
+
if (model === "per_token") return "per token";
|
|
4390
|
+
if (model === "per_call") return "per call";
|
|
4391
|
+
return model.startsWith("per_") ? model.replace(/^per_/, "per ").replace(/_/g, " ") : model;
|
|
4392
|
+
}
|
|
4393
|
+
function isInteractive(stdin, stdout) {
|
|
4394
|
+
return Boolean(stdin.isTTY && stdout.isTTY);
|
|
4395
|
+
}
|
|
4396
|
+
function shouldConfirmCost(opts) {
|
|
4397
|
+
return !opts.json && !opts.yes && opts.isTTY && opts.baseCost > 0;
|
|
4398
|
+
}
|
|
4055
4399
|
async function runList(args) {
|
|
4056
4400
|
const catalog = await fetchCatalog({ summary: true });
|
|
4057
4401
|
if (args.json) {
|
|
@@ -4097,7 +4441,7 @@ async function runInfo(args) {
|
|
|
4097
4441
|
}
|
|
4098
4442
|
console.log(`${integration}/${endpoint}`);
|
|
4099
4443
|
console.log(
|
|
4100
|
-
` billing: ${info2.billing.
|
|
4444
|
+
` billing: ${formatCurrency(info2.billing.baseCost, info2.billing.currency)} ${billingUnit(info2.billing.model)}`
|
|
4101
4445
|
);
|
|
4102
4446
|
console.log();
|
|
4103
4447
|
console.log("Input schema:");
|
|
@@ -4112,6 +4456,31 @@ async function runInvoke(args) {
|
|
|
4112
4456
|
const { integration, endpoint } = parseTarget(args.target);
|
|
4113
4457
|
const body = resolveBody({ body: args.body, bodyFile: args.bodyFile });
|
|
4114
4458
|
const timeoutMs = args.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
4459
|
+
const interactive = isInteractive(process.stdin, process.stdout);
|
|
4460
|
+
if (!args.json && !args.yes && interactive) {
|
|
4461
|
+
let info2 = null;
|
|
4462
|
+
try {
|
|
4463
|
+
info2 = findEndpoint(await fetchCatalog({ summary: true }), integration, endpoint);
|
|
4464
|
+
} catch {
|
|
4465
|
+
console.error("Note: could not verify the call cost; proceeding. Pass --yes to skip this check.");
|
|
4466
|
+
info2 = null;
|
|
4467
|
+
}
|
|
4468
|
+
if (info2 && shouldConfirmCost({
|
|
4469
|
+
json: !!args.json,
|
|
4470
|
+
yes: !!args.yes,
|
|
4471
|
+
isTTY: interactive,
|
|
4472
|
+
baseCost: info2.billing.baseCost
|
|
4473
|
+
})) {
|
|
4474
|
+
const cost = formatCurrency(info2.billing.baseCost, info2.billing.currency);
|
|
4475
|
+
const ok2 = await p7.confirm({
|
|
4476
|
+
message: `${integration}/${endpoint} costs ${cost} ${billingUnit(info2.billing.model)}, billed to your account. Continue?`
|
|
4477
|
+
});
|
|
4478
|
+
if (p7.isCancel(ok2) || !ok2) {
|
|
4479
|
+
p7.cancel("Cancelled \u2014 no call made.");
|
|
4480
|
+
process.exit(0);
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4115
4484
|
let jwt;
|
|
4116
4485
|
try {
|
|
4117
4486
|
jwt = await ensureToken();
|
|
@@ -4254,6 +4623,12 @@ var invoke = defineCommand16({
|
|
|
4254
4623
|
type: "string",
|
|
4255
4624
|
description: "Request timeout in milliseconds (default: 120000)",
|
|
4256
4625
|
required: false
|
|
4626
|
+
},
|
|
4627
|
+
yes: {
|
|
4628
|
+
type: "boolean",
|
|
4629
|
+
alias: "y",
|
|
4630
|
+
description: "Skip the paid-call cost confirmation",
|
|
4631
|
+
default: false
|
|
4257
4632
|
}
|
|
4258
4633
|
},
|
|
4259
4634
|
async run({ args }) {
|
|
@@ -4267,7 +4642,8 @@ var invoke = defineCommand16({
|
|
|
4267
4642
|
body: args.body,
|
|
4268
4643
|
bodyFile: args["body-file"],
|
|
4269
4644
|
json: args.json,
|
|
4270
|
-
timeout
|
|
4645
|
+
timeout,
|
|
4646
|
+
yes: args.yes
|
|
4271
4647
|
});
|
|
4272
4648
|
} catch (err) {
|
|
4273
4649
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -4331,6 +4707,12 @@ var invoke_default = defineCommand17({
|
|
|
4331
4707
|
type: "string",
|
|
4332
4708
|
description: "Request timeout in milliseconds (default: 120000)",
|
|
4333
4709
|
required: false
|
|
4710
|
+
},
|
|
4711
|
+
yes: {
|
|
4712
|
+
type: "boolean",
|
|
4713
|
+
alias: "y",
|
|
4714
|
+
description: "Skip the paid-call cost confirmation",
|
|
4715
|
+
default: false
|
|
4334
4716
|
}
|
|
4335
4717
|
},
|
|
4336
4718
|
async run({ args }) {
|
|
@@ -4352,7 +4734,8 @@ var invoke_default = defineCommand17({
|
|
|
4352
4734
|
body: args.body,
|
|
4353
4735
|
bodyFile: args["body-file"],
|
|
4354
4736
|
json: args.json,
|
|
4355
|
-
timeout
|
|
4737
|
+
timeout,
|
|
4738
|
+
yes: args.yes
|
|
4356
4739
|
});
|
|
4357
4740
|
} catch (err) {
|
|
4358
4741
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -4363,10 +4746,10 @@ var invoke_default = defineCommand17({
|
|
|
4363
4746
|
|
|
4364
4747
|
// src/cli/commands/library.ts
|
|
4365
4748
|
import { defineCommand as defineCommand18 } from "citty";
|
|
4366
|
-
import { existsSync as existsSync12, readFileSync as
|
|
4367
|
-
import { join as
|
|
4749
|
+
import { existsSync as existsSync12, readFileSync as readFileSync14 } from "fs";
|
|
4750
|
+
import { join as join13, resolve as resolve9 } from "path";
|
|
4368
4751
|
import { parse as parseToml4 } from "smol-toml";
|
|
4369
|
-
import * as
|
|
4752
|
+
import * as p8 from "@clack/prompts";
|
|
4370
4753
|
var DEFAULT_LIBRARY_APP = "deepdotspace-site";
|
|
4371
4754
|
var publish = defineCommand18({
|
|
4372
4755
|
meta: {
|
|
@@ -4428,25 +4811,25 @@ var publish = defineCommand18({
|
|
|
4428
4811
|
async run({ args }) {
|
|
4429
4812
|
const json = !!args.json;
|
|
4430
4813
|
const intro6 = (s) => {
|
|
4431
|
-
if (!json)
|
|
4814
|
+
if (!json) p8.intro(s);
|
|
4432
4815
|
};
|
|
4433
4816
|
const info2 = (s) => {
|
|
4434
|
-
if (!json)
|
|
4817
|
+
if (!json) p8.log.info(s);
|
|
4435
4818
|
};
|
|
4436
4819
|
const die = (msg) => {
|
|
4437
4820
|
if (json) console.error(JSON.stringify({ ok: false, error: msg }));
|
|
4438
|
-
else
|
|
4821
|
+
else p8.cancel(msg);
|
|
4439
4822
|
process.exit(1);
|
|
4440
4823
|
};
|
|
4441
4824
|
intro6("Publishing to the DeepSpace library");
|
|
4442
4825
|
let appName = typeof args.app === "string" && args.app.trim() ? args.app.trim() : void 0;
|
|
4443
4826
|
if (!appName) {
|
|
4444
4827
|
const appDir = resolve9(typeof args.dir === "string" && args.dir ? args.dir : ".");
|
|
4445
|
-
const wranglerPath =
|
|
4828
|
+
const wranglerPath = join13(appDir, "wrangler.toml");
|
|
4446
4829
|
if (!existsSync12(wranglerPath)) {
|
|
4447
4830
|
return die("No --app provided and no wrangler.toml found. Either pass --app <name> or run from your app's directory.");
|
|
4448
4831
|
}
|
|
4449
|
-
const cfg = parseToml4(
|
|
4832
|
+
const cfg = parseToml4(readFileSync14(wranglerPath, "utf-8"));
|
|
4450
4833
|
const nameRes = resolveAppName(cfg.name);
|
|
4451
4834
|
if (!nameRes.ok) return die(`wrangler.toml: ${nameRes.reason}`);
|
|
4452
4835
|
appName = nameRes.name;
|
|
@@ -4502,9 +4885,9 @@ var publish = defineCommand18({
|
|
|
4502
4885
|
if (!parsed.success) {
|
|
4503
4886
|
return die(parsed.error ?? `Publish failed (HTTP ${res.status}).`);
|
|
4504
4887
|
}
|
|
4505
|
-
|
|
4506
|
-
if (parsed.data?.url)
|
|
4507
|
-
|
|
4888
|
+
p8.log.success(`Published ${appName} as ${parsed.data?.templateHandle} (v${parsed.data?.version})`);
|
|
4889
|
+
if (parsed.data?.url) p8.log.message(parsed.data.url);
|
|
4890
|
+
p8.outro("Done");
|
|
4508
4891
|
}
|
|
4509
4892
|
});
|
|
4510
4893
|
var unpublish = defineCommand18({
|
|
@@ -4533,10 +4916,10 @@ var unpublish = defineCommand18({
|
|
|
4533
4916
|
const json = !!args.json;
|
|
4534
4917
|
const die = (msg) => {
|
|
4535
4918
|
if (json) console.error(JSON.stringify({ ok: false, error: msg }));
|
|
4536
|
-
else
|
|
4919
|
+
else p8.cancel(msg);
|
|
4537
4920
|
process.exit(1);
|
|
4538
4921
|
};
|
|
4539
|
-
if (!json)
|
|
4922
|
+
if (!json) p8.intro("Unpublishing library entry");
|
|
4540
4923
|
let token;
|
|
4541
4924
|
try {
|
|
4542
4925
|
token = await ensureToken();
|
|
@@ -4562,8 +4945,8 @@ var unpublish = defineCommand18({
|
|
|
4562
4945
|
process.exit(parsed.success ? 0 : 1);
|
|
4563
4946
|
}
|
|
4564
4947
|
if (!parsed.success) return die(parsed.error ?? `HTTP ${res.status}`);
|
|
4565
|
-
|
|
4566
|
-
|
|
4948
|
+
p8.log.success(`Unpublished ${parsed.data?.templateHandle}`);
|
|
4949
|
+
p8.outro("Done");
|
|
4567
4950
|
}
|
|
4568
4951
|
});
|
|
4569
4952
|
var library_default = defineCommand18({
|
|
@@ -4579,10 +4962,10 @@ var library_default = defineCommand18({
|
|
|
4579
4962
|
|
|
4580
4963
|
// src/cli/commands/feedback.ts
|
|
4581
4964
|
import { defineCommand as defineCommand19 } from "citty";
|
|
4582
|
-
import * as
|
|
4583
|
-
import { existsSync as existsSync13, readFileSync as
|
|
4584
|
-
import { dirname as
|
|
4585
|
-
import { fileURLToPath } from "url";
|
|
4965
|
+
import * as p9 from "@clack/prompts";
|
|
4966
|
+
import { existsSync as existsSync13, readFileSync as readFileSync15 } from "fs";
|
|
4967
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
4968
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4586
4969
|
import { release } from "os";
|
|
4587
4970
|
var API_URL7 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
4588
4971
|
var TYPES = ["bug", "feature", "other"];
|
|
@@ -4602,14 +4985,14 @@ function normalizeType(raw) {
|
|
|
4602
4985
|
}
|
|
4603
4986
|
function readCliVersion() {
|
|
4604
4987
|
try {
|
|
4605
|
-
const here =
|
|
4988
|
+
const here = dirname4(fileURLToPath2(import.meta.url));
|
|
4606
4989
|
const candidates = [
|
|
4607
|
-
|
|
4608
|
-
|
|
4990
|
+
join14(here, "..", "package.json"),
|
|
4991
|
+
join14(here, "..", "..", "..", "package.json")
|
|
4609
4992
|
];
|
|
4610
4993
|
for (const path of candidates) {
|
|
4611
4994
|
if (!existsSync13(path)) continue;
|
|
4612
|
-
const pkg2 = JSON.parse(
|
|
4995
|
+
const pkg2 = JSON.parse(readFileSync15(path, "utf-8"));
|
|
4613
4996
|
if (pkg2.name === "deepspace" && pkg2.version) return pkg2.version;
|
|
4614
4997
|
}
|
|
4615
4998
|
} catch {
|
|
@@ -4714,21 +5097,21 @@ var feedback_default = defineCommand19({
|
|
|
4714
5097
|
);
|
|
4715
5098
|
}
|
|
4716
5099
|
if (interactive && (!args.type || !title || !body)) {
|
|
4717
|
-
|
|
5100
|
+
p9.intro("DeepSpace Feedback");
|
|
4718
5101
|
if (!args.type) {
|
|
4719
|
-
const picked = await
|
|
5102
|
+
const picked = await p9.select({
|
|
4720
5103
|
message: "What kind of feedback is this?",
|
|
4721
5104
|
options: TYPES.map((t) => ({ value: t, label: TYPE_LABELS[t] })),
|
|
4722
5105
|
initialValue: type
|
|
4723
5106
|
});
|
|
4724
|
-
if (
|
|
4725
|
-
|
|
5107
|
+
if (p9.isCancel(picked)) {
|
|
5108
|
+
p9.cancel("Cancelled.");
|
|
4726
5109
|
process.exit(0);
|
|
4727
5110
|
}
|
|
4728
5111
|
type = picked;
|
|
4729
5112
|
}
|
|
4730
5113
|
if (!title) {
|
|
4731
|
-
const t = await
|
|
5114
|
+
const t = await p9.text({
|
|
4732
5115
|
message: "Title",
|
|
4733
5116
|
placeholder: "Short summary of the issue",
|
|
4734
5117
|
validate: (v) => {
|
|
@@ -4738,14 +5121,14 @@ var feedback_default = defineCommand19({
|
|
|
4738
5121
|
return void 0;
|
|
4739
5122
|
}
|
|
4740
5123
|
});
|
|
4741
|
-
if (
|
|
4742
|
-
|
|
5124
|
+
if (p9.isCancel(t)) {
|
|
5125
|
+
p9.cancel("Cancelled.");
|
|
4743
5126
|
process.exit(0);
|
|
4744
5127
|
}
|
|
4745
5128
|
title = String(t);
|
|
4746
5129
|
}
|
|
4747
5130
|
if (!body) {
|
|
4748
|
-
const m = await
|
|
5131
|
+
const m = await p9.text({
|
|
4749
5132
|
message: "Details",
|
|
4750
5133
|
placeholder: "What happened? Steps to reproduce, what you expected\u2026",
|
|
4751
5134
|
validate: (v) => {
|
|
@@ -4755,8 +5138,8 @@ var feedback_default = defineCommand19({
|
|
|
4755
5138
|
return void 0;
|
|
4756
5139
|
}
|
|
4757
5140
|
});
|
|
4758
|
-
if (
|
|
4759
|
-
|
|
5141
|
+
if (p9.isCancel(m)) {
|
|
5142
|
+
p9.cancel("Cancelled.");
|
|
4760
5143
|
process.exit(0);
|
|
4761
5144
|
}
|
|
4762
5145
|
body = String(m);
|
|
@@ -4774,7 +5157,7 @@ var feedback_default = defineCommand19({
|
|
|
4774
5157
|
return fail2(err.message);
|
|
4775
5158
|
}
|
|
4776
5159
|
if (interactive && !args.yes) {
|
|
4777
|
-
|
|
5160
|
+
p9.note(
|
|
4778
5161
|
`${TYPE_LABELS[payload.type]}
|
|
4779
5162
|
${payload.title}
|
|
4780
5163
|
|
|
@@ -4783,9 +5166,9 @@ ${payload.body}
|
|
|
4783
5166
|
Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payload.platform}` + (payload.appName ? ` \xB7 app ${payload.appName}` : ""),
|
|
4784
5167
|
"Review"
|
|
4785
5168
|
);
|
|
4786
|
-
const ok = await
|
|
4787
|
-
if (
|
|
4788
|
-
|
|
5169
|
+
const ok = await p9.confirm({ message: "Send this to the DeepSpace team?" });
|
|
5170
|
+
if (p9.isCancel(ok) || !ok) {
|
|
5171
|
+
p9.cancel("Not sent.");
|
|
4789
5172
|
process.exit(0);
|
|
4790
5173
|
}
|
|
4791
5174
|
}
|
|
@@ -4809,7 +5192,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
4809
5192
|
return;
|
|
4810
5193
|
}
|
|
4811
5194
|
if (interactive) {
|
|
4812
|
-
|
|
5195
|
+
p9.outro(`Thanks! Submitted as ${result.report.id}.`);
|
|
4813
5196
|
} else {
|
|
4814
5197
|
console.log(`Submitted feedback ${result.report.id} (${result.report.type}).`);
|
|
4815
5198
|
}
|
|
@@ -4819,8 +5202,18 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
4819
5202
|
|
|
4820
5203
|
// src/cli/commands/secrets.ts
|
|
4821
5204
|
import { defineCommand as defineCommand20 } from "citty";
|
|
4822
|
-
import { readFileSync as
|
|
4823
|
-
|
|
5205
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
5206
|
+
|
|
5207
|
+
// src/cli/lib/citty-args.ts
|
|
5208
|
+
function dedupePositionals(bound, rest) {
|
|
5209
|
+
const restArr = Array.isArray(rest) ? rest : [];
|
|
5210
|
+
return [.../* @__PURE__ */ new Set([bound, ...restArr])].filter(
|
|
5211
|
+
(v) => typeof v === "string" && v.length > 0
|
|
5212
|
+
);
|
|
5213
|
+
}
|
|
5214
|
+
|
|
5215
|
+
// src/cli/commands/secrets.ts
|
|
5216
|
+
var DEPLOY_URL8 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
4824
5217
|
var COMMON_ARGS = {
|
|
4825
5218
|
app: {
|
|
4826
5219
|
type: "string",
|
|
@@ -4877,6 +5270,7 @@ function warnIfDebugRoutesEnabled(secrets) {
|
|
|
4877
5270
|
return true;
|
|
4878
5271
|
}
|
|
4879
5272
|
var APPLY_HINT = "Run `deepspace deploy` to apply \u2014 secrets take effect at deploy time.";
|
|
5273
|
+
var LOCAL_DEV_HINT = "Running `deepspace dev`? Restart it to load the change locally.";
|
|
4880
5274
|
var list5 = defineCommand20({
|
|
4881
5275
|
meta: { name: "list", description: "List masked secrets in a config" },
|
|
4882
5276
|
args: {
|
|
@@ -4891,7 +5285,7 @@ var list5 = defineCommand20({
|
|
|
4891
5285
|
async run({ args }) {
|
|
4892
5286
|
try {
|
|
4893
5287
|
const t = await resolveTarget(args);
|
|
4894
|
-
const { secrets } = await listSecrets(
|
|
5288
|
+
const { secrets } = await listSecrets(DEPLOY_URL8, t.token, t.appId, t.configName);
|
|
4895
5289
|
if (args.json) {
|
|
4896
5290
|
console.log(JSON.stringify({ appId: t.appId, config: t.configName, secrets }, null, 2));
|
|
4897
5291
|
return;
|
|
@@ -4917,9 +5311,7 @@ var set = defineCommand20({
|
|
|
4917
5311
|
async run({ args }) {
|
|
4918
5312
|
try {
|
|
4919
5313
|
const t = await resolveTarget(args);
|
|
4920
|
-
const pairs =
|
|
4921
|
-
(v) => typeof v === "string" && v.length > 0
|
|
4922
|
-
);
|
|
5314
|
+
const pairs = dedupePositionals(args.secret, args._);
|
|
4923
5315
|
const secrets = {};
|
|
4924
5316
|
const dupes = [];
|
|
4925
5317
|
for (const pair of pairs) {
|
|
@@ -4938,12 +5330,15 @@ var set = defineCommand20({
|
|
|
4938
5330
|
}
|
|
4939
5331
|
if (Object.keys(secrets).length === 1) {
|
|
4940
5332
|
const [[k, v]] = Object.entries(secrets);
|
|
4941
|
-
await setSecret(
|
|
5333
|
+
await setSecret(DEPLOY_URL8, t.token, t.appId, t.configName, k, v);
|
|
4942
5334
|
} else {
|
|
4943
|
-
await uploadSecrets(
|
|
5335
|
+
await uploadSecrets(DEPLOY_URL8, t.token, t.appId, t.configName, secrets, false);
|
|
4944
5336
|
}
|
|
4945
5337
|
console.log(`Set ${Object.keys(secrets).length} secret${Object.keys(secrets).length === 1 ? "" : "s"} in ${t.configName}.`);
|
|
4946
|
-
if (!warnIfDebugRoutesEnabled(secrets))
|
|
5338
|
+
if (!warnIfDebugRoutesEnabled(secrets)) {
|
|
5339
|
+
console.log(APPLY_HINT);
|
|
5340
|
+
console.log(LOCAL_DEV_HINT);
|
|
5341
|
+
}
|
|
4947
5342
|
} catch (err) {
|
|
4948
5343
|
fail(err);
|
|
4949
5344
|
}
|
|
@@ -4961,11 +5356,11 @@ var get = defineCommand20({
|
|
|
4961
5356
|
const t = await resolveTarget(args);
|
|
4962
5357
|
const key = validateSecretName(args.key);
|
|
4963
5358
|
if (args.plain) {
|
|
4964
|
-
const { value } = await getSecretPlain(
|
|
5359
|
+
const { value } = await getSecretPlain(DEPLOY_URL8, t.token, t.appId, t.configName, key);
|
|
4965
5360
|
process.stdout.write(process.stdout.isTTY ? value + "\n" : value);
|
|
4966
5361
|
return;
|
|
4967
5362
|
}
|
|
4968
|
-
const { secrets } = await listSecrets(
|
|
5363
|
+
const { secrets } = await listSecrets(DEPLOY_URL8, t.token, t.appId, t.configName);
|
|
4969
5364
|
const item = secrets.find((s) => s.key === key);
|
|
4970
5365
|
if (!item) fail(new Error(`Secret "${key}" not found in ${t.configName}`));
|
|
4971
5366
|
console.log(`${item.key} (v${item.version}, ${item.updatedAt})`);
|
|
@@ -4983,15 +5378,13 @@ var del2 = defineCommand20({
|
|
|
4983
5378
|
async run({ args }) {
|
|
4984
5379
|
try {
|
|
4985
5380
|
const t = await resolveTarget(args);
|
|
4986
|
-
const keys =
|
|
4987
|
-
(v) => typeof v === "string" && v.length > 0
|
|
4988
|
-
);
|
|
5381
|
+
const keys = dedupePositionals(args.key, args._);
|
|
4989
5382
|
let deleted = 0;
|
|
4990
5383
|
let absent = 0;
|
|
4991
5384
|
for (const key of keys) {
|
|
4992
5385
|
const name = validateSecretName(key);
|
|
4993
5386
|
try {
|
|
4994
|
-
await deleteSecret(
|
|
5387
|
+
await deleteSecret(DEPLOY_URL8, t.token, t.appId, t.configName, name);
|
|
4995
5388
|
deleted++;
|
|
4996
5389
|
} catch (err) {
|
|
4997
5390
|
if (err?.status === 404) absent++;
|
|
@@ -5020,10 +5413,10 @@ var upload = defineCommand20({
|
|
|
5020
5413
|
async run({ args }) {
|
|
5021
5414
|
try {
|
|
5022
5415
|
const t = await resolveTarget(args);
|
|
5023
|
-
const content = args.file === "-" ?
|
|
5416
|
+
const content = args.file === "-" ? readFileSync16(0, "utf-8") : readFileSync16(args.file, "utf-8");
|
|
5024
5417
|
const secrets = parseSecretsUpload(content);
|
|
5025
5418
|
if (Object.keys(secrets).length === 0) fail(new Error("No secrets found in the input."));
|
|
5026
|
-
await uploadSecrets(
|
|
5419
|
+
await uploadSecrets(DEPLOY_URL8, t.token, t.appId, t.configName, secrets, args.replace);
|
|
5027
5420
|
console.log(`Uploaded ${Object.keys(secrets).length} secrets to ${t.configName}.`);
|
|
5028
5421
|
if (!warnIfDebugRoutesEnabled(secrets)) console.log(APPLY_HINT);
|
|
5029
5422
|
} catch (err) {
|
|
@@ -5048,7 +5441,7 @@ var download = defineCommand20({
|
|
|
5048
5441
|
if (!["dotenv", "json", "shell"].includes(format)) {
|
|
5049
5442
|
fail(new Error(`Unknown format "${args.format}" \u2014 use dotenv, json, or shell.`));
|
|
5050
5443
|
}
|
|
5051
|
-
const { secrets } = await fetchSecretsValues(
|
|
5444
|
+
const { secrets } = await fetchSecretsValues(DEPLOY_URL8, t.token, t.appId, t.configName);
|
|
5052
5445
|
process.stdout.write(formatSecretsDownload(secrets, format));
|
|
5053
5446
|
} catch (err) {
|
|
5054
5447
|
fail(err);
|
|
@@ -5065,7 +5458,7 @@ var pull = defineCommand20({
|
|
|
5065
5458
|
if (!appDir) fail(new Error("Run from a DeepSpace app directory (one containing wrangler.toml)."));
|
|
5066
5459
|
const t = await resolveTarget(args);
|
|
5067
5460
|
const ownerId = decodeJwtPayload(t.token).sub;
|
|
5068
|
-
const pulled = await pullAppSecretsCache(
|
|
5461
|
+
const pulled = await pullAppSecretsCache(DEPLOY_URL8, t.token, t.appId, t.configName);
|
|
5069
5462
|
if (!pulled) {
|
|
5070
5463
|
console.log(`No secrets in ${t.configName} yet \u2014 nothing to pull.`);
|
|
5071
5464
|
return;
|
|
@@ -5089,7 +5482,7 @@ var configsList = defineCommand20({
|
|
|
5089
5482
|
async run({ args }) {
|
|
5090
5483
|
try {
|
|
5091
5484
|
const t = await resolveTarget(args);
|
|
5092
|
-
const { configs: configs2 } = await listConfigs(
|
|
5485
|
+
const { configs: configs2 } = await listConfigs(DEPLOY_URL8, t.token, t.appId);
|
|
5093
5486
|
if (configs2.length === 0) {
|
|
5094
5487
|
console.log("No configs yet \u2014 the first `secrets set` creates one.");
|
|
5095
5488
|
return;
|
|
@@ -5114,7 +5507,7 @@ var configsCreate = defineCommand20({
|
|
|
5114
5507
|
const t = await resolveTarget(args);
|
|
5115
5508
|
const name = validateConfigName(args.name);
|
|
5116
5509
|
const copyFrom = args["copy-from"] || void 0;
|
|
5117
|
-
const { configs: configs2 } = await listConfigs(
|
|
5510
|
+
const { configs: configs2 } = await listConfigs(DEPLOY_URL8, t.token, t.appId);
|
|
5118
5511
|
if (configs2.some((c) => c.name === name)) {
|
|
5119
5512
|
if (copyFrom) {
|
|
5120
5513
|
fail(
|
|
@@ -5126,7 +5519,7 @@ var configsCreate = defineCommand20({
|
|
|
5126
5519
|
console.log(`Config ${name} already exists.`);
|
|
5127
5520
|
return;
|
|
5128
5521
|
}
|
|
5129
|
-
await createConfig(
|
|
5522
|
+
await createConfig(DEPLOY_URL8, t.token, t.appId, name, copyFrom);
|
|
5130
5523
|
console.log(`Created ${name}.`);
|
|
5131
5524
|
} catch (err) {
|
|
5132
5525
|
fail(err);
|
|
@@ -5143,7 +5536,7 @@ var configsDelete = defineCommand20({
|
|
|
5143
5536
|
try {
|
|
5144
5537
|
const t = await resolveTarget(args);
|
|
5145
5538
|
const name = validateConfigName(args.name);
|
|
5146
|
-
await deleteConfig(
|
|
5539
|
+
await deleteConfig(DEPLOY_URL8, t.token, t.appId, name);
|
|
5147
5540
|
console.log(`Deleted ${name}.`);
|
|
5148
5541
|
} catch (err) {
|
|
5149
5542
|
fail(err);
|
|
@@ -5215,28 +5608,36 @@ var init_default = defineCommand21({
|
|
|
5215
5608
|
});
|
|
5216
5609
|
|
|
5217
5610
|
// src/cli/cli.ts
|
|
5218
|
-
var __dirname =
|
|
5219
|
-
var pkg = JSON.parse(
|
|
5611
|
+
var __dirname = dirname5(fileURLToPath3(import.meta.url));
|
|
5612
|
+
var pkg = JSON.parse(readFileSync17(join15(__dirname, "..", "package.json"), "utf-8"));
|
|
5220
5613
|
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync14("/etc/ssl/certs/ca-certificates.crt")) {
|
|
5221
5614
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
5222
5615
|
}
|
|
5223
5616
|
var create2 = defineCommand22({
|
|
5224
5617
|
meta: {
|
|
5225
5618
|
name: "create",
|
|
5226
|
-
description: "Create a new DeepSpace app"
|
|
5619
|
+
description: "Create a new DeepSpace app (runs create-deepspace; all flags are forwarded)"
|
|
5227
5620
|
},
|
|
5228
5621
|
args: {
|
|
5229
5622
|
name: {
|
|
5230
5623
|
type: "positional",
|
|
5231
5624
|
description: "App name",
|
|
5232
5625
|
required: false
|
|
5626
|
+
},
|
|
5627
|
+
interactive: {
|
|
5628
|
+
type: "boolean",
|
|
5629
|
+
description: "Prompt for options instead of using defaults"
|
|
5630
|
+
},
|
|
5631
|
+
local: {
|
|
5632
|
+
type: "string",
|
|
5633
|
+
description: "Use a local SDK monorepo checkout instead of the published package"
|
|
5233
5634
|
}
|
|
5234
5635
|
},
|
|
5235
|
-
run({
|
|
5236
|
-
const
|
|
5237
|
-
console.log(`Running:
|
|
5238
|
-
|
|
5239
|
-
|
|
5636
|
+
run({ rawArgs }) {
|
|
5637
|
+
const scaffolder = `create-deepspace@${pkg.version}`;
|
|
5638
|
+
console.log(`Running: npx ${scaffolder} ${rawArgs.join(" ")}`.trimEnd() + "\n");
|
|
5639
|
+
const res = spawnSync6("npx", ["-y", scaffolder, ...rawArgs], { stdio: "inherit" });
|
|
5640
|
+
process.exit(res.status ?? 1);
|
|
5240
5641
|
}
|
|
5241
5642
|
});
|
|
5242
5643
|
var main = defineCommand22({
|
|
@@ -5251,13 +5652,13 @@ var main = defineCommand22({
|
|
|
5251
5652
|
login: login_default,
|
|
5252
5653
|
logout: logout_default,
|
|
5253
5654
|
whoami: whoami_default,
|
|
5655
|
+
apps: apps_default,
|
|
5254
5656
|
dev: dev_default,
|
|
5255
5657
|
kill: kill_default,
|
|
5256
5658
|
test: test_default,
|
|
5257
5659
|
screenshot: screenshot_default,
|
|
5258
5660
|
"test-accounts": test_accounts_default,
|
|
5259
5661
|
add: add_default,
|
|
5260
|
-
skills: skills_default,
|
|
5261
5662
|
integrations: integrations_default,
|
|
5262
5663
|
invoke: invoke_default,
|
|
5263
5664
|
deploy: deploy_default,
|