deepspace 0.3.11 → 0.4.0

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 CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/cli.ts
4
- import { defineCommand as defineCommand18, runMain } from "citty";
4
+ import { defineCommand as defineCommand19, runMain } from "citty";
5
5
  import { execSync as execSync5 } from "child_process";
6
- import { readFileSync as readFileSync10, existsSync as existsSync13 } from "fs";
7
- import { dirname as dirname2, join as join14 } from "path";
6
+ import { readFileSync as readFileSync11, existsSync as existsSync14 } from "fs";
7
+ import { dirname as dirname2, join as join16 } from "path";
8
8
  import { fileURLToPath } from "url";
9
9
 
10
10
  // src/cli/commands/login.ts
@@ -14,6 +14,7 @@ import { join as join2 } from "path";
14
14
  import { homedir } from "os";
15
15
  import { exec } from "child_process";
16
16
  import { platform } from "os";
17
+ import { randomBytes, createHash } from "crypto";
17
18
  import * as p2 from "@clack/prompts";
18
19
 
19
20
  // src/cli/lib/spinner.ts
@@ -180,7 +181,6 @@ var SDK_MANAGED_KEYS = /* @__PURE__ */ new Set([
180
181
  "OWNER_USER_ID",
181
182
  "APP_OWNER_JWT",
182
183
  "APP_IDENTITY_TOKEN",
183
- "INTERNAL_STORAGE_HMAC_SECRET",
184
184
  "ALLOW_DEBUG_ROUTES"
185
185
  ]);
186
186
  var DEV_VARS_DIVIDER = "# --- not managed by the SDK; preserved across dev/test runs ---";
@@ -302,7 +302,6 @@ async function writeDevVars(appDir, env, ownerId, callerJwt) {
302
302
  `OWNER_USER_ID=${ownerId}`,
303
303
  `APP_OWNER_JWT=${appOwnerJwt}`,
304
304
  ...appIdentityToken ? [`APP_IDENTITY_TOKEN=${appIdentityToken}`] : [],
305
- `INTERNAL_STORAGE_HMAC_SECRET=dev-${Date.now()}`,
306
305
  // Open /api/debug/* (proxied to RecordRoom) for dev + tests only.
307
306
  // Production secrets never set this, so deployed apps 404 the route.
308
307
  `ALLOW_DEBUG_ROUTES=true`
@@ -363,7 +362,13 @@ var login_default = defineCommand({
363
362
  p2.intro("DeepSpace Login");
364
363
  const s = createSpinner();
365
364
  s.start("Creating login session...");
366
- const sessionRes = await fetch(`${AUTH_URL}/api/auth/cli/session`, { method: "POST" });
365
+ const codeVerifier = base64url(randomBytes(32));
366
+ const codeChallenge = base64url(createHash("sha256").update(codeVerifier).digest());
367
+ const sessionRes = await fetch(`${AUTH_URL}/api/auth/cli/session`, {
368
+ method: "POST",
369
+ headers: { "Content-Type": "application/json" },
370
+ body: JSON.stringify({ code_challenge: codeChallenge })
371
+ });
367
372
  if (!sessionRes.ok) {
368
373
  s.stop("Failed");
369
374
  p2.cancel("Could not create login session");
@@ -381,7 +386,7 @@ var login_default = defineCommand({
381
386
  ${loginUrl}`);
382
387
  openBrowser(loginUrl);
383
388
  s.start("Waiting for authentication...");
384
- const result = await pollForCompletion(sessionId);
389
+ const result = await pollForCompletion(sessionId, codeVerifier);
385
390
  if (!result) {
386
391
  s.stop("Timed out");
387
392
  p2.cancel("Login timed out. Run `deepspace login` to try again.");
@@ -400,13 +405,15 @@ plans on the web dashboard:
400
405
  p2.outro("Done");
401
406
  }
402
407
  });
403
- async function pollForCompletion(sessionId) {
408
+ async function pollForCompletion(sessionId, codeVerifier) {
404
409
  const maxAttempts = 120;
405
410
  const interval = 5e3;
406
411
  for (let i = 0; i < maxAttempts; i++) {
407
412
  await sleep(interval);
408
413
  try {
409
- const res = await fetch(`${AUTH_URL}/api/auth/cli/status/${sessionId}`);
414
+ const res = await fetch(`${AUTH_URL}/api/auth/cli/status/${sessionId}`, {
415
+ headers: { "x-code-verifier": codeVerifier }
416
+ });
410
417
  if (res.status === 410 || res.status === 404) return null;
411
418
  if (!res.ok) continue;
412
419
  const data = await res.json();
@@ -425,7 +432,7 @@ async function pollForCompletion(sessionId) {
425
432
  }
426
433
  function storeCredentials(sessionToken, jwt) {
427
434
  const dir = join2(homedir(), ".deepspace");
428
- mkdirSync(dir, { recursive: true });
435
+ mkdirSync(dir, { recursive: true, mode: 448 });
429
436
  writeFileSync2(join2(dir, "session"), sessionToken, { mode: 384 });
430
437
  writeFileSync2(join2(dir, "token"), jwt, { mode: 384 });
431
438
  }
@@ -437,6 +444,9 @@ function openBrowser(url) {
437
444
  function sleep(ms) {
438
445
  return new Promise((resolve9) => setTimeout(resolve9, ms));
439
446
  }
447
+ function base64url(bytes) {
448
+ return bytes.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
449
+ }
440
450
  async function doEmailLogin(email, password) {
441
451
  const res = await fetch(`${AUTH_URL}/api/auth/sign-in/email`, {
442
452
  method: "POST",
@@ -506,8 +516,8 @@ var logout_default = defineCommand2({
506
516
 
507
517
  // src/cli/commands/dev.ts
508
518
  import { defineCommand as defineCommand3 } from "citty";
509
- import { existsSync as existsSync5 } from "fs";
510
- import { join as join5, resolve as resolve2 } from "path";
519
+ import { existsSync as existsSync6 } from "fs";
520
+ import { join as join6, resolve as resolve2 } from "path";
511
521
  import spawn from "cross-spawn";
512
522
 
513
523
  // src/cli/auth.ts
@@ -544,7 +554,7 @@ async function ensureToken() {
544
554
  if (!token2) {
545
555
  throw new Error("Session expired. Run `deepspace login` to re-authenticate.");
546
556
  }
547
- mkdirSync2(DIR2, { recursive: true });
557
+ mkdirSync2(DIR2, { recursive: true, mode: 448 });
548
558
  writeFileSync3(TOKEN_PATH2, token2, { mode: 384 });
549
559
  return token2;
550
560
  }
@@ -557,9 +567,37 @@ function isTokenValid(jwt) {
557
567
  }
558
568
  }
559
569
 
570
+ // src/cli/lib/install-status.ts
571
+ import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
572
+ import { join as join5 } from "path";
573
+ function ensureInstallReady(appDir) {
574
+ if (existsSync4(join5(appDir, "node_modules", "deepspace", "package.json"))) return;
575
+ const sentinelDir = join5(appDir, ".deepspace");
576
+ const errPath = join5(sentinelDir, "install.err");
577
+ const startedPath = join5(sentinelDir, "install.started");
578
+ const donePath = join5(sentinelDir, "install.done");
579
+ const logPath = join5(sentinelDir, "install.log");
580
+ if (existsSync4(errPath)) {
581
+ console.error("Background install failed:");
582
+ console.error(readFileSync4(errPath, "utf-8").trimEnd());
583
+ if (existsSync4(logPath)) console.error(`
584
+ Full log: ${logPath}`);
585
+ console.error("\nRun `npm install` (or `bun install`) manually, then retry.");
586
+ process.exit(1);
587
+ }
588
+ if (existsSync4(startedPath) && !existsSync4(donePath)) {
589
+ console.error("Dependencies are still installing in the background.");
590
+ if (existsSync4(logPath)) console.error(`Tail progress: tail -f ${logPath}`);
591
+ console.error("Retry once it finishes.");
592
+ process.exit(1);
593
+ }
594
+ console.error("Dependencies not installed. Run `npm install` (or `bun install`) first.");
595
+ process.exit(1);
596
+ }
597
+
560
598
  // src/cli/lib/preflight.ts
561
599
  import { execFileSync } from "child_process";
562
- import { existsSync as existsSync4 } from "fs";
600
+ import { existsSync as existsSync5 } from "fs";
563
601
  import { resolve } from "path";
564
602
  var DLL_NOT_FOUND = -1073741515;
565
603
  function preflightWindowsWorkerd(appDir) {
@@ -572,7 +610,7 @@ function preflightWindowsWorkerd(appDir) {
572
610
  "bin",
573
611
  "workerd.exe"
574
612
  );
575
- if (!existsSync4(workerdExe)) return;
613
+ if (!existsSync5(workerdExe)) return;
576
614
  try {
577
615
  execFileSync(workerdExe, ["--help"], { stdio: "pipe", timeout: 1e4 });
578
616
  return;
@@ -622,10 +660,11 @@ var dev_default = defineCommand3({
622
660
  const appDir = resolve2(args.dir ?? ".");
623
661
  const env = args.prod ? "prod" : "dev";
624
662
  const port = resolvePort(args.port);
625
- if (!existsSync5(join5(appDir, "wrangler.toml"))) {
663
+ if (!existsSync6(join6(appDir, "wrangler.toml"))) {
626
664
  console.error("No wrangler.toml found. Are you in a DeepSpace app directory?");
627
665
  process.exit(1);
628
666
  }
667
+ ensureInstallReady(appDir);
629
668
  let token2;
630
669
  try {
631
670
  token2 = await ensureToken();
@@ -834,8 +873,8 @@ function isAlive(pid) {
834
873
 
835
874
  // src/cli/commands/test.ts
836
875
  import { defineCommand as defineCommand5 } from "citty";
837
- import { existsSync as existsSync6 } from "fs";
838
- import { join as join6, resolve as resolve3 } from "path";
876
+ import { existsSync as existsSync7 } from "fs";
877
+ import { join as join7, resolve as resolve3 } from "path";
839
878
  import { sync as spawnSync3 } from "cross-spawn";
840
879
 
841
880
  // src/cli/lib/playwright.ts
@@ -885,10 +924,11 @@ var test_default = defineCommand5({
885
924
  const appDir = resolve3(".");
886
925
  const suite = args.suite ?? "default";
887
926
  const port = resolvePort3(args.port);
888
- if (!existsSync6(join6(appDir, "wrangler.toml"))) {
927
+ if (!existsSync7(join7(appDir, "wrangler.toml"))) {
889
928
  console.error("No wrangler.toml found. Are you in a DeepSpace app directory?");
890
929
  process.exit(1);
891
930
  }
931
+ ensureInstallReady(appDir);
892
932
  let token2;
893
933
  let ownerId;
894
934
  try {
@@ -1019,17 +1059,17 @@ var screenshot_default = defineCommand6({
1019
1059
  // src/cli/commands/test-accounts.ts
1020
1060
  import { defineCommand as defineCommand7 } from "citty";
1021
1061
  import * as p3 from "@clack/prompts";
1022
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
1023
- import { join as join7 } from "path";
1062
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
1063
+ import { join as join8 } from "path";
1024
1064
  import { homedir as homedir4 } from "os";
1025
1065
  var SESSION_COOKIE2 = "__Secure-better-auth.session_token";
1026
1066
  var AUTH_URL4 = process.env.DEEPSPACE_AUTH_URL ?? ENVS.prod.auth;
1027
- var DIR3 = join7(homedir4(), ".deepspace");
1028
- var ACCOUNTS_PATH = join7(DIR3, "test-accounts.json");
1067
+ var DIR3 = join8(homedir4(), ".deepspace");
1068
+ var ACCOUNTS_PATH = join8(DIR3, "test-accounts.json");
1029
1069
  function loadAccounts() {
1030
- if (!existsSync7(ACCOUNTS_PATH)) return [];
1070
+ if (!existsSync8(ACCOUNTS_PATH)) return [];
1031
1071
  try {
1032
- return JSON.parse(readFileSync4(ACCOUNTS_PATH, "utf-8"));
1072
+ return JSON.parse(readFileSync5(ACCOUNTS_PATH, "utf-8"));
1033
1073
  } catch {
1034
1074
  return [];
1035
1075
  }
@@ -1039,7 +1079,7 @@ function saveAccounts(accounts) {
1039
1079
  writeFileSync4(ACCOUNTS_PATH, JSON.stringify(accounts, null, 2), { mode: 384 });
1040
1080
  }
1041
1081
  function sessionCookie() {
1042
- const token2 = readFileSync4(SESSION_PATH2, "utf-8").trim();
1082
+ const token2 = readFileSync5(SESSION_PATH2, "utf-8").trim();
1043
1083
  return `${SESSION_COOKIE2}=${encodeURIComponent(token2)}`;
1044
1084
  }
1045
1085
  async function fetchRemoteAccounts() {
@@ -1306,9 +1346,9 @@ var test_accounts_default = defineCommand7({
1306
1346
  // src/cli/commands/deploy.ts
1307
1347
  import { defineCommand as defineCommand8 } from "citty";
1308
1348
  import { execSync as execSync2 } from "child_process";
1309
- import { readFileSync as readFileSync5, readdirSync, existsSync as existsSync8 } from "fs";
1349
+ import { readFileSync as readFileSync6, readdirSync, existsSync as existsSync9 } from "fs";
1310
1350
  import { parse as parseToml2 } from "smol-toml";
1311
- import { join as join8, resolve as resolve5, dirname } from "path";
1351
+ import { join as join9, resolve as resolve5, dirname } from "path";
1312
1352
  import { pathToFileURL } from "url";
1313
1353
  import * as p4 from "@clack/prompts";
1314
1354
 
@@ -1337,7 +1377,6 @@ var RESERVED_BINDING_NAMES = /* @__PURE__ */ new Set([
1337
1377
  "AUTH_WORKER_URL",
1338
1378
  "APP_IDENTITY_TOKEN",
1339
1379
  "APP_OWNER_JWT",
1340
- "INTERNAL_STORAGE_HMAC_SECRET",
1341
1380
  "USAGE_EVENTS"
1342
1381
  ]);
1343
1382
  function validateBindingManifest(manifest) {
@@ -1518,6 +1557,7 @@ function asObjectArray(v) {
1518
1557
  // src/cli/commands/deploy.ts
1519
1558
  var DEPLOY_URL = process.env.DEEPSPACE_DEPLOY_URL ?? ENVS.prod.deploy;
1520
1559
  var API_URL = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
1560
+ var CLOUDFLARE_DEPLOY_ERROR_HINT = "Deployment reached the DeepSpace deploy worker, but Cloudflare's deployment control-plane API failed. This is often caused by a Cloudflare Dashboard/API incident or Workers for Platforms entitlement outage. Already deployed apps should keep serving; wait for Cloudflare to recover and retry.";
1521
1561
  var RESERVED_RUN_WORKER_FIRST = /* @__PURE__ */ new Set([
1522
1562
  "/api/*",
1523
1563
  "/ws/*",
@@ -1541,6 +1581,24 @@ function extractRunWorkerFirst(cfg) {
1541
1581
  }
1542
1582
  return out;
1543
1583
  }
1584
+ function isLikelyCloudflareDeployFailure(status2, error) {
1585
+ if (status2 >= 500) return true;
1586
+ if (!error) return false;
1587
+ return [
1588
+ "Upload session failed",
1589
+ "Asset upload failed",
1590
+ "Worker deploy failed",
1591
+ "entitlements.not_available",
1592
+ "Internal Server Error"
1593
+ ].some((needle) => error.includes(needle));
1594
+ }
1595
+ function formatDeployWorkerError(status2, error) {
1596
+ const detail = error ?? `Deployment error (${status2})`;
1597
+ if (!isLikelyCloudflareDeployFailure(status2, error)) return detail;
1598
+ return `${CLOUDFLARE_DEPLOY_ERROR_HINT}
1599
+
1600
+ Underlying error: ${detail}`;
1601
+ }
1544
1602
  var deploy_default = defineCommand8({
1545
1603
  meta: {
1546
1604
  name: "deploy",
@@ -1555,13 +1613,14 @@ var deploy_default = defineCommand8({
1555
1613
  },
1556
1614
  async run({ args }) {
1557
1615
  const appDir = resolve5(args.dir ?? ".");
1558
- p4.intro("Deploying DeepSpace app");
1559
- const wranglerPath = join8(appDir, "wrangler.toml");
1560
- if (!existsSync8(wranglerPath)) {
1561
- p4.cancel("No wrangler.toml found. Are you in a DeepSpace app directory?");
1616
+ const wranglerPath = join9(appDir, "wrangler.toml");
1617
+ if (!existsSync9(wranglerPath)) {
1618
+ console.error("No wrangler.toml found. Are you in a DeepSpace app directory?");
1562
1619
  process.exit(1);
1563
1620
  }
1564
- const wranglerConfig = parseToml2(readFileSync5(wranglerPath, "utf-8"));
1621
+ ensureInstallReady(appDir);
1622
+ p4.intro("Deploying DeepSpace app");
1623
+ const wranglerConfig = parseToml2(readFileSync6(wranglerPath, "utf-8"));
1565
1624
  const nameRes = resolveAppName(wranglerConfig.name);
1566
1625
  if (!nameRes.ok) {
1567
1626
  p4.cancel(`wrangler.toml: ${nameRes.reason}`);
@@ -1592,33 +1651,33 @@ var deploy_default = defineCommand8({
1592
1651
  process.exit(1);
1593
1652
  }
1594
1653
  s.stop("Built");
1595
- const deployConfigPath = join8(appDir, ".wrangler", "deploy", "config.json");
1596
- if (!existsSync8(deployConfigPath)) {
1654
+ const deployConfigPath = join9(appDir, ".wrangler", "deploy", "config.json");
1655
+ if (!existsSync9(deployConfigPath)) {
1597
1656
  p4.cancel("Build output config not found at .wrangler/deploy/config.json");
1598
1657
  process.exit(1);
1599
1658
  }
1600
- const deployConfig = JSON.parse(readFileSync5(deployConfigPath, "utf-8"));
1659
+ const deployConfig = JSON.parse(readFileSync6(deployConfigPath, "utf-8"));
1601
1660
  const outputWranglerPath = resolve5(dirname(deployConfigPath), deployConfig.configPath);
1602
- if (!existsSync8(outputWranglerPath)) {
1661
+ if (!existsSync9(outputWranglerPath)) {
1603
1662
  p4.cancel(`Output wrangler.json not found at ${outputWranglerPath}`);
1604
1663
  process.exit(1);
1605
1664
  }
1606
- const outputConfig = JSON.parse(readFileSync5(outputWranglerPath, "utf-8"));
1665
+ const outputConfig = JSON.parse(readFileSync6(outputWranglerPath, "utf-8"));
1607
1666
  const workerDir = dirname(outputWranglerPath);
1608
- const workerBundlePath = join8(workerDir, outputConfig.main);
1667
+ const workerBundlePath = join9(workerDir, outputConfig.main);
1609
1668
  const clientDir = outputConfig.assets?.directory ? resolve5(workerDir, outputConfig.assets.directory) : null;
1610
- if (!existsSync8(workerBundlePath)) {
1669
+ if (!existsSync9(workerBundlePath)) {
1611
1670
  p4.cancel(`Worker bundle not found at ${workerBundlePath}`);
1612
1671
  process.exit(1);
1613
1672
  }
1614
- if (!clientDir || !existsSync8(clientDir)) {
1673
+ if (!clientDir || !existsSync9(clientDir)) {
1615
1674
  p4.cancel(`Client assets not found at ${clientDir}`);
1616
1675
  process.exit(1);
1617
1676
  }
1618
1677
  s.start("Collecting assets...");
1619
1678
  const assets = collectAssets(clientDir);
1620
1679
  s.stop(`Collected ${assets.length} assets`);
1621
- const workerJs = readFileSync5(workerBundlePath, "utf-8");
1680
+ const workerJs = readFileSync6(workerBundlePath, "utf-8");
1622
1681
  const doBindings = outputConfig.durable_objects?.bindings;
1623
1682
  const sqliteClasses = new Set(
1624
1683
  outputConfig.migrations?.flatMap((m) => m.new_sqlite_classes ?? []) ?? []
@@ -1645,10 +1704,10 @@ var deploy_default = defineCommand8({
1645
1704
  `Custom bindings: ${customBindings.map((b) => `${b.name} (${b.type})`).join(", ")}`
1646
1705
  );
1647
1706
  }
1648
- const devVarsPath = join8(appDir, ".dev.vars");
1707
+ const devVarsPath = join9(appDir, ".dev.vars");
1649
1708
  let userSecrets = {};
1650
- if (existsSync8(devVarsPath)) {
1651
- const customSection = extractCustomDevVars(readFileSync5(devVarsPath, "utf-8"));
1709
+ if (existsSync9(devVarsPath)) {
1710
+ const customSection = extractCustomDevVars(readFileSync6(devVarsPath, "utf-8"));
1652
1711
  if (customSection) {
1653
1712
  try {
1654
1713
  userSecrets = parseDevVars(customSection);
@@ -1706,7 +1765,7 @@ var deploy_default = defineCommand8({
1706
1765
  const body = await res.json().catch(() => ({}));
1707
1766
  if (!res.ok || !body.success) {
1708
1767
  s.stop("Deploy failed");
1709
- p4.cancel(body.error ?? `Deployment error (${res.status})`);
1768
+ p4.cancel(formatDeployWorkerError(res.status, body.error));
1710
1769
  process.exit(1);
1711
1770
  }
1712
1771
  if (body.url) {
@@ -1730,15 +1789,15 @@ var deploy_default = defineCommand8({
1730
1789
  }
1731
1790
  });
1732
1791
  async function syncSubscriptionPlans(appDir, appName, token2) {
1733
- const subsPath = join8(appDir, "src", "subscriptions.ts");
1734
- if (!existsSync8(subsPath)) return;
1792
+ const subsPath = join9(appDir, "src", "subscriptions.ts");
1793
+ if (!existsSync9(subsPath)) return;
1735
1794
  const s = createSpinner();
1736
1795
  s.start("Syncing subscription plans...");
1737
1796
  let plans;
1738
1797
  try {
1739
1798
  const esbuild = await import("esbuild");
1740
- const outDir = join8(appDir, ".wrangler", "deploy");
1741
- const outFile = join8(outDir, "subscriptions.bundle.mjs");
1799
+ const outDir = join9(appDir, ".wrangler", "deploy");
1800
+ const outFile = join9(outDir, "subscriptions.bundle.mjs");
1742
1801
  await esbuild.build({
1743
1802
  entryPoints: [subsPath],
1744
1803
  bundle: true,
@@ -1879,15 +1938,15 @@ current billing period? (Skip to leave them grandfathered.)`
1879
1938
  }
1880
1939
  }
1881
1940
  async function syncOneTimeProducts(appDir, appName, token2) {
1882
- const productsPath = join8(appDir, "src", "products.ts");
1883
- if (!existsSync8(productsPath)) return;
1941
+ const productsPath = join9(appDir, "src", "products.ts");
1942
+ if (!existsSync9(productsPath)) return;
1884
1943
  const s = createSpinner();
1885
1944
  s.start("Syncing one-time products...");
1886
1945
  let products;
1887
1946
  try {
1888
1947
  const esbuild = await import("esbuild");
1889
- const outDir = join8(appDir, ".wrangler", "deploy");
1890
- const outFile = join8(outDir, "products.bundle.mjs");
1948
+ const outDir = join9(appDir, ".wrangler", "deploy");
1949
+ const outFile = join9(outDir, "products.bundle.mjs");
1891
1950
  await esbuild.build({
1892
1951
  entryPoints: [productsPath],
1893
1952
  bundle: true,
@@ -1961,14 +2020,14 @@ function collectAssets(dir) {
1961
2020
  function walk(d, prefix) {
1962
2021
  for (const entry of readdirSync(d, { withFileTypes: true })) {
1963
2022
  if (entry.name === ".assetsignore") continue;
1964
- const full = join8(d, entry.name);
2023
+ const full = join9(d, entry.name);
1965
2024
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
1966
2025
  if (entry.isDirectory()) {
1967
2026
  walk(full, rel);
1968
2027
  } else {
1969
2028
  assets.push({
1970
2029
  path: "/" + rel,
1971
- contentBase64: readFileSync5(full).toString("base64")
2030
+ contentBase64: readFileSync6(full).toString("base64")
1972
2031
  });
1973
2032
  }
1974
2033
  }
@@ -1979,8 +2038,8 @@ function collectAssets(dir) {
1979
2038
 
1980
2039
  // src/cli/commands/undeploy.ts
1981
2040
  import { defineCommand as defineCommand9 } from "citty";
1982
- import { readFileSync as readFileSync6, existsSync as existsSync9 } from "fs";
1983
- import { join as join9 } from "path";
2041
+ import { readFileSync as readFileSync7, existsSync as existsSync10 } from "fs";
2042
+ import { join as join10 } from "path";
1984
2043
  import { parse as parseToml3 } from "smol-toml";
1985
2044
  import * as p5 from "@clack/prompts";
1986
2045
  var DEPLOY_URL2 = process.env.DEEPSPACE_DEPLOY_URL ?? ENVS.prod.deploy;
@@ -1999,9 +2058,9 @@ var undeploy_default = defineCommand9({
1999
2058
  async run({ args }) {
2000
2059
  let appName = args.name;
2001
2060
  if (!appName) {
2002
- const wranglerPath = join9(process.cwd(), "wrangler.toml");
2003
- if (existsSync9(wranglerPath)) {
2004
- const config = parseToml3(readFileSync6(wranglerPath, "utf-8"));
2061
+ const wranglerPath = join10(process.cwd(), "wrangler.toml");
2062
+ if (existsSync10(wranglerPath)) {
2063
+ const config = parseToml3(readFileSync7(wranglerPath, "utf-8"));
2005
2064
  if (config.name) appName = config.name;
2006
2065
  }
2007
2066
  }
@@ -2092,14 +2151,14 @@ var whoami_default = defineCommand10({
2092
2151
 
2093
2152
  // src/cli/commands/add.ts
2094
2153
  import { defineCommand as defineCommand11 } from "citty";
2095
- import { existsSync as existsSync10 } from "fs";
2096
- import { resolve as resolve6, join as join10 } from "path";
2154
+ import { existsSync as existsSync11 } from "fs";
2155
+ import { resolve as resolve6, join as join11 } from "path";
2097
2156
  import { execSync as execSync3 } from "child_process";
2098
2157
  function findScript(from) {
2099
- const inNodeModules = join10(from, "node_modules", "deepspace", "scripts", "add-feature.cjs");
2100
- if (existsSync10(inNodeModules)) return inNodeModules;
2101
- const inDotDeepspace = join10(from, ".deepspace", "scripts", "add-feature.cjs");
2102
- if (existsSync10(inDotDeepspace)) return inDotDeepspace;
2158
+ const inNodeModules = join11(from, "node_modules", "deepspace", "scripts", "add-feature.cjs");
2159
+ if (existsSync11(inNodeModules)) return inNodeModules;
2160
+ const inDotDeepspace = join11(from, ".deepspace", "scripts", "add-feature.cjs");
2161
+ if (existsSync11(inDotDeepspace)) return inDotDeepspace;
2103
2162
  return null;
2104
2163
  }
2105
2164
  var add_default = defineCommand11({
@@ -2132,12 +2191,13 @@ var add_default = defineCommand11({
2132
2191
  },
2133
2192
  run({ args }) {
2134
2193
  const appDir = resolve6(args.dir ?? ".");
2194
+ ensureInstallReady(appDir);
2135
2195
  const script = findScript(appDir);
2136
2196
  if (!script) {
2137
2197
  console.error("Could not find the deepspace feature installer.");
2138
2198
  console.error("Looked in:");
2139
- console.error(` ${join10(appDir, "node_modules", "deepspace", "scripts", "add-feature.cjs")}`);
2140
- console.error(` ${join10(appDir, ".deepspace", "scripts", "add-feature.cjs")}`);
2199
+ console.error(` ${join11(appDir, "node_modules", "deepspace", "scripts", "add-feature.cjs")}`);
2200
+ console.error(` ${join11(appDir, ".deepspace", "scripts", "add-feature.cjs")}`);
2141
2201
  console.error("Are you in a DeepSpace app directory? Try `npm install` first.");
2142
2202
  process.exit(1);
2143
2203
  }
@@ -2158,19 +2218,96 @@ var add_default = defineCommand11({
2158
2218
  }
2159
2219
  });
2160
2220
 
2161
- // src/cli/commands/domain.ts
2221
+ // src/cli/commands/skills.ts
2162
2222
  import { defineCommand as defineCommand12 } from "citty";
2223
+ import spawn2 from "cross-spawn";
2224
+ import { mkdirSync as mkdirSync4 } from "fs";
2225
+ import { join as join12 } from "path";
2226
+ import { homedir as homedir5 } from "os";
2227
+ var SKILL_REPO = "deepdotspace/deepspace-skill";
2228
+ function runSkillsAdd(extraArgs) {
2229
+ return new Promise((resolve9) => {
2230
+ const child = spawn2(
2231
+ "npx",
2232
+ ["-y", "skills@latest", "add", SKILL_REPO, ...extraArgs],
2233
+ { stdio: "inherit" }
2234
+ );
2235
+ child.on("close", (code) => resolve9(code ?? 1));
2236
+ child.on("error", (err) => {
2237
+ console.error(`Failed to invoke npx: ${err.message}`);
2238
+ console.error("Is Node.js installed and on PATH?");
2239
+ resolve9(1);
2240
+ });
2241
+ });
2242
+ }
2243
+ function precreateClaudeDir(baseDir) {
2244
+ mkdirSync4(join12(baseDir, ".claude"), { recursive: true });
2245
+ }
2246
+ var add = defineCommand12({
2247
+ meta: {
2248
+ name: "add",
2249
+ description: "Install the DeepSpace skill for your coding agent"
2250
+ },
2251
+ args: {
2252
+ global: {
2253
+ type: "boolean",
2254
+ alias: "g",
2255
+ description: "Install globally (~/.agents/skills/) instead of into the current directory",
2256
+ default: false
2257
+ },
2258
+ yes: {
2259
+ type: "boolean",
2260
+ alias: "y",
2261
+ description: "Skip prompts (assume yes for any confirmation)",
2262
+ default: false
2263
+ },
2264
+ agent: {
2265
+ type: "string",
2266
+ description: "Target a single agent (e.g. claude-code, codex, opencode). Default: install for all detected agents.",
2267
+ required: false
2268
+ }
2269
+ },
2270
+ async run({ args }) {
2271
+ const extra = [];
2272
+ if (args.global) extra.push("-g");
2273
+ if (args.yes) extra.push("-y");
2274
+ if (args.agent) extra.push("--agent", args.agent);
2275
+ if (!args.agent || args.agent === "claude-code") {
2276
+ const baseDir = args.global ? homedir5() : process.cwd();
2277
+ try {
2278
+ precreateClaudeDir(baseDir);
2279
+ } catch (err) {
2280
+ console.warn(`
2281
+ Note: could not pre-create .claude/ for Claude Code: ${err?.message ?? err}`);
2282
+ }
2283
+ }
2284
+ const code = await runSkillsAdd(extra);
2285
+ if (code !== 0) process.exit(code);
2286
+ }
2287
+ });
2288
+ var skills_default = defineCommand12({
2289
+ meta: {
2290
+ name: "skills",
2291
+ description: "Manage the DeepSpace agent skill (Claude Code, Codex, OpenCode, Cursor, ...)"
2292
+ },
2293
+ subCommands: {
2294
+ add
2295
+ }
2296
+ });
2297
+
2298
+ // src/cli/commands/domain.ts
2299
+ import { defineCommand as defineCommand13 } from "citty";
2163
2300
  import { execSync as execSync4 } from "child_process";
2164
2301
 
2165
2302
  // src/cli/lib/app-context.ts
2166
- import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
2167
- import { join as join11, resolve as resolve7 } from "path";
2303
+ import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
2304
+ import { join as join13, resolve as resolve7 } from "path";
2168
2305
  import { parse as parseToml4 } from "smol-toml";
2169
2306
  function detectAppName(cwd = process.cwd()) {
2170
- const wranglerPath = join11(resolve7(cwd), "wrangler.toml");
2171
- if (!existsSync11(wranglerPath)) return null;
2307
+ const wranglerPath = join13(resolve7(cwd), "wrangler.toml");
2308
+ if (!existsSync12(wranglerPath)) return null;
2172
2309
  try {
2173
- const cfg = parseToml4(readFileSync7(wranglerPath, "utf-8"));
2310
+ const cfg = parseToml4(readFileSync8(wranglerPath, "utf-8"));
2174
2311
  return typeof cfg.name === "string" && cfg.name.length > 0 ? cfg.name : null;
2175
2312
  } catch {
2176
2313
  return null;
@@ -2240,7 +2377,7 @@ async function confirm3(message) {
2240
2377
  });
2241
2378
  });
2242
2379
  }
2243
- var search = defineCommand12({
2380
+ var search = defineCommand13({
2244
2381
  meta: { name: "search", description: "Search for available domains" },
2245
2382
  args: {
2246
2383
  query: { type: "positional", description: "Domain or keyword", required: true },
@@ -2270,7 +2407,7 @@ var search = defineCommand12({
2270
2407
  }
2271
2408
  }
2272
2409
  });
2273
- var buy = defineCommand12({
2410
+ var buy = defineCommand13({
2274
2411
  meta: { name: "buy", description: "Buy a domain and attach it to an app" },
2275
2412
  args: {
2276
2413
  domain: { type: "positional", description: "Domain to buy", required: true },
@@ -2359,7 +2496,7 @@ var buy = defineCommand12({
2359
2496
  process.exit(1);
2360
2497
  }
2361
2498
  });
2362
- var list2 = defineCommand12({
2499
+ var list2 = defineCommand13({
2363
2500
  meta: { name: "list", description: "List your domains" },
2364
2501
  args: {
2365
2502
  json: { type: "boolean", description: "Emit JSON" }
@@ -2383,7 +2520,7 @@ var list2 = defineCommand12({
2383
2520
  }
2384
2521
  }
2385
2522
  });
2386
- var status = defineCommand12({
2523
+ var status = defineCommand13({
2387
2524
  meta: { name: "status", description: "Show details for one domain" },
2388
2525
  args: {
2389
2526
  domain: { type: "positional", description: "Domain", required: true },
@@ -2411,7 +2548,7 @@ var status = defineCommand12({
2411
2548
  console.log(`Charged: ${fmtCents(found.chargedCents)}/yr`);
2412
2549
  }
2413
2550
  });
2414
- var attach = defineCommand12({
2551
+ var attach = defineCommand13({
2415
2552
  meta: { name: "attach", description: "Re-point a domain at a different app" },
2416
2553
  args: {
2417
2554
  domain: { type: "positional", description: "Domain to re-point", required: true },
@@ -2442,7 +2579,7 @@ var attach = defineCommand12({
2442
2579
  console.log(`\u2713 ${args.domain} now points at ${targetApp}`);
2443
2580
  }
2444
2581
  });
2445
- var detach = defineCommand12({
2582
+ var detach = defineCommand13({
2446
2583
  meta: {
2447
2584
  name: "detach",
2448
2585
  description: "Stop routing the domain (keeps the registration; auto-renew unchanged)"
@@ -2472,7 +2609,7 @@ var detach = defineCommand12({
2472
2609
  console.log(`\u2713 ${args.domain} detached. Use \`deepspace domain attach\` to re-route, or \`renew --auto off\` to stop auto-renewal.`);
2473
2610
  }
2474
2611
  });
2475
- var renew = defineCommand12({
2612
+ var renew = defineCommand13({
2476
2613
  meta: { name: "renew", description: "Toggle auto-renewal at the registrar" },
2477
2614
  args: {
2478
2615
  domain: { type: "positional", description: "Domain", required: true },
@@ -2506,16 +2643,16 @@ function openBrowser2(url) {
2506
2643
  } catch {
2507
2644
  }
2508
2645
  }
2509
- var domain_default = defineCommand12({
2646
+ var domain_default = defineCommand13({
2510
2647
  meta: { name: "domain", description: "Buy and manage custom domains" },
2511
2648
  subCommands: { search, buy, list: list2, status, attach, detach, renew }
2512
2649
  });
2513
2650
 
2514
2651
  // src/cli/commands/integrations.ts
2515
- import { defineCommand as defineCommand13 } from "citty";
2652
+ import { defineCommand as defineCommand14 } from "citty";
2516
2653
 
2517
2654
  // src/cli/commands/_invoke-impl.ts
2518
- import { readFileSync as readFileSync8 } from "fs";
2655
+ import { readFileSync as readFileSync9 } from "fs";
2519
2656
  var API_URL3 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
2520
2657
  var DEFAULT_TIMEOUT_MS = 12e4;
2521
2658
  function parseTarget(target) {
@@ -2536,7 +2673,7 @@ function resolveBody(opts) {
2536
2673
  if (opts.body != null) {
2537
2674
  raw = opts.body;
2538
2675
  } else if (opts.bodyFile != null) {
2539
- raw = opts.bodyFile === "-" ? readFileSync8(0, "utf-8") : readFileSync8(opts.bodyFile, "utf-8");
2676
+ raw = opts.bodyFile === "-" ? readFileSync9(0, "utf-8") : readFileSync9(opts.bodyFile, "utf-8");
2540
2677
  } else {
2541
2678
  return "{}";
2542
2679
  }
@@ -2686,7 +2823,7 @@ async function runInvoke(args) {
2686
2823
  }
2687
2824
 
2688
2825
  // src/cli/commands/integrations.ts
2689
- var list3 = defineCommand13({
2826
+ var list3 = defineCommand14({
2690
2827
  meta: {
2691
2828
  name: "list",
2692
2829
  description: "List all available integrations"
@@ -2707,7 +2844,7 @@ var list3 = defineCommand13({
2707
2844
  }
2708
2845
  }
2709
2846
  });
2710
- var info = defineCommand13({
2847
+ var info = defineCommand14({
2711
2848
  meta: {
2712
2849
  name: "info",
2713
2850
  description: "Print schema + example body for an integration endpoint"
@@ -2733,7 +2870,7 @@ var info = defineCommand13({
2733
2870
  }
2734
2871
  }
2735
2872
  });
2736
- var invoke = defineCommand13({
2873
+ var invoke = defineCommand14({
2737
2874
  meta: {
2738
2875
  name: "invoke",
2739
2876
  description: "Invoke a platform integration as the logged-in user"
@@ -2786,7 +2923,7 @@ var invoke = defineCommand13({
2786
2923
  }
2787
2924
  }
2788
2925
  });
2789
- var integrations_default = defineCommand13({
2926
+ var integrations_default = defineCommand14({
2790
2927
  meta: {
2791
2928
  name: "integrations",
2792
2929
  description: "List, inspect, and invoke platform integrations"
@@ -2799,8 +2936,8 @@ var integrations_default = defineCommand13({
2799
2936
  });
2800
2937
 
2801
2938
  // src/cli/commands/invoke.ts
2802
- import { defineCommand as defineCommand14 } from "citty";
2803
- var invoke_default = defineCommand14({
2939
+ import { defineCommand as defineCommand15 } from "citty";
2940
+ var invoke_default = defineCommand15({
2804
2941
  meta: {
2805
2942
  name: "invoke",
2806
2943
  description: "Invoke a platform integration as the logged-in user"
@@ -2873,7 +3010,7 @@ var invoke_default = defineCommand14({
2873
3010
  });
2874
3011
 
2875
3012
  // src/cli/commands/managed-repos.ts
2876
- import { defineCommand as defineCommand15 } from "citty";
3013
+ import { defineCommand as defineCommand16 } from "citty";
2877
3014
  var API_URL4 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
2878
3015
  var SIMPLE_APP_ID = /^[a-z0-9][a-z0-9_.:-]{0,119}$/i;
2879
3016
  var SIMPLE_APP_NAME = /^[a-z0-9][a-z0-9_-]{0,119}$/i;
@@ -2932,7 +3069,7 @@ async function confirm4(message) {
2932
3069
  });
2933
3070
  });
2934
3071
  }
2935
- var list4 = defineCommand15({
3072
+ var list4 = defineCommand16({
2936
3073
  meta: {
2937
3074
  name: "list",
2938
3075
  description: "List your DeepSpace-managed repos and quota"
@@ -2962,7 +3099,7 @@ var list4 = defineCommand15({
2962
3099
  }
2963
3100
  }
2964
3101
  });
2965
- var create2 = defineCommand15({
3102
+ var create2 = defineCommand16({
2966
3103
  meta: {
2967
3104
  name: "create",
2968
3105
  description: "Create a private DeepSpace-managed GitHub repo"
@@ -3014,7 +3151,7 @@ var create2 = defineCommand15({
3014
3151
  printRepo(result.repo);
3015
3152
  }
3016
3153
  });
3017
- var token = defineCommand15({
3154
+ var token = defineCommand16({
3018
3155
  meta: {
3019
3156
  name: "token",
3020
3157
  description: "Mint a short-lived GitHub token for a DeepSpace-managed repo"
@@ -3049,7 +3186,7 @@ var token = defineCommand15({
3049
3186
  console.log(`Clone: git clone https://x-access-token:${encodeURIComponent(result.token.token)}@github.com/${result.repo.fullName}.git`);
3050
3187
  }
3051
3188
  });
3052
- var remove = defineCommand15({
3189
+ var remove = defineCommand16({
3053
3190
  meta: {
3054
3191
  name: "delete",
3055
3192
  description: "Delete a DeepSpace-managed GitHub repo"
@@ -3102,7 +3239,7 @@ var remove = defineCommand15({
3102
3239
  );
3103
3240
  }
3104
3241
  });
3105
- var managed_repos_default = defineCommand15({
3242
+ var managed_repos_default = defineCommand16({
3106
3243
  meta: {
3107
3244
  name: "managed-repos",
3108
3245
  description: "Create and manage DeepSpace-owned GitHub repos"
@@ -3116,13 +3253,13 @@ var managed_repos_default = defineCommand15({
3116
3253
  });
3117
3254
 
3118
3255
  // src/cli/commands/library.ts
3119
- import { defineCommand as defineCommand16 } from "citty";
3120
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
3121
- import { join as join12, resolve as resolve8 } from "path";
3256
+ import { defineCommand as defineCommand17 } from "citty";
3257
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
3258
+ import { join as join14, resolve as resolve8 } from "path";
3122
3259
  import { parse as parseToml5 } from "smol-toml";
3123
3260
  import * as p6 from "@clack/prompts";
3124
3261
  var DEFAULT_LIBRARY_APP = "deepdotspace-site";
3125
- var publish = defineCommand16({
3262
+ var publish = defineCommand17({
3126
3263
  meta: {
3127
3264
  name: "publish",
3128
3265
  description: "Publish the current app to the DeepSpace library"
@@ -3196,11 +3333,11 @@ var publish = defineCommand16({
3196
3333
  let appName = typeof args.app === "string" && args.app.trim() ? args.app.trim() : void 0;
3197
3334
  if (!appName) {
3198
3335
  const appDir = resolve8(typeof args.dir === "string" && args.dir ? args.dir : ".");
3199
- const wranglerPath = join12(appDir, "wrangler.toml");
3200
- if (!existsSync12(wranglerPath)) {
3336
+ const wranglerPath = join14(appDir, "wrangler.toml");
3337
+ if (!existsSync13(wranglerPath)) {
3201
3338
  return die("No --app provided and no wrangler.toml found. Either pass --app <name> or run from your app's directory.");
3202
3339
  }
3203
- const cfg = parseToml5(readFileSync9(wranglerPath, "utf-8"));
3340
+ const cfg = parseToml5(readFileSync10(wranglerPath, "utf-8"));
3204
3341
  const nameRes = resolveAppName(cfg.name);
3205
3342
  if (!nameRes.ok) return die(`wrangler.toml: ${nameRes.reason}`);
3206
3343
  appName = nameRes.name;
@@ -3261,7 +3398,7 @@ var publish = defineCommand16({
3261
3398
  p6.outro("Done");
3262
3399
  }
3263
3400
  });
3264
- var unpublish = defineCommand16({
3401
+ var unpublish = defineCommand17({
3265
3402
  meta: {
3266
3403
  name: "unpublish",
3267
3404
  description: "Remove a library entry (owner or admin only)"
@@ -3320,7 +3457,7 @@ var unpublish = defineCommand16({
3320
3457
  p6.outro("Done");
3321
3458
  }
3322
3459
  });
3323
- var library_default = defineCommand16({
3460
+ var library_default = defineCommand17({
3324
3461
  meta: {
3325
3462
  name: "library",
3326
3463
  description: "Manage your DeepSpace library entries"
@@ -3332,12 +3469,12 @@ var library_default = defineCommand16({
3332
3469
  });
3333
3470
 
3334
3471
  // src/cli/commands/admin.ts
3335
- import { defineCommand as defineCommand17 } from "citty";
3336
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
3337
- import { homedir as homedir5 } from "os";
3338
- import { join as join13 } from "path";
3472
+ import { defineCommand as defineCommand18 } from "citty";
3473
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
3474
+ import { homedir as homedir6 } from "os";
3475
+ import { join as join15 } from "path";
3339
3476
  var AUTH_URL5 = process.env.DEEPSPACE_AUTH_URL ?? ENVS.prod.auth;
3340
- var impersonate = defineCommand17({
3477
+ var impersonate = defineCommand18({
3341
3478
  meta: {
3342
3479
  name: "impersonate",
3343
3480
  description: "Store a short-lived CLI token for another user"
@@ -3385,15 +3522,15 @@ var impersonate = defineCommand17({
3385
3522
  console.error(`Failed: ${data.error ?? `HTTP ${res.status}`}`);
3386
3523
  process.exit(1);
3387
3524
  }
3388
- const dir = join13(homedir5(), ".deepspace");
3389
- mkdirSync4(dir, { recursive: true });
3525
+ const dir = join15(homedir6(), ".deepspace");
3526
+ mkdirSync5(dir, { recursive: true });
3390
3527
  writeFileSync5(TOKEN_PATH2, data.token, { mode: 384 });
3391
3528
  console.log(`Impersonating ${data.user.name ?? data.user.email ?? data.user.id}`);
3392
3529
  console.log(`Email: ${data.user.email ?? "(none)"}`);
3393
3530
  console.log(`UserID: ${data.user.id}`);
3394
3531
  }
3395
3532
  });
3396
- var admin_default = defineCommand17({
3533
+ var admin_default = defineCommand18({
3397
3534
  meta: {
3398
3535
  name: "admin",
3399
3536
  description: "Maintainer-only admin commands"
@@ -3405,11 +3542,11 @@ var admin_default = defineCommand17({
3405
3542
 
3406
3543
  // src/cli/cli.ts
3407
3544
  var __dirname = dirname2(fileURLToPath(import.meta.url));
3408
- var pkg = JSON.parse(readFileSync10(join14(__dirname, "..", "package.json"), "utf-8"));
3409
- if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync13("/etc/ssl/certs/ca-certificates.crt")) {
3545
+ var pkg = JSON.parse(readFileSync11(join16(__dirname, "..", "package.json"), "utf-8"));
3546
+ if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync14("/etc/ssl/certs/ca-certificates.crt")) {
3410
3547
  process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
3411
3548
  }
3412
- var create3 = defineCommand18({
3549
+ var create3 = defineCommand19({
3413
3550
  meta: {
3414
3551
  name: "create",
3415
3552
  description: "Create a new DeepSpace app"
@@ -3428,7 +3565,7 @@ var create3 = defineCommand18({
3428
3565
  execSync5(`npm create deepspace@latest${name}`, { stdio: "inherit" });
3429
3566
  }
3430
3567
  });
3431
- var main = defineCommand18({
3568
+ var main = defineCommand19({
3432
3569
  meta: {
3433
3570
  name: "deepspace",
3434
3571
  version: pkg.version,
@@ -3445,6 +3582,7 @@ var main = defineCommand18({
3445
3582
  screenshot: screenshot_default,
3446
3583
  "test-accounts": test_accounts_default,
3447
3584
  add: add_default,
3585
+ skills: skills_default,
3448
3586
  integrations: integrations_default,
3449
3587
  "managed-repos": managed_repos_default,
3450
3588
  invoke: invoke_default,