@workflow-code/cli 0.1.0 → 0.1.2
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.
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
__commonJS,
|
|
30
|
+
__toESM
|
|
31
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-FYS2JH42.js";
|
|
2
3
|
|
|
3
4
|
// src/index.ts
|
|
4
5
|
import path from "path";
|
|
5
6
|
import { pathToFileURL } from "url";
|
|
6
7
|
async function main(argv = process.argv.slice(2)) {
|
|
7
8
|
if (argv[0] === "workspace") {
|
|
8
|
-
const workspaceCli = await import("./workspace-
|
|
9
|
+
const workspaceCli = await import("./workspace-QUP6RU65.js");
|
|
9
10
|
await workspaceCli.main(argv.slice(1));
|
|
10
11
|
return typeof process.exitCode === "number" ? process.exitCode : 0;
|
|
11
12
|
}
|
|
@@ -16,7 +17,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
16
17
|
}
|
|
17
18
|
const { register } = await import("tsx/esm/api");
|
|
18
19
|
register();
|
|
19
|
-
const localCli = await import("./local-
|
|
20
|
+
const localCli = await import("./local-6VUUVT3C.js");
|
|
20
21
|
return localCli.main(argv);
|
|
21
22
|
}
|
|
22
23
|
function formatHelp() {
|
|
@@ -1,11 +1,474 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
__commonJS,
|
|
4
|
+
__toESM
|
|
5
|
+
} from "./chunk-FYS2JH42.js";
|
|
6
|
+
|
|
7
|
+
// ../../node_modules/.pnpm/ignore@7.0.6/node_modules/ignore/index.js
|
|
8
|
+
var require_ignore = __commonJS({
|
|
9
|
+
"../../node_modules/.pnpm/ignore@7.0.6/node_modules/ignore/index.js"(exports, module) {
|
|
10
|
+
"use strict";
|
|
11
|
+
function makeArray(subject) {
|
|
12
|
+
return Array.isArray(subject) ? subject : [subject];
|
|
13
|
+
}
|
|
14
|
+
var UNDEFINED = void 0;
|
|
15
|
+
var EMPTY = "";
|
|
16
|
+
var SPACE = " ";
|
|
17
|
+
var ESCAPE = "\\";
|
|
18
|
+
var REGEX_TEST_BLANK_LINE = /^\s+$/;
|
|
19
|
+
var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
|
|
20
|
+
var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
|
|
21
|
+
var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
|
|
22
|
+
var REGEX_SPLITALL_CRLF = /\r?\n/g;
|
|
23
|
+
var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
|
|
24
|
+
var REGEX_TEST_TRAILING_SLASH = /\/$/;
|
|
25
|
+
var SLASH = "/";
|
|
26
|
+
var TMP_KEY_IGNORE = "node-ignore";
|
|
27
|
+
if (typeof Symbol !== "undefined") {
|
|
28
|
+
TMP_KEY_IGNORE = /* @__PURE__ */ Symbol.for("node-ignore");
|
|
29
|
+
}
|
|
30
|
+
var KEY_IGNORE = TMP_KEY_IGNORE;
|
|
31
|
+
var define = (object, key, value) => {
|
|
32
|
+
Object.defineProperty(object, key, { value });
|
|
33
|
+
return value;
|
|
34
|
+
};
|
|
35
|
+
var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
|
|
36
|
+
var RETURN_FALSE = () => false;
|
|
37
|
+
var sanitizeRange = (range) => range.replace(
|
|
38
|
+
REGEX_REGEXP_RANGE,
|
|
39
|
+
(match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match : EMPTY
|
|
40
|
+
);
|
|
41
|
+
var negateRange = (range) => range.startsWith("!") || range.startsWith("\\^") ? `^${range.slice(range[0] === "!" ? 1 : 2)}` : range;
|
|
42
|
+
var cleanRangeBackSlash = (slashes) => {
|
|
43
|
+
const { length } = slashes;
|
|
44
|
+
return slashes.slice(0, length - length % 2);
|
|
45
|
+
};
|
|
46
|
+
var REPLACERS = [
|
|
47
|
+
[
|
|
48
|
+
// Remove BOM
|
|
49
|
+
// TODO:
|
|
50
|
+
// Other similar zero-width characters?
|
|
51
|
+
/^\uFEFF/,
|
|
52
|
+
() => EMPTY
|
|
53
|
+
],
|
|
54
|
+
// > Trailing spaces are ignored unless they are quoted with backslash ("\")
|
|
55
|
+
[
|
|
56
|
+
// (a\ ) -> (a )
|
|
57
|
+
// (a ) -> (a)
|
|
58
|
+
// (a ) -> (a)
|
|
59
|
+
// (a \ ) -> (a )
|
|
60
|
+
/((?:\\\\)*?)(\\?\s+)$/,
|
|
61
|
+
(_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
|
|
62
|
+
],
|
|
63
|
+
// Replace (\ ) with ' '
|
|
64
|
+
// (\ ) -> ' '
|
|
65
|
+
// (\\ ) -> '\\ '
|
|
66
|
+
// (\\\ ) -> '\\ '
|
|
67
|
+
[
|
|
68
|
+
/(\\+?)\s/g,
|
|
69
|
+
(_, m1) => {
|
|
70
|
+
const { length } = m1;
|
|
71
|
+
return m1.slice(0, length - length % 2) + SPACE;
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
// Escape metacharacters
|
|
75
|
+
// which is written down by users but means special for regular expressions.
|
|
76
|
+
// > There are 12 characters with special meanings:
|
|
77
|
+
// > - the backslash \,
|
|
78
|
+
// > - the caret ^,
|
|
79
|
+
// > - the dollar sign $,
|
|
80
|
+
// > - the period or dot .,
|
|
81
|
+
// > - the vertical bar or pipe symbol |,
|
|
82
|
+
// > - the question mark ?,
|
|
83
|
+
// > - the asterisk or star *,
|
|
84
|
+
// > - the plus sign +,
|
|
85
|
+
// > - the opening parenthesis (,
|
|
86
|
+
// > - the closing parenthesis ),
|
|
87
|
+
// > - and the opening square bracket [,
|
|
88
|
+
// > - the opening curly brace {,
|
|
89
|
+
// > These special characters are often called "metacharacters".
|
|
90
|
+
[
|
|
91
|
+
/[\\$.|*+(){^]/g,
|
|
92
|
+
(match) => `\\${match}`
|
|
93
|
+
],
|
|
94
|
+
[
|
|
95
|
+
// > a question mark (?) matches a single character
|
|
96
|
+
/(?!\\)\?/g,
|
|
97
|
+
() => "[^/]"
|
|
98
|
+
],
|
|
99
|
+
// leading slash
|
|
100
|
+
[
|
|
101
|
+
// > A leading slash matches the beginning of the pathname.
|
|
102
|
+
// > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
|
|
103
|
+
// A leading slash matches the beginning of the pathname
|
|
104
|
+
/^\//,
|
|
105
|
+
() => "^"
|
|
106
|
+
],
|
|
107
|
+
// replace special metacharacter slash after the leading slash
|
|
108
|
+
[
|
|
109
|
+
/\//g,
|
|
110
|
+
() => "\\/"
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
// > A leading "**" followed by a slash means match in all directories.
|
|
114
|
+
// > For example, "**/foo" matches file or directory "foo" anywhere,
|
|
115
|
+
// > the same as pattern "foo".
|
|
116
|
+
// > "**/foo/bar" matches file or directory "bar" anywhere that is directly
|
|
117
|
+
// > under directory "foo".
|
|
118
|
+
// Notice that the '*'s have been replaced as '\\*'
|
|
119
|
+
/^\^*(?:\\\*\\\*\\\/)+/,
|
|
120
|
+
// '**/foo' <-> 'foo'
|
|
121
|
+
() => "^(?:.*\\/)?"
|
|
122
|
+
],
|
|
123
|
+
// starting
|
|
124
|
+
[
|
|
125
|
+
// there will be no leading '/'
|
|
126
|
+
// (which has been replaced by section "leading slash")
|
|
127
|
+
// If starts with '**', adding a '^' to the regular expression also works
|
|
128
|
+
/^(?=[^^])/,
|
|
129
|
+
function startingReplacer() {
|
|
130
|
+
return !/\/(?!$)/.test(this) ? "(?:^|\\/)" : "^";
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
// two globstars
|
|
134
|
+
[
|
|
135
|
+
// Use lookahead assertions so that we could match more than one `'/**'`
|
|
136
|
+
/\\\/\\\*\\\*(?=\\\/|$)/g,
|
|
137
|
+
// Zero, one or several directories
|
|
138
|
+
// should not use '*', or it will be replaced by the next replacer
|
|
139
|
+
// Check if it is not the last `'/**'`
|
|
140
|
+
(_, index, str) => index + 6 < str.length ? "(?:\\/[^\\/]+)*" : "\\/.+"
|
|
141
|
+
],
|
|
142
|
+
// normal intermediate wildcards
|
|
143
|
+
[
|
|
144
|
+
// Never replace escaped '*'
|
|
145
|
+
// ignore rule '\*' will match the path '*'
|
|
146
|
+
// 'abc.*/' -> go
|
|
147
|
+
// 'abc.*' -> skip this rule,
|
|
148
|
+
// coz trailing single wildcard will be handed by [trailing wildcard]
|
|
149
|
+
/(^|[^\\]+)(\\\*)+(?=.+)/g,
|
|
150
|
+
// '*.js' matches '.js'
|
|
151
|
+
// '*.js' doesn't match 'abc'
|
|
152
|
+
(_, p1, p2) => {
|
|
153
|
+
const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
|
|
154
|
+
return p1 + unescaped;
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
[
|
|
158
|
+
// unescape, revert step 3 except for back slash
|
|
159
|
+
// For example, if a user escape a '\\*',
|
|
160
|
+
// after step 3, the result will be '\\\\\\*'
|
|
161
|
+
/\\\\\\(?=[$.|*+(){^])/g,
|
|
162
|
+
() => ESCAPE
|
|
163
|
+
],
|
|
164
|
+
[
|
|
165
|
+
// '\\\\' -> '\\'
|
|
166
|
+
/\\\\/g,
|
|
167
|
+
() => ESCAPE
|
|
168
|
+
],
|
|
169
|
+
[
|
|
170
|
+
// > The range notation, e.g. [a-zA-Z],
|
|
171
|
+
// > can be used to match one of the characters in a range.
|
|
172
|
+
// `\` is escaped by step 3
|
|
173
|
+
/(\\)?\[([^\]/]*?)(\\*)($|\])/g,
|
|
174
|
+
(match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` : close === "]" ? endEscape.length % 2 === 0 ? `[${negateRange(sanitizeRange(range))}${endEscape}]` : "[]" : "[]"
|
|
175
|
+
],
|
|
176
|
+
// ending
|
|
177
|
+
[
|
|
178
|
+
// 'js' will not match 'js.'
|
|
179
|
+
// 'ab' will not match 'abc'
|
|
180
|
+
/(?:[^*])$/,
|
|
181
|
+
// WTF!
|
|
182
|
+
// https://git-scm.com/docs/gitignore
|
|
183
|
+
// changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
|
|
184
|
+
// which re-fixes #24, #38
|
|
185
|
+
// > If there is a separator at the end of the pattern then the pattern
|
|
186
|
+
// > will only match directories, otherwise the pattern can match both
|
|
187
|
+
// > files and directories.
|
|
188
|
+
// 'js*' will not match 'a.js'
|
|
189
|
+
// 'js/' will not match 'a.js'
|
|
190
|
+
// 'js' will match 'a.js' and 'a.js/'
|
|
191
|
+
(match) => /\/$/.test(match) ? `${match}$` : `${match}(?=$|\\/$)`
|
|
192
|
+
]
|
|
193
|
+
];
|
|
194
|
+
var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
|
|
195
|
+
var MODE_IGNORE = "regex";
|
|
196
|
+
var MODE_CHECK_IGNORE = "checkRegex";
|
|
197
|
+
var UNDERSCORE = "_";
|
|
198
|
+
var TRAILING_WILD_CARD_REPLACERS = {
|
|
199
|
+
[MODE_IGNORE](_, p1) {
|
|
200
|
+
const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
|
|
201
|
+
return `${prefix}(?=$|\\/$)`;
|
|
202
|
+
},
|
|
203
|
+
[MODE_CHECK_IGNORE](_, p1) {
|
|
204
|
+
const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
|
|
205
|
+
return `${prefix}(?=$|\\/$)`;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
var makeRegexPrefix = (pattern) => REPLACERS.reduce(
|
|
209
|
+
(prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)),
|
|
210
|
+
pattern
|
|
211
|
+
);
|
|
212
|
+
var isString = (subject) => typeof subject === "string";
|
|
213
|
+
var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
|
|
214
|
+
var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
|
|
215
|
+
var IgnoreRule = class {
|
|
216
|
+
constructor(pattern, mark, body, ignoreCase, negative, prefix) {
|
|
217
|
+
this.pattern = pattern;
|
|
218
|
+
this.mark = mark;
|
|
219
|
+
this.negative = negative;
|
|
220
|
+
define(this, "body", body);
|
|
221
|
+
define(this, "ignoreCase", ignoreCase);
|
|
222
|
+
define(this, "regexPrefix", prefix);
|
|
223
|
+
}
|
|
224
|
+
get regex() {
|
|
225
|
+
const key = UNDERSCORE + MODE_IGNORE;
|
|
226
|
+
if (this[key]) {
|
|
227
|
+
return this[key];
|
|
228
|
+
}
|
|
229
|
+
return this._make(MODE_IGNORE, key);
|
|
230
|
+
}
|
|
231
|
+
get checkRegex() {
|
|
232
|
+
const key = UNDERSCORE + MODE_CHECK_IGNORE;
|
|
233
|
+
if (this[key]) {
|
|
234
|
+
return this[key];
|
|
235
|
+
}
|
|
236
|
+
return this._make(MODE_CHECK_IGNORE, key);
|
|
237
|
+
}
|
|
238
|
+
_make(mode, key) {
|
|
239
|
+
const str = this.regexPrefix.replace(
|
|
240
|
+
REGEX_REPLACE_TRAILING_WILDCARD,
|
|
241
|
+
// It does not need to bind pattern
|
|
242
|
+
TRAILING_WILD_CARD_REPLACERS[mode]
|
|
243
|
+
);
|
|
244
|
+
const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
|
|
245
|
+
return define(this, key, regex);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
var createRule = ({
|
|
249
|
+
pattern,
|
|
250
|
+
mark
|
|
251
|
+
}, ignoreCase) => {
|
|
252
|
+
let negative = false;
|
|
253
|
+
let body = pattern;
|
|
254
|
+
if (body.indexOf("!") === 0) {
|
|
255
|
+
negative = true;
|
|
256
|
+
body = body.substr(1);
|
|
257
|
+
}
|
|
258
|
+
body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
|
|
259
|
+
const regexPrefix = makeRegexPrefix(body);
|
|
260
|
+
return new IgnoreRule(
|
|
261
|
+
pattern,
|
|
262
|
+
mark,
|
|
263
|
+
body,
|
|
264
|
+
ignoreCase,
|
|
265
|
+
negative,
|
|
266
|
+
regexPrefix
|
|
267
|
+
);
|
|
268
|
+
};
|
|
269
|
+
var RuleManager = class {
|
|
270
|
+
constructor(ignoreCase) {
|
|
271
|
+
this._ignoreCase = ignoreCase;
|
|
272
|
+
this._rules = [];
|
|
273
|
+
}
|
|
274
|
+
_add(pattern) {
|
|
275
|
+
if (pattern && pattern[KEY_IGNORE]) {
|
|
276
|
+
this._rules = this._rules.concat(pattern._rules._rules);
|
|
277
|
+
this._added = true;
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (isString(pattern)) {
|
|
281
|
+
pattern = {
|
|
282
|
+
pattern
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
if (checkPattern(pattern.pattern)) {
|
|
286
|
+
const rule = createRule(pattern, this._ignoreCase);
|
|
287
|
+
this._added = true;
|
|
288
|
+
this._rules.push(rule);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// @param {Array<string> | string | Ignore} pattern
|
|
292
|
+
add(pattern) {
|
|
293
|
+
this._added = false;
|
|
294
|
+
makeArray(
|
|
295
|
+
isString(pattern) ? splitPattern(pattern) : pattern
|
|
296
|
+
).forEach(this._add, this);
|
|
297
|
+
return this._added;
|
|
298
|
+
}
|
|
299
|
+
// Test one single path without recursively checking parent directories
|
|
300
|
+
//
|
|
301
|
+
// - checkUnignored `boolean` whether should check if the path is unignored,
|
|
302
|
+
// setting `checkUnignored` to `false` could reduce additional
|
|
303
|
+
// path matching.
|
|
304
|
+
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
305
|
+
// @returns {TestResult} true if a file is ignored
|
|
306
|
+
test(path5, checkUnignored, mode) {
|
|
307
|
+
let ignored = false;
|
|
308
|
+
let unignored = false;
|
|
309
|
+
let matchedRule;
|
|
310
|
+
this._rules.forEach((rule) => {
|
|
311
|
+
const { negative } = rule;
|
|
312
|
+
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const matched = rule[mode].test(path5);
|
|
316
|
+
if (!matched) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
ignored = !negative;
|
|
320
|
+
unignored = negative;
|
|
321
|
+
matchedRule = negative ? UNDEFINED : rule;
|
|
322
|
+
});
|
|
323
|
+
const ret = {
|
|
324
|
+
ignored,
|
|
325
|
+
unignored
|
|
326
|
+
};
|
|
327
|
+
if (matchedRule) {
|
|
328
|
+
ret.rule = matchedRule;
|
|
329
|
+
}
|
|
330
|
+
return ret;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
var throwError = (message, Ctor) => {
|
|
334
|
+
throw new Ctor(message);
|
|
335
|
+
};
|
|
336
|
+
var checkPath = (path5, originalPath, doThrow) => {
|
|
337
|
+
if (!isString(path5)) {
|
|
338
|
+
return doThrow(
|
|
339
|
+
`path must be a string, but got \`${originalPath}\``,
|
|
340
|
+
TypeError
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
if (!path5) {
|
|
344
|
+
return doThrow(`path must not be empty`, TypeError);
|
|
345
|
+
}
|
|
346
|
+
if (checkPath.isNotRelative(path5)) {
|
|
347
|
+
const r = "`path.relative()`d";
|
|
348
|
+
return doThrow(
|
|
349
|
+
`path should be a ${r} string, but got "${originalPath}"`,
|
|
350
|
+
RangeError
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
return true;
|
|
354
|
+
};
|
|
355
|
+
var isNotRelative = (path5) => REGEX_TEST_INVALID_PATH.test(path5);
|
|
356
|
+
checkPath.isNotRelative = isNotRelative;
|
|
357
|
+
checkPath.convert = (p) => p;
|
|
358
|
+
var Ignore = class {
|
|
359
|
+
constructor({
|
|
360
|
+
ignorecase = true,
|
|
361
|
+
ignoreCase = ignorecase,
|
|
362
|
+
allowRelativePaths = false
|
|
363
|
+
} = {}) {
|
|
364
|
+
define(this, KEY_IGNORE, true);
|
|
365
|
+
this._rules = new RuleManager(ignoreCase);
|
|
366
|
+
this._strictPathCheck = !allowRelativePaths;
|
|
367
|
+
this._initCache();
|
|
368
|
+
}
|
|
369
|
+
_initCache() {
|
|
370
|
+
this._ignoreCache = /* @__PURE__ */ Object.create(null);
|
|
371
|
+
this._testCache = /* @__PURE__ */ Object.create(null);
|
|
372
|
+
}
|
|
373
|
+
add(pattern) {
|
|
374
|
+
if (this._rules.add(pattern)) {
|
|
375
|
+
this._initCache();
|
|
376
|
+
}
|
|
377
|
+
return this;
|
|
378
|
+
}
|
|
379
|
+
// legacy
|
|
380
|
+
addPattern(pattern) {
|
|
381
|
+
return this.add(pattern);
|
|
382
|
+
}
|
|
383
|
+
// @returns {TestResult}
|
|
384
|
+
_test(originalPath, cache, checkUnignored, slices) {
|
|
385
|
+
const path5 = originalPath && checkPath.convert(originalPath);
|
|
386
|
+
checkPath(
|
|
387
|
+
path5,
|
|
388
|
+
originalPath,
|
|
389
|
+
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
390
|
+
);
|
|
391
|
+
return this._t(path5, cache, checkUnignored, slices);
|
|
392
|
+
}
|
|
393
|
+
checkIgnore(path5) {
|
|
394
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path5)) {
|
|
395
|
+
return this.test(path5);
|
|
396
|
+
}
|
|
397
|
+
const slices = path5.split(SLASH).filter(Boolean);
|
|
398
|
+
slices.pop();
|
|
399
|
+
if (slices.length) {
|
|
400
|
+
const parent = this._t(
|
|
401
|
+
slices.join(SLASH) + SLASH,
|
|
402
|
+
this._testCache,
|
|
403
|
+
true,
|
|
404
|
+
slices
|
|
405
|
+
);
|
|
406
|
+
if (parent.ignored) {
|
|
407
|
+
return parent;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return this._rules.test(path5, false, MODE_CHECK_IGNORE);
|
|
411
|
+
}
|
|
412
|
+
_t(path5, cache, checkUnignored, slices) {
|
|
413
|
+
if (path5 in cache) {
|
|
414
|
+
return cache[path5];
|
|
415
|
+
}
|
|
416
|
+
if (!slices) {
|
|
417
|
+
slices = path5.split(SLASH).filter(Boolean);
|
|
418
|
+
}
|
|
419
|
+
slices.pop();
|
|
420
|
+
if (!slices.length) {
|
|
421
|
+
return cache[path5] = this._rules.test(path5, checkUnignored, MODE_IGNORE);
|
|
422
|
+
}
|
|
423
|
+
const parent = this._t(
|
|
424
|
+
slices.join(SLASH) + SLASH,
|
|
425
|
+
cache,
|
|
426
|
+
checkUnignored,
|
|
427
|
+
slices
|
|
428
|
+
);
|
|
429
|
+
return cache[path5] = parent.ignored ? parent : this._rules.test(path5, checkUnignored, MODE_IGNORE);
|
|
430
|
+
}
|
|
431
|
+
ignores(path5) {
|
|
432
|
+
return this._test(path5, this._ignoreCache, false).ignored;
|
|
433
|
+
}
|
|
434
|
+
createFilter() {
|
|
435
|
+
return (path5) => !this.ignores(path5);
|
|
436
|
+
}
|
|
437
|
+
filter(paths) {
|
|
438
|
+
return makeArray(paths).filter(this.createFilter());
|
|
439
|
+
}
|
|
440
|
+
// @returns {TestResult}
|
|
441
|
+
test(path5) {
|
|
442
|
+
return this._test(path5, this._testCache, true);
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
var factory = (options) => new Ignore(options);
|
|
446
|
+
var isPathValid = (path5) => checkPath(path5 && checkPath.convert(path5), path5, RETURN_FALSE);
|
|
447
|
+
var setupWindows = () => {
|
|
448
|
+
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
449
|
+
checkPath.convert = makePosix;
|
|
450
|
+
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
451
|
+
checkPath.isNotRelative = (path5) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path5) || isNotRelative(path5);
|
|
452
|
+
};
|
|
453
|
+
if (
|
|
454
|
+
// Detect `process` so that it can run in browsers.
|
|
455
|
+
typeof process !== "undefined" && process.platform === "win32"
|
|
456
|
+
) {
|
|
457
|
+
setupWindows();
|
|
458
|
+
}
|
|
459
|
+
module.exports = factory;
|
|
460
|
+
factory.default = factory;
|
|
461
|
+
module.exports.isPathValid = isPathValid;
|
|
462
|
+
define(module.exports, /* @__PURE__ */ Symbol.for("setupWindows"), setupWindows);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
2
465
|
|
|
3
466
|
// src/workspace.ts
|
|
4
467
|
import { spawn } from "child_process";
|
|
5
468
|
import { randomUUID } from "crypto";
|
|
6
469
|
import { existsSync as existsSync2 } from "fs";
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
470
|
+
import { mkdir as mkdir3, readFile as readFile3, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
471
|
+
import path4 from "path";
|
|
9
472
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
10
473
|
|
|
11
474
|
// ../../shared/auth-config/index.ts
|
|
@@ -120,12 +583,267 @@ function isWorkflowUuid(value) {
|
|
|
120
583
|
return WORKFLOW_UUID_PATTERN.test(value.trim());
|
|
121
584
|
}
|
|
122
585
|
|
|
586
|
+
// ../../shared/project-upload/node.ts
|
|
587
|
+
import { copyFile, lstat, mkdir, readFile, readdir } from "fs/promises";
|
|
588
|
+
import path2 from "path";
|
|
589
|
+
|
|
590
|
+
// ../../shared/project-upload/index.ts
|
|
591
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
592
|
+
|
|
593
|
+
// ../../shared/kanban-project/index.ts
|
|
594
|
+
var KANBAN_MANIFEST_FILE = "kanban.json";
|
|
595
|
+
var KANBAN_ENTRY_FILE = "index.html";
|
|
596
|
+
var KANBAN_ARTIFACT_DIR = ".";
|
|
597
|
+
function readPackageProjectType(value) {
|
|
598
|
+
if (!isRecord2(value)) return void 0;
|
|
599
|
+
const workflowCode = value["workflowCode"];
|
|
600
|
+
if (!isRecord2(workflowCode)) return void 0;
|
|
601
|
+
return workflowCode["projectType"] === "kanban" ? "kanban" : void 0;
|
|
602
|
+
}
|
|
603
|
+
function readKanbanArtifactConfig(value) {
|
|
604
|
+
if (!isRecord2(value)) {
|
|
605
|
+
throw new Error("package.json root must be an object.");
|
|
606
|
+
}
|
|
607
|
+
const workflowCode = value["workflowCode"];
|
|
608
|
+
if (!isRecord2(workflowCode)) {
|
|
609
|
+
throw new Error("package.json workflowCode must be an object for a Kanban project.");
|
|
610
|
+
}
|
|
611
|
+
const rawConfig = workflowCode["kanban"];
|
|
612
|
+
if (rawConfig !== void 0 && !isRecord2(rawConfig)) {
|
|
613
|
+
throw new Error("package.json workflowCode.kanban must be an object.");
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
artifactDir: readKanbanRelativePath(
|
|
617
|
+
rawConfig?.["artifactDir"],
|
|
618
|
+
"workflowCode.kanban.artifactDir",
|
|
619
|
+
KANBAN_ARTIFACT_DIR,
|
|
620
|
+
true
|
|
621
|
+
),
|
|
622
|
+
entry: readKanbanRelativePath(
|
|
623
|
+
rawConfig?.["entry"],
|
|
624
|
+
"workflowCode.kanban.entry",
|
|
625
|
+
KANBAN_ENTRY_FILE,
|
|
626
|
+
false
|
|
627
|
+
)
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function createKanbanArtifactEntryPath(config) {
|
|
631
|
+
return config.artifactDir === KANBAN_ARTIFACT_DIR ? config.entry : `${config.artifactDir}/${config.entry}`;
|
|
632
|
+
}
|
|
633
|
+
function readKanbanRelativePath(value, field, fallback, allowDot) {
|
|
634
|
+
const raw = value === void 0 ? fallback : value;
|
|
635
|
+
if (typeof raw !== "string" || raw.trim() === "") {
|
|
636
|
+
throw new Error(`package.json ${field} must be a non-empty string.`);
|
|
637
|
+
}
|
|
638
|
+
const normalized = raw.trim().replaceAll("\\", "/").replace(/\/+$/, "");
|
|
639
|
+
if (allowDot && normalized === ".") return normalized;
|
|
640
|
+
if (normalized === "" || normalized === "." || normalized.startsWith("/") || normalized.startsWith("//") || /^[a-zA-Z]:/.test(normalized) || normalized.includes("\0") || normalized.split("/").some((part) => part === "" || part === "." || part === "..")) {
|
|
641
|
+
throw new Error(`package.json ${field} must be a safe project-relative path.`);
|
|
642
|
+
}
|
|
643
|
+
const reservedDirectory = normalized.split("/").find((part) => [".git", ".hg", ".svn", "node_modules"].includes(part.toLowerCase()));
|
|
644
|
+
if (reservedDirectory !== void 0) {
|
|
645
|
+
throw new Error(
|
|
646
|
+
`package.json ${field} must not use reserved directory ${JSON.stringify(reservedDirectory)}.`
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
if (!allowDot && !/\.html?$/i.test(normalized)) {
|
|
650
|
+
throw new Error(`package.json ${field} must point to an HTML file.`);
|
|
651
|
+
}
|
|
652
|
+
return normalized;
|
|
653
|
+
}
|
|
654
|
+
function isRecord2(value) {
|
|
655
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// ../../shared/project-upload/index.ts
|
|
659
|
+
var WORKFLOW_IGNORE_FILE = ".workflowignore";
|
|
660
|
+
function hasWorkflowIgnoreRules(content) {
|
|
661
|
+
if (content === void 0) return false;
|
|
662
|
+
return content.split(/\r?\n/).some((line) => {
|
|
663
|
+
const trimmed = line.trim();
|
|
664
|
+
return trimmed !== "" && !trimmed.startsWith("#");
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
function resolveWorkflowUploadRequiredPaths(packageJson, availablePaths) {
|
|
668
|
+
const normalizedAvailablePaths = new Set(
|
|
669
|
+
Array.from(availablePaths, (filePath) => normalizeWorkflowUploadPath(filePath))
|
|
670
|
+
);
|
|
671
|
+
if (readPackageProjectType(packageJson) === "kanban") {
|
|
672
|
+
const artifact = readKanbanArtifactConfig(packageJson);
|
|
673
|
+
return [
|
|
674
|
+
"package.json",
|
|
675
|
+
createKanbanArtifactEntryPath(artifact),
|
|
676
|
+
...normalizedAvailablePaths.has(KANBAN_MANIFEST_FILE) ? [KANBAN_MANIFEST_FILE] : []
|
|
677
|
+
];
|
|
678
|
+
}
|
|
679
|
+
return ["package.json", "index.ts"];
|
|
680
|
+
}
|
|
681
|
+
function createWorkflowUploadMatcher(content) {
|
|
682
|
+
const ruleLines = content === void 0 ? [] : content.split(/\r?\n/);
|
|
683
|
+
const matcher = (0, import_ignore.default)().add(ruleLines);
|
|
684
|
+
return {
|
|
685
|
+
ignores(relativePath, options) {
|
|
686
|
+
const normalized = normalizeWorkflowUploadPath(relativePath, options);
|
|
687
|
+
return normalized === WORKFLOW_IGNORE_FILE ? false : matcher.ignores(normalized);
|
|
688
|
+
},
|
|
689
|
+
explain(relativePath, options) {
|
|
690
|
+
const normalized = normalizeWorkflowUploadPath(relativePath, options);
|
|
691
|
+
if (normalized === WORKFLOW_IGNORE_FILE) return void 0;
|
|
692
|
+
return findEffectiveWorkflowIgnoreRule(normalized, ruleLines);
|
|
693
|
+
},
|
|
694
|
+
assertRequiredPaths(relativePaths) {
|
|
695
|
+
for (const relativePath of relativePaths) {
|
|
696
|
+
const normalized = normalizeWorkflowUploadPath(relativePath);
|
|
697
|
+
if (!matcher.ignores(normalized)) continue;
|
|
698
|
+
const rule = findEffectiveWorkflowIgnoreRule(normalized, ruleLines);
|
|
699
|
+
const suffix = rule === void 0 ? "" : ` by rule ${JSON.stringify(rule)}`;
|
|
700
|
+
throw new Error(
|
|
701
|
+
`Required upload path ${JSON.stringify(normalized)} is excluded by ${WORKFLOW_IGNORE_FILE}${suffix}.`
|
|
702
|
+
);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
function normalizeWorkflowUploadPath(relativePath, options = {}) {
|
|
708
|
+
const normalized = relativePath.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
709
|
+
const withoutTrailingSlash = normalized.replace(/\/+$/, "");
|
|
710
|
+
if (withoutTrailingSlash === "" || withoutTrailingSlash.startsWith("/") || /^[a-zA-Z]:/.test(withoutTrailingSlash) || withoutTrailingSlash.includes("\0") || withoutTrailingSlash.split("/").some((part) => part === "" || part === "." || part === "..")) {
|
|
711
|
+
throw new Error(`Invalid workflow upload path ${JSON.stringify(relativePath)}.`);
|
|
712
|
+
}
|
|
713
|
+
return options.directory === true ? `${withoutTrailingSlash}/` : withoutTrailingSlash;
|
|
714
|
+
}
|
|
715
|
+
function createWorkflowUploadPortablePathKey(relativePath) {
|
|
716
|
+
return normalizeWorkflowUploadPath(relativePath).normalize("NFC").toLowerCase();
|
|
717
|
+
}
|
|
718
|
+
function findEffectiveWorkflowIgnoreRule(normalizedPath, ruleLines) {
|
|
719
|
+
const matcher = (0, import_ignore.default)();
|
|
720
|
+
let ignored = false;
|
|
721
|
+
let effectiveRule;
|
|
722
|
+
for (const ruleLine of ruleLines) {
|
|
723
|
+
matcher.add(ruleLine);
|
|
724
|
+
const nextIgnored = matcher.ignores(normalizedPath);
|
|
725
|
+
if (nextIgnored !== ignored) {
|
|
726
|
+
ignored = nextIgnored;
|
|
727
|
+
effectiveRule = ruleLine;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return ignored ? effectiveRule : void 0;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// ../../shared/project-upload/node.ts
|
|
734
|
+
async function createWorkflowUploadPlan(rootDir) {
|
|
735
|
+
const projectRoot = path2.resolve(rootDir);
|
|
736
|
+
const workflowIgnorePath = path2.join(projectRoot, WORKFLOW_IGNORE_FILE);
|
|
737
|
+
const workflowIgnoreStat = await lstat(workflowIgnorePath).catch(() => void 0);
|
|
738
|
+
if (workflowIgnoreStat?.isSymbolicLink()) {
|
|
739
|
+
throw new Error(`${WORKFLOW_IGNORE_FILE} must be a regular file.`);
|
|
740
|
+
}
|
|
741
|
+
const workflowIgnorePresent = workflowIgnoreStat?.isFile() === true;
|
|
742
|
+
if (workflowIgnoreStat !== void 0 && !workflowIgnorePresent) {
|
|
743
|
+
throw new Error(`${WORKFLOW_IGNORE_FILE} must be a regular file.`);
|
|
744
|
+
}
|
|
745
|
+
const workflowIgnoreContent = workflowIgnorePresent ? await readWorkflowUploadUtf8File(workflowIgnorePath, WORKFLOW_IGNORE_FILE) : void 0;
|
|
746
|
+
const matcher = createWorkflowUploadMatcher(
|
|
747
|
+
workflowIgnoreContent
|
|
748
|
+
);
|
|
749
|
+
const files = [];
|
|
750
|
+
const availableRegularPaths = /* @__PURE__ */ new Set();
|
|
751
|
+
const portablePaths = /* @__PURE__ */ new Map();
|
|
752
|
+
const ignoredPaths = [];
|
|
753
|
+
const walk = async (currentDir) => {
|
|
754
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
755
|
+
for (const entry of entries) {
|
|
756
|
+
const absolutePath = path2.join(currentDir, entry.name);
|
|
757
|
+
const relativePath = normalizeWorkflowUploadPath(path2.relative(projectRoot, absolutePath));
|
|
758
|
+
const portablePath = createWorkflowUploadPortablePathKey(relativePath);
|
|
759
|
+
const conflictingPath = portablePaths.get(portablePath);
|
|
760
|
+
if (conflictingPath !== void 0 && conflictingPath !== relativePath) {
|
|
761
|
+
throw new Error(
|
|
762
|
+
`Workflow upload paths ${JSON.stringify(conflictingPath)} and ${JSON.stringify(relativePath)} conflict on a case-insensitive filesystem.`
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
portablePaths.set(portablePath, relativePath);
|
|
766
|
+
if (entry.isDirectory()) {
|
|
767
|
+
if (matcher.ignores(relativePath, { directory: true })) {
|
|
768
|
+
ignoredPaths.push(`${relativePath}/`);
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
await walk(absolutePath);
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
774
|
+
if (!entry.isFile()) {
|
|
775
|
+
throw new Error(`Workflow upload path ${JSON.stringify(relativePath)} must be a regular file or directory.`);
|
|
776
|
+
}
|
|
777
|
+
availableRegularPaths.add(relativePath);
|
|
778
|
+
if (matcher.ignores(relativePath)) {
|
|
779
|
+
ignoredPaths.push(relativePath);
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
const fileStat = await lstat(absolutePath);
|
|
783
|
+
files.push({ path: relativePath, absolutePath, size: fileStat.size });
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
await walk(projectRoot);
|
|
787
|
+
files.sort((left, right) => left.path.localeCompare(right.path));
|
|
788
|
+
ignoredPaths.sort((left, right) => left.localeCompare(right));
|
|
789
|
+
if (!availableRegularPaths.has("package.json")) {
|
|
790
|
+
throw new Error("Workflow package must contain package.json.");
|
|
791
|
+
}
|
|
792
|
+
const packageJson = parsePackageJson(await readWorkflowUploadUtf8File(
|
|
793
|
+
path2.join(projectRoot, "package.json"),
|
|
794
|
+
"package.json"
|
|
795
|
+
));
|
|
796
|
+
const requiredPaths = resolveWorkflowUploadRequiredPaths(
|
|
797
|
+
packageJson,
|
|
798
|
+
availableRegularPaths
|
|
799
|
+
);
|
|
800
|
+
matcher.assertRequiredPaths(requiredPaths);
|
|
801
|
+
for (const requiredPath of requiredPaths) {
|
|
802
|
+
if (!availableRegularPaths.has(requiredPath)) {
|
|
803
|
+
throw new Error(`Workflow package must contain required upload path ${JSON.stringify(requiredPath)}.`);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
workflowIgnorePresent,
|
|
808
|
+
workflowIgnoreConfigured: hasWorkflowIgnoreRules(workflowIgnoreContent),
|
|
809
|
+
files,
|
|
810
|
+
ignoredPaths,
|
|
811
|
+
totalBytes: files.reduce((total, file) => total + file.size, 0),
|
|
812
|
+
requiredPaths
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
async function copyWorkflowUploadFiles(sourceDir, targetDir) {
|
|
816
|
+
const plan = await createWorkflowUploadPlan(sourceDir);
|
|
817
|
+
await mkdir(targetDir, { recursive: true });
|
|
818
|
+
for (const file of plan.files) {
|
|
819
|
+
const targetPath = path2.join(targetDir, ...file.path.split("/"));
|
|
820
|
+
await mkdir(path2.dirname(targetPath), { recursive: true });
|
|
821
|
+
await copyFile(file.absolutePath, targetPath);
|
|
822
|
+
}
|
|
823
|
+
return plan;
|
|
824
|
+
}
|
|
825
|
+
function parsePackageJson(content) {
|
|
826
|
+
try {
|
|
827
|
+
return JSON.parse(content);
|
|
828
|
+
} catch {
|
|
829
|
+
throw new Error("Workflow package.json is invalid JSON.");
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
async function readWorkflowUploadUtf8File(filePath, label) {
|
|
833
|
+
const content = await readFile(filePath);
|
|
834
|
+
try {
|
|
835
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
836
|
+
} catch {
|
|
837
|
+
throw new Error(`Workflow ${label} must be a UTF-8 text file.`);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
123
841
|
// src/auth-config.ts
|
|
124
842
|
import { readFileSync } from "fs";
|
|
125
|
-
import { mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
843
|
+
import { mkdir as mkdir2, readFile as readFile2, rm, writeFile } from "fs/promises";
|
|
126
844
|
async function readCliAuthConfig(env = process.env) {
|
|
127
845
|
try {
|
|
128
|
-
const raw = await
|
|
846
|
+
const raw = await readFile2(resolveWorkflowCliAuthFilePath(env), "utf8");
|
|
129
847
|
return normalizeWorkflowAuthConfig(JSON.parse(raw));
|
|
130
848
|
} catch {
|
|
131
849
|
return createEmptyWorkflowAuthConfig();
|
|
@@ -140,7 +858,7 @@ function readCliAuthConfigSync(env = process.env) {
|
|
|
140
858
|
}
|
|
141
859
|
}
|
|
142
860
|
async function writeCliAuthConfig(config, env = process.env) {
|
|
143
|
-
await
|
|
861
|
+
await mkdir2(resolveWorkflowCliAuthDir(env), { recursive: true });
|
|
144
862
|
await writeFile(
|
|
145
863
|
resolveWorkflowCliAuthFilePath(env),
|
|
146
864
|
`${JSON.stringify(normalizeWorkflowAuthConfig(config), null, 2)}
|
|
@@ -154,28 +872,28 @@ async function clearCliAuthConfig(env = process.env) {
|
|
|
154
872
|
|
|
155
873
|
// src/env.ts
|
|
156
874
|
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
157
|
-
import
|
|
875
|
+
import path3 from "path";
|
|
158
876
|
import { parse } from "dotenv";
|
|
159
877
|
function loadCliEnv() {
|
|
160
878
|
const cliRoot = process.cwd();
|
|
161
879
|
const defaultRepoRoot = findRepoRoot(cliRoot) ?? cliRoot;
|
|
162
|
-
const initialRepoRoot = process.env.WORKFLOW_REPO_ROOT ?
|
|
880
|
+
const initialRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path3.resolve(process.env.WORKFLOW_REPO_ROOT) : defaultRepoRoot;
|
|
163
881
|
loadEnvFiles([
|
|
164
|
-
|
|
165
|
-
|
|
882
|
+
path3.join(cliRoot, ".env"),
|
|
883
|
+
path3.join(initialRepoRoot, ".env")
|
|
166
884
|
]);
|
|
167
|
-
const resolvedRepoRoot = process.env.WORKFLOW_REPO_ROOT ?
|
|
885
|
+
const resolvedRepoRoot = process.env.WORKFLOW_REPO_ROOT ? path3.resolve(process.env.WORKFLOW_REPO_ROOT) : initialRepoRoot;
|
|
168
886
|
if (resolvedRepoRoot !== initialRepoRoot) {
|
|
169
|
-
loadEnvFiles([
|
|
887
|
+
loadEnvFiles([path3.join(resolvedRepoRoot, ".env")]);
|
|
170
888
|
}
|
|
171
889
|
}
|
|
172
890
|
function findRepoRoot(startDir) {
|
|
173
|
-
let current =
|
|
891
|
+
let current = path3.resolve(startDir);
|
|
174
892
|
while (true) {
|
|
175
|
-
if (existsSync(
|
|
893
|
+
if (existsSync(path3.join(current, "pnpm-workspace.yaml")) && existsSync(path3.join(current, "packages", "cli", "package.json"))) {
|
|
176
894
|
return current;
|
|
177
895
|
}
|
|
178
|
-
const parent =
|
|
896
|
+
const parent = path3.dirname(current);
|
|
179
897
|
if (parent === current) return void 0;
|
|
180
898
|
current = parent;
|
|
181
899
|
}
|
|
@@ -199,7 +917,7 @@ function unique(values) {
|
|
|
199
917
|
|
|
200
918
|
// src/workspace.ts
|
|
201
919
|
var DEFAULT_SERVER_URL = "http://localhost:7125";
|
|
202
|
-
var CLI_MODULE_DIR =
|
|
920
|
+
var CLI_MODULE_DIR = path4.dirname(fileURLToPath(import.meta.url));
|
|
203
921
|
var DEFAULT_DEVICE_FLOW_CLIENT_NAME = "Workflow Workspace CLI";
|
|
204
922
|
loadCliEnv();
|
|
205
923
|
async function main(argv = process.argv.slice(2)) {
|
|
@@ -349,7 +1067,7 @@ async function commandUpload(parsed) {
|
|
|
349
1067
|
if (!workflowId) {
|
|
350
1068
|
throw new Error("Workflow package.json must include a UUID id. Use `workflow-code workspace upload <workflow> --create` after login to create and bind a server project.");
|
|
351
1069
|
}
|
|
352
|
-
const archivePath = parsed.options.file ?
|
|
1070
|
+
const archivePath = parsed.options.file ? path4.resolve(parsed.options.file) : await packWorkflow(workflowArg, parsed.options.output, parsed.options.path);
|
|
353
1071
|
const uploadResult = await uploadPackage({
|
|
354
1072
|
workflowId,
|
|
355
1073
|
archivePath,
|
|
@@ -458,7 +1176,7 @@ async function commandDownload(parsed) {
|
|
|
458
1176
|
const result = await fetchApi({
|
|
459
1177
|
server: parsed.options.server,
|
|
460
1178
|
token: parsed.options.token,
|
|
461
|
-
path: `/api/workflows/${encodeURIComponent(workflowId)}/files?target=${encodeURIComponent(target)}`
|
|
1179
|
+
path: `/api/workflows/${encodeURIComponent(workflowId)}/files?target=${encodeURIComponent(target)}&includeBinary=true`
|
|
462
1180
|
});
|
|
463
1181
|
printApiResponse(result);
|
|
464
1182
|
assertApiOk(result);
|
|
@@ -466,14 +1184,14 @@ async function commandDownload(parsed) {
|
|
|
466
1184
|
return;
|
|
467
1185
|
}
|
|
468
1186
|
const repoRoot = resolveRepoRoot();
|
|
469
|
-
const targetDir = parsed.options.path ?
|
|
1187
|
+
const targetDir = parsed.options.path ? path4.resolve(parsed.options.path) : path4.join(repoRoot, "workspace", "workflow", workflowArg);
|
|
470
1188
|
await rm2(targetDir, { recursive: true, force: true });
|
|
471
|
-
await
|
|
1189
|
+
await mkdir3(targetDir, { recursive: true });
|
|
472
1190
|
for (const file of result.data.files) {
|
|
473
1191
|
const safePath = normalizeWorkflowFilePath(file.path);
|
|
474
|
-
const targetPath =
|
|
475
|
-
await
|
|
476
|
-
await writeFile2(targetPath, file
|
|
1192
|
+
const targetPath = path4.join(targetDir, safePath);
|
|
1193
|
+
await mkdir3(path4.dirname(targetPath), { recursive: true });
|
|
1194
|
+
await writeFile2(targetPath, decodeWorkflowFileContent(file));
|
|
477
1195
|
}
|
|
478
1196
|
}
|
|
479
1197
|
async function commandPublish(parsed) {
|
|
@@ -504,27 +1222,25 @@ async function commandHealth(parsed) {
|
|
|
504
1222
|
}
|
|
505
1223
|
async function packWorkflow(workflowName, outputPath, sourcePath) {
|
|
506
1224
|
const repoRoot = resolveRepoRoot();
|
|
507
|
-
const workflowDir = sourcePath === void 0 ?
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const
|
|
512
|
-
const
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
await
|
|
516
|
-
await mkdir2(path3.join(stagingDir, "workspace", "workflow"), { recursive: true });
|
|
517
|
-
await mkdir2(path3.dirname(archivePath), { recursive: true });
|
|
1225
|
+
const workflowDir = sourcePath === void 0 ? path4.join(repoRoot, "workspace", "workflow", workflowName) : path4.resolve(sourcePath);
|
|
1226
|
+
await readPackageJsonFile(path4.join(workflowDir, "package.json"));
|
|
1227
|
+
const packsDir = process.env.WORKFLOW_WORKSPACE_PACKS_DIR ? path4.resolve(process.env.WORKFLOW_WORKSPACE_PACKS_DIR) : path4.join(repoRoot, "workspace", ".packs");
|
|
1228
|
+
const stagingDir = path4.join(packsDir, "tmp", randomUUID(), workflowName);
|
|
1229
|
+
const archivePath = outputPath ? path4.resolve(outputPath) : path4.join(packsDir, `${workflowName}-${createTimestamp()}.tgz`);
|
|
1230
|
+
const workspaceRoot = sourcePath === void 0 ? path4.join(repoRoot, "workspace", "workflow") : path4.dirname(workflowDir);
|
|
1231
|
+
await rm2(path4.dirname(stagingDir), { recursive: true, force: true });
|
|
1232
|
+
await mkdir3(path4.join(stagingDir, "workspace", "workflow"), { recursive: true });
|
|
1233
|
+
await mkdir3(path4.dirname(archivePath), { recursive: true });
|
|
518
1234
|
await stageWorkflowWithLocalDependencies({
|
|
519
1235
|
workspaceRoot,
|
|
520
1236
|
workflowDir,
|
|
521
1237
|
workflowName,
|
|
522
|
-
stagingRoot:
|
|
1238
|
+
stagingRoot: path4.join(stagingDir, "workspace", "workflow")
|
|
523
1239
|
});
|
|
524
1240
|
const result = await runCommand("tar", ["-czf", archivePath, "-C", stagingDir, "."], {
|
|
525
1241
|
cwd: repoRoot
|
|
526
1242
|
});
|
|
527
|
-
await rm2(
|
|
1243
|
+
await rm2(path4.dirname(stagingDir), { recursive: true, force: true });
|
|
528
1244
|
if (result.exitCode !== 0) {
|
|
529
1245
|
throw new Error(`Failed to create archive: ${result.stderr || result.stdout}`);
|
|
530
1246
|
}
|
|
@@ -543,8 +1259,8 @@ async function resolveRemoteWorkflowId(parsed) {
|
|
|
543
1259
|
}
|
|
544
1260
|
async function readWorkflowPackageContext(workflowArg, sourcePath) {
|
|
545
1261
|
const repoRoot = resolveRepoRoot();
|
|
546
|
-
const workflowDir = sourcePath === void 0 ?
|
|
547
|
-
const packageJsonPath =
|
|
1262
|
+
const workflowDir = sourcePath === void 0 ? path4.join(repoRoot, "workspace", "workflow", workflowArg) : path4.resolve(sourcePath);
|
|
1263
|
+
const packageJsonPath = path4.join(workflowDir, "package.json");
|
|
548
1264
|
const packageJson = await readPackageJsonFile(packageJsonPath);
|
|
549
1265
|
const workflowId = typeof packageJson.id === "string" && isWorkflowUuid(packageJson.id) ? packageJson.id.trim() : void 0;
|
|
550
1266
|
const workflowName = readRequiredPackageString(packageJson, "name");
|
|
@@ -580,7 +1296,7 @@ async function ensureWorkflowProjectCreated(options) {
|
|
|
580
1296
|
}
|
|
581
1297
|
async function readPackageJsonFile(packageJsonPath) {
|
|
582
1298
|
try {
|
|
583
|
-
const raw = JSON.parse(await
|
|
1299
|
+
const raw = JSON.parse(await readFile3(packageJsonPath, "utf8"));
|
|
584
1300
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
585
1301
|
throw new Error(`Workflow package "${packageJsonPath}" must contain a JSON object.`);
|
|
586
1302
|
}
|
|
@@ -611,8 +1327,8 @@ async function writeWorkflowPackageId(packageJsonPath, workflowId) {
|
|
|
611
1327
|
);
|
|
612
1328
|
}
|
|
613
1329
|
async function uploadPackage(options) {
|
|
614
|
-
const archiveBuffer = await
|
|
615
|
-
const archiveName =
|
|
1330
|
+
const archiveBuffer = await readFile3(options.archivePath);
|
|
1331
|
+
const archiveName = path4.basename(options.archivePath);
|
|
616
1332
|
const response = await fetch(
|
|
617
1333
|
`${trimTrailingSlash(options.server)}/api/workflows/${encodeURIComponent(options.workflowId)}/package?fileName=${encodeURIComponent(archiveName)}`,
|
|
618
1334
|
{
|
|
@@ -683,13 +1399,7 @@ async function fetchApi(options) {
|
|
|
683
1399
|
return response.json();
|
|
684
1400
|
}
|
|
685
1401
|
async function copyWorkflowSource(sourceDir, targetDir) {
|
|
686
|
-
|
|
687
|
-
recursive: true,
|
|
688
|
-
filter(source) {
|
|
689
|
-
const relative = path3.relative(sourceDir, source);
|
|
690
|
-
return relative === "" || !shouldExcludePackagePath(relative);
|
|
691
|
-
}
|
|
692
|
-
});
|
|
1402
|
+
return copyWorkflowUploadFiles(sourceDir, targetDir);
|
|
693
1403
|
}
|
|
694
1404
|
async function stageWorkflowWithLocalDependencies(options) {
|
|
695
1405
|
const queue = [options.workflowName];
|
|
@@ -700,13 +1410,23 @@ async function stageWorkflowWithLocalDependencies(options) {
|
|
|
700
1410
|
continue;
|
|
701
1411
|
}
|
|
702
1412
|
visited.add(currentWorkflowName);
|
|
703
|
-
const sourceDir = currentWorkflowName === options.workflowName ? options.workflowDir :
|
|
704
|
-
if (!existsSync2(
|
|
1413
|
+
const sourceDir = currentWorkflowName === options.workflowName ? options.workflowDir : path4.join(options.workspaceRoot, currentWorkflowName);
|
|
1414
|
+
if (!existsSync2(path4.join(sourceDir, "package.json"))) {
|
|
705
1415
|
throw new Error(
|
|
706
1416
|
`Workflow "${options.workflowName}" references local workflow "${currentWorkflowName}", but ${sourceDir} is missing package.json.`
|
|
707
1417
|
);
|
|
708
1418
|
}
|
|
709
|
-
await copyWorkflowSource(
|
|
1419
|
+
const uploadPlan = await copyWorkflowSource(
|
|
1420
|
+
sourceDir,
|
|
1421
|
+
path4.join(options.stagingRoot, currentWorkflowName)
|
|
1422
|
+
);
|
|
1423
|
+
if (currentWorkflowName === options.workflowName && !uploadPlan.workflowIgnoreConfigured) {
|
|
1424
|
+
process.stderr.write([
|
|
1425
|
+
"Warning: .workflowignore is missing or has no active rules; all regular project files will be uploaded.",
|
|
1426
|
+
`.gitignore is not used. Files: ${uploadPlan.files.length}; bytes: ${uploadPlan.totalBytes}.`,
|
|
1427
|
+
""
|
|
1428
|
+
].join("\n"));
|
|
1429
|
+
}
|
|
710
1430
|
for (const dependency of await findLocalWorkflowDependencies(sourceDir)) {
|
|
711
1431
|
if (!visited.has(dependency)) {
|
|
712
1432
|
queue.push(dependency);
|
|
@@ -717,11 +1437,11 @@ async function stageWorkflowWithLocalDependencies(options) {
|
|
|
717
1437
|
async function findLocalWorkflowDependencies(sourceDir) {
|
|
718
1438
|
const discovered = /* @__PURE__ */ new Set();
|
|
719
1439
|
for (const fileName of ["index.ts", "interface.ts", "globals.d.ts"]) {
|
|
720
|
-
const filePath =
|
|
1440
|
+
const filePath = path4.join(sourceDir, fileName);
|
|
721
1441
|
if (!existsSync2(filePath)) {
|
|
722
1442
|
continue;
|
|
723
1443
|
}
|
|
724
|
-
const source = await
|
|
1444
|
+
const source = await readFile3(filePath, "utf8");
|
|
725
1445
|
for (const match of source.matchAll(/(?:from\s+|reference path=)\"(\.\.\/([^/\"']+)(?:\/[^\"']*)?)\"/g)) {
|
|
726
1446
|
const workflowName = match[2]?.trim();
|
|
727
1447
|
if (workflowName) {
|
|
@@ -737,39 +1457,30 @@ async function findLocalWorkflowDependencies(sourceDir) {
|
|
|
737
1457
|
}
|
|
738
1458
|
return [...discovered].sort((left, right) => left.localeCompare(right));
|
|
739
1459
|
}
|
|
740
|
-
function shouldExcludePackagePath(relativePath) {
|
|
741
|
-
const parts = relativePath.split(/[\\/]/);
|
|
742
|
-
const name = parts.at(-1) ?? "";
|
|
743
|
-
const excludedDirectories = /* @__PURE__ */ new Set([
|
|
744
|
-
"node_modules",
|
|
745
|
-
"dist",
|
|
746
|
-
"build",
|
|
747
|
-
"out",
|
|
748
|
-
"coverage",
|
|
749
|
-
".git",
|
|
750
|
-
".hg",
|
|
751
|
-
".svn",
|
|
752
|
-
".cache",
|
|
753
|
-
".turbo",
|
|
754
|
-
".next",
|
|
755
|
-
".nuxt",
|
|
756
|
-
".pnpm-store"
|
|
757
|
-
]);
|
|
758
|
-
if (parts.some((part) => excludedDirectories.has(part))) {
|
|
759
|
-
return true;
|
|
760
|
-
}
|
|
761
|
-
if (name === ".env" || name.startsWith(".env.")) {
|
|
762
|
-
return name !== ".env.example";
|
|
763
|
-
}
|
|
764
|
-
return name === ".DS_Store" || name === "Thumbs.db" || name.endsWith(".tmp") || name.endsWith(".log") || name.endsWith(".tsbuildinfo") || name.endsWith("~");
|
|
765
|
-
}
|
|
766
1460
|
function normalizeWorkflowFilePath(filePath) {
|
|
767
1461
|
const normalized = filePath.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
768
|
-
if (normalized === "" || normalized.startsWith("/") || /^[a-zA-Z]:/.test(normalized) || normalized.split("/").some((part) => part === "" || part === "." || part === "..")
|
|
1462
|
+
if (normalized === "" || normalized.startsWith("/") || /^[a-zA-Z]:/.test(normalized) || normalized.split("/").some((part) => part === "" || part === "." || part === "..")) {
|
|
769
1463
|
throw new Error(`Invalid workflow file path "${filePath}".`);
|
|
770
1464
|
}
|
|
771
1465
|
return normalized;
|
|
772
1466
|
}
|
|
1467
|
+
function decodeWorkflowFileContent(file) {
|
|
1468
|
+
if (file.encoding === void 0) {
|
|
1469
|
+
return file.content;
|
|
1470
|
+
}
|
|
1471
|
+
if (file.encoding !== "base64") {
|
|
1472
|
+
throw new Error(`Unsupported encoding for workflow file "${file.path}".`);
|
|
1473
|
+
}
|
|
1474
|
+
const normalized = file.content.replace(/=+$/, "");
|
|
1475
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(file.content)) {
|
|
1476
|
+
throw new Error(`Invalid base64 content for workflow file "${file.path}".`);
|
|
1477
|
+
}
|
|
1478
|
+
const decoded = Buffer.from(file.content, "base64");
|
|
1479
|
+
if (decoded.toString("base64").replace(/=+$/, "") !== normalized) {
|
|
1480
|
+
throw new Error(`Invalid base64 content for workflow file "${file.path}".`);
|
|
1481
|
+
}
|
|
1482
|
+
return decoded;
|
|
1483
|
+
}
|
|
773
1484
|
function parseArgs(argv) {
|
|
774
1485
|
const [command = "", ...rest] = argv;
|
|
775
1486
|
const positional = [];
|
|
@@ -927,7 +1638,7 @@ function printUsage() {
|
|
|
927
1638
|
}
|
|
928
1639
|
function resolveRepoRoot(startDir = process.cwd()) {
|
|
929
1640
|
if (process.env.WORKFLOW_REPO_ROOT !== void 0) {
|
|
930
|
-
return
|
|
1641
|
+
return path4.resolve(process.env.WORKFLOW_REPO_ROOT);
|
|
931
1642
|
}
|
|
932
1643
|
for (const candidate of [startDir, CLI_MODULE_DIR]) {
|
|
933
1644
|
const repoRoot = findRepoRoot2(candidate);
|
|
@@ -938,12 +1649,12 @@ function resolveRepoRoot(startDir = process.cwd()) {
|
|
|
938
1649
|
return process.cwd();
|
|
939
1650
|
}
|
|
940
1651
|
function findRepoRoot2(startDir) {
|
|
941
|
-
let current =
|
|
1652
|
+
let current = path4.resolve(startDir);
|
|
942
1653
|
while (true) {
|
|
943
1654
|
if (isRepoRoot(current)) {
|
|
944
1655
|
return current;
|
|
945
1656
|
}
|
|
946
|
-
const parent =
|
|
1657
|
+
const parent = path4.dirname(current);
|
|
947
1658
|
if (parent === current) {
|
|
948
1659
|
return void 0;
|
|
949
1660
|
}
|
|
@@ -951,7 +1662,7 @@ function findRepoRoot2(startDir) {
|
|
|
951
1662
|
}
|
|
952
1663
|
}
|
|
953
1664
|
function isRepoRoot(candidate) {
|
|
954
|
-
return existsSync2(
|
|
1665
|
+
return existsSync2(path4.join(candidate, "pnpm-workspace.yaml")) && existsSync2(path4.join(candidate, "package.json")) && existsSync2(path4.join(candidate, "workspace", "package.json")) && existsSync2(path4.join(candidate, "packages", "cli", "package.json"));
|
|
955
1666
|
}
|
|
956
1667
|
function trimTrailingSlash(value) {
|
|
957
1668
|
return value.replace(/\/+$/, "");
|
|
@@ -1018,13 +1729,14 @@ function readRetryAfterSeconds(data) {
|
|
|
1018
1729
|
const value = data.retryAfterSeconds;
|
|
1019
1730
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
1020
1731
|
}
|
|
1021
|
-
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(
|
|
1732
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(path4.resolve(process.argv[1])).href) {
|
|
1022
1733
|
main().catch((error) => {
|
|
1023
1734
|
console.error(error instanceof Error ? error.message : String(error));
|
|
1024
1735
|
process.exitCode = 1;
|
|
1025
1736
|
});
|
|
1026
1737
|
}
|
|
1027
1738
|
export {
|
|
1739
|
+
decodeWorkflowFileContent,
|
|
1028
1740
|
ensureWorkflowProjectCreated,
|
|
1029
1741
|
findLocalWorkflowDependencies,
|
|
1030
1742
|
formatForbiddenMessage,
|