@dsh-workbench/shared 1.1.2 → 1.1.3

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.
@@ -2,11 +2,17 @@ export declare const MARKET_INDEX_FORMAT = 1;
2
2
  export declare const MARKET_INDEX_PATH = "market.json";
3
3
  export declare const MARKET_DISCOVER_ROUTE = "panels/market-discover";
4
4
  export declare const MARKET_DOC_ROUTE = "panels/market-doc";
5
+ export declare const MARKET_GIT_PROBE_ROUTE = "panels/git-probe";
5
6
  export declare const MARKET_PUBLISH_PREVIEW_ROUTE = "panels/market-publish-preview";
6
7
  export declare const MARKET_SOURCES_RESOURCE = "market-sources";
7
8
  export declare const MARKET_SOURCES_ROUTE = "panels/market-sources";
8
9
  export declare const MARKET_WORKBENCH_LABEL = "workbench";
9
10
  export type MarketSourceKind = 'http' | 'git';
11
+ export type GitProbeStatus = 'ok' | 'auth' | 'unreachable';
12
+ export interface GitProbePayload {
13
+ readonly status: GitProbeStatus;
14
+ readonly detail?: string;
15
+ }
10
16
  export type MarketSourcePolicy = 'artifacts-in-repo' | 'catalog-only';
11
17
  export interface IndexSourceSpec {
12
18
  readonly kind: MarketSourceKind;
@@ -2,6 +2,7 @@ export const MARKET_INDEX_FORMAT = 1;
2
2
  export const MARKET_INDEX_PATH = 'market.json';
3
3
  export const MARKET_DISCOVER_ROUTE = 'panels/market-discover';
4
4
  export const MARKET_DOC_ROUTE = 'panels/market-doc';
5
+ export const MARKET_GIT_PROBE_ROUTE = 'panels/git-probe';
5
6
  export const MARKET_PUBLISH_PREVIEW_ROUTE = 'panels/market-publish-preview';
6
7
  export const MARKET_SOURCES_RESOURCE = 'market-sources';
7
8
  export const MARKET_SOURCES_ROUTE = 'panels/market-sources';
package/dist/host.d.ts CHANGED
@@ -15,6 +15,7 @@ export * from './contract/long-task.js';
15
15
  export * from './lib/text.js';
16
16
  export * from './lib/ui.js';
17
17
  export * from './lib/board-fact.js';
18
+ export * from './lib/git-address.js';
18
19
  export * from './api/blocker-table.js';
19
20
  export * from './contract/unit-declaration.js';
20
21
  export * from './host/board-fact.js';
package/dist/host.js CHANGED
@@ -15,6 +15,7 @@ export * from './contract/long-task.js';
15
15
  export * from './lib/text.js';
16
16
  export * from './lib/ui.js';
17
17
  export * from './lib/board-fact.js';
18
+ export * from './lib/git-address.js';
18
19
  export * from './api/blocker-table.js';
19
20
  export * from './contract/unit-declaration.js';
20
21
  export * from './host/board-fact.js';
package/dist/i18n/en.js CHANGED
@@ -248,6 +248,7 @@ export const en = {
248
248
  'panels.market.add.failurePnpmMissing': 'pnpm was not found, cannot install',
249
249
  'panels.market.add.failureInstalled': 'It is already installed in this workbench. The same package cannot be installed over itself: uninstall it first, then install again. The uninstall did not succeed this time.',
250
250
  'panels.market.add.failureGeneric': 'Something went wrong during install — see the install details',
251
+ 'panels.market.add.failureCredentials': 'This repository needs credentials: this machine has none for it. Clone it once in a terminal, set up a credential helper, or install from the SSH address.',
251
252
  'panels.market.add.approveTitle': 'Your approval is needed for install scripts',
252
253
  'panels.market.add.approveCaution': 'Only allow packages you trust: install scripts run on this machine with your permissions.',
253
254
  'panels.market.add.approveRun': 'Allow and continue installing',
@@ -320,6 +321,7 @@ export const en = {
320
321
  'panels.discover.noSourceHint': 'Add a module market index (http address or git repository) to browse and install its modules here',
321
322
  'panels.discover.sourcesFailed': 'Could not read the index sources.',
322
323
  'panels.discover.unreadable': 'Could not read this index.',
324
+ 'panels.discover.sourceAuth': 'This index source could not be read: this machine has no git credentials for it. Set up credentials (or switch the source to its SSH address), then refresh.',
323
325
  'panels.discover.invalid': 'This index is not in a valid format.',
324
326
  'panels.discover.emptyRepo': 'This repository has no commits yet.',
325
327
  'panels.discover.missingIndex': 'This repository has no {path} yet.',
@@ -343,8 +345,23 @@ export const en = {
343
345
  'panels.discover.badShellDetail': 'This version is not compatible with the running workbench {current}; it requires {peer}',
344
346
  'panels.discover.unverified': 'Workbench unverified',
345
347
  'panels.discover.installing': 'Installing…',
348
+ 'panels.discover.installingNamed': 'Installing {name}…',
349
+ 'panels.discover.cancelInstall': 'Cancel install',
350
+ 'panels.discover.cancelling': 'Cancelling…',
351
+ 'panels.discover.installCancelled': 'Install cancelled: {name}',
346
352
  'panels.discover.installedDone': 'Installed: {name}',
347
353
  'panels.discover.failed': 'Failed: {reason}',
354
+ 'panels.discover.transportTitle': 'Where to read this repository',
355
+ 'panels.discover.transportSsh': 'SSH',
356
+ 'panels.discover.transportHttps': 'HTTPS',
357
+ 'panels.discover.transportOk': 'Readable',
358
+ 'panels.discover.transportAuth': 'Needs credentials',
359
+ 'panels.discover.transportUnreachable': 'Unreachable',
360
+ 'panels.discover.transportUnknown': 'Not probed',
361
+ 'panels.discover.transportChecking': 'Checking…',
362
+ 'panels.discover.transportTest': 'Test this address',
363
+ 'panels.discover.transportPlaceholder': 'Or paste another address (mirror, alias)',
364
+ 'panels.discover.transportNeedsAuth': 'This repository needs credentials: clone it once in a terminal, or set up an SSH key / credential helper, then install again.',
348
365
  'panels.discover.expand': 'Show versions',
349
366
  'panels.discover.collapse': 'Hide versions',
350
367
  'panels.discover.versionCount': '{n} versions',
@@ -258,6 +258,7 @@ export declare const dictionaries: {
258
258
  readonly 'panels.market.add.failurePnpmMissing': "没有找到 pnpm,无法安装";
259
259
  readonly 'panels.market.add.failureInstalled': "它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。";
260
260
  readonly 'panels.market.add.failureGeneric': "安装过程中出错,原因见安装详情";
261
+ readonly 'panels.market.add.failureCredentials': "这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。";
261
262
  readonly 'panels.market.add.approveTitle': "需要你允许安装脚本";
262
263
  readonly 'panels.market.add.approveCaution': "只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。";
263
264
  readonly 'panels.market.add.approveRun': "允许并继续安装";
@@ -330,6 +331,7 @@ export declare const dictionaries: {
330
331
  readonly 'panels.discover.noSourceHint': "添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块";
331
332
  readonly 'panels.discover.sourcesFailed': "无法读取索引源";
332
333
  readonly 'panels.discover.unreadable': "无法读取此索引";
334
+ readonly 'panels.discover.sourceAuth': "这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。";
333
335
  readonly 'panels.discover.invalid': "此索引的格式无效";
334
336
  readonly 'panels.discover.emptyRepo': "这个仓库还没有任何提交";
335
337
  readonly 'panels.discover.missingIndex': "仓库里还没有索引文件 {path}";
@@ -353,8 +355,23 @@ export declare const dictionaries: {
353
355
  readonly 'panels.discover.badShellDetail': "此版本与当前的工作台 {current} 不兼容,它要求 {peer}";
354
356
  readonly 'panels.discover.unverified': "工作台未验证";
355
357
  readonly 'panels.discover.installing': "正在安装…";
358
+ readonly 'panels.discover.installingNamed': "正在安装「{name}」…";
359
+ readonly 'panels.discover.cancelInstall': "取消安装";
360
+ readonly 'panels.discover.cancelling': "正在取消…";
361
+ readonly 'panels.discover.installCancelled': "已取消安装:{name}";
356
362
  readonly 'panels.discover.installedDone': "装好了:{name}";
357
363
  readonly 'panels.discover.failed': "操作失败:{reason}";
364
+ readonly 'panels.discover.transportTitle': "从哪读这个仓库";
365
+ readonly 'panels.discover.transportSsh': "SSH";
366
+ readonly 'panels.discover.transportHttps': "HTTPS";
367
+ readonly 'panels.discover.transportOk': "能读";
368
+ readonly 'panels.discover.transportAuth': "要凭证";
369
+ readonly 'panels.discover.transportUnreachable': "连不上";
370
+ readonly 'panels.discover.transportUnknown': "没探成";
371
+ readonly 'panels.discover.transportChecking': "正在探测…";
372
+ readonly 'panels.discover.transportTest': "试这个地址";
373
+ readonly 'panels.discover.transportPlaceholder': "或贴一个别的地址(公司镜像、别名)";
374
+ readonly 'panels.discover.transportNeedsAuth': "这个仓库要凭证:先在终端里把它 clone 一次,或配好 SSH key / 凭据助手;配好后再点安装。";
358
375
  readonly 'panels.discover.expand': "展开版本";
359
376
  readonly 'panels.discover.collapse': "收起版本";
360
377
  readonly 'panels.discover.versionCount': "{n} 个版本";
@@ -735,7 +752,7 @@ export declare const dictionaries: {
735
752
  readonly 'configSync.emptyProviders': "工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把模型供应商那几行同步过来,或自己去「模型」里配。";
736
753
  readonly 'configSync.failed': "同步没成功,再试一次。";
737
754
  };
738
- en: Record<"time.now" | "time.ago" | "time.minutes" | "time.hours" | "time.days" | "blocker.retry" | "blocker.copy" | "blocker.unknown.title" | "blocker.login.go" | "blocker.login.titleGeneric" | "blocker.login.title" | "blocker.login.manual" | "blocker.login.hint" | "blocker.forbidden.open" | "blocker.forbidden.titleGeneric" | "blocker.forbidden.title" | "blocker.forbidden.hint" | "blocker.timeout.hint" | "blocker.exec.hint" | "blocker.fix.install" | "blocker.market.open" | "env.unit.failed" | "env.unit.failedHint" | "env.unit.unsupported" | "env.unit.unsupportedHint" | "env.unit.degraded" | "env.unit.degradedHint" | "env.unit.unchecked" | "env.unit.uncheckedHint" | "profileCreate.nav" | "profileCreate.lead" | "profileCreate.name" | "profileCreate.nameHint" | "profileCreate.source" | "profileCreate.current" | "profileCreate.copy" | "profileCreate.settings" | "profileCreate.create" | "profileCreate.creating" | "profileCreate.created" | "profileCreate.command" | "profileCreate.readFailed" | "profileCreate.retry" | "profileCreate.reading" | "profileCreate.noProfiles" | "profileCreate.failed" | "configSync.nav" | "configSync.lead" | "configSync.source" | "configSync.sourceBroken" | "configSync.sourceRows" | "configSync.sourceDead" | "configSync.refresh" | "configSync.loading" | "configSync.readHint" | "configSync.tag.new" | "configSync.tag.differs" | "configSync.conflictNote" | "configSync.code.lang" | "configSync.code.copy" | "configSync.code.copied" | "configSync.code.wrap" | "configSync.code.unwrap" | "configSync.code.collapse" | "configSync.code.collapseAria" | "configSync.code.expandAria" | "configSync.code.expand" | "configSync.missing" | "configSync.apply" | "configSync.applyNone" | "configSync.applying" | "configSync.applied" | "configSync.appliedUnverified" | "configSync.appliedIds" | "configSync.skippedIds" | "configSync.nothing" | "configSync.unreadable" | "configSync.noSource" | "configSync.emptyProviders" | "configSync.failed" | "env.need.bin.missing" | "env.need.bin.hint" | "env.need.extension.missing" | "env.need.extension.outdated" | "env.need.extension.hint" | "env.need.lib.missing" | "env.need.lib.outdated" | "env.need.lib.unsatisfied" | "env.need.lib.hint" | "env.need.env.missing" | "env.need.env.hint" | "brand.name" | "toggle.open" | "toggle.collapse" | "project.label" | "workspace.section" | "project.none" | "project.empty" | "project.add" | "project.add.busy" | "project.add.failed" | "project.search.label" | "project.search.placeholder" | "project.search.empty" | "project.group.workspaces" | "project.group.defaultWorkspace" | "project.group.workshop" | "project.rename.row" | "project.rename.current" | "project.rename.title" | "project.rename.description" | "project.rename.field" | "project.rename.placeholder" | "project.rename.hint" | "project.rename.save" | "project.rename.saving" | "project.rename.cancel" | "project.rename.failed" | "session.new" | "session.new.label" | "session.empty" | "session.noProject" | "session.list.label" | "session.copy" | "session.pinned" | "session.actions" | "status.idle" | "status.running" | "status.longTask" | "status.waitingApproval" | "status.planReview" | "status.waitingAnswer" | "status.compact.approval" | "status.compact.planReview" | "status.compact.answer" | "status.completed" | "status.subagentsRunning.one" | "status.subagentsRunning.other" | "project.attention.warning.one" | "project.attention.warning.other" | "project.attention.running.one" | "project.attention.running.other" | "project.attention.longTask.one" | "project.attention.longTask.other" | "project.attention.done.one" | "project.attention.done.other" | "project.attention.state.warning" | "project.attention.state.running" | "project.attention.state.done" | "hover.copied" | "time.short.minutes" | "time.short.hours" | "time.short.days" | "time.short.months" | "time.short.years" | "panels.title" | "panels.groupBoardless" | "panels.groupPlugins" | "panels.market.defaultHint" | "panels.market.defaultLabel" | "panels.market.defaultLocked" | "panels.followAll" | "panels.followAllConfirmTitle" | "panels.followAllConfirmDetail" | "panels.followAllConfirmAck" | "panels.followAllConfirmYes" | "panels.followAllConfirmNo" | "panels.enabled" | "panels.disabled" | "panels.choose" | "panels.buildModule" | "panels.failed" | "panels.dragHint" | "panels.unknownStep" | "panels.labelWithHint" | "panels.hintJoin" | "panels.dep.failed" | "panels.dep.unchecked" | "panels.dep.missing" | "panels.dep.outdated" | "panels.dep.degraded" | "panels.dep.unsupported" | "panels.tab.modules" | "panels.tab.market" | "panels.browseMarket" | "panels.noneInstalled" | "panels.noneInstalledHint" | "panels.market.installed" | "panels.market.notActive" | "panels.market.notUsable" | "panels.market.broken" | "panels.market.hasNew" | "panels.market.hasProblem" | "panels.market.missing" | "panels.market.unchecked" | "panels.market.uncheckedHint" | "panels.market.checking" | "panels.market.sectionInstalled" | "panels.market.sectionPending" | "panels.market.sectionShared" | "panels.market.sharedUsedBy" | "panels.market.listSeparator" | "panels.market.sharedMissing" | "panels.market.sharedOutdated" | "panels.market.sharedUnsatisfied" | "panels.market.sharedOk" | "panels.market.versionArrow" | "panels.market.lead" | "panels.market.install" | "panels.market.update" | "panels.market.swapSlow" | "panels.market.removeSlow" | "panels.market.updateNoChange" | "panels.market.updateUnknownVersion" | "panels.market.updateGone" | "panels.market.updateRestored" | "panels.market.updateBehind" | "panels.market.selfUpdateFailed" | "panels.market.selfUpdateUnknown" | "panels.market.selfUpdateRolledBack" | "panels.market.uninstall" | "panels.market.uninstallLabel" | "panels.market.installing" | "panels.market.updating" | "panels.market.uninstalling" | "panels.market.confirmUninstallTitle" | "panels.market.confirmUninstallDetail" | "panels.market.confirmUninstallAck" | "panels.market.confirmYes" | "panels.market.confirmNo" | "panels.market.failed" | "panels.market.needEnv" | "panels.market.needCommands" | "panels.market.needBinary" | "panels.market.needLib" | "panels.market.localMark" | "panels.market.noSource" | "panels.market.badSource" | "panels.market.empty" | "panels.market.sectionPlugins" | "panels.market.moduleOutdated" | "panels.market.updateNeedsWorkbench" | "panels.market.updateIncompatible" | "panels.market.moduleRefused" | "panels.market.moduleRestartHint" | "panels.market.pendingRestart" | "panels.market.pendingFollowUp" | "panels.market.migrationHint" | "panels.market.migrateAction" | "panels.market.migrating" | "panels.market.migrateConfirmTitle" | "panels.market.migrateConfirmDetail" | "panels.market.migrateConfirmAck" | "panels.market.migrateConfirmYes" | "panels.market.migrateDone" | "panels.market.dismissFollowUp" | "panels.market.dismissing" | "panels.market.dismissFollowUpTitle" | "panels.market.dismissFollowUpDetail" | "panels.market.dismissFollowUpAck" | "panels.market.dismissFollowUpYes" | "panels.market.dismissed" | "panels.market.workbenchName" | "panels.market.pluginBroken" | "panels.market.restartNeeded" | "panels.market.foot" | "panels.market.recheck" | "panels.market.checkUpdates" | "panels.market.checkedAt" | "panels.market.justNow" | "panels.market.minutesAgo" | "panels.market.hoursAgo" | "panels.market.add.description" | "panels.market.add.specPlaceholder" | "panels.market.add.guideToggle" | "panels.market.add.guideHide" | "panels.market.add.guideIdTitle" | "panels.market.add.guideIdExample" | "panels.market.add.guideIdHint" | "panels.market.add.guideGitTitle" | "panels.market.add.guideGitExample" | "panels.market.add.guideGitHint" | "panels.market.add.guidePathTitle" | "panels.market.add.guidePathExample" | "panels.market.add.guidePathHint" | "panels.market.add.guideExampleLabel" | "panels.market.add.guideFill" | "panels.market.add.guideSafety" | "panels.market.add.registryLegend" | "panels.market.add.registryOfficial" | "panels.market.add.registryMirror" | "panels.market.add.registryWithHost" | "panels.market.add.registryToggle" | "panels.market.add.installVersion" | "panels.market.add.registryDefault" | "panels.market.add.registryCustom" | "panels.market.add.registryCustomPlaceholder" | "panels.market.add.registryCustomHint" | "panels.market.add.registryCustomInvalid" | "panels.market.add.run" | "panels.market.add.edit" | "panels.market.add.changeRegistry" | "panels.market.add.installingTitle" | "panels.market.add.installedTitle" | "panels.market.add.failedTitle" | "panels.market.add.cancelledTitle" | "panels.market.add.failureNetworkHost" | "panels.market.add.problemInvalid" | "panels.market.add.problemInstalled" | "panels.market.add.problemNotFound" | "panels.market.add.problemNotPackage" | "panels.market.add.problemNotBundle" | "panels.market.add.problemNotWorkbenchModule" | "panels.market.add.problemNotModuleOrPlugin" | "panels.market.add.failureNotModuleOrPlugin" | "panels.market.add.installedPlugin" | "panels.market.add.pluginPreview" | "panels.market.add.pluginAlias" | "panels.market.add.problemNetwork" | "panels.market.add.problemUnknown" | "panels.market.add.failureNetwork" | "panels.market.add.failureNotFound" | "panels.market.add.failureNoMatchingVersion" | "panels.market.add.failureDiskFull" | "panels.market.add.failurePermission" | "panels.market.add.failureBuildBlocked" | "panels.market.add.failureIntegrity" | "panels.market.add.failureTimeout" | "panels.market.add.failurePnpmMissing" | "panels.market.add.failureInstalled" | "panels.market.add.failureGeneric" | "panels.market.add.approveTitle" | "panels.market.add.approveCaution" | "panels.market.add.approveRun" | "panels.market.add.restart" | "panels.market.add.tookEffect" | "panels.market.add.details" | "panels.market.add.open" | "panels.market.add.title" | "panels.market.add.intro" | "panels.market.add.specLabel" | "panels.market.add.specHint" | "panels.market.add.exampleTitle" | "panels.market.add.exampleFill" | "panels.market.add.registryLabel" | "panels.market.add.registryProfile" | "panels.market.add.registryPnpm" | "panels.market.add.check" | "panels.market.add.checking" | "panels.market.add.classifying" | "panels.market.add.change" | "panels.market.add.previewTitle" | "panels.market.add.fieldName" | "panels.market.add.fieldVersion" | "panels.market.add.fieldDescription" | "panels.market.add.fieldSource" | "panels.market.add.install" | "panels.market.add.installing" | "panels.market.add.cancel" | "panels.market.add.close" | "panels.market.add.retry" | "panels.market.add.changeSource" | "panels.market.tabInstalled" | "panels.market.tabs" | "panels.tab.discover" | "panels.discover.loading" | "panels.discover.slowHint" | "panels.discover.lead" | "panels.discover.addSource" | "panels.discover.addingSource" | "panels.discover.addFirstSource" | "panels.discover.removeSource" | "panels.discover.removeTitle" | "panels.discover.removeBody" | "panels.discover.sourceActions" | "panels.discover.sourceStateWritable" | "panels.discover.sourceStateReadOnly" | "panels.discover.sourceEnable" | "panels.discover.sourceDisable" | "panels.discover.sourceWorking" | "panels.discover.sourceEnabled" | "panels.discover.sourceReadOnly" | "panels.discover.refresh" | "panels.discover.search" | "panels.discover.clearSearch" | "panels.discover.all" | "panels.discover.sourceLabel" | "panels.discover.sourceKind" | "panels.discover.sourceKindHttp" | "panels.discover.sourceKindGit" | "panels.discover.sourceUrl" | "panels.discover.sourcePlaceholder" | "panels.discover.sourceRef" | "panels.discover.sourcePath" | "panels.discover.sourceLocal" | "panels.discover.sourceLocalHint" | "panels.discover.save" | "panels.discover.cancel" | "panels.discover.retry" | "panels.discover.noSource" | "panels.discover.noSourceHint" | "panels.discover.sourcesFailed" | "panels.discover.unreadable" | "panels.discover.invalid" | "panels.discover.emptyRepo" | "panels.discover.missingIndex" | "panels.discover.initTitle" | "panels.discover.initCta" | "panels.discover.initWhat" | "panels.discover.initBranch" | "panels.discover.initBranchHint" | "panels.discover.initBranchBad" | "panels.discover.initOk" | "panels.discover.initBusy" | "panels.discover.initDone" | "panels.discover.stale" | "panels.discover.empty" | "panels.discover.noMatch" | "panels.discover.notInstalled" | "panels.discover.installed" | "panels.discover.installedVersion" | "panels.discover.update" | "panels.discover.badShell" | "panels.discover.badShellDetail" | "panels.discover.unverified" | "panels.discover.installing" | "panels.discover.installedDone" | "panels.discover.failed" | "panels.discover.expand" | "panels.discover.collapse" | "panels.discover.versionCount" | "panels.discover.sourceNpm" | "panels.discover.sourceNpmDefault" | "panels.discover.sourceGit" | "panels.discover.installVersion" | "panels.discover.confirmTitle" | "panels.discover.confirmDetail" | "panels.discover.confirmAck" | "panels.discover.confirmOk" | "panels.discover.confirmCancel" | "panels.discover.marketMenu" | "panels.discover.manageSources" | "panels.discover.sourcesTitle" | "panels.discover.sourcesIntro" | "panels.discover.sourcesLabel" | "panels.discover.sourceTrust" | "panels.discover.sourceDuplicate" | "panels.discover.sourceBadUrl" | "panels.discover.close" | "panels.discover.labelsMenu" | "panels.discover.labelsCount" | "panels.discover.tagsAll" | "panels.discover.sort" | "panels.discover.sortWith" | "panels.discover.sortRelevance" | "panels.discover.sortDefault" | "panels.discover.sortPublished" | "panels.discover.categoriesLabel" | "panels.discover.showMore" | "panels.discover.entryMeta" | "panels.discover.entryMetaAuthor" | "panels.discover.openEntry" | "panels.discover.cardInstall" | "panels.discover.cardInstalled" | "panels.discover.cardUpdate" | "panels.discover.cardBlocked" | "panels.discover.installTitle" | "panels.discover.installVersionTitle" | "panels.discover.openInstalled" | "panels.discover.noCompatibleVersion" | "panels.discover.detailBack" | "panels.discover.publishedAt" | "panels.discover.detailMarket" | "panels.discover.detailIncompatible" | "panels.discover.detailUnknown" | "panels.discover.detailSource" | "panels.discover.authorUnknown" | "panels.discover.tabOverview" | "panels.discover.tabReadme" | "panels.discover.tabChangelog" | "panels.discover.docReadme" | "panels.discover.docChangelog" | "panels.discover.docLoading" | "panels.discover.docMissing" | "panels.discover.docUnavailable" | "panels.discover.docUnknownReason" | "panels.discover.detailTabs" | "panels.discover.factPackage" | "panels.discover.factRegistry" | "panels.discover.factRepository" | "panels.discover.factCommit" | "panels.discover.factDirectory" | "panels.discover.factPublished" | "panels.discover.factAuthor" | "panels.discover.factHomepage" | "panels.discover.factCategory" | "panels.discover.factLabels" | "panels.discover.factMarket" | "panels.discover.detailVersions" | "panels.discover.versionsLabel" | "panels.discover.tagRecommended" | "panels.discover.tagPrerelease" | "panels.discover.tagInstalled" | "panels.discover.tagIncompatible" | "panels.discover.tagUnknown" | "panels.discover.selected" | "panels.discover.done" | "panels.discover.installTrust" | "panels.discover.progress" | "panels.market.add.approveBuilds" | "panels.market.add.approveHint" | "panels.market.add.doneApplied" | "panels.market.add.doneRestart" | "panels.market.add.restartWhy" | "panels.market.add.restartWhy.no-hmr" | "panels.market.add.restartWhy.package-moved" | "panels.market.add.restartWhy.host-module" | "panels.market.add.restartWhy.unmanaged-plugin" | "panels.market.add.restartWhy.module-comparison" | "panels.market.add.cancelled" | "panels.market.add.failed" | "panels.market.add.removed" | "panels.market.add.supplyPending" | "panels.market.add.supplyFailed" | "panels.market.add.notModule" | "panels.market.add.removedRestart" | "panels.market.add.remove" | "panels.market.add.problem.invalidSpec" | "panels.market.add.problem.alreadyInstalled" | "panels.market.add.problem.notFound" | "panels.market.add.problem.notAPackage" | "panels.market.add.problem.notABundle" | "panels.market.add.problem.network" | "panels.market.add.problem.unknown" | "panels.market.add.reason.invalidSpec" | "panels.market.add.reason.incompatible" | "panels.market.add.reason.notBundle" | "panels.market.add.reason.notRemovable" | "panels.market.add.reason.bundleInUse" | "panels.market.add.reason.stopProfile" | "panels.market.add.reason.staleApproval" | "panels.market.add.reason.operationError" | "panels.market.add.reason.buildBlocked" | "panels.market.add.reason.pnpmMissing" | "panels.market.add.reason.noMatchingVersion" | "panels.market.add.reason.diskFull" | "panels.market.add.reason.permission" | "panels.market.add.reason.integrity" | "panels.market.add.reason.timeout" | "panels.market.add.reason.network" | "panels.market.add.reason.notFound" | "panels.market.add.reason.unknown" | "blocker.fix.update" | "blocker.fix.running" | "blocker.fix.failed" | "blocker.retry.running" | "panels.reading" | "panels.cardBroken" | "panels.cardRetry" | "panels.empty" | "panels.emptyHint" | "env.title" | "env.checking" | "env.installing" | "env.failed" | "env.elapsed" | "env.stepFailed.install" | "env.stepFailed.path" | "env.stepFailed.shell" | "env.toolchain.ok" | "env.toolchain.warn" | "env.opencli.ok" | "env.bridge.ok" | "env.bridge.short" | "env.bridge.why" | "env.bridge.hold" | "env.bridge.daemon" | "env.bridge.extension" | "env.bridge.extensionLink" | "env.bridge.profile" | "env.bridge.stale" | "env.bridge.unknown" | "env.fix.title" | "env.fix.why" | "env.fix.whyPath" | "env.fix.whyShell" | "env.fix.step" | "env.fix.stepPath" | "env.fix.stepShell" | "env.fix.permission" | "env.fix.network" | "env.fix.details" | "env.retry" | "env.wake" | "env.wake.opening" | "env.wake.browserOpen" | "env.wake.noBrowser" | "env.wake.failed" | "env.bridge.continue" | "env.diy.ok" | "env.diy.short" | "env.diy.hold" | "env.diy.why" | "env.diy.rows" | "env.diy.noRow" | "env.diy.step" | "env.diy.continue" | "env.copyCommand" | "env.copied" | "env.step.toolchain" | "env.step.opencli" | "env.step.bridge" | "env.step.diy" | "env.step.warm" | "env.warm.done" | "env.warm.short" | "adapterSet.not-configured" | "adapterSet.no-profile" | "adapterSet.malformed" | "adapterSet.not-resolvable" | "adapterSet.import-failed" | "adapterSet.bad-export" | "adapterSet.factory-failed" | "adapterSet.incompatible-version" | "adapterSet.missing-member" | "env.unit.hint" | "rightbar.label" | "rightbar.expand" | "rightbar.collapse" | "rightbar.column.label" | "rightbar.column.workbench" | "rightbar.column.dsh" | "rightbar.refresh" | "rightbar.refreshing" | "rightbar.updatedAt" | "rightbar.noProject" | "rightbar.openPlatform" | "error.unknown" | "board.title" | "panel.conversation" | "panels.label" | "adapterSet.title" | "adapterSet.lead" | "adapterSet.active" | "adapterSet.defaults" | "adapterSet.failed" | "adapterSet.healthUnreadable" | "workbenchSettings.nav" | "workbenchSettings.lead" | "sidebarEdition.nav" | "sidebarEdition.lead" | "sidebarEdition.official" | "sidebarEdition.officialHint" | "sidebarEdition.custom" | "sidebarEdition.customHint" | "sidebarEdition.saving" | "sidebarEdition.reloadRequired" | "sidebarEdition.reload" | "sidebarEdition.failed" | "debug.workspace" | "debug.status" | "debug.status.trouble" | "debug.stalled" | "debug.act.pause" | "debug.act.resume" | "debug.act.stop" | "debug.act.stop.ask" | "debug.card.here.title" | "debug.card.here.note" | "debug.card.away.note" | "debug.card.paused.note" | "debug.card.hidden.note" | "record.waiting" | "record.waiting.note" | "record.recording" | "record.recording.note" | "record.recording.shots" | "record.finished" | "record.finished.note" | "record.act.cancel" | "record.act.halt" | "approval.record.site" | "approval.record.what" | "approval.record.lands" | "approval.record.noUrl" | "approval.record.oneAction" | "approval.record.noSwitch" | "approval.longTask.what" | "approval.longTask.signal" | "approval.publish.module" | "approval.publish.target" | "approval.publish.version" | "approval.publish.author" | "approval.publish.authorMissing" | "approval.publish.owner" | "approval.publish.ownerUnowned" | "approval.publish.ownerTaken" | "approval.publish.unit" | "approval.publish.unitTaken" | "approval.publish.path" | "approval.publish.pathTaken" | "approval.publish.registry" | "approval.publish.repo" | "approval.publish.branch" | "approval.publish.defaultBranch" | "approval.publish.artifacts" | "approval.publish.index" | "approval.publish.commits" | "approval.publish.twoCommits" | "approval.publish.reading" | "approval.publish.changelog" | "approval.publish.changelogPending" | "approval.publish.changelogMissing" | "approval.publish.targetAuto" | "approval.publish.targetTeam" | "approval.publish.targetPublic" | "approval.publish.targetTarball" | "approval.publish.targetGit" | "approval.publish.targetMarket" | "approval.publish.targetLocal" | "approval.market.source" | "approval.market.url" | "approval.market.action" | "approval.market.policy" | "approval.market.enable" | "approval.market.disable" | "approval.market.writable" | "approval.market.readOnly" | "approval.market.reading" | "markdown.copy" | "markdown.copied" | "markdown.footnotes", string>;
755
+ en: Record<"time.now" | "time.ago" | "time.minutes" | "time.hours" | "time.days" | "blocker.retry" | "blocker.copy" | "blocker.unknown.title" | "blocker.login.go" | "blocker.login.titleGeneric" | "blocker.login.title" | "blocker.login.manual" | "blocker.login.hint" | "blocker.forbidden.open" | "blocker.forbidden.titleGeneric" | "blocker.forbidden.title" | "blocker.forbidden.hint" | "blocker.timeout.hint" | "blocker.exec.hint" | "blocker.fix.install" | "blocker.market.open" | "env.unit.failed" | "env.unit.failedHint" | "env.unit.unsupported" | "env.unit.unsupportedHint" | "env.unit.degraded" | "env.unit.degradedHint" | "env.unit.unchecked" | "env.unit.uncheckedHint" | "profileCreate.nav" | "profileCreate.lead" | "profileCreate.name" | "profileCreate.nameHint" | "profileCreate.source" | "profileCreate.current" | "profileCreate.copy" | "profileCreate.settings" | "profileCreate.create" | "profileCreate.creating" | "profileCreate.created" | "profileCreate.command" | "profileCreate.readFailed" | "profileCreate.retry" | "profileCreate.reading" | "profileCreate.noProfiles" | "profileCreate.failed" | "configSync.nav" | "configSync.lead" | "configSync.source" | "configSync.sourceBroken" | "configSync.sourceRows" | "configSync.sourceDead" | "configSync.refresh" | "configSync.loading" | "configSync.readHint" | "configSync.tag.new" | "configSync.tag.differs" | "configSync.conflictNote" | "configSync.code.lang" | "configSync.code.copy" | "configSync.code.copied" | "configSync.code.wrap" | "configSync.code.unwrap" | "configSync.code.collapse" | "configSync.code.collapseAria" | "configSync.code.expandAria" | "configSync.code.expand" | "configSync.missing" | "configSync.apply" | "configSync.applyNone" | "configSync.applying" | "configSync.applied" | "configSync.appliedUnverified" | "configSync.appliedIds" | "configSync.skippedIds" | "configSync.nothing" | "configSync.unreadable" | "configSync.noSource" | "configSync.emptyProviders" | "configSync.failed" | "env.need.bin.missing" | "env.need.bin.hint" | "env.need.extension.missing" | "env.need.extension.outdated" | "env.need.extension.hint" | "env.need.lib.missing" | "env.need.lib.outdated" | "env.need.lib.unsatisfied" | "env.need.lib.hint" | "env.need.env.missing" | "env.need.env.hint" | "brand.name" | "toggle.open" | "toggle.collapse" | "project.label" | "workspace.section" | "project.none" | "project.empty" | "project.add" | "project.add.busy" | "project.add.failed" | "project.search.label" | "project.search.placeholder" | "project.search.empty" | "project.group.workspaces" | "project.group.defaultWorkspace" | "project.group.workshop" | "project.rename.row" | "project.rename.current" | "project.rename.title" | "project.rename.description" | "project.rename.field" | "project.rename.placeholder" | "project.rename.hint" | "project.rename.save" | "project.rename.saving" | "project.rename.cancel" | "project.rename.failed" | "session.new" | "session.new.label" | "session.empty" | "session.noProject" | "session.list.label" | "session.copy" | "session.pinned" | "session.actions" | "status.idle" | "status.running" | "status.longTask" | "status.waitingApproval" | "status.planReview" | "status.waitingAnswer" | "status.compact.approval" | "status.compact.planReview" | "status.compact.answer" | "status.completed" | "status.subagentsRunning.one" | "status.subagentsRunning.other" | "project.attention.warning.one" | "project.attention.warning.other" | "project.attention.running.one" | "project.attention.running.other" | "project.attention.longTask.one" | "project.attention.longTask.other" | "project.attention.done.one" | "project.attention.done.other" | "project.attention.state.warning" | "project.attention.state.running" | "project.attention.state.done" | "hover.copied" | "time.short.minutes" | "time.short.hours" | "time.short.days" | "time.short.months" | "time.short.years" | "panels.title" | "panels.groupBoardless" | "panels.groupPlugins" | "panels.market.defaultHint" | "panels.market.defaultLabel" | "panels.market.defaultLocked" | "panels.followAll" | "panels.followAllConfirmTitle" | "panels.followAllConfirmDetail" | "panels.followAllConfirmAck" | "panels.followAllConfirmYes" | "panels.followAllConfirmNo" | "panels.enabled" | "panels.disabled" | "panels.choose" | "panels.buildModule" | "panels.failed" | "panels.dragHint" | "panels.unknownStep" | "panels.labelWithHint" | "panels.hintJoin" | "panels.dep.failed" | "panels.dep.unchecked" | "panels.dep.missing" | "panels.dep.outdated" | "panels.dep.degraded" | "panels.dep.unsupported" | "panels.tab.modules" | "panels.tab.market" | "panels.browseMarket" | "panels.noneInstalled" | "panels.noneInstalledHint" | "panels.market.installed" | "panels.market.notActive" | "panels.market.notUsable" | "panels.market.broken" | "panels.market.hasNew" | "panels.market.hasProblem" | "panels.market.missing" | "panels.market.unchecked" | "panels.market.uncheckedHint" | "panels.market.checking" | "panels.market.sectionInstalled" | "panels.market.sectionPending" | "panels.market.sectionShared" | "panels.market.sharedUsedBy" | "panels.market.listSeparator" | "panels.market.sharedMissing" | "panels.market.sharedOutdated" | "panels.market.sharedUnsatisfied" | "panels.market.sharedOk" | "panels.market.versionArrow" | "panels.market.lead" | "panels.market.install" | "panels.market.update" | "panels.market.swapSlow" | "panels.market.removeSlow" | "panels.market.updateNoChange" | "panels.market.updateUnknownVersion" | "panels.market.updateGone" | "panels.market.updateRestored" | "panels.market.updateBehind" | "panels.market.selfUpdateFailed" | "panels.market.selfUpdateUnknown" | "panels.market.selfUpdateRolledBack" | "panels.market.uninstall" | "panels.market.uninstallLabel" | "panels.market.installing" | "panels.market.updating" | "panels.market.uninstalling" | "panels.market.confirmUninstallTitle" | "panels.market.confirmUninstallDetail" | "panels.market.confirmUninstallAck" | "panels.market.confirmYes" | "panels.market.confirmNo" | "panels.market.failed" | "panels.market.needEnv" | "panels.market.needCommands" | "panels.market.needBinary" | "panels.market.needLib" | "panels.market.localMark" | "panels.market.noSource" | "panels.market.badSource" | "panels.market.empty" | "panels.market.sectionPlugins" | "panels.market.moduleOutdated" | "panels.market.updateNeedsWorkbench" | "panels.market.updateIncompatible" | "panels.market.moduleRefused" | "panels.market.moduleRestartHint" | "panels.market.pendingRestart" | "panels.market.pendingFollowUp" | "panels.market.migrationHint" | "panels.market.migrateAction" | "panels.market.migrating" | "panels.market.migrateConfirmTitle" | "panels.market.migrateConfirmDetail" | "panels.market.migrateConfirmAck" | "panels.market.migrateConfirmYes" | "panels.market.migrateDone" | "panels.market.dismissFollowUp" | "panels.market.dismissing" | "panels.market.dismissFollowUpTitle" | "panels.market.dismissFollowUpDetail" | "panels.market.dismissFollowUpAck" | "panels.market.dismissFollowUpYes" | "panels.market.dismissed" | "panels.market.workbenchName" | "panels.market.pluginBroken" | "panels.market.restartNeeded" | "panels.market.foot" | "panels.market.recheck" | "panels.market.checkUpdates" | "panels.market.checkedAt" | "panels.market.justNow" | "panels.market.minutesAgo" | "panels.market.hoursAgo" | "panels.market.add.description" | "panels.market.add.specPlaceholder" | "panels.market.add.guideToggle" | "panels.market.add.guideHide" | "panels.market.add.guideIdTitle" | "panels.market.add.guideIdExample" | "panels.market.add.guideIdHint" | "panels.market.add.guideGitTitle" | "panels.market.add.guideGitExample" | "panels.market.add.guideGitHint" | "panels.market.add.guidePathTitle" | "panels.market.add.guidePathExample" | "panels.market.add.guidePathHint" | "panels.market.add.guideExampleLabel" | "panels.market.add.guideFill" | "panels.market.add.guideSafety" | "panels.market.add.registryLegend" | "panels.market.add.registryOfficial" | "panels.market.add.registryMirror" | "panels.market.add.registryWithHost" | "panels.market.add.registryToggle" | "panels.market.add.installVersion" | "panels.market.add.registryDefault" | "panels.market.add.registryCustom" | "panels.market.add.registryCustomPlaceholder" | "panels.market.add.registryCustomHint" | "panels.market.add.registryCustomInvalid" | "panels.market.add.run" | "panels.market.add.edit" | "panels.market.add.changeRegistry" | "panels.market.add.installingTitle" | "panels.market.add.installedTitle" | "panels.market.add.failedTitle" | "panels.market.add.cancelledTitle" | "panels.market.add.failureNetworkHost" | "panels.market.add.problemInvalid" | "panels.market.add.problemInstalled" | "panels.market.add.problemNotFound" | "panels.market.add.problemNotPackage" | "panels.market.add.problemNotBundle" | "panels.market.add.problemNotWorkbenchModule" | "panels.market.add.problemNotModuleOrPlugin" | "panels.market.add.failureNotModuleOrPlugin" | "panels.market.add.installedPlugin" | "panels.market.add.pluginPreview" | "panels.market.add.pluginAlias" | "panels.market.add.problemNetwork" | "panels.market.add.problemUnknown" | "panels.market.add.failureNetwork" | "panels.market.add.failureNotFound" | "panels.market.add.failureNoMatchingVersion" | "panels.market.add.failureDiskFull" | "panels.market.add.failurePermission" | "panels.market.add.failureBuildBlocked" | "panels.market.add.failureIntegrity" | "panels.market.add.failureTimeout" | "panels.market.add.failurePnpmMissing" | "panels.market.add.failureInstalled" | "panels.market.add.failureGeneric" | "panels.market.add.failureCredentials" | "panels.market.add.approveTitle" | "panels.market.add.approveCaution" | "panels.market.add.approveRun" | "panels.market.add.restart" | "panels.market.add.tookEffect" | "panels.market.add.details" | "panels.market.add.open" | "panels.market.add.title" | "panels.market.add.intro" | "panels.market.add.specLabel" | "panels.market.add.specHint" | "panels.market.add.exampleTitle" | "panels.market.add.exampleFill" | "panels.market.add.registryLabel" | "panels.market.add.registryProfile" | "panels.market.add.registryPnpm" | "panels.market.add.check" | "panels.market.add.checking" | "panels.market.add.classifying" | "panels.market.add.change" | "panels.market.add.previewTitle" | "panels.market.add.fieldName" | "panels.market.add.fieldVersion" | "panels.market.add.fieldDescription" | "panels.market.add.fieldSource" | "panels.market.add.install" | "panels.market.add.installing" | "panels.market.add.cancel" | "panels.market.add.close" | "panels.market.add.retry" | "panels.market.add.changeSource" | "panels.market.tabInstalled" | "panels.market.tabs" | "panels.tab.discover" | "panels.discover.loading" | "panels.discover.slowHint" | "panels.discover.lead" | "panels.discover.addSource" | "panels.discover.addingSource" | "panels.discover.addFirstSource" | "panels.discover.removeSource" | "panels.discover.removeTitle" | "panels.discover.removeBody" | "panels.discover.sourceActions" | "panels.discover.sourceStateWritable" | "panels.discover.sourceStateReadOnly" | "panels.discover.sourceEnable" | "panels.discover.sourceDisable" | "panels.discover.sourceWorking" | "panels.discover.sourceEnabled" | "panels.discover.sourceReadOnly" | "panels.discover.refresh" | "panels.discover.search" | "panels.discover.clearSearch" | "panels.discover.all" | "panels.discover.sourceLabel" | "panels.discover.sourceKind" | "panels.discover.sourceKindHttp" | "panels.discover.sourceKindGit" | "panels.discover.sourceUrl" | "panels.discover.sourcePlaceholder" | "panels.discover.sourceRef" | "panels.discover.sourcePath" | "panels.discover.sourceLocal" | "panels.discover.sourceLocalHint" | "panels.discover.save" | "panels.discover.cancel" | "panels.discover.retry" | "panels.discover.noSource" | "panels.discover.noSourceHint" | "panels.discover.sourcesFailed" | "panels.discover.unreadable" | "panels.discover.sourceAuth" | "panels.discover.invalid" | "panels.discover.emptyRepo" | "panels.discover.missingIndex" | "panels.discover.initTitle" | "panels.discover.initCta" | "panels.discover.initWhat" | "panels.discover.initBranch" | "panels.discover.initBranchHint" | "panels.discover.initBranchBad" | "panels.discover.initOk" | "panels.discover.initBusy" | "panels.discover.initDone" | "panels.discover.stale" | "panels.discover.empty" | "panels.discover.noMatch" | "panels.discover.notInstalled" | "panels.discover.installed" | "panels.discover.installedVersion" | "panels.discover.update" | "panels.discover.badShell" | "panels.discover.badShellDetail" | "panels.discover.unverified" | "panels.discover.installing" | "panels.discover.installingNamed" | "panels.discover.cancelInstall" | "panels.discover.cancelling" | "panels.discover.installCancelled" | "panels.discover.installedDone" | "panels.discover.failed" | "panels.discover.transportTitle" | "panels.discover.transportSsh" | "panels.discover.transportHttps" | "panels.discover.transportOk" | "panels.discover.transportAuth" | "panels.discover.transportUnreachable" | "panels.discover.transportUnknown" | "panels.discover.transportChecking" | "panels.discover.transportTest" | "panels.discover.transportPlaceholder" | "panels.discover.transportNeedsAuth" | "panels.discover.expand" | "panels.discover.collapse" | "panels.discover.versionCount" | "panels.discover.sourceNpm" | "panels.discover.sourceNpmDefault" | "panels.discover.sourceGit" | "panels.discover.installVersion" | "panels.discover.confirmTitle" | "panels.discover.confirmDetail" | "panels.discover.confirmAck" | "panels.discover.confirmOk" | "panels.discover.confirmCancel" | "panels.discover.marketMenu" | "panels.discover.manageSources" | "panels.discover.sourcesTitle" | "panels.discover.sourcesIntro" | "panels.discover.sourcesLabel" | "panels.discover.sourceTrust" | "panels.discover.sourceDuplicate" | "panels.discover.sourceBadUrl" | "panels.discover.close" | "panels.discover.labelsMenu" | "panels.discover.labelsCount" | "panels.discover.tagsAll" | "panels.discover.sort" | "panels.discover.sortWith" | "panels.discover.sortRelevance" | "panels.discover.sortDefault" | "panels.discover.sortPublished" | "panels.discover.categoriesLabel" | "panels.discover.showMore" | "panels.discover.entryMeta" | "panels.discover.entryMetaAuthor" | "panels.discover.openEntry" | "panels.discover.cardInstall" | "panels.discover.cardInstalled" | "panels.discover.cardUpdate" | "panels.discover.cardBlocked" | "panels.discover.installTitle" | "panels.discover.installVersionTitle" | "panels.discover.openInstalled" | "panels.discover.noCompatibleVersion" | "panels.discover.detailBack" | "panels.discover.publishedAt" | "panels.discover.detailMarket" | "panels.discover.detailIncompatible" | "panels.discover.detailUnknown" | "panels.discover.detailSource" | "panels.discover.authorUnknown" | "panels.discover.tabOverview" | "panels.discover.tabReadme" | "panels.discover.tabChangelog" | "panels.discover.docReadme" | "panels.discover.docChangelog" | "panels.discover.docLoading" | "panels.discover.docMissing" | "panels.discover.docUnavailable" | "panels.discover.docUnknownReason" | "panels.discover.detailTabs" | "panels.discover.factPackage" | "panels.discover.factRegistry" | "panels.discover.factRepository" | "panels.discover.factCommit" | "panels.discover.factDirectory" | "panels.discover.factPublished" | "panels.discover.factAuthor" | "panels.discover.factHomepage" | "panels.discover.factCategory" | "panels.discover.factLabels" | "panels.discover.factMarket" | "panels.discover.detailVersions" | "panels.discover.versionsLabel" | "panels.discover.tagRecommended" | "panels.discover.tagPrerelease" | "panels.discover.tagInstalled" | "panels.discover.tagIncompatible" | "panels.discover.tagUnknown" | "panels.discover.selected" | "panels.discover.done" | "panels.discover.installTrust" | "panels.discover.progress" | "panels.market.add.approveBuilds" | "panels.market.add.approveHint" | "panels.market.add.doneApplied" | "panels.market.add.doneRestart" | "panels.market.add.restartWhy" | "panels.market.add.restartWhy.no-hmr" | "panels.market.add.restartWhy.package-moved" | "panels.market.add.restartWhy.host-module" | "panels.market.add.restartWhy.unmanaged-plugin" | "panels.market.add.restartWhy.module-comparison" | "panels.market.add.cancelled" | "panels.market.add.failed" | "panels.market.add.removed" | "panels.market.add.supplyPending" | "panels.market.add.supplyFailed" | "panels.market.add.notModule" | "panels.market.add.removedRestart" | "panels.market.add.remove" | "panels.market.add.problem.invalidSpec" | "panels.market.add.problem.alreadyInstalled" | "panels.market.add.problem.notFound" | "panels.market.add.problem.notAPackage" | "panels.market.add.problem.notABundle" | "panels.market.add.problem.network" | "panels.market.add.problem.unknown" | "panels.market.add.reason.invalidSpec" | "panels.market.add.reason.incompatible" | "panels.market.add.reason.notBundle" | "panels.market.add.reason.notRemovable" | "panels.market.add.reason.bundleInUse" | "panels.market.add.reason.stopProfile" | "panels.market.add.reason.staleApproval" | "panels.market.add.reason.operationError" | "panels.market.add.reason.buildBlocked" | "panels.market.add.reason.pnpmMissing" | "panels.market.add.reason.noMatchingVersion" | "panels.market.add.reason.diskFull" | "panels.market.add.reason.permission" | "panels.market.add.reason.integrity" | "panels.market.add.reason.timeout" | "panels.market.add.reason.network" | "panels.market.add.reason.notFound" | "panels.market.add.reason.unknown" | "blocker.fix.update" | "blocker.fix.running" | "blocker.fix.failed" | "blocker.retry.running" | "panels.reading" | "panels.cardBroken" | "panels.cardRetry" | "panels.empty" | "panels.emptyHint" | "env.title" | "env.checking" | "env.installing" | "env.failed" | "env.elapsed" | "env.stepFailed.install" | "env.stepFailed.path" | "env.stepFailed.shell" | "env.toolchain.ok" | "env.toolchain.warn" | "env.opencli.ok" | "env.bridge.ok" | "env.bridge.short" | "env.bridge.why" | "env.bridge.hold" | "env.bridge.daemon" | "env.bridge.extension" | "env.bridge.extensionLink" | "env.bridge.profile" | "env.bridge.stale" | "env.bridge.unknown" | "env.fix.title" | "env.fix.why" | "env.fix.whyPath" | "env.fix.whyShell" | "env.fix.step" | "env.fix.stepPath" | "env.fix.stepShell" | "env.fix.permission" | "env.fix.network" | "env.fix.details" | "env.retry" | "env.wake" | "env.wake.opening" | "env.wake.browserOpen" | "env.wake.noBrowser" | "env.wake.failed" | "env.bridge.continue" | "env.diy.ok" | "env.diy.short" | "env.diy.hold" | "env.diy.why" | "env.diy.rows" | "env.diy.noRow" | "env.diy.step" | "env.diy.continue" | "env.copyCommand" | "env.copied" | "env.step.toolchain" | "env.step.opencli" | "env.step.bridge" | "env.step.diy" | "env.step.warm" | "env.warm.done" | "env.warm.short" | "adapterSet.not-configured" | "adapterSet.no-profile" | "adapterSet.malformed" | "adapterSet.not-resolvable" | "adapterSet.import-failed" | "adapterSet.bad-export" | "adapterSet.factory-failed" | "adapterSet.incompatible-version" | "adapterSet.missing-member" | "env.unit.hint" | "rightbar.label" | "rightbar.expand" | "rightbar.collapse" | "rightbar.column.label" | "rightbar.column.workbench" | "rightbar.column.dsh" | "rightbar.refresh" | "rightbar.refreshing" | "rightbar.updatedAt" | "rightbar.noProject" | "rightbar.openPlatform" | "error.unknown" | "board.title" | "panel.conversation" | "panels.label" | "adapterSet.title" | "adapterSet.lead" | "adapterSet.active" | "adapterSet.defaults" | "adapterSet.failed" | "adapterSet.healthUnreadable" | "workbenchSettings.nav" | "workbenchSettings.lead" | "sidebarEdition.nav" | "sidebarEdition.lead" | "sidebarEdition.official" | "sidebarEdition.officialHint" | "sidebarEdition.custom" | "sidebarEdition.customHint" | "sidebarEdition.saving" | "sidebarEdition.reloadRequired" | "sidebarEdition.reload" | "sidebarEdition.failed" | "debug.workspace" | "debug.status" | "debug.status.trouble" | "debug.stalled" | "debug.act.pause" | "debug.act.resume" | "debug.act.stop" | "debug.act.stop.ask" | "debug.card.here.title" | "debug.card.here.note" | "debug.card.away.note" | "debug.card.paused.note" | "debug.card.hidden.note" | "record.waiting" | "record.waiting.note" | "record.recording" | "record.recording.note" | "record.recording.shots" | "record.finished" | "record.finished.note" | "record.act.cancel" | "record.act.halt" | "approval.record.site" | "approval.record.what" | "approval.record.lands" | "approval.record.noUrl" | "approval.record.oneAction" | "approval.record.noSwitch" | "approval.longTask.what" | "approval.longTask.signal" | "approval.publish.module" | "approval.publish.target" | "approval.publish.version" | "approval.publish.author" | "approval.publish.authorMissing" | "approval.publish.owner" | "approval.publish.ownerUnowned" | "approval.publish.ownerTaken" | "approval.publish.unit" | "approval.publish.unitTaken" | "approval.publish.path" | "approval.publish.pathTaken" | "approval.publish.registry" | "approval.publish.repo" | "approval.publish.branch" | "approval.publish.defaultBranch" | "approval.publish.artifacts" | "approval.publish.index" | "approval.publish.commits" | "approval.publish.twoCommits" | "approval.publish.reading" | "approval.publish.changelog" | "approval.publish.changelogPending" | "approval.publish.changelogMissing" | "approval.publish.targetAuto" | "approval.publish.targetTeam" | "approval.publish.targetPublic" | "approval.publish.targetTarball" | "approval.publish.targetGit" | "approval.publish.targetMarket" | "approval.publish.targetLocal" | "approval.market.source" | "approval.market.url" | "approval.market.action" | "approval.market.policy" | "approval.market.enable" | "approval.market.disable" | "approval.market.writable" | "approval.market.readOnly" | "approval.market.reading" | "markdown.copy" | "markdown.copied" | "markdown.footnotes", string>;
739
756
  };
740
757
  /** 中文词表的键类型(从 `zh.ts` 转出):`en` 与模块词表都得覆盖同一批键。 */
741
758
  export type { WorkbenchMessages };
package/dist/i18n/zh.d.ts CHANGED
@@ -256,6 +256,7 @@ export declare const zh: {
256
256
  readonly 'panels.market.add.failurePnpmMissing': "没有找到 pnpm,无法安装";
257
257
  readonly 'panels.market.add.failureInstalled': "它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。";
258
258
  readonly 'panels.market.add.failureGeneric': "安装过程中出错,原因见安装详情";
259
+ readonly 'panels.market.add.failureCredentials': "这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。";
259
260
  readonly 'panels.market.add.approveTitle': "需要你允许安装脚本";
260
261
  readonly 'panels.market.add.approveCaution': "只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。";
261
262
  readonly 'panels.market.add.approveRun': "允许并继续安装";
@@ -328,6 +329,7 @@ export declare const zh: {
328
329
  readonly 'panels.discover.noSourceHint': "添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块";
329
330
  readonly 'panels.discover.sourcesFailed': "无法读取索引源";
330
331
  readonly 'panels.discover.unreadable': "无法读取此索引";
332
+ readonly 'panels.discover.sourceAuth': "这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。";
331
333
  readonly 'panels.discover.invalid': "此索引的格式无效";
332
334
  readonly 'panels.discover.emptyRepo': "这个仓库还没有任何提交";
333
335
  readonly 'panels.discover.missingIndex': "仓库里还没有索引文件 {path}";
@@ -351,8 +353,23 @@ export declare const zh: {
351
353
  readonly 'panels.discover.badShellDetail': "此版本与当前的工作台 {current} 不兼容,它要求 {peer}";
352
354
  readonly 'panels.discover.unverified': "工作台未验证";
353
355
  readonly 'panels.discover.installing': "正在安装…";
356
+ readonly 'panels.discover.installingNamed': "正在安装「{name}」…";
357
+ readonly 'panels.discover.cancelInstall': "取消安装";
358
+ readonly 'panels.discover.cancelling': "正在取消…";
359
+ readonly 'panels.discover.installCancelled': "已取消安装:{name}";
354
360
  readonly 'panels.discover.installedDone': "装好了:{name}";
355
361
  readonly 'panels.discover.failed': "操作失败:{reason}";
362
+ readonly 'panels.discover.transportTitle': "从哪读这个仓库";
363
+ readonly 'panels.discover.transportSsh': "SSH";
364
+ readonly 'panels.discover.transportHttps': "HTTPS";
365
+ readonly 'panels.discover.transportOk': "能读";
366
+ readonly 'panels.discover.transportAuth': "要凭证";
367
+ readonly 'panels.discover.transportUnreachable': "连不上";
368
+ readonly 'panels.discover.transportUnknown': "没探成";
369
+ readonly 'panels.discover.transportChecking': "正在探测…";
370
+ readonly 'panels.discover.transportTest': "试这个地址";
371
+ readonly 'panels.discover.transportPlaceholder': "或贴一个别的地址(公司镜像、别名)";
372
+ readonly 'panels.discover.transportNeedsAuth': "这个仓库要凭证:先在终端里把它 clone 一次,或配好 SSH key / 凭据助手;配好后再点安装。";
356
373
  readonly 'panels.discover.expand': "展开版本";
357
374
  readonly 'panels.discover.collapse': "收起版本";
358
375
  readonly 'panels.discover.versionCount': "{n} 个版本";
package/dist/i18n/zh.js CHANGED
@@ -248,6 +248,7 @@ export const zh = {
248
248
  'panels.market.add.failurePnpmMissing': '没有找到 pnpm,无法安装',
249
249
  'panels.market.add.failureInstalled': '它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。',
250
250
  'panels.market.add.failureGeneric': '安装过程中出错,原因见安装详情',
251
+ 'panels.market.add.failureCredentials': '这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。',
251
252
  'panels.market.add.approveTitle': '需要你允许安装脚本',
252
253
  'panels.market.add.approveCaution': '只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。',
253
254
  'panels.market.add.approveRun': '允许并继续安装',
@@ -320,6 +321,7 @@ export const zh = {
320
321
  'panels.discover.noSourceHint': '添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块',
321
322
  'panels.discover.sourcesFailed': '无法读取索引源',
322
323
  'panels.discover.unreadable': '无法读取此索引',
324
+ 'panels.discover.sourceAuth': '这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。',
323
325
  'panels.discover.invalid': '此索引的格式无效',
324
326
  'panels.discover.emptyRepo': '这个仓库还没有任何提交',
325
327
  'panels.discover.missingIndex': '仓库里还没有索引文件 {path}',
@@ -343,8 +345,23 @@ export const zh = {
343
345
  'panels.discover.badShellDetail': '此版本与当前的工作台 {current} 不兼容,它要求 {peer}',
344
346
  'panels.discover.unverified': '工作台未验证',
345
347
  'panels.discover.installing': '正在安装…',
348
+ 'panels.discover.installingNamed': '正在安装「{name}」…',
349
+ 'panels.discover.cancelInstall': '取消安装',
350
+ 'panels.discover.cancelling': '正在取消…',
351
+ 'panels.discover.installCancelled': '已取消安装:{name}',
346
352
  'panels.discover.installedDone': '装好了:{name}',
347
353
  'panels.discover.failed': '操作失败:{reason}',
354
+ 'panels.discover.transportTitle': '从哪读这个仓库',
355
+ 'panels.discover.transportSsh': 'SSH',
356
+ 'panels.discover.transportHttps': 'HTTPS',
357
+ 'panels.discover.transportOk': '能读',
358
+ 'panels.discover.transportAuth': '要凭证',
359
+ 'panels.discover.transportUnreachable': '连不上',
360
+ 'panels.discover.transportUnknown': '没探成',
361
+ 'panels.discover.transportChecking': '正在探测…',
362
+ 'panels.discover.transportTest': '试这个地址',
363
+ 'panels.discover.transportPlaceholder': '或贴一个别的地址(公司镜像、别名)',
364
+ 'panels.discover.transportNeedsAuth': '这个仓库要凭证:先在终端里把它 clone 一次,或配好 SSH key / 凭据助手;配好后再点安装。',
348
365
  'panels.discover.expand': '展开版本',
349
366
  'panels.discover.collapse': '收起版本',
350
367
  'panels.discover.versionCount': '{n} 个版本',
package/dist/index.d.ts CHANGED
@@ -66,6 +66,7 @@ export * from './i18n/settings.js';
66
66
  export * from './i18n/zh.js';
67
67
  export * from './lib/blocker-action.js';
68
68
  export * from './lib/market-index.js';
69
+ export * from './lib/git-address.js';
69
70
  export * from './lib/board-fact.js';
70
71
  export * from './lib/busy.js';
71
72
  export * from './lib/dsh-client.js';
package/dist/index.js CHANGED
@@ -66,6 +66,7 @@ export * from './i18n/settings.js';
66
66
  export * from './i18n/zh.js';
67
67
  export * from './lib/blocker-action.js';
68
68
  export * from './lib/market-index.js';
69
+ export * from './lib/git-address.js';
69
70
  export * from './lib/board-fact.js';
70
71
  export * from './lib/busy.js';
71
72
  export * from './lib/dsh-client.js';
@@ -0,0 +1,23 @@
1
+ export interface GitAddress {
2
+ readonly kind: 'https' | 'ssh';
3
+ readonly host: string;
4
+ readonly path: string;
5
+ readonly user?: string;
6
+ readonly port?: number;
7
+ }
8
+ export interface GitTransportCandidate {
9
+ readonly kind: 'https' | 'ssh';
10
+ readonly url: string;
11
+ }
12
+ /**
13
+ * 把一个 git 地址拆成「哪台主机 + 哪个路径」,不管发布者当初用的是 https、ssh 还是
14
+ * scp 那种 `git@host:path` 写法;认不出来给 undefined。
15
+ */
16
+ export declare function gitAddressOf(url: string): GitAddress | undefined;
17
+ /** 一份地址的规范写法:ssh 一律成 `ssh://user@host/path`(pnpm 认这个),https 原样。 */
18
+ export declare function gitAddressText(address: GitAddress): string;
19
+ /**
20
+ * 同一个仓库的两种读法,发布者用的那种排前面。ssh 那条一律规范成 `ssh://` 形式,
21
+ * 因为 `git@host:path` 拼进安装 spec 时 pnpm 不认;https 那条保留发布者的原样(含 http)。
22
+ */
23
+ export declare function gitTransportCandidates(url: string): readonly GitTransportCandidate[];
@@ -0,0 +1,79 @@
1
+ const SCP = /^(?:([A-Za-z0-9._-]+)@)?([A-Za-z0-9.-]+):(?!\/)(\S+)$/;
2
+ function bare(url) {
3
+ return url.trim().replace(/^git\+/, '');
4
+ }
5
+ function pathOf(pathname) {
6
+ return pathname.replace(/^\/+/, '').replace(/\/+$/, '');
7
+ }
8
+ /**
9
+ * 把一个 git 地址拆成「哪台主机 + 哪个路径」,不管发布者当初用的是 https、ssh 还是
10
+ * scp 那种 `git@host:path` 写法;认不出来给 undefined。
11
+ */
12
+ export function gitAddressOf(url) {
13
+ const text = bare(url);
14
+ if (text === '')
15
+ return undefined;
16
+ if (text.includes('://')) {
17
+ let parsed;
18
+ try {
19
+ parsed = new URL(text);
20
+ }
21
+ catch {
22
+ return undefined;
23
+ }
24
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:' && parsed.protocol !== 'ssh:') {
25
+ return undefined;
26
+ }
27
+ const path = pathOf(parsed.pathname);
28
+ if (path === '')
29
+ return undefined;
30
+ const port = parsed.port === '' ? undefined : Number(parsed.port);
31
+ const shared = {
32
+ host: parsed.hostname,
33
+ path,
34
+ ...(port === undefined ? {} : { port }),
35
+ };
36
+ if (parsed.protocol !== 'ssh:')
37
+ return { kind: 'https', ...shared };
38
+ return { kind: 'ssh', ...shared, ...(parsed.username === '' ? {} : { user: parsed.username }) };
39
+ }
40
+ const scp = SCP.exec(text);
41
+ if (scp === null)
42
+ return undefined;
43
+ const path = pathOf(scp[3] ?? '');
44
+ if (path === '')
45
+ return undefined;
46
+ return {
47
+ kind: 'ssh',
48
+ host: scp[2] ?? '',
49
+ path,
50
+ ...(scp[1] === undefined ? {} : { user: scp[1] }),
51
+ };
52
+ }
53
+ /** 一份地址的规范写法:ssh 一律成 `ssh://user@host/path`(pnpm 认这个),https 原样。 */
54
+ export function gitAddressText(address) {
55
+ const port = address.port === undefined ? '' : `:${String(address.port)}`;
56
+ if (address.kind === 'ssh') {
57
+ return `ssh://${address.user === undefined || address.user === '' ? 'git' : address.user}@${address.host}${port}/${address.path}`;
58
+ }
59
+ return `https://${address.host}${port}/${address.path}`;
60
+ }
61
+ /**
62
+ * 同一个仓库的两种读法,发布者用的那种排前面。ssh 那条一律规范成 `ssh://` 形式,
63
+ * 因为 `git@host:path` 拼进安装 spec 时 pnpm 不认;https 那条保留发布者的原样(含 http)。
64
+ */
65
+ export function gitTransportCandidates(url) {
66
+ const address = gitAddressOf(url);
67
+ if (address === undefined) {
68
+ const only = bare(url);
69
+ return only === '' ? [] : [{ kind: only.startsWith('ssh') ? 'ssh' : 'https', url: only }];
70
+ }
71
+ const primary = {
72
+ kind: address.kind,
73
+ url: address.kind === 'ssh' ? gitAddressText(address) : bare(url),
74
+ };
75
+ const other = address.kind === 'https'
76
+ ? { kind: 'ssh', url: gitAddressText({ kind: 'ssh', host: address.host, path: address.path }) }
77
+ : { kind: 'https', url: gitAddressText({ kind: 'https', host: address.host, path: address.path }) };
78
+ return other.url === primary.url ? [primary] : [primary, other];
79
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/shared",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "工作台与模块共享的纯代码与契约类型:类型、纯逻辑、哑组件、平台解析。宿主侧的东西从 /host 进(不影响浏览器产物)。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -2,6 +2,7 @@ export const MARKET_INDEX_FORMAT = 1;
2
2
  export const MARKET_INDEX_PATH = 'market.json';
3
3
  export const MARKET_DISCOVER_ROUTE = 'panels/market-discover';
4
4
  export const MARKET_DOC_ROUTE = 'panels/market-doc';
5
+ export const MARKET_GIT_PROBE_ROUTE = 'panels/git-probe';
5
6
  export const MARKET_PUBLISH_PREVIEW_ROUTE = 'panels/market-publish-preview';
6
7
  export const MARKET_SOURCES_RESOURCE = 'market-sources';
7
8
  export const MARKET_SOURCES_ROUTE = 'panels/market-sources';
@@ -9,6 +10,13 @@ export const MARKET_WORKBENCH_LABEL = 'workbench';
9
10
 
10
11
  export type MarketSourceKind = 'http' | 'git';
11
12
 
13
+ export type GitProbeStatus = 'ok' | 'auth' | 'unreachable';
14
+
15
+ export interface GitProbePayload {
16
+ readonly status: GitProbeStatus;
17
+ readonly detail?: string;
18
+ }
19
+
12
20
  export type MarketSourcePolicy = 'artifacts-in-repo' | 'catalog-only';
13
21
 
14
22
  export interface IndexSourceSpec {
package/src/host.ts CHANGED
@@ -15,6 +15,7 @@ export * from './contract/long-task.js';
15
15
  export * from './lib/text.js';
16
16
  export * from './lib/ui.js';
17
17
  export * from './lib/board-fact.js';
18
+ export * from './lib/git-address.js';
18
19
  export * from './api/blocker-table.js';
19
20
  export * from './contract/unit-declaration.js';
20
21
  export * from './host/board-fact.js';
package/src/i18n/en.ts CHANGED
@@ -258,6 +258,7 @@ export const en: Record<keyof WorkbenchMessages, string> = {
258
258
  'panels.market.add.failureInstalled':
259
259
  'It is already installed in this workbench. The same package cannot be installed over itself: uninstall it first, then install again. The uninstall did not succeed this time.',
260
260
  'panels.market.add.failureGeneric': 'Something went wrong during install — see the install details',
261
+ 'panels.market.add.failureCredentials': 'This repository needs credentials: this machine has none for it. Clone it once in a terminal, set up a credential helper, or install from the SSH address.',
261
262
  'panels.market.add.approveTitle': 'Your approval is needed for install scripts',
262
263
  'panels.market.add.approveCaution': 'Only allow packages you trust: install scripts run on this machine with your permissions.',
263
264
  'panels.market.add.approveRun': 'Allow and continue installing',
@@ -330,6 +331,7 @@ export const en: Record<keyof WorkbenchMessages, string> = {
330
331
  'panels.discover.noSourceHint': 'Add a module market index (http address or git repository) to browse and install its modules here',
331
332
  'panels.discover.sourcesFailed': 'Could not read the index sources.',
332
333
  'panels.discover.unreadable': 'Could not read this index.',
334
+ 'panels.discover.sourceAuth': 'This index source could not be read: this machine has no git credentials for it. Set up credentials (or switch the source to its SSH address), then refresh.',
333
335
  'panels.discover.invalid': 'This index is not in a valid format.',
334
336
  'panels.discover.emptyRepo': 'This repository has no commits yet.',
335
337
  'panels.discover.missingIndex': 'This repository has no {path} yet.',
@@ -353,8 +355,23 @@ export const en: Record<keyof WorkbenchMessages, string> = {
353
355
  'panels.discover.badShellDetail': 'This version is not compatible with the running workbench {current}; it requires {peer}',
354
356
  'panels.discover.unverified': 'Workbench unverified',
355
357
  'panels.discover.installing': 'Installing…',
358
+ 'panels.discover.installingNamed': 'Installing {name}…',
359
+ 'panels.discover.cancelInstall': 'Cancel install',
360
+ 'panels.discover.cancelling': 'Cancelling…',
361
+ 'panels.discover.installCancelled': 'Install cancelled: {name}',
356
362
  'panels.discover.installedDone': 'Installed: {name}',
357
363
  'panels.discover.failed': 'Failed: {reason}',
364
+ 'panels.discover.transportTitle': 'Where to read this repository',
365
+ 'panels.discover.transportSsh': 'SSH',
366
+ 'panels.discover.transportHttps': 'HTTPS',
367
+ 'panels.discover.transportOk': 'Readable',
368
+ 'panels.discover.transportAuth': 'Needs credentials',
369
+ 'panels.discover.transportUnreachable': 'Unreachable',
370
+ 'panels.discover.transportUnknown': 'Not probed',
371
+ 'panels.discover.transportChecking': 'Checking…',
372
+ 'panels.discover.transportTest': 'Test this address',
373
+ 'panels.discover.transportPlaceholder': 'Or paste another address (mirror, alias)',
374
+ 'panels.discover.transportNeedsAuth': 'This repository needs credentials: clone it once in a terminal, or set up an SSH key / credential helper, then install again.',
358
375
  'panels.discover.expand': 'Show versions',
359
376
  'panels.discover.collapse': 'Hide versions',
360
377
  'panels.discover.versionCount': '{n} versions',
package/src/i18n/zh.ts CHANGED
@@ -255,6 +255,7 @@ export const zh = {
255
255
  'panels.market.add.failureInstalled':
256
256
  '它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。',
257
257
  'panels.market.add.failureGeneric': '安装过程中出错,原因见安装详情',
258
+ 'panels.market.add.failureCredentials': '这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。',
258
259
  'panels.market.add.approveTitle': '需要你允许安装脚本',
259
260
  'panels.market.add.approveCaution': '只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。',
260
261
  'panels.market.add.approveRun': '允许并继续安装',
@@ -327,6 +328,7 @@ export const zh = {
327
328
  'panels.discover.noSourceHint': '添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块',
328
329
  'panels.discover.sourcesFailed': '无法读取索引源',
329
330
  'panels.discover.unreadable': '无法读取此索引',
331
+ 'panels.discover.sourceAuth': '这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。',
330
332
  'panels.discover.invalid': '此索引的格式无效',
331
333
  'panels.discover.emptyRepo': '这个仓库还没有任何提交',
332
334
  'panels.discover.missingIndex': '仓库里还没有索引文件 {path}',
@@ -350,8 +352,23 @@ export const zh = {
350
352
  'panels.discover.badShellDetail': '此版本与当前的工作台 {current} 不兼容,它要求 {peer}',
351
353
  'panels.discover.unverified': '工作台未验证',
352
354
  'panels.discover.installing': '正在安装…',
355
+ 'panels.discover.installingNamed': '正在安装「{name}」…',
356
+ 'panels.discover.cancelInstall': '取消安装',
357
+ 'panels.discover.cancelling': '正在取消…',
358
+ 'panels.discover.installCancelled': '已取消安装:{name}',
353
359
  'panels.discover.installedDone': '装好了:{name}',
354
360
  'panels.discover.failed': '操作失败:{reason}',
361
+ 'panels.discover.transportTitle': '从哪读这个仓库',
362
+ 'panels.discover.transportSsh': 'SSH',
363
+ 'panels.discover.transportHttps': 'HTTPS',
364
+ 'panels.discover.transportOk': '能读',
365
+ 'panels.discover.transportAuth': '要凭证',
366
+ 'panels.discover.transportUnreachable': '连不上',
367
+ 'panels.discover.transportUnknown': '没探成',
368
+ 'panels.discover.transportChecking': '正在探测…',
369
+ 'panels.discover.transportTest': '试这个地址',
370
+ 'panels.discover.transportPlaceholder': '或贴一个别的地址(公司镜像、别名)',
371
+ 'panels.discover.transportNeedsAuth': '这个仓库要凭证:先在终端里把它 clone 一次,或配好 SSH key / 凭据助手;配好后再点安装。',
355
372
  'panels.discover.expand': '展开版本',
356
373
  'panels.discover.collapse': '收起版本',
357
374
  'panels.discover.versionCount': '{n} 个版本',
package/src/index.ts CHANGED
@@ -66,6 +66,7 @@ export * from './i18n/settings.js';
66
66
  export * from './i18n/zh.js';
67
67
  export * from './lib/blocker-action.js';
68
68
  export * from './lib/market-index.js';
69
+ export * from './lib/git-address.js';
69
70
  export * from './lib/board-fact.js';
70
71
  export * from './lib/busy.js';
71
72
  export * from './lib/dsh-client.js';
@@ -0,0 +1,63 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { gitAddressOf, gitAddressText, gitTransportCandidates } from './git-address.js';
3
+
4
+ describe('git 地址的两种读法', () => {
5
+ it('https 原样留着,另一条推成 ssh://', () => {
6
+ expect(gitTransportCandidates('https://e.coding.net/org/repo.git')).toEqual([
7
+ { kind: 'https', url: 'https://e.coding.net/org/repo.git' },
8
+ { kind: 'ssh', url: 'ssh://git@e.coding.net/org/repo.git' },
9
+ ]);
10
+ });
11
+
12
+ it('scp 写法当 ssh,并规范成 ssh://(pnpm 只认这个)', () => {
13
+ expect(gitTransportCandidates('git@e.coding.net:org/repo.git')).toEqual([
14
+ { kind: 'ssh', url: 'ssh://git@e.coding.net/org/repo.git' },
15
+ { kind: 'https', url: 'https://e.coding.net/org/repo.git' },
16
+ ]);
17
+ });
18
+
19
+ it('git+ 前缀先剥掉,别带进 spec', () => {
20
+ expect(gitTransportCandidates('git+https://host/org/repo.git')[0]).toEqual({
21
+ kind: 'https',
22
+ url: 'https://host/org/repo.git',
23
+ });
24
+ });
25
+
26
+ it('端口只留在它本来那一种上,另一种回到默认端口', () => {
27
+ expect(gitTransportCandidates('ssh://git@host:2222/org/repo.git')).toEqual([
28
+ { kind: 'ssh', url: 'ssh://git@host:2222/org/repo.git' },
29
+ { kind: 'https', url: 'https://host/org/repo.git' },
30
+ ]);
31
+ expect(gitTransportCandidates('https://host:8443/org/repo.git')).toEqual([
32
+ { kind: 'https', url: 'https://host:8443/org/repo.git' },
33
+ { kind: 'ssh', url: 'ssh://git@host/org/repo.git' },
34
+ ]);
35
+ });
36
+
37
+ it('http 的仓库留着 http,别替发布者升到 https', () => {
38
+ expect(gitTransportCandidates('http://host/org/repo.git')[0]).toEqual({
39
+ kind: 'https',
40
+ url: 'http://host/org/repo.git',
41
+ });
42
+ });
43
+
44
+ it('拆得开要拆对,拆不开给 undefined', () => {
45
+ expect(gitAddressOf('https://host/a/b.git')).toEqual({ kind: 'https', host: 'host', path: 'a/b.git' });
46
+ expect(gitAddressOf('ssh://git@host:2222/a/b.git')).toEqual({
47
+ kind: 'ssh',
48
+ host: 'host',
49
+ path: 'a/b.git',
50
+ user: 'git',
51
+ port: 2222,
52
+ });
53
+ expect(gitAddressOf('git@host:a/b.git')).toEqual({ kind: 'ssh', host: 'host', path: 'a/b.git', user: 'git' });
54
+ expect(gitAddressOf('https://host/')).toBeUndefined();
55
+ expect(gitAddressOf('ftp://host/a.git')).toBeUndefined();
56
+ expect(gitAddressOf('')).toBeUndefined();
57
+ });
58
+
59
+ it('拼回去是规范写法,用户名缺省补 git', () => {
60
+ expect(gitAddressText({ kind: 'ssh', host: 'h', path: 'a/b.git' })).toBe('ssh://git@h/a/b.git');
61
+ expect(gitAddressText({ kind: 'https', host: 'h', path: 'a/b.git', port: 8443 })).toBe('https://h:8443/a/b.git');
62
+ });
63
+ });
@@ -0,0 +1,92 @@
1
+ export interface GitAddress {
2
+ readonly kind: 'https' | 'ssh';
3
+ readonly host: string;
4
+ readonly path: string;
5
+ readonly user?: string;
6
+ readonly port?: number;
7
+ }
8
+
9
+ export interface GitTransportCandidate {
10
+ readonly kind: 'https' | 'ssh';
11
+ readonly url: string;
12
+ }
13
+
14
+ const SCP = /^(?:([A-Za-z0-9._-]+)@)?([A-Za-z0-9.-]+):(?!\/)(\S+)$/;
15
+
16
+ function bare(url: string): string {
17
+ return url.trim().replace(/^git\+/, '');
18
+ }
19
+
20
+ function pathOf(pathname: string): string {
21
+ return pathname.replace(/^\/+/, '').replace(/\/+$/, '');
22
+ }
23
+
24
+ /**
25
+ * 把一个 git 地址拆成「哪台主机 + 哪个路径」,不管发布者当初用的是 https、ssh 还是
26
+ * scp 那种 `git@host:path` 写法;认不出来给 undefined。
27
+ */
28
+ export function gitAddressOf(url: string): GitAddress | undefined {
29
+ const text = bare(url);
30
+ if (text === '') return undefined;
31
+ if (text.includes('://')) {
32
+ let parsed: URL;
33
+ try {
34
+ parsed = new URL(text);
35
+ } catch {
36
+ return undefined;
37
+ }
38
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:' && parsed.protocol !== 'ssh:') {
39
+ return undefined;
40
+ }
41
+ const path = pathOf(parsed.pathname);
42
+ if (path === '') return undefined;
43
+ const port = parsed.port === '' ? undefined : Number(parsed.port);
44
+ const shared = {
45
+ host: parsed.hostname,
46
+ path,
47
+ ...(port === undefined ? {} : { port }),
48
+ };
49
+ if (parsed.protocol !== 'ssh:') return { kind: 'https', ...shared };
50
+ return { kind: 'ssh', ...shared, ...(parsed.username === '' ? {} : { user: parsed.username }) };
51
+ }
52
+ const scp = SCP.exec(text);
53
+ if (scp === null) return undefined;
54
+ const path = pathOf(scp[3] ?? '');
55
+ if (path === '') return undefined;
56
+ return {
57
+ kind: 'ssh',
58
+ host: scp[2] ?? '',
59
+ path,
60
+ ...(scp[1] === undefined ? {} : { user: scp[1] }),
61
+ };
62
+ }
63
+
64
+ /** 一份地址的规范写法:ssh 一律成 `ssh://user@host/path`(pnpm 认这个),https 原样。 */
65
+ export function gitAddressText(address: GitAddress): string {
66
+ const port = address.port === undefined ? '' : `:${String(address.port)}`;
67
+ if (address.kind === 'ssh') {
68
+ return `ssh://${address.user === undefined || address.user === '' ? 'git' : address.user}@${address.host}${port}/${address.path}`;
69
+ }
70
+ return `https://${address.host}${port}/${address.path}`;
71
+ }
72
+
73
+ /**
74
+ * 同一个仓库的两种读法,发布者用的那种排前面。ssh 那条一律规范成 `ssh://` 形式,
75
+ * 因为 `git@host:path` 拼进安装 spec 时 pnpm 不认;https 那条保留发布者的原样(含 http)。
76
+ */
77
+ export function gitTransportCandidates(url: string): readonly GitTransportCandidate[] {
78
+ const address = gitAddressOf(url);
79
+ if (address === undefined) {
80
+ const only = bare(url);
81
+ return only === '' ? [] : [{ kind: only.startsWith('ssh') ? 'ssh' : 'https', url: only }];
82
+ }
83
+ const primary: GitTransportCandidate = {
84
+ kind: address.kind,
85
+ url: address.kind === 'ssh' ? gitAddressText(address) : bare(url),
86
+ };
87
+ const other: GitTransportCandidate =
88
+ address.kind === 'https'
89
+ ? { kind: 'ssh', url: gitAddressText({ kind: 'ssh', host: address.host, path: address.path }) }
90
+ : { kind: 'https', url: gitAddressText({ kind: 'https', host: address.host, path: address.path }) };
91
+ return other.url === primary.url ? [primary] : [primary, other];
92
+ }