@brainervirus/workit-cli 8.40.6 → 8.40.8

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.
Files changed (2) hide show
  1. package/dist/index.js +135 -26
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -6389,7 +6389,7 @@ var init_zod = __esm(() => {
6389
6389
  // packages/workit-core/src/core/workspaces.ts
6390
6390
  import { spawnSync as spawnSync2 } from "node:child_process";
6391
6391
  import { createHash } from "node:crypto";
6392
- import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync } from "node:fs";
6392
+ import { existsSync as existsSync2, lstatSync, readFileSync as readFileSync2, realpathSync } from "node:fs";
6393
6393
  import path2 from "node:path";
6394
6394
  function workspaceDefaultTarget(cwd, globalDefault) {
6395
6395
  const ws = resolveRuntimeWorkspaceVcs(cwd);
@@ -6537,6 +6537,15 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6537
6537
  return cached;
6538
6538
  let dir = path2.resolve(cwd);
6539
6539
  while (!existsSync2(path2.join(dir, ".git"))) {
6540
+ if (["HEAD", "objects", "refs"].every((name) => existsSync2(path2.join(dir, name)))) {
6541
+ const real = realpathOf(dir);
6542
+ const owner = ownInternals(real) === true ? gitDirOwner(real) : null;
6543
+ if (owner === null)
6544
+ return Error(`${cwd} is in a repository with no work tree at ${real}: no grants apply`);
6545
+ const probe = { main: owner, superproject: null };
6546
+ probes.set(cwd, probe);
6547
+ return probe;
6548
+ }
6540
6549
  const up = path2.dirname(dir);
6541
6550
  if (up === dir)
6542
6551
  return null;
@@ -6566,7 +6575,24 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6566
6575
  if (!gitDir || !common)
6567
6576
  return failed;
6568
6577
  let main = null;
6569
- if (path2.resolve(gitDir) !== path2.resolve(common)) {
6578
+ if (path2.resolve(gitDir) === path2.resolve(common)) {
6579
+ const real = realpathOf(common);
6580
+ if (!ownGitDir(path2.join(dir, ".git"), real)) {
6581
+ const owner = gitDirOwner(real);
6582
+ if (owner === null)
6583
+ return Error(`${cwd} uses the repository at ${real}, owned by no checkout workit can name`);
6584
+ if (owner !== realpathOf(dir))
6585
+ main = owner;
6586
+ }
6587
+ const lender = ownInternals(real);
6588
+ if (lender === false)
6589
+ return Error(`${cwd} borrows git internals from outside ${real} that no checkout owns`);
6590
+ if (lender !== true && lender !== realpathOf(dir)) {
6591
+ if (main !== null && main !== lender)
6592
+ return Error(`${cwd} mixes the repositories of ${main} and ${lender}`);
6593
+ main = lender;
6594
+ }
6595
+ } else {
6570
6596
  const list = git(["worktree", "list", "--porcelain"]);
6571
6597
  if (list === null)
6572
6598
  return failed;
@@ -6575,6 +6601,44 @@ var nonBlank, branchPreset, commitPreset, workspaceBranchPolicySchema, workspace
6575
6601
  const probe = { main, superproject: superproject || null };
6576
6602
  probes.set(cwd, probe);
6577
6603
  return probe;
6604
+ }, ownGitDir = (dotGit, real) => {
6605
+ try {
6606
+ return lstatSync(dotGit).isDirectory() && realpathOf(dotGit) === real;
6607
+ } catch {
6608
+ return false;
6609
+ }
6610
+ }, INTERNALS, ownInternals = (real) => {
6611
+ let lender = null;
6612
+ for (const name of INTERNALS) {
6613
+ const at = path2.join(real, name);
6614
+ try {
6615
+ lstatSync(at);
6616
+ } catch {
6617
+ continue;
6618
+ }
6619
+ let resolved;
6620
+ try {
6621
+ resolved = (realpathSync.native ?? realpathSync)(at);
6622
+ } catch {
6623
+ return false;
6624
+ }
6625
+ const rel = path2.relative(real, resolved);
6626
+ if (rel && !rel.startsWith("..") && !path2.isAbsolute(rel))
6627
+ continue;
6628
+ const owner = path2.basename(resolved) === name ? gitDirOwner(path2.dirname(resolved)) : null;
6629
+ if (owner === null || lender !== null && lender !== owner)
6630
+ return false;
6631
+ lender = owner;
6632
+ }
6633
+ return lender ?? true;
6634
+ }, gitDirOwner = (real) => {
6635
+ const parts = real.split(/[\\/]/u);
6636
+ const at = parts.lastIndexOf(".git");
6637
+ if (at < 1)
6638
+ return null;
6639
+ const rest = parts.slice(at + 1);
6640
+ const module = rest[0] === "modules" || rest[0] === "worktrees" && rest[2] === "modules";
6641
+ return rest.length === 0 || module ? parts.slice(0, at).join(path2.sep) || path2.sep : null;
6578
6642
  }, mainCheckoutOf = (cwd) => {
6579
6643
  const probe = probeCheckout(cwd);
6580
6644
  return probe instanceof Error ? null : probe?.main ?? null;
@@ -7035,6 +7099,7 @@ var init_workspaces = __esm(() => {
7035
7099
  name = "WorkspaceConfigError";
7036
7100
  };
7037
7101
  probes = new Map;
7102
+ INTERNALS = ["refs", "objects", "config", "packed-refs", "commondir"];
7038
7103
  runtimeWorkspaceIndexSchema = object({
7039
7104
  workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
7040
7105
  }).passthrough();
@@ -9352,7 +9417,7 @@ var package_default;
9352
9417
  var init_package = __esm(() => {
9353
9418
  package_default = {
9354
9419
  name: "@brainervirus/workit-cli",
9355
- version: "8.40.6",
9420
+ version: "8.40.8",
9356
9421
  private: false,
9357
9422
  description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
9358
9423
  keywords: [
@@ -9390,13 +9455,13 @@ var init_package = __esm(() => {
9390
9455
  },
9391
9456
  dependencies: {
9392
9457
  "@babel/parser": "7.29.9",
9393
- "@brainervirus/workit-cursor": "^8.40.6",
9458
+ "@brainervirus/workit-cursor": "^8.40.8",
9394
9459
  "@inkjs/ui": "2.0.0",
9395
9460
  ink: "7.1.1",
9396
9461
  react: "19.2.8"
9397
9462
  },
9398
9463
  devDependencies: {
9399
- "@brainervirus/workit-core": "^8.40.6"
9464
+ "@brainervirus/workit-core": "^8.40.8"
9400
9465
  },
9401
9466
  engines: {
9402
9467
  node: ">=24"
@@ -9662,7 +9727,7 @@ import {
9662
9727
  closeSync,
9663
9728
  fchmodSync,
9664
9729
  fsyncSync,
9665
- lstatSync,
9730
+ lstatSync as lstatSync2,
9666
9731
  mkdirSync as mkdirSync3,
9667
9732
  openSync,
9668
9733
  renameSync,
@@ -9686,7 +9751,7 @@ function writeFileAtomic(file, content, mode) {
9686
9751
  const root = path10.parse(parent).root;
9687
9752
  for (;; ) {
9688
9753
  try {
9689
- if (lstatSync(parent).isSymbolicLink())
9754
+ if (lstatSync2(parent).isSymbolicLink())
9690
9755
  throw new Error(`symlinked write path: ${parent}`);
9691
9756
  } catch (error) {
9692
9757
  if (error.code !== "ENOENT")
@@ -9701,7 +9766,7 @@ function writeFileAtomic(file, content, mode) {
9701
9766
  mkdirSync3(directory, { recursive: true });
9702
9767
  let existing = null;
9703
9768
  try {
9704
- existing = lstatSync(absolute);
9769
+ existing = lstatSync2(absolute);
9705
9770
  } catch (error) {
9706
9771
  if (error.code !== "ENOENT")
9707
9772
  throw error;
@@ -18797,6 +18862,7 @@ var SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLARATIONS
18797
18862
  let here = dir;
18798
18863
  const config = [...inherited];
18799
18864
  let gitDir = env.GIT_DIR;
18865
+ let from = "GIT_DIR";
18800
18866
  let index = 0;
18801
18867
  for (;index < words.length; index++) {
18802
18868
  const word = words[index];
@@ -18804,18 +18870,21 @@ var SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLARATIONS
18804
18870
  here = words[index + 1] ? joinDir(here, words[++index]) : here;
18805
18871
  else if (GIT_CONFIG_OPTIONS.has(word)) {
18806
18872
  if (word === "--git-dir")
18807
- gitDir = words[index + 1];
18873
+ [gitDir, from] = [words[index + 1], "--git-dir"];
18808
18874
  if (words[index + 1] !== undefined)
18809
18875
  config.push(word, words[++index]);
18810
18876
  } else if (/^--(?:config-env|git-dir)=/.test(word)) {
18811
18877
  if (word.startsWith("--git-dir="))
18812
- gitDir = word.slice("--git-dir=".length);
18878
+ [gitDir, from] = [word.slice("--git-dir=".length), "--git-dir"];
18813
18879
  config.push(word);
18814
18880
  } else if (GIT_VALUE_OPTIONS.has(word))
18815
18881
  index++;
18816
18882
  else if (!word.startsWith("-"))
18817
18883
  break;
18818
18884
  }
18885
+ if (env.GIT_COMMON_DIR)
18886
+ [gitDir, from] = [env.GIT_COMMON_DIR, "GIT_COMMON_DIR"];
18887
+ const known = here !== undefined;
18819
18888
  if (gitDir)
18820
18889
  here = joinDir(here, gitDir.replace(/(?:^|[\\/]+)\.git[\\/]*$/, "") || ".");
18821
18890
  return {
@@ -18824,7 +18893,8 @@ var SHELLS, POWERSHELLS, EVALS, WRAPPERS, WRAPPER_VALUES, KEYWORDS, DECLARATIONS
18824
18893
  args: words.slice(index),
18825
18894
  ...config.length ? { config } : {},
18826
18895
  ...Object.keys(env).length ? { env } : {},
18827
- ...stdin === undefined ? {} : { stdin }
18896
+ ...stdin === undefined ? {} : { stdin },
18897
+ ...known && here === undefined ? { redirect: from } : {}
18828
18898
  };
18829
18899
  }, RECENT, LAUNCHERS, WORKIT_PACKAGE, PACKAGE_RUNNERS, OUTPUT_FILTERS, WORKIT_GLOBAL, PUSH_VALUE_OPTIONS, VALUE_OPTIONS, API_VALUES, API_FIELDS, GIT_COMMANDS;
18830
18900
  var init_raw_git = __esm(() => {
@@ -66622,7 +66692,7 @@ import { spawnSync as spawnSync15 } from "node:child_process";
66622
66692
  import {
66623
66693
  chmodSync,
66624
66694
  existsSync as existsSync15,
66625
- lstatSync as lstatSync4,
66695
+ lstatSync as lstatSync5,
66626
66696
  mkdirSync as mkdirSync5,
66627
66697
  readFileSync as readFileSync15,
66628
66698
  renameSync as renameSync3,
@@ -66833,7 +66903,7 @@ exit 0
66833
66903
  }
66834
66904
  }, exists = (file) => {
66835
66905
  try {
66836
- lstatSync4(file);
66906
+ lstatSync5(file);
66837
66907
  return true;
66838
66908
  } catch {
66839
66909
  return false;
@@ -67667,7 +67737,7 @@ import { spawnSync as spawnSync16 } from "node:child_process";
67667
67737
  import { createHash as createHash14 } from "node:crypto";
67668
67738
  import {
67669
67739
  existsSync as existsSync17,
67670
- lstatSync as lstatSync5,
67740
+ lstatSync as lstatSync6,
67671
67741
  mkdirSync as mkdirSync8,
67672
67742
  mkdtempSync,
67673
67743
  readdirSync as readdirSync10,
@@ -68145,7 +68215,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
68145
68215
  const want = stampCodexAgent(readFileSync18(path39.join(source, file), "utf8"), version);
68146
68216
  let link = false;
68147
68217
  try {
68148
- link = lstatSync5(dest).isSymbolicLink();
68218
+ link = lstatSync6(dest).isSymbolicLink();
68149
68219
  } catch {
68150
68220
  link = false;
68151
68221
  }
@@ -68872,7 +68942,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
68872
68942
  detail: "cursor plugin not inspected on this host"
68873
68943
  };
68874
68944
  }
68875
- if (existsSync17(res.cursorPluginDir) && lstatSync5(res.cursorPluginDir).isSymbolicLink()) {
68945
+ if (existsSync17(res.cursorPluginDir) && lstatSync6(res.cursorPluginDir).isSymbolicLink()) {
68876
68946
  let target = "";
68877
68947
  try {
68878
68948
  target = readlinkSync2(res.cursorPluginDir);
@@ -70086,7 +70156,7 @@ import {
70086
70156
  copyFileSync as copyFileSync5,
70087
70157
  cpSync as cpSync4,
70088
70158
  existsSync as existsSync18,
70089
- lstatSync as lstatSync6,
70159
+ lstatSync as lstatSync7,
70090
70160
  mkdirSync as mkdirSync9,
70091
70161
  mkdtempSync as mkdtempSync2,
70092
70162
  readFileSync as readFileSync19,
@@ -70539,7 +70609,7 @@ function applyOpenCode(root, res) {
70539
70609
  function copyPluginDir(src, dest) {
70540
70610
  const realSrc = realpathSync9(src);
70541
70611
  const marker = path40.join(dest, ".workit-root");
70542
- const destIsLink = existsSync18(dest) && lstatSync6(dest).isSymbolicLink();
70612
+ const destIsLink = existsSync18(dest) && lstatSync7(dest).isSymbolicLink();
70543
70613
  const synced = !destIsLink && readFileSafe(marker)?.trim() === realSrc && samePluginContent(realSrc, dest, dest);
70544
70614
  if (synced)
70545
70615
  return "Skipped";
@@ -70566,7 +70636,7 @@ function copyPluginDir(src, dest) {
70566
70636
  `, "utf8");
70567
70637
  if (!samePluginContent(realSrc, stage, dest))
70568
70638
  throw new Error("staged adapter content is incomplete");
70569
- if (lstatSync6(stage).isSymbolicLink()) {
70639
+ if (lstatSync7(stage).isSymbolicLink()) {
70570
70640
  throw new Error("staged adapter resolved to a symlink — refusing fragile cache install");
70571
70641
  }
70572
70642
  if (hadDir)
@@ -75660,7 +75730,7 @@ var init_apply = __esm(() => {
75660
75730
  });
75661
75731
 
75662
75732
  // packages/workit-cli/src/upgrade/plan.ts
75663
- import { existsSync as existsSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync8, lstatSync as lstatSync7, readFileSync as readFileSync23 } from "node:fs";
75733
+ import { existsSync as existsSync23, mkdtempSync as mkdtempSync3, rmSync as rmSync8, lstatSync as lstatSync8, readFileSync as readFileSync23 } from "node:fs";
75664
75734
  import path47 from "node:path";
75665
75735
  import os17 from "node:os";
75666
75736
  function previewUpgrade(hosts = HOSTS2, deps = {}) {
@@ -75970,7 +76040,7 @@ var codexRegistered = (configFile) => {
75970
76040
  }
75971
76041
  const packageFile = path47.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
75972
76042
  const installed = objectOrNull(packageFile);
75973
- if (installed?.name !== "@brainervirus/workit-cli" || lstatSync7(path47.dirname(packageFile)).isSymbolicLink()) {
76043
+ if (installed?.name !== "@brainervirus/workit-cli" || lstatSync8(path47.dirname(packageFile)).isSymbolicLink()) {
75974
76044
  plan.skipped.push({
75975
76045
  host: "cli",
75976
76046
  reason: "no managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
@@ -106949,7 +107019,7 @@ var init_audit = __esm(() => {
106949
107019
  import { spawn as spawn2 } from "node:child_process";
106950
107020
  import {
106951
107021
  existsSync as existsSync29,
106952
- lstatSync as lstatSync8,
107022
+ lstatSync as lstatSync9,
106953
107023
  mkdirSync as mkdirSync12,
106954
107024
  mkdtempSync as mkdtempSync4,
106955
107025
  readdirSync as readdirSync15,
@@ -107059,7 +107129,7 @@ function removeStaleCopies(tmp = os23.tmpdir()) {
107059
107129
  continue;
107060
107130
  const dir = path72.join(tmp, name);
107061
107131
  try {
107062
- const stat = lstatSync8(dir);
107132
+ const stat = lstatSync9(dir);
107063
107133
  if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
107064
107134
  continue;
107065
107135
  const pid = Number(readFileSync30(path72.join(dir, PID_FILE), "utf8"));
@@ -107125,7 +107195,7 @@ function copySymlink(repo, tree, from, to) {
107125
107195
  function writeInside(copy, file, content) {
107126
107196
  const target = path72.join(copy, file);
107127
107197
  try {
107128
- const stat = lstatSync8(target);
107198
+ const stat = lstatSync9(target);
107129
107199
  if (!stat.isFile() || !inside5(realpathSync11(copy), realpathSync11(path72.dirname(target))))
107130
107200
  return false;
107131
107201
  } catch {
@@ -107159,7 +107229,7 @@ function copyWorkingTree(repo) {
107159
107229
  const from = path72.join(repo, relative);
107160
107230
  let stat;
107161
107231
  try {
107162
- stat = lstatSync8(from);
107232
+ stat = lstatSync9(from);
107163
107233
  } catch {
107164
107234
  continue;
107165
107235
  }
@@ -107956,10 +108026,28 @@ var init_handoff = __esm(() => {
107956
108026
  init_output();
107957
108027
  });
107958
108028
 
108029
+ // packages/workit-cli/src/main.ts
108030
+ import path77 from "node:path";
108031
+
108032
+ // packages/workit-core/src/git/env-redirect.ts
108033
+ var GIT_REDIRECT_ENV = [
108034
+ "GIT_DIR",
108035
+ "GIT_WORK_TREE",
108036
+ "GIT_COMMON_DIR",
108037
+ "GIT_INDEX_FILE",
108038
+ "GIT_OBJECT_DIRECTORY",
108039
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
108040
+ "GIT_NAMESPACE"
108041
+ ];
108042
+ var gitRedirectsIn = (...envs) => GIT_REDIRECT_ENV.filter((name) => envs.some((env) => env[name] !== undefined));
108043
+ var gitRedirectRefusal = (names, verb, cwd) => ({
108044
+ error: `git_env_redirect: ${names.join(", ")} ${names.length === 1 ? "is" : "are"} set, so git would act on the repository ${names.length === 1 ? "it names" : "they name"} while grants are checked for ${cwd}; workit ${verb} does not run`,
108045
+ unblock: `unset ${names.join(" ")}, or cd into the repository and run workit ${verb} there`
108046
+ });
108047
+
107959
108048
  // packages/workit-cli/src/main.ts
107960
108049
  init_host_session();
107961
108050
  init_package();
107962
- import path77 from "node:path";
107963
108051
 
107964
108052
  // packages/workit-cli/src/verbs/registry.ts
107965
108053
  var TASK_FAMILY_NAMES = [
@@ -108942,6 +109030,14 @@ async function main(argv, overrides = {}, options = {}) {
108942
109030
  const checked = checkFlags(entry, ended);
108943
109031
  if ("error" in checked)
108944
109032
  return emit(routed, fail2("invalid_input", checked.error, { unblock: checked.unblock }));
109033
+ const gated = gatedVerb(entry, checked.args);
109034
+ if (gated) {
109035
+ const redirects = gitRedirectsIn(routed.env, process.env);
109036
+ if (redirects.length) {
109037
+ const refusal = gitRedirectRefusal(redirects, gated, routed.cwd);
109038
+ return emit(routed, fail2("blocked", refusal.error, { unblock: refusal.unblock }));
109039
+ }
109040
+ }
108945
109041
  if (parsed.cwd !== null) {
108946
109042
  try {
108947
109043
  process.chdir(routed.cwd);
@@ -108967,6 +109063,19 @@ async function main(argv, overrides = {}, options = {}) {
108967
109063
  const outcome = verbWord ? OUTCOMES2[`${entry.name} ${verbWord}`] : undefined;
108968
109064
  return withFailureLine(io, command, route, outcome);
108969
109065
  }
109066
+ var GRANT_GATED = {
109067
+ git: new Set(["push"]),
109068
+ release: new Set(["start", "finish", "publish"]),
109069
+ pr: new Set(["create", "merge", "ready", "edit"]),
109070
+ stack: new Set(["sync", "restack", "land"]),
109071
+ ci: new Set(["rerun"])
109072
+ };
109073
+ var gatedVerb = (entry, args) => {
109074
+ const word = firstWord(args);
109075
+ const sub = word === undefined ? undefined : findSubcommand(entry, word);
109076
+ const name = sub?.name ?? word;
109077
+ return name !== undefined && GRANT_GATED[entry.name]?.has(name) ? `${entry.name} ${name}` : null;
109078
+ };
108970
109079
  var OUTCOMES2 = {
108971
109080
  "pr merge": "PR not merged",
108972
109081
  "pr create": "PR not created",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "8.40.6",
3
+ "version": "8.40.8",
4
4
  "private": false,
5
5
  "description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
6
6
  "keywords": [
@@ -38,13 +38,13 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@babel/parser": "7.29.9",
41
- "@brainervirus/workit-cursor": "^8.40.6",
41
+ "@brainervirus/workit-cursor": "^8.40.8",
42
42
  "@inkjs/ui": "2.0.0",
43
43
  "ink": "7.1.1",
44
44
  "react": "19.2.8"
45
45
  },
46
46
  "devDependencies": {
47
- "@brainervirus/workit-core": "^8.40.6"
47
+ "@brainervirus/workit-core": "^8.40.8"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=24"