@produck/agent-toolkit 0.8.2 → 0.9.1
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.
- package/README.md +22 -22
- package/bin/agent-toolkit.mjs +33 -8
- package/bin/build-publish-assets.mjs +132 -24
- package/bin/command/enforce-node-baseline/index.mjs +18 -5
- package/bin/command/preflight/index.mjs +20 -4
- package/bin/command/run-capture/index.mjs +7 -1
- package/bin/command/shared/workspace-validation.mjs +9 -3
- package/bin/command/sync-coverage/index.mjs +103 -48
- package/bin/command/sync-coverage/required-c8-config.json +15 -0
- package/bin/command/sync-editorconfig/index.mjs +2 -1
- package/bin/command/sync-format/index.mjs +92 -37
- package/bin/command/sync-git/index.mjs +97 -35
- package/bin/command/sync-install/index.mjs +10 -3
- package/bin/command/sync-instructions/index.mjs +35 -10
- package/bin/command/sync-lint/eslint.config.template.mjs +32 -0
- package/bin/command/sync-lint/index.mjs +119 -60
- package/bin/command/sync-publish/help.txt +4 -2
- package/bin/command/sync-publish/index.mjs +126 -35
- package/bin/command/validate-commit-msg/index.mjs +46 -25
- package/package.json +5 -3
- package/publish-assets/eslint.config.template.mjs +32 -0
- package/publish-assets/gitignore +3 -0
- package/publish-assets/instructions/produck/20-produck-commit.instructions.md +3 -3
- package/publish-assets/instructions/produck/stale.instructions.md +1 -0
- package/publish-assets/instructions/produck/tooling-version-baseline.json +36 -1
- package/publish-assets/lerna.json +14 -0
- package/publish-assets/prettierrc +11 -0
|
@@ -13,8 +13,14 @@ const PACKAGE_ROOT = path.resolve(COMMAND_DIR, '../../..');
|
|
|
13
13
|
const REPO_ROOT = path.resolve(PACKAGE_ROOT, '../..');
|
|
14
14
|
const TOOLKIT_PACKAGE_JSON = path.resolve(PACKAGE_ROOT, 'package.json');
|
|
15
15
|
const TOOLING_BASELINE_CANDIDATE_PATHS = [
|
|
16
|
-
path.resolve(
|
|
17
|
-
|
|
16
|
+
path.resolve(
|
|
17
|
+
REPO_ROOT,
|
|
18
|
+
'.github/distribution/produck/tooling-version-baseline.json',
|
|
19
|
+
),
|
|
20
|
+
path.resolve(
|
|
21
|
+
PACKAGE_ROOT,
|
|
22
|
+
'publish-assets/instructions/produck/tooling-version-baseline.json',
|
|
23
|
+
),
|
|
18
24
|
];
|
|
19
25
|
|
|
20
26
|
const GITATTRIBUTES_FILE = '.gitattributes';
|
|
@@ -26,7 +32,8 @@ const REQUIRED_BASELINE_SCRIPT_KEY = 'produck:baseline';
|
|
|
26
32
|
const REQUIRED_BASELINE_SCRIPT_VALUE =
|
|
27
33
|
'npm exec --package=@produck/agent-toolkit@latest -- agent-toolkit enforce-node-baseline --cwd .';
|
|
28
34
|
const REQUIRED_COMMIT_CHECK_SCRIPT_KEY = 'produck:commit:check';
|
|
29
|
-
const REQUIRED_COMMIT_CHECK_SCRIPT_VALUE =
|
|
35
|
+
const REQUIRED_COMMIT_CHECK_SCRIPT_VALUE =
|
|
36
|
+
'npm run produck:format && npm run produck:lint';
|
|
30
37
|
const REQUIRED_PREPARE_SCRIPT_KEY = 'prepare';
|
|
31
38
|
const REQUIRED_PREPARE_SCRIPT_VALUE = 'husky';
|
|
32
39
|
|
|
@@ -39,7 +46,8 @@ const GITIGNORE_SOURCE_CANDIDATE_PATHS = [
|
|
|
39
46
|
path.resolve(PACKAGE_ROOT, 'publish-assets/gitignore'),
|
|
40
47
|
];
|
|
41
48
|
|
|
42
|
-
const REQUIRED_PRE_COMMIT_HOOK =
|
|
49
|
+
const REQUIRED_PRE_COMMIT_HOOK =
|
|
50
|
+
'#!/usr/bin/env sh\nnpm run produck:commit:check\n';
|
|
43
51
|
const REQUIRED_COMMIT_MSG_HOOK =
|
|
44
52
|
'#!/usr/bin/env sh\nnode ./node_modules/@produck/agent-toolkit/bin/agent-toolkit.mjs validate-commit-msg --file "$1"\n';
|
|
45
53
|
|
|
@@ -57,26 +65,40 @@ function parseJsonFile(filePath, label) {
|
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
function getRequiredToolkitDevDependency() {
|
|
60
|
-
const overrideVersion = String(
|
|
68
|
+
const overrideVersion = String(
|
|
69
|
+
process.env.PRODUCK_TOOLKIT_VERSION_OVERRIDE || '',
|
|
70
|
+
).trim();
|
|
61
71
|
if (overrideVersion) {
|
|
62
72
|
return overrideVersion;
|
|
63
73
|
}
|
|
64
|
-
|
|
74
|
+
// The 'npm' (non-.cmd) branch is only reached on non-Windows platforms.
|
|
75
|
+
// Tests run on Windows only.
|
|
76
|
+
/* c8 ignore next */
|
|
65
77
|
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
66
|
-
const latestResult = spawnSync(
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
const latestResult = spawnSync(
|
|
79
|
+
npmCommand,
|
|
80
|
+
['view', '@produck/agent-toolkit', 'version'],
|
|
81
|
+
{
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
},
|
|
84
|
+
);
|
|
69
85
|
|
|
70
86
|
const latestVersion = String(latestResult.stdout || '').trim();
|
|
87
|
+
// The npm registry call succeeds with a version in production but is not made
|
|
88
|
+
// during tests (no network access).
|
|
89
|
+
/* c8 ignore start */
|
|
71
90
|
if (latestResult.status === 0 && latestVersion) {
|
|
72
91
|
return latestVersion;
|
|
73
92
|
}
|
|
93
|
+
/* c8 ignore stop */
|
|
74
94
|
|
|
75
95
|
const pkg = parseJsonFile(TOOLKIT_PACKAGE_JSON, 'Toolkit package.json');
|
|
76
96
|
const version = typeof pkg.version === 'string' ? pkg.version.trim() : '';
|
|
77
97
|
|
|
78
98
|
if (!version) {
|
|
79
|
-
console.error(
|
|
99
|
+
console.error(
|
|
100
|
+
`Toolkit package version is missing: ${TOOLKIT_PACKAGE_JSON}`,
|
|
101
|
+
);
|
|
80
102
|
process.exit(2);
|
|
81
103
|
}
|
|
82
104
|
|
|
@@ -84,12 +106,16 @@ function getRequiredToolkitDevDependency() {
|
|
|
84
106
|
}
|
|
85
107
|
|
|
86
108
|
function loadToolingBaseline() {
|
|
87
|
-
const toolingBaselinePath = TOOLING_BASELINE_CANDIDATE_PATHS.find(
|
|
88
|
-
|
|
89
|
-
|
|
109
|
+
const toolingBaselinePath = TOOLING_BASELINE_CANDIDATE_PATHS.find(
|
|
110
|
+
(candidatePath) => {
|
|
111
|
+
return fs.existsSync(candidatePath);
|
|
112
|
+
},
|
|
113
|
+
);
|
|
90
114
|
|
|
91
115
|
if (!toolingBaselinePath) {
|
|
92
|
-
console.error(
|
|
116
|
+
console.error(
|
|
117
|
+
'Tooling baseline file does not exist in expected locations:',
|
|
118
|
+
);
|
|
93
119
|
for (const candidatePath of TOOLING_BASELINE_CANDIDATE_PATHS) {
|
|
94
120
|
console.error(`- ${candidatePath}`);
|
|
95
121
|
}
|
|
@@ -134,16 +160,20 @@ function findMissingGitignoreEntries(currentContent, requiredEntries) {
|
|
|
134
160
|
return [...requiredEntries];
|
|
135
161
|
}
|
|
136
162
|
|
|
137
|
-
const existingLines = new Set(
|
|
163
|
+
const existingLines = new Set(
|
|
164
|
+
currentContent.split('\n').map((line) => line.trimEnd()),
|
|
165
|
+
);
|
|
138
166
|
|
|
139
167
|
return requiredEntries.filter((entry) => !existingLines.has(entry));
|
|
140
168
|
}
|
|
141
169
|
|
|
142
170
|
function loadGitSourceFiles() {
|
|
143
|
-
const gitattributesSourcePath = GITATTRIBUTES_SOURCE_CANDIDATE_PATHS.find(
|
|
171
|
+
const gitattributesSourcePath = GITATTRIBUTES_SOURCE_CANDIDATE_PATHS.find(
|
|
172
|
+
(p) => fs.existsSync(p),
|
|
173
|
+
);
|
|
174
|
+
const gitignoreSourcePath = GITIGNORE_SOURCE_CANDIDATE_PATHS.find((p) =>
|
|
144
175
|
fs.existsSync(p),
|
|
145
176
|
);
|
|
146
|
-
const gitignoreSourcePath = GITIGNORE_SOURCE_CANDIDATE_PATHS.find((p) => fs.existsSync(p));
|
|
147
177
|
|
|
148
178
|
if (!gitattributesSourcePath) {
|
|
149
179
|
console.error('Org .gitattributes source not found in expected locations:');
|
|
@@ -175,7 +205,9 @@ function loadGitSourceFiles() {
|
|
|
175
205
|
|
|
176
206
|
function buildScriptState(pkg) {
|
|
177
207
|
const scripts =
|
|
178
|
-
pkg.scripts &&
|
|
208
|
+
pkg.scripts &&
|
|
209
|
+
typeof pkg.scripts === 'object' &&
|
|
210
|
+
!Array.isArray(pkg.scripts)
|
|
179
211
|
? { ...pkg.scripts }
|
|
180
212
|
: {};
|
|
181
213
|
|
|
@@ -207,8 +239,14 @@ function buildDevDependencyState(pkg) {
|
|
|
207
239
|
return {
|
|
208
240
|
devDependencies,
|
|
209
241
|
previousManaged: {
|
|
210
|
-
husky:
|
|
211
|
-
|
|
242
|
+
husky:
|
|
243
|
+
typeof devDependencies.husky === 'string'
|
|
244
|
+
? devDependencies.husky
|
|
245
|
+
: null,
|
|
246
|
+
lerna:
|
|
247
|
+
typeof devDependencies.lerna === 'string'
|
|
248
|
+
? devDependencies.lerna
|
|
249
|
+
: null,
|
|
212
250
|
'@produck/agent-toolkit':
|
|
213
251
|
typeof devDependencies['@produck/agent-toolkit'] === 'string'
|
|
214
252
|
? devDependencies['@produck/agent-toolkit']
|
|
@@ -260,11 +298,15 @@ export function runSyncGit(options) {
|
|
|
260
298
|
requiredDevDependencies,
|
|
261
299
|
);
|
|
262
300
|
|
|
263
|
-
const matchesRequiredBaseline = !(
|
|
301
|
+
const matchesRequiredBaseline = !(
|
|
302
|
+
REQUIRED_BASELINE_SCRIPT_KEY in scriptValidation.mismatches
|
|
303
|
+
);
|
|
264
304
|
const matchesRequiredCommitCheck = !(
|
|
265
305
|
REQUIRED_COMMIT_CHECK_SCRIPT_KEY in scriptValidation.mismatches
|
|
266
306
|
);
|
|
267
|
-
const matchesRequiredPrepare = !(
|
|
307
|
+
const matchesRequiredPrepare = !(
|
|
308
|
+
REQUIRED_PREPARE_SCRIPT_KEY in scriptValidation.mismatches
|
|
309
|
+
);
|
|
268
310
|
const matchesRequiredManagedDevDependencies = dependencyValidation.ok;
|
|
269
311
|
|
|
270
312
|
const gitAttributesPath = path.resolve(cwd, GITATTRIBUTES_FILE);
|
|
@@ -280,14 +322,17 @@ export function runSyncGit(options) {
|
|
|
280
322
|
const gitignoreExists = currentGitignoreContent !== null;
|
|
281
323
|
const preCommitHookExists = currentPreCommitHook !== null;
|
|
282
324
|
const commitMsgHookExists = currentCommitMsgHook !== null;
|
|
283
|
-
const matchesRequiredGitAttributes =
|
|
325
|
+
const matchesRequiredGitAttributes =
|
|
326
|
+
currentContent === requiredGitAttributesContent;
|
|
284
327
|
const missingGitignoreEntries = findMissingGitignoreEntries(
|
|
285
328
|
currentGitignoreContent,
|
|
286
329
|
gitignoreRequiredEntries,
|
|
287
330
|
);
|
|
288
331
|
const matchesRequiredGitignore = missingGitignoreEntries.length === 0;
|
|
289
|
-
const matchesRequiredPreCommitHook =
|
|
290
|
-
|
|
332
|
+
const matchesRequiredPreCommitHook =
|
|
333
|
+
currentPreCommitHook === REQUIRED_PRE_COMMIT_HOOK;
|
|
334
|
+
const matchesRequiredCommitMsgHook =
|
|
335
|
+
currentCommitMsgHook === REQUIRED_COMMIT_MSG_HOOK;
|
|
291
336
|
|
|
292
337
|
const mismatches = [];
|
|
293
338
|
if (!matchesRequiredGitAttributes) {
|
|
@@ -337,16 +382,23 @@ export function runSyncGit(options) {
|
|
|
337
382
|
fs.writeFileSync(gitignorePath, gitignoreOrgContent, 'utf8');
|
|
338
383
|
} else {
|
|
339
384
|
const appendText = `\n# produck:org-baseline\n${missingGitignoreEntries.join('\n')}\n`;
|
|
340
|
-
fs.writeFileSync(
|
|
385
|
+
fs.writeFileSync(
|
|
386
|
+
gitignorePath,
|
|
387
|
+
currentGitignoreContent + appendText,
|
|
388
|
+
'utf8',
|
|
389
|
+
);
|
|
341
390
|
}
|
|
342
391
|
}
|
|
343
392
|
|
|
344
393
|
fs.writeFileSync(preCommitHookPath, REQUIRED_PRE_COMMIT_HOOK, 'utf8');
|
|
345
394
|
fs.writeFileSync(commitMsgHookPath, REQUIRED_COMMIT_MSG_HOOK, 'utf8');
|
|
346
395
|
|
|
347
|
-
scriptState.scripts[REQUIRED_BASELINE_SCRIPT_KEY] =
|
|
348
|
-
|
|
349
|
-
scriptState.scripts[
|
|
396
|
+
scriptState.scripts[REQUIRED_BASELINE_SCRIPT_KEY] =
|
|
397
|
+
REQUIRED_BASELINE_SCRIPT_VALUE;
|
|
398
|
+
scriptState.scripts[REQUIRED_COMMIT_CHECK_SCRIPT_KEY] =
|
|
399
|
+
REQUIRED_COMMIT_CHECK_SCRIPT_VALUE;
|
|
400
|
+
scriptState.scripts[REQUIRED_PREPARE_SCRIPT_KEY] =
|
|
401
|
+
REQUIRED_PREPARE_SCRIPT_VALUE;
|
|
350
402
|
pkg.scripts = scriptState.scripts;
|
|
351
403
|
|
|
352
404
|
for (const [name, version] of Object.entries(requiredDevDependencies)) {
|
|
@@ -354,7 +406,11 @@ export function runSyncGit(options) {
|
|
|
354
406
|
}
|
|
355
407
|
pkg.devDependencies = dependencyState.devDependencies;
|
|
356
408
|
|
|
357
|
-
fs.writeFileSync(
|
|
409
|
+
fs.writeFileSync(
|
|
410
|
+
rootPackageJsonPath,
|
|
411
|
+
`${JSON.stringify(pkg, null, 2)}\n`,
|
|
412
|
+
'utf8',
|
|
413
|
+
);
|
|
358
414
|
}
|
|
359
415
|
|
|
360
416
|
const report = {
|
|
@@ -393,12 +449,16 @@ export function runSyncGit(options) {
|
|
|
393
449
|
matchesRequiredBaselineBefore: matchesRequiredBaseline,
|
|
394
450
|
matchesRequiredCommitCheckBefore: matchesRequiredCommitCheck,
|
|
395
451
|
matchesRequiredPrepareBefore: matchesRequiredPrepare,
|
|
396
|
-
matchesRequiredManagedDevDependenciesBefore:
|
|
452
|
+
matchesRequiredManagedDevDependenciesBefore:
|
|
453
|
+
matchesRequiredManagedDevDependencies,
|
|
397
454
|
mismatchesBefore: mismatches,
|
|
398
455
|
fileExistsAfter: requiresUpdate && mode === 'sync' ? true : fileExists,
|
|
399
|
-
gitignoreExistsAfter:
|
|
400
|
-
|
|
401
|
-
|
|
456
|
+
gitignoreExistsAfter:
|
|
457
|
+
requiresUpdate && mode === 'sync' ? true : gitignoreExists,
|
|
458
|
+
preCommitHookExistsAfter:
|
|
459
|
+
requiresUpdate && mode === 'sync' ? true : preCommitHookExists,
|
|
460
|
+
commitMsgHookExistsAfter:
|
|
461
|
+
requiresUpdate && mode === 'sync' ? true : commitMsgHookExists,
|
|
402
462
|
matchesRequiredGitAttributesAfter:
|
|
403
463
|
requiresUpdate && mode === 'sync' ? true : matchesRequiredGitAttributes,
|
|
404
464
|
matchesRequiredGitignoreAfter:
|
|
@@ -416,7 +476,9 @@ export function runSyncGit(options) {
|
|
|
416
476
|
matchesRequiredPrepareAfter:
|
|
417
477
|
requiresUpdate && mode === 'sync' ? true : matchesRequiredPrepare,
|
|
418
478
|
matchesRequiredManagedDevDependenciesAfter:
|
|
419
|
-
requiresUpdate && mode === 'sync'
|
|
479
|
+
requiresUpdate && mode === 'sync'
|
|
480
|
+
? true
|
|
481
|
+
: matchesRequiredManagedDevDependencies,
|
|
420
482
|
mismatchesAfter: requiresUpdate && mode === 'sync' ? [] : mismatches,
|
|
421
483
|
updated: requiresUpdate && mode === 'sync',
|
|
422
484
|
},
|
|
@@ -44,7 +44,9 @@ export function runSyncInstall(options) {
|
|
|
44
44
|
|
|
45
45
|
const pkg = parseJsonFile(rootPackageJsonPath, 'Root package.json');
|
|
46
46
|
const scripts =
|
|
47
|
-
pkg.scripts &&
|
|
47
|
+
pkg.scripts &&
|
|
48
|
+
typeof pkg.scripts === 'object' &&
|
|
49
|
+
!Array.isArray(pkg.scripts)
|
|
48
50
|
? { ...pkg.scripts }
|
|
49
51
|
: {};
|
|
50
52
|
|
|
@@ -57,7 +59,8 @@ export function runSyncInstall(options) {
|
|
|
57
59
|
? scripts[LEGACY_INSTALL_SCRIPT_KEY]
|
|
58
60
|
: null;
|
|
59
61
|
|
|
60
|
-
const matchesRequiredInstall =
|
|
62
|
+
const matchesRequiredInstall =
|
|
63
|
+
previousInstall === REQUIRED_INSTALL_SCRIPT_VALUE;
|
|
61
64
|
const legacyInstallScriptPresent = previousLegacyInstall !== null;
|
|
62
65
|
const requiresUpdate = !matchesRequiredInstall || legacyInstallScriptPresent;
|
|
63
66
|
|
|
@@ -65,7 +68,11 @@ export function runSyncInstall(options) {
|
|
|
65
68
|
delete scripts[LEGACY_INSTALL_SCRIPT_KEY];
|
|
66
69
|
scripts[REQUIRED_INSTALL_SCRIPT_KEY] = REQUIRED_INSTALL_SCRIPT_VALUE;
|
|
67
70
|
pkg.scripts = scripts;
|
|
68
|
-
fs.writeFileSync(
|
|
71
|
+
fs.writeFileSync(
|
|
72
|
+
rootPackageJsonPath,
|
|
73
|
+
`${JSON.stringify(pkg, null, 2)}\n`,
|
|
74
|
+
'utf8',
|
|
75
|
+
);
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
const report = {
|
|
@@ -3,18 +3,30 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
|
|
5
5
|
import { getSingle, hasFlag } from '../shared/args.mjs';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
loadTextResource,
|
|
8
|
+
printTextResource,
|
|
9
|
+
} from '../shared/text-resource.mjs';
|
|
7
10
|
|
|
8
11
|
const COMMAND_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
9
12
|
const PACKAGE_ROOT = path.resolve(COMMAND_DIR, '../../..');
|
|
10
13
|
const PUBLISH_ASSETS_ROOT = path.resolve(PACKAGE_ROOT, 'publish-assets');
|
|
11
|
-
const PUBLISH_INSTRUCTIONS_ROOT = path.resolve(
|
|
12
|
-
|
|
14
|
+
const PUBLISH_INSTRUCTIONS_ROOT = path.resolve(
|
|
15
|
+
PUBLISH_ASSETS_ROOT,
|
|
16
|
+
'instructions',
|
|
17
|
+
);
|
|
18
|
+
const PUBLISH_NAMESPACE_ROOT = path.resolve(
|
|
19
|
+
PUBLISH_INSTRUCTIONS_ROOT,
|
|
20
|
+
'produck',
|
|
21
|
+
);
|
|
13
22
|
const MANAGED_MARKER = '<!-- managed-by: @produck/agent-toolkit -->';
|
|
14
23
|
const DEFAULT_NAMESPACE_OUT_DIR = '.github/instructions/produck';
|
|
15
24
|
const USER_SPACE_ENTRYPOINT = '.github/copilot-instructions.md';
|
|
16
25
|
const HELP_FILE = path.resolve(COMMAND_DIR, 'help.txt');
|
|
17
|
-
const USER_SPACE_BOOTSTRAP_FILE = path.resolve(
|
|
26
|
+
const USER_SPACE_BOOTSTRAP_FILE = path.resolve(
|
|
27
|
+
COMMAND_DIR,
|
|
28
|
+
'user-space-bootstrap.md',
|
|
29
|
+
);
|
|
18
30
|
|
|
19
31
|
export function printSyncInstructionsHelp() {
|
|
20
32
|
printTextResource(HELP_FILE);
|
|
@@ -46,7 +58,9 @@ function loadDefaultInstructionsTemplate() {
|
|
|
46
58
|
}
|
|
47
59
|
|
|
48
60
|
console.error('No built-in instruction assets found.');
|
|
49
|
-
console.error(
|
|
61
|
+
console.error(
|
|
62
|
+
'Run prepack/publish to generate publish-assets, or pass --source explicitly.',
|
|
63
|
+
);
|
|
50
64
|
process.exit(2);
|
|
51
65
|
}
|
|
52
66
|
|
|
@@ -75,9 +89,14 @@ function isManagedFile(filePath) {
|
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
function buildUserSpaceBootstrapContent(namespaceDirPath, cwd) {
|
|
78
|
-
const namespaceDisplayPath = path
|
|
92
|
+
const namespaceDisplayPath = path
|
|
93
|
+
.relative(cwd, namespaceDirPath)
|
|
94
|
+
.replace(/\\/g, '/');
|
|
79
95
|
let content = loadTextResource(USER_SPACE_BOOTSTRAP_FILE);
|
|
80
|
-
content = content.replace(
|
|
96
|
+
content = content.replace(
|
|
97
|
+
/\{\{NAMESPACE_GLOB\}\}/g,
|
|
98
|
+
`${namespaceDisplayPath}/*.instructions.md`,
|
|
99
|
+
);
|
|
81
100
|
if (!content.endsWith('\n')) {
|
|
82
101
|
content = `${content}\n`;
|
|
83
102
|
}
|
|
@@ -114,7 +133,9 @@ export function runSyncInstructions(options) {
|
|
|
114
133
|
sourceResolved = sourcePath;
|
|
115
134
|
entries = readInstructionEntriesFromDirectory(sourcePath);
|
|
116
135
|
if (entries.length === 0) {
|
|
117
|
-
console.error(
|
|
136
|
+
console.error(
|
|
137
|
+
`No .instructions.md files in source directory: ${sourcePath}`,
|
|
138
|
+
);
|
|
118
139
|
process.exit(2);
|
|
119
140
|
}
|
|
120
141
|
} else {
|
|
@@ -138,7 +159,9 @@ export function runSyncInstructions(options) {
|
|
|
138
159
|
const outLooksLikeFile = outArg.endsWith('.md');
|
|
139
160
|
|
|
140
161
|
if (outLooksLikeFile && entries.length > 1) {
|
|
141
|
-
console.error(
|
|
162
|
+
console.error(
|
|
163
|
+
'Target --out is a file path but source has multiple instruction files.',
|
|
164
|
+
);
|
|
142
165
|
console.error('Use an output directory for multi-file sync.');
|
|
143
166
|
process.exit(2);
|
|
144
167
|
}
|
|
@@ -190,7 +213,9 @@ export function runSyncInstructions(options) {
|
|
|
190
213
|
}
|
|
191
214
|
}
|
|
192
215
|
|
|
193
|
-
const toWrite = planned.filter(
|
|
216
|
+
const toWrite = planned.filter(
|
|
217
|
+
(item) => !unchanged.includes(item.targetPath),
|
|
218
|
+
);
|
|
194
219
|
|
|
195
220
|
const pruneDeletes = [];
|
|
196
221
|
if (prune && fs.existsSync(outDir)) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import tseslint from 'typescript-eslint';
|
|
4
|
+
import json from '@eslint/json';
|
|
5
|
+
import markdown from '@eslint/markdown';
|
|
6
|
+
import { defineConfig } from 'eslint/config';
|
|
7
|
+
import * as ProduckRule from '@produck/eslint-rules';
|
|
8
|
+
|
|
9
|
+
export default defineConfig([
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
|
|
12
|
+
plugins: { js },
|
|
13
|
+
extends: ['js/recommended'],
|
|
14
|
+
languageOptions: { globals: { ...globals.browser, ...globals.node } },
|
|
15
|
+
},
|
|
16
|
+
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,
|
|
31
|
+
ProduckRule.excludeGitIgnore(import.meta.url),
|
|
32
|
+
]);
|