@dsh-workbench/shared 1.1.2 → 1.1.4

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.
@@ -1,3 +1,4 @@
1
+ import type { MarketInstalledModule } from './market-index.js';
1
2
  import type { UnitTitle } from '../unit.js';
2
3
  export declare const BUNDLE_REGISTRIES_ROUTE = "bundle-registries";
3
4
  export declare const BUNDLE_INSPECT_ROUTE = "bundle-inspect";
@@ -125,6 +126,7 @@ export interface ModuleVersion {
125
126
  readonly latestBlocked?: ModuleUpdateBlock;
126
127
  readonly local?: boolean;
127
128
  readonly refused?: readonly string[];
129
+ readonly market?: MarketInstalledModule;
128
130
  }
129
131
  export interface WorkbenchVersion {
130
132
  readonly pkg: string;
@@ -2,11 +2,18 @@ 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";
6
+ export declare const MARKET_INSTALLED_ROUTE = "panels/market-installed";
5
7
  export declare const MARKET_PUBLISH_PREVIEW_ROUTE = "panels/market-publish-preview";
6
8
  export declare const MARKET_SOURCES_RESOURCE = "market-sources";
7
9
  export declare const MARKET_SOURCES_ROUTE = "panels/market-sources";
8
10
  export declare const MARKET_WORKBENCH_LABEL = "workbench";
9
11
  export type MarketSourceKind = 'http' | 'git';
12
+ export type GitProbeStatus = 'ok' | 'auth' | 'unreachable';
13
+ export interface GitProbePayload {
14
+ readonly status: GitProbeStatus;
15
+ readonly detail?: string;
16
+ }
10
17
  export type MarketSourcePolicy = 'artifacts-in-repo' | 'catalog-only';
11
18
  export interface IndexSourceSpec {
12
19
  readonly kind: MarketSourceKind;
@@ -164,9 +171,22 @@ export interface DiscoverFilter {
164
171
  readonly category?: string;
165
172
  readonly label?: string;
166
173
  }
174
+ export type GitTransportKind = 'https' | 'ssh';
167
175
  export interface MarketSourcesPayload {
168
176
  readonly sources: readonly MarketSourceConfig[];
169
177
  readonly selected: string | null;
178
+ readonly transports?: Readonly<Record<string, GitTransportKind>>;
179
+ }
180
+ export interface MarketInstalledModule {
181
+ readonly pkg: string;
182
+ readonly unit: string;
183
+ readonly version: string;
184
+ readonly sourceId: string;
185
+ readonly sourceLabel: string;
186
+ readonly source: MarketIndexSource;
187
+ }
188
+ export interface MarketInstalledPayload {
189
+ readonly modules: readonly MarketInstalledModule[];
170
190
  }
171
191
  export interface MarketPublishDestination {
172
192
  readonly url: string;
@@ -2,6 +2,8 @@ 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';
6
+ export const MARKET_INSTALLED_ROUTE = 'panels/market-installed';
5
7
  export const MARKET_PUBLISH_PREVIEW_ROUTE = 'panels/market-publish-preview';
6
8
  export const MARKET_SOURCES_RESOURCE = 'market-sources';
7
9
  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
@@ -147,6 +147,7 @@ export const en = {
147
147
  'panels.market.confirmUninstallAck': 'I understand: using it again means reinstalling it.',
148
148
  'panels.market.confirmYes': 'Uninstall',
149
149
  'panels.market.confirmNo': 'Cancel',
150
+ 'panels.market.noMarketSource': 'The index has no newer version of this module (refresh the index and retry)',
150
151
  'panels.market.failed': 'Failed: {reason}',
151
152
  'panels.market.needEnv': 'Set {env} in the terminal that started the workbench first',
152
153
  'panels.market.needCommands': 'Missing commands: {commands}',
@@ -183,8 +184,9 @@ export const en = {
183
184
  'panels.market.pluginBroken': 'This plugin install is broken: it cannot be identified. Uninstall it first, then ask the agent to reinstall it by package name.',
184
185
  'panels.market.restartNeeded': 'The new version is installed — restart once to pick it up.',
185
186
  'panels.market.foot': 'After installing, enable it in the panel page of that project.',
186
- 'panels.market.recheck': 'Check for updates',
187
187
  'panels.market.checkUpdates': 'Check for updates',
188
+ 'panels.market.checkingNow': 'Checking…',
189
+ 'panels.market.checkFailed': 'The last check failed. Check your connection and retry.',
188
190
  'panels.market.checkedAt': 'Last checked: {time}',
189
191
  'panels.market.justNow': 'just now',
190
192
  'panels.market.minutesAgo': '{n} min ago',
@@ -248,6 +250,7 @@ export const en = {
248
250
  'panels.market.add.failurePnpmMissing': 'pnpm was not found, cannot install',
249
251
  '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
252
  'panels.market.add.failureGeneric': 'Something went wrong during install — see the install details',
253
+ '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
254
  'panels.market.add.approveTitle': 'Your approval is needed for install scripts',
252
255
  'panels.market.add.approveCaution': 'Only allow packages you trust: install scripts run on this machine with your permissions.',
253
256
  'panels.market.add.approveRun': 'Allow and continue installing',
@@ -320,6 +323,7 @@ export const en = {
320
323
  'panels.discover.noSourceHint': 'Add a module market index (http address or git repository) to browse and install its modules here',
321
324
  'panels.discover.sourcesFailed': 'Could not read the index sources.',
322
325
  'panels.discover.unreadable': 'Could not read this index.',
326
+ '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
327
  'panels.discover.invalid': 'This index is not in a valid format.',
324
328
  'panels.discover.emptyRepo': 'This repository has no commits yet.',
325
329
  'panels.discover.missingIndex': 'This repository has no {path} yet.',
@@ -343,8 +347,26 @@ export const en = {
343
347
  'panels.discover.badShellDetail': 'This version is not compatible with the running workbench {current}; it requires {peer}',
344
348
  'panels.discover.unverified': 'Workbench unverified',
345
349
  'panels.discover.installing': 'Installing…',
350
+ 'panels.discover.installingNamed': 'Installing {name}…',
351
+ 'panels.discover.cancelInstall': 'Cancel install',
352
+ 'panels.discover.cancelling': 'Cancelling…',
353
+ 'panels.discover.installCancelled': 'Install cancelled: {name}',
346
354
  'panels.discover.installedDone': 'Installed: {name}',
347
355
  'panels.discover.failed': 'Failed: {reason}',
356
+ 'panels.discover.transportTitle': 'Where to read this repository',
357
+ 'panels.discover.transportSsh': 'SSH',
358
+ 'panels.discover.transportHttps': 'HTTPS',
359
+ 'panels.discover.transportOk': 'Readable',
360
+ 'panels.discover.transportAuth': 'Needs credentials',
361
+ 'panels.discover.transportUnreachable': 'Unreachable',
362
+ 'panels.discover.transportUnknown': 'Not probed',
363
+ 'panels.discover.transportChecking': 'Checking…',
364
+ 'panels.discover.transportTest': 'Test this address',
365
+ 'panels.discover.transportPlaceholder': 'Or paste another address (mirror, alias)',
366
+ 'panels.discover.transportNeedsAuth': 'This repository needs credentials: clone it once in a terminal, or set up an SSH key / credential helper, then install again.',
367
+ 'panels.discover.transportChange': 'Change address',
368
+ 'panels.discover.transportChangeHide': 'Hide',
369
+ 'panels.discover.transportNone': 'No readable address',
348
370
  'panels.discover.expand': 'Show versions',
349
371
  'panels.discover.collapse': 'Hide versions',
350
372
  'panels.discover.versionCount': '{n} versions',
@@ -157,6 +157,7 @@ export declare const dictionaries: {
157
157
  readonly 'panels.market.confirmUninstallAck': "我明白:卸载后想再用,得重新装一遍。";
158
158
  readonly 'panels.market.confirmYes': "卸载";
159
159
  readonly 'panels.market.confirmNo': "取消";
160
+ readonly 'panels.market.noMarketSource': "索引里没有这个模块的新版本(刷新一次索引再试)";
160
161
  readonly 'panels.market.failed': "没成功:{reason}";
161
162
  readonly 'panels.market.needEnv': "先在启动工作台的终端里设 {env}";
162
163
  readonly 'panels.market.needCommands': "缺这几条命令:{commands}";
@@ -193,8 +194,9 @@ export declare const dictionaries: {
193
194
  readonly 'panels.market.pluginBroken': "这份插件装坏了:认不出它是什么。可以先卸载,再让 agent 按包名重装一次。";
194
195
  readonly 'panels.market.restartNeeded': "新版装好了,重启一次才生效。";
195
196
  readonly 'panels.market.foot': "装好后到那个项目的面板页勾选它,模块才会出现。";
196
- readonly 'panels.market.recheck': "重新检查更新";
197
197
  readonly 'panels.market.checkUpdates': "检查更新";
198
+ readonly 'panels.market.checkingNow': "正在检查…";
199
+ readonly 'panels.market.checkFailed': "最近一次没查到,检查网络后重试";
198
200
  readonly 'panels.market.checkedAt': "最近检查:{time}";
199
201
  readonly 'panels.market.justNow': "刚刚";
200
202
  readonly 'panels.market.minutesAgo': "{n} 分钟前";
@@ -258,6 +260,7 @@ export declare const dictionaries: {
258
260
  readonly 'panels.market.add.failurePnpmMissing': "没有找到 pnpm,无法安装";
259
261
  readonly 'panels.market.add.failureInstalled': "它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。";
260
262
  readonly 'panels.market.add.failureGeneric': "安装过程中出错,原因见安装详情";
263
+ readonly 'panels.market.add.failureCredentials': "这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。";
261
264
  readonly 'panels.market.add.approveTitle': "需要你允许安装脚本";
262
265
  readonly 'panels.market.add.approveCaution': "只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。";
263
266
  readonly 'panels.market.add.approveRun': "允许并继续安装";
@@ -330,6 +333,7 @@ export declare const dictionaries: {
330
333
  readonly 'panels.discover.noSourceHint': "添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块";
331
334
  readonly 'panels.discover.sourcesFailed': "无法读取索引源";
332
335
  readonly 'panels.discover.unreadable': "无法读取此索引";
336
+ readonly 'panels.discover.sourceAuth': "这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。";
333
337
  readonly 'panels.discover.invalid': "此索引的格式无效";
334
338
  readonly 'panels.discover.emptyRepo': "这个仓库还没有任何提交";
335
339
  readonly 'panels.discover.missingIndex': "仓库里还没有索引文件 {path}";
@@ -353,8 +357,26 @@ export declare const dictionaries: {
353
357
  readonly 'panels.discover.badShellDetail': "此版本与当前的工作台 {current} 不兼容,它要求 {peer}";
354
358
  readonly 'panels.discover.unverified': "工作台未验证";
355
359
  readonly 'panels.discover.installing': "正在安装…";
360
+ readonly 'panels.discover.installingNamed': "正在安装「{name}」…";
361
+ readonly 'panels.discover.cancelInstall': "取消安装";
362
+ readonly 'panels.discover.cancelling': "正在取消…";
363
+ readonly 'panels.discover.installCancelled': "已取消安装:{name}";
356
364
  readonly 'panels.discover.installedDone': "装好了:{name}";
357
365
  readonly 'panels.discover.failed': "操作失败:{reason}";
366
+ readonly 'panels.discover.transportTitle': "从哪读这个仓库";
367
+ readonly 'panels.discover.transportSsh': "SSH";
368
+ readonly 'panels.discover.transportHttps': "HTTPS";
369
+ readonly 'panels.discover.transportOk': "能读";
370
+ readonly 'panels.discover.transportAuth': "要凭证";
371
+ readonly 'panels.discover.transportUnreachable': "连不上";
372
+ readonly 'panels.discover.transportUnknown': "没探成";
373
+ readonly 'panels.discover.transportChecking': "正在探测…";
374
+ readonly 'panels.discover.transportTest': "试这个地址";
375
+ readonly 'panels.discover.transportPlaceholder': "或贴一个别的地址(公司镜像、别名)";
376
+ readonly 'panels.discover.transportNeedsAuth': "这个仓库要凭证:先在终端里把它 clone 一次,或配好 SSH key / 凭据助手;配好后再点安装。";
377
+ readonly 'panels.discover.transportChange': "换一个地址";
378
+ readonly 'panels.discover.transportChangeHide': "收起";
379
+ readonly 'panels.discover.transportNone': "没有可读的地址";
358
380
  readonly 'panels.discover.expand': "展开版本";
359
381
  readonly 'panels.discover.collapse': "收起版本";
360
382
  readonly 'panels.discover.versionCount': "{n} 个版本";
@@ -735,7 +757,7 @@ export declare const dictionaries: {
735
757
  readonly 'configSync.emptyProviders': "工作台还没有任何模型供应商 —— 去「配置同步」从某个 profile 把模型供应商那几行同步过来,或自己去「模型」里配。";
736
758
  readonly 'configSync.failed': "同步没成功,再试一次。";
737
759
  };
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>;
760
+ 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.noMarketSource" | "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.checkUpdates" | "panels.market.checkingNow" | "panels.market.checkFailed" | "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.transportChange" | "panels.discover.transportChangeHide" | "panels.discover.transportNone" | "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
761
  };
740
762
  /** 中文词表的键类型(从 `zh.ts` 转出):`en` 与模块词表都得覆盖同一批键。 */
741
763
  export type { WorkbenchMessages };
package/dist/i18n/zh.d.ts CHANGED
@@ -155,6 +155,7 @@ export declare const zh: {
155
155
  readonly 'panels.market.confirmUninstallAck': "我明白:卸载后想再用,得重新装一遍。";
156
156
  readonly 'panels.market.confirmYes': "卸载";
157
157
  readonly 'panels.market.confirmNo': "取消";
158
+ readonly 'panels.market.noMarketSource': "索引里没有这个模块的新版本(刷新一次索引再试)";
158
159
  readonly 'panels.market.failed': "没成功:{reason}";
159
160
  readonly 'panels.market.needEnv': "先在启动工作台的终端里设 {env}";
160
161
  readonly 'panels.market.needCommands': "缺这几条命令:{commands}";
@@ -191,8 +192,9 @@ export declare const zh: {
191
192
  readonly 'panels.market.pluginBroken': "这份插件装坏了:认不出它是什么。可以先卸载,再让 agent 按包名重装一次。";
192
193
  readonly 'panels.market.restartNeeded': "新版装好了,重启一次才生效。";
193
194
  readonly 'panels.market.foot': "装好后到那个项目的面板页勾选它,模块才会出现。";
194
- readonly 'panels.market.recheck': "重新检查更新";
195
195
  readonly 'panels.market.checkUpdates': "检查更新";
196
+ readonly 'panels.market.checkingNow': "正在检查…";
197
+ readonly 'panels.market.checkFailed': "最近一次没查到,检查网络后重试";
196
198
  readonly 'panels.market.checkedAt': "最近检查:{time}";
197
199
  readonly 'panels.market.justNow': "刚刚";
198
200
  readonly 'panels.market.minutesAgo': "{n} 分钟前";
@@ -256,6 +258,7 @@ export declare const zh: {
256
258
  readonly 'panels.market.add.failurePnpmMissing': "没有找到 pnpm,无法安装";
257
259
  readonly 'panels.market.add.failureInstalled': "它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。";
258
260
  readonly 'panels.market.add.failureGeneric': "安装过程中出错,原因见安装详情";
261
+ readonly 'panels.market.add.failureCredentials': "这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。";
259
262
  readonly 'panels.market.add.approveTitle': "需要你允许安装脚本";
260
263
  readonly 'panels.market.add.approveCaution': "只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。";
261
264
  readonly 'panels.market.add.approveRun': "允许并继续安装";
@@ -328,6 +331,7 @@ export declare const zh: {
328
331
  readonly 'panels.discover.noSourceHint': "添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块";
329
332
  readonly 'panels.discover.sourcesFailed': "无法读取索引源";
330
333
  readonly 'panels.discover.unreadable': "无法读取此索引";
334
+ readonly 'panels.discover.sourceAuth': "这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。";
331
335
  readonly 'panels.discover.invalid': "此索引的格式无效";
332
336
  readonly 'panels.discover.emptyRepo': "这个仓库还没有任何提交";
333
337
  readonly 'panels.discover.missingIndex': "仓库里还没有索引文件 {path}";
@@ -351,8 +355,26 @@ export declare const zh: {
351
355
  readonly 'panels.discover.badShellDetail': "此版本与当前的工作台 {current} 不兼容,它要求 {peer}";
352
356
  readonly 'panels.discover.unverified': "工作台未验证";
353
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}";
354
362
  readonly 'panels.discover.installedDone': "装好了:{name}";
355
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 / 凭据助手;配好后再点安装。";
375
+ readonly 'panels.discover.transportChange': "换一个地址";
376
+ readonly 'panels.discover.transportChangeHide': "收起";
377
+ readonly 'panels.discover.transportNone': "没有可读的地址";
356
378
  readonly 'panels.discover.expand': "展开版本";
357
379
  readonly 'panels.discover.collapse': "收起版本";
358
380
  readonly 'panels.discover.versionCount': "{n} 个版本";
package/dist/i18n/zh.js CHANGED
@@ -147,6 +147,7 @@ export const zh = {
147
147
  'panels.market.confirmUninstallAck': '我明白:卸载后想再用,得重新装一遍。',
148
148
  'panels.market.confirmYes': '卸载',
149
149
  'panels.market.confirmNo': '取消',
150
+ 'panels.market.noMarketSource': '索引里没有这个模块的新版本(刷新一次索引再试)',
150
151
  'panels.market.failed': '没成功:{reason}',
151
152
  'panels.market.needEnv': '先在启动工作台的终端里设 {env}',
152
153
  'panels.market.needCommands': '缺这几条命令:{commands}',
@@ -183,8 +184,9 @@ export const zh = {
183
184
  'panels.market.pluginBroken': '这份插件装坏了:认不出它是什么。可以先卸载,再让 agent 按包名重装一次。',
184
185
  'panels.market.restartNeeded': '新版装好了,重启一次才生效。',
185
186
  'panels.market.foot': '装好后到那个项目的面板页勾选它,模块才会出现。',
186
- 'panels.market.recheck': '重新检查更新',
187
187
  'panels.market.checkUpdates': '检查更新',
188
+ 'panels.market.checkingNow': '正在检查…',
189
+ 'panels.market.checkFailed': '最近一次没查到,检查网络后重试',
188
190
  'panels.market.checkedAt': '最近检查:{time}',
189
191
  'panels.market.justNow': '刚刚',
190
192
  'panels.market.minutesAgo': '{n} 分钟前',
@@ -248,6 +250,7 @@ export const zh = {
248
250
  'panels.market.add.failurePnpmMissing': '没有找到 pnpm,无法安装',
249
251
  'panels.market.add.failureInstalled': '它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。',
250
252
  'panels.market.add.failureGeneric': '安装过程中出错,原因见安装详情',
253
+ 'panels.market.add.failureCredentials': '这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。',
251
254
  'panels.market.add.approveTitle': '需要你允许安装脚本',
252
255
  'panels.market.add.approveCaution': '只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。',
253
256
  'panels.market.add.approveRun': '允许并继续安装',
@@ -320,6 +323,7 @@ export const zh = {
320
323
  'panels.discover.noSourceHint': '添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块',
321
324
  'panels.discover.sourcesFailed': '无法读取索引源',
322
325
  'panels.discover.unreadable': '无法读取此索引',
326
+ 'panels.discover.sourceAuth': '这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。',
323
327
  'panels.discover.invalid': '此索引的格式无效',
324
328
  'panels.discover.emptyRepo': '这个仓库还没有任何提交',
325
329
  'panels.discover.missingIndex': '仓库里还没有索引文件 {path}',
@@ -343,8 +347,26 @@ export const zh = {
343
347
  'panels.discover.badShellDetail': '此版本与当前的工作台 {current} 不兼容,它要求 {peer}',
344
348
  'panels.discover.unverified': '工作台未验证',
345
349
  'panels.discover.installing': '正在安装…',
350
+ 'panels.discover.installingNamed': '正在安装「{name}」…',
351
+ 'panels.discover.cancelInstall': '取消安装',
352
+ 'panels.discover.cancelling': '正在取消…',
353
+ 'panels.discover.installCancelled': '已取消安装:{name}',
346
354
  'panels.discover.installedDone': '装好了:{name}',
347
355
  'panels.discover.failed': '操作失败:{reason}',
356
+ 'panels.discover.transportTitle': '从哪读这个仓库',
357
+ 'panels.discover.transportSsh': 'SSH',
358
+ 'panels.discover.transportHttps': 'HTTPS',
359
+ 'panels.discover.transportOk': '能读',
360
+ 'panels.discover.transportAuth': '要凭证',
361
+ 'panels.discover.transportUnreachable': '连不上',
362
+ 'panels.discover.transportUnknown': '没探成',
363
+ 'panels.discover.transportChecking': '正在探测…',
364
+ 'panels.discover.transportTest': '试这个地址',
365
+ 'panels.discover.transportPlaceholder': '或贴一个别的地址(公司镜像、别名)',
366
+ 'panels.discover.transportNeedsAuth': '这个仓库要凭证:先在终端里把它 clone 一次,或配好 SSH key / 凭据助手;配好后再点安装。',
367
+ 'panels.discover.transportChange': '换一个地址',
368
+ 'panels.discover.transportChangeHide': '收起',
369
+ 'panels.discover.transportNone': '没有可读的地址',
348
370
  'panels.discover.expand': '展开版本',
349
371
  'panels.discover.collapse': '收起版本',
350
372
  '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.4",
4
4
  "description": "工作台与模块共享的纯代码与契约类型:类型、纯逻辑、哑组件、平台解析。宿主侧的东西从 /host 进(不影响浏览器产物)。",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,3 +1,4 @@
1
+ import type { MarketInstalledModule } from './market-index.js';
1
2
  import type { UnitTitle } from '../unit.js';
2
3
 
3
4
  export const BUNDLE_REGISTRIES_ROUTE = 'bundle-registries';
@@ -187,6 +188,7 @@ export interface ModuleVersion {
187
188
  readonly latestBlocked?: ModuleUpdateBlock;
188
189
  readonly local?: boolean;
189
190
  readonly refused?: readonly string[];
191
+ readonly market?: MarketInstalledModule;
190
192
  }
191
193
 
192
194
  export interface WorkbenchVersion {
@@ -2,6 +2,8 @@ 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';
6
+ export const MARKET_INSTALLED_ROUTE = 'panels/market-installed';
5
7
  export const MARKET_PUBLISH_PREVIEW_ROUTE = 'panels/market-publish-preview';
6
8
  export const MARKET_SOURCES_RESOURCE = 'market-sources';
7
9
  export const MARKET_SOURCES_ROUTE = 'panels/market-sources';
@@ -9,6 +11,13 @@ export const MARKET_WORKBENCH_LABEL = 'workbench';
9
11
 
10
12
  export type MarketSourceKind = 'http' | 'git';
11
13
 
14
+ export type GitProbeStatus = 'ok' | 'auth' | 'unreachable';
15
+
16
+ export interface GitProbePayload {
17
+ readonly status: GitProbeStatus;
18
+ readonly detail?: string;
19
+ }
20
+
12
21
  export type MarketSourcePolicy = 'artifacts-in-repo' | 'catalog-only';
13
22
 
14
23
  export interface IndexSourceSpec {
@@ -209,9 +218,25 @@ export interface DiscoverFilter {
209
218
  readonly label?: string;
210
219
  }
211
220
 
221
+ export type GitTransportKind = 'https' | 'ssh';
222
+
212
223
  export interface MarketSourcesPayload {
213
224
  readonly sources: readonly MarketSourceConfig[];
214
225
  readonly selected: string | null;
226
+ readonly transports?: Readonly<Record<string, GitTransportKind>>;
227
+ }
228
+
229
+ export interface MarketInstalledModule {
230
+ readonly pkg: string;
231
+ readonly unit: string;
232
+ readonly version: string;
233
+ readonly sourceId: string;
234
+ readonly sourceLabel: string;
235
+ readonly source: MarketIndexSource;
236
+ }
237
+
238
+ export interface MarketInstalledPayload {
239
+ readonly modules: readonly MarketInstalledModule[];
215
240
  }
216
241
 
217
242
  export interface MarketPublishDestination {
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
@@ -154,6 +154,7 @@ export const en: Record<keyof WorkbenchMessages, string> = {
154
154
  'I understand: using it again means reinstalling it.',
155
155
  'panels.market.confirmYes': 'Uninstall',
156
156
  'panels.market.confirmNo': 'Cancel',
157
+ 'panels.market.noMarketSource': 'The index has no newer version of this module (refresh the index and retry)',
157
158
  'panels.market.failed': 'Failed: {reason}',
158
159
  'panels.market.needEnv': 'Set {env} in the terminal that started the workbench first',
159
160
  'panels.market.needCommands': 'Missing commands: {commands}',
@@ -190,8 +191,9 @@ export const en: Record<keyof WorkbenchMessages, string> = {
190
191
  'panels.market.pluginBroken': 'This plugin install is broken: it cannot be identified. Uninstall it first, then ask the agent to reinstall it by package name.',
191
192
  'panels.market.restartNeeded': 'The new version is installed — restart once to pick it up.',
192
193
  'panels.market.foot': 'After installing, enable it in the panel page of that project.',
193
- 'panels.market.recheck': 'Check for updates',
194
194
  'panels.market.checkUpdates': 'Check for updates',
195
+ 'panels.market.checkingNow': 'Checking…',
196
+ 'panels.market.checkFailed': 'The last check failed. Check your connection and retry.',
195
197
  'panels.market.checkedAt': 'Last checked: {time}',
196
198
  'panels.market.justNow': 'just now',
197
199
  'panels.market.minutesAgo': '{n} min ago',
@@ -258,6 +260,7 @@ export const en: Record<keyof WorkbenchMessages, string> = {
258
260
  'panels.market.add.failureInstalled':
259
261
  '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
262
  'panels.market.add.failureGeneric': 'Something went wrong during install — see the install details',
263
+ '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
264
  'panels.market.add.approveTitle': 'Your approval is needed for install scripts',
262
265
  'panels.market.add.approveCaution': 'Only allow packages you trust: install scripts run on this machine with your permissions.',
263
266
  'panels.market.add.approveRun': 'Allow and continue installing',
@@ -330,6 +333,7 @@ export const en: Record<keyof WorkbenchMessages, string> = {
330
333
  'panels.discover.noSourceHint': 'Add a module market index (http address or git repository) to browse and install its modules here',
331
334
  'panels.discover.sourcesFailed': 'Could not read the index sources.',
332
335
  'panels.discover.unreadable': 'Could not read this index.',
336
+ '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
337
  'panels.discover.invalid': 'This index is not in a valid format.',
334
338
  'panels.discover.emptyRepo': 'This repository has no commits yet.',
335
339
  'panels.discover.missingIndex': 'This repository has no {path} yet.',
@@ -353,8 +357,26 @@ export const en: Record<keyof WorkbenchMessages, string> = {
353
357
  'panels.discover.badShellDetail': 'This version is not compatible with the running workbench {current}; it requires {peer}',
354
358
  'panels.discover.unverified': 'Workbench unverified',
355
359
  'panels.discover.installing': 'Installing…',
360
+ 'panels.discover.installingNamed': 'Installing {name}…',
361
+ 'panels.discover.cancelInstall': 'Cancel install',
362
+ 'panels.discover.cancelling': 'Cancelling…',
363
+ 'panels.discover.installCancelled': 'Install cancelled: {name}',
356
364
  'panels.discover.installedDone': 'Installed: {name}',
357
365
  'panels.discover.failed': 'Failed: {reason}',
366
+ 'panels.discover.transportTitle': 'Where to read this repository',
367
+ 'panels.discover.transportSsh': 'SSH',
368
+ 'panels.discover.transportHttps': 'HTTPS',
369
+ 'panels.discover.transportOk': 'Readable',
370
+ 'panels.discover.transportAuth': 'Needs credentials',
371
+ 'panels.discover.transportUnreachable': 'Unreachable',
372
+ 'panels.discover.transportUnknown': 'Not probed',
373
+ 'panels.discover.transportChecking': 'Checking…',
374
+ 'panels.discover.transportTest': 'Test this address',
375
+ 'panels.discover.transportPlaceholder': 'Or paste another address (mirror, alias)',
376
+ 'panels.discover.transportNeedsAuth': 'This repository needs credentials: clone it once in a terminal, or set up an SSH key / credential helper, then install again.',
377
+ 'panels.discover.transportChange': 'Change address',
378
+ 'panels.discover.transportChangeHide': 'Hide',
379
+ 'panels.discover.transportNone': 'No readable address',
358
380
  'panels.discover.expand': 'Show versions',
359
381
  'panels.discover.collapse': 'Hide versions',
360
382
  'panels.discover.versionCount': '{n} versions',
package/src/i18n/zh.ts CHANGED
@@ -151,6 +151,7 @@ export const zh = {
151
151
  'panels.market.confirmUninstallAck': '我明白:卸载后想再用,得重新装一遍。',
152
152
  'panels.market.confirmYes': '卸载',
153
153
  'panels.market.confirmNo': '取消',
154
+ 'panels.market.noMarketSource': '索引里没有这个模块的新版本(刷新一次索引再试)',
154
155
  'panels.market.failed': '没成功:{reason}',
155
156
  'panels.market.needEnv': '先在启动工作台的终端里设 {env}',
156
157
  'panels.market.needCommands': '缺这几条命令:{commands}',
@@ -187,8 +188,9 @@ export const zh = {
187
188
  'panels.market.pluginBroken': '这份插件装坏了:认不出它是什么。可以先卸载,再让 agent 按包名重装一次。',
188
189
  'panels.market.restartNeeded': '新版装好了,重启一次才生效。',
189
190
  'panels.market.foot': '装好后到那个项目的面板页勾选它,模块才会出现。',
190
- 'panels.market.recheck': '重新检查更新',
191
191
  'panels.market.checkUpdates': '检查更新',
192
+ 'panels.market.checkingNow': '正在检查…',
193
+ 'panels.market.checkFailed': '最近一次没查到,检查网络后重试',
192
194
  'panels.market.checkedAt': '最近检查:{time}',
193
195
  'panels.market.justNow': '刚刚',
194
196
  'panels.market.minutesAgo': '{n} 分钟前',
@@ -255,6 +257,7 @@ export const zh = {
255
257
  'panels.market.add.failureInstalled':
256
258
  '它已经装在这份工作台里了。同一个包不能就地覆盖,得先卸载再装;这次卸载也没成功。',
257
259
  'panels.market.add.failureGeneric': '安装过程中出错,原因见安装详情',
260
+ 'panels.market.add.failureCredentials': '这个仓库要凭证:本机没有它的 git 凭据。先在终端里 clone 一次、配好凭据助手,或改用 SSH 地址,再装一次。',
258
261
  'panels.market.add.approveTitle': '需要你允许安装脚本',
259
262
  'panels.market.add.approveCaution': '只允许你信得过的包:安装脚本会以你的权限在这台机器上运行。',
260
263
  'panels.market.add.approveRun': '允许并继续安装',
@@ -327,6 +330,7 @@ export const zh = {
327
330
  'panels.discover.noSourceHint': '添加一个模块市场索引(http 地址或 git 仓库),即可在这里浏览和安装其中的模块',
328
331
  'panels.discover.sourcesFailed': '无法读取索引源',
329
332
  'panels.discover.unreadable': '无法读取此索引',
333
+ 'panels.discover.sourceAuth': '这个索引源读不了:本机没有它的 git 凭据。配好凭据(或在源里改用 SSH 地址),再点右上角的刷新。',
330
334
  'panels.discover.invalid': '此索引的格式无效',
331
335
  'panels.discover.emptyRepo': '这个仓库还没有任何提交',
332
336
  'panels.discover.missingIndex': '仓库里还没有索引文件 {path}',
@@ -350,8 +354,26 @@ export const zh = {
350
354
  'panels.discover.badShellDetail': '此版本与当前的工作台 {current} 不兼容,它要求 {peer}',
351
355
  'panels.discover.unverified': '工作台未验证',
352
356
  'panels.discover.installing': '正在安装…',
357
+ 'panels.discover.installingNamed': '正在安装「{name}」…',
358
+ 'panels.discover.cancelInstall': '取消安装',
359
+ 'panels.discover.cancelling': '正在取消…',
360
+ 'panels.discover.installCancelled': '已取消安装:{name}',
353
361
  'panels.discover.installedDone': '装好了:{name}',
354
362
  'panels.discover.failed': '操作失败:{reason}',
363
+ 'panels.discover.transportTitle': '从哪读这个仓库',
364
+ 'panels.discover.transportSsh': 'SSH',
365
+ 'panels.discover.transportHttps': 'HTTPS',
366
+ 'panels.discover.transportOk': '能读',
367
+ 'panels.discover.transportAuth': '要凭证',
368
+ 'panels.discover.transportUnreachable': '连不上',
369
+ 'panels.discover.transportUnknown': '没探成',
370
+ 'panels.discover.transportChecking': '正在探测…',
371
+ 'panels.discover.transportTest': '试这个地址',
372
+ 'panels.discover.transportPlaceholder': '或贴一个别的地址(公司镜像、别名)',
373
+ 'panels.discover.transportNeedsAuth': '这个仓库要凭证:先在终端里把它 clone 一次,或配好 SSH key / 凭据助手;配好后再点安装。',
374
+ 'panels.discover.transportChange': '换一个地址',
375
+ 'panels.discover.transportChangeHide': '收起',
376
+ 'panels.discover.transportNone': '没有可读的地址',
355
377
  'panels.discover.expand': '展开版本',
356
378
  'panels.discover.collapse': '收起版本',
357
379
  '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
+ }