@zoahhq/cli 0.1.2 → 0.1.3

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.
Files changed (3) hide show
  1. package/README.md +10 -10
  2. package/dist/cli.mjs +181 -175
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -139,7 +139,7 @@ fresh `agent/<timestamp>` branch off main, so an agent's edits stay reviewable
139
139
  rather than landing on main.
140
140
 
141
141
  **4. Check it worked.** `status` reports the connected project, the branch, and
142
- workspace role. It also reports credential health. `whoami` reports the
142
+ organization role. It also reports credential health. `whoami` reports the
143
143
  identity, role, and instance.
144
144
 
145
145
  #### What the agent gets
@@ -149,17 +149,17 @@ session without direct human confirmation. Confirmation actions stay in the
149
149
  Zoah app. The server replaces renderer-only and workspace-agent verbs with
150
150
  the session tools below.
151
151
 
152
- | Group | Tools |
153
- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
154
- | Session | `connect`, `status`, `pullEvents`, `disconnect`, `whoami`, `logout`, `describeProperties` |
155
- | Workspaces and projects | `listWorkspaces`, `createWorkspace`, `listProjects`, `createProject`, `updateProject` |
156
- | Branches | `listBranches`, `createBranch` |
157
- | Pull requests | `createPullRequest`, `getPullRequest`, `updatePullRequest`, `commentOnPullRequest` |
158
- | Canvas | one per applicable Action API verb for nodes, pages, components, slots, variants, variables, themes, breakpoints, events, and queries |
152
+ | Group | Tools |
153
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
154
+ | Session | `connect`, `status`, `pullEvents`, `disconnect`, `whoami`, `logout`, `describeProperties` |
155
+ | Organizations and projects | `listOrganizations`, `createOrganization`, `listProjects`, `createProject`, `updateProject` |
156
+ | Branches | `listBranches`, `createBranch` |
157
+ | Pull requests | `createPullRequest`, `getPullRequest`, `updatePullRequest`, `commentOnPullRequest` |
158
+ | Canvas | one per applicable Action API verb for nodes, pages, components, slots, variants, variables, themes, breakpoints, events, and queries |
159
159
 
160
160
  Two properties are worth knowing. Mutation tools return only after the sync
161
161
  gateway acks the write, so a returned success means persisted, not queued. And
162
- the server does not provide branch, project, or workspace deletion.
162
+ the server does not provide branch, project, or organization deletion.
163
163
  `pullEvents` returns structured rejection and collaborator action details. It
164
164
  also returns merge summaries. Sync and cache signals mean the agent should
165
165
  re-query after reconnect catch-up.
@@ -339,7 +339,7 @@ When the import fails (e.g. the server returns 400 because no components were ex
339
339
 
340
340
  Commit these files. They bind the checkout to the Zoah project:
341
341
 
342
- - `.zoah/config.json`: workspace and project binding, written on the first import.
342
+ - `.zoah/config.json`: organization and project binding, written on the first import.
343
343
  - `.zoah/components.json`: component IDs, package exports, and slot anchors.
344
344
  - `.zoah/manifest.json`: published package name, version, and registry URL.
345
345
 
package/dist/cli.mjs CHANGED
@@ -467,29 +467,29 @@ var init_client = __esm({
467
467
  );
468
468
  }
469
469
  /**
470
- * Every workspace the user belongs to (`GET /api/import/organizations`).
470
+ * Every organization the user belongs to (`GET /api/import/organizations`).
471
471
  *
472
- * The workspace is the outermost scope an agent works in and was the only one
472
+ * The organization is the outermost scope an agent works in and was the only one
473
473
  * with no way to see it: responses carried an opaque `orgId` and the readable
474
474
  * slug appeared only inside an app URL. Membership comes from the owner-group
475
475
  * walk the sync gateway already performs on every socket identify, so this
476
- * lists every workspace rather than the one the human last selected.
476
+ * lists every organization rather than the one the human last selected.
477
477
  */
478
- listWorkspaces() {
478
+ listOrganizations() {
479
479
  return this.send(
480
480
  "GET",
481
481
  "/api/import/organizations"
482
482
  );
483
483
  }
484
484
  /**
485
- * Create a workspace (`POST /api/import/organizations`).
485
+ * Create an organization (`POST /api/import/organizations`).
486
486
  *
487
487
  * The server creates it and keeps the org-capable credential to itself, so
488
488
  * this call carries nothing but the name. The slug is derived server-side
489
489
  * from that name: `slug` is globally unique, so a caller that invented one
490
490
  * would be inventing a value it cannot check.
491
491
  */
492
- createWorkspace(name) {
492
+ createOrganization(name) {
493
493
  return this.send(
494
494
  "POST",
495
495
  "/api/import/organizations",
@@ -53471,8 +53471,8 @@ var init_ai_action_style_keys = __esm({
53471
53471
 
53472
53472
  // ../shared/dist/ai/opaque/opaqueActions.js
53473
53473
  import { z as z51 } from "zod";
53474
- function isWorkspaceActionType(type) {
53475
- return WORKSPACE_ACTION_TYPES.includes(type);
53474
+ function isOrganizationActionType(type) {
53475
+ return ORGANIZATION_ACTION_TYPES.includes(type);
53476
53476
  }
53477
53477
  function def(type, description, input, options) {
53478
53478
  var _a2;
@@ -53485,7 +53485,7 @@ function def(type, description, input, options) {
53485
53485
  function getOpaqueActionDef(type) {
53486
53486
  return OPAQUE_ACTIONS.find((a5) => a5.type === type);
53487
53487
  }
53488
- var shaderLayersSchema, variableValue, STYLE_KEYS, STYLE_TRAPS, nodeUpdatesSchema, WORKSPACE_ACTION_TYPES, componentId, pageId, variantId, OPAQUE_ACTIONS;
53488
+ var shaderLayersSchema, variableValue, STYLE_KEYS, STYLE_TRAPS, nodeUpdatesSchema, ORGANIZATION_ACTION_TYPES, componentId, pageId, variantId, OPAQUE_ACTIONS;
53489
53489
  var init_opaqueActions = __esm({
53490
53490
  "../shared/dist/ai/opaque/opaqueActions.js"() {
53491
53491
  "use strict";
@@ -53530,7 +53530,7 @@ var init_opaqueActions = __esm({
53530
53530
  base: z51.record(z51.string(), z51.unknown()).optional().describe(`Visual properties. VALID KEYS \u2014 no others are accepted, and one invalid key rejects the WHOLE edit: ${STYLE_KEYS.join(", ")}. Common mistakes: ${STYLE_TRAPS}.`)
53531
53531
  }).optional()
53532
53532
  }).describe("Initial/updated values: `styles` for visual properties, `name` for the layer name, `innerText` for text content (text nodes only), `svgPath` to promote to vector, `shaderLayers` for shader effects, plus the semantic node fields (placeholder, inputValue, inputTextType, htmlTag, className, url, target, frameUrl).");
53533
- WORKSPACE_ACTION_TYPES = [
53533
+ ORGANIZATION_ACTION_TYPES = [
53534
53534
  "listProjects",
53535
53535
  "createProject",
53536
53536
  "updateProject",
@@ -53821,12 +53821,12 @@ var init_opaqueActions = __esm({
53821
53821
  sourceBranch: z51.string().optional().describe("The branch whose OPEN pull request to comment on. Pass this OR prId."),
53822
53822
  body: z51.string().describe("The comment, in plain text.")
53823
53823
  })),
53824
- def("listProjects", "List the projects in the user's current workspace (organization): id, name, slug, and last-update time. The [Workspace] context block already carries this list \u2014 call this only when you need a FRESH read (e.g. right after you created a project).", z51.object({}), { readOnly: true }),
53825
- def("createProject", "Create a new project in the user's current workspace. Returns the new project's id and slug. Set `open: true` to also navigate the user's browser to it \u2014 do that only when the user asked to open or start working in it.", z51.object({
53824
+ def("listProjects", "List the projects in the user's current organization: id, name, slug, and last-update time. The [Organization] context block already carries this list \u2014 call this only when you need a FRESH read (e.g. right after you created a project).", z51.object({}), { readOnly: true }),
53825
+ def("createProject", "Create a new project in the user's current organization. Returns the new project's id and slug. Set `open: true` to also navigate the user's browser to it \u2014 do that only when the user asked to open or start working in it.", z51.object({
53826
53826
  name: z51.string().describe("Display name for the new project."),
53827
53827
  open: z51.boolean().optional().describe("True to navigate the user's browser to the new project. Only when the user asked to open it.")
53828
53828
  })),
53829
- def("updateProject", "Rename a project in the user's current workspace. Never navigates.", z51.object({
53829
+ def("updateProject", "Rename a project in the user's current organization. Never navigates.", z51.object({
53830
53830
  projectRef: z51.string().describe("The target project's id, or its exact display name."),
53831
53831
  name: z51.string().describe("The new display name.")
53832
53832
  })),
@@ -53836,7 +53836,7 @@ var init_opaqueActions = __esm({
53836
53836
  def("setTargetProject", "Point this turn's canvas verbs at a project WITHOUT navigating the user's browser. Later canvas edits run against that project in the background, on this agent's own work branch. Use this to act on a project the user did not ask to open.", z51.object({
53837
53837
  projectRef: z51.string().describe("The target project's id, or its exact display name.")
53838
53838
  })),
53839
- def("createAgent", "Create a new agent for the user. With `projectId` the new agent is DEDICATED: it can act only inside that project, and the user finds it in that project's agent picker. Without `projectId` it is another workspace agent. This does not start the new agent \u2014 the user sends its first message.", z51.object({
53839
+ def("createAgent", "Create a new agent for the user. With `projectId` the new agent is DEDICATED: it can act only inside that project, and the user finds it in that project's agent picker. Without `projectId` it is another organization agent. This does not start the new agent \u2014 the user sends its first message.", z51.object({
53840
53840
  name: z51.string().optional().describe("Display name for the new agent (default: 'Agent N')."),
53841
53841
  projectId: z51.string().optional().describe("Bind the new agent to this project id.")
53842
53842
  })),
@@ -53943,7 +53943,7 @@ var init_brief_context = __esm({
53943
53943
  });
53944
53944
 
53945
53945
  // ../shared/dist/ai/conversation-personas.js
53946
- var AGENT_PREAMBLE, MULTI_FAMILY_GUIDANCE, CONVERSATIONAL_PERSONA, WORKSPACE_PERSONA, CANVAS_PERSONA, CANVAS_STYLES_SUPPLIED_NOTE;
53946
+ var AGENT_PREAMBLE, MULTI_FAMILY_GUIDANCE, CONVERSATIONAL_PERSONA, ORGANIZATION_PERSONA, CANVAS_PERSONA, CANVAS_STYLES_SUPPLIED_NOTE;
53947
53947
  var init_conversation_personas = __esm({
53948
53948
  "../shared/dist/ai/conversation-personas.js"() {
53949
53949
  "use strict";
@@ -53977,11 +53977,11 @@ uses the filesystem tools. Some tasks use more than one; that's fine.
53977
53977
  " asks to build/generate a new brand or design system.",
53978
53978
  "- You work inside THIS project only. If the user asks for work outside it \u2014",
53979
53979
  " creating projects, or renaming or editing other projects \u2014 say that a",
53980
- " WORKSPACE agent does that, in the agent picker's Workspace section."
53980
+ " ORGANIZATION agent does that, in the agent picker's Organization section."
53981
53981
  ].join("\n");
53982
- WORKSPACE_PERSONA = [
53983
- "You are the user's WORKSPACE agent. No project is open on screen.",
53984
- "- The [Workspace] block above lists the workspace's projects (name, slug,",
53982
+ ORGANIZATION_PERSONA = [
53983
+ "You are the user's ORGANIZATION agent. No project is open on screen.",
53984
+ "- The [Organization] block above lists the organization's projects (name, slug,",
53985
53985
  " id). Resolve a project the user names from that list; ask only",
53986
53986
  " when two projects genuinely collide. Call listProjects only for a FRESH",
53987
53987
  " read (e.g. right after you created a project).",
@@ -54020,7 +54020,7 @@ uses the filesystem tools. Some tasks use more than one; that's fine.
54020
54020
  " correct property. Fix and retry rather than reporting failure to the user.",
54021
54021
  "- You work inside THIS project only. If the user asks for work outside it \u2014",
54022
54022
  " creating projects, or renaming or editing other projects \u2014 say that a",
54023
- " WORKSPACE agent does that, in the agent picker's Workspace section."
54023
+ " ORGANIZATION agent does that, in the agent picker's Organization section."
54024
54024
  ].join("\n");
54025
54025
  CANVAS_STYLES_SUPPLIED_NOTE = [
54026
54026
  "- The selected element's CURRENT STYLES are listed above and are up to date.",
@@ -57607,7 +57607,7 @@ var init_page_generator = __esm({
57607
57607
  });
57608
57608
 
57609
57609
  // ../shared/dist/element-generation/components/adapters/deployment/app-runtime.js
57610
- var NODE_HOOK_ATTR, INSTANCE_HOOK_ATTR, DATA_ATTR_PREFIX;
57610
+ var NODE_HOOK_ATTR, BUSY_CONTROL_KEY, INSTANCE_HOOK_ATTR, DATA_ATTR_PREFIX;
57611
57611
  var init_app_runtime = __esm({
57612
57612
  "../shared/dist/element-generation/components/adapters/deployment/app-runtime.js"() {
57613
57613
  "use strict";
@@ -57615,6 +57615,7 @@ var init_app_runtime = __esm({
57615
57615
  init_deployed_naming();
57616
57616
  init_constants3();
57617
57617
  NODE_HOOK_ATTR = dataAttr("node");
57618
+ BUSY_CONTROL_KEY = `__${DEPLOYED_NAMING.dataAttrPrefix}Control`;
57618
57619
  INSTANCE_HOOK_ATTR = dataAttr("instance");
57619
57620
  DATA_ATTR_PREFIX = DEPLOYED_NAMING.dataAttrPrefix;
57620
57621
  }
@@ -88283,7 +88284,7 @@ var CLI_VERSION;
88283
88284
  var init_version = __esm({
88284
88285
  "src/config/version.ts"() {
88285
88286
  "use strict";
88286
- CLI_VERSION = true ? "0.1.2" : "0.0.0-dev";
88287
+ CLI_VERSION = true ? "0.1.3" : "0.0.0-dev";
88287
88288
  }
88288
88289
  });
88289
88290
 
@@ -90638,13 +90639,13 @@ function serializeProject(project) {
90638
90639
  slug: typeof project.slug === "string" ? project.slug : null
90639
90640
  };
90640
90641
  }
90641
- async function loadWorkspaceProjects() {
90642
+ async function loadOrganizationProjects() {
90642
90643
  const matches = await Project2.query({}).reduce({});
90643
90644
  return matches.filter((project) => !!project);
90644
90645
  }
90645
90646
  async function executeOrgActionAsync(action, context) {
90646
90647
  var _a2, _b;
90647
- const projects = await loadWorkspaceProjects();
90648
+ const projects = await loadOrganizationProjects();
90648
90649
  if (action.type === "listProjects") {
90649
90650
  return {
90650
90651
  action,
@@ -90670,7 +90671,7 @@ async function executeOrgActionAsync(action, context) {
90670
90671
  return {
90671
90672
  action,
90672
90673
  success: false,
90673
- error: `No project "${ref2}" in this workspace. Call listProjects to see what is there.`
90674
+ error: `No project "${ref2}" in this organization. Call listProjects to see what is there.`
90674
90675
  };
90675
90676
  }
90676
90677
  const named = Object.assign(Object.assign({}, action), { projectRef: resolved.id });
@@ -90705,7 +90706,7 @@ function executeCreateProject(action, context, existing) {
90705
90706
  return {
90706
90707
  action,
90707
90708
  success: false,
90708
- error: `This workspace already has a project called "${name}" (${taken.id}). Two projects with one name leave every later reference ambiguous.`
90709
+ error: `This organization already has a project called "${name}" (${taken.id}). Two projects with one name leave every later reference ambiguous.`
90709
90710
  };
90710
90711
  }
90711
90712
  const actionIds = [];
@@ -96622,7 +96623,7 @@ var init_async_context = __esm({
96622
96623
  });
96623
96624
 
96624
96625
  // src/opaque/headless-client.ts
96625
- function isWorkspaceClientUsable(client2) {
96626
+ function isOrganizationClientUsable(client2) {
96626
96627
  return client2.isWebSocketOpen() && client2.isOrgConfirmed();
96627
96628
  }
96628
96629
  function assertNodeWebSocket() {
@@ -96742,7 +96743,7 @@ async function resolveProjectRef(listing, reference) {
96742
96743
  throw new ProjectRefError("Project reference is empty.");
96743
96744
  }
96744
96745
  const { projects } = listing;
96745
- const workspace = listing.workspace ?? (listing.orgId ? { id: listing.orgId, name: null, slug: null } : void 0);
96746
+ const organization = listing.organization ?? (listing.orgId ? { id: listing.orgId, name: null, slug: null } : void 0);
96746
96747
  if (PROJECT_ID_PATTERN.test(trimmed)) {
96747
96748
  const mine = projects.find(
96748
96749
  (p4) => p4.id.toLowerCase() === trimmed.toLowerCase()
@@ -96753,38 +96754,38 @@ async function resolveProjectRef(listing, reference) {
96753
96754
  name: mine.name,
96754
96755
  slug: mine.slug,
96755
96756
  matchedBy: "id",
96756
- workspace
96757
+ organization
96757
96758
  };
96758
96759
  }
96759
96760
  throw new ProjectRefError(
96760
- `${trimmed} is not among this workspace's projects. Call listProjects to see what is here, or pass \`workspace\` to look somewhere else. Nothing was connected.`
96761
+ `${trimmed} is not among this organization's projects. Call listProjects to see what is here, or pass \`organization\` to look somewhere else. Nothing was connected.`
96761
96762
  );
96762
96763
  }
96763
96764
  const { record, matchedBy } = matchRef({
96764
96765
  reference: trimmed,
96765
96766
  records: projects,
96766
96767
  noun: "project",
96767
- emptyMessage: "This workspace has no projects. Call createProject, then connect to it.",
96768
- candidatesPrefix: "This workspace's projects"
96768
+ emptyMessage: "This organization has no projects. Call createProject, then connect to it.",
96769
+ candidatesPrefix: "This organization's projects"
96769
96770
  });
96770
96771
  return {
96771
96772
  projectId: record.id,
96772
96773
  name: record.name,
96773
96774
  slug: record.slug,
96774
96775
  matchedBy,
96775
- workspace
96776
+ organization
96776
96777
  };
96777
96778
  }
96778
- async function resolveWorkspaceRef(api, reference) {
96779
+ async function resolveOrganizationRef(api, reference) {
96779
96780
  const trimmed = reference.trim();
96780
96781
  if (!trimmed) {
96781
- throw new ProjectRefError("Workspace reference is empty.");
96782
+ throw new ProjectRefError("Organization reference is empty.");
96782
96783
  }
96783
- const { organizations } = await api.listWorkspaces();
96784
+ const { organizations } = await api.listOrganizations();
96784
96785
  if (ORG_ID_PATTERN.test(trimmed)) {
96785
96786
  const known = organizations.find((o3) => o3.id === trimmed);
96786
96787
  return {
96787
- workspaceId: trimmed,
96788
+ organizationId: trimmed,
96788
96789
  ...known ? { name: known.name, slug: known.slug } : {},
96789
96790
  role: known?.role ?? "read",
96790
96791
  matchedBy: "id"
@@ -96793,12 +96794,12 @@ async function resolveWorkspaceRef(api, reference) {
96793
96794
  const { record, matchedBy } = matchRef({
96794
96795
  reference: trimmed,
96795
96796
  records: organizations,
96796
- noun: "workspace",
96797
- emptyMessage: "This account belongs to no workspace yet.",
96798
- candidatesPrefix: "Your workspaces"
96797
+ noun: "organization",
96798
+ emptyMessage: "This account belongs to no organization yet.",
96799
+ candidatesPrefix: "Your organizations"
96799
96800
  });
96800
96801
  return {
96801
- workspaceId: record.id,
96802
+ organizationId: record.id,
96802
96803
  name: record.name,
96803
96804
  slug: record.slug,
96804
96805
  role: record.role,
@@ -97363,12 +97364,12 @@ var init_ai_action_api = __esm({
97363
97364
  },
97364
97365
  {
97365
97366
  type: "listProjects",
97366
- description: "List the projects in the user's current workspace (organization): id, name, slug, and last-update time. The [Workspace] context block already carries this list \u2014 call this only when you need a FRESH read (e.g. right after you created a project).",
97367
+ description: "List the projects in the user's current organization: id, name, slug, and last-update time. The [Organization] context block already carries this list \u2014 call this only when you need a FRESH read (e.g. right after you created a project).",
97367
97368
  parameters: {}
97368
97369
  },
97369
97370
  {
97370
97371
  type: "createProject",
97371
- description: "Create a new project in the user's current workspace. Returns the new project's id and slug. Set `open: true` to also navigate the user's browser to it \u2014 do that only when the user asked to open or start working in it.",
97372
+ description: "Create a new project in the user's current organization. Returns the new project's id and slug. Set `open: true` to also navigate the user's browser to it \u2014 do that only when the user asked to open or start working in it.",
97372
97373
  parameters: {
97373
97374
  name: "string - Display name for the new project.",
97374
97375
  open: "boolean (optional) - True to navigate the user's browser to the new project. Only when the user asked to open it."
@@ -97376,7 +97377,7 @@ var init_ai_action_api = __esm({
97376
97377
  },
97377
97378
  {
97378
97379
  type: "updateProject",
97379
- description: "Rename a project in the user's current workspace. Never navigates.",
97380
+ description: "Rename a project in the user's current organization. Never navigates.",
97380
97381
  parameters: {
97381
97382
  projectRef: "string - The target project's id, or its exact display name.",
97382
97383
  name: "string - The new display name."
@@ -97398,7 +97399,7 @@ var init_ai_action_api = __esm({
97398
97399
  },
97399
97400
  {
97400
97401
  type: "createAgent",
97401
- description: "Create a new agent for the user. With `projectId` the new agent is DEDICATED: it can act only inside that project, and the user finds it in that project's agent picker. Without `projectId` it is another workspace agent. This does not start the new agent \u2014 the user sends its first message.",
97402
+ description: "Create a new agent for the user. With `projectId` the new agent is DEDICATED: it can act only inside that project, and the user finds it in that project's agent picker. Without `projectId` it is another organization agent. This does not start the new agent \u2014 the user sends its first message.",
97402
97403
  parameters: {
97403
97404
  name: "string (optional) - Display name for the new agent (default: 'Agent N').",
97404
97405
  projectId: "string (optional) - Bind the new agent to this project id."
@@ -98603,13 +98604,13 @@ async function runMcpServer(options) {
98603
98604
  options.baseUrlOverride ?? creds.baseUrl ?? BUILT_IN_BASE_URL
98604
98605
  );
98605
98606
  if (credentialInstance === session.baseUrl) return null;
98606
- return `The credential now points at ${credentialInstance}, but this session is open against ${session.baseUrl}. Refusing to send this call to a different instance than the one you are working on: the token would be presented to the wrong server, and on a development machine the two are commonly local dev and production. Nothing was sent. Either restore the credential for ${session.baseUrl} (\`zoah login\` in that workspace), or call \`disconnect\` and then \`connect\` to move this session to ${credentialInstance} deliberately.`;
98607
+ return `The credential now points at ${credentialInstance}, but this session is open against ${session.baseUrl}. Refusing to send this call to a different instance than the one you are working on: the token would be presented to the wrong server, and on a development machine the two are commonly local dev and production. Nothing was sent. Either restore the credential for ${session.baseUrl} (\`zoah login\` in that directory), or call \`disconnect\` and then \`connect\` to move this session to ${credentialInstance} deliberately.`;
98607
98608
  }
98608
98609
  function loginScope() {
98609
98610
  return existsSync10(zoahPaths.localCredentials(process.cwd())) || existsSync10(legacyOpacityPaths.localCredentials(process.cwd())) ? "local" : "global";
98610
98611
  }
98611
98612
  let pendingSignIn = null;
98612
- let selectedWorkspace = null;
98613
+ let selectedOrganization = null;
98613
98614
  let sessionEndedBy = null;
98614
98615
  function noSessionMessage() {
98615
98616
  return (sessionEndedBy ? `No session: ${sessionEndedBy}. ` : "No session. ") + "Call `connect` with `project` (a slug, a name or an id) to open one; add `branch` to pick a branch, or omit it to work on a fresh agent branch.";
@@ -98666,18 +98667,18 @@ async function runMcpServer(options) {
98666
98667
  return result;
98667
98668
  }
98668
98669
  }
98669
- let ambientWorkspace = null;
98670
+ let ambientOrganization = null;
98670
98671
  function describeWorkingIn(fallbackId) {
98671
- if (selectedWorkspace) {
98672
+ if (selectedOrganization) {
98672
98673
  return {
98673
- id: selectedWorkspace.workspaceId,
98674
- name: selectedWorkspace.name ?? null,
98675
- slug: selectedWorkspace.slug ?? null,
98674
+ id: selectedOrganization.organizationId,
98675
+ name: selectedOrganization.name ?? null,
98676
+ slug: selectedOrganization.slug ?? null,
98676
98677
  pinnedBy: "connect"
98677
98678
  };
98678
98679
  }
98679
- if (ambientWorkspace) {
98680
- return { ...ambientWorkspace, pinnedBy: "the human's selection" };
98680
+ if (ambientOrganization) {
98681
+ return { ...ambientOrganization, pinnedBy: "the human's selection" };
98681
98682
  }
98682
98683
  return fallbackId ? {
98683
98684
  id: fallbackId,
@@ -98686,57 +98687,60 @@ async function runMcpServer(options) {
98686
98687
  pinnedBy: "the human's selection"
98687
98688
  } : null;
98688
98689
  }
98689
- function workspaceLabel(fallbackId) {
98690
+ function organizationLabel(fallbackId) {
98690
98691
  const working = describeWorkingIn(fallbackId);
98691
98692
  return working?.slug ?? working?.id ?? fallbackId;
98692
98693
  }
98693
- function describeSelectedWorkspace() {
98694
+ function describeSelectedOrganization() {
98694
98695
  const working = describeWorkingIn();
98695
- return working ? { workspace: working } : {};
98696
+ return working ? { organization: working } : {};
98696
98697
  }
98697
- async function pinWorkspace(reference) {
98698
+ async function pinOrganization(reference) {
98698
98699
  if (!reference) return {};
98699
- const resolved = await resolveWorkspaceRef(await currentApi(), reference);
98700
- const droppedSession = resolved.workspaceId !== selectedWorkspace?.workspaceId ? await endSessionForWorkspaceChange(resolved) : void 0;
98701
- selectedWorkspace = resolved;
98700
+ const resolved = await resolveOrganizationRef(
98701
+ await currentApi(),
98702
+ reference
98703
+ );
98704
+ const droppedSession = resolved.organizationId !== selectedOrganization?.organizationId ? await endSessionForOrganizationChange(resolved) : void 0;
98705
+ selectedOrganization = resolved;
98702
98706
  applyRole(resolved.role);
98703
98707
  return droppedSession ? { droppedSession } : {};
98704
98708
  }
98705
- async function endSessionForWorkspaceChange(to) {
98709
+ async function endSessionForOrganizationChange(to) {
98706
98710
  const dropped = session ? {
98707
98711
  project: session.projectId,
98708
98712
  branch: session.branchSlug,
98709
- fromWorkspace: workspaceLabel(session.orgId),
98710
- toWorkspace: to.slug ?? to.workspaceId
98713
+ fromOrganization: organizationLabel(session.orgId),
98714
+ toOrganization: to.slug ?? to.organizationId
98711
98715
  } : void 0;
98712
98716
  if (session) await teardownSession();
98713
- await teardownWorkspaceClient();
98717
+ await teardownOrganizationClient();
98714
98718
  if (!dropped) return void 0;
98715
- sessionEndedBy = `switching to workspace ${dropped.toWorkspace} ended the session on ${dropped.project} (${dropped.branch}), because that session's token was minted for a project in ${dropped.fromWorkspace}`;
98719
+ sessionEndedBy = `switching to organization ${dropped.toOrganization} ended the session on ${dropped.project} (${dropped.branch}), because that session's token was minted for a project in ${dropped.fromOrganization}`;
98716
98720
  return dropped;
98717
98721
  }
98718
98722
  const syncUrlOverride = options.syncUrlOverride ?? process.env.ZOAH_SYNC_WS_URL ?? process.env.OPACITY_SYNC_WS_URL;
98719
98723
  let session = null;
98720
- let workspaceClient = null;
98724
+ let organizationClient = null;
98721
98725
  function applyClientRole(client2, role) {
98722
98726
  let applied = false;
98723
98727
  if (session?.client === client2) {
98724
98728
  session.role = role;
98725
98729
  applied = true;
98726
98730
  }
98727
- if (workspaceClient?.client === client2) {
98728
- workspaceClient.role = role;
98731
+ if (organizationClient?.client === client2) {
98732
+ organizationClient.role = role;
98729
98733
  applied = true;
98730
98734
  }
98731
98735
  if (applied) applyRole(role);
98732
98736
  }
98733
- async function teardownWorkspaceClient() {
98734
- if (!workspaceClient) return;
98735
- const { client: client2 } = workspaceClient;
98736
- workspaceClient = null;
98737
+ async function teardownOrganizationClient() {
98738
+ if (!organizationClient) return;
98739
+ const { client: client2 } = organizationClient;
98740
+ organizationClient = null;
98737
98741
  await client2.disconnectAndWait();
98738
98742
  }
98739
- async function ensureWorkspaceClient() {
98743
+ async function ensureOrganizationClient() {
98740
98744
  if (session) {
98741
98745
  return {
98742
98746
  client: session.client,
@@ -98744,15 +98748,15 @@ async function runMcpServer(options) {
98744
98748
  role: session.role
98745
98749
  };
98746
98750
  }
98747
- if (workspaceClient) return workspaceClient;
98748
- let orgId = selectedWorkspace?.workspaceId;
98751
+ if (organizationClient) return organizationClient;
98752
+ let orgId = selectedOrganization?.organizationId;
98749
98753
  if (!orgId) {
98750
- const { organizations, activeOrganizationId } = await (await currentApi()).listWorkspaces();
98754
+ const { organizations, activeOrganizationId } = await (await currentApi()).listOrganizations();
98751
98755
  orgId = activeOrganizationId ?? (organizations.length === 1 ? organizations[0]?.id : void 0);
98752
98756
  }
98753
98757
  if (!orgId) {
98754
98758
  throw new Error(
98755
- "No workspace selected, and you belong to more than one. Call listWorkspaces to see them, then connect with `workspace` to choose one."
98759
+ "No organization selected, and you belong to more than one. Call listOrganizations to see them, then connect with `organization` to choose one."
98756
98760
  );
98757
98761
  }
98758
98762
  let minted = await (await currentApi()).mintAgentSyncToken({ orgId });
@@ -98770,14 +98774,14 @@ async function runMcpServer(options) {
98770
98774
  return minted.token;
98771
98775
  }
98772
98776
  });
98773
- workspaceClient = {
98777
+ organizationClient = {
98774
98778
  client: client2,
98775
98779
  orgId: minted.orgId,
98776
98780
  role: minted.role,
98777
98781
  getSyncTokenExpiresAt: () => minted.expiresAt
98778
98782
  };
98779
98783
  applyRole(minted.role);
98780
- return workspaceClient;
98784
+ return organizationClient;
98781
98785
  }
98782
98786
  async function teardownSession() {
98783
98787
  if (!session) return;
@@ -98785,7 +98789,7 @@ async function runMcpServer(options) {
98785
98789
  const { client: client2 } = session;
98786
98790
  session = null;
98787
98791
  await client2.disconnectAndWait();
98788
- applyRole(selectedWorkspace?.role ?? null);
98792
+ applyRole(selectedOrganization?.role ?? null);
98789
98793
  }
98790
98794
  function pushEvent(event) {
98791
98795
  if (!session) return;
@@ -98801,15 +98805,15 @@ async function runMcpServer(options) {
98801
98805
  let minted = await (await currentApi()).mintAgentSyncToken({
98802
98806
  projectId,
98803
98807
  branchSlug,
98804
- // ORG-scoped: the token names the workspace, not this project. The
98805
- // The gateway confines this token to projects owned by the workspace.
98808
+ // ORG-scoped: the token names the organization, not this project. The
98809
+ // The gateway confines this token to projects owned by the organization.
98806
98810
  // The session selects one project through its socket context.
98807
98811
  orgScoped: true
98808
98812
  });
98809
98813
  const wsUrl = syncUrlOverride ?? minted.syncUrl ?? deriveSyncWsUrl(await currentBaseUrl());
98810
- const adopted = workspaceClient && workspaceClient.orgId === minted.orgId ? workspaceClient : null;
98814
+ const adopted = organizationClient && organizationClient.orgId === minted.orgId ? organizationClient : null;
98811
98815
  if (adopted) {
98812
- workspaceClient = null;
98816
+ organizationClient = null;
98813
98817
  try {
98814
98818
  await enterProjectScope(adopted.client, {
98815
98819
  orgId: minted.orgId,
@@ -98965,7 +98969,7 @@ async function runMcpServer(options) {
98965
98969
  const def3 = OPAQUE_ACTIONS.find((candidate) => candidate.type === type);
98966
98970
  if ((def3?.mutates ?? true) && s5.role === "read") {
98967
98971
  throw new Error(
98968
- `${type}: this workspace role is read-only. NOTHING was written.`
98972
+ `${type}: this organization role is read-only. NOTHING was written.`
98969
98973
  );
98970
98974
  }
98971
98975
  const wasDown = !socketUsable(s5);
@@ -99003,17 +99007,17 @@ async function runMcpServer(options) {
99003
99007
  await client2.waitForActionAck(actionId, VERB_ACK_TIMEOUT_MS);
99004
99008
  }
99005
99009
  }
99006
- async function runWorkspaceVerb(type, input) {
99007
- const { client: client2, orgId, role } = await ensureWorkspaceClient();
99010
+ async function runOrganizationVerb(type, input) {
99011
+ const { client: client2, orgId, role } = await ensureOrganizationClient();
99008
99012
  const def3 = OPAQUE_ACTIONS.find((candidate) => candidate.type === type);
99009
99013
  if ((def3?.mutates ?? true) && role === "read") {
99010
99014
  throw new Error(
99011
- `${type}: this workspace role is read-only. NOTHING was written.`
99015
+ `${type}: this organization role is read-only. NOTHING was written.`
99012
99016
  );
99013
99017
  }
99014
- if ((def3?.mutates ?? true) && await awaitLiveClient(client2, isWorkspaceClientUsable) === "down") {
99018
+ if ((def3?.mutates ?? true) && await awaitLiveClient(client2, isOrganizationClientUsable) === "down") {
99015
99019
  throw new Error(
99016
- `${type}: the workspace sync connection is down. NOTHING was written. Nothing is queued or applied later. Call this verb again after the connection returns.`
99020
+ `${type}: the organization sync connection is down. NOTHING was written. Nothing is queued or applied later. Call this verb again after the connection returns.`
99017
99021
  );
99018
99022
  }
99019
99023
  return client2.runWithSchemas(async () => {
@@ -99024,7 +99028,7 @@ async function runMcpServer(options) {
99024
99028
  return {
99025
99029
  action: { type },
99026
99030
  success: false,
99027
- error: !org ? `Workspace ${orgId} could not be loaded, so ${type} has nothing to act on.` : `This session has no signed-in user, so ${type} cannot run.`
99031
+ error: !org ? `Organization ${orgId} could not be loaded, so ${type} has nothing to act on.` : `This session has no signed-in user, so ${type} cannot run.`
99028
99032
  };
99029
99033
  }
99030
99034
  const action = { type, ...input };
@@ -99033,20 +99037,20 @@ async function runMcpServer(options) {
99033
99037
  return executed;
99034
99038
  });
99035
99039
  }
99036
- async function workspaceListing() {
99037
- const executed = await runWorkspaceVerb("listProjects", {});
99040
+ async function organizationListing() {
99041
+ const executed = await runOrganizationVerb("listProjects", {});
99038
99042
  if (!executed.success) {
99039
99043
  throw new Error(executed.error ?? "listProjects failed");
99040
99044
  }
99041
99045
  const { projects } = executed.data;
99042
99046
  return {
99043
99047
  projects,
99044
- workspace: selectedWorkspace ? {
99045
- id: selectedWorkspace.workspaceId,
99046
- name: selectedWorkspace.name ?? null,
99047
- slug: selectedWorkspace.slug ?? null
99048
+ organization: selectedOrganization ? {
99049
+ id: selectedOrganization.organizationId,
99050
+ name: selectedOrganization.name ?? null,
99051
+ slug: selectedOrganization.slug ?? null
99048
99052
  } : null,
99049
- orgId: selectedWorkspace?.workspaceId ?? null
99053
+ orgId: selectedOrganization?.organizationId ?? null
99050
99054
  };
99051
99055
  }
99052
99056
  function reviewUrlFor(s5, prId) {
@@ -99058,7 +99062,7 @@ async function runMcpServer(options) {
99058
99062
  if (!dropped) return {};
99059
99063
  return {
99060
99064
  droppedSession: { project: dropped.project, branch: dropped.branch },
99061
- droppedSessionReason: `Switching to workspace ${dropped.toWorkspace} ended the session on ${dropped.project} (${dropped.branch}): that session's token was minted for a project in ${dropped.fromWorkspace}, so keeping it open would leave the next write landing in a workspace you have stopped talking about. Every verb that returned success was confirmed by the server before it returned. Open a session here with \`project\`.`
99065
+ droppedSessionReason: `Switching to organization ${dropped.toOrganization} ended the session on ${dropped.project} (${dropped.branch}): that session's token was minted for a project in ${dropped.fromOrganization}, so keeping it open would leave the next write landing in an organization you have stopped talking about. Every verb that returned success was confirmed by the server before it returned. Open a session here with \`project\`.`
99062
99066
  };
99063
99067
  }
99064
99068
  const server = new McpServer({ name: "zoah", version: CLI_VERSION });
@@ -99087,8 +99091,8 @@ async function runMcpServer(options) {
99087
99091
  "Name what to open: pass `project` (a slug, a name or an id). Call listProjects to see what is available, or run `zoah mcp init` in a repo linked to a project to bake in a default."
99088
99092
  );
99089
99093
  }
99090
- resolved = await resolveProjectRef(await workspaceListing(), named);
99091
- if (resolved.workspace) ambientWorkspace = resolved.workspace;
99094
+ resolved = await resolveProjectRef(await organizationListing(), named);
99095
+ if (resolved.organization) ambientOrganization = resolved.organization;
99092
99096
  const projectId = resolved.projectId;
99093
99097
  await teardownSession();
99094
99098
  if (options.readOnly || branch) {
@@ -99134,10 +99138,10 @@ async function runMcpServer(options) {
99134
99138
  sessionEndedBy = null;
99135
99139
  return jsonResult({
99136
99140
  connected: true,
99137
- // Which workspace this project is in, named rather than implied. The
99138
- // same project name in two workspaces is two different projects, so a
99141
+ // Which organization this project is in, named rather than implied. The
99142
+ // same project name in two organizations is two different projects, so a
99139
99143
  // connected result that omits it is ambiguous by construction.
99140
- workspace: describeWorkingIn(session.orgId),
99144
+ organization: describeWorkingIn(session.orgId),
99141
99145
  role: session.role,
99142
99146
  projectId,
99143
99147
  // Name what the reference resolved to. A partial match that lands on
@@ -99168,13 +99172,13 @@ async function runMcpServer(options) {
99168
99172
  server.registerTool(
99169
99173
  "connect",
99170
99174
  {
99171
- description: "Choose what you are working on: workspace, project, and branch. Call it to start, and again whenever you want to switch any of the three. It signs you in first if it has to, so a session usually needs nothing else. Safe to call at any time: it reports which state it is in rather than assuming one. When it returns an `authUrl`, give that URL to the human, wait for them to approve it, then call `connect` again - do not open it yourself and do not ask them for a token.",
99175
+ description: "Choose what you are working on: organization, project, and branch. Call it to start, and again whenever you want to switch any of the three. It signs you in first if it has to, so a session usually needs nothing else. Safe to call at any time: it reports which state it is in rather than assuming one. When it returns an `authUrl`, give that URL to the human, wait for them to approve it, then call `connect` again - do not open it yourself and do not ask them for a token.",
99172
99176
  inputSchema: {
99173
99177
  baseUrl: z57.string().optional().describe(
99174
99178
  "The Zoah instance to use, e.g. http://localhost:5071. Wins over the launch flag, the saved credential and the built-in default, and is saved so later calls agree. Needed on a clean workspace: with no credential file yet, the built-in default is a guess, and on a multi-instance dev machine it is usually the wrong port."
99175
99179
  ),
99176
- workspace: z57.string().optional().describe(
99177
- "Workspace to work in: its slug, its name, or its id. Stays selected for the rest of this session, so later calls and listProjects all scope to it. Omit to follow the human's own selection. Call listWorkspaces to see them."
99180
+ organization: z57.string().optional().describe(
99181
+ "Organization to work in: its slug, its name, or its id. Stays selected for the rest of this session, so later calls and listProjects all scope to it. Omit to follow the human's own selection. Call listOrganizations to see them."
99178
99182
  ),
99179
99183
  project: z57.string().optional().describe(
99180
99184
  "Project to connect to: its slug, its name, or its id. Omit it to sign in only." + (options.defaultProject ? ` Defaults to this repo's linked project (${options.defaultProject}).` : " Call listProjects to see what is available.")
@@ -99184,7 +99188,7 @@ async function runMcpServer(options) {
99184
99188
  )
99185
99189
  }
99186
99190
  },
99187
- async ({ baseUrl, workspace, project, branch }) => {
99191
+ async ({ baseUrl, organization, project, branch }) => {
99188
99192
  try {
99189
99193
  const creds = await currentCreds().catch(() => null);
99190
99194
  const target = resolveBaseUrl({
@@ -99196,7 +99200,7 @@ async function runMcpServer(options) {
99196
99200
  const health = creds ? credentialHealth(creds.token) : null;
99197
99201
  const usable = creds !== null && health !== null && !health.expired && !health.expiringSoon && stripSlash(creds.baseUrl) === target.baseUrl;
99198
99202
  if (usable) {
99199
- const pin = await pinWorkspace(workspace);
99203
+ const pin = await pinOrganization(organization);
99200
99204
  if (!project && !options.defaultProject) {
99201
99205
  return jsonResult({
99202
99206
  signedIn: true,
@@ -99204,9 +99208,9 @@ async function runMcpServer(options) {
99204
99208
  signingInTo: target.baseUrl,
99205
99209
  baseUrlSource: target.source,
99206
99210
  credentialExpiresInSeconds: health.expiresInSeconds,
99207
- ...describeSelectedWorkspace(),
99211
+ ...describeSelectedOrganization(),
99208
99212
  ...describeDrop(pin),
99209
- note: selectedWorkspace !== null ? `Already signed in, and working in ${selectedWorkspace.slug ?? selectedWorkspace.workspaceId}. Pass \`project\` to connect to one, or call listProjects to see what is there.` : "Already signed in. Pass `project` to connect to one, or call listProjects to see what is available."
99213
+ note: selectedOrganization !== null ? `Already signed in, and working in ${selectedOrganization.slug ?? selectedOrganization.organizationId}. Pass \`project\` to connect to one, or call listProjects to see what is there.` : "Already signed in. Pass `project` to connect to one, or call listProjects to see what is available."
99210
99214
  });
99211
99215
  }
99212
99216
  const connected = await connectAndDescribe({ project, branch });
@@ -99228,7 +99232,7 @@ async function runMcpServer(options) {
99228
99232
  }),
99229
99233
  startedAtMs: Date.now(),
99230
99234
  baseUrl: target.baseUrl,
99231
- workspace,
99235
+ organization,
99232
99236
  project,
99233
99237
  branch
99234
99238
  };
@@ -99258,14 +99262,16 @@ async function runMcpServer(options) {
99258
99262
  pendingSignIn = null;
99259
99263
  const wanted = project ?? pending.project;
99260
99264
  const wantedBranch = branch ?? pending.branch;
99261
- const pin = await pinWorkspace(workspace ?? pending.workspace);
99265
+ const pin = await pinOrganization(
99266
+ organization ?? pending.organization
99267
+ );
99262
99268
  if (!wanted && !options.defaultProject) {
99263
99269
  return jsonResult({
99264
99270
  signedIn: true,
99265
99271
  userEmail,
99266
99272
  signingInTo: target.baseUrl,
99267
99273
  baseUrlSource: target.source,
99268
- ...describeSelectedWorkspace(),
99274
+ ...describeSelectedOrganization(),
99269
99275
  ...describeDrop(pin),
99270
99276
  note: "Signed in. Pass `project` to connect to one, or call listProjects to see what is available."
99271
99277
  });
@@ -99309,57 +99315,57 @@ async function runMcpServer(options) {
99309
99315
  }
99310
99316
  );
99311
99317
  server.registerTool(
99312
- "listWorkspaces",
99318
+ "listOrganizations",
99313
99319
  {
99314
- description: "List the Zoah workspaces you belong to (id, name, slug), and say which one this session is working in. A workspace holds projects; anything in another workspace is invisible until you switch, and reads as 'not found' rather than 'elsewhere'. Switch with connect({ workspace }).",
99320
+ description: "List the Zoah organizations you belong to (id, name, slug), and say which one this session is working in. An organization holds projects; anything in another organization is invisible until you switch, and reads as 'not found' rather than 'elsewhere'. Switch with connect({ organization }).",
99315
99321
  inputSchema: {}
99316
99322
  },
99317
99323
  async () => {
99318
99324
  try {
99319
- const { organizations, activeOrganizationId } = await (await currentApi()).listWorkspaces();
99325
+ const { organizations, activeOrganizationId } = await (await currentApi()).listOrganizations();
99320
99326
  return jsonResult({
99321
- workspaces: organizations.map((workspace) => ({
99322
- ...workspace,
99327
+ organizations: organizations.map((organization) => ({
99328
+ ...organization,
99323
99329
  // Two different meanings of "current", kept apart on purpose. The
99324
99330
  // human's stored selection decides where a call that names no
99325
- // workspace lands; this session's pin decides where THIS session
99331
+ // organization lands; this session's pin decides where THIS session
99326
99332
  // works. Collapsing them into one flag would hide which of the two
99327
99333
  // a caller is looking at.
99328
- active: workspace.id === activeOrganizationId,
99329
- workingHere: selectedWorkspace ? workspace.id === selectedWorkspace.workspaceId : workspace.id === activeOrganizationId
99334
+ active: organization.id === activeOrganizationId,
99335
+ workingHere: selectedOrganization ? organization.id === selectedOrganization.organizationId : organization.id === activeOrganizationId
99330
99336
  })),
99331
99337
  workingIn: describeWorkingIn(activeOrganizationId ?? void 0),
99332
99338
  ...organizations.length === 0 ? {
99333
- note: "This account belongs to no workspace yet. Call createWorkspace to make one. Projects live inside a workspace, so nothing else can be created first."
99339
+ note: "This account belongs to no organization yet. Call createOrganization to make one. Projects live inside an organization, so nothing else can be created first."
99334
99340
  } : {}
99335
99341
  });
99336
99342
  } catch (error) {
99337
99343
  return errorResult2(
99338
- `listWorkspaces failed: ${describeError2(error)}`
99344
+ `listOrganizations failed: ${describeError2(error)}`
99339
99345
  );
99340
99346
  }
99341
99347
  }
99342
99348
  );
99343
99349
  if (!options.readOnly) {
99344
99350
  server.registerTool(
99345
- "createWorkspace",
99351
+ "createOrganization",
99346
99352
  {
99347
- description: "Create a new Zoah workspace and work in it. A workspace holds projects, so this is the first step on an account that has none. createProject needs a workspace to hold the project. This session switches to it, which drops any open session. Ask the human before creating one if they may already have a workspace you have not looked at: call listWorkspaces first.",
99353
+ description: "Create a new Zoah organization and work in it. An organization holds projects, so this is the first step on an account that has none. createProject needs an organization to hold the project. This session switches to it, which drops any open session. Ask the human before creating one if they may already have an organization you have not looked at: call listOrganizations first.",
99348
99354
  inputSchema: {
99349
99355
  name: z57.string().describe(
99350
- 'Name for the workspace, e.g. "Acme Design". The slug is derived from it server-side.'
99356
+ 'Name for the organization, e.g. "Acme Design". The slug is derived from it server-side.'
99351
99357
  )
99352
99358
  }
99353
99359
  },
99354
99360
  async ({ name }) => {
99355
99361
  try {
99356
- const created = await (await currentApi()).createWorkspace(name);
99357
- const dropped = await endSessionForWorkspaceChange({
99358
- workspaceId: created.id,
99362
+ const created = await (await currentApi()).createOrganization(name);
99363
+ const dropped = await endSessionForOrganizationChange({
99364
+ organizationId: created.id,
99359
99365
  slug: created.slug
99360
99366
  });
99361
- selectedWorkspace = {
99362
- workspaceId: created.id,
99367
+ selectedOrganization = {
99368
+ organizationId: created.id,
99363
99369
  name: created.name,
99364
99370
  slug: created.slug,
99365
99371
  role: "admin",
@@ -99367,23 +99373,23 @@ async function runMcpServer(options) {
99367
99373
  };
99368
99374
  applyRole("admin");
99369
99375
  return jsonResult({
99370
- workspace: {
99376
+ organization: {
99371
99377
  id: created.id,
99372
99378
  name: created.name,
99373
99379
  slug: created.slug
99374
99380
  },
99375
99381
  workingHere: true,
99376
99382
  ...describeDrop({ droppedSession: dropped }),
99377
- ...created.becameActiveWorkspace ? {
99378
- becameActiveWorkspace: true,
99379
- note: "This account had no workspace, so this one is now its default - the app will open onto it. Create a project with createProject, then call connect to start work."
99383
+ ...created.becameActiveOrganization ? {
99384
+ becameActiveOrganization: true,
99385
+ note: "This account had no organization, so this one is now its default - the app will open onto it. Create a project with createProject, then call connect to start work."
99380
99386
  } : {
99381
- note: "Created and selected for this session. The human's own default workspace is unchanged. Create a project with createProject, then call connect to start work."
99387
+ note: "Created and selected for this session. The human's own default organization is unchanged. Create a project with createProject, then call connect to start work."
99382
99388
  }
99383
99389
  });
99384
99390
  } catch (error) {
99385
99391
  return errorResult2(
99386
- `createWorkspace failed: ${describeError2(error)}`
99392
+ `createOrganization failed: ${describeError2(error)}`
99387
99393
  );
99388
99394
  }
99389
99395
  }
@@ -99392,14 +99398,14 @@ async function runMcpServer(options) {
99392
99398
  server.registerTool(
99393
99399
  "listProjects",
99394
99400
  {
99395
- description: "List the projects in the Zoah workspace this session is working in (id, name, slug), and name that workspace. Call this before connect to discover what you can connect to. Connect accepts the slug, the name, or the id. Call listWorkspaces to work elsewhere.",
99401
+ description: "List the projects in the Zoah organization this session is working in (id, name, slug), and name that organization. Call this before connect to discover what you can connect to. Connect accepts the slug, the name, or the id. Call listOrganizations to work elsewhere.",
99396
99402
  inputSchema: {}
99397
99403
  },
99398
99404
  async () => {
99399
99405
  try {
99400
- const result = await workspaceListing();
99406
+ const result = await organizationListing();
99401
99407
  return jsonResult({
99402
- workspace: result.workspace ?? { id: result.orgId },
99408
+ organization: result.organization ?? { id: result.orgId },
99403
99409
  orgId: result.orgId,
99404
99410
  projects: result.projects.map(({ id, name, slug }) => ({
99405
99411
  id,
@@ -99407,7 +99413,7 @@ async function runMcpServer(options) {
99407
99413
  slug
99408
99414
  })),
99409
99415
  ...result.projects.length === 0 ? {
99410
- note: "This workspace has no projects. Call createProject, then connect to it."
99416
+ note: "This organization has no projects. Call createProject, then connect to it."
99411
99417
  } : {}
99412
99418
  });
99413
99419
  } catch (error) {
@@ -99421,14 +99427,14 @@ async function runMcpServer(options) {
99421
99427
  const roleGatedTool = server.registerTool(
99422
99428
  "createProject",
99423
99429
  {
99424
- description: "Create a new project in this session's workspace. The new project becomes this session's target. Call connect to open a branch in it.",
99430
+ description: "Create a new project in this session's organization. The new project becomes this session's target. Call connect to open a branch in it.",
99425
99431
  inputSchema: {
99426
99432
  name: z57.string().describe('Name for the new project, e.g. "Marketing Site"')
99427
99433
  }
99428
99434
  },
99429
99435
  async ({ name }) => {
99430
99436
  try {
99431
- const executed = await runWorkspaceVerb("createProject", {
99437
+ const executed = await runOrganizationVerb("createProject", {
99432
99438
  name,
99433
99439
  kind: "app"
99434
99440
  });
@@ -99438,7 +99444,7 @@ async function runMcpServer(options) {
99438
99444
  );
99439
99445
  }
99440
99446
  const { project: created } = executed.data;
99441
- await teardownWorkspaceClient();
99447
+ await teardownOrganizationClient();
99442
99448
  return jsonResult({
99443
99449
  id: created.id,
99444
99450
  name: created.name,
@@ -99480,7 +99486,7 @@ async function runMcpServer(options) {
99480
99486
  credentialBaseUrl: who.baseUrl,
99481
99487
  credentialExpired: health.expired,
99482
99488
  credentialExpiresInSeconds: health.expiresInSeconds,
99483
- ...describeSelectedWorkspace(),
99489
+ ...describeSelectedOrganization(),
99484
99490
  ...session ? {
99485
99491
  session: {
99486
99492
  projectId: session.projectId,
@@ -99520,8 +99526,8 @@ async function runMcpServer(options) {
99520
99526
  await teardownSession();
99521
99527
  sessionEndedBy = `signing out removed ${outcome.removedPath}, the credential this session's token was minted from`;
99522
99528
  }
99523
- selectedWorkspace = null;
99524
- ambientWorkspace = null;
99529
+ selectedOrganization = null;
99530
+ ambientOrganization = null;
99525
99531
  return jsonResult({
99526
99532
  removed: true,
99527
99533
  removedPath: outcome.removedPath,
@@ -99602,7 +99608,7 @@ async function runMcpServer(options) {
99602
99608
  try {
99603
99609
  if (s5.role === "read") {
99604
99610
  throw new Error(
99605
- "this workspace role is read-only. NOTHING was written."
99611
+ "this organization role is read-only. NOTHING was written."
99606
99612
  );
99607
99613
  }
99608
99614
  if (await awaitLiveSocket(s5) === "down") {
@@ -99762,7 +99768,7 @@ async function runMcpServer(options) {
99762
99768
  const roleGatedTool = server.registerTool(
99763
99769
  "updateProject",
99764
99770
  {
99765
- description: "Rename a project in this session's workspace. Name the project by id or by its exact current name. This tool only changes the name.",
99771
+ description: "Rename a project in this session's organization. Name the project by id or by its exact current name. This tool only changes the name.",
99766
99772
  inputSchema: {
99767
99773
  projectRef: z57.string().describe(
99768
99774
  "The project to rename: its id, or its exact current name. Call listProjects to see what is there."
@@ -99772,7 +99778,7 @@ async function runMcpServer(options) {
99772
99778
  },
99773
99779
  async ({ projectRef, name }) => {
99774
99780
  try {
99775
- const executed = await runWorkspaceVerb("updateProject", {
99781
+ const executed = await runOrganizationVerb("updateProject", {
99776
99782
  projectRef,
99777
99783
  name
99778
99784
  });
@@ -99854,7 +99860,7 @@ async function runMcpServer(options) {
99854
99860
  try {
99855
99861
  if (s5.role === "read") {
99856
99862
  throw new Error(
99857
- "this workspace role is read-only. NOTHING was written."
99863
+ "this organization role is read-only. NOTHING was written."
99858
99864
  );
99859
99865
  }
99860
99866
  if (await awaitLiveSocket(s5) === "down") {
@@ -100023,7 +100029,7 @@ async function runMcpServer(options) {
100023
100029
  // that move together, so it read `false` while a live localhost
100024
100030
  // session was addressing production.
100025
100031
  sessionInstance: session.baseUrl,
100026
- workspace: describeWorkingIn(session.orgId),
100032
+ organization: describeWorkingIn(session.orgId),
100027
100033
  baseUrlMismatch: stripSlash(baseUrl) !== session.baseUrl,
100028
100034
  ...moved ? { instanceMovedWarning: moved } : {},
100029
100035
  bufferedEvents: session.events.length,
@@ -100037,9 +100043,9 @@ async function runMcpServer(options) {
100037
100043
  credentialExpiringSoon: health.expiringSoon,
100038
100044
  cliTokenExpiresAt,
100039
100045
  cliTokenExpiresInSeconds: health.expiresInSeconds,
100040
- // The workspace pin survives a disconnect: it is a session
100046
+ // The organization pin survives a disconnect: it is a session
100041
100047
  // choice, not a property of the socket.
100042
- ...describeSelectedWorkspace(),
100048
+ ...describeSelectedOrganization(),
100043
100049
  baseUrl,
100044
100050
  credentialBaseUrl: creds.baseUrl,
100045
100051
  // A real comparison, not a constant. This was hard-coded `false`
@@ -100130,7 +100136,7 @@ async function runMcpServer(options) {
100130
100136
  if (def3.mutates) trackRoleGatedTool(tool);
100131
100137
  }
100132
100138
  for (const def3 of OPAQUE_ACTIONS) {
100133
- if (isWorkspaceActionType(def3.type)) continue;
100139
+ if (isOrganizationActionType(def3.type)) continue;
100134
100140
  if (SESSION_WRAPPED_VERBS.has(def3.type)) continue;
100135
100141
  if (!canServeCatalogAction(def3, options.readOnly === true)) continue;
100136
100142
  registerCatalogVerb(def3);
@@ -100548,7 +100554,7 @@ init_login();
100548
100554
  init_logout();
100549
100555
  import { Command } from "commander";
100550
100556
 
100551
- // src/commands/workspace.ts
100557
+ // src/commands/organization.ts
100552
100558
  init_client();
100553
100559
  init_session();
100554
100560
  async function client(opts) {
@@ -100561,27 +100567,27 @@ async function client(opts) {
100561
100567
  found.creds.baseUrl ?? opts.baseUrl
100562
100568
  );
100563
100569
  }
100564
- async function runWorkspaceList(opts) {
100565
- const { organizations } = await (await client(opts)).listWorkspaces();
100570
+ async function runOrganizationList(opts) {
100571
+ const { organizations } = await (await client(opts)).listOrganizations();
100566
100572
  if (organizations.length === 0) {
100567
100573
  console.log(
100568
- "No workspaces. Create one with `zoah workspace create <name>`."
100574
+ "No organizations. Create one with `zoah organization create <name>`."
100569
100575
  );
100570
100576
  return;
100571
100577
  }
100572
- for (const workspace of organizations) {
100578
+ for (const organization of organizations) {
100573
100579
  console.log(
100574
- `${workspace.active ? "*" : " "} ${workspace.slug ?? workspace.id} ${workspace.name}`
100580
+ `${organization.active ? "*" : " "} ${organization.slug ?? organization.id} ${organization.name}`
100575
100581
  );
100576
100582
  }
100577
- console.log("\n* = the workspace a command with no workspace uses.");
100583
+ console.log("\n* = the organization a command with no organization uses.");
100578
100584
  }
100579
- async function runWorkspaceCreate(opts) {
100580
- const created = await (await client(opts)).createWorkspace(opts.name);
100581
- console.log(`Created workspace "${created.name}" (${created.slug}).`);
100582
- if (created.becameActiveWorkspace) {
100585
+ async function runOrganizationCreate(opts) {
100586
+ const created = await (await client(opts)).createOrganization(opts.name);
100587
+ console.log(`Created organization "${created.name}" (${created.slug}).`);
100588
+ if (created.becameActiveOrganization) {
100583
100589
  console.log(
100584
- "This account had no workspace, so this one is now its default."
100590
+ "This account had no organization, so this one is now its default."
100585
100591
  );
100586
100592
  }
100587
100593
  console.log(
@@ -101594,12 +101600,12 @@ async function main() {
101594
101600
  fail(err);
101595
101601
  }
101596
101602
  });
101597
- const workspace = program.command("workspace").description(
101598
- "Workspaces: the outermost scope, holding this account's projects."
101603
+ const organization = program.command("organization").description(
101604
+ "Organizations: the outermost scope, holding this account's projects."
101599
101605
  );
101600
- workspace.command("list").description("List the workspaces this account belongs to.").action(async () => {
101606
+ organization.command("list").description("List the organizations this account belongs to.").action(async () => {
101601
101607
  try {
101602
- await runWorkspaceList({
101608
+ await runOrganizationList({
101603
101609
  cwd: process.cwd(),
101604
101610
  baseUrl: program.opts().baseUrl ?? DEFAULT_BASE_URL
101605
101611
  });
@@ -101607,9 +101613,9 @@ async function main() {
101607
101613
  fail(err);
101608
101614
  }
101609
101615
  });
101610
- workspace.command("create").argument("<name>", 'Workspace name, e.g. "Acme Design"').description("Create a workspace. The slug is derived from the name.").action(async (name) => {
101616
+ organization.command("create").argument("<name>", 'Organization name, e.g. "Acme Design"').description("Create an organization. The slug is derived from the name.").action(async (name) => {
101611
101617
  try {
101612
- await runWorkspaceCreate({
101618
+ await runOrganizationCreate({
101613
101619
  name,
101614
101620
  cwd: process.cwd(),
101615
101621
  baseUrl: program.opts().baseUrl ?? DEFAULT_BASE_URL
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zoahhq/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Zoah CLI: import React components, publish via Zoah, swap local imports",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Zoah Inc.",
@@ -41,8 +41,8 @@
41
41
  "tsup": "^8.3.5",
42
42
  "typescript": "^5.8.3",
43
43
  "vitest": "^2.1.8",
44
- "@opacityapp/opaque": "0.0.1",
45
- "@opacityapp/shared": "0.1.0"
44
+ "@opacityapp/shared": "0.1.0",
45
+ "@opacityapp/opaque": "0.0.1"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "tsup",