@brainervirus/workit-claude-code 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/.claude-plugin/plugin.json +1 -1
- package/dist/workit-hook.js +45 -45
- package/dist/workit.js +902 -253
- package/package.json +3 -3
package/dist/workit.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@brainervirus/workit-cli",
|
|
68
|
-
version: "
|
|
68
|
+
version: "7.1.0",
|
|
69
69
|
private: false,
|
|
70
70
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
71
71
|
keywords: [
|
|
@@ -103,9 +103,9 @@ var init_package = __esm(() => {
|
|
|
103
103
|
},
|
|
104
104
|
dependencies: {
|
|
105
105
|
"@babel/parser": "7.29.9",
|
|
106
|
-
"@brainervirus/workit-core": "
|
|
107
|
-
"@brainervirus/workit-cursor": "
|
|
108
|
-
"@brainervirus/workit-opencode": "
|
|
106
|
+
"@brainervirus/workit-core": "^7.1.0",
|
|
107
|
+
"@brainervirus/workit-cursor": "^7.1.0",
|
|
108
|
+
"@brainervirus/workit-opencode": "^7.1.0",
|
|
109
109
|
"@inkjs/ui": "2.0.0",
|
|
110
110
|
ink: "7.1.1",
|
|
111
111
|
react: "19.2.8"
|
|
@@ -15029,14 +15029,14 @@ var diagnosticLogger, setDiagnosticLogger = (logger) => {
|
|
|
15029
15029
|
if (result.status === "malformed")
|
|
15030
15030
|
throw new Error(result.error);
|
|
15031
15031
|
return result.config ?? DEFAULTS;
|
|
15032
|
-
}, resolveBranchPolicy = (config, workspace) => {
|
|
15032
|
+
}, vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path13.join(configDir(), "vcs.json"), branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"), resolveBranchPolicy = (config, workspace) => {
|
|
15033
15033
|
const wp = workspace?.branchPolicy ?? {};
|
|
15034
15034
|
const preset = Object.hasOwn(PRESETS, wp.preset) ? wp.preset : config.branchPolicy?.preset ?? "gitflow";
|
|
15035
15035
|
const merged = mergePreset(preset, {
|
|
15036
15036
|
allowed: wp.allowed,
|
|
15037
15037
|
protectedNames: wp.protected
|
|
15038
15038
|
}, config);
|
|
15039
|
-
const allowed = merged.allowed.map(
|
|
15039
|
+
const allowed = merged.allowed.map(branchGlobPattern);
|
|
15040
15040
|
return {
|
|
15041
15041
|
preset,
|
|
15042
15042
|
allowed,
|
|
@@ -15090,6 +15090,14 @@ var init_config = __esm(() => {
|
|
|
15090
15090
|
import { createHash as createHash8 } from "node:crypto";
|
|
15091
15091
|
import { readFileSync as readFileSync4, realpathSync as realpathSync3 } from "node:fs";
|
|
15092
15092
|
import path14 from "node:path";
|
|
15093
|
+
function workspaceDefaultTarget(cwd, globalDefault) {
|
|
15094
|
+
const ws = resolveRuntimeWorkspaceVcs(cwd);
|
|
15095
|
+
const wp = ws?.branchPolicy ?? {};
|
|
15096
|
+
const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
|
|
15097
|
+
const selected = resolveRuntimeWorkspacePolicy(cwd, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
15098
|
+
const policyDefault = resolveBranchPolicy(readConfig(), selected.policy ? { branchPolicy: selected.policy } : null).defaultTargetBranch;
|
|
15099
|
+
return String(ws?.vcs?.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : globalDefault ?? policyDefault) ?? "develop");
|
|
15100
|
+
}
|
|
15093
15101
|
var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspaceCommitPolicySchema, workspaceProfileSchema, versionSourceSchema, releaseTrackSchema, workspaceConfigSchema, workspacesFileSchema, workspacesRevision = (contents) => createHash8("sha256").update(contents ?? "<missing>").digest("hex"), validateWorkspacesDocument = (parsed, file) => {
|
|
15094
15102
|
if (!isConfigObject(parsed)) {
|
|
15095
15103
|
return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
|
|
@@ -15279,7 +15287,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
15279
15287
|
profiles: record(nonBlank, profileSchema).optional()
|
|
15280
15288
|
}).passthrough();
|
|
15281
15289
|
return entrySchema;
|
|
15282
|
-
}, resolveRuntimeWorkspaceVcs = (cwd) => resolveRuntimeWorkspaceCandidate(cwd, "vcs"), runtimeWorkspaceIndexSchema,
|
|
15290
|
+
}, resolveRuntimeWorkspaceVcs = (cwd) => resolveRuntimeWorkspaceCandidate(cwd, "vcs"), runtimeWorkspaceIndexSchema, matchRuntimeWorkspace = (cwd) => {
|
|
15283
15291
|
const file = path14.join(configDir(), "workspaces.json");
|
|
15284
15292
|
let raw;
|
|
15285
15293
|
try {
|
|
@@ -15314,8 +15322,15 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
15314
15322
|
});
|
|
15315
15323
|
const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
|
|
15316
15324
|
const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
|
|
15317
|
-
|
|
15325
|
+
return selected ? { file, selected } : null;
|
|
15326
|
+
}, resolveRuntimeReleaseTracks = (cwd) => {
|
|
15327
|
+
const matched = matchRuntimeWorkspace(cwd);
|
|
15328
|
+
return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
|
|
15329
|
+
}, resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
|
|
15330
|
+
const matched = matchRuntimeWorkspace(cwd);
|
|
15331
|
+
if (!matched)
|
|
15318
15332
|
return null;
|
|
15333
|
+
const { file, selected } = matched;
|
|
15319
15334
|
const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
|
|
15320
15335
|
if (!policy.success) {
|
|
15321
15336
|
const detail = policy.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspace"}: ${issue.message}`).join("; ");
|
|
@@ -15416,26 +15431,31 @@ var init_workspaces = __esm(() => {
|
|
|
15416
15431
|
object({ kind: literal("manual") }).strict()
|
|
15417
15432
|
]);
|
|
15418
15433
|
releaseTrackSchema = object({
|
|
15419
|
-
strategy: branchPreset,
|
|
15434
|
+
strategy: branchPreset.optional(),
|
|
15420
15435
|
productionBranch: nonBlank,
|
|
15421
15436
|
integrationBranch: nonBlank,
|
|
15422
|
-
naming: object({
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15427
|
-
|
|
15428
|
-
|
|
15429
|
-
|
|
15437
|
+
naming: object({
|
|
15438
|
+
feature: nonBlank.optional(),
|
|
15439
|
+
release: nonBlank.optional(),
|
|
15440
|
+
hotfix: nonBlank.optional()
|
|
15441
|
+
}).passthrough().optional(),
|
|
15442
|
+
baseBranch: nonBlank.optional(),
|
|
15443
|
+
mergeBackBranches: array(nonBlank).optional(),
|
|
15444
|
+
pullRequestTarget: nonBlank.optional(),
|
|
15445
|
+
tagNamespace: string2().optional(),
|
|
15446
|
+
versionSource: versionSourceSchema.optional(),
|
|
15447
|
+
requiredChecks: array(nonBlank).optional(),
|
|
15448
|
+
critical: array(nonBlank).optional()
|
|
15449
|
+
}).passthrough().superRefine((track, context) => {
|
|
15430
15450
|
for (const [field, values] of [
|
|
15431
|
-
["mergeBackBranches", track.mergeBackBranches],
|
|
15432
|
-
["requiredChecks", track.requiredChecks]
|
|
15451
|
+
["mergeBackBranches", track.mergeBackBranches ?? []],
|
|
15452
|
+
["requiredChecks", track.requiredChecks ?? []]
|
|
15433
15453
|
]) {
|
|
15434
15454
|
if (new Set(values).size !== values.length) {
|
|
15435
15455
|
context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
|
|
15436
15456
|
}
|
|
15437
15457
|
}
|
|
15438
|
-
if (track.versionSource
|
|
15458
|
+
if (track.versionSource?.kind === "package-json" && (path14.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
|
|
15439
15459
|
context.addIssue({
|
|
15440
15460
|
code: "custom",
|
|
15441
15461
|
path: ["versionSource", "path"],
|
|
@@ -15502,11 +15522,473 @@ var init_workspaces = __esm(() => {
|
|
|
15502
15522
|
}).passthrough();
|
|
15503
15523
|
});
|
|
15504
15524
|
|
|
15525
|
+
// packages/workit-core/src/core/release-tracks.ts
|
|
15526
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
15527
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
15528
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
15529
|
+
function readReleaseTracks(raw) {
|
|
15530
|
+
const out = { tracks: [], issues: [], error: null, protectedBranches: [] };
|
|
15531
|
+
if (raw === undefined || raw === null)
|
|
15532
|
+
return out;
|
|
15533
|
+
if (!isRecord3(raw)) {
|
|
15534
|
+
out.issues.push("releaseTracks is not an object; ignored");
|
|
15535
|
+
return out;
|
|
15536
|
+
}
|
|
15537
|
+
const fatal = [];
|
|
15538
|
+
const protectedNames = new Set;
|
|
15539
|
+
for (const [name, entry] of Object.entries(raw).toSorted(([a], [b]) => a < b ? -1 : 1)) {
|
|
15540
|
+
const label = `release track ${JSON.stringify(name)}`;
|
|
15541
|
+
if (!isRecord3(entry)) {
|
|
15542
|
+
out.issues.push(`${label} is not an object; ignored`);
|
|
15543
|
+
continue;
|
|
15544
|
+
}
|
|
15545
|
+
for (const branch of namedBranches(entry))
|
|
15546
|
+
protectedNames.add(branch);
|
|
15547
|
+
if (!name.trim()) {
|
|
15548
|
+
out.issues.push("a release track with a blank name was ignored");
|
|
15549
|
+
continue;
|
|
15550
|
+
}
|
|
15551
|
+
let critical = [];
|
|
15552
|
+
if (Array.isArray(entry.critical))
|
|
15553
|
+
critical = entry.critical.filter((item) => typeof item === "string");
|
|
15554
|
+
else if (entry.critical !== undefined)
|
|
15555
|
+
out.issues.push(`${label} critical: must be a list of field names; ignored`);
|
|
15556
|
+
const isCritical = (field) => critical.some((item) => field === item || field.startsWith(`${item}.`));
|
|
15557
|
+
const problem = (field, message) => {
|
|
15558
|
+
if (isCritical(field))
|
|
15559
|
+
fatal.push(`${label} ${field}: ${message}`);
|
|
15560
|
+
else
|
|
15561
|
+
out.issues.push(`${label} ${field}: ${message}`);
|
|
15562
|
+
};
|
|
15563
|
+
for (const key of Object.keys(entry))
|
|
15564
|
+
if (!KNOWN_FIELDS.has(key))
|
|
15565
|
+
problem(key, "unknown field, ignored");
|
|
15566
|
+
const productionBranch = branchName(entry.productionBranch);
|
|
15567
|
+
const integrationBranch = branchName(entry.integrationBranch);
|
|
15568
|
+
if (!productionBranch)
|
|
15569
|
+
problem("productionBranch", "missing or not a branch name");
|
|
15570
|
+
if (!integrationBranch)
|
|
15571
|
+
problem("integrationBranch", "missing or not a branch name");
|
|
15572
|
+
const optionalBranch = (field) => {
|
|
15573
|
+
if (entry[field] === undefined)
|
|
15574
|
+
return null;
|
|
15575
|
+
const value = branchName(entry[field]);
|
|
15576
|
+
if (!value)
|
|
15577
|
+
problem(field, "not a branch name; using the integration branch");
|
|
15578
|
+
return value;
|
|
15579
|
+
};
|
|
15580
|
+
const baseBranch = optionalBranch("baseBranch");
|
|
15581
|
+
const pullRequestTarget = optionalBranch("pullRequestTarget");
|
|
15582
|
+
let mergeBackBranches = [];
|
|
15583
|
+
if (entry.mergeBackBranches !== undefined) {
|
|
15584
|
+
const list = Array.isArray(entry.mergeBackBranches) ? entry.mergeBackBranches.map(branchName) : [null];
|
|
15585
|
+
if (list.some((item) => item === null))
|
|
15586
|
+
problem("mergeBackBranches", "must be a list of branch names; ignored");
|
|
15587
|
+
else
|
|
15588
|
+
mergeBackBranches = [...new Set(list)];
|
|
15589
|
+
}
|
|
15590
|
+
const naming = {};
|
|
15591
|
+
if (entry.naming !== undefined) {
|
|
15592
|
+
if (!isRecord3(entry.naming))
|
|
15593
|
+
problem("naming", "not an object; ignored");
|
|
15594
|
+
else
|
|
15595
|
+
for (const kind of ["feature", "release", "hotfix"]) {
|
|
15596
|
+
const template = entry.naming[kind];
|
|
15597
|
+
if (template === undefined)
|
|
15598
|
+
continue;
|
|
15599
|
+
if (typeof template !== "string" || !template.trim())
|
|
15600
|
+
problem(`naming.${kind}`, "not a template string; ignored");
|
|
15601
|
+
else if (!literalOf(template))
|
|
15602
|
+
problem(`naming.${kind}`, "needs literal text besides placeholders; ignored");
|
|
15603
|
+
else
|
|
15604
|
+
naming[kind] = template.trim();
|
|
15605
|
+
}
|
|
15606
|
+
}
|
|
15607
|
+
if (!productionBranch || !integrationBranch) {
|
|
15608
|
+
out.issues.push(`${label} was skipped: it needs a productionBranch and integrationBranch`);
|
|
15609
|
+
continue;
|
|
15610
|
+
}
|
|
15611
|
+
out.tracks.push({
|
|
15612
|
+
name,
|
|
15613
|
+
productionBranch,
|
|
15614
|
+
integrationBranch,
|
|
15615
|
+
baseBranch: baseBranch ?? integrationBranch,
|
|
15616
|
+
pullRequestTarget: pullRequestTarget ?? integrationBranch,
|
|
15617
|
+
mergeBackBranches,
|
|
15618
|
+
naming
|
|
15619
|
+
});
|
|
15620
|
+
}
|
|
15621
|
+
out.protectedBranches = [...protectedNames];
|
|
15622
|
+
if (fatal.length)
|
|
15623
|
+
out.error = `workspace releaseTracks cannot be read by this Workit (${fatal.join("; ")}); upgrade Workit or fix the track`;
|
|
15624
|
+
return out;
|
|
15625
|
+
}
|
|
15626
|
+
function resolveReleaseTrack(input) {
|
|
15627
|
+
const tracks = [...input.tracks];
|
|
15628
|
+
const issues = [...input.issues ?? []];
|
|
15629
|
+
const requested = input.requested?.trim();
|
|
15630
|
+
if (tracks.length === 0) {
|
|
15631
|
+
if (requested)
|
|
15632
|
+
return {
|
|
15633
|
+
status: "invalid",
|
|
15634
|
+
error: `no release tracks configured for this workspace; --track ${requested} cannot apply`,
|
|
15635
|
+
issues
|
|
15636
|
+
};
|
|
15637
|
+
return { status: "none", issues };
|
|
15638
|
+
}
|
|
15639
|
+
const names = tracks.map((track) => track.name).join(", ");
|
|
15640
|
+
let envProblem = null;
|
|
15641
|
+
const done = (track, source, detail, warnings = [], ambiguous = null) => ({
|
|
15642
|
+
status: "resolved",
|
|
15643
|
+
track: track && track.name !== IMPLICIT ? track : null,
|
|
15644
|
+
source,
|
|
15645
|
+
detail,
|
|
15646
|
+
warnings: [...issues, ...envProblem ? [envProblem] : [], ...warnings],
|
|
15647
|
+
tracks,
|
|
15648
|
+
blocking: envProblem ?? ambiguous
|
|
15649
|
+
});
|
|
15650
|
+
if (requested) {
|
|
15651
|
+
const named = tracks.find((track) => track.name === requested);
|
|
15652
|
+
if (!named)
|
|
15653
|
+
return {
|
|
15654
|
+
status: "invalid",
|
|
15655
|
+
error: `no release track ${JSON.stringify(requested)}; configured: ${names}`,
|
|
15656
|
+
issues
|
|
15657
|
+
};
|
|
15658
|
+
return done(named, "flag", `track ${named.name} was requested explicitly`);
|
|
15659
|
+
}
|
|
15660
|
+
const owned = (branch) => branch !== null && tracks.some((track) => [
|
|
15661
|
+
track.integrationBranch,
|
|
15662
|
+
track.productionBranch,
|
|
15663
|
+
track.baseBranch,
|
|
15664
|
+
track.pullRequestTarget
|
|
15665
|
+
].includes(branch));
|
|
15666
|
+
const implicit = input.defaultBranch && !owned(input.defaultBranch) ? {
|
|
15667
|
+
name: IMPLICIT,
|
|
15668
|
+
productionBranch: input.defaultBranch,
|
|
15669
|
+
integrationBranch: input.defaultBranch,
|
|
15670
|
+
baseBranch: input.defaultBranch,
|
|
15671
|
+
pullRequestTarget: input.defaultBranch,
|
|
15672
|
+
mergeBackBranches: [],
|
|
15673
|
+
naming: {}
|
|
15674
|
+
} : null;
|
|
15675
|
+
const candidates = implicit ? [...tracks, implicit] : tracks;
|
|
15676
|
+
const label = (track) => track.name === IMPLICIT ? `the workspace default line (${track.integrationBranch})` : `track ${track.name}`;
|
|
15677
|
+
const fallback = (why) => {
|
|
15678
|
+
const byDefault = input.defaultBranch ? tracks.filter((track) => track.integrationBranch === input.defaultBranch || track.pullRequestTarget === input.defaultBranch) : [];
|
|
15679
|
+
const track = byDefault.length === 1 ? byDefault[0] : null;
|
|
15680
|
+
const target = track ? `track ${track.name}` : `default target ${input.defaultBranch ?? "(none)"}`;
|
|
15681
|
+
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;
|
|
15682
|
+
return done(track, "default", `${why}; using the workspace ${target}`, [
|
|
15683
|
+
`release track not determined: ${why}; using the workspace ${target} (pass --track <name> to choose)`
|
|
15684
|
+
], ambiguous);
|
|
15685
|
+
};
|
|
15686
|
+
const branch = input.branch;
|
|
15687
|
+
if (branch) {
|
|
15688
|
+
const owners = ownedBy(candidates, branch);
|
|
15689
|
+
if (owners.length === 1)
|
|
15690
|
+
return done(owners[0], "branch", `${branch} is a branch of ${label(owners[0])}`);
|
|
15691
|
+
if (owners.length > 1)
|
|
15692
|
+
return fallback(`${branch} belongs to more than one track (${owners.map((track) => track.name).join(", ")})`);
|
|
15693
|
+
}
|
|
15694
|
+
const env = input.envRequested?.trim();
|
|
15695
|
+
if (env) {
|
|
15696
|
+
const named = tracks.find((track) => track.name === env);
|
|
15697
|
+
if (named)
|
|
15698
|
+
return done(named, "env", `WORKFLOW_RELEASE_TRACK selects track ${named.name}`);
|
|
15699
|
+
envProblem = `WORKFLOW_RELEASE_TRACK=${env} names no release track of this workspace (${names}); ignored`;
|
|
15700
|
+
}
|
|
15701
|
+
if (!branch)
|
|
15702
|
+
return fallback("HEAD is detached");
|
|
15703
|
+
if (tracks.length === 1 && !implicit)
|
|
15704
|
+
return done(tracks[0], "only-track", `${tracks[0].name} is the only track`);
|
|
15705
|
+
let remotes = null;
|
|
15706
|
+
const short = (ref) => shortRef(ref, remotes ??= input.probe.remotes());
|
|
15707
|
+
const ownerOf = (ref) => {
|
|
15708
|
+
const owner = ownedBy(candidates, short(ref));
|
|
15709
|
+
return owner.length === 1 ? owner[0] : null;
|
|
15710
|
+
};
|
|
15711
|
+
const followRecorded = (start) => {
|
|
15712
|
+
let cursor = start;
|
|
15713
|
+
const seen = new Set([start]);
|
|
15714
|
+
for (let hop = 0;hop < MAX_RECORDED_HOPS; hop += 1) {
|
|
15715
|
+
const recorded = input.probe.recordedBase(cursor);
|
|
15716
|
+
if (!recorded)
|
|
15717
|
+
return null;
|
|
15718
|
+
const base = short(recorded);
|
|
15719
|
+
const owner = ownerOf(base);
|
|
15720
|
+
if (owner)
|
|
15721
|
+
return owner;
|
|
15722
|
+
if (ownedBy(candidates, base).length > 1 || seen.has(base))
|
|
15723
|
+
return null;
|
|
15724
|
+
seen.add(base);
|
|
15725
|
+
cursor = base;
|
|
15726
|
+
}
|
|
15727
|
+
return null;
|
|
15728
|
+
};
|
|
15729
|
+
const recordedOwner = followRecorded(branch);
|
|
15730
|
+
if (recordedOwner)
|
|
15731
|
+
return done(recordedOwner, "recorded-base", `${branch} was created on ${label(recordedOwner)}'s line (recorded base)`);
|
|
15732
|
+
for (const source of ["reflog", "checkout"]) {
|
|
15733
|
+
const ref = source === "reflog" ? input.probe.createdFrom(branch) : input.probe.checkedOutFrom(branch);
|
|
15734
|
+
if (!ref)
|
|
15735
|
+
continue;
|
|
15736
|
+
const owner = ownerOf(ref) ?? followRecorded(short(ref));
|
|
15737
|
+
if (owner)
|
|
15738
|
+
return done(owner, source, `${branch} was created from ${short(ref)} (${source === "reflog" ? "branch reflog" : "HEAD reflog"})`);
|
|
15739
|
+
}
|
|
15740
|
+
const forks = [];
|
|
15741
|
+
for (const track of candidates)
|
|
15742
|
+
for (const ref of new Set([track.integrationBranch, track.baseBranch])) {
|
|
15743
|
+
const sha = input.probe.mergeBase(branch, ref);
|
|
15744
|
+
if (sha)
|
|
15745
|
+
forks.push({ track, ref, sha });
|
|
15746
|
+
}
|
|
15747
|
+
if (forks.length === 0)
|
|
15748
|
+
return fallback(`no track branch could be compared with ${branch} (fetch the track branches)`);
|
|
15749
|
+
const ancestry = new Map;
|
|
15750
|
+
const descends = (older, newer) => {
|
|
15751
|
+
if (older === newer)
|
|
15752
|
+
return false;
|
|
15753
|
+
const key = `${older}>${newer}`;
|
|
15754
|
+
if (!ancestry.has(key))
|
|
15755
|
+
ancestry.set(key, input.probe.isAncestor(older, newer));
|
|
15756
|
+
return ancestry.get(key);
|
|
15757
|
+
};
|
|
15758
|
+
const winners = forks.filter((fork) => forks.every((other) => other.track === fork.track || descends(other.sha, fork.sha)));
|
|
15759
|
+
const winningTracks = [...new Set(winners.map((fork) => fork.track))];
|
|
15760
|
+
if (winningTracks.length === 1 && forks.some((fork) => fork.track !== winningTracks[0])) {
|
|
15761
|
+
const win = winners[0];
|
|
15762
|
+
return done(win.track, "ancestry", `${branch} forked from ${win.ref} at ${win.sha.slice(0, 12)}, after every other line's fork point`);
|
|
15763
|
+
}
|
|
15764
|
+
if (winningTracks.length === 1)
|
|
15765
|
+
return fallback(`only ${label(winningTracks[0])} could be compared with ${branch}`);
|
|
15766
|
+
const newest = forks.filter((fork) => !forks.some((other) => descends(fork.sha, other.sha)));
|
|
15767
|
+
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 ")}`);
|
|
15768
|
+
}
|
|
15769
|
+
function gitTrackProbe(cwd) {
|
|
15770
|
+
let remote;
|
|
15771
|
+
let remotes;
|
|
15772
|
+
const tip = (branch) => {
|
|
15773
|
+
remote ??= pushRemoteName(cwd) ?? "origin";
|
|
15774
|
+
return resolveRef(cwd, `refs/remotes/${remote}/${branch}`) ?? resolveRef(cwd, `refs/heads/${branch}`);
|
|
15775
|
+
};
|
|
15776
|
+
return {
|
|
15777
|
+
remotes: () => remotes ??= remoteNames(cwd),
|
|
15778
|
+
recordedBase: (branch) => git4(cwd, ["config", "--get", recordedBaseKey(branch)]) || null,
|
|
15779
|
+
createdFrom: (branch) => {
|
|
15780
|
+
const log = git4(cwd, ["reflog", "show", "--format=%gs", `refs/heads/${branch}`, "--"]);
|
|
15781
|
+
const oldest = log?.split(`
|
|
15782
|
+
`).findLast(Boolean) ?? "";
|
|
15783
|
+
const match = /^branch: Created from (\S+)$/u.exec(oldest);
|
|
15784
|
+
return match && match[1] !== "HEAD" ? match[1] : null;
|
|
15785
|
+
},
|
|
15786
|
+
checkedOutFrom: (branch) => {
|
|
15787
|
+
const own = reflog(cwd, `refs/heads/${branch}`);
|
|
15788
|
+
const created = own.at(-1);
|
|
15789
|
+
if (!created || created.subject !== "branch: Created from HEAD")
|
|
15790
|
+
return null;
|
|
15791
|
+
const pattern = new RegExp(`^checkout: moving from (\\S+) to ${escapeRegExp(branch)}$`, "u");
|
|
15792
|
+
const entry = reflog(cwd, "HEAD").findLast((item) => item.time >= created.time && item.sha === created.sha && pattern.test(item.subject));
|
|
15793
|
+
return entry ? pattern.exec(entry.subject)?.[1] ?? null : null;
|
|
15794
|
+
},
|
|
15795
|
+
mergeBase: (branch, trackBranch) => {
|
|
15796
|
+
const base = tip(trackBranch);
|
|
15797
|
+
return base && resolveRef(cwd, `refs/heads/${branch}`) ? mergeBase(cwd, base, `refs/heads/${branch}`) : null;
|
|
15798
|
+
},
|
|
15799
|
+
isAncestor: (ancestor, descendant) => git4(cwd, ["merge-base", "--is-ancestor", ancestor, descendant]) !== null
|
|
15800
|
+
};
|
|
15801
|
+
}
|
|
15802
|
+
function workspaceReleaseTracks(cwd) {
|
|
15803
|
+
const raw = resolveRuntimeReleaseTracks(cwd);
|
|
15804
|
+
return { workspace: raw?.workspace ?? null, ...readReleaseTracks(raw?.releaseTracks) };
|
|
15805
|
+
}
|
|
15806
|
+
function resolveTrackFor(cwd, options) {
|
|
15807
|
+
const read = workspaceReleaseTracks(cwd);
|
|
15808
|
+
if (read.error)
|
|
15809
|
+
return { status: "invalid", error: read.error, issues: read.issues };
|
|
15810
|
+
if (read.tracks.length === 0 && !options.track?.trim())
|
|
15811
|
+
return { status: "none", issues: read.issues };
|
|
15812
|
+
const branch = options.branch === undefined ? currentBranch(cwd) : options.branch;
|
|
15813
|
+
const envRequested = process.env.WORKFLOW_RELEASE_TRACK?.trim() || null;
|
|
15814
|
+
const input = {
|
|
15815
|
+
tracks: read.tracks,
|
|
15816
|
+
requested: options.track ?? null,
|
|
15817
|
+
envRequested,
|
|
15818
|
+
branch,
|
|
15819
|
+
defaultBranch: options.defaultBranch,
|
|
15820
|
+
issues: read.issues
|
|
15821
|
+
};
|
|
15822
|
+
let key = null;
|
|
15823
|
+
if (!options.probe) {
|
|
15824
|
+
const refs = git4(cwd, [
|
|
15825
|
+
"for-each-ref",
|
|
15826
|
+
"--format=%(refname) %(objectname)",
|
|
15827
|
+
"refs/heads",
|
|
15828
|
+
"refs/remotes"
|
|
15829
|
+
]) ?? "";
|
|
15830
|
+
const head = git4(cwd, ["reflog", "show", "-n", "1", "--format=%H %gs", "HEAD", "--"]) ?? "";
|
|
15831
|
+
const own = branch ? [
|
|
15832
|
+
git4(cwd, [
|
|
15833
|
+
"log",
|
|
15834
|
+
"-g",
|
|
15835
|
+
"-n",
|
|
15836
|
+
"1",
|
|
15837
|
+
"--date=unix",
|
|
15838
|
+
"--format=%H %gd %gs",
|
|
15839
|
+
`refs/heads/${branch}`,
|
|
15840
|
+
"--"
|
|
15841
|
+
]) ?? "",
|
|
15842
|
+
git4(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
|
|
15843
|
+
] : [];
|
|
15844
|
+
key = createHash9("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
|
|
15845
|
+
const hit = memo3.get(key);
|
|
15846
|
+
if (hit)
|
|
15847
|
+
return hit;
|
|
15848
|
+
}
|
|
15849
|
+
const resolution = resolveReleaseTrack({ ...input, probe: options.probe ?? gitTrackProbe(cwd) });
|
|
15850
|
+
if (key) {
|
|
15851
|
+
if (memo3.size >= MEMO_LIMIT)
|
|
15852
|
+
memo3.delete(memo3.keys().next().value);
|
|
15853
|
+
memo3.set(key, resolution);
|
|
15854
|
+
}
|
|
15855
|
+
return resolution;
|
|
15856
|
+
}
|
|
15857
|
+
function releaseTracksReport(cwd) {
|
|
15858
|
+
let raw;
|
|
15859
|
+
try {
|
|
15860
|
+
raw = resolveRuntimeReleaseTracks(cwd);
|
|
15861
|
+
} catch (error) {
|
|
15862
|
+
return {
|
|
15863
|
+
workspace: null,
|
|
15864
|
+
tracks: [],
|
|
15865
|
+
resolved: null,
|
|
15866
|
+
warnings: [],
|
|
15867
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15868
|
+
};
|
|
15869
|
+
}
|
|
15870
|
+
const read = readReleaseTracks(raw?.releaseTracks);
|
|
15871
|
+
const tracks = read.tracks.map(({ name, integrationBranch, productionBranch }) => ({
|
|
15872
|
+
name,
|
|
15873
|
+
integrationBranch,
|
|
15874
|
+
productionBranch
|
|
15875
|
+
}));
|
|
15876
|
+
const base = { workspace: raw?.workspace ?? null, tracks };
|
|
15877
|
+
if (read.error)
|
|
15878
|
+
return { ...base, resolved: null, warnings: read.issues, error: read.error };
|
|
15879
|
+
if (tracks.length === 0)
|
|
15880
|
+
return { ...base, resolved: null, warnings: read.issues, error: null };
|
|
15881
|
+
let defaultBranch;
|
|
15882
|
+
try {
|
|
15883
|
+
defaultBranch = workspaceDefaultTarget(cwd, globalDefaultTarget());
|
|
15884
|
+
} catch (error) {
|
|
15885
|
+
return {
|
|
15886
|
+
...base,
|
|
15887
|
+
resolved: null,
|
|
15888
|
+
warnings: read.issues,
|
|
15889
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15890
|
+
};
|
|
15891
|
+
}
|
|
15892
|
+
const resolution = resolveTrackFor(cwd, { defaultBranch });
|
|
15893
|
+
if (resolution.status === "invalid")
|
|
15894
|
+
return { ...base, resolved: null, warnings: resolution.issues, error: resolution.error };
|
|
15895
|
+
if (resolution.status === "none")
|
|
15896
|
+
return { ...base, resolved: null, warnings: resolution.issues, error: null };
|
|
15897
|
+
return {
|
|
15898
|
+
...base,
|
|
15899
|
+
resolved: {
|
|
15900
|
+
name: resolution.track?.name ?? null,
|
|
15901
|
+
source: resolution.source,
|
|
15902
|
+
detail: resolution.detail
|
|
15903
|
+
},
|
|
15904
|
+
warnings: resolution.warnings,
|
|
15905
|
+
error: null
|
|
15906
|
+
};
|
|
15907
|
+
}
|
|
15908
|
+
var ReleaseTrackError, KNOWN_FIELDS, BRANCH_FIELDS, PLACEHOLDER, HAS_PLACEHOLDER, isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), branchName = (value) => typeof value === "string" && value.trim() && !value.trim().startsWith("-") ? value.trim() : null, namedBranches = (entry) => [
|
|
15909
|
+
...BRANCH_FIELDS.map((field) => branchName(entry[field])),
|
|
15910
|
+
...Array.isArray(entry.mergeBackBranches) ? entry.mergeBackBranches.map(branchName) : []
|
|
15911
|
+
].filter((name) => name !== null), literalOf = (template) => template.replace(PLACEHOLDER, "").replace(/[*/]/gu, "").trim(), trackBranches = (tracks) => [
|
|
15912
|
+
...new Set(tracks.flatMap((track) => [
|
|
15913
|
+
track.productionBranch,
|
|
15914
|
+
track.integrationBranch,
|
|
15915
|
+
track.baseBranch,
|
|
15916
|
+
track.pullRequestTarget,
|
|
15917
|
+
...track.mergeBackBranches
|
|
15918
|
+
]))
|
|
15919
|
+
], namingGlob = (template) => HAS_PLACEHOLDER.test(template) ? template.replace(PLACEHOLDER, "*") : `${template.replace(/\/?\*?$/u, "")}/*`, trackBranchName = (track, kind, slug) => {
|
|
15920
|
+
const template = track?.naming[kind];
|
|
15921
|
+
if (!template)
|
|
15922
|
+
return null;
|
|
15923
|
+
return HAS_PLACEHOLDER.test(template) ? template.replace(PLACEHOLDER, slug) : `${template.replace(/\/?\*?$/u, "")}/${slug}`;
|
|
15924
|
+
}, IMPLICIT = "", ownedBy = (tracks, branch) => tracks.filter((track) => [track.integrationBranch, track.productionBranch, track.baseBranch].includes(branch)), shortRef = (ref, remotes) => {
|
|
15925
|
+
const bare = ref.replace(/^refs\/heads\//u, "").replace(/^refs\/remotes\/[^/]+\//u, "");
|
|
15926
|
+
const remote = remotes.find((name) => bare.startsWith(`${name}/`));
|
|
15927
|
+
return remote ? bare.slice(remote.length + 1) : bare;
|
|
15928
|
+
}, MAX_RECORDED_HOPS = 10, git4 = (cwd, args) => {
|
|
15929
|
+
const run = spawnSync7("git", args, {
|
|
15930
|
+
cwd,
|
|
15931
|
+
encoding: "utf8",
|
|
15932
|
+
timeout: 20000,
|
|
15933
|
+
windowsHide: true,
|
|
15934
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
15935
|
+
});
|
|
15936
|
+
return run.status === 0 ? (run.stdout ?? "").trim() : null;
|
|
15937
|
+
}, recordedBaseKey = (branch) => `branch.${branch}.workitBase`, recordBranchBase = (cwd, branch, base) => {
|
|
15938
|
+
git4(cwd, ["config", recordedBaseKey(branch), base]);
|
|
15939
|
+
}, escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"), reflog = (cwd, ref) => (git4(cwd, ["log", "-g", "--date=unix", "--format=%H%x09%gd%x09%gs", ref, "--"]) ?? "").split(`
|
|
15940
|
+
`).map((line) => {
|
|
15941
|
+
const [sha = "", selector = "", ...subject] = line.split("\t");
|
|
15942
|
+
return {
|
|
15943
|
+
sha,
|
|
15944
|
+
time: Number(/@\{(\d+)\}$/u.exec(selector)?.[1] ?? Number.NaN),
|
|
15945
|
+
subject: subject.join("\t")
|
|
15946
|
+
};
|
|
15947
|
+
}).filter((entry) => entry.sha && Number.isFinite(entry.time)), globalDefaultTarget = () => {
|
|
15948
|
+
try {
|
|
15949
|
+
const parsed = JSON.parse(readFileSync5(vcsConfigPath(), "utf8"));
|
|
15950
|
+
return isRecord3(parsed) ? parsed.defaultTargetBranch : undefined;
|
|
15951
|
+
} catch {
|
|
15952
|
+
return;
|
|
15953
|
+
}
|
|
15954
|
+
}, memo3, MEMO_LIMIT = 64, describeReleaseTracks = (report) => report.tracks.length === 0 && !report.error ? [] : [
|
|
15955
|
+
`release tracks: ${report.tracks.map((track) => `${track.name} (${track.integrationBranch} -> ${track.productionBranch})`).join(", ") || "(none usable)"}`,
|
|
15956
|
+
...report.resolved ? [
|
|
15957
|
+
`this checkout: ${report.resolved.name ?? "workspace default"} (${report.resolved.detail})`
|
|
15958
|
+
] : [],
|
|
15959
|
+
...report.error ? [`release tracks error: ${report.error}`] : [],
|
|
15960
|
+
...report.warnings.map((warning) => `note: ${warning}`)
|
|
15961
|
+
];
|
|
15962
|
+
var init_release_tracks = __esm(() => {
|
|
15963
|
+
init_rev();
|
|
15964
|
+
init_config();
|
|
15965
|
+
init_workspaces();
|
|
15966
|
+
ReleaseTrackError = class ReleaseTrackError extends Error {
|
|
15967
|
+
};
|
|
15968
|
+
KNOWN_FIELDS = new Set([
|
|
15969
|
+
"strategy",
|
|
15970
|
+
"productionBranch",
|
|
15971
|
+
"integrationBranch",
|
|
15972
|
+
"naming",
|
|
15973
|
+
"baseBranch",
|
|
15974
|
+
"mergeBackBranches",
|
|
15975
|
+
"pullRequestTarget",
|
|
15976
|
+
"tagNamespace",
|
|
15977
|
+
"versionSource",
|
|
15978
|
+
"requiredChecks",
|
|
15979
|
+
"critical"
|
|
15980
|
+
]);
|
|
15981
|
+
BRANCH_FIELDS = ["productionBranch", "integrationBranch", "baseBranch", "pullRequestTarget"];
|
|
15982
|
+
PLACEHOLDER = /\{[^}]*\}/gu;
|
|
15983
|
+
HAS_PLACEHOLDER = /\{[^}]*\}/u;
|
|
15984
|
+
memo3 = new Map;
|
|
15985
|
+
});
|
|
15986
|
+
|
|
15505
15987
|
// packages/workit-core/src/core/vcs-config.ts
|
|
15506
15988
|
import fs12 from "node:fs";
|
|
15507
15989
|
import path15 from "node:path";
|
|
15508
|
-
import { spawnSync as
|
|
15509
|
-
function vcsConfig(mode, cwd) {
|
|
15990
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
15991
|
+
function vcsConfig(mode, cwd, options = {}) {
|
|
15510
15992
|
const ws = resolveRuntimeWorkspaceVcs(vcsCwd(cwd));
|
|
15511
15993
|
const wsVcs = ws?.vcs ?? {};
|
|
15512
15994
|
const wsYt = ws?.youtrack ?? {};
|
|
@@ -15516,10 +15998,7 @@ function vcsConfig(mode, cwd) {
|
|
|
15516
15998
|
const determinateRoot = cwd !== undefined || process.env.WORKFLOW_WORKSPACE_ROOT !== undefined;
|
|
15517
15999
|
const rawProvider = wsVcs.provider ?? (determinateRoot ? remoteProvider(root) : null) ?? cfg.provider ?? null;
|
|
15518
16000
|
const provider = rawProvider === null || rawProvider === undefined ? null : String(rawProvider).toLowerCase() || null;
|
|
15519
|
-
const
|
|
15520
|
-
const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
|
|
15521
|
-
const policyDefault = resolveBranchPolicyFor(root).defaultTargetBranch;
|
|
15522
|
-
const defaultTarget = String(wsVcs.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : cfg.defaultTargetBranch ?? policyDefault) ?? "develop");
|
|
16001
|
+
const workspaceDefault = workspaceDefaultTarget(root, cfg.defaultTargetBranch);
|
|
15523
16002
|
const linkIssues = typeof wsYt.link_issues === "boolean" ? wsYt.link_issues : null;
|
|
15524
16003
|
const youtrackBaseUrl = typeof wsYt.baseUrl === "string" ? wsYt.baseUrl : null;
|
|
15525
16004
|
let issuesProvider = null;
|
|
@@ -15531,11 +16010,24 @@ function vcsConfig(mode, cwd) {
|
|
|
15531
16010
|
if (mode === "resolve") {
|
|
15532
16011
|
if (cfgStatus === "malformed")
|
|
15533
16012
|
return { ok: false, error: cfgError, configPath: cfgPath };
|
|
16013
|
+
const trackResolution = resolveTrackFor(root, {
|
|
16014
|
+
track: options.track,
|
|
16015
|
+
...options.branch !== undefined ? { branch: options.branch } : {},
|
|
16016
|
+
defaultBranch: workspaceDefault
|
|
16017
|
+
});
|
|
16018
|
+
if (trackResolution.status === "invalid")
|
|
16019
|
+
return { ok: false, error: trackResolution.error, configPath: workspacesPath() };
|
|
16020
|
+
const releaseTrack = trackSummary(trackResolution);
|
|
16021
|
+
const defaultTarget = releaseTrack?.track?.pullRequestTarget ?? workspaceDefault;
|
|
16022
|
+
const baseBranch = releaseTrack?.track?.baseBranch ?? defaultTarget;
|
|
15534
16023
|
return {
|
|
15535
16024
|
ok: true,
|
|
15536
16025
|
workspace_name: ws?.name ?? null,
|
|
15537
16026
|
provider,
|
|
15538
16027
|
defaultTargetBranch: defaultTarget,
|
|
16028
|
+
workspaceDefaultTargetBranch: workspaceDefault,
|
|
16029
|
+
baseBranch,
|
|
16030
|
+
releaseTrack,
|
|
15539
16031
|
link_issues: linkIssues,
|
|
15540
16032
|
youtrack_base_url: youtrackBaseUrl,
|
|
15541
16033
|
issues_provider: issuesProvider,
|
|
@@ -15559,7 +16051,7 @@ function vcsConfig(mode, cwd) {
|
|
|
15559
16051
|
ok: true,
|
|
15560
16052
|
configPath: path15.resolve(cfgPath),
|
|
15561
16053
|
provider,
|
|
15562
|
-
defaultTargetBranch:
|
|
16054
|
+
defaultTargetBranch: workspaceDefault,
|
|
15563
16055
|
pr: cfg.pr ?? {},
|
|
15564
16056
|
workspace_name: ws?.name ?? null,
|
|
15565
16057
|
link_issues: linkIssues,
|
|
@@ -15577,8 +16069,8 @@ function vcsConfig(mode, cwd) {
|
|
|
15577
16069
|
}
|
|
15578
16070
|
return out;
|
|
15579
16071
|
}
|
|
15580
|
-
var
|
|
15581
|
-
const r =
|
|
16072
|
+
var workspacesPath = () => path15.join(configDir(), "workspaces.json"), vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd(), remoteProvider = (cwd) => {
|
|
16073
|
+
const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
15582
16074
|
if (r.status !== 0)
|
|
15583
16075
|
return null;
|
|
15584
16076
|
const url = (r.stdout ?? "").trim();
|
|
@@ -15605,29 +16097,60 @@ var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path15.join(configD
|
|
|
15605
16097
|
return { status: "valid", path: file, config: parsed };
|
|
15606
16098
|
}
|
|
15607
16099
|
return { status: "malformed", path: file, config: {}, error: `${file} is not a JSON object` };
|
|
15608
|
-
}
|
|
16100
|
+
}, trackSummary = (resolution) => resolution.status === "resolved" ? {
|
|
16101
|
+
name: resolution.track?.name ?? null,
|
|
16102
|
+
source: resolution.source,
|
|
16103
|
+
detail: resolution.detail,
|
|
16104
|
+
warnings: resolution.warnings,
|
|
16105
|
+
track: resolution.track,
|
|
16106
|
+
tracks: resolution.tracks,
|
|
16107
|
+
blocking: resolution.blocking
|
|
16108
|
+
} : null;
|
|
15609
16109
|
var init_vcs_config = __esm(() => {
|
|
15610
16110
|
init_config();
|
|
15611
16111
|
init_workspaces();
|
|
15612
|
-
|
|
16112
|
+
init_release_tracks();
|
|
15613
16113
|
});
|
|
15614
16114
|
|
|
15615
16115
|
// packages/workit-core/src/core/branch.ts
|
|
15616
16116
|
import { execFileSync } from "node:child_process";
|
|
15617
|
-
import { createHash as
|
|
16117
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
15618
16118
|
import path16 from "node:path";
|
|
15619
16119
|
function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
15620
16120
|
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
15621
16121
|
const config = readConfig();
|
|
15622
16122
|
return kind === "branch" ? {
|
|
15623
|
-
branchPolicy: resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null),
|
|
16123
|
+
branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null)),
|
|
15624
16124
|
provenance: { branchPolicy: selected.source }
|
|
15625
16125
|
} : {
|
|
15626
16126
|
commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
|
|
15627
16127
|
provenance: { commitPolicy: selected.source }
|
|
15628
16128
|
};
|
|
15629
16129
|
}
|
|
15630
|
-
var
|
|
16130
|
+
var withReleaseTracks = (workspaceRoot, policy) => {
|
|
16131
|
+
const read = workspaceReleaseTracks(workspaceRoot);
|
|
16132
|
+
if (read.error)
|
|
16133
|
+
throw new ReleaseTrackError(read.error);
|
|
16134
|
+
if (read.tracks.length === 0 && read.protectedBranches.length === 0)
|
|
16135
|
+
return policy;
|
|
16136
|
+
const known = new Set(policy.allowed.map((pattern) => pattern.source));
|
|
16137
|
+
const allowed = [...policy.allowed];
|
|
16138
|
+
for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
|
|
16139
|
+
const pattern = branchGlobPattern(glob);
|
|
16140
|
+
if (!known.has(pattern.source)) {
|
|
16141
|
+
known.add(pattern.source);
|
|
16142
|
+
allowed.push(pattern);
|
|
16143
|
+
}
|
|
16144
|
+
}
|
|
16145
|
+
return {
|
|
16146
|
+
...policy,
|
|
16147
|
+
allowed,
|
|
16148
|
+
protected: new Set([
|
|
16149
|
+
...policy.protected,
|
|
16150
|
+
...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
|
|
16151
|
+
])
|
|
16152
|
+
};
|
|
16153
|
+
}, validateBranchNamePolicy = (name, policy, source) => {
|
|
15631
16154
|
const allowed = policy.allowed.map((pattern) => `/${pattern.source}/${pattern.flags}`);
|
|
15632
16155
|
if (policy.protected.has(name.toLowerCase())) {
|
|
15633
16156
|
const correction = `choose a non-protected branch matching one of: ${allowed.join(", ")}`;
|
|
@@ -15658,7 +16181,7 @@ var validateBranchNamePolicy = (name, policy, source) => {
|
|
|
15658
16181
|
const source = resolved.provenance.branchPolicy;
|
|
15659
16182
|
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
15660
16183
|
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
15661
|
-
const fingerprint =
|
|
16184
|
+
const fingerprint = createHash10("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
15662
16185
|
return {
|
|
15663
16186
|
branchPolicy,
|
|
15664
16187
|
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
@@ -15669,7 +16192,7 @@ var validateBranchNamePolicy = (name, policy, source) => {
|
|
|
15669
16192
|
const resolved = effectiveWorkspacePolicy(workspaceRoot, "commit");
|
|
15670
16193
|
const policy = resolved.commitPolicy;
|
|
15671
16194
|
const source = resolved.provenance.commitPolicy;
|
|
15672
|
-
const fingerprint =
|
|
16195
|
+
const fingerprint = createHash10("sha256").update(JSON.stringify({ preset: policy.preset, pattern: policy.pattern ?? null, source })).digest("hex");
|
|
15673
16196
|
return { policy, source, fingerprint };
|
|
15674
16197
|
}, validateCommitMessagePolicy = (message, policy, source) => {
|
|
15675
16198
|
const attempted = message.split(`
|
|
@@ -15759,6 +16282,7 @@ var init_branch = __esm(() => {
|
|
|
15759
16282
|
init_config();
|
|
15760
16283
|
init_workspaces();
|
|
15761
16284
|
init_vcs_config();
|
|
16285
|
+
init_release_tracks();
|
|
15762
16286
|
});
|
|
15763
16287
|
|
|
15764
16288
|
// packages/workit-core/src/core/route-intent.ts
|
|
@@ -15767,11 +16291,11 @@ var init_route_intent = __esm(() => {
|
|
|
15767
16291
|
});
|
|
15768
16292
|
|
|
15769
16293
|
// packages/workit-core/src/core/runtime-identity.ts
|
|
15770
|
-
import { createHash as
|
|
15771
|
-
import { readFileSync as
|
|
15772
|
-
var sha256Hex = (bytes) =>
|
|
16294
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
16295
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
16296
|
+
var sha256Hex = (bytes) => createHash11("sha256").update(bytes).digest("hex"), bundleHashOfFile = (file) => {
|
|
15773
16297
|
try {
|
|
15774
|
-
return sha256Hex(
|
|
16298
|
+
return sha256Hex(readFileSync6(file));
|
|
15775
16299
|
} catch {
|
|
15776
16300
|
return null;
|
|
15777
16301
|
}
|
|
@@ -17796,7 +18320,7 @@ var init_pr_body = __esm(() => {
|
|
|
17796
18320
|
|
|
17797
18321
|
// packages/workit-core/src/core/pr-create.ts
|
|
17798
18322
|
import path19 from "node:path";
|
|
17799
|
-
import { spawnSync as
|
|
18323
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
17800
18324
|
import { pathToFileURL } from "node:url";
|
|
17801
18325
|
var safePushUrl = (remote) => {
|
|
17802
18326
|
const raw = remote.trim();
|
|
@@ -17824,7 +18348,7 @@ var safePushUrl = (remote) => {
|
|
|
17824
18348
|
const target = safePushUrl(remote);
|
|
17825
18349
|
if (!target)
|
|
17826
18350
|
return false;
|
|
17827
|
-
const result =
|
|
18351
|
+
const result = spawnSync9("git", ["config", "--get-regexp", "^url\\..*\\.(insteadof|pushinsteadof)$"], { cwd, encoding: "utf8" });
|
|
17828
18352
|
if (result.status !== 0 && result.status !== 1)
|
|
17829
18353
|
return false;
|
|
17830
18354
|
const prefixes = (result.stdout ?? "").split(/\r?\n/u).map((line) => line.trim().slice(line.trim().indexOf(" ") + 1)).filter(Boolean);
|
|
@@ -18400,7 +18924,7 @@ var init_core3 = __esm(() => {
|
|
|
18400
18924
|
});
|
|
18401
18925
|
|
|
18402
18926
|
// packages/workit-cli/src/task.ts
|
|
18403
|
-
import { readFileSync as
|
|
18927
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
18404
18928
|
import path22 from "node:path";
|
|
18405
18929
|
async function readInput(input) {
|
|
18406
18930
|
if (typeof input === "string")
|
|
@@ -18417,7 +18941,7 @@ async function payloadValue(raw, deps) {
|
|
|
18417
18941
|
return { ok: true, value: {} };
|
|
18418
18942
|
let source;
|
|
18419
18943
|
try {
|
|
18420
|
-
source = raw === "-" ? await readInput(deps.stdin ?? process.stdin) : raw.startsWith("@") ? decodeUtf8(
|
|
18944
|
+
source = raw === "-" ? await readInput(deps.stdin ?? process.stdin) : raw.startsWith("@") ? decodeUtf8(readFileSync7(raw.slice(1))) : raw;
|
|
18421
18945
|
} catch (error) {
|
|
18422
18946
|
return {
|
|
18423
18947
|
ok: false,
|
|
@@ -18750,7 +19274,7 @@ function isImplicitTaskForm(argv) {
|
|
|
18750
19274
|
const [action, first] = argv;
|
|
18751
19275
|
if (!action)
|
|
18752
19276
|
return false;
|
|
18753
|
-
if (
|
|
19277
|
+
if (IMPLICIT2.has(action))
|
|
18754
19278
|
return true;
|
|
18755
19279
|
if (action === "start")
|
|
18756
19280
|
return first !== undefined && !first.startsWith("--");
|
|
@@ -18948,7 +19472,7 @@ async function run(argv, io) {
|
|
|
18948
19472
|
}
|
|
18949
19473
|
return emit(io, fail("invalid_input", `unknown task action ${action ?? ""}`, { unblock: USAGE }));
|
|
18950
19474
|
}
|
|
18951
|
-
var USAGE = 'workit task status [--all] | task start "<objective>" | task note "<text>" [--next "<t>"] [--objective "<t>"] | task close [--outcome verified|limited|stopped] [--summary "<t>"] [--confirm] | task adopt <id>',
|
|
19475
|
+
var USAGE = 'workit task status [--all] | task start "<objective>" | task note "<text>" [--next "<t>"] [--objective "<t>"] | task close [--outcome verified|limited|stopped] [--summary "<t>"] [--confirm] | task adopt <id>', IMPLICIT2, VALUE_FLAGS, SWITCHES, ENGINE_CODES, engineFailure = (io, result, unblock) => emit(io, fail(ENGINE_CODES[result.code] ?? "failed", `${result.code}: ${result.error}`, {
|
|
18952
19476
|
data: { code: result.code },
|
|
18953
19477
|
...unblock ? { unblock } : result.code === "busy" ? { unblock: "retry the same command" } : {}
|
|
18954
19478
|
})), OUTCOMES, rootFor = (io) => io.env.WORKFLOW_WORKSPACE_ROOT || checkRoot(io.cwd);
|
|
@@ -18956,7 +19480,7 @@ var init_task2 = __esm(() => {
|
|
|
18956
19480
|
init_check_config();
|
|
18957
19481
|
init_output();
|
|
18958
19482
|
init_task();
|
|
18959
|
-
|
|
19483
|
+
IMPLICIT2 = new Set(["status", "note", "adopt"]);
|
|
18960
19484
|
VALUE_FLAGS = new Set(["--next", "--objective", "--outcome", "--summary"]);
|
|
18961
19485
|
SWITCHES = new Set(["--all", "--json", "--confirm"]);
|
|
18962
19486
|
ENGINE_CODES = {
|
|
@@ -61542,7 +62066,7 @@ var init_gitignore = __esm(() => {
|
|
|
61542
62066
|
// packages/workit-core/src/core/changelog.ts
|
|
61543
62067
|
import fs16 from "node:fs";
|
|
61544
62068
|
import path23 from "node:path";
|
|
61545
|
-
import { createHash as
|
|
62069
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
61546
62070
|
function normalizeBullet(text) {
|
|
61547
62071
|
text = text.trim();
|
|
61548
62072
|
const m = BULLET_RE.exec(text);
|
|
@@ -61829,7 +62353,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
61829
62353
|
|
|
61830
62354
|
## [Unreleased]
|
|
61831
62355
|
|
|
61832
|
-
`, digestBytes2 = (value) =>
|
|
62356
|
+
`, digestBytes2 = (value) => createHash12("sha256").update(value).digest("hex"), readChangelogSource = (target) => {
|
|
61833
62357
|
if (!fs16.existsSync(target)) {
|
|
61834
62358
|
const bytes = Buffer.from(SKELETON, "utf8");
|
|
61835
62359
|
return { exists: false, bytes, text: SKELETON };
|
|
@@ -61869,13 +62393,13 @@ var init_changelog = __esm(() => {
|
|
|
61869
62393
|
});
|
|
61870
62394
|
|
|
61871
62395
|
// packages/workit-core/src/core/hygiene.ts
|
|
61872
|
-
import { existsSync as existsSync9, readFileSync as
|
|
62396
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
|
|
61873
62397
|
import path24 from "node:path";
|
|
61874
62398
|
var repoRoot2, templatesDir = () => path24.join(repoRoot2, "templates", "hygiene"), packageJson = (root) => {
|
|
61875
62399
|
if (!existsSync9(path24.join(root, "package.json")))
|
|
61876
62400
|
return null;
|
|
61877
62401
|
try {
|
|
61878
|
-
return JSON.parse(
|
|
62402
|
+
return JSON.parse(readFileSync9(path24.join(root, "package.json"), "utf8"));
|
|
61879
62403
|
} catch {
|
|
61880
62404
|
return null;
|
|
61881
62405
|
}
|
|
@@ -61911,7 +62435,7 @@ var repoRoot2, templatesDir = () => path24.join(repoRoot2, "templates", "hygiene
|
|
|
61911
62435
|
const tpl = path24.join(templatesDir(), file);
|
|
61912
62436
|
if (!existsSync9(tpl))
|
|
61913
62437
|
continue;
|
|
61914
|
-
const content =
|
|
62438
|
+
const content = readFileSync9(tpl, "utf8").replace(/<PROJECT>/g, path24.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
|
|
61915
62439
|
planned.push({ path: path24.join(root, file), content });
|
|
61916
62440
|
}
|
|
61917
62441
|
return planned;
|
|
@@ -61923,13 +62447,13 @@ var init_hygiene = __esm(() => {
|
|
|
61923
62447
|
});
|
|
61924
62448
|
|
|
61925
62449
|
// packages/workit-cli/src/admin/setup-state.ts
|
|
61926
|
-
import { existsSync as existsSync10, readFileSync as
|
|
62450
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
|
|
61927
62451
|
import path25 from "node:path";
|
|
61928
62452
|
var classifySetupFile = (dir, name) => {
|
|
61929
62453
|
const file = path25.join(dir, name);
|
|
61930
62454
|
let raw;
|
|
61931
62455
|
try {
|
|
61932
|
-
raw =
|
|
62456
|
+
raw = readFileSync10(file, "utf8");
|
|
61933
62457
|
} catch {
|
|
61934
62458
|
if (existsSync10(file)) {
|
|
61935
62459
|
return { file, status: "malformed", error: `${file} is not readable` };
|
|
@@ -61978,7 +62502,7 @@ function mergeOpenCodePlugins(plugin, pin) {
|
|
|
61978
62502
|
return { config, changed };
|
|
61979
62503
|
}
|
|
61980
62504
|
function mergeOpenCodeConfig(config, pin) {
|
|
61981
|
-
const base =
|
|
62505
|
+
const base = isRecord4(config) ? { ...config } : {};
|
|
61982
62506
|
const changed = [];
|
|
61983
62507
|
const plugins = mergeOpenCodePlugins(base.plugin, pin);
|
|
61984
62508
|
if (plugins.changed.length > 0) {
|
|
@@ -61988,7 +62512,7 @@ function mergeOpenCodeConfig(config, pin) {
|
|
|
61988
62512
|
return { config: base, changed };
|
|
61989
62513
|
}
|
|
61990
62514
|
function mergeCursorEnabledPlugins(enabled) {
|
|
61991
|
-
const prev =
|
|
62515
|
+
const prev = isRecord4(enabled) ? { ...enabled } : {};
|
|
61992
62516
|
const next = { ...prev, workit: true };
|
|
61993
62517
|
delete next["workflow-toolkit"];
|
|
61994
62518
|
delete next["local/workflow-toolkit"];
|
|
@@ -62010,7 +62534,7 @@ function mergeCursorPluginDirs(pluginDirs, pluginDir) {
|
|
|
62010
62534
|
return { config: next, changed };
|
|
62011
62535
|
}
|
|
62012
62536
|
function mergeCursorSettings(settings, pluginDir) {
|
|
62013
|
-
const base =
|
|
62537
|
+
const base = isRecord4(settings) ? { ...settings } : {};
|
|
62014
62538
|
const changed = [];
|
|
62015
62539
|
const enabled = mergeCursorEnabledPlugins(base.enabled_plugins);
|
|
62016
62540
|
if (enabled.changed.length > 0) {
|
|
@@ -62025,8 +62549,8 @@ function mergeCursorSettings(settings, pluginDir) {
|
|
|
62025
62549
|
return { config: base, changed };
|
|
62026
62550
|
}
|
|
62027
62551
|
function mergeCursorMcp(mcp, serverName, server) {
|
|
62028
|
-
const base =
|
|
62029
|
-
const servers =
|
|
62552
|
+
const base = isRecord4(mcp) ? { ...mcp } : {};
|
|
62553
|
+
const servers = isRecord4(base.mcpServers) ? { ...base.mcpServers } : {};
|
|
62030
62554
|
delete servers["workflow-toolkit"];
|
|
62031
62555
|
servers[serverName] = server;
|
|
62032
62556
|
const changed = JSON.stringify(servers) !== JSON.stringify(base.mcpServers) ? ["mcpServers"] : [];
|
|
@@ -62034,7 +62558,7 @@ function mergeCursorMcp(mcp, serverName, server) {
|
|
|
62034
62558
|
return { config: base, changed };
|
|
62035
62559
|
}
|
|
62036
62560
|
function cursorHookDrift(installed) {
|
|
62037
|
-
if (!
|
|
62561
|
+
if (!isRecord4(installed) || !isRecord4(installed.hooks))
|
|
62038
62562
|
return ["hooks file is not a hook map"];
|
|
62039
62563
|
const hooks = installed.hooks;
|
|
62040
62564
|
const drift = [];
|
|
@@ -62044,7 +62568,7 @@ function cursorHookDrift(installed) {
|
|
|
62044
62568
|
continue;
|
|
62045
62569
|
const canonical = canonicalHookEntry(event);
|
|
62046
62570
|
const entry = Array.isArray(list) ? list[0] : undefined;
|
|
62047
|
-
if (!
|
|
62571
|
+
if (!isRecord4(entry) || entry.command !== canonical.command || event === "preToolUse" && entry.matcher !== canonical.matcher)
|
|
62048
62572
|
drift.push(event);
|
|
62049
62573
|
}
|
|
62050
62574
|
return drift;
|
|
@@ -62068,7 +62592,7 @@ function cursorHooksEntry(_packageDir) {
|
|
|
62068
62592
|
args: []
|
|
62069
62593
|
};
|
|
62070
62594
|
}
|
|
62071
|
-
var OPENCODE_NPM_PIN = "@brainervirus/workit-opencode",
|
|
62595
|
+
var OPENCODE_NPM_PIN = "@brainervirus/workit-opencode", isRecord4 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), named = (s, name) => s === name || s.startsWith(`${name}@`), CURSOR_RUNTIME_PACKAGE = "@brainervirus/workit-cursor@latest", CURSOR_HOOK_RUN_COMMAND, CURSOR_PRETOOLUSE_MATCHER = "Write|Edit|Delete|Shell|Remove|ApplyPatch|Apply_Patch|Patch|Rename|Mkdir|Mv|Cp|Touch", canonicalHookEntry = (event) => event === "preToolUse" ? { command: CURSOR_HOOK_RUN_COMMAND, matcher: CURSOR_PRETOOLUSE_MATCHER, failClosed: true } : { command: CURSOR_HOOK_RUN_COMMAND, failClosed: true };
|
|
62072
62596
|
var init_registration = __esm(() => {
|
|
62073
62597
|
CURSOR_HOOK_RUN_COMMAND = `npx -y --prefer-online --min-release-age=0 --package=${CURSOR_RUNTIME_PACKAGE} workit-cursor-hook`;
|
|
62074
62598
|
});
|
|
@@ -62087,12 +62611,12 @@ var init_support_matrix = __esm(() => {
|
|
|
62087
62611
|
});
|
|
62088
62612
|
|
|
62089
62613
|
// packages/workit-cli/src/admin/host-install.ts
|
|
62090
|
-
import { spawnSync as
|
|
62614
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
62091
62615
|
import {
|
|
62092
62616
|
accessSync,
|
|
62093
62617
|
constants as constants2,
|
|
62094
62618
|
existsSync as existsSync11,
|
|
62095
|
-
readFileSync as
|
|
62619
|
+
readFileSync as readFileSync11,
|
|
62096
62620
|
readdirSync as readdirSync4,
|
|
62097
62621
|
realpathSync as realpathSync6,
|
|
62098
62622
|
statSync as statSync2
|
|
@@ -62358,7 +62882,7 @@ function runHostCommand(step, context = {}) {
|
|
|
62358
62882
|
stderr: `Cannot safely execute batch shim ${step.command}; resolve its Node.js CLI entrypoint and retry`
|
|
62359
62883
|
};
|
|
62360
62884
|
}
|
|
62361
|
-
const result =
|
|
62885
|
+
const result = spawnSync10(step.command, step.args, {
|
|
62362
62886
|
cwd: step.cwd,
|
|
62363
62887
|
env: (() => {
|
|
62364
62888
|
const home = context.home ?? context.env?.HOME ?? os6.homedir();
|
|
@@ -62382,7 +62906,7 @@ function runHostCommand(step, context = {}) {
|
|
|
62382
62906
|
}
|
|
62383
62907
|
var resolveWindowsShimScript = (shim) => {
|
|
62384
62908
|
try {
|
|
62385
|
-
const contents =
|
|
62909
|
+
const contents = readFileSync11(shim, "utf8");
|
|
62386
62910
|
return resolveWindowsShimEntry(contents, shim);
|
|
62387
62911
|
} catch {
|
|
62388
62912
|
return null;
|
|
@@ -62403,7 +62927,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62403
62927
|
}, isPiWorkitInstalled = (home, env = process.env) => {
|
|
62404
62928
|
const settings = path27.join(env.PI_CODING_AGENT_DIR ?? path27.join(home, ".pi", "agent"), "settings.json");
|
|
62405
62929
|
try {
|
|
62406
|
-
const document2 = JSON.parse(
|
|
62930
|
+
const document2 = JSON.parse(readFileSync11(settings, "utf8"));
|
|
62407
62931
|
return (document2.packages ?? []).some((entry) => {
|
|
62408
62932
|
const source = entry && typeof entry === "object" && !Array.isArray(entry) ? entry.source : entry;
|
|
62409
62933
|
const value = String(source).replaceAll("\\", "/").replace(/\/+$/, "");
|
|
@@ -62418,7 +62942,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62418
62942
|
path27.join(root, "package.json")
|
|
62419
62943
|
]) {
|
|
62420
62944
|
try {
|
|
62421
|
-
const manifest = JSON.parse(
|
|
62945
|
+
const manifest = JSON.parse(readFileSync11(file, "utf8"));
|
|
62422
62946
|
const repository = typeof manifest.repository === "string" ? manifest.repository : manifest.repository?.url;
|
|
62423
62947
|
if ((manifest.name === "workit" || manifest.name === "@brainervirus/workit-codex") && repository?.replace(/\.git$/, "").toLowerCase() === "https://github.com/brainervirus/workit")
|
|
62424
62948
|
return true;
|
|
@@ -62459,7 +62983,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62459
62983
|
return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
|
|
62460
62984
|
}, isCanonicalClaudePlugin = (root) => {
|
|
62461
62985
|
try {
|
|
62462
|
-
const manifest = JSON.parse(
|
|
62986
|
+
const manifest = JSON.parse(readFileSync11(path27.join(root, ".claude-plugin", "plugin.json"), "utf8"));
|
|
62463
62987
|
const repository = typeof manifest.repository === "string" ? manifest.repository : manifest.repository?.url;
|
|
62464
62988
|
return manifest.name === "workit" && repository?.replace(/\.git$/, "").toLowerCase() === "https://github.com/brainervirus/workit";
|
|
62465
62989
|
} catch {
|
|
@@ -62469,7 +62993,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62469
62993
|
const file = path27.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json");
|
|
62470
62994
|
let registry;
|
|
62471
62995
|
try {
|
|
62472
|
-
registry = JSON.parse(
|
|
62996
|
+
registry = JSON.parse(readFileSync11(file, "utf8"));
|
|
62473
62997
|
} catch {
|
|
62474
62998
|
return [];
|
|
62475
62999
|
}
|
|
@@ -62518,7 +63042,7 @@ var init_host_install = __esm(() => {
|
|
|
62518
63042
|
});
|
|
62519
63043
|
|
|
62520
63044
|
// packages/workit-core/src/core/skill-manifests.ts
|
|
62521
|
-
import { existsSync as existsSync12, readFileSync as
|
|
63045
|
+
import { existsSync as existsSync12, readFileSync as readFileSync12, readdirSync as readdirSync5, statSync as statSync3 } from "node:fs";
|
|
62522
63046
|
import path28 from "node:path";
|
|
62523
63047
|
var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync12(root) ? readdirSync5(root).filter((name) => existsSync12(path28.join(root, name, "SKILL.md"))).toSorted() : [], validateSkillManifests = (root, expected, label) => {
|
|
62524
63048
|
const actual = skillManifestNames(root);
|
|
@@ -62536,7 +63060,7 @@ var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync12(root) ? re
|
|
|
62536
63060
|
const file = path28.join(dir, entry.name);
|
|
62537
63061
|
if (entry.isDirectory())
|
|
62538
63062
|
pending.push(file);
|
|
62539
|
-
else if ((statSync3(file).mode & 73) !== 0 ||
|
|
63063
|
+
else if ((statSync3(file).mode & 73) !== 0 || readFileSync12(file).subarray(0, 2).toString("latin1") === "#!") {
|
|
62540
63064
|
return `Cursor vendor contains active file: ${file}`;
|
|
62541
63065
|
}
|
|
62542
63066
|
}
|
|
@@ -62561,13 +63085,13 @@ var init_skill_manifests = __esm(() => {
|
|
|
62561
63085
|
});
|
|
62562
63086
|
|
|
62563
63087
|
// packages/workit-cli/src/admin/doctor.ts
|
|
62564
|
-
import { spawnSync as
|
|
63088
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
62565
63089
|
import {
|
|
62566
63090
|
existsSync as existsSync13,
|
|
62567
63091
|
lstatSync as lstatSync4,
|
|
62568
63092
|
mkdirSync as mkdirSync4,
|
|
62569
63093
|
mkdtempSync,
|
|
62570
|
-
readFileSync as
|
|
63094
|
+
readFileSync as readFileSync13,
|
|
62571
63095
|
readlinkSync as readlinkSync2,
|
|
62572
63096
|
rmSync as rmSync2,
|
|
62573
63097
|
statSync as statSync4,
|
|
@@ -62611,14 +63135,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
62611
63135
|
};
|
|
62612
63136
|
}, readJson = (p) => {
|
|
62613
63137
|
try {
|
|
62614
|
-
const parsed = JSON.parse(
|
|
63138
|
+
const parsed = JSON.parse(readFileSync13(p, "utf8"));
|
|
62615
63139
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
62616
63140
|
} catch {
|
|
62617
63141
|
return null;
|
|
62618
63142
|
}
|
|
62619
63143
|
}, parsesAsConfigObject = (p) => {
|
|
62620
63144
|
try {
|
|
62621
|
-
return isConfigObject(JSON.parse(
|
|
63145
|
+
return isConfigObject(JSON.parse(readFileSync13(p, "utf8")));
|
|
62622
63146
|
} catch {
|
|
62623
63147
|
return false;
|
|
62624
63148
|
}
|
|
@@ -62645,7 +63169,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
62645
63169
|
}
|
|
62646
63170
|
return false;
|
|
62647
63171
|
}, versionOf = (bin, env, timeout) => {
|
|
62648
|
-
const r =
|
|
63172
|
+
const r = spawnSync11(bin, ["--version"], { encoding: "utf8", env, timeout });
|
|
62649
63173
|
if (r.error)
|
|
62650
63174
|
return null;
|
|
62651
63175
|
return (r.stdout ?? "").trim();
|
|
@@ -62890,11 +63414,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
62890
63414
|
}, validNodeEntry = (entry, runtime, env) => {
|
|
62891
63415
|
try {
|
|
62892
63416
|
const stat = statSync4(entry);
|
|
62893
|
-
if (!stat.isFile() || stat.size === 0 || !
|
|
63417
|
+
if (!stat.isFile() || stat.size === 0 || !readFileSync13(entry, "utf8").startsWith(`#!/usr/bin/env node
|
|
62894
63418
|
`)) {
|
|
62895
63419
|
return false;
|
|
62896
63420
|
}
|
|
62897
|
-
return
|
|
63421
|
+
return spawnSync11(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
|
|
62898
63422
|
} catch {
|
|
62899
63423
|
return false;
|
|
62900
63424
|
}
|
|
@@ -63108,7 +63632,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63108
63632
|
if (!cmd)
|
|
63109
63633
|
return null;
|
|
63110
63634
|
try {
|
|
63111
|
-
const r =
|
|
63635
|
+
const r = spawnSync11(cmd, ["view", pkgName, "version"], {
|
|
63112
63636
|
encoding: "utf8",
|
|
63113
63637
|
timeout: 20000,
|
|
63114
63638
|
env: res.env
|
|
@@ -63419,12 +63943,27 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63419
63943
|
fix: `Choose a matching workspace with WORKFLOW_WORKSPACE_NAME or repair ${file}`
|
|
63420
63944
|
};
|
|
63421
63945
|
}
|
|
63422
|
-
if (match)
|
|
63423
|
-
|
|
63424
|
-
|
|
63425
|
-
|
|
63426
|
-
|
|
63427
|
-
|
|
63946
|
+
if (match) {
|
|
63947
|
+
const matched = `current directory matches workspace "${match.name}"`;
|
|
63948
|
+
const tracks = releaseTracksReport(res.cwd);
|
|
63949
|
+
const lines = describeReleaseTracks(tracks);
|
|
63950
|
+
const detail = [matched, ...lines].join("; ");
|
|
63951
|
+
if (tracks.error)
|
|
63952
|
+
return {
|
|
63953
|
+
id: "workspace_mismatch",
|
|
63954
|
+
status: "fail",
|
|
63955
|
+
detail,
|
|
63956
|
+
fix: `Repair releaseTracks in ${file} (or upgrade Workit for a critical field)`
|
|
63957
|
+
};
|
|
63958
|
+
if (tracks.warnings.length)
|
|
63959
|
+
return {
|
|
63960
|
+
id: "workspace_mismatch",
|
|
63961
|
+
status: "warn",
|
|
63962
|
+
detail,
|
|
63963
|
+
fix: `Fix the reported releaseTracks fields in ${file}, or pass --track <name> where the track is not determined`
|
|
63964
|
+
};
|
|
63965
|
+
return { id: "workspace_mismatch", status: "pass", detail };
|
|
63966
|
+
}
|
|
63428
63967
|
return {
|
|
63429
63968
|
id: "workspace_mismatch",
|
|
63430
63969
|
status: "fail",
|
|
@@ -63433,7 +63972,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63433
63972
|
};
|
|
63434
63973
|
}, isPlaceholder = (p) => {
|
|
63435
63974
|
try {
|
|
63436
|
-
return
|
|
63975
|
+
return readFileSync13(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
|
|
63437
63976
|
} catch {
|
|
63438
63977
|
return false;
|
|
63439
63978
|
}
|
|
@@ -63522,7 +64061,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63522
64061
|
}, defaultIdentityProbes = (env) => ({
|
|
63523
64062
|
origin: (cwd) => {
|
|
63524
64063
|
try {
|
|
63525
|
-
const out =
|
|
64064
|
+
const out = spawnSync11("git", ["remote", "get-url", "origin"], {
|
|
63526
64065
|
cwd,
|
|
63527
64066
|
encoding: "utf8",
|
|
63528
64067
|
env
|
|
@@ -63534,7 +64073,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63534
64073
|
},
|
|
63535
64074
|
ghLogin: (e) => {
|
|
63536
64075
|
try {
|
|
63537
|
-
const out =
|
|
64076
|
+
const out = spawnSync11("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
|
|
63538
64077
|
const login = (out.stdout ?? "").trim();
|
|
63539
64078
|
return out.status === 0 && login ? login : null;
|
|
63540
64079
|
} catch {
|
|
@@ -63543,7 +64082,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63543
64082
|
},
|
|
63544
64083
|
glabLogin: (e) => {
|
|
63545
64084
|
try {
|
|
63546
|
-
const out =
|
|
64085
|
+
const out = spawnSync11("glab", ["api", "user", "--jq", ".username"], {
|
|
63547
64086
|
encoding: "utf8",
|
|
63548
64087
|
env: e
|
|
63549
64088
|
});
|
|
@@ -63555,7 +64094,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63555
64094
|
},
|
|
63556
64095
|
sshLogin: (host) => {
|
|
63557
64096
|
try {
|
|
63558
|
-
const out =
|
|
64097
|
+
const out = spawnSync11("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
|
|
63559
64098
|
encoding: "utf8",
|
|
63560
64099
|
env
|
|
63561
64100
|
});
|
|
@@ -63749,6 +64288,7 @@ var init_doctor = __esm(() => {
|
|
|
63749
64288
|
init_store_lock();
|
|
63750
64289
|
init_runtime_identity();
|
|
63751
64290
|
init_boundary();
|
|
64291
|
+
init_release_tracks();
|
|
63752
64292
|
init_config();
|
|
63753
64293
|
init_package_root();
|
|
63754
64294
|
init_registration();
|
|
@@ -63797,7 +64337,7 @@ import {
|
|
|
63797
64337
|
lstatSync as lstatSync5,
|
|
63798
64338
|
mkdirSync as mkdirSync5,
|
|
63799
64339
|
mkdtempSync as mkdtempSync2,
|
|
63800
|
-
readFileSync as
|
|
64340
|
+
readFileSync as readFileSync14,
|
|
63801
64341
|
readdirSync as readdirSync6,
|
|
63802
64342
|
realpathSync as realpathSync7,
|
|
63803
64343
|
renameSync as renameSync3,
|
|
@@ -63966,7 +64506,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
63966
64506
|
if (values.applyProject) {
|
|
63967
64507
|
const root = path30.resolve(opts.cwd ?? process.cwd());
|
|
63968
64508
|
const gitignorePath = path30.join(root, ".gitignore");
|
|
63969
|
-
const existing = existsSync14(gitignorePath) ?
|
|
64509
|
+
const existing = existsSync14(gitignorePath) ? readFileSync14(gitignorePath, "utf8") : "";
|
|
63970
64510
|
const existingLines = new Set(existing.split(`
|
|
63971
64511
|
`).map((l) => l.trim()).filter(Boolean));
|
|
63972
64512
|
const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
|
|
@@ -63997,7 +64537,7 @@ function deepMerge(base, patch) {
|
|
|
63997
64537
|
const out = { ...base };
|
|
63998
64538
|
for (const [key, value] of Object.entries(patch)) {
|
|
63999
64539
|
const prev = out[key];
|
|
64000
|
-
out[key] =
|
|
64540
|
+
out[key] = isRecord5(prev) && isRecord5(value) ? deepMerge(prev, value) : value;
|
|
64001
64541
|
}
|
|
64002
64542
|
return out;
|
|
64003
64543
|
}
|
|
@@ -64324,8 +64864,8 @@ function applyCursorMcp(root, res) {
|
|
|
64324
64864
|
}
|
|
64325
64865
|
const mcpBase = mcpExisting.kind === "record" ? mcpExisting.value : {};
|
|
64326
64866
|
const server = cursorMcpServerEntry(res.cursorPluginDir);
|
|
64327
|
-
const servers =
|
|
64328
|
-
const current =
|
|
64867
|
+
const servers = isRecord5(mcpBase.mcpServers) ? mcpBase.mcpServers : {};
|
|
64868
|
+
const current = isRecord5(servers.workit) ? servers.workit : {};
|
|
64329
64869
|
const previousArgs = Array.isArray(current.args) ? current.args.map(String) : [];
|
|
64330
64870
|
const previousPackage = previousArgs.find((arg) => arg.startsWith("--package=@brainervirus/workit-cursor@") && arg !== `--package=${CURSOR_RUNTIME_PACKAGE}`);
|
|
64331
64871
|
if (previousPackage) {
|
|
@@ -64586,7 +65126,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64586
65126
|
}, configuredTokenPath = (config, ...keys) => {
|
|
64587
65127
|
let cursor = config;
|
|
64588
65128
|
for (const key of keys) {
|
|
64589
|
-
if (!
|
|
65129
|
+
if (!isRecord5(cursor))
|
|
64590
65130
|
return null;
|
|
64591
65131
|
cursor = cursor[key];
|
|
64592
65132
|
}
|
|
@@ -64599,8 +65139,8 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64599
65139
|
return configured ?? fallback;
|
|
64600
65140
|
}, readConfigRecord = (file) => {
|
|
64601
65141
|
try {
|
|
64602
|
-
const value = JSON.parse(
|
|
64603
|
-
return
|
|
65142
|
+
const value = JSON.parse(readFileSync14(file, "utf8"));
|
|
65143
|
+
return isRecord5(value) ? value : null;
|
|
64604
65144
|
} catch {
|
|
64605
65145
|
return null;
|
|
64606
65146
|
}
|
|
@@ -64617,10 +65157,10 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64617
65157
|
cursorMcp: options.cursorMcp ?? path30.join(home, ".cursor", "mcp.json"),
|
|
64618
65158
|
cursorPluginDir: options.cursorPluginDir ?? path30.join(home, ".cursor", "plugins", "local", "workit")
|
|
64619
65159
|
};
|
|
64620
|
-
},
|
|
65160
|
+
}, isRecord5 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
|
|
64621
65161
|
let raw;
|
|
64622
65162
|
try {
|
|
64623
|
-
raw =
|
|
65163
|
+
raw = readFileSync14(p, "utf8");
|
|
64624
65164
|
} catch {
|
|
64625
65165
|
if (existsSync14(p))
|
|
64626
65166
|
return { kind: "malformed", error: `${p} is not readable` };
|
|
@@ -64632,12 +65172,12 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64632
65172
|
} catch {
|
|
64633
65173
|
return { kind: "malformed", error: `${p} is not valid JSON` };
|
|
64634
65174
|
}
|
|
64635
|
-
if (
|
|
65175
|
+
if (isRecord5(value))
|
|
64636
65176
|
return { kind: "record", value, raw };
|
|
64637
65177
|
return { kind: "malformed", error: `${p} is not a JSON object` };
|
|
64638
65178
|
}, readFileSafe = (p) => {
|
|
64639
65179
|
try {
|
|
64640
|
-
return
|
|
65180
|
+
return readFileSync14(p, "utf8");
|
|
64641
65181
|
} catch {
|
|
64642
65182
|
return null;
|
|
64643
65183
|
}
|
|
@@ -64652,7 +65192,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64652
65192
|
}
|
|
64653
65193
|
}, isAdapter = (root, platform) => {
|
|
64654
65194
|
try {
|
|
64655
|
-
const pkg = JSON.parse(
|
|
65195
|
+
const pkg = JSON.parse(readFileSync14(path30.join(root, "package.json"), "utf8"));
|
|
64656
65196
|
return pkg.name === `@brainervirus/workit-${platform}`;
|
|
64657
65197
|
} catch {
|
|
64658
65198
|
return false;
|
|
@@ -64681,7 +65221,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64681
65221
|
if (entry.isDirectory()) {
|
|
64682
65222
|
if (!statSync5(installed).isDirectory() || !samePluginContent(source, installed, path30.join(relative, entry.name)))
|
|
64683
65223
|
return false;
|
|
64684
|
-
} else if (!
|
|
65224
|
+
} else if (!readFileSync14(source).equals(readFileSync14(installed))) {
|
|
64685
65225
|
return false;
|
|
64686
65226
|
}
|
|
64687
65227
|
}
|
|
@@ -64709,7 +65249,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64709
65249
|
continue;
|
|
64710
65250
|
if (existsSync14(path30.join(sourceRules, entry.name)))
|
|
64711
65251
|
continue;
|
|
64712
|
-
preserved.set(entry.name,
|
|
65252
|
+
preserved.set(entry.name, readFileSync14(path30.join(installedRules, entry.name)));
|
|
64713
65253
|
}
|
|
64714
65254
|
} catch {}
|
|
64715
65255
|
return preserved;
|
|
@@ -64763,10 +65303,10 @@ var init_setup = __esm(() => {
|
|
|
64763
65303
|
});
|
|
64764
65304
|
|
|
64765
65305
|
// packages/workit-core/src/core/branch-policy.ts
|
|
64766
|
-
import { spawnSync as
|
|
65306
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
64767
65307
|
var PREFIXES, detectBranchPolicy = (workspaceRoot) => {
|
|
64768
65308
|
const branchExists = (name) => {
|
|
64769
|
-
const r =
|
|
65309
|
+
const r = spawnSync12("git", ["branch", "--list", name], {
|
|
64770
65310
|
cwd: workspaceRoot,
|
|
64771
65311
|
encoding: "utf8"
|
|
64772
65312
|
});
|
|
@@ -64826,7 +65366,7 @@ var init_branch_policy = __esm(() => {
|
|
|
64826
65366
|
});
|
|
64827
65367
|
|
|
64828
65368
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
64829
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
65369
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
64830
65370
|
import path31 from "node:path";
|
|
64831
65371
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
|
|
64832
65372
|
function applyWorkspaceBranchPolicy(opts) {
|
|
@@ -64924,7 +65464,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
64924
65464
|
}
|
|
64925
65465
|
var readFileSafe2 = (p) => {
|
|
64926
65466
|
try {
|
|
64927
|
-
return
|
|
65467
|
+
return readFileSync15(p, "utf8");
|
|
64928
65468
|
} catch {
|
|
64929
65469
|
return null;
|
|
64930
65470
|
}
|
|
@@ -65103,17 +65643,18 @@ function setProfileEditorValue(profile, field, value, defaults = {}) {
|
|
|
65103
65643
|
};
|
|
65104
65644
|
}
|
|
65105
65645
|
function trackEditorValue(track, field) {
|
|
65646
|
+
const source = track.versionSource ?? { kind: "git-tag" };
|
|
65106
65647
|
if (field.startsWith("naming."))
|
|
65107
|
-
return track.naming[field.slice(7)];
|
|
65648
|
+
return track.naming?.[field.slice(7)] ?? "";
|
|
65108
65649
|
if (field === "mergeBackBranches" || field === "requiredChecks")
|
|
65109
|
-
return track[field].join(", ");
|
|
65650
|
+
return (track[field] ?? []).join(", ");
|
|
65110
65651
|
if (field.startsWith("versionSource.")) {
|
|
65111
65652
|
const key = field.slice(14);
|
|
65112
65653
|
if (key === "kind")
|
|
65113
|
-
return
|
|
65654
|
+
return source.kind;
|
|
65114
65655
|
if (key === "path")
|
|
65115
|
-
return
|
|
65116
|
-
return
|
|
65656
|
+
return source.kind === "package-json" ? source.path : "";
|
|
65657
|
+
return source.kind === "package-json" ? source.field : "";
|
|
65117
65658
|
}
|
|
65118
65659
|
return String(track[field] ?? "");
|
|
65119
65660
|
}
|
|
@@ -65123,12 +65664,13 @@ function setTrackEditorValue(track, field, value) {
|
|
|
65123
65664
|
if (field === "mergeBackBranches" || field === "requiredChecks")
|
|
65124
65665
|
return { ...track, [field]: splitList(value) };
|
|
65125
65666
|
if (field.startsWith("versionSource.")) {
|
|
65667
|
+
const current = track.versionSource ?? { kind: "git-tag" };
|
|
65126
65668
|
const key = field.slice(14);
|
|
65127
|
-
const kind = key === "kind" ? value :
|
|
65669
|
+
const kind = key === "kind" ? value : current.kind;
|
|
65128
65670
|
const versionSource = kind === "package-json" ? {
|
|
65129
65671
|
kind,
|
|
65130
|
-
path: key === "path" ? value :
|
|
65131
|
-
field: key === "field" ? value :
|
|
65672
|
+
path: key === "path" ? value : current.kind === kind ? current.path : "package.json",
|
|
65673
|
+
field: key === "field" ? value : current.kind === kind ? current.field : "version"
|
|
65132
65674
|
} : kind === "manual" ? { kind } : { kind: "git-tag" };
|
|
65133
65675
|
return { ...track, versionSource };
|
|
65134
65676
|
}
|
|
@@ -65762,13 +66304,13 @@ var init_wizard_state = __esm(() => {
|
|
|
65762
66304
|
});
|
|
65763
66305
|
|
|
65764
66306
|
// packages/workit-cli/src/admin/uninstall.ts
|
|
65765
|
-
import { existsSync as existsSync16, readFileSync as
|
|
66307
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16, realpathSync as realpathSync8, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "node:fs";
|
|
65766
66308
|
import os9 from "node:os";
|
|
65767
66309
|
import path33 from "node:path";
|
|
65768
66310
|
function cleanCursorSettings(settings, pluginDir) {
|
|
65769
66311
|
const next = { ...settings };
|
|
65770
66312
|
let changed = false;
|
|
65771
|
-
if (
|
|
66313
|
+
if (isRecord6(next.enabled_plugins)) {
|
|
65772
66314
|
const enabled = { ...next.enabled_plugins };
|
|
65773
66315
|
for (const identity of ["workit", ...CURSOR_LEGACY_IDENTITIES]) {
|
|
65774
66316
|
if (identity in enabled) {
|
|
@@ -65809,7 +66351,7 @@ function cleanOpenCodeConfig(config) {
|
|
|
65809
66351
|
function cleanCursorMcp(mcp) {
|
|
65810
66352
|
const next = { ...mcp };
|
|
65811
66353
|
let changed = false;
|
|
65812
|
-
if (
|
|
66354
|
+
if (isRecord6(next.mcpServers)) {
|
|
65813
66355
|
const servers = { ...next.mcpServers };
|
|
65814
66356
|
for (const name of ["workit", "workflow-toolkit"]) {
|
|
65815
66357
|
if (name in servers) {
|
|
@@ -65834,7 +66376,7 @@ function cleanPiConfig(config) {
|
|
|
65834
66376
|
changed = true;
|
|
65835
66377
|
}
|
|
65836
66378
|
}
|
|
65837
|
-
const pi =
|
|
66379
|
+
const pi = isRecord6(next.pi) ? { ...next.pi } : null;
|
|
65838
66380
|
if (pi && Array.isArray(pi.extensions)) {
|
|
65839
66381
|
const kept = pi.extensions.filter((entry) => !String(entry).includes("workit"));
|
|
65840
66382
|
if (kept.length !== pi.extensions.length) {
|
|
@@ -65982,10 +66524,10 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
65982
66524
|
codexPluginDir: path33.join(home, ".codex", "plugins", "workit"),
|
|
65983
66525
|
piConfig: path33.join(home, ".pi", "config.json")
|
|
65984
66526
|
};
|
|
65985
|
-
},
|
|
66527
|
+
}, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
|
|
65986
66528
|
let raw;
|
|
65987
66529
|
try {
|
|
65988
|
-
raw =
|
|
66530
|
+
raw = readFileSync16(file, "utf8");
|
|
65989
66531
|
} catch {
|
|
65990
66532
|
if (existsSync16(file))
|
|
65991
66533
|
return { kind: "malformed", error: `${file} is not readable` };
|
|
@@ -65993,7 +66535,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
65993
66535
|
}
|
|
65994
66536
|
try {
|
|
65995
66537
|
const value = JSON.parse(raw);
|
|
65996
|
-
return
|
|
66538
|
+
return isRecord6(value) ? { kind: "record", value } : { kind: "malformed", error: `${file} is not a JSON object` };
|
|
65997
66539
|
} catch {
|
|
65998
66540
|
return { kind: "malformed", error: `${file} is not valid JSON` };
|
|
65999
66541
|
}
|
|
@@ -66035,7 +66577,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
66035
66577
|
`;
|
|
66036
66578
|
let current;
|
|
66037
66579
|
try {
|
|
66038
|
-
current =
|
|
66580
|
+
current = readFileSync16(target, "utf8");
|
|
66039
66581
|
} catch (error) {
|
|
66040
66582
|
return {
|
|
66041
66583
|
status: "failed",
|
|
@@ -68305,7 +68847,7 @@ var init_steps = __esm(async () => {
|
|
|
68305
68847
|
import { appendFileSync, mkdirSync as mkdirSync7, readdirSync as readdirSync7, unlinkSync as unlinkSync3 } from "node:fs";
|
|
68306
68848
|
import os11 from "node:os";
|
|
68307
68849
|
import path34 from "node:path";
|
|
68308
|
-
var REDACTED = "[REDACTED]", DEFAULT_MAX_RATE = 20, DEFAULT_RATE_WINDOW_MS = 1000, DEFAULT_MAX_FIELD_LENGTH = 200, DEFAULT_MAX_STACK_LINES = 30, DAY_FILE, RETAINED_DAYS = 7, SECRET_VALUE, KEY_EQ_VALUE, URL_QUERY, splitKey = (key) => key.split(/[_-]+|(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/).map((word) => word.toLowerCase()), SENSITIVE_WORDS, STACK_WORDS,
|
|
68850
|
+
var REDACTED = "[REDACTED]", DEFAULT_MAX_RATE = 20, DEFAULT_RATE_WINDOW_MS = 1000, DEFAULT_MAX_FIELD_LENGTH = 200, DEFAULT_MAX_STACK_LINES = 30, DAY_FILE, RETAINED_DAYS = 7, SECRET_VALUE, KEY_EQ_VALUE, URL_QUERY, splitKey = (key) => key.split(/[_-]+|(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/).map((word) => word.toLowerCase()), SENSITIVE_WORDS, STACK_WORDS, escapeRegExp3 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), resolveStateDir = () => {
|
|
68309
68851
|
const override = process.env.WORKFLOW_TOOLKIT_STATE;
|
|
68310
68852
|
if (override)
|
|
68311
68853
|
return override;
|
|
@@ -68507,7 +69049,7 @@ var init_logger = __esm(() => {
|
|
|
68507
69049
|
"query"
|
|
68508
69050
|
]);
|
|
68509
69051
|
STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
68510
|
-
homePattern = new RegExp(`${
|
|
69052
|
+
homePattern = new RegExp(`${escapeRegExp3(os11.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
68511
69053
|
DEFAULT_OPTIONS = {
|
|
68512
69054
|
maxFieldLength: DEFAULT_MAX_FIELD_LENGTH,
|
|
68513
69055
|
maxStackLines: DEFAULT_MAX_STACK_LINES
|
|
@@ -68772,12 +69314,12 @@ var init_init = __esm(() => {
|
|
|
68772
69314
|
});
|
|
68773
69315
|
|
|
68774
69316
|
// packages/workit-cli/src/upgrade.ts
|
|
68775
|
-
import { spawnSync as
|
|
69317
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
68776
69318
|
import {
|
|
68777
69319
|
existsSync as existsSync17,
|
|
68778
69320
|
mkdtempSync as mkdtempSync3,
|
|
68779
69321
|
rmSync as rmSync6,
|
|
68780
|
-
readFileSync as
|
|
69322
|
+
readFileSync as readFileSync17,
|
|
68781
69323
|
mkdirSync as mkdirSync8,
|
|
68782
69324
|
copyFileSync as copyFileSync5,
|
|
68783
69325
|
chmodSync,
|
|
@@ -68786,7 +69328,7 @@ import {
|
|
|
68786
69328
|
} from "node:fs";
|
|
68787
69329
|
import path35 from "node:path";
|
|
68788
69330
|
import os12 from "node:os";
|
|
68789
|
-
import { createHash as
|
|
69331
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
68790
69332
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
68791
69333
|
const paths = upgradePaths(deps);
|
|
68792
69334
|
const { home, configDir } = paths;
|
|
@@ -68914,7 +69456,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
68914
69456
|
mkdirSync8(backup, { recursive: true, mode: 448 });
|
|
68915
69457
|
for (const file of Object.keys(plan.configDigests))
|
|
68916
69458
|
if (existsSync17(file)) {
|
|
68917
|
-
const target = path35.join(backup,
|
|
69459
|
+
const target = path35.join(backup, createHash13("sha256").update(file).digest("hex").slice(0, 12) + "-" + path35.basename(file));
|
|
68918
69460
|
copyFileSync5(file, target);
|
|
68919
69461
|
chmodSync(target, 384);
|
|
68920
69462
|
}
|
|
@@ -69128,7 +69670,7 @@ async function runLaunchCommand(argv, deps = {}) {
|
|
|
69128
69670
|
}
|
|
69129
69671
|
if (deps.run)
|
|
69130
69672
|
return deps.run(host, hostArgs).status ?? 1;
|
|
69131
|
-
return
|
|
69673
|
+
return spawnSync13(launch.command, launch.args, {
|
|
69132
69674
|
stdio: "inherit",
|
|
69133
69675
|
env
|
|
69134
69676
|
}).status ?? 1;
|
|
@@ -69162,14 +69704,14 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
69162
69704
|
return null;
|
|
69163
69705
|
let data;
|
|
69164
69706
|
try {
|
|
69165
|
-
data = JSON.parse(
|
|
69707
|
+
data = JSON.parse(readFileSync17(file, "utf8"));
|
|
69166
69708
|
} catch {
|
|
69167
69709
|
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
69168
69710
|
}
|
|
69169
69711
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
69170
69712
|
throw new Error(`${file} is not a configuration object`);
|
|
69171
69713
|
return data;
|
|
69172
|
-
}, digest2 = (file) => existsSync17(file) ?
|
|
69714
|
+
}, digest2 = (file) => existsSync17(file) ? createHash13("sha256").update(readFileSync17(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
69173
69715
|
const { home, env } = upgradePaths(deps);
|
|
69174
69716
|
let step;
|
|
69175
69717
|
try {
|
|
@@ -69309,12 +69851,49 @@ var init_launch = __esm(() => {
|
|
|
69309
69851
|
init_upgrade();
|
|
69310
69852
|
});
|
|
69311
69853
|
|
|
69854
|
+
// packages/workit-cli/src/prompt.ts
|
|
69855
|
+
import { createInterface } from "node:readline/promises";
|
|
69856
|
+
async function askLine(question, output = process.stdout) {
|
|
69857
|
+
const prompt = createInterface({ input: process.stdin, output });
|
|
69858
|
+
try {
|
|
69859
|
+
return await prompt.question(question);
|
|
69860
|
+
} finally {
|
|
69861
|
+
prompt.close();
|
|
69862
|
+
}
|
|
69863
|
+
}
|
|
69864
|
+
async function askOrCancel(io, ask) {
|
|
69865
|
+
try {
|
|
69866
|
+
return await ask();
|
|
69867
|
+
} catch (error) {
|
|
69868
|
+
if (!isPromptAbort(error))
|
|
69869
|
+
throw error;
|
|
69870
|
+
io.stderr(`
|
|
69871
|
+
Cancelled.
|
|
69872
|
+
`);
|
|
69873
|
+
return null;
|
|
69874
|
+
}
|
|
69875
|
+
}
|
|
69876
|
+
function cancelled(io) {
|
|
69877
|
+
if (io.json) {
|
|
69878
|
+
const envelope = {
|
|
69879
|
+
ok: false,
|
|
69880
|
+
code: "failed",
|
|
69881
|
+
data: { reason: "cancelled" },
|
|
69882
|
+
error: "cancelled"
|
|
69883
|
+
};
|
|
69884
|
+
io.stdout(`${JSON.stringify(envelope)}
|
|
69885
|
+
`);
|
|
69886
|
+
}
|
|
69887
|
+
return CANCELLED_EXIT;
|
|
69888
|
+
}
|
|
69889
|
+
var CANCELLED_EXIT = 130, isPromptAbort = (error) => typeof error === "object" && error !== null && (error.name === "AbortError" || error.code === "ABORT_ERR");
|
|
69890
|
+
var init_prompt = () => {};
|
|
69891
|
+
|
|
69312
69892
|
// packages/workit-cli/src/verbs/doctor.ts
|
|
69313
69893
|
var exports_doctor = {};
|
|
69314
69894
|
__export(exports_doctor, {
|
|
69315
69895
|
run: () => run5
|
|
69316
69896
|
});
|
|
69317
|
-
import { createInterface } from "node:readline/promises";
|
|
69318
69897
|
async function confirmForcedLockClear(root, args, io) {
|
|
69319
69898
|
const lock = inspectMetadataLock(root);
|
|
69320
69899
|
if (!lock.present)
|
|
@@ -69331,23 +69910,20 @@ async function confirmForcedLockClear(root, args, io) {
|
|
|
69331
69910
|
`);
|
|
69332
69911
|
return false;
|
|
69333
69912
|
}
|
|
69334
|
-
const
|
|
69335
|
-
|
|
69336
|
-
|
|
69337
|
-
|
|
69338
|
-
try {
|
|
69339
|
-
const answer = await rl.question("Remove this lock even if its holder may be alive? [y/N] ");
|
|
69340
|
-
return /^y(es)?$/i.test(answer.trim());
|
|
69341
|
-
} finally {
|
|
69342
|
-
rl.close();
|
|
69343
|
-
}
|
|
69913
|
+
const answer = await askOrCancel(io, () => askLine("Remove this lock even if its holder may be alive? [y/N] ", io.json ? process.stderr : process.stdout));
|
|
69914
|
+
if (answer === null)
|
|
69915
|
+
return "cancelled";
|
|
69916
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
69344
69917
|
}
|
|
69345
69918
|
async function run5(argv, io) {
|
|
69346
69919
|
const root = workspaceRootFor();
|
|
69347
69920
|
const force = argv.includes("--force");
|
|
69348
69921
|
let fixLock = null;
|
|
69349
69922
|
if (argv.includes("--fix-lock")) {
|
|
69350
|
-
|
|
69923
|
+
const confirmed = force ? await confirmForcedLockClear(root, argv, io) : true;
|
|
69924
|
+
if (confirmed === "cancelled")
|
|
69925
|
+
return cancelled(io);
|
|
69926
|
+
if (!confirmed) {
|
|
69351
69927
|
if (!io.json)
|
|
69352
69928
|
return 3;
|
|
69353
69929
|
return emit(io, fail("blocked", "fix-lock --force: refusing without --yes outside an interactive terminal", {
|
|
@@ -69386,6 +69962,7 @@ var init_doctor2 = __esm(() => {
|
|
|
69386
69962
|
init_doctor();
|
|
69387
69963
|
init_store_lock();
|
|
69388
69964
|
init_output();
|
|
69965
|
+
init_prompt();
|
|
69389
69966
|
init_task();
|
|
69390
69967
|
});
|
|
69391
69968
|
|
|
@@ -69493,8 +70070,8 @@ var init_redact = __esm(() => {
|
|
|
69493
70070
|
});
|
|
69494
70071
|
|
|
69495
70072
|
// packages/workit-core/src/checks.ts
|
|
69496
|
-
import { spawn, spawnSync as
|
|
69497
|
-
import { createHash as
|
|
70073
|
+
import { spawn, spawnSync as spawnSync14 } from "node:child_process";
|
|
70074
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
69498
70075
|
import fs17 from "node:fs";
|
|
69499
70076
|
import os13 from "node:os";
|
|
69500
70077
|
import path36 from "node:path";
|
|
@@ -69672,7 +70249,7 @@ function runCheckCommand(argv, options) {
|
|
|
69672
70249
|
if (!child?.pid)
|
|
69673
70250
|
return;
|
|
69674
70251
|
if (windows)
|
|
69675
|
-
|
|
70252
|
+
spawnSync14("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
69676
70253
|
stdio: "ignore",
|
|
69677
70254
|
windowsHide: true
|
|
69678
70255
|
});
|
|
@@ -69828,7 +70405,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
69828
70405
|
}
|
|
69829
70406
|
return report;
|
|
69830
70407
|
}
|
|
69831
|
-
var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${
|
|
70408
|
+
var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${createHash14("sha256").update(log).digest("hex")}`, LOG_RETENTION;
|
|
69832
70409
|
var init_checks3 = __esm(() => {
|
|
69833
70410
|
init_redact();
|
|
69834
70411
|
MAX_LOG_BYTES = 2 * 1024 * 1024;
|
|
@@ -69917,7 +70494,6 @@ __export(exports_grant, {
|
|
|
69917
70494
|
run: () => run8,
|
|
69918
70495
|
runGrant: () => runGrant
|
|
69919
70496
|
});
|
|
69920
|
-
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
69921
70497
|
function show(argv, io) {
|
|
69922
70498
|
const all = argv.includes("--all");
|
|
69923
70499
|
const named = argv.filter((arg) => !arg.startsWith("--"));
|
|
@@ -69941,10 +70517,13 @@ function show(argv, io) {
|
|
|
69941
70517
|
} catch (error) {
|
|
69942
70518
|
return emit(io, fail("invalid_input", error instanceof Error ? error.message : String(error)));
|
|
69943
70519
|
}
|
|
69944
|
-
|
|
70520
|
+
const tracks = releaseTracksReport(io.cwd);
|
|
70521
|
+
const shown = tracks.tracks.length || tracks.error ? { ...autonomy, releaseTracks: tracks } : autonomy;
|
|
70522
|
+
return emit(io, ok(shown), (data) => [
|
|
69945
70523
|
...data.note ? [`note: ${data.note}`] : [],
|
|
69946
70524
|
data.workspace ? `workspace ${data.workspace} (${data.source === "default" ? "D4 defaults" : `from ${data.source}`})` : "no workspace matches this checkout: D4 defaults apply",
|
|
69947
70525
|
...describe2(data.grants, data.configured, data.defaultEndpoint, data.verification),
|
|
70526
|
+
...describeReleaseTracks(tracks).map((line) => ` ${line}`),
|
|
69948
70527
|
"raising a grant needs the user: workit grant set <workspace> <kind>=<value>"
|
|
69949
70528
|
]);
|
|
69950
70529
|
}
|
|
@@ -70002,7 +70581,9 @@ async function change(verb, argv, io, deps) {
|
|
|
70002
70581
|
const agent = agentMarker(io.env);
|
|
70003
70582
|
if (!deps.interactive() || agent)
|
|
70004
70583
|
return emit(io, fail("blocked", `grant_raise_refused: raising ${raised.map(({ kind }) => kind).join(", ")} needs the user at an interactive terminal${agent ? ` (this shell belongs to an agent: ${agent} is set)` : ""}; grants are never raised headless`, { unblock: `ask the user to run, in their own terminal: ${command}` }));
|
|
70005
|
-
const answer = await deps.ask(`Raise ${raised.map(({ kind, value }) => `${kind}=${value}`).join(", ")} for workspace "${workspace}"? An agent there may then do this without asking. Type the workspace name to confirm: `);
|
|
70584
|
+
const answer = await askOrCancel(io, () => deps.ask(`Raise ${raised.map(({ kind, value }) => `${kind}=${value}`).join(", ")} for workspace "${workspace}"? An agent there may then do this without asking. Type the workspace name to confirm: `));
|
|
70585
|
+
if (answer === null)
|
|
70586
|
+
return cancelled(io);
|
|
70006
70587
|
if (answer.trim() !== workspace)
|
|
70007
70588
|
return emit(io, fail("blocked", "grant change not confirmed; nothing was written"));
|
|
70008
70589
|
}
|
|
@@ -70037,7 +70618,9 @@ var USAGE2 = "workit grant show [<workspace>] [--all] | grant set <workspace> <k
|
|
|
70037
70618
|
usage: ${USAGE2}`)), run8 = (argv, io) => runGrant(argv, io);
|
|
70038
70619
|
var init_grant = __esm(() => {
|
|
70039
70620
|
init_autonomy();
|
|
70621
|
+
init_release_tracks();
|
|
70040
70622
|
init_output();
|
|
70623
|
+
init_prompt();
|
|
70041
70624
|
AGENT_ENV = [
|
|
70042
70625
|
"CLAUDECODE",
|
|
70043
70626
|
"OPENCODE",
|
|
@@ -70048,14 +70631,7 @@ var init_grant = __esm(() => {
|
|
|
70048
70631
|
];
|
|
70049
70632
|
defaultDeps = {
|
|
70050
70633
|
interactive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
|
|
70051
|
-
ask:
|
|
70052
|
-
const prompt = createInterface2({ input: process.stdin, output: process.stdout });
|
|
70053
|
-
try {
|
|
70054
|
-
return await prompt.question(question);
|
|
70055
|
-
} finally {
|
|
70056
|
-
prompt.close();
|
|
70057
|
-
}
|
|
70058
|
-
}
|
|
70634
|
+
ask: (question) => askLine(question)
|
|
70059
70635
|
};
|
|
70060
70636
|
});
|
|
70061
70637
|
|
|
@@ -70392,9 +70968,9 @@ var init_check = __esm(() => {
|
|
|
70392
70968
|
var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
70393
70969
|
|
|
70394
70970
|
// packages/workit-core/src/git/ops.ts
|
|
70395
|
-
import { spawnSync as
|
|
70971
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
70396
70972
|
function dirtEntries(cwd) {
|
|
70397
|
-
const run =
|
|
70973
|
+
const run = git5(cwd, ["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
|
|
70398
70974
|
if (!run.ok)
|
|
70399
70975
|
return [];
|
|
70400
70976
|
const parts = run.stdout.split("\x00");
|
|
@@ -70410,9 +70986,19 @@ function dirtEntries(cwd) {
|
|
|
70410
70986
|
return out;
|
|
70411
70987
|
}
|
|
70412
70988
|
function gitBranch(cwd, input) {
|
|
70413
|
-
const name = input.name.trim();
|
|
70414
70989
|
if (!headSha(cwd) && currentBranch(cwd) === null)
|
|
70415
70990
|
return failure3("invalid_input", "not inside a git repository with a commit");
|
|
70991
|
+
const explicitBase = input.base?.trim() || null;
|
|
70992
|
+
const resolved = vcsConfig("resolve", cwd, {
|
|
70993
|
+
track: input.track ?? null,
|
|
70994
|
+
...explicitBase ? { branch: explicitBase } : {}
|
|
70995
|
+
});
|
|
70996
|
+
const releaseTrack = resolved.ok === false ? null : resolved.releaseTrack ?? null;
|
|
70997
|
+
if (releaseTrack?.blocking && (!explicitBase || input.name === undefined))
|
|
70998
|
+
return failure3("blocked", String(releaseTrack.blocking), "workit git branch … --track <name> # or --base <branch>");
|
|
70999
|
+
const name = (input.name ?? (input.kind && input.slug ? trackBranchName(releaseTrack?.track ?? null, input.kind, input.slug) ?? `${input.kind}/${input.slug}` : "")).trim();
|
|
71000
|
+
if (!name)
|
|
71001
|
+
return failure3("invalid_input", "missing branch name");
|
|
70416
71002
|
if (!validRefName(cwd, name))
|
|
70417
71003
|
return failure3("invalid_input", `invalid branch name ${JSON.stringify(name)}`);
|
|
70418
71004
|
const policy = validateBranchNameFor(cwd, name);
|
|
@@ -70420,23 +71006,25 @@ function gitBranch(cwd, input) {
|
|
|
70420
71006
|
return failure3("blocked", policy.error, policy.correction);
|
|
70421
71007
|
if (resolveRef(cwd, `refs/heads/${name}`))
|
|
70422
71008
|
return failure3("failed", `branch_exists: ${name} already exists`, `git switch ${name}`);
|
|
70423
|
-
let base =
|
|
71009
|
+
let base = explicitBase;
|
|
70424
71010
|
let defaultTarget = null;
|
|
70425
|
-
|
|
70426
|
-
if (resolved.ok === false && !base)
|
|
71011
|
+
let defaultBase = null;
|
|
71012
|
+
if (resolved.ok === false && (!base || input.track))
|
|
70427
71013
|
return failure3("blocked", String(resolved.error), "fix ~/.config/workit/vcs.json or pass --base <branch>");
|
|
70428
|
-
if (resolved.ok !== false)
|
|
71014
|
+
if (resolved.ok !== false) {
|
|
70429
71015
|
defaultTarget = String(resolved.defaultTargetBranch ?? "") || null;
|
|
70430
|
-
|
|
71016
|
+
defaultBase = String(resolved.baseBranch ?? "") || defaultTarget;
|
|
71017
|
+
}
|
|
71018
|
+
base ??= defaultBase;
|
|
70431
71019
|
if (!base)
|
|
70432
71020
|
return failure3("invalid_input", "no default target branch is configured; pass --base <branch>");
|
|
70433
71021
|
if (base.startsWith("-"))
|
|
70434
71022
|
return failure3("invalid_input", "--base must not start with -");
|
|
70435
|
-
const notes = [];
|
|
71023
|
+
const notes = [...releaseTrack?.warnings ?? []];
|
|
70436
71024
|
const remotes = remoteNames(cwd);
|
|
70437
71025
|
const remote = remotes.includes("origin") ? "origin" : pushRemoteName(cwd);
|
|
70438
71026
|
const localTip = resolveRef(cwd, `refs/heads/${base}`);
|
|
70439
|
-
const stackParent = localTip !== null && base !== defaultTarget && !isProtectedTarget(cwd, base);
|
|
71027
|
+
const stackParent = localTip !== null && base !== defaultTarget && base !== defaultBase && !isProtectedTarget(cwd, base);
|
|
70440
71028
|
let baseRef = null;
|
|
70441
71029
|
if (stackParent)
|
|
70442
71030
|
baseRef = `refs/heads/${base}`;
|
|
@@ -70454,18 +71042,19 @@ function gitBranch(cwd, input) {
|
|
|
70454
71042
|
}
|
|
70455
71043
|
} else if (localTip)
|
|
70456
71044
|
baseRef = `refs/heads/${base}`;
|
|
70457
|
-
if (!baseRef &&
|
|
71045
|
+
if (!baseRef && git5(cwd, ["rev-parse", "--verify", "-q", `${base}^{commit}`]).ok)
|
|
70458
71046
|
baseRef = base;
|
|
70459
|
-
const baseSha = baseRef ?
|
|
71047
|
+
const baseSha = baseRef ? git5(cwd, ["rev-parse", "--verify", "-q", `${baseRef}^{commit}`]).stdout.trim() : "";
|
|
70460
71048
|
if (!baseRef || !baseSha)
|
|
70461
71049
|
return failure3("not_found", `base ${base} does not resolve (no ${remote ?? "remote"}/${base}, no local ${base})`, `git fetch ${remote ?? "origin"} ${base} # or pass --base <ref>`);
|
|
70462
71050
|
const dirt = classifyBranchDirt(cwd);
|
|
70463
71051
|
if (dirt === "stash-required" && !input.carry)
|
|
70464
71052
|
return failure3("blocked", "dirty_worktree: tracked changes outside docs/ would ride along to the new branch", `commit them first (workit git commit -m … -- <paths>), or pass --carry to bring them along`);
|
|
70465
71053
|
const previous = currentBranch(cwd);
|
|
70466
|
-
const switched =
|
|
71054
|
+
const switched = git5(cwd, ["switch", "--no-track", "-c", name, baseSha]);
|
|
70467
71055
|
if (!switched.ok)
|
|
70468
71056
|
return failure3("failed", `git switch -c ${name} failed: ${gitError(switched)}`);
|
|
71057
|
+
recordBranchBase(cwd, name, base);
|
|
70469
71058
|
return success2({
|
|
70470
71059
|
branch: name,
|
|
70471
71060
|
previous,
|
|
@@ -70473,7 +71062,8 @@ function gitBranch(cwd, input) {
|
|
|
70473
71062
|
baseRef,
|
|
70474
71063
|
baseSha,
|
|
70475
71064
|
carried: dirt !== "clean",
|
|
70476
|
-
notes
|
|
71065
|
+
notes,
|
|
71066
|
+
releaseTrack
|
|
70477
71067
|
});
|
|
70478
71068
|
}
|
|
70479
71069
|
function lintCommitMessage(cwd, message) {
|
|
@@ -70488,7 +71078,7 @@ function lintCommitMessage(cwd, message) {
|
|
|
70488
71078
|
}
|
|
70489
71079
|
if (preset !== "auto")
|
|
70490
71080
|
return { ok: true };
|
|
70491
|
-
const log =
|
|
71081
|
+
const log = git5(cwd, ["log", "-n", "50", "--no-merges", "--format=%s"]);
|
|
70492
71082
|
const subjects = log.ok ? log.stdout.split(`
|
|
70493
71083
|
`).filter(Boolean) : [];
|
|
70494
71084
|
const detected = detectCommitFlavor(subjects).flavor;
|
|
@@ -70526,28 +71116,28 @@ function gitCommit(cwd, input) {
|
|
|
70526
71116
|
if (paths.length) {
|
|
70527
71117
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
70528
71118
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
70529
|
-
const added =
|
|
71119
|
+
const added = git5(cwd, ["add", "-A", "--", ...paths]);
|
|
70530
71120
|
if (!added.ok)
|
|
70531
71121
|
return failure3("failed", `git add failed: ${gitError(added)}`);
|
|
70532
71122
|
args.push("--", ...paths);
|
|
70533
71123
|
} else if (input.all) {
|
|
70534
|
-
const added =
|
|
71124
|
+
const added = git5(cwd, ["add", "-A"]);
|
|
70535
71125
|
if (!added.ok)
|
|
70536
71126
|
return failure3("failed", `git add failed: ${gitError(added)}`);
|
|
70537
71127
|
} else {
|
|
70538
|
-
const staged =
|
|
71128
|
+
const staged = git5(cwd, ["diff", "--cached", "--name-only", "-z"]);
|
|
70539
71129
|
if (staged.ok && !staged.stdout.replaceAll("\x00", "")) {
|
|
70540
71130
|
const dirt = dirtEntries(cwd);
|
|
70541
71131
|
return failure3(dirt.length ? "blocked" : "failed", dirt.length ? `nothing_staged: nothing is staged and workit never commits unrelated changes implicitly (${dirt.length} changed: ${dirt.slice(0, 5).map((entry) => entry.slice(3)).join(", ")}${dirt.length > 5 ? ", …" : ""})` : "nothing_to_commit: the working tree is clean", dirt.length ? `workit git commit -m '<msg>' -- <paths> # or --all to commit every change` : undefined);
|
|
70542
71132
|
}
|
|
70543
71133
|
}
|
|
70544
|
-
const committed =
|
|
71134
|
+
const committed = git5(cwd, args, { timeoutMs: COMMIT_TIMEOUT_MS, env: input.env });
|
|
70545
71135
|
if (!committed.ok)
|
|
70546
71136
|
return failure3("failed", `git commit failed: ${gitError(committed, 6)}`);
|
|
70547
71137
|
const sha = headSha(cwd);
|
|
70548
71138
|
if (!sha)
|
|
70549
71139
|
return failure3("failed", "the commit did not resolve");
|
|
70550
|
-
const files = nulList(
|
|
71140
|
+
const files = nulList(git5(cwd, ["diff-tree", "--root", "--no-commit-id", "--name-only", "-r", "-z", sha]).stdout);
|
|
70551
71141
|
const leftDirty = dirtEntries(cwd).length;
|
|
70552
71142
|
const listed = [];
|
|
70553
71143
|
let size = 0;
|
|
@@ -70619,9 +71209,9 @@ function recordedRemoteTip(cwd, plan) {
|
|
|
70619
71209
|
return;
|
|
70620
71210
|
}
|
|
70621
71211
|
function includesRemoteTip(cwd, branch, tip) {
|
|
70622
|
-
if (
|
|
71212
|
+
if (git5(cwd, ["merge-base", "--is-ancestor", tip, `refs/heads/${branch}`]).ok)
|
|
70623
71213
|
return true;
|
|
70624
|
-
const reflog =
|
|
71214
|
+
const reflog = git5(cwd, ["reflog", "show", "--format=%H", `refs/heads/${branch}`, "--"]);
|
|
70625
71215
|
return reflog.ok && reflog.stdout.split(`
|
|
70626
71216
|
`).some((line) => line.trim() === tip);
|
|
70627
71217
|
}
|
|
@@ -70671,7 +71261,7 @@ ${run.stdout}`;
|
|
|
70671
71261
|
return failure3("failed", `push_unverified: ${plan.remote}/${plan.branch} is at ${after.sha?.slice(0, 12) ?? "(absent)"}, not the pushed ${plan.sha.slice(0, 12)}`, "workit verify-delivery push");
|
|
70672
71262
|
let upstream = false;
|
|
70673
71263
|
if (input.setUpstream) {
|
|
70674
|
-
upstream =
|
|
71264
|
+
upstream = git5(cwd, ["config", `branch.${plan.branch}.remote`, plan.remote]).ok && git5(cwd, ["config", `branch.${plan.branch}.merge`, `refs/heads/${plan.branch}`]).ok;
|
|
70675
71265
|
}
|
|
70676
71266
|
const row = appendObserved(cwd, {
|
|
70677
71267
|
type: pushed ? "push.verified" : "push.noop",
|
|
@@ -70721,8 +71311,8 @@ function deleteRemoteBranch(cwd, target, branch, expectedTip, options = {}) {
|
|
|
70721
71311
|
${run.stdout}`;
|
|
70722
71312
|
return /stale info|cannot lock ref|fetch first|non-fast-forward/iu.test(text) ? { ok: false, lease: true, error: "the remote branch tip changed before deletion" } : { ok: false, lease: false, error: gitError(run) };
|
|
70723
71313
|
}
|
|
70724
|
-
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000,
|
|
70725
|
-
const result =
|
|
71314
|
+
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
|
|
71315
|
+
const result = spawnSync15("git", args, {
|
|
70726
71316
|
cwd,
|
|
70727
71317
|
encoding: "utf8",
|
|
70728
71318
|
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
@@ -70742,11 +71332,12 @@ var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git4 = (cwd, args, options = {}
|
|
|
70742
71332
|
const lines = redactText(`${run.stderr}
|
|
70743
71333
|
${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trim()).filter((value) => value && !value.startsWith("hint:"));
|
|
70744
71334
|
return lines.slice(-max).join(" / ").slice(0, 400) || "git failed";
|
|
70745
|
-
}, validRefName = (cwd, name) => !name.startsWith("-") &&
|
|
71335
|
+
}, validRefName = (cwd, name) => !name.startsWith("-") && git5(cwd, ["check-ref-format", "--branch", name]).ok, nulList = (text) => text.split("\x00").filter(Boolean), SESSION_SAFE, SHA;
|
|
70746
71336
|
var init_ops = __esm(() => {
|
|
70747
71337
|
init_branch();
|
|
70748
71338
|
init_commit_flavors();
|
|
70749
71339
|
init_pr_create();
|
|
71340
|
+
init_release_tracks();
|
|
70750
71341
|
init_vcs_config();
|
|
70751
71342
|
init_redact();
|
|
70752
71343
|
init_ledger();
|
|
@@ -71175,7 +71766,7 @@ var init_report = __esm(() => {
|
|
|
71175
71766
|
});
|
|
71176
71767
|
|
|
71177
71768
|
// packages/workit-core/src/forge/pr-ops.ts
|
|
71178
|
-
import { spawnSync as
|
|
71769
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
71179
71770
|
function fillFromCommits(cwd, resolved, base) {
|
|
71180
71771
|
const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
|
|
71181
71772
|
if (!base.startsWith("-"))
|
|
@@ -71183,7 +71774,7 @@ function fillFromCommits(cwd, resolved, base) {
|
|
|
71183
71774
|
const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
|
|
71184
71775
|
if (!from)
|
|
71185
71776
|
return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
|
|
71186
|
-
const log =
|
|
71777
|
+
const log = spawnSync16("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
|
|
71187
71778
|
cwd,
|
|
71188
71779
|
encoding: "utf8",
|
|
71189
71780
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -71382,6 +71973,7 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
|
|
|
71382
71973
|
const gone = !deleted.ok && remoteRefTip(cwd, resolved.remote, `refs/heads/${branch}`);
|
|
71383
71974
|
deletedBranch = deleted.ok || gone && gone.ok && gone.sha === null ? true : { error: deleted.error };
|
|
71384
71975
|
}
|
|
71976
|
+
const mergeBack = mergeBackFor(cwd, doc.base);
|
|
71385
71977
|
const row = appendObserved(cwd, {
|
|
71386
71978
|
type: "pr.merged",
|
|
71387
71979
|
actor: input.actor,
|
|
@@ -71407,11 +71999,25 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
|
|
|
71407
71999
|
verdict,
|
|
71408
72000
|
grant: { source: grant.source },
|
|
71409
72001
|
deletedBranch,
|
|
71410
|
-
recorded: row.ok ? { id: String(row.value.id) } : { error: row.error }
|
|
72002
|
+
recorded: row.ok ? { id: String(row.value.id) } : { error: row.error },
|
|
72003
|
+
mergeBack: mergeBack.branches,
|
|
72004
|
+
mergeBackTrack: mergeBack.track
|
|
71411
72005
|
}
|
|
71412
72006
|
};
|
|
71413
72007
|
}
|
|
71414
|
-
var VERIFY_DELAYS_MS, noun = (resolved) => resolved.forge.kind === "github" ? "pull request" : "merge request", grantBlocked = (decision) => failure3("blocked", decision.error, decision.unblock),
|
|
72008
|
+
var VERIFY_DELAYS_MS, noun = (resolved) => resolved.forge.kind === "github" ? "pull request" : "merge request", grantBlocked = (decision) => failure3("blocked", decision.error, decision.unblock), mergeBackFor = (cwd, base) => {
|
|
72009
|
+
try {
|
|
72010
|
+
const owners = workspaceReleaseTracks(cwd).tracks.filter((track) => track.productionBranch === base);
|
|
72011
|
+
if (owners.length !== 1)
|
|
72012
|
+
return { track: null, branches: [] };
|
|
72013
|
+
return {
|
|
72014
|
+
track: owners[0].name,
|
|
72015
|
+
branches: owners[0].mergeBackBranches.filter((branch) => branch !== base)
|
|
72016
|
+
};
|
|
72017
|
+
} catch {
|
|
72018
|
+
return { track: null, branches: [] };
|
|
72019
|
+
}
|
|
72020
|
+
}, refuse = (error, unblock, refusal) => ({
|
|
71415
72021
|
ok: false,
|
|
71416
72022
|
code: "blocked",
|
|
71417
72023
|
error,
|
|
@@ -71422,6 +72028,7 @@ var init_pr_ops = __esm(() => {
|
|
|
71422
72028
|
init_autonomy();
|
|
71423
72029
|
init_branch();
|
|
71424
72030
|
init_vcs_config();
|
|
72031
|
+
init_release_tracks();
|
|
71425
72032
|
init_ops();
|
|
71426
72033
|
init_rev();
|
|
71427
72034
|
init_ledger();
|
|
@@ -71442,7 +72049,7 @@ var init_pr_ops = __esm(() => {
|
|
|
71442
72049
|
});
|
|
71443
72050
|
|
|
71444
72051
|
// packages/workit-core/src/forge/exec.ts
|
|
71445
|
-
import { spawnSync as
|
|
72052
|
+
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
71446
72053
|
import fs19 from "node:fs";
|
|
71447
72054
|
import path39 from "node:path";
|
|
71448
72055
|
function findExecutable(bin, env) {
|
|
@@ -71477,7 +72084,7 @@ function systemRunner(kind, apiHost, env = process.env) {
|
|
|
71477
72084
|
if (!exe)
|
|
71478
72085
|
return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
|
|
71479
72086
|
const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
|
|
71480
|
-
const result =
|
|
72087
|
+
const result = spawnSync17(exe, [...args], {
|
|
71481
72088
|
encoding: "utf8",
|
|
71482
72089
|
env: { ...childEnv, ...token },
|
|
71483
72090
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -72390,7 +72997,7 @@ var exports_pr = {};
|
|
|
72390
72997
|
__export(exports_pr, {
|
|
72391
72998
|
run: () => run10
|
|
72392
72999
|
});
|
|
72393
|
-
import { readFileSync as
|
|
73000
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
72394
73001
|
import path40 from "node:path";
|
|
72395
73002
|
async function status(argv, io) {
|
|
72396
73003
|
const flags = parseFlags(argv, { pr: "value", branch: "value", "log-lines": "value" });
|
|
@@ -72443,6 +73050,7 @@ function verdictBlock(cwd, branch) {
|
|
|
72443
73050
|
async function create4(argv, io) {
|
|
72444
73051
|
const flags = parseFlags(argv, {
|
|
72445
73052
|
base: "value",
|
|
73053
|
+
track: "value",
|
|
72446
73054
|
title: "value",
|
|
72447
73055
|
body: "value",
|
|
72448
73056
|
"body-file": "value",
|
|
@@ -72461,18 +73069,26 @@ async function create4(argv, io) {
|
|
|
72461
73069
|
let body = flags.values.body ?? null;
|
|
72462
73070
|
if (flags.values["body-file"] !== undefined) {
|
|
72463
73071
|
try {
|
|
72464
|
-
body =
|
|
73072
|
+
body = readFileSync18(path40.resolve(io.cwd, flags.values["body-file"]), "utf8");
|
|
72465
73073
|
} catch {
|
|
72466
73074
|
return usage3(io, `cannot read --body-file ${flags.values["body-file"]}`, CREATE_USAGE);
|
|
72467
73075
|
}
|
|
72468
73076
|
}
|
|
73077
|
+
if (flags.values.base !== undefined && flags.values.track !== undefined)
|
|
73078
|
+
return usage3(io, "pass --base or --track, not both (--track picks the base for you)", CREATE_USAGE);
|
|
72469
73079
|
let base = flags.values.base ?? null;
|
|
73080
|
+
let releaseTrack = null;
|
|
72470
73081
|
if (!base) {
|
|
72471
|
-
const resolved = vcsConfig("resolve", io.cwd);
|
|
73082
|
+
const resolved = vcsConfig("resolve", io.cwd, { track: flags.values.track ?? null });
|
|
72472
73083
|
if (resolved.ok === false)
|
|
72473
73084
|
return emit(io, fail("blocked", String(resolved.error), {
|
|
72474
73085
|
unblock: "fix ~/.config/workit/vcs.json or pass --base <b>"
|
|
72475
73086
|
}));
|
|
73087
|
+
releaseTrack = resolved.releaseTrack ?? null;
|
|
73088
|
+
if (releaseTrack?.blocking)
|
|
73089
|
+
return emit(io, fail("blocked", releaseTrack.blocking, {
|
|
73090
|
+
unblock: "workit pr create --track <name> … # or --base <branch>"
|
|
73091
|
+
}));
|
|
72476
73092
|
base = String(resolved.defaultTargetBranch ?? "") || null;
|
|
72477
73093
|
}
|
|
72478
73094
|
if (!base)
|
|
@@ -72502,8 +73118,11 @@ async function create4(argv, io) {
|
|
|
72502
73118
|
}, forgeDeps.sleep);
|
|
72503
73119
|
if (!result.ok)
|
|
72504
73120
|
return forgeFail(io, result);
|
|
72505
|
-
|
|
73121
|
+
const created = releaseTrack ? { ...result.data, releaseTrack } : result.data;
|
|
73122
|
+
return emit(io, ok(created), (data) => [
|
|
72506
73123
|
`${data.created ? "opened" : "found open"} ${connected.data.forge.kind === "github" ? "PR #" : "MR !"}${data.number}${data.draft && data.created ? " (draft)" : ""}: ${data.branch} -> ${data.base} ${data.url}`,
|
|
73124
|
+
...data.releaseTrack?.name ? [`release track: ${data.releaseTrack.name} (${data.releaseTrack.detail})`] : [],
|
|
73125
|
+
...(data.releaseTrack?.warnings ?? []).map((warning) => `note: ${warning}`),
|
|
72507
73126
|
`head ${data.head.slice(0, 12)} verified on the forge`,
|
|
72508
73127
|
..."error" in data.recorded ? [`ledger: not recorded (${data.recorded.error})`] : []
|
|
72509
73128
|
]);
|
|
@@ -72532,6 +73151,9 @@ async function merge3(argv, io) {
|
|
|
72532
73151
|
return emit(io, ok(result.data), (data) => [
|
|
72533
73152
|
`merged ${connected.data.forge.kind === "github" ? "PR #" : "MR !"}${data.number} (${data.method}) at head ${data.head.slice(0, 12)}${data.mergeSha ? ` -> ${data.mergeSha.slice(0, 12)}` : ""}`,
|
|
72534
73153
|
data.verdict.required ? `verdict ${data.verdict.verdictId ?? "?"} accepted for that head` : "no verdict required (workspace grants merge: true)",
|
|
73154
|
+
...data.mergeBack.length ? [
|
|
73155
|
+
`merge back: ${data.base} is the ${data.mergeBackTrack} production branch; bring it into ${data.mergeBack.join(", ")}`
|
|
73156
|
+
] : [],
|
|
72535
73157
|
...data.deletedBranch === true ? [`deleted ${data.branch}`] : typeof data.deletedBranch === "object" ? [`branch not deleted: ${data.deletedBranch.error}`] : [],
|
|
72536
73158
|
..."error" in data.recorded ? [`ledger: not recorded (${data.recorded.error})`] : []
|
|
72537
73159
|
]);
|
|
@@ -72546,7 +73168,7 @@ async function run10(argv, io) {
|
|
|
72546
73168
|
return merge3(rest, io);
|
|
72547
73169
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown pr subcommand "${sub}"` : "missing pr subcommand", USAGE4);
|
|
72548
73170
|
}
|
|
72549
|
-
var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b>] (--title <t> [--body <text> | --body-file <f>] | --fill) [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--method squash|merge|rebase] [--delete-branch] [--json]", USAGE4 = "workit pr status|create|merge ... (workit help pr)", METHODS2;
|
|
73171
|
+
var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b> | --track <t>] (--title <t> [--body <text> | --body-file <f>] | --fill) [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--method squash|merge|rebase] [--delete-branch] [--json]", USAGE4 = "workit pr status|create|merge ... (workit help pr)", METHODS2;
|
|
72550
73172
|
var init_pr = __esm(() => {
|
|
72551
73173
|
init_pr_body();
|
|
72552
73174
|
init_pr_ops();
|
|
@@ -72777,7 +73399,13 @@ __export(exports_git, {
|
|
|
72777
73399
|
run: () => run12
|
|
72778
73400
|
});
|
|
72779
73401
|
async function branch(argv, io) {
|
|
72780
|
-
const flags = parseFlags(argv, {
|
|
73402
|
+
const flags = parseFlags(argv, {
|
|
73403
|
+
base: "value",
|
|
73404
|
+
kind: "value",
|
|
73405
|
+
slug: "value",
|
|
73406
|
+
track: "value",
|
|
73407
|
+
carry: "boolean"
|
|
73408
|
+
});
|
|
72781
73409
|
if (typeof flags === "string")
|
|
72782
73410
|
return usage3(io, flags, BRANCH_USAGE);
|
|
72783
73411
|
const { kind, slug } = flags.values;
|
|
@@ -72789,18 +73417,19 @@ async function branch(argv, io) {
|
|
|
72789
73417
|
return usage3(io, "--kind must be feature, bugfix or hotfix", BRANCH_USAGE);
|
|
72790
73418
|
if (kind !== undefined && flags.positionals.length)
|
|
72791
73419
|
return usage3(io, "pass a name or --kind/--slug, not both", BRANCH_USAGE);
|
|
72792
|
-
|
|
72793
|
-
if (!name)
|
|
73420
|
+
if (kind === undefined && !flags.positionals[0])
|
|
72794
73421
|
return usage3(io, "missing branch name", BRANCH_USAGE);
|
|
72795
73422
|
const result = gitBranch(io.cwd, {
|
|
72796
|
-
name,
|
|
73423
|
+
...kind !== undefined ? { kind, slug } : { name: flags.positionals[0] },
|
|
72797
73424
|
base: flags.values.base ?? null,
|
|
73425
|
+
track: flags.values.track ?? null,
|
|
72798
73426
|
carry: flags.booleans.has("carry")
|
|
72799
73427
|
});
|
|
72800
73428
|
if (!result.ok)
|
|
72801
73429
|
return forgeFail(io, result);
|
|
72802
73430
|
return emit(io, ok(result.data), (data) => [
|
|
72803
73431
|
`switched to new branch ${data.branch} from ${data.baseRef} (${short2(data.baseSha)})${data.carried ? ", carrying uncommitted changes" : ""}`,
|
|
73432
|
+
...data.releaseTrack?.name ? [`release track: ${data.releaseTrack.name} (${data.releaseTrack.detail})`] : [],
|
|
72804
73433
|
...data.notes.map((note) => `note: ${note}`)
|
|
72805
73434
|
]);
|
|
72806
73435
|
}
|
|
@@ -72921,7 +73550,7 @@ async function run12(argv, io) {
|
|
|
72921
73550
|
return push(rest, io);
|
|
72922
73551
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown git subcommand "${sub}"` : "missing git subcommand", USAGE5);
|
|
72923
73552
|
}
|
|
72924
|
-
var BRANCH_USAGE = "workit git branch <name> | --kind feature|bugfix|hotfix --slug <s> [--base <b>] [--carry] [--json]", COMMIT_USAGE = "workit git commit -m <msg> [--all | [--] <paths…>] [--json]", PUSH_USAGE = "workit git push [--set-upstream] [--force-with-lease [--expect <sha>] [--overwrite-unintegrated]] [--json]", USAGE5 = "workit git branch|commit|push ... (workit help git)", short2 = (sha) => sha ? sha.slice(0, 12) : "(none)";
|
|
73553
|
+
var BRANCH_USAGE = "workit git branch <name> | --kind feature|bugfix|hotfix --slug <s> [--base <b>] [--track <t>] [--carry] [--json]", COMMIT_USAGE = "workit git commit -m <msg> [--all | [--] <paths…>] [--json]", PUSH_USAGE = "workit git push [--set-upstream] [--force-with-lease [--expect <sha>] [--overwrite-unintegrated]] [--json]", USAGE5 = "workit git branch|commit|push ... (workit help git)", short2 = (sha) => sha ? sha.slice(0, 12) : "(none)";
|
|
72925
73554
|
var init_git2 = __esm(() => {
|
|
72926
73555
|
init_autonomy();
|
|
72927
73556
|
init_ops();
|
|
@@ -72932,7 +73561,7 @@ var init_git2 = __esm(() => {
|
|
|
72932
73561
|
});
|
|
72933
73562
|
|
|
72934
73563
|
// packages/workit-core/src/forge/verify.ts
|
|
72935
|
-
import { spawnSync as
|
|
73564
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
72936
73565
|
function finish(cwd, report, actor) {
|
|
72937
73566
|
const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
|
|
72938
73567
|
const out = { ...report, delivered };
|
|
@@ -73145,7 +73774,7 @@ var NPM_NAME, SEMVER, SAFE_ARG, systemNpm = (args) => {
|
|
|
73145
73774
|
};
|
|
73146
73775
|
const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
|
|
73147
73776
|
const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
|
|
73148
|
-
const result = process.platform === "win32" ?
|
|
73777
|
+
const result = process.platform === "win32" ? spawnSync18(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync18("npm", [...args], options);
|
|
73149
73778
|
return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
73150
73779
|
}, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
|
|
73151
73780
|
try {
|
|
@@ -73252,8 +73881,8 @@ var init_verify_delivery = __esm(() => {
|
|
|
73252
73881
|
});
|
|
73253
73882
|
|
|
73254
73883
|
// packages/workit-core/src/stack.ts
|
|
73255
|
-
import { spawnSync as
|
|
73256
|
-
import { createHash as
|
|
73884
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73885
|
+
import { createHash as createHash15, randomBytes as randomBytes3 } from "node:crypto";
|
|
73257
73886
|
import fs21 from "node:fs";
|
|
73258
73887
|
import path41 from "node:path";
|
|
73259
73888
|
function worktreeOf(cwd, branch) {
|
|
@@ -73353,7 +73982,7 @@ function stacksDir(cwd) {
|
|
|
73353
73982
|
return { ok: true, data: path41.join(root.value.root, "stacks") };
|
|
73354
73983
|
}
|
|
73355
73984
|
function parseStack(raw) {
|
|
73356
|
-
if (!
|
|
73985
|
+
if (!isRecord7(raw) || !Array.isArray(raw.branches))
|
|
73357
73986
|
return null;
|
|
73358
73987
|
const name = str3(raw.name);
|
|
73359
73988
|
const trunk = str3(raw.trunk);
|
|
@@ -73361,12 +73990,12 @@ function parseStack(raw) {
|
|
|
73361
73990
|
return null;
|
|
73362
73991
|
const branches = [];
|
|
73363
73992
|
for (const item of raw.branches) {
|
|
73364
|
-
if (!
|
|
73993
|
+
if (!isRecord7(item))
|
|
73365
73994
|
return null;
|
|
73366
73995
|
const branch = str3(item.branch);
|
|
73367
73996
|
if (!branch)
|
|
73368
73997
|
return null;
|
|
73369
|
-
const merged =
|
|
73998
|
+
const merged = isRecord7(item.merged) ? {
|
|
73370
73999
|
pr: typeof item.merged.pr === "number" ? item.merged.pr : null,
|
|
73371
74000
|
mergeSha: str3(item.merged.mergeSha),
|
|
73372
74001
|
at: str3(item.merged.at) ?? ""
|
|
@@ -73379,7 +74008,7 @@ function parseStack(raw) {
|
|
|
73379
74008
|
lastParentHead: str3(item.lastParentHead),
|
|
73380
74009
|
patchId: str3(item.patchId),
|
|
73381
74010
|
merged,
|
|
73382
|
-
...
|
|
74011
|
+
...isRecord7(item.pendingRestack) && str3(item.pendingRestack.from) && str3(item.pendingRestack.tip) && str3(item.pendingRestack.onto) ? {
|
|
73383
74012
|
pendingRestack: {
|
|
73384
74013
|
from: str3(item.pendingRestack.from),
|
|
73385
74014
|
tip: str3(item.pendingRestack.tip),
|
|
@@ -73765,7 +74394,7 @@ function commitKeys(cwd, range) {
|
|
|
73765
74394
|
const patches = new Map;
|
|
73766
74395
|
const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
|
|
73767
74396
|
if (diff.ok && diff.stdout.trim()) {
|
|
73768
|
-
const ids =
|
|
74397
|
+
const ids = spawnSync19("git", ["patch-id", "--stable"], {
|
|
73769
74398
|
cwd,
|
|
73770
74399
|
input: diff.stdout,
|
|
73771
74400
|
encoding: "utf8",
|
|
@@ -74373,7 +75002,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74373
75002
|
...unblock ? { unblock } : {},
|
|
74374
75003
|
...data ? { data } : {}
|
|
74375
75004
|
}), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
74376
|
-
const run =
|
|
75005
|
+
const run = spawnSync19("git", args, {
|
|
74377
75006
|
cwd,
|
|
74378
75007
|
encoding: "utf8",
|
|
74379
75008
|
timeout: timeoutMs,
|
|
@@ -74404,7 +75033,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74404
75033
|
return dir.ok ? path41.join(dir.data, "worktrees") : null;
|
|
74405
75034
|
}, firstLine = (run) => (`${run.stderr}
|
|
74406
75035
|
${run.stdout}`.split(`
|
|
74407
|
-
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${
|
|
75036
|
+
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash15("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
|
|
74408
75037
|
if (name.length === 0 || name.length > 200)
|
|
74409
75038
|
return false;
|
|
74410
75039
|
for (let index = 0;index < name.length; index += 1) {
|
|
@@ -74413,7 +75042,7 @@ ${run.stdout}`.split(`
|
|
|
74413
75042
|
return false;
|
|
74414
75043
|
}
|
|
74415
75044
|
return true;
|
|
74416
|
-
},
|
|
75045
|
+
}, isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), str3 = (value) => typeof value === "string" && value ? value : null, LOCK_WAIT_MS3 = 2000, HEARTBEAT_MS = 20000, HEARTBEAT_STALE_MS, OWNERLESS_STALE_MS = 30000, OWNER = "owner", readOwner = (lock) => {
|
|
74417
75046
|
let raw = null;
|
|
74418
75047
|
try {
|
|
74419
75048
|
raw = fs21.readFileSync(path41.join(lock, OWNER), "utf8");
|
|
@@ -74459,7 +75088,7 @@ __export(exports_stack, {
|
|
|
74459
75088
|
run: () => run14
|
|
74460
75089
|
});
|
|
74461
75090
|
async function plan(argv, io) {
|
|
74462
|
-
const flags = parseFlags(argv, { name: "value", trunk: "value" });
|
|
75091
|
+
const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
|
|
74463
75092
|
if (typeof flags === "string")
|
|
74464
75093
|
return usage3(io, flags, PLAN_USAGE);
|
|
74465
75094
|
const name = flags.values.name ?? null;
|
|
@@ -74472,7 +75101,20 @@ async function plan(argv, io) {
|
|
|
74472
75101
|
if (selected.ok)
|
|
74473
75102
|
existing = selected.data;
|
|
74474
75103
|
}
|
|
74475
|
-
const
|
|
75104
|
+
const track = flags.values.track ?? null;
|
|
75105
|
+
if (track !== null && flags.values.trunk !== undefined)
|
|
75106
|
+
return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE);
|
|
75107
|
+
let trunk = flags.values.trunk ?? existing?.trunk ?? null;
|
|
75108
|
+
if (trunk === null || track !== null) {
|
|
75109
|
+
const derived = defaultTrunk(io, track, flags.positionals[0] ?? null);
|
|
75110
|
+
if ("error" in derived)
|
|
75111
|
+
return emit(io, fail("blocked", derived.error, {
|
|
75112
|
+
unblock: "workit stack plan --track <name> … # or --trunk <branch>"
|
|
75113
|
+
}));
|
|
75114
|
+
if (existing && track !== null && derived.trunk !== existing.trunk)
|
|
75115
|
+
return emit(io, fail("invalid_input", `stack ${existing.name} is on trunk ${existing.trunk}; --track ${track} targets ${derived.trunk ?? "(none)"}`, { unblock: "drop --track to re-plan on the recorded trunk" }));
|
|
75116
|
+
trunk ??= derived.trunk ?? "main";
|
|
75117
|
+
}
|
|
74476
75118
|
const connected = connect(io, flags.positionals[0] ?? null);
|
|
74477
75119
|
const resolved = connected.ok ? connected.data : null;
|
|
74478
75120
|
const planned = planStack(io.cwd, resolved, { name, trunk, branches: flags.positionals }, existing);
|
|
@@ -74632,9 +75274,16 @@ async function run14(argv, io) {
|
|
|
74632
75274
|
return land(rest, io);
|
|
74633
75275
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown stack subcommand "${sub}"` : "missing stack subcommand", USAGE7);
|
|
74634
75276
|
}
|
|
74635
|
-
var PLAN_USAGE = "workit stack plan [--name <n>] [--trunk <b>] [<bottom> … <top>] [--json]", STATUS_USAGE2 = "workit stack status [--name <n>] [--json]", SYNC_USAGE = "workit stack sync [--name <n>] [--local] [--dry-run] [--force <branch>]… [--json]", LAND_USAGE = "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--timeout 20m] [--interval 30s] [--json]", USAGE7 = "workit stack plan|status|sync|land ... (workit help stack)", short4 = (sha) => sha ? sha.slice(0, 12) : "?", stackFailed = (io, result) => emit(io, fail(result.code, result.error, { unblock: result.unblock, data: result.data ?? {} })), defaultTrunk = (io) => {
|
|
74636
|
-
const resolved = vcsConfig("resolve", io.cwd
|
|
74637
|
-
|
|
75277
|
+
var PLAN_USAGE = "workit stack plan [--name <n>] [--trunk <b> | --track <t>] [<bottom> … <top>] [--json]", STATUS_USAGE2 = "workit stack status [--name <n>] [--json]", SYNC_USAGE = "workit stack sync [--name <n>] [--local] [--dry-run] [--force <branch>]… [--json]", LAND_USAGE = "workit stack land [--name <n>] [--dry-run] [--max <n>] [--method squash|merge|rebase] [--timeout 20m] [--interval 30s] [--json]", USAGE7 = "workit stack plan|status|sync|land ... (workit help stack)", short4 = (sha) => sha ? sha.slice(0, 12) : "?", stackFailed = (io, result) => emit(io, fail(result.code, result.error, { unblock: result.unblock, data: result.data ?? {} })), defaultTrunk = (io, track, branch) => {
|
|
75278
|
+
const resolved = vcsConfig("resolve", io.cwd, {
|
|
75279
|
+
track,
|
|
75280
|
+
...branch ? { branch } : {}
|
|
75281
|
+
});
|
|
75282
|
+
if (resolved.ok === false)
|
|
75283
|
+
return track !== null || String(resolved.configPath ?? "").endsWith("workspaces.json") ? { error: String(resolved.error) } : { trunk: null };
|
|
75284
|
+
if (resolved.releaseTrack?.blocking)
|
|
75285
|
+
return { error: String(resolved.releaseTrack.blocking) };
|
|
75286
|
+
return { trunk: String(resolved.defaultTargetBranch ?? "") || null };
|
|
74638
75287
|
}, label = (forge, pr) => pr === null ? "no PR" : `${forge === "gitlab" ? "MR !" : "PR #"}${pr}`, renderSync = (data) => [
|
|
74639
75288
|
`${data.dryRun ? "would sync" : "synced"} stack ${data.name}${data.merged.length ? `; merged: ${data.merged.map((item) => item.branch).join(", ")}` : ""}`,
|
|
74640
75289
|
...data.steps.map((step) => [
|
|
@@ -90686,11 +91335,11 @@ var init_rules = __esm(() => {
|
|
|
90686
91335
|
});
|
|
90687
91336
|
|
|
90688
91337
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
90689
|
-
import { spawnSync as
|
|
90690
|
-
import { existsSync as existsSync18, readdirSync as readdirSync8, readFileSync as
|
|
91338
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
91339
|
+
import { existsSync as existsSync18, readdirSync as readdirSync8, readFileSync as readFileSync19, statSync as statSync7 } from "node:fs";
|
|
90691
91340
|
import path43 from "node:path";
|
|
90692
|
-
function
|
|
90693
|
-
const run =
|
|
91341
|
+
function git6(cwd, args) {
|
|
91342
|
+
const run = spawnSync20("git", ["-c", "core.quotepath=off", ...args], {
|
|
90694
91343
|
cwd,
|
|
90695
91344
|
encoding: "utf8",
|
|
90696
91345
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -90726,20 +91375,20 @@ function expandPaths(cwd, inputs) {
|
|
|
90726
91375
|
function resolveBase(cwd, base) {
|
|
90727
91376
|
const candidates = base ? [base] : ["origin/main", "main", "origin/master", "master"];
|
|
90728
91377
|
for (const candidate of candidates) {
|
|
90729
|
-
if (!
|
|
91378
|
+
if (!git6(cwd, ["rev-parse", "--verify", "--quiet", `${candidate}^{commit}`]).ok)
|
|
90730
91379
|
continue;
|
|
90731
|
-
const mergeBase =
|
|
91380
|
+
const mergeBase = git6(cwd, ["merge-base", candidate, "HEAD"]);
|
|
90732
91381
|
return mergeBase.ok ? mergeBase.stdout.trim() : null;
|
|
90733
91382
|
}
|
|
90734
91383
|
return null;
|
|
90735
91384
|
}
|
|
90736
91385
|
function changedLines(cwd, base) {
|
|
90737
|
-
const root =
|
|
91386
|
+
const root = git6(cwd, ["rev-parse", "--show-toplevel"]).stdout.trim();
|
|
90738
91387
|
const changed = new Map;
|
|
90739
|
-
const names =
|
|
91388
|
+
const names = git6(root, ["diff", "--name-only", "-z", "--no-renames", "--diff-filter=AM", base]);
|
|
90740
91389
|
for (const file of names.stdout.split("\x00").filter(Boolean)) {
|
|
90741
91390
|
const lines = new Set;
|
|
90742
|
-
const diff =
|
|
91391
|
+
const diff = git6(root, ["diff", "-U0", "--no-color", "--no-ext-diff", base, "--", file]);
|
|
90743
91392
|
for (const line of diff.stdout.split(`
|
|
90744
91393
|
`)) {
|
|
90745
91394
|
const hunk = /^@@ -\S+ \+(\d+)(?:,(\d+))? @@/.exec(line);
|
|
@@ -90752,7 +91401,7 @@ function changedLines(cwd, base) {
|
|
|
90752
91401
|
}
|
|
90753
91402
|
changed.set(path43.join(root, file), lines);
|
|
90754
91403
|
}
|
|
90755
|
-
const untracked =
|
|
91404
|
+
const untracked = git6(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
90756
91405
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
90757
91406
|
changed.set(path43.join(root, file), "all");
|
|
90758
91407
|
return changed;
|
|
@@ -90767,7 +91416,7 @@ function auditFiles(files, display) {
|
|
|
90767
91416
|
const shown = display(file);
|
|
90768
91417
|
let parsed;
|
|
90769
91418
|
try {
|
|
90770
|
-
parsed = parseSource(
|
|
91419
|
+
parsed = parseSource(readFileSync19(file, "utf8"), file);
|
|
90771
91420
|
} catch (error) {
|
|
90772
91421
|
parseErrors.push({
|
|
90773
91422
|
file: shown,
|
|
@@ -90835,7 +91484,7 @@ import {
|
|
|
90835
91484
|
mkdirSync as mkdirSync9,
|
|
90836
91485
|
mkdtempSync as mkdtempSync4,
|
|
90837
91486
|
readdirSync as readdirSync9,
|
|
90838
|
-
readFileSync as
|
|
91487
|
+
readFileSync as readFileSync20,
|
|
90839
91488
|
readlinkSync as readlinkSync3,
|
|
90840
91489
|
realpathSync as realpathSync9,
|
|
90841
91490
|
renameSync as renameSync5,
|
|
@@ -90944,7 +91593,7 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
90944
91593
|
const stat = lstatSync7(dir);
|
|
90945
91594
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
90946
91595
|
continue;
|
|
90947
|
-
const pid = Number(
|
|
91596
|
+
const pid = Number(readFileSync20(path44.join(dir, PID_FILE), "utf8"));
|
|
90948
91597
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
90949
91598
|
continue;
|
|
90950
91599
|
} catch (error) {
|
|
@@ -91022,18 +91671,18 @@ function copyWorkingTree(repo) {
|
|
|
91022
91671
|
const dir = mkdtempSync4(path44.join(os14.tmpdir(), TEMP_PREFIX));
|
|
91023
91672
|
writeFileSync9(path44.join(dir, PID_FILE), String(process.pid));
|
|
91024
91673
|
const tree = path44.join(dir, "tree");
|
|
91025
|
-
const head =
|
|
91026
|
-
if (head &&
|
|
91027
|
-
const branch =
|
|
91674
|
+
const head = git6(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
91675
|
+
if (head && git6(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
91676
|
+
const branch = git6(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
91028
91677
|
if (branch) {
|
|
91029
|
-
|
|
91030
|
-
|
|
91678
|
+
git6(tree, ["update-ref", `refs/heads/${branch}`, head]);
|
|
91679
|
+
git6(tree, ["symbolic-ref", "HEAD", `refs/heads/${branch}`]);
|
|
91031
91680
|
} else
|
|
91032
|
-
|
|
91033
|
-
|
|
91681
|
+
git6(tree, ["update-ref", "--no-deref", "HEAD", head]);
|
|
91682
|
+
git6(tree, ["reset", "-q"]);
|
|
91034
91683
|
} else
|
|
91035
91684
|
mkdirSync9(tree, { recursive: true });
|
|
91036
|
-
const listed =
|
|
91685
|
+
const listed = git6(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00");
|
|
91037
91686
|
const dirs = new Set([""]);
|
|
91038
91687
|
for (const relative of listed) {
|
|
91039
91688
|
if (!relative)
|
|
@@ -91096,10 +91745,10 @@ function runCommand(command, cwd, timeoutMs, env) {
|
|
|
91096
91745
|
async function runMutation(options) {
|
|
91097
91746
|
const started = performance.now();
|
|
91098
91747
|
const { repo } = options;
|
|
91099
|
-
const tracked =
|
|
91748
|
+
const tracked = git6(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
91100
91749
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
91101
91750
|
try {
|
|
91102
|
-
return { file, text:
|
|
91751
|
+
return { file, text: readFileSync20(path44.join(repo, file), "utf8") };
|
|
91103
91752
|
} catch {
|
|
91104
91753
|
return { file, text: "" };
|
|
91105
91754
|
}
|
|
@@ -91112,7 +91761,7 @@ async function runMutation(options) {
|
|
|
91112
91761
|
if (NOT_SOURCE.test(relative) || !existsSync19(absolute))
|
|
91113
91762
|
continue;
|
|
91114
91763
|
try {
|
|
91115
|
-
candidates.push(...mutantsFor(
|
|
91764
|
+
candidates.push(...mutantsFor(readFileSync20(absolute, "utf8"), relative, lines));
|
|
91116
91765
|
} catch {}
|
|
91117
91766
|
}
|
|
91118
91767
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -91192,7 +91841,7 @@ async function runMutation(options) {
|
|
|
91192
91841
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
91193
91842
|
continue;
|
|
91194
91843
|
}
|
|
91195
|
-
const original =
|
|
91844
|
+
const original = readFileSync20(path44.join(copy, mutant.file), "utf8");
|
|
91196
91845
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
91197
91846
|
current = { file: mutant.file, original };
|
|
91198
91847
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -91398,7 +92047,7 @@ async function run16(argv, io) {
|
|
|
91398
92047
|
if (typeof options === "string")
|
|
91399
92048
|
return emit(io, fail("invalid_input", `${options}
|
|
91400
92049
|
usage: ${USAGE9}`));
|
|
91401
|
-
const top =
|
|
92050
|
+
const top = git6(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
91402
92051
|
const repo = top.ok ? path45.resolve(top.stdout.trim()) : null;
|
|
91403
92052
|
const display = (file) => toPosix(path45.relative(io.cwd, file) || file);
|
|
91404
92053
|
let base = null;
|
|
@@ -91610,7 +92259,7 @@ var exports_youtrack = {};
|
|
|
91610
92259
|
__export(exports_youtrack, {
|
|
91611
92260
|
run: () => run17
|
|
91612
92261
|
});
|
|
91613
|
-
import { readFileSync as
|
|
92262
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
91614
92263
|
import path46 from "node:path";
|
|
91615
92264
|
async function run17(argv, io) {
|
|
91616
92265
|
const [sub, ...rest] = argv;
|
|
@@ -91657,7 +92306,7 @@ async function run17(argv, io) {
|
|
|
91657
92306
|
let markdown = flags.values.markdown ?? "";
|
|
91658
92307
|
if (flags.values.file)
|
|
91659
92308
|
try {
|
|
91660
|
-
markdown =
|
|
92309
|
+
markdown = readFileSync21(path46.resolve(io.cwd, flags.values.file), "utf8");
|
|
91661
92310
|
} catch (error) {
|
|
91662
92311
|
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE10);
|
|
91663
92312
|
}
|
|
@@ -91725,7 +92374,7 @@ var exports_changelog = {};
|
|
|
91725
92374
|
__export(exports_changelog, {
|
|
91726
92375
|
run: () => run18
|
|
91727
92376
|
});
|
|
91728
|
-
import { readFileSync as
|
|
92377
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
91729
92378
|
import path47 from "node:path";
|
|
91730
92379
|
async function run18(argv, io) {
|
|
91731
92380
|
const [sub, ...rest] = argv;
|
|
@@ -91772,7 +92421,7 @@ async function run18(argv, io) {
|
|
|
91772
92421
|
]);
|
|
91773
92422
|
}
|
|
91774
92423
|
var USAGE11 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
91775
|
-
const text = raw === "-" ?
|
|
92424
|
+
const text = raw === "-" ? readFileSync22(0, "utf8") : raw.startsWith("@") ? readFileSync22(path47.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
91776
92425
|
return JSON.parse(text);
|
|
91777
92426
|
};
|
|
91778
92427
|
var init_changelog2 = __esm(() => {
|
|
@@ -91949,7 +92598,7 @@ var VERBS = [
|
|
|
91949
92598
|
{
|
|
91950
92599
|
name: "pr",
|
|
91951
92600
|
group: "delivery",
|
|
91952
|
-
usage: "workit pr status [--pr <n>] | pr create [--base <b>] (--title <t> | --fill) [--draft] | pr merge [--pr <n>] [--method squash|merge|rebase] [--delete-branch]",
|
|
92601
|
+
usage: "workit pr status [--pr <n>] | pr create [--base <b> | --track <t>] (--title <t> | --fill) [--draft] | pr merge [--pr <n>] [--method squash|merge|rebase] [--delete-branch]",
|
|
91953
92602
|
summary: "PR/MR state with failing log tails and next action; open a SHA-verified PR; merge only when READY, verified and granted",
|
|
91954
92603
|
load: () => Promise.resolve().then(() => (init_pr(), exports_pr))
|
|
91955
92604
|
},
|
|
@@ -91963,7 +92612,7 @@ var VERBS = [
|
|
|
91963
92612
|
{
|
|
91964
92613
|
name: "git",
|
|
91965
92614
|
group: "delivery",
|
|
91966
|
-
usage: "workit git branch <name> [--base <b>] | git commit -m <msg> [--all | -- <paths…>] | git push [--set-upstream] [--force-with-lease]",
|
|
92615
|
+
usage: "workit git branch <name> [--base <b>] [--track <t>] | git commit -m <msg> [--all | -- <paths…>] | git push [--set-upstream] [--force-with-lease]",
|
|
91967
92616
|
summary: "Policy-checked branch and commit (Workit-Session trailer); push with a lease and a verified remote tip",
|
|
91968
92617
|
load: () => Promise.resolve().then(() => (init_git2(), exports_git))
|
|
91969
92618
|
},
|