@iodes/releasekit 0.1.0 → 0.1.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.
Files changed (78) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +292 -110
  3. package/dist/cli.js +7 -5
  4. package/dist/content.d.ts +8 -0
  5. package/dist/content.js +5 -3
  6. package/dist/export.js +4 -3
  7. package/dist/images.d.ts +14 -5
  8. package/dist/images.js +32 -8
  9. package/dist/model.d.ts +29 -0
  10. package/dist/model.js +27 -3
  11. package/dist/prompts.d.ts +2 -2
  12. package/dist/prompts.js +24 -16
  13. package/dist/validate.js +2 -2
  14. package/examples/README.md +34 -14
  15. package/examples/backup-encryption/README.md +19 -0
  16. package/examples/backup-encryption/dark.png +0 -0
  17. package/examples/backup-encryption/dark.prompt.md +52 -0
  18. package/examples/backup-encryption/dimensions-edit.prompt.md +7 -0
  19. package/examples/backup-encryption/flat-render-requests.md +15 -0
  20. package/examples/backup-encryption/light.png +0 -0
  21. package/examples/backup-encryption/light.prompt.md +52 -0
  22. package/examples/backup-encryption/pair-review.md +18 -0
  23. package/examples/backup-encryption/scene.yaml +31 -0
  24. package/examples/connected-route/README.md +23 -0
  25. package/examples/connected-route/dark.png +0 -0
  26. package/examples/connected-route/dark.prompt.md +58 -0
  27. package/examples/connected-route/light.png +0 -0
  28. package/examples/connected-route/light.prompt.md +58 -0
  29. package/examples/connected-route/pair-review.md +22 -0
  30. package/examples/connected-route/render-requests.md +171 -0
  31. package/examples/connected-route/scene.yaml +59 -0
  32. package/examples/feature-briefs.yaml +96 -89
  33. package/examples/location-preferences/README.md +18 -0
  34. package/examples/location-preferences/dark.png +0 -0
  35. package/examples/location-preferences/dark.prompt.md +52 -0
  36. package/examples/location-preferences/light.png +0 -0
  37. package/examples/location-preferences/light.prompt.md +52 -0
  38. package/examples/location-preferences/pair-review.md +17 -0
  39. package/examples/location-preferences/scene.yaml +26 -0
  40. package/examples/provided-media/README.md +15 -0
  41. package/examples/provided-media/scene.yaml +22 -0
  42. package/examples/queue-action/README.md +15 -15
  43. package/examples/queue-action/alignment-edit.prompt.md +8 -8
  44. package/examples/queue-action/dark.prompt.md +58 -58
  45. package/examples/queue-action/light.prompt.md +58 -58
  46. package/examples/queue-action/pair-review.md +33 -33
  47. package/examples/queue-action/scene.yaml +41 -41
  48. package/examples/release-notes.en-US.json +56 -56
  49. package/examples/release-notes.ko-KR.json +56 -56
  50. package/examples/storage-breakdown/README.md +18 -0
  51. package/examples/storage-breakdown/dark.png +0 -0
  52. package/examples/storage-breakdown/dark.prompt.md +52 -0
  53. package/examples/storage-breakdown/light.png +0 -0
  54. package/examples/storage-breakdown/light.prompt.md +52 -0
  55. package/examples/storage-breakdown/pair-review.md +18 -0
  56. package/examples/storage-breakdown/scene.yaml +28 -0
  57. package/examples/tablet-reading/README.md +18 -0
  58. package/examples/tablet-reading/content-edit.prompt.md +7 -0
  59. package/examples/tablet-reading/dark.png +0 -0
  60. package/examples/tablet-reading/dark.prompt.md +52 -0
  61. package/examples/tablet-reading/light.png +0 -0
  62. package/examples/tablet-reading/light.prompt.md +52 -0
  63. package/examples/tablet-reading/pair-review.md +18 -0
  64. package/examples/tablet-reading/scene.yaml +29 -0
  65. package/kit/references/composition-recipes.md +89 -73
  66. package/kit/references/format.md +26 -24
  67. package/kit/references/media-sources.md +34 -0
  68. package/kit/references/theme-pairing.md +55 -53
  69. package/kit/references/visual-language.md +73 -69
  70. package/kit/references/workflow.md +24 -24
  71. package/kit/references/writing.md +27 -27
  72. package/kit/skills/releasekit-draft/SKILL.md +10 -10
  73. package/kit/skills/releasekit-image/SKILL.md +16 -16
  74. package/kit/skills/releasekit-review/SKILL.md +12 -12
  75. package/kit/skills/releasekit-translate/SKILL.md +10 -10
  76. package/package.json +54 -52
  77. package/schemas/bundle.schema.json +26 -1
  78. package/schemas/visual.schema.json +42 -0
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 SO, HYEONSEOP
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SO, HYEONSEOP
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,110 +1,292 @@
1
- # ReleaseKit
2
-
3
- Git-based visual release notes, written with your coding agent and stored with your product.
4
-
5
- ReleaseKit provides a deterministic CLI, portable agent skills, an original visual language, and versioned content files. Your agent writes the copy and uses its available image tools. The CLI prepares Git evidence, compiles image prompts, validates artifacts, and exports JSON with local assets.
6
-
7
- ## Project image policy
8
-
9
- Dark **and** light illustrations are recommended by default. Choose one theme when generation cost matters more than providing a dedicated variant for both viewer themes:
10
-
11
- ```yaml
12
- # releasekit/config.yaml
13
- visuals:
14
- themes: both # both | dark | light
15
- ```
16
-
17
- This edits one field in the complete generated config; keep the other visual settings. You can also select the policy at setup with `releasekit init --themes light`.
18
-
19
- One scene brief drives both variants. Object positions, scale, crop, interaction state, and semantic colors stay consistent while presentation surfaces and lighting adapt. Single-theme exports contain one real asset and an explicit fallback, without inventing a second variant. Images are shared across locales.
20
-
21
- `releasekit image plan <version>` reports pending and reusable asset counts before any image generation. It never calls a model API. Previously imported current assets are reused. If image generation is unavailable, the prompts remain available for an external tool.
22
-
23
- ## Local setup
24
-
25
- Requires Git and Node.js 22.12 or later. Node.js 24 is recommended for development.
26
-
27
- ```sh
28
- npm install
29
- npm run build
30
- npm pack
31
- npm install -g ./iodes-releasekit-0.1.0.tgz
32
- ```
33
-
34
- The package can be built and installed locally; no public registry publication is required. In the product's Git repository:
35
-
36
- ```sh
37
- releasekit init --tools codex,claude,cursor --themes both
38
- ```
39
-
40
- Codex and Cursor share a single project skill tree to avoid duplicate discovery. Claude Code receives its project skill tree. Installation prints invocation hints. `releasekit update` refreshes owned files, preserves user edits, and reports conflicts.
41
-
42
- ## Agent workflow
43
-
44
- Ask your agent to use `releasekit-draft` to create notes between two tags or commits. Include the desired release version. For example:
45
-
46
- > Prepare release 1.4.0 from v1.3.0 to v1.4.0. Write Korean and English notes, create the configured image variants, and export the latest three releases.
47
-
48
- The installed skills are `releasekit-draft`, `releasekit-image`, `releasekit-translate`, and `releasekit-review`. They use the CLI rather than implementing Git parsing or asset bookkeeping again.
49
-
50
- ```sh
51
- releasekit prepare 1.4.0 --from v1.3.0 --to v1.4.0 --previous 1.3.0
52
- releasekit note add 1.4.0 queue-action
53
- # Fill the note files, evidence references, and shared visual brief.
54
- releasekit image plan 1.4.0
55
- # Generate externally or through the agent's image tool, then select the files.
56
- releasekit image import 1.4.0 queue-action --theme dark --file ./selected-dark.png
57
- releasekit image import 1.4.0 queue-action --theme light --file ./selected-light.png
58
- # Review the completed translation before marking it current.
59
- releasekit translation mark 1.4.0 queue-action --locale en-US
60
- releasekit validate 1.4.0
61
- releasekit finalize 1.4.0
62
- releasekit export --current 1.4.0 --limit 3 --locale ko-KR --out ./release-output
63
- ```
64
-
65
- Use `--from-root` for an explicitly requested full-history first release. `--to` defaults to `HEAD`, and `--previous` can supply the default comparison start. Existing drafts are edited in place; `prepare` does not overwrite them. `--json` provides structured results, and `--cwd` selects a project working directory.
66
-
67
- There is no built-in model API, viewer, hosted database, automatic Git commit, or publishing step.
68
-
69
- ## Visual guidance
70
-
71
- The built-in guidance goes beyond a style adjective. It includes eight composition recipes, feature-to-image selection, a scene contract, semantic palette roles, theme-pair invariants, text rules, cost-aware reuse, external generation handoff, and visual acceptance checks.
72
-
73
- For each note, the agent derives the visual message from its evidence, selects the appropriate archetype, and writes feature-specific relationships and correctness constraints. The CLI combines that scene with common presentation rules, only the selected recipe, and the requested theme. Review first checks what the image claims, then visual clarity, then theme correspondence. Worked examples do not set the layout for other notes.
74
-
75
- - [Visual language](kit/references/visual-language.md)
76
- - [Composition recipes](kit/references/composition-recipes.md)
77
- - [Theme pairs and cost](kit/references/theme-pairing.md)
78
- - [Writing and translation](kit/references/writing.md)
79
- - [Original dark/light example and three-version bundles](examples/README.md)
80
-
81
- All shipped guidance uses independent, brand-neutral descriptions. Product-specific imagery should depict the user's actual feature. Reference-company identities, attributed style labels, copied artwork, and unrelated product silhouettes do not belong in briefs or generated output.
82
-
83
- ## Version and file contract
84
-
85
- Each release stores its own changes and an explicit `previous` release link. Export follows that chain, keeping the current version and the configured number of preceding versions in separate groups. The default count is three including current. Version strings are not sorted to infer ancestry, and similar notes in separate versions are retained.
86
-
87
- Content uses YAML metadata, Markdown locale files, image briefs and prompts, and local raster assets. Git boundaries are pinned to immutable commits. Notes carry evidence, and translations carry source fingerprints. A ready release has a content fingerprint so later edits are detected.
88
-
89
- Project visual defaults are captured when a release is prepared. To apply changed project settings to an existing draft:
90
-
91
- ```sh
92
- releasekit image plan 1.4.0 --sync-config
93
- ```
94
-
95
- This preserves selected files and schedules only the newly required or stale variants. Ready content must first be reopened with `status: draft` and `contentHash: null`.
96
-
97
- See [the file contract](kit/references/format.md) and the generated [JSON schemas](schemas). Export contains display data and relative assets, excluding Git evidence, prompts, and private source paths. Consumers select `image.variants[theme]` or `image.variants[image.fallbackTheme]` and safely render `bodyMarkdown`.
98
-
99
- ## Development checks
100
-
101
- ```sh
102
- npm run check
103
- npm test
104
- npm run build
105
- npm pack --dry-run
106
- ```
107
-
108
- Tests cover pinned Git ranges, reverted changes, branched release history, theme scheduling, asset integrity, single-theme fallback, stale translations, finalized content edits, installation conflicts, and command-line behavior. CI runs on Windows and Linux with Node.js 22 and 24.
109
-
110
- MIT licensed.
1
+ <div align="center">
2
+
3
+ <h1>ReleaseKit</h1>
4
+
5
+ <p><strong>Turn Git changes into visual release notes.</strong></p>
6
+ <p>Written with your coding agent. Versioned with your product.</p>
7
+
8
+ <p>
9
+ <a href="https://www.npmjs.com/package/@iodes/releasekit"><img src="https://img.shields.io/npm/v/@iodes/releasekit?color=4678ED" alt="npm version"></a>
10
+ <a href="https://github.com/iodes/ReleaseKit/actions/workflows/check.yml"><img src="https://github.com/iodes/ReleaseKit/actions/workflows/check.yml/badge.svg" alt="Check workflow status"></a>
11
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-4678ED" alt="License: MIT"></a>
12
+ </p>
13
+
14
+ <p>
15
+ <a href="#quick-start">Quick start</a> &middot;
16
+ <a href="#workflow">Workflow</a> &middot;
17
+ <a href="examples/README.md">Examples</a> &middot;
18
+ <a href="#documentation">Documentation</a>
19
+ </p>
20
+
21
+ </div>
22
+
23
+ ReleaseKit pairs a deterministic CLI with portable agent skills. Your agent writes the notes and selects or creates images; the CLI collects Git evidence, prepares image requests, validates content, and exports JSON with local assets.
24
+
25
+ | Dark | Light |
26
+ | :---: | :---: |
27
+ | ![A blue queue action revealed behind a list row on a charcoal canvas](examples/queue-action/dark.png) | ![The same queue action and list geometry on a light canvas](examples/queue-action/light.png) |
28
+
29
+ *One scene brief, two theme variants. Fictional feature illustrations. [Browse the composition gallery →](examples/README.md#composition-gallery)*
30
+
31
+ ## Why ReleaseKit?
32
+
33
+ - **Grounded in Git.** Draft from tags or commits, pin the evidence, and keep each release's changes together.
34
+ - **Works with your agent.** Use portable skills for Codex, Claude Code, and Cursor, plus the image tools already available to you.
35
+ - **Visuals for your feature.** Generate flat explanations in dark and light, or reuse an approved screenshot, photo, or content image across both viewer themes.
36
+ - **Content you own.** Keep Markdown, translations, and images in your repository. Export JSON and local assets for your product to display.
37
+
38
+ ## Quick start
39
+
40
+ Requires **Git** and **Node.js 22.12+**.
41
+
42
+ ### 1. Install
43
+
44
+ ```sh
45
+ npm install -g @iodes/releasekit
46
+ ```
47
+
48
+ ### 2. Set up your product
49
+
50
+ Run inside your product's Git repository:
51
+
52
+ ```sh
53
+ releasekit init --tools codex,claude,cursor --themes both
54
+ ```
55
+
56
+ Choose the tools you use: `codex`, `claude`, `cursor`, or a comma-separated list. Then edit `releasekit/config.yaml` to set your product name, source language, locales, and visual settings. Setup prints the skill invocation hints for each tool.
57
+
58
+ ### 3. Ask your agent
59
+
60
+ Start with the installed `releasekit-draft` skill. Example conversation with an image tool available:
61
+
62
+ ```text
63
+ You: Use releasekit-draft to draft 1.4.0 from v1.3.0 to v1.4.0.
64
+ Write Korean and English notes.
65
+ AI: Created releasekit/releases/1.4.0/
66
+ ✓ Pinned the Git range and collected change evidence
67
+ Wrote release notes in ko-KR and en-US
68
+
69
+ You: Add images for the notes.
70
+ AI: ✓ Generated dark/light explanations from shared scene briefs
71
+ Reviewed and imported both variants for each generated graphic
72
+ The product-detail image is pending; I need an approved capture
73
+ or photo. Translation work can continue while it is pending.
74
+
75
+ You: Use ./approved-capture.png for the product-detail note.
76
+ AI: ✓ Reviewed and imported it once for both viewer themes
77
+
78
+ You: Review and finalize 1.4.0, then export up to three releases
79
+ in English to ./release-output.
80
+ AI: ✓ Validated notes, translations, and images
81
+ Marked release 1.4.0 ready
82
+ Exported release-output/
83
+ ├── release-notes.json ← Notes grouped by release
84
+ └── assets/ ← Theme variants and shared supplied images
85
+ ```
86
+
87
+ Invoke the skill with `$releasekit-draft` in Codex, `/releasekit-draft` in Claude Code, or the skill picker in Cursor. The agent runs the CLI, generates flat explanations, and requests approved source images when the actual product or content must be shown.
88
+
89
+ ## Workflow
90
+
91
+ ```text
92
+ Git range Release draft → Notes + images + translations → Validate → Export
93
+ ```
94
+
95
+ | Skill | Purpose |
96
+ | --- | --- |
97
+ | `releasekit-draft` | Create or revise notes from a Git range. |
98
+ | `releasekit-image` | Plan, generate or request, review, and import images. |
99
+ | `releasekit-translate` | Translate notes and track source freshness. |
100
+ | `releasekit-review` | Review content, evidence, images, and release readiness. |
101
+
102
+ The agent handles editorial work, media selection, and image generation where appropriate. The CLI handles files, evidence, validation, and export. Finalizing a release marks local content ready; committing, publishing, and displaying it remain separate steps.
103
+
104
+ <details>
105
+ <summary><strong>Step-by-step CLI workflow</strong></summary>
106
+
107
+ Replace the sample version, Git refs, and note ID with your own. If release `1.3.0` already exists in ReleaseKit, add `--previous 1.3.0` to link its history.
108
+
109
+ ```sh
110
+ releasekit prepare 1.4.0 --from v1.3.0 --to v1.4.0
111
+ releasekit note add 1.4.0 queue-action
112
+
113
+ # Fill the notes, evidence references, and visual brief.
114
+ # Choose an archetype and set scene.source to generated for this example.
115
+ releasekit image plan 1.4.0
116
+
117
+ # Generate and review the dark image with your agent or an external tool.
118
+ releasekit image import 1.4.0 queue-action --theme dark --file ./selected-dark.png
119
+
120
+ # Plan again to use the accepted dark image as a composition reference.
121
+ releasekit image plan 1.4.0
122
+ # Generate and review the matching light image, then import it.
123
+ releasekit image import 1.4.0 queue-action --theme light --file ./selected-light.png
124
+
125
+ # Review the completed translation before marking it current.
126
+ releasekit translation mark 1.4.0 queue-action --locale en-US
127
+ releasekit validate 1.4.0
128
+ releasekit finalize 1.4.0
129
+ releasekit export --current 1.4.0 --limit 3 --locale ko-KR --out ./release-output
130
+ ```
131
+
132
+ - Use `--from-root` for an explicitly requested full-history first release.
133
+ - `--to` defaults to `HEAD`; `--previous` can supply the comparison start.
134
+ - Edit existing drafts in place. `prepare` never overwrites them.
135
+ - Use `note add --no-image` for an intentionally text-only note.
136
+ - Add `--json` for structured results or `--cwd` to select a project directory.
137
+ - Export to a new directory; an existing destination is never overwritten.
138
+
139
+ See the [agent workflow](kit/references/workflow.md) for ancestry rules and continuing existing releases.
140
+
141
+ </details>
142
+
143
+ <details>
144
+ <summary><strong>Updating installed skills</strong></summary>
145
+
146
+ After installing a newer package version, run `releasekit update` in your product repository. It refreshes managed files, preserves user edits, and reports conflicts.
147
+
148
+ Codex and Cursor share `.agents/skills` to avoid duplicate discovery. Claude Code uses `.claude/skills`.
149
+
150
+ </details>
151
+
152
+ ## Image themes
153
+
154
+ **Generated graphics default to dark and light.** Paired variants share one scene brief, preserving geometry, feature meaning, and semantic colors while presentation surfaces adapt. Images are shared across locales.
155
+
156
+ Choose `scene.source` in each note's visual brief before planning:
157
+
158
+ | Source | Use for | Theme handling |
159
+ | --- | --- | --- |
160
+ | `generated` | Flat glyphs, interface explanations, diagrams, and data graphics supported by the feature. | Separate images for the configured dark/light themes. |
161
+ | `provided` | Approved screenshots, photographs, or content artwork. Required for `object-detail` and `editorial-scene`. | One unchanged `shared` asset, or distinct genuine theme captures. |
162
+
163
+ Choose a single theme during setup with `--themes dark` or `--themes light`, or edit this field in the generated configuration while keeping the other visual settings:
164
+
165
+ ```yaml
166
+ # releasekit/config.yaml
167
+ visuals:
168
+ themes: both # both | dark | light
169
+ ```
170
+
171
+ `releasekit image plan <version>` reports pending and reusable assets, with separate `generationRequests` and `providedRequests` counts. It reuses current imports and never calls a model API. Single-theme exports contain one real asset and an explicit fallback.
172
+
173
+ Requests with `action: generate` include a prompt for the agent or an external tool. Requests with `action: provide` have `promptFile: null` and identify the needed source. Missing supplied media stays pending and blocks finalization; the agent can continue independent writing and translation work.
174
+
175
+ <details>
176
+ <summary><strong>Importing one supplied image for both themes</strong></summary>
177
+
178
+ Complete the note's visual brief with `scene.source: provided`. This example uses the note ID `product-detail`:
179
+
180
+ ```sh
181
+ releasekit image plan 1.4.0
182
+
183
+ # Once an approved capture or photo is available, inspect it and import.
184
+ releasekit image import 1.4.0 product-detail --theme shared --file ./approved-capture.png
185
+ ```
186
+
187
+ The CLI keeps the original bytes, dimensions, and colors. One `shared` asset serves both viewer themes without generating or duplicating another file.
188
+
189
+ If genuine dark/light captures exist, import them with `--theme dark` and `--theme light` instead. A note must use either `shared` or themed entries; remove the previous variant entries when switching. A missing configured capture remains a supplied-image request.
190
+
191
+ Follow the current image plan even if older prompt files remain. See the [supplied-media example](examples/provided-media/README.md) and [media source guide](kit/references/media-sources.md) for pending inputs and older briefs.
192
+
193
+ </details>
194
+
195
+ <details>
196
+ <summary><strong>Applying changed settings to an existing draft</strong></summary>
197
+
198
+ Releases capture the project's visual settings when prepared. To apply updated defaults:
199
+
200
+ ```sh
201
+ releasekit image plan 1.4.0 --sync-config
202
+ ```
203
+
204
+ This preserves selected files and schedules only newly required or stale variants. Reopen ready content first by setting `status: draft` and `contentHash: null` in its `release.yaml`.
205
+
206
+ </details>
207
+
208
+ ## Content and export
209
+
210
+ Everything lives alongside your product:
211
+
212
+ ```text
213
+ releasekit/
214
+ ├── config.yaml
215
+ └── releases/
216
+ └── 1.4.0/
217
+ ├── release.yaml # Metadata, note order, previous release
218
+ ├── evidence.json # Pinned Git evidence
219
+ ├── changes.patch # Net change for this release
220
+ ├── notes/ # Markdown for each locale
221
+ ├── visuals/ # Scene briefs, media sources, and variants
222
+ ├── prompts/ # Prompts for pending generated variants
223
+ └── assets/ # Selected raster images
224
+ ```
225
+
226
+ Export follows explicit `previous` links, keeping each version's notes in a separate group. The default limit is **three releases, including the current one**. Similar notes in different versions remain separate.
227
+
228
+ The bundle contains display data and relative assets. Git evidence, prompts, and private source paths stay out of the export. Consumers safely render `bodyMarkdown` and select `image.variants[theme]`, falling back to `image.variants[image.fallbackTheme]` when needed. Text-only notes have `image: null`.
229
+
230
+ `fallbackTheme` can be `dark`, `light`, or `shared`. A shared-image export contains one `image.variants.shared` entry with `fallbackTheme: shared`; the same consumer lookup displays it in either viewer theme. Preserve the supplied image's original appearance when displaying it.
231
+
232
+ Translations track source fingerprints, and finalized releases record content fingerprints to detect later edits. See the [file contract](kit/references/format.md) and [JSON schemas](schemas) for the full structure.
233
+
234
+ ## Documentation
235
+
236
+ | Guide | What it covers |
237
+ | --- | --- |
238
+ | [Agent workflow](kit/references/workflow.md) | Git boundaries, drafts, review, and export. |
239
+ | [Writing and translation](kit/references/writing.md) | Product copy, evidence, and locale freshness. |
240
+ | [Visual language](kit/references/visual-language.md) | Composition, hierarchy, materials, and acceptance checks. |
241
+ | [Choosing generated or supplied media](kit/references/media-sources.md) | Source selection, pending captures, and shared assets. |
242
+ | [Composition recipes](kit/references/composition-recipes.md) | Eight presentation categories matched to the feature and its source. |
243
+ | [Theme pairs and cost](kit/references/theme-pairing.md) | Shared geometry, single-theme policies, and reuse. |
244
+ | [File contract](kit/references/format.md) · [JSON schemas](schemas) | Authoring files and the public export format. |
245
+ | [Worked examples](examples/README.md) | Paired illustrations, supplied-image workflow, independent briefs, and three-release bundles. |
246
+
247
+ Visual guidance uses independent, brand-neutral descriptions. Each illustration should communicate the actual feature through its own scene. Worked examples demonstrate the process; each note gets its own composition.
248
+
249
+ The built-in guidance covers source selection, a scene contract, semantic palette roles, theme-pair invariants, text rules, cost-aware reuse, and visual acceptance checks. Generated icons are compact flat monochrome glyphs. Physical details and content previews use supplied images rather than invented 3D objects or decorative scenes.
250
+
251
+ ## Development
252
+
253
+ Use **Node.js 24** for development. From a local checkout:
254
+
255
+ ```sh
256
+ npm ci
257
+ npm run check
258
+ npm test
259
+ npm run build
260
+ npm pack --dry-run
261
+ ```
262
+
263
+ CI runs on Windows and Linux with Node.js 22 and 24. Tests cover Git ranges, release history, image integrity, theme policies, supplied media and shared assets, translation freshness, finalization, installation conflicts, and CLI behavior.
264
+
265
+ <details>
266
+ <summary><strong>Install from a local checkout</strong></summary>
267
+
268
+ ```sh
269
+ npm pack
270
+ npm install -g ./iodes-releasekit-0.1.0.tgz
271
+ ```
272
+
273
+ Use the tarball filename printed by `npm pack` if the package version differs. Packing builds the package automatically.
274
+
275
+ </details>
276
+
277
+ <details>
278
+ <summary><strong>Publishing this package</strong></summary>
279
+
280
+ The [Publish workflow](.github/workflows/publish.yml) runs manually on a `release/x.y.z` branch. The branch selects the major/minor release line and starting patch; all three components must be numeric with no leading zeros.
281
+
282
+ Once the workflow exists on the default and release branches, open **Actions → Publish → Run workflow** and select the release branch. It pins the selected commit and calculates the next available patch from both Git tags and npm versions. For `release/0.1.0`, publishing starts at `0.1.0` if unused, then advances past the highest existing patch to `0.1.1`, `0.1.2`, and so on. A newer major/minor line blocks older lines, and registry errors stop the workflow.
283
+
284
+ The runner restores dependencies and updates the package and lockfile with `npm version --no-git-tag-version`; no version-bump commit is needed. The CLI reads that package version for `--version`. After checks, tests, build, and package preview pass, the workflow creates a new tag and publishes through the npm trusted publisher configured for `publish.yml`.
285
+
286
+ Existing tags are never moved. Every run calculates a fresh version, even for the same commit. If an earlier attempt already created a tag or published a package, rerunning advances to the next patch. Tag pushes do not start publishing.
287
+
288
+ </details>
289
+
290
+ ## License
291
+
292
+ [MIT](LICENSE) © 2026 SO, HYEONSEOP.
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import path from 'node:path';
3
+ import { readFileSync } from 'node:fs';
3
4
  import { Command, Option } from 'commander';
4
5
  import { Project, prepare } from './project.js';
5
6
  import { initProject, installSkills } from './install.js';
@@ -7,9 +8,10 @@ import { addNote, markTranslation, syncImagePolicy } from './content.js';
7
8
  import { planImages, importImage } from './images.js';
8
9
  import { validate, finalize } from './validate.js';
9
10
  import { exportBundle } from './export.js';
10
- import { configSchema, noteMetaSchema, theme } from './model.js';
11
+ import { configSchema, noteMetaSchema, assetVariant } from './model.js';
12
+ const { version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
11
13
  const program = new Command();
12
- program.name('releasekit').description('Git-based visual release content and agent skills').version('0.1.0')
14
+ program.name('releasekit').description('Git-based visual release content and agent skills').version(version)
13
15
  .option('--cwd <directory>', 'project working directory', process.cwd())
14
16
  .option('--json', 'print machine-readable results');
15
17
  const project = () => Project.find(path.resolve(program.opts().cwd));
@@ -44,7 +46,7 @@ note.command('add <version> <id>').description('Scaffold a note and its locale f
44
46
  emit({ version, note: id, status: 'draft' });
45
47
  });
46
48
  const images = program.command('image').description('Plan themed illustrations and register selected files');
47
- images.command('plan <version>').description('Write pending prompts and report asset counts without calling a model')
49
+ images.command('plan <version>').description('Plan generation or supplied-image requests without calling a model')
48
50
  .option('--sync-config', 'apply current project image settings to this draft')
49
51
  .action(async (version, options) => {
50
52
  const instance = project();
@@ -53,9 +55,9 @@ images.command('plan <version>').description('Write pending prompts and report a
53
55
  emit(await planImages(instance, version));
54
56
  });
55
57
  images.command('import <version> <note>').description('Import a selected raster variant')
56
- .addOption(new Option('--theme <theme>', 'variant to register').choices(['dark', 'light']).makeOptionMandatory())
58
+ .addOption(new Option('--theme <theme>', 'variant to register; shared is for supplied images').choices(['dark', 'light', 'shared']).makeOptionMandatory())
57
59
  .requiredOption('--file <file>', 'selected local PNG, JPEG, or WebP')
58
- .action(async (version, id, options) => emit(await importImage(project(), version, id, theme.parse(options.theme), path.resolve(program.opts().cwd, options.file))));
60
+ .action(async (version, id, options) => emit(await importImage(project(), version, id, assetVariant.parse(options.theme), path.resolve(program.opts().cwd, options.file))));
59
61
  const translation = program.command('translation').description('Track source freshness for reviewed translations');
60
62
  translation.command('mark <version> <note>').description('Mark an already reviewed translation current')
61
63
  .requiredOption('--locale <locale>', 'translation language code')
package/dist/content.d.ts CHANGED
@@ -7,6 +7,7 @@ export declare function readVisual(project: Project, version: string, id: string
7
7
  schemaVersion: 1;
8
8
  scene: {
9
9
  archetype: "data-view" | "device-view" | "editorial-scene" | "icon-tile" | "object-detail" | "spatial-view" | "symbol-pair" | "ui-detail";
10
+ source?: "generated" | "provided" | undefined;
10
11
  subject: string;
11
12
  message: string;
12
13
  focus: string;
@@ -33,6 +34,13 @@ export declare function readVisual(project: Project, version: string, id: string
33
34
  width: number;
34
35
  height: number;
35
36
  } | undefined;
37
+ shared?: {
38
+ file: string;
39
+ sha256: string;
40
+ sceneHash: string;
41
+ width: number;
42
+ height: number;
43
+ } | undefined;
36
44
  };
37
45
  }>;
38
46
  export declare function checkReferenceFiles(project: Project, references: string[]): Promise<void>;
package/dist/content.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as fs from 'node:fs/promises';
2
- import { locale, noteMetaSchema, visualSchema } from './model.js';
2
+ import { locale, noteMetaSchema, visualSchema, imageSource } from './model.js';
3
3
  import { identifier, writeYaml, writeNote, readNote, noteHash, exists, readYaml } from './files.js';
4
4
  import { Project, editable } from './project.js';
5
5
  export async function addNote(project, version, id, category, image) {
@@ -16,7 +16,7 @@ export async function addNote(project, version, id, category, image) {
16
16
  if (image) {
17
17
  await writeYaml(await project.releaseFile(version, `visuals/${id}.yaml`), {
18
18
  schemaVersion: 1,
19
- scene: { archetype: '', subject: '', message: '', focus: '', composition: '', context: '', elements: [], preserve: [], avoid: [], text: [], references: [] },
19
+ scene: { archetype: '', source: '', subject: '', message: '', focus: '', composition: '', context: '', elements: [], preserve: [], avoid: [], text: [], references: [] },
20
20
  variants: {},
21
21
  });
22
22
  }
@@ -52,7 +52,9 @@ export async function syncImagePolicy(project, version) {
52
52
  await project.save(release);
53
53
  }
54
54
  export async function readVisual(project, version, id) {
55
- return readYaml(await project.releaseFile(version, `visuals/${identifier(id)}.yaml`), visualSchema);
55
+ const visual = await readYaml(await project.releaseFile(version, `visuals/${identifier(id)}.yaml`), visualSchema);
56
+ imageSource(visual.scene);
57
+ return visual;
56
58
  }
57
59
  export async function checkReferenceFiles(project, references) {
58
60
  const { within } = await import('./files.js');
package/dist/export.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { Project } from './project.js';
4
- import { bundleSchema, themes, locale } from './model.js';
4
+ import { bundleSchema, activeVariants, locale } from './model.js';
5
5
  import { validate } from './validate.js';
6
6
  import { exists, readNote, write } from './files.js';
7
7
  import { readVisual } from './content.js';
@@ -25,8 +25,9 @@ export async function exportBundle(project, current, options) {
25
25
  const exported = { id: note.id, category: note.category, title: text.title, bodyMarkdown: text.body, image: null };
26
26
  if (note.image) {
27
27
  const visual = await readVisual(project, release.version, note.id);
28
- exported.image = { alt: text.alt, fallbackTheme: themes(release.visuals)[0], variants: {} };
29
- for (const variant of themes(release.visuals)) {
28
+ const variants = activeVariants(visual, release.visuals);
29
+ exported.image = { alt: text.alt, fallbackTheme: variants[0], variants: {} };
30
+ for (const variant of variants) {
30
31
  const asset = visual.variants[variant];
31
32
  const relative = `assets/${release.version}/${path.posix.basename(asset.file)}`;
32
33
  exported.image.variants[variant] = { src: relative, width: asset.width, height: asset.height };
package/dist/images.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Theme, type Visual } from './model.js';
1
+ import { type AssetVariant, type Visual } from './model.js';
2
2
  import { Project } from './project.js';
3
3
  export declare function inspectImage(bytes: Buffer): Promise<{
4
4
  width: number;
@@ -6,13 +6,20 @@ export declare function inspectImage(bytes: Buffer): Promise<{
6
6
  extension: string;
7
7
  sha256: string;
8
8
  }>;
9
- export interface ImageRequest {
9
+ export type ImageRequest = {
10
10
  note: string;
11
- theme: Theme;
11
+ theme: AssetVariant;
12
12
  reason: 'missing' | 'stale';
13
+ } & ({
14
+ action: 'generate';
13
15
  promptFile: string;
14
16
  compositionReference: string | null;
15
- }
17
+ } | {
18
+ action: 'provide';
19
+ promptFile: null;
20
+ compositionReference: null;
21
+ instruction: string;
22
+ });
16
23
  export declare function planImages(project: Project, version: string): Promise<{
17
24
  version: string;
18
25
  configuredThemes: ("dark" | "light")[];
@@ -20,9 +27,11 @@ export declare function planImages(project: Project, version: string): Promise<{
20
27
  readyAssets: number;
21
28
  pendingAssets: number;
22
29
  requests: ImageRequest[];
30
+ generationRequests: number;
31
+ providedRequests: number;
23
32
  costNote: string;
24
33
  }>;
25
- export declare function importImage(project: Project, version: string, noteId: string, variant: Theme, source: string): Promise<{
34
+ export declare function importImage(project: Project, version: string, noteId: string, variant: AssetVariant, source: string): Promise<{
26
35
  file: string;
27
36
  sha256: string;
28
37
  sceneHash: string;