safeword 0.26.1 → 0.27.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 (38) hide show
  1. package/dist/{check-6763ESQ6.js → check-OH44W34Z.js} +3 -3
  2. package/dist/{chunk-NINE7AWZ.js → chunk-5A745HPE.js} +35 -36
  3. package/dist/chunk-5A745HPE.js.map +1 -0
  4. package/dist/{chunk-3GIBXEUI.js → chunk-6ZRDSDK4.js} +28 -5
  5. package/dist/chunk-6ZRDSDK4.js.map +1 -0
  6. package/dist/{chunk-5IOM3XLW.js → chunk-FK24HNGM.js} +2 -2
  7. package/dist/{chunk-Q4VPBNNZ.js → chunk-PEKTMTDF.js} +15 -1
  8. package/dist/chunk-PEKTMTDF.js.map +1 -0
  9. package/dist/cli.js +5 -5
  10. package/dist/{diff-O6NACWXR.js → diff-ASICF664.js} +3 -3
  11. package/dist/index.js +2 -2
  12. package/dist/presets/typescript/index.d.ts +7 -2
  13. package/dist/presets/typescript/index.js +2 -2
  14. package/dist/{reset-P5QGTALW.js → reset-7BFS4OJL.js} +3 -3
  15. package/dist/{setup-TGFZXS4G.js → setup-PGZOUKHI.js} +6 -5
  16. package/dist/{setup-TGFZXS4G.js.map → setup-PGZOUKHI.js.map} +1 -1
  17. package/dist/{upgrade-WL6K6B6O.js → upgrade-Y7AVKJTN.js} +4 -4
  18. package/package.json +22 -20
  19. package/templates/commands/audit.md +4 -1
  20. package/templates/hooks/lib/active-ticket.ts +43 -2
  21. package/templates/hooks/lib/lint.ts +35 -7
  22. package/templates/hooks/lib/quality-state.ts +4 -0
  23. package/templates/hooks/post-tool-bypass-warn.ts +1 -0
  24. package/templates/hooks/post-tool-quality.ts +16 -2
  25. package/templates/hooks/pre-tool-quality.ts +31 -23
  26. package/templates/hooks/stop-quality.ts +67 -4
  27. package/templates/skills/audit/SKILL.md +280 -0
  28. package/templates/skills/cleanup-zombies/SKILL.md +50 -0
  29. package/templates/skills/lint/SKILL.md +55 -0
  30. package/templates/skills/verify/SKILL.md +115 -0
  31. package/dist/chunk-3GIBXEUI.js.map +0 -1
  32. package/dist/chunk-NINE7AWZ.js.map +0 -1
  33. package/dist/chunk-Q4VPBNNZ.js.map +0 -1
  34. /package/dist/{check-6763ESQ6.js.map → check-OH44W34Z.js.map} +0 -0
  35. /package/dist/{chunk-5IOM3XLW.js.map → chunk-FK24HNGM.js.map} +0 -0
  36. /package/dist/{diff-O6NACWXR.js.map → diff-ASICF664.js.map} +0 -0
  37. /package/dist/{reset-P5QGTALW.js.map → reset-7BFS4OJL.js.map} +0 -0
  38. /package/dist/{upgrade-WL6K6B6O.js.map → upgrade-Y7AVKJTN.js.map} +0 -0
@@ -6,8 +6,8 @@ import {
6
6
  createProjectContext,
7
7
  getMissingPacks,
8
8
  reconcile
9
- } from "./chunk-NINE7AWZ.js";
10
- import "./chunk-Q4VPBNNZ.js";
9
+ } from "./chunk-5A745HPE.js";
10
+ import "./chunk-PEKTMTDF.js";
11
11
  import {
12
12
  VERSION
13
13
  } from "./chunk-ORQHKDT2.js";
@@ -187,4 +187,4 @@ async function check(options) {
187
187
  export {
188
188
  check
189
189
  };
190
- //# sourceMappingURL=check-6763ESQ6.js.map
190
+ //# sourceMappingURL=check-OH44W34Z.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  detect
3
- } from "./chunk-Q4VPBNNZ.js";
3
+ } from "./chunk-PEKTMTDF.js";
4
4
  import {
5
5
  VERSION
6
6
  } from "./chunk-ORQHKDT2.js";
@@ -1279,8 +1279,7 @@ var pythonManagedFiles = {
1279
1279
  },
1280
1280
  // Project-level import-linter config (created only if layers detected and no existing config)
1281
1281
  ".importlinter": {
1282
- // Rule conflict: unicorn/no-useless-undefined removes explicit undefined, sonarjs/no-inconsistent-returns wants it
1283
- // eslint-disable-next-line sonarjs/no-inconsistent-returns
1282
+ // eslint-disable-next-line sonarjs/no-inconsistent-returns -- generator returns undefined to skip file
1284
1283
  generator: (ctx) => {
1285
1284
  if (!ctx.languages?.python) return;
1286
1285
  if (ctx.projectType.existingImportLinterConfig) return;
@@ -1358,7 +1357,7 @@ function parseClippyKeys(content) {
1358
1357
  const trimmed = line.trim();
1359
1358
  if (trimmed && !trimmed.startsWith("#")) {
1360
1359
  const match = /^([\w-]+)\s*=/.exec(trimmed);
1361
- if (match) keys.add(match[1]);
1360
+ if (match?.[1]) keys.add(match[1]);
1362
1361
  }
1363
1362
  }
1364
1363
  return keys;
@@ -1515,10 +1514,9 @@ function detectFromPythonDeps(cwd) {
1515
1514
  content = readFileSync4(pyprojectPath, "utf8");
1516
1515
  }
1517
1516
  if (!content) return void 0;
1518
- const matches = [...content.matchAll(/dbt-(\w+)/g)];
1519
- for (const match of matches) {
1520
- if (match[1] === "core") continue;
1521
- const dialect = ADAPTER_TO_DIALECT[match[1]];
1517
+ const adapters = [...content.matchAll(/dbt-(\w+)/g)].map((m) => m[1]).filter((a) => a !== void 0 && a !== "core");
1518
+ for (const adapter of adapters) {
1519
+ const dialect = ADAPTER_TO_DIALECT[adapter];
1522
1520
  if (dialect) return dialect;
1523
1521
  }
1524
1522
  return void 0;
@@ -1533,7 +1531,7 @@ function detectFromSqlcConfig(cwd) {
1533
1531
  try {
1534
1532
  const content = readFileSync4(nodePath9.join(directory, filename), "utf8");
1535
1533
  const match = /engine['":\s]+(\w+)/.exec(content);
1536
- if (match) return ADAPTER_TO_DIALECT[match[1]] ?? match[1];
1534
+ if (match?.[1]) return ADAPTER_TO_DIALECT[match[1]] ?? match[1];
1537
1535
  } catch {
1538
1536
  continue;
1539
1537
  }
@@ -1546,7 +1544,7 @@ function detectFromPrismaSchema(cwd) {
1546
1544
  try {
1547
1545
  const content = readFileSync4(schemaPath, "utf8");
1548
1546
  const match = /provider\s*=\s*"(\w+)"/.exec(content);
1549
- if (!match) return void 0;
1547
+ if (!match?.[1]) return void 0;
1550
1548
  return PROVIDER_TO_DIALECT[match[1]];
1551
1549
  } catch {
1552
1550
  return void 0;
@@ -1559,7 +1557,7 @@ function detectFromDrizzleConfig(cwd) {
1559
1557
  try {
1560
1558
  const content = readFileSync4(filePath, "utf8");
1561
1559
  const match = /dialect\s*:\s*["'](\w+)["']/.exec(content);
1562
- if (match) return DRIZZLE_TO_DIALECT[match[1]];
1560
+ if (match?.[1]) return DRIZZLE_TO_DIALECT[match[1]];
1563
1561
  } catch {
1564
1562
  continue;
1565
1563
  }
@@ -1572,7 +1570,7 @@ function detectFromDatabaseUrl(cwd) {
1572
1570
  try {
1573
1571
  const content = readFileSync4(envPath, "utf8");
1574
1572
  const match = /DATABASE_URL\s*=\s*["']?(\w+):/.exec(content);
1575
- if (!match) return void 0;
1573
+ if (!match?.[1]) return void 0;
1576
1574
  return SCHEME_TO_DIALECT[match[1]];
1577
1575
  } catch {
1578
1576
  return void 0;
@@ -1689,13 +1687,13 @@ const scopedNextConfigs = nextPaths?.flatMap((filePath) =>
1689
1687
  configs.nextOnlyRules.map((config) => ({ ...config, files: [filePath] }))
1690
1688
  ) ?? [];`;
1691
1689
  }
1692
- var OPTIONAL_CONFIGS_SNIPPET = ` // Testing configs - always included (file-scoped to *.test.* and *.e2e.*)
1693
- ...configs.vitest,
1694
- ...configs.playwright,
1695
- // Storybook - always included (file-scoped to *.stories.*)
1696
- ...configs.storybook,
1697
- // TanStack Query - always included (rules only match useQuery/useMutation patterns)
1698
- ...configs.tanstackQuery,
1690
+ var OPTIONAL_CONFIGS_SNIPPET = ` // Testing configs - only if detected (plugins have framework peer deps)
1691
+ ...(detect.hasVitest(deps) ? configs.vitest : []),
1692
+ ...(detect.hasPlaywright(deps) ? configs.playwright : []),
1693
+ // Storybook - only if detected (v10+ requires storybook peer dep)
1694
+ ...(detect.hasStorybook(deps) ? configs.storybook : []),
1695
+ // TanStack Query - only if detected (has typescript peer dep)
1696
+ ...(detect.hasTanstackQuery(deps) ? configs.tanstackQuery : []),
1699
1697
  // Tailwind - only if detected (plugin needs tailwind config to validate classes)
1700
1698
  ...(detect.hasTailwind(deps) ? configs.tailwind : []),
1701
1699
  // Turborepo - only if detected (validates env vars are declared in turbo.json)
@@ -2019,8 +2017,7 @@ var typescriptOwnedFiles = {
2019
2017
  ) : void 0
2020
2018
  },
2021
2019
  ".safeword/.prettierrc": {
2022
- // Rule conflict: unicorn/no-useless-undefined removes explicit undefined, sonarjs/no-inconsistent-returns wants it
2023
- // eslint-disable-next-line sonarjs/no-inconsistent-returns
2020
+ // eslint-disable-next-line sonarjs/no-inconsistent-returns -- generator returns undefined to skip file
2024
2021
  generator: (ctx) => {
2025
2022
  if (!ctx.languages?.javascript || ctx.projectType.existingFormatter) {
2026
2023
  return;
@@ -2034,8 +2031,7 @@ var typescriptOwnedFiles = {
2034
2031
  var typescriptManagedFiles = {
2035
2032
  // Project-level ESLint config (created only if no existing ESLint config)
2036
2033
  "eslint.config.mjs": {
2037
- // Rule conflict: unicorn/no-useless-undefined removes explicit undefined, sonarjs/no-inconsistent-returns wants it
2038
- // eslint-disable-next-line sonarjs/no-inconsistent-returns
2034
+ // eslint-disable-next-line sonarjs/no-inconsistent-returns -- generator returns undefined to skip file
2039
2035
  generator: (ctx) => {
2040
2036
  if (ctx.projectType.existingEslintConfig) return;
2041
2037
  if (!ctx.languages?.javascript) return;
@@ -2044,8 +2040,7 @@ var typescriptManagedFiles = {
2044
2040
  },
2045
2041
  // Minimal tsconfig for ESLint type-checked linting (only if missing)
2046
2042
  "tsconfig.json": {
2047
- // Rule conflict: unicorn/no-useless-undefined removes explicit undefined, sonarjs/no-inconsistent-returns wants it
2048
- // eslint-disable-next-line sonarjs/no-inconsistent-returns
2043
+ // eslint-disable-next-line sonarjs/no-inconsistent-returns -- generator returns undefined to skip file
2049
2044
  generator: (ctx) => {
2050
2045
  if (!ctx.languages?.javascript) return;
2051
2046
  if (!ctx.developmentDeps.typescript && !ctx.developmentDeps["typescript-eslint"]) {
@@ -2077,8 +2072,7 @@ var typescriptManagedFiles = {
2077
2072
  },
2078
2073
  // Project-level Prettier config (created only if no existing formatter)
2079
2074
  ".prettierrc": {
2080
- // Rule conflict: unicorn/no-useless-undefined removes explicit undefined, sonarjs/no-inconsistent-returns wants it
2081
- // eslint-disable-next-line sonarjs/no-inconsistent-returns
2075
+ // eslint-disable-next-line sonarjs/no-inconsistent-returns -- generator returns undefined to skip file
2082
2076
  generator: (ctx) => {
2083
2077
  if (!ctx.languages?.javascript) return;
2084
2078
  if (ctx.projectType.existingFormatter) return;
@@ -2356,7 +2350,12 @@ var SAFEWORD_SCHEMA = {
2356
2350
  ".claude/commands/debug.md",
2357
2351
  ".claude/commands/quality-review.md",
2358
2352
  ".claude/commands/refactor.md",
2359
- ".claude/commands/testing.md"
2353
+ ".claude/commands/testing.md",
2354
+ // Commands converted to skills (ticket 038)
2355
+ ".claude/commands/lint.md",
2356
+ ".claude/commands/verify.md",
2357
+ ".claude/commands/audit.md",
2358
+ ".claude/commands/cleanup-zombies.md"
2360
2359
  ],
2361
2360
  // Packages to uninstall on upgrade (now bundled in safeword/eslint)
2362
2361
  deprecatedPackages: [
@@ -2575,14 +2574,14 @@ var SAFEWORD_SCHEMA = {
2575
2574
  ".claude/skills/ticket-system/SKILL.md": {
2576
2575
  template: "skills/ticket-system/SKILL.md"
2577
2576
  },
2578
- // Claude commandsonly standalone commands that have no matching skill
2579
- // Skills auto-create /slash-commands, so shim commands are redundant
2580
- ".claude/commands/verify.md": { template: "commands/verify.md" },
2581
- ".claude/commands/audit.md": { template: "commands/audit.md" },
2582
- ".claude/commands/cleanup-zombies.md": {
2583
- template: "commands/cleanup-zombies.md"
2577
+ // Claude skillsaction commands with disable-model-invocation
2578
+ // Skills auto-create /slash-commands, so separate commands are unnecessary
2579
+ ".claude/skills/lint/SKILL.md": { template: "skills/lint/SKILL.md" },
2580
+ ".claude/skills/verify/SKILL.md": { template: "skills/verify/SKILL.md" },
2581
+ ".claude/skills/audit/SKILL.md": { template: "skills/audit/SKILL.md" },
2582
+ ".claude/skills/cleanup-zombies/SKILL.md": {
2583
+ template: "skills/cleanup-zombies/SKILL.md"
2584
2584
  },
2585
- ".claude/commands/lint.md": { template: "commands/lint.md" },
2586
2585
  // Cursor rules
2587
2586
  ".cursor/rules/safeword-core.mdc": {
2588
2587
  template: "cursor/rules/safeword-core.mdc"
@@ -2937,4 +2936,4 @@ export {
2937
2936
  detectLanguages2,
2938
2937
  createProjectContext
2939
2938
  };
2940
- //# sourceMappingURL=chunk-NINE7AWZ.js.map
2939
+ //# sourceMappingURL=chunk-5A745HPE.js.map