@celilo/cli 0.3.19 → 0.3.20
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
CHANGED
|
@@ -28,7 +28,16 @@ import { log } from '../prompts';
|
|
|
28
28
|
import type { CommandResult } from '../types';
|
|
29
29
|
|
|
30
30
|
type UpgradeOutcome =
|
|
31
|
-
| {
|
|
31
|
+
| {
|
|
32
|
+
status: 'success';
|
|
33
|
+
moduleId: string;
|
|
34
|
+
/** Version that was on disk before the upgrade (manifest.yml semver). */
|
|
35
|
+
previousVersion: string;
|
|
36
|
+
/** Version that's now installed. Includes +N revision when known
|
|
37
|
+
* (registry-driven upgrades pass the canonical "1.0.0+5" form;
|
|
38
|
+
* path-driven upgrades fall back to the manifest semver). */
|
|
39
|
+
newVersion: string;
|
|
40
|
+
}
|
|
32
41
|
| { status: 'failed'; moduleId: string; error: string }
|
|
33
42
|
// `skipped` means the path expanded from a glob but isn't an
|
|
34
43
|
// upgradable target — either no manifest at all (probably a non-
|
|
@@ -37,6 +46,18 @@ type UpgradeOutcome =
|
|
|
37
46
|
// `celilo module update modules/*` does what users expect.
|
|
38
47
|
| { status: 'skipped'; moduleId: string; reason: string };
|
|
39
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Tunables for `upgradeOne`. Quiet mode silences the per-call log
|
|
51
|
+
* lines so callers driving a batch (the registry sweep) can render
|
|
52
|
+
* their own structured output without duplicates. `displayVersion`
|
|
53
|
+
* lets the registry caller carry the canonical `+N` revision through
|
|
54
|
+
* to both the DB column and the success log.
|
|
55
|
+
*/
|
|
56
|
+
interface UpgradeOpts {
|
|
57
|
+
quiet?: boolean;
|
|
58
|
+
displayVersion?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
40
61
|
/**
|
|
41
62
|
* Parse a celilo version string into [major, minor, patch, revision].
|
|
42
63
|
* Celilo's published versions look like `1.0.0+3` — semver core plus a
|
|
@@ -108,7 +129,18 @@ async function fetchAndUpgrade(
|
|
|
108
129
|
try {
|
|
109
130
|
// Registry packages are pre-verified at publish time; skip the
|
|
110
131
|
// signature check here to match `module import`'s registry path.
|
|
111
|
-
|
|
132
|
+
// `quiet: true` suppresses upgradeOne's per-call log lines so the
|
|
133
|
+
// sweep can render its own structured per-module output without
|
|
134
|
+
// duplicates. `displayVersion: version` carries the registry's
|
|
135
|
+
// canonical "X.Y.Z+N" through to both the DB column and the success
|
|
136
|
+
// log line — without it, output would say "v1.0.0 → v1.0.0" because
|
|
137
|
+
// the manifest semver doesn't include the +N revision.
|
|
138
|
+
return await upgradeOne(
|
|
139
|
+
tmpPath,
|
|
140
|
+
db,
|
|
141
|
+
{ ...flags, 'skip-verify': true },
|
|
142
|
+
{ quiet: true, displayVersion: version },
|
|
143
|
+
);
|
|
112
144
|
} finally {
|
|
113
145
|
try {
|
|
114
146
|
await unlink(tmpPath);
|
|
@@ -123,6 +155,7 @@ async function upgradeOne(
|
|
|
123
155
|
sourcePath: string,
|
|
124
156
|
db: ReturnType<typeof getDb>,
|
|
125
157
|
flags: Record<string, string | boolean> = {},
|
|
158
|
+
opts: UpgradeOpts = {},
|
|
126
159
|
): Promise<UpgradeOutcome> {
|
|
127
160
|
const originalCwd = process.env.CELILO_ORIGINAL_CWD || process.cwd();
|
|
128
161
|
const importPath = resolve(originalCwd, sourcePath);
|
|
@@ -162,7 +195,7 @@ async function upgradeOne(
|
|
|
162
195
|
error: verifyResult.error || 'Package verification failed',
|
|
163
196
|
};
|
|
164
197
|
}
|
|
165
|
-
} else {
|
|
198
|
+
} else if (!opts.quiet) {
|
|
166
199
|
log.warn('Skipping package signature verification (--skip-verify)');
|
|
167
200
|
}
|
|
168
201
|
}
|
|
@@ -207,8 +240,17 @@ async function upgradeOne(
|
|
|
207
240
|
};
|
|
208
241
|
}
|
|
209
242
|
|
|
210
|
-
|
|
211
|
-
|
|
243
|
+
// Old version comes from the DB so we capture whatever was last
|
|
244
|
+
// recorded (which IS the registry-versioned form, e.g. "1.0.0+5",
|
|
245
|
+
// for registry-driven installs/upgrades).
|
|
246
|
+
const previousVersion = module.version;
|
|
247
|
+
// New version: prefer the caller-supplied display version (registry's
|
|
248
|
+
// canonical "X.Y.Z+N"), fall back to the manifest semver core when
|
|
249
|
+
// upgrading from a local path.
|
|
250
|
+
const newVersion = opts.displayVersion ?? newManifest.version;
|
|
251
|
+
if (!opts.quiet) {
|
|
252
|
+
log.info(`Upgrading ${moduleId}: ${previousVersion} → ${newVersion}`);
|
|
253
|
+
}
|
|
212
254
|
|
|
213
255
|
// Copy new module files, preserving generated output and state
|
|
214
256
|
const installedPath = module.sourcePath;
|
|
@@ -226,11 +268,13 @@ async function upgradeOne(
|
|
|
226
268
|
// Clean up temp dir if we extracted a .netapp
|
|
227
269
|
if (tempDir) await cleanupTempDir(tempDir);
|
|
228
270
|
|
|
229
|
-
// Update manifest in database
|
|
271
|
+
// Update manifest in database. We persist the display version (with
|
|
272
|
+
// +N when known) so subsequent `module list` / `module update` calls
|
|
273
|
+
// see the same version string the registry reported.
|
|
230
274
|
db.update(modules)
|
|
231
275
|
.set({
|
|
232
276
|
manifestData: newManifest as unknown as Record<string, unknown>,
|
|
233
|
-
version:
|
|
277
|
+
version: newVersion,
|
|
234
278
|
name: newManifest.name,
|
|
235
279
|
})
|
|
236
280
|
.where(eq(modules.id, moduleId))
|
|
@@ -241,13 +285,18 @@ async function upgradeOne(
|
|
|
241
285
|
|
|
242
286
|
if (newManifest.provides?.capabilities && newManifest.provides.capabilities.length > 0) {
|
|
243
287
|
const regResult = await registerModuleCapabilities(moduleId, newManifest, db.$client);
|
|
244
|
-
if (!regResult.success) {
|
|
288
|
+
if (!regResult.success && !opts.quiet) {
|
|
289
|
+
// Capability re-registration warnings are useful when upgrading
|
|
290
|
+
// from a path (operator iterating on dev module); for the
|
|
291
|
+
// registry sweep, the caller will surface them itself if needed.
|
|
245
292
|
log.warn(` ${moduleId}: capability re-registration warning: ${regResult.error}`);
|
|
246
293
|
}
|
|
247
294
|
}
|
|
248
295
|
|
|
249
|
-
|
|
250
|
-
|
|
296
|
+
if (!opts.quiet) {
|
|
297
|
+
log.success(`Upgraded ${moduleId} (${previousVersion} → ${newVersion})`);
|
|
298
|
+
}
|
|
299
|
+
return { status: 'success', moduleId, previousVersion, newVersion };
|
|
251
300
|
}
|
|
252
301
|
|
|
253
302
|
/**
|
|
@@ -411,17 +460,18 @@ async function runRegistrySweep(
|
|
|
411
460
|
|
|
412
461
|
if (nonBreaking.length > 0) {
|
|
413
462
|
log.info(`Auto-applying ${nonBreaking.length} non-breaking update(s):`);
|
|
414
|
-
for (const plan of nonBreaking) {
|
|
415
|
-
console.log(
|
|
416
|
-
` ↑ ${plan.moduleId.padEnd(30)} ${plan.installedVersion} → ${plan.targetVersion} (${plan.classification})`,
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
463
|
for (const plan of nonBreaking) {
|
|
420
464
|
const result = await fetchAndUpgrade(client, plan.moduleId, plan.targetVersion, db, flags);
|
|
421
465
|
if (result.status === 'failed') {
|
|
422
466
|
failed.push({ moduleId: plan.moduleId, error: result.error });
|
|
467
|
+
console.log(
|
|
468
|
+
` ✗ ${plan.moduleId.padEnd(30)} ${plan.installedVersion} → ${plan.targetVersion} (${plan.classification}, FAILED)`,
|
|
469
|
+
);
|
|
423
470
|
} else if (result.status === 'success') {
|
|
424
471
|
appliedNonBreaking++;
|
|
472
|
+
console.log(
|
|
473
|
+
` ✓ ${plan.moduleId.padEnd(30)} ${result.previousVersion} → ${result.newVersion} (${plan.classification})`,
|
|
474
|
+
);
|
|
425
475
|
}
|
|
426
476
|
// status === 'skipped' shouldn't happen for registry-fetched packages
|
|
427
477
|
// (we know the module is installed; the package definitely has a
|
|
@@ -453,8 +503,14 @@ async function runRegistrySweep(
|
|
|
453
503
|
const result = await fetchAndUpgrade(client, plan.moduleId, plan.targetVersion, db, flags);
|
|
454
504
|
if (result.status === 'failed') {
|
|
455
505
|
failed.push({ moduleId: plan.moduleId, error: result.error });
|
|
506
|
+
console.log(
|
|
507
|
+
` ✗ ${plan.moduleId.padEnd(30)} ${plan.installedVersion} → ${plan.targetVersion} (major, FAILED)`,
|
|
508
|
+
);
|
|
456
509
|
} else if (result.status === 'success') {
|
|
457
510
|
appliedBreaking++;
|
|
511
|
+
console.log(
|
|
512
|
+
` ✓ ${plan.moduleId.padEnd(30)} ${result.previousVersion} → ${result.newVersion} (major)`,
|
|
513
|
+
);
|
|
458
514
|
}
|
|
459
515
|
}
|
|
460
516
|
}
|
|
@@ -29,6 +29,9 @@ export interface ValidationResult {
|
|
|
29
29
|
options?: Array<{ value: string; label: string; hint?: string }>;
|
|
30
30
|
per_selection?: { key_pattern: string; prompt: string; type?: string; derive_from?: string };
|
|
31
31
|
generate?: { method: string; length: number; encoding: string };
|
|
32
|
+
/** For `type: string-map` only — labels shown in the add-loop prompt. */
|
|
33
|
+
key_label?: string;
|
|
34
|
+
value_label?: string;
|
|
32
35
|
}>;
|
|
33
36
|
}
|
|
34
37
|
|
|
@@ -383,6 +386,9 @@ async function findMissingRequiredVariables(
|
|
|
383
386
|
type?: string;
|
|
384
387
|
options?: Array<{ value: string; label: string; hint?: string }>;
|
|
385
388
|
per_selection?: { key_pattern: string; prompt: string; type?: string; derive_from?: string };
|
|
389
|
+
generate?: { method: string; length: number; encoding: string };
|
|
390
|
+
key_label?: string;
|
|
391
|
+
value_label?: string;
|
|
386
392
|
}>
|
|
387
393
|
> {
|
|
388
394
|
const missing: Array<{
|
|
@@ -394,6 +400,8 @@ async function findMissingRequiredVariables(
|
|
|
394
400
|
options?: Array<{ value: string; label: string; hint?: string }>;
|
|
395
401
|
per_selection?: { key_pattern: string; prompt: string; type?: string; derive_from?: string };
|
|
396
402
|
generate?: { method: string; length: number; encoding: string };
|
|
403
|
+
key_label?: string;
|
|
404
|
+
value_label?: string;
|
|
397
405
|
}> = [];
|
|
398
406
|
|
|
399
407
|
// Check declared variables (user config, capability, system, infrastructure)
|
|
@@ -460,6 +468,12 @@ async function findMissingRequiredVariables(
|
|
|
460
468
|
source: 'secret',
|
|
461
469
|
description: secret.description,
|
|
462
470
|
generate: secret.generate,
|
|
471
|
+
// Pass through manifest-declared type + add-loop labels so the
|
|
472
|
+
// bus payload can drive the right responder UX (e.g. string-map
|
|
473
|
+
// gets the per-key add-loop instead of the JSON-blob prompt).
|
|
474
|
+
type: secret.type,
|
|
475
|
+
key_label: secret.key_label,
|
|
476
|
+
value_label: secret.value_label,
|
|
463
477
|
});
|
|
464
478
|
}
|
|
465
479
|
}
|