@somewhere-tech/cli 0.21.2 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/auth.js +15 -2
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/db.js +41 -28
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.js +137 -47
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/docs.js +21 -2
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/env.js +34 -4
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/exec.js +38 -2
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/logs.js +59 -15
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/project.js +51 -19
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/promote.js +14 -4
- package/dist/commands/promote.js.map +1 -1
- package/dist/commands/pull.js +17 -6
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/rollback.js +14 -4
- package/dist/commands/rollback.js.map +1 -1
- package/dist/commands/status.js +39 -19
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/typecheck.js +19 -4
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/lib/client.js +10 -1
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/output.js +6 -0
- package/dist/lib/output.js.map +1 -1
- package/package.json +2 -2
package/dist/commands/auth.js
CHANGED
|
@@ -5,7 +5,7 @@ import { deviceLogin, DeviceLoginTimeout, DeviceCodeUnsupported, } from '../lib/
|
|
|
5
5
|
import { ApiClient } from '../lib/client.js';
|
|
6
6
|
import { clearConfig, loadConfig, saveConfig, saveGlobalMcpConfig, } from '../lib/config.js';
|
|
7
7
|
import { getDeviceId, getDeviceKeyName } from '../lib/device.js';
|
|
8
|
-
import { dim, error, info, success, teal } from '../lib/output.js';
|
|
8
|
+
import { dim, error, info, printJson, success, teal } from '../lib/output.js';
|
|
9
9
|
async function loginAction(opts) {
|
|
10
10
|
if (opts.legacy) {
|
|
11
11
|
await runLegacyLogin();
|
|
@@ -29,7 +29,8 @@ export function registerAuth(program) {
|
|
|
29
29
|
program
|
|
30
30
|
.command('whoami')
|
|
31
31
|
.description('Show current user info')
|
|
32
|
-
.
|
|
32
|
+
.option('--json', 'Print the raw account response as JSON')
|
|
33
|
+
.action(async (opts) => {
|
|
33
34
|
const config = loadConfig();
|
|
34
35
|
if (!config) {
|
|
35
36
|
error('Not logged in. Run: somewhere login');
|
|
@@ -38,6 +39,10 @@ export function registerAuth(program) {
|
|
|
38
39
|
const client = new ApiClient(config.token);
|
|
39
40
|
try {
|
|
40
41
|
const r = await client.call('GET', '/auth/whoami');
|
|
42
|
+
if (opts.json) {
|
|
43
|
+
printJson(r);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
41
46
|
const tier = r.user.effective_tier === 'builder' ? 'Builder' : 'Free';
|
|
42
47
|
console.log(`${teal(r.user.email)} ${dim(`(${tier})`)}`);
|
|
43
48
|
if (r.user.name)
|
|
@@ -50,6 +55,14 @@ export function registerAuth(program) {
|
|
|
50
55
|
catch {
|
|
51
56
|
// Agents gate on `whoami` to validate the token — a stored-but-dead token
|
|
52
57
|
// must NOT report success. Show the cached identity, then exit non-zero.
|
|
58
|
+
if (opts.json) {
|
|
59
|
+
printJson({
|
|
60
|
+
error: 'WHOAMI_FAILED',
|
|
61
|
+
message: 'Could not fetch account details — token may be expired. Run: somewhere login',
|
|
62
|
+
});
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
53
66
|
console.log(teal(config.user.email));
|
|
54
67
|
info(dim('Could not fetch account details — token may be expired. Run: somewhere login'));
|
|
55
68
|
process.exitCode = 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,gBAAgB,CAAC;AAClC,OAAO,GAAiB,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/db.js
CHANGED
|
@@ -2,8 +2,7 @@ import { writeFileSync } from 'node:fs';
|
|
|
2
2
|
import ora from '../lib/spinner.js';
|
|
3
3
|
import { ApiClient } from '../lib/client.js';
|
|
4
4
|
import { getToken, loadProjectConfig } from '../lib/config.js';
|
|
5
|
-
import { dim, error, info, success, table, teal, yellow } from '../lib/output.js';
|
|
6
|
-
const API_BASE = 'https://api.somewhere.tech/v1';
|
|
5
|
+
import { dim, error, info, printJson, success, table, teal, yellow } from '../lib/output.js';
|
|
7
6
|
export function registerDb(program) {
|
|
8
7
|
const db = program.command('db').description('Run SQL against your project\'s database');
|
|
9
8
|
db
|
|
@@ -73,6 +72,7 @@ export function registerDb(program) {
|
|
|
73
72
|
.description('Export the full database as SQL (schema + every row). Pipe to a file: somewhere db dump > backup.sql')
|
|
74
73
|
.option('--project <id>', 'Project ID (defaults to .somewhere.json)')
|
|
75
74
|
.option('-o, --output <file>', 'Write to file instead of stdout')
|
|
75
|
+
.option('--json', 'Print the dump response as JSON')
|
|
76
76
|
.action(async (opts) => {
|
|
77
77
|
let projectId = opts.project;
|
|
78
78
|
if (!projectId) {
|
|
@@ -83,50 +83,58 @@ export function registerDb(program) {
|
|
|
83
83
|
}
|
|
84
84
|
projectId = config.project_id;
|
|
85
85
|
}
|
|
86
|
-
|
|
87
|
-
const spinner = ora('Dumping database…').start();
|
|
86
|
+
const client = new ApiClient(getToken());
|
|
87
|
+
const spinner = opts.json ? null : ora('Dumping database…').start();
|
|
88
88
|
try {
|
|
89
|
-
const res = await
|
|
90
|
-
method: 'POST',
|
|
91
|
-
headers: {
|
|
92
|
-
Authorization: `Bearer ${getToken()}`,
|
|
93
|
-
'Content-Type': 'application/json',
|
|
94
|
-
},
|
|
95
|
-
body: JSON.stringify({ project_id: projectId }),
|
|
96
|
-
});
|
|
89
|
+
const res = await client.callRaw('POST', '/db/dump', { project_id: projectId });
|
|
97
90
|
if (!res.ok) {
|
|
98
|
-
spinner
|
|
99
|
-
const body = await res.text();
|
|
91
|
+
spinner?.fail('Dump failed');
|
|
100
92
|
try {
|
|
101
|
-
const json = JSON.parse(body);
|
|
102
|
-
error(`${json.error ?? 'ERROR'}: ${json.message ?? body.slice(0, 200)}`);
|
|
93
|
+
const json = JSON.parse(res.body);
|
|
94
|
+
error(`${json.error ?? 'ERROR'}: ${json.message ?? res.body.slice(0, 200)}`);
|
|
103
95
|
}
|
|
104
96
|
catch {
|
|
105
|
-
error(`HTTP ${res.status}: ${body.slice(0, 200)}`);
|
|
97
|
+
error(`HTTP ${res.status}: ${res.body.slice(0, 200)}`);
|
|
106
98
|
}
|
|
107
99
|
process.exit(1);
|
|
108
100
|
}
|
|
109
|
-
const sql =
|
|
110
|
-
const tables = res.headers
|
|
111
|
-
const rows = res.headers
|
|
112
|
-
const truncated = res.headers
|
|
101
|
+
const sql = res.body;
|
|
102
|
+
const tables = res.headers['x-tables'] ?? '?';
|
|
103
|
+
const rows = res.headers['x-rows'] ?? '?';
|
|
104
|
+
const truncated = res.headers['x-truncated-tables'];
|
|
105
|
+
const dumpResult = {
|
|
106
|
+
sql,
|
|
107
|
+
tables,
|
|
108
|
+
rows,
|
|
109
|
+
truncated_tables: truncated ?? null,
|
|
110
|
+
};
|
|
113
111
|
if (opts.output) {
|
|
114
112
|
writeFileSync(opts.output, sql);
|
|
115
|
-
|
|
113
|
+
if (opts.json) {
|
|
114
|
+
printJson(dumpResult);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
spinner?.succeed(`Wrote ${opts.output} (${tables} tables, ${rows} rows)`);
|
|
118
|
+
}
|
|
116
119
|
}
|
|
117
120
|
else {
|
|
118
|
-
spinner
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
spinner?.stop();
|
|
122
|
+
if (opts.json) {
|
|
123
|
+
printJson(dumpResult);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
process.stdout.write(sql);
|
|
127
|
+
// Summary to STDERR — stdout must stay pure SQL for `db dump > backup.sql`.
|
|
128
|
+
process.stderr.write(dim(`${tables} tables, ${rows} rows`) + '\n');
|
|
129
|
+
}
|
|
122
130
|
}
|
|
123
|
-
if (truncated) {
|
|
131
|
+
if (truncated && !opts.json) {
|
|
124
132
|
// stderr for the same reason (applies to the piped-dump path).
|
|
125
133
|
process.stderr.write(yellow(`⚠ Per-table row cap hit on: ${truncated} — contact support for a streaming dump if needed.`) + '\n');
|
|
126
134
|
}
|
|
127
135
|
}
|
|
128
136
|
catch (err) {
|
|
129
|
-
spinner
|
|
137
|
+
spinner?.fail('Dump failed');
|
|
130
138
|
error(err instanceof Error ? err.message : String(err));
|
|
131
139
|
process.exit(1);
|
|
132
140
|
}
|
|
@@ -135,6 +143,7 @@ export function registerDb(program) {
|
|
|
135
143
|
.command('tables')
|
|
136
144
|
.description('List tables in the project database')
|
|
137
145
|
.option('--project <id>', 'Project ID (defaults to .somewhere.json)')
|
|
146
|
+
.option('--json', 'Print the raw tables response as JSON')
|
|
138
147
|
.action(async (opts) => {
|
|
139
148
|
const client = new ApiClient(getToken());
|
|
140
149
|
let projectId = opts.project;
|
|
@@ -148,6 +157,10 @@ export function registerDb(program) {
|
|
|
148
157
|
}
|
|
149
158
|
try {
|
|
150
159
|
const r = await client.call('GET', '/db/tables', undefined, { project_id: projectId });
|
|
160
|
+
if (opts.json) {
|
|
161
|
+
printJson(r);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
151
164
|
// The API returns tables as an array of NAME STRINGS. (The old CLI read
|
|
152
165
|
// them as { name, row_count } objects, so every name came back empty and
|
|
153
166
|
// every row count printed "?" — audit #5.) Normalize defensively so a
|
package/dist/commands/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/commands/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,GAAG,MAAM,mBAAmB,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/commands/db.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isBuildError, renderBuildError } from '../lib/build-errors.js';
|
|
|
5
5
|
import { getToken, loadConfig, loadProjectConfig, saveConfig, saveProjectConfig } from '../lib/config.js';
|
|
6
6
|
import { collectFiles, formatBytes } from '../lib/files.js';
|
|
7
7
|
import { mintTempAccount } from '../lib/temp-auth.js';
|
|
8
|
-
import { dim, error, green, info, red, success, teal, warn, yellow } from '../lib/output.js';
|
|
8
|
+
import { dim, error, green, info, printJson, red, success, teal, warn, yellow } from '../lib/output.js';
|
|
9
9
|
// Resolve the deploy target directory. `resolve` (not `join`) so an absolute
|
|
10
10
|
// `dir` is honored as-is — `join(cwd, '/abs/path')` produced `/cwd/abs/path`
|
|
11
11
|
// → ENOENT (tsk_c616fe5d). `resolve` also normalizes `..` segments.
|
|
@@ -30,7 +30,39 @@ export function prebuiltOptIn(opts) {
|
|
|
30
30
|
// EMPTY and the server signal is unambiguous.
|
|
31
31
|
const SERVER_FRAMEWORK_DEPS = ['express', 'fastify', 'koa', '@nestjs/core', '@hapi/hapi', 'restify'];
|
|
32
32
|
const SERVER_CODE_PATTERN = /\bapp\.listen\s*\(|\bhttp\.createServer\s*\(|\bfastify\s*\(\s*\)|new\s+Koa\s*\(/;
|
|
33
|
+
const NEXT_APP_SIGNAL_PREFIX = 'Next.js app';
|
|
34
|
+
const NEXT_CONFIG_PATTERN = /^next\.config\.(js|ts|mjs)$/;
|
|
35
|
+
const NEXT_ROUTER_FILE_PATTERN = /^(?:src\/)?(?:app\/(?:.*\/)?(?:page|layout|route|loading|error|not-found)\.(?:js|jsx|ts|tsx|mdx)|pages\/.+\.(?:js|jsx|ts|tsx|mdx))$/;
|
|
36
|
+
const NEXT_APP_WARNING = "somewhere.tech serves static files + serverless functions, not SSR — Next.js apps don't run here. " +
|
|
37
|
+
'Port API routes to functions/ handlers, or start from a Vite React app; the platform compiles raw JSX/TSX on deploy.';
|
|
38
|
+
export function isNextAppShapeSignal(signal) {
|
|
39
|
+
return signal.startsWith(`${NEXT_APP_SIGNAL_PREFIX} (`);
|
|
40
|
+
}
|
|
41
|
+
function detectNextAppShape(files) {
|
|
42
|
+
const pkgRaw = files['package.json'];
|
|
43
|
+
if (pkgRaw) {
|
|
44
|
+
try {
|
|
45
|
+
const pkg = JSON.parse(pkgRaw);
|
|
46
|
+
if (pkg.dependencies?.next || pkg.devDependencies?.next) {
|
|
47
|
+
return `${NEXT_APP_SIGNAL_PREFIX} (package.json depends on "next")`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
/* unparseable package.json is someone else's problem */
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const path of Object.keys(files)) {
|
|
55
|
+
if (NEXT_CONFIG_PATTERN.test(path))
|
|
56
|
+
return `${NEXT_APP_SIGNAL_PREFIX} (${path})`;
|
|
57
|
+
if (NEXT_ROUTER_FILE_PATTERN.test(path))
|
|
58
|
+
return `${NEXT_APP_SIGNAL_PREFIX} (${path} router file)`;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
33
62
|
export function detectNodeServerShape(files, functions) {
|
|
63
|
+
const nextSignal = detectNextAppShape(files);
|
|
64
|
+
if (nextSignal)
|
|
65
|
+
return nextSignal;
|
|
34
66
|
if (Object.keys(functions).length > 0)
|
|
35
67
|
return null; // has real functions — trust it
|
|
36
68
|
const pkgRaw = files['package.json'];
|
|
@@ -68,15 +100,31 @@ export function deriveTempProjectName(dirPath) {
|
|
|
68
100
|
const base = slugify(basename(dirPath)) || 'project';
|
|
69
101
|
return `${base}-${randomSuffix()}`;
|
|
70
102
|
}
|
|
71
|
-
// The claim-relay block derives its "N hours" from the server's
|
|
72
|
-
// (10800 → 3).
|
|
73
|
-
//
|
|
74
|
-
// (an absolute timestamp), not the original ttl_seconds.
|
|
103
|
+
// The first-mint claim-relay block derives its "N hours" from the server's
|
|
104
|
+
// ttl_seconds (10800 → 3). Reused sessions with no saved expiry (old configs)
|
|
105
|
+
// still fall back here instead of crashing.
|
|
75
106
|
export function formatTtlHours(ttlSeconds) {
|
|
76
107
|
if (!ttlSeconds || !Number.isFinite(ttlSeconds))
|
|
77
108
|
return 3;
|
|
78
109
|
return Math.round(ttlSeconds / 3600) || 3;
|
|
79
110
|
}
|
|
111
|
+
export function formatRemainingTempTime(expiresAt, nowMs = Date.now()) {
|
|
112
|
+
const expiresMs = new Date(expiresAt).getTime();
|
|
113
|
+
if (!Number.isFinite(expiresMs))
|
|
114
|
+
return null;
|
|
115
|
+
const totalMinutes = Math.max(0, Math.ceil((expiresMs - nowMs) / 60_000));
|
|
116
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
117
|
+
const minutes = totalMinutes % 60;
|
|
118
|
+
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
119
|
+
}
|
|
120
|
+
function hasReusableTempCredential(config, nowMs = Date.now()) {
|
|
121
|
+
if (!config?.token || !config.temporary)
|
|
122
|
+
return false;
|
|
123
|
+
if (!config.temp_expires_at)
|
|
124
|
+
return true;
|
|
125
|
+
const expiresMs = new Date(config.temp_expires_at).getTime();
|
|
126
|
+
return Number.isFinite(expiresMs) && expiresMs > nowMs;
|
|
127
|
+
}
|
|
80
128
|
export function registerDeploy(program) {
|
|
81
129
|
program
|
|
82
130
|
.command('deploy [dir]')
|
|
@@ -92,6 +140,7 @@ export function registerDeploy(program) {
|
|
|
92
140
|
'for the bundled files. Use it only when you need full control of your own build.')
|
|
93
141
|
.option('--allow-bundled', 'Alias for --prebuilt.')
|
|
94
142
|
.option('--temporary', 'Deploy without an account — creates a temporary 3-hour workspace you can claim later')
|
|
143
|
+
.option('--json', 'Print the raw deploy response as JSON')
|
|
95
144
|
.action(async (dir, opts) => {
|
|
96
145
|
const targetDir = resolveTargetDir(dir);
|
|
97
146
|
const storedConfig = loadConfig();
|
|
@@ -103,6 +152,13 @@ export function registerDeploy(program) {
|
|
|
103
152
|
// exit here would make CI/agent tooling treat "you could deploy without
|
|
104
153
|
// an account" as a broken command.
|
|
105
154
|
if (!storedConfig?.token && !opts.temporary) {
|
|
155
|
+
if (opts.json) {
|
|
156
|
+
printJson({
|
|
157
|
+
message: 'No account found. To deploy without logging in, rerun with --temporary.',
|
|
158
|
+
docs_command: 'somewhere docs start',
|
|
159
|
+
});
|
|
160
|
+
process.exit(0);
|
|
161
|
+
}
|
|
106
162
|
console.log('No account found. To deploy without logging in, rerun with --temporary.');
|
|
107
163
|
console.log('Everything you can run without an account: somewhere docs start');
|
|
108
164
|
process.exit(0);
|
|
@@ -117,24 +173,26 @@ export function registerDeploy(program) {
|
|
|
117
173
|
// Already have a real account — --temporary would be a downgrade,
|
|
118
174
|
// so ignore it rather than silently minting a throwaway workspace
|
|
119
175
|
// next to the dev's own projects.
|
|
120
|
-
|
|
176
|
+
if (!opts.json)
|
|
177
|
+
info('Already logged in — deploying to your account.');
|
|
121
178
|
token = getToken();
|
|
122
179
|
}
|
|
123
|
-
else if (storedConfig
|
|
124
|
-
storedConfig.temporary &&
|
|
125
|
-
storedConfig.temp_expires_at &&
|
|
126
|
-
new Date(storedConfig.temp_expires_at).getTime() > Date.now()) {
|
|
180
|
+
else if (hasReusableTempCredential(storedConfig)) {
|
|
127
181
|
// Reuse silently — this is the "one credential across shells"
|
|
128
182
|
// requirement: a second `--temporary` deploy in the same 3h window
|
|
129
183
|
// (a different terminal, a re-run) must not mint a second project.
|
|
130
184
|
token = storedConfig.token;
|
|
131
|
-
tempSession = {
|
|
185
|
+
tempSession = {
|
|
186
|
+
claimUrl: storedConfig.claim_url ?? '',
|
|
187
|
+
expiresAt: storedConfig.temp_expires_at,
|
|
188
|
+
reused: true,
|
|
189
|
+
};
|
|
132
190
|
}
|
|
133
191
|
else {
|
|
134
|
-
const powSpinner = ora('Solving proof-of-work…').start();
|
|
192
|
+
const powSpinner = opts.json ? null : ora('Solving proof-of-work…').start();
|
|
135
193
|
try {
|
|
136
194
|
const account = await mintTempAccount();
|
|
137
|
-
powSpinner
|
|
195
|
+
powSpinner?.stop();
|
|
138
196
|
saveConfig({
|
|
139
197
|
token: account.key,
|
|
140
198
|
temporary: true,
|
|
@@ -143,10 +201,14 @@ export function registerDeploy(program) {
|
|
|
143
201
|
user: { email: '', username: '' },
|
|
144
202
|
});
|
|
145
203
|
token = account.key;
|
|
146
|
-
tempSession = {
|
|
204
|
+
tempSession = {
|
|
205
|
+
claimUrl: account.claim_url,
|
|
206
|
+
ttlSeconds: account.ttl_seconds,
|
|
207
|
+
reused: false,
|
|
208
|
+
};
|
|
147
209
|
}
|
|
148
210
|
catch (err) {
|
|
149
|
-
powSpinner
|
|
211
|
+
powSpinner?.fail('Could not create a temporary session');
|
|
150
212
|
error(err instanceof Error ? err.message : String(err));
|
|
151
213
|
process.exit(1);
|
|
152
214
|
}
|
|
@@ -176,11 +238,11 @@ export function registerDeploy(program) {
|
|
|
176
238
|
else if (tempSession) {
|
|
177
239
|
// No `.somewhere.json` and no account to run `somewhere init` —
|
|
178
240
|
// auto-create the project so a temp deploy is a single command.
|
|
179
|
-
const createSpinner = ora('Creating a temporary project...').start();
|
|
241
|
+
const createSpinner = opts.json ? null : ora('Creating a temporary project...').start();
|
|
180
242
|
try {
|
|
181
243
|
const name = deriveTempProjectName(targetDir);
|
|
182
244
|
const created = await client.call('POST', '/projects', { name, subdomain: name });
|
|
183
|
-
createSpinner
|
|
245
|
+
createSpinner?.stop();
|
|
184
246
|
saveProjectConfig(targetDir, {
|
|
185
247
|
project_id: created.id,
|
|
186
248
|
name: created.name,
|
|
@@ -189,7 +251,7 @@ export function registerDeploy(program) {
|
|
|
189
251
|
projectId = created.id;
|
|
190
252
|
}
|
|
191
253
|
catch (err) {
|
|
192
|
-
createSpinner
|
|
254
|
+
createSpinner?.fail('Could not create a temporary project');
|
|
193
255
|
error(err instanceof Error ? err.message : String(err));
|
|
194
256
|
process.exit(1);
|
|
195
257
|
}
|
|
@@ -199,29 +261,34 @@ export function registerDeploy(program) {
|
|
|
199
261
|
process.exit(1);
|
|
200
262
|
}
|
|
201
263
|
}
|
|
202
|
-
const spinner = ora('Collecting files...').start();
|
|
264
|
+
const spinner = opts.json ? null : ora('Collecting files...').start();
|
|
203
265
|
const { files, binaryFiles, functions, skipped } = collectFiles(targetDir);
|
|
204
266
|
// A deploy replaces the whole project, so a file we skip is DELETED from
|
|
205
267
|
// production if it was there before. Never silent — surface every skip.
|
|
206
|
-
if (skipped.length) {
|
|
207
|
-
spinner
|
|
268
|
+
if (skipped.length && !opts.json) {
|
|
269
|
+
spinner?.stop();
|
|
208
270
|
warn(`${skipped.length} file(s) will NOT be uploaded — a deploy is a full ` +
|
|
209
271
|
`replacement, so any already deployed will be REMOVED from production:`);
|
|
210
272
|
for (const s of skipped)
|
|
211
273
|
warn(` ${dim('•')} ${s.path} — ${s.reason}`);
|
|
212
|
-
spinner
|
|
274
|
+
spinner?.start();
|
|
213
275
|
}
|
|
214
276
|
// Node-server pre-flight (tsk_8e8c6bc8) — see detectNodeServerShape.
|
|
215
277
|
const serverSignal = detectNodeServerShape(files, functions);
|
|
216
|
-
if (serverSignal) {
|
|
217
|
-
spinner
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
278
|
+
if (serverSignal && !opts.json) {
|
|
279
|
+
spinner?.stop();
|
|
280
|
+
if (isNextAppShapeSignal(serverSignal)) {
|
|
281
|
+
warn(NEXT_APP_WARNING);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
warn(`This looks like a Node server app (${serverSignal}) — somewhere.tech does not run server processes.`);
|
|
285
|
+
warn('It will deploy as static files only: your routes will NOT run, and the');
|
|
286
|
+
warn('server source will be publicly readable at its file path.');
|
|
287
|
+
warn('The platform shape: static files at the root + API handlers under functions/');
|
|
288
|
+
warn('(each default-exports async (req, sw) and becomes a route).');
|
|
289
|
+
warn('Full quickstart: somewhere docs start');
|
|
290
|
+
}
|
|
291
|
+
spinner?.start();
|
|
225
292
|
}
|
|
226
293
|
const totalFiles = Object.keys(files).length +
|
|
227
294
|
Object.keys(binaryFiles).length +
|
|
@@ -232,9 +299,11 @@ export function registerDeploy(program) {
|
|
|
232
299
|
const binaryBytes = Object.values(binaryFiles)
|
|
233
300
|
.reduce((sum, b64) => sum + Math.floor((b64.length * 3) / 4), 0);
|
|
234
301
|
const totalBytes = textBytes + binaryBytes;
|
|
235
|
-
spinner
|
|
236
|
-
|
|
237
|
-
|
|
302
|
+
if (spinner) {
|
|
303
|
+
spinner.text = opts.dryRun
|
|
304
|
+
? `Checking ${totalFiles} files (${formatBytes(totalBytes)})...`
|
|
305
|
+
: `Deploying ${totalFiles} files (${formatBytes(totalBytes)})...`;
|
|
306
|
+
}
|
|
238
307
|
try {
|
|
239
308
|
const body = {
|
|
240
309
|
project_id: projectId,
|
|
@@ -269,14 +338,26 @@ export function registerDeploy(program) {
|
|
|
269
338
|
const plan = await client.call('POST', '/deploy', body, undefined, {
|
|
270
339
|
timeoutMs: LONG_CALL_TIMEOUT_MS,
|
|
271
340
|
});
|
|
272
|
-
spinner
|
|
273
|
-
|
|
341
|
+
spinner?.stop();
|
|
342
|
+
if (opts.json) {
|
|
343
|
+
printJson(plan);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
printDryRun(plan, scope);
|
|
347
|
+
}
|
|
274
348
|
return;
|
|
275
349
|
}
|
|
276
350
|
const result = await client.call('POST', '/deploy', body, undefined, {
|
|
277
351
|
timeoutMs: LONG_CALL_TIMEOUT_MS,
|
|
278
352
|
});
|
|
279
|
-
spinner
|
|
353
|
+
spinner?.stop();
|
|
354
|
+
if (opts.json) {
|
|
355
|
+
printJson(result);
|
|
356
|
+
if (result.function_errors && result.function_errors.length > 0) {
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
280
361
|
const staticCount = typeof result.files === 'number'
|
|
281
362
|
? result.files
|
|
282
363
|
: (result.files ?? []).length;
|
|
@@ -323,18 +404,27 @@ export function registerDeploy(program) {
|
|
|
323
404
|
warn(w);
|
|
324
405
|
}
|
|
325
406
|
if (tempSession) {
|
|
326
|
-
// Agent-relay success message (tsk_35674c33
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
|
|
407
|
+
// Agent-relay success message (tsk_35674c33): every temp deploy,
|
|
408
|
+
// minted or silently reused, ends with this block so the claim path
|
|
409
|
+
// is never missed. Reused sessions report the absolute account clock
|
|
410
|
+
// instead of re-promising a fresh 3 hours.
|
|
411
|
+
const remaining = tempSession.reused && tempSession.expiresAt
|
|
412
|
+
? formatRemainingTempTime(tempSession.expiresAt)
|
|
413
|
+
: null;
|
|
414
|
+
if (remaining) {
|
|
415
|
+
success(`Live at ${teal(result.url)}`);
|
|
416
|
+
info(`This temporary workspace expires in ${remaining} — claiming keeps ALL projects under it.`);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
const hours = formatTtlHours(tempSession.ttlSeconds);
|
|
420
|
+
success(`Live at ${teal(result.url)} — yours for ${hours} hour${hours === 1 ? '' : 's'}.`);
|
|
421
|
+
}
|
|
331
422
|
info(`To keep it: ${teal(tempSession.claimUrl)}`);
|
|
332
423
|
info("Claiming connects the Somewhere MCP so your agent can manage this project's");
|
|
333
424
|
info('database, email, and cron directly next time.');
|
|
334
|
-
// Additive pointer (tsk_497b7eeb)
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
// redeploys) — `docs start` is that map, no account required.
|
|
425
|
+
// Additive pointer (tsk_497b7eeb). Next thing a fresh agent needs is
|
|
426
|
+
// the anonymous capability map (tables via `somewhere db query`,
|
|
427
|
+
// logs, redeploys) — `docs start` is that map, no account required.
|
|
338
428
|
info('What else works without an account: somewhere docs start');
|
|
339
429
|
}
|
|
340
430
|
else {
|
|
@@ -354,7 +444,7 @@ export function registerDeploy(program) {
|
|
|
354
444
|
}
|
|
355
445
|
}
|
|
356
446
|
catch (err) {
|
|
357
|
-
spinner
|
|
447
|
+
spinner?.fail(opts.dryRun ? 'Dry run failed' : 'Deploy failed');
|
|
358
448
|
// Structured build failures get the full treatment: file:line
|
|
359
449
|
// heading + a code frame rebuilt from the local source (we have the
|
|
360
450
|
// files the server compiled — this is where the CLI beats a remote
|