@galaxyproject/orbit 0.0.0 → 0.9.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 (451) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/LICENSE +21 -0
  3. package/README.md +760 -5
  4. package/bin/legacy-mcp-config.js +363 -0
  5. package/bin/orbit.js +810 -0
  6. package/bin/pi-extension-path.d.ts +4 -0
  7. package/bin/pi-extension-path.js +44 -0
  8. package/bin/provider-auth.d.ts +22 -0
  9. package/bin/provider-auth.js +77 -0
  10. package/bin/thinking-pref.js +38 -0
  11. package/bin/update-check.d.ts +15 -0
  12. package/bin/update-check.js +137 -0
  13. package/extensions/cli-update/index.ts +32 -0
  14. package/extensions/orbit/activity-hooks.ts +141 -0
  15. package/extensions/orbit/activity.ts +116 -0
  16. package/extensions/orbit/agent-dir.ts +11 -0
  17. package/extensions/orbit/auto-resume.ts +352 -0
  18. package/extensions/orbit/config.ts +3 -0
  19. package/extensions/orbit/confusables.ts +1 -0
  20. package/extensions/orbit/context.ts +957 -0
  21. package/extensions/orbit/dashboard-commands.ts +191 -0
  22. package/extensions/orbit/dashboard-store.ts +473 -0
  23. package/extensions/orbit/dashboard-tools.ts +1185 -0
  24. package/extensions/orbit/empty-completion.ts +99 -0
  25. package/extensions/orbit/evidence-gate.ts +1276 -0
  26. package/extensions/orbit/evidence-override-command.ts +294 -0
  27. package/extensions/orbit/exec-guard/bash-risk.ts +1408 -0
  28. package/extensions/orbit/exec-guard/gate.ts +181 -0
  29. package/extensions/orbit/exec-guard/guardian-config.ts +54 -0
  30. package/extensions/orbit/exec-guard/index.ts +1 -0
  31. package/extensions/orbit/exec-guard/model-tier.ts +36 -0
  32. package/extensions/orbit/exec-guard/path-jail.ts +54 -0
  33. package/extensions/orbit/exec-guard/policy.ts +342 -0
  34. package/extensions/orbit/exec-guard/runtime-state.ts +15 -0
  35. package/extensions/orbit/exec-guard/sensitive-read.ts +525 -0
  36. package/extensions/orbit/exec-guard/types.ts +42 -0
  37. package/extensions/orbit/execution-commands.ts +134 -0
  38. package/extensions/orbit/feedback-command.ts +81 -0
  39. package/extensions/orbit/feedback.ts +96 -0
  40. package/extensions/orbit/galaxy-api.test.ts +122 -0
  41. package/extensions/orbit/galaxy-api.ts +606 -0
  42. package/extensions/orbit/galaxy-artifact-link-guidance.ts +5 -0
  43. package/extensions/orbit/galaxy-destructive-gate.ts +113 -0
  44. package/extensions/orbit/galaxy-enrich.ts +1108 -0
  45. package/extensions/orbit/galaxy-failure.ts +101 -0
  46. package/extensions/orbit/galaxy-fixture.ts +126 -0
  47. package/extensions/orbit/galaxy-history-guard.ts +233 -0
  48. package/extensions/orbit/galaxy-job-block.ts +347 -0
  49. package/extensions/orbit/galaxy-job-ops.ts +288 -0
  50. package/extensions/orbit/galaxy-live-source.ts +929 -0
  51. package/extensions/orbit/galaxy-markdown-adapter.ts +248 -0
  52. package/extensions/orbit/galaxy-op-policy.ts +332 -0
  53. package/extensions/orbit/galaxy-ops-tools.ts +326 -0
  54. package/extensions/orbit/galaxy-output-store.ts +80 -0
  55. package/extensions/orbit/galaxy-output.ts +346 -0
  56. package/extensions/orbit/galaxy-page-binding.ts +222 -0
  57. package/extensions/orbit/galaxy-page-markdown-guidance.ts +15 -0
  58. package/extensions/orbit/galaxy-page-ops.ts +159 -0
  59. package/extensions/orbit/galaxy-page-sync.test.ts +417 -0
  60. package/extensions/orbit/galaxy-page-sync.ts +318 -0
  61. package/extensions/orbit/galaxy-pages-api.ts +203 -0
  62. package/extensions/orbit/galaxy-pages-sync.ts +409 -0
  63. package/extensions/orbit/galaxy-poll-guard.ts +189 -0
  64. package/extensions/orbit/galaxy-poller.ts +706 -0
  65. package/extensions/orbit/galaxy-provenance.ts +623 -0
  66. package/extensions/orbit/galaxy-reconcile.ts +956 -0
  67. package/extensions/orbit/galaxy-recovery.ts +176 -0
  68. package/extensions/orbit/galaxy-repeat-guard.ts +55 -0
  69. package/extensions/orbit/galaxy-submission-capture.ts +707 -0
  70. package/extensions/orbit/galaxy-submission.ts +502 -0
  71. package/extensions/orbit/galaxy-tool-source.ts +78 -0
  72. package/extensions/orbit/galaxy-tool-wrap.ts +234 -0
  73. package/extensions/orbit/galaxy-udt-block.ts +127 -0
  74. package/extensions/orbit/galaxy-upload-tus.ts +334 -0
  75. package/extensions/orbit/galaxy-upload.ts +300 -0
  76. package/extensions/orbit/galaxy-version-capture.ts +65 -0
  77. package/extensions/orbit/git.ts +173 -0
  78. package/extensions/orbit/harness-block-fields.ts +597 -0
  79. package/extensions/orbit/index.ts +593 -0
  80. package/extensions/orbit/init-gate.ts +284 -0
  81. package/extensions/orbit/instructions-command.ts +136 -0
  82. package/extensions/orbit/invocation-failure-hint.ts +57 -0
  83. package/extensions/orbit/iwc-plan-check.ts +94 -0
  84. package/extensions/orbit/lesson-command.ts +303 -0
  85. package/extensions/orbit/lesson-hint.ts +245 -0
  86. package/extensions/orbit/lesson-nudge.ts +106 -0
  87. package/extensions/orbit/lessons/compose.ts +177 -0
  88. package/extensions/orbit/lessons/counters.ts +120 -0
  89. package/extensions/orbit/lessons/enabled.ts +116 -0
  90. package/extensions/orbit/lessons/matcher.ts +346 -0
  91. package/extensions/orbit/lessons/paths.ts +286 -0
  92. package/extensions/orbit/lessons/pi-event-contract.ts +105 -0
  93. package/extensions/orbit/lessons/propose-replay.ts +103 -0
  94. package/extensions/orbit/lessons/propose-tool.ts +222 -0
  95. package/extensions/orbit/lessons/propose.ts +502 -0
  96. package/extensions/orbit/lessons/replay.ts +89 -0
  97. package/extensions/orbit/lessons/reproduction-index.ts +83 -0
  98. package/extensions/orbit/lessons/search-tool.ts +99 -0
  99. package/extensions/orbit/lessons/search.ts +136 -0
  100. package/extensions/orbit/lessons/store.ts +415 -0
  101. package/extensions/orbit/lessons/text.ts +36 -0
  102. package/extensions/orbit/lessons/types.ts +69 -0
  103. package/extensions/orbit/lessons/user-dir.ts +24 -0
  104. package/extensions/orbit/lessons/user-lesson.ts +88 -0
  105. package/extensions/orbit/lessons/wrapper.ts +61 -0
  106. package/extensions/orbit/lessons-command.ts +147 -0
  107. package/extensions/orbit/local-exec.ts +39 -0
  108. package/extensions/orbit/mcp-output.ts +179 -0
  109. package/extensions/orbit/mcp-servers.test.ts +24 -0
  110. package/extensions/orbit/mcp-servers.ts +25 -0
  111. package/extensions/orbit/model-script.ts +351 -0
  112. package/extensions/orbit/notebook-anchors.ts +342 -0
  113. package/extensions/orbit/notebook-writer.ts +863 -0
  114. package/extensions/orbit/observation-allowlists.ts +1109 -0
  115. package/extensions/orbit/observation-replay.ts +148 -0
  116. package/extensions/orbit/observation-triggers.ts +563 -0
  117. package/extensions/orbit/observation-ui.ts +175 -0
  118. package/extensions/orbit/observations-command.ts +421 -0
  119. package/extensions/orbit/observations-config.ts +200 -0
  120. package/extensions/orbit/observations.ts +1381 -0
  121. package/extensions/orbit/profiles.ts +270 -0
  122. package/extensions/orbit/progress-updates.ts +95 -0
  123. package/extensions/orbit/proposal-commands.ts +882 -0
  124. package/extensions/orbit/provenance-fs-file.ts +59 -0
  125. package/extensions/orbit/provenance-fs.ts +32 -0
  126. package/extensions/orbit/provenance-memory-fs.ts +59 -0
  127. package/extensions/orbit/record-store-file.ts +177 -0
  128. package/extensions/orbit/record-store-page.ts +77 -0
  129. package/extensions/orbit/record-store-seam.ts +47 -0
  130. package/extensions/orbit/record-store.ts +149 -0
  131. package/extensions/orbit/registry-carrier.ts +107 -0
  132. package/extensions/orbit/registry-eligibility.ts +95 -0
  133. package/extensions/orbit/registry-evaluation.ts +403 -0
  134. package/extensions/orbit/registry-evaluator.ts +519 -0
  135. package/extensions/orbit/registry-import.ts +91 -0
  136. package/extensions/orbit/registry-lock.ts +221 -0
  137. package/extensions/orbit/registry-memory-fs.ts +42 -0
  138. package/extensions/orbit/registry-page-carrier.ts +103 -0
  139. package/extensions/orbit/registry-proposal.ts +1348 -0
  140. package/extensions/orbit/registry-runtime.ts +234 -0
  141. package/extensions/orbit/registry-schema.ts +735 -0
  142. package/extensions/orbit/registry-submitter.ts +59 -0
  143. package/extensions/orbit/registry-templates.ts +346 -0
  144. package/extensions/orbit/registry.ts +476 -0
  145. package/extensions/orbit/sandbox/index.ts +120 -0
  146. package/extensions/orbit/sandbox/sandbox-bash.ts +93 -0
  147. package/extensions/orbit/sandbox/sandbox-config.ts +87 -0
  148. package/extensions/orbit/sandbox/sandbox-init-message.ts +28 -0
  149. package/extensions/orbit/secret-redaction.ts +247 -0
  150. package/extensions/orbit/session-index/cwd.ts +18 -0
  151. package/extensions/orbit/session-index/db.ts +56 -0
  152. package/extensions/orbit/session-index/indexer.ts +154 -0
  153. package/extensions/orbit/session-index/is-enabled.ts +17 -0
  154. package/extensions/orbit/session-index/parse.ts +254 -0
  155. package/extensions/orbit/session-index/query.ts +209 -0
  156. package/extensions/orbit/session-index/schema.ts +72 -0
  157. package/extensions/orbit/session-index/tools.ts +152 -0
  158. package/extensions/orbit/session-lifecycle.ts +321 -0
  159. package/extensions/orbit/skill-triggers.ts +159 -0
  160. package/extensions/orbit/skills-command.ts +48 -0
  161. package/extensions/orbit/skills-discovery.ts +435 -0
  162. package/extensions/orbit/skills.ts +84 -0
  163. package/extensions/orbit/sra-import-gate.ts +77 -0
  164. package/extensions/orbit/state.ts +265 -0
  165. package/extensions/orbit/submission-replay.ts +147 -0
  166. package/extensions/orbit/sync-command.ts +157 -0
  167. package/extensions/orbit/teams/critic-parser.ts +93 -0
  168. package/extensions/orbit/teams/dispatcher.ts +210 -0
  169. package/extensions/orbit/teams/is-enabled.ts +22 -0
  170. package/extensions/orbit/teams/tool.ts +187 -0
  171. package/extensions/orbit/teams/types.ts +57 -0
  172. package/extensions/orbit/teams/validate.ts +42 -0
  173. package/extensions/orbit/tester-id-command.ts +133 -0
  174. package/extensions/orbit/tools-sync.ts +279 -0
  175. package/extensions/orbit/tools.ts +1300 -0
  176. package/extensions/orbit/types.ts +41 -0
  177. package/extensions/orbit/ui-bridge.ts +55 -0
  178. package/extensions/orbit/ulid.ts +60 -0
  179. package/extensions/orbit/user-instructions.ts +388 -0
  180. package/extensions/orbit/vendor/skills/_catalog.json +68 -0
  181. package/extensions/orbit/vendor/skills/_manifest.json +1106 -0
  182. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/SKILL.md +112 -0
  183. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_provenance.json +218 -0
  184. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_required_tools.json +33 -0
  185. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/_verify.json +4 -0
  186. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/add.json +50 -0
  187. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-extract.json +51 -0
  188. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-next-step.json +42 -0
  189. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/draft-validate.json +140 -0
  190. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/cli/list.json +32 -0
  191. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/galaxy-tool-job-failure-reference.md +137 -0
  192. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/notes/open-requirements-ledger.md +173 -0
  193. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-tool-summary.schema.json +175 -0
  194. package/extensions/orbit/vendor/skills/advance-galaxy-draft-step/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
  195. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/SKILL.md +82 -0
  196. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_provenance.json +133 -0
  197. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_required_tools.json +16 -0
  198. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/_verify.json +4 -0
  199. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/cli/draft-validate.json +140 -0
  200. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/galaxy-workflow-draft-format.md +135 -0
  201. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
  202. package/extensions/orbit/vendor/skills/apply-galaxy-workflow-changeset/references/schemas/galaxy-workflow-draft.schema.json +2727 -0
  203. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/SKILL.md +84 -0
  204. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_provenance.json +166 -0
  205. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/_verify.json +29 -0
  206. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/galaxy-workflow-testability-design.md +136 -0
  207. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  208. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/iwc-test-data-conventions.md +308 -0
  209. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-asserts-idioms.md +246 -0
  210. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/notes/planemo-workflow-test-architecture.md +151 -0
  211. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
  212. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  213. package/extensions/orbit/vendor/skills/changeset-to-galaxy-test-plan/references/schemas/tests-format.schema.json +7328 -0
  214. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/SKILL.md +127 -0
  215. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_provenance.json +198 -0
  216. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_required_tools.json +16 -0
  217. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/_verify.json +4 -0
  218. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/cli/convert.json +123 -0
  219. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/galaxy-data-flow-draft-contract.md +129 -0
  220. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  221. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/iwc-test-data-conventions.md +308 -0
  222. package/extensions/orbit/vendor/skills/compare-against-iwc-exemplar/references/notes/open-requirements-ledger.md +173 -0
  223. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/SKILL.md +73 -0
  224. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_provenance.json +160 -0
  225. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/_verify.json +4 -0
  226. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.md +43 -0
  227. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-collection-semantics.yml +1250 -0
  228. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-tool-job-failure-reference.md +137 -0
  229. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  230. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  231. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/nextflow-operators-to-galaxy-collection-recipes.md +98 -0
  232. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-asserts-idioms.md +246 -0
  233. package/extensions/orbit/vendor/skills/debug-galaxy-workflow-output/references/notes/planemo-workflow-test-architecture.md +151 -0
  234. package/extensions/orbit/vendor/skills/discover-shed-tool/SKILL.md +174 -0
  235. package/extensions/orbit/vendor/skills/discover-shed-tool/_provenance.json +130 -0
  236. package/extensions/orbit/vendor/skills/discover-shed-tool/_required_tools.json +18 -0
  237. package/extensions/orbit/vendor/skills/discover-shed-tool/_verify.json +17 -0
  238. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-revisions.json +48 -0
  239. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-search.json +95 -0
  240. package/extensions/orbit/vendor/skills/discover-shed-tool/references/cli/tool-versions.json +39 -0
  241. package/extensions/orbit/vendor/skills/discover-shed-tool/references/notes/component-tool-shed-search.md +230 -0
  242. package/extensions/orbit/vendor/skills/discover-shed-tool/references/schemas/galaxy-tool-discovery.schema.json +231 -0
  243. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/SKILL.md +93 -0
  244. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_provenance.json +201 -0
  245. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_required_tools.json +28 -0
  246. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/_verify.json +17 -0
  247. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/planemo.md +44 -0
  248. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/cli/validate-tests.json +40 -0
  249. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/galaxy-workflow-testability-design.md +136 -0
  250. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-shortcuts-anti-patterns.md +357 -0
  251. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/iwc-test-data-conventions.md +308 -0
  252. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
  253. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
  254. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/galaxy-workflow-test-plan.schema.json +552 -0
  255. package/extensions/orbit/vendor/skills/implement-galaxy-workflow-test/references/schemas/tests-format.schema.json +7328 -0
  256. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/SKILL.md +81 -0
  257. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_provenance.json +93 -0
  258. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/_verify.json +17 -0
  259. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/notes/open-requirements-ledger.md +173 -0
  260. package/extensions/orbit/vendor/skills/interview-to-galaxy-workflow-changeset/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  261. package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/SKILL.md +81 -0
  262. package/extensions/orbit/vendor/skills/pipeline-update-interview-to-galaxy/_assembly.json +23 -0
  263. package/extensions/orbit/vendor/skills/run-workflow-test/SKILL.md +79 -0
  264. package/extensions/orbit/vendor/skills/run-workflow-test/_provenance.json +125 -0
  265. package/extensions/orbit/vendor/skills/run-workflow-test/_required_tools.json +28 -0
  266. package/extensions/orbit/vendor/skills/run-workflow-test/_verify.json +4 -0
  267. package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/planemo.md +44 -0
  268. package/extensions/orbit/vendor/skills/run-workflow-test/references/cli/validate-tests.json +40 -0
  269. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  270. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-asserts-idioms.md +246 -0
  271. package/extensions/orbit/vendor/skills/run-workflow-test/references/notes/planemo-workflow-test-architecture.md +151 -0
  272. package/extensions/orbit/vendor/skills/run-workflow-test/references/schemas/tests-format.schema.json +7328 -0
  273. package/extensions/orbit/vendor/skills/skills/LICENSE +21 -0
  274. package/extensions/orbit/vendor/skills/skills/collection-manipulation/README.md +39 -0
  275. package/extensions/orbit/vendor/skills/skills/collection-manipulation/SKILL.md +892 -0
  276. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/api-patterns.md +927 -0
  277. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/apply-rules.md +1482 -0
  278. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/test-patterns.md +996 -0
  279. package/extensions/orbit/vendor/skills/skills/collection-manipulation/references/tools.md +609 -0
  280. package/extensions/orbit/vendor/skills/skills/galaxy-data-libraries/SKILL.md +170 -0
  281. package/extensions/orbit/vendor/skills/skills/galaxy-integration/README.md +162 -0
  282. package/extensions/orbit/vendor/skills/skills/galaxy-integration/SKILL.md +99 -0
  283. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/README.md +119 -0
  284. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/tool-checking.md +419 -0
  285. package/extensions/orbit/vendor/skills/skills/galaxy-integration/examples/workflow-testing.md +617 -0
  286. package/extensions/orbit/vendor/skills/skills/galaxy-integration/galaxy-integration.md +614 -0
  287. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/SKILL.md +144 -0
  288. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/average_col3.ipynb +68 -0
  289. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/extract_sample_metadata.ipynb +190 -0
  290. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/variant_annotation.ipynb +816 -0
  291. package/extensions/orbit/vendor/skills/skills/galaxy-integration/jupyterlite/examples/vcp_variant_map.ipynb +443 -0
  292. package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/README.md +165 -0
  293. package/extensions/orbit/vendor/skills/skills/galaxy-integration/scripts/galaxy_tool_checker.py +521 -0
  294. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/SKILL.md +128 -0
  295. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/gotchas.md +135 -0
  296. package/extensions/orbit/vendor/skills/skills/galaxy-mcp-reference/history-access.md +132 -0
  297. package/extensions/orbit/vendor/skills/skills/reproduciblify/SKILL.md +146 -0
  298. package/extensions/orbit/vendor/skills/skills/reproduciblify/references/directives.yml +496 -0
  299. package/extensions/orbit/vendor/skills/skills/udt-authoring/SKILL.md +245 -0
  300. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/01-minimal-echo.yml +27 -0
  301. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/02-single-data-in-out.yml +27 -0
  302. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/03-multiple-data-js.yml +28 -0
  303. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/04-select-integer-boolean.yml +41 -0
  304. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/05-resource-requirements.yml +25 -0
  305. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/06-biocontainer-tool.yml +38 -0
  306. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/07-inline-python-script.yml +56 -0
  307. package/extensions/orbit/vendor/skills/skills/udt-authoring/examples/08-configfile-script.yml +74 -0
  308. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/common-mistakes.md +76 -0
  309. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/schema-reference.md +155 -0
  310. package/extensions/orbit/vendor/skills/skills/udt-authoring/references/templating.md +196 -0
  311. package/extensions/orbit/vendor/skills/skills/udt-authoring/scripts/validate.py +109 -0
  312. package/extensions/orbit/vendor/skills/skills/workflow-reports/README.md +71 -0
  313. package/extensions/orbit/vendor/skills/skills/workflow-reports/SKILL.md +190 -0
  314. package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/histology-staining.md +145 -0
  315. package/extensions/orbit/vendor/skills/skills/workflow-reports/examples/tissue-microarray-analysis.md +176 -0
  316. package/extensions/orbit/vendor/skills/skills/workflow-reports/references/directives.md +415 -0
  317. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/SKILL.md +98 -0
  318. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_provenance.json +93 -0
  319. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_required_tools.json +28 -0
  320. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/_verify.json +17 -0
  321. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/convert.json +123 -0
  322. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/foundry.md +25 -0
  323. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/cli/validate.json +142 -0
  324. package/extensions/orbit/vendor/skills/summarize-galaxy-workflow/references/schemas/summary-galaxy-workflow.schema.json +687 -0
  325. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/SKILL.md +74 -0
  326. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_provenance.json +71 -0
  327. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_required_tools.json +16 -0
  328. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/_verify.json +4 -0
  329. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/cli/validate.json +142 -0
  330. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-invocation-failure-reference.md +138 -0
  331. package/extensions/orbit/vendor/skills/validate-galaxy-workflow/references/notes/galaxy-workflow-testability-design.md +136 -0
  332. package/extensions/orbit/vendor-skills.ts +283 -0
  333. package/extensions/orbit/workspace-state-dir.ts +46 -0
  334. package/extensions/orbit-handoff/index.ts +73 -0
  335. package/extensions/orbit-handoff/orbit-launcher.ts +142 -0
  336. package/extensions/whats-new/index.ts +98 -0
  337. package/lessons/LICENSE +17 -0
  338. package/lessons/README.md +117 -0
  339. package/lessons/SCHEMA.md +187 -0
  340. package/lessons/build-snapshot.mjs +311 -0
  341. package/lessons/data/downloaded-file-is-not-what-its-extension-says.md +61 -0
  342. package/lessons/galaxy-api/403-history-is-a-hard-stop.md +57 -0
  343. package/lessons/galaxy-api/collection-into-single-dataset-input.md +61 -0
  344. package/lessons/galaxy-api/connectedvalue-in-command-line.md +62 -0
  345. package/lessons/galaxy-api/hid-is-not-an-id.md +59 -0
  346. package/lessons/galaxy-api/invoke-workflow-inputs-not-params.md +60 -0
  347. package/lessons/galaxy-api/repeat-param-pipe-keys.md +63 -0
  348. package/lessons/galaxy-api/run-tool-returns-on-submit.md +61 -0
  349. package/lessons/galaxy-tools/reference-index-not-on-server.md +62 -0
  350. package/lessons/log.md +42 -0
  351. package/lessons/reproduction/input-population-mismatch.md +59 -0
  352. package/lessons/reproduction/methods-text-vs-executed-parameters.md +62 -0
  353. package/lessons/snapshot.json +1004 -0
  354. package/lessons/stats/de-contrast-direction-and-sample-labels.md +63 -0
  355. package/lessons/stats/na-coerced-to-zero-in-filters.md +59 -0
  356. package/lessons/validate.mjs +1219 -0
  357. package/package.json +103 -5
  358. package/shared/agent-prompt.d.ts +8 -0
  359. package/shared/agent-prompt.js +15 -0
  360. package/shared/approval-prompt.d.ts +4 -0
  361. package/shared/approval-prompt.js +61 -0
  362. package/shared/brain-env.d.ts +14 -0
  363. package/shared/brain-env.js +108 -0
  364. package/shared/brain-exit.d.ts +20 -0
  365. package/shared/brain-exit.js +149 -0
  366. package/shared/capability-profile.d.ts +16 -0
  367. package/shared/capability-profile.js +75 -0
  368. package/shared/config-source.d.ts +13 -0
  369. package/shared/config-source.js +17 -0
  370. package/shared/confusables.d.ts +3 -0
  371. package/shared/confusables.js +93 -0
  372. package/shared/custom-provider.d.ts +45 -0
  373. package/shared/custom-provider.js +169 -0
  374. package/shared/dashboard-contract.d.ts +123 -0
  375. package/shared/dashboard-contract.js +560 -0
  376. package/shared/dashboard-layout-store.d.ts +44 -0
  377. package/shared/dashboard-layout-store.js +281 -0
  378. package/shared/feedback-contract.d.ts +61 -0
  379. package/shared/feedback-contract.js +146 -0
  380. package/shared/galaxy-artifact-links.d.ts +30 -0
  381. package/shared/galaxy-artifact-links.js +166 -0
  382. package/shared/galaxy-credentials.d.ts +26 -0
  383. package/shared/galaxy-credentials.js +71 -0
  384. package/shared/galaxy-destructive.d.ts +21 -0
  385. package/shared/galaxy-destructive.js +269 -0
  386. package/shared/galaxy-guidance.d.ts +2 -0
  387. package/shared/galaxy-guidance.js +53 -0
  388. package/shared/galaxy-live-contract.d.ts +92 -0
  389. package/shared/galaxy-live-contract.js +180 -0
  390. package/shared/galaxy-page-cells.d.ts +2 -0
  391. package/shared/galaxy-page-cells.js +22 -0
  392. package/shared/galaxy-tool-family.d.ts +5 -0
  393. package/shared/galaxy-tool-family.js +27 -0
  394. package/shared/galaxy-url.d.ts +1 -0
  395. package/shared/galaxy-url.js +48 -0
  396. package/shared/gtn.d.ts +31 -0
  397. package/shared/gtn.js +253 -0
  398. package/shared/handled-prompt.d.ts +3 -0
  399. package/shared/handled-prompt.js +26 -0
  400. package/shared/known-provider.d.ts +11 -0
  401. package/shared/known-provider.js +89 -0
  402. package/shared/lesson-hint-marker.d.ts +7 -0
  403. package/shared/lesson-hint-marker.js +32 -0
  404. package/shared/lesson-rules.d.ts +150 -0
  405. package/shared/lesson-rules.js +203 -0
  406. package/shared/malformed-object-ids.d.ts +1 -0
  407. package/shared/malformed-object-ids.js +37 -0
  408. package/shared/markdown-sections.d.ts +10 -0
  409. package/shared/markdown-sections.js +118 -0
  410. package/shared/notebook-fences.d.ts +12 -0
  411. package/shared/notebook-fences.js +53 -0
  412. package/shared/observation-contract.d.ts +91 -0
  413. package/shared/observation-contract.js +544 -0
  414. package/shared/orbit-config.d.ts +226 -0
  415. package/shared/orbit-config.js +189 -0
  416. package/shared/orbit-env.d.ts +13 -0
  417. package/shared/orbit-env.js +124 -0
  418. package/shared/orbit-shell-contract.d.ts +74 -0
  419. package/shared/orbit-shell-contract.js +30 -0
  420. package/shared/page-content-hash.d.ts +1 -0
  421. package/shared/page-content-hash.js +13 -0
  422. package/shared/pi-default-model.d.ts +7 -0
  423. package/shared/pi-default-model.js +41 -0
  424. package/shared/prompt-blocks.d.ts +87 -0
  425. package/shared/prompt-blocks.js +898 -0
  426. package/shared/provider-auth-caps.d.ts +22 -0
  427. package/shared/provider-auth-caps.js +57 -0
  428. package/shared/random.d.ts +2 -0
  429. package/shared/random.js +15 -0
  430. package/shared/record-excerpt.d.ts +4 -0
  431. package/shared/record-excerpt.js +16 -0
  432. package/shared/redirect-guard.d.ts +36 -0
  433. package/shared/redirect-guard.js +235 -0
  434. package/shared/skills-pin.d.ts +8 -0
  435. package/shared/skills-pin.js +9 -0
  436. package/shared/skills-router.d.ts +17 -0
  437. package/shared/skills-router.js +63 -0
  438. package/shared/sra-import.d.ts +34 -0
  439. package/shared/sra-import.js +206 -0
  440. package/shared/state-dir.d.ts +21 -0
  441. package/shared/state-dir.js +240 -0
  442. package/shared/team-dispatch-contract.d.ts +28 -0
  443. package/shared/team-dispatch-contract.js +1 -0
  444. package/shared/truncate-middle.d.ts +11 -0
  445. package/shared/truncate-middle.js +68 -0
  446. package/shared/version-compare.d.ts +10 -0
  447. package/shared/version-compare.js +74 -0
  448. package/shared/whats-new.d.ts +31 -0
  449. package/shared/whats-new.js +83 -0
  450. package/shared/wsl.d.ts +10 -0
  451. package/shared/wsl.js +24 -0
@@ -0,0 +1,15 @@
1
+ // Set by the bash sandbox layer when the OS sandbox is actually live for bash
2
+ // (false on unsupported platforms or a failed init). Lives in exec-guard, the
3
+ // lower layer, so the gate can query it without importing upward into the sandbox
4
+ // module. Layer 1 (write confinement) does NOT relax anything off this flag; it is
5
+ // kept here as the seam a future sound auto-allow (contained, recoverable
6
+ // unknown-bash) will read.
7
+ let sandboxActive = false;
8
+
9
+ export function setSandboxActive(active: boolean): void {
10
+ sandboxActive = active;
11
+ }
12
+
13
+ export function isSandboxActive(): boolean {
14
+ return sandboxActive;
15
+ }
@@ -0,0 +1,525 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { WORKSPACE_STATE_DIR_NAMES } from "../workspace-state-dir";
4
+ import { piAgentDir } from "../agent-dir";
5
+
6
+ // Directories under $HOME that hold credentials/secrets.
7
+ const SENSITIVE_HOME_DIRS = [
8
+ ".ssh",
9
+ ".aws",
10
+ ".gnupg",
11
+ ".config/gcloud",
12
+ ".kube",
13
+ ".docker",
14
+ "Library/Keychains",
15
+ ];
16
+ // Exact files under $HOME.
17
+ // Both brain config locations: a newer release may have copied the config
18
+ // into ~/.orbit, and this one reads it from there when it exists.
19
+ //
20
+ // The observation files are here for the same reason config.json is. The
21
+ // token store holds the retract tokens the intake route accepts as proof of
22
+ // ownership, and the outbox holds the install token that ties rows together --
23
+ // neither belongs in a model request. The sent log carries neither token, but
24
+ // it is the user's record of what they reported and is read through
25
+ // /observations, not by the agent.
26
+ const SENSITIVE_HOME_FILES = [
27
+ ".netrc",
28
+ ".loom/config.json",
29
+ ".orbit/config.json",
30
+ ".loom/observations-tokens.json",
31
+ ".orbit/observations-tokens.json",
32
+ ".loom/observations-outbox.jsonl",
33
+ ".orbit/observations-outbox.jsonl",
34
+ ".loom/observations-sent.jsonl",
35
+ ".orbit/observations-sent.jsonl",
36
+ ".pgpass",
37
+ ".npmrc",
38
+ ];
39
+ // Files inside pi's agent dir that hold live credentials. auth.json is pi's
40
+ // CredentialStore -- an api-key `key`, or an OAuth access+refresh pair; mcp.json
41
+ // and galaxy-profiles.json carry Galaxy keys. These want the floor more than
42
+ // the config.json entries above, not less: those are safeStorage blobs, but pi
43
+ // reads these directly and refreshes auth.json in place (app/src/main/
44
+ // oauth-handler.ts), so Orbit cannot encrypt them and this is the only
45
+ // protection they get. Listed separately from SENSITIVE_HOME_FILES because the
46
+ // whole directory relocates with PI_CODING_AGENT_DIR and is then not under
47
+ // $HOME at all. models.json holds the env var NAME rather than the secret, and
48
+ // models-store.json is a refreshed provider catalog, so both stay readable.
49
+ const AGENT_DIR_CREDENTIAL_FILES = ["auth.json", "mcp.json", "galaxy-profiles.json"];
50
+ // Basename / extension patterns sensitive anywhere.
51
+ const SENSITIVE_BASENAME =
52
+ /^(\.env(\..+)?|id_rsa|id_ed25519|id_ecdsa|.*\.pem|.*\.key|.*\.keychain(-db)?|credentials)$/i;
53
+
54
+ function within(abs: string, dir: string): boolean {
55
+ const rel = path.relative(dir, abs);
56
+ return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
57
+ }
58
+
59
+ /**
60
+ * `within`, case-folded. Only the credential-store lists use it.
61
+ *
62
+ * macOS is case-insensitive and its realpath does not normalize case, so
63
+ * `Library/Keychains` and `library/keychains` name one directory that an
64
+ * exact-case list only half-covers -- `library/keychains/user.kb` walked
65
+ * straight past this check. Folding can over-match a literally lowercase
66
+ * `library/keychains` on Linux, which errs toward refusing a read, and that is
67
+ * the safe direction for a list whose whole purpose is credential stores.
68
+ *
69
+ * Deliberately NOT used by the write-protection carve-out below: there a match
70
+ * means "this is an analysis workspace, so allow the write", and folding would
71
+ * widen an exemption rather than a refusal.
72
+ */
73
+ function withinFolded(abs: string, dir: string): boolean {
74
+ return within(abs.toLowerCase(), dir.toLowerCase());
75
+ }
76
+
77
+ // Dedicated credential stores: the home-relative dirs and exact files above
78
+ // that exist solely to hold secrets. The agent has no legitimate reason to read
79
+ // their CONTENTS, so reads are denied for every model tier (not just downgraded
80
+ // to an ask). This is the floor that closes #183 -- ~/.orbit/config.json is a
81
+ // store. The basename patterns (.env, *.pem, *.key, ...) are deliberately NOT
82
+ // stores: those can be project fixtures, so they keep the ask/deny-by-tier path.
83
+ // `agentDir` is injected so tests can relocate the store the same way
84
+ // PI_CODING_AGENT_DIR does in a real run; the default resolves it exactly as
85
+ // the rest of Orbit does.
86
+ export function isCredentialStore(
87
+ absPath: string,
88
+ home: string,
89
+ agentDir: string = piAgentDir(),
90
+ ): boolean {
91
+ const norm = path.normalize(absPath);
92
+ for (const d of SENSITIVE_HOME_DIRS) if (withinFolded(norm, path.join(home, d))) return true;
93
+ // Also as realpaths: callers compare resolved targets, so a config.json that
94
+ // is itself a symlink into the workspace would otherwise read as a plain
95
+ // workspace file.
96
+ return credentialFileCandidates(home, agentDir).has(norm.toLowerCase());
97
+ }
98
+
99
+ interface CandidateSnapshot {
100
+ candidates: Set<string>;
101
+ watched: Map<string, DirSignature>;
102
+ // Each symlink the walk followed, signed as the link itself.
103
+ links: Map<string, DirSignature>;
104
+ // False while any watched dir changed too recently to trust; see
105
+ // RACY_WINDOW_MS.
106
+ settled: boolean;
107
+ }
108
+
109
+ interface DirSignature {
110
+ key: string;
111
+ changedAt: number;
112
+ }
113
+
114
+ const candidateCache = new Map<string, CandidateSnapshot>();
115
+ const CANDIDATE_CACHE_LIMIT = 16;
116
+
117
+ // A change in the same timestamp tick as one a snapshot already saw leaves the
118
+ // stamps unchanged (Linux stamps from a coarse jiffy clock, HFS+ to the
119
+ // second), so a snapshot taken within this long of a watched dir changing is
120
+ // rebuilt on the next call instead of trusted. The same window catches a
121
+ // change that lands in a resolved dir between resolving it and statting it.
122
+ // Same idea as git's racy-index check.
123
+ const RACY_WINDOW_MS = 1000;
124
+
125
+ /**
126
+ * Every spelling of every credential file, lexical and resolved, lowercased.
127
+ *
128
+ * Every file read and every directory listing entry on the web surface comes
129
+ * through here, and resolving each file costs one or two realpath walks --
130
+ * slow enough on Windows to matter -- so the set is cached per (home,
131
+ * agentDir). The cache is keyed on an lstat of every directory whose entries
132
+ * the resolution depended on: each one a candidate's parent is walked through
133
+ * component by component, including the dir that holds each symlink along the
134
+ * way and every dir that link's target passes through in turn (see
135
+ * watchResolution). What a candidate resolves to can only change when an
136
+ * entry in one of those dirs is created, removed, renamed or replaced, and
137
+ * each of those rewrites that dir -- so a symlink planted at
138
+ * `~/.orbit/config.json`, a renamed ancestor relinked to its old name, or a
139
+ * link halfway down the chain re-pointed somewhere else all show up on the
140
+ * very next call. ctime is in the signature because mtime alone can be put
141
+ * back with `touch -r`, and no ordinary file call can set ctime.
142
+ *
143
+ * A settled snapshot never re-checks its own age, so a clock set backwards
144
+ * far enough to reproduce an old mtime:ctime:ino tuple would go unnoticed.
145
+ * That's accepted: whoever can roll back the clock is outside what this
146
+ * guards against, and the racy window is only about time moving forward.
147
+ */
148
+ function credentialFileCandidates(home: string, agentDir: string): Set<string> {
149
+ // No home: the lexical relative paths, exactly as before. They resolve
150
+ // against the cwd, so there's nothing stable to cache them under.
151
+ if (!home) {
152
+ const lexical = SENSITIVE_HOME_FILES.map((f) => path.join(home, f));
153
+ const resolvedParents = new Map<string, ResolvedDir>();
154
+ for (const f of AGENT_DIR_CREDENTIAL_FILES) {
155
+ const p = path.join(agentDir, f);
156
+ lexical.push(...withRealpath(p, resolvedParents, isSymlink(p)));
157
+ }
158
+ return new Set(lexical.map((c) => c.toLowerCase()));
159
+ }
160
+
161
+ // Keyed on the absolute dirs: PI_CODING_AGENT_DIR may be relative, and a
162
+ // snapshot of a relative dir would outlive a chdir. The candidates keep the
163
+ // spellings as given too, since on Windows resolving a drive-less home
164
+ // prepends the cwd's drive and callers may still pass the drive-less form.
165
+ const absHome = path.resolve(home);
166
+ const absAgentDir = path.resolve(agentDir);
167
+ const key = JSON.stringify([absHome, absAgentDir]);
168
+ const cached = candidateCache.get(key);
169
+ if (cached?.settled && signaturesMatch(cached.watched) && signaturesMatch(cached.links)) {
170
+ return cached.candidates;
171
+ }
172
+
173
+ const builtAt = Date.now();
174
+ const files = [
175
+ ...SENSITIVE_HOME_FILES.map((f) => path.join(home, f)),
176
+ ...AGENT_DIR_CREDENTIAL_FILES.map((f) => path.join(agentDir, f)),
177
+ ];
178
+ const candidates = new Set<string>();
179
+ if (absHome !== home) for (const f of SENSITIVE_HOME_FILES) addFolded(candidates, absHome, f);
180
+ if (absAgentDir !== agentDir) {
181
+ for (const f of AGENT_DIR_CREDENTIAL_FILES) addFolded(candidates, absAgentDir, f);
182
+ }
183
+ // Walk (and so sign) every dir BEFORE realpath resolves it, so a change
184
+ // that lands mid-build leaves a stale signature behind and forces the next
185
+ // call to rebuild.
186
+ const walk: WalkState = { watched: new Map(), links: new Map(), targets: new Map() };
187
+ const parents = new Map<string, Walk>();
188
+ for (const f of files) {
189
+ const dir = path.dirname(f);
190
+ if (!parents.has(dir)) parents.set(dir, watchResolution(dir, walk));
191
+ }
192
+ const { watched, links } = walk;
193
+ const resolvedParents = new Map<string, ResolvedDir>();
194
+ let sawLink = false;
195
+ for (const f of files) {
196
+ const link = isSymlink(f);
197
+ if (link) sawLink = true;
198
+ for (const c of withRealpath(f, resolvedParents, link, parents)) {
199
+ candidates.add(c.toLowerCase());
200
+ }
201
+ }
202
+ // realpath decides the spellings, since that's what callers compare against;
203
+ // the walk only decides what to watch. If it disagrees with fs.realpathSync
204
+ // -- a race, or some platform quirk the walk doesn't model -- the watched
205
+ // set may be the wrong one, so don't trust it.
206
+ //
207
+ //
208
+ // The native one is compared too, except that an 8.3 short name the walk
209
+ // kept (`RUNNER~1`) may come back expanded: which long name it stands for is
210
+ // an entry in a dir the walk already signed, so it can't change unseen, and
211
+ // without this every home under a short-name tmpdir rebuilt on every call.
212
+ // A subst or mapped drive coming back as its target is still a mismatch,
213
+ // since the drive mapping is in no dir the walk can sign.
214
+ let walksAgree = true;
215
+ for (const [dir, w] of parents) {
216
+ const r = resolvedParents.get(dir);
217
+ if (!w.complete || w.real !== (r?.js ?? null)) walksAgree = false;
218
+ else if (!sameButShortNames(w.real, r?.native ?? null)) walksAgree = false;
219
+ }
220
+ // A credential file that is itself a symlink resolves through its target's
221
+ // dirs, and a dangling one starts resolving the moment its target is
222
+ // created, so that snapshot is never trusted: rare enough that paying the
223
+ // full walk on every call is fine.
224
+ const settled =
225
+ walksAgree &&
226
+ !sawLink &&
227
+ [...watched.values()].every((sig) => sig.changedAt < builtAt - RACY_WINDOW_MS);
228
+
229
+ if (candidateCache.size >= CANDIDATE_CACHE_LIMIT && !candidateCache.has(key)) {
230
+ candidateCache.clear();
231
+ }
232
+ candidateCache.set(key, { candidates, watched, links, settled });
233
+ return candidates;
234
+ }
235
+
236
+ // Case-folded equality, letting a component the walk kept as an 8.3 short
237
+ // name (`~` and a digit) stand for whatever long name sits in that position.
238
+ function sameButShortNames(walked: string | null, native: string | null): boolean {
239
+ if (walked === null || native === null) return walked === native;
240
+ const a = walked.toLowerCase();
241
+ const b = native.toLowerCase();
242
+ if (a === b) return true;
243
+ if (process.platform !== "win32") return false;
244
+ const as = a.split(path.sep);
245
+ const bs = b.split(path.sep);
246
+ if (as.length !== bs.length || as[0] !== bs[0]) return false;
247
+ return as.every((c, i) => c === bs[i] || /~\d/.test(c));
248
+ }
249
+
250
+ function addFolded(set: Set<string>, dir: string, file: string): void {
251
+ set.add(path.join(dir, file).toLowerCase());
252
+ }
253
+
254
+ interface Walk {
255
+ // False when the walk hit something it can't promise to notice changing.
256
+ complete: boolean;
257
+ // Where the dir resolved to, or null when it doesn't exist (yet).
258
+ real: string | null;
259
+ }
260
+
261
+ interface WalkState {
262
+ // Every dir whose entries a resolution read. Only dirs go in here.
263
+ watched: Map<string, DirSignature>;
264
+ links: Map<string, DirSignature>;
265
+ // readlink results, so links shared by several credential dirs (macOS's
266
+ // /var, say) are read once per build.
267
+ targets: Map<string, string>;
268
+ }
269
+
270
+ // At least what any of our kernels allows in one lookup (Linux 40, macOS 32).
271
+ // A chain realpath gives up on but the walk finishes just disagrees with it,
272
+ // which leaves the snapshot untrusted.
273
+ const MAX_LINK_HOPS = 40;
274
+
275
+ /**
276
+ * Resolve `dir` the way realpath does -- one component at a time with lstat,
277
+ * splicing a symlink's target in ahead of whatever is left -- and sign every
278
+ * directory whose entries that depended on: every dir walked through, which
279
+ * includes the one holding each link and every dir the link's target passes
280
+ * through. Each link is signed as well, since a Windows junction can be
281
+ * re-pointed in place without touching the dir it sits in.
282
+ *
283
+ * A missing component is fine wherever it turns up -- in the path as written
284
+ * or in a dangling link's target: the walk stops in the dir it would appear
285
+ * in, that dir is already signed, and creating the entry rewrites it.
286
+ * Anything else that stops the walk (an unreadable dir or link, a file where
287
+ * a dir should be, too many hops) means the dirs a later resolution
288
+ * would depend on aren't known, so the walk reports itself incomplete and the
289
+ * snapshot is rebuilt on every call.
290
+ *
291
+ * So does a link target containing `..`. The kernel applies it to the dir the
292
+ * preceding link really points into; fs.realpathSync drops it textually, so
293
+ * the two land in different places and depend on different dirs. Neither
294
+ * answer can be watched for both, so both realpaths are just redone each call.
295
+ */
296
+ function watchResolution(dir: string, state: WalkState): Walk {
297
+ const incomplete = { complete: false, real: null };
298
+ const abs = path.resolve(dir);
299
+ let cur = path.parse(abs).root;
300
+ if (!state.watched.has(cur)) state.watched.set(cur, dirSignature(cur));
301
+ // A stack: the next component is at the end.
302
+ const pending = components(abs.slice(cur.length)).reverse();
303
+ let hops = 0;
304
+ while (pending.length > 0) {
305
+ const next = path.join(cur, pending.pop()!);
306
+ if (state.watched.has(next)) {
307
+ cur = next;
308
+ continue;
309
+ }
310
+ let target = state.targets.get(next);
311
+ if (target === undefined) {
312
+ let st: fs.Stats;
313
+ try {
314
+ st = fs.lstatSync(next);
315
+ } catch (err) {
316
+ return { complete: (err as NodeJS.ErrnoException).code === "ENOENT", real: null };
317
+ }
318
+ if (!st.isSymbolicLink()) {
319
+ if (!st.isDirectory()) return incomplete;
320
+ state.watched.set(next, signatureOf(st));
321
+ cur = next;
322
+ continue;
323
+ }
324
+ state.links.set(next, signatureOf(st));
325
+ try {
326
+ target = fs.readlinkSync(next);
327
+ } catch {
328
+ return incomplete;
329
+ }
330
+ state.targets.set(next, target);
331
+ }
332
+ if (++hops > MAX_LINK_HOPS) return incomplete;
333
+ // Split on both separators: on POSIX a backslash is just a name
334
+ // character, and calling it one only errs toward incomplete.
335
+ if (target.split(/[\\/]/).includes("..")) return incomplete;
336
+ const resolved = path.resolve(cur, target);
337
+ cur = path.parse(resolved).root;
338
+ if (!state.watched.has(cur)) state.watched.set(cur, dirSignature(cur));
339
+ const parts = components(resolved.slice(cur.length));
340
+ for (let i = parts.length - 1; i >= 0; i--) pending.push(parts[i]);
341
+ }
342
+ return { complete: true, real: cur };
343
+ }
344
+
345
+ function components(rel: string): string[] {
346
+ return rel.split(path.sep).filter(Boolean);
347
+ }
348
+
349
+ function isSymlink(p: string): boolean {
350
+ try {
351
+ return fs.lstatSync(p).isSymbolicLink();
352
+ } catch {
353
+ return false;
354
+ }
355
+ }
356
+
357
+ function dirSignature(dir: string): DirSignature {
358
+ try {
359
+ return signatureOf(fs.lstatSync(dir));
360
+ } catch {
361
+ return { key: "absent", changedAt: -Infinity };
362
+ }
363
+ }
364
+
365
+ function signatureOf(st: fs.Stats): DirSignature {
366
+ return {
367
+ key: `${st.mtimeMs}:${st.ctimeMs}:${st.ino}`,
368
+ // max, so a future mtime set by hand keeps the snapshot untrusted too.
369
+ changedAt: Math.max(st.mtimeMs, st.ctimeMs),
370
+ };
371
+ }
372
+
373
+ function signaturesMatch(watched: Map<string, DirSignature>): boolean {
374
+ for (const [dir, sig] of watched) if (dirSignature(dir).key !== sig.key) return false;
375
+ return true;
376
+ }
377
+
378
+ // A dir resolved both ways: fs.realpathSync is what the exec-guard's jail
379
+ // hands us, and the native one (what fs.promises.realpath gives the web files
380
+ // surface) can differ from it: a `..` in a link target anywhere, and on
381
+ // Windows an expanded 8.3 short name or a subst or mapped drive's target.
382
+ interface ResolvedDir {
383
+ js: string | null;
384
+ native: string | null;
385
+ }
386
+
387
+ // A path both as written and as resolved, since callers hand us realpaths. Only
388
+ // a file that is itself a symlink needs its own realpath; anything else
389
+ // resolves through its parent, which is resolved once per directory and shared
390
+ // through `resolvedParents`. That also covers a file that doesn't exist yet.
391
+ function withRealpath(
392
+ p: string,
393
+ resolvedParents: Map<string, ResolvedDir>,
394
+ isLink: boolean,
395
+ walks?: Map<string, Walk>,
396
+ ): string[] {
397
+ const out = [p];
398
+ if (isLink) {
399
+ const own = resolveBothWays(p);
400
+ if (own.js !== null || own.native !== null) {
401
+ for (const r of [own.js, own.native]) if (r !== null) out.push(r);
402
+ return out;
403
+ }
404
+ /* dangling -- the parent-resolved spelling is still worth having */
405
+ }
406
+ const dir = path.dirname(p);
407
+ let realDir = resolvedParents.get(dir);
408
+ if (!realDir) {
409
+ realDir = resolveBothWays(dir, walks?.get(dir));
410
+ resolvedParents.set(dir, realDir);
411
+ }
412
+ for (const r of [realDir.js, realDir.native]) {
413
+ if (r !== null) out.push(path.join(r, path.basename(p)));
414
+ }
415
+ return out;
416
+ }
417
+
418
+ /**
419
+ * Both realpaths of `p`. A completed walk that agrees with fs.realpathSync has
420
+ * just done what the kernel does -- it only completes when no link target has
421
+ * a `..` in it, the one place the two part ways -- so off Windows the native
422
+ * call is skipped then. On Windows the native one can still differ (an 8.3
423
+ * short name comes back expanded, a subst or mapped drive as its target), and
424
+ * callers that resolved natively hand us that spelling, so it always runs there.
425
+ */
426
+ function resolveBothWays(p: string, walk?: Walk): ResolvedDir {
427
+ const attempt = (resolve: (p: string) => string): string | null => {
428
+ try {
429
+ return resolve(p);
430
+ } catch {
431
+ /* nothing on disk yet -- the lexical path is all there is */
432
+ return null;
433
+ }
434
+ };
435
+ const js = attempt(fs.realpathSync);
436
+ if (process.platform !== "win32" && walk?.complete && walk.real === js) {
437
+ return { js, native: js };
438
+ }
439
+ return { js, native: attempt(fs.realpathSync.native) };
440
+ }
441
+
442
+ export function isSensitivePath(absPath: string, home: string, agentDir?: string): boolean {
443
+ if (isCredentialStore(absPath, home, agentDir)) return true;
444
+ if (SENSITIVE_BASENAME.test(path.basename(path.normalize(absPath)))) return true;
445
+ return false;
446
+ }
447
+
448
+ // Case-folded path-segment membership. macOS HFS+ is case-insensitive and
449
+ // realpath does not normalize case there, so `.Git` / `.LOOM` would otherwise
450
+ // dodge the check. Folding may over-match a literal `.Git` dir on case-sensitive
451
+ // Linux, but that errs toward protection.
452
+ function hasSegment(p: string, name: string): boolean {
453
+ return p.split(path.sep).some((s) => s.toLowerCase() === name);
454
+ }
455
+
456
+ // Write targets gated even inside the workspace jail. A file under `.git`
457
+ // (hooks run on the next git operation; config can redirect hooksPath) or under
458
+ // a state dir (`.loom` or `.orbit` -- Orbit's own session state) should never be
459
+ // written by the model silently -- it uses git commands for repo ops, not the
460
+ // write tool.
461
+ //
462
+ // `home` enables the one carve-out we need: Orbit files analyses under
463
+ // $HOME/.loom/analyses/<name>/ (and, after the rename, $HOME/.orbit/analyses),
464
+ // so those workspaces sit under a state-dir segment yet are the agent's actual
465
+ // work product, not Orbit state. Writes there are allowed -- but a *nested*
466
+ // `.git`/`.loom`/`.orbit` inside an analysis (a real repo's hooks, or the
467
+ // per-workspace state dir) stays protected. Everything else with a `.git` or
468
+ // state-dir segment -- Orbit's home state, some other repo's .git, a
469
+ // per-workspace state dir outside the analyses tree, or a path whose cwd
470
+ // happens to sit inside one -- stays gated. `.git` is never carved out: a
471
+ // workspace is never legitimately inside one. Pass home="" for the plain
472
+ // absolute check (callers without a home / the unit tests).
473
+ export function isProtectedWritePath(absPath: string, home = ""): boolean {
474
+ if (hasSegment(path.normalize(absPath), ".git")) return true;
475
+ return isOrbitStatePath(absPath, home);
476
+ }
477
+
478
+ // The harness-owned record: the signed registry and frozen templates under
479
+ // `<state dir>/state/`, and the per-attempt provenance under
480
+ // `<state dir>/provenance/`. Nothing the model does needs to write either, and
481
+ // an approval it could write itself would not be consent, so these are a
482
+ // floor for the file tools -- denied, not asked about -- where the rest of the
483
+ // state dir only prompts.
484
+ const RECORD_STORE_DIRS = new Set(["state", "provenance"]);
485
+
486
+ export function isRecordStorePath(absPath: string): boolean {
487
+ const segments = path.normalize(absPath).split(path.sep);
488
+ for (let i = 0; i < segments.length - 1; i++) {
489
+ if (!(WORKSPACE_STATE_DIR_NAMES as readonly string[]).includes(segments[i].toLowerCase())) {
490
+ continue;
491
+ }
492
+ if (RECORD_STORE_DIRS.has(segments[i + 1].toLowerCase())) return true;
493
+ }
494
+ return false;
495
+ }
496
+
497
+ // Both spellings are state in every workspace, whichever one it actually uses:
498
+ // a `.loom` workspace must not leave a sibling `.orbit` writable, or the other
499
+ // way round.
500
+ function hasStateSegment(p: string): boolean {
501
+ return WORKSPACE_STATE_DIR_NAMES.some((name) => hasSegment(p, name));
502
+ }
503
+
504
+ // Orbit's own state: a path with a state-dir segment that is NOT the analyses
505
+ // tree Orbit hands the agent as a workspace. Split out of isProtectedWritePath
506
+ // so the bash classifier can reuse exactly this carve-out without also
507
+ // inheriting the `.git` rule -- a `.git` write through bash is an ordinary
508
+ // unrecognized command, not a catastrophic one. (home is compared
509
+ // un-realpath'd, matching isSensitivePath; pass home="" for the plain absolute
510
+ // check.)
511
+ export function isOrbitStatePath(absPath: string, home = ""): boolean {
512
+ const norm = path.normalize(absPath);
513
+ if (!hasStateSegment(norm)) return false;
514
+ // A home that itself sits under a state dir gets no carve-out: the segment
515
+ // above it is state no matter which analyses tree the path is in.
516
+ if (home && !hasStateSegment(path.normalize(home))) {
517
+ for (const name of WORKSPACE_STATE_DIR_NAMES) {
518
+ const analyses = path.join(home, name, "analyses");
519
+ if (within(norm, analyses) && !hasStateSegment(path.relative(analyses, norm))) {
520
+ return false;
521
+ }
522
+ }
523
+ }
524
+ return true;
525
+ }
@@ -0,0 +1,42 @@
1
+ export type Decision = "allow" | "ask" | "deny";
2
+ export type ModelTier = "trusted" | "weak";
3
+
4
+ export interface GuardianConfig {
5
+ enabled: boolean;
6
+ dangerouslyBypassPermissions: boolean;
7
+ trustedWorkspaces: string[];
8
+ extraWorkspaceRoots: string[];
9
+ consentAcknowledged: { version: string; at: string } | null;
10
+ /** Opt-in: run allowed bash inside an OS sandbox (confines bash writes + network). */
11
+ sandbox: boolean;
12
+ }
13
+
14
+ export interface PathResolver {
15
+ /** Realpath the target (resolving the deepest existing ancestor for not-yet-existing
16
+ * targets) and report whether it lands inside any allowed root. */
17
+ contains(targetPath: string): { resolved: string; inside: boolean };
18
+ }
19
+
20
+ export interface PolicyRequest {
21
+ toolName: string;
22
+ toolInput: Record<string, unknown>;
23
+ modelTier: ModelTier;
24
+ config: GuardianConfig;
25
+ interactive: boolean;
26
+ cwd: string;
27
+ }
28
+
29
+ export interface PolicyDeps {
30
+ resolver: PathResolver;
31
+ home: string;
32
+ }
33
+
34
+ export interface PolicyResult {
35
+ decision: Decision;
36
+ // e.g. "bypass", "bash:safe", "bash:catastrophic", "write:in-jail", "read:sensitive",
37
+ // "galaxy:destructive", "default:ask"
38
+ category: string;
39
+ reason: string; // human-facing
40
+ }
41
+
42
+ export const CONSENT_VERSION = "1";