@canaryai/cli 0.2.6 → 0.2.8

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.
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
2
  import {
3
3
  PlaywrightClient
4
- } from "./chunk-PDC425CK.js";
4
+ } from "./chunk-FK3EZADZ.js";
5
5
 
6
6
  // src/local-browser/host.ts
7
7
  var HEARTBEAT_INTERVAL_MS = 3e4;
@@ -370,4 +370,4 @@ var LocalBrowserHost = class {
370
370
  export {
371
371
  LocalBrowserHost
372
372
  };
373
- //# sourceMappingURL=chunk-RYCPA32L.js.map
373
+ //# sourceMappingURL=chunk-K2OB72B6.js.map
@@ -34,4 +34,4 @@ export {
34
34
  getSubDir,
35
35
  makeTempDirSync
36
36
  };
37
- //# sourceMappingURL=chunk-AHYNXUHF.js.map
37
+ //# sourceMappingURL=chunk-XAA5VQ5N.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../tmp/src/index.ts"],"sourcesContent":["/**\n * Canary Temp Directory Helpers\n *\n * Centralizes all temporary file/directory creation under a single\n * `/tmp/canary/` base directory. This ensures the cleanup daemon only\n * removes files we own, not OS or third-party temp entries.\n *\n * All public functions lazily ensure the base directory exists on first\n * use, so callers never need to worry about directory creation.\n *\n * @module tmp\n * @see packages/tmp/README.md\n */\n\nimport os from 'node:os';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { mkdir, mkdtemp } from 'node:fs/promises';\nimport { randomUUID } from 'node:crypto';\n\n/** Base directory for all canary temp files */\nconst CANARY_TMP_DIR = path.join(os.tmpdir(), 'canary');\n\n/** Restrictive permissions: owner-only access (rwx------) */\nconst DIR_MODE = 0o700;\n\n/**\n * Tracks whether the base directory has been created this process.\n * Once created, skip redundant mkdir calls.\n */\nlet dirEnsured = false;\n\nconst ensureSync = (): void => {\n if (dirEnsured) return;\n fs.mkdirSync(CANARY_TMP_DIR, { recursive: true, mode: DIR_MODE });\n dirEnsured = true;\n};\n\nconst ensureAsync = async (): Promise<void> => {\n if (dirEnsured) return;\n await mkdir(CANARY_TMP_DIR, { recursive: true, mode: DIR_MODE });\n dirEnsured = true;\n};\n\n/** Get the canary tmp base directory path (lazily ensures dir exists) */\nexport const getCanaryTmpDir = (): string => {\n ensureSync();\n return CANARY_TMP_DIR;\n};\n\n/** Ensure the canary base directory exists (async, idempotent) */\nexport const ensureCanaryTmpDir = async (): Promise<string> => {\n await ensureAsync();\n return CANARY_TMP_DIR;\n};\n\n/**\n * Get a named subdirectory under the canary tmp dir, creating it if needed.\n *\n * Accepts nested paths (e.g. `'workflow-runs/abc-123'`).\n *\n * @example\n * const dir = getSubDir('cache-agent');\n * // => '/tmp/canary/cache-agent' (created with 0o700 permissions)\n */\nexport const getSubDir = (name: string): string => {\n ensureSync();\n const dir = path.join(CANARY_TMP_DIR, name);\n fs.mkdirSync(dir, { recursive: true, mode: DIR_MODE });\n return dir;\n};\n\n/**\n * Async version of getSubDir. Prefer this in async contexts to avoid\n * blocking the event loop on first call.\n */\nexport const getSubDirAsync = async (name: string): Promise<string> => {\n await ensureAsync();\n const dir = path.join(CANARY_TMP_DIR, name);\n await mkdir(dir, { recursive: true, mode: DIR_MODE });\n return dir;\n};\n\n/** Create a temp directory under /tmp/canary/ with the given prefix */\nexport const makeTempDir = async (prefix: string): Promise<string> => {\n await ensureAsync();\n return mkdtemp(path.join(CANARY_TMP_DIR, prefix));\n};\n\n/** Synchronous version of makeTempDir */\nexport const makeTempDirSync = (prefix: string): string => {\n ensureSync();\n return fs.mkdtempSync(path.join(CANARY_TMP_DIR, prefix));\n};\n\n/** Generate a temp file path under /tmp/canary/ (ensures dir exists, does NOT create the file) */\nexport const getTempFilePath = (prefix: string, suffix: string = ''): string => {\n ensureSync();\n return path.join(CANARY_TMP_DIR, `${prefix}${randomUUID()}${suffix}`);\n};\n"],"mappings":";;;AAcA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,SAAS,OAAO,eAAe;AAC/B,SAAS,kBAAkB;AAG3B,IAAM,iBAAiB,KAAK,KAAK,GAAG,OAAO,GAAG,QAAQ;AAGtD,IAAM,WAAW;AAMjB,IAAI,aAAa;AAEjB,IAAM,aAAa,MAAY;AAC7B,MAAI,WAAY;AAChB,KAAG,UAAU,gBAAgB,EAAE,WAAW,MAAM,MAAM,SAAS,CAAC;AAChE,eAAa;AACf;AASO,IAAM,kBAAkB,MAAc;AAC3C,aAAW;AACX,SAAO;AACT;AAiBO,IAAM,YAAY,CAAC,SAAyB;AACjD,aAAW;AACX,QAAM,MAAM,KAAK,KAAK,gBAAgB,IAAI;AAC1C,KAAG,UAAU,KAAK,EAAE,WAAW,MAAM,MAAM,SAAS,CAAC;AACrD,SAAO;AACT;AAoBO,IAAM,kBAAkB,CAAC,WAA2B;AACzD,aAAW;AACX,SAAO,GAAG,YAAY,KAAK,KAAK,gBAAgB,MAAM,CAAC;AACzD;","names":[]}
1
+ {"version":3,"sources":["../../tmp/src/index.ts"],"sourcesContent":["/**\n * Canary Temp Directory Helpers\n *\n * Centralizes all temporary file/directory creation under a single\n * `/tmp/canary/` base directory. This ensures the cleanup daemon only\n * removes files we own, not OS or third-party temp entries.\n *\n * All public functions lazily ensure the base directory exists on first\n * use, so callers never need to worry about directory creation.\n *\n * @module tmp\n * @see packages/tmp/README.md\n */\n\nimport os from 'node:os';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { mkdir, mkdtemp } from 'node:fs/promises';\nimport { randomUUID } from 'node:crypto';\n\n/** Base directory for all canary temp files */\nconst CANARY_TMP_DIR = path.join(os.tmpdir(), 'canary');\n\n/** Restrictive permissions: owner-only access (rwx------) */\nconst DIR_MODE = 0o700;\n\n/**\n * Tracks whether the base directory has been created this process.\n * Once created, skip redundant mkdir calls.\n */\nlet dirEnsured = false;\n\nconst ensureSync = (): void => {\n if (dirEnsured) return;\n fs.mkdirSync(CANARY_TMP_DIR, { recursive: true, mode: DIR_MODE });\n dirEnsured = true;\n};\n\nconst ensureAsync = async (): Promise<void> => {\n if (dirEnsured) return;\n await mkdir(CANARY_TMP_DIR, { recursive: true, mode: DIR_MODE });\n dirEnsured = true;\n};\n\n/** Get the canary tmp base directory path (lazily ensures dir exists) */\nexport const getCanaryTmpDir = (): string => {\n ensureSync();\n return CANARY_TMP_DIR;\n};\n\n/** Ensure the canary base directory exists (async, idempotent) */\nexport const ensureCanaryTmpDir = async (): Promise<string> => {\n await ensureAsync();\n return CANARY_TMP_DIR;\n};\n\n/**\n * Get a named subdirectory under the canary tmp dir, creating it if needed.\n *\n * Accepts nested paths (e.g. `'workflow-runs/abc-123'`).\n *\n * @example\n * const dir = getSubDir('cache-agent');\n * // => '/tmp/canary/cache-agent' (created with 0o700 permissions)\n */\nexport const getSubDir = (name: string): string => {\n ensureSync();\n const dir = path.join(CANARY_TMP_DIR, name);\n fs.mkdirSync(dir, { recursive: true, mode: DIR_MODE });\n return dir;\n};\n\n/**\n * Async version of getSubDir. Prefer this in async contexts to avoid\n * blocking the event loop on first call.\n */\nexport const getSubDirAsync = async (name: string): Promise<string> => {\n await ensureAsync();\n const dir = path.join(CANARY_TMP_DIR, name);\n await mkdir(dir, { recursive: true, mode: DIR_MODE });\n return dir;\n};\n\n/** Create a temp directory under /tmp/canary/ with the given prefix */\nexport const makeTempDir = async (prefix: string): Promise<string> => {\n await ensureAsync();\n return mkdtemp(path.join(CANARY_TMP_DIR, prefix));\n};\n\n/** Synchronous version of makeTempDir */\nexport const makeTempDirSync = (prefix: string): string => {\n ensureSync();\n return fs.mkdtempSync(path.join(CANARY_TMP_DIR, prefix));\n};\n\n/** Generate a temp file path under /tmp/canary/ (ensures dir exists, does NOT create the file) */\nexport const getTempFilePath = (prefix: string, suffix: string = ''): string => {\n ensureSync();\n return path.join(CANARY_TMP_DIR, `${prefix}${randomUUID()}${suffix}`);\n};\n\n// ============================================================================\n// Org-scoped helpers — isolate temp files by organization ID\n// ============================================================================\n\n/** UUID v4 pattern — all orgIds in this codebase are UUIDs */\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** Validate orgId is a UUID to prevent path traversal */\nconst validateOrgId = (orgId: string): void => {\n if (!UUID_RE.test(orgId)) {\n throw new Error(`Invalid orgId for tmp path: expected UUID, got \"${orgId}\"`);\n }\n};\n\n/** Get the org-scoped tmp base directory: `/tmp/canary/{orgId}/` */\nexport const getOrgTmpDir = (orgId: string): string => {\n validateOrgId(orgId);\n ensureSync();\n const dir = path.join(CANARY_TMP_DIR, orgId);\n fs.mkdirSync(dir, { recursive: true, mode: DIR_MODE });\n return dir;\n};\n\n/** Get a named subdirectory under the org-scoped tmp dir, creating it synchronously. */\nexport const getOrgSubDir = (opts: { orgId: string; name: string }): string => {\n validateOrgId(opts.orgId);\n ensureSync();\n const dir = path.join(CANARY_TMP_DIR, opts.orgId, opts.name);\n fs.mkdirSync(dir, { recursive: true, mode: DIR_MODE });\n return dir;\n};\n\n/** Async version of getOrgSubDir. */\nexport const getOrgSubDirAsync = async (opts: { orgId: string; name: string }): Promise<string> => {\n validateOrgId(opts.orgId);\n await ensureAsync();\n const dir = path.join(CANARY_TMP_DIR, opts.orgId, opts.name);\n await mkdir(dir, { recursive: true, mode: DIR_MODE });\n return dir;\n};\n\n/** Create a temp directory under `/tmp/canary/{orgId}/` with the given prefix. */\nexport const makeOrgTempDir = async (opts: { orgId: string; prefix: string }): Promise<string> => {\n const base = getOrgTmpDir(opts.orgId);\n return mkdtemp(path.join(base, opts.prefix));\n};\n\n/** Synchronous version of makeOrgTempDir. */\nexport const makeOrgTempDirSync = (opts: { orgId: string; prefix: string }): string => {\n const base = getOrgTmpDir(opts.orgId);\n return fs.mkdtempSync(path.join(base, opts.prefix));\n};\n\n/** Generate a temp file path under `/tmp/canary/{orgId}/` (ensures dir exists, does NOT create the file). */\nexport const getOrgTempFilePath = (opts: { orgId: string; prefix: string; suffix?: string }): string => {\n const base = getOrgTmpDir(opts.orgId);\n return path.join(base, `${opts.prefix}${randomUUID()}${opts.suffix ?? ''}`);\n};\n"],"mappings":";;;AAcA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,SAAS,OAAO,eAAe;AAC/B,SAAS,kBAAkB;AAG3B,IAAM,iBAAiB,KAAK,KAAK,GAAG,OAAO,GAAG,QAAQ;AAGtD,IAAM,WAAW;AAMjB,IAAI,aAAa;AAEjB,IAAM,aAAa,MAAY;AAC7B,MAAI,WAAY;AAChB,KAAG,UAAU,gBAAgB,EAAE,WAAW,MAAM,MAAM,SAAS,CAAC;AAChE,eAAa;AACf;AASO,IAAM,kBAAkB,MAAc;AAC3C,aAAW;AACX,SAAO;AACT;AAiBO,IAAM,YAAY,CAAC,SAAyB;AACjD,aAAW;AACX,QAAM,MAAM,KAAK,KAAK,gBAAgB,IAAI;AAC1C,KAAG,UAAU,KAAK,EAAE,WAAW,MAAM,MAAM,SAAS,CAAC;AACrD,SAAO;AACT;AAoBO,IAAM,kBAAkB,CAAC,WAA2B;AACzD,aAAW;AACX,SAAO,GAAG,YAAY,KAAK,KAAK,gBAAgB,MAAM,CAAC;AACzD;","names":[]}
@@ -1,14 +1,14 @@
1
1
  import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
2
  import {
3
3
  LocalBrowserHost
4
- } from "./chunk-RYCPA32L.js";
4
+ } from "./chunk-K2OB72B6.js";
5
5
  import {
6
6
  getArgValue,
7
7
  hasFlag,
8
8
  resolveConfig
9
9
  } from "./chunk-PWWQGYFG.js";
10
- import "./chunk-PDC425CK.js";
11
- import "./chunk-AHYNXUHF.js";
10
+ import "./chunk-FK3EZADZ.js";
11
+ import "./chunk-XAA5VQ5N.js";
12
12
  import "./chunk-P5Z2Y5VV.js";
13
13
  import "./chunk-VKVL7WBN.js";
14
14
 
@@ -241,4 +241,4 @@ async function runDebugWorkflow(argv) {
241
241
  export {
242
242
  runDebugWorkflow
243
243
  };
244
- //# sourceMappingURL=debug-workflow-G5ZAZCYG.js.map
244
+ //# sourceMappingURL=debug-workflow-55G4Y6YT.js.map
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-PWWQGYFG.js";
11
11
  import {
12
12
  getSubDir
13
- } from "./chunk-AHYNXUHF.js";
13
+ } from "./chunk-XAA5VQ5N.js";
14
14
  import "./chunk-VKVL7WBN.js";
15
15
 
16
16
  // src/docs.ts
@@ -270,4 +270,4 @@ async function runDocs(argv) {
270
270
  export {
271
271
  runDocs
272
272
  };
273
- //# sourceMappingURL=docs-QLCF2LS6.js.map
273
+ //# sourceMappingURL=docs-RPFT7ZJB.js.map
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-PWWQGYFG.js";
20
20
  import {
21
21
  makeTempDirSync
22
- } from "./chunk-AHYNXUHF.js";
22
+ } from "./chunk-XAA5VQ5N.js";
23
23
  import {
24
24
  __require
25
25
  } from "./chunk-VKVL7WBN.js";
@@ -636,11 +636,84 @@ function formatFailedTests(failedTests, appUrl) {
636
636
  }
637
637
  return lines.join("\n");
638
638
  }
639
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
640
+ async function resolveTestConfig(apiUrl, token, propertyArg, environmentArg) {
641
+ if (!propertyArg && !environmentArg) return {};
642
+ const res = await fetch(`${apiUrl}/workflows/test-config`, {
643
+ headers: { Authorization: `Bearer ${token}` }
644
+ });
645
+ if (!res.ok) {
646
+ const text = await res.text();
647
+ throw new Error(`Failed to fetch test config: ${res.status} ${text}`);
648
+ }
649
+ const data = await res.json();
650
+ if (!data.ok || !data.properties) {
651
+ throw new Error(`Failed to fetch test config: ${data.error ?? "Unknown error"}`);
652
+ }
653
+ const { properties } = data;
654
+ let property;
655
+ if (propertyArg) {
656
+ if (UUID_RE.test(propertyArg)) {
657
+ property = properties.find((p) => p.id === propertyArg);
658
+ } else {
659
+ property = properties.find(
660
+ (p) => p.name.toLowerCase() === propertyArg.toLowerCase()
661
+ );
662
+ }
663
+ if (!property) {
664
+ const available = properties.map((p) => ` - ${p.name} (${p.id})`).join("\n");
665
+ throw new Error(
666
+ `Property "${propertyArg}" not found.
667
+ Available properties:
668
+ ${available}`
669
+ );
670
+ }
671
+ } else if (environmentArg) {
672
+ if (properties.length === 0) {
673
+ throw new Error("No properties found in your organization.");
674
+ }
675
+ if (properties.length > 1) {
676
+ const available = properties.map((p) => ` - ${p.name} (${p.id})`).join("\n");
677
+ throw new Error(
678
+ `--environment requires --property when multiple properties exist.
679
+ Available properties:
680
+ ${available}`
681
+ );
682
+ }
683
+ property = properties[0];
684
+ }
685
+ const result = {};
686
+ if (property) {
687
+ result.propertyId = property.id;
688
+ if (environmentArg) {
689
+ let env;
690
+ if (UUID_RE.test(environmentArg)) {
691
+ env = property.environments.find((e) => e.id === environmentArg);
692
+ } else {
693
+ env = property.environments.find(
694
+ (e) => e.name.toLowerCase() === environmentArg.toLowerCase()
695
+ );
696
+ }
697
+ if (!env) {
698
+ const available = property.environments.map((e) => ` - ${e.name}${e.isDefault ? " (default)" : ""} (${e.id})`).join("\n");
699
+ throw new Error(
700
+ `Environment "${environmentArg}" not found for property "${property.name}".
701
+ Available environments:
702
+ ${available}`
703
+ );
704
+ }
705
+ result.environmentId = env.id;
706
+ }
707
+ }
708
+ return result;
709
+ }
639
710
  async function runRemoteTest(argv) {
640
711
  const apiUrl = getArgValue3(argv, "--api-url") ?? process5.env.CANARY_API_URL ?? "https://api.trycanary.ai";
641
712
  const token = getArgValue3(argv, "--token") ?? process5.env.CANARY_API_TOKEN ?? await readStoredToken();
642
713
  const tag = getArgValue3(argv, "--tag");
643
714
  const namePattern = getArgValue3(argv, "--name-pattern");
715
+ const propertyArg = getArgValue3(argv, "--property");
716
+ const environmentArg = getArgValue3(argv, "--environment");
644
717
  const verbose = hasFlag2(argv, "--verbose", "-v");
645
718
  if (!token) {
646
719
  console.error("Error: No API token found.");
@@ -652,7 +725,18 @@ async function runRemoteTest(argv) {
652
725
  console.error(" canary test --remote --token cnry_...");
653
726
  process5.exit(1);
654
727
  }
728
+ let resolvedConfig = {};
729
+ if (propertyArg || environmentArg) {
730
+ try {
731
+ resolvedConfig = await resolveTestConfig(apiUrl, token, propertyArg, environmentArg);
732
+ } catch (err) {
733
+ console.error(`${err instanceof Error ? err.message : String(err)}`);
734
+ process5.exit(1);
735
+ }
736
+ }
655
737
  console.log("Starting remote workflow tests...");
738
+ if (resolvedConfig.propertyId) console.log(` Property: ${propertyArg}`);
739
+ if (resolvedConfig.environmentId) console.log(` Environment: ${environmentArg}`);
656
740
  if (tag) console.log(` Filtering by tag: ${tag}`);
657
741
  if (namePattern) console.log(` Filtering by name pattern: ${namePattern}`);
658
742
  console.log("");
@@ -660,6 +744,9 @@ async function runRemoteTest(argv) {
660
744
  if (tag) queryParams.set("tag", tag);
661
745
  if (namePattern) queryParams.set("namePattern", namePattern);
662
746
  const triggerUrl = `${apiUrl}/workflows/test-runs${queryParams.toString() ? `?${queryParams}` : ""}`;
747
+ const body = {};
748
+ if (resolvedConfig.propertyId) body.propertyId = resolvedConfig.propertyId;
749
+ if (resolvedConfig.environmentId) body.environmentId = resolvedConfig.environmentId;
663
750
  let triggerRes;
664
751
  try {
665
752
  triggerRes = await fetch(triggerUrl, {
@@ -667,7 +754,8 @@ async function runRemoteTest(argv) {
667
754
  headers: {
668
755
  Authorization: `Bearer ${token}`,
669
756
  "Content-Type": "application/json"
670
- }
757
+ },
758
+ body: JSON.stringify(body)
671
759
  });
672
760
  } catch (err) {
673
761
  console.error(`Failed to connect to API: ${err}`);
@@ -912,10 +1000,10 @@ function isSuperadminToken(token) {
912
1000
  // src/index.ts
913
1001
  var require2 = createRequire2(import.meta.url);
914
1002
  var pkg = require2("../package.json");
915
- var loadMcp = () => import("./mcp-Q666YHHT.js").then((m) => m.runMcp);
916
- var loadLocalBrowser = () => import("./local-browser-5ZVPHF5H.js").then((m) => m.runLocalBrowser);
917
- var loadDebugWorkflow = () => import("./debug-workflow-G5ZAZCYG.js").then((m) => m.runDebugWorkflow);
918
- var loadRecord = () => import("./record-W5QERB5Z.js").then((m) => m.runRecord);
1003
+ var loadMcp = () => import("./mcp-4JVLADZL.js").then((m) => m.runMcp);
1004
+ var loadLocalBrowser = () => import("./local-browser-X7J27IGS.js").then((m) => m.runLocalBrowser);
1005
+ var loadDebugWorkflow = () => import("./debug-workflow-55G4Y6YT.js").then((m) => m.runDebugWorkflow);
1006
+ var loadRecord = () => import("./record-4OX7HXWQ.js").then((m) => m.runRecord);
919
1007
  var canary = { run };
920
1008
  var baseDir = typeof __dirname !== "undefined" ? __dirname : path4.dirname(fileURLToPath2(import.meta.url));
921
1009
  var preloadPath = path4.join(baseDir, "runner", "preload.js");
@@ -982,6 +1070,8 @@ function printHelp({ isSuperadmin }) {
982
1070
  "Remote test options:",
983
1071
  " --token <key> API key (or set CANARY_API_TOKEN)",
984
1072
  " --api-url <url> API URL (default: https://api.trycanary.ai)",
1073
+ " --property <name|id> Target a specific property",
1074
+ " --environment <name|id> Target a specific environment",
985
1075
  " --tag <tag> Filter workflows by tag",
986
1076
  " --name-pattern <pat> Filter workflows by name pattern",
987
1077
  " --verbose, -v Show all events",
@@ -1096,6 +1186,8 @@ function printTestHelp() {
1096
1186
  " --remote Run tests remotely (required)",
1097
1187
  " --token <key> API key (or set CANARY_API_TOKEN)",
1098
1188
  " --api-url <url> API URL (default: https://api.trycanary.ai)",
1189
+ " --property <name|id> Target a specific property",
1190
+ " --environment <name|id> Target a specific environment",
1099
1191
  " --tag <tag> Filter workflows by tag",
1100
1192
  " --name-pattern <pat> Filter workflows by name pattern",
1101
1193
  " --verbose, -v Show all events",
@@ -1104,7 +1196,8 @@ function printTestHelp() {
1104
1196
  " canary test Run all local tests",
1105
1197
  ' canary test --grep "login" Run tests matching "login"',
1106
1198
  " canary test --headed --workers 1 Debug with visible browser",
1107
- " canary test --remote --tag smoke Run remote smoke tests"
1199
+ " canary test --remote --tag smoke Run remote smoke tests",
1200
+ ' canary test --remote --property "My App" --environment staging'
1108
1201
  ].join("\n")
1109
1202
  );
1110
1203
  }
@@ -1207,7 +1300,7 @@ async function main(argv) {
1207
1300
  return;
1208
1301
  }
1209
1302
  if (command === "docs") {
1210
- const { runDocs } = await import("./docs-QLCF2LS6.js");
1303
+ const { runDocs } = await import("./docs-RPFT7ZJB.js");
1211
1304
  await runDocs(rest);
1212
1305
  return;
1213
1306
  }