@iodes/releasekit 0.1.7 → 0.2.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.
- package/README.md +71 -5
- package/dist/assets.d.ts +4 -3
- package/dist/assets.js +4 -2
- package/dist/cli.js +115 -27
- package/dist/content.d.ts +7 -5
- package/dist/content.js +3 -1
- package/dist/export.d.ts +1 -0
- package/dist/export.js +33 -17
- package/dist/files.js +7 -2
- package/dist/images.d.ts +5 -3
- package/dist/images.js +3 -1
- package/dist/install.d.ts +36 -3
- package/dist/install.js +33 -5
- package/dist/migrate-config.d.ts +10 -0
- package/dist/migrate-config.js +44 -0
- package/dist/model.d.ts +69 -7
- package/dist/model.js +28 -5
- package/dist/move.d.ts +24 -0
- package/dist/move.js +292 -0
- package/dist/project.d.ts +13 -5
- package/dist/project.js +187 -33
- package/dist/refs.d.ts +6 -0
- package/dist/refs.js +29 -0
- package/dist/setup.d.ts +18 -0
- package/dist/setup.js +55 -0
- package/dist/status.d.ts +31 -0
- package/dist/status.js +52 -0
- package/dist/validate.d.ts +5 -2
- package/dist/validate.js +31 -17
- package/kit/references/adoption.md +3 -1
- package/kit/references/channels.md +88 -0
- package/kit/references/format.md +15 -5
- package/kit/references/workflow.md +4 -4
- package/kit/skills/releasekit-draft/SKILL.md +3 -1
- package/kit/skills/releasekit-finalize/SKILL.md +4 -2
- package/kit/skills/releasekit-image/SKILL.md +2 -0
- package/package.json +2 -1
- package/schemas/bundle.schema.json +54 -5
- package/schemas/config.schema.json +125 -9
- package/schemas/release.schema.json +46 -5
package/dist/install.d.ts
CHANGED
|
@@ -1,23 +1,56 @@
|
|
|
1
1
|
import { Project } from './project.js';
|
|
2
2
|
import { type ProjectConfig } from './model.js';
|
|
3
|
-
export declare function installSkills(project: Project): Promise<{
|
|
3
|
+
export declare function installSkills(project: Project, tools?: ProjectConfig['tools']): Promise<{
|
|
4
4
|
tools: ("claude" | "codex" | "cursor")[];
|
|
5
5
|
written: string[];
|
|
6
6
|
conflicts: string[];
|
|
7
|
+
unchanged: string[];
|
|
7
8
|
hints: {
|
|
8
9
|
codex: string;
|
|
9
10
|
claude: string;
|
|
10
11
|
cursor: string;
|
|
11
12
|
};
|
|
12
13
|
}>;
|
|
13
|
-
export declare function
|
|
14
|
+
export declare function updateProject(project: Project): Promise<{
|
|
15
|
+
product: string;
|
|
16
|
+
migrations: string[];
|
|
17
|
+
backup: null;
|
|
18
|
+
tools: ("claude" | "codex" | "cursor")[];
|
|
19
|
+
written: string[];
|
|
20
|
+
conflicts: string[];
|
|
21
|
+
unchanged: string[];
|
|
22
|
+
hints: {
|
|
23
|
+
codex: string;
|
|
24
|
+
claude: string;
|
|
25
|
+
cursor: string;
|
|
26
|
+
};
|
|
27
|
+
} | {
|
|
28
|
+
product: string;
|
|
29
|
+
migrations: string[];
|
|
30
|
+
backup: string;
|
|
31
|
+
tools: ("claude" | "codex" | "cursor")[];
|
|
32
|
+
written: string[];
|
|
33
|
+
conflicts: string[];
|
|
34
|
+
unchanged: string[];
|
|
35
|
+
hints: {
|
|
36
|
+
codex: string;
|
|
37
|
+
claude: string;
|
|
38
|
+
cursor: string;
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
41
|
+
export declare function formatUpdate(result: Awaited<ReturnType<typeof updateProject>>): string;
|
|
42
|
+
export interface InitOptions {
|
|
14
43
|
product?: string;
|
|
15
44
|
tools?: ProjectConfig['tools'];
|
|
16
45
|
themes?: ProjectConfig['visuals']['themes'];
|
|
17
|
-
|
|
46
|
+
sourceLocale?: string;
|
|
47
|
+
locales?: string[];
|
|
48
|
+
}
|
|
49
|
+
export declare function initProject(project: Project, options: InitOptions): Promise<{
|
|
18
50
|
tools: ("claude" | "codex" | "cursor")[];
|
|
19
51
|
written: string[];
|
|
20
52
|
conflicts: string[];
|
|
53
|
+
unchanged: string[];
|
|
21
54
|
hints: {
|
|
22
55
|
codex: string;
|
|
23
56
|
claude: string;
|
package/dist/install.js
CHANGED
|
@@ -3,18 +3,20 @@ import path from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { Project } from './project.js';
|
|
6
|
+
import { migrateConfig } from './migrate-config.js';
|
|
6
7
|
import { configSchema, defaultConfig } from './model.js';
|
|
7
8
|
import { exists, within, write, writeYaml, digest } from './files.js';
|
|
8
9
|
const resources = fileURLToPath(new URL('../kit/', import.meta.url));
|
|
9
10
|
const names = ['releasekit-draft', 'releasekit-image', 'releasekit-finalize'];
|
|
10
11
|
const managedSchema = z.record(z.string(), z.string().regex(/^[a-f0-9]{64}$/));
|
|
11
|
-
export async function installSkills(project) {
|
|
12
|
+
export async function installSkills(project, tools) {
|
|
12
13
|
const config = await project.config();
|
|
14
|
+
const selected = tools ?? config.tools;
|
|
13
15
|
const marker = await project.content('managed-skills.json');
|
|
14
16
|
const managed = await exists(marker) ? managedSchema.parse(JSON.parse(await fs.readFile(marker, 'utf8'))) : {};
|
|
15
|
-
const roots = new Set(
|
|
17
|
+
const roots = new Set(selected.map(tool => tool === 'claude' ? '.claude/skills' : '.agents/skills'));
|
|
16
18
|
const references = (await fs.readdir(path.join(resources, 'references'))).filter(file => file.endsWith('.md')).sort();
|
|
17
|
-
const written = [], conflicts = [];
|
|
19
|
+
const written = [], conflicts = [], unchanged = [];
|
|
18
20
|
for (const root of roots) {
|
|
19
21
|
for (const name of names) {
|
|
20
22
|
const sourceFiles = [
|
|
@@ -29,6 +31,7 @@ export async function installSkills(project) {
|
|
|
29
31
|
const actual = digest(await fs.readFile(destination));
|
|
30
32
|
if (actual === expected) {
|
|
31
33
|
managed[item.destination] = expected;
|
|
34
|
+
unchanged.push(item.destination);
|
|
32
35
|
continue;
|
|
33
36
|
}
|
|
34
37
|
if (actual !== managed[item.destination]) {
|
|
@@ -43,12 +46,30 @@ export async function installSkills(project) {
|
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
48
|
await write(marker, JSON.stringify(managed, null, 2) + '\n');
|
|
46
|
-
return { tools:
|
|
49
|
+
return { tools: selected, written, conflicts, unchanged, hints: {
|
|
47
50
|
codex: 'Use $releasekit-draft, $releasekit-image, or $releasekit-finalize.',
|
|
48
51
|
claude: 'Use /releasekit-draft, /releasekit-image, or /releasekit-finalize.',
|
|
49
52
|
cursor: 'Use the installed releasekit-* skills from the agent skill picker or name them in your request.',
|
|
50
53
|
} };
|
|
51
54
|
}
|
|
55
|
+
export async function updateProject(project) {
|
|
56
|
+
const migration = await migrateConfig(project);
|
|
57
|
+
return { ...await installSkills(project, ['codex', 'claude', 'cursor']), ...migration };
|
|
58
|
+
}
|
|
59
|
+
export function formatUpdate(result) {
|
|
60
|
+
const lines = [result.conflicts.length ? 'Update needs attention.' : result.tools.length ? 'Skills are up to date.' : 'No agent tools selected.',
|
|
61
|
+
` Updated: ${result.written.length} files`, ` Already current: ${result.unchanged.length} files`, ` Modified files preserved: ${result.conflicts.length}`];
|
|
62
|
+
if (result.migrations.length) {
|
|
63
|
+
lines.push('', ...result.migrations.map(item => ` Configuration: ${item}`), ` Original configuration: ${result.backup}`);
|
|
64
|
+
}
|
|
65
|
+
if (result.conflicts.length) {
|
|
66
|
+
lines.push('', ...result.conflicts.map(file => ` ! ${file}`), 'Compare these files with the installed package templates and merge the changes you want to keep.');
|
|
67
|
+
}
|
|
68
|
+
if (result.tools.length)
|
|
69
|
+
lines.push('', ...result.tools.map(tool => ` ${tool}: ${result.hints[tool]}`));
|
|
70
|
+
lines.push('', 'Next: releasekit status');
|
|
71
|
+
return lines.join('\n');
|
|
72
|
+
}
|
|
52
73
|
export async function initProject(project, options) {
|
|
53
74
|
const file = await project.content('config.yaml');
|
|
54
75
|
if (await exists(file))
|
|
@@ -58,6 +79,13 @@ export async function initProject(project, options) {
|
|
|
58
79
|
config.tools = [...new Set(options.tools)];
|
|
59
80
|
if (options.themes)
|
|
60
81
|
config.visuals.themes = options.themes;
|
|
61
|
-
|
|
82
|
+
if (options.sourceLocale !== undefined)
|
|
83
|
+
config.sourceLocale = options.sourceLocale;
|
|
84
|
+
config.locales = options.locales ?? [config.sourceLocale];
|
|
85
|
+
configSchema.parse(config);
|
|
86
|
+
if (!config.locales.includes(config.sourceLocale) || new Set(config.locales).size !== config.locales.length) {
|
|
87
|
+
throw new Error('Project locales must be unique and include the source locale.');
|
|
88
|
+
}
|
|
89
|
+
await writeYaml(file, config);
|
|
62
90
|
return { config: file, ...await installSkills(project) };
|
|
63
91
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { parseDocument } from 'yaml';
|
|
3
|
+
import { Project, parseProjectConfig } from './project.js';
|
|
4
|
+
import { canonical, exists, parseYaml, write } from './files.js';
|
|
5
|
+
export async function migrateConfig(project) {
|
|
6
|
+
const file = await project.content('config.yaml');
|
|
7
|
+
if (!(await exists(file)))
|
|
8
|
+
throw new Error('ReleaseKit is not initialized. Run releasekit init first.');
|
|
9
|
+
const original = await fs.readFile(file, 'utf8');
|
|
10
|
+
const raw = parseYaml(original);
|
|
11
|
+
const migrations = [];
|
|
12
|
+
if (raw && typeof raw === 'object' && 'history' in raw && raw.history && typeof raw.history === 'object' && 'limit' in raw.history) {
|
|
13
|
+
delete raw.history.limit;
|
|
14
|
+
migrations.push('Removed history.limit; use export --limit to limit exported releases. Omit --limit to export all releases.');
|
|
15
|
+
}
|
|
16
|
+
// Validate the complete proposed configuration before touching any files.
|
|
17
|
+
const config = parseProjectConfig(raw);
|
|
18
|
+
if (!migrations.length)
|
|
19
|
+
return { product: config.product, migrations, backup: null };
|
|
20
|
+
const document = parseDocument(original);
|
|
21
|
+
document.deleteIn(['history', 'limit']);
|
|
22
|
+
let migrated = document.toString();
|
|
23
|
+
if (original.includes('\r\n'))
|
|
24
|
+
migrated = migrated.replace(/\r?\n/g, '\r\n');
|
|
25
|
+
if (original.startsWith('\uFEFF') && !migrated.startsWith('\uFEFF'))
|
|
26
|
+
migrated = '\uFEFF' + migrated;
|
|
27
|
+
if (canonical(parseYaml(migrated)) !== canonical(raw))
|
|
28
|
+
throw new Error('Configuration migration would change unrelated settings. No files were changed.');
|
|
29
|
+
const backup = await project.content('config.yaml.before-update');
|
|
30
|
+
try {
|
|
31
|
+
await fs.writeFile(backup, original, { flag: 'wx' });
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error.code !== 'EEXIST')
|
|
35
|
+
throw error;
|
|
36
|
+
if (await fs.readFile(backup, 'utf8') !== original) {
|
|
37
|
+
throw new Error(`A different configuration backup already exists at ${backup}. Move it aside before running update again; no files were overwritten.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (await fs.readFile(file, 'utf8') !== original)
|
|
41
|
+
throw new Error('Configuration changed during update. Run update again; the configuration was not overwritten.');
|
|
42
|
+
await write(file, migrated);
|
|
43
|
+
return { product: config.product, migrations, backup };
|
|
44
|
+
}
|
package/dist/model.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const segment: z.ZodString;
|
|
3
|
+
export declare const channelName: z.ZodString;
|
|
4
|
+
export declare const channelRefSchema: z.ZodObject<{
|
|
5
|
+
channel: z.ZodString;
|
|
6
|
+
version: z.ZodString;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export type ReleaseRef = {
|
|
9
|
+
version: string;
|
|
10
|
+
channel?: string;
|
|
11
|
+
};
|
|
12
|
+
export type ReleaseId = string | ReleaseRef;
|
|
13
|
+
export declare const releasedAtSchema: z.ZodUnion<readonly [z.ZodISODate, z.ZodISODateTime]>;
|
|
3
14
|
export declare const sha: z.ZodString;
|
|
4
15
|
export declare const locale: z.ZodString;
|
|
5
16
|
export declare const theme: z.ZodEnum<{
|
|
@@ -66,13 +77,33 @@ export declare const historyStartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
66
77
|
version: z.ZodNull;
|
|
67
78
|
}, z.core.$strict>], "past">;
|
|
68
79
|
export type HistoryStart = z.infer<typeof historyStartSchema>;
|
|
80
|
+
export declare const channelsSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
81
|
+
include: z.ZodArray<z.ZodString>;
|
|
82
|
+
history: z.ZodOptional<z.ZodObject<{
|
|
83
|
+
start: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
84
|
+
ref: z.ZodString;
|
|
85
|
+
sha: z.ZodString;
|
|
86
|
+
past: z.ZodLiteral<"summary">;
|
|
87
|
+
version: z.ZodString;
|
|
88
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
89
|
+
ref: z.ZodString;
|
|
90
|
+
sha: z.ZodString;
|
|
91
|
+
past: z.ZodLiteral<"history">;
|
|
92
|
+
version: z.ZodString;
|
|
93
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
94
|
+
ref: z.ZodString;
|
|
95
|
+
sha: z.ZodString;
|
|
96
|
+
past: z.ZodLiteral<"skip">;
|
|
97
|
+
version: z.ZodNull;
|
|
98
|
+
}, z.core.$strict>], "past">>;
|
|
99
|
+
}, z.core.$strict>>;
|
|
100
|
+
}, z.core.$strict>>;
|
|
69
101
|
export declare const configSchema: z.ZodObject<{
|
|
70
102
|
schemaVersion: z.ZodLiteral<1>;
|
|
71
103
|
product: z.ZodString;
|
|
72
104
|
sourceLocale: z.ZodString;
|
|
73
105
|
locales: z.ZodArray<z.ZodString>;
|
|
74
|
-
history: z.ZodObject<{
|
|
75
|
-
limit: z.ZodNumber;
|
|
106
|
+
history: z.ZodOptional<z.ZodObject<{
|
|
76
107
|
start: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
77
108
|
ref: z.ZodString;
|
|
78
109
|
sha: z.ZodString;
|
|
@@ -89,7 +120,28 @@ export declare const configSchema: z.ZodObject<{
|
|
|
89
120
|
past: z.ZodLiteral<"skip">;
|
|
90
121
|
version: z.ZodNull;
|
|
91
122
|
}, z.core.$strict>], "past">>;
|
|
92
|
-
}, z.core.$strict
|
|
123
|
+
}, z.core.$strict>>;
|
|
124
|
+
channels: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
125
|
+
include: z.ZodArray<z.ZodString>;
|
|
126
|
+
history: z.ZodOptional<z.ZodObject<{
|
|
127
|
+
start: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
128
|
+
ref: z.ZodString;
|
|
129
|
+
sha: z.ZodString;
|
|
130
|
+
past: z.ZodLiteral<"summary">;
|
|
131
|
+
version: z.ZodString;
|
|
132
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
133
|
+
ref: z.ZodString;
|
|
134
|
+
sha: z.ZodString;
|
|
135
|
+
past: z.ZodLiteral<"history">;
|
|
136
|
+
version: z.ZodString;
|
|
137
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
138
|
+
ref: z.ZodString;
|
|
139
|
+
sha: z.ZodString;
|
|
140
|
+
past: z.ZodLiteral<"skip">;
|
|
141
|
+
version: z.ZodNull;
|
|
142
|
+
}, z.core.$strict>], "past">>;
|
|
143
|
+
}, z.core.$strict>>;
|
|
144
|
+
}, z.core.$strict>>]>>;
|
|
93
145
|
visuals: z.ZodObject<{
|
|
94
146
|
themes: z.ZodEnum<{
|
|
95
147
|
both: "both";
|
|
@@ -146,8 +198,12 @@ export type NoteMeta = z.infer<typeof noteMetaSchema>;
|
|
|
146
198
|
export declare const releaseSchema: z.ZodObject<{
|
|
147
199
|
schemaVersion: z.ZodLiteral<1>;
|
|
148
200
|
version: z.ZodString;
|
|
149
|
-
|
|
150
|
-
|
|
201
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
202
|
+
releasedAt: z.ZodUnion<readonly [z.ZodISODate, z.ZodISODateTime]>;
|
|
203
|
+
previous: z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
204
|
+
channel: z.ZodString;
|
|
205
|
+
version: z.ZodString;
|
|
206
|
+
}, z.core.$strict>]>>;
|
|
151
207
|
status: z.ZodEnum<{
|
|
152
208
|
draft: "draft";
|
|
153
209
|
ready: "ready";
|
|
@@ -316,10 +372,16 @@ export declare const bundleSchema: z.ZodObject<{
|
|
|
316
372
|
schemaVersion: z.ZodLiteral<1>;
|
|
317
373
|
currentVersion: z.ZodString;
|
|
318
374
|
locale: z.ZodString;
|
|
375
|
+
viewChannel: z.ZodOptional<z.ZodString>;
|
|
376
|
+
currentChannel: z.ZodOptional<z.ZodString>;
|
|
319
377
|
releases: z.ZodArray<z.ZodObject<{
|
|
320
378
|
version: z.ZodString;
|
|
321
|
-
|
|
322
|
-
|
|
379
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
380
|
+
releasedAt: z.ZodUnion<readonly [z.ZodISODate, z.ZodISODateTime]>;
|
|
381
|
+
previous: z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
382
|
+
channel: z.ZodString;
|
|
383
|
+
version: z.ZodString;
|
|
384
|
+
}, z.core.$strict>]>>;
|
|
323
385
|
notes: z.ZodArray<z.ZodObject<{
|
|
324
386
|
id: z.ZodString;
|
|
325
387
|
category: z.ZodEnum<{
|
package/dist/model.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export const segment = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._+-]{0,95}$/);
|
|
3
|
+
export const channelName = z.string().regex(/^(?!(?:con|prn|aux|nul|com[1-9]|lpt[1-9])$)[a-z][a-z0-9-]{0,62}$/);
|
|
4
|
+
export const channelRefSchema = z.strictObject({ channel: channelName, version: segment });
|
|
5
|
+
export const releasedAtSchema = z.union([z.iso.date(), z.iso.datetime({ offset: true }).regex(/T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/)]);
|
|
3
6
|
export const sha = z.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/);
|
|
4
7
|
export const locale = z.string().regex(/^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/);
|
|
5
8
|
export const theme = z.enum(['dark', 'light']);
|
|
@@ -27,10 +30,25 @@ export const historyStartSchema = z.discriminatedUnion('past', [
|
|
|
27
30
|
z.strictObject({ ref: z.string().min(1), sha, past: z.literal('history'), version: segment }),
|
|
28
31
|
z.strictObject({ ref: z.string().min(1), sha, past: z.literal('skip'), version: z.null() }),
|
|
29
32
|
]);
|
|
33
|
+
const historySettings = z.strictObject({ start: historyStartSchema.optional() });
|
|
34
|
+
export const channelsSchema = z.record(channelName, z.strictObject({
|
|
35
|
+
include: z.array(channelName).min(1), history: historySettings.optional(),
|
|
36
|
+
})).superRefine((channels, ctx) => {
|
|
37
|
+
if (!Object.keys(channels).length)
|
|
38
|
+
ctx.addIssue({ code: 'custom', message: 'Use channels: false to disable channels.' });
|
|
39
|
+
for (const [name, settings] of Object.entries(channels)) {
|
|
40
|
+
if (new Set(settings.include).size !== settings.include.length)
|
|
41
|
+
ctx.addIssue({ code: 'custom', path: [name, 'include'], message: 'Included channels must be unique.' });
|
|
42
|
+
for (const included of settings.include)
|
|
43
|
+
if (!Object.hasOwn(channels, included))
|
|
44
|
+
ctx.addIssue({ code: 'custom', path: [name, 'include'], message: `Unknown included channel: ${included}` });
|
|
45
|
+
}
|
|
46
|
+
});
|
|
30
47
|
export const configSchema = z.strictObject({
|
|
31
48
|
schemaVersion: z.literal(1), product: z.string().min(1),
|
|
32
49
|
sourceLocale: locale, locales: z.array(locale).min(1),
|
|
33
|
-
history:
|
|
50
|
+
history: historySettings.optional(),
|
|
51
|
+
channels: z.union([z.literal(false), channelsSchema]).optional(),
|
|
34
52
|
visuals: visualPolicySchema,
|
|
35
53
|
tools: z.array(z.enum(['codex', 'claude', 'cursor'])),
|
|
36
54
|
});
|
|
@@ -43,12 +61,16 @@ export const noteMetaSchema = z.strictObject({
|
|
|
43
61
|
commits: z.array(sha), paths: z.array(z.string()), image: z.boolean(),
|
|
44
62
|
});
|
|
45
63
|
export const releaseSchema = z.strictObject({
|
|
46
|
-
schemaVersion: z.literal(1), version: segment,
|
|
47
|
-
previous: segment.nullable(), status: z.enum(['draft', 'ready']),
|
|
64
|
+
schemaVersion: z.literal(1), version: segment, channel: channelName.optional(), releasedAt: releasedAtSchema,
|
|
65
|
+
previous: z.union([segment, channelRefSchema]).nullable(), status: z.enum(['draft', 'ready']),
|
|
48
66
|
source: sourceSchema, initialContent: z.enum(['summary', 'history']).optional(),
|
|
49
67
|
sourceLocale: locale, locales: z.array(locale).min(1),
|
|
50
68
|
visuals: visualPolicySchema, notes: z.array(noteMetaSchema),
|
|
51
69
|
emptyReason: z.string().nullable(), contentHash: z.string().nullable(),
|
|
70
|
+
}).superRefine((release, ctx) => {
|
|
71
|
+
if (release.previous !== null && (release.channel === undefined ? typeof release.previous !== 'string' : typeof release.previous === 'string')) {
|
|
72
|
+
ctx.addIssue({ code: 'custom', path: ['previous'], message: 'Channel releases require a channel/version predecessor; unchanneled releases require a version string.' });
|
|
73
|
+
}
|
|
52
74
|
});
|
|
53
75
|
export const noteTextSchema = z.strictObject({
|
|
54
76
|
title: z.string().min(1), alt: z.string(), sourceHash: z.string().nullable(),
|
|
@@ -80,8 +102,9 @@ const exportedImage = z.strictObject({
|
|
|
80
102
|
});
|
|
81
103
|
export const bundleSchema = z.strictObject({
|
|
82
104
|
schemaVersion: z.literal(1), currentVersion: segment, locale,
|
|
105
|
+
viewChannel: channelName.optional(), currentChannel: channelName.optional(),
|
|
83
106
|
releases: z.array(z.strictObject({
|
|
84
|
-
version: segment,
|
|
107
|
+
version: segment, channel: channelName.optional(), releasedAt: releasedAtSchema, previous: z.union([segment, channelRefSchema]).nullable(),
|
|
85
108
|
notes: z.array(z.strictObject({
|
|
86
109
|
id: segment, category: noteMetaSchema.shape.category, title: z.string(), bodyMarkdown: z.string(),
|
|
87
110
|
image: z.strictObject({
|
|
@@ -119,7 +142,7 @@ export function activeVariants(visual, policy) {
|
|
|
119
142
|
export function defaultConfig(product) {
|
|
120
143
|
return {
|
|
121
144
|
schemaVersion: 1, product, sourceLocale: 'en-US', locales: ['en-US'],
|
|
122
|
-
|
|
145
|
+
tools: ['codex', 'claude', 'cursor'],
|
|
123
146
|
visuals: {
|
|
124
147
|
themes: 'both', preset: 'quiet-product', width: 1280, height: 800, accent: '#4678ED',
|
|
125
148
|
dark: { canvas: '#242527', surface: '#18191B', raised: '#343638', primary: '#B9BBBE', secondary: '#777B80', divider: '#46494D' },
|
package/dist/move.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Project } from './project.js';
|
|
2
|
+
import { type ReleaseRef } from './model.js';
|
|
3
|
+
export interface MoveOptions {
|
|
4
|
+
fromChannel?: string;
|
|
5
|
+
toChannel?: string;
|
|
6
|
+
toUnchanneled?: boolean;
|
|
7
|
+
after?: string;
|
|
8
|
+
atStart?: boolean;
|
|
9
|
+
dryRun?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function moveReleases(project: Project, versions: string[], options: MoveOptions): Promise<{
|
|
12
|
+
dryRun: boolean;
|
|
13
|
+
moved: {
|
|
14
|
+
from: ReleaseRef;
|
|
15
|
+
to: ReleaseRef;
|
|
16
|
+
status: "draft" | "ready";
|
|
17
|
+
}[];
|
|
18
|
+
updatedReleases: ReleaseRef[];
|
|
19
|
+
updatedFiles: string[];
|
|
20
|
+
paths: {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
}[];
|
|
24
|
+
}>;
|