substrate-ai 0.20.55 → 0.20.57

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/cli/index.js CHANGED
@@ -1,31 +1,32 @@
1
1
  #!/usr/bin/env node
2
- import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics } from "../health-PSnpYDAa.js";
2
+ import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics } from "../health-PdI4-96I.js";
3
3
  import { createLogger } from "../logger-KeHncl-f.js";
4
4
  import { createEventBus } from "../helpers-CElYrONe.js";
5
- import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-VcMmfo2w.js";
5
+ import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-W2emvN3F.js";
6
6
  import "../adapter-registry-DXLMTmfD.js";
7
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, validateStopAfterFromConflict } from "../run-CeaNSnD6.js";
8
- import "../errors-CogpxBUg.js";
7
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DcDoaG12.js";
8
+ import "../errors-CKFu8YI9.js";
9
9
  import "../routing-CcBOCuC9.js";
10
10
  import "../decisions-C0pz9Clx.js";
11
11
  import "../version-manager-impl-BmOWu8ml.js";
12
- import { registerUpgradeCommand } from "../upgrade-CF4__LCr.js";
12
+ import { registerUpgradeCommand } from "../upgrade-CAqLkNUP.js";
13
13
  import { Command } from "commander";
14
14
  import { fileURLToPath } from "url";
15
15
  import { dirname, join, resolve } from "path";
16
16
  import { access, mkdir, readFile, writeFile } from "fs/promises";
17
17
  import yaml from "js-yaml";
18
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
18
+ import * as actualFS from "node:fs";
19
+ import { existsSync, promises, readFileSync, writeFileSync } from "node:fs";
19
20
  import { execFile, spawn } from "node:child_process";
20
21
  import * as path$3 from "node:path";
21
22
  import * as path$2 from "node:path";
22
23
  import * as path$1 from "node:path";
23
- import { basename as basename$1, join as join$1, resolve as resolve$1 } from "node:path";
24
+ import { basename as basename$1, join as join$1, posix, relative, resolve as resolve$1, win32 } from "node:path";
24
25
  import { randomUUID } from "node:crypto";
25
26
  import { z } from "zod";
26
27
  import * as fs from "node:fs/promises";
27
- import { access as access$1, readFile as readFile$1, readdir as readdir$1 } from "node:fs/promises";
28
- import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
28
+ import { access as access$1, lstat, readFile as readFile$1, readdir as readdir$1, readlink, realpath } from "node:fs/promises";
29
+ import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, lstatSync, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdir as readdir$2, readdirSync as readdirSync$1, readlinkSync, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
29
30
  import { homedir } from "os";
30
31
  import { createRequire } from "node:module";
31
32
  import { fileURLToPath as fileURLToPath$1 } from "node:url";
@@ -3037,10 +3038,3810 @@ function registerConfigCommand(program, _version) {
3037
3038
  });
3038
3039
  }
3039
3040
 
3041
+ //#endregion
3042
+ //#region node_modules/lru-cache/dist/esm/index.js
3043
+ /**
3044
+ * @module LRUCache
3045
+ */
3046
+ const perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
3047
+ const warned = new Set();
3048
+ /* c8 ignore start */
3049
+ const PROCESS = typeof process === "object" && !!process ? process : {};
3050
+ /* c8 ignore start */
3051
+ const emitWarning = (msg, type, code, fn) => {
3052
+ typeof PROCESS.emitWarning === "function" ? PROCESS.emitWarning(msg, type, code, fn) : console.error(`[${code}] ${type}: ${msg}`);
3053
+ };
3054
+ let AC = globalThis.AbortController;
3055
+ let AS = globalThis.AbortSignal;
3056
+ /* c8 ignore start */
3057
+ if (typeof AC === "undefined") {
3058
+ AS = class AbortSignal {
3059
+ onabort;
3060
+ _onabort = [];
3061
+ reason;
3062
+ aborted = false;
3063
+ addEventListener(_, fn) {
3064
+ this._onabort.push(fn);
3065
+ }
3066
+ };
3067
+ AC = class AbortController {
3068
+ constructor() {
3069
+ warnACPolyfill();
3070
+ }
3071
+ signal = new AS();
3072
+ abort(reason) {
3073
+ if (this.signal.aborted) return;
3074
+ this.signal.reason = reason;
3075
+ this.signal.aborted = true;
3076
+ for (const fn of this.signal._onabort) fn(reason);
3077
+ this.signal.onabort?.(reason);
3078
+ }
3079
+ };
3080
+ let printACPolyfillWarning = PROCESS.env?.LRU_CACHE_IGNORE_AC_WARNING !== "1";
3081
+ const warnACPolyfill = () => {
3082
+ if (!printACPolyfillWarning) return;
3083
+ printACPolyfillWarning = false;
3084
+ emitWarning("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.", "NO_ABORT_CONTROLLER", "ENOTSUP", warnACPolyfill);
3085
+ };
3086
+ }
3087
+ /* c8 ignore stop */
3088
+ const shouldWarn = (code) => !warned.has(code);
3089
+ const TYPE = Symbol("type");
3090
+ const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
3091
+ /* c8 ignore start */
3092
+ const getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null;
3093
+ /* c8 ignore stop */
3094
+ var ZeroArray = class extends Array {
3095
+ constructor(size) {
3096
+ super(size);
3097
+ this.fill(0);
3098
+ }
3099
+ };
3100
+ var Stack = class Stack {
3101
+ heap;
3102
+ length;
3103
+ static #constructing = false;
3104
+ static create(max) {
3105
+ const HeapCls = getUintArray(max);
3106
+ if (!HeapCls) return [];
3107
+ Stack.#constructing = true;
3108
+ const s = new Stack(max, HeapCls);
3109
+ Stack.#constructing = false;
3110
+ return s;
3111
+ }
3112
+ constructor(max, HeapCls) {
3113
+ /* c8 ignore start */
3114
+ if (!Stack.#constructing) throw new TypeError("instantiate Stack using Stack.create(n)");
3115
+ /* c8 ignore stop */
3116
+ this.heap = new HeapCls(max);
3117
+ this.length = 0;
3118
+ }
3119
+ push(n) {
3120
+ this.heap[this.length++] = n;
3121
+ }
3122
+ pop() {
3123
+ return this.heap[--this.length];
3124
+ }
3125
+ };
3126
+ /**
3127
+ * Default export, the thing you're using this module to get.
3128
+ *
3129
+ * The `K` and `V` types define the key and value types, respectively. The
3130
+ * optional `FC` type defines the type of the `context` object passed to
3131
+ * `cache.fetch()` and `cache.memo()`.
3132
+ *
3133
+ * Keys and values **must not** be `null` or `undefined`.
3134
+ *
3135
+ * All properties from the options object (with the exception of `max`,
3136
+ * `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
3137
+ * added as normal public members. (The listed options are read-only getters.)
3138
+ *
3139
+ * Changing any of these will alter the defaults for subsequent method calls.
3140
+ */
3141
+ var LRUCache = class LRUCache {
3142
+ #max;
3143
+ #maxSize;
3144
+ #dispose;
3145
+ #disposeAfter;
3146
+ #fetchMethod;
3147
+ #memoMethod;
3148
+ /**
3149
+ * {@link LRUCache.OptionsBase.ttl}
3150
+ */
3151
+ ttl;
3152
+ /**
3153
+ * {@link LRUCache.OptionsBase.ttlResolution}
3154
+ */
3155
+ ttlResolution;
3156
+ /**
3157
+ * {@link LRUCache.OptionsBase.ttlAutopurge}
3158
+ */
3159
+ ttlAutopurge;
3160
+ /**
3161
+ * {@link LRUCache.OptionsBase.updateAgeOnGet}
3162
+ */
3163
+ updateAgeOnGet;
3164
+ /**
3165
+ * {@link LRUCache.OptionsBase.updateAgeOnHas}
3166
+ */
3167
+ updateAgeOnHas;
3168
+ /**
3169
+ * {@link LRUCache.OptionsBase.allowStale}
3170
+ */
3171
+ allowStale;
3172
+ /**
3173
+ * {@link LRUCache.OptionsBase.noDisposeOnSet}
3174
+ */
3175
+ noDisposeOnSet;
3176
+ /**
3177
+ * {@link LRUCache.OptionsBase.noUpdateTTL}
3178
+ */
3179
+ noUpdateTTL;
3180
+ /**
3181
+ * {@link LRUCache.OptionsBase.maxEntrySize}
3182
+ */
3183
+ maxEntrySize;
3184
+ /**
3185
+ * {@link LRUCache.OptionsBase.sizeCalculation}
3186
+ */
3187
+ sizeCalculation;
3188
+ /**
3189
+ * {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
3190
+ */
3191
+ noDeleteOnFetchRejection;
3192
+ /**
3193
+ * {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
3194
+ */
3195
+ noDeleteOnStaleGet;
3196
+ /**
3197
+ * {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
3198
+ */
3199
+ allowStaleOnFetchAbort;
3200
+ /**
3201
+ * {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
3202
+ */
3203
+ allowStaleOnFetchRejection;
3204
+ /**
3205
+ * {@link LRUCache.OptionsBase.ignoreFetchAbort}
3206
+ */
3207
+ ignoreFetchAbort;
3208
+ #size;
3209
+ #calculatedSize;
3210
+ #keyMap;
3211
+ #keyList;
3212
+ #valList;
3213
+ #next;
3214
+ #prev;
3215
+ #head;
3216
+ #tail;
3217
+ #free;
3218
+ #disposed;
3219
+ #sizes;
3220
+ #starts;
3221
+ #ttls;
3222
+ #hasDispose;
3223
+ #hasFetchMethod;
3224
+ #hasDisposeAfter;
3225
+ /**
3226
+ * Do not call this method unless you need to inspect the
3227
+ * inner workings of the cache. If anything returned by this
3228
+ * object is modified in any way, strange breakage may occur.
3229
+ *
3230
+ * These fields are private for a reason!
3231
+ *
3232
+ * @internal
3233
+ */
3234
+ static unsafeExposeInternals(c) {
3235
+ return {
3236
+ starts: c.#starts,
3237
+ ttls: c.#ttls,
3238
+ sizes: c.#sizes,
3239
+ keyMap: c.#keyMap,
3240
+ keyList: c.#keyList,
3241
+ valList: c.#valList,
3242
+ next: c.#next,
3243
+ prev: c.#prev,
3244
+ get head() {
3245
+ return c.#head;
3246
+ },
3247
+ get tail() {
3248
+ return c.#tail;
3249
+ },
3250
+ free: c.#free,
3251
+ isBackgroundFetch: (p) => c.#isBackgroundFetch(p),
3252
+ backgroundFetch: (k, index, options, context) => c.#backgroundFetch(k, index, options, context),
3253
+ moveToTail: (index) => c.#moveToTail(index),
3254
+ indexes: (options) => c.#indexes(options),
3255
+ rindexes: (options) => c.#rindexes(options),
3256
+ isStale: (index) => c.#isStale(index)
3257
+ };
3258
+ }
3259
+ /**
3260
+ * {@link LRUCache.OptionsBase.max} (read-only)
3261
+ */
3262
+ get max() {
3263
+ return this.#max;
3264
+ }
3265
+ /**
3266
+ * {@link LRUCache.OptionsBase.maxSize} (read-only)
3267
+ */
3268
+ get maxSize() {
3269
+ return this.#maxSize;
3270
+ }
3271
+ /**
3272
+ * The total computed size of items in the cache (read-only)
3273
+ */
3274
+ get calculatedSize() {
3275
+ return this.#calculatedSize;
3276
+ }
3277
+ /**
3278
+ * The number of items stored in the cache (read-only)
3279
+ */
3280
+ get size() {
3281
+ return this.#size;
3282
+ }
3283
+ /**
3284
+ * {@link LRUCache.OptionsBase.fetchMethod} (read-only)
3285
+ */
3286
+ get fetchMethod() {
3287
+ return this.#fetchMethod;
3288
+ }
3289
+ get memoMethod() {
3290
+ return this.#memoMethod;
3291
+ }
3292
+ /**
3293
+ * {@link LRUCache.OptionsBase.dispose} (read-only)
3294
+ */
3295
+ get dispose() {
3296
+ return this.#dispose;
3297
+ }
3298
+ /**
3299
+ * {@link LRUCache.OptionsBase.disposeAfter} (read-only)
3300
+ */
3301
+ get disposeAfter() {
3302
+ return this.#disposeAfter;
3303
+ }
3304
+ constructor(options) {
3305
+ const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, memoMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort } = options;
3306
+ if (max !== 0 && !isPosInt(max)) throw new TypeError("max option must be a nonnegative integer");
3307
+ const UintArray = max ? getUintArray(max) : Array;
3308
+ if (!UintArray) throw new Error("invalid max value: " + max);
3309
+ this.#max = max;
3310
+ this.#maxSize = maxSize;
3311
+ this.maxEntrySize = maxEntrySize || this.#maxSize;
3312
+ this.sizeCalculation = sizeCalculation;
3313
+ if (this.sizeCalculation) {
3314
+ if (!this.#maxSize && !this.maxEntrySize) throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");
3315
+ if (typeof this.sizeCalculation !== "function") throw new TypeError("sizeCalculation set to non-function");
3316
+ }
3317
+ if (memoMethod !== void 0 && typeof memoMethod !== "function") throw new TypeError("memoMethod must be a function if defined");
3318
+ this.#memoMethod = memoMethod;
3319
+ if (fetchMethod !== void 0 && typeof fetchMethod !== "function") throw new TypeError("fetchMethod must be a function if specified");
3320
+ this.#fetchMethod = fetchMethod;
3321
+ this.#hasFetchMethod = !!fetchMethod;
3322
+ this.#keyMap = new Map();
3323
+ this.#keyList = new Array(max).fill(void 0);
3324
+ this.#valList = new Array(max).fill(void 0);
3325
+ this.#next = new UintArray(max);
3326
+ this.#prev = new UintArray(max);
3327
+ this.#head = 0;
3328
+ this.#tail = 0;
3329
+ this.#free = Stack.create(max);
3330
+ this.#size = 0;
3331
+ this.#calculatedSize = 0;
3332
+ if (typeof dispose === "function") this.#dispose = dispose;
3333
+ if (typeof disposeAfter === "function") {
3334
+ this.#disposeAfter = disposeAfter;
3335
+ this.#disposed = [];
3336
+ } else {
3337
+ this.#disposeAfter = void 0;
3338
+ this.#disposed = void 0;
3339
+ }
3340
+ this.#hasDispose = !!this.#dispose;
3341
+ this.#hasDisposeAfter = !!this.#disposeAfter;
3342
+ this.noDisposeOnSet = !!noDisposeOnSet;
3343
+ this.noUpdateTTL = !!noUpdateTTL;
3344
+ this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection;
3345
+ this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection;
3346
+ this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort;
3347
+ this.ignoreFetchAbort = !!ignoreFetchAbort;
3348
+ if (this.maxEntrySize !== 0) {
3349
+ if (this.#maxSize !== 0) {
3350
+ if (!isPosInt(this.#maxSize)) throw new TypeError("maxSize must be a positive integer if specified");
3351
+ }
3352
+ if (!isPosInt(this.maxEntrySize)) throw new TypeError("maxEntrySize must be a positive integer if specified");
3353
+ this.#initializeSizeTracking();
3354
+ }
3355
+ this.allowStale = !!allowStale;
3356
+ this.noDeleteOnStaleGet = !!noDeleteOnStaleGet;
3357
+ this.updateAgeOnGet = !!updateAgeOnGet;
3358
+ this.updateAgeOnHas = !!updateAgeOnHas;
3359
+ this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1;
3360
+ this.ttlAutopurge = !!ttlAutopurge;
3361
+ this.ttl = ttl || 0;
3362
+ if (this.ttl) {
3363
+ if (!isPosInt(this.ttl)) throw new TypeError("ttl must be a positive integer if specified");
3364
+ this.#initializeTTLTracking();
3365
+ }
3366
+ if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) throw new TypeError("At least one of max, maxSize, or ttl is required");
3367
+ if (!this.ttlAutopurge && !this.#max && !this.#maxSize) {
3368
+ const code = "LRU_CACHE_UNBOUNDED";
3369
+ if (shouldWarn(code)) {
3370
+ warned.add(code);
3371
+ const msg = "TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.";
3372
+ emitWarning(msg, "UnboundedCacheWarning", code, LRUCache);
3373
+ }
3374
+ }
3375
+ }
3376
+ /**
3377
+ * Return the number of ms left in the item's TTL. If item is not in cache,
3378
+ * returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
3379
+ */
3380
+ getRemainingTTL(key) {
3381
+ return this.#keyMap.has(key) ? Infinity : 0;
3382
+ }
3383
+ #initializeTTLTracking() {
3384
+ const ttls = new ZeroArray(this.#max);
3385
+ const starts = new ZeroArray(this.#max);
3386
+ this.#ttls = ttls;
3387
+ this.#starts = starts;
3388
+ this.#setItemTTL = (index, ttl, start = perf.now()) => {
3389
+ starts[index] = ttl !== 0 ? start : 0;
3390
+ ttls[index] = ttl;
3391
+ if (ttl !== 0 && this.ttlAutopurge) {
3392
+ const t = setTimeout(() => {
3393
+ if (this.#isStale(index)) this.#delete(this.#keyList[index], "expire");
3394
+ }, ttl + 1);
3395
+ /* c8 ignore start */
3396
+ if (t.unref) t.unref();
3397
+ }
3398
+ };
3399
+ this.#updateItemAge = (index) => {
3400
+ starts[index] = ttls[index] !== 0 ? perf.now() : 0;
3401
+ };
3402
+ this.#statusTTL = (status, index) => {
3403
+ if (ttls[index]) {
3404
+ const ttl = ttls[index];
3405
+ const start = starts[index];
3406
+ /* c8 ignore next */
3407
+ if (!ttl || !start) return;
3408
+ status.ttl = ttl;
3409
+ status.start = start;
3410
+ status.now = cachedNow || getNow();
3411
+ const age = status.now - start;
3412
+ status.remainingTTL = ttl - age;
3413
+ }
3414
+ };
3415
+ let cachedNow = 0;
3416
+ const getNow = () => {
3417
+ const n = perf.now();
3418
+ if (this.ttlResolution > 0) {
3419
+ cachedNow = n;
3420
+ const t = setTimeout(() => cachedNow = 0, this.ttlResolution);
3421
+ /* c8 ignore start */
3422
+ if (t.unref) t.unref();
3423
+ }
3424
+ return n;
3425
+ };
3426
+ this.getRemainingTTL = (key) => {
3427
+ const index = this.#keyMap.get(key);
3428
+ if (index === void 0) return 0;
3429
+ const ttl = ttls[index];
3430
+ const start = starts[index];
3431
+ if (!ttl || !start) return Infinity;
3432
+ const age = (cachedNow || getNow()) - start;
3433
+ return ttl - age;
3434
+ };
3435
+ this.#isStale = (index) => {
3436
+ const s = starts[index];
3437
+ const t = ttls[index];
3438
+ return !!t && !!s && (cachedNow || getNow()) - s > t;
3439
+ };
3440
+ }
3441
+ #updateItemAge = () => {};
3442
+ #statusTTL = () => {};
3443
+ #setItemTTL = () => {};
3444
+ /* c8 ignore stop */
3445
+ #isStale = () => false;
3446
+ #initializeSizeTracking() {
3447
+ const sizes = new ZeroArray(this.#max);
3448
+ this.#calculatedSize = 0;
3449
+ this.#sizes = sizes;
3450
+ this.#removeItemSize = (index) => {
3451
+ this.#calculatedSize -= sizes[index];
3452
+ sizes[index] = 0;
3453
+ };
3454
+ this.#requireSize = (k, v, size, sizeCalculation) => {
3455
+ if (this.#isBackgroundFetch(v)) return 0;
3456
+ if (!isPosInt(size)) if (sizeCalculation) {
3457
+ if (typeof sizeCalculation !== "function") throw new TypeError("sizeCalculation must be a function");
3458
+ size = sizeCalculation(v, k);
3459
+ if (!isPosInt(size)) throw new TypeError("sizeCalculation return invalid (expect positive integer)");
3460
+ } else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");
3461
+ return size;
3462
+ };
3463
+ this.#addItemSize = (index, size, status) => {
3464
+ sizes[index] = size;
3465
+ if (this.#maxSize) {
3466
+ const maxSize = this.#maxSize - sizes[index];
3467
+ while (this.#calculatedSize > maxSize) this.#evict(true);
3468
+ }
3469
+ this.#calculatedSize += sizes[index];
3470
+ if (status) {
3471
+ status.entrySize = size;
3472
+ status.totalCalculatedSize = this.#calculatedSize;
3473
+ }
3474
+ };
3475
+ }
3476
+ #removeItemSize = (_i) => {};
3477
+ #addItemSize = (_i, _s, _st) => {};
3478
+ #requireSize = (_k, _v, size, sizeCalculation) => {
3479
+ if (size || sizeCalculation) throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");
3480
+ return 0;
3481
+ };
3482
+ *#indexes({ allowStale = this.allowStale } = {}) {
3483
+ if (this.#size) for (let i = this.#tail;;) {
3484
+ if (!this.#isValidIndex(i)) break;
3485
+ if (allowStale || !this.#isStale(i)) yield i;
3486
+ if (i === this.#head) break;
3487
+ else i = this.#prev[i];
3488
+ }
3489
+ }
3490
+ *#rindexes({ allowStale = this.allowStale } = {}) {
3491
+ if (this.#size) for (let i = this.#head;;) {
3492
+ if (!this.#isValidIndex(i)) break;
3493
+ if (allowStale || !this.#isStale(i)) yield i;
3494
+ if (i === this.#tail) break;
3495
+ else i = this.#next[i];
3496
+ }
3497
+ }
3498
+ #isValidIndex(index) {
3499
+ return index !== void 0 && this.#keyMap.get(this.#keyList[index]) === index;
3500
+ }
3501
+ /**
3502
+ * Return a generator yielding `[key, value]` pairs,
3503
+ * in order from most recently used to least recently used.
3504
+ */
3505
+ *entries() {
3506
+ for (const i of this.#indexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
3507
+ }
3508
+ /**
3509
+ * Inverse order version of {@link LRUCache.entries}
3510
+ *
3511
+ * Return a generator yielding `[key, value]` pairs,
3512
+ * in order from least recently used to most recently used.
3513
+ */
3514
+ *rentries() {
3515
+ for (const i of this.#rindexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
3516
+ }
3517
+ /**
3518
+ * Return a generator yielding the keys in the cache,
3519
+ * in order from most recently used to least recently used.
3520
+ */
3521
+ *keys() {
3522
+ for (const i of this.#indexes()) {
3523
+ const k = this.#keyList[i];
3524
+ if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
3525
+ }
3526
+ }
3527
+ /**
3528
+ * Inverse order version of {@link LRUCache.keys}
3529
+ *
3530
+ * Return a generator yielding the keys in the cache,
3531
+ * in order from least recently used to most recently used.
3532
+ */
3533
+ *rkeys() {
3534
+ for (const i of this.#rindexes()) {
3535
+ const k = this.#keyList[i];
3536
+ if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
3537
+ }
3538
+ }
3539
+ /**
3540
+ * Return a generator yielding the values in the cache,
3541
+ * in order from most recently used to least recently used.
3542
+ */
3543
+ *values() {
3544
+ for (const i of this.#indexes()) {
3545
+ const v = this.#valList[i];
3546
+ if (v !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
3547
+ }
3548
+ }
3549
+ /**
3550
+ * Inverse order version of {@link LRUCache.values}
3551
+ *
3552
+ * Return a generator yielding the values in the cache,
3553
+ * in order from least recently used to most recently used.
3554
+ */
3555
+ *rvalues() {
3556
+ for (const i of this.#rindexes()) {
3557
+ const v = this.#valList[i];
3558
+ if (v !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
3559
+ }
3560
+ }
3561
+ /**
3562
+ * Iterating over the cache itself yields the same results as
3563
+ * {@link LRUCache.entries}
3564
+ */
3565
+ [Symbol.iterator]() {
3566
+ return this.entries();
3567
+ }
3568
+ /**
3569
+ * A String value that is used in the creation of the default string
3570
+ * description of an object. Called by the built-in method
3571
+ * `Object.prototype.toString`.
3572
+ */
3573
+ [Symbol.toStringTag] = "LRUCache";
3574
+ /**
3575
+ * Find a value for which the supplied fn method returns a truthy value,
3576
+ * similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
3577
+ */
3578
+ find(fn, getOptions = {}) {
3579
+ for (const i of this.#indexes()) {
3580
+ const v = this.#valList[i];
3581
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
3582
+ if (value === void 0) continue;
3583
+ if (fn(value, this.#keyList[i], this)) return this.get(this.#keyList[i], getOptions);
3584
+ }
3585
+ }
3586
+ /**
3587
+ * Call the supplied function on each item in the cache, in order from most
3588
+ * recently used to least recently used.
3589
+ *
3590
+ * `fn` is called as `fn(value, key, cache)`.
3591
+ *
3592
+ * If `thisp` is provided, function will be called in the `this`-context of
3593
+ * the provided object, or the cache if no `thisp` object is provided.
3594
+ *
3595
+ * Does not update age or recenty of use, or iterate over stale values.
3596
+ */
3597
+ forEach(fn, thisp = this) {
3598
+ for (const i of this.#indexes()) {
3599
+ const v = this.#valList[i];
3600
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
3601
+ if (value === void 0) continue;
3602
+ fn.call(thisp, value, this.#keyList[i], this);
3603
+ }
3604
+ }
3605
+ /**
3606
+ * The same as {@link LRUCache.forEach} but items are iterated over in
3607
+ * reverse order. (ie, less recently used items are iterated over first.)
3608
+ */
3609
+ rforEach(fn, thisp = this) {
3610
+ for (const i of this.#rindexes()) {
3611
+ const v = this.#valList[i];
3612
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
3613
+ if (value === void 0) continue;
3614
+ fn.call(thisp, value, this.#keyList[i], this);
3615
+ }
3616
+ }
3617
+ /**
3618
+ * Delete any stale entries. Returns true if anything was removed,
3619
+ * false otherwise.
3620
+ */
3621
+ purgeStale() {
3622
+ let deleted = false;
3623
+ for (const i of this.#rindexes({ allowStale: true })) if (this.#isStale(i)) {
3624
+ this.#delete(this.#keyList[i], "expire");
3625
+ deleted = true;
3626
+ }
3627
+ return deleted;
3628
+ }
3629
+ /**
3630
+ * Get the extended info about a given entry, to get its value, size, and
3631
+ * TTL info simultaneously. Returns `undefined` if the key is not present.
3632
+ *
3633
+ * Unlike {@link LRUCache#dump}, which is designed to be portable and survive
3634
+ * serialization, the `start` value is always the current timestamp, and the
3635
+ * `ttl` is a calculated remaining time to live (negative if expired).
3636
+ *
3637
+ * Always returns stale values, if their info is found in the cache, so be
3638
+ * sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
3639
+ * if relevant.
3640
+ */
3641
+ info(key) {
3642
+ const i = this.#keyMap.get(key);
3643
+ if (i === void 0) return void 0;
3644
+ const v = this.#valList[i];
3645
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
3646
+ if (value === void 0) return void 0;
3647
+ const entry = { value };
3648
+ if (this.#ttls && this.#starts) {
3649
+ const ttl = this.#ttls[i];
3650
+ const start = this.#starts[i];
3651
+ if (ttl && start) {
3652
+ const remain = ttl - (perf.now() - start);
3653
+ entry.ttl = remain;
3654
+ entry.start = Date.now();
3655
+ }
3656
+ }
3657
+ if (this.#sizes) entry.size = this.#sizes[i];
3658
+ return entry;
3659
+ }
3660
+ /**
3661
+ * Return an array of [key, {@link LRUCache.Entry}] tuples which can be
3662
+ * passed to {@link LRLUCache#load}.
3663
+ *
3664
+ * The `start` fields are calculated relative to a portable `Date.now()`
3665
+ * timestamp, even if `performance.now()` is available.
3666
+ *
3667
+ * Stale entries are always included in the `dump`, even if
3668
+ * {@link LRUCache.OptionsBase.allowStale} is false.
3669
+ *
3670
+ * Note: this returns an actual array, not a generator, so it can be more
3671
+ * easily passed around.
3672
+ */
3673
+ dump() {
3674
+ const arr = [];
3675
+ for (const i of this.#indexes({ allowStale: true })) {
3676
+ const key = this.#keyList[i];
3677
+ const v = this.#valList[i];
3678
+ const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
3679
+ if (value === void 0 || key === void 0) continue;
3680
+ const entry = { value };
3681
+ if (this.#ttls && this.#starts) {
3682
+ entry.ttl = this.#ttls[i];
3683
+ const age = perf.now() - this.#starts[i];
3684
+ entry.start = Math.floor(Date.now() - age);
3685
+ }
3686
+ if (this.#sizes) entry.size = this.#sizes[i];
3687
+ arr.unshift([key, entry]);
3688
+ }
3689
+ return arr;
3690
+ }
3691
+ /**
3692
+ * Reset the cache and load in the items in entries in the order listed.
3693
+ *
3694
+ * The shape of the resulting cache may be different if the same options are
3695
+ * not used in both caches.
3696
+ *
3697
+ * The `start` fields are assumed to be calculated relative to a portable
3698
+ * `Date.now()` timestamp, even if `performance.now()` is available.
3699
+ */
3700
+ load(arr) {
3701
+ this.clear();
3702
+ for (const [key, entry] of arr) {
3703
+ if (entry.start) {
3704
+ const age = Date.now() - entry.start;
3705
+ entry.start = perf.now() - age;
3706
+ }
3707
+ this.set(key, entry.value, entry);
3708
+ }
3709
+ }
3710
+ /**
3711
+ * Add a value to the cache.
3712
+ *
3713
+ * Note: if `undefined` is specified as a value, this is an alias for
3714
+ * {@link LRUCache#delete}
3715
+ *
3716
+ * Fields on the {@link LRUCache.SetOptions} options param will override
3717
+ * their corresponding values in the constructor options for the scope
3718
+ * of this single `set()` operation.
3719
+ *
3720
+ * If `start` is provided, then that will set the effective start
3721
+ * time for the TTL calculation. Note that this must be a previous
3722
+ * value of `performance.now()` if supported, or a previous value of
3723
+ * `Date.now()` if not.
3724
+ *
3725
+ * Options object may also include `size`, which will prevent
3726
+ * calling the `sizeCalculation` function and just use the specified
3727
+ * number if it is a positive integer, and `noDisposeOnSet` which
3728
+ * will prevent calling a `dispose` function in the case of
3729
+ * overwrites.
3730
+ *
3731
+ * If the `size` (or return value of `sizeCalculation`) for a given
3732
+ * entry is greater than `maxEntrySize`, then the item will not be
3733
+ * added to the cache.
3734
+ *
3735
+ * Will update the recency of the entry.
3736
+ *
3737
+ * If the value is `undefined`, then this is an alias for
3738
+ * `cache.delete(key)`. `undefined` is never stored in the cache.
3739
+ */
3740
+ set(k, v, setOptions = {}) {
3741
+ if (v === void 0) {
3742
+ this.delete(k);
3743
+ return this;
3744
+ }
3745
+ const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status } = setOptions;
3746
+ let { noUpdateTTL = this.noUpdateTTL } = setOptions;
3747
+ const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation);
3748
+ if (this.maxEntrySize && size > this.maxEntrySize) {
3749
+ if (status) {
3750
+ status.set = "miss";
3751
+ status.maxEntrySizeExceeded = true;
3752
+ }
3753
+ this.#delete(k, "set");
3754
+ return this;
3755
+ }
3756
+ let index = this.#size === 0 ? void 0 : this.#keyMap.get(k);
3757
+ if (index === void 0) {
3758
+ index = this.#size === 0 ? this.#tail : this.#free.length !== 0 ? this.#free.pop() : this.#size === this.#max ? this.#evict(false) : this.#size;
3759
+ this.#keyList[index] = k;
3760
+ this.#valList[index] = v;
3761
+ this.#keyMap.set(k, index);
3762
+ this.#next[this.#tail] = index;
3763
+ this.#prev[index] = this.#tail;
3764
+ this.#tail = index;
3765
+ this.#size++;
3766
+ this.#addItemSize(index, size, status);
3767
+ if (status) status.set = "add";
3768
+ noUpdateTTL = false;
3769
+ } else {
3770
+ this.#moveToTail(index);
3771
+ const oldVal = this.#valList[index];
3772
+ if (v !== oldVal) {
3773
+ if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
3774
+ oldVal.__abortController.abort(new Error("replaced"));
3775
+ const { __staleWhileFetching: s } = oldVal;
3776
+ if (s !== void 0 && !noDisposeOnSet) {
3777
+ if (this.#hasDispose) this.#dispose?.(s, k, "set");
3778
+ if (this.#hasDisposeAfter) this.#disposed?.push([
3779
+ s,
3780
+ k,
3781
+ "set"
3782
+ ]);
3783
+ }
3784
+ } else if (!noDisposeOnSet) {
3785
+ if (this.#hasDispose) this.#dispose?.(oldVal, k, "set");
3786
+ if (this.#hasDisposeAfter) this.#disposed?.push([
3787
+ oldVal,
3788
+ k,
3789
+ "set"
3790
+ ]);
3791
+ }
3792
+ this.#removeItemSize(index);
3793
+ this.#addItemSize(index, size, status);
3794
+ this.#valList[index] = v;
3795
+ if (status) {
3796
+ status.set = "replace";
3797
+ const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ? oldVal.__staleWhileFetching : oldVal;
3798
+ if (oldValue !== void 0) status.oldValue = oldValue;
3799
+ }
3800
+ } else if (status) status.set = "update";
3801
+ }
3802
+ if (ttl !== 0 && !this.#ttls) this.#initializeTTLTracking();
3803
+ if (this.#ttls) {
3804
+ if (!noUpdateTTL) this.#setItemTTL(index, ttl, start);
3805
+ if (status) this.#statusTTL(status, index);
3806
+ }
3807
+ if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) {
3808
+ const dt = this.#disposed;
3809
+ let task;
3810
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
3811
+ }
3812
+ return this;
3813
+ }
3814
+ /**
3815
+ * Evict the least recently used item, returning its value or
3816
+ * `undefined` if cache is empty.
3817
+ */
3818
+ pop() {
3819
+ try {
3820
+ while (this.#size) {
3821
+ const val = this.#valList[this.#head];
3822
+ this.#evict(true);
3823
+ if (this.#isBackgroundFetch(val)) {
3824
+ if (val.__staleWhileFetching) return val.__staleWhileFetching;
3825
+ } else if (val !== void 0) return val;
3826
+ }
3827
+ } finally {
3828
+ if (this.#hasDisposeAfter && this.#disposed) {
3829
+ const dt = this.#disposed;
3830
+ let task;
3831
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
3832
+ }
3833
+ }
3834
+ }
3835
+ #evict(free) {
3836
+ const head = this.#head;
3837
+ const k = this.#keyList[head];
3838
+ const v = this.#valList[head];
3839
+ if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) v.__abortController.abort(new Error("evicted"));
3840
+ else if (this.#hasDispose || this.#hasDisposeAfter) {
3841
+ if (this.#hasDispose) this.#dispose?.(v, k, "evict");
3842
+ if (this.#hasDisposeAfter) this.#disposed?.push([
3843
+ v,
3844
+ k,
3845
+ "evict"
3846
+ ]);
3847
+ }
3848
+ this.#removeItemSize(head);
3849
+ if (free) {
3850
+ this.#keyList[head] = void 0;
3851
+ this.#valList[head] = void 0;
3852
+ this.#free.push(head);
3853
+ }
3854
+ if (this.#size === 1) {
3855
+ this.#head = this.#tail = 0;
3856
+ this.#free.length = 0;
3857
+ } else this.#head = this.#next[head];
3858
+ this.#keyMap.delete(k);
3859
+ this.#size--;
3860
+ return head;
3861
+ }
3862
+ /**
3863
+ * Check if a key is in the cache, without updating the recency of use.
3864
+ * Will return false if the item is stale, even though it is technically
3865
+ * in the cache.
3866
+ *
3867
+ * Check if a key is in the cache, without updating the recency of
3868
+ * use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
3869
+ * to `true` in either the options or the constructor.
3870
+ *
3871
+ * Will return `false` if the item is stale, even though it is technically in
3872
+ * the cache. The difference can be determined (if it matters) by using a
3873
+ * `status` argument, and inspecting the `has` field.
3874
+ *
3875
+ * Will not update item age unless
3876
+ * {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
3877
+ */
3878
+ has(k, hasOptions = {}) {
3879
+ const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
3880
+ const index = this.#keyMap.get(k);
3881
+ if (index !== void 0) {
3882
+ const v = this.#valList[index];
3883
+ if (this.#isBackgroundFetch(v) && v.__staleWhileFetching === void 0) return false;
3884
+ if (!this.#isStale(index)) {
3885
+ if (updateAgeOnHas) this.#updateItemAge(index);
3886
+ if (status) {
3887
+ status.has = "hit";
3888
+ this.#statusTTL(status, index);
3889
+ }
3890
+ return true;
3891
+ } else if (status) {
3892
+ status.has = "stale";
3893
+ this.#statusTTL(status, index);
3894
+ }
3895
+ } else if (status) status.has = "miss";
3896
+ return false;
3897
+ }
3898
+ /**
3899
+ * Like {@link LRUCache#get} but doesn't update recency or delete stale
3900
+ * items.
3901
+ *
3902
+ * Returns `undefined` if the item is stale, unless
3903
+ * {@link LRUCache.OptionsBase.allowStale} is set.
3904
+ */
3905
+ peek(k, peekOptions = {}) {
3906
+ const { allowStale = this.allowStale } = peekOptions;
3907
+ const index = this.#keyMap.get(k);
3908
+ if (index === void 0 || !allowStale && this.#isStale(index)) return;
3909
+ const v = this.#valList[index];
3910
+ return this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
3911
+ }
3912
+ #backgroundFetch(k, index, options, context) {
3913
+ const v = index === void 0 ? void 0 : this.#valList[index];
3914
+ if (this.#isBackgroundFetch(v)) return v;
3915
+ const ac = new AC();
3916
+ const { signal } = options;
3917
+ signal?.addEventListener("abort", () => ac.abort(signal.reason), { signal: ac.signal });
3918
+ const fetchOpts = {
3919
+ signal: ac.signal,
3920
+ options,
3921
+ context
3922
+ };
3923
+ const cb = (v$1, updateCache = false) => {
3924
+ const { aborted } = ac.signal;
3925
+ const ignoreAbort = options.ignoreFetchAbort && v$1 !== void 0;
3926
+ if (options.status) if (aborted && !updateCache) {
3927
+ options.status.fetchAborted = true;
3928
+ options.status.fetchError = ac.signal.reason;
3929
+ if (ignoreAbort) options.status.fetchAbortIgnored = true;
3930
+ } else options.status.fetchResolved = true;
3931
+ if (aborted && !ignoreAbort && !updateCache) return fetchFail(ac.signal.reason);
3932
+ const bf$1 = p;
3933
+ if (this.#valList[index] === p) if (v$1 === void 0) if (bf$1.__staleWhileFetching) this.#valList[index] = bf$1.__staleWhileFetching;
3934
+ else this.#delete(k, "fetch");
3935
+ else {
3936
+ if (options.status) options.status.fetchUpdated = true;
3937
+ this.set(k, v$1, fetchOpts.options);
3938
+ }
3939
+ return v$1;
3940
+ };
3941
+ const eb = (er) => {
3942
+ if (options.status) {
3943
+ options.status.fetchRejected = true;
3944
+ options.status.fetchError = er;
3945
+ }
3946
+ return fetchFail(er);
3947
+ };
3948
+ const fetchFail = (er) => {
3949
+ const { aborted } = ac.signal;
3950
+ const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
3951
+ const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
3952
+ const noDelete = allowStale || options.noDeleteOnFetchRejection;
3953
+ const bf$1 = p;
3954
+ if (this.#valList[index] === p) {
3955
+ const del = !noDelete || bf$1.__staleWhileFetching === void 0;
3956
+ if (del) this.#delete(k, "fetch");
3957
+ else if (!allowStaleAborted) this.#valList[index] = bf$1.__staleWhileFetching;
3958
+ }
3959
+ if (allowStale) {
3960
+ if (options.status && bf$1.__staleWhileFetching !== void 0) options.status.returnedStale = true;
3961
+ return bf$1.__staleWhileFetching;
3962
+ } else if (bf$1.__returned === bf$1) throw er;
3963
+ };
3964
+ const pcall = (res, rej) => {
3965
+ const fmp = this.#fetchMethod?.(k, v, fetchOpts);
3966
+ if (fmp && fmp instanceof Promise) fmp.then((v$1) => res(v$1 === void 0 ? void 0 : v$1), rej);
3967
+ ac.signal.addEventListener("abort", () => {
3968
+ if (!options.ignoreFetchAbort || options.allowStaleOnFetchAbort) {
3969
+ res(void 0);
3970
+ if (options.allowStaleOnFetchAbort) res = (v$1) => cb(v$1, true);
3971
+ }
3972
+ });
3973
+ };
3974
+ if (options.status) options.status.fetchDispatched = true;
3975
+ const p = new Promise(pcall).then(cb, eb);
3976
+ const bf = Object.assign(p, {
3977
+ __abortController: ac,
3978
+ __staleWhileFetching: v,
3979
+ __returned: void 0
3980
+ });
3981
+ if (index === void 0) {
3982
+ this.set(k, bf, {
3983
+ ...fetchOpts.options,
3984
+ status: void 0
3985
+ });
3986
+ index = this.#keyMap.get(k);
3987
+ } else this.#valList[index] = bf;
3988
+ return bf;
3989
+ }
3990
+ #isBackgroundFetch(p) {
3991
+ if (!this.#hasFetchMethod) return false;
3992
+ const b = p;
3993
+ return !!b && b instanceof Promise && b.hasOwnProperty("__staleWhileFetching") && b.__abortController instanceof AC;
3994
+ }
3995
+ async fetch(k, fetchOptions = {}) {
3996
+ const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL, noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal } = fetchOptions;
3997
+ if (!this.#hasFetchMethod) {
3998
+ if (status) status.fetch = "get";
3999
+ return this.get(k, {
4000
+ allowStale,
4001
+ updateAgeOnGet,
4002
+ noDeleteOnStaleGet,
4003
+ status
4004
+ });
4005
+ }
4006
+ const options = {
4007
+ allowStale,
4008
+ updateAgeOnGet,
4009
+ noDeleteOnStaleGet,
4010
+ ttl,
4011
+ noDisposeOnSet,
4012
+ size,
4013
+ sizeCalculation,
4014
+ noUpdateTTL,
4015
+ noDeleteOnFetchRejection,
4016
+ allowStaleOnFetchRejection,
4017
+ allowStaleOnFetchAbort,
4018
+ ignoreFetchAbort,
4019
+ status,
4020
+ signal
4021
+ };
4022
+ let index = this.#keyMap.get(k);
4023
+ if (index === void 0) {
4024
+ if (status) status.fetch = "miss";
4025
+ const p = this.#backgroundFetch(k, index, options, context);
4026
+ return p.__returned = p;
4027
+ } else {
4028
+ const v = this.#valList[index];
4029
+ if (this.#isBackgroundFetch(v)) {
4030
+ const stale = allowStale && v.__staleWhileFetching !== void 0;
4031
+ if (status) {
4032
+ status.fetch = "inflight";
4033
+ if (stale) status.returnedStale = true;
4034
+ }
4035
+ return stale ? v.__staleWhileFetching : v.__returned = v;
4036
+ }
4037
+ const isStale = this.#isStale(index);
4038
+ if (!forceRefresh && !isStale) {
4039
+ if (status) status.fetch = "hit";
4040
+ this.#moveToTail(index);
4041
+ if (updateAgeOnGet) this.#updateItemAge(index);
4042
+ if (status) this.#statusTTL(status, index);
4043
+ return v;
4044
+ }
4045
+ const p = this.#backgroundFetch(k, index, options, context);
4046
+ const hasStale = p.__staleWhileFetching !== void 0;
4047
+ const staleVal = hasStale && allowStale;
4048
+ if (status) {
4049
+ status.fetch = isStale ? "stale" : "refresh";
4050
+ if (staleVal && isStale) status.returnedStale = true;
4051
+ }
4052
+ return staleVal ? p.__staleWhileFetching : p.__returned = p;
4053
+ }
4054
+ }
4055
+ async forceFetch(k, fetchOptions = {}) {
4056
+ const v = await this.fetch(k, fetchOptions);
4057
+ if (v === void 0) throw new Error("fetch() returned undefined");
4058
+ return v;
4059
+ }
4060
+ memo(k, memoOptions = {}) {
4061
+ const memoMethod = this.#memoMethod;
4062
+ if (!memoMethod) throw new Error("no memoMethod provided to constructor");
4063
+ const { context, forceRefresh,...options } = memoOptions;
4064
+ const v = this.get(k, options);
4065
+ if (!forceRefresh && v !== void 0) return v;
4066
+ const vv = memoMethod(k, v, {
4067
+ options,
4068
+ context
4069
+ });
4070
+ this.set(k, vv, options);
4071
+ return vv;
4072
+ }
4073
+ /**
4074
+ * Return a value from the cache. Will update the recency of the cache
4075
+ * entry found.
4076
+ *
4077
+ * If the key is not found, get() will return `undefined`.
4078
+ */
4079
+ get(k, getOptions = {}) {
4080
+ const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status } = getOptions;
4081
+ const index = this.#keyMap.get(k);
4082
+ if (index !== void 0) {
4083
+ const value = this.#valList[index];
4084
+ const fetching = this.#isBackgroundFetch(value);
4085
+ if (status) this.#statusTTL(status, index);
4086
+ if (this.#isStale(index)) {
4087
+ if (status) status.get = "stale";
4088
+ if (!fetching) {
4089
+ if (!noDeleteOnStaleGet) this.#delete(k, "expire");
4090
+ if (status && allowStale) status.returnedStale = true;
4091
+ return allowStale ? value : void 0;
4092
+ } else {
4093
+ if (status && allowStale && value.__staleWhileFetching !== void 0) status.returnedStale = true;
4094
+ return allowStale ? value.__staleWhileFetching : void 0;
4095
+ }
4096
+ } else {
4097
+ if (status) status.get = "hit";
4098
+ if (fetching) return value.__staleWhileFetching;
4099
+ this.#moveToTail(index);
4100
+ if (updateAgeOnGet) this.#updateItemAge(index);
4101
+ return value;
4102
+ }
4103
+ } else if (status) status.get = "miss";
4104
+ }
4105
+ #connect(p, n) {
4106
+ this.#prev[n] = p;
4107
+ this.#next[p] = n;
4108
+ }
4109
+ #moveToTail(index) {
4110
+ if (index !== this.#tail) {
4111
+ if (index === this.#head) this.#head = this.#next[index];
4112
+ else this.#connect(this.#prev[index], this.#next[index]);
4113
+ this.#connect(this.#tail, index);
4114
+ this.#tail = index;
4115
+ }
4116
+ }
4117
+ /**
4118
+ * Deletes a key out of the cache.
4119
+ *
4120
+ * Returns true if the key was deleted, false otherwise.
4121
+ */
4122
+ delete(k) {
4123
+ return this.#delete(k, "delete");
4124
+ }
4125
+ #delete(k, reason) {
4126
+ let deleted = false;
4127
+ if (this.#size !== 0) {
4128
+ const index = this.#keyMap.get(k);
4129
+ if (index !== void 0) {
4130
+ deleted = true;
4131
+ if (this.#size === 1) this.#clear(reason);
4132
+ else {
4133
+ this.#removeItemSize(index);
4134
+ const v = this.#valList[index];
4135
+ if (this.#isBackgroundFetch(v)) v.__abortController.abort(new Error("deleted"));
4136
+ else if (this.#hasDispose || this.#hasDisposeAfter) {
4137
+ if (this.#hasDispose) this.#dispose?.(v, k, reason);
4138
+ if (this.#hasDisposeAfter) this.#disposed?.push([
4139
+ v,
4140
+ k,
4141
+ reason
4142
+ ]);
4143
+ }
4144
+ this.#keyMap.delete(k);
4145
+ this.#keyList[index] = void 0;
4146
+ this.#valList[index] = void 0;
4147
+ if (index === this.#tail) this.#tail = this.#prev[index];
4148
+ else if (index === this.#head) this.#head = this.#next[index];
4149
+ else {
4150
+ const pi = this.#prev[index];
4151
+ this.#next[pi] = this.#next[index];
4152
+ const ni = this.#next[index];
4153
+ this.#prev[ni] = this.#prev[index];
4154
+ }
4155
+ this.#size--;
4156
+ this.#free.push(index);
4157
+ }
4158
+ }
4159
+ }
4160
+ if (this.#hasDisposeAfter && this.#disposed?.length) {
4161
+ const dt = this.#disposed;
4162
+ let task;
4163
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
4164
+ }
4165
+ return deleted;
4166
+ }
4167
+ /**
4168
+ * Clear the cache entirely, throwing away all values.
4169
+ */
4170
+ clear() {
4171
+ return this.#clear("delete");
4172
+ }
4173
+ #clear(reason) {
4174
+ for (const index of this.#rindexes({ allowStale: true })) {
4175
+ const v = this.#valList[index];
4176
+ if (this.#isBackgroundFetch(v)) v.__abortController.abort(new Error("deleted"));
4177
+ else {
4178
+ const k = this.#keyList[index];
4179
+ if (this.#hasDispose) this.#dispose?.(v, k, reason);
4180
+ if (this.#hasDisposeAfter) this.#disposed?.push([
4181
+ v,
4182
+ k,
4183
+ reason
4184
+ ]);
4185
+ }
4186
+ }
4187
+ this.#keyMap.clear();
4188
+ this.#valList.fill(void 0);
4189
+ this.#keyList.fill(void 0);
4190
+ if (this.#ttls && this.#starts) {
4191
+ this.#ttls.fill(0);
4192
+ this.#starts.fill(0);
4193
+ }
4194
+ if (this.#sizes) this.#sizes.fill(0);
4195
+ this.#head = 0;
4196
+ this.#tail = 0;
4197
+ this.#free.length = 0;
4198
+ this.#calculatedSize = 0;
4199
+ this.#size = 0;
4200
+ if (this.#hasDisposeAfter && this.#disposed) {
4201
+ const dt = this.#disposed;
4202
+ let task;
4203
+ while (task = dt?.shift()) this.#disposeAfter?.(...task);
4204
+ }
4205
+ }
4206
+ };
4207
+
4208
+ //#endregion
4209
+ //#region node_modules/path-scurry/dist/esm/index.js
4210
+ const realpathSync$2 = realpathSync$1.native;
4211
+ const defaultFS = {
4212
+ lstatSync,
4213
+ readdir: readdir$2,
4214
+ readdirSync: readdirSync$1,
4215
+ readlinkSync,
4216
+ realpathSync: realpathSync$2,
4217
+ promises: {
4218
+ lstat,
4219
+ readdir: readdir$1,
4220
+ readlink,
4221
+ realpath
4222
+ }
4223
+ };
4224
+ const fsFromOption = (fsOption) => !fsOption || fsOption === defaultFS || fsOption === actualFS ? defaultFS : {
4225
+ ...defaultFS,
4226
+ ...fsOption,
4227
+ promises: {
4228
+ ...defaultFS.promises,
4229
+ ...fsOption.promises || {}
4230
+ }
4231
+ };
4232
+ const uncDriveRegexp = /^\\\\\?\\([a-z]:)\\?$/i;
4233
+ const uncToDrive = (rootPath) => rootPath.replace(/\//g, "\\").replace(uncDriveRegexp, "$1\\");
4234
+ const eitherSep = /[\\\/]/;
4235
+ const UNKNOWN = 0;
4236
+ const IFIFO = 1;
4237
+ const IFCHR = 2;
4238
+ const IFDIR = 4;
4239
+ const IFBLK = 6;
4240
+ const IFREG = 8;
4241
+ const IFLNK = 10;
4242
+ const IFSOCK = 12;
4243
+ const IFMT = 15;
4244
+ const IFMT_UNKNOWN = ~IFMT;
4245
+ const READDIR_CALLED = 16;
4246
+ const LSTAT_CALLED = 32;
4247
+ const ENOTDIR = 64;
4248
+ const ENOENT = 128;
4249
+ const ENOREADLINK = 256;
4250
+ const ENOREALPATH = 512;
4251
+ const ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
4252
+ const TYPEMASK = 1023;
4253
+ const entToType = (s) => s.isFile() ? IFREG : s.isDirectory() ? IFDIR : s.isSymbolicLink() ? IFLNK : s.isCharacterDevice() ? IFCHR : s.isBlockDevice() ? IFBLK : s.isSocket() ? IFSOCK : s.isFIFO() ? IFIFO : UNKNOWN;
4254
+ const normalizeCache = new Map();
4255
+ const normalize = (s) => {
4256
+ const c = normalizeCache.get(s);
4257
+ if (c) return c;
4258
+ const n = s.normalize("NFKD");
4259
+ normalizeCache.set(s, n);
4260
+ return n;
4261
+ };
4262
+ const normalizeNocaseCache = new Map();
4263
+ const normalizeNocase = (s) => {
4264
+ const c = normalizeNocaseCache.get(s);
4265
+ if (c) return c;
4266
+ const n = normalize(s.toLowerCase());
4267
+ normalizeNocaseCache.set(s, n);
4268
+ return n;
4269
+ };
4270
+ /**
4271
+ * An LRUCache for storing resolved path strings or Path objects.
4272
+ * @internal
4273
+ */
4274
+ var ResolveCache = class extends LRUCache {
4275
+ constructor() {
4276
+ super({ max: 256 });
4277
+ }
4278
+ };
4279
+ /**
4280
+ * an LRUCache for storing child entries.
4281
+ * @internal
4282
+ */
4283
+ var ChildrenCache = class extends LRUCache {
4284
+ constructor(maxSize = 16 * 1024) {
4285
+ super({
4286
+ maxSize,
4287
+ sizeCalculation: (a) => a.length + 1
4288
+ });
4289
+ }
4290
+ };
4291
+ const setAsCwd = Symbol("PathScurry setAsCwd");
4292
+ /**
4293
+ * Path objects are sort of like a super-powered
4294
+ * {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent}
4295
+ *
4296
+ * Each one represents a single filesystem entry on disk, which may or may not
4297
+ * exist. It includes methods for reading various types of information via
4298
+ * lstat, readlink, and readdir, and caches all information to the greatest
4299
+ * degree possible.
4300
+ *
4301
+ * Note that fs operations that would normally throw will instead return an
4302
+ * "empty" value. This is in order to prevent excessive overhead from error
4303
+ * stack traces.
4304
+ */
4305
+ var PathBase = class {
4306
+ /**
4307
+ * the basename of this path
4308
+ *
4309
+ * **Important**: *always* test the path name against any test string
4310
+ * usingthe {@link isNamed} method, and not by directly comparing this
4311
+ * string. Otherwise, unicode path strings that the system sees as identical
4312
+ * will not be properly treated as the same path, leading to incorrect
4313
+ * behavior and possible security issues.
4314
+ */
4315
+ name;
4316
+ /**
4317
+ * the Path entry corresponding to the path root.
4318
+ *
4319
+ * @internal
4320
+ */
4321
+ root;
4322
+ /**
4323
+ * All roots found within the current PathScurry family
4324
+ *
4325
+ * @internal
4326
+ */
4327
+ roots;
4328
+ /**
4329
+ * a reference to the parent path, or undefined in the case of root entries
4330
+ *
4331
+ * @internal
4332
+ */
4333
+ parent;
4334
+ /**
4335
+ * boolean indicating whether paths are compared case-insensitively
4336
+ * @internal
4337
+ */
4338
+ nocase;
4339
+ /**
4340
+ * boolean indicating that this path is the current working directory
4341
+ * of the PathScurry collection that contains it.
4342
+ */
4343
+ isCWD = false;
4344
+ #fs;
4345
+ #dev;
4346
+ get dev() {
4347
+ return this.#dev;
4348
+ }
4349
+ #mode;
4350
+ get mode() {
4351
+ return this.#mode;
4352
+ }
4353
+ #nlink;
4354
+ get nlink() {
4355
+ return this.#nlink;
4356
+ }
4357
+ #uid;
4358
+ get uid() {
4359
+ return this.#uid;
4360
+ }
4361
+ #gid;
4362
+ get gid() {
4363
+ return this.#gid;
4364
+ }
4365
+ #rdev;
4366
+ get rdev() {
4367
+ return this.#rdev;
4368
+ }
4369
+ #blksize;
4370
+ get blksize() {
4371
+ return this.#blksize;
4372
+ }
4373
+ #ino;
4374
+ get ino() {
4375
+ return this.#ino;
4376
+ }
4377
+ #size;
4378
+ get size() {
4379
+ return this.#size;
4380
+ }
4381
+ #blocks;
4382
+ get blocks() {
4383
+ return this.#blocks;
4384
+ }
4385
+ #atimeMs;
4386
+ get atimeMs() {
4387
+ return this.#atimeMs;
4388
+ }
4389
+ #mtimeMs;
4390
+ get mtimeMs() {
4391
+ return this.#mtimeMs;
4392
+ }
4393
+ #ctimeMs;
4394
+ get ctimeMs() {
4395
+ return this.#ctimeMs;
4396
+ }
4397
+ #birthtimeMs;
4398
+ get birthtimeMs() {
4399
+ return this.#birthtimeMs;
4400
+ }
4401
+ #atime;
4402
+ get atime() {
4403
+ return this.#atime;
4404
+ }
4405
+ #mtime;
4406
+ get mtime() {
4407
+ return this.#mtime;
4408
+ }
4409
+ #ctime;
4410
+ get ctime() {
4411
+ return this.#ctime;
4412
+ }
4413
+ #birthtime;
4414
+ get birthtime() {
4415
+ return this.#birthtime;
4416
+ }
4417
+ #matchName;
4418
+ #depth;
4419
+ #fullpath;
4420
+ #fullpathPosix;
4421
+ #relative;
4422
+ #relativePosix;
4423
+ #type;
4424
+ #children;
4425
+ #linkTarget;
4426
+ #realpath;
4427
+ /**
4428
+ * This property is for compatibility with the Dirent class as of
4429
+ * Node v20, where Dirent['parentPath'] refers to the path of the
4430
+ * directory that was passed to readdir. For root entries, it's the path
4431
+ * to the entry itself.
4432
+ */
4433
+ get parentPath() {
4434
+ return (this.parent || this).fullpath();
4435
+ }
4436
+ /**
4437
+ * Deprecated alias for Dirent['parentPath'] Somewhat counterintuitively,
4438
+ * this property refers to the *parent* path, not the path object itself.
4439
+ */
4440
+ get path() {
4441
+ return this.parentPath;
4442
+ }
4443
+ /**
4444
+ * Do not create new Path objects directly. They should always be accessed
4445
+ * via the PathScurry class or other methods on the Path class.
4446
+ *
4447
+ * @internal
4448
+ */
4449
+ constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
4450
+ this.name = name;
4451
+ this.#matchName = nocase ? normalizeNocase(name) : normalize(name);
4452
+ this.#type = type & TYPEMASK;
4453
+ this.nocase = nocase;
4454
+ this.roots = roots;
4455
+ this.root = root || this;
4456
+ this.#children = children;
4457
+ this.#fullpath = opts.fullpath;
4458
+ this.#relative = opts.relative;
4459
+ this.#relativePosix = opts.relativePosix;
4460
+ this.parent = opts.parent;
4461
+ if (this.parent) this.#fs = this.parent.#fs;
4462
+ else this.#fs = fsFromOption(opts.fs);
4463
+ }
4464
+ /**
4465
+ * Returns the depth of the Path object from its root.
4466
+ *
4467
+ * For example, a path at `/foo/bar` would have a depth of 2.
4468
+ */
4469
+ depth() {
4470
+ if (this.#depth !== void 0) return this.#depth;
4471
+ if (!this.parent) return this.#depth = 0;
4472
+ return this.#depth = this.parent.depth() + 1;
4473
+ }
4474
+ /**
4475
+ * @internal
4476
+ */
4477
+ childrenCache() {
4478
+ return this.#children;
4479
+ }
4480
+ /**
4481
+ * Get the Path object referenced by the string path, resolved from this Path
4482
+ */
4483
+ resolve(path$4) {
4484
+ if (!path$4) return this;
4485
+ const rootPath = this.getRootString(path$4);
4486
+ const dir = path$4.substring(rootPath.length);
4487
+ const dirParts = dir.split(this.splitSep);
4488
+ const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
4489
+ return result;
4490
+ }
4491
+ #resolveParts(dirParts) {
4492
+ let p = this;
4493
+ for (const part of dirParts) p = p.child(part);
4494
+ return p;
4495
+ }
4496
+ /**
4497
+ * Returns the cached children Path objects, if still available. If they
4498
+ * have fallen out of the cache, then returns an empty array, and resets the
4499
+ * READDIR_CALLED bit, so that future calls to readdir() will require an fs
4500
+ * lookup.
4501
+ *
4502
+ * @internal
4503
+ */
4504
+ children() {
4505
+ const cached = this.#children.get(this);
4506
+ if (cached) return cached;
4507
+ const children = Object.assign([], { provisional: 0 });
4508
+ this.#children.set(this, children);
4509
+ this.#type &= ~READDIR_CALLED;
4510
+ return children;
4511
+ }
4512
+ /**
4513
+ * Resolves a path portion and returns or creates the child Path.
4514
+ *
4515
+ * Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is
4516
+ * `'..'`.
4517
+ *
4518
+ * This should not be called directly. If `pathPart` contains any path
4519
+ * separators, it will lead to unsafe undefined behavior.
4520
+ *
4521
+ * Use `Path.resolve()` instead.
4522
+ *
4523
+ * @internal
4524
+ */
4525
+ child(pathPart, opts) {
4526
+ if (pathPart === "" || pathPart === ".") return this;
4527
+ if (pathPart === "..") return this.parent || this;
4528
+ const children = this.children();
4529
+ const name = this.nocase ? normalizeNocase(pathPart) : normalize(pathPart);
4530
+ for (const p of children) if (p.#matchName === name) return p;
4531
+ const s = this.parent ? this.sep : "";
4532
+ const fullpath = this.#fullpath ? this.#fullpath + s + pathPart : void 0;
4533
+ const pchild = this.newChild(pathPart, UNKNOWN, {
4534
+ ...opts,
4535
+ parent: this,
4536
+ fullpath
4537
+ });
4538
+ if (!this.canReaddir()) pchild.#type |= ENOENT;
4539
+ children.push(pchild);
4540
+ return pchild;
4541
+ }
4542
+ /**
4543
+ * The relative path from the cwd. If it does not share an ancestor with
4544
+ * the cwd, then this ends up being equivalent to the fullpath()
4545
+ */
4546
+ relative() {
4547
+ if (this.isCWD) return "";
4548
+ if (this.#relative !== void 0) return this.#relative;
4549
+ const name = this.name;
4550
+ const p = this.parent;
4551
+ if (!p) return this.#relative = this.name;
4552
+ const pv = p.relative();
4553
+ return pv + (!pv || !p.parent ? "" : this.sep) + name;
4554
+ }
4555
+ /**
4556
+ * The relative path from the cwd, using / as the path separator.
4557
+ * If it does not share an ancestor with
4558
+ * the cwd, then this ends up being equivalent to the fullpathPosix()
4559
+ * On posix systems, this is identical to relative().
4560
+ */
4561
+ relativePosix() {
4562
+ if (this.sep === "/") return this.relative();
4563
+ if (this.isCWD) return "";
4564
+ if (this.#relativePosix !== void 0) return this.#relativePosix;
4565
+ const name = this.name;
4566
+ const p = this.parent;
4567
+ if (!p) return this.#relativePosix = this.fullpathPosix();
4568
+ const pv = p.relativePosix();
4569
+ return pv + (!pv || !p.parent ? "" : "/") + name;
4570
+ }
4571
+ /**
4572
+ * The fully resolved path string for this Path entry
4573
+ */
4574
+ fullpath() {
4575
+ if (this.#fullpath !== void 0) return this.#fullpath;
4576
+ const name = this.name;
4577
+ const p = this.parent;
4578
+ if (!p) return this.#fullpath = this.name;
4579
+ const pv = p.fullpath();
4580
+ const fp = pv + (!p.parent ? "" : this.sep) + name;
4581
+ return this.#fullpath = fp;
4582
+ }
4583
+ /**
4584
+ * On platforms other than windows, this is identical to fullpath.
4585
+ *
4586
+ * On windows, this is overridden to return the forward-slash form of the
4587
+ * full UNC path.
4588
+ */
4589
+ fullpathPosix() {
4590
+ if (this.#fullpathPosix !== void 0) return this.#fullpathPosix;
4591
+ if (this.sep === "/") return this.#fullpathPosix = this.fullpath();
4592
+ if (!this.parent) {
4593
+ const p$1 = this.fullpath().replace(/\\/g, "/");
4594
+ if (/^[a-z]:\//i.test(p$1)) return this.#fullpathPosix = `//?/${p$1}`;
4595
+ else return this.#fullpathPosix = p$1;
4596
+ }
4597
+ const p = this.parent;
4598
+ const pfpp = p.fullpathPosix();
4599
+ const fpp = pfpp + (!pfpp || !p.parent ? "" : "/") + this.name;
4600
+ return this.#fullpathPosix = fpp;
4601
+ }
4602
+ /**
4603
+ * Is the Path of an unknown type?
4604
+ *
4605
+ * Note that we might know *something* about it if there has been a previous
4606
+ * filesystem operation, for example that it does not exist, or is not a
4607
+ * link, or whether it has child entries.
4608
+ */
4609
+ isUnknown() {
4610
+ return (this.#type & IFMT) === UNKNOWN;
4611
+ }
4612
+ isType(type) {
4613
+ return this[`is${type}`]();
4614
+ }
4615
+ getType() {
4616
+ return this.isUnknown() ? "Unknown" : this.isDirectory() ? "Directory" : this.isFile() ? "File" : this.isSymbolicLink() ? "SymbolicLink" : this.isFIFO() ? "FIFO" : this.isCharacterDevice() ? "CharacterDevice" : this.isBlockDevice() ? "BlockDevice" : this.isSocket() ? "Socket" : "Unknown";
4617
+ /* c8 ignore stop */
4618
+ }
4619
+ /**
4620
+ * Is the Path a regular file?
4621
+ */
4622
+ isFile() {
4623
+ return (this.#type & IFMT) === IFREG;
4624
+ }
4625
+ /**
4626
+ * Is the Path a directory?
4627
+ */
4628
+ isDirectory() {
4629
+ return (this.#type & IFMT) === IFDIR;
4630
+ }
4631
+ /**
4632
+ * Is the path a character device?
4633
+ */
4634
+ isCharacterDevice() {
4635
+ return (this.#type & IFMT) === IFCHR;
4636
+ }
4637
+ /**
4638
+ * Is the path a block device?
4639
+ */
4640
+ isBlockDevice() {
4641
+ return (this.#type & IFMT) === IFBLK;
4642
+ }
4643
+ /**
4644
+ * Is the path a FIFO pipe?
4645
+ */
4646
+ isFIFO() {
4647
+ return (this.#type & IFMT) === IFIFO;
4648
+ }
4649
+ /**
4650
+ * Is the path a socket?
4651
+ */
4652
+ isSocket() {
4653
+ return (this.#type & IFMT) === IFSOCK;
4654
+ }
4655
+ /**
4656
+ * Is the path a symbolic link?
4657
+ */
4658
+ isSymbolicLink() {
4659
+ return (this.#type & IFLNK) === IFLNK;
4660
+ }
4661
+ /**
4662
+ * Return the entry if it has been subject of a successful lstat, or
4663
+ * undefined otherwise.
4664
+ *
4665
+ * Does not read the filesystem, so an undefined result *could* simply
4666
+ * mean that we haven't called lstat on it.
4667
+ */
4668
+ lstatCached() {
4669
+ return this.#type & LSTAT_CALLED ? this : void 0;
4670
+ }
4671
+ /**
4672
+ * Return the cached link target if the entry has been the subject of a
4673
+ * successful readlink, or undefined otherwise.
4674
+ *
4675
+ * Does not read the filesystem, so an undefined result *could* just mean we
4676
+ * don't have any cached data. Only use it if you are very sure that a
4677
+ * readlink() has been called at some point.
4678
+ */
4679
+ readlinkCached() {
4680
+ return this.#linkTarget;
4681
+ }
4682
+ /**
4683
+ * Returns the cached realpath target if the entry has been the subject
4684
+ * of a successful realpath, or undefined otherwise.
4685
+ *
4686
+ * Does not read the filesystem, so an undefined result *could* just mean we
4687
+ * don't have any cached data. Only use it if you are very sure that a
4688
+ * realpath() has been called at some point.
4689
+ */
4690
+ realpathCached() {
4691
+ return this.#realpath;
4692
+ }
4693
+ /**
4694
+ * Returns the cached child Path entries array if the entry has been the
4695
+ * subject of a successful readdir(), or [] otherwise.
4696
+ *
4697
+ * Does not read the filesystem, so an empty array *could* just mean we
4698
+ * don't have any cached data. Only use it if you are very sure that a
4699
+ * readdir() has been called recently enough to still be valid.
4700
+ */
4701
+ readdirCached() {
4702
+ const children = this.children();
4703
+ return children.slice(0, children.provisional);
4704
+ }
4705
+ /**
4706
+ * Return true if it's worth trying to readlink. Ie, we don't (yet) have
4707
+ * any indication that readlink will definitely fail.
4708
+ *
4709
+ * Returns false if the path is known to not be a symlink, if a previous
4710
+ * readlink failed, or if the entry does not exist.
4711
+ */
4712
+ canReadlink() {
4713
+ if (this.#linkTarget) return true;
4714
+ if (!this.parent) return false;
4715
+ const ifmt = this.#type & IFMT;
4716
+ return !(ifmt !== UNKNOWN && ifmt !== IFLNK || this.#type & ENOREADLINK || this.#type & ENOENT);
4717
+ }
4718
+ /**
4719
+ * Return true if readdir has previously been successfully called on this
4720
+ * path, indicating that cachedReaddir() is likely valid.
4721
+ */
4722
+ calledReaddir() {
4723
+ return !!(this.#type & READDIR_CALLED);
4724
+ }
4725
+ /**
4726
+ * Returns true if the path is known to not exist. That is, a previous lstat
4727
+ * or readdir failed to verify its existence when that would have been
4728
+ * expected, or a parent entry was marked either enoent or enotdir.
4729
+ */
4730
+ isENOENT() {
4731
+ return !!(this.#type & ENOENT);
4732
+ }
4733
+ /**
4734
+ * Return true if the path is a match for the given path name. This handles
4735
+ * case sensitivity and unicode normalization.
4736
+ *
4737
+ * Note: even on case-sensitive systems, it is **not** safe to test the
4738
+ * equality of the `.name` property to determine whether a given pathname
4739
+ * matches, due to unicode normalization mismatches.
4740
+ *
4741
+ * Always use this method instead of testing the `path.name` property
4742
+ * directly.
4743
+ */
4744
+ isNamed(n) {
4745
+ return !this.nocase ? this.#matchName === normalize(n) : this.#matchName === normalizeNocase(n);
4746
+ }
4747
+ /**
4748
+ * Return the Path object corresponding to the target of a symbolic link.
4749
+ *
4750
+ * If the Path is not a symbolic link, or if the readlink call fails for any
4751
+ * reason, `undefined` is returned.
4752
+ *
4753
+ * Result is cached, and thus may be outdated if the filesystem is mutated.
4754
+ */
4755
+ async readlink() {
4756
+ const target = this.#linkTarget;
4757
+ if (target) return target;
4758
+ if (!this.canReadlink()) return void 0;
4759
+ /* c8 ignore start */
4760
+ if (!this.parent) return void 0;
4761
+ /* c8 ignore stop */
4762
+ try {
4763
+ const read = await this.#fs.promises.readlink(this.fullpath());
4764
+ const linkTarget = (await this.parent.realpath())?.resolve(read);
4765
+ if (linkTarget) return this.#linkTarget = linkTarget;
4766
+ } catch (er) {
4767
+ this.#readlinkFail(er.code);
4768
+ return void 0;
4769
+ }
4770
+ }
4771
+ /**
4772
+ * Synchronous {@link PathBase.readlink}
4773
+ */
4774
+ readlinkSync() {
4775
+ const target = this.#linkTarget;
4776
+ if (target) return target;
4777
+ if (!this.canReadlink()) return void 0;
4778
+ /* c8 ignore start */
4779
+ if (!this.parent) return void 0;
4780
+ /* c8 ignore stop */
4781
+ try {
4782
+ const read = this.#fs.readlinkSync(this.fullpath());
4783
+ const linkTarget = this.parent.realpathSync()?.resolve(read);
4784
+ if (linkTarget) return this.#linkTarget = linkTarget;
4785
+ } catch (er) {
4786
+ this.#readlinkFail(er.code);
4787
+ return void 0;
4788
+ }
4789
+ }
4790
+ #readdirSuccess(children) {
4791
+ this.#type |= READDIR_CALLED;
4792
+ for (let p = children.provisional; p < children.length; p++) {
4793
+ const c = children[p];
4794
+ if (c) c.#markENOENT();
4795
+ }
4796
+ }
4797
+ #markENOENT() {
4798
+ if (this.#type & ENOENT) return;
4799
+ this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN;
4800
+ this.#markChildrenENOENT();
4801
+ }
4802
+ #markChildrenENOENT() {
4803
+ const children = this.children();
4804
+ children.provisional = 0;
4805
+ for (const p of children) p.#markENOENT();
4806
+ }
4807
+ #markENOREALPATH() {
4808
+ this.#type |= ENOREALPATH;
4809
+ this.#markENOTDIR();
4810
+ }
4811
+ #markENOTDIR() {
4812
+ /* c8 ignore start */
4813
+ if (this.#type & ENOTDIR) return;
4814
+ /* c8 ignore stop */
4815
+ let t = this.#type;
4816
+ if ((t & IFMT) === IFDIR) t &= IFMT_UNKNOWN;
4817
+ this.#type = t | ENOTDIR;
4818
+ this.#markChildrenENOENT();
4819
+ }
4820
+ #readdirFail(code = "") {
4821
+ if (code === "ENOTDIR" || code === "EPERM") this.#markENOTDIR();
4822
+ else if (code === "ENOENT") this.#markENOENT();
4823
+ else this.children().provisional = 0;
4824
+ }
4825
+ #lstatFail(code = "") {
4826
+ /* c8 ignore start */
4827
+ if (code === "ENOTDIR") {
4828
+ const p = this.parent;
4829
+ p.#markENOTDIR();
4830
+ } else if (code === "ENOENT")
4831
+ /* c8 ignore stop */
4832
+ this.#markENOENT();
4833
+ }
4834
+ #readlinkFail(code = "") {
4835
+ let ter = this.#type;
4836
+ ter |= ENOREADLINK;
4837
+ if (code === "ENOENT") ter |= ENOENT;
4838
+ if (code === "EINVAL" || code === "UNKNOWN") ter &= IFMT_UNKNOWN;
4839
+ this.#type = ter;
4840
+ /* c8 ignore start */
4841
+ if (code === "ENOTDIR" && this.parent) this.parent.#markENOTDIR();
4842
+ /* c8 ignore stop */
4843
+ }
4844
+ #readdirAddChild(e, c) {
4845
+ return this.#readdirMaybePromoteChild(e, c) || this.#readdirAddNewChild(e, c);
4846
+ }
4847
+ #readdirAddNewChild(e, c) {
4848
+ const type = entToType(e);
4849
+ const child = this.newChild(e.name, type, { parent: this });
4850
+ const ifmt = child.#type & IFMT;
4851
+ if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) child.#type |= ENOTDIR;
4852
+ c.unshift(child);
4853
+ c.provisional++;
4854
+ return child;
4855
+ }
4856
+ #readdirMaybePromoteChild(e, c) {
4857
+ for (let p = c.provisional; p < c.length; p++) {
4858
+ const pchild = c[p];
4859
+ const name = this.nocase ? normalizeNocase(e.name) : normalize(e.name);
4860
+ if (name !== pchild.#matchName) continue;
4861
+ return this.#readdirPromoteChild(e, pchild, p, c);
4862
+ }
4863
+ }
4864
+ #readdirPromoteChild(e, p, index, c) {
4865
+ const v = p.name;
4866
+ p.#type = p.#type & IFMT_UNKNOWN | entToType(e);
4867
+ if (v !== e.name) p.name = e.name;
4868
+ if (index !== c.provisional) {
4869
+ if (index === c.length - 1) c.pop();
4870
+ else c.splice(index, 1);
4871
+ c.unshift(p);
4872
+ }
4873
+ c.provisional++;
4874
+ return p;
4875
+ }
4876
+ /**
4877
+ * Call lstat() on this Path, and update all known information that can be
4878
+ * determined.
4879
+ *
4880
+ * Note that unlike `fs.lstat()`, the returned value does not contain some
4881
+ * information, such as `mode`, `dev`, `nlink`, and `ino`. If that
4882
+ * information is required, you will need to call `fs.lstat` yourself.
4883
+ *
4884
+ * If the Path refers to a nonexistent file, or if the lstat call fails for
4885
+ * any reason, `undefined` is returned. Otherwise the updated Path object is
4886
+ * returned.
4887
+ *
4888
+ * Results are cached, and thus may be out of date if the filesystem is
4889
+ * mutated.
4890
+ */
4891
+ async lstat() {
4892
+ if ((this.#type & ENOENT) === 0) try {
4893
+ this.#applyStat(await this.#fs.promises.lstat(this.fullpath()));
4894
+ return this;
4895
+ } catch (er) {
4896
+ this.#lstatFail(er.code);
4897
+ }
4898
+ }
4899
+ /**
4900
+ * synchronous {@link PathBase.lstat}
4901
+ */
4902
+ lstatSync() {
4903
+ if ((this.#type & ENOENT) === 0) try {
4904
+ this.#applyStat(this.#fs.lstatSync(this.fullpath()));
4905
+ return this;
4906
+ } catch (er) {
4907
+ this.#lstatFail(er.code);
4908
+ }
4909
+ }
4910
+ #applyStat(st) {
4911
+ const { atime, atimeMs, birthtime, birthtimeMs, blksize, blocks, ctime, ctimeMs, dev, gid, ino, mode, mtime, mtimeMs, nlink, rdev, size, uid } = st;
4912
+ this.#atime = atime;
4913
+ this.#atimeMs = atimeMs;
4914
+ this.#birthtime = birthtime;
4915
+ this.#birthtimeMs = birthtimeMs;
4916
+ this.#blksize = blksize;
4917
+ this.#blocks = blocks;
4918
+ this.#ctime = ctime;
4919
+ this.#ctimeMs = ctimeMs;
4920
+ this.#dev = dev;
4921
+ this.#gid = gid;
4922
+ this.#ino = ino;
4923
+ this.#mode = mode;
4924
+ this.#mtime = mtime;
4925
+ this.#mtimeMs = mtimeMs;
4926
+ this.#nlink = nlink;
4927
+ this.#rdev = rdev;
4928
+ this.#size = size;
4929
+ this.#uid = uid;
4930
+ const ifmt = entToType(st);
4931
+ this.#type = this.#type & IFMT_UNKNOWN | ifmt | LSTAT_CALLED;
4932
+ if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) this.#type |= ENOTDIR;
4933
+ }
4934
+ #onReaddirCB = [];
4935
+ #readdirCBInFlight = false;
4936
+ #callOnReaddirCB(children) {
4937
+ this.#readdirCBInFlight = false;
4938
+ const cbs = this.#onReaddirCB.slice();
4939
+ this.#onReaddirCB.length = 0;
4940
+ cbs.forEach((cb) => cb(null, children));
4941
+ }
4942
+ /**
4943
+ * Standard node-style callback interface to get list of directory entries.
4944
+ *
4945
+ * If the Path cannot or does not contain any children, then an empty array
4946
+ * is returned.
4947
+ *
4948
+ * Results are cached, and thus may be out of date if the filesystem is
4949
+ * mutated.
4950
+ *
4951
+ * @param cb The callback called with (er, entries). Note that the `er`
4952
+ * param is somewhat extraneous, as all readdir() errors are handled and
4953
+ * simply result in an empty set of entries being returned.
4954
+ * @param allowZalgo Boolean indicating that immediately known results should
4955
+ * *not* be deferred with `queueMicrotask`. Defaults to `false`. Release
4956
+ * zalgo at your peril, the dark pony lord is devious and unforgiving.
4957
+ */
4958
+ readdirCB(cb, allowZalgo = false) {
4959
+ if (!this.canReaddir()) {
4960
+ if (allowZalgo) cb(null, []);
4961
+ else queueMicrotask(() => cb(null, []));
4962
+ return;
4963
+ }
4964
+ const children = this.children();
4965
+ if (this.calledReaddir()) {
4966
+ const c = children.slice(0, children.provisional);
4967
+ if (allowZalgo) cb(null, c);
4968
+ else queueMicrotask(() => cb(null, c));
4969
+ return;
4970
+ }
4971
+ this.#onReaddirCB.push(cb);
4972
+ if (this.#readdirCBInFlight) return;
4973
+ this.#readdirCBInFlight = true;
4974
+ const fullpath = this.fullpath();
4975
+ this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {
4976
+ if (er) {
4977
+ this.#readdirFail(er.code);
4978
+ children.provisional = 0;
4979
+ } else {
4980
+ for (const e of entries) this.#readdirAddChild(e, children);
4981
+ this.#readdirSuccess(children);
4982
+ }
4983
+ this.#callOnReaddirCB(children.slice(0, children.provisional));
4984
+ return;
4985
+ });
4986
+ }
4987
+ #asyncReaddirInFlight;
4988
+ /**
4989
+ * Return an array of known child entries.
4990
+ *
4991
+ * If the Path cannot or does not contain any children, then an empty array
4992
+ * is returned.
4993
+ *
4994
+ * Results are cached, and thus may be out of date if the filesystem is
4995
+ * mutated.
4996
+ */
4997
+ async readdir() {
4998
+ if (!this.canReaddir()) return [];
4999
+ const children = this.children();
5000
+ if (this.calledReaddir()) return children.slice(0, children.provisional);
5001
+ const fullpath = this.fullpath();
5002
+ if (this.#asyncReaddirInFlight) await this.#asyncReaddirInFlight;
5003
+ else {
5004
+ /* c8 ignore start */
5005
+ let resolve$2 = () => {};
5006
+ /* c8 ignore stop */
5007
+ this.#asyncReaddirInFlight = new Promise((res) => resolve$2 = res);
5008
+ try {
5009
+ for (const e of await this.#fs.promises.readdir(fullpath, { withFileTypes: true })) this.#readdirAddChild(e, children);
5010
+ this.#readdirSuccess(children);
5011
+ } catch (er) {
5012
+ this.#readdirFail(er.code);
5013
+ children.provisional = 0;
5014
+ }
5015
+ this.#asyncReaddirInFlight = void 0;
5016
+ resolve$2();
5017
+ }
5018
+ return children.slice(0, children.provisional);
5019
+ }
5020
+ /**
5021
+ * synchronous {@link PathBase.readdir}
5022
+ */
5023
+ readdirSync() {
5024
+ if (!this.canReaddir()) return [];
5025
+ const children = this.children();
5026
+ if (this.calledReaddir()) return children.slice(0, children.provisional);
5027
+ const fullpath = this.fullpath();
5028
+ try {
5029
+ for (const e of this.#fs.readdirSync(fullpath, { withFileTypes: true })) this.#readdirAddChild(e, children);
5030
+ this.#readdirSuccess(children);
5031
+ } catch (er) {
5032
+ this.#readdirFail(er.code);
5033
+ children.provisional = 0;
5034
+ }
5035
+ return children.slice(0, children.provisional);
5036
+ }
5037
+ canReaddir() {
5038
+ if (this.#type & ENOCHILD) return false;
5039
+ const ifmt = IFMT & this.#type;
5040
+ /* c8 ignore start */
5041
+ if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) return false;
5042
+ /* c8 ignore stop */
5043
+ return true;
5044
+ }
5045
+ shouldWalk(dirs, walkFilter) {
5046
+ return (this.#type & IFDIR) === IFDIR && !(this.#type & ENOCHILD) && !dirs.has(this) && (!walkFilter || walkFilter(this));
5047
+ }
5048
+ /**
5049
+ * Return the Path object corresponding to path as resolved
5050
+ * by realpath(3).
5051
+ *
5052
+ * If the realpath call fails for any reason, `undefined` is returned.
5053
+ *
5054
+ * Result is cached, and thus may be outdated if the filesystem is mutated.
5055
+ * On success, returns a Path object.
5056
+ */
5057
+ async realpath() {
5058
+ if (this.#realpath) return this.#realpath;
5059
+ if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type) return void 0;
5060
+ try {
5061
+ const rp = await this.#fs.promises.realpath(this.fullpath());
5062
+ return this.#realpath = this.resolve(rp);
5063
+ } catch (_) {
5064
+ this.#markENOREALPATH();
5065
+ }
5066
+ }
5067
+ /**
5068
+ * Synchronous {@link realpath}
5069
+ */
5070
+ realpathSync() {
5071
+ if (this.#realpath) return this.#realpath;
5072
+ if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type) return void 0;
5073
+ try {
5074
+ const rp = this.#fs.realpathSync(this.fullpath());
5075
+ return this.#realpath = this.resolve(rp);
5076
+ } catch (_) {
5077
+ this.#markENOREALPATH();
5078
+ }
5079
+ }
5080
+ /**
5081
+ * Internal method to mark this Path object as the scurry cwd,
5082
+ * called by {@link PathScurry#chdir}
5083
+ *
5084
+ * @internal
5085
+ */
5086
+ [setAsCwd](oldCwd) {
5087
+ if (oldCwd === this) return;
5088
+ oldCwd.isCWD = false;
5089
+ this.isCWD = true;
5090
+ const changed = new Set([]);
5091
+ let rp = [];
5092
+ let p = this;
5093
+ while (p && p.parent) {
5094
+ changed.add(p);
5095
+ p.#relative = rp.join(this.sep);
5096
+ p.#relativePosix = rp.join("/");
5097
+ p = p.parent;
5098
+ rp.push("..");
5099
+ }
5100
+ p = oldCwd;
5101
+ while (p && p.parent && !changed.has(p)) {
5102
+ p.#relative = void 0;
5103
+ p.#relativePosix = void 0;
5104
+ p = p.parent;
5105
+ }
5106
+ }
5107
+ };
5108
+ /**
5109
+ * Path class used on win32 systems
5110
+ *
5111
+ * Uses `'\\'` as the path separator for returned paths, either `'\\'` or `'/'`
5112
+ * as the path separator for parsing paths.
5113
+ */
5114
+ var PathWin32 = class PathWin32 extends PathBase {
5115
+ /**
5116
+ * Separator for generating path strings.
5117
+ */
5118
+ sep = "\\";
5119
+ /**
5120
+ * Separator for parsing path strings.
5121
+ */
5122
+ splitSep = eitherSep;
5123
+ /**
5124
+ * Do not create new Path objects directly. They should always be accessed
5125
+ * via the PathScurry class or other methods on the Path class.
5126
+ *
5127
+ * @internal
5128
+ */
5129
+ constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
5130
+ super(name, type, root, roots, nocase, children, opts);
5131
+ }
5132
+ /**
5133
+ * @internal
5134
+ */
5135
+ newChild(name, type = UNKNOWN, opts = {}) {
5136
+ return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
5137
+ }
5138
+ /**
5139
+ * @internal
5140
+ */
5141
+ getRootString(path$4) {
5142
+ return win32.parse(path$4).root;
5143
+ }
5144
+ /**
5145
+ * @internal
5146
+ */
5147
+ getRoot(rootPath) {
5148
+ rootPath = uncToDrive(rootPath.toUpperCase());
5149
+ if (rootPath === this.root.name) return this.root;
5150
+ for (const [compare, root] of Object.entries(this.roots)) if (this.sameRoot(rootPath, compare)) return this.roots[rootPath] = root;
5151
+ return this.roots[rootPath] = new PathScurryWin32(rootPath, this).root;
5152
+ }
5153
+ /**
5154
+ * @internal
5155
+ */
5156
+ sameRoot(rootPath, compare = this.root.name) {
5157
+ rootPath = rootPath.toUpperCase().replace(/\//g, "\\").replace(uncDriveRegexp, "$1\\");
5158
+ return rootPath === compare;
5159
+ }
5160
+ };
5161
+ /**
5162
+ * Path class used on all posix systems.
5163
+ *
5164
+ * Uses `'/'` as the path separator.
5165
+ */
5166
+ var PathPosix = class PathPosix extends PathBase {
5167
+ /**
5168
+ * separator for parsing path strings
5169
+ */
5170
+ splitSep = "/";
5171
+ /**
5172
+ * separator for generating path strings
5173
+ */
5174
+ sep = "/";
5175
+ /**
5176
+ * Do not create new Path objects directly. They should always be accessed
5177
+ * via the PathScurry class or other methods on the Path class.
5178
+ *
5179
+ * @internal
5180
+ */
5181
+ constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
5182
+ super(name, type, root, roots, nocase, children, opts);
5183
+ }
5184
+ /**
5185
+ * @internal
5186
+ */
5187
+ getRootString(path$4) {
5188
+ return path$4.startsWith("/") ? "/" : "";
5189
+ }
5190
+ /**
5191
+ * @internal
5192
+ */
5193
+ getRoot(_rootPath) {
5194
+ return this.root;
5195
+ }
5196
+ /**
5197
+ * @internal
5198
+ */
5199
+ newChild(name, type = UNKNOWN, opts = {}) {
5200
+ return new PathPosix(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
5201
+ }
5202
+ };
5203
+ /**
5204
+ * The base class for all PathScurry classes, providing the interface for path
5205
+ * resolution and filesystem operations.
5206
+ *
5207
+ * Typically, you should *not* instantiate this class directly, but rather one
5208
+ * of the platform-specific classes, or the exported {@link PathScurry} which
5209
+ * defaults to the current platform.
5210
+ */
5211
+ var PathScurryBase = class {
5212
+ /**
5213
+ * The root Path entry for the current working directory of this Scurry
5214
+ */
5215
+ root;
5216
+ /**
5217
+ * The string path for the root of this Scurry's current working directory
5218
+ */
5219
+ rootPath;
5220
+ /**
5221
+ * A collection of all roots encountered, referenced by rootPath
5222
+ */
5223
+ roots;
5224
+ /**
5225
+ * The Path entry corresponding to this PathScurry's current working directory.
5226
+ */
5227
+ cwd;
5228
+ #resolveCache;
5229
+ #resolvePosixCache;
5230
+ #children;
5231
+ /**
5232
+ * Perform path comparisons case-insensitively.
5233
+ *
5234
+ * Defaults true on Darwin and Windows systems, false elsewhere.
5235
+ */
5236
+ nocase;
5237
+ #fs;
5238
+ /**
5239
+ * This class should not be instantiated directly.
5240
+ *
5241
+ * Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry
5242
+ *
5243
+ * @internal
5244
+ */
5245
+ constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs: fs$1 = defaultFS } = {}) {
5246
+ this.#fs = fsFromOption(fs$1);
5247
+ if (cwd instanceof URL || cwd.startsWith("file://")) cwd = fileURLToPath$1(cwd);
5248
+ const cwdPath = pathImpl.resolve(cwd);
5249
+ this.roots = Object.create(null);
5250
+ this.rootPath = this.parseRootPath(cwdPath);
5251
+ this.#resolveCache = new ResolveCache();
5252
+ this.#resolvePosixCache = new ResolveCache();
5253
+ this.#children = new ChildrenCache(childrenCacheSize);
5254
+ const split = cwdPath.substring(this.rootPath.length).split(sep);
5255
+ if (split.length === 1 && !split[0]) split.pop();
5256
+ /* c8 ignore start */
5257
+ if (nocase === void 0) throw new TypeError("must provide nocase setting to PathScurryBase ctor");
5258
+ /* c8 ignore stop */
5259
+ this.nocase = nocase;
5260
+ this.root = this.newRoot(this.#fs);
5261
+ this.roots[this.rootPath] = this.root;
5262
+ let prev = this.root;
5263
+ let len = split.length - 1;
5264
+ const joinSep = pathImpl.sep;
5265
+ let abs = this.rootPath;
5266
+ let sawFirst = false;
5267
+ for (const part of split) {
5268
+ const l = len--;
5269
+ prev = prev.child(part, {
5270
+ relative: new Array(l).fill("..").join(joinSep),
5271
+ relativePosix: new Array(l).fill("..").join("/"),
5272
+ fullpath: abs += (sawFirst ? "" : joinSep) + part
5273
+ });
5274
+ sawFirst = true;
5275
+ }
5276
+ this.cwd = prev;
5277
+ }
5278
+ /**
5279
+ * Get the depth of a provided path, string, or the cwd
5280
+ */
5281
+ depth(path$4 = this.cwd) {
5282
+ if (typeof path$4 === "string") path$4 = this.cwd.resolve(path$4);
5283
+ return path$4.depth();
5284
+ }
5285
+ /**
5286
+ * Return the cache of child entries. Exposed so subclasses can create
5287
+ * child Path objects in a platform-specific way.
5288
+ *
5289
+ * @internal
5290
+ */
5291
+ childrenCache() {
5292
+ return this.#children;
5293
+ }
5294
+ /**
5295
+ * Resolve one or more path strings to a resolved string
5296
+ *
5297
+ * Same interface as require('path').resolve.
5298
+ *
5299
+ * Much faster than path.resolve() when called multiple times for the same
5300
+ * path, because the resolved Path objects are cached. Much slower
5301
+ * otherwise.
5302
+ */
5303
+ resolve(...paths) {
5304
+ let r = "";
5305
+ for (let i = paths.length - 1; i >= 0; i--) {
5306
+ const p = paths[i];
5307
+ if (!p || p === ".") continue;
5308
+ r = r ? `${p}/${r}` : p;
5309
+ if (this.isAbsolute(p)) break;
5310
+ }
5311
+ const cached = this.#resolveCache.get(r);
5312
+ if (cached !== void 0) return cached;
5313
+ const result = this.cwd.resolve(r).fullpath();
5314
+ this.#resolveCache.set(r, result);
5315
+ return result;
5316
+ }
5317
+ /**
5318
+ * Resolve one or more path strings to a resolved string, returning
5319
+ * the posix path. Identical to .resolve() on posix systems, but on
5320
+ * windows will return a forward-slash separated UNC path.
5321
+ *
5322
+ * Same interface as require('path').resolve.
5323
+ *
5324
+ * Much faster than path.resolve() when called multiple times for the same
5325
+ * path, because the resolved Path objects are cached. Much slower
5326
+ * otherwise.
5327
+ */
5328
+ resolvePosix(...paths) {
5329
+ let r = "";
5330
+ for (let i = paths.length - 1; i >= 0; i--) {
5331
+ const p = paths[i];
5332
+ if (!p || p === ".") continue;
5333
+ r = r ? `${p}/${r}` : p;
5334
+ if (this.isAbsolute(p)) break;
5335
+ }
5336
+ const cached = this.#resolvePosixCache.get(r);
5337
+ if (cached !== void 0) return cached;
5338
+ const result = this.cwd.resolve(r).fullpathPosix();
5339
+ this.#resolvePosixCache.set(r, result);
5340
+ return result;
5341
+ }
5342
+ /**
5343
+ * find the relative path from the cwd to the supplied path string or entry
5344
+ */
5345
+ relative(entry = this.cwd) {
5346
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5347
+ return entry.relative();
5348
+ }
5349
+ /**
5350
+ * find the relative path from the cwd to the supplied path string or
5351
+ * entry, using / as the path delimiter, even on Windows.
5352
+ */
5353
+ relativePosix(entry = this.cwd) {
5354
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5355
+ return entry.relativePosix();
5356
+ }
5357
+ /**
5358
+ * Return the basename for the provided string or Path object
5359
+ */
5360
+ basename(entry = this.cwd) {
5361
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5362
+ return entry.name;
5363
+ }
5364
+ /**
5365
+ * Return the dirname for the provided string or Path object
5366
+ */
5367
+ dirname(entry = this.cwd) {
5368
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5369
+ return (entry.parent || entry).fullpath();
5370
+ }
5371
+ async readdir(entry = this.cwd, opts = { withFileTypes: true }) {
5372
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5373
+ else if (!(entry instanceof PathBase)) {
5374
+ opts = entry;
5375
+ entry = this.cwd;
5376
+ }
5377
+ const { withFileTypes } = opts;
5378
+ if (!entry.canReaddir()) return [];
5379
+ else {
5380
+ const p = await entry.readdir();
5381
+ return withFileTypes ? p : p.map((e) => e.name);
5382
+ }
5383
+ }
5384
+ readdirSync(entry = this.cwd, opts = { withFileTypes: true }) {
5385
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5386
+ else if (!(entry instanceof PathBase)) {
5387
+ opts = entry;
5388
+ entry = this.cwd;
5389
+ }
5390
+ const { withFileTypes = true } = opts;
5391
+ if (!entry.canReaddir()) return [];
5392
+ else if (withFileTypes) return entry.readdirSync();
5393
+ else return entry.readdirSync().map((e) => e.name);
5394
+ }
5395
+ /**
5396
+ * Call lstat() on the string or Path object, and update all known
5397
+ * information that can be determined.
5398
+ *
5399
+ * Note that unlike `fs.lstat()`, the returned value does not contain some
5400
+ * information, such as `mode`, `dev`, `nlink`, and `ino`. If that
5401
+ * information is required, you will need to call `fs.lstat` yourself.
5402
+ *
5403
+ * If the Path refers to a nonexistent file, or if the lstat call fails for
5404
+ * any reason, `undefined` is returned. Otherwise the updated Path object is
5405
+ * returned.
5406
+ *
5407
+ * Results are cached, and thus may be out of date if the filesystem is
5408
+ * mutated.
5409
+ */
5410
+ async lstat(entry = this.cwd) {
5411
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5412
+ return entry.lstat();
5413
+ }
5414
+ /**
5415
+ * synchronous {@link PathScurryBase.lstat}
5416
+ */
5417
+ lstatSync(entry = this.cwd) {
5418
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5419
+ return entry.lstatSync();
5420
+ }
5421
+ async readlink(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
5422
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5423
+ else if (!(entry instanceof PathBase)) {
5424
+ withFileTypes = entry.withFileTypes;
5425
+ entry = this.cwd;
5426
+ }
5427
+ const e = await entry.readlink();
5428
+ return withFileTypes ? e : e?.fullpath();
5429
+ }
5430
+ readlinkSync(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
5431
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5432
+ else if (!(entry instanceof PathBase)) {
5433
+ withFileTypes = entry.withFileTypes;
5434
+ entry = this.cwd;
5435
+ }
5436
+ const e = entry.readlinkSync();
5437
+ return withFileTypes ? e : e?.fullpath();
5438
+ }
5439
+ async realpath(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
5440
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5441
+ else if (!(entry instanceof PathBase)) {
5442
+ withFileTypes = entry.withFileTypes;
5443
+ entry = this.cwd;
5444
+ }
5445
+ const e = await entry.realpath();
5446
+ return withFileTypes ? e : e?.fullpath();
5447
+ }
5448
+ realpathSync(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
5449
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5450
+ else if (!(entry instanceof PathBase)) {
5451
+ withFileTypes = entry.withFileTypes;
5452
+ entry = this.cwd;
5453
+ }
5454
+ const e = entry.realpathSync();
5455
+ return withFileTypes ? e : e?.fullpath();
5456
+ }
5457
+ async walk(entry = this.cwd, opts = {}) {
5458
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5459
+ else if (!(entry instanceof PathBase)) {
5460
+ opts = entry;
5461
+ entry = this.cwd;
5462
+ }
5463
+ const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
5464
+ const results = [];
5465
+ if (!filter || filter(entry)) results.push(withFileTypes ? entry : entry.fullpath());
5466
+ const dirs = new Set();
5467
+ const walk = (dir, cb) => {
5468
+ dirs.add(dir);
5469
+ dir.readdirCB((er, entries) => {
5470
+ /* c8 ignore start */
5471
+ if (er) return cb(er);
5472
+ /* c8 ignore stop */
5473
+ let len = entries.length;
5474
+ if (!len) return cb();
5475
+ const next = () => {
5476
+ if (--len === 0) cb();
5477
+ };
5478
+ for (const e of entries) {
5479
+ if (!filter || filter(e)) results.push(withFileTypes ? e : e.fullpath());
5480
+ if (follow && e.isSymbolicLink()) e.realpath().then((r) => r?.isUnknown() ? r.lstat() : r).then((r) => r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next());
5481
+ else if (e.shouldWalk(dirs, walkFilter)) walk(e, next);
5482
+ else next();
5483
+ }
5484
+ }, true);
5485
+ };
5486
+ const start = entry;
5487
+ return new Promise((res, rej) => {
5488
+ walk(start, (er) => {
5489
+ /* c8 ignore start */
5490
+ if (er) return rej(er);
5491
+ /* c8 ignore stop */
5492
+ res(results);
5493
+ });
5494
+ });
5495
+ }
5496
+ walkSync(entry = this.cwd, opts = {}) {
5497
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5498
+ else if (!(entry instanceof PathBase)) {
5499
+ opts = entry;
5500
+ entry = this.cwd;
5501
+ }
5502
+ const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
5503
+ const results = [];
5504
+ if (!filter || filter(entry)) results.push(withFileTypes ? entry : entry.fullpath());
5505
+ const dirs = new Set([entry]);
5506
+ for (const dir of dirs) {
5507
+ const entries = dir.readdirSync();
5508
+ for (const e of entries) {
5509
+ if (!filter || filter(e)) results.push(withFileTypes ? e : e.fullpath());
5510
+ let r = e;
5511
+ if (e.isSymbolicLink()) {
5512
+ if (!(follow && (r = e.realpathSync()))) continue;
5513
+ if (r.isUnknown()) r.lstatSync();
5514
+ }
5515
+ if (r.shouldWalk(dirs, walkFilter)) dirs.add(r);
5516
+ }
5517
+ }
5518
+ return results;
5519
+ }
5520
+ /**
5521
+ * Support for `for await`
5522
+ *
5523
+ * Alias for {@link PathScurryBase.iterate}
5524
+ *
5525
+ * Note: As of Node 19, this is very slow, compared to other methods of
5526
+ * walking. Consider using {@link PathScurryBase.stream} if memory overhead
5527
+ * and backpressure are concerns, or {@link PathScurryBase.walk} if not.
5528
+ */
5529
+ [Symbol.asyncIterator]() {
5530
+ return this.iterate();
5531
+ }
5532
+ iterate(entry = this.cwd, options = {}) {
5533
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5534
+ else if (!(entry instanceof PathBase)) {
5535
+ options = entry;
5536
+ entry = this.cwd;
5537
+ }
5538
+ return this.stream(entry, options)[Symbol.asyncIterator]();
5539
+ }
5540
+ /**
5541
+ * Iterating over a PathScurry performs a synchronous walk.
5542
+ *
5543
+ * Alias for {@link PathScurryBase.iterateSync}
5544
+ */
5545
+ [Symbol.iterator]() {
5546
+ return this.iterateSync();
5547
+ }
5548
+ *iterateSync(entry = this.cwd, opts = {}) {
5549
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5550
+ else if (!(entry instanceof PathBase)) {
5551
+ opts = entry;
5552
+ entry = this.cwd;
5553
+ }
5554
+ const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
5555
+ if (!filter || filter(entry)) yield withFileTypes ? entry : entry.fullpath();
5556
+ const dirs = new Set([entry]);
5557
+ for (const dir of dirs) {
5558
+ const entries = dir.readdirSync();
5559
+ for (const e of entries) {
5560
+ if (!filter || filter(e)) yield withFileTypes ? e : e.fullpath();
5561
+ let r = e;
5562
+ if (e.isSymbolicLink()) {
5563
+ if (!(follow && (r = e.realpathSync()))) continue;
5564
+ if (r.isUnknown()) r.lstatSync();
5565
+ }
5566
+ if (r.shouldWalk(dirs, walkFilter)) dirs.add(r);
5567
+ }
5568
+ }
5569
+ }
5570
+ stream(entry = this.cwd, opts = {}) {
5571
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5572
+ else if (!(entry instanceof PathBase)) {
5573
+ opts = entry;
5574
+ entry = this.cwd;
5575
+ }
5576
+ const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
5577
+ const results = new Minipass({ objectMode: true });
5578
+ if (!filter || filter(entry)) results.write(withFileTypes ? entry : entry.fullpath());
5579
+ const dirs = new Set();
5580
+ const queue = [entry];
5581
+ let processing = 0;
5582
+ const process$1 = () => {
5583
+ let paused = false;
5584
+ while (!paused) {
5585
+ const dir = queue.shift();
5586
+ if (!dir) {
5587
+ if (processing === 0) results.end();
5588
+ return;
5589
+ }
5590
+ processing++;
5591
+ dirs.add(dir);
5592
+ const onReaddir = (er, entries, didRealpaths = false) => {
5593
+ /* c8 ignore start */
5594
+ if (er) return results.emit("error", er);
5595
+ /* c8 ignore stop */
5596
+ if (follow && !didRealpaths) {
5597
+ const promises$1 = [];
5598
+ for (const e of entries) if (e.isSymbolicLink()) promises$1.push(e.realpath().then((r) => r?.isUnknown() ? r.lstat() : r));
5599
+ if (promises$1.length) {
5600
+ Promise.all(promises$1).then(() => onReaddir(null, entries, true));
5601
+ return;
5602
+ }
5603
+ }
5604
+ for (const e of entries) if (e && (!filter || filter(e))) {
5605
+ if (!results.write(withFileTypes ? e : e.fullpath())) paused = true;
5606
+ }
5607
+ processing--;
5608
+ for (const e of entries) {
5609
+ const r = e.realpathCached() || e;
5610
+ if (r.shouldWalk(dirs, walkFilter)) queue.push(r);
5611
+ }
5612
+ if (paused && !results.flowing) results.once("drain", process$1);
5613
+ else if (!sync$1) process$1();
5614
+ };
5615
+ let sync$1 = true;
5616
+ dir.readdirCB(onReaddir, true);
5617
+ sync$1 = false;
5618
+ }
5619
+ };
5620
+ process$1();
5621
+ return results;
5622
+ }
5623
+ streamSync(entry = this.cwd, opts = {}) {
5624
+ if (typeof entry === "string") entry = this.cwd.resolve(entry);
5625
+ else if (!(entry instanceof PathBase)) {
5626
+ opts = entry;
5627
+ entry = this.cwd;
5628
+ }
5629
+ const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
5630
+ const results = new Minipass({ objectMode: true });
5631
+ const dirs = new Set();
5632
+ if (!filter || filter(entry)) results.write(withFileTypes ? entry : entry.fullpath());
5633
+ const queue = [entry];
5634
+ let processing = 0;
5635
+ const process$1 = () => {
5636
+ let paused = false;
5637
+ while (!paused) {
5638
+ const dir = queue.shift();
5639
+ if (!dir) {
5640
+ if (processing === 0) results.end();
5641
+ return;
5642
+ }
5643
+ processing++;
5644
+ dirs.add(dir);
5645
+ const entries = dir.readdirSync();
5646
+ for (const e of entries) if (!filter || filter(e)) {
5647
+ if (!results.write(withFileTypes ? e : e.fullpath())) paused = true;
5648
+ }
5649
+ processing--;
5650
+ for (const e of entries) {
5651
+ let r = e;
5652
+ if (e.isSymbolicLink()) {
5653
+ if (!(follow && (r = e.realpathSync()))) continue;
5654
+ if (r.isUnknown()) r.lstatSync();
5655
+ }
5656
+ if (r.shouldWalk(dirs, walkFilter)) queue.push(r);
5657
+ }
5658
+ }
5659
+ if (paused && !results.flowing) results.once("drain", process$1);
5660
+ };
5661
+ process$1();
5662
+ return results;
5663
+ }
5664
+ chdir(path$4 = this.cwd) {
5665
+ const oldCwd = this.cwd;
5666
+ this.cwd = typeof path$4 === "string" ? this.cwd.resolve(path$4) : path$4;
5667
+ this.cwd[setAsCwd](oldCwd);
5668
+ }
5669
+ };
5670
+ /**
5671
+ * Windows implementation of {@link PathScurryBase}
5672
+ *
5673
+ * Defaults to case insensitve, uses `'\\'` to generate path strings. Uses
5674
+ * {@link PathWin32} for Path objects.
5675
+ */
5676
+ var PathScurryWin32 = class extends PathScurryBase {
5677
+ /**
5678
+ * separator for generating path strings
5679
+ */
5680
+ sep = "\\";
5681
+ constructor(cwd = process.cwd(), opts = {}) {
5682
+ const { nocase = true } = opts;
5683
+ super(cwd, win32, "\\", {
5684
+ ...opts,
5685
+ nocase
5686
+ });
5687
+ this.nocase = nocase;
5688
+ for (let p = this.cwd; p; p = p.parent) p.nocase = this.nocase;
5689
+ }
5690
+ /**
5691
+ * @internal
5692
+ */
5693
+ parseRootPath(dir) {
5694
+ return win32.parse(dir).root.toUpperCase();
5695
+ }
5696
+ /**
5697
+ * @internal
5698
+ */
5699
+ newRoot(fs$1) {
5700
+ return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs$1 });
5701
+ }
5702
+ /**
5703
+ * Return true if the provided path string is an absolute path
5704
+ */
5705
+ isAbsolute(p) {
5706
+ return p.startsWith("/") || p.startsWith("\\") || /^[a-z]:(\/|\\)/i.test(p);
5707
+ }
5708
+ };
5709
+ /**
5710
+ * {@link PathScurryBase} implementation for all posix systems other than Darwin.
5711
+ *
5712
+ * Defaults to case-sensitive matching, uses `'/'` to generate path strings.
5713
+ *
5714
+ * Uses {@link PathPosix} for Path objects.
5715
+ */
5716
+ var PathScurryPosix = class extends PathScurryBase {
5717
+ /**
5718
+ * separator for generating path strings
5719
+ */
5720
+ sep = "/";
5721
+ constructor(cwd = process.cwd(), opts = {}) {
5722
+ const { nocase = false } = opts;
5723
+ super(cwd, posix, "/", {
5724
+ ...opts,
5725
+ nocase
5726
+ });
5727
+ this.nocase = nocase;
5728
+ }
5729
+ /**
5730
+ * @internal
5731
+ */
5732
+ parseRootPath(_dir) {
5733
+ return "/";
5734
+ }
5735
+ /**
5736
+ * @internal
5737
+ */
5738
+ newRoot(fs$1) {
5739
+ return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs$1 });
5740
+ }
5741
+ /**
5742
+ * Return true if the provided path string is an absolute path
5743
+ */
5744
+ isAbsolute(p) {
5745
+ return p.startsWith("/");
5746
+ }
5747
+ };
5748
+ /**
5749
+ * {@link PathScurryBase} implementation for Darwin (macOS) systems.
5750
+ *
5751
+ * Defaults to case-insensitive matching, uses `'/'` for generating path
5752
+ * strings.
5753
+ *
5754
+ * Uses {@link PathPosix} for Path objects.
5755
+ */
5756
+ var PathScurryDarwin = class extends PathScurryPosix {
5757
+ constructor(cwd = process.cwd(), opts = {}) {
5758
+ const { nocase = true } = opts;
5759
+ super(cwd, {
5760
+ ...opts,
5761
+ nocase
5762
+ });
5763
+ }
5764
+ };
5765
+ /**
5766
+ * Default {@link PathBase} implementation for the current platform.
5767
+ *
5768
+ * {@link PathWin32} on Windows systems, {@link PathPosix} on all others.
5769
+ */
5770
+ const Path = process.platform === "win32" ? PathWin32 : PathPosix;
5771
+ /**
5772
+ * Default {@link PathScurryBase} implementation for the current platform.
5773
+ *
5774
+ * {@link PathScurryWin32} on Windows systems, {@link PathScurryDarwin} on
5775
+ * Darwin (macOS) systems, {@link PathScurryPosix} on all others.
5776
+ */
5777
+ const PathScurry = process.platform === "win32" ? PathScurryWin32 : process.platform === "darwin" ? PathScurryDarwin : PathScurryPosix;
5778
+
5779
+ //#endregion
5780
+ //#region node_modules/glob/dist/esm/pattern.js
5781
+ const isPatternList = (pl) => pl.length >= 1;
5782
+ const isGlobList = (gl) => gl.length >= 1;
5783
+ /**
5784
+ * An immutable-ish view on an array of glob parts and their parsed
5785
+ * results
5786
+ */
5787
+ var Pattern = class Pattern {
5788
+ #patternList;
5789
+ #globList;
5790
+ #index;
5791
+ length;
5792
+ #platform;
5793
+ #rest;
5794
+ #globString;
5795
+ #isDrive;
5796
+ #isUNC;
5797
+ #isAbsolute;
5798
+ #followGlobstar = true;
5799
+ constructor(patternList, globList, index, platform) {
5800
+ if (!isPatternList(patternList)) throw new TypeError("empty pattern list");
5801
+ if (!isGlobList(globList)) throw new TypeError("empty glob list");
5802
+ if (globList.length !== patternList.length) throw new TypeError("mismatched pattern list and glob list lengths");
5803
+ this.length = patternList.length;
5804
+ if (index < 0 || index >= this.length) throw new TypeError("index out of range");
5805
+ this.#patternList = patternList;
5806
+ this.#globList = globList;
5807
+ this.#index = index;
5808
+ this.#platform = platform;
5809
+ if (this.#index === 0) {
5810
+ if (this.isUNC()) {
5811
+ const [p0, p1, p2, p3, ...prest] = this.#patternList;
5812
+ const [g0, g1, g2, g3, ...grest] = this.#globList;
5813
+ if (prest[0] === "") {
5814
+ prest.shift();
5815
+ grest.shift();
5816
+ }
5817
+ const p = [
5818
+ p0,
5819
+ p1,
5820
+ p2,
5821
+ p3,
5822
+ ""
5823
+ ].join("/");
5824
+ const g = [
5825
+ g0,
5826
+ g1,
5827
+ g2,
5828
+ g3,
5829
+ ""
5830
+ ].join("/");
5831
+ this.#patternList = [p, ...prest];
5832
+ this.#globList = [g, ...grest];
5833
+ this.length = this.#patternList.length;
5834
+ } else if (this.isDrive() || this.isAbsolute()) {
5835
+ const [p1, ...prest] = this.#patternList;
5836
+ const [g1, ...grest] = this.#globList;
5837
+ if (prest[0] === "") {
5838
+ prest.shift();
5839
+ grest.shift();
5840
+ }
5841
+ const p = p1 + "/";
5842
+ const g = g1 + "/";
5843
+ this.#patternList = [p, ...prest];
5844
+ this.#globList = [g, ...grest];
5845
+ this.length = this.#patternList.length;
5846
+ }
5847
+ }
5848
+ }
5849
+ /**
5850
+ * The first entry in the parsed list of patterns
5851
+ */
5852
+ pattern() {
5853
+ return this.#patternList[this.#index];
5854
+ }
5855
+ /**
5856
+ * true of if pattern() returns a string
5857
+ */
5858
+ isString() {
5859
+ return typeof this.#patternList[this.#index] === "string";
5860
+ }
5861
+ /**
5862
+ * true of if pattern() returns GLOBSTAR
5863
+ */
5864
+ isGlobstar() {
5865
+ return this.#patternList[this.#index] === GLOBSTAR;
5866
+ }
5867
+ /**
5868
+ * true if pattern() returns a regexp
5869
+ */
5870
+ isRegExp() {
5871
+ return this.#patternList[this.#index] instanceof RegExp;
5872
+ }
5873
+ /**
5874
+ * The /-joined set of glob parts that make up this pattern
5875
+ */
5876
+ globString() {
5877
+ return this.#globString = this.#globString || (this.#index === 0 ? this.isAbsolute() ? this.#globList[0] + this.#globList.slice(1).join("/") : this.#globList.join("/") : this.#globList.slice(this.#index).join("/"));
5878
+ }
5879
+ /**
5880
+ * true if there are more pattern parts after this one
5881
+ */
5882
+ hasMore() {
5883
+ return this.length > this.#index + 1;
5884
+ }
5885
+ /**
5886
+ * The rest of the pattern after this part, or null if this is the end
5887
+ */
5888
+ rest() {
5889
+ if (this.#rest !== void 0) return this.#rest;
5890
+ if (!this.hasMore()) return this.#rest = null;
5891
+ this.#rest = new Pattern(this.#patternList, this.#globList, this.#index + 1, this.#platform);
5892
+ this.#rest.#isAbsolute = this.#isAbsolute;
5893
+ this.#rest.#isUNC = this.#isUNC;
5894
+ this.#rest.#isDrive = this.#isDrive;
5895
+ return this.#rest;
5896
+ }
5897
+ /**
5898
+ * true if the pattern represents a //unc/path/ on windows
5899
+ */
5900
+ isUNC() {
5901
+ const pl = this.#patternList;
5902
+ return this.#isUNC !== void 0 ? this.#isUNC : this.#isUNC = this.#platform === "win32" && this.#index === 0 && pl[0] === "" && pl[1] === "" && typeof pl[2] === "string" && !!pl[2] && typeof pl[3] === "string" && !!pl[3];
5903
+ }
5904
+ /**
5905
+ * True if the pattern starts with a drive letter on Windows
5906
+ */
5907
+ isDrive() {
5908
+ const pl = this.#patternList;
5909
+ return this.#isDrive !== void 0 ? this.#isDrive : this.#isDrive = this.#platform === "win32" && this.#index === 0 && this.length > 1 && typeof pl[0] === "string" && /^[a-z]:$/i.test(pl[0]);
5910
+ }
5911
+ /**
5912
+ * True if the pattern is rooted on an absolute path
5913
+ */
5914
+ isAbsolute() {
5915
+ const pl = this.#patternList;
5916
+ return this.#isAbsolute !== void 0 ? this.#isAbsolute : this.#isAbsolute = pl[0] === "" && pl.length > 1 || this.isDrive() || this.isUNC();
5917
+ }
5918
+ /**
5919
+ * consume the root of the pattern, and return it
5920
+ */
5921
+ root() {
5922
+ const p = this.#patternList[0];
5923
+ return typeof p === "string" && this.isAbsolute() && this.#index === 0 ? p : "";
5924
+ }
5925
+ /**
5926
+ * Check to see if the current globstar pattern is allowed to follow
5927
+ * a symbolic link.
5928
+ */
5929
+ checkFollowGlobstar() {
5930
+ return !(this.#index === 0 || !this.isGlobstar() || !this.#followGlobstar);
5931
+ }
5932
+ /**
5933
+ * Mark that the current globstar pattern is following a symbolic link
5934
+ */
5935
+ markFollowGlobstar() {
5936
+ if (this.#index === 0 || !this.isGlobstar() || !this.#followGlobstar) return false;
5937
+ this.#followGlobstar = false;
5938
+ return true;
5939
+ }
5940
+ };
5941
+
5942
+ //#endregion
5943
+ //#region node_modules/glob/dist/esm/ignore.js
5944
+ const defaultPlatform$1 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
5945
+ /**
5946
+ * Class used to process ignored patterns
5947
+ */
5948
+ var Ignore = class {
5949
+ relative;
5950
+ relativeChildren;
5951
+ absolute;
5952
+ absoluteChildren;
5953
+ platform;
5954
+ mmopts;
5955
+ constructor(ignored, { nobrace, nocase, noext, noglobstar, platform = defaultPlatform$1 }) {
5956
+ this.relative = [];
5957
+ this.absolute = [];
5958
+ this.relativeChildren = [];
5959
+ this.absoluteChildren = [];
5960
+ this.platform = platform;
5961
+ this.mmopts = {
5962
+ dot: true,
5963
+ nobrace,
5964
+ nocase,
5965
+ noext,
5966
+ noglobstar,
5967
+ optimizationLevel: 2,
5968
+ platform,
5969
+ nocomment: true,
5970
+ nonegate: true
5971
+ };
5972
+ for (const ign of ignored) this.add(ign);
5973
+ }
5974
+ add(ign) {
5975
+ const mm = new Minimatch(ign, this.mmopts);
5976
+ for (let i = 0; i < mm.set.length; i++) {
5977
+ const parsed = mm.set[i];
5978
+ const globParts = mm.globParts[i];
5979
+ /* c8 ignore start */
5980
+ if (!parsed || !globParts) throw new Error("invalid pattern object");
5981
+ while (parsed[0] === "." && globParts[0] === ".") {
5982
+ parsed.shift();
5983
+ globParts.shift();
5984
+ }
5985
+ /* c8 ignore stop */
5986
+ const p = new Pattern(parsed, globParts, 0, this.platform);
5987
+ const m = new Minimatch(p.globString(), this.mmopts);
5988
+ const children = globParts[globParts.length - 1] === "**";
5989
+ const absolute = p.isAbsolute();
5990
+ if (absolute) this.absolute.push(m);
5991
+ else this.relative.push(m);
5992
+ if (children) if (absolute) this.absoluteChildren.push(m);
5993
+ else this.relativeChildren.push(m);
5994
+ }
5995
+ }
5996
+ ignored(p) {
5997
+ const fullpath = p.fullpath();
5998
+ const fullpaths = `${fullpath}/`;
5999
+ const relative$1 = p.relative() || ".";
6000
+ const relatives = `${relative$1}/`;
6001
+ for (const m of this.relative) if (m.match(relative$1) || m.match(relatives)) return true;
6002
+ for (const m of this.absolute) if (m.match(fullpath) || m.match(fullpaths)) return true;
6003
+ return false;
6004
+ }
6005
+ childrenIgnored(p) {
6006
+ const fullpath = p.fullpath() + "/";
6007
+ const relative$1 = (p.relative() || ".") + "/";
6008
+ for (const m of this.relativeChildren) if (m.match(relative$1)) return true;
6009
+ for (const m of this.absoluteChildren) if (m.match(fullpath)) return true;
6010
+ return false;
6011
+ }
6012
+ };
6013
+
6014
+ //#endregion
6015
+ //#region node_modules/glob/dist/esm/processor.js
6016
+ /**
6017
+ * A cache of which patterns have been processed for a given Path
6018
+ */
6019
+ var HasWalkedCache = class HasWalkedCache {
6020
+ store;
6021
+ constructor(store = new Map()) {
6022
+ this.store = store;
6023
+ }
6024
+ copy() {
6025
+ return new HasWalkedCache(new Map(this.store));
6026
+ }
6027
+ hasWalked(target, pattern) {
6028
+ return this.store.get(target.fullpath())?.has(pattern.globString());
6029
+ }
6030
+ storeWalked(target, pattern) {
6031
+ const fullpath = target.fullpath();
6032
+ const cached = this.store.get(fullpath);
6033
+ if (cached) cached.add(pattern.globString());
6034
+ else this.store.set(fullpath, new Set([pattern.globString()]));
6035
+ }
6036
+ };
6037
+ /**
6038
+ * A record of which paths have been matched in a given walk step,
6039
+ * and whether they only are considered a match if they are a directory,
6040
+ * and whether their absolute or relative path should be returned.
6041
+ */
6042
+ var MatchRecord = class {
6043
+ store = new Map();
6044
+ add(target, absolute, ifDir) {
6045
+ const n = (absolute ? 2 : 0) | (ifDir ? 1 : 0);
6046
+ const current = this.store.get(target);
6047
+ this.store.set(target, current === void 0 ? n : n & current);
6048
+ }
6049
+ entries() {
6050
+ return [...this.store.entries()].map(([path$4, n]) => [
6051
+ path$4,
6052
+ !!(n & 2),
6053
+ !!(n & 1)
6054
+ ]);
6055
+ }
6056
+ };
6057
+ /**
6058
+ * A collection of patterns that must be processed in a subsequent step
6059
+ * for a given path.
6060
+ */
6061
+ var SubWalks = class {
6062
+ store = new Map();
6063
+ add(target, pattern) {
6064
+ if (!target.canReaddir()) return;
6065
+ const subs = this.store.get(target);
6066
+ if (subs) {
6067
+ if (!subs.find((p) => p.globString() === pattern.globString())) subs.push(pattern);
6068
+ } else this.store.set(target, [pattern]);
6069
+ }
6070
+ get(target) {
6071
+ const subs = this.store.get(target);
6072
+ /* c8 ignore start */
6073
+ if (!subs) throw new Error("attempting to walk unknown path");
6074
+ /* c8 ignore stop */
6075
+ return subs;
6076
+ }
6077
+ entries() {
6078
+ return this.keys().map((k) => [k, this.store.get(k)]);
6079
+ }
6080
+ keys() {
6081
+ return [...this.store.keys()].filter((t) => t.canReaddir());
6082
+ }
6083
+ };
6084
+ /**
6085
+ * The class that processes patterns for a given path.
6086
+ *
6087
+ * Handles child entry filtering, and determining whether a path's
6088
+ * directory contents must be read.
6089
+ */
6090
+ var Processor = class Processor {
6091
+ hasWalkedCache;
6092
+ matches = new MatchRecord();
6093
+ subwalks = new SubWalks();
6094
+ patterns;
6095
+ follow;
6096
+ dot;
6097
+ opts;
6098
+ constructor(opts, hasWalkedCache) {
6099
+ this.opts = opts;
6100
+ this.follow = !!opts.follow;
6101
+ this.dot = !!opts.dot;
6102
+ this.hasWalkedCache = hasWalkedCache ? hasWalkedCache.copy() : new HasWalkedCache();
6103
+ }
6104
+ processPatterns(target, patterns) {
6105
+ this.patterns = patterns;
6106
+ const processingSet = patterns.map((p) => [target, p]);
6107
+ for (let [t, pattern] of processingSet) {
6108
+ this.hasWalkedCache.storeWalked(t, pattern);
6109
+ const root = pattern.root();
6110
+ const absolute = pattern.isAbsolute() && this.opts.absolute !== false;
6111
+ if (root) {
6112
+ t = t.resolve(root === "/" && this.opts.root !== void 0 ? this.opts.root : root);
6113
+ const rest$1 = pattern.rest();
6114
+ if (!rest$1) {
6115
+ this.matches.add(t, true, false);
6116
+ continue;
6117
+ } else pattern = rest$1;
6118
+ }
6119
+ if (t.isENOENT()) continue;
6120
+ let p;
6121
+ let rest;
6122
+ let changed = false;
6123
+ while (typeof (p = pattern.pattern()) === "string" && (rest = pattern.rest())) {
6124
+ const c = t.resolve(p);
6125
+ t = c;
6126
+ pattern = rest;
6127
+ changed = true;
6128
+ }
6129
+ p = pattern.pattern();
6130
+ rest = pattern.rest();
6131
+ if (changed) {
6132
+ if (this.hasWalkedCache.hasWalked(t, pattern)) continue;
6133
+ this.hasWalkedCache.storeWalked(t, pattern);
6134
+ }
6135
+ if (typeof p === "string") {
6136
+ const ifDir = p === ".." || p === "" || p === ".";
6137
+ this.matches.add(t.resolve(p), absolute, ifDir);
6138
+ continue;
6139
+ } else if (p === GLOBSTAR) {
6140
+ if (!t.isSymbolicLink() || this.follow || pattern.checkFollowGlobstar()) this.subwalks.add(t, pattern);
6141
+ const rp = rest?.pattern();
6142
+ const rrest = rest?.rest();
6143
+ if (!rest || (rp === "" || rp === ".") && !rrest) this.matches.add(t, absolute, rp === "" || rp === ".");
6144
+ else if (rp === "..") {
6145
+ /* c8 ignore start */
6146
+ const tp = t.parent || t;
6147
+ /* c8 ignore stop */
6148
+ if (!rrest) this.matches.add(tp, absolute, true);
6149
+ else if (!this.hasWalkedCache.hasWalked(tp, rrest)) this.subwalks.add(tp, rrest);
6150
+ }
6151
+ } else if (p instanceof RegExp) this.subwalks.add(t, pattern);
6152
+ }
6153
+ return this;
6154
+ }
6155
+ subwalkTargets() {
6156
+ return this.subwalks.keys();
6157
+ }
6158
+ child() {
6159
+ return new Processor(this.opts, this.hasWalkedCache);
6160
+ }
6161
+ filterEntries(parent, entries) {
6162
+ const patterns = this.subwalks.get(parent);
6163
+ const results = this.child();
6164
+ for (const e of entries) for (const pattern of patterns) {
6165
+ const absolute = pattern.isAbsolute();
6166
+ const p = pattern.pattern();
6167
+ const rest = pattern.rest();
6168
+ if (p === GLOBSTAR) results.testGlobstar(e, pattern, rest, absolute);
6169
+ else if (p instanceof RegExp) results.testRegExp(e, p, rest, absolute);
6170
+ else results.testString(e, p, rest, absolute);
6171
+ }
6172
+ return results;
6173
+ }
6174
+ testGlobstar(e, pattern, rest, absolute) {
6175
+ if (this.dot || !e.name.startsWith(".")) {
6176
+ if (!pattern.hasMore()) this.matches.add(e, absolute, false);
6177
+ if (e.canReaddir()) {
6178
+ if (this.follow || !e.isSymbolicLink()) this.subwalks.add(e, pattern);
6179
+ else if (e.isSymbolicLink()) {
6180
+ if (rest && pattern.checkFollowGlobstar()) this.subwalks.add(e, rest);
6181
+ else if (pattern.markFollowGlobstar()) this.subwalks.add(e, pattern);
6182
+ }
6183
+ }
6184
+ }
6185
+ if (rest) {
6186
+ const rp = rest.pattern();
6187
+ if (typeof rp === "string" && rp !== ".." && rp !== "" && rp !== ".") this.testString(e, rp, rest.rest(), absolute);
6188
+ else if (rp === "..") {
6189
+ /* c8 ignore start */
6190
+ const ep = e.parent || e;
6191
+ /* c8 ignore stop */
6192
+ this.subwalks.add(ep, rest);
6193
+ } else if (rp instanceof RegExp) this.testRegExp(e, rp, rest.rest(), absolute);
6194
+ }
6195
+ }
6196
+ testRegExp(e, p, rest, absolute) {
6197
+ if (!p.test(e.name)) return;
6198
+ if (!rest) this.matches.add(e, absolute, false);
6199
+ else this.subwalks.add(e, rest);
6200
+ }
6201
+ testString(e, p, rest, absolute) {
6202
+ if (!e.isNamed(p)) return;
6203
+ if (!rest) this.matches.add(e, absolute, false);
6204
+ else this.subwalks.add(e, rest);
6205
+ }
6206
+ };
6207
+
6208
+ //#endregion
6209
+ //#region node_modules/glob/dist/esm/walker.js
6210
+ const makeIgnore = (ignore, opts) => typeof ignore === "string" ? new Ignore([ignore], opts) : Array.isArray(ignore) ? new Ignore(ignore, opts) : ignore;
6211
+ /**
6212
+ * basic walking utilities that all the glob walker types use
6213
+ */
6214
+ var GlobUtil = class {
6215
+ path;
6216
+ patterns;
6217
+ opts;
6218
+ seen = new Set();
6219
+ paused = false;
6220
+ aborted = false;
6221
+ #onResume = [];
6222
+ #ignore;
6223
+ #sep;
6224
+ signal;
6225
+ maxDepth;
6226
+ includeChildMatches;
6227
+ constructor(patterns, path$4, opts) {
6228
+ this.patterns = patterns;
6229
+ this.path = path$4;
6230
+ this.opts = opts;
6231
+ this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
6232
+ this.includeChildMatches = opts.includeChildMatches !== false;
6233
+ if (opts.ignore || !this.includeChildMatches) {
6234
+ this.#ignore = makeIgnore(opts.ignore ?? [], opts);
6235
+ if (!this.includeChildMatches && typeof this.#ignore.add !== "function") {
6236
+ const m = "cannot ignore child matches, ignore lacks add() method.";
6237
+ throw new Error(m);
6238
+ }
6239
+ }
6240
+ /* c8 ignore start */
6241
+ this.maxDepth = opts.maxDepth || Infinity;
6242
+ /* c8 ignore stop */
6243
+ if (opts.signal) {
6244
+ this.signal = opts.signal;
6245
+ this.signal.addEventListener("abort", () => {
6246
+ this.#onResume.length = 0;
6247
+ });
6248
+ }
6249
+ }
6250
+ #ignored(path$4) {
6251
+ return this.seen.has(path$4) || !!this.#ignore?.ignored?.(path$4);
6252
+ }
6253
+ #childrenIgnored(path$4) {
6254
+ return !!this.#ignore?.childrenIgnored?.(path$4);
6255
+ }
6256
+ pause() {
6257
+ this.paused = true;
6258
+ }
6259
+ resume() {
6260
+ /* c8 ignore start */
6261
+ if (this.signal?.aborted) return;
6262
+ /* c8 ignore stop */
6263
+ this.paused = false;
6264
+ let fn = void 0;
6265
+ while (!this.paused && (fn = this.#onResume.shift())) fn();
6266
+ }
6267
+ onResume(fn) {
6268
+ if (this.signal?.aborted) return;
6269
+ /* c8 ignore start */
6270
+ if (!this.paused) fn();
6271
+ else
6272
+ /* c8 ignore stop */
6273
+ this.#onResume.push(fn);
6274
+ }
6275
+ async matchCheck(e, ifDir) {
6276
+ if (ifDir && this.opts.nodir) return void 0;
6277
+ let rpc;
6278
+ if (this.opts.realpath) {
6279
+ rpc = e.realpathCached() || await e.realpath();
6280
+ if (!rpc) return void 0;
6281
+ e = rpc;
6282
+ }
6283
+ const needStat = e.isUnknown() || this.opts.stat;
6284
+ const s = needStat ? await e.lstat() : e;
6285
+ if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) {
6286
+ const target = await s.realpath();
6287
+ /* c8 ignore start */
6288
+ if (target && (target.isUnknown() || this.opts.stat)) await target.lstat();
6289
+ }
6290
+ return this.matchCheckTest(s, ifDir);
6291
+ }
6292
+ matchCheckTest(e, ifDir) {
6293
+ return e && (this.maxDepth === Infinity || e.depth() <= this.maxDepth) && (!ifDir || e.canReaddir()) && (!this.opts.nodir || !e.isDirectory()) && (!this.opts.nodir || !this.opts.follow || !e.isSymbolicLink() || !e.realpathCached()?.isDirectory()) && !this.#ignored(e) ? e : void 0;
6294
+ }
6295
+ matchCheckSync(e, ifDir) {
6296
+ if (ifDir && this.opts.nodir) return void 0;
6297
+ let rpc;
6298
+ if (this.opts.realpath) {
6299
+ rpc = e.realpathCached() || e.realpathSync();
6300
+ if (!rpc) return void 0;
6301
+ e = rpc;
6302
+ }
6303
+ const needStat = e.isUnknown() || this.opts.stat;
6304
+ const s = needStat ? e.lstatSync() : e;
6305
+ if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) {
6306
+ const target = s.realpathSync();
6307
+ if (target && (target?.isUnknown() || this.opts.stat)) target.lstatSync();
6308
+ }
6309
+ return this.matchCheckTest(s, ifDir);
6310
+ }
6311
+ matchFinish(e, absolute) {
6312
+ if (this.#ignored(e)) return;
6313
+ if (!this.includeChildMatches && this.#ignore?.add) {
6314
+ const ign = `${e.relativePosix()}/**`;
6315
+ this.#ignore.add(ign);
6316
+ }
6317
+ const abs = this.opts.absolute === void 0 ? absolute : this.opts.absolute;
6318
+ this.seen.add(e);
6319
+ const mark = this.opts.mark && e.isDirectory() ? this.#sep : "";
6320
+ if (this.opts.withFileTypes) this.matchEmit(e);
6321
+ else if (abs) {
6322
+ const abs$1 = this.opts.posix ? e.fullpathPosix() : e.fullpath();
6323
+ this.matchEmit(abs$1 + mark);
6324
+ } else {
6325
+ const rel = this.opts.posix ? e.relativePosix() : e.relative();
6326
+ const pre = this.opts.dotRelative && !rel.startsWith(".." + this.#sep) ? "." + this.#sep : "";
6327
+ this.matchEmit(!rel ? "." + mark : pre + rel + mark);
6328
+ }
6329
+ }
6330
+ async match(e, absolute, ifDir) {
6331
+ const p = await this.matchCheck(e, ifDir);
6332
+ if (p) this.matchFinish(p, absolute);
6333
+ }
6334
+ matchSync(e, absolute, ifDir) {
6335
+ const p = this.matchCheckSync(e, ifDir);
6336
+ if (p) this.matchFinish(p, absolute);
6337
+ }
6338
+ walkCB(target, patterns, cb) {
6339
+ /* c8 ignore start */
6340
+ if (this.signal?.aborted) cb();
6341
+ /* c8 ignore stop */
6342
+ this.walkCB2(target, patterns, new Processor(this.opts), cb);
6343
+ }
6344
+ walkCB2(target, patterns, processor, cb) {
6345
+ if (this.#childrenIgnored(target)) return cb();
6346
+ if (this.signal?.aborted) cb();
6347
+ if (this.paused) {
6348
+ this.onResume(() => this.walkCB2(target, patterns, processor, cb));
6349
+ return;
6350
+ }
6351
+ processor.processPatterns(target, patterns);
6352
+ let tasks = 1;
6353
+ const next = () => {
6354
+ if (--tasks === 0) cb();
6355
+ };
6356
+ for (const [m, absolute, ifDir] of processor.matches.entries()) {
6357
+ if (this.#ignored(m)) continue;
6358
+ tasks++;
6359
+ this.match(m, absolute, ifDir).then(() => next());
6360
+ }
6361
+ for (const t of processor.subwalkTargets()) {
6362
+ if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) continue;
6363
+ tasks++;
6364
+ const childrenCached = t.readdirCached();
6365
+ if (t.calledReaddir()) this.walkCB3(t, childrenCached, processor, next);
6366
+ else t.readdirCB((_, entries) => this.walkCB3(t, entries, processor, next), true);
6367
+ }
6368
+ next();
6369
+ }
6370
+ walkCB3(target, entries, processor, cb) {
6371
+ processor = processor.filterEntries(target, entries);
6372
+ let tasks = 1;
6373
+ const next = () => {
6374
+ if (--tasks === 0) cb();
6375
+ };
6376
+ for (const [m, absolute, ifDir] of processor.matches.entries()) {
6377
+ if (this.#ignored(m)) continue;
6378
+ tasks++;
6379
+ this.match(m, absolute, ifDir).then(() => next());
6380
+ }
6381
+ for (const [target$1, patterns] of processor.subwalks.entries()) {
6382
+ tasks++;
6383
+ this.walkCB2(target$1, patterns, processor.child(), next);
6384
+ }
6385
+ next();
6386
+ }
6387
+ walkCBSync(target, patterns, cb) {
6388
+ /* c8 ignore start */
6389
+ if (this.signal?.aborted) cb();
6390
+ /* c8 ignore stop */
6391
+ this.walkCB2Sync(target, patterns, new Processor(this.opts), cb);
6392
+ }
6393
+ walkCB2Sync(target, patterns, processor, cb) {
6394
+ if (this.#childrenIgnored(target)) return cb();
6395
+ if (this.signal?.aborted) cb();
6396
+ if (this.paused) {
6397
+ this.onResume(() => this.walkCB2Sync(target, patterns, processor, cb));
6398
+ return;
6399
+ }
6400
+ processor.processPatterns(target, patterns);
6401
+ let tasks = 1;
6402
+ const next = () => {
6403
+ if (--tasks === 0) cb();
6404
+ };
6405
+ for (const [m, absolute, ifDir] of processor.matches.entries()) {
6406
+ if (this.#ignored(m)) continue;
6407
+ this.matchSync(m, absolute, ifDir);
6408
+ }
6409
+ for (const t of processor.subwalkTargets()) {
6410
+ if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) continue;
6411
+ tasks++;
6412
+ const children = t.readdirSync();
6413
+ this.walkCB3Sync(t, children, processor, next);
6414
+ }
6415
+ next();
6416
+ }
6417
+ walkCB3Sync(target, entries, processor, cb) {
6418
+ processor = processor.filterEntries(target, entries);
6419
+ let tasks = 1;
6420
+ const next = () => {
6421
+ if (--tasks === 0) cb();
6422
+ };
6423
+ for (const [m, absolute, ifDir] of processor.matches.entries()) {
6424
+ if (this.#ignored(m)) continue;
6425
+ this.matchSync(m, absolute, ifDir);
6426
+ }
6427
+ for (const [target$1, patterns] of processor.subwalks.entries()) {
6428
+ tasks++;
6429
+ this.walkCB2Sync(target$1, patterns, processor.child(), next);
6430
+ }
6431
+ next();
6432
+ }
6433
+ };
6434
+ var GlobWalker = class extends GlobUtil {
6435
+ matches = new Set();
6436
+ constructor(patterns, path$4, opts) {
6437
+ super(patterns, path$4, opts);
6438
+ }
6439
+ matchEmit(e) {
6440
+ this.matches.add(e);
6441
+ }
6442
+ async walk() {
6443
+ if (this.signal?.aborted) throw this.signal.reason;
6444
+ if (this.path.isUnknown()) await this.path.lstat();
6445
+ await new Promise((res, rej) => {
6446
+ this.walkCB(this.path, this.patterns, () => {
6447
+ if (this.signal?.aborted) rej(this.signal.reason);
6448
+ else res(this.matches);
6449
+ });
6450
+ });
6451
+ return this.matches;
6452
+ }
6453
+ walkSync() {
6454
+ if (this.signal?.aborted) throw this.signal.reason;
6455
+ if (this.path.isUnknown()) this.path.lstatSync();
6456
+ this.walkCBSync(this.path, this.patterns, () => {
6457
+ if (this.signal?.aborted) throw this.signal.reason;
6458
+ });
6459
+ return this.matches;
6460
+ }
6461
+ };
6462
+ var GlobStream = class extends GlobUtil {
6463
+ results;
6464
+ constructor(patterns, path$4, opts) {
6465
+ super(patterns, path$4, opts);
6466
+ this.results = new Minipass({
6467
+ signal: this.signal,
6468
+ objectMode: true
6469
+ });
6470
+ this.results.on("drain", () => this.resume());
6471
+ this.results.on("resume", () => this.resume());
6472
+ }
6473
+ matchEmit(e) {
6474
+ this.results.write(e);
6475
+ if (!this.results.flowing) this.pause();
6476
+ }
6477
+ stream() {
6478
+ const target = this.path;
6479
+ if (target.isUnknown()) target.lstat().then(() => {
6480
+ this.walkCB(target, this.patterns, () => this.results.end());
6481
+ });
6482
+ else this.walkCB(target, this.patterns, () => this.results.end());
6483
+ return this.results;
6484
+ }
6485
+ streamSync() {
6486
+ if (this.path.isUnknown()) this.path.lstatSync();
6487
+ this.walkCBSync(this.path, this.patterns, () => this.results.end());
6488
+ return this.results;
6489
+ }
6490
+ };
6491
+
6492
+ //#endregion
6493
+ //#region node_modules/glob/dist/esm/glob.js
6494
+ const defaultPlatform = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
6495
+ /**
6496
+ * An object that can perform glob pattern traversals.
6497
+ */
6498
+ var Glob = class {
6499
+ absolute;
6500
+ cwd;
6501
+ root;
6502
+ dot;
6503
+ dotRelative;
6504
+ follow;
6505
+ ignore;
6506
+ magicalBraces;
6507
+ mark;
6508
+ matchBase;
6509
+ maxDepth;
6510
+ nobrace;
6511
+ nocase;
6512
+ nodir;
6513
+ noext;
6514
+ noglobstar;
6515
+ pattern;
6516
+ platform;
6517
+ realpath;
6518
+ scurry;
6519
+ stat;
6520
+ signal;
6521
+ windowsPathsNoEscape;
6522
+ withFileTypes;
6523
+ includeChildMatches;
6524
+ /**
6525
+ * The options provided to the constructor.
6526
+ */
6527
+ opts;
6528
+ /**
6529
+ * An array of parsed immutable {@link Pattern} objects.
6530
+ */
6531
+ patterns;
6532
+ /**
6533
+ * All options are stored as properties on the `Glob` object.
6534
+ *
6535
+ * See {@link GlobOptions} for full options descriptions.
6536
+ *
6537
+ * Note that a previous `Glob` object can be passed as the
6538
+ * `GlobOptions` to another `Glob` instantiation to re-use settings
6539
+ * and caches with a new pattern.
6540
+ *
6541
+ * Traversal functions can be called multiple times to run the walk
6542
+ * again.
6543
+ */
6544
+ constructor(pattern, opts) {
6545
+ /* c8 ignore start */
6546
+ if (!opts) throw new TypeError("glob options required");
6547
+ /* c8 ignore stop */
6548
+ this.withFileTypes = !!opts.withFileTypes;
6549
+ this.signal = opts.signal;
6550
+ this.follow = !!opts.follow;
6551
+ this.dot = !!opts.dot;
6552
+ this.dotRelative = !!opts.dotRelative;
6553
+ this.nodir = !!opts.nodir;
6554
+ this.mark = !!opts.mark;
6555
+ if (!opts.cwd) this.cwd = "";
6556
+ else if (opts.cwd instanceof URL || opts.cwd.startsWith("file://")) opts.cwd = fileURLToPath$1(opts.cwd);
6557
+ this.cwd = opts.cwd || "";
6558
+ this.root = opts.root;
6559
+ this.magicalBraces = !!opts.magicalBraces;
6560
+ this.nobrace = !!opts.nobrace;
6561
+ this.noext = !!opts.noext;
6562
+ this.realpath = !!opts.realpath;
6563
+ this.absolute = opts.absolute;
6564
+ this.includeChildMatches = opts.includeChildMatches !== false;
6565
+ this.noglobstar = !!opts.noglobstar;
6566
+ this.matchBase = !!opts.matchBase;
6567
+ this.maxDepth = typeof opts.maxDepth === "number" ? opts.maxDepth : Infinity;
6568
+ this.stat = !!opts.stat;
6569
+ this.ignore = opts.ignore;
6570
+ if (this.withFileTypes && this.absolute !== void 0) throw new Error("cannot set absolute and withFileTypes:true");
6571
+ if (typeof pattern === "string") pattern = [pattern];
6572
+ this.windowsPathsNoEscape = !!opts.windowsPathsNoEscape || opts.allowWindowsEscape === false;
6573
+ if (this.windowsPathsNoEscape) pattern = pattern.map((p) => p.replace(/\\/g, "/"));
6574
+ if (this.matchBase) {
6575
+ if (opts.noglobstar) throw new TypeError("base matching requires globstar");
6576
+ pattern = pattern.map((p) => p.includes("/") ? p : `./**/${p}`);
6577
+ }
6578
+ this.pattern = pattern;
6579
+ this.platform = opts.platform || defaultPlatform;
6580
+ this.opts = {
6581
+ ...opts,
6582
+ platform: this.platform
6583
+ };
6584
+ if (opts.scurry) {
6585
+ this.scurry = opts.scurry;
6586
+ if (opts.nocase !== void 0 && opts.nocase !== opts.scurry.nocase) throw new Error("nocase option contradicts provided scurry option");
6587
+ } else {
6588
+ const Scurry = opts.platform === "win32" ? PathScurryWin32 : opts.platform === "darwin" ? PathScurryDarwin : opts.platform ? PathScurryPosix : PathScurry;
6589
+ this.scurry = new Scurry(this.cwd, {
6590
+ nocase: opts.nocase,
6591
+ fs: opts.fs
6592
+ });
6593
+ }
6594
+ this.nocase = this.scurry.nocase;
6595
+ const nocaseMagicOnly = this.platform === "darwin" || this.platform === "win32";
6596
+ const mmo = {
6597
+ ...opts,
6598
+ dot: this.dot,
6599
+ matchBase: this.matchBase,
6600
+ nobrace: this.nobrace,
6601
+ nocase: this.nocase,
6602
+ nocaseMagicOnly,
6603
+ nocomment: true,
6604
+ noext: this.noext,
6605
+ nonegate: true,
6606
+ optimizationLevel: 2,
6607
+ platform: this.platform,
6608
+ windowsPathsNoEscape: this.windowsPathsNoEscape,
6609
+ debug: !!this.opts.debug
6610
+ };
6611
+ const mms = this.pattern.map((p) => new Minimatch(p, mmo));
6612
+ const [matchSet, globParts] = mms.reduce((set, m) => {
6613
+ set[0].push(...m.set);
6614
+ set[1].push(...m.globParts);
6615
+ return set;
6616
+ }, [[], []]);
6617
+ this.patterns = matchSet.map((set, i) => {
6618
+ const g = globParts[i];
6619
+ /* c8 ignore start */
6620
+ if (!g) throw new Error("invalid pattern object");
6621
+ /* c8 ignore stop */
6622
+ return new Pattern(set, g, 0, this.platform);
6623
+ });
6624
+ }
6625
+ async walk() {
6626
+ return [...await new GlobWalker(this.patterns, this.scurry.cwd, {
6627
+ ...this.opts,
6628
+ maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
6629
+ platform: this.platform,
6630
+ nocase: this.nocase,
6631
+ includeChildMatches: this.includeChildMatches
6632
+ }).walk()];
6633
+ }
6634
+ walkSync() {
6635
+ return [...new GlobWalker(this.patterns, this.scurry.cwd, {
6636
+ ...this.opts,
6637
+ maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
6638
+ platform: this.platform,
6639
+ nocase: this.nocase,
6640
+ includeChildMatches: this.includeChildMatches
6641
+ }).walkSync()];
6642
+ }
6643
+ stream() {
6644
+ return new GlobStream(this.patterns, this.scurry.cwd, {
6645
+ ...this.opts,
6646
+ maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
6647
+ platform: this.platform,
6648
+ nocase: this.nocase,
6649
+ includeChildMatches: this.includeChildMatches
6650
+ }).stream();
6651
+ }
6652
+ streamSync() {
6653
+ return new GlobStream(this.patterns, this.scurry.cwd, {
6654
+ ...this.opts,
6655
+ maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
6656
+ platform: this.platform,
6657
+ nocase: this.nocase,
6658
+ includeChildMatches: this.includeChildMatches
6659
+ }).streamSync();
6660
+ }
6661
+ /**
6662
+ * Default sync iteration function. Returns a Generator that
6663
+ * iterates over the results.
6664
+ */
6665
+ iterateSync() {
6666
+ return this.streamSync()[Symbol.iterator]();
6667
+ }
6668
+ [Symbol.iterator]() {
6669
+ return this.iterateSync();
6670
+ }
6671
+ /**
6672
+ * Default async iteration function. Returns an AsyncGenerator that
6673
+ * iterates over the results.
6674
+ */
6675
+ iterate() {
6676
+ return this.stream()[Symbol.asyncIterator]();
6677
+ }
6678
+ [Symbol.asyncIterator]() {
6679
+ return this.iterate();
6680
+ }
6681
+ };
6682
+
6683
+ //#endregion
6684
+ //#region node_modules/glob/dist/esm/has-magic.js
6685
+ /**
6686
+ * Return true if the patterns provided contain any magic glob characters,
6687
+ * given the options provided.
6688
+ *
6689
+ * Brace expansion is not considered "magic" unless the `magicalBraces` option
6690
+ * is set, as brace expansion just turns one string into an array of strings.
6691
+ * So a pattern like `'x{a,b}y'` would return `false`, because `'xay'` and
6692
+ * `'xby'` both do not contain any magic glob characters, and it's treated the
6693
+ * same as if you had called it on `['xay', 'xby']`. When `magicalBraces:true`
6694
+ * is in the options, brace expansion _is_ treated as a pattern having magic.
6695
+ */
6696
+ const hasMagic = (pattern, options = {}) => {
6697
+ if (!Array.isArray(pattern)) pattern = [pattern];
6698
+ for (const p of pattern) if (new Minimatch(p, options).hasMagic()) return true;
6699
+ return false;
6700
+ };
6701
+
6702
+ //#endregion
6703
+ //#region node_modules/glob/dist/esm/index.js
6704
+ function globStreamSync(pattern, options = {}) {
6705
+ return new Glob(pattern, options).streamSync();
6706
+ }
6707
+ function globStream(pattern, options = {}) {
6708
+ return new Glob(pattern, options).stream();
6709
+ }
6710
+ function globSync(pattern, options = {}) {
6711
+ return new Glob(pattern, options).walkSync();
6712
+ }
6713
+ async function glob_(pattern, options = {}) {
6714
+ return new Glob(pattern, options).walk();
6715
+ }
6716
+ function globIterateSync(pattern, options = {}) {
6717
+ return new Glob(pattern, options).iterateSync();
6718
+ }
6719
+ function globIterate(pattern, options = {}) {
6720
+ return new Glob(pattern, options).iterate();
6721
+ }
6722
+ const streamSync = globStreamSync;
6723
+ const stream = Object.assign(globStream, { sync: globStreamSync });
6724
+ const iterateSync = globIterateSync;
6725
+ const iterate = Object.assign(globIterate, { sync: globIterateSync });
6726
+ const sync = Object.assign(globSync, {
6727
+ stream: globStreamSync,
6728
+ iterate: globIterateSync
6729
+ });
6730
+ const glob = Object.assign(glob_, {
6731
+ glob: glob_,
6732
+ globSync,
6733
+ sync,
6734
+ globStream,
6735
+ stream,
6736
+ globStreamSync,
6737
+ streamSync,
6738
+ globIterate,
6739
+ iterate,
6740
+ globIterateSync,
6741
+ iterateSync,
6742
+ Glob,
6743
+ hasMagic,
6744
+ escape,
6745
+ unescape
6746
+ });
6747
+ glob.glob = glob;
6748
+
6749
+ //#endregion
6750
+ //#region src/cli/commands/resume-drift-detector.ts
6751
+ const DEFAULT_SCAN_GLOBS = ["packages/*/src/**/*.ts", "src/**/*.ts"];
6752
+ /**
6753
+ * Detect manifest-vs-working-tree drift for `substrate resume`.
6754
+ *
6755
+ * Scans files matching the configured glob patterns using the `glob` library.
6756
+ * For each story entry in `manifest.per_story_state` where
6757
+ * `phase === 'IN_STORY_CREATION'` AND `status === 'dispatched'`, checks whether
6758
+ * any scanned file has an mtime newer than the story's `started_at` timestamp.
6759
+ * If so, the manifest is considered drifted.
6760
+ *
6761
+ * Scan globs are read from the `SUBSTRATE_RESUME_DRIFT_SCAN_GLOBS` environment
6762
+ * variable (comma-separated), falling back to the defaults:
6763
+ * "packages/&#42;/src/&#42;&#42;/&#42;.ts" and "src/&#42;&#42;/&#42;.ts"
6764
+ *
6765
+ * @param manifest - The run manifest data (parsed and validated from disk)
6766
+ * @param projectRoot - Absolute path to the project root for glob scanning
6767
+ * @returns `{ drifted, evidence }` where `evidence` contains up to 3 sample
6768
+ * newer files per drifted story entry.
6769
+ */
6770
+ async function detectManifestDriftAgainstWorkingTree(manifest, projectRoot) {
6771
+ const envGlobs = process.env["SUBSTRATE_RESUME_DRIFT_SCAN_GLOBS"];
6772
+ const scanGlobs = envGlobs !== void 0 && envGlobs.trim() !== "" ? envGlobs.split(",").map((g) => g.trim()).filter(Boolean) : DEFAULT_SCAN_GLOBS;
6773
+ const qualifying = Object.entries(manifest.per_story_state).filter(([, s]) => s.phase === "IN_STORY_CREATION" && s.status === "dispatched");
6774
+ if (qualifying.length === 0) return {
6775
+ drifted: false,
6776
+ evidence: []
6777
+ };
6778
+ const scannedAbsPaths = await glob(scanGlobs, {
6779
+ cwd: projectRoot,
6780
+ absolute: true,
6781
+ nodir: true
6782
+ });
6783
+ if (scannedAbsPaths.length === 0) return {
6784
+ drifted: false,
6785
+ evidence: []
6786
+ };
6787
+ const evidence = [];
6788
+ for (const [storyKey, storyState] of qualifying) {
6789
+ const storyTimestampMs = new Date(storyState.started_at).getTime();
6790
+ const newerFiles = [];
6791
+ for (const absPath of scannedAbsPaths) try {
6792
+ const { mtimeMs } = await promises.stat(absPath);
6793
+ if (mtimeMs > storyTimestampMs) newerFiles.push(relative(projectRoot, absPath).replace(/\\/g, "/"));
6794
+ } catch {}
6795
+ if (newerFiles.length > 0) evidence.push({
6796
+ storyKey,
6797
+ sampleFiles: newerFiles.slice(0, 3),
6798
+ totalNewerFiles: newerFiles.length
6799
+ });
6800
+ }
6801
+ return {
6802
+ drifted: evidence.length > 0,
6803
+ evidence
6804
+ };
6805
+ }
6806
+
3040
6807
  //#endregion
3041
6808
  //#region src/cli/commands/resume.ts
3042
6809
  const logger$14 = createLogger("resume-cmd");
3043
6810
  /**
6811
+ * Format a human-readable duration from an ISO-8601 timestamp to "now".
6812
+ */
6813
+ function formatAgo(isoTimestamp) {
6814
+ const diffMs = Date.now() - new Date(isoTimestamp).getTime();
6815
+ const totalSeconds = Math.max(0, Math.floor(diffMs / 1e3));
6816
+ if (totalSeconds < 60) return `${totalSeconds} second${totalSeconds === 1 ? "" : "s"} ago`;
6817
+ const minutes = Math.floor(totalSeconds / 60);
6818
+ if (minutes < 60) return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
6819
+ const hours = Math.floor(minutes / 60);
6820
+ if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
6821
+ const days = Math.floor(hours / 24);
6822
+ return `${days} day${days === 1 ? "" : "s"} ago`;
6823
+ }
6824
+ /**
6825
+ * Format the drift error message shown to the operator when drift is detected.
6826
+ * The output must contain the substring "manifest drift detected" (checked by AC5 test).
6827
+ */
6828
+ function formatDriftError(result, manifest) {
6829
+ const lines = [];
6830
+ for (const ev of result.evidence) {
6831
+ const storyState = manifest.per_story_state[ev.storyKey];
6832
+ const recordedAt = storyState?.started_at ?? "unknown";
6833
+ const ago = formatAgo(recordedAt);
6834
+ const sampleList = ev.sampleFiles.join(", ");
6835
+ const fileCount = ev.totalNewerFiles;
6836
+ lines.push(`substrate resume: manifest drift detected for story ${ev.storyKey}`);
6837
+ lines.push(` manifest phase: IN_STORY_CREATION dispatched (recorded ${ago})`);
6838
+ lines.push(` working tree: ${fileCount} file${fileCount === 1 ? "" : "s"} newer than manifest (sample: ${sampleList})`);
6839
+ lines.push("");
6840
+ }
6841
+ lines.push("This usually means the orchestrator died after writing dev-story output but", "before persisting the phase advancement (obs_2026-05-03_022 class).", "Re-dispatching from IN_STORY_CREATION would clobber that work.", "", "Recovery options:", " 1. Inspect the working tree, validate dev-story output, then commit it", " as if the pipeline had shipped LGTM — see obs_022 recovery runbook.", " 2. To proceed with re-dispatch anyway (clobbering disk state),", " re-run with --force-from-manifest.");
6842
+ return lines.join("\n");
6843
+ }
6844
+ /**
3044
6845
  * Map internal orchestrator phase names to pipeline event protocol phase names.
3045
6846
  */
3046
6847
  function mapInternalPhaseToEventPhase(internalPhase) {
@@ -3064,6 +6865,20 @@ async function runResumeAction(options) {
3064
6865
  const dbRoot = await resolveMainRepoRoot(projectRoot);
3065
6866
  const packPath = join(dbRoot, "packs", packName);
3066
6867
  const dbPath = join(dbRoot, ".substrate", "substrate.db");
6868
+ if (!options.forceFromManifest) {
6869
+ const { manifest: runManifest } = await resolveRunManifest(dbRoot, specifiedRunId ?? void 0);
6870
+ if (runManifest !== null) try {
6871
+ const manifestData = await runManifest.read();
6872
+ const driftResult = await detectManifestDriftAgainstWorkingTree(manifestData, projectRoot);
6873
+ if (driftResult.drifted) {
6874
+ const errMsg = formatDriftError(driftResult, manifestData);
6875
+ process.stderr.write(errMsg + "\n");
6876
+ return 1;
6877
+ }
6878
+ } catch (driftErr) {
6879
+ logger$14.debug({ err: driftErr }, "manifest drift check failed — proceeding with resume");
6880
+ }
6881
+ }
3067
6882
  const doltDir = join(dbRoot, ".substrate", "state", ".dolt");
3068
6883
  if (!existsSync$1(dbPath) && !existsSync$1(doltDir)) {
3069
6884
  const errorMsg = `Decision store not initialized. Run 'substrate init' first.`;
@@ -3394,7 +7209,8 @@ async function runFullPipelineFromPhase(options) {
3394
7209
  run_id: payload.runId,
3395
7210
  active_dispatches: payload.activeDispatches,
3396
7211
  completed_dispatches: payload.completedDispatches,
3397
- queued_dispatches: payload.queuedDispatches
7212
+ queued_dispatches: payload.queuedDispatches,
7213
+ ...payload.perStoryState !== void 0 ? { per_story_state: payload.perStoryState } : {}
3398
7214
  });
3399
7215
  });
3400
7216
  }
@@ -3493,7 +7309,7 @@ async function runFullPipelineFromPhase(options) {
3493
7309
  }
3494
7310
  }
3495
7311
  function registerResumeCommand(program, _version = "0.0.0", projectRoot = process.cwd(), registry) {
3496
- program.command("resume").description("Resume a previously interrupted pipeline run").option("--run-id <id>", "Pipeline run ID to resume (defaults to latest)").option("--pack <name>", "Methodology pack name", "bmad").option("--stop-after <phase>", "Stop pipeline after this phase completes (overrides saved state)").option("--concurrency <n>", "Maximum parallel conflict groups", (v) => parseInt(v, 10), 3).option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--max-review-cycles <n>", "Maximum review cycles per story (default: 2)", (v) => parseInt(v, 10), 2).option("--agent <id>", "Agent backend: claude-code (default), codex, or gemini").action(async (opts) => {
7312
+ program.command("resume").description("Resume a previously interrupted pipeline run").option("--run-id <id>", "Pipeline run ID to resume (defaults to latest)").option("--pack <name>", "Methodology pack name", "bmad").option("--stop-after <phase>", "Stop pipeline after this phase completes (overrides saved state)").option("--concurrency <n>", "Maximum parallel conflict groups", (v) => parseInt(v, 10), 3).option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--max-review-cycles <n>", "Maximum review cycles per story (default: 2)", (v) => parseInt(v, 10), 2).option("--agent <id>", "Agent backend: claude-code (default), codex, or gemini").option("--force-from-manifest", "Bypass manifest drift check and proceed with re-dispatch (Story 66-3 / obs_2026-05-03_022 fix #3)").action(async (opts) => {
3497
7313
  const outputFormat = opts.outputFormat === "json" ? "json" : "human";
3498
7314
  const exitCode = await runResumeAction({
3499
7315
  runId: opts.runId,
@@ -3505,6 +7321,7 @@ function registerResumeCommand(program, _version = "0.0.0", projectRoot = proces
3505
7321
  events: opts.events,
3506
7322
  maxReviewCycles: opts.maxReviewCycles,
3507
7323
  agent: opts.agent,
7324
+ forceFromManifest: opts.forceFromManifest,
3508
7325
  registry
3509
7326
  });
3510
7327
  process.exitCode = exitCode;
@@ -3667,7 +7484,7 @@ async function runStatusAction(options) {
3667
7484
  logger$13.debug({ err }, "Work graph query failed, continuing without work graph data");
3668
7485
  }
3669
7486
  if (run === void 0) {
3670
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-BdsvEnfm.js");
7487
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-HmyFdWEf.js");
3671
7488
  const substrateDirPath = join(projectRoot, ".substrate");
3672
7489
  const processInfo = inspectProcessTree$1({
3673
7490
  projectRoot,
@@ -3746,6 +7563,14 @@ async function runStatusAction(options) {
3746
7563
  const completedCount = storyMetricsRows.filter((r) => r.result === "success").length;
3747
7564
  const storiesPerHour = pipelineWallClockMs > 0 ? Math.round(completedCount / (pipelineWallClockMs / 36e5) * 100) / 100 : 0;
3748
7565
  const totalCostUsd = storyMetricsRows.reduce((sum, r) => sum + (r.cost_usd ?? 0), 0);
7566
+ let latestHeartbeatPerStoryState;
7567
+ const heartbeatSnapshotPath = join(dbRoot, ".substrate", "latest-heartbeat-per-story-state.json");
7568
+ try {
7569
+ if (existsSync$1(heartbeatSnapshotPath)) {
7570
+ const raw = readFileSync$1(heartbeatSnapshotPath, "utf-8");
7571
+ latestHeartbeatPerStoryState = JSON.parse(raw);
7572
+ }
7573
+ } catch {}
3749
7574
  const enhancedOutput = {
3750
7575
  ...statusOutput,
3751
7576
  story_metrics: storyMetricsV2,
@@ -3758,7 +7583,8 @@ async function runStatusAction(options) {
3758
7583
  cost_usd: totalCostUsd
3759
7584
  },
3760
7585
  story_states: storeStories,
3761
- workGraph: workGraph ?? null
7586
+ workGraph: workGraph ?? null,
7587
+ latest_heartbeat_per_story_state: latestHeartbeatPerStoryState ?? {}
3762
7588
  };
3763
7589
  process.stdout.write(formatOutput(enhancedOutput, "json", true) + "\n");
3764
7590
  } else {
@@ -4623,7 +8449,7 @@ function defaultSupervisorDeps() {
4623
8449
  if (cached === null) {
4624
8450
  const { AdapterRegistry: AR } = await import(
4625
8451
  /* @vite-ignore */
4626
- "../adapter-registry-CcahKCG1.js"
8452
+ "../adapter-registry-k7ZX3Bz6.js"
4627
8453
  );
4628
8454
  cached = new AR();
4629
8455
  await cached.discoverAndRegister();
@@ -5190,11 +9016,11 @@ async function runSupervisorAction(options, deps = {}) {
5190
9016
  try {
5191
9017
  const { createExperimenter } = await import(
5192
9018
  /* @vite-ignore */
5193
- "../experimenter-2KGF4bLj.js"
9019
+ "../experimenter-DxxwicpK.js"
5194
9020
  );
5195
9021
  const { getLatestRun: getLatest } = await import(
5196
9022
  /* @vite-ignore */
5197
- "../decisions-UFV5YFaW.js"
9023
+ "../decisions-4F91LrVD.js"
5198
9024
  );
5199
9025
  const expAdapter = createDatabaseAdapter({
5200
9026
  backend: "auto",
@@ -5204,7 +9030,7 @@ async function runSupervisorAction(options, deps = {}) {
5204
9030
  await initSchema(expAdapter);
5205
9031
  const { runRunAction: runPipeline } = await import(
5206
9032
  /* @vite-ignore */
5207
- "../run-CkFWtcjl.js"
9033
+ "../run-BF8oeJhG.js"
5208
9034
  );
5209
9035
  const runStoryFn = async (opts) => {
5210
9036
  const exitCode = await runPipeline({
@@ -5736,7 +9562,7 @@ async function runMetricsAction(options) {
5736
9562
  const routingConfigPath = join(dbDir, "routing.yml");
5737
9563
  let routingConfig = null;
5738
9564
  if (existsSync$1(routingConfigPath)) try {
5739
- const { loadModelRoutingConfig } = await import("../routing-BNGNSI0w.js");
9565
+ const { loadModelRoutingConfig } = await import("../routing-0ykvBl_4.js");
5740
9566
  routingConfig = loadModelRoutingConfig(routingConfigPath);
5741
9567
  } catch {}
5742
9568
  if (routingConfig === null) routingConfig = {
@@ -9372,8 +13198,8 @@ async function createProgram() {
9372
13198
  /** Fire-and-forget startup version check (story 8.3, AC3/AC5) */
9373
13199
  function checkForUpdatesInBackground(currentVersion) {
9374
13200
  if (process.env.SUBSTRATE_NO_UPDATE_CHECK === "1") return;
9375
- import("../upgrade-Csv0GRft.js").then(async () => {
9376
- const { createVersionManager } = await import("../version-manager-impl-C-mrgne3.js");
13201
+ import("../upgrade-C8LAnB6W.js").then(async () => {
13202
+ const { createVersionManager } = await import("../version-manager-impl-DaA_ALYK.js");
9377
13203
  const vm = createVersionManager();
9378
13204
  const result = await vm.checkForUpdates();
9379
13205
  if (result.updateAvailable) {