Repository navigation
Expand file tree
/
Copy pathfork-features.json
More file actions
628 lines (628 loc) · 60.8 KB
/
Copy pathfork-features.json
File metadata and controls
628 lines (628 loc) · 60.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
{
"comment": "Every feature this fork carries over pingdotgg/t3code. Each entry's \"keep\" line is the per-file resolution rule an upstream merge conflict is settled by: what of ours must survive in the listed files, and what takes upstream. scripts/check-fork-features.ts fails when a keep line, a listed file or a test file is gone, then runs the listed tests. .github/workflows/fork-update.yml runs it in the gate, so an upstream merge that deletes a fork seam stops before it can publish. See docs/agents/upstream-conflict-resolution.md and docs/operations/fork-windows-build.md.",
"features": [
{
"name": "fork-app-identity",
"description": "The fork installs and runs beside official T3 Code: its own app id, product name, state directory (~/.t3-fork) and t3code-fork:// link scheme, the one the OS routes to the app. The renderer itself is served from upstream's t3code://app, see fork-connect-renderer-origin. Issues #34 and #59.",
"keep": "Our app id, product name, window title, ~/.t3-fork state directory, t3code-fork:// link scheme and Linux desktop entry name and WM class replace upstream's wherever these files set them; the renderer scheme stays upstream's t3code; take upstream for the rest of these files, then re-apply those settings on top.",
"files": [
"apps/desktop/src/app/DesktopEnvironment.ts",
"apps/desktop/src/app/DesktopEarlyElectronStartup.ts",
"apps/desktop/src/app/DesktopLinuxUrlHandler.ts",
"apps/desktop/src/electron/ElectronProtocol.ts",
"apps/desktop/src/app/DesktopEnvironment.test.ts",
"apps/desktop/src/app/DesktopPreReadyPlatform.test.ts",
"apps/desktop/src/window/DesktopWindow.test.ts"
],
"test": "apps/desktop/src/app/DesktopLinuxUrlHandler.test.ts",
"patchesUpstream": true
},
{
"name": "fork-desktop-build",
"description": "The desktop build stages the fork's app id, product name and installer file name, and reads its update source from T3CODE_DESKTOP_UPDATE_REPOSITORY. scripts/release-smoke.ts also carries the fork's fix for running the release-only shell steps under Git for Windows bash. Issues #59, #75 and #94.",
"keep": "Our app id, product name, installer file name, the T3CODE_DESKTOP_UPDATE_REPOSITORY update source and the Git for Windows bash fix in release-smoke.ts replace upstream's; take upstream for the rest of these files, then re-apply those parts on top.",
"files": ["scripts/build-desktop-artifact.ts", "scripts/release-smoke.ts"],
"test": "scripts/build-desktop-artifact.test.ts",
"patchesUpstream": true
},
{
"name": "windows-console-suppression",
"description": "Spawned server and provider processes no longer draw a console window on Windows. Issue #82.",
"keep": "windowsConsole.ts is ours whole; take upstream for the rest of the other listed files, then re-apply every call into windowsConsole.ts that hides a spawned console window on top.",
"files": [
"packages/shared/src/windowsConsole.ts",
"packages/shared/src/shell.ts",
"apps/desktop/src/main.ts",
"apps/server/src/bin.ts",
"apps/server/src/serviceLauncher.ts"
],
"test": "packages/shared/src/windowsConsole.test.ts",
"patchesUpstream": true
},
{
"name": "terminal-subprocess-poll",
"description": "Bounded terminal and preview polling on one shared back-off engine: a probe budget held under the poll period, bounded fan-out, a round that backs off when nothing changed and returns to the base period on any event. Issue #83, merged in #106, re-applied on upstream v0.0.39's terminal manager in #125. pollLoop.ts is the fork's own module and upstream has no file at that path, so its test cannot pass on plain upstream.",
"keep": "pollLoop.ts is ours whole, and Manager.ts and PortScanner.ts must still drive their polling through it; take upstream for the rest of those two files, then re-apply the pollLoop call sites on top.",
"files": [
"apps/server/src/pollLoop.ts",
"apps/server/src/terminal/Manager.ts",
"apps/server/src/preview/PortScanner.ts"
],
"test": "apps/server/src/pollLoop.test.ts",
"patchesUpstream": true
},
{
"name": "fork-automatic-updates",
"description": "A found update downloads with no click and installs on the next quit. One update pill label names the waiting version, Settings shows the state in plain words, and a switch turns it off for upstream's two-click flow. forkAutomaticUpdates.ts and forkAutomaticUpdates.logic.ts are the fork's own modules and upstream has no file at either path, so the test cannot pass on plain upstream. Issue #113.",
"keep": "forkAutomaticUpdates.ts and forkAutomaticUpdates.logic.ts are ours whole, and the automatic download, the single update pill label, the Settings state and switch, and the IPC channel that carries them survive in the other listed files; the \"Update pill label\" row in docs/internals/glossary.md is ours whole too; everything else in those files takes upstream.",
"files": [
"apps/desktop/src/updates/forkAutomaticUpdates.ts",
"apps/desktop/src/updates/DesktopUpdates.ts",
"apps/desktop/src/updates/updateMachine.ts",
"apps/desktop/src/updates/updatesTestHarness.ts",
"apps/desktop/src/updates/DesktopUpdates.test.ts",
"apps/desktop/src/settings/DesktopAppSettings.ts",
"apps/desktop/src/ipc/channels.ts",
"apps/desktop/src/ipc/methods/updates.ts",
"apps/desktop/src/ipc/DesktopIpcHandlers.ts",
"apps/desktop/src/preload.ts",
"packages/contracts/src/ipc.ts",
"apps/web/src/components/forkAutomaticUpdates.logic.ts",
"apps/web/src/components/forkAutomaticUpdates.logic.test.ts",
"apps/web/src/components/sidebar/SidebarUpdatePill.tsx",
"apps/web/src/components/settings/SettingsPanels.tsx",
"docs/internals/glossary.md"
],
"test": "apps/desktop/src/updates/forkAutomaticUpdates.test.ts",
"patchesUpstream": true
},
{
"name": "fork-repository-identity-read-path",
"description": "A project's repository identity is resolved off the read path and stored on its projection row, so a snapshot read never runs git. Issue #72.",
"keep": "RepositoryIdentityReactor.ts, its service, the 003 fork migration and GitWorkDepth.ts are ours whole, and ProjectionSnapshotQuery.ts must keep serving the stored repository_identity_json column instead of resolving an identity on the read path; take upstream for the rest of ProjectionSnapshotQuery.ts, then re-apply the stored-column reads on top.",
"files": [
"apps/server/src/orchestration/Layers/RepositoryIdentityReactor.ts",
"apps/server/src/orchestration/Services/RepositoryIdentityReactor.ts",
"apps/server/src/persistence/ForkMigrations/003_ProjectionProjectRepositoryIdentity.ts",
"apps/server/src/vcs/GitWorkDepth.ts",
"apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts"
],
"test": "apps/server/src/orchestration/Layers/ShellSnapshotSpawn.test.ts",
"patchesUpstream": true
},
{
"name": "fm-acp-provider",
"description": "First Mate is driven through its ACP door as a configurable ACP agent provider. Issues #78 and #79.",
"keep": "Every listed file is the fork's own and upstream has no file at these paths, so keep our side of anything that conflicts here; nothing in these files takes upstream. If upstream adds a file at one of these paths, keep our file and rename upstream's.",
"files": [
"apps/server/src/provider/acpAgent/AcpAgentProvider.ts",
"apps/server/src/provider/acpAgent/AcpAgentDriver.ts",
"apps/server/src/provider/acpAgent/AcpAgentAdapter.ts",
"apps/server/src/provider/acpAgent/AcpAgentIdentity.ts",
"apps/server/src/provider/acpAgent/AcpAgentSupport.ts"
],
"test": "apps/server/src/provider/acpAgent/AcpAgentProvider.test.ts",
"patchesUpstream": false
},
{
"name": "fm-worker-threads",
"description": "First Mate workers show up as read-only threads, with the fork's own migration track behind them. Issue #81.",
"keep": "AcpAgentWorkerThreadReactor.ts, AcpAgentWorkerSessions.ts, AcpPeerSessions.ts and ForkMigrations.ts are ours whole, and decider.ts must keep our read-only thread handling; take upstream for the rest of decider.ts, then re-apply the read-only rules on top.",
"files": [
"apps/server/src/provider/acpAgent/AcpAgentWorkerThreadReactor.ts",
"apps/server/src/provider/acpAgent/AcpAgentWorkerSessions.ts",
"apps/server/src/provider/acp/AcpPeerSessions.ts",
"apps/server/src/persistence/ForkMigrations.ts",
"apps/server/src/orchestration/decider.ts"
],
"test": "apps/server/src/orchestration/decider.readOnly.test.ts",
"patchesUpstream": true
},
{
"name": "fork-connect-public-env",
"description": "The desktop build ships with T3 Connect switched on. A clone with no .env gets .env.example copied to .env before the build spawns, so server.asar and app.asar carry the public Clerk key and relay URL. fork-public-env.ts is the fork's own module and upstream has no file at that path, so its test cannot pass on plain upstream. Issue #137.",
"keep": "fork-public-env.ts is ours whole, and the call that copies .env.example to .env before the build spawns survives in build-desktop-artifact.ts, the workflow and the doc; everything else in those files takes upstream.",
"files": [
"scripts/lib/fork-public-env.ts",
"scripts/build-desktop-artifact.ts",
".github/workflows/fork-update.yml",
"docs/operations/fork-windows-build.md"
],
"test": "scripts/lib/fork-public-env.test.ts",
"patchesUpstream": true
},
{
"name": "fork-connect-renderer-origin",
"description": "T3 Connect sign-in works in the fork. T3's production Clerk instance accepts t3code://app and rejects t3code-fork://app with origin_invalid, so the renderer is served from upstream's t3code scheme while the Clerk bridge, the installer and the Linux desktop entry keep the fork's t3code-fork link scheme. On first launch ForkRendererStorageMigration.ts copies localStorage (drafts, prompt stash, themes, sidebar and second mate folds) from the old t3code-fork://app origin to t3code://app. The Clerk bridge registers its link scheme as privileged on its own, and Electron keeps the secure, fetch and CORS schemes of the last call only, so DesktopClerk.ts lists every scheme again right after creating the bridge. Without that t3code://app is not a secure context, crypto.subtle is undefined and every T3 Connect relay call fails. ForkRendererStorageMigration.ts is the fork's own module and upstream has no file at that path, so its test cannot pass on plain upstream.",
"keep": "ForkRendererStorageMigration.ts is ours whole. getDesktopLinkScheme, the link schemes in the privileged scheme list and the comments on them survive in ElectronProtocol.ts; DesktopClerk.ts, DesktopLinuxUrlHandler.ts and DesktopPreReadyPlatform.ts pass getDesktopLinkScheme where upstream passes getDesktopScheme; registerDesktopSchemePrivilegesSync stays exported from ElectronProtocol.ts and DesktopClerk.ts calls it right after createClerkBridge; the migration call before registerDesktopProtocol survives in DesktopApp.ts; the Google and GitHub sign-in note survives in the doc; everything else in those files takes upstream.",
"files": [
"apps/desktop/src/app/ForkRendererStorageMigration.ts",
"apps/desktop/src/electron/ElectronProtocol.ts",
"apps/desktop/src/app/DesktopClerk.ts",
"apps/desktop/src/app/DesktopLinuxUrlHandler.ts",
"apps/desktop/src/app/DesktopPreReadyPlatform.ts",
"apps/desktop/src/app/DesktopApp.ts",
"docs/operations/fork-windows-build.md"
],
"test": [
"apps/desktop/src/app/ForkRendererStorageMigration.test.ts",
"apps/desktop/src/electron/ElectronProtocol.test.ts",
"apps/desktop/src/app/DesktopClerk.schemePrivileges.test.ts"
],
"patchesUpstream": true
},
{
"name": "fm-worker-thread-model",
"description": "A read-only worker thread says which model and thinking level is behind it: a strip where the composer would sit, and badges on a full sidebar row; a compact row leaves them to the hover card so its title keeps room. ReadOnlyThreadModel.tsx and readOnlyThreadModel.logic.ts are the fork's own modules and upstream has no file at either path, so the test cannot pass on plain upstream. Issue #135.",
"keep": "ReadOnlyThreadModel.tsx and readOnlyThreadModel.logic.ts are ours whole, and the model and thinking level strip and sidebar badges they add survive in ChatView.tsx and Sidebar.tsx; everything else in those files takes upstream.",
"files": [
"apps/web/src/components/chat/ReadOnlyThreadModel.tsx",
"apps/web/src/components/chat/readOnlyThreadModel.logic.ts",
"apps/web/src/components/ChatView.tsx",
"apps/web/src/components/Sidebar.tsx"
],
"test": "apps/web/src/components/chat/readOnlyThreadModel.test.tsx",
"patchesUpstream": true
},
{
"name": "fm-fleet-thread-roles",
"description": "Fleet threads carry a role. The First Mate thread never auto-settles and, pinned, has its own sidebar slot; fm-fleet-sidebar-tree arranges second mates and workers.",
"keep": "fleetThreads.ts, useStartFirstMateThread.ts and fork migration 8 are ours whole, and the fleetRole and fleetRepo fields, the First Mate sidebar slot, the settlement exception and the single First Mate invariant survive in the files listed; everything else in those files follows upstream.",
"files": [
"packages/contracts/src/orchestration.ts",
"packages/client-runtime/src/fleetThreads.ts",
"apps/server/src/orchestration/commandInvariants.ts",
"apps/server/src/orchestration/ThreadSettlementPolicy.ts",
"apps/server/src/persistence/ForkMigrations/008_ProjectionThreadsFleetRole.ts",
"apps/web/src/components/Sidebar.tsx",
"apps/web/src/hooks/useStartFirstMateThread.ts"
],
"test": "apps/server/src/orchestration/decider.fleetRole.test.ts",
"patchesUpstream": true
},
{
"name": "fm-fleet-sidebar-tree",
"description": "The sidebar shows First Mate's fleet as a tree above the other threads. First Mate always holds the top, above a divider: the pinned First Mate, or else the newest live one, with any others under it; with none live, a Start First Mate row stands there instead. Second mates follow in repository-name order and never move with activity; each worker is indented under the second mate that shares its fleetRepo, and a second mate can fold its workers away; the fold is saved with the other sidebar settings, like a project fold, so it survives Settings, project edits and a restart. A settled or snoozed worker leaves the tree and lists in the Settled or Snoozed section with the other threads, and un-settling or waking it puts it back under its second mate. A settled second mate leaves the tree for Settled with all its workers, each listed by its own state, and un-settling it brings it and its live workers back. A snoozed second mate stays a full row in the tree, dimmed, with its wake control, and a pinned second mate keeps its unpin. One rule, resolveParkedState, decides parking for both the tree and the sections, and a drag out of Settled or Snoozed lands a worker straight in the tree. A compact row in Settled or Snoozed always shows its title and the whole role word, and leaves the model and thinking level to the hover card. Fleet rows name their role on the model line in their own colour, then the model and reasoning level, with a ship, sailboat or pickaxe beside the project icon. A second mate's colour, and its workers' quieter one, comes from its project icon as the sidebar shows it: a badge's own colour, or an image logo's main colour read once from the image, with only its lightness set for each theme. Only an icon with no usable colour falls back to a stable colour from the repository name. First Mate keeps its pink.",
"keep": "fleetSidebar.logic.ts, fleetTone.logic.ts, FleetTone.tsx, their tests, Sidebar.fleetTree.test.tsx, FirstMateIcon.tsx and FleetRoleIcon.tsx are ours whole. In Sidebar.tsx the fleet tree rows built by useFleetTreeRows, the parkedStateOf helper that calls resolveParkedState and feeds both buildFleetTree and the section loop through sidebarSectionFor, the fleetTreeThreadKeys hold on a drag that lands in the tree, the compact row that keeps the whole role word and drops the model badges, the FleetRowPlacement prop and onPin on SidebarThreadRow, the role line, the fold arrow, the First Mate slot with its Start First Mate row and divider survive; partitionFirstMateThreads survives in Sidebar.logic.ts and its tests in Sidebar.logic.test.ts; the First Mate threads section of docs/user/thread-sidebar.md is ours; in uiStateStore.ts the fleetRepoExpandedById field, its load and save lines, setFleetRepoExpanded and resetUiStateForTests survive, and in uiStateStore.test.ts the fleetRepoExpandedById lines and the folded second mates test survive. Everything else in those files takes upstream.",
"files": [
"apps/web/src/components/sidebar/fleetSidebar.logic.ts",
"apps/web/src/components/sidebar/fleetTone.logic.ts",
"apps/web/src/components/sidebar/FleetTone.tsx",
"apps/web/src/components/FirstMateIcon.tsx",
"apps/web/src/components/FleetRoleIcon.tsx",
"apps/web/src/components/Sidebar.tsx",
"apps/web/src/components/Sidebar.logic.ts",
"apps/web/src/components/Sidebar.logic.test.ts",
"apps/web/src/uiStateStore.ts",
"apps/web/src/uiStateStore.test.ts",
"docs/user/thread-sidebar.md"
],
"test": [
"apps/web/src/components/sidebar/fleetSidebar.logic.test.ts",
"apps/web/src/components/sidebar/fleetTone.logic.test.ts",
"apps/web/src/components/Sidebar.fleetTree.test.tsx"
],
"patchesUpstream": true
},
{
"name": "fm-fleet-thread-read-only-clear",
"description": "The fleet can clear read-only on a second mate's thread with thread.read-only.clear, so the user can type into it. Only the fleet issuer may send it, and only on a fleet-owned, unarchived thread whose fleetRole is second-mate. It records a thread.read-only-cleared event that sets readOnly to false on the thread and its shell row, so it survives a restart and clients update. Nothing makes a thread read-only again. The server advertises fleetThreadReadOnlyClear in its environment capabilities.",
"keep": "fleetThreadReadOnlyClear.test.ts is ours whole. The thread.read-only-cleared case survives in threadReducer.test.ts, and the fleetThreadReadOnlyClear assertion survives in ServerEnvironment.test.ts. The thread.read-only.clear command, the thread.read-only-cleared event and payload, and the OrchestrationThread.readOnly comment survive in orchestration.ts; the fleetThreadReadOnlyClear capability survives in environment.ts and ServerEnvironment.ts; readOnlyClearRefusal survives in fleetThreads.ts; the issuer stamp for the command survives in Normalizer.ts; the command case survives in decider.ts; the event case survives in projector.ts, ProjectionPipeline.ts and threadReducer.ts; and the payload re-export survives in Schemas.ts. Everything else in those files takes upstream.",
"files": [
"packages/contracts/src/orchestration.ts",
"packages/contracts/src/environment.ts",
"packages/client-runtime/src/state/threadReducer.ts",
"apps/server/src/environment/ServerEnvironment.ts",
"apps/server/src/orchestration/fleetThreads.ts",
"apps/server/src/orchestration/Normalizer.ts",
"apps/server/src/orchestration/decider.ts",
"apps/server/src/orchestration/projector.ts",
"apps/server/src/orchestration/Schemas.ts",
"apps/server/src/orchestration/Layers/ProjectionPipeline.ts"
],
"test": [
"apps/server/src/orchestration/fleetThreadReadOnlyClear.test.ts",
"packages/client-runtime/src/state/threadReducer.test.ts",
"apps/server/src/environment/ServerEnvironment.test.ts"
],
"patchesUpstream": true
},
{
"name": "fm-fleet-thread-berth-set",
"description": "The fleet can set fleetRole and fleetRepo on a thread it already owns with thread.fleet-berth.set, to repair threads created before the fleet sent them. Only the fleet issuer may send it, only on a fleet-owned, unarchived thread that is not the First Mate thread, and never with fleetRole first-mate, so only thread.create makes a First Mate thread. It records a thread.fleet-berth-set event that sets fleet_role and fleet_repo on the thread and its shell row, so it survives a restart and clients update. The berth a thread already has is accepted and keeps its updatedAt. The server advertises fleetThreadBerthSet in its environment capabilities.",
"keep": "fleetThreadBerthSet.test.ts is ours whole. The thread.fleet-berth-set case survives in threadReducer.test.ts, the fleetThreadBerthSet assertion survives in ServerEnvironment.test.ts, and the fleet berth set test survives in server.test.ts. The thread.fleet-berth.set command, the thread.fleet-berth-set event and payload, and the OrchestrationThread.fleetRole comment survive in orchestration.ts; the fleetThreadBerthSet capability survives in environment.ts and ServerEnvironment.ts; resolveFleetBerth survives in fleetThreads.ts; the issuer stamp for the command survives in Normalizer.ts; the command case survives in decider.ts; the event case survives in projector.ts, ProjectionPipeline.ts and threadReducer.ts; the payload re-export survives in Schemas.ts; and the thread.fleet-berth.set sentence of the Fleet role row survives in docs/internals/glossary.md. Everything else in those files takes upstream.",
"files": [
"packages/contracts/src/orchestration.ts",
"packages/contracts/src/environment.ts",
"packages/client-runtime/src/state/threadReducer.ts",
"apps/server/src/environment/ServerEnvironment.ts",
"apps/server/src/orchestration/fleetThreads.ts",
"apps/server/src/orchestration/Normalizer.ts",
"apps/server/src/orchestration/decider.ts",
"apps/server/src/orchestration/projector.ts",
"apps/server/src/orchestration/Schemas.ts",
"apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
"docs/internals/glossary.md"
],
"test": [
"apps/server/src/orchestration/fleetThreadBerthSet.test.ts",
"packages/client-runtime/src/state/threadReducer.test.ts",
"apps/server/src/environment/ServerEnvironment.test.ts",
"apps/server/src/server.test.ts"
],
"patchesUpstream": true
},
{
"name": "fm-turn-start-when-busy",
"description": "A turn start can ask to wait for an idle thread with whenBusy: \"queue\", so a supervisor's wake never steers into a turn the person just started. The decider holds it while the thread is busy, starts it in the command that frees the thread after a normal turn end, and drops it with a recorded reason on Stop, a stopped, interrupted or failed session, a failed turn start, archive or delete. It is persisted, so it survives a restart and runs once. The server advertises turnStartWhenBusy in its environment capabilities.",
"keep": "deferredTurnStarts.ts, ProjectionThreadDeferredTurnStarts.ts, fork migration 9 and turnStartWhenBusy.integration.test.ts are ours whole. The whenBusy option, the thread.turn-start-deferred and thread.deferred-turn-start-dropped events, the thread.deferred-turn-start.release command and the deferredTurnStarts and pendingTurnStart fields survive in orchestration.ts; the turnStartWhenBusy capability survives in environment.ts and ServerEnvironment.ts; the whenBusy queue branch, the release command case and the decideOrchestrationCommand wrapper that calls followDeferredTurnStarts survive in decider.ts; the projectEvent wrapper that calls projectDeferredTurnStarts survives in projector.ts; the deferred-turn-start table writes and reads survive in ProjectionPipeline.ts and ProjectionSnapshotQuery.ts; the startup release loop survives in serverRuntimeStartup.ts; and holdCompletion, getSteers, getTurnInputs and awaitSends survive in TestProviderAdapter.integration.ts. Everything else in those files takes upstream.",
"files": [
"packages/contracts/src/orchestration.ts",
"packages/contracts/src/environment.ts",
"apps/server/src/environment/ServerEnvironment.ts",
"apps/server/src/orchestration/deferredTurnStarts.ts",
"apps/server/src/orchestration/decider.ts",
"apps/server/src/orchestration/projector.ts",
"apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
"apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts",
"apps/server/src/serverRuntimeStartup.ts",
"apps/server/src/persistence/ProjectionThreadDeferredTurnStarts.ts",
"apps/server/src/persistence/ForkMigrations/009_ProjectionThreadDeferredTurnStarts.ts",
"apps/server/integration/TestProviderAdapter.integration.ts"
],
"test": "apps/server/integration/turnStartWhenBusy.integration.test.ts",
"patchesUpstream": true
},
{
"name": "fm-turn-start-when-busy-environment",
"description": "A deferred turn start (whenBusy: \"queue\") can carry an environment. The engine keeps it in memory, never on an event or in the deferred-turn-start table, and hands it to the provider reactor when the deferred turn start runs, so the session spawned or restarted for it gets it, as for a direct start. The deferred turn start records only hasEnvironment. After a restart the environment is gone, so the decider drops it with the environment-lost reason instead of running it without it. The decider asks the engine through DeciderContext, a signed-off exception to pure orchestration. The server advertises turnStartWhenBusyEnvironment in its environment capabilities.",
"keep": "TurnEnvironment.ts, DeciderContext.ts and deferredTurnStarts.ts are ours whole, including makeDeferredTurnEnvironments and the environment-lost drop in releaseDeferredTurnStart. The hasEnvironment field and the environment-lost drop reason survive in orchestration.ts; the turnStartWhenBusyEnvironment capability survives in environment.ts and ServerEnvironment.ts; and the deferredTurnEnvironments instance, the DeciderContext it provides around decideOrchestrationCommand and its remember call after the commit survive in OrchestrationEngine.ts. Everything else in those files takes upstream.",
"files": [
"packages/contracts/src/orchestration.ts",
"packages/contracts/src/environment.ts",
"apps/server/src/environment/ServerEnvironment.ts",
"apps/server/src/orchestration/TurnEnvironment.ts",
"apps/server/src/orchestration/DeciderContext.ts",
"apps/server/src/orchestration/deferredTurnStarts.ts",
"apps/server/src/orchestration/Layers/OrchestrationEngine.ts"
],
"test": "apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts",
"testName": "defers a turn start that carries an environment and starts it when free|after a restart, drops a deferred turn start whose environment died with the process|does not defer a turn start that carries an environment without whenBusy",
"patchesUpstream": true
},
{
"name": "fm-turn-start-when-busy-environment-reactor-tests",
"description": "The provider reactor tests for fm-turn-start-when-busy-environment: a deferred turn start spawns or restarts its session with its environment, and one on an idle thread applies it like a direct start. The manifest takes one test file per entry, so these tests have their own entry.",
"keep": "The three tests named in testName, the setThreadTurnRunning helper and the whenBusy option of dispatchTurn survive in ProviderCommandReactor.test.ts. Everything else in that file takes upstream.",
"files": ["apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts"],
"test": "apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts",
"testName": "a deferred turn start spawns its session with its environment|a deferred turn start restarts a live session for its environment|a turn start that asks to wait applies its environment on an idle thread",
"patchesUpstream": true
},
{
"name": "fm-turn-start-when-busy-environment-restart-test",
"description": "The startup test for fm-turn-start-when-busy-environment: after a real restart a deferred turn start with an environment is dropped with environment-lost and the one behind it runs. The manifest takes one test file per entry, so this test has its own entry.",
"keep": "The test named in testName and the decodeProviderEnvironment helper survive in orphanedProviderSessionStartup.integration.test.ts. Everything else in that file takes upstream.",
"files": ["apps/server/integration/orphanedProviderSessionStartup.integration.test.ts"],
"test": "apps/server/integration/orphanedProviderSessionStartup.integration.test.ts",
"testName": "drops a deferred turn start whose environment a restart lost",
"patchesUpstream": true
},
{
"name": "fm-turn-start-when-busy-ended-session",
"description": "A thread whose session ended (stopped, interrupted or error) counts as free for a turn start that asks to queue once no turn is active and the latest turn is not running, so the start runs at once instead of becoming a deferred turn start that no event releases. A runtime error without a turn id keeps the running turn named in the session, so an error raised mid-turn keeps the thread busy while an error left by a failed turn frees it. A deferred turn start an older server left on such a thread runs at the next startup, through the startup release loop.",
"keep": "deferredTurnStarts.ts is ours whole, including the ended-session rule in sessionIsFree. In ProviderRuntimeIngestion.ts the runtime.error session-set keeps activeTurnId: eventTurnId ?? activeTurnId; everything else in that file takes upstream.",
"files": [
"apps/server/src/orchestration/deferredTurnStarts.ts",
"apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts"
],
"test": "apps/server/integration/turnStartWhenBusy.integration.test.ts",
"testName": "a turn start that asks to queue runs at once on a thread whose session stopped|a turn start that asks to queue runs at once after a failed turn|a turn start that asks to queue waits for a turn that raised a runtime error without a turn id",
"patchesUpstream": true
},
{
"name": "fm-turn-start-when-busy-ended-session-restart-test",
"description": "The startup test for fm-turn-start-when-busy-ended-session: a deferred turn start left on a stopped session before a restart runs after it. A testName narrows a single test file, and this test lives in another file, so it has its own entry.",
"keep": "The test named in testName survives in orphanedProviderSessionStartup.integration.test.ts. Everything else in that file takes upstream.",
"files": ["apps/server/integration/orphanedProviderSessionStartup.integration.test.ts"],
"test": "apps/server/integration/orphanedProviderSessionStartup.integration.test.ts",
"testName": "starts a turn start deferred on a stopped session after a restart",
"patchesUpstream": true
},
{
"name": "claude-option-change-keeps-background-work",
"description": "A Claude model or option change, such as the context window, no longer restarts a session that has live background work. A restart ends every background shell and agent the Claude process runs. The reactor keeps that session, and the adapter applies the change to it with setModel, applyFlagSettings and setMaxThinkingTokens. With no background work the change still restarts, as upstream does.",
"keep": "The backgroundLiveness condition on shouldRestartForModelSelectionChange survives in ProviderCommandReactor.ts. In ClaudeAdapter.ts these survive: ClaudeFlagSettings and its Query import, ClaudeSelectionSettings, flagOrCleared, resolveClaudeSelectionSettings, launchThinkingDisplay, applySelectionSettings, the selectionSettings context field in place of currentEffort (and the subagent effort that reads it), the applyFlagSettings member and the thinkingDisplay parameter of setMaxThinkingTokens in ClaudeQueryRuntime, and their use in startSession and sendTurn. In ProviderCommandReactor.test.ts these survive: the two tests named in testName, the backgroundLiveness harness field, ThreadBackgroundLivenessService in the runtime type, and Layer.provideMerge(ThreadBackgroundLiveness.layer) in projectionSnapshotLayer. Everything else in those files takes upstream.",
"files": [
"apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
"apps/server/src/provider/Layers/ClaudeAdapter.ts",
"apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts"
],
"test": "apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts",
"testName": "keeps a claude session with live background work when only the context window changes|still restarts a session with live background work when the instance changes",
"patchesUpstream": true
},
{
"name": "claude-option-change-keeps-background-work-adapter-tests",
"description": "The Claude adapter tests for claude-option-change-keeps-background-work: an option change reaches the running query without a new one. The manifest takes one test file per entry, so these tests have their own entry.",
"keep": "The two tests named in testName and the applyFlagSettingsCalls field and applyFlagSettings member of FakeClaudeQuery survive in ClaudeAdapter.test.ts. Everything else in that file takes upstream.",
"files": ["apps/server/src/provider/Layers/ClaudeAdapter.test.ts"],
"test": "apps/server/src/provider/Layers/ClaudeAdapter.test.ts",
"testName": "applies option changes to the running session without a new query|turns thinking off and on in the running session",
"patchesUpstream": true
},
{
"name": "live-background-work-restart-warning",
"description": "Picking a model on another provider instance while the thread has live background work shows a warning toast: the switch restarts the session on the next message and the background work stops. Web and desktop only; the mobile picker cannot switch instance in a started thread.",
"keep": "getLiveBackgroundWorkRestartWarning and its OrchestrationThreadShell import survive in ChatView.logic.ts, its describe block and import survive in ChatView.logic.test.ts, and its import, its toast in onProviderModelSelect and the activeThreadShell?.backgroundLiveness dependency of that callback survive in ChatView.tsx. Everything else in those files takes upstream.",
"files": [
"apps/web/src/components/ChatView.logic.ts",
"apps/web/src/components/ChatView.tsx",
"apps/web/src/components/ChatView.logic.test.ts"
],
"test": "apps/web/src/components/ChatView.logic.test.ts",
"testName": "getLiveBackgroundWorkRestartWarning",
"patchesUpstream": true
},
{
"name": "stopped-background-command-rows",
"description": "A resumed Claude session reports the previous process's unfinished background shells and monitors as stopped tasks with no task type. Ingestion recovers the type and owning agent from the task's saved start row, so they are no longer stamped as subagents. Web and mobile label a stopped background command with its description and fold several that stopped together into one row. backgroundCommands.ts is the fork's own module and upstream has no file at that path.",
"keep": "The taskType and agentId recovery from the saved task row (findTaskClassInActivities and its call in the task.completed branch) survives in ProviderRuntimeIngestion.ts, and its test survives in ProviderRuntimeIngestion.test.ts. Everything else in those files takes upstream.",
"files": [
"apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
"apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts"
],
"test": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts",
"testName": "classifies a resumed session",
"patchesUpstream": true
},
{
"name": "stopped-background-command-rows-web",
"description": "The web half of stopped-background-command-rows: the row label and the fold of adjacent stopped background commands.",
"keep": "backgroundCommands.ts is ours whole, and so is its ./work-log/background-commands export in packages/client-runtime/package.json. In session-logic.ts the background-commands import, the stoppedBackgroundCommands field, its label in toDerivedWorkLogEntry and its fold in collapseDerivedWorkLogEntries survive, and the \"stopped background commands\" describe block survives in session-logic.test.ts. Everything else in those files takes upstream.",
"files": [
"packages/client-runtime/src/work-log/backgroundCommands.ts",
"packages/client-runtime/package.json",
"apps/web/src/session-logic.ts",
"apps/web/src/session-logic.test.ts"
],
"test": "apps/web/src/session-logic.test.ts",
"testName": "stopped background commands",
"patchesUpstream": true
},
{
"name": "stopped-background-command-rows-mobile",
"description": "The mobile half of stopped-background-command-rows, on the same shared module as web.",
"keep": "In threadActivity.ts the background-commands import, the stoppedBackgroundCommands field, its label in toDerivedWorkLogEntry and its fold in collapseDerivedWorkLogEntries survive, and the \"stopped background commands\" describe block survives in threadActivity.test.ts. Everything else in those files takes upstream.",
"files": [
"apps/mobile/src/lib/threadActivity.ts",
"apps/mobile/src/lib/threadActivity.test.ts"
],
"test": "apps/mobile/src/lib/threadActivity.test.ts",
"testName": "stopped background commands",
"patchesUpstream": true
},
{
"name": "fork-app-icon",
"description": "The fork's app icon: an orange T3 tile with a navy corner badge carrying the badge label from forkBuild.ts. forkAppIcon.ts holds its geometry once; the sidebar header renders it as SVG and scripts/generate-fork-icons.ts rasterises it into every icon file the desktop and web builds ship, so the taskbar icon and the header icon match. forkAppIcon.ts, ForkAppIcon.tsx, generate-fork-icons.ts and assets/fork/ are the fork's own and upstream has none of them, so the tests cannot pass on plain upstream. Issues #59 and #154.",
"keep": "forkAppIcon.ts, ForkAppIcon.tsx, generate-fork-icons.ts and every file in assets/fork/ are ours whole. The ./forkAppIcon export survives in packages/shared/package.json, the fork* icon paths and the fork web brand survive in brand-assets.ts, and SidebarChrome.tsx still shows ForkAppIcon in the sidebar header. Everything else in those three files takes upstream. After any merge, run node scripts/generate-fork-icons.ts; the generator test fails if the committed icons drift from it.",
"files": [
"packages/shared/src/forkAppIcon.ts",
"packages/shared/src/forkBuild.ts",
"packages/shared/package.json",
"apps/web/src/components/ForkAppIcon.tsx",
"apps/web/src/components/sidebar/SidebarChrome.tsx",
"scripts/generate-fork-icons.ts",
"scripts/lib/brand-assets.ts",
"assets/fork/fork-universal-1024.png",
"assets/fork/fork-macos-1024.png",
"assets/fork/fork-windows.ico",
"assets/fork/fork-web-favicon.ico",
"assets/fork/fork-web-favicon-16x16.png",
"assets/fork/fork-web-favicon-32x32.png",
"assets/fork/fork-web-apple-touch-180.png"
],
"test": ["packages/shared/src/forkAppIcon.test.ts", "scripts/generate-fork-icons.test.ts"],
"patchesUpstream": true
},
{
"name": "fm-fleet-wake-turn-start",
"description": "A turn start can be marked with fleetWake: true, so First Mate's wake prompt never shows in a thread as if the user typed it. The turn runs as an unmarked one. The decider copies the mark onto the thread.message-sent event, a deferred turn start keeps it while it waits, and fork migration 10 stores it in the fleet_wake column of projection_thread_messages, so it survives a reload and a restart. Web, desktop and mobile show the message as one muted Fleet notice line that expands to the prompt, and the web timeline minimap skips it. A wake is not the user's own message: it does not set a thread's latestUserMessageAt, so it does not move the thread up the sidebar or the command palette, and web does not take it as the server echoing the user's send. The decider's queued turn start guard still counts it, since a wake is real pending work. The server advertises turnStartFleetWake in its environment capabilities.",
"keep": "fleetWakeTurnStart.test.ts, fleetWake.ts and fleetWake.test.ts in client-runtime, FleetNoticeTimelineRow.tsx, FleetNoticeRow.tsx and FleetNoticeRow.test.tsx in mobile, and fork migration 10 are ours whole, and deferredTurnStarts.ts is ours whole including its fleetWake lines. The fleetWake fields on ThreadTurnStartCommand, the client turn start command, OrchestrationMessage, OrchestrationDeferredTurnStart and ThreadMessageSentPayload survive in orchestration.ts; the turnStartFleetWake capability survives in environment.ts and ServerEnvironment.ts and its assertion in ServerEnvironment.test.ts; the fleetWake spread on the thread.turn.start message-sent payload survives in decider.ts; the fleetWake spread on the message-sent message survives in projector.ts and threadReducer.ts; the fleetWake carry on the message upsert and the fleetWake skip in the latestUserMessageAt fold survive in ProjectionPipeline.ts; the fleetWake field survives in Services/ProjectionThreadMessages.ts; the fleet_wake column writes and reads, the fleetWake row mapping and the fleet_wake = 0 filter on the latest user message time survive in Layers/ProjectionThreadMessages.ts, and the column reads and row mapping in ProjectionSnapshotQuery.ts; the migration 10 entry survives in ForkMigrations.ts and ForkMigrations.test.ts; the ./state/fleet-wake export survives in client-runtime package.json; the findLatestUserSentMessage call survives in ChatView.tsx and in mobile use-thread-selection.ts; the fleetWake branch to FleetNoticeTimelineRow survives in MessagesTimeline.tsx; the fleetWake branch to FleetNoticeRow survives in mobile ThreadFeed.tsx; the fleetWake skip survives in timelineMinimapItems.ts; the fleetWake tests survive in orchestration.test.ts, threadReducer.test.ts, Layers/ProjectionThreadMessages.test.ts and MessagesTimeline.test.tsx; the Fleet wake row survives in docs/internals/glossary.md; and the Fleet notice paragraph survives in docs/user/thread-sidebar.md. Everything else in those files takes upstream.",
"files": [
"packages/contracts/src/orchestration.ts",
"packages/contracts/src/environment.ts",
"packages/client-runtime/src/state/threadReducer.ts",
"apps/server/src/environment/ServerEnvironment.ts",
"apps/server/src/orchestration/decider.ts",
"apps/server/src/orchestration/deferredTurnStarts.ts",
"apps/server/src/orchestration/projector.ts",
"apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
"apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts",
"apps/server/src/persistence/Services/ProjectionThreadMessages.ts",
"apps/server/src/persistence/Layers/ProjectionThreadMessages.ts",
"apps/server/src/persistence/ForkMigrations.ts",
"apps/server/src/persistence/ForkMigrations/010_ProjectionThreadMessagesFleetWake.ts",
"apps/web/src/components/chat/FleetNoticeTimelineRow.tsx",
"apps/web/src/components/chat/MessagesTimeline.tsx",
"apps/web/src/components/chat/timelineMinimapItems.ts",
"docs/internals/glossary.md",
"docs/user/thread-sidebar.md",
"packages/client-runtime/src/state/fleetWake.ts",
"packages/client-runtime/package.json",
"apps/web/src/components/ChatView.tsx",
"apps/mobile/src/features/threads/FleetNoticeRow.tsx",
"apps/mobile/src/features/threads/ThreadFeed.tsx",
"apps/mobile/src/state/use-thread-selection.ts"
],
"test": [
"apps/server/src/orchestration/fleetWakeTurnStart.test.ts",
"packages/contracts/src/orchestration.test.ts",
"packages/client-runtime/src/state/threadReducer.test.ts",
"apps/server/src/environment/ServerEnvironment.test.ts",
"apps/server/src/persistence/ForkMigrations.test.ts",
"packages/client-runtime/src/state/fleetWake.test.ts",
"apps/server/src/persistence/Layers/ProjectionThreadMessages.test.ts",
"apps/mobile/src/features/threads/FleetNoticeRow.test.tsx"
],
"patchesUpstream": true
},
{
"name": "fm-fleet-wake-turn-start-timeline-tests",
"description": "The thread view test for fm-fleet-wake-turn-start: a typed message still shows as the user's, a marked message shows as one Fleet notice line, and clicking the line shows and hides its prompt. A testName narrows a single test file, so this test has its own entry.",
"keep": "The test named in testName survives in MessagesTimeline.test.tsx. Everything else in that file takes upstream.",
"files": ["apps/web/src/components/chat/MessagesTimeline.test.tsx"],
"test": "apps/web/src/components/chat/MessagesTimeline.test.tsx",
"testName": "folds a fleet wake into a notice that expands to its prompt",
"patchesUpstream": true
},
{
"name": "claude-turn-ends-on-its-own-result",
"description": "On resume after a Claude process died with background tasks running, Claude Code runs a queued orphaned-task notice as its own turn before the prompt. A requested turn now ends only on a result that echoes the uuid of a message sent into it: its prompt or any steer. Every steer is sent with its own uuid.",
"keep": "In ClaudeAdapter.ts these survive: resultAnswersTurn and its early return in handleResultMessage, the sentMessageUuids field of ClaudeTurnState, and the uuid sendTurn gives every message it queues. In ClaudeAdapter.test.ts the test named in testName survives. Everything else in those files takes upstream.",
"files": [
"apps/server/src/provider/Layers/ClaudeAdapter.ts",
"apps/server/src/provider/Layers/ClaudeAdapter.test.ts"
],
"test": "apps/server/src/provider/Layers/ClaudeAdapter.test.ts",
"testName": "ends a resumed turn on its own prompt's result, not a queued task notice's",
"patchesUpstream": true
},
{
"name": "provider-intake-backlog",
"description": "Runtime ingestion records each provider event per thread in ProviderIntakeLag as it is queued and applied, and forgets a thread when its session ends or it is deleted. The HTTP shell snapshot and fleet_list_threads report the backlog. Shell subscriptions that ask for it receive provider-intake items naming the threads more than 5 seconds behind. client-runtime keeps the latest one on the shell snapshot, never in the cache, and the web sidebar labels such a row Catching up. ProviderIntakeLag.ts is the fork's own module and upstream has no file at that path.",
"keep": "ProviderIntakeLag.ts and ProviderIntakeLag.test.ts are ours whole. These survive: the recordQueued, recordApplied and forgetThread calls in ProviderRuntimeIngestion.ts; ProviderIntakeLag.layer in runtimeLayer.ts; the providerIntake field in the shellSnapshot handler of http.ts; the shellProviderIntake flag and the behindBacklogChanges merge in the subscribeShell handler of ws.ts; ProviderIntakeBacklog, the optional providerIntake field of OrchestrationShellSnapshot, the provider-intake item of OrchestrationShellStreamItem and requestProviderIntake in orchestration.ts; shellProviderIntake in server.ts; the providerIntake field in the fleet tools.ts and handlers.ts; latestIntake, withIntake, intakeRequest and the persist destructuring in client-runtime shell.ts; threadIntakeBehindSinceAtom in threadShell.ts; useThreadIntakeBehindSince in web entities.ts and the catchingUp status in Sidebar.tsx; ProviderIntakeLag.layer in server.test.ts, McpHttpServer.test.ts and OrchestrationEngineHarness.integration.ts; and the tests that exercise them. Everything else in those files takes upstream.",
"files": [
"apps/server/src/orchestration/ProviderIntakeLag.ts",
"apps/server/src/orchestration/ProviderIntakeLag.test.ts",
"apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
"apps/server/src/orchestration/runtimeLayer.ts",
"apps/server/src/orchestration/http.ts",
"apps/server/src/ws.ts",
"packages/contracts/src/orchestration.ts",
"packages/contracts/src/server.ts",
"apps/server/src/mcp/toolkits/fleet/tools.ts",
"apps/server/src/mcp/toolkits/fleet/handlers.ts",
"apps/server/src/mcp/toolkits/fleet/handlers.test.ts",
"packages/client-runtime/src/state/shell.ts",
"packages/client-runtime/src/state/shell-sync.test.ts",
"packages/client-runtime/src/state/threadShell.ts",
"packages/client-runtime/src/state/entities.test.ts",
"apps/web/src/state/entities.ts",
"apps/web/src/components/Sidebar.tsx",
"apps/server/src/server.test.ts",
"apps/server/integration/OrchestrationEngineHarness.integration.ts",
"apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts",
"apps/server/src/mcp/McpHttpServer.test.ts"
],
"test": "apps/server/src/orchestration/ProviderIntakeLag.test.ts",
"patchesUpstream": true
},
{
"name": "reaper-spares-busy-sessions",
"description": "The provider session reaper never stops a session whose projection shows it starting or running, whose provider events are still queued, or whose last provider event is recent. It stops through ProviderService.stopIdleSession, which checks the adapter's live session under the same per-thread lock sendTurn holds, and refuses a session that is running, connecting, mid-turn or running background tasks. The Claude adapter reports its live background task count on its session.",
"keep": "In ProviderSessionReaper.ts the intake backlog check, the last provider event in lastActivityMs, the starting and running status check, the stopIdleSession call and its logs survive. In ProviderService.ts (Layers) withThreadLock, its use in sendTurn and stopIdleSession survive; in ProviderService.ts (Services) stopIdleSession and providerSessionBusyReason survive. backgroundTaskCount survives in contracts provider.ts and in ClaudeAdapter.ts listSessions. The stopIdleSession stubs in test mocks survive. In ProviderSessionReaper.test.ts the liveSessions option, the stopIdleSession mock, ProviderIntakeLag.layer and the describe block named in testName survive. Everything else in those files takes upstream.",
"files": [
"apps/server/src/provider/Layers/ProviderSessionReaper.ts",
"apps/server/src/provider/Layers/ProviderSessionReaper.test.ts",
"apps/server/src/provider/Layers/ProviderService.ts",
"apps/server/src/provider/Services/ProviderService.ts",
"apps/server/src/provider/Layers/ProviderService.test.ts",
"packages/contracts/src/provider.ts",
"apps/server/src/provider/Layers/ClaudeAdapter.ts"
],
"test": "apps/server/src/provider/Layers/ProviderSessionReaper.test.ts",
"testName": "never stops a session whose view is behind its provider",
"patchesUpstream": true
},
{
"name": "stopped-turn-settles-interrupted",
"description": "A turn.completed whose state is interrupted or cancelled, such as a session stop, sets the session interrupted, so the turn settles interrupted instead of completed, as turn.aborted already did.",
"keep": "In ProviderRuntimeIngestion.ts the interrupted and cancelled branch of the turn.completed session status survives, and in ProviderRuntimeIngestion.test.ts the test named in testName survives. Everything else in those files takes upstream.",
"files": [
"apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
"apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts"
],
"test": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts",
"testName": "records a turn the provider ended as",
"patchesUpstream": true
},
{
"name": "session-process-job",
"description": "On Windows, every process a provider session starts, at any depth, ends when the session stops or the server exits. Each session's provider process gets its own job object with kill-on-close and no breakaway, and processes it started before joining the job are moved in right after. If the job binding does not work, the server logs an error and reports a processes.session-jobs-unavailable config issue that Settings > Diagnostics shows as a warning on web and desktop, and packaged builds are checked for it.",
"keep": "sessionProcessJob.ts and its test fixture are ours whole; take upstream for the rest of the other listed files, then re-apply on top: the installSessionProcessJobs() call in bin.ts, the ...sessionProcessJobEnv spread in each session spawn's environment, the ffi-rs dependency in apps/server/package.json, ffi-rs in the server external roots expected by cli-external-packages.test.ts, the sessionProcessJobsReportLayer in server.ts, sessionProcessJobsIssues() in both issue lists in ws.ts, the processes.session-jobs-unavailable issue kind in packages/contracts/src/server.ts, the session jobs warning at the top of DiagnosticsSettings.tsx, the ffi-rs native-load probe in build-desktop-artifact.ts, and the session process jobs check in smoke-cli-archive.ts.",
"files": [
"apps/server/src/process/sessionProcessJob.ts",
"apps/server/src/provider/testFixtures/sessionProcessTree.mjs",
"apps/server/src/bin.ts",
"apps/server/src/server.ts",
"apps/server/src/ws.ts",
"apps/server/src/provider/Layers/ClaudeAdapter.ts",
"apps/server/src/provider/Layers/CodexSessionRuntime.ts",
"apps/server/src/provider/acp/AcpSessionRuntime.ts",
"apps/server/src/provider/opencodeRuntime.ts",
"apps/server/package.json",
"packages/contracts/src/server.ts",
"apps/web/src/components/settings/DiagnosticsSettings.tsx",
"scripts/build-desktop-artifact.ts",
"scripts/smoke-cli-archive.ts",
"scripts/lib/cli-external-packages.test.ts"
],
"test": "apps/server/src/process/sessionProcessJob.test.ts",
"patchesUpstream": true
},
{
"name": "claude-plugin-skills",
"description": "The Claude skill picker also lists the skills of Claude Code plugins that are installed and enabled, named plugin:skill as the CLI names them, and a pick goes out as /plugin:skill. Web and mobile label these rows Plugin, and a plugin whose one skill repeats its name is shown once.",
"keep": "ClaudePluginSkills.ts and its test are ours whole. In ClaudeSkills.ts these survive: the resolveClaudePluginSkillRoots import and call, the plugin scope, the plugin roots and their namespace in the roots list, the plugin:skill name built from the namespace, and the skillOverrides skip for a namespaced skill. In providerSkills.ts the plugin source kind and the repeated-name rule in formatProviderSkillDisplayName survive, with their two tests in providerSkills.test.ts. The plugin entries in the source maps of ComposerCommandMenu.tsx and ComposerCommandPopover.tsx survive. The plugin paragraph under Skills in providers-claude.md survives. Everything else in those files takes upstream.",
"files": [
"apps/server/src/provider/Drivers/ClaudePluginSkills.ts",
"apps/server/src/provider/Drivers/ClaudeSkills.ts",
"packages/client-runtime/src/providerSkills.ts",
"apps/web/src/components/chat/ComposerCommandMenu.tsx",
"apps/mobile/src/features/threads/ComposerCommandPopover.tsx",
"docs/user/providers-claude.md"
],
"test": [
"apps/server/src/provider/Drivers/ClaudePluginSkills.test.ts",
"packages/client-runtime/src/providerSkills.test.ts"
],
"patchesUpstream": true
},
{
"name": "t3-connect-unlink-this-pc",
"description": "Settings > Connections shows an Unlink this PC row whenever the environment holds a T3 Connect link, and when the link state cannot be read. It clears the link stored on this PC with the local unlink call, needs no relay token and no sign-in to the account that made the link, and still needs the relay:write scope. The local unlink always runs first; the relay revoke follows on its own with the signed-in account's token and never holds the unlink up. Upstream only unlinks when the last switch that shows ON is turned OFF, and switching T3 Connect off while publishing is on needs a relink that this PC refuses for another account, so that switch stayed ON and the link stayed. Here, for the two Settings switches only, a T3 Connect switch-off refused for the typed different-account reason is carried into the request that directly follows it, so switching publishing off next unlinks, as long as the account, the environment and the link state are unchanged. Onboarding keeps upstream's reconcileCloudState and never unlinks. The different-account conflict carries a typed reason on the wire, the error names the row by that reason, and the row says so when the stored link belongs to another account than the one signed in. After an unlink the user is told when the account that made the link still lists this PC.",
"keep": "forkUnlinkThisPc.ts, its test, forkRevokeRelayLink.ts and ForkUnlinkThisPcRow.tsx are ours whole. In useCloudLinkController.ts these survive: the useForkLinkFailures call and its describeFailure call around the failure message, the useForkUnlinkThisPc call after reconcileCloudState, and linkedAccountDiffers, reconcileSettingsSwitches, unlinkOffer and unlinkThisPc in the returned object. reconcileCloudState itself is returned as upstream wrote it. In ConnectionsSettings.tsx these survive: the ForkUnlinkThisPcRow import, the row rendered after the Publish agent activity row in ConfiguredCloudLinkRow, the isUnlinking state that feeds isBusy, and reconcileSettingsSwitches taken from the controller in place of reconcileCloudState. In environmentHttp.ts these survive: EnvironmentConflictReason, its type, and the optional reason string on EnvironmentHttpConflictError. In apps/server/src/cloud/http.ts the reason on the conflict that validateLinkedCloudUser returns survives, with its type import, and in server.test.ts the assertion on it. The Unlink this PC paragraph under Manage or revoke access in remote-access.md survives. Everything else in those files takes upstream.",
"files": [
"apps/web/src/cloud/forkUnlinkThisPc.ts",
"apps/web/src/cloud/forkRevokeRelayLink.ts",
"apps/web/src/components/settings/ForkUnlinkThisPcRow.tsx",
"apps/web/src/cloud/useCloudLinkController.ts",
"apps/web/src/components/settings/ConnectionsSettings.tsx",
"packages/contracts/src/environmentHttp.ts",
"apps/server/src/cloud/http.ts",
"apps/server/src/server.test.ts",
"docs/user/remote-access.md"
],
"test": "apps/web/src/cloud/forkUnlinkThisPc.test.tsx",
"patchesUpstream": true
},
{
"name": "gh-telemetry-off",
"description": "Every gh the server starts runs with GH_TELEMETRY=0. gh 2.92 can start a detached gh send-telemetry child; on Windows that child has no console, so the tzutil it runs opened a visible console window. The user's own gh configuration is left alone.",
"keep": "The GH_TELEMETRY=0 entry that runUnbounded adds to the environment of every gh in VcsProcess.ts survives, with its comment; take upstream for the rest of the file.",
"files": ["apps/server/src/vcs/VcsProcess.ts"],
"test": "apps/server/src/vcs/VcsProcess.test.ts",
"testName": "turns off GitHub CLI telemetry for every gh it starts, and only for gh",
"patchesUpstream": true
},
{
"name": "effect-taskkill-after-exit",
"description": "On Windows, Effect's child process spawner no longer runs taskkill against a pid whose process has already exited. Before, every child that exited non-zero started two taskkill runs on its dead pid, each with its own console host, and the pid could already belong to an unrelated process. The patch backports the guard Effect 4.0.4 ships to 4.0.0-rc.115.",
"keep": "The patch file and its patchedDependencies line in pnpm-workspace.yaml are ours whole while the fork is on @effect/platform-node-shared 4.0.0-rc.115; when upstream moves the fork to 4.0.4 or later, which carries the same guard, take upstream and drop both.",
"files": ["patches/@effect__platform-node-shared@4.0.0-rc.115.patch", "pnpm-workspace.yaml"],
"test": "apps/server/src/process/taskkillAfterExit.test.ts",
"patchesUpstream": true
}
]
}