veodl 1.12.0 → 2.0.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.
- package/CHANGELOG.md +27 -0
- package/README.md +183 -100
- package/bin/veo.js +47 -2
- package/docs/AGENT_GUIDE.md +1 -0
- package/native/android-arm64/veo +0 -0
- package/native/darwin-arm64/veo +0 -0
- package/native/darwin-x64/veo +0 -0
- package/native/linux-arm64/veo +0 -0
- package/native/linux-x64/veo +0 -0
- package/native/win32-arm64/veo.exe +0 -0
- package/native/win32-x64/veo.exe +0 -0
- package/package.json +53 -61
- package/src/alias.js +0 -258
- package/src/backend-update.js +0 -191
- package/src/backend.js +0 -548
- package/src/changes.js +0 -278
- package/src/cli.js +0 -781
- package/src/compatibility.js +0 -39
- package/src/config-clipboard.js +0 -67
- package/src/config-diagnostics.js +0 -155
- package/src/config-editor.js +0 -404
- package/src/config-errors.js +0 -64
- package/src/config-reset.js +0 -39
- package/src/config-template.js +0 -227
- package/src/config.js +0 -307
- package/src/disk-space.js +0 -68
- package/src/doctor.js +0 -302
- package/src/download-cache.js +0 -31
- package/src/downloader.js +0 -669
- package/src/execution.js +0 -68
- package/src/experimental-fragments.js +0 -29
- package/src/flush.js +0 -66
- package/src/history.js +0 -173
- package/src/inline-region.js +0 -72
- package/src/inspect-media.js +0 -179
- package/src/interactive.js +0 -120
- package/src/jobs.js +0 -218
- package/src/legacy-config-comments.js +0 -106
- package/src/naming.js +0 -54
- package/src/open-file.js +0 -15
- package/src/option-suggestions.js +0 -43
- package/src/output.js +0 -81
- package/src/path-links.js +0 -53
- package/src/paths.js +0 -26
- package/src/playlist.js +0 -31
- package/src/progress.js +0 -341
- package/src/run-archive.js +0 -148
- package/src/runs.js +0 -346
- package/src/source-discovery.js +0 -303
- package/src/state.js +0 -27
- package/src/stats.js +0 -63
- package/src/terminal-size.js +0 -8
- package/src/terminal-title.js +0 -19
- package/src/tool-setup.js +0 -151
- package/src/uninstall.js +0 -222
- package/src/updater.js +0 -229
- package/src/utils.js +0 -208
- package/src/version.js +0 -38
package/src/changes.js
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import { commandOutput } from './output.js';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { terminalColumns } from './terminal-size.js';
|
|
4
|
-
import { wrap } from './progress.js';
|
|
5
|
-
import { compareVersions } from './version.js';
|
|
6
|
-
import { packageVersion } from './updater.js';
|
|
7
|
-
import { suggestOption } from './option-suggestions.js';
|
|
8
|
-
import { cleanText } from './utils.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* `veo changes` reads the CHANGELOG.md that ships inside this package, so the
|
|
12
|
-
* notes always belong to the installed code and work without network access. The
|
|
13
|
-
* file is parsed into data instead of being printed: sections, bullets, nested
|
|
14
|
-
* bullets and wrapped lines survive, and `--json` returns the same structure.
|
|
15
|
-
*/
|
|
16
|
-
const RELEASE = /^##\s+v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.]+)?)(?:\s+[-–—]\s+(\d{4}-\d{2}-\d{2}))?\s*$/;
|
|
17
|
-
const SECTION = /^###\s+(.+?)\s*$/;
|
|
18
|
-
const BULLET = /^(\s*)-\s+(.*)$/;
|
|
19
|
-
const VERSION = /^\d+(\.\d+)*$/;
|
|
20
|
-
const MARKER = '(installed)';
|
|
21
|
-
const SHOWN = 5;
|
|
22
|
-
const USAGE = 'Usage: veo changes [<version>] [--json] [--latest] [--since <version>] [--to <version>] [--range <from>..<to>]';
|
|
23
|
-
|
|
24
|
-
export const CHANGES_HELP = `veo changes [<version>] [--json] [--latest] [--since <version>]
|
|
25
|
-
[--to <version>] [--range <from>..<to>]
|
|
26
|
-
|
|
27
|
-
List every released version, newest first, and mark the installed one. With a version
|
|
28
|
-
(or --version) show that release's notes; a partial version such as 1.10 selects the
|
|
29
|
-
newest match. --since shows everything newer than a version, --to and --range set both
|
|
30
|
-
ends of a range, and --latest shows only the newest release. Notes come from the
|
|
31
|
-
CHANGELOG.md shipped with this veo version, so the command needs no network access and
|
|
32
|
-
prints no automatic update hint. Use --json for scripting.
|
|
33
|
-
`;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Keep a Changelog style document becomes releases, newest first. A heading of
|
|
37
|
-
* second level that is not a version ends the notes, so an appended file list or
|
|
38
|
-
* a second document cannot leak into the last release.
|
|
39
|
-
*/
|
|
40
|
-
export function parseChangelog(markdown) {
|
|
41
|
-
const releases = [];
|
|
42
|
-
let release = null;
|
|
43
|
-
let section = null;
|
|
44
|
-
let item = null; // Current top-level bullet and parent of any nested ones.
|
|
45
|
-
let last = null; // Most recent bullet, which a wrapped line continues.
|
|
46
|
-
for (const raw of String(markdown).split(/\r?\n/)) {
|
|
47
|
-
const line = raw.replace(/\s+$/, '');
|
|
48
|
-
if (!line.trim()) { last = null; continue; }
|
|
49
|
-
const heading = RELEASE.exec(line);
|
|
50
|
-
if (heading) {
|
|
51
|
-
release = { version: heading[1], date: heading[2] || null, sections: [] };
|
|
52
|
-
releases.push(release);
|
|
53
|
-
section = null; item = null; last = null;
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
// A second-level heading that is not a version ends the notes; the document
|
|
57
|
-
// title above the first release is preamble and ignored.
|
|
58
|
-
if (/^##\s/.test(line)) break;
|
|
59
|
-
if (!release) continue;
|
|
60
|
-
const type = SECTION.exec(line);
|
|
61
|
-
if (type) {
|
|
62
|
-
section = { type: cleanText(type[1]), items: [] };
|
|
63
|
-
release.sections.push(section);
|
|
64
|
-
item = null; last = null;
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
if (!section) continue;
|
|
68
|
-
const bullet = BULLET.exec(line);
|
|
69
|
-
if (bullet) {
|
|
70
|
-
const text = cleanText(bullet[2]);
|
|
71
|
-
if (!text) continue;
|
|
72
|
-
if (!bullet[1].length || !item) {
|
|
73
|
-
item = { text, items: [] };
|
|
74
|
-
section.items.push(item);
|
|
75
|
-
last = item;
|
|
76
|
-
} else {
|
|
77
|
-
last = { text, items: [] };
|
|
78
|
-
item.items.push(last);
|
|
79
|
-
}
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
// Without a bullet the line continues the previous one; the changelog wraps prose.
|
|
83
|
-
if (last) last.text = cleanText(`${last.text} ${line.trim()}`);
|
|
84
|
-
}
|
|
85
|
-
return releases.sort((left, right) => compareVersions(right.version, left.version));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Entry counts per section type, in the order the changelog lists them. */
|
|
89
|
-
export function releaseCounts(release) {
|
|
90
|
-
return Object.fromEntries(release.sections.filter(section => section.items.length)
|
|
91
|
-
.map(section => [section.type, section.items.length]));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const summary = counts => Object.entries(counts).map(([type, count]) => `${type} ${count}`).join(', ');
|
|
95
|
-
|
|
96
|
-
/** Exact match first, then the newest release starting with the given prefix. */
|
|
97
|
-
export function resolveVersion(releases, requested, label = 'version') {
|
|
98
|
-
const wanted = String(requested ?? '').trim().replace(/^v/i, '');
|
|
99
|
-
if (!VERSION.test(wanted)) throw new Error(`${label} must be a version number such as 1.11.0.`);
|
|
100
|
-
const exact = releases.find(release => release.version === wanted);
|
|
101
|
-
if (exact) return exact;
|
|
102
|
-
const partial = releases.filter(release => release.version.startsWith(`${wanted}.`) || release.version.startsWith(`${wanted}-`));
|
|
103
|
-
if (partial.length) return partial.reduce((best, release) => compareVersions(release.version, best.version) > 0 ? release : best);
|
|
104
|
-
const known = releases.map(release => release.version);
|
|
105
|
-
if (!known.length) throw new Error(`${label} "${cleanText(requested)}" cannot be resolved: the changelog lists no releases.`);
|
|
106
|
-
const guess = suggestOption(wanted, known);
|
|
107
|
-
const list = known.slice(0, SHOWN).join(', ');
|
|
108
|
-
throw new Error(`Unknown ${label} "${cleanText(requested)}".${guess ? ` Did you mean "${guess}"?` : ''} Known versions: ${list}${known.length > SHOWN ? ', …' : ''}.`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** Which releases a request selects, and under which heading they are shown. */
|
|
112
|
-
export function selectReleases(releases, { version = null, latest = false, since = null, to = null } = {}) {
|
|
113
|
-
const sorted = [...releases].sort((left, right) => compareVersions(right.version, left.version));
|
|
114
|
-
const newest = sorted[0]?.version ?? null;
|
|
115
|
-
if (version) {
|
|
116
|
-
const release = resolveVersion(sorted, version);
|
|
117
|
-
return { mode: 'version', from: release.version, to: release.version, versions: [release] };
|
|
118
|
-
}
|
|
119
|
-
if (latest) return { mode: 'latest', from: newest, to: newest, versions: sorted.slice(0, 1) };
|
|
120
|
-
if (since || to) {
|
|
121
|
-
const from = since ? resolveVersion(sorted, since, '--since').version : null;
|
|
122
|
-
const upper = to ? resolveVersion(sorted, to, '--to').version : null;
|
|
123
|
-
if (from && upper && compareVersions(upper, from) < 0) throw new Error(`--to ${upper} is older than --since ${from}.`);
|
|
124
|
-
const versions = sorted.filter(release => (!from || compareVersions(release.version, from) > 0)
|
|
125
|
-
&& (!upper || compareVersions(release.version, upper) <= 0));
|
|
126
|
-
if (!versions.length) {
|
|
127
|
-
if (from && !upper) throw new Error(`This veo is already at ${from}; no newer changes are listed.`);
|
|
128
|
-
throw new Error(`No changes listed between ${from ?? 'the first release'} and ${upper ?? newest}.`);
|
|
129
|
-
}
|
|
130
|
-
return { mode: 'range', from, to: upper ?? newest, versions };
|
|
131
|
-
}
|
|
132
|
-
return { mode: 'list', from: null, to: null, versions: sorted };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/** The shipped changelog, or a clear error when an installation lost the file. */
|
|
136
|
-
export async function readChangelog(file = new URL('../CHANGELOG.md', import.meta.url)) {
|
|
137
|
-
let markdown;
|
|
138
|
-
try {
|
|
139
|
-
markdown = await readFile(file, 'utf8');
|
|
140
|
-
} catch (error) {
|
|
141
|
-
if (error.code === 'ENOENT' || error.code === 'EISDIR') throw new Error(`No CHANGELOG.md found at ${file}.`);
|
|
142
|
-
throw error;
|
|
143
|
-
}
|
|
144
|
-
return parseChangelog(markdown);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function bulletLines(entry, stream, depth) {
|
|
148
|
-
const prefix = `${' '.repeat(depth)}- `;
|
|
149
|
-
const hanging = ' '.repeat(prefix.length);
|
|
150
|
-
// Notes are wrapped instead of shortened: a release note that loses its tail
|
|
151
|
-
// because the terminal is narrow would be worse than useless.
|
|
152
|
-
const columns = stream?.isTTY ? Math.max(24, terminalColumns(stream) - prefix.length - 1) : Infinity;
|
|
153
|
-
return wrap(entry.text, columns).split('\n').map((line, index) => (index ? hanging : prefix) + line);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function releaseLines(release, stream, installed, header) {
|
|
157
|
-
const lines = [];
|
|
158
|
-
if (header) lines.push(release.version + (installed ? ` ${MARKER}` : ''));
|
|
159
|
-
for (const section of release.sections) {
|
|
160
|
-
if (!section.items.length) continue;
|
|
161
|
-
lines.push(section.type);
|
|
162
|
-
for (const entry of section.items) {
|
|
163
|
-
lines.push(...bulletLines(entry, stream, 1));
|
|
164
|
-
for (const nested of entry.items) lines.push(...bulletLines(nested, stream, 2));
|
|
165
|
-
}
|
|
166
|
-
lines.push('');
|
|
167
|
-
}
|
|
168
|
-
if (lines.at(-1) === '') lines.pop();
|
|
169
|
-
return lines;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const plural = count => `${count} version${count === 1 ? '' : 's'}`;
|
|
173
|
-
|
|
174
|
-
export function formatChanges(selection, { current, stream } = {}) {
|
|
175
|
-
const { mode, versions } = selection;
|
|
176
|
-
if (!versions.length) return 'veo changes\n\nNo release notes found in CHANGELOG.md.\n';
|
|
177
|
-
if (mode === 'list') {
|
|
178
|
-
const width = Math.max(...versions.map(release => release.version.length));
|
|
179
|
-
const lines = [`veo changes (${plural(versions.length)}, newest first)`, ''];
|
|
180
|
-
for (const release of versions) {
|
|
181
|
-
const installed = release.version === current ? MARKER : '';
|
|
182
|
-
const row = ` ${release.version.padEnd(width)} ${installed.padEnd(MARKER.length)}`;
|
|
183
|
-
const counts = summary(releaseCounts(release));
|
|
184
|
-
// A release without entries must not leave trailing spaces in the column.
|
|
185
|
-
lines.push(counts ? `${row} ${counts}` : row);
|
|
186
|
-
}
|
|
187
|
-
lines.push('');
|
|
188
|
-
lines.push('Use veo changes <version> for one version, veo changes --since <version> for');
|
|
189
|
-
lines.push('everything newer than a given version, or --json for scripting.');
|
|
190
|
-
return `${lines.join('\n')}\n`;
|
|
191
|
-
}
|
|
192
|
-
const title = mode === 'range'
|
|
193
|
-
? `veo changes ${selection.from ? `${selection.from} to ${selection.to}` : `up to ${selection.to}`} (${plural(versions.length)}, newest first)`
|
|
194
|
-
: `veo changes ${selection.from}`;
|
|
195
|
-
const lines = [title, ''];
|
|
196
|
-
for (const release of versions) {
|
|
197
|
-
lines.push(...releaseLines(release, stream, release.version === current, mode === 'range'));
|
|
198
|
-
lines.push('');
|
|
199
|
-
}
|
|
200
|
-
lines.pop();
|
|
201
|
-
return `${lines.join('\n')}\n`;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const sectionsJson = release => release.sections.filter(section => section.items.length)
|
|
205
|
-
.map(section => ({ type: section.type, items: section.items }));
|
|
206
|
-
|
|
207
|
-
function changesJson(selection, current) {
|
|
208
|
-
if (selection.mode === 'list') {
|
|
209
|
-
return {
|
|
210
|
-
current,
|
|
211
|
-
count: selection.versions.length,
|
|
212
|
-
versions: selection.versions.map(release => {
|
|
213
|
-
const counts = releaseCounts(release);
|
|
214
|
-
return { version: release.version, date: release.date, installed: release.version === current, counts, summary: summary(counts) };
|
|
215
|
-
}),
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
if (selection.mode === 'range') {
|
|
219
|
-
return {
|
|
220
|
-
current,
|
|
221
|
-
from: selection.from,
|
|
222
|
-
to: selection.to,
|
|
223
|
-
count: selection.versions.length,
|
|
224
|
-
versions: selection.versions.map(release => ({
|
|
225
|
-
version: release.version, date: release.date, installed: release.version === current, sections: sectionsJson(release),
|
|
226
|
-
})),
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
const [release] = selection.versions;
|
|
230
|
-
return { current, version: release.version, date: release.date, installed: release.version === current, sections: sectionsJson(release) };
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function versionValue(value, flag) {
|
|
234
|
-
if (!value || value.startsWith('-')) throw new Error(`${flag} requires a version number such as 1.11.0.`);
|
|
235
|
-
return value;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export function parseChangesArgs(args) {
|
|
239
|
-
const options = { json: false, latest: false, version: null, since: null, to: null };
|
|
240
|
-
for (let index = 0; index < args.length; index++) {
|
|
241
|
-
let arg = args[index];
|
|
242
|
-
let inline = null;
|
|
243
|
-
const equals = arg.indexOf('=');
|
|
244
|
-
if (arg.startsWith('--') && equals > 2) { inline = arg.slice(equals + 1); arg = arg.slice(0, equals); }
|
|
245
|
-
const value = () => versionValue(inline ?? args[++index], arg);
|
|
246
|
-
if (arg === '--json') options.json = true;
|
|
247
|
-
else if (arg === '--latest') options.latest = true;
|
|
248
|
-
else if (arg === '--version') options.version = value();
|
|
249
|
-
else if (arg === '--since') options.since = value();
|
|
250
|
-
else if (arg === '--to') options.to = value();
|
|
251
|
-
else if (arg === '--range') {
|
|
252
|
-
const [from, to] = value().split('..');
|
|
253
|
-
if (!from || !to) throw new Error(`--range must look like 1.9.0..1.11.0. ${USAGE}`);
|
|
254
|
-
options.since ??= from;
|
|
255
|
-
options.to ??= to;
|
|
256
|
-
} else if (arg.startsWith('-')) throw new Error(`Unknown option "${arg}". ${USAGE}`);
|
|
257
|
-
else if (!options.version) options.version = arg;
|
|
258
|
-
else throw new Error(USAGE);
|
|
259
|
-
}
|
|
260
|
-
const ranged = options.since || options.to;
|
|
261
|
-
if (options.version && (ranged || options.latest)) throw new Error(`Use either a version or --latest/--since/--to, not both. ${USAGE}`);
|
|
262
|
-
if (options.latest && ranged) throw new Error(`Use --latest on its own. ${USAGE}`);
|
|
263
|
-
return options;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export async function changesMain(args = [], { stdout = process.stdout, current = null, file } = {}) {
|
|
267
|
-
[args, stdout] = commandOutput(args, stdout);
|
|
268
|
-
if (args.some(arg => ['--help', '-h'].includes(arg))) {
|
|
269
|
-
stdout.write(CHANGES_HELP);
|
|
270
|
-
return 0;
|
|
271
|
-
}
|
|
272
|
-
const options = parseChangesArgs(args);
|
|
273
|
-
const installed = current ?? await packageVersion();
|
|
274
|
-
const selection = selectReleases(await readChangelog(file), options);
|
|
275
|
-
if (options.json) stdout.write(`${JSON.stringify(changesJson(selection, installed))}\n`);
|
|
276
|
-
else stdout.write(formatChanges(selection, { current: installed, stream: stdout }));
|
|
277
|
-
return 0;
|
|
278
|
-
}
|