deepspace 0.28.1 → 0.28.2

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
@@ -1800,6 +1800,24 @@ function healBlocker(appDir, wranglerEnv) {
1800
1800
  }
1801
1801
  return null;
1802
1802
  }
1803
+ async function registerForLocalRun(appDir, token, wranglerEnv) {
1804
+ try {
1805
+ return (await ensureAppRegistered(appDir, token, wranglerEnv))?.appId ?? null;
1806
+ } catch (registrationError) {
1807
+ let hasUsableId = false;
1808
+ try {
1809
+ hasUsableId = readAppId(appDir, wranglerEnv) !== null;
1810
+ } catch {
1811
+ }
1812
+ if (!hasUsableId) throw registrationError;
1813
+ const firstLine = registrationError instanceof Error ? registrationError.message.split("\n")[0] : String(registrationError);
1814
+ process.stderr.write(
1815
+ `warning: could not register the app (${firstLine}) \u2014 continuing without app secrets.
1816
+ `
1817
+ );
1818
+ return null;
1819
+ }
1820
+ }
1803
1821
  function healRefusal(appDir, wranglerEnv) {
1804
1822
  const blocker = healBlocker(appDir, wranglerEnv);
1805
1823
  if (blocker === "placeholder_committed") {
@@ -2332,7 +2350,7 @@ function resolveWorkspaceWorktree(worktrees, workspaceId) {
2332
2350
  // src/cli/lib/source-api.ts
2333
2351
  function githubSourceRefusal(appId, repository) {
2334
2352
  return new Refusal(
2335
- `This app uses GitHub source (${repository}). Use normal Git/GitHub for source operations (clone, fetch, push); \`deepspace deploy\` ships the local working tree without changing Git.`,
2353
+ `This app uses GitHub source (${repository}). Use normal Git/GitHub for source operations. \`deepspace deploy\` ships the local working tree without changing Git.`,
2336
2354
  "source_managed_by_github",
2337
2355
  { extra: { appId, repository } }
2338
2356
  );
@@ -3776,7 +3794,11 @@ async function ensurePortFree(port, host, waitMs = 15e3) {
3776
3794
  `Port ${port} is already in use.
3777
3795
  Free it with \`${killArgv.join(" ")}\`, or use another port: \`--port <other>\`.`,
3778
3796
  "port_in_use",
3779
- { extra: { port } }
3797
+ // The machine action the contract documents for this refusal — the prose
3798
+ // named it while `--json` carried none (2026-08-28 coldstart AX). Not
3799
+ // actionRequired: freeing the port and choosing another port are both
3800
+ // legitimate, so the choice stays the caller's.
3801
+ { extra: { port }, action: { cwd: process.cwd(), argv: killArgv } }
3780
3802
  );
3781
3803
  }
3782
3804
  async function isHttpResponding(port, timeoutMs = 2e3) {
@@ -3918,6 +3940,7 @@ var dev_default = defineDeepspaceCommand({
3918
3940
  writeLaunchConfigIfMissing(appDir, detectAppName(appDir) ?? basename2(appDir), port, {
3919
3941
  updatePort: explicitPort
3920
3942
  });
3943
+ ensureInstallReady(appDir);
3921
3944
  let token;
3922
3945
  try {
3923
3946
  token = await ensureToken();
@@ -3940,21 +3963,12 @@ var dev_default = defineDeepspaceCommand({
3940
3963
  if (wranglerEnv) say(`Wrangler env: ${wranglerEnv}`);
3941
3964
  say(`Port: ${port}`);
3942
3965
  if (host !== DEFAULT_DEV_HOST) say(`Host: ${host}`);
3943
- ensureInstallReady(appDir);
3944
3966
  const lintFindings = await lintProjectSchemas(appDir);
3945
3967
  if (lintFindings && lintFindings.length > 0 && !args.json) {
3946
3968
  for (const line of formatSchemaLintFindings(lintFindings)) console.warn(line);
3947
3969
  }
3948
3970
  let generatedSecretsCache;
3949
- let appIdForSecrets = null;
3950
- try {
3951
- appIdForSecrets = (await ensureAppRegistered(appDir, token, wranglerEnv))?.appId ?? null;
3952
- } catch (registrationError) {
3953
- process.stderr.write(
3954
- `warning: could not register the app (${registrationError instanceof Error ? registrationError.message.split("\n")[0] : String(registrationError)}) \u2014 continuing without app secrets.
3955
- `
3956
- );
3957
- }
3971
+ const appIdForSecrets = await registerForLocalRun(appDir, token, wranglerEnv);
3958
3972
  if (appIdForSecrets) {
3959
3973
  try {
3960
3974
  const refreshed = await refreshSecretsCache(DEPLOY_URL2, token, appIdForSecrets, wranglerEnv);
@@ -4644,6 +4658,7 @@ var test_default = defineDeepspaceCommand({
4644
4658
  arg: args.port,
4645
4659
  worktree: () => resolveWorktreePort(appDir)
4646
4660
  });
4661
+ ensureInstallReady(appDir);
4647
4662
  if (suite !== "unit") await ensurePortFree(port, "0.0.0.0");
4648
4663
  let token;
4649
4664
  let ownerId;
@@ -4658,17 +4673,8 @@ var test_default = defineDeepspaceCommand({
4658
4673
  { action: cliAction("deepspace", "auth", "login") }
4659
4674
  );
4660
4675
  }
4661
- ensureInstallReady(appDir);
4662
4676
  let generatedSecretsCache;
4663
- let appIdForSecrets = null;
4664
- try {
4665
- appIdForSecrets = (await ensureAppRegistered(appDir, token, wranglerEnv))?.appId ?? null;
4666
- } catch (registrationError) {
4667
- process.stderr.write(
4668
- `warning: could not register the app (${registrationError instanceof Error ? registrationError.message.split("\n")[0] : String(registrationError)}) \u2014 continuing without app secrets.
4669
- `
4670
- );
4671
- }
4677
+ const appIdForSecrets = await registerForLocalRun(appDir, token, wranglerEnv);
4672
4678
  if (appIdForSecrets) {
4673
4679
  try {
4674
4680
  const refreshed = await refreshSecretsCache(DEPLOY_URL3, token, appIdForSecrets, wranglerEnv);
@@ -4928,7 +4934,8 @@ async function requireConsent(opts) {
4928
4934
 
4929
4935
  // src/cli/commands/test-accounts.ts
4930
4936
  function testAccountFailure(err, fallbackCode) {
4931
- const message = err instanceof Error ? err.message : String(err);
4937
+ const raw = err instanceof Error ? err.message : String(err);
4938
+ const message = raw.replace(/\.\s*$/, "");
4932
4939
  const code = err instanceof TestAccountServiceError ? err.code : void 0;
4933
4940
  if (code === "test_account_cap") {
4934
4941
  return new Refusal(
@@ -4948,7 +4955,7 @@ function testAccountFailure(err, fallbackCode) {
4948
4955
  "not_authenticated"
4949
4956
  );
4950
4957
  }
4951
- return new Refusal(`Failed: ${message}`, code ?? fallbackCode);
4958
+ return new Refusal(`Failed: ${raw}`, code ?? fallbackCode);
4952
4959
  }
4953
4960
  var create = defineDeepspaceCommand({
4954
4961
  meta: {
@@ -5291,7 +5298,7 @@ var recover = defineDeepspaceCommand({
5291
5298
  targets = remote.filter((account) => !known.has(account.id));
5292
5299
  if (targets.length === 0) {
5293
5300
  if (!args.json) console.log("Every pool account already has a local credential.");
5294
- return { data: { recovered: [], alreadyLocal: remote.length } };
5301
+ return { data: { recovered: [], alreadyLocal: remote.length, savedTo: TEST_ACCOUNTS_PATH } };
5295
5302
  }
5296
5303
  } else {
5297
5304
  const match = args.id ? remote.find((account) => account.id === args.id) : remote.find((account) => account.email === args.email);
@@ -5342,7 +5349,7 @@ Stored in ${TEST_ACCOUNTS_PATH}. ${rotatedCount} account(s) had no stored creden
5342
5349
  Stored in ${TEST_ACCOUNTS_PATH}. Passwords were retrieved, not reset \u2014 other machines' credentials still work.`
5343
5350
  );
5344
5351
  }
5345
- return { data: { recovered, requested: targets.length, failures: [] } };
5352
+ return { data: { recovered, requested: targets.length, failures: [], savedTo: TEST_ACCOUNTS_PATH } };
5346
5353
  }
5347
5354
  });
5348
5355
  var test_accounts_default = defineCommand2({
@@ -8055,6 +8062,9 @@ var whoami_default = defineDeepspaceCommand({
8055
8062
  console.log(`Email: ${payload.email ?? "(none)"}`);
8056
8063
  console.log(`Type: ${accountType}`);
8057
8064
  if (payload.iss) console.log(`Issuer: ${payload.iss}`);
8065
+ if (payload.exp) {
8066
+ console.log(`Expires: ${new Date(payload.exp * 1e3).toISOString()} (renews on use)`);
8067
+ }
8058
8068
  console.log(`Dashboard: ${DASHBOARD_URL}`);
8059
8069
  if (isTestAccount) {
8060
8070
  console.log("");
@@ -8537,7 +8547,7 @@ function renderSummary(summary) {
8537
8547
  var usage_default = defineDeepspaceCommand({
8538
8548
  meta: {
8539
8549
  name: "usage",
8540
- description: "Show account-wide credits and integration spend (all apps)"
8550
+ description: "Show account-wide credits and integration spend (all apps). Storage is per app: `deepspace app files list`"
8541
8551
  },
8542
8552
  async run({ args }) {
8543
8553
  const token = await ensureToken();
@@ -11289,7 +11299,7 @@ function httpRefusal(response, tokens) {
11289
11299
  }
11290
11300
  if (response.status === 404 && !server) {
11291
11301
  return new Refusal(
11292
- "This app does not expose the requested agent endpoint.",
11302
+ "No agent endpoint answered for this app. Either the app name/id is wrong (`deepspace app list` shows yours), or the app does not register assistant tools \u2014 its worker needs `registerAgent(app, { tools, inApp: false })` deployed.",
11293
11303
  "agent_endpoint_not_found"
11294
11304
  );
11295
11305
  }
@@ -12252,6 +12262,9 @@ var init_default = defineDeepspaceCommand({
12252
12262
  console.log(
12253
12263
  `Registered on ${DEEPSPACE_ENV} as a NEW app under ${accountLabel(token)}; the original is untouched.`
12254
12264
  );
12265
+ console.log(
12266
+ "Note: the fork keeps the wrangler `name` \u2014 its first deploy targets the SAME subdomain as the original. For a separate URL, change `name` in wrangler.toml (and APP_NAME) before deploying."
12267
+ );
12255
12268
  } else {
12256
12269
  console.log(`Registered ${appId}${envSuffix} on ${DEEPSPACE_ENV} to ${accountLabel(token)}${commitNote}`);
12257
12270
  if (replacedMalformed !== null) {
@@ -12403,6 +12416,7 @@ var status_default = defineCommand12({
12403
12416
  json.sessionError = sessionError("Not logged in. Run `deepspace auth login` first.");
12404
12417
  } else {
12405
12418
  let who = null;
12419
+ let undecodableToken = false;
12406
12420
  try {
12407
12421
  const payload = decodeJwtPayload(
12408
12422
  readFileSync23(TOKEN_PATH, "utf-8").trim()
@@ -12410,13 +12424,39 @@ var status_default = defineCommand12({
12410
12424
  if (payload.email) who = payload.email;
12411
12425
  userId = payload.sub ?? null;
12412
12426
  } catch {
12427
+ undecodableToken = existsSync26(TOKEN_PATH);
12428
+ }
12429
+ let sessionLineEmitted = false;
12430
+ if (undecodableToken) {
12431
+ try {
12432
+ const healed = await ensureToken();
12433
+ const payload = decodeJwtPayload(healed);
12434
+ if (payload.email) who = payload.email;
12435
+ userId = payload.sub ?? null;
12436
+ } catch (err) {
12437
+ sessionLineEmitted = true;
12438
+ const offline = err instanceof TypeError || errorCode(err) === "network_error";
12439
+ if (offline) {
12440
+ lines.push(["Session", "logged in \xB7 stored token unreadable, could not verify offline"]);
12441
+ json.loggedIn = true;
12442
+ } else {
12443
+ lines.push(["Session", "stored credentials unusable \u2014 run `deepspace auth login`"]);
12444
+ facts.loggedIn = false;
12445
+ json.loggedIn = false;
12446
+ json.sessionError = sessionError(
12447
+ "Stored credentials are unusable. Run `deepspace auth login`."
12448
+ );
12449
+ }
12450
+ }
12451
+ }
12452
+ if (!sessionLineEmitted) {
12453
+ lines.push([
12454
+ "Session",
12455
+ `${who ?? "logged in"} \xB7 renews on use (re-login only after 30 idle days)`
12456
+ ]);
12457
+ json.loggedIn = true;
12458
+ if (who) json.user = who;
12413
12459
  }
12414
- lines.push([
12415
- "Session",
12416
- `${who ?? "logged in"} \xB7 renews on use (re-login only after 30 idle days)`
12417
- ]);
12418
- json.loggedIn = true;
12419
- if (who) json.user = who;
12420
12460
  }
12421
12461
  const appDir = findAppDir();
12422
12462
  if (!appDir) {
@@ -12551,9 +12591,10 @@ var status_default = defineCommand12({
12551
12591
  ]);
12552
12592
  json.source = { ...source, revision: sourceResult.value.revision };
12553
12593
  } else {
12594
+ const observed = inferredGithub ? observedGitHubRepository(appDir) : null;
12554
12595
  lines.push([
12555
12596
  "Source",
12556
- `unclaimed \xB7 ${inferredGithub ? "first release claims GitHub (from this checkout\u2019s remote), permanently" : "first deploy or push claims DeepSpace, permanently"}`
12597
+ `unclaimed \xB7 ${inferredGithub ? `first release claims GitHub${observed ? ` (${observed})` : ""} from this checkout\u2019s remote, permanently` : "first deploy or push claims DeepSpace, permanently"}`
12557
12598
  ]);
12558
12599
  json.source = null;
12559
12600
  json.sourceInference = inferredGithub ? "github" : "deepspace";
@@ -14175,9 +14216,9 @@ var newWorkspaceCommand = defineDeepspaceCommand({
14175
14216
  },
14176
14217
  async run({ args }) {
14177
14218
  const task = typeof args.task === "string" ? args.task.trim() : "";
14178
- if (!task) {
14219
+ if (!task || task.startsWith("-")) {
14179
14220
  throw new Refusal(
14180
- 'A workspace needs a task \u2014 pass -t "<what this workspace is for>" (it is shown to every collaborator and agent).',
14221
+ 'A workspace needs a task \u2014 pass -t "<what this workspace is for>" (quote it, and put flags like --json after it; it is shown to every collaborator and agent).',
14181
14222
  "invalid_task"
14182
14223
  );
14183
14224
  }
@@ -15528,7 +15569,7 @@ function formatEvent2(e, lands, actors) {
15528
15569
  detail = `"${String(s.task ?? "")}" from ${short(s.baseOid)}`;
15529
15570
  break;
15530
15571
  case "workspace.synced":
15531
- detail = `${e.subjectId ? `${e.subjectId} ` : ""}\u2192 ${short(s.headOid)}`;
15572
+ detail = `${e.subjectId ? `${e.subjectId} ` : ""}${typeof s.task === "string" && s.task ? `"${s.task}" ` : ""}\u2192 ${short(s.headOid)}`;
15532
15573
  break;
15533
15574
  case "workspace.landed":
15534
15575
  detail = `"${String(s.task ?? "")}" \u2192 ${short(s.landedOid)} on ${String(s.into ?? "trunk")}`;
@@ -15799,6 +15840,7 @@ function reportSource(appId, state, json) {
15799
15840
  );
15800
15841
  }
15801
15842
  console.log(`Revision: ${state.revision}`);
15843
+ console.log(`Registered: ${state.registered ? "yes" : "no"}`);
15802
15844
  }
15803
15845
 
15804
15846
  // src/cli/commands/update.ts
@@ -15809,7 +15851,7 @@ import { join as join28, resolve as resolve22 } from "path";
15809
15851
  // package.json
15810
15852
  var package_default = {
15811
15853
  name: "deepspace",
15812
- version: "0.28.1",
15854
+ version: "0.28.2",
15813
15855
  engines: {
15814
15856
  node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
15815
15857
  },