@somewhere-tech/cli 0.1.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.
@@ -0,0 +1,81 @@
1
+ import { ApiClient } from '../lib/client.js';
2
+ import { getToken, loadProjectConfig } from '../lib/config.js';
3
+ import { dim, error, red, teal, yellow } from '../lib/output.js';
4
+ export function registerLogs(program) {
5
+ program
6
+ .command('logs [project]')
7
+ .description('Show recent logs')
8
+ .option('--level <level>', 'Filter by level (debug, info, warn, error)')
9
+ .option('--tail <n>', 'Number of lines', '20')
10
+ .option('--follow', 'Keep polling for new logs')
11
+ .action(async (project, opts) => {
12
+ const token = getToken();
13
+ const client = new ApiClient(token);
14
+ let projectId = project;
15
+ if (!projectId) {
16
+ const config = loadProjectConfig();
17
+ if (!config) {
18
+ error('No project. Pass a project ID or run from a linked directory.');
19
+ process.exit(1);
20
+ }
21
+ projectId = config.project_id;
22
+ }
23
+ const query = {
24
+ project_id: projectId,
25
+ limit: parseInt(String(opts.tail), 10) || 20,
26
+ level: opts.level,
27
+ };
28
+ try {
29
+ const result = await client.call('GET', '/logs', undefined, query);
30
+ if (!result.logs?.length) {
31
+ console.log(dim(' No logs yet.'));
32
+ return;
33
+ }
34
+ for (const log of result.logs.reverse()) {
35
+ const time = new Date(log.created_at).toLocaleTimeString();
36
+ const levelStr = formatLevel(log.level);
37
+ console.log(` ${dim(`[${levelStr}]`)} ${dim(time)} ${log.message}`);
38
+ }
39
+ if (opts.follow) {
40
+ console.log(dim('\n Polling for new logs... (Ctrl+C to stop)\n'));
41
+ let lastSeen = result.logs[result.logs.length - 1]?.created_at;
42
+ const poll = async () => {
43
+ try {
44
+ const fresh = await client.call('GET', '/logs', undefined, {
45
+ project_id: projectId,
46
+ limit: 50,
47
+ level: opts.level,
48
+ after: lastSeen,
49
+ });
50
+ for (const log of (fresh.logs ?? []).reverse()) {
51
+ const time = new Date(log.created_at).toLocaleTimeString();
52
+ const levelStr = formatLevel(log.level);
53
+ console.log(` ${dim(`[${levelStr}]`)} ${dim(time)} ${log.message}`);
54
+ lastSeen = log.created_at;
55
+ }
56
+ }
57
+ catch { }
58
+ };
59
+ setInterval(poll, 3000);
60
+ await new Promise(() => { }); // hang forever
61
+ }
62
+ }
63
+ catch (err) {
64
+ error(err instanceof Error ? err.message : String(err));
65
+ process.exit(1);
66
+ }
67
+ });
68
+ }
69
+ function formatLevel(level) {
70
+ switch (level) {
71
+ case 'error':
72
+ return red(level);
73
+ case 'warn':
74
+ return yellow(level);
75
+ case 'info':
76
+ return teal(level);
77
+ default:
78
+ return dim(level);
79
+ }
80
+ }
81
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import _open from 'open';
2
+ import { ApiClient } from '../lib/client.js';
3
+ import { getToken, loadProjectConfig } from '../lib/config.js';
4
+ import { dim, error, info } from '../lib/output.js';
5
+ export function registerOpen(program) {
6
+ program
7
+ .command('open [project]')
8
+ .description('Open the project URL in your browser')
9
+ .option('--dashboard', 'Open the dashboard instead')
10
+ .action(async (project, opts) => {
11
+ if (opts.dashboard) {
12
+ info(`Opening ${dim('https://somewhere.tech/dashboard')}...`);
13
+ await _open('https://somewhere.tech/dashboard');
14
+ return;
15
+ }
16
+ const token = getToken();
17
+ const client = new ApiClient(token);
18
+ let subdomain;
19
+ if (project) {
20
+ try {
21
+ const p = await client.call('GET', `/projects/${encodeURIComponent(project)}`);
22
+ subdomain = p.subdomain;
23
+ }
24
+ catch (err) {
25
+ error(err instanceof Error ? err.message : String(err));
26
+ process.exit(1);
27
+ }
28
+ }
29
+ else {
30
+ const config = loadProjectConfig();
31
+ subdomain = config?.subdomain;
32
+ }
33
+ if (!subdomain) {
34
+ error('No project linked. Pass a project name or run from a linked directory.');
35
+ process.exit(1);
36
+ }
37
+ const url = `https://${subdomain}.somewhere.tech`;
38
+ info(`Opening ${dim(url)}...`);
39
+ await _open(url);
40
+ });
41
+ }
42
+ //# sourceMappingURL=open.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,CAAC;AACzB,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,MAAM,kBAAkB,CAAC;AAEpD,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,sCAAsC,CAAC;SACnD,MAAM,CAAC,aAAa,EAAE,4BAA4B,CAAC;SACnD,MAAM,CAAC,KAAK,EAAE,OAA2B,EAAE,IAAI,EAAE,EAAE;QAClD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC,WAAW,GAAG,CAAC,kCAAkC,CAAC,KAAK,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;QAEpC,IAAI,SAA6B,CAAC;QAElC,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CACzB,KAAK,EACL,aAAa,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAC3C,CAAC;gBACF,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;YAC1B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;YACnC,SAAS,GAAG,MAAM,EAAE,SAAS,CAAC;QAChC,CAAC;QAED,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,KAAK,CACH,wEAAwE,CACzE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,GAAG,GAAG,WAAW,SAAS,iBAAiB,CAAC;QAClD,IAAI,CAAC,WAAW,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,135 @@
1
+ import prompts from 'prompts';
2
+ import ora from 'ora';
3
+ import { ApiClient } from '../lib/client.js';
4
+ import { getToken } from '../lib/config.js';
5
+ import { dim, error, info, statusDot, success, table, teal, timeAgo, } from '../lib/output.js';
6
+ export function registerProject(program) {
7
+ const proj = program
8
+ .command('project')
9
+ .description('Manage projects');
10
+ proj
11
+ .command('create <name>')
12
+ .description('Create a new project')
13
+ .option('--subdomain <subdomain>', 'Custom subdomain')
14
+ .option('--draft', 'Create as draft without deploying')
15
+ .action(async (name, opts) => {
16
+ const client = new ApiClient(getToken());
17
+ const spinner = ora('Creating project...').start();
18
+ try {
19
+ const p = await client.call('POST', '/projects', {
20
+ name,
21
+ subdomain: opts.subdomain ?? name.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
22
+ });
23
+ spinner.stop();
24
+ success(`Project created: ${teal(p.name)}`);
25
+ info(`ID: ${dim(p.id)}`);
26
+ if (p.url)
27
+ info(`URL: ${p.url}`);
28
+ info(`Status: ${statusDot(p.status)}`);
29
+ }
30
+ catch (err) {
31
+ spinner.fail('Failed');
32
+ error(err instanceof Error ? err.message : String(err));
33
+ process.exit(1);
34
+ }
35
+ });
36
+ proj
37
+ .command('list')
38
+ .alias('ls')
39
+ .description('List all projects')
40
+ .action(listProjects);
41
+ // Also register top-level `somewhere projects` alias
42
+ program
43
+ .command('projects')
44
+ .description('List all projects')
45
+ .action(listProjects);
46
+ proj
47
+ .command('view [name-or-id]')
48
+ .description('View project details')
49
+ .action(async (nameOrId) => {
50
+ const client = new ApiClient(getToken());
51
+ const id = nameOrId ?? 'default';
52
+ try {
53
+ const p = await client.call('GET', `/projects/${encodeURIComponent(id)}`);
54
+ console.log(`\n ${teal(String(p.name))}`);
55
+ info(`Status: ${statusDot(String(p.status ?? ''))}`);
56
+ if (p.subdomain)
57
+ info(`URL: https://${p.subdomain}.somewhere.tech`);
58
+ if (p.created_at)
59
+ info(`Created: ${String(p.created_at)}`);
60
+ }
61
+ catch (err) {
62
+ error(err instanceof Error ? err.message : String(err));
63
+ process.exit(1);
64
+ }
65
+ });
66
+ proj
67
+ .command('delete <name-or-id>')
68
+ .description('Permanently delete a project and all its data')
69
+ .action(async (nameOrId) => {
70
+ const client = new ApiClient(getToken());
71
+ const { confirm } = await prompts({
72
+ type: 'text',
73
+ name: 'confirm',
74
+ message: `This will permanently delete "${nameOrId}" and all its data.\n Type the project name to confirm`,
75
+ });
76
+ if (confirm !== nameOrId) {
77
+ error('Name did not match. Aborted.');
78
+ return;
79
+ }
80
+ const spinner = ora('Requesting deletion...').start();
81
+ try {
82
+ await client.call('POST', `/projects/${encodeURIComponent(nameOrId)}/request-delete`);
83
+ spinner.text = 'Confirmation code sent to your email. Enter it below.';
84
+ spinner.stop();
85
+ const { code } = await prompts({
86
+ type: 'text',
87
+ name: 'code',
88
+ message: 'Confirmation code (from email)',
89
+ });
90
+ if (!code) {
91
+ error('No code entered. Aborted.');
92
+ return;
93
+ }
94
+ const delSpinner = ora('Deleting...').start();
95
+ await client.call('DELETE', `/projects/${encodeURIComponent(nameOrId)}`, { code });
96
+ delSpinner.stop();
97
+ success('Deleted.');
98
+ }
99
+ catch (err) {
100
+ spinner.stop();
101
+ error(err instanceof Error ? err.message : String(err));
102
+ process.exit(1);
103
+ }
104
+ });
105
+ }
106
+ async function listProjects() {
107
+ const client = new ApiClient(getToken());
108
+ const spinner = ora('Fetching projects...').start();
109
+ try {
110
+ const result = await client.call('GET', '/projects');
111
+ spinner.stop();
112
+ if (!result.projects.length) {
113
+ info('No projects yet. Create one: somewhere project create <name>');
114
+ return;
115
+ }
116
+ table(['Name', 'Status', 'URL', 'Updated'], result.projects.map((p) => [
117
+ p.name,
118
+ statusDot(p.status),
119
+ p.subdomain
120
+ ? `${p.subdomain}.somewhere.tech`
121
+ : p.slug
122
+ ? `${dim('…/' + p.slug)}`
123
+ : '',
124
+ p.updated_at ? timeAgo(p.updated_at) : '',
125
+ ]));
126
+ console.log('');
127
+ info(dim(`${result.deployed_count} of ${result.deploy_limit} deploy slots used (${result.tier === 'builder' ? 'Builder' : 'Free'})`));
128
+ }
129
+ catch (err) {
130
+ spinner.fail('Failed');
131
+ error(err instanceof Error ? err.message : String(err));
132
+ process.exit(1);
133
+ }
134
+ }
135
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/commands/project.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,SAAS,EAAe,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EACL,GAAG,EACH,KAAK,EACL,IAAI,EACJ,SAAS,EACT,OAAO,EACP,KAAK,EACL,IAAI,EACJ,OAAO,GACR,MAAM,kBAAkB,CAAC;AAE1B,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,MAAM,IAAI,GAAG,OAAO;SACjB,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,iBAAiB,CAAC,CAAC;IAElC,IAAI;SACD,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,sBAAsB,CAAC;SACnC,MAAM,CAAC,yBAAyB,EAAE,kBAAkB,CAAC;SACrD,MAAM,CAAC,SAAS,EAAE,mCAAmC,CAAC;SACtD,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,IAAI,EAAE,EAAE;QACnC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,GAAG,CAAC,qBAAqB,CAAC,CAAC,KAAK,EAAE,CAAC;QACnD,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAMxB,MAAM,EAAE,WAAW,EAAE;gBACtB,IAAI;gBACJ,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;aAC5E,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,oBAAoB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC5C,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;YACzB,IAAI,CAAC,CAAC,GAAG;gBAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACjC,IAAI,CAAC,WAAW,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,IAAI;SACD,OAAO,CAAC,MAAM,CAAC;SACf,KAAK,CAAC,IAAI,CAAC;SACX,WAAW,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,YAAY,CAAC,CAAC;IAExB,qDAAqD;IACrD,OAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,YAAY,CAAC,CAAC;IAExB,IAAI;SACD,OAAO,CAAC,mBAAmB,CAAC;SAC5B,WAAW,CAAC,sBAAsB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,QAA4B,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzC,MAAM,EAAE,GAAG,QAAQ,IAAI,SAAS,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CACzB,KAAK,EACL,aAAa,kBAAkB,CAAC,EAAE,CAAC,EAAE,CACtC,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,CAAC,cAAc,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACxD,IAAI,CAAC,CAAC,SAAS;gBAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC;YAC1E,IAAI,CAAC,CAAC,UAAU;gBAAE,IAAI,CAAC,cAAc,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,IAAI;SACD,OAAO,CAAC,qBAAqB,CAAC;SAC9B,WAAW,CAAC,+CAA+C,CAAC;SAC5D,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,EAAE;QACjC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzC,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,CAAC;YAChC,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,iCAAiC,QAAQ,yDAAyD;SAC5G,CAAC,CAAC;QAEH,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;YACzB,KAAK,CAAC,8BAA8B,CAAC,CAAC;YACtC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,wBAAwB,CAAC,CAAC,KAAK,EAAE,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CACf,MAAM,EACN,aAAa,kBAAkB,CAAC,QAAQ,CAAC,iBAAiB,CAC3D,CAAC;YACF,OAAO,CAAC,IAAI,GAAG,uDAAuD,CAAC;YACvE,OAAO,CAAC,IAAI,EAAE,CAAC;YAEf,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC;gBAC7B,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,gCAAgC;aAC1C,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,KAAK,CAAC,2BAA2B,CAAC,CAAC;gBACnC,OAAO;YACT,CAAC;YAED,MAAM,UAAU,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,KAAK,EAAE,CAAC;YAC9C,MAAM,MAAM,CAAC,IAAI,CACf,QAAQ,EACR,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EAC3C,EAAE,IAAI,EAAE,CACT,CAAC;YACF,UAAU,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,CAAC,UAAU,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,KAAK,UAAU,YAAY;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,GAAG,CAAC,sBAAsB,CAAC,CAAC,KAAK,EAAE,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAW7B,KAAK,EAAE,WAAW,CAAC,CAAC;QACvB,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,8DAA8D,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,KAAK,CACH,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,EACpC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACzB,CAAC,CAAC,IAAI;YACN,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;YACnB,CAAC,CAAC,SAAS;gBACT,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,iBAAiB;gBACjC,CAAC,CAAC,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE;oBACzB,CAAC,CAAC,EAAE;YACR,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;SAC1C,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,IAAI,CACF,GAAG,CACD,GAAG,MAAM,CAAC,cAAc,OAAO,MAAM,CAAC,YAAY,uBAAuB,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAC3H,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { ApiClient } from '../lib/client.js';
2
+ import { getToken, loadProjectConfig } from '../lib/config.js';
3
+ import { dim, error, info, statusDot, teal, timeAgo } from '../lib/output.js';
4
+ export function registerStatus(program) {
5
+ program
6
+ .command('status')
7
+ .description('Show project and workspace status')
8
+ .action(async () => {
9
+ const token = getToken();
10
+ const client = new ApiClient(token);
11
+ const config = loadProjectConfig();
12
+ if (!config) {
13
+ error('No project linked. Run `somewhere init` first.');
14
+ process.exit(1);
15
+ }
16
+ try {
17
+ const p = await client.call('GET', `/projects/${encodeURIComponent(config.project_id)}`);
18
+ console.log(`\n Project: ${teal(p.name)} (${statusDot(p.status)})`);
19
+ if (p.subdomain) {
20
+ info(`URL: https://${p.subdomain}.somewhere.tech`);
21
+ }
22
+ if (p.updated_at) {
23
+ info(`Last deploy: ${timeAgo(p.updated_at)}`);
24
+ }
25
+ }
26
+ catch (err) {
27
+ error(`Project: ${err instanceof Error ? err.message : String(err)}`);
28
+ }
29
+ try {
30
+ const ws = await client.call('GET', '/hosted/status');
31
+ console.log('');
32
+ const wsStatus = ws.status === 'ready' ? `Running` : ws.status;
33
+ info(`Workspace: ${wsStatus}`);
34
+ if (ws.terminal_url) {
35
+ info(`Terminal: ${dim(ws.terminal_url)}`);
36
+ }
37
+ }
38
+ catch {
39
+ // No workspace or not configured — just skip
40
+ }
41
+ console.log('');
42
+ });
43
+ }
44
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,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,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE9E,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,mCAAmC,CAAC;SAChD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAC;QAEnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,KAAK,CAAC,gDAAgD,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAKxB,KAAK,EAAE,aAAa,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAEhE,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrE,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;gBAChB,IAAI,CAAC,gBAAgB,CAAC,CAAC,SAAS,iBAAiB,CAAC,CAAC;YACrD,CAAC;YACD,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;gBACjB,IAAI,CAAC,gBAAgB,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,CAAC,YAAY,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAGzB,KAAK,EAAE,gBAAgB,CAAC,CAAC;YAE5B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,EAAE,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;YAC/D,IAAI,CAAC,cAAc,QAAQ,EAAE,CAAC,CAAC;YAC/B,IAAI,EAAE,CAAC,YAAY,EAAE,CAAC;gBACpB,IAAI,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;QAC/C,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ import { Command } from 'commander';
2
+ import { registerAuth } from './commands/auth.js';
3
+ import { registerInit } from './commands/init.js';
4
+ import { registerProject } from './commands/project.js';
5
+ import { registerDeploy } from './commands/deploy.js';
6
+ import { registerLogs } from './commands/logs.js';
7
+ import { registerEnv } from './commands/env.js';
8
+ import { registerStatus } from './commands/status.js';
9
+ import { registerOpen } from './commands/open.js';
10
+ import { registerDev } from './commands/dev.js';
11
+ import { registerApi } from './commands/api.js';
12
+ const program = new Command()
13
+ .name('somewhere')
14
+ .description('CLI for somewhere.tech')
15
+ .version('0.1.0');
16
+ registerAuth(program);
17
+ registerInit(program);
18
+ registerProject(program);
19
+ registerDeploy(program);
20
+ registerLogs(program);
21
+ registerEnv(program);
22
+ registerStatus(program);
23
+ registerOpen(program);
24
+ registerDev(program);
25
+ registerApi(program);
26
+ program.parse();
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE;KAC1B,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,wBAAwB,CAAC;KACrC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,eAAe,CAAC,OAAO,CAAC,CAAC;AACzB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,cAAc,CAAC,OAAO,CAAC,CAAC;AACxB,YAAY,CAAC,OAAO,CAAC,CAAC;AACtB,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,WAAW,CAAC,OAAO,CAAC,CAAC;AAErB,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,68 @@
1
+ import http from 'node:http';
2
+ import open from 'open';
3
+ const AUTH_URL = 'https://somewhere.tech/auth/cli';
4
+ /**
5
+ * Browser-based OAuth login flow:
6
+ * 1. Start local HTTP server on a random port
7
+ * 2. Open browser to /auth/cli?redirect=http://localhost:PORT/callback
8
+ * 3. User authenticates via Google OAuth
9
+ * 4. Platform redirects to localhost with ?token=smt_...&email=...&username=...
10
+ * 5. Return the received credentials
11
+ */
12
+ export async function browserLogin() {
13
+ return new Promise((resolve, reject) => {
14
+ const server = http.createServer((req, res) => {
15
+ const url = new URL(req.url ?? '/', `http://localhost`);
16
+ if (url.pathname === '/callback') {
17
+ const token = url.searchParams.get('token');
18
+ const email = url.searchParams.get('email') ?? '';
19
+ const username = url.searchParams.get('username') ?? '';
20
+ if (!token) {
21
+ res.writeHead(400, { 'Content-Type': 'text/html' });
22
+ res.end('<h1>Authentication failed</h1><p>No token received. Close this tab and try again.</p>');
23
+ reject(new Error('No token in callback'));
24
+ server.close();
25
+ return;
26
+ }
27
+ res.writeHead(200, { 'Content-Type': 'text/html' });
28
+ res.end(`
29
+ <html>
30
+ <body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#0d0e14;color:#e5e7eb">
31
+ <div style="text-align:center">
32
+ <div style="font-size:48px;margin-bottom:16px">✓</div>
33
+ <h1 style="font-size:24px;margin:0 0 8px;color:#2dd4bf">Logged in</h1>
34
+ <p style="color:#9ca3af">You can close this tab and return to the terminal.</p>
35
+ </div>
36
+ </body>
37
+ </html>
38
+ `);
39
+ resolve({
40
+ token,
41
+ user: { email, username },
42
+ });
43
+ setTimeout(() => server.close(), 500);
44
+ return;
45
+ }
46
+ res.writeHead(404);
47
+ res.end();
48
+ });
49
+ server.listen(0, '127.0.0.1', () => {
50
+ const addr = server.address();
51
+ if (!addr || typeof addr === 'string') {
52
+ reject(new Error('Failed to start local server'));
53
+ return;
54
+ }
55
+ const port = addr.port;
56
+ const redirect = `http://localhost:${port}/callback`;
57
+ const loginUrl = `${AUTH_URL}?redirect=${encodeURIComponent(redirect)}`;
58
+ open(loginUrl);
59
+ });
60
+ server.on('error', reject);
61
+ // Timeout after 5 minutes
62
+ setTimeout(() => {
63
+ server.close();
64
+ reject(new Error('Login timed out. Try again.'));
65
+ }, 5 * 60 * 1000);
66
+ });
67
+ }
68
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,QAAQ,GAAG,iCAAiC,CAAC;AAQnD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,OAAO,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;YAExD,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACjC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;gBAClD,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;gBAExD,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;oBACpD,GAAG,CAAC,GAAG,CAAC,uFAAuF,CAAC,CAAC;oBACjG,MAAM,CAAC,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC;oBAC1C,MAAM,CAAC,KAAK,EAAE,CAAC;oBACf,OAAO;gBACT,CAAC;gBAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC;;;;;;;;;;SAUP,CAAC,CAAC;gBAEH,OAAO,CAAC;oBACN,KAAK;oBACL,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;iBAC1B,CAAC,CAAC;gBAEH,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC;gBACtC,OAAO;YACT,CAAC;YAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtC,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;gBAClD,OAAO;YACT,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;YACvB,MAAM,QAAQ,GAAG,oBAAoB,IAAI,WAAW,CAAC;YACrD,MAAM,QAAQ,GAAG,GAAG,QAAQ,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE3B,0BAA0B;QAC1B,UAAU,CAAC,GAAG,EAAE;YACd,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;QACnD,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,52 @@
1
+ const BASE_URL = 'https://api.somewhere.tech/v1';
2
+ export class ApiClient {
3
+ token;
4
+ constructor(token) {
5
+ this.token = token;
6
+ }
7
+ async call(method, path, body, query) {
8
+ let url = `${BASE_URL}${path}`;
9
+ if (query) {
10
+ const params = new URLSearchParams();
11
+ for (const [k, v] of Object.entries(query)) {
12
+ if (v !== undefined)
13
+ params.append(k, String(v));
14
+ }
15
+ const qs = params.toString();
16
+ if (qs)
17
+ url += `?${qs}`;
18
+ }
19
+ const headers = {
20
+ Authorization: `Bearer ${this.token}`,
21
+ Accept: 'application/json',
22
+ };
23
+ let reqBody;
24
+ if (body !== undefined) {
25
+ headers['Content-Type'] = 'application/json';
26
+ reqBody = JSON.stringify(body);
27
+ }
28
+ const res = await fetch(url, { method, headers, body: reqBody });
29
+ const text = await res.text();
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(text);
33
+ }
34
+ catch {
35
+ throw new CliApiError('INVALID_RESPONSE', `Non-JSON response (${res.status}): ${text.slice(0, 200)}`, res.status);
36
+ }
37
+ if (parsed.ok === true)
38
+ return parsed.data;
39
+ throw new CliApiError(parsed.error ?? 'UNKNOWN', parsed.message ?? 'Unknown error', res.status);
40
+ }
41
+ }
42
+ export class CliApiError extends Error {
43
+ code;
44
+ statusCode;
45
+ constructor(code, message, statusCode) {
46
+ super(message);
47
+ this.code = code;
48
+ this.statusCode = statusCode;
49
+ this.name = 'CliApiError';
50
+ }
51
+ }
52
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAG,+BAA+B,CAAC;AAEjD,MAAM,OAAO,SAAS;IACS;IAA7B,YAA6B,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;IAAG,CAAC;IAE9C,KAAK,CAAC,IAAI,CACR,MAAc,EACd,IAAY,EACZ,IAAc,EACd,KAAmD;QAEnD,IAAI,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI,EAAE,CAAC;QAC/B,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YACrC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,SAAS;oBAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACnD,CAAC;YACD,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC7B,IAAI,EAAE;gBAAE,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;QAC1B,CAAC;QAED,MAAM,OAAO,GAA2B;YACtC,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;YACrC,MAAM,EAAE,kBAAkB;SAC3B,CAAC;QAEF,IAAI,OAA2B,CAAC;QAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;YAC7C,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,MAAsB,CAAC;QAE3B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,WAAW,CACnB,kBAAkB,EAClB,sBAAsB,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAC1D,GAAG,CAAC,MAAM,CACX,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,CAAC,EAAE,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC;QAE3C,MAAM,IAAI,WAAW,CAClB,MAA6B,CAAC,KAAK,IAAI,SAAS,EAChD,MAA+B,CAAC,OAAO,IAAI,eAAe,EAC3D,GAAG,CAAC,MAAM,CACX,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,WAAY,SAAQ,KAAK;IAElB;IAEA;IAHlB,YACkB,IAAY,EAC5B,OAAe,EACC,UAAkB;QAElC,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,SAAI,GAAJ,IAAI,CAAQ;QAEZ,eAAU,GAAV,UAAU,CAAQ;QAGlC,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,64 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ const CONFIG_DIR = join(homedir(), '.somewhere');
5
+ const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
6
+ const PROJECT_FILE = '.somewhere.json';
7
+ function ensureDir() {
8
+ if (!existsSync(CONFIG_DIR))
9
+ mkdirSync(CONFIG_DIR, { recursive: true });
10
+ }
11
+ export function loadConfig() {
12
+ if (!existsSync(CONFIG_PATH))
13
+ return null;
14
+ try {
15
+ return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ export function saveConfig(config) {
22
+ ensureDir();
23
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
24
+ }
25
+ export function clearConfig() {
26
+ if (existsSync(CONFIG_PATH))
27
+ unlinkSync(CONFIG_PATH);
28
+ }
29
+ export function getToken() {
30
+ const config = loadConfig();
31
+ if (!config?.token) {
32
+ console.error('Not logged in. Run: somewhere login');
33
+ process.exit(1);
34
+ }
35
+ return config.token;
36
+ }
37
+ export function loadProjectConfig(dir = process.cwd()) {
38
+ const path = join(dir, PROJECT_FILE);
39
+ if (!existsSync(path))
40
+ return null;
41
+ try {
42
+ return JSON.parse(readFileSync(path, 'utf-8'));
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ export function saveProjectConfig(dir, config) {
49
+ writeFileSync(join(dir, PROJECT_FILE), JSON.stringify(config, null, 2) + '\n');
50
+ }
51
+ export function saveMcpConfig(dir, token) {
52
+ const mcp = {
53
+ mcpServers: {
54
+ somewhere: {
55
+ url: 'https://mcp.somewhere.tech/mcp',
56
+ headers: {
57
+ Authorization: `Bearer ${token}`,
58
+ },
59
+ },
60
+ },
61
+ };
62
+ writeFileSync(join(dir, '.mcp.json'), JSON.stringify(mcp, null, 2) + '\n');
63
+ }
64
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AACjD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AACpD,MAAM,YAAY,GAAG,iBAAiB,CAAC;AAEvC,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAc,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,SAAS,EAAE,CAAC;IACZ,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,IAAI,UAAU,CAAC,WAAW,CAAC;QAAE,UAAU,CAAC,WAAW,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAkB,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,MAAqB;IAClE,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,KAAa;IACtD,MAAM,GAAG,GAAG;QACV,UAAU,EAAE;YACV,SAAS,EAAE;gBACT,GAAG,EAAE,gCAAgC;gBACrC,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,KAAK,EAAE;iBACjC;aACF;SACF;KACF,CAAC;IACF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,68 @@
1
+ import chalk from 'chalk';
2
+ export const teal = chalk.hex('#2dd4bf');
3
+ export const dim = chalk.dim;
4
+ export const bold = chalk.bold;
5
+ export const red = chalk.red;
6
+ export const green = chalk.green;
7
+ export const yellow = chalk.yellow;
8
+ export function success(msg) {
9
+ console.log(`${green('✓')} ${msg}`);
10
+ }
11
+ export function error(msg) {
12
+ console.error(`${red('✗')} ${msg}`);
13
+ }
14
+ export function warn(msg) {
15
+ console.log(`${yellow('!')} ${msg}`);
16
+ }
17
+ export function info(msg) {
18
+ console.log(` ${msg}`);
19
+ }
20
+ export function heading(msg) {
21
+ console.log(`\n${bold(msg)}\n`);
22
+ }
23
+ export function table(headers, rows, widths) {
24
+ const colWidths = widths ??
25
+ headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)) + 2);
26
+ const headerLine = headers
27
+ .map((h, i) => dim(h.toUpperCase().padEnd(colWidths[i])))
28
+ .join('');
29
+ console.log(` ${headerLine}`);
30
+ for (const row of rows) {
31
+ const line = row
32
+ .map((cell, i) => (cell ?? '').padEnd(colWidths[i]))
33
+ .join('');
34
+ console.log(` ${line}`);
35
+ }
36
+ }
37
+ export function timeAgo(dateStr) {
38
+ const diff = Date.now() - new Date(dateStr).getTime();
39
+ const mins = Math.floor(diff / 60_000);
40
+ if (mins < 1)
41
+ return 'just now';
42
+ if (mins < 60)
43
+ return `${mins}m ago`;
44
+ const hours = Math.floor(mins / 60);
45
+ if (hours < 24)
46
+ return `${hours}h ago`;
47
+ const days = Math.floor(hours / 24);
48
+ if (days < 30)
49
+ return `${days}d ago`;
50
+ return `${Math.floor(days / 30)}mo ago`;
51
+ }
52
+ export function statusDot(status) {
53
+ switch (status) {
54
+ case 'deployed':
55
+ case 'active':
56
+ case 'ready':
57
+ return `${green('●')} Live`;
58
+ case 'draft':
59
+ return `${dim('○')} Draft`;
60
+ case 'archived':
61
+ return `${dim('◌')} Archived`;
62
+ case 'frozen':
63
+ return `${yellow('●')} Frozen`;
64
+ default:
65
+ return status;
66
+ }
67
+ }
68
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map