@1aboveio/skills 0.18.0 → 0.19.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 (41) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/runtime/skills/distribution/generated/recipes.json +43 -23
  4. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +1 -1
  5. package/runtime/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +23 -1
  6. package/skills/engineering/engineering-runtime/coherence/workflow.json +65 -15
  7. package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +1 -1
  8. package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +23 -1
  9. package/skills/engineering/resolve-issues/SKILL.md +1 -1
  10. package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +55 -11
  11. package/skills/engineering/resolve-issues/scripts/run-state.mjs +4 -4
  12. package/skills/engineering/resolve-release/references/related-skills.md +1 -0
  13. package/skills/engineering/rush-issues/LICENSE +3 -0
  14. package/skills/engineering/rush-issues/SKILL.md +179 -0
  15. package/skills/engineering/rush-issues/agents/openai.yaml +9 -0
  16. package/skills/engineering/rush-issues/evals/evals.json +65 -0
  17. package/skills/engineering/rush-issues/references/canary.md +45 -0
  18. package/skills/engineering/rush-issues/references/cicd.md +37 -0
  19. package/skills/engineering/rush-issues/references/combine.md +51 -0
  20. package/skills/engineering/rush-issues/references/expire.md +55 -0
  21. package/skills/engineering/rush-issues/references/exploration.md +53 -0
  22. package/skills/engineering/rush-issues/references/implementation.md +66 -0
  23. package/skills/engineering/rush-issues/references/preflight.md +31 -0
  24. package/skills/engineering/rush-issues/references/profiling.md +78 -0
  25. package/skills/engineering/rush-issues/references/review.md +48 -0
  26. package/skills/engineering/rush-issues/references/shared-modules.md +66 -0
  27. package/skills/engineering/rush-issues/references/task-plan.md +110 -0
  28. package/skills/engineering/rush-issues/scripts/discover-models.mjs +9 -0
  29. package/skills/engineering/rush-issues/scripts/model-catalog.mjs +9 -0
  30. package/skills/engineering/rush-issues/scripts/preflight-models.mjs +466 -0
  31. package/skills/engineering/rush-release/LICENSE +3 -0
  32. package/skills/engineering/rush-release/SKILL.md +99 -0
  33. package/skills/engineering/rush-release/agents/openai.yaml +8 -0
  34. package/skills/engineering/rush-release/evals/evals.json +44 -0
  35. package/skills/engineering/rush-release/references/candidate.md +30 -0
  36. package/skills/engineering/rush-release/references/cut.md +66 -0
  37. package/skills/engineering/rush-release/references/preflight.md +47 -0
  38. package/skills/engineering/rush-release/references/publish.md +100 -0
  39. package/skills/engineering/rush-release/scripts/apply.mjs +185 -0
  40. package/skills/engineering/rush-release/scripts/green-head.mjs +231 -0
  41. package/skills/engineering/rush-release/scripts/plan.mjs +264 -0
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env node
2
+ // Changelog + SemVer plan from baseline tag..SHA.
3
+ //
4
+ // Usage:
5
+ // node plan.mjs --sha <sha> [--trunk main] [--json] [--strict]
6
+ //
7
+ // Exit: 0 ok · 1 git/inspect failed · 2 usage
8
+ import { existsSync, readFileSync } from 'node:fs'
9
+ import { join } from 'node:path'
10
+ import { spawnSync } from 'node:child_process'
11
+ import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
12
+
13
+ const SEMVER_RE = /^v?(\d+)\.(\d+)\.(\d+)$/
14
+ const TITLE_RE = /^\s*([a-zA-Z]+)(?:\(([^)]*)\))?(!)?:\s*(.+)$/
15
+ const SECTION_BY_TYPE = {
16
+ feat: 'Added',
17
+ fix: 'Fixed',
18
+ perf: 'Changed',
19
+ refactor: 'Changed',
20
+ revert: 'Removed',
21
+ security: 'Security',
22
+ }
23
+ const INTERNAL_TYPES = new Set(['build', 'chore', 'ci', 'docs', 'style', 'test'])
24
+ const SECTION_ORDER = ['Breaking', 'Added', 'Changed', 'Removed', 'Fixed', 'Security']
25
+
26
+ export function parseSemver(input) {
27
+ const match = SEMVER_RE.exec(String(input || '').trim())
28
+ if (!match) return null
29
+ return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) }
30
+ }
31
+
32
+ export function formatVersion(version) {
33
+ return `${version.major}.${version.minor}.${version.patch}`
34
+ }
35
+
36
+ export function compareVersions(left, right) {
37
+ for (const key of ['major', 'minor', 'patch']) {
38
+ if (left[key] !== right[key]) return left[key] < right[key] ? -1 : 1
39
+ }
40
+ return 0
41
+ }
42
+
43
+ export function latestReleaseTag(tags) {
44
+ const parsed = tags
45
+ .map((tag) => ({ tag, version: parseSemver(tag) }))
46
+ .filter((item) => item.version)
47
+ if (parsed.length === 0) return null
48
+ parsed.sort((left, right) => compareVersions(left.version, right.version))
49
+ return parsed[parsed.length - 1]
50
+ }
51
+
52
+ export function classifySubject(subject, body = '') {
53
+ const title = String(subject || '').trim()
54
+ const match = TITLE_RE.exec(title)
55
+ const type = match ? match[1].toLowerCase() : 'other'
56
+ const breaking = Boolean(match && match[3]) || /(^|\n)BREAKING[ -]CHANGE:/.test(body)
57
+ const internal = INTERNAL_TYPES.has(type)
58
+ const section = breaking ? 'Breaking' : internal ? null : (SECTION_BY_TYPE[type] || 'Changed')
59
+ return {
60
+ title,
61
+ type,
62
+ breaking,
63
+ internal,
64
+ section,
65
+ scope: match ? match[2] || null : null,
66
+ summary: match ? match[4] : title,
67
+ }
68
+ }
69
+
70
+ export function bumpFor(changes, current, { strict = false } = {}) {
71
+ const zeroVer = !strict && current.major === 0
72
+ if (changes.some((change) => change.breaking)) {
73
+ return { bump: zeroVer ? 'minor' : 'major', reason: 'breaking change in the release content' }
74
+ }
75
+ if (changes.some((change) => change.type === 'feat')) {
76
+ return { bump: 'minor', reason: 'new feature in the release content' }
77
+ }
78
+ return { bump: 'patch', reason: 'fixes and internal changes only' }
79
+ }
80
+
81
+ export function nextVersion(current, bump) {
82
+ if (bump === 'major') return { major: current.major + 1, minor: 0, patch: 0 }
83
+ if (bump === 'minor') return { major: current.major, minor: current.minor + 1, patch: 0 }
84
+ return { major: current.major, minor: current.minor, patch: current.patch + 1 }
85
+ }
86
+
87
+ export function renderChangelog({ version, date, changes }) {
88
+ const groups = new Map(SECTION_ORDER.map((name) => [name, []]))
89
+ for (const change of changes) {
90
+ if (!change.section) continue
91
+ const list = groups.get(change.section)
92
+ if (list) list.push(change)
93
+ }
94
+ const lines = [`## [${version}] - ${date}`]
95
+ for (const name of SECTION_ORDER) {
96
+ const items = groups.get(name)
97
+ if (!items.length) continue
98
+ lines.push('', `### ${name}`)
99
+ for (const item of items) lines.push(`- ${item.summary}`)
100
+ }
101
+ if (lines.length === 1) {
102
+ lines.push('', '- See the commits included in this tag.')
103
+ }
104
+ return `${lines.join('\n')}\n`
105
+ }
106
+
107
+ export function discoverVersionFiles(root) {
108
+ const files = []
109
+ for (const name of ['package.json', 'package-lock.json', 'pyproject.toml', 'VERSION']) {
110
+ if (existsSync(join(root, name))) files.push(name)
111
+ }
112
+ return files
113
+ }
114
+
115
+ export function currentVersionFromFiles(root, files = discoverVersionFiles(root)) {
116
+ if (files.includes('package.json')) {
117
+ const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
118
+ const parsed = parseSemver(pkg.version)
119
+ if (parsed) return formatVersion(parsed)
120
+ }
121
+ if (files.includes('pyproject.toml')) {
122
+ const text = readFileSync(join(root, 'pyproject.toml'), 'utf8')
123
+ const match = text.match(/^version\s*=\s*"([^"]+)"/m)
124
+ const parsed = match && parseSemver(match[1])
125
+ if (parsed) return formatVersion(parsed)
126
+ }
127
+ if (files.includes('VERSION')) {
128
+ const parsed = parseSemver(readFileSync(join(root, 'VERSION'), 'utf8'))
129
+ if (parsed) return formatVersion(parsed)
130
+ }
131
+ return null
132
+ }
133
+
134
+ function git(args, cwd) {
135
+ const result = spawnSync('git', args, { encoding: 'utf8', cwd })
136
+ if (result.status !== 0) {
137
+ const err = new Error(result.stderr.trim() || `git ${args.join(' ')} failed`)
138
+ err.exitCode = 1
139
+ throw err
140
+ }
141
+ return result.stdout
142
+ }
143
+
144
+ function versionFilesAt(sha, cwd) {
145
+ const tree = new Set(git(['ls-tree', '-r', '--name-only', sha], cwd)
146
+ .split('\n')
147
+ .map((line) => line.trim())
148
+ .filter(Boolean))
149
+ return ['package.json', 'package-lock.json', 'pyproject.toml', 'VERSION']
150
+ .filter((name) => tree.has(name))
151
+ }
152
+
153
+ function versionFromGitFiles(sha, files, cwd) {
154
+ const contents = (path) => git(['show', `${sha}:${path}`], cwd)
155
+ if (files.includes('package.json')) {
156
+ const parsed = parseSemver(JSON.parse(contents('package.json')).version)
157
+ if (parsed) return formatVersion(parsed)
158
+ }
159
+ if (files.includes('pyproject.toml')) {
160
+ const match = contents('pyproject.toml').match(/^version\s*=\s*"([^"]+)"/m)
161
+ const parsed = match && parseSemver(match[1])
162
+ if (parsed) return formatVersion(parsed)
163
+ }
164
+ if (files.includes('VERSION')) {
165
+ const parsed = parseSemver(contents('VERSION'))
166
+ if (parsed) return formatVersion(parsed)
167
+ }
168
+ return null
169
+ }
170
+
171
+ function parseLog(stdout) {
172
+ return stdout
173
+ .split('\u001e')
174
+ .map((chunk) => chunk.trim())
175
+ .filter(Boolean)
176
+ .map((chunk) => {
177
+ const [subject, ...rest] = chunk.split('\n')
178
+ return classifySubject(subject, rest.join('\n'))
179
+ })
180
+ }
181
+
182
+ export function planRelease({ sha, trunk = 'main', strict = false, cwd = process.cwd(), now = new Date() } = {}) {
183
+ if (!sha) {
184
+ const err = new Error('usage: plan.mjs --sha <sha> [--trunk main] [--json] [--strict]')
185
+ err.exitCode = 2
186
+ throw err
187
+ }
188
+ git(['rev-parse', '--verify', sha], cwd)
189
+ const tags = git(['tag', '--merged', sha, '--list', 'v*'], cwd)
190
+ .split('\n')
191
+ .map((line) => line.trim())
192
+ .filter((tag) => parseSemver(tag))
193
+ const baseline = latestReleaseTag(tags)
194
+ const range = baseline ? `${baseline.tag}..${sha}` : sha
195
+ const logArgs = baseline
196
+ ? ['log', range, '--first-parent', '--format=%s%n%b%x1e']
197
+ : ['log', sha, '--first-parent', '-n', '50', '--format=%s%n%b%x1e']
198
+ const changes = parseLog(git(logArgs, cwd))
199
+ const files = versionFilesAt(sha, cwd)
200
+ const fileVersion = versionFromGitFiles(sha, files, cwd)
201
+ const current = parseSemver(fileVersion) || baseline?.version || { major: 0, minor: 0, patch: 0 }
202
+ const { bump, reason } = bumpFor(changes, current, { strict })
203
+ const next = nextVersion(current, bump)
204
+ const version = formatVersion(next)
205
+ const date = now.toISOString().slice(0, 10)
206
+ return {
207
+ trunk,
208
+ sha,
209
+ baselineTag: baseline?.tag || null,
210
+ currentVersion: formatVersion(current),
211
+ bump,
212
+ reason,
213
+ nextVersion: version,
214
+ tag: `v${version}`,
215
+ versionFiles: files,
216
+ changes,
217
+ date,
218
+ changelogMarkdown: renderChangelog({ version, date, changes }),
219
+ }
220
+ }
221
+
222
+ function parseArgs(argv) {
223
+ const opts = { json: false, strict: false, trunk: 'main', sha: null }
224
+ for (let i = 0; i < argv.length; i += 1) {
225
+ const arg = argv[i]
226
+ if (arg === '--json') opts.json = true
227
+ else if (arg === '--strict') opts.strict = true
228
+ else if (arg === '--sha') opts.sha = argv[++i]
229
+ else if (arg === '--trunk') opts.trunk = argv[++i]
230
+ else if (arg === '--help' || arg === '-h') opts.help = true
231
+ else {
232
+ const err = new Error(`unknown argument: ${arg}`)
233
+ err.exitCode = 2
234
+ throw err
235
+ }
236
+ }
237
+ if (opts.help) return opts
238
+ if (!opts.sha || !opts.trunk) {
239
+ const err = new Error('usage: plan.mjs --sha <sha> [--trunk main] [--json] [--strict]')
240
+ err.exitCode = 2
241
+ throw err
242
+ }
243
+ return opts
244
+ }
245
+
246
+ export function main(argv = process.argv.slice(2)) {
247
+ const opts = parseArgs(argv)
248
+ if (opts.help) {
249
+ process.stdout.write('plan.mjs --sha <sha> [--trunk main] [--json] [--strict]\n')
250
+ return 0
251
+ }
252
+ const result = planRelease(opts)
253
+ process.stdout.write(opts.json ? `${JSON.stringify(result, null, 2)}\n` : `${result.tag}\n${result.changelogMarkdown}`)
254
+ return 0
255
+ }
256
+
257
+ if (isMainModule(import.meta.url)) {
258
+ try {
259
+ process.exitCode = main()
260
+ } catch (error) {
261
+ process.stderr.write(`${error.message}\n`)
262
+ process.exitCode = error.exitCode || 1
263
+ }
264
+ }