@workflow-code/cli 0.2.2-20260826002 → 0.2.3-20260901001

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,12 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- __commonJS,
4
- __toESM,
3
+ clearCliAuthConfig,
4
+ isWorkflowAuthExpiringSoon,
5
+ readCliAuthConfig,
6
+ readCliAuthConfigSync,
7
+ writeCliAuthConfig
8
+ } from "./chunk-PGM3IPWA.js";
9
+ import {
10
+ prepareCliInvocation
11
+ } from "./chunk-DPFPLLLT.js";
12
+ import {
13
+ isWorkflowUuid,
14
+ readWorkflowProjectInfo,
15
+ resolveWorkflowRelatedProjectAccess
16
+ } from "./chunk-27OW6OJ3.js";
17
+ import {
5
18
  getCurrentLocale,
6
19
  i18n,
7
- prepareCliInvocation,
8
20
  translateWorkflowCodeError
9
- } from "./chunk-2DNWG5WR.js";
21
+ } from "./chunk-TCYG46PO.js";
22
+ import {
23
+ __commonJS,
24
+ __toESM
25
+ } from "./chunk-NSPRIPOP.js";
10
26
 
11
27
  // node_modules/.pnpm/ignore@7.0.6/node_modules/ignore/index.js
12
28
  var require_ignore = __commonJS({
@@ -307,7 +323,7 @@ var require_ignore = __commonJS({
307
323
  // path matching.
308
324
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
309
325
  // @returns {TestResult} true if a file is ignored
310
- test(path5, checkUnignored, mode) {
326
+ test(path4, checkUnignored, mode) {
311
327
  let ignored = false;
312
328
  let unignored = false;
313
329
  let matchedRule;
@@ -316,7 +332,7 @@ var require_ignore = __commonJS({
316
332
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
317
333
  return;
318
334
  }
319
- const matched = rule[mode].test(path5);
335
+ const matched = rule[mode].test(path4);
320
336
  if (!matched) {
321
337
  return;
322
338
  }
@@ -337,17 +353,17 @@ var require_ignore = __commonJS({
337
353
  var throwError = (message, Ctor) => {
338
354
  throw new Ctor(message);
339
355
  };
340
- var checkPath = (path5, originalPath, doThrow) => {
341
- if (!isString(path5)) {
356
+ var checkPath = (path4, originalPath, doThrow) => {
357
+ if (!isString(path4)) {
342
358
  return doThrow(
343
359
  `path must be a string, but got \`${originalPath}\``,
344
360
  TypeError
345
361
  );
346
362
  }
347
- if (!path5) {
363
+ if (!path4) {
348
364
  return doThrow(`path must not be empty`, TypeError);
349
365
  }
350
- if (checkPath.isNotRelative(path5)) {
366
+ if (checkPath.isNotRelative(path4)) {
351
367
  const r = "`path.relative()`d";
352
368
  return doThrow(
353
369
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -356,7 +372,7 @@ var require_ignore = __commonJS({
356
372
  }
357
373
  return true;
358
374
  };
359
- var isNotRelative = (path5) => REGEX_TEST_INVALID_PATH.test(path5);
375
+ var isNotRelative = (path4) => REGEX_TEST_INVALID_PATH.test(path4);
360
376
  checkPath.isNotRelative = isNotRelative;
361
377
  checkPath.convert = (p) => p;
362
378
  var Ignore = class {
@@ -386,19 +402,19 @@ var require_ignore = __commonJS({
386
402
  }
387
403
  // @returns {TestResult}
388
404
  _test(originalPath, cache, checkUnignored, slices) {
389
- const path5 = originalPath && checkPath.convert(originalPath);
405
+ const path4 = originalPath && checkPath.convert(originalPath);
390
406
  checkPath(
391
- path5,
407
+ path4,
392
408
  originalPath,
393
409
  this._strictPathCheck ? throwError : RETURN_FALSE
394
410
  );
395
- return this._t(path5, cache, checkUnignored, slices);
411
+ return this._t(path4, cache, checkUnignored, slices);
396
412
  }
397
- checkIgnore(path5) {
398
- if (!REGEX_TEST_TRAILING_SLASH.test(path5)) {
399
- return this.test(path5);
413
+ checkIgnore(path4) {
414
+ if (!REGEX_TEST_TRAILING_SLASH.test(path4)) {
415
+ return this.test(path4);
400
416
  }
401
- const slices = path5.split(SLASH).filter(Boolean);
417
+ const slices = path4.split(SLASH).filter(Boolean);
402
418
  slices.pop();
403
419
  if (slices.length) {
404
420
  const parent = this._t(
@@ -411,18 +427,18 @@ var require_ignore = __commonJS({
411
427
  return parent;
412
428
  }
413
429
  }
414
- return this._rules.test(path5, false, MODE_CHECK_IGNORE);
430
+ return this._rules.test(path4, false, MODE_CHECK_IGNORE);
415
431
  }
416
- _t(path5, cache, checkUnignored, slices) {
417
- if (path5 in cache) {
418
- return cache[path5];
432
+ _t(path4, cache, checkUnignored, slices) {
433
+ if (path4 in cache) {
434
+ return cache[path4];
419
435
  }
420
436
  if (!slices) {
421
- slices = path5.split(SLASH).filter(Boolean);
437
+ slices = path4.split(SLASH).filter(Boolean);
422
438
  }
423
439
  slices.pop();
424
440
  if (!slices.length) {
425
- return cache[path5] = this._rules.test(path5, checkUnignored, MODE_IGNORE);
441
+ return cache[path4] = this._rules.test(path4, checkUnignored, MODE_IGNORE);
426
442
  }
427
443
  const parent = this._t(
428
444
  slices.join(SLASH) + SLASH,
@@ -430,29 +446,29 @@ var require_ignore = __commonJS({
430
446
  checkUnignored,
431
447
  slices
432
448
  );
433
- return cache[path5] = parent.ignored ? parent : this._rules.test(path5, checkUnignored, MODE_IGNORE);
449
+ return cache[path4] = parent.ignored ? parent : this._rules.test(path4, checkUnignored, MODE_IGNORE);
434
450
  }
435
- ignores(path5) {
436
- return this._test(path5, this._ignoreCache, false).ignored;
451
+ ignores(path4) {
452
+ return this._test(path4, this._ignoreCache, false).ignored;
437
453
  }
438
454
  createFilter() {
439
- return (path5) => !this.ignores(path5);
455
+ return (path4) => !this.ignores(path4);
440
456
  }
441
457
  filter(paths) {
442
458
  return makeArray(paths).filter(this.createFilter());
443
459
  }
444
460
  // @returns {TestResult}
445
- test(path5) {
446
- return this._test(path5, this._testCache, true);
461
+ test(path4) {
462
+ return this._test(path4, this._testCache, true);
447
463
  }
448
464
  };
449
465
  var factory = (options) => new Ignore(options);
450
- var isPathValid = (path5) => checkPath(path5 && checkPath.convert(path5), path5, RETURN_FALSE);
466
+ var isPathValid = (path4) => checkPath(path4 && checkPath.convert(path4), path4, RETURN_FALSE);
451
467
  var setupWindows = () => {
452
468
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
453
469
  checkPath.convert = makePosix;
454
470
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
455
- checkPath.isNotRelative = (path5) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path5) || isNotRelative(path5);
471
+ checkPath.isNotRelative = (path4) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path4) || isNotRelative(path4);
456
472
  };
457
473
  if (
458
474
  // Detect `process` so that it can run in browsers.
@@ -471,122 +487,10 @@ var require_ignore = __commonJS({
471
487
  import { spawn } from "child_process";
472
488
  import { createHash, randomUUID } from "crypto";
473
489
  import { existsSync as existsSync2 } from "fs";
474
- import { copyFile as copyFile2, mkdir as mkdir3, readFile as readFile3, readdir as readdir2, rename, rm as rm2, writeFile as writeFile2 } from "fs/promises";
475
- import path4 from "path";
490
+ import { copyFile as copyFile2, mkdir as mkdir2, readFile as readFile2, readdir as readdir2, rename, rm, writeFile } from "fs/promises";
491
+ import path3 from "path";
476
492
  import { fileURLToPath, pathToFileURL } from "url";
477
493
 
478
- // .shared/auth-config/index.ts
479
- var WORKFLOW_AUTH_FILE_NAME = "workflow-auth.json";
480
- var DEFAULT_MAC_PLATFORM = "darwin";
481
- var DEFAULT_WINDOWS_PLATFORM = "win32";
482
- var DEFAULT_OTHER_PLATFORM = "linux";
483
- function createEmptyWorkflowAuthConfig() {
484
- return {
485
- serverUrl: "",
486
- apiKey: ""
487
- };
488
- }
489
- function normalizeWorkflowAuthConfig(value) {
490
- if (!isRecord(value)) {
491
- return createEmptyWorkflowAuthConfig();
492
- }
493
- return {
494
- // Accept legacy field names (remoteUrl, token) from pre-migration
495
- // config files so existing users don't lose their credentials on upgrade.
496
- serverUrl: readString(value.serverUrl) ?? readString(value.remoteUrl) ?? "",
497
- apiKey: readString(value.apiKey) ?? readString(value.token) ?? "",
498
- expiresAt: readString(value.expiresAt),
499
- user: isRecord(value.user) ? {
500
- userId: readString(value.user.userId) ?? "",
501
- email: readString(value.user.email) ?? "",
502
- displayName: readString(value.user.displayName) ?? "",
503
- avatarUrl: readString(value.user.avatarUrl)
504
- } : void 0,
505
- source: value.source === "device_flow" || value.source === "manual" || value.source === "password" ? value.source : void 0
506
- };
507
- }
508
- function isWorkflowAuthExpiringSoon(expiresAt, options = {}) {
509
- if (!expiresAt) {
510
- return false;
511
- }
512
- const expiresAtMs = new Date(expiresAt).getTime();
513
- if (!Number.isFinite(expiresAtMs)) {
514
- return false;
515
- }
516
- const now = options.now ?? Date.now();
517
- const thresholdMs = options.thresholdMs ?? 1e3 * 60 * 60 * 24 * 3;
518
- return expiresAtMs - now <= thresholdMs;
519
- }
520
- function resolveWorkflowCliAuthDir(env = readProcessEnv()) {
521
- if (readString(env.WORKFLOW_CLI_AUTH_DIR)) {
522
- return normalizePath(env.WORKFLOW_CLI_AUTH_DIR);
523
- }
524
- if (readPlatform(env) === DEFAULT_WINDOWS_PLATFORM) {
525
- return joinPath(
526
- env.APPDATA ?? joinPath(resolveHomeDir(env), "AppData", "Roaming"),
527
- "workflow-code"
528
- );
529
- }
530
- if (readPlatform(env) === DEFAULT_MAC_PLATFORM) {
531
- return joinPath(resolveHomeDir(env), "Library", "Application Support", "workflow-code");
532
- }
533
- return joinPath(
534
- env.XDG_CONFIG_HOME ?? joinPath(resolveHomeDir(env), ".config"),
535
- "workflow-code"
536
- );
537
- }
538
- function resolveWorkflowCliAuthFilePath(env = readProcessEnv()) {
539
- return joinPath(resolveWorkflowCliAuthDir(env), WORKFLOW_AUTH_FILE_NAME);
540
- }
541
- function resolveHomeDir(env) {
542
- return env.HOME ?? "";
543
- }
544
- function readPlatform(env) {
545
- return env.platform ?? readProcessPlatform();
546
- }
547
- function isRecord(value) {
548
- return typeof value === "object" && value !== null;
549
- }
550
- function readString(value) {
551
- return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
552
- }
553
- function joinPath(...parts) {
554
- return normalizePath(parts.filter((part) => part !== "").join("/"));
555
- }
556
- function normalizePath(value) {
557
- const normalized = value.replaceAll("\\", "/");
558
- if (/^[A-Za-z]:\//.test(normalized)) {
559
- const drive = normalized.slice(0, 2);
560
- const rest = normalized.slice(2).replace(/\/+/g, "/");
561
- return `${drive}${rest.startsWith("/") ? rest : `/${rest}`}`;
562
- }
563
- return normalized.replace(/\/+/g, "/");
564
- }
565
- function readProcessEnv() {
566
- const processValue = readGlobalProcess();
567
- return {
568
- ...processValue?.env ?? {},
569
- platform: processValue?.platform ?? DEFAULT_OTHER_PLATFORM
570
- };
571
- }
572
- function readProcessPlatform() {
573
- return readGlobalProcess()?.platform ?? DEFAULT_OTHER_PLATFORM;
574
- }
575
- function readGlobalProcess() {
576
- const processValue = Reflect.get(globalThis, "process");
577
- if (typeof processValue !== "object" || processValue === null) {
578
- return void 0;
579
- }
580
- return processValue;
581
- }
582
-
583
- // .shared/workflow-ids/index.ts
584
- import path from "path";
585
- var WORKFLOW_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
586
- function isWorkflowUuid(value) {
587
- return WORKFLOW_UUID_PATTERN.test(value.trim());
588
- }
589
-
590
494
  // .shared/project-types/index.ts
591
495
  var WORKFLOW_PROJECT_TYPE_DEFINITIONS = [
592
496
  {
@@ -633,7 +537,7 @@ function mapNodePlatformToWorkflowDesktopPlatform(platform) {
633
537
 
634
538
  // .shared/project-upload/node.ts
635
539
  import { copyFile, lstat, mkdir, readFile, readdir } from "fs/promises";
636
- import path2 from "path";
540
+ import path from "path";
637
541
 
638
542
  // .shared/project-upload/index.ts
639
543
  var import_ignore = __toESM(require_ignore(), 1);
@@ -642,29 +546,29 @@ var import_ignore = __toESM(require_ignore(), 1);
642
546
  var KANBAN_MANIFEST_FILE = "kanban.json";
643
547
  var KANBAN_ENTRY_FILE = "index.html";
644
548
  var KANBAN_ARTIFACT_DIR = ".";
645
- var KANBAN_DATA_SOURCE_ID_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
646
- var KANBAN_WORKFLOW_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
647
- var MAX_KANBAN_DATA_SOURCES = 32;
648
- var MAX_KANBAN_DATA_SOURCE_PREFIXES = 32;
649
- var MAX_KANBAN_DATA_SOURCE_KEY_LENGTH = 1024;
650
549
  function readPackageProjectType(value) {
651
- if (!isRecord2(value)) return void 0;
550
+ if (!isRecord(value)) return void 0;
652
551
  const workflowCode = value["workflowCode"];
653
- if (!isRecord2(workflowCode)) return void 0;
552
+ if (!isRecord(workflowCode)) return void 0;
654
553
  return workflowCode["projectType"] === "kanban" ? "kanban" : void 0;
655
554
  }
656
555
  function readKanbanArtifactConfig(value) {
657
- if (!isRecord2(value)) {
556
+ if (!isRecord(value)) {
658
557
  throw new Error("package.json root must be an object.");
659
558
  }
660
559
  const workflowCode = value["workflowCode"];
661
- if (!isRecord2(workflowCode)) {
560
+ if (!isRecord(workflowCode)) {
662
561
  throw new Error("package.json workflowCode must be an object for a Kanban project.");
663
562
  }
664
563
  const rawConfig = workflowCode["kanban"];
665
- if (rawConfig !== void 0 && !isRecord2(rawConfig)) {
564
+ if (rawConfig !== void 0 && !isRecord(rawConfig)) {
666
565
  throw new Error("package.json workflowCode.kanban must be an object.");
667
566
  }
567
+ if (rawConfig?.["dataSources"] !== void 0) {
568
+ throw new Error(
569
+ "package.json workflowCode.kanban.dataSources was removed; declare workflowCode.projectInfo.relatedProjects instead."
570
+ );
571
+ }
668
572
  return {
669
573
  artifactDir: readKanbanRelativePath(
670
574
  rawConfig?.["artifactDir"],
@@ -677,8 +581,7 @@ function readKanbanArtifactConfig(value) {
677
581
  "workflowCode.kanban.entry",
678
582
  KANBAN_ENTRY_FILE,
679
583
  false
680
- ),
681
- dataSources: parseKanbanDataSources(rawConfig?.["dataSources"])
584
+ )
682
585
  };
683
586
  }
684
587
  function createKanbanArtifactEntryPath(config) {
@@ -705,68 +608,7 @@ function readKanbanRelativePath(value, field, fallback, allowDot) {
705
608
  }
706
609
  return normalized;
707
610
  }
708
- function parseKanbanDataSources(value) {
709
- if (value === void 0) return [];
710
- if (!Array.isArray(value)) {
711
- throw new Error("package.json workflowCode.kanban.dataSources must be an array.");
712
- }
713
- if (value.length > MAX_KANBAN_DATA_SOURCES) {
714
- throw new Error(`package.json workflowCode.kanban.dataSources supports at most ${MAX_KANBAN_DATA_SOURCES} items.`);
715
- }
716
- const ids = /* @__PURE__ */ new Set();
717
- return value.map((item, index) => {
718
- if (!isRecord2(item)) {
719
- throw new Error(`package.json workflowCode.kanban.dataSources[${index}] must be an object.`);
720
- }
721
- const supportedFields = /* @__PURE__ */ new Set(["id", "kind", "projectId", "keyPrefixes"]);
722
- if (Object.keys(item).some((field) => !supportedFields.has(field))) {
723
- throw new Error(`package.json workflowCode.kanban.dataSources[${index}] contains unsupported fields.`);
724
- }
725
- const id = readNonEmptyString(item["id"], `workflowCode.kanban.dataSources[${index}].id`);
726
- if (!KANBAN_DATA_SOURCE_ID_PATTERN.test(id)) {
727
- throw new Error(`package.json workflowCode.kanban.dataSources[${index}].id is invalid.`);
728
- }
729
- if (ids.has(id)) {
730
- throw new Error(`package.json workflowCode.kanban.dataSources contains duplicate id "${id}".`);
731
- }
732
- ids.add(id);
733
- if (item["kind"] !== "workflow-kv") {
734
- throw new Error(`package.json workflowCode.kanban.dataSources[${index}].kind is unsupported.`);
735
- }
736
- const projectId = readNonEmptyString(
737
- item["projectId"],
738
- `workflowCode.kanban.dataSources[${index}].projectId`
739
- );
740
- if (!KANBAN_WORKFLOW_UUID_PATTERN.test(projectId)) {
741
- throw new Error(`package.json workflowCode.kanban.dataSources[${index}].projectId must be a UUID.`);
742
- }
743
- const rawPrefixes = item["keyPrefixes"];
744
- if (!Array.isArray(rawPrefixes) || rawPrefixes.length === 0 || rawPrefixes.length > MAX_KANBAN_DATA_SOURCE_PREFIXES) {
745
- throw new Error(
746
- `package.json workflowCode.kanban.dataSources[${index}].keyPrefixes must contain 1 to ${MAX_KANBAN_DATA_SOURCE_PREFIXES} items.`
747
- );
748
- }
749
- const keyPrefixes = rawPrefixes.map((prefix, prefixIndex) => {
750
- const normalized = readNonEmptyString(
751
- prefix,
752
- `workflowCode.kanban.dataSources[${index}].keyPrefixes[${prefixIndex}]`
753
- );
754
- if (normalized.length > MAX_KANBAN_DATA_SOURCE_KEY_LENGTH || normalized.includes("\0")) {
755
- throw new Error(`package.json workflowCode.kanban.dataSources[${index}].keyPrefixes[${prefixIndex}] is invalid.`);
756
- }
757
- return normalized;
758
- });
759
- if (new Set(keyPrefixes).size !== keyPrefixes.length) {
760
- throw new Error(`package.json workflowCode.kanban.dataSources[${index}].keyPrefixes contains duplicates.`);
761
- }
762
- return { id, kind: "workflow-kv", projectId, keyPrefixes };
763
- });
764
- }
765
- function readNonEmptyString(value, field) {
766
- if (typeof value !== "string" || value.trim() === "") throw new Error(`kanban.json ${field} must be a non-empty string.`);
767
- return value.trim();
768
- }
769
- function isRecord2(value) {
611
+ function isRecord(value) {
770
612
  return typeof value === "object" && value !== null && !Array.isArray(value);
771
613
  }
772
614
 
@@ -847,8 +689,8 @@ function findEffectiveWorkflowIgnoreRule(normalizedPath, ruleLines) {
847
689
 
848
690
  // .shared/project-upload/node.ts
849
691
  async function createWorkflowUploadPlan(rootDir) {
850
- const projectRoot = path2.resolve(rootDir);
851
- const workflowIgnorePath = path2.join(projectRoot, WORKFLOW_IGNORE_FILE);
692
+ const projectRoot = path.resolve(rootDir);
693
+ const workflowIgnorePath = path.join(projectRoot, WORKFLOW_IGNORE_FILE);
852
694
  const workflowIgnoreStat = await lstat(workflowIgnorePath).catch(() => void 0);
853
695
  if (workflowIgnoreStat?.isSymbolicLink()) {
854
696
  throw new Error(`${WORKFLOW_IGNORE_FILE} must be a regular file.`);
@@ -868,8 +710,8 @@ async function createWorkflowUploadPlan(rootDir) {
868
710
  const walk = async (currentDir) => {
869
711
  const entries = await readdir(currentDir, { withFileTypes: true });
870
712
  for (const entry of entries) {
871
- const absolutePath = path2.join(currentDir, entry.name);
872
- const relativePath = normalizeWorkflowUploadPath(path2.relative(projectRoot, absolutePath));
713
+ const absolutePath = path.join(currentDir, entry.name);
714
+ const relativePath = normalizeWorkflowUploadPath(path.relative(projectRoot, absolutePath));
873
715
  const portablePath = createWorkflowUploadPortablePathKey(relativePath);
874
716
  const conflictingPath = portablePaths.get(portablePath);
875
717
  if (conflictingPath !== void 0 && conflictingPath !== relativePath) {
@@ -905,7 +747,7 @@ async function createWorkflowUploadPlan(rootDir) {
905
747
  throw new Error("Workflow package must contain package.json.");
906
748
  }
907
749
  const packageJson = parsePackageJson(await readWorkflowUploadUtf8File(
908
- path2.join(projectRoot, "package.json"),
750
+ path.join(projectRoot, "package.json"),
909
751
  "package.json"
910
752
  ));
911
753
  const requiredPaths = resolveWorkflowUploadRequiredPaths(
@@ -931,8 +773,8 @@ async function copyWorkflowUploadFiles(sourceDir, targetDir) {
931
773
  const plan = await createWorkflowUploadPlan(sourceDir);
932
774
  await mkdir(targetDir, { recursive: true });
933
775
  for (const file of plan.files) {
934
- const targetPath = path2.join(targetDir, ...file.path.split("/"));
935
- await mkdir(path2.dirname(targetPath), { recursive: true });
776
+ const targetPath = path.join(targetDir, ...file.path.split("/"));
777
+ await mkdir(path.dirname(targetPath), { recursive: true });
936
778
  await copyFile(file.absolutePath, targetPath);
937
779
  }
938
780
  return plan;
@@ -953,71 +795,230 @@ async function readWorkflowUploadUtf8File(filePath, label) {
953
795
  }
954
796
  }
955
797
 
956
- // src/workspace.ts
957
- import {
958
- createWorkflowProjectDependencyLocks,
959
- inspectLocalWorkflowStructure,
960
- isProjectGroupHostDataPath,
961
- parseWorkflowProjectDependencyLocks,
962
- readKanbanArtifactConfig as readKanbanArtifactConfig2
963
- } from "workflow-code";
964
-
965
- // src/auth-config.ts
966
- import { readFileSync } from "fs";
967
- import { mkdir as mkdir2, readFile as readFile2, rm, writeFile } from "fs/promises";
968
- async function readCliAuthConfig(env = process.env) {
969
- try {
970
- const raw = await readFile2(resolveWorkflowCliAuthFilePath(env), "utf8");
971
- return normalizeWorkflowAuthConfig(JSON.parse(raw));
972
- } catch {
973
- return createEmptyWorkflowAuthConfig();
798
+ // .shared/project-dependencies/index.ts
799
+ function createWorkflowProjectDependencyLocks(relatedProjects, selections) {
800
+ const selectionsById = /* @__PURE__ */ new Map();
801
+ for (const selection of selections) {
802
+ if (selectionsById.has(selection.alias)) {
803
+ throw dependencyError(
804
+ "duplicateSelection",
805
+ `Duplicate dependency selection ${JSON.stringify(selection.alias)}.`,
806
+ { alias: selection.alias }
807
+ );
808
+ }
809
+ selectionsById.set(selection.alias, selection.delivery);
810
+ }
811
+ const locks = relatedProjects.map((relatedProject) => ({
812
+ alias: relatedProject.alias,
813
+ projectId: relatedProject.projectId,
814
+ delivery: selectionsById.get(relatedProject.alias) ?? "external"
815
+ }));
816
+ for (const alias of selectionsById.keys()) {
817
+ if (!relatedProjects.some((relatedProject) => relatedProject.alias === alias)) {
818
+ throw dependencyError(
819
+ "unknownSelection",
820
+ `Unknown dependency selection ${JSON.stringify(alias)}.`,
821
+ { alias }
822
+ );
823
+ }
974
824
  }
825
+ return locks;
975
826
  }
976
- function readCliAuthConfigSync(env = process.env) {
977
- try {
978
- const raw = readFileSync(resolveWorkflowCliAuthFilePath(env), "utf8");
979
- return normalizeWorkflowAuthConfig(JSON.parse(raw));
980
- } catch {
981
- return createEmptyWorkflowAuthConfig();
827
+ function parseWorkflowProjectDependencyLocks(value, options = {}) {
828
+ if (!Array.isArray(value)) {
829
+ throw dependencyError("lockArray", "Project dependency lock must be an array.");
982
830
  }
831
+ const aliases = /* @__PURE__ */ new Set();
832
+ const projectIds = /* @__PURE__ */ new Set();
833
+ return value.map((item, index) => {
834
+ const dependency = parseDependencyLock(item, index, options.published === true);
835
+ if (aliases.has(dependency.alias)) {
836
+ throw dependencyError(
837
+ "duplicateAlias",
838
+ `Project dependency alias ${JSON.stringify(dependency.alias)} is duplicated.`,
839
+ { alias: dependency.alias }
840
+ );
841
+ }
842
+ aliases.add(dependency.alias);
843
+ if (projectIds.has(dependency.projectId)) {
844
+ throw dependencyError(
845
+ "duplicateDependencyProjectId",
846
+ `Project dependency projectId ${JSON.stringify(dependency.projectId)} is duplicated.`,
847
+ { projectId: dependency.projectId }
848
+ );
849
+ }
850
+ projectIds.add(dependency.projectId);
851
+ return dependency;
852
+ });
983
853
  }
984
- async function writeCliAuthConfig(config, env = process.env) {
985
- await mkdir2(resolveWorkflowCliAuthDir(env), { recursive: true });
986
- await writeFile(
987
- resolveWorkflowCliAuthFilePath(env),
988
- `${JSON.stringify(normalizeWorkflowAuthConfig(config), null, 2)}
989
- `,
990
- "utf8"
854
+ function isProjectGroupHostDataPath(filePath) {
855
+ const normalized = filePath.replaceAll("\\", "/").replace(/^\.\/+/, "").toLowerCase();
856
+ const parts = normalized.split("/");
857
+ if (parts.some((part) => [
858
+ ".workflow-kv",
859
+ ".workflow-persistent-values",
860
+ ".workflow-runs",
861
+ ".workflow-schedules",
862
+ ".workflow-code",
863
+ ".workflow-files",
864
+ ".data",
865
+ "local-project-registries",
866
+ "workflow-files"
867
+ ].includes(part))) {
868
+ return true;
869
+ }
870
+ const baseName = parts.at(-1) ?? "";
871
+ if (baseName === "workflow-code.sqlite" || baseName.startsWith("workflow-code.sqlite-") || baseName === "workflow-auth.json" || baseName === "local-projects.json") {
872
+ return true;
873
+ }
874
+ return baseName === ".env" || baseName === ".envrc" || baseName.startsWith(".env.") && baseName !== ".env.example";
875
+ }
876
+ function parseDependencyLock(value, index, published) {
877
+ if (!isRecord2(value)) {
878
+ throw dependencyError(
879
+ "lockObject",
880
+ `Project dependency lock[${index}] must be an object.`,
881
+ { field: `Project dependency lock[${index}]` }
882
+ );
883
+ }
884
+ assertSupportedFields(
885
+ value,
886
+ ["alias", "projectId", "delivery", "version", "sourceHash"],
887
+ `dependencies[${index}]`
991
888
  );
889
+ const alias = readNonEmptyString(value["alias"], `dependencies[${index}].alias`);
890
+ if (!/^[a-z][a-z0-9_-]{0,63}$/.test(alias)) {
891
+ throw dependencyError(
892
+ "lockAlias",
893
+ `Project dependency lock[${index}].alias is invalid.`,
894
+ { field: `Project dependency lock[${index}].alias` }
895
+ );
896
+ }
897
+ const projectId = readUuid(value["projectId"], `dependencies[${index}].projectId`);
898
+ const delivery = value["delivery"];
899
+ if (delivery !== "included" && delivery !== "external") {
900
+ throw dependencyError(
901
+ "lockDelivery",
902
+ `Project dependency lock[${index}].delivery is invalid.`,
903
+ { field: `Project dependency lock[${index}].delivery` }
904
+ );
905
+ }
906
+ const version = readOptionalString(value["version"], `dependencies[${index}].version`);
907
+ const sourceHash = readOptionalString(value["sourceHash"], `dependencies[${index}].sourceHash`);
908
+ if (delivery === "external" && (version !== void 0 || sourceHash !== void 0)) {
909
+ throw dependencyError(
910
+ "externalPinned",
911
+ `External dependency ${JSON.stringify(alias)} cannot pin a version or source hash.`,
912
+ { alias }
913
+ );
914
+ }
915
+ if (published && delivery === "included" && (version === void 0 || sourceHash === void 0)) {
916
+ throw dependencyError(
917
+ "includedPinRequired",
918
+ `Included dependency ${JSON.stringify(alias)} must pin version and sourceHash.`,
919
+ { alias }
920
+ );
921
+ }
922
+ if (version !== void 0 && !/^\d+\.\d+\.\d+$/.test(version)) {
923
+ throw dependencyError(
924
+ "includedVersionInvalid",
925
+ `Included dependency ${JSON.stringify(alias)} has an invalid version.`,
926
+ { alias }
927
+ );
928
+ }
929
+ if (sourceHash !== void 0 && !/^[a-f0-9]{64}$/.test(sourceHash)) {
930
+ throw dependencyError(
931
+ "includedHashInvalid",
932
+ `Included dependency ${JSON.stringify(alias)} has an invalid sourceHash.`,
933
+ { alias }
934
+ );
935
+ }
936
+ return {
937
+ alias,
938
+ projectId,
939
+ delivery,
940
+ ...version === void 0 ? {} : { version },
941
+ ...sourceHash === void 0 ? {} : { sourceHash }
942
+ };
992
943
  }
993
- async function clearCliAuthConfig(env = process.env) {
994
- await rm(resolveWorkflowCliAuthFilePath(env), { force: true });
944
+ function readUuid(value, field) {
945
+ const result = readNonEmptyString(value, field);
946
+ if (!isWorkflowUuid(result)) {
947
+ throw dependencyError("uuidRequired", `Project group ${field} must be a UUID.`, { field });
948
+ }
949
+ return result;
950
+ }
951
+ function readNonEmptyString(value, field) {
952
+ if (typeof value !== "string" || value.trim() === "") {
953
+ throw dependencyError("nonEmptyString", `${field} must be a non-empty string.`, { field });
954
+ }
955
+ return value.trim();
956
+ }
957
+ function readOptionalString(value, field) {
958
+ if (value === void 0) return void 0;
959
+ if (typeof value !== "string" || value.trim() === "") {
960
+ throw dependencyError(
961
+ "optionalNonEmptyString",
962
+ `${field} must be a non-empty string when provided.`,
963
+ { field }
964
+ );
965
+ }
966
+ return value.trim();
967
+ }
968
+ function isRecord2(value) {
969
+ return typeof value === "object" && value !== null && !Array.isArray(value);
970
+ }
971
+ function assertSupportedFields(value, supportedFields, field) {
972
+ const supported = new Set(supportedFields);
973
+ const unsupported = Object.keys(value).find((key) => !supported.has(key));
974
+ if (unsupported !== void 0) {
975
+ throw dependencyError(
976
+ "unsupportedField",
977
+ `${field}.${unsupported} is not supported.`,
978
+ { field: `${field}.${unsupported}` }
979
+ );
980
+ }
981
+ }
982
+ function dependencyError(key, message, values) {
983
+ return Object.assign(new Error(message), {
984
+ name: "WorkflowProjectDependencyLocalizedError",
985
+ workflowCodeI18n: {
986
+ namespace: "common",
987
+ key: `projectDependencies.validation.${key}`,
988
+ ...values === void 0 ? {} : { values }
989
+ }
990
+ });
995
991
  }
996
992
 
993
+ // src/workspace.ts
994
+ import {
995
+ inspectLocalWorkflowStructure
996
+ } from "workflow-code";
997
+
997
998
  // src/env.ts
998
- import { existsSync, readFileSync as readFileSync2 } from "fs";
999
- import path3 from "path";
999
+ import { existsSync, readFileSync } from "fs";
1000
+ import path2 from "path";
1000
1001
  import { parse } from "dotenv";
1001
1002
  function loadCliEnv() {
1002
1003
  const cliRoot = process.cwd();
1003
1004
  const defaultRepoRoot = findWorkspaceRepositoryRoot(cliRoot) ?? cliRoot;
1004
- const initialRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path3.resolve(process.env.WORKFLOW_REPO_ROOT) : defaultRepoRoot;
1005
+ const initialRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path2.resolve(process.env.WORKFLOW_REPO_ROOT) : defaultRepoRoot;
1005
1006
  loadEnvFiles([
1006
- path3.join(cliRoot, ".env"),
1007
- path3.join(initialRepoRoot, ".env")
1007
+ path2.join(cliRoot, ".env"),
1008
+ path2.join(initialRepoRoot, ".env")
1008
1009
  ]);
1009
- const resolvedRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path3.resolve(process.env.WORKFLOW_REPO_ROOT) : initialRepoRoot;
1010
+ const resolvedRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path2.resolve(process.env.WORKFLOW_REPO_ROOT) : initialRepoRoot;
1010
1011
  if (resolvedRepoRoot !== initialRepoRoot) {
1011
- loadEnvFiles([path3.join(resolvedRepoRoot, ".env")]);
1012
+ loadEnvFiles([path2.join(resolvedRepoRoot, ".env")]);
1012
1013
  }
1013
1014
  }
1014
1015
  function findWorkspaceRepositoryRoot(startDir) {
1015
- let current = path3.resolve(startDir);
1016
+ let current = path2.resolve(startDir);
1016
1017
  while (true) {
1017
- if (existsSync(path3.join(current, "pnpm-workspace.yaml")) && existsSync(path3.join(current, "package.json")) && existsSync(path3.join(current, "workspace", "package.json")) && existsSync(path3.join(current, "workspace", "workflow"))) {
1018
+ if (existsSync(path2.join(current, "pnpm-workspace.yaml")) && existsSync(path2.join(current, "package.json")) && existsSync(path2.join(current, "workspace", "package.json")) && existsSync(path2.join(current, "workspace", "workflow"))) {
1018
1019
  return current;
1019
1020
  }
1020
- const parent = path3.dirname(current);
1021
+ const parent = path2.dirname(current);
1021
1022
  if (parent === current) return void 0;
1022
1023
  current = parent;
1023
1024
  }
@@ -1027,7 +1028,7 @@ function loadEnvFiles(filePaths) {
1027
1028
  if (!existsSync(filePath)) {
1028
1029
  continue;
1029
1030
  }
1030
- const values = parse(readFileSync2(filePath));
1031
+ const values = parse(readFileSync(filePath));
1031
1032
  for (const [key, value] of Object.entries(values)) {
1032
1033
  if (process.env[key] === void 0) {
1033
1034
  process.env[key] = value;
@@ -1041,7 +1042,7 @@ function unique(values) {
1041
1042
 
1042
1043
  // src/workspace.ts
1043
1044
  var DEFAULT_SERVER_URL = "http://localhost:7125";
1044
- var CLI_MODULE_DIR = path4.dirname(fileURLToPath(import.meta.url));
1045
+ var CLI_MODULE_DIR = path3.dirname(fileURLToPath(import.meta.url));
1045
1046
  var DEFAULT_DEVICE_FLOW_CLIENT_NAME = "Workflow Workspace CLI";
1046
1047
  loadCliEnv();
1047
1048
  async function main(argv = process.argv.slice(2), options = {}) {
@@ -1177,7 +1178,7 @@ async function commandStatus() {
1177
1178
  }
1178
1179
  async function commandPack(parsed) {
1179
1180
  const workflowName = requirePositional(parsed, 0, "workflow");
1180
- if (parsed.options.projectGroup === true || parsed.options.publishGroup === true || parsed.options.dependencies.length > 0 || parsed.options.dataGrants.length > 0) {
1181
+ if (parsed.options.projectGroup === true || parsed.options.publishGroup === true || parsed.options.dependencies.length > 0) {
1181
1182
  const packed = await packProjectGroup({
1182
1183
  workflowArg: workflowName,
1183
1184
  sourcePath: parsed.options.path,
@@ -1210,7 +1211,7 @@ async function commandUpload(parsed) {
1210
1211
  if (!workflowId) {
1211
1212
  throw new Error(i18n.t("workflowIdRequired", { ns: "cli" }));
1212
1213
  }
1213
- const archivePath = parsed.options.file ? path4.resolve(parsed.options.file) : await packWorkflow(workflowArg, parsed.options.output, parsed.options.path);
1214
+ const archivePath = parsed.options.file ? path3.resolve(parsed.options.file) : await packWorkflow(workflowArg, parsed.options.output, parsed.options.path);
1214
1215
  const executionTargets = resolveRequestedExecutionTargets(parsed.options, packageContext.projectType);
1215
1216
  const uploadResult = await uploadPackage({
1216
1217
  workflowId,
@@ -1256,7 +1257,7 @@ async function commandUpload(parsed) {
1256
1257
  }
1257
1258
  }
1258
1259
  function shouldUseProjectGroupUpload(options) {
1259
- return options.projectGroup === true || options.publishGroup === true || options.dependencies.length > 0 || options.dataGrants.length > 0;
1260
+ return options.projectGroup === true || options.publishGroup === true || options.dependencies.length > 0;
1260
1261
  }
1261
1262
  async function commandProjectGroupUpload(parsed, workflowArg, forcePublish = false) {
1262
1263
  if (parsed.options.file !== void 0) {
@@ -1281,7 +1282,7 @@ async function commandProjectGroupUpload(parsed, workflowArg, forcePublish = fal
1281
1282
  });
1282
1283
  for (const dependency of contexts.dependencies) {
1283
1284
  await ensureWorkflowProjectCreated({
1284
- packageContext: dependency,
1285
+ packageContext: dependency.packageContext,
1285
1286
  server: parsed.options.server,
1286
1287
  token: parsed.options.token
1287
1288
  });
@@ -1320,24 +1321,6 @@ async function commandProjectGroupUpload(parsed, workflowArg, forcePublish = fal
1320
1321
  assertApiOk(prepared);
1321
1322
  return;
1322
1323
  }
1323
- const grantsByProject = resolveExplicitDataGrants(
1324
- packed.manifest.dependencies,
1325
- parsed.options.dataGrants
1326
- );
1327
- for (const [sourceProjectId, prefixes] of grantsByProject) {
1328
- const grant = await fetchApi({
1329
- server: parsed.options.server,
1330
- token: parsed.options.token,
1331
- path: `/api/workflows/${encodeURIComponent(sourceProjectId)}/data-source-grants/${encodeURIComponent(packed.manifest.rootProjectId)}`,
1332
- method: "PUT",
1333
- body: { keyPrefixes: prefixes }
1334
- });
1335
- if (grant.errCode !== 0) {
1336
- printApiResponse(grant);
1337
- assertApiOk(grant);
1338
- return;
1339
- }
1340
- }
1341
1324
  if (!forcePublish && parsed.options.releaseLog === void 0 && parsed.options.publishGroup !== true) {
1342
1325
  printApiResponse(prepared);
1343
1326
  return;
@@ -1436,7 +1419,7 @@ async function commandDownload(parsed) {
1436
1419
  return;
1437
1420
  }
1438
1421
  const repoRoot2 = resolveRepoRoot();
1439
- const rootTargetDir = parsed.options.path ? path4.resolve(parsed.options.path) : path4.join(repoRoot2, "workspace", "workflow", workflowArg);
1422
+ const rootTargetDir = parsed.options.path ? path3.resolve(parsed.options.path) : path3.join(repoRoot2, "workspace", "workflow", workflowArg);
1440
1423
  const materialized = await materializeProjectGroupDownload(result2.data, rootTargetDir);
1441
1424
  const locallyAvailableProjectIds = new Set(materialized.map((project) => project.projectId));
1442
1425
  const skippedDependencies = result2.data.skippedDependencies.filter((item) => item.dependency.delivery !== "included" || !locallyAvailableProjectIds.has(item.dependency.projectId));
@@ -1464,14 +1447,14 @@ async function commandDownload(parsed) {
1464
1447
  return;
1465
1448
  }
1466
1449
  const repoRoot = resolveRepoRoot();
1467
- const targetDir = parsed.options.path ? path4.resolve(parsed.options.path) : path4.join(repoRoot, "workspace", "workflow", workflowArg);
1468
- await rm2(targetDir, { recursive: true, force: true });
1469
- await mkdir3(targetDir, { recursive: true });
1450
+ const targetDir = parsed.options.path ? path3.resolve(parsed.options.path) : path3.join(repoRoot, "workspace", "workflow", workflowArg);
1451
+ await rm(targetDir, { recursive: true, force: true });
1452
+ await mkdir2(targetDir, { recursive: true });
1470
1453
  for (const file of result.data.files) {
1471
1454
  const safePath = normalizeWorkflowFilePath(file.path);
1472
- const targetPath = path4.join(targetDir, safePath);
1473
- await mkdir3(path4.dirname(targetPath), { recursive: true });
1474
- await writeFile2(targetPath, decodeWorkflowFileContent(file));
1455
+ const targetPath = path3.join(targetDir, safePath);
1456
+ await mkdir2(path3.dirname(targetPath), { recursive: true });
1457
+ await writeFile(targetPath, decodeWorkflowFileContent(file));
1475
1458
  }
1476
1459
  }
1477
1460
  async function commandPublish(parsed) {
@@ -1547,17 +1530,11 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1547
1530
  } catch {
1548
1531
  throw new Error(i18n.t("projectGroupDownloadRootPackageInvalidJson", { ns: "cli" }));
1549
1532
  }
1550
- const declaredSources = readKanbanArtifactConfig2(rootPackageJson).dataSources;
1551
- const selfReference = declaredSources.find((source) => source.projectId === download.rootProjectId);
1552
- if (selfReference !== void 0) {
1553
- throw new Error(i18n.t("projectGroupDownloadSelfReference", {
1554
- ns: "cli",
1555
- sourceId: JSON.stringify(selfReference.id)
1556
- }));
1557
- }
1558
- if (declaredSources.length !== dependencies.length || declaredSources.some((source) => {
1559
- const dependency = dependencies.find((candidate) => candidate.sourceId === source.id);
1560
- return dependency === void 0 || dependency.kind !== source.kind || dependency.projectId !== source.projectId || JSON.stringify(dependency.keyPrefixes) !== JSON.stringify(source.keyPrefixes);
1533
+ const rootProjectInfo = readWorkflowProjectInfo(rootPackageJson);
1534
+ const declaredRelations = rootProjectInfo.relatedProjects;
1535
+ if (declaredRelations.length !== dependencies.length || declaredRelations.some((relation) => {
1536
+ const dependency = dependencies.find((candidate) => candidate.alias === relation.alias);
1537
+ return dependency === void 0 || dependency.projectId.toLowerCase() !== relation.projectId.toLowerCase();
1561
1538
  })) {
1562
1539
  throw new Error(i18n.t("projectGroupDownloadLockMismatch", { ns: "cli" }));
1563
1540
  }
@@ -1611,20 +1588,30 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1611
1588
  projectId: JSON.stringify(project.projectId)
1612
1589
  }));
1613
1590
  }
1614
- if (project.role === "root" && project.sourceId !== void 0) {
1615
- throw new Error(i18n.t("projectGroupDownloadRootSourceIdForbidden", { ns: "cli" }));
1591
+ if (project.role === "root" && project.alias !== void 0) {
1592
+ throw new Error(i18n.t("projectGroupDownloadRootAliasForbidden", { ns: "cli" }));
1616
1593
  }
1617
1594
  if (project.role === "dependency") {
1618
1595
  const matchingDependencies = includedDependencies.filter((dependency) => dependency.projectId === project.projectId && dependency.version === project.version && dependency.sourceHash === project.sourceHash);
1619
- if (matchingDependencies.length === 0 || project.sourceId !== void 0 && !matchingDependencies.some((dependency) => dependency.sourceId === project.sourceId)) {
1596
+ if (matchingDependencies.length === 0 || project.alias !== void 0 && !matchingDependencies.some((dependency) => dependency.alias === project.alias)) {
1620
1597
  throw new Error(i18n.t("projectGroupDownloadUndeclaredDependency", {
1621
1598
  ns: "cli",
1622
1599
  projectId: JSON.stringify(project.projectId)
1623
1600
  }));
1624
1601
  }
1602
+ const matchingDependency = project.alias === void 0 ? matchingDependencies[0] : matchingDependencies.find((dependency) => dependency.alias === project.alias);
1603
+ if (matchingDependency !== void 0) {
1604
+ assertConfirmedRelatedProject({
1605
+ rootProjectId: download.rootProjectId,
1606
+ rootProjectInfo,
1607
+ targetProjectId: project.projectId,
1608
+ targetPackageJson: packageJson,
1609
+ alias: matchingDependency.alias
1610
+ });
1611
+ }
1625
1612
  }
1626
1613
  }
1627
- const parentDir = path4.dirname(rootTargetDir);
1614
+ const parentDir = path3.dirname(rootTargetDir);
1628
1615
  const existingById = await findSiblingProjectsById(parentDir);
1629
1616
  const materialized = [];
1630
1617
  const pending = [];
@@ -1633,9 +1620,21 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1633
1620
  for (const project of orderedProjects) {
1634
1621
  const existingPath = existingById.get(project.projectId);
1635
1622
  if (existingPath !== void 0) {
1636
- await assertDownloadedProjectRole(existingPath, project.projectId, project.role);
1623
+ const packageJson = await assertDownloadedProjectRole(existingPath, project.projectId, project.role);
1624
+ if (project.role === "dependency") {
1625
+ const dependency = includedDependencies.find((candidate) => candidate.projectId === project.projectId && (project.alias === void 0 || candidate.alias === project.alias));
1626
+ if (dependency !== void 0) {
1627
+ assertConfirmedRelatedProject({
1628
+ rootProjectId: download.rootProjectId,
1629
+ rootProjectInfo,
1630
+ targetProjectId: project.projectId,
1631
+ targetPackageJson: packageJson,
1632
+ alias: dependency.alias
1633
+ });
1634
+ }
1635
+ }
1637
1636
  materialized.push({
1638
- ...project.sourceId === void 0 ? {} : { sourceId: project.sourceId },
1637
+ ...project.alias === void 0 ? {} : { alias: project.alias },
1639
1638
  projectId: project.projectId,
1640
1639
  projectName: project.projectName,
1641
1640
  role: project.role,
@@ -1644,7 +1643,7 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1644
1643
  });
1645
1644
  continue;
1646
1645
  }
1647
- const targetDir = project.role === "root" ? rootTargetDir : path4.join(parentDir, createProjectDirectoryName(project.projectName, project.projectId));
1646
+ const targetDir = project.role === "root" ? rootTargetDir : path3.join(parentDir, createProjectDirectoryName(project.projectName, project.projectId));
1648
1647
  if (existsSync2(targetDir)) {
1649
1648
  throw new Error(i18n.t("projectGroupDownloadDirectoryProjectMismatch", {
1650
1649
  ns: "cli",
@@ -1652,7 +1651,7 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1652
1651
  path: JSON.stringify(targetDir)
1653
1652
  }));
1654
1653
  }
1655
- const targetKey = createPortableLocalPathKey(path4.resolve(targetDir));
1654
+ const targetKey = createPortableLocalPathKey(path3.resolve(targetDir));
1656
1655
  if (targetKeys.has(targetKey)) {
1657
1656
  throw new Error(i18n.t("projectGroupDownloadDirectoryCollision", {
1658
1657
  ns: "cli",
@@ -1668,6 +1667,16 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1668
1667
  const existingPath = existingById.get(projectId);
1669
1668
  if (existingPath === void 0) continue;
1670
1669
  const packageJson = await assertDownloadedProjectRole(existingPath, projectId, "dependency");
1670
+ const dependency = includedDependencies.find((candidate) => candidate.projectId === projectId);
1671
+ if (dependency !== void 0) {
1672
+ assertConfirmedRelatedProject({
1673
+ rootProjectId: download.rootProjectId,
1674
+ rootProjectInfo,
1675
+ targetProjectId: projectId,
1676
+ targetPackageJson: packageJson,
1677
+ alias: dependency.alias
1678
+ });
1679
+ }
1671
1680
  materialized.push({
1672
1681
  projectId,
1673
1682
  projectName: readRequiredPackageString(packageJson, "name"),
@@ -1676,23 +1685,23 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1676
1685
  alreadyAvailable: true
1677
1686
  });
1678
1687
  }
1679
- await mkdir3(parentDir, { recursive: true });
1680
- const stagingRoot = path4.join(parentDir, `.workflow-download-group-${randomUUID()}`);
1688
+ await mkdir2(parentDir, { recursive: true });
1689
+ const stagingRoot = path3.join(parentDir, `.workflow-download-group-${randomUUID()}`);
1681
1690
  const staged = [];
1682
1691
  const moved = [];
1683
1692
  try {
1684
- await mkdir3(stagingRoot, { recursive: false });
1693
+ await mkdir2(stagingRoot, { recursive: false });
1685
1694
  for (const item of pending) {
1686
1695
  const { project, targetDir } = item;
1687
- const stagingDir = path4.join(stagingRoot, project.projectId);
1688
- await mkdir3(stagingDir, { recursive: true });
1696
+ const stagingDir = path3.join(stagingRoot, project.projectId);
1697
+ await mkdir2(stagingDir, { recursive: true });
1689
1698
  for (const file of project.files) {
1690
1699
  const safePath = normalizeWorkflowFilePath(file.path);
1691
- const targetPath = path4.join(stagingDir, ...safePath.split("/"));
1692
- await mkdir3(path4.dirname(targetPath), { recursive: true });
1693
- await writeFile2(targetPath, decodeWorkflowFileContent(file));
1700
+ const targetPath = path3.join(stagingDir, ...safePath.split("/"));
1701
+ await mkdir2(path3.dirname(targetPath), { recursive: true });
1702
+ await writeFile(targetPath, decodeWorkflowFileContent(file));
1694
1703
  }
1695
- const packageJson = await readPackageJsonFile(path4.join(stagingDir, "package.json"));
1704
+ const packageJson = await readPackageJsonFile(path3.join(stagingDir, "package.json"));
1696
1705
  if (packageJson["id"] !== project.projectId) {
1697
1706
  throw new Error(i18n.t("projectGroupDownloadedPackageIdMismatch", {
1698
1707
  ns: "cli",
@@ -1707,7 +1716,7 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1707
1716
  moved.push(item.targetDir);
1708
1717
  existingById.set(item.project.projectId, item.targetDir);
1709
1718
  materialized.push({
1710
- ...item.project.sourceId === void 0 ? {} : { sourceId: item.project.sourceId },
1719
+ ...item.project.alias === void 0 ? {} : { alias: item.project.alias },
1711
1720
  projectId: item.project.projectId,
1712
1721
  projectName: item.project.projectName,
1713
1722
  role: item.project.role,
@@ -1717,16 +1726,16 @@ async function materializeProjectGroupDownload(download, rootTargetDir) {
1717
1726
  }
1718
1727
  } catch (error) {
1719
1728
  for (const targetDir of moved) {
1720
- await rm2(targetDir, { recursive: true, force: true }).catch(() => void 0);
1729
+ await rm(targetDir, { recursive: true, force: true }).catch(() => void 0);
1721
1730
  }
1722
1731
  throw error;
1723
1732
  } finally {
1724
- await rm2(stagingRoot, { recursive: true, force: true }).catch(() => void 0);
1733
+ await rm(stagingRoot, { recursive: true, force: true }).catch(() => void 0);
1725
1734
  }
1726
1735
  return materialized.sort((left, right) => left.role === right.role ? left.projectId.localeCompare(right.projectId) : left.role === "root" ? -1 : 1);
1727
1736
  }
1728
1737
  async function assertDownloadedProjectRole(projectDir, projectId, role, packageJson) {
1729
- const metadata = packageJson ?? await readPackageJsonFile(path4.join(projectDir, "package.json"));
1738
+ const metadata = packageJson ?? await readPackageJsonFile(path3.join(projectDir, "package.json"));
1730
1739
  if (metadata["id"] !== projectId) {
1731
1740
  throw new Error(i18n.t("projectGroupDownloadedPackageIdMismatch", {
1732
1741
  ns: "cli",
@@ -1734,56 +1743,40 @@ async function assertDownloadedProjectRole(projectDir, projectId, role, packageJ
1734
1743
  }));
1735
1744
  }
1736
1745
  const projectType = inspectLocalWorkflowStructure({ workflowDir: projectDir }).projectType;
1737
- const expectedProjectType = role === "root" ? "kanban" : "workflow";
1738
- if (projectType !== expectedProjectType) {
1746
+ if (role === "root" && projectType !== "kanban") {
1739
1747
  throw new Error(i18n.t("projectGroupDownloadedProjectTypeMismatch", {
1740
1748
  ns: "cli",
1741
1749
  projectId: JSON.stringify(projectId),
1742
- projectType: expectedProjectType
1750
+ projectType: "kanban"
1743
1751
  }));
1744
1752
  }
1745
1753
  return metadata;
1746
1754
  }
1755
+ function assertConfirmedRelatedProject(options) {
1756
+ const targetProjectInfo = readWorkflowProjectInfo(options.targetPackageJson);
1757
+ if (resolveWorkflowRelatedProjectAccess({
1758
+ consumerProjectId: options.rootProjectId,
1759
+ consumerProjectInfo: options.rootProjectInfo,
1760
+ targetProjectId: options.targetProjectId,
1761
+ targetProjectInfo,
1762
+ alias: options.alias
1763
+ }) === void 0) {
1764
+ throw new Error(i18n.t("projectGroupRelatedProjectPending", {
1765
+ ns: "cli",
1766
+ alias: JSON.stringify(options.alias)
1767
+ }));
1768
+ }
1769
+ }
1747
1770
  function createPortableLocalPathKey(filePath) {
1748
1771
  return filePath.normalize("NFC").toLowerCase();
1749
1772
  }
1750
- function resolveExplicitDataGrants(dependencies, sourceIds) {
1751
- const selected = /* @__PURE__ */ new Set();
1752
- for (const sourceId of sourceIds) {
1753
- if (selected.has(sourceId)) {
1754
- throw new Error(i18n.t("duplicateGrantDataAccessSource", {
1755
- ns: "cli",
1756
- sourceId: JSON.stringify(sourceId)
1757
- }));
1758
- }
1759
- selected.add(sourceId);
1760
- }
1761
- const grants = /* @__PURE__ */ new Map();
1762
- for (const sourceId of selected) {
1763
- const dependency = dependencies.find((candidate) => candidate.sourceId === sourceId);
1764
- if (dependency === void 0) {
1765
- throw new Error(i18n.t("unknownGrantDataAccessSource", {
1766
- ns: "cli",
1767
- sourceId: JSON.stringify(sourceId)
1768
- }));
1769
- }
1770
- grants.set(dependency.projectId, [
1771
- ...grants.get(dependency.projectId) ?? [],
1772
- ...dependency.keyPrefixes
1773
- ]);
1774
- }
1775
- for (const [projectId, prefixes] of grants) {
1776
- grants.set(projectId, [...new Set(prefixes)]);
1777
- }
1778
- return grants;
1779
- }
1780
1773
  async function findSiblingProjectsById(parentDir) {
1781
1774
  const projects = /* @__PURE__ */ new Map();
1782
1775
  const entries = await readdir2(parentDir, { withFileTypes: true }).catch(() => []);
1783
1776
  for (const entry of entries) {
1784
1777
  if (!entry.isDirectory()) continue;
1785
- const projectDir = path4.join(parentDir, entry.name);
1786
- const packageJson = await readPackageJsonFile(path4.join(projectDir, "package.json")).catch(() => void 0);
1778
+ const projectDir = path3.join(parentDir, entry.name);
1779
+ const packageJson = await readPackageJsonFile(path3.join(projectDir, "package.json")).catch(() => void 0);
1787
1780
  const projectId = packageJson?.["id"];
1788
1781
  if (typeof projectId === "string" && isWorkflowUuid(projectId) && !projects.has(projectId)) {
1789
1782
  projects.set(projectId, projectDir);
@@ -1807,26 +1800,26 @@ async function commandHealth(parsed) {
1807
1800
  }
1808
1801
  async function packWorkflow(workflowName, outputPath, sourcePath, options = {}) {
1809
1802
  const repoRoot = resolveRepoRoot();
1810
- const workflowDir = sourcePath === void 0 ? path4.join(repoRoot, "workspace", "workflow", workflowName) : path4.resolve(sourcePath);
1811
- await readPackageJsonFile(path4.join(workflowDir, "package.json"));
1812
- const packsDir = process.env.WORKFLOW_WORKSPACE_PACKS_DIR ? path4.resolve(process.env.WORKFLOW_WORKSPACE_PACKS_DIR) : path4.join(repoRoot, "workspace", ".packs");
1813
- const stagingDir = path4.join(packsDir, "tmp", randomUUID(), workflowName);
1814
- const archivePath = outputPath ? path4.resolve(outputPath) : path4.join(packsDir, `${workflowName}-${createTimestamp()}.tgz`);
1815
- const workspaceRoot = sourcePath === void 0 ? path4.join(repoRoot, "workspace", "workflow") : path4.dirname(workflowDir);
1816
- await rm2(path4.dirname(stagingDir), { recursive: true, force: true });
1817
- await mkdir3(path4.join(stagingDir, "workspace", "workflow"), { recursive: true });
1818
- await mkdir3(path4.dirname(archivePath), { recursive: true });
1803
+ const workflowDir = sourcePath === void 0 ? path3.join(repoRoot, "workspace", "workflow", workflowName) : path3.resolve(sourcePath);
1804
+ await readPackageJsonFile(path3.join(workflowDir, "package.json"));
1805
+ const packsDir = process.env.WORKFLOW_WORKSPACE_PACKS_DIR ? path3.resolve(process.env.WORKFLOW_WORKSPACE_PACKS_DIR) : path3.join(repoRoot, "workspace", ".packs");
1806
+ const stagingDir = path3.join(packsDir, "tmp", randomUUID(), workflowName);
1807
+ const archivePath = outputPath ? path3.resolve(outputPath) : path3.join(packsDir, `${workflowName}-${createTimestamp()}.tgz`);
1808
+ const workspaceRoot = sourcePath === void 0 ? path3.join(repoRoot, "workspace", "workflow") : path3.dirname(workflowDir);
1809
+ await rm(path3.dirname(stagingDir), { recursive: true, force: true });
1810
+ await mkdir2(path3.join(stagingDir, "workspace", "workflow"), { recursive: true });
1811
+ await mkdir2(path3.dirname(archivePath), { recursive: true });
1819
1812
  await stageWorkflowWithLocalDependencies({
1820
1813
  workspaceRoot,
1821
1814
  workflowDir,
1822
1815
  workflowName,
1823
- stagingRoot: path4.join(stagingDir, "workspace", "workflow"),
1816
+ stagingRoot: path3.join(stagingDir, "workspace", "workflow"),
1824
1817
  projectGroupSafe: options.projectGroupSafe === true
1825
1818
  });
1826
1819
  const result = await runCommand("tar", ["-czf", archivePath, "-C", stagingDir, "."], {
1827
1820
  cwd: repoRoot
1828
1821
  });
1829
- await rm2(path4.dirname(stagingDir), { recursive: true, force: true });
1822
+ await rm(path3.dirname(stagingDir), { recursive: true, force: true });
1830
1823
  if (result.exitCode !== 0) {
1831
1824
  throw new Error(i18n.t("archiveCreateFailed", {
1832
1825
  ns: "cli",
@@ -1843,74 +1836,69 @@ async function readProjectGroupContexts(options) {
1843
1836
  if (!root.workflowId) {
1844
1837
  throw new Error(i18n.t("projectGroupRootIdRequired", { ns: "cli" }));
1845
1838
  }
1846
- const dataSources = readKanbanArtifactConfig2(root.packageJson).dataSources;
1847
- const selfReference = dataSources.find((source) => source.projectId === root.workflowId);
1848
- if (selfReference !== void 0) {
1849
- throw new Error(i18n.t("projectGroupSelfReference", {
1850
- ns: "cli",
1851
- sourceId: JSON.stringify(selfReference.id)
1852
- }));
1853
- }
1839
+ const rootProjectInfo = readWorkflowProjectInfo(root.packageJson);
1840
+ const relatedProjects = rootProjectInfo.relatedProjects;
1854
1841
  const dependencyPaths = /* @__PURE__ */ new Map();
1855
1842
  for (const option of options.dependencyOptions) {
1856
1843
  const separator = option.indexOf("=");
1857
- const sourceId = separator < 1 ? "" : option.slice(0, separator).trim();
1844
+ const alias = separator < 1 ? "" : option.slice(0, separator).trim();
1858
1845
  const dependencyPath = separator < 0 ? "" : option.slice(separator + 1).trim();
1859
- if (sourceId === "" || dependencyPath === "") {
1846
+ if (alias === "" || dependencyPath === "") {
1860
1847
  throw new Error(i18n.t("invalidDependencyOption", {
1861
1848
  ns: "cli",
1862
1849
  option: JSON.stringify(option)
1863
1850
  }));
1864
1851
  }
1865
- if (dependencyPaths.has(sourceId)) {
1852
+ if (dependencyPaths.has(alias)) {
1866
1853
  throw new Error(i18n.t("duplicateDependencySource", {
1867
1854
  ns: "cli",
1868
- sourceId: JSON.stringify(sourceId)
1855
+ alias: JSON.stringify(alias)
1869
1856
  }));
1870
1857
  }
1871
- dependencyPaths.set(sourceId, path4.resolve(dependencyPath));
1858
+ dependencyPaths.set(alias, path3.resolve(dependencyPath));
1872
1859
  }
1873
1860
  const locks = createWorkflowProjectDependencyLocks(
1874
- dataSources,
1875
- [...dependencyPaths.keys()].map((sourceId) => ({ sourceId, delivery: "included" }))
1861
+ relatedProjects,
1862
+ [...dependencyPaths.keys()].map((alias) => ({ alias, delivery: "included" }))
1876
1863
  );
1877
1864
  const dependenciesByProject = /* @__PURE__ */ new Map();
1878
- for (const [sourceId, dependencyPath] of dependencyPaths) {
1879
- const source = dataSources.find((candidate) => candidate.id === sourceId);
1880
- const context = await readWorkflowPackageContext(sourceId, dependencyPath);
1881
- if (context.projectType !== "workflow") {
1882
- throw new Error(i18n.t("dependencyMustBeWorkflow", {
1883
- ns: "cli",
1884
- sourceId: JSON.stringify(sourceId)
1885
- }));
1886
- }
1887
- if (context.workflowId !== source.projectId) {
1865
+ for (const [alias, dependencyPath] of dependencyPaths) {
1866
+ const relation = relatedProjects.find((candidate) => candidate.alias === alias);
1867
+ const context = await readWorkflowPackageContext(alias, dependencyPath);
1868
+ if (context.workflowId !== relation.projectId) {
1888
1869
  throw new Error(i18n.t("dependencyPackageIdMismatch", {
1889
1870
  ns: "cli",
1890
- sourceId: JSON.stringify(sourceId),
1891
- projectId: JSON.stringify(source.projectId)
1871
+ alias: JSON.stringify(alias),
1872
+ projectId: JSON.stringify(relation.projectId)
1892
1873
  }));
1893
1874
  }
1894
- const existing = dependenciesByProject.get(source.projectId);
1895
- if (existing !== void 0 && existing.workflowDir !== context.workflowDir) {
1875
+ assertConfirmedRelatedProject({
1876
+ rootProjectId: root.workflowId,
1877
+ rootProjectInfo,
1878
+ targetProjectId: context.workflowId,
1879
+ targetPackageJson: context.packageJson,
1880
+ alias
1881
+ });
1882
+ const existing = dependenciesByProject.get(relation.projectId);
1883
+ if (existing !== void 0 && existing.packageContext.workflowDir !== context.workflowDir) {
1896
1884
  throw new Error(i18n.t("dependencyProjectPathConflict", {
1897
1885
  ns: "cli",
1898
- projectId: JSON.stringify(source.projectId)
1886
+ projectId: JSON.stringify(relation.projectId)
1899
1887
  }));
1900
1888
  }
1901
- dependenciesByProject.set(source.projectId, context);
1889
+ dependenciesByProject.set(relation.projectId, { alias, packageContext: context });
1902
1890
  }
1903
1891
  return { root, dependencies: [...dependenciesByProject.values()], locks };
1904
1892
  }
1905
1893
  async function packProjectGroup(options) {
1906
1894
  const contexts = options.contexts ?? await readProjectGroupContexts(options);
1907
1895
  const repoRoot = resolveRepoRoot();
1908
- const packsDir = process.env.WORKFLOW_WORKSPACE_PACKS_DIR ? path4.resolve(process.env.WORKFLOW_WORKSPACE_PACKS_DIR) : path4.join(repoRoot, "workspace", ".packs");
1909
- const groupRoot = path4.join(packsDir, "tmp", `project-group-${randomUUID()}`);
1910
- const projectsDir = path4.join(groupRoot, "projects");
1911
- const archivePath = options.outputPath ? path4.resolve(options.outputPath) : path4.join(packsDir, `project-group-${createTimestamp()}.tgz`);
1912
- await mkdir3(projectsDir, { recursive: true });
1913
- await mkdir3(path4.dirname(archivePath), { recursive: true });
1896
+ const packsDir = process.env.WORKFLOW_WORKSPACE_PACKS_DIR ? path3.resolve(process.env.WORKFLOW_WORKSPACE_PACKS_DIR) : path3.join(repoRoot, "workspace", ".packs");
1897
+ const groupRoot = path3.join(packsDir, "tmp", `project-group-${randomUUID()}`);
1898
+ const projectsDir = path3.join(groupRoot, "projects");
1899
+ const archivePath = options.outputPath ? path3.resolve(options.outputPath) : path3.join(packsDir, `project-group-${createTimestamp()}.tgz`);
1900
+ await mkdir2(projectsDir, { recursive: true });
1901
+ await mkdir2(path3.dirname(archivePath), { recursive: true });
1914
1902
  const rootArchivePath = `projects/${contexts.root.workflowId}.tgz`;
1915
1903
  const projects = [{
1916
1904
  projectId: contexts.root.workflowId,
@@ -1920,21 +1908,22 @@ async function packProjectGroup(options) {
1920
1908
  try {
1921
1909
  await packWorkflow(
1922
1910
  contexts.root.workflowArg,
1923
- path4.join(groupRoot, ...rootArchivePath.split("/")),
1911
+ path3.join(groupRoot, ...rootArchivePath.split("/")),
1924
1912
  contexts.root.workflowDir,
1925
1913
  { projectGroupSafe: true }
1926
1914
  );
1927
1915
  for (const dependency of contexts.dependencies) {
1928
- const dependencyArchivePath = `projects/${dependency.workflowId}.tgz`;
1916
+ const dependencyArchivePath = `projects/${dependency.packageContext.workflowId}.tgz`;
1929
1917
  projects.push({
1930
- projectId: dependency.workflowId,
1918
+ projectId: dependency.packageContext.workflowId,
1931
1919
  role: "dependency",
1932
- archivePath: dependencyArchivePath
1920
+ archivePath: dependencyArchivePath,
1921
+ alias: dependency.alias
1933
1922
  });
1934
1923
  await packWorkflow(
1935
- dependency.workflowArg,
1936
- path4.join(groupRoot, ...dependencyArchivePath.split("/")),
1937
- dependency.workflowDir,
1924
+ dependency.packageContext.workflowArg,
1925
+ path3.join(groupRoot, ...dependencyArchivePath.split("/")),
1926
+ dependency.packageContext.workflowDir,
1938
1927
  { projectGroupSafe: true }
1939
1928
  );
1940
1929
  }
@@ -1944,7 +1933,7 @@ async function packProjectGroup(options) {
1944
1933
  projects,
1945
1934
  dependencies: contexts.locks
1946
1935
  };
1947
- await writeFile2(path4.join(groupRoot, "project-group.json"), `${JSON.stringify(manifest, null, 2)}
1936
+ await writeFile(path3.join(groupRoot, "project-group.json"), `${JSON.stringify(manifest, null, 2)}
1948
1937
  `);
1949
1938
  const result = await runCommand("tar", ["-czf", archivePath, "-C", groupRoot, "."], { cwd: repoRoot });
1950
1939
  if (result.exitCode !== 0) {
@@ -1957,15 +1946,15 @@ async function packProjectGroup(options) {
1957
1946
  archivePath,
1958
1947
  manifest,
1959
1948
  root: contexts.root,
1960
- dependencies: contexts.dependencies
1949
+ dependencies: contexts.dependencies.map((dependency) => dependency.packageContext)
1961
1950
  };
1962
1951
  } finally {
1963
- await rm2(groupRoot, { recursive: true, force: true });
1952
+ await rm(groupRoot, { recursive: true, force: true });
1964
1953
  }
1965
1954
  }
1966
1955
  async function uploadProjectGroupPackage(options) {
1967
- const archiveBuffer = await readFile3(options.archivePath);
1968
- const archiveName = path4.basename(options.archivePath);
1956
+ const archiveBuffer = await readFile2(options.archivePath);
1957
+ const archiveName = path3.basename(options.archivePath);
1969
1958
  const query = new URLSearchParams({ fileName: archiveName });
1970
1959
  if (options.executionTargets !== void 0) {
1971
1960
  query.set("serverRuntime", String(options.executionTargets.server));
@@ -2003,8 +1992,8 @@ async function resolveRemoteWorkflowId(parsed) {
2003
1992
  }
2004
1993
  async function readWorkflowPackageContext(workflowArg, sourcePath) {
2005
1994
  const repoRoot = resolveRepoRoot();
2006
- const workflowDir = sourcePath === void 0 ? path4.join(repoRoot, "workspace", "workflow", workflowArg) : path4.resolve(sourcePath);
2007
- const packageJsonPath = path4.join(workflowDir, "package.json");
1995
+ const workflowDir = sourcePath === void 0 ? path3.join(repoRoot, "workspace", "workflow", workflowArg) : path3.resolve(sourcePath);
1996
+ const packageJsonPath = path3.join(workflowDir, "package.json");
2008
1997
  const packageJson = await readPackageJsonFile(packageJsonPath);
2009
1998
  const workflowId = typeof packageJson.id === "string" && isWorkflowUuid(packageJson.id) ? packageJson.id.trim() : void 0;
2010
1999
  const workflowName = readRequiredPackageString(packageJson, "name");
@@ -2020,6 +2009,14 @@ async function readWorkflowPackageContext(workflowArg, sourcePath) {
2020
2009
  };
2021
2010
  }
2022
2011
  async function ensureWorkflowProjectCreated(options) {
2012
+ const workflowId = options.packageContext.workflowId;
2013
+ if (workflowId === void 0) {
2014
+ throw new Error(i18n.t("workflowIdRequired", { ns: "cli" }));
2015
+ }
2016
+ const projectInfo = readWorkflowProjectInfo(options.packageContext.packageJson);
2017
+ if (projectInfo.dataStorage === null) {
2018
+ throw new Error(i18n.t("projectInfoDataStorageRequired", { ns: "cli" }));
2019
+ }
2023
2020
  const created = await fetchApi({
2024
2021
  server: options.server,
2025
2022
  token: options.token,
@@ -2028,7 +2025,8 @@ async function ensureWorkflowProjectCreated(options) {
2028
2025
  body: {
2029
2026
  name: options.packageContext.workflowName,
2030
2027
  projectType: options.packageContext.projectType,
2031
- ...options.packageContext.workflowId ? { workflowId: options.packageContext.workflowId } : {}
2028
+ workflowId,
2029
+ projectInfo
2032
2030
  }
2033
2031
  });
2034
2032
  if (created.errCode !== 0 || created.data === void 0) {
@@ -2036,14 +2034,14 @@ async function ensureWorkflowProjectCreated(options) {
2036
2034
  assertApiOk(created);
2037
2035
  throw new Error(i18n.t("projectCreationFailed", { ns: "cli" }));
2038
2036
  }
2039
- if (!options.packageContext.workflowId || options.packageContext.workflowId !== created.data.workflowId) {
2040
- await writeWorkflowPackageId(options.packageContext.packageJsonPath, created.data.workflowId);
2037
+ if (created.data.workflowId !== workflowId) {
2038
+ throw new Error(i18n.t("projectCreationIdMismatch", { ns: "cli" }));
2041
2039
  }
2042
2040
  return created.data;
2043
2041
  }
2044
2042
  async function readPackageJsonFile(packageJsonPath) {
2045
2043
  try {
2046
- const raw = JSON.parse(await readFile3(packageJsonPath, "utf8"));
2044
+ const raw = JSON.parse(await readFile2(packageJsonPath, "utf8"));
2047
2045
  if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
2048
2046
  throw new Error(i18n.t("packageMustBeObject", { ns: "cli", path: packageJsonPath }));
2049
2047
  }
@@ -2062,20 +2060,9 @@ function readRequiredPackageString(packageJson, key) {
2062
2060
  }
2063
2061
  return value.trim();
2064
2062
  }
2065
- async function writeWorkflowPackageId(packageJsonPath, workflowId) {
2066
- const packageJson = await readPackageJsonFile(packageJsonPath);
2067
- await writeFile2(
2068
- packageJsonPath,
2069
- `${JSON.stringify({
2070
- ...packageJson,
2071
- id: workflowId
2072
- }, null, 2)}
2073
- `
2074
- );
2075
- }
2076
2063
  async function uploadPackage(options) {
2077
- const archiveBuffer = await readFile3(options.archivePath);
2078
- const archiveName = path4.basename(options.archivePath);
2064
+ const archiveBuffer = await readFile2(options.archivePath);
2065
+ const archiveName = path3.basename(options.archivePath);
2079
2066
  const query = new URLSearchParams({ fileName: archiveName });
2080
2067
  if (options.executionTargets !== void 0) {
2081
2068
  query.set("serverRuntime", String(options.executionTargets.server));
@@ -2169,10 +2156,10 @@ async function copyWorkflowSource(sourceDir, targetDir, options = {}) {
2169
2156
  path: JSON.stringify(forbiddenRequiredPath)
2170
2157
  }));
2171
2158
  }
2172
- await mkdir3(targetDir, { recursive: true });
2159
+ await mkdir2(targetDir, { recursive: true });
2173
2160
  for (const file of files) {
2174
- const targetPath = path4.join(targetDir, ...file.path.split("/"));
2175
- await mkdir3(path4.dirname(targetPath), { recursive: true });
2161
+ const targetPath = path3.join(targetDir, ...file.path.split("/"));
2162
+ await mkdir2(path3.dirname(targetPath), { recursive: true });
2176
2163
  await copyFile2(file.absolutePath, targetPath);
2177
2164
  }
2178
2165
  return {
@@ -2191,8 +2178,8 @@ async function stageWorkflowWithLocalDependencies(options) {
2191
2178
  continue;
2192
2179
  }
2193
2180
  visited.add(currentWorkflowName);
2194
- const sourceDir = currentWorkflowName === options.workflowName ? options.workflowDir : path4.join(options.workspaceRoot, currentWorkflowName);
2195
- if (!existsSync2(path4.join(sourceDir, "package.json"))) {
2181
+ const sourceDir = currentWorkflowName === options.workflowName ? options.workflowDir : path3.join(options.workspaceRoot, currentWorkflowName);
2182
+ if (!existsSync2(path3.join(sourceDir, "package.json"))) {
2196
2183
  throw new Error(i18n.t("localDependencyMissingPackage", {
2197
2184
  ns: "cli",
2198
2185
  workflow: options.workflowName,
@@ -2202,7 +2189,7 @@ async function stageWorkflowWithLocalDependencies(options) {
2202
2189
  }
2203
2190
  const uploadPlan = await copyWorkflowSource(
2204
2191
  sourceDir,
2205
- path4.join(options.stagingRoot, currentWorkflowName),
2192
+ path3.join(options.stagingRoot, currentWorkflowName),
2206
2193
  { projectGroupSafe: options.projectGroupSafe }
2207
2194
  );
2208
2195
  if (currentWorkflowName === options.workflowName && !uploadPlan.workflowIgnoreConfigured) {
@@ -2223,11 +2210,11 @@ async function stageWorkflowWithLocalDependencies(options) {
2223
2210
  async function findLocalWorkflowDependencies(sourceDir) {
2224
2211
  const discovered = /* @__PURE__ */ new Set();
2225
2212
  for (const fileName of ["index.ts", "interface.ts", "globals.d.ts"]) {
2226
- const filePath = path4.join(sourceDir, fileName);
2213
+ const filePath = path3.join(sourceDir, fileName);
2227
2214
  if (!existsSync2(filePath)) {
2228
2215
  continue;
2229
2216
  }
2230
- const source = await readFile3(filePath, "utf8");
2217
+ const source = await readFile2(filePath, "utf8");
2231
2218
  for (const match of source.matchAll(/(?:from\s+|reference path=)\"(\.\.\/([^/\"']+)(?:\/[^\"']*)?)\"/g)) {
2232
2219
  const workflowName = match[2]?.trim();
2233
2220
  if (workflowName) {
@@ -2289,7 +2276,6 @@ function parseArgs(argv) {
2289
2276
  server: process.env.WORKFLOW_SERVER_URL ?? authConfig.serverUrl ?? DEFAULT_SERVER_URL,
2290
2277
  token: process.env.WORKFLOW_SERVER_ADMIN_KEY ?? authConfig.apiKey ?? "",
2291
2278
  dependencies: [],
2292
- dataGrants: [],
2293
2279
  desktopPlatforms: []
2294
2280
  };
2295
2281
  for (let index = 0; index < rest.length; index += 1) {
@@ -2355,8 +2341,7 @@ function parseArgs(argv) {
2355
2341
  options.dependencies.push(requireValue(rest, index += 1, "--dependency"));
2356
2342
  break;
2357
2343
  case "--grant-data-access":
2358
- options.dataGrants.push(requireValue(rest, index += 1, "--grant-data-access"));
2359
- break;
2344
+ throw new Error(i18n.t("unknownWorkspaceOption", { ns: "cli", option: arg }));
2360
2345
  case "--project-group":
2361
2346
  options.projectGroup = true;
2362
2347
  break;
@@ -2391,9 +2376,6 @@ function parseArgs(argv) {
2391
2376
  if (options.dependencies.length > 0 && command !== "pack" && command !== "upload" && command !== "publish") {
2392
2377
  throw new Error(i18n.t("dependencyOptionCommandUnsupported", { ns: "cli" }));
2393
2378
  }
2394
- if (options.dataGrants.length > 0 && command !== "upload" && command !== "publish") {
2395
- throw new Error(i18n.t("grantDataAccessCommandUnsupported", { ns: "cli" }));
2396
- }
2397
2379
  if (options.deployment !== void 0 && command !== "publish") {
2398
2380
  throw new Error(i18n.t("deploymentCommandUnsupported", { ns: "cli" }));
2399
2381
  }
@@ -2410,7 +2392,7 @@ function parseArgs(argv) {
2410
2392
  if (options.sourceMode === "bundled" && options.desktopPlatforms.length > 0) {
2411
2393
  throw new Error(i18n.t("desktopPlatformRequiresSource", { ns: "cli" }));
2412
2394
  }
2413
- if (options.deployment !== void 0 && (options.projectGroup === true || options.dependencies.length > 0 || options.dataGrants.length > 0 || options.path !== void 0 || options.file !== void 0 || options.output !== void 0 || options.create === true || options.releaseLog !== void 0 || options.sourceMode !== void 0 || hasExecutionTargetOptions)) {
2395
+ if (options.deployment !== void 0 && (options.projectGroup === true || options.dependencies.length > 0 || options.path !== void 0 || options.file !== void 0 || options.output !== void 0 || options.create === true || options.releaseLog !== void 0 || options.sourceMode !== void 0 || hasExecutionTargetOptions)) {
2414
2396
  throw new Error(i18n.t("deploymentOptionsConflict", { ns: "cli" }));
2415
2397
  }
2416
2398
  return {
@@ -2501,7 +2483,7 @@ function printUsage() {
2501
2483
  }
2502
2484
  function resolveRepoRoot(startDir = process.cwd()) {
2503
2485
  if (process.env.WORKFLOW_REPO_ROOT !== void 0) {
2504
- return path4.resolve(process.env.WORKFLOW_REPO_ROOT);
2486
+ return path3.resolve(process.env.WORKFLOW_REPO_ROOT);
2505
2487
  }
2506
2488
  for (const candidate of [startDir, CLI_MODULE_DIR]) {
2507
2489
  const repoRoot = findWorkspaceRepositoryRoot(candidate);
@@ -2576,7 +2558,7 @@ function readRetryAfterSeconds(data) {
2576
2558
  const value = data.retryAfterSeconds;
2577
2559
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
2578
2560
  }
2579
- if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(path4.resolve(process.argv[1])).href) {
2561
+ if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(path3.resolve(process.argv[1])).href) {
2580
2562
  main().catch((error) => {
2581
2563
  console.error(translateWorkflowCodeError(error));
2582
2564
  process.exitCode = 1;
@@ -2597,13 +2579,11 @@ export {
2597
2579
  readPackageJsonFile,
2598
2580
  readProjectGroupContexts,
2599
2581
  readWorkflowPackageContext,
2600
- resolveExplicitDataGrants,
2601
2582
  resolveRemoteWorkflowId,
2602
2583
  resolveRepoRoot,
2603
2584
  resolveRequestedExecutionTargets,
2604
2585
  shouldUseProjectGroupUpload,
2605
2586
  stageWorkflowWithLocalDependencies,
2606
2587
  waitForDeviceToken,
2607
- waitForPreparation,
2608
- writeWorkflowPackageId
2588
+ waitForPreparation
2609
2589
  };