@danceiny/gotry 0.0.1-rc.14 → 0.0.1-rc.16

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 (142) hide show
  1. package/README.md +26 -20
  2. package/README.zh-CN.md +27 -21
  3. package/bin/gotry-bootstrap.js +331 -3
  4. package/cordis.gotry-patch.yml +10 -0
  5. package/data/airline-airports.json +39 -0
  6. package/dist/capabilities/agent-reach-deep.js +1 -1
  7. package/dist/capabilities/agent-reach.js +1 -1
  8. package/dist/capabilities/anything.js +1 -1
  9. package/dist/capabilities/artifacts.js +217 -0
  10. package/dist/capabilities/effect.js +293 -0
  11. package/dist/capabilities/fact-log.js +41 -0
  12. package/dist/capabilities/flyai.js +1 -1
  13. package/dist/capabilities/hbcli.js +43 -1
  14. package/dist/capabilities/incident-log.js +1 -1
  15. package/dist/capabilities/opensky.js +1 -1
  16. package/dist/capabilities/resilience.js +90 -0
  17. package/dist/capabilities/session/action-cache.js +1 -1
  18. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  19. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  20. package/dist/capabilities/session/benchmark.js +2 -1
  21. package/dist/capabilities/session/extension-bridge.js +345 -0
  22. package/dist/capabilities/session/extension-channel.js +93 -0
  23. package/dist/capabilities/session/extract.js +1 -1
  24. package/dist/capabilities/session/health-watch.js +216 -0
  25. package/dist/capabilities/session/read-guard.js +1 -1
  26. package/dist/capabilities/session/transport.js +1 -1
  27. package/dist/capabilities/session/wizard.js +377 -0
  28. package/dist/capabilities/session-consent.js +1 -1
  29. package/dist/capabilities/session-login.js +77 -1
  30. package/dist/capabilities/session-search.js +69 -2
  31. package/dist/capabilities/weather.js +1 -1
  32. package/dist/scripts/action-cache-tests.js +1 -1
  33. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  34. package/dist/scripts/agent-reach-tests.js +1 -1
  35. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  36. package/dist/scripts/anything-tests.js +1 -1
  37. package/dist/scripts/async-collect.js +1 -1
  38. package/dist/scripts/booking-saga-tests.js +187 -0
  39. package/dist/scripts/bootstrap-tests.js +49 -3
  40. package/dist/scripts/build-changelog.js +279 -0
  41. package/dist/scripts/changelog-tests.js +165 -0
  42. package/dist/scripts/companion-tests.js +1 -1
  43. package/dist/scripts/diff-test.js +1 -1
  44. package/dist/scripts/effect-tests.js +474 -0
  45. package/dist/scripts/engine-run.js +1 -1
  46. package/dist/scripts/engine-tests.js +1 -1
  47. package/dist/scripts/extension-tests.js +468 -0
  48. package/dist/scripts/fact-gate-tests.js +318 -0
  49. package/dist/scripts/flyai-tests.js +1 -1
  50. package/dist/scripts/hbcli-e2e-tests.js +180 -0
  51. package/dist/scripts/hbcli-tests.js +1 -1
  52. package/dist/scripts/health-watch-cli.js +51 -0
  53. package/dist/scripts/i18n-tests.js +1 -1
  54. package/dist/scripts/incident-tests.js +1 -1
  55. package/dist/scripts/journey-tests.js +1 -1
  56. package/dist/scripts/ledger-tests.js +1 -1
  57. package/dist/scripts/ledger-workflow-crash.js +1 -1
  58. package/dist/scripts/memory-capture-tests.js +1 -1
  59. package/dist/scripts/memory-decay-tests.js +1 -1
  60. package/dist/scripts/memory-metrics.js +1 -1
  61. package/dist/scripts/memory-value-report.js +1 -1
  62. package/dist/scripts/nightly-evidence-tests.js +186 -0
  63. package/dist/scripts/nightly-evidence.js +289 -0
  64. package/dist/scripts/nudge-digest.js +1 -1
  65. package/dist/scripts/onboarding-tests.js +218 -0
  66. package/dist/scripts/opensky-check.js +1 -1
  67. package/dist/scripts/opensky-tests.js +1 -1
  68. package/dist/scripts/price-drift-tests.js +441 -0
  69. package/dist/scripts/price-drift-watch.js +491 -0
  70. package/dist/scripts/probe-poi-tests.js +1 -1
  71. package/dist/scripts/product-metrics.js +1 -1
  72. package/dist/scripts/publish-preverify.js +1 -1
  73. package/dist/scripts/realtime-pricing-tests.js +1 -1
  74. package/dist/scripts/replay-async.js +1 -1
  75. package/dist/scripts/replay-real.js +1 -1
  76. package/dist/scripts/replay.js +1 -1
  77. package/dist/scripts/session-attach-diagnose.js +1 -1
  78. package/dist/scripts/session-attach-poc.js +1 -1
  79. package/dist/scripts/session-benchmark.js +1 -1
  80. package/dist/scripts/session-extract-tests.js +1 -1
  81. package/dist/scripts/session-login.js +1 -1
  82. package/dist/scripts/session-tests.js +1 -1
  83. package/dist/scripts/skeleton-check.js +1 -1
  84. package/dist/scripts/skeleton-integration-test.js +1 -1
  85. package/dist/scripts/skills-contract-tests.js +1 -1
  86. package/dist/scripts/smoke.js +159 -1
  87. package/dist/scripts/state-cli-tests.js +1 -1
  88. package/dist/scripts/state-cli.js +1 -1
  89. package/dist/scripts/time-eval-tests.js +1 -1
  90. package/dist/scripts/travel-timeline-tests.js +1 -1
  91. package/dist/scripts/unified-tests.js +1 -1
  92. package/dist/scripts/weather-tests.js +1 -1
  93. package/dist/scripts/wizard-bootstrap.js +32 -0
  94. package/dist/scripts/z3-race-tests.js +1 -1
  95. package/dist/src/artifact-gate.js +310 -0
  96. package/dist/src/bookable-facts.js +349 -0
  97. package/dist/src/booking-saga.js +153 -0
  98. package/dist/src/bridge.js +1 -1
  99. package/dist/src/companions.js +1 -1
  100. package/dist/src/contracts.js +1 -1
  101. package/dist/src/dsh-llm.js +31 -7
  102. package/dist/src/engine.js +1 -1
  103. package/dist/src/i18n.js +1 -1
  104. package/dist/src/index.js +322 -46
  105. package/dist/src/journey.js +1 -1
  106. package/dist/src/loop.js +1 -1
  107. package/dist/src/memory-capture.js +1 -1
  108. package/dist/src/memory-decay.js +1 -1
  109. package/dist/src/memory-utility.js +1 -1
  110. package/dist/src/mock-llm.js +1 -1
  111. package/dist/src/model.js +1 -1
  112. package/dist/src/realtime-pricing.js +14 -7
  113. package/dist/src/slot-spec.js +1 -1
  114. package/dist/src/state-ledger.js +1 -1
  115. package/dist/src/time-anchor.js +1 -1
  116. package/dist/src/tool-packet.js +1 -1
  117. package/dist/src/travel-slots.js +1 -1
  118. package/dist/src/travel-timeline.js +1 -1
  119. package/dist/src/unified.js +1 -1
  120. package/dist/src/wish-pool.js +1 -1
  121. package/dist/src/z3-shared.js +1 -1
  122. package/extension/README.md +26 -0
  123. package/extension/background.js +160 -0
  124. package/extension/content-bridge.js +41 -0
  125. package/extension/content-main.js +62 -0
  126. package/extension/manifest.json +32 -0
  127. package/package.json +8 -2
  128. package/ts/capabilities/artifacts.ts +235 -0
  129. package/ts/capabilities/fact-log.ts +54 -0
  130. package/ts/capabilities/hbcli.ts +46 -0
  131. package/ts/capabilities/session/benchmark.ts +4 -1
  132. package/ts/capabilities/session/extension-bridge.ts +354 -0
  133. package/ts/capabilities/session/extension-channel.ts +92 -0
  134. package/ts/capabilities/session/health-watch.ts +257 -0
  135. package/ts/capabilities/session/wizard.ts +282 -0
  136. package/ts/capabilities/session-login.ts +53 -2
  137. package/ts/capabilities/session-search.ts +68 -3
  138. package/ts/src/artifact-gate.ts +365 -0
  139. package/ts/src/bookable-facts.ts +557 -0
  140. package/ts/src/booking-saga.ts +133 -0
  141. package/ts/src/dsh-llm.ts +40 -3
  142. package/ts/src/index.ts +230 -28
@@ -0,0 +1,279 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ const TYPE_TO_KEEP_A_CHANGELOG = {
5
+ feat: 'Added',
6
+ fix: 'Fixed',
7
+ perf: 'Changed',
8
+ refactor: 'Changed',
9
+ docs: 'Documentation',
10
+ test: 'Tests',
11
+ build: 'Build',
12
+ ci: 'CI',
13
+ chore: 'Chore',
14
+ revert: 'Reverted'
15
+ };
16
+ const DISPLAY_ORDER = [
17
+ 'feat',
18
+ 'fix',
19
+ 'perf',
20
+ 'refactor',
21
+ 'revert',
22
+ 'docs',
23
+ 'test',
24
+ 'build',
25
+ 'ci',
26
+ 'chore',
27
+ 'other'
28
+ ];
29
+ const CONVENTIONAL_RE = /^(feat|fix|perf|refactor|docs|test|build|ci|chore|revert)(?:\(([^)]+)\))?(!)?:\s*(.+)$/;
30
+ export function parseCommit(raw) {
31
+ const lines = raw.split('\n');
32
+ const firstLine = lines[0] ?? '';
33
+ if (!firstLine) return null;
34
+ const { head, prRef } = splitSubjectAndPr(firstLine);
35
+ const match = head.match(CONVENTIONAL_RE);
36
+ if (!match) {
37
+ return {
38
+ sha: '',
39
+ type: 'other',
40
+ scope: null,
41
+ subject: head,
42
+ prRef,
43
+ raw
44
+ };
45
+ }
46
+ const [, type, scope] = match;
47
+ const colonIdx = head.indexOf(': ');
48
+ const subject = colonIdx >= 0 ? head.slice(colonIdx + 2).trim() : head;
49
+ return {
50
+ sha: '',
51
+ type: type,
52
+ scope: scope ?? null,
53
+ subject,
54
+ prRef,
55
+ raw
56
+ };
57
+ }
58
+ function splitSubjectAndPr(text) {
59
+ const m = text.match(/\s+\(#(\d+)\)\s*$/);
60
+ if (m) return {
61
+ head: text.slice(0, m.index).trim(),
62
+ prRef: m[1]
63
+ };
64
+ return {
65
+ head: text.trim(),
66
+ prRef: null
67
+ };
68
+ }
69
+ function extractPrRef(text) {
70
+ const m = text.match(/\(#(\d+)\)/);
71
+ return m ? m[1] : null;
72
+ }
73
+ export function listCommits(opts) {
74
+ const args = [
75
+ 'log',
76
+ '--no-merges',
77
+ '--pretty=format:%H%x00%s%x00%b%x00%x1e'
78
+ ];
79
+ if (opts.since) args.push(`${opts.since}..HEAD`);
80
+ const out = execFileSync('git', args, {
81
+ cwd: opts.cwd,
82
+ encoding: 'utf8'
83
+ });
84
+ if (!out) return [];
85
+ return out.split('\u001e').filter(Boolean).map((raw)=>{
86
+ const [sha, subject, body] = raw.split('\u0000').map((s)=>(s ?? '').trim());
87
+ return {
88
+ sha: sha ?? '',
89
+ subject: subject ?? '',
90
+ body: body ?? ''
91
+ };
92
+ });
93
+ }
94
+ export function groupCommits(commits) {
95
+ const sections = new Map();
96
+ for (const c of commits){
97
+ if (!sections.has(c.type)) sections.set(c.type, {
98
+ type: c.type,
99
+ items: []
100
+ });
101
+ sections.get(c.type).items.push({
102
+ subject: c.subject,
103
+ sha: c.sha,
104
+ prRef: c.prRef
105
+ });
106
+ }
107
+ const out = [];
108
+ for (const t of DISPLAY_ORDER){
109
+ const sec = sections.get(t);
110
+ if (sec && sec.items.length > 0) out.push(sec);
111
+ }
112
+ return out;
113
+ }
114
+ export function renderMarkdownEntry(entry) {
115
+ const lines = [];
116
+ lines.push(`## [${entry.version}] - ${entry.date}`);
117
+ lines.push('');
118
+ for (const sec of entry.sections){
119
+ const header = sec.type === 'other' ? 'Other' : TYPE_TO_KEEP_A_CHANGELOG[sec.type] ?? sec.type;
120
+ lines.push(`### ${header}`);
121
+ lines.push('');
122
+ for (const item of sec.items){
123
+ const subject = truncateSubject(item.subject, 120);
124
+ const suffix = item.prRef ? ` (#${item.prRef})` : item.sha ? ` (${item.sha.slice(0, 7)})` : '';
125
+ lines.push(`- ${subject}${suffix}`);
126
+ }
127
+ lines.push('');
128
+ }
129
+ return lines.join('\n');
130
+ }
131
+ function truncateSubject(text, max) {
132
+ if (text.length <= max * 2) {
133
+ const breakers = [
134
+ '。',
135
+ '——',
136
+ '; ',
137
+ ' — ',
138
+ ',',
139
+ ','
140
+ ];
141
+ for (const b of breakers){
142
+ const i = text.indexOf(b);
143
+ if (i > 30 && i <= max * 2) return `${text.slice(0, i).trim()}…`;
144
+ }
145
+ }
146
+ return `${text.slice(0, max).trim()}…`;
147
+ }
148
+ export function buildEntry(opts) {
149
+ return {
150
+ version: opts.version,
151
+ date: opts.date,
152
+ sections: groupCommits(opts.commits)
153
+ };
154
+ }
155
+ const CHANGELOG_HEADER = `# Changelog
156
+
157
+ All notable changes to this project will be documented in this file.
158
+
159
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
160
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
161
+
162
+ `;
163
+ export function splitChangelog(raw) {
164
+ const firstSection = raw.indexOf('\n## [');
165
+ if (firstSection < 0) return {
166
+ preamble: raw.endsWith('\n') ? raw : `${raw}\n`,
167
+ history: []
168
+ };
169
+ const preamble = raw.slice(0, firstSection + 1);
170
+ const history = raw.slice(firstSection + 1);
171
+ return {
172
+ preamble,
173
+ history: [
174
+ history
175
+ ]
176
+ };
177
+ }
178
+ export function prependEntry(raw, entryMarkdown) {
179
+ if (!existsSync(join('..', 'CHANGELOG.md')) && !raw) {
180
+ return CHANGELOG_HEADER + entryMarkdown;
181
+ }
182
+ const split = splitChangelog(raw || CHANGELOG_HEADER + '');
183
+ return split.preamble + entryMarkdown + '\n' + split.history.join('').replace(/^\n/, '');
184
+ }
185
+ function arg(name) {
186
+ const i = process.argv.indexOf(name);
187
+ return i >= 0 ? process.argv[i + 1] : undefined;
188
+ }
189
+ function readPackageVersion() {
190
+ const raw = JSON.parse(readFileSync(join('..', 'package.json'), 'utf8'));
191
+ if (!raw.version) throw new Error('package.json 缺 version 字段');
192
+ return raw.version;
193
+ }
194
+ function gitHeadSha() {
195
+ return execFileSync('git', [
196
+ 'rev-parse',
197
+ 'HEAD'
198
+ ], {
199
+ encoding: 'utf8'
200
+ }).trim();
201
+ }
202
+ export function buildFromGit(opts) {
203
+ const rawCommits = listCommits({
204
+ cwd: opts.cwd,
205
+ since: opts.since
206
+ });
207
+ const parsed = [];
208
+ for (const r of rawCommits){
209
+ const m = parseCommit(r.subject);
210
+ if (!m) continue;
211
+ m.sha = r.sha;
212
+ m.raw = r.body;
213
+ parsed.push(m);
214
+ }
215
+ const entry = buildEntry({
216
+ version: opts.version,
217
+ date: opts.date,
218
+ commits: parsed
219
+ });
220
+ const markdown = renderMarkdownEntry(entry);
221
+ return {
222
+ entry,
223
+ markdown
224
+ };
225
+ }
226
+ async function main() {
227
+ const cwd = join('..');
228
+ const version = arg('--version') ?? readPackageVersion();
229
+ const date = arg('--date') ?? new Date().toISOString().slice(0, 10);
230
+ const since = arg('--since');
231
+ const write = process.argv.includes('--write');
232
+ let sinceTag = since;
233
+ if (!sinceTag) {
234
+ const out = execFileSync('git', [
235
+ 'tag',
236
+ '-l',
237
+ 'v*',
238
+ '--sort=-v:refname'
239
+ ], {
240
+ cwd,
241
+ encoding: 'utf8'
242
+ });
243
+ const tags = out.split('\n').map((t)=>t.trim()).filter(Boolean);
244
+ sinceTag = tags.find((t)=>t !== `v${version}` && tagsAreLessThan(t, `v${version}`)) ?? tags[tags.length - 1];
245
+ }
246
+ if (!sinceTag) {
247
+ console.error('build-changelog: 找不到起始 tag;传 --since <tag> 显式指定');
248
+ process.exit(2);
249
+ }
250
+ const { entry, markdown } = buildFromGit({
251
+ cwd,
252
+ version,
253
+ date,
254
+ since: sinceTag
255
+ });
256
+ const existing = existsSync(join(cwd, 'CHANGELOG.md')) ? readFileSync(join(cwd, 'CHANGELOG.md'), 'utf8') : '';
257
+ const next = write ? prependEntry(existing, markdown) : markdown;
258
+ console.log(`# build-changelog: ${entry.sections.length} sections / ${entry.sections.reduce((n, s)=>n + s.items.length, 0)} commits since ${sinceTag}`);
259
+ for (const sec of entry.sections){
260
+ console.log(`## ${sec.type} (${sec.items.length})`);
261
+ for (const it of sec.items)console.log(` - ${it.subject}${it.prRef ? ` (#${it.prRef})` : ''}`);
262
+ }
263
+ if (write) {
264
+ writeFileSync(join(cwd, 'CHANGELOG.md'), next, 'utf8');
265
+ console.log(`\n>> wrote CHANGELOG.md (${next.length}B) @ ${gitHeadSha().slice(0, 7)}`);
266
+ }
267
+ }
268
+ function tagsAreLessThan(a, b) {
269
+ return a < b;
270
+ }
271
+ if (process.argv[1]?.endsWith('build-changelog.ts')) {
272
+ main().catch((e)=>{
273
+ console.error(`build-changelog error: ${e.message}`);
274
+ process.exit(1);
275
+ });
276
+ }
277
+
278
+
279
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/build-changelog.ts
@@ -0,0 +1,165 @@
1
+ import assert from 'node:assert/strict';
2
+ import { buildEntry, groupCommits, parseCommit, prependEntry, renderMarkdownEntry, splitChangelog } from './build-changelog.js';
3
+ let passed = 0;
4
+ function ok(label) {
5
+ passed += 1;
6
+ console.log(` ok ${label}`);
7
+ }
8
+ const sample = parseCommit('feat(cost): 价表 provider-aware v2 + 价格漂移监测 (#68)');
9
+ assert.ok(sample);
10
+ assert.equal(sample.type, 'feat');
11
+ assert.equal(sample.scope, 'cost');
12
+ assert.equal(sample.subject, '价表 provider-aware v2 + 价格漂移监测');
13
+ assert.equal(sample.prRef, '68');
14
+ ok('parseCommit feat(scope)! + #PR');
15
+ const noScope = parseCommit('fix: 修复登录页可见性');
16
+ assert.equal(noScope.type, 'fix');
17
+ assert.equal(noScope.scope, null);
18
+ assert.equal(noScope.subject, '修复登录页可见性');
19
+ assert.equal(noScope.prRef, null);
20
+ ok('parseCommit fix 无 scope');
21
+ const other = parseCommit('docs: README 更新');
22
+ assert.equal(other.type, 'docs');
23
+ const legacy = parseCommit('feat(issue #21 P3.6): 会话扩展 onboarding UX 闭环(点点点 + 装完零重跑)');
24
+ assert.equal(legacy.type, 'feat');
25
+ assert.equal(legacy.scope, 'issue #21 P3.6');
26
+ const historical = parseCommit('Merge branch main into feat/x');
27
+ assert.equal(historical.type, 'other');
28
+ assert.equal(historical.subject, 'Merge branch main into feat/x');
29
+ ok('parseCommit 历史 commit + 中文 subject + 无 #PR 兼容');
30
+ for (const t of [
31
+ 'perf',
32
+ 'refactor',
33
+ 'docs',
34
+ 'test',
35
+ 'build',
36
+ 'ci',
37
+ 'chore',
38
+ 'revert'
39
+ ]){
40
+ const p = parseCommit(`${t}: 一些改动`);
41
+ assert.equal(p.type, t);
42
+ }
43
+ ok('parseCommit 全 9 类型支持');
44
+ const commits = [
45
+ {
46
+ sha: 'aaa',
47
+ type: 'fix',
48
+ scope: null,
49
+ subject: 'fix bug',
50
+ prRef: '1',
51
+ raw: ''
52
+ },
53
+ {
54
+ sha: 'bbb',
55
+ type: 'feat',
56
+ scope: null,
57
+ subject: 'add feature',
58
+ prRef: '2',
59
+ raw: ''
60
+ },
61
+ {
62
+ sha: 'ccc',
63
+ type: 'docs',
64
+ scope: null,
65
+ subject: 'update docs',
66
+ prRef: null,
67
+ raw: ''
68
+ },
69
+ {
70
+ sha: 'ddd',
71
+ type: 'other',
72
+ scope: null,
73
+ subject: 'random commit',
74
+ prRef: null,
75
+ raw: ''
76
+ }
77
+ ];
78
+ const grouped = groupCommits(commits);
79
+ assert.equal(grouped.length, 4);
80
+ assert.equal(grouped[0].type, 'feat');
81
+ assert.equal(grouped[1].type, 'fix');
82
+ assert.equal(grouped[2].type, 'docs');
83
+ assert.equal(grouped[3].type, 'other');
84
+ ok('groupCommits Keep a Changelog 显示顺序(Added → Fixed → Documentation → Other)');
85
+ const entry = buildEntry({
86
+ version: '0.0.1-rc.16',
87
+ date: '2026-08-30',
88
+ commits: [
89
+ {
90
+ sha: 'aaa',
91
+ type: 'feat',
92
+ scope: null,
93
+ subject: 'add a brand new feature with substantial description text',
94
+ prRef: '2',
95
+ raw: ''
96
+ },
97
+ {
98
+ sha: 'bbb',
99
+ type: 'fix',
100
+ scope: null,
101
+ subject: 'fix a critical bug in the rendering path of the parser',
102
+ prRef: '1',
103
+ raw: ''
104
+ },
105
+ {
106
+ sha: 'ccc',
107
+ type: 'docs',
108
+ scope: null,
109
+ subject: 'update the documentation for the new auth module',
110
+ prRef: null,
111
+ raw: ''
112
+ }
113
+ ]
114
+ });
115
+ const md = renderMarkdownEntry(entry);
116
+ assert.match(md, /^## \[0\.0\.1-rc\.16\] - 2026-08-30/);
117
+ assert.match(md, /### Added/);
118
+ assert.match(md, /### Fixed/);
119
+ assert.match(md, /### Documentation/);
120
+ assert.match(md, /- add a brand new feature[^()]*\(#2\)/);
121
+ assert.match(md, /- fix a critical bug[^()]*\(#1\)/);
122
+ assert.match(md, /- update the documentation[^()]*\(ccc\)/);
123
+ ok('renderMarkdownEntry 节结构 + PR/sha 后缀');
124
+ const existing = `# Changelog
125
+
126
+ All notable changes to this project will be documented in this file.
127
+
128
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
129
+
130
+ ## [0.0.1-rc.15] - 2026-08-29
131
+
132
+ ### Added
133
+ - 预订 saga 状态机
134
+ `;
135
+ const newMd = renderMarkdownEntry(entry);
136
+ const next = prependEntry(existing, newMd);
137
+ assert.match(next, /## \[0\.0\.1-rc\.16\] - 2026-08-30/);
138
+ assert.match(next, /## \[0\.0\.1-rc\.15\] - 2026-08-29/);
139
+ assert.match(next, /预订 saga 状态机/);
140
+ ok('prependEntry:新版本段在顶部,历史段原样保留');
141
+ const fromEmpty = prependEntry('', newMd);
142
+ assert.match(fromEmpty, /Keep a Changelog/);
143
+ assert.match(fromEmpty, /## \[0\.0\.1-rc\.16\]/);
144
+ ok('prependEntry:空文件首次生成');
145
+ const split = splitChangelog(existing);
146
+ assert.ok(split.preamble.includes('All notable changes'));
147
+ assert.ok(split.history[0].includes('## [0.0.1-rc.15]'));
148
+ ok('splitChangelog preamble/history 分隔正确');
149
+ const emptyEntry = buildEntry({
150
+ version: '0.0.1-rc.16',
151
+ date: '2026-08-30',
152
+ commits: []
153
+ });
154
+ const emptyMd = renderMarkdownEntry(emptyEntry);
155
+ assert.match(emptyMd, /## \[0\.0\.1-rc\.16\]/);
156
+ ok('buildEntry 空 commit 列表 → 仍输出版本头(0 section,合规)');
157
+ const breaking = parseCommit('feat(api)!: 重命名端点 /v1/users → /v2/users (#99)');
158
+ assert.equal(breaking.type, 'feat');
159
+ assert.equal(breaking.subject, '重命名端点 /v1/users → /v2/users');
160
+ assert.equal(breaking.prRef, '99');
161
+ ok('parseCommit feat(scope)!: breaking change marker 容错');
162
+ console.log(`changelog tests: ${passed} 组断言全绿(纯函数)`);
163
+
164
+
165
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/changelog-tests.ts
@@ -109,4 +109,4 @@ pass('多人并存与 id 稳定性', ()=>{
109
109
  console.log(`\nCOMPANION TESTS: ${n}/4 OK(memory-design P2 守门面)`);
110
110
 
111
111
 
112
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/companion-tests.ts
112
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/companion-tests.ts
@@ -36,4 +36,4 @@ for (const id of Object.keys(tsV)){
36
36
  console.log('\nDIFF TEST OK: 双路径判定一致(纯 TS,无 Python 依赖)');
37
37
 
38
38
 
39
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/diff-test.ts
39
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/scripts/diff-test.ts