@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venturewild/workspace",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "description": "Claude Code Web — Replit/Lovable-style chat-first browser UI that wraps the AI agent already installed on your machine.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -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
  }