@archmax-ai/harness 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -0
  3. package/dist/agent.d.ts +174 -0
  4. package/dist/agent.js +140 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/assembly/compose.d.ts +170 -0
  7. package/dist/assembly/compose.js +391 -0
  8. package/dist/assembly/compose.js.map +1 -0
  9. package/dist/assembly/delegation-registry.d.ts +5 -0
  10. package/dist/assembly/delegation-registry.js +118 -0
  11. package/dist/assembly/delegation-registry.js.map +1 -0
  12. package/dist/assembly/index.d.ts +192 -0
  13. package/dist/assembly/index.js +265 -0
  14. package/dist/assembly/index.js.map +1 -0
  15. package/dist/assembly/plain.d.ts +7 -0
  16. package/dist/assembly/plain.js +41 -0
  17. package/dist/assembly/plain.js.map +1 -0
  18. package/dist/authoring-skill/archmax-harness/README.md +76 -0
  19. package/dist/authoring-skill/archmax-harness/SKILL.md +241 -0
  20. package/dist/authoring-skill/archmax-harness/references/backend-integration.md +626 -0
  21. package/dist/authoring-skill/archmax-harness/references/cases.md +41 -0
  22. package/dist/authoring-skill/archmax-harness/references/diagnostics.md +51 -0
  23. package/dist/authoring-skill/archmax-harness/references/hook-and-test-scripts.md +1070 -0
  24. package/dist/authoring-skill/archmax-harness/references/hooks-and-scripts.md +82 -0
  25. package/dist/authoring-skill/archmax-harness/references/wiring.md +101 -0
  26. package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +1631 -0
  27. package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +241 -0
  28. package/dist/behaviour/support.d.ts +232 -0
  29. package/dist/behaviour/support.js +339 -0
  30. package/dist/behaviour/support.js.map +1 -0
  31. package/dist/cli/banner.d.ts +11 -0
  32. package/dist/cli/banner.js +29 -0
  33. package/dist/cli/banner.js.map +1 -0
  34. package/dist/cli/bootstrap.d.ts +33 -0
  35. package/dist/cli/bootstrap.js +153 -0
  36. package/dist/cli/bootstrap.js.map +1 -0
  37. package/dist/cli/command.d.ts +39 -0
  38. package/dist/cli/command.js +97 -0
  39. package/dist/cli/command.js.map +1 -0
  40. package/dist/cli/state-flow.d.ts +46 -0
  41. package/dist/cli/state-flow.js +268 -0
  42. package/dist/cli/state-flow.js.map +1 -0
  43. package/dist/cli/style.d.ts +41 -0
  44. package/dist/cli/style.js +64 -0
  45. package/dist/cli/style.js.map +1 -0
  46. package/dist/cli/turn.d.ts +41 -0
  47. package/dist/cli/turn.js +161 -0
  48. package/dist/cli/turn.js.map +1 -0
  49. package/dist/cli.d.ts +10 -0
  50. package/dist/cli.js +426 -0
  51. package/dist/cli.js.map +1 -0
  52. package/dist/core/code-description.d.ts +22 -0
  53. package/dist/core/code-description.js +38 -0
  54. package/dist/core/code-description.js.map +1 -0
  55. package/dist/core/deepagents.d.ts +183 -0
  56. package/dist/core/deepagents.js +128 -0
  57. package/dist/core/deepagents.js.map +1 -0
  58. package/dist/core/events.d.ts +350 -0
  59. package/dist/core/events.js +205 -0
  60. package/dist/core/events.js.map +1 -0
  61. package/dist/core/frontmatter.d.ts +15 -0
  62. package/dist/core/frontmatter.js +32 -0
  63. package/dist/core/frontmatter.js.map +1 -0
  64. package/dist/core/listing-redact.d.ts +37 -0
  65. package/dist/core/listing-redact.js +88 -0
  66. package/dist/core/listing-redact.js.map +1 -0
  67. package/dist/core/match.d.ts +26 -0
  68. package/dist/core/match.js +75 -0
  69. package/dist/core/match.js.map +1 -0
  70. package/dist/core/message-readers.d.ts +84 -0
  71. package/dist/core/message-readers.js +159 -0
  72. package/dist/core/message-readers.js.map +1 -0
  73. package/dist/core/messages.d.ts +49 -0
  74. package/dist/core/messages.js +85 -0
  75. package/dist/core/messages.js.map +1 -0
  76. package/dist/core/mount-prompt.d.ts +28 -0
  77. package/dist/core/mount-prompt.js +55 -0
  78. package/dist/core/mount-prompt.js.map +1 -0
  79. package/dist/core/mount-redact.d.ts +28 -0
  80. package/dist/core/mount-redact.js +32 -0
  81. package/dist/core/mount-redact.js.map +1 -0
  82. package/dist/core/mounts.d.ts +88 -0
  83. package/dist/core/mounts.js +147 -0
  84. package/dist/core/mounts.js.map +1 -0
  85. package/dist/core/path-mapping.d.ts +52 -0
  86. package/dist/core/path-mapping.js +113 -0
  87. package/dist/core/path-mapping.js.map +1 -0
  88. package/dist/core/platform-prompt.generated.d.ts +2 -0
  89. package/dist/core/platform-prompt.generated.js +4 -0
  90. package/dist/core/platform-prompt.generated.js.map +1 -0
  91. package/dist/core/prompt.d.ts +42 -0
  92. package/dist/core/prompt.js +75 -0
  93. package/dist/core/prompt.js.map +1 -0
  94. package/dist/core/session-id.d.ts +38 -0
  95. package/dist/core/session-id.js +61 -0
  96. package/dist/core/session-id.js.map +1 -0
  97. package/dist/core/session-store.d.ts +85 -0
  98. package/dist/core/session-store.js +149 -0
  99. package/dist/core/session-store.js.map +1 -0
  100. package/dist/core/session-zone.d.ts +54 -0
  101. package/dist/core/session-zone.js +82 -0
  102. package/dist/core/session-zone.js.map +1 -0
  103. package/dist/core/skill-prompt.d.ts +31 -0
  104. package/dist/core/skill-prompt.js +54 -0
  105. package/dist/core/skill-prompt.js.map +1 -0
  106. package/dist/core/skill-redact.d.ts +15 -0
  107. package/dist/core/skill-redact.js +27 -0
  108. package/dist/core/skill-redact.js.map +1 -0
  109. package/dist/core/skills.d.ts +172 -0
  110. package/dist/core/skills.js +214 -0
  111. package/dist/core/skills.js.map +1 -0
  112. package/dist/core/tool-mocks.d.ts +23 -0
  113. package/dist/core/tool-mocks.js +39 -0
  114. package/dist/core/tool-mocks.js.map +1 -0
  115. package/dist/core/tool-telemetry.d.ts +16 -0
  116. package/dist/core/tool-telemetry.js +40 -0
  117. package/dist/core/tool-telemetry.js.map +1 -0
  118. package/dist/core/usage.d.ts +114 -0
  119. package/dist/core/usage.js +226 -0
  120. package/dist/core/usage.js.map +1 -0
  121. package/dist/core/workspace-context.d.ts +136 -0
  122. package/dist/core/workspace-context.js +178 -0
  123. package/dist/core/workspace-context.js.map +1 -0
  124. package/dist/core/workspace-prompt.d.ts +7 -0
  125. package/dist/core/workspace-prompt.js +102 -0
  126. package/dist/core/workspace-prompt.js.map +1 -0
  127. package/dist/core/workspace-router.d.ts +61 -0
  128. package/dist/core/workspace-router.js +145 -0
  129. package/dist/core/workspace-router.js.map +1 -0
  130. package/dist/core/workspace.d.ts +85 -0
  131. package/dist/core/workspace.js +193 -0
  132. package/dist/core/workspace.js.map +1 -0
  133. package/dist/core/zones.d.ts +181 -0
  134. package/dist/core/zones.js +202 -0
  135. package/dist/core/zones.js.map +1 -0
  136. package/dist/env.d.ts +99 -0
  137. package/dist/env.js +271 -0
  138. package/dist/env.js.map +1 -0
  139. package/dist/index.d.ts +265 -0
  140. package/dist/index.js +197 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/kernel/kernel.d.ts +192 -0
  143. package/dist/kernel/kernel.js +751 -0
  144. package/dist/kernel/kernel.js.map +1 -0
  145. package/dist/lifecycle/hook-shape.d.ts +44 -0
  146. package/dist/lifecycle/hook-shape.js +66 -0
  147. package/dist/lifecycle/hook-shape.js.map +1 -0
  148. package/dist/lifecycle/runner.d.ts +177 -0
  149. package/dist/lifecycle/runner.js +372 -0
  150. package/dist/lifecycle/runner.js.map +1 -0
  151. package/dist/lifecycle/transcript.d.ts +27 -0
  152. package/dist/lifecycle/transcript.js +43 -0
  153. package/dist/lifecycle/transcript.js.map +1 -0
  154. package/dist/machine/allow.d.ts +65 -0
  155. package/dist/machine/allow.js +107 -0
  156. package/dist/machine/allow.js.map +1 -0
  157. package/dist/machine/delegation.d.ts +9 -0
  158. package/dist/machine/delegation.js +10 -0
  159. package/dist/machine/delegation.js.map +1 -0
  160. package/dist/machine/diagnostic.d.ts +14 -0
  161. package/dist/machine/diagnostic.js +2 -0
  162. package/dist/machine/diagnostic.js.map +1 -0
  163. package/dist/machine/lint-spec.d.ts +4 -0
  164. package/dist/machine/lint-spec.js +266 -0
  165. package/dist/machine/lint-spec.js.map +1 -0
  166. package/dist/machine/load-spec.d.ts +90 -0
  167. package/dist/machine/load-spec.js +120 -0
  168. package/dist/machine/load-spec.js.map +1 -0
  169. package/dist/machine/machine.d.ts +273 -0
  170. package/dist/machine/machine.js +551 -0
  171. package/dist/machine/machine.js.map +1 -0
  172. package/dist/machine/mount-grants.d.ts +25 -0
  173. package/dist/machine/mount-grants.js +24 -0
  174. package/dist/machine/mount-grants.js.map +1 -0
  175. package/dist/machine/slug.d.ts +14 -0
  176. package/dist/machine/slug.js +17 -0
  177. package/dist/machine/slug.js.map +1 -0
  178. package/dist/machine/spec-schema.d.ts +662 -0
  179. package/dist/machine/spec-schema.js +717 -0
  180. package/dist/machine/spec-schema.js.map +1 -0
  181. package/dist/machine/tool-names.d.ts +98 -0
  182. package/dist/machine/tool-names.js +144 -0
  183. package/dist/machine/tool-names.js.map +1 -0
  184. package/dist/machine/triggers.d.ts +114 -0
  185. package/dist/machine/triggers.js +165 -0
  186. package/dist/machine/triggers.js.map +1 -0
  187. package/dist/machine/types.d.ts +186 -0
  188. package/dist/machine/types.js +12 -0
  189. package/dist/machine/types.js.map +1 -0
  190. package/dist/machine/validate-spec.d.ts +42 -0
  191. package/dist/machine/validate-spec.js +29 -0
  192. package/dist/machine/validate-spec.js.map +1 -0
  193. package/dist/machine/variables.d.ts +196 -0
  194. package/dist/machine/variables.js +415 -0
  195. package/dist/machine/variables.js.map +1 -0
  196. package/dist/public/cli.d.ts +15 -0
  197. package/dist/public/cli.js +14 -0
  198. package/dist/public/cli.js.map +1 -0
  199. package/dist/public/messages.d.ts +33 -0
  200. package/dist/public/messages.js +33 -0
  201. package/dist/public/messages.js.map +1 -0
  202. package/dist/public/sandbox.d.ts +99 -0
  203. package/dist/public/sandbox.js +32 -0
  204. package/dist/public/sandbox.js.map +1 -0
  205. package/dist/public/spec.d.ts +147 -0
  206. package/dist/public/spec.js +149 -0
  207. package/dist/public/spec.js.map +1 -0
  208. package/dist/public/testing.d.ts +71 -0
  209. package/dist/public/testing.js +39 -0
  210. package/dist/public/testing.js.map +1 -0
  211. package/dist/rubrics/rubrics.d.ts +135 -0
  212. package/dist/rubrics/rubrics.js +145 -0
  213. package/dist/rubrics/rubrics.js.map +1 -0
  214. package/dist/runtime/contract.d.ts +73 -0
  215. package/dist/runtime/contract.js +96 -0
  216. package/dist/runtime/contract.js.map +1 -0
  217. package/dist/sandbox/assets/parts/core.js +22 -0
  218. package/dist/sandbox/assets/parts/lifecycle-hook.js +47 -0
  219. package/dist/sandbox/bridge.d.ts +16 -0
  220. package/dist/sandbox/bridge.js +95 -0
  221. package/dist/sandbox/bridge.js.map +1 -0
  222. package/dist/sandbox/executor.d.ts +46 -0
  223. package/dist/sandbox/executor.js +119 -0
  224. package/dist/sandbox/executor.js.map +1 -0
  225. package/dist/sandbox/imports.d.ts +33 -0
  226. package/dist/sandbox/imports.js +67 -0
  227. package/dist/sandbox/imports.js.map +1 -0
  228. package/dist/sandbox/prelude.d.ts +12 -0
  229. package/dist/sandbox/prelude.js +51 -0
  230. package/dist/sandbox/prelude.js.map +1 -0
  231. package/dist/sandbox/ptc-gateway.d.ts +104 -0
  232. package/dist/sandbox/ptc-gateway.js +167 -0
  233. package/dist/sandbox/ptc-gateway.js.map +1 -0
  234. package/dist/sandbox/runtime.d.ts +59 -0
  235. package/dist/sandbox/runtime.js +51 -0
  236. package/dist/sandbox/runtime.js.map +1 -0
  237. package/dist/sandbox/tools.d.ts +34 -0
  238. package/dist/sandbox/tools.js +147 -0
  239. package/dist/sandbox/tools.js.map +1 -0
  240. package/dist/sessions/operations.d.ts +79 -0
  241. package/dist/sessions/operations.js +121 -0
  242. package/dist/sessions/operations.js.map +1 -0
  243. package/dist/sessions/resolve.d.ts +97 -0
  244. package/dist/sessions/resolve.js +145 -0
  245. package/dist/sessions/resolve.js.map +1 -0
  246. package/dist/sessions/resume.d.ts +242 -0
  247. package/dist/sessions/resume.js +288 -0
  248. package/dist/sessions/resume.js.map +1 -0
  249. package/dist/sessions/scope.d.ts +99 -0
  250. package/dist/sessions/scope.js +145 -0
  251. package/dist/sessions/scope.js.map +1 -0
  252. package/dist/sessions/summary.d.ts +65 -0
  253. package/dist/sessions/summary.js +56 -0
  254. package/dist/sessions/summary.js.map +1 -0
  255. package/dist/testing/assertions.d.ts +30 -0
  256. package/dist/testing/assertions.js +231 -0
  257. package/dist/testing/assertions.js.map +1 -0
  258. package/dist/testing/case-document.d.ts +141 -0
  259. package/dist/testing/case-document.js +51 -0
  260. package/dist/testing/case-document.js.map +1 -0
  261. package/dist/testing/case-schema.d.ts +29 -0
  262. package/dist/testing/case-schema.js +519 -0
  263. package/dist/testing/case-schema.js.map +1 -0
  264. package/dist/testing/discovery.d.ts +10 -0
  265. package/dist/testing/discovery.js +24 -0
  266. package/dist/testing/discovery.js.map +1 -0
  267. package/dist/testing/driver.d.ts +78 -0
  268. package/dist/testing/driver.js +117 -0
  269. package/dist/testing/driver.js.map +1 -0
  270. package/dist/testing/grade.d.ts +116 -0
  271. package/dist/testing/grade.js +261 -0
  272. package/dist/testing/grade.js.map +1 -0
  273. package/dist/testing/interpreter.d.ts +55 -0
  274. package/dist/testing/interpreter.js +103 -0
  275. package/dist/testing/interpreter.js.map +1 -0
  276. package/dist/testing/mock-middleware.d.ts +5 -0
  277. package/dist/testing/mock-middleware.js +33 -0
  278. package/dist/testing/mock-middleware.js.map +1 -0
  279. package/dist/testing/runner.d.ts +205 -0
  280. package/dist/testing/runner.js +266 -0
  281. package/dist/testing/runner.js.map +1 -0
  282. package/dist/testing/target.d.ts +27 -0
  283. package/dist/testing/target.js +21 -0
  284. package/dist/testing/target.js.map +1 -0
  285. package/dist/validate/validate.d.ts +41 -0
  286. package/dist/validate/validate.js +669 -0
  287. package/dist/validate/validate.js.map +1 -0
  288. package/dist/workflow/agent-tools.d.ts +10 -0
  289. package/dist/workflow/agent-tools.js +10 -0
  290. package/dist/workflow/agent-tools.js.map +1 -0
  291. package/dist/workflow/checkpointer.d.ts +52 -0
  292. package/dist/workflow/checkpointer.js +200 -0
  293. package/dist/workflow/checkpointer.js.map +1 -0
  294. package/dist/workflow/control-tools.d.ts +174 -0
  295. package/dist/workflow/control-tools.js +468 -0
  296. package/dist/workflow/control-tools.js.map +1 -0
  297. package/dist/workflow/governance.d.ts +104 -0
  298. package/dist/workflow/governance.js +546 -0
  299. package/dist/workflow/governance.js.map +1 -0
  300. package/dist/workflow/middleware.d.ts +85 -0
  301. package/dist/workflow/middleware.js +283 -0
  302. package/dist/workflow/middleware.js.map +1 -0
  303. package/dist/workflow/on-error.d.ts +25 -0
  304. package/dist/workflow/on-error.js +58 -0
  305. package/dist/workflow/on-error.js.map +1 -0
  306. package/dist/workflow/parks.d.ts +46 -0
  307. package/dist/workflow/parks.js +513 -0
  308. package/dist/workflow/parks.js.map +1 -0
  309. package/dist/workflow/paths.d.ts +67 -0
  310. package/dist/workflow/paths.js +108 -0
  311. package/dist/workflow/paths.js.map +1 -0
  312. package/dist/workflow/prompt-cache.d.ts +70 -0
  313. package/dist/workflow/prompt-cache.js +103 -0
  314. package/dist/workflow/prompt-cache.js.map +1 -0
  315. package/dist/workflow/prompt-pruning.d.ts +20 -0
  316. package/dist/workflow/prompt-pruning.js +83 -0
  317. package/dist/workflow/prompt-pruning.js.map +1 -0
  318. package/dist/workflow/render-prompt.d.ts +45 -0
  319. package/dist/workflow/render-prompt.js +140 -0
  320. package/dist/workflow/render-prompt.js.map +1 -0
  321. package/dist/workflow/runtime-config.d.ts +7 -0
  322. package/dist/workflow/runtime-config.js +9 -0
  323. package/dist/workflow/runtime-config.js.map +1 -0
  324. package/dist/workflow/session-artifacts.d.ts +90 -0
  325. package/dist/workflow/session-artifacts.js +134 -0
  326. package/dist/workflow/session-artifacts.js.map +1 -0
  327. package/dist/workflow/session-view.d.ts +31 -0
  328. package/dist/workflow/session-view.js +94 -0
  329. package/dist/workflow/session-view.js.map +1 -0
  330. package/dist/workflow/snapshot.d.ts +14 -0
  331. package/dist/workflow/snapshot.js +97 -0
  332. package/dist/workflow/snapshot.js.map +1 -0
  333. package/dist/workflow/state.d.ts +347 -0
  334. package/dist/workflow/state.js +322 -0
  335. package/dist/workflow/state.js.map +1 -0
  336. package/dist/workflow/sub-workflow.d.ts +174 -0
  337. package/dist/workflow/sub-workflow.js +392 -0
  338. package/dist/workflow/sub-workflow.js.map +1 -0
  339. package/dist/workflow/tool-service.d.ts +48 -0
  340. package/dist/workflow/tool-service.js +291 -0
  341. package/dist/workflow/tool-service.js.map +1 -0
  342. package/dist/workflow/turn-boundary.d.ts +39 -0
  343. package/dist/workflow/turn-boundary.js +128 -0
  344. package/dist/workflow/turn-boundary.js.map +1 -0
  345. package/dist/workflow/turn-runner.d.ts +40 -0
  346. package/dist/workflow/turn-runner.js +122 -0
  347. package/dist/workflow/turn-runner.js.map +1 -0
  348. package/dist/workflow/workflow-tools.d.ts +46 -0
  349. package/dist/workflow/workflow-tools.js +90 -0
  350. package/dist/workflow/workflow-tools.js.map +1 -0
  351. package/package.json +119 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-context.js","sourceRoot":"","sources":["../../src/core/workspace-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type MountPrefixes } from "./zones.js";
2
+ /**
3
+ * Render the "Workspace zones" section of the system prompt for one assembly's
4
+ * resolved mounts. Every name it prints is a route the workspace actually
5
+ * serves; a workspace with no mounts simply gets no mount bullets.
6
+ */
7
+ export declare function renderWorkspaceZones(mounts?: MountPrefixes): string;
@@ -0,0 +1,102 @@
1
+ import { NO_MOUNTS, SESSION_OFFLOAD_DIRS, SESSION_OPEN_DIR, } from "./zones.js";
2
+ /**
3
+ * The system prompt's account of the workspace, **rendered from the assembly's
4
+ * resolved mount table** rather than written by hand.
5
+ *
6
+ * The same reason the graph section is rendered from the loaded spec: prose about
7
+ * enforcement drifts from enforcement. A hand-maintained list of mounts in the
8
+ * platform prompt has to be edited every time a consumer's mount table changes,
9
+ * and when it is not, the agent is told it has directories that do not exist —
10
+ * it then reads a missing path while faithfully quoting its own instructions.
11
+ * Deriving the list from {@link MountPrefixes} (the very keys the composite
12
+ * routes on and the kernel classifies against) makes that unrepresentable.
13
+ *
14
+ * Consumer-declared mounts are the workspace's shape, so a custom platform prompt
15
+ * inherits an accurate description without restating one.
16
+ */
17
+ /**
18
+ * Mount names as the agent addresses them: directories with a trailing slash,
19
+ * file mounts by their exact path, each in backticks and alphabetically ordered
20
+ * so the rendered prompt is stable across assemblies of the same table.
21
+ *
22
+ * Dot-prefixed mounts are omitted: `.platform/` and its kind carry the runtime's
23
+ * own inputs (the platform prompt the agent is already reading), not authored
24
+ * content it should go looking through.
25
+ *
26
+ * **Governed** mounts are omitted too, and for a load-bearing reason: which of
27
+ * them a state reaches varies, and this section is part of the cacheable prefix,
28
+ * which does not. They are disclosed where they apply, in the volatile "Current
29
+ * state" block (see `renderMountsSection`).
30
+ */
31
+ function mountNames(mounts, writable) {
32
+ const isWritable = (name) => mounts.writable.includes(name);
33
+ const pick = (names) => names.filter((name) => !name.startsWith(".") &&
34
+ !mounts.governed.includes(name) &&
35
+ isWritable(name) === writable).sort();
36
+ const entry = (name, label) => ({
37
+ label,
38
+ // Only a directory mount is ever unsearchable (`resolveMounts` lists no file).
39
+ browseOnly: mounts.unsearchable.includes(name),
40
+ });
41
+ return [
42
+ ...pick(mounts.dirs).map((name) => entry(name, `\`${name}/\``)),
43
+ ...pick(mounts.files).map((name) => entry(name, `\`${name}\``)),
44
+ ];
45
+ }
46
+ /**
47
+ * Render the "Workspace zones" section of the system prompt for one assembly's
48
+ * resolved mounts. Every name it prints is a route the workspace actually
49
+ * serves; a workspace with no mounts simply gets no mount bullets.
50
+ */
51
+ export function renderWorkspaceZones(mounts = NO_MOUNTS) {
52
+ const offload = SESSION_OFFLOAD_DIRS.map((dir) => `\`${dir}/\``).join(", ");
53
+ const readOnly = mountNames(mounts, false);
54
+ const writable = mountNames(mounts, true);
55
+ const bullets = [
56
+ `- **\`${SESSION_OPEN_DIR}/\`** — your working area: intermediate files and the ` +
57
+ `artifacts you produce. Always readable and writable, whatever state you are in.`,
58
+ `- **${offload}** — where the runtime parks oversized tool results and ` +
59
+ `history. Read them when handed a path (paginate with \`read_file\` offset/limit); ` +
60
+ `you cannot write there.`,
61
+ ];
62
+ if (readOnly.length + writable.length > 0) {
63
+ // One bullet per mount, each with its posture, rather than two prose groups:
64
+ // the agent addresses a mount by name, so the name is what must carry whether
65
+ // it can be written. Same vocabulary as the volatile per-state listing.
66
+ const notes = [];
67
+ if (readOnly.length > 0) {
68
+ notes.push("A `read-only` mount refuses writes; read it freely.");
69
+ }
70
+ if (writable.length > 0) {
71
+ notes.push(`A \`read/write\` mount is as open to you as \`${SESSION_OPEN_DIR}/\`: write there when ` +
72
+ `the work belongs outside this run, and the write is checked against the active ` +
73
+ `state's tool rules like any other. It outlives the run, so keep scratch files out.`);
74
+ }
75
+ if ([...readOnly, ...writable].some((m) => m.browseOnly)) {
76
+ notes.push("A `browse only` mount is listed and read, never searched: a search from the root " +
77
+ "leaves it out, and a search addressed at it is answered by the mount itself.");
78
+ }
79
+ const line = (posture) => (m) => ` - **${m.label}** — ${posture}${m.browseOnly ? ", browse only" : ""}`;
80
+ bullets.push(`- **Mounts** — authored content beside the run, each marked with what you may do there:`, ...readOnly.map(line("read-only")), ...writable.map(line("read/write")),
81
+ // Indented, so it reads as the rest of the bullet rather than a new one.
82
+ ` ${notes.join(" ")}`);
83
+ }
84
+ bullets.push(`- **Any other path in the root** belongs to this run and is governed by the ` +
85
+ `active state's tool rules: write one only where the state's spec allows it.`);
86
+ if (mounts.governed.length > 0) {
87
+ // Named nowhere here on purpose: which of them this state reaches is in the
88
+ // volatile block, so this prefix stays byte-identical across states.
89
+ bullets.push(`- **Some mounts are given per state.** The ones available where you are now are ` +
90
+ `listed under "Mounts available in this state" in the "Current state" block; a path ` +
91
+ `under any other is blocked here.`);
92
+ }
93
+ return [
94
+ "## Workspace zones",
95
+ "",
96
+ "Your workspace root **is this run** — writable and private to it. Authored",
97
+ "content is mounted beside it, read-only unless a mount below says otherwise.",
98
+ "",
99
+ ...bullets,
100
+ ].join("\n");
101
+ }
102
+ //# sourceMappingURL=workspace-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-prompt.js","sourceRoot":"","sources":["../../src/core/workspace-prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { BackendProtocolV2, CompositeBackend } from "deepagents";
2
+ import { classifyWorkspacePath } from "./zones.js";
3
+ import type { MountPrefixes } from "./mounts.js";
4
+ /**
5
+ * The workspace's single entry point, wrapping the mount-routing
6
+ * {@link CompositeBackend}. It owns the three things prefix routing cannot do
7
+ * on its own:
8
+ *
9
+ * 1. **Canonicalization.** `CompositeBackend` routes by literal prefix, but
10
+ * the workspace convention — agent tool calls, generated lifecycle scripts,
11
+ * the runtime's own `./skills/` discovery glob, documented authoring style —
12
+ * uses relative and dot-prefixed paths. Without canonicalizing first,
13
+ * `./skills/x` misses the `/skills/` mount and silently falls through to
14
+ * the run root: reads report the file missing and writes land in run state.
15
+ * 2. **File mounts.** A mount key without a trailing slash (`/AGENTS.md`) names
16
+ * one file, which a route prefix cannot express: prefix matching is
17
+ * `startsWith`, so `/AGENTS.md` would also capture `/AGENTS.md.bak`, and the
18
+ * stripped key would collapse to `/`.
19
+ * 3. **Agent-visible root shaping.** While a session is bound, a listing of `/`
20
+ * shows exactly the namespace the agent may address: authored mounts and
21
+ * authored root files plus the agent-addressable run areas, with the
22
+ * runtime-internal areas omitted. Listings outside a bound session (e.g.
23
+ * enumerating session folders for `runs.list()`) are returned untouched.
24
+ * 4. **Search posture.** A root-wide `grep`/`glob` fans out to every route and
25
+ * one route's `{ error }` is fatal to it, and the composite hands a route
26
+ * `/` whether the search was addressed at the mount or fanned out. A mount
27
+ * declared `searchable: false` is therefore absent from the composite that
28
+ * serves searches, and a search addressed at it (the mount or a path inside
29
+ * it) is delegated to its route directly, so the backend's own answer —
30
+ * matches or refusal — reaches the caller verbatim.
31
+ */
32
+ export interface WorkspaceRouterOptions {
33
+ /** Mount-routing backend: session zone as default route, authored zone mounted. */
34
+ composite: CompositeBackend;
35
+ /**
36
+ * The composite `grep`/`glob` fan out through: the same default route and the
37
+ * searchable directory routes only. Defaults to `composite`, which is exact
38
+ * when no mount is unsearchable.
39
+ */
40
+ searchComposite?: CompositeBackend;
41
+ /**
42
+ * Unsearchable directory mounts by mount name → the very route object the
43
+ * composite would have called, so an addressed search keeps the route's
44
+ * read-only wrapping and prefix-aware refusals. Default: none.
45
+ */
46
+ unsearchableRoutes?: ReadonlyMap<string, BackendProtocolV2>;
47
+ /** Exact-path file mounts, by mount name (e.g. `AGENTS.md` → its backend). */
48
+ fileMounts: Map<string, BackendProtocolV2>;
49
+ /** This workspace's resolved mount keys, for root-listing shaping. */
50
+ mountPrefixes: MountPrefixes;
51
+ /** The session id bound to the current async context, if any. */
52
+ boundSessionId: () => string | undefined;
53
+ }
54
+ /** Thrown when a workspace path resolves above the workspace root. */
55
+ export declare class WorkspacePathEscapeError extends Error {
56
+ readonly path: string;
57
+ constructor(path: string);
58
+ }
59
+ export declare function createWorkspaceRouter(options: WorkspaceRouterOptions): BackendProtocolV2;
60
+ /** Re-exported so callers can classify a path with the router's own rules. */
61
+ export { classifyWorkspacePath };
@@ -0,0 +1,145 @@
1
+ import { canonicalizeRelPath } from "./workspace.js";
2
+ import { SESSION_INTERNAL_DIRS, classifyWorkspacePath, mountNameOf } from "./zones.js";
3
+ /** Thrown when a workspace path resolves above the workspace root. */
4
+ export class WorkspacePathEscapeError extends Error {
5
+ path;
6
+ constructor(path) {
7
+ super(`Path ${JSON.stringify(path)} resolves outside the workspace root; ` +
8
+ `workspace paths may not traverse above it.`);
9
+ this.path = path;
10
+ this.name = "WorkspacePathEscapeError";
11
+ }
12
+ }
13
+ const INTERNAL_DIR_SET = new Set(SESSION_INTERNAL_DIRS);
14
+ /** Canonical, leading-slash form of a workspace path. Throws on escapes. */
15
+ function canonical(path) {
16
+ const { path: rel, escapes } = canonicalizeRelPath(path);
17
+ if (escapes)
18
+ throw new WorkspacePathEscapeError(path);
19
+ return `/${rel}`;
20
+ }
21
+ /** Directory-entry name of a `FileInfo` path (trailing slash tolerated). */
22
+ function entryName(path) {
23
+ return canonicalizeRelPath(path).path.split("/")[0] ?? "";
24
+ }
25
+ export function createWorkspaceRouter(options) {
26
+ const { composite, fileMounts, mountPrefixes, boundSessionId } = options;
27
+ const searchComposite = options.searchComposite ?? composite;
28
+ const unsearchableRoutes = options.unsearchableRoutes ?? new Map();
29
+ /** The file mount serving `path` exactly, or `null` for normal routing. */
30
+ const fileMount = (path) => {
31
+ const rel = canonical(path).slice(1);
32
+ const backend = fileMounts.get(rel);
33
+ return backend ? { backend, key: `/${rel}` } : null;
34
+ };
35
+ /**
36
+ * The unsearchable mount a search at `target` is addressed at, with the
37
+ * route-relative path the composite would have handed its route, or `null`
38
+ * when the search belongs to the fan-out composite. The routing mount is the
39
+ * longest-prefix match across every mount, so a searchable mount nested in an
40
+ * unsearchable one (or the reverse) is still routed to its own backend.
41
+ */
42
+ const addressedUnsearchable = (target) => {
43
+ const name = mountNameOf(target.slice(1), mountPrefixes);
44
+ const backend = name === null ? undefined : unsearchableRoutes.get(name);
45
+ if (!name || !backend)
46
+ return null;
47
+ // The composite's own formula: strip the route prefix, keep the leading
48
+ // slash, and the mount itself becomes `/`.
49
+ return { backend, name, routePath: target.slice(name.length + 1) || "/" };
50
+ };
51
+ /** Hide runtime-internal areas and surface file mounts at `/`. */
52
+ const shapeRoot = async (path, files) => {
53
+ if (path !== "/" || !boundSessionId())
54
+ return files;
55
+ const visible = files.filter((file) => !INTERNAL_DIR_SET.has(entryName(file.path)));
56
+ const present = new Set(visible.map((file) => canonicalizeRelPath(file.path).path));
57
+ for (const name of mountPrefixes.files) {
58
+ if (present.has(name))
59
+ continue;
60
+ const mounted = fileMounts.get(name);
61
+ if (!mounted)
62
+ continue;
63
+ const res = await mounted.readRaw(`/${name}`);
64
+ if (!res.error && res.data)
65
+ visible.push({ path: `/${name}`, is_dir: false });
66
+ }
67
+ return visible.sort((a, b) => a.path.localeCompare(b.path));
68
+ };
69
+ const router = {
70
+ // Preserve the CompositeBackend duck-type (`routePrefixes`) so Deep Agents
71
+ // components that detect mount-routing backends still recognize this one.
72
+ get routePrefixes() {
73
+ return composite.routePrefixes;
74
+ },
75
+ async ls(path) {
76
+ const target = canonical(path);
77
+ const file = fileMount(target);
78
+ const res = file ? await file.backend.ls(file.key) : await composite.ls(target);
79
+ if (res.error || !res.files)
80
+ return res;
81
+ return { ...res, files: await shapeRoot(target, res.files) };
82
+ },
83
+ read(filePath, offset, limit) {
84
+ const target = canonical(filePath);
85
+ const file = fileMount(target);
86
+ return file
87
+ ? file.backend.read(file.key, offset, limit)
88
+ : composite.read(target, offset, limit);
89
+ },
90
+ readRaw(filePath) {
91
+ const target = canonical(filePath);
92
+ const file = fileMount(target);
93
+ return file ? file.backend.readRaw(file.key) : composite.readRaw(target);
94
+ },
95
+ async grep(pattern, path, glob) {
96
+ if (path == null)
97
+ return searchComposite.grep(pattern, path, glob);
98
+ const target = canonical(path);
99
+ const direct = addressedUnsearchable(target);
100
+ if (!direct)
101
+ return searchComposite.grep(pattern, target, glob);
102
+ const res = await direct.backend.grep(pattern, direct.routePath, glob);
103
+ if (res.error)
104
+ return res;
105
+ // Re-apply the route prefix as the composite does for its own routes.
106
+ return {
107
+ ...res,
108
+ matches: (res.matches ?? []).map((m) => ({ ...m, path: `/${direct.name}${m.path}` })),
109
+ };
110
+ },
111
+ async glob(pattern, path) {
112
+ if (path === undefined)
113
+ return searchComposite.glob(pattern, path);
114
+ const target = canonical(path);
115
+ const direct = addressedUnsearchable(target);
116
+ if (!direct)
117
+ return searchComposite.glob(pattern, target);
118
+ const res = await direct.backend.glob(pattern, direct.routePath);
119
+ if (res.error)
120
+ return res;
121
+ return {
122
+ ...res,
123
+ files: (res.files ?? []).map((f) => ({ ...f, path: `/${direct.name}${f.path}` })),
124
+ };
125
+ },
126
+ write(filePath, content) {
127
+ const target = canonical(filePath);
128
+ // Route the write to the file mount so its own read-only semantics answer,
129
+ // rather than creating a run-state shadow copy at the same path.
130
+ const file = fileMount(target);
131
+ return file ? file.backend.write(file.key, content) : composite.write(target, content);
132
+ },
133
+ edit(filePath, oldString, newString, replaceAll) {
134
+ const target = canonical(filePath);
135
+ const file = fileMount(target);
136
+ return file
137
+ ? file.backend.edit(file.key, oldString, newString, replaceAll)
138
+ : composite.edit(target, oldString, newString, replaceAll);
139
+ },
140
+ };
141
+ return router;
142
+ }
143
+ /** Re-exported so callers can classify a path with the router's own rules. */
144
+ export { classifyWorkspacePath };
145
+ //# sourceMappingURL=workspace-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-router.js","sourceRoot":"","sources":["../../src/core/workspace-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import type { BackendProtocolV2, FileData, FileInfo } from "deepagents";
2
+ /**
3
+ * Single file-access layer for the runtime.
4
+ *
5
+ * Every read of a file in the agent workspace — machine config, system prompt,
6
+ * hook scripts, `archmax_run` sources, lifecycle artifacts — flows
7
+ * through here so it is served by the configured LangChain Deep Agents
8
+ * {@link BackendProtocolV2}. Swap the backend (filesystem, store, sandbox,
9
+ * remote) and the whole runtime follows, with no direct `fs` coupling.
10
+ * Deletion — the one operation the backend protocol does not model — is owned
11
+ * by the session store (`SessionStore.deleteSession`), not this layer.
12
+ */
13
+ export declare class Workspace {
14
+ private readonly backend;
15
+ constructor(backend: BackendProtocolV2);
16
+ readText(path: string): Promise<string | null>;
17
+ /**
18
+ * Write text to a workspace file through the backend. Parent directories are
19
+ * created by the backend. Throws if the backend reports a write error.
20
+ */
21
+ writeText(path: string, contents: string): Promise<void>;
22
+ /** Write a value as pretty-printed JSON through {@link writeText}. */
23
+ writeJson(path: string, value: unknown): Promise<void>;
24
+ /**
25
+ * Replace `oldString` with `newString` in an existing workspace file through
26
+ * the backend's `edit` operation. Used to update an already-written file (e.g.
27
+ * an approval request's frontmatter on decision) on a create-only backend, which
28
+ * refuses to overwrite. Throws if the backend reports an error.
29
+ */
30
+ editText(path: string, oldString: string, newString: string, replaceAll?: boolean): Promise<void>;
31
+ /** Backends throw on e.g. path traversal; treat any failure as "absent". */
32
+ private tryReadRaw;
33
+ readJson<T = unknown>(path: string): Promise<T | null>;
34
+ exists(path: string): Promise<boolean>;
35
+ /**
36
+ * Immediate children of a directory as {@link FileInfo} entries. A missing
37
+ * directory and an unreadable one both read as empty — which is what most
38
+ * callers want, and is wrong for anything replaying durable state: see
39
+ * {@link listDirStrict}.
40
+ */
41
+ listDir(path: string): Promise<FileInfo[]>;
42
+ /**
43
+ * {@link listDir}, but a backend that failed to answer throws instead of
44
+ * reading as an empty directory. For a caller that replays durable state, the
45
+ * difference is everything: a transient read error must not be indistinguishable
46
+ * from a session with no checkpoints, or the session silently forks (issue #27).
47
+ *
48
+ * A directory the backend reports as absent is still empty, not an error — a
49
+ * session's first turn has no `checkpoints/` folder yet.
50
+ */
51
+ listDirStrict(path: string): Promise<FileInfo[]>;
52
+ /**
53
+ * {@link readJson}, but distinguishes the three outcomes a durable replay has
54
+ * to tell apart: the file is absent (`null`), or it is there and unreadable —
55
+ * an unparseable or unfetchable checkpoint throws rather than being skipped.
56
+ */
57
+ readJsonStrict<T = unknown>(path: string): Promise<T | null>;
58
+ }
59
+ /** Strip leading slashes to get a workspace-relative path. */
60
+ export declare function normalizeRelPath(p: string): string;
61
+ /** A canonicalized workspace-relative path plus whether it escapes the root. */
62
+ export interface CanonicalRelPath {
63
+ /** The resolved relative path: `//` and `.` collapsed, `..` applied. */
64
+ path: string;
65
+ /** True when a `..` segment climbs above the workspace root. */
66
+ escapes: boolean;
67
+ }
68
+ /**
69
+ * Canonicalize a workspace-relative path to the single form the backend will
70
+ * resolve to: strip leading slashes, drop `.` and empty (`//`) segments, and
71
+ * apply `..` against the accumulated path. A `..` that would climb above the
72
+ * root is preserved as a leading `..` and flags `escapes`.
73
+ *
74
+ * Every path-governance decision (read-only zone, `forbid_paths`, scratchpad,
75
+ * `scratchpad/`) canonicalizes through here so none can be dodged with a
76
+ * `./`, `.//`, or `..` prefix: all three mechanisms see the same path the
77
+ * backend will act on.
78
+ */
79
+ export declare function canonicalizeRelPath(p: string): CanonicalRelPath;
80
+ /** Convert a relative or virtual path to the leading-slash form backends expect. */
81
+ export declare function toBackendPath(p: string): string;
82
+ /** Workspace-relative basename of a (possibly trailing-slash) directory path. */
83
+ export declare function dirName(path: string): string;
84
+ /** Decode {@link FileData} (v1 line array, v2 string, or binary) to text. */
85
+ export declare function fileDataToText(data: FileData): string | null;
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Single file-access layer for the runtime.
3
+ *
4
+ * Every read of a file in the agent workspace — machine config, system prompt,
5
+ * hook scripts, `archmax_run` sources, lifecycle artifacts — flows
6
+ * through here so it is served by the configured LangChain Deep Agents
7
+ * {@link BackendProtocolV2}. Swap the backend (filesystem, store, sandbox,
8
+ * remote) and the whole runtime follows, with no direct `fs` coupling.
9
+ * Deletion — the one operation the backend protocol does not model — is owned
10
+ * by the session store (`SessionStore.deleteSession`), not this layer.
11
+ */
12
+ export class Workspace {
13
+ backend;
14
+ constructor(backend) {
15
+ this.backend = backend;
16
+ }
17
+ async readText(path) {
18
+ const res = await this.tryReadRaw(path);
19
+ if (!res || res.error || !res.data)
20
+ return null;
21
+ return fileDataToText(res.data);
22
+ }
23
+ /**
24
+ * Write text to a workspace file through the backend. Parent directories are
25
+ * created by the backend. Throws if the backend reports a write error.
26
+ */
27
+ async writeText(path, contents) {
28
+ const res = await this.backend.write(toBackendPath(path), contents);
29
+ const error = res?.error;
30
+ if (error)
31
+ throw new Error(error);
32
+ }
33
+ /** Write a value as pretty-printed JSON through {@link writeText}. */
34
+ async writeJson(path, value) {
35
+ await this.writeText(path, `${JSON.stringify(value, null, 2)}\n`);
36
+ }
37
+ /**
38
+ * Replace `oldString` with `newString` in an existing workspace file through
39
+ * the backend's `edit` operation. Used to update an already-written file (e.g.
40
+ * an approval request's frontmatter on decision) on a create-only backend, which
41
+ * refuses to overwrite. Throws if the backend reports an error.
42
+ */
43
+ async editText(path, oldString, newString, replaceAll = false) {
44
+ const res = await this.backend.edit(toBackendPath(path), oldString, newString, replaceAll);
45
+ const error = res?.error;
46
+ if (error)
47
+ throw new Error(error);
48
+ }
49
+ /** Backends throw on e.g. path traversal; treat any failure as "absent". */
50
+ async tryReadRaw(path) {
51
+ try {
52
+ return await this.backend.readRaw(toBackendPath(path));
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ async readJson(path) {
59
+ const text = await this.readText(path);
60
+ if (text == null)
61
+ return null;
62
+ try {
63
+ return JSON.parse(text);
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
69
+ async exists(path) {
70
+ const res = await this.tryReadRaw(path);
71
+ return res != null && !res.error && res.data != null;
72
+ }
73
+ /**
74
+ * Immediate children of a directory as {@link FileInfo} entries. A missing
75
+ * directory and an unreadable one both read as empty — which is what most
76
+ * callers want, and is wrong for anything replaying durable state: see
77
+ * {@link listDirStrict}.
78
+ */
79
+ async listDir(path) {
80
+ try {
81
+ const res = await this.backend.ls(toBackendPath(path));
82
+ return res.error || !res.files ? [] : res.files;
83
+ }
84
+ catch {
85
+ return [];
86
+ }
87
+ }
88
+ /**
89
+ * {@link listDir}, but a backend that failed to answer throws instead of
90
+ * reading as an empty directory. For a caller that replays durable state, the
91
+ * difference is everything: a transient read error must not be indistinguishable
92
+ * from a session with no checkpoints, or the session silently forks (issue #27).
93
+ *
94
+ * A directory the backend reports as absent is still empty, not an error — a
95
+ * session's first turn has no `checkpoints/` folder yet.
96
+ */
97
+ async listDirStrict(path) {
98
+ const res = await this.backend.ls(toBackendPath(path));
99
+ if (res.error) {
100
+ if (isAbsentError(res.error))
101
+ return [];
102
+ throw new Error(`cannot list '${path}': ${res.error}`);
103
+ }
104
+ return res.files ?? [];
105
+ }
106
+ /**
107
+ * {@link readJson}, but distinguishes the three outcomes a durable replay has
108
+ * to tell apart: the file is absent (`null`), or it is there and unreadable —
109
+ * an unparseable or unfetchable checkpoint throws rather than being skipped.
110
+ */
111
+ async readJsonStrict(path) {
112
+ const res = await this.backend.readRaw(toBackendPath(path));
113
+ if (res.error) {
114
+ if (isAbsentError(res.error))
115
+ return null;
116
+ throw new Error(`cannot read '${path}': ${res.error}`);
117
+ }
118
+ if (!res.data)
119
+ return null;
120
+ const text = fileDataToText(res.data);
121
+ if (text == null)
122
+ throw new Error(`cannot read '${path}': its content is not decodable text`);
123
+ try {
124
+ return JSON.parse(text);
125
+ }
126
+ catch (err) {
127
+ throw new Error(`cannot parse '${path}' as JSON: ${err.message}`, { cause: err });
128
+ }
129
+ }
130
+ }
131
+ /**
132
+ * Whether a backend error says the path does not exist, as opposed to saying it
133
+ * could not be read. Backends phrase this themselves, so the test is on the
134
+ * wording every one of them uses.
135
+ */
136
+ function isAbsentError(error) {
137
+ return /not found|no such file|does not exist|missing|enoent/i.test(error);
138
+ }
139
+ /** Strip leading slashes to get a workspace-relative path. */
140
+ export function normalizeRelPath(p) {
141
+ return String(p).replace(/^\/+/, "");
142
+ }
143
+ /**
144
+ * Canonicalize a workspace-relative path to the single form the backend will
145
+ * resolve to: strip leading slashes, drop `.` and empty (`//`) segments, and
146
+ * apply `..` against the accumulated path. A `..` that would climb above the
147
+ * root is preserved as a leading `..` and flags `escapes`.
148
+ *
149
+ * Every path-governance decision (read-only zone, `forbid_paths`, scratchpad,
150
+ * `scratchpad/`) canonicalizes through here so none can be dodged with a
151
+ * `./`, `.//`, or `..` prefix: all three mechanisms see the same path the
152
+ * backend will act on.
153
+ */
154
+ export function canonicalizeRelPath(p) {
155
+ const out = [];
156
+ let escapes = false;
157
+ for (const seg of normalizeRelPath(String(p)).split("/")) {
158
+ if (seg === "" || seg === ".")
159
+ continue;
160
+ if (seg === "..") {
161
+ if (out.length > 0 && out[out.length - 1] !== "..") {
162
+ out.pop();
163
+ }
164
+ else {
165
+ out.push("..");
166
+ escapes = true;
167
+ }
168
+ continue;
169
+ }
170
+ out.push(seg);
171
+ }
172
+ return { path: out.join("/"), escapes };
173
+ }
174
+ /** Convert a relative or virtual path to the leading-slash form backends expect. */
175
+ export function toBackendPath(p) {
176
+ return `/${normalizeRelPath(p)}`;
177
+ }
178
+ /** Workspace-relative basename of a (possibly trailing-slash) directory path. */
179
+ export function dirName(path) {
180
+ return normalizeRelPath(path).replace(/\/+$/, "").split("/").pop() ?? "";
181
+ }
182
+ /** Decode {@link FileData} (v1 line array, v2 string, or binary) to text. */
183
+ export function fileDataToText(data) {
184
+ const content = data.content;
185
+ if (typeof content === "string")
186
+ return content;
187
+ if (Array.isArray(content))
188
+ return content.join("\n");
189
+ if (content instanceof Uint8Array)
190
+ return new TextDecoder().decode(content);
191
+ return null;
192
+ }
193
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/core/workspace.ts"],"names":[],"mappings":"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"}