@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
package/dist/workit-hook.js
CHANGED
|
@@ -8574,7 +8574,7 @@ function pushRemoteName(cwd, branch) {
|
|
|
8574
8574
|
|
|
8575
8575
|
// packages/workit-core/src/ledger.ts
|
|
8576
8576
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
8577
|
-
import { createHash as
|
|
8577
|
+
import { createHash as createHash8, randomBytes as randomBytes2 } from "node:crypto";
|
|
8578
8578
|
import fs6 from "node:fs";
|
|
8579
8579
|
import path8 from "node:path";
|
|
8580
8580
|
|
|
@@ -10322,10 +10322,227 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
10322
10322
|
}
|
|
10323
10323
|
|
|
10324
10324
|
// packages/workit-core/src/host-session.ts
|
|
10325
|
-
import { createHash as
|
|
10325
|
+
import { createHash as createHash7, randomBytes, timingSafeEqual } from "node:crypto";
|
|
10326
10326
|
import fs5 from "node:fs";
|
|
10327
10327
|
import path7 from "node:path";
|
|
10328
10328
|
|
|
10329
|
+
// packages/workit-core/src/core/branch.ts
|
|
10330
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
10331
|
+
var withReleaseTracks = (workspaceRoot, policy) => {
|
|
10332
|
+
const read = workspaceReleaseTracks(workspaceRoot);
|
|
10333
|
+
if (read.error)
|
|
10334
|
+
throw new ReleaseTrackError(read.error);
|
|
10335
|
+
if (read.tracks.length === 0 && read.protectedBranches.length === 0)
|
|
10336
|
+
return policy;
|
|
10337
|
+
const known = new Set(policy.allowed.map((pattern) => pattern.source));
|
|
10338
|
+
const allowed = [...policy.allowed];
|
|
10339
|
+
for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
|
|
10340
|
+
const pattern = branchGlobPattern(glob);
|
|
10341
|
+
if (!known.has(pattern.source)) {
|
|
10342
|
+
known.add(pattern.source);
|
|
10343
|
+
allowed.push(pattern);
|
|
10344
|
+
}
|
|
10345
|
+
}
|
|
10346
|
+
return {
|
|
10347
|
+
...policy,
|
|
10348
|
+
allowed,
|
|
10349
|
+
protected: new Set([
|
|
10350
|
+
...policy.protected,
|
|
10351
|
+
...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
|
|
10352
|
+
])
|
|
10353
|
+
};
|
|
10354
|
+
};
|
|
10355
|
+
function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
10356
|
+
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
10357
|
+
const config = readConfig();
|
|
10358
|
+
return kind === "branch" ? {
|
|
10359
|
+
branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null, () => repoBranchPreset(workspaceRoot))),
|
|
10360
|
+
provenance: { branchPolicy: selected.source }
|
|
10361
|
+
} : {
|
|
10362
|
+
commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
|
|
10363
|
+
provenance: { commitPolicy: selected.source }
|
|
10364
|
+
};
|
|
10365
|
+
}
|
|
10366
|
+
var KIND_SYNONYMS = {
|
|
10367
|
+
fix: "bugfix",
|
|
10368
|
+
fixes: "bugfix",
|
|
10369
|
+
bug: "bugfix",
|
|
10370
|
+
bugs: "bugfix",
|
|
10371
|
+
bugfixes: "bugfix",
|
|
10372
|
+
feat: "feature",
|
|
10373
|
+
features: "feature",
|
|
10374
|
+
chore: "feature",
|
|
10375
|
+
docs: "feature",
|
|
10376
|
+
doc: "feature",
|
|
10377
|
+
refactor: "feature",
|
|
10378
|
+
test: "feature",
|
|
10379
|
+
tests: "feature",
|
|
10380
|
+
ci: "feature",
|
|
10381
|
+
build: "feature",
|
|
10382
|
+
perf: "feature",
|
|
10383
|
+
style: "feature",
|
|
10384
|
+
deps: "feature",
|
|
10385
|
+
task: "feature",
|
|
10386
|
+
enhancement: "feature",
|
|
10387
|
+
hot: "hotfix",
|
|
10388
|
+
hotfixes: "hotfix",
|
|
10389
|
+
releases: "release",
|
|
10390
|
+
rel: "release"
|
|
10391
|
+
};
|
|
10392
|
+
var allowedKinds = (allowed) => [
|
|
10393
|
+
...new Set(allowed.map((pattern) => /^\^([\w.-]+)\\?\/\.\*\$$/u.exec(pattern.source)?.[1]?.toLowerCase()).filter((kind) => Boolean(kind)))
|
|
10394
|
+
];
|
|
10395
|
+
var editDistance = (a, b) => {
|
|
10396
|
+
const row = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
10397
|
+
for (let i = 1;i <= a.length; i++) {
|
|
10398
|
+
let previous = row[0];
|
|
10399
|
+
row[0] = i;
|
|
10400
|
+
for (let j = 1;j <= b.length; j++) {
|
|
10401
|
+
const saved = row[j];
|
|
10402
|
+
row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
10403
|
+
previous = saved;
|
|
10404
|
+
}
|
|
10405
|
+
}
|
|
10406
|
+
return row[b.length];
|
|
10407
|
+
};
|
|
10408
|
+
var suggestBranchName = (name, kinds) => {
|
|
10409
|
+
if (!kinds.length)
|
|
10410
|
+
return null;
|
|
10411
|
+
const slash = name.indexOf("/");
|
|
10412
|
+
const prefix = slash > 0 ? name.slice(0, slash).toLowerCase() : "";
|
|
10413
|
+
const rest = (slash > 0 ? name.slice(slash + 1) : name) || "name";
|
|
10414
|
+
const synonym = KIND_SYNONYMS[prefix];
|
|
10415
|
+
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;
|
|
10416
|
+
const kind = (synonym && kinds.includes(synonym) ? synonym : null) ?? near ?? (kinds.includes("feature") ? "feature" : kinds[0]);
|
|
10417
|
+
return `${kind}/${rest}`;
|
|
10418
|
+
};
|
|
10419
|
+
var kindList = (kinds) => kinds.map((kind) => `${kind}/`).join(", ");
|
|
10420
|
+
var aliasNote = (kinds) => {
|
|
10421
|
+
const notes = [
|
|
10422
|
+
["fix", "bugfix"],
|
|
10423
|
+
["chore", "feature"]
|
|
10424
|
+
].filter(([, kind]) => kinds.includes(kind)).map(([alias, kind]) => `${alias}/ is ${kind}/`);
|
|
10425
|
+
return notes.length ? ` (${notes.join(", ")})` : "";
|
|
10426
|
+
};
|
|
10427
|
+
var validateBranchNamePolicy = (name, policy, source) => {
|
|
10428
|
+
const allowed = policy.allowed.map((pattern) => `/${pattern.source}/${pattern.flags}`);
|
|
10429
|
+
const kinds = allowedKinds(policy.allowed);
|
|
10430
|
+
if (policy.protected.has(name.toLowerCase())) {
|
|
10431
|
+
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(", ")}`;
|
|
10432
|
+
return {
|
|
10433
|
+
ok: false,
|
|
10434
|
+
rule: "protected_ref",
|
|
10435
|
+
source,
|
|
10436
|
+
attempted: name,
|
|
10437
|
+
correction,
|
|
10438
|
+
error: `protected_ref: branch ${JSON.stringify(name)} is protected by ${source}; ${correction}`
|
|
10439
|
+
};
|
|
10440
|
+
}
|
|
10441
|
+
if (!policy.allowed.some((pattern) => pattern.test(name))) {
|
|
10442
|
+
const suggestion = suggestBranchName(name, kinds);
|
|
10443
|
+
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(", ")}`;
|
|
10444
|
+
return {
|
|
10445
|
+
ok: false,
|
|
10446
|
+
rule: "allowed_pattern",
|
|
10447
|
+
source,
|
|
10448
|
+
attempted: name,
|
|
10449
|
+
correction,
|
|
10450
|
+
error: `allowed_pattern: branch ${JSON.stringify(name)} violates ${source} policy; ${correction}`
|
|
10451
|
+
};
|
|
10452
|
+
}
|
|
10453
|
+
return { ok: true };
|
|
10454
|
+
};
|
|
10455
|
+
var branchPolicySnapshotFor = (workspaceRoot) => {
|
|
10456
|
+
const resolved = effectiveWorkspacePolicy(workspaceRoot, "branch");
|
|
10457
|
+
const branchPolicy = resolved.branchPolicy;
|
|
10458
|
+
const source = resolved.provenance.branchPolicy;
|
|
10459
|
+
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
10460
|
+
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
10461
|
+
const fingerprint = createHash6("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
10462
|
+
return {
|
|
10463
|
+
branchPolicy,
|
|
10464
|
+
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
10465
|
+
source,
|
|
10466
|
+
fingerprint
|
|
10467
|
+
};
|
|
10468
|
+
};
|
|
10469
|
+
var validateBranchNameFor = (workspaceRoot, name) => {
|
|
10470
|
+
try {
|
|
10471
|
+
const resolved = branchPolicySnapshotFor(workspaceRoot);
|
|
10472
|
+
return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
|
|
10473
|
+
} catch (error) {
|
|
10474
|
+
const correction = "repair or select a valid workspace policy before creating a branch";
|
|
10475
|
+
return {
|
|
10476
|
+
ok: false,
|
|
10477
|
+
rule: "policy_unavailable",
|
|
10478
|
+
source: "workspaces.json",
|
|
10479
|
+
attempted: name,
|
|
10480
|
+
correction,
|
|
10481
|
+
error: `policy_unavailable: cannot validate branch ${JSON.stringify(name)} because ${error instanceof Error ? error.message : String(error)}; ${correction}`
|
|
10482
|
+
};
|
|
10483
|
+
}
|
|
10484
|
+
};
|
|
10485
|
+
var resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
|
|
10486
|
+
var gitFlowOf = (root, integration) => {
|
|
10487
|
+
try {
|
|
10488
|
+
if (resolveBranchPolicyFor(root).preset !== "gitflow")
|
|
10489
|
+
return null;
|
|
10490
|
+
const selected = resolveRuntimeWorkspacePolicy(root, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined).policy;
|
|
10491
|
+
const names = branchNames(root);
|
|
10492
|
+
const production = productionBranchOf(names);
|
|
10493
|
+
const develop = selected?.developBranch?.trim() || (integration && integration.toLowerCase() !== production ? integration : "develop");
|
|
10494
|
+
return { develop, production, developExists: names.has(develop) };
|
|
10495
|
+
} catch {
|
|
10496
|
+
return null;
|
|
10497
|
+
}
|
|
10498
|
+
};
|
|
10499
|
+
var releaseBranchesOf = (cwd) => {
|
|
10500
|
+
try {
|
|
10501
|
+
const resolved = resolveBranchPolicyFor(cwd);
|
|
10502
|
+
const flow = resolved.preset === "gitflow" ? gitFlowOf(cwd) : null;
|
|
10503
|
+
return {
|
|
10504
|
+
preset: resolved.preset,
|
|
10505
|
+
branches: flow ? [flow.production, flow.develop] : [],
|
|
10506
|
+
production: flow ? flow.production : resolved.defaultTargetBranch
|
|
10507
|
+
};
|
|
10508
|
+
} catch {
|
|
10509
|
+
return { preset: "unknown", branches: [], production: null };
|
|
10510
|
+
}
|
|
10511
|
+
};
|
|
10512
|
+
var releaseBranch = (cwd, branch) => releaseBranchesOf(cwd).branches.some((name) => name.toLowerCase() === branch.toLowerCase());
|
|
10513
|
+
var branchGuidance = (cwd) => {
|
|
10514
|
+
try {
|
|
10515
|
+
const patterns = branchPolicySnapshotFor(cwd).namePolicy.allowed;
|
|
10516
|
+
const kinds = allowedKinds(patterns);
|
|
10517
|
+
const kindShaped = new Set(kinds.map((kind) => branchGlobPattern(`${kind}/*`).source));
|
|
10518
|
+
const anyName = patterns.some((pattern) => pattern.source === "^.*$");
|
|
10519
|
+
const others = patterns.filter((pattern) => !kindShaped.has(pattern.source)).map((pattern) => globOf(pattern));
|
|
10520
|
+
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.`;
|
|
10521
|
+
const resolved = vcsConfig("resolve", cwd);
|
|
10522
|
+
const integration = resolved.ok === false ? null : String(resolved.defaultTargetBranch ?? "") || null;
|
|
10523
|
+
const flow = resolved.releaseTrack?.track ? null : gitFlowOf(cwd, integration);
|
|
10524
|
+
if (flow?.developExists)
|
|
10525
|
+
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}.`;
|
|
10526
|
+
const names = branchNames(cwd);
|
|
10527
|
+
const configured = String(resolved.baseBranch ?? integration ?? "") || null;
|
|
10528
|
+
const trunk = productionBranchOf(names);
|
|
10529
|
+
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.";
|
|
10530
|
+
return `${allowed} ${base}`;
|
|
10531
|
+
} catch {
|
|
10532
|
+
return null;
|
|
10533
|
+
}
|
|
10534
|
+
};
|
|
10535
|
+
var globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*", "*").replace(/\\(.)/gu, "$1");
|
|
10536
|
+
var policy = (root) => resolveBranchPolicyFor(root);
|
|
10537
|
+
var isProtected = (root, name) => policy(root).protected.has(name.toLowerCase());
|
|
10538
|
+
var isProtectedTarget = (root, name) => {
|
|
10539
|
+
try {
|
|
10540
|
+
return isProtected(root, name);
|
|
10541
|
+
} catch {
|
|
10542
|
+
return true;
|
|
10543
|
+
}
|
|
10544
|
+
};
|
|
10545
|
+
|
|
10329
10546
|
// packages/workit-core/src/core/logger.ts
|
|
10330
10547
|
import os3 from "node:os";
|
|
10331
10548
|
import path6 from "node:path";
|
|
@@ -10415,7 +10632,7 @@ function hostSessionFromEnv(env) {
|
|
|
10415
10632
|
}
|
|
10416
10633
|
var ISSUED_PER_LEAD = 64;
|
|
10417
10634
|
var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/3";
|
|
10418
|
-
var hash = (value) =>
|
|
10635
|
+
var hash = (value) => createHash7("sha256").update(value).digest("hex").slice(0, 32);
|
|
10419
10636
|
var userIssuedRoot = () => path7.join(resolveStateDir(), "issued");
|
|
10420
10637
|
var userTokenRoot = () => path7.join(resolveStateDir(), "issued-tokens");
|
|
10421
10638
|
function migrateRepoIssued(cwd) {
|
|
@@ -10465,7 +10682,7 @@ var removeIfEmpty = (dir) => {
|
|
|
10465
10682
|
fs5.rmdirSync(dir);
|
|
10466
10683
|
} catch {}
|
|
10467
10684
|
};
|
|
10468
|
-
var tokenHash = (token) =>
|
|
10685
|
+
var tokenHash = (token) => createHash7("sha256").update(token).digest("hex");
|
|
10469
10686
|
function recordIssuedSession(cwd, lead, issued) {
|
|
10470
10687
|
const token = randomBytes(18).toString("hex");
|
|
10471
10688
|
try {
|
|
@@ -10485,6 +10702,21 @@ function recordIssuedSession(cwd, lead, issued) {
|
|
|
10485
10702
|
return null;
|
|
10486
10703
|
}
|
|
10487
10704
|
}
|
|
10705
|
+
function judgeBranch(cwd) {
|
|
10706
|
+
const branch = currentBranch(cwd);
|
|
10707
|
+
return branch && !isProtectedTarget(cwd, branch) ? branch : null;
|
|
10708
|
+
}
|
|
10709
|
+
function verdictCommand(options) {
|
|
10710
|
+
const kind = options.judge === "verifier" ? "<live|unit>" : options.judge === "reviewer" ? "review" : "<live|unit|review>";
|
|
10711
|
+
return [
|
|
10712
|
+
"workit ledger verdict <verified|failed|blocked>",
|
|
10713
|
+
`--kind ${kind}`,
|
|
10714
|
+
`--branch ${options.branch ?? "<branch>"}`,
|
|
10715
|
+
options.session ? `--session ${options.session}` : null,
|
|
10716
|
+
options.token ? `--token=${options.token}` : null,
|
|
10717
|
+
'--how "<what you ran and saw>"'
|
|
10718
|
+
].filter(Boolean).join(" ");
|
|
10719
|
+
}
|
|
10488
10720
|
function pruneIssued(dir, own, tokens) {
|
|
10489
10721
|
try {
|
|
10490
10722
|
const entries = fs5.readdirSync(dir);
|
|
@@ -10642,7 +10874,7 @@ function diffHash(cwd, base, head) {
|
|
|
10642
10874
|
], GIT_TIMEOUTS.worktree);
|
|
10643
10875
|
if (!diff.ok || !diff.stdout)
|
|
10644
10876
|
return null;
|
|
10645
|
-
const hash =
|
|
10877
|
+
const hash = createHash8("sha256");
|
|
10646
10878
|
for (const line of diff.stdout.split(`
|
|
10647
10879
|
`)) {
|
|
10648
10880
|
if (line.startsWith("index "))
|
|
@@ -10777,7 +11009,7 @@ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
|
|
|
10777
11009
|
ledgerLock.release(lock, token);
|
|
10778
11010
|
}
|
|
10779
11011
|
}
|
|
10780
|
-
var sha2562 = (text) =>
|
|
11012
|
+
var sha2562 = (text) => createHash8("sha256").update(text).digest("hex");
|
|
10781
11013
|
var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
10782
11014
|
${body}`);
|
|
10783
11015
|
var TAIL_BYTES = 64 * 1024;
|
|
@@ -11528,7 +11760,7 @@ var productDecision = (task, ledger) => {
|
|
|
11528
11760
|
};
|
|
11529
11761
|
const since = Date.parse(task.createdAt);
|
|
11530
11762
|
const branch = ledger.branch();
|
|
11531
|
-
const row = ledger.rows().findLast((item) => item.type === "decision" && !item.superseded && (item.branch ?? null) === branch && Date.parse(item.at) >= since);
|
|
11763
|
+
const row = ledger.rows().findLast((item) => item.type === "decision" && item.by !== "decider" && !item.superseded && (item.branch ?? null) === branch && Date.parse(item.at) >= since);
|
|
11532
11764
|
return row ? { met: true, reason: `ledger decision ${row.id} records the choice`, decisionIds: [] } : {
|
|
11533
11765
|
met: false,
|
|
11534
11766
|
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>"`)',
|
|
@@ -12288,7 +12520,7 @@ var suggested = (kind) => kind === "merge" ? "verified" : "true";
|
|
|
12288
12520
|
var grantHint = (workspace, kind) => `ask the user to run, in their own terminal: workit grant set ${workspace ?? "<workspace>"} ${kind}=${suggested(kind)}`;
|
|
12289
12521
|
|
|
12290
12522
|
// packages/workit-core/src/core/task-store.ts
|
|
12291
|
-
import { createHash as
|
|
12523
|
+
import { createHash as createHash10, randomUUID as randomUUID3 } from "node:crypto";
|
|
12292
12524
|
import * as fs11 from "node:fs";
|
|
12293
12525
|
import path15 from "node:path";
|
|
12294
12526
|
|
|
@@ -13178,7 +13410,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
|
|
|
13178
13410
|
});
|
|
13179
13411
|
|
|
13180
13412
|
// packages/workit-core/src/store/reduce.ts
|
|
13181
|
-
import { createHash as
|
|
13413
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
13182
13414
|
var OPENING_TYPES = new Set([
|
|
13183
13415
|
"task.opened",
|
|
13184
13416
|
"task.imported",
|
|
@@ -13207,7 +13439,7 @@ var isObject5 = (value) => typeof value === "object" && value !== null && !Array
|
|
|
13207
13439
|
var isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
|
|
13208
13440
|
var BLOB_REF = "$blob";
|
|
13209
13441
|
var 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;
|
|
13210
|
-
var blobDigest = (value) =>
|
|
13442
|
+
var blobDigest = (value) => createHash9("sha256").update(JSON.stringify(value)).digest("hex");
|
|
13211
13443
|
var toBlob = (value, blobs) => {
|
|
13212
13444
|
if (!isObject5(value))
|
|
13213
13445
|
return value;
|
|
@@ -14436,7 +14668,7 @@ class TaskStore {
|
|
|
14436
14668
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
14437
14669
|
}
|
|
14438
14670
|
withKeyLock(key, operation) {
|
|
14439
|
-
const digest =
|
|
14671
|
+
const digest = createHash10("sha256").update(key).digest("hex").slice(0, 32);
|
|
14440
14672
|
return this.withLock(path15.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
14441
14673
|
}
|
|
14442
14674
|
bindLocked(taskId, key, timestamp) {
|
|
@@ -15061,7 +15293,7 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
|
|
|
15061
15293
|
var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
|
|
15062
15294
|
|
|
15063
15295
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
15064
|
-
import { createHash as
|
|
15296
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
15065
15297
|
import * as fs13 from "node:fs";
|
|
15066
15298
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
15067
15299
|
import path17 from "node:path";
|
|
@@ -15071,8 +15303,13 @@ import { spawnSync as spawnSync9 } from "node:child_process";
|
|
|
15071
15303
|
import fs12 from "node:fs";
|
|
15072
15304
|
import path16 from "node:path";
|
|
15073
15305
|
var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
|
|
15074
|
-
var CHECKS_FILE = "workit
|
|
15075
|
-
var
|
|
15306
|
+
var CHECKS_FILE = ".workit/checks.json";
|
|
15307
|
+
var LEGACY_CHECKS_FILE = "workit.checks.json";
|
|
15308
|
+
function checksConfigFile(root) {
|
|
15309
|
+
const current = path16.join(root, CHECKS_FILE);
|
|
15310
|
+
const legacy = path16.join(root, LEGACY_CHECKS_FILE);
|
|
15311
|
+
return !fs12.existsSync(current) && fs12.existsSync(legacy) ? legacy : current;
|
|
15312
|
+
}
|
|
15076
15313
|
function repoHeavyCommands(root) {
|
|
15077
15314
|
try {
|
|
15078
15315
|
const value = JSON.parse(fs12.readFileSync(checksConfigFile(root), "utf8"));
|
|
@@ -15196,19 +15433,25 @@ var GATES = ["testing", "verification"];
|
|
|
15196
15433
|
function loadCheckConfig(cwd) {
|
|
15197
15434
|
const root = checkRoot(cwd);
|
|
15198
15435
|
const file = checksConfigFile(root);
|
|
15436
|
+
const legacy = path16.basename(file) === LEGACY_CHECKS_FILE;
|
|
15437
|
+
const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
|
|
15438
|
+
const note = legacy ? {
|
|
15439
|
+
note: `${LEGACY_CHECKS_FILE} is deprecated; move it to ${CHECKS_FILE} (workit doctor --fix)`
|
|
15440
|
+
} : {};
|
|
15199
15441
|
const none = (error = null) => ({
|
|
15200
|
-
source: error ?
|
|
15442
|
+
source: error ? label : "none",
|
|
15201
15443
|
root,
|
|
15202
15444
|
checks: [],
|
|
15203
15445
|
gates: {},
|
|
15204
|
-
error
|
|
15446
|
+
error,
|
|
15447
|
+
...note
|
|
15205
15448
|
});
|
|
15206
15449
|
let text = null;
|
|
15207
15450
|
try {
|
|
15208
15451
|
text = fs12.readFileSync(file, "utf8");
|
|
15209
15452
|
} catch (error) {
|
|
15210
15453
|
if (error.code !== "ENOENT")
|
|
15211
|
-
return none(`cannot read ${
|
|
15454
|
+
return none(`cannot read ${label}: ${error.message}`);
|
|
15212
15455
|
}
|
|
15213
15456
|
if (text === null) {
|
|
15214
15457
|
const checks = detectedChecks(root);
|
|
@@ -15218,33 +15461,33 @@ function loadCheckConfig(cwd) {
|
|
|
15218
15461
|
try {
|
|
15219
15462
|
parsed = JSON.parse(text);
|
|
15220
15463
|
} catch {
|
|
15221
|
-
return none(`${
|
|
15464
|
+
return none(`${label} is not valid JSON`);
|
|
15222
15465
|
}
|
|
15223
15466
|
if (!isRecord3(parsed) || !isRecord3(parsed.checks))
|
|
15224
|
-
return none(`${
|
|
15467
|
+
return none(`${label} must be {"checks":{"<name>":"<command>"|["argv",…]}}`);
|
|
15225
15468
|
const checks = [];
|
|
15226
15469
|
for (const [name, value] of Object.entries(parsed.checks)) {
|
|
15227
15470
|
if (!CHECK_NAME.test(name))
|
|
15228
|
-
return none(`${
|
|
15471
|
+
return none(`${label}: check name "${name}" must match ${CHECK_NAME.source}`);
|
|
15229
15472
|
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");
|
|
15230
15473
|
if (argv instanceof Error)
|
|
15231
|
-
return none(`${
|
|
15474
|
+
return none(`${label}: check "${name}": ${argv.message}`);
|
|
15232
15475
|
checks.push({ name, argv, accepts: [argv] });
|
|
15233
15476
|
}
|
|
15234
15477
|
const gates = {};
|
|
15235
15478
|
if (parsed.gates !== undefined) {
|
|
15236
15479
|
if (!isRecord3(parsed.gates))
|
|
15237
|
-
return none(`${
|
|
15480
|
+
return none(`${label}: gates must be {"testing":"<name>"|["<name>",…]}`);
|
|
15238
15481
|
for (const [gate, value] of Object.entries(parsed.gates)) {
|
|
15239
15482
|
if (!GATES.includes(gate))
|
|
15240
|
-
return none(`${
|
|
15483
|
+
return none(`${label}: unknown gate "${gate}" (use ${GATES.join(" or ")})`);
|
|
15241
15484
|
const names = typeof value === "string" ? [value] : value;
|
|
15242
15485
|
if (!Array.isArray(names) || names.length === 0 || !names.every((name) => typeof name === "string" && checks.some((c) => c.name === name)))
|
|
15243
|
-
return none(`${
|
|
15486
|
+
return none(`${label}: gates.${gate} must name configured checks`);
|
|
15244
15487
|
gates[gate] = names;
|
|
15245
15488
|
}
|
|
15246
15489
|
}
|
|
15247
|
-
return { source:
|
|
15490
|
+
return { source: label, root, checks, gates, error: null, ...note, resources: parsed.resources };
|
|
15248
15491
|
}
|
|
15249
15492
|
var sameArgv = (left, right) => left.length === right.length && left.every((item, index) => item === right[index]);
|
|
15250
15493
|
function matchesNamedCheck(config, name, argv, cwd) {
|
|
@@ -15283,7 +15526,7 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
15283
15526
|
}
|
|
15284
15527
|
|
|
15285
15528
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
15286
|
-
var digestBytes = (value) =>
|
|
15529
|
+
var digestBytes = (value) => createHash11("sha256").update(value).digest("hex");
|
|
15287
15530
|
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`);
|
|
15288
15531
|
var relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".";
|
|
15289
15532
|
var canonicalPath = (value) => {
|
|
@@ -15711,7 +15954,7 @@ function evaluateObservedGate(task, requirement, statuses, config) {
|
|
|
15711
15954
|
return {
|
|
15712
15955
|
satisfied: [],
|
|
15713
15956
|
considered,
|
|
15714
|
-
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}
|
|
15957
|
+
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())}`
|
|
15715
15958
|
};
|
|
15716
15959
|
const satisfied = fresh.filter(named);
|
|
15717
15960
|
if (satisfied.length)
|
|
@@ -17932,7 +18175,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
17932
18175
|
};
|
|
17933
18176
|
});
|
|
17934
18177
|
// packages/workit-core/src/hooks/context.ts
|
|
17935
|
-
import { createHash as
|
|
18178
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
17936
18179
|
import fs14 from "node:fs";
|
|
17937
18180
|
import path18 from "node:path";
|
|
17938
18181
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
@@ -18088,7 +18331,7 @@ var turnContextText = (input, descriptor) => {
|
|
|
18088
18331
|
}
|
|
18089
18332
|
};
|
|
18090
18333
|
var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
18091
|
-
var digestOf = (text) =>
|
|
18334
|
+
var digestOf = (text) => createHash12("sha256").update(text).digest("hex");
|
|
18092
18335
|
var turnMarker = (input) => {
|
|
18093
18336
|
if (!input.session.id)
|
|
18094
18337
|
return null;
|
|
@@ -18167,214 +18410,6 @@ import fs16 from "node:fs";
|
|
|
18167
18410
|
import os5 from "node:os";
|
|
18168
18411
|
import path20 from "node:path";
|
|
18169
18412
|
|
|
18170
|
-
// packages/workit-core/src/core/branch.ts
|
|
18171
|
-
import { createHash as createHash12 } from "node:crypto";
|
|
18172
|
-
var withReleaseTracks = (workspaceRoot, policy) => {
|
|
18173
|
-
const read = workspaceReleaseTracks(workspaceRoot);
|
|
18174
|
-
if (read.error)
|
|
18175
|
-
throw new ReleaseTrackError(read.error);
|
|
18176
|
-
if (read.tracks.length === 0 && read.protectedBranches.length === 0)
|
|
18177
|
-
return policy;
|
|
18178
|
-
const known = new Set(policy.allowed.map((pattern) => pattern.source));
|
|
18179
|
-
const allowed = [...policy.allowed];
|
|
18180
|
-
for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
|
|
18181
|
-
const pattern = branchGlobPattern(glob);
|
|
18182
|
-
if (!known.has(pattern.source)) {
|
|
18183
|
-
known.add(pattern.source);
|
|
18184
|
-
allowed.push(pattern);
|
|
18185
|
-
}
|
|
18186
|
-
}
|
|
18187
|
-
return {
|
|
18188
|
-
...policy,
|
|
18189
|
-
allowed,
|
|
18190
|
-
protected: new Set([
|
|
18191
|
-
...policy.protected,
|
|
18192
|
-
...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
|
|
18193
|
-
])
|
|
18194
|
-
};
|
|
18195
|
-
};
|
|
18196
|
-
function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
18197
|
-
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
18198
|
-
const config = readConfig();
|
|
18199
|
-
return kind === "branch" ? {
|
|
18200
|
-
branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null, () => repoBranchPreset(workspaceRoot))),
|
|
18201
|
-
provenance: { branchPolicy: selected.source }
|
|
18202
|
-
} : {
|
|
18203
|
-
commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
|
|
18204
|
-
provenance: { commitPolicy: selected.source }
|
|
18205
|
-
};
|
|
18206
|
-
}
|
|
18207
|
-
var KIND_SYNONYMS = {
|
|
18208
|
-
fix: "bugfix",
|
|
18209
|
-
fixes: "bugfix",
|
|
18210
|
-
bug: "bugfix",
|
|
18211
|
-
bugs: "bugfix",
|
|
18212
|
-
bugfixes: "bugfix",
|
|
18213
|
-
feat: "feature",
|
|
18214
|
-
features: "feature",
|
|
18215
|
-
chore: "feature",
|
|
18216
|
-
docs: "feature",
|
|
18217
|
-
doc: "feature",
|
|
18218
|
-
refactor: "feature",
|
|
18219
|
-
test: "feature",
|
|
18220
|
-
tests: "feature",
|
|
18221
|
-
ci: "feature",
|
|
18222
|
-
build: "feature",
|
|
18223
|
-
perf: "feature",
|
|
18224
|
-
style: "feature",
|
|
18225
|
-
deps: "feature",
|
|
18226
|
-
task: "feature",
|
|
18227
|
-
enhancement: "feature",
|
|
18228
|
-
hot: "hotfix",
|
|
18229
|
-
hotfixes: "hotfix",
|
|
18230
|
-
releases: "release",
|
|
18231
|
-
rel: "release"
|
|
18232
|
-
};
|
|
18233
|
-
var allowedKinds = (allowed) => [
|
|
18234
|
-
...new Set(allowed.map((pattern) => /^\^([\w.-]+)\\?\/\.\*\$$/u.exec(pattern.source)?.[1]?.toLowerCase()).filter((kind) => Boolean(kind)))
|
|
18235
|
-
];
|
|
18236
|
-
var editDistance = (a, b) => {
|
|
18237
|
-
const row = Array.from({ length: b.length + 1 }, (_, index) => index);
|
|
18238
|
-
for (let i = 1;i <= a.length; i++) {
|
|
18239
|
-
let previous = row[0];
|
|
18240
|
-
row[0] = i;
|
|
18241
|
-
for (let j = 1;j <= b.length; j++) {
|
|
18242
|
-
const saved = row[j];
|
|
18243
|
-
row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
18244
|
-
previous = saved;
|
|
18245
|
-
}
|
|
18246
|
-
}
|
|
18247
|
-
return row[b.length];
|
|
18248
|
-
};
|
|
18249
|
-
var suggestBranchName = (name, kinds) => {
|
|
18250
|
-
if (!kinds.length)
|
|
18251
|
-
return null;
|
|
18252
|
-
const slash = name.indexOf("/");
|
|
18253
|
-
const prefix = slash > 0 ? name.slice(0, slash).toLowerCase() : "";
|
|
18254
|
-
const rest = (slash > 0 ? name.slice(slash + 1) : name) || "name";
|
|
18255
|
-
const synonym = KIND_SYNONYMS[prefix];
|
|
18256
|
-
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;
|
|
18257
|
-
const kind = (synonym && kinds.includes(synonym) ? synonym : null) ?? near ?? (kinds.includes("feature") ? "feature" : kinds[0]);
|
|
18258
|
-
return `${kind}/${rest}`;
|
|
18259
|
-
};
|
|
18260
|
-
var kindList = (kinds) => kinds.map((kind) => `${kind}/`).join(", ");
|
|
18261
|
-
var aliasNote = (kinds) => {
|
|
18262
|
-
const notes = [
|
|
18263
|
-
["fix", "bugfix"],
|
|
18264
|
-
["chore", "feature"]
|
|
18265
|
-
].filter(([, kind]) => kinds.includes(kind)).map(([alias, kind]) => `${alias}/ is ${kind}/`);
|
|
18266
|
-
return notes.length ? ` (${notes.join(", ")})` : "";
|
|
18267
|
-
};
|
|
18268
|
-
var validateBranchNamePolicy = (name, policy, source) => {
|
|
18269
|
-
const allowed = policy.allowed.map((pattern) => `/${pattern.source}/${pattern.flags}`);
|
|
18270
|
-
const kinds = allowedKinds(policy.allowed);
|
|
18271
|
-
if (policy.protected.has(name.toLowerCase())) {
|
|
18272
|
-
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(", ")}`;
|
|
18273
|
-
return {
|
|
18274
|
-
ok: false,
|
|
18275
|
-
rule: "protected_ref",
|
|
18276
|
-
source,
|
|
18277
|
-
attempted: name,
|
|
18278
|
-
correction,
|
|
18279
|
-
error: `protected_ref: branch ${JSON.stringify(name)} is protected by ${source}; ${correction}`
|
|
18280
|
-
};
|
|
18281
|
-
}
|
|
18282
|
-
if (!policy.allowed.some((pattern) => pattern.test(name))) {
|
|
18283
|
-
const suggestion = suggestBranchName(name, kinds);
|
|
18284
|
-
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(", ")}`;
|
|
18285
|
-
return {
|
|
18286
|
-
ok: false,
|
|
18287
|
-
rule: "allowed_pattern",
|
|
18288
|
-
source,
|
|
18289
|
-
attempted: name,
|
|
18290
|
-
correction,
|
|
18291
|
-
error: `allowed_pattern: branch ${JSON.stringify(name)} violates ${source} policy; ${correction}`
|
|
18292
|
-
};
|
|
18293
|
-
}
|
|
18294
|
-
return { ok: true };
|
|
18295
|
-
};
|
|
18296
|
-
var branchPolicySnapshotFor = (workspaceRoot) => {
|
|
18297
|
-
const resolved = effectiveWorkspacePolicy(workspaceRoot, "branch");
|
|
18298
|
-
const branchPolicy = resolved.branchPolicy;
|
|
18299
|
-
const source = resolved.provenance.branchPolicy;
|
|
18300
|
-
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
18301
|
-
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
18302
|
-
const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
18303
|
-
return {
|
|
18304
|
-
branchPolicy,
|
|
18305
|
-
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
18306
|
-
source,
|
|
18307
|
-
fingerprint
|
|
18308
|
-
};
|
|
18309
|
-
};
|
|
18310
|
-
var validateBranchNameFor = (workspaceRoot, name) => {
|
|
18311
|
-
try {
|
|
18312
|
-
const resolved = branchPolicySnapshotFor(workspaceRoot);
|
|
18313
|
-
return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
|
|
18314
|
-
} catch (error) {
|
|
18315
|
-
const correction = "repair or select a valid workspace policy before creating a branch";
|
|
18316
|
-
return {
|
|
18317
|
-
ok: false,
|
|
18318
|
-
rule: "policy_unavailable",
|
|
18319
|
-
source: "workspaces.json",
|
|
18320
|
-
attempted: name,
|
|
18321
|
-
correction,
|
|
18322
|
-
error: `policy_unavailable: cannot validate branch ${JSON.stringify(name)} because ${error instanceof Error ? error.message : String(error)}; ${correction}`
|
|
18323
|
-
};
|
|
18324
|
-
}
|
|
18325
|
-
};
|
|
18326
|
-
var resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
|
|
18327
|
-
var gitFlowOf = (root, integration) => {
|
|
18328
|
-
try {
|
|
18329
|
-
if (resolveBranchPolicyFor(root).preset !== "gitflow")
|
|
18330
|
-
return null;
|
|
18331
|
-
const selected = resolveRuntimeWorkspacePolicy(root, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined).policy;
|
|
18332
|
-
const names = branchNames(root);
|
|
18333
|
-
const production = productionBranchOf(names);
|
|
18334
|
-
const develop = selected?.developBranch?.trim() || (integration && integration.toLowerCase() !== production ? integration : "develop");
|
|
18335
|
-
return { develop, production, developExists: names.has(develop) };
|
|
18336
|
-
} catch {
|
|
18337
|
-
return null;
|
|
18338
|
-
}
|
|
18339
|
-
};
|
|
18340
|
-
var releaseBranchesOf = (cwd) => {
|
|
18341
|
-
try {
|
|
18342
|
-
const resolved = resolveBranchPolicyFor(cwd);
|
|
18343
|
-
const flow = resolved.preset === "gitflow" ? gitFlowOf(cwd) : null;
|
|
18344
|
-
return {
|
|
18345
|
-
preset: resolved.preset,
|
|
18346
|
-
branches: flow ? [flow.production, flow.develop] : [],
|
|
18347
|
-
production: flow ? flow.production : resolved.defaultTargetBranch
|
|
18348
|
-
};
|
|
18349
|
-
} catch {
|
|
18350
|
-
return { preset: "unknown", branches: [], production: null };
|
|
18351
|
-
}
|
|
18352
|
-
};
|
|
18353
|
-
var releaseBranch = (cwd, branch) => releaseBranchesOf(cwd).branches.some((name) => name.toLowerCase() === branch.toLowerCase());
|
|
18354
|
-
var branchGuidance = (cwd) => {
|
|
18355
|
-
try {
|
|
18356
|
-
const patterns = branchPolicySnapshotFor(cwd).namePolicy.allowed;
|
|
18357
|
-
const kinds = allowedKinds(patterns);
|
|
18358
|
-
const kindShaped = new Set(kinds.map((kind) => branchGlobPattern(`${kind}/*`).source));
|
|
18359
|
-
const anyName = patterns.some((pattern) => pattern.source === "^.*$");
|
|
18360
|
-
const others = patterns.filter((pattern) => !kindShaped.has(pattern.source)).map((pattern) => globOf(pattern));
|
|
18361
|
-
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.`;
|
|
18362
|
-
const resolved = vcsConfig("resolve", cwd);
|
|
18363
|
-
const integration = resolved.ok === false ? null : String(resolved.defaultTargetBranch ?? "") || null;
|
|
18364
|
-
const flow = resolved.releaseTrack?.track ? null : gitFlowOf(cwd, integration);
|
|
18365
|
-
if (flow?.developExists)
|
|
18366
|
-
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}.`;
|
|
18367
|
-
const names = branchNames(cwd);
|
|
18368
|
-
const configured = String(resolved.baseBranch ?? integration ?? "") || null;
|
|
18369
|
-
const trunk = productionBranchOf(names);
|
|
18370
|
-
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.";
|
|
18371
|
-
return `${allowed} ${base}`;
|
|
18372
|
-
} catch {
|
|
18373
|
-
return null;
|
|
18374
|
-
}
|
|
18375
|
-
};
|
|
18376
|
-
var globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*", "*").replace(/\\(.)/gu, "$1");
|
|
18377
|
-
|
|
18378
18413
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
18379
18414
|
import { createHash as createHash13 } from "node:crypto";
|
|
18380
18415
|
import fs15 from "node:fs";
|
|
@@ -22368,9 +22403,14 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
|
22368
22403
|
if (role !== "judge" || !event.agentId)
|
|
22369
22404
|
return readOnly;
|
|
22370
22405
|
const own = subagentSession(session, event.agentId);
|
|
22371
|
-
const
|
|
22372
|
-
const
|
|
22373
|
-
|
|
22406
|
+
const cwd = input.cwd || process.cwd();
|
|
22407
|
+
const token = session ? recordIssuedSession(cwd, session, own) : null;
|
|
22408
|
+
if (session && !token)
|
|
22409
|
+
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.`;
|
|
22410
|
+
const judge = event.agentType.endsWith("reviewer") ? "reviewer" : "verifier";
|
|
22411
|
+
const line = verdictCommand({ branch: judgeBranch(cwd), judge, session: own, token });
|
|
22412
|
+
const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
|
|
22413
|
+
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." : ""}`;
|
|
22374
22414
|
};
|
|
22375
22415
|
function handleHook(input, deps) {
|
|
22376
22416
|
const { descriptor } = deps;
|