@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.
- package/dist/chunk-27OW6OJ3.js +276 -0
- package/dist/chunk-DPFPLLLT.js +66 -0
- package/dist/chunk-HZABRDJK.js +169 -0
- package/dist/chunk-NSPRIPOP.js +36 -0
- package/dist/chunk-OLNPMIEF.js +14 -0
- package/dist/chunk-PGM3IPWA.js +174 -0
- package/dist/{chunk-2DNWG5WR.js → chunk-TCYG46PO.js} +664 -484
- package/dist/index.js +19 -4
- package/dist/{local-TCDSZTVL.js → local-R4Q7NLP6.js} +52 -14
- package/dist/mcp-PNIRX64G.js +26643 -0
- package/dist/openai-responses-runner-2MPK3UAP.js +210 -0
- package/dist/openai-runner-stdio-ZQJG73I4.js +8 -0
- package/dist/{workspace-Y4TEIVC7.js → workspace-4DAJK3ZR.js} +448 -468
- package/package.json +12 -6
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
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-
|
|
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(
|
|
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(
|
|
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 = (
|
|
341
|
-
if (!isString(
|
|
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 (!
|
|
363
|
+
if (!path4) {
|
|
348
364
|
return doThrow(`path must not be empty`, TypeError);
|
|
349
365
|
}
|
|
350
|
-
if (checkPath.isNotRelative(
|
|
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 = (
|
|
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
|
|
405
|
+
const path4 = originalPath && checkPath.convert(originalPath);
|
|
390
406
|
checkPath(
|
|
391
|
-
|
|
407
|
+
path4,
|
|
392
408
|
originalPath,
|
|
393
409
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
394
410
|
);
|
|
395
|
-
return this._t(
|
|
411
|
+
return this._t(path4, cache, checkUnignored, slices);
|
|
396
412
|
}
|
|
397
|
-
checkIgnore(
|
|
398
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
399
|
-
return this.test(
|
|
413
|
+
checkIgnore(path4) {
|
|
414
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path4)) {
|
|
415
|
+
return this.test(path4);
|
|
400
416
|
}
|
|
401
|
-
const slices =
|
|
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(
|
|
430
|
+
return this._rules.test(path4, false, MODE_CHECK_IGNORE);
|
|
415
431
|
}
|
|
416
|
-
_t(
|
|
417
|
-
if (
|
|
418
|
-
return cache[
|
|
432
|
+
_t(path4, cache, checkUnignored, slices) {
|
|
433
|
+
if (path4 in cache) {
|
|
434
|
+
return cache[path4];
|
|
419
435
|
}
|
|
420
436
|
if (!slices) {
|
|
421
|
-
slices =
|
|
437
|
+
slices = path4.split(SLASH).filter(Boolean);
|
|
422
438
|
}
|
|
423
439
|
slices.pop();
|
|
424
440
|
if (!slices.length) {
|
|
425
|
-
return cache[
|
|
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[
|
|
449
|
+
return cache[path4] = parent.ignored ? parent : this._rules.test(path4, checkUnignored, MODE_IGNORE);
|
|
434
450
|
}
|
|
435
|
-
ignores(
|
|
436
|
-
return this._test(
|
|
451
|
+
ignores(path4) {
|
|
452
|
+
return this._test(path4, this._ignoreCache, false).ignored;
|
|
437
453
|
}
|
|
438
454
|
createFilter() {
|
|
439
|
-
return (
|
|
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(
|
|
446
|
-
return this._test(
|
|
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 = (
|
|
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 = (
|
|
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
|
|
475
|
-
import
|
|
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
|
|
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 (!
|
|
550
|
+
if (!isRecord(value)) return void 0;
|
|
652
551
|
const workflowCode = value["workflowCode"];
|
|
653
|
-
if (!
|
|
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 (!
|
|
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 (!
|
|
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 && !
|
|
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
|
|
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 =
|
|
851
|
-
const workflowIgnorePath =
|
|
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 =
|
|
872
|
-
const relativePath = normalizeWorkflowUploadPath(
|
|
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
|
-
|
|
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 =
|
|
935
|
-
await mkdir(
|
|
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
|
-
//
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
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
|
|
977
|
-
|
|
978
|
-
|
|
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
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
"
|
|
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
|
-
|
|
994
|
-
|
|
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
|
|
999
|
-
import
|
|
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 ?
|
|
1005
|
+
const initialRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path2.resolve(process.env.WORKFLOW_REPO_ROOT) : defaultRepoRoot;
|
|
1005
1006
|
loadEnvFiles([
|
|
1006
|
-
|
|
1007
|
-
|
|
1007
|
+
path2.join(cliRoot, ".env"),
|
|
1008
|
+
path2.join(initialRepoRoot, ".env")
|
|
1008
1009
|
]);
|
|
1009
|
-
const resolvedRepoRoot = process.env.WORKFLOW_REPO_ROOT ?
|
|
1010
|
+
const resolvedRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path2.resolve(process.env.WORKFLOW_REPO_ROOT) : initialRepoRoot;
|
|
1010
1011
|
if (resolvedRepoRoot !== initialRepoRoot) {
|
|
1011
|
-
loadEnvFiles([
|
|
1012
|
+
loadEnvFiles([path2.join(resolvedRepoRoot, ".env")]);
|
|
1012
1013
|
}
|
|
1013
1014
|
}
|
|
1014
1015
|
function findWorkspaceRepositoryRoot(startDir) {
|
|
1015
|
-
let current =
|
|
1016
|
+
let current = path2.resolve(startDir);
|
|
1016
1017
|
while (true) {
|
|
1017
|
-
if (existsSync(
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
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 ?
|
|
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
|
|
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 ?
|
|
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 ?
|
|
1468
|
-
await
|
|
1469
|
-
await
|
|
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 =
|
|
1473
|
-
await
|
|
1474
|
-
await
|
|
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
|
|
1551
|
-
const
|
|
1552
|
-
if (
|
|
1553
|
-
|
|
1554
|
-
|
|
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.
|
|
1615
|
-
throw new Error(i18n.t("
|
|
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.
|
|
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 =
|
|
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.
|
|
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 :
|
|
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(
|
|
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
|
|
1680
|
-
const stagingRoot =
|
|
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
|
|
1693
|
+
await mkdir2(stagingRoot, { recursive: false });
|
|
1685
1694
|
for (const item of pending) {
|
|
1686
1695
|
const { project, targetDir } = item;
|
|
1687
|
-
const stagingDir =
|
|
1688
|
-
await
|
|
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 =
|
|
1692
|
-
await
|
|
1693
|
-
await
|
|
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(
|
|
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.
|
|
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
|
|
1729
|
+
await rm(targetDir, { recursive: true, force: true }).catch(() => void 0);
|
|
1721
1730
|
}
|
|
1722
1731
|
throw error;
|
|
1723
1732
|
} finally {
|
|
1724
|
-
await
|
|
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(
|
|
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
|
-
|
|
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:
|
|
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 =
|
|
1786
|
-
const packageJson = await readPackageJsonFile(
|
|
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 ?
|
|
1811
|
-
await readPackageJsonFile(
|
|
1812
|
-
const packsDir = process.env.WORKFLOW_WORKSPACE_PACKS_DIR ?
|
|
1813
|
-
const stagingDir =
|
|
1814
|
-
const archivePath = outputPath ?
|
|
1815
|
-
const workspaceRoot = sourcePath === void 0 ?
|
|
1816
|
-
await
|
|
1817
|
-
await
|
|
1818
|
-
await
|
|
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:
|
|
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
|
|
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
|
|
1847
|
-
const
|
|
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
|
|
1844
|
+
const alias = separator < 1 ? "" : option.slice(0, separator).trim();
|
|
1858
1845
|
const dependencyPath = separator < 0 ? "" : option.slice(separator + 1).trim();
|
|
1859
|
-
if (
|
|
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(
|
|
1852
|
+
if (dependencyPaths.has(alias)) {
|
|
1866
1853
|
throw new Error(i18n.t("duplicateDependencySource", {
|
|
1867
1854
|
ns: "cli",
|
|
1868
|
-
|
|
1855
|
+
alias: JSON.stringify(alias)
|
|
1869
1856
|
}));
|
|
1870
1857
|
}
|
|
1871
|
-
dependencyPaths.set(
|
|
1858
|
+
dependencyPaths.set(alias, path3.resolve(dependencyPath));
|
|
1872
1859
|
}
|
|
1873
1860
|
const locks = createWorkflowProjectDependencyLocks(
|
|
1874
|
-
|
|
1875
|
-
[...dependencyPaths.keys()].map((
|
|
1861
|
+
relatedProjects,
|
|
1862
|
+
[...dependencyPaths.keys()].map((alias) => ({ alias, delivery: "included" }))
|
|
1876
1863
|
);
|
|
1877
1864
|
const dependenciesByProject = /* @__PURE__ */ new Map();
|
|
1878
|
-
for (const [
|
|
1879
|
-
const
|
|
1880
|
-
const context = await readWorkflowPackageContext(
|
|
1881
|
-
if (context.
|
|
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
|
-
|
|
1891
|
-
projectId: JSON.stringify(
|
|
1871
|
+
alias: JSON.stringify(alias),
|
|
1872
|
+
projectId: JSON.stringify(relation.projectId)
|
|
1892
1873
|
}));
|
|
1893
1874
|
}
|
|
1894
|
-
|
|
1895
|
-
|
|
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(
|
|
1886
|
+
projectId: JSON.stringify(relation.projectId)
|
|
1899
1887
|
}));
|
|
1900
1888
|
}
|
|
1901
|
-
dependenciesByProject.set(
|
|
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 ?
|
|
1909
|
-
const groupRoot =
|
|
1910
|
-
const projectsDir =
|
|
1911
|
-
const archivePath = options.outputPath ?
|
|
1912
|
-
await
|
|
1913
|
-
await
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
1952
|
+
await rm(groupRoot, { recursive: true, force: true });
|
|
1964
1953
|
}
|
|
1965
1954
|
}
|
|
1966
1955
|
async function uploadProjectGroupPackage(options) {
|
|
1967
|
-
const archiveBuffer = await
|
|
1968
|
-
const archiveName =
|
|
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 ?
|
|
2007
|
-
const packageJsonPath =
|
|
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
|
-
|
|
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 (
|
|
2040
|
-
|
|
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
|
|
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
|
|
2078
|
-
const archiveName =
|
|
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
|
|
2159
|
+
await mkdir2(targetDir, { recursive: true });
|
|
2173
2160
|
for (const file of files) {
|
|
2174
|
-
const targetPath =
|
|
2175
|
-
await
|
|
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 :
|
|
2195
|
-
if (!existsSync2(
|
|
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
|
-
|
|
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 =
|
|
2213
|
+
const filePath = path3.join(sourceDir, fileName);
|
|
2227
2214
|
if (!existsSync2(filePath)) {
|
|
2228
2215
|
continue;
|
|
2229
2216
|
}
|
|
2230
|
-
const source = await
|
|
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
|
-
|
|
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.
|
|
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
|
|
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(
|
|
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
|
};
|