@aperant/framework 0.6.5 → 0.6.7
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/CHANGELOG.md +155 -0
- package/README.md +17 -251
- package/dist/cli/commands/check-version.d.mts.map +1 -1
- package/dist/cli/commands/check-version.mjs +76 -1
- package/dist/cli/commands/check-version.mjs.map +1 -1
- package/dist/cli/commands/ci-watch.d.mts.map +1 -1
- package/dist/cli/commands/ci-watch.mjs +34 -4
- package/dist/cli/commands/ci-watch.mjs.map +1 -1
- package/dist/cli/commands/commit.d.mts.map +1 -1
- package/dist/cli/commands/commit.mjs +25 -8
- package/dist/cli/commands/commit.mjs.map +1 -1
- package/dist/cli/commands/event.d.mts.map +1 -1
- package/dist/cli/commands/event.mjs +66 -0
- package/dist/cli/commands/event.mjs.map +1 -1
- package/dist/cli/commands/init.d.mts +8 -1
- package/dist/cli/commands/init.d.mts.map +1 -1
- package/dist/cli/commands/init.mjs +91 -9
- package/dist/cli/commands/init.mjs.map +1 -1
- package/dist/cli/commands/modes.d.mts.map +1 -1
- package/dist/cli/commands/modes.mjs +2 -1
- package/dist/cli/commands/modes.mjs.map +1 -1
- package/dist/cli/commands/release-notes.d.mts +11 -0
- package/dist/cli/commands/release-notes.d.mts.map +1 -0
- package/dist/cli/commands/release-notes.mjs +173 -0
- package/dist/cli/commands/release-notes.mjs.map +1 -0
- package/dist/cli/commands/task.d.mts.map +1 -1
- package/dist/cli/commands/task.mjs +285 -139
- package/dist/cli/commands/task.mjs.map +1 -1
- package/dist/cli/commands/triage.d.mts.map +1 -1
- package/dist/cli/commands/triage.mjs +9 -5
- package/dist/cli/commands/triage.mjs.map +1 -1
- package/dist/cli/config/load.d.mts +14 -0
- package/dist/cli/config/load.d.mts.map +1 -1
- package/dist/cli/config/load.mjs +40 -0
- package/dist/cli/config/load.mjs.map +1 -1
- package/dist/cli/config/upgrade-gitignore.d.mts.map +1 -1
- package/dist/cli/config/upgrade-gitignore.mjs +6 -0
- package/dist/cli/config/upgrade-gitignore.mjs.map +1 -1
- package/dist/cli/consistency/parse-review.d.mts.map +1 -1
- package/dist/cli/consistency/parse-review.mjs +4 -1
- package/dist/cli/consistency/parse-review.mjs.map +1 -1
- package/dist/cli/coordination/auto-emit-artifact-ready.d.mts +16 -0
- package/dist/cli/coordination/auto-emit-artifact-ready.d.mts.map +1 -0
- package/dist/cli/coordination/auto-emit-artifact-ready.mjs +88 -0
- package/dist/cli/coordination/auto-emit-artifact-ready.mjs.map +1 -0
- package/dist/cli/coordination/event-schema.d.mts +16 -0
- package/dist/cli/coordination/event-schema.d.mts.map +1 -0
- package/dist/cli/coordination/event-schema.mjs +161 -0
- package/dist/cli/coordination/event-schema.mjs.map +1 -0
- package/dist/cli/coordination/store.d.mts +6 -0
- package/dist/cli/coordination/store.d.mts.map +1 -1
- package/dist/cli/coordination/store.mjs +14 -0
- package/dist/cli/coordination/store.mjs.map +1 -1
- package/dist/cli/dispatch.d.mts.map +1 -1
- package/dist/cli/dispatch.mjs +2 -0
- package/dist/cli/dispatch.mjs.map +1 -1
- package/dist/cli/gate/gates/review-clean.d.mts.map +1 -1
- package/dist/cli/gate/gates/review-clean.mjs +4 -2
- package/dist/cli/gate/gates/review-clean.mjs.map +1 -1
- package/dist/cli/help.mjs +2 -2
- package/dist/cli/help.mjs.map +1 -1
- package/dist/cli/install/update-chips.d.mts +23 -0
- package/dist/cli/install/update-chips.d.mts.map +1 -1
- package/dist/cli/install/update-chips.mjs +60 -0
- package/dist/cli/install/update-chips.mjs.map +1 -1
- package/dist/cli/release-notes/compile.d.mts +38 -0
- package/dist/cli/release-notes/compile.d.mts.map +1 -0
- package/dist/cli/release-notes/compile.mjs +244 -0
- package/dist/cli/release-notes/compile.mjs.map +1 -0
- package/dist/cli/release-notes/draft.d.mts +73 -0
- package/dist/cli/release-notes/draft.d.mts.map +1 -0
- package/dist/cli/release-notes/draft.mjs +120 -0
- package/dist/cli/release-notes/draft.mjs.map +1 -0
- package/dist/cli/release-notes/output-dir.d.mts +20 -0
- package/dist/cli/release-notes/output-dir.d.mts.map +1 -0
- package/dist/cli/release-notes/output-dir.mjs +42 -0
- package/dist/cli/release-notes/output-dir.mjs.map +1 -0
- package/dist/cli/release-notes/persona-filter.d.mts +51 -0
- package/dist/cli/release-notes/persona-filter.d.mts.map +1 -0
- package/dist/cli/release-notes/persona-filter.mjs +127 -0
- package/dist/cli/release-notes/persona-filter.mjs.map +1 -0
- package/dist/cli/release-notes/publish.d.mts +23 -0
- package/dist/cli/release-notes/publish.d.mts.map +1 -0
- package/dist/cli/release-notes/publish.mjs +125 -0
- package/dist/cli/release-notes/publish.mjs.map +1 -0
- package/dist/cli/release-notes/ship-autodraft.d.mts +37 -0
- package/dist/cli/release-notes/ship-autodraft.d.mts.map +1 -0
- package/dist/cli/release-notes/ship-autodraft.mjs +97 -0
- package/dist/cli/release-notes/ship-autodraft.mjs.map +1 -0
- package/dist/cli/roadmap/conductor-view.d.mts +13 -0
- package/dist/cli/roadmap/conductor-view.d.mts.map +1 -0
- package/dist/cli/roadmap/conductor-view.mjs +31 -0
- package/dist/cli/roadmap/conductor-view.mjs.map +1 -0
- package/dist/cli/route/skill-discover.d.mts.map +1 -1
- package/dist/cli/route/skill-discover.mjs +2 -1
- package/dist/cli/route/skill-discover.mjs.map +1 -1
- package/dist/cli/task/ids.d.mts +7 -4
- package/dist/cli/task/ids.d.mts.map +1 -1
- package/dist/cli/task/ids.mjs +11 -10
- package/dist/cli/task/ids.mjs.map +1 -1
- package/dist/types/config.d.ts +11 -7
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +9 -1
- package/prompts/conductor-status-check.md +23 -0
- package/prompts/conductor-sub-agent.md +57 -0
- package/prompts/conductor-system.md +172 -0
- package/skills/apt-close-task/SKILL.md +25 -0
- package/skills/apt-diagram/SKILL.md +45 -9
- package/skills/apt-plan/SKILL.md +12 -0
- package/skills/apt-plan/adapters/conductor.md +98 -0
- package/skills/apt-release-notes/SKILL.md +193 -0
- package/skills/apt-release-notes/appendices/persona-voice.md +59 -0
- package/skills/apt-setup/SKILL.md +148 -3
- package/skills/apt-ship/SKILL.md +74 -12
- package/skills/apt-spar/SKILL.md +290 -0
- package/skills/apt-update/SKILL.md +51 -9
- package/skills/apt-watch-ci/SKILL.md +2 -2
- package/src/cli/commands/check-version.mjs +73 -1
- package/src/cli/commands/ci-watch.mjs +35 -4
- package/src/cli/commands/commit.mjs +27 -8
- package/src/cli/commands/event.mjs +68 -0
- package/src/cli/commands/init.mjs +101 -9
- package/src/cli/commands/modes.mjs +2 -1
- package/src/cli/commands/release-notes.mjs +187 -0
- package/src/cli/commands/task.mjs +305 -152
- package/src/cli/commands/triage.mjs +14 -5
- package/src/cli/config/load.mjs +37 -0
- package/src/cli/config/upgrade-gitignore.mjs +6 -0
- package/src/cli/consistency/parse-review.mjs +3 -1
- package/src/cli/coordination/auto-emit-artifact-ready.mjs +96 -0
- package/src/cli/coordination/event-schema.d.ts +13 -0
- package/src/cli/coordination/event-schema.mjs +174 -0
- package/src/cli/coordination/store.mjs +14 -0
- package/src/cli/dispatch.mjs +2 -0
- package/src/cli/gate/gates/review-clean.mjs +4 -2
- package/src/cli/help.mjs +2 -2
- package/src/cli/install/update-chips.mjs +57 -0
- package/src/cli/release-notes/compile.mjs +261 -0
- package/src/cli/release-notes/draft.mjs +133 -0
- package/src/cli/release-notes/output-dir.mjs +52 -0
- package/src/cli/release-notes/persona-filter.mjs +126 -0
- package/src/cli/release-notes/publish.mjs +128 -0
- package/src/cli/release-notes/ship-autodraft.mjs +106 -0
- package/src/cli/roadmap/conductor-view.d.ts +10 -0
- package/src/cli/roadmap/conductor-view.mjs +31 -0
- package/src/cli/route/skill-discover.mjs +2 -1
- package/src/cli/task/ids.mjs +15 -13
- package/templates/config.json +28 -3
- package/workflows/docs.md +12 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* release-notes/ship-autodraft.mjs — apt-ship Section 2.6 helper.
|
|
3
|
+
*
|
|
4
|
+
* Deterministic, unit-testable shape: given a feature-registry diff +
|
|
5
|
+
* personas envelope + persona_filter mode, decide whether the PR body
|
|
6
|
+
* should grow a `Release note: …` line OR ship should block.
|
|
7
|
+
*
|
|
8
|
+
* This module is intentionally pure — the apt-ship SKILL.md body shells
|
|
9
|
+
* `apt-tools features-audit . --diff-since <base> --json` and feeds the
|
|
10
|
+
* envelope here. Keeping the decision pure makes TD-4 trivial: fixture in,
|
|
11
|
+
* decision out, no I/O.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { buildPersonaTierMap, classifyFragment } from './persona-filter.mjs'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} FeatureDiffEntry
|
|
18
|
+
* @property {string} feature_id
|
|
19
|
+
* @property {string} [area]
|
|
20
|
+
* @property {string[]} [personas]
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} AutodraftInput
|
|
25
|
+
* @property {FeatureDiffEntry[]} featureDiff
|
|
26
|
+
* @property {{ personas?: Array<{ ui_json?: unknown }> } | null} personasEnvelope
|
|
27
|
+
* @property {'primary' | 'primary+secondary' | 'all'} personaFilter
|
|
28
|
+
* @property {boolean} requirePrField
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {{
|
|
33
|
+
* status: 'draft',
|
|
34
|
+
* line: string,
|
|
35
|
+
* persona: string,
|
|
36
|
+
* matchedFeatures: string[],
|
|
37
|
+
* } | {
|
|
38
|
+
* status: 'block',
|
|
39
|
+
* reason: 'no-feature-match' | 'no-persona-signal',
|
|
40
|
+
* message: string,
|
|
41
|
+
* } | {
|
|
42
|
+
* status: 'warn',
|
|
43
|
+
* reason: 'no-feature-match' | 'no-persona-signal',
|
|
44
|
+
* message: string,
|
|
45
|
+
* }} AutodraftResult
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
const BLOCK_MESSAGE =
|
|
49
|
+
'[APT] No release-note signal found — author manual note in PR body or label PR no-notes'
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Compute the autodraft decision.
|
|
53
|
+
*
|
|
54
|
+
* @param {AutodraftInput} input
|
|
55
|
+
* @returns {AutodraftResult}
|
|
56
|
+
*/
|
|
57
|
+
export function decideAutodraft(input) {
|
|
58
|
+
const tierMap = buildPersonaTierMap(input.personasEnvelope)
|
|
59
|
+
|
|
60
|
+
if (!Array.isArray(input.featureDiff) || input.featureDiff.length === 0) {
|
|
61
|
+
return failClassify(input, 'no-feature-match')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Walk the diff; the first feature whose persona resolves into the
|
|
65
|
+
// filter mode wins. (Multi-persona dispatch is intentionally out of
|
|
66
|
+
// scope here — host LLM-side narrative can refine per persona; the
|
|
67
|
+
// CLI just picks a clean signal so ship is decisive.)
|
|
68
|
+
for (const feature of input.featureDiff) {
|
|
69
|
+
if (!Array.isArray(feature.personas) || feature.personas.length === 0) continue
|
|
70
|
+
for (const personaTag of feature.personas) {
|
|
71
|
+
const decision = classifyFragment(personaTag, tierMap, input.personaFilter)
|
|
72
|
+
if (decision.bucket === 'body' && decision.resolvedTier) {
|
|
73
|
+
return {
|
|
74
|
+
status: 'draft',
|
|
75
|
+
line: `Release note: ${feature.feature_id} — ships for ${personaTag}.`,
|
|
76
|
+
persona: personaTag,
|
|
77
|
+
matchedFeatures: [feature.feature_id],
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// No persona signal anywhere — features exist but none carry a tag
|
|
84
|
+
// that the roster + filter accept.
|
|
85
|
+
return failClassify(input, 'no-persona-signal')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Translate a failure reason into the right envelope shape based on
|
|
90
|
+
* `require_pr_field`. require=true → block; require=false → warn (skill
|
|
91
|
+
* proceeds without the line).
|
|
92
|
+
*
|
|
93
|
+
* @param {AutodraftInput} input
|
|
94
|
+
* @param {'no-feature-match' | 'no-persona-signal'} reason
|
|
95
|
+
* @returns {AutodraftResult}
|
|
96
|
+
*/
|
|
97
|
+
function failClassify(input, reason) {
|
|
98
|
+
if (input.requirePrField) {
|
|
99
|
+
return { status: 'block', reason, message: BLOCK_MESSAGE }
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
status: 'warn',
|
|
103
|
+
reason,
|
|
104
|
+
message: `[APT] auto-draft skipped (${reason}) — release_notes.require_pr_field is false; proceeding without a Release note line.`,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for the .mjs conductor-view helper.
|
|
3
|
+
* Hand-authored — the import path points at src/.mjs directly.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ConductorRoadmapView {
|
|
7
|
+
scopes: Array<{ scope: string; roadmap: unknown }>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function buildConductorRoadmapView(projectRoot: string): ConductorRoadmapView
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* conductor-view.mjs — read-only roadmap surface for the Aperant
|
|
3
|
+
* Conductor's `getRoadmap` tool.
|
|
4
|
+
*
|
|
5
|
+
* Wraps `loadRoadmapForScope` + `listRoadmapScopes` so the Conductor sees
|
|
6
|
+
* the same overlay-aware view every framework command sees. Direct reads
|
|
7
|
+
* of `.aperant/roadmap/*\/phases/*.json` or `milestones.json` would miss
|
|
8
|
+
* the dual-write overlay (seed_id from legacy blob, etc.) — Codex
|
|
9
|
+
* roundtable correction #3.
|
|
10
|
+
*
|
|
11
|
+
* Step 5 of Conductor v2 ship order.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { loadRoadmapForScope } from './io.mjs'
|
|
15
|
+
import { listRoadmapScopes } from './paths.mjs'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Build a flat per-scope roadmap snapshot for the Conductor.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} projectRoot
|
|
21
|
+
* @returns {{ scopes: Array<{ scope: string, roadmap: unknown }> }}
|
|
22
|
+
*/
|
|
23
|
+
export function buildConductorRoadmapView(projectRoot) {
|
|
24
|
+
const scopes = listRoadmapScopes(projectRoot)
|
|
25
|
+
const out = []
|
|
26
|
+
for (const scope of scopes) {
|
|
27
|
+
const roadmap = loadRoadmapForScope(projectRoot, scope)
|
|
28
|
+
if (roadmap !== null) out.push({ scope, roadmap })
|
|
29
|
+
}
|
|
30
|
+
return { scopes: out }
|
|
31
|
+
}
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
} from 'node:fs'
|
|
30
30
|
import { isAbsolute, join, relative, resolve } from 'node:path'
|
|
31
31
|
import { parse as parseYaml } from 'yaml'
|
|
32
|
+
import { sanitizeAptVersionForYamlParse } from '../install/version-header.mjs'
|
|
32
33
|
import { SkillFrontmatterSchema } from '../skill-author/contract.mjs'
|
|
33
34
|
|
|
34
35
|
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n/
|
|
@@ -126,7 +127,7 @@ function readSkill(file) {
|
|
|
126
127
|
}
|
|
127
128
|
let parsed
|
|
128
129
|
try {
|
|
129
|
-
parsed = parseYaml(m[1])
|
|
130
|
+
parsed = parseYaml(sanitizeAptVersionForYamlParse(m[1]))
|
|
130
131
|
} catch (err) {
|
|
131
132
|
return {
|
|
132
133
|
ok: false,
|
package/src/cli/task/ids.mjs
CHANGED
|
@@ -9,8 +9,7 @@ import { join, resolve } from 'node:path'
|
|
|
9
9
|
* Supported formats: YY-MM-DD (default, sorts chronologically), DD-MM-YY, MM-DD-YY
|
|
10
10
|
* Uses hyphens as separators for filesystem safety.
|
|
11
11
|
*/
|
|
12
|
-
export function formatDateForTask(dateFormat) {
|
|
13
|
-
const now = new Date()
|
|
12
|
+
export function formatDateForTask(dateFormat, now = new Date()) {
|
|
14
13
|
const yy = String(now.getFullYear()).slice(2)
|
|
15
14
|
const mm = String(now.getMonth() + 1).padStart(2, '0')
|
|
16
15
|
const dd = String(now.getDate()).padStart(2, '0')
|
|
@@ -27,20 +26,23 @@ export function formatDateForTask(dateFormat) {
|
|
|
27
26
|
|
|
28
27
|
/**
|
|
29
28
|
* Generate a short task ID from description + timestamp.
|
|
30
|
-
* Format: {
|
|
31
|
-
*
|
|
29
|
+
* Format: {slug}_{date}
|
|
30
|
+
* Slug comes first so task lists scan by verb instead of by date.
|
|
32
31
|
* Date format is configurable via preferences.date_format in config.
|
|
32
|
+
* Same-day same-slug collisions are disambiguated by the caller
|
|
33
|
+
* (see commands/task.mjs) via a numeric -2, -3, … suffix; this
|
|
34
|
+
* generator never emits a counter or a random hash.
|
|
33
35
|
*/
|
|
34
|
-
export function generateTaskId(description, config) {
|
|
35
|
-
const slug =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
export function generateTaskId(description, config, now = new Date()) {
|
|
37
|
+
const slug =
|
|
38
|
+
description
|
|
39
|
+
.toLowerCase()
|
|
40
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
41
|
+
.slice(0, 40)
|
|
42
|
+
.replace(/^-|-$/g, '') || 'task'
|
|
40
43
|
const dateFormat = config?.preferences?.date_format || 'YY-MM-DD'
|
|
41
|
-
const date = formatDateForTask(dateFormat)
|
|
42
|
-
|
|
43
|
-
return `${date}_${slug}-${hash}`
|
|
44
|
+
const date = formatDateForTask(dateFormat, now)
|
|
45
|
+
return `${slug}_${date}`
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export function getTaskDir(projectDir, taskId) {
|
package/templates/config.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 5,
|
|
3
3
|
"project_type": "unknown",
|
|
4
4
|
"share": {
|
|
5
5
|
"$comment": "Artifact-sharing policy (C35). Source of truth: packages/framework/src/cli/config/share-policy.mjs. visibility = 'solo' | 'team' | 'oss' preset; individual share.* toggles override it. share.digests = null inherits from config.digests.enabled.",
|
|
@@ -107,12 +107,37 @@
|
|
|
107
107
|
"debate_mode": "auto"
|
|
108
108
|
},
|
|
109
109
|
"diagram": {
|
|
110
|
-
"mode": "file"
|
|
111
|
-
"mcpConsent": null
|
|
110
|
+
"mode": "file"
|
|
112
111
|
},
|
|
113
112
|
"docs_policy": {
|
|
114
113
|
"$comment": "C33 docs-coherence policy. Override via /apt:setup Batch 7. Keys are globs/paths; values are 'auto-update' | 'flag-drift' | 'skip'. Missing block → defaults from packages/framework/templates/docs-policy-defaults.json apply."
|
|
115
114
|
},
|
|
115
|
+
"changelog": {
|
|
116
|
+
"$comment": "v5 — persona-aware changelog + release-notes system. Two surfaces: dev changelog (CHANGELOG.md from commits, default ON) and user-facing release notes (docs/releases, default OFF). Opt in per project via /apt:setup Batch 9. See packages/framework/skills/apt-release-notes/SKILL.md.",
|
|
117
|
+
"dev": {
|
|
118
|
+
"enabled": true,
|
|
119
|
+
"file": "CHANGELOG.md",
|
|
120
|
+
"format": "keep-a-changelog",
|
|
121
|
+
"source": "commits"
|
|
122
|
+
},
|
|
123
|
+
"release_notes": {
|
|
124
|
+
"enabled": false,
|
|
125
|
+
"audience": null,
|
|
126
|
+
"output_dir": "docs/releases",
|
|
127
|
+
"persona_filter": "primary+secondary",
|
|
128
|
+
"require_pr_field": true,
|
|
129
|
+
"draft": {
|
|
130
|
+
"on_pr_merge": true,
|
|
131
|
+
"fragments_dir": "docs/releases/_unreleased"
|
|
132
|
+
},
|
|
133
|
+
"compile": {
|
|
134
|
+
"on_tag": true
|
|
135
|
+
},
|
|
136
|
+
"publish": {
|
|
137
|
+
"targets": ["github-release"]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
116
141
|
"router": {
|
|
117
142
|
"llm": {
|
|
118
143
|
"enabled": true,
|
package/workflows/docs.md
CHANGED
|
@@ -90,6 +90,18 @@ Gather facts from the actual codebase. The depth depends on doc type:
|
|
|
90
90
|
- Conventional commit messages to categorize changes
|
|
91
91
|
- Breaking changes (commits with `BREAKING CHANGE` or `!:`)
|
|
92
92
|
|
|
93
|
+
> **Two-skill split (v0.7.0+).** `/apt:docs changelog` owns the
|
|
94
|
+
> dev-flavored `CHANGELOG.md` surface — internal task IDs, file paths,
|
|
95
|
+
> schema-bump notes, process trivia. For the user-facing complement,
|
|
96
|
+
> projects can opt in to `/apt:release-notes` via `/apt:setup` →
|
|
97
|
+
> Batch 9. That skill produces persona-voice-tuned release notes
|
|
98
|
+
> (towncrier-style fragments at PR-merge time, compiled per tag, pushed
|
|
99
|
+
> to GitHub Releases). The two skills coexist intentionally: a single
|
|
100
|
+
> `--audience` flag inside `/apt:docs changelog` drifts to a
|
|
101
|
+
> lowest-common-denominator artifact that satisfies neither audience.
|
|
102
|
+
> See `packages/framework/skills/apt-release-notes/SKILL.md` for the
|
|
103
|
+
> opt-in surface and the three modes (draft / compile / publish).
|
|
104
|
+
|
|
93
105
|
### For Contributing
|
|
94
106
|
- Development setup steps (verified by checking file existence)
|
|
95
107
|
- Test commands (verified by running them)
|