@agent-native/core 0.69.0 → 0.70.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 (200) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +48 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/changelog/parse.ts +245 -0
  5. package/corpus/core/src/cli/changelog.ts +199 -0
  6. package/corpus/core/src/cli/index.ts +19 -0
  7. package/corpus/core/src/cli/recap.ts +24 -1
  8. package/corpus/core/src/cli/skills.ts +72 -45
  9. package/corpus/core/src/client/CommandMenu.tsx +183 -75
  10. package/corpus/core/src/client/agent-chat-adapter.ts +44 -7
  11. package/corpus/core/src/client/analytics.ts +181 -0
  12. package/corpus/core/src/client/changelog/Changelog.tsx +321 -0
  13. package/corpus/core/src/client/index.ts +11 -0
  14. package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +54 -0
  15. package/corpus/core/src/client/settings/useBuilderStatus.ts +82 -20
  16. package/corpus/core/src/mcp/build-server.ts +1 -1
  17. package/corpus/core/src/mcp/embed-app.ts +112 -6
  18. package/corpus/core/src/server/attribution.ts +211 -0
  19. package/corpus/core/src/server/auth.ts +6 -0
  20. package/corpus/core/src/server/better-auth-instance.ts +49 -5
  21. package/corpus/core/src/server/builder-browser.ts +27 -1
  22. package/corpus/core/src/server/core-routes-plugin.ts +58 -0
  23. package/corpus/core/src/server/google-oauth.ts +19 -6
  24. package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
  25. package/corpus/core/src/styles/agent-conversation.css +21 -0
  26. package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  27. package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  28. package/corpus/templates/analytics/CHANGELOG.md +10 -0
  29. package/corpus/templates/analytics/actions/install-dashboard-template.ts +2 -2
  30. package/corpus/templates/analytics/actions/open-traffic-dashboard.ts +1 -1
  31. package/corpus/templates/analytics/actions/update-dashboard.ts +5 -3
  32. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +180 -144
  33. package/corpus/templates/analytics/app/components/layout/Header.tsx +2 -2
  34. package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
  35. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +221 -213
  36. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +6 -3
  37. package/corpus/templates/analytics/app/lib/demo-dashboard-path.ts +1 -1
  38. package/corpus/templates/analytics/app/lib/last-opened.ts +2 -1
  39. package/corpus/templates/analytics/app/pages/Settings.tsx +4 -0
  40. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -3
  41. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +2 -2
  42. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +101 -99
  43. package/corpus/templates/analytics/app/pages/overview/OverviewPage.tsx +1 -1
  44. package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +18 -5
  45. package/corpus/templates/analytics/app/routes/catalog.tsx +1 -1
  46. package/corpus/templates/analytics/app/routes/dashboards.$id.tsx +9 -0
  47. package/corpus/templates/analytics/app/routes/traffic.tsx +1 -1
  48. package/corpus/templates/analytics/changelog/2026-06-23-the-dashboards-and-analyses-sidebar-settings-buttons-now-sta.md +6 -0
  49. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +145 -0
  50. package/corpus/templates/analytics/server/db/index.ts +1 -1
  51. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +9 -2
  52. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +1 -1
  53. package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -2
  54. package/corpus/templates/analytics/server/plugins/core-routes.ts +6 -6
  55. package/corpus/templates/assets/CHANGELOG.md +10 -0
  56. package/corpus/templates/assets/app/root.tsx +7 -1
  57. package/corpus/templates/assets/app/routes/settings.tsx +6 -0
  58. package/corpus/templates/brain/CHANGELOG.md +10 -0
  59. package/corpus/templates/brain/app/root.tsx +7 -1
  60. package/corpus/templates/brain/app/routes/settings.tsx +8 -1
  61. package/corpus/templates/calendar/CHANGELOG.md +10 -0
  62. package/corpus/templates/calendar/app/pages/Settings.tsx +4 -0
  63. package/corpus/templates/calendar/app/root.tsx +7 -1
  64. package/corpus/templates/chat/CHANGELOG.md +10 -0
  65. package/corpus/templates/chat/app/root.tsx +7 -1
  66. package/corpus/templates/clips/CHANGELOG.md +10 -0
  67. package/corpus/templates/clips/app/components/player/share-dialog.tsx +33 -7
  68. package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +8 -0
  69. package/corpus/templates/clips/app/components/player/video-player.tsx +150 -20
  70. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +7 -11
  71. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +31 -0
  72. package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +71 -0
  73. package/corpus/templates/clips/app/root.tsx +7 -1
  74. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +15 -1
  75. package/corpus/templates/clips/app/routes/record.tsx +78 -5
  76. package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -5
  77. package/corpus/templates/clips/changelog/2026-06-23-clips-shared-in-slack-no-longer-show-a-could-not-start-playb.md +6 -0
  78. package/corpus/templates/clips/changelog/2026-06-23-made-the-play-button-on-shared-and-embedded-clips-scale-with.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-06-23-public-clip-share-links-now-show-whether-they-ll-play-inline.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-06-23-screen-camera-recordings-now-keep-the-presenter-s-face-in-th.md +6 -0
  81. package/corpus/templates/clips/desktop/src/lib/recorder.ts +20 -0
  82. package/corpus/templates/clips/desktop/src/main.tsx +3 -0
  83. package/corpus/templates/clips/desktop/src/overlays/region-record-border.tsx +76 -0
  84. package/corpus/templates/clips/desktop/src/styles.css +49 -0
  85. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +2 -1
  86. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +67 -1
  87. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
  88. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +4 -1
  89. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +51 -1
  90. package/corpus/templates/clips/shared/share-attribution.ts +79 -0
  91. package/corpus/templates/content/CHANGELOG.md +10 -0
  92. package/corpus/templates/content/app/root.tsx +7 -1
  93. package/corpus/templates/design/CHANGELOG.md +10 -0
  94. package/corpus/templates/design/actions/generate-design.ts +4 -0
  95. package/corpus/templates/design/app/root.tsx +7 -1
  96. package/corpus/templates/design/app/routes/settings.tsx +10 -2
  97. package/corpus/templates/dispatch/CHANGELOG.md +10 -0
  98. package/corpus/templates/dispatch/app/root.tsx +7 -1
  99. package/corpus/templates/forms/CHANGELOG.md +10 -0
  100. package/corpus/templates/forms/app/root.tsx +7 -1
  101. package/corpus/templates/macros/CHANGELOG.md +10 -0
  102. package/corpus/templates/macros/app/root.tsx +7 -1
  103. package/corpus/templates/mail/CHANGELOG.md +10 -0
  104. package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +3 -0
  105. package/corpus/templates/mail/app/pages/SettingsPage.tsx +27 -0
  106. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +31 -17
  107. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -4
  108. package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +34 -24
  109. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -4
  110. package/corpus/templates/plan/AGENTS.md +4 -0
  111. package/corpus/templates/plan/CHANGELOG.md +10 -0
  112. package/corpus/templates/plan/actions/view-screen.ts +5 -0
  113. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +98 -1
  114. package/corpus/templates/plan/app/pages/PlansPage.tsx +107 -7
  115. package/corpus/templates/plan/app/root.tsx +7 -1
  116. package/corpus/templates/plan/shared/share-attribution.ts +72 -0
  117. package/corpus/templates/slides/CHANGELOG.md +10 -0
  118. package/corpus/templates/slides/app/root.tsx +7 -1
  119. package/corpus/templates/videos/CHANGELOG.md +4 -151
  120. package/corpus/templates/videos/app/root.tsx +7 -1
  121. package/dist/changelog/parse.d.ts +70 -0
  122. package/dist/changelog/parse.d.ts.map +1 -0
  123. package/dist/changelog/parse.js +200 -0
  124. package/dist/changelog/parse.js.map +1 -0
  125. package/dist/cli/changelog.d.ts +4 -0
  126. package/dist/cli/changelog.d.ts.map +1 -0
  127. package/dist/cli/changelog.js +166 -0
  128. package/dist/cli/changelog.js.map +1 -0
  129. package/dist/cli/index.js +18 -0
  130. package/dist/cli/index.js.map +1 -1
  131. package/dist/cli/recap.d.ts.map +1 -1
  132. package/dist/cli/recap.js +22 -1
  133. package/dist/cli/recap.js.map +1 -1
  134. package/dist/cli/skills.d.ts +3 -3
  135. package/dist/cli/skills.d.ts.map +1 -1
  136. package/dist/cli/skills.js +72 -45
  137. package/dist/cli/skills.js.map +1 -1
  138. package/dist/client/CommandMenu.d.ts +17 -1
  139. package/dist/client/CommandMenu.d.ts.map +1 -1
  140. package/dist/client/CommandMenu.js +49 -13
  141. package/dist/client/CommandMenu.js.map +1 -1
  142. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  143. package/dist/client/agent-chat-adapter.js +43 -6
  144. package/dist/client/agent-chat-adapter.js.map +1 -1
  145. package/dist/client/analytics.d.ts +18 -0
  146. package/dist/client/analytics.d.ts.map +1 -1
  147. package/dist/client/analytics.js +177 -0
  148. package/dist/client/analytics.js.map +1 -1
  149. package/dist/client/changelog/Changelog.d.ts +47 -0
  150. package/dist/client/changelog/Changelog.d.ts.map +1 -0
  151. package/dist/client/changelog/Changelog.js +138 -0
  152. package/dist/client/changelog/Changelog.js.map +1 -0
  153. package/dist/client/index.d.ts +2 -1
  154. package/dist/client/index.d.ts.map +1 -1
  155. package/dist/client/index.js +2 -1
  156. package/dist/client/index.js.map +1 -1
  157. package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
  158. package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  159. package/dist/client/mcp-apps/McpAppRenderer.js +42 -1
  160. package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
  161. package/dist/client/settings/useBuilderStatus.d.ts +2 -0
  162. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  163. package/dist/client/settings/useBuilderStatus.js +58 -10
  164. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  165. package/dist/mcp/build-server.js +1 -1
  166. package/dist/mcp/build-server.js.map +1 -1
  167. package/dist/mcp/embed-app.d.ts.map +1 -1
  168. package/dist/mcp/embed-app.js +112 -6
  169. package/dist/mcp/embed-app.js.map +1 -1
  170. package/dist/server/attribution.d.ts +83 -0
  171. package/dist/server/attribution.d.ts.map +1 -0
  172. package/dist/server/attribution.js +178 -0
  173. package/dist/server/attribution.js.map +1 -0
  174. package/dist/server/auth.d.ts.map +1 -1
  175. package/dist/server/auth.js +7 -0
  176. package/dist/server/auth.js.map +1 -1
  177. package/dist/server/better-auth-instance.d.ts +9 -1
  178. package/dist/server/better-auth-instance.d.ts.map +1 -1
  179. package/dist/server/better-auth-instance.js +32 -2
  180. package/dist/server/better-auth-instance.js.map +1 -1
  181. package/dist/server/builder-browser.d.ts +4 -0
  182. package/dist/server/builder-browser.d.ts.map +1 -1
  183. package/dist/server/builder-browser.js +20 -1
  184. package/dist/server/builder-browser.js.map +1 -1
  185. package/dist/server/core-routes-plugin.d.ts +25 -0
  186. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  187. package/dist/server/core-routes-plugin.js +38 -0
  188. package/dist/server/core-routes-plugin.js.map +1 -1
  189. package/dist/server/google-oauth.d.ts.map +1 -1
  190. package/dist/server/google-oauth.js +16 -2
  191. package/dist/server/google-oauth.js.map +1 -1
  192. package/dist/shared/mcp-embed-headers.js +1 -1
  193. package/dist/shared/mcp-embed-headers.js.map +1 -1
  194. package/dist/styles/agent-conversation.css +21 -0
  195. package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  196. package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  197. package/package.json +1 -1
  198. package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
  199. package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
  200. /package/corpus/templates/analytics/app/routes/{dashboards.tsx → dashboards._index.tsx} +0 -0
@@ -1,157 +1,10 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased] - 2026-02-28
3
+ All notable user-facing changes to Agent-Native Videos are documented here. Open it any
4
+ time from the command menu (Cmd+K → "What's new").
4
5
 
5
- ### Architecture Improvements ✨
6
-
7
- - **Extracted Animation Logic to Reusable Pure Function**
8
- - Created `app/remotion/animations/useElementAnimations.ts` (202 lines)
9
- - Exported `calculateElementAnimations()` - pure function (not hook)
10
- - Removed 130 lines of animation logic from InteractiveCardGrid
11
- - Centralized all animation calculations in testable function
12
- - Can be called inside loops (no Rules of Hooks violations)
13
- - Other compositions can now reuse animation system instantly
14
- - Reduced InteractiveCardGrid from 400+ to 320 lines
15
- - Simpler and faster than hook-based approach
16
-
17
- - **Centralized Configuration Constants**
18
- - Created `app/config/constants.ts` (204 lines)
19
- - Eliminated all magic numbers across codebase
20
- - Organized by domain: ANIMATION_CONFIG, CURSOR_CONFIG, CARD_CONFIG, UI_CONFIG, etc.
21
- - Type-safe with `as const`
22
- - Well-documented with inline comments
23
-
24
- - **Code Quality Improvements**
25
- - Max function length: 87 lines → 42 lines
26
- - Animation logic now testable in isolation
27
- - Proper type guards with centralized validation
28
- - Cleaner separation of concerns
29
-
30
- **Impact**: Architecture grade improved from C+ to A-
6
+ ## 2026-06-23
31
7
 
32
8
  ### Added
33
9
 
34
- - **Color Animation Support**: Background and border color properties for cursor interactions
35
- - Added `backgroundColor` and `borderColor` to animation property options
36
- - Implemented color interpolation function for smooth color transitions
37
- - Color picker UI with native browser color input
38
- - Colors animate from each element's base color to target color (preserves multicolor designs)
39
-
40
- - **Click Animation Return-to-Hover**: Click animations now properly animate back
41
- - Implemented "there-and-back" animation (0→1→0 progress mapping)
42
- - Doubles animation duration to accommodate forward and return transitions
43
- - Smooth easing applied to both directions
44
-
45
- - **Timeline Visual Enhancements**
46
- - Changed cursor keyframe click indicator dot from grey/white to yellow (#facc15)
47
- - Improved visual distinction for click events in timeline
48
-
49
- ### Changed
50
-
51
- - **Playback Speed System**: Simplified from adaptive to manual control
52
- - Removed adaptive playback rate compensation based on FPS measurement
53
- - Added manual playback speed dropdown (0.25× to 2×)
54
- - Moved speed selector to VideoPlayer bottom controls (next to Frame counter)
55
- - Removed playback speed from Timeline component
56
-
57
- - **Composition Creation Workflow**: Restored AI-powered generation
58
- - Rewrote `NewCompositionPopover` with full agent chat integration
59
- - Added file attachment support (images, videos, SVGs via data URLs)
60
- - Implemented postMessage API for parent window communication
61
- - Added event listener for `builder.agentChat.chatRunning` completion detection
62
- - Slug-based URL generation with conflict resolution (`/c/comp-title`, `/c/comp-title-2`)
63
- - Navigate to `/c/new` on submission for AI generation
64
-
65
- - **Properties Panel Improvements**
66
- - Removed composition name input from Properties > Properties section (non-editable)
67
- - Hidden "x" unit label to avoid confusion with delete button (kept "px", "deg", etc.)
68
- - Moved "Add Property" section above property list (below Motion Curve)
69
- - Swapped + button to left side of dropdown
70
- - Added Enter key support to add properties from dropdown
71
- - Changed focus ring color to red-400 for consistency
72
- - Removed hex code display next to color picker (visible in native picker)
73
-
74
- - **Animation System Architecture**
75
- - Updated `AnimationKeyframe.value` type to support `number | string` for colors
76
- - Color animations only apply when `hoverProgress > 0` or `clickProgress > 0`
77
- - Each element's base color extracted and used as animation starting point
78
- - Hover and click animations support mixed numeric and color properties
79
-
80
- ### Fixed
81
-
82
- - Browser cache issues causing stale code errors
83
- - Fixed `ReferenceError: adaptivePlaybackRate is not defined`
84
- - Fixed `ReferenceError: onCreateComposition is not defined`
85
- - Solution: Dev server restart to clear Vite cache
86
-
87
- - Color animation not preserving element colors
88
- - Cards were all turning blue when backgroundColor animation added
89
- - Fixed by interpolating from each card's unique base color instead of fixed start color
90
- - Only applies color animations during active hover/click (preserves idle state)
91
-
92
- - Click animations jumping back to hover state
93
- - Animations were not tweening back, causing abrupt transitions
94
- - Implemented smooth 0→1→0 progress curve with doubled duration
95
-
96
- ### Technical Details
97
-
98
- #### Color Interpolation Implementation
99
-
100
- ```typescript
101
- // New function in elementAnimations.ts
102
- export function interpolateColor(
103
- color1: string,
104
- color2: string,
105
- progress: number,
106
- ): string;
107
- ```
108
-
109
- - Parses hex colors to RGB components
110
- - Linear interpolation per channel
111
- - Returns hex color string
112
-
113
- #### Animation Progress Mapping
114
-
115
- ```typescript
116
- // Click animation: 0→1→0 curve
117
- const rawProgress = framesSinceClick / clickDuration; // 0→2
118
- clickProgress = rawProgress <= 1 ? rawProgress : 2 - rawProgress; // 0→1→0
119
- ```
120
-
121
- #### Files Modified
122
-
123
- - `app/components/VideoPlayer.tsx` - Simplified playback rate
124
- - `app/components/Timeline.tsx` - Removed playback UI, changed dot color
125
- - `app/pages/CompositionView.tsx` - Playback rate state management
126
- - `app/components/NewCompositionPopover.tsx` - Complete rewrite for agent chat integration
127
- - `app/components/Sidebar.tsx` - Updated props, removed name input
128
- - `app/components/PropsEditor.tsx` - Removed composition name field
129
- - `app/components/CurrentElementPanel.tsx` - Color properties, UI improvements
130
- - `app/types/elementAnimations.ts` - Color support, interpolation
131
- - `app/remotion/compositions/InteractiveCardGrid.tsx` - Color animation logic
132
-
133
- #### Files Created
134
-
135
- - `app/remotion/animations/useElementAnimations.ts` (209 lines) - **Reusable animation hook**
136
- - `app/config/constants.ts` (204 lines) - **Centralized configuration**
137
- - `app/utils/compositionHelpers.ts` (378 lines) - Helper functions library
138
- - `app/utils/debug.ts` (104 lines) - Production-safe logging utility
139
- - `scripts/create-composition.ts` (127 lines) - Example composition script
140
- - `COMPOSITION_GUIDE.md` (787 lines) - Comprehensive API reference
141
- - `QUICK_START.md` (498 lines) - Beginner-friendly guide
142
- - `README.md` (209 lines) - Project overview
143
- - `CHANGELOG.md`, `CODE_REVIEW.md`, `TODO.md`, `PR_DESCRIPTION.md`, `SESSION_SUMMARY.md`
144
-
145
- ### Developer Experience
146
-
147
- - Native `<select>` supports type-to-search for properties
148
- - Arrow keys navigate property options
149
- - Enter key adds selected property
150
- - Color picker shows hex values natively
151
- - Improved visual hierarchy in properties panel
152
-
153
- ---
154
-
155
- ## Notes
156
-
157
- All changes maintain backward compatibility with existing compositions. Color animation feature is additive and optional.
10
+ - See what's new right inside Agent-Native Videos a changelog now lives in the command menu (Cmd+K).
@@ -20,6 +20,7 @@ import {
20
20
  configureTracking,
21
21
  getThemeInitScript,
22
22
  } from "@agent-native/core/client";
23
+ import changelog from "../CHANGELOG.md?raw";
23
24
  configureTracking({
24
25
  getDefaultProps: (_name, properties) => ({
25
26
  ...properties,
@@ -83,7 +84,12 @@ function AppContent() {
83
84
 
84
85
  return (
85
86
  <>
86
- <CommandMenu open={cmdkOpen} onOpenChange={setCmdkOpen}>
87
+ <CommandMenu
88
+ open={cmdkOpen}
89
+ onOpenChange={setCmdkOpen}
90
+ changelog={changelog}
91
+ changelogKey="videos"
92
+ >
87
93
  <CommandMenu.Group heading="Videos">
88
94
  <CommandMenu.Item onSelect={() => {}}>
89
95
  Search compositions
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Shared, dependency-free changelog parsing + serialization.
3
+ *
4
+ * Used by BOTH:
5
+ * - the browser bundle (rendering an app's CHANGELOG.md in the command
6
+ * menu / settings "What's new" surface), and
7
+ * - the `agent-native changelog` CLI (rolling pending entry files up into
8
+ * CHANGELOG.md).
9
+ *
10
+ * Keep this file isomorphic: no Node, no browser, no third-party deps. The
11
+ * markdown shape is the conventional "Keep a Changelog" layout — a top-level
12
+ * `# Changelog` heading followed by one `## <release>` section per release.
13
+ */
14
+ /** A single released section of a CHANGELOG.md file. */
15
+ export interface ChangelogEntry {
16
+ /** Stable id derived from the heading — used for "unseen" tracking. */
17
+ id: string;
18
+ /** Raw heading text, e.g. `2026-06-23` or `v1.2.0 — 2026-06-23`. */
19
+ title: string;
20
+ /** ISO date (YYYY-MM-DD) extracted from the heading, if present. */
21
+ date?: string;
22
+ /** Version label extracted from the heading, if present. */
23
+ version?: string;
24
+ /** Markdown body beneath the heading (until the next `## ` section). */
25
+ body: string;
26
+ }
27
+ /** A not-yet-released entry authored as a `changelog/<file>.md` file. */
28
+ export interface PendingChangelogEntry {
29
+ /** Category — `added`, `improved`, `fixed`, `changed`, etc. */
30
+ type: ChangelogChangeType;
31
+ /** ISO date the entry was authored (YYYY-MM-DD). */
32
+ date?: string;
33
+ /** User-facing description (markdown, single bullet). */
34
+ text: string;
35
+ }
36
+ export type ChangelogChangeType = "added" | "improved" | "fixed" | "changed" | "removed" | "security";
37
+ /**
38
+ * Order changes are grouped under a release heading. Anything not listed here
39
+ * falls back to the "changed" group, then renders in insertion order.
40
+ */
41
+ export declare const CHANGELOG_GROUP_ORDER: ChangelogChangeType[];
42
+ declare const GROUP_LABELS: Record<ChangelogChangeType, string>;
43
+ /** Lowercase, hyphenate, and strip to a URL/id-safe slug. */
44
+ export declare function changelogSlug(value: string): string;
45
+ /**
46
+ * Parse a CHANGELOG.md document into structured release entries.
47
+ *
48
+ * Tolerant by design: an empty or malformed file yields an empty list rather
49
+ * than throwing, so a missing/partial changelog never breaks the UI.
50
+ */
51
+ export declare function parseChangelog(markdown: string): ChangelogEntry[];
52
+ /**
53
+ * Parse a pending `changelog/<file>.md` entry: optional `---` frontmatter
54
+ * (`type:` / `date:`) followed by the markdown description body.
55
+ */
56
+ export declare function parsePendingEntry(content: string): PendingChangelogEntry;
57
+ /**
58
+ * Render a set of pending entries as a single dated release section (the body
59
+ * that goes beneath a `## <date>` heading). Groups bullets by type.
60
+ */
61
+ export declare function renderReleaseBody(entries: PendingChangelogEntry[]): string;
62
+ declare const CHANGELOG_HEADER: string;
63
+ /**
64
+ * Roll a batch of pending entries into an existing CHANGELOG.md document,
65
+ * prepending a new `## <date>` section above the most recent release. Returns
66
+ * the full updated document. Pure — the CLI handles file IO and deletion.
67
+ */
68
+ export declare function rollupChangelog(existing: string, pending: PendingChangelogEntry[], releaseDate: string): string;
69
+ export { CHANGELOG_HEADER, GROUP_LABELS };
70
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/changelog/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,yEAAyE;AACzE,MAAM,WAAW,qBAAqB;IACpC,+DAA+D;IAC/D,IAAI,EAAE,mBAAmB,CAAC;IAC1B,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,mBAAmB,GAC3B,OAAO,GACP,UAAU,GACV,OAAO,GACP,SAAS,GACT,SAAS,GACT,UAAU,CAAC;AAEf;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,mBAAmB,EAOtD,CAAC;AAEF,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAOrD,CAAC;AAIF,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMnD;AAiBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CA+CjE;AAOD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAuBxE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,EAAE,GAAG,MAAM,CAwB1E;AAED,QAAA,MAAM,gBAAgB,QAEgD,CAAC;AAEvE;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,qBAAqB,EAAE,EAChC,WAAW,EAAE,MAAM,GAClB,MAAM,CAgBR;AAED,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Shared, dependency-free changelog parsing + serialization.
3
+ *
4
+ * Used by BOTH:
5
+ * - the browser bundle (rendering an app's CHANGELOG.md in the command
6
+ * menu / settings "What's new" surface), and
7
+ * - the `agent-native changelog` CLI (rolling pending entry files up into
8
+ * CHANGELOG.md).
9
+ *
10
+ * Keep this file isomorphic: no Node, no browser, no third-party deps. The
11
+ * markdown shape is the conventional "Keep a Changelog" layout — a top-level
12
+ * `# Changelog` heading followed by one `## <release>` section per release.
13
+ */
14
+ /**
15
+ * Order changes are grouped under a release heading. Anything not listed here
16
+ * falls back to the "changed" group, then renders in insertion order.
17
+ */
18
+ export const CHANGELOG_GROUP_ORDER = [
19
+ "added",
20
+ "improved",
21
+ "fixed",
22
+ "changed",
23
+ "removed",
24
+ "security",
25
+ ];
26
+ const GROUP_LABELS = {
27
+ added: "Added",
28
+ improved: "Improved",
29
+ fixed: "Fixed",
30
+ changed: "Changed",
31
+ removed: "Removed",
32
+ security: "Security",
33
+ };
34
+ const ISO_DATE = /(\d{4}-\d{2}-\d{2})/;
35
+ /** Lowercase, hyphenate, and strip to a URL/id-safe slug. */
36
+ export function changelogSlug(value) {
37
+ return value
38
+ .toLowerCase()
39
+ .replace(/[^a-z0-9]+/g, "-")
40
+ .replace(/^-+|-+$/g, "")
41
+ .slice(0, 60);
42
+ }
43
+ function normalizeType(raw) {
44
+ const value = (raw ?? "").trim().toLowerCase();
45
+ if (CHANGELOG_GROUP_ORDER.includes(value)) {
46
+ return value;
47
+ }
48
+ // Friendly aliases.
49
+ if (value === "feature" || value === "new" || value === "add")
50
+ return "added";
51
+ if (value === "improvement" || value === "enhancement" || value === "perf") {
52
+ return "improved";
53
+ }
54
+ if (value === "fix" || value === "bugfix" || value === "bug")
55
+ return "fixed";
56
+ if (value === "remove" || value === "deprecated")
57
+ return "removed";
58
+ return "changed";
59
+ }
60
+ /**
61
+ * Parse a CHANGELOG.md document into structured release entries.
62
+ *
63
+ * Tolerant by design: an empty or malformed file yields an empty list rather
64
+ * than throwing, so a missing/partial changelog never breaks the UI.
65
+ */
66
+ export function parseChangelog(markdown) {
67
+ if (!markdown || typeof markdown !== "string")
68
+ return [];
69
+ const lines = markdown.split(/\r?\n/);
70
+ const entries = [];
71
+ const seenIds = new Set();
72
+ let currentTitle = null;
73
+ let bodyLines = [];
74
+ const flush = () => {
75
+ if (currentTitle === null)
76
+ return;
77
+ const title = currentTitle.trim();
78
+ const date = title.match(ISO_DATE)?.[1];
79
+ const version = title.match(/v?\d+\.\d+(?:\.\d+)?/)?.[0];
80
+ // Build a stable, unique id from the heading.
81
+ let base = changelogSlug(title) || "entry";
82
+ let id = base;
83
+ let n = 2;
84
+ while (seenIds.has(id))
85
+ id = `${base}-${n++}`;
86
+ seenIds.add(id);
87
+ entries.push({
88
+ id,
89
+ title,
90
+ date,
91
+ version: version && version !== date ? version : undefined,
92
+ body: bodyLines.join("\n").trim(),
93
+ });
94
+ currentTitle = null;
95
+ bodyLines = [];
96
+ };
97
+ for (const line of lines) {
98
+ // `## ` (but not `### `) starts a new release section.
99
+ const match = /^##\s+(?!#)(.+?)\s*$/.exec(line);
100
+ if (match) {
101
+ flush();
102
+ currentTitle = stripBrackets(match[1]);
103
+ continue;
104
+ }
105
+ // Skip the top-level `# Changelog` title and anything before the first `##`.
106
+ if (currentTitle === null)
107
+ continue;
108
+ bodyLines.push(line);
109
+ }
110
+ flush();
111
+ return entries;
112
+ }
113
+ /** `## [1.2.0]` → `1.2.0`; leaves un-bracketed headings untouched. */
114
+ function stripBrackets(title) {
115
+ return title.replace(/^\[(.+?)\]\s*/, "$1 ").trim();
116
+ }
117
+ /**
118
+ * Parse a pending `changelog/<file>.md` entry: optional `---` frontmatter
119
+ * (`type:` / `date:`) followed by the markdown description body.
120
+ */
121
+ export function parsePendingEntry(content) {
122
+ let type;
123
+ let date;
124
+ let body = content;
125
+ const fm = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(content);
126
+ if (fm) {
127
+ for (const raw of fm[1].split(/\r?\n/)) {
128
+ const kv = /^([a-zA-Z]+)\s*:\s*(.+?)\s*$/.exec(raw);
129
+ if (!kv)
130
+ continue;
131
+ const key = kv[1].toLowerCase();
132
+ const value = kv[2].replace(/^["']|["']$/g, "").trim();
133
+ if (key === "type")
134
+ type = value;
135
+ else if (key === "date")
136
+ date = value.match(ISO_DATE)?.[1] ?? value;
137
+ }
138
+ body = content.slice(fm[0].length);
139
+ }
140
+ return {
141
+ type: normalizeType(type),
142
+ date,
143
+ text: body.trim(),
144
+ };
145
+ }
146
+ /**
147
+ * Render a set of pending entries as a single dated release section (the body
148
+ * that goes beneath a `## <date>` heading). Groups bullets by type.
149
+ */
150
+ export function renderReleaseBody(entries) {
151
+ const groups = new Map();
152
+ for (const entry of entries) {
153
+ const text = entry.text.trim();
154
+ if (!text)
155
+ continue;
156
+ const bullet = text.includes("\n")
157
+ ? // Preserve multi-line bodies, indenting continuation lines.
158
+ text
159
+ .split(/\r?\n/)
160
+ .map((l, i) => (i === 0 ? `- ${l}` : ` ${l}`))
161
+ .join("\n")
162
+ : `- ${text}`;
163
+ const list = groups.get(entry.type) ?? [];
164
+ list.push(bullet);
165
+ groups.set(entry.type, list);
166
+ }
167
+ const sections = [];
168
+ for (const type of CHANGELOG_GROUP_ORDER) {
169
+ const list = groups.get(type);
170
+ if (!list?.length)
171
+ continue;
172
+ sections.push(`### ${GROUP_LABELS[type]}\n\n${list.join("\n")}`);
173
+ }
174
+ return sections.join("\n\n");
175
+ }
176
+ const CHANGELOG_HEADER = "# Changelog\n\n" +
177
+ "All notable user-facing changes to this app are documented here.\n";
178
+ /**
179
+ * Roll a batch of pending entries into an existing CHANGELOG.md document,
180
+ * prepending a new `## <date>` section above the most recent release. Returns
181
+ * the full updated document. Pure — the CLI handles file IO and deletion.
182
+ */
183
+ export function rollupChangelog(existing, pending, releaseDate) {
184
+ const body = renderReleaseBody(pending);
185
+ if (!body)
186
+ return existing || `${CHANGELOG_HEADER}`;
187
+ const section = `## ${releaseDate}\n\n${body}\n`;
188
+ const doc = (existing || CHANGELOG_HEADER).replace(/\s+$/, "");
189
+ // Insert the new section immediately before the first existing `## ` release
190
+ // so the header/intro stays on top and releases stay newest-first.
191
+ const firstRelease = doc.search(/^##\s+(?!#)/m);
192
+ if (firstRelease === -1) {
193
+ return `${doc}\n\n${section}\n`;
194
+ }
195
+ const head = doc.slice(0, firstRelease).replace(/\s+$/, "");
196
+ const rest = doc.slice(firstRelease);
197
+ return `${head}\n\n${section}\n${rest}\n`;
198
+ }
199
+ export { CHANGELOG_HEADER, GROUP_LABELS };
200
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/changelog/parse.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared, dependency-free changelog parsing + serialization.\n *\n * Used by BOTH:\n * - the browser bundle (rendering an app's CHANGELOG.md in the command\n * menu / settings \"What's new\" surface), and\n * - the `agent-native changelog` CLI (rolling pending entry files up into\n * CHANGELOG.md).\n *\n * Keep this file isomorphic: no Node, no browser, no third-party deps. The\n * markdown shape is the conventional \"Keep a Changelog\" layout — a top-level\n * `# Changelog` heading followed by one `## <release>` section per release.\n */\n\n/** A single released section of a CHANGELOG.md file. */\nexport interface ChangelogEntry {\n /** Stable id derived from the heading — used for \"unseen\" tracking. */\n id: string;\n /** Raw heading text, e.g. `2026-06-23` or `v1.2.0 — 2026-06-23`. */\n title: string;\n /** ISO date (YYYY-MM-DD) extracted from the heading, if present. */\n date?: string;\n /** Version label extracted from the heading, if present. */\n version?: string;\n /** Markdown body beneath the heading (until the next `## ` section). */\n body: string;\n}\n\n/** A not-yet-released entry authored as a `changelog/<file>.md` file. */\nexport interface PendingChangelogEntry {\n /** Category — `added`, `improved`, `fixed`, `changed`, etc. */\n type: ChangelogChangeType;\n /** ISO date the entry was authored (YYYY-MM-DD). */\n date?: string;\n /** User-facing description (markdown, single bullet). */\n text: string;\n}\n\nexport type ChangelogChangeType =\n | \"added\"\n | \"improved\"\n | \"fixed\"\n | \"changed\"\n | \"removed\"\n | \"security\";\n\n/**\n * Order changes are grouped under a release heading. Anything not listed here\n * falls back to the \"changed\" group, then renders in insertion order.\n */\nexport const CHANGELOG_GROUP_ORDER: ChangelogChangeType[] = [\n \"added\",\n \"improved\",\n \"fixed\",\n \"changed\",\n \"removed\",\n \"security\",\n];\n\nconst GROUP_LABELS: Record<ChangelogChangeType, string> = {\n added: \"Added\",\n improved: \"Improved\",\n fixed: \"Fixed\",\n changed: \"Changed\",\n removed: \"Removed\",\n security: \"Security\",\n};\n\nconst ISO_DATE = /(\\d{4}-\\d{2}-\\d{2})/;\n\n/** Lowercase, hyphenate, and strip to a URL/id-safe slug. */\nexport function changelogSlug(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60);\n}\n\nfunction normalizeType(raw: string | undefined): ChangelogChangeType {\n const value = (raw ?? \"\").trim().toLowerCase();\n if ((CHANGELOG_GROUP_ORDER as string[]).includes(value)) {\n return value as ChangelogChangeType;\n }\n // Friendly aliases.\n if (value === \"feature\" || value === \"new\" || value === \"add\") return \"added\";\n if (value === \"improvement\" || value === \"enhancement\" || value === \"perf\") {\n return \"improved\";\n }\n if (value === \"fix\" || value === \"bugfix\" || value === \"bug\") return \"fixed\";\n if (value === \"remove\" || value === \"deprecated\") return \"removed\";\n return \"changed\";\n}\n\n/**\n * Parse a CHANGELOG.md document into structured release entries.\n *\n * Tolerant by design: an empty or malformed file yields an empty list rather\n * than throwing, so a missing/partial changelog never breaks the UI.\n */\nexport function parseChangelog(markdown: string): ChangelogEntry[] {\n if (!markdown || typeof markdown !== \"string\") return [];\n\n const lines = markdown.split(/\\r?\\n/);\n const entries: ChangelogEntry[] = [];\n const seenIds = new Set<string>();\n\n let currentTitle: string | null = null;\n let bodyLines: string[] = [];\n\n const flush = () => {\n if (currentTitle === null) return;\n const title = currentTitle.trim();\n const date = title.match(ISO_DATE)?.[1];\n const version = title.match(/v?\\d+\\.\\d+(?:\\.\\d+)?/)?.[0];\n // Build a stable, unique id from the heading.\n let base = changelogSlug(title) || \"entry\";\n let id = base;\n let n = 2;\n while (seenIds.has(id)) id = `${base}-${n++}`;\n seenIds.add(id);\n entries.push({\n id,\n title,\n date,\n version: version && version !== date ? version : undefined,\n body: bodyLines.join(\"\\n\").trim(),\n });\n currentTitle = null;\n bodyLines = [];\n };\n\n for (const line of lines) {\n // `## ` (but not `### `) starts a new release section.\n const match = /^##\\s+(?!#)(.+?)\\s*$/.exec(line);\n if (match) {\n flush();\n currentTitle = stripBrackets(match[1]);\n continue;\n }\n // Skip the top-level `# Changelog` title and anything before the first `##`.\n if (currentTitle === null) continue;\n bodyLines.push(line);\n }\n flush();\n\n return entries;\n}\n\n/** `## [1.2.0]` → `1.2.0`; leaves un-bracketed headings untouched. */\nfunction stripBrackets(title: string): string {\n return title.replace(/^\\[(.+?)\\]\\s*/, \"$1 \").trim();\n}\n\n/**\n * Parse a pending `changelog/<file>.md` entry: optional `---` frontmatter\n * (`type:` / `date:`) followed by the markdown description body.\n */\nexport function parsePendingEntry(content: string): PendingChangelogEntry {\n let type: string | undefined;\n let date: string | undefined;\n let body = content;\n\n const fm = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/.exec(content);\n if (fm) {\n for (const raw of fm[1].split(/\\r?\\n/)) {\n const kv = /^([a-zA-Z]+)\\s*:\\s*(.+?)\\s*$/.exec(raw);\n if (!kv) continue;\n const key = kv[1].toLowerCase();\n const value = kv[2].replace(/^[\"']|[\"']$/g, \"\").trim();\n if (key === \"type\") type = value;\n else if (key === \"date\") date = value.match(ISO_DATE)?.[1] ?? value;\n }\n body = content.slice(fm[0].length);\n }\n\n return {\n type: normalizeType(type),\n date,\n text: body.trim(),\n };\n}\n\n/**\n * Render a set of pending entries as a single dated release section (the body\n * that goes beneath a `## <date>` heading). Groups bullets by type.\n */\nexport function renderReleaseBody(entries: PendingChangelogEntry[]): string {\n const groups = new Map<ChangelogChangeType, string[]>();\n for (const entry of entries) {\n const text = entry.text.trim();\n if (!text) continue;\n const bullet = text.includes(\"\\n\")\n ? // Preserve multi-line bodies, indenting continuation lines.\n text\n .split(/\\r?\\n/)\n .map((l, i) => (i === 0 ? `- ${l}` : ` ${l}`))\n .join(\"\\n\")\n : `- ${text}`;\n const list = groups.get(entry.type) ?? [];\n list.push(bullet);\n groups.set(entry.type, list);\n }\n\n const sections: string[] = [];\n for (const type of CHANGELOG_GROUP_ORDER) {\n const list = groups.get(type);\n if (!list?.length) continue;\n sections.push(`### ${GROUP_LABELS[type]}\\n\\n${list.join(\"\\n\")}`);\n }\n return sections.join(\"\\n\\n\");\n}\n\nconst CHANGELOG_HEADER =\n \"# Changelog\\n\\n\" +\n \"All notable user-facing changes to this app are documented here.\\n\";\n\n/**\n * Roll a batch of pending entries into an existing CHANGELOG.md document,\n * prepending a new `## <date>` section above the most recent release. Returns\n * the full updated document. Pure — the CLI handles file IO and deletion.\n */\nexport function rollupChangelog(\n existing: string,\n pending: PendingChangelogEntry[],\n releaseDate: string,\n): string {\n const body = renderReleaseBody(pending);\n if (!body) return existing || `${CHANGELOG_HEADER}`;\n\n const section = `## ${releaseDate}\\n\\n${body}\\n`;\n\n const doc = (existing || CHANGELOG_HEADER).replace(/\\s+$/, \"\");\n // Insert the new section immediately before the first existing `## ` release\n // so the header/intro stays on top and releases stay newest-first.\n const firstRelease = doc.search(/^##\\s+(?!#)/m);\n if (firstRelease === -1) {\n return `${doc}\\n\\n${section}\\n`;\n }\n const head = doc.slice(0, firstRelease).replace(/\\s+$/, \"\");\n const rest = doc.slice(firstRelease);\n return `${head}\\n\\n${section}\\n${rest}\\n`;\n}\n\nexport { CHANGELOG_HEADER, GROUP_LABELS };\n"]}
@@ -0,0 +1,4 @@
1
+ import { CHANGELOG_HEADER } from "../changelog/parse.js";
2
+ export declare function runChangelog(args: string[]): Promise<number>;
3
+ export { CHANGELOG_HEADER };
4
+ //# sourceMappingURL=changelog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/cli/changelog.ts"],"names":[],"mappings":"AAiBA,OAAO,EAKL,gBAAgB,EAEjB,MAAM,uBAAuB,CAAC;AAsJ/B,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBlE;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * `agent-native changelog` — author and roll up an app's user-facing changelog.
3
+ *
4
+ * The model mirrors changesets: instead of editing the shared CHANGELOG.md
5
+ * directly (which conflicts when many agents work in parallel), each change
6
+ * drops a small pending entry file under `changelog/`. A later `release` rolls
7
+ * every pending file up into a single dated section of CHANGELOG.md.
8
+ *
9
+ * agent-native changelog add "Recordings can be trimmed before sharing" --type added
10
+ * agent-native changelog release # roll pending → CHANGELOG.md (today)
11
+ * agent-native changelog list # show pending + released
12
+ *
13
+ * Runs in the current app directory (process.cwd()).
14
+ */
15
+ import fs from "fs";
16
+ import path from "path";
17
+ import { parsePendingEntry, parseChangelog, rollupChangelog, changelogSlug, CHANGELOG_HEADER, } from "../changelog/parse.js";
18
+ const CHANGELOG_FILE = "CHANGELOG.md";
19
+ const PENDING_DIR = "changelog";
20
+ function todayIso() {
21
+ // Local date in YYYY-MM-DD. The CLI is the one place a wall-clock read is
22
+ // appropriate (unlike workflow scripts), so `new Date()` is fine here.
23
+ const d = new Date();
24
+ const pad = (n) => String(n).padStart(2, "0");
25
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
26
+ }
27
+ /** Minimal flag parser: supports `--key value` and `--key=value`. */
28
+ function parseFlags(args) {
29
+ const flags = {};
30
+ const rest = [];
31
+ for (let i = 0; i < args.length; i++) {
32
+ const arg = args[i];
33
+ if (arg.startsWith("--")) {
34
+ const eq = arg.indexOf("=");
35
+ if (eq !== -1) {
36
+ flags[arg.slice(2, eq)] = arg.slice(eq + 1);
37
+ }
38
+ else {
39
+ const next = args[i + 1];
40
+ if (next && !next.startsWith("--")) {
41
+ flags[arg.slice(2)] = next;
42
+ i++;
43
+ }
44
+ else {
45
+ flags[arg.slice(2)] = "true";
46
+ }
47
+ }
48
+ }
49
+ else {
50
+ rest.push(arg);
51
+ }
52
+ }
53
+ return { flags, rest };
54
+ }
55
+ function printUsage() {
56
+ console.log([
57
+ "Usage:",
58
+ ' agent-native changelog add "<summary>" [--type added|improved|fixed|changed|removed|security] [--date YYYY-MM-DD]',
59
+ " agent-native changelog release [--date YYYY-MM-DD]",
60
+ " agent-native changelog list",
61
+ "",
62
+ "Entries are user-facing notes. `add` writes a pending file under",
63
+ ` ${PENDING_DIR}/; \`release\` rolls all pending files into ${CHANGELOG_FILE}.`,
64
+ ].join("\n"));
65
+ }
66
+ function cmdAdd(args) {
67
+ const { flags, rest } = parseFlags(args);
68
+ const summary = rest.join(" ").trim();
69
+ if (!summary) {
70
+ console.error('Provide a summary, e.g. changelog add "Faster search"');
71
+ return 1;
72
+ }
73
+ const type = (flags.type ?? "changed");
74
+ const date = flags.date?.match(/\d{4}-\d{2}-\d{2}/)?.[0] ?? todayIso();
75
+ const dir = path.resolve(PENDING_DIR);
76
+ fs.mkdirSync(dir, { recursive: true });
77
+ const slug = changelogSlug(summary) || "entry";
78
+ let file = path.join(dir, `${date}-${slug}.md`);
79
+ let n = 2;
80
+ while (fs.existsSync(file)) {
81
+ file = path.join(dir, `${date}-${slug}-${n++}.md`);
82
+ }
83
+ // Blank line after the closing frontmatter delimiter so the generated file
84
+ // is already Prettier-clean (Markdown requires a blank line before body text)
85
+ // and never trips the repo fmt check.
86
+ const content = `---\ntype: ${type}\ndate: ${date}\n---\n\n${summary}\n`;
87
+ fs.writeFileSync(file, content, "utf-8");
88
+ console.log(`Added changelog entry: ${path.relative(process.cwd(), file)}`);
89
+ return 0;
90
+ }
91
+ function readPending() {
92
+ const dir = path.resolve(PENDING_DIR);
93
+ if (!fs.existsSync(dir))
94
+ return [];
95
+ return fs
96
+ .readdirSync(dir)
97
+ .filter((f) => f.endsWith(".md") && f.toLowerCase() !== "readme.md")
98
+ .sort()
99
+ .map((f) => ({
100
+ file: path.join(dir, f),
101
+ content: fs.readFileSync(path.join(dir, f), "utf-8"),
102
+ }));
103
+ }
104
+ function cmdRelease(args) {
105
+ const { flags } = parseFlags(args);
106
+ const date = flags.date?.match(/\d{4}-\d{2}-\d{2}/)?.[0] ?? todayIso();
107
+ const pendingFiles = readPending();
108
+ if (pendingFiles.length === 0) {
109
+ console.log("No pending changelog entries to release.");
110
+ return 0;
111
+ }
112
+ const pending = pendingFiles.map((p) => parsePendingEntry(p.content));
113
+ const changelogPath = path.resolve(CHANGELOG_FILE);
114
+ const existing = fs.existsSync(changelogPath)
115
+ ? fs.readFileSync(changelogPath, "utf-8")
116
+ : "";
117
+ const next = rollupChangelog(existing, pending, date);
118
+ fs.writeFileSync(changelogPath, next, "utf-8");
119
+ // Remove the pending entries now that they're released.
120
+ for (const p of pendingFiles)
121
+ fs.rmSync(p.file);
122
+ console.log(`Released ${pendingFiles.length} entr${pendingFiles.length === 1 ? "y" : "ies"} into ${CHANGELOG_FILE} (## ${date}).`);
123
+ return 0;
124
+ }
125
+ function cmdList() {
126
+ const pending = readPending();
127
+ const changelogPath = path.resolve(CHANGELOG_FILE);
128
+ const released = fs.existsSync(changelogPath)
129
+ ? parseChangelog(fs.readFileSync(changelogPath, "utf-8"))
130
+ : [];
131
+ console.log(`Pending (${pending.length}):`);
132
+ for (const p of pending) {
133
+ const entry = parsePendingEntry(p.content);
134
+ console.log(` - [${entry.type}] ${entry.text.split("\n")[0]} (${path.basename(p.file)})`);
135
+ }
136
+ console.log("");
137
+ console.log(`Released (${released.length}):`);
138
+ for (const r of released.slice(0, 10))
139
+ console.log(` - ${r.title}`);
140
+ return 0;
141
+ }
142
+ export async function runChangelog(args) {
143
+ const sub = args[0];
144
+ const rest = args.slice(1);
145
+ switch (sub) {
146
+ case "add":
147
+ return cmdAdd(rest);
148
+ case "release":
149
+ return cmdRelease(rest);
150
+ case "list":
151
+ return cmdList();
152
+ case undefined:
153
+ case "help":
154
+ case "--help":
155
+ case "-h":
156
+ printUsage();
157
+ return 0;
158
+ default:
159
+ console.error(`Unknown changelog subcommand: ${sub}\n`);
160
+ printUsage();
161
+ return 1;
162
+ }
163
+ }
164
+ // Re-export header for callers that want to seed an empty CHANGELOG.md.
165
+ export { CHANGELOG_HEADER };
166
+ //# sourceMappingURL=changelog.js.map