@brainervirus/workit-claude-code 8.0.1 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/workit-hook.js +37 -36
- package/dist/workit.js +599 -322
- package/package.json +3 -3
package/dist/workit.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@brainervirus/workit-cli",
|
|
68
|
-
version: "8.0
|
|
68
|
+
version: "8.1.0",
|
|
69
69
|
private: false,
|
|
70
70
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
71
71
|
keywords: [
|
|
@@ -103,9 +103,9 @@ var init_package = __esm(() => {
|
|
|
103
103
|
},
|
|
104
104
|
dependencies: {
|
|
105
105
|
"@babel/parser": "7.29.9",
|
|
106
|
-
"@brainervirus/workit-core": "^8.0
|
|
107
|
-
"@brainervirus/workit-cursor": "^8.0
|
|
108
|
-
"@brainervirus/workit-opencode": "^8.0
|
|
106
|
+
"@brainervirus/workit-core": "^8.1.0",
|
|
107
|
+
"@brainervirus/workit-cursor": "^8.1.0",
|
|
108
|
+
"@brainervirus/workit-opencode": "^8.1.0",
|
|
109
109
|
"@inkjs/ui": "2.0.0",
|
|
110
110
|
ink: "7.1.1",
|
|
111
111
|
react: "19.2.8"
|
|
@@ -14919,60 +14919,6 @@ var init_task_context = __esm(() => {
|
|
|
14919
14919
|
privateKey = /-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?-----END [^-]*PRIVATE KEY-----/gi;
|
|
14920
14920
|
});
|
|
14921
14921
|
|
|
14922
|
-
// packages/workit-core/src/core/commit-flavors.ts
|
|
14923
|
-
var CONVENTIONAL_RE, TICKET_RE, GITMOJI_RE, matchCommitFlavor = (message, flavor, pattern) => {
|
|
14924
|
-
const subject = message.split(`
|
|
14925
|
-
`, 1)[0] ?? "";
|
|
14926
|
-
switch (flavor) {
|
|
14927
|
-
case "conventional":
|
|
14928
|
-
return CONVENTIONAL_RE.test(subject);
|
|
14929
|
-
case "gitmoji":
|
|
14930
|
-
return GITMOJI_RE.test(subject);
|
|
14931
|
-
case "ticket-prefix":
|
|
14932
|
-
return TICKET_RE.test(subject);
|
|
14933
|
-
case "freeform":
|
|
14934
|
-
return subject.trim().length > 0;
|
|
14935
|
-
case "custom":
|
|
14936
|
-
if (!pattern)
|
|
14937
|
-
return false;
|
|
14938
|
-
try {
|
|
14939
|
-
return new RegExp(pattern).test(subject);
|
|
14940
|
-
} catch {
|
|
14941
|
-
return false;
|
|
14942
|
-
}
|
|
14943
|
-
case "auto":
|
|
14944
|
-
return subject.trim().length > 0;
|
|
14945
|
-
}
|
|
14946
|
-
}, DETECTABLE, detectCommitFlavor = (subjects, threshold = 0.7) => {
|
|
14947
|
-
if (subjects.length === 0)
|
|
14948
|
-
return { flavor: null, confidence: 0 };
|
|
14949
|
-
const votes = new Map;
|
|
14950
|
-
for (const subject of subjects) {
|
|
14951
|
-
const hit = DETECTABLE.find((flavor) => matchCommitFlavor(subject, flavor));
|
|
14952
|
-
if (hit)
|
|
14953
|
-
votes.set(hit, (votes.get(hit) ?? 0) + 1);
|
|
14954
|
-
}
|
|
14955
|
-
let best = null;
|
|
14956
|
-
let count = 0;
|
|
14957
|
-
for (const [flavor, votesFor] of votes) {
|
|
14958
|
-
if (votesFor > count) {
|
|
14959
|
-
best = flavor;
|
|
14960
|
-
count = votesFor;
|
|
14961
|
-
}
|
|
14962
|
-
}
|
|
14963
|
-
const confidence = count / subjects.length;
|
|
14964
|
-
return best !== null && confidence >= threshold ? { flavor: best, confidence } : { flavor: null, confidence };
|
|
14965
|
-
};
|
|
14966
|
-
var init_commit_flavors = __esm(() => {
|
|
14967
|
-
CONVENTIONAL_RE = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .+/;
|
|
14968
|
-
TICKET_RE = /^[A-Z]{2,}-\d+\b/;
|
|
14969
|
-
GITMOJI_RE = /^\p{Extended_Pictographic}/u;
|
|
14970
|
-
DETECTABLE = ["conventional", "gitmoji", "ticket-prefix"];
|
|
14971
|
-
});
|
|
14972
|
-
|
|
14973
|
-
// packages/workit-core/src/core/git.ts
|
|
14974
|
-
var init_git = () => {};
|
|
14975
|
-
|
|
14976
14922
|
// packages/workit-core/src/core/boundary.ts
|
|
14977
14923
|
var EVENT, errorDetail = (err) => {
|
|
14978
14924
|
if (err instanceof Error) {
|
|
@@ -15057,7 +15003,7 @@ var diagnosticLogger, setDiagnosticLogger = (logger) => {
|
|
|
15057
15003
|
if (!migrationFailed)
|
|
15058
15004
|
migratedDir = dir;
|
|
15059
15005
|
return dir;
|
|
15060
|
-
}, configDir = () => ensureConfigDir(), LOCALE_RE, DEFAULTS, readSafe = (p) => {
|
|
15006
|
+
}, configDir = () => ensureConfigDir(), LOCALE_RE, DEFAULTS, unchosenBranchPolicy, readSafe = (p) => {
|
|
15061
15007
|
try {
|
|
15062
15008
|
return readFileSync3(p, "utf8");
|
|
15063
15009
|
} catch {
|
|
@@ -15079,22 +15025,21 @@ var diagnosticLogger, setDiagnosticLogger = (logger) => {
|
|
|
15079
15025
|
const locale = LOCALE_RE.test(String(input.locale ?? "")) ? input.locale : DEFAULTS.locale;
|
|
15080
15026
|
const preset = Object.hasOwn(PRESETS, input.branchPolicy?.preset) ? input.branchPolicy?.preset : "gitflow";
|
|
15081
15027
|
const commitPreset = COMMIT_PRESETS.includes(String(input.commitPolicy?.preset ?? "")) ? input.commitPolicy?.preset : "conventional";
|
|
15082
|
-
|
|
15083
|
-
|
|
15084
|
-
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
|
|
15089
|
-
|
|
15090
|
-
|
|
15091
|
-
}
|
|
15092
|
-
commitPolicy: {
|
|
15093
|
-
preset: commitPreset,
|
|
15094
|
-
...typeof input.commitPolicy?.pattern === "string" ? { pattern: input.commitPolicy.pattern } : {}
|
|
15095
|
-
}
|
|
15028
|
+
const config = {
|
|
15029
|
+
locale,
|
|
15030
|
+
localeOptions: Array.isArray(input.localeOptions) ? input.localeOptions : DEFAULTS.localeOptions,
|
|
15031
|
+
branchPolicy: mergePreset(preset, {
|
|
15032
|
+
allowed: Array.isArray(input.branchPolicy?.allowed) ? input.branchPolicy.allowed : undefined,
|
|
15033
|
+
protectedNames: Array.isArray(input.branchPolicy?.protected) ? input.branchPolicy.protected : undefined
|
|
15034
|
+
}, DEFAULTS),
|
|
15035
|
+
commitPolicy: {
|
|
15036
|
+
preset: commitPreset,
|
|
15037
|
+
...typeof input.commitPolicy?.pattern === "string" ? { pattern: input.commitPolicy.pattern } : {}
|
|
15096
15038
|
}
|
|
15097
15039
|
};
|
|
15040
|
+
if (!Object.hasOwn(PRESETS, input.branchPolicy?.preset))
|
|
15041
|
+
unchosenBranchPolicy.add(config);
|
|
15042
|
+
return { status: "valid", path: file, config };
|
|
15098
15043
|
}, readConfigTyped = (dir) => {
|
|
15099
15044
|
const file = path13.join(dir ?? configDir(), "config.json");
|
|
15100
15045
|
return parseConfigResult(readSafe(file), file);
|
|
@@ -15108,9 +15053,11 @@ var diagnosticLogger, setDiagnosticLogger = (logger) => {
|
|
|
15108
15053
|
if (result.status === "malformed")
|
|
15109
15054
|
throw new Error(result.error);
|
|
15110
15055
|
return result.config ?? DEFAULTS;
|
|
15111
|
-
}, vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path13.join(configDir(), "vcs.json"), branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"), resolveBranchPolicy = (config, workspace) => {
|
|
15056
|
+
}, vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path13.join(configDir(), "vcs.json"), branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"), resolveBranchPolicy = (config, workspace, repoPreset) => {
|
|
15112
15057
|
const wp = workspace?.branchPolicy ?? {};
|
|
15113
|
-
const
|
|
15058
|
+
const workspacePreset = Object.hasOwn(PRESETS, wp.preset);
|
|
15059
|
+
const detected = !workspacePreset && unchosenBranchPolicy.has(config) ? repoPreset?.() ?? null : null;
|
|
15060
|
+
const preset = workspacePreset ? wp.preset : detected ?? config.branchPolicy?.preset ?? "gitflow";
|
|
15114
15061
|
const merged = mergePreset(preset, {
|
|
15115
15062
|
allowed: wp.allowed,
|
|
15116
15063
|
protectedNames: wp.protected
|
|
@@ -15119,9 +15066,10 @@ var diagnosticLogger, setDiagnosticLogger = (logger) => {
|
|
|
15119
15066
|
return {
|
|
15120
15067
|
preset,
|
|
15121
15068
|
allowed,
|
|
15122
|
-
protected: new Set(merged.protected.map((p) => p.toLowerCase())),
|
|
15069
|
+
protected: new Set([...merged.protected, ...detected ? PRESETS.gitflow.protected : []].map((p) => p.toLowerCase())),
|
|
15123
15070
|
integration: wp.integration === "merge" ? "merge" : "pr",
|
|
15124
|
-
defaultTargetBranch: preset === "github-flow" ? "main" : preset === "trunk-based" ? "master" : "develop"
|
|
15071
|
+
defaultTargetBranch: preset === "github-flow" ? "main" : preset === "trunk-based" ? "master" : "develop",
|
|
15072
|
+
detected: detected !== null
|
|
15125
15073
|
};
|
|
15126
15074
|
}, COMMIT_PRESETS, resolveCommitPolicy = (config, workspace) => {
|
|
15127
15075
|
const wp = workspace?.commitPolicy ?? {};
|
|
@@ -15155,6 +15103,7 @@ var init_config = __esm(() => {
|
|
|
15155
15103
|
},
|
|
15156
15104
|
commitPolicy: { preset: "conventional" }
|
|
15157
15105
|
};
|
|
15106
|
+
unchosenBranchPolicy = new WeakSet([DEFAULTS]);
|
|
15158
15107
|
COMMIT_PRESETS = [
|
|
15159
15108
|
"conventional",
|
|
15160
15109
|
"gitmoji",
|
|
@@ -15165,6 +15114,126 @@ var init_config = __esm(() => {
|
|
|
15165
15114
|
];
|
|
15166
15115
|
});
|
|
15167
15116
|
|
|
15117
|
+
// packages/workit-core/src/core/branch-policy.ts
|
|
15118
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
15119
|
+
var PREFIXES, branchNames = (workspaceRoot) => {
|
|
15120
|
+
const r = spawnSync7("git", ["for-each-ref", "--format=%(refname)", "refs/heads", "refs/remotes/origin"], { cwd: workspaceRoot, encoding: "utf8" });
|
|
15121
|
+
if (r.status !== 0)
|
|
15122
|
+
return new Set;
|
|
15123
|
+
return new Set((r.stdout ?? "").split(`
|
|
15124
|
+
`).filter(Boolean).map((ref) => ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref.slice("refs/remotes/origin/".length)));
|
|
15125
|
+
}, detectBranchPolicy = (workspaceRoot) => {
|
|
15126
|
+
const names = branchNames(workspaceRoot);
|
|
15127
|
+
const develop = names.has("develop");
|
|
15128
|
+
const main = names.has("main");
|
|
15129
|
+
const master = names.has("master");
|
|
15130
|
+
const root = main ? "main" : master ? "master" : null;
|
|
15131
|
+
if (develop) {
|
|
15132
|
+
return {
|
|
15133
|
+
preset: "gitflow",
|
|
15134
|
+
developBranch: "develop",
|
|
15135
|
+
integration: "merge",
|
|
15136
|
+
protected: root ? [root, "develop"] : ["develop"],
|
|
15137
|
+
allowed: [...PRESETS.gitflow.allowed],
|
|
15138
|
+
prefixes: PREFIXES
|
|
15139
|
+
};
|
|
15140
|
+
}
|
|
15141
|
+
if (root === "main") {
|
|
15142
|
+
return {
|
|
15143
|
+
preset: "github-flow",
|
|
15144
|
+
developBranch: null,
|
|
15145
|
+
integration: "pr",
|
|
15146
|
+
protected: [root],
|
|
15147
|
+
allowed: ["*"],
|
|
15148
|
+
prefixes: PREFIXES
|
|
15149
|
+
};
|
|
15150
|
+
}
|
|
15151
|
+
if (root === "master") {
|
|
15152
|
+
return {
|
|
15153
|
+
preset: "trunk-based",
|
|
15154
|
+
developBranch: null,
|
|
15155
|
+
integration: "pr",
|
|
15156
|
+
protected: [root],
|
|
15157
|
+
allowed: ["*"],
|
|
15158
|
+
prefixes: PREFIXES
|
|
15159
|
+
};
|
|
15160
|
+
}
|
|
15161
|
+
return {
|
|
15162
|
+
preset: "gitflow",
|
|
15163
|
+
developBranch: null,
|
|
15164
|
+
integration: "merge",
|
|
15165
|
+
protected: [],
|
|
15166
|
+
allowed: [],
|
|
15167
|
+
prefixes: PREFIXES
|
|
15168
|
+
};
|
|
15169
|
+
}, repoBranchPreset = (workspaceRoot) => {
|
|
15170
|
+
const detected = detectBranchPolicy(workspaceRoot);
|
|
15171
|
+
return detected.developBranch || detected.allowed.length ? detected.preset : null;
|
|
15172
|
+
};
|
|
15173
|
+
var init_branch_policy = __esm(() => {
|
|
15174
|
+
init_config();
|
|
15175
|
+
PREFIXES = {
|
|
15176
|
+
feature: "feature/*",
|
|
15177
|
+
bugfix: "bugfix/*",
|
|
15178
|
+
release: "release/*",
|
|
15179
|
+
hotfix: "hotfix/*"
|
|
15180
|
+
};
|
|
15181
|
+
});
|
|
15182
|
+
|
|
15183
|
+
// packages/workit-core/src/core/commit-flavors.ts
|
|
15184
|
+
var CONVENTIONAL_RE, TICKET_RE, GITMOJI_RE, matchCommitFlavor = (message, flavor, pattern) => {
|
|
15185
|
+
const subject = message.split(`
|
|
15186
|
+
`, 1)[0] ?? "";
|
|
15187
|
+
switch (flavor) {
|
|
15188
|
+
case "conventional":
|
|
15189
|
+
return CONVENTIONAL_RE.test(subject);
|
|
15190
|
+
case "gitmoji":
|
|
15191
|
+
return GITMOJI_RE.test(subject);
|
|
15192
|
+
case "ticket-prefix":
|
|
15193
|
+
return TICKET_RE.test(subject);
|
|
15194
|
+
case "freeform":
|
|
15195
|
+
return subject.trim().length > 0;
|
|
15196
|
+
case "custom":
|
|
15197
|
+
if (!pattern)
|
|
15198
|
+
return false;
|
|
15199
|
+
try {
|
|
15200
|
+
return new RegExp(pattern).test(subject);
|
|
15201
|
+
} catch {
|
|
15202
|
+
return false;
|
|
15203
|
+
}
|
|
15204
|
+
case "auto":
|
|
15205
|
+
return subject.trim().length > 0;
|
|
15206
|
+
}
|
|
15207
|
+
}, DETECTABLE, detectCommitFlavor = (subjects, threshold = 0.7) => {
|
|
15208
|
+
if (subjects.length === 0)
|
|
15209
|
+
return { flavor: null, confidence: 0 };
|
|
15210
|
+
const votes = new Map;
|
|
15211
|
+
for (const subject of subjects) {
|
|
15212
|
+
const hit = DETECTABLE.find((flavor) => matchCommitFlavor(subject, flavor));
|
|
15213
|
+
if (hit)
|
|
15214
|
+
votes.set(hit, (votes.get(hit) ?? 0) + 1);
|
|
15215
|
+
}
|
|
15216
|
+
let best = null;
|
|
15217
|
+
let count = 0;
|
|
15218
|
+
for (const [flavor, votesFor] of votes) {
|
|
15219
|
+
if (votesFor > count) {
|
|
15220
|
+
best = flavor;
|
|
15221
|
+
count = votesFor;
|
|
15222
|
+
}
|
|
15223
|
+
}
|
|
15224
|
+
const confidence = count / subjects.length;
|
|
15225
|
+
return best !== null && confidence >= threshold ? { flavor: best, confidence } : { flavor: null, confidence };
|
|
15226
|
+
};
|
|
15227
|
+
var init_commit_flavors = __esm(() => {
|
|
15228
|
+
CONVENTIONAL_RE = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .+/;
|
|
15229
|
+
TICKET_RE = /^[A-Z]{2,}-\d+\b/;
|
|
15230
|
+
GITMOJI_RE = /^\p{Extended_Pictographic}/u;
|
|
15231
|
+
DETECTABLE = ["conventional", "gitmoji", "ticket-prefix"];
|
|
15232
|
+
});
|
|
15233
|
+
|
|
15234
|
+
// packages/workit-core/src/core/git.ts
|
|
15235
|
+
var init_git = () => {};
|
|
15236
|
+
|
|
15168
15237
|
// packages/workit-core/src/core/workspaces.ts
|
|
15169
15238
|
import { createHash as createHash8 } from "node:crypto";
|
|
15170
15239
|
import { readFileSync as readFileSync4, realpathSync as realpathSync3 } from "node:fs";
|
|
@@ -15174,7 +15243,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
|
|
|
15174
15243
|
const wp = ws?.branchPolicy ?? {};
|
|
15175
15244
|
const hasWorkspacePolicy = typeof wp.preset === "string" && Object.hasOwn(PRESETS, wp.preset);
|
|
15176
15245
|
const selected = resolveRuntimeWorkspacePolicy(cwd, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
15177
|
-
const policyDefault = resolveBranchPolicy(readConfig(), selected.policy ? { branchPolicy: selected.policy } : null).defaultTargetBranch;
|
|
15246
|
+
const policyDefault = resolveBranchPolicy(readConfig(), selected.policy ? { branchPolicy: selected.policy } : null, () => repoBranchPreset(cwd)).defaultTargetBranch;
|
|
15178
15247
|
return String(ws?.vcs?.defaultTargetBranch ?? (hasWorkspacePolicy ? policyDefault : globalDefault ?? policyDefault) ?? "develop");
|
|
15179
15248
|
}
|
|
15180
15249
|
var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspaceCommitPolicySchema, workspaceProfileSchema, versionSourceSchema, releaseTrackSchema, workspaceConfigSchema, workspacesFileSchema, workspacesRevision = (contents) => createHash8("sha256").update(contents ?? "<missing>").digest("hex"), validateWorkspacesDocument = (parsed, file) => {
|
|
@@ -15456,7 +15525,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
15456
15525
|
commitPolicy: profile?.commitPolicy ? `profile:${profileName}` : workspace.commitPolicy ? `workspace:${workspace.name}` : "user-default"
|
|
15457
15526
|
}
|
|
15458
15527
|
};
|
|
15459
|
-
}, resolveWorkspacePolicy = (config, workspace, profileName) => {
|
|
15528
|
+
}, resolveWorkspacePolicy = (config, workspace, profileName, repoPreset) => {
|
|
15460
15529
|
const selected = workspace ? resolveWorkspaceProfile(workspace, profileName) : {
|
|
15461
15530
|
status: "resolved",
|
|
15462
15531
|
profileName: null,
|
|
@@ -15469,7 +15538,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
15469
15538
|
status: "resolved",
|
|
15470
15539
|
workspace: selected.workspace,
|
|
15471
15540
|
profileName: selected.profileName,
|
|
15472
|
-
branchPolicy: resolveBranchPolicy(config, selected.workspace),
|
|
15541
|
+
branchPolicy: resolveBranchPolicy(config, selected.workspace, repoPreset),
|
|
15473
15542
|
commitPolicy: resolveCommitPolicy(config, selected.workspace),
|
|
15474
15543
|
provenance: selected.provenance
|
|
15475
15544
|
};
|
|
@@ -15477,6 +15546,7 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
|
|
|
15477
15546
|
var init_workspaces = __esm(() => {
|
|
15478
15547
|
init_zod();
|
|
15479
15548
|
init_config();
|
|
15549
|
+
init_branch_policy();
|
|
15480
15550
|
nonBlank = string2().refine((value) => value.trim().length > 0, "must not be blank");
|
|
15481
15551
|
branchPreset = custom((value) => typeof value === "string" && Object.hasOwn(PRESETS, value), "unsupported branch preset");
|
|
15482
15552
|
commitPreset = custom((value) => typeof value === "string" && COMMIT_PRESETS.includes(value), "unsupported commit preset");
|
|
@@ -15603,7 +15673,7 @@ var init_workspaces = __esm(() => {
|
|
|
15603
15673
|
|
|
15604
15674
|
// packages/workit-core/src/core/release-tracks.ts
|
|
15605
15675
|
import { createHash as createHash9 } from "node:crypto";
|
|
15606
|
-
import { spawnSync as
|
|
15676
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
15607
15677
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
15608
15678
|
function readReleaseTracks(raw) {
|
|
15609
15679
|
const out = { tracks: [], issues: [], error: null, protectedBranches: [] };
|
|
@@ -16005,7 +16075,7 @@ var ReleaseTrackError, KNOWN_FIELDS, BRANCH_FIELDS, PLACEHOLDER, HAS_PLACEHOLDER
|
|
|
16005
16075
|
const remote = remotes.find((name) => bare.startsWith(`${name}/`));
|
|
16006
16076
|
return remote ? bare.slice(remote.length + 1) : bare;
|
|
16007
16077
|
}, MAX_RECORDED_HOPS = 10, git4 = (cwd, args) => {
|
|
16008
|
-
const run =
|
|
16078
|
+
const run = spawnSync8("git", args, {
|
|
16009
16079
|
cwd,
|
|
16010
16080
|
encoding: "utf8",
|
|
16011
16081
|
timeout: 20000,
|
|
@@ -16066,7 +16136,7 @@ var init_release_tracks = __esm(() => {
|
|
|
16066
16136
|
// packages/workit-core/src/core/vcs-config.ts
|
|
16067
16137
|
import fs12 from "node:fs";
|
|
16068
16138
|
import path15 from "node:path";
|
|
16069
|
-
import { spawnSync as
|
|
16139
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
16070
16140
|
function vcsConfig(mode, cwd, options = {}) {
|
|
16071
16141
|
const ws = resolveRuntimeWorkspaceVcs(vcsCwd(cwd));
|
|
16072
16142
|
const wsVcs = ws?.vcs ?? {};
|
|
@@ -16149,7 +16219,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
16149
16219
|
return out;
|
|
16150
16220
|
}
|
|
16151
16221
|
var workspacesPath = () => path15.join(configDir(), "workspaces.json"), vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd(), remoteProvider = (cwd) => {
|
|
16152
|
-
const r =
|
|
16222
|
+
const r = spawnSync9("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
16153
16223
|
if (r.status !== 0)
|
|
16154
16224
|
return null;
|
|
16155
16225
|
const url = (r.stdout ?? "").trim();
|
|
@@ -16199,7 +16269,7 @@ function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
|
16199
16269
|
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
16200
16270
|
const config = readConfig();
|
|
16201
16271
|
return kind === "branch" ? {
|
|
16202
|
-
branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null)),
|
|
16272
|
+
branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null, () => repoBranchPreset(workspaceRoot))),
|
|
16203
16273
|
provenance: { branchPolicy: selected.source }
|
|
16204
16274
|
} : {
|
|
16205
16275
|
commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
|
|
@@ -16356,6 +16426,7 @@ var withReleaseTracks = (workspaceRoot, policy) => {
|
|
|
16356
16426
|
return dirty ? "carry" : "clean";
|
|
16357
16427
|
};
|
|
16358
16428
|
var init_branch = __esm(() => {
|
|
16429
|
+
init_branch_policy();
|
|
16359
16430
|
init_commit_flavors();
|
|
16360
16431
|
init_git();
|
|
16361
16432
|
init_config();
|
|
@@ -18464,7 +18535,7 @@ var init_pr_body = __esm(() => {
|
|
|
18464
18535
|
|
|
18465
18536
|
// packages/workit-core/src/core/pr-create.ts
|
|
18466
18537
|
import path19 from "node:path";
|
|
18467
|
-
import { spawnSync as
|
|
18538
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
18468
18539
|
import { pathToFileURL } from "node:url";
|
|
18469
18540
|
var safePushUrl = (remote) => {
|
|
18470
18541
|
const raw = remote.trim();
|
|
@@ -18492,7 +18563,7 @@ var safePushUrl = (remote) => {
|
|
|
18492
18563
|
const target = safePushUrl(remote);
|
|
18493
18564
|
if (!target)
|
|
18494
18565
|
return false;
|
|
18495
|
-
const result =
|
|
18566
|
+
const result = spawnSync10("git", ["config", "--get-regexp", "^url\\..*\\.(insteadof|pushinsteadof)$"], { cwd, encoding: "utf8" });
|
|
18496
18567
|
if (result.status !== 0 && result.status !== 1)
|
|
18497
18568
|
return false;
|
|
18498
18569
|
const prefixes = (result.stdout ?? "").split(/\r?\n/u).map((line) => line.trim().slice(line.trim().indexOf(" ") + 1)).filter(Boolean);
|
|
@@ -62780,7 +62851,7 @@ var init_support_matrix = __esm(() => {
|
|
|
62780
62851
|
});
|
|
62781
62852
|
|
|
62782
62853
|
// packages/workit-cli/src/admin/host-install.ts
|
|
62783
|
-
import { spawnSync as
|
|
62854
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
62784
62855
|
import {
|
|
62785
62856
|
accessSync,
|
|
62786
62857
|
constants as constants2,
|
|
@@ -63051,7 +63122,7 @@ function runHostCommand(step, context = {}) {
|
|
|
63051
63122
|
stderr: `Cannot safely execute batch shim ${step.command}; resolve its Node.js CLI entrypoint and retry`
|
|
63052
63123
|
};
|
|
63053
63124
|
}
|
|
63054
|
-
const result =
|
|
63125
|
+
const result = spawnSync11(step.command, step.args, {
|
|
63055
63126
|
cwd: step.cwd,
|
|
63056
63127
|
env: (() => {
|
|
63057
63128
|
const home = context.home ?? context.env?.HOME ?? os6.homedir();
|
|
@@ -63256,7 +63327,7 @@ var init_skill_manifests = __esm(() => {
|
|
|
63256
63327
|
});
|
|
63257
63328
|
|
|
63258
63329
|
// packages/workit-cli/src/admin/doctor.ts
|
|
63259
|
-
import { spawnSync as
|
|
63330
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
63260
63331
|
import {
|
|
63261
63332
|
existsSync as existsSync13,
|
|
63262
63333
|
lstatSync as lstatSync4,
|
|
@@ -63340,7 +63411,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63340
63411
|
}
|
|
63341
63412
|
return false;
|
|
63342
63413
|
}, versionOf = (bin, env, timeout) => {
|
|
63343
|
-
const r =
|
|
63414
|
+
const r = spawnSync12(bin, ["--version"], { encoding: "utf8", env, timeout });
|
|
63344
63415
|
if (r.error)
|
|
63345
63416
|
return null;
|
|
63346
63417
|
return (r.stdout ?? "").trim();
|
|
@@ -63589,7 +63660,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63589
63660
|
`)) {
|
|
63590
63661
|
return false;
|
|
63591
63662
|
}
|
|
63592
|
-
return
|
|
63663
|
+
return spawnSync12(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
|
|
63593
63664
|
} catch {
|
|
63594
63665
|
return false;
|
|
63595
63666
|
}
|
|
@@ -63803,7 +63874,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63803
63874
|
if (!cmd)
|
|
63804
63875
|
return null;
|
|
63805
63876
|
try {
|
|
63806
|
-
const r =
|
|
63877
|
+
const r = spawnSync12(cmd, ["view", pkgName, "version"], {
|
|
63807
63878
|
encoding: "utf8",
|
|
63808
63879
|
timeout: 20000,
|
|
63809
63880
|
env: res.env
|
|
@@ -64087,6 +64158,16 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64087
64158
|
detail: `malformed config: ${bad.join(", ")}`,
|
|
64088
64159
|
fix: `Repair the malformed config in ${bad[0]}`
|
|
64089
64160
|
};
|
|
64161
|
+
}, branchPresetLine = (res, workspace) => {
|
|
64162
|
+
try {
|
|
64163
|
+
const resolved = resolveWorkspacePolicy(readConfigFromDir(res.configDir), workspace, undefined, () => repoBranchPreset(res.cwd));
|
|
64164
|
+
if (resolved.status === "invalid")
|
|
64165
|
+
return [];
|
|
64166
|
+
const { preset, detected } = resolved.branchPolicy;
|
|
64167
|
+
return [`preset: ${detected ? `detected (${preset})` : preset}`];
|
|
64168
|
+
} catch {
|
|
64169
|
+
return [];
|
|
64170
|
+
}
|
|
64090
64171
|
}, checkWorkspaceMismatch = (res) => {
|
|
64091
64172
|
const result = readWorkspacesResult(res.configDir);
|
|
64092
64173
|
const file = result.path;
|
|
@@ -64094,7 +64175,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64094
64175
|
return {
|
|
64095
64176
|
id: "workspace_mismatch",
|
|
64096
64177
|
status: "pass",
|
|
64097
|
-
detail: "no workspaces configured"
|
|
64178
|
+
detail: ["no workspaces configured", ...branchPresetLine(res, null)].join("; ")
|
|
64098
64179
|
};
|
|
64099
64180
|
if (result.status === "malformed" || result.status === "invalid")
|
|
64100
64181
|
return {
|
|
@@ -64118,7 +64199,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64118
64199
|
const matched = `current directory matches workspace "${match.name}"`;
|
|
64119
64200
|
const tracks = releaseTracksReport(res.cwd);
|
|
64120
64201
|
const lines = describeReleaseTracks(tracks);
|
|
64121
|
-
const detail = [matched, ...lines].join("; ");
|
|
64202
|
+
const detail = [matched, ...branchPresetLine(res, match), ...lines].join("; ");
|
|
64122
64203
|
if (tracks.error)
|
|
64123
64204
|
return {
|
|
64124
64205
|
id: "workspace_mismatch",
|
|
@@ -64232,7 +64313,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64232
64313
|
}, defaultIdentityProbes = (env) => ({
|
|
64233
64314
|
origin: (cwd) => {
|
|
64234
64315
|
try {
|
|
64235
|
-
const out =
|
|
64316
|
+
const out = spawnSync12("git", ["remote", "get-url", "origin"], {
|
|
64236
64317
|
cwd,
|
|
64237
64318
|
encoding: "utf8",
|
|
64238
64319
|
env
|
|
@@ -64244,7 +64325,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64244
64325
|
},
|
|
64245
64326
|
ghLogin: (e) => {
|
|
64246
64327
|
try {
|
|
64247
|
-
const out =
|
|
64328
|
+
const out = spawnSync12("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
|
|
64248
64329
|
const login = (out.stdout ?? "").trim();
|
|
64249
64330
|
return out.status === 0 && login ? login : null;
|
|
64250
64331
|
} catch {
|
|
@@ -64253,7 +64334,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64253
64334
|
},
|
|
64254
64335
|
glabLogin: (e) => {
|
|
64255
64336
|
try {
|
|
64256
|
-
const out =
|
|
64337
|
+
const out = spawnSync12("glab", ["api", "user", "--jq", ".username"], {
|
|
64257
64338
|
encoding: "utf8",
|
|
64258
64339
|
env: e
|
|
64259
64340
|
});
|
|
@@ -64265,7 +64346,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64265
64346
|
},
|
|
64266
64347
|
sshLogin: (host) => {
|
|
64267
64348
|
try {
|
|
64268
|
-
const out =
|
|
64349
|
+
const out = spawnSync12("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
|
|
64269
64350
|
encoding: "utf8",
|
|
64270
64351
|
env
|
|
64271
64352
|
});
|
|
@@ -64460,6 +64541,7 @@ var init_doctor = __esm(() => {
|
|
|
64460
64541
|
init_runtime_identity();
|
|
64461
64542
|
init_boundary();
|
|
64462
64543
|
init_release_tracks();
|
|
64544
|
+
init_branch_policy();
|
|
64463
64545
|
init_config();
|
|
64464
64546
|
init_package_root();
|
|
64465
64547
|
init_registration();
|
|
@@ -65473,69 +65555,6 @@ var init_setup = __esm(() => {
|
|
|
65473
65555
|
SETUP_OVERRIDES = [...YT_OVERRIDES, ...VCS_OVERRIDES];
|
|
65474
65556
|
});
|
|
65475
65557
|
|
|
65476
|
-
// packages/workit-core/src/core/branch-policy.ts
|
|
65477
|
-
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
65478
|
-
var PREFIXES, detectBranchPolicy = (workspaceRoot) => {
|
|
65479
|
-
const branchExists = (name) => {
|
|
65480
|
-
const r = spawnSync12("git", ["branch", "--list", name], {
|
|
65481
|
-
cwd: workspaceRoot,
|
|
65482
|
-
encoding: "utf8"
|
|
65483
|
-
});
|
|
65484
|
-
return r.status === 0 && (r.stdout ?? "").trim() !== "";
|
|
65485
|
-
};
|
|
65486
|
-
const develop = branchExists("develop");
|
|
65487
|
-
const main = branchExists("main");
|
|
65488
|
-
const master = branchExists("master");
|
|
65489
|
-
const root = main ? "main" : master ? "master" : null;
|
|
65490
|
-
if (develop) {
|
|
65491
|
-
return {
|
|
65492
|
-
preset: "gitflow",
|
|
65493
|
-
developBranch: "develop",
|
|
65494
|
-
integration: "merge",
|
|
65495
|
-
protected: root ? [root, "develop"] : ["develop"],
|
|
65496
|
-
allowed: [...PRESETS.gitflow.allowed],
|
|
65497
|
-
prefixes: PREFIXES
|
|
65498
|
-
};
|
|
65499
|
-
}
|
|
65500
|
-
if (root === "main") {
|
|
65501
|
-
return {
|
|
65502
|
-
preset: "github-flow",
|
|
65503
|
-
developBranch: null,
|
|
65504
|
-
integration: "pr",
|
|
65505
|
-
protected: [root],
|
|
65506
|
-
allowed: ["*"],
|
|
65507
|
-
prefixes: PREFIXES
|
|
65508
|
-
};
|
|
65509
|
-
}
|
|
65510
|
-
if (root === "master") {
|
|
65511
|
-
return {
|
|
65512
|
-
preset: "trunk-based",
|
|
65513
|
-
developBranch: null,
|
|
65514
|
-
integration: "pr",
|
|
65515
|
-
protected: [root],
|
|
65516
|
-
allowed: ["*"],
|
|
65517
|
-
prefixes: PREFIXES
|
|
65518
|
-
};
|
|
65519
|
-
}
|
|
65520
|
-
return {
|
|
65521
|
-
preset: "gitflow",
|
|
65522
|
-
developBranch: null,
|
|
65523
|
-
integration: "merge",
|
|
65524
|
-
protected: [],
|
|
65525
|
-
allowed: [],
|
|
65526
|
-
prefixes: PREFIXES
|
|
65527
|
-
};
|
|
65528
|
-
};
|
|
65529
|
-
var init_branch_policy = __esm(() => {
|
|
65530
|
-
init_config();
|
|
65531
|
-
PREFIXES = {
|
|
65532
|
-
feature: "feature/*",
|
|
65533
|
-
bugfix: "bugfix/*",
|
|
65534
|
-
release: "release/*",
|
|
65535
|
-
hotfix: "hotfix/*"
|
|
65536
|
-
};
|
|
65537
|
-
});
|
|
65538
|
-
|
|
65539
65558
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
65540
65559
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "node:fs";
|
|
65541
65560
|
import path31 from "node:path";
|
|
@@ -68624,7 +68643,7 @@ function Screen({
|
|
|
68624
68643
|
};
|
|
68625
68644
|
const checkout = resolveBasePath(draft.values);
|
|
68626
68645
|
const workspace = resolveWorkspaceFromEntries(checkout, draft.values.workspaces);
|
|
68627
|
-
const resolved = resolveWorkspacePolicy(config, workspace);
|
|
68646
|
+
const resolved = resolveWorkspacePolicy(config, workspace, undefined, () => repoBranchPreset(checkout));
|
|
68628
68647
|
if (resolved.status === "invalid")
|
|
68629
68648
|
return { error: resolved.error };
|
|
68630
68649
|
return {
|
|
@@ -71425,6 +71444,46 @@ var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock)
|
|
|
71425
71444
|
|
|
71426
71445
|
// packages/workit-core/src/git/ops.ts
|
|
71427
71446
|
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
71447
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
|
|
71448
|
+
import path39 from "node:path";
|
|
71449
|
+
function operationInProgress(cwd) {
|
|
71450
|
+
const markers = [
|
|
71451
|
+
["rebase-merge", "rebase"],
|
|
71452
|
+
["rebase-apply", "rebase"],
|
|
71453
|
+
["MERGE_HEAD", "merge"],
|
|
71454
|
+
["CHERRY_PICK_HEAD", "cherry-pick"],
|
|
71455
|
+
["REVERT_HEAD", "revert"]
|
|
71456
|
+
];
|
|
71457
|
+
const run = git5(cwd, ["rev-parse", ...markers.flatMap(([name]) => ["--git-path", name])]);
|
|
71458
|
+
if (!run.ok)
|
|
71459
|
+
return null;
|
|
71460
|
+
const found = run.stdout.split(`
|
|
71461
|
+
`).map((line) => path39.resolve(cwd, line.trim()));
|
|
71462
|
+
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
71463
|
+
for (const [index, [, operation]] of markers.entries()) {
|
|
71464
|
+
const marker = found[index];
|
|
71465
|
+
if (!marker || !existsSync18(marker))
|
|
71466
|
+
continue;
|
|
71467
|
+
if (index === 1 && existsSync18(path39.join(marker, "applying")))
|
|
71468
|
+
return { operation: "am", commitAllowed: false, branch: null };
|
|
71469
|
+
if (index === 0 && existsSync18(path39.join(marker, "amend")) && !conflicted()) {
|
|
71470
|
+
let headName = "";
|
|
71471
|
+
try {
|
|
71472
|
+
headName = readFileSync18(path39.join(marker, "head-name"), "utf8").trim();
|
|
71473
|
+
} catch {}
|
|
71474
|
+
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
71475
|
+
return { operation, commitAllowed: branch !== null, branch };
|
|
71476
|
+
}
|
|
71477
|
+
if ((operation === "revert" || operation === "merge") && !conflicted())
|
|
71478
|
+
return { operation, commitAllowed: true, branch: null };
|
|
71479
|
+
return { operation, commitAllowed: false, branch: null };
|
|
71480
|
+
}
|
|
71481
|
+
return null;
|
|
71482
|
+
}
|
|
71483
|
+
function inProgressFailure(operation, verb) {
|
|
71484
|
+
const command = operation === "am" ? "git am" : `git ${operation}`;
|
|
71485
|
+
return failure3("blocked", `${operation.replace("-", "_")}_in_progress: a ${operation === "am" ? "git am" : operation} is in progress; finish or abort it before workit can ${verb}`, `resolve the conflicts, git add <files>, then ${command} --continue # or ${command} --abort to return to where you started`);
|
|
71486
|
+
}
|
|
71428
71487
|
function dirtEntries(cwd) {
|
|
71429
71488
|
const run = git5(cwd, ["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
|
|
71430
71489
|
if (!run.ok)
|
|
@@ -71444,6 +71503,9 @@ function dirtEntries(cwd) {
|
|
|
71444
71503
|
function gitBranch(cwd, input) {
|
|
71445
71504
|
if (!headSha(cwd) && currentBranch(cwd) === null)
|
|
71446
71505
|
return failure3("invalid_input", "not inside a git repository with a commit");
|
|
71506
|
+
const progress = operationInProgress(cwd);
|
|
71507
|
+
if (progress)
|
|
71508
|
+
return inProgressFailure(progress.operation, "create a branch");
|
|
71447
71509
|
const explicitBase = input.base?.trim() || null;
|
|
71448
71510
|
const resolved = vcsConfig("resolve", cwd, {
|
|
71449
71511
|
track: input.track ?? null,
|
|
@@ -71548,53 +71610,156 @@ function lintCommitMessage(cwd, message) {
|
|
|
71548
71610
|
correction: `use a ${detected} commit subject`
|
|
71549
71611
|
};
|
|
71550
71612
|
}
|
|
71613
|
+
function messageTrailers(cwd, message) {
|
|
71614
|
+
const run = git5(cwd, [...TRAILER_CONFIG, "interpret-trailers", "--parse", "--no-divider"], {
|
|
71615
|
+
input: `${message}
|
|
71616
|
+
`
|
|
71617
|
+
});
|
|
71618
|
+
return run.ok ? run.stdout.split(`
|
|
71619
|
+
`).filter((line) => line.trim()) : [];
|
|
71620
|
+
}
|
|
71621
|
+
function withTrailers(cwd, message, trailers) {
|
|
71622
|
+
if (!trailers.length)
|
|
71623
|
+
return message;
|
|
71624
|
+
const run = git5(cwd, [
|
|
71625
|
+
...TRAILER_CONFIG,
|
|
71626
|
+
"interpret-trailers",
|
|
71627
|
+
"--no-divider",
|
|
71628
|
+
"--if-exists",
|
|
71629
|
+
"addIfDifferent",
|
|
71630
|
+
...trailers.flatMap((trailer) => ["--trailer", trailer])
|
|
71631
|
+
], { input: `${message}
|
|
71632
|
+
` });
|
|
71633
|
+
return run.ok ? run.stdout.trim() : `${message}
|
|
71634
|
+
|
|
71635
|
+
${trailers.join(`
|
|
71636
|
+
`)}`;
|
|
71637
|
+
}
|
|
71638
|
+
function branchesContaining(cwd, sha) {
|
|
71639
|
+
const run = git5(cwd, [
|
|
71640
|
+
"for-each-ref",
|
|
71641
|
+
"--format=%(refname)",
|
|
71642
|
+
"--contains",
|
|
71643
|
+
sha,
|
|
71644
|
+
"refs/heads",
|
|
71645
|
+
"refs/remotes"
|
|
71646
|
+
]);
|
|
71647
|
+
const names = new Set;
|
|
71648
|
+
for (const ref of run.ok ? run.stdout.split(`
|
|
71649
|
+
`) : []) {
|
|
71650
|
+
if (ref.startsWith("refs/heads/"))
|
|
71651
|
+
names.add(ref.slice("refs/heads/".length));
|
|
71652
|
+
else if (ref.startsWith("refs/remotes/")) {
|
|
71653
|
+
const name = ref.split("/").slice(3).join("/");
|
|
71654
|
+
if (name && name !== "HEAD")
|
|
71655
|
+
names.add(name);
|
|
71656
|
+
}
|
|
71657
|
+
}
|
|
71658
|
+
return names;
|
|
71659
|
+
}
|
|
71660
|
+
function sharedBranchContaining(cwd, sha, branch) {
|
|
71661
|
+
const resolved = vcsConfig("resolve", cwd);
|
|
71662
|
+
const defaults = new Set(resolved.ok === false ? [] : [resolved.defaultTargetBranch, resolved.baseBranch].map((value) => String(value ?? "")).filter(Boolean));
|
|
71663
|
+
for (const name of branchesContaining(cwd, sha))
|
|
71664
|
+
if (name !== branch && (defaults.has(name) || isProtectedTarget(cwd, name)))
|
|
71665
|
+
return name;
|
|
71666
|
+
return null;
|
|
71667
|
+
}
|
|
71551
71668
|
function gitCommit(cwd, input) {
|
|
71552
|
-
const
|
|
71553
|
-
if (!
|
|
71554
|
-
return failure3("invalid_input", "a commit message is required (-m <msg>)");
|
|
71669
|
+
const given = input.message?.trim() ?? "";
|
|
71670
|
+
if (!given && !input.amend)
|
|
71671
|
+
return failure3("invalid_input", "a commit message is required (-m <msg> or -F <file>)");
|
|
71555
71672
|
const paths = input.paths ?? [];
|
|
71556
71673
|
if (input.all && paths.length)
|
|
71557
71674
|
return failure3("invalid_input", "pass --all or paths, not both");
|
|
71558
|
-
const
|
|
71675
|
+
const progress = operationInProgress(cwd);
|
|
71676
|
+
if (progress && !progress.commitAllowed)
|
|
71677
|
+
return inProgressFailure(progress.operation, "commit");
|
|
71678
|
+
const branch = progress?.branch ?? currentBranch(cwd);
|
|
71559
71679
|
if (!branch)
|
|
71560
71680
|
return failure3("invalid_input", "HEAD is detached; commit on a branch (workit git branch <name>)");
|
|
71561
71681
|
if (isProtectedTarget(cwd, branch))
|
|
71562
71682
|
return failure3("blocked", `protected_branch: ${branch} is protected by the workspace branch policy; workit never commits to it`, "workit git branch <feature/name> # then commit there");
|
|
71563
|
-
const
|
|
71564
|
-
if (!
|
|
71565
|
-
return failure3("
|
|
71683
|
+
const previous = input.amend ? headSha(cwd) : null;
|
|
71684
|
+
if (input.amend && !previous)
|
|
71685
|
+
return failure3("invalid_input", `nothing to amend: ${branch} has no commit yet`);
|
|
71686
|
+
if (previous) {
|
|
71687
|
+
const shared = sharedBranchContaining(cwd, previous, branch);
|
|
71688
|
+
if (shared)
|
|
71689
|
+
return failure3("blocked", `amend_shared_commit: ${previous.slice(0, 12)} is already on ${shared}, so it is not ${branch}'s own commit; workit never rewrites it`, "workit git commit -m '<msg>' -- <paths> # add a new commit instead");
|
|
71690
|
+
}
|
|
71691
|
+
let message = given;
|
|
71692
|
+
let carried = [];
|
|
71693
|
+
if (given) {
|
|
71694
|
+
const lint = lintCommitMessage(cwd, given);
|
|
71695
|
+
if (!lint.ok)
|
|
71696
|
+
return failure3("blocked", lint.error, lint.correction);
|
|
71697
|
+
}
|
|
71698
|
+
if (previous) {
|
|
71699
|
+
const kept = git5(cwd, ["log", "-1", "--format=%B", previous]);
|
|
71700
|
+
if (!kept.ok)
|
|
71701
|
+
return failure3("failed", `could not read the message of ${branch}: ${gitError(kept)}`);
|
|
71702
|
+
if (given)
|
|
71703
|
+
carried = messageTrailers(cwd, kept.stdout.trim());
|
|
71704
|
+
else
|
|
71705
|
+
message = kept.stdout.trim();
|
|
71706
|
+
}
|
|
71566
71707
|
const session = input.actor.session;
|
|
71567
71708
|
if (session && !SESSION_SAFE.test(session))
|
|
71568
71709
|
return failure3("invalid_input", "WORKIT_SESSION_ID must be 1-128 characters of [A-Za-z0-9_.:@/+-]");
|
|
71569
|
-
const
|
|
71570
|
-
|
|
71571
|
-
|
|
71710
|
+
const changeRequired = !input.amend && !input.allowEmpty;
|
|
71711
|
+
const emptyAmend = previous !== null && git5(cwd, ["rev-parse", "--verify", "-q", `${previous}^{tree}`]).stdout.trim() === git5(cwd, ["rev-parse", "--verify", "-q", `${previous}~1^{tree}`]).stdout.trim();
|
|
71712
|
+
const args = ["commit", "--no-edit"];
|
|
71713
|
+
if (input.amend)
|
|
71714
|
+
args.push("--amend");
|
|
71715
|
+
if (input.allowEmpty || emptyAmend)
|
|
71716
|
+
args.push("--allow-empty");
|
|
71717
|
+
args.push("-m", withTrailers(cwd, message, [...carried, ...session ? [`Workit-Session: ${session}`] : []]));
|
|
71572
71718
|
if (paths.length) {
|
|
71573
71719
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
71574
71720
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
71575
|
-
const
|
|
71576
|
-
|
|
71577
|
-
|
|
71721
|
+
const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
|
|
71722
|
+
const addable = paths.filter((value) => existsSync18(path39.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
|
|
71723
|
+
if (addable.length) {
|
|
71724
|
+
const added = git5(cwd, ["add", "-A", "--", ...addable]);
|
|
71725
|
+
if (!added.ok)
|
|
71726
|
+
return failure3("failed", `git add failed: ${gitError(added)}`);
|
|
71727
|
+
}
|
|
71728
|
+
if (changeRequired && git5(cwd, ["diff", "--cached", "--quiet", "HEAD", "--", ...paths]).ok)
|
|
71729
|
+
return nothingToCommit(`${paths.join(", ")} has no change to commit`);
|
|
71578
71730
|
args.push("--", ...paths);
|
|
71579
71731
|
} else if (input.all) {
|
|
71580
71732
|
const added = git5(cwd, ["add", "-A"]);
|
|
71581
71733
|
if (!added.ok)
|
|
71582
71734
|
return failure3("failed", `git add failed: ${gitError(added)}`);
|
|
71583
|
-
|
|
71735
|
+
if (changeRequired && git5(cwd, ["diff", "--cached", "--quiet"]).ok)
|
|
71736
|
+
return nothingToCommit("the working tree is clean");
|
|
71737
|
+
} else if (changeRequired) {
|
|
71584
71738
|
const staged = git5(cwd, ["diff", "--cached", "--name-only", "-z"]);
|
|
71585
71739
|
if (staged.ok && !staged.stdout.replaceAll("\x00", "")) {
|
|
71586
71740
|
const dirt = dirtEntries(cwd);
|
|
71587
|
-
|
|
71741
|
+
if (!dirt.length)
|
|
71742
|
+
return nothingToCommit("the working tree is clean");
|
|
71743
|
+
return failure3("blocked", `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 ? ", …" : ""})`, `workit git commit -m '<msg>' -- <paths> # or --all to commit every change`);
|
|
71588
71744
|
}
|
|
71589
71745
|
}
|
|
71590
|
-
const committed = git5(cwd, args, {
|
|
71746
|
+
const committed = git5(cwd, args, {
|
|
71747
|
+
timeoutMs: COMMIT_TIMEOUT_MS,
|
|
71748
|
+
env: input.env
|
|
71749
|
+
});
|
|
71591
71750
|
if (!committed.ok)
|
|
71592
|
-
return failure3("failed", `git commit failed
|
|
71751
|
+
return failure3("failed", `git commit failed (a hook or git refused it):
|
|
71752
|
+
${gitOutput(committed)}`);
|
|
71593
71753
|
const sha = headSha(cwd);
|
|
71594
71754
|
if (!sha)
|
|
71595
71755
|
return failure3("failed", "the commit did not resolve");
|
|
71596
|
-
const
|
|
71756
|
+
const merge = git5(cwd, ["rev-parse", "-q", "--verify", `${sha}^2`]).ok;
|
|
71757
|
+
const files = nulList(git5(cwd, merge ? ["diff", "--name-only", "-z", `${sha}^1`, sha] : ["diff-tree", "--root", "--no-commit-id", "--name-only", "-r", "-z", sha]).stdout);
|
|
71597
71758
|
const leftDirty = dirtEntries(cwd).length;
|
|
71759
|
+
const notes = [];
|
|
71760
|
+
const upstream = `refs/remotes/${pushRemoteName(cwd, branch) ?? "origin"}/${branch}`;
|
|
71761
|
+
if (previous && git5(cwd, ["merge-base", "--is-ancestor", previous, upstream]).ok)
|
|
71762
|
+
notes.push(`the amended commit ${previous.slice(0, 12)} was already pushed (${upstream.slice("refs/remotes/".length)}); publish the rewrite with: workit git push --force-with-lease`);
|
|
71598
71763
|
const listed = [];
|
|
71599
71764
|
let size = 0;
|
|
71600
71765
|
for (const file of files) {
|
|
@@ -71614,7 +71779,8 @@ function gitCommit(cwd, input) {
|
|
|
71614
71779
|
subject: (message.split(`
|
|
71615
71780
|
`, 1)[0] ?? "").slice(0, 200),
|
|
71616
71781
|
files: listed,
|
|
71617
|
-
fileCount: files.length
|
|
71782
|
+
fileCount: files.length,
|
|
71783
|
+
...previous ? { amended: previous } : {}
|
|
71618
71784
|
});
|
|
71619
71785
|
return success2({
|
|
71620
71786
|
sha,
|
|
@@ -71623,10 +71789,15 @@ function gitCommit(cwd, input) {
|
|
|
71623
71789
|
files,
|
|
71624
71790
|
leftDirty,
|
|
71625
71791
|
session,
|
|
71792
|
+
amended: previous,
|
|
71793
|
+
notes,
|
|
71626
71794
|
recorded: row.ok ? { id: String(row.value.id) } : { error: row.error }
|
|
71627
71795
|
});
|
|
71628
71796
|
}
|
|
71629
71797
|
function pushPreflight(cwd, options = {}) {
|
|
71798
|
+
const progress = operationInProgress(cwd);
|
|
71799
|
+
if (progress)
|
|
71800
|
+
return inProgressFailure(progress.operation, "push");
|
|
71630
71801
|
const branch = options.branch ?? currentBranch(cwd);
|
|
71631
71802
|
if (!branch)
|
|
71632
71803
|
return failure3("invalid_input", "HEAD is detached; push a branch");
|
|
@@ -71665,11 +71836,35 @@ function recordedRemoteTip(cwd, plan) {
|
|
|
71665
71836
|
return;
|
|
71666
71837
|
}
|
|
71667
71838
|
function includesRemoteTip(cwd, branch, tip) {
|
|
71668
|
-
|
|
71839
|
+
const ref = `refs/heads/${branch}`;
|
|
71840
|
+
if (git5(cwd, ["merge-base", "--is-ancestor", tip, ref]).ok)
|
|
71669
71841
|
return true;
|
|
71670
|
-
const reflog = git5(cwd, ["reflog", "show", "--format=%H",
|
|
71671
|
-
|
|
71672
|
-
|
|
71842
|
+
const reflog = git5(cwd, ["reflog", "show", "--format=%H", ref, "--"]);
|
|
71843
|
+
const former = [
|
|
71844
|
+
...new Set((reflog.ok ? reflog.stdout : "").split(`
|
|
71845
|
+
`).map((line) => line.trim()).filter(Boolean))
|
|
71846
|
+
];
|
|
71847
|
+
if (former.includes(tip))
|
|
71848
|
+
return true;
|
|
71849
|
+
if (!former.length)
|
|
71850
|
+
return false;
|
|
71851
|
+
const outside = git5(cwd, ["rev-list", "-n", "1", "--stdin"], {
|
|
71852
|
+
input: `${tip}
|
|
71853
|
+
${former.map((sha) => `^${sha}`).join(`
|
|
71854
|
+
`)}
|
|
71855
|
+
`
|
|
71856
|
+
});
|
|
71857
|
+
return outside.ok && !outside.stdout.trim();
|
|
71858
|
+
}
|
|
71859
|
+
function patchEquivalent(cwd, branch, tip) {
|
|
71860
|
+
const ref = `refs/heads/${branch}`;
|
|
71861
|
+
const merges = git5(cwd, ["rev-list", "--count", "--merges", `${ref}..${tip}`]);
|
|
71862
|
+
if (!merges.ok || merges.stdout.trim() !== "0")
|
|
71863
|
+
return false;
|
|
71864
|
+
const cherry = git5(cwd, ["cherry", ref, tip]);
|
|
71865
|
+
const lines = cherry.ok ? cherry.stdout.split(`
|
|
71866
|
+
`).filter(Boolean) : [];
|
|
71867
|
+
return lines.length > 0 && lines.every((line) => line.startsWith("-"));
|
|
71673
71868
|
}
|
|
71674
71869
|
function executePush(cwd, plan, input) {
|
|
71675
71870
|
const before = remoteRefTip(cwd, plan.rawUrl, `refs/heads/${plan.branch}`);
|
|
@@ -71704,9 +71899,17 @@ ${run.stdout}`;
|
|
|
71704
71899
|
return failure3("unavailable", `git push to ${plan.url} timed out`);
|
|
71705
71900
|
if (/stale info/iu.test(text))
|
|
71706
71901
|
return failure3("blocked", `lease_mismatch: ${plan.remote}/${plan.branch} moved while pushing`, `git fetch ${plan.remote} ${plan.branch} && git rebase ${plan.remote}/${plan.branch} # or merge it; then: workit git push`);
|
|
71902
|
+
const rejected = /non-fast-forward|fetch first|\[rejected\]/iu.test(text);
|
|
71903
|
+
const integrated = rejected && before.sha !== null && includesRemoteTip(cwd, plan.branch, before.sha);
|
|
71904
|
+
const equivalent = rejected && !integrated && before.sha !== null && patchEquivalent(cwd, plan.branch, before.sha);
|
|
71905
|
+
if (before.sha !== null && (integrated || equivalent)) {
|
|
71906
|
+
const lease = recordedRemoteTip(cwd, plan) === before.sha ? "workit git push --force-with-lease" : `workit git push --force-with-lease --expect ${before.sha}`;
|
|
71907
|
+
return failure3("failed", integrated ? `non_fast_forward: local ${plan.branch} was rewritten (amend or rebase) after ${plan.remote}/${plan.branch} (${before.sha.slice(0, 12)}) was pushed; that tip is already part of the local history, so do not fetch and rebase` : `non_fast_forward: every commit on ${plan.remote}/${plan.branch} (${before.sha.slice(0, 12)}) has a patch-equivalent commit in local ${plan.branch} (rebased elsewhere); fetching and rebasing would apply them twice`, integrated ? lease : `${lease} --overwrite-unintegrated # after checking ${plan.remote}/${plan.branch} holds nothing else`);
|
|
71908
|
+
}
|
|
71707
71909
|
if (/non-fast-forward|fetch first|\[rejected\]/iu.test(text))
|
|
71708
71910
|
return failure3("failed", `non_fast_forward: ${plan.remote}/${plan.branch} has commits this branch does not`, `git fetch ${plan.remote} && git rebase ${plan.remote}/${plan.branch} # or, if the rewrite is intended: workit git push --force-with-lease`);
|
|
71709
|
-
return failure3("failed", `git push to ${plan.url} failed:
|
|
71911
|
+
return failure3("failed", `git push to ${plan.url} failed:
|
|
71912
|
+
${gitOutput(run)}`);
|
|
71710
71913
|
}
|
|
71711
71914
|
pushed = true;
|
|
71712
71915
|
}
|
|
@@ -71765,7 +71968,11 @@ function deleteRemoteBranch(cwd, target, branch, expectedTip, options = {}) {
|
|
|
71765
71968
|
return { ok: true };
|
|
71766
71969
|
const text = `${run.stderr}
|
|
71767
71970
|
${run.stdout}`;
|
|
71768
|
-
return /stale info|cannot lock ref|fetch first|non-fast-forward/iu.test(text) ? {
|
|
71971
|
+
return /stale info|cannot lock ref|fetch first|non-fast-forward/iu.test(text) ? {
|
|
71972
|
+
ok: false,
|
|
71973
|
+
lease: true,
|
|
71974
|
+
error: "the remote branch tip changed before deletion"
|
|
71975
|
+
} : { ok: false, lease: false, error: gitError(run) };
|
|
71769
71976
|
}
|
|
71770
71977
|
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
|
|
71771
71978
|
const result = spawnSync16("git", args, {
|
|
@@ -71776,7 +71983,7 @@ var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}
|
|
|
71776
71983
|
timeout: options.timeoutMs ?? GIT_TIMEOUTS.local,
|
|
71777
71984
|
killSignal: "SIGKILL",
|
|
71778
71985
|
windowsHide: true,
|
|
71779
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
71986
|
+
...options.input === undefined ? { stdio: ["ignore", "pipe", "pipe"] } : { input: options.input, stdio: ["pipe", "pipe", "pipe"] }
|
|
71780
71987
|
});
|
|
71781
71988
|
return {
|
|
71782
71989
|
ok: result.status === 0,
|
|
@@ -71788,7 +71995,22 @@ var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}
|
|
|
71788
71995
|
const lines = redactText(`${run.stderr}
|
|
71789
71996
|
${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trim()).filter((value) => value && !value.startsWith("hint:"));
|
|
71790
71997
|
return lines.slice(-max).join(" / ").slice(0, 400) || "git failed";
|
|
71791
|
-
},
|
|
71998
|
+
}, OUTPUT_LINES = 200, OUTPUT_LINE_CHARS = 1000, gitOutput = (run) => {
|
|
71999
|
+
const lines = redactText(`${run.stderr}
|
|
72000
|
+
${run.stdout ?? ""}`).split(/\r?\n/u).map((value) => value.trimEnd()).filter((value) => value.trim() && !value.trimStart().startsWith("hint:")).map((value) => value.length > OUTPUT_LINE_CHARS ? `${value.slice(0, OUTPUT_LINE_CHARS)}…` : value);
|
|
72001
|
+
if (!lines.length)
|
|
72002
|
+
return "git failed";
|
|
72003
|
+
if (lines.length <= OUTPUT_LINES)
|
|
72004
|
+
return lines.join(`
|
|
72005
|
+
`);
|
|
72006
|
+
const half = OUTPUT_LINES / 2;
|
|
72007
|
+
return [
|
|
72008
|
+
...lines.slice(0, half),
|
|
72009
|
+
`… ${lines.length - OUTPUT_LINES} lines omitted …`,
|
|
72010
|
+
...lines.slice(-half)
|
|
72011
|
+
].join(`
|
|
72012
|
+
`);
|
|
72013
|
+
}, validRefName = (cwd, name) => !name.startsWith("-") && git5(cwd, ["check-ref-format", "--branch", name]).ok, nulList = (text) => text.split("\x00").filter(Boolean), SESSION_SAFE, TRAILER_CONFIG, nothingToCommit = (what) => failure3("failed", `nothing_to_commit: ${what}`, "workit git commit --allow-empty -m '<msg>' # only to record an empty commit on purpose"), SHA;
|
|
71792
72014
|
var init_ops = __esm(() => {
|
|
71793
72015
|
init_branch();
|
|
71794
72016
|
init_commit_flavors();
|
|
@@ -71800,15 +72022,16 @@ var init_ops = __esm(() => {
|
|
|
71800
72022
|
init_rev();
|
|
71801
72023
|
COMMIT_TIMEOUT_MS = 10 * 60000;
|
|
71802
72024
|
SESSION_SAFE = /^[\w.:@/+-]{1,128}$/u;
|
|
72025
|
+
TRAILER_CONFIG = ["-c", "trailer.separators=:", "-c", "trailer.where=end"];
|
|
71803
72026
|
SHA = /^[0-9a-f]{40,64}$/u;
|
|
71804
72027
|
});
|
|
71805
72028
|
|
|
71806
72029
|
// packages/workit-core/src/forge/reruns.ts
|
|
71807
72030
|
import fs19 from "node:fs";
|
|
71808
|
-
import
|
|
72031
|
+
import path40 from "node:path";
|
|
71809
72032
|
function rerunLogPath(cwd) {
|
|
71810
72033
|
const common = gitCommonDir(cwd);
|
|
71811
|
-
return common ?
|
|
72034
|
+
return common ? path40.join(common, "workit", "ci-reruns.jsonl") : null;
|
|
71812
72035
|
}
|
|
71813
72036
|
function rerunCounts(cwd, key) {
|
|
71814
72037
|
const counts = new Map;
|
|
@@ -71843,7 +72066,7 @@ function recordReruns(cwd, rows) {
|
|
|
71843
72066
|
if (!file)
|
|
71844
72067
|
return false;
|
|
71845
72068
|
try {
|
|
71846
|
-
fs19.mkdirSync(
|
|
72069
|
+
fs19.mkdirSync(path40.dirname(file), { recursive: true });
|
|
71847
72070
|
fs19.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
|
|
71848
72071
|
`).join(""));
|
|
71849
72072
|
return true;
|
|
@@ -71856,7 +72079,7 @@ function withRerunLock(cwd, fn) {
|
|
|
71856
72079
|
if (!file)
|
|
71857
72080
|
return fn();
|
|
71858
72081
|
const lock = `${file.slice(0, -".jsonl".length)}.lock`;
|
|
71859
|
-
fs19.mkdirSync(
|
|
72082
|
+
fs19.mkdirSync(path40.dirname(lock), { recursive: true });
|
|
71860
72083
|
const until = Date.now() + LOCK_WAIT_MS2;
|
|
71861
72084
|
for (;; ) {
|
|
71862
72085
|
try {
|
|
@@ -72564,13 +72787,13 @@ var init_pr_ops = __esm(() => {
|
|
|
72564
72787
|
// packages/workit-core/src/forge/exec.ts
|
|
72565
72788
|
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
72566
72789
|
import fs20 from "node:fs";
|
|
72567
|
-
import
|
|
72790
|
+
import path41 from "node:path";
|
|
72568
72791
|
function findExecutable(bin, env) {
|
|
72569
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
72792
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path41.delimiter).filter(Boolean);
|
|
72570
72793
|
const exts = process.platform === "win32" ? [".exe"] : [""];
|
|
72571
72794
|
for (const dir of dirs)
|
|
72572
72795
|
for (const ext of exts) {
|
|
72573
|
-
const candidate =
|
|
72796
|
+
const candidate = path41.join(dir, `${bin}${ext}`);
|
|
72574
72797
|
try {
|
|
72575
72798
|
const stat = fs20.statSync(candidate);
|
|
72576
72799
|
if (stat.isFile())
|
|
@@ -73559,8 +73782,8 @@ var exports_pr = {};
|
|
|
73559
73782
|
__export(exports_pr, {
|
|
73560
73783
|
run: () => run10
|
|
73561
73784
|
});
|
|
73562
|
-
import { readFileSync as
|
|
73563
|
-
import
|
|
73785
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
73786
|
+
import path42 from "node:path";
|
|
73564
73787
|
async function status(argv, io) {
|
|
73565
73788
|
const flags = parseFlags(argv, { pr: "value", branch: "value", "log-lines": "value" });
|
|
73566
73789
|
if (typeof flags === "string")
|
|
@@ -73631,7 +73854,7 @@ async function create4(argv, io) {
|
|
|
73631
73854
|
let body = flags.values.body ?? null;
|
|
73632
73855
|
if (flags.values["body-file"] !== undefined) {
|
|
73633
73856
|
try {
|
|
73634
|
-
body =
|
|
73857
|
+
body = readFileSync19(path42.resolve(io.cwd, flags.values["body-file"]), "utf8");
|
|
73635
73858
|
} catch {
|
|
73636
73859
|
return usage3(io, `cannot read --body-file ${flags.values["body-file"]}`, CREATE_USAGE);
|
|
73637
73860
|
}
|
|
@@ -73976,6 +74199,8 @@ var exports_git = {};
|
|
|
73976
74199
|
__export(exports_git, {
|
|
73977
74200
|
run: () => run12
|
|
73978
74201
|
});
|
|
74202
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
74203
|
+
import path43 from "node:path";
|
|
73979
74204
|
async function branch(argv, io) {
|
|
73980
74205
|
const flags = parseFlags(argv, {
|
|
73981
74206
|
base: "value",
|
|
@@ -74012,7 +74237,15 @@ async function branch(argv, io) {
|
|
|
74012
74237
|
]);
|
|
74013
74238
|
}
|
|
74014
74239
|
function parseCommit(argv) {
|
|
74015
|
-
const out = {
|
|
74240
|
+
const out = {
|
|
74241
|
+
messages: [],
|
|
74242
|
+
files: [],
|
|
74243
|
+
all: false,
|
|
74244
|
+
amend: false,
|
|
74245
|
+
noEdit: false,
|
|
74246
|
+
allowEmpty: false,
|
|
74247
|
+
paths: []
|
|
74248
|
+
};
|
|
74016
74249
|
for (let index = 0;index < argv.length; index += 1) {
|
|
74017
74250
|
const arg = argv[index];
|
|
74018
74251
|
if (arg === "--") {
|
|
@@ -74021,23 +74254,24 @@ function parseCommit(argv) {
|
|
|
74021
74254
|
}
|
|
74022
74255
|
if (arg === "--json")
|
|
74023
74256
|
continue;
|
|
74024
|
-
|
|
74025
|
-
|
|
74026
|
-
|
|
74027
|
-
}
|
|
74028
|
-
if (arg === "-m" || arg === "--message") {
|
|
74029
|
-
const value = argv[++index];
|
|
74030
|
-
if (value === undefined)
|
|
74031
|
-
return `${arg} requires a message`;
|
|
74032
|
-
out.messages.push(value);
|
|
74033
|
-
continue;
|
|
74034
|
-
}
|
|
74035
|
-
if (arg.startsWith("--message=")) {
|
|
74036
|
-
out.messages.push(arg.slice("--message=".length));
|
|
74257
|
+
const flag = COMMIT_SWITCHES[arg];
|
|
74258
|
+
if (flag) {
|
|
74259
|
+
out[flag] = true;
|
|
74037
74260
|
continue;
|
|
74038
74261
|
}
|
|
74039
|
-
|
|
74040
|
-
out.messages
|
|
74262
|
+
const valued = [
|
|
74263
|
+
["-m", "--message", out.messages],
|
|
74264
|
+
["-F", "--file", out.files]
|
|
74265
|
+
].find(([shortName, longName]) => arg === shortName || arg === longName || arg.startsWith(`${longName}=`) || arg.startsWith(shortName) && arg.length > 2);
|
|
74266
|
+
if (valued) {
|
|
74267
|
+
const [shortName, longName, into] = valued;
|
|
74268
|
+
if (arg === shortName || arg === longName) {
|
|
74269
|
+
const value = argv[++index];
|
|
74270
|
+
if (value === undefined)
|
|
74271
|
+
return `${arg} requires a ${shortName === "-m" ? "message" : "file"}`;
|
|
74272
|
+
into.push(value);
|
|
74273
|
+
} else
|
|
74274
|
+
into.push(arg.startsWith(`${longName}=`) ? arg.slice(longName.length + 1) : arg.slice(2));
|
|
74041
74275
|
continue;
|
|
74042
74276
|
}
|
|
74043
74277
|
if (arg.startsWith("-"))
|
|
@@ -74046,20 +74280,48 @@ function parseCommit(argv) {
|
|
|
74046
74280
|
}
|
|
74047
74281
|
return out;
|
|
74048
74282
|
}
|
|
74283
|
+
function commitMessage(parsed, io) {
|
|
74284
|
+
if (parsed.messages.length && parsed.files.length)
|
|
74285
|
+
return { error: "pass -m or -F, not both" };
|
|
74286
|
+
if (parsed.files.length > 1)
|
|
74287
|
+
return { error: "-F takes one file" };
|
|
74288
|
+
const [file] = parsed.files;
|
|
74289
|
+
if (file === undefined)
|
|
74290
|
+
return parsed.messages.join(`
|
|
74291
|
+
|
|
74292
|
+
`);
|
|
74293
|
+
try {
|
|
74294
|
+
return file === "-" ? readFileSync20(0, "utf8") : readFileSync20(path43.resolve(io.cwd, file), "utf8");
|
|
74295
|
+
} catch (error) {
|
|
74296
|
+
return {
|
|
74297
|
+
error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
|
|
74298
|
+
};
|
|
74299
|
+
}
|
|
74300
|
+
}
|
|
74049
74301
|
async function commit(argv, io) {
|
|
74050
74302
|
const parsed = parseCommit(argv);
|
|
74051
74303
|
if (typeof parsed === "string")
|
|
74052
74304
|
return usage3(io, parsed, COMMIT_USAGE);
|
|
74053
|
-
if (!parsed.messages.length)
|
|
74054
|
-
return usage3(io, "missing -m <msg>", COMMIT_USAGE);
|
|
74055
74305
|
if (parsed.all && parsed.paths.length)
|
|
74056
74306
|
return usage3(io, "pass --all or paths, not both", COMMIT_USAGE);
|
|
74307
|
+
if (parsed.noEdit && !parsed.amend)
|
|
74308
|
+
return usage3(io, "--no-edit only applies with --amend", COMMIT_USAGE);
|
|
74309
|
+
const given = parsed.messages.length + parsed.files.length > 0;
|
|
74310
|
+
if (parsed.noEdit && given)
|
|
74311
|
+
return usage3(io, "--no-edit keeps the message; drop -m/-F or --no-edit", COMMIT_USAGE);
|
|
74312
|
+
if (!given && !parsed.noEdit)
|
|
74313
|
+
return usage3(io, parsed.amend ? "--amend needs -m/-F or --no-edit" : "missing -m <msg> or -F <file>", COMMIT_USAGE);
|
|
74314
|
+
const message = given ? commitMessage(parsed, io) : null;
|
|
74315
|
+
if (message !== null && typeof message !== "string")
|
|
74316
|
+
return usage3(io, message.error, COMMIT_USAGE);
|
|
74317
|
+
if (message !== null && !message.trim())
|
|
74318
|
+
return usage3(io, "the commit message is empty", COMMIT_USAGE);
|
|
74057
74319
|
const result = gitCommit(io.cwd, {
|
|
74058
|
-
message
|
|
74059
|
-
|
|
74060
|
-
`),
|
|
74320
|
+
message,
|
|
74061
74321
|
all: parsed.all,
|
|
74062
74322
|
paths: parsed.paths,
|
|
74323
|
+
amend: parsed.amend,
|
|
74324
|
+
allowEmpty: parsed.allowEmpty,
|
|
74063
74325
|
actor: actorFromEnv(io.env),
|
|
74064
74326
|
env: io.env
|
|
74065
74327
|
});
|
|
@@ -74068,8 +74330,9 @@ async function commit(argv, io) {
|
|
|
74068
74330
|
await ensureImplicitTask(io);
|
|
74069
74331
|
return emit(io, ok(result.data), (data) => [
|
|
74070
74332
|
`${data.branch} ${short2(data.sha)} ${data.message.split(`
|
|
74071
|
-
`, 1)[0]} (${data.files.length} file${data.files.length === 1 ? "" : "s"})`,
|
|
74333
|
+
`, 1)[0]} (${data.files.length ? `${data.files.length} file${data.files.length === 1 ? "" : "s"}` : "empty commit"})${data.amended ? `, amends ${short2(data.amended)}` : ""}`,
|
|
74072
74334
|
...data.leftDirty ? [`${data.leftDirty} change(s) left uncommitted`] : [],
|
|
74335
|
+
...data.notes.map((note) => `note: ${note}`),
|
|
74073
74336
|
..."error" in data.recorded ? [`ledger: not recorded (${data.recorded.error})`] : [],
|
|
74074
74337
|
...data.session ? [] : ["note: WORKIT_SESSION_ID is unset; this commit has no session author"]
|
|
74075
74338
|
]);
|
|
@@ -74103,7 +74366,10 @@ async function push(argv, io) {
|
|
|
74103
74366
|
}
|
|
74104
74367
|
const grant = requireGrant(io.cwd, "push", { forge: !plan.data.local });
|
|
74105
74368
|
if (!grant.allowed)
|
|
74106
|
-
return emit(io, fail("blocked", grant.error, {
|
|
74369
|
+
return emit(io, fail("blocked", grant.error, {
|
|
74370
|
+
unblock: grant.unblock,
|
|
74371
|
+
data: { reason: grant.reason }
|
|
74372
|
+
}));
|
|
74107
74373
|
const result = executePush(io.cwd, plan.data, {
|
|
74108
74374
|
forceWithLease: flags.booleans.has("force-with-lease"),
|
|
74109
74375
|
overwriteUnintegrated: flags.booleans.has("overwrite-unintegrated"),
|
|
@@ -74112,7 +74378,10 @@ async function push(argv, io) {
|
|
|
74112
74378
|
actor: actorFromEnv(io.env)
|
|
74113
74379
|
});
|
|
74114
74380
|
if (!result.ok)
|
|
74115
|
-
return forgeFail(io, result, {
|
|
74381
|
+
return forgeFail(io, result, {
|
|
74382
|
+
branch: plan.data.branch,
|
|
74383
|
+
sha: plan.data.sha
|
|
74384
|
+
});
|
|
74116
74385
|
return emit(io, ok(result.data), (data) => [
|
|
74117
74386
|
data.pushed ? `pushed ${data.branch} ${short2(data.previous)} -> ${short2(data.sha)} to ${data.remote}${data.forced ? " (force-with-lease)" : ""}; remote tip verified` : `${data.remote}/${data.branch} is already at ${short2(data.sha)}; remote tip verified`,
|
|
74118
74387
|
...data.upstream ? [`upstream: ${data.remote}/${data.branch}`] : []
|
|
@@ -74128,7 +74397,7 @@ async function run12(argv, io) {
|
|
|
74128
74397
|
return push(rest, io);
|
|
74129
74398
|
return usage3(io, sub && !sub.startsWith("-") ? `unknown git subcommand "${sub}"` : "missing git subcommand", USAGE5);
|
|
74130
74399
|
}
|
|
74131
|
-
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
|
|
74400
|
+
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|--message <msg>… | -F|--file <file|-> [--amend [--no-edit]] [--allow-empty] [-a|--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)", COMMIT_SWITCHES;
|
|
74132
74401
|
var init_git2 = __esm(() => {
|
|
74133
74402
|
init_autonomy();
|
|
74134
74403
|
init_ops();
|
|
@@ -74136,6 +74405,13 @@ var init_git2 = __esm(() => {
|
|
|
74136
74405
|
init_implicit_task();
|
|
74137
74406
|
init_output();
|
|
74138
74407
|
init_forge_common();
|
|
74408
|
+
COMMIT_SWITCHES = {
|
|
74409
|
+
"-a": "all",
|
|
74410
|
+
"--all": "all",
|
|
74411
|
+
"--amend": "amend",
|
|
74412
|
+
"--no-edit": "noEdit",
|
|
74413
|
+
"--allow-empty": "allowEmpty"
|
|
74414
|
+
};
|
|
74139
74415
|
});
|
|
74140
74416
|
|
|
74141
74417
|
// packages/workit-core/src/forge/verify.ts
|
|
@@ -74462,7 +74738,7 @@ var init_verify_delivery = __esm(() => {
|
|
|
74462
74738
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
74463
74739
|
import { createHash as createHash15, randomBytes as randomBytes3 } from "node:crypto";
|
|
74464
74740
|
import fs22 from "node:fs";
|
|
74465
|
-
import
|
|
74741
|
+
import path44 from "node:path";
|
|
74466
74742
|
function worktreeOf(cwd, branch) {
|
|
74467
74743
|
const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
|
|
74468
74744
|
if (!list.ok)
|
|
@@ -74506,7 +74782,7 @@ function gitRestack(cwd, input) {
|
|
|
74506
74782
|
if (!scratch)
|
|
74507
74783
|
return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
|
|
74508
74784
|
fs22.mkdirSync(scratch, { recursive: true });
|
|
74509
|
-
dir =
|
|
74785
|
+
dir = path44.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
|
|
74510
74786
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
74511
74787
|
if (!added.ok)
|
|
74512
74788
|
return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
|
|
@@ -74547,7 +74823,7 @@ function pruneScratch(cwd) {
|
|
|
74547
74823
|
if (!scratch || !fs22.existsSync(scratch))
|
|
74548
74824
|
return;
|
|
74549
74825
|
for (const name of fs22.readdirSync(scratch)) {
|
|
74550
|
-
const dir =
|
|
74826
|
+
const dir = path44.join(scratch, name);
|
|
74551
74827
|
if (!rebaseInProgress(dir) && !trackedDirt(dir))
|
|
74552
74828
|
gitRun3(cwd, ["worktree", "remove", "--force", dir]);
|
|
74553
74829
|
}
|
|
@@ -74557,7 +74833,7 @@ function stacksDir(cwd) {
|
|
|
74557
74833
|
const root = storeRoot(cwd);
|
|
74558
74834
|
if (!root.ok)
|
|
74559
74835
|
return stackFail(root.code, root.error, root.unblock);
|
|
74560
|
-
return { ok: true, data:
|
|
74836
|
+
return { ok: true, data: path44.join(root.value.root, "stacks") };
|
|
74561
74837
|
}
|
|
74562
74838
|
function parseStack(raw) {
|
|
74563
74839
|
if (!isRecord7(raw) || !Array.isArray(raw.branches))
|
|
@@ -74609,7 +74885,7 @@ function readStack(cwd, name) {
|
|
|
74609
74885
|
const dir = stacksDir(cwd);
|
|
74610
74886
|
if (!dir.ok)
|
|
74611
74887
|
return dir;
|
|
74612
|
-
const file =
|
|
74888
|
+
const file = path44.join(dir.data, fileFor(name));
|
|
74613
74889
|
let text;
|
|
74614
74890
|
try {
|
|
74615
74891
|
text = fs22.readFileSync(file, "utf8");
|
|
@@ -74630,7 +74906,7 @@ function writeStack(cwd, stack, now = new Date) {
|
|
|
74630
74906
|
const dir = stacksDir(cwd);
|
|
74631
74907
|
if (!dir.ok)
|
|
74632
74908
|
return dir;
|
|
74633
|
-
const file =
|
|
74909
|
+
const file = path44.join(dir.data, fileFor(stack.name));
|
|
74634
74910
|
const temp = `${file}.${process.pid}.tmp`;
|
|
74635
74911
|
try {
|
|
74636
74912
|
fs22.mkdirSync(dir.data, { recursive: true });
|
|
@@ -74658,7 +74934,7 @@ function listStacks(cwd) {
|
|
|
74658
74934
|
for (const name of names) {
|
|
74659
74935
|
let parsed = null;
|
|
74660
74936
|
try {
|
|
74661
|
-
parsed = parseStack(JSON.parse(fs22.readFileSync(
|
|
74937
|
+
parsed = parseStack(JSON.parse(fs22.readFileSync(path44.join(dir.data, name), "utf8")));
|
|
74662
74938
|
} catch {
|
|
74663
74939
|
parsed = null;
|
|
74664
74940
|
}
|
|
@@ -74717,7 +74993,7 @@ function takeLock(lock) {
|
|
|
74717
74993
|
host: localLockHost(),
|
|
74718
74994
|
nonce: randomBytes3(8).toString("hex")
|
|
74719
74995
|
};
|
|
74720
|
-
fs22.writeFileSync(
|
|
74996
|
+
fs22.writeFileSync(path44.join(lock, OWNER), JSON.stringify(owner));
|
|
74721
74997
|
return owner;
|
|
74722
74998
|
}
|
|
74723
74999
|
function reapLock(lock, observed) {
|
|
@@ -74754,7 +75030,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74754
75030
|
return dir;
|
|
74755
75031
|
if (!validName(name))
|
|
74756
75032
|
return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
|
|
74757
|
-
const lock =
|
|
75033
|
+
const lock = path44.join(dir.data, `${fileFor(name)}.lock`);
|
|
74758
75034
|
try {
|
|
74759
75035
|
fs22.mkdirSync(dir.data, { recursive: true });
|
|
74760
75036
|
} catch (error) {
|
|
@@ -74784,7 +75060,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74784
75060
|
const touch = () => {
|
|
74785
75061
|
try {
|
|
74786
75062
|
const now = new Date;
|
|
74787
|
-
fs22.utimesSync(
|
|
75063
|
+
fs22.utimesSync(path44.join(lock, OWNER), now, now);
|
|
74788
75064
|
} catch {}
|
|
74789
75065
|
};
|
|
74790
75066
|
const beat = setInterval(touch, HEARTBEAT_MS);
|
|
@@ -75624,7 +75900,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
75624
75900
|
return !status.ok || status.stdout.trim() !== "";
|
|
75625
75901
|
}, scratchDir = (cwd) => {
|
|
75626
75902
|
const dir = stacksDir(cwd);
|
|
75627
|
-
return dir.ok ?
|
|
75903
|
+
return dir.ok ? path44.join(dir.data, "worktrees") : null;
|
|
75628
75904
|
}, firstLine = (run) => (`${run.stderr}
|
|
75629
75905
|
${run.stdout}`.split(`
|
|
75630
75906
|
`).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) => {
|
|
@@ -75639,12 +75915,12 @@ ${run.stdout}`.split(`
|
|
|
75639
75915
|
}, 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) => {
|
|
75640
75916
|
let raw = null;
|
|
75641
75917
|
try {
|
|
75642
|
-
raw = fs22.readFileSync(
|
|
75918
|
+
raw = fs22.readFileSync(path44.join(lock, OWNER), "utf8");
|
|
75643
75919
|
} catch {
|
|
75644
75920
|
raw = null;
|
|
75645
75921
|
}
|
|
75646
75922
|
let age = null;
|
|
75647
|
-
for (const target of [
|
|
75923
|
+
for (const target of [path44.join(lock, OWNER), lock])
|
|
75648
75924
|
try {
|
|
75649
75925
|
age = Date.now() - fs22.statSync(target).mtimeMs;
|
|
75650
75926
|
break;
|
|
@@ -75894,7 +76170,7 @@ var init_stack2 = __esm(() => {
|
|
|
75894
76170
|
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
75895
76171
|
import { createHash as createHash16 } from "node:crypto";
|
|
75896
76172
|
import fs23 from "node:fs";
|
|
75897
|
-
import
|
|
76173
|
+
import path45 from "node:path";
|
|
75898
76174
|
function expandBraces(pattern, limit = 64) {
|
|
75899
76175
|
for (let index = 0;index < pattern.length; index += 1) {
|
|
75900
76176
|
if (pattern[index] === "\\") {
|
|
@@ -76128,7 +76404,7 @@ function parsePlan(raw, defaults, name) {
|
|
|
76128
76404
|
id,
|
|
76129
76405
|
branch,
|
|
76130
76406
|
base: optional("base") ?? "",
|
|
76131
|
-
worktree:
|
|
76407
|
+
worktree: path45.resolve(defaults.root, optional("worktree") ?? path45.join(defaults.worktreeRoot, id)),
|
|
76132
76408
|
tier,
|
|
76133
76409
|
dependsOn: [...new Set(dependsOn ?? [])],
|
|
76134
76410
|
scope,
|
|
@@ -76357,11 +76633,11 @@ function defaultTrunk(cwd) {
|
|
|
76357
76633
|
}
|
|
76358
76634
|
function mainCheckout(cwd) {
|
|
76359
76635
|
const common = gitCommonDir(cwd);
|
|
76360
|
-
return common &&
|
|
76636
|
+
return common && path45.basename(common) === ".git" ? path45.dirname(common) : path45.resolve(cwd);
|
|
76361
76637
|
}
|
|
76362
76638
|
function worktreeRoot(cwd) {
|
|
76363
76639
|
const main = mainCheckout(cwd);
|
|
76364
|
-
return
|
|
76640
|
+
return path45.join(path45.dirname(main), `${path45.basename(main)}-wt`);
|
|
76365
76641
|
}
|
|
76366
76642
|
function sliceHash(slice) {
|
|
76367
76643
|
const {
|
|
@@ -76379,7 +76655,7 @@ function fanoutsDir(cwd) {
|
|
|
76379
76655
|
const root = storeRoot(cwd);
|
|
76380
76656
|
if (!root.ok)
|
|
76381
76657
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
76382
|
-
return { ok: true, data:
|
|
76658
|
+
return { ok: true, data: path45.join(root.value.root, "fanouts") };
|
|
76383
76659
|
}
|
|
76384
76660
|
function parseStored(raw) {
|
|
76385
76661
|
if (!isRecord8(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -76445,7 +76721,7 @@ function readFanout(cwd, name) {
|
|
|
76445
76721
|
const dir = fanoutsDir(cwd);
|
|
76446
76722
|
if (!dir.ok)
|
|
76447
76723
|
return dir;
|
|
76448
|
-
const file =
|
|
76724
|
+
const file = path45.join(dir.data, stackFileName(name));
|
|
76449
76725
|
let parsed = null;
|
|
76450
76726
|
try {
|
|
76451
76727
|
parsed = parseStored(JSON.parse(fs23.readFileSync(file, "utf8")));
|
|
@@ -76470,7 +76746,7 @@ function listFanouts(cwd) {
|
|
|
76470
76746
|
for (const entry of names) {
|
|
76471
76747
|
let parsed = null;
|
|
76472
76748
|
try {
|
|
76473
|
-
parsed = parseStored(JSON.parse(fs23.readFileSync(
|
|
76749
|
+
parsed = parseStored(JSON.parse(fs23.readFileSync(path45.join(dir.data, entry), "utf8")));
|
|
76474
76750
|
} catch {
|
|
76475
76751
|
parsed = null;
|
|
76476
76752
|
}
|
|
@@ -76500,7 +76776,7 @@ function writeFanout(cwd, plan) {
|
|
|
76500
76776
|
const dir = fanoutsDir(cwd);
|
|
76501
76777
|
if (!dir.ok)
|
|
76502
76778
|
return dir;
|
|
76503
|
-
const file =
|
|
76779
|
+
const file = path45.join(dir.data, stackFileName(plan.name));
|
|
76504
76780
|
const temp = `${file}.${process.pid}.tmp`;
|
|
76505
76781
|
try {
|
|
76506
76782
|
fs23.mkdirSync(dir.data, { recursive: true });
|
|
@@ -76704,7 +76980,7 @@ var init_fanout = __esm(() => {
|
|
|
76704
76980
|
// packages/workit-core/src/fanout-worktree.ts
|
|
76705
76981
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
76706
76982
|
import fs24 from "node:fs";
|
|
76707
|
-
import
|
|
76983
|
+
import path46 from "node:path";
|
|
76708
76984
|
function rowSample(lines) {
|
|
76709
76985
|
const out = [];
|
|
76710
76986
|
let bytes = 0;
|
|
@@ -76764,7 +77040,7 @@ function adminDir(worktree) {
|
|
|
76764
77040
|
const file = dir.stdout.trim();
|
|
76765
77041
|
let token = null;
|
|
76766
77042
|
try {
|
|
76767
|
-
token = fs24.readFileSync(
|
|
77043
|
+
token = fs24.readFileSync(path46.join(file, TOKEN_FILE), "utf8").trim() || null;
|
|
76768
77044
|
} catch {
|
|
76769
77045
|
token = null;
|
|
76770
77046
|
}
|
|
@@ -76772,7 +77048,7 @@ function adminDir(worktree) {
|
|
|
76772
77048
|
const stat = worktreeDeps.stat(file);
|
|
76773
77049
|
return {
|
|
76774
77050
|
path: file,
|
|
76775
|
-
id:
|
|
77051
|
+
id: path46.basename(file),
|
|
76776
77052
|
ino: stat.ino.toString(),
|
|
76777
77053
|
token,
|
|
76778
77054
|
birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
|
|
@@ -76788,7 +77064,7 @@ function markAdminDir(worktree) {
|
|
|
76788
77064
|
return null;
|
|
76789
77065
|
const token = randomBytes4(16).toString("hex");
|
|
76790
77066
|
try {
|
|
76791
|
-
fs24.writeFileSync(
|
|
77067
|
+
fs24.writeFileSync(path46.join(admin.path, TOKEN_FILE), `${token}
|
|
76792
77068
|
`);
|
|
76793
77069
|
} catch {
|
|
76794
77070
|
return null;
|
|
@@ -76803,7 +77079,7 @@ function excludeScratch(cwd) {
|
|
|
76803
77079
|
const common = gitCommonDir(cwd);
|
|
76804
77080
|
if (!common)
|
|
76805
77081
|
return;
|
|
76806
|
-
const file =
|
|
77082
|
+
const file = path46.join(common, "info", "exclude");
|
|
76807
77083
|
let text = "";
|
|
76808
77084
|
try {
|
|
76809
77085
|
text = fs24.readFileSync(file, "utf8");
|
|
@@ -76812,7 +77088,7 @@ function excludeScratch(cwd) {
|
|
|
76812
77088
|
}
|
|
76813
77089
|
if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
|
|
76814
77090
|
return;
|
|
76815
|
-
fs24.mkdirSync(
|
|
77091
|
+
fs24.mkdirSync(path46.dirname(file), { recursive: true });
|
|
76816
77092
|
fs24.appendFileSync(file, `${text && !text.endsWith(`
|
|
76817
77093
|
`) ? `
|
|
76818
77094
|
` : ""}# workit fanout: per-worker scratch dirs
|
|
@@ -76820,7 +77096,7 @@ ${EXCLUDE_LINE}
|
|
|
76820
77096
|
`);
|
|
76821
77097
|
}
|
|
76822
77098
|
function ensureScratch(worktree) {
|
|
76823
|
-
const scratch =
|
|
77099
|
+
const scratch = path46.join(worktree, SCRATCH_DIR);
|
|
76824
77100
|
fs24.mkdirSync(scratch, { recursive: true });
|
|
76825
77101
|
return scratch;
|
|
76826
77102
|
}
|
|
@@ -77038,7 +77314,7 @@ function unpushedCount(cwd, branch) {
|
|
|
77038
77314
|
return count.ok ? Number(count.stdout.trim()) : null;
|
|
77039
77315
|
}
|
|
77040
77316
|
function removeScratch(worktree) {
|
|
77041
|
-
const scratch =
|
|
77317
|
+
const scratch = path46.join(worktree, SCRATCH_DIR);
|
|
77042
77318
|
let stat;
|
|
77043
77319
|
try {
|
|
77044
77320
|
stat = fs24.lstatSync(scratch);
|
|
@@ -77054,16 +77330,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
77054
77330
|
try {
|
|
77055
77331
|
return fs24.realpathSync.native(target);
|
|
77056
77332
|
} catch {
|
|
77057
|
-
return
|
|
77333
|
+
return path46.resolve(target);
|
|
77058
77334
|
}
|
|
77059
77335
|
}, samePath = (a, b) => {
|
|
77060
77336
|
const left = canonical2(a);
|
|
77061
77337
|
const right = canonical2(b);
|
|
77062
77338
|
return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
77063
77339
|
}, inside2 = (child, parent) => {
|
|
77064
|
-
const relative =
|
|
77065
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
77066
|
-
}, slicePath = (cwd, slice) =>
|
|
77340
|
+
const relative = path46.relative(canonical2(parent), canonical2(child));
|
|
77341
|
+
return relative === "" || !relative.startsWith("..") && !path46.isAbsolute(relative);
|
|
77342
|
+
}, slicePath = (cwd, slice) => path46.isAbsolute(slice.worktree) ? slice.worktree : path46.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, TOKEN_FILE = "workit-fanout-token", worktreeDeps, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
|
|
77067
77343
|
`)[0] || "unknown error"}`);
|
|
77068
77344
|
var init_fanout_worktree = __esm(() => {
|
|
77069
77345
|
init_ops();
|
|
@@ -77839,7 +78115,7 @@ __export(exports_fanout, {
|
|
|
77839
78115
|
run: () => run15
|
|
77840
78116
|
});
|
|
77841
78117
|
import fs25 from "node:fs";
|
|
77842
|
-
import
|
|
78118
|
+
import path47 from "node:path";
|
|
77843
78119
|
function forgeFor(io, offline) {
|
|
77844
78120
|
if (offline)
|
|
77845
78121
|
return { forge: null, error: "--offline" };
|
|
@@ -77900,7 +78176,7 @@ function plan2(argv, io) {
|
|
|
77900
78176
|
return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
|
|
77901
78177
|
if (flags.positionals.length !== 1)
|
|
77902
78178
|
return usage3(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
|
|
77903
|
-
const file =
|
|
78179
|
+
const file = path47.resolve(io.cwd, flags.positionals[0]);
|
|
77904
78180
|
let raw;
|
|
77905
78181
|
try {
|
|
77906
78182
|
raw = JSON.parse(fs25.readFileSync(file, "utf8"));
|
|
@@ -93332,7 +93608,7 @@ var init_ast = __esm(() => {
|
|
|
93332
93608
|
|
|
93333
93609
|
// packages/workit-cli/src/test-audit/rules.ts
|
|
93334
93610
|
import { builtinModules } from "node:module";
|
|
93335
|
-
import
|
|
93611
|
+
import path48 from "node:path";
|
|
93336
93612
|
function testCallee(call) {
|
|
93337
93613
|
let callee = call.callee;
|
|
93338
93614
|
if (callee.type === "CallExpression")
|
|
@@ -93825,12 +94101,12 @@ function checkConstantsOnly(ctx, emit) {
|
|
|
93825
94101
|
}
|
|
93826
94102
|
function checkOverMocking(ctx, emit) {
|
|
93827
94103
|
const { program } = ctx.parsed;
|
|
93828
|
-
const unit =
|
|
94104
|
+
const unit = path48.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
|
|
93829
94105
|
const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
|
|
93830
94106
|
const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
|
|
93831
94107
|
for (const call of mocked) {
|
|
93832
94108
|
const spec = call.arguments[0].value;
|
|
93833
|
-
const base =
|
|
94109
|
+
const base = path48.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
93834
94110
|
if (base === unit)
|
|
93835
94111
|
emit({
|
|
93836
94112
|
rule: "over-mocking",
|
|
@@ -94219,8 +94495,8 @@ var init_rules = __esm(() => {
|
|
|
94219
94495
|
|
|
94220
94496
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
94221
94497
|
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
94222
|
-
import { existsSync as
|
|
94223
|
-
import
|
|
94498
|
+
import { existsSync as existsSync19, readdirSync as readdirSync8, readFileSync as readFileSync21, statSync as statSync7 } from "node:fs";
|
|
94499
|
+
import path49 from "node:path";
|
|
94224
94500
|
function git6(cwd, args) {
|
|
94225
94501
|
const run = spawnSync23("git", ["-c", "core.quotepath=off", ...args], {
|
|
94226
94502
|
cwd,
|
|
@@ -94233,7 +94509,7 @@ function walkTests(dir, out) {
|
|
|
94233
94509
|
for (const entry of readdirSync8(dir, { withFileTypes: true })) {
|
|
94234
94510
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
94235
94511
|
continue;
|
|
94236
|
-
const full =
|
|
94512
|
+
const full = path49.join(dir, entry.name);
|
|
94237
94513
|
if (entry.isDirectory()) {
|
|
94238
94514
|
if (!SKIP_DIRS.has(entry.name))
|
|
94239
94515
|
walkTests(full, out);
|
|
@@ -94245,8 +94521,8 @@ function expandPaths(cwd, inputs) {
|
|
|
94245
94521
|
const files = [];
|
|
94246
94522
|
const missing = [];
|
|
94247
94523
|
for (const input of inputs.length > 0 ? inputs : ["."]) {
|
|
94248
|
-
const full =
|
|
94249
|
-
if (!
|
|
94524
|
+
const full = path49.resolve(cwd, input);
|
|
94525
|
+
if (!existsSync19(full))
|
|
94250
94526
|
missing.push(input);
|
|
94251
94527
|
else if (statSync7(full).isDirectory())
|
|
94252
94528
|
walkTests(full, files);
|
|
@@ -94282,11 +94558,11 @@ function changedLines(cwd, base) {
|
|
|
94282
94558
|
for (let offset = 0;offset < count; offset += 1)
|
|
94283
94559
|
lines.add(start + offset);
|
|
94284
94560
|
}
|
|
94285
|
-
changed.set(
|
|
94561
|
+
changed.set(path49.join(root, file), lines);
|
|
94286
94562
|
}
|
|
94287
94563
|
const untracked = git6(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
94288
94564
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
94289
|
-
changed.set(
|
|
94565
|
+
changed.set(path49.join(root, file), "all");
|
|
94290
94566
|
return changed;
|
|
94291
94567
|
}
|
|
94292
94568
|
function auditFiles(files, display) {
|
|
@@ -94299,7 +94575,7 @@ function auditFiles(files, display) {
|
|
|
94299
94575
|
const shown = display(file);
|
|
94300
94576
|
let parsed;
|
|
94301
94577
|
try {
|
|
94302
|
-
parsed = parseSource(
|
|
94578
|
+
parsed = parseSource(readFileSync21(file, "utf8"), file);
|
|
94303
94579
|
} catch (error) {
|
|
94304
94580
|
parseErrors.push({
|
|
94305
94581
|
file: shown,
|
|
@@ -94348,7 +94624,7 @@ function auditFiles(files, display) {
|
|
|
94348
94624
|
durationMs: Math.round(performance.now() - started)
|
|
94349
94625
|
};
|
|
94350
94626
|
}
|
|
94351
|
-
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(
|
|
94627
|
+
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path49.sep).join("/"), SEVERITY_ORDER, ruleIds;
|
|
94352
94628
|
var init_audit = __esm(() => {
|
|
94353
94629
|
init_ast();
|
|
94354
94630
|
init_rules();
|
|
@@ -94362,12 +94638,12 @@ var init_audit = __esm(() => {
|
|
|
94362
94638
|
// packages/workit-cli/src/test-audit/mutate.ts
|
|
94363
94639
|
import { spawn as spawn2 } from "node:child_process";
|
|
94364
94640
|
import {
|
|
94365
|
-
existsSync as
|
|
94641
|
+
existsSync as existsSync20,
|
|
94366
94642
|
lstatSync as lstatSync7,
|
|
94367
94643
|
mkdirSync as mkdirSync9,
|
|
94368
94644
|
mkdtempSync as mkdtempSync4,
|
|
94369
94645
|
readdirSync as readdirSync9,
|
|
94370
|
-
readFileSync as
|
|
94646
|
+
readFileSync as readFileSync22,
|
|
94371
94647
|
readlinkSync as readlinkSync3,
|
|
94372
94648
|
realpathSync as realpathSync9,
|
|
94373
94649
|
renameSync as renameSync5,
|
|
@@ -94378,7 +94654,7 @@ import {
|
|
|
94378
94654
|
copyFileSync as copyFileSync6
|
|
94379
94655
|
} from "node:fs";
|
|
94380
94656
|
import os14 from "node:os";
|
|
94381
|
-
import
|
|
94657
|
+
import path50 from "node:path";
|
|
94382
94658
|
function mutantsFor(source, file, lines) {
|
|
94383
94659
|
const parsed = parseSource(source, file);
|
|
94384
94660
|
const out = [];
|
|
@@ -94451,7 +94727,7 @@ function relatedTests(source, testFiles) {
|
|
|
94451
94727
|
for (const match of text.matchAll(SPECIFIER)) {
|
|
94452
94728
|
const spec = match[1];
|
|
94453
94729
|
if (spec.startsWith(".")) {
|
|
94454
|
-
if (stripExt(
|
|
94730
|
+
if (stripExt(path50.posix.join(path50.posix.dirname(file), spec)) === target)
|
|
94455
94731
|
return true;
|
|
94456
94732
|
} else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
|
|
94457
94733
|
return true;
|
|
@@ -94471,12 +94747,12 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
94471
94747
|
for (const name of names) {
|
|
94472
94748
|
if (!name.startsWith(TEMP_PREFIX))
|
|
94473
94749
|
continue;
|
|
94474
|
-
const dir =
|
|
94750
|
+
const dir = path50.join(tmp, name);
|
|
94475
94751
|
try {
|
|
94476
94752
|
const stat = lstatSync7(dir);
|
|
94477
94753
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
94478
94754
|
continue;
|
|
94479
|
-
const pid = Number(
|
|
94755
|
+
const pid = Number(readFileSync22(path50.join(dir, PID_FILE), "utf8"));
|
|
94480
94756
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
94481
94757
|
continue;
|
|
94482
94758
|
} catch (error) {
|
|
@@ -94493,8 +94769,8 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
94493
94769
|
function linkNodeModules(origin, target, repo, copy) {
|
|
94494
94770
|
mkdirSync9(target, { recursive: true });
|
|
94495
94771
|
for (const entry of readdirSync9(origin, { withFileTypes: true })) {
|
|
94496
|
-
const from =
|
|
94497
|
-
const to =
|
|
94772
|
+
const from = path50.join(origin, entry.name);
|
|
94773
|
+
const to = path50.join(target, entry.name);
|
|
94498
94774
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
94499
94775
|
linkNodeModules(from, to, repo, copy);
|
|
94500
94776
|
continue;
|
|
@@ -94510,9 +94786,9 @@ function linkNodeModules(origin, target, repo, copy) {
|
|
|
94510
94786
|
} catch {
|
|
94511
94787
|
continue;
|
|
94512
94788
|
}
|
|
94513
|
-
const relative =
|
|
94514
|
-
if (!relative.startsWith("..") && !
|
|
94515
|
-
symlinkSync(
|
|
94789
|
+
const relative = path50.relative(repo, real);
|
|
94790
|
+
if (!relative.startsWith("..") && !path50.isAbsolute(relative) && !relative.split(path50.sep).includes("node_modules")) {
|
|
94791
|
+
symlinkSync(path50.join(copy, relative), to, "junction");
|
|
94516
94792
|
continue;
|
|
94517
94793
|
}
|
|
94518
94794
|
}
|
|
@@ -94528,7 +94804,7 @@ function copySymlink(repo, tree, from, to) {
|
|
|
94528
94804
|
}
|
|
94529
94805
|
const realRepo = realpathSync9(repo);
|
|
94530
94806
|
if (real && inside3(realRepo, real)) {
|
|
94531
|
-
symlinkSync(
|
|
94807
|
+
symlinkSync(path50.relative(path50.dirname(to), path50.join(tree, path50.relative(realRepo, real))), to);
|
|
94532
94808
|
return;
|
|
94533
94809
|
}
|
|
94534
94810
|
if (real && statSync8(real).isFile())
|
|
@@ -94537,10 +94813,10 @@ function copySymlink(repo, tree, from, to) {
|
|
|
94537
94813
|
symlinkSync(readlinkSync3(from), to);
|
|
94538
94814
|
}
|
|
94539
94815
|
function writeInside(copy, file, content) {
|
|
94540
|
-
const target =
|
|
94816
|
+
const target = path50.join(copy, file);
|
|
94541
94817
|
try {
|
|
94542
94818
|
const stat = lstatSync7(target);
|
|
94543
|
-
if (!stat.isFile() || !inside3(realpathSync9(copy), realpathSync9(
|
|
94819
|
+
if (!stat.isFile() || !inside3(realpathSync9(copy), realpathSync9(path50.dirname(target))))
|
|
94544
94820
|
return false;
|
|
94545
94821
|
} catch {
|
|
94546
94822
|
return false;
|
|
@@ -94551,9 +94827,9 @@ function writeInside(copy, file, content) {
|
|
|
94551
94827
|
return true;
|
|
94552
94828
|
}
|
|
94553
94829
|
function copyWorkingTree(repo) {
|
|
94554
|
-
const dir = mkdtempSync4(
|
|
94555
|
-
writeFileSync10(
|
|
94556
|
-
const tree =
|
|
94830
|
+
const dir = mkdtempSync4(path50.join(os14.tmpdir(), TEMP_PREFIX));
|
|
94831
|
+
writeFileSync10(path50.join(dir, PID_FILE), String(process.pid));
|
|
94832
|
+
const tree = path50.join(dir, "tree");
|
|
94557
94833
|
const head = git6(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
94558
94834
|
if (head && git6(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
94559
94835
|
const branch = git6(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
@@ -94570,29 +94846,29 @@ function copyWorkingTree(repo) {
|
|
|
94570
94846
|
for (const relative of listed) {
|
|
94571
94847
|
if (!relative)
|
|
94572
94848
|
continue;
|
|
94573
|
-
const from =
|
|
94849
|
+
const from = path50.join(repo, relative);
|
|
94574
94850
|
let stat;
|
|
94575
94851
|
try {
|
|
94576
94852
|
stat = lstatSync7(from);
|
|
94577
94853
|
} catch {
|
|
94578
94854
|
continue;
|
|
94579
94855
|
}
|
|
94580
|
-
const to =
|
|
94581
|
-
mkdirSync9(
|
|
94856
|
+
const to = path50.join(tree, relative);
|
|
94857
|
+
mkdirSync9(path50.dirname(to), { recursive: true });
|
|
94582
94858
|
if (stat.isSymbolicLink())
|
|
94583
94859
|
copySymlink(repo, tree, from, to);
|
|
94584
94860
|
else if (stat.isFile())
|
|
94585
94861
|
copyFileSync6(from, to);
|
|
94586
|
-
let parent =
|
|
94862
|
+
let parent = path50.dirname(relative);
|
|
94587
94863
|
while (parent !== "." && !dirs.has(parent)) {
|
|
94588
94864
|
dirs.add(parent);
|
|
94589
|
-
parent =
|
|
94865
|
+
parent = path50.dirname(parent);
|
|
94590
94866
|
}
|
|
94591
94867
|
}
|
|
94592
94868
|
for (const parent of dirs) {
|
|
94593
|
-
const modules =
|
|
94594
|
-
if (
|
|
94595
|
-
linkNodeModules(modules,
|
|
94869
|
+
const modules = path50.join(repo, parent, "node_modules");
|
|
94870
|
+
if (existsSync20(modules) && !existsSync20(path50.join(tree, parent, "node_modules")))
|
|
94871
|
+
linkNodeModules(modules, path50.join(tree, parent, "node_modules"), repo, tree);
|
|
94596
94872
|
}
|
|
94597
94873
|
return { dir, tree };
|
|
94598
94874
|
}
|
|
@@ -94631,20 +94907,20 @@ async function runMutation(options) {
|
|
|
94631
94907
|
const tracked = git6(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
94632
94908
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
94633
94909
|
try {
|
|
94634
|
-
return { file, text:
|
|
94910
|
+
return { file, text: readFileSync22(path50.join(repo, file), "utf8") };
|
|
94635
94911
|
} catch {
|
|
94636
94912
|
return { file, text: "" };
|
|
94637
94913
|
}
|
|
94638
94914
|
});
|
|
94639
94915
|
const candidates = [];
|
|
94640
94916
|
for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
94641
|
-
const relative = toPosix(
|
|
94917
|
+
const relative = toPosix(path50.relative(repo, absolute));
|
|
94642
94918
|
if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
|
|
94643
94919
|
continue;
|
|
94644
|
-
if (NOT_SOURCE.test(relative) || !
|
|
94920
|
+
if (NOT_SOURCE.test(relative) || !existsSync20(absolute))
|
|
94645
94921
|
continue;
|
|
94646
94922
|
try {
|
|
94647
|
-
candidates.push(...mutantsFor(
|
|
94923
|
+
candidates.push(...mutantsFor(readFileSync22(absolute, "utf8"), relative, lines));
|
|
94648
94924
|
} catch {}
|
|
94649
94925
|
}
|
|
94650
94926
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -94652,9 +94928,9 @@ async function runMutation(options) {
|
|
|
94652
94928
|
for (const mutant of mutants)
|
|
94653
94929
|
if (!related.has(mutant.file))
|
|
94654
94930
|
related.set(mutant.file, relatedTests(mutant.file, testFiles));
|
|
94655
|
-
const cwdRelative =
|
|
94931
|
+
const cwdRelative = path50.relative(repo, options.cwd);
|
|
94656
94932
|
const asArg = (file) => {
|
|
94657
|
-
const relative = toPosix(
|
|
94933
|
+
const relative = toPosix(path50.relative(cwdRelative, file));
|
|
94658
94934
|
return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
|
|
94659
94935
|
};
|
|
94660
94936
|
const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
|
|
@@ -94689,7 +94965,7 @@ async function runMutation(options) {
|
|
|
94689
94965
|
return finish2(options, 0, results, counts, started);
|
|
94690
94966
|
removeStaleCopies();
|
|
94691
94967
|
const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
|
|
94692
|
-
const copyCwd =
|
|
94968
|
+
const copyCwd = path50.join(copy, cwdRelative);
|
|
94693
94969
|
let current = null;
|
|
94694
94970
|
const restore = () => {
|
|
94695
94971
|
if (current)
|
|
@@ -94724,7 +95000,7 @@ async function runMutation(options) {
|
|
|
94724
95000
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
94725
95001
|
continue;
|
|
94726
95002
|
}
|
|
94727
|
-
const original =
|
|
95003
|
+
const original = readFileSync22(path50.join(copy, mutant.file), "utf8");
|
|
94728
95004
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
94729
95005
|
current = { file: mutant.file, original };
|
|
94730
95006
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -94781,8 +95057,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
|
|
|
94781
95057
|
return error.code === "EPERM";
|
|
94782
95058
|
}
|
|
94783
95059
|
}, inside3 = (root, file) => {
|
|
94784
|
-
const relative =
|
|
94785
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
95060
|
+
const relative = path50.relative(root, file);
|
|
95061
|
+
return relative === "" || !relative.startsWith("..") && !path50.isAbsolute(relative);
|
|
94786
95062
|
}, active, killTree = (child) => {
|
|
94787
95063
|
try {
|
|
94788
95064
|
if (child.pid && process.platform !== "win32")
|
|
@@ -94830,8 +95106,8 @@ var exports_test_audit = {};
|
|
|
94830
95106
|
__export(exports_test_audit, {
|
|
94831
95107
|
run: () => run17
|
|
94832
95108
|
});
|
|
94833
|
-
import { existsSync as
|
|
94834
|
-
import
|
|
95109
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
95110
|
+
import path51 from "node:path";
|
|
94835
95111
|
function parse7(argv) {
|
|
94836
95112
|
const options = {
|
|
94837
95113
|
paths: [],
|
|
@@ -94935,8 +95211,8 @@ async function run17(argv, io) {
|
|
|
94935
95211
|
return emit(io, fail("invalid_input", `${options}
|
|
94936
95212
|
usage: ${USAGE10}`));
|
|
94937
95213
|
const top = git6(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
94938
|
-
const repo = top.ok ?
|
|
94939
|
-
const display = (file) => toPosix(
|
|
95214
|
+
const repo = top.ok ? path51.resolve(top.stdout.trim()) : null;
|
|
95215
|
+
const display = (file) => toPosix(path51.relative(io.cwd, file) || file);
|
|
94940
95216
|
let base = null;
|
|
94941
95217
|
let changed = null;
|
|
94942
95218
|
if (options.diff || options.mutate) {
|
|
@@ -94953,7 +95229,7 @@ usage: ${USAGE10}`));
|
|
|
94953
95229
|
}
|
|
94954
95230
|
let files;
|
|
94955
95231
|
if (options.diff && changed)
|
|
94956
|
-
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) &&
|
|
95232
|
+
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync21(file)).toSorted();
|
|
94957
95233
|
else {
|
|
94958
95234
|
const expanded = expandPaths(io.cwd, options.paths);
|
|
94959
95235
|
if (expanded.missing.length > 0)
|
|
@@ -95178,8 +95454,8 @@ var exports_youtrack = {};
|
|
|
95178
95454
|
__export(exports_youtrack, {
|
|
95179
95455
|
run: () => run19
|
|
95180
95456
|
});
|
|
95181
|
-
import { readFileSync as
|
|
95182
|
-
import
|
|
95457
|
+
import { readFileSync as readFileSync23 } from "node:fs";
|
|
95458
|
+
import path52 from "node:path";
|
|
95183
95459
|
async function run19(argv, io) {
|
|
95184
95460
|
const [sub, ...rest] = argv;
|
|
95185
95461
|
if (sub !== "note" && sub !== "time" && sub !== "meeting")
|
|
@@ -95225,7 +95501,7 @@ async function run19(argv, io) {
|
|
|
95225
95501
|
let markdown = flags.values.markdown ?? "";
|
|
95226
95502
|
if (flags.values.file)
|
|
95227
95503
|
try {
|
|
95228
|
-
markdown =
|
|
95504
|
+
markdown = readFileSync23(path52.resolve(io.cwd, flags.values.file), "utf8");
|
|
95229
95505
|
} catch (error) {
|
|
95230
95506
|
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE12);
|
|
95231
95507
|
}
|
|
@@ -95293,8 +95569,8 @@ var exports_changelog = {};
|
|
|
95293
95569
|
__export(exports_changelog, {
|
|
95294
95570
|
run: () => run20
|
|
95295
95571
|
});
|
|
95296
|
-
import { readFileSync as
|
|
95297
|
-
import
|
|
95572
|
+
import { readFileSync as readFileSync24 } from "node:fs";
|
|
95573
|
+
import path53 from "node:path";
|
|
95298
95574
|
async function run20(argv, io) {
|
|
95299
95575
|
const [sub, ...rest] = argv;
|
|
95300
95576
|
if (sub !== "apply")
|
|
@@ -95340,7 +95616,7 @@ async function run20(argv, io) {
|
|
|
95340
95616
|
]);
|
|
95341
95617
|
}
|
|
95342
95618
|
var USAGE13 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
95343
|
-
const text = raw === "-" ?
|
|
95619
|
+
const text = raw === "-" ? readFileSync24(0, "utf8") : raw.startsWith("@") ? readFileSync24(path53.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
95344
95620
|
return JSON.parse(text);
|
|
95345
95621
|
};
|
|
95346
95622
|
var init_changelog2 = __esm(() => {
|
|
@@ -95436,7 +95712,7 @@ var init_handoff = __esm(() => {
|
|
|
95436
95712
|
|
|
95437
95713
|
// packages/workit-cli/src/main.ts
|
|
95438
95714
|
init_package();
|
|
95439
|
-
import
|
|
95715
|
+
import path54 from "node:path";
|
|
95440
95716
|
|
|
95441
95717
|
// packages/workit-cli/src/help.ts
|
|
95442
95718
|
var HELP_FLAGS = new Set(["--help", "-h"]);
|
|
@@ -95764,8 +96040,8 @@ var VERBS = [
|
|
|
95764
96040
|
},
|
|
95765
96041
|
{
|
|
95766
96042
|
name: "commit",
|
|
95767
|
-
usage: "workit git commit -m|--message <msg>… [-a|--all | [--] <paths…>]",
|
|
95768
|
-
summary: "Commit with a linted Conventional Commit message and the session trailer"
|
|
96043
|
+
usage: "workit git commit -m|--message <msg>… | -F|--file <file|-> [--amend [--no-edit]] [--allow-empty] [-a|--all | [--] <paths…>]",
|
|
96044
|
+
summary: "Commit (or --amend) with a linted Conventional Commit message and the session trailer"
|
|
95769
96045
|
},
|
|
95770
96046
|
{
|
|
95771
96047
|
name: "push",
|
|
@@ -95776,6 +96052,7 @@ var VERBS = [
|
|
|
95776
96052
|
examples: [
|
|
95777
96053
|
"workit git branch --kind feature --slug help-everywhere",
|
|
95778
96054
|
'workit git commit -m "fix(cli): answer help flags first" --all',
|
|
96055
|
+
"workit git commit --amend --no-edit -- src/forgotten.ts",
|
|
95779
96056
|
"workit git push --set-upstream"
|
|
95780
96057
|
],
|
|
95781
96058
|
load: () => Promise.resolve().then(() => (init_git2(), exports_git))
|
|
@@ -96056,7 +96333,7 @@ var defaultIo = (json) => ({
|
|
|
96056
96333
|
});
|
|
96057
96334
|
async function main(argv, overrides = {}, options = {}) {
|
|
96058
96335
|
const parsed = parseGlobals(argv);
|
|
96059
|
-
const cwd =
|
|
96336
|
+
const cwd = path54.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
96060
96337
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
96061
96338
|
if (parsed.error)
|
|
96062
96339
|
return emit(io, fail("invalid_input", parsed.error));
|