@brainervirus/workit-claude-code 7.0.0 → 7.2.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 +49 -49
- package/dist/workit.js +1026 -276
- package/package.json +3 -3
- package/skills/implement/SKILL.md +3 -2
- package/skills/ship/SKILL.md +31 -13
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.2.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.2.0",
|
|
107
|
+
"@brainervirus/workit-cursor": "^7.2.0",
|
|
108
|
+
"@brainervirus/workit-opencode": "^7.2.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"],
|
|
@@ -15453,7 +15473,7 @@ var init_workspaces = __esm(() => {
|
|
|
15453
15473
|
account: nonBlank.optional()
|
|
15454
15474
|
}).passthrough().optional(),
|
|
15455
15475
|
autoApprove: union([boolean2(), array(nonBlank)]).optional(),
|
|
15456
|
-
defaultEndpoint:
|
|
15476
|
+
defaultEndpoint: unknown().optional(),
|
|
15457
15477
|
verification: _enum(["self", "independent"]).optional(),
|
|
15458
15478
|
autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
|
|
15459
15479
|
kind,
|
|
@@ -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
|
}
|
|
@@ -15933,6 +16457,46 @@ var init_safe_write = () => {};
|
|
|
15933
16457
|
import { copyFileSync as copyFileSync3, existsSync as existsSync6 } from "node:fs";
|
|
15934
16458
|
import os3 from "node:os";
|
|
15935
16459
|
import path18 from "node:path";
|
|
16460
|
+
function endpointOf(entry) {
|
|
16461
|
+
const raw = entry?.defaultEndpoint;
|
|
16462
|
+
if (raw === undefined)
|
|
16463
|
+
return { raw, endpoint: DEFAULT_ENDPOINT };
|
|
16464
|
+
if (isDefaultEndpoint(raw))
|
|
16465
|
+
return { raw, endpoint: raw };
|
|
16466
|
+
return {
|
|
16467
|
+
raw,
|
|
16468
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
16469
|
+
issue: `defaultEndpoint ${JSON.stringify(raw)} is not one of ${DEFAULT_ENDPOINTS.join(", ")}; using ${DEFAULT_ENDPOINT}`
|
|
16470
|
+
};
|
|
16471
|
+
}
|
|
16472
|
+
function effectiveEndpoint(endpoint, context) {
|
|
16473
|
+
if (endpoint === "commit")
|
|
16474
|
+
return { endpoint };
|
|
16475
|
+
const missing = (kind) => `${kind} grant missing; ${grantHint(context.workspace, kind)}`;
|
|
16476
|
+
if (context.grants.push === false)
|
|
16477
|
+
return { endpoint: "commit", reason: missing("push") };
|
|
16478
|
+
if (context.grants.pr === false)
|
|
16479
|
+
return { endpoint: "commit", reason: missing("pr") };
|
|
16480
|
+
if (context.configured.length > 0 && !context.accountConfigured)
|
|
16481
|
+
return {
|
|
16482
|
+
endpoint: "commit",
|
|
16483
|
+
reason: `vcs.account missing; set vcs.account for workspace "${context.workspace ?? "?"}" in ~/.config/workit/workspaces.json`
|
|
16484
|
+
};
|
|
16485
|
+
if (endpoint === "merged" && context.grants.merge === false)
|
|
16486
|
+
return { endpoint: "green", reason: missing("merge") };
|
|
16487
|
+
return { endpoint };
|
|
16488
|
+
}
|
|
16489
|
+
function endpointView(entry, context) {
|
|
16490
|
+
const { raw, endpoint, issue } = endpointOf(entry);
|
|
16491
|
+
const effective = effectiveEndpoint(endpoint, context);
|
|
16492
|
+
return {
|
|
16493
|
+
defaultEndpoint: endpoint,
|
|
16494
|
+
configuredEndpoint: raw ?? null,
|
|
16495
|
+
effectiveEndpoint: effective.endpoint,
|
|
16496
|
+
...effective.reason ? { endpointReason: effective.reason } : {},
|
|
16497
|
+
...issue ? { endpointIssue: issue } : {}
|
|
16498
|
+
};
|
|
16499
|
+
}
|
|
15936
16500
|
function configuredGrants(entry) {
|
|
15937
16501
|
const record = entry ?? {};
|
|
15938
16502
|
const raw = record.autonomy;
|
|
@@ -15958,18 +16522,28 @@ function resolveAutonomy(cwd) {
|
|
|
15958
16522
|
source: "default",
|
|
15959
16523
|
accountConfigured: false,
|
|
15960
16524
|
defaultEndpoint: DEFAULT_ENDPOINT,
|
|
16525
|
+
configuredEndpoint: null,
|
|
16526
|
+
effectiveEndpoint: DEFAULT_ENDPOINT,
|
|
15961
16527
|
verification: DEFAULT_VERIFICATION,
|
|
15962
16528
|
note: override
|
|
15963
16529
|
};
|
|
15964
16530
|
const workspace = resolveWorkspaceFrom(cwd, grantsDir(), process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
|
|
15965
16531
|
const { grants, source } = configuredGrants(workspace);
|
|
16532
|
+
const full = { ...DEFAULT_GRANTS, ...grants };
|
|
16533
|
+
const configured = GRANT_KINDS.filter((kind) => grants[kind] !== undefined);
|
|
16534
|
+
const accountConfigured = Boolean(workspace?.vcs?.account);
|
|
15966
16535
|
return {
|
|
15967
16536
|
workspace: workspace?.name ?? null,
|
|
15968
|
-
grants:
|
|
15969
|
-
configured
|
|
16537
|
+
grants: full,
|
|
16538
|
+
configured,
|
|
15970
16539
|
source,
|
|
15971
|
-
accountConfigured
|
|
15972
|
-
|
|
16540
|
+
accountConfigured,
|
|
16541
|
+
...endpointView(workspace, {
|
|
16542
|
+
workspace: workspace?.name ?? null,
|
|
16543
|
+
grants: full,
|
|
16544
|
+
configured,
|
|
16545
|
+
accountConfigured
|
|
16546
|
+
}),
|
|
15973
16547
|
verification: verificationOf(workspace)
|
|
15974
16548
|
};
|
|
15975
16549
|
}
|
|
@@ -16075,14 +16649,21 @@ function writeGrants(workspaceName, changes, dir = grantsDir(), endpoint, verifi
|
|
|
16075
16649
|
error: `failed to write ${current.path}: ${error instanceof Error ? error.message : String(error)}`
|
|
16076
16650
|
};
|
|
16077
16651
|
}
|
|
16652
|
+
const full = { ...DEFAULT_GRANTS, ...grants };
|
|
16653
|
+
const configured = GRANT_KINDS.filter((kind) => grants[kind] !== undefined);
|
|
16078
16654
|
return {
|
|
16079
16655
|
ok: true,
|
|
16080
16656
|
path: current.path,
|
|
16081
16657
|
backup,
|
|
16082
16658
|
workspace: workspaceName,
|
|
16083
|
-
grants:
|
|
16084
|
-
configured
|
|
16085
|
-
|
|
16659
|
+
grants: full,
|
|
16660
|
+
configured,
|
|
16661
|
+
...endpointView(entry, {
|
|
16662
|
+
workspace: workspaceName,
|
|
16663
|
+
grants: full,
|
|
16664
|
+
configured,
|
|
16665
|
+
accountConfigured: Boolean(accountOf(entry))
|
|
16666
|
+
}),
|
|
16086
16667
|
verification: verificationOf(entry)
|
|
16087
16668
|
};
|
|
16088
16669
|
}
|
|
@@ -16094,12 +16675,19 @@ function listGrants(dir = grantsDir()) {
|
|
|
16094
16675
|
path: current.path,
|
|
16095
16676
|
workspaces: current.entries.map((entry) => {
|
|
16096
16677
|
const { grants } = configuredGrants(entry);
|
|
16678
|
+
const full = { ...DEFAULT_GRANTS, ...grants };
|
|
16679
|
+
const configured = GRANT_KINDS.filter((kind) => grants[kind] !== undefined);
|
|
16097
16680
|
return {
|
|
16098
16681
|
name: entry.name,
|
|
16099
16682
|
glob: entry.glob,
|
|
16100
|
-
grants:
|
|
16101
|
-
configured
|
|
16102
|
-
|
|
16683
|
+
grants: full,
|
|
16684
|
+
configured,
|
|
16685
|
+
...endpointView(entry, {
|
|
16686
|
+
workspace: entry.name,
|
|
16687
|
+
grants: full,
|
|
16688
|
+
configured,
|
|
16689
|
+
accountConfigured: Boolean(entry.vcs?.account)
|
|
16690
|
+
}),
|
|
16103
16691
|
verification: verificationOf(entry)
|
|
16104
16692
|
};
|
|
16105
16693
|
})
|
|
@@ -16114,7 +16702,7 @@ var accountHome = () => {
|
|
|
16114
16702
|
}, grantsHome, grantsDir = () => path18.join(grantsHome.resolve(), ".config", "workit"), grantsOverride = () => {
|
|
16115
16703
|
const configured = path18.resolve(resolveConfigDir());
|
|
16116
16704
|
return configured === path18.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path18.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
16117
|
-
}, GRANT_KINDS, DEFAULT_GRANTS, DEFAULT_ENDPOINT = "commit",
|
|
16705
|
+
}, GRANT_KINDS, DEFAULT_GRANTS, DEFAULT_ENDPOINTS, DEFAULT_ENDPOINT = "commit", isDefaultEndpoint = (value) => typeof value === "string" && DEFAULT_ENDPOINTS.includes(value), raisesEndpoint = (current, next) => DEFAULT_ENDPOINTS.indexOf(next) > DEFAULT_ENDPOINTS.indexOf(current), DEFAULT_VERIFICATION = "self", verificationOf = (entry) => entry?.verification === "independent" ? "independent" : "self", isGrantKind = (value) => typeof value === "string" && GRANT_KINDS.includes(value), isGrantValue = (value) => value === true || value === false || value === "verified", normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value, fromAutoApprove = (value) => {
|
|
16118
16706
|
if (value === true)
|
|
16119
16707
|
return { push: true, pr: true, merge: "verified" };
|
|
16120
16708
|
if (!Array.isArray(value))
|
|
@@ -16126,7 +16714,7 @@ var accountHome = () => {
|
|
|
16126
16714
|
else if (item === "merge")
|
|
16127
16715
|
grants.merge = "verified";
|
|
16128
16716
|
return Object.keys(grants).length > 0 ? grants : null;
|
|
16129
|
-
}, suggested = (kind) => kind === "merge" ? "verified" : "true", grantHint = (workspace, kind) => `ask the user to run, in their own terminal: workit grant set ${workspace ?? "<workspace>"} ${kind}=${suggested(kind)}`, raises = (kind, current, next) => {
|
|
16717
|
+
}, accountOf = (entry) => entry?.vcs?.account, suggested = (kind) => kind === "merge" ? "verified" : "true", grantHint = (workspace, kind) => `ask the user to run, in their own terminal: workit grant set ${workspace ?? "<workspace>"} ${kind}=${suggested(kind)}`, raises = (kind, current, next) => {
|
|
16130
16718
|
const rank = (value) => value === true ? 2 : value === "verified" ? 1 : 0;
|
|
16131
16719
|
return rank(normalized(kind, next)) > rank(normalized(kind, current));
|
|
16132
16720
|
};
|
|
@@ -16143,6 +16731,7 @@ var init_autonomy = __esm(() => {
|
|
|
16143
16731
|
release: false,
|
|
16144
16732
|
rerun: true
|
|
16145
16733
|
});
|
|
16734
|
+
DEFAULT_ENDPOINTS = ["commit", "pr", "green", "merged"];
|
|
16146
16735
|
});
|
|
16147
16736
|
|
|
16148
16737
|
// packages/workit-core/src/core/task-engine.ts
|
|
@@ -17796,7 +18385,7 @@ var init_pr_body = __esm(() => {
|
|
|
17796
18385
|
|
|
17797
18386
|
// packages/workit-core/src/core/pr-create.ts
|
|
17798
18387
|
import path19 from "node:path";
|
|
17799
|
-
import { spawnSync as
|
|
18388
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
17800
18389
|
import { pathToFileURL } from "node:url";
|
|
17801
18390
|
var safePushUrl = (remote) => {
|
|
17802
18391
|
const raw = remote.trim();
|
|
@@ -17824,7 +18413,7 @@ var safePushUrl = (remote) => {
|
|
|
17824
18413
|
const target = safePushUrl(remote);
|
|
17825
18414
|
if (!target)
|
|
17826
18415
|
return false;
|
|
17827
|
-
const result =
|
|
18416
|
+
const result = spawnSync9("git", ["config", "--get-regexp", "^url\\..*\\.(insteadof|pushinsteadof)$"], { cwd, encoding: "utf8" });
|
|
17828
18417
|
if (result.status !== 0 && result.status !== 1)
|
|
17829
18418
|
return false;
|
|
17830
18419
|
const prefixes = (result.stdout ?? "").split(/\r?\n/u).map((line) => line.trim().slice(line.trim().indexOf(" ") + 1)).filter(Boolean);
|
|
@@ -18400,7 +18989,7 @@ var init_core3 = __esm(() => {
|
|
|
18400
18989
|
});
|
|
18401
18990
|
|
|
18402
18991
|
// packages/workit-cli/src/task.ts
|
|
18403
|
-
import { readFileSync as
|
|
18992
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
18404
18993
|
import path22 from "node:path";
|
|
18405
18994
|
async function readInput(input) {
|
|
18406
18995
|
if (typeof input === "string")
|
|
@@ -18417,7 +19006,7 @@ async function payloadValue(raw, deps) {
|
|
|
18417
19006
|
return { ok: true, value: {} };
|
|
18418
19007
|
let source;
|
|
18419
19008
|
try {
|
|
18420
|
-
source = raw === "-" ? await readInput(deps.stdin ?? process.stdin) : raw.startsWith("@") ? decodeUtf8(
|
|
19009
|
+
source = raw === "-" ? await readInput(deps.stdin ?? process.stdin) : raw.startsWith("@") ? decodeUtf8(readFileSync7(raw.slice(1))) : raw;
|
|
18421
19010
|
} catch (error) {
|
|
18422
19011
|
return {
|
|
18423
19012
|
ok: false,
|
|
@@ -18750,7 +19339,7 @@ function isImplicitTaskForm(argv) {
|
|
|
18750
19339
|
const [action, first] = argv;
|
|
18751
19340
|
if (!action)
|
|
18752
19341
|
return false;
|
|
18753
|
-
if (
|
|
19342
|
+
if (IMPLICIT2.has(action))
|
|
18754
19343
|
return true;
|
|
18755
19344
|
if (action === "start")
|
|
18756
19345
|
return first !== undefined && !first.startsWith("--");
|
|
@@ -18948,7 +19537,7 @@ async function run(argv, io) {
|
|
|
18948
19537
|
}
|
|
18949
19538
|
return emit(io, fail("invalid_input", `unknown task action ${action ?? ""}`, { unblock: USAGE }));
|
|
18950
19539
|
}
|
|
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>',
|
|
19540
|
+
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
19541
|
data: { code: result.code },
|
|
18953
19542
|
...unblock ? { unblock } : result.code === "busy" ? { unblock: "retry the same command" } : {}
|
|
18954
19543
|
})), OUTCOMES, rootFor = (io) => io.env.WORKFLOW_WORKSPACE_ROOT || checkRoot(io.cwd);
|
|
@@ -18956,7 +19545,7 @@ var init_task2 = __esm(() => {
|
|
|
18956
19545
|
init_check_config();
|
|
18957
19546
|
init_output();
|
|
18958
19547
|
init_task();
|
|
18959
|
-
|
|
19548
|
+
IMPLICIT2 = new Set(["status", "note", "adopt"]);
|
|
18960
19549
|
VALUE_FLAGS = new Set(["--next", "--objective", "--outcome", "--summary"]);
|
|
18961
19550
|
SWITCHES = new Set(["--all", "--json", "--confirm"]);
|
|
18962
19551
|
ENGINE_CODES = {
|
|
@@ -61542,7 +62131,7 @@ var init_gitignore = __esm(() => {
|
|
|
61542
62131
|
// packages/workit-core/src/core/changelog.ts
|
|
61543
62132
|
import fs16 from "node:fs";
|
|
61544
62133
|
import path23 from "node:path";
|
|
61545
|
-
import { createHash as
|
|
62134
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
61546
62135
|
function normalizeBullet(text) {
|
|
61547
62136
|
text = text.trim();
|
|
61548
62137
|
const m = BULLET_RE.exec(text);
|
|
@@ -61829,7 +62418,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
61829
62418
|
|
|
61830
62419
|
## [Unreleased]
|
|
61831
62420
|
|
|
61832
|
-
`, digestBytes2 = (value) =>
|
|
62421
|
+
`, digestBytes2 = (value) => createHash12("sha256").update(value).digest("hex"), readChangelogSource = (target) => {
|
|
61833
62422
|
if (!fs16.existsSync(target)) {
|
|
61834
62423
|
const bytes = Buffer.from(SKELETON, "utf8");
|
|
61835
62424
|
return { exists: false, bytes, text: SKELETON };
|
|
@@ -61869,13 +62458,13 @@ var init_changelog = __esm(() => {
|
|
|
61869
62458
|
});
|
|
61870
62459
|
|
|
61871
62460
|
// packages/workit-core/src/core/hygiene.ts
|
|
61872
|
-
import { existsSync as existsSync9, readFileSync as
|
|
62461
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "node:fs";
|
|
61873
62462
|
import path24 from "node:path";
|
|
61874
62463
|
var repoRoot2, templatesDir = () => path24.join(repoRoot2, "templates", "hygiene"), packageJson = (root) => {
|
|
61875
62464
|
if (!existsSync9(path24.join(root, "package.json")))
|
|
61876
62465
|
return null;
|
|
61877
62466
|
try {
|
|
61878
|
-
return JSON.parse(
|
|
62467
|
+
return JSON.parse(readFileSync9(path24.join(root, "package.json"), "utf8"));
|
|
61879
62468
|
} catch {
|
|
61880
62469
|
return null;
|
|
61881
62470
|
}
|
|
@@ -61911,7 +62500,7 @@ var repoRoot2, templatesDir = () => path24.join(repoRoot2, "templates", "hygiene
|
|
|
61911
62500
|
const tpl = path24.join(templatesDir(), file);
|
|
61912
62501
|
if (!existsSync9(tpl))
|
|
61913
62502
|
continue;
|
|
61914
|
-
const content =
|
|
62503
|
+
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
62504
|
planned.push({ path: path24.join(root, file), content });
|
|
61916
62505
|
}
|
|
61917
62506
|
return planned;
|
|
@@ -61923,13 +62512,13 @@ var init_hygiene = __esm(() => {
|
|
|
61923
62512
|
});
|
|
61924
62513
|
|
|
61925
62514
|
// packages/workit-cli/src/admin/setup-state.ts
|
|
61926
|
-
import { existsSync as existsSync10, readFileSync as
|
|
62515
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
|
|
61927
62516
|
import path25 from "node:path";
|
|
61928
62517
|
var classifySetupFile = (dir, name) => {
|
|
61929
62518
|
const file = path25.join(dir, name);
|
|
61930
62519
|
let raw;
|
|
61931
62520
|
try {
|
|
61932
|
-
raw =
|
|
62521
|
+
raw = readFileSync10(file, "utf8");
|
|
61933
62522
|
} catch {
|
|
61934
62523
|
if (existsSync10(file)) {
|
|
61935
62524
|
return { file, status: "malformed", error: `${file} is not readable` };
|
|
@@ -61978,7 +62567,7 @@ function mergeOpenCodePlugins(plugin, pin) {
|
|
|
61978
62567
|
return { config, changed };
|
|
61979
62568
|
}
|
|
61980
62569
|
function mergeOpenCodeConfig(config, pin) {
|
|
61981
|
-
const base =
|
|
62570
|
+
const base = isRecord4(config) ? { ...config } : {};
|
|
61982
62571
|
const changed = [];
|
|
61983
62572
|
const plugins = mergeOpenCodePlugins(base.plugin, pin);
|
|
61984
62573
|
if (plugins.changed.length > 0) {
|
|
@@ -61988,7 +62577,7 @@ function mergeOpenCodeConfig(config, pin) {
|
|
|
61988
62577
|
return { config: base, changed };
|
|
61989
62578
|
}
|
|
61990
62579
|
function mergeCursorEnabledPlugins(enabled) {
|
|
61991
|
-
const prev =
|
|
62580
|
+
const prev = isRecord4(enabled) ? { ...enabled } : {};
|
|
61992
62581
|
const next = { ...prev, workit: true };
|
|
61993
62582
|
delete next["workflow-toolkit"];
|
|
61994
62583
|
delete next["local/workflow-toolkit"];
|
|
@@ -62010,7 +62599,7 @@ function mergeCursorPluginDirs(pluginDirs, pluginDir) {
|
|
|
62010
62599
|
return { config: next, changed };
|
|
62011
62600
|
}
|
|
62012
62601
|
function mergeCursorSettings(settings, pluginDir) {
|
|
62013
|
-
const base =
|
|
62602
|
+
const base = isRecord4(settings) ? { ...settings } : {};
|
|
62014
62603
|
const changed = [];
|
|
62015
62604
|
const enabled = mergeCursorEnabledPlugins(base.enabled_plugins);
|
|
62016
62605
|
if (enabled.changed.length > 0) {
|
|
@@ -62025,8 +62614,8 @@ function mergeCursorSettings(settings, pluginDir) {
|
|
|
62025
62614
|
return { config: base, changed };
|
|
62026
62615
|
}
|
|
62027
62616
|
function mergeCursorMcp(mcp, serverName, server) {
|
|
62028
|
-
const base =
|
|
62029
|
-
const servers =
|
|
62617
|
+
const base = isRecord4(mcp) ? { ...mcp } : {};
|
|
62618
|
+
const servers = isRecord4(base.mcpServers) ? { ...base.mcpServers } : {};
|
|
62030
62619
|
delete servers["workflow-toolkit"];
|
|
62031
62620
|
servers[serverName] = server;
|
|
62032
62621
|
const changed = JSON.stringify(servers) !== JSON.stringify(base.mcpServers) ? ["mcpServers"] : [];
|
|
@@ -62034,7 +62623,7 @@ function mergeCursorMcp(mcp, serverName, server) {
|
|
|
62034
62623
|
return { config: base, changed };
|
|
62035
62624
|
}
|
|
62036
62625
|
function cursorHookDrift(installed) {
|
|
62037
|
-
if (!
|
|
62626
|
+
if (!isRecord4(installed) || !isRecord4(installed.hooks))
|
|
62038
62627
|
return ["hooks file is not a hook map"];
|
|
62039
62628
|
const hooks = installed.hooks;
|
|
62040
62629
|
const drift = [];
|
|
@@ -62044,7 +62633,7 @@ function cursorHookDrift(installed) {
|
|
|
62044
62633
|
continue;
|
|
62045
62634
|
const canonical = canonicalHookEntry(event);
|
|
62046
62635
|
const entry = Array.isArray(list) ? list[0] : undefined;
|
|
62047
|
-
if (!
|
|
62636
|
+
if (!isRecord4(entry) || entry.command !== canonical.command || event === "preToolUse" && entry.matcher !== canonical.matcher)
|
|
62048
62637
|
drift.push(event);
|
|
62049
62638
|
}
|
|
62050
62639
|
return drift;
|
|
@@ -62068,7 +62657,7 @@ function cursorHooksEntry(_packageDir) {
|
|
|
62068
62657
|
args: []
|
|
62069
62658
|
};
|
|
62070
62659
|
}
|
|
62071
|
-
var OPENCODE_NPM_PIN = "@brainervirus/workit-opencode",
|
|
62660
|
+
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
62661
|
var init_registration = __esm(() => {
|
|
62073
62662
|
CURSOR_HOOK_RUN_COMMAND = `npx -y --prefer-online --min-release-age=0 --package=${CURSOR_RUNTIME_PACKAGE} workit-cursor-hook`;
|
|
62074
62663
|
});
|
|
@@ -62087,12 +62676,12 @@ var init_support_matrix = __esm(() => {
|
|
|
62087
62676
|
});
|
|
62088
62677
|
|
|
62089
62678
|
// packages/workit-cli/src/admin/host-install.ts
|
|
62090
|
-
import { spawnSync as
|
|
62679
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
62091
62680
|
import {
|
|
62092
62681
|
accessSync,
|
|
62093
62682
|
constants as constants2,
|
|
62094
62683
|
existsSync as existsSync11,
|
|
62095
|
-
readFileSync as
|
|
62684
|
+
readFileSync as readFileSync11,
|
|
62096
62685
|
readdirSync as readdirSync4,
|
|
62097
62686
|
realpathSync as realpathSync6,
|
|
62098
62687
|
statSync as statSync2
|
|
@@ -62358,7 +62947,7 @@ function runHostCommand(step, context = {}) {
|
|
|
62358
62947
|
stderr: `Cannot safely execute batch shim ${step.command}; resolve its Node.js CLI entrypoint and retry`
|
|
62359
62948
|
};
|
|
62360
62949
|
}
|
|
62361
|
-
const result =
|
|
62950
|
+
const result = spawnSync10(step.command, step.args, {
|
|
62362
62951
|
cwd: step.cwd,
|
|
62363
62952
|
env: (() => {
|
|
62364
62953
|
const home = context.home ?? context.env?.HOME ?? os6.homedir();
|
|
@@ -62382,7 +62971,7 @@ function runHostCommand(step, context = {}) {
|
|
|
62382
62971
|
}
|
|
62383
62972
|
var resolveWindowsShimScript = (shim) => {
|
|
62384
62973
|
try {
|
|
62385
|
-
const contents =
|
|
62974
|
+
const contents = readFileSync11(shim, "utf8");
|
|
62386
62975
|
return resolveWindowsShimEntry(contents, shim);
|
|
62387
62976
|
} catch {
|
|
62388
62977
|
return null;
|
|
@@ -62403,7 +62992,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62403
62992
|
}, isPiWorkitInstalled = (home, env = process.env) => {
|
|
62404
62993
|
const settings = path27.join(env.PI_CODING_AGENT_DIR ?? path27.join(home, ".pi", "agent"), "settings.json");
|
|
62405
62994
|
try {
|
|
62406
|
-
const document2 = JSON.parse(
|
|
62995
|
+
const document2 = JSON.parse(readFileSync11(settings, "utf8"));
|
|
62407
62996
|
return (document2.packages ?? []).some((entry) => {
|
|
62408
62997
|
const source = entry && typeof entry === "object" && !Array.isArray(entry) ? entry.source : entry;
|
|
62409
62998
|
const value = String(source).replaceAll("\\", "/").replace(/\/+$/, "");
|
|
@@ -62418,7 +63007,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62418
63007
|
path27.join(root, "package.json")
|
|
62419
63008
|
]) {
|
|
62420
63009
|
try {
|
|
62421
|
-
const manifest = JSON.parse(
|
|
63010
|
+
const manifest = JSON.parse(readFileSync11(file, "utf8"));
|
|
62422
63011
|
const repository = typeof manifest.repository === "string" ? manifest.repository : manifest.repository?.url;
|
|
62423
63012
|
if ((manifest.name === "workit" || manifest.name === "@brainervirus/workit-codex") && repository?.replace(/\.git$/, "").toLowerCase() === "https://github.com/brainervirus/workit")
|
|
62424
63013
|
return true;
|
|
@@ -62459,7 +63048,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62459
63048
|
return relative === "" || !relative.startsWith("..") && !path27.isAbsolute(relative);
|
|
62460
63049
|
}, isCanonicalClaudePlugin = (root) => {
|
|
62461
63050
|
try {
|
|
62462
|
-
const manifest = JSON.parse(
|
|
63051
|
+
const manifest = JSON.parse(readFileSync11(path27.join(root, ".claude-plugin", "plugin.json"), "utf8"));
|
|
62463
63052
|
const repository = typeof manifest.repository === "string" ? manifest.repository : manifest.repository?.url;
|
|
62464
63053
|
return manifest.name === "workit" && repository?.replace(/\.git$/, "").toLowerCase() === "https://github.com/brainervirus/workit";
|
|
62465
63054
|
} catch {
|
|
@@ -62469,7 +63058,7 @@ var resolveWindowsShimScript = (shim) => {
|
|
|
62469
63058
|
const file = path27.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json");
|
|
62470
63059
|
let registry;
|
|
62471
63060
|
try {
|
|
62472
|
-
registry = JSON.parse(
|
|
63061
|
+
registry = JSON.parse(readFileSync11(file, "utf8"));
|
|
62473
63062
|
} catch {
|
|
62474
63063
|
return [];
|
|
62475
63064
|
}
|
|
@@ -62518,7 +63107,7 @@ var init_host_install = __esm(() => {
|
|
|
62518
63107
|
});
|
|
62519
63108
|
|
|
62520
63109
|
// packages/workit-core/src/core/skill-manifests.ts
|
|
62521
|
-
import { existsSync as existsSync12, readFileSync as
|
|
63110
|
+
import { existsSync as existsSync12, readFileSync as readFileSync12, readdirSync as readdirSync5, statSync as statSync3 } from "node:fs";
|
|
62522
63111
|
import path28 from "node:path";
|
|
62523
63112
|
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
63113
|
const actual = skillManifestNames(root);
|
|
@@ -62536,7 +63125,7 @@ var WORKIT_METHOD_SKILLS, skillManifestNames = (root) => existsSync12(root) ? re
|
|
|
62536
63125
|
const file = path28.join(dir, entry.name);
|
|
62537
63126
|
if (entry.isDirectory())
|
|
62538
63127
|
pending.push(file);
|
|
62539
|
-
else if ((statSync3(file).mode & 73) !== 0 ||
|
|
63128
|
+
else if ((statSync3(file).mode & 73) !== 0 || readFileSync12(file).subarray(0, 2).toString("latin1") === "#!") {
|
|
62540
63129
|
return `Cursor vendor contains active file: ${file}`;
|
|
62541
63130
|
}
|
|
62542
63131
|
}
|
|
@@ -62561,13 +63150,13 @@ var init_skill_manifests = __esm(() => {
|
|
|
62561
63150
|
});
|
|
62562
63151
|
|
|
62563
63152
|
// packages/workit-cli/src/admin/doctor.ts
|
|
62564
|
-
import { spawnSync as
|
|
63153
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
62565
63154
|
import {
|
|
62566
63155
|
existsSync as existsSync13,
|
|
62567
63156
|
lstatSync as lstatSync4,
|
|
62568
63157
|
mkdirSync as mkdirSync4,
|
|
62569
63158
|
mkdtempSync,
|
|
62570
|
-
readFileSync as
|
|
63159
|
+
readFileSync as readFileSync13,
|
|
62571
63160
|
readlinkSync as readlinkSync2,
|
|
62572
63161
|
rmSync as rmSync2,
|
|
62573
63162
|
statSync as statSync4,
|
|
@@ -62611,14 +63200,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
62611
63200
|
};
|
|
62612
63201
|
}, readJson = (p) => {
|
|
62613
63202
|
try {
|
|
62614
|
-
const parsed = JSON.parse(
|
|
63203
|
+
const parsed = JSON.parse(readFileSync13(p, "utf8"));
|
|
62615
63204
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
62616
63205
|
} catch {
|
|
62617
63206
|
return null;
|
|
62618
63207
|
}
|
|
62619
63208
|
}, parsesAsConfigObject = (p) => {
|
|
62620
63209
|
try {
|
|
62621
|
-
return isConfigObject(JSON.parse(
|
|
63210
|
+
return isConfigObject(JSON.parse(readFileSync13(p, "utf8")));
|
|
62622
63211
|
} catch {
|
|
62623
63212
|
return false;
|
|
62624
63213
|
}
|
|
@@ -62645,7 +63234,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
62645
63234
|
}
|
|
62646
63235
|
return false;
|
|
62647
63236
|
}, versionOf = (bin, env, timeout) => {
|
|
62648
|
-
const r =
|
|
63237
|
+
const r = spawnSync11(bin, ["--version"], { encoding: "utf8", env, timeout });
|
|
62649
63238
|
if (r.error)
|
|
62650
63239
|
return null;
|
|
62651
63240
|
return (r.stdout ?? "").trim();
|
|
@@ -62890,11 +63479,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
62890
63479
|
}, validNodeEntry = (entry, runtime, env) => {
|
|
62891
63480
|
try {
|
|
62892
63481
|
const stat = statSync4(entry);
|
|
62893
|
-
if (!stat.isFile() || stat.size === 0 || !
|
|
63482
|
+
if (!stat.isFile() || stat.size === 0 || !readFileSync13(entry, "utf8").startsWith(`#!/usr/bin/env node
|
|
62894
63483
|
`)) {
|
|
62895
63484
|
return false;
|
|
62896
63485
|
}
|
|
62897
|
-
return
|
|
63486
|
+
return spawnSync11(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
|
|
62898
63487
|
} catch {
|
|
62899
63488
|
return false;
|
|
62900
63489
|
}
|
|
@@ -63108,7 +63697,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63108
63697
|
if (!cmd)
|
|
63109
63698
|
return null;
|
|
63110
63699
|
try {
|
|
63111
|
-
const r =
|
|
63700
|
+
const r = spawnSync11(cmd, ["view", pkgName, "version"], {
|
|
63112
63701
|
encoding: "utf8",
|
|
63113
63702
|
timeout: 20000,
|
|
63114
63703
|
env: res.env
|
|
@@ -63419,12 +64008,27 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63419
64008
|
fix: `Choose a matching workspace with WORKFLOW_WORKSPACE_NAME or repair ${file}`
|
|
63420
64009
|
};
|
|
63421
64010
|
}
|
|
63422
|
-
if (match)
|
|
63423
|
-
|
|
63424
|
-
|
|
63425
|
-
|
|
63426
|
-
|
|
63427
|
-
|
|
64011
|
+
if (match) {
|
|
64012
|
+
const matched = `current directory matches workspace "${match.name}"`;
|
|
64013
|
+
const tracks = releaseTracksReport(res.cwd);
|
|
64014
|
+
const lines = describeReleaseTracks(tracks);
|
|
64015
|
+
const detail = [matched, ...lines].join("; ");
|
|
64016
|
+
if (tracks.error)
|
|
64017
|
+
return {
|
|
64018
|
+
id: "workspace_mismatch",
|
|
64019
|
+
status: "fail",
|
|
64020
|
+
detail,
|
|
64021
|
+
fix: `Repair releaseTracks in ${file} (or upgrade Workit for a critical field)`
|
|
64022
|
+
};
|
|
64023
|
+
if (tracks.warnings.length)
|
|
64024
|
+
return {
|
|
64025
|
+
id: "workspace_mismatch",
|
|
64026
|
+
status: "warn",
|
|
64027
|
+
detail,
|
|
64028
|
+
fix: `Fix the reported releaseTracks fields in ${file}, or pass --track <name> where the track is not determined`
|
|
64029
|
+
};
|
|
64030
|
+
return { id: "workspace_mismatch", status: "pass", detail };
|
|
64031
|
+
}
|
|
63428
64032
|
return {
|
|
63429
64033
|
id: "workspace_mismatch",
|
|
63430
64034
|
status: "fail",
|
|
@@ -63433,7 +64037,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63433
64037
|
};
|
|
63434
64038
|
}, isPlaceholder = (p) => {
|
|
63435
64039
|
try {
|
|
63436
|
-
return
|
|
64040
|
+
return readFileSync13(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
|
|
63437
64041
|
} catch {
|
|
63438
64042
|
return false;
|
|
63439
64043
|
}
|
|
@@ -63522,7 +64126,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63522
64126
|
}, defaultIdentityProbes = (env) => ({
|
|
63523
64127
|
origin: (cwd) => {
|
|
63524
64128
|
try {
|
|
63525
|
-
const out =
|
|
64129
|
+
const out = spawnSync11("git", ["remote", "get-url", "origin"], {
|
|
63526
64130
|
cwd,
|
|
63527
64131
|
encoding: "utf8",
|
|
63528
64132
|
env
|
|
@@ -63534,7 +64138,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63534
64138
|
},
|
|
63535
64139
|
ghLogin: (e) => {
|
|
63536
64140
|
try {
|
|
63537
|
-
const out =
|
|
64141
|
+
const out = spawnSync11("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
|
|
63538
64142
|
const login = (out.stdout ?? "").trim();
|
|
63539
64143
|
return out.status === 0 && login ? login : null;
|
|
63540
64144
|
} catch {
|
|
@@ -63543,7 +64147,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63543
64147
|
},
|
|
63544
64148
|
glabLogin: (e) => {
|
|
63545
64149
|
try {
|
|
63546
|
-
const out =
|
|
64150
|
+
const out = spawnSync11("glab", ["api", "user", "--jq", ".username"], {
|
|
63547
64151
|
encoding: "utf8",
|
|
63548
64152
|
env: e
|
|
63549
64153
|
});
|
|
@@ -63555,7 +64159,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63555
64159
|
},
|
|
63556
64160
|
sshLogin: (host) => {
|
|
63557
64161
|
try {
|
|
63558
|
-
const out =
|
|
64162
|
+
const out = spawnSync11("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
|
|
63559
64163
|
encoding: "utf8",
|
|
63560
64164
|
env
|
|
63561
64165
|
});
|
|
@@ -63749,6 +64353,7 @@ var init_doctor = __esm(() => {
|
|
|
63749
64353
|
init_store_lock();
|
|
63750
64354
|
init_runtime_identity();
|
|
63751
64355
|
init_boundary();
|
|
64356
|
+
init_release_tracks();
|
|
63752
64357
|
init_config();
|
|
63753
64358
|
init_package_root();
|
|
63754
64359
|
init_registration();
|
|
@@ -63797,7 +64402,7 @@ import {
|
|
|
63797
64402
|
lstatSync as lstatSync5,
|
|
63798
64403
|
mkdirSync as mkdirSync5,
|
|
63799
64404
|
mkdtempSync as mkdtempSync2,
|
|
63800
|
-
readFileSync as
|
|
64405
|
+
readFileSync as readFileSync14,
|
|
63801
64406
|
readdirSync as readdirSync6,
|
|
63802
64407
|
realpathSync as realpathSync7,
|
|
63803
64408
|
renameSync as renameSync3,
|
|
@@ -63966,7 +64571,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
63966
64571
|
if (values.applyProject) {
|
|
63967
64572
|
const root = path30.resolve(opts.cwd ?? process.cwd());
|
|
63968
64573
|
const gitignorePath = path30.join(root, ".gitignore");
|
|
63969
|
-
const existing = existsSync14(gitignorePath) ?
|
|
64574
|
+
const existing = existsSync14(gitignorePath) ? readFileSync14(gitignorePath, "utf8") : "";
|
|
63970
64575
|
const existingLines = new Set(existing.split(`
|
|
63971
64576
|
`).map((l) => l.trim()).filter(Boolean));
|
|
63972
64577
|
const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
|
|
@@ -63997,7 +64602,7 @@ function deepMerge(base, patch) {
|
|
|
63997
64602
|
const out = { ...base };
|
|
63998
64603
|
for (const [key, value] of Object.entries(patch)) {
|
|
63999
64604
|
const prev = out[key];
|
|
64000
|
-
out[key] =
|
|
64605
|
+
out[key] = isRecord5(prev) && isRecord5(value) ? deepMerge(prev, value) : value;
|
|
64001
64606
|
}
|
|
64002
64607
|
return out;
|
|
64003
64608
|
}
|
|
@@ -64324,8 +64929,8 @@ function applyCursorMcp(root, res) {
|
|
|
64324
64929
|
}
|
|
64325
64930
|
const mcpBase = mcpExisting.kind === "record" ? mcpExisting.value : {};
|
|
64326
64931
|
const server = cursorMcpServerEntry(res.cursorPluginDir);
|
|
64327
|
-
const servers =
|
|
64328
|
-
const current =
|
|
64932
|
+
const servers = isRecord5(mcpBase.mcpServers) ? mcpBase.mcpServers : {};
|
|
64933
|
+
const current = isRecord5(servers.workit) ? servers.workit : {};
|
|
64329
64934
|
const previousArgs = Array.isArray(current.args) ? current.args.map(String) : [];
|
|
64330
64935
|
const previousPackage = previousArgs.find((arg) => arg.startsWith("--package=@brainervirus/workit-cursor@") && arg !== `--package=${CURSOR_RUNTIME_PACKAGE}`);
|
|
64331
64936
|
if (previousPackage) {
|
|
@@ -64586,7 +65191,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64586
65191
|
}, configuredTokenPath = (config, ...keys) => {
|
|
64587
65192
|
let cursor = config;
|
|
64588
65193
|
for (const key of keys) {
|
|
64589
|
-
if (!
|
|
65194
|
+
if (!isRecord5(cursor))
|
|
64590
65195
|
return null;
|
|
64591
65196
|
cursor = cursor[key];
|
|
64592
65197
|
}
|
|
@@ -64599,8 +65204,8 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64599
65204
|
return configured ?? fallback;
|
|
64600
65205
|
}, readConfigRecord = (file) => {
|
|
64601
65206
|
try {
|
|
64602
|
-
const value = JSON.parse(
|
|
64603
|
-
return
|
|
65207
|
+
const value = JSON.parse(readFileSync14(file, "utf8"));
|
|
65208
|
+
return isRecord5(value) ? value : null;
|
|
64604
65209
|
} catch {
|
|
64605
65210
|
return null;
|
|
64606
65211
|
}
|
|
@@ -64617,10 +65222,10 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64617
65222
|
cursorMcp: options.cursorMcp ?? path30.join(home, ".cursor", "mcp.json"),
|
|
64618
65223
|
cursorPluginDir: options.cursorPluginDir ?? path30.join(home, ".cursor", "plugins", "local", "workit")
|
|
64619
65224
|
};
|
|
64620
|
-
},
|
|
65225
|
+
}, isRecord5 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
|
|
64621
65226
|
let raw;
|
|
64622
65227
|
try {
|
|
64623
|
-
raw =
|
|
65228
|
+
raw = readFileSync14(p, "utf8");
|
|
64624
65229
|
} catch {
|
|
64625
65230
|
if (existsSync14(p))
|
|
64626
65231
|
return { kind: "malformed", error: `${p} is not readable` };
|
|
@@ -64632,12 +65237,12 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64632
65237
|
} catch {
|
|
64633
65238
|
return { kind: "malformed", error: `${p} is not valid JSON` };
|
|
64634
65239
|
}
|
|
64635
|
-
if (
|
|
65240
|
+
if (isRecord5(value))
|
|
64636
65241
|
return { kind: "record", value, raw };
|
|
64637
65242
|
return { kind: "malformed", error: `${p} is not a JSON object` };
|
|
64638
65243
|
}, readFileSafe = (p) => {
|
|
64639
65244
|
try {
|
|
64640
|
-
return
|
|
65245
|
+
return readFileSync14(p, "utf8");
|
|
64641
65246
|
} catch {
|
|
64642
65247
|
return null;
|
|
64643
65248
|
}
|
|
@@ -64652,7 +65257,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64652
65257
|
}
|
|
64653
65258
|
}, isAdapter = (root, platform) => {
|
|
64654
65259
|
try {
|
|
64655
|
-
const pkg = JSON.parse(
|
|
65260
|
+
const pkg = JSON.parse(readFileSync14(path30.join(root, "package.json"), "utf8"));
|
|
64656
65261
|
return pkg.name === `@brainervirus/workit-${platform}`;
|
|
64657
65262
|
} catch {
|
|
64658
65263
|
return false;
|
|
@@ -64681,7 +65286,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64681
65286
|
if (entry.isDirectory()) {
|
|
64682
65287
|
if (!statSync5(installed).isDirectory() || !samePluginContent(source, installed, path30.join(relative, entry.name)))
|
|
64683
65288
|
return false;
|
|
64684
|
-
} else if (!
|
|
65289
|
+
} else if (!readFileSync14(source).equals(readFileSync14(installed))) {
|
|
64685
65290
|
return false;
|
|
64686
65291
|
}
|
|
64687
65292
|
}
|
|
@@ -64709,7 +65314,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
64709
65314
|
continue;
|
|
64710
65315
|
if (existsSync14(path30.join(sourceRules, entry.name)))
|
|
64711
65316
|
continue;
|
|
64712
|
-
preserved.set(entry.name,
|
|
65317
|
+
preserved.set(entry.name, readFileSync14(path30.join(installedRules, entry.name)));
|
|
64713
65318
|
}
|
|
64714
65319
|
} catch {}
|
|
64715
65320
|
return preserved;
|
|
@@ -64763,10 +65368,10 @@ var init_setup = __esm(() => {
|
|
|
64763
65368
|
});
|
|
64764
65369
|
|
|
64765
65370
|
// packages/workit-core/src/core/branch-policy.ts
|
|
64766
|
-
import { spawnSync as
|
|
65371
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
64767
65372
|
var PREFIXES, detectBranchPolicy = (workspaceRoot) => {
|
|
64768
65373
|
const branchExists = (name) => {
|
|
64769
|
-
const r =
|
|
65374
|
+
const r = spawnSync12("git", ["branch", "--list", name], {
|
|
64770
65375
|
cwd: workspaceRoot,
|
|
64771
65376
|
encoding: "utf8"
|
|
64772
65377
|
});
|
|
@@ -64826,7 +65431,7 @@ var init_branch_policy = __esm(() => {
|
|
|
64826
65431
|
});
|
|
64827
65432
|
|
|
64828
65433
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
64829
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
65434
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
64830
65435
|
import path31 from "node:path";
|
|
64831
65436
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
|
|
64832
65437
|
function applyWorkspaceBranchPolicy(opts) {
|
|
@@ -64924,7 +65529,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
64924
65529
|
}
|
|
64925
65530
|
var readFileSafe2 = (p) => {
|
|
64926
65531
|
try {
|
|
64927
|
-
return
|
|
65532
|
+
return readFileSync15(p, "utf8");
|
|
64928
65533
|
} catch {
|
|
64929
65534
|
return null;
|
|
64930
65535
|
}
|
|
@@ -65103,17 +65708,18 @@ function setProfileEditorValue(profile, field, value, defaults = {}) {
|
|
|
65103
65708
|
};
|
|
65104
65709
|
}
|
|
65105
65710
|
function trackEditorValue(track, field) {
|
|
65711
|
+
const source = track.versionSource ?? { kind: "git-tag" };
|
|
65106
65712
|
if (field.startsWith("naming."))
|
|
65107
|
-
return track.naming[field.slice(7)];
|
|
65713
|
+
return track.naming?.[field.slice(7)] ?? "";
|
|
65108
65714
|
if (field === "mergeBackBranches" || field === "requiredChecks")
|
|
65109
|
-
return track[field].join(", ");
|
|
65715
|
+
return (track[field] ?? []).join(", ");
|
|
65110
65716
|
if (field.startsWith("versionSource.")) {
|
|
65111
65717
|
const key = field.slice(14);
|
|
65112
65718
|
if (key === "kind")
|
|
65113
|
-
return
|
|
65719
|
+
return source.kind;
|
|
65114
65720
|
if (key === "path")
|
|
65115
|
-
return
|
|
65116
|
-
return
|
|
65721
|
+
return source.kind === "package-json" ? source.path : "";
|
|
65722
|
+
return source.kind === "package-json" ? source.field : "";
|
|
65117
65723
|
}
|
|
65118
65724
|
return String(track[field] ?? "");
|
|
65119
65725
|
}
|
|
@@ -65123,12 +65729,13 @@ function setTrackEditorValue(track, field, value) {
|
|
|
65123
65729
|
if (field === "mergeBackBranches" || field === "requiredChecks")
|
|
65124
65730
|
return { ...track, [field]: splitList(value) };
|
|
65125
65731
|
if (field.startsWith("versionSource.")) {
|
|
65732
|
+
const current = track.versionSource ?? { kind: "git-tag" };
|
|
65126
65733
|
const key = field.slice(14);
|
|
65127
|
-
const kind = key === "kind" ? value :
|
|
65734
|
+
const kind = key === "kind" ? value : current.kind;
|
|
65128
65735
|
const versionSource = kind === "package-json" ? {
|
|
65129
65736
|
kind,
|
|
65130
|
-
path: key === "path" ? value :
|
|
65131
|
-
field: key === "field" ? value :
|
|
65737
|
+
path: key === "path" ? value : current.kind === kind ? current.path : "package.json",
|
|
65738
|
+
field: key === "field" ? value : current.kind === kind ? current.field : "version"
|
|
65132
65739
|
} : kind === "manual" ? { kind } : { kind: "git-tag" };
|
|
65133
65740
|
return { ...track, versionSource };
|
|
65134
65741
|
}
|
|
@@ -65762,13 +66369,13 @@ var init_wizard_state = __esm(() => {
|
|
|
65762
66369
|
});
|
|
65763
66370
|
|
|
65764
66371
|
// packages/workit-cli/src/admin/uninstall.ts
|
|
65765
|
-
import { existsSync as existsSync16, readFileSync as
|
|
66372
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16, realpathSync as realpathSync8, rmSync as rmSync5, writeFileSync as writeFileSync8 } from "node:fs";
|
|
65766
66373
|
import os9 from "node:os";
|
|
65767
66374
|
import path33 from "node:path";
|
|
65768
66375
|
function cleanCursorSettings(settings, pluginDir) {
|
|
65769
66376
|
const next = { ...settings };
|
|
65770
66377
|
let changed = false;
|
|
65771
|
-
if (
|
|
66378
|
+
if (isRecord6(next.enabled_plugins)) {
|
|
65772
66379
|
const enabled = { ...next.enabled_plugins };
|
|
65773
66380
|
for (const identity of ["workit", ...CURSOR_LEGACY_IDENTITIES]) {
|
|
65774
66381
|
if (identity in enabled) {
|
|
@@ -65809,7 +66416,7 @@ function cleanOpenCodeConfig(config) {
|
|
|
65809
66416
|
function cleanCursorMcp(mcp) {
|
|
65810
66417
|
const next = { ...mcp };
|
|
65811
66418
|
let changed = false;
|
|
65812
|
-
if (
|
|
66419
|
+
if (isRecord6(next.mcpServers)) {
|
|
65813
66420
|
const servers = { ...next.mcpServers };
|
|
65814
66421
|
for (const name of ["workit", "workflow-toolkit"]) {
|
|
65815
66422
|
if (name in servers) {
|
|
@@ -65834,7 +66441,7 @@ function cleanPiConfig(config) {
|
|
|
65834
66441
|
changed = true;
|
|
65835
66442
|
}
|
|
65836
66443
|
}
|
|
65837
|
-
const pi =
|
|
66444
|
+
const pi = isRecord6(next.pi) ? { ...next.pi } : null;
|
|
65838
66445
|
if (pi && Array.isArray(pi.extensions)) {
|
|
65839
66446
|
const kept = pi.extensions.filter((entry) => !String(entry).includes("workit"));
|
|
65840
66447
|
if (kept.length !== pi.extensions.length) {
|
|
@@ -65982,10 +66589,10 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
65982
66589
|
codexPluginDir: path33.join(home, ".codex", "plugins", "workit"),
|
|
65983
66590
|
piConfig: path33.join(home, ".pi", "config.json")
|
|
65984
66591
|
};
|
|
65985
|
-
},
|
|
66592
|
+
}, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
|
|
65986
66593
|
let raw;
|
|
65987
66594
|
try {
|
|
65988
|
-
raw =
|
|
66595
|
+
raw = readFileSync16(file, "utf8");
|
|
65989
66596
|
} catch {
|
|
65990
66597
|
if (existsSync16(file))
|
|
65991
66598
|
return { kind: "malformed", error: `${file} is not readable` };
|
|
@@ -65993,7 +66600,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
65993
66600
|
}
|
|
65994
66601
|
try {
|
|
65995
66602
|
const value = JSON.parse(raw);
|
|
65996
|
-
return
|
|
66603
|
+
return isRecord6(value) ? { kind: "record", value } : { kind: "malformed", error: `${file} is not a JSON object` };
|
|
65997
66604
|
} catch {
|
|
65998
66605
|
return { kind: "malformed", error: `${file} is not valid JSON` };
|
|
65999
66606
|
}
|
|
@@ -66035,7 +66642,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
66035
66642
|
`;
|
|
66036
66643
|
let current;
|
|
66037
66644
|
try {
|
|
66038
|
-
current =
|
|
66645
|
+
current = readFileSync16(target, "utf8");
|
|
66039
66646
|
} catch (error) {
|
|
66040
66647
|
return {
|
|
66041
66648
|
status: "failed",
|
|
@@ -68305,7 +68912,7 @@ var init_steps = __esm(async () => {
|
|
|
68305
68912
|
import { appendFileSync, mkdirSync as mkdirSync7, readdirSync as readdirSync7, unlinkSync as unlinkSync3 } from "node:fs";
|
|
68306
68913
|
import os11 from "node:os";
|
|
68307
68914
|
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,
|
|
68915
|
+
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
68916
|
const override = process.env.WORKFLOW_TOOLKIT_STATE;
|
|
68310
68917
|
if (override)
|
|
68311
68918
|
return override;
|
|
@@ -68507,7 +69114,7 @@ var init_logger = __esm(() => {
|
|
|
68507
69114
|
"query"
|
|
68508
69115
|
]);
|
|
68509
69116
|
STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
68510
|
-
homePattern = new RegExp(`${
|
|
69117
|
+
homePattern = new RegExp(`${escapeRegExp3(os11.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
68511
69118
|
DEFAULT_OPTIONS = {
|
|
68512
69119
|
maxFieldLength: DEFAULT_MAX_FIELD_LENGTH,
|
|
68513
69120
|
maxStackLines: DEFAULT_MAX_STACK_LINES
|
|
@@ -68772,12 +69379,12 @@ var init_init = __esm(() => {
|
|
|
68772
69379
|
});
|
|
68773
69380
|
|
|
68774
69381
|
// packages/workit-cli/src/upgrade.ts
|
|
68775
|
-
import { spawnSync as
|
|
69382
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
68776
69383
|
import {
|
|
68777
69384
|
existsSync as existsSync17,
|
|
68778
69385
|
mkdtempSync as mkdtempSync3,
|
|
68779
69386
|
rmSync as rmSync6,
|
|
68780
|
-
readFileSync as
|
|
69387
|
+
readFileSync as readFileSync17,
|
|
68781
69388
|
mkdirSync as mkdirSync8,
|
|
68782
69389
|
copyFileSync as copyFileSync5,
|
|
68783
69390
|
chmodSync,
|
|
@@ -68786,7 +69393,7 @@ import {
|
|
|
68786
69393
|
} from "node:fs";
|
|
68787
69394
|
import path35 from "node:path";
|
|
68788
69395
|
import os12 from "node:os";
|
|
68789
|
-
import { createHash as
|
|
69396
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
68790
69397
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
68791
69398
|
const paths = upgradePaths(deps);
|
|
68792
69399
|
const { home, configDir } = paths;
|
|
@@ -68914,7 +69521,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
68914
69521
|
mkdirSync8(backup, { recursive: true, mode: 448 });
|
|
68915
69522
|
for (const file of Object.keys(plan.configDigests))
|
|
68916
69523
|
if (existsSync17(file)) {
|
|
68917
|
-
const target = path35.join(backup,
|
|
69524
|
+
const target = path35.join(backup, createHash13("sha256").update(file).digest("hex").slice(0, 12) + "-" + path35.basename(file));
|
|
68918
69525
|
copyFileSync5(file, target);
|
|
68919
69526
|
chmodSync(target, 384);
|
|
68920
69527
|
}
|
|
@@ -69128,7 +69735,7 @@ async function runLaunchCommand(argv, deps = {}) {
|
|
|
69128
69735
|
}
|
|
69129
69736
|
if (deps.run)
|
|
69130
69737
|
return deps.run(host, hostArgs).status ?? 1;
|
|
69131
|
-
return
|
|
69738
|
+
return spawnSync13(launch.command, launch.args, {
|
|
69132
69739
|
stdio: "inherit",
|
|
69133
69740
|
env
|
|
69134
69741
|
}).status ?? 1;
|
|
@@ -69162,14 +69769,14 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
69162
69769
|
return null;
|
|
69163
69770
|
let data;
|
|
69164
69771
|
try {
|
|
69165
|
-
data = JSON.parse(
|
|
69772
|
+
data = JSON.parse(readFileSync17(file, "utf8"));
|
|
69166
69773
|
} catch {
|
|
69167
69774
|
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
69168
69775
|
}
|
|
69169
69776
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
69170
69777
|
throw new Error(`${file} is not a configuration object`);
|
|
69171
69778
|
return data;
|
|
69172
|
-
}, digest2 = (file) => existsSync17(file) ?
|
|
69779
|
+
}, digest2 = (file) => existsSync17(file) ? createHash13("sha256").update(readFileSync17(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
69173
69780
|
const { home, env } = upgradePaths(deps);
|
|
69174
69781
|
let step;
|
|
69175
69782
|
try {
|
|
@@ -69309,12 +69916,49 @@ var init_launch = __esm(() => {
|
|
|
69309
69916
|
init_upgrade();
|
|
69310
69917
|
});
|
|
69311
69918
|
|
|
69919
|
+
// packages/workit-cli/src/prompt.ts
|
|
69920
|
+
import { createInterface } from "node:readline/promises";
|
|
69921
|
+
async function askLine(question, output = process.stdout) {
|
|
69922
|
+
const prompt = createInterface({ input: process.stdin, output });
|
|
69923
|
+
try {
|
|
69924
|
+
return await prompt.question(question);
|
|
69925
|
+
} finally {
|
|
69926
|
+
prompt.close();
|
|
69927
|
+
}
|
|
69928
|
+
}
|
|
69929
|
+
async function askOrCancel(io, ask) {
|
|
69930
|
+
try {
|
|
69931
|
+
return await ask();
|
|
69932
|
+
} catch (error) {
|
|
69933
|
+
if (!isPromptAbort(error))
|
|
69934
|
+
throw error;
|
|
69935
|
+
io.stderr(`
|
|
69936
|
+
Cancelled.
|
|
69937
|
+
`);
|
|
69938
|
+
return null;
|
|
69939
|
+
}
|
|
69940
|
+
}
|
|
69941
|
+
function cancelled(io) {
|
|
69942
|
+
if (io.json) {
|
|
69943
|
+
const envelope = {
|
|
69944
|
+
ok: false,
|
|
69945
|
+
code: "failed",
|
|
69946
|
+
data: { reason: "cancelled" },
|
|
69947
|
+
error: "cancelled"
|
|
69948
|
+
};
|
|
69949
|
+
io.stdout(`${JSON.stringify(envelope)}
|
|
69950
|
+
`);
|
|
69951
|
+
}
|
|
69952
|
+
return CANCELLED_EXIT;
|
|
69953
|
+
}
|
|
69954
|
+
var CANCELLED_EXIT = 130, isPromptAbort = (error) => typeof error === "object" && error !== null && (error.name === "AbortError" || error.code === "ABORT_ERR");
|
|
69955
|
+
var init_prompt = () => {};
|
|
69956
|
+
|
|
69312
69957
|
// packages/workit-cli/src/verbs/doctor.ts
|
|
69313
69958
|
var exports_doctor = {};
|
|
69314
69959
|
__export(exports_doctor, {
|
|
69315
69960
|
run: () => run5
|
|
69316
69961
|
});
|
|
69317
|
-
import { createInterface } from "node:readline/promises";
|
|
69318
69962
|
async function confirmForcedLockClear(root, args, io) {
|
|
69319
69963
|
const lock = inspectMetadataLock(root);
|
|
69320
69964
|
if (!lock.present)
|
|
@@ -69331,23 +69975,20 @@ async function confirmForcedLockClear(root, args, io) {
|
|
|
69331
69975
|
`);
|
|
69332
69976
|
return false;
|
|
69333
69977
|
}
|
|
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
|
-
}
|
|
69978
|
+
const answer = await askOrCancel(io, () => askLine("Remove this lock even if its holder may be alive? [y/N] ", io.json ? process.stderr : process.stdout));
|
|
69979
|
+
if (answer === null)
|
|
69980
|
+
return "cancelled";
|
|
69981
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
69344
69982
|
}
|
|
69345
69983
|
async function run5(argv, io) {
|
|
69346
69984
|
const root = workspaceRootFor();
|
|
69347
69985
|
const force = argv.includes("--force");
|
|
69348
69986
|
let fixLock = null;
|
|
69349
69987
|
if (argv.includes("--fix-lock")) {
|
|
69350
|
-
|
|
69988
|
+
const confirmed = force ? await confirmForcedLockClear(root, argv, io) : true;
|
|
69989
|
+
if (confirmed === "cancelled")
|
|
69990
|
+
return cancelled(io);
|
|
69991
|
+
if (!confirmed) {
|
|
69351
69992
|
if (!io.json)
|
|
69352
69993
|
return 3;
|
|
69353
69994
|
return emit(io, fail("blocked", "fix-lock --force: refusing without --yes outside an interactive terminal", {
|
|
@@ -69386,6 +70027,7 @@ var init_doctor2 = __esm(() => {
|
|
|
69386
70027
|
init_doctor();
|
|
69387
70028
|
init_store_lock();
|
|
69388
70029
|
init_output();
|
|
70030
|
+
init_prompt();
|
|
69389
70031
|
init_task();
|
|
69390
70032
|
});
|
|
69391
70033
|
|
|
@@ -69493,8 +70135,8 @@ var init_redact = __esm(() => {
|
|
|
69493
70135
|
});
|
|
69494
70136
|
|
|
69495
70137
|
// packages/workit-core/src/checks.ts
|
|
69496
|
-
import { spawn, spawnSync as
|
|
69497
|
-
import { createHash as
|
|
70138
|
+
import { spawn, spawnSync as spawnSync14 } from "node:child_process";
|
|
70139
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
69498
70140
|
import fs17 from "node:fs";
|
|
69499
70141
|
import os13 from "node:os";
|
|
69500
70142
|
import path36 from "node:path";
|
|
@@ -69672,7 +70314,7 @@ function runCheckCommand(argv, options) {
|
|
|
69672
70314
|
if (!child?.pid)
|
|
69673
70315
|
return;
|
|
69674
70316
|
if (windows)
|
|
69675
|
-
|
|
70317
|
+
spawnSync14("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
69676
70318
|
stdio: "ignore",
|
|
69677
70319
|
windowsHide: true
|
|
69678
70320
|
});
|
|
@@ -69828,7 +70470,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
69828
70470
|
}
|
|
69829
70471
|
return report;
|
|
69830
70472
|
}
|
|
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:${
|
|
70473
|
+
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
70474
|
var init_checks3 = __esm(() => {
|
|
69833
70475
|
init_redact();
|
|
69834
70476
|
MAX_LOG_BYTES = 2 * 1024 * 1024;
|
|
@@ -69917,7 +70559,6 @@ __export(exports_grant, {
|
|
|
69917
70559
|
run: () => run8,
|
|
69918
70560
|
runGrant: () => runGrant
|
|
69919
70561
|
});
|
|
69920
|
-
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
69921
70562
|
function show(argv, io) {
|
|
69922
70563
|
const all = argv.includes("--all");
|
|
69923
70564
|
const named = argv.filter((arg) => !arg.startsWith("--"));
|
|
@@ -69932,7 +70573,7 @@ function show(argv, io) {
|
|
|
69932
70573
|
return emit(io, fail("not_found", `no workspace named "${named[0]}" in ${listed.path}`));
|
|
69933
70574
|
return emit(io, ok({ path: listed.path, defaults: DEFAULT_GRANTS, workspaces: rows }), () => rows.flatMap((entry) => [
|
|
69934
70575
|
`${entry.name} (${entry.glob})`,
|
|
69935
|
-
...describe2(entry.grants, entry.configured, entry
|
|
70576
|
+
...describe2(entry.grants, entry.configured, entry, entry.verification)
|
|
69936
70577
|
]));
|
|
69937
70578
|
}
|
|
69938
70579
|
let autonomy;
|
|
@@ -69941,10 +70582,13 @@ function show(argv, io) {
|
|
|
69941
70582
|
} catch (error) {
|
|
69942
70583
|
return emit(io, fail("invalid_input", error instanceof Error ? error.message : String(error)));
|
|
69943
70584
|
}
|
|
69944
|
-
|
|
70585
|
+
const tracks = releaseTracksReport(io.cwd);
|
|
70586
|
+
const shown = tracks.tracks.length || tracks.error ? { ...autonomy, releaseTracks: tracks } : autonomy;
|
|
70587
|
+
return emit(io, ok(shown), (data) => [
|
|
69945
70588
|
...data.note ? [`note: ${data.note}`] : [],
|
|
69946
70589
|
data.workspace ? `workspace ${data.workspace} (${data.source === "default" ? "D4 defaults" : `from ${data.source}`})` : "no workspace matches this checkout: D4 defaults apply",
|
|
69947
|
-
...describe2(data.grants, data.configured, data
|
|
70590
|
+
...describe2(data.grants, data.configured, data, data.verification),
|
|
70591
|
+
...describeReleaseTracks(tracks).map((line) => ` ${line}`),
|
|
69948
70592
|
"raising a grant needs the user: workit grant set <workspace> <kind>=<value>"
|
|
69949
70593
|
]);
|
|
69950
70594
|
}
|
|
@@ -69966,10 +70610,10 @@ async function change(verb, argv, io, deps) {
|
|
|
69966
70610
|
if (kind === "defaultEndpoint") {
|
|
69967
70611
|
if (verb === "unset")
|
|
69968
70612
|
endpoint = null;
|
|
69969
|
-
else if (raw
|
|
70613
|
+
else if (isDefaultEndpoint(raw))
|
|
69970
70614
|
endpoint = raw;
|
|
69971
70615
|
else
|
|
69972
|
-
return usage2(io, `${spec}: defaultEndpoint must be
|
|
70616
|
+
return usage2(io, `${spec}: defaultEndpoint must be ${DEFAULT_ENDPOINTS.join(", ")}`);
|
|
69973
70617
|
continue;
|
|
69974
70618
|
}
|
|
69975
70619
|
if (kind === "verification") {
|
|
@@ -69993,8 +70637,8 @@ async function change(verb, argv, io, deps) {
|
|
|
69993
70637
|
changes.push({ kind, value });
|
|
69994
70638
|
}
|
|
69995
70639
|
const raised = changes.filter(({ kind, value }) => raises(kind, entry.grants[kind], value ?? DEFAULT_GRANTS[kind])).map(({ kind, value }) => ({ kind, value: String(value ?? DEFAULT_GRANTS[kind]) }));
|
|
69996
|
-
if (endpoint
|
|
69997
|
-
raised.push({ kind: "defaultEndpoint", value:
|
|
70640
|
+
if (endpoint && raisesEndpoint(entry.defaultEndpoint, endpoint))
|
|
70641
|
+
raised.push({ kind: "defaultEndpoint", value: endpoint });
|
|
69998
70642
|
if (verification !== undefined && verification !== "independent" && entry.verification === "independent")
|
|
69999
70643
|
raised.push({ kind: "verification", value: "self" });
|
|
70000
70644
|
if (raised.length > 0) {
|
|
@@ -70002,7 +70646,9 @@ async function change(verb, argv, io, deps) {
|
|
|
70002
70646
|
const agent = agentMarker(io.env);
|
|
70003
70647
|
if (!deps.interactive() || agent)
|
|
70004
70648
|
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: `);
|
|
70649
|
+
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: `));
|
|
70650
|
+
if (answer === null)
|
|
70651
|
+
return cancelled(io);
|
|
70006
70652
|
if (answer.trim() !== workspace)
|
|
70007
70653
|
return emit(io, fail("blocked", "grant change not confirmed; nothing was written"));
|
|
70008
70654
|
}
|
|
@@ -70011,7 +70657,7 @@ async function change(verb, argv, io, deps) {
|
|
|
70011
70657
|
return emit(io, fail(written.code, written.error));
|
|
70012
70658
|
return emit(io, ok(written), (data) => [
|
|
70013
70659
|
`${data.workspace}: grants updated in ${data.path}${data.backup ? ` (previous copy: ${data.backup})` : ""}`,
|
|
70014
|
-
...describe2(data.grants, data.configured, data
|
|
70660
|
+
...describe2(data.grants, data.configured, data, data.verification)
|
|
70015
70661
|
]);
|
|
70016
70662
|
}
|
|
70017
70663
|
async function runGrant(argv, io, deps = defaultDeps) {
|
|
@@ -70029,15 +70675,18 @@ async function runGrant(argv, io, deps = defaultDeps) {
|
|
|
70029
70675
|
}
|
|
70030
70676
|
return usage2(io, `unknown subcommand "${sub}"`);
|
|
70031
70677
|
}
|
|
70032
|
-
var USAGE2 = "workit grant show [<workspace>] [--all] | grant set <workspace> <kind>=<true|false|verified>… [defaultEndpoint=commit|pr] [verification=self|independent] | grant unset <workspace> <kind>… (kinds: push, pr, merge, release, rerun, defaultEndpoint, verification)", AGENT_ENV, agentMarker = (env) => AGENT_ENV.find((name) => env[name]) ?? Object.keys(env).find((name) => name.startsWith("CODEX_") && env[name]), defaultDeps, parseValue = (raw) => raw === "true" || raw === "yes" || raw === "on" ? true : raw === "false" || raw === "no" || raw === "off" ? false : raw === "verified" ? "verified" : null, describe2 = (grants, configured, endpoint, verification) => [
|
|
70678
|
+
var USAGE2 = "workit grant show [<workspace>] [--all] | grant set <workspace> <kind>=<true|false|verified>… [defaultEndpoint=commit|pr|green|merged] [verification=self|independent] | grant unset <workspace> <kind>… (kinds: push, pr, merge, release, rerun, defaultEndpoint, verification)", AGENT_ENV, agentMarker = (env) => AGENT_ENV.find((name) => env[name]) ?? Object.keys(env).find((name) => name.startsWith("CODEX_") && env[name]), defaultDeps, parseValue = (raw) => raw === "true" || raw === "yes" || raw === "on" ? true : raw === "false" || raw === "no" || raw === "off" ? false : raw === "verified" ? "verified" : null, STOPS_AT, endpointLabel = (view) => view.effectiveEndpoint === view.defaultEndpoint ? view.defaultEndpoint : `${view.defaultEndpoint} (effective: ${view.effectiveEndpoint}${view.endpointReason ? `, ${view.endpointReason}` : ""})`, describe2 = (grants, configured, endpoint, verification) => [
|
|
70033
70679
|
...GRANT_KINDS.map((kind) => ` ${kind.padEnd(8)}${String(grants[kind]).padEnd(10)}${configured.includes(kind) ? "configured" : "default"}${kind === "release" ? " (no consumer yet: reserved, not enforced)" : ""}`),
|
|
70034
|
-
` default endpoint: ${endpoint} (an unnamed request stops at ${endpoint
|
|
70680
|
+
` default endpoint: ${endpointLabel(endpoint)} (an unnamed request stops at ${STOPS_AT[endpoint.effectiveEndpoint]})`,
|
|
70681
|
+
...endpoint.endpointIssue ? [` note: ${endpoint.endpointIssue}`] : [],
|
|
70035
70682
|
` verification: ${verification} (${verification === "independent" ? "a normal-risk behavior change needs a non-author verdict" : "a normal-risk behavior change needs a passing check and the author's --self verdict, shown as self-reviewed"})`
|
|
70036
70683
|
], usage2 = (io, message) => emit(io, fail("invalid_input", `${message}
|
|
70037
70684
|
usage: ${USAGE2}`)), run8 = (argv, io) => runGrant(argv, io);
|
|
70038
70685
|
var init_grant = __esm(() => {
|
|
70039
70686
|
init_autonomy();
|
|
70687
|
+
init_release_tracks();
|
|
70040
70688
|
init_output();
|
|
70689
|
+
init_prompt();
|
|
70041
70690
|
AGENT_ENV = [
|
|
70042
70691
|
"CLAUDECODE",
|
|
70043
70692
|
"OPENCODE",
|
|
@@ -70048,14 +70697,13 @@ var init_grant = __esm(() => {
|
|
|
70048
70697
|
];
|
|
70049
70698
|
defaultDeps = {
|
|
70050
70699
|
interactive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
|
|
70051
|
-
ask:
|
|
70052
|
-
|
|
70053
|
-
|
|
70054
|
-
|
|
70055
|
-
|
|
70056
|
-
|
|
70057
|
-
|
|
70058
|
-
}
|
|
70700
|
+
ask: (question) => askLine(question)
|
|
70701
|
+
};
|
|
70702
|
+
STOPS_AT = {
|
|
70703
|
+
commit: "a local commit",
|
|
70704
|
+
pr: "an opened PR",
|
|
70705
|
+
green: "a merge-ready PR: CI green, threads resolved, verified; never merged",
|
|
70706
|
+
merged: "a merged PR (workit pr merge)"
|
|
70059
70707
|
};
|
|
70060
70708
|
});
|
|
70061
70709
|
|
|
@@ -70392,9 +71040,9 @@ var init_check = __esm(() => {
|
|
|
70392
71040
|
var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
70393
71041
|
|
|
70394
71042
|
// packages/workit-core/src/git/ops.ts
|
|
70395
|
-
import { spawnSync as
|
|
71043
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
70396
71044
|
function dirtEntries(cwd) {
|
|
70397
|
-
const run =
|
|
71045
|
+
const run = git5(cwd, ["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
|
|
70398
71046
|
if (!run.ok)
|
|
70399
71047
|
return [];
|
|
70400
71048
|
const parts = run.stdout.split("\x00");
|
|
@@ -70410,9 +71058,19 @@ function dirtEntries(cwd) {
|
|
|
70410
71058
|
return out;
|
|
70411
71059
|
}
|
|
70412
71060
|
function gitBranch(cwd, input) {
|
|
70413
|
-
const name = input.name.trim();
|
|
70414
71061
|
if (!headSha(cwd) && currentBranch(cwd) === null)
|
|
70415
71062
|
return failure3("invalid_input", "not inside a git repository with a commit");
|
|
71063
|
+
const explicitBase = input.base?.trim() || null;
|
|
71064
|
+
const resolved = vcsConfig("resolve", cwd, {
|
|
71065
|
+
track: input.track ?? null,
|
|
71066
|
+
...explicitBase ? { branch: explicitBase } : {}
|
|
71067
|
+
});
|
|
71068
|
+
const releaseTrack = resolved.ok === false ? null : resolved.releaseTrack ?? null;
|
|
71069
|
+
if (releaseTrack?.blocking && (!explicitBase || input.name === undefined))
|
|
71070
|
+
return failure3("blocked", String(releaseTrack.blocking), "workit git branch … --track <name> # or --base <branch>");
|
|
71071
|
+
const name = (input.name ?? (input.kind && input.slug ? trackBranchName(releaseTrack?.track ?? null, input.kind, input.slug) ?? `${input.kind}/${input.slug}` : "")).trim();
|
|
71072
|
+
if (!name)
|
|
71073
|
+
return failure3("invalid_input", "missing branch name");
|
|
70416
71074
|
if (!validRefName(cwd, name))
|
|
70417
71075
|
return failure3("invalid_input", `invalid branch name ${JSON.stringify(name)}`);
|
|
70418
71076
|
const policy = validateBranchNameFor(cwd, name);
|
|
@@ -70420,23 +71078,25 @@ function gitBranch(cwd, input) {
|
|
|
70420
71078
|
return failure3("blocked", policy.error, policy.correction);
|
|
70421
71079
|
if (resolveRef(cwd, `refs/heads/${name}`))
|
|
70422
71080
|
return failure3("failed", `branch_exists: ${name} already exists`, `git switch ${name}`);
|
|
70423
|
-
let base =
|
|
71081
|
+
let base = explicitBase;
|
|
70424
71082
|
let defaultTarget = null;
|
|
70425
|
-
|
|
70426
|
-
if (resolved.ok === false && !base)
|
|
71083
|
+
let defaultBase = null;
|
|
71084
|
+
if (resolved.ok === false && (!base || input.track))
|
|
70427
71085
|
return failure3("blocked", String(resolved.error), "fix ~/.config/workit/vcs.json or pass --base <branch>");
|
|
70428
|
-
if (resolved.ok !== false)
|
|
71086
|
+
if (resolved.ok !== false) {
|
|
70429
71087
|
defaultTarget = String(resolved.defaultTargetBranch ?? "") || null;
|
|
70430
|
-
|
|
71088
|
+
defaultBase = String(resolved.baseBranch ?? "") || defaultTarget;
|
|
71089
|
+
}
|
|
71090
|
+
base ??= defaultBase;
|
|
70431
71091
|
if (!base)
|
|
70432
71092
|
return failure3("invalid_input", "no default target branch is configured; pass --base <branch>");
|
|
70433
71093
|
if (base.startsWith("-"))
|
|
70434
71094
|
return failure3("invalid_input", "--base must not start with -");
|
|
70435
|
-
const notes = [];
|
|
71095
|
+
const notes = [...releaseTrack?.warnings ?? []];
|
|
70436
71096
|
const remotes = remoteNames(cwd);
|
|
70437
71097
|
const remote = remotes.includes("origin") ? "origin" : pushRemoteName(cwd);
|
|
70438
71098
|
const localTip = resolveRef(cwd, `refs/heads/${base}`);
|
|
70439
|
-
const stackParent = localTip !== null && base !== defaultTarget && !isProtectedTarget(cwd, base);
|
|
71099
|
+
const stackParent = localTip !== null && base !== defaultTarget && base !== defaultBase && !isProtectedTarget(cwd, base);
|
|
70440
71100
|
let baseRef = null;
|
|
70441
71101
|
if (stackParent)
|
|
70442
71102
|
baseRef = `refs/heads/${base}`;
|
|
@@ -70454,18 +71114,19 @@ function gitBranch(cwd, input) {
|
|
|
70454
71114
|
}
|
|
70455
71115
|
} else if (localTip)
|
|
70456
71116
|
baseRef = `refs/heads/${base}`;
|
|
70457
|
-
if (!baseRef &&
|
|
71117
|
+
if (!baseRef && git5(cwd, ["rev-parse", "--verify", "-q", `${base}^{commit}`]).ok)
|
|
70458
71118
|
baseRef = base;
|
|
70459
|
-
const baseSha = baseRef ?
|
|
71119
|
+
const baseSha = baseRef ? git5(cwd, ["rev-parse", "--verify", "-q", `${baseRef}^{commit}`]).stdout.trim() : "";
|
|
70460
71120
|
if (!baseRef || !baseSha)
|
|
70461
71121
|
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
71122
|
const dirt = classifyBranchDirt(cwd);
|
|
70463
71123
|
if (dirt === "stash-required" && !input.carry)
|
|
70464
71124
|
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
71125
|
const previous = currentBranch(cwd);
|
|
70466
|
-
const switched =
|
|
71126
|
+
const switched = git5(cwd, ["switch", "--no-track", "-c", name, baseSha]);
|
|
70467
71127
|
if (!switched.ok)
|
|
70468
71128
|
return failure3("failed", `git switch -c ${name} failed: ${gitError(switched)}`);
|
|
71129
|
+
recordBranchBase(cwd, name, base);
|
|
70469
71130
|
return success2({
|
|
70470
71131
|
branch: name,
|
|
70471
71132
|
previous,
|
|
@@ -70473,7 +71134,8 @@ function gitBranch(cwd, input) {
|
|
|
70473
71134
|
baseRef,
|
|
70474
71135
|
baseSha,
|
|
70475
71136
|
carried: dirt !== "clean",
|
|
70476
|
-
notes
|
|
71137
|
+
notes,
|
|
71138
|
+
releaseTrack
|
|
70477
71139
|
});
|
|
70478
71140
|
}
|
|
70479
71141
|
function lintCommitMessage(cwd, message) {
|
|
@@ -70488,7 +71150,7 @@ function lintCommitMessage(cwd, message) {
|
|
|
70488
71150
|
}
|
|
70489
71151
|
if (preset !== "auto")
|
|
70490
71152
|
return { ok: true };
|
|
70491
|
-
const log =
|
|
71153
|
+
const log = git5(cwd, ["log", "-n", "50", "--no-merges", "--format=%s"]);
|
|
70492
71154
|
const subjects = log.ok ? log.stdout.split(`
|
|
70493
71155
|
`).filter(Boolean) : [];
|
|
70494
71156
|
const detected = detectCommitFlavor(subjects).flavor;
|
|
@@ -70526,28 +71188,28 @@ function gitCommit(cwd, input) {
|
|
|
70526
71188
|
if (paths.length) {
|
|
70527
71189
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
70528
71190
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
70529
|
-
const added =
|
|
71191
|
+
const added = git5(cwd, ["add", "-A", "--", ...paths]);
|
|
70530
71192
|
if (!added.ok)
|
|
70531
71193
|
return failure3("failed", `git add failed: ${gitError(added)}`);
|
|
70532
71194
|
args.push("--", ...paths);
|
|
70533
71195
|
} else if (input.all) {
|
|
70534
|
-
const added =
|
|
71196
|
+
const added = git5(cwd, ["add", "-A"]);
|
|
70535
71197
|
if (!added.ok)
|
|
70536
71198
|
return failure3("failed", `git add failed: ${gitError(added)}`);
|
|
70537
71199
|
} else {
|
|
70538
|
-
const staged =
|
|
71200
|
+
const staged = git5(cwd, ["diff", "--cached", "--name-only", "-z"]);
|
|
70539
71201
|
if (staged.ok && !staged.stdout.replaceAll("\x00", "")) {
|
|
70540
71202
|
const dirt = dirtEntries(cwd);
|
|
70541
71203
|
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
71204
|
}
|
|
70543
71205
|
}
|
|
70544
|
-
const committed =
|
|
71206
|
+
const committed = git5(cwd, args, { timeoutMs: COMMIT_TIMEOUT_MS, env: input.env });
|
|
70545
71207
|
if (!committed.ok)
|
|
70546
71208
|
return failure3("failed", `git commit failed: ${gitError(committed, 6)}`);
|
|
70547
71209
|
const sha = headSha(cwd);
|
|
70548
71210
|
if (!sha)
|
|
70549
71211
|
return failure3("failed", "the commit did not resolve");
|
|
70550
|
-
const files = nulList(
|
|
71212
|
+
const files = nulList(git5(cwd, ["diff-tree", "--root", "--no-commit-id", "--name-only", "-r", "-z", sha]).stdout);
|
|
70551
71213
|
const leftDirty = dirtEntries(cwd).length;
|
|
70552
71214
|
const listed = [];
|
|
70553
71215
|
let size = 0;
|
|
@@ -70619,9 +71281,9 @@ function recordedRemoteTip(cwd, plan) {
|
|
|
70619
71281
|
return;
|
|
70620
71282
|
}
|
|
70621
71283
|
function includesRemoteTip(cwd, branch, tip) {
|
|
70622
|
-
if (
|
|
71284
|
+
if (git5(cwd, ["merge-base", "--is-ancestor", tip, `refs/heads/${branch}`]).ok)
|
|
70623
71285
|
return true;
|
|
70624
|
-
const reflog =
|
|
71286
|
+
const reflog = git5(cwd, ["reflog", "show", "--format=%H", `refs/heads/${branch}`, "--"]);
|
|
70625
71287
|
return reflog.ok && reflog.stdout.split(`
|
|
70626
71288
|
`).some((line) => line.trim() === tip);
|
|
70627
71289
|
}
|
|
@@ -70671,7 +71333,7 @@ ${run.stdout}`;
|
|
|
70671
71333
|
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
71334
|
let upstream = false;
|
|
70673
71335
|
if (input.setUpstream) {
|
|
70674
|
-
upstream =
|
|
71336
|
+
upstream = git5(cwd, ["config", `branch.${plan.branch}.remote`, plan.remote]).ok && git5(cwd, ["config", `branch.${plan.branch}.merge`, `refs/heads/${plan.branch}`]).ok;
|
|
70675
71337
|
}
|
|
70676
71338
|
const row = appendObserved(cwd, {
|
|
70677
71339
|
type: pushed ? "push.verified" : "push.noop",
|
|
@@ -70721,8 +71383,8 @@ function deleteRemoteBranch(cwd, target, branch, expectedTip, options = {}) {
|
|
|
70721
71383
|
${run.stdout}`;
|
|
70722
71384
|
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
71385
|
}
|
|
70724
|
-
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000,
|
|
70725
|
-
const result =
|
|
71386
|
+
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
|
|
71387
|
+
const result = spawnSync15("git", args, {
|
|
70726
71388
|
cwd,
|
|
70727
71389
|
encoding: "utf8",
|
|
70728
71390
|
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
@@ -70742,11 +71404,12 @@ var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git4 = (cwd, args, options = {}
|
|
|
70742
71404
|
const lines = redactText(`${run.stderr}
|
|
70743
71405
|
${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trim()).filter((value) => value && !value.startsWith("hint:"));
|
|
70744
71406
|
return lines.slice(-max).join(" / ").slice(0, 400) || "git failed";
|
|
70745
|
-
}, validRefName = (cwd, name) => !name.startsWith("-") &&
|
|
71407
|
+
}, validRefName = (cwd, name) => !name.startsWith("-") && git5(cwd, ["check-ref-format", "--branch", name]).ok, nulList = (text) => text.split("\x00").filter(Boolean), SESSION_SAFE, SHA;
|
|
70746
71408
|
var init_ops = __esm(() => {
|
|
70747
71409
|
init_branch();
|
|
70748
71410
|
init_commit_flavors();
|
|
70749
71411
|
init_pr_create();
|
|
71412
|
+
init_release_tracks();
|
|
70750
71413
|
init_vcs_config();
|
|
70751
71414
|
init_redact();
|
|
70752
71415
|
init_ledger();
|
|
@@ -70903,6 +71566,32 @@ function blockersOf(input) {
|
|
|
70903
71566
|
}
|
|
70904
71567
|
return out;
|
|
70905
71568
|
}
|
|
71569
|
+
function babysitAction(next, reason, draft) {
|
|
71570
|
+
switch (next) {
|
|
71571
|
+
case "MERGED":
|
|
71572
|
+
return "merged";
|
|
71573
|
+
case "CLOSED":
|
|
71574
|
+
return null;
|
|
71575
|
+
case "RESOLVE_CONFLICTS":
|
|
71576
|
+
case "REBASE":
|
|
71577
|
+
return "update-branch";
|
|
71578
|
+
case "RESOLVE_THREADS":
|
|
71579
|
+
case "ADDRESS_REVIEW":
|
|
71580
|
+
return "address-threads";
|
|
71581
|
+
case "FIX_CI":
|
|
71582
|
+
return "fix-ci";
|
|
71583
|
+
case "WAITING_CI":
|
|
71584
|
+
return "wait";
|
|
71585
|
+
case "IN_MERGE_QUEUE":
|
|
71586
|
+
return "wait-forge";
|
|
71587
|
+
default:
|
|
71588
|
+
if (draft)
|
|
71589
|
+
return "mark-ready";
|
|
71590
|
+
if (next === "NOT_MERGEABLE" && reason === "mergeability_unknown")
|
|
71591
|
+
return "wait-forge";
|
|
71592
|
+
return "ready";
|
|
71593
|
+
}
|
|
71594
|
+
}
|
|
70906
71595
|
function computeBehindBase(cwd, remotes, baseSha, headSha_, options = {}) {
|
|
70907
71596
|
const empty = { behind: null, ahead: null, upToDate: null };
|
|
70908
71597
|
if (!baseSha)
|
|
@@ -71027,7 +71716,8 @@ function buildStatusDoc(cwd, resolved, status, options) {
|
|
|
71027
71716
|
blockers: status.state === "open" ? blockers.map((blocker) => blocker.reason) : [],
|
|
71028
71717
|
identity: options.identity ?? null,
|
|
71029
71718
|
truncated: status.truncated,
|
|
71030
|
-
next: blockers[0]?.next ?? "READY"
|
|
71719
|
+
next: blockers[0]?.next ?? "READY",
|
|
71720
|
+
babysit: babysitAction(blockers[0]?.next ?? "READY", blockers[0]?.reason ?? null, status.draft || blockers.some((blocker) => blocker.next === "MARK_READY"))
|
|
71031
71721
|
});
|
|
71032
71722
|
}
|
|
71033
71723
|
function prStatusReport(cwd, resolved, options = {}) {
|
|
@@ -71175,7 +71865,7 @@ var init_report = __esm(() => {
|
|
|
71175
71865
|
});
|
|
71176
71866
|
|
|
71177
71867
|
// packages/workit-core/src/forge/pr-ops.ts
|
|
71178
|
-
import { spawnSync as
|
|
71868
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
71179
71869
|
function fillFromCommits(cwd, resolved, base) {
|
|
71180
71870
|
const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
|
|
71181
71871
|
if (!base.startsWith("-"))
|
|
@@ -71183,7 +71873,7 @@ function fillFromCommits(cwd, resolved, base) {
|
|
|
71183
71873
|
const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
|
|
71184
71874
|
if (!from)
|
|
71185
71875
|
return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
|
|
71186
|
-
const log =
|
|
71876
|
+
const log = spawnSync16("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
|
|
71187
71877
|
cwd,
|
|
71188
71878
|
encoding: "utf8",
|
|
71189
71879
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -71382,6 +72072,7 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
|
|
|
71382
72072
|
const gone = !deleted.ok && remoteRefTip(cwd, resolved.remote, `refs/heads/${branch}`);
|
|
71383
72073
|
deletedBranch = deleted.ok || gone && gone.ok && gone.sha === null ? true : { error: deleted.error };
|
|
71384
72074
|
}
|
|
72075
|
+
const mergeBack = mergeBackFor(cwd, doc.base);
|
|
71385
72076
|
const row = appendObserved(cwd, {
|
|
71386
72077
|
type: "pr.merged",
|
|
71387
72078
|
actor: input.actor,
|
|
@@ -71407,11 +72098,25 @@ async function mergePullRequest(cwd, resolved, input, sleep) {
|
|
|
71407
72098
|
verdict,
|
|
71408
72099
|
grant: { source: grant.source },
|
|
71409
72100
|
deletedBranch,
|
|
71410
|
-
recorded: row.ok ? { id: String(row.value.id) } : { error: row.error }
|
|
72101
|
+
recorded: row.ok ? { id: String(row.value.id) } : { error: row.error },
|
|
72102
|
+
mergeBack: mergeBack.branches,
|
|
72103
|
+
mergeBackTrack: mergeBack.track
|
|
71411
72104
|
}
|
|
71412
72105
|
};
|
|
71413
72106
|
}
|
|
71414
|
-
var VERIFY_DELAYS_MS, noun = (resolved) => resolved.forge.kind === "github" ? "pull request" : "merge request", grantBlocked = (decision) => failure3("blocked", decision.error, decision.unblock),
|
|
72107
|
+
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) => {
|
|
72108
|
+
try {
|
|
72109
|
+
const owners = workspaceReleaseTracks(cwd).tracks.filter((track) => track.productionBranch === base);
|
|
72110
|
+
if (owners.length !== 1)
|
|
72111
|
+
return { track: null, branches: [] };
|
|
72112
|
+
return {
|
|
72113
|
+
track: owners[0].name,
|
|
72114
|
+
branches: owners[0].mergeBackBranches.filter((branch) => branch !== base)
|
|
72115
|
+
};
|
|
72116
|
+
} catch {
|
|
72117
|
+
return { track: null, branches: [] };
|
|
72118
|
+
}
|
|
72119
|
+
}, refuse = (error, unblock, refusal) => ({
|
|
71415
72120
|
ok: false,
|
|
71416
72121
|
code: "blocked",
|
|
71417
72122
|
error,
|
|
@@ -71422,6 +72127,7 @@ var init_pr_ops = __esm(() => {
|
|
|
71422
72127
|
init_autonomy();
|
|
71423
72128
|
init_branch();
|
|
71424
72129
|
init_vcs_config();
|
|
72130
|
+
init_release_tracks();
|
|
71425
72131
|
init_ops();
|
|
71426
72132
|
init_rev();
|
|
71427
72133
|
init_ledger();
|
|
@@ -71442,7 +72148,7 @@ var init_pr_ops = __esm(() => {
|
|
|
71442
72148
|
});
|
|
71443
72149
|
|
|
71444
72150
|
// packages/workit-core/src/forge/exec.ts
|
|
71445
|
-
import { spawnSync as
|
|
72151
|
+
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
71446
72152
|
import fs19 from "node:fs";
|
|
71447
72153
|
import path39 from "node:path";
|
|
71448
72154
|
function findExecutable(bin, env) {
|
|
@@ -71477,7 +72183,7 @@ function systemRunner(kind, apiHost, env = process.env) {
|
|
|
71477
72183
|
if (!exe)
|
|
71478
72184
|
return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
|
|
71479
72185
|
const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
|
|
71480
|
-
const result =
|
|
72186
|
+
const result = spawnSync17(exe, [...args], {
|
|
71481
72187
|
encoding: "utf8",
|
|
71482
72188
|
env: { ...childEnv, ...token },
|
|
71483
72189
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -72370,6 +73076,8 @@ function renderStatus(doc) {
|
|
|
72370
73076
|
lines.push(`blockers: ${doc.blockers.join(", ")}`);
|
|
72371
73077
|
if (doc.identity?.note)
|
|
72372
73078
|
lines.push(`identity: ${doc.identity.note}`);
|
|
73079
|
+
if (doc.babysit)
|
|
73080
|
+
lines.push(`babysit: ${doc.babysit}`);
|
|
72373
73081
|
lines.push(`next: ${doc.next}`);
|
|
72374
73082
|
return lines;
|
|
72375
73083
|
}
|
|
@@ -72390,7 +73098,7 @@ var exports_pr = {};
|
|
|
72390
73098
|
__export(exports_pr, {
|
|
72391
73099
|
run: () => run10
|
|
72392
73100
|
});
|
|
72393
|
-
import { readFileSync as
|
|
73101
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
72394
73102
|
import path40 from "node:path";
|
|
72395
73103
|
async function status(argv, io) {
|
|
72396
73104
|
const flags = parseFlags(argv, { pr: "value", branch: "value", "log-lines": "value" });
|
|
@@ -72443,6 +73151,7 @@ function verdictBlock(cwd, branch) {
|
|
|
72443
73151
|
async function create4(argv, io) {
|
|
72444
73152
|
const flags = parseFlags(argv, {
|
|
72445
73153
|
base: "value",
|
|
73154
|
+
track: "value",
|
|
72446
73155
|
title: "value",
|
|
72447
73156
|
body: "value",
|
|
72448
73157
|
"body-file": "value",
|
|
@@ -72461,18 +73170,26 @@ async function create4(argv, io) {
|
|
|
72461
73170
|
let body = flags.values.body ?? null;
|
|
72462
73171
|
if (flags.values["body-file"] !== undefined) {
|
|
72463
73172
|
try {
|
|
72464
|
-
body =
|
|
73173
|
+
body = readFileSync18(path40.resolve(io.cwd, flags.values["body-file"]), "utf8");
|
|
72465
73174
|
} catch {
|
|
72466
73175
|
return usage3(io, `cannot read --body-file ${flags.values["body-file"]}`, CREATE_USAGE);
|
|
72467
73176
|
}
|
|
72468
73177
|
}
|
|
73178
|
+
if (flags.values.base !== undefined && flags.values.track !== undefined)
|
|
73179
|
+
return usage3(io, "pass --base or --track, not both (--track picks the base for you)", CREATE_USAGE);
|
|
72469
73180
|
let base = flags.values.base ?? null;
|
|
73181
|
+
let releaseTrack = null;
|
|
72470
73182
|
if (!base) {
|
|
72471
|
-
const resolved = vcsConfig("resolve", io.cwd);
|
|
73183
|
+
const resolved = vcsConfig("resolve", io.cwd, { track: flags.values.track ?? null });
|
|
72472
73184
|
if (resolved.ok === false)
|
|
72473
73185
|
return emit(io, fail("blocked", String(resolved.error), {
|
|
72474
73186
|
unblock: "fix ~/.config/workit/vcs.json or pass --base <b>"
|
|
72475
73187
|
}));
|
|
73188
|
+
releaseTrack = resolved.releaseTrack ?? null;
|
|
73189
|
+
if (releaseTrack?.blocking)
|
|
73190
|
+
return emit(io, fail("blocked", releaseTrack.blocking, {
|
|
73191
|
+
unblock: "workit pr create --track <name> … # or --base <branch>"
|
|
73192
|
+
}));
|
|
72476
73193
|
base = String(resolved.defaultTargetBranch ?? "") || null;
|
|
72477
73194
|
}
|
|
72478
73195
|
if (!base)
|
|
@@ -72502,8 +73219,11 @@ async function create4(argv, io) {
|
|
|
72502
73219
|
}, forgeDeps.sleep);
|
|
72503
73220
|
if (!result.ok)
|
|
72504
73221
|
return forgeFail(io, result);
|
|
72505
|
-
|
|
73222
|
+
const created = releaseTrack ? { ...result.data, releaseTrack } : result.data;
|
|
73223
|
+
return emit(io, ok(created), (data) => [
|
|
72506
73224
|
`${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}`,
|
|
73225
|
+
...data.releaseTrack?.name ? [`release track: ${data.releaseTrack.name} (${data.releaseTrack.detail})`] : [],
|
|
73226
|
+
...(data.releaseTrack?.warnings ?? []).map((warning) => `note: ${warning}`),
|
|
72507
73227
|
`head ${data.head.slice(0, 12)} verified on the forge`,
|
|
72508
73228
|
..."error" in data.recorded ? [`ledger: not recorded (${data.recorded.error})`] : []
|
|
72509
73229
|
]);
|
|
@@ -72532,6 +73252,9 @@ async function merge3(argv, io) {
|
|
|
72532
73252
|
return emit(io, ok(result.data), (data) => [
|
|
72533
73253
|
`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
73254
|
data.verdict.required ? `verdict ${data.verdict.verdictId ?? "?"} accepted for that head` : "no verdict required (workspace grants merge: true)",
|
|
73255
|
+
...data.mergeBack.length ? [
|
|
73256
|
+
`merge back: ${data.base} is the ${data.mergeBackTrack} production branch; bring it into ${data.mergeBack.join(", ")}`
|
|
73257
|
+
] : [],
|
|
72535
73258
|
...data.deletedBranch === true ? [`deleted ${data.branch}`] : typeof data.deletedBranch === "object" ? [`branch not deleted: ${data.deletedBranch.error}`] : [],
|
|
72536
73259
|
..."error" in data.recorded ? [`ledger: not recorded (${data.recorded.error})`] : []
|
|
72537
73260
|
]);
|
|
@@ -72546,7 +73269,7 @@ async function run10(argv, io) {
|
|
|
72546
73269
|
return merge3(rest, io);
|
|
72547
73270
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown pr subcommand "${sub}"` : "missing pr subcommand", USAGE4);
|
|
72548
73271
|
}
|
|
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;
|
|
73272
|
+
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
73273
|
var init_pr = __esm(() => {
|
|
72551
73274
|
init_pr_body();
|
|
72552
73275
|
init_pr_ops();
|
|
@@ -72777,7 +73500,13 @@ __export(exports_git, {
|
|
|
72777
73500
|
run: () => run12
|
|
72778
73501
|
});
|
|
72779
73502
|
async function branch(argv, io) {
|
|
72780
|
-
const flags = parseFlags(argv, {
|
|
73503
|
+
const flags = parseFlags(argv, {
|
|
73504
|
+
base: "value",
|
|
73505
|
+
kind: "value",
|
|
73506
|
+
slug: "value",
|
|
73507
|
+
track: "value",
|
|
73508
|
+
carry: "boolean"
|
|
73509
|
+
});
|
|
72781
73510
|
if (typeof flags === "string")
|
|
72782
73511
|
return usage3(io, flags, BRANCH_USAGE);
|
|
72783
73512
|
const { kind, slug } = flags.values;
|
|
@@ -72789,18 +73518,19 @@ async function branch(argv, io) {
|
|
|
72789
73518
|
return usage3(io, "--kind must be feature, bugfix or hotfix", BRANCH_USAGE);
|
|
72790
73519
|
if (kind !== undefined && flags.positionals.length)
|
|
72791
73520
|
return usage3(io, "pass a name or --kind/--slug, not both", BRANCH_USAGE);
|
|
72792
|
-
|
|
72793
|
-
if (!name)
|
|
73521
|
+
if (kind === undefined && !flags.positionals[0])
|
|
72794
73522
|
return usage3(io, "missing branch name", BRANCH_USAGE);
|
|
72795
73523
|
const result = gitBranch(io.cwd, {
|
|
72796
|
-
name,
|
|
73524
|
+
...kind !== undefined ? { kind, slug } : { name: flags.positionals[0] },
|
|
72797
73525
|
base: flags.values.base ?? null,
|
|
73526
|
+
track: flags.values.track ?? null,
|
|
72798
73527
|
carry: flags.booleans.has("carry")
|
|
72799
73528
|
});
|
|
72800
73529
|
if (!result.ok)
|
|
72801
73530
|
return forgeFail(io, result);
|
|
72802
73531
|
return emit(io, ok(result.data), (data) => [
|
|
72803
73532
|
`switched to new branch ${data.branch} from ${data.baseRef} (${short2(data.baseSha)})${data.carried ? ", carrying uncommitted changes" : ""}`,
|
|
73533
|
+
...data.releaseTrack?.name ? [`release track: ${data.releaseTrack.name} (${data.releaseTrack.detail})`] : [],
|
|
72804
73534
|
...data.notes.map((note) => `note: ${note}`)
|
|
72805
73535
|
]);
|
|
72806
73536
|
}
|
|
@@ -72921,7 +73651,7 @@ async function run12(argv, io) {
|
|
|
72921
73651
|
return push(rest, io);
|
|
72922
73652
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown git subcommand "${sub}"` : "missing git subcommand", USAGE5);
|
|
72923
73653
|
}
|
|
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)";
|
|
73654
|
+
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
73655
|
var init_git2 = __esm(() => {
|
|
72926
73656
|
init_autonomy();
|
|
72927
73657
|
init_ops();
|
|
@@ -72932,7 +73662,7 @@ var init_git2 = __esm(() => {
|
|
|
72932
73662
|
});
|
|
72933
73663
|
|
|
72934
73664
|
// packages/workit-core/src/forge/verify.ts
|
|
72935
|
-
import { spawnSync as
|
|
73665
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
72936
73666
|
function finish(cwd, report, actor) {
|
|
72937
73667
|
const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
|
|
72938
73668
|
const out = { ...report, delivered };
|
|
@@ -73145,7 +73875,7 @@ var NPM_NAME, SEMVER, SAFE_ARG, systemNpm = (args) => {
|
|
|
73145
73875
|
};
|
|
73146
73876
|
const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
|
|
73147
73877
|
const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
|
|
73148
|
-
const result = process.platform === "win32" ?
|
|
73878
|
+
const result = process.platform === "win32" ? spawnSync18(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync18("npm", [...args], options);
|
|
73149
73879
|
return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
73150
73880
|
}, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
|
|
73151
73881
|
try {
|
|
@@ -73252,8 +73982,8 @@ var init_verify_delivery = __esm(() => {
|
|
|
73252
73982
|
});
|
|
73253
73983
|
|
|
73254
73984
|
// packages/workit-core/src/stack.ts
|
|
73255
|
-
import { spawnSync as
|
|
73256
|
-
import { createHash as
|
|
73985
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73986
|
+
import { createHash as createHash15, randomBytes as randomBytes3 } from "node:crypto";
|
|
73257
73987
|
import fs21 from "node:fs";
|
|
73258
73988
|
import path41 from "node:path";
|
|
73259
73989
|
function worktreeOf(cwd, branch) {
|
|
@@ -73353,7 +74083,7 @@ function stacksDir(cwd) {
|
|
|
73353
74083
|
return { ok: true, data: path41.join(root.value.root, "stacks") };
|
|
73354
74084
|
}
|
|
73355
74085
|
function parseStack(raw) {
|
|
73356
|
-
if (!
|
|
74086
|
+
if (!isRecord7(raw) || !Array.isArray(raw.branches))
|
|
73357
74087
|
return null;
|
|
73358
74088
|
const name = str3(raw.name);
|
|
73359
74089
|
const trunk = str3(raw.trunk);
|
|
@@ -73361,12 +74091,12 @@ function parseStack(raw) {
|
|
|
73361
74091
|
return null;
|
|
73362
74092
|
const branches = [];
|
|
73363
74093
|
for (const item of raw.branches) {
|
|
73364
|
-
if (!
|
|
74094
|
+
if (!isRecord7(item))
|
|
73365
74095
|
return null;
|
|
73366
74096
|
const branch = str3(item.branch);
|
|
73367
74097
|
if (!branch)
|
|
73368
74098
|
return null;
|
|
73369
|
-
const merged =
|
|
74099
|
+
const merged = isRecord7(item.merged) ? {
|
|
73370
74100
|
pr: typeof item.merged.pr === "number" ? item.merged.pr : null,
|
|
73371
74101
|
mergeSha: str3(item.merged.mergeSha),
|
|
73372
74102
|
at: str3(item.merged.at) ?? ""
|
|
@@ -73379,7 +74109,7 @@ function parseStack(raw) {
|
|
|
73379
74109
|
lastParentHead: str3(item.lastParentHead),
|
|
73380
74110
|
patchId: str3(item.patchId),
|
|
73381
74111
|
merged,
|
|
73382
|
-
...
|
|
74112
|
+
...isRecord7(item.pendingRestack) && str3(item.pendingRestack.from) && str3(item.pendingRestack.tip) && str3(item.pendingRestack.onto) ? {
|
|
73383
74113
|
pendingRestack: {
|
|
73384
74114
|
from: str3(item.pendingRestack.from),
|
|
73385
74115
|
tip: str3(item.pendingRestack.tip),
|
|
@@ -73765,7 +74495,7 @@ function commitKeys(cwd, range) {
|
|
|
73765
74495
|
const patches = new Map;
|
|
73766
74496
|
const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
|
|
73767
74497
|
if (diff.ok && diff.stdout.trim()) {
|
|
73768
|
-
const ids =
|
|
74498
|
+
const ids = spawnSync19("git", ["patch-id", "--stable"], {
|
|
73769
74499
|
cwd,
|
|
73770
74500
|
input: diff.stdout,
|
|
73771
74501
|
encoding: "utf8",
|
|
@@ -74373,7 +75103,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74373
75103
|
...unblock ? { unblock } : {},
|
|
74374
75104
|
...data ? { data } : {}
|
|
74375
75105
|
}), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
74376
|
-
const run =
|
|
75106
|
+
const run = spawnSync19("git", args, {
|
|
74377
75107
|
cwd,
|
|
74378
75108
|
encoding: "utf8",
|
|
74379
75109
|
timeout: timeoutMs,
|
|
@@ -74404,7 +75134,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74404
75134
|
return dir.ok ? path41.join(dir.data, "worktrees") : null;
|
|
74405
75135
|
}, firstLine = (run) => (`${run.stderr}
|
|
74406
75136
|
${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()}-${
|
|
75137
|
+
`).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
75138
|
if (name.length === 0 || name.length > 200)
|
|
74409
75139
|
return false;
|
|
74410
75140
|
for (let index = 0;index < name.length; index += 1) {
|
|
@@ -74413,7 +75143,7 @@ ${run.stdout}`.split(`
|
|
|
74413
75143
|
return false;
|
|
74414
75144
|
}
|
|
74415
75145
|
return true;
|
|
74416
|
-
},
|
|
75146
|
+
}, 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
75147
|
let raw = null;
|
|
74418
75148
|
try {
|
|
74419
75149
|
raw = fs21.readFileSync(path41.join(lock, OWNER), "utf8");
|
|
@@ -74459,7 +75189,7 @@ __export(exports_stack, {
|
|
|
74459
75189
|
run: () => run14
|
|
74460
75190
|
});
|
|
74461
75191
|
async function plan(argv, io) {
|
|
74462
|
-
const flags = parseFlags(argv, { name: "value", trunk: "value" });
|
|
75192
|
+
const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
|
|
74463
75193
|
if (typeof flags === "string")
|
|
74464
75194
|
return usage3(io, flags, PLAN_USAGE);
|
|
74465
75195
|
const name = flags.values.name ?? null;
|
|
@@ -74472,7 +75202,20 @@ async function plan(argv, io) {
|
|
|
74472
75202
|
if (selected.ok)
|
|
74473
75203
|
existing = selected.data;
|
|
74474
75204
|
}
|
|
74475
|
-
const
|
|
75205
|
+
const track = flags.values.track ?? null;
|
|
75206
|
+
if (track !== null && flags.values.trunk !== undefined)
|
|
75207
|
+
return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE);
|
|
75208
|
+
let trunk = flags.values.trunk ?? existing?.trunk ?? null;
|
|
75209
|
+
if (trunk === null || track !== null) {
|
|
75210
|
+
const derived = defaultTrunk(io, track, flags.positionals[0] ?? null);
|
|
75211
|
+
if ("error" in derived)
|
|
75212
|
+
return emit(io, fail("blocked", derived.error, {
|
|
75213
|
+
unblock: "workit stack plan --track <name> … # or --trunk <branch>"
|
|
75214
|
+
}));
|
|
75215
|
+
if (existing && track !== null && derived.trunk !== existing.trunk)
|
|
75216
|
+
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" }));
|
|
75217
|
+
trunk ??= derived.trunk ?? "main";
|
|
75218
|
+
}
|
|
74476
75219
|
const connected = connect(io, flags.positionals[0] ?? null);
|
|
74477
75220
|
const resolved = connected.ok ? connected.data : null;
|
|
74478
75221
|
const planned = planStack(io.cwd, resolved, { name, trunk, branches: flags.positionals }, existing);
|
|
@@ -74632,9 +75375,16 @@ async function run14(argv, io) {
|
|
|
74632
75375
|
return land(rest, io);
|
|
74633
75376
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown stack subcommand "${sub}"` : "missing stack subcommand", USAGE7);
|
|
74634
75377
|
}
|
|
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
|
-
|
|
75378
|
+
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) => {
|
|
75379
|
+
const resolved = vcsConfig("resolve", io.cwd, {
|
|
75380
|
+
track,
|
|
75381
|
+
...branch ? { branch } : {}
|
|
75382
|
+
});
|
|
75383
|
+
if (resolved.ok === false)
|
|
75384
|
+
return track !== null || String(resolved.configPath ?? "").endsWith("workspaces.json") ? { error: String(resolved.error) } : { trunk: null };
|
|
75385
|
+
if (resolved.releaseTrack?.blocking)
|
|
75386
|
+
return { error: String(resolved.releaseTrack.blocking) };
|
|
75387
|
+
return { trunk: String(resolved.defaultTargetBranch ?? "") || null };
|
|
74638
75388
|
}, label = (forge, pr) => pr === null ? "no PR" : `${forge === "gitlab" ? "MR !" : "PR #"}${pr}`, renderSync = (data) => [
|
|
74639
75389
|
`${data.dryRun ? "would sync" : "synced"} stack ${data.name}${data.merged.length ? `; merged: ${data.merged.map((item) => item.branch).join(", ")}` : ""}`,
|
|
74640
75390
|
...data.steps.map((step) => [
|
|
@@ -90686,11 +91436,11 @@ var init_rules = __esm(() => {
|
|
|
90686
91436
|
});
|
|
90687
91437
|
|
|
90688
91438
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
90689
|
-
import { spawnSync as
|
|
90690
|
-
import { existsSync as existsSync18, readdirSync as readdirSync8, readFileSync as
|
|
91439
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
91440
|
+
import { existsSync as existsSync18, readdirSync as readdirSync8, readFileSync as readFileSync19, statSync as statSync7 } from "node:fs";
|
|
90691
91441
|
import path43 from "node:path";
|
|
90692
|
-
function
|
|
90693
|
-
const run =
|
|
91442
|
+
function git6(cwd, args) {
|
|
91443
|
+
const run = spawnSync20("git", ["-c", "core.quotepath=off", ...args], {
|
|
90694
91444
|
cwd,
|
|
90695
91445
|
encoding: "utf8",
|
|
90696
91446
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -90726,20 +91476,20 @@ function expandPaths(cwd, inputs) {
|
|
|
90726
91476
|
function resolveBase(cwd, base) {
|
|
90727
91477
|
const candidates = base ? [base] : ["origin/main", "main", "origin/master", "master"];
|
|
90728
91478
|
for (const candidate of candidates) {
|
|
90729
|
-
if (!
|
|
91479
|
+
if (!git6(cwd, ["rev-parse", "--verify", "--quiet", `${candidate}^{commit}`]).ok)
|
|
90730
91480
|
continue;
|
|
90731
|
-
const mergeBase =
|
|
91481
|
+
const mergeBase = git6(cwd, ["merge-base", candidate, "HEAD"]);
|
|
90732
91482
|
return mergeBase.ok ? mergeBase.stdout.trim() : null;
|
|
90733
91483
|
}
|
|
90734
91484
|
return null;
|
|
90735
91485
|
}
|
|
90736
91486
|
function changedLines(cwd, base) {
|
|
90737
|
-
const root =
|
|
91487
|
+
const root = git6(cwd, ["rev-parse", "--show-toplevel"]).stdout.trim();
|
|
90738
91488
|
const changed = new Map;
|
|
90739
|
-
const names =
|
|
91489
|
+
const names = git6(root, ["diff", "--name-only", "-z", "--no-renames", "--diff-filter=AM", base]);
|
|
90740
91490
|
for (const file of names.stdout.split("\x00").filter(Boolean)) {
|
|
90741
91491
|
const lines = new Set;
|
|
90742
|
-
const diff =
|
|
91492
|
+
const diff = git6(root, ["diff", "-U0", "--no-color", "--no-ext-diff", base, "--", file]);
|
|
90743
91493
|
for (const line of diff.stdout.split(`
|
|
90744
91494
|
`)) {
|
|
90745
91495
|
const hunk = /^@@ -\S+ \+(\d+)(?:,(\d+))? @@/.exec(line);
|
|
@@ -90752,7 +91502,7 @@ function changedLines(cwd, base) {
|
|
|
90752
91502
|
}
|
|
90753
91503
|
changed.set(path43.join(root, file), lines);
|
|
90754
91504
|
}
|
|
90755
|
-
const untracked =
|
|
91505
|
+
const untracked = git6(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
90756
91506
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
90757
91507
|
changed.set(path43.join(root, file), "all");
|
|
90758
91508
|
return changed;
|
|
@@ -90767,7 +91517,7 @@ function auditFiles(files, display) {
|
|
|
90767
91517
|
const shown = display(file);
|
|
90768
91518
|
let parsed;
|
|
90769
91519
|
try {
|
|
90770
|
-
parsed = parseSource(
|
|
91520
|
+
parsed = parseSource(readFileSync19(file, "utf8"), file);
|
|
90771
91521
|
} catch (error) {
|
|
90772
91522
|
parseErrors.push({
|
|
90773
91523
|
file: shown,
|
|
@@ -90835,7 +91585,7 @@ import {
|
|
|
90835
91585
|
mkdirSync as mkdirSync9,
|
|
90836
91586
|
mkdtempSync as mkdtempSync4,
|
|
90837
91587
|
readdirSync as readdirSync9,
|
|
90838
|
-
readFileSync as
|
|
91588
|
+
readFileSync as readFileSync20,
|
|
90839
91589
|
readlinkSync as readlinkSync3,
|
|
90840
91590
|
realpathSync as realpathSync9,
|
|
90841
91591
|
renameSync as renameSync5,
|
|
@@ -90944,7 +91694,7 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
90944
91694
|
const stat = lstatSync7(dir);
|
|
90945
91695
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
90946
91696
|
continue;
|
|
90947
|
-
const pid = Number(
|
|
91697
|
+
const pid = Number(readFileSync20(path44.join(dir, PID_FILE), "utf8"));
|
|
90948
91698
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
90949
91699
|
continue;
|
|
90950
91700
|
} catch (error) {
|
|
@@ -91022,18 +91772,18 @@ function copyWorkingTree(repo) {
|
|
|
91022
91772
|
const dir = mkdtempSync4(path44.join(os14.tmpdir(), TEMP_PREFIX));
|
|
91023
91773
|
writeFileSync9(path44.join(dir, PID_FILE), String(process.pid));
|
|
91024
91774
|
const tree = path44.join(dir, "tree");
|
|
91025
|
-
const head =
|
|
91026
|
-
if (head &&
|
|
91027
|
-
const branch =
|
|
91775
|
+
const head = git6(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
91776
|
+
if (head && git6(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
91777
|
+
const branch = git6(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
91028
91778
|
if (branch) {
|
|
91029
|
-
|
|
91030
|
-
|
|
91779
|
+
git6(tree, ["update-ref", `refs/heads/${branch}`, head]);
|
|
91780
|
+
git6(tree, ["symbolic-ref", "HEAD", `refs/heads/${branch}`]);
|
|
91031
91781
|
} else
|
|
91032
|
-
|
|
91033
|
-
|
|
91782
|
+
git6(tree, ["update-ref", "--no-deref", "HEAD", head]);
|
|
91783
|
+
git6(tree, ["reset", "-q"]);
|
|
91034
91784
|
} else
|
|
91035
91785
|
mkdirSync9(tree, { recursive: true });
|
|
91036
|
-
const listed =
|
|
91786
|
+
const listed = git6(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00");
|
|
91037
91787
|
const dirs = new Set([""]);
|
|
91038
91788
|
for (const relative of listed) {
|
|
91039
91789
|
if (!relative)
|
|
@@ -91096,10 +91846,10 @@ function runCommand(command, cwd, timeoutMs, env) {
|
|
|
91096
91846
|
async function runMutation(options) {
|
|
91097
91847
|
const started = performance.now();
|
|
91098
91848
|
const { repo } = options;
|
|
91099
|
-
const tracked =
|
|
91849
|
+
const tracked = git6(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
91100
91850
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
91101
91851
|
try {
|
|
91102
|
-
return { file, text:
|
|
91852
|
+
return { file, text: readFileSync20(path44.join(repo, file), "utf8") };
|
|
91103
91853
|
} catch {
|
|
91104
91854
|
return { file, text: "" };
|
|
91105
91855
|
}
|
|
@@ -91112,7 +91862,7 @@ async function runMutation(options) {
|
|
|
91112
91862
|
if (NOT_SOURCE.test(relative) || !existsSync19(absolute))
|
|
91113
91863
|
continue;
|
|
91114
91864
|
try {
|
|
91115
|
-
candidates.push(...mutantsFor(
|
|
91865
|
+
candidates.push(...mutantsFor(readFileSync20(absolute, "utf8"), relative, lines));
|
|
91116
91866
|
} catch {}
|
|
91117
91867
|
}
|
|
91118
91868
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -91192,7 +91942,7 @@ async function runMutation(options) {
|
|
|
91192
91942
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
91193
91943
|
continue;
|
|
91194
91944
|
}
|
|
91195
|
-
const original =
|
|
91945
|
+
const original = readFileSync20(path44.join(copy, mutant.file), "utf8");
|
|
91196
91946
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
91197
91947
|
current = { file: mutant.file, original };
|
|
91198
91948
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -91398,7 +92148,7 @@ async function run16(argv, io) {
|
|
|
91398
92148
|
if (typeof options === "string")
|
|
91399
92149
|
return emit(io, fail("invalid_input", `${options}
|
|
91400
92150
|
usage: ${USAGE9}`));
|
|
91401
|
-
const top =
|
|
92151
|
+
const top = git6(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
91402
92152
|
const repo = top.ok ? path45.resolve(top.stdout.trim()) : null;
|
|
91403
92153
|
const display = (file) => toPosix(path45.relative(io.cwd, file) || file);
|
|
91404
92154
|
let base = null;
|
|
@@ -91610,7 +92360,7 @@ var exports_youtrack = {};
|
|
|
91610
92360
|
__export(exports_youtrack, {
|
|
91611
92361
|
run: () => run17
|
|
91612
92362
|
});
|
|
91613
|
-
import { readFileSync as
|
|
92363
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
91614
92364
|
import path46 from "node:path";
|
|
91615
92365
|
async function run17(argv, io) {
|
|
91616
92366
|
const [sub, ...rest] = argv;
|
|
@@ -91657,7 +92407,7 @@ async function run17(argv, io) {
|
|
|
91657
92407
|
let markdown = flags.values.markdown ?? "";
|
|
91658
92408
|
if (flags.values.file)
|
|
91659
92409
|
try {
|
|
91660
|
-
markdown =
|
|
92410
|
+
markdown = readFileSync21(path46.resolve(io.cwd, flags.values.file), "utf8");
|
|
91661
92411
|
} catch (error) {
|
|
91662
92412
|
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE10);
|
|
91663
92413
|
}
|
|
@@ -91725,7 +92475,7 @@ var exports_changelog = {};
|
|
|
91725
92475
|
__export(exports_changelog, {
|
|
91726
92476
|
run: () => run18
|
|
91727
92477
|
});
|
|
91728
|
-
import { readFileSync as
|
|
92478
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
91729
92479
|
import path47 from "node:path";
|
|
91730
92480
|
async function run18(argv, io) {
|
|
91731
92481
|
const [sub, ...rest] = argv;
|
|
@@ -91772,7 +92522,7 @@ async function run18(argv, io) {
|
|
|
91772
92522
|
]);
|
|
91773
92523
|
}
|
|
91774
92524
|
var USAGE11 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
91775
|
-
const text = raw === "-" ?
|
|
92525
|
+
const text = raw === "-" ? readFileSync22(0, "utf8") : raw.startsWith("@") ? readFileSync22(path47.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
91776
92526
|
return JSON.parse(text);
|
|
91777
92527
|
};
|
|
91778
92528
|
var init_changelog2 = __esm(() => {
|
|
@@ -91949,7 +92699,7 @@ var VERBS = [
|
|
|
91949
92699
|
{
|
|
91950
92700
|
name: "pr",
|
|
91951
92701
|
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]",
|
|
92702
|
+
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
92703
|
summary: "PR/MR state with failing log tails and next action; open a SHA-verified PR; merge only when READY, verified and granted",
|
|
91954
92704
|
load: () => Promise.resolve().then(() => (init_pr(), exports_pr))
|
|
91955
92705
|
},
|
|
@@ -91963,7 +92713,7 @@ var VERBS = [
|
|
|
91963
92713
|
{
|
|
91964
92714
|
name: "git",
|
|
91965
92715
|
group: "delivery",
|
|
91966
|
-
usage: "workit git branch <name> [--base <b>] | git commit -m <msg> [--all | -- <paths…>] | git push [--set-upstream] [--force-with-lease]",
|
|
92716
|
+
usage: "workit git branch <name> [--base <b>] [--track <t>] | git commit -m <msg> [--all | -- <paths…>] | git push [--set-upstream] [--force-with-lease]",
|
|
91967
92717
|
summary: "Policy-checked branch and commit (Workit-Session trailer); push with a lease and a verified remote tip",
|
|
91968
92718
|
load: () => Promise.resolve().then(() => (init_git2(), exports_git))
|
|
91969
92719
|
},
|