clickroom 0.1.0 → 0.2.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/README.md CHANGED
@@ -98,6 +98,22 @@ Each `clickroom` terminal is a live **session**. The dashboard (`/`, team only)
98
98
 
99
99
  In a review, the project name in the toolbar is a switcher with the same list. `clickroom list` prints it in the terminal.
100
100
 
101
+ ## Workspaces
102
+
103
+ On clickroom.dev every team has a workspace at its own address, `<workspace>.clickroom.dev`, with its own people, projects, comments and builds. Each review is at `<workspace>.clickroom.dev/<project>`.
104
+
105
+ - **Signing up:** on clickroom.dev, *Start a workspace* signs you in with your email address (a link, or Google) and asks for a name and an address. You're its owner and signed in there right away.
106
+ - **Your workspaces:** clickroom.dev lists every workspace your address is in, as an owner, teammate or client. *Open* signs you in there. Each workspace's dashboard has *Switch* next to its name.
107
+ - **Sharing from a computer:** `clickroom login <workspace>`, then `clickroom` in a project. Builds are uploaded. Live dev servers (the relay) belong to the first workspace only.
108
+ - **Separate by design:** a sign-in, a CLI key or a share link of one workspace opens nothing in another, even for a project with the same name (`test/workspaces.test.js`). The admin key and the Slack webhook belong to the first workspace.
109
+
110
+ How it's set up:
111
+ - `APP_HOST` (`{ws}.clickroom.dev`) and `DEFAULT_WS` (`yna`) turn workspaces on. The first workspace keeps its storage from before workspaces (Registry `registry`, rooms and builds by project name). Others use Registry `ws:<slug>`, and rooms and builds under `<slug>/`.
112
+ - The `Directory` Durable Object knows every workspace and which email addresses are in each. Each workspace's Registry keeps that list up to date.
113
+ - The bare domain (`AUTH_URL`) has the public pages, `/login` and the list of your workspaces. It also keeps the API for CLIs set up before, and Google's return address.
114
+ - Prototypes run on `{name}--{ws}.clickroom-preview.dev` (`PROTO_HOST`), a separate site. Each review address frames the review from there.
115
+ - `PASSTHROUGH_HOSTS` lists hosts under the wildcard route that aren't the app's, such as the relay's tunnel.
116
+
101
117
  ## People
102
118
 
103
119
  Everyone except share-link clients signs in as themselves, by email address. A browser stays signed in for 30 days from its last visit; signing in again while signed in (clickroom.dev's *Sign in*) goes straight to the dashboard.
package/bin/clickroom.js CHANGED
@@ -8,7 +8,7 @@ import { call } from '../cli/client.js';
8
8
  const HELP = `clickroom: multiplayer review for locally built prototypes
9
9
 
10
10
  On a teammate's computer
11
- clickroom login [url] connect this computer to your team's clickroom (default https://clickroom.dev):
11
+ clickroom login <workspace> connect this computer to your team's workspace (acme → acme.clickroom.dev):
12
12
  approve it in the browser where you're signed in from your invite
13
13
  clickroom then, in a project: builds it, uploads it as v1 and keeps the session open
14
14
  (p pushes the next version). The team sees it on the dashboard.
package/cli/gaps.js CHANGED
@@ -18,7 +18,7 @@ const questionCount = async (name) =>
18
18
 
19
19
  // Resolves to the number of questions it added (drafts), or throws.
20
20
  export async function findGaps(name, root) {
21
- if (!hasClaude()) throw new Error('Claude Code (`claude`) is not installed on this Mac');
21
+ if (!hasClaude()) throw new Error('Claude Code (`claude`) is not installed on the computer running `clickroom` for this project');
22
22
  const before = await questionCount(name);
23
23
  const mcp = JSON.stringify({ mcpServers: { clickroom: { command: process.execPath, args: [path.join(ROOT, 'bin', 'clickroom.js'), 'mcp'] } } });
24
24
  const args = ['-p', gapsPrompt(name), '--mcp-config', mcp, '--strict-mcp-config', '--tools', 'Read,Glob,Grep', '--allowedTools', TOOLS.join(','), '--disallowedTools', NEVER.join(','), '--no-session-persistence'];
package/cli/login.js CHANGED
@@ -5,12 +5,14 @@ import { bold, dim } from './dev.js';
5
5
 
6
6
  export const DEFAULT_URL = 'https://clickroom.dev';
7
7
 
8
- // `clickroom login [url]`: connects this computer to a clickroom server as you. It opens a page in
9
- // your browser (where you're signed in from your invite) to approve this computer, then keeps a
10
- // key of its own in ~/.clickroom/credentials.json.
8
+ // `clickroom login [workspace|url]`: connects this computer to a clickroom workspace as you
9
+ // ("acme" means https://acme.clickroom.dev). It opens a page in your browser (where you're signed
10
+ // in from your invite) to approve this computer, then keeps a key of its own in
11
+ // ~/.clickroom/credentials.json.
11
12
  export async function login(arg) {
13
+ if (arg && /^[a-z][a-z0-9-]{1,19}$/.test(arg)) arg = `https://${arg}.${new URL(DEFAULT_URL).hostname}`;
12
14
  const url = (arg || process.env.CLICKROOM_URL || credentials()?.url || DEFAULT_URL).replace(/\/$/, '');
13
- if (!/^https?:\/\//.test(url)) throw new Error('usage: clickroom login [https://clickroom.example]');
15
+ if (!/^https?:\/\//.test(url)) throw new Error('usage: clickroom login <workspace> (or a URL: clickroom login https://acme.clickroom.dev)');
14
16
  if (adminToken() && !process.env.CLICKROOM_TOKEN) console.log(dim(' This computer has the admin key (.dev.vars), which the clickroom command uses first.'));
15
17
  const res = await fetch(`${url}/__ps/api/cli-login`, {
16
18
  method: 'POST',
package/cli/note.js CHANGED
@@ -3,7 +3,7 @@ import { call } from './client.js';
3
3
  import { changedSource, folderChanges } from './changes.js';
4
4
 
5
5
  // The version note when a push comes without one ("Push v16" on the dashboard, or an empty
6
- // answer in the terminal): Claude Code on this Mac (`claude -p`) describes the source changes
6
+ // answer in the terminal): Claude Code on this computer (`claude -p`) describes the source changes
7
7
  // since the last push as reviewers will notice them, plus the comments fixed in this version.
8
8
  // Without git, Claude or a usable answer: the fixed comments, else the changed file names.
9
9
  // CLICKROOM_AUTO_NOTE=off never asks Claude.
package/cli/share.js CHANGED
@@ -102,8 +102,9 @@ export async function share(arg, opts) {
102
102
  let base, teamUrl, clientUrl;
103
103
  const links = () => {
104
104
  base = tunnelUrl || `http://localhost:${port}`;
105
- teamUrl = `${base}/s/${encodeURIComponent(name)}`;
106
- clientUrl = `${project.origin || base}/s/${encodeURIComponent(name)}?t=${project.token}`;
105
+ // The review's own address when the server has one (APP_URL/<name>), else /s/<name>.
106
+ teamUrl = project.reviewUrl || `${base}/s/${encodeURIComponent(name)}`;
107
+ clientUrl = `${project.reviewUrl || `${project.origin || base}/s/${encodeURIComponent(name)}`}?t=${project.token}`;
107
108
  console.log('');
108
109
  console.log(` ${bold('Review (you, team)')} ${teamUrl} ${dim('(press o to open it signed in)')}`);
109
110
  console.log(` ${bold('Client link')} ${clientUrl}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clickroom",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Share prototype builds for review: pins, region comments, threads, versions, and agent hand-off (MCP). Teammates push builds to their team’s clickroom with `clickroom login`.",
5
5
  "type": "module",
6
6
  "bin": {