@donkeylabs/cli 2.0.17 → 2.0.19
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/package.json +1 -1
- package/src/commands/docs.ts +35 -15
- package/src/commands/init-enhanced.ts +2 -0
- package/src/commands/init.ts +10 -10
- package/src/commands/update.ts +360 -0
- package/src/index.ts +16 -1
package/package.json
CHANGED
package/src/commands/docs.ts
CHANGED
|
@@ -23,35 +23,30 @@ interface DocsCommandOptions {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Find the
|
|
26
|
+
* Find the server package directory from installed @donkeylabs/server
|
|
27
27
|
*/
|
|
28
|
-
function
|
|
29
|
-
// Try common locations
|
|
28
|
+
function findServerPkgDir(): string | null {
|
|
30
29
|
const possiblePaths = [
|
|
31
|
-
|
|
32
|
-
join(process.cwd(), "node_modules", "
|
|
33
|
-
|
|
34
|
-
join(process.cwd(), "
|
|
35
|
-
// Workspace/monorepo
|
|
36
|
-
join(process.cwd(), "..", "server", "docs"),
|
|
37
|
-
join(process.cwd(), "..", "..", "packages", "server", "docs"),
|
|
30
|
+
join(process.cwd(), "node_modules", "@donkeylabs", "server"),
|
|
31
|
+
join(process.cwd(), "node_modules", ".bun", "@donkeylabs", "server"),
|
|
32
|
+
join(process.cwd(), "..", "server"),
|
|
33
|
+
join(process.cwd(), "..", "..", "packages", "server"),
|
|
38
34
|
];
|
|
39
35
|
|
|
40
36
|
for (const path of possiblePaths) {
|
|
41
|
-
|
|
37
|
+
const docsDir = join(path, "docs");
|
|
38
|
+
if (existsSync(docsDir) && statSync(docsDir).isDirectory()) {
|
|
42
39
|
return path;
|
|
43
40
|
}
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
// Try to resolve from require
|
|
47
43
|
try {
|
|
48
44
|
const serverPkgPath = require.resolve("@donkeylabs/server/package.json", {
|
|
49
45
|
paths: [process.cwd()],
|
|
50
46
|
});
|
|
51
47
|
const serverDir = dirname(serverPkgPath);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return docsPath;
|
|
48
|
+
if (existsSync(join(serverDir, "docs"))) {
|
|
49
|
+
return serverDir;
|
|
55
50
|
}
|
|
56
51
|
} catch {
|
|
57
52
|
// Package not found
|
|
@@ -60,6 +55,30 @@ function findDocsPath(): string | null {
|
|
|
60
55
|
return null;
|
|
61
56
|
}
|
|
62
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Find the docs directory from installed @donkeylabs/server
|
|
60
|
+
*/
|
|
61
|
+
function findDocsPath(): string | null {
|
|
62
|
+
const serverDir = findServerPkgDir();
|
|
63
|
+
if (!serverDir) return null;
|
|
64
|
+
return join(serverDir, "docs");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Sync agents.md from the server package root to the project root
|
|
69
|
+
*/
|
|
70
|
+
function syncAgentsMd(): void {
|
|
71
|
+
const serverDir = findServerPkgDir();
|
|
72
|
+
if (!serverDir) return;
|
|
73
|
+
|
|
74
|
+
const agentsMdSrc = join(serverDir, "agents.md");
|
|
75
|
+
if (!existsSync(agentsMdSrc)) return;
|
|
76
|
+
|
|
77
|
+
const content = readFileSync(agentsMdSrc, "utf-8");
|
|
78
|
+
writeFileSync(join(process.cwd(), "agents.md"), content);
|
|
79
|
+
console.log(pc.green("✓ Synced agents.md"));
|
|
80
|
+
}
|
|
81
|
+
|
|
63
82
|
/**
|
|
64
83
|
* Get list of available doc files
|
|
65
84
|
*/
|
|
@@ -201,6 +220,7 @@ export async function docsCommand(args: string[], options: DocsCommandOptions =
|
|
|
201
220
|
console.log(pc.dim(`Target: ${outputDir}/\n`));
|
|
202
221
|
|
|
203
222
|
const synced = syncAllDocs(docsPath, outputDir);
|
|
223
|
+
syncAgentsMd();
|
|
204
224
|
|
|
205
225
|
console.log(pc.green(`\n✓ Synced ${synced} documentation files to ${outputDir}/`));
|
|
206
226
|
console.log(pc.dim(`\nTip: Add ${outputDir}/ to your .gitignore if you don't want to commit docs.`));
|
|
@@ -374,6 +374,7 @@ function createPackageJson(projectDir: string, options: InitOptions) {
|
|
|
374
374
|
"prepare": "bun --bun svelte-kit sync && bun run gen:types || echo ''",
|
|
375
375
|
"check": "bun --bun svelte-kit sync && bun --bun svelte-check --tsconfig ./tsconfig.json",
|
|
376
376
|
"gen:types": "donkeylabs generate",
|
|
377
|
+
"update": "donkeylabs update",
|
|
377
378
|
"cli": "donkeylabs",
|
|
378
379
|
"test": "bun test",
|
|
379
380
|
...(options.deployment === "docker" && {
|
|
@@ -386,6 +387,7 @@ function createPackageJson(projectDir: string, options: InitOptions) {
|
|
|
386
387
|
"build": "bun build src/server/index.ts --outdir=dist",
|
|
387
388
|
"start": "bun run dist/index.js",
|
|
388
389
|
"gen:types": "bunx donkeylabs generate",
|
|
390
|
+
"update": "bunx donkeylabs update",
|
|
389
391
|
"test": "bun test",
|
|
390
392
|
"lint": "bun --bun tsc --noEmit",
|
|
391
393
|
...(options.deployment === "docker" && {
|
package/src/commands/init.ts
CHANGED
|
@@ -167,7 +167,7 @@ export async function initCommand(args: string[]) {
|
|
|
167
167
|
} else {
|
|
168
168
|
console.log(pc.green("\n✓ Dependencies installed\n"));
|
|
169
169
|
|
|
170
|
-
// Copy
|
|
170
|
+
// Copy agents.md and docs/ from @donkeylabs/server to project root
|
|
171
171
|
await copyDocsFromServer(targetDir);
|
|
172
172
|
}
|
|
173
173
|
|
|
@@ -324,7 +324,7 @@ async function copyDirectory(src: string, dest: string): Promise<void> {
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
/**
|
|
327
|
-
* Copy
|
|
327
|
+
* Copy agents.md and docs/ from @donkeylabs/server to project root
|
|
328
328
|
* for AI-assisted development
|
|
329
329
|
*/
|
|
330
330
|
async function copyDocsFromServer(targetDir: string): Promise<void> {
|
|
@@ -334,19 +334,19 @@ async function copyDocsFromServer(targetDir: string): Promise<void> {
|
|
|
334
334
|
return; // Server package not installed
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
// Copy
|
|
338
|
-
const
|
|
339
|
-
if (existsSync(
|
|
340
|
-
const
|
|
341
|
-
await copyFile(
|
|
342
|
-
console.log(pc.green(" Created:"), "
|
|
337
|
+
// Copy agents.md
|
|
338
|
+
const agentsMdSrc = join(serverPkgPath, "agents.md");
|
|
339
|
+
if (existsSync(agentsMdSrc)) {
|
|
340
|
+
const agentsMdDest = join(targetDir, "agents.md");
|
|
341
|
+
await copyFile(agentsMdSrc, agentsMdDest);
|
|
342
|
+
console.log(pc.green(" Created:"), "agents.md (AI instructions)");
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
// Copy docs/ directory
|
|
346
346
|
const docsSrc = join(serverPkgPath, "docs");
|
|
347
347
|
if (existsSync(docsSrc)) {
|
|
348
|
-
const docsDest = join(targetDir, "docs");
|
|
348
|
+
const docsDest = join(targetDir, "docs", "donkeylabs");
|
|
349
349
|
await copyDirectory(docsSrc, docsDest);
|
|
350
|
-
console.log(pc.green(" Created:"), "docs/ (detailed documentation)");
|
|
350
|
+
console.log(pc.green(" Created:"), "docs/donkeylabs/ (detailed documentation)");
|
|
351
351
|
}
|
|
352
352
|
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update Command
|
|
3
|
+
*
|
|
4
|
+
* Check for and install updates to @donkeylabs packages.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* donkeylabs update # Interactive update selection
|
|
8
|
+
* donkeylabs update --all # Update all packages
|
|
9
|
+
* donkeylabs update --check # Check for updates only (no install)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, readFileSync, writeFileSync, rmSync } from "fs";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { execSync } from "child_process";
|
|
15
|
+
import pc from "picocolors";
|
|
16
|
+
|
|
17
|
+
const DONKEYLABS_PACKAGES = [
|
|
18
|
+
"@donkeylabs/server",
|
|
19
|
+
"@donkeylabs/adapter-sveltekit",
|
|
20
|
+
"@donkeylabs/cli",
|
|
21
|
+
"@donkeylabs/mcp",
|
|
22
|
+
"@donkeylabs/adapter-serverless",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
interface PackageInfo {
|
|
26
|
+
name: string;
|
|
27
|
+
currentVersion: string | null;
|
|
28
|
+
latestVersion: string | null;
|
|
29
|
+
hasUpdate: boolean;
|
|
30
|
+
isDev: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface UpdateOptions {
|
|
34
|
+
all?: boolean;
|
|
35
|
+
check?: boolean;
|
|
36
|
+
skipDocs?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get installed version from package.json
|
|
41
|
+
*/
|
|
42
|
+
function getInstalledPackages(packageJsonPath: string): Map<string, { version: string; isDev: boolean }> {
|
|
43
|
+
const installed = new Map<string, { version: string; isDev: boolean }>();
|
|
44
|
+
|
|
45
|
+
if (!existsSync(packageJsonPath)) {
|
|
46
|
+
return installed;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
50
|
+
|
|
51
|
+
// Check dependencies
|
|
52
|
+
if (pkg.dependencies) {
|
|
53
|
+
for (const [name, version] of Object.entries(pkg.dependencies)) {
|
|
54
|
+
if (DONKEYLABS_PACKAGES.includes(name)) {
|
|
55
|
+
installed.set(name, { version: String(version), isDev: false });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check devDependencies
|
|
61
|
+
if (pkg.devDependencies) {
|
|
62
|
+
for (const [name, version] of Object.entries(pkg.devDependencies)) {
|
|
63
|
+
if (DONKEYLABS_PACKAGES.includes(name)) {
|
|
64
|
+
installed.set(name, { version: String(version), isDev: true });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return installed;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get latest version from npm registry
|
|
74
|
+
*/
|
|
75
|
+
async function getLatestVersion(packageName: string): Promise<string | null> {
|
|
76
|
+
try {
|
|
77
|
+
const result = execSync(`npm view ${packageName} version 2>/dev/null`, {
|
|
78
|
+
encoding: "utf-8",
|
|
79
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
80
|
+
});
|
|
81
|
+
return result.trim();
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Parse version string (handles workspace:*, ^, ~, etc.)
|
|
89
|
+
*/
|
|
90
|
+
function parseVersion(version: string): string {
|
|
91
|
+
if (version.startsWith("workspace:")) {
|
|
92
|
+
return "workspace";
|
|
93
|
+
}
|
|
94
|
+
// Remove ^, ~, >=, etc.
|
|
95
|
+
return version.replace(/^[\^~>=<]+/, "");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Compare versions (simple semver comparison)
|
|
100
|
+
*/
|
|
101
|
+
function isNewerVersion(current: string, latest: string): boolean {
|
|
102
|
+
if (current === "workspace") return false;
|
|
103
|
+
|
|
104
|
+
const currentParts = current.split(".").map(Number);
|
|
105
|
+
const latestParts = latest.split(".").map(Number);
|
|
106
|
+
|
|
107
|
+
for (let i = 0; i < 3; i++) {
|
|
108
|
+
const c = currentParts[i] || 0;
|
|
109
|
+
const l = latestParts[i] || 0;
|
|
110
|
+
if (l > c) return true;
|
|
111
|
+
if (l < c) return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check for updates
|
|
119
|
+
*/
|
|
120
|
+
async function checkForUpdates(packageJsonPath: string): Promise<PackageInfo[]> {
|
|
121
|
+
const installed = getInstalledPackages(packageJsonPath);
|
|
122
|
+
const packages: PackageInfo[] = [];
|
|
123
|
+
|
|
124
|
+
console.log(pc.dim("\nChecking for updates...\n"));
|
|
125
|
+
|
|
126
|
+
for (const name of DONKEYLABS_PACKAGES) {
|
|
127
|
+
const info = installed.get(name);
|
|
128
|
+
|
|
129
|
+
if (!info) {
|
|
130
|
+
continue; // Not installed
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const currentVersion = parseVersion(info.version);
|
|
134
|
+
const latestVersion = await getLatestVersion(name);
|
|
135
|
+
|
|
136
|
+
const hasUpdate = latestVersion
|
|
137
|
+
? isNewerVersion(currentVersion, latestVersion)
|
|
138
|
+
: false;
|
|
139
|
+
|
|
140
|
+
packages.push({
|
|
141
|
+
name,
|
|
142
|
+
currentVersion,
|
|
143
|
+
latestVersion,
|
|
144
|
+
hasUpdate,
|
|
145
|
+
isDev: info.isDev,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return packages;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Display update status
|
|
154
|
+
*/
|
|
155
|
+
function displayUpdateStatus(packages: PackageInfo[]): void {
|
|
156
|
+
const hasUpdates = packages.some((p) => p.hasUpdate);
|
|
157
|
+
|
|
158
|
+
console.log(pc.bold("Package Status\n"));
|
|
159
|
+
|
|
160
|
+
for (const pkg of packages) {
|
|
161
|
+
const statusIcon = pkg.hasUpdate
|
|
162
|
+
? pc.yellow("⬆")
|
|
163
|
+
: pc.green("✓");
|
|
164
|
+
|
|
165
|
+
const versionInfo = pkg.hasUpdate
|
|
166
|
+
? `${pc.dim(pkg.currentVersion)} → ${pc.green(pkg.latestVersion)}`
|
|
167
|
+
: pc.dim(pkg.currentVersion || "unknown");
|
|
168
|
+
|
|
169
|
+
const devBadge = pkg.isDev ? pc.dim(" (dev)") : "";
|
|
170
|
+
|
|
171
|
+
console.log(` ${statusIcon} ${pkg.name}${devBadge}`);
|
|
172
|
+
console.log(` ${versionInfo}\n`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!hasUpdates) {
|
|
176
|
+
console.log(pc.green("All packages are up to date!"));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Interactive package selection using simple prompt
|
|
182
|
+
*/
|
|
183
|
+
async function selectPackagesToUpdate(packages: PackageInfo[]): Promise<PackageInfo[]> {
|
|
184
|
+
const updatable = packages.filter((p) => p.hasUpdate);
|
|
185
|
+
|
|
186
|
+
if (updatable.length === 0) {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log(pc.bold("\nSelect packages to update:\n"));
|
|
191
|
+
|
|
192
|
+
// Display options
|
|
193
|
+
console.log(` ${pc.cyan("0)")} Update all packages`);
|
|
194
|
+
updatable.forEach((pkg, i) => {
|
|
195
|
+
console.log(
|
|
196
|
+
` ${pc.cyan(`${i + 1})`)} ${pkg.name} ${pc.dim(`${pkg.currentVersion} → ${pkg.latestVersion}`)}`
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
console.log(` ${pc.cyan("s)")} Skip update\n`);
|
|
200
|
+
|
|
201
|
+
// Read input
|
|
202
|
+
process.stdout.write(pc.bold("Enter selection (0-" + updatable.length + ", or s): "));
|
|
203
|
+
|
|
204
|
+
const input = await new Promise<string>((resolve) => {
|
|
205
|
+
let data = "";
|
|
206
|
+
process.stdin.setEncoding("utf8");
|
|
207
|
+
process.stdin.once("data", (chunk) => {
|
|
208
|
+
data = chunk.toString().trim();
|
|
209
|
+
resolve(data);
|
|
210
|
+
});
|
|
211
|
+
process.stdin.resume();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
process.stdin.pause();
|
|
215
|
+
|
|
216
|
+
if (input.toLowerCase() === "s") {
|
|
217
|
+
return [];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (input === "0") {
|
|
221
|
+
return updatable;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const index = parseInt(input, 10);
|
|
225
|
+
if (index >= 1 && index <= updatable.length) {
|
|
226
|
+
return [updatable[index - 1]];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
console.log(pc.yellow("\nInvalid selection, skipping update."));
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Update package.json with new versions
|
|
235
|
+
*/
|
|
236
|
+
function updatePackageJson(
|
|
237
|
+
packageJsonPath: string,
|
|
238
|
+
packagesToUpdate: PackageInfo[]
|
|
239
|
+
): void {
|
|
240
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
241
|
+
|
|
242
|
+
for (const pkgInfo of packagesToUpdate) {
|
|
243
|
+
const versionString = `^${pkgInfo.latestVersion}`;
|
|
244
|
+
|
|
245
|
+
if (pkgInfo.isDev && pkg.devDependencies?.[pkgInfo.name]) {
|
|
246
|
+
pkg.devDependencies[pkgInfo.name] = versionString;
|
|
247
|
+
} else if (pkg.dependencies?.[pkgInfo.name]) {
|
|
248
|
+
pkg.dependencies[pkgInfo.name] = versionString;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Run bun install
|
|
257
|
+
*/
|
|
258
|
+
function runInstall(): void {
|
|
259
|
+
console.log(pc.dim("\nRemoving node_modules..."));
|
|
260
|
+
const nodeModulesPath = join(process.cwd(), "node_modules");
|
|
261
|
+
if (existsSync(nodeModulesPath)) {
|
|
262
|
+
rmSync(nodeModulesPath, { recursive: true, force: true });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Also remove bun.lock for clean install
|
|
266
|
+
const bunLockPath = join(process.cwd(), "bun.lock");
|
|
267
|
+
if (existsSync(bunLockPath)) {
|
|
268
|
+
rmSync(bunLockPath);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.log(pc.dim("Running bun install...\n"));
|
|
272
|
+
execSync("bun install", { stdio: "inherit" });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Sync documentation
|
|
277
|
+
*/
|
|
278
|
+
async function syncDocs(): Promise<void> {
|
|
279
|
+
console.log(pc.dim("\nSyncing documentation..."));
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
const { docsCommand } = await import("./docs");
|
|
283
|
+
await docsCommand([], {});
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.log(pc.yellow("Could not sync docs (this is optional)"));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export async function updateCommand(
|
|
290
|
+
args: string[],
|
|
291
|
+
options: UpdateOptions = {}
|
|
292
|
+
): Promise<void> {
|
|
293
|
+
const packageJsonPath = join(process.cwd(), "package.json");
|
|
294
|
+
|
|
295
|
+
if (!existsSync(packageJsonPath)) {
|
|
296
|
+
console.error(pc.red("Error: No package.json found in current directory."));
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Check for updates
|
|
301
|
+
const packages = await checkForUpdates(packageJsonPath);
|
|
302
|
+
|
|
303
|
+
if (packages.length === 0) {
|
|
304
|
+
console.log(pc.yellow("No @donkeylabs packages found in this project."));
|
|
305
|
+
console.log(pc.dim("\nInstall with: bun add @donkeylabs/server"));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Display status
|
|
310
|
+
displayUpdateStatus(packages);
|
|
311
|
+
|
|
312
|
+
// Check-only mode
|
|
313
|
+
if (options.check || args.includes("--check") || args.includes("-c")) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const updatable = packages.filter((p) => p.hasUpdate);
|
|
318
|
+
|
|
319
|
+
if (updatable.length === 0) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Select packages to update
|
|
324
|
+
let packagesToUpdate: PackageInfo[];
|
|
325
|
+
|
|
326
|
+
if (options.all || args.includes("--all") || args.includes("-a")) {
|
|
327
|
+
packagesToUpdate = updatable;
|
|
328
|
+
} else {
|
|
329
|
+
packagesToUpdate = await selectPackagesToUpdate(packages);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (packagesToUpdate.length === 0) {
|
|
333
|
+
console.log(pc.dim("\nNo packages selected for update."));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Confirm
|
|
338
|
+
console.log(pc.bold("\nUpdating packages:"));
|
|
339
|
+
for (const pkg of packagesToUpdate) {
|
|
340
|
+
console.log(` • ${pkg.name} → ${pc.green(pkg.latestVersion)}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Update package.json
|
|
344
|
+
console.log(pc.dim("\nUpdating package.json..."));
|
|
345
|
+
updatePackageJson(packageJsonPath, packagesToUpdate);
|
|
346
|
+
|
|
347
|
+
// Run install
|
|
348
|
+
runInstall();
|
|
349
|
+
|
|
350
|
+
// Sync docs
|
|
351
|
+
if (!options.skipDocs && !args.includes("--skip-docs")) {
|
|
352
|
+
await syncDocs();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
console.log(pc.green("\n✓ Update complete!"));
|
|
356
|
+
console.log(pc.dim("\nUpdated packages:"));
|
|
357
|
+
for (const pkg of packagesToUpdate) {
|
|
358
|
+
console.log(` ${pc.green("•")} ${pkg.name}@${pkg.latestVersion}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,9 @@ const { positionals, values } = parseArgs({
|
|
|
20
20
|
local: { type: "boolean", short: "l" },
|
|
21
21
|
list: { type: "boolean" },
|
|
22
22
|
output: { type: "string", short: "o" },
|
|
23
|
+
all: { type: "boolean", short: "a" },
|
|
24
|
+
check: { type: "boolean", short: "c" },
|
|
25
|
+
"skip-docs": { type: "boolean" },
|
|
23
26
|
},
|
|
24
27
|
allowPositionals: true,
|
|
25
28
|
});
|
|
@@ -39,6 +42,7 @@ ${pc.bold("Commands:")}
|
|
|
39
42
|
${pc.cyan("add")} Add optional plugins (images, auth, etc.)
|
|
40
43
|
${pc.cyan("generate")} Generate types (registry, context, client)
|
|
41
44
|
${pc.cyan("plugin")} Plugin management
|
|
45
|
+
${pc.cyan("update")} Check and install package updates
|
|
42
46
|
${pc.cyan("docs")} Sync documentation from installed package
|
|
43
47
|
${pc.cyan("deploy")} <platform> Deploy (vercel, cloudflare, aws, vps)
|
|
44
48
|
${pc.cyan("deploy history")} Show deployment history
|
|
@@ -60,9 +64,11 @@ ${pc.bold("Options:")}
|
|
|
60
64
|
donkeylabs init --type sveltekit # SvelteKit + adapter project
|
|
61
65
|
donkeylabs generate
|
|
62
66
|
donkeylabs plugin create myPlugin
|
|
67
|
+
donkeylabs update # Interactive package update
|
|
68
|
+
donkeylabs update --check # Check for updates only
|
|
69
|
+
donkeylabs update --all # Update all packages
|
|
63
70
|
donkeylabs docs # Sync all docs to ./docs/donkeylabs/
|
|
64
71
|
donkeylabs docs --list # List available docs
|
|
65
|
-
donkeylabs docs workflows # Sync specific doc
|
|
66
72
|
donkeylabs deploy vercel # Deploy to Vercel
|
|
67
73
|
donkeylabs config # Interactive configuration
|
|
68
74
|
donkeylabs config set DATABASE_URL postgresql://...
|
|
@@ -124,6 +130,15 @@ async function main() {
|
|
|
124
130
|
await docsCommand(positionals.slice(1), { list: values.list, output: values.output });
|
|
125
131
|
break;
|
|
126
132
|
|
|
133
|
+
case "update":
|
|
134
|
+
const { updateCommand } = await import("./commands/update");
|
|
135
|
+
await updateCommand(positionals.slice(1), {
|
|
136
|
+
all: values.all,
|
|
137
|
+
check: values.check,
|
|
138
|
+
skipDocs: values["skip-docs"],
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
|
|
127
142
|
case "deploy":
|
|
128
143
|
const subcommand = positionals[1];
|
|
129
144
|
if (subcommand === "history") {
|