@workit-dev/codex 0.0.0-stage → 1.0.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.
Files changed (55) hide show
  1. package/.codex-plugin/plugin.json +32 -0
  2. package/.mcp.json +9 -0
  3. package/README.md +29 -2
  4. package/agents/workit-implementer.toml +52 -0
  5. package/agents/workit-reviewer.toml +32 -0
  6. package/agents/workit-verifier.toml +38 -0
  7. package/bin/launch-mcp.mjs +42 -0
  8. package/bin/node-resolve.mjs +249 -0
  9. package/bin/workit-paths.mjs +242 -0
  10. package/dist/launch-mcp.js +31422 -0
  11. package/dist/workit-hook-2hj7pbaj.js +23598 -0
  12. package/dist/workit-hook-3g6cv3hd.js +10 -0
  13. package/dist/workit-hook-3qaf6adn.js +10 -0
  14. package/dist/workit-hook-6n3h8wh7.js +104 -0
  15. package/dist/workit-hook-am9gge2k.js +583 -0
  16. package/dist/workit-hook-avy6vsn6.js +88 -0
  17. package/dist/workit-hook-b8nrcfzr.js +151 -0
  18. package/dist/workit-hook-ehy7rps6.js +200 -0
  19. package/dist/workit-hook-jy7y0gdx.js +70 -0
  20. package/dist/workit-hook-mk64s4fk.js +19 -0
  21. package/dist/workit-hook-y0ga088a.js +9 -0
  22. package/dist/workit-hook-zyzsv436.js +43 -0
  23. package/dist/workit-hook.js +94 -0
  24. package/hooks/hooks.json +46 -0
  25. package/package.json +48 -4
  26. package/skills/workit-architecture/SKILL.md +72 -0
  27. package/skills/workit-architecture/agents/openai.yaml +3 -0
  28. package/skills/workit-architecture/references/instruction-files.md +52 -0
  29. package/skills/workit-architecture/references/vocabulary.md +53 -0
  30. package/skills/workit-bdd/SKILL.md +53 -0
  31. package/skills/workit-continue/SKILL.md +54 -0
  32. package/skills/workit-debug/SKILL.md +45 -0
  33. package/skills/workit-deslop/SKILL.md +58 -0
  34. package/skills/workit-fanout/SKILL.md +71 -0
  35. package/skills/workit-fanout/references/brief.md +141 -0
  36. package/skills/workit-fanout/references/orchestration.md +169 -0
  37. package/skills/workit-implement/SKILL.md +71 -0
  38. package/skills/workit-retro/SKILL.md +72 -0
  39. package/skills/workit-retro/agents/openai.yaml +3 -0
  40. package/skills/workit-retro/references/sources.md +35 -0
  41. package/skills/workit-retro/references/steering.md +39 -0
  42. package/skills/workit-review/SKILL.md +66 -0
  43. package/skills/workit-review/references/impact.md +24 -0
  44. package/skills/workit-shape/SKILL.md +71 -0
  45. package/skills/workit-shape/references/diagrams.md +17 -0
  46. package/skills/workit-shape/references/knowledge.md +61 -0
  47. package/skills/workit-shape/references/mockups.md +15 -0
  48. package/skills/workit-shape/references/slicing.md +44 -0
  49. package/skills/workit-ship/SKILL.md +71 -0
  50. package/skills/workit-ship/references/changelog.md +44 -0
  51. package/skills/workit-ship/references/pr-body.md +32 -0
  52. package/skills/workit-ship/references/release.md +39 -0
  53. package/skills/workit-test-audit/SKILL.md +54 -0
  54. package/skills/workit-verify-app/SKILL.md +68 -0
  55. package/skills/workit-verify-app/references/template.md +51 -0
@@ -0,0 +1,583 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ stateDir3
4
+ } from "./workit-hook-6n3h8wh7.js";
5
+
6
+ // packages/workit-core/src/core/heavy-words.ts
7
+ import fs3 from "node:fs";
8
+ import path3 from "node:path";
9
+
10
+ // packages/workit-core/src/check-config.ts
11
+ import { spawnSync as spawnSync2 } from "node:child_process";
12
+ import fs2 from "node:fs";
13
+ import path2 from "node:path";
14
+
15
+ // packages/workit-core/src/git/facts.ts
16
+ import { spawnSync } from "node:child_process";
17
+ import fs from "node:fs";
18
+ import path from "node:path";
19
+ var cache = new Map;
20
+ var revParse = (cwd, args) => {
21
+ const run = spawnSync("git", ["rev-parse", "--path-format=absolute", ...args], {
22
+ cwd,
23
+ encoding: "utf8",
24
+ timeout: 20000,
25
+ killSignal: "SIGKILL",
26
+ windowsHide: true
27
+ });
28
+ if (run.status !== 0)
29
+ return null;
30
+ const lines = (run.stdout ?? "").split(/\r?\n/u).filter(Boolean);
31
+ return lines.length === args.length ? lines : null;
32
+ };
33
+ var realOrNull = (file) => {
34
+ try {
35
+ return fs.realpathSync.native(file);
36
+ } catch {
37
+ return null;
38
+ }
39
+ };
40
+ var stillValid = (facts) => {
41
+ const gitDir = realOrNull(facts.gitDir);
42
+ if (!gitDir)
43
+ return false;
44
+ if (!facts.top)
45
+ return true;
46
+ const dotGit = path.join(facts.top, ".git");
47
+ let target = null;
48
+ try {
49
+ if (fs.statSync(dotGit).isDirectory())
50
+ target = dotGit;
51
+ else {
52
+ const match = /^gitdir:\s*(.+?)\s*$/mu.exec(fs.readFileSync(dotGit, "utf8"));
53
+ target = match ? path.resolve(facts.top, match[1]) : null;
54
+ }
55
+ } catch {
56
+ return false;
57
+ }
58
+ return target !== null && realOrNull(target) === gitDir;
59
+ };
60
+ function gitDirs(cwd) {
61
+ const key = path.resolve(cwd);
62
+ const hit = cache.get(key);
63
+ if (hit && stillValid(hit))
64
+ return hit;
65
+ cache.delete(key);
66
+ const full = revParse(key, ["--git-dir", "--git-common-dir", "--show-toplevel"]);
67
+ const dirs = full ?? revParse(key, ["--git-dir", "--git-common-dir"]);
68
+ if (!dirs)
69
+ return null;
70
+ const facts = { gitDir: dirs[0], commonDir: dirs[1], top: dirs[2] ?? null };
71
+ cache.set(key, facts);
72
+ return facts;
73
+ }
74
+ var callReads = null;
75
+ function withinCall(fn) {
76
+ if (callReads)
77
+ return fn();
78
+ callReads = new Map;
79
+ try {
80
+ return fn();
81
+ } finally {
82
+ callReads = null;
83
+ }
84
+ }
85
+ function originUrl(cwd) {
86
+ const key = path.resolve(cwd);
87
+ if (callReads?.has(key))
88
+ return callReads.get(key) ?? null;
89
+ const run = spawnSync("git", ["remote", "get-url", "origin"], {
90
+ cwd,
91
+ encoding: "utf8",
92
+ timeout: 20000,
93
+ killSignal: "SIGKILL",
94
+ windowsHide: true
95
+ });
96
+ const url = run.status === 0 ? (run.stdout ?? "").trim() || null : null;
97
+ callReads?.set(key, url);
98
+ return url;
99
+ }
100
+
101
+ // packages/workit-core/src/check-config.ts
102
+ var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
103
+ var SCRIPT_CHECK_ALIASES = { packaging: "test:packaging" };
104
+ var CHECKS_FILE = ".workit/checks.json";
105
+ var LEGACY_CHECKS_FILE = "workit.checks.json";
106
+ function checksConfigFile(root) {
107
+ const current = path2.join(root, CHECKS_FILE);
108
+ const legacy = path2.join(root, LEGACY_CHECKS_FILE);
109
+ return !fs2.existsSync(current) && fs2.existsSync(legacy) ? legacy : current;
110
+ }
111
+ var GENERATED_GITIGNORES = new Set([`*
112
+ `, `*
113
+ !risk-paths
114
+ `]);
115
+ function repoHeavyCommands(root) {
116
+ try {
117
+ const value = JSON.parse(fs2.readFileSync(checksConfigFile(root), "utf8"));
118
+ const resources = isRecord(value) ? value.resources : undefined;
119
+ const list = isRecord(resources) ? resources.heavyCommands : undefined;
120
+ return Array.isArray(list) ? list.filter((item) => typeof item === "string") : [];
121
+ } catch {
122
+ return [];
123
+ }
124
+ }
125
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
126
+ var SHELL_META = /[|&;<>()$`\\*?[\]{}~!#]/u;
127
+ function splitCommand(command) {
128
+ const argv = [];
129
+ let current = "";
130
+ let quote = null;
131
+ let started = false;
132
+ for (const char of command) {
133
+ if (quote) {
134
+ if (char === quote)
135
+ quote = null;
136
+ else
137
+ current += char;
138
+ continue;
139
+ }
140
+ if (char === '"' || char === "'") {
141
+ quote = char;
142
+ started = true;
143
+ continue;
144
+ }
145
+ if (/\s/u.test(char)) {
146
+ if (started)
147
+ argv.push(current);
148
+ current = "";
149
+ started = false;
150
+ continue;
151
+ }
152
+ if (SHELL_META.test(char))
153
+ return new Error(`"${command}" uses shell syntax (${char}); configure an argv array instead`);
154
+ current += char;
155
+ started = true;
156
+ }
157
+ if (quote)
158
+ return new Error(`"${command}" has an unterminated quote`);
159
+ if (started)
160
+ argv.push(current);
161
+ return argv.length ? argv : new Error("empty command");
162
+ }
163
+ var git = (cwd, args) => {
164
+ const run = spawnSync2("git", args, {
165
+ cwd,
166
+ encoding: "utf8",
167
+ timeout: 20000,
168
+ killSignal: "SIGKILL",
169
+ windowsHide: true
170
+ });
171
+ const value = run.status === 0 ? (run.stdout ?? "").trim() : "";
172
+ return value || null;
173
+ };
174
+ function checkRoot(cwd) {
175
+ return path2.resolve(gitDirs(cwd)?.top ?? cwd);
176
+ }
177
+ var packageManager = (root) => {
178
+ const has = (file) => fs2.existsSync(path2.join(root, file));
179
+ if (has("bun.lock") || has("bun.lockb"))
180
+ return "bun";
181
+ if (has("pnpm-lock.yaml"))
182
+ return "pnpm";
183
+ if (has("yarn.lock"))
184
+ return "yarn";
185
+ return "npm";
186
+ };
187
+ var scriptCheck = (pm, name) => {
188
+ const argv = [pm, "run", name];
189
+ const accepts = [argv];
190
+ if (pm === "pnpm" || pm === "yarn" || pm === "npm" && name === "test")
191
+ accepts.push([pm, name]);
192
+ return { name, argv, accepts };
193
+ };
194
+ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
195
+ function detectedChecks(root) {
196
+ const read = (file) => {
197
+ try {
198
+ return fs2.readFileSync(path2.join(root, file), "utf8");
199
+ } catch {
200
+ return null;
201
+ }
202
+ };
203
+ const checks = [];
204
+ const add = (check) => {
205
+ if (!checks.some((item) => item.name === check.name))
206
+ checks.push(check);
207
+ };
208
+ const manifestText = read("package.json");
209
+ if (manifestText !== null) {
210
+ let manifest = null;
211
+ try {
212
+ manifest = JSON.parse(manifestText);
213
+ } catch {}
214
+ const scripts = isRecord(manifest) && isRecord(manifest.scripts) ? manifest.scripts : {};
215
+ const pm = packageManager(root);
216
+ for (const name of SCRIPT_CHECKS) {
217
+ const script = scripts[name];
218
+ if (typeof script === "string" && script.trim() !== "")
219
+ add(scriptCheck(pm, name));
220
+ }
221
+ for (const [name, script] of Object.entries(SCRIPT_CHECK_ALIASES)) {
222
+ const body = scripts[script];
223
+ if (typeof body === "string" && body.trim() !== "")
224
+ add({ ...scriptCheck(pm, script), name });
225
+ }
226
+ }
227
+ const plain = (name, argv) => ({ name, argv, accepts: [argv] });
228
+ if (read("go.mod") !== null)
229
+ add(plain("test", ["go", "test", "./..."]));
230
+ if (read("Cargo.toml") !== null)
231
+ add(plain("test", ["cargo", "test"]));
232
+ if (read("pytest.ini") !== null || /\bpytest\b/u.test(read("pyproject.toml") ?? ""))
233
+ add(plain("test", ["pytest"]));
234
+ const makefile = read("Makefile") ?? read("makefile") ?? read("GNUmakefile");
235
+ if (makefile !== null && /^test\s*:(?!=)/mu.test(makefile))
236
+ add(plain("test", ["make", "test"]));
237
+ return checks;
238
+ }
239
+ var GATES = ["testing", "verification"];
240
+ var UNSUPPORTED_GLOB = /[?[\]{}!\\]|[@+*]\(/u;
241
+ var REGENERABLE_SHAPE = 'cleanup.regenerable must be a list of repo-relative globs (["packages/*/skills"])';
242
+ function cleanupGlobs(value) {
243
+ if (value === undefined)
244
+ return [];
245
+ if (!isRecord(value))
246
+ return new Error('cleanup must be {"regenerable":["<glob>",…]}');
247
+ const unknown = Object.keys(value).find((key) => key !== "regenerable");
248
+ if (unknown)
249
+ return new Error(`cleanup.${unknown} is not a setting (use cleanup.regenerable)`);
250
+ const list = value.regenerable ?? [];
251
+ if (!Array.isArray(list))
252
+ return new Error(REGENERABLE_SHAPE);
253
+ const globs = [];
254
+ for (const item of list) {
255
+ if (typeof item !== "string")
256
+ return new Error(REGENERABLE_SHAPE);
257
+ const glob = item.trim().replace(/\/+$/u, "");
258
+ if (!glob || glob.startsWith("/") || glob.split("/").includes(".."))
259
+ return new Error(`${REGENERABLE_SHAPE}; "${item}" is not repo-relative`);
260
+ if (UNSUPPORTED_GLOB.test(glob))
261
+ return new Error(`${REGENERABLE_SHAPE}; "${item}" uses syntax beyond * and **`);
262
+ if (/^\*+$/u.test(glob.split("/").at(-1) ?? ""))
263
+ return new Error(`${REGENERABLE_SHAPE}; "${item}" ends in a bare wildcard, which would discard ignored files such as .env: name the generated dir`);
264
+ globs.push(glob);
265
+ }
266
+ return globs;
267
+ }
268
+ function configFileFor(root) {
269
+ const own = checksConfigFile(root);
270
+ if (fs2.existsSync(own))
271
+ return own;
272
+ const common = git(root, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
273
+ if (!common || path2.basename(common) !== ".git")
274
+ return own;
275
+ const main = path2.dirname(common);
276
+ if (path2.resolve(main) === path2.resolve(root))
277
+ return own;
278
+ const shared = checksConfigFile(main);
279
+ return fs2.existsSync(shared) ? shared : own;
280
+ }
281
+ function loadCheckConfig(cwd) {
282
+ const root = checkRoot(cwd);
283
+ const file = configFileFor(root);
284
+ const legacy = path2.basename(file) === LEGACY_CHECKS_FILE;
285
+ const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
286
+ const note = legacy ? {
287
+ note: `${LEGACY_CHECKS_FILE} is deprecated; move it to ${CHECKS_FILE} (workit doctor --fix)`
288
+ } : {};
289
+ const none = (error = null) => ({
290
+ source: error ? label : "none",
291
+ root,
292
+ checks: [],
293
+ gates: {},
294
+ groups: {},
295
+ error,
296
+ ...note
297
+ });
298
+ let text = null;
299
+ try {
300
+ text = fs2.readFileSync(file, "utf8");
301
+ } catch (error) {
302
+ if (error.code !== "ENOENT")
303
+ return none(`cannot read ${label}: ${error.message}`);
304
+ }
305
+ if (text === null) {
306
+ const checks = detectedChecks(root);
307
+ return checks.length ? { source: "defaults", root, checks, gates: {}, groups: {}, error: null } : none();
308
+ }
309
+ let parsed;
310
+ try {
311
+ parsed = JSON.parse(text);
312
+ } catch {
313
+ return none(`${label} is not valid JSON`);
314
+ }
315
+ if (!isRecord(parsed) || !isRecord(parsed.checks))
316
+ return none(`${label} must be {"checks":{"<name>":"<command>"|["argv",…]}}`);
317
+ const checks = [];
318
+ for (const [name, value] of Object.entries(parsed.checks)) {
319
+ if (!CHECK_NAME.test(name))
320
+ return none(`${label}: check name "${name}" must match ${CHECK_NAME.source}`);
321
+ 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");
322
+ if (argv instanceof Error)
323
+ return none(`${label}: check "${name}": ${argv.message}`);
324
+ checks.push({ name, argv, accepts: [argv] });
325
+ }
326
+ const gates = {};
327
+ if (parsed.gates !== undefined) {
328
+ if (!isRecord(parsed.gates))
329
+ return none(`${label}: gates must be {"testing":"<name>"|["<name>",…]}`);
330
+ for (const [gate, value] of Object.entries(parsed.gates)) {
331
+ if (!GATES.includes(gate))
332
+ return none(`${label}: unknown gate "${gate}" (use ${GATES.join(" or ")})`);
333
+ const names = typeof value === "string" ? [value] : value;
334
+ if (!Array.isArray(names) || names.length === 0 || !names.every((name) => typeof name === "string" && checks.some((c) => c.name === name)))
335
+ return none(`${label}: gates.${gate} must name configured checks`);
336
+ gates[gate] = names;
337
+ }
338
+ }
339
+ const groups = {};
340
+ if (parsed.groups !== undefined) {
341
+ if (!isRecord(parsed.groups))
342
+ return none(`${label}: groups must be {"ci":["<name>",…]}`);
343
+ for (const [group, value] of Object.entries(parsed.groups)) {
344
+ if (!CHECK_NAME.test(group))
345
+ return none(`${label}: group name "${group}" must match ${CHECK_NAME.source}`);
346
+ if (checks.some((c) => c.name === group))
347
+ return none(`${label}: group "${group}" has the name of a configured check`);
348
+ if (!Array.isArray(value) || value.length === 0 || !value.every((name) => typeof name === "string" && checks.some((c) => c.name === name)))
349
+ return none(`${label}: groups.${group} must be a non-empty list of configured checks`);
350
+ groups[group] = [...new Set(value)];
351
+ }
352
+ }
353
+ const regenerable = cleanupGlobs(parsed.cleanup);
354
+ if (regenerable instanceof Error)
355
+ return none(`${label}: ${regenerable.message}`);
356
+ return {
357
+ source: label,
358
+ root,
359
+ checks,
360
+ gates,
361
+ groups,
362
+ error: null,
363
+ ...note,
364
+ resources: parsed.resources,
365
+ regenerable
366
+ };
367
+ }
368
+ var sameArgv = (left, right) => left.length === right.length && left.every((item, index) => item === right[index]);
369
+ function matchesNamedCheck(config, name, argv, cwd) {
370
+ if (config.error || name === null || cwd !== ".")
371
+ return false;
372
+ const check = config.checks.find((item) => item.name === name);
373
+ return Boolean(check?.accepts.some((accepted) => sameArgv(accepted, argv)));
374
+ }
375
+ function gateCheckNames(config, dimension) {
376
+ const explicit = config.gates[dimension];
377
+ if (explicit)
378
+ return explicit;
379
+ const names = config.checks.map((check) => check.name);
380
+ if (dimension === "testing")
381
+ return names.includes("test") ? ["test"] : [];
382
+ return names;
383
+ }
384
+ var workitOnPath;
385
+ function workitAvailable(env = process.env) {
386
+ if (workitOnPath !== undefined)
387
+ return workitOnPath;
388
+ const windows = process.platform === "win32";
389
+ const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
390
+ const dirs = (env.PATH ?? env.Path ?? "").split(path2.delimiter).filter(Boolean);
391
+ workitOnPath = dirs.some((dir) => exts.some((ext) => {
392
+ try {
393
+ return fs2.statSync(path2.join(dir, `workit${ext}`)).isFile();
394
+ } catch {
395
+ return false;
396
+ }
397
+ }));
398
+ return workitOnPath;
399
+ }
400
+ function checkCommand(args, version, onPath = workitAvailable()) {
401
+ return onPath ? `workit check ${args}` : `npx -y @workit-dev/cli@${version} check ${args}`;
402
+ }
403
+ var only = (...names) => new Set(names);
404
+ var FORMATTERS = {
405
+ oxfmt: "any",
406
+ prettier: "any",
407
+ dprint: only("fmt", "check"),
408
+ biome: only("format"),
409
+ black: "any",
410
+ isort: "any",
411
+ yapf: "any",
412
+ autopep8: "any",
413
+ ruff: only("format"),
414
+ gofmt: "any",
415
+ goimports: "any",
416
+ rustfmt: "any",
417
+ "clang-format": "any",
418
+ shfmt: "any",
419
+ stylua: "any",
420
+ taplo: only("fmt", "format"),
421
+ cargo: only("fmt"),
422
+ go: only("fmt"),
423
+ deno: only("fmt"),
424
+ mix: only("format"),
425
+ terraform: only("fmt"),
426
+ zig: only("fmt")
427
+ };
428
+ var FILE_LINTERS = {
429
+ eslint: "any",
430
+ oxlint: "any",
431
+ stylelint: "any",
432
+ tslint: "any",
433
+ biome: only("lint", "check"),
434
+ ruff: only("check"),
435
+ deno: only("lint"),
436
+ flake8: "any",
437
+ pylint: "any",
438
+ shellcheck: "any",
439
+ markdownlint: "any",
440
+ "markdownlint-cli2": "any",
441
+ hadolint: "any",
442
+ yamllint: "any",
443
+ actionlint: "any",
444
+ rubocop: "any"
445
+ };
446
+ var FORMAT_SCRIPT = /^(?:format|fmt|prettier)(?:$|[:_.-])/iu;
447
+ var RUNNERS = new Set(["npx", "bunx", "pnpx"]);
448
+ var PACKAGE_MANAGERS = new Set(["npm", "pnpm", "yarn", "bun"]);
449
+ var PM_EXEC = new Set(["exec", "x", "dlx"]);
450
+ var PM_RUN = new Set(["run", "run-script"]);
451
+ var PYTHON_RUNNERS = new Set(["uv", "poetry", "pipenv", "pdm", "hatch", "rye"]);
452
+ var toolName = (word) => (word?.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat|ps1)$/u, "");
453
+ var firstPositional = (words, from) => {
454
+ let index = from;
455
+ while (index < words.length && words[index].startsWith("-")) {
456
+ if (words[index] === "--")
457
+ return index + 1;
458
+ index += 1;
459
+ }
460
+ return index;
461
+ };
462
+ function fileTarget(word, cwd) {
463
+ if (/[*?[\]{}]/u.test(word) || word.endsWith("/") || word.endsWith(path2.sep))
464
+ return false;
465
+ if (!/\.[A-Za-z0-9]+$/u.test(path2.basename(word)))
466
+ return false;
467
+ if (!cwd)
468
+ return true;
469
+ try {
470
+ return !fs2.statSync(path2.resolve(cwd, word)).isDirectory();
471
+ } catch {
472
+ return true;
473
+ }
474
+ }
475
+ var subcommandOf = (rule, words) => {
476
+ if (rule === "any")
477
+ return null;
478
+ const at = firstPositional(words, 1);
479
+ return rule.has(words[at] ?? "") ? words[at] : undefined;
480
+ };
481
+ function classify(words, cwd, depth) {
482
+ if (depth > 4 || !words.length)
483
+ return null;
484
+ const name = toolName(words[0]);
485
+ const inner = (from) => classify(words.slice(from), cwd, depth + 1);
486
+ if (RUNNERS.has(name))
487
+ return inner(firstPositional(words, 1));
488
+ if (PYTHON_RUNNERS.has(name) && words[firstPositional(words, 1)] === "run")
489
+ return inner(firstPositional(words, firstPositional(words, 1) + 1));
490
+ if (/^python[\d.]*$/u.test(name)) {
491
+ const at = words.indexOf("-m");
492
+ return at > 0 ? inner(at + 1) : null;
493
+ }
494
+ if (PACKAGE_MANAGERS.has(name)) {
495
+ const at = firstPositional(words, 1);
496
+ const command = words[at] ?? "";
497
+ if (PM_EXEC.has(command))
498
+ return inner(firstPositional(words, at + 1));
499
+ const script = PM_RUN.has(command) ? words[firstPositional(words, at + 1)] : command;
500
+ if (script && FORMAT_SCRIPT.test(script))
501
+ return {
502
+ kind: "formatter",
503
+ tool: `${name} ${script}`,
504
+ reason: `\`${name} ${PM_RUN.has(command) ? `${command} ` : ""}${script}\` only formats`
505
+ };
506
+ return name === "npm" || PM_RUN.has(command) ? null : inner(at);
507
+ }
508
+ const formatter = FORMATTERS[name];
509
+ if (formatter) {
510
+ const sub = subcommandOf(formatter, words);
511
+ if (sub !== undefined) {
512
+ const tool = sub ? `${name} ${sub}` : name;
513
+ return { kind: "formatter", tool, reason: `${tool} is a formatter` };
514
+ }
515
+ }
516
+ const linter = FILE_LINTERS[name];
517
+ if (!linter)
518
+ return null;
519
+ const sub = subcommandOf(linter, words);
520
+ if (sub === undefined)
521
+ return null;
522
+ const targets = words.slice(sub ? words.indexOf(sub) + 1 : 1).filter((word) => !word.startsWith("-") && !/^\d+$/u.test(word));
523
+ if (!targets.length || !targets.every((word) => fileTarget(word, cwd)))
524
+ return null;
525
+ const tool = sub ? `${name} ${sub}` : name;
526
+ return {
527
+ kind: "file-lint",
528
+ tool,
529
+ reason: `${tool} lints ${targets.length} named file${targets.length === 1 ? "" : "s"}`
530
+ };
531
+ }
532
+ function lightCommand(argv, cwd) {
533
+ return classify(argv, cwd, 0);
534
+ }
535
+
536
+ // packages/workit-core/src/core/heavy-words.ts
537
+ var HEAVY_WORDS = new Set(("npm npx pnpm pnpx yarn bun bunx deno corepack make gmake docker podman nerdctl " + "python python3 py uv poetry pdm pipenv hatch rye bundle rake nx " + "jest vitest mocha ava tap karma jasmine nyc c8 tsc vue-tsc svelte-check eslint stylelint " + "tslint webpack webpack-cli rollup parcel tsup vite next nuxt nuxi astro ng react-scripts " + "playwright cypress wdio testcafe turbo lerna sonar-scanner sonarless sonarless-mcp go " + "golangci-lint gotestsum staticcheck cargo mvn mvnw gradle gradlew ant sbt bazel bazelisk " + "buck2 dotnet msbuild pytest py.test tox nox mypy pyright pylint coverage maturin pip pip3 " + "rspec rails phpunit pest phpstan psalm composer mix swift xcodebuild flutter dart pod cmake " + "ninja meson ctest scons docker-compose buildah earthly").split(" "));
538
+ var wordsOf = (command) => command.split(/[\s;&|()<>`'"]+/u).map((word) => (word.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat)$/u, "")).filter(Boolean);
539
+ var stateDir2 = (env) => stateDir3(env);
540
+ var readJson = (file) => {
541
+ try {
542
+ return JSON.parse(fs3.readFileSync(file, "utf8"));
543
+ } catch {
544
+ return;
545
+ }
546
+ };
547
+ var patternWords = (cwd, env) => {
548
+ const patterns = [];
549
+ const machine = readJson(path3.join(stateDir2(env), "heavy-commands.json"));
550
+ if (Array.isArray(machine?.patterns))
551
+ patterns.push(...machine.patterns);
552
+ for (let dir = path3.resolve(cwd);; dir = path3.dirname(dir)) {
553
+ if (fs3.existsSync(path3.join(dir, ".git"))) {
554
+ patterns.push(...repoHeavyCommands(dir));
555
+ break;
556
+ }
557
+ if (path3.dirname(dir) === dir)
558
+ break;
559
+ }
560
+ const words = new Set;
561
+ for (const pattern of patterns) {
562
+ if (typeof pattern !== "string")
563
+ continue;
564
+ const first = wordsOf(pattern)[0];
565
+ if (!first || first.includes("*"))
566
+ return null;
567
+ words.add(first);
568
+ }
569
+ return words;
570
+ };
571
+ function maybeHeavy2(command, cwd, env = process.env) {
572
+ try {
573
+ const words = wordsOf(command);
574
+ if (words.some((word) => HEAVY_WORDS.has(word) || /^python[\d.]*$/u.test(word)))
575
+ return true;
576
+ const extra = patternWords(cwd, env);
577
+ return extra === null || words.some((word) => extra.has(word));
578
+ } catch {
579
+ return true;
580
+ }
581
+ }
582
+
583
+ export { gitDirs, withinCall, originUrl, CHECKS_FILE, repoHeavyCommands, loadCheckConfig, matchesNamedCheck, gateCheckNames, checkCommand, lightCommand, stateDir2, maybeHeavy2 };
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ dataDir
4
+ } from "./workit-hook-6n3h8wh7.js";
5
+
6
+ // packages/workit-core/src/core/cli-locate.ts
7
+ import { closeSync, existsSync, openSync, readSync } from "node:fs";
8
+ import path from "node:path";
9
+ var LAUNCHER_MARKER = "workit-owned-launcher";
10
+ var CLI_PACKAGE_PATH = ["node_modules", "@workit-dev", "cli"];
11
+ var installRoot = (env, platform = process.platform) => {
12
+ if (env.WORKIT_INSTALL_ROOT)
13
+ return env.WORKIT_INSTALL_ROOT;
14
+ const data = dataDir(env, platform);
15
+ return platform === "win32" ? path.join(data, "install") : data;
16
+ };
17
+ var ownedLauncherPath = (env, platform = process.platform) => path.join(installRoot(env, platform), "bin", platform === "win32" ? "workit.cmd" : "workit");
18
+ var ownedCurrentEntry = (env, platform = process.platform) => path.join(installRoot(env, platform), "current", ...CLI_PACKAGE_PATH, "dist", "index.js");
19
+ var head = (file) => {
20
+ let fd;
21
+ try {
22
+ fd = openSync(file, "r");
23
+ const buffer = Buffer.alloc(256);
24
+ const read = readSync(fd, buffer, 0, buffer.length, 0);
25
+ return buffer.subarray(0, read).toString("utf8");
26
+ } catch {
27
+ return "";
28
+ } finally {
29
+ if (fd !== undefined)
30
+ closeSync(fd);
31
+ }
32
+ };
33
+ var locateWorkitCli = (options = {}) => {
34
+ const env = options.env ?? process.env;
35
+ const platform = options.platform ?? process.platform;
36
+ const exists = options.exists ?? existsSync;
37
+ const read = options.read ?? head;
38
+ const node = options.node ?? process.execPath;
39
+ const launcher = ownedLauncherPath(env, platform);
40
+ if (exists(launcher) && read(launcher).includes(LAUNCHER_MARKER))
41
+ return {
42
+ source: "owned-launcher",
43
+ command: launcher,
44
+ args: [],
45
+ binDir: path.dirname(launcher)
46
+ };
47
+ const current = ownedCurrentEntry(env, platform);
48
+ if (exists(current))
49
+ return {
50
+ source: "owned-current",
51
+ command: node,
52
+ args: [current],
53
+ binDir: null
54
+ };
55
+ if (options.bundled && exists(options.bundled))
56
+ return {
57
+ source: "bundled",
58
+ command: node,
59
+ args: [options.bundled],
60
+ binDir: null
61
+ };
62
+ return { source: "path", command: "workit", args: [], binDir: null };
63
+ };
64
+ var pathKey = (env) => Object.keys(env).find((key) => key.toUpperCase() === "PATH") ?? "PATH";
65
+ var workitCliEnv = (located, env = process.env, platform = process.platform) => {
66
+ if (located.source === "path")
67
+ return {};
68
+ const patch = {
69
+ WORKIT_CLI: [located.command, ...located.args].join(" ")
70
+ };
71
+ if (located.binDir) {
72
+ const key = pathKey(env);
73
+ const delimiter = platform === "win32" ? ";" : ":";
74
+ const same = (dir) => platform === "win32" ? path.win32.normalize(dir).toLowerCase() === path.win32.normalize(located.binDir).toLowerCase() : path.posix.normalize(dir) === path.posix.normalize(located.binDir);
75
+ const rest = (env[key] ?? "").split(delimiter).filter((dir) => dir && !same(dir));
76
+ patch[key] = [located.binDir, ...rest].join(delimiter);
77
+ }
78
+ return patch;
79
+ };
80
+ var useOwnedWorkitCli = (options = {}) => {
81
+ const env = options.env ?? process.env;
82
+ const located = locateWorkitCli({ ...options, env });
83
+ Object.assign(env, workitCliEnv(located, env, options.platform));
84
+ return located;
85
+ };
86
+ export {
87
+ useOwnedWorkitCli
88
+ };