@penvhq/launcher 0.9.5 → 0.11.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/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
- import { PenvError, ManifestEngine } from '@penvhq/core';
1
+ import { Environment, PenvError, ManifestEngine, PackageKind, Manifest } from '@penvhq/core';
2
+ import { InstallRuntime } from '@penvhq/cli/install';
2
3
 
3
4
  /**
4
5
  * Every byte penv downloads comes through here.
@@ -156,50 +157,6 @@ interface WriteDeclarationOptions extends DeclarationSubject {
156
157
  /** Writes the declaration and answers with the path a message prints. */
157
158
  declare function writeDeclaration(options: WriteDeclarationOptions): string;
158
159
 
159
- /**
160
- * `$PENV_HOME` — the one directory the launcher owns.
161
- *
162
- * Engines and extensions are addressed by exact name and exact version, so a
163
- * machine holds every version any of its projects pins at once and no project's
164
- * command is ever answered by another project's bytes.
165
- */
166
- /** A read-only view of the process environment. */
167
- type Environment = Readonly<Record<string, string | undefined>>;
168
- /** The variable that moves the store off `~/.penv`. */
169
- declare const PENV_HOME_VAR = "PENV_HOME";
170
- /** The two things the store holds, and the directory each lives under. */
171
- type PackageKind = "engines" | "extensions";
172
- /** How the launcher was installed, recorded by the installer that did it. */
173
- declare const HOME_META_FILE = "meta.json";
174
- /** Written beside an installed package: the SSRI of the tarball it came from. */
175
- declare const INTEGRITY_FILE = ".penv-integrity";
176
- /** The update command for a launcher whose installer recorded nothing. */
177
- declare const NPM_UPDATE_COMMAND = "npm install -g @penvhq/launcher";
178
- /** The store, from the environment. `~/.penv` unless `$PENV_HOME` says otherwise. */
179
- declare function penvHome(env: Environment): string;
180
- /**
181
- * Where one exact version lives.
182
- *
183
- * The manifest's grammar already refuses a name or a version that could climb
184
- * out of the store, so the containment check is the second lock rather than the
185
- * first: this function is also reached from `penv add`, where the name is
186
- * whatever the user typed.
187
- *
188
- * Containment is measured against the bucket, not against `$PENV_HOME`. A name
189
- * of `../extensions/x` stays inside the store while landing an engine among the
190
- * extensions, and a store where the two are not separated is a store where the
191
- * kind a caller asked for is not the kind it gets.
192
- */
193
- declare function packageDir(home: string, kind: PackageKind, name: string, version: string): string;
194
- /**
195
- * The command that updates this launcher.
196
- *
197
- * Advisory, so it never throws: a store with no `meta.json`, or one holding
198
- * something unreadable, falls back to the npm form rather than turning a
199
- * manifest-format refusal into a second failure about a metadata file.
200
- */
201
- declare function launcherUpdateCommand(home: string): string;
202
-
203
160
  /**
204
161
  * Handing the command over.
205
162
  *
@@ -269,6 +226,10 @@ declare function bundledEngine(): Engine;
269
226
 
270
227
  /** The command that materializes everything the manifest pins. */
271
228
  declare const INSTALL_COMMAND = "penv install";
229
+ /** The command that moves the engine pin, with no version: whatever `latest` points at. */
230
+ declare const UPGRADE_COMMAND = "penv upgrade";
231
+ /** The flag that answers `upgrade`'s one question ahead of time. */
232
+ declare const YES_FLAG = "--yes";
272
233
  /** How long a package outside the official scope must have existed. */
273
234
  declare const MIN_PACKAGE_AGE_DAYS = 7;
274
235
  /** The flag that overrides {@link MIN_PACKAGE_AGE_DAYS}, and only that. */
@@ -330,6 +291,23 @@ declare class AddLocalFlagError extends PenvError {
330
291
  readonly name = "AddLocalFlagError";
331
292
  constructor(subject: string);
332
293
  }
294
+ /**
295
+ * The extension resolved and is not something penv can import.
296
+ *
297
+ * `add` used to certify resolution and stop there, so a package whose `exports`
298
+ * pointed at TypeScript source got three green checks and failed much later,
299
+ * from an unrelated command. The load check runs here, at the one moment the
300
+ * operator is looking at the provider.
301
+ */
302
+ declare class ExtensionNotImportableError extends PenvError {
303
+ readonly name = "ExtensionNotImportableError";
304
+ constructor(name: string, entry: string | undefined, local: boolean);
305
+ }
306
+ /** The extension imported and threw. Its own failure is the diagnosis. */
307
+ declare class ExtensionUnloadableError extends PenvError {
308
+ readonly name = "ExtensionUnloadableError";
309
+ constructor(name: string, entry: string, detail: string, local: boolean);
310
+ }
333
311
  /** `--local` on a package the project does not have. */
334
312
  declare class LocalExtensionUnresolvedError extends PenvError {
335
313
  readonly name = "LocalExtensionUnresolvedError";
@@ -350,10 +328,16 @@ declare class OfficialRegistryError extends PenvError {
350
328
  readonly name = "OfficialRegistryError";
351
329
  constructor(name: string, registry: string);
352
330
  }
353
- /** The registry could not be read at all. */
331
+ /**
332
+ * The registry could not be read at all.
333
+ *
334
+ * `retry` is the command that would repeat this resolution. Two commands read a
335
+ * release — `add` and `upgrade` — and a refusal that named the wrong one would
336
+ * send the reader to a command that answers a different question.
337
+ */
354
338
  declare class RegistryUnreadableError extends PenvError {
355
339
  readonly name = "RegistryUnreadableError";
356
- constructor(name: string, url: string, detail: string);
340
+ constructor(name: string, url: string, detail: string, retry?: string);
357
341
  }
358
342
  /** The registry has no such package. */
359
343
  declare class PackageUnknownError extends PenvError {
@@ -363,7 +347,7 @@ declare class PackageUnknownError extends PenvError {
363
347
  /** The package exists; the version asked for does not. */
364
348
  declare class VersionUnknownError extends PenvError {
365
349
  readonly name = "VersionUnknownError";
366
- constructor(name: string, version: string, url: string);
350
+ constructor(name: string, version: string, url: string, retry?: string);
367
351
  }
368
352
  /** The registry answered, but without a fact the manifest has to record. */
369
353
  declare class ReleaseIncompleteError extends PenvError {
@@ -428,12 +412,77 @@ declare class EnginePinMismatchError extends PenvError {
428
412
  readonly name = "EnginePinMismatchError";
429
413
  constructor(pinned: string, ran: string);
430
414
  }
415
+ /** `penv upgrade` with something other than one optional version. */
416
+ declare class UpgradeSubjectError extends PenvError {
417
+ readonly name = "UpgradeSubjectError";
418
+ constructor();
419
+ }
420
+ /** A flag `penv upgrade` does not have. */
421
+ declare class UpgradeFlagError extends PenvError {
422
+ readonly name = "UpgradeFlagError";
423
+ constructor(flag: string);
424
+ }
425
+ /** `penv upgrade` needs the registry, and `--no-download` says this run has no network. */
426
+ declare class UpgradeNoDownloadError extends PenvError {
427
+ readonly name = "UpgradeNoDownloadError";
428
+ constructor();
429
+ }
430
+ /**
431
+ * `penv upgrade` on a machine with nobody at it.
432
+ *
433
+ * Unattended, penv will move the pin only to a version somebody named and only
434
+ * with the flag that says they meant it: what upgrade rewrites is two committed
435
+ * files, and a pipeline that picks the engine is a pipeline choosing which bytes
436
+ * the project runs.
437
+ */
438
+ declare class UpgradeUnattendedError extends PenvError {
439
+ readonly name = "UpgradeUnattendedError";
440
+ constructor();
441
+ }
442
+ /** The upgrade was shown and declined. Neither committed file was touched. */
443
+ declare class UpgradeDeclinedError extends PenvError {
444
+ readonly name = "UpgradeDeclinedError";
445
+ constructor(version: string);
446
+ }
447
+ /**
448
+ * The package manager refused, so the pin stayed where it was.
449
+ *
450
+ * The dependency moves before the manifest for exactly this reason: an upgrade
451
+ * that cannot finish leaves a project pinning the engine it was already running.
452
+ */
453
+ declare class UpgradeInstallFailedError extends PenvError {
454
+ readonly name = "UpgradeInstallFailedError";
455
+ constructor(command: string);
456
+ }
431
457
  /** An installed directory with nothing runnable in it. */
432
458
  declare class EngineEntryError extends PenvError {
433
459
  readonly name = "EngineEntryError";
434
460
  constructor(name: string, version: string, dir: string);
435
461
  }
436
462
 
463
+ /**
464
+ * What the launcher alone knows about `$PENV_HOME`: how the installation that
465
+ * created it updates itself, and what it writes beside an installed package.
466
+ *
467
+ * The store's layout — where `$PENV_HOME` is and where one exact version lives —
468
+ * is `@penvhq/core`'s, because the engine reads the same directories the
469
+ * launcher fills.
470
+ */
471
+ /** How the launcher was installed, recorded by the installer that did it. */
472
+ declare const HOME_META_FILE = "meta.json";
473
+ /** Written beside an installed package: the SSRI of the tarball it came from. */
474
+ declare const INTEGRITY_FILE = ".penv-integrity";
475
+ /** The update command for a launcher whose installer recorded nothing. */
476
+ declare const NPM_UPDATE_COMMAND = "npm install -g @penvhq/launcher";
477
+ /**
478
+ * The command that updates this launcher.
479
+ *
480
+ * Advisory, so it never throws: a store with no `meta.json`, or one holding
481
+ * something unreadable, falls back to the npm form rather than turning a
482
+ * manifest-format refusal into a second failure about a metadata file.
483
+ */
484
+ declare function launcherUpdateCommand(home: string): string;
485
+
437
486
  /**
438
487
  * The one hash penv checks: npm's SSRI, over the tarball bytes.
439
488
  *
@@ -552,6 +601,8 @@ interface ReleaseQuery {
552
601
  readonly version?: string;
553
602
  /** Only when the package comes from somewhere other than npmjs. */
554
603
  readonly registry?: string;
604
+ /** The command that would repeat this resolution. Absent means `penv add <name>`. */
605
+ readonly retry?: string;
555
606
  readonly fetcher: Fetcher;
556
607
  }
557
608
  /** The packument's address, which an exact name can be built rather than searched. */
@@ -625,4 +676,51 @@ interface ArchiveSubject {
625
676
  /** Every regular file in an npm tarball, `package/` stripped. */
626
677
  declare function readTarball(gzipped: Uint8Array, subject: ArchiveSubject): TarEntry[];
627
678
 
628
- export { AddFlagError, AddLocalFlagError, AddLocalInCiError, AddNoDownloadError, AddNotInteractiveError, type AddOptions, AddPackageNameError, AddRegistryError, type AddResult, AddSubjectError, ArchiveError, type ArchiveSubject, BUNDLED_ENGINE_PIN, DEFAULT_REGISTRY, DEV_PIN_INTEGRITY, DEV_PIN_VERSION, DeclarationMissingError, DeclarationNotSelfContainedError, type DeclarationSubject, type Delegation, DownloadFailedError, DownloadIntegrityError, ENGINE_BIN, type Engine, EngineEntryError, EnginePinMismatchError, EnginePinUnreleasedError, type Environment, type ExtensionPackage, type Fetcher, HOME_META_FILE, INSTALL_COMMAND, INTEGRITY_FILE, InstallDeclinedError, type InstallOptions, type InstallState, type Installation, LOCAL_FLAG, type LauncherIo, type LauncherOptions, LocalExtensionUnresolvedError, MIN_PACKAGE_AGE_DAYS, NPM_UPDATE_COMMAND, NoProjectError, OfficialRegistryError, PENV_HOME_VAR, PackageCorruptError, type PackageKind, PackageMissingError, PackageTooYoungError, PackageUnknownError, type Pin, type Project, type ProviderEntry, RegistryUnreadableError, type Release, ReleaseIncompleteError, type ReleaseQuery, type Spawner, TRUST_YOUNG_FLAG, type TarEntry, TrustDeclinedError, TrustPublisherMissingError, TrustReasonMissingError, VersionUnknownError, add, assertReleasePin, bundledEngine, declarationPath, engineAt, fetchRelease, findAdoptedRoot, findProject, httpFetcher, inspectInstall, installPin, integrityOf, launcherUpdateCommand, nodeSpawner, packageDir, packumentUrl, penvHome, readExtensionPackage, readProviderEntries, readTarball, releaseEnginePin, renderDeclaration, runLauncher, setProviderType, tarballUrl, writeDeclaration };
679
+ /**
680
+ * `penv upgrade [version]` — the one command that moves the engine pin.
681
+ *
682
+ * It belongs to the launcher for the same reason `add` does: everything it
683
+ * writes is the launcher's. An engine cannot compute the npm integrity of its
684
+ * own tarball, and the pin is a promise about bytes, so the integrity comes from
685
+ * the registry's `dist.integrity` and from nowhere else — never hashed here, and
686
+ * never typed by a person. Before this command existed, moving the pin meant
687
+ * hand-editing a version *and* an 88-character hash into the one file whose
688
+ * whole purpose is that its bytes are verified, and a mistyped character came
689
+ * back as a supply-chain check failing closed.
690
+ *
691
+ * Two committed files move: the manifest's engine pin and the project's
692
+ * `@penvhq/penv` dependency, at the same exact version. They move together or
693
+ * not at all — one consent covers both, and the dependency lands first, so a
694
+ * package manager that refuses leaves a project still pinning the engine it was
695
+ * already running.
696
+ *
697
+ * Extensions are not touched. Each carries its own pin and its own trust
698
+ * decision, and re-pinning them because the engine moved would be penv choosing
699
+ * bytes nobody reviewed; `penv add <package>@<version>` moves one.
700
+ *
701
+ * A downgrade is an upgrade backwards and takes the same path — a pin is a pin,
702
+ * and a project that needs the engine it ran last week is not asking for
703
+ * something penv should argue with.
704
+ */
705
+
706
+ interface UpgradeOptions {
707
+ /** The tokens after `upgrade`. */
708
+ readonly argv: readonly string[];
709
+ /** The project root — the directory holding `.penv/`. */
710
+ readonly root: string;
711
+ readonly manifestFile: string;
712
+ /** The manifest as the launcher already parsed it. */
713
+ readonly manifest: Manifest;
714
+ readonly home: string;
715
+ readonly io: LauncherIo;
716
+ readonly fetcher: Fetcher;
717
+ /** The launcher's `--no-download`: this run reaches no registry at all. */
718
+ readonly noDownload?: boolean;
719
+ /** True on a CI runner, which may have a terminal and still have nobody at it. */
720
+ readonly ci?: boolean;
721
+ /** Injected in tests: how the project's dependency is installed. Never spawns there. */
722
+ readonly install?: InstallRuntime;
723
+ }
724
+ declare function upgrade(options: UpgradeOptions): Promise<void>;
725
+
726
+ export { AddFlagError, AddLocalFlagError, AddLocalInCiError, AddNoDownloadError, AddNotInteractiveError, type AddOptions, AddPackageNameError, AddRegistryError, type AddResult, AddSubjectError, ArchiveError, type ArchiveSubject, BUNDLED_ENGINE_PIN, DEFAULT_REGISTRY, DEV_PIN_INTEGRITY, DEV_PIN_VERSION, DeclarationMissingError, DeclarationNotSelfContainedError, type DeclarationSubject, type Delegation, DownloadFailedError, DownloadIntegrityError, ENGINE_BIN, type Engine, EngineEntryError, EnginePinMismatchError, EnginePinUnreleasedError, ExtensionNotImportableError, type ExtensionPackage, ExtensionUnloadableError, type Fetcher, HOME_META_FILE, INSTALL_COMMAND, INTEGRITY_FILE, InstallDeclinedError, type InstallOptions, type InstallState, type Installation, LOCAL_FLAG, type LauncherIo, type LauncherOptions, LocalExtensionUnresolvedError, MIN_PACKAGE_AGE_DAYS, NPM_UPDATE_COMMAND, NoProjectError, OfficialRegistryError, PackageCorruptError, PackageMissingError, PackageTooYoungError, PackageUnknownError, type Pin, type Project, type ProviderEntry, RegistryUnreadableError, type Release, ReleaseIncompleteError, type ReleaseQuery, type Spawner, TRUST_YOUNG_FLAG, type TarEntry, TrustDeclinedError, TrustPublisherMissingError, TrustReasonMissingError, UPGRADE_COMMAND, UpgradeDeclinedError, UpgradeFlagError, UpgradeInstallFailedError, UpgradeNoDownloadError, type UpgradeOptions, UpgradeSubjectError, UpgradeUnattendedError, VersionUnknownError, YES_FLAG, add, assertReleasePin, bundledEngine, declarationPath, engineAt, fetchRelease, findAdoptedRoot, findProject, httpFetcher, inspectInstall, installPin, integrityOf, launcherUpdateCommand, nodeSpawner, packumentUrl, readExtensionPackage, readProviderEntries, readTarball, releaseEnginePin, renderDeclaration, runLauncher, setProviderType, tarballUrl, upgrade, writeDeclaration };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { PenvError, ManifestEngine } from '@penvhq/core';
1
+ import { Environment, PenvError, ManifestEngine, PackageKind, Manifest } from '@penvhq/core';
2
+ import { InstallRuntime } from '@penvhq/cli/install';
2
3
 
3
4
  /**
4
5
  * Every byte penv downloads comes through here.
@@ -156,50 +157,6 @@ interface WriteDeclarationOptions extends DeclarationSubject {
156
157
  /** Writes the declaration and answers with the path a message prints. */
157
158
  declare function writeDeclaration(options: WriteDeclarationOptions): string;
158
159
 
159
- /**
160
- * `$PENV_HOME` — the one directory the launcher owns.
161
- *
162
- * Engines and extensions are addressed by exact name and exact version, so a
163
- * machine holds every version any of its projects pins at once and no project's
164
- * command is ever answered by another project's bytes.
165
- */
166
- /** A read-only view of the process environment. */
167
- type Environment = Readonly<Record<string, string | undefined>>;
168
- /** The variable that moves the store off `~/.penv`. */
169
- declare const PENV_HOME_VAR = "PENV_HOME";
170
- /** The two things the store holds, and the directory each lives under. */
171
- type PackageKind = "engines" | "extensions";
172
- /** How the launcher was installed, recorded by the installer that did it. */
173
- declare const HOME_META_FILE = "meta.json";
174
- /** Written beside an installed package: the SSRI of the tarball it came from. */
175
- declare const INTEGRITY_FILE = ".penv-integrity";
176
- /** The update command for a launcher whose installer recorded nothing. */
177
- declare const NPM_UPDATE_COMMAND = "npm install -g @penvhq/launcher";
178
- /** The store, from the environment. `~/.penv` unless `$PENV_HOME` says otherwise. */
179
- declare function penvHome(env: Environment): string;
180
- /**
181
- * Where one exact version lives.
182
- *
183
- * The manifest's grammar already refuses a name or a version that could climb
184
- * out of the store, so the containment check is the second lock rather than the
185
- * first: this function is also reached from `penv add`, where the name is
186
- * whatever the user typed.
187
- *
188
- * Containment is measured against the bucket, not against `$PENV_HOME`. A name
189
- * of `../extensions/x` stays inside the store while landing an engine among the
190
- * extensions, and a store where the two are not separated is a store where the
191
- * kind a caller asked for is not the kind it gets.
192
- */
193
- declare function packageDir(home: string, kind: PackageKind, name: string, version: string): string;
194
- /**
195
- * The command that updates this launcher.
196
- *
197
- * Advisory, so it never throws: a store with no `meta.json`, or one holding
198
- * something unreadable, falls back to the npm form rather than turning a
199
- * manifest-format refusal into a second failure about a metadata file.
200
- */
201
- declare function launcherUpdateCommand(home: string): string;
202
-
203
160
  /**
204
161
  * Handing the command over.
205
162
  *
@@ -269,6 +226,10 @@ declare function bundledEngine(): Engine;
269
226
 
270
227
  /** The command that materializes everything the manifest pins. */
271
228
  declare const INSTALL_COMMAND = "penv install";
229
+ /** The command that moves the engine pin, with no version: whatever `latest` points at. */
230
+ declare const UPGRADE_COMMAND = "penv upgrade";
231
+ /** The flag that answers `upgrade`'s one question ahead of time. */
232
+ declare const YES_FLAG = "--yes";
272
233
  /** How long a package outside the official scope must have existed. */
273
234
  declare const MIN_PACKAGE_AGE_DAYS = 7;
274
235
  /** The flag that overrides {@link MIN_PACKAGE_AGE_DAYS}, and only that. */
@@ -330,6 +291,23 @@ declare class AddLocalFlagError extends PenvError {
330
291
  readonly name = "AddLocalFlagError";
331
292
  constructor(subject: string);
332
293
  }
294
+ /**
295
+ * The extension resolved and is not something penv can import.
296
+ *
297
+ * `add` used to certify resolution and stop there, so a package whose `exports`
298
+ * pointed at TypeScript source got three green checks and failed much later,
299
+ * from an unrelated command. The load check runs here, at the one moment the
300
+ * operator is looking at the provider.
301
+ */
302
+ declare class ExtensionNotImportableError extends PenvError {
303
+ readonly name = "ExtensionNotImportableError";
304
+ constructor(name: string, entry: string | undefined, local: boolean);
305
+ }
306
+ /** The extension imported and threw. Its own failure is the diagnosis. */
307
+ declare class ExtensionUnloadableError extends PenvError {
308
+ readonly name = "ExtensionUnloadableError";
309
+ constructor(name: string, entry: string, detail: string, local: boolean);
310
+ }
333
311
  /** `--local` on a package the project does not have. */
334
312
  declare class LocalExtensionUnresolvedError extends PenvError {
335
313
  readonly name = "LocalExtensionUnresolvedError";
@@ -350,10 +328,16 @@ declare class OfficialRegistryError extends PenvError {
350
328
  readonly name = "OfficialRegistryError";
351
329
  constructor(name: string, registry: string);
352
330
  }
353
- /** The registry could not be read at all. */
331
+ /**
332
+ * The registry could not be read at all.
333
+ *
334
+ * `retry` is the command that would repeat this resolution. Two commands read a
335
+ * release — `add` and `upgrade` — and a refusal that named the wrong one would
336
+ * send the reader to a command that answers a different question.
337
+ */
354
338
  declare class RegistryUnreadableError extends PenvError {
355
339
  readonly name = "RegistryUnreadableError";
356
- constructor(name: string, url: string, detail: string);
340
+ constructor(name: string, url: string, detail: string, retry?: string);
357
341
  }
358
342
  /** The registry has no such package. */
359
343
  declare class PackageUnknownError extends PenvError {
@@ -363,7 +347,7 @@ declare class PackageUnknownError extends PenvError {
363
347
  /** The package exists; the version asked for does not. */
364
348
  declare class VersionUnknownError extends PenvError {
365
349
  readonly name = "VersionUnknownError";
366
- constructor(name: string, version: string, url: string);
350
+ constructor(name: string, version: string, url: string, retry?: string);
367
351
  }
368
352
  /** The registry answered, but without a fact the manifest has to record. */
369
353
  declare class ReleaseIncompleteError extends PenvError {
@@ -428,12 +412,77 @@ declare class EnginePinMismatchError extends PenvError {
428
412
  readonly name = "EnginePinMismatchError";
429
413
  constructor(pinned: string, ran: string);
430
414
  }
415
+ /** `penv upgrade` with something other than one optional version. */
416
+ declare class UpgradeSubjectError extends PenvError {
417
+ readonly name = "UpgradeSubjectError";
418
+ constructor();
419
+ }
420
+ /** A flag `penv upgrade` does not have. */
421
+ declare class UpgradeFlagError extends PenvError {
422
+ readonly name = "UpgradeFlagError";
423
+ constructor(flag: string);
424
+ }
425
+ /** `penv upgrade` needs the registry, and `--no-download` says this run has no network. */
426
+ declare class UpgradeNoDownloadError extends PenvError {
427
+ readonly name = "UpgradeNoDownloadError";
428
+ constructor();
429
+ }
430
+ /**
431
+ * `penv upgrade` on a machine with nobody at it.
432
+ *
433
+ * Unattended, penv will move the pin only to a version somebody named and only
434
+ * with the flag that says they meant it: what upgrade rewrites is two committed
435
+ * files, and a pipeline that picks the engine is a pipeline choosing which bytes
436
+ * the project runs.
437
+ */
438
+ declare class UpgradeUnattendedError extends PenvError {
439
+ readonly name = "UpgradeUnattendedError";
440
+ constructor();
441
+ }
442
+ /** The upgrade was shown and declined. Neither committed file was touched. */
443
+ declare class UpgradeDeclinedError extends PenvError {
444
+ readonly name = "UpgradeDeclinedError";
445
+ constructor(version: string);
446
+ }
447
+ /**
448
+ * The package manager refused, so the pin stayed where it was.
449
+ *
450
+ * The dependency moves before the manifest for exactly this reason: an upgrade
451
+ * that cannot finish leaves a project pinning the engine it was already running.
452
+ */
453
+ declare class UpgradeInstallFailedError extends PenvError {
454
+ readonly name = "UpgradeInstallFailedError";
455
+ constructor(command: string);
456
+ }
431
457
  /** An installed directory with nothing runnable in it. */
432
458
  declare class EngineEntryError extends PenvError {
433
459
  readonly name = "EngineEntryError";
434
460
  constructor(name: string, version: string, dir: string);
435
461
  }
436
462
 
463
+ /**
464
+ * What the launcher alone knows about `$PENV_HOME`: how the installation that
465
+ * created it updates itself, and what it writes beside an installed package.
466
+ *
467
+ * The store's layout — where `$PENV_HOME` is and where one exact version lives —
468
+ * is `@penvhq/core`'s, because the engine reads the same directories the
469
+ * launcher fills.
470
+ */
471
+ /** How the launcher was installed, recorded by the installer that did it. */
472
+ declare const HOME_META_FILE = "meta.json";
473
+ /** Written beside an installed package: the SSRI of the tarball it came from. */
474
+ declare const INTEGRITY_FILE = ".penv-integrity";
475
+ /** The update command for a launcher whose installer recorded nothing. */
476
+ declare const NPM_UPDATE_COMMAND = "npm install -g @penvhq/launcher";
477
+ /**
478
+ * The command that updates this launcher.
479
+ *
480
+ * Advisory, so it never throws: a store with no `meta.json`, or one holding
481
+ * something unreadable, falls back to the npm form rather than turning a
482
+ * manifest-format refusal into a second failure about a metadata file.
483
+ */
484
+ declare function launcherUpdateCommand(home: string): string;
485
+
437
486
  /**
438
487
  * The one hash penv checks: npm's SSRI, over the tarball bytes.
439
488
  *
@@ -552,6 +601,8 @@ interface ReleaseQuery {
552
601
  readonly version?: string;
553
602
  /** Only when the package comes from somewhere other than npmjs. */
554
603
  readonly registry?: string;
604
+ /** The command that would repeat this resolution. Absent means `penv add <name>`. */
605
+ readonly retry?: string;
555
606
  readonly fetcher: Fetcher;
556
607
  }
557
608
  /** The packument's address, which an exact name can be built rather than searched. */
@@ -625,4 +676,51 @@ interface ArchiveSubject {
625
676
  /** Every regular file in an npm tarball, `package/` stripped. */
626
677
  declare function readTarball(gzipped: Uint8Array, subject: ArchiveSubject): TarEntry[];
627
678
 
628
- export { AddFlagError, AddLocalFlagError, AddLocalInCiError, AddNoDownloadError, AddNotInteractiveError, type AddOptions, AddPackageNameError, AddRegistryError, type AddResult, AddSubjectError, ArchiveError, type ArchiveSubject, BUNDLED_ENGINE_PIN, DEFAULT_REGISTRY, DEV_PIN_INTEGRITY, DEV_PIN_VERSION, DeclarationMissingError, DeclarationNotSelfContainedError, type DeclarationSubject, type Delegation, DownloadFailedError, DownloadIntegrityError, ENGINE_BIN, type Engine, EngineEntryError, EnginePinMismatchError, EnginePinUnreleasedError, type Environment, type ExtensionPackage, type Fetcher, HOME_META_FILE, INSTALL_COMMAND, INTEGRITY_FILE, InstallDeclinedError, type InstallOptions, type InstallState, type Installation, LOCAL_FLAG, type LauncherIo, type LauncherOptions, LocalExtensionUnresolvedError, MIN_PACKAGE_AGE_DAYS, NPM_UPDATE_COMMAND, NoProjectError, OfficialRegistryError, PENV_HOME_VAR, PackageCorruptError, type PackageKind, PackageMissingError, PackageTooYoungError, PackageUnknownError, type Pin, type Project, type ProviderEntry, RegistryUnreadableError, type Release, ReleaseIncompleteError, type ReleaseQuery, type Spawner, TRUST_YOUNG_FLAG, type TarEntry, TrustDeclinedError, TrustPublisherMissingError, TrustReasonMissingError, VersionUnknownError, add, assertReleasePin, bundledEngine, declarationPath, engineAt, fetchRelease, findAdoptedRoot, findProject, httpFetcher, inspectInstall, installPin, integrityOf, launcherUpdateCommand, nodeSpawner, packageDir, packumentUrl, penvHome, readExtensionPackage, readProviderEntries, readTarball, releaseEnginePin, renderDeclaration, runLauncher, setProviderType, tarballUrl, writeDeclaration };
679
+ /**
680
+ * `penv upgrade [version]` — the one command that moves the engine pin.
681
+ *
682
+ * It belongs to the launcher for the same reason `add` does: everything it
683
+ * writes is the launcher's. An engine cannot compute the npm integrity of its
684
+ * own tarball, and the pin is a promise about bytes, so the integrity comes from
685
+ * the registry's `dist.integrity` and from nowhere else — never hashed here, and
686
+ * never typed by a person. Before this command existed, moving the pin meant
687
+ * hand-editing a version *and* an 88-character hash into the one file whose
688
+ * whole purpose is that its bytes are verified, and a mistyped character came
689
+ * back as a supply-chain check failing closed.
690
+ *
691
+ * Two committed files move: the manifest's engine pin and the project's
692
+ * `@penvhq/penv` dependency, at the same exact version. They move together or
693
+ * not at all — one consent covers both, and the dependency lands first, so a
694
+ * package manager that refuses leaves a project still pinning the engine it was
695
+ * already running.
696
+ *
697
+ * Extensions are not touched. Each carries its own pin and its own trust
698
+ * decision, and re-pinning them because the engine moved would be penv choosing
699
+ * bytes nobody reviewed; `penv add <package>@<version>` moves one.
700
+ *
701
+ * A downgrade is an upgrade backwards and takes the same path — a pin is a pin,
702
+ * and a project that needs the engine it ran last week is not asking for
703
+ * something penv should argue with.
704
+ */
705
+
706
+ interface UpgradeOptions {
707
+ /** The tokens after `upgrade`. */
708
+ readonly argv: readonly string[];
709
+ /** The project root — the directory holding `.penv/`. */
710
+ readonly root: string;
711
+ readonly manifestFile: string;
712
+ /** The manifest as the launcher already parsed it. */
713
+ readonly manifest: Manifest;
714
+ readonly home: string;
715
+ readonly io: LauncherIo;
716
+ readonly fetcher: Fetcher;
717
+ /** The launcher's `--no-download`: this run reaches no registry at all. */
718
+ readonly noDownload?: boolean;
719
+ /** True on a CI runner, which may have a terminal and still have nobody at it. */
720
+ readonly ci?: boolean;
721
+ /** Injected in tests: how the project's dependency is installed. Never spawns there. */
722
+ readonly install?: InstallRuntime;
723
+ }
724
+ declare function upgrade(options: UpgradeOptions): Promise<void>;
725
+
726
+ export { AddFlagError, AddLocalFlagError, AddLocalInCiError, AddNoDownloadError, AddNotInteractiveError, type AddOptions, AddPackageNameError, AddRegistryError, type AddResult, AddSubjectError, ArchiveError, type ArchiveSubject, BUNDLED_ENGINE_PIN, DEFAULT_REGISTRY, DEV_PIN_INTEGRITY, DEV_PIN_VERSION, DeclarationMissingError, DeclarationNotSelfContainedError, type DeclarationSubject, type Delegation, DownloadFailedError, DownloadIntegrityError, ENGINE_BIN, type Engine, EngineEntryError, EnginePinMismatchError, EnginePinUnreleasedError, ExtensionNotImportableError, type ExtensionPackage, ExtensionUnloadableError, type Fetcher, HOME_META_FILE, INSTALL_COMMAND, INTEGRITY_FILE, InstallDeclinedError, type InstallOptions, type InstallState, type Installation, LOCAL_FLAG, type LauncherIo, type LauncherOptions, LocalExtensionUnresolvedError, MIN_PACKAGE_AGE_DAYS, NPM_UPDATE_COMMAND, NoProjectError, OfficialRegistryError, PackageCorruptError, PackageMissingError, PackageTooYoungError, PackageUnknownError, type Pin, type Project, type ProviderEntry, RegistryUnreadableError, type Release, ReleaseIncompleteError, type ReleaseQuery, type Spawner, TRUST_YOUNG_FLAG, type TarEntry, TrustDeclinedError, TrustPublisherMissingError, TrustReasonMissingError, UPGRADE_COMMAND, UpgradeDeclinedError, UpgradeFlagError, UpgradeInstallFailedError, UpgradeNoDownloadError, type UpgradeOptions, UpgradeSubjectError, UpgradeUnattendedError, VersionUnknownError, YES_FLAG, add, assertReleasePin, bundledEngine, declarationPath, engineAt, fetchRelease, findAdoptedRoot, findProject, httpFetcher, inspectInstall, installPin, integrityOf, launcherUpdateCommand, nodeSpawner, packumentUrl, readExtensionPackage, readProviderEntries, readTarball, releaseEnginePin, renderDeclaration, runLauncher, setProviderType, tarballUrl, upgrade, writeDeclaration };
package/dist/index.js CHANGED
@@ -20,6 +20,8 @@ import {
20
20
  EngineEntryError,
21
21
  EnginePinMismatchError,
22
22
  EnginePinUnreleasedError,
23
+ ExtensionNotImportableError,
24
+ ExtensionUnloadableError,
23
25
  HOME_META_FILE,
24
26
  INSTALL_COMMAND,
25
27
  INTEGRITY_FILE,
@@ -30,7 +32,6 @@ import {
30
32
  NPM_UPDATE_COMMAND,
31
33
  NoProjectError,
32
34
  OfficialRegistryError,
33
- PENV_HOME_VAR,
34
35
  PackageCorruptError,
35
36
  PackageMissingError,
36
37
  PackageTooYoungError,
@@ -41,7 +42,15 @@ import {
41
42
  TrustDeclinedError,
42
43
  TrustPublisherMissingError,
43
44
  TrustReasonMissingError,
45
+ UPGRADE_COMMAND,
46
+ UpgradeDeclinedError,
47
+ UpgradeFlagError,
48
+ UpgradeInstallFailedError,
49
+ UpgradeNoDownloadError,
50
+ UpgradeSubjectError,
51
+ UpgradeUnattendedError,
44
52
  VersionUnknownError,
53
+ YES_FLAG,
45
54
  add,
46
55
  assertReleasePin,
47
56
  bundledEngine,
@@ -56,9 +65,7 @@ import {
56
65
  integrityOf,
57
66
  launcherUpdateCommand,
58
67
  nodeSpawner,
59
- packageDir,
60
68
  packumentUrl,
61
- penvHome,
62
69
  readExtensionPackage,
63
70
  readProviderEntries,
64
71
  readTarball,
@@ -67,8 +74,9 @@ import {
67
74
  runLauncher,
68
75
  setProviderType,
69
76
  tarballUrl,
77
+ upgrade,
70
78
  writeDeclaration
71
- } from "./chunk-4YZYBC5T.js";
79
+ } from "./chunk-USYQEKPW.js";
72
80
  export {
73
81
  AddFlagError,
74
82
  AddLocalFlagError,
@@ -91,6 +99,8 @@ export {
91
99
  EngineEntryError,
92
100
  EnginePinMismatchError,
93
101
  EnginePinUnreleasedError,
102
+ ExtensionNotImportableError,
103
+ ExtensionUnloadableError,
94
104
  HOME_META_FILE,
95
105
  INSTALL_COMMAND,
96
106
  INTEGRITY_FILE,
@@ -101,7 +111,6 @@ export {
101
111
  NPM_UPDATE_COMMAND,
102
112
  NoProjectError,
103
113
  OfficialRegistryError,
104
- PENV_HOME_VAR,
105
114
  PackageCorruptError,
106
115
  PackageMissingError,
107
116
  PackageTooYoungError,
@@ -112,7 +121,15 @@ export {
112
121
  TrustDeclinedError,
113
122
  TrustPublisherMissingError,
114
123
  TrustReasonMissingError,
124
+ UPGRADE_COMMAND,
125
+ UpgradeDeclinedError,
126
+ UpgradeFlagError,
127
+ UpgradeInstallFailedError,
128
+ UpgradeNoDownloadError,
129
+ UpgradeSubjectError,
130
+ UpgradeUnattendedError,
115
131
  VersionUnknownError,
132
+ YES_FLAG,
116
133
  add,
117
134
  assertReleasePin,
118
135
  bundledEngine,
@@ -127,9 +144,7 @@ export {
127
144
  integrityOf,
128
145
  launcherUpdateCommand,
129
146
  nodeSpawner,
130
- packageDir,
131
147
  packumentUrl,
132
- penvHome,
133
148
  readExtensionPackage,
134
149
  readProviderEntries,
135
150
  readTarball,
@@ -138,6 +153,7 @@ export {
138
153
  runLauncher,
139
154
  setProviderType,
140
155
  tarballUrl,
156
+ upgrade,
141
157
  writeDeclaration
142
158
  };
143
159
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@penvhq/launcher",
3
- "version": "0.9.5",
3
+ "version": "0.11.0",
4
4
  "description": "The stable penv launcher: it verifies the engine your project pins and hands over the command.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -22,8 +22,8 @@
22
22
  ],
23
23
  "dependencies": {
24
24
  "zod": "4.4.3",
25
- "@penvhq/cli": "0.9.5",
26
- "@penvhq/core": "0.9.5"
25
+ "@penvhq/cli": "0.11.0",
26
+ "@penvhq/core": "0.11.0"
27
27
  },
28
28
  "scripts": {
29
29
  "build": "tsup"