@whittlelabs/sifter 0.30.7 → 0.30.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +32 -4
  2. package/bin.js +1919 -1604
  3. package/bin.js.map +4 -4
  4. package/package.json +1 -1
package/bin.js CHANGED
@@ -11861,12 +11861,38 @@ var require_environment = __commonJS({
11861
11861
  }
11862
11862
  });
11863
11863
 
11864
+ // ../../packages/shuttle/dist/branding/scaffold.js
11865
+ var require_scaffold = __commonJS({
11866
+ "../../packages/shuttle/dist/branding/scaffold.js"(exports2) {
11867
+ "use strict";
11868
+ Object.defineProperty(exports2, "__esModule", { value: true });
11869
+ exports2.scaffoldedConfigPath = scaffoldedConfigPath2;
11870
+ exports2.planScaffold = planScaffold2;
11871
+ var path_1 = require("path");
11872
+ function scaffoldedConfigPath2(brand, configDir) {
11873
+ return (0, path_1.join)(configDir, `${brand.product.id}.yaml`);
11874
+ }
11875
+ function planScaffold2(brand, setupOptions, existing) {
11876
+ const pools = Array.isArray(existing.pools) ? existing.pools : [];
11877
+ const first = pools[0];
11878
+ const prior = first !== null && typeof first === "object" && typeof first.executor === "string" ? first.executor : void 0;
11879
+ const executor = setupOptions.executor ?? prior ?? brand.defaultExecutor;
11880
+ const source = setupOptions.executor !== void 0 ? "flag" : prior !== void 0 ? "existing" : "default";
11881
+ const executors = existing.executors !== null && typeof existing.executors === "object" ? existing.executors : {};
11882
+ const block = executor === void 0 ? void 0 : executors[executor];
11883
+ const keptBlock = setupOptions.executor === void 0 && block !== null && typeof block === "object" ? block : void 0;
11884
+ return { executor, source, keptBlock };
11885
+ }
11886
+ }
11887
+ });
11888
+
11864
11889
  // ../../packages/shuttle/dist/preflight/checks.js
11865
11890
  var require_checks = __commonJS({
11866
11891
  "../../packages/shuttle/dist/preflight/checks.js"(exports2) {
11867
11892
  "use strict";
11868
11893
  Object.defineProperty(exports2, "__esModule", { value: true });
11869
11894
  exports2.PREFLIGHT_FLOORS = exports2.CHECKS = void 0;
11895
+ var path_1 = require("path");
11870
11896
  var registry_1 = require_registry();
11871
11897
  var claude_code_1 = require_claude_code();
11872
11898
  var http_api_1 = require_http_api();
@@ -11877,6 +11903,7 @@ var require_checks = __commonJS({
11877
11903
  var version_check_1 = require_version_check();
11878
11904
  var apply_1 = require_apply();
11879
11905
  var environment_1 = require_environment();
11906
+ var scaffold_1 = require_scaffold();
11880
11907
  var NODE_FLOOR = "20.0.0";
11881
11908
  var DISK_FLOOR_BYTES = 1024 * 1024 * 1024;
11882
11909
  var WORKSPACE_EXECUTOR = "claude-code";
@@ -11923,11 +11950,67 @@ var require_checks = __commonJS({
11923
11950
  return typeof tmpDir === "string" && tmpDir.length > 0 ? (0, apply_1.expandHome)(tmpDir) : osTmpDir;
11924
11951
  }
11925
11952
  async function withConfig(name, probes, body) {
11953
+ if (!hasReadablePairing(probes))
11954
+ return skip(name, NO_PAIRING);
11926
11955
  const result = probes.readConfig();
11927
11956
  if (!result.ok)
11928
11957
  return skip(name, "the config did not load; see config-loadable");
11929
11958
  return body(result.value);
11930
11959
  }
11960
+ var NO_PAIRING = "no readable pairing; see pairing-present";
11961
+ function hasReadablePairing(probes) {
11962
+ const stored = probes.readPairing();
11963
+ return stored.ok && stored.value !== null;
11964
+ }
11965
+ function initPlan(probes, subject) {
11966
+ const existing = probes.readScaffoldedConfig();
11967
+ if (!existing.ok)
11968
+ return existing;
11969
+ return {
11970
+ ok: true,
11971
+ value: (0, scaffold_1.planScaffold)(subject.brand, subject.requestedExecutor !== void 0 ? { executor: subject.requestedExecutor } : {}, existing.value ?? {})
11972
+ };
11973
+ }
11974
+ function initRunRoot(plan, subject, osTmpDir) {
11975
+ if (plan.executor !== WORKSPACE_EXECUTOR)
11976
+ return osTmpDir;
11977
+ if (subject.requestedTmpDir !== void 0 && subject.requestedTmpDir.length > 0) {
11978
+ return (0, apply_1.expandHome)(subject.requestedTmpDir);
11979
+ }
11980
+ const settings = {
11981
+ ...subject.brand.executorDefaults?.[WORKSPACE_EXECUTOR] ?? {},
11982
+ ...plan.keptBlock ?? {}
11983
+ };
11984
+ const tmpDir = settings.tmpDir;
11985
+ return typeof tmpDir === "string" && tmpDir.length > 0 ? (0, apply_1.expandHome)(tmpDir) : osTmpDir;
11986
+ }
11987
+ function belowNodeFloor(probes) {
11988
+ return (0, version_check_1.compareSemver)(bareVersion(probes.nodeVersion()), NODE_FLOOR) < 0;
11989
+ }
11990
+ function needsFetch(check) {
11991
+ return {
11992
+ ...check,
11993
+ async run(probes, subject) {
11994
+ if (belowNodeFloor(probes)) {
11995
+ return skip(check.name, "no network call on a runtime below the Node floor; see node-version");
11996
+ }
11997
+ return check.run(probes, subject);
11998
+ }
11999
+ };
12000
+ }
12001
+ var platformSupported = {
12002
+ name: "platform-supported",
12003
+ phases: ["init", "run", "doctor"],
12004
+ prerequisite: true,
12005
+ async run(probes, subject) {
12006
+ const platform = probes.platform();
12007
+ if (platform === "win32") {
12008
+ return fail("platform-supported", "native Windows is not supported", `install WSL (https://learn.microsoft.com/windows/wsl/install), then install and run ${subject.brand.product.cliBinary} inside it`);
12009
+ }
12010
+ return pass("platform-supported", PLATFORM_NAMES[platform] ?? platform);
12011
+ }
12012
+ };
12013
+ var PLATFORM_NAMES = { darwin: "macOS", linux: "Linux" };
11931
12014
  var nodeVersion = {
11932
12015
  name: "node-version",
11933
12016
  phases: ["init", "run", "doctor"],
@@ -11961,6 +12044,8 @@ var require_checks = __commonJS({
11961
12044
  name: "config-loadable",
11962
12045
  phases: ["run", "doctor"],
11963
12046
  async run(probes, subject) {
12047
+ if (!hasReadablePairing(probes))
12048
+ return skip("config-loadable", NO_PAIRING);
11964
12049
  const result = probes.readConfig();
11965
12050
  if (!result.ok) {
11966
12051
  return fail("config-loadable", oneLine(result.error), `fix the config, or run \`${subject.brand.product.cliBinary} init\` to rewrite it from this pairing`);
@@ -12045,15 +12130,20 @@ var require_checks = __commonJS({
12045
12130
  phases: ["init", "run", "doctor"],
12046
12131
  async run(probes, subject) {
12047
12132
  if (subject.phase === "init") {
12048
- const requested = subject.requestedExecutor;
12049
- if (requested === void 0) {
12050
- return skip("executor-coverage", "no --executor given; the brand default will be scaffolded");
12133
+ const plan = initPlan(probes, subject);
12134
+ if (!plan.ok) {
12135
+ return fail("executor-coverage", `the existing config could not be read: ${oneLine(plan.error)}`, `fix that file or remove it (init writes a fresh one), then run ${subject.brand.product.cliBinary} init again`);
12136
+ }
12137
+ const executor = plan.value.executor;
12138
+ if (executor === void 0) {
12139
+ return skip("executor-coverage", "init configures no executor for this build");
12051
12140
  }
12141
+ const origin = PLAN_SOURCE[plan.value.source];
12052
12142
  const allowed = subject.brand.executorAllowlist;
12053
- if (!allowed.includes("*") && !allowed.includes(requested)) {
12054
- return fail("executor-coverage", `--executor=${requested} is not in this build's allowlist`, `choose one of: ${allowed.join(", ")}`);
12143
+ if (!allowed.includes("*") && !allowed.includes(executor)) {
12144
+ return fail("executor-coverage", `${executor} (${origin}) is not in this build's allowlist`, `choose one of: ${allowed.join(", ")}`);
12055
12145
  }
12056
- return pass("executor-coverage", `--executor=${requested} is allowed by this build`);
12146
+ return pass("executor-coverage", `init will configure ${executor} (${origin})`);
12057
12147
  }
12058
12148
  return withConfig("executor-coverage", probes, (config) => {
12059
12149
  const names = configuredExecutors(config);
@@ -12082,8 +12172,13 @@ var require_checks = __commonJS({
12082
12172
  };
12083
12173
  var gitCli = {
12084
12174
  name: "git-cli",
12085
- phases: ["run", "doctor"],
12175
+ phases: ["init", "run", "doctor"],
12086
12176
  async run(probes, subject) {
12177
+ if (subject.phase === "init") {
12178
+ return atInit("git-cli", probes, subject, () => toolVerdict("git-cli", "git", probes, subject, {
12179
+ missingRemedy: "install git, or configure an executor that needs no checkout"
12180
+ }));
12181
+ }
12087
12182
  return withConfig("git-cli", probes, async (config) => {
12088
12183
  if (!configuredExecutors(config).includes(WORKSPACE_EXECUTOR)) {
12089
12184
  return skip("git-cli", `no ${WORKSPACE_EXECUTOR} executor configured; nothing checks out a workspace`);
@@ -12096,15 +12191,16 @@ var require_checks = __commonJS({
12096
12191
  };
12097
12192
  var claudeCli = {
12098
12193
  name: "claude-cli",
12099
- phases: ["run", "doctor"],
12194
+ phases: ["init", "run", "doctor"],
12100
12195
  async run(probes, subject) {
12196
+ if (subject.phase === "init") {
12197
+ return atInit("claude-cli", probes, subject, () => toolVerdict("claude-cli", "claude", probes, subject, { missingRemedy: CLAUDE_INSTALL }));
12198
+ }
12101
12199
  return withConfig("claude-cli", probes, async (config) => {
12102
12200
  if (!configuredExecutors(config).includes(WORKSPACE_EXECUTOR)) {
12103
12201
  return skip("claude-cli", `no ${WORKSPACE_EXECUTOR} executor configured`);
12104
12202
  }
12105
- return toolVerdict("claude-cli", "claude", probes, subject, {
12106
- missingRemedy: "install Claude Code (npm install -g @anthropic-ai/claude-code)"
12107
- });
12203
+ return toolVerdict("claude-cli", "claude", probes, subject, { missingRemedy: CLAUDE_INSTALL });
12108
12204
  });
12109
12205
  }
12110
12206
  };
@@ -12119,6 +12215,9 @@ var require_checks = __commonJS({
12119
12215
  if (config.credentials !== void 0) {
12120
12216
  return skip("claude-auth", "hosted mode: the model key is revealed per job, not read from a login");
12121
12217
  }
12218
+ if (await probes.which("claude") === null || !(await probes.versionOf("claude")).ran) {
12219
+ return skip("claude-auth", "no working claude CLI to be signed in to; see claude-cli");
12220
+ }
12122
12221
  if (subject.deep) {
12123
12222
  const round = await probes.claudeRoundTrip();
12124
12223
  if (!round.ok) {
@@ -12139,23 +12238,45 @@ var require_checks = __commonJS({
12139
12238
  };
12140
12239
  var runRootWritable = {
12141
12240
  name: "run-root-writable",
12142
- phases: ["run", "doctor"],
12241
+ phases: ["init", "run", "doctor"],
12143
12242
  async run(probes, subject) {
12144
- return withConfig("run-root-writable", probes, async (config) => {
12145
- const targets = [
12146
- ["config dir", subject.paths.configDir],
12147
- ["run root", runRoot(config, subject, osTmpDirOf(probes))]
12148
- ];
12149
- for (const [label, dir] of targets) {
12150
- const probe = await probes.mkdtemp(dir);
12151
- if (!probe.ok) {
12152
- return fail("run-root-writable", `cannot create a directory in the ${label} ${dir}: ${oneLine(probe.error)}`, `make ${dir} writable by the user running this (chown -R $(whoami) ${dir})`);
12153
- }
12154
- }
12155
- return pass("run-root-writable", targets.map(([, dir]) => dir).join(" and "));
12156
- });
12243
+ if (subject.phase === "init") {
12244
+ const plan = initPlan(probes, subject);
12245
+ if (!plan.ok)
12246
+ return skip("run-root-writable", "the existing config could not be read; see executor-coverage");
12247
+ const configBase = await nearestExisting(probes, subject.paths.configDir);
12248
+ return writableVerdict(probes, [
12249
+ ["config dir", configBase, subject.paths.configDir],
12250
+ ["run root", initRunRoot(plan.value, subject, osTmpDirOf(probes))]
12251
+ ]);
12252
+ }
12253
+ return withConfig("run-root-writable", probes, async (config) => writableVerdict(probes, [
12254
+ ["config dir", subject.paths.configDir],
12255
+ ["run root", runRoot(config, subject, osTmpDirOf(probes))]
12256
+ ]));
12157
12257
  }
12158
12258
  };
12259
+ async function writableVerdict(probes, targets) {
12260
+ for (const [label, dir, about] of targets) {
12261
+ const probe = await probes.mkdtemp(dir);
12262
+ if (!probe.ok) {
12263
+ const what = about !== void 0 && about !== dir ? `the ${label} ${about} (in ${dir})` : `the ${label} ${dir}`;
12264
+ return fail("run-root-writable", `cannot create a directory for ${what}: ${oneLine(probe.error)}`, `make ${dir} writable by the user running this (chown -R $(whoami) ${dir})`);
12265
+ }
12266
+ }
12267
+ return pass("run-root-writable", targets.map(([, dir, about]) => about ?? dir).join(" and "));
12268
+ }
12269
+ async function nearestExisting(probes, dir) {
12270
+ let current = dir;
12271
+ for (; ; ) {
12272
+ if (await probes.stat(current) !== null)
12273
+ return current;
12274
+ const parent = (0, path_1.dirname)(current);
12275
+ if (parent === current)
12276
+ return current;
12277
+ current = parent;
12278
+ }
12279
+ }
12159
12280
  var diskSpace = {
12160
12281
  name: "disk-space",
12161
12282
  phases: ["run", "doctor"],
@@ -12207,12 +12328,13 @@ var require_checks = __commonJS({
12207
12328
  }
12208
12329
  };
12209
12330
  exports2.CHECKS = [
12331
+ platformSupported,
12210
12332
  nodeVersion,
12211
12333
  pairingPresent,
12212
12334
  configLoadable,
12213
- pairingLive,
12335
+ needsFetch(pairingLive),
12214
12336
  pairingEnvironment,
12215
- keepReachable,
12337
+ needsFetch(keepReachable),
12216
12338
  executorCoverage,
12217
12339
  gitCli,
12218
12340
  claudeCli,
@@ -12220,7 +12342,7 @@ var require_checks = __commonJS({
12220
12342
  runRootWritable,
12221
12343
  diskSpace,
12222
12344
  overlayHosts,
12223
- jobsReachable,
12345
+ needsFetch(jobsReachable),
12224
12346
  versionCurrent
12225
12347
  ];
12226
12348
  async function toolVerdict(name, bin, probes, subject, opts) {
@@ -12229,7 +12351,11 @@ var require_checks = __commonJS({
12229
12351
  return fail(name, `${bin} is not on PATH`, opts.missingRemedy);
12230
12352
  }
12231
12353
  const floor = subject.brand.minimumToolVersions?.[bin];
12232
- const version = await probes.versionOf(bin);
12354
+ const outcome = await probes.versionOf(bin);
12355
+ if (!outcome.ran) {
12356
+ return fail(name, `${bin} at ${found} is there but cannot run: \`${bin} --version\` ${oneLine(outcome.reason)}`, cannotRunRemedy(bin, found, outcome.reason, probes.platform(), opts.missingRemedy));
12357
+ }
12358
+ const version = outcome.version;
12233
12359
  if (version === null) {
12234
12360
  return warn(name, `${bin} at ${found}, version unreadable`);
12235
12361
  }
@@ -12238,6 +12364,27 @@ var require_checks = __commonJS({
12238
12364
  }
12239
12365
  return pass(name, `${bin} ${version} at ${found}`);
12240
12366
  }
12367
+ function cannotRunRemedy(bin, found, reason, platform, missingRemedy) {
12368
+ if (bin === "git" && (platform === "darwin" || /xcrun|developer path/i.test(reason))) {
12369
+ return "this is the macOS placeholder git: install the Command Line Tools with `xcode-select --install`, or install git another way (e.g. Homebrew) ahead of it on PATH";
12370
+ }
12371
+ return `run \`${bin} --version\` to see why ${found} fails, then reinstall it (${missingRemedy})`;
12372
+ }
12373
+ var CLAUDE_INSTALL = "install Claude Code (npm install -g @anthropic-ai/claude-code)";
12374
+ async function atInit(name, probes, subject, body) {
12375
+ const plan = initPlan(probes, subject);
12376
+ if (!plan.ok)
12377
+ return skip(name, "the existing config could not be read; see executor-coverage");
12378
+ if (plan.value.executor !== WORKSPACE_EXECUTOR) {
12379
+ return skip(name, plan.value.executor === void 0 ? "init configures no executor for this build" : `init configures ${plan.value.executor}, which needs no ${WORKSPACE_EXECUTOR} tools`);
12380
+ }
12381
+ return body();
12382
+ }
12383
+ var PLAN_SOURCE = {
12384
+ flag: "from --executor",
12385
+ existing: "kept from your existing config",
12386
+ default: "the default"
12387
+ };
12241
12388
  function mergedExecutorConfigs(config, subject) {
12242
12389
  const user = config.executors;
12243
12390
  const defaults = subject.brand.executorDefaults;
@@ -12277,1514 +12424,967 @@ var require_typed_exit = __commonJS({
12277
12424
  }
12278
12425
  });
12279
12426
 
12280
- // ../../packages/jobs/dist/response.js
12281
- var require_response = __commonJS({
12282
- "../../packages/jobs/dist/response.js"(exports2) {
12427
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
12428
+ var require_identity = __commonJS({
12429
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js"(exports2) {
12283
12430
  "use strict";
12284
- Object.defineProperty(exports2, "__esModule", { value: true });
12285
- exports2.NonJsonResponseError = exports2.ServiceUnavailableError = void 0;
12286
- exports2.readJsonResponse = readJsonResponse;
12287
- var EXCERPT_LIMIT = 120;
12288
- var UNAVAILABLE_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
12289
- var UnreadableResponseError = class extends Error {
12290
- host;
12291
- statusCode;
12292
- statusText;
12293
- contentType;
12294
- bodyExcerpt;
12295
- constructor(message, detail) {
12296
- super(message);
12297
- this.host = detail.host;
12298
- this.statusCode = detail.statusCode;
12299
- this.statusText = detail.statusText;
12300
- this.contentType = detail.contentType;
12301
- this.bodyExcerpt = detail.bodyExcerpt;
12302
- }
12303
- };
12304
- var ServiceUnavailableError = class extends UnreadableResponseError {
12305
- code = "SERVICE_UNAVAILABLE";
12306
- constructor(detail) {
12307
- super(`${detail.host} answered ${formatStatus(detail)} (content-type: ${detail.contentType ?? "none"})${detail.bodyExcerpt ? `: ${detail.bodyExcerpt}` : ""}`, detail);
12308
- this.name = "ServiceUnavailableError";
12309
- }
12310
- };
12311
- exports2.ServiceUnavailableError = ServiceUnavailableError;
12312
- var NonJsonResponseError = class extends UnreadableResponseError {
12313
- code = "RESPONSE_NOT_JSON";
12314
- constructor(detail) {
12315
- super(`${detail.host} answered ${formatStatus(detail)} with content-type ${detail.contentType ?? "none"}, not JSON${detail.bodyExcerpt ? `: ${detail.bodyExcerpt}` : ""}`, detail);
12316
- this.name = "NonJsonResponseError";
12317
- }
12318
- };
12319
- exports2.NonJsonResponseError = NonJsonResponseError;
12320
- function formatStatus(detail) {
12321
- return detail.statusText ? `${detail.statusCode} ${detail.statusText}` : `${detail.statusCode}`;
12322
- }
12323
- function isJson(contentType) {
12324
- if (!contentType)
12325
- return false;
12326
- const essence = contentType.split(";")[0].trim().toLowerCase();
12327
- return essence === "application/json" || essence.endsWith("+json");
12328
- }
12329
- function excerpt(body) {
12330
- const collapsed = body.replace(/\s+/g, " ").trim();
12331
- return collapsed.length > EXCERPT_LIMIT ? `${collapsed.slice(0, EXCERPT_LIMIT)}...` : collapsed;
12332
- }
12333
- function hostOf(url) {
12334
- try {
12335
- return new URL(url).host;
12336
- } catch {
12337
- return url;
12338
- }
12431
+ var ALIAS = Symbol.for("yaml.alias");
12432
+ var DOC = Symbol.for("yaml.document");
12433
+ var MAP = Symbol.for("yaml.map");
12434
+ var PAIR = Symbol.for("yaml.pair");
12435
+ var SCALAR = Symbol.for("yaml.scalar");
12436
+ var SEQ = Symbol.for("yaml.seq");
12437
+ var NODE_TYPE = Symbol.for("yaml.node.type");
12438
+ var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
12439
+ var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
12440
+ var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
12441
+ var isPair = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === PAIR;
12442
+ var isScalar = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SCALAR;
12443
+ var isSeq = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SEQ;
12444
+ function isCollection(node) {
12445
+ if (node && typeof node === "object")
12446
+ switch (node[NODE_TYPE]) {
12447
+ case MAP:
12448
+ case SEQ:
12449
+ return true;
12450
+ }
12451
+ return false;
12339
12452
  }
12340
- async function readJsonResponse(response, url) {
12341
- const contentType = response.headers.get("content-type");
12342
- const unavailable = UNAVAILABLE_STATUSES.has(response.status);
12343
- if (unavailable || !isJson(contentType)) {
12344
- const body = await response.text().catch(() => "");
12345
- const detail = {
12346
- host: hostOf(url),
12347
- statusCode: response.status,
12348
- statusText: response.statusText ?? "",
12349
- contentType,
12350
- bodyExcerpt: excerpt(body)
12351
- };
12352
- throw unavailable ? new ServiceUnavailableError(detail) : new NonJsonResponseError(detail);
12353
- }
12354
- return await response.json();
12453
+ function isNode(node) {
12454
+ if (node && typeof node === "object")
12455
+ switch (node[NODE_TYPE]) {
12456
+ case ALIAS:
12457
+ case MAP:
12458
+ case SCALAR:
12459
+ case SEQ:
12460
+ return true;
12461
+ }
12462
+ return false;
12355
12463
  }
12464
+ var hasAnchor = (node) => (isScalar(node) || isCollection(node)) && !!node.anchor;
12465
+ exports2.ALIAS = ALIAS;
12466
+ exports2.DOC = DOC;
12467
+ exports2.MAP = MAP;
12468
+ exports2.NODE_TYPE = NODE_TYPE;
12469
+ exports2.PAIR = PAIR;
12470
+ exports2.SCALAR = SCALAR;
12471
+ exports2.SEQ = SEQ;
12472
+ exports2.hasAnchor = hasAnchor;
12473
+ exports2.isAlias = isAlias;
12474
+ exports2.isCollection = isCollection;
12475
+ exports2.isDocument = isDocument;
12476
+ exports2.isMap = isMap;
12477
+ exports2.isNode = isNode;
12478
+ exports2.isPair = isPair;
12479
+ exports2.isScalar = isScalar;
12480
+ exports2.isSeq = isSeq;
12356
12481
  }
12357
12482
  });
12358
12483
 
12359
- // ../../packages/jobs/dist/client.js
12360
- var require_client2 = __commonJS({
12361
- "../../packages/jobs/dist/client.js"(exports2) {
12484
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/visit.js
12485
+ var require_visit = __commonJS({
12486
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/visit.js"(exports2) {
12362
12487
  "use strict";
12363
- Object.defineProperty(exports2, "__esModule", { value: true });
12364
- exports2.JobsClient = void 0;
12365
- var response_1 = require_response();
12366
- var JobsClient = class {
12367
- baseUrl;
12368
- apiKey;
12369
- accessToken;
12370
- getAccessToken;
12371
- onResponse;
12372
- constructor(config) {
12373
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
12374
- this.apiKey = config.apiKey;
12375
- this.accessToken = config.accessToken;
12376
- this.getAccessToken = config.getAccessToken;
12377
- this.onResponse = config.onResponse;
12378
- }
12379
- /**
12380
- * Headers for one request. The auth header is resolved per call so a
12381
- * long-lived client picks up a refreshed token from `getAccessToken`
12382
- * (the manager behind it re-mints before expiry) instead of pinning the
12383
- * token it happened to hold at construction.
12384
- */
12385
- async buildHeaders(forceRefresh = false) {
12386
- const headers = { "Content-Type": "application/json" };
12387
- if (this.apiKey) {
12388
- headers["X-API-Key"] = this.apiKey;
12389
- } else if (this.getAccessToken) {
12390
- const token = await this.getAccessToken({ forceRefresh });
12391
- if (token)
12392
- headers["Authorization"] = `Bearer ${token}`;
12393
- } else if (this.accessToken) {
12394
- headers["Authorization"] = `Bearer ${this.accessToken}`;
12395
- }
12396
- return headers;
12488
+ var identity = require_identity();
12489
+ var BREAK = Symbol("break visit");
12490
+ var SKIP = Symbol("skip children");
12491
+ var REMOVE = Symbol("remove node");
12492
+ function visit(node, visitor) {
12493
+ const visitor_ = initVisitor(visitor);
12494
+ if (identity.isDocument(node)) {
12495
+ const cd = visit_(null, node.contents, visitor_, Object.freeze([node]));
12496
+ if (cd === REMOVE)
12497
+ node.contents = null;
12498
+ } else
12499
+ visit_(null, node, visitor_, Object.freeze([]));
12500
+ }
12501
+ visit.BREAK = BREAK;
12502
+ visit.SKIP = SKIP;
12503
+ visit.REMOVE = REMOVE;
12504
+ function visit_(key, node, visitor, path) {
12505
+ const ctrl = callVisitor(key, node, visitor, path);
12506
+ if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
12507
+ replaceNode(key, path, ctrl);
12508
+ return visit_(key, ctrl, visitor, path);
12397
12509
  }
12398
- /**
12399
- * Fetch with one auth retry. A 401 on a token-provider client usually means
12400
- * the token was invalidated server-side (Keep restart, key rotation,
12401
- * revoke-then-repair, clock skew) while the local expiry timer still thinks
12402
- * it's valid. Force a re-mint and retry once before surfacing the failure.
12403
- * `onResponse` (min-version contract) fires on the response we actually act
12404
- * on. `body` is a string, so it is safe to resend.
12405
- */
12406
- async fetchWithAuthRetry(method, url, body) {
12407
- let response = await fetch(url, { method, headers: await this.buildHeaders(), body });
12408
- if (response.status === 401 && this.getAccessToken) {
12409
- response = await fetch(url, { method, headers: await this.buildHeaders(true), body });
12510
+ if (typeof ctrl !== "symbol") {
12511
+ if (identity.isCollection(node)) {
12512
+ path = Object.freeze(path.concat(node));
12513
+ for (let i = 0; i < node.items.length; ++i) {
12514
+ const ci = visit_(i, node.items[i], visitor, path);
12515
+ if (typeof ci === "number")
12516
+ i = ci - 1;
12517
+ else if (ci === BREAK)
12518
+ return BREAK;
12519
+ else if (ci === REMOVE) {
12520
+ node.items.splice(i, 1);
12521
+ i -= 1;
12522
+ }
12523
+ }
12524
+ } else if (identity.isPair(node)) {
12525
+ path = Object.freeze(path.concat(node));
12526
+ const ck = visit_("key", node.key, visitor, path);
12527
+ if (ck === BREAK)
12528
+ return BREAK;
12529
+ else if (ck === REMOVE)
12530
+ node.key = null;
12531
+ const cv = visit_("value", node.value, visitor, path);
12532
+ if (cv === BREAK)
12533
+ return BREAK;
12534
+ else if (cv === REMOVE)
12535
+ node.value = null;
12410
12536
  }
12411
- this.onResponse?.(response);
12412
- return response;
12413
- }
12414
- // ── Job Pools ──────────────────────────────────────────────
12415
- async createJobPool(options) {
12416
- return this.request("POST", "/api/job-pools", options);
12417
- }
12418
- /**
12419
- * Idempotent upsert by `(principal_class, principal_id, name)`. When the
12420
- * pool exists, returns the existing row without modifying membership
12421
- * constraints. The Sift provisioning hook relies on this semantics.
12422
- */
12423
- async findOrCreateJobPool(options) {
12424
- return this.request("POST", "/api/job-pools?idempotent=true", options);
12425
- }
12426
- async listJobPools(filters) {
12427
- const params = new URLSearchParams();
12428
- if (filters?.principalClass)
12429
- params.set("principalClass", filters.principalClass);
12430
- if (filters?.principalId)
12431
- params.set("principalId", filters.principalId);
12432
- if (filters?.name)
12433
- params.set("name", filters.name);
12434
- const qs = params.toString();
12435
- const { pools } = await this.request("GET", `/api/job-pools${qs ? `?${qs}` : ""}`);
12436
- return pools;
12437
12537
  }
12438
- async getJobPool(poolId) {
12439
- return this.request("GET", `/api/job-pools/${poolId}`);
12538
+ return ctrl;
12539
+ }
12540
+ async function visitAsync(node, visitor) {
12541
+ const visitor_ = initVisitor(visitor);
12542
+ if (identity.isDocument(node)) {
12543
+ const cd = await visitAsync_(null, node.contents, visitor_, Object.freeze([node]));
12544
+ if (cd === REMOVE)
12545
+ node.contents = null;
12546
+ } else
12547
+ await visitAsync_(null, node, visitor_, Object.freeze([]));
12548
+ }
12549
+ visitAsync.BREAK = BREAK;
12550
+ visitAsync.SKIP = SKIP;
12551
+ visitAsync.REMOVE = REMOVE;
12552
+ async function visitAsync_(key, node, visitor, path) {
12553
+ const ctrl = await callVisitor(key, node, visitor, path);
12554
+ if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
12555
+ replaceNode(key, path, ctrl);
12556
+ return visitAsync_(key, ctrl, visitor, path);
12440
12557
  }
12441
- /**
12442
- * Resolve a pool by exact name. Names are unique per OWNER, not globally
12443
- * (whittlelabs#763), and this method lists without a principal filter, so
12444
- * the same name can legitimately come back under several owners. That
12445
- * reference is inherently ambiguous — and silently picking one (the old
12446
- * behavior took the server's newest-first ordering) is exactly the
12447
- * capture vector the per-owner constraint closed, re-opened cross-owner.
12448
- * So it refuses instead: reference the pool by id, or list with explicit
12449
- * principal filters, when more than one owner holds the name.
12450
- */
12451
- async resolveJobPoolByName(name) {
12452
- const pools = await this.listJobPools({ name });
12453
- const matches = pools.filter((p) => p.name === name);
12454
- const owners = new Set(matches.map((p) => `${p.principalClass ?? ""}/${p.principalId ?? ""}`));
12455
- if (owners.size > 1) {
12456
- const error = new Error(`Job pool name "${name}" is ambiguous: ${matches.length} pools under ${owners.size} different owners hold it. Reference the pool by id, or resolve it with explicit principal filters (listJobPools).`);
12457
- error.code = "JOB_POOL_NAME_AMBIGUOUS";
12458
- throw error;
12558
+ if (typeof ctrl !== "symbol") {
12559
+ if (identity.isCollection(node)) {
12560
+ path = Object.freeze(path.concat(node));
12561
+ for (let i = 0; i < node.items.length; ++i) {
12562
+ const ci = await visitAsync_(i, node.items[i], visitor, path);
12563
+ if (typeof ci === "number")
12564
+ i = ci - 1;
12565
+ else if (ci === BREAK)
12566
+ return BREAK;
12567
+ else if (ci === REMOVE) {
12568
+ node.items.splice(i, 1);
12569
+ i -= 1;
12570
+ }
12571
+ }
12572
+ } else if (identity.isPair(node)) {
12573
+ path = Object.freeze(path.concat(node));
12574
+ const ck = await visitAsync_("key", node.key, visitor, path);
12575
+ if (ck === BREAK)
12576
+ return BREAK;
12577
+ else if (ck === REMOVE)
12578
+ node.key = null;
12579
+ const cv = await visitAsync_("value", node.value, visitor, path);
12580
+ if (cv === BREAK)
12581
+ return BREAK;
12582
+ else if (cv === REMOVE)
12583
+ node.value = null;
12459
12584
  }
12460
- return matches[0];
12461
12585
  }
12462
- /** Internal: resolve a `PoolRef` to a pool id. */
12463
- async resolvePoolRef(ref) {
12464
- if ("id" in ref)
12465
- return ref.id;
12466
- const pool = await this.resolveJobPoolByName(ref.name);
12467
- if (!pool)
12468
- throw new Error(`Job pool not found by name: "${ref.name}"`);
12469
- return pool.id;
12586
+ return ctrl;
12587
+ }
12588
+ function initVisitor(visitor) {
12589
+ if (typeof visitor === "object" && (visitor.Collection || visitor.Node || visitor.Value)) {
12590
+ return Object.assign({
12591
+ Alias: visitor.Node,
12592
+ Map: visitor.Node,
12593
+ Scalar: visitor.Node,
12594
+ Seq: visitor.Node
12595
+ }, visitor.Value && {
12596
+ Map: visitor.Value,
12597
+ Scalar: visitor.Value,
12598
+ Seq: visitor.Value
12599
+ }, visitor.Collection && {
12600
+ Map: visitor.Collection,
12601
+ Seq: visitor.Collection
12602
+ }, visitor);
12470
12603
  }
12471
- // ── Members ──────────────────────────────────────────────────────
12472
- // A subscriber joins a pool by registering as a member of it. These
12473
- // map to the server's `/api/job-pools/:poolId/members` routes.
12474
- async listMembers(poolId) {
12475
- const { members } = await this.request("GET", `/api/job-pools/${poolId}/members`);
12476
- return members;
12604
+ return visitor;
12605
+ }
12606
+ function callVisitor(key, node, visitor, path) {
12607
+ if (typeof visitor === "function")
12608
+ return visitor(key, node, path);
12609
+ if (identity.isMap(node))
12610
+ return visitor.Map?.(key, node, path);
12611
+ if (identity.isSeq(node))
12612
+ return visitor.Seq?.(key, node, path);
12613
+ if (identity.isPair(node))
12614
+ return visitor.Pair?.(key, node, path);
12615
+ if (identity.isScalar(node))
12616
+ return visitor.Scalar?.(key, node, path);
12617
+ if (identity.isAlias(node))
12618
+ return visitor.Alias?.(key, node, path);
12619
+ return void 0;
12620
+ }
12621
+ function replaceNode(key, path, node) {
12622
+ const parent = path[path.length - 1];
12623
+ if (identity.isCollection(parent)) {
12624
+ parent.items[key] = node;
12625
+ } else if (identity.isPair(parent)) {
12626
+ if (key === "key")
12627
+ parent.key = node;
12628
+ else
12629
+ parent.value = node;
12630
+ } else if (identity.isDocument(parent)) {
12631
+ parent.contents = node;
12632
+ } else {
12633
+ const pt = identity.isAlias(parent) ? "alias" : "scalar";
12634
+ throw new Error(`Cannot replace node with ${pt} parent`);
12477
12635
  }
12478
- async registerMember(poolId, options) {
12479
- return this.request("POST", `/api/job-pools/${poolId}/members`, options);
12636
+ }
12637
+ exports2.visit = visit;
12638
+ exports2.visitAsync = visitAsync;
12639
+ }
12640
+ });
12641
+
12642
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/directives.js
12643
+ var require_directives = __commonJS({
12644
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/directives.js"(exports2) {
12645
+ "use strict";
12646
+ var identity = require_identity();
12647
+ var visit = require_visit();
12648
+ var escapeChars = {
12649
+ "!": "%21",
12650
+ ",": "%2C",
12651
+ "[": "%5B",
12652
+ "]": "%5D",
12653
+ "{": "%7B",
12654
+ "}": "%7D"
12655
+ };
12656
+ var escapeTagName = (tn) => tn.replace(/[!,[\]{}]/g, (ch) => escapeChars[ch]);
12657
+ var Directives = class _Directives {
12658
+ constructor(yaml, tags) {
12659
+ this.docStart = null;
12660
+ this.docEnd = false;
12661
+ this.yaml = Object.assign({}, _Directives.defaultYaml, yaml);
12662
+ this.tags = Object.assign({}, _Directives.defaultTags, tags);
12480
12663
  }
12481
- async updateMember(poolId, memberId, options) {
12482
- return this.request("PUT", `/api/job-pools/${poolId}/members/${memberId}`, options);
12664
+ clone() {
12665
+ const copy = new _Directives(this.yaml, this.tags);
12666
+ copy.docStart = this.docStart;
12667
+ return copy;
12483
12668
  }
12484
- // ── Jobs (producer) ──────────────────────────────────────────────
12485
12669
  /**
12486
- * Enqueue a job into a job pool. The `inputs` are opaque to Jobs; a Shuttle
12487
- * reads the strategy header inside them to decide how to run it (ADR 0005).
12670
+ * During parsing, get a Directives instance for the current document and
12671
+ * update the stream state according to the current version's spec.
12488
12672
  */
12489
- async enqueueJob(options) {
12490
- const jobPoolId = await this.resolvePoolRef(options.pool);
12491
- const body = {
12492
- jobPoolId,
12493
- title: options.title,
12494
- instructions: options.instructions,
12495
- maxAttempts: options.maxAttempts,
12496
- deadlineDuration: options.deadlineDuration,
12497
- claimDeadlineDuration: options.claimDeadlineDuration,
12498
- priority: options.priority,
12499
- tags: options.tags,
12500
- clientRef: options.clientRef,
12501
- clientContext: options.clientContext,
12502
- inputs: options.inputs
12503
- };
12504
- return this.request("POST", "/api/jobs", body);
12505
- }
12506
- async getJob(jobId) {
12507
- return this.request("GET", `/api/jobs/${jobId}`);
12508
- }
12509
- async updateJob(jobId, options) {
12510
- return this.request("PATCH", `/api/jobs/${jobId}`, options);
12511
- }
12512
- async cancelJob(jobId) {
12513
- return this.request("PUT", `/api/jobs/${jobId}`);
12514
- }
12515
- // ── Outputs ──────────────────────────────────────────────────────
12516
- async listOutputs(jobId) {
12517
- const all = [];
12518
- const pageSize = 100;
12519
- for (let offset = 0; ; offset += pageSize) {
12520
- const { outputs, total } = await this.request("GET", `/api/jobs/${jobId}/output?limit=${pageSize}&offset=${offset}`);
12521
- all.push(...outputs);
12522
- if (outputs.length === 0 || all.length >= total)
12523
- break;
12524
- }
12525
- return all;
12526
- }
12527
- async createOutput(jobId, options) {
12528
- return this.request("POST", `/api/jobs/${jobId}/output`, options);
12673
+ atDocument() {
12674
+ const res = new _Directives(this.yaml, this.tags);
12675
+ switch (this.yaml.version) {
12676
+ case "1.1":
12677
+ this.atNextDocument = true;
12678
+ break;
12679
+ case "1.2":
12680
+ this.atNextDocument = false;
12681
+ this.yaml = {
12682
+ explicit: _Directives.defaultYaml.explicit,
12683
+ version: "1.2"
12684
+ };
12685
+ this.tags = Object.assign({}, _Directives.defaultTags);
12686
+ break;
12687
+ }
12688
+ return res;
12529
12689
  }
12530
12690
  /**
12531
- * Post a batch of live progress frames for a running job. Best-effort
12532
- * telemetry: the service publishes it over core NATS and never derives
12533
- * authoritative state from it, so callers should swallow failures rather than
12534
- * let a dropped frame affect the job.
12691
+ * @param onError - May be called even if the action was successful
12692
+ * @returns `true` on success
12535
12693
  */
12536
- async postProgress(jobId, options) {
12537
- await this.request("POST", `/api/jobs/${jobId}/progress`, options);
12694
+ add(line, onError) {
12695
+ if (this.atNextDocument) {
12696
+ this.yaml = { explicit: _Directives.defaultYaml.explicit, version: "1.1" };
12697
+ this.tags = Object.assign({}, _Directives.defaultTags);
12698
+ this.atNextDocument = false;
12699
+ }
12700
+ const parts = line.trim().split(/[ \t]+/);
12701
+ const name = parts.shift();
12702
+ switch (name) {
12703
+ case "%TAG": {
12704
+ if (parts.length !== 2) {
12705
+ onError(0, "%TAG directive should contain exactly two parts");
12706
+ if (parts.length < 2)
12707
+ return false;
12708
+ }
12709
+ const [handle, prefix] = parts;
12710
+ this.tags[handle] = prefix;
12711
+ return true;
12712
+ }
12713
+ case "%YAML": {
12714
+ this.yaml.explicit = true;
12715
+ if (parts.length !== 1) {
12716
+ onError(0, "%YAML directive should contain exactly one part");
12717
+ return false;
12718
+ }
12719
+ const [version] = parts;
12720
+ if (version === "1.1" || version === "1.2") {
12721
+ this.yaml.version = version;
12722
+ return true;
12723
+ } else {
12724
+ const isValid = /^\d+\.\d+$/.test(version);
12725
+ onError(6, `Unsupported YAML version ${version}`, isValid);
12726
+ return false;
12727
+ }
12728
+ }
12729
+ default:
12730
+ onError(0, `Unknown directive ${name}`, true);
12731
+ return false;
12732
+ }
12538
12733
  }
12539
- // ── Attendance (subscriber dispatch lifecycle) ───────────────────
12540
12734
  /**
12541
- * Accept a dispatched job. The subscribe loop calls this; direct
12542
- * callers should be rare. Returns the dispatched-job context the
12543
- * subscriber needs to execute and submit.
12735
+ * Resolves a tag, matching handles to those defined in %TAG directives.
12736
+ *
12737
+ * @returns Resolved tag, which may also be the non-specific tag `'!'` or a
12738
+ * `'!local'` tag, or `null` if unresolvable.
12544
12739
  */
12545
- async acceptDispatch(jobId) {
12546
- return this.request("POST", `/api/jobs/${jobId}/attendance`);
12547
- }
12548
- async submit(jobId, options) {
12549
- return this.request("PUT", `/api/jobs/${jobId}/attendance`, options);
12550
- }
12551
- // ── Discovery (rare) ─────────────────────────────────────────────
12552
- async listDispatchableJobs(options) {
12553
- const params = new URLSearchParams();
12554
- if (options?.pools?.length)
12555
- params.set("pools", options.pools.join(","));
12556
- if (options?.tags?.length)
12557
- params.set("tags", options.tags.join(","));
12558
- if (options?.maxAttempts !== void 0)
12559
- params.set("maxAttempts", String(options.maxAttempts));
12560
- if (options?.minPriority !== void 0)
12561
- params.set("minPriority", String(options.minPriority));
12562
- if (options?.limit !== void 0)
12563
- params.set("limit", String(options.limit));
12564
- if (options?.offset !== void 0)
12565
- params.set("offset", String(options.offset));
12566
- if (options?.sort)
12567
- params.set("sort", options.sort);
12568
- const qs = params.toString();
12569
- const { jobs, total, directives } = await this.request("GET", `/api/my/jobs${qs ? `?${qs}` : ""}`);
12570
- return {
12571
- data: jobs,
12572
- pagination: { total, limit: options?.limit ?? 25, offset: options?.offset ?? 0 },
12573
- directives: directives ?? null
12574
- };
12740
+ tagName(source, onError) {
12741
+ if (source === "!")
12742
+ return "!";
12743
+ if (source[0] !== "!") {
12744
+ onError(`Not a valid tag: ${source}`);
12745
+ return null;
12746
+ }
12747
+ if (source[1] === "<") {
12748
+ const verbatim = source.slice(2, -1);
12749
+ if (verbatim === "!" || verbatim === "!!") {
12750
+ onError(`Verbatim tags aren't resolved, so ${source} is invalid.`);
12751
+ return null;
12752
+ }
12753
+ if (source[source.length - 1] !== ">")
12754
+ onError("Verbatim tags must end with a >");
12755
+ return verbatim;
12756
+ }
12757
+ const [, handle, suffix] = source.match(/^(.*!)([^!]*)$/s);
12758
+ if (!suffix)
12759
+ onError(`The ${source} tag has no suffix`);
12760
+ const prefix = this.tags[handle];
12761
+ if (prefix) {
12762
+ try {
12763
+ return prefix + decodeURIComponent(suffix);
12764
+ } catch (error) {
12765
+ onError(String(error));
12766
+ return null;
12767
+ }
12768
+ }
12769
+ if (handle === "!")
12770
+ return source;
12771
+ onError(`Could not resolve tag: ${source}`);
12772
+ return null;
12575
12773
  }
12576
- // ── HTTP plumbing ────────────────────────────────────────────────
12577
12774
  /**
12578
- * Every call's one reader. `readJsonResponse` refuses to parse a reply that
12579
- * is not the API's JSON — an ingress 502/503/504 while a pod rolls, or any
12580
- * non-JSON body — and throws a named failure instead of a parse error. What
12581
- * comes back here is the API's own envelope, success or not.
12775
+ * Given a fully resolved tag, returns its printable string form,
12776
+ * taking into account current tag prefixes and defaults.
12582
12777
  */
12583
- async request(method, path, body) {
12584
- const url = `${this.baseUrl}${path}`;
12585
- const response = await this.fetchWithAuthRetry(method, url, body ? JSON.stringify(body) : void 0);
12586
- const json = await (0, response_1.readJsonResponse)(response, url);
12587
- if (!response.ok || !json.success) {
12588
- const errorMessage = json.error?.message ?? `Request failed with status ${response.status}`;
12589
- const error = new Error(errorMessage);
12590
- error.code = json.error?.code;
12591
- error.statusCode = response.status;
12592
- throw error;
12778
+ tagString(tag) {
12779
+ for (const [handle, prefix] of Object.entries(this.tags)) {
12780
+ if (tag.startsWith(prefix))
12781
+ return handle + escapeTagName(tag.substring(prefix.length));
12593
12782
  }
12594
- return json.data;
12783
+ return tag[0] === "!" ? tag : `!<${tag}>`;
12784
+ }
12785
+ toString(doc) {
12786
+ const lines = this.yaml.explicit ? [`%YAML ${this.yaml.version || "1.2"}`] : [];
12787
+ const tagEntries = Object.entries(this.tags);
12788
+ let tagNames;
12789
+ if (doc && tagEntries.length > 0 && identity.isNode(doc.contents)) {
12790
+ const tags = {};
12791
+ visit.visit(doc.contents, (_key, node) => {
12792
+ if (identity.isNode(node) && node.tag)
12793
+ tags[node.tag] = true;
12794
+ });
12795
+ tagNames = Object.keys(tags);
12796
+ } else
12797
+ tagNames = [];
12798
+ for (const [handle, prefix] of tagEntries) {
12799
+ if (handle === "!!" && prefix === "tag:yaml.org,2002:")
12800
+ continue;
12801
+ if (!doc || tagNames.some((tn) => tn.startsWith(prefix)))
12802
+ lines.push(`%TAG ${handle} ${prefix}`);
12803
+ }
12804
+ return lines.join("\n");
12595
12805
  }
12596
12806
  };
12597
- exports2.JobsClient = JobsClient;
12807
+ Directives.defaultYaml = { explicit: false, version: "1.2" };
12808
+ Directives.defaultTags = { "!!": "tag:yaml.org,2002:" };
12809
+ exports2.Directives = Directives;
12598
12810
  }
12599
12811
  });
12600
12812
 
12601
- // ../../packages/jobs/dist/subscribe.js
12602
- var require_subscribe = __commonJS({
12603
- "../../packages/jobs/dist/subscribe.js"(exports2) {
12813
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/anchors.js
12814
+ var require_anchors = __commonJS({
12815
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/anchors.js"(exports2) {
12604
12816
  "use strict";
12605
- Object.defineProperty(exports2, "__esModule", { value: true });
12606
- exports2.subscribe = subscribe;
12607
- var response_1 = require_response();
12608
- var NULL_LOGGER = {
12609
- debug: () => {
12610
- },
12611
- info: () => {
12612
- },
12613
- warn: () => {
12614
- },
12615
- error: () => {
12817
+ var identity = require_identity();
12818
+ var visit = require_visit();
12819
+ function anchorIsValid(anchor) {
12820
+ if (/[\x00-\x19\s,[\]{}]/.test(anchor)) {
12821
+ const sa = JSON.stringify(anchor);
12822
+ const msg = `Anchor must not contain whitespace or control characters: ${sa}`;
12823
+ throw new Error(msg);
12616
12824
  }
12617
- };
12618
- function sleep(ms) {
12619
- return new Promise((resolve) => setTimeout(resolve, ms));
12620
- }
12621
- function formatDuration(ms) {
12622
- const seconds = Math.round(ms / 1e3);
12623
- if (seconds < 60)
12624
- return `${seconds}s`;
12625
- const minutes = Math.floor(seconds / 60);
12626
- const rest = seconds % 60;
12627
- return rest === 0 ? `${minutes}m` : `${minutes}m ${rest}s`;
12825
+ return true;
12628
12826
  }
12629
- function subscribe(opts) {
12630
- const logger = opts.logger ?? NULL_LOGGER;
12631
- const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
12632
- const maxConcurrency = opts.maxConcurrency ?? 1;
12633
- let stopped = true;
12634
- let pollTimer = null;
12635
- let inflight = 0;
12636
- let resolvedPoolIds = [];
12637
- let unavailableSince = null;
12638
- async function start() {
12639
- if (!stopped)
12640
- return;
12641
- stopped = false;
12642
- resolvedPoolIds = [];
12643
- for (const ref of opts.pools) {
12644
- const id = await opts.jobsClient.resolvePoolRef(ref);
12645
- resolvedPoolIds.push(id);
12646
- await opts.jobsClient.registerMember(id, {
12647
- identityType: opts.subscriber.identityType,
12648
- identityId: opts.subscriber.identityId,
12649
- intelligence: opts.subscriber.intelligence,
12650
- ...opts.subscriber.displayName !== void 0 ? { displayName: opts.subscriber.displayName } : {},
12651
- ...opts.subscriber.metadata !== void 0 ? { metadata: opts.subscriber.metadata } : {}
12652
- });
12827
+ function anchorNames(root) {
12828
+ const anchors = /* @__PURE__ */ new Set();
12829
+ visit.visit(root, {
12830
+ Value(_key, node) {
12831
+ if (node.anchor)
12832
+ anchors.add(node.anchor);
12653
12833
  }
12654
- logger.info("subscribe loop started", { pools: resolvedPoolIds, maxConcurrency });
12655
- schedulePoll(pollIntervalMs);
12656
- }
12657
- async function stop() {
12658
- if (stopped)
12659
- return;
12660
- stopped = true;
12661
- if (pollTimer !== null) {
12662
- clearTimeout(pollTimer);
12663
- pollTimer = null;
12664
- }
12665
- while (inflight > 0) {
12666
- await sleep(100);
12667
- }
12668
- logger.info("subscribe loop stopped");
12669
- }
12670
- function schedulePoll(delayMs) {
12671
- pollTimer = setTimeout(() => {
12672
- void poll();
12673
- }, delayMs);
12834
+ });
12835
+ return anchors;
12836
+ }
12837
+ function findNewAnchor(prefix, exclude) {
12838
+ for (let i = 1; true; ++i) {
12839
+ const name = `${prefix}${i}`;
12840
+ if (!exclude.has(name))
12841
+ return name;
12674
12842
  }
12675
- async function poll() {
12676
- if (stopped)
12677
- return;
12678
- if (inflight >= maxConcurrency) {
12679
- schedulePoll(pollIntervalMs);
12680
- return;
12681
- }
12682
- try {
12683
- const { data, directives } = await opts.jobsClient.listDispatchableJobs({
12684
- pools: resolvedPoolIds,
12685
- limit: maxConcurrency - inflight,
12686
- sort: "priority:desc,queued_at:asc"
12687
- });
12688
- if (unavailableSince !== null) {
12689
- logger.info(`Sift is reachable again after ${formatDuration(Date.now() - unavailableSince)}`);
12690
- unavailableSince = null;
12691
- }
12692
- if (directives && Object.keys(directives).length > 0 && opts.onDirectives) {
12693
- try {
12694
- await opts.onDirectives(directives);
12695
- } catch (err) {
12696
- logger.error("onDirectives handler failed", {
12697
- error: err instanceof Error ? err.message : String(err)
12698
- });
12699
- }
12700
- }
12701
- if (stopped)
12702
- return;
12703
- for (const job of data) {
12704
- if (inflight >= maxConcurrency)
12705
- break;
12706
- inflight++;
12707
- void runOnce(job).finally(() => {
12708
- inflight--;
12709
- });
12710
- }
12711
- } catch (err) {
12712
- if (err instanceof response_1.ServiceUnavailableError) {
12713
- if (unavailableSince === null) {
12714
- unavailableSince = Date.now();
12715
- logger.warn(`Sift is unavailable (${err.host} answered ${err.statusCode}${err.statusText ? ` ${err.statusText}` : ""}). This is typical during a deployment window; the Sifter will keep trying.`);
12843
+ }
12844
+ function createNodeAnchors(doc, prefix) {
12845
+ const aliasObjects = [];
12846
+ const sourceObjects = /* @__PURE__ */ new Map();
12847
+ let prevAnchors = null;
12848
+ return {
12849
+ onAnchor: (source) => {
12850
+ aliasObjects.push(source);
12851
+ prevAnchors ?? (prevAnchors = anchorNames(doc));
12852
+ const anchor = findNewAnchor(prefix, prevAnchors);
12853
+ prevAnchors.add(anchor);
12854
+ return anchor;
12855
+ },
12856
+ /**
12857
+ * With circular references, the source node is only resolved after all
12858
+ * of its child nodes are. This is why anchors are set only after all of
12859
+ * the nodes have been created.
12860
+ */
12861
+ setAnchors: () => {
12862
+ for (const source of aliasObjects) {
12863
+ const ref = sourceObjects.get(source);
12864
+ if (typeof ref === "object" && ref.anchor && (identity.isScalar(ref.node) || identity.isCollection(ref.node))) {
12865
+ ref.node.anchor = ref.anchor;
12716
12866
  } else {
12717
- logger.debug?.("Sift still unavailable", {
12718
- host: err.host,
12719
- status: err.statusCode,
12720
- unavailableFor: formatDuration(Date.now() - unavailableSince)
12721
- });
12867
+ const error = new Error("Failed to resolve repeated object (this should not happen)");
12868
+ error.source = source;
12869
+ throw error;
12722
12870
  }
12723
- } else {
12724
- logger.error("poll failed", { error: err instanceof Error ? err.message : String(err) });
12725
12871
  }
12726
- }
12727
- if (!stopped)
12728
- schedulePoll(pollIntervalMs);
12729
- }
12730
- async function runOnce(available) {
12731
- let dispatch;
12732
- try {
12733
- dispatch = await opts.jobsClient.acceptDispatch(available.id);
12734
- } catch (err) {
12735
- const statusCode = err.statusCode;
12736
- if (statusCode === 409) {
12737
- logger.debug?.("claim conflict; another member accepted", { jobId: available.id });
12738
- return;
12872
+ },
12873
+ sourceObjects
12874
+ };
12875
+ }
12876
+ exports2.anchorIsValid = anchorIsValid;
12877
+ exports2.anchorNames = anchorNames;
12878
+ exports2.createNodeAnchors = createNodeAnchors;
12879
+ exports2.findNewAnchor = findNewAnchor;
12880
+ }
12881
+ });
12882
+
12883
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/applyReviver.js
12884
+ var require_applyReviver = __commonJS({
12885
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/applyReviver.js"(exports2) {
12886
+ "use strict";
12887
+ function applyReviver(reviver, obj, key, val) {
12888
+ if (val && typeof val === "object") {
12889
+ if (Array.isArray(val)) {
12890
+ for (let i = 0, len = val.length; i < len; ++i) {
12891
+ const v0 = val[i];
12892
+ const v1 = applyReviver(reviver, val, String(i), v0);
12893
+ if (v1 === void 0)
12894
+ delete val[i];
12895
+ else if (v1 !== v0)
12896
+ val[i] = v1;
12739
12897
  }
12740
- logger.error("failed to accept dispatch", {
12741
- jobId: available.id,
12742
- error: err instanceof Error ? err.message : String(err)
12743
- });
12744
- return;
12745
- }
12746
- const controller = new AbortController();
12747
- let quietTimer = null;
12748
- const quietWindowMs = dispatch.deadline ? new Date(dispatch.deadline).getTime() - Date.now() : null;
12749
- const armQuietTimer = () => {
12750
- if (quietWindowMs === null)
12751
- return;
12752
- if (quietTimer !== null)
12753
- clearTimeout(quietTimer);
12754
- const ms = quietWindowMs - 3e4;
12755
- if (ms > 0) {
12756
- quietTimer = setTimeout(() => controller.abort(), ms);
12757
- } else {
12758
- controller.abort();
12898
+ } else if (val instanceof Map) {
12899
+ for (const k of Array.from(val.keys())) {
12900
+ const v0 = val.get(k);
12901
+ const v1 = applyReviver(reviver, val, k, v0);
12902
+ if (v1 === void 0)
12903
+ val.delete(k);
12904
+ else if (v1 !== v0)
12905
+ val.set(k, v1);
12759
12906
  }
12760
- };
12761
- armQuietTimer();
12762
- const activity = {
12763
- record: () => {
12764
- if (!controller.signal.aborted)
12765
- armQuietTimer();
12907
+ } else if (val instanceof Set) {
12908
+ for (const v0 of Array.from(val)) {
12909
+ const v1 = applyReviver(reviver, val, v0, v0);
12910
+ if (v1 === void 0)
12911
+ val.delete(v0);
12912
+ else if (v1 !== v0) {
12913
+ val.delete(v0);
12914
+ val.add(v1);
12915
+ }
12766
12916
  }
12767
- };
12768
- let result;
12769
- try {
12770
- result = await opts.onJob(dispatch, controller.signal, activity);
12771
- } catch (err) {
12772
- result = {
12773
- status: "failed",
12774
- reason: `onJob threw: ${err instanceof Error ? err.message : String(err)}`
12775
- };
12776
- } finally {
12777
- if (quietTimer !== null)
12778
- clearTimeout(quietTimer);
12779
- }
12780
- try {
12781
- for (const output of result.outputs ?? []) {
12782
- await opts.jobsClient.createOutput(dispatch.job.id, {
12783
- label: output.label,
12784
- content: output.content
12785
- });
12917
+ } else {
12918
+ for (const [k, v0] of Object.entries(val)) {
12919
+ const v1 = applyReviver(reviver, val, k, v0);
12920
+ if (v1 === void 0)
12921
+ delete val[k];
12922
+ else if (v1 !== v0)
12923
+ val[k] = v1;
12786
12924
  }
12787
- await opts.jobsClient.submit(dispatch.job.id, {
12788
- status: result.status,
12789
- ...result.reason !== void 0 ? { reason: result.reason } : {}
12790
- });
12791
- } catch (err) {
12792
- logger.error("submit/close failed", {
12793
- jobId: dispatch.job.id,
12794
- error: err instanceof Error ? err.message : String(err)
12795
- });
12796
12925
  }
12797
12926
  }
12798
- return { start, stop };
12927
+ return reviver.call(obj, key, val);
12799
12928
  }
12929
+ exports2.applyReviver = applyReviver;
12800
12930
  }
12801
12931
  });
12802
12932
 
12803
- // ../../packages/jobs/dist/index.js
12804
- var require_dist3 = __commonJS({
12805
- "../../packages/jobs/dist/index.js"(exports2) {
12806
- "use strict";
12807
- Object.defineProperty(exports2, "__esModule", { value: true });
12808
- exports2.subscribe = exports2.ServiceUnavailableError = exports2.NonJsonResponseError = exports2.JobsClient = void 0;
12809
- var client_1 = require_client2();
12810
- Object.defineProperty(exports2, "JobsClient", { enumerable: true, get: function() {
12811
- return client_1.JobsClient;
12812
- } });
12813
- var response_1 = require_response();
12814
- Object.defineProperty(exports2, "NonJsonResponseError", { enumerable: true, get: function() {
12815
- return response_1.NonJsonResponseError;
12816
- } });
12817
- Object.defineProperty(exports2, "ServiceUnavailableError", { enumerable: true, get: function() {
12818
- return response_1.ServiceUnavailableError;
12819
- } });
12820
- var subscribe_1 = require_subscribe();
12821
- Object.defineProperty(exports2, "subscribe", { enumerable: true, get: function() {
12822
- return subscribe_1.subscribe;
12823
- } });
12824
- }
12825
- });
12826
-
12827
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
12828
- var require_identity = __commonJS({
12829
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js"(exports2) {
12933
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/toJS.js
12934
+ var require_toJS = __commonJS({
12935
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/toJS.js"(exports2) {
12830
12936
  "use strict";
12831
- var ALIAS = Symbol.for("yaml.alias");
12832
- var DOC = Symbol.for("yaml.document");
12833
- var MAP = Symbol.for("yaml.map");
12834
- var PAIR = Symbol.for("yaml.pair");
12835
- var SCALAR = Symbol.for("yaml.scalar");
12836
- var SEQ = Symbol.for("yaml.seq");
12837
- var NODE_TYPE = Symbol.for("yaml.node.type");
12838
- var isAlias = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === ALIAS;
12839
- var isDocument = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === DOC;
12840
- var isMap = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === MAP;
12841
- var isPair = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === PAIR;
12842
- var isScalar = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SCALAR;
12843
- var isSeq = (node) => !!node && typeof node === "object" && node[NODE_TYPE] === SEQ;
12844
- function isCollection(node) {
12845
- if (node && typeof node === "object")
12846
- switch (node[NODE_TYPE]) {
12847
- case MAP:
12848
- case SEQ:
12849
- return true;
12850
- }
12851
- return false;
12852
- }
12853
- function isNode(node) {
12854
- if (node && typeof node === "object")
12855
- switch (node[NODE_TYPE]) {
12856
- case ALIAS:
12857
- case MAP:
12858
- case SCALAR:
12859
- case SEQ:
12860
- return true;
12861
- }
12862
- return false;
12937
+ var identity = require_identity();
12938
+ function toJS(value, arg, ctx) {
12939
+ if (Array.isArray(value))
12940
+ return value.map((v, i) => toJS(v, String(i), ctx));
12941
+ if (value && typeof value.toJSON === "function") {
12942
+ if (!ctx || !identity.hasAnchor(value))
12943
+ return value.toJSON(arg, ctx);
12944
+ const data = { aliasCount: 0, count: 1, res: void 0 };
12945
+ ctx.anchors.set(value, data);
12946
+ ctx.onCreate = (res2) => {
12947
+ data.res = res2;
12948
+ delete ctx.onCreate;
12949
+ };
12950
+ const res = value.toJSON(arg, ctx);
12951
+ if (ctx.onCreate)
12952
+ ctx.onCreate(res);
12953
+ return res;
12954
+ }
12955
+ if (typeof value === "bigint" && !ctx?.keep)
12956
+ return Number(value);
12957
+ return value;
12863
12958
  }
12864
- var hasAnchor = (node) => (isScalar(node) || isCollection(node)) && !!node.anchor;
12865
- exports2.ALIAS = ALIAS;
12866
- exports2.DOC = DOC;
12867
- exports2.MAP = MAP;
12868
- exports2.NODE_TYPE = NODE_TYPE;
12869
- exports2.PAIR = PAIR;
12870
- exports2.SCALAR = SCALAR;
12871
- exports2.SEQ = SEQ;
12872
- exports2.hasAnchor = hasAnchor;
12873
- exports2.isAlias = isAlias;
12874
- exports2.isCollection = isCollection;
12875
- exports2.isDocument = isDocument;
12876
- exports2.isMap = isMap;
12877
- exports2.isNode = isNode;
12878
- exports2.isPair = isPair;
12879
- exports2.isScalar = isScalar;
12880
- exports2.isSeq = isSeq;
12959
+ exports2.toJS = toJS;
12881
12960
  }
12882
12961
  });
12883
12962
 
12884
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/visit.js
12885
- var require_visit = __commonJS({
12886
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/visit.js"(exports2) {
12963
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Node.js
12964
+ var require_Node = __commonJS({
12965
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Node.js"(exports2) {
12887
12966
  "use strict";
12967
+ var applyReviver = require_applyReviver();
12888
12968
  var identity = require_identity();
12889
- var BREAK = Symbol("break visit");
12890
- var SKIP = Symbol("skip children");
12891
- var REMOVE = Symbol("remove node");
12892
- function visit(node, visitor) {
12893
- const visitor_ = initVisitor(visitor);
12894
- if (identity.isDocument(node)) {
12895
- const cd = visit_(null, node.contents, visitor_, Object.freeze([node]));
12896
- if (cd === REMOVE)
12897
- node.contents = null;
12898
- } else
12899
- visit_(null, node, visitor_, Object.freeze([]));
12900
- }
12901
- visit.BREAK = BREAK;
12902
- visit.SKIP = SKIP;
12903
- visit.REMOVE = REMOVE;
12904
- function visit_(key, node, visitor, path) {
12905
- const ctrl = callVisitor(key, node, visitor, path);
12906
- if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
12907
- replaceNode(key, path, ctrl);
12908
- return visit_(key, ctrl, visitor, path);
12909
- }
12910
- if (typeof ctrl !== "symbol") {
12911
- if (identity.isCollection(node)) {
12912
- path = Object.freeze(path.concat(node));
12913
- for (let i = 0; i < node.items.length; ++i) {
12914
- const ci = visit_(i, node.items[i], visitor, path);
12915
- if (typeof ci === "number")
12916
- i = ci - 1;
12917
- else if (ci === BREAK)
12918
- return BREAK;
12919
- else if (ci === REMOVE) {
12920
- node.items.splice(i, 1);
12921
- i -= 1;
12922
- }
12923
- }
12924
- } else if (identity.isPair(node)) {
12925
- path = Object.freeze(path.concat(node));
12926
- const ck = visit_("key", node.key, visitor, path);
12927
- if (ck === BREAK)
12928
- return BREAK;
12929
- else if (ck === REMOVE)
12930
- node.key = null;
12931
- const cv = visit_("value", node.value, visitor, path);
12932
- if (cv === BREAK)
12933
- return BREAK;
12934
- else if (cv === REMOVE)
12935
- node.value = null;
12936
- }
12937
- }
12938
- return ctrl;
12939
- }
12940
- async function visitAsync(node, visitor) {
12941
- const visitor_ = initVisitor(visitor);
12942
- if (identity.isDocument(node)) {
12943
- const cd = await visitAsync_(null, node.contents, visitor_, Object.freeze([node]));
12944
- if (cd === REMOVE)
12945
- node.contents = null;
12946
- } else
12947
- await visitAsync_(null, node, visitor_, Object.freeze([]));
12948
- }
12949
- visitAsync.BREAK = BREAK;
12950
- visitAsync.SKIP = SKIP;
12951
- visitAsync.REMOVE = REMOVE;
12952
- async function visitAsync_(key, node, visitor, path) {
12953
- const ctrl = await callVisitor(key, node, visitor, path);
12954
- if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
12955
- replaceNode(key, path, ctrl);
12956
- return visitAsync_(key, ctrl, visitor, path);
12957
- }
12958
- if (typeof ctrl !== "symbol") {
12959
- if (identity.isCollection(node)) {
12960
- path = Object.freeze(path.concat(node));
12961
- for (let i = 0; i < node.items.length; ++i) {
12962
- const ci = await visitAsync_(i, node.items[i], visitor, path);
12963
- if (typeof ci === "number")
12964
- i = ci - 1;
12965
- else if (ci === BREAK)
12966
- return BREAK;
12967
- else if (ci === REMOVE) {
12968
- node.items.splice(i, 1);
12969
- i -= 1;
12970
- }
12971
- }
12972
- } else if (identity.isPair(node)) {
12973
- path = Object.freeze(path.concat(node));
12974
- const ck = await visitAsync_("key", node.key, visitor, path);
12975
- if (ck === BREAK)
12976
- return BREAK;
12977
- else if (ck === REMOVE)
12978
- node.key = null;
12979
- const cv = await visitAsync_("value", node.value, visitor, path);
12980
- if (cv === BREAK)
12981
- return BREAK;
12982
- else if (cv === REMOVE)
12983
- node.value = null;
12984
- }
12969
+ var toJS = require_toJS();
12970
+ var NodeBase = class {
12971
+ constructor(type) {
12972
+ Object.defineProperty(this, identity.NODE_TYPE, { value: type });
12985
12973
  }
12986
- return ctrl;
12987
- }
12988
- function initVisitor(visitor) {
12989
- if (typeof visitor === "object" && (visitor.Collection || visitor.Node || visitor.Value)) {
12990
- return Object.assign({
12991
- Alias: visitor.Node,
12992
- Map: visitor.Node,
12993
- Scalar: visitor.Node,
12994
- Seq: visitor.Node
12995
- }, visitor.Value && {
12996
- Map: visitor.Value,
12997
- Scalar: visitor.Value,
12998
- Seq: visitor.Value
12999
- }, visitor.Collection && {
13000
- Map: visitor.Collection,
13001
- Seq: visitor.Collection
13002
- }, visitor);
12974
+ /** Create a copy of this node. */
12975
+ clone() {
12976
+ const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));
12977
+ if (this.range)
12978
+ copy.range = this.range.slice();
12979
+ return copy;
13003
12980
  }
13004
- return visitor;
13005
- }
13006
- function callVisitor(key, node, visitor, path) {
13007
- if (typeof visitor === "function")
13008
- return visitor(key, node, path);
13009
- if (identity.isMap(node))
13010
- return visitor.Map?.(key, node, path);
13011
- if (identity.isSeq(node))
13012
- return visitor.Seq?.(key, node, path);
13013
- if (identity.isPair(node))
13014
- return visitor.Pair?.(key, node, path);
13015
- if (identity.isScalar(node))
13016
- return visitor.Scalar?.(key, node, path);
13017
- if (identity.isAlias(node))
13018
- return visitor.Alias?.(key, node, path);
13019
- return void 0;
13020
- }
13021
- function replaceNode(key, path, node) {
13022
- const parent = path[path.length - 1];
13023
- if (identity.isCollection(parent)) {
13024
- parent.items[key] = node;
13025
- } else if (identity.isPair(parent)) {
13026
- if (key === "key")
13027
- parent.key = node;
13028
- else
13029
- parent.value = node;
13030
- } else if (identity.isDocument(parent)) {
13031
- parent.contents = node;
13032
- } else {
13033
- const pt = identity.isAlias(parent) ? "alias" : "scalar";
13034
- throw new Error(`Cannot replace node with ${pt} parent`);
12981
+ /** A plain JavaScript representation of this node. */
12982
+ toJS(doc, { mapAsMap, maxAliasCount, onAnchor, reviver } = {}) {
12983
+ if (!identity.isDocument(doc))
12984
+ throw new TypeError("A document argument is required");
12985
+ const ctx = {
12986
+ anchors: /* @__PURE__ */ new Map(),
12987
+ doc,
12988
+ keep: true,
12989
+ mapAsMap: mapAsMap === true,
12990
+ mapKeyWarned: false,
12991
+ maxAliasCount: typeof maxAliasCount === "number" ? maxAliasCount : 100
12992
+ };
12993
+ const res = toJS.toJS(this, "", ctx);
12994
+ if (typeof onAnchor === "function")
12995
+ for (const { count, res: res2 } of ctx.anchors.values())
12996
+ onAnchor(res2, count);
12997
+ return typeof reviver === "function" ? applyReviver.applyReviver(reviver, { "": res }, "", res) : res;
13035
12998
  }
13036
- }
13037
- exports2.visit = visit;
13038
- exports2.visitAsync = visitAsync;
12999
+ };
13000
+ exports2.NodeBase = NodeBase;
13039
13001
  }
13040
13002
  });
13041
13003
 
13042
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/directives.js
13043
- var require_directives = __commonJS({
13044
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/directives.js"(exports2) {
13004
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Alias.js
13005
+ var require_Alias = __commonJS({
13006
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Alias.js"(exports2) {
13045
13007
  "use strict";
13046
- var identity = require_identity();
13008
+ var anchors = require_anchors();
13047
13009
  var visit = require_visit();
13048
- var escapeChars = {
13049
- "!": "%21",
13050
- ",": "%2C",
13051
- "[": "%5B",
13052
- "]": "%5D",
13053
- "{": "%7B",
13054
- "}": "%7D"
13055
- };
13056
- var escapeTagName = (tn) => tn.replace(/[!,[\]{}]/g, (ch) => escapeChars[ch]);
13057
- var Directives = class _Directives {
13058
- constructor(yaml, tags) {
13059
- this.docStart = null;
13060
- this.docEnd = false;
13061
- this.yaml = Object.assign({}, _Directives.defaultYaml, yaml);
13062
- this.tags = Object.assign({}, _Directives.defaultTags, tags);
13063
- }
13064
- clone() {
13065
- const copy = new _Directives(this.yaml, this.tags);
13066
- copy.docStart = this.docStart;
13067
- return copy;
13010
+ var identity = require_identity();
13011
+ var Node = require_Node();
13012
+ var toJS = require_toJS();
13013
+ var Alias = class extends Node.NodeBase {
13014
+ constructor(source) {
13015
+ super(identity.ALIAS);
13016
+ this.source = source;
13017
+ Object.defineProperty(this, "tag", {
13018
+ set() {
13019
+ throw new Error("Alias nodes cannot have tags");
13020
+ }
13021
+ });
13068
13022
  }
13069
13023
  /**
13070
- * During parsing, get a Directives instance for the current document and
13071
- * update the stream state according to the current version's spec.
13024
+ * Resolve the value of this alias within `doc`, finding the last
13025
+ * instance of the `source` anchor before this node.
13072
13026
  */
13073
- atDocument() {
13074
- const res = new _Directives(this.yaml, this.tags);
13075
- switch (this.yaml.version) {
13076
- case "1.1":
13077
- this.atNextDocument = true;
13078
- break;
13079
- case "1.2":
13080
- this.atNextDocument = false;
13081
- this.yaml = {
13082
- explicit: _Directives.defaultYaml.explicit,
13083
- version: "1.2"
13084
- };
13085
- this.tags = Object.assign({}, _Directives.defaultTags);
13027
+ resolve(doc, ctx) {
13028
+ if (ctx?.maxAliasCount === 0)
13029
+ throw new ReferenceError("Alias resolution is disabled");
13030
+ let nodes;
13031
+ if (ctx?.aliasResolveCache) {
13032
+ nodes = ctx.aliasResolveCache;
13033
+ } else {
13034
+ nodes = [];
13035
+ visit.visit(doc, {
13036
+ Node: (_key, node) => {
13037
+ if (identity.isAlias(node) || identity.hasAnchor(node))
13038
+ nodes.push(node);
13039
+ }
13040
+ });
13041
+ if (ctx)
13042
+ ctx.aliasResolveCache = nodes;
13043
+ }
13044
+ let found = void 0;
13045
+ for (const node of nodes) {
13046
+ if (node === this)
13086
13047
  break;
13048
+ if (node.anchor === this.source)
13049
+ found = node;
13087
13050
  }
13088
- return res;
13051
+ return found;
13089
13052
  }
13090
- /**
13091
- * @param onError - May be called even if the action was successful
13092
- * @returns `true` on success
13093
- */
13094
- add(line, onError) {
13095
- if (this.atNextDocument) {
13096
- this.yaml = { explicit: _Directives.defaultYaml.explicit, version: "1.1" };
13097
- this.tags = Object.assign({}, _Directives.defaultTags);
13098
- this.atNextDocument = false;
13099
- }
13100
- const parts = line.trim().split(/[ \t]+/);
13101
- const name = parts.shift();
13102
- switch (name) {
13103
- case "%TAG": {
13104
- if (parts.length !== 2) {
13105
- onError(0, "%TAG directive should contain exactly two parts");
13106
- if (parts.length < 2)
13107
- return false;
13108
- }
13109
- const [handle, prefix] = parts;
13110
- this.tags[handle] = prefix;
13111
- return true;
13112
- }
13113
- case "%YAML": {
13114
- this.yaml.explicit = true;
13115
- if (parts.length !== 1) {
13116
- onError(0, "%YAML directive should contain exactly one part");
13117
- return false;
13118
- }
13119
- const [version] = parts;
13120
- if (version === "1.1" || version === "1.2") {
13121
- this.yaml.version = version;
13122
- return true;
13123
- } else {
13124
- const isValid = /^\d+\.\d+$/.test(version);
13125
- onError(6, `Unsupported YAML version ${version}`, isValid);
13126
- return false;
13127
- }
13128
- }
13129
- default:
13130
- onError(0, `Unknown directive ${name}`, true);
13131
- return false;
13053
+ toJSON(_arg, ctx) {
13054
+ if (!ctx)
13055
+ return { source: this.source };
13056
+ const { anchors: anchors2, doc, maxAliasCount } = ctx;
13057
+ const source = this.resolve(doc, ctx);
13058
+ if (!source) {
13059
+ const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
13060
+ throw new ReferenceError(msg);
13132
13061
  }
13133
- }
13134
- /**
13135
- * Resolves a tag, matching handles to those defined in %TAG directives.
13136
- *
13137
- * @returns Resolved tag, which may also be the non-specific tag `'!'` or a
13138
- * `'!local'` tag, or `null` if unresolvable.
13139
- */
13140
- tagName(source, onError) {
13141
- if (source === "!")
13142
- return "!";
13143
- if (source[0] !== "!") {
13144
- onError(`Not a valid tag: ${source}`);
13145
- return null;
13062
+ let data = anchors2.get(source);
13063
+ if (!data) {
13064
+ toJS.toJS(source, null, ctx);
13065
+ data = anchors2.get(source);
13146
13066
  }
13147
- if (source[1] === "<") {
13148
- const verbatim = source.slice(2, -1);
13149
- if (verbatim === "!" || verbatim === "!!") {
13150
- onError(`Verbatim tags aren't resolved, so ${source} is invalid.`);
13151
- return null;
13152
- }
13153
- if (source[source.length - 1] !== ">")
13154
- onError("Verbatim tags must end with a >");
13155
- return verbatim;
13067
+ if (data?.res === void 0) {
13068
+ const msg = "This should not happen: Alias anchor was not resolved?";
13069
+ throw new ReferenceError(msg);
13156
13070
  }
13157
- const [, handle, suffix] = source.match(/^(.*!)([^!]*)$/s);
13158
- if (!suffix)
13159
- onError(`The ${source} tag has no suffix`);
13160
- const prefix = this.tags[handle];
13161
- if (prefix) {
13162
- try {
13163
- return prefix + decodeURIComponent(suffix);
13164
- } catch (error) {
13165
- onError(String(error));
13166
- return null;
13071
+ if (maxAliasCount >= 0) {
13072
+ data.count += 1;
13073
+ if (data.aliasCount === 0)
13074
+ data.aliasCount = getAliasCount(doc, source, anchors2);
13075
+ if (data.count * data.aliasCount > maxAliasCount) {
13076
+ const msg = "Excessive alias count indicates a resource exhaustion attack";
13077
+ throw new ReferenceError(msg);
13167
13078
  }
13168
13079
  }
13169
- if (handle === "!")
13170
- return source;
13171
- onError(`Could not resolve tag: ${source}`);
13172
- return null;
13080
+ return data.res;
13173
13081
  }
13174
- /**
13175
- * Given a fully resolved tag, returns its printable string form,
13176
- * taking into account current tag prefixes and defaults.
13177
- */
13178
- tagString(tag) {
13179
- for (const [handle, prefix] of Object.entries(this.tags)) {
13180
- if (tag.startsWith(prefix))
13181
- return handle + escapeTagName(tag.substring(prefix.length));
13082
+ toString(ctx, _onComment, _onChompKeep) {
13083
+ const src = `*${this.source}`;
13084
+ if (ctx) {
13085
+ anchors.anchorIsValid(this.source);
13086
+ if (ctx.options.verifyAliasOrder && !ctx.anchors.has(this.source)) {
13087
+ const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
13088
+ throw new Error(msg);
13089
+ }
13090
+ if (ctx.implicitKey)
13091
+ return `${src} `;
13182
13092
  }
13183
- return tag[0] === "!" ? tag : `!<${tag}>`;
13093
+ return src;
13184
13094
  }
13185
- toString(doc) {
13186
- const lines = this.yaml.explicit ? [`%YAML ${this.yaml.version || "1.2"}`] : [];
13187
- const tagEntries = Object.entries(this.tags);
13188
- let tagNames;
13189
- if (doc && tagEntries.length > 0 && identity.isNode(doc.contents)) {
13190
- const tags = {};
13191
- visit.visit(doc.contents, (_key, node) => {
13192
- if (identity.isNode(node) && node.tag)
13193
- tags[node.tag] = true;
13194
- });
13195
- tagNames = Object.keys(tags);
13196
- } else
13197
- tagNames = [];
13198
- for (const [handle, prefix] of tagEntries) {
13199
- if (handle === "!!" && prefix === "tag:yaml.org,2002:")
13200
- continue;
13201
- if (!doc || tagNames.some((tn) => tn.startsWith(prefix)))
13202
- lines.push(`%TAG ${handle} ${prefix}`);
13095
+ };
13096
+ function getAliasCount(doc, node, anchors2) {
13097
+ if (identity.isAlias(node)) {
13098
+ const source = node.resolve(doc);
13099
+ const anchor = anchors2 && source && anchors2.get(source);
13100
+ return anchor ? anchor.count * anchor.aliasCount : 0;
13101
+ } else if (identity.isCollection(node)) {
13102
+ let count = 0;
13103
+ for (const item of node.items) {
13104
+ const c = getAliasCount(doc, item, anchors2);
13105
+ if (c > count)
13106
+ count = c;
13203
13107
  }
13204
- return lines.join("\n");
13108
+ return count;
13109
+ } else if (identity.isPair(node)) {
13110
+ const kc = getAliasCount(doc, node.key, anchors2);
13111
+ const vc = getAliasCount(doc, node.value, anchors2);
13112
+ return Math.max(kc, vc);
13205
13113
  }
13206
- };
13207
- Directives.defaultYaml = { explicit: false, version: "1.2" };
13208
- Directives.defaultTags = { "!!": "tag:yaml.org,2002:" };
13209
- exports2.Directives = Directives;
13114
+ return 1;
13115
+ }
13116
+ exports2.Alias = Alias;
13210
13117
  }
13211
13118
  });
13212
13119
 
13213
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/anchors.js
13214
- var require_anchors = __commonJS({
13215
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/anchors.js"(exports2) {
13120
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Scalar.js
13121
+ var require_Scalar = __commonJS({
13122
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Scalar.js"(exports2) {
13216
13123
  "use strict";
13217
13124
  var identity = require_identity();
13218
- var visit = require_visit();
13219
- function anchorIsValid(anchor) {
13220
- if (/[\x00-\x19\s,[\]{}]/.test(anchor)) {
13221
- const sa = JSON.stringify(anchor);
13222
- const msg = `Anchor must not contain whitespace or control characters: ${sa}`;
13223
- throw new Error(msg);
13125
+ var Node = require_Node();
13126
+ var toJS = require_toJS();
13127
+ var isScalarValue = (value) => !value || typeof value !== "function" && typeof value !== "object";
13128
+ var Scalar = class extends Node.NodeBase {
13129
+ constructor(value) {
13130
+ super(identity.SCALAR);
13131
+ this.value = value;
13224
13132
  }
13225
- return true;
13226
- }
13227
- function anchorNames(root) {
13228
- const anchors = /* @__PURE__ */ new Set();
13229
- visit.visit(root, {
13230
- Value(_key, node) {
13231
- if (node.anchor)
13232
- anchors.add(node.anchor);
13233
- }
13234
- });
13235
- return anchors;
13236
- }
13237
- function findNewAnchor(prefix, exclude) {
13238
- for (let i = 1; true; ++i) {
13239
- const name = `${prefix}${i}`;
13240
- if (!exclude.has(name))
13241
- return name;
13133
+ toJSON(arg, ctx) {
13134
+ return ctx?.keep ? this.value : toJS.toJS(this.value, arg, ctx);
13242
13135
  }
13243
- }
13244
- function createNodeAnchors(doc, prefix) {
13245
- const aliasObjects = [];
13246
- const sourceObjects = /* @__PURE__ */ new Map();
13247
- let prevAnchors = null;
13248
- return {
13249
- onAnchor: (source) => {
13250
- aliasObjects.push(source);
13251
- prevAnchors ?? (prevAnchors = anchorNames(doc));
13252
- const anchor = findNewAnchor(prefix, prevAnchors);
13253
- prevAnchors.add(anchor);
13254
- return anchor;
13255
- },
13256
- /**
13257
- * With circular references, the source node is only resolved after all
13258
- * of its child nodes are. This is why anchors are set only after all of
13259
- * the nodes have been created.
13260
- */
13261
- setAnchors: () => {
13262
- for (const source of aliasObjects) {
13263
- const ref = sourceObjects.get(source);
13264
- if (typeof ref === "object" && ref.anchor && (identity.isScalar(ref.node) || identity.isCollection(ref.node))) {
13265
- ref.node.anchor = ref.anchor;
13266
- } else {
13267
- const error = new Error("Failed to resolve repeated object (this should not happen)");
13268
- error.source = source;
13269
- throw error;
13270
- }
13271
- }
13272
- },
13273
- sourceObjects
13274
- };
13275
- }
13276
- exports2.anchorIsValid = anchorIsValid;
13277
- exports2.anchorNames = anchorNames;
13278
- exports2.createNodeAnchors = createNodeAnchors;
13279
- exports2.findNewAnchor = findNewAnchor;
13136
+ toString() {
13137
+ return String(this.value);
13138
+ }
13139
+ };
13140
+ Scalar.BLOCK_FOLDED = "BLOCK_FOLDED";
13141
+ Scalar.BLOCK_LITERAL = "BLOCK_LITERAL";
13142
+ Scalar.PLAIN = "PLAIN";
13143
+ Scalar.QUOTE_DOUBLE = "QUOTE_DOUBLE";
13144
+ Scalar.QUOTE_SINGLE = "QUOTE_SINGLE";
13145
+ exports2.Scalar = Scalar;
13146
+ exports2.isScalarValue = isScalarValue;
13280
13147
  }
13281
13148
  });
13282
13149
 
13283
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/applyReviver.js
13284
- var require_applyReviver = __commonJS({
13285
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/applyReviver.js"(exports2) {
13150
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/createNode.js
13151
+ var require_createNode = __commonJS({
13152
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/createNode.js"(exports2) {
13286
13153
  "use strict";
13287
- function applyReviver(reviver, obj, key, val) {
13288
- if (val && typeof val === "object") {
13289
- if (Array.isArray(val)) {
13290
- for (let i = 0, len = val.length; i < len; ++i) {
13291
- const v0 = val[i];
13292
- const v1 = applyReviver(reviver, val, String(i), v0);
13293
- if (v1 === void 0)
13294
- delete val[i];
13295
- else if (v1 !== v0)
13296
- val[i] = v1;
13297
- }
13298
- } else if (val instanceof Map) {
13299
- for (const k of Array.from(val.keys())) {
13300
- const v0 = val.get(k);
13301
- const v1 = applyReviver(reviver, val, k, v0);
13302
- if (v1 === void 0)
13303
- val.delete(k);
13304
- else if (v1 !== v0)
13305
- val.set(k, v1);
13306
- }
13307
- } else if (val instanceof Set) {
13308
- for (const v0 of Array.from(val)) {
13309
- const v1 = applyReviver(reviver, val, v0, v0);
13310
- if (v1 === void 0)
13311
- val.delete(v0);
13312
- else if (v1 !== v0) {
13313
- val.delete(v0);
13314
- val.add(v1);
13315
- }
13316
- }
13154
+ var Alias = require_Alias();
13155
+ var identity = require_identity();
13156
+ var Scalar = require_Scalar();
13157
+ var defaultTagPrefix = "tag:yaml.org,2002:";
13158
+ function findTagObject(value, tagName, tags) {
13159
+ if (tagName) {
13160
+ const match = tags.filter((t) => t.tag === tagName);
13161
+ const tagObj = match.find((t) => !t.format) ?? match[0];
13162
+ if (!tagObj)
13163
+ throw new Error(`Tag ${tagName} not found`);
13164
+ return tagObj;
13165
+ }
13166
+ return tags.find((t) => t.identify?.(value) && !t.format);
13167
+ }
13168
+ function createNode(value, tagName, ctx) {
13169
+ if (identity.isDocument(value))
13170
+ value = value.contents;
13171
+ if (identity.isNode(value))
13172
+ return value;
13173
+ if (identity.isPair(value)) {
13174
+ const map = ctx.schema[identity.MAP].createNode?.(ctx.schema, null, ctx);
13175
+ map.items.push(value);
13176
+ return map;
13177
+ }
13178
+ if (value instanceof String || value instanceof Number || value instanceof Boolean || typeof BigInt !== "undefined" && value instanceof BigInt) {
13179
+ value = value.valueOf();
13180
+ }
13181
+ const { aliasDuplicateObjects, onAnchor, onTagObj, schema, sourceObjects } = ctx;
13182
+ let ref = void 0;
13183
+ if (aliasDuplicateObjects && value && typeof value === "object") {
13184
+ ref = sourceObjects.get(value);
13185
+ if (ref) {
13186
+ ref.anchor ?? (ref.anchor = onAnchor(value));
13187
+ return new Alias.Alias(ref.anchor);
13317
13188
  } else {
13318
- for (const [k, v0] of Object.entries(val)) {
13319
- const v1 = applyReviver(reviver, val, k, v0);
13320
- if (v1 === void 0)
13321
- delete val[k];
13322
- else if (v1 !== v0)
13323
- val[k] = v1;
13324
- }
13189
+ ref = { anchor: null, node: null };
13190
+ sourceObjects.set(value, ref);
13325
13191
  }
13326
13192
  }
13327
- return reviver.call(obj, key, val);
13193
+ if (tagName?.startsWith("!!"))
13194
+ tagName = defaultTagPrefix + tagName.slice(2);
13195
+ let tagObj = findTagObject(value, tagName, schema.tags);
13196
+ if (!tagObj) {
13197
+ if (value && typeof value.toJSON === "function") {
13198
+ value = value.toJSON();
13199
+ }
13200
+ if (!value || typeof value !== "object") {
13201
+ const node2 = new Scalar.Scalar(value);
13202
+ if (ref)
13203
+ ref.node = node2;
13204
+ return node2;
13205
+ }
13206
+ tagObj = value instanceof Map ? schema[identity.MAP] : Symbol.iterator in Object(value) ? schema[identity.SEQ] : schema[identity.MAP];
13207
+ }
13208
+ if (onTagObj) {
13209
+ onTagObj(tagObj);
13210
+ delete ctx.onTagObj;
13211
+ }
13212
+ const node = tagObj?.createNode ? tagObj.createNode(ctx.schema, value, ctx) : typeof tagObj?.nodeClass?.from === "function" ? tagObj.nodeClass.from(ctx.schema, value, ctx) : new Scalar.Scalar(value);
13213
+ if (tagName)
13214
+ node.tag = tagName;
13215
+ else if (!tagObj.default)
13216
+ node.tag = tagObj.tag;
13217
+ if (ref)
13218
+ ref.node = node;
13219
+ return node;
13328
13220
  }
13329
- exports2.applyReviver = applyReviver;
13221
+ exports2.createNode = createNode;
13330
13222
  }
13331
13223
  });
13332
13224
 
13333
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/toJS.js
13334
- var require_toJS = __commonJS({
13335
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/toJS.js"(exports2) {
13225
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Collection.js
13226
+ var require_Collection = __commonJS({
13227
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Collection.js"(exports2) {
13336
13228
  "use strict";
13229
+ var createNode = require_createNode();
13337
13230
  var identity = require_identity();
13338
- function toJS(value, arg, ctx) {
13339
- if (Array.isArray(value))
13340
- return value.map((v, i) => toJS(v, String(i), ctx));
13341
- if (value && typeof value.toJSON === "function") {
13342
- if (!ctx || !identity.hasAnchor(value))
13343
- return value.toJSON(arg, ctx);
13344
- const data = { aliasCount: 0, count: 1, res: void 0 };
13345
- ctx.anchors.set(value, data);
13346
- ctx.onCreate = (res2) => {
13347
- data.res = res2;
13348
- delete ctx.onCreate;
13349
- };
13350
- const res = value.toJSON(arg, ctx);
13351
- if (ctx.onCreate)
13352
- ctx.onCreate(res);
13353
- return res;
13231
+ var Node = require_Node();
13232
+ function collectionFromPath(schema, path, value) {
13233
+ let v = value;
13234
+ for (let i = path.length - 1; i >= 0; --i) {
13235
+ const k = path[i];
13236
+ if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
13237
+ const a = [];
13238
+ a[k] = v;
13239
+ v = a;
13240
+ } else {
13241
+ v = /* @__PURE__ */ new Map([[k, v]]);
13242
+ }
13354
13243
  }
13355
- if (typeof value === "bigint" && !ctx?.keep)
13356
- return Number(value);
13357
- return value;
13244
+ return createNode.createNode(v, void 0, {
13245
+ aliasDuplicateObjects: false,
13246
+ keepUndefined: false,
13247
+ onAnchor: () => {
13248
+ throw new Error("This should not happen, please report a bug.");
13249
+ },
13250
+ schema,
13251
+ sourceObjects: /* @__PURE__ */ new Map()
13252
+ });
13358
13253
  }
13359
- exports2.toJS = toJS;
13360
- }
13361
- });
13362
-
13363
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Node.js
13364
- var require_Node = __commonJS({
13365
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Node.js"(exports2) {
13366
- "use strict";
13367
- var applyReviver = require_applyReviver();
13368
- var identity = require_identity();
13369
- var toJS = require_toJS();
13370
- var NodeBase = class {
13371
- constructor(type) {
13372
- Object.defineProperty(this, identity.NODE_TYPE, { value: type });
13254
+ var isEmptyPath = (path) => path == null || typeof path === "object" && !!path[Symbol.iterator]().next().done;
13255
+ var Collection = class extends Node.NodeBase {
13256
+ constructor(type, schema) {
13257
+ super(type);
13258
+ Object.defineProperty(this, "schema", {
13259
+ value: schema,
13260
+ configurable: true,
13261
+ enumerable: false,
13262
+ writable: true
13263
+ });
13373
13264
  }
13374
- /** Create a copy of this node. */
13375
- clone() {
13265
+ /**
13266
+ * Create a copy of this collection.
13267
+ *
13268
+ * @param schema - If defined, overwrites the original's schema
13269
+ */
13270
+ clone(schema) {
13376
13271
  const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));
13272
+ if (schema)
13273
+ copy.schema = schema;
13274
+ copy.items = copy.items.map((it) => identity.isNode(it) || identity.isPair(it) ? it.clone(schema) : it);
13377
13275
  if (this.range)
13378
13276
  copy.range = this.range.slice();
13379
13277
  return copy;
13380
13278
  }
13381
- /** A plain JavaScript representation of this node. */
13382
- toJS(doc, { mapAsMap, maxAliasCount, onAnchor, reviver } = {}) {
13383
- if (!identity.isDocument(doc))
13384
- throw new TypeError("A document argument is required");
13385
- const ctx = {
13386
- anchors: /* @__PURE__ */ new Map(),
13387
- doc,
13388
- keep: true,
13389
- mapAsMap: mapAsMap === true,
13390
- mapKeyWarned: false,
13391
- maxAliasCount: typeof maxAliasCount === "number" ? maxAliasCount : 100
13392
- };
13393
- const res = toJS.toJS(this, "", ctx);
13394
- if (typeof onAnchor === "function")
13395
- for (const { count, res: res2 } of ctx.anchors.values())
13396
- onAnchor(res2, count);
13397
- return typeof reviver === "function" ? applyReviver.applyReviver(reviver, { "": res }, "", res) : res;
13279
+ /**
13280
+ * Adds a value to the collection. For `!!map` and `!!omap` the value must
13281
+ * be a Pair instance or a `{ key, value }` object, which may not have a key
13282
+ * that already exists in the map.
13283
+ */
13284
+ addIn(path, value) {
13285
+ if (isEmptyPath(path))
13286
+ this.add(value);
13287
+ else {
13288
+ const [key, ...rest] = path;
13289
+ const node = this.get(key, true);
13290
+ if (identity.isCollection(node))
13291
+ node.addIn(rest, value);
13292
+ else if (node === void 0 && this.schema)
13293
+ this.set(key, collectionFromPath(this.schema, rest, value));
13294
+ else
13295
+ throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
13296
+ }
13398
13297
  }
13399
- };
13400
- exports2.NodeBase = NodeBase;
13401
- }
13402
- });
13403
-
13404
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Alias.js
13405
- var require_Alias = __commonJS({
13406
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Alias.js"(exports2) {
13407
- "use strict";
13408
- var anchors = require_anchors();
13409
- var visit = require_visit();
13410
- var identity = require_identity();
13411
- var Node = require_Node();
13412
- var toJS = require_toJS();
13413
- var Alias = class extends Node.NodeBase {
13414
- constructor(source) {
13415
- super(identity.ALIAS);
13416
- this.source = source;
13417
- Object.defineProperty(this, "tag", {
13418
- set() {
13419
- throw new Error("Alias nodes cannot have tags");
13420
- }
13421
- });
13298
+ /**
13299
+ * Removes a value from the collection.
13300
+ * @returns `true` if the item was found and removed.
13301
+ */
13302
+ deleteIn(path) {
13303
+ const [key, ...rest] = path;
13304
+ if (rest.length === 0)
13305
+ return this.delete(key);
13306
+ const node = this.get(key, true);
13307
+ if (identity.isCollection(node))
13308
+ return node.deleteIn(rest);
13309
+ else
13310
+ throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
13422
13311
  }
13423
13312
  /**
13424
- * Resolve the value of this alias within `doc`, finding the last
13425
- * instance of the `source` anchor before this node.
13313
+ * Returns item at `key`, or `undefined` if not found. By default unwraps
13314
+ * scalar values from their surrounding node; to disable set `keepScalar` to
13315
+ * `true` (collections are always returned intact).
13426
13316
  */
13427
- resolve(doc, ctx) {
13428
- if (ctx?.maxAliasCount === 0)
13429
- throw new ReferenceError("Alias resolution is disabled");
13430
- let nodes;
13431
- if (ctx?.aliasResolveCache) {
13432
- nodes = ctx.aliasResolveCache;
13433
- } else {
13434
- nodes = [];
13435
- visit.visit(doc, {
13436
- Node: (_key, node) => {
13437
- if (identity.isAlias(node) || identity.hasAnchor(node))
13438
- nodes.push(node);
13439
- }
13440
- });
13441
- if (ctx)
13442
- ctx.aliasResolveCache = nodes;
13443
- }
13444
- let found = void 0;
13445
- for (const node of nodes) {
13446
- if (node === this)
13447
- break;
13448
- if (node.anchor === this.source)
13449
- found = node;
13450
- }
13451
- return found;
13317
+ getIn(path, keepScalar) {
13318
+ const [key, ...rest] = path;
13319
+ const node = this.get(key, true);
13320
+ if (rest.length === 0)
13321
+ return !keepScalar && identity.isScalar(node) ? node.value : node;
13322
+ else
13323
+ return identity.isCollection(node) ? node.getIn(rest, keepScalar) : void 0;
13452
13324
  }
13453
- toJSON(_arg, ctx) {
13454
- if (!ctx)
13455
- return { source: this.source };
13456
- const { anchors: anchors2, doc, maxAliasCount } = ctx;
13457
- const source = this.resolve(doc, ctx);
13458
- if (!source) {
13459
- const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
13460
- throw new ReferenceError(msg);
13461
- }
13462
- let data = anchors2.get(source);
13463
- if (!data) {
13464
- toJS.toJS(source, null, ctx);
13465
- data = anchors2.get(source);
13466
- }
13467
- if (data?.res === void 0) {
13468
- const msg = "This should not happen: Alias anchor was not resolved?";
13469
- throw new ReferenceError(msg);
13470
- }
13471
- if (maxAliasCount >= 0) {
13472
- data.count += 1;
13473
- if (data.aliasCount === 0)
13474
- data.aliasCount = getAliasCount(doc, source, anchors2);
13475
- if (data.count * data.aliasCount > maxAliasCount) {
13476
- const msg = "Excessive alias count indicates a resource exhaustion attack";
13477
- throw new ReferenceError(msg);
13478
- }
13479
- }
13480
- return data.res;
13325
+ hasAllNullValues(allowScalar) {
13326
+ return this.items.every((node) => {
13327
+ if (!identity.isPair(node))
13328
+ return false;
13329
+ const n = node.value;
13330
+ return n == null || allowScalar && identity.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
13331
+ });
13481
13332
  }
13482
- toString(ctx, _onComment, _onChompKeep) {
13483
- const src = `*${this.source}`;
13484
- if (ctx) {
13485
- anchors.anchorIsValid(this.source);
13486
- if (ctx.options.verifyAliasOrder && !ctx.anchors.has(this.source)) {
13487
- const msg = `Unresolved alias (the anchor must be set before the alias): ${this.source}`;
13488
- throw new Error(msg);
13489
- }
13490
- if (ctx.implicitKey)
13491
- return `${src} `;
13492
- }
13493
- return src;
13333
+ /**
13334
+ * Checks if the collection includes a value with the key `key`.
13335
+ */
13336
+ hasIn(path) {
13337
+ const [key, ...rest] = path;
13338
+ if (rest.length === 0)
13339
+ return this.has(key);
13340
+ const node = this.get(key, true);
13341
+ return identity.isCollection(node) ? node.hasIn(rest) : false;
13494
13342
  }
13495
- };
13496
- function getAliasCount(doc, node, anchors2) {
13497
- if (identity.isAlias(node)) {
13498
- const source = node.resolve(doc);
13499
- const anchor = anchors2 && source && anchors2.get(source);
13500
- return anchor ? anchor.count * anchor.aliasCount : 0;
13501
- } else if (identity.isCollection(node)) {
13502
- let count = 0;
13503
- for (const item of node.items) {
13504
- const c = getAliasCount(doc, item, anchors2);
13505
- if (c > count)
13506
- count = c;
13343
+ /**
13344
+ * Sets a value in this collection. For `!!set`, `value` needs to be a
13345
+ * boolean to add/remove the item from the set.
13346
+ */
13347
+ setIn(path, value) {
13348
+ const [key, ...rest] = path;
13349
+ if (rest.length === 0) {
13350
+ this.set(key, value);
13351
+ } else {
13352
+ const node = this.get(key, true);
13353
+ if (identity.isCollection(node))
13354
+ node.setIn(rest, value);
13355
+ else if (node === void 0 && this.schema)
13356
+ this.set(key, collectionFromPath(this.schema, rest, value));
13357
+ else
13358
+ throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
13507
13359
  }
13508
- return count;
13509
- } else if (identity.isPair(node)) {
13510
- const kc = getAliasCount(doc, node.key, anchors2);
13511
- const vc = getAliasCount(doc, node.value, anchors2);
13512
- return Math.max(kc, vc);
13513
13360
  }
13514
- return 1;
13515
- }
13516
- exports2.Alias = Alias;
13361
+ };
13362
+ exports2.Collection = Collection;
13363
+ exports2.collectionFromPath = collectionFromPath;
13364
+ exports2.isEmptyPath = isEmptyPath;
13517
13365
  }
13518
13366
  });
13519
13367
 
13520
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Scalar.js
13521
- var require_Scalar = __commonJS({
13522
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Scalar.js"(exports2) {
13368
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/stringifyComment.js
13369
+ var require_stringifyComment = __commonJS({
13370
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/stringifyComment.js"(exports2) {
13523
13371
  "use strict";
13524
- var identity = require_identity();
13525
- var Node = require_Node();
13526
- var toJS = require_toJS();
13527
- var isScalarValue = (value) => !value || typeof value !== "function" && typeof value !== "object";
13528
- var Scalar = class extends Node.NodeBase {
13529
- constructor(value) {
13530
- super(identity.SCALAR);
13531
- this.value = value;
13532
- }
13533
- toJSON(arg, ctx) {
13534
- return ctx?.keep ? this.value : toJS.toJS(this.value, arg, ctx);
13535
- }
13536
- toString() {
13537
- return String(this.value);
13538
- }
13539
- };
13540
- Scalar.BLOCK_FOLDED = "BLOCK_FOLDED";
13541
- Scalar.BLOCK_LITERAL = "BLOCK_LITERAL";
13542
- Scalar.PLAIN = "PLAIN";
13543
- Scalar.QUOTE_DOUBLE = "QUOTE_DOUBLE";
13544
- Scalar.QUOTE_SINGLE = "QUOTE_SINGLE";
13545
- exports2.Scalar = Scalar;
13546
- exports2.isScalarValue = isScalarValue;
13372
+ var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
13373
+ function indentComment(comment, indent) {
13374
+ if (/^\n+$/.test(comment))
13375
+ return comment.substring(1);
13376
+ return indent ? comment.replace(/^(?! *$)/gm, indent) : comment;
13377
+ }
13378
+ var lineComment = (str, indent, comment) => str.endsWith("\n") ? indentComment(comment, indent) : comment.includes("\n") ? "\n" + indentComment(comment, indent) : (str.endsWith(" ") ? "" : " ") + comment;
13379
+ exports2.indentComment = indentComment;
13380
+ exports2.lineComment = lineComment;
13381
+ exports2.stringifyComment = stringifyComment;
13547
13382
  }
13548
13383
  });
13549
13384
 
13550
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/createNode.js
13551
- var require_createNode = __commonJS({
13552
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/doc/createNode.js"(exports2) {
13553
- "use strict";
13554
- var Alias = require_Alias();
13555
- var identity = require_identity();
13556
- var Scalar = require_Scalar();
13557
- var defaultTagPrefix = "tag:yaml.org,2002:";
13558
- function findTagObject(value, tagName, tags) {
13559
- if (tagName) {
13560
- const match = tags.filter((t) => t.tag === tagName);
13561
- const tagObj = match.find((t) => !t.format) ?? match[0];
13562
- if (!tagObj)
13563
- throw new Error(`Tag ${tagName} not found`);
13564
- return tagObj;
13565
- }
13566
- return tags.find((t) => t.identify?.(value) && !t.format);
13567
- }
13568
- function createNode(value, tagName, ctx) {
13569
- if (identity.isDocument(value))
13570
- value = value.contents;
13571
- if (identity.isNode(value))
13572
- return value;
13573
- if (identity.isPair(value)) {
13574
- const map = ctx.schema[identity.MAP].createNode?.(ctx.schema, null, ctx);
13575
- map.items.push(value);
13576
- return map;
13577
- }
13578
- if (value instanceof String || value instanceof Number || value instanceof Boolean || typeof BigInt !== "undefined" && value instanceof BigInt) {
13579
- value = value.valueOf();
13580
- }
13581
- const { aliasDuplicateObjects, onAnchor, onTagObj, schema, sourceObjects } = ctx;
13582
- let ref = void 0;
13583
- if (aliasDuplicateObjects && value && typeof value === "object") {
13584
- ref = sourceObjects.get(value);
13585
- if (ref) {
13586
- ref.anchor ?? (ref.anchor = onAnchor(value));
13587
- return new Alias.Alias(ref.anchor);
13588
- } else {
13589
- ref = { anchor: null, node: null };
13590
- sourceObjects.set(value, ref);
13591
- }
13592
- }
13593
- if (tagName?.startsWith("!!"))
13594
- tagName = defaultTagPrefix + tagName.slice(2);
13595
- let tagObj = findTagObject(value, tagName, schema.tags);
13596
- if (!tagObj) {
13597
- if (value && typeof value.toJSON === "function") {
13598
- value = value.toJSON();
13599
- }
13600
- if (!value || typeof value !== "object") {
13601
- const node2 = new Scalar.Scalar(value);
13602
- if (ref)
13603
- ref.node = node2;
13604
- return node2;
13605
- }
13606
- tagObj = value instanceof Map ? schema[identity.MAP] : Symbol.iterator in Object(value) ? schema[identity.SEQ] : schema[identity.MAP];
13607
- }
13608
- if (onTagObj) {
13609
- onTagObj(tagObj);
13610
- delete ctx.onTagObj;
13611
- }
13612
- const node = tagObj?.createNode ? tagObj.createNode(ctx.schema, value, ctx) : typeof tagObj?.nodeClass?.from === "function" ? tagObj.nodeClass.from(ctx.schema, value, ctx) : new Scalar.Scalar(value);
13613
- if (tagName)
13614
- node.tag = tagName;
13615
- else if (!tagObj.default)
13616
- node.tag = tagObj.tag;
13617
- if (ref)
13618
- ref.node = node;
13619
- return node;
13620
- }
13621
- exports2.createNode = createNode;
13622
- }
13623
- });
13624
-
13625
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Collection.js
13626
- var require_Collection = __commonJS({
13627
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/Collection.js"(exports2) {
13628
- "use strict";
13629
- var createNode = require_createNode();
13630
- var identity = require_identity();
13631
- var Node = require_Node();
13632
- function collectionFromPath(schema, path, value) {
13633
- let v = value;
13634
- for (let i = path.length - 1; i >= 0; --i) {
13635
- const k = path[i];
13636
- if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
13637
- const a = [];
13638
- a[k] = v;
13639
- v = a;
13640
- } else {
13641
- v = /* @__PURE__ */ new Map([[k, v]]);
13642
- }
13643
- }
13644
- return createNode.createNode(v, void 0, {
13645
- aliasDuplicateObjects: false,
13646
- keepUndefined: false,
13647
- onAnchor: () => {
13648
- throw new Error("This should not happen, please report a bug.");
13649
- },
13650
- schema,
13651
- sourceObjects: /* @__PURE__ */ new Map()
13652
- });
13653
- }
13654
- var isEmptyPath = (path) => path == null || typeof path === "object" && !!path[Symbol.iterator]().next().done;
13655
- var Collection = class extends Node.NodeBase {
13656
- constructor(type, schema) {
13657
- super(type);
13658
- Object.defineProperty(this, "schema", {
13659
- value: schema,
13660
- configurable: true,
13661
- enumerable: false,
13662
- writable: true
13663
- });
13664
- }
13665
- /**
13666
- * Create a copy of this collection.
13667
- *
13668
- * @param schema - If defined, overwrites the original's schema
13669
- */
13670
- clone(schema) {
13671
- const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));
13672
- if (schema)
13673
- copy.schema = schema;
13674
- copy.items = copy.items.map((it) => identity.isNode(it) || identity.isPair(it) ? it.clone(schema) : it);
13675
- if (this.range)
13676
- copy.range = this.range.slice();
13677
- return copy;
13678
- }
13679
- /**
13680
- * Adds a value to the collection. For `!!map` and `!!omap` the value must
13681
- * be a Pair instance or a `{ key, value }` object, which may not have a key
13682
- * that already exists in the map.
13683
- */
13684
- addIn(path, value) {
13685
- if (isEmptyPath(path))
13686
- this.add(value);
13687
- else {
13688
- const [key, ...rest] = path;
13689
- const node = this.get(key, true);
13690
- if (identity.isCollection(node))
13691
- node.addIn(rest, value);
13692
- else if (node === void 0 && this.schema)
13693
- this.set(key, collectionFromPath(this.schema, rest, value));
13694
- else
13695
- throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
13696
- }
13697
- }
13698
- /**
13699
- * Removes a value from the collection.
13700
- * @returns `true` if the item was found and removed.
13701
- */
13702
- deleteIn(path) {
13703
- const [key, ...rest] = path;
13704
- if (rest.length === 0)
13705
- return this.delete(key);
13706
- const node = this.get(key, true);
13707
- if (identity.isCollection(node))
13708
- return node.deleteIn(rest);
13709
- else
13710
- throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
13711
- }
13712
- /**
13713
- * Returns item at `key`, or `undefined` if not found. By default unwraps
13714
- * scalar values from their surrounding node; to disable set `keepScalar` to
13715
- * `true` (collections are always returned intact).
13716
- */
13717
- getIn(path, keepScalar) {
13718
- const [key, ...rest] = path;
13719
- const node = this.get(key, true);
13720
- if (rest.length === 0)
13721
- return !keepScalar && identity.isScalar(node) ? node.value : node;
13722
- else
13723
- return identity.isCollection(node) ? node.getIn(rest, keepScalar) : void 0;
13724
- }
13725
- hasAllNullValues(allowScalar) {
13726
- return this.items.every((node) => {
13727
- if (!identity.isPair(node))
13728
- return false;
13729
- const n = node.value;
13730
- return n == null || allowScalar && identity.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
13731
- });
13732
- }
13733
- /**
13734
- * Checks if the collection includes a value with the key `key`.
13735
- */
13736
- hasIn(path) {
13737
- const [key, ...rest] = path;
13738
- if (rest.length === 0)
13739
- return this.has(key);
13740
- const node = this.get(key, true);
13741
- return identity.isCollection(node) ? node.hasIn(rest) : false;
13742
- }
13743
- /**
13744
- * Sets a value in this collection. For `!!set`, `value` needs to be a
13745
- * boolean to add/remove the item from the set.
13746
- */
13747
- setIn(path, value) {
13748
- const [key, ...rest] = path;
13749
- if (rest.length === 0) {
13750
- this.set(key, value);
13751
- } else {
13752
- const node = this.get(key, true);
13753
- if (identity.isCollection(node))
13754
- node.setIn(rest, value);
13755
- else if (node === void 0 && this.schema)
13756
- this.set(key, collectionFromPath(this.schema, rest, value));
13757
- else
13758
- throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
13759
- }
13760
- }
13761
- };
13762
- exports2.Collection = Collection;
13763
- exports2.collectionFromPath = collectionFromPath;
13764
- exports2.isEmptyPath = isEmptyPath;
13765
- }
13766
- });
13767
-
13768
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/stringifyComment.js
13769
- var require_stringifyComment = __commonJS({
13770
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/stringifyComment.js"(exports2) {
13771
- "use strict";
13772
- var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
13773
- function indentComment(comment, indent) {
13774
- if (/^\n+$/.test(comment))
13775
- return comment.substring(1);
13776
- return indent ? comment.replace(/^(?! *$)/gm, indent) : comment;
13777
- }
13778
- var lineComment = (str, indent, comment) => str.endsWith("\n") ? indentComment(comment, indent) : comment.includes("\n") ? "\n" + indentComment(comment, indent) : (str.endsWith(" ") ? "" : " ") + comment;
13779
- exports2.indentComment = indentComment;
13780
- exports2.lineComment = lineComment;
13781
- exports2.stringifyComment = stringifyComment;
13782
- }
13783
- });
13784
-
13785
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/foldFlowLines.js
13786
- var require_foldFlowLines = __commonJS({
13787
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/foldFlowLines.js"(exports2) {
13385
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/foldFlowLines.js
13386
+ var require_foldFlowLines = __commonJS({
13387
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/stringify/foldFlowLines.js"(exports2) {
13788
13388
  "use strict";
13789
13389
  var FOLD_FLOW = "flow";
13790
13390
  var FOLD_BLOCK = "block";
@@ -20028,126 +19628,673 @@ var require_public_api = __commonJS({
20028
19628
  doc.errors.forEach(errors.prettifyError(source, lineCounter2));
20029
19629
  doc.warnings.forEach(errors.prettifyError(source, lineCounter2));
20030
19630
  }
20031
- if (docs.length > 0)
20032
- return docs;
20033
- return Object.assign([], { empty: true }, composer$1.streamInfo());
20034
- }
20035
- function parseDocument(source, options = {}) {
20036
- const { lineCounter: lineCounter2, prettyErrors } = parseOptions(options);
20037
- const parser$1 = new parser.Parser(lineCounter2?.addNewLine);
20038
- const composer$1 = new composer.Composer(options);
20039
- let doc = null;
20040
- for (const _doc of composer$1.compose(parser$1.parse(source), true, source.length)) {
20041
- if (!doc)
20042
- doc = _doc;
20043
- else if (doc.options.logLevel !== "silent") {
20044
- doc.errors.push(new errors.YAMLParseError(_doc.range.slice(0, 2), "MULTIPLE_DOCS", "Source contains multiple documents; please use YAML.parseAllDocuments()"));
20045
- break;
19631
+ if (docs.length > 0)
19632
+ return docs;
19633
+ return Object.assign([], { empty: true }, composer$1.streamInfo());
19634
+ }
19635
+ function parseDocument(source, options = {}) {
19636
+ const { lineCounter: lineCounter2, prettyErrors } = parseOptions(options);
19637
+ const parser$1 = new parser.Parser(lineCounter2?.addNewLine);
19638
+ const composer$1 = new composer.Composer(options);
19639
+ let doc = null;
19640
+ for (const _doc of composer$1.compose(parser$1.parse(source), true, source.length)) {
19641
+ if (!doc)
19642
+ doc = _doc;
19643
+ else if (doc.options.logLevel !== "silent") {
19644
+ doc.errors.push(new errors.YAMLParseError(_doc.range.slice(0, 2), "MULTIPLE_DOCS", "Source contains multiple documents; please use YAML.parseAllDocuments()"));
19645
+ break;
19646
+ }
19647
+ }
19648
+ if (prettyErrors && lineCounter2) {
19649
+ doc.errors.forEach(errors.prettifyError(source, lineCounter2));
19650
+ doc.warnings.forEach(errors.prettifyError(source, lineCounter2));
19651
+ }
19652
+ return doc;
19653
+ }
19654
+ function parse(src, reviver, options) {
19655
+ let _reviver = void 0;
19656
+ if (typeof reviver === "function") {
19657
+ _reviver = reviver;
19658
+ } else if (options === void 0 && reviver && typeof reviver === "object") {
19659
+ options = reviver;
19660
+ }
19661
+ const doc = parseDocument(src, options);
19662
+ if (!doc)
19663
+ return null;
19664
+ doc.warnings.forEach((warning) => log.warn(doc.options.logLevel, warning));
19665
+ if (doc.errors.length > 0) {
19666
+ if (doc.options.logLevel !== "silent")
19667
+ throw doc.errors[0];
19668
+ else
19669
+ doc.errors = [];
19670
+ }
19671
+ return doc.toJS(Object.assign({ reviver: _reviver }, options));
19672
+ }
19673
+ function stringify(value, replacer, options) {
19674
+ let _replacer = null;
19675
+ if (typeof replacer === "function" || Array.isArray(replacer)) {
19676
+ _replacer = replacer;
19677
+ } else if (options === void 0 && replacer) {
19678
+ options = replacer;
19679
+ }
19680
+ if (typeof options === "string")
19681
+ options = options.length;
19682
+ if (typeof options === "number") {
19683
+ const indent = Math.round(options);
19684
+ options = indent < 1 ? void 0 : indent > 8 ? { indent: 8 } : { indent };
19685
+ }
19686
+ if (value === void 0) {
19687
+ const { keepUndefined } = options ?? replacer ?? {};
19688
+ if (!keepUndefined)
19689
+ return void 0;
19690
+ }
19691
+ if (identity.isDocument(value) && !_replacer)
19692
+ return value.toString(options);
19693
+ return new Document.Document(value, _replacer, options).toString(options);
19694
+ }
19695
+ exports2.parse = parse;
19696
+ exports2.parseAllDocuments = parseAllDocuments;
19697
+ exports2.parseDocument = parseDocument;
19698
+ exports2.stringify = stringify;
19699
+ }
19700
+ });
19701
+
19702
+ // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/index.js
19703
+ var require_dist3 = __commonJS({
19704
+ "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/index.js"(exports2) {
19705
+ "use strict";
19706
+ var composer = require_composer();
19707
+ var Document = require_Document();
19708
+ var Schema = require_Schema();
19709
+ var errors = require_errors3();
19710
+ var Alias = require_Alias();
19711
+ var identity = require_identity();
19712
+ var Pair = require_Pair();
19713
+ var Scalar = require_Scalar();
19714
+ var YAMLMap = require_YAMLMap();
19715
+ var YAMLSeq = require_YAMLSeq();
19716
+ var cst = require_cst();
19717
+ var lexer = require_lexer();
19718
+ var lineCounter = require_line_counter();
19719
+ var parser = require_parser();
19720
+ var publicApi = require_public_api();
19721
+ var visit = require_visit();
19722
+ exports2.Composer = composer.Composer;
19723
+ exports2.Document = Document.Document;
19724
+ exports2.Schema = Schema.Schema;
19725
+ exports2.YAMLError = errors.YAMLError;
19726
+ exports2.YAMLParseError = errors.YAMLParseError;
19727
+ exports2.YAMLWarning = errors.YAMLWarning;
19728
+ exports2.Alias = Alias.Alias;
19729
+ exports2.isAlias = identity.isAlias;
19730
+ exports2.isCollection = identity.isCollection;
19731
+ exports2.isDocument = identity.isDocument;
19732
+ exports2.isMap = identity.isMap;
19733
+ exports2.isNode = identity.isNode;
19734
+ exports2.isPair = identity.isPair;
19735
+ exports2.isScalar = identity.isScalar;
19736
+ exports2.isSeq = identity.isSeq;
19737
+ exports2.Pair = Pair.Pair;
19738
+ exports2.Scalar = Scalar.Scalar;
19739
+ exports2.YAMLMap = YAMLMap.YAMLMap;
19740
+ exports2.YAMLSeq = YAMLSeq.YAMLSeq;
19741
+ exports2.CST = cst;
19742
+ exports2.Lexer = lexer.Lexer;
19743
+ exports2.LineCounter = lineCounter.LineCounter;
19744
+ exports2.Parser = parser.Parser;
19745
+ exports2.parse = publicApi.parse;
19746
+ exports2.parseAllDocuments = publicApi.parseAllDocuments;
19747
+ exports2.parseDocument = publicApi.parseDocument;
19748
+ exports2.stringify = publicApi.stringify;
19749
+ exports2.visit = visit.visit;
19750
+ exports2.visitAsync = visit.visitAsync;
19751
+ }
19752
+ });
19753
+
19754
+ // ../../packages/jobs/dist/response.js
19755
+ var require_response = __commonJS({
19756
+ "../../packages/jobs/dist/response.js"(exports2) {
19757
+ "use strict";
19758
+ Object.defineProperty(exports2, "__esModule", { value: true });
19759
+ exports2.NonJsonResponseError = exports2.ServiceUnavailableError = void 0;
19760
+ exports2.readJsonResponse = readJsonResponse;
19761
+ var EXCERPT_LIMIT = 120;
19762
+ var UNAVAILABLE_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
19763
+ var UnreadableResponseError = class extends Error {
19764
+ host;
19765
+ statusCode;
19766
+ statusText;
19767
+ contentType;
19768
+ bodyExcerpt;
19769
+ constructor(message, detail) {
19770
+ super(message);
19771
+ this.host = detail.host;
19772
+ this.statusCode = detail.statusCode;
19773
+ this.statusText = detail.statusText;
19774
+ this.contentType = detail.contentType;
19775
+ this.bodyExcerpt = detail.bodyExcerpt;
19776
+ }
19777
+ };
19778
+ var ServiceUnavailableError = class extends UnreadableResponseError {
19779
+ code = "SERVICE_UNAVAILABLE";
19780
+ constructor(detail) {
19781
+ super(`${detail.host} answered ${formatStatus(detail)} (content-type: ${detail.contentType ?? "none"})${detail.bodyExcerpt ? `: ${detail.bodyExcerpt}` : ""}`, detail);
19782
+ this.name = "ServiceUnavailableError";
19783
+ }
19784
+ };
19785
+ exports2.ServiceUnavailableError = ServiceUnavailableError;
19786
+ var NonJsonResponseError = class extends UnreadableResponseError {
19787
+ code = "RESPONSE_NOT_JSON";
19788
+ constructor(detail) {
19789
+ super(`${detail.host} answered ${formatStatus(detail)} with content-type ${detail.contentType ?? "none"}, not JSON${detail.bodyExcerpt ? `: ${detail.bodyExcerpt}` : ""}`, detail);
19790
+ this.name = "NonJsonResponseError";
19791
+ }
19792
+ };
19793
+ exports2.NonJsonResponseError = NonJsonResponseError;
19794
+ function formatStatus(detail) {
19795
+ return detail.statusText ? `${detail.statusCode} ${detail.statusText}` : `${detail.statusCode}`;
19796
+ }
19797
+ function isJson(contentType) {
19798
+ if (!contentType)
19799
+ return false;
19800
+ const essence = contentType.split(";")[0].trim().toLowerCase();
19801
+ return essence === "application/json" || essence.endsWith("+json");
19802
+ }
19803
+ function excerpt(body) {
19804
+ const collapsed = body.replace(/\s+/g, " ").trim();
19805
+ return collapsed.length > EXCERPT_LIMIT ? `${collapsed.slice(0, EXCERPT_LIMIT)}...` : collapsed;
19806
+ }
19807
+ function hostOf(url) {
19808
+ try {
19809
+ return new URL(url).host;
19810
+ } catch {
19811
+ return url;
19812
+ }
19813
+ }
19814
+ async function readJsonResponse(response, url) {
19815
+ const contentType = response.headers.get("content-type");
19816
+ const unavailable = UNAVAILABLE_STATUSES.has(response.status);
19817
+ if (unavailable || !isJson(contentType)) {
19818
+ const body = await response.text().catch(() => "");
19819
+ const detail = {
19820
+ host: hostOf(url),
19821
+ statusCode: response.status,
19822
+ statusText: response.statusText ?? "",
19823
+ contentType,
19824
+ bodyExcerpt: excerpt(body)
19825
+ };
19826
+ throw unavailable ? new ServiceUnavailableError(detail) : new NonJsonResponseError(detail);
19827
+ }
19828
+ return await response.json();
19829
+ }
19830
+ }
19831
+ });
19832
+
19833
+ // ../../packages/jobs/dist/client.js
19834
+ var require_client2 = __commonJS({
19835
+ "../../packages/jobs/dist/client.js"(exports2) {
19836
+ "use strict";
19837
+ Object.defineProperty(exports2, "__esModule", { value: true });
19838
+ exports2.JobsClient = void 0;
19839
+ var response_1 = require_response();
19840
+ var JobsClient = class {
19841
+ baseUrl;
19842
+ apiKey;
19843
+ accessToken;
19844
+ getAccessToken;
19845
+ onResponse;
19846
+ constructor(config) {
19847
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
19848
+ this.apiKey = config.apiKey;
19849
+ this.accessToken = config.accessToken;
19850
+ this.getAccessToken = config.getAccessToken;
19851
+ this.onResponse = config.onResponse;
19852
+ }
19853
+ /**
19854
+ * Headers for one request. The auth header is resolved per call so a
19855
+ * long-lived client picks up a refreshed token from `getAccessToken`
19856
+ * (the manager behind it re-mints before expiry) instead of pinning the
19857
+ * token it happened to hold at construction.
19858
+ */
19859
+ async buildHeaders(forceRefresh = false) {
19860
+ const headers = { "Content-Type": "application/json" };
19861
+ if (this.apiKey) {
19862
+ headers["X-API-Key"] = this.apiKey;
19863
+ } else if (this.getAccessToken) {
19864
+ const token = await this.getAccessToken({ forceRefresh });
19865
+ if (token)
19866
+ headers["Authorization"] = `Bearer ${token}`;
19867
+ } else if (this.accessToken) {
19868
+ headers["Authorization"] = `Bearer ${this.accessToken}`;
19869
+ }
19870
+ return headers;
19871
+ }
19872
+ /**
19873
+ * Fetch with one auth retry. A 401 on a token-provider client usually means
19874
+ * the token was invalidated server-side (Keep restart, key rotation,
19875
+ * revoke-then-repair, clock skew) while the local expiry timer still thinks
19876
+ * it's valid. Force a re-mint and retry once before surfacing the failure.
19877
+ * `onResponse` (min-version contract) fires on the response we actually act
19878
+ * on. `body` is a string, so it is safe to resend.
19879
+ */
19880
+ async fetchWithAuthRetry(method, url, body) {
19881
+ let response = await fetch(url, { method, headers: await this.buildHeaders(), body });
19882
+ if (response.status === 401 && this.getAccessToken) {
19883
+ response = await fetch(url, { method, headers: await this.buildHeaders(true), body });
19884
+ }
19885
+ this.onResponse?.(response);
19886
+ return response;
19887
+ }
19888
+ // ── Job Pools ──────────────────────────────────────────────
19889
+ async createJobPool(options) {
19890
+ return this.request("POST", "/api/job-pools", options);
19891
+ }
19892
+ /**
19893
+ * Idempotent upsert by `(principal_class, principal_id, name)`. When the
19894
+ * pool exists, returns the existing row without modifying membership
19895
+ * constraints. The Sift provisioning hook relies on this semantics.
19896
+ */
19897
+ async findOrCreateJobPool(options) {
19898
+ return this.request("POST", "/api/job-pools?idempotent=true", options);
19899
+ }
19900
+ async listJobPools(filters) {
19901
+ const params = new URLSearchParams();
19902
+ if (filters?.principalClass)
19903
+ params.set("principalClass", filters.principalClass);
19904
+ if (filters?.principalId)
19905
+ params.set("principalId", filters.principalId);
19906
+ if (filters?.name)
19907
+ params.set("name", filters.name);
19908
+ const qs = params.toString();
19909
+ const { pools } = await this.request("GET", `/api/job-pools${qs ? `?${qs}` : ""}`);
19910
+ return pools;
19911
+ }
19912
+ async getJobPool(poolId) {
19913
+ return this.request("GET", `/api/job-pools/${poolId}`);
19914
+ }
19915
+ /**
19916
+ * Resolve a pool by exact name. Names are unique per OWNER, not globally
19917
+ * (whittlelabs#763), and this method lists without a principal filter, so
19918
+ * the same name can legitimately come back under several owners. That
19919
+ * reference is inherently ambiguous — and silently picking one (the old
19920
+ * behavior took the server's newest-first ordering) is exactly the
19921
+ * capture vector the per-owner constraint closed, re-opened cross-owner.
19922
+ * So it refuses instead: reference the pool by id, or list with explicit
19923
+ * principal filters, when more than one owner holds the name.
19924
+ */
19925
+ async resolveJobPoolByName(name) {
19926
+ const pools = await this.listJobPools({ name });
19927
+ const matches = pools.filter((p) => p.name === name);
19928
+ const owners = new Set(matches.map((p) => `${p.principalClass ?? ""}/${p.principalId ?? ""}`));
19929
+ if (owners.size > 1) {
19930
+ const error = new Error(`Job pool name "${name}" is ambiguous: ${matches.length} pools under ${owners.size} different owners hold it. Reference the pool by id, or resolve it with explicit principal filters (listJobPools).`);
19931
+ error.code = "JOB_POOL_NAME_AMBIGUOUS";
19932
+ throw error;
19933
+ }
19934
+ return matches[0];
19935
+ }
19936
+ /** Internal: resolve a `PoolRef` to a pool id. */
19937
+ async resolvePoolRef(ref) {
19938
+ if ("id" in ref)
19939
+ return ref.id;
19940
+ const pool = await this.resolveJobPoolByName(ref.name);
19941
+ if (!pool)
19942
+ throw new Error(`Job pool not found by name: "${ref.name}"`);
19943
+ return pool.id;
19944
+ }
19945
+ // ── Members ──────────────────────────────────────────────────────
19946
+ // A subscriber joins a pool by registering as a member of it. These
19947
+ // map to the server's `/api/job-pools/:poolId/members` routes.
19948
+ async listMembers(poolId) {
19949
+ const { members } = await this.request("GET", `/api/job-pools/${poolId}/members`);
19950
+ return members;
19951
+ }
19952
+ async registerMember(poolId, options) {
19953
+ return this.request("POST", `/api/job-pools/${poolId}/members`, options);
19954
+ }
19955
+ async updateMember(poolId, memberId, options) {
19956
+ return this.request("PUT", `/api/job-pools/${poolId}/members/${memberId}`, options);
19957
+ }
19958
+ // ── Jobs (producer) ──────────────────────────────────────────────
19959
+ /**
19960
+ * Enqueue a job into a job pool. The `inputs` are opaque to Jobs; a Shuttle
19961
+ * reads the strategy header inside them to decide how to run it (ADR 0005).
19962
+ */
19963
+ async enqueueJob(options) {
19964
+ const jobPoolId = await this.resolvePoolRef(options.pool);
19965
+ const body = {
19966
+ jobPoolId,
19967
+ title: options.title,
19968
+ instructions: options.instructions,
19969
+ maxAttempts: options.maxAttempts,
19970
+ deadlineDuration: options.deadlineDuration,
19971
+ claimDeadlineDuration: options.claimDeadlineDuration,
19972
+ priority: options.priority,
19973
+ tags: options.tags,
19974
+ clientRef: options.clientRef,
19975
+ clientContext: options.clientContext,
19976
+ inputs: options.inputs
19977
+ };
19978
+ return this.request("POST", "/api/jobs", body);
19979
+ }
19980
+ async getJob(jobId) {
19981
+ return this.request("GET", `/api/jobs/${jobId}`);
19982
+ }
19983
+ async updateJob(jobId, options) {
19984
+ return this.request("PATCH", `/api/jobs/${jobId}`, options);
19985
+ }
19986
+ async cancelJob(jobId) {
19987
+ return this.request("PUT", `/api/jobs/${jobId}`);
19988
+ }
19989
+ // ── Outputs ──────────────────────────────────────────────────────
19990
+ async listOutputs(jobId) {
19991
+ const all = [];
19992
+ const pageSize = 100;
19993
+ for (let offset = 0; ; offset += pageSize) {
19994
+ const { outputs, total } = await this.request("GET", `/api/jobs/${jobId}/output?limit=${pageSize}&offset=${offset}`);
19995
+ all.push(...outputs);
19996
+ if (outputs.length === 0 || all.length >= total)
19997
+ break;
19998
+ }
19999
+ return all;
20000
+ }
20001
+ async createOutput(jobId, options) {
20002
+ return this.request("POST", `/api/jobs/${jobId}/output`, options);
20003
+ }
20004
+ /**
20005
+ * Post a batch of live progress frames for a running job. Best-effort
20006
+ * telemetry: the service publishes it over core NATS and never derives
20007
+ * authoritative state from it, so callers should swallow failures rather than
20008
+ * let a dropped frame affect the job.
20009
+ */
20010
+ async postProgress(jobId, options) {
20011
+ await this.request("POST", `/api/jobs/${jobId}/progress`, options);
20012
+ }
20013
+ // ── Attendance (subscriber dispatch lifecycle) ───────────────────
20014
+ /**
20015
+ * Accept a dispatched job. The subscribe loop calls this; direct
20016
+ * callers should be rare. Returns the dispatched-job context the
20017
+ * subscriber needs to execute and submit.
20018
+ */
20019
+ async acceptDispatch(jobId) {
20020
+ return this.request("POST", `/api/jobs/${jobId}/attendance`);
20021
+ }
20022
+ async submit(jobId, options) {
20023
+ return this.request("PUT", `/api/jobs/${jobId}/attendance`, options);
20024
+ }
20025
+ // ── Discovery (rare) ─────────────────────────────────────────────
20026
+ async listDispatchableJobs(options) {
20027
+ const params = new URLSearchParams();
20028
+ if (options?.pools?.length)
20029
+ params.set("pools", options.pools.join(","));
20030
+ if (options?.tags?.length)
20031
+ params.set("tags", options.tags.join(","));
20032
+ if (options?.maxAttempts !== void 0)
20033
+ params.set("maxAttempts", String(options.maxAttempts));
20034
+ if (options?.minPriority !== void 0)
20035
+ params.set("minPriority", String(options.minPriority));
20036
+ if (options?.limit !== void 0)
20037
+ params.set("limit", String(options.limit));
20038
+ if (options?.offset !== void 0)
20039
+ params.set("offset", String(options.offset));
20040
+ if (options?.sort)
20041
+ params.set("sort", options.sort);
20042
+ const qs = params.toString();
20043
+ const { jobs, total, directives } = await this.request("GET", `/api/my/jobs${qs ? `?${qs}` : ""}`);
20044
+ return {
20045
+ data: jobs,
20046
+ pagination: { total, limit: options?.limit ?? 25, offset: options?.offset ?? 0 },
20047
+ directives: directives ?? null
20048
+ };
20049
+ }
20050
+ // ── HTTP plumbing ────────────────────────────────────────────────
20051
+ /**
20052
+ * Every call's one reader. `readJsonResponse` refuses to parse a reply that
20053
+ * is not the API's JSON — an ingress 502/503/504 while a pod rolls, or any
20054
+ * non-JSON body — and throws a named failure instead of a parse error. What
20055
+ * comes back here is the API's own envelope, success or not.
20056
+ */
20057
+ async request(method, path, body) {
20058
+ const url = `${this.baseUrl}${path}`;
20059
+ const response = await this.fetchWithAuthRetry(method, url, body ? JSON.stringify(body) : void 0);
20060
+ const json = await (0, response_1.readJsonResponse)(response, url);
20061
+ if (!response.ok || !json.success) {
20062
+ const errorMessage = json.error?.message ?? `Request failed with status ${response.status}`;
20063
+ const error = new Error(errorMessage);
20064
+ error.code = json.error?.code;
20065
+ error.statusCode = response.status;
20066
+ throw error;
20067
+ }
20068
+ return json.data;
20069
+ }
20070
+ };
20071
+ exports2.JobsClient = JobsClient;
20072
+ }
20073
+ });
20074
+
20075
+ // ../../packages/jobs/dist/subscribe.js
20076
+ var require_subscribe = __commonJS({
20077
+ "../../packages/jobs/dist/subscribe.js"(exports2) {
20078
+ "use strict";
20079
+ Object.defineProperty(exports2, "__esModule", { value: true });
20080
+ exports2.subscribe = subscribe;
20081
+ var response_1 = require_response();
20082
+ var NULL_LOGGER = {
20083
+ debug: () => {
20084
+ },
20085
+ info: () => {
20086
+ },
20087
+ warn: () => {
20088
+ },
20089
+ error: () => {
20090
+ }
20091
+ };
20092
+ function sleep(ms) {
20093
+ return new Promise((resolve) => setTimeout(resolve, ms));
20094
+ }
20095
+ function formatDuration(ms) {
20096
+ const seconds = Math.round(ms / 1e3);
20097
+ if (seconds < 60)
20098
+ return `${seconds}s`;
20099
+ const minutes = Math.floor(seconds / 60);
20100
+ const rest = seconds % 60;
20101
+ return rest === 0 ? `${minutes}m` : `${minutes}m ${rest}s`;
20102
+ }
20103
+ function subscribe(opts) {
20104
+ const logger = opts.logger ?? NULL_LOGGER;
20105
+ const pollIntervalMs = opts.pollIntervalMs ?? 2e3;
20106
+ const maxConcurrency = opts.maxConcurrency ?? 1;
20107
+ let stopped = true;
20108
+ let pollTimer = null;
20109
+ let inflight = 0;
20110
+ let resolvedPoolIds = [];
20111
+ let unavailableSince = null;
20112
+ async function start() {
20113
+ if (!stopped)
20114
+ return;
20115
+ stopped = false;
20116
+ resolvedPoolIds = [];
20117
+ for (const ref of opts.pools) {
20118
+ const id = await opts.jobsClient.resolvePoolRef(ref);
20119
+ resolvedPoolIds.push(id);
20120
+ await opts.jobsClient.registerMember(id, {
20121
+ identityType: opts.subscriber.identityType,
20122
+ identityId: opts.subscriber.identityId,
20123
+ intelligence: opts.subscriber.intelligence,
20124
+ ...opts.subscriber.displayName !== void 0 ? { displayName: opts.subscriber.displayName } : {},
20125
+ ...opts.subscriber.metadata !== void 0 ? { metadata: opts.subscriber.metadata } : {}
20126
+ });
20127
+ }
20128
+ logger.info("subscribe loop started", { pools: resolvedPoolIds, maxConcurrency });
20129
+ schedulePoll(pollIntervalMs);
20130
+ }
20131
+ async function stop() {
20132
+ if (stopped)
20133
+ return;
20134
+ stopped = true;
20135
+ if (pollTimer !== null) {
20136
+ clearTimeout(pollTimer);
20137
+ pollTimer = null;
20138
+ }
20139
+ while (inflight > 0) {
20140
+ await sleep(100);
20141
+ }
20142
+ logger.info("subscribe loop stopped");
20143
+ }
20144
+ function schedulePoll(delayMs) {
20145
+ pollTimer = setTimeout(() => {
20146
+ void poll();
20147
+ }, delayMs);
20148
+ }
20149
+ async function poll() {
20150
+ if (stopped)
20151
+ return;
20152
+ if (inflight >= maxConcurrency) {
20153
+ schedulePoll(pollIntervalMs);
20154
+ return;
20155
+ }
20156
+ try {
20157
+ const { data, directives } = await opts.jobsClient.listDispatchableJobs({
20158
+ pools: resolvedPoolIds,
20159
+ limit: maxConcurrency - inflight,
20160
+ sort: "priority:desc,queued_at:asc"
20161
+ });
20162
+ if (unavailableSince !== null) {
20163
+ logger.info(`Sift is reachable again after ${formatDuration(Date.now() - unavailableSince)}`);
20164
+ unavailableSince = null;
20165
+ }
20166
+ if (directives && Object.keys(directives).length > 0 && opts.onDirectives) {
20167
+ try {
20168
+ await opts.onDirectives(directives);
20169
+ } catch (err) {
20170
+ logger.error("onDirectives handler failed", {
20171
+ error: err instanceof Error ? err.message : String(err)
20172
+ });
20173
+ }
20174
+ }
20175
+ if (stopped)
20176
+ return;
20177
+ for (const job of data) {
20178
+ if (inflight >= maxConcurrency)
20179
+ break;
20180
+ inflight++;
20181
+ void runOnce(job).finally(() => {
20182
+ inflight--;
20183
+ });
20184
+ }
20185
+ } catch (err) {
20186
+ if (err instanceof response_1.ServiceUnavailableError) {
20187
+ if (unavailableSince === null) {
20188
+ unavailableSince = Date.now();
20189
+ logger.warn(`Sift is unavailable (${err.host} answered ${err.statusCode}${err.statusText ? ` ${err.statusText}` : ""}). This is typical during a deployment window; the Sifter will keep trying.`);
20190
+ } else {
20191
+ logger.debug?.("Sift still unavailable", {
20192
+ host: err.host,
20193
+ status: err.statusCode,
20194
+ unavailableFor: formatDuration(Date.now() - unavailableSince)
20195
+ });
20196
+ }
20197
+ } else {
20198
+ logger.error("poll failed", { error: err instanceof Error ? err.message : String(err) });
20199
+ }
20200
+ }
20201
+ if (!stopped)
20202
+ schedulePoll(pollIntervalMs);
20203
+ }
20204
+ async function runOnce(available) {
20205
+ let dispatch;
20206
+ try {
20207
+ dispatch = await opts.jobsClient.acceptDispatch(available.id);
20208
+ } catch (err) {
20209
+ const statusCode = err.statusCode;
20210
+ if (statusCode === 409) {
20211
+ logger.debug?.("claim conflict; another member accepted", { jobId: available.id });
20212
+ return;
20213
+ }
20214
+ logger.error("failed to accept dispatch", {
20215
+ jobId: available.id,
20216
+ error: err instanceof Error ? err.message : String(err)
20217
+ });
20218
+ return;
20219
+ }
20220
+ const controller = new AbortController();
20221
+ let quietTimer = null;
20222
+ const quietWindowMs = dispatch.deadline ? new Date(dispatch.deadline).getTime() - Date.now() : null;
20223
+ const armQuietTimer = () => {
20224
+ if (quietWindowMs === null)
20225
+ return;
20226
+ if (quietTimer !== null)
20227
+ clearTimeout(quietTimer);
20228
+ const ms = quietWindowMs - 3e4;
20229
+ if (ms > 0) {
20230
+ quietTimer = setTimeout(() => controller.abort(), ms);
20231
+ } else {
20232
+ controller.abort();
20233
+ }
20234
+ };
20235
+ armQuietTimer();
20236
+ const activity = {
20237
+ record: () => {
20238
+ if (!controller.signal.aborted)
20239
+ armQuietTimer();
20240
+ }
20241
+ };
20242
+ let result;
20243
+ try {
20244
+ result = await opts.onJob(dispatch, controller.signal, activity);
20245
+ } catch (err) {
20246
+ result = {
20247
+ status: "failed",
20248
+ reason: `onJob threw: ${err instanceof Error ? err.message : String(err)}`
20249
+ };
20250
+ } finally {
20251
+ if (quietTimer !== null)
20252
+ clearTimeout(quietTimer);
20253
+ }
20254
+ try {
20255
+ for (const output of result.outputs ?? []) {
20256
+ await opts.jobsClient.createOutput(dispatch.job.id, {
20257
+ label: output.label,
20258
+ content: output.content
20259
+ });
20260
+ }
20261
+ await opts.jobsClient.submit(dispatch.job.id, {
20262
+ status: result.status,
20263
+ ...result.reason !== void 0 ? { reason: result.reason } : {}
20264
+ });
20265
+ } catch (err) {
20266
+ logger.error("submit/close failed", {
20267
+ jobId: dispatch.job.id,
20268
+ error: err instanceof Error ? err.message : String(err)
20269
+ });
20046
20270
  }
20047
20271
  }
20048
- if (prettyErrors && lineCounter2) {
20049
- doc.errors.forEach(errors.prettifyError(source, lineCounter2));
20050
- doc.warnings.forEach(errors.prettifyError(source, lineCounter2));
20051
- }
20052
- return doc;
20053
- }
20054
- function parse(src, reviver, options) {
20055
- let _reviver = void 0;
20056
- if (typeof reviver === "function") {
20057
- _reviver = reviver;
20058
- } else if (options === void 0 && reviver && typeof reviver === "object") {
20059
- options = reviver;
20060
- }
20061
- const doc = parseDocument(src, options);
20062
- if (!doc)
20063
- return null;
20064
- doc.warnings.forEach((warning) => log.warn(doc.options.logLevel, warning));
20065
- if (doc.errors.length > 0) {
20066
- if (doc.options.logLevel !== "silent")
20067
- throw doc.errors[0];
20068
- else
20069
- doc.errors = [];
20070
- }
20071
- return doc.toJS(Object.assign({ reviver: _reviver }, options));
20072
- }
20073
- function stringify(value, replacer, options) {
20074
- let _replacer = null;
20075
- if (typeof replacer === "function" || Array.isArray(replacer)) {
20076
- _replacer = replacer;
20077
- } else if (options === void 0 && replacer) {
20078
- options = replacer;
20079
- }
20080
- if (typeof options === "string")
20081
- options = options.length;
20082
- if (typeof options === "number") {
20083
- const indent = Math.round(options);
20084
- options = indent < 1 ? void 0 : indent > 8 ? { indent: 8 } : { indent };
20085
- }
20086
- if (value === void 0) {
20087
- const { keepUndefined } = options ?? replacer ?? {};
20088
- if (!keepUndefined)
20089
- return void 0;
20090
- }
20091
- if (identity.isDocument(value) && !_replacer)
20092
- return value.toString(options);
20093
- return new Document.Document(value, _replacer, options).toString(options);
20272
+ return { start, stop };
20094
20273
  }
20095
- exports2.parse = parse;
20096
- exports2.parseAllDocuments = parseAllDocuments;
20097
- exports2.parseDocument = parseDocument;
20098
- exports2.stringify = stringify;
20099
20274
  }
20100
20275
  });
20101
20276
 
20102
- // ../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/index.js
20277
+ // ../../packages/jobs/dist/index.js
20103
20278
  var require_dist4 = __commonJS({
20104
- "../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/index.js"(exports2) {
20279
+ "../../packages/jobs/dist/index.js"(exports2) {
20105
20280
  "use strict";
20106
- var composer = require_composer();
20107
- var Document = require_Document();
20108
- var Schema = require_Schema();
20109
- var errors = require_errors3();
20110
- var Alias = require_Alias();
20111
- var identity = require_identity();
20112
- var Pair = require_Pair();
20113
- var Scalar = require_Scalar();
20114
- var YAMLMap = require_YAMLMap();
20115
- var YAMLSeq = require_YAMLSeq();
20116
- var cst = require_cst();
20117
- var lexer = require_lexer();
20118
- var lineCounter = require_line_counter();
20119
- var parser = require_parser();
20120
- var publicApi = require_public_api();
20121
- var visit = require_visit();
20122
- exports2.Composer = composer.Composer;
20123
- exports2.Document = Document.Document;
20124
- exports2.Schema = Schema.Schema;
20125
- exports2.YAMLError = errors.YAMLError;
20126
- exports2.YAMLParseError = errors.YAMLParseError;
20127
- exports2.YAMLWarning = errors.YAMLWarning;
20128
- exports2.Alias = Alias.Alias;
20129
- exports2.isAlias = identity.isAlias;
20130
- exports2.isCollection = identity.isCollection;
20131
- exports2.isDocument = identity.isDocument;
20132
- exports2.isMap = identity.isMap;
20133
- exports2.isNode = identity.isNode;
20134
- exports2.isPair = identity.isPair;
20135
- exports2.isScalar = identity.isScalar;
20136
- exports2.isSeq = identity.isSeq;
20137
- exports2.Pair = Pair.Pair;
20138
- exports2.Scalar = Scalar.Scalar;
20139
- exports2.YAMLMap = YAMLMap.YAMLMap;
20140
- exports2.YAMLSeq = YAMLSeq.YAMLSeq;
20141
- exports2.CST = cst;
20142
- exports2.Lexer = lexer.Lexer;
20143
- exports2.LineCounter = lineCounter.LineCounter;
20144
- exports2.Parser = parser.Parser;
20145
- exports2.parse = publicApi.parse;
20146
- exports2.parseAllDocuments = publicApi.parseAllDocuments;
20147
- exports2.parseDocument = publicApi.parseDocument;
20148
- exports2.stringify = publicApi.stringify;
20149
- exports2.visit = visit.visit;
20150
- exports2.visitAsync = visit.visitAsync;
20281
+ Object.defineProperty(exports2, "__esModule", { value: true });
20282
+ exports2.subscribe = exports2.ServiceUnavailableError = exports2.NonJsonResponseError = exports2.JobsClient = void 0;
20283
+ var client_1 = require_client2();
20284
+ Object.defineProperty(exports2, "JobsClient", { enumerable: true, get: function() {
20285
+ return client_1.JobsClient;
20286
+ } });
20287
+ var response_1 = require_response();
20288
+ Object.defineProperty(exports2, "NonJsonResponseError", { enumerable: true, get: function() {
20289
+ return response_1.NonJsonResponseError;
20290
+ } });
20291
+ Object.defineProperty(exports2, "ServiceUnavailableError", { enumerable: true, get: function() {
20292
+ return response_1.ServiceUnavailableError;
20293
+ } });
20294
+ var subscribe_1 = require_subscribe();
20295
+ Object.defineProperty(exports2, "subscribe", { enumerable: true, get: function() {
20296
+ return subscribe_1.subscribe;
20297
+ } });
20151
20298
  }
20152
20299
  });
20153
20300
 
@@ -20280,7 +20427,7 @@ var require_loader = __commonJS({
20280
20427
  var fs_1 = require("fs");
20281
20428
  var path_1 = require("path");
20282
20429
  var os_1 = require("os");
20283
- var yaml_1 = require_dist4();
20430
+ var yaml_1 = require_dist3();
20284
20431
  var schema_1 = require_schema4();
20285
20432
  var apply_1 = require_apply();
20286
20433
  function fileExists(filePath) {
@@ -20470,8 +20617,10 @@ var require_probes = __commonJS({
20470
20617
  var promises_1 = require("fs/promises");
20471
20618
  var os_1 = __importDefault(require("os"));
20472
20619
  var path_1 = __importDefault(require("path"));
20620
+ var yaml_1 = require_dist3();
20473
20621
  var keep_1 = require_dist2();
20474
- var jobs_1 = require_dist3();
20622
+ var jobs_1 = require_dist4();
20623
+ var scaffold_1 = require_scaffold();
20475
20624
  var loader_1 = require_loader();
20476
20625
  var store_1 = require_store();
20477
20626
  var version_check_1 = require_version_check();
@@ -20495,9 +20644,11 @@ var require_probes = __commonJS({
20495
20644
  };
20496
20645
  let pairingRead;
20497
20646
  let configRead;
20647
+ let scaffoldedRead;
20498
20648
  const versions = /* @__PURE__ */ new Map();
20499
20649
  return {
20500
20650
  nodeVersion: () => process.version,
20651
+ platform: () => process.platform,
20501
20652
  osTmpDir: () => os_1.default.tmpdir(),
20502
20653
  async which(bin) {
20503
20654
  const dirs = (process.env.PATH ?? "").split(path_1.default.delimiter).filter(Boolean);
@@ -20512,12 +20663,13 @@ var require_probes = __commonJS({
20512
20663
  return null;
20513
20664
  },
20514
20665
  async versionOf(bin) {
20515
- if (versions.has(bin))
20516
- return versions.get(bin) ?? null;
20517
- const raw = await runForOutput(bin, ["--version"], VERSION_TIMEOUT_MS);
20518
- const parsed = raw === null ? null : raw.match(/\d+\.\d+\.\d+/)?.[0] ?? null;
20519
- versions.set(bin, parsed);
20520
- return parsed;
20666
+ const known = versions.get(bin);
20667
+ if (known !== void 0)
20668
+ return known;
20669
+ const outcome = await runCapturing(bin, ["--version"], VERSION_TIMEOUT_MS);
20670
+ const result = outcome.ok ? { ran: true, version: outcome.stdout.match(/\d+\.\d+\.\d+/)?.[0] ?? null } : { ran: false, reason: outcome.reason };
20671
+ versions.set(bin, result);
20672
+ return result;
20521
20673
  },
20522
20674
  async reach(url) {
20523
20675
  const controller = new AbortController();
@@ -20595,6 +20747,28 @@ var require_probes = __commonJS({
20595
20747
  }
20596
20748
  return configRead;
20597
20749
  },
20750
+ readScaffoldedConfig() {
20751
+ if (scaffoldedRead !== void 0)
20752
+ return scaffoldedRead;
20753
+ const file = (0, scaffold_1.scaffoldedConfigPath)(options.brand, options.paths.configDir);
20754
+ let raw;
20755
+ try {
20756
+ raw = (0, fs_1.readFileSync)(file, "utf-8");
20757
+ } catch (err) {
20758
+ scaffoldedRead = err.code === "ENOENT" ? { ok: true, value: null } : { ok: false, error: `${file}: ${describe(err)}` };
20759
+ return scaffoldedRead;
20760
+ }
20761
+ try {
20762
+ const parsed = (0, yaml_1.parse)(raw);
20763
+ scaffoldedRead = {
20764
+ ok: true,
20765
+ value: parsed !== null && typeof parsed === "object" ? parsed : {}
20766
+ };
20767
+ } catch (err) {
20768
+ scaffoldedRead = { ok: false, error: `${file}: ${describe(err)}` };
20769
+ }
20770
+ return scaffoldedRead;
20771
+ },
20598
20772
  async mintAgentToken(pairing) {
20599
20773
  const tokens = new keep_1.AgentTokenManager({
20600
20774
  keepApiUrl: pairing.keepApiUrl,
@@ -20661,16 +20835,21 @@ var require_probes = __commonJS({
20661
20835
  latestVersion: () => observedLatest
20662
20836
  };
20663
20837
  }
20664
- function runForOutput(bin, args, timeoutMs) {
20838
+ async function runForOutput(bin, args, timeoutMs) {
20839
+ const outcome = await runCapturing(bin, args, timeoutMs);
20840
+ return outcome.ok ? outcome.stdout : null;
20841
+ }
20842
+ function runCapturing(bin, args, timeoutMs) {
20665
20843
  return new Promise((resolve) => {
20666
20844
  let child;
20667
20845
  try {
20668
20846
  child = (0, child_process_1.spawn)(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
20669
- } catch {
20670
- resolve(null);
20847
+ } catch (err) {
20848
+ resolve({ ok: false, reason: describe(err) });
20671
20849
  return;
20672
20850
  }
20673
20851
  let stdout = "";
20852
+ let stderr = "";
20674
20853
  let settled = false;
20675
20854
  const settle = (value) => {
20676
20855
  if (settled)
@@ -20680,18 +20859,27 @@ var require_probes = __commonJS({
20680
20859
  };
20681
20860
  const timer = setTimeout(() => {
20682
20861
  child.kill("SIGKILL");
20683
- settle(null);
20862
+ settle({ ok: false, reason: `did not finish within ${Math.round(timeoutMs / 1e3)}s` });
20684
20863
  }, timeoutMs);
20685
20864
  child.stdout?.on("data", (chunk) => {
20686
20865
  stdout += chunk.toString("utf8");
20687
20866
  });
20688
- child.on("error", () => {
20867
+ child.stderr?.on("data", (chunk) => {
20868
+ stderr += chunk.toString("utf8");
20869
+ });
20870
+ child.on("error", (err) => {
20689
20871
  clearTimeout(timer);
20690
- settle(null);
20872
+ settle({ ok: false, reason: describe(err) });
20691
20873
  });
20692
- child.on("close", (code) => {
20874
+ child.on("close", (code, signal) => {
20693
20875
  clearTimeout(timer);
20694
- settle(code === 0 ? stdout.trim() : null);
20876
+ if (code === 0) {
20877
+ settle({ ok: true, stdout: stdout.trim() });
20878
+ return;
20879
+ }
20880
+ const status = code === null ? `was killed by ${signal ?? "a signal"}` : `exited ${code}`;
20881
+ const said = stderr.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
20882
+ settle({ ok: false, reason: said ? `${status}: ${said}` : status });
20695
20883
  });
20696
20884
  });
20697
20885
  }
@@ -20782,11 +20970,19 @@ var require_preflight = __commonJS({
20782
20970
  var typed_exit_1 = require_typed_exit();
20783
20971
  async function runPreflight(probes, subject) {
20784
20972
  const verdicts = [];
20973
+ let blockedBy;
20785
20974
  for (const check of checks_1.CHECKS) {
20786
20975
  if (!check.phases.includes(subject.phase))
20787
20976
  continue;
20977
+ if (blockedBy !== void 0) {
20978
+ verdicts.push({ name: check.name, status: "SKIP", detail: `not checked; see ${blockedBy}` });
20979
+ continue;
20980
+ }
20788
20981
  try {
20789
- verdicts.push(await check.run(probes, subject));
20982
+ const verdict = await check.run(probes, subject);
20983
+ verdicts.push(verdict);
20984
+ if (check.prerequisite === true && verdict.status === "FAIL")
20985
+ blockedBy = check.name;
20790
20986
  } catch (err) {
20791
20987
  if ((0, typed_exit_1.isTypedExit)(err))
20792
20988
  throw err;
@@ -22627,6 +22823,8 @@ var require_device_code = __commonJS({
22627
22823
  Object.defineProperty(exports2, "__esModule", { value: true });
22628
22824
  exports2.pair = pair;
22629
22825
  exports2.webFirstRemedy = webFirstRemedy;
22826
+ exports2.noPoolRefusal = noPoolRefusal;
22827
+ exports2.issuedButNotKept = issuedButNotKept;
22630
22828
  var os_1 = require("os");
22631
22829
  var apply_1 = require_apply();
22632
22830
  var version_check_1 = require_version_check();
@@ -22690,14 +22888,22 @@ var require_device_code = __commonJS({
22690
22888
  });
22691
22889
  log(opts.brand.strings?.pairingDoneMessage ?? `Paired ${displayName}.`);
22692
22890
  }
22693
- const jobPools = await discoverMemberPools({
22694
- keepApiUrl: reg.keepApiUrl,
22695
- jobsApiUrl: reg.jobsApiUrl,
22696
- clientId: token.clientId,
22697
- clientSecret: token.clientSecret,
22698
- fetcher,
22699
- brand: opts.brand
22700
- });
22891
+ let jobPools;
22892
+ try {
22893
+ jobPools = await discoverMemberPools({
22894
+ keepApiUrl: reg.keepApiUrl,
22895
+ jobsApiUrl: reg.jobsApiUrl,
22896
+ clientId: token.clientId,
22897
+ clientSecret: token.clientSecret,
22898
+ fetcher,
22899
+ brand: opts.brand
22900
+ });
22901
+ } catch (err) {
22902
+ if ((0, typed_exit_1.isTypedExit)(err))
22903
+ throw err;
22904
+ const reason = err instanceof Error ? err.message : String(err);
22905
+ throw new Error(issuedButNotKept(opts.brand, token.serviceIdentity.displayName, `"${token.serviceIdentity.displayName}" was paired, but its pools could not be read from Jobs: ${reason}`, true));
22906
+ }
22701
22907
  return {
22702
22908
  schemaVersion: 1,
22703
22909
  keepApiUrl: reg.keepApiUrl,
@@ -22747,7 +22953,7 @@ var require_device_code = __commonJS({
22747
22953
  }
22748
22954
  function webFirstRemedy(brand, cause) {
22749
22955
  const reason = cause instanceof Error ? cause.message : String(cause);
22750
- const where = brand.product.webPairingUrl ? brand.product.webPairingUrl : `your ${brand.product.title} web app, under Settings, Sifters`;
22956
+ const where = webPairingPlace(brand);
22751
22957
  return [
22752
22958
  `Could not start browser pairing: ${reason}`,
22753
22959
  "",
@@ -22755,6 +22961,27 @@ var require_device_code = __commonJS({
22755
22961
  `command it shows (${brand.product.cliBinary} init --pairing-code=<code>).`
22756
22962
  ].join("\n");
22757
22963
  }
22964
+ function noPoolRefusal(brand, identity) {
22965
+ return [
22966
+ `"${identity}" was paired, but it has no pool to take work from, so it would never be sent any.`,
22967
+ "Nothing was saved on this machine.",
22968
+ "",
22969
+ `Pools are set up when a pairing starts from the web: open ${webPairingPlace(brand)},`,
22970
+ `remove "${identity}" if it is listed, press Pair a Sifter, and run the command it shows.`
22971
+ ].join("\n");
22972
+ }
22973
+ function issuedButNotKept(brand, identity, reason, restored) {
22974
+ return [
22975
+ reason,
22976
+ "",
22977
+ restored ? "Nothing was saved on this machine, so it is as it was before init." : `Some of what init wrote could not be put back; check ${brand.paths.configDir} before pairing again.`,
22978
+ `Keep has already issued "${identity}", which this machine will not use: open`,
22979
+ `${webPairingPlace(brand)}, remove "${identity}", then pair again from there.`
22980
+ ].join("\n");
22981
+ }
22982
+ function webPairingPlace(brand) {
22983
+ return brand.product.webPairingUrl ? brand.product.webPairingUrl : `your ${brand.product.title} web app, under Settings, Sifters`;
22984
+ }
22758
22985
  function columnsOf(opts) {
22759
22986
  return opts.columns ?? process.stdout.columns;
22760
22987
  }
@@ -23008,7 +23235,9 @@ var require_init = __commonJS({
23008
23235
  Object.defineProperty(exports2, "__esModule", { value: true });
23009
23236
  exports2.buildInitCommand = buildInitCommand;
23010
23237
  var fsp = __importStar(require("fs/promises"));
23238
+ var path_1 = require("path");
23011
23239
  var commander_1 = require_commander();
23240
+ var scaffold_1 = require_scaffold();
23012
23241
  var apply_1 = require_apply();
23013
23242
  var environment_1 = require_environment();
23014
23243
  var device_code_1 = require_device_code();
@@ -23036,17 +23265,6 @@ var require_init = __commonJS({
23036
23265
  console.log(line);
23037
23266
  }
23038
23267
  const paths = (0, apply_1.resolvePaths)(effectiveBrand, profile);
23039
- await fsp.mkdir(paths.configDir, { recursive: true });
23040
- for (const step of effectiveBrand.setupSteps ?? []) {
23041
- if (step.phase === "pre-pair") {
23042
- await step.run({
23043
- brand: effectiveBrand,
23044
- configDir: paths.configDir,
23045
- log: (line) => console.log(line),
23046
- setupOptions
23047
- });
23048
- }
23049
- }
23050
23268
  const preflight = await (0, preflight_1.runPreflight)((0, preflight_1.createProbes)({
23051
23269
  brand: effectiveBrand,
23052
23270
  paths,
@@ -23056,42 +23274,77 @@ var require_init = __commonJS({
23056
23274
  paths,
23057
23275
  phase: "init",
23058
23276
  deep: false,
23059
- ...setupOptions.executor ? { requestedExecutor: setupOptions.executor } : {}
23277
+ ...setupOptions.executor ? { requestedExecutor: setupOptions.executor } : {},
23278
+ ...setupOptions.tmpDir ? { requestedTmpDir: setupOptions.tmpDir } : {}
23060
23279
  });
23061
23280
  (0, preflight_1.printReport)(preflight.verdicts, false);
23062
23281
  if ((0, preflight_1.hasFailure)(preflight.verdicts)) {
23063
23282
  process.exit(preflight_1.PREFLIGHT_EXIT_CODE);
23064
23283
  }
23065
- const pairing = await (0, device_code_1.pair)({
23066
- brand: effectiveBrand,
23067
- pairingCode: options.pairingCode,
23068
- // Keep's answer is the half no local table can predict: it
23069
- // builds `verification_uri` from its OWN configuration, so a
23070
- // tier pointed at a page nobody serves looks exactly like a
23071
- // healthy one until an operator opens the link.
23072
- ...report ? {
23073
- onVerificationUri: (uri) => console.log(asJson ? (0, environment_1.verificationJson)(uri) : (0, environment_1.renderVerificationLine)(uri))
23074
- } : {}
23075
- });
23076
- const store = new store_1.PairingConfigStore(paths.configFile);
23077
- await store.write(pairing);
23078
- const spendStore = new spend_store_1.SpendStore(paths.spendStateFile);
23079
- const seedCaps = {
23080
- dailyTokens: setupOptions.dailyCap ?? effectiveBrand.defaultCaps.dailyTokens,
23081
- monthlyTokens: setupOptions.monthlyCap ?? effectiveBrand.defaultCaps.monthlyTokens,
23082
- dailyUsd: effectiveBrand.defaultCaps.dailyUsd,
23083
- monthlyUsd: effectiveBrand.defaultCaps.monthlyUsd
23084
- };
23085
- await spendStore.setCaps(seedCaps);
23086
- for (const step of effectiveBrand.setupSteps ?? []) {
23087
- if (step.phase === "post-pair") {
23088
- await step.run({
23089
- brand: effectiveBrand,
23090
- configDir: paths.configDir,
23091
- log: (line) => console.log(line),
23092
- setupOptions
23093
- });
23284
+ const createdDir = await fsp.mkdir(paths.configDir, { recursive: true });
23285
+ try {
23286
+ for (const step of effectiveBrand.setupSteps ?? []) {
23287
+ if (step.phase === "pre-pair") {
23288
+ await step.run({
23289
+ brand: effectiveBrand,
23290
+ configDir: paths.configDir,
23291
+ log: (line) => console.log(line),
23292
+ setupOptions
23293
+ });
23294
+ }
23295
+ }
23296
+ const pairing = await (0, device_code_1.pair)({
23297
+ brand: effectiveBrand,
23298
+ pairingCode: options.pairingCode,
23299
+ // Keep's answer is the half no local table can predict: it
23300
+ // builds `verification_uri` from its OWN configuration, so a
23301
+ // tier pointed at a page nobody serves looks exactly like a
23302
+ // healthy one until an operator opens the link.
23303
+ ...report ? {
23304
+ onVerificationUri: (uri) => console.log(asJson ? (0, environment_1.verificationJson)(uri) : (0, environment_1.renderVerificationLine)(uri))
23305
+ } : {}
23306
+ });
23307
+ const identity = pairing.serviceIdentity.displayName;
23308
+ if (pairing.jobPools.length === 0) {
23309
+ throw new Error((0, device_code_1.noPoolRefusal)(effectiveBrand, identity));
23310
+ }
23311
+ const written = await snapshot([
23312
+ paths.configFile,
23313
+ paths.spendStateFile,
23314
+ (0, scaffold_1.scaffoldedConfigPath)(effectiveBrand, paths.configDir)
23315
+ ]);
23316
+ try {
23317
+ const store = new store_1.PairingConfigStore(paths.configFile);
23318
+ await store.write(pairing);
23319
+ const spendStore = new spend_store_1.SpendStore(paths.spendStateFile);
23320
+ const seedCaps = {
23321
+ dailyTokens: setupOptions.dailyCap ?? effectiveBrand.defaultCaps.dailyTokens,
23322
+ monthlyTokens: setupOptions.monthlyCap ?? effectiveBrand.defaultCaps.monthlyTokens,
23323
+ dailyUsd: effectiveBrand.defaultCaps.dailyUsd,
23324
+ monthlyUsd: effectiveBrand.defaultCaps.monthlyUsd
23325
+ };
23326
+ await spendStore.setCaps(seedCaps);
23327
+ for (const step of effectiveBrand.setupSteps ?? []) {
23328
+ if (step.phase === "post-pair") {
23329
+ await step.run({
23330
+ brand: effectiveBrand,
23331
+ configDir: paths.configDir,
23332
+ log: (line) => console.log(line),
23333
+ setupOptions
23334
+ });
23335
+ }
23336
+ }
23337
+ } catch (err) {
23338
+ if ((0, typed_exit_1.isTypedExit)(err))
23339
+ throw err;
23340
+ const restored = await restore(written);
23341
+ const reason = err instanceof Error ? err.message : String(err);
23342
+ throw new Error((0, device_code_1.issuedButNotKept)(effectiveBrand, identity, `"${identity}" was paired, but saving it on this machine failed: ${reason}`, restored));
23094
23343
  }
23344
+ } catch (err) {
23345
+ if (createdDir !== void 0)
23346
+ await removeEmptyDirs(paths.configDir, createdDir);
23347
+ throw err;
23095
23348
  }
23096
23349
  const profileFlag = profile === apply_1.DEFAULT_PROFILE ? "" : ` --profile ${profile}`;
23097
23350
  console.log("");
@@ -23111,6 +23364,52 @@ var require_init = __commonJS({
23111
23364
  }
23112
23365
  });
23113
23366
  }
23367
+ async function snapshot(files) {
23368
+ const out = [];
23369
+ for (const path of files) {
23370
+ try {
23371
+ out.push({ path, before: await fsp.readFile(path) });
23372
+ } catch (err) {
23373
+ if (err.code !== "ENOENT")
23374
+ throw err;
23375
+ out.push({ path, before: null });
23376
+ }
23377
+ }
23378
+ return out;
23379
+ }
23380
+ async function restore(files) {
23381
+ let clean = true;
23382
+ for (const { path, before } of files) {
23383
+ await fsp.rm(`${path}.tmp`, { force: true }).catch(() => {
23384
+ clean = false;
23385
+ });
23386
+ try {
23387
+ if (before === null)
23388
+ await fsp.rm(path, { force: true });
23389
+ else
23390
+ await fsp.writeFile(path, before);
23391
+ } catch {
23392
+ clean = false;
23393
+ }
23394
+ }
23395
+ return clean;
23396
+ }
23397
+ async function removeEmptyDirs(deepest, top) {
23398
+ let current = deepest;
23399
+ for (; ; ) {
23400
+ try {
23401
+ await fsp.rmdir(current);
23402
+ } catch {
23403
+ return;
23404
+ }
23405
+ if (current === top)
23406
+ return;
23407
+ const parent = (0, path_1.dirname)(current);
23408
+ if (parent === current)
23409
+ return;
23410
+ current = parent;
23411
+ }
23412
+ }
23114
23413
  function profileFlagDescription(brand) {
23115
23414
  const known = Object.keys(brand.environments ?? {}).sort();
23116
23415
  const base = 'Config profile to pair into (isolates this pairing under its own dir; default "default")';
@@ -24650,7 +24949,7 @@ var require_shuttle = __commonJS({
24650
24949
  exports2.mergeExecutorDefaults = mergeExecutorDefaults;
24651
24950
  exports2.resolveAuth = resolveAuth;
24652
24951
  var os_1 = require("os");
24653
- var jobs_1 = require_dist3();
24952
+ var jobs_1 = require_dist4();
24654
24953
  var self_update_1 = require_self_update();
24655
24954
  var decommission_1 = require_decommission();
24656
24955
  var loom_1 = require_dist();
@@ -25415,8 +25714,8 @@ var require_dist5 = __commonJS({
25415
25714
  "../../packages/shuttle/dist/index.js"(exports2) {
25416
25715
  "use strict";
25417
25716
  Object.defineProperty(exports2, "__esModule", { value: true });
25418
- exports2.listPairings = exports2.PairingConfigStore = exports2.pair = exports2.DEFAULT_REFUSAL_MESSAGE = exports2.DEFAULT_MONTHLY_PERIOD = exports2.DEFAULT_DAILY_PERIOD = exports2.SUBSTRATE_BRAND = exports2.verificationJson = exports2.resolveEnvironment = exports2.renderVerificationLine = exports2.renderEnvironmentReport = exports2.isWorthReporting = exports2.hostOf = exports2.environmentReportJson = exports2.applyEnvironment = exports2.renderTemplate = exports2.expandHome = exports2.resolvePaths = exports2.SpendStore = exports2.AuditLogStore = exports2.createSpendTrackerObserver = exports2.createAuditLogObserver = exports2.createLoggerObserver = exports2.SpendCapExceeded = exports2.ObserverChain = exports2.createCustomScriptExecutor = exports2.createWebhookExecutor = exports2.createHttpApiExecutor = exports2.createClaudeCodeExecutor = exports2.ExecutorRegistry = exports2.AgentCredentialRevokedError = exports2.runPreflight = exports2.renderLines = exports2.renderJson = exports2.printReport = exports2.hasFailure = exports2.createProbes = exports2.checksFor = exports2.PREFLIGHT_FLOORS = exports2.PREFLIGHT_EXIT_CODE = exports2.CHECKS = exports2.readResponseLatestVersion = exports2.checkResponseMinVersion = exports2.compareSemver = exports2.UpgradeRequiredError = exports2.LATEST_VERSION_HEADER = exports2.MIN_VERSION_HEADER = exports2.loadConfig = exports2.Shuttle = exports2.createCli = void 0;
25419
- exports2.revokePairing = void 0;
25717
+ exports2.pair = exports2.scaffoldedConfigPath = exports2.planScaffold = exports2.DEFAULT_REFUSAL_MESSAGE = exports2.DEFAULT_MONTHLY_PERIOD = exports2.DEFAULT_DAILY_PERIOD = exports2.SUBSTRATE_BRAND = exports2.verificationJson = exports2.resolveEnvironment = exports2.renderVerificationLine = exports2.renderEnvironmentReport = exports2.isWorthReporting = exports2.hostOf = exports2.environmentReportJson = exports2.applyEnvironment = exports2.renderTemplate = exports2.expandHome = exports2.resolvePaths = exports2.SpendStore = exports2.AuditLogStore = exports2.createSpendTrackerObserver = exports2.createAuditLogObserver = exports2.createLoggerObserver = exports2.SpendCapExceeded = exports2.ObserverChain = exports2.createCustomScriptExecutor = exports2.createWebhookExecutor = exports2.createHttpApiExecutor = exports2.createClaudeCodeExecutor = exports2.ExecutorRegistry = exports2.AgentCredentialRevokedError = exports2.runPreflight = exports2.renderLines = exports2.renderJson = exports2.printReport = exports2.hasFailure = exports2.createProbes = exports2.checksFor = exports2.PREFLIGHT_FLOORS = exports2.PREFLIGHT_EXIT_CODE = exports2.CHECKS = exports2.readResponseLatestVersion = exports2.checkResponseMinVersion = exports2.compareSemver = exports2.UpgradeRequiredError = exports2.LATEST_VERSION_HEADER = exports2.MIN_VERSION_HEADER = exports2.loadConfig = exports2.Shuttle = exports2.createCli = void 0;
25718
+ exports2.revokePairing = exports2.listPairings = exports2.PairingConfigStore = void 0;
25420
25719
  var cli_1 = require_cli();
25421
25720
  Object.defineProperty(exports2, "createCli", { enumerable: true, get: function() {
25422
25721
  return cli_1.createCli;
@@ -25578,6 +25877,13 @@ var require_dist5 = __commonJS({
25578
25877
  Object.defineProperty(exports2, "DEFAULT_REFUSAL_MESSAGE", { enumerable: true, get: function() {
25579
25878
  return defaults_1.DEFAULT_REFUSAL_MESSAGE;
25580
25879
  } });
25880
+ var scaffold_1 = require_scaffold();
25881
+ Object.defineProperty(exports2, "planScaffold", { enumerable: true, get: function() {
25882
+ return scaffold_1.planScaffold;
25883
+ } });
25884
+ Object.defineProperty(exports2, "scaffoldedConfigPath", { enumerable: true, get: function() {
25885
+ return scaffold_1.scaffoldedConfigPath;
25886
+ } });
25581
25887
  var device_code_1 = require_device_code();
25582
25888
  Object.defineProperty(exports2, "pair", { enumerable: true, get: function() {
25583
25889
  return device_code_1.pair;
@@ -25602,9 +25908,9 @@ var import_shuttle2 = __toESM(require_dist5());
25602
25908
  // src/brand.ts
25603
25909
  var import_path = require("path");
25604
25910
  var import_promises = require("fs/promises");
25605
- var import_yaml = __toESM(require_dist4());
25911
+ var import_yaml = __toESM(require_dist3());
25606
25912
  var import_shuttle = __toESM(require_dist5());
25607
- var buildVersion = true ? "0.30.7" : pkg.version;
25913
+ var buildVersion = true ? "0.30.8" : pkg.version;
25608
25914
  var sifterBrand = {
25609
25915
  product: {
25610
25916
  id: "sifter",
@@ -25628,6 +25934,10 @@ var sifterBrand = {
25628
25934
  configSearchPaths: ["~/.sifter/sifter.yaml"]
25629
25935
  },
25630
25936
  executorAllowlist: ["claude-code", "anthropic-api", "http-api", "webhook", "custom-script"],
25937
+ // What `init` configures when neither --executor nor an existing
25938
+ // sifter.yaml names one. The init pre-flight reads it too, to check git and
25939
+ // claude before the pairing code is spent.
25940
+ defaultExecutor: "claude-code",
25631
25941
  // Floors the pre-flight enforces on the binaries the claude-code executor
25632
25942
  // spawns. Both are deliberately conservative — below the floor FAILS, so a
25633
25943
  // number chosen for tidiness rather than necessity would refuse a working
@@ -25727,14 +26037,14 @@ var sifterBrand = {
25727
26037
  // executor block (e.g. a claude-code `tmpDir`) and polling unless a fresh
25728
26038
  // flag overrides them, and log what happened. We only (re)scaffold an
25729
26039
  // executor block when there isn't one to preserve.
26040
+ //
26041
+ // Which executor, and whether its block is kept, is `planScaffold`'s
26042
+ // call, the same one the init pre-flight made before the pairing code
26043
+ // was spent. A pairing with no pools never reaches this step: init
26044
+ // refuses it before writing anything.
25730
26045
  run: async (ctx) => {
25731
- const yamlPath = (0, import_path.join)(ctx.configDir, "sifter.yaml");
26046
+ const yamlPath = (0, import_shuttle.scaffoldedConfigPath)(ctx.brand, ctx.configDir);
25732
26047
  const pairing = new import_shuttle.PairingConfigStore((0, import_path.join)(ctx.configDir, "config.json")).read();
25733
- if (pairing.jobPools.length === 0) {
25734
- throw new Error(
25735
- "Pairing returned no job pools. The Sift backend should have provisioned one for this user during pre-pair."
25736
- );
25737
- }
25738
26048
  let existing = {};
25739
26049
  try {
25740
26050
  existing = (0, import_yaml.parse)(await (0, import_promises.readFile)(yamlPath, "utf8")) ?? {};
@@ -25743,10 +26053,15 @@ var sifterBrand = {
25743
26053
  }
25744
26054
  const isUpdate = Object.keys(existing).length > 0;
25745
26055
  const existingExecutors = existing.executors ?? {};
25746
- const existingPools = Array.isArray(existing.pools) ? existing.pools : [];
25747
- const priorExecutor = typeof existingPools[0]?.executor === "string" ? existingPools[0].executor : void 0;
25748
- const executor = ctx.setupOptions.executor ?? priorExecutor ?? "claude-code";
25749
- const executorBlock = !ctx.setupOptions.executor && existingExecutors[executor] !== void 0 ? existingExecutors[executor] : await buildExecutorBlock(executor, ctx);
26056
+ const plan = (0, import_shuttle.planScaffold)(ctx.brand, ctx.setupOptions, existing);
26057
+ const executor = plan.executor;
26058
+ if (executor === void 0) {
26059
+ throw new Error("No executor to configure: pass --executor.");
26060
+ }
26061
+ const executorBlock = plan.keptBlock !== void 0 ? {
26062
+ ...plan.keptBlock,
26063
+ ...executor === "claude-code" && ctx.setupOptions.tmpDir ? { tmpDir: ctx.setupOptions.tmpDir } : {}
26064
+ } : await buildExecutorBlock(executor, ctx);
25750
26065
  const doc = {
25751
26066
  auth: {
25752
26067
  jobsApiUrl: pairing.jobsApiUrl