@brainervirus/workit-pi 7.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/worker.js CHANGED
@@ -8457,26 +8457,31 @@ var versionSourceSchema = discriminatedUnion("kind", [
8457
8457
  object({ kind: literal("manual") }).strict()
8458
8458
  ]);
8459
8459
  var releaseTrackSchema = object({
8460
- strategy: branchPreset,
8460
+ strategy: branchPreset.optional(),
8461
8461
  productionBranch: nonBlank,
8462
8462
  integrationBranch: nonBlank,
8463
- naming: object({ feature: nonBlank, release: nonBlank, hotfix: nonBlank }).strict(),
8464
- baseBranch: nonBlank,
8465
- mergeBackBranches: array(nonBlank),
8466
- pullRequestTarget: nonBlank,
8467
- tagNamespace: string2(),
8468
- versionSource: versionSourceSchema,
8469
- requiredChecks: array(nonBlank)
8470
- }).strict().superRefine((track, context) => {
8463
+ naming: object({
8464
+ feature: nonBlank.optional(),
8465
+ release: nonBlank.optional(),
8466
+ hotfix: nonBlank.optional()
8467
+ }).passthrough().optional(),
8468
+ baseBranch: nonBlank.optional(),
8469
+ mergeBackBranches: array(nonBlank).optional(),
8470
+ pullRequestTarget: nonBlank.optional(),
8471
+ tagNamespace: string2().optional(),
8472
+ versionSource: versionSourceSchema.optional(),
8473
+ requiredChecks: array(nonBlank).optional(),
8474
+ critical: array(nonBlank).optional()
8475
+ }).passthrough().superRefine((track, context) => {
8471
8476
  for (const [field, values] of [
8472
- ["mergeBackBranches", track.mergeBackBranches],
8473
- ["requiredChecks", track.requiredChecks]
8477
+ ["mergeBackBranches", track.mergeBackBranches ?? []],
8478
+ ["requiredChecks", track.requiredChecks ?? []]
8474
8479
  ]) {
8475
8480
  if (new Set(values).size !== values.length) {
8476
8481
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
8477
8482
  }
8478
8483
  }
8479
- if (track.versionSource.kind === "package-json" && (path2.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
8484
+ if (track.versionSource?.kind === "package-json" && (path2.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
8480
8485
  context.addIssue({
8481
8486
  code: "custom",
8482
8487
  path: ["versionSource", "path"],
@@ -8539,6 +8544,22 @@ var workspacesFileSchema = object({ workspaces: array(workspaceConfigSchema).opt
8539
8544
  var runtimeWorkspaceIndexSchema = object({
8540
8545
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
8541
8546
  }).passthrough();
8547
+
8548
+ // packages/workit-core/src/core/release-tracks.ts
8549
+ var KNOWN_FIELDS = new Set([
8550
+ "strategy",
8551
+ "productionBranch",
8552
+ "integrationBranch",
8553
+ "naming",
8554
+ "baseBranch",
8555
+ "mergeBackBranches",
8556
+ "pullRequestTarget",
8557
+ "tagNamespace",
8558
+ "versionSource",
8559
+ "requiredChecks",
8560
+ "critical"
8561
+ ]);
8562
+ var memo2 = new Map;
8542
8563
  // packages/workit-core/src/core/policy/judgment.ts
8543
8564
  var LEGACY_KEYS = new Set(["assessment", "facts", "signals", "consequences", "verification"]);
8544
8565
  var YES = new Set(["true", "yes", "y", "1", "on"]);
package/dist/workit.js CHANGED
@@ -3,7 +3,7 @@ import { randomUUID as randomUUID5 } from "node:crypto";
3
3
  import { fileURLToPath as fileURLToPath2 } from "node:url";
4
4
 
5
5
  // packages/workit-core/src/core.ts
6
- import { spawnSync as spawnSync11 } from "node:child_process";
6
+ import { spawnSync as spawnSync12 } from "node:child_process";
7
7
  import { existsSync as existsSync7, realpathSync as realpathSync5 } from "node:fs";
8
8
  import path19 from "node:path";
9
9
 
@@ -12420,6 +12420,11 @@ function worktreeSignal(cwd, options = {}) {
12420
12420
  }
12421
12421
  return `sig:${hash.digest("hex")}`;
12422
12422
  }
12423
+ function mergeBase(cwd, a, b) {
12424
+ if (!safeArg(a) || !safeArg(b))
12425
+ return null;
12426
+ return line(git2(cwd, ["merge-base", a, b]));
12427
+ }
12423
12428
  function patchId(cwd, base, head) {
12424
12429
  if (!safeArg(base) || !safeArg(head))
12425
12430
  return null;
@@ -12443,9 +12448,33 @@ function patchId(cwd, base, head) {
12443
12448
  const id = git2(cwd, ["patch-id", "--stable"], { input: diff.stdout });
12444
12449
  return line(id)?.split(/\s+/u)[0] ?? null;
12445
12450
  }
12451
+ function remoteNames(cwd) {
12452
+ return (git2(cwd, ["remote"]).stdout ?? "").split(/\r?\n/u).map((value) => value.trim()).filter(Boolean);
12453
+ }
12454
+ function resolveRef(cwd, ref) {
12455
+ if (!safeArg(ref))
12456
+ return null;
12457
+ return line(git2(cwd, ["rev-parse", "--verify", "-q", `${ref}^{commit}`]));
12458
+ }
12459
+ var config2 = (cwd, key) => line(git2(cwd, ["config", "--get", key]));
12446
12460
  function currentBranch(cwd) {
12447
12461
  return line(git2(cwd, ["symbolic-ref", "--short", "-q", "HEAD"]));
12448
12462
  }
12463
+ function pushRemoteName(cwd, branch) {
12464
+ const name = branch ?? currentBranch(cwd);
12465
+ const remotes = remoteNames(cwd);
12466
+ const candidates = [
12467
+ name ? config2(cwd, `branch.${name}.pushRemote`) : null,
12468
+ config2(cwd, "remote.pushDefault"),
12469
+ name ? config2(cwd, `branch.${name}.remote`) : null
12470
+ ];
12471
+ for (const candidate of candidates)
12472
+ if (candidate && candidate !== "." && remotes.includes(candidate))
12473
+ return candidate;
12474
+ if (remotes.includes("origin"))
12475
+ return "origin";
12476
+ return remotes.length === 1 ? remotes[0] : null;
12477
+ }
12449
12478
 
12450
12479
  // packages/workit-core/src/core/policy/derive.ts
12451
12480
  import { existsSync as existsSync3 } from "node:fs";
@@ -13895,7 +13924,7 @@ var exportDigest = (bundle) => sha256({
13895
13924
  task: bundle.task
13896
13925
  });
13897
13926
  // packages/workit-core/src/core/branch.ts
13898
- import { createHash as createHash9 } from "node:crypto";
13927
+ import { createHash as createHash10 } from "node:crypto";
13899
13928
 
13900
13929
  // packages/workit-core/src/core/git.ts
13901
13930
  import { execFileSync } from "node:child_process";
@@ -14125,6 +14154,8 @@ var readConfig = () => {
14125
14154
  throw new Error(result.error);
14126
14155
  return result.config ?? DEFAULTS;
14127
14156
  };
14157
+ var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path12.join(configDir(), "vcs.json");
14158
+ var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
14128
14159
  var resolveBranchPolicy = (config, workspace) => {
14129
14160
  const wp = workspace?.branchPolicy ?? {};
14130
14161
  const preset = Object.hasOwn(PRESETS, wp.preset) ? wp.preset : config.branchPolicy?.preset ?? "gitflow";
@@ -14132,7 +14163,7 @@ var resolveBranchPolicy = (config, workspace) => {
14132
14163
  allowed: wp.allowed,
14133
14164
  protectedNames: wp.protected
14134
14165
  }, config);
14135
- const allowed = merged.allowed.map((p) => new RegExp(`^${p.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"));
14166
+ const allowed = merged.allowed.map(branchGlobPattern);
14136
14167
  return {
14137
14168
  preset,
14138
14169
  allowed,
@@ -14197,26 +14228,31 @@ var versionSourceSchema = discriminatedUnion("kind", [
14197
14228
  object({ kind: literal("manual") }).strict()
14198
14229
  ]);
14199
14230
  var releaseTrackSchema = object({
14200
- strategy: branchPreset,
14231
+ strategy: branchPreset.optional(),
14201
14232
  productionBranch: nonBlank,
14202
14233
  integrationBranch: nonBlank,
14203
- naming: object({ feature: nonBlank, release: nonBlank, hotfix: nonBlank }).strict(),
14204
- baseBranch: nonBlank,
14205
- mergeBackBranches: array(nonBlank),
14206
- pullRequestTarget: nonBlank,
14207
- tagNamespace: string2(),
14208
- versionSource: versionSourceSchema,
14209
- requiredChecks: array(nonBlank)
14210
- }).strict().superRefine((track, context) => {
14234
+ naming: object({
14235
+ feature: nonBlank.optional(),
14236
+ release: nonBlank.optional(),
14237
+ hotfix: nonBlank.optional()
14238
+ }).passthrough().optional(),
14239
+ baseBranch: nonBlank.optional(),
14240
+ mergeBackBranches: array(nonBlank).optional(),
14241
+ pullRequestTarget: nonBlank.optional(),
14242
+ tagNamespace: string2().optional(),
14243
+ versionSource: versionSourceSchema.optional(),
14244
+ requiredChecks: array(nonBlank).optional(),
14245
+ critical: array(nonBlank).optional()
14246
+ }).passthrough().superRefine((track, context) => {
14211
14247
  for (const [field, values] of [
14212
- ["mergeBackBranches", track.mergeBackBranches],
14213
- ["requiredChecks", track.requiredChecks]
14248
+ ["mergeBackBranches", track.mergeBackBranches ?? []],
14249
+ ["requiredChecks", track.requiredChecks ?? []]
14214
14250
  ]) {
14215
14251
  if (new Set(values).size !== values.length) {
14216
14252
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
14217
14253
  }
14218
14254
  }
14219
- if (track.versionSource.kind === "package-json" && (path13.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
14255
+ if (track.versionSource?.kind === "package-json" && (path13.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
14220
14256
  context.addIssue({
14221
14257
  code: "custom",
14222
14258
  path: ["versionSource", "path"],
@@ -14484,7 +14520,7 @@ var resolveRuntimeWorkspaceVcs = (cwd) => resolveRuntimeWorkspaceCandidate(cwd,
14484
14520
  var runtimeWorkspaceIndexSchema = object({
14485
14521
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
14486
14522
  }).passthrough();
14487
- var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
14523
+ var matchRuntimeWorkspace = (cwd) => {
14488
14524
  const file = path13.join(configDir(), "workspaces.json");
14489
14525
  let raw;
14490
14526
  try {
@@ -14519,8 +14555,17 @@ var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
14519
14555
  });
14520
14556
  const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
14521
14557
  const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
14522
- if (!selected)
14558
+ return selected ? { file, selected } : null;
14559
+ };
14560
+ var resolveRuntimeReleaseTracks = (cwd) => {
14561
+ const matched = matchRuntimeWorkspace(cwd);
14562
+ return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
14563
+ };
14564
+ var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
14565
+ const matched = matchRuntimeWorkspace(cwd);
14566
+ if (!matched)
14523
14567
  return null;
14568
+ const { file, selected } = matched;
14524
14569
  const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
14525
14570
  if (!policy.success) {
14526
14571
  const detail = policy.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspace"}: ${issue.message}`).join("; ");
@@ -14546,15 +14591,423 @@ var resolveRuntimeWorkspacePolicy = (cwd, kind, requestedProfile) => {
14546
14591
  source: profilePolicy ? `profile:${profileName}` : workspacePolicy ? `workspace:${candidate.name}` : "user-default"
14547
14592
  };
14548
14593
  };
14594
+ function workspaceDefaultTarget(cwd, globalDefault) {
14595
+ const ws = resolveRuntimeWorkspaceVcs(cwd);
14596
+ const wp = ws?.branchPolicy ?? {};
14597
+ const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
14598
+ const selected = resolveRuntimeWorkspacePolicy(cwd, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined);
14599
+ const policyDefault = resolveBranchPolicy(readConfig(), selected.policy ? { branchPolicy: selected.policy } : null).defaultTargetBranch;
14600
+ return String(ws?.vcs?.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : globalDefault ?? policyDefault) ?? "develop");
14601
+ }
14549
14602
 
14550
14603
  // packages/workit-core/src/core/vcs-config.ts
14551
14604
  import fs12 from "node:fs";
14552
14605
  import path14 from "node:path";
14606
+ import { spawnSync as spawnSync8 } from "node:child_process";
14607
+
14608
+ // packages/workit-core/src/core/release-tracks.ts
14609
+ import { createHash as createHash9 } from "node:crypto";
14553
14610
  import { spawnSync as spawnSync7 } from "node:child_process";
14554
- var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path14.join(configDir(), "vcs.json");
14611
+ class ReleaseTrackError extends Error {
14612
+ }
14613
+ var KNOWN_FIELDS = new Set([
14614
+ "strategy",
14615
+ "productionBranch",
14616
+ "integrationBranch",
14617
+ "naming",
14618
+ "baseBranch",
14619
+ "mergeBackBranches",
14620
+ "pullRequestTarget",
14621
+ "tagNamespace",
14622
+ "versionSource",
14623
+ "requiredChecks",
14624
+ "critical"
14625
+ ]);
14626
+ var BRANCH_FIELDS = ["productionBranch", "integrationBranch", "baseBranch", "pullRequestTarget"];
14627
+ var PLACEHOLDER = /\{[^}]*\}/gu;
14628
+ var HAS_PLACEHOLDER = /\{[^}]*\}/u;
14629
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
14630
+ var branchName = (value) => typeof value === "string" && value.trim() && !value.trim().startsWith("-") ? value.trim() : null;
14631
+ var namedBranches = (entry) => [
14632
+ ...BRANCH_FIELDS.map((field) => branchName(entry[field])),
14633
+ ...Array.isArray(entry.mergeBackBranches) ? entry.mergeBackBranches.map(branchName) : []
14634
+ ].filter((name) => name !== null);
14635
+ var literalOf = (template) => template.replace(PLACEHOLDER, "").replace(/[*/]/gu, "").trim();
14636
+ function readReleaseTracks(raw) {
14637
+ const out = { tracks: [], issues: [], error: null, protectedBranches: [] };
14638
+ if (raw === undefined || raw === null)
14639
+ return out;
14640
+ if (!isRecord3(raw)) {
14641
+ out.issues.push("releaseTracks is not an object; ignored");
14642
+ return out;
14643
+ }
14644
+ const fatal = [];
14645
+ const protectedNames = new Set;
14646
+ for (const [name, entry] of Object.entries(raw).toSorted(([a], [b]) => a < b ? -1 : 1)) {
14647
+ const label = `release track ${JSON.stringify(name)}`;
14648
+ if (!isRecord3(entry)) {
14649
+ out.issues.push(`${label} is not an object; ignored`);
14650
+ continue;
14651
+ }
14652
+ for (const branch of namedBranches(entry))
14653
+ protectedNames.add(branch);
14654
+ if (!name.trim()) {
14655
+ out.issues.push("a release track with a blank name was ignored");
14656
+ continue;
14657
+ }
14658
+ let critical = [];
14659
+ if (Array.isArray(entry.critical))
14660
+ critical = entry.critical.filter((item) => typeof item === "string");
14661
+ else if (entry.critical !== undefined)
14662
+ out.issues.push(`${label} critical: must be a list of field names; ignored`);
14663
+ const isCritical = (field) => critical.some((item) => field === item || field.startsWith(`${item}.`));
14664
+ const problem = (field, message) => {
14665
+ if (isCritical(field))
14666
+ fatal.push(`${label} ${field}: ${message}`);
14667
+ else
14668
+ out.issues.push(`${label} ${field}: ${message}`);
14669
+ };
14670
+ for (const key of Object.keys(entry))
14671
+ if (!KNOWN_FIELDS.has(key))
14672
+ problem(key, "unknown field, ignored");
14673
+ const productionBranch = branchName(entry.productionBranch);
14674
+ const integrationBranch = branchName(entry.integrationBranch);
14675
+ if (!productionBranch)
14676
+ problem("productionBranch", "missing or not a branch name");
14677
+ if (!integrationBranch)
14678
+ problem("integrationBranch", "missing or not a branch name");
14679
+ const optionalBranch = (field) => {
14680
+ if (entry[field] === undefined)
14681
+ return null;
14682
+ const value = branchName(entry[field]);
14683
+ if (!value)
14684
+ problem(field, "not a branch name; using the integration branch");
14685
+ return value;
14686
+ };
14687
+ const baseBranch = optionalBranch("baseBranch");
14688
+ const pullRequestTarget = optionalBranch("pullRequestTarget");
14689
+ let mergeBackBranches = [];
14690
+ if (entry.mergeBackBranches !== undefined) {
14691
+ const list = Array.isArray(entry.mergeBackBranches) ? entry.mergeBackBranches.map(branchName) : [null];
14692
+ if (list.some((item) => item === null))
14693
+ problem("mergeBackBranches", "must be a list of branch names; ignored");
14694
+ else
14695
+ mergeBackBranches = [...new Set(list)];
14696
+ }
14697
+ const naming = {};
14698
+ if (entry.naming !== undefined) {
14699
+ if (!isRecord3(entry.naming))
14700
+ problem("naming", "not an object; ignored");
14701
+ else
14702
+ for (const kind of ["feature", "release", "hotfix"]) {
14703
+ const template = entry.naming[kind];
14704
+ if (template === undefined)
14705
+ continue;
14706
+ if (typeof template !== "string" || !template.trim())
14707
+ problem(`naming.${kind}`, "not a template string; ignored");
14708
+ else if (!literalOf(template))
14709
+ problem(`naming.${kind}`, "needs literal text besides placeholders; ignored");
14710
+ else
14711
+ naming[kind] = template.trim();
14712
+ }
14713
+ }
14714
+ if (!productionBranch || !integrationBranch) {
14715
+ out.issues.push(`${label} was skipped: it needs a productionBranch and integrationBranch`);
14716
+ continue;
14717
+ }
14718
+ out.tracks.push({
14719
+ name,
14720
+ productionBranch,
14721
+ integrationBranch,
14722
+ baseBranch: baseBranch ?? integrationBranch,
14723
+ pullRequestTarget: pullRequestTarget ?? integrationBranch,
14724
+ mergeBackBranches,
14725
+ naming
14726
+ });
14727
+ }
14728
+ out.protectedBranches = [...protectedNames];
14729
+ if (fatal.length)
14730
+ out.error = `workspace releaseTracks cannot be read by this Workit (${fatal.join("; ")}); upgrade Workit or fix the track`;
14731
+ return out;
14732
+ }
14733
+ var trackBranches = (tracks) => [
14734
+ ...new Set(tracks.flatMap((track) => [
14735
+ track.productionBranch,
14736
+ track.integrationBranch,
14737
+ track.baseBranch,
14738
+ track.pullRequestTarget,
14739
+ ...track.mergeBackBranches
14740
+ ]))
14741
+ ];
14742
+ var namingGlob = (template) => HAS_PLACEHOLDER.test(template) ? template.replace(PLACEHOLDER, "*") : `${template.replace(/\/?\*?$/u, "")}/*`;
14743
+ var IMPLICIT = "";
14744
+ var ownedBy = (tracks, branch) => tracks.filter((track) => [track.integrationBranch, track.productionBranch, track.baseBranch].includes(branch));
14745
+ var shortRef = (ref, remotes) => {
14746
+ const bare = ref.replace(/^refs\/heads\//u, "").replace(/^refs\/remotes\/[^/]+\//u, "");
14747
+ const remote = remotes.find((name) => bare.startsWith(`${name}/`));
14748
+ return remote ? bare.slice(remote.length + 1) : bare;
14749
+ };
14750
+ var MAX_RECORDED_HOPS = 10;
14751
+ function resolveReleaseTrack(input) {
14752
+ const tracks = [...input.tracks];
14753
+ const issues = [...input.issues ?? []];
14754
+ const requested = input.requested?.trim();
14755
+ if (tracks.length === 0) {
14756
+ if (requested)
14757
+ return {
14758
+ status: "invalid",
14759
+ error: `no release tracks configured for this workspace; --track ${requested} cannot apply`,
14760
+ issues
14761
+ };
14762
+ return { status: "none", issues };
14763
+ }
14764
+ const names = tracks.map((track) => track.name).join(", ");
14765
+ let envProblem = null;
14766
+ const done = (track, source, detail, warnings = [], ambiguous = null) => ({
14767
+ status: "resolved",
14768
+ track: track && track.name !== IMPLICIT ? track : null,
14769
+ source,
14770
+ detail,
14771
+ warnings: [...issues, ...envProblem ? [envProblem] : [], ...warnings],
14772
+ tracks,
14773
+ blocking: envProblem ?? ambiguous
14774
+ });
14775
+ if (requested) {
14776
+ const named = tracks.find((track) => track.name === requested);
14777
+ if (!named)
14778
+ return {
14779
+ status: "invalid",
14780
+ error: `no release track ${JSON.stringify(requested)}; configured: ${names}`,
14781
+ issues
14782
+ };
14783
+ return done(named, "flag", `track ${named.name} was requested explicitly`);
14784
+ }
14785
+ const owned = (branch) => branch !== null && tracks.some((track) => [
14786
+ track.integrationBranch,
14787
+ track.productionBranch,
14788
+ track.baseBranch,
14789
+ track.pullRequestTarget
14790
+ ].includes(branch));
14791
+ const implicit = input.defaultBranch && !owned(input.defaultBranch) ? {
14792
+ name: IMPLICIT,
14793
+ productionBranch: input.defaultBranch,
14794
+ integrationBranch: input.defaultBranch,
14795
+ baseBranch: input.defaultBranch,
14796
+ pullRequestTarget: input.defaultBranch,
14797
+ mergeBackBranches: [],
14798
+ naming: {}
14799
+ } : null;
14800
+ const candidates = implicit ? [...tracks, implicit] : tracks;
14801
+ const label = (track) => track.name === IMPLICIT ? `the workspace default line (${track.integrationBranch})` : `track ${track.name}`;
14802
+ const fallback = (why) => {
14803
+ const byDefault = input.defaultBranch ? tracks.filter((track) => track.integrationBranch === input.defaultBranch || track.pullRequestTarget === input.defaultBranch) : [];
14804
+ const track = byDefault.length === 1 ? byDefault[0] : null;
14805
+ const target = track ? `track ${track.name}` : `default target ${input.defaultBranch ?? "(none)"}`;
14806
+ const ambiguous = candidates.length >= 2 ? `can't tell which release line ${input.branch ?? "HEAD"} is on (${why}); pass --track <name> (${names}) or --base <branch>` : null;
14807
+ return done(track, "default", `${why}; using the workspace ${target}`, [
14808
+ `release track not determined: ${why}; using the workspace ${target} (pass --track <name> to choose)`
14809
+ ], ambiguous);
14810
+ };
14811
+ const branch = input.branch;
14812
+ if (branch) {
14813
+ const owners = ownedBy(candidates, branch);
14814
+ if (owners.length === 1)
14815
+ return done(owners[0], "branch", `${branch} is a branch of ${label(owners[0])}`);
14816
+ if (owners.length > 1)
14817
+ return fallback(`${branch} belongs to more than one track (${owners.map((track) => track.name).join(", ")})`);
14818
+ }
14819
+ const env = input.envRequested?.trim();
14820
+ if (env) {
14821
+ const named = tracks.find((track) => track.name === env);
14822
+ if (named)
14823
+ return done(named, "env", `WORKFLOW_RELEASE_TRACK selects track ${named.name}`);
14824
+ envProblem = `WORKFLOW_RELEASE_TRACK=${env} names no release track of this workspace (${names}); ignored`;
14825
+ }
14826
+ if (!branch)
14827
+ return fallback("HEAD is detached");
14828
+ if (tracks.length === 1 && !implicit)
14829
+ return done(tracks[0], "only-track", `${tracks[0].name} is the only track`);
14830
+ let remotes = null;
14831
+ const short = (ref) => shortRef(ref, remotes ??= input.probe.remotes());
14832
+ const ownerOf = (ref) => {
14833
+ const owner = ownedBy(candidates, short(ref));
14834
+ return owner.length === 1 ? owner[0] : null;
14835
+ };
14836
+ const followRecorded = (start) => {
14837
+ let cursor = start;
14838
+ const seen = new Set([start]);
14839
+ for (let hop = 0;hop < MAX_RECORDED_HOPS; hop += 1) {
14840
+ const recorded = input.probe.recordedBase(cursor);
14841
+ if (!recorded)
14842
+ return null;
14843
+ const base = short(recorded);
14844
+ const owner = ownerOf(base);
14845
+ if (owner)
14846
+ return owner;
14847
+ if (ownedBy(candidates, base).length > 1 || seen.has(base))
14848
+ return null;
14849
+ seen.add(base);
14850
+ cursor = base;
14851
+ }
14852
+ return null;
14853
+ };
14854
+ const recordedOwner = followRecorded(branch);
14855
+ if (recordedOwner)
14856
+ return done(recordedOwner, "recorded-base", `${branch} was created on ${label(recordedOwner)}'s line (recorded base)`);
14857
+ for (const source of ["reflog", "checkout"]) {
14858
+ const ref = source === "reflog" ? input.probe.createdFrom(branch) : input.probe.checkedOutFrom(branch);
14859
+ if (!ref)
14860
+ continue;
14861
+ const owner = ownerOf(ref) ?? followRecorded(short(ref));
14862
+ if (owner)
14863
+ return done(owner, source, `${branch} was created from ${short(ref)} (${source === "reflog" ? "branch reflog" : "HEAD reflog"})`);
14864
+ }
14865
+ const forks = [];
14866
+ for (const track of candidates)
14867
+ for (const ref of new Set([track.integrationBranch, track.baseBranch])) {
14868
+ const sha = input.probe.mergeBase(branch, ref);
14869
+ if (sha)
14870
+ forks.push({ track, ref, sha });
14871
+ }
14872
+ if (forks.length === 0)
14873
+ return fallback(`no track branch could be compared with ${branch} (fetch the track branches)`);
14874
+ const ancestry = new Map;
14875
+ const descends = (older, newer) => {
14876
+ if (older === newer)
14877
+ return false;
14878
+ const key = `${older}>${newer}`;
14879
+ if (!ancestry.has(key))
14880
+ ancestry.set(key, input.probe.isAncestor(older, newer));
14881
+ return ancestry.get(key);
14882
+ };
14883
+ const winners = forks.filter((fork) => forks.every((other) => other.track === fork.track || descends(other.sha, fork.sha)));
14884
+ const winningTracks = [...new Set(winners.map((fork) => fork.track))];
14885
+ if (winningTracks.length === 1 && forks.some((fork) => fork.track !== winningTracks[0])) {
14886
+ const win = winners[0];
14887
+ return done(win.track, "ancestry", `${branch} forked from ${win.ref} at ${win.sha.slice(0, 12)}, after every other line's fork point`);
14888
+ }
14889
+ if (winningTracks.length === 1)
14890
+ return fallback(`only ${label(winningTracks[0])} could be compared with ${branch}`);
14891
+ const newest = forks.filter((fork) => !forks.some((other) => descends(fork.sha, other.sha)));
14892
+ return fallback(`${branch} has the same or unrelated fork points with ${[...new Set(newest.map((fork) => `${fork.ref} (${fork.track.name === IMPLICIT ? "workspace default" : fork.track.name})`))].join(" and ")}`);
14893
+ }
14894
+ var git4 = (cwd, args) => {
14895
+ const run = spawnSync7("git", args, {
14896
+ cwd,
14897
+ encoding: "utf8",
14898
+ timeout: 20000,
14899
+ windowsHide: true,
14900
+ stdio: ["ignore", "pipe", "ignore"]
14901
+ });
14902
+ return run.status === 0 ? (run.stdout ?? "").trim() : null;
14903
+ };
14904
+ var recordedBaseKey = (branch) => `branch.${branch}.workitBase`;
14905
+ var escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
14906
+ var reflog = (cwd, ref) => (git4(cwd, ["log", "-g", "--date=unix", "--format=%H%x09%gd%x09%gs", ref, "--"]) ?? "").split(`
14907
+ `).map((line) => {
14908
+ const [sha = "", selector = "", ...subject] = line.split("\t");
14909
+ return {
14910
+ sha,
14911
+ time: Number(/@\{(\d+)\}$/u.exec(selector)?.[1] ?? Number.NaN),
14912
+ subject: subject.join("\t")
14913
+ };
14914
+ }).filter((entry) => entry.sha && Number.isFinite(entry.time));
14915
+ function gitTrackProbe(cwd) {
14916
+ let remote;
14917
+ let remotes;
14918
+ const tip = (branch) => {
14919
+ remote ??= pushRemoteName(cwd) ?? "origin";
14920
+ return resolveRef(cwd, `refs/remotes/${remote}/${branch}`) ?? resolveRef(cwd, `refs/heads/${branch}`);
14921
+ };
14922
+ return {
14923
+ remotes: () => remotes ??= remoteNames(cwd),
14924
+ recordedBase: (branch) => git4(cwd, ["config", "--get", recordedBaseKey(branch)]) || null,
14925
+ createdFrom: (branch) => {
14926
+ const log = git4(cwd, ["reflog", "show", "--format=%gs", `refs/heads/${branch}`, "--"]);
14927
+ const oldest = log?.split(`
14928
+ `).findLast(Boolean) ?? "";
14929
+ const match = /^branch: Created from (\S+)$/u.exec(oldest);
14930
+ return match && match[1] !== "HEAD" ? match[1] : null;
14931
+ },
14932
+ checkedOutFrom: (branch) => {
14933
+ const own = reflog(cwd, `refs/heads/${branch}`);
14934
+ const created = own.at(-1);
14935
+ if (!created || created.subject !== "branch: Created from HEAD")
14936
+ return null;
14937
+ const pattern = new RegExp(`^checkout: moving from (\\S+) to ${escapeRegExp(branch)}$`, "u");
14938
+ const entry = reflog(cwd, "HEAD").findLast((item) => item.time >= created.time && item.sha === created.sha && pattern.test(item.subject));
14939
+ return entry ? pattern.exec(entry.subject)?.[1] ?? null : null;
14940
+ },
14941
+ mergeBase: (branch, trackBranch) => {
14942
+ const base = tip(trackBranch);
14943
+ return base && resolveRef(cwd, `refs/heads/${branch}`) ? mergeBase(cwd, base, `refs/heads/${branch}`) : null;
14944
+ },
14945
+ isAncestor: (ancestor, descendant) => git4(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]) !== null
14946
+ };
14947
+ }
14948
+ function workspaceReleaseTracks(cwd) {
14949
+ const raw = resolveRuntimeReleaseTracks(cwd);
14950
+ return { workspace: raw?.workspace ?? null, ...readReleaseTracks(raw?.releaseTracks) };
14951
+ }
14952
+ var memo3 = new Map;
14953
+ var MEMO_LIMIT = 64;
14954
+ function resolveTrackFor(cwd, options) {
14955
+ const read = workspaceReleaseTracks(cwd);
14956
+ if (read.error)
14957
+ return { status: "invalid", error: read.error, issues: read.issues };
14958
+ if (read.tracks.length === 0 && !options.track?.trim())
14959
+ return { status: "none", issues: read.issues };
14960
+ const branch = options.branch === undefined ? currentBranch(cwd) : options.branch;
14961
+ const envRequested = process.env.WORKFLOW_RELEASE_TRACK?.trim() || null;
14962
+ const input = {
14963
+ tracks: read.tracks,
14964
+ requested: options.track ?? null,
14965
+ envRequested,
14966
+ branch,
14967
+ defaultBranch: options.defaultBranch,
14968
+ issues: read.issues
14969
+ };
14970
+ let key = null;
14971
+ if (!options.probe) {
14972
+ const refs = git4(cwd, [
14973
+ "for-each-ref",
14974
+ "--format=%(refname) %(objectname)",
14975
+ "refs/heads",
14976
+ "refs/remotes"
14977
+ ]) ?? "";
14978
+ const head = git4(cwd, ["reflog", "show", "-n", "1", "--format=%H %gs", "HEAD", "--"]) ?? "";
14979
+ const own = branch ? [
14980
+ git4(cwd, [
14981
+ "log",
14982
+ "-g",
14983
+ "-n",
14984
+ "1",
14985
+ "--date=unix",
14986
+ "--format=%H %gd %gs",
14987
+ `refs/heads/${branch}`,
14988
+ "--"
14989
+ ]) ?? "",
14990
+ git4(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
14991
+ ] : [];
14992
+ key = createHash9("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
14993
+ const hit = memo3.get(key);
14994
+ if (hit)
14995
+ return hit;
14996
+ }
14997
+ const resolution = resolveReleaseTrack({ ...input, probe: options.probe ?? gitTrackProbe(cwd) });
14998
+ if (key) {
14999
+ if (memo3.size >= MEMO_LIMIT)
15000
+ memo3.delete(memo3.keys().next().value);
15001
+ memo3.set(key, resolution);
15002
+ }
15003
+ return resolution;
15004
+ }
15005
+
15006
+ // packages/workit-core/src/core/vcs-config.ts
15007
+ var workspacesPath = () => path14.join(configDir(), "workspaces.json");
14555
15008
  var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
14556
15009
  var remoteProvider = (cwd) => {
14557
- const r = spawnSync7("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
15010
+ const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
14558
15011
  if (r.status !== 0)
14559
15012
  return null;
14560
15013
  const url = (r.stdout ?? "").trim();
@@ -14591,7 +15044,7 @@ var remoteEndpoint = (remote) => {
14591
15044
  var configuredSshEndpoint = (host) => {
14592
15045
  if (host.startsWith("-"))
14593
15046
  return null;
14594
- const resolved = spawnSync7("ssh", ["-G", host], {
15047
+ const resolved = spawnSync8("ssh", ["-G", host], {
14595
15048
  encoding: "utf8",
14596
15049
  timeout: 5000,
14597
15050
  maxBuffer: 1024 * 1024,
@@ -14656,7 +15109,16 @@ var readVcsConfig = () => {
14656
15109
  }
14657
15110
  return { status: "malformed", path: file, config: {}, error: `${file} is not a JSON object` };
14658
15111
  };
14659
- function vcsConfig(mode, cwd) {
15112
+ var trackSummary = (resolution) => resolution.status === "resolved" ? {
15113
+ name: resolution.track?.name ?? null,
15114
+ source: resolution.source,
15115
+ detail: resolution.detail,
15116
+ warnings: resolution.warnings,
15117
+ track: resolution.track,
15118
+ tracks: resolution.tracks,
15119
+ blocking: resolution.blocking
15120
+ } : null;
15121
+ function vcsConfig(mode, cwd, options = {}) {
14660
15122
  const ws = resolveRuntimeWorkspaceVcs(vcsCwd(cwd));
14661
15123
  const wsVcs = ws?.vcs ?? {};
14662
15124
  const wsYt = ws?.youtrack ?? {};
@@ -14666,10 +15128,7 @@ function vcsConfig(mode, cwd) {
14666
15128
  const determinateRoot = cwd !== undefined || process.env.WORKFLOW_WORKSPACE_ROOT !== undefined;
14667
15129
  const rawProvider = wsVcs.provider ?? (determinateRoot ? remoteProvider(root) : null) ?? cfg.provider ?? null;
14668
15130
  const provider = rawProvider === null || rawProvider === undefined ? null : String(rawProvider).toLowerCase() || null;
14669
- const wp = ws?.branchPolicy ?? {};
14670
- const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
14671
- const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
14672
- const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
15131
+ const workspaceDefault = workspaceDefaultTarget(root, cfg.defaultTargetBranch);
14673
15132
  const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
14674
15133
  const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
14675
15134
  let issuesProvider = null;
@@ -14681,11 +15140,24 @@ function vcsConfig(mode, cwd) {
14681
15140
  if (mode === "resolve") {
14682
15141
  if (cfgStatus === "malformed")
14683
15142
  return { ok: false, error: cfgError, configPath: cfgPath };
15143
+ const trackResolution = resolveTrackFor(root, {
15144
+ track: options.track,
15145
+ ...options.branch !== undefined ? { branch: options.branch } : {},
15146
+ defaultBranch: workspaceDefault
15147
+ });
15148
+ if (trackResolution.status === "invalid")
15149
+ return { ok: false, error: trackResolution.error, configPath: workspacesPath() };
15150
+ const releaseTrack = trackSummary(trackResolution);
15151
+ const defaultTarget = releaseTrack?.track?.pullRequestTarget ?? workspaceDefault;
15152
+ const baseBranch = releaseTrack?.track?.baseBranch ?? defaultTarget;
14684
15153
  return {
14685
15154
  ok: true,
14686
15155
  workspace_name: ws?.name ?? null,
14687
15156
  provider,
14688
15157
  defaultTargetBranch: defaultTarget,
15158
+ workspaceDefaultTargetBranch: workspaceDefault,
15159
+ baseBranch,
15160
+ releaseTrack,
14689
15161
  link_issues: linkIssues,
14690
15162
  youtrack_base_url: youtrackBaseUrl,
14691
15163
  issues_provider: issuesProvider,
@@ -14709,7 +15181,7 @@ function vcsConfig(mode, cwd) {
14709
15181
  ok: true,
14710
15182
  configPath: path14.resolve(cfgPath),
14711
15183
  provider,
14712
- defaultTargetBranch: defaultTarget,
15184
+ defaultTargetBranch: workspaceDefault,
14713
15185
  pr: cfg.pr ?? {},
14714
15186
  workspace_name: ws?.name ?? null,
14715
15187
  link_issues: linkIssues,
@@ -14745,7 +15217,7 @@ function mergedPrStyle(limit = 6, cwd) {
14745
15217
  `).filter((l) => l.startsWith("## ")).map((l) => l.trim()),
14746
15218
  descriptionPreview: desc.slice(0, 600)
14747
15219
  });
14748
- const remoteResult = spawnSync7("git", ["remote", "get-url", "--push", "--all", "origin"], {
15220
+ const remoteResult = spawnSync8("git", ["remote", "get-url", "--push", "--all", "origin"], {
14749
15221
  cwd,
14750
15222
  encoding: "utf8"
14751
15223
  });
@@ -14761,7 +15233,7 @@ function mergedPrStyle(limit = 6, cwd) {
14761
15233
  if (!hostingApiHostMatches(remote, host))
14762
15234
  return { ok: false, error: "PR style target does not match the provider host" };
14763
15235
  if (provider === "gitlab") {
14764
- const run = (args) => spawnSync7("glab", ["api", ...args], {
15236
+ const run = (args) => spawnSync8("glab", ["api", ...args], {
14765
15237
  cwd,
14766
15238
  encoding: "utf8",
14767
15239
  env
@@ -14781,7 +15253,7 @@ function mergedPrStyle(limit = 6, cwd) {
14781
15253
  });
14782
15254
  }
14783
15255
  } else if (provider === "github") {
14784
- const r = spawnSync7("gh", [
15256
+ const r = spawnSync8("gh", [
14785
15257
  "pr",
14786
15258
  "list",
14787
15259
  "--repo",
@@ -14814,11 +15286,35 @@ function mergedPrStyle(limit = 6, cwd) {
14814
15286
  }
14815
15287
 
14816
15288
  // packages/workit-core/src/core/branch.ts
15289
+ var withReleaseTracks = (workspaceRoot, policy) => {
15290
+ const read = workspaceReleaseTracks(workspaceRoot);
15291
+ if (read.error)
15292
+ throw new ReleaseTrackError(read.error);
15293
+ if (read.tracks.length === 0 && read.protectedBranches.length === 0)
15294
+ return policy;
15295
+ const known = new Set(policy.allowed.map((pattern) => pattern.source));
15296
+ const allowed = [...policy.allowed];
15297
+ for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
15298
+ const pattern = branchGlobPattern(glob);
15299
+ if (!known.has(pattern.source)) {
15300
+ known.add(pattern.source);
15301
+ allowed.push(pattern);
15302
+ }
15303
+ }
15304
+ return {
15305
+ ...policy,
15306
+ allowed,
15307
+ protected: new Set([
15308
+ ...policy.protected,
15309
+ ...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
15310
+ ])
15311
+ };
15312
+ };
14817
15313
  function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
14818
15314
  const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
14819
15315
  const config = readConfig();
14820
15316
  return kind === "branch" ? {
14821
- branchPolicy: resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null),
15317
+ branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null)),
14822
15318
  provenance: { branchPolicy: selected.source }
14823
15319
  } : {
14824
15320
  commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
@@ -14857,7 +15353,7 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
14857
15353
  const source = resolved.provenance.branchPolicy;
14858
15354
  const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
14859
15355
  const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
14860
- const fingerprint = createHash9("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
15356
+ const fingerprint = createHash10("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
14861
15357
  return {
14862
15358
  branchPolicy,
14863
15359
  namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
@@ -14881,7 +15377,6 @@ var validateBranchNameFor = (workspaceRoot, name) => {
14881
15377
  };
14882
15378
  }
14883
15379
  };
14884
- var resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
14885
15380
 
14886
15381
  // packages/workit-core/src/core/route-intent.ts
14887
15382
  var shellBranchTarget = (command) => {
@@ -16751,7 +17246,7 @@ class WorkitCore {
16751
17246
  }
16752
17247
  }
16753
17248
  // packages/workit-core/src/core/repo-context.ts
16754
- import { spawnSync as spawnSync8 } from "node:child_process";
17249
+ import { spawnSync as spawnSync9 } from "node:child_process";
16755
17250
  import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
16756
17251
  import path16 from "node:path";
16757
17252
  var isSafeContextRange = (value) => value.length <= 4096 && (() => {
@@ -16780,7 +17275,7 @@ var invalidRange = (cwd) => ({
16780
17275
  cwd
16781
17276
  });
16782
17277
  var runGit = (cwd, args) => {
16783
- const result = spawnSync8("git", args, { cwd, encoding: "utf8" });
17278
+ const result = spawnSync9("git", args, { cwd, encoding: "utf8" });
16784
17279
  return {
16785
17280
  stdout: (result.stdout ?? "").trimEnd(),
16786
17281
  stderr: (result.stderr ?? "").trimEnd(),
@@ -17221,12 +17716,12 @@ function releaseNotesContext(root, rangeOrTag) {
17221
17716
  }
17222
17717
 
17223
17718
  // packages/workit-core/src/core/tracker-issues.ts
17224
- import { spawnSync as spawnSync10 } from "node:child_process";
17719
+ import { spawnSync as spawnSync11 } from "node:child_process";
17225
17720
 
17226
17721
  // packages/workit-core/src/core/pr-create.ts
17227
17722
  import fs13 from "node:fs";
17228
17723
  import path17 from "node:path";
17229
- import { spawnSync as spawnSync9 } from "node:child_process";
17724
+ import { spawnSync as spawnSync10 } from "node:child_process";
17230
17725
  // packages/workit-core/src/forge/pr-body.ts
17231
17726
  function parseGhIssue(value) {
17232
17727
  const m = /issues\/(\d+)/.exec(value);
@@ -17251,7 +17746,7 @@ function whichOnPath(tool) {
17251
17746
  }
17252
17747
  var hostingCliAvailable = (provider) => whichOnPath(provider === "gitlab" ? "glab" : "gh") !== null;
17253
17748
  var pushRemote = (cwd) => {
17254
- const result = spawnSync9("git", ["remote", "get-url", "--push", "--all", "origin"], {
17749
+ const result = spawnSync10("git", ["remote", "get-url", "--push", "--all", "origin"], {
17255
17750
  cwd,
17256
17751
  encoding: "utf8"
17257
17752
  });
@@ -17282,7 +17777,7 @@ var defaultCli = (bin, available) => {
17282
17777
  if (!available)
17283
17778
  return null;
17284
17779
  return (args, root) => {
17285
- const out = spawnSync10(bin, args, {
17780
+ const out = spawnSync11(bin, args, {
17286
17781
  cwd: root,
17287
17782
  encoding: "utf8",
17288
17783
  env: { ...process.env, PATH: process.env.PATH ?? "" }
@@ -17815,7 +18310,7 @@ function resolveInside(root, candidate) {
17815
18310
  }
17816
18311
  function run2(root, executable, args, env = {}) {
17817
18312
  const cwd = realpathSync5(root);
17818
- const result = spawnSync11(executable, args, {
18313
+ const result = spawnSync12(executable, args, {
17819
18314
  cwd,
17820
18315
  encoding: "utf8",
17821
18316
  env: { ...process.env, ...env }
@@ -18266,7 +18761,7 @@ function writeGate(cwd, paths) {
18266
18761
  }
18267
18762
  }
18268
18763
  // packages/workit-core/src/hooks/hosts/fields.ts
18269
- var isRecord3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
18764
+ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
18270
18765
  var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
18271
18766
  var SHELLS = new Set(["sh", "bash", "zsh", "dash", "pwsh", "powershell", "cmd"]);
18272
18767
  var WRITE_TOOLS = new Set([
@@ -18290,7 +18785,7 @@ var WRITE_TOOLS = new Set([
18290
18785
  ]);
18291
18786
  var PATH_KEYS = ["file_path", "filePath", "notebook_path", "path", "target_file", "file"];
18292
18787
  var writePaths = (input) => {
18293
- if (!isRecord3(input))
18788
+ if (!isRecord4(input))
18294
18789
  return [];
18295
18790
  const paths = PATH_KEYS.map((key) => input[key]).filter(nonEmpty2);
18296
18791
  for (const value of Object.values(input))
@@ -18669,9 +19164,9 @@ import { randomUUID as randomUUID4 } from "node:crypto";
18669
19164
  // packages/workit-pi/src/worker-protocol.ts
18670
19165
  var MAX_WORKER_LINE_BYTES = 64 * 1024;
18671
19166
  var MAX_WORKER_STDERR_BYTES = 64 * 1024;
18672
- var isRecord4 = (value) => typeof value === "object" && value !== null;
19167
+ var isRecord5 = (value) => typeof value === "object" && value !== null;
18673
19168
  var parseEvent2 = (value) => {
18674
- if (!isRecord4(value) || typeof value.type !== "string")
19169
+ if (!isRecord5(value) || typeof value.type !== "string")
18675
19170
  return null;
18676
19171
  if (value.type === "workit_worker_ready") {
18677
19172
  if (typeof value.workerId !== "string" || typeof value.sessionId !== "string")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-pi",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "Workit native extension for Pi — tools, method skills, and session continuity",
5
5
  "keywords": [
6
6
  "agentic-coding",