@produck/agent-toolkit 0.9.0 → 0.9.2

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.
@@ -21,8 +21,13 @@ const TOOLING_BASELINE_CANDIDATE_PATHS = [
21
21
  ];
22
22
  const GLOB_TOKEN_PATTERN = /[*?{}[\]]/;
23
23
  const REQUIRED_ROOT_COVERAGE_SCRIPT_KEY = 'produck:coverage';
24
- const REQUIRED_ROOT_COVERAGE_SCRIPT_VALUE =
25
- 'c8 --config .c8rc.json npm run test --workspaces --if-present';
24
+ const REQUIRED_ROOT_COVERAGE_SCRIPT_VALUE = [
25
+ 'c8',
26
+ '--config .c8rc.json',
27
+ 'npm run test',
28
+ '--workspaces',
29
+ '--if-present',
30
+ ].join(' ');
26
31
  const REQUIRED_COVERAGE_SCRIPT_KEY = 'produck:coverage';
27
32
  const REQUIRED_TEST_SCRIPT_KEY = 'test';
28
33
  const DEFAULT_TEST_SCRIPT_VALUE =
@@ -4,7 +4,7 @@ Usage:
4
4
 
5
5
  Behavior:
6
6
  - Applies organization-required root shared scripts:
7
- - scripts.produck:baseline = npm exec --package=@produck/agent-toolkit@latest -- agent-toolkit enforce-node-baseline --cwd .
7
+ - scripts.produck:baseline = npm exec --package=@produck/agent-toolkit@latest -- agent-toolkit enforce-node-baseline --cwd . && npm run produck:install
8
8
  - scripts.produck:commit:check = npm run produck:format && npm run produck:lint
9
9
  - scripts.prepare = husky
10
10
  - Applies organization-required root shared managed devDependencies:
@@ -29,11 +29,22 @@ const HUSKY_DIR = '.husky';
29
29
  const PRE_COMMIT_HOOK_FILE = 'pre-commit';
30
30
  const COMMIT_MSG_HOOK_FILE = 'commit-msg';
31
31
  const REQUIRED_BASELINE_SCRIPT_KEY = 'produck:baseline';
32
- const REQUIRED_BASELINE_SCRIPT_VALUE =
33
- 'npm exec --package=@produck/agent-toolkit@latest -- agent-toolkit enforce-node-baseline --cwd .';
32
+ const REQUIRED_BASELINE_SCRIPT_VALUE = [
33
+ [
34
+ 'npm exec',
35
+ '--package=@produck/agent-toolkit@latest',
36
+ '--',
37
+ 'agent-toolkit',
38
+ 'enforce-node-baseline',
39
+ '--cwd .',
40
+ ].join(' '),
41
+ 'npm run produck:install',
42
+ ].join(' && ');
34
43
  const REQUIRED_COMMIT_CHECK_SCRIPT_KEY = 'produck:commit:check';
35
- const REQUIRED_COMMIT_CHECK_SCRIPT_VALUE =
36
- 'npm run produck:format && npm run produck:lint';
44
+ const REQUIRED_COMMIT_CHECK_SCRIPT_VALUE = [
45
+ 'npm run produck:format',
46
+ 'npm run produck:lint',
47
+ ].join(' && ');
37
48
  const REQUIRED_PREPARE_SCRIPT_KEY = 'prepare';
38
49
  const REQUIRED_PREPARE_SCRIPT_VALUE = 'husky';
39
50
 
@@ -9,7 +9,7 @@ const COMMAND_DIR = path.dirname(fileURLToPath(import.meta.url));
9
9
  const HELP_FILE = path.resolve(COMMAND_DIR, 'help.txt');
10
10
  const LEGACY_INSTALL_SCRIPT_KEY = 'deps:install';
11
11
  const REQUIRED_INSTALL_SCRIPT_KEY = 'produck:install';
12
- const REQUIRED_INSTALL_SCRIPT_VALUE = 'npm -v && npm install';
12
+ const REQUIRED_INSTALL_SCRIPT_VALUE = ['npm -v', 'npm install'].join(' && ');
13
13
 
14
14
  export function printSyncInstallHelp() {
15
15
  printTextResource(HELP_FILE);
@@ -1,8 +1,6 @@
1
1
  import js from '@eslint/js';
2
2
  import globals from 'globals';
3
3
  import tseslint from 'typescript-eslint';
4
- import json from '@eslint/json';
5
- import markdown from '@eslint/markdown';
6
4
  import { defineConfig } from 'eslint/config';
7
5
  import * as ProduckRule from '@produck/eslint-rules';
8
6
 
@@ -14,19 +12,8 @@ export default defineConfig([
14
12
  languageOptions: { globals: { ...globals.browser, ...globals.node } },
15
13
  },
16
14
  tseslint.configs.recommended,
17
- {
18
- files: ['**/*.json'],
19
- ignores: ['**/package-lock.json'],
20
- plugins: { json },
21
- language: 'json/json',
22
- extends: ['json/recommended'],
23
- },
24
- {
25
- files: ['**/*.md'],
26
- plugins: { markdown },
27
- language: 'markdown/gfm',
28
- extends: ['markdown/recommended'],
29
- },
30
- ProduckRule.config,
15
+ ProduckRule.config.ecma,
16
+ ProduckRule.config.json,
17
+ ProduckRule.config.markdown,
31
18
  ProduckRule.excludeGitIgnore(import.meta.url),
32
19
  ]);
@@ -21,6 +21,12 @@ const TOOLING_BASELINE_CANDIDATE_PATHS = [
21
21
  ];
22
22
  const ESLINT_RULES_PACKAGE_NAME = '@produck/eslint-rules';
23
23
  const ESLINT_CONFIG_FILE = 'eslint.config.mjs';
24
+ const REQUIRED_ESLINT_ENTRIES = [
25
+ 'ProduckRule.config.ecma',
26
+ 'ProduckRule.config.json',
27
+ 'ProduckRule.config.markdown',
28
+ 'ProduckRule.excludeGitIgnore(import.meta.url)',
29
+ ];
24
30
 
25
31
  const REQUIRED_LINT_SCRIPT_KEY = 'produck:lint';
26
32
  const REQUIRED_LINT_SCRIPT_VALUE = 'eslint --fix . --max-warnings=0';
@@ -54,16 +60,27 @@ function readFileIfExists(filePath) {
54
60
  return fs.readFileSync(filePath, 'utf8');
55
61
  }
56
62
 
57
- function getRequiredEslintRulesDevDependency() {
58
- // Prefer the in-tree source of truth: when sync-lint runs from inside the
59
- // monorepo, the eslint-rules package.json is the authoritative version. When
60
- // sync-lint runs as an installed dependency, fall back to the publish-assets
61
- // tooling baseline (which build-publish-assets injects at prepack time from
62
- // the same package.json).
63
+ const ESLINT_TOOLING_PACKAGE_NAMES = [
64
+ 'eslint',
65
+ '@eslint/js',
66
+ '@eslint/json',
67
+ '@eslint/markdown',
68
+ '@eslint/config-helpers',
69
+ 'typescript-eslint',
70
+ 'globals',
71
+ ];
72
+
73
+ function getRequiredEslintDevDependencies() {
74
+ // Prefer the in-tree source of truth for @produck/eslint-rules: when
75
+ // sync-lint runs inside the monorepo, eslint-rules/package.json is
76
+ // authoritative. When running as an installed dependency, fall back to the
77
+ // publish-assets tooling baseline.
63
78
  const inTreeEslintRulesPkgPath = path.resolve(
64
79
  REPO_ROOT,
65
80
  'packages/eslint-rules/package.json',
66
81
  );
82
+
83
+ let eslintRulesVersion = '';
67
84
  if (fs.existsSync(inTreeEslintRulesPkgPath)) {
68
85
  const eslintRulesPkg = parseJsonFile(
69
86
  inTreeEslintRulesPkgPath,
@@ -71,13 +88,13 @@ function getRequiredEslintRulesDevDependency() {
71
88
  );
72
89
  // The '' fallback is for when the in-tree package.json has a non-string
73
90
  // version field, which never occurs for this package.
74
- const version =
91
+ const v =
75
92
  typeof eslintRulesPkg.version === 'string'
76
93
  ? eslintRulesPkg.version.trim()
77
94
  : /* c8 ignore next */
78
95
  '';
79
- if (version) {
80
- return version;
96
+ if (v) {
97
+ eslintRulesVersion = v;
81
98
  }
82
99
  }
83
100
 
@@ -87,9 +104,9 @@ function getRequiredEslintRulesDevDependency() {
87
104
  },
88
105
  );
89
106
 
107
+ /* c8 ignore next 7 */
90
108
  if (!toolingBaselinePath) {
91
- console.error('Cannot resolve @produck/eslint-rules version. Looked at:');
92
- console.error(`- ${inTreeEslintRulesPkgPath}`);
109
+ console.error('Cannot resolve ESLint tooling versions. Looked at:');
93
110
  for (const candidatePath of TOOLING_BASELINE_CANDIDATE_PATHS) {
94
111
  console.error(`- ${candidatePath}`);
95
112
  }
@@ -97,21 +114,40 @@ function getRequiredEslintRulesDevDependency() {
97
114
  }
98
115
 
99
116
  const baseline = parseJsonFile(toolingBaselinePath, 'Tooling baseline file');
100
- const entry = baseline?.tools?.[ESLINT_RULES_PACKAGE_NAME];
101
- // The '' fallback is for when the tooling baseline lacks a string version entry
102
- // for the eslint-rules package, which the repository always provides.
103
- /* c8 ignore next 2 */
104
- const version =
105
- typeof entry?.version === 'string' ? entry.version.trim() : '';
106
-
107
- if (!version) {
108
- console.error(
109
- `Tooling baseline tools["${ESLINT_RULES_PACKAGE_NAME}"].version must be a non-empty string: ${toolingBaselinePath}`,
110
- );
111
- process.exit(2);
117
+
118
+ /* c8 ignore next 12 */
119
+ if (!eslintRulesVersion) {
120
+ const entry = baseline?.tools?.[ESLINT_RULES_PACKAGE_NAME];
121
+ const v = typeof entry?.version === 'string' ? entry.version.trim() : '';
122
+ if (!v) {
123
+ console.error(
124
+ `Tooling baseline tools["${ESLINT_RULES_PACKAGE_NAME}"].version must be a non-empty string: ${toolingBaselinePath}`,
125
+ );
126
+ process.exit(2);
127
+ }
128
+ eslintRulesVersion = v;
112
129
  }
113
130
 
114
- return version;
131
+ const deps = { [ESLINT_RULES_PACKAGE_NAME]: eslintRulesVersion };
132
+
133
+ for (const name of ESLINT_TOOLING_PACKAGE_NAMES) {
134
+ const entry = baseline?.tools?.[name];
135
+ const v =
136
+ typeof entry?.version === 'string'
137
+ ? entry.version.trim()
138
+ : /* c8 ignore next */
139
+ '';
140
+ /* c8 ignore next 6 */
141
+ if (!v) {
142
+ console.error(
143
+ `Tooling baseline tools["${name}"].version must be a non-empty string: ${toolingBaselinePath}`,
144
+ );
145
+ process.exit(2);
146
+ }
147
+ deps[name] = v;
148
+ }
149
+
150
+ return deps;
115
151
  }
116
152
 
117
153
  function patchEslintConfig(existing) {
@@ -139,7 +175,7 @@ function patchEslintConfig(existing) {
139
175
  }
140
176
 
141
177
  output =
142
- `${output.slice(0, exportEnd)} ProduckRule.config,\n ProduckRule.excludeGitIgnore(import.meta.url),\n` +
178
+ `${output.slice(0, exportEnd)} ProduckRule.config.ecma,\n ProduckRule.config.json,\n ProduckRule.config.markdown,\n ProduckRule.excludeGitIgnore(import.meta.url),\n` +
143
179
  output.slice(exportEnd);
144
180
 
145
181
  if (!output.endsWith('\n')) {
@@ -186,19 +222,15 @@ export function runSyncLint(options) {
186
222
  typeof scripts[REQUIRED_LINT_SCRIPT_KEY] === 'string'
187
223
  ? scripts[REQUIRED_LINT_SCRIPT_KEY]
188
224
  : null;
189
- const previousEslintRules =
190
- typeof devDependencies['@produck/eslint-rules'] === 'string'
191
- ? devDependencies['@produck/eslint-rules']
192
- : null;
193
-
194
- const requiredEslintRulesDependency = getRequiredEslintRulesDevDependency();
225
+ const requiredEslintDevDeps = getRequiredEslintDevDependencies();
195
226
 
196
227
  const eslintConfigPath = path.resolve(cwd, ESLINT_CONFIG_FILE);
197
228
  const previousEslintConfig = readFileIfExists(eslintConfigPath);
198
229
 
199
230
  const matchesRequiredLint = previousLint === REQUIRED_LINT_SCRIPT_VALUE;
200
- const matchesRequiredEslintRules =
201
- previousEslintRules === requiredEslintRulesDependency;
231
+ const matchesRequiredEslintDeps = Object.entries(requiredEslintDevDeps).every(
232
+ ([name, version]) => devDependencies[name] === version,
233
+ );
202
234
 
203
235
  let eslintConfigAction = 'unchanged';
204
236
  let matchesRequiredEslintConfig = false;
@@ -209,8 +241,14 @@ export function runSyncLint(options) {
209
241
  nextEslintConfigText = REQUIRED_ESLINT_CONFIG;
210
242
  } else if (previousEslintConfig === REQUIRED_ESLINT_CONFIG) {
211
243
  matchesRequiredEslintConfig = true;
212
- } else if (previousEslintConfig.includes('@produck/eslint-rules')) {
244
+ } else if (
245
+ previousEslintConfig.includes(ESLINT_RULES_PACKAGE_NAME) &&
246
+ REQUIRED_ESLINT_ENTRIES.every((e) => previousEslintConfig.includes(e))
247
+ ) {
213
248
  matchesRequiredEslintConfig = true;
249
+ } else if (previousEslintConfig.includes(ESLINT_RULES_PACKAGE_NAME)) {
250
+ eslintConfigAction = 'replaced';
251
+ nextEslintConfigText = REQUIRED_ESLINT_CONFIG;
214
252
  } else {
215
253
  const patched = patchEslintConfig(previousEslintConfig);
216
254
  if (patched.ok) {
@@ -223,7 +261,7 @@ export function runSyncLint(options) {
223
261
 
224
262
  const requiresUpdate =
225
263
  !matchesRequiredLint ||
226
- !matchesRequiredEslintRules ||
264
+ !matchesRequiredEslintDeps ||
227
265
  !matchesRequiredEslintConfig;
228
266
  const hasUnpatchableEslintConfig = eslintConfigAction === 'unpatchable';
229
267
 
@@ -231,7 +269,9 @@ export function runSyncLint(options) {
231
269
  scripts[REQUIRED_LINT_SCRIPT_KEY] = REQUIRED_LINT_SCRIPT_VALUE;
232
270
  pkg.scripts = scripts;
233
271
 
234
- devDependencies['@produck/eslint-rules'] = requiredEslintRulesDependency;
272
+ for (const [name, version] of Object.entries(requiredEslintDevDeps)) {
273
+ devDependencies[name] = version;
274
+ }
235
275
  pkg.devDependencies = devDependencies;
236
276
 
237
277
  fs.writeFileSync(
@@ -257,22 +297,22 @@ export function runSyncLint(options) {
257
297
  required: {
258
298
  lintScriptKey: REQUIRED_LINT_SCRIPT_KEY,
259
299
  lintScriptValue: REQUIRED_LINT_SCRIPT_VALUE,
260
- eslintRulesVersion: requiredEslintRulesDependency,
300
+ eslintDevDependencies: requiredEslintDevDeps,
261
301
  eslintConfigPath: path.relative(cwd, eslintConfigPath),
262
302
  eslintConfigAction,
263
303
  },
264
304
  status: {
265
305
  matchesRequiredLintBefore: matchesRequiredLint,
266
- matchesRequiredEslintRulesBefore: matchesRequiredEslintRules,
306
+ matchesRequiredEslintDepsBefore: matchesRequiredEslintDeps,
267
307
  matchesRequiredEslintConfigBefore: matchesRequiredEslintConfig,
268
308
  matchesRequiredLintAfter:
269
309
  requiresUpdate && mode === 'sync' && !hasUnpatchableEslintConfig
270
310
  ? true
271
311
  : matchesRequiredLint,
272
- matchesRequiredEslintRulesAfter:
312
+ matchesRequiredEslintDepsAfter:
273
313
  requiresUpdate && mode === 'sync' && !hasUnpatchableEslintConfig
274
314
  ? true
275
- : matchesRequiredEslintRules,
315
+ : matchesRequiredEslintDeps,
276
316
  matchesRequiredEslintConfigAfter:
277
317
  requiresUpdate && mode === 'sync' && !hasUnpatchableEslintConfig
278
318
  ? true
@@ -16,11 +16,16 @@ const LERNA_TEMPLATE_CANDIDATE_PATHS = [
16
16
  ];
17
17
 
18
18
  const REQUIRED_PUBLISH_CHECK_SCRIPT_KEY = 'produck:publish:check';
19
- const REQUIRED_PUBLISH_CHECK_SCRIPT_VALUE =
20
- 'npm run produck:install && npm run produck:coverage && npm run produck:commit:check';
19
+ const REQUIRED_PUBLISH_CHECK_SCRIPT_VALUE = [
20
+ 'npm run produck:install',
21
+ 'npm run produck:coverage',
22
+ 'npm run produck:commit:check',
23
+ ].join(' && ');
21
24
  const REQUIRED_PUBLISH_SCRIPT_KEY = 'produck:publish';
22
- const REQUIRED_PUBLISH_SCRIPT_VALUE =
23
- 'npm run produck:publish:check && npm run publish --';
25
+ const REQUIRED_PUBLISH_SCRIPT_VALUE = [
26
+ 'npm run produck:publish:check',
27
+ 'npm run publish --',
28
+ ].join(' && ');
24
29
  const REQUIRED_LERNA_VERSION_COMMIT_HOOKS = false;
25
30
 
26
31
  export function printSyncPublishHelp() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@produck/agent-toolkit",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Central CLI toolkit for organization AI execution workflows",
5
5
  "type": "module",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "license": "MIT",
31
31
  "devDependencies": {
32
- "@produck/eslint-rules": "^0.3.6",
32
+ "@produck/eslint-rules": "^0.4.0",
33
33
  "c8": "11.0.0"
34
34
  },
35
- "gitHead": "d13162976bfbf23756e678027aaffe464b7c8177"
35
+ "gitHead": "aa9500630476fb423720f0b0056096e0e87e4c21"
36
36
  }
@@ -1,8 +1,6 @@
1
1
  import js from '@eslint/js';
2
2
  import globals from 'globals';
3
3
  import tseslint from 'typescript-eslint';
4
- import json from '@eslint/json';
5
- import markdown from '@eslint/markdown';
6
4
  import { defineConfig } from 'eslint/config';
7
5
  import * as ProduckRule from '@produck/eslint-rules';
8
6
 
@@ -14,19 +12,8 @@ export default defineConfig([
14
12
  languageOptions: { globals: { ...globals.browser, ...globals.node } },
15
13
  },
16
14
  tseslint.configs.recommended,
17
- {
18
- files: ['**/*.json'],
19
- ignores: ['**/package-lock.json'],
20
- plugins: { json },
21
- language: 'json/json',
22
- extends: ['json/recommended'],
23
- },
24
- {
25
- files: ['**/*.md'],
26
- plugins: { markdown },
27
- language: 'markdown/gfm',
28
- extends: ['markdown/recommended'],
29
- },
30
- ProduckRule.config,
15
+ ProduckRule.config.ecma,
16
+ ProduckRule.config.json,
17
+ ProduckRule.config.markdown,
31
18
  ProduckRule.excludeGitIgnore(import.meta.url),
32
19
  ]);
@@ -58,7 +58,7 @@
58
58
  "allowLatest": false
59
59
  },
60
60
  "@produck/eslint-rules": {
61
- "version": "0.3.6",
61
+ "version": "0.4.0",
62
62
  "policy": "pinned",
63
63
  "allowLatest": false
64
64
  }