deepspace 0.3.10 → 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.
Files changed (120) hide show
  1. package/dist/cli.js +331 -115
  2. package/dist/cli.js.map +1 -1
  3. package/dist/index.d.ts +199 -16
  4. package/dist/index.js +354 -166
  5. package/dist/index.js.map +1 -1
  6. package/dist/server.d.ts +242 -73
  7. package/dist/server.js +985 -374
  8. package/dist/server.js.map +1 -1
  9. package/dist/worker.d.ts +322 -73
  10. package/dist/worker.js +961 -343
  11. package/dist/worker.js.map +1 -1
  12. package/features/admin-page/feature.json +29 -0
  13. package/features/admin-page/src/AdminPage.tsx +292 -0
  14. package/features/admin-page/src/admin-schema.ts +20 -0
  15. package/features/ai-chat/feature.json +41 -0
  16. package/features/ai-chat/src/AiChatPage.tsx +692 -0
  17. package/features/ai-chat/src/ChatPanel.tsx +1098 -0
  18. package/features/ai-chat/src/ai-chat-schema.ts +11 -0
  19. package/features/canvas/feature.json +45 -0
  20. package/features/canvas/src/CanvasEditorPage.tsx +87 -0
  21. package/features/canvas/src/CanvasListPage.tsx +202 -0
  22. package/features/canvas/src/canvas-schema.ts +33 -0
  23. package/features/canvas/src/components/CanvasToolbar.tsx +170 -0
  24. package/features/canvas/src/components/CanvasView.tsx +369 -0
  25. package/features/canvas/src/components/ShapeRenderer.tsx +114 -0
  26. package/features/cron/feature.json +33 -0
  27. package/features/cron/src/CronLogPage.tsx +100 -0
  28. package/features/cron/src/cron.ts +25 -0
  29. package/features/docs/feature.json +96 -0
  30. package/features/docs/src/DocsEditorPage.tsx +1012 -0
  31. package/features/docs/src/DocsListPage.tsx +951 -0
  32. package/features/docs/src/DocsOutlinePanel.tsx +68 -0
  33. package/features/docs/src/DocsPresence.tsx +138 -0
  34. package/features/docs/src/InviteDialog.tsx +336 -0
  35. package/features/docs/src/LibrarySidebar.tsx +464 -0
  36. package/features/docs/src/docs-favorites.ts +18 -0
  37. package/features/docs/src/docs-library-types.ts +15 -0
  38. package/features/docs/src/docs-schema.ts +80 -0
  39. package/features/docs/src/docs-ui.css +309 -0
  40. package/features/docs/src/editor/DocEditorSurface.tsx +257 -0
  41. package/features/docs/src/editor/DocsTiptapToolbar.tsx +560 -0
  42. package/features/docs/src/editor/useDocEditor.ts +206 -0
  43. package/features/docs/src/use-yjs-room-with-awareness.ts +285 -0
  44. package/features/file-attachments/feature.json +42 -0
  45. package/features/file-attachments/src/AttachmentsPage.tsx +864 -0
  46. package/features/file-attachments/src/attachments-constants.ts +9 -0
  47. package/features/file-attachments/src/attachments-schema.ts +45 -0
  48. package/features/file-attachments/src/useFilePreview.ts +471 -0
  49. package/features/file-attachments/src/useMimeTypeDetection.ts +138 -0
  50. package/features/file-manager/feature.json +24 -0
  51. package/features/file-manager/src/FileManagerPage.tsx +330 -0
  52. package/features/integration-test/feature.json +18 -0
  53. package/features/integration-test/src/IntegrationTestPage.tsx +423 -0
  54. package/features/integration-test/src/integration.spec.ts +42 -0
  55. package/features/items/feature.json +33 -0
  56. package/features/items/src/ItemsPage.tsx +325 -0
  57. package/features/items/src/items-constants.ts +10 -0
  58. package/features/items/src/items-schema.ts +27 -0
  59. package/features/kanban/feature.json +18 -0
  60. package/features/kanban/src/Kanban.tsx +283 -0
  61. package/features/landing/feature.json +62 -0
  62. package/features/landing/src/LandingPage.tsx +627 -0
  63. package/features/landing/src/primitives.tsx +389 -0
  64. package/features/landing/src/sections/FAQSection.tsx +110 -0
  65. package/features/landing/src/sections/FeaturesGridSection.tsx +311 -0
  66. package/features/landing/src/sections/HowItWorksSection.tsx +62 -0
  67. package/features/landing/src/sections/LogoCloudSection.tsx +58 -0
  68. package/features/landing/src/sections/ShowcaseSection.tsx +63 -0
  69. package/features/landing/src/sections/StatsSection.tsx +31 -0
  70. package/features/landing/src/sections/TeamSection.tsx +86 -0
  71. package/features/landing/src/sections/TestimonialsSection.tsx +68 -0
  72. package/features/landing/src/sections/VideoSection.tsx +71 -0
  73. package/features/leaderboard/feature.json +33 -0
  74. package/features/leaderboard/src/LeaderboardPage.tsx +372 -0
  75. package/features/leaderboard/src/leaderboard-constants.ts +21 -0
  76. package/features/leaderboard/src/leaderboard-schema.ts +36 -0
  77. package/features/messaging/feature.json +111 -0
  78. package/features/messaging/src/ChatMultiPage.tsx +300 -0
  79. package/features/messaging/src/ChatPage.tsx +75 -0
  80. package/features/messaging/src/components/chat/ChatHeader.tsx +76 -0
  81. package/features/messaging/src/components/chat/MessageActionSheet.tsx +168 -0
  82. package/features/messaging/src/components/chat/MessageInput.tsx +65 -0
  83. package/features/messaging/src/components/chat/MessageItem.tsx +352 -0
  84. package/features/messaging/src/components/chat/MessageList.tsx +248 -0
  85. package/features/messaging/src/components/chat/ReactionPicker.tsx +2 -0
  86. package/features/messaging/src/components/chat/ThreadPanel.tsx +107 -0
  87. package/features/messaging/src/components/chat/UserProfilePopover.tsx +158 -0
  88. package/features/messaging/src/components/chat-multi/AddMemberModal.tsx +188 -0
  89. package/features/messaging/src/components/chat-multi/BrowseGroupsModal.tsx +163 -0
  90. package/features/messaging/src/components/chat-multi/ChannelListItem.tsx +147 -0
  91. package/features/messaging/src/components/chat-multi/ChannelSettingsPanel.tsx +344 -0
  92. package/features/messaging/src/components/chat-multi/ChannelSidebar.tsx +460 -0
  93. package/features/messaging/src/components/chat-multi/CreateGroupModal.tsx +190 -0
  94. package/features/messaging/src/components/chat-multi/InvitationList.tsx +149 -0
  95. package/features/messaging/src/components/chat-multi/NewMessageModal.tsx +159 -0
  96. package/features/messaging/src/hooks/useChatChannel.ts +64 -0
  97. package/features/messaging/src/hooks/useLongPress.ts +74 -0
  98. package/features/messaging/src/hooks/useMultiChannel.ts +142 -0
  99. package/features/messaging/src/messaging-schema.ts +25 -0
  100. package/features/presence-test/feature.json +21 -0
  101. package/features/presence-test/src/PresenceTestPage.tsx +120 -0
  102. package/features/sidebar/feature.json +19 -0
  103. package/features/sidebar/src/AppSidebar.tsx +558 -0
  104. package/features/tasks/feature.json +33 -0
  105. package/features/tasks/src/TasksPage.tsx +598 -0
  106. package/features/tasks/src/tasks-constants.ts +43 -0
  107. package/features/tasks/src/tasks-schema.ts +56 -0
  108. package/features/testing/feature.json +49 -0
  109. package/features/testing/src/TestPage.tsx +145 -0
  110. package/features/testing/src/cpu-burn-action.ts +51 -0
  111. package/features/testing/src/subrequest-burn-action.ts +53 -0
  112. package/features/testing/src/test-schema.ts +23 -0
  113. package/features/topbar/feature.json +18 -0
  114. package/features/topbar/src/Topbar.tsx +353 -0
  115. package/features/tree/feature.json +26 -0
  116. package/features/tree/src/TreeSidebar.tsx +607 -0
  117. package/features/tree/src/tree-constants.ts +68 -0
  118. package/features/tree/src/tree-hooks.ts +258 -0
  119. package/package.json +4 -2
  120. package/scripts/add-feature.cjs +654 -0
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 defineCommand17, 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 join13 } 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
@@ -530,21 +540,21 @@ var DIR2 = join4(homedir3(), ".deepspace");
530
540
  var SESSION_PATH2 = join4(DIR2, "session");
531
541
  var TOKEN_PATH2 = join4(DIR2, "token");
532
542
  async function ensureToken() {
533
- if (!existsSync3(SESSION_PATH2)) {
534
- throw new Error("Not logged in. Run `deepspace login` first.");
535
- }
536
- const sessionToken = readFileSync3(SESSION_PATH2, "utf-8").trim();
537
543
  if (existsSync3(TOKEN_PATH2)) {
538
544
  const existing = readFileSync3(TOKEN_PATH2, "utf-8").trim();
539
545
  if (isTokenValid(existing)) {
540
546
  return existing;
541
547
  }
542
548
  }
549
+ if (!existsSync3(SESSION_PATH2)) {
550
+ throw new Error("Not logged in. Run `deepspace login` first.");
551
+ }
552
+ const sessionToken = readFileSync3(SESSION_PATH2, "utf-8").trim();
543
553
  const token2 = await exchangeSession(AUTH_URL3, sessionToken);
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,12 +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 candidate = join10(from, ".deepspace", "scripts", "add-feature.cjs");
2100
- if (existsSync10(candidate)) return candidate;
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;
2101
2162
  return null;
2102
2163
  }
2103
2164
  var add_default = defineCommand11({
@@ -2130,10 +2191,14 @@ var add_default = defineCommand11({
2130
2191
  },
2131
2192
  run({ args }) {
2132
2193
  const appDir = resolve6(args.dir ?? ".");
2194
+ ensureInstallReady(appDir);
2133
2195
  const script = findScript(appDir);
2134
2196
  if (!script) {
2135
- console.error("No .deepspace/scripts/add-feature.cjs found.");
2136
- console.error("Are you in a DeepSpace app directory?");
2197
+ console.error("Could not find the deepspace feature installer.");
2198
+ console.error("Looked in:");
2199
+ console.error(` ${join11(appDir, "node_modules", "deepspace", "scripts", "add-feature.cjs")}`);
2200
+ console.error(` ${join11(appDir, ".deepspace", "scripts", "add-feature.cjs")}`);
2201
+ console.error("Are you in a DeepSpace app directory? Try `npm install` first.");
2137
2202
  process.exit(1);
2138
2203
  }
2139
2204
  const passArgs = [];
@@ -2153,19 +2218,96 @@ var add_default = defineCommand11({
2153
2218
  }
2154
2219
  });
2155
2220
 
2156
- // src/cli/commands/domain.ts
2221
+ // src/cli/commands/skills.ts
2157
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";
2158
2300
  import { execSync as execSync4 } from "child_process";
2159
2301
 
2160
2302
  // src/cli/lib/app-context.ts
2161
- import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
2162
- 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";
2163
2305
  import { parse as parseToml4 } from "smol-toml";
2164
2306
  function detectAppName(cwd = process.cwd()) {
2165
- const wranglerPath = join11(resolve7(cwd), "wrangler.toml");
2166
- if (!existsSync11(wranglerPath)) return null;
2307
+ const wranglerPath = join13(resolve7(cwd), "wrangler.toml");
2308
+ if (!existsSync12(wranglerPath)) return null;
2167
2309
  try {
2168
- const cfg = parseToml4(readFileSync7(wranglerPath, "utf-8"));
2310
+ const cfg = parseToml4(readFileSync8(wranglerPath, "utf-8"));
2169
2311
  return typeof cfg.name === "string" && cfg.name.length > 0 ? cfg.name : null;
2170
2312
  } catch {
2171
2313
  return null;
@@ -2235,7 +2377,7 @@ async function confirm3(message) {
2235
2377
  });
2236
2378
  });
2237
2379
  }
2238
- var search = defineCommand12({
2380
+ var search = defineCommand13({
2239
2381
  meta: { name: "search", description: "Search for available domains" },
2240
2382
  args: {
2241
2383
  query: { type: "positional", description: "Domain or keyword", required: true },
@@ -2265,7 +2407,7 @@ var search = defineCommand12({
2265
2407
  }
2266
2408
  }
2267
2409
  });
2268
- var buy = defineCommand12({
2410
+ var buy = defineCommand13({
2269
2411
  meta: { name: "buy", description: "Buy a domain and attach it to an app" },
2270
2412
  args: {
2271
2413
  domain: { type: "positional", description: "Domain to buy", required: true },
@@ -2354,7 +2496,7 @@ var buy = defineCommand12({
2354
2496
  process.exit(1);
2355
2497
  }
2356
2498
  });
2357
- var list2 = defineCommand12({
2499
+ var list2 = defineCommand13({
2358
2500
  meta: { name: "list", description: "List your domains" },
2359
2501
  args: {
2360
2502
  json: { type: "boolean", description: "Emit JSON" }
@@ -2378,7 +2520,7 @@ var list2 = defineCommand12({
2378
2520
  }
2379
2521
  }
2380
2522
  });
2381
- var status = defineCommand12({
2523
+ var status = defineCommand13({
2382
2524
  meta: { name: "status", description: "Show details for one domain" },
2383
2525
  args: {
2384
2526
  domain: { type: "positional", description: "Domain", required: true },
@@ -2406,7 +2548,7 @@ var status = defineCommand12({
2406
2548
  console.log(`Charged: ${fmtCents(found.chargedCents)}/yr`);
2407
2549
  }
2408
2550
  });
2409
- var attach = defineCommand12({
2551
+ var attach = defineCommand13({
2410
2552
  meta: { name: "attach", description: "Re-point a domain at a different app" },
2411
2553
  args: {
2412
2554
  domain: { type: "positional", description: "Domain to re-point", required: true },
@@ -2437,7 +2579,7 @@ var attach = defineCommand12({
2437
2579
  console.log(`\u2713 ${args.domain} now points at ${targetApp}`);
2438
2580
  }
2439
2581
  });
2440
- var detach = defineCommand12({
2582
+ var detach = defineCommand13({
2441
2583
  meta: {
2442
2584
  name: "detach",
2443
2585
  description: "Stop routing the domain (keeps the registration; auto-renew unchanged)"
@@ -2467,7 +2609,7 @@ var detach = defineCommand12({
2467
2609
  console.log(`\u2713 ${args.domain} detached. Use \`deepspace domain attach\` to re-route, or \`renew --auto off\` to stop auto-renewal.`);
2468
2610
  }
2469
2611
  });
2470
- var renew = defineCommand12({
2612
+ var renew = defineCommand13({
2471
2613
  meta: { name: "renew", description: "Toggle auto-renewal at the registrar" },
2472
2614
  args: {
2473
2615
  domain: { type: "positional", description: "Domain", required: true },
@@ -2501,16 +2643,16 @@ function openBrowser2(url) {
2501
2643
  } catch {
2502
2644
  }
2503
2645
  }
2504
- var domain_default = defineCommand12({
2646
+ var domain_default = defineCommand13({
2505
2647
  meta: { name: "domain", description: "Buy and manage custom domains" },
2506
2648
  subCommands: { search, buy, list: list2, status, attach, detach, renew }
2507
2649
  });
2508
2650
 
2509
2651
  // src/cli/commands/integrations.ts
2510
- import { defineCommand as defineCommand13 } from "citty";
2652
+ import { defineCommand as defineCommand14 } from "citty";
2511
2653
 
2512
2654
  // src/cli/commands/_invoke-impl.ts
2513
- import { readFileSync as readFileSync8 } from "fs";
2655
+ import { readFileSync as readFileSync9 } from "fs";
2514
2656
  var API_URL3 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
2515
2657
  var DEFAULT_TIMEOUT_MS = 12e4;
2516
2658
  function parseTarget(target) {
@@ -2531,7 +2673,7 @@ function resolveBody(opts) {
2531
2673
  if (opts.body != null) {
2532
2674
  raw = opts.body;
2533
2675
  } else if (opts.bodyFile != null) {
2534
- 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");
2535
2677
  } else {
2536
2678
  return "{}";
2537
2679
  }
@@ -2681,7 +2823,7 @@ async function runInvoke(args) {
2681
2823
  }
2682
2824
 
2683
2825
  // src/cli/commands/integrations.ts
2684
- var list3 = defineCommand13({
2826
+ var list3 = defineCommand14({
2685
2827
  meta: {
2686
2828
  name: "list",
2687
2829
  description: "List all available integrations"
@@ -2702,7 +2844,7 @@ var list3 = defineCommand13({
2702
2844
  }
2703
2845
  }
2704
2846
  });
2705
- var info = defineCommand13({
2847
+ var info = defineCommand14({
2706
2848
  meta: {
2707
2849
  name: "info",
2708
2850
  description: "Print schema + example body for an integration endpoint"
@@ -2728,7 +2870,7 @@ var info = defineCommand13({
2728
2870
  }
2729
2871
  }
2730
2872
  });
2731
- var invoke = defineCommand13({
2873
+ var invoke = defineCommand14({
2732
2874
  meta: {
2733
2875
  name: "invoke",
2734
2876
  description: "Invoke a platform integration as the logged-in user"
@@ -2781,7 +2923,7 @@ var invoke = defineCommand13({
2781
2923
  }
2782
2924
  }
2783
2925
  });
2784
- var integrations_default = defineCommand13({
2926
+ var integrations_default = defineCommand14({
2785
2927
  meta: {
2786
2928
  name: "integrations",
2787
2929
  description: "List, inspect, and invoke platform integrations"
@@ -2794,8 +2936,8 @@ var integrations_default = defineCommand13({
2794
2936
  });
2795
2937
 
2796
2938
  // src/cli/commands/invoke.ts
2797
- import { defineCommand as defineCommand14 } from "citty";
2798
- var invoke_default = defineCommand14({
2939
+ import { defineCommand as defineCommand15 } from "citty";
2940
+ var invoke_default = defineCommand15({
2799
2941
  meta: {
2800
2942
  name: "invoke",
2801
2943
  description: "Invoke a platform integration as the logged-in user"
@@ -2868,7 +3010,7 @@ var invoke_default = defineCommand14({
2868
3010
  });
2869
3011
 
2870
3012
  // src/cli/commands/managed-repos.ts
2871
- import { defineCommand as defineCommand15 } from "citty";
3013
+ import { defineCommand as defineCommand16 } from "citty";
2872
3014
  var API_URL4 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
2873
3015
  var SIMPLE_APP_ID = /^[a-z0-9][a-z0-9_.:-]{0,119}$/i;
2874
3016
  var SIMPLE_APP_NAME = /^[a-z0-9][a-z0-9_-]{0,119}$/i;
@@ -2927,7 +3069,7 @@ async function confirm4(message) {
2927
3069
  });
2928
3070
  });
2929
3071
  }
2930
- var list4 = defineCommand15({
3072
+ var list4 = defineCommand16({
2931
3073
  meta: {
2932
3074
  name: "list",
2933
3075
  description: "List your DeepSpace-managed repos and quota"
@@ -2957,7 +3099,7 @@ var list4 = defineCommand15({
2957
3099
  }
2958
3100
  }
2959
3101
  });
2960
- var create2 = defineCommand15({
3102
+ var create2 = defineCommand16({
2961
3103
  meta: {
2962
3104
  name: "create",
2963
3105
  description: "Create a private DeepSpace-managed GitHub repo"
@@ -3009,7 +3151,7 @@ var create2 = defineCommand15({
3009
3151
  printRepo(result.repo);
3010
3152
  }
3011
3153
  });
3012
- var token = defineCommand15({
3154
+ var token = defineCommand16({
3013
3155
  meta: {
3014
3156
  name: "token",
3015
3157
  description: "Mint a short-lived GitHub token for a DeepSpace-managed repo"
@@ -3044,7 +3186,7 @@ var token = defineCommand15({
3044
3186
  console.log(`Clone: git clone https://x-access-token:${encodeURIComponent(result.token.token)}@github.com/${result.repo.fullName}.git`);
3045
3187
  }
3046
3188
  });
3047
- var remove = defineCommand15({
3189
+ var remove = defineCommand16({
3048
3190
  meta: {
3049
3191
  name: "delete",
3050
3192
  description: "Delete a DeepSpace-managed GitHub repo"
@@ -3097,7 +3239,7 @@ var remove = defineCommand15({
3097
3239
  );
3098
3240
  }
3099
3241
  });
3100
- var managed_repos_default = defineCommand15({
3242
+ var managed_repos_default = defineCommand16({
3101
3243
  meta: {
3102
3244
  name: "managed-repos",
3103
3245
  description: "Create and manage DeepSpace-owned GitHub repos"
@@ -3111,13 +3253,13 @@ var managed_repos_default = defineCommand15({
3111
3253
  });
3112
3254
 
3113
3255
  // src/cli/commands/library.ts
3114
- import { defineCommand as defineCommand16 } from "citty";
3115
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
3116
- 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";
3117
3259
  import { parse as parseToml5 } from "smol-toml";
3118
3260
  import * as p6 from "@clack/prompts";
3119
3261
  var DEFAULT_LIBRARY_APP = "deepdotspace-site";
3120
- var publish = defineCommand16({
3262
+ var publish = defineCommand17({
3121
3263
  meta: {
3122
3264
  name: "publish",
3123
3265
  description: "Publish the current app to the DeepSpace library"
@@ -3191,11 +3333,11 @@ var publish = defineCommand16({
3191
3333
  let appName = typeof args.app === "string" && args.app.trim() ? args.app.trim() : void 0;
3192
3334
  if (!appName) {
3193
3335
  const appDir = resolve8(typeof args.dir === "string" && args.dir ? args.dir : ".");
3194
- const wranglerPath = join12(appDir, "wrangler.toml");
3195
- if (!existsSync12(wranglerPath)) {
3336
+ const wranglerPath = join14(appDir, "wrangler.toml");
3337
+ if (!existsSync13(wranglerPath)) {
3196
3338
  return die("No --app provided and no wrangler.toml found. Either pass --app <name> or run from your app's directory.");
3197
3339
  }
3198
- const cfg = parseToml5(readFileSync9(wranglerPath, "utf-8"));
3340
+ const cfg = parseToml5(readFileSync10(wranglerPath, "utf-8"));
3199
3341
  const nameRes = resolveAppName(cfg.name);
3200
3342
  if (!nameRes.ok) return die(`wrangler.toml: ${nameRes.reason}`);
3201
3343
  appName = nameRes.name;
@@ -3256,7 +3398,7 @@ var publish = defineCommand16({
3256
3398
  p6.outro("Done");
3257
3399
  }
3258
3400
  });
3259
- var unpublish = defineCommand16({
3401
+ var unpublish = defineCommand17({
3260
3402
  meta: {
3261
3403
  name: "unpublish",
3262
3404
  description: "Remove a library entry (owner or admin only)"
@@ -3315,7 +3457,7 @@ var unpublish = defineCommand16({
3315
3457
  p6.outro("Done");
3316
3458
  }
3317
3459
  });
3318
- var library_default = defineCommand16({
3460
+ var library_default = defineCommand17({
3319
3461
  meta: {
3320
3462
  name: "library",
3321
3463
  description: "Manage your DeepSpace library entries"
@@ -3326,13 +3468,85 @@ var library_default = defineCommand16({
3326
3468
  }
3327
3469
  });
3328
3470
 
3471
+ // src/cli/commands/admin.ts
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";
3476
+ var AUTH_URL5 = process.env.DEEPSPACE_AUTH_URL ?? ENVS.prod.auth;
3477
+ var impersonate = defineCommand18({
3478
+ meta: {
3479
+ name: "impersonate",
3480
+ description: "Store a short-lived CLI token for another user"
3481
+ },
3482
+ args: {
3483
+ email: {
3484
+ type: "string",
3485
+ description: "Target user email",
3486
+ required: false
3487
+ },
3488
+ userId: {
3489
+ type: "string",
3490
+ description: "Target user id",
3491
+ required: false
3492
+ },
3493
+ secret: {
3494
+ type: "string",
3495
+ description: "Admin secret; defaults to DEEPSPACE_ADMIN_SECRET",
3496
+ required: false
3497
+ }
3498
+ },
3499
+ async run({ args }) {
3500
+ const secret = args.secret ?? process.env.DEEPSPACE_ADMIN_SECRET;
3501
+ if (!secret) {
3502
+ console.error("Missing admin secret. Set DEEPSPACE_ADMIN_SECRET or pass --secret.");
3503
+ process.exit(1);
3504
+ }
3505
+ if (!args.email && !args.userId) {
3506
+ console.error("Pass --email or --userId.");
3507
+ process.exit(1);
3508
+ }
3509
+ const res = await fetch(`${AUTH_URL5}/api/auth/admin/impersonate`, {
3510
+ method: "POST",
3511
+ headers: {
3512
+ "Content-Type": "application/json",
3513
+ Authorization: `Bearer ${secret}`
3514
+ },
3515
+ body: JSON.stringify({
3516
+ email: args.email,
3517
+ userId: args.userId
3518
+ })
3519
+ });
3520
+ const data = await res.json().catch(() => ({}));
3521
+ if (!res.ok || !data.token || !data.user) {
3522
+ console.error(`Failed: ${data.error ?? `HTTP ${res.status}`}`);
3523
+ process.exit(1);
3524
+ }
3525
+ const dir = join15(homedir6(), ".deepspace");
3526
+ mkdirSync5(dir, { recursive: true });
3527
+ writeFileSync5(TOKEN_PATH2, data.token, { mode: 384 });
3528
+ console.log(`Impersonating ${data.user.name ?? data.user.email ?? data.user.id}`);
3529
+ console.log(`Email: ${data.user.email ?? "(none)"}`);
3530
+ console.log(`UserID: ${data.user.id}`);
3531
+ }
3532
+ });
3533
+ var admin_default = defineCommand18({
3534
+ meta: {
3535
+ name: "admin",
3536
+ description: "Maintainer-only admin commands"
3537
+ },
3538
+ subCommands: {
3539
+ impersonate
3540
+ }
3541
+ });
3542
+
3329
3543
  // src/cli/cli.ts
3330
3544
  var __dirname = dirname2(fileURLToPath(import.meta.url));
3331
- var pkg = JSON.parse(readFileSync10(join13(__dirname, "..", "package.json"), "utf-8"));
3332
- 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")) {
3333
3547
  process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
3334
3548
  }
3335
- var create3 = defineCommand17({
3549
+ var create3 = defineCommand19({
3336
3550
  meta: {
3337
3551
  name: "create",
3338
3552
  description: "Create a new DeepSpace app"
@@ -3351,7 +3565,7 @@ var create3 = defineCommand17({
3351
3565
  execSync5(`npm create deepspace@latest${name}`, { stdio: "inherit" });
3352
3566
  }
3353
3567
  });
3354
- var main = defineCommand17({
3568
+ var main = defineCommand19({
3355
3569
  meta: {
3356
3570
  name: "deepspace",
3357
3571
  version: pkg.version,
@@ -3368,13 +3582,15 @@ var main = defineCommand17({
3368
3582
  screenshot: screenshot_default,
3369
3583
  "test-accounts": test_accounts_default,
3370
3584
  add: add_default,
3585
+ skills: skills_default,
3371
3586
  integrations: integrations_default,
3372
3587
  "managed-repos": managed_repos_default,
3373
3588
  invoke: invoke_default,
3374
3589
  deploy: deploy_default,
3375
3590
  undeploy: undeploy_default,
3376
3591
  domain: domain_default,
3377
- library: library_default
3592
+ library: library_default,
3593
+ admin: admin_default
3378
3594
  }
3379
3595
  // No `run()` here — citty cascades parent run() AFTER subcommand finishes,
3380
3596
  // which corrupts agent-friendly output (`--json`) and prints noise on every