@chainingintention/pi-web-cn 1.202608.8 → 1.202608.10

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 (199) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +123 -72
  3. package/dist/cli.js.map +1 -1
  4. package/dist/client/assets/{CodeViewer-CWKEeX0r.js → CodeViewer-DCl56K0Z.js} +2 -2
  5. package/dist/client/assets/{TerminalPanel-BmA7Ayzk.js → TerminalPanel-DCvoEjUF.js} +6 -6
  6. package/dist/client/assets/{index-D6j67Izj.js → index-CMvms5cF.js} +534 -512
  7. package/dist/client/index.html +1 -1
  8. package/dist/config.js +39 -18
  9. package/dist/config.js.map +1 -1
  10. package/dist/nativeServices/serviceAction.js +128 -0
  11. package/dist/nativeServices/serviceAction.js.map +1 -0
  12. package/dist/pi-web-plugins/git/browser/git-contract.js +108 -0
  13. package/dist/pi-web-plugins/git/browser/git-panel.js +609 -0
  14. package/dist/pi-web-plugins/git/browser/gitFileList.js +43 -0
  15. package/dist/pi-web-plugins/git/browser/gitFileShared.js +16 -0
  16. package/dist/pi-web-plugins/git/browser/gitFileTree.js +81 -0
  17. package/dist/pi-web-plugins/git/browser/gitFileViewPreference.js +35 -0
  18. package/dist/pi-web-plugins/git/browser/gitRoute.js +42 -0
  19. package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +10 -0
  20. package/dist/pi-web-plugins/git/browser/unifiedDiff.js +301 -0
  21. package/dist/pi-web-plugins/git/git-backend.js +433 -0
  22. package/dist/pi-web-plugins/git/package.json +15 -0
  23. package/dist/pi-web-plugins/git/server-plugin.js +176 -0
  24. package/dist/pi-web-plugins/info/infoInternals.js +1 -1
  25. package/dist/pi-web-plugins/info/pi-web-plugin.js +2 -2
  26. package/dist/pi-web-plugins/relays/pi-web-plugin.js +1 -1
  27. package/dist/pi-web-plugins/relays/relayDiscovery.js +128 -23
  28. package/dist/pi-web-plugins/relays/relaysPanelElement.js +138 -16
  29. package/dist/pi-web-plugins/updates/pi-web-plugin.js +1 -1
  30. package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +1 -1
  31. package/dist/piWebVersionReport.js +63 -4
  32. package/dist/piWebVersionReport.js.map +1 -1
  33. package/dist/plugin-api.d.ts +40 -18
  34. package/dist/pluginRecoveryCli.js +172 -0
  35. package/dist/pluginRecoveryCli.js.map +1 -0
  36. package/dist/server/activity/workspaceActivityService.js +7 -1
  37. package/dist/server/activity/workspaceActivityService.js.map +1 -1
  38. package/dist/server/app.js +49 -23
  39. package/dist/server/app.js.map +1 -1
  40. package/dist/server/audit/managementAuditStore.js +4 -2
  41. package/dist/server/audit/managementAuditStore.js.map +1 -1
  42. package/dist/server/configRoutes.js +4 -5
  43. package/dist/server/configRoutes.js.map +1 -1
  44. package/dist/server/machines/machineClient.js +23 -4
  45. package/dist/server/machines/machineClient.js.map +1 -1
  46. package/dist/server/machines/machineProxyRoutes.js +162 -8
  47. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  48. package/dist/server/managementEmbed.js +6 -0
  49. package/dist/server/managementEmbed.js.map +1 -1
  50. package/dist/server/piWebPluginCatalog.js +441 -0
  51. package/dist/server/piWebPluginCatalog.js.map +1 -0
  52. package/dist/server/piWebPluginLifecycle.js +162 -0
  53. package/dist/server/piWebPluginLifecycle.js.map +1 -0
  54. package/dist/server/piWebPluginService.js +55 -7
  55. package/dist/server/piWebPluginService.js.map +1 -1
  56. package/dist/server/plugins/pluginBackendProxyRoutes.js +80 -0
  57. package/dist/server/plugins/pluginBackendProxyRoutes.js.map +1 -0
  58. package/dist/server/plugins/serverPluginExec.js +184 -0
  59. package/dist/server/plugins/serverPluginExec.js.map +1 -0
  60. package/dist/server/plugins/serverPluginRuntime.js +480 -0
  61. package/dist/server/plugins/serverPluginRuntime.js.map +1 -0
  62. package/dist/server/realtime/sessionEventHub.js +13 -0
  63. package/dist/server/realtime/sessionEventHub.js.map +1 -1
  64. package/dist/server/realtime/sessionEventScope.js +8 -1
  65. package/dist/server/realtime/sessionEventScope.js.map +1 -1
  66. package/dist/server/requestCancellation.js +28 -0
  67. package/dist/server/requestCancellation.js.map +1 -0
  68. package/dist/server/sessiond/agentProcessEnvironment.js +61 -0
  69. package/dist/server/sessiond/agentProcessEnvironment.js.map +1 -0
  70. package/dist/server/sessiond/managementProjectResolver.js +16 -0
  71. package/dist/server/sessiond/managementProjectResolver.js.map +1 -0
  72. package/dist/server/sessiond/pluginBackendRoutes.js +78 -0
  73. package/dist/server/sessiond/pluginBackendRoutes.js.map +1 -0
  74. package/dist/server/sessiond/sessionProxyRoutes.js +1 -0
  75. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  76. package/dist/server/sessiond/sessionServiceDependencies.js +0 -1
  77. package/dist/server/sessiond/sessionServiceDependencies.js.map +1 -1
  78. package/dist/server/sessiond/sessiondStateOwnership.js +139 -0
  79. package/dist/server/sessiond/sessiondStateOwnership.js.map +1 -0
  80. package/dist/server/sessiond/workspaceCatalogRoutes.js +38 -0
  81. package/dist/server/sessiond/workspaceCatalogRoutes.js.map +1 -0
  82. package/dist/server/sessiond/workspaceRemovalRoutes.js +56 -0
  83. package/dist/server/sessiond/workspaceRemovalRoutes.js.map +1 -0
  84. package/dist/server/sessiond.js +98 -11
  85. package/dist/server/sessiond.js.map +1 -1
  86. package/dist/server/sessions/authService.js +15 -51
  87. package/dist/server/sessions/authService.js.map +1 -1
  88. package/dist/server/sessions/dockerEnvironmentFacts.js +181 -0
  89. package/dist/server/sessions/dockerEnvironmentFacts.js.map +1 -0
  90. package/dist/server/sessions/managementAgentTools.js +12 -4
  91. package/dist/server/sessions/managementAgentTools.js.map +1 -1
  92. package/dist/server/sessions/managementSandbox.js +5 -5
  93. package/dist/server/sessions/managementSandbox.js.map +1 -1
  94. package/dist/server/sessions/piSessionManagerGateway.js +129 -2
  95. package/dist/server/sessions/piSessionManagerGateway.js.map +1 -1
  96. package/dist/server/sessions/piSessionService.js +268 -119
  97. package/dist/server/sessions/piSessionService.js.map +1 -1
  98. package/dist/server/sessions/sessionCommandService.js +15 -1
  99. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  100. package/dist/server/sessions/sessionEnvironmentFacts.js +48 -0
  101. package/dist/server/sessions/sessionEnvironmentFacts.js.map +1 -0
  102. package/dist/server/sessions/sessionFileFormat.js +27 -0
  103. package/dist/server/sessions/sessionFileFormat.js.map +1 -0
  104. package/dist/server/sessions/sessionFileHeader.js +82 -23
  105. package/dist/server/sessions/sessionFileHeader.js.map +1 -1
  106. package/dist/server/sessions/sessionRoutes.js +16 -2
  107. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  108. package/dist/server/sessions/sessionSummaryScanner.js +491 -0
  109. package/dist/server/sessions/sessionSummaryScanner.js.map +1 -0
  110. package/dist/server/sessions/spawnSubsessionTool.js +4 -8
  111. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -1
  112. package/dist/server/sessions/spawnTargetResolver.js +2 -2
  113. package/dist/server/sessions/spawnTargetResolver.js.map +1 -1
  114. package/dist/server/status/machineStatusRoutes.js +10 -0
  115. package/dist/server/status/machineStatusRoutes.js.map +1 -0
  116. package/dist/server/status/machineStatusService.js +115 -0
  117. package/dist/server/status/machineStatusService.js.map +1 -0
  118. package/dist/server/status/workspaceAttribution.js +71 -0
  119. package/dist/server/status/workspaceAttribution.js.map +1 -0
  120. package/dist/server/terminalProxyRoutes.js.map +1 -1
  121. package/dist/server/workbench/skillSync.js +9 -1
  122. package/dist/server/workbench/skillSync.js.map +1 -1
  123. package/dist/server/workspaceExplorerRoutes.js +12 -25
  124. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  125. package/dist/server/workspaces/effectivePathAccess.js +3 -2
  126. package/dist/server/workspaces/effectivePathAccess.js.map +1 -1
  127. package/dist/server/workspaces/fileContentService.js +17 -9
  128. package/dist/server/workspaces/fileContentService.js.map +1 -1
  129. package/dist/server/workspaces/fileOperationService.js +4 -17
  130. package/dist/server/workspaces/fileOperationService.js.map +1 -1
  131. package/dist/server/workspaces/filePreviewResponseHeaders.js +18 -0
  132. package/dist/server/workspaces/filePreviewResponseHeaders.js.map +1 -0
  133. package/dist/server/workspaces/filePreviewResponsePolicy.js +55 -0
  134. package/dist/server/workspaces/filePreviewResponsePolicy.js.map +1 -0
  135. package/dist/server/workspaces/filePreviewService.js +81 -0
  136. package/dist/server/workspaces/filePreviewService.js.map +1 -0
  137. package/dist/server/workspaces/projectWorkspaceCwds.js +2 -2
  138. package/dist/server/workspaces/projectWorkspaceCwds.js.map +1 -1
  139. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js +416 -0
  140. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js.map +1 -0
  141. package/dist/server/workspaces/workspaceCatalog.js +87 -0
  142. package/dist/server/workspaces/workspaceCatalog.js.map +1 -0
  143. package/dist/server/workspaces/workspaceContext.js +5 -5
  144. package/dist/server/workspaces/workspaceContext.js.map +1 -1
  145. package/dist/server/workspaces/workspaceDeletionRoutes.js +114 -99
  146. package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -1
  147. package/dist/server/workspaces/workspaceProviderRegistry.js +650 -0
  148. package/dist/server/workspaces/workspaceProviderRegistry.js.map +1 -0
  149. package/dist/server/workspaces/workspaceRemovalService.js +258 -0
  150. package/dist/server/workspaces/workspaceRemovalService.js.map +1 -0
  151. package/dist/server/workspaces/workspaceRouteContext.js +2 -1
  152. package/dist/server/workspaces/workspaceRouteContext.js.map +1 -1
  153. package/dist/server/workspaces/workspaceRouteErrors.js +7 -0
  154. package/dist/server/workspaces/workspaceRouteErrors.js.map +1 -0
  155. package/dist/server/workspaces/worktreePreRemoveHook.js +39 -0
  156. package/dist/server/workspaces/worktreePreRemoveHook.js.map +1 -0
  157. package/dist/server-plugin-api.d.ts +115 -0
  158. package/dist/server-plugin-api.js +2 -0
  159. package/dist/server-plugin-api.js.map +1 -0
  160. package/dist/serverPluginRecovery.js +138 -0
  161. package/dist/serverPluginRecovery.js.map +1 -0
  162. package/dist/sessiond/config.js +6 -0
  163. package/dist/sessiond/config.js.map +1 -1
  164. package/dist/sessiond/sessionDaemonClient.js +7 -6
  165. package/dist/sessiond/sessionDaemonClient.js.map +1 -1
  166. package/dist/shared/apiTypes.js +2 -0
  167. package/dist/shared/apiTypes.js.map +1 -1
  168. package/dist/shared/capabilities.js +2 -0
  169. package/dist/shared/capabilities.js.map +1 -1
  170. package/dist/shared/federatedRoutes.js +28 -2
  171. package/dist/shared/federatedRoutes.js.map +1 -1
  172. package/dist/shared/machineStatus.js +60 -0
  173. package/dist/shared/machineStatus.js.map +1 -0
  174. package/dist/shared/pluginApiTypes.d.ts +155 -0
  175. package/dist/shared/pluginBackendProtocol.js +110 -0
  176. package/dist/shared/pluginBackendProtocol.js.map +1 -0
  177. package/dist/shared/pluginIds.js +3 -0
  178. package/dist/shared/pluginIds.js.map +1 -1
  179. package/dist/shared/pluginRecoveryCommands.js +14 -0
  180. package/dist/shared/pluginRecoveryCommands.js.map +1 -0
  181. package/dist/shared/workspaceFiles.js +41 -2
  182. package/dist/shared/workspaceFiles.js.map +1 -1
  183. package/dist/shared/workspaceRemovalProtocol.js +24 -0
  184. package/dist/shared/workspaceRemovalProtocol.js.map +1 -0
  185. package/docs/config.md +12 -5
  186. package/docs/plugins.md +15 -21
  187. package/package.json +27 -8
  188. package/server-plugin-api.d.ts +1 -0
  189. package/skills/README.md +12 -0
  190. package/skills/relay/SKILL.md +115 -0
  191. package/dist/client/assets/UnifiedDiffViewer-2DACwxFY.js +0 -39
  192. package/dist/plugin-api/unstable.d.ts +0 -22
  193. package/dist/server/sessions/parentSessionLocator.js +0 -75
  194. package/dist/server/sessions/parentSessionLocator.js.map +0 -1
  195. package/dist/server/workspaces/imagePreviewService.js +0 -40
  196. package/dist/server/workspaces/imagePreviewService.js.map +0 -1
  197. package/dist/shared/apiTypes.d.ts +0 -1323
  198. package/dist/shared/thinkingLevels.d.ts +0 -29
  199. package/plugin-api/unstable.d.ts +0 -1
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: relay
3
+ description: "How the Relay method works: executing a plan as a chain of independent sessions that each do one slice and hand off to the next via spawn_session. Load this skill only when you already know you are in a relay: a prompt states you are working under the Relay framework (or relay/chain), points you at a relay charter/status/log, or the user invokes this skill directly. Do not load it for generic multi-step plans or ordinary spawn_session use."
4
+ ---
5
+
6
+ # Relay
7
+
8
+ Relay is a way to execute a long or complex plan as a chain of independent sessions. Each session runs **one leg** — a single well-sized slice of the work — then hands the work off to a fresh session that runs the next leg. The chain continues until the goal is reached.
9
+
10
+ There is no coordinator and no referee. Each runner is the coordinator for their own leg: smart enough to do the work, adapt to what they discover, and hand off cleanly. Trust is distributed to every agent, not held by a god-agent above them.
11
+
12
+ Relay works because it does not try to recreate human management structures. The point is fewer boundaries, less hierarchy, and more fluid execution. The thing that makes that safe is **context containment**: every leg starts with a fresh, small context, and the accumulated knowledge lives in compact documents on disk rather than in any one session's memory.
13
+
14
+ ## The hard constraint that shapes everything
15
+
16
+ `spawn_session` is fire-and-forget. When you spawn the next leg, **you do not see its output and you cannot correct it.** The only thing that travels down the chain is what you wrote to disk. A human may be watching in the UI, but they intervene by reading your documents, not by relaying messages between sessions.
17
+
18
+ Two consequences follow, and they govern the whole method:
19
+
20
+ - **Make your work durable before you hand off.** Update the status, append the log, save/commit the artifacts (commit if the relay says to), and only then spawn the next leg. Anything not on disk is lost.
21
+ - **Hand off exactly once, at the end.** Do not spawn early, do not spawn several runners "to parallelize," and never spawn while you still have work in flight. One leg, one handoff.
22
+
23
+ ## The relay packet
24
+
25
+ A relay is carried by a small packet of documents. By default they live in `.pi-web/relays/<name>/` unless the user or the dispatching prompt says otherwise — always follow an explicit location if given.
26
+
27
+ Every relay has these three core files:
28
+
29
+ **Charter** (`charter.md`) — the stable agreement, written when the relay is planned. It must contain, at minimum:
30
+
31
+ - **Relay identity.** The relay name and root path, so runners know exactly which relay they are on.
32
+ - **Goal / finish line.** A concrete, achievable end state. Without this the relay runs forever — this is non-negotiable.
33
+ - **Sizing.** How much is *one leg*? This is project- and plan-specific; the charter defines it (a task, a slice, a time/scope budget — whatever fits). The skill does not decide this for you.
34
+ - **Task selection policy.** How a runner chooses the next task when `status.md` does not name one explicitly.
35
+ - **Handover.** How a runner hands off: what the spawn prompt should say and what the next runner must read. A normal handoff starts with a natural header containing the relay name and next leg number, then points at `charter.md` and `status.md`, not the full log.
36
+ - **Intervention signal.** When and how a runner must stop and get the human, and how that is made visible. The charter must define this; the skill does not define it for you.
37
+ - **Reading discipline.** The files a runner should read to orient, and any files that should not be read defensively.
38
+
39
+ The charter *can* be edited, but it should rarely *need* to be. If it is changing every leg, that is a smell — the design wasn't settled, or the goal is drifting. Treat frequent charter edits as a reason to stop and involve the human.
40
+
41
+ **Status** (`status.md`) — the compact baton/current state. This is the file every runner reads after the charter, and every runner updates before handoff or stop. Keep it short enough that a fresh runner can load it cheaply. It should answer:
42
+
43
+ - **Current position.** Where the relay is now.
44
+ - **Current or next task.** The next leg if known; otherwise enough information to apply the charter's task selection policy.
45
+ - **Leg tracking.** The last completed leg and the next leg to run. Keep this explicit so runners do not have to infer whether “current leg” means the leg just finished or the leg being handed off, and so new PI-WEB sessions can distinguish relay legs from the first line of their prompt without naming instructions.
46
+ - **Relevant context.** Only the files, sections, commands, artifacts, or specific log entries needed for the next leg.
47
+ - **Progress documentation.** Where this runner must write progress: update `status.md`, append `log.md`, update artifacts, commit, etc.
48
+ - **Blockers / intervention state.** Current risks, open decisions, or active reasons to stop.
49
+
50
+ Think of `status.md` as the thing passed from runner to runner. If it grows into a history dump, compress it back into current state plus pointers. If an older relay lacks leg tracking, repair it when you update status; prefer the leg number from the prompt or status, and do not read `log.md` end-to-end just to count prior legs.
51
+
52
+ **Log** (`log.md`) — append-only history. Each leg appends a concise entry recording what it did, decisions made and why, durable artifacts changed, status updates made, and blockers. The log preserves auditability, but it is **not** orientation memory.
53
+
54
+ Do not read `log.md` end-to-end by default. Read targeted log entries only when `status.md` points to them, when the charter requires a specific lookup, or when there is an inconsistency you must resolve before continuing.
55
+
56
+ Optional files such as `plan.md`, `backlog.md`, or artifact notes are fine, but runners should read them only when the charter/status points to the relevant part.
57
+
58
+ ## Context containment rule
59
+
60
+ A runner normally reads:
61
+
62
+ 1. `charter.md`
63
+ 2. `status.md`
64
+ 3. Only the specific files or log entries referenced for the current leg
65
+
66
+ Do not defensively rebuild the relay's full history. Do not read the full log, the full backlog, or a large artifact tree just because they exist. The relay stays scalable because each runner pays only for the context needed now.
67
+
68
+ If `status.md` is insufficient, fix the baton rather than compensating by reading everything. Use targeted inspection to clarify the current state, update `status.md` so the next runner has a clean start, and continue only if the task is still clear. If reconstructing the state would require broad archaeology or judgment about past intent, stop and raise the intervention signal.
69
+
70
+ ## Running one leg
71
+
72
+ This is the loop you run when you are dispatched into a relay.
73
+
74
+ 1. **Orient from the packet.** Read `charter.md` and `status.md`. Confirm the relay name/root, goal, sizing, handoff protocol, last completed leg, next leg to run, intervention signal, and current/next task. If you are not sure you are in a relay, the prompt or `.pi-web/relays/` is your clue — and reading this skill means you are.
75
+ 2. **Choose the leg.** Prefer the explicit current/next task in `status.md`. If none is named, apply the charter's task selection policy. If that still requires context, inspect only the referenced plan/backlog/artifact sections. If the next task is still ambiguous or would materially change direction, stop and involve the human.
76
+ 3. **Re-anchor to the goal.** Does the goal still make sense given the status and what you now see? If reality has diverged from the charter, that is often an intervention moment — don't quietly redefine the task.
77
+ 4. **Run one leg.** Do exactly one well-sized slice, per the charter's sizing. Resist doing "just a bit more" — extra scope bloats context and breaks the containment that makes Relay work.
78
+ 5. **Document progress.** Make all work durable. Update `status.md` with the new current state, last completed leg, next leg to run (if any), next task or task-selection pointer, relevant context for the next runner, and blockers. Append a concise `log.md` entry with what you did, why, decisions made, artifacts changed, and whether you are handing off or stopping.
79
+ 6. **Decide: hand off, or stop.**
80
+ - **Hand off** if there is a clear next leg and you are on track. Use `spawn_session` once, with a prompt whose first line is a natural task header containing the relay name and next leg number (for example, `Relay "<name>" leg <N> begins now.`), followed by the Relay method and pointers to `charter.md` and `status.md` (so this skill loads and they can orient cheaply). Then you are done. Handoff is deliberately fire-and-forget: `spawn_session` starts an independent session you will not see and cannot steer — do not reach for a tracked subsession to keep an eye on it. Letting go is the point. The next runner is trusted to run their own leg, and the relay packet is the only thread between you; if you feel the need to watch downstream work, that usually means the leg wasn't sized or handed off cleanly, or an intervention signal should have fired.
81
+ - **Stop — do not spawn —** if the goal is reached, or you are blocked, or the charter's intervention signal fires. Update `status.md`, append a clear note in `log.md`, and raise the intervention signal so the watching human sees exactly what happened and what they need to decide. A stalled relay that stopped cleanly with a clear blocker is a success; a relay that spawned a confused next runner is a failure.
82
+
83
+ A good handoff prompt is short and explicit. Put the relay identity and leg number at the very beginning so PI-WEB's session title generator sees useful distinguishing context without any naming instruction:
84
+
85
+ ```text
86
+ Relay "<name>" leg <N> begins now.
87
+
88
+ You are the next runner in this Relay method chain.
89
+
90
+ Read:
91
+ - .pi-web/relays/<name>/charter.md
92
+ - .pi-web/relays/<name>/status.md
93
+
94
+ Do not read log.md end-to-end. Use it only for targeted lookup if status.md or charter.md points you there.
95
+
96
+ Run one leg according to the charter. Before handing off, update status.md, append log.md, make work durable, then either spawn the next leg once or stop with a clear intervention note.
97
+ ```
98
+
99
+ ## Planning a relay
100
+
101
+ When the user asks to set up a relay, your job is to produce the relay packet: `charter.md`, `status.md`, and `log.md`. The charter must have the required slots filled: relay identity, goal, sizing, task selection policy, handover, intervention signal, and reading discipline. The initial status must give the first runner a compact baton: current position, leg tracking (usually last completed leg 0 and next leg to run 1 for a new relay), first task or task selection pointer, relevant context, documentation expectations, and known blockers. The log may start empty or with a short seed entry explaining that the relay was created.
102
+
103
+ Draw the required choices out from the user rather than inventing them: ask what the finish line is, how much should be one leg, how runners pick tasks, how runners hand off, what they should read, and when they must stop and get the human. Sizing, task selection, and the intervention signal especially are the user's to decide — propose options if it helps them think, but do not quietly settle them yourself.
104
+
105
+ Do **not** impose what a "good" plan, leg size, or cadence looks like — those are deeply project-, plan-, and human-specific, and getting them wrong by being prescriptive is worse than leaving them to the user. Your value in planning is making sure the relay is *runnable*: the finish line exists, sizing is stated, task selection is stated, handover is stated, reading discipline is stated, and the intervention signal is stated. Once the packet is agreed, you can dispatch the first leg with `spawn_session`.
106
+
107
+ ## Smells to watch for
108
+
109
+ - **No finish line** → infinite relay. Refuse to run a relay without a defined goal.
110
+ - **Goal drift** → each leg quietly restates the task. Re-anchor every leg.
111
+ - **Charter churn** → the charter changes every leg. The design isn't settled; involve the human.
112
+ - **Status bloat** → `status.md` turns into a history dump. Compress it to current state plus targeted pointers.
113
+ - **Defensive reading** → reading the full log/backlog/artifact tree to feel safe. Use the packet and targeted lookups; stop if the baton is not enough.
114
+ - **Eager spawning** → spawning early, spawning several runners, or spawning before work is durable. One leg, one handoff, at the end.
115
+ - **Silent stall** → getting stuck and stopping with no note, or spawning anyway. Always update status, log the blocker, and surface it.
@@ -1,39 +0,0 @@
1
- import{_ as e,a as t,f as n,g as r,m as i,p as a}from"./index-D6j67Izj.js";var o=class{diff(e,t,n={}){let r;typeof n==`function`?(r=n,n={}):`callback`in n&&(r=n.callback);let i=this.castInput(e,n),a=this.castInput(t,n),o=this.removeEmpty(this.tokenize(i,n)),s=this.removeEmpty(this.tokenize(a,n));return this.diffWithOptionsObj(o,s,n,r)}diffWithOptionsObj(e,t,n,r){let i=e=>{if(e=this.postProcess(e,n),r){setTimeout(function(){r(e)},0);return}else return e},a=t.length,o=e.length,s=1,c=a+o;n.maxEditLength!=null&&(c=Math.min(c,n.maxEditLength));let l=n.timeout??1/0,u=Date.now()+l,d=[{oldPos:-1,lastComponent:void 0}],f=this.extractCommon(d[0],t,e,0,n);if(d[0].oldPos+1>=o&&f+1>=a)return i(this.buildValues(d[0].lastComponent,t,e));let p=-1/0,m=1/0,h=()=>{for(let r=Math.max(p,-s);r<=Math.min(m,s);r+=2){let s,c=d[r-1],l=d[r+1];c&&(d[r-1]=void 0);let u=!1;if(l){let e=l.oldPos-r;u=l&&0<=e&&e<a}let h=c&&c.oldPos+1<o;if(!u&&!h){d[r]=void 0;continue}if(s=!h||u&&c.oldPos<l.oldPos?this.addToPath(l,!0,!1,0,n):this.addToPath(c,!1,!0,1,n),f=this.extractCommon(s,t,e,r,n),s.oldPos+1>=o&&f+1>=a)return i(this.buildValues(s.lastComponent,t,e))||!0;d[r]=s,s.oldPos+1>=o&&(m=Math.min(m,r-1)),f+1>=a&&(p=Math.max(p,r+1))}s++};if(r)(function e(){setTimeout(function(){if(s>c||Date.now()>u)return r(void 0);h()||e()},0)})();else for(;s<=c&&Date.now()<=u;){let e=h();if(e)return e}}addToPath(e,t,n,r,i){let a=e.lastComponent;return a&&!i.oneChangePerToken&&a.added===t&&a.removed===n?{oldPos:e.oldPos+r,lastComponent:{count:a.count+1,added:t,removed:n,previousComponent:a.previousComponent}}:{oldPos:e.oldPos+r,lastComponent:{count:1,added:t,removed:n,previousComponent:a}}}extractCommon(e,t,n,r,i){let a=t.length,o=n.length,s=e.oldPos,c=s-r,l=0;for(;c+1<a&&s+1<o&&this.equals(n[s+1],t[c+1],i);)c++,s++,l++,i.oneChangePerToken&&(e.lastComponent={count:1,previousComponent:e.lastComponent,added:!1,removed:!1});return l&&!i.oneChangePerToken&&(e.lastComponent={count:l,previousComponent:e.lastComponent,added:!1,removed:!1}),e.oldPos=s,c}equals(e,t,n){return n.comparator?n.comparator(e,t):e===t||!!n.ignoreCase&&e.toLowerCase()===t.toLowerCase()}removeEmpty(e){let t=[];for(let n=0;n<e.length;n++)e[n]&&t.push(e[n]);return t}castInput(e,t){return e}tokenize(e,t){return Array.from(e)}join(e){return e.join(``)}postProcess(e,t){return e}get useLongestToken(){return!1}buildValues(e,t,n){let r=[],i;for(;e;)r.push(e),i=e.previousComponent,delete e.previousComponent,e=i;r.reverse();let a=r.length,o=0,s=0,c=0;for(;o<a;o++){let e=r[o];if(e.removed)e.value=this.join(n.slice(c,c+e.count)),c+=e.count;else{if(!e.added&&this.useLongestToken){let r=t.slice(s,s+e.count);r=r.map(function(e,t){let r=n[c+t];return r.length>e.length?r:e}),e.value=this.join(r)}else e.value=this.join(t.slice(s,s+e.count));s+=e.count,e.added||(c+=e.count)}}return r}},s=new class extends o{};function c(e,t,n){return s.diff(e,t,n)}function l(e,t){let n;for(n=0;n<e.length&&n<t.length;n++)if(e[n]!=t[n])return e.slice(0,n);return e.slice(0,n)}function u(e,t){let n;if(!e||!t||e[e.length-1]!=t[t.length-1])return``;for(n=0;n<e.length&&n<t.length;n++)if(e[e.length-(n+1)]!=t[t.length-(n+1)])return e.slice(-n);return e.slice(-n)}function d(e,t,n){if(e.slice(0,t.length)!=t)throw Error(`string ${JSON.stringify(e)} doesn't start with prefix ${JSON.stringify(t)}; this is a bug`);return n+e.slice(t.length)}function f(e,t,n){if(!t)return e+n;if(e.slice(-t.length)!=t)throw Error(`string ${JSON.stringify(e)} doesn't end with suffix ${JSON.stringify(t)}; this is a bug`);return e.slice(0,-t.length)+n}function p(e,t){return d(e,t,``)}function m(e,t){return f(e,t,``)}function h(e,t){return t.slice(0,g(e,t))}function g(e,t){let n=0;e.length>t.length&&(n=e.length-t.length);let r=t.length;e.length<t.length&&(r=e.length);let i=Array(r),a=0;i[0]=0;for(let e=1;e<r;e++){for(t[e]==t[a]?i[e]=i[a]:i[e]=a;a>0&&t[e]!=t[a];)a=i[a];t[e]==t[a]&&a++}a=0;for(let r=n;r<e.length;r++){for(;a>0&&e[r]!=t[a];)a=i[a];e[r]==t[a]&&a++}return a}function _(e,t){let n=[];for(let r of Array.from(t.segment(e))){let e=r.segment;n.length&&/\s/.test(n[n.length-1])&&/\s/.test(e)?n[n.length-1]+=e:n.push(e)}return n}function v(e,t){if(t)return b(e,t)[1];let n;for(n=e.length-1;n>=0&&e[n].match(/\s/);n--);return e.substring(n+1)}function y(e,t){if(t)return b(e,t)[0];let n=e.match(/^\s*/);return n?n[0]:``}function b(e,t){if(!t)return[y(e),v(e)];if(t.resolvedOptions().granularity!=`word`)throw Error(`The segmenter passed must have a granularity of "word"`);let n=_(e,t),r=n[0],i=n[n.length-1];return[/\s/.test(r)?r:``,/\s/.test(i)?i:``]}var x=`a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}`,S=RegExp(`[${x}]+|\\s+|[^${x}]`,`ug`);new class extends o{equals(e,t,n){return n.ignoreCase&&(e=e.toLowerCase(),t=t.toLowerCase()),e.trim()===t.trim()}tokenize(e,t={}){let n;if(t.intlSegmenter){let r=t.intlSegmenter;if(r.resolvedOptions().granularity!=`word`)throw Error(`The segmenter passed must have a granularity of "word"`);n=_(e,r)}else n=e.match(S)||[];let r=[],i=null;return n.forEach(e=>{/\s/.test(e)?i==null?r.push(e):r.push(r.pop()+e):i!=null&&/\s/.test(i)?r[r.length-1]==i?r.push(r.pop()+e):r.push(i+e):r.push(e),i=e}),r}join(e){return e.map((e,t)=>t==0?e:e.replace(/^\s+/,``)).join(``)}postProcess(e,t){if(!e||t.oneChangePerToken)return e;let n=null,r=null,i=null;return e.forEach(e=>{e.added?r=e:e.removed?i=e:((r||i)&&C(n,i,r,e,t.intlSegmenter),n=e,r=null,i=null)}),(r||i)&&C(n,i,r,null,t.intlSegmenter),e}};function C(e,t,n,r,i){if(t&&n){let[a,o]=b(t.value,i),[s,c]=b(n.value,i);if(e){let r=l(a,s);e.value=f(e.value,s,r),t.value=p(t.value,r),n.value=p(n.value,r)}if(r){let e=u(o,c);r.value=d(r.value,c,e),t.value=m(t.value,e),n.value=m(n.value,e)}}else if(n){if(e){let e=y(n.value,i);n.value=n.value.substring(e.length)}if(r){let e=y(r.value,i);r.value=r.value.substring(e.length)}}else if(e&&r){let n=y(r.value,i),[a,o]=b(t.value,i),s=l(n,a);t.value=p(t.value,s);let c=u(p(n,s),o);t.value=m(t.value,c),r.value=d(r.value,n,c),e.value=f(e.value,n,n.slice(0,n.length-c.length))}else if(r){let e=y(r.value,i),n=h(v(t.value,i),e);t.value=m(t.value,n)}else if(e){let n=h(v(e.value,i),y(t.value,i));t.value=p(t.value,n)}}new class extends o{tokenize(e){let t=RegExp(`(\\r?\\n)|[${x}]+|[^\\S\\n\\r]+|[^${x}]`,`ug`);return e.match(t)||[]}},new class extends o{constructor(){super(...arguments),this.tokenize=w}equals(e,t,n){return n.ignoreWhitespace?((!n.newlineIsToken||!e.includes(`
2
- `))&&(e=e.trim()),(!n.newlineIsToken||!t.includes(`
3
- `))&&(t=t.trim())):n.ignoreNewlineAtEof&&!n.newlineIsToken&&(e.endsWith(`
4
- `)&&(e=e.slice(0,-1)),t.endsWith(`
5
- `)&&(t=t.slice(0,-1))),super.equals(e,t,n)}};function w(e,t){t.stripTrailingCr&&(e=e.replace(/\r\n/g,`
6
- `));let n=[],r=e.split(/(\n|\r\n)/);r[r.length-1]||r.pop();for(let e=0;e<r.length;e++){let i=r[e];e%2&&!t.newlineIsToken?n[n.length-1]+=i:n.push(i)}return n}function T(e){return e==`.`||e==`!`||e==`?`}new class extends o{tokenize(e){let t=[],n=0;for(let r=0;r<e.length;r++){if(r==e.length-1){t.push(e.slice(n));break}if(T(e[r])&&e[r+1].match(/\s/)){for(t.push(e.slice(n,r+1)),r=n=r+1;e[r+1]?.match(/\s/);)r++;t.push(e.slice(n,r+1)),n=r+1}}return t}},new class extends o{tokenize(e){return e.split(/([{}:;,]|\s+)/)}},new class extends o{constructor(){super(...arguments),this.tokenize=w}get useLongestToken(){return!0}castInput(e,t){let{undefinedReplacement:n,stringifyReplacer:r=(e,t)=>t===void 0?n:t}=t;return typeof e==`string`?e:JSON.stringify(E(e,null,null,r),null,` `)}equals(e,t,n){return super.equals(e.replace(/,([\r\n])/g,`$1`),t.replace(/,([\r\n])/g,`$1`),n)}};function E(e,t,n,r,i){t||=[],n||=[],r&&(e=r(i===void 0?``:i,e));let a;for(a=0;a<t.length;a+=1)if(t[a]===e)return n[a];let o;if(Object.prototype.toString.call(e)===`[object Array]`){for(t.push(e),o=Array(e.length),n.push(o),a=0;a<e.length;a+=1)o[a]=E(e[a],t,n,r,String(a));return t.pop(),n.pop(),o}if(e&&e.toJSON&&(e=e.toJSON()),typeof e==`object`&&e){t.push(e),o={},n.push(o);let i=[],s;for(s in e)Object.prototype.hasOwnProperty.call(e,s)&&i.push(s);for(i.sort(),a=0;a<i.length;a+=1)s=i[a],o[s]=E(e[s],t,n,r,s);t.pop(),n.pop()}else o=e;return o}new class extends o{tokenize(e){return e.slice()}join(e){return e}removeEmpty(e){return e}};var D=/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/,O=5e3,k=20,A=.2,j=.25;function M(e){let t=N(e);return I(t),t}function N(e){let t=P(e),n=[],r,i;for(let e of t){let t=D.exec(e);if(t!==null){r=Number(t[1]),i=Number(t[2]),n.push(F(`hunk`,``,e));continue}if(r!==void 0&&i!==void 0){if(e.startsWith(`+`)){n.push(F(`add`,`+`,e.slice(1),{newLineNumber:i})),i++;continue}if(e.startsWith(`-`)){n.push(F(`remove`,`-`,e.slice(1),{oldLineNumber:r})),r++;continue}if(e.startsWith(` `)){n.push(F(`context`,` `,e.slice(1),{oldLineNumber:r,newLineNumber:i})),r++,i++;continue}if(e.startsWith(`\\`)){n.push(F(`marker`,``,e));continue}}r=void 0,i=void 0,n.push(F(`meta`,``,e))}return n}function P(e){if(e===``)return[];let t=e.replace(/\r\n/g,`
7
- `).replace(/\r/g,`
8
- `).split(`
9
- `);return t.at(-1)===``&&t.pop(),t}function F(e,t,n,r={}){return{kind:e,prefix:t,text:n,spans:n===``?[]:[{text:n,changed:!1}],...r}}function I(e){let t=0;for(;t<e.length;){if(e[t]?.kind!==`remove`){t++;continue}let n=t;for(;e[t]?.kind===`remove`;)t++;let r=t;for(;e[t]?.kind===`add`;)t++;r!==t&&L(e.slice(n,r),e.slice(r,t))}}function L(e,t){if(!(e.length+t.length>k))for(let n of R(e,t)){let e=U(n.removed.text,n.added.text);e!==void 0&&(n.removed.spans=e.removed,n.added.spans=e.added)}}function R(e,t){if(e.length===t.length)return e.map((e,n)=>({removed:e,added:t[n]})).filter(z);if(e.length===1)return B(e[0],t);if(t.length===1)return V(e,t[0]);let n=[],r=Math.min(e.length,t.length);for(let i=0;i<r;i++){let r=e[i],a=t[i];r===void 0||a===void 0||W(r.text,a.text)>=j&&n.push({removed:r,added:a})}return n}function z(e){return e.added!==void 0}function B(e,t){if(e===void 0)return[];let n=H(e.text,t);return n===void 0?[]:[{removed:e,added:n}]}function V(e,t){if(t===void 0)return[];let n=H(t.text,e);return n===void 0?[]:[{removed:n,added:t}]}function H(e,t){let n,r=j;for(let i of t){let t=W(e,i.text);t<=r||(n=i,r=t)}return n}function U(e,t){if(e===t||e.length>O||t.length>O)return;let n=c(e,t),r=G(n,e,t);if(Math.max(e.length,t.length)>=20&&r<A)return;let i=[],a=[];for(let e of n)e.value!==``&&(e.added?a.push({text:e.value,changed:!0}):e.removed?i.push({text:e.value,changed:!0}):(i.push({text:e.value,changed:!1}),a.push({text:e.value,changed:!1})));if(!(!i.some(e=>e.changed)&&!a.some(e=>e.changed)))return{removed:K(i),added:K(a)}}function W(e,t){return e===t?1:e.length>O||t.length>O?0:G(c(e,t),e,t)}function G(e,t,n){let r=Math.max(t.length,n.length);return r===0?1:e.reduce((e,t)=>t.added||t.removed?e:e+t.value.length,0)/r}function K(e){let t=[];for(let n of e){let e=t[t.length-1];e?.changed===n.changed?e.text+=n.text:t.push({...n})}return t}var q=class extends i{constructor(...e){super(...e),this.diff=``}render(){let e=M(this.diff);return e.length===0?r`<p class="empty">没有差异。</p>`:r`
10
- <div class="scroller">
11
- <div class="diff-grid" role="table" aria-label="统一差异">
12
- ${e.map(e=>this.renderLine(e))}
13
- </div>
14
- </div>
15
- `}renderLine(e){let t=e.kind;return r`
16
- <div class="line" role="row">
17
- <span class=${`cell line-number old ${t}`} role="cell">${Y(e.oldLineNumber)}</span>
18
- <span class=${`cell line-number new ${t}`} role="cell">${Y(e.newLineNumber)}</span>
19
- <span class=${`cell prefix ${t}`} role="cell">${e.prefix}</span>
20
- <span class=${`cell content ${t}`} role="cell">${J(e.spans)}</span>
21
- </div>
22
- `}static{this.styles=e`
23
- :host { display: block; min-height: 0; height: 100%; color: var(--pi-text); background: var(--pi-bg); }
24
- .empty { box-sizing: border-box; margin: 0; padding: 10px; color: var(--pi-muted); }
25
- .scroller { height: 100%; min-height: 0; overflow: auto; background: var(--pi-bg); }
26
- .diff-grid { display: grid; grid-template-columns: max-content max-content 2ch max-content; width: max-content; min-width: 100%; padding: 6px 0; font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; line-height: 1.45; }
27
- .line { display: contents; }
28
- .cell { min-height: 1.45em; white-space: pre; }
29
- .line-number { min-width: 4ch; padding: 0 8px; border-right: 1px solid var(--pi-border-muted); color: var(--pi-dim); text-align: right; user-select: none; }
30
- .prefix { padding: 0 4px; color: var(--pi-dim); text-align: center; user-select: none; }
31
- .content { padding: 0 12px 0 4px; }
32
- .meta { color: var(--pi-dim); }
33
- .hunk { background: color-mix(in srgb, var(--pi-accent) 9%, transparent); color: var(--pi-accent); }
34
- .add { background: color-mix(in srgb, var(--pi-success) 12%, transparent); }
35
- .remove { background: color-mix(in srgb, var(--pi-danger) 12%, transparent); }
36
- .marker { color: var(--pi-dim); }
37
- .content.add .inline-change { border-radius: 2px; background: color-mix(in srgb, var(--pi-success) 36%, transparent); color: var(--pi-text); }
38
- .content.remove .inline-change { border-radius: 2px; background: color-mix(in srgb, var(--pi-danger) 36%, transparent); color: var(--pi-text); }
39
- `}};t([n()],q.prototype,`diff`,void 0),q=t([a(`unified-diff-viewer`)],q);function J(e){return e.map(e=>r`<span class=${e.changed?`inline-change`:``}>${e.text}</span>`)}function Y(e){return e===void 0?``:String(e)}export{q as UnifiedDiffViewer};
@@ -1,22 +0,0 @@
1
- import type { TerminalCommandRun, TerminalCommandRunFilter, TerminalCommandRunHandle, Workspace, WorkspaceTerminalCommandInput } from "../plugin-api.js";
2
- export interface UnstableRunTerminalCommandInput extends WorkspaceTerminalCommandInput {
3
- workspace: Workspace;
4
- }
5
- export interface UnstableTerminalCommandRunsRuntime {
6
- runCommand(input: UnstableRunTerminalCommandInput): Promise<TerminalCommandRunHandle>;
7
- listCommandRuns(filter?: TerminalCommandRunFilter): Promise<TerminalCommandRun[]>;
8
- getCommandRun(runId: string): Promise<TerminalCommandRun | undefined>;
9
- open(options?: {
10
- terminalId?: string | undefined;
11
- }): void;
12
- }
13
- export interface UnstableRuntimeCapabilities {
14
- terminalCommandRuns: UnstableTerminalCommandRunsRuntime;
15
- openSettings?: (section?: string) => void;
16
- }
17
- export interface UnstablePluginRuntimeContext {
18
- piWebUnstable?: UnstableRuntimeCapabilities;
19
- }
20
- export interface UnstableWorkspacePanelContext {
21
- piWebUnstable?: Pick<UnstableRuntimeCapabilities, "terminalCommandRuns">;
22
- }
@@ -1,75 +0,0 @@
1
- import { canonicalizeStoredCwd, cwdPathsEqual } from "../workingDirectory.js";
2
- /**
3
- * Locate the parents of `sessions` that live in a different working directory,
4
- * keyed by the `parentSessionPath` the child recorded.
5
- *
6
- * Sessions are listed per working directory, so a child spawned into another
7
- * worktree of the same project has a `parentSessionPath` that resolves to
8
- * nothing in its own list. The parent's cwd and id are recorded in the parent
9
- * session file's header, so one small header read per distinct missing parent is
10
- * enough to point at it — no cross-workspace listing required.
11
- *
12
- * Parents already present in `sessions` are skipped without a read: they are
13
- * linkable by path already, so the IO would buy nothing. Headers for a given
14
- * path are immutable in practice, so `readHeader` is free to cache; this
15
- * function stays stateless.
16
- */
17
- export async function locateOutOfListingParents(sessions, listingCwd, readHeader) {
18
- const located = new Map();
19
- for (const parentSessionPath of missingParentPaths(sessions)) {
20
- const location = await parentLocation(parentSessionPath, readHeader);
21
- // A parent sharing the listing's cwd is not "elsewhere": it is absent for
22
- // some other reason (archived and moved, or simply not listed), and offering
23
- // a jump to this same workspace would not help.
24
- if (location === undefined || cwdPathsEqual(location.parentSessionCwd, listingCwd))
25
- continue;
26
- located.set(parentSessionPath, location);
27
- }
28
- return located;
29
- }
30
- /** Distinct recorded parent paths that no session in the listing occupies. */
31
- function missingParentPaths(sessions) {
32
- const listedPaths = new Set(sessions.map((session) => canonicalizeStoredCwd(session.path)));
33
- const missing = new Set();
34
- for (const session of sessions) {
35
- const parentSessionPath = session.parentSessionPath;
36
- if (parentSessionPath === undefined || parentSessionPath === "")
37
- continue;
38
- if (listedPaths.has(canonicalizeStoredCwd(parentSessionPath)))
39
- continue;
40
- missing.add(parentSessionPath);
41
- }
42
- return missing;
43
- }
44
- /**
45
- * A parent whose header is unreadable or carries no cwd (very old session files)
46
- * has no reportable location, so the browser keeps saying only that the parent is
47
- * unavailable.
48
- */
49
- async function parentLocation(parentSessionPath, readHeader) {
50
- const header = await readHeader(parentSessionPath);
51
- if (header?.cwd === undefined)
52
- return undefined;
53
- return { parentSessionId: header.id, parentSessionCwd: canonicalizeStoredCwd(header.cwd) };
54
- }
55
- /**
56
- * Count, per listed session path, how many sessions outside this listing record
57
- * it as their parent, so a parent row can show that it has children that are not
58
- * visible beneath it.
59
- *
60
- * Children are identified only by the parent session *file* path they recorded,
61
- * which is exactly the link Pi writes into the child header; neither a header
62
- * read of the parent nor the child's own location is required.
63
- */
64
- export function countOutOfListingChildren(sessions, childParentSessionPaths) {
65
- const listedPaths = new Map(sessions.map((session) => [canonicalizeStoredCwd(session.path), session.path]));
66
- const counts = new Map();
67
- for (const parentSessionPath of childParentSessionPaths) {
68
- const listedPath = listedPaths.get(canonicalizeStoredCwd(parentSessionPath));
69
- if (listedPath === undefined)
70
- continue;
71
- counts.set(listedPath, (counts.get(listedPath) ?? 0) + 1);
72
- }
73
- return counts;
74
- }
75
- //# sourceMappingURL=parentSessionLocator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"parentSessionLocator.js","sourceRoot":"","sources":["../../../src/server/sessions/parentSessionLocator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAkB9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,QAA2C,EAC3C,UAAkB,EAClB,UAA+B;IAE/B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAiC,CAAC;IACzD,KAAK,MAAM,iBAAiB,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7D,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;QACrE,0EAA0E;QAC1E,6EAA6E;QAC7E,gDAAgD;QAChD,IAAI,QAAQ,KAAK,SAAS,IAAI,aAAa,CAAC,QAAQ,CAAC,gBAAgB,EAAE,UAAU,CAAC;YAAE,SAAS;QAC7F,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,SAAS,kBAAkB,CAAC,QAA2C;IACrE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5F,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACpD,IAAI,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,KAAK,EAAE;YAAE,SAAS;QAC1E,IAAI,WAAW,CAAC,GAAG,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;YAAE,SAAS;QACxE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc,CAAC,iBAAyB,EAAE,UAA+B;IACtF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACnD,IAAI,MAAM,EAAE,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAChD,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,EAAE,gBAAgB,EAAE,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AAC7F,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAA2C,EAC3C,uBAA0C;IAE1C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5G,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,iBAAiB,IAAI,uBAAuB,EAAE,CAAC;QACxD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAC7E,IAAI,UAAU,KAAK,SAAS;YAAE,SAAS;QACvC,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,40 +0,0 @@
1
- import { createReadStream } from "node:fs";
2
- import { stat } from "node:fs/promises";
3
- import { extname } from "node:path";
4
- import { MAX_IMAGE_PREVIEW_BYTES, MAX_IMAGE_PREVIEW_LABEL } from "../../shared/workspaceFiles.js";
5
- import { resolveWorkspacePathAccessTarget } from "./pathAccessPolicy.js";
6
- const IMAGE_MIME_TYPES = {
7
- ".avif": "image/avif",
8
- ".bmp": "image/bmp",
9
- ".gif": "image/gif",
10
- ".ico": "image/x-icon",
11
- ".jpeg": "image/jpeg",
12
- ".jpg": "image/jpeg",
13
- ".png": "image/png",
14
- ".svg": "image/svg+xml",
15
- ".webp": "image/webp",
16
- };
17
- export function imageMimeTypeForPath(path) {
18
- return IMAGE_MIME_TYPES[extname(path).toLowerCase()];
19
- }
20
- export async function readWorkspaceImagePreview(rootPath, path, pathAccess) {
21
- if (path === undefined || path === "")
22
- throw new Error("path query parameter is required");
23
- const { target, displayPath } = await resolveWorkspacePathAccessTarget(rootPath, path, pathAccess);
24
- const s = await stat(target);
25
- if (!s.isFile())
26
- throw new Error("Path is not a file");
27
- const mimeType = imageMimeTypeForPath(displayPath);
28
- if (mimeType === undefined)
29
- throw new Error("Image preview is not supported for this file type");
30
- if (s.size > MAX_IMAGE_PREVIEW_BYTES)
31
- throw new Error(`Image is too large to preview (limit ${MAX_IMAGE_PREVIEW_LABEL})`);
32
- return {
33
- path: displayPath,
34
- mimeType,
35
- size: s.size,
36
- modifiedAt: s.mtime.toISOString(),
37
- stream: createReadStream(target),
38
- };
39
- }
40
- //# sourceMappingURL=imagePreviewService.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"imagePreviewService.js","sourceRoot":"","sources":["../../../src/server/workspaces/imagePreviewService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAmB,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAClG,OAAO,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAC;AAEzE,MAAM,gBAAgB,GAAuC;IAC3D,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,cAAc;IACtB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,OAAO,EAAE,YAAY;CACtB,CAAC;AAUF,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,QAAgB,EAAE,IAAwB,EAAE,UAAkC;IAC5H,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IAC3F,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,gCAAgC,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IACnG,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,QAAQ,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACjG,IAAI,CAAC,CAAC,IAAI,GAAG,uBAAuB;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,uBAAuB,GAAG,CAAC,CAAC;IAC1H,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,QAAQ;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE;QACjC,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC;KACjC,CAAC;AACJ,CAAC"}