@visulima/task-runner 1.0.0-alpha.7 → 1.0.0-alpha.9

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +3 -1
  3. package/dist/index.d.ts +3093 -49
  4. package/dist/index.js +29 -19
  5. package/dist/packem_chunks/index.js +5593 -0
  6. package/dist/packem_shared/{Cache-CWaX_c8U.js → Cache-CbhoA268.js} +151 -10
  7. package/dist/packem_shared/{FileAccessTracker-CQ5Ot7Hd.js → FileAccessTracker-D8zIURPU.js} +1 -1
  8. package/dist/packem_shared/{FingerprintManager-CV7U4f4f.js → FingerprintManager-78DjwWQ4.js} +1 -1
  9. package/dist/packem_shared/HttpRemoteCache-BTXUBH7t.js +290 -0
  10. package/dist/packem_shared/INPUT_URI_SCHEMES-DRm76YI5.js +69 -0
  11. package/dist/packem_shared/{IncrementalFileHasher-BRS76-mb.js → IncrementalFileHasher-BBhVK491.js} +1 -1
  12. package/dist/packem_shared/ReapiRemoteCache-vgRxDMmu.js +1012 -0
  13. package/dist/packem_shared/{TaskOrchestrator-rf45vW5c.js → TaskOrchestrator-CdRaQhTO.js} +100 -11
  14. package/dist/packem_shared/{TrackedTaskExecutor-CFPpQfXF.js → TrackedTaskExecutor-CWSMfHAW.js} +2 -2
  15. package/dist/packem_shared/V2_ROOT-DKBLxKo4.js +14 -0
  16. package/dist/packem_shared/actionDigestForTaskHash-BRE-9MT6.js +121 -0
  17. package/dist/packem_shared/archive-CnggHWb-.js +152 -0
  18. package/dist/packem_shared/{buildForwardDependencyMap-DLPgKEto.js → buildForwardDependencyMap-0BJFMMPv.js} +1 -2
  19. package/dist/packem_shared/{collectFiles-ClXHnHhg.js → collectFiles-cc1gokGU.js} +2 -1
  20. package/dist/packem_shared/{computeTaskHash-DYqfrDGq.js → computeTaskHash-DHoBJ_-V.js} +10 -4
  21. package/dist/packem_shared/containsBlob-CwGB0a_q.js +125 -0
  22. package/dist/packem_shared/{createTaskGraph-B7nH0kY_.js → createTaskGraph-Bwl4hwAf.js} +23 -2
  23. package/dist/packem_shared/{defaultTaskRunner-Cp7jCmIl.js → defaultTaskRunner-BaX4ZbFv.js} +58 -15
  24. package/dist/packem_shared/{detectFrameworks-CeFzKE6J.js → detectFrameworks-D7nyTc-o.js} +1 -1
  25. package/dist/packem_shared/{detectScriptShell-CR-xXKA4.js → detectScriptShell-CzxCM9-t.js} +1 -1
  26. package/dist/packem_shared/digestBuffer-CPdI2E1d.js +48 -0
  27. package/dist/packem_shared/{expandArguments-0AwD2BIA.js → expandArguments-Ba-hHYff.js} +2 -1
  28. package/dist/packem_shared/expandTokensInString-Bb7nYehP.js +47 -0
  29. package/dist/packem_shared/{extractPackageName-BllKetnz.js → extractPackageName-CMHjqGj_.js} +2 -3
  30. package/dist/packem_shared/{generateRunSummary-BE1jnQ3H.js → generateRunSummary-Bah7CFay.js} +1 -1
  31. package/dist/packem_shared/getCurrentBranch-DVNikt0P.js +156 -0
  32. package/dist/packem_shared/getMainWorktreeRoot-iBqToQJ4.js +114 -0
  33. package/dist/packem_shared/{parseCommands-D-IgF8Zh.js → parseCommands-DDdIxaH5.js} +8 -3
  34. package/dist/packem_shared/resolveCacheMode-CsmHT_0o.js +21 -0
  35. package/dist/packem_shared/{runConcurrently-CmfC4r-f.js → runConcurrently-BCGQ9fJl.js} +1 -1
  36. package/dist/packem_shared/shell-quote-DWJJbt21.js +3 -0
  37. package/dist/packem_shared/{utils-zO0ZRgtf.js → utils-Bmnj-H2J.js} +4 -1
  38. package/index.js +556 -723
  39. package/package.json +26 -13
  40. package/dist/affected.d.ts +0 -82
  41. package/dist/archive.d.ts +0 -38
  42. package/dist/cache.d.ts +0 -138
  43. package/dist/chrome-trace.d.ts +0 -53
  44. package/dist/command-parser/expand-arguments.d.ts +0 -11
  45. package/dist/command-parser/expand-shortcut.d.ts +0 -15
  46. package/dist/command-parser/expand-wildcard.d.ts +0 -13
  47. package/dist/command-parser/index.d.ts +0 -18
  48. package/dist/command-parser/strip-quotes.d.ts +0 -6
  49. package/dist/concurrent-fallback.d.ts +0 -16
  50. package/dist/concurrent.d.ts +0 -23
  51. package/dist/default-task-runner.d.ts +0 -44
  52. package/dist/detect-shell.d.ts +0 -19
  53. package/dist/file-access-tracker.d.ts +0 -59
  54. package/dist/fingerprint.d.ts +0 -54
  55. package/dist/flow-controllers/index.d.ts +0 -7
  56. package/dist/flow-controllers/input-handler.d.ts +0 -44
  57. package/dist/flow-controllers/log-timings.d.ts +0 -18
  58. package/dist/flow-controllers/restart-process.d.ts +0 -21
  59. package/dist/flow-controllers/teardown.d.ts +0 -22
  60. package/dist/framework-inference.d.ts +0 -35
  61. package/dist/graph-visualizer.d.ts +0 -74
  62. package/dist/incremental-hasher.d.ts +0 -76
  63. package/dist/life-cycle.d.ts +0 -38
  64. package/dist/lockfile-hasher.d.ts +0 -73
  65. package/dist/log-reporter.d.ts +0 -34
  66. package/dist/native-binding.d.ts +0 -106
  67. package/dist/output-resolver.d.ts +0 -20
  68. package/dist/packem_shared/RemoteCache-DSU3lc87.js +0 -219
  69. package/dist/packem_shared/archive-UQHAnZUa.js +0 -102
  70. package/dist/project-constraints.d.ts +0 -9
  71. package/dist/remote-cache.d.ts +0 -100
  72. package/dist/run-summary.d.ts +0 -111
  73. package/dist/task-graph-utils.d.ts +0 -39
  74. package/dist/task-graph.d.ts +0 -22
  75. package/dist/task-hasher.d.ts +0 -104
  76. package/dist/task-orchestrator.d.ts +0 -38
  77. package/dist/task-scheduler.d.ts +0 -41
  78. package/dist/terminal-buffer.d.ts +0 -29
  79. package/dist/tracked-executor.d.ts +0 -46
  80. package/dist/types.d.ts +0 -757
  81. package/dist/utils.d.ts +0 -39
@@ -0,0 +1,125 @@
1
+ import { createRequire as __cjs_createRequire } from "node:module";
2
+
3
+ const __cjs_require = __cjs_createRequire(import.meta.url);
4
+
5
+ const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
6
+
7
+ const __cjs_getBuiltinModule = (module) => {
8
+ // Check if we're in Node.js and version supports getBuiltinModule
9
+ if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
10
+ const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
11
+ // Node.js 20.16.0+ and 22.3.0+
12
+ if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
13
+ return __cjs_getProcess.getBuiltinModule(module);
14
+ }
15
+ }
16
+ // Fallback to createRequire
17
+ return __cjs_require(module);
18
+ };
19
+
20
+ const {
21
+ createReadStream,
22
+ createWriteStream
23
+ } = __cjs_getBuiltinModule("node:fs");
24
+ const {
25
+ stat,
26
+ mkdir,
27
+ writeFile,
28
+ rename,
29
+ rm,
30
+ utimes
31
+ } = __cjs_getBuiltinModule("node:fs/promises");
32
+ const {
33
+ pipeline
34
+ } = __cjs_getBuiltinModule("node:stream/promises");
35
+ import { dirname } from '@visulima/path';
36
+ import { u as uniqueId } from './utils-Bmnj-H2J.js';
37
+ import { digestFile } from './digestBuffer-CPdI2E1d.js';
38
+ import { casBlobPath, tmpDirectory } from './V2_ROOT-DKBLxKo4.js';
39
+
40
+ const containsBlob = async (root, digest) => {
41
+ try {
42
+ const stats = await stat(casBlobPath(root, digest.hash));
43
+ return stats.isFile() && stats.size === digest.sizeBytes;
44
+ } catch {
45
+ return false;
46
+ }
47
+ };
48
+ const putBlobFromFile = async (root, digest, sourcePath) => {
49
+ const finalPath = casBlobPath(root, digest.hash);
50
+ if (await containsBlob(root, digest)) {
51
+ await touchBlob(root, digest).catch(() => {
52
+ });
53
+ return;
54
+ }
55
+ const stagingPath = await stageBlob(root, sourcePath);
56
+ try {
57
+ await mkdir(dirname(finalPath), { recursive: true });
58
+ await rename(stagingPath, finalPath);
59
+ } catch (error) {
60
+ await rm(stagingPath, { force: true }).catch(() => {
61
+ });
62
+ if (!isAlreadyExistsError(error)) {
63
+ throw error;
64
+ }
65
+ }
66
+ };
67
+ const putBlobFromBytes = async (root, digest, bytes) => {
68
+ const finalPath = casBlobPath(root, digest.hash);
69
+ if (await containsBlob(root, digest)) {
70
+ await touchBlob(root, digest).catch(() => {
71
+ });
72
+ return;
73
+ }
74
+ const tmpDirectoryPath = tmpDirectory(root);
75
+ const stagingPath = `${tmpDirectoryPath}/${uniqueId()}`;
76
+ await mkdir(tmpDirectoryPath, { recursive: true });
77
+ await writeFile(stagingPath, bytes);
78
+ try {
79
+ await mkdir(dirname(finalPath), { recursive: true });
80
+ await rename(stagingPath, finalPath);
81
+ } catch (error) {
82
+ await rm(stagingPath, { force: true }).catch(() => {
83
+ });
84
+ if (!isAlreadyExistsError(error)) {
85
+ throw error;
86
+ }
87
+ }
88
+ };
89
+ const fetchBlobToFile = async (root, digest, destinationPath) => {
90
+ const sourcePath = casBlobPath(root, digest.hash);
91
+ try {
92
+ await stat(sourcePath);
93
+ } catch {
94
+ return false;
95
+ }
96
+ await mkdir(dirname(destinationPath), { recursive: true });
97
+ await pipeline(createReadStream(sourcePath), createWriteStream(destinationPath));
98
+ await touchBlob(root, digest).catch(() => {
99
+ });
100
+ return true;
101
+ };
102
+ const verifyBlob = async (filePath, expected) => {
103
+ const computed = await digestFile(filePath);
104
+ return computed?.hash === expected.hash && computed.sizeBytes === expected.sizeBytes;
105
+ };
106
+ const touchBlob = async (root, digest) => {
107
+ const now = /* @__PURE__ */ new Date();
108
+ await utimes(casBlobPath(root, digest.hash), now, now);
109
+ };
110
+ const stageBlob = async (root, sourcePath) => {
111
+ const tmpDirectoryPath = tmpDirectory(root);
112
+ const stagingPath = `${tmpDirectoryPath}/${uniqueId()}`;
113
+ await mkdir(tmpDirectoryPath, { recursive: true });
114
+ await pipeline(createReadStream(sourcePath), createWriteStream(stagingPath));
115
+ return stagingPath;
116
+ };
117
+ const isAlreadyExistsError = (error) => {
118
+ if (typeof error !== "object" || error === null) {
119
+ return false;
120
+ }
121
+ const { code } = error;
122
+ return code === "EEXIST" || code === "ENOTEMPTY";
123
+ };
124
+
125
+ export { containsBlob, fetchBlobToFile, putBlobFromBytes, putBlobFromFile, touchBlob, verifyBlob };
@@ -16,6 +16,13 @@ const parseTaskId = (taskId) => {
16
16
  target: parts[1]
17
17
  };
18
18
  };
19
+ const normalizeWarningPattern = (value) => {
20
+ if (value === void 0) {
21
+ return void 0;
22
+ }
23
+ const list = typeof value === "string" ? [value] : value;
24
+ return list.length === 0 ? void 0 : list;
25
+ };
19
26
  const getTaskOutputs = (projectName, targetName, workspace, targetDefaults) => {
20
27
  const project = workspace.projects[projectName];
21
28
  const targetConfig = project?.targets?.[targetName];
@@ -38,13 +45,20 @@ const getSameProjectTask = (projectName, targetName, overrides, workspace, targe
38
45
  };
39
46
  return [
40
47
  {
48
+ always: project.targets?.[targetName]?.always ?? targetDefaults?.[targetName]?.always,
41
49
  cache: project.targets?.[targetName]?.cache ?? targetDefaults?.[targetName]?.cache,
50
+ cacheOnWarning: project.targets?.[targetName]?.cacheOnWarning ?? targetDefaults?.[targetName]?.cacheOnWarning,
51
+ cacheRestore: project.targets?.[targetName]?.cacheRestore ?? targetDefaults?.[targetName]?.cacheRestore,
42
52
  id: getTaskId(target),
43
53
  outputs: getTaskOutputs(projectName, targetName, workspace, targetDefaults),
44
54
  overrides,
45
55
  parallelism: project.targets?.[targetName]?.parallelism ?? targetDefaults?.[targetName]?.parallelism,
46
56
  projectRoot: project.root,
47
- target
57
+ target,
58
+ warningPattern: normalizeWarningPattern(
59
+ project.targets?.[targetName]?.warningPattern ?? targetDefaults?.[targetName]?.warningPattern
60
+ ),
61
+ when: project.targets?.[targetName]?.when ?? targetDefaults?.[targetName]?.when
48
62
  }
49
63
  ];
50
64
  };
@@ -63,13 +77,20 @@ const getDependencyProjectTasks = (projectName, targetName, overrides, workspace
63
77
  target: targetName
64
78
  };
65
79
  tasks.push({
80
+ always: depProject.targets?.[targetName]?.always ?? targetDefaults?.[targetName]?.always,
66
81
  cache: depProject.targets?.[targetName]?.cache ?? targetDefaults?.[targetName]?.cache,
82
+ cacheOnWarning: depProject.targets?.[targetName]?.cacheOnWarning ?? targetDefaults?.[targetName]?.cacheOnWarning,
83
+ cacheRestore: depProject.targets?.[targetName]?.cacheRestore ?? targetDefaults?.[targetName]?.cacheRestore,
67
84
  id: getTaskId(target),
68
85
  outputs: getTaskOutputs(dep.target, targetName, workspace, targetDefaults),
69
86
  overrides,
70
87
  parallelism: depProject.targets?.[targetName]?.parallelism ?? targetDefaults?.[targetName]?.parallelism,
71
88
  projectRoot: depProject.root,
72
- target
89
+ target,
90
+ warningPattern: normalizeWarningPattern(
91
+ depProject.targets?.[targetName]?.warningPattern ?? targetDefaults?.[targetName]?.warningPattern
92
+ ),
93
+ when: depProject.targets?.[targetName]?.when ?? targetDefaults?.[targetName]?.when
73
94
  });
74
95
  }
75
96
  }
@@ -1,12 +1,42 @@
1
- import { x as xxh3Hash } from './utils-zO0ZRgtf.js';
2
- import { Cache } from './Cache-CWaX_c8U.js';
3
- import { inferFrameworkEnvPatterns } from './detectFrameworks-CeFzKE6J.js';
4
- import { IncrementalFileHasher } from './IncrementalFileHasher-BRS76-mb.js';
5
- import { RemoteCache } from './RemoteCache-DSU3lc87.js';
6
- import { InProcessTaskHasher } from './computeTaskHash-DYqfrDGq.js';
7
- import { TaskOrchestrator } from './TaskOrchestrator-rf45vW5c.js';
1
+ import { x as xxh3Hash } from './utils-Bmnj-H2J.js';
2
+ import { createRemoteCacheBackend } from './resolveCacheMode-CsmHT_0o.js';
3
+ import { Cache } from './Cache-CbhoA268.js';
4
+ import { inferFrameworkEnvPatterns } from './detectFrameworks-D7nyTc-o.js';
5
+ import { IncrementalFileHasher } from './IncrementalFileHasher-BBhVK491.js';
6
+ import { InProcessTaskHasher } from './computeTaskHash-DHoBJ_-V.js';
7
+ import { TaskOrchestrator } from './TaskOrchestrator-CdRaQhTO.js';
8
8
  import { TaskScheduler } from './parsePartition-BfLbHGAx.js';
9
9
 
10
+ const partitionAlwaysTasks = (taskGraph) => {
11
+ const alwaysTasks = [];
12
+ const remaining = {};
13
+ for (const [id, task] of Object.entries(taskGraph.tasks)) {
14
+ if (task.always) {
15
+ alwaysTasks.push(task);
16
+ } else {
17
+ remaining[id] = task;
18
+ }
19
+ }
20
+ if (alwaysTasks.length === 0) {
21
+ return { alwaysTasks: [], graph: taskGraph };
22
+ }
23
+ const alwaysIds = new Set(alwaysTasks.map((t) => t.id));
24
+ const dependencies = {};
25
+ for (const [id, deps] of Object.entries(taskGraph.dependencies)) {
26
+ if (alwaysIds.has(id)) {
27
+ continue;
28
+ }
29
+ dependencies[id] = deps.filter((dep) => !alwaysIds.has(dep));
30
+ }
31
+ return {
32
+ alwaysTasks,
33
+ graph: {
34
+ dependencies,
35
+ roots: taskGraph.roots.filter((id) => !alwaysIds.has(id)),
36
+ tasks: remaining
37
+ }
38
+ };
39
+ };
10
40
  const computeGlobalEnvNamespace = (globalEnv) => {
11
41
  if (!globalEnv || globalEnv.length === 0) {
12
42
  return void 0;
@@ -56,21 +86,23 @@ const defaultTaskRunner = async (_tasks, options, context) => {
56
86
  targetDefaults: options.targetDefaults,
57
87
  workspaceRoot
58
88
  });
89
+ const { alwaysTasks, graph: scheduledGraph } = partitionAlwaysTasks(taskGraph);
59
90
  const maxParallel = resolveParallel(options.parallel);
60
- const scheduler = new TaskScheduler(taskGraph, projectGraph, maxParallel);
91
+ const scheduler = new TaskScheduler(scheduledGraph, projectGraph, maxParallel);
61
92
  const resolveCommand = (task) => {
62
93
  const project = projectGraph.nodes[task.target.project];
63
94
  const targetConfig = project?.data.targets?.[task.target.target];
64
95
  const defaultConfig = options.targetDefaults?.[task.target.target];
65
96
  return targetConfig?.command ?? defaultConfig?.command;
66
97
  };
67
- const remoteCache = options.remoteCache ? new RemoteCache(options.remoteCache) : void 0;
98
+ const remoteCache = options.remoteCache ? createRemoteCacheBackend(options.remoteCache) : void 0;
68
99
  let fingerprintEnvPatterns = options.fingerprintEnvPatterns ?? [];
69
100
  if (options.frameworkInference && options.autoFingerprint) {
70
101
  const inferredPatterns = await inferFrameworkEnvPatterns(workspaceRoot, projects);
71
102
  fingerprintEnvPatterns = [.../* @__PURE__ */ new Set([...fingerprintEnvPatterns, ...inferredPatterns])];
72
103
  }
73
104
  const orchestrator = new TaskOrchestrator({
105
+ alwaysTasks,
74
106
  autoFingerprint: options.autoFingerprint,
75
107
  cache,
76
108
  cacheDiagnostics: options.cacheDiagnostics,
@@ -78,23 +110,34 @@ const defaultTaskRunner = async (_tasks, options, context) => {
78
110
  dryRun: options.dryRun,
79
111
  fingerprintEnvPatterns,
80
112
  lifeCycle,
113
+ // Bridge-local upload errors (tar/digest in hash-bridge) flow back
114
+ // through the same callback the wire-level backend uses, so a user
115
+ // observes upload failures regardless of where they originate.
116
+ onRemoteUploadError: options.remoteCache?.onUploadError,
81
117
  remoteCache,
82
118
  resolveCommand: options.autoFingerprint ? resolveCommand : void 0,
83
119
  scheduler,
84
120
  skipCache: options.skipNxCache,
85
121
  summarize: options.summarize,
86
122
  taskExecutor,
87
- taskGraph,
123
+ taskGraph: scheduledGraph,
88
124
  taskHasher,
89
125
  untrackedEnvVars: options.untrackedEnvVars,
90
126
  workspaceRoot
91
127
  });
92
- const results = await orchestrator.run();
93
- if (incrementalHasher) {
94
- await incrementalHasher.save().catch(() => {
95
- });
128
+ try {
129
+ const results = await orchestrator.run();
130
+ if (incrementalHasher) {
131
+ await incrementalHasher.save().catch(() => {
132
+ });
133
+ }
134
+ return results;
135
+ } finally {
136
+ if (remoteCache) {
137
+ await remoteCache.close().catch(() => {
138
+ });
139
+ }
96
140
  }
97
- return results;
98
141
  };
99
142
 
100
143
  export { defaultTaskRunner };
@@ -1,5 +1,5 @@
1
1
  import { join } from '@visulima/path';
2
- import { r as readPackageDeps } from './utils-zO0ZRgtf.js';
2
+ import { r as readPackageDeps } from './utils-Bmnj-H2J.js';
3
3
 
4
4
  const FRAMEWORK_DEFINITIONS = [
5
5
  {
@@ -37,7 +37,7 @@ const detectScriptShell = () => {
37
37
  stdio: ["ignore", "pipe", "ignore"],
38
38
  timeout: 5e3
39
39
  }).trim();
40
- if (result && result !== "undefined" && result !== "") {
40
+ if (result && result !== "undefined" && result !== "null" && result !== "") {
41
41
  cachedShellPath = result;
42
42
  return result;
43
43
  }
@@ -0,0 +1,48 @@
1
+ import { createRequire as __cjs_createRequire } from "node:module";
2
+
3
+ const __cjs_require = __cjs_createRequire(import.meta.url);
4
+
5
+ const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
6
+
7
+ const __cjs_getBuiltinModule = (module) => {
8
+ // Check if we're in Node.js and version supports getBuiltinModule
9
+ if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
10
+ const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
11
+ // Node.js 20.16.0+ and 22.3.0+
12
+ if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
13
+ return __cjs_getProcess.getBuiltinModule(module);
14
+ }
15
+ }
16
+ // Fallback to createRequire
17
+ return __cjs_require(module);
18
+ };
19
+
20
+ const {
21
+ createHash
22
+ } = __cjs_getBuiltinModule("node:crypto");
23
+ const {
24
+ createReadStream
25
+ } = __cjs_getBuiltinModule("node:fs");
26
+ const {
27
+ stat
28
+ } = __cjs_getBuiltinModule("node:fs/promises");
29
+
30
+ const digestBuffer = (bytes) => {
31
+ const hash = createHash("sha256").update(bytes).digest("hex");
32
+ return { hash, sizeBytes: bytes.byteLength };
33
+ };
34
+ const digestFile = async (filePath) => {
35
+ try {
36
+ const { size } = await stat(filePath);
37
+ const hasher = createHash("sha256");
38
+ const source = createReadStream(filePath);
39
+ for await (const chunk of source) {
40
+ hasher.update(chunk);
41
+ }
42
+ return { hash: hasher.digest("hex"), sizeBytes: size };
43
+ } catch {
44
+ return void 0;
45
+ }
46
+ };
47
+
48
+ export { digestBuffer, digestFile };
@@ -1,5 +1,6 @@
1
+ import { s as shellQuote } from './shell-quote-DWJJbt21.js';
2
+
1
3
  const PLACEHOLDER_REGEX = /\\?\{([@*]|[1-9]\d*)\}/g;
2
- const shellQuote = (s) => `'${s.replaceAll("'", String.raw`'\''`)}'`;
3
4
  const expandArguments = (config, additionalArguments) => {
4
5
  if (additionalArguments.length === 0) {
5
6
  return config;
@@ -0,0 +1,47 @@
1
+ import { s as shellQuote } from './shell-quote-DWJJbt21.js';
2
+
3
+ const TOKEN_PATHS = {
4
+ "affected.files": "affectedFiles",
5
+ changed_files: "affectedFiles"
6
+ };
7
+ const TOKEN_REGEX = /\\?\$\{\s*([\w.]+)\s*(?:\|\s*flag\s+(["'])(.*?)\2\s*)?\}/g;
8
+ const rewriteForProjectRoot = (filePath, projectRoot) => {
9
+ if (filePath === projectRoot) {
10
+ return ".";
11
+ }
12
+ const prefix = `${projectRoot}/`;
13
+ if (filePath.startsWith(prefix)) {
14
+ return filePath.slice(prefix.length);
15
+ }
16
+ return void 0;
17
+ };
18
+ const expandTokensInString = (command, context) => command.replaceAll(TOKEN_REGEX, (match, name, _quote, flagValue) => {
19
+ if (match.startsWith("\\")) {
20
+ return match.slice(1);
21
+ }
22
+ const sourceKey = TOKEN_PATHS[name];
23
+ if (!sourceKey) {
24
+ return match;
25
+ }
26
+ const rawFiles = context[sourceKey] ?? [];
27
+ const files = context.projectRoot ? rawFiles.map((f) => rewriteForProjectRoot(f, context.projectRoot)).filter((f) => f !== void 0) : rawFiles;
28
+ if (files.length === 0) {
29
+ return "";
30
+ }
31
+ if (flagValue !== void 0 && flagValue.length > 0) {
32
+ return files.map((file) => `${flagValue} ${shellQuote(file)}`).join(" ");
33
+ }
34
+ return files.map(shellQuote).join(" ");
35
+ });
36
+ const expandTokens = (config, context) => {
37
+ if (!config.command.includes("${")) {
38
+ return config;
39
+ }
40
+ const command = expandTokensInString(config.command, context);
41
+ if (command === config.command) {
42
+ return config;
43
+ }
44
+ return { ...config, command };
45
+ };
46
+
47
+ export { expandTokens, expandTokensInString };
@@ -20,7 +20,7 @@ const __cjs_getBuiltinModule = (module) => {
20
20
  const {
21
21
  readFile
22
22
  } = __cjs_getBuiltinModule("node:fs/promises");
23
- import { r as readPackageDeps, e as createXxh3Hasher } from './utils-zO0ZRgtf.js';
23
+ import { r as readPackageDeps, e as createXxh3Hasher } from './utils-Bmnj-H2J.js';
24
24
  import { join } from '@visulima/path';
25
25
 
26
26
  const extractPackageName = (path) => {
@@ -44,8 +44,7 @@ const parseNpmLockfile = (content) => {
44
44
  continue;
45
45
  }
46
46
  const name = extractPackageName(path);
47
- if (name && // Use the first (top-level) occurrence
48
- !versions.has(name)) {
47
+ if (name && !versions.has(name)) {
49
48
  versions.set(name, entry.version);
50
49
  }
51
50
  }
@@ -23,7 +23,7 @@ const {
23
23
  writeFile
24
24
  } = __cjs_getBuiltinModule("node:fs/promises");
25
25
  import { join } from '@visulima/path';
26
- import { u as uniqueId } from './utils-zO0ZRgtf.js';
26
+ import { u as uniqueId } from './utils-Bmnj-H2J.js';
27
27
 
28
28
  const getCacheStatus = (result) => {
29
29
  switch (result.status) {
@@ -0,0 +1,156 @@
1
+ import { createRequire as __cjs_createRequire } from "node:module";
2
+
3
+ const __cjs_require = __cjs_createRequire(import.meta.url);
4
+
5
+ const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
6
+
7
+ const __cjs_getBuiltinModule = (module) => {
8
+ // Check if we're in Node.js and version supports getBuiltinModule
9
+ if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
10
+ const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
11
+ // Node.js 20.16.0+ and 22.3.0+
12
+ if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
13
+ return __cjs_getProcess.getBuiltinModule(module);
14
+ }
15
+ }
16
+ // Fallback to createRequire
17
+ return __cjs_require(module);
18
+ };
19
+
20
+ const {
21
+ execFileSync
22
+ } = __cjs_getBuiltinModule("node:child_process");
23
+
24
+ const normalisePlatform = (value) => value === "windows" ? "win32" : value;
25
+ const matchPlatform = (clause, current) => {
26
+ const list = Array.isArray(clause) ? clause : [clause];
27
+ return list.some((p) => normalisePlatform(p) === normalisePlatform(current));
28
+ };
29
+ const matchBranch = (clause, current) => {
30
+ if (current === "") {
31
+ return false;
32
+ }
33
+ const list = Array.isArray(clause) ? clause : [clause];
34
+ return list.includes(current);
35
+ };
36
+ const matchSingleEnv = (matcher, env) => {
37
+ if (typeof matcher === "string") {
38
+ const value2 = env[matcher];
39
+ return value2 !== void 0 && value2 !== "";
40
+ }
41
+ const value = env[matcher.name];
42
+ if (matcher.equals !== void 0) {
43
+ return value === matcher.equals;
44
+ }
45
+ if (matcher.exists !== void 0) {
46
+ const present = value !== void 0 && value !== "";
47
+ return matcher.exists ? present : !present;
48
+ }
49
+ return value !== void 0 && value !== "";
50
+ };
51
+ const matchEnv = (clause, env) => {
52
+ const list = Array.isArray(clause) ? clause : [clause];
53
+ return list.some((m) => matchSingleEnv(m, env));
54
+ };
55
+ const detectCi = (env) => {
56
+ const value = env.CI;
57
+ return value !== void 0 && value !== "" && value !== "false" && value !== "0";
58
+ };
59
+ const branchCache = /* @__PURE__ */ new Map();
60
+ const getCurrentBranch = (cwd) => {
61
+ const cached = branchCache.get(cwd);
62
+ if (cached !== void 0) {
63
+ return cached;
64
+ }
65
+ try {
66
+ const out = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd, stdio: ["ignore", "pipe", "ignore"] });
67
+ let branch = out.toString("utf8").trim();
68
+ if (branch === "HEAD") {
69
+ branch = "";
70
+ }
71
+ branchCache.set(cwd, branch);
72
+ return branch;
73
+ } catch {
74
+ branchCache.set(cwd, "");
75
+ return "";
76
+ }
77
+ };
78
+ const resetBranchCache = () => {
79
+ branchCache.clear();
80
+ };
81
+ const resolveWhenContext = (context) => {
82
+ const env = context.env ?? process.env;
83
+ return {
84
+ branch: context.branch ?? "",
85
+ ci: context.ci ?? detectCi(env),
86
+ currentPlatform: context.platform ?? process.platform,
87
+ env
88
+ };
89
+ };
90
+ const evaluateWhen = (when, context = {}) => {
91
+ if (!when) {
92
+ return true;
93
+ }
94
+ const { branch, ci, currentPlatform, env } = resolveWhenContext(context);
95
+ if (when.os !== void 0 && !matchPlatform(when.os, currentPlatform)) {
96
+ return false;
97
+ }
98
+ if (when.env !== void 0 && !matchEnv(when.env, env)) {
99
+ return false;
100
+ }
101
+ if (when.branch !== void 0 && !matchBranch(when.branch, branch)) {
102
+ return false;
103
+ }
104
+ if (when.ci !== void 0 && when.ci !== ci) {
105
+ return false;
106
+ }
107
+ if (when.not) {
108
+ if (when.not.os !== void 0 && matchPlatform(when.not.os, currentPlatform)) {
109
+ return false;
110
+ }
111
+ if (when.not.env !== void 0 && matchEnv(when.not.env, env)) {
112
+ return false;
113
+ }
114
+ if (when.not.branch !== void 0 && matchBranch(when.not.branch, branch)) {
115
+ return false;
116
+ }
117
+ if (when.not.ci !== void 0 && when.not.ci === ci) {
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ };
123
+ const explainWhen = (when, context = {}) => {
124
+ if (!when || evaluateWhen(when, context)) {
125
+ return "";
126
+ }
127
+ const { branch, ci, currentPlatform, env } = resolveWhenContext(context);
128
+ const reasons = [];
129
+ if (when.os !== void 0 && !matchPlatform(when.os, currentPlatform)) {
130
+ reasons.push(`os=${currentPlatform} does not match ${JSON.stringify(when.os)}`);
131
+ }
132
+ if (when.env !== void 0 && !matchEnv(when.env, env)) {
133
+ reasons.push(`env clause did not match`);
134
+ }
135
+ if (when.branch !== void 0 && !matchBranch(when.branch, branch)) {
136
+ reasons.push(`branch=${branch || "(unknown)"} does not match ${JSON.stringify(when.branch)}`);
137
+ }
138
+ if (when.ci !== void 0 && when.ci !== ci) {
139
+ reasons.push(`ci=${ci} does not match required ci=${when.ci}`);
140
+ }
141
+ if (when.not?.os !== void 0 && matchPlatform(when.not.os, currentPlatform)) {
142
+ reasons.push(`os=${currentPlatform} matches excluded ${JSON.stringify(when.not.os)}`);
143
+ }
144
+ if (when.not?.env !== void 0 && matchEnv(when.not.env, env)) {
145
+ reasons.push(`env clause matches excluded matcher`);
146
+ }
147
+ if (when.not?.branch !== void 0 && matchBranch(when.not.branch, branch)) {
148
+ reasons.push(`branch=${branch} matches excluded ${JSON.stringify(when.not.branch)}`);
149
+ }
150
+ if (when.not?.ci !== void 0 && when.not.ci === ci) {
151
+ reasons.push(`ci=${ci} matches excluded ci=${when.not.ci}`);
152
+ }
153
+ return reasons.join("; ");
154
+ };
155
+
156
+ export { evaluateWhen, explainWhen, getCurrentBranch, resetBranchCache };