@abarcenas/ai-workflow-template 1.29.0 → 1.33.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.
- package/.agents/instructions/learned-knowledge.instructions.md +46 -0
- package/.github/workflows/npm-publish.yml +3 -0
- package/.github/workflows/pr-test.yml +23 -0
- package/.husky/post-merge +1 -0
- package/.husky/pre-commit +2 -0
- package/README.md +48 -1
- package/bin/setup.js +23 -0
- package/package.json +7 -2
- package/scripts/setup/constants.js +226 -0
- package/scripts/setup/discover.js +261 -0
- package/scripts/setup/discover.test.js +408 -0
- package/scripts/setup/hooks.js +280 -0
- package/scripts/setup/hooks.test.js +527 -0
- package/scripts/setup/husky-init.js +127 -0
- package/scripts/setup/index.js +354 -0
- package/scripts/setup/index.test.js +664 -0
- package/scripts/setup/prepare.js +127 -0
- package/scripts/setup/prepare.test.js +718 -0
- package/scripts/setup/sync-phase.js +179 -0
- package/scripts/setup/sync-phase.test.js +195 -0
- package/scripts/setup/ui.js +521 -0
- package/scripts/setup/utils.js +371 -0
- package/scripts/sync.js +9 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// prepare.js — Handle consumer package.json prepare script
|
|
3
|
+
// ═════════════════════════════════════════════════════════════════════════════
|
|
4
|
+
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
|
|
7
|
+
import { safeWriteJson } from './utils.js'
|
|
8
|
+
import { step, stepSuccess, stepWarn } from './ui.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Handles the prepare script in the consumer's package.json.
|
|
12
|
+
*
|
|
13
|
+
* Merges `"husky"` into the `scripts.prepare` field according to the
|
|
14
|
+
* classification of the existing (or absent) prepare script:
|
|
15
|
+
*
|
|
16
|
+
* | # | Condition | Action | Return action |
|
|
17
|
+
* |---|------------------------------------|--------------------------|----------------|
|
|
18
|
+
* | 1 | No `package.json` | Skip with warning | `skipped` |
|
|
19
|
+
* | 2 | Prepare already contains "husky" | Skip (already configured)| `skipped` |
|
|
20
|
+
* | 3 | No prepare script | Set to `"husky"` | `added` |
|
|
21
|
+
* | 4 | Simple prepare (single command) | Append `&& husky` | `merged` |
|
|
22
|
+
* | 5 | Complex prepare + `--force` | Replace with `"husky"` | `added` |
|
|
23
|
+
* | 5 | Complex prepare, no `--force` | Warn, skip auto-merge | `skipped` |
|
|
24
|
+
* | 6 | `--dry-run` | Log, do not write | `dry-run` |
|
|
25
|
+
*
|
|
26
|
+
* @param {object} context - Context object from discover.js.
|
|
27
|
+
* @param {string} context.consumerRoot - Absolute path to consumer root.
|
|
28
|
+
* @param {object|undefined} context.consumerPackageJson - Parsed package.json.
|
|
29
|
+
* @param {string|undefined} context.existingPrepare - Existing prepare script.
|
|
30
|
+
* @param {boolean} context.prepareIsSimple - Whether the script is simple.
|
|
31
|
+
* @param {boolean} context.dryRun - Do not modify when `true`.
|
|
32
|
+
* @param {boolean} context.force - Force overwrite when `true`.
|
|
33
|
+
* @returns {Promise<{action: string, message: string}>}
|
|
34
|
+
*/
|
|
35
|
+
export async function handlePrepare(context) {
|
|
36
|
+
const {
|
|
37
|
+
consumerRoot,
|
|
38
|
+
consumerPackageJson,
|
|
39
|
+
existingPrepare,
|
|
40
|
+
prepareIsSimple,
|
|
41
|
+
dryRun,
|
|
42
|
+
force,
|
|
43
|
+
} = context
|
|
44
|
+
|
|
45
|
+
// ── Case 1: No package.json ──────────────────────────────────────────
|
|
46
|
+
if (!consumerPackageJson) {
|
|
47
|
+
stepWarn('Skipping prepare script — no package.json found')
|
|
48
|
+
return { action: 'skipped', message: 'No package.json found' }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Case 2: Prepare already includes "husky" ─────────────────────────
|
|
52
|
+
if (existingPrepare && existingPrepare.includes('husky')) {
|
|
53
|
+
stepSuccess('Prepare script already includes husky')
|
|
54
|
+
return { action: 'skipped', message: 'prepare script already includes husky' }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── Case 3: No prepare script ────────────────────────────────────────
|
|
58
|
+
if (!existingPrepare || existingPrepare.trim() === '') {
|
|
59
|
+
if (dryRun) {
|
|
60
|
+
step('[dry-run] Would add "prepare": "husky" to package.json')
|
|
61
|
+
return { action: 'dry-run', message: 'Would add "prepare": "husky" to package.json' }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const pkgPath = join(consumerRoot, 'package.json')
|
|
65
|
+
const updated = {
|
|
66
|
+
...consumerPackageJson,
|
|
67
|
+
scripts: { ...(consumerPackageJson.scripts || {}), prepare: 'husky' },
|
|
68
|
+
}
|
|
69
|
+
safeWriteJson(pkgPath, updated)
|
|
70
|
+
stepSuccess('Added "prepare": "husky" to package.json')
|
|
71
|
+
return { action: 'added', message: 'Added "prepare": "husky" to package.json' }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ── Case 4: Simple prepare script (single command, auto-merge safe) ──
|
|
75
|
+
if (prepareIsSimple) {
|
|
76
|
+
if (dryRun) {
|
|
77
|
+
step(`[dry-run] Would merge husky: "${existingPrepare} && husky"`)
|
|
78
|
+
return { action: 'dry-run', message: `Would merge: "${existingPrepare} && husky"` }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const pkgPath = join(consumerRoot, 'package.json')
|
|
82
|
+
const updated = {
|
|
83
|
+
...consumerPackageJson,
|
|
84
|
+
scripts: {
|
|
85
|
+
...(consumerPackageJson.scripts || {}),
|
|
86
|
+
prepare: `${existingPrepare} && husky`,
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
safeWriteJson(pkgPath, updated)
|
|
90
|
+
stepSuccess('Merged husky into existing prepare script')
|
|
91
|
+
return { action: 'merged', message: 'Merged husky into existing prepare script' }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── Case 5: Complex prepare script ───────────────────────────────────
|
|
95
|
+
// (multi-line, has || or ;, or && chain > 3 — detected by discover.js)
|
|
96
|
+
|
|
97
|
+
// Check dry-run before branching on force
|
|
98
|
+
if (dryRun) {
|
|
99
|
+
if (force) {
|
|
100
|
+
step('[dry-run] Would replace complex prepare script with "husky" (--force)')
|
|
101
|
+
return { action: 'dry-run', message: 'Would replace complex prepare with "husky" (--force)' }
|
|
102
|
+
}
|
|
103
|
+
step('[dry-run] Complex prepare script — would skip (use --force to override)')
|
|
104
|
+
return { action: 'dry-run', message: 'Complex prepare — would skip (use --force to override)' }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (force) {
|
|
108
|
+
const pkgPath = join(consumerRoot, 'package.json')
|
|
109
|
+
const updated = {
|
|
110
|
+
...consumerPackageJson,
|
|
111
|
+
scripts: {
|
|
112
|
+
...(consumerPackageJson.scripts || {}),
|
|
113
|
+
prepare: 'husky',
|
|
114
|
+
},
|
|
115
|
+
}
|
|
116
|
+
safeWriteJson(pkgPath, updated)
|
|
117
|
+
stepSuccess('Replaced complex prepare script with "husky" (--force)')
|
|
118
|
+
return { action: 'added', message: 'Replaced complex prepare script with "husky" (--force)' }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// No --force: warn and skip — consumer must merge manually
|
|
122
|
+
stepWarn(
|
|
123
|
+
'Complex prepare script — skipping auto-merge. ' +
|
|
124
|
+
'Use --force to override, or manually add " && husky" to the prepare script.',
|
|
125
|
+
)
|
|
126
|
+
return { action: 'skipped', message: 'Complex prepare script — manual merge required' }
|
|
127
|
+
}
|