deepspace 0.28.0 → 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/CHANGELOG.md +43 -0
- package/README.md +8 -0
- package/dist/{chunk-652TIGI4.js → chunk-DMUR67NG.js} +2 -2
- package/dist/{chunk-652TIGI4.js.map → chunk-DMUR67NG.js.map} +1 -1
- package/dist/cli.js +546 -72
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +1 -1
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +1 -1
- package/dist/documentation.js.map +1 -1
- package/dist/server.d.ts +21 -1
- package/dist/server.js +52 -12
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +99 -1
- package/dist/worker.js +360 -34
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/cli.ts
|
|
4
4
|
import {
|
|
5
|
-
defineCommand as
|
|
5
|
+
defineCommand as defineCommand15,
|
|
6
6
|
runMain,
|
|
7
7
|
runCommand,
|
|
8
8
|
renderUsage
|
|
@@ -660,6 +660,9 @@ var INVALID_URLS = {
|
|
|
660
660
|
platform: "http://127.0.0.1:9",
|
|
661
661
|
deploy: "http://127.0.0.1:9"
|
|
662
662
|
};
|
|
663
|
+
function appDomainForEnv(env) {
|
|
664
|
+
return env === "production" ? "app.space" : env === "staging" ? "spacestest.com" : null;
|
|
665
|
+
}
|
|
663
666
|
var PLATFORM_URLS = DEEPSPACE_ENV === "production" ? PROD_URLS : DEEPSPACE_ENV === "staging" ? STAGING_URLS : INVALID_URLS;
|
|
664
667
|
var PLANE_AUTH_URLS = {
|
|
665
668
|
production: PROD_URLS.auth,
|
|
@@ -689,10 +692,11 @@ function decodeJwtPayload(token) {
|
|
|
689
692
|
return JSON.parse(Buffer.from(payloadSegment, "base64url").toString("utf8"));
|
|
690
693
|
}
|
|
691
694
|
|
|
692
|
-
// src/
|
|
695
|
+
// src/shared/auth-session.ts
|
|
693
696
|
var SESSION_COOKIE = "__Secure-better-auth.session_token";
|
|
694
|
-
|
|
695
|
-
|
|
697
|
+
|
|
698
|
+
// src/cli/session.ts
|
|
699
|
+
async function exchangeSessionToken(authUrl, sessionToken, path, action, body) {
|
|
696
700
|
let res;
|
|
697
701
|
try {
|
|
698
702
|
res = await fetchWithTransientRetry(
|
|
@@ -701,8 +705,10 @@ async function exchangeSession(authUrl, sessionToken) {
|
|
|
701
705
|
method: "POST",
|
|
702
706
|
headers: {
|
|
703
707
|
Cookie: `${SESSION_COOKIE}=${encodeURIComponent(sessionToken)}`,
|
|
704
|
-
Origin: authUrl
|
|
705
|
-
|
|
708
|
+
Origin: authUrl,
|
|
709
|
+
...body === void 0 ? {} : { "Content-Type": "application/json" }
|
|
710
|
+
},
|
|
711
|
+
body
|
|
706
712
|
}),
|
|
707
713
|
{ timeoutMs: 15e3 }
|
|
708
714
|
);
|
|
@@ -717,7 +723,7 @@ async function exchangeSession(authUrl, sessionToken) {
|
|
|
717
723
|
if (res.status === 401) return null;
|
|
718
724
|
if (!res.ok) {
|
|
719
725
|
throw new ApiError(
|
|
720
|
-
`The auth service could not
|
|
726
|
+
`The auth service could not ${action} (HTTP ${res.status}). Retry without logging in again.`,
|
|
721
727
|
res.status,
|
|
722
728
|
res.status === 429 ? "rate_limited" : "auth_service_unavailable",
|
|
723
729
|
path
|
|
@@ -744,6 +750,18 @@ async function exchangeSession(authUrl, sessionToken) {
|
|
|
744
750
|
}
|
|
745
751
|
return data.token;
|
|
746
752
|
}
|
|
753
|
+
function exchangeSession(authUrl, sessionToken) {
|
|
754
|
+
return exchangeSessionToken(authUrl, sessionToken, "/api/auth/token", "refresh the CLI token");
|
|
755
|
+
}
|
|
756
|
+
function exchangeAgentSession(authUrl, sessionToken, target2) {
|
|
757
|
+
return exchangeSessionToken(
|
|
758
|
+
authUrl,
|
|
759
|
+
sessionToken,
|
|
760
|
+
"/api/auth/agent-token",
|
|
761
|
+
"mint the app-specific agent token",
|
|
762
|
+
JSON.stringify({ target: target2 })
|
|
763
|
+
);
|
|
764
|
+
}
|
|
747
765
|
|
|
748
766
|
// src/cli/lib/secure-file.ts
|
|
749
767
|
import { chmodSync, writeFileSync } from "fs";
|
|
@@ -814,6 +832,14 @@ function isTokenValid(jwt, minimumValidityMs) {
|
|
|
814
832
|
async function refreshTokenFromSession() {
|
|
815
833
|
return await exchangeStoredSession();
|
|
816
834
|
}
|
|
835
|
+
async function mintAgentToken(target2) {
|
|
836
|
+
if (!existsSync(SESSION_PATH)) throw notAuthenticated("Not logged in");
|
|
837
|
+
const sessionToken = readFileSync2(SESSION_PATH, "utf-8").trim();
|
|
838
|
+
const token = await exchangeAgentSession(AUTH_URL, sessionToken, target2);
|
|
839
|
+
if (!token)
|
|
840
|
+
throw notAuthenticated("The stored session is no longer valid (expired or unreadable)");
|
|
841
|
+
return token;
|
|
842
|
+
}
|
|
817
843
|
async function exchangeStoredSession() {
|
|
818
844
|
if (!existsSync(SESSION_PATH)) return null;
|
|
819
845
|
const sessionToken = readFileSync2(SESSION_PATH, "utf-8").trim();
|
|
@@ -1774,6 +1800,24 @@ function healBlocker(appDir, wranglerEnv) {
|
|
|
1774
1800
|
}
|
|
1775
1801
|
return null;
|
|
1776
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
|
+
}
|
|
1777
1821
|
function healRefusal(appDir, wranglerEnv) {
|
|
1778
1822
|
const blocker = healBlocker(appDir, wranglerEnv);
|
|
1779
1823
|
if (blocker === "placeholder_committed") {
|
|
@@ -2306,7 +2350,7 @@ function resolveWorkspaceWorktree(worktrees, workspaceId) {
|
|
|
2306
2350
|
// src/cli/lib/source-api.ts
|
|
2307
2351
|
function githubSourceRefusal(appId, repository) {
|
|
2308
2352
|
return new Refusal(
|
|
2309
|
-
`This app uses GitHub source (${repository}). Use normal Git/GitHub for source operations
|
|
2353
|
+
`This app uses GitHub source (${repository}). Use normal Git/GitHub for source operations. \`deepspace deploy\` ships the local working tree without changing Git.`,
|
|
2310
2354
|
"source_managed_by_github",
|
|
2311
2355
|
{ extra: { appId, repository } }
|
|
2312
2356
|
);
|
|
@@ -3750,7 +3794,11 @@ async function ensurePortFree(port, host, waitMs = 15e3) {
|
|
|
3750
3794
|
`Port ${port} is already in use.
|
|
3751
3795
|
Free it with \`${killArgv.join(" ")}\`, or use another port: \`--port <other>\`.`,
|
|
3752
3796
|
"port_in_use",
|
|
3753
|
-
|
|
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 } }
|
|
3754
3802
|
);
|
|
3755
3803
|
}
|
|
3756
3804
|
async function isHttpResponding(port, timeoutMs = 2e3) {
|
|
@@ -3892,6 +3940,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
3892
3940
|
writeLaunchConfigIfMissing(appDir, detectAppName(appDir) ?? basename2(appDir), port, {
|
|
3893
3941
|
updatePort: explicitPort
|
|
3894
3942
|
});
|
|
3943
|
+
ensureInstallReady(appDir);
|
|
3895
3944
|
let token;
|
|
3896
3945
|
try {
|
|
3897
3946
|
token = await ensureToken();
|
|
@@ -3914,21 +3963,12 @@ var dev_default = defineDeepspaceCommand({
|
|
|
3914
3963
|
if (wranglerEnv) say(`Wrangler env: ${wranglerEnv}`);
|
|
3915
3964
|
say(`Port: ${port}`);
|
|
3916
3965
|
if (host !== DEFAULT_DEV_HOST) say(`Host: ${host}`);
|
|
3917
|
-
ensureInstallReady(appDir);
|
|
3918
3966
|
const lintFindings = await lintProjectSchemas(appDir);
|
|
3919
3967
|
if (lintFindings && lintFindings.length > 0 && !args.json) {
|
|
3920
3968
|
for (const line of formatSchemaLintFindings(lintFindings)) console.warn(line);
|
|
3921
3969
|
}
|
|
3922
3970
|
let generatedSecretsCache;
|
|
3923
|
-
|
|
3924
|
-
try {
|
|
3925
|
-
appIdForSecrets = (await ensureAppRegistered(appDir, token, wranglerEnv))?.appId ?? null;
|
|
3926
|
-
} catch (registrationError) {
|
|
3927
|
-
process.stderr.write(
|
|
3928
|
-
`warning: could not register the app (${registrationError instanceof Error ? registrationError.message.split("\n")[0] : String(registrationError)}) \u2014 continuing without app secrets.
|
|
3929
|
-
`
|
|
3930
|
-
);
|
|
3931
|
-
}
|
|
3971
|
+
const appIdForSecrets = await registerForLocalRun(appDir, token, wranglerEnv);
|
|
3932
3972
|
if (appIdForSecrets) {
|
|
3933
3973
|
try {
|
|
3934
3974
|
const refreshed = await refreshSecretsCache(DEPLOY_URL2, token, appIdForSecrets, wranglerEnv);
|
|
@@ -4436,7 +4476,6 @@ function saveTestAccountStore(store) {
|
|
|
4436
4476
|
}
|
|
4437
4477
|
|
|
4438
4478
|
// src/cli/lib/test-account-service.ts
|
|
4439
|
-
var SESSION_COOKIE2 = "__Secure-better-auth.session_token";
|
|
4440
4479
|
var TestAccountServiceError = class extends Error {
|
|
4441
4480
|
constructor(message, code) {
|
|
4442
4481
|
super(message);
|
|
@@ -4449,7 +4488,7 @@ function serviceError(data, fallback) {
|
|
|
4449
4488
|
var AUTH_URL4 = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
|
|
4450
4489
|
function sessionCookie() {
|
|
4451
4490
|
const token = readFileSync12(SESSION_PATH, "utf-8").trim();
|
|
4452
|
-
return `${
|
|
4491
|
+
return `${SESSION_COOKIE}=${encodeURIComponent(token)}`;
|
|
4453
4492
|
}
|
|
4454
4493
|
async function fetchRemoteTestAccounts() {
|
|
4455
4494
|
const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
|
|
@@ -4619,6 +4658,7 @@ var test_default = defineDeepspaceCommand({
|
|
|
4619
4658
|
arg: args.port,
|
|
4620
4659
|
worktree: () => resolveWorktreePort(appDir)
|
|
4621
4660
|
});
|
|
4661
|
+
ensureInstallReady(appDir);
|
|
4622
4662
|
if (suite !== "unit") await ensurePortFree(port, "0.0.0.0");
|
|
4623
4663
|
let token;
|
|
4624
4664
|
let ownerId;
|
|
@@ -4633,17 +4673,8 @@ var test_default = defineDeepspaceCommand({
|
|
|
4633
4673
|
{ action: cliAction("deepspace", "auth", "login") }
|
|
4634
4674
|
);
|
|
4635
4675
|
}
|
|
4636
|
-
ensureInstallReady(appDir);
|
|
4637
4676
|
let generatedSecretsCache;
|
|
4638
|
-
|
|
4639
|
-
try {
|
|
4640
|
-
appIdForSecrets = (await ensureAppRegistered(appDir, token, wranglerEnv))?.appId ?? null;
|
|
4641
|
-
} catch (registrationError) {
|
|
4642
|
-
process.stderr.write(
|
|
4643
|
-
`warning: could not register the app (${registrationError instanceof Error ? registrationError.message.split("\n")[0] : String(registrationError)}) \u2014 continuing without app secrets.
|
|
4644
|
-
`
|
|
4645
|
-
);
|
|
4646
|
-
}
|
|
4677
|
+
const appIdForSecrets = await registerForLocalRun(appDir, token, wranglerEnv);
|
|
4647
4678
|
if (appIdForSecrets) {
|
|
4648
4679
|
try {
|
|
4649
4680
|
const refreshed = await refreshSecretsCache(DEPLOY_URL3, token, appIdForSecrets, wranglerEnv);
|
|
@@ -4903,7 +4934,8 @@ async function requireConsent(opts) {
|
|
|
4903
4934
|
|
|
4904
4935
|
// src/cli/commands/test-accounts.ts
|
|
4905
4936
|
function testAccountFailure(err, fallbackCode) {
|
|
4906
|
-
const
|
|
4937
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
4938
|
+
const message = raw.replace(/\.\s*$/, "");
|
|
4907
4939
|
const code = err instanceof TestAccountServiceError ? err.code : void 0;
|
|
4908
4940
|
if (code === "test_account_cap") {
|
|
4909
4941
|
return new Refusal(
|
|
@@ -4923,7 +4955,7 @@ function testAccountFailure(err, fallbackCode) {
|
|
|
4923
4955
|
"not_authenticated"
|
|
4924
4956
|
);
|
|
4925
4957
|
}
|
|
4926
|
-
return new Refusal(`Failed: ${
|
|
4958
|
+
return new Refusal(`Failed: ${raw}`, code ?? fallbackCode);
|
|
4927
4959
|
}
|
|
4928
4960
|
var create = defineDeepspaceCommand({
|
|
4929
4961
|
meta: {
|
|
@@ -5266,7 +5298,7 @@ var recover = defineDeepspaceCommand({
|
|
|
5266
5298
|
targets = remote.filter((account) => !known.has(account.id));
|
|
5267
5299
|
if (targets.length === 0) {
|
|
5268
5300
|
if (!args.json) console.log("Every pool account already has a local credential.");
|
|
5269
|
-
return { data: { recovered: [], alreadyLocal: remote.length } };
|
|
5301
|
+
return { data: { recovered: [], alreadyLocal: remote.length, savedTo: TEST_ACCOUNTS_PATH } };
|
|
5270
5302
|
}
|
|
5271
5303
|
} else {
|
|
5272
5304
|
const match = args.id ? remote.find((account) => account.id === args.id) : remote.find((account) => account.email === args.email);
|
|
@@ -5317,7 +5349,7 @@ Stored in ${TEST_ACCOUNTS_PATH}. ${rotatedCount} account(s) had no stored creden
|
|
|
5317
5349
|
Stored in ${TEST_ACCOUNTS_PATH}. Passwords were retrieved, not reset \u2014 other machines' credentials still work.`
|
|
5318
5350
|
);
|
|
5319
5351
|
}
|
|
5320
|
-
return { data: { recovered, requested: targets.length, failures: [] } };
|
|
5352
|
+
return { data: { recovered, requested: targets.length, failures: [], savedTo: TEST_ACCOUNTS_PATH } };
|
|
5321
5353
|
}
|
|
5322
5354
|
});
|
|
5323
5355
|
var test_accounts_default = defineCommand2({
|
|
@@ -8030,6 +8062,9 @@ var whoami_default = defineDeepspaceCommand({
|
|
|
8030
8062
|
console.log(`Email: ${payload.email ?? "(none)"}`);
|
|
8031
8063
|
console.log(`Type: ${accountType}`);
|
|
8032
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
|
+
}
|
|
8033
8068
|
console.log(`Dashboard: ${DASHBOARD_URL}`);
|
|
8034
8069
|
if (isTestAccount) {
|
|
8035
8070
|
console.log("");
|
|
@@ -8512,7 +8547,7 @@ function renderSummary(summary) {
|
|
|
8512
8547
|
var usage_default = defineDeepspaceCommand({
|
|
8513
8548
|
meta: {
|
|
8514
8549
|
name: "usage",
|
|
8515
|
-
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`"
|
|
8516
8551
|
},
|
|
8517
8552
|
async run({ args }) {
|
|
8518
8553
|
const token = await ensureToken();
|
|
@@ -10975,6 +11010,412 @@ var integrations_default = defineCommand9({
|
|
|
10975
11010
|
}
|
|
10976
11011
|
});
|
|
10977
11012
|
|
|
11013
|
+
// src/cli/commands/agent.ts
|
|
11014
|
+
import { createReadStream } from "fs";
|
|
11015
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
11016
|
+
|
|
11017
|
+
// src/server/agent-target.ts
|
|
11018
|
+
var PRODUCTION_OFFICIAL_AGENT_ORIGINS = ["https://admin.deep.space"];
|
|
11019
|
+
var PRODUCTION_APP_DOMAIN = "app.space";
|
|
11020
|
+
function normalizeAgentTargetOrigin(value, policy) {
|
|
11021
|
+
if (typeof value !== "string" || !value) return null;
|
|
11022
|
+
let url;
|
|
11023
|
+
try {
|
|
11024
|
+
url = new URL(value);
|
|
11025
|
+
} catch {
|
|
11026
|
+
return null;
|
|
11027
|
+
}
|
|
11028
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== "/") return null;
|
|
11029
|
+
const hostname = url.hostname.toLowerCase();
|
|
11030
|
+
const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(hostname);
|
|
11031
|
+
if (loopback) {
|
|
11032
|
+
return policy.allowLoopback && ["http:", "https:"].includes(url.protocol) ? url.origin : null;
|
|
11033
|
+
}
|
|
11034
|
+
if (url.protocol !== "https:" || url.port) return null;
|
|
11035
|
+
if (policy.appDomain.toLowerCase() === PRODUCTION_APP_DOMAIN && PRODUCTION_OFFICIAL_AGENT_ORIGINS.includes(url.origin)) {
|
|
11036
|
+
return url.origin;
|
|
11037
|
+
}
|
|
11038
|
+
const suffix = `.${policy.appDomain.toLowerCase()}`;
|
|
11039
|
+
if (!hostname.endsWith(suffix)) return null;
|
|
11040
|
+
const label = hostname.slice(0, -suffix.length);
|
|
11041
|
+
return !label.includes(".") && validateAppName(label).valid ? url.origin : null;
|
|
11042
|
+
}
|
|
11043
|
+
|
|
11044
|
+
// src/shared/bounded-body.ts
|
|
11045
|
+
var BodyTooLargeError = class extends Error {
|
|
11046
|
+
constructor(maxBytes) {
|
|
11047
|
+
super(`Body exceeds ${maxBytes} bytes`);
|
|
11048
|
+
this.maxBytes = maxBytes;
|
|
11049
|
+
this.name = "BodyTooLargeError";
|
|
11050
|
+
}
|
|
11051
|
+
};
|
|
11052
|
+
async function readBoundedBodyText(source, maxBytes) {
|
|
11053
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {
|
|
11054
|
+
throw new TypeError("maxBytes must be a positive safe integer");
|
|
11055
|
+
}
|
|
11056
|
+
const declared = source.headers.get("content-length");
|
|
11057
|
+
if (declared && /^\d+$/.test(declared.trim()) && Number(declared) > maxBytes) {
|
|
11058
|
+
await source.body?.cancel().catch(() => void 0);
|
|
11059
|
+
throw new BodyTooLargeError(maxBytes);
|
|
11060
|
+
}
|
|
11061
|
+
if (!source.body) return "";
|
|
11062
|
+
const reader = source.body.getReader();
|
|
11063
|
+
const decoder = new TextDecoder();
|
|
11064
|
+
let bytes = 0;
|
|
11065
|
+
let text2 = "";
|
|
11066
|
+
try {
|
|
11067
|
+
while (true) {
|
|
11068
|
+
const chunk = await reader.read();
|
|
11069
|
+
if (chunk.done) break;
|
|
11070
|
+
bytes += chunk.value.byteLength;
|
|
11071
|
+
if (bytes > maxBytes) {
|
|
11072
|
+
await reader.cancel().catch(() => void 0);
|
|
11073
|
+
throw new BodyTooLargeError(maxBytes);
|
|
11074
|
+
}
|
|
11075
|
+
text2 += decoder.decode(chunk.value, { stream: true });
|
|
11076
|
+
}
|
|
11077
|
+
return text2 + decoder.decode();
|
|
11078
|
+
} finally {
|
|
11079
|
+
reader.releaseLock();
|
|
11080
|
+
}
|
|
11081
|
+
}
|
|
11082
|
+
|
|
11083
|
+
// src/shared/agent-tool-protocol.ts
|
|
11084
|
+
var AGENT_TOOL_REQUEST_BODY_CAP = 64 * 1024;
|
|
11085
|
+
var AGENT_TOOL_RESPONSE_BODY_CAP = 1024 * 1024;
|
|
11086
|
+
|
|
11087
|
+
// src/cli/commands/agent.ts
|
|
11088
|
+
var DEFAULT_TIMEOUT_MS2 = 12e4;
|
|
11089
|
+
var MAX_TIMEOUT_MS = 6e5;
|
|
11090
|
+
var MAX_INPUT_BYTES = AGENT_TOOL_REQUEST_BODY_CAP;
|
|
11091
|
+
var MAX_RESPONSE_BYTES = AGENT_TOOL_RESPONSE_BODY_CAP;
|
|
11092
|
+
function badApp(message) {
|
|
11093
|
+
throw new Refusal(message, "invalid_agent_app");
|
|
11094
|
+
}
|
|
11095
|
+
function isCanonicalAppLabel(value) {
|
|
11096
|
+
return value.length >= APP_NAME_RULES.minLength && value.length <= APP_NAME_RULES.maxLength && APP_NAME_RULES.pattern.test(value);
|
|
11097
|
+
}
|
|
11098
|
+
function resolveAgentTarget(app2, plane = DEEPSPACE_ENV) {
|
|
11099
|
+
if (typeof app2 !== "string" || !app2)
|
|
11100
|
+
badApp("App must be a canonical app name or canonical app URL.");
|
|
11101
|
+
const appDomain = appDomainForEnv(plane);
|
|
11102
|
+
if (!appDomain) badApp("The selected DeepSpace environment is invalid.");
|
|
11103
|
+
if (app2.toLowerCase() === "localhost") {
|
|
11104
|
+
badApp("Pass an explicit loopback URL for local development (e.g. 'http://localhost:8787').");
|
|
11105
|
+
}
|
|
11106
|
+
if (isCanonicalAppLabel(app2)) {
|
|
11107
|
+
return { url: `https://${app2}.${appDomain}` };
|
|
11108
|
+
}
|
|
11109
|
+
const url = normalizeAgentTargetOrigin(app2, {
|
|
11110
|
+
appDomain,
|
|
11111
|
+
allowLoopback: true
|
|
11112
|
+
});
|
|
11113
|
+
if (!url) {
|
|
11114
|
+
badApp(
|
|
11115
|
+
"App URL must be an exact canonical app origin (or a root loopback URL for local development)."
|
|
11116
|
+
);
|
|
11117
|
+
}
|
|
11118
|
+
return { url };
|
|
11119
|
+
}
|
|
11120
|
+
function parseAgentTimeout(raw) {
|
|
11121
|
+
if (raw == null) return DEFAULT_TIMEOUT_MS2;
|
|
11122
|
+
const value = typeof raw === "number" ? raw : Number(raw);
|
|
11123
|
+
if (!Number.isInteger(value) || value <= 0 || value > MAX_TIMEOUT_MS) {
|
|
11124
|
+
throw new Refusal(
|
|
11125
|
+
`Invalid --timeout '${String(raw)}'. Must be a positive integer up to ${MAX_TIMEOUT_MS} milliseconds.`,
|
|
11126
|
+
"invalid_timeout"
|
|
11127
|
+
);
|
|
11128
|
+
}
|
|
11129
|
+
return value;
|
|
11130
|
+
}
|
|
11131
|
+
function assertInputSize(value) {
|
|
11132
|
+
if (Buffer.byteLength(value) > MAX_INPUT_BYTES) {
|
|
11133
|
+
throw new Refusal(`Input exceeds the ${MAX_INPUT_BYTES}-byte limit.`, "input_too_large");
|
|
11134
|
+
}
|
|
11135
|
+
}
|
|
11136
|
+
function serializeAgentInput(input) {
|
|
11137
|
+
const body = JSON.stringify({ input });
|
|
11138
|
+
if (Buffer.byteLength(body) > AGENT_TOOL_REQUEST_BODY_CAP) {
|
|
11139
|
+
throw new Refusal(
|
|
11140
|
+
`Tool request exceeds the ${AGENT_TOOL_REQUEST_BODY_CAP}-byte limit.`,
|
|
11141
|
+
"input_too_large"
|
|
11142
|
+
);
|
|
11143
|
+
}
|
|
11144
|
+
return body;
|
|
11145
|
+
}
|
|
11146
|
+
async function readBoundedLocalInput(source) {
|
|
11147
|
+
const chunks = [];
|
|
11148
|
+
let size = 0;
|
|
11149
|
+
for await (const chunk of source) {
|
|
11150
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
11151
|
+
size += buffer.length;
|
|
11152
|
+
if (size > MAX_INPUT_BYTES) {
|
|
11153
|
+
throw new Refusal(`Input exceeds the ${MAX_INPUT_BYTES}-byte limit.`, "input_too_large");
|
|
11154
|
+
}
|
|
11155
|
+
chunks.push(buffer);
|
|
11156
|
+
}
|
|
11157
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
11158
|
+
}
|
|
11159
|
+
async function resolveAgentInput(opts) {
|
|
11160
|
+
if (opts.input != null && opts.inputFile != null) {
|
|
11161
|
+
throw new Refusal("Pass either --input or --input-file, not both.", "conflicting_input_args");
|
|
11162
|
+
}
|
|
11163
|
+
let raw = "{}";
|
|
11164
|
+
if (opts.input != null) {
|
|
11165
|
+
raw = opts.input;
|
|
11166
|
+
assertInputSize(raw);
|
|
11167
|
+
} else if (opts.inputFile != null) {
|
|
11168
|
+
if (opts.inputFile === "-") {
|
|
11169
|
+
raw = await readBoundedLocalInput(process.stdin);
|
|
11170
|
+
} else {
|
|
11171
|
+
try {
|
|
11172
|
+
raw = await readBoundedLocalInput(createReadStream(opts.inputFile));
|
|
11173
|
+
} catch (error) {
|
|
11174
|
+
if (error instanceof Refusal) throw error;
|
|
11175
|
+
throw new Refusal(`Could not read input file '${opts.inputFile}'.`, "input_file_unreadable");
|
|
11176
|
+
}
|
|
11177
|
+
}
|
|
11178
|
+
}
|
|
11179
|
+
try {
|
|
11180
|
+
return JSON.parse(raw);
|
|
11181
|
+
} catch {
|
|
11182
|
+
throw new Refusal("Input is not valid JSON.", "invalid_input_json");
|
|
11183
|
+
}
|
|
11184
|
+
}
|
|
11185
|
+
function isRecord(value) {
|
|
11186
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11187
|
+
}
|
|
11188
|
+
function validApp(value) {
|
|
11189
|
+
return isRecord(value) && typeof value.id === "string" && typeof value.name === "string";
|
|
11190
|
+
}
|
|
11191
|
+
function validTool(value) {
|
|
11192
|
+
return isRecord(value) && typeof value.name === "string" && typeof value.description === "string" && Object.prototype.hasOwnProperty.call(value, "inputSchema");
|
|
11193
|
+
}
|
|
11194
|
+
function parseToolsResponse(value) {
|
|
11195
|
+
if (!isRecord(value) || value.ok !== true || !validApp(value.app) || !Array.isArray(value.tools)) {
|
|
11196
|
+
throw new Refusal("The app returned an unexpected tools response.", "invalid_agent_response");
|
|
11197
|
+
}
|
|
11198
|
+
if (!value.tools.every(validTool)) {
|
|
11199
|
+
throw new Refusal("The app returned an invalid tool definition.", "invalid_agent_response");
|
|
11200
|
+
}
|
|
11201
|
+
return { ok: true, app: value.app, tools: value.tools };
|
|
11202
|
+
}
|
|
11203
|
+
function parseInvokeResponse(value) {
|
|
11204
|
+
if (!isRecord(value) || value.ok !== true || !Object.prototype.hasOwnProperty.call(value, "result")) {
|
|
11205
|
+
throw new Refusal("The app returned an unexpected tool response.", "invalid_agent_response");
|
|
11206
|
+
}
|
|
11207
|
+
return { ok: true, result: value.result };
|
|
11208
|
+
}
|
|
11209
|
+
function safeServerCode(value) {
|
|
11210
|
+
return typeof value === "string" && /^[a-z][a-z0-9_]{0,63}$/.test(value) ? value : void 0;
|
|
11211
|
+
}
|
|
11212
|
+
function redact(value, tokens) {
|
|
11213
|
+
return tokens.reduce(
|
|
11214
|
+
(text2, token) => token ? text2.split(token).join("[redacted]") : text2,
|
|
11215
|
+
value
|
|
11216
|
+
);
|
|
11217
|
+
}
|
|
11218
|
+
function redactValue(value, tokens) {
|
|
11219
|
+
if (typeof value === "string") return redact(value, tokens);
|
|
11220
|
+
if (Array.isArray(value)) return value.map((item) => redactValue(item, tokens));
|
|
11221
|
+
if (isRecord(value)) {
|
|
11222
|
+
return Object.fromEntries(
|
|
11223
|
+
Object.entries(value).map(([key, item]) => [redact(key, tokens), redactValue(item, tokens)])
|
|
11224
|
+
);
|
|
11225
|
+
}
|
|
11226
|
+
return value;
|
|
11227
|
+
}
|
|
11228
|
+
async function readResponseText(response) {
|
|
11229
|
+
try {
|
|
11230
|
+
return await readBoundedBodyText(response, MAX_RESPONSE_BYTES);
|
|
11231
|
+
} catch (error) {
|
|
11232
|
+
if (error instanceof BodyTooLargeError) {
|
|
11233
|
+
throw new Refusal(
|
|
11234
|
+
`App response exceeds the ${MAX_RESPONSE_BYTES}-byte limit.`,
|
|
11235
|
+
"response_too_large"
|
|
11236
|
+
);
|
|
11237
|
+
}
|
|
11238
|
+
throw error;
|
|
11239
|
+
}
|
|
11240
|
+
}
|
|
11241
|
+
async function requestJson(url, init, token, timeout) {
|
|
11242
|
+
const controller = new AbortController();
|
|
11243
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
11244
|
+
try {
|
|
11245
|
+
let response;
|
|
11246
|
+
try {
|
|
11247
|
+
response = await fetch(url, {
|
|
11248
|
+
...init,
|
|
11249
|
+
headers: { ...init.headers, authorization: `Bearer ${token}` },
|
|
11250
|
+
redirect: "manual",
|
|
11251
|
+
signal: controller.signal
|
|
11252
|
+
});
|
|
11253
|
+
} catch (error) {
|
|
11254
|
+
if (controller.signal.aborted || error instanceof Error && error.name === "AbortError") {
|
|
11255
|
+
throw new Refusal(`Request timed out after ${timeout}ms.`, "agent_timeout");
|
|
11256
|
+
}
|
|
11257
|
+
throw new Refusal("Could not reach the app agent endpoint.", "agent_network_error");
|
|
11258
|
+
}
|
|
11259
|
+
if (response.status >= 300 && response.status < 400) {
|
|
11260
|
+
await response.body?.cancel().catch(() => void 0);
|
|
11261
|
+
throw new Refusal(
|
|
11262
|
+
"App agent endpoint redirected; refusing to forward credentials.",
|
|
11263
|
+
"agent_redirect_refused"
|
|
11264
|
+
);
|
|
11265
|
+
}
|
|
11266
|
+
let text2;
|
|
11267
|
+
try {
|
|
11268
|
+
text2 = await readResponseText(response);
|
|
11269
|
+
} catch (error) {
|
|
11270
|
+
if (error instanceof Refusal) throw error;
|
|
11271
|
+
if (controller.signal.aborted || error instanceof Error && error.name === "AbortError") {
|
|
11272
|
+
throw new Refusal(`Request timed out after ${timeout}ms.`, "agent_timeout");
|
|
11273
|
+
}
|
|
11274
|
+
throw new Refusal("Could not read the app agent response.", "agent_network_error");
|
|
11275
|
+
}
|
|
11276
|
+
let body = null;
|
|
11277
|
+
if (text2) {
|
|
11278
|
+
try {
|
|
11279
|
+
body = JSON.parse(text2);
|
|
11280
|
+
} catch {
|
|
11281
|
+
if (response.ok)
|
|
11282
|
+
throw new Refusal("The app returned a non-JSON response.", "invalid_agent_response");
|
|
11283
|
+
}
|
|
11284
|
+
}
|
|
11285
|
+
return { status: response.status, body, text: text2 };
|
|
11286
|
+
} finally {
|
|
11287
|
+
clearTimeout(timer);
|
|
11288
|
+
}
|
|
11289
|
+
}
|
|
11290
|
+
function httpRefusal(response, tokens) {
|
|
11291
|
+
const server = isRecord(response.body) ? response.body : void 0;
|
|
11292
|
+
const code = safeServerCode(server?.code);
|
|
11293
|
+
const message = typeof server?.error === "string" ? redact(server.error, tokens).slice(0, 500) : "";
|
|
11294
|
+
if (response.status === 403) {
|
|
11295
|
+
return new Refusal(
|
|
11296
|
+
message || "You are not allowed to use this app agent.",
|
|
11297
|
+
code ?? "agent_forbidden"
|
|
11298
|
+
);
|
|
11299
|
+
}
|
|
11300
|
+
if (response.status === 404 && !server) {
|
|
11301
|
+
return new Refusal(
|
|
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.",
|
|
11303
|
+
"agent_endpoint_not_found"
|
|
11304
|
+
);
|
|
11305
|
+
}
|
|
11306
|
+
return new Refusal(
|
|
11307
|
+
message || `App agent request failed (${response.status}).`,
|
|
11308
|
+
code ?? (response.status === 404 ? "agent_endpoint_not_found" : "agent_request_failed")
|
|
11309
|
+
);
|
|
11310
|
+
}
|
|
11311
|
+
async function callAgent(target2, path, init, timeout) {
|
|
11312
|
+
let token = await mintAgentToken(target2.url);
|
|
11313
|
+
const tokens = [token];
|
|
11314
|
+
let retried = false;
|
|
11315
|
+
for (; ; ) {
|
|
11316
|
+
const response = await requestJson(`${target2.url}${path}`, init, token, timeout);
|
|
11317
|
+
if (response.status !== 401) {
|
|
11318
|
+
if (response.status < 200 || response.status >= 300) throw httpRefusal(response, tokens);
|
|
11319
|
+
return redactValue(response.body, tokens);
|
|
11320
|
+
}
|
|
11321
|
+
if (!retried) {
|
|
11322
|
+
retried = true;
|
|
11323
|
+
token = await mintAgentToken(target2.url);
|
|
11324
|
+
tokens.push(token);
|
|
11325
|
+
continue;
|
|
11326
|
+
}
|
|
11327
|
+
throw new Refusal(
|
|
11328
|
+
"Authentication was rejected. Run `deepspace auth login` and try again.",
|
|
11329
|
+
"not_authenticated",
|
|
11330
|
+
{ action: cliAction("deepspace", "auth", "login") }
|
|
11331
|
+
);
|
|
11332
|
+
}
|
|
11333
|
+
}
|
|
11334
|
+
async function runAgentTools(args) {
|
|
11335
|
+
const target2 = resolveAgentTarget(args.app);
|
|
11336
|
+
const body = parseToolsResponse(
|
|
11337
|
+
await callAgent(target2, "/_deepspace/agent/tools", { method: "GET" }, DEFAULT_TIMEOUT_MS2)
|
|
11338
|
+
);
|
|
11339
|
+
if (!args.json) {
|
|
11340
|
+
console.log(`App: ${body.app.name} (${body.app.id}, ${target2.url})`);
|
|
11341
|
+
if (body.tools.length === 0) console.log("Tools: none");
|
|
11342
|
+
else {
|
|
11343
|
+
console.log("Tools:");
|
|
11344
|
+
for (const tool of body.tools) {
|
|
11345
|
+
console.log(`- ${tool.name}: ${tool.description}`);
|
|
11346
|
+
console.log(` Input: ${JSON.stringify(tool.inputSchema)}`);
|
|
11347
|
+
if (tool.outputSchema !== void 0) {
|
|
11348
|
+
console.log(` Output: ${JSON.stringify(tool.outputSchema)}`);
|
|
11349
|
+
}
|
|
11350
|
+
}
|
|
11351
|
+
}
|
|
11352
|
+
}
|
|
11353
|
+
return { data: { app: body.app, url: target2.url, tools: body.tools } };
|
|
11354
|
+
}
|
|
11355
|
+
async function runAgentInvoke(args) {
|
|
11356
|
+
const target2 = resolveAgentTarget(args.app);
|
|
11357
|
+
const input = await resolveAgentInput({ input: args.input, inputFile: args.inputFile });
|
|
11358
|
+
const tool = args.tool;
|
|
11359
|
+
if (typeof tool !== "string" || !tool)
|
|
11360
|
+
throw new Refusal("Tool name is required.", "invalid_agent_tool");
|
|
11361
|
+
const requestBody = serializeAgentInput(input);
|
|
11362
|
+
const body = parseInvokeResponse(
|
|
11363
|
+
await callAgent(
|
|
11364
|
+
target2,
|
|
11365
|
+
`/_deepspace/agent/tools/${encodeURIComponent(tool)}`,
|
|
11366
|
+
{
|
|
11367
|
+
method: "POST",
|
|
11368
|
+
headers: { "content-type": "application/json" },
|
|
11369
|
+
body: requestBody
|
|
11370
|
+
},
|
|
11371
|
+
parseAgentTimeout(args.timeout)
|
|
11372
|
+
)
|
|
11373
|
+
);
|
|
11374
|
+
if (!args.json) {
|
|
11375
|
+
console.log(`App: ${args.app} (${target2.url})`);
|
|
11376
|
+
console.log(`Tool: ${tool}`);
|
|
11377
|
+
console.log("Result:");
|
|
11378
|
+
console.log(JSON.stringify(body.result, null, 2));
|
|
11379
|
+
}
|
|
11380
|
+
return { data: { app: args.app, url: target2.url, tool, result: body.result } };
|
|
11381
|
+
}
|
|
11382
|
+
var tools = defineDeepspaceCommand({
|
|
11383
|
+
meta: { name: "tools", description: "List the agent tools exposed by an app" },
|
|
11384
|
+
args: {
|
|
11385
|
+
app: { type: "positional", description: "Canonical app name or URL", required: true }
|
|
11386
|
+
},
|
|
11387
|
+
async run({ args }) {
|
|
11388
|
+
return runAgentTools({ app: args.app, json: args.json });
|
|
11389
|
+
}
|
|
11390
|
+
});
|
|
11391
|
+
var invoke2 = defineDeepspaceCommand({
|
|
11392
|
+
meta: { name: "invoke", description: "Invoke an agent tool exposed by an app" },
|
|
11393
|
+
args: {
|
|
11394
|
+
app: { type: "positional", description: "Canonical app name or URL", required: true },
|
|
11395
|
+
tool: { type: "positional", description: "Tool name", required: true },
|
|
11396
|
+
input: { type: "string", description: "Inline JSON tool input" },
|
|
11397
|
+
"input-file": { type: "string", description: "JSON input file (use - for stdin)" },
|
|
11398
|
+
timeout: {
|
|
11399
|
+
type: "string",
|
|
11400
|
+
description: `Request timeout in milliseconds (default: ${DEFAULT_TIMEOUT_MS2})`
|
|
11401
|
+
}
|
|
11402
|
+
},
|
|
11403
|
+
async run({ args }) {
|
|
11404
|
+
return runAgentInvoke({
|
|
11405
|
+
app: args.app,
|
|
11406
|
+
tool: args.tool,
|
|
11407
|
+
input: args.input,
|
|
11408
|
+
inputFile: args["input-file"],
|
|
11409
|
+
timeout: args.timeout,
|
|
11410
|
+
json: args.json
|
|
11411
|
+
});
|
|
11412
|
+
}
|
|
11413
|
+
});
|
|
11414
|
+
var agent_default = defineCommand10({
|
|
11415
|
+
meta: { name: "agent", description: "List and invoke an app\u2019s stateless local agent tools" },
|
|
11416
|
+
subCommands: { tools, invoke: invoke2 }
|
|
11417
|
+
});
|
|
11418
|
+
|
|
10978
11419
|
// src/cli/commands/feedback.ts
|
|
10979
11420
|
import * as p16 from "@clack/prompts";
|
|
10980
11421
|
import { existsSync as existsSync25, readFileSync as readFileSync21 } from "fs";
|
|
@@ -11201,7 +11642,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
11201
11642
|
});
|
|
11202
11643
|
|
|
11203
11644
|
// src/cli/commands/secrets.ts
|
|
11204
|
-
import { defineCommand as
|
|
11645
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
11205
11646
|
import { readFileSync as readFileSync22 } from "fs";
|
|
11206
11647
|
|
|
11207
11648
|
// src/cli/lib/citty-args.ts
|
|
@@ -11284,7 +11725,7 @@ function warnIfDebugRoutesEnabled(secrets) {
|
|
|
11284
11725
|
var APPLY_HINT = "Run `deepspace deploy` to apply \u2014 secrets take effect at deploy time.";
|
|
11285
11726
|
var APPLIES_AT_DEPLOY = { appliesAtDeploy: true, devRestartRequired: true };
|
|
11286
11727
|
var LOCAL_DEV_HINT = "Running `deepspace dev start`? Restart it to load the change locally.";
|
|
11287
|
-
var list6 =
|
|
11728
|
+
var list6 = defineCommand11({
|
|
11288
11729
|
meta: { name: "list", description: "List masked secrets in a config" },
|
|
11289
11730
|
args: {
|
|
11290
11731
|
...COMMON_ARGS,
|
|
@@ -11310,7 +11751,7 @@ var list6 = defineCommand10({
|
|
|
11310
11751
|
}
|
|
11311
11752
|
}
|
|
11312
11753
|
});
|
|
11313
|
-
var set =
|
|
11754
|
+
var set = defineCommand11({
|
|
11314
11755
|
meta: { name: "set", description: "Set secrets from KEY=value pairs, or KEY --stdin" },
|
|
11315
11756
|
args: {
|
|
11316
11757
|
...COMMON_ARGS,
|
|
@@ -11394,7 +11835,7 @@ var set = defineCommand10({
|
|
|
11394
11835
|
);
|
|
11395
11836
|
}
|
|
11396
11837
|
});
|
|
11397
|
-
var get2 =
|
|
11838
|
+
var get2 = defineCommand11({
|
|
11398
11839
|
meta: { name: "get", description: "Get a secret; pass --plain to print the value" },
|
|
11399
11840
|
args: {
|
|
11400
11841
|
...COMMON_ARGS,
|
|
@@ -11432,7 +11873,7 @@ var get2 = defineCommand10({
|
|
|
11432
11873
|
);
|
|
11433
11874
|
}
|
|
11434
11875
|
});
|
|
11435
|
-
var del2 =
|
|
11876
|
+
var del2 = defineCommand11({
|
|
11436
11877
|
meta: { name: "delete", description: "Delete one or more secrets" },
|
|
11437
11878
|
args: {
|
|
11438
11879
|
...COMMON_ARGS,
|
|
@@ -11468,7 +11909,7 @@ var del2 = defineCommand10({
|
|
|
11468
11909
|
);
|
|
11469
11910
|
}
|
|
11470
11911
|
});
|
|
11471
|
-
var upload =
|
|
11912
|
+
var upload = defineCommand11({
|
|
11472
11913
|
meta: { name: "upload", description: "Upload secrets from a dotenv or JSON file" },
|
|
11473
11914
|
args: {
|
|
11474
11915
|
...COMMON_ARGS,
|
|
@@ -11527,7 +11968,7 @@ async function readUploadSource(file) {
|
|
|
11527
11968
|
);
|
|
11528
11969
|
}
|
|
11529
11970
|
}
|
|
11530
|
-
var download =
|
|
11971
|
+
var download = defineCommand11({
|
|
11531
11972
|
meta: { name: "download", description: "Download a config\u2019s secrets (dotenv/json/shell)" },
|
|
11532
11973
|
args: {
|
|
11533
11974
|
...COMMON_ARGS,
|
|
@@ -11567,7 +12008,7 @@ var download = defineCommand10({
|
|
|
11567
12008
|
process.stdout.write(formatSecretsDownload(secrets, format));
|
|
11568
12009
|
}
|
|
11569
12010
|
});
|
|
11570
|
-
var pull =
|
|
12011
|
+
var pull = defineCommand11({
|
|
11571
12012
|
meta: { name: "pull", description: "Refresh the .dev.vars cache from the app store" },
|
|
11572
12013
|
args: { ...COMMON_ARGS },
|
|
11573
12014
|
async run({ args }) {
|
|
@@ -11608,7 +12049,7 @@ var pull = defineCommand10({
|
|
|
11608
12049
|
);
|
|
11609
12050
|
}
|
|
11610
12051
|
});
|
|
11611
|
-
var configsList =
|
|
12052
|
+
var configsList = defineCommand11({
|
|
11612
12053
|
meta: { name: "list", description: "List the app\u2019s configs" },
|
|
11613
12054
|
args: { ...COMMON_ARGS },
|
|
11614
12055
|
async run({ args }) {
|
|
@@ -11625,7 +12066,7 @@ var configsList = defineCommand10({
|
|
|
11625
12066
|
});
|
|
11626
12067
|
}
|
|
11627
12068
|
});
|
|
11628
|
-
var configsCreate =
|
|
12069
|
+
var configsCreate = defineCommand11({
|
|
11629
12070
|
meta: { name: "create", description: "Create a config (optionally copying another)" },
|
|
11630
12071
|
args: {
|
|
11631
12072
|
...COMMON_ARGS,
|
|
@@ -11659,7 +12100,7 @@ var configsCreate = defineCommand10({
|
|
|
11659
12100
|
);
|
|
11660
12101
|
}
|
|
11661
12102
|
});
|
|
11662
|
-
var configsDelete =
|
|
12103
|
+
var configsDelete = defineCommand11({
|
|
11663
12104
|
meta: { name: "delete", description: "Delete a config and all of its secrets" },
|
|
11664
12105
|
args: {
|
|
11665
12106
|
...COMMON_ARGS,
|
|
@@ -11704,11 +12145,11 @@ var configsDelete = defineCommand10({
|
|
|
11704
12145
|
);
|
|
11705
12146
|
}
|
|
11706
12147
|
});
|
|
11707
|
-
var configs =
|
|
12148
|
+
var configs = defineCommand11({
|
|
11708
12149
|
meta: { name: "configs", description: "Manage the app\u2019s secrets configs" },
|
|
11709
12150
|
subCommands: { list: configsList, create: configsCreate, delete: configsDelete }
|
|
11710
12151
|
});
|
|
11711
|
-
var secrets_default =
|
|
12152
|
+
var secrets_default = defineCommand11({
|
|
11712
12153
|
meta: { name: "secrets", description: "Manage the app\u2019s secrets store" },
|
|
11713
12154
|
subCommands: {
|
|
11714
12155
|
list: list6,
|
|
@@ -11821,6 +12262,9 @@ var init_default = defineDeepspaceCommand({
|
|
|
11821
12262
|
console.log(
|
|
11822
12263
|
`Registered on ${DEEPSPACE_ENV} as a NEW app under ${accountLabel(token)}; the original is untouched.`
|
|
11823
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
|
+
);
|
|
11824
12268
|
} else {
|
|
11825
12269
|
console.log(`Registered ${appId}${envSuffix} on ${DEEPSPACE_ENV} to ${accountLabel(token)}${commitNote}`);
|
|
11826
12270
|
if (replacedMalformed !== null) {
|
|
@@ -11869,7 +12313,7 @@ var init_default = defineDeepspaceCommand({
|
|
|
11869
12313
|
});
|
|
11870
12314
|
|
|
11871
12315
|
// src/cli/commands/status.ts
|
|
11872
|
-
import { defineCommand as
|
|
12316
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
11873
12317
|
import * as p17 from "@clack/prompts";
|
|
11874
12318
|
import { existsSync as existsSync26, readFileSync as readFileSync23 } from "fs";
|
|
11875
12319
|
function timeAgo(iso) {
|
|
@@ -11913,7 +12357,7 @@ function resolveStatusApp(appDir, wranglerEnv) {
|
|
|
11913
12357
|
return { appName, appId: null, appIdError: err.message };
|
|
11914
12358
|
}
|
|
11915
12359
|
}
|
|
11916
|
-
var status_default =
|
|
12360
|
+
var status_default = defineCommand12({
|
|
11917
12361
|
meta: {
|
|
11918
12362
|
name: "status",
|
|
11919
12363
|
description: "One screenful of current state \u2014 always names the platform plane (env, services) \u2014 plus session, app, workspace, and live release"
|
|
@@ -11972,6 +12416,7 @@ var status_default = defineCommand11({
|
|
|
11972
12416
|
json.sessionError = sessionError("Not logged in. Run `deepspace auth login` first.");
|
|
11973
12417
|
} else {
|
|
11974
12418
|
let who = null;
|
|
12419
|
+
let undecodableToken = false;
|
|
11975
12420
|
try {
|
|
11976
12421
|
const payload = decodeJwtPayload(
|
|
11977
12422
|
readFileSync23(TOKEN_PATH, "utf-8").trim()
|
|
@@ -11979,13 +12424,39 @@ var status_default = defineCommand11({
|
|
|
11979
12424
|
if (payload.email) who = payload.email;
|
|
11980
12425
|
userId = payload.sub ?? null;
|
|
11981
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;
|
|
11982
12459
|
}
|
|
11983
|
-
lines.push([
|
|
11984
|
-
"Session",
|
|
11985
|
-
`${who ?? "logged in"} \xB7 renews on use (re-login only after 30 idle days)`
|
|
11986
|
-
]);
|
|
11987
|
-
json.loggedIn = true;
|
|
11988
|
-
if (who) json.user = who;
|
|
11989
12460
|
}
|
|
11990
12461
|
const appDir = findAppDir();
|
|
11991
12462
|
if (!appDir) {
|
|
@@ -12120,9 +12591,10 @@ var status_default = defineCommand11({
|
|
|
12120
12591
|
]);
|
|
12121
12592
|
json.source = { ...source, revision: sourceResult.value.revision };
|
|
12122
12593
|
} else {
|
|
12594
|
+
const observed = inferredGithub ? observedGitHubRepository(appDir) : null;
|
|
12123
12595
|
lines.push([
|
|
12124
12596
|
"Source",
|
|
12125
|
-
`unclaimed \xB7 ${inferredGithub ?
|
|
12597
|
+
`unclaimed \xB7 ${inferredGithub ? `first release claims GitHub${observed ? ` (${observed})` : ""} from this checkout\u2019s remote, permanently` : "first deploy or push claims DeepSpace, permanently"}`
|
|
12126
12598
|
]);
|
|
12127
12599
|
json.source = null;
|
|
12128
12600
|
json.sourceInference = inferredGithub ? "github" : "deepspace";
|
|
@@ -13156,7 +13628,7 @@ Re-run with --allow-do-deletion to accept the data loss.`,
|
|
|
13156
13628
|
});
|
|
13157
13629
|
|
|
13158
13630
|
// src/cli/commands/workspace.ts
|
|
13159
|
-
import { defineCommand as
|
|
13631
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
13160
13632
|
|
|
13161
13633
|
// src/cli/commands/workspace/new.ts
|
|
13162
13634
|
import * as p25 from "@clack/prompts";
|
|
@@ -13744,9 +14216,9 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
13744
14216
|
},
|
|
13745
14217
|
async run({ args }) {
|
|
13746
14218
|
const task = typeof args.task === "string" ? args.task.trim() : "";
|
|
13747
|
-
if (!task) {
|
|
14219
|
+
if (!task || task.startsWith("-")) {
|
|
13748
14220
|
throw new Refusal(
|
|
13749
|
-
'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).',
|
|
13750
14222
|
"invalid_task"
|
|
13751
14223
|
);
|
|
13752
14224
|
}
|
|
@@ -15048,7 +15520,7 @@ var dropWorkspaceCommand = defineDeepspaceCommand({
|
|
|
15048
15520
|
});
|
|
15049
15521
|
|
|
15050
15522
|
// src/cli/commands/workspace.ts
|
|
15051
|
-
var workspace_default =
|
|
15523
|
+
var workspace_default = defineCommand13({
|
|
15052
15524
|
meta: {
|
|
15053
15525
|
name: "workspace",
|
|
15054
15526
|
description: "Durable parallel-agent workspaces (new/attach/sync/list/status/land/drop)"
|
|
@@ -15097,7 +15569,7 @@ function formatEvent2(e, lands, actors) {
|
|
|
15097
15569
|
detail = `"${String(s.task ?? "")}" from ${short(s.baseOid)}`;
|
|
15098
15570
|
break;
|
|
15099
15571
|
case "workspace.synced":
|
|
15100
|
-
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)}`;
|
|
15101
15573
|
break;
|
|
15102
15574
|
case "workspace.landed":
|
|
15103
15575
|
detail = `"${String(s.task ?? "")}" \u2192 ${short(s.landedOid)} on ${String(s.into ?? "trunk")}`;
|
|
@@ -15227,7 +15699,7 @@ var activity_default = defineDeepspaceCommand({
|
|
|
15227
15699
|
});
|
|
15228
15700
|
|
|
15229
15701
|
// src/cli/commands/git-credential.ts
|
|
15230
|
-
import { defineCommand as
|
|
15702
|
+
import { defineCommand as defineCommand14 } from "citty";
|
|
15231
15703
|
function parseFields(input) {
|
|
15232
15704
|
const fields = /* @__PURE__ */ new Map();
|
|
15233
15705
|
for (const line of input.split("\n")) {
|
|
@@ -15269,7 +15741,7 @@ function declineHint(op, input, token, deployUrl) {
|
|
|
15269
15741
|
}
|
|
15270
15742
|
return "";
|
|
15271
15743
|
}
|
|
15272
|
-
var git_credential_default =
|
|
15744
|
+
var git_credential_default = defineCommand14({
|
|
15273
15745
|
meta: {
|
|
15274
15746
|
name: "git-credential",
|
|
15275
15747
|
description: "Git credential helper (installed automatically; not for direct use)"
|
|
@@ -15368,6 +15840,7 @@ function reportSource(appId, state, json) {
|
|
|
15368
15840
|
);
|
|
15369
15841
|
}
|
|
15370
15842
|
console.log(`Revision: ${state.revision}`);
|
|
15843
|
+
console.log(`Registered: ${state.registered ? "yes" : "no"}`);
|
|
15371
15844
|
}
|
|
15372
15845
|
|
|
15373
15846
|
// src/cli/commands/update.ts
|
|
@@ -15378,7 +15851,7 @@ import { join as join28, resolve as resolve22 } from "path";
|
|
|
15378
15851
|
// package.json
|
|
15379
15852
|
var package_default = {
|
|
15380
15853
|
name: "deepspace",
|
|
15381
|
-
version: "0.28.
|
|
15854
|
+
version: "0.28.2",
|
|
15382
15855
|
engines: {
|
|
15383
15856
|
node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
|
|
15384
15857
|
},
|
|
@@ -15700,7 +16173,7 @@ var pkg = JSON.parse(readFileSync27(join29(__dirname, "..", "package.json"), "ut
|
|
|
15700
16173
|
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync31("/etc/ssl/certs/ca-certificates.crt")) {
|
|
15701
16174
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
15702
16175
|
}
|
|
15703
|
-
var create2 =
|
|
16176
|
+
var create2 = defineCommand15({
|
|
15704
16177
|
meta: {
|
|
15705
16178
|
name: "create",
|
|
15706
16179
|
description: "Create a new DeepSpace app (runs create-deepspace; all flags are forwarded)"
|
|
@@ -15749,11 +16222,11 @@ var create2 = defineCommand14({
|
|
|
15749
16222
|
}
|
|
15750
16223
|
});
|
|
15751
16224
|
var rename = (cmd, name) => ({ ...cmd, meta: { ...cmd.meta ?? {}, name } });
|
|
15752
|
-
var auth =
|
|
16225
|
+
var auth = defineCommand15({
|
|
15753
16226
|
meta: { name: "auth", description: "Session: login, logout, whoami" },
|
|
15754
16227
|
subCommands: { login: login_default, logout: logout_default, whoami: whoami_default }
|
|
15755
16228
|
});
|
|
15756
|
-
var app =
|
|
16229
|
+
var app = defineCommand15({
|
|
15757
16230
|
meta: {
|
|
15758
16231
|
name: "app",
|
|
15759
16232
|
description: "The app itself: create, init, list, files, source, update, undeploy, transfer, collaborators, domain, usage"
|
|
@@ -15772,11 +16245,11 @@ var app = defineCommand14({
|
|
|
15772
16245
|
update: update_default
|
|
15773
16246
|
}
|
|
15774
16247
|
});
|
|
15775
|
-
var devGroup =
|
|
16248
|
+
var devGroup = defineCommand15({
|
|
15776
16249
|
meta: { name: "dev", description: "Local development" },
|
|
15777
16250
|
subCommands: { start: rename(dev_default, "start"), kill: kill_default }
|
|
15778
16251
|
});
|
|
15779
|
-
var testGroup =
|
|
16252
|
+
var testGroup = defineCommand15({
|
|
15780
16253
|
meta: { name: "test", description: "App tests and test tooling" },
|
|
15781
16254
|
subCommands: {
|
|
15782
16255
|
run: rename(test_default, "run"),
|
|
@@ -15784,7 +16257,7 @@ var testGroup = defineCommand14({
|
|
|
15784
16257
|
accounts: rename(test_accounts_default, "accounts")
|
|
15785
16258
|
}
|
|
15786
16259
|
});
|
|
15787
|
-
var main =
|
|
16260
|
+
var main = defineCommand15({
|
|
15788
16261
|
meta: {
|
|
15789
16262
|
name: "deepspace",
|
|
15790
16263
|
version: pkg.version,
|
|
@@ -15810,6 +16283,7 @@ var main = defineCommand14({
|
|
|
15810
16283
|
add: add_default,
|
|
15811
16284
|
secrets: secrets_default,
|
|
15812
16285
|
integrations: integrations_default,
|
|
16286
|
+
agent: agent_default,
|
|
15813
16287
|
auth,
|
|
15814
16288
|
app,
|
|
15815
16289
|
feedback: feedback_default,
|