@brainervirus/workit-cursor 8.17.1 → 8.19.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/.cursor-plugin/plugin.json +1 -1
- package/dist/cursor-session-start.js +279 -240
- package/dist/mcp-server.js +4411 -4400
- package/dist/workit-hook.js +280 -240
- package/package.json +3 -3
- package/skills/workit-bdd/SKILL.md +1 -1
- package/skills/workit-fanout/SKILL.md +2 -2
- package/skills/workit-fanout/references/orchestration.md +21 -0
- package/skills/workit-retro/SKILL.md +2 -2
- package/skills/workit-review/SKILL.md +4 -1
- package/skills/workit-ship/SKILL.md +1 -1
- package/skills/workit-verify-app/SKILL.md +1 -1
|
@@ -10331,6 +10331,221 @@ var init_vcs_config = __esm(() => {
|
|
|
10331
10331
|
TRACKERS = new Set(["github", "gitlab", "youtrack"]);
|
|
10332
10332
|
});
|
|
10333
10333
|
|
|
10334
|
+
// packages/workit-core/src/core/commit-flavors.ts
|
|
10335
|
+
var init_commit_flavors = () => {};
|
|
10336
|
+
|
|
10337
|
+
// packages/workit-core/src/core/git.ts
|
|
10338
|
+
var init_git = () => {};
|
|
10339
|
+
|
|
10340
|
+
// packages/workit-core/src/core/branch.ts
|
|
10341
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
10342
|
+
function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
10343
|
+
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
10344
|
+
const config = readConfig();
|
|
10345
|
+
return kind === "branch" ? {
|
|
10346
|
+
branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null, () => repoBranchPreset(workspaceRoot))),
|
|
10347
|
+
provenance: { branchPolicy: selected.source }
|
|
10348
|
+
} : {
|
|
10349
|
+
commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
|
|
10350
|
+
provenance: { commitPolicy: selected.source }
|
|
10351
|
+
};
|
|
10352
|
+
}
|
|
10353
|
+
var withReleaseTracks = (workspaceRoot, policy) => {
|
|
10354
|
+
const read = workspaceReleaseTracks(workspaceRoot);
|
|
10355
|
+
if (read.error)
|
|
10356
|
+
throw new ReleaseTrackError(read.error);
|
|
10357
|
+
if (read.tracks.length === 0 && read.protectedBranches.length === 0)
|
|
10358
|
+
return policy;
|
|
10359
|
+
const known = new Set(policy.allowed.map((pattern) => pattern.source));
|
|
10360
|
+
const allowed = [...policy.allowed];
|
|
10361
|
+
for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
|
|
10362
|
+
const pattern = branchGlobPattern(glob);
|
|
10363
|
+
if (!known.has(pattern.source)) {
|
|
10364
|
+
known.add(pattern.source);
|
|
10365
|
+
allowed.push(pattern);
|
|
10366
|
+
}
|
|
10367
|
+
}
|
|
10368
|
+
return {
|
|
10369
|
+
...policy,
|
|
10370
|
+
allowed,
|
|
10371
|
+
protected: new Set([
|
|
10372
|
+
...policy.protected,
|
|
10373
|
+
...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
|
|
10374
|
+
])
|
|
10375
|
+
};
|
|
10376
|
+
}, KIND_SYNONYMS, allowedKinds = (allowed) => [
|
|
10377
|
+
...new Set(allowed.map((pattern) => /^\^([\w.-]+)\\?\/\.\*\$$/u.exec(pattern.source)?.[1]?.toLowerCase()).filter((kind) => Boolean(kind)))
|
|
10378
|
+
], editDistance = (a, b) => {
|
|
10379
|
+
const row = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
10380
|
+
for (let i = 1;i <= a.length; i++) {
|
|
10381
|
+
let previous = row[0];
|
|
10382
|
+
row[0] = i;
|
|
10383
|
+
for (let j = 1;j <= b.length; j++) {
|
|
10384
|
+
const saved = row[j];
|
|
10385
|
+
row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
10386
|
+
previous = saved;
|
|
10387
|
+
}
|
|
10388
|
+
}
|
|
10389
|
+
return row[b.length];
|
|
10390
|
+
}, suggestBranchName = (name, kinds) => {
|
|
10391
|
+
if (!kinds.length)
|
|
10392
|
+
return null;
|
|
10393
|
+
const slash = name.indexOf("/");
|
|
10394
|
+
const prefix = slash > 0 ? name.slice(0, slash).toLowerCase() : "";
|
|
10395
|
+
const rest = (slash > 0 ? name.slice(slash + 1) : name) || "name";
|
|
10396
|
+
const synonym = KIND_SYNONYMS[prefix];
|
|
10397
|
+
const near = kinds.map((kind) => ({ kind, distance: editDistance(prefix, kind) })).filter((entry) => prefix && entry.distance <= 2).toSorted((a, b) => a.distance - b.distance)[0]?.kind;
|
|
10398
|
+
const kind = (synonym && kinds.includes(synonym) ? synonym : null) ?? near ?? (kinds.includes("feature") ? "feature" : kinds[0]);
|
|
10399
|
+
return `${kind}/${rest}`;
|
|
10400
|
+
}, kindList = (kinds) => kinds.map((kind) => `${kind}/`).join(", "), aliasNote = (kinds) => {
|
|
10401
|
+
const notes = [
|
|
10402
|
+
["fix", "bugfix"],
|
|
10403
|
+
["chore", "feature"]
|
|
10404
|
+
].filter(([, kind]) => kinds.includes(kind)).map(([alias, kind]) => `${alias}/ is ${kind}/`);
|
|
10405
|
+
return notes.length ? ` (${notes.join(", ")})` : "";
|
|
10406
|
+
}, validateBranchNamePolicy = (name, policy, source) => {
|
|
10407
|
+
const allowed = policy.allowed.map((pattern) => `/${pattern.source}/${pattern.flags}`);
|
|
10408
|
+
const kinds = allowedKinds(policy.allowed);
|
|
10409
|
+
if (policy.protected.has(name.toLowerCase())) {
|
|
10410
|
+
const correction = kinds.length ? `choose a non-protected branch of an allowed kind (${kindList(kinds)}), e.g. ${kinds[0]}/<slug>: workit git branch --kind ${kinds[0]} --slug <slug>` : `choose a non-protected branch matching one of: ${allowed.join(", ")}`;
|
|
10411
|
+
return {
|
|
10412
|
+
ok: false,
|
|
10413
|
+
rule: "protected_ref",
|
|
10414
|
+
source,
|
|
10415
|
+
attempted: name,
|
|
10416
|
+
correction,
|
|
10417
|
+
error: `protected_ref: branch ${JSON.stringify(name)} is protected by ${source}; ${correction}`
|
|
10418
|
+
};
|
|
10419
|
+
}
|
|
10420
|
+
if (!policy.allowed.some((pattern) => pattern.test(name))) {
|
|
10421
|
+
const suggestion = suggestBranchName(name, kinds);
|
|
10422
|
+
const correction = suggestion && policy.allowed.some((pattern) => pattern.test(suggestion)) ? `use ${JSON.stringify(suggestion)}; the allowed kinds are ${kindList(kinds)} (workit git branch ${suggestion})` : `choose a branch matching one of: ${allowed.join(", ")}`;
|
|
10423
|
+
return {
|
|
10424
|
+
ok: false,
|
|
10425
|
+
rule: "allowed_pattern",
|
|
10426
|
+
source,
|
|
10427
|
+
attempted: name,
|
|
10428
|
+
correction,
|
|
10429
|
+
error: `allowed_pattern: branch ${JSON.stringify(name)} violates ${source} policy; ${correction}`
|
|
10430
|
+
};
|
|
10431
|
+
}
|
|
10432
|
+
return { ok: true };
|
|
10433
|
+
}, branchPolicySnapshotFor = (workspaceRoot) => {
|
|
10434
|
+
const resolved = effectiveWorkspacePolicy(workspaceRoot, "branch");
|
|
10435
|
+
const branchPolicy = resolved.branchPolicy;
|
|
10436
|
+
const source = resolved.provenance.branchPolicy;
|
|
10437
|
+
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
10438
|
+
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
10439
|
+
const fingerprint = createHash6("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
10440
|
+
return {
|
|
10441
|
+
branchPolicy,
|
|
10442
|
+
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
10443
|
+
source,
|
|
10444
|
+
fingerprint
|
|
10445
|
+
};
|
|
10446
|
+
}, validateBranchNameFor = (workspaceRoot, name) => {
|
|
10447
|
+
try {
|
|
10448
|
+
const resolved = branchPolicySnapshotFor(workspaceRoot);
|
|
10449
|
+
return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
|
|
10450
|
+
} catch (error) {
|
|
10451
|
+
const correction = "repair or select a valid workspace policy before creating a branch";
|
|
10452
|
+
return {
|
|
10453
|
+
ok: false,
|
|
10454
|
+
rule: "policy_unavailable",
|
|
10455
|
+
source: "workspaces.json",
|
|
10456
|
+
attempted: name,
|
|
10457
|
+
correction,
|
|
10458
|
+
error: `policy_unavailable: cannot validate branch ${JSON.stringify(name)} because ${error instanceof Error ? error.message : String(error)}; ${correction}`
|
|
10459
|
+
};
|
|
10460
|
+
}
|
|
10461
|
+
}, resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy, gitFlowOf = (root, integration) => {
|
|
10462
|
+
try {
|
|
10463
|
+
if (resolveBranchPolicyFor(root).preset !== "gitflow")
|
|
10464
|
+
return null;
|
|
10465
|
+
const selected = resolveRuntimeWorkspacePolicy(root, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined).policy;
|
|
10466
|
+
const names = branchNames(root);
|
|
10467
|
+
const production = productionBranchOf(names);
|
|
10468
|
+
const develop = selected?.developBranch?.trim() || (integration && integration.toLowerCase() !== production ? integration : "develop");
|
|
10469
|
+
return { develop, production, developExists: names.has(develop) };
|
|
10470
|
+
} catch {
|
|
10471
|
+
return null;
|
|
10472
|
+
}
|
|
10473
|
+
}, releaseBranchesOf = (cwd) => {
|
|
10474
|
+
try {
|
|
10475
|
+
const resolved = resolveBranchPolicyFor(cwd);
|
|
10476
|
+
const flow = resolved.preset === "gitflow" ? gitFlowOf(cwd) : null;
|
|
10477
|
+
return {
|
|
10478
|
+
preset: resolved.preset,
|
|
10479
|
+
branches: flow ? [flow.production, flow.develop] : [],
|
|
10480
|
+
production: flow ? flow.production : resolved.defaultTargetBranch
|
|
10481
|
+
};
|
|
10482
|
+
} catch {
|
|
10483
|
+
return { preset: "unknown", branches: [], production: null };
|
|
10484
|
+
}
|
|
10485
|
+
}, releaseBranch = (cwd, branch) => releaseBranchesOf(cwd).branches.some((name) => name.toLowerCase() === branch.toLowerCase()), branchGuidance = (cwd) => {
|
|
10486
|
+
try {
|
|
10487
|
+
const patterns = branchPolicySnapshotFor(cwd).namePolicy.allowed;
|
|
10488
|
+
const kinds = allowedKinds(patterns);
|
|
10489
|
+
const kindShaped = new Set(kinds.map((kind) => branchGlobPattern(`${kind}/*`).source));
|
|
10490
|
+
const anyName = patterns.some((pattern) => pattern.source === "^.*$");
|
|
10491
|
+
const others = patterns.filter((pattern) => !kindShaped.has(pattern.source)).map((pattern) => globOf(pattern));
|
|
10492
|
+
const allowed = anyName ? "Any non-protected branch name is allowed here." : `${kinds.length ? `Allowed branch kinds here: ${kindList(kinds)}${aliasNote(kinds)}` : "Allowed branch names here:"}${others.length ? `${kinds.length ? "; also" : ""} names matching ${others.join(", ")}` : ""}; anything else is denied.`;
|
|
10493
|
+
const resolved = vcsConfig("resolve", cwd);
|
|
10494
|
+
const integration = resolved.ok === false ? null : String(resolved.defaultTargetBranch ?? "") || null;
|
|
10495
|
+
const flow = resolved.releaseTrack?.track ? null : gitFlowOf(cwd, integration);
|
|
10496
|
+
if (flow?.developExists)
|
|
10497
|
+
return `${allowed} git-flow: feature/, bugfix/ and release/ start from origin/${flow.develop}, hotfix/ from origin/${flow.production}; feature/ and bugfix/ land on ${flow.develop}, release/ and hotfix/ on ${flow.production}.`;
|
|
10498
|
+
const names = branchNames(cwd);
|
|
10499
|
+
const configured = String(resolved.baseBranch ?? integration ?? "") || null;
|
|
10500
|
+
const trunk = productionBranchOf(names);
|
|
10501
|
+
const base = configured && names.has(configured) ? `Branch from origin/${configured}.` : names.has(trunk) ? `Branch from origin/${trunk}${configured ? ` (the default target ${configured} does not exist here)` : ""}.` : "No base branch exists here yet; pass the base explicitly.";
|
|
10502
|
+
return `${allowed} ${base}`;
|
|
10503
|
+
} catch {
|
|
10504
|
+
return null;
|
|
10505
|
+
}
|
|
10506
|
+
}, globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*", "*").replace(/\\(.)/gu, "$1"), policy = (root) => resolveBranchPolicyFor(root), isProtected = (root, name) => policy(root).protected.has(name.toLowerCase()), isProtectedTarget = (root, name) => {
|
|
10507
|
+
try {
|
|
10508
|
+
return isProtected(root, name);
|
|
10509
|
+
} catch {
|
|
10510
|
+
return true;
|
|
10511
|
+
}
|
|
10512
|
+
};
|
|
10513
|
+
var init_branch = __esm(() => {
|
|
10514
|
+
init_branch_policy();
|
|
10515
|
+
init_commit_flavors();
|
|
10516
|
+
init_git();
|
|
10517
|
+
init_config();
|
|
10518
|
+
init_workspaces();
|
|
10519
|
+
init_vcs_config();
|
|
10520
|
+
init_release_tracks();
|
|
10521
|
+
KIND_SYNONYMS = {
|
|
10522
|
+
fix: "bugfix",
|
|
10523
|
+
fixes: "bugfix",
|
|
10524
|
+
bug: "bugfix",
|
|
10525
|
+
bugs: "bugfix",
|
|
10526
|
+
bugfixes: "bugfix",
|
|
10527
|
+
feat: "feature",
|
|
10528
|
+
features: "feature",
|
|
10529
|
+
chore: "feature",
|
|
10530
|
+
docs: "feature",
|
|
10531
|
+
doc: "feature",
|
|
10532
|
+
refactor: "feature",
|
|
10533
|
+
test: "feature",
|
|
10534
|
+
tests: "feature",
|
|
10535
|
+
ci: "feature",
|
|
10536
|
+
build: "feature",
|
|
10537
|
+
perf: "feature",
|
|
10538
|
+
style: "feature",
|
|
10539
|
+
deps: "feature",
|
|
10540
|
+
task: "feature",
|
|
10541
|
+
enhancement: "feature",
|
|
10542
|
+
hot: "hotfix",
|
|
10543
|
+
hotfixes: "hotfix",
|
|
10544
|
+
releases: "release",
|
|
10545
|
+
rel: "release"
|
|
10546
|
+
};
|
|
10547
|
+
});
|
|
10548
|
+
|
|
10334
10549
|
// packages/workit-core/src/core/logger.ts
|
|
10335
10550
|
import os3 from "node:os";
|
|
10336
10551
|
import path6 from "node:path";
|
|
@@ -10392,7 +10607,7 @@ var init_logger = __esm(() => {
|
|
|
10392
10607
|
});
|
|
10393
10608
|
|
|
10394
10609
|
// packages/workit-core/src/host-session.ts
|
|
10395
|
-
import { createHash as
|
|
10610
|
+
import { createHash as createHash7, randomBytes, timingSafeEqual } from "node:crypto";
|
|
10396
10611
|
import fs5 from "node:fs";
|
|
10397
10612
|
import path7 from "node:path";
|
|
10398
10613
|
function hostSessionFromEnv(env) {
|
|
@@ -10467,6 +10682,21 @@ function recordIssuedSession(cwd, lead, issued) {
|
|
|
10467
10682
|
return null;
|
|
10468
10683
|
}
|
|
10469
10684
|
}
|
|
10685
|
+
function judgeBranch(cwd) {
|
|
10686
|
+
const branch = currentBranch(cwd);
|
|
10687
|
+
return branch && !isProtectedTarget(cwd, branch) ? branch : null;
|
|
10688
|
+
}
|
|
10689
|
+
function verdictCommand(options) {
|
|
10690
|
+
const kind = options.judge === "verifier" ? "<live|unit>" : options.judge === "reviewer" ? "review" : "<live|unit|review>";
|
|
10691
|
+
return [
|
|
10692
|
+
"workit ledger verdict <verified|failed|blocked>",
|
|
10693
|
+
`--kind ${kind}`,
|
|
10694
|
+
`--branch ${options.branch ?? "<branch>"}`,
|
|
10695
|
+
options.session ? `--session ${options.session}` : null,
|
|
10696
|
+
options.token ? `--token=${options.token}` : null,
|
|
10697
|
+
'--how "<what you ran and saw>"'
|
|
10698
|
+
].filter(Boolean).join(" ");
|
|
10699
|
+
}
|
|
10470
10700
|
function pruneIssued(dir, own, tokens) {
|
|
10471
10701
|
try {
|
|
10472
10702
|
const entries = fs5.readdirSync(dir);
|
|
@@ -10488,7 +10718,7 @@ function issuedBinding(cwd, claimed) {
|
|
|
10488
10718
|
return null;
|
|
10489
10719
|
return leadBound ? "token" : "legacy";
|
|
10490
10720
|
}
|
|
10491
|
-
var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null, ISSUED_PER_LEAD = 64, ISSUED_SESSIONS_MARKER = "workit-issued-sessions/3", hash = (value) =>
|
|
10721
|
+
var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null, ISSUED_PER_LEAD = 64, ISSUED_SESSIONS_MARKER = "workit-issued-sessions/3", hash = (value) => createHash7("sha256").update(value).digest("hex").slice(0, 32), userIssuedRoot = () => path7.join(resolveStateDir(), "issued"), userTokenRoot = () => path7.join(resolveStateDir(), "issued-tokens"), safeList = (dir) => {
|
|
10492
10722
|
try {
|
|
10493
10723
|
return fs5.readdirSync(dir);
|
|
10494
10724
|
} catch {
|
|
@@ -10498,7 +10728,7 @@ var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "")
|
|
|
10498
10728
|
try {
|
|
10499
10729
|
fs5.rmdirSync(dir);
|
|
10500
10730
|
} catch {}
|
|
10501
|
-
}, tokenHash = (token) =>
|
|
10731
|
+
}, tokenHash = (token) => createHash7("sha256").update(token).digest("hex"), issuedRecord = (cwd, claimed) => {
|
|
10502
10732
|
const cut = claimed.lastIndexOf(":");
|
|
10503
10733
|
if (cut <= 0)
|
|
10504
10734
|
return null;
|
|
@@ -10521,7 +10751,9 @@ var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "")
|
|
|
10521
10751
|
}
|
|
10522
10752
|
}, OWN_CHILD_SHELL;
|
|
10523
10753
|
var init_host_session = __esm(() => {
|
|
10754
|
+
init_branch();
|
|
10524
10755
|
init_logger();
|
|
10756
|
+
init_rev();
|
|
10525
10757
|
init_paths();
|
|
10526
10758
|
HOST_SESSION_VARS = [
|
|
10527
10759
|
["OPENCODE_SESSION_ID", () => "opencode"],
|
|
@@ -10537,7 +10769,7 @@ var init_host_session = __esm(() => {
|
|
|
10537
10769
|
|
|
10538
10770
|
// packages/workit-core/src/ledger.ts
|
|
10539
10771
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
10540
|
-
import { createHash as
|
|
10772
|
+
import { createHash as createHash8, randomBytes as randomBytes2 } from "node:crypto";
|
|
10541
10773
|
import fs6 from "node:fs";
|
|
10542
10774
|
import path8 from "node:path";
|
|
10543
10775
|
function resolveCommit(cwd, ref) {
|
|
@@ -10593,7 +10825,7 @@ function diffHash(cwd, base, head) {
|
|
|
10593
10825
|
], GIT_TIMEOUTS.worktree);
|
|
10594
10826
|
if (!diff.ok || !diff.stdout)
|
|
10595
10827
|
return null;
|
|
10596
|
-
const hash =
|
|
10828
|
+
const hash = createHash8("sha256");
|
|
10597
10829
|
for (const line of diff.stdout.split(`
|
|
10598
10830
|
`)) {
|
|
10599
10831
|
if (line.startsWith("index "))
|
|
@@ -11196,7 +11428,7 @@ var LEDGER_VERSION = 1, MAX_LINE_BYTES = 4096, PASSING, FAILING, STRONG_RESULTS,
|
|
|
11196
11428
|
} catch {}
|
|
11197
11429
|
}
|
|
11198
11430
|
return null;
|
|
11199
|
-
}, ledgerLock, sha2562 = (text) =>
|
|
11431
|
+
}, ledgerLock, sha2562 = (text) => createHash8("sha256").update(text).digest("hex"), chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
11200
11432
|
${body}`), TAIL_BYTES, lastLine = (fd, size) => {
|
|
11201
11433
|
for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
|
|
11202
11434
|
const buffer = Buffer.alloc(span);
|
|
@@ -11526,7 +11758,7 @@ var RULES, derived2 = (spec) => ({
|
|
|
11526
11758
|
};
|
|
11527
11759
|
const since = Date.parse(task.createdAt);
|
|
11528
11760
|
const branch = ledger.branch();
|
|
11529
|
-
const row = ledger.rows().findLast((item) => item.type === "decision" && !item.superseded && (item.branch ?? null) === branch && Date.parse(item.at) >= since);
|
|
11761
|
+
const row = ledger.rows().findLast((item) => item.type === "decision" && item.by !== "decider" && !item.superseded && (item.branch ?? null) === branch && Date.parse(item.at) >= since);
|
|
11530
11762
|
return row ? { met: true, reason: `ledger decision ${row.id} records the choice`, decisionIds: [] } : {
|
|
11531
11763
|
met: false,
|
|
11532
11764
|
reason: 'open product choice: ask the user, then `workit ledger decision "<choice>" --why "<reason>"` (or, if it is not open, `workit policy assess --judge product-choice=no --why "<reason>"`)',
|
|
@@ -13162,7 +13394,7 @@ var isPlainObject2 = (value) => typeof value === "object" && value !== null && !
|
|
|
13162
13394
|
});
|
|
13163
13395
|
|
|
13164
13396
|
// packages/workit-core/src/store/reduce.ts
|
|
13165
|
-
import { createHash as
|
|
13397
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
13166
13398
|
function reduce(state, event, blobs) {
|
|
13167
13399
|
const data = event.data;
|
|
13168
13400
|
const known = KNOWN_TYPES.has(event.type);
|
|
@@ -13229,7 +13461,7 @@ function eventType(before, after) {
|
|
|
13229
13461
|
return "task.noted";
|
|
13230
13462
|
return "task.updated";
|
|
13231
13463
|
}
|
|
13232
|
-
var OPENING_TYPES, KNOWN_TYPES, isObject5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string"), BLOB_REF = "$blob", blobRef = (value) => isObject5(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null, blobDigest = (value) =>
|
|
13464
|
+
var OPENING_TYPES, KNOWN_TYPES, isObject5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string"), BLOB_REF = "$blob", blobRef = (value) => isObject5(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null, blobDigest = (value) => createHash9("sha256").update(JSON.stringify(value)).digest("hex"), toBlob = (value, blobs) => {
|
|
13233
13465
|
if (!isObject5(value))
|
|
13234
13466
|
return value;
|
|
13235
13467
|
const digest = blobDigest(value);
|
|
@@ -13300,7 +13532,7 @@ var init_notes = __esm(() => {
|
|
|
13300
13532
|
});
|
|
13301
13533
|
|
|
13302
13534
|
// packages/workit-core/src/core/task-store.ts
|
|
13303
|
-
import { createHash as
|
|
13535
|
+
import { createHash as createHash10, randomUUID as randomUUID3 } from "node:crypto";
|
|
13304
13536
|
import * as fs11 from "node:fs";
|
|
13305
13537
|
import path15 from "node:path";
|
|
13306
13538
|
|
|
@@ -14264,7 +14496,7 @@ class TaskStore {
|
|
|
14264
14496
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
14265
14497
|
}
|
|
14266
14498
|
withKeyLock(key, operation) {
|
|
14267
|
-
const digest =
|
|
14499
|
+
const digest = createHash10("sha256").update(key).digest("hex").slice(0, 32);
|
|
14268
14500
|
return this.withLock(path15.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
14269
14501
|
}
|
|
14270
14502
|
bindLocked(taskId, key, timestamp) {
|
|
@@ -15033,6 +15265,11 @@ var init_workers = __esm(() => {
|
|
|
15033
15265
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
15034
15266
|
import fs12 from "node:fs";
|
|
15035
15267
|
import path16 from "node:path";
|
|
15268
|
+
function checksConfigFile(root) {
|
|
15269
|
+
const current = path16.join(root, CHECKS_FILE);
|
|
15270
|
+
const legacy = path16.join(root, LEGACY_CHECKS_FILE);
|
|
15271
|
+
return !fs12.existsSync(current) && fs12.existsSync(legacy) ? legacy : current;
|
|
15272
|
+
}
|
|
15036
15273
|
function repoHeavyCommands(root) {
|
|
15037
15274
|
try {
|
|
15038
15275
|
const value = JSON.parse(fs12.readFileSync(checksConfigFile(root), "utf8"));
|
|
@@ -15124,19 +15361,25 @@ function detectedChecks(root) {
|
|
|
15124
15361
|
function loadCheckConfig(cwd) {
|
|
15125
15362
|
const root = checkRoot(cwd);
|
|
15126
15363
|
const file = checksConfigFile(root);
|
|
15364
|
+
const legacy = path16.basename(file) === LEGACY_CHECKS_FILE;
|
|
15365
|
+
const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
|
|
15366
|
+
const note = legacy ? {
|
|
15367
|
+
note: `${LEGACY_CHECKS_FILE} is deprecated; move it to ${CHECKS_FILE} (workit doctor --fix)`
|
|
15368
|
+
} : {};
|
|
15127
15369
|
const none = (error = null) => ({
|
|
15128
|
-
source: error ?
|
|
15370
|
+
source: error ? label : "none",
|
|
15129
15371
|
root,
|
|
15130
15372
|
checks: [],
|
|
15131
15373
|
gates: {},
|
|
15132
|
-
error
|
|
15374
|
+
error,
|
|
15375
|
+
...note
|
|
15133
15376
|
});
|
|
15134
15377
|
let text = null;
|
|
15135
15378
|
try {
|
|
15136
15379
|
text = fs12.readFileSync(file, "utf8");
|
|
15137
15380
|
} catch (error) {
|
|
15138
15381
|
if (error.code !== "ENOENT")
|
|
15139
|
-
return none(`cannot read ${
|
|
15382
|
+
return none(`cannot read ${label}: ${error.message}`);
|
|
15140
15383
|
}
|
|
15141
15384
|
if (text === null) {
|
|
15142
15385
|
const checks = detectedChecks(root);
|
|
@@ -15146,33 +15389,33 @@ function loadCheckConfig(cwd) {
|
|
|
15146
15389
|
try {
|
|
15147
15390
|
parsed = JSON.parse(text);
|
|
15148
15391
|
} catch {
|
|
15149
|
-
return none(`${
|
|
15392
|
+
return none(`${label} is not valid JSON`);
|
|
15150
15393
|
}
|
|
15151
15394
|
if (!isRecord3(parsed) || !isRecord3(parsed.checks))
|
|
15152
|
-
return none(`${
|
|
15395
|
+
return none(`${label} must be {"checks":{"<name>":"<command>"|["argv",…]}}`);
|
|
15153
15396
|
const checks = [];
|
|
15154
15397
|
for (const [name, value] of Object.entries(parsed.checks)) {
|
|
15155
15398
|
if (!CHECK_NAME.test(name))
|
|
15156
|
-
return none(`${
|
|
15399
|
+
return none(`${label}: check name "${name}" must match ${CHECK_NAME.source}`);
|
|
15157
15400
|
const argv = typeof value === "string" ? splitCommand(value) : Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string" && item.length > 0) ? value : new Error("expected a command string or a non-empty argv array");
|
|
15158
15401
|
if (argv instanceof Error)
|
|
15159
|
-
return none(`${
|
|
15402
|
+
return none(`${label}: check "${name}": ${argv.message}`);
|
|
15160
15403
|
checks.push({ name, argv, accepts: [argv] });
|
|
15161
15404
|
}
|
|
15162
15405
|
const gates = {};
|
|
15163
15406
|
if (parsed.gates !== undefined) {
|
|
15164
15407
|
if (!isRecord3(parsed.gates))
|
|
15165
|
-
return none(`${
|
|
15408
|
+
return none(`${label}: gates must be {"testing":"<name>"|["<name>",…]}`);
|
|
15166
15409
|
for (const [gate, value] of Object.entries(parsed.gates)) {
|
|
15167
15410
|
if (!GATES.includes(gate))
|
|
15168
|
-
return none(`${
|
|
15411
|
+
return none(`${label}: unknown gate "${gate}" (use ${GATES.join(" or ")})`);
|
|
15169
15412
|
const names = typeof value === "string" ? [value] : value;
|
|
15170
15413
|
if (!Array.isArray(names) || names.length === 0 || !names.every((name) => typeof name === "string" && checks.some((c) => c.name === name)))
|
|
15171
|
-
return none(`${
|
|
15414
|
+
return none(`${label}: gates.${gate} must name configured checks`);
|
|
15172
15415
|
gates[gate] = names;
|
|
15173
15416
|
}
|
|
15174
15417
|
}
|
|
15175
|
-
return { source:
|
|
15418
|
+
return { source: label, root, checks, gates, error: null, ...note, resources: parsed.resources };
|
|
15176
15419
|
}
|
|
15177
15420
|
function matchesNamedCheck(config, name, argv, cwd) {
|
|
15178
15421
|
if (config.error || name === null || cwd !== ".")
|
|
@@ -15207,7 +15450,7 @@ function workitAvailable(env = process.env) {
|
|
|
15207
15450
|
function checkCommand(args, version, onPath = workitAvailable()) {
|
|
15208
15451
|
return onPath ? `workit check ${args}` : `npx -y @brainervirus/workit-cli@${version} check ${args}`;
|
|
15209
15452
|
}
|
|
15210
|
-
var SCRIPT_CHECKS, CHECKS_FILE = "workit
|
|
15453
|
+
var SCRIPT_CHECKS, CHECKS_FILE = ".workit/checks.json", LEGACY_CHECKS_FILE = "workit.checks.json", isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SHELL_META, git4 = (cwd, args) => {
|
|
15211
15454
|
const run = spawnSync9("git", args, {
|
|
15212
15455
|
cwd,
|
|
15213
15456
|
encoding: "utf8",
|
|
@@ -15241,7 +15484,7 @@ var init_check_config = __esm(() => {
|
|
|
15241
15484
|
});
|
|
15242
15485
|
|
|
15243
15486
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
15244
|
-
import { createHash as
|
|
15487
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
15245
15488
|
import * as fs13 from "node:fs";
|
|
15246
15489
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
15247
15490
|
import path17 from "node:path";
|
|
@@ -15423,7 +15666,7 @@ function evaluateObservedGate(task, requirement, statuses, config) {
|
|
|
15423
15666
|
return {
|
|
15424
15667
|
satisfied: [],
|
|
15425
15668
|
considered,
|
|
15426
|
-
reason: requirement.dimension === "testing" && config.checks.length ? `no \`test\` check is configured; add one (or gates.testing) to ${CHECKS_FILE}, then run ${checkCommand("test", runtimeVersion())}` : `no checks are configured or detected; add ${CHECKS_FILE}
|
|
15669
|
+
reason: requirement.dimension === "testing" && config.checks.length ? `no \`test\` check is configured; add one (or gates.testing) to ${CHECKS_FILE}, then run ${checkCommand("test", runtimeVersion())}` : `no checks are configured or detected; add ${CHECKS_FILE}, e.g. {"checks":{"test":"<your test command>"}}, then run ${checkCommand("test", runtimeVersion())}`
|
|
15427
15670
|
};
|
|
15428
15671
|
const satisfied = fresh.filter(named);
|
|
15429
15672
|
if (satisfied.length)
|
|
@@ -15695,7 +15938,7 @@ function boundTaskSummary(summary) {
|
|
|
15695
15938
|
brief.truncated = JSON.stringify(brief).includes("…") || progress.blockers.length > BRIEF_BLOCKERS || unmet.length > BRIEF_OPEN;
|
|
15696
15939
|
return brief;
|
|
15697
15940
|
}
|
|
15698
|
-
var digestBytes = (value) =>
|
|
15941
|
+
var digestBytes = (value) => createHash11("sha256").update(value).digest("hex"), inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`), relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".", canonicalPath = (value) => {
|
|
15699
15942
|
if (typeof value !== "string" || !value)
|
|
15700
15943
|
return null;
|
|
15701
15944
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
@@ -17861,7 +18104,7 @@ var support = (descriptor, axis) => {
|
|
|
17861
18104
|
});
|
|
17862
18105
|
|
|
17863
18106
|
// packages/workit-core/src/hooks/context.ts
|
|
17864
|
-
import { createHash as
|
|
18107
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
17865
18108
|
import fs14 from "node:fs";
|
|
17866
18109
|
import path18 from "node:path";
|
|
17867
18110
|
function sessionCompactContext(store, session, context, selection = "session-bound") {
|
|
@@ -17996,7 +18239,7 @@ ${options.addendum}` : ""}
|
|
|
17996
18239
|
} catch {
|
|
17997
18240
|
return null;
|
|
17998
18241
|
}
|
|
17999
|
-
}, TURN_TTL_MS, digestOf = (text) =>
|
|
18242
|
+
}, TURN_TTL_MS, digestOf = (text) => createHash12("sha256").update(text).digest("hex"), turnMarker = (input) => {
|
|
18000
18243
|
if (!input.session.id)
|
|
18001
18244
|
return null;
|
|
18002
18245
|
try {
|
|
@@ -18070,215 +18313,6 @@ var init_context = __esm(() => {
|
|
|
18070
18313
|
TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
18071
18314
|
});
|
|
18072
18315
|
|
|
18073
|
-
// packages/workit-core/src/core/commit-flavors.ts
|
|
18074
|
-
var init_commit_flavors = () => {};
|
|
18075
|
-
|
|
18076
|
-
// packages/workit-core/src/core/git.ts
|
|
18077
|
-
var init_git = () => {};
|
|
18078
|
-
|
|
18079
|
-
// packages/workit-core/src/core/branch.ts
|
|
18080
|
-
import { createHash as createHash12 } from "node:crypto";
|
|
18081
|
-
function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
18082
|
-
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
18083
|
-
const config = readConfig();
|
|
18084
|
-
return kind === "branch" ? {
|
|
18085
|
-
branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null, () => repoBranchPreset(workspaceRoot))),
|
|
18086
|
-
provenance: { branchPolicy: selected.source }
|
|
18087
|
-
} : {
|
|
18088
|
-
commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
|
|
18089
|
-
provenance: { commitPolicy: selected.source }
|
|
18090
|
-
};
|
|
18091
|
-
}
|
|
18092
|
-
var withReleaseTracks = (workspaceRoot, policy) => {
|
|
18093
|
-
const read = workspaceReleaseTracks(workspaceRoot);
|
|
18094
|
-
if (read.error)
|
|
18095
|
-
throw new ReleaseTrackError(read.error);
|
|
18096
|
-
if (read.tracks.length === 0 && read.protectedBranches.length === 0)
|
|
18097
|
-
return policy;
|
|
18098
|
-
const known = new Set(policy.allowed.map((pattern) => pattern.source));
|
|
18099
|
-
const allowed = [...policy.allowed];
|
|
18100
|
-
for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
|
|
18101
|
-
const pattern = branchGlobPattern(glob);
|
|
18102
|
-
if (!known.has(pattern.source)) {
|
|
18103
|
-
known.add(pattern.source);
|
|
18104
|
-
allowed.push(pattern);
|
|
18105
|
-
}
|
|
18106
|
-
}
|
|
18107
|
-
return {
|
|
18108
|
-
...policy,
|
|
18109
|
-
allowed,
|
|
18110
|
-
protected: new Set([
|
|
18111
|
-
...policy.protected,
|
|
18112
|
-
...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
|
|
18113
|
-
])
|
|
18114
|
-
};
|
|
18115
|
-
}, KIND_SYNONYMS, allowedKinds = (allowed) => [
|
|
18116
|
-
...new Set(allowed.map((pattern) => /^\^([\w.-]+)\\?\/\.\*\$$/u.exec(pattern.source)?.[1]?.toLowerCase()).filter((kind) => Boolean(kind)))
|
|
18117
|
-
], editDistance = (a, b) => {
|
|
18118
|
-
const row = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
18119
|
-
for (let i = 1;i <= a.length; i++) {
|
|
18120
|
-
let previous = row[0];
|
|
18121
|
-
row[0] = i;
|
|
18122
|
-
for (let j = 1;j <= b.length; j++) {
|
|
18123
|
-
const saved = row[j];
|
|
18124
|
-
row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
18125
|
-
previous = saved;
|
|
18126
|
-
}
|
|
18127
|
-
}
|
|
18128
|
-
return row[b.length];
|
|
18129
|
-
}, suggestBranchName = (name, kinds) => {
|
|
18130
|
-
if (!kinds.length)
|
|
18131
|
-
return null;
|
|
18132
|
-
const slash = name.indexOf("/");
|
|
18133
|
-
const prefix = slash > 0 ? name.slice(0, slash).toLowerCase() : "";
|
|
18134
|
-
const rest = (slash > 0 ? name.slice(slash + 1) : name) || "name";
|
|
18135
|
-
const synonym = KIND_SYNONYMS[prefix];
|
|
18136
|
-
const near = kinds.map((kind) => ({ kind, distance: editDistance(prefix, kind) })).filter((entry) => prefix && entry.distance <= 2).toSorted((a, b) => a.distance - b.distance)[0]?.kind;
|
|
18137
|
-
const kind = (synonym && kinds.includes(synonym) ? synonym : null) ?? near ?? (kinds.includes("feature") ? "feature" : kinds[0]);
|
|
18138
|
-
return `${kind}/${rest}`;
|
|
18139
|
-
}, kindList = (kinds) => kinds.map((kind) => `${kind}/`).join(", "), aliasNote = (kinds) => {
|
|
18140
|
-
const notes = [
|
|
18141
|
-
["fix", "bugfix"],
|
|
18142
|
-
["chore", "feature"]
|
|
18143
|
-
].filter(([, kind]) => kinds.includes(kind)).map(([alias, kind]) => `${alias}/ is ${kind}/`);
|
|
18144
|
-
return notes.length ? ` (${notes.join(", ")})` : "";
|
|
18145
|
-
}, validateBranchNamePolicy = (name, policy, source) => {
|
|
18146
|
-
const allowed = policy.allowed.map((pattern) => `/${pattern.source}/${pattern.flags}`);
|
|
18147
|
-
const kinds = allowedKinds(policy.allowed);
|
|
18148
|
-
if (policy.protected.has(name.toLowerCase())) {
|
|
18149
|
-
const correction = kinds.length ? `choose a non-protected branch of an allowed kind (${kindList(kinds)}), e.g. ${kinds[0]}/<slug>: workit git branch --kind ${kinds[0]} --slug <slug>` : `choose a non-protected branch matching one of: ${allowed.join(", ")}`;
|
|
18150
|
-
return {
|
|
18151
|
-
ok: false,
|
|
18152
|
-
rule: "protected_ref",
|
|
18153
|
-
source,
|
|
18154
|
-
attempted: name,
|
|
18155
|
-
correction,
|
|
18156
|
-
error: `protected_ref: branch ${JSON.stringify(name)} is protected by ${source}; ${correction}`
|
|
18157
|
-
};
|
|
18158
|
-
}
|
|
18159
|
-
if (!policy.allowed.some((pattern) => pattern.test(name))) {
|
|
18160
|
-
const suggestion = suggestBranchName(name, kinds);
|
|
18161
|
-
const correction = suggestion && policy.allowed.some((pattern) => pattern.test(suggestion)) ? `use ${JSON.stringify(suggestion)}; the allowed kinds are ${kindList(kinds)} (workit git branch ${suggestion})` : `choose a branch matching one of: ${allowed.join(", ")}`;
|
|
18162
|
-
return {
|
|
18163
|
-
ok: false,
|
|
18164
|
-
rule: "allowed_pattern",
|
|
18165
|
-
source,
|
|
18166
|
-
attempted: name,
|
|
18167
|
-
correction,
|
|
18168
|
-
error: `allowed_pattern: branch ${JSON.stringify(name)} violates ${source} policy; ${correction}`
|
|
18169
|
-
};
|
|
18170
|
-
}
|
|
18171
|
-
return { ok: true };
|
|
18172
|
-
}, branchPolicySnapshotFor = (workspaceRoot) => {
|
|
18173
|
-
const resolved = effectiveWorkspacePolicy(workspaceRoot, "branch");
|
|
18174
|
-
const branchPolicy = resolved.branchPolicy;
|
|
18175
|
-
const source = resolved.provenance.branchPolicy;
|
|
18176
|
-
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
18177
|
-
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
18178
|
-
const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
18179
|
-
return {
|
|
18180
|
-
branchPolicy,
|
|
18181
|
-
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
18182
|
-
source,
|
|
18183
|
-
fingerprint
|
|
18184
|
-
};
|
|
18185
|
-
}, validateBranchNameFor = (workspaceRoot, name) => {
|
|
18186
|
-
try {
|
|
18187
|
-
const resolved = branchPolicySnapshotFor(workspaceRoot);
|
|
18188
|
-
return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
|
|
18189
|
-
} catch (error) {
|
|
18190
|
-
const correction = "repair or select a valid workspace policy before creating a branch";
|
|
18191
|
-
return {
|
|
18192
|
-
ok: false,
|
|
18193
|
-
rule: "policy_unavailable",
|
|
18194
|
-
source: "workspaces.json",
|
|
18195
|
-
attempted: name,
|
|
18196
|
-
correction,
|
|
18197
|
-
error: `policy_unavailable: cannot validate branch ${JSON.stringify(name)} because ${error instanceof Error ? error.message : String(error)}; ${correction}`
|
|
18198
|
-
};
|
|
18199
|
-
}
|
|
18200
|
-
}, resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy, gitFlowOf = (root, integration) => {
|
|
18201
|
-
try {
|
|
18202
|
-
if (resolveBranchPolicyFor(root).preset !== "gitflow")
|
|
18203
|
-
return null;
|
|
18204
|
-
const selected = resolveRuntimeWorkspacePolicy(root, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined).policy;
|
|
18205
|
-
const names = branchNames(root);
|
|
18206
|
-
const production = productionBranchOf(names);
|
|
18207
|
-
const develop = selected?.developBranch?.trim() || (integration && integration.toLowerCase() !== production ? integration : "develop");
|
|
18208
|
-
return { develop, production, developExists: names.has(develop) };
|
|
18209
|
-
} catch {
|
|
18210
|
-
return null;
|
|
18211
|
-
}
|
|
18212
|
-
}, releaseBranchesOf = (cwd) => {
|
|
18213
|
-
try {
|
|
18214
|
-
const resolved = resolveBranchPolicyFor(cwd);
|
|
18215
|
-
const flow = resolved.preset === "gitflow" ? gitFlowOf(cwd) : null;
|
|
18216
|
-
return {
|
|
18217
|
-
preset: resolved.preset,
|
|
18218
|
-
branches: flow ? [flow.production, flow.develop] : [],
|
|
18219
|
-
production: flow ? flow.production : resolved.defaultTargetBranch
|
|
18220
|
-
};
|
|
18221
|
-
} catch {
|
|
18222
|
-
return { preset: "unknown", branches: [], production: null };
|
|
18223
|
-
}
|
|
18224
|
-
}, releaseBranch = (cwd, branch) => releaseBranchesOf(cwd).branches.some((name) => name.toLowerCase() === branch.toLowerCase()), branchGuidance = (cwd) => {
|
|
18225
|
-
try {
|
|
18226
|
-
const patterns = branchPolicySnapshotFor(cwd).namePolicy.allowed;
|
|
18227
|
-
const kinds = allowedKinds(patterns);
|
|
18228
|
-
const kindShaped = new Set(kinds.map((kind) => branchGlobPattern(`${kind}/*`).source));
|
|
18229
|
-
const anyName = patterns.some((pattern) => pattern.source === "^.*$");
|
|
18230
|
-
const others = patterns.filter((pattern) => !kindShaped.has(pattern.source)).map((pattern) => globOf(pattern));
|
|
18231
|
-
const allowed = anyName ? "Any non-protected branch name is allowed here." : `${kinds.length ? `Allowed branch kinds here: ${kindList(kinds)}${aliasNote(kinds)}` : "Allowed branch names here:"}${others.length ? `${kinds.length ? "; also" : ""} names matching ${others.join(", ")}` : ""}; anything else is denied.`;
|
|
18232
|
-
const resolved = vcsConfig("resolve", cwd);
|
|
18233
|
-
const integration = resolved.ok === false ? null : String(resolved.defaultTargetBranch ?? "") || null;
|
|
18234
|
-
const flow = resolved.releaseTrack?.track ? null : gitFlowOf(cwd, integration);
|
|
18235
|
-
if (flow?.developExists)
|
|
18236
|
-
return `${allowed} git-flow: feature/, bugfix/ and release/ start from origin/${flow.develop}, hotfix/ from origin/${flow.production}; feature/ and bugfix/ land on ${flow.develop}, release/ and hotfix/ on ${flow.production}.`;
|
|
18237
|
-
const names = branchNames(cwd);
|
|
18238
|
-
const configured = String(resolved.baseBranch ?? integration ?? "") || null;
|
|
18239
|
-
const trunk = productionBranchOf(names);
|
|
18240
|
-
const base = configured && names.has(configured) ? `Branch from origin/${configured}.` : names.has(trunk) ? `Branch from origin/${trunk}${configured ? ` (the default target ${configured} does not exist here)` : ""}.` : "No base branch exists here yet; pass the base explicitly.";
|
|
18241
|
-
return `${allowed} ${base}`;
|
|
18242
|
-
} catch {
|
|
18243
|
-
return null;
|
|
18244
|
-
}
|
|
18245
|
-
}, globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*", "*").replace(/\\(.)/gu, "$1");
|
|
18246
|
-
var init_branch = __esm(() => {
|
|
18247
|
-
init_branch_policy();
|
|
18248
|
-
init_commit_flavors();
|
|
18249
|
-
init_git();
|
|
18250
|
-
init_config();
|
|
18251
|
-
init_workspaces();
|
|
18252
|
-
init_vcs_config();
|
|
18253
|
-
init_release_tracks();
|
|
18254
|
-
KIND_SYNONYMS = {
|
|
18255
|
-
fix: "bugfix",
|
|
18256
|
-
fixes: "bugfix",
|
|
18257
|
-
bug: "bugfix",
|
|
18258
|
-
bugs: "bugfix",
|
|
18259
|
-
bugfixes: "bugfix",
|
|
18260
|
-
feat: "feature",
|
|
18261
|
-
features: "feature",
|
|
18262
|
-
chore: "feature",
|
|
18263
|
-
docs: "feature",
|
|
18264
|
-
doc: "feature",
|
|
18265
|
-
refactor: "feature",
|
|
18266
|
-
test: "feature",
|
|
18267
|
-
tests: "feature",
|
|
18268
|
-
ci: "feature",
|
|
18269
|
-
build: "feature",
|
|
18270
|
-
perf: "feature",
|
|
18271
|
-
style: "feature",
|
|
18272
|
-
deps: "feature",
|
|
18273
|
-
task: "feature",
|
|
18274
|
-
enhancement: "feature",
|
|
18275
|
-
hot: "hotfix",
|
|
18276
|
-
hotfixes: "hotfix",
|
|
18277
|
-
releases: "release",
|
|
18278
|
-
rel: "release"
|
|
18279
|
-
};
|
|
18280
|
-
});
|
|
18281
|
-
|
|
18282
18316
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
18283
18317
|
import { createHash as createHash13 } from "node:crypto";
|
|
18284
18318
|
import fs15 from "node:fs";
|
|
@@ -22221,9 +22255,14 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
|
22221
22255
|
if (role !== "judge" || !event.agentId)
|
|
22222
22256
|
return readOnly;
|
|
22223
22257
|
const own = subagentSession(session, event.agentId);
|
|
22224
|
-
const
|
|
22225
|
-
const
|
|
22226
|
-
|
|
22258
|
+
const cwd = input.cwd || process.cwd();
|
|
22259
|
+
const token = session ? recordIssuedSession(cwd, session, own) : null;
|
|
22260
|
+
if (session && !token)
|
|
22261
|
+
return `${readOnly} ${own} was already issued to an earlier subagent, so no token is handed out again and a verdict under it would be refused (unbound_session). Record no verdict as ${own}: spawn a fresh verifier or reviewer, which gets its own session and token.`;
|
|
22262
|
+
const judge = event.agentType.endsWith("reviewer") ? "reviewer" : "verifier";
|
|
22263
|
+
const line = verdictCommand({ branch: judgeBranch(cwd), judge, session: own, token });
|
|
22264
|
+
const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
|
|
22265
|
+
return `${readOnly} Its own Workit session is ${own}, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${line}\`.${token ? " The token is this subagent's alone: never write it into a report, a file or a commit. --token needs a workit CLI at least as new as this plugin; if the CLI answers that --token is an unknown option, update the workit CLI (workit upgrade --cli) and record again." : ""}`;
|
|
22227
22266
|
}, failureDecision = (descriptor, event, error) => {
|
|
22228
22267
|
if (event === "shell.pre" || event === "tool.pre" || event === "write.pre")
|
|
22229
22268
|
return descriptor.shellPolicy.failClosed ? { kind: "deny", reason: error, unblock: null } : NONE5;
|