@uapkg/cli 1.3.2 → 1.4.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.
Files changed (93) hide show
  1. package/dist/app/CompositionRoot.js.map +1 -1
  2. package/dist/app/UAPKGApplication.js.map +1 -1
  3. package/dist/build/BuildMetadata.js +2 -2
  4. package/dist/cli/parseCommandLine.js.map +1 -1
  5. package/dist/cli/parsing/UAPKGCommandLineParser.js.map +1 -1
  6. package/dist/cli/parsing/UAPKGParserRegistry.js.map +1 -1
  7. package/dist/cli/parsing/modules/AddCommandModule.js +4 -4
  8. package/dist/cli/parsing/modules/AddCommandModule.js.map +1 -1
  9. package/dist/cli/parsing/modules/ConfigCommandModule.js +2 -2
  10. package/dist/cli/parsing/modules/ConfigCommandModule.js.map +1 -1
  11. package/dist/cli/parsing/modules/InitCommandModule.js +2 -2
  12. package/dist/cli/parsing/modules/InitCommandModule.js.map +1 -1
  13. package/dist/cli/parsing/modules/InstallCommandModule.js +3 -3
  14. package/dist/cli/parsing/modules/InstallCommandModule.js.map +1 -1
  15. package/dist/cli/parsing/modules/LifecycleCommandModule.js.map +1 -1
  16. package/dist/cli/parsing/modules/ListCommandModule.js +1 -1
  17. package/dist/cli/parsing/modules/ListCommandModule.js.map +1 -1
  18. package/dist/cli/parsing/modules/LoginCommandModule.js +2 -2
  19. package/dist/cli/parsing/modules/LoginCommandModule.js.map +1 -1
  20. package/dist/cli/parsing/modules/LogoutCommandModule.js.map +1 -1
  21. package/dist/cli/parsing/modules/OutdatedCommandModule.js.map +1 -1
  22. package/dist/cli/parsing/modules/PackCommandModule.js +2 -2
  23. package/dist/cli/parsing/modules/PackCommandModule.js.map +1 -1
  24. package/dist/cli/parsing/modules/ProjectGetNameCommandModule.js.map +1 -1
  25. package/dist/cli/parsing/modules/PublishCommandModule.js +3 -3
  26. package/dist/cli/parsing/modules/PublishCommandModule.js.map +1 -1
  27. package/dist/cli/parsing/modules/RegistryCommandModule.js.map +1 -1
  28. package/dist/cli/parsing/modules/RemoveCommandModule.js +1 -1
  29. package/dist/cli/parsing/modules/RemoveCommandModule.js.map +1 -1
  30. package/dist/cli/parsing/modules/RequestsCommandModule.js +1 -1
  31. package/dist/cli/parsing/modules/RequestsCommandModule.js.map +1 -1
  32. package/dist/cli/parsing/modules/UpdateCommandModule.js +3 -3
  33. package/dist/cli/parsing/modules/UpdateCommandModule.js.map +1 -1
  34. package/dist/cli/parsing/modules/WhoamiCommandModule.d.ts.map +1 -1
  35. package/dist/cli/parsing/modules/WhoamiCommandModule.js.map +1 -1
  36. package/dist/cli/parsing/modules/WhyCommandModule.js +1 -1
  37. package/dist/cli/parsing/modules/WhyCommandModule.js.map +1 -1
  38. package/dist/cli/runUAPKGCLI.js.map +1 -1
  39. package/dist/cli-bootstrap.js.map +1 -1
  40. package/dist/commands/AddCommand.js.map +1 -1
  41. package/dist/commands/ConfigCommand.js.map +1 -1
  42. package/dist/commands/InitCommand.d.ts.map +1 -1
  43. package/dist/commands/InitCommand.js +2 -2
  44. package/dist/commands/InitCommand.js.map +1 -1
  45. package/dist/commands/InstallCommand.js.map +1 -1
  46. package/dist/commands/ListCommand.js.map +1 -1
  47. package/dist/commands/LoginCommand.js.map +1 -1
  48. package/dist/commands/LogoutCommand.js.map +1 -1
  49. package/dist/commands/OutdatedCommand.js.map +1 -1
  50. package/dist/commands/PackCommand.js.map +1 -1
  51. package/dist/commands/PackageLifecycleCommand.js.map +1 -1
  52. package/dist/commands/PostinstallCandidateBuilder.js.map +1 -1
  53. package/dist/commands/ProjectGetNameCommand.js.map +1 -1
  54. package/dist/commands/PublishCommand.js.map +1 -1
  55. package/dist/commands/RegistryCommand.js.map +1 -1
  56. package/dist/commands/RemoveCommand.js.map +1 -1
  57. package/dist/commands/RequestsCommand.js.map +1 -1
  58. package/dist/commands/UpdateCommand.js.map +1 -1
  59. package/dist/commands/WhoamiCommand.js.map +1 -1
  60. package/dist/commands/WhyCommand.js.map +1 -1
  61. package/dist/commands/add/DependencyAddResolver.js.map +1 -1
  62. package/dist/control-plane/AccountManager.js +1 -1
  63. package/dist/control-plane/AccountManager.js.map +1 -1
  64. package/dist/control-plane/AuthMetadataStore.js.map +1 -1
  65. package/dist/control-plane/AuthenticationSelector.js +5 -5
  66. package/dist/control-plane/AuthenticationSelector.js.map +1 -1
  67. package/dist/control-plane/ControlPlaneClient.js.map +1 -1
  68. package/dist/control-plane/ControlPlaneEndpoints.js.map +1 -1
  69. package/dist/control-plane/ControlPlaneTypes.js.map +1 -1
  70. package/dist/control-plane/DPoPKeyStore.js.map +1 -1
  71. package/dist/control-plane/GitHubActionsOidcCredentialProvider.js.map +1 -1
  72. package/dist/control-plane/PublishRequestErrorMapper.js.map +1 -1
  73. package/dist/control-plane/RegistryTrustResolver.js.map +1 -1
  74. package/dist/postinstall/api/definePostinstall.js.map +1 -1
  75. package/dist/postinstall/loader/ExportValidator.js.map +1 -1
  76. package/dist/postinstall/loader/PostinstallLoader.js.map +1 -1
  77. package/dist/postinstall/markers/MarkerBlockEditor.js.map +1 -1
  78. package/dist/postinstall/runner/PostinstallOrchestrator.js.map +1 -1
  79. package/dist/postinstall/unreal/BuildCsInjector.js.map +1 -1
  80. package/dist/postinstall/unreal/CSharpInjectionEngine.js.map +1 -1
  81. package/dist/postinstall/unreal/CSharpStructureAnalyzer.d.ts.map +1 -1
  82. package/dist/postinstall/unreal/CSharpStructureAnalyzer.js.map +1 -1
  83. package/dist/postinstall/unreal/TargetCsInjector.js.map +1 -1
  84. package/dist/postinstall/unreal/UnrealSourceCatalog.js.map +1 -1
  85. package/dist/prompts/InkPromptService.js.map +1 -1
  86. package/dist/reporting/DiagnosticReporter.js.map +1 -1
  87. package/dist/reporting/InkDiagnosticRenderer.js.map +1 -1
  88. package/dist/reporting/InstallProgressReporter.js.map +1 -1
  89. package/dist/reporting/JsonReporter.js.map +1 -1
  90. package/dist/reporting/RegistryRequestTerminalFormatter.js +1 -1
  91. package/dist/reporting/RegistryRequestTerminalFormatter.js.map +1 -1
  92. package/dist/reporting/TextDiagnosticRenderer.js.map +1 -1
  93. package/package.json +26 -14
@@ -1 +1 @@
1
- {"version":3,"file":"PublishCommand.js","names":[],"sources":["../../src/commands/PublishCommand.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { isAbsolute, join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { readPackageClaimsFromArchive } from '@uapkg/package-claims';\nimport { getRegistryRepoPath } from '@uapkg/registry-core';\nimport { RegistryMetaSchema, type RegistryType } from '@uapkg/registry-schema';\nimport type { CompositionRoot } from '../app/CompositionRoot.js';\nimport type { UAPKGOutputFormat } from '../cli/UAPKGCommandLine.js';\nimport { describeControlPlaneError } from '../control-plane/AccountManager.js';\nimport { ArtifactObserver } from '../control-plane/ArtifactObserver.js';\nimport { AuthenticationSelector } from '../control-plane/AuthenticationSelector.js';\nimport { ControlPlaneClient } from '../control-plane/ControlPlaneClient.js';\nimport {\n type ControlPlaneAuthMode,\n ControlPlaneError,\n type RegistryRequestDetail,\n type RegistryRequestStatus,\n type RegistryRequestSubmission,\n} from '../control-plane/ControlPlaneTypes.js';\nimport {\n createGitHubActionsPublishIdempotencyKey,\n PublishIdempotencyStore,\n} from '../control-plane/PublishIdempotencyStore.js';\nimport { publishRequestDiagnosticForError } from '../control-plane/PublishRequestErrorMapper.js';\nimport { InkPromptService } from '../prompts/InkPromptService.js';\nimport {\n formatRegistryRequestTerminal,\n isRegistryRequestSuccessStatus,\n isRegistryRequestTerminalStatus,\n} from '../reporting/RegistryRequestTerminalFormatter.js';\nimport type { Command } from './Command.js';\n\nconst execFileAsync = promisify(execFile);\nconst PUBLISH_WATCH_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport interface PublishCommandOptions {\n readonly registry?: string;\n readonly owner?: string;\n readonly repository?: string;\n readonly tag?: string;\n readonly asset?: string;\n readonly assetPath?: string;\n readonly auth: ControlPlaneAuthMode;\n readonly detach: boolean;\n readonly outputFormat: UAPKGOutputFormat;\n}\n\n/**\n * Artifact-first publish (PS-REQ-002): the CLI observes the exact release\n * artifact (download or `--asset-path`), reads packaged claims from it, and\n * submits the route-derived publish operation. The packaged archive — never\n * the working tree — is what gets published.\n */\nexport class PublishCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: PublishCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n try {\n const manifestResult = await this.root.packageManifest.readManifest();\n if (!manifestResult.ok) {\n throw new Error(manifestResult.diagnostics[0]?.message ?? 'Unable to read uapkg.json.');\n }\n const manifest = manifestResult.value;\n\n const registryAlias = this.options.registry ?? manifest.publish?.registry;\n const trust = await this.root.registryTrustResolver.resolve(registryAlias);\n const source = await this.resolveSource(manifest.version, manifest.publish);\n\n const observer = new ArtifactObserver();\n const artifact = this.options.assetPath\n ? await observer.observeLocalArchive(resolveAssetPath(this.root.cwd, this.options.assetPath))\n : await observer.downloadReleaseAsset(source.repository, source.releaseTag, source.assetName);\n\n try {\n const claimsResult = await readPackageClaimsFromArchive(artifact.archivePath);\n if (!claimsResult.ok) {\n throw new Error(\n claimsResult.diagnostics[0]?.message ?? 'Unable to read the packaged uapkg.json from the artifact.',\n );\n }\n const claims = claimsResult.value;\n if (\n this.options.outputFormat === 'text' &&\n (claims.name !== manifest.name || claims.version !== manifest.version)\n ) {\n process.stderr.write(\n `Publishing ${claims.name}@${claims.version} from the packaged artifact (local manifest says ${manifest.name}@${manifest.version}).\\n`,\n );\n }\n\n const registryType = await readTrustedRegistryType(trust.cacheShortId);\n if (registryType === 'public' && claims.private) {\n throw new Error(\n `\"${claims.name}\" is marked private in its packaged manifest; a public UAPKG registry does not accept private packages.`,\n );\n }\n\n const scopedOwner = scopedOwnerName(claims.name);\n const configuredOwner = normalizeOwner(this.options.owner ?? manifest.publish?.owner);\n if (scopedOwner && configuredOwner && configuredOwner.toLowerCase() !== scopedOwner.toLowerCase()) {\n throw new Error(\n `Package \"${claims.name}\" belongs to the \"${scopedOwner}\" namespace; --owner cannot select \"${configuredOwner}\".`,\n );\n }\n const owner = scopedOwner ?? configuredOwner;\n\n const selector = new AuthenticationSelector(this.root.accountManager, new InkPromptService());\n const oidcTarget = { registryId: trust.registryId, packageName: claims.name };\n const requestedScopes = this.options.detach\n ? (['publishing.request.create'] as const)\n : (['publishing.request.create', 'publishing.request.read.self'] as const);\n let authentication = await selector.select(this.options.auth, trust, requestedScopes, true, oidcTarget);\n let requestOtp = authentication.otp;\n authentication = { kind: authentication.kind, credential: authentication.credential };\n\n const submission: RegistryRequestSubmission = {\n registryId: trust.registryId,\n ...(owner ? { ownerOrganizationName: owner } : {}),\n payload: {\n packageName: claims.name,\n packageVersion: claims.version,\n source,\n observedIntegrity: { sha256: artifact.sha256, sizeBytes: artifact.sizeBytes },\n claims,\n },\n };\n\n const idempotencyStore = new PublishIdempotencyStore();\n const submissionDigest = PublishIdempotencyStore.submissionDigest('publish', submission);\n const usesActionsIdempotency = authentication.kind === 'oidc';\n const idempotencyKey = usesActionsIdempotency\n ? createGitHubActionsPublishIdempotencyKey({\n registryId: trust.registryId,\n packageName: claims.name,\n packageVersion: claims.version,\n artifactSha256: artifact.sha256,\n })\n : idempotencyStore.getOrCreate(submissionDigest, () => randomUUID());\n\n const client = new ControlPlaneClient(trust.apiBaseUrl);\n let created: Awaited<ReturnType<ControlPlaneClient['submitRegistryRequest']>>;\n try {\n created = await client.submitRegistryRequest(authentication.credential, 'publish', submission, {\n idempotencyKey,\n otp: requestOtp,\n });\n } catch (error) {\n if (this.options.outputFormat === 'json') throw error;\n this.root.diagnostics.reportOne(\n publishRequestDiagnosticForError(error, {\n packageName: claims.name,\n packageVersion: claims.version,\n registryAlias: trust.alias,\n registryName: trust.registryName,\n registryIssuer: trust.issuer,\n credentialKind: authentication.kind,\n ...(owner ? { requestedOwner: owner } : {}),\n repository: source.repository,\n }),\n );\n return 1;\n } finally {\n // The request-scoped proof must not remain reachable while the CLI\n // polls, refreshes credentials, or watches the durable request.\n requestOtp = undefined;\n }\n if (this.options.detach) {\n this.printCreated(created.requestId, created.status, trust.alias);\n return 0;\n }\n\n const readRequest = async () => {\n try {\n return await client.getRegistryRequestDetail(authentication.credential, created.requestId);\n } catch (error) {\n if (!(error instanceof ControlPlaneError) || error.status !== 401) throw error;\n if (authentication.kind === 'gat') throw error;\n if (authentication.kind === 'login') {\n this.root.accountManager.invalidateAccessCredentials(trust);\n }\n authentication = await selector.select(\n authentication.kind,\n trust,\n ['publishing.request.read.self'],\n false,\n oidcTarget,\n );\n return client.getRegistryRequestDetail(authentication.credential, created.requestId);\n }\n };\n\n let detail = await readRequest();\n let previousStatus = '';\n const deadline = Date.now() + PUBLISH_WATCH_TIMEOUT_MS;\n while (!isRegistryRequestTerminalStatus(detail.request.status)) {\n if (Date.now() >= deadline) {\n throw new Error(\n `Timed out waiting for publishing request ${detail.request.id}. Check it with \\`uapkg requests status ${detail.request.id}\\`.`,\n );\n }\n if (this.options.outputFormat === 'text' && detail.request.status !== previousStatus) {\n process.stdout.write(\n `${detail.request.id}: ${detail.request.status}${detail.request.currentStep ? ` (${detail.request.currentStep})` : ''}\\n`,\n );\n previousStatus = detail.request.status;\n }\n await delay(2_000);\n detail = await readRequest();\n }\n\n if (!usesActionsIdempotency) idempotencyStore.clear(submissionDigest);\n\n if (isRegistryRequestSuccessStatus(detail.request.status)) {\n let refreshWarning: string | undefined;\n try {\n await this.root.registryTrustResolver.forceRefresh(trust);\n } catch (error) {\n refreshWarning = error instanceof Error ? error.message : String(error);\n }\n this.printTerminal(detail, trust.alias, refreshWarning);\n return 0;\n }\n\n this.printTerminal(detail, trust.alias);\n return 1;\n } finally {\n await artifact.cleanup();\n }\n } catch (error) {\n process.stderr.write(`${describeControlPlaneError(error)}\\n`);\n return 1;\n }\n }\n\n private async resolveSource(\n packageVersion: string,\n manifestPublish:\n | {\n readonly repository?: string;\n readonly asset?: string;\n }\n | undefined,\n ) {\n const repository = normalizeGitHubRepository(\n this.options.repository ?? manifestPublish?.repository ?? (await this.gitOrigin()),\n );\n const releaseTag = (this.options.tag ?? `v${packageVersion}`).trim();\n const assetName = (this.options.asset ?? manifestPublish?.asset ?? 'package.tgz').trim();\n if (!releaseTag) throw new Error('The GitHub Release tag cannot be empty.');\n if (!assetName || assetName.includes('/') || assetName.includes('\\\\')) {\n throw new Error('The GitHub Release asset must be a file name, not a path.');\n }\n return {\n type: 'github_release' as const,\n repository,\n releaseTag,\n assetName,\n };\n }\n\n private async gitOrigin(): Promise<string> {\n const git = (this.root.config.get('git') as string | null) ?? 'git';\n try {\n const { stdout } = await execFileAsync(git, ['remote', 'get-url', 'origin'], {\n cwd: this.root.cwd,\n timeout: 10_000,\n });\n return stdout.trim();\n } catch (error) {\n throw new Error('Unable to derive the GitHub repository from remote \"origin\". Use --repository.', {\n cause: error,\n });\n }\n }\n\n private printCreated(requestId: string, status: RegistryRequestStatus, registryAlias: string): void {\n if (this.options.outputFormat === 'json') {\n process.stdout.write(`${JSON.stringify({ ok: true, registry: registryAlias, requestId, status })}\\n`);\n return;\n }\n process.stdout.write(`Publishing request ${requestId} submitted to \"${registryAlias}\" (${status}).\\n`);\n }\n\n private printTerminal(detail: RegistryRequestDetail, registryAlias: string, refreshWarning?: string): void {\n const output = formatRegistryRequestTerminal({\n detail,\n registryAlias,\n outputFormat: this.options.outputFormat,\n presentation: { kind: 'publish' },\n ...(refreshWarning ? { registryRefreshWarning: refreshWarning } : {}),\n });\n process.stdout.write(output.stdout);\n if (output.stderr) process.stderr.write(output.stderr);\n }\n}\n\n/** Reads the installer-trusted registry type from the projected registry snapshot. */\nexport async function readTrustedRegistryType(cacheShortId: string): Promise<RegistryType> {\n const metaPath = join(getRegistryRepoPath(cacheShortId), '.uapkg', 'registry.meta.json');\n if (!existsSync(metaPath)) {\n throw new Error('Trusted registry metadata is missing; registry policy cannot be determined.');\n }\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = RegistryMetaSchema.safeParse(JSON.parse(raw) as unknown);\n if (!parsed.success) {\n throw new Error('metadata does not match a supported registry schema');\n }\n return parsed.data.registry.registryType;\n } catch (error) {\n throw new Error('Trusted registry metadata is invalid or uses an unsupported schema version.', { cause: error });\n }\n}\n\nfunction resolveAssetPath(cwd: string, assetPath: string): string {\n return isAbsolute(assetPath) ? assetPath : join(cwd, assetPath);\n}\n\nfunction normalizeGitHubRepository(input: string): string {\n let value = input.trim();\n const scp = value.match(/^git@github\\.com:([^/]+)\\/(.+)$/i);\n if (scp) value = `${scp[1]}/${scp[2]}`;\n\n if (value.includes('://')) {\n const url = new URL(value);\n if (url.hostname.toLowerCase() !== 'github.com') {\n throw new Error('Publishing sources must be hosted on github.com in UAPKG v1.');\n }\n value = url.pathname.replace(/^\\/+/, '');\n }\n value = value.replace(/\\.git$/i, '').replace(/\\/+$/, '');\n if (!/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/.test(value)) {\n throw new Error('Expected a GitHub repository in owner/repository form.');\n }\n return value.toLowerCase();\n}\n\nfunction scopedOwnerName(packageName: string): string | undefined {\n const match = packageName.match(/^@([^/]+)\\/[^/]+$/);\n return match?.[1]?.toLowerCase();\n}\n\nfunction normalizeOwner(value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n const owner = value.trim().toLowerCase();\n if (!/^[a-z0-9][a-z0-9-_]*$/.test(owner)) {\n throw new Error('The publish owner must be a valid UAPKG organization name.');\n }\n return owner;\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PublishCommand.js","names":[],"sources":["../../src/commands/PublishCommand.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { randomUUID } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { isAbsolute, join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { readPackageClaimsFromArchive } from '@uapkg/package-claims';\nimport { getRegistryRepoPath } from '@uapkg/registry-core';\nimport { RegistryMetaSchema, type RegistryType } from '@uapkg/registry-schema';\nimport type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\nimport type { UAPKGOutputFormat } from '#cli/cli/UAPKGCommandLine.ts';\nimport { describeControlPlaneError } from '#cli/control-plane/AccountManager.ts';\nimport { ArtifactObserver } from '#cli/control-plane/ArtifactObserver.ts';\nimport { AuthenticationSelector } from '#cli/control-plane/AuthenticationSelector.ts';\nimport { ControlPlaneClient } from '#cli/control-plane/ControlPlaneClient.ts';\nimport {\n type ControlPlaneAuthMode,\n ControlPlaneError,\n type RegistryRequestDetail,\n type RegistryRequestStatus,\n type RegistryRequestSubmission,\n} from '#cli/control-plane/ControlPlaneTypes.ts';\nimport {\n createGitHubActionsPublishIdempotencyKey,\n PublishIdempotencyStore,\n} from '#cli/control-plane/PublishIdempotencyStore.ts';\nimport { publishRequestDiagnosticForError } from '#cli/control-plane/PublishRequestErrorMapper.ts';\nimport { InkPromptService } from '#cli/prompts/InkPromptService.tsx';\nimport {\n formatRegistryRequestTerminal,\n isRegistryRequestSuccessStatus,\n isRegistryRequestTerminalStatus,\n} from '#cli/reporting/RegistryRequestTerminalFormatter.ts';\nimport type { Command } from '#cli/commands/Command.ts';\n\nconst execFileAsync = promisify(execFile);\nconst PUBLISH_WATCH_TIMEOUT_MS = 30 * 60 * 1000;\n\nexport interface PublishCommandOptions {\n readonly registry?: string;\n readonly owner?: string;\n readonly repository?: string;\n readonly tag?: string;\n readonly asset?: string;\n readonly assetPath?: string;\n readonly auth: ControlPlaneAuthMode;\n readonly detach: boolean;\n readonly outputFormat: UAPKGOutputFormat;\n}\n\n/**\n * Artifact-first publish (PS-REQ-002): the CLI observes the exact release\n * artifact (download or `--asset-path`), reads packaged claims from it, and\n * submits the route-derived publish operation. The packaged archive — never\n * the working tree — is what gets published.\n */\nexport class PublishCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: PublishCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n try {\n const manifestResult = await this.root.packageManifest.readManifest();\n if (!manifestResult.ok) {\n throw new Error(manifestResult.diagnostics[0]?.message ?? 'Unable to read uapkg.json.');\n }\n const manifest = manifestResult.value;\n\n const registryAlias = this.options.registry ?? manifest.publish?.registry;\n const trust = await this.root.registryTrustResolver.resolve(registryAlias);\n const source = await this.resolveSource(manifest.version, manifest.publish);\n\n const observer = new ArtifactObserver();\n const artifact = this.options.assetPath\n ? await observer.observeLocalArchive(resolveAssetPath(this.root.cwd, this.options.assetPath))\n : await observer.downloadReleaseAsset(source.repository, source.releaseTag, source.assetName);\n\n try {\n const claimsResult = await readPackageClaimsFromArchive(artifact.archivePath);\n if (!claimsResult.ok) {\n throw new Error(\n claimsResult.diagnostics[0]?.message ?? 'Unable to read the packaged uapkg.json from the artifact.',\n );\n }\n const claims = claimsResult.value;\n if (\n this.options.outputFormat === 'text' &&\n (claims.name !== manifest.name || claims.version !== manifest.version)\n ) {\n process.stderr.write(\n `Publishing ${claims.name}@${claims.version} from the packaged artifact (local manifest says ${manifest.name}@${manifest.version}).\\n`,\n );\n }\n\n const registryType = await readTrustedRegistryType(trust.cacheShortId);\n if (registryType === 'public' && claims.private) {\n throw new Error(\n `\"${claims.name}\" is marked private in its packaged manifest; a public UAPKG registry does not accept private packages.`,\n );\n }\n\n const scopedOwner = scopedOwnerName(claims.name);\n const configuredOwner = normalizeOwner(this.options.owner ?? manifest.publish?.owner);\n if (scopedOwner && configuredOwner && configuredOwner.toLowerCase() !== scopedOwner.toLowerCase()) {\n throw new Error(\n `Package \"${claims.name}\" belongs to the \"${scopedOwner}\" namespace; --owner cannot select \"${configuredOwner}\".`,\n );\n }\n const owner = scopedOwner ?? configuredOwner;\n\n const selector = new AuthenticationSelector(this.root.accountManager, new InkPromptService());\n const oidcTarget = { registryId: trust.registryId, packageName: claims.name };\n const requestedScopes = this.options.detach\n ? (['publishing.request.create'] as const)\n : (['publishing.request.create', 'publishing.request.read.self'] as const);\n let authentication = await selector.select(this.options.auth, trust, requestedScopes, true, oidcTarget);\n let requestOtp = authentication.otp;\n authentication = { kind: authentication.kind, credential: authentication.credential };\n\n const submission: RegistryRequestSubmission = {\n registryId: trust.registryId,\n ...(owner ? { ownerOrganizationName: owner } : {}),\n payload: {\n packageName: claims.name,\n packageVersion: claims.version,\n source,\n observedIntegrity: { sha256: artifact.sha256, sizeBytes: artifact.sizeBytes },\n claims,\n },\n };\n\n const idempotencyStore = new PublishIdempotencyStore();\n const submissionDigest = PublishIdempotencyStore.submissionDigest('publish', submission);\n const usesActionsIdempotency = authentication.kind === 'oidc';\n const idempotencyKey = usesActionsIdempotency\n ? createGitHubActionsPublishIdempotencyKey({\n registryId: trust.registryId,\n packageName: claims.name,\n packageVersion: claims.version,\n artifactSha256: artifact.sha256,\n })\n : idempotencyStore.getOrCreate(submissionDigest, () => randomUUID());\n\n const client = new ControlPlaneClient(trust.apiBaseUrl);\n let created: Awaited<ReturnType<ControlPlaneClient['submitRegistryRequest']>>;\n try {\n created = await client.submitRegistryRequest(authentication.credential, 'publish', submission, {\n idempotencyKey,\n otp: requestOtp,\n });\n } catch (error) {\n if (this.options.outputFormat === 'json') throw error;\n this.root.diagnostics.reportOne(\n publishRequestDiagnosticForError(error, {\n packageName: claims.name,\n packageVersion: claims.version,\n registryAlias: trust.alias,\n registryName: trust.registryName,\n registryIssuer: trust.issuer,\n credentialKind: authentication.kind,\n ...(owner ? { requestedOwner: owner } : {}),\n repository: source.repository,\n }),\n );\n return 1;\n } finally {\n // The request-scoped proof must not remain reachable while the CLI\n // polls, refreshes credentials, or watches the durable request.\n requestOtp = undefined;\n }\n if (this.options.detach) {\n this.printCreated(created.requestId, created.status, trust.alias);\n return 0;\n }\n\n const readRequest = async () => {\n try {\n return await client.getRegistryRequestDetail(authentication.credential, created.requestId);\n } catch (error) {\n if (!(error instanceof ControlPlaneError) || error.status !== 401) throw error;\n if (authentication.kind === 'gat') throw error;\n if (authentication.kind === 'login') {\n this.root.accountManager.invalidateAccessCredentials(trust);\n }\n authentication = await selector.select(\n authentication.kind,\n trust,\n ['publishing.request.read.self'],\n false,\n oidcTarget,\n );\n return client.getRegistryRequestDetail(authentication.credential, created.requestId);\n }\n };\n\n let detail = await readRequest();\n let previousStatus = '';\n const deadline = Date.now() + PUBLISH_WATCH_TIMEOUT_MS;\n while (!isRegistryRequestTerminalStatus(detail.request.status)) {\n if (Date.now() >= deadline) {\n throw new Error(\n `Timed out waiting for publishing request ${detail.request.id}. Check it with \\`uapkg requests status ${detail.request.id}\\`.`,\n );\n }\n if (this.options.outputFormat === 'text' && detail.request.status !== previousStatus) {\n process.stdout.write(\n `${detail.request.id}: ${detail.request.status}${detail.request.currentStep ? ` (${detail.request.currentStep})` : ''}\\n`,\n );\n previousStatus = detail.request.status;\n }\n await delay(2_000);\n detail = await readRequest();\n }\n\n if (!usesActionsIdempotency) idempotencyStore.clear(submissionDigest);\n\n if (isRegistryRequestSuccessStatus(detail.request.status)) {\n let refreshWarning: string | undefined;\n try {\n await this.root.registryTrustResolver.forceRefresh(trust);\n } catch (error) {\n refreshWarning = error instanceof Error ? error.message : String(error);\n }\n this.printTerminal(detail, trust.alias, refreshWarning);\n return 0;\n }\n\n this.printTerminal(detail, trust.alias);\n return 1;\n } finally {\n await artifact.cleanup();\n }\n } catch (error) {\n process.stderr.write(`${describeControlPlaneError(error)}\\n`);\n return 1;\n }\n }\n\n private async resolveSource(\n packageVersion: string,\n manifestPublish:\n | {\n readonly repository?: string;\n readonly asset?: string;\n }\n | undefined,\n ) {\n const repository = normalizeGitHubRepository(\n this.options.repository ?? manifestPublish?.repository ?? (await this.gitOrigin()),\n );\n const releaseTag = (this.options.tag ?? `v${packageVersion}`).trim();\n const assetName = (this.options.asset ?? manifestPublish?.asset ?? 'package.tgz').trim();\n if (!releaseTag) throw new Error('The GitHub Release tag cannot be empty.');\n if (!assetName || assetName.includes('/') || assetName.includes('\\\\')) {\n throw new Error('The GitHub Release asset must be a file name, not a path.');\n }\n return {\n type: 'github_release' as const,\n repository,\n releaseTag,\n assetName,\n };\n }\n\n private async gitOrigin(): Promise<string> {\n const git = (this.root.config.get('git') as string | null) ?? 'git';\n try {\n const { stdout } = await execFileAsync(git, ['remote', 'get-url', 'origin'], {\n cwd: this.root.cwd,\n timeout: 10_000,\n });\n return stdout.trim();\n } catch (error) {\n throw new Error('Unable to derive the GitHub repository from remote \"origin\". Use --repository.', {\n cause: error,\n });\n }\n }\n\n private printCreated(requestId: string, status: RegistryRequestStatus, registryAlias: string): void {\n if (this.options.outputFormat === 'json') {\n process.stdout.write(`${JSON.stringify({ ok: true, registry: registryAlias, requestId, status })}\\n`);\n return;\n }\n process.stdout.write(`Publishing request ${requestId} submitted to \"${registryAlias}\" (${status}).\\n`);\n }\n\n private printTerminal(detail: RegistryRequestDetail, registryAlias: string, refreshWarning?: string): void {\n const output = formatRegistryRequestTerminal({\n detail,\n registryAlias,\n outputFormat: this.options.outputFormat,\n presentation: { kind: 'publish' },\n ...(refreshWarning ? { registryRefreshWarning: refreshWarning } : {}),\n });\n process.stdout.write(output.stdout);\n if (output.stderr) process.stderr.write(output.stderr);\n }\n}\n\n/** Reads the installer-trusted registry type from the projected registry snapshot. */\nexport async function readTrustedRegistryType(cacheShortId: string): Promise<RegistryType> {\n const metaPath = join(getRegistryRepoPath(cacheShortId), '.uapkg', 'registry.meta.json');\n if (!existsSync(metaPath)) {\n throw new Error('Trusted registry metadata is missing; registry policy cannot be determined.');\n }\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = RegistryMetaSchema.safeParse(JSON.parse(raw) as unknown);\n if (!parsed.success) {\n throw new Error('metadata does not match a supported registry schema');\n }\n return parsed.data.registry.registryType;\n } catch (error) {\n throw new Error('Trusted registry metadata is invalid or uses an unsupported schema version.', { cause: error });\n }\n}\n\nfunction resolveAssetPath(cwd: string, assetPath: string): string {\n return isAbsolute(assetPath) ? assetPath : join(cwd, assetPath);\n}\n\nfunction normalizeGitHubRepository(input: string): string {\n let value = input.trim();\n const scp = value.match(/^git@github\\.com:([^/]+)\\/(.+)$/i);\n if (scp) value = `${scp[1]}/${scp[2]}`;\n\n if (value.includes('://')) {\n const url = new URL(value);\n if (url.hostname.toLowerCase() !== 'github.com') {\n throw new Error('Publishing sources must be hosted on github.com in UAPKG v1.');\n }\n value = url.pathname.replace(/^\\/+/, '');\n }\n value = value.replace(/\\.git$/i, '').replace(/\\/+$/, '');\n if (!/^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/.test(value)) {\n throw new Error('Expected a GitHub repository in owner/repository form.');\n }\n return value.toLowerCase();\n}\n\nfunction scopedOwnerName(packageName: string): string | undefined {\n const match = packageName.match(/^@([^/]+)\\/[^/]+$/);\n return match?.[1]?.toLowerCase();\n}\n\nfunction normalizeOwner(value: string | undefined): string | undefined {\n if (value === undefined) return undefined;\n const owner = value.trim().toLowerCase();\n if (!/^[a-z0-9][a-z0-9-_]*$/.test(owner)) {\n throw new Error('The publish owner must be a valid UAPKG organization name.');\n }\n return owner;\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RegistryCommand.js","names":[],"sources":["../../src/commands/RegistryCommand.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ConfigInstance } from '@uapkg/config';\nimport { createParseErrorDiagnostic, type Diagnostic } from '@uapkg/diagnostics';\nimport Log from '@uapkg/log';\nimport type { CompositionRoot } from '../app/CompositionRoot.js';\nimport type { UAPKGConfigScope, UAPKGOutputFormat, UAPKGRegistryAction } from '../cli/UAPKGCommandLine.js';\nimport type { Command } from './Command.js';\n\nexport interface RegistryCommandOptions {\n action: UAPKGRegistryAction;\n name?: string;\n url?: string;\n refType?: 'branch' | 'tag' | 'rev';\n refValue?: string;\n scope?: UAPKGConfigScope;\n output: UAPKGOutputFormat;\n}\n\nexport interface RegistryCommandRuntime {\n isInteractiveTerminal(): boolean;\n}\n\nconst processRuntime: RegistryCommandRuntime = {\n isInteractiveTerminal: () => process.stdin.isTTY === true && process.stderr.isTTY === true,\n};\n\nexport class RegistryCommand implements Command {\n private configDiagnostics: readonly Diagnostic[] = [];\n\n constructor(\n private readonly root: CompositionRoot,\n private readonly options: RegistryCommandOptions,\n private readonly runtime: RegistryCommandRuntime = processRuntime,\n ) {}\n\n public async execute(): Promise<number> {\n const config = this.root.config;\n this.configDiagnostics = config.getDiagnostics();\n this.reportIfText(this.configDiagnostics);\n\n switch (this.options.action) {\n case 'list':\n return this.executeList(config);\n case 'add':\n return this.executeAdd(config);\n case 'remove':\n return this.executeRemove(config);\n case 'use':\n return this.executeUse(config);\n case 'auth':\n return this.executeAuth(config);\n case 'refresh':\n return this.executeRefresh(config);\n default:\n return this.fail([\n createParseErrorDiagnostic(`Unsupported registry action: ${String(this.options.action satisfies never)}`),\n ]);\n }\n }\n\n private executeList(config: ConfigInstance): number {\n const registries = this.options.scope\n ? config.get('registries', { scope: this.options.scope })\n : config.get('registries');\n this.print(registries ?? {});\n return 0;\n }\n\n private executeAdd(config: ConfigInstance): number {\n const name = this.options.name;\n const url = this.options.url;\n if (!name || !url) {\n return this.fail([createParseErrorDiagnostic('registry add requires <name> and <url>.')]);\n }\n\n const ref = this.resolveRef();\n\n const setUrl = config.set(`registries.${name}.url`, url, this.scopeOptions());\n if (!setUrl.ok) return this.fail(setUrl.diagnostics);\n this.persistPlan(setUrl.value.file, setUrl.value.values);\n\n const setRef = config.set(`registries.${name}.ref`, ref, this.scopeOptions());\n if (!setRef.ok) return this.fail(setRef.diagnostics);\n this.persistPlan(setRef.value.file, setRef.value.values);\n\n config.reload({ cwd: this.root.cwd });\n this.reportIfText(config.getDiagnostics());\n this.print({\n action: 'add',\n name,\n url,\n ref,\n scope: this.options.scope ?? 'auto',\n });\n return 0;\n }\n\n private executeRemove(config: ConfigInstance): number {\n const name = this.options.name;\n if (!name) {\n return this.fail([createParseErrorDiagnostic('registry remove requires <name>.')]);\n }\n\n const plan = config.delete(`registries.${name}`, this.scopeOptions());\n if (!plan.ok) return this.fail(plan.diagnostics);\n this.persistPlan(plan.value.file, plan.value.values);\n\n config.reload({ cwd: this.root.cwd });\n this.reportIfText(config.getDiagnostics());\n this.print({ action: 'remove', name, scope: this.options.scope ?? 'auto' });\n return 0;\n }\n\n private executeUse(config: ConfigInstance): number {\n const name = this.options.name;\n if (!name) {\n return this.fail([createParseErrorDiagnostic('registry use requires <name>.')]);\n }\n\n const plan = config.set('registry', name, this.scopeOptions());\n if (!plan.ok) return this.fail(plan.diagnostics);\n this.persistPlan(plan.value.file, plan.value.values);\n\n config.reload({ cwd: this.root.cwd });\n this.reportIfText(config.getDiagnostics());\n this.print({ action: 'use', name, scope: this.options.scope ?? 'auto' });\n return 0;\n }\n\n private async executeAuth(config: ConfigInstance): Promise<number> {\n if (this.options.scope) {\n return this.fail([createParseErrorDiagnostic('registry auth does not accept --global or --local.')]);\n }\n\n const name = this.resolveRegistryName(config);\n if (!name) return 1;\n const registryResult = this.root.registryCore.getOrCreateRegistry(name);\n if (!registryResult.ok) return this.fail(registryResult.diagnostics);\n\n let accessResult = await registryResult.value.probeAccess({ interactive: false });\n let usedInteractivePrompt = false;\n const hasTerminal = this.runtime.isInteractiveTerminal();\n if (!accessResult.ok && hasTerminal) {\n usedInteractivePrompt = true;\n accessResult = await registryResult.value.probeAccess({ interactive: true });\n }\n\n if (!accessResult.ok) {\n return this.fail(this.withAuthenticationGuidance(accessResult.diagnostics, name, hasTerminal));\n }\n\n this.succeedOperational(\n 'auth',\n {\n action: 'auth',\n name,\n accessible: true,\n interactive: usedInteractivePrompt,\n },\n `Registry \"${name}\" is accessible with the current system Git credentials.`,\n accessResult.diagnostics,\n );\n return 0;\n }\n\n private async executeRefresh(config: ConfigInstance): Promise<number> {\n if (this.options.scope) {\n return this.fail([createParseErrorDiagnostic('registry refresh does not accept --global or --local.')]);\n }\n\n const name = this.resolveRegistryName(config);\n if (!name) return 1;\n const registryResult = this.root.registryCore.getOrCreateRegistry(name);\n if (!registryResult.ok) return this.fail(registryResult.diagnostics);\n\n const refreshResult = await registryResult.value.ensureUpToDate({\n bypassFreshnessCheck: true,\n logicalRegistryName: name,\n });\n if (!refreshResult.ok) return this.fail(refreshResult.diagnostics);\n if (refreshResult.value === 'Failed') {\n const diagnostics =\n refreshResult.diagnostics.length > 0\n ? refreshResult.diagnostics\n : [createParseErrorDiagnostic(`Registry \"${name}\" could not be refreshed.`)];\n return this.fail(diagnostics);\n }\n\n this.succeedOperational(\n 'refresh',\n { action: 'refresh', name, result: refreshResult.value },\n `Registry \"${name}\" refreshed.`,\n refreshResult.diagnostics,\n );\n return 0;\n }\n\n private resolveRegistryName(config: ConfigInstance): string | undefined {\n const candidate = this.options.name ?? config.get('registry');\n if (typeof candidate !== 'string' || candidate.trim().length === 0) {\n this.fail([\n createParseErrorDiagnostic(\n `registry ${this.options.action} requires a registry alias or a selected default registry.`,\n ),\n ]);\n return undefined;\n }\n return candidate.trim();\n }\n\n private withAuthenticationGuidance(\n diagnostics: readonly Diagnostic[],\n name: string,\n interactiveTerminalAvailable: boolean,\n ): readonly Diagnostic[] {\n return diagnostics.map((diagnostic) => ({\n ...diagnostic,\n message: `Git could not access registry \"${name}\".`,\n hint: interactiveTerminalAvailable\n ? 'Configure access with a system Git credential helper, SSH key/agent, or deploy key, then retry.'\n : `No interactive terminal is available. Configure a system Git credential helper, GIT_ASKPASS, SSH key/agent, or CI deploy key, then retry 'uapkg registry auth ${name}'.`,\n }));\n }\n\n private resolveRef(): { type: 'branch' | 'tag' | 'rev'; value: string } {\n const type = this.options.refType ?? 'branch';\n const value = this.options.refValue ?? 'main';\n return { type, value };\n }\n\n private scopeOptions(): { scope?: UAPKGConfigScope } {\n return this.options.scope ? { scope: this.options.scope } : {};\n }\n\n private persistPlan(filePath: string, values: Record<string, unknown>): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, `${JSON.stringify(values, null, 2)}\\n`, 'utf8');\n }\n\n private fail(diagnostics: readonly Diagnostic[]): number {\n if (this.options.output === 'json') {\n this.root.json.emit({\n status: 'error',\n command: `registry ${this.options.action}`,\n diagnostics: [...this.configDiagnostics, ...diagnostics],\n });\n } else {\n this.root.diagnostics.reportAll(diagnostics);\n }\n return 1;\n }\n\n private reportIfText(diagnostics: readonly Diagnostic[]): void {\n if (this.options.output === 'text') {\n this.root.diagnostics.reportAll(diagnostics);\n }\n }\n\n private succeedOperational(\n action: 'auth' | 'refresh',\n data: Record<string, unknown>,\n text: string,\n diagnostics: readonly Diagnostic[],\n ): void {\n if (this.options.output === 'json') {\n this.root.json.emit({\n status: 'ok',\n command: `registry ${action}`,\n data,\n diagnostics: [...this.configDiagnostics, ...diagnostics],\n });\n return;\n }\n\n this.root.diagnostics.reportAll(diagnostics);\n process.stdout.write(`${text}\\n`);\n }\n\n private print(value: unknown): void {\n if (this.options.output === 'json' || typeof value === 'object') {\n Log.info(JSON.stringify(value, null, 2));\n return;\n }\n Log.info(JSON.stringify(value));\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"RegistryCommand.js","names":[],"sources":["../../src/commands/RegistryCommand.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ConfigInstance } from '@uapkg/config';\nimport { createParseErrorDiagnostic, type Diagnostic } from '@uapkg/diagnostics';\nimport Log from '@uapkg/log';\nimport type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\nimport type { UAPKGConfigScope, UAPKGOutputFormat, UAPKGRegistryAction } from '#cli/cli/UAPKGCommandLine.ts';\nimport type { Command } from '#cli/commands/Command.ts';\n\nexport interface RegistryCommandOptions {\n action: UAPKGRegistryAction;\n name?: string;\n url?: string;\n refType?: 'branch' | 'tag' | 'rev';\n refValue?: string;\n scope?: UAPKGConfigScope;\n output: UAPKGOutputFormat;\n}\n\nexport interface RegistryCommandRuntime {\n isInteractiveTerminal(): boolean;\n}\n\nconst processRuntime: RegistryCommandRuntime = {\n isInteractiveTerminal: () => process.stdin.isTTY === true && process.stderr.isTTY === true,\n};\n\nexport class RegistryCommand implements Command {\n private configDiagnostics: readonly Diagnostic[] = [];\n\n constructor(\n private readonly root: CompositionRoot,\n private readonly options: RegistryCommandOptions,\n private readonly runtime: RegistryCommandRuntime = processRuntime,\n ) {}\n\n public async execute(): Promise<number> {\n const config = this.root.config;\n this.configDiagnostics = config.getDiagnostics();\n this.reportIfText(this.configDiagnostics);\n\n switch (this.options.action) {\n case 'list':\n return this.executeList(config);\n case 'add':\n return this.executeAdd(config);\n case 'remove':\n return this.executeRemove(config);\n case 'use':\n return this.executeUse(config);\n case 'auth':\n return this.executeAuth(config);\n case 'refresh':\n return this.executeRefresh(config);\n default:\n return this.fail([\n createParseErrorDiagnostic(`Unsupported registry action: ${String(this.options.action satisfies never)}`),\n ]);\n }\n }\n\n private executeList(config: ConfigInstance): number {\n const registries = this.options.scope\n ? config.get('registries', { scope: this.options.scope })\n : config.get('registries');\n this.print(registries ?? {});\n return 0;\n }\n\n private executeAdd(config: ConfigInstance): number {\n const name = this.options.name;\n const url = this.options.url;\n if (!name || !url) {\n return this.fail([createParseErrorDiagnostic('registry add requires <name> and <url>.')]);\n }\n\n const ref = this.resolveRef();\n\n const setUrl = config.set(`registries.${name}.url`, url, this.scopeOptions());\n if (!setUrl.ok) return this.fail(setUrl.diagnostics);\n this.persistPlan(setUrl.value.file, setUrl.value.values);\n\n const setRef = config.set(`registries.${name}.ref`, ref, this.scopeOptions());\n if (!setRef.ok) return this.fail(setRef.diagnostics);\n this.persistPlan(setRef.value.file, setRef.value.values);\n\n config.reload({ cwd: this.root.cwd });\n this.reportIfText(config.getDiagnostics());\n this.print({\n action: 'add',\n name,\n url,\n ref,\n scope: this.options.scope ?? 'auto',\n });\n return 0;\n }\n\n private executeRemove(config: ConfigInstance): number {\n const name = this.options.name;\n if (!name) {\n return this.fail([createParseErrorDiagnostic('registry remove requires <name>.')]);\n }\n\n const plan = config.delete(`registries.${name}`, this.scopeOptions());\n if (!plan.ok) return this.fail(plan.diagnostics);\n this.persistPlan(plan.value.file, plan.value.values);\n\n config.reload({ cwd: this.root.cwd });\n this.reportIfText(config.getDiagnostics());\n this.print({ action: 'remove', name, scope: this.options.scope ?? 'auto' });\n return 0;\n }\n\n private executeUse(config: ConfigInstance): number {\n const name = this.options.name;\n if (!name) {\n return this.fail([createParseErrorDiagnostic('registry use requires <name>.')]);\n }\n\n const plan = config.set('registry', name, this.scopeOptions());\n if (!plan.ok) return this.fail(plan.diagnostics);\n this.persistPlan(plan.value.file, plan.value.values);\n\n config.reload({ cwd: this.root.cwd });\n this.reportIfText(config.getDiagnostics());\n this.print({ action: 'use', name, scope: this.options.scope ?? 'auto' });\n return 0;\n }\n\n private async executeAuth(config: ConfigInstance): Promise<number> {\n if (this.options.scope) {\n return this.fail([createParseErrorDiagnostic('registry auth does not accept --global or --local.')]);\n }\n\n const name = this.resolveRegistryName(config);\n if (!name) return 1;\n const registryResult = this.root.registryCore.getOrCreateRegistry(name);\n if (!registryResult.ok) return this.fail(registryResult.diagnostics);\n\n let accessResult = await registryResult.value.probeAccess({ interactive: false });\n let usedInteractivePrompt = false;\n const hasTerminal = this.runtime.isInteractiveTerminal();\n if (!accessResult.ok && hasTerminal) {\n usedInteractivePrompt = true;\n accessResult = await registryResult.value.probeAccess({ interactive: true });\n }\n\n if (!accessResult.ok) {\n return this.fail(this.withAuthenticationGuidance(accessResult.diagnostics, name, hasTerminal));\n }\n\n this.succeedOperational(\n 'auth',\n {\n action: 'auth',\n name,\n accessible: true,\n interactive: usedInteractivePrompt,\n },\n `Registry \"${name}\" is accessible with the current system Git credentials.`,\n accessResult.diagnostics,\n );\n return 0;\n }\n\n private async executeRefresh(config: ConfigInstance): Promise<number> {\n if (this.options.scope) {\n return this.fail([createParseErrorDiagnostic('registry refresh does not accept --global or --local.')]);\n }\n\n const name = this.resolveRegistryName(config);\n if (!name) return 1;\n const registryResult = this.root.registryCore.getOrCreateRegistry(name);\n if (!registryResult.ok) return this.fail(registryResult.diagnostics);\n\n const refreshResult = await registryResult.value.ensureUpToDate({\n bypassFreshnessCheck: true,\n logicalRegistryName: name,\n });\n if (!refreshResult.ok) return this.fail(refreshResult.diagnostics);\n if (refreshResult.value === 'Failed') {\n const diagnostics =\n refreshResult.diagnostics.length > 0\n ? refreshResult.diagnostics\n : [createParseErrorDiagnostic(`Registry \"${name}\" could not be refreshed.`)];\n return this.fail(diagnostics);\n }\n\n this.succeedOperational(\n 'refresh',\n { action: 'refresh', name, result: refreshResult.value },\n `Registry \"${name}\" refreshed.`,\n refreshResult.diagnostics,\n );\n return 0;\n }\n\n private resolveRegistryName(config: ConfigInstance): string | undefined {\n const candidate = this.options.name ?? config.get('registry');\n if (typeof candidate !== 'string' || candidate.trim().length === 0) {\n this.fail([\n createParseErrorDiagnostic(\n `registry ${this.options.action} requires a registry alias or a selected default registry.`,\n ),\n ]);\n return undefined;\n }\n return candidate.trim();\n }\n\n private withAuthenticationGuidance(\n diagnostics: readonly Diagnostic[],\n name: string,\n interactiveTerminalAvailable: boolean,\n ): readonly Diagnostic[] {\n return diagnostics.map((diagnostic) => ({\n ...diagnostic,\n message: `Git could not access registry \"${name}\".`,\n hint: interactiveTerminalAvailable\n ? 'Configure access with a system Git credential helper, SSH key/agent, or deploy key, then retry.'\n : `No interactive terminal is available. Configure a system Git credential helper, GIT_ASKPASS, SSH key/agent, or CI deploy key, then retry 'uapkg registry auth ${name}'.`,\n }));\n }\n\n private resolveRef(): { type: 'branch' | 'tag' | 'rev'; value: string } {\n const type = this.options.refType ?? 'branch';\n const value = this.options.refValue ?? 'main';\n return { type, value };\n }\n\n private scopeOptions(): { scope?: UAPKGConfigScope } {\n return this.options.scope ? { scope: this.options.scope } : {};\n }\n\n private persistPlan(filePath: string, values: Record<string, unknown>): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, `${JSON.stringify(values, null, 2)}\\n`, 'utf8');\n }\n\n private fail(diagnostics: readonly Diagnostic[]): number {\n if (this.options.output === 'json') {\n this.root.json.emit({\n status: 'error',\n command: `registry ${this.options.action}`,\n diagnostics: [...this.configDiagnostics, ...diagnostics],\n });\n } else {\n this.root.diagnostics.reportAll(diagnostics);\n }\n return 1;\n }\n\n private reportIfText(diagnostics: readonly Diagnostic[]): void {\n if (this.options.output === 'text') {\n this.root.diagnostics.reportAll(diagnostics);\n }\n }\n\n private succeedOperational(\n action: 'auth' | 'refresh',\n data: Record<string, unknown>,\n text: string,\n diagnostics: readonly Diagnostic[],\n ): void {\n if (this.options.output === 'json') {\n this.root.json.emit({\n status: 'ok',\n command: `registry ${action}`,\n data,\n diagnostics: [...this.configDiagnostics, ...diagnostics],\n });\n return;\n }\n\n this.root.diagnostics.reportAll(diagnostics);\n process.stdout.write(`${text}\\n`);\n }\n\n private print(value: unknown): void {\n if (this.options.output === 'json' || typeof value === 'object') {\n Log.info(JSON.stringify(value, null, 2));\n return;\n }\n Log.info(JSON.stringify(value));\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"RemoveCommand.js","names":[],"sources":["../../src/commands/RemoveCommand.ts"],"sourcesContent":["import type { CompositionRoot } from '../app/CompositionRoot.js';\nimport type { Command } from './Command.js';\nimport { InstallCommand } from './InstallCommand.js';\n\nexport interface RemoveCommandOptions {\n readonly packageName: string;\n readonly outputFormat: 'text' | 'json';\n readonly dryRun?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// RemoveCommand — removes a dependency from every bucket in the manifest and\n// then immediately re-runs `InstallCommand` so on-disk state is reconciled.\n//\n// The installer's plan diff is what actually deletes the installed plugin —\n// RemoveCommand's job is (1) mutate the manifest, (2) trigger the install.\n// ---------------------------------------------------------------------------\nexport class RemoveCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: RemoveCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n const result = await this.root.packageManifest.removeDependency(this.options.packageName);\n\n if (!result.ok) {\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({ status: 'error', command: 'remove', diagnostics: result.diagnostics });\n } else {\n this.root.diagnostics.reportAll(result.diagnostics);\n }\n return 1;\n }\n\n const missing = result.diagnostics.some((diagnostic) => diagnostic.code === 'DEPENDENCY_NOT_FOUND');\n\n if (result.diagnostics.length > 0 && this.options.outputFormat === 'text') {\n this.root.diagnostics.reportAll(result.diagnostics);\n }\n\n if (missing) {\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({\n status: 'ok',\n command: 'remove',\n data: { removed: false, packageName: this.options.packageName },\n diagnostics: result.diagnostics,\n });\n }\n return 0;\n }\n\n if (this.options.outputFormat === 'text') {\n process.stdout.write(`Removed \"${this.options.packageName}\" from uapkg.json\\n`);\n }\n\n // Reconcile on-disk state by delegating to the installer pipeline.\n const install = new InstallCommand(this.root, {\n force: false,\n frozen: false,\n dryRun: this.options.dryRun === true,\n outputFormat: this.options.outputFormat,\n });\n return install.execute();\n }\n}\n"],"mappings":";;;AAiBA,IAAa,gBAAb,MAA8C;CAEzB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,MAAM,SAAS,MAAM,KAAK,KAAK,gBAAgB,iBAAiB,KAAK,QAAQ,WAAW;EAExF,IAAI,CAAC,OAAO,IAAI;GACd,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,KAAK;IAAE,QAAQ;IAAS,SAAS;IAAU,aAAa,OAAO;GAAY,CAAC;QAE3F,KAAK,KAAK,YAAY,UAAU,OAAO,WAAW;GAEpD,OAAO;EACT;EAEA,MAAM,UAAU,OAAO,YAAY,MAAM,eAAe,WAAW,SAAS,sBAAsB;EAElG,IAAI,OAAO,YAAY,SAAS,KAAK,KAAK,QAAQ,iBAAiB,QACjE,KAAK,KAAK,YAAY,UAAU,OAAO,WAAW;EAGpD,IAAI,SAAS;GACX,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,KAAK;IAClB,QAAQ;IACR,SAAS;IACT,MAAM;KAAE,SAAS;KAAO,aAAa,KAAK,QAAQ;IAAY;IAC9D,aAAa,OAAO;GACtB,CAAC;GAEH,OAAO;EACT;EAEA,IAAI,KAAK,QAAQ,iBAAiB,QAChC,QAAQ,OAAO,MAAM,YAAY,KAAK,QAAQ,YAAY,oBAAoB;EAUhF,OAAO,IANa,eAAe,KAAK,MAAM;GAC5C,OAAO;GACP,QAAQ;GACR,QAAQ,KAAK,QAAQ,WAAW;GAChC,cAAc,KAAK,QAAQ;EAC7B,CACa,CAAC,CAAC,QAAQ;CACzB;AACF"}
1
+ {"version":3,"file":"RemoveCommand.js","names":[],"sources":["../../src/commands/RemoveCommand.ts"],"sourcesContent":["import type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\nimport type { Command } from '#cli/commands/Command.ts';\nimport { InstallCommand } from '#cli/commands/InstallCommand.ts';\n\nexport interface RemoveCommandOptions {\n readonly packageName: string;\n readonly outputFormat: 'text' | 'json';\n readonly dryRun?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// RemoveCommand — removes a dependency from every bucket in the manifest and\n// then immediately re-runs `InstallCommand` so on-disk state is reconciled.\n//\n// The installer's plan diff is what actually deletes the installed plugin —\n// RemoveCommand's job is (1) mutate the manifest, (2) trigger the install.\n// ---------------------------------------------------------------------------\nexport class RemoveCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: RemoveCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n const result = await this.root.packageManifest.removeDependency(this.options.packageName);\n\n if (!result.ok) {\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({ status: 'error', command: 'remove', diagnostics: result.diagnostics });\n } else {\n this.root.diagnostics.reportAll(result.diagnostics);\n }\n return 1;\n }\n\n const missing = result.diagnostics.some((diagnostic) => diagnostic.code === 'DEPENDENCY_NOT_FOUND');\n\n if (result.diagnostics.length > 0 && this.options.outputFormat === 'text') {\n this.root.diagnostics.reportAll(result.diagnostics);\n }\n\n if (missing) {\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({\n status: 'ok',\n command: 'remove',\n data: { removed: false, packageName: this.options.packageName },\n diagnostics: result.diagnostics,\n });\n }\n return 0;\n }\n\n if (this.options.outputFormat === 'text') {\n process.stdout.write(`Removed \"${this.options.packageName}\" from uapkg.json\\n`);\n }\n\n // Reconcile on-disk state by delegating to the installer pipeline.\n const install = new InstallCommand(this.root, {\n force: false,\n frozen: false,\n dryRun: this.options.dryRun === true,\n outputFormat: this.options.outputFormat,\n });\n return install.execute();\n }\n}\n"],"mappings":";;;AAiBA,IAAa,gBAAb,MAA8C;CAEzB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,MAAM,SAAS,MAAM,KAAK,KAAK,gBAAgB,iBAAiB,KAAK,QAAQ,WAAW;EAExF,IAAI,CAAC,OAAO,IAAI;GACd,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,KAAK;IAAE,QAAQ;IAAS,SAAS;IAAU,aAAa,OAAO;GAAY,CAAC;QAE3F,KAAK,KAAK,YAAY,UAAU,OAAO,WAAW;GAEpD,OAAO;EACT;EAEA,MAAM,UAAU,OAAO,YAAY,MAAM,eAAe,WAAW,SAAS,sBAAsB;EAElG,IAAI,OAAO,YAAY,SAAS,KAAK,KAAK,QAAQ,iBAAiB,QACjE,KAAK,KAAK,YAAY,UAAU,OAAO,WAAW;EAGpD,IAAI,SAAS;GACX,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,KAAK;IAClB,QAAQ;IACR,SAAS;IACT,MAAM;KAAE,SAAS;KAAO,aAAa,KAAK,QAAQ;IAAY;IAC9D,aAAa,OAAO;GACtB,CAAC;GAEH,OAAO;EACT;EAEA,IAAI,KAAK,QAAQ,iBAAiB,QAChC,QAAQ,OAAO,MAAM,YAAY,KAAK,QAAQ,YAAY,oBAAoB;EAUhF,OAAO,IANa,eAAe,KAAK,MAAM;GAC5C,OAAO;GACP,QAAQ;GACR,QAAQ,KAAK,QAAQ,WAAW;GAChC,cAAc,KAAK,QAAQ;EAC7B,CACa,CAAC,CAAC,QAAQ;CACzB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"RequestsCommand.js","names":[],"sources":["../../src/commands/RequestsCommand.ts"],"sourcesContent":["import type { CompositionRoot } from '../app/CompositionRoot.js';\nimport type { UAPKGOutputFormat } from '../cli/UAPKGCommandLine.js';\nimport { describeControlPlaneError } from '../control-plane/AccountManager.js';\nimport { ControlPlaneClient } from '../control-plane/ControlPlaneClient.js';\nimport {\n ControlPlaneError,\n type RegistryRequestDetail,\n type RegistryRequestStatus,\n} from '../control-plane/ControlPlaneTypes.js';\nimport {\n formatRegistryRequestTerminal,\n isRegistryRequestSuccessStatus,\n isRegistryRequestTerminalStatus,\n} from '../reporting/RegistryRequestTerminalFormatter.js';\nimport type { Command } from './Command.js';\n\nexport interface RequestsCommandOptions {\n readonly action: 'list' | 'status';\n readonly requestId?: string;\n readonly registry?: string;\n readonly status?: RegistryRequestStatus;\n readonly watch: boolean;\n readonly outputFormat: UAPKGOutputFormat;\n}\n\nexport class RequestsCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: RequestsCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n try {\n const trust = await this.root.registryTrustResolver.resolve(this.options.registry);\n let authentication = await this.root.accountManager.getAccessCredential(trust, ['publishing.request.read.self']);\n const client = new ControlPlaneClient(trust.apiBaseUrl);\n\n if (this.options.action === 'list') {\n const requests = await client.listRegistryRequests(\n authentication.credential,\n trust.registryId,\n this.options.status,\n );\n this.printList(requests, trust.alias);\n return 0;\n }\n\n if (!this.options.requestId) throw new Error('`uapkg requests status` requires a request ID.');\n let detail = await client.getRegistryRequestDetail(authentication.credential, this.options.requestId);\n if (this.options.watch) {\n let lastStatus = '';\n while (!isRegistryRequestTerminalStatus(detail.request.status)) {\n if (this.options.outputFormat === 'text' && detail.request.status !== lastStatus) {\n process.stdout.write(\n `${detail.request.id}: ${detail.request.status}${detail.request.currentStep ? ` (${detail.request.currentStep})` : ''}\\n`,\n );\n lastStatus = detail.request.status;\n }\n await delay(2_000);\n try {\n detail = await client.getRegistryRequestDetail(authentication.credential, this.options.requestId);\n } catch (error) {\n if (!(error instanceof ControlPlaneError) || error.status !== 401) throw error;\n this.root.accountManager.invalidateAccessCredentials(trust);\n authentication = await this.root.accountManager.getAccessCredential(trust, [\n 'publishing.request.read.self',\n ]);\n detail = await client.getRegistryRequestDetail(authentication.credential, this.options.requestId);\n }\n }\n }\n this.printRequest(detail, trust.alias);\n return isRegistryRequestSuccessStatus(detail.request.status) ||\n !isRegistryRequestTerminalStatus(detail.request.status)\n ? 0\n : 1;\n } catch (error) {\n process.stderr.write(`${describeControlPlaneError(error)}\\n`);\n return 1;\n }\n }\n\n private printList(requests: readonly unknown[], registryAlias: string): void {\n if (this.options.outputFormat === 'json') {\n process.stdout.write(`${JSON.stringify({ ok: true, registry: registryAlias, requests })}\\n`);\n return;\n }\n if (requests.length === 0) {\n process.stdout.write(`No publishing requests found for \"${registryAlias}\".\\n`);\n return;\n }\n for (const value of requests as Array<{\n id: string;\n status: string;\n kind: string;\n payload?: { packageName?: string; packageVersion?: string };\n }>) {\n const packageCoordinate = value.payload?.packageName\n ? ` ${value.payload.packageName}${value.payload.packageVersion ? `@${value.payload.packageVersion}` : ''}`\n : '';\n process.stdout.write(`${value.id} ${value.status} ${value.kind}${packageCoordinate}\\n`);\n }\n }\n\n private printRequest(detail: RegistryRequestDetail, registryAlias: string): void {\n const output = formatRegistryRequestTerminal({\n detail,\n registryAlias,\n outputFormat: this.options.outputFormat,\n presentation: { kind: 'status' },\n });\n process.stdout.write(output.stdout);\n }\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"mappings":";;;;;;AAyBA,IAAa,kBAAb,MAAgD;CAE3B;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,KAAK,sBAAsB,QAAQ,KAAK,QAAQ,QAAQ;GACjF,IAAI,iBAAiB,MAAM,KAAK,KAAK,eAAe,oBAAoB,OAAO,CAAC,8BAA8B,CAAC;GAC/G,MAAM,SAAS,IAAI,mBAAmB,MAAM,UAAU;GAEtD,IAAI,KAAK,QAAQ,WAAW,QAAQ;IAClC,MAAM,WAAW,MAAM,OAAO,qBAC5B,eAAe,YACf,MAAM,YACN,KAAK,QAAQ,MACf;IACA,KAAK,UAAU,UAAU,MAAM,KAAK;IACpC,OAAO;GACT;GAEA,IAAI,CAAC,KAAK,QAAQ,WAAW,MAAM,IAAI,MAAM,gDAAgD;GAC7F,IAAI,SAAS,MAAM,OAAO,yBAAyB,eAAe,YAAY,KAAK,QAAQ,SAAS;GACpG,IAAI,KAAK,QAAQ,OAAO;IACtB,IAAI,aAAa;IACjB,OAAO,CAAC,gCAAgC,OAAO,QAAQ,MAAM,GAAG;KAC9D,IAAI,KAAK,QAAQ,iBAAiB,UAAU,OAAO,QAAQ,WAAW,YAAY;MAChF,QAAQ,OAAO,MACb,GAAG,OAAO,QAAQ,GAAG,IAAI,OAAO,QAAQ,SAAS,OAAO,QAAQ,cAAc,KAAK,OAAO,QAAQ,YAAY,KAAK,GAAG,GACxH;MACA,aAAa,OAAO,QAAQ;KAC9B;KACA,MAAM,MAAM,GAAK;KACjB,IAAI;MACF,SAAS,MAAM,OAAO,yBAAyB,eAAe,YAAY,KAAK,QAAQ,SAAS;KAClG,SAAS,OAAO;MACd,IAAI,EAAE,iBAAiB,sBAAsB,MAAM,WAAW,KAAK,MAAM;MACzE,KAAK,KAAK,eAAe,4BAA4B,KAAK;MAC1D,iBAAiB,MAAM,KAAK,KAAK,eAAe,oBAAoB,OAAO,CACzE,8BACF,CAAC;MACD,SAAS,MAAM,OAAO,yBAAyB,eAAe,YAAY,KAAK,QAAQ,SAAS;KAClG;IACF;GACF;GACA,KAAK,aAAa,QAAQ,MAAM,KAAK;GACrC,OAAO,+BAA+B,OAAO,QAAQ,MAAM,KACzD,CAAC,gCAAgC,OAAO,QAAQ,MAAM,IACpD,IACA;EACN,SAAS,OAAO;GACd,QAAQ,OAAO,MAAM,GAAG,0BAA0B,KAAK,EAAE,GAAG;GAC5D,OAAO;EACT;CACF;CAEA,AAAQ,UAAU,UAA8B,eAA6B;EAC3E,IAAI,KAAK,QAAQ,iBAAiB,QAAQ;GACxC,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU;IAAE,IAAI;IAAM,UAAU;IAAe;GAAS,CAAC,EAAE,GAAG;GAC3F;EACF;EACA,IAAI,SAAS,WAAW,GAAG;GACzB,QAAQ,OAAO,MAAM,qCAAqC,cAAc,KAAK;GAC7E;EACF;EACA,KAAK,MAAM,SAAS,UAKhB;GACF,MAAM,oBAAoB,MAAM,SAAS,cACrC,IAAI,MAAM,QAAQ,cAAc,MAAM,QAAQ,iBAAiB,IAAI,MAAM,QAAQ,mBAAmB,OACpG;GACJ,QAAQ,OAAO,MAAM,GAAG,MAAM,GAAG,GAAG,MAAM,OAAO,GAAG,MAAM,OAAO,kBAAkB,GAAG;EACxF;CACF;CAEA,AAAQ,aAAa,QAA+B,eAA6B;EAC/E,MAAM,SAAS,8BAA8B;GAC3C;GACA;GACA,cAAc,KAAK,QAAQ;GAC3B,cAAc,EAAE,MAAM,SAAS;EACjC,CAAC;EACD,QAAQ,OAAO,MAAM,OAAO,MAAM;CACpC;AACF;AAEA,SAAS,MAAM,cAAqC;CAClD,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,YAAY,CAAC;AACnE"}
1
+ {"version":3,"file":"RequestsCommand.js","names":[],"sources":["../../src/commands/RequestsCommand.ts"],"sourcesContent":["import type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\nimport type { UAPKGOutputFormat } from '#cli/cli/UAPKGCommandLine.ts';\nimport { describeControlPlaneError } from '#cli/control-plane/AccountManager.ts';\nimport { ControlPlaneClient } from '#cli/control-plane/ControlPlaneClient.ts';\nimport {\n ControlPlaneError,\n type RegistryRequestDetail,\n type RegistryRequestStatus,\n} from '#cli/control-plane/ControlPlaneTypes.ts';\nimport {\n formatRegistryRequestTerminal,\n isRegistryRequestSuccessStatus,\n isRegistryRequestTerminalStatus,\n} from '#cli/reporting/RegistryRequestTerminalFormatter.ts';\nimport type { Command } from '#cli/commands/Command.ts';\n\nexport interface RequestsCommandOptions {\n readonly action: 'list' | 'status';\n readonly requestId?: string;\n readonly registry?: string;\n readonly status?: RegistryRequestStatus;\n readonly watch: boolean;\n readonly outputFormat: UAPKGOutputFormat;\n}\n\nexport class RequestsCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: RequestsCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n try {\n const trust = await this.root.registryTrustResolver.resolve(this.options.registry);\n let authentication = await this.root.accountManager.getAccessCredential(trust, ['publishing.request.read.self']);\n const client = new ControlPlaneClient(trust.apiBaseUrl);\n\n if (this.options.action === 'list') {\n const requests = await client.listRegistryRequests(\n authentication.credential,\n trust.registryId,\n this.options.status,\n );\n this.printList(requests, trust.alias);\n return 0;\n }\n\n if (!this.options.requestId) throw new Error('`uapkg requests status` requires a request ID.');\n let detail = await client.getRegistryRequestDetail(authentication.credential, this.options.requestId);\n if (this.options.watch) {\n let lastStatus = '';\n while (!isRegistryRequestTerminalStatus(detail.request.status)) {\n if (this.options.outputFormat === 'text' && detail.request.status !== lastStatus) {\n process.stdout.write(\n `${detail.request.id}: ${detail.request.status}${detail.request.currentStep ? ` (${detail.request.currentStep})` : ''}\\n`,\n );\n lastStatus = detail.request.status;\n }\n await delay(2_000);\n try {\n detail = await client.getRegistryRequestDetail(authentication.credential, this.options.requestId);\n } catch (error) {\n if (!(error instanceof ControlPlaneError) || error.status !== 401) throw error;\n this.root.accountManager.invalidateAccessCredentials(trust);\n authentication = await this.root.accountManager.getAccessCredential(trust, [\n 'publishing.request.read.self',\n ]);\n detail = await client.getRegistryRequestDetail(authentication.credential, this.options.requestId);\n }\n }\n }\n this.printRequest(detail, trust.alias);\n return isRegistryRequestSuccessStatus(detail.request.status) ||\n !isRegistryRequestTerminalStatus(detail.request.status)\n ? 0\n : 1;\n } catch (error) {\n process.stderr.write(`${describeControlPlaneError(error)}\\n`);\n return 1;\n }\n }\n\n private printList(requests: readonly unknown[], registryAlias: string): void {\n if (this.options.outputFormat === 'json') {\n process.stdout.write(`${JSON.stringify({ ok: true, registry: registryAlias, requests })}\\n`);\n return;\n }\n if (requests.length === 0) {\n process.stdout.write(`No publishing requests found for \"${registryAlias}\".\\n`);\n return;\n }\n for (const value of requests as Array<{\n id: string;\n status: string;\n kind: string;\n payload?: { packageName?: string; packageVersion?: string };\n }>) {\n const packageCoordinate = value.payload?.packageName\n ? ` ${value.payload.packageName}${value.payload.packageVersion ? `@${value.payload.packageVersion}` : ''}`\n : '';\n process.stdout.write(`${value.id} ${value.status} ${value.kind}${packageCoordinate}\\n`);\n }\n }\n\n private printRequest(detail: RegistryRequestDetail, registryAlias: string): void {\n const output = formatRegistryRequestTerminal({\n detail,\n registryAlias,\n outputFormat: this.options.outputFormat,\n presentation: { kind: 'status' },\n });\n process.stdout.write(output.stdout);\n }\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n"],"mappings":";;;;;;AAyBA,IAAa,kBAAb,MAAgD;CAE3B;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,KAAK,sBAAsB,QAAQ,KAAK,QAAQ,QAAQ;GACjF,IAAI,iBAAiB,MAAM,KAAK,KAAK,eAAe,oBAAoB,OAAO,CAAC,8BAA8B,CAAC;GAC/G,MAAM,SAAS,IAAI,mBAAmB,MAAM,UAAU;GAEtD,IAAI,KAAK,QAAQ,WAAW,QAAQ;IAClC,MAAM,WAAW,MAAM,OAAO,qBAC5B,eAAe,YACf,MAAM,YACN,KAAK,QAAQ,MACf;IACA,KAAK,UAAU,UAAU,MAAM,KAAK;IACpC,OAAO;GACT;GAEA,IAAI,CAAC,KAAK,QAAQ,WAAW,MAAM,IAAI,MAAM,gDAAgD;GAC7F,IAAI,SAAS,MAAM,OAAO,yBAAyB,eAAe,YAAY,KAAK,QAAQ,SAAS;GACpG,IAAI,KAAK,QAAQ,OAAO;IACtB,IAAI,aAAa;IACjB,OAAO,CAAC,gCAAgC,OAAO,QAAQ,MAAM,GAAG;KAC9D,IAAI,KAAK,QAAQ,iBAAiB,UAAU,OAAO,QAAQ,WAAW,YAAY;MAChF,QAAQ,OAAO,MACb,GAAG,OAAO,QAAQ,GAAG,IAAI,OAAO,QAAQ,SAAS,OAAO,QAAQ,cAAc,KAAK,OAAO,QAAQ,YAAY,KAAK,GAAG,GACxH;MACA,aAAa,OAAO,QAAQ;KAC9B;KACA,MAAM,MAAM,GAAK;KACjB,IAAI;MACF,SAAS,MAAM,OAAO,yBAAyB,eAAe,YAAY,KAAK,QAAQ,SAAS;KAClG,SAAS,OAAO;MACd,IAAI,EAAE,iBAAiB,sBAAsB,MAAM,WAAW,KAAK,MAAM;MACzE,KAAK,KAAK,eAAe,4BAA4B,KAAK;MAC1D,iBAAiB,MAAM,KAAK,KAAK,eAAe,oBAAoB,OAAO,CACzE,8BACF,CAAC;MACD,SAAS,MAAM,OAAO,yBAAyB,eAAe,YAAY,KAAK,QAAQ,SAAS;KAClG;IACF;GACF;GACA,KAAK,aAAa,QAAQ,MAAM,KAAK;GACrC,OAAO,+BAA+B,OAAO,QAAQ,MAAM,KACzD,CAAC,gCAAgC,OAAO,QAAQ,MAAM,IACpD,IACA;EACN,SAAS,OAAO;GACd,QAAQ,OAAO,MAAM,GAAG,0BAA0B,KAAK,EAAE,GAAG;GAC5D,OAAO;EACT;CACF;CAEA,AAAQ,UAAU,UAA8B,eAA6B;EAC3E,IAAI,KAAK,QAAQ,iBAAiB,QAAQ;GACxC,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU;IAAE,IAAI;IAAM,UAAU;IAAe;GAAS,CAAC,EAAE,GAAG;GAC3F;EACF;EACA,IAAI,SAAS,WAAW,GAAG;GACzB,QAAQ,OAAO,MAAM,qCAAqC,cAAc,KAAK;GAC7E;EACF;EACA,KAAK,MAAM,SAAS,UAKhB;GACF,MAAM,oBAAoB,MAAM,SAAS,cACrC,IAAI,MAAM,QAAQ,cAAc,MAAM,QAAQ,iBAAiB,IAAI,MAAM,QAAQ,mBAAmB,OACpG;GACJ,QAAQ,OAAO,MAAM,GAAG,MAAM,GAAG,GAAG,MAAM,OAAO,GAAG,MAAM,OAAO,kBAAkB,GAAG;EACxF;CACF;CAEA,AAAQ,aAAa,QAA+B,eAA6B;EAC/E,MAAM,SAAS,8BAA8B;GAC3C;GACA;GACA,cAAc,KAAK,QAAQ;GAC3B,cAAc,EAAE,MAAM,SAAS;EACjC,CAAC;EACD,QAAQ,OAAO,MAAM,OAAO,MAAM;CACpC;AACF;AAEA,SAAS,MAAM,cAAqC;CAClD,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,YAAY,CAAC;AACnE"}
@@ -1 +1 @@
1
- {"version":3,"file":"UpdateCommand.js","names":[],"sources":["../../src/commands/UpdateCommand.ts"],"sourcesContent":["import { parsePackageSpec } from '@uapkg/common';\nimport type { PackageName, VersionRange } from '@uapkg/common-schema';\nimport {\n createInvalidPackageSpecDiagnostic,\n createPackageNotFoundDiagnostic,\n type Diagnostic,\n} from '@uapkg/diagnostics';\nimport type { Dependency, Manifest } from '@uapkg/package-manifest-schema';\nimport type { CompositionRoot } from '../app/CompositionRoot.js';\nimport type { Command } from './Command.js';\nimport { InstallCommand } from './InstallCommand.js';\n\nexport interface UpdateCommandOptions {\n readonly specs: readonly string[];\n readonly force: boolean;\n readonly dryRun: boolean;\n readonly outputFormat: 'text' | 'json';\n}\n\ntype Bucket = 'dependencies' | 'devDependencies' | 'peerDependencies';\n\ninterface LocatedDependency {\n readonly bucket: Bucket;\n readonly registry: Dependency['registry'];\n}\n\n/**\n * `uapkg update [specs...]` — re-resolve and re-install.\n *\n * Modes:\n *\n * * `uapkg update` — full update (all packages).\n * * `uapkg update foo` — re-resolve `foo` via the\n * normal install flow; lockfile diff skips untouched packages.\n * * `uapkg update foo@^2.0.0` — rewrite `foo`'s range in the\n * manifest (preserving its bucket + registry) then re-install.\n * * `uapkg update foo@^2 @scope/bar@~1.5` — array form; each spec is\n * processed in order before a single install pass.\n *\n * Never throws — errors become diagnostics. Specs that reference unknown\n * packages produce `PACKAGE_NOT_FOUND` against the local manifest.\n */\nexport class UpdateCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: UpdateCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n if (this.options.specs.length === 0) {\n return this.delegateToInstall();\n }\n\n const manifestResult = await this.root.packageManifest.readManifest();\n if (!manifestResult.ok) return this.fail(manifestResult.diagnostics);\n\n const diagnostics: Diagnostic[] = [];\n for (const rawSpec of this.options.specs) {\n const applyResult = await this.applySpec(rawSpec, manifestResult.value);\n if (!applyResult.ok) diagnostics.push(...applyResult.diagnostics);\n }\n\n if (diagnostics.length > 0) return this.fail(diagnostics);\n\n return this.delegateToInstall();\n }\n\n /**\n * Parse a single `<name>[@range]` spec and, if a range is supplied, rewrite\n * the manifest entry preserving its existing bucket + registry. Bare-name\n * specs are a no-op at the manifest level — the subsequent install pass\n * handles the re-resolve.\n */\n private async applySpec(\n rawSpec: string,\n manifest: Manifest,\n ): Promise<{ ok: true } | { ok: false; diagnostics: Diagnostic[] }> {\n const specResult = parsePackageSpec(rawSpec);\n if (!specResult.ok) return { ok: false, diagnostics: [...specResult.diagnostics] };\n const spec = specResult.value;\n\n if (spec.org) {\n return {\n ok: false,\n diagnostics: [\n createInvalidPackageSpecDiagnostic(\n rawSpec,\n 'scoped specifiers (@org/name) are reserved for a future registry iteration',\n ),\n ],\n };\n }\n\n const located = this.locateDependency(manifest, spec.name as unknown as string);\n if (!located) {\n return {\n ok: false,\n diagnostics: [createPackageNotFoundDiagnostic(spec.name as unknown as PackageName, String(manifest.name))],\n };\n }\n\n if (!spec.range) return { ok: true };\n\n const addResult = await this.root.packageManifest.addDependency(\n spec.name as unknown as string,\n {\n version: spec.range as unknown as VersionRange,\n registry: located.registry,\n },\n { bucket: located.bucket },\n );\n if (!addResult.ok) return { ok: false, diagnostics: [...addResult.diagnostics] };\n return { ok: true };\n }\n\n /**\n * Find `name` in the manifest buckets, preserving the source-of-truth\n * bucket + registry so `applySpec` doesn't move the dep between buckets.\n */\n private locateDependency(manifest: Manifest, name: string): LocatedDependency | null {\n const order: Bucket[] = ['dependencies', 'devDependencies', 'peerDependencies'];\n for (const bucket of order) {\n const entries = manifest[bucket];\n if (entries && name in entries) {\n return { bucket, registry: entries[name].registry };\n }\n }\n return null;\n }\n\n private delegateToInstall(): Promise<number> {\n const install = new InstallCommand(this.root, {\n force: this.options.force,\n frozen: false,\n dryRun: this.options.dryRun,\n outputFormat: this.options.outputFormat,\n });\n return install.execute();\n }\n\n private fail(diagnostics: readonly Diagnostic[]): number {\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({ status: 'error', command: 'update', diagnostics });\n } else {\n this.root.diagnostics.reportAll(diagnostics);\n }\n return 1;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,gBAAb,MAA8C;CAEzB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,IAAI,KAAK,QAAQ,MAAM,WAAW,GAChC,OAAO,KAAK,kBAAkB;EAGhC,MAAM,iBAAiB,MAAM,KAAK,KAAK,gBAAgB,aAAa;EACpE,IAAI,CAAC,eAAe,IAAI,OAAO,KAAK,KAAK,eAAe,WAAW;EAEnE,MAAM,cAA4B,CAAC;EACnC,KAAK,MAAM,WAAW,KAAK,QAAQ,OAAO;GACxC,MAAM,cAAc,MAAM,KAAK,UAAU,SAAS,eAAe,KAAK;GACtE,IAAI,CAAC,YAAY,IAAI,YAAY,KAAK,GAAG,YAAY,WAAW;EAClE;EAEA,IAAI,YAAY,SAAS,GAAG,OAAO,KAAK,KAAK,WAAW;EAExD,OAAO,KAAK,kBAAkB;CAChC;;;;;;;CAQA,MAAc,UACZ,SACA,UACkE;EAClE,MAAM,aAAa,iBAAiB,OAAO;EAC3C,IAAI,CAAC,WAAW,IAAI,OAAO;GAAE,IAAI;GAAO,aAAa,CAAC,GAAG,WAAW,WAAW;EAAE;EACjF,MAAM,OAAO,WAAW;EAExB,IAAI,KAAK,KACP,OAAO;GACL,IAAI;GACJ,aAAa,CACX,mCACE,SACA,4EACF,CACF;EACF;EAGF,MAAM,UAAU,KAAK,iBAAiB,UAAU,KAAK,IAAyB;EAC9E,IAAI,CAAC,SACH,OAAO;GACL,IAAI;GACJ,aAAa,CAAC,gCAAgC,KAAK,MAAgC,OAAO,SAAS,IAAI,CAAC,CAAC;EAC3G;EAGF,IAAI,CAAC,KAAK,OAAO,OAAO,EAAE,IAAI,KAAK;EAEnC,MAAM,YAAY,MAAM,KAAK,KAAK,gBAAgB,cAChD,KAAK,MACL;GACE,SAAS,KAAK;GACd,UAAU,QAAQ;EACpB,GACA,EAAE,QAAQ,QAAQ,OAAO,CAC3B;EACA,IAAI,CAAC,UAAU,IAAI,OAAO;GAAE,IAAI;GAAO,aAAa,CAAC,GAAG,UAAU,WAAW;EAAE;EAC/E,OAAO,EAAE,IAAI,KAAK;CACpB;;;;;CAMA,AAAQ,iBAAiB,UAAoB,MAAwC;EAEnF,KAAK,MAAM,UAAU;GADI;GAAgB;GAAmB;EACnC,GAAG;GAC1B,MAAM,UAAU,SAAS;GACzB,IAAI,WAAW,QAAQ,SACrB,OAAO;IAAE;IAAQ,UAAU,QAAQ,KAAK,CAAC;GAAS;EAEtD;EACA,OAAO;CACT;CAEA,AAAQ,oBAAqC;EAO3C,OAAO,IANa,eAAe,KAAK,MAAM;GAC5C,OAAO,KAAK,QAAQ;GACpB,QAAQ;GACR,QAAQ,KAAK,QAAQ;GACrB,cAAc,KAAK,QAAQ;EAC7B,CACa,CAAC,CAAC,QAAQ;CACzB;CAEA,AAAQ,KAAK,aAA4C;EACvD,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,KAAK;GAAE,QAAQ;GAAS,SAAS;GAAU;EAAY,CAAC;OAEvE,KAAK,KAAK,YAAY,UAAU,WAAW;EAE7C,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"UpdateCommand.js","names":[],"sources":["../../src/commands/UpdateCommand.ts"],"sourcesContent":["import { parsePackageSpec } from '@uapkg/common';\nimport type { PackageName, VersionRange } from '@uapkg/common-schema';\nimport {\n createInvalidPackageSpecDiagnostic,\n createPackageNotFoundDiagnostic,\n type Diagnostic,\n} from '@uapkg/diagnostics';\nimport type { Dependency, Manifest } from '@uapkg/package-manifest-schema';\nimport type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\nimport type { Command } from '#cli/commands/Command.ts';\nimport { InstallCommand } from '#cli/commands/InstallCommand.ts';\n\nexport interface UpdateCommandOptions {\n readonly specs: readonly string[];\n readonly force: boolean;\n readonly dryRun: boolean;\n readonly outputFormat: 'text' | 'json';\n}\n\ntype Bucket = 'dependencies' | 'devDependencies' | 'peerDependencies';\n\ninterface LocatedDependency {\n readonly bucket: Bucket;\n readonly registry: Dependency['registry'];\n}\n\n/**\n * `uapkg update [specs...]` — re-resolve and re-install.\n *\n * Modes:\n *\n * * `uapkg update` — full update (all packages).\n * * `uapkg update foo` — re-resolve `foo` via the\n * normal install flow; lockfile diff skips untouched packages.\n * * `uapkg update foo@^2.0.0` — rewrite `foo`'s range in the\n * manifest (preserving its bucket + registry) then re-install.\n * * `uapkg update foo@^2 @scope/bar@~1.5` — array form; each spec is\n * processed in order before a single install pass.\n *\n * Never throws — errors become diagnostics. Specs that reference unknown\n * packages produce `PACKAGE_NOT_FOUND` against the local manifest.\n */\nexport class UpdateCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: UpdateCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n if (this.options.specs.length === 0) {\n return this.delegateToInstall();\n }\n\n const manifestResult = await this.root.packageManifest.readManifest();\n if (!manifestResult.ok) return this.fail(manifestResult.diagnostics);\n\n const diagnostics: Diagnostic[] = [];\n for (const rawSpec of this.options.specs) {\n const applyResult = await this.applySpec(rawSpec, manifestResult.value);\n if (!applyResult.ok) diagnostics.push(...applyResult.diagnostics);\n }\n\n if (diagnostics.length > 0) return this.fail(diagnostics);\n\n return this.delegateToInstall();\n }\n\n /**\n * Parse a single `<name>[@range]` spec and, if a range is supplied, rewrite\n * the manifest entry preserving its existing bucket + registry. Bare-name\n * specs are a no-op at the manifest level — the subsequent install pass\n * handles the re-resolve.\n */\n private async applySpec(\n rawSpec: string,\n manifest: Manifest,\n ): Promise<{ ok: true } | { ok: false; diagnostics: Diagnostic[] }> {\n const specResult = parsePackageSpec(rawSpec);\n if (!specResult.ok) return { ok: false, diagnostics: [...specResult.diagnostics] };\n const spec = specResult.value;\n\n if (spec.org) {\n return {\n ok: false,\n diagnostics: [\n createInvalidPackageSpecDiagnostic(\n rawSpec,\n 'scoped specifiers (@org/name) are reserved for a future registry iteration',\n ),\n ],\n };\n }\n\n const located = this.locateDependency(manifest, spec.name as unknown as string);\n if (!located) {\n return {\n ok: false,\n diagnostics: [createPackageNotFoundDiagnostic(spec.name as unknown as PackageName, String(manifest.name))],\n };\n }\n\n if (!spec.range) return { ok: true };\n\n const addResult = await this.root.packageManifest.addDependency(\n spec.name as unknown as string,\n {\n version: spec.range as unknown as VersionRange,\n registry: located.registry,\n },\n { bucket: located.bucket },\n );\n if (!addResult.ok) return { ok: false, diagnostics: [...addResult.diagnostics] };\n return { ok: true };\n }\n\n /**\n * Find `name` in the manifest buckets, preserving the source-of-truth\n * bucket + registry so `applySpec` doesn't move the dep between buckets.\n */\n private locateDependency(manifest: Manifest, name: string): LocatedDependency | null {\n const order: Bucket[] = ['dependencies', 'devDependencies', 'peerDependencies'];\n for (const bucket of order) {\n const entries = manifest[bucket];\n if (entries && name in entries) {\n return { bucket, registry: entries[name].registry };\n }\n }\n return null;\n }\n\n private delegateToInstall(): Promise<number> {\n const install = new InstallCommand(this.root, {\n force: this.options.force,\n frozen: false,\n dryRun: this.options.dryRun,\n outputFormat: this.options.outputFormat,\n });\n return install.execute();\n }\n\n private fail(diagnostics: readonly Diagnostic[]): number {\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({ status: 'error', command: 'update', diagnostics });\n } else {\n this.root.diagnostics.reportAll(diagnostics);\n }\n return 1;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,gBAAb,MAA8C;CAEzB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,IAAI,KAAK,QAAQ,MAAM,WAAW,GAChC,OAAO,KAAK,kBAAkB;EAGhC,MAAM,iBAAiB,MAAM,KAAK,KAAK,gBAAgB,aAAa;EACpE,IAAI,CAAC,eAAe,IAAI,OAAO,KAAK,KAAK,eAAe,WAAW;EAEnE,MAAM,cAA4B,CAAC;EACnC,KAAK,MAAM,WAAW,KAAK,QAAQ,OAAO;GACxC,MAAM,cAAc,MAAM,KAAK,UAAU,SAAS,eAAe,KAAK;GACtE,IAAI,CAAC,YAAY,IAAI,YAAY,KAAK,GAAG,YAAY,WAAW;EAClE;EAEA,IAAI,YAAY,SAAS,GAAG,OAAO,KAAK,KAAK,WAAW;EAExD,OAAO,KAAK,kBAAkB;CAChC;;;;;;;CAQA,MAAc,UACZ,SACA,UACkE;EAClE,MAAM,aAAa,iBAAiB,OAAO;EAC3C,IAAI,CAAC,WAAW,IAAI,OAAO;GAAE,IAAI;GAAO,aAAa,CAAC,GAAG,WAAW,WAAW;EAAE;EACjF,MAAM,OAAO,WAAW;EAExB,IAAI,KAAK,KACP,OAAO;GACL,IAAI;GACJ,aAAa,CACX,mCACE,SACA,4EACF,CACF;EACF;EAGF,MAAM,UAAU,KAAK,iBAAiB,UAAU,KAAK,IAAyB;EAC9E,IAAI,CAAC,SACH,OAAO;GACL,IAAI;GACJ,aAAa,CAAC,gCAAgC,KAAK,MAAgC,OAAO,SAAS,IAAI,CAAC,CAAC;EAC3G;EAGF,IAAI,CAAC,KAAK,OAAO,OAAO,EAAE,IAAI,KAAK;EAEnC,MAAM,YAAY,MAAM,KAAK,KAAK,gBAAgB,cAChD,KAAK,MACL;GACE,SAAS,KAAK;GACd,UAAU,QAAQ;EACpB,GACA,EAAE,QAAQ,QAAQ,OAAO,CAC3B;EACA,IAAI,CAAC,UAAU,IAAI,OAAO;GAAE,IAAI;GAAO,aAAa,CAAC,GAAG,UAAU,WAAW;EAAE;EAC/E,OAAO,EAAE,IAAI,KAAK;CACpB;;;;;CAMA,AAAQ,iBAAiB,UAAoB,MAAwC;EAEnF,KAAK,MAAM,UAAU;GADI;GAAgB;GAAmB;EACnC,GAAG;GAC1B,MAAM,UAAU,SAAS;GACzB,IAAI,WAAW,QAAQ,SACrB,OAAO;IAAE;IAAQ,UAAU,QAAQ,KAAK,CAAC;GAAS;EAEtD;EACA,OAAO;CACT;CAEA,AAAQ,oBAAqC;EAO3C,OAAO,IANa,eAAe,KAAK,MAAM;GAC5C,OAAO,KAAK,QAAQ;GACpB,QAAQ;GACR,QAAQ,KAAK,QAAQ;GACrB,cAAc,KAAK,QAAQ;EAC7B,CACa,CAAC,CAAC,QAAQ;CACzB;CAEA,AAAQ,KAAK,aAA4C;EACvD,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,KAAK;GAAE,QAAQ;GAAS,SAAS;GAAU;EAAY,CAAC;OAEvE,KAAK,KAAK,YAAY,UAAU,WAAW;EAE7C,OAAO;CACT;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"WhoamiCommand.js","names":[],"sources":["../../src/commands/WhoamiCommand.ts"],"sourcesContent":["import type { CompositionRoot } from '../app/CompositionRoot.js';\nimport type { UAPKGOutputFormat, UAPKGWhoamiField } from '../cli/UAPKGCommandLine.js';\nimport { controlPlaneDiagnosticForError, describeControlPlaneError } from '../control-plane/AccountManager.js';\nimport { ControlPlaneClient } from '../control-plane/ControlPlaneClient.js';\nimport type { Command } from './Command.js';\n\nexport interface WhoamiCommandOptions {\n readonly field?: UAPKGWhoamiField;\n readonly registry?: string;\n readonly outputFormat: UAPKGOutputFormat;\n}\n\nexport interface WhoamiCommandData {\n readonly account: {\n readonly id: string;\n readonly username: string;\n readonly displayName: string;\n };\n readonly registry: {\n readonly id: string;\n readonly name: string;\n readonly alias: string;\n };\n readonly deviceName: string;\n}\n\nexport interface WhoamiFieldData {\n readonly field: UAPKGWhoamiField;\n readonly value: string;\n}\n\nexport class WhoamiCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: WhoamiCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n try {\n const trust = await this.root.registryTrustResolver.resolve(this.options.registry);\n const access = await this.root.accountManager.getAccessCredential(trust, ['identity.self.read']);\n const self = await new ControlPlaneClient(trust.apiBaseUrl).getSelf(access.credential);\n if (self.registry.id !== trust.registryId || self.grant.id !== access.grant.grantId) {\n throw new Error('The control plane returned identity information for an unexpected registry grant.');\n }\n\n const data: WhoamiCommandData = {\n account: self.account,\n registry: { id: trust.registryId, name: trust.registryName, alias: trust.alias },\n deviceName: self.grant.deviceName,\n };\n\n if (this.options.field) {\n const fieldData: WhoamiFieldData = {\n field: this.options.field,\n value: selectedFieldValue(this.options.field, data),\n };\n if (this.options.outputFormat === 'json') {\n this.root.json.emitSuccess('whoami', fieldData);\n } else {\n process.stdout.write(`${fieldData.value}\\n`);\n }\n return 0;\n }\n\n if (this.options.outputFormat === 'json') {\n this.root.json.emitSuccess('whoami', data);\n } else {\n process.stdout.write(`Username: ${data.account.username}\\n`);\n process.stdout.write(`User ID: ${data.account.id}\\n`);\n process.stdout.write(`Display Name: ${data.account.displayName}\\n`);\n process.stdout.write(`Registry: ${data.registry.name}\\n`);\n process.stdout.write(`Registry ID: ${data.registry.id}\\n`);\n process.stdout.write(`Registry Alias: ${data.registry.alias}\\n`);\n process.stdout.write(`Device: ${data.deviceName}\\n`);\n }\n return 0;\n } catch (error) {\n if (this.options.outputFormat === 'json') {\n this.root.json.emitError('whoami', [controlPlaneDiagnosticForError(error, 'whoami')]);\n } else {\n process.stderr.write(`${describeControlPlaneError(error)}\\n`);\n }\n return 1;\n }\n }\n}\n\nfunction selectedFieldValue(field: UAPKGWhoamiField, data: WhoamiCommandData): string {\n switch (field) {\n case 'username':\n return data.account.username;\n case 'user-id':\n return data.account.id;\n case 'registry':\n return data.registry.name;\n case 'registry-id':\n return data.registry.id;\n default:\n return field satisfies never;\n }\n}\n"],"mappings":";;;;AA+BA,IAAa,gBAAb,MAA8C;CAEzB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,KAAK,sBAAsB,QAAQ,KAAK,QAAQ,QAAQ;GACjF,MAAM,SAAS,MAAM,KAAK,KAAK,eAAe,oBAAoB,OAAO,CAAC,oBAAoB,CAAC;GAC/F,MAAM,OAAO,MAAM,IAAI,mBAAmB,MAAM,UAAU,CAAC,CAAC,QAAQ,OAAO,UAAU;GACrF,IAAI,KAAK,SAAS,OAAO,MAAM,cAAc,KAAK,MAAM,OAAO,OAAO,MAAM,SAC1E,MAAM,IAAI,MAAM,mFAAmF;GAGrG,MAAM,OAA0B;IAC9B,SAAS,KAAK;IACd,UAAU;KAAE,IAAI,MAAM;KAAY,MAAM,MAAM;KAAc,OAAO,MAAM;IAAM;IAC/E,YAAY,KAAK,MAAM;GACzB;GAEA,IAAI,KAAK,QAAQ,OAAO;IACtB,MAAM,YAA6B;KACjC,OAAO,KAAK,QAAQ;KACpB,OAAO,mBAAmB,KAAK,QAAQ,OAAO,IAAI;IACpD;IACA,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,YAAY,UAAU,SAAS;SAE9C,QAAQ,OAAO,MAAM,GAAG,UAAU,MAAM,GAAG;IAE7C,OAAO;GACT;GAEA,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,YAAY,UAAU,IAAI;QACpC;IACL,QAAQ,OAAO,MAAM,aAAa,KAAK,QAAQ,SAAS,GAAG;IAC3D,QAAQ,OAAO,MAAM,YAAY,KAAK,QAAQ,GAAG,GAAG;IACpD,QAAQ,OAAO,MAAM,iBAAiB,KAAK,QAAQ,YAAY,GAAG;IAClE,QAAQ,OAAO,MAAM,aAAa,KAAK,SAAS,KAAK,GAAG;IACxD,QAAQ,OAAO,MAAM,gBAAgB,KAAK,SAAS,GAAG,GAAG;IACzD,QAAQ,OAAO,MAAM,mBAAmB,KAAK,SAAS,MAAM,GAAG;IAC/D,QAAQ,OAAO,MAAM,WAAW,KAAK,WAAW,GAAG;GACrD;GACA,OAAO;EACT,SAAS,OAAO;GACd,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,UAAU,UAAU,CAAC,+BAA+B,OAAO,QAAQ,CAAC,CAAC;QAEpF,QAAQ,OAAO,MAAM,GAAG,0BAA0B,KAAK,EAAE,GAAG;GAE9D,OAAO;EACT;CACF;AACF;AAEA,SAAS,mBAAmB,OAAyB,MAAiC;CACpF,QAAQ,OAAR;EACE,KAAK,YACH,OAAO,KAAK,QAAQ;EACtB,KAAK,WACH,OAAO,KAAK,QAAQ;EACtB,KAAK,YACH,OAAO,KAAK,SAAS;EACvB,KAAK,eACH,OAAO,KAAK,SAAS;EACvB,SACE,OAAO;CACX;AACF"}
1
+ {"version":3,"file":"WhoamiCommand.js","names":[],"sources":["../../src/commands/WhoamiCommand.ts"],"sourcesContent":["import type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\nimport type { UAPKGOutputFormat, UAPKGWhoamiField } from '#cli/cli/UAPKGCommandLine.ts';\nimport { controlPlaneDiagnosticForError, describeControlPlaneError } from '#cli/control-plane/AccountManager.ts';\nimport { ControlPlaneClient } from '#cli/control-plane/ControlPlaneClient.ts';\nimport type { Command } from '#cli/commands/Command.ts';\n\nexport interface WhoamiCommandOptions {\n readonly field?: UAPKGWhoamiField;\n readonly registry?: string;\n readonly outputFormat: UAPKGOutputFormat;\n}\n\nexport interface WhoamiCommandData {\n readonly account: {\n readonly id: string;\n readonly username: string;\n readonly displayName: string;\n };\n readonly registry: {\n readonly id: string;\n readonly name: string;\n readonly alias: string;\n };\n readonly deviceName: string;\n}\n\nexport interface WhoamiFieldData {\n readonly field: UAPKGWhoamiField;\n readonly value: string;\n}\n\nexport class WhoamiCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: WhoamiCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n try {\n const trust = await this.root.registryTrustResolver.resolve(this.options.registry);\n const access = await this.root.accountManager.getAccessCredential(trust, ['identity.self.read']);\n const self = await new ControlPlaneClient(trust.apiBaseUrl).getSelf(access.credential);\n if (self.registry.id !== trust.registryId || self.grant.id !== access.grant.grantId) {\n throw new Error('The control plane returned identity information for an unexpected registry grant.');\n }\n\n const data: WhoamiCommandData = {\n account: self.account,\n registry: { id: trust.registryId, name: trust.registryName, alias: trust.alias },\n deviceName: self.grant.deviceName,\n };\n\n if (this.options.field) {\n const fieldData: WhoamiFieldData = {\n field: this.options.field,\n value: selectedFieldValue(this.options.field, data),\n };\n if (this.options.outputFormat === 'json') {\n this.root.json.emitSuccess('whoami', fieldData);\n } else {\n process.stdout.write(`${fieldData.value}\\n`);\n }\n return 0;\n }\n\n if (this.options.outputFormat === 'json') {\n this.root.json.emitSuccess('whoami', data);\n } else {\n process.stdout.write(`Username: ${data.account.username}\\n`);\n process.stdout.write(`User ID: ${data.account.id}\\n`);\n process.stdout.write(`Display Name: ${data.account.displayName}\\n`);\n process.stdout.write(`Registry: ${data.registry.name}\\n`);\n process.stdout.write(`Registry ID: ${data.registry.id}\\n`);\n process.stdout.write(`Registry Alias: ${data.registry.alias}\\n`);\n process.stdout.write(`Device: ${data.deviceName}\\n`);\n }\n return 0;\n } catch (error) {\n if (this.options.outputFormat === 'json') {\n this.root.json.emitError('whoami', [controlPlaneDiagnosticForError(error, 'whoami')]);\n } else {\n process.stderr.write(`${describeControlPlaneError(error)}\\n`);\n }\n return 1;\n }\n }\n}\n\nfunction selectedFieldValue(field: UAPKGWhoamiField, data: WhoamiCommandData): string {\n switch (field) {\n case 'username':\n return data.account.username;\n case 'user-id':\n return data.account.id;\n case 'registry':\n return data.registry.name;\n case 'registry-id':\n return data.registry.id;\n default:\n return field satisfies never;\n }\n}\n"],"mappings":";;;;AA+BA,IAAa,gBAAb,MAA8C;CAEzB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,KAAK,sBAAsB,QAAQ,KAAK,QAAQ,QAAQ;GACjF,MAAM,SAAS,MAAM,KAAK,KAAK,eAAe,oBAAoB,OAAO,CAAC,oBAAoB,CAAC;GAC/F,MAAM,OAAO,MAAM,IAAI,mBAAmB,MAAM,UAAU,CAAC,CAAC,QAAQ,OAAO,UAAU;GACrF,IAAI,KAAK,SAAS,OAAO,MAAM,cAAc,KAAK,MAAM,OAAO,OAAO,MAAM,SAC1E,MAAM,IAAI,MAAM,mFAAmF;GAGrG,MAAM,OAA0B;IAC9B,SAAS,KAAK;IACd,UAAU;KAAE,IAAI,MAAM;KAAY,MAAM,MAAM;KAAc,OAAO,MAAM;IAAM;IAC/E,YAAY,KAAK,MAAM;GACzB;GAEA,IAAI,KAAK,QAAQ,OAAO;IACtB,MAAM,YAA6B;KACjC,OAAO,KAAK,QAAQ;KACpB,OAAO,mBAAmB,KAAK,QAAQ,OAAO,IAAI;IACpD;IACA,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,YAAY,UAAU,SAAS;SAE9C,QAAQ,OAAO,MAAM,GAAG,UAAU,MAAM,GAAG;IAE7C,OAAO;GACT;GAEA,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,YAAY,UAAU,IAAI;QACpC;IACL,QAAQ,OAAO,MAAM,aAAa,KAAK,QAAQ,SAAS,GAAG;IAC3D,QAAQ,OAAO,MAAM,YAAY,KAAK,QAAQ,GAAG,GAAG;IACpD,QAAQ,OAAO,MAAM,iBAAiB,KAAK,QAAQ,YAAY,GAAG;IAClE,QAAQ,OAAO,MAAM,aAAa,KAAK,SAAS,KAAK,GAAG;IACxD,QAAQ,OAAO,MAAM,gBAAgB,KAAK,SAAS,GAAG,GAAG;IACzD,QAAQ,OAAO,MAAM,mBAAmB,KAAK,SAAS,MAAM,GAAG;IAC/D,QAAQ,OAAO,MAAM,WAAW,KAAK,WAAW,GAAG;GACrD;GACA,OAAO;EACT,SAAS,OAAO;GACd,IAAI,KAAK,QAAQ,iBAAiB,QAChC,KAAK,KAAK,KAAK,UAAU,UAAU,CAAC,+BAA+B,OAAO,QAAQ,CAAC,CAAC;QAEpF,QAAQ,OAAO,MAAM,GAAG,0BAA0B,KAAK,EAAE,GAAG;GAE9D,OAAO;EACT;CACF;AACF;AAEA,SAAS,mBAAmB,OAAyB,MAAiC;CACpF,QAAQ,OAAR;EACE,KAAK,YACH,OAAO,KAAK,QAAQ;EACtB,KAAK,WACH,OAAO,KAAK,QAAQ;EACtB,KAAK,YACH,OAAO,KAAK,SAAS;EACvB,KAAK,eACH,OAAO,KAAK,SAAS;EACvB,SACE,OAAO;CACX;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"WhyCommand.js","names":[],"sources":["../../src/commands/WhyCommand.ts"],"sourcesContent":["import type { PackageName } from '@uapkg/common-schema';\nimport type { CompositionRoot } from '../app/CompositionRoot.js';\nimport type { Command } from './Command.js';\n\nexport interface WhyCommandOptions {\n readonly target: string;\n readonly outputFormat: 'text' | 'json';\n}\n\n/**\n * `uapkg why <name>` — prints every dependency path from a graph root to the\n * target package. Implemented as a pure consumer of\n * {@link PackageManifest.explainWhy}.\n *\n * Exit code 0 when the target is present, 3 when not found, 1 on any\n * resolver error.\n */\nexport class WhyCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: WhyCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n const target = this.options.target as PackageName;\n const result = await this.root.packageManifest.explainWhy(target);\n\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({\n status: result.ok ? 'ok' : 'error',\n command: 'why',\n data: result.ok ? result.value : undefined,\n diagnostics: result.diagnostics,\n });\n return result.ok ? (result.value.paths.length === 0 && !result.value.foundAsRoot ? 3 : 0) : 1;\n }\n\n this.root.diagnostics.reportAll(result.diagnostics);\n if (!result.ok) return 1;\n\n const { paths, foundAsRoot } = result.value;\n if (paths.length === 0 && !foundAsRoot) {\n process.stdout.write(`No installation of \"${target}\" in the resolved graph.\\n`);\n return 3;\n }\n if (foundAsRoot) {\n process.stdout.write(`${target} (declared at root)\\n`);\n }\n for (const p of paths) {\n const rendered = p.path.map((e) => `${e.name}@${e.version}`).join(' → ');\n process.stdout.write(` ${rendered}\\n`);\n }\n return 0;\n }\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,aAAb,MAA2C;CAEtB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,MAAM,SAAS,KAAK,QAAQ;EAC5B,MAAM,SAAS,MAAM,KAAK,KAAK,gBAAgB,WAAW,MAAM;EAEhE,IAAI,KAAK,QAAQ,iBAAiB,QAAQ;GACxC,KAAK,KAAK,KAAK,KAAK;IAClB,QAAQ,OAAO,KAAK,OAAO;IAC3B,SAAS;IACT,MAAM,OAAO,KAAK,OAAO,QAAQ;IACjC,aAAa,OAAO;GACtB,CAAC;GACD,OAAO,OAAO,KAAM,OAAO,MAAM,MAAM,WAAW,KAAK,CAAC,OAAO,MAAM,cAAc,IAAI,IAAK;EAC9F;EAEA,KAAK,KAAK,YAAY,UAAU,OAAO,WAAW;EAClD,IAAI,CAAC,OAAO,IAAI,OAAO;EAEvB,MAAM,EAAE,OAAO,gBAAgB,OAAO;EACtC,IAAI,MAAM,WAAW,KAAK,CAAC,aAAa;GACtC,QAAQ,OAAO,MAAM,uBAAuB,OAAO,2BAA2B;GAC9E,OAAO;EACT;EACA,IAAI,aACF,QAAQ,OAAO,MAAM,GAAG,OAAO,sBAAsB;EAEvD,KAAK,MAAM,KAAK,OAAO;GACrB,MAAM,WAAW,EAAE,KAAK,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS,CAAC,CAAC,KAAK,KAAK;GACvE,QAAQ,OAAO,MAAM,KAAK,SAAS,GAAG;EACxC;EACA,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"WhyCommand.js","names":[],"sources":["../../src/commands/WhyCommand.ts"],"sourcesContent":["import type { PackageName } from '@uapkg/common-schema';\nimport type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\nimport type { Command } from '#cli/commands/Command.ts';\n\nexport interface WhyCommandOptions {\n readonly target: string;\n readonly outputFormat: 'text' | 'json';\n}\n\n/**\n * `uapkg why <name>` — prints every dependency path from a graph root to the\n * target package. Implemented as a pure consumer of\n * {@link PackageManifest.explainWhy}.\n *\n * Exit code 0 when the target is present, 3 when not found, 1 on any\n * resolver error.\n */\nexport class WhyCommand implements Command {\n public constructor(\n private readonly root: CompositionRoot,\n private readonly options: WhyCommandOptions,\n ) {}\n\n public async execute(): Promise<number> {\n const target = this.options.target as PackageName;\n const result = await this.root.packageManifest.explainWhy(target);\n\n if (this.options.outputFormat === 'json') {\n this.root.json.emit({\n status: result.ok ? 'ok' : 'error',\n command: 'why',\n data: result.ok ? result.value : undefined,\n diagnostics: result.diagnostics,\n });\n return result.ok ? (result.value.paths.length === 0 && !result.value.foundAsRoot ? 3 : 0) : 1;\n }\n\n this.root.diagnostics.reportAll(result.diagnostics);\n if (!result.ok) return 1;\n\n const { paths, foundAsRoot } = result.value;\n if (paths.length === 0 && !foundAsRoot) {\n process.stdout.write(`No installation of \"${target}\" in the resolved graph.\\n`);\n return 3;\n }\n if (foundAsRoot) {\n process.stdout.write(`${target} (declared at root)\\n`);\n }\n for (const p of paths) {\n const rendered = p.path.map((e) => `${e.name}@${e.version}`).join(' → ');\n process.stdout.write(` ${rendered}\\n`);\n }\n return 0;\n }\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,aAAb,MAA2C;CAEtB;CACA;CAFnB,AAAO,YACL,AAAiB,MACjB,AAAiB,SACjB;EAFiB;EACA;CAChB;CAEH,MAAa,UAA2B;EACtC,MAAM,SAAS,KAAK,QAAQ;EAC5B,MAAM,SAAS,MAAM,KAAK,KAAK,gBAAgB,WAAW,MAAM;EAEhE,IAAI,KAAK,QAAQ,iBAAiB,QAAQ;GACxC,KAAK,KAAK,KAAK,KAAK;IAClB,QAAQ,OAAO,KAAK,OAAO;IAC3B,SAAS;IACT,MAAM,OAAO,KAAK,OAAO,QAAQ;IACjC,aAAa,OAAO;GACtB,CAAC;GACD,OAAO,OAAO,KAAM,OAAO,MAAM,MAAM,WAAW,KAAK,CAAC,OAAO,MAAM,cAAc,IAAI,IAAK;EAC9F;EAEA,KAAK,KAAK,YAAY,UAAU,OAAO,WAAW;EAClD,IAAI,CAAC,OAAO,IAAI,OAAO;EAEvB,MAAM,EAAE,OAAO,gBAAgB,OAAO;EACtC,IAAI,MAAM,WAAW,KAAK,CAAC,aAAa;GACtC,QAAQ,OAAO,MAAM,uBAAuB,OAAO,2BAA2B;GAC9E,OAAO;EACT;EACA,IAAI,aACF,QAAQ,OAAO,MAAM,GAAG,OAAO,sBAAsB;EAEvD,KAAK,MAAM,KAAK,OAAO;GACrB,MAAM,WAAW,EAAE,KAAK,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS,CAAC,CAAC,KAAK,KAAK;GACvE,QAAQ,OAAO,MAAM,KAAK,SAAS,GAAG;EACxC;EACA,OAAO;CACT;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"DependencyAddResolver.js","names":[],"sources":["../../../src/commands/add/DependencyAddResolver.ts"],"sourcesContent":["import type { PackageSpec, VersionRange } from '@uapkg/common-schema';\nimport { DEFAULT_REGISTRY_ALIAS, RegistryNameSchema, VersionRangeSchema } from '@uapkg/common-schema';\nimport { createRegistryNotFoundDiagnostic, fail, ok, type Result } from '@uapkg/diagnostics';\nimport type { Dependency } from '@uapkg/package-manifest-schema';\nimport type { CompositionRoot } from '../../app/CompositionRoot.js';\n\nexport interface ResolvedAddDependency {\n readonly dependency: Dependency;\n readonly resolvedVersion: string;\n}\n\n/**\n * Resolves an `add` request against the selected registry before mutating the\n * manifest, ensuring package and version existence.\n */\nexport class DependencyAddResolver {\n public constructor(private readonly root: CompositionRoot) {}\n\n public async resolve(spec: PackageSpec, registryNameInput?: string): Promise<Result<ResolvedAddDependency>> {\n const registryCandidate = registryNameInput ?? (this.root.config.get('registry') as string | null) ?? 'default';\n const registryNameResult = RegistryNameSchema.safeParse(registryCandidate);\n if (!registryNameResult.success) {\n return fail([createRegistryNotFoundDiagnostic(registryCandidate)]);\n }\n const registryName = registryNameResult.data;\n\n const registryResult = this.root.registryCore.getOrCreateRegistry(registryName);\n if (!registryResult.ok) return registryResult as Result<never>;\n\n const requestedRange = spec.range ?? ('*' as unknown as VersionRange);\n const resolution = await registryResult.value.resolvePackage(\n spec.name as unknown as string,\n requestedRange,\n registryName,\n );\n if (!resolution.ok) return resolution as Result<never>;\n\n const dependencyRange = spec.range ?? VersionRangeSchema.parse(`^${resolution.value.version}`);\n\n // Only an explicit non-default --registry is recorded; the default alias stays absent in the manifest.\n const recordedRegistry =\n registryNameInput !== undefined && registryName !== DEFAULT_REGISTRY_ALIAS ? registryName : undefined;\n\n return ok(\n {\n dependency: {\n version: dependencyRange,\n ...(recordedRegistry !== undefined ? { registry: recordedRegistry } : {}),\n },\n resolvedVersion: resolution.value.version,\n },\n resolution.diagnostics,\n );\n }\n}\n"],"mappings":";;;;;;;;AAeA,IAAa,wBAAb,MAAmC;CACG;CAApC,AAAO,YAAY,AAAiB,MAAuB;EAAvB;CAAwB;CAE5D,MAAa,QAAQ,MAAmB,mBAAoE;EAC1G,MAAM,oBAAoB,qBAAsB,KAAK,KAAK,OAAO,IAAI,UAAU,KAAuB;EACtG,MAAM,qBAAqB,mBAAmB,UAAU,iBAAiB;EACzE,IAAI,CAAC,mBAAmB,SACtB,OAAO,KAAK,CAAC,iCAAiC,iBAAiB,CAAC,CAAC;EAEnE,MAAM,eAAe,mBAAmB;EAExC,MAAM,iBAAiB,KAAK,KAAK,aAAa,oBAAoB,YAAY;EAC9E,IAAI,CAAC,eAAe,IAAI,OAAO;EAE/B,MAAM,iBAAiB,KAAK,SAAU;EACtC,MAAM,aAAa,MAAM,eAAe,MAAM,eAC5C,KAAK,MACL,gBACA,YACF;EACA,IAAI,CAAC,WAAW,IAAI,OAAO;EAE3B,MAAM,kBAAkB,KAAK,SAAS,mBAAmB,MAAM,IAAI,WAAW,MAAM,SAAS;EAG7F,MAAM,mBACJ,sBAAsB,UAAa,iBAAiB,yBAAyB,eAAe;EAE9F,OAAO,GACL;GACE,YAAY;IACV,SAAS;IACT,GAAI,qBAAqB,SAAY,EAAE,UAAU,iBAAiB,IAAI,CAAC;GACzE;GACA,iBAAiB,WAAW,MAAM;EACpC,GACA,WAAW,WACb;CACF;AACF"}
1
+ {"version":3,"file":"DependencyAddResolver.js","names":[],"sources":["../../../src/commands/add/DependencyAddResolver.ts"],"sourcesContent":["import type { PackageSpec, VersionRange } from '@uapkg/common-schema';\nimport { DEFAULT_REGISTRY_ALIAS, RegistryNameSchema, VersionRangeSchema } from '@uapkg/common-schema';\nimport { createRegistryNotFoundDiagnostic, fail, ok, type Result } from '@uapkg/diagnostics';\nimport type { Dependency } from '@uapkg/package-manifest-schema';\nimport type { CompositionRoot } from '#cli/app/CompositionRoot.ts';\n\nexport interface ResolvedAddDependency {\n readonly dependency: Dependency;\n readonly resolvedVersion: string;\n}\n\n/**\n * Resolves an `add` request against the selected registry before mutating the\n * manifest, ensuring package and version existence.\n */\nexport class DependencyAddResolver {\n public constructor(private readonly root: CompositionRoot) {}\n\n public async resolve(spec: PackageSpec, registryNameInput?: string): Promise<Result<ResolvedAddDependency>> {\n const registryCandidate = registryNameInput ?? (this.root.config.get('registry') as string | null) ?? 'default';\n const registryNameResult = RegistryNameSchema.safeParse(registryCandidate);\n if (!registryNameResult.success) {\n return fail([createRegistryNotFoundDiagnostic(registryCandidate)]);\n }\n const registryName = registryNameResult.data;\n\n const registryResult = this.root.registryCore.getOrCreateRegistry(registryName);\n if (!registryResult.ok) return registryResult as Result<never>;\n\n const requestedRange = spec.range ?? ('*' as unknown as VersionRange);\n const resolution = await registryResult.value.resolvePackage(\n spec.name as unknown as string,\n requestedRange,\n registryName,\n );\n if (!resolution.ok) return resolution as Result<never>;\n\n const dependencyRange = spec.range ?? VersionRangeSchema.parse(`^${resolution.value.version}`);\n\n // Only an explicit non-default --registry is recorded; the default alias stays absent in the manifest.\n const recordedRegistry =\n registryNameInput !== undefined && registryName !== DEFAULT_REGISTRY_ALIAS ? registryName : undefined;\n\n return ok(\n {\n dependency: {\n version: dependencyRange,\n ...(recordedRegistry !== undefined ? { registry: recordedRegistry } : {}),\n },\n resolvedVersion: resolution.value.version,\n },\n resolution.diagnostics,\n );\n }\n}\n"],"mappings":";;;;;;;;AAeA,IAAa,wBAAb,MAAmC;CACG;CAApC,AAAO,YAAY,AAAiB,MAAuB;EAAvB;CAAwB;CAE5D,MAAa,QAAQ,MAAmB,mBAAoE;EAC1G,MAAM,oBAAoB,qBAAsB,KAAK,KAAK,OAAO,IAAI,UAAU,KAAuB;EACtG,MAAM,qBAAqB,mBAAmB,UAAU,iBAAiB;EACzE,IAAI,CAAC,mBAAmB,SACtB,OAAO,KAAK,CAAC,iCAAiC,iBAAiB,CAAC,CAAC;EAEnE,MAAM,eAAe,mBAAmB;EAExC,MAAM,iBAAiB,KAAK,KAAK,aAAa,oBAAoB,YAAY;EAC9E,IAAI,CAAC,eAAe,IAAI,OAAO;EAE/B,MAAM,iBAAiB,KAAK,SAAU;EACtC,MAAM,aAAa,MAAM,eAAe,MAAM,eAC5C,KAAK,MACL,gBACA,YACF;EACA,IAAI,CAAC,WAAW,IAAI,OAAO;EAE3B,MAAM,kBAAkB,KAAK,SAAS,mBAAmB,MAAM,IAAI,WAAW,MAAM,SAAS;EAG7F,MAAM,mBACJ,sBAAsB,UAAa,iBAAiB,yBAAyB,eAAe;EAE9F,OAAO,GACL;GACE,YAAY;IACV,SAAS;IACT,GAAI,qBAAqB,SAAY,EAAE,UAAU,iBAAiB,IAAI,CAAC;GACzE;GACA,iBAAiB,WAAW,MAAM;EACpC,GACA,WAAW,WACb;CACF;AACF"}
@@ -713,7 +713,7 @@ function loginFinalizationTimeoutError(registryAlias) {
713
713
  function loginConfirmationAmbiguousError(registryAlias) {
714
714
  return new LoginError("LOGIN_FAILED", [
715
715
  "UAPKG could not determine whether the service activated this login.",
716
- "The locally saved credentials were kept to avoid orphaning a possibly active grant.",
716
+ "Your saved credentials were kept because this login may be active.",
717
717
  `Run \`uapkg whoami --registry ${registryAlias}\` to check the login before retrying.`
718
718
  ].join(" "));
719
719
  }