@venturewild/workspace 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server/bin/wild-workspace.mjs +101 -0
- package/server/src/index.mjs +263 -48
- package/server/src/workspace-registry.mjs +225 -0
- package/server/src/workspaces.mjs +111 -0
- package/web/dist/assets/index-PAS8Inwp.js +91 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-B44y93r4.js +0 -91
package/package.json
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
} from '../src/auto-update.mjs';
|
|
33
33
|
import { openOwnerBrowser } from '../src/owner-browser.mjs';
|
|
34
34
|
import { planReset, applyReset, RESET_KEEPS } from '../src/reset.mjs';
|
|
35
|
+
import { createWorkspaceRails } from '../src/workspaces.mjs';
|
|
35
36
|
|
|
36
37
|
const __filename = url.fileURLToPath(import.meta.url);
|
|
37
38
|
const __dirname = path.dirname(__filename);
|
|
@@ -57,6 +58,10 @@ Usage:
|
|
|
57
58
|
flush local config (preview without --yes; keeps your files)
|
|
58
59
|
wild-workspace whoami show the currently-bound account
|
|
59
60
|
wild-workspace rotate-token mint a new account token; invalidates the old one
|
|
61
|
+
wild-workspace workspace create "<name>" [--slug s] create a shared workspace (its own slug, owned by you)
|
|
62
|
+
wild-workspace workspace list shared workspaces you belong to
|
|
63
|
+
wild-workspace workspace add-member <slug> <email> add a teammate (they must have a slug already)
|
|
64
|
+
wild-workspace workspace remove-member <slug> <email-or-accountId> remove a teammate
|
|
60
65
|
wild-workspace doctor [--share] diagnose this machine's install (✅/⚠️/❌ + logs)
|
|
61
66
|
wild-workspace logs [name] [--tail N] list logs, or tail one (cli/server/daemon/…)
|
|
62
67
|
wild-workspace operator enable let the wild-workspace team help with your install (mints a token)
|
|
@@ -104,6 +109,7 @@ function parseArgs(argv) {
|
|
|
104
109
|
else if (arg === '--rotate') { opts.rotate = true; }
|
|
105
110
|
else if (arg === '--yes' || arg === '-y') { opts.yes = true; }
|
|
106
111
|
else if (arg === '--kind') { opts.kind = argv[++i]; }
|
|
112
|
+
else if (arg === '--slug') { opts.slug = argv[++i]; }
|
|
107
113
|
else if (arg === '--limit') { opts.limit = Number(argv[++i]); }
|
|
108
114
|
else if (arg === '--tier') { opts.tier = Number(argv[++i]); }
|
|
109
115
|
else if (arg === '--minutes') { opts.minutes = Number(argv[++i]); }
|
|
@@ -429,6 +435,98 @@ async function runRotateTokenCommand() {
|
|
|
429
435
|
console.log('to force an immediate reconnect.');
|
|
430
436
|
}
|
|
431
437
|
|
|
438
|
+
// `wild-workspace workspace {create|list|add-member|remove-member}` — multi-host
|
|
439
|
+
// step 2 (membership). The FOUNDATION's drivable surface: create a shared
|
|
440
|
+
// workspace (its own slug, owned by you), manage its member set, and read the
|
|
441
|
+
// shared workspaces you belong to. The polished invite/join/lobby UX is later;
|
|
442
|
+
// these are operator/dev affordances over the rails (you never copy-paste a
|
|
443
|
+
// token — they read your bound account). Requires `wild-workspace login` first.
|
|
444
|
+
async function runWorkspaceCommand(action, opts) {
|
|
445
|
+
const config = buildConfig(opts);
|
|
446
|
+
if (!config.accountToken) {
|
|
447
|
+
console.error('not logged in. Run `wild-workspace login <payload>` after claiming a slug.');
|
|
448
|
+
process.exitCode = 1;
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const rails = createWorkspaceRails(config, { accountToken: config.accountToken });
|
|
452
|
+
const fail = (r) => {
|
|
453
|
+
console.error(`✗ ${r.message || r.code || 'failed'}${r.code ? ` (${r.code})` : ''}`);
|
|
454
|
+
process.exitCode = 1;
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
if (action === 'create') {
|
|
458
|
+
const name = opts.positional.slice(2).join(' ').trim();
|
|
459
|
+
if (!name) {
|
|
460
|
+
console.error('usage: wild-workspace workspace create "<name>" [--slug <slug>]');
|
|
461
|
+
process.exitCode = 1;
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const r = await rails.create(name, opts.slug || null);
|
|
465
|
+
if (!r.ok) return fail(r);
|
|
466
|
+
console.log(`✓ created shared workspace "${r.data.name}"`);
|
|
467
|
+
console.log(` slug : ${r.data.slug}`);
|
|
468
|
+
console.log(` url : https://${r.data.slug}.venturewild.llc (once routing lands — step 3)`);
|
|
469
|
+
console.log('');
|
|
470
|
+
console.log(' Add a teammate (they must have claimed a slug already):');
|
|
471
|
+
console.log(` wild-workspace workspace add-member ${r.data.slug} <their-email>`);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (action === 'list') {
|
|
476
|
+
const r = await rails.list();
|
|
477
|
+
if (!r.ok) return fail(r);
|
|
478
|
+
const ws = r.data.workspaces || [];
|
|
479
|
+
if (!ws.length) {
|
|
480
|
+
console.log('you belong to no shared workspaces yet.');
|
|
481
|
+
console.log(' create one: wild-workspace workspace create "<name>"');
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
console.log(`shared workspaces you belong to: ${ws.length}`);
|
|
485
|
+
for (const w of ws) {
|
|
486
|
+
console.log(` ${w.slug.padEnd(20)} ${w.role.padEnd(7)} "${w.name}" (owner: ${w.owner_email})`);
|
|
487
|
+
}
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (action === 'add-member') {
|
|
492
|
+
const slug = opts.positional[2];
|
|
493
|
+
const email = opts.positional[3];
|
|
494
|
+
if (!slug || !email) {
|
|
495
|
+
console.error('usage: wild-workspace workspace add-member <slug> <email>');
|
|
496
|
+
process.exitCode = 1;
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const r = await rails.addMember(slug, email);
|
|
500
|
+
if (!r.ok) return fail(r);
|
|
501
|
+
console.log(`✓ added ${email} to ${slug} (account ${r.data.account_id}).`);
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (action === 'remove-member') {
|
|
506
|
+
const slug = opts.positional[2];
|
|
507
|
+
const ref = opts.positional[3];
|
|
508
|
+
if (!slug || !ref) {
|
|
509
|
+
console.error('usage: wild-workspace workspace remove-member <slug> <email-or-accountId>');
|
|
510
|
+
process.exitCode = 1;
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const r = await rails.removeMember(slug, ref);
|
|
514
|
+
if (!r.ok) return fail(r);
|
|
515
|
+
console.log(
|
|
516
|
+
r.data.removed
|
|
517
|
+
? `✓ removed ${ref} from ${slug}.`
|
|
518
|
+
: `${ref} was not a member of ${slug} (nothing to remove).`,
|
|
519
|
+
);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
console.log('unknown workspace action. use: create | list | add-member | remove-member');
|
|
524
|
+
console.log(' wild-workspace workspace create "<name>" [--slug <slug>]');
|
|
525
|
+
console.log(' wild-workspace workspace list');
|
|
526
|
+
console.log(' wild-workspace workspace add-member <slug> <email>');
|
|
527
|
+
console.log(' wild-workspace workspace remove-member <slug> <email-or-accountId>');
|
|
528
|
+
}
|
|
529
|
+
|
|
432
530
|
async function runWhoamiCommand() {
|
|
433
531
|
const config = buildConfig({});
|
|
434
532
|
const account = loadAccount(config.dataDir);
|
|
@@ -890,6 +988,9 @@ async function main() {
|
|
|
890
988
|
if (opts.positional[0] === 'rotate-token') {
|
|
891
989
|
return runRotateTokenCommand();
|
|
892
990
|
}
|
|
991
|
+
if (opts.positional[0] === 'workspace') {
|
|
992
|
+
return runWorkspaceCommand(opts.positional[1], opts);
|
|
993
|
+
}
|
|
893
994
|
if (opts.positional[0] === 'doctor') {
|
|
894
995
|
return runDoctorCommand(opts);
|
|
895
996
|
}
|