clearotron 0.4.0-beta.1 → 0.4.0-beta.2

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 (250) hide show
  1. package/INSTALL.md +4 -31
  2. package/README.md +5 -5
  3. package/bin/brandowner.mjs +1 -1
  4. package/bin/onboard.mjs +18 -74
  5. package/bin/start.mjs +58 -14
  6. package/bin/update.mjs +4 -1
  7. package/build-info.json +2 -2
  8. package/demo/full-country-search/run/_driver/search-policy.json +1 -1
  9. package/demo/full-country-search/run/status.json +1 -1
  10. package/demo/global-preliminary-search/run/_driver/search-policy.json +1 -1
  11. package/demo/global-preliminary-search/run/status.json +1 -1
  12. package/demo/knockout-search/run/_driver/search-policy.json +1 -1
  13. package/demo/knockout-search/run/status.json +1 -1
  14. package/demo/multi-country-focus-search/run/_driver/search-policy.json +1 -1
  15. package/demo/multi-country-focus-search/run/status.json +1 -1
  16. package/docs/README.md +1 -0
  17. package/docs/SECURITY-OWASP.md +298 -0
  18. package/docs/SECURITY.md +18 -13
  19. package/docs/architecture/02-architecture.md +5 -5
  20. package/docs/architecture/03-run-lifecycle.md +28 -29
  21. package/docs/architecture/04-configuration-reference.md +3 -4
  22. package/docs/architecture/05-config-governance.md +5 -7
  23. package/docs/architecture/06-operations-runbook.md +0 -12
  24. package/docs/architecture/07-quality-and-audit.md +12 -13
  25. package/docs/architecture/09-security-and-data.md +9 -4
  26. package/driver/CHANGELOG.md +60 -0
  27. package/driver/ask-ledger.mjs +2 -0
  28. package/driver/authority-trees.mjs +90 -8
  29. package/driver/band-shape.mjs +5 -5
  30. package/driver/case-law-ledger.mjs +19 -3
  31. package/driver/claim-liveness.mjs +30 -1
  32. package/driver/clearance-variants-record.mjs +10 -3
  33. package/driver/common-law-receipts.mjs +62 -12
  34. package/driver/commonlaw-carry.mjs +1 -1
  35. package/driver/compare.mjs +2 -2
  36. package/driver/connotation-search.mjs +30 -101
  37. package/driver/contract-arm2-baseline.json +6 -5
  38. package/driver/contract-e3-backlog.mjs +60 -60
  39. package/driver/contract-vocabulary.mjs +38 -31
  40. package/driver/coverage-form-io.mjs +13 -1
  41. package/driver/coverage-form.mjs +42 -4
  42. package/driver/coverage-ledger.mjs +3 -5
  43. package/driver/cross-check-wait.mjs +43 -0
  44. package/driver/declination-call.mjs +33 -9
  45. package/driver/declination-tool.mjs +27 -15
  46. package/driver/deferral-row.mjs +139 -0
  47. package/driver/degraded-parts.mjs +377 -0
  48. package/driver/deliver-trigger.sh +1 -1
  49. package/driver/demo-container.mjs +4 -1
  50. package/driver/dev-portal.mjs +4 -4
  51. package/driver/dispatch-record.mjs +2 -2
  52. package/driver/driver.config.mjs +177 -87
  53. package/driver/effective-scope.mjs +58 -2
  54. package/driver/engine/anthropic-agent.mjs +103 -27
  55. package/driver/engine/auth.mjs +2 -2
  56. package/driver/engine/child-record.mjs +11 -0
  57. package/driver/engine/cli-version.mjs +4 -3
  58. package/driver/engine/common.mjs +17 -2
  59. package/driver/engine/deny-authority-write.mjs +3 -1
  60. package/driver/engine/engine-env.mjs +174 -0
  61. package/driver/engine/engine-spawn.mjs +179 -0
  62. package/driver/engine/mcp/band-server.mjs +1 -1
  63. package/driver/engine/mcp/codex-config.mjs +112 -3
  64. package/driver/engine/mcp/declination-server.mjs +9 -8
  65. package/driver/engine/mcp/dispositions-server.mjs +2 -1
  66. package/driver/engine/mcp/fetch-server.mjs +14 -11
  67. package/driver/engine/mcp/gather-config.mjs +22 -10
  68. package/driver/engine/mcp/perplexity-server.mjs +96 -16
  69. package/driver/engine/mcp/probe-server.mjs +43 -21
  70. package/driver/engine/mcp/public-fetch.mjs +195 -0
  71. package/driver/engine/mcp/recording-server.mjs +78 -13
  72. package/driver/engine/mcp/supplemental.mjs +13 -13
  73. package/driver/engine/mcp/unit-note-server.mjs +50 -1
  74. package/driver/engine/openai-agent.mjs +109 -28
  75. package/driver/engine/probe.mjs +152 -19
  76. package/driver/enqueue-schema.mjs +3 -3
  77. package/driver/findings-model.mjs +64 -13
  78. package/driver/floor-duty.mjs +21 -5
  79. package/driver/form-neighbourhood.mjs +5 -2
  80. package/driver/framework-method.mjs +304 -0
  81. package/driver/gateway.mjs +44 -16
  82. package/driver/hand-off-exits.mjs +129 -0
  83. package/driver/jx.mjs +8 -5
  84. package/driver/knockout-assess-record.mjs +7 -1
  85. package/driver/knockout-frame-record.mjs +96 -34
  86. package/driver/knockout-review-record.mjs +7 -2
  87. package/driver/matter-frame-record.mjs +31 -2
  88. package/driver/methodology-witness.mjs +6 -3
  89. package/driver/named-band.mjs +1 -1
  90. package/driver/owner-use-check.mjs +45 -10
  91. package/driver/package.json +1 -1
  92. package/driver/partial-payload-baseline.json +4 -0
  93. package/driver/phase0.mjs +2 -2
  94. package/driver/pipeline-knockout.mjs +128 -35
  95. package/driver/pipeline.mjs +373 -598
  96. package/driver/placement-carry.mjs +20 -1
  97. package/driver/placement-form-io.mjs +18 -4
  98. package/driver/placement-form.mjs +52 -3
  99. package/driver/placement-union.mjs +32 -5
  100. package/driver/portal-report.mjs +3 -3
  101. package/driver/portal-service.mjs +4 -3
  102. package/driver/portal-static.mjs +11 -18
  103. package/driver/profile-page.html +5 -5
  104. package/driver/profiles.mjs +5 -5
  105. package/driver/progress.mjs +5 -3
  106. package/driver/provider-usage.mjs +1 -1
  107. package/driver/publish/index.mjs +94 -22
  108. package/driver/publish/knockout.mjs +133 -12
  109. package/driver/publish/profiles-page.mjs +2 -0
  110. package/driver/publish/publish-inputs.mjs +10 -4
  111. package/driver/publish/render-knockout.mjs +47 -20
  112. package/driver/publish/render.mjs +12 -7
  113. package/driver/publish/report-data.mjs +2 -0
  114. package/driver/publish/search-depth.mjs +77 -4
  115. package/driver/publish/templates/report.css +1 -1
  116. package/driver/publish/xlsx.mjs +34 -15
  117. package/driver/reasoning-tripwires.mjs +2 -160
  118. package/driver/recall-receipt.mjs +27 -0
  119. package/driver/record-carry.mjs +8 -8
  120. package/driver/reference-score.mjs +142 -20
  121. package/driver/register-count.mjs +5 -3
  122. package/driver/register-digest-record.mjs +13 -0
  123. package/driver/register-plan.mjs +156 -75
  124. package/driver/register-records.mjs +27 -3
  125. package/driver/registration-scripts.mjs +22 -0
  126. package/driver/repair-composers.mjs +19 -3
  127. package/driver/repair-contract.mjs +1 -1
  128. package/driver/repairs.mjs +5 -2
  129. package/driver/reviewer-open-points.mjs +33 -0
  130. package/driver/rule-shape.mjs +8 -8
  131. package/driver/run-economics.mjs +2 -2
  132. package/driver/run-integrity.mjs +2 -2
  133. package/driver/runner.mjs +17 -5
  134. package/driver/scope-facts.mjs +89 -12
  135. package/driver/score-redaction.mjs +247 -0
  136. package/driver/search-policy.mjs +17 -0
  137. package/driver/skills/README.md +2 -2
  138. package/driver/skills/clearance-common-law/SKILL.md +29 -36
  139. package/driver/skills/clearance-common-law/perplexity-prompts.md +5 -27
  140. package/driver/skills/clearance-register/SKILL.md +15 -16
  141. package/driver/skills/clearance-register/digest.md +14 -30
  142. package/driver/skills/clearance-register/register-recipes.md +14 -56
  143. package/driver/skills/clearance-register/unit.md +36 -47
  144. package/driver/skills/clearance-search/SKILL.md +6 -8
  145. package/driver/skills/clearance-search/delivery-contract.md +0 -7
  146. package/driver/skills/clearance-search/firm-wide-reasoning.md +5 -4
  147. package/driver/skills/clearance-search/phase2-execution.md +5 -6
  148. package/driver/skills/clearance-search/risk-framework-triage.md +2 -2
  149. package/driver/skills/clearance-search/synthesis-rules.md +5 -5
  150. package/driver/skills/clearance-search/template-formatting.md +2 -2
  151. package/driver/skills/clearance-variants/SKILL.md +6 -6
  152. package/driver/skills/clearance-variants/transliteration-scripts.md +1 -1
  153. package/driver/skills/knockout-assess/SKILL.md +31 -1
  154. package/driver/skills/knockout-frame/SKILL.md +42 -10
  155. package/driver/skills/matter-frame/SKILL.md +12 -5
  156. package/driver/skills/narrative-refutation/SKILL.md +3 -1
  157. package/driver/skills/placement-inquiry/SKILL.md +4 -0
  158. package/driver/stage-context.mjs +23 -2
  159. package/driver/stages-knockout.mjs +92 -79
  160. package/driver/stages.mjs +88 -53
  161. package/driver/stray-artifacts.mjs +9 -5
  162. package/driver/suite-census.json +620 -140
  163. package/driver/synthesis-record.mjs +26 -4
  164. package/driver/systemd/README.md +5 -6
  165. package/driver/systemd/clearotron-worker.service +6 -1
  166. package/driver/tokens.mjs +2 -2
  167. package/driver/unit-inventory.mjs +21 -40
  168. package/driver/variant-manifest-model.mjs +21 -2
  169. package/driver/verify-knockout.mjs +163 -4
  170. package/driver/verify.mjs +40 -14
  171. package/driver/web-grid.mjs +150 -0
  172. package/driver/withheld-families.mjs +113 -4
  173. package/driver/worker-heartbeat.mjs +13 -2
  174. package/mcp-server/CHANGELOG.md +4 -0
  175. package/mcp-server/README.md +1 -1
  176. package/mcp-server/lib/knockout.mjs +1 -1
  177. package/mcp-server/lib/ops.mjs +10 -10
  178. package/mcp-server/lib/scrub.mjs +1 -1
  179. package/mcp-server/lib/trace.mjs +3 -2
  180. package/mcp-server/package.json +1 -1
  181. package/mcp-server/server.mjs +2 -2
  182. package/package.json +1 -1
  183. package/portal-ui/dist/assets/{index-D_O_55vK.js → index-BPAUjcI0.js} +1 -1
  184. package/portal-ui/dist/assets/{index-5CCwiJG7.css → index-D2wrw9cH.css} +18 -2
  185. package/portal-ui/dist/assets/plus-jakarta-sans-BUCHxqJ-.woff2 +0 -0
  186. package/portal-ui/dist/index.html +2 -15
  187. package/portal-ui/package.json +1 -1
  188. package/providers/_shared/enumerate.mjs +155 -50
  189. package/providers/_shared/execute-plan.mjs +62 -16
  190. package/providers/_shared/ledger.mjs +1 -1
  191. package/providers/_shared/plan-guards.mjs +7 -0
  192. package/providers/clarivate/src/core.js +54 -6
  193. package/providers/corsearch/README.md +1 -2
  194. package/providers/corsearch/src/core.js +2 -2
  195. package/providers/oauth-mcp-bridge/CHANGELOG.md +4 -0
  196. package/providers/oauth-mcp-bridge/README.md +8 -7
  197. package/providers/oauth-mcp-bridge/bridge.mjs +21 -5
  198. package/providers/oauth-mcp-bridge/package.json +1 -1
  199. package/providers/oauth-mcp-bridge/systemd/courtlistener-mcp.service +1 -1
  200. package/providers/oauth-mcp-bridge/warm-server.mjs +16 -5
  201. package/providers/perplexity/src/core.js +246 -21
  202. package/providers/signa/src/core.js +27 -25
  203. package/scripts/README.md +2 -1
  204. package/scripts/added-reference-check.mjs +2 -1
  205. package/scripts/backup-recall-stores.mjs +5 -5
  206. package/scripts/demo-evidence.mjs +2 -1
  207. package/scripts/drive-env-check.mjs +2 -1
  208. package/scripts/e2e-first-time.mjs +469 -0
  209. package/scripts/e2e-scenario-ops.mjs +441 -0
  210. package/scripts/e2e.mjs +104 -16
  211. package/scripts/env-audit.mjs +8 -0
  212. package/scripts/freeze-example-run.mjs +7 -7
  213. package/scripts/generated-files-are-current.mjs +2 -1
  214. package/scripts/hand-off-exits-probe.mjs +75 -0
  215. package/scripts/import-cycle-check.mjs +2 -1
  216. package/scripts/merge-shape-check.mjs +2 -1
  217. package/scripts/package-size-budget.mjs +2 -1
  218. package/scripts/record-carry-probe.mjs +1 -1
  219. package/scripts/release-install-check.mjs +4 -1
  220. package/scripts/release-note-required.mjs +44 -10
  221. package/scripts/render-check.mjs +5 -2
  222. package/scripts/report-offline-render-check.mjs +169 -0
  223. package/scripts/score.mjs +76 -5
  224. package/scripts/strip-titles-and-attributions.mjs +2 -1
  225. package/scripts/strip-tracker-citations.mjs +2 -1
  226. package/scripts/test-full.mjs +2 -1
  227. package/scripts/test-run.mjs +10 -3
  228. package/scripts/third-party-notices.mjs +3 -1
  229. package/scripts/travelling-predicates.mjs +1 -1
  230. package/scripts/writing-standard-check.mjs +2 -1
  231. package/shared/brand-fonts.mjs +59 -0
  232. package/shared/brand.mjs +5 -5
  233. package/shared/browser-temp-root.mjs +3 -2
  234. package/shared/doctrine-overlay.mjs +1 -1
  235. package/shared/driver-dir.mjs +27 -2
  236. package/shared/fonts/OFL-fira-code.txt +93 -0
  237. package/shared/fonts/OFL-plus-jakarta-sans.txt +93 -0
  238. package/shared/fonts/README.md +37 -0
  239. package/shared/fonts/fira-code.woff2 +0 -0
  240. package/shared/fonts/plus-jakarta-sans.woff2 +0 -0
  241. package/shared/npm-cli.mjs +23 -0
  242. package/shared/os-advice.mjs +14 -2
  243. package/shared/path-seps.mjs +42 -0
  244. package/shared/process-table.mjs +71 -3
  245. package/shared/reference-guard-classes.mjs +30 -6
  246. package/shared/root-doc-commands.mjs +6 -2
  247. package/shared/running-start.mjs +24 -7
  248. package/shared/scope.mjs +2 -2
  249. package/shared/wsl.mjs +1 -1
  250. package/driver/known-conflicts.mjs +0 -345
@@ -0,0 +1,93 @@
1
+ Copyright 2014-2020 The Fira Code Project Authors (https://github.com/tonsky/FiraCode)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ https://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Copyright 2020 The Plus Jakarta Sans Project Authors (https://github.com/tokotype/PlusJakartaSans)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,37 @@
1
+ # Fonts
2
+
3
+ The two typefaces every report, pool index and portal page is set in. They ship inside the package, and
4
+ each report carries them inside its own file, so opening a report fetches nothing from anywhere.
5
+
6
+ | File | Typeface | Licence |
7
+ |---|---|---|
8
+ | `plus-jakarta-sans.woff2` | Plus Jakarta Sans, the text face, weights 200–800 | SIL Open Font License 1.1, [`OFL-plus-jakarta-sans.txt`](OFL-plus-jakarta-sans.txt) |
9
+ | `fira-code.woff2` | Fira Code, the code face, weights 300–700 | SIL Open Font License 1.1, [`OFL-fira-code.txt`](OFL-fira-code.txt) |
10
+
11
+ Neither licence reserves a font name, so these subsets keep their names.
12
+
13
+ ## Where they come from
14
+
15
+ Each file is a subset of the variable font in the [google/fonts](https://github.com/google/fonts)
16
+ repository:
17
+
18
+ | File | Source | Last upstream commit to that folder | sha256 of the source file |
19
+ |---|---|---|---|
20
+ | `plus-jakarta-sans.woff2` | `ofl/plusjakartasans/PlusJakartaSans[wght].ttf` | `8b0a1d0f5983c89bc2b93f1b5fb55f9e252744b5` | `89b3fb38aa0d275d7a731d0d817a4f1622b316b4d7fbdedcf02ee9099ff68bc8` |
21
+ | `fira-code.woff2` | `ofl/firacode/FiraCode[wght].ttf` | `5020a98352f1909554697e1da4132da253727138` | `9335b082b3c7850d98a64b584f3417f65355f3471278bb5eeb8c6c0e8657aeeb` |
22
+
23
+ The licence files are that repository's `OFL.txt` for each family.
24
+
25
+ The subset keeps the Latin and Latin Extended ranges Google Fonts serves, plus the four arrows U+2190–2193,
26
+ which the reports use and Google's Latin range leaves out. It keeps every layout feature, the whole
27
+ weight axis and every name record, so the copyright and licence notices stay inside each file. Made with
28
+ fonttools 4.65.0:
29
+
30
+ ```sh
31
+ pyftsubset <source>.ttf --flavor=woff2 --layout-features='*' --name-IDs='*' --name-languages='*' \
32
+ --name-legacy --notdef-outline --output-file=<file>.woff2 \
33
+ --unicodes="U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2190-2193,U+2212,U+2215,U+FEFF,U+FFFD,U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF"
34
+ ```
35
+
36
+ A character outside that set, such as Japanese or Greek, is drawn by the reader's own system fonts, as it
37
+ was before these files existed.
Binary file
@@ -0,0 +1,23 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
+ // npm-cli.mjs — HOW TO RUN NPM WITHOUT A SHELL, on every platform.
4
+ //
5
+ // ON WINDOWS NPM IS A BATCH FILE. `npm` there is `npm.cmd`, and Node refuses to start a batch file without
6
+ // a shell (EINVAL, since the 2024 fix for batch-file argument injection). A shell is no way round it here:
7
+ // the engine install passes `<package>@>=<floor>`, and cmd.exe reads that `>` as a redirection into a file.
8
+ // npm itself is a Node program, `npm-cli.js`, so on Windows it runs through the Node running now: the one
9
+ // npm named when it launched this process, else the one beside `node.exe`, which is where Node's own
10
+ // Windows installer puts it. Elsewhere `npm` is run as it always was.
11
+
12
+ import { existsSync } from "node:fs";
13
+ import { win32 } from "node:path";
14
+
15
+ /** The command and arguments that run npm with `args`: `{command, args}`. `platform` is a parameter so the Windows branch runs on a Linux CI. */
16
+ export function npmInvocation(args = [], { platform = process.platform, env = process.env, execPath = process.execPath, exists = existsSync } = {}) {
17
+ if (platform !== "win32") return { command: "npm", args };
18
+ const named = String(env.npm_execpath ?? "");
19
+ if (/npm-cli\.js$/i.test(named) && exists(named)) return { command: execPath, args: [named, ...args] };
20
+ const beside = win32.join(win32.dirname(execPath), "node_modules", "npm", "bin", "npm-cli.js");
21
+ if (exists(beside)) return { command: execPath, args: [beside, ...args] };
22
+ return { command: "npm", args };
23
+ }
@@ -85,7 +85,19 @@ export const chdirPrefix = (dir, { platform = process.platform } = {}) =>
85
85
  *
86
86
  * `null` where this platform has no such mechanism in the product, so a caller prints nothing rather
87
87
  * than naming a service manager the reader does not have. Windows was told the background form was
88
- * "managed by systemd", which is not on the machine and cannot be installed onto it.
88
+ * "managed by systemd", which is not on the machine and cannot be installed onto it, and a Mac was told
89
+ * the same: `--background` installs systemd units, and of the platforms the product runs on only Linux
90
+ * has systemd.
89
91
  */
90
92
  export const backgroundManager = ({ platform = process.platform } = {}) =>
91
- (isWindows(platform) ? null : "systemd");
93
+ (platform === "linux" ? "systemd" : null);
94
+
95
+ /**
96
+ * What `start --background` answers on Windows, where it has nothing to install: the background form is
97
+ * systemd units, and Windows has no systemd. Printed as it stands and nothing else, before `start` writes
98
+ * anything or calls systemctl (owner's ruling, 2026-09-23). `null` elsewhere. Asked of Windows by name
99
+ * rather than of `backgroundManager`, which answers `null` on other machines too, and a Mac must not be
100
+ * told it is Windows.
101
+ */
102
+ export const backgroundRefusal = ({ platform = process.platform } = {}) =>
103
+ (isWindows(platform) ? "Background mode isn't available on Windows. Run `clearotron start` and keep its window open." : null);
@@ -0,0 +1,42 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
+ // path-seps.mjs — THE SEPARATOR A PATH WAS BUILT WITH, for code that reads a path with a regex.
4
+ //
5
+ // `join` builds a path with the platform's own separator: "/" on Linux and macOS, "\" on Windows. A regex
6
+ // written against "/" matches nothing on Windows, so the reader that holds it says "not a run directory"
7
+ // or "no agent" about a path that is both, and the grid tool refused every full clearance that way.
8
+ //
9
+ // WINDOWS ACCEPTS BOTH, so both are separators there. On Linux and macOS "\" is an ordinary filename
10
+ // character, so it stays one: the class is chosen from the platform, and a Linux path reads exactly as it
11
+ // did before this file existed. `platform` is a parameter so the Windows branch runs on a Linux CI.
12
+
13
+ import { STUDIO_SEGMENT_RE } from "./pre-rename-spellings.mjs";
14
+
15
+ /** A regex source matching one path separator on `platform`. */
16
+ export function sepClass(platform = process.platform) {
17
+ return platform === "win32" ? "[\\\\/]" : "/";
18
+ }
19
+
20
+ /** A regex source matching one character that is not a path separator on `platform`. */
21
+ export function notSepClass(platform = process.platform) {
22
+ return platform === "win32" ? "[^\\\\/]" : "[^/]";
23
+ }
24
+
25
+ /** Everything after the last separator: the file's own name. */
26
+ export function lastSegment(p, platform = process.platform) {
27
+ const s = String(p ?? "");
28
+ const cut = platform === "win32" ? Math.max(s.lastIndexOf("/"), s.lastIndexOf("\\")) : s.lastIndexOf("/");
29
+ return s.slice(cut + 1);
30
+ }
31
+
32
+ /** Does the path hold a separator at all, as opposed to being a bare name? */
33
+ export function hasSep(p, platform = process.platform) {
34
+ const s = String(p ?? "");
35
+ return s.includes("/") || (platform === "win32" && s.includes("\\"));
36
+ }
37
+
38
+ /** Is `p` inside a run directory: somewhere under `…/studio/<either segment spelling>/`? */
39
+ export function underStudioSegment(p, platform = process.platform) {
40
+ const S = sepClass(platform);
41
+ return new RegExp(`${S}studio${S}${STUDIO_SEGMENT_RE}${S}`).test(String(p ?? ""));
42
+ }
@@ -55,10 +55,19 @@ import { spawnSync } from "node:child_process";
55
55
  * how a portability fix ships broken on the platform it was written for.
56
56
  */
57
57
  export function processTable({ platform = process.platform, runPs = defaultRunPs,
58
- everyUser = false, uid = currentUid() } = {}) {
59
- const all = platform === "linux" ? fromProc() : fromPs(runPs);
58
+ runPowerShell = defaultRunPowerShell, everyUser = false, uid = currentUid(), selfPid = process.pid } = {}) {
59
+ const all = platform === "linux" ? fromProc() : platform === "win32" ? fromWindows(runPowerShell) : fromPs(runPs);
60
60
  if (all == null) return null; // could not look, and that survives the filter
61
61
  if (everyUser) return all;
62
+ // WINDOWS HAS NO UID, so "this user's own" is asked of the logon SESSION instead: each user signed in
63
+ // to a machine has their own, and services run in session 0. It is the nearest thing Windows answers
64
+ // without an administrator, and it keeps doctor off another account's programs, which is the second
65
+ // half of the contract above. A listing that does not hold this process cannot say which session is
66
+ // ours, so it is returned whole, as the no-uid case below returns it.
67
+ if (platform === "win32") {
68
+ const me = all.find((p) => p.pid === selfPid);
69
+ return me && me.session != null ? all.filter((p) => p.session === me.session) : all;
70
+ }
62
71
  // A box with no uid to compare against (a platform with no getuid) cannot answer "is this mine", and
63
72
  // guessing would hand back either everything or nothing. Everything is the honest one: the caller
64
73
  // gets what it always got, and the row carries `uid: null` so it can see the question was unanswered.
@@ -119,7 +128,66 @@ function fromPs(runPs) {
119
128
  return out.length ? out : null;
120
129
  }
121
130
 
131
+ // ── WINDOWS: THE SAME CONTRACT, READ THROUGH POWERSHELL ─────────────────────────────────────────────────
132
+ //
133
+ // Windows has neither /proc nor ps. What it has on every supported version, with no administrator, is
134
+ // Windows PowerShell and the process list it reads from the system (Win32_Process). One row per process,
135
+ // fields separated by "|", the command line last because it is the only field that can hold a "|".
136
+ //
137
+ // THE START TIME IS PRINTED AS A NUMBER, never as a date: PowerShell writes dates in the machine's own
138
+ // locale, and a parse of that would read one day as another on half the machines it met. `ToFileTimeUtc`
139
+ // is the count of 100-nanosecond ticks since 1601, the same on every machine, and `windowsTicksToMs`
140
+ // turns it into the epoch milliseconds the rest of this file uses.
141
+ //
142
+ // The script holds no double quote, so no rule about quoting an argument can change what PowerShell
143
+ // receives. The output encoding is asked for inside a try: a machine locked to PowerShell's constrained
144
+ // mode refuses that line, and only a command line with non-ASCII characters in it suffers for it.
145
+ export function windowsProcessScript(pid = null) {
146
+ const only = Number.isInteger(pid) && pid > 0 ? ` -Filter 'ProcessId=${pid}'` : "";
147
+ return "try { [Console]::OutputEncoding = [Text.Encoding]::UTF8 } catch {}; "
148
+ + `Get-CimInstance Win32_Process${only} | ForEach-Object { $c = $_.CreationDate; `
149
+ + "'{0}|{1}|{2}|{3}|{4}' -f $_.ProcessId, $_.ParentProcessId, $(if ($c) { $c.ToFileTimeUtc() } else { '' }), "
150
+ + "$_.SessionId, ($_.CommandLine -replace '\\s+', ' ') }";
151
+ }
152
+
153
+ /** Windows file time (100 ns ticks since 1601-01-01 UTC) to epoch milliseconds; NaN for anything else. */
154
+ export function windowsTicksToMs(ticks) {
155
+ const t = String(ticks ?? "").trim();
156
+ if (!/^\d{15,19}$/.test(t)) return NaN;
157
+ return Number((BigInt(t) - 116444736000000000n) / 10000n);
158
+ }
159
+
160
+ /** The rows `windowsProcessScript` printed: `{pid, ppid, startedAt, session, cmd}`. Unparseable lines are skipped. */
161
+ export function parseWindowsRows(stdout) {
162
+ const out = [];
163
+ for (const line of String(stdout ?? "").split(/\r?\n/)) {
164
+ const m = /^(\d+)\|(\d*)\|(\d*)\|(\d*)\|(.*)$/.exec(line.trim());
165
+ if (!m) continue;
166
+ out.push({ pid: Number(m[1]), ppid: m[2] === "" ? null : Number(m[2]), startedAt: windowsTicksToMs(m[3]),
167
+ session: m[4] === "" ? null : Number(m[4]), uid: null, cmd: m[5].trim() });
168
+ }
169
+ return out;
170
+ }
171
+
172
+ /** Windows: every process, or null when PowerShell could not be run or printed nothing it could parse. */
173
+ function fromWindows(runPowerShell) {
174
+ const r = runPowerShell(windowsProcessScript());
175
+ if (!r || r.status !== 0 || typeof r.stdout !== "string") return null;
176
+ const out = parseWindowsRows(r.stdout);
177
+ // As for `ps`: this process is in the listing, so an empty parse is an instrument that broke.
178
+ return out.length ? out : null;
179
+ }
180
+
181
+ /**
182
+ * Run one PowerShell script and capture what it prints. `windowsHide` because this is started from the
183
+ * portal and the worker many times an hour, and a console program started by a process without a
184
+ * console of its own opens a window.
185
+ */
186
+ const defaultRunPowerShell = (script) =>
187
+ spawnSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script],
188
+ { encoding: "utf8", windowsHide: true, timeout: 30_000, maxBuffer: 16 * 1024 * 1024 });
189
+
122
190
  const defaultRunPs = () =>
123
191
  spawnSync("ps", ["-Ao", "pid=,uid=,lstart=,command="], { encoding: "utf8", maxBuffer: 8 * 1024 * 1024 });
124
192
 
125
- export { defaultRunPs };
193
+ export { defaultRunPs, defaultRunPowerShell };
@@ -39,12 +39,21 @@
39
39
  // `deploy` IS A SKILL NAME AND IS NOT BANNED, for the same reason. It is an ordinary English word and a
40
40
  // paragraph about deploying would be refused line by line.
41
41
  //
42
- // `clawdi` IS NOT BANNED, and this one was measured rather than reasoned. It reads like an internal
43
- // name and it is the product's own default agent id: `CLEAROTRON_DEFAULT_AGENT=clawdi` is in
44
- // INSTALL.md, in the configuration reference and in the operations runbook, and it is a path segment in
45
- // every run directory. 49 lines carry it in that sense and none carries it as a reference to the other
46
- // product, which is the class that would have been worth refusing. Banning it would refuse the install
47
- // instructions a stranger reads first.
42
+ // THE PRODUCT'S FORMER DEFAULT AGENT ID IS NOW BANNED, and the reason it was not is worth keeping
43
+ // because it was a good one. It was the id an install ran as: it named a setting in the install
44
+ // instructions, in the configuration reference and in the operations runbook, and it was a path segment
45
+ // in every run directory. 49 lines carried it in that sense. A guard refusing it would have refused the
46
+ // install instructions a stranger reads first, so it was left alone and the reason written down.
47
+ //
48
+ // Ruling 563 (2026-09-27) took every functional use of it out of the product, and the ban is the closing
49
+ // step: without it the id comes back and nothing says so. The class is below, and its pattern is the only
50
+ // place in this tree that spells it — a `pattern:` line is code, and this guard reads comments and
51
+ // markdown, never code, so the class does not refuse its own definition.
52
+ //
53
+ // WHAT THE BAN DOES NOT DISTURB. This check is diff-shaped: what a change ADDS is refused, and what is
54
+ // already here is not its business. Two lines still carry the id on purpose — a record of a measurement
55
+ // taken over archived runs, and a captured error message from a real incident — and neither is refused,
56
+ // because neither is added by anything. That is the mechanism, not an exemption list to maintain.
48
57
 
49
58
  import { execFileSync } from "node:child_process";
50
59
  import { CUT_RECORD_PRESENT, isWithheld } from "./withheld-paths-access.mjs";
@@ -157,6 +166,21 @@ export const CLASSES = [
157
166
  + "not. A reader outside this project cannot open the number. Say why the code is as it is; put "
158
167
  + "the citation in the commit message or the pull request body.",
159
168
  },
169
+ {
170
+ // NOT A NAME THIS PROJECT USES FOR HOW IT IS BUILT — it is an identifier the product SHIPPED, which is
171
+ // why it is banned only now that it ships nowhere. The remedy is the same as the login class's: say
172
+ // what the thing is for, not what it was called.
173
+ id: "retired-agent-id",
174
+ // NO WORD BOUNDARIES, and that is deliberate. `\b` does not match before an underscore, so a
175
+ // boundaried pattern let every prefixed spelling of the id through — a setting name carrying it as a
176
+ // prefix read as clean, which is the shape a returning identifier actually takes. The id is a coined
177
+ // word, so an unanchored match has no innocent population to refuse.
178
+ pattern: /clawdi/i,
179
+ why: "the agent id this product used to default to. It was a path segment in every run directory and "
180
+ + "named in the install instructions until it was taken out of the product; a new line carrying it "
181
+ + "is either residue or a reference to a different product. Name the setting that holds the agent, "
182
+ + "or the install's own default, rather than one particular value of it.",
183
+ },
160
184
  {
161
185
  id: "login",
162
186
  pattern: /\b(?:testuser|azureuser|devuser)[0-9]*\b/i,
@@ -39,7 +39,7 @@ export const NPX = /npx clearotron [a-z]/g;
39
39
  * fresh `npx`, which resolves whichever channel npm picks at that moment — the stable, for a reader who
40
40
  * installed the beta (owner ruling, 2026-09-18).
41
41
  */
42
- export const GLOBAL_INSTALL = /npm install -g clearotron|npx clearotron(?:@[\w.-]+)? install\b/;
42
+ export const GLOBAL_INSTALL = /npm install (?:-g|--global) clearotron|npx clearotron(?:@[\w.-]+)? install\b/;
43
43
  /** The paragraph that is ABOUT the shim, where the short form is the point. */
44
44
  export const SHIM_PARAGRAPH = /short form|on your `PATH`|stop typing/;
45
45
 
@@ -53,6 +53,9 @@ export function commandSites(file, text) {
53
53
  const lines = String(text ?? "").split("\n");
54
54
  const installedAt = lines.findIndex((l) => GLOBAL_INSTALL.test(l));
55
55
  const globalFrom = installedAt === -1 ? Infinity : installedAt + 1;
56
+ // A sentence can install and then use the command on one line ("`npm install --global clearotron`, then
57
+ // `clearotron install`"): a bare site on the install's own line counts as after it when it comes later.
58
+ const installCol = installedAt === -1 ? Infinity : lines[installedAt].search(GLOBAL_INSTALL);
56
59
  const para = [];
57
60
  let n = 0;
58
61
  for (const line of lines) { if (line.trim() === "") n++; para.push(n); }
@@ -60,7 +63,8 @@ export function commandSites(file, text) {
60
63
  const bare = [], npx = [];
61
64
  lines.forEach((line, i) => {
62
65
  if (BARE.test(line)) {
63
- bare.push({ file, line: i + 1, text: line.trim(), paragraph: textOf(para[i]), afterGlobalInstall: i + 1 > globalFrom });
66
+ const afterGlobalInstall = i + 1 > globalFrom || (i === installedAt && line.search(BARE) > installCol);
67
+ bare.push({ file, line: i + 1, text: line.trim(), paragraph: textOf(para[i]), afterGlobalInstall });
64
68
  }
65
69
  npx.push(...(line.match(NPX) ?? []).map(() => ({ file, line: i + 1 })));
66
70
  });
@@ -13,9 +13,9 @@
13
13
  // record whose process is gone is read as absent, and `status` asks the portal itself before saying the
14
14
  // product is up. Three answers, all honest: up; started but not answering; not running.
15
15
 
16
- import { mkdirSync, readdirSync, readFileSync, renameSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
16
+ import { mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
17
17
  import { homedir } from "node:os";
18
- import { dirname, join } from "node:path";
18
+ import { dirname, isAbsolute, join, relative, sep } from "node:path";
19
19
 
20
20
  /**
21
21
  * Where the records live: one file per serving process, beside the settings and the revocation list.
@@ -34,6 +34,20 @@ export function pidAlive(pid) {
34
34
  try { process.kill(pid, 0); return true; } catch (e) { return e?.code === "EPERM"; }
35
35
  }
36
36
 
37
+ /** `dir` and its parents up to and including `made`, deepest first; [] when `dir` is not inside `made`. */
38
+ export function madeChain(dir, made, { realpath = realpathSync.native } = {}) {
39
+ if (!made) return [];
40
+ let steps;
41
+ try {
42
+ const r = relative(realpath(made), realpath(dir));
43
+ if (r.startsWith("..") || isAbsolute(r)) return [];
44
+ steps = r ? r.split(sep).length : 0;
45
+ } catch { return []; }
46
+ const out = [];
47
+ for (let d = dir, i = 0; i <= steps; i++, d = dirname(d)) out.push(d);
48
+ return out;
49
+ }
50
+
37
51
  /**
38
52
  * Record one serving start. Returns the function that removes the record; calling it twice is harmless,
39
53
  * so the caller can hang it on both its own shutdown and the process's `exit`.
@@ -49,16 +63,19 @@ export function recordRunning(rec, { dir = runningDir() } = {}) {
49
63
  const tmp = `${file}.tmp`;
50
64
  writeFileSync(tmp, `${JSON.stringify(rec, null, 2)}\n`, { mode: 0o600 });
51
65
  renameSync(tmp, file);
66
+ // THE FOLDERS TO TRY, WORKED OUT NOW AND BOUNDED BY WHAT mkdirSync MADE. The walk used to stop when a
67
+ // parent's spelling equalled `made`'s, and on Windows it never did, so it went on up and removed every
68
+ // empty folder to the drive's root: seen on a Windows runner, 2026-09-23, where it took the home the
69
+ // test had made. Both ends are asked of the machine itself, which spells them one way, and a record that
70
+ // is not inside what was made has nothing of its own to remove.
71
+ const chain = madeChain(dir, made);
52
72
  let gone = false;
53
73
  return () => {
54
74
  if (gone) return;
55
75
  gone = true;
56
76
  try { rmSync(file, { force: true }); } catch { /* already gone */ }
57
- if (made) {
58
- for (let d = dir; ; d = dirname(d)) {
59
- try { rmdirSync(d); } catch { break; } // not empty, or gone: either way, not ours to take
60
- if (d === made) break;
61
- }
77
+ for (const d of chain) {
78
+ try { rmdirSync(d); } catch { break; } // not empty, or gone: either way, not ours to take
62
79
  }
63
80
  };
64
81
  }
package/shared/scope.mjs CHANGED
@@ -5,7 +5,7 @@
5
5
  // cf-access.mjs is the OUTER transport gate: "is this a cordillera person?" (CF Access JWT, per request).
6
6
  // This module is the INNER gate: "WHAT may this principal do, on WHICH run?" Three principal kinds:
7
7
  // ops — full: every read tool across all runs + the write verbs (start_run/stop_run/feed_context)
8
- // + what-if (stdio only). Minted for clawdi/ops, and used unconditionally on the trusted
8
+ // + what-if (stdio only). Minted for the ops agent, and used unconditionally on the trusted
9
9
  // local stdio surface.
10
10
  // user — read-only, bound to EXACTLY ONE delivered run; cannot enumerate or read other runs and
11
11
  // cannot call any write/spend tool. This is what a report's "Ask your AI" link mints.
@@ -203,7 +203,7 @@ export const TOOL_SCOPES = {
203
203
  run_changes: {}, diff_artifact: {},
204
204
  list_runs: { crossRun: true, accountSafe: true, present: "scrub" }, search_runs: { crossRun: true },
205
205
  // list_profiles enumerates the firm's customer roster (not run-bound). Mark crossRun so it is allowed to
206
- // ops (clawdi/intake) + internal (CF-authed staff) but DENIED to a run-scoped user token (an external
206
+ // ops (intake) + internal (CF-authed staff) but DENIED to a run-scoped user token (an external
207
207
  // report viewer must not enumerate the client list).
208
208
  list_profiles: { crossRun: true },
209
209
  // plan_run RESOLVES a prospective search and describes it: depth, effective scope, the account's caps.
package/shared/wsl.mjs CHANGED
@@ -7,7 +7,7 @@
7
7
  import { existsSync, readFileSync } from "node:fs";
8
8
 
9
9
  /**
10
- * BOTH SIGNALS INJECTABLE, for the reason `platformEngineRefusal` gives: the readers this protects are the
10
+ * BOTH SIGNALS INJECTABLE, as every platform branch here is: the readers this protects are the
11
11
  * ones who cannot run this suite to find out, so a Linux runner has to be able to drive both answers
12
12
  * rather than read the source and agree with it.
13
13
  *