@brainervirus/workit-cursor 7.0.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10053,6 +10053,7 @@ var readConfig = () => {
10053
10053
  throw new Error(result.error);
10054
10054
  return result.config ?? DEFAULTS;
10055
10055
  };
10056
+ var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
10056
10057
  var resolveBranchPolicy = (config, workspace) => {
10057
10058
  const wp = workspace?.branchPolicy ?? {};
10058
10059
  const preset = Object.hasOwn(PRESETS, wp.preset) ? wp.preset : config.branchPolicy?.preset ?? "gitflow";
@@ -10060,7 +10061,7 @@ var resolveBranchPolicy = (config, workspace) => {
10060
10061
  allowed: wp.allowed,
10061
10062
  protectedNames: wp.protected
10062
10063
  }, config);
10063
- const allowed = merged.allowed.map((p) => new RegExp(`^${p.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i"));
10064
+ const allowed = merged.allowed.map(branchGlobPattern);
10064
10065
  return {
10065
10066
  preset,
10066
10067
  allowed,
@@ -10125,26 +10126,31 @@ var versionSourceSchema = discriminatedUnion("kind", [
10125
10126
  object({ kind: literal("manual") }).strict()
10126
10127
  ]);
10127
10128
  var releaseTrackSchema = object({
10128
- strategy: branchPreset,
10129
+ strategy: branchPreset.optional(),
10129
10130
  productionBranch: nonBlank,
10130
10131
  integrationBranch: nonBlank,
10131
- naming: object({ feature: nonBlank, release: nonBlank, hotfix: nonBlank }).strict(),
10132
- baseBranch: nonBlank,
10133
- mergeBackBranches: array(nonBlank),
10134
- pullRequestTarget: nonBlank,
10135
- tagNamespace: string2(),
10136
- versionSource: versionSourceSchema,
10137
- requiredChecks: array(nonBlank)
10138
- }).strict().superRefine((track, context) => {
10132
+ naming: object({
10133
+ feature: nonBlank.optional(),
10134
+ release: nonBlank.optional(),
10135
+ hotfix: nonBlank.optional()
10136
+ }).passthrough().optional(),
10137
+ baseBranch: nonBlank.optional(),
10138
+ mergeBackBranches: array(nonBlank).optional(),
10139
+ pullRequestTarget: nonBlank.optional(),
10140
+ tagNamespace: string2().optional(),
10141
+ versionSource: versionSourceSchema.optional(),
10142
+ requiredChecks: array(nonBlank).optional(),
10143
+ critical: array(nonBlank).optional()
10144
+ }).passthrough().superRefine((track, context) => {
10139
10145
  for (const [field, values] of [
10140
- ["mergeBackBranches", track.mergeBackBranches],
10141
- ["requiredChecks", track.requiredChecks]
10146
+ ["mergeBackBranches", track.mergeBackBranches ?? []],
10147
+ ["requiredChecks", track.requiredChecks ?? []]
10142
10148
  ]) {
10143
10149
  if (new Set(values).size !== values.length) {
10144
10150
  context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
10145
10151
  }
10146
10152
  }
10147
- if (track.versionSource.kind === "package-json" && (path6.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
10153
+ if (track.versionSource?.kind === "package-json" && (path6.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
10148
10154
  context.addIssue({
10149
10155
  code: "custom",
10150
10156
  path: ["versionSource", "path"],
@@ -10411,7 +10417,7 @@ var runtimeWorkspacePolicySchema = (kind) => {
10411
10417
  var runtimeWorkspaceIndexSchema = object({
10412
10418
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
10413
10419
  }).passthrough();
10414
- var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
10420
+ var matchRuntimeWorkspace = (cwd) => {
10415
10421
  const file = path6.join(configDir(), "workspaces.json");
10416
10422
  let raw;
10417
10423
  try {
@@ -10446,8 +10452,17 @@ var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
10446
10452
  });
10447
10453
  const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
10448
10454
  const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
10449
- if (!selected)
10455
+ return selected ? { file, selected } : null;
10456
+ };
10457
+ var resolveRuntimeReleaseTracks = (cwd) => {
10458
+ const matched = matchRuntimeWorkspace(cwd);
10459
+ return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
10460
+ };
10461
+ var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
10462
+ const matched = matchRuntimeWorkspace(cwd);
10463
+ if (!matched)
10450
10464
  return null;
10465
+ const { file, selected } = matched;
10451
10466
  const policy = runtimeWorkspacePolicySchema(kind).safeParse(selected);
10452
10467
  if (!policy.success) {
10453
10468
  const detail = policy.error.issues.map((issue) => `${issue.path.map(String).join(".") || "workspace"}: ${issue.message}`).join("; ");
@@ -16228,11 +16243,176 @@ var turnContextText = (input, descriptor) => {
16228
16243
  };
16229
16244
  // packages/workit-core/src/core/branch.ts
16230
16245
  import { createHash as createHash9 } from "node:crypto";
16246
+
16247
+ // packages/workit-core/src/core/release-tracks.ts
16248
+ class ReleaseTrackError extends Error {
16249
+ }
16250
+ var KNOWN_FIELDS = new Set([
16251
+ "strategy",
16252
+ "productionBranch",
16253
+ "integrationBranch",
16254
+ "naming",
16255
+ "baseBranch",
16256
+ "mergeBackBranches",
16257
+ "pullRequestTarget",
16258
+ "tagNamespace",
16259
+ "versionSource",
16260
+ "requiredChecks",
16261
+ "critical"
16262
+ ]);
16263
+ var BRANCH_FIELDS = ["productionBranch", "integrationBranch", "baseBranch", "pullRequestTarget"];
16264
+ var PLACEHOLDER = /\{[^}]*\}/gu;
16265
+ var HAS_PLACEHOLDER = /\{[^}]*\}/u;
16266
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
16267
+ var branchName = (value) => typeof value === "string" && value.trim() && !value.trim().startsWith("-") ? value.trim() : null;
16268
+ var namedBranches = (entry) => [
16269
+ ...BRANCH_FIELDS.map((field) => branchName(entry[field])),
16270
+ ...Array.isArray(entry.mergeBackBranches) ? entry.mergeBackBranches.map(branchName) : []
16271
+ ].filter((name) => name !== null);
16272
+ var literalOf = (template) => template.replace(PLACEHOLDER, "").replace(/[*/]/gu, "").trim();
16273
+ function readReleaseTracks(raw) {
16274
+ const out = { tracks: [], issues: [], error: null, protectedBranches: [] };
16275
+ if (raw === undefined || raw === null)
16276
+ return out;
16277
+ if (!isRecord3(raw)) {
16278
+ out.issues.push("releaseTracks is not an object; ignored");
16279
+ return out;
16280
+ }
16281
+ const fatal = [];
16282
+ const protectedNames = new Set;
16283
+ for (const [name, entry] of Object.entries(raw).toSorted(([a], [b]) => a < b ? -1 : 1)) {
16284
+ const label = `release track ${JSON.stringify(name)}`;
16285
+ if (!isRecord3(entry)) {
16286
+ out.issues.push(`${label} is not an object; ignored`);
16287
+ continue;
16288
+ }
16289
+ for (const branch of namedBranches(entry))
16290
+ protectedNames.add(branch);
16291
+ if (!name.trim()) {
16292
+ out.issues.push("a release track with a blank name was ignored");
16293
+ continue;
16294
+ }
16295
+ let critical = [];
16296
+ if (Array.isArray(entry.critical))
16297
+ critical = entry.critical.filter((item) => typeof item === "string");
16298
+ else if (entry.critical !== undefined)
16299
+ out.issues.push(`${label} critical: must be a list of field names; ignored`);
16300
+ const isCritical = (field) => critical.some((item) => field === item || field.startsWith(`${item}.`));
16301
+ const problem = (field, message) => {
16302
+ if (isCritical(field))
16303
+ fatal.push(`${label} ${field}: ${message}`);
16304
+ else
16305
+ out.issues.push(`${label} ${field}: ${message}`);
16306
+ };
16307
+ for (const key of Object.keys(entry))
16308
+ if (!KNOWN_FIELDS.has(key))
16309
+ problem(key, "unknown field, ignored");
16310
+ const productionBranch = branchName(entry.productionBranch);
16311
+ const integrationBranch = branchName(entry.integrationBranch);
16312
+ if (!productionBranch)
16313
+ problem("productionBranch", "missing or not a branch name");
16314
+ if (!integrationBranch)
16315
+ problem("integrationBranch", "missing or not a branch name");
16316
+ const optionalBranch = (field) => {
16317
+ if (entry[field] === undefined)
16318
+ return null;
16319
+ const value = branchName(entry[field]);
16320
+ if (!value)
16321
+ problem(field, "not a branch name; using the integration branch");
16322
+ return value;
16323
+ };
16324
+ const baseBranch = optionalBranch("baseBranch");
16325
+ const pullRequestTarget = optionalBranch("pullRequestTarget");
16326
+ let mergeBackBranches = [];
16327
+ if (entry.mergeBackBranches !== undefined) {
16328
+ const list = Array.isArray(entry.mergeBackBranches) ? entry.mergeBackBranches.map(branchName) : [null];
16329
+ if (list.some((item) => item === null))
16330
+ problem("mergeBackBranches", "must be a list of branch names; ignored");
16331
+ else
16332
+ mergeBackBranches = [...new Set(list)];
16333
+ }
16334
+ const naming = {};
16335
+ if (entry.naming !== undefined) {
16336
+ if (!isRecord3(entry.naming))
16337
+ problem("naming", "not an object; ignored");
16338
+ else
16339
+ for (const kind of ["feature", "release", "hotfix"]) {
16340
+ const template = entry.naming[kind];
16341
+ if (template === undefined)
16342
+ continue;
16343
+ if (typeof template !== "string" || !template.trim())
16344
+ problem(`naming.${kind}`, "not a template string; ignored");
16345
+ else if (!literalOf(template))
16346
+ problem(`naming.${kind}`, "needs literal text besides placeholders; ignored");
16347
+ else
16348
+ naming[kind] = template.trim();
16349
+ }
16350
+ }
16351
+ if (!productionBranch || !integrationBranch) {
16352
+ out.issues.push(`${label} was skipped: it needs a productionBranch and integrationBranch`);
16353
+ continue;
16354
+ }
16355
+ out.tracks.push({
16356
+ name,
16357
+ productionBranch,
16358
+ integrationBranch,
16359
+ baseBranch: baseBranch ?? integrationBranch,
16360
+ pullRequestTarget: pullRequestTarget ?? integrationBranch,
16361
+ mergeBackBranches,
16362
+ naming
16363
+ });
16364
+ }
16365
+ out.protectedBranches = [...protectedNames];
16366
+ if (fatal.length)
16367
+ out.error = `workspace releaseTracks cannot be read by this Workit (${fatal.join("; ")}); upgrade Workit or fix the track`;
16368
+ return out;
16369
+ }
16370
+ var trackBranches = (tracks) => [
16371
+ ...new Set(tracks.flatMap((track) => [
16372
+ track.productionBranch,
16373
+ track.integrationBranch,
16374
+ track.baseBranch,
16375
+ track.pullRequestTarget,
16376
+ ...track.mergeBackBranches
16377
+ ]))
16378
+ ];
16379
+ var namingGlob = (template) => HAS_PLACEHOLDER.test(template) ? template.replace(PLACEHOLDER, "*") : `${template.replace(/\/?\*?$/u, "")}/*`;
16380
+ function workspaceReleaseTracks(cwd) {
16381
+ const raw = resolveRuntimeReleaseTracks(cwd);
16382
+ return { workspace: raw?.workspace ?? null, ...readReleaseTracks(raw?.releaseTracks) };
16383
+ }
16384
+ var memo3 = new Map;
16385
+
16386
+ // packages/workit-core/src/core/branch.ts
16387
+ var withReleaseTracks = (workspaceRoot, policy) => {
16388
+ const read = workspaceReleaseTracks(workspaceRoot);
16389
+ if (read.error)
16390
+ throw new ReleaseTrackError(read.error);
16391
+ if (read.tracks.length === 0 && read.protectedBranches.length === 0)
16392
+ return policy;
16393
+ const known = new Set(policy.allowed.map((pattern) => pattern.source));
16394
+ const allowed = [...policy.allowed];
16395
+ for (const glob of read.tracks.flatMap((track) => Object.values(track.naming).map(namingGlob))) {
16396
+ const pattern = branchGlobPattern(glob);
16397
+ if (!known.has(pattern.source)) {
16398
+ known.add(pattern.source);
16399
+ allowed.push(pattern);
16400
+ }
16401
+ }
16402
+ return {
16403
+ ...policy,
16404
+ allowed,
16405
+ protected: new Set([
16406
+ ...policy.protected,
16407
+ ...[...trackBranches(read.tracks), ...read.protectedBranches].map((name) => name.toLowerCase())
16408
+ ])
16409
+ };
16410
+ };
16231
16411
  function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
16232
16412
  const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
16233
16413
  const config = readConfig();
16234
16414
  return kind === "branch" ? {
16235
- branchPolicy: resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null),
16415
+ branchPolicy: withReleaseTracks(workspaceRoot, resolveBranchPolicy(config, selected.policy ? { branchPolicy: selected.policy } : null)),
16236
16416
  provenance: { branchPolicy: selected.source }
16237
16417
  } : {
16238
16418
  commitPolicy: resolveCommitPolicy(config, selected.policy ? { commitPolicy: selected.policy } : null),
@@ -16581,7 +16761,7 @@ function writeGate(cwd, paths) {
16581
16761
  // packages/workit-core/src/hooks/hosts/fields.ts
16582
16762
  import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
16583
16763
  import path17 from "node:path";
16584
- var isRecord3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
16764
+ var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
16585
16765
  var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
16586
16766
  var optionalText = (value) => typeof value === "string" ? value : null;
16587
16767
  var existingDirectory = (value) => {
@@ -16637,7 +16817,7 @@ var WRITE_TOOLS = new Set([
16637
16817
  var isWriteTool = (name) => typeof name === "string" && WRITE_TOOLS.has(name.toLowerCase().replace(/[_-]/g, ""));
16638
16818
  var PATH_KEYS = ["file_path", "filePath", "notebook_path", "path", "target_file", "file"];
16639
16819
  var writePaths = (input) => {
16640
- if (!isRecord3(input))
16820
+ if (!isRecord4(input))
16641
16821
  return [];
16642
16822
  const paths = PATH_KEYS.map((key) => input[key]).filter(nonEmpty2);
16643
16823
  for (const value of Object.values(input))
@@ -16841,7 +17021,7 @@ var EVENTS = {
16841
17021
  };
16842
17022
  var SOURCES = new Set(["startup", "resume", "clear", "compact", "fork"]);
16843
17023
  var SHELL_TOOLS = new Set(["Bash", "PowerShell"]);
16844
- var toolCommand = (value) => isRecord3(value.tool_input) ? commandText(value.tool_input.command) : null;
17024
+ var toolCommand = (value) => isRecord4(value.tool_input) ? commandText(value.tool_input.command) : null;
16845
17025
  var eventOf = (name, value) => {
16846
17026
  const toolUseId = optionalText(value.tool_use_id);
16847
17027
  switch (name) {
@@ -16871,7 +17051,7 @@ var eventOf = (name, value) => {
16871
17051
  const command = toolCommand(value);
16872
17052
  if (!SHELL_TOOLS.has(String(value.tool_name)) || !command)
16873
17053
  return { ok: false, error: "only shell PostToolUse is mapped" };
16874
- const response = isRecord3(value.tool_response) ? value.tool_response : {};
17054
+ const response = isRecord4(value.tool_response) ? value.tool_response : {};
16875
17055
  return {
16876
17056
  ok: true,
16877
17057
  event: {
@@ -16947,14 +17127,14 @@ var render = (decision, native) => {
16947
17127
  var claudeCodeAdapter = {
16948
17128
  descriptor: CLAUDE_CODE_DESCRIPTOR,
16949
17129
  parse(raw) {
16950
- const native = isRecord3(raw) && Object.hasOwn(EVENTS, String(raw.hook_event_name)) ? raw.hook_event_name : null;
17130
+ const native = isRecord4(raw) && Object.hasOwn(EVENTS, String(raw.hook_event_name)) ? raw.hook_event_name : null;
16951
17131
  const fail = (error) => ({
16952
17132
  ok: false,
16953
17133
  error,
16954
17134
  native,
16955
17135
  event: native ? EVENTS[native] : null
16956
17136
  });
16957
- if (!isRecord3(raw) || !native)
17137
+ if (!isRecord4(raw) || !native)
16958
17138
  return fail("hook_event_name is required");
16959
17139
  if (!nonEmpty2(raw.session_id))
16960
17140
  return fail("session_id is required");
@@ -17096,7 +17276,7 @@ var SHELL_TOOLS2 = new Set(["bash", "unified-exec"]);
17096
17276
  var isShellTool = (name) => SHELL_TOOLS2.has(String(name).toLowerCase());
17097
17277
  var SOURCES2 = new Set(["startup", "resume", "clear", "compact"]);
17098
17278
  var parseCodexHookInput = (value) => {
17099
- if (!isRecord3(value) || !Object.hasOwn(EVENTS2, String(value.hook_event_name)))
17279
+ if (!isRecord4(value) || !Object.hasOwn(EVENTS2, String(value.hook_event_name)))
17100
17280
  return { ok: false, error: "hook_event_name is required" };
17101
17281
  const event = value.hook_event_name;
17102
17282
  const cwd = existingDirectory(value.cwd);
@@ -17104,7 +17284,7 @@ var parseCodexHookInput = (value) => {
17104
17284
  return { ok: false, error: "cwd must be an existing absolute directory" };
17105
17285
  if (event === "PreToolUse" && !nonEmpty2(value.tool_name))
17106
17286
  return { ok: false, error: "tool_name is required" };
17107
- const command = isRecord3(value.tool_input) ? commandText(value.tool_input.command) : null;
17287
+ const command = isRecord4(value.tool_input) ? commandText(value.tool_input.command) : null;
17108
17288
  if (event === "PreToolUse" && isShellTool(value.tool_name) && !command)
17109
17289
  return { ok: false, error: "tool_input.command is required for shell tools" };
17110
17290
  if (event === "SubagentStart" && !nonEmpty2(value.agent_id))
@@ -17187,7 +17367,7 @@ var codexAdapter = {
17187
17367
  const host = detectCodexSurface(env);
17188
17368
  const parsed = parseCodexHookInput(raw);
17189
17369
  if (!parsed.ok) {
17190
- const native = isRecord3(raw) && Object.hasOwn(EVENTS2, String(raw.hook_event_name)) ? raw.hook_event_name : null;
17370
+ const native = isRecord4(raw) && Object.hasOwn(EVENTS2, String(raw.hook_event_name)) ? raw.hook_event_name : null;
17191
17371
  return { ok: false, error: parsed.error, native, event: native ? EVENTS2[native] : null };
17192
17372
  }
17193
17373
  const input = parsed.data;
@@ -17326,7 +17506,7 @@ var EVENTS3 = {
17326
17506
  preCompact: "compact.pre"
17327
17507
  };
17328
17508
  var parseCursorHookInput = (value) => {
17329
- if (!isRecord3(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
17509
+ if (!isRecord4(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
17330
17510
  return { ok: false, error: "hook_event_name is required" };
17331
17511
  const roots = value.workspace_roots;
17332
17512
  if (!Array.isArray(roots) || roots.length === 0 || !roots.every(nonEmpty2))
@@ -17432,7 +17612,7 @@ var cursorAdapter = {
17432
17612
  parse(raw) {
17433
17613
  const parsed = parseCursorHookInput(raw);
17434
17614
  if (!parsed.ok) {
17435
- const native = isRecord3(raw) && Object.hasOwn(EVENTS3, String(raw.hook_event_name)) ? raw.hook_event_name : null;
17615
+ const native = isRecord4(raw) && Object.hasOwn(EVENTS3, String(raw.hook_event_name)) ? raw.hook_event_name : null;
17436
17616
  return { ok: false, error: parsed.error, native, event: native ? EVENTS3[native] : null };
17437
17617
  }
17438
17618
  const input = parsed.data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin — shared MCP transport, native hooks, and sixteen method skills",
6
6
  "keywords": [
@@ -44,8 +44,8 @@
44
44
  "build": "bun scripts/build.ts"
45
45
  },
46
46
  "dependencies": {
47
- "@brainervirus/workit-core": "^7.0.0",
48
- "@brainervirus/workit-mcp": "^7.0.0"
47
+ "@brainervirus/workit-core": "^7.1.0",
48
+ "@brainervirus/workit-mcp": "^7.1.0"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=24"