@limenet-ch/baseline 2.9.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 (105) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +272 -0
  3. package/js/dist/bin.d.ts +2 -0
  4. package/js/dist/bin.js +59 -0
  5. package/js/dist/bin.js.map +1 -0
  6. package/js/dist/checks/allows-tooling-in-claude-settings-check.d.ts +11 -0
  7. package/js/dist/checks/allows-tooling-in-claude-settings-check.js +14 -0
  8. package/js/dist/checks/allows-tooling-in-claude-settings-check.js.map +1 -0
  9. package/js/dist/checks/biome-uses-local-schema-check.d.ts +21 -0
  10. package/js/dist/checks/biome-uses-local-schema-check.js +78 -0
  11. package/js/dist/checks/biome-uses-local-schema-check.js.map +1 -0
  12. package/js/dist/checks/calls-baseline-check.d.ts +11 -0
  13. package/js/dist/checks/calls-baseline-check.js +34 -0
  14. package/js/dist/checks/calls-baseline-check.js.map +1 -0
  15. package/js/dist/checks/check.d.ts +37 -0
  16. package/js/dist/checks/check.js +54 -0
  17. package/js/dist/checks/check.js.map +1 -0
  18. package/js/dist/checks/ci-sets-node-version-check.d.ts +10 -0
  19. package/js/dist/checks/ci-sets-node-version-check.js +43 -0
  20. package/js/dist/checks/ci-sets-node-version-check.js.map +1 -0
  21. package/js/dist/checks/claude-settings-check.d.ts +30 -0
  22. package/js/dist/checks/claude-settings-check.js +43 -0
  23. package/js/dist/checks/claude-settings-check.js.map +1 -0
  24. package/js/dist/checks/denies-env-reads-in-claude-settings-check.d.ts +13 -0
  25. package/js/dist/checks/denies-env-reads-in-claude-settings-check.js +25 -0
  26. package/js/dist/checks/denies-env-reads-in-claude-settings-check.js.map +1 -0
  27. package/js/dist/checks/does-not-have-copilot-or-junie-agent-files-check.d.ts +5 -0
  28. package/js/dist/checks/does-not-have-copilot-or-junie-agent-files-check.js +25 -0
  29. package/js/dist/checks/does-not-have-copilot-or-junie-agent-files-check.js.map +1 -0
  30. package/js/dist/checks/does-not-use-both-baseline-runners-check.d.ts +13 -0
  31. package/js/dist/checks/does-not-use-both-baseline-runners-check.js +30 -0
  32. package/js/dist/checks/does-not-use-both-baseline-runners-check.js.map +1 -0
  33. package/js/dist/checks/hardens-npm-supply-chain-check.d.ts +5 -0
  34. package/js/dist/checks/hardens-npm-supply-chain-check.js +68 -0
  35. package/js/dist/checks/hardens-npm-supply-chain-check.js.map +1 -0
  36. package/js/dist/checks/has-ci-jobs-check.d.ts +9 -0
  37. package/js/dist/checks/has-ci-jobs-check.js +14 -0
  38. package/js/dist/checks/has-ci-jobs-check.js.map +1 -0
  39. package/js/dist/checks/has-editorconfig-check.d.ts +6 -0
  40. package/js/dist/checks/has-editorconfig-check.js +42 -0
  41. package/js/dist/checks/has-editorconfig-check.js.map +1 -0
  42. package/js/dist/checks/has-npm-scripts-check.d.ts +5 -0
  43. package/js/dist/checks/has-npm-scripts-check.js +20 -0
  44. package/js/dist/checks/has-npm-scripts-check.js.map +1 -0
  45. package/js/dist/checks/has-trivy-config-check.d.ts +26 -0
  46. package/js/dist/checks/has-trivy-config-check.js +179 -0
  47. package/js/dist/checks/has-trivy-config-check.js.map +1 -0
  48. package/js/dist/checks/is-ci-lint-complete-check.d.ts +10 -0
  49. package/js/dist/checks/is-ci-lint-complete-check.js +25 -0
  50. package/js/dist/checks/is-ci-lint-complete-check.js.map +1 -0
  51. package/js/dist/checks/node-version-check.d.ts +5 -0
  52. package/js/dist/checks/node-version-check.js +77 -0
  53. package/js/dist/checks/node-version-check.js.map +1 -0
  54. package/js/dist/checks/periodic-check.d.ts +16 -0
  55. package/js/dist/checks/periodic-check.js +34 -0
  56. package/js/dist/checks/periodic-check.js.map +1 -0
  57. package/js/dist/checks/registry.d.ts +10 -0
  58. package/js/dist/checks/registry.js +56 -0
  59. package/js/dist/checks/registry.js.map +1 -0
  60. package/js/dist/checks/runs-ci-lint-hook-in-claude-settings-check.d.ts +6 -0
  61. package/js/dist/checks/runs-ci-lint-hook-in-claude-settings-check.js +26 -0
  62. package/js/dist/checks/runs-ci-lint-hook-in-claude-settings-check.js.map +1 -0
  63. package/js/dist/checks/updates-dependencies-check.d.ts +5 -0
  64. package/js/dist/checks/updates-dependencies-check.js +8 -0
  65. package/js/dist/checks/updates-dependencies-check.js.map +1 -0
  66. package/js/dist/checks/uses-release-it-check.d.ts +12 -0
  67. package/js/dist/checks/uses-release-it-check.js +40 -0
  68. package/js/dist/checks/uses-release-it-check.js.map +1 -0
  69. package/js/dist/commands/check.d.ts +7 -0
  70. package/js/dist/commands/check.js +59 -0
  71. package/js/dist/commands/check.js.map +1 -0
  72. package/js/dist/commands/install-skills.d.ts +16 -0
  73. package/js/dist/commands/install-skills.js +47 -0
  74. package/js/dist/commands/install-skills.js.map +1 -0
  75. package/js/dist/commands/periodic.d.ts +6 -0
  76. package/js/dist/commands/periodic.js +40 -0
  77. package/js/dist/commands/periodic.js.map +1 -0
  78. package/js/dist/index.d.ts +8 -0
  79. package/js/dist/index.js +9 -0
  80. package/js/dist/index.js.map +1 -0
  81. package/js/dist/policy.d.ts +45 -0
  82. package/js/dist/policy.js +145 -0
  83. package/js/dist/policy.js.map +1 -0
  84. package/js/dist/project.d.ts +26 -0
  85. package/js/dist/project.js +64 -0
  86. package/js/dist/project.js.map +1 -0
  87. package/js/dist/state.d.ts +21 -0
  88. package/js/dist/state.js +36 -0
  89. package/js/dist/state.js.map +1 -0
  90. package/js/dist/support/ci-jobs.d.ts +13 -0
  91. package/js/dist/support/ci-jobs.js +42 -0
  92. package/js/dist/support/ci-jobs.js.map +1 -0
  93. package/js/dist/support/npmrc.d.ts +10 -0
  94. package/js/dist/support/npmrc.js +36 -0
  95. package/js/dist/support/npmrc.js.map +1 -0
  96. package/js/dist/support/versions.d.ts +10 -0
  97. package/js/dist/support/versions.js +34 -0
  98. package/js/dist/support/versions.js.map +1 -0
  99. package/js/skills/creating-a-release/SKILL.md +45 -0
  100. package/js/skills/updating-dependencies/SKILL.md +104 -0
  101. package/package.json +67 -0
  102. package/policy/policy.json +131 -0
  103. package/policy/policy.schema.json +284 -0
  104. package/policy/templates/editorconfig +18 -0
  105. package/policy/templates/trivy.yaml +19 -0
@@ -0,0 +1,179 @@
1
+ import { parse, parseDocument } from 'yaml';
2
+ import { policy } from '../policy.js';
3
+ import { CI_FILE, checkRequiredCiJobs, readCiJobs } from '../support/ci-jobs.js';
4
+ import { FixableCheck } from './check.js';
5
+ /**
6
+ * Trivy's setup, identical to the Laravel runner's: the security CI job, the
7
+ * canonical trivy.yaml, an ignore file, and the cache directory in .gitignore.
8
+ *
9
+ * The canonical config skips paths a JS project does not have (`vendor/**`,
10
+ * `storage/logs/`, `.ddev/`). Skipping a directory that is not there costs
11
+ * nothing, and one shared template means the two runners cannot drift — so the
12
+ * npm runner requires the same file rather than a trimmed variant.
13
+ */
14
+ export class HasTrivyConfigCheck extends FixableCheck {
15
+ static checkName = 'hasTrivyConfig';
16
+ fix(dry = false) {
17
+ const ciResult = checkRequiredCiJobs(this.project, policy().stringListMap('trivy.ciJob'), (message) => this.comment(message));
18
+ if (ciResult !== 'pass') {
19
+ if (dry) {
20
+ return ciResult;
21
+ }
22
+ this.addMissingCiJobs();
23
+ }
24
+ const gitignoreResult = this.ensureGitignoreEntry(policy().string('trivy.gitignoreEntry'), 'ignore the Trivy cache directory', dry);
25
+ if (gitignoreResult !== null && dry) {
26
+ return gitignoreResult;
27
+ }
28
+ const ignoreFile = policy().string('trivy.ignoreFile');
29
+ if (!this.project.exists(ignoreFile)) {
30
+ this.comment(`Missing ignore file: create ${ignoreFile} in project root (an empty file is acceptable)`);
31
+ if (dry) {
32
+ return 'fail';
33
+ }
34
+ this.project.write(ignoreFile, '');
35
+ }
36
+ const configFile = policy().string('trivy.configFile');
37
+ const contents = this.project.read(configFile);
38
+ if (contents === null) {
39
+ this.comment(`${configFile} not found`);
40
+ if (dry) {
41
+ return 'fail';
42
+ }
43
+ this.project.write(configFile, this.canonicalConfig());
44
+ return this.fix(true);
45
+ }
46
+ // parseDocument() keeps comments and formatting across the write below,
47
+ // and collects syntax errors instead of throwing.
48
+ const document = parseDocument(contents);
49
+ if (document.errors.length > 0) {
50
+ this.comment(`${configFile} could not be parsed: ${document.errors[0]?.message ?? 'invalid YAML'}`);
51
+ return 'fail';
52
+ }
53
+ const config = document.toJS();
54
+ if (typeof config !== 'object' || config === null) {
55
+ this.comment(`${configFile} is empty or invalid`);
56
+ return 'fail';
57
+ }
58
+ let changed = false;
59
+ for (const forbidden of policy().strings('trivy.forbiddenKeys')) {
60
+ if (!(forbidden in config)) {
61
+ continue;
62
+ }
63
+ this.comment(`Forbidden key in ${configFile}: '${forbidden}' must not be set (use Trivy's default severity behavior)`);
64
+ if (dry) {
65
+ return 'fail';
66
+ }
67
+ document.delete(forbidden);
68
+ changed = true;
69
+ }
70
+ for (const [path, expected] of this.requirements(parse(this.canonicalConfig()))) {
71
+ const dotted = path.join('.');
72
+ const current = this.getByPath(config, path);
73
+ if (Array.isArray(expected)) {
74
+ const declared = Array.isArray(current) ? current : [];
75
+ const missing = expected.filter((entry) => !declared.includes(entry));
76
+ if (missing.length === 0) {
77
+ continue;
78
+ }
79
+ this.comment(`Missing entries in ${configFile}: ${dotted} must include ${missing.join(', ')}`);
80
+ if (dry) {
81
+ return 'fail';
82
+ }
83
+ document.setIn(path, [...declared, ...missing]);
84
+ changed = true;
85
+ continue;
86
+ }
87
+ if (current === expected) {
88
+ continue;
89
+ }
90
+ this.comment(`Invalid value in ${configFile}: '${dotted}' must equal ${typeof expected === 'boolean' ? String(expected) : `'${String(expected)}'`}`);
91
+ if (dry) {
92
+ return 'fail';
93
+ }
94
+ document.setIn(path, expected);
95
+ changed = true;
96
+ }
97
+ if (dry) {
98
+ return 'pass';
99
+ }
100
+ if (changed) {
101
+ this.project.write(configFile, document.toString());
102
+ }
103
+ return this.fix(true);
104
+ }
105
+ /** The canonical body, written verbatim into a project that has none. */
106
+ canonicalConfig() {
107
+ return policy().template(policy().string('trivy.template'));
108
+ }
109
+ /**
110
+ * The canonical config read as a requirement set: every scalar leaf must be
111
+ * equal in the project's file, every list leaf contained in it. Keys the
112
+ * template does not mention are the project's own business.
113
+ */
114
+ requirements(node, prefix = []) {
115
+ if (typeof node !== 'object' || node === null || Array.isArray(node)) {
116
+ return [];
117
+ }
118
+ const found = [];
119
+ for (const [key, value] of Object.entries(node)) {
120
+ const path = [...prefix, key];
121
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
122
+ found.push(...this.requirements(value, path));
123
+ continue;
124
+ }
125
+ found.push([path, value]);
126
+ }
127
+ return found;
128
+ }
129
+ getByPath(config, path) {
130
+ return path.reduce((carry, segment) => {
131
+ if (typeof carry !== 'object' || carry === null) {
132
+ return undefined;
133
+ }
134
+ return carry[segment];
135
+ }, config);
136
+ }
137
+ /** Adds each missing job, leaving the rest of the pipeline untouched. */
138
+ addMissingCiJobs() {
139
+ const contents = this.project.read(CI_FILE);
140
+ if (contents === null || readCiJobs(this.project, () => { }) === null) {
141
+ return;
142
+ }
143
+ const document = parseDocument(contents);
144
+ let changed = false;
145
+ for (const [job, accepted] of Object.entries(policy().stringListMap('trivy.ciJob'))) {
146
+ if (document.hasIn([job])) {
147
+ continue;
148
+ }
149
+ document.setIn([job], { extends: [accepted[0]] });
150
+ changed = true;
151
+ }
152
+ if (changed) {
153
+ this.project.write(CI_FILE, document.toString());
154
+ }
155
+ }
156
+ ensureGitignoreEntry(entry, reason, dry) {
157
+ const contents = this.project.read('.gitignore');
158
+ if (contents === null) {
159
+ this.comment(`Missing .gitignore in project root: create it and add '${entry}'`);
160
+ if (dry) {
161
+ return 'fail';
162
+ }
163
+ this.project.write('.gitignore', `${entry}\n`);
164
+ return 'fail';
165
+ }
166
+ const normalise = (line) => line.trim().replace(/^\/+|\/+$/g, '');
167
+ if (contents.split('\n').map(normalise).includes(normalise(entry))) {
168
+ return null;
169
+ }
170
+ this.comment(`Missing entry in .gitignore: add '${entry}' to ${reason}`);
171
+ if (dry) {
172
+ return 'fail';
173
+ }
174
+ const prefix = contents === '' || contents.endsWith('\n') ? '' : '\n';
175
+ this.project.write('.gitignore', `${contents}${prefix}${entry}\n`);
176
+ return 'fail';
177
+ }
178
+ }
179
+ //# sourceMappingURL=has-trivy-config-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"has-trivy-config-check.js","sourceRoot":"","sources":["../../src/checks/has-trivy-config-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { Check, type CheckResult } from './check.js';
2
+ /**
3
+ * The JS counterpart of the PHP runner's isCiLintComplete: same intent, different
4
+ * toolchain — the linter and type checker must actually run in `ci-lint`, not
5
+ * just be installed.
6
+ */
7
+ export declare class IsCiLintCompleteCheck extends Check {
8
+ static readonly checkName = "isCiLintComplete";
9
+ check(): CheckResult;
10
+ }
@@ -0,0 +1,25 @@
1
+ import { policy } from '../policy.js';
2
+ import { Check } from './check.js';
3
+ /**
4
+ * The JS counterpart of the PHP runner's isCiLintComplete: same intent, different
5
+ * toolchain — the linter and type checker must actually run in `ci-lint`, not
6
+ * just be installed.
7
+ */
8
+ export class IsCiLintCompleteCheck extends Check {
9
+ static checkName = 'isCiLintComplete';
10
+ check() {
11
+ const script = this.project.readJson('package.json')?.scripts?.['ci-lint'];
12
+ if (script === undefined) {
13
+ this.comment('Missing ci-lint script in package.json: Add "ci-lint" to scripts section');
14
+ return 'fail';
15
+ }
16
+ for (const required of policy().strings('ciLint.required.js')) {
17
+ if (!script.includes(required)) {
18
+ this.comment(`Incomplete ci-lint script in package.json: it must run "${required}"`);
19
+ return 'fail';
20
+ }
21
+ }
22
+ return 'pass';
23
+ }
24
+ }
25
+ //# sourceMappingURL=is-ci-lint-complete-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-ci-lint-complete-check.js","sourceRoot":"","sources":["../../src/checks/is-ci-lint-complete-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,KAAK,EAAoB,MAAM,YAAY,CAAA;AAMpD;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC5C,MAAM,CAAmB,SAAS,GAAG,kBAAkB,CAAA;IAEvD,KAAK;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAc,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAA;QAEvF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,0EAA0E,CAAC,CAAA;YAExF,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC5D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,2DAA2D,QAAQ,GAAG,CAAC,CAAA;gBAEpF,OAAO,MAAM,CAAA;YACjB,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAA;IACjB,CAAC;CACJ"}
@@ -0,0 +1,5 @@
1
+ import { type CheckResult, FixableCheck } from './check.js';
2
+ export declare class NodeVersionCheck extends FixableCheck {
3
+ static readonly checkName = "nodeVersion";
4
+ fix(dry?: boolean): CheckResult;
5
+ }
@@ -0,0 +1,77 @@
1
+ import { policy } from '../policy.js';
2
+ import { compatible, guaranteesAtLeast, lowestMajor } from '../support/versions.js';
3
+ import { FixableCheck } from './check.js';
4
+ export class NodeVersionCheck extends FixableCheck {
5
+ static checkName = 'nodeVersion';
6
+ fix(dry = false) {
7
+ const packageJson = this.project.readJson('package.json');
8
+ if (packageJson === null) {
9
+ this.comment('Package.json missing: Create package.json in project root');
10
+ return 'fail';
11
+ }
12
+ const floor = policy().string('node.minMajor');
13
+ const engines = nonEmpty(packageJson.engines?.node);
14
+ const nvmrc = nonEmpty(this.project.read('.nvmrc')?.trim());
15
+ // Two declared-but-conflicting versions need a human decision — never auto-fixed.
16
+ if (engines !== null && nvmrc !== null && !compatible(engines, nvmrc)) {
17
+ this.comment(`Node version mismatch: package.json engines.node (${engines}) and .nvmrc (${nvmrc}) disagree`);
18
+ return 'fail';
19
+ }
20
+ const enginesTooLow = engines !== null && !guaranteesAtLeast(engines, floor);
21
+ const nvmrcTooLow = nvmrc !== null && !guaranteesAtLeast(nvmrc, floor);
22
+ // A below-floor declaration is bumped to the floor; otherwise keep the project's own line.
23
+ const major = enginesTooLow || nvmrcTooLow ? floor : resolveMajor(engines, nvmrc, floor);
24
+ if (engines === null) {
25
+ this.comment(`package.json missing engines.node: add "engines": { "node": "^${major}" }`);
26
+ if (dry) {
27
+ return 'fail';
28
+ }
29
+ }
30
+ else if (enginesTooLow) {
31
+ this.comment(`engines.node (${engines}) allows Node < ${floor}; require Node >= ${floor} (e.g. "^${floor}")`);
32
+ if (dry) {
33
+ return 'fail';
34
+ }
35
+ }
36
+ if (nvmrc === null) {
37
+ this.comment(`.nvmrc missing: create a .nvmrc pinning Node "${major}"`);
38
+ if (dry) {
39
+ return 'fail';
40
+ }
41
+ }
42
+ else if (nvmrcTooLow) {
43
+ this.comment(`.nvmrc (${nvmrc}) pins Node < ${floor}: set it to "${floor}"`);
44
+ if (dry) {
45
+ return 'fail';
46
+ }
47
+ }
48
+ if (dry) {
49
+ return 'pass';
50
+ }
51
+ if (engines === null || enginesTooLow) {
52
+ packageJson.engines = { ...packageJson.engines, node: `^${major}` };
53
+ this.project.writeJson('package.json', packageJson);
54
+ }
55
+ if (nvmrc === null || nvmrcTooLow) {
56
+ this.project.write('.nvmrc', `${major}\n`);
57
+ }
58
+ return this.fix(true);
59
+ }
60
+ }
61
+ /** The major to establish: the .nvmrc value, then engines.node, then the floor. */
62
+ function resolveMajor(engines, nvmrc, floor) {
63
+ for (const candidate of [nvmrc, engines]) {
64
+ if (candidate === null) {
65
+ continue;
66
+ }
67
+ const major = lowestMajor(candidate);
68
+ if (major !== null) {
69
+ return major;
70
+ }
71
+ }
72
+ return floor;
73
+ }
74
+ function nonEmpty(value) {
75
+ return value === undefined || value === '' ? null : value;
76
+ }
77
+ //# sourceMappingURL=node-version-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-version-check.js","sourceRoot":"","sources":["../../src/checks/node-version-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Check, type CheckResult } from './check.js';
2
+ /**
3
+ * A requirement that cannot be verified statically because it needs a developer
4
+ * to do something on a schedule. Mirrors src/Checks/AbstractPeriodicCheck.php.
5
+ */
6
+ export declare abstract class PeriodicCheck extends Check {
7
+ /** Shown to the developer by `baseline periodic`. */
8
+ abstract promptDescription(): string;
9
+ intervalDays(): number;
10
+ /** Return false to skip the check entirely — e.g. an optional tool is absent. */
11
+ isApplicable(): boolean;
12
+ /** Do not override: preconditions belong in isApplicable(). */
13
+ check(): CheckResult;
14
+ private hasExpired;
15
+ }
16
+ export declare function isPeriodic(check: Check): check is PeriodicCheck;
@@ -0,0 +1,34 @@
1
+ import { policy } from '../policy.js';
2
+ import { lastRun } from '../state.js';
3
+ import { Check } from './check.js';
4
+ /**
5
+ * A requirement that cannot be verified statically because it needs a developer
6
+ * to do something on a schedule. Mirrors src/Checks/AbstractPeriodicCheck.php.
7
+ */
8
+ export class PeriodicCheck extends Check {
9
+ intervalDays() {
10
+ return policy().number('periodic.defaultIntervalDays');
11
+ }
12
+ /** Return false to skip the check entirely — e.g. an optional tool is absent. */
13
+ isApplicable() {
14
+ return true;
15
+ }
16
+ /** Do not override: preconditions belong in isApplicable(). */
17
+ check() {
18
+ const previous = lastRun(this.project, this.name);
19
+ if (previous === null || this.hasExpired(previous)) {
20
+ this.comment('Run `npx baseline periodic` to complete this periodic check');
21
+ return 'fail';
22
+ }
23
+ return 'pass';
24
+ }
25
+ hasExpired(previous) {
26
+ const due = new Date(previous);
27
+ due.setDate(due.getDate() + this.intervalDays());
28
+ return due.getTime() < Date.now();
29
+ }
30
+ }
31
+ export function isPeriodic(check) {
32
+ return check instanceof PeriodicCheck;
33
+ }
34
+ //# sourceMappingURL=periodic-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"periodic-check.js","sourceRoot":"","sources":["../../src/checks/periodic-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,KAAK,EAAoB,MAAM,YAAY,CAAA;AAEpD;;;GAGG;AACH,MAAM,OAAgB,aAAc,SAAQ,KAAK;IAI7C,YAAY;QACR,OAAO,MAAM,EAAE,CAAC,MAAM,CAAC,8BAA8B,CAAC,CAAA;IAC1D,CAAC;IAED,iFAAiF;IACjF,YAAY;QACR,OAAO,IAAI,CAAA;IACf,CAAC;IAED,+DAA+D;IAC/D,KAAK;QACD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAEjD,IAAI,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,OAAO,CAAC,6DAA6D,CAAC,CAAA;YAE3E,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,OAAO,MAAM,CAAA;IACjB,CAAC;IAEO,UAAU,CAAC,QAAc;QAC7B,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC9B,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,CAAA;QAEhD,OAAO,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACrC,CAAC;CACJ;AAED,MAAM,UAAU,UAAU,CAAC,KAAY;IACnC,OAAO,KAAK,YAAY,aAAa,CAAA;AACzC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Project } from '../project.js';
2
+ import type { Check, CommentCollector } from './check.js';
3
+ type CheckConstructor = (new (project: Project, comments: CommentCollector) => Check) & {
4
+ readonly checkName: string;
5
+ };
6
+ export declare function allChecks(): CheckConstructor[];
7
+ export declare function checkNames(): string[];
8
+ export declare function findCheck(name: string): CheckConstructor | undefined;
9
+ export declare function createChecks(project: Project, comments: CommentCollector): Check[];
10
+ export {};
@@ -0,0 +1,56 @@
1
+ import { AllowsToolingInClaudeSettingsCheck } from './allows-tooling-in-claude-settings-check.js';
2
+ import { BiomeUsesLocalSchemaCheck } from './biome-uses-local-schema-check.js';
3
+ import { CallsBaselineCheck } from './calls-baseline-check.js';
4
+ import { CiSetsNodeVersionCheck } from './ci-sets-node-version-check.js';
5
+ import { DeniesEnvReadsInClaudeSettingsCheck } from './denies-env-reads-in-claude-settings-check.js';
6
+ import { DoesNotHaveCopilotOrJunieAgentFilesCheck } from './does-not-have-copilot-or-junie-agent-files-check.js';
7
+ import { DoesNotUseBothBaselineRunnersCheck } from './does-not-use-both-baseline-runners-check.js';
8
+ import { HardensNpmSupplyChainCheck } from './hardens-npm-supply-chain-check.js';
9
+ import { HasCiJobsCheck } from './has-ci-jobs-check.js';
10
+ import { HasEditorconfigCheck } from './has-editorconfig-check.js';
11
+ import { HasNpmScriptsCheck } from './has-npm-scripts-check.js';
12
+ import { HasTrivyConfigCheck } from './has-trivy-config-check.js';
13
+ import { IsCiLintCompleteCheck } from './is-ci-lint-complete-check.js';
14
+ import { NodeVersionCheck } from './node-version-check.js';
15
+ import { RunsCiLintHookInClaudeSettingsCheck } from './runs-ci-lint-hook-in-claude-settings-check.js';
16
+ import { UpdatesDependenciesCheck } from './updates-dependencies-check.js';
17
+ import { UsesReleaseItCheck } from './uses-release-it-check.js';
18
+ /**
19
+ * Every check this runner knows about, in execution and display order.
20
+ *
21
+ * This is intentionally a subset of the PHP runner's registry: only the checks
22
+ * that mean something in a project with no PHP and no DDEV are here. See the
23
+ * README for the ported / not-ported table.
24
+ */
25
+ const checks = [
26
+ AllowsToolingInClaudeSettingsCheck,
27
+ BiomeUsesLocalSchemaCheck,
28
+ CallsBaselineCheck,
29
+ CiSetsNodeVersionCheck,
30
+ DeniesEnvReadsInClaudeSettingsCheck,
31
+ DoesNotHaveCopilotOrJunieAgentFilesCheck,
32
+ DoesNotUseBothBaselineRunnersCheck,
33
+ HardensNpmSupplyChainCheck,
34
+ HasCiJobsCheck,
35
+ HasEditorconfigCheck,
36
+ HasNpmScriptsCheck,
37
+ HasTrivyConfigCheck,
38
+ IsCiLintCompleteCheck,
39
+ NodeVersionCheck,
40
+ RunsCiLintHookInClaudeSettingsCheck,
41
+ UpdatesDependenciesCheck,
42
+ UsesReleaseItCheck,
43
+ ];
44
+ export function allChecks() {
45
+ return [...checks];
46
+ }
47
+ export function checkNames() {
48
+ return checks.map((check) => check.checkName);
49
+ }
50
+ export function findCheck(name) {
51
+ return checks.find((check) => check.checkName === name);
52
+ }
53
+ export function createChecks(project, comments) {
54
+ return checks.map((Constructor) => new Constructor(project, comments));
55
+ }
56
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/checks/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kCAAkC,EAAE,MAAM,8CAA8C,CAAA;AACjG,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAA;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAE9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,mCAAmC,EAAE,MAAM,gDAAgD,CAAA;AACpG,OAAO,EAAE,wCAAwC,EAAE,MAAM,uDAAuD,CAAA;AAChH,OAAO,EAAE,kCAAkC,EAAE,MAAM,+CAA+C,CAAA;AAClG,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAA;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,mCAAmC,EAAE,MAAM,iDAAiD,CAAA;AACrG,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAA;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAO/D;;;;;;GAMG;AACH,MAAM,MAAM,GAAuB;IAC/B,kCAAkC;IAClC,yBAAyB;IACzB,kBAAkB;IAClB,sBAAsB;IACtB,mCAAmC;IACnC,wCAAwC;IACxC,kCAAkC;IAClC,0BAA0B;IAC1B,cAAc;IACd,oBAAoB;IACpB,kBAAkB;IAClB,mBAAmB;IACnB,qBAAqB;IACrB,gBAAgB;IAChB,mCAAmC;IACnC,wBAAwB;IACxB,kBAAkB;CACrB,CAAA;AAED,MAAM,UAAU,SAAS;IACrB,OAAO,CAAC,GAAG,MAAM,CAAC,CAAA;AACtB,CAAC;AAED,MAAM,UAAU,UAAU;IACtB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IAClC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC,CAAA;AAC3D,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAgB,EAAE,QAA0B;IACrE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAA;AAC1E,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { CheckResult } from './check.js';
2
+ import { ClaudeSettingsCheck } from './claude-settings-check.js';
3
+ export declare class RunsCiLintHookInClaudeSettingsCheck extends ClaudeSettingsCheck {
4
+ static readonly checkName = "runsCiLintHookInClaudeSettings";
5
+ fix(dry?: boolean): CheckResult;
6
+ }
@@ -0,0 +1,26 @@
1
+ import { policy } from '../policy.js';
2
+ import { ClaudeSettingsCheck } from './claude-settings-check.js';
3
+ export class RunsCiLintHookInClaudeSettingsCheck extends ClaudeSettingsCheck {
4
+ static checkName = 'runsCiLintHookInClaudeSettings';
5
+ fix(dry = false) {
6
+ // The JS command, not the PHP runner's `ddev composer run ci-lint`.
7
+ const command = policy().string('claude.ciLintHookCommand.js');
8
+ const settings = this.readSettings();
9
+ const stopGroups = settings.hooks?.Stop ?? [];
10
+ const present = stopGroups.some((group) => (group.hooks ?? []).some((hook) => hook.command === command));
11
+ if (present) {
12
+ return 'pass';
13
+ }
14
+ this.comment(`Claude settings: add a Stop hook running "${command}" to .claude/settings.json`);
15
+ if (dry) {
16
+ return 'fail';
17
+ }
18
+ settings.hooks = {
19
+ ...settings.hooks,
20
+ Stop: [...stopGroups, { matcher: '', hooks: [{ type: 'command', command }] }],
21
+ };
22
+ this.writeSettings(settings);
23
+ return 'pass';
24
+ }
25
+ }
26
+ //# sourceMappingURL=runs-ci-lint-hook-in-claude-settings-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs-ci-lint-hook-in-claude-settings-check.js","sourceRoot":"","sources":["../../src/checks/runs-ci-lint-hook-in-claude-settings-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAEhE,MAAM,OAAO,mCAAoC,SAAQ,mBAAmB;IACxE,MAAM,CAAmB,SAAS,GAAG,gCAAgC,CAAA;IAErE,GAAG,CAAC,GAAG,GAAG,KAAK;QACX,oEAAoE;QACpE,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,6BAA6B,CAAC,CAAA;QAE9D,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAA;QACpC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,CAAA;QAE7C,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CACtC,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,OAAO,CAAC,CAC/D,CAAA;QAED,IAAI,OAAO,EAAE,CAAC;YACV,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,6CAA6C,OAAO,4BAA4B,CAAC,CAAA;QAE9F,IAAI,GAAG,EAAE,CAAC;YACN,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,QAAQ,CAAC,KAAK,GAAG;YACb,GAAG,QAAQ,CAAC,KAAK;YACjB,IAAI,EAAE,CAAC,GAAG,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;SAChF,CAAA;QAED,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;QAE5B,OAAO,MAAM,CAAA;IACjB,CAAC;CACJ"}
@@ -0,0 +1,5 @@
1
+ import { PeriodicCheck } from './periodic-check.js';
2
+ export declare class UpdatesDependenciesCheck extends PeriodicCheck {
3
+ static readonly checkName = "updatesDependencies";
4
+ promptDescription(): string;
5
+ }
@@ -0,0 +1,8 @@
1
+ import { PeriodicCheck } from './periodic-check.js';
2
+ export class UpdatesDependenciesCheck extends PeriodicCheck {
3
+ static checkName = 'updatesDependencies';
4
+ promptDescription() {
5
+ return 'Run the `updating-dependencies` skill to update npm dependencies, review changelogs, and check for semver-blocked majors.';
6
+ }
7
+ }
8
+ //# sourceMappingURL=updates-dependencies-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updates-dependencies-check.js","sourceRoot":"","sources":["../../src/checks/updates-dependencies-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,MAAM,OAAO,wBAAyB,SAAQ,aAAa;IACvD,MAAM,CAAmB,SAAS,GAAG,qBAAqB,CAAA;IAE1D,iBAAiB;QACb,OAAO,2HAA2H,CAAA;IACtI,CAAC;CACJ"}
@@ -0,0 +1,12 @@
1
+ import { type CheckResult, FixableCheck } from './check.js';
2
+ /**
3
+ * The JS counterpart of the PHP runner's usesReleaseIt. Deliberately the
4
+ * opposite assertion about @release-it/bumper: in a Laravel project the bumper
5
+ * writes the version into composer.json, whereas here package.json is already
6
+ * release-it's own source of truth, so a bumper pointed at it is redundant and a
7
+ * bumper pointed at composer.json is meaningless.
8
+ */
9
+ export declare class UsesReleaseItCheck extends FixableCheck {
10
+ static readonly checkName = "usesReleaseIt";
11
+ fix(dry?: boolean): CheckResult;
12
+ }
@@ -0,0 +1,40 @@
1
+ import { FixableCheck } from './check.js';
2
+ /**
3
+ * The JS counterpart of the PHP runner's usesReleaseIt. Deliberately the
4
+ * opposite assertion about @release-it/bumper: in a Laravel project the bumper
5
+ * writes the version into composer.json, whereas here package.json is already
6
+ * release-it's own source of truth, so a bumper pointed at it is redundant and a
7
+ * bumper pointed at composer.json is meaningless.
8
+ */
9
+ export class UsesReleaseItCheck extends FixableCheck {
10
+ static checkName = 'usesReleaseIt';
11
+ fix(dry = false) {
12
+ const packageJson = this.project.readJson('package.json');
13
+ if (packageJson === null) {
14
+ this.comment('Package.json missing: Create package.json in project root');
15
+ return 'fail';
16
+ }
17
+ if (packageJson.devDependencies?.['release-it'] === undefined) {
18
+ // Installing is the developer's call — this check never runs npm.
19
+ this.comment('Missing release-it: run "npm install --save-dev release-it"');
20
+ return 'fail';
21
+ }
22
+ const bumper = this.project.readJson('.release-it.json')?.plugins?.['@release-it/bumper'];
23
+ if (bumper !== undefined) {
24
+ this.comment("Remove the @release-it/bumper plugin from .release-it.json: release-it already writes package.json, which is this project's source of truth");
25
+ return 'fail';
26
+ }
27
+ const release = packageJson.scripts?.release;
28
+ if (release?.includes('release-it')) {
29
+ return 'pass';
30
+ }
31
+ this.comment('Missing release script in package.json: Add "release": "release-it" to scripts section');
32
+ if (dry) {
33
+ return 'fail';
34
+ }
35
+ packageJson.scripts = { ...packageJson.scripts, release: 'release-it' };
36
+ this.project.writeJson('package.json', packageJson);
37
+ return this.fix(true);
38
+ }
39
+ }
40
+ //# sourceMappingURL=uses-release-it-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uses-release-it-check.js","sourceRoot":"","sources":["../../src/checks/uses-release-it-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,YAAY,EAAE,MAAM,YAAY,CAAA;AAW3D;;;;;;GAMG;AACH,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAChD,MAAM,CAAmB,SAAS,GAAG,eAAe,CAAA;IAEpD,GAAG,CAAC,GAAG,GAAG,KAAK;QACX,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAc,cAAc,CAAC,CAAA;QAEtE,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAA;YAEzE,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,IAAI,WAAW,CAAC,eAAe,EAAE,CAAC,YAAY,CAAC,KAAK,SAAS,EAAE,CAAC;YAC5D,kEAAkE;YAClE,IAAI,CAAC,OAAO,CAAC,6DAA6D,CAAC,CAAA;YAE3E,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,MAAM,MAAM,GACR,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAkB,kBAAkB,CAAC,EAAE,OAAO,EAAE,CAAC,oBAAoB,CAAC,CAAA;QAE/F,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CACR,6IAA6I,CAChJ,CAAA;YAED,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,CAAA;QAE5C,IAAI,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YAClC,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,wFAAwF,CAAC,CAAA;QAEtG,IAAI,GAAG,EAAE,CAAC;YACN,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,WAAW,CAAC,OAAO,GAAG,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAA;QACvE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;QAEnD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;CACJ"}
@@ -0,0 +1,7 @@
1
+ import type { Project } from '../project.js';
2
+ export interface CheckOptions {
3
+ fix: boolean;
4
+ verbose: boolean;
5
+ }
6
+ /** Runs every registered check and returns the process exit code. */
7
+ export declare function runCheck(project: Project, options: CheckOptions): number;