dsh-config-manager 0.1.78 → 0.1.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/lib/adapters/credentials.d.ts +6 -2
  2. package/lib/adapters/credentials.js +19 -3
  3. package/lib/adapters/file-collection.js +2 -1
  4. package/lib/adapters/mcp.d.ts +48 -2
  5. package/lib/adapters/mcp.js +265 -3
  6. package/lib/adapters/messages.d.ts +3 -0
  7. package/lib/adapters/messages.js +7 -0
  8. package/lib/adapters/plugin-files.js +2 -1
  9. package/lib/adapters/plugins.js +105 -20
  10. package/lib/adapters/pnpm-workspace.d.ts +32 -0
  11. package/lib/adapters/pnpm-workspace.js +113 -2
  12. package/lib/adapters/prompts.d.ts +6 -2
  13. package/lib/adapters/prompts.js +17 -2
  14. package/lib/adapters/providers.d.ts +19 -2
  15. package/lib/adapters/providers.js +59 -3
  16. package/lib/adapters/settings.d.ts +6 -2
  17. package/lib/adapters/settings.js +13 -2
  18. package/lib/adapters/skills.d.ts +25 -1
  19. package/lib/adapters/skills.js +60 -0
  20. package/lib/adapters/ui.d.ts +6 -2
  21. package/lib/adapters/ui.js +13 -2
  22. package/lib/adapters/units.d.ts +18 -0
  23. package/lib/adapters/units.js +39 -0
  24. package/lib/adapters/workspaces.js +2 -1
  25. package/lib/client.d.ts +401 -112
  26. package/lib/client.js +2899 -1525
  27. package/lib/core/backup.js +20 -0
  28. package/lib/core/mcp-connector-store.d.ts +159 -0
  29. package/lib/core/mcp-connector-store.js +445 -0
  30. package/lib/core/messages-core.d.ts +2 -0
  31. package/lib/core/messages-core.js +4 -0
  32. package/lib/core/messages.d.ts +20 -0
  33. package/lib/core/messages.js +44 -0
  34. package/lib/core/phase3-host.js +18 -1
  35. package/lib/core/plugin-cli.d.ts +22 -2
  36. package/lib/core/plugin-cli.js +22 -3
  37. package/lib/core/recovery-orchestrator.d.ts +3 -1
  38. package/lib/core/recovery-orchestrator.js +75 -16
  39. package/lib/core/rollback-activity.d.ts +89 -0
  40. package/lib/core/rollback-activity.js +350 -0
  41. package/lib/core/rollback-ledger.d.ts +0 -9
  42. package/lib/core/rollback-ledger.js +37 -0
  43. package/lib/core/rollback-merge.d.ts +22 -2
  44. package/lib/core/rollback-merge.js +63 -13
  45. package/lib/core/rollback-point.d.ts +93 -0
  46. package/lib/core/rollback-point.js +420 -101
  47. package/lib/core/rollback-undo-journal.d.ts +123 -0
  48. package/lib/core/rollback-undo-journal.js +517 -0
  49. package/lib/core/self-update.js +2 -4
  50. package/lib/core/text-fidelity.d.ts +89 -0
  51. package/lib/core/text-fidelity.js +176 -0
  52. package/lib/core/types.d.ts +12 -3
  53. package/lib/core/update-check.js +2 -4
  54. package/lib/core/validator.d.ts +9 -0
  55. package/lib/core/validator.js +12 -0
  56. package/lib/foreign/bundle.js +42 -3
  57. package/lib/foreign/claude-code.js +358 -26
  58. package/lib/foreign/claude-sessions.d.ts +51 -8
  59. package/lib/foreign/claude-sessions.js +111 -13
  60. package/lib/foreign/read-claude-code.d.ts +33 -4
  61. package/lib/foreign/read-claude-code.js +446 -65
  62. package/lib/foreign/read-claude-plugins.d.ts +36 -0
  63. package/lib/foreign/read-claude-plugins.js +403 -0
  64. package/lib/foreign/registry.js +25 -2
  65. package/lib/foreign/truth-table.js +6 -4
  66. package/lib/foreign/types.d.ts +170 -2
  67. package/lib/index.d.ts +14 -5
  68. package/lib/index.js +60 -16
  69. package/lib/market/git-file-writer.js +7 -1
  70. package/lib/profiles/dsh-profile-launcher.d.ts +20 -0
  71. package/lib/profiles/dsh-profile-launcher.js +58 -1
  72. package/lib/profiles/dsh-profile-shared.d.ts +8 -2
  73. package/lib/profiles/dsh-profile-shared.js +8 -2
  74. package/lib/routes/foreign.js +8 -1
  75. package/lib/routes/index.d.ts +1 -1
  76. package/lib/routes/kit.d.ts +2 -2
  77. package/lib/routes/sync.js +173 -9
  78. package/lib/schema/manifest.d.ts +6 -1
  79. package/lib/schema/manifest.js +55 -0
  80. package/lib/schema/types.d.ts +47 -2
  81. package/lib/sync/ancestor.d.ts +22 -0
  82. package/lib/sync/ancestor.js +66 -2
  83. package/lib/sync/autosync-config.d.ts +73 -0
  84. package/lib/sync/autosync-config.js +89 -0
  85. package/lib/sync/autosync-scheduler.d.ts +80 -6
  86. package/lib/sync/autosync-scheduler.js +263 -40
  87. package/lib/sync/gist/gist-transport.d.ts +18 -1
  88. package/lib/sync/gist/gist-transport.js +42 -3
  89. package/lib/sync/gist/messages.d.ts +2 -0
  90. package/lib/sync/gist/messages.js +5 -0
  91. package/lib/sync/git/git-transport.d.ts +42 -3
  92. package/lib/sync/git/git-transport.js +146 -3
  93. package/lib/sync/merge.d.ts +47 -14
  94. package/lib/sync/merge.js +242 -222
  95. package/lib/sync/messages.d.ts +8 -0
  96. package/lib/sync/messages.js +19 -0
  97. package/lib/sync/risk.d.ts +19 -2
  98. package/lib/sync/risk.js +10 -3
  99. package/lib/sync/s3/messages.d.ts +6 -0
  100. package/lib/sync/s3/messages.js +13 -0
  101. package/lib/sync/s3/s3-transport.d.ts +9 -1
  102. package/lib/sync/s3/s3-transport.js +78 -6
  103. package/lib/sync/s3/sigv4.js +11 -2
  104. package/lib/sync/sync-engine.d.ts +212 -8
  105. package/lib/sync/sync-engine.js +514 -58
  106. package/lib/sync/sync-history.d.ts +11 -0
  107. package/lib/sync/sync-history.js +20 -0
  108. package/lib/sync/sync-state.d.ts +43 -0
  109. package/lib/sync/sync-state.js +44 -0
  110. package/lib/sync/sync-watcher.d.ts +76 -0
  111. package/lib/sync/sync-watcher.js +202 -0
  112. package/lib/sync/text-merge.d.ts +85 -0
  113. package/lib/sync/text-merge.js +513 -0
  114. package/lib/sync/transport.d.ts +48 -0
  115. package/lib/sync/transport.js +12 -0
  116. package/lib/sync/watch-scope.d.ts +38 -0
  117. package/lib/sync/watch-scope.js +95 -0
  118. package/lib/sync/webdav/webdav-transport.d.ts +16 -2
  119. package/lib/sync/webdav/webdav-transport.js +128 -11
  120. package/lib/ui/foreign-view.js +10 -0
  121. package/lib/ui/i18n.d.ts +9 -0
  122. package/lib/ui/i18n.js +22 -0
  123. package/lib/ui/rollback-view.d.ts +12 -0
  124. package/lib/ui/rollback-view.js +2 -0
  125. package/lib/ui/sync-settings-view.d.ts +47 -0
  126. package/lib/ui/sync-settings-view.js +24 -0
  127. package/lib/ui/types.d.ts +21 -0
  128. package/lib/utils/env-lock.d.ts +1 -0
  129. package/lib/utils/env-lock.js +7 -4
  130. package/package.json +6 -6
  131. package/src/adapters/credentials.ts +22 -4
  132. package/src/adapters/file-collection.ts +2 -1
  133. package/src/adapters/mcp.test.ts +235 -1
  134. package/src/adapters/mcp.ts +276 -5
  135. package/src/adapters/messages.ts +7 -0
  136. package/src/adapters/plugin-files.ts +2 -1
  137. package/src/adapters/plugins.test.ts +176 -2
  138. package/src/adapters/plugins.ts +107 -21
  139. package/src/adapters/pnpm-workspace.test.ts +89 -1
  140. package/src/adapters/pnpm-workspace.ts +127 -2
  141. package/src/adapters/prompts.ts +20 -3
  142. package/src/adapters/providers.ts +62 -4
  143. package/src/adapters/settings.ts +16 -3
  144. package/src/adapters/skills.test.ts +141 -0
  145. package/src/adapters/skills.ts +58 -2
  146. package/src/adapters/ui.ts +16 -3
  147. package/src/adapters/units-entries.test.ts +190 -0
  148. package/src/adapters/units.ts +50 -0
  149. package/src/adapters/workspaces.ts +2 -1
  150. package/src/client/about/PluginUpdateDialog.tsx +4 -2
  151. package/src/client/about/ReleaseNotesDialog.tsx +4 -2
  152. package/src/client/chat/RollbackReviewDialog.tsx +3 -2
  153. package/src/client/common/Skeleton.tsx +32 -0
  154. package/src/client/common/api-base.test.ts +36 -0
  155. package/src/client/common/http.test.ts +12 -1
  156. package/src/client/common/http.ts +8 -2
  157. package/src/client/common/routes.ts +46 -3
  158. package/src/client/config-manager.module.css +321 -11
  159. package/src/client/home/HomePanel.tsx +14 -6
  160. package/src/client/import/ForeignImportView.tsx +3 -1
  161. package/src/client/import/import-wizard-steps.tsx +2 -1
  162. package/src/client/library/ArtifactRow.tsx +12 -2
  163. package/src/client/library/LibraryActions.tsx +6 -3
  164. package/src/client/library/LibraryPanel.tsx +21 -3
  165. package/src/client/library/RestorePlanView.tsx +4 -2
  166. package/src/client/locales.ts +3 -0
  167. package/src/client/market/market-api.test.ts +3 -2
  168. package/src/client/recovery/RecoveryPanel.tsx +54 -7
  169. package/src/client/recovery/RollbackCard.tsx +7 -2
  170. package/src/client/recovery/RollbackDiffPane.tsx +3 -2
  171. package/src/client/recovery/recovery-locales.ts +20 -2
  172. package/src/client/recovery/recovery-view.test.ts +39 -1
  173. package/src/client/recovery/recovery-view.ts +23 -1
  174. package/src/client/run-store.test.ts +1 -1
  175. package/src/client/run-store.ts +4 -0
  176. package/src/client/sync/AutosyncCard.tsx +49 -6
  177. package/src/client/sync/MergeModal.tsx +220 -0
  178. package/src/client/sync/MergePreviewView.tsx +306 -0
  179. package/src/client/sync/SyncActivityBar.tsx +31 -0
  180. package/src/client/sync/SyncConfirmView.tsx +2 -1
  181. package/src/client/sync/SyncPanel.tsx +130 -87
  182. package/src/client/sync/SyncProbeRow.tsx +162 -0
  183. package/src/client/sync/SyncSettingsView.test.ts +27 -2
  184. package/src/client/sync/WorkDirCard.tsx +44 -6
  185. package/src/client/sync/history-model.ts +4 -1
  186. package/src/client/sync/merge-view.test.ts +248 -0
  187. package/src/client/sync/merge-view.ts +398 -0
  188. package/src/client/sync/probe-view.test.ts +90 -0
  189. package/src/client/sync/probe-view.ts +63 -0
  190. package/src/client/sync/remote-device-view.test.ts +35 -0
  191. package/src/client/sync/remote-device-view.ts +25 -0
  192. package/src/client/sync/sync-api.test.ts +5 -3
  193. package/src/client/sync/sync-api.ts +212 -2
  194. package/src/client/sync/sync-entry.test.ts +78 -0
  195. package/src/client/sync/sync-entry.ts +53 -0
  196. package/src/client/sync/sync-locales.ts +234 -2
  197. package/src/client/sync/sync-view.test.ts +18 -1
  198. package/src/client/sync/sync-view.ts +20 -0
  199. package/src/core/backup.test.ts +41 -0
  200. package/src/core/backup.ts +20 -0
  201. package/src/core/mcp-connector-store.test.ts +265 -0
  202. package/src/core/mcp-connector-store.ts +516 -0
  203. package/src/core/messages-core.ts +4 -0
  204. package/src/core/messages.ts +46 -0
  205. package/src/core/phase3-host.ts +18 -1
  206. package/src/core/phase3-production-integration.test.ts +4 -0
  207. package/src/core/plugin-cli.test.ts +26 -0
  208. package/src/core/plugin-cli.ts +30 -4
  209. package/src/core/recovery-orchestrator.test.ts +104 -5
  210. package/src/core/recovery-orchestrator.ts +74 -17
  211. package/src/core/rollback-activity.test.ts +311 -0
  212. package/src/core/rollback-activity.ts +367 -0
  213. package/src/core/rollback-cross-session.test.ts +694 -0
  214. package/src/core/rollback-interrupted.test.ts +137 -0
  215. package/src/core/rollback-ledger.ts +32 -0
  216. package/src/core/rollback-merge.test.ts +130 -0
  217. package/src/core/rollback-merge.ts +78 -14
  218. package/src/core/rollback-point.ts +468 -91
  219. package/src/core/rollback-undo-journal.test.ts +508 -0
  220. package/src/core/rollback-undo-journal.ts +571 -0
  221. package/src/core/self-update.ts +2 -5
  222. package/src/core/text-fidelity.test.ts +189 -0
  223. package/src/core/text-fidelity.ts +197 -0
  224. package/src/core/types.ts +11 -3
  225. package/src/core/update-check.ts +2 -5
  226. package/src/core/validator.ts +14 -0
  227. package/src/foreign/bundle-origin.test.ts +265 -0
  228. package/src/foreign/bundle.ts +45 -5
  229. package/src/foreign/claude-code.test.ts +268 -0
  230. package/src/foreign/claude-code.ts +406 -25
  231. package/src/foreign/claude-plugins.test.ts +234 -0
  232. package/src/foreign/claude-sessions.test.ts +141 -0
  233. package/src/foreign/claude-sessions.ts +179 -23
  234. package/src/foreign/file-budget.test.ts +4 -1
  235. package/src/foreign/read-claude-code.test.ts +320 -0
  236. package/src/foreign/read-claude-code.ts +490 -71
  237. package/src/foreign/read-claude-plugins.ts +465 -0
  238. package/src/foreign/registry.ts +25 -2
  239. package/src/foreign/session-ir.test.ts +65 -0
  240. package/src/foreign/truth-table.test.ts +81 -0
  241. package/src/foreign/truth-table.ts +6 -3
  242. package/src/foreign/types.ts +162 -2
  243. package/src/index.facade.test.ts +26 -4
  244. package/src/index.ts +76 -19
  245. package/src/market/git-file-writer.test.ts +4 -0
  246. package/src/market/git-file-writer.ts +7 -1
  247. package/src/profiles/dsh-profile-launcher.test.ts +68 -3
  248. package/src/profiles/dsh-profile-launcher.ts +56 -1
  249. package/src/profiles/dsh-profile-shared.ts +8 -2
  250. package/src/routes/foreign.ts +8 -1
  251. package/src/routes/index.ts +1 -1
  252. package/src/routes/kit.ts +2 -2
  253. package/src/routes/sync.ts +176 -9
  254. package/src/schema/manifest-schema.test.ts +87 -2
  255. package/src/schema/manifest.ts +57 -1
  256. package/src/schema/types.ts +45 -2
  257. package/src/sync/ancestor.ts +76 -2
  258. package/src/sync/autosync-config.test.ts +73 -1
  259. package/src/sync/autosync-config.ts +124 -0
  260. package/src/sync/autosync-risk-tier.test.ts +38 -2
  261. package/src/sync/autosync-scheduler.test.ts +264 -12
  262. package/src/sync/autosync-scheduler.ts +296 -44
  263. package/src/sync/gist/gist-conditional-write.test.ts +203 -0
  264. package/src/sync/gist/gist-transport.ts +53 -5
  265. package/src/sync/gist/messages.ts +5 -0
  266. package/src/sync/git/git-probe.test.ts +80 -0
  267. package/src/sync/git/git-transport.test.ts +185 -0
  268. package/src/sync/git/git-transport.ts +178 -5
  269. package/src/sync/merge.test.ts +188 -55
  270. package/src/sync/merge.ts +282 -224
  271. package/src/sync/messages.ts +19 -0
  272. package/src/sync/risk.ts +29 -5
  273. package/src/sync/s3/messages.ts +13 -0
  274. package/src/sync/s3/s3-conditional-write.test.ts +330 -0
  275. package/src/sync/s3/s3-transport.test.ts +2 -1
  276. package/src/sync/s3/s3-transport.ts +87 -9
  277. package/src/sync/s3/sigv4.test.ts +4 -1
  278. package/src/sync/s3/sigv4.ts +11 -2
  279. package/src/sync/sync-device-identity.test.ts +267 -0
  280. package/src/sync/sync-engine.test.ts +410 -19
  281. package/src/sync/sync-engine.ts +602 -57
  282. package/src/sync/sync-history.test.ts +16 -1
  283. package/src/sync/sync-history.ts +26 -0
  284. package/src/sync/sync-state.test.ts +64 -0
  285. package/src/sync/sync-state.ts +79 -0
  286. package/src/sync/sync-watcher.test.ts +197 -0
  287. package/src/sync/sync-watcher.ts +246 -0
  288. package/src/sync/text-merge.test.ts +358 -0
  289. package/src/sync/text-merge.ts +554 -0
  290. package/src/sync/transport.ts +57 -0
  291. package/src/sync/watch-scope.test.ts +122 -0
  292. package/src/sync/watch-scope.ts +120 -0
  293. package/src/sync/webdav/webdav-conditional-write.test.ts +360 -0
  294. package/src/sync/webdav/webdav-transport.ts +137 -14
  295. package/src/ui/foreign-view.test.ts +34 -0
  296. package/src/ui/foreign-view.ts +10 -0
  297. package/src/ui/i18n.ts +22 -0
  298. package/src/ui/rollback-view.ts +14 -0
  299. package/src/ui/sync-settings-view.test.ts +28 -1
  300. package/src/ui/sync-settings-view.ts +43 -0
  301. package/src/ui/types.ts +22 -0
  302. package/src/utils/env-lock.ts +8 -5
package/lib/index.d.ts CHANGED
@@ -61,7 +61,7 @@ import { SyncEngine } from './sync/sync-engine.ts';
61
61
  import { SyncSessionStore } from './sync/sync-session.ts';
62
62
  import { AutoSyncScheduler } from './sync/autosync-scheduler.ts';
63
63
  import { BackupScheduler } from './sync/backup-scheduler.ts';
64
- import type { AutosyncInterval, AutosyncRunStatus } from './sync/autosync-config.ts';
64
+ import type { AutosyncInterval, AutosyncRunStatus, AutosyncAutoApplyTier, AutosyncConflictPolicy } from './sync/autosync-config.ts';
65
65
  import { MigrationStore, type MigrationKind, type MigrationResult } from './core/migration-history.ts';
66
66
  import type { SyncConfig, SyncTransportType } from './sync/sync-config.ts';
67
67
  import type { SyncSelection, SyncSelectionMode } from './sync/sync-selection.ts';
@@ -78,7 +78,7 @@ export declare const name = "config-manager";
78
78
  /** Services required before the engine can mount (present in every profile). */
79
79
  export declare const inject: string[];
80
80
  /** Plugin version, kept in sync with package.json ("version"). */
81
- export declare const PLUGIN_VERSION = "0.1.78";
81
+ export declare const PLUGIN_VERSION = "0.1.80";
82
82
  /**
83
83
  * Star 引导弹窗指向的 GitHub 仓库(用户引导点 Star 的目标)。
84
84
  * 与 package.json 的 repository 字段保持一致;界面不可改(硬编码,参照
@@ -131,7 +131,7 @@ export interface Config {
131
131
  /**
132
132
  * 本文件保留的 7 条路由的路径(被源码级守卫按文件窗口钉住,见下方 routesList 注释)。
133
133
  *
134
- * 其余 72 条路由的路径**声明在各自的组文件里**(src/routes/*.ts 的 endpoint({ path, methods }))——
134
+ * 其余 75 条路由的路径**声明在各自的组文件里**(src/routes/*.ts 的 endpoint({ path, methods }))——
135
135
  * 新增一条 API 只需那一条声明,不再有「常量表 + 路由对象」两处要同步。
136
136
  */
137
137
  export declare const API: {
@@ -221,8 +221,9 @@ export declare class DshPluginsFacade implements PluginsFacade {
221
221
  private readonly runner;
222
222
  constructor(homeDir: string, profile: string, patchFile: PatchFileFacade, runner?: typeof runDshPlugin, msg?: MsgFunc);
223
223
  listInstalled(): Promise<PluginInfo[]>;
224
- install(pkg: string, spec?: string, signal?: AbortSignal): Promise<{
224
+ install(pkg: string, target?: string, signal?: AbortSignal): Promise<{
225
225
  needsRestart: boolean;
226
+ installedVersion?: string | null;
226
227
  }>;
227
228
  }
228
229
  /**
@@ -858,7 +859,7 @@ export type RouteEnvInferred = {
858
859
  } | {
859
860
  error: string;
860
861
  }>;
861
- rebuild: (repoUrl: string, mode: 'relink' | 'reclone') => Promise<GitWorkDirFacts>;
862
+ rebuild: (repoUrl: string, mode: 'relink' | 'adopt' | 'reclone') => Promise<GitWorkDirFacts>;
862
863
  };
863
864
  syncSectionCatalog: {
864
865
  id: SectionId;
@@ -990,6 +991,14 @@ export declare function buildAutosyncStatusByChannel(dir: string): Promise<Recor
990
991
  interface AutosyncStatusResponse {
991
992
  enabled: boolean;
992
993
  interval: AutosyncInterval;
994
+ /** 真·自动同步:本地改动即时触发(缺省 true) */
995
+ realtime: boolean;
996
+ /** realtime 下的远端轮询间隔(ms) */
997
+ remoteCheckMs: number;
998
+ /** 自动应用的最高风险等级(缺省 medium:plugins/mcp 也自动落盘) */
999
+ autoApplyTier: AutosyncAutoApplyTier;
1000
+ /** 双侧都改时的策略(缺省 local:保留本机并推上去) */
1001
+ conflictPolicy: AutosyncConflictPolicy;
993
1002
  lastRunAt?: string;
994
1003
  lastRunStatus?: AutosyncRunStatus;
995
1004
  lastRunMessage?: string;
package/lib/index.js CHANGED
@@ -67,10 +67,11 @@ import { msgOf, zhMsg } from './core/messages.js';
67
67
  import { engineMsg, getEngineLocale, setEngineLanguageSource, setEngineLocale } from './core/engine-locale.js';
68
68
  import { RollbackAutoTracker, RollbackPointEngine, ROLLBACK_POINTS_DIR_NAME, rollbackSessionBindingOf, rollbackTrackedEventOf } from './core/rollback-point.js';
69
69
  import { ROLLBACK_ATTRIBUTION_FILE_NAME, RollbackWriteAttribution } from './core/rollback-attribution.js';
70
+ import { ROLLBACK_ACTIVITY_FILE_NAME, RollbackSessionActivity } from './core/rollback-activity.js';
70
71
  import { isRollbackEnabled, onRollbackEnabledChange, setRollbackEnabled } from './core/rollback-gate.js';
71
72
  // t3:宿主斜杠命令 /rollback(与 HTTP 路由同一道写入门;命令服务惰取,未组合时安静跳过)。
72
73
  import { agentSessionFactsOf, registerRollbackCommand } from './core/command-rollback.js';
73
- import { cleanupAbortedInstall, hasDshBundlePatch, installAnchorFromProfileContext, installErrorFor, installSpecFor, listInstalledPlugins, profileNameFromProfileContext, resolveProcessProfileName, resolveProfileDir, readProfileManifest, runDshPlugin, validateProfileName } from './core/plugin-cli.js';
74
+ import { cleanupAbortedInstall, hasDshBundlePatch, installAnchorFromProfileContext, installErrorFor, readInstalledVersion, listInstalledPlugins, profileNameFromProfileContext, resolveProcessProfileName, resolveProfileDir, readProfileManifest, runDshPlugin, validateProfileName } from './core/plugin-cli.js';
74
75
  import { ImportUserSkippedError } from './core/types.js';
75
76
  import { PLUGIN_NPM_PACKAGE } from './core/update-check.js';
76
77
  import { planSelfUpdate, runSelfUpdate } from './core/self-update.js';
@@ -106,7 +107,7 @@ import { readRollbackEnabledSync } from './sync/ui-prefs.js';
106
107
  import { AUTO_BACKUP_PREFIX, isValidExportFileName, resolveNonCollidingExportName, writeBackupNote } from './sync/backup-files.js';
107
108
  import { DEFAULT_RETENTION_POLICY, selectPruneCandidatesByPolicy } from './sync/retention-policy.js';
108
109
  import { selectPruneCandidates } from './core/backup.js';
109
- import { readAllAutosyncConfigs, readAutosyncConfig } from './sync/autosync-config.js';
110
+ import { readAllAutosyncConfigs, readAutosyncConfig, DEFAULT_AUTOSYNC_REALTIME, DEFAULT_AUTOSYNC_REMOTE_CHECK_MS, DEFAULT_AUTOSYNC_AUTO_APPLY_TIER, DEFAULT_AUTOSYNC_CONFLICT_POLICY, lastRunFailureMessage, } from './sync/autosync-config.js';
110
111
  import { appendAutosyncEntry } from './sync/sync-history.js';
111
112
  import { MigrationStore, MIGRATION_HISTORY_DIR } from './core/migration-history.js';
112
113
  import { readSyncConfig, validateRepoUrl, validateWebDavUrl, isWebDavConfig, isS3Config, isGistConfig, channelOf, parseSyncChannel, SYNC_CHANNELS, GIST_PROVIDER, isS3CompatProvider, validateCloudChannelInput, cloudSecretRef } from './sync/sync-config.js';
@@ -138,7 +139,7 @@ export const name = 'config-manager';
138
139
  /** Services required before the engine can mount (present in every profile). */
139
140
  export const inject = ['settings', 'credentials'];
140
141
  /** Plugin version, kept in sync with package.json ("version"). */
141
- export const PLUGIN_VERSION = '0.1.78';
142
+ export const PLUGIN_VERSION = '0.1.80';
142
143
  /** Plugin own package name — excluded from its own exported plugins list. */
143
144
  const PLUGIN_NAME = 'dsh-config-manager';
144
145
  /**
@@ -160,7 +161,7 @@ export const DEFAULT_GITHUB_CLIENT_ID = 'Ov23liq4i7n8UsylGRfb';
160
161
  /**
161
162
  * 本文件保留的 7 条路由的路径(被源码级守卫按文件窗口钉住,见下方 routesList 注释)。
162
163
  *
163
- * 其余 72 条路由的路径**声明在各自的组文件里**(src/routes/*.ts 的 endpoint({ path, methods }))——
164
+ * 其余 75 条路由的路径**声明在各自的组文件里**(src/routes/*.ts 的 endpoint({ path, methods }))——
164
165
  * 新增一条 API 只需那一条声明,不再有「常量表 + 路由对象」两处要同步。
165
166
  */
166
167
  export const API = {
@@ -526,12 +527,13 @@ export class DshPluginsFacade {
526
527
  async listInstalled() {
527
528
  return listInstalledPlugins(this.homeDir, this.profile);
528
529
  }
529
- async install(pkg, spec, signal) {
530
+ async install(pkg, target, signal) {
530
531
  const profileDir = resolveProfileDir(this.homeDir, this.profile);
531
- // 非 registry 来源(github:/git+/file: 等)按来源 spec 安装;registry 包按裸包名装
532
- // npm 最新版(官方机制)。spec 丢失(旧备份)时退化为裸包名 → pnpm fetch-404,
533
- // 由 installErrorFor 给出可操作诊断。
534
- const result = await this.runner(profileDir, this.profile, ['add', installSpecFor(pkg, spec)], undefined, signal);
532
+ // target 由调用方(adapters/plugins.ts 的 pluginInstallTarget)推导完毕,这里只执行:
533
+ // registry 包带精确版本或「包名@spec」,pnpm 才不会静默沿用目标机既有 spec(issue #101)。
534
+ // 缺省退化为裸包名(旧调用方)→ pnpm fetch-404,由 installErrorFor 给出可操作诊断。
535
+ const spec = target !== undefined && target !== '' ? target : pkg;
536
+ const result = await this.runner(profileDir, this.profile, ['add', spec], undefined, signal);
535
537
  // 用户「跳过当前插件」:宿主 kill 了子进程 → 清理半装状态(删依赖行 + 删 node_modules/<pkg>,
536
538
  // 防止「package.json 声明了依赖但没装全」导致 DSH 启动失败),再以跳过语义抛错。
537
539
  if (result.aborted || (signal !== undefined && signal.aborted)) {
@@ -549,7 +551,8 @@ export class DshPluginsFacade {
549
551
  const reason = error instanceof Error ? error.message : String(error);
550
552
  throw new Error(this.msg('host.activationRowFailed', { pkg, reason }));
551
553
  }
552
- return { needsRestart: true };
554
+ // 回读实际落盘版本:调用方据此校验升级是否真的生效(issue #101),而不是只看子进程退出码。
555
+ return { needsRestart: true, installedVersion: readInstalledVersion(profileDir, pkg) };
553
556
  }
554
557
  }
555
558
  /** Workspace facade over the real ctx.workspaceRegistry. */
@@ -2368,12 +2371,19 @@ export async function buildAutosyncStatus(dir, channel) {
2368
2371
  const elapsedMs = cfg.lastRunAt === undefined || cfg.lastRunAt === ''
2369
2372
  ? -1
2370
2373
  : Math.max(0, Date.now() - Date.parse(cfg.lastRunAt));
2374
+ // issue #105:只有本轮真的失败才回传错误原文(success/skipped/partial 不得带上一轮的旧错误)
2375
+ const failureMessage = lastRunFailureMessage(cfg);
2371
2376
  return {
2372
2377
  enabled: cfg.enabled,
2373
2378
  interval: cfg.interval,
2379
+ // 真·自动同步三件套(缺省值在读取层已补齐,这里回传「生效中的值」)
2380
+ realtime: cfg.realtime ?? DEFAULT_AUTOSYNC_REALTIME,
2381
+ remoteCheckMs: cfg.remoteCheckMs ?? DEFAULT_AUTOSYNC_REMOTE_CHECK_MS,
2382
+ autoApplyTier: cfg.autoApplyTier ?? DEFAULT_AUTOSYNC_AUTO_APPLY_TIER,
2383
+ conflictPolicy: cfg.conflictPolicy ?? DEFAULT_AUTOSYNC_CONFLICT_POLICY,
2374
2384
  ...(cfg.lastRunAt !== undefined ? { lastRunAt: cfg.lastRunAt } : {}),
2375
2385
  ...(cfg.lastRunStatus !== undefined ? { lastRunStatus: cfg.lastRunStatus } : {}),
2376
- ...(cfg.lastRunMessage !== undefined ? { lastRunMessage: cfg.lastRunMessage } : {}),
2386
+ ...(failureMessage !== undefined ? { lastRunMessage: failureMessage } : {}),
2377
2387
  // issue #79:跳过原因以**码**回传(界面本地化);不再只留在 info 级日志里
2378
2388
  ...(cfg.lastRunSkipReason !== undefined ? { lastRunSkipReason: cfg.lastRunSkipReason } : {}),
2379
2389
  ...(cfg.lastRunSkipCount !== undefined ? { lastRunSkipCount: cfg.lastRunSkipCount } : {}),
@@ -2390,12 +2400,18 @@ export async function buildAutosyncStatusByChannel(dir) {
2390
2400
  const elapsedMs = cfg.lastRunAt === undefined || cfg.lastRunAt === ''
2391
2401
  ? -1
2392
2402
  : Math.max(0, Date.now() - Date.parse(cfg.lastRunAt));
2403
+ // issue #105:同 buildAutosyncStatus —— 只有本轮失败才带错误原文
2404
+ const failureMessage = lastRunFailureMessage(cfg);
2393
2405
  return {
2394
2406
  enabled: cfg.enabled,
2395
2407
  interval: cfg.interval,
2408
+ realtime: cfg.realtime ?? DEFAULT_AUTOSYNC_REALTIME,
2409
+ remoteCheckMs: cfg.remoteCheckMs ?? DEFAULT_AUTOSYNC_REMOTE_CHECK_MS,
2410
+ autoApplyTier: cfg.autoApplyTier ?? DEFAULT_AUTOSYNC_AUTO_APPLY_TIER,
2411
+ conflictPolicy: cfg.conflictPolicy ?? DEFAULT_AUTOSYNC_CONFLICT_POLICY,
2396
2412
  ...(cfg.lastRunAt !== undefined ? { lastRunAt: cfg.lastRunAt } : {}),
2397
2413
  ...(cfg.lastRunStatus !== undefined ? { lastRunStatus: cfg.lastRunStatus } : {}),
2398
- ...(cfg.lastRunMessage !== undefined ? { lastRunMessage: cfg.lastRunMessage } : {}),
2414
+ ...(failureMessage !== undefined ? { lastRunMessage: failureMessage } : {}),
2399
2415
  ...(cfg.lastRunSkipReason !== undefined ? { lastRunSkipReason: cfg.lastRunSkipReason } : {}),
2400
2416
  ...(cfg.lastRunSkipCount !== undefined ? { lastRunSkipCount: cfg.lastRunSkipCount } : {}),
2401
2417
  consecutiveFailures: cfg.consecutiveFailures,
@@ -3206,6 +3222,10 @@ function makeRoutes(deps) {
3206
3222
  mutationLock: host.mutationLock,
3207
3223
  isBlocked: () => host.safeModeIsBlocked?.() ?? false,
3208
3224
  phase3Recovery: host.phase3Recovery,
3225
+ // 真·自动同步:本地配置文件监听(realtime 通道)以 $DSH_HOME 为基准;
3226
+ // 监听清单由 sync/watch-scope.ts 静态派生,已排除 sessions/ 与调度器自写文件(避免自激)。
3227
+ homeDir: host.homeDir,
3228
+ ...(host.profile === undefined ? {} : { profile: host.profile }),
3209
3229
  // Phase 6:autosync 既写 sync-history.json(既有语义),也写统一迁移历史(COMPLETE 不变量)。
3210
3230
  appendHistoryFn: async (entry) => {
3211
3231
  await appendAutosyncEntry(syncDir, entry).catch(() => undefined);
@@ -3384,7 +3404,13 @@ function makeRoutes(deps) {
3384
3404
  if (port === undefined)
3385
3405
  return { state: 'FREE' };
3386
3406
  const insp = await port.inspectLockState();
3387
- return { state: insp.state, ...(insp.detail !== undefined ? { detail: insp.detail } : {}) };
3407
+ // ownerInstanceId 只给编排器做 journal↔锁归属匹配(判定「正在跑」vs「残留事故」),
3408
+ // 不进任何 HTTP 响应体(编排器只消费不回传)。
3409
+ return {
3410
+ state: insp.state,
3411
+ ...(insp.detail !== undefined ? { detail: insp.detail } : {}),
3412
+ ...(insp.ownerInstanceId !== undefined ? { ownerInstanceId: insp.ownerInstanceId } : {}),
3413
+ };
3388
3414
  },
3389
3415
  recoverStaleLock: async () => {
3390
3416
  const port = host.mutationLock;
@@ -3501,13 +3527,17 @@ function makeRoutes(deps) {
3501
3527
  // 也不伪装成「工作副本不存在」。
3502
3528
  inspect: async (repoUrl) => {
3503
3529
  try {
3504
- return { facts: await makeGitTransport(repoUrl).inspectWorkDir() };
3530
+ // issue #104 建议 3:`/sync/status` 要回传「领先远端提交数 / 远端快照数」,
3531
+ // 用户看不见积压,就会在「以为在备份」的状态下一直失败。detail 多出的几条命令
3532
+ // 都是本地只读(rev-list / status / ls-tree),不发网络请求。
3533
+ return { facts: await makeGitTransport(repoUrl).inspectWorkDir({ detail: true }) };
3505
3534
  }
3506
3535
  catch (err) {
3507
3536
  return { error: err instanceof Error ? err.message : String(err) };
3508
3537
  }
3509
3538
  },
3510
- // 重建:relink 非破坏;reclone 删目录重克隆(调用方必须先取得用户确认)
3539
+ // 重建:relink 非破坏;adopt 合并远端历史(不改写本地提交,issue #104);
3540
+ // reclone 删目录重克隆(调用方必须先取得用户确认)
3511
3541
  rebuild: async (repoUrl, mode) => {
3512
3542
  const transport = makeGitTransport(repoUrl);
3513
3543
  await transport.rebuildWorkDir(mode);
@@ -3541,7 +3571,7 @@ function makeRoutes(deps) {
3541
3571
  /**
3542
3572
  * 路由表:本文件只保留被源码级守卫按**文件窗口**钉住的 7 条(host-entry 审计 F-04 记录的
3543
3573
  * tests/host/**、src/core/model-tools.test.ts、src/core/phase1-wiring.test.ts 的窗口断言)。
3544
- * 其余 72 条已按域拆到 src/routes/*.ts,由 buildRoutes 组装。
3574
+ * 其余 75 条已按域拆到 src/routes/*.ts,由 buildRoutes 组装。
3545
3575
  * 注册顺序不影响匹配:命名路由必须互不相同(webServer 契约)。
3546
3576
  */
3547
3577
  const routeEnv = makeRouteEnv();
@@ -4393,11 +4423,21 @@ export function apply(ctx, config) {
4393
4423
  warn: (line) => host.log.warn(line),
4394
4424
  });
4395
4425
  void rollbackAttribution.load();
4426
+ // 会话活跃时间窗(2026-10-18):**每个 session/event 都记一次**活跃 —— 与工具参数无关,
4427
+ // 因此 bash / 脚本 / 外部编辑器写出的路径也能按「文件 mtime 落在谁的活跃窗口内」判定归属;
4428
+ // 落在**谁都不活跃**的时刻 = 手改 / 外部工具 ⇒ 回退零写入并如实报 unclaimed(绝不静默覆盖)。
4429
+ // 同样是 best-effort:读写失败只 warn,退化成「没有时间证据」(回退行为与加它之前逐字一致)。
4430
+ const rollbackActivity = new RollbackSessionActivity({
4431
+ file: path.join(dataDir, ROLLBACK_POINTS_DIR_NAME, ROLLBACK_ACTIVITY_FILE_NAME),
4432
+ warn: (line) => host.log.warn(line),
4433
+ });
4434
+ void rollbackActivity.load();
4396
4435
  const rollbackEngine = new RollbackPointEngine({
4397
4436
  dataDir,
4398
4437
  homeDir,
4399
4438
  log: (line) => host.log.warn(line),
4400
4439
  attribution: rollbackAttribution,
4440
+ activity: rollbackActivity,
4401
4441
  fork: async ({ sessionId, boundarySeq }) => {
4402
4442
  const forkSession = forkPort.forkSession;
4403
4443
  if (typeof forkSession !== 'function') {
@@ -4420,6 +4460,7 @@ export function apply(ctx, config) {
4420
4460
  engine: rollbackEngine,
4421
4461
  log: (line) => host.log.warn(line),
4422
4462
  attribution: rollbackAttribution,
4463
+ activity: rollbackActivity,
4423
4464
  });
4424
4465
  ctx.effect(() => {
4425
4466
  let chain = Promise.resolve();
@@ -4507,6 +4548,9 @@ export function apply(ctx, config) {
4507
4548
  unlisten();
4508
4549
  detach();
4509
4550
  rollbackTracker.stop();
4551
+ // 卸载时把**未落盘**的活跃窗口刷下去(debounce 里可能还有几条):丢了它,
4552
+ // 下次启动就少一段「谁在什么时候活跃」的证据 —— 归属会因此退回「未判定」。
4553
+ void rollbackActivity.dispose();
4510
4554
  };
4511
4555
  }, 'config-manager: rollback auto points');
4512
4556
  // ------------------------------------------- 宿主斜杠命令 /rollback(t3)
@@ -192,7 +192,13 @@ export class GitFileWriterClient {
192
192
  const fileArg = quoteGitValue(credFile.replace(/\\/g, '/'));
193
193
  await atomicWriteFile(credFile, `https://${this.credentialUsername}:${token}@github.com\n`, { mode: 0o600, symlink: 'reject' });
194
194
  return {
195
- extraArgs: ['-c', 'credential.helper=', '-c', `credential.helper=store --file=${fileArg}`],
195
+ // issue #103:同 git-transport.buildCredentialArgs —— store 用 username 作查找键,
196
+ // 不钉住就会被全局 `.gitconfig` 的 `credential.<url>.username` 顶掉而查不到口令。
197
+ extraArgs: [
198
+ '-c', 'credential.helper=',
199
+ '-c', `credential.helper=store --file=${fileArg}`,
200
+ '-c', `credential.username=${this.credentialUsername}`,
201
+ ],
196
202
  cleanup: async () => { await fs.rm(tmpDir, { recursive: true, force: true }); },
197
203
  };
198
204
  }
@@ -97,6 +97,26 @@ export declare function logTail(logText: string, lines?: number): string;
97
97
  * 推断不出来(如源码树 tsx 直启 / Electron)时回退 PATH 上的 dsh(.cmd 走 shell)。
98
98
  */
99
99
  export declare function defaultResolveCli(): DshCliCommand | null;
100
+ /**
101
+ * 直启 bin.js 用的运行时:宿主是 Electron 时必须以 `ELECTRON_RUN_AS_NODE=1` 当 node 用
102
+ * (桌面端宿主 `process.execPath` 是 DeepSeek Harness.exe,真机实测可正常跑 CLI)。
103
+ */
104
+ export declare function resolveDirectCliRunner(versions?: Readonly<Record<string, string | undefined>>): {
105
+ command: string;
106
+ env?: Readonly<Record<string, string>>;
107
+ };
108
+ /**
109
+ * 从 PATH 上的 dsh 包装脚本反解真正的 CLI 入口(`.../@deepseek-ai/dsh/lib/bin.js`)。
110
+ *
111
+ * 为什么必须反解(真机实测根因):Windows 上 `.cmd/.bat` 只能经 shell 起,而
112
+ * **中间 cmd 层 + `detached: true` 会丢掉孙进程的 stdout/stderr** ——
113
+ * `dsh.cmd --version` 经 detached 起时日志恒 0 字节(非 detached 正常),
114
+ * 于是启动器永远读不到 `dsh web: <带 token 的 URL>` 那行,用户只看到
115
+ * 「20 秒内未确认就绪 / 没能抓到带 token 的 URL」。直启 bin.js 则正常(约 8 秒出 URL)。
116
+ *
117
+ * 先按 npm/pnpm 的常见布局找同目录 `node_modules`,再退回脚本内嵌的入口路径。
118
+ */
119
+ export declare function findCliEntryForShim(shimPath: string): string | null;
100
120
  /** 档案 → 是否可启动(唯一判据在 shared,UI 与本模块共用)。 */
101
121
  export { isLaunchableShape };
102
122
  /** 档案启动器(每个实例无状态,可直接复用)。 */
@@ -9,6 +9,9 @@
9
9
  * 生态里的做法同样如此(dsh-profile-manager 的 `dshm start`、DSH Launcher 的桌面启动器),
10
10
  * 都是「由启动器 spawn 一个实例」;本模块把这件事做进插件:
11
11
  * web 形态档案 → detached 子进程 + 自动挑空闲端口 + 从启动日志里抓认证 URL + HTTP 探活。
12
+ * 子进程必须**直启**(node/Electron-as-node 跑 `bin.js`):Windows 上经 `.cmd` 包装脚本
13
+ * (`shell: true` 或中间 cmd 层)再 `detached: true` 会丢掉孙进程的 stdout/stderr,
14
+ * 日志文件恒 0 字节 ⇒ 永远抓不到 `dsh web: <带 token 的 URL>`(真机实测,见 findCliEntryForShim)。
12
15
  *
13
16
  * 设计约束:
14
17
  * - 只消费 DSH 的稳定表面(启动参数 + 启动日志里的 `dsh web:` 行),不 import 任何
@@ -97,7 +100,18 @@ export function defaultResolveCli() {
97
100
  }
98
101
  return null;
99
102
  }
100
- return { command: fromPath, prefixArgs: [], shell: /\.(cmd|bat)$/i.test(fromPath) };
103
+ const needsShell = /\.(cmd|bat)$/i.test(fromPath);
104
+ // Windows 的 .cmd/.bat 只能经 shell 起,而「中间 cmd 层 + detached」会吞掉孙进程的
105
+ // stdio(日志恒 0 字节 ⇒ 永远抓不到带 token 的 URL)。能反解出真入口就直接跑,
106
+ // 只有反解不出来时才退回包装脚本(那时日志里没有 URL,UI 会如实报 urlNotFound)。
107
+ if (needsShell) {
108
+ const entry = findCliEntryForShim(fromPath);
109
+ if (entry !== null) {
110
+ const runner = resolveDirectCliRunner();
111
+ return { command: runner.command, prefixArgs: [entry], shell: false, env: runner.env };
112
+ }
113
+ }
114
+ return { command: fromPath, prefixArgs: [], shell: needsShell };
101
115
  }
102
116
  /** bin.js 是否属于 @deepseek-ai/dsh(读上一级的 package.json.name)。 */
103
117
  function isDshBinPath(binPath) {
@@ -123,6 +137,49 @@ function findOnPath(names) {
123
137
  }
124
138
  return null;
125
139
  }
140
+ /**
141
+ * 直启 bin.js 用的运行时:宿主是 Electron 时必须以 `ELECTRON_RUN_AS_NODE=1` 当 node 用
142
+ * (桌面端宿主 `process.execPath` 是 DeepSeek Harness.exe,真机实测可正常跑 CLI)。
143
+ */
144
+ export function resolveDirectCliRunner(versions = process.versions) {
145
+ if (versions['electron'] !== undefined)
146
+ return { command: process.execPath, env: { ELECTRON_RUN_AS_NODE: '1' } };
147
+ return { command: process.execPath };
148
+ }
149
+ /**
150
+ * 从 PATH 上的 dsh 包装脚本反解真正的 CLI 入口(`.../@deepseek-ai/dsh/lib/bin.js`)。
151
+ *
152
+ * 为什么必须反解(真机实测根因):Windows 上 `.cmd/.bat` 只能经 shell 起,而
153
+ * **中间 cmd 层 + `detached: true` 会丢掉孙进程的 stdout/stderr** ——
154
+ * `dsh.cmd --version` 经 detached 起时日志恒 0 字节(非 detached 正常),
155
+ * 于是启动器永远读不到 `dsh web: <带 token 的 URL>` 那行,用户只看到
156
+ * 「20 秒内未确认就绪 / 没能抓到带 token 的 URL」。直启 bin.js 则正常(约 8 秒出 URL)。
157
+ *
158
+ * 先按 npm/pnpm 的常见布局找同目录 `node_modules`,再退回脚本内嵌的入口路径。
159
+ */
160
+ export function findCliEntryForShim(shimPath) {
161
+ const dir = dirname(shimPath);
162
+ const candidates = [
163
+ join(dir, 'node_modules', '@deepseek-ai', 'dsh', 'lib', 'bin.js'), // npm 全局前缀(dsh.cmd 同目录)
164
+ join(dir, '..', 'node_modules', '@deepseek-ai', 'dsh', 'lib', 'bin.js'), // <prefix>/bin/dsh.cmd
165
+ join(dir, '..', '..', 'node_modules', '@deepseek-ai', 'dsh', 'lib', 'bin.js'),
166
+ join(dir, '..', '@deepseek-ai', 'dsh', 'lib', 'bin.js'), // pnpm <store>/.bin/dsh.cmd
167
+ ];
168
+ for (const candidate of candidates) {
169
+ if (isDshBinPath(candidate))
170
+ return candidate;
171
+ }
172
+ const text = readTextSafe(shimPath);
173
+ if (text === null)
174
+ return null;
175
+ // 脚本内嵌路径可能是相对当前目录的(`%dp0%\node_modules\…`)也可能是 `..\node_modules\…`,
176
+ // 故把可选的前导相对段一起抓下来,再按 shim 所在目录解析。
177
+ const embedded = /(?:\.\.[\\/]|[.][\\/])?node_modules[\\/]+@deepseek-ai[\\/]+dsh[\\/]+lib[\\/]+bin\.js/iu.exec(text);
178
+ if (embedded === null)
179
+ return null;
180
+ const resolved = join(dir, embedded[0]);
181
+ return isDshBinPath(resolved) ? resolved : null;
182
+ }
126
183
  /** 档案 → 是否可启动(唯一判据在 shared,UI 与本模块共用)。 */
127
184
  export { isLaunchableShape };
128
185
  /** 档案启动器(每个实例无状态,可直接复用)。 */
@@ -134,8 +134,14 @@ export interface DshProfileRunningView {
134
134
  export type DshProfileStopOutcome = 'graceful' | 'killed' | 'already-stopped';
135
135
  /** 启动回执里的非致命告警码。 */
136
136
  export type DshProfileLaunchWarning = 'notReady' | 'urlNotFound';
137
- /** 等待新实例就绪的上限(宿主探活默认值;UI 文案引用同一常量,避免两处各写一个数字)。 */
138
- export declare const DSH_PROFILE_LAUNCH_TIMEOUT_MS = 20000;
137
+ /**
138
+ * 等待新实例就绪的上限(宿主探活默认值;UI 文案引用同一常量,避免两处各写一个数字)。
139
+ *
140
+ * 真机口径(web 档案):端口约 3 秒就 LISTENING,但带 token 的 URL 要等 dsh 把整棵插件树
141
+ * settle 完 + startup audit 走完才打印,实测 8–10 秒,插件多的档案会更久(有过 >20 秒的样本)。
142
+ * 20 秒会把「慢但成功」误判成未就绪,故放宽到 30 秒。
143
+ */
144
+ export declare const DSH_PROFILE_LAUNCH_TIMEOUT_MS = 30000;
139
145
  /** GET /profiles 的响应负载(列表 + 当前运行 + 运行中实例 + 模板清单)。 */
140
146
  export interface DshProfilesSnapshot {
141
147
  profiles: DshProfileMeta[];
@@ -6,8 +6,14 @@
6
6
  * 引擎(`dsh-profile-manager.ts`,用 node fs)与 UI 视图模型/React 壳都只从这里取
7
7
  * 类型、常量与纯函数。
8
8
  */
9
- /** 等待新实例就绪的上限(宿主探活默认值;UI 文案引用同一常量,避免两处各写一个数字)。 */
10
- export const DSH_PROFILE_LAUNCH_TIMEOUT_MS = 20_000;
9
+ /**
10
+ * 等待新实例就绪的上限(宿主探活默认值;UI 文案引用同一常量,避免两处各写一个数字)。
11
+ *
12
+ * 真机口径(web 档案):端口约 3 秒就 LISTENING,但带 token 的 URL 要等 dsh 把整棵插件树
13
+ * settle 完 + startup audit 走完才打印,实测 8–10 秒,插件多的档案会更久(有过 >20 秒的样本)。
14
+ * 20 秒会把「慢但成功」误判成未就绪,故放宽到 30 秒。
15
+ */
16
+ export const DSH_PROFILE_LAUNCH_TIMEOUT_MS = 30_000;
11
17
  export const DSH_PROFILE_TEMPLATES = [
12
18
  { id: 'base', bundles: ['@deepseek-ai/dsh-base'], patchReload: 'live' },
13
19
  { id: 'web', bundles: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app'], patchReload: 'live' },
@@ -17,7 +17,8 @@
17
17
  * ② **不做导入**:本路由只产包,**绝不**触碰 $DSH_HOME 下的配置。导入仍由既有
18
18
  * /analyze → /plan → /execute 完成(导入前快照、冲突判定、dry-run 全部自动生效);
19
19
  * ③ **凭据值绝不进响应**:只回 skipped 机器码 + 凭据**引用名**(值在转换层就已被剥离,
20
- * 见 src/foreign/types.ts 的不变量①);
20
+ * 见 src/foreign/types.ts 的不变量①);溯源块(origin:来源标识 / 位置 / 项目根 / 插件元数据 /
21
+ * 跳过聚合 / 凭据引用名)同样**只含标识与计数**,绝无任何配置值;
21
22
  * ④ **空结果不静默成功**:一个分区都产不出来 → 400 + 稳定码(与 CLI 的退出码 1 同口径),
22
23
  * 否则用户会拿到一个自检通过却什么都没有的包。
23
24
  *
@@ -198,6 +199,12 @@ export function foreignRoutes(env) {
198
199
  skipped: result.skipped,
199
200
  // 凭据只给**引用名**(形如 mcp:gitnexus:GITHUB_TOKEN):导入后由用户在 DSH 里补录
200
201
  credentialRefs: result.credentialRefs,
202
+ /**
203
+ * 溯源块(**additive**):来源标识 / 读取位置 / 项目根 / 插件元数据 / 跳过聚合 /
204
+ * 凭据引用名 —— 界面据此让用户核对「这包从哪来」(同一位也写进 manifest.foreign)。
205
+ * 翻译层没给 origin 时该键**不出现**(JSON.stringify 丢弃 undefined)⇒ 旧响应逐字不变。
206
+ */
207
+ origin: result.origin,
201
208
  /** 检测到的本机位置(相对 home),供界面显示「从哪儿读的」 */
202
209
  detectedPaths: detection.paths,
203
210
  conflictPolicy: FOREIGN_CONFLICT_POLICY,
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * 顺序对匹配无影响:DSH webServer 的契约是「命名路由必须互不相同,注册顺序不影响请求」
5
5
  * (见 @deepseek-ai/dsh-host-webserver 的 WebServer 文档)。src/index.ts 保留的 7 条被源码级
6
- * 守卫按文件窗口钉住,其余 72 条在这里组装。
6
+ * 守卫按文件窗口钉住,其余 75 条在这里组装。
7
7
  */
8
8
  import type { WebRoute } from './kit.ts';
9
9
  import type { RoutesEnv } from './context.ts';
@@ -8,8 +8,8 @@
8
8
  * - 「每条路由首行 guard」这条安全不变量此前**只写在注释里**,零测试覆盖;
9
9
  * - 3 条 prefix 路由自造围栏(裸 isLoopbackRequest + 自判方法)。
10
10
  *
11
- * 计数口径(三路一致 = 78,勿再照抄旧审计初稿的计数 —— 那是计数口径 overcount):
12
- * 路由快照 79 条 = 现行 `endpoint()` 声明 79 条 = 运行期 `buildRoutes()` 72 条 + `src/index.ts` 保留的 7 条。
11
+ * 计数口径(三路一致 = 82,勿再照抄旧审计初稿的计数 —— 那是计数口径 overcount):
12
+ * 路由快照 82 条 = 现行 `endpoint()` 声明 82 条 = 运行期 `buildRoutes()` 75 条 + `src/index.ts` 保留的 7 条。
13
13
  * 增删路由后必须同步这段计数、`src/routes/index.ts` 的头注释与 parity 快照清单;`tests/route/route-parity.test.ts`
14
14
  * 的「路由计数散文」守卫会拿真实声明数逐条对账(写错即红灯)。
15
15
  *