dsh-git-worktree 0.3.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/README.en.md +48 -18
  3. package/README.md +49 -18
  4. package/lib/adapters/git.js +8 -0
  5. package/lib/adapters/git.js.map +1 -1
  6. package/lib/adapters/registry.js +107 -2
  7. package/lib/adapters/registry.js.map +1 -1
  8. package/lib/checkpoint.d.ts +3 -0
  9. package/lib/checkpoint.js +29 -0
  10. package/lib/checkpoint.js.map +1 -0
  11. package/lib/client/WorktreeReviewRow.d.ts +1 -1
  12. package/lib/client/WorktreeReviewRow.js +26 -6
  13. package/lib/client/WorktreeReviewRow.js.map +1 -1
  14. package/lib/client/actions.d.ts +49 -4
  15. package/lib/client/actions.js +104 -0
  16. package/lib/client/actions.js.map +1 -1
  17. package/lib/client/console-remote/adapter.js +10 -3
  18. package/lib/client/console-remote/adapter.js.map +1 -1
  19. package/lib/client/review-console/DeliveryProof.d.ts +5 -0
  20. package/lib/client/review-console/DeliveryProof.js +32 -0
  21. package/lib/client/review-console/DeliveryProof.js.map +1 -0
  22. package/lib/client/review-console/PreflightStatus.d.ts +12 -0
  23. package/lib/client/review-console/PreflightStatus.js +31 -0
  24. package/lib/client/review-console/PreflightStatus.js.map +1 -0
  25. package/lib/client/review-console/ReviewActions.d.ts +4 -1
  26. package/lib/client/review-console/ReviewActions.js +657 -31
  27. package/lib/client/review-console/ReviewActions.js.map +1 -1
  28. package/lib/client/review-console/WorktreeReviewPanel.d.ts +3 -1
  29. package/lib/client/review-console/WorktreeReviewPanel.js +35 -5
  30. package/lib/client/review-console/WorktreeReviewPanel.js.map +1 -1
  31. package/lib/client/review-console/preflight-cache.d.ts +21 -0
  32. package/lib/client/review-console/preflight-cache.js +98 -0
  33. package/lib/client/review-console/preflight-cache.js.map +1 -0
  34. package/lib/client/review-console/preview-recovery-cache.d.ts +20 -0
  35. package/lib/client/review-console/preview-recovery-cache.js +103 -0
  36. package/lib/client/review-console/preview-recovery-cache.js.map +1 -0
  37. package/lib/client/review-console/recovery-continuation.d.ts +53 -0
  38. package/lib/client/review-console/recovery-continuation.js +483 -0
  39. package/lib/client/review-console/recovery-continuation.js.map +1 -0
  40. package/lib/client/review-console/review-console.styles.js +36 -4
  41. package/lib/client/review-console/review-console.styles.js.map +1 -1
  42. package/lib/client/target-console/TargetStatusAction.d.ts +4 -2
  43. package/lib/client/target-console/TargetStatusAction.js +196 -23
  44. package/lib/client/target-console/TargetStatusAction.js.map +1 -1
  45. package/lib/client/target-console/WorktreeConsoleView.d.ts +4 -2
  46. package/lib/client/target-console/WorktreeConsoleView.js +33 -73
  47. package/lib/client/target-console/WorktreeConsoleView.js.map +1 -1
  48. package/lib/client/target-console/WorktreeManagerModal.d.ts +13 -0
  49. package/lib/client/target-console/WorktreeManagerModal.js +8 -0
  50. package/lib/client/target-console/WorktreeManagerModal.js.map +1 -0
  51. package/lib/client/target-console/WorktreeReviewStatus.d.ts +3 -1
  52. package/lib/client/target-console/WorktreeReviewStatus.js +35 -15
  53. package/lib/client/target-console/WorktreeReviewStatus.js.map +1 -1
  54. package/lib/client/target-console/index.d.ts +2 -1
  55. package/lib/client/target-console/index.js +4 -3
  56. package/lib/client/target-console/index.js.map +1 -1
  57. package/lib/client/target-console/target-console.styles.js +22 -3
  58. package/lib/client/target-console/target-console.styles.js.map +1 -1
  59. package/lib/client.js +2976 -211
  60. package/lib/console-contract.d.ts +110 -1
  61. package/lib/console-contract.js.map +1 -1
  62. package/lib/console-host/control-plane.d.ts +6 -1
  63. package/lib/console-host/control-plane.js +363 -44
  64. package/lib/console-host/control-plane.js.map +1 -1
  65. package/lib/console-host/errors.d.ts +2 -2
  66. package/lib/console-host/errors.js +21 -5
  67. package/lib/console-host/errors.js.map +1 -1
  68. package/lib/console-host/projection.d.ts +5 -3
  69. package/lib/console-host/projection.js +103 -11
  70. package/lib/console-host/projection.js.map +1 -1
  71. package/lib/console-host/service.d.ts +10 -5
  72. package/lib/console-host/service.js +48 -6
  73. package/lib/console-host/service.js.map +1 -1
  74. package/lib/console-remote/descriptors.js +37 -1
  75. package/lib/console-remote/descriptors.js.map +1 -1
  76. package/lib/console-remote/remote.d.ts +10 -5
  77. package/lib/console-remote/remote.js.map +1 -1
  78. package/lib/console-remote/schemas.d.ts +103 -1
  79. package/lib/console-remote/schemas.js +166 -6
  80. package/lib/console-remote/schemas.js.map +1 -1
  81. package/lib/index.d.ts +13 -2
  82. package/lib/index.js.map +1 -1
  83. package/lib/ports.d.ts +79 -1
  84. package/lib/session-checkout-apply.d.ts +76 -0
  85. package/lib/session-checkout-apply.js +608 -143
  86. package/lib/session-checkout-apply.js.map +1 -1
  87. package/lib/session-checkout-module.js +775 -117
  88. package/lib/session-checkout-module.js.map +1 -1
  89. package/lib/types.d.ts +104 -3
  90. package/lib/types.js.map +1 -1
  91. package/package.json +14 -14
  92. package/scripts/check-publish.mjs +2 -2
package/lib/types.d.ts CHANGED
@@ -28,6 +28,16 @@ export interface WorktreeValidationItem {
28
28
  status: 'passed' | 'failed' | 'not_run';
29
29
  summary?: string;
30
30
  }
31
+ /** A saved stage that exists only in the managed Worktree history until final delivery. */
32
+ export interface WorktreeCheckpointView {
33
+ checkpointId: string;
34
+ sequence: number;
35
+ reviewId: string;
36
+ createdAt: number;
37
+ summary: string;
38
+ validationStatus: WorktreeValidationStatus;
39
+ changedFiles: string[];
40
+ }
31
41
  export interface WorktreeReviewView {
32
42
  reviewId: string;
33
43
  iteration: number;
@@ -47,6 +57,9 @@ export interface WorktreeDeliveryProofView {
47
57
  localHeadBefore: string;
48
58
  localHeadAfter: string;
49
59
  changedFiles: string[];
60
+ /** Validation evidence copied from the exact Review that authorized this delivery. */
61
+ validationStatus?: WorktreeValidationStatus;
62
+ validationSummary?: string;
50
63
  /** Whether this round's commit is still an ancestor of Local HEAD at view time. null when there is no commit. */
51
64
  commitInLocalHistory: boolean | null;
52
65
  }
@@ -91,7 +104,7 @@ export type WorktreeDeliveryView = {
91
104
  proof?: WorktreeDeliveryProofView;
92
105
  deliveredAt: number;
93
106
  };
94
- export type WorktreeApplyPreflightBlockedReason = 'not_owner' | 'not_ready_for_review' | 'stale_target' | 'stale_isolated' | 'project_acceptance_busy' | 'checkout_unavailable' | 'git_error';
107
+ export type WorktreeApplyPreflightBlockedReason = 'not_owner' | 'not_ready_for_review' | 'stale_target' | 'stale_local' | 'stale_isolated' | 'project_acceptance_busy' | 'checkout_unavailable' | 'git_error';
95
108
  export interface WorktreeApplyPreflightFacts {
96
109
  checkoutId: string;
97
110
  reviewId: string;
@@ -104,6 +117,12 @@ export interface WorktreeApplyPreflightFacts {
104
117
  isolatedHeadOid: string;
105
118
  changedFiles: string[];
106
119
  }
120
+ export interface WorktreeAcceptanceBlockerView {
121
+ checkoutId: string;
122
+ ownerSessionId: string;
123
+ revision: number;
124
+ state: 'preview_active' | 'preview_detached' | 'finalized' | 'retained' | 'working' | 'ready_for_review' | 'delivered';
125
+ }
107
126
  export type WorktreeApplyPreflightView = ({
108
127
  status: 'ready' | 'local_advanced' | 'already_in_local';
109
128
  localModified: false;
@@ -119,6 +138,8 @@ export type WorktreeApplyPreflightView = ({
119
138
  revision: number;
120
139
  reason: WorktreeApplyPreflightBlockedReason;
121
140
  message: string;
141
+ /** Path-free identity for the exact Worktree holding this project's acceptance slot. */
142
+ blocker?: WorktreeAcceptanceBlockerView;
122
143
  };
123
144
  export interface SessionTargetProjectView {
124
145
  id: string;
@@ -150,6 +171,10 @@ export interface SessionTargetView {
150
171
  revision: number;
151
172
  /** Delivery state for isolated checkouts; Local targets do not carry it. */
152
173
  delivery?: WorktreeDeliveryView;
174
+ /** Linear saved stages that remain unpublished to Local. */
175
+ checkpoints?: WorktreeCheckpointView[];
176
+ /** Host-derived CAS generation for the exact active Review/checkpoint state. */
177
+ checkpointGeneration?: string;
153
178
  /** Current project Local Preview slot state; does not expose another checkout identity. */
154
179
  reviewSlot?: 'available' | 'waiting';
155
180
  /** Owner Session holding the slot, used only for navigation/status. */
@@ -177,15 +202,83 @@ export interface SessionCheckoutFinishOperation extends SessionCheckoutOperation
177
202
  export interface SessionCheckoutPreviewOperation extends SessionCheckoutOperationBase {
178
203
  action: 'preview';
179
204
  }
205
+ export interface SessionCheckoutCheckpointOperation extends SessionCheckoutOperationBase {
206
+ action: 'checkpoint';
207
+ commitMessage: string;
208
+ expectedReviewId: string;
209
+ expectedGeneration: string;
210
+ requestId: string;
211
+ }
212
+ export type WorktreePreviewRecoveryActionBlockReason = 'stale_local' | 'preview_modified' | 'commit_isolation_conflict' | 'operation_not_allowed' | 'project_acceptance_busy';
213
+ export type WorktreePreviewRecoveryRollbackAction = {
214
+ status: 'safe';
215
+ targetTreeOid: string;
216
+ } | {
217
+ status: 'blocked';
218
+ code: WorktreePreviewRecoveryActionBlockReason;
219
+ message: string;
220
+ conflictingFiles?: string[];
221
+ };
222
+ export type WorktreePreviewRecoveryFinalizeAction = {
223
+ status: 'safe';
224
+ taskTreeOid: string;
225
+ finalIndexTreeOid: string;
226
+ expectedWorkingTreeOid: string;
227
+ commitRequired: boolean;
228
+ } | {
229
+ status: 'blocked';
230
+ code: WorktreePreviewRecoveryActionBlockReason;
231
+ message: string;
232
+ conflictingFiles?: string[];
233
+ };
234
+ /** Host-issued read-only recovery context. Mutation always recomputes and compares it under the Host lock. */
235
+ export interface WorktreePreviewRecoveryProof {
236
+ sessionId: string;
237
+ checkoutId: string;
238
+ reviewId: string;
239
+ previewId: string;
240
+ revision: number;
241
+ generation: string;
242
+ /** SHA-256 over the complete durable receipt; binds proof to retained recovery evidence. */
243
+ receiptFingerprint: string;
244
+ localFingerprint: string;
245
+ localHeadOid: string;
246
+ localHeadRef: string | null;
247
+ localHeadTreeOid: string;
248
+ localIndexTreeOid: string;
249
+ localWorkingTreeOid: string;
250
+ rollback: WorktreePreviewRecoveryRollbackAction;
251
+ finalize: WorktreePreviewRecoveryFinalizeAction;
252
+ blocker?: WorktreeAcceptanceBlockerView;
253
+ }
254
+ export type WorktreePreviewRecoveryPreflightBlockedReason = 'not_owner' | 'not_preview_detached' | 'stale_target' | 'artifacts_missing' | 'checkout_unavailable' | 'git_error';
255
+ export type WorktreePreviewRecoveryPreflightView = {
256
+ status: 'assessed';
257
+ localModified: false;
258
+ proof: WorktreePreviewRecoveryProof;
259
+ } | {
260
+ status: 'blocked';
261
+ localModified: false;
262
+ checkoutId: string;
263
+ reviewId: string | null;
264
+ previewId: string | null;
265
+ revision: number;
266
+ reason: WorktreePreviewRecoveryPreflightBlockedReason;
267
+ message: string;
268
+ };
180
269
  export interface SessionCheckoutRollbackPreviewOperation extends SessionCheckoutOperationBase {
181
270
  action: 'rollback_preview';
182
271
  /** Structured withdraw-and-continue flow returns to working instead of preserving the review. */
183
272
  resumeRevision?: boolean;
273
+ /** Required only for preview_detached; it is context to re-verify, never bearer permission. */
274
+ recoveryProof?: WorktreePreviewRecoveryProof;
184
275
  }
185
276
  export interface SessionCheckoutFinalizePreviewOperation extends SessionCheckoutOperationBase {
186
277
  action: 'finalize_preview';
187
278
  commitMessage: string;
188
279
  retention?: WorktreeRetentionMode;
280
+ /** Required only for preview_detached; it is context to re-verify, never bearer permission. */
281
+ recoveryProof?: WorktreePreviewRecoveryProof;
189
282
  }
190
283
  export interface SessionCheckoutRetryCleanupOperation extends SessionCheckoutOperationBase {
191
284
  action: 'retry_cleanup';
@@ -198,7 +291,7 @@ export interface SessionCheckoutDiscardOperation extends SessionCheckoutOperatio
198
291
  export interface SessionCheckoutRecoverOperation extends SessionCheckoutOperationBase {
199
292
  action: 'recover';
200
293
  }
201
- export type SessionCheckoutOperation = SessionCheckoutApplyOperation | SessionCheckoutFinishOperation | SessionCheckoutPreviewOperation | SessionCheckoutRollbackPreviewOperation | SessionCheckoutFinalizePreviewOperation | SessionCheckoutRetryCleanupOperation | SessionCheckoutDiscardOperation | SessionCheckoutRecoverOperation;
294
+ export type SessionCheckoutOperation = SessionCheckoutApplyOperation | SessionCheckoutFinishOperation | SessionCheckoutPreviewOperation | SessionCheckoutCheckpointOperation | SessionCheckoutRollbackPreviewOperation | SessionCheckoutFinalizePreviewOperation | SessionCheckoutRetryCleanupOperation | SessionCheckoutDiscardOperation | SessionCheckoutRecoverOperation;
202
295
  export interface SessionCheckoutAppliedResult {
203
296
  status: 'applied';
204
297
  target: SessionTargetView;
@@ -209,6 +302,12 @@ export interface SessionCheckoutPreviewedResult {
209
302
  target: SessionTargetView;
210
303
  changedFiles: string[];
211
304
  }
305
+ export interface SessionCheckoutCheckpointedResult {
306
+ status: 'checkpointed';
307
+ target: SessionTargetView;
308
+ checkpoint: WorktreeCheckpointView;
309
+ changedFiles: string[];
310
+ }
212
311
  export interface SessionCheckoutPreviewRolledBackResult {
213
312
  status: 'preview_rolled_back';
214
313
  target: SessionTargetView;
@@ -270,6 +369,8 @@ export interface ManagedWorktreeSummaryView {
270
369
  phase: SessionCheckoutPhase;
271
370
  dirty: boolean;
272
371
  commitOid: string | null;
372
+ /** Number of saved managed-Worktree stages not yet delivered to Local. */
373
+ checkpointCount?: number;
273
374
  retention?: Exclude<WorktreeRetentionMode, 'cleanup'>;
274
375
  retainedAt?: number;
275
376
  expiresAt?: number | null;
@@ -311,7 +412,7 @@ export interface SessionCheckoutOperationErrorResult {
311
412
  message: string;
312
413
  target?: SessionTargetView;
313
414
  }
314
- export type SessionCheckoutOperationResult = SessionCheckoutAppliedResult | SessionCheckoutPreviewedResult | SessionCheckoutPreviewRolledBackResult | SessionCheckoutPreviewDetachedResult | SessionCheckoutFinishedResult | SessionCheckoutConflictResult | SessionCheckoutDiscardedResult | SessionCheckoutRecoveredResult | SessionCheckoutOperationErrorResult;
415
+ export type SessionCheckoutOperationResult = SessionCheckoutAppliedResult | SessionCheckoutPreviewedResult | SessionCheckoutCheckpointedResult | SessionCheckoutPreviewRolledBackResult | SessionCheckoutPreviewDetachedResult | SessionCheckoutFinishedResult | SessionCheckoutConflictResult | SessionCheckoutDiscardedResult | SessionCheckoutRecoveredResult | SessionCheckoutOperationErrorResult;
315
416
  export declare const SESSION_CHECKOUT_ERROR_CODES: readonly ["session_not_found", "project_not_found", "project_root_missing", "not_git_repository", "target_unselected", "target_already_bound", "project_mismatch", "checkout_missing", "checkout_mismatch", "recovery_required", "registry_corrupt", "git_operation_failed", "not_owner", "stale_target", "dirty_confirmation_required", "apply_conflict", "apply_failed", "invalid_input", "invalid_plan", "stale_local", "stale_isolated", "git_error", "commit_isolation_conflict", "checkout_limit_reached", "project_acceptance_busy", "operation_not_allowed", "preview_not_active", "preview_modified", "recovery_unsafe"];
316
417
  export type SessionCheckoutErrorCode = typeof SESSION_CHECKOUT_ERROR_CODES[number];
317
418
  export interface SessionCheckoutFailure {
package/lib/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA8XH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,mBAAmB;IACnB,mBAAmB;IACnB,sBAAsB;IACtB,oBAAoB;IACpB,mBAAmB;IACnB,sBAAsB;IACtB,kBAAkB;IAClB,kBAAkB;IAClB,mBAAmB;IACnB,mBAAmB;IACnB,kBAAkB;IAClB,sBAAsB;IACtB,WAAW;IACX,cAAc;IACd,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,eAAe;IACf,cAAc;IACd,aAAa;IACb,gBAAgB;IAChB,WAAW;IACX,2BAA2B;IAC3B,wBAAwB;IACxB,yBAAyB;IACzB,uBAAuB;IACvB,oBAAoB;IACpB,kBAAkB;IAClB,iBAAiB;CACT,CAAA"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgfH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,mBAAmB;IACnB,mBAAmB;IACnB,sBAAsB;IACtB,oBAAoB;IACpB,mBAAmB;IACnB,sBAAsB;IACtB,kBAAkB;IAClB,kBAAkB;IAClB,mBAAmB;IACnB,mBAAmB;IACnB,kBAAkB;IAClB,sBAAsB;IACtB,WAAW;IACX,cAAc;IACd,6BAA6B;IAC7B,gBAAgB;IAChB,cAAc;IACd,eAAe;IACf,cAAc;IACd,aAAa;IACb,gBAAgB;IAChB,WAAW;IACX,2BAA2B;IAC3B,wBAAwB;IACxB,yBAAyB;IACzB,uBAAuB;IACvB,oBAAoB;IACpB,kBAAkB;IAClB,iBAAiB;CACT,CAAA"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-git-worktree",
3
- "version": "0.3.2",
4
- "description": "Experimental Git worktree Session Targets for DeepSeek Harness with real isolated sessions, review ToolViews, human-confirmed delivery, and safe cleanup.",
3
+ "version": "0.6.0",
4
+ "description": "Experimental Git worktree Session Targets for DeepSeek Harness with isolated sessions, review checkpoints, human-confirmed delivery, and safe recovery.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -59,7 +59,7 @@
59
59
  },
60
60
  "homepage": "https://github.com/wloops/dsh-git-worktree#readme",
61
61
  "engines": {
62
- "node": ">=20"
62
+ "node": "^22.19.0 || >=24.0.0"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "node scripts/clean-lib.mjs && tsc && tsdown",
@@ -76,14 +76,14 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@deepseek-ai/cordis": "4.0.1",
79
- "@deepseek-ai/dsh-agent": "0.1.0-rc.7",
80
- "@deepseek-ai/dsh-commands": "0.1.0-rc.7",
81
- "@deepseek-ai/dsh-session": "0.1.0-rc.7",
82
- "@deepseek-ai/dsh-subprocess": "0.1.0-rc.7",
83
- "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.7",
84
- "@deepseek-ai/dsh-tools": "0.1.0-rc.7",
85
- "@deepseek-ai/dsh-typert-protocol": "0.1.0-rc.7",
86
- "@deepseek-ai/dsh-typert-registry": "0.1.0-rc.7",
79
+ "@deepseek-ai/dsh-agent": "0.1.1-rc.2",
80
+ "@deepseek-ai/dsh-commands": "0.1.1-rc.2",
81
+ "@deepseek-ai/dsh-session": "0.1.1-rc.2",
82
+ "@deepseek-ai/dsh-subprocess": "0.1.1-rc.2",
83
+ "@deepseek-ai/dsh-system-prompt": "0.1.1-rc.2",
84
+ "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
85
+ "@deepseek-ai/dsh-typert-protocol": "0.1.1-rc.2",
86
+ "@deepseek-ai/dsh-typert-registry": "0.1.1-rc.2",
87
87
  "@deepseek-ai/schemastery": "3.18.1",
88
88
  "zod": "4.4.3"
89
89
  },
@@ -91,9 +91,9 @@
91
91
  "react": "^18.2.0"
92
92
  },
93
93
  "devDependencies": {
94
- "@deepseek-ai/dsh-api-gateway": "0.1.0-rc.7",
95
- "@deepseek-ai/dsh-client-connection": "0.1.0-rc.7",
96
- "@deepseek-ai/dsh-typert-loader": "0.1.0-rc.7",
94
+ "@deepseek-ai/dsh-api-gateway": "0.1.1-rc.2",
95
+ "@deepseek-ai/dsh-client-connection": "0.1.1-rc.2",
96
+ "@deepseek-ai/dsh-typert-loader": "0.1.1-rc.2",
97
97
  "@testing-library/react": "^16.3.2",
98
98
  "@types/node": "^22.0.0",
99
99
  "@types/react": "~18.3.31",
@@ -94,7 +94,7 @@ try {
94
94
  if (hostContribution?.package !== manifest.name || hostContribution.face !== 'host') fail('./typert has invalid package/face identity')
95
95
  if (remoteContribution?.package !== manifest.name) fail('./remote has invalid package identity')
96
96
  if (hostContribution.invocations !== remoteContribution.descriptors) fail('./typert and ./remote must share one descriptor array instance')
97
- const expectedRemoteMethods = ['current', 'list', 'create', 'inspect', 'reviewDiff', 'preflight', 'preview', 'resumeRevision', 'rollbackPreview', 'discard', 'finalize', 'finalizePreview', 'setRetention', 'retryCleanup', 'beginNextIteration']
97
+ const expectedRemoteMethods = ['current', 'list', 'create', 'inspect', 'reviewDiff', 'preflight', 'previewRecoveryPreflight', 'preparePreviewRecoveryAnalysis', 'createPreviewRecoveryHandoff', 'preview', 'checkpoint', 'resumeRevision', 'prepareReviewRegeneration', 'rollbackPreview', 'discard', 'finalize', 'finalizePreview', 'setRetention', 'retryCleanup', 'beginNextIteration']
98
98
  if (JSON.stringify(hostContribution.invocations.map(value => value.method)) !== JSON.stringify(expectedRemoteMethods)) {
99
99
  fail(`manual Remote methods differ from the required surface: ${hostContribution.invocations.map(value => value.method).join(', ')}`)
100
100
  }
@@ -161,7 +161,7 @@ if (!handoff || handoff.id !== manifest.name || typeof handoff.factory !== 'func
161
161
  fail(`client bundle must call window.__ModuleLoader__.load with id ${JSON.stringify(manifest.name)} and a factory`)
162
162
  }
163
163
  const browserRequire = (specifier) => {
164
- if (specifier === '@deepseek-ai/dsh-client-ui-primitives') return { Modal: () => null }
164
+ if (specifier === '@deepseek-ai/dsh-client-ui-primitives') return { Modal: () => null, Menu: () => null }
165
165
  return require(specifier)
166
166
  }
167
167
  let clientExports