@brainervirus/workit-cursor 8.18.0 → 8.19.1

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.
@@ -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 createHash7, randomBytes as randomBytes2 } from "node:crypto";
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 createHash6, randomBytes, timingSafeEqual } from "node:crypto";
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) => createHash6("sha256").update(value).digest("hex").slice(0, 32);
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) => createHash6("sha256").update(token).digest("hex");
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 = createHash7("sha256");
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) => createHash7("sha256").update(text).digest("hex");
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;
@@ -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 createHash9, randomUUID as randomUUID3 } from "node:crypto";
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 createHash8 } from "node:crypto";
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) => createHash8("sha256").update(JSON.stringify(value)).digest("hex");
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 = createHash9("sha256").update(key).digest("hex").slice(0, 32);
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 createHash10 } from "node:crypto";
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";
@@ -15294,7 +15526,7 @@ function checkCommand(args, version, onPath = workitAvailable()) {
15294
15526
  }
15295
15527
 
15296
15528
  // packages/workit-core/src/core/task-evaluation.ts
15297
- var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
15529
+ var digestBytes = (value) => createHash11("sha256").update(value).digest("hex");
15298
15530
  var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`);
15299
15531
  var relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".";
15300
15532
  var canonicalPath = (value) => {
@@ -17943,7 +18175,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
17943
18175
  };
17944
18176
  });
17945
18177
  // packages/workit-core/src/hooks/context.ts
17946
- import { createHash as createHash11 } from "node:crypto";
18178
+ import { createHash as createHash12 } from "node:crypto";
17947
18179
  import fs14 from "node:fs";
17948
18180
  import path18 from "node:path";
17949
18181
  var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
@@ -18099,7 +18331,7 @@ var turnContextText = (input, descriptor) => {
18099
18331
  }
18100
18332
  };
18101
18333
  var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
18102
- var digestOf = (text) => createHash11("sha256").update(text).digest("hex");
18334
+ var digestOf = (text) => createHash12("sha256").update(text).digest("hex");
18103
18335
  var turnMarker = (input) => {
18104
18336
  if (!input.session.id)
18105
18337
  return null;
@@ -18178,214 +18410,6 @@ import fs16 from "node:fs";
18178
18410
  import os5 from "node:os";
18179
18411
  import path20 from "node:path";
18180
18412
 
18181
- // packages/workit-core/src/core/branch.ts
18182
- import { createHash as createHash12 } from "node:crypto";
18183
- var withReleaseTracks = (workspaceRoot, policy) => {
18184
- const read = workspaceReleaseTracks(workspaceRoot);
18185
- if (read.error)
18186
- throw new ReleaseTrackError(read.error);
18187
- if (read.tracks.length === 0 && read.protectedBranches.length === 0)
18188
- return policy;
18189
- const known = new Set(policy.allowed.map((pattern) => pattern.source));
18190
- const allowed = [...policy.allowed];
18191
- for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
18192
- const pattern = branchGlobPattern(glob);
18193
- if (!known.has(pattern.source)) {
18194
- known.add(pattern.source);
18195
- allowed.push(pattern);
18196
- }
18197
- }
18198
- return {
18199
- ...policy,
18200
- allowed,
18201
- protected: new Set([
18202
- ...policy.protected,
18203
- ...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
18204
- ])
18205
- };
18206
- };
18207
- function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
18208
- const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
18209
- const config = readConfig();
18210
- return kind === "branch" ? {
18211
- branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null, () => repoBranchPreset(workspaceRoot))),
18212
- provenance: { branchPolicy: selected.source }
18213
- } : {
18214
- commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
18215
- provenance: { commitPolicy: selected.source }
18216
- };
18217
- }
18218
- var KIND_SYNONYMS = {
18219
- fix: "bugfix",
18220
- fixes: "bugfix",
18221
- bug: "bugfix",
18222
- bugs: "bugfix",
18223
- bugfixes: "bugfix",
18224
- feat: "feature",
18225
- features: "feature",
18226
- chore: "feature",
18227
- docs: "feature",
18228
- doc: "feature",
18229
- refactor: "feature",
18230
- test: "feature",
18231
- tests: "feature",
18232
- ci: "feature",
18233
- build: "feature",
18234
- perf: "feature",
18235
- style: "feature",
18236
- deps: "feature",
18237
- task: "feature",
18238
- enhancement: "feature",
18239
- hot: "hotfix",
18240
- hotfixes: "hotfix",
18241
- releases: "release",
18242
- rel: "release"
18243
- };
18244
- var allowedKinds = (allowed) => [
18245
- ...new Set(allowed.map((pattern) => /^\^([\w.-]+)\\?\/\.\*\$$/u.exec(pattern.source)?.[1]?.toLowerCase()).filter((kind) => Boolean(kind)))
18246
- ];
18247
- var editDistance = (a, b) => {
18248
- const row = Array.from({ length: b.length + 1 }, (_, index) => index);
18249
- for (let i = 1;i <= a.length; i++) {
18250
- let previous = row[0];
18251
- row[0] = i;
18252
- for (let j = 1;j <= b.length; j++) {
18253
- const saved = row[j];
18254
- row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
18255
- previous = saved;
18256
- }
18257
- }
18258
- return row[b.length];
18259
- };
18260
- var suggestBranchName = (name, kinds) => {
18261
- if (!kinds.length)
18262
- return null;
18263
- const slash = name.indexOf("/");
18264
- const prefix = slash > 0 ? name.slice(0, slash).toLowerCase() : "";
18265
- const rest = (slash > 0 ? name.slice(slash + 1) : name) || "name";
18266
- const synonym = KIND_SYNONYMS[prefix];
18267
- 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;
18268
- const kind = (synonym && kinds.includes(synonym) ? synonym : null) ?? near ?? (kinds.includes("feature") ? "feature" : kinds[0]);
18269
- return `${kind}/${rest}`;
18270
- };
18271
- var kindList = (kinds) => kinds.map((kind) => `${kind}/`).join(", ");
18272
- var aliasNote = (kinds) => {
18273
- const notes = [
18274
- ["fix", "bugfix"],
18275
- ["chore", "feature"]
18276
- ].filter(([, kind]) => kinds.includes(kind)).map(([alias, kind]) => `${alias}/ is ${kind}/`);
18277
- return notes.length ? ` (${notes.join(", ")})` : "";
18278
- };
18279
- var validateBranchNamePolicy = (name, policy, source) => {
18280
- const allowed = policy.allowed.map((pattern) => `/${pattern.source}/${pattern.flags}`);
18281
- const kinds = allowedKinds(policy.allowed);
18282
- if (policy.protected.has(name.toLowerCase())) {
18283
- 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(", ")}`;
18284
- return {
18285
- ok: false,
18286
- rule: "protected_ref",
18287
- source,
18288
- attempted: name,
18289
- correction,
18290
- error: `protected_ref: branch ${JSON.stringify(name)} is protected by ${source}; ${correction}`
18291
- };
18292
- }
18293
- if (!policy.allowed.some((pattern) => pattern.test(name))) {
18294
- const suggestion = suggestBranchName(name, kinds);
18295
- 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(", ")}`;
18296
- return {
18297
- ok: false,
18298
- rule: "allowed_pattern",
18299
- source,
18300
- attempted: name,
18301
- correction,
18302
- error: `allowed_pattern: branch ${JSON.stringify(name)} violates ${source} policy; ${correction}`
18303
- };
18304
- }
18305
- return { ok: true };
18306
- };
18307
- var branchPolicySnapshotFor = (workspaceRoot) => {
18308
- const resolved = effectiveWorkspacePolicy(workspaceRoot, "branch");
18309
- const branchPolicy = resolved.branchPolicy;
18310
- const source = resolved.provenance.branchPolicy;
18311
- const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
18312
- const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
18313
- const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
18314
- return {
18315
- branchPolicy,
18316
- namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
18317
- source,
18318
- fingerprint
18319
- };
18320
- };
18321
- var validateBranchNameFor = (workspaceRoot, name) => {
18322
- try {
18323
- const resolved = branchPolicySnapshotFor(workspaceRoot);
18324
- return validateBranchNamePolicy(name, resolved.namePolicy, resolved.source);
18325
- } catch (error) {
18326
- const correction = "repair or select a valid workspace policy before creating a branch";
18327
- return {
18328
- ok: false,
18329
- rule: "policy_unavailable",
18330
- source: "workspaces.json",
18331
- attempted: name,
18332
- correction,
18333
- error: `policy_unavailable: cannot validate branch ${JSON.stringify(name)} because ${error instanceof Error ? error.message : String(error)}; ${correction}`
18334
- };
18335
- }
18336
- };
18337
- var resolveBranchPolicyFor = (workspaceRoot, profileName) => effectiveWorkspacePolicy(workspaceRoot, "branch", profileName).branchPolicy;
18338
- var gitFlowOf = (root, integration) => {
18339
- try {
18340
- if (resolveBranchPolicyFor(root).preset !== "gitflow")
18341
- return null;
18342
- const selected = resolveRuntimeWorkspacePolicy(root, "branch", process.env.WORKFLOW_PROFILE?.trim() || undefined).policy;
18343
- const names = branchNames(root);
18344
- const production = productionBranchOf(names);
18345
- const develop = selected?.developBranch?.trim() || (integration && integration.toLowerCase() !== production ? integration : "develop");
18346
- return { develop, production, developExists: names.has(develop) };
18347
- } catch {
18348
- return null;
18349
- }
18350
- };
18351
- var releaseBranchesOf = (cwd) => {
18352
- try {
18353
- const resolved = resolveBranchPolicyFor(cwd);
18354
- const flow = resolved.preset === "gitflow" ? gitFlowOf(cwd) : null;
18355
- return {
18356
- preset: resolved.preset,
18357
- branches: flow ? [flow.production, flow.develop] : [],
18358
- production: flow ? flow.production : resolved.defaultTargetBranch
18359
- };
18360
- } catch {
18361
- return { preset: "unknown", branches: [], production: null };
18362
- }
18363
- };
18364
- var releaseBranch = (cwd, branch) => releaseBranchesOf(cwd).branches.some((name) => name.toLowerCase() === branch.toLowerCase());
18365
- var branchGuidance = (cwd) => {
18366
- try {
18367
- const patterns = branchPolicySnapshotFor(cwd).namePolicy.allowed;
18368
- const kinds = allowedKinds(patterns);
18369
- const kindShaped = new Set(kinds.map((kind) => branchGlobPattern(`${kind}/*`).source));
18370
- const anyName = patterns.some((pattern) => pattern.source === "^.*$");
18371
- const others = patterns.filter((pattern) => !kindShaped.has(pattern.source)).map((pattern) => globOf(pattern));
18372
- 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.`;
18373
- const resolved = vcsConfig("resolve", cwd);
18374
- const integration = resolved.ok === false ? null : String(resolved.defaultTargetBranch ?? "") || null;
18375
- const flow = resolved.releaseTrack?.track ? null : gitFlowOf(cwd, integration);
18376
- if (flow?.developExists)
18377
- 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}.`;
18378
- const names = branchNames(cwd);
18379
- const configured = String(resolved.baseBranch ?? integration ?? "") || null;
18380
- const trunk = productionBranchOf(names);
18381
- 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.";
18382
- return `${allowed} ${base}`;
18383
- } catch {
18384
- return null;
18385
- }
18386
- };
18387
- var globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*", "*").replace(/\\(.)/gu, "$1");
18388
-
18389
18413
  // packages/workit-core/src/hooks/session-marker.ts
18390
18414
  import { createHash as createHash13 } from "node:crypto";
18391
18415
  import fs15 from "node:fs";
@@ -22379,9 +22403,14 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
22379
22403
  if (role !== "judge" || !event.agentId)
22380
22404
  return readOnly;
22381
22405
  const own = subagentSession(session, event.agentId);
22382
- const token = session ? recordIssuedSession(input.cwd || process.cwd(), session, own) : null;
22383
- const flags = token ? `--session ${own} --token ${token}` : `--session ${own}`;
22384
- return `${readOnly} Its own Workit session is ${own}: record verdicts with \`workit ledger verdict <result> ${flags} ...\` so the ledger tells it apart from the author.${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." : ""}`;
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." : ""}`;
22385
22414
  };
22386
22415
  function handleHook(input, deps) {
22387
22416
  const { descriptor } = deps;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "8.18.0",
3
+ "version": "8.19.1",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin — shared MCP transport, native hooks, and sixteen method skills",
6
6
  "keywords": [
@@ -46,8 +46,8 @@
46
46
  "build": "bun scripts/build.ts"
47
47
  },
48
48
  "devDependencies": {
49
- "@brainervirus/workit-core": "^8.18.0",
50
- "@brainervirus/workit-mcp": "^8.18.0"
49
+ "@brainervirus/workit-core": "^8.19.1",
50
+ "@brainervirus/workit-mcp": "^8.19.1"
51
51
  },
52
52
  "engines": {
53
53
  "node": ">=24"
@@ -24,7 +24,10 @@ description: Build a requested change in small verified steps - follow local pat
24
24
  lease waits and names its holder (`workit lock status`).
25
25
  5. Prove the feature on its real surface with the project's `verify-<app>`
26
26
  skill; none yet? Write one (read the `workit-verify-app` skill's SKILL.md and follow it). Tests show branch behavior,
27
- not that the feature works.
27
+ not that the feature works. The report carries what you observed: a UI
28
+ change a screenshot or console/network check (chrome devtools or
29
+ agent-browser), an API a quoted real response. App not runnable? Say so
30
+ plainly, never claim success.
28
31
  6. Commit: `workit git commit -m "<type>: <what>" -- <paths>` (or `--all`).
29
32
  No endpoint named? Stop here and state the next command. Hand delivery to
30
33
  ship, which pushes and opens the PR with its body shape (read the `workit-ship` skill's SKILL.md and follow it), only
@@ -55,8 +58,7 @@ flag was never invoked)
55
58
 
56
59
  Good: "Added `--since`. measured: `workit check test` exit 0;
57
60
  `mytool log --since 2d` printed 3 entries against the fixture repo. inferred:
58
- the GitLab path behaves the same (shared parser, not run). Verification handed
59
- to the verifier agent."
61
+ the GitLab path behaves the same (not run). Handed to the verifier agent."
60
62
 
61
63
  ## Check
62
64
 
@@ -27,7 +27,10 @@ way a user would.
27
27
  - **Drive:** how to exercise it: CLI invocations, `curl` against routes, a
28
28
  browser tool for UI, with fixture data.
29
29
  - **Evidence:** what to capture (exit code, response body, screenshot path)
30
- and the command that records it.
30
+ and the command that records it. A UI is driven with chrome devtools or
31
+ agent-browser, with a screenshot or console/network observation; an API
32
+ with a real call, response quoted. The report carries the observation.
33
+ App not runnable? Say so plainly, never claim success.
31
34
  - **Cleanup:** stop processes, remove temp data.
32
35
  - **Feature map:** feature, how to drive it, expected observation.
33
36
  3. **Prove it end-to-end once:** launch, drive one feature, capture evidence,
@@ -54,7 +57,8 @@ report `clean`, `changed` (what) or `blocked` (why).
54
57
  Bad: "Verify by running the tests." (that is not the real surface)
55
58
 
56
59
  Good: "Launch `bun run dev` (ready: `listening on :5173`, 30 s). Drive:
57
- `curl -s localhost:5173/api/health` returns `{"ok":true}`. Evidence:
60
+ `curl -s localhost:5173/api/health` returned `{"ok":true}`; screenshot of
61
+ /settings at .workit-scratch/settings.png. Evidence:
58
62
  `workit check --name verify-web -- bun scripts/smoke.ts` exit 0."
59
63
 
60
64
  ## Check
@@ -30,6 +30,8 @@ description: Launch, drive and observe <app> on its real surface (<cli|web|api>)
30
30
  ## Evidence
31
31
  `workit check --name verify-<app> -- <driver command>` records exit code and log.
32
32
  Screenshots go to `<tmp dir>/verify-<app>/<feature>.png`; cite the path.
33
+ UI: also report a console or network observation. API: quote the real response.
34
+ If the app cannot be run, say so plainly instead of claiming success.
33
35
 
34
36
  ## Cleanup
35
37
  `<command>` (stop servers, remove `<tmp dir>`).