@qawolf/cli 1.24.0 → 1.25.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.
@@ -5494,9 +5494,34 @@ var bigintProcessor = (_schema, ctx, _json, _params) => {
5494
5494
  throw new Error("BigInt cannot be represented in JSON Schema");
5495
5495
  }
5496
5496
  };
5497
+ var symbolProcessor = (_schema, ctx, _json, _params) => {
5498
+ if (ctx.unrepresentable === "throw") {
5499
+ throw new Error("Symbols cannot be represented in JSON Schema");
5500
+ }
5501
+ };
5502
+ var nullProcessor = (_schema, ctx, json, _params) => {
5503
+ if (ctx.target === "openapi-3.0") {
5504
+ json.type = "string";
5505
+ json.nullable = true;
5506
+ json.enum = [null];
5507
+ } else {
5508
+ json.type = "null";
5509
+ }
5510
+ };
5511
+ var undefinedProcessor = (_schema, ctx, _json, _params) => {
5512
+ if (ctx.unrepresentable === "throw") {
5513
+ throw new Error("Undefined cannot be represented in JSON Schema");
5514
+ }
5515
+ };
5516
+ var voidProcessor = (_schema, ctx, _json, _params) => {
5517
+ if (ctx.unrepresentable === "throw") {
5518
+ throw new Error("Void cannot be represented in JSON Schema");
5519
+ }
5520
+ };
5497
5521
  var neverProcessor = (_schema, _ctx, json, _params) => {
5498
5522
  json.not = {};
5499
5523
  };
5524
+ var anyProcessor = (_schema, _ctx, _json, _params) => {};
5500
5525
  var unknownProcessor = (_schema, _ctx, _json, _params) => {};
5501
5526
  var dateProcessor = (_schema, ctx, _json, _params) => {
5502
5527
  if (ctx.unrepresentable === "throw") {
@@ -5550,16 +5575,71 @@ var literalProcessor = (schema, ctx, json, _params) => {
5550
5575
  json.enum = vals;
5551
5576
  }
5552
5577
  };
5578
+ var nanProcessor = (_schema, ctx, _json, _params) => {
5579
+ if (ctx.unrepresentable === "throw") {
5580
+ throw new Error("NaN cannot be represented in JSON Schema");
5581
+ }
5582
+ };
5583
+ var templateLiteralProcessor = (schema, _ctx, json, _params) => {
5584
+ const _json = json;
5585
+ const pattern = schema._zod.pattern;
5586
+ if (!pattern)
5587
+ throw new Error("Pattern not found in template literal");
5588
+ _json.type = "string";
5589
+ _json.pattern = pattern.source;
5590
+ };
5591
+ var fileProcessor = (schema, _ctx, json, _params) => {
5592
+ const _json = json;
5593
+ const file = {
5594
+ type: "string",
5595
+ format: "binary",
5596
+ contentEncoding: "binary"
5597
+ };
5598
+ const { minimum, maximum, mime } = schema._zod.bag;
5599
+ if (minimum !== undefined)
5600
+ file.minLength = minimum;
5601
+ if (maximum !== undefined)
5602
+ file.maxLength = maximum;
5603
+ if (mime) {
5604
+ if (mime.length === 1) {
5605
+ file.contentMediaType = mime[0];
5606
+ Object.assign(_json, file);
5607
+ } else {
5608
+ Object.assign(_json, file);
5609
+ _json.anyOf = mime.map((m) => ({ contentMediaType: m }));
5610
+ }
5611
+ } else {
5612
+ Object.assign(_json, file);
5613
+ }
5614
+ };
5615
+ var successProcessor = (_schema, _ctx, json, _params) => {
5616
+ json.type = "boolean";
5617
+ };
5553
5618
  var customProcessor = (_schema, ctx, _json, _params) => {
5554
5619
  if (ctx.unrepresentable === "throw") {
5555
5620
  throw new Error("Custom types cannot be represented in JSON Schema");
5556
5621
  }
5557
5622
  };
5623
+ var functionProcessor = (_schema, ctx, _json, _params) => {
5624
+ if (ctx.unrepresentable === "throw") {
5625
+ throw new Error("Function types cannot be represented in JSON Schema");
5626
+ }
5627
+ };
5558
5628
  var transformProcessor = (_schema, ctx, _json, _params) => {
5559
5629
  if (ctx.unrepresentable === "throw") {
5560
5630
  throw new Error("Transforms cannot be represented in JSON Schema");
5561
5631
  }
5562
5632
  };
5633
+ var mapProcessor = (_schema, ctx, _json, _params) => {
5634
+ if (ctx.unrepresentable === "throw") {
5635
+ throw new Error("Map cannot be represented in JSON Schema");
5636
+ }
5637
+ };
5638
+ var setProcessor = (_schema, ctx, _json, _params) => {
5639
+ if (ctx.unrepresentable === "throw") {
5640
+ throw new Error("Set cannot be represented in JSON Schema");
5641
+ }
5642
+ };
5563
5643
  var arrayProcessor = (schema, ctx, _json, params) => {
5564
5644
  const json = _json;
5565
5645
  const def = schema._zod.def;
@@ -5640,6 +5720,48 @@ var intersectionProcessor = (schema, ctx, json, params) => {
5640
5720
  ];
5641
5721
  json.allOf = allOf;
5642
5722
  };
5723
+ var tupleProcessor = (schema, ctx, _json, params) => {
5724
+ const json = _json;
5725
+ const def = schema._zod.def;
5726
+ json.type = "array";
5727
+ const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
5728
+ const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
5729
+ const prefixItems = def.items.map((x, i) => process2(x, ctx, {
5730
+ ...params,
5731
+ path: [...params.path, prefixPath, i]
5732
+ }));
5733
+ const rest = def.rest ? process2(def.rest, ctx, {
5734
+ ...params,
5735
+ path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
5736
+ }) : null;
5737
+ if (ctx.target === "draft-2020-12") {
5738
+ json.prefixItems = prefixItems;
5739
+ if (rest) {
5740
+ json.items = rest;
5741
+ }
5742
+ } else if (ctx.target === "openapi-3.0") {
5743
+ json.items = {
5744
+ anyOf: prefixItems
5745
+ };
5746
+ if (rest) {
5747
+ json.items.anyOf.push(rest);
5748
+ }
5749
+ json.minItems = prefixItems.length;
5750
+ if (!rest) {
5751
+ json.maxItems = prefixItems.length;
5752
+ }
5753
+ } else {
5754
+ json.items = prefixItems;
5755
+ if (rest) {
5756
+ json.additionalItems = rest;
5757
+ }
5758
+ }
5759
+ const { minimum, maximum } = schema._zod.bag;
5760
+ if (typeof minimum === "number")
5761
+ json.minItems = minimum;
5762
+ if (typeof maximum === "number")
5763
+ json.maxItems = maximum;
5764
+ };
5643
5765
  var recordProcessor = (schema, ctx, _json, params) => {
5644
5766
  const json = _json;
5645
5767
  const def = schema._zod.def;
@@ -5736,6 +5858,12 @@ var readonlyProcessor = (schema, ctx, json, params) => {
5736
5858
  seen.ref = def.innerType;
5737
5859
  json.readOnly = true;
5738
5860
  };
5861
+ var promiseProcessor = (schema, ctx, _json, params) => {
5862
+ const def = schema._zod.def;
5863
+ process2(def.innerType, ctx, params);
5864
+ const seen = ctx.seen.get(schema);
5865
+ seen.ref = def.innerType;
5866
+ };
5739
5867
  var optionalProcessor = (schema, ctx, _json, params) => {
5740
5868
  const def = schema._zod.def;
5741
5869
  process2(def.innerType, ctx, params);
@@ -5748,6 +5876,81 @@ var lazyProcessor = (schema, ctx, _json, params) => {
5748
5876
  const seen = ctx.seen.get(schema);
5749
5877
  seen.ref = innerType;
5750
5878
  };
5879
+ var allProcessors = {
5880
+ string: stringProcessor,
5881
+ number: numberProcessor,
5882
+ boolean: booleanProcessor,
5883
+ bigint: bigintProcessor,
5884
+ symbol: symbolProcessor,
5885
+ null: nullProcessor,
5886
+ undefined: undefinedProcessor,
5887
+ void: voidProcessor,
5888
+ never: neverProcessor,
5889
+ any: anyProcessor,
5890
+ unknown: unknownProcessor,
5891
+ date: dateProcessor,
5892
+ enum: enumProcessor,
5893
+ literal: literalProcessor,
5894
+ nan: nanProcessor,
5895
+ template_literal: templateLiteralProcessor,
5896
+ file: fileProcessor,
5897
+ success: successProcessor,
5898
+ custom: customProcessor,
5899
+ function: functionProcessor,
5900
+ transform: transformProcessor,
5901
+ map: mapProcessor,
5902
+ set: setProcessor,
5903
+ array: arrayProcessor,
5904
+ object: objectProcessor,
5905
+ union: unionProcessor,
5906
+ intersection: intersectionProcessor,
5907
+ tuple: tupleProcessor,
5908
+ record: recordProcessor,
5909
+ nullable: nullableProcessor,
5910
+ nonoptional: nonoptionalProcessor,
5911
+ default: defaultProcessor,
5912
+ prefault: prefaultProcessor,
5913
+ catch: catchProcessor,
5914
+ pipe: pipeProcessor,
5915
+ readonly: readonlyProcessor,
5916
+ promise: promiseProcessor,
5917
+ optional: optionalProcessor,
5918
+ lazy: lazyProcessor
5919
+ };
5920
+ function toJSONSchema(input, params) {
5921
+ if ("_idmap" in input) {
5922
+ const registry = input;
5923
+ const ctx = initializeContext({ ...params, processors: allProcessors });
5924
+ const defs = {};
5925
+ for (const entry of registry._idmap.entries()) {
5926
+ const [_, schema] = entry;
5927
+ process2(schema, ctx);
5928
+ }
5929
+ const schemas = {};
5930
+ const external = {
5931
+ registry,
5932
+ uri: params?.uri,
5933
+ defs
5934
+ };
5935
+ ctx.external = external;
5936
+ for (const entry of registry._idmap.entries()) {
5937
+ const [key, schema] = entry;
5938
+ extractDefs(ctx, schema);
5939
+ schemas[key] = finalize(ctx, schema);
5940
+ }
5941
+ if (Object.keys(defs).length > 0) {
5942
+ const defsSegment = ctx.target === "draft-2020-12" ? "$defs" : "definitions";
5943
+ schemas.__shared = {
5944
+ [defsSegment]: defs
5945
+ };
5946
+ }
5947
+ return { schemas };
5948
+ }
5949
+ const ctx = initializeContext({ ...params, processors: allProcessors });
5950
+ process2(input, ctx);
5951
+ extractDefs(ctx, input);
5952
+ return finalize(ctx, input);
5953
+ }
5751
5954
  // node_modules/zod/v4/classic/iso.js
5752
5955
  var exports_iso = {};
5753
5956
  __export(exports_iso, {
@@ -6833,6 +7036,10 @@ var identityResponse = union([
6833
7036
  user: never().optional()
6834
7037
  }).transform(({ organization }) => ({ organization }))
6835
7038
  ]);
7039
+ // node_modules/@qawolf/api-contracts/dist/v1/identity/organizations.js
7040
+ var identityOrganizationsResponse = object({
7041
+ organizations: array(identityOrganization)
7042
+ });
6836
7043
  // node_modules/@qawolf/api-contracts/dist/v1/ids.js
6837
7044
  var defaultIdSchemas = {
6838
7045
  aiTask: string2().min(1).describe("The id of the AI task."),
@@ -8537,11 +8744,82 @@ var makeContractsV1 = (ids) => {
8537
8744
  };
8538
8745
  var publicContractsV1 = makeContractsV1(defaultIdSchemas);
8539
8746
 
8747
+ // src/core/pluralize.ts
8748
+ function pluralize(count, singular, plural = `${singular}s`) {
8749
+ return `${String(count)} ${count === 1 ? singular : plural}`;
8750
+ }
8751
+
8540
8752
  // src/core/formatSeconds.ts
8541
8753
  function formatSeconds(ms) {
8542
8754
  return `${Math.round(ms / 1000)}s`;
8543
8755
  }
8544
8756
 
8757
+ // src/core/messages/authErrors.ts
8758
+ var authErrorMessages = {
8759
+ identity: {
8760
+ invalidOrUnauthorized: "API key is invalid or unauthorized",
8761
+ unexpectedFormat: "Could not verify API key: unexpected response format",
8762
+ couldNotVerify: (detail, status) => `Could not verify API key: ${detail || `HTTP ${status}`}`,
8763
+ couldNotVerifyNetwork: (cause) => `Could not verify API key: ${cause}`,
8764
+ timedOut: (timeoutMs) => `Could not verify API key: the QA Wolf API did not answer within ${formatSeconds(timeoutMs)}.`
8765
+ },
8766
+ request: {
8767
+ rejected401: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 401). Check your API key.`,
8768
+ rejected402: (noun) => `QA Wolf API refused the${noun ? ` ${noun}` : ""} request (HTTP 402): billing prevented it.`,
8769
+ rejected403: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 403). Check that your API key has access to this environment.`,
8770
+ notFound404: (noun) => `QA Wolf API could not find ${noun ? `${noun} for that environment` : "that environment"} (HTTP 404). Check the --env value.`,
8771
+ failedWithStatus: (status, noun) => `QA Wolf API${noun ? ` ${noun}` : ""} request failed (HTTP ${status}).`,
8772
+ networkUnreachable: (baseUrl, noun) => `Could not reach the QA Wolf API at ${baseUrl}${noun ? ` to fetch ${noun}` : ""}. Check your network connection and QAWOLF_HOST_URL.`,
8773
+ timedOut: (timeoutMs, noun) => `The QA Wolf API${noun ? ` ${noun}` : ""} request timed out after ${formatSeconds(timeoutMs)}. The work may still be finishing on the platform.`,
8774
+ unexpectedResponse: (noun) => `Unexpected${noun ? ` ${noun}` : ""} response from the QA Wolf API.`
8775
+ },
8776
+ workos: {
8777
+ unexpectedResponse: "WorkOS returned an unexpected response",
8778
+ unexpectedResponseWithStatus: (status) => `WorkOS returned an unexpected response (HTTP ${status})`,
8779
+ unreachable: (detail) => `Could not reach WorkOS: ${detail}`,
8780
+ redirected: "WorkOS answered with a redirect, which the CLI does not follow for a sign-in request",
8781
+ noClientForSession: "This session names no WorkOS client"
8782
+ },
8783
+ bundle: {
8784
+ linkExpired: "The flow bundle download link has expired. Please run `qawolf flows pull` again to refresh.",
8785
+ failedWithStatus: (status) => `Could not download the flow bundle (HTTP ${status}).`,
8786
+ networkUnreachable: "Could not reach the flow bundle storage. Check your network connection and try again.",
8787
+ timedOut: (timeoutMs) => `Downloading the flow bundle stalled — no data arrived for ${formatSeconds(timeoutMs)}. Please try again.`,
8788
+ malformed: "The flow bundle download was malformed. Please run `qawolf flows pull` again."
8789
+ }
8790
+ };
8791
+
8792
+ // src/core/messages/whoami.ts
8793
+ var whoamiMessages = {
8794
+ source: (source) => `Source: ${source}`,
8795
+ authFailed: (source, error) => `Authentication failed (source: ${source}): ${error}`,
8796
+ authenticatedAs: (teamName, source) => `Authenticated as ${teamName} (source: ${source})`,
8797
+ teamNote: (input) => [
8798
+ `Workspace: ${input.team.name}`,
8799
+ `ID: ${input.team.id}`,
8800
+ input.team.slug ? `Slug: ${input.team.slug}` : undefined,
8801
+ input.teamUrl ? `URL: ${input.teamUrl}` : undefined,
8802
+ `Source: ${input.source}`
8803
+ ].filter((line) => Boolean(line)).join(`
8804
+ `),
8805
+ organizationNote: (input) => [
8806
+ `Organization: ${input.organization.name}`,
8807
+ `ID: ${input.organization.id}`,
8808
+ `Source: ${input.source}`
8809
+ ].join(`
8810
+ `),
8811
+ activeWorkspace: (workspaceId, found) => found ? `${found.workspace} (${found.organization})` : `${workspaceId} — no longer in reach; run 'qawolf auth switch'`,
8812
+ userNote: (input) => [
8813
+ `User: ${input.user.email}`,
8814
+ `ID: ${input.user.id}`,
8815
+ `Organization: ${input.organization.name}`,
8816
+ input.activeWorkspace ? `Workspace: ${input.activeWorkspace}` : undefined,
8817
+ input.organizations.length > 0 ? `Workspaces: ${input.organizations.map((o) => `${o.name}: ${o.workspaces.map((w) => w.name).join(", ")}`).join(" | ")}` : undefined,
8818
+ `Source: ${input.source}`
8819
+ ].filter((line) => Boolean(line)).join(`
8820
+ `)
8821
+ };
8822
+
8545
8823
  // src/core/messages/auth.ts
8546
8824
  var authMessages = {
8547
8825
  title: "QA Wolf Authentication",
@@ -8559,7 +8837,47 @@ var authMessages = {
8559
8837
  whoamiFailed: "Not authenticated",
8560
8838
  login: {
8561
8839
  nonInteractive: "auth login requires an interactive terminal. Set the QAWOLF_API_KEY environment variable for CI authentication.",
8562
- reAuthPrompt: "You are already authenticated. Re-authenticate?"
8840
+ reAuthPrompt: "You are already authenticated. Re-authenticate?",
8841
+ chooseMethod: "How do you want to sign in?",
8842
+ methodBrowser: "Browser",
8843
+ methodBrowserHint: "Sign in with your QA Wolf account",
8844
+ methodApiKey: "API key",
8845
+ methodApiKeyHint: "Paste a team key — needed for flows pull and flows run",
8846
+ apiKeyPrecedence: {
8847
+ env: "QAWOLF_API_KEY is set, and an API key takes precedence over a browser session. Commands continue to use that key until you unset the variable.",
8848
+ stored: "A stored API key takes precedence over a browser session. Commands continue to use that key until you run 'qawolf auth logout' and sign in again."
8849
+ }
8850
+ },
8851
+ device: {
8852
+ unavailable: "This QA Wolf deployment does not offer browser sign-in. Run 'qawolf auth login' again and choose 'API key'.",
8853
+ configUnreachable: "Could not ask this QA Wolf deployment whether it offers browser sign-in. Check your connection, then try again.",
8854
+ confirmCode: (userCode) => `Your code is ${userCode}`,
8855
+ visitUrl: (url) => `Confirm it at ${url}`,
8856
+ visitUrlPlain: (url) => `Or go to ${url} and enter the code`,
8857
+ openFailed: (url) => `Could not open a browser automatically. Open ${url} yourself to continue.`,
8858
+ waiting: "Waiting for you to finish in the browser",
8859
+ signedIn: (email) => `Signed in as ${email}.`,
8860
+ failed: {
8861
+ "access-denied": "The sign-in request was rejected.",
8862
+ expired: "The sign-in request expired. Run 'qawolf auth login' to retry.",
8863
+ timeout: "The sign-in request timed out. Run 'qawolf auth login' to retry.",
8864
+ network: "Could not reach WorkOS to complete sign-in.",
8865
+ unavailable: "Could not start browser sign-in.",
8866
+ cancelled: "Sign-in cancelled."
8867
+ }
8868
+ },
8869
+ workspace: {
8870
+ chooseOrganization: "Which organization do you want to work in?",
8871
+ choose: "Which workspace do you want to use?",
8872
+ workspaceCount: (count) => pluralize(count, "workspace"),
8873
+ working: (organization, workspace) => `Working in ${workspace} (${organization}).`,
8874
+ none: "This account reaches no organizations yet.",
8875
+ cancelled: "Workspace not changed.",
8876
+ notSignedIn: "Workspace switching needs a browser sign-in. Run 'qawolf auth login' and choose Browser.",
8877
+ sessionExpired: "Your session could not be renewed. Run 'qawolf auth login' to sign in again.",
8878
+ nonInteractive: "auth switch needs an interactive terminal, or set QAWOLF_WORKSPACE to name a workspace.",
8879
+ sessionChanged: "The stored sign-in changed while you made your choice. Run the command again.",
8880
+ saveFailed: (detail) => `Could not save the workspace choice: ${detail}`
8563
8881
  },
8564
8882
  logout: {
8565
8883
  title: "Log Out",
@@ -8571,58 +8889,8 @@ var authMessages = {
8571
8889
  success: "Logged out successfully.",
8572
8890
  cancelled: "Logout cancelled."
8573
8891
  },
8574
- errors: {
8575
- identity: {
8576
- invalidOrUnauthorized: "API key is invalid or unauthorized",
8577
- unexpectedFormat: "Could not verify API key: unexpected response format",
8578
- couldNotVerify: (detail, status) => `Could not verify API key: ${detail || `HTTP ${status}`}`,
8579
- couldNotVerifyNetwork: (cause) => `Could not verify API key: ${cause}`,
8580
- timedOut: (timeoutMs) => `Could not verify API key: the QA Wolf API did not answer within ${formatSeconds(timeoutMs)}.`
8581
- },
8582
- request: {
8583
- rejected401: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 401). Check your API key.`,
8584
- rejected402: (noun) => `QA Wolf API refused the${noun ? ` ${noun}` : ""} request (HTTP 402): billing prevented it.`,
8585
- rejected403: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 403). Check that your API key has access to this environment.`,
8586
- notFound404: (noun) => `QA Wolf API could not find ${noun ? `${noun} for that environment` : "that environment"} (HTTP 404). Check the --env value.`,
8587
- failedWithStatus: (status, noun) => `QA Wolf API${noun ? ` ${noun}` : ""} request failed (HTTP ${status}).`,
8588
- networkUnreachable: (baseUrl, noun) => `Could not reach the QA Wolf API at ${baseUrl}${noun ? ` to fetch ${noun}` : ""}. Check your network connection and QAWOLF_HOST_URL.`,
8589
- timedOut: (timeoutMs, noun) => `The QA Wolf API${noun ? ` ${noun}` : ""} request timed out after ${formatSeconds(timeoutMs)}. The work may still be finishing on the platform.`,
8590
- unexpectedResponse: (noun) => `Unexpected${noun ? ` ${noun}` : ""} response from the QA Wolf API.`
8591
- },
8592
- bundle: {
8593
- linkExpired: "The flow bundle download link has expired. Please run `qawolf flows pull` again to refresh.",
8594
- failedWithStatus: (status) => `Could not download the flow bundle (HTTP ${status}).`,
8595
- networkUnreachable: "Could not reach the flow bundle storage. Check your network connection and try again.",
8596
- timedOut: (timeoutMs) => `Downloading the flow bundle stalled — no data arrived for ${formatSeconds(timeoutMs)}. Please try again.`,
8597
- malformed: "The flow bundle download was malformed. Please run `qawolf flows pull` again."
8598
- }
8599
- },
8600
- whoami: {
8601
- source: (source) => `Source: ${source}`,
8602
- authFailed: (source, error) => `Authentication failed (source: ${source}): ${error}`,
8603
- authenticatedAs: (teamName, source) => `Authenticated as ${teamName} (source: ${source})`,
8604
- teamNote: (input) => [
8605
- `Team: ${input.team.name}`,
8606
- `ID: ${input.team.id}`,
8607
- input.team.slug ? `Slug: ${input.team.slug}` : undefined,
8608
- input.teamUrl ? `URL: ${input.teamUrl}` : undefined,
8609
- `Source: ${input.source}`
8610
- ].filter((line) => Boolean(line)).join(`
8611
- `),
8612
- organizationNote: (input) => [
8613
- `Organization: ${input.organization.name}`,
8614
- `ID: ${input.organization.id}`,
8615
- `Source: ${input.source}`
8616
- ].join(`
8617
- `),
8618
- userNote: (input) => [
8619
- `User: ${input.user.email}`,
8620
- `ID: ${input.user.id}`,
8621
- `Organization: ${input.organization.name}`,
8622
- `Source: ${input.source}`
8623
- ].join(`
8624
- `)
8625
- }
8892
+ errors: authErrorMessages,
8893
+ whoami: whoamiMessages
8626
8894
  };
8627
8895
  // src/core/messages/toolNotFound.ts
8628
8896
  var installRemedy = "Run `qawolf install` to install the runtime dependencies.";
@@ -8638,11 +8906,6 @@ ${installRemedy}`;
8638
8906
  function packageLoadFailed(pkg, envDir, detail) {
8639
8907
  return toolNotRunnable(`Could not load ${pkg} from ${envDir}`, detail);
8640
8908
  }
8641
- // src/core/pluralize.ts
8642
- function pluralize(count, singular, plural = `${singular}s`) {
8643
- return `${String(count)} ${count === 1 ? singular : plural}`;
8644
- }
8645
-
8646
8909
  // src/core/messages/flows.ts
8647
8910
  var flowsMessages = {
8648
8911
  title: "Flows",
@@ -10365,6 +10628,176 @@ function makeDefaultFs() {
10365
10628
  };
10366
10629
  }
10367
10630
 
10631
+ // src/core/publicApi/flagKind.ts
10632
+ function flagKind(schema) {
10633
+ if (schema.type === "string")
10634
+ return { ok: true, kind: "string" };
10635
+ if (schema.type === "number" || schema.type === "integer") {
10636
+ return { ok: true, kind: "number" };
10637
+ }
10638
+ if (schema.type === "boolean")
10639
+ return { ok: true, kind: "boolean" };
10640
+ if (schema.type === "array") {
10641
+ if (schema.items?.type !== "string") {
10642
+ return {
10643
+ ok: false,
10644
+ reason: "only string arrays can be expressed as flags"
10645
+ };
10646
+ }
10647
+ return { ok: true, kind: "string-array" };
10648
+ }
10649
+ if (schema.type === "object") {
10650
+ if (schema.properties) {
10651
+ return {
10652
+ ok: false,
10653
+ reason: "nested objects cannot be expressed as flags"
10654
+ };
10655
+ }
10656
+ if (typeof schema.additionalProperties === "object" && schema.additionalProperties.type === "string") {
10657
+ return { ok: true, kind: "key-value-record" };
10658
+ }
10659
+ return { ok: false, reason: "nested objects cannot be expressed as flags" };
10660
+ }
10661
+ return {
10662
+ ok: false,
10663
+ reason: `type ${schema.type ?? "unknown"} cannot be expressed as a flag`
10664
+ };
10665
+ }
10666
+
10667
+ // src/core/publicApi/objectShape.ts
10668
+ var asObjectShape = (schema) => schema.type === "object" && schema.properties ? { properties: schema.properties, required: new Set(schema.required) } : undefined;
10669
+ function mergeIntersection(members) {
10670
+ const shape = { properties: {}, required: new Set };
10671
+ for (const member of members) {
10672
+ const memberShape = asObjectShape(member);
10673
+ if (!memberShape) {
10674
+ return {
10675
+ ok: false,
10676
+ field: "",
10677
+ reason: "intersection members must be object schemas"
10678
+ };
10679
+ }
10680
+ for (const [field, fieldSchema] of Object.entries(memberShape.properties)) {
10681
+ if (field in shape.properties) {
10682
+ return {
10683
+ ok: false,
10684
+ field,
10685
+ reason: "field appears in multiple intersection members"
10686
+ };
10687
+ }
10688
+ shape.properties[field] = fieldSchema;
10689
+ if (memberShape.required.has(field))
10690
+ shape.required.add(field);
10691
+ }
10692
+ }
10693
+ return { ok: true, shape };
10694
+ }
10695
+ function mergeUnion(branches) {
10696
+ const shapes = [];
10697
+ for (const branch of branches) {
10698
+ const branchShape = asObjectShape(branch);
10699
+ if (!branchShape) {
10700
+ return {
10701
+ ok: false,
10702
+ field: "",
10703
+ reason: "union branches must be object schemas"
10704
+ };
10705
+ }
10706
+ shapes.push(branchShape);
10707
+ }
10708
+ const shape = { properties: {}, required: new Set };
10709
+ for (const branchShape of shapes) {
10710
+ for (const [field, fieldSchema] of Object.entries(branchShape.properties)) {
10711
+ const existing = shape.properties[field];
10712
+ if (!existing) {
10713
+ shape.properties[field] = { ...fieldSchema };
10714
+ continue;
10715
+ }
10716
+ const kinds = [flagKind(existing), flagKind(fieldSchema)];
10717
+ if (kinds[0]?.ok && kinds[1]?.ok) {
10718
+ if (kinds[0].kind !== kinds[1].kind) {
10719
+ return {
10720
+ ok: false,
10721
+ field,
10722
+ reason: "field has conflicting types across union branches"
10723
+ };
10724
+ }
10725
+ } else if (JSON.stringify({ ...existing, description: undefined }) !== JSON.stringify({ ...fieldSchema, description: undefined })) {
10726
+ return {
10727
+ ok: false,
10728
+ field,
10729
+ reason: "field has conflicting object schemas across union branches"
10730
+ };
10731
+ }
10732
+ if (!existing.description && fieldSchema.description) {
10733
+ existing.description = fieldSchema.description;
10734
+ }
10735
+ }
10736
+ }
10737
+ const discriminator = Object.keys(shape.properties).find((field) => {
10738
+ const values = shapes.map((branch) => branch.properties[field]?.const);
10739
+ return values.every((value) => typeof value === "string") && new Set(values).size === shapes.length && shapes.every((branch) => branch.required.has(field));
10740
+ });
10741
+ for (const [field, fieldSchema] of Object.entries(shape.properties)) {
10742
+ const occurrences = shapes.filter((branch) => (field in branch.properties));
10743
+ if (occurrences.length === shapes.length && occurrences.every((branch) => branch.required.has(field))) {
10744
+ shape.required.add(field);
10745
+ }
10746
+ if (field === discriminator) {
10747
+ const values = shapes.map((branch) => branch.properties[field]?.const);
10748
+ fieldSchema.description = `One of: ${values.join(", ")}`;
10749
+ }
10750
+ }
10751
+ return { ok: true, shape };
10752
+ }
10753
+ function toObjectShape(schema) {
10754
+ if (schema.allOf)
10755
+ return mergeIntersection(schema.allOf);
10756
+ const branches = schema.oneOf ?? schema.anyOf;
10757
+ if (branches)
10758
+ return mergeUnion(branches);
10759
+ const shape = asObjectShape(schema);
10760
+ if (shape)
10761
+ return { ok: true, shape };
10762
+ return {
10763
+ ok: false,
10764
+ field: "",
10765
+ reason: "contract input must be an object schema"
10766
+ };
10767
+ }
10768
+
10769
+ // src/shell/platform/applyWorkspaceId.ts
10770
+ var acceptsWorkspace = new WeakMap;
10771
+ function takesWorkspaceId(inputSchema) {
10772
+ const cached = acceptsWorkspace.get(inputSchema);
10773
+ if (cached !== undefined)
10774
+ return cached;
10775
+ let accepted = false;
10776
+ try {
10777
+ const jsonSchema = toJSONSchema(inputSchema, {
10778
+ io: "input"
10779
+ });
10780
+ const shape = toObjectShape(jsonSchema);
10781
+ accepted = shape.ok && "workspaceId" in shape.shape.properties;
10782
+ } catch {
10783
+ accepted = false;
10784
+ }
10785
+ acceptsWorkspace.set(inputSchema, accepted);
10786
+ return accepted;
10787
+ }
10788
+ function applyWorkspaceId(inputSchema, input, workspaceId) {
10789
+ if (!workspaceId)
10790
+ return input;
10791
+ if (typeof input !== "object" || input === null)
10792
+ return input;
10793
+ const existing = input.workspaceId;
10794
+ if (existing !== undefined)
10795
+ return input;
10796
+ if (!takesWorkspaceId(inputSchema))
10797
+ return input;
10798
+ return { ...input, workspaceId };
10799
+ }
10800
+
10368
10801
  // src/shell/platform/parseErrorBody.ts
10369
10802
  var defaultMaxLength = 1024;
10370
10803
  function asRecord(value) {
@@ -10497,7 +10930,7 @@ function callPublicApi(trpc, contract, input, options) {
10497
10930
  }
10498
10931
  function makeCallPublicApiMethod(trpc, deps, readBackoffMs) {
10499
10932
  return async (contract, input, options) => requestWithRetry({
10500
- call: () => callPublicApi(trpc, contract, input, options),
10933
+ call: () => callPublicApi(trpc, contract, applyWorkspaceId(contract.input, input, deps.workspaceId), options),
10501
10934
  backoffMs: contract.kind === "read" ? readBackoffMs : [],
10502
10935
  describe: (err) => describeRequestError(err, deps.baseUrl, contract.name),
10503
10936
  sleep: deps.sleep
@@ -11497,10 +11930,16 @@ async function downloadBundle(signedUrl, deps) {
11497
11930
  return { ok: true, value: { tmpArchive } };
11498
11931
  }
11499
11932
 
11500
- // src/shell/platform/getIdentity.ts
11933
+ // src/shell/platform/organizations.ts
11934
+ function parseOrganizationsResponse(json) {
11935
+ const parsed = identityOrganizationsResponse.safeParse(json);
11936
+ return parsed.success ? parsed.data.organizations : undefined;
11937
+ }
11938
+
11939
+ // src/shell/platform/getAccessibleOrganizations.ts
11501
11940
  var timeoutMs = 1e4;
11502
- async function getIdentity(apiKey, deps) {
11503
- const url = `${deps.baseUrl}/api/v0/identity`;
11941
+ async function getAccessibleOrganizations(apiKey, deps) {
11942
+ const url = `${deps.baseUrl}/api/v0/identity/organizations`;
11504
11943
  let response;
11505
11944
  try {
11506
11945
  response = await deps.fetch(url, {
@@ -11511,6 +11950,51 @@ async function getIdentity(apiKey, deps) {
11511
11950
  if (isTimeoutError(error)) {
11512
11951
  return { ok: false, error: { kind: "timeout", timeoutMs } };
11513
11952
  }
11953
+ return { ok: false, error: { kind: "network", cause: toError(error) } };
11954
+ }
11955
+ if (!response.ok) {
11956
+ const body = await response.text().catch(() => "");
11957
+ return {
11958
+ ok: false,
11959
+ error: { kind: "http", status: response.status, body }
11960
+ };
11961
+ }
11962
+ let json;
11963
+ try {
11964
+ json = await response.json();
11965
+ } catch (error) {
11966
+ if (isTimeoutError(error)) {
11967
+ return { ok: false, error: { kind: "timeout", timeoutMs } };
11968
+ }
11969
+ json = undefined;
11970
+ }
11971
+ const organizations = parseOrganizationsResponse(json);
11972
+ if (!organizations) {
11973
+ return {
11974
+ ok: false,
11975
+ error: {
11976
+ kind: "parse",
11977
+ cause: Error("organizations response did not match the contract")
11978
+ }
11979
+ };
11980
+ }
11981
+ return { ok: true, data: organizations };
11982
+ }
11983
+
11984
+ // src/shell/platform/getIdentity.ts
11985
+ var timeoutMs2 = 1e4;
11986
+ async function getIdentity(apiKey, deps) {
11987
+ const url = `${deps.baseUrl}/api/v0/identity`;
11988
+ let response;
11989
+ try {
11990
+ response = await deps.fetch(url, {
11991
+ headers: { Authorization: `Bearer ${apiKey}` },
11992
+ signal: AbortSignal.timeout(timeoutMs2)
11993
+ });
11994
+ } catch (error) {
11995
+ if (isTimeoutError(error)) {
11996
+ return { ok: false, error: { kind: "timeout", timeoutMs: timeoutMs2 } };
11997
+ }
11514
11998
  return {
11515
11999
  ok: false,
11516
12000
  error: { kind: "network", cause: toError(error) }
@@ -11528,7 +12012,7 @@ async function getIdentity(apiKey, deps) {
11528
12012
  json = await response.json();
11529
12013
  } catch (error) {
11530
12014
  if (isTimeoutError(error)) {
11531
- return { ok: false, error: { kind: "timeout", timeoutMs } };
12015
+ return { ok: false, error: { kind: "timeout", timeoutMs: timeoutMs2 } };
11532
12016
  }
11533
12017
  json = undefined;
11534
12018
  }
@@ -11539,6 +12023,24 @@ async function getIdentity(apiKey, deps) {
11539
12023
  return { ok: true, data: parsed.data };
11540
12024
  }
11541
12025
 
12026
+ // src/shell/platform/identityMethods.ts
12027
+ function createIdentityMethods(apiKey, deps, backoffMs) {
12028
+ return {
12029
+ getIdentity: () => requestWithRetry({
12030
+ call: () => getIdentity(apiKey, deps),
12031
+ backoffMs,
12032
+ describe: describeIdentityError,
12033
+ sleep: deps.sleep
12034
+ }),
12035
+ getAccessibleOrganizations: () => requestWithRetry({
12036
+ call: () => getAccessibleOrganizations(apiKey, deps),
12037
+ backoffMs,
12038
+ describe: describeIdentityError,
12039
+ sleep: deps.sleep
12040
+ })
12041
+ };
12042
+ }
12043
+
11542
12044
  // src/shell/platform/types.ts
11543
12045
  var environmentListItemSchema = object({
11544
12046
  envId: string2(),
@@ -11838,14 +12340,7 @@ function createPlatformClient(apiKey, deps) {
11838
12340
  return { ok: true, value: { signedUrl: result.value.url } };
11839
12341
  }
11840
12342
  return {
11841
- async getIdentity() {
11842
- return requestWithRetry({
11843
- call: () => getIdentity(apiKey, deps),
11844
- backoffMs: requestBackoffMs2,
11845
- describe: describeIdentityError,
11846
- sleep: deps.sleep
11847
- });
11848
- },
12343
+ ...createIdentityMethods(apiKey, deps, requestBackoffMs2),
11849
12344
  getFlowsBundleUrl: getFlowsBundleUrlImpl,
11850
12345
  callPublicApi: makeCallPublicApiMethod(trpc, deps, requestBackoffMs2),
11851
12346
  async getEnvVars(envId) {
@@ -12599,4 +13094,4 @@ export {
12599
13094
  createRunnerSdk
12600
13095
  };
12601
13096
 
12602
- //# debugId=231C026DA9D7E0DD64756E2164756E21
13097
+ //# debugId=DD6DEC33C9C6693F64756E2164756E21