project-tiny-context-harness 0.8.17 → 0.11.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 (488) hide show
  1. package/README.md +93 -30
  2. package/assets/README.md +158 -44
  3. package/assets/README.zh-CN.md +88 -29
  4. package/assets/agents/AGENTS_CORE.md +2 -2
  5. package/assets/context_templates/context.toml +6 -1
  6. package/assets/runtime/windows-job-supervisor/formal_process_supervisor_native_helpers.cs +301 -0
  7. package/assets/runtime/windows-job-supervisor/formal_process_supervisor_native_run.cs +197 -0
  8. package/assets/runtime/windows-job-supervisor/formal_process_supervisor_native_types.cs +215 -0
  9. package/assets/runtime/windows-job-supervisor/windows_job_process_supervisor.ps1 +117 -0
  10. package/assets/skills/design-resource-authoring/SKILL.md +6 -3
  11. package/assets/skills/design-resource-authoring/references/authority-delta-assessment.md +52 -0
  12. package/assets/skills/design-resource-authoring/references/downstream-handoff.md +5 -1
  13. package/assets/skills/design-system-authoring/SKILL.md +23 -17
  14. package/assets/skills/design-system-authoring/references/authority-adoption.md +19 -9
  15. package/assets/skills/design-system-authoring/references/open-design-design-system-provider.md +4 -0
  16. package/assets/skills/long-task-workflow/SKILL.md +6 -6
  17. package/assets/skills/long-task-workflow/references/authority-lifecycle.md +10 -4
  18. package/assets/skills/long-task-workflow/references/contract-authoring.md +5 -5
  19. package/assets/skills/long-task-workflow/references/evidence-design.md +14 -3
  20. package/assets/skills/long-task-workflow/references/source-authoring.md +11 -8
  21. package/assets/tools/context_rules.json +53 -0
  22. package/assets/tools/validate_context.py +302 -77
  23. package/dist/cli.js +2 -1
  24. package/dist/commands/context-create.d.ts +1 -0
  25. package/dist/commands/context-create.js +90 -0
  26. package/dist/commands/context-inspect.d.ts +1 -0
  27. package/dist/commands/context-inspect.js +98 -0
  28. package/dist/commands/context-move.d.ts +1 -0
  29. package/dist/commands/context-move.js +78 -0
  30. package/dist/commands/context-register.d.ts +1 -0
  31. package/dist/commands/context-register.js +110 -0
  32. package/dist/commands/context-transaction.d.ts +1 -0
  33. package/dist/commands/context-transaction.js +84 -0
  34. package/dist/commands/context.d.ts +1 -0
  35. package/dist/commands/context.js +36 -0
  36. package/dist/commands/design-authority-delta.d.ts +1 -0
  37. package/dist/commands/design-authority-delta.js +53 -0
  38. package/dist/commands/design-authority.d.ts +1 -0
  39. package/dist/commands/design-authority.js +104 -0
  40. package/dist/commands/design-resource.js +8 -1
  41. package/dist/commands/doctor.d.ts +1 -1
  42. package/dist/commands/doctor.js +61 -3
  43. package/dist/commands/index.js +19 -2
  44. package/dist/commands/long-task-authoring.js +20 -2
  45. package/dist/commands/long-task-workdir.d.ts +2 -0
  46. package/dist/commands/long-task-workdir.js +23 -0
  47. package/dist/commands/long-task.js +75 -6
  48. package/dist/commands/route.d.ts +15 -0
  49. package/dist/commands/route.js +142 -0
  50. package/dist/index.d.ts +3 -13
  51. package/dist/index.js +3 -12
  52. package/dist/lib/cli-exit.d.ts +14 -0
  53. package/dist/lib/cli-exit.js +19 -0
  54. package/dist/lib/context-catalog/catalog-default-footprint.d.ts +3 -0
  55. package/dist/lib/context-catalog/catalog-default-footprint.js +53 -0
  56. package/dist/lib/context-catalog/catalog-diagnostics.d.ts +9 -0
  57. package/dist/lib/context-catalog/catalog-diagnostics.js +34 -0
  58. package/dist/lib/context-catalog/catalog-discovery.d.ts +7 -0
  59. package/dist/lib/context-catalog/catalog-discovery.js +81 -0
  60. package/dist/lib/context-catalog/catalog-load.d.ts +8 -0
  61. package/dist/lib/context-catalog/catalog-load.js +187 -0
  62. package/dist/lib/context-catalog/catalog-path-validation.d.ts +7 -0
  63. package/dist/lib/context-catalog/catalog-path-validation.js +62 -0
  64. package/dist/lib/context-catalog/catalog-paths.d.ts +11 -0
  65. package/dist/lib/context-catalog/catalog-paths.js +41 -0
  66. package/dist/lib/context-catalog/catalog-portable-contract.d.ts +15 -0
  67. package/dist/lib/context-catalog/catalog-portable-contract.js +68 -0
  68. package/dist/lib/context-catalog/catalog-staged-path-safety.d.ts +1 -0
  69. package/dist/lib/context-catalog/catalog-staged-path-safety.js +36 -0
  70. package/dist/lib/context-catalog/catalog-types.d.ts +40 -0
  71. package/dist/lib/context-catalog/catalog-types.js +1 -0
  72. package/dist/lib/context-catalog/catalog-validation.d.ts +9 -0
  73. package/dist/lib/context-catalog/catalog-validation.js +148 -0
  74. package/dist/lib/context-create/context-create-path.d.ts +2 -0
  75. package/dist/lib/context-create/context-create-path.js +30 -0
  76. package/dist/lib/context-create/context-create-template.d.ts +2 -0
  77. package/dist/lib/context-create/context-create-template.js +95 -0
  78. package/dist/lib/context-create/context-create-types.d.ts +28 -0
  79. package/dist/lib/context-create/context-create-types.js +1 -0
  80. package/dist/lib/context-create/context-create-write.d.ts +1 -0
  81. package/dist/lib/context-create/context-create-write.js +85 -0
  82. package/dist/lib/context-create/context-create.d.ts +2 -0
  83. package/dist/lib/context-create/context-create.js +84 -0
  84. package/dist/lib/context-default-footprint.d.ts +2 -3
  85. package/dist/lib/context-default-footprint.js +49 -57
  86. package/dist/lib/context-doctor/context-doctor-types.d.ts +16 -0
  87. package/dist/lib/context-doctor/context-doctor-types.js +15 -0
  88. package/dist/lib/context-doctor/context-doctor.d.ts +2 -0
  89. package/dist/lib/context-doctor/context-doctor.js +130 -0
  90. package/dist/lib/context-graph-snapshot.d.ts +5 -0
  91. package/dist/lib/context-graph-snapshot.js +46 -25
  92. package/dist/lib/context-inspect/context-inspect-projection.d.ts +9 -0
  93. package/dist/lib/context-inspect/context-inspect-projection.js +49 -0
  94. package/dist/lib/context-inspect/context-inspect-render.d.ts +2 -0
  95. package/dist/lib/context-inspect/context-inspect-render.js +29 -0
  96. package/dist/lib/context-inspect/context-inspect-types.d.ts +43 -0
  97. package/dist/lib/context-inspect/context-inspect-types.js +1 -0
  98. package/dist/lib/context-inspect/context-inspect.d.ts +2 -0
  99. package/dist/lib/context-inspect/context-inspect.js +104 -0
  100. package/dist/lib/context-manifest-schema.d.ts +1 -1
  101. package/dist/lib/context-manifest-schema.js +4 -20
  102. package/dist/lib/context-markdown/context-markdown-analysis.d.ts +15 -0
  103. package/dist/lib/context-markdown/context-markdown-analysis.js +245 -0
  104. package/dist/lib/context-markdown/context-markdown-extract.d.ts +7 -0
  105. package/dist/lib/context-markdown/context-markdown-extract.js +114 -0
  106. package/dist/lib/context-markdown/context-markdown-types.d.ts +57 -0
  107. package/dist/lib/context-markdown/context-markdown-types.js +1 -0
  108. package/dist/lib/context-move/context-move-input.d.ts +8 -0
  109. package/dist/lib/context-move/context-move-input.js +17 -0
  110. package/dist/lib/context-move/context-move-literal-scan.d.ts +20 -0
  111. package/dist/lib/context-move/context-move-literal-scan.js +213 -0
  112. package/dist/lib/context-move/context-move-live-validation.d.ts +3 -0
  113. package/dist/lib/context-move/context-move-live-validation.js +56 -0
  114. package/dist/lib/context-move/context-move-markdown-plan.d.ts +22 -0
  115. package/dist/lib/context-move/context-move-markdown-plan.js +39 -0
  116. package/dist/lib/context-move/context-move-projection.d.ts +3 -0
  117. package/dist/lib/context-move/context-move-projection.js +11 -0
  118. package/dist/lib/context-move/context-move-reference-validation.d.ts +11 -0
  119. package/dist/lib/context-move/context-move-reference-validation.js +64 -0
  120. package/dist/lib/context-move/context-move-render.d.ts +2 -0
  121. package/dist/lib/context-move/context-move-render.js +24 -0
  122. package/dist/lib/context-move/context-move-support.d.ts +10 -0
  123. package/dist/lib/context-move/context-move-support.js +88 -0
  124. package/dist/lib/context-move/context-move-transaction-plan.d.ts +24 -0
  125. package/dist/lib/context-move/context-move-transaction-plan.js +108 -0
  126. package/dist/lib/context-move/context-move-types.d.ts +74 -0
  127. package/dist/lib/context-move/context-move-types.js +1 -0
  128. package/dist/lib/context-move/context-move.d.ts +8 -0
  129. package/dist/lib/context-move/context-move.js +180 -0
  130. package/dist/lib/context-mutation/manifest-lossless-patch.d.ts +28 -0
  131. package/dist/lib/context-mutation/manifest-lossless-patch.js +208 -0
  132. package/dist/lib/context-mutation/markdown-link-patch.d.ts +34 -0
  133. package/dist/lib/context-mutation/markdown-link-patch.js +143 -0
  134. package/dist/lib/context-mutation/markdown-link-spans.d.ts +10 -0
  135. package/dist/lib/context-mutation/markdown-link-spans.js +179 -0
  136. package/dist/lib/context-mutation/mutation-cas.d.ts +13 -0
  137. package/dist/lib/context-mutation/mutation-cas.js +365 -0
  138. package/dist/lib/context-mutation/mutation-command-support.d.ts +12 -0
  139. package/dist/lib/context-mutation/mutation-command-support.js +57 -0
  140. package/dist/lib/context-mutation/mutation-commit.d.ts +12 -0
  141. package/dist/lib/context-mutation/mutation-commit.js +89 -0
  142. package/dist/lib/context-mutation/mutation-directories.d.ts +5 -0
  143. package/dist/lib/context-mutation/mutation-directories.js +56 -0
  144. package/dist/lib/context-mutation/mutation-file-state.d.ts +14 -0
  145. package/dist/lib/context-mutation/mutation-file-state.js +137 -0
  146. package/dist/lib/context-mutation/mutation-journal-file-validation.d.ts +1 -0
  147. package/dist/lib/context-mutation/mutation-journal-file-validation.js +106 -0
  148. package/dist/lib/context-mutation/mutation-journal-io.d.ts +5 -0
  149. package/dist/lib/context-mutation/mutation-journal-io.js +55 -0
  150. package/dist/lib/context-mutation/mutation-journal-storage.d.ts +18 -0
  151. package/dist/lib/context-mutation/mutation-journal-storage.js +283 -0
  152. package/dist/lib/context-mutation/mutation-journal-validation-support.d.ts +16 -0
  153. package/dist/lib/context-mutation/mutation-journal-validation-support.js +140 -0
  154. package/dist/lib/context-mutation/mutation-journal-validation.d.ts +3 -0
  155. package/dist/lib/context-mutation/mutation-journal-validation.js +177 -0
  156. package/dist/lib/context-mutation/mutation-journal.d.ts +8 -0
  157. package/dist/lib/context-mutation/mutation-journal.js +111 -0
  158. package/dist/lib/context-mutation/mutation-live-validation.d.ts +3 -0
  159. package/dist/lib/context-mutation/mutation-live-validation.js +51 -0
  160. package/dist/lib/context-mutation/mutation-long-task-guard.d.ts +6 -0
  161. package/dist/lib/context-mutation/mutation-long-task-guard.js +57 -0
  162. package/dist/lib/context-mutation/mutation-recovery.d.ts +4 -0
  163. package/dist/lib/context-mutation/mutation-recovery.js +189 -0
  164. package/dist/lib/context-mutation/mutation-staged-fs.d.ts +5 -0
  165. package/dist/lib/context-mutation/mutation-staged-fs.js +56 -0
  166. package/dist/lib/context-mutation/mutation-types.d.ts +103 -0
  167. package/dist/lib/context-mutation/mutation-types.js +1 -0
  168. package/dist/lib/context-register/context-register-input.d.ts +11 -0
  169. package/dist/lib/context-register/context-register-input.js +43 -0
  170. package/dist/lib/context-register/context-register-render.d.ts +2 -0
  171. package/dist/lib/context-register/context-register-render.js +21 -0
  172. package/dist/lib/context-register/context-register-support.d.ts +6 -0
  173. package/dist/lib/context-register/context-register-support.js +46 -0
  174. package/dist/lib/context-register/context-register-types.d.ts +46 -0
  175. package/dist/lib/context-register/context-register-types.js +1 -0
  176. package/dist/lib/context-register/context-register.d.ts +8 -0
  177. package/dist/lib/context-register/context-register.js +155 -0
  178. package/dist/lib/context-router/context-route-budget.d.ts +15 -0
  179. package/dist/lib/context-router/context-route-budget.js +14 -0
  180. package/dist/lib/context-router/context-route-candidates.d.ts +15 -0
  181. package/dist/lib/context-router/context-route-candidates.js +112 -0
  182. package/dist/lib/context-router/context-route-order.d.ts +6 -0
  183. package/dist/lib/context-router/context-route-order.js +53 -0
  184. package/dist/lib/context-router/context-route-paths.d.ts +16 -0
  185. package/dist/lib/context-router/context-route-paths.js +109 -0
  186. package/dist/lib/context-router/context-route-render.d.ts +2 -0
  187. package/dist/lib/context-router/context-route-render.js +32 -0
  188. package/dist/lib/context-router/context-route-scan.d.ts +18 -0
  189. package/dist/lib/context-router/context-route-scan.js +156 -0
  190. package/dist/lib/context-router/context-route-selection.d.ts +16 -0
  191. package/dist/lib/context-router/context-route-selection.js +72 -0
  192. package/dist/lib/context-router/context-route-terms.d.ts +13 -0
  193. package/dist/lib/context-router/context-route-terms.js +202 -0
  194. package/dist/lib/context-router/context-route-types.d.ts +101 -0
  195. package/dist/lib/context-router/context-route-types.js +1 -0
  196. package/dist/lib/context-router/context-route.d.ts +2 -0
  197. package/dist/lib/context-router/context-route.js +127 -0
  198. package/dist/lib/context-units-migration.d.ts +13 -0
  199. package/dist/lib/context-units-migration.js +217 -0
  200. package/dist/lib/design-authority-binding.d.ts +7 -0
  201. package/dist/lib/design-authority-binding.js +96 -0
  202. package/dist/lib/design-authority-closure.d.ts +3 -0
  203. package/dist/lib/design-authority-closure.js +201 -0
  204. package/dist/lib/design-authority-delta-codec-primitives.d.ts +10 -0
  205. package/dist/lib/design-authority-delta-codec-primitives.js +58 -0
  206. package/dist/lib/design-authority-delta-codec.d.ts +2 -0
  207. package/dist/lib/design-authority-delta-codec.js +193 -0
  208. package/dist/lib/design-authority-delta-types.d.ts +65 -0
  209. package/dist/lib/design-authority-delta-types.js +6 -0
  210. package/dist/lib/design-authority-delta-validation.d.ts +2 -0
  211. package/dist/lib/design-authority-delta-validation.js +16 -0
  212. package/dist/lib/design-authority-digest.d.ts +8 -0
  213. package/dist/lib/design-authority-digest.js +36 -0
  214. package/dist/lib/design-authority-files.d.ts +9 -0
  215. package/dist/lib/design-authority-files.js +62 -0
  216. package/dist/lib/design-authority-format.d.ts +2 -0
  217. package/dist/lib/design-authority-format.js +93 -0
  218. package/dist/lib/design-authority-links.d.ts +10 -0
  219. package/dist/lib/design-authority-links.js +137 -0
  220. package/dist/lib/design-authority-manifest.d.ts +4 -0
  221. package/dist/lib/design-authority-manifest.js +144 -0
  222. package/dist/lib/design-authority-tokens.d.ts +9 -0
  223. package/dist/lib/design-authority-tokens.js +45 -0
  224. package/dist/lib/design-authority-types.d.ts +80 -0
  225. package/dist/lib/design-authority-types.js +23 -0
  226. package/dist/lib/design-md-tool-adapter.d.ts +9 -0
  227. package/dist/lib/design-md-tool-adapter.js +152 -0
  228. package/dist/lib/design-md-tool-normalization.d.ts +7 -0
  229. package/dist/lib/design-md-tool-normalization.js +78 -0
  230. package/dist/lib/design-md-tool-types.d.ts +99 -0
  231. package/dist/lib/design-md-tool-types.js +8 -0
  232. package/dist/lib/design-resource-handoff-input-types.d.ts +1 -1
  233. package/dist/lib/design-resource-handoff-manifest-projection.js +3 -0
  234. package/dist/lib/design-resource-handoff-shape.js +14 -2
  235. package/dist/lib/design-resource-handoff-types.d.ts +3 -0
  236. package/dist/lib/design-resource-handoff-validation.js +16 -4
  237. package/dist/lib/design-resource-implementation-feasibility-validation-support.js +1 -1
  238. package/dist/lib/design-resource-recovery-current.js +22 -0
  239. package/dist/lib/design-resource-recovery-shape.js +64 -7
  240. package/dist/lib/design-resource-recovery-types.d.ts +4 -1
  241. package/dist/lib/design-resource-symbolic-fact-shape.js +7 -1
  242. package/dist/lib/design-resource-symbolic-fact-types.d.ts +3 -0
  243. package/dist/lib/design-resource-symbolic-fact-validation.js +15 -3
  244. package/dist/lib/doctor.d.ts +2 -1
  245. package/dist/lib/doctor.js +29 -1
  246. package/dist/lib/fs.js +1 -1
  247. package/dist/lib/long-task-acceptance-reachability-claims.d.ts +2 -0
  248. package/dist/lib/long-task-acceptance-reachability-claims.js +279 -0
  249. package/dist/lib/long-task-acceptance-reachability-design.d.ts +2 -0
  250. package/dist/lib/long-task-acceptance-reachability-design.js +96 -0
  251. package/dist/lib/long-task-acceptance-reachability-external.d.ts +9 -0
  252. package/dist/lib/long-task-acceptance-reachability-external.js +123 -0
  253. package/dist/lib/long-task-acceptance-reachability-helpers.d.ts +64 -0
  254. package/dist/lib/long-task-acceptance-reachability-helpers.js +473 -0
  255. package/dist/lib/long-task-acceptance-reachability-semantic.d.ts +2 -0
  256. package/dist/lib/long-task-acceptance-reachability-semantic.js +122 -0
  257. package/dist/lib/long-task-acceptance-reachability-types.d.ts +91 -0
  258. package/dist/lib/long-task-acceptance-reachability-types.js +1 -0
  259. package/dist/lib/long-task-acceptance-reachability.d.ts +4 -0
  260. package/dist/lib/long-task-acceptance-reachability.js +115 -0
  261. package/dist/lib/long-task-activation-validation.d.ts +6 -0
  262. package/dist/lib/long-task-activation-validation.js +72 -69
  263. package/dist/lib/long-task-active-authority-lock-context.d.ts +4 -0
  264. package/dist/lib/long-task-active-authority-lock-context.js +29 -0
  265. package/dist/lib/long-task-applicability-identity.d.ts +25 -0
  266. package/dist/lib/long-task-applicability-identity.js +60 -0
  267. package/dist/lib/long-task-authoring-preflight-diagnostics.js +8 -0
  268. package/dist/lib/long-task-authoring-preflight-types.d.ts +2 -0
  269. package/dist/lib/long-task-authoring-preflight-types.js +9 -0
  270. package/dist/lib/long-task-authoring-preflight.js +18 -2
  271. package/dist/lib/long-task-authority-material-diff.js +4 -0
  272. package/dist/lib/long-task-authority-materials.js +19 -0
  273. package/dist/lib/long-task-authority-policy.d.ts +3 -0
  274. package/dist/lib/long-task-authority-policy.js +3 -0
  275. package/dist/lib/long-task-authority-revision-details.js +2 -1
  276. package/dist/lib/long-task-authority-types.d.ts +2 -0
  277. package/dist/lib/long-task-authority.js +2 -0
  278. package/dist/lib/long-task-check-shape.js +6 -1
  279. package/dist/lib/long-task-claim-definitions.js +1 -3
  280. package/dist/lib/long-task-claim-semantic-proof-floor.d.ts +3 -0
  281. package/dist/lib/long-task-claim-semantic-proof-floor.js +78 -0
  282. package/dist/lib/long-task-claims.d.ts +0 -18
  283. package/dist/lib/long-task-claims.js +15 -14
  284. package/dist/lib/long-task-command-process.js +3 -0
  285. package/dist/lib/long-task-compact-authoring.js +3 -0
  286. package/dist/lib/long-task-compact-projections.js +10 -0
  287. package/dist/lib/long-task-complete-delivery-evidence-types.d.ts +38 -0
  288. package/dist/lib/long-task-complete-delivery-evidence-types.js +1 -0
  289. package/dist/lib/long-task-completion-types.d.ts +109 -0
  290. package/dist/lib/long-task-completion-types.js +1 -0
  291. package/dist/lib/long-task-conformance-policy.d.ts +2 -1
  292. package/dist/lib/long-task-conformance-policy.js +11 -4
  293. package/dist/lib/long-task-context-authority-topology.js +6 -4
  294. package/dist/lib/long-task-contract-types.d.ts +52 -1
  295. package/dist/lib/long-task-counterfactual-sandbox.d.ts +7 -1
  296. package/dist/lib/long-task-counterfactual-sandbox.js +86 -6
  297. package/dist/lib/long-task-delivery-compiler-preflight.d.ts +24 -0
  298. package/dist/lib/long-task-delivery-compiler-preflight.js +32 -0
  299. package/dist/lib/long-task-delivery-compiler.d.ts +1 -0
  300. package/dist/lib/long-task-delivery-compiler.js +59 -44
  301. package/dist/lib/long-task-delivery-parser.d.ts +3 -0
  302. package/dist/lib/long-task-delivery-parser.js +26 -8
  303. package/dist/lib/long-task-delivery-types.d.ts +2 -0
  304. package/dist/lib/long-task-delivery-types.js +2 -0
  305. package/dist/lib/long-task-delivery-validation.d.ts +6 -1
  306. package/dist/lib/long-task-delivery-validation.js +19 -4
  307. package/dist/lib/long-task-design-feasibility-binding.d.ts +1 -0
  308. package/dist/lib/long-task-design-feasibility-binding.js +3 -3
  309. package/dist/lib/long-task-design-feasibility-source-closure.js +11 -2
  310. package/dist/lib/long-task-design-obligation.d.ts +50 -0
  311. package/dist/lib/long-task-design-obligation.js +99 -0
  312. package/dist/lib/long-task-design-resource-handoff.d.ts +3 -1
  313. package/dist/lib/long-task-design-resource-handoff.js +36 -12
  314. package/dist/lib/long-task-design-resource-method-binding.js +12 -0
  315. package/dist/lib/long-task-effective-external-takeover.d.ts +15 -0
  316. package/dist/lib/long-task-effective-external-takeover.js +109 -0
  317. package/dist/lib/long-task-effective-external-ui-takeover.d.ts +5 -0
  318. package/dist/lib/long-task-effective-external-ui-takeover.js +117 -0
  319. package/dist/lib/long-task-evidence-capability-codec.js +91 -0
  320. package/dist/lib/long-task-evidence-capability-runtime.js +62 -14
  321. package/dist/lib/long-task-evidence-capability-types.d.ts +3 -2
  322. package/dist/lib/long-task-evidence-v2.d.ts +6 -1
  323. package/dist/lib/long-task-evidence-v2.js +253 -170
  324. package/dist/lib/long-task-execution-observation.d.ts +7 -0
  325. package/dist/lib/long-task-execution-observation.js +21 -4
  326. package/dist/lib/long-task-expected-authority.d.ts +4 -0
  327. package/dist/lib/long-task-expected-authority.js +126 -0
  328. package/dist/lib/long-task-external-confirmation-artifacts.d.ts +9 -0
  329. package/dist/lib/long-task-external-confirmation-artifacts.js +138 -0
  330. package/dist/lib/long-task-external-confirmation-attestation.d.ts +20 -0
  331. package/dist/lib/long-task-external-confirmation-attestation.js +115 -0
  332. package/dist/lib/long-task-external-confirmation-challenge.d.ts +23 -0
  333. package/dist/lib/long-task-external-confirmation-challenge.js +164 -0
  334. package/dist/lib/long-task-external-confirmation-context.d.ts +14 -0
  335. package/dist/lib/long-task-external-confirmation-context.js +53 -0
  336. package/dist/lib/long-task-external-confirmation-evaluation.d.ts +11 -0
  337. package/dist/lib/long-task-external-confirmation-evaluation.js +454 -0
  338. package/dist/lib/long-task-external-confirmation-expected.d.ts +8 -0
  339. package/dist/lib/long-task-external-confirmation-expected.js +200 -0
  340. package/dist/lib/long-task-external-confirmation-identity.d.ts +10 -0
  341. package/dist/lib/long-task-external-confirmation-identity.js +77 -0
  342. package/dist/lib/long-task-external-confirmation-plan.d.ts +25 -0
  343. package/dist/lib/long-task-external-confirmation-plan.js +148 -0
  344. package/dist/lib/long-task-external-confirmation-preparation.d.ts +4 -0
  345. package/dist/lib/long-task-external-confirmation-preparation.js +100 -0
  346. package/dist/lib/long-task-external-confirmation-shape.d.ts +8 -0
  347. package/dist/lib/long-task-external-confirmation-shape.js +387 -0
  348. package/dist/lib/long-task-external-confirmation-state.d.ts +10 -0
  349. package/dist/lib/long-task-external-confirmation-state.js +109 -0
  350. package/dist/lib/long-task-external-confirmation-types.d.ts +195 -0
  351. package/dist/lib/long-task-external-confirmation-types.js +1 -0
  352. package/dist/lib/long-task-final-integrity.d.ts +2 -0
  353. package/dist/lib/long-task-final-integrity.js +21 -10
  354. package/dist/lib/long-task-final-v2.d.ts +7 -2
  355. package/dist/lib/long-task-final-v2.js +179 -55
  356. package/dist/lib/long-task-finalization-identity.d.ts +27 -0
  357. package/dist/lib/long-task-finalization-identity.js +58 -0
  358. package/dist/lib/long-task-finding-context.d.ts +1 -1
  359. package/dist/lib/long-task-finding-context.js +139 -13
  360. package/dist/lib/long-task-freshness.d.ts +27 -0
  361. package/dist/lib/long-task-freshness.js +128 -5
  362. package/dist/lib/long-task-git.js +3 -3
  363. package/dist/lib/long-task-material-input-closure.d.ts +3 -0
  364. package/dist/lib/long-task-material-input-closure.js +92 -0
  365. package/dist/lib/long-task-obligation-authority-resolution.d.ts +12 -0
  366. package/dist/lib/long-task-obligation-authority-resolution.js +57 -0
  367. package/dist/lib/long-task-obligation-semantic-identity.d.ts +16 -0
  368. package/dist/lib/long-task-obligation-semantic-identity.js +116 -0
  369. package/dist/lib/long-task-observation-authority.d.ts +11 -0
  370. package/dist/lib/long-task-observation-authority.js +137 -6
  371. package/dist/lib/long-task-process-table.d.ts +2 -5
  372. package/dist/lib/long-task-process-table.js +21 -53
  373. package/dist/lib/long-task-process-tree.d.ts +0 -1
  374. package/dist/lib/long-task-process-tree.js +24 -54
  375. package/dist/lib/long-task-proof-adequacy.d.ts +12 -0
  376. package/dist/lib/long-task-proof-adequacy.js +57 -0
  377. package/dist/lib/long-task-proof-capability-floor.d.ts +6 -0
  378. package/dist/lib/long-task-proof-capability-floor.js +137 -0
  379. package/dist/lib/long-task-repair-frontier-checks.d.ts +8 -0
  380. package/dist/lib/long-task-repair-frontier-checks.js +93 -0
  381. package/dist/lib/long-task-repair-frontier-groups.d.ts +2 -0
  382. package/dist/lib/long-task-repair-frontier-groups.js +64 -0
  383. package/dist/lib/long-task-repair-frontier-utils.d.ts +6 -0
  384. package/dist/lib/long-task-repair-frontier-utils.js +27 -0
  385. package/dist/lib/long-task-repair-frontier.d.ts +14 -0
  386. package/dist/lib/long-task-repair-frontier.js +132 -0
  387. package/dist/lib/long-task-risk.d.ts +3 -2
  388. package/dist/lib/long-task-risk.js +73 -24
  389. package/dist/lib/long-task-root-shape.js +148 -8
  390. package/dist/lib/long-task-runner-freeze.d.ts +2 -1
  391. package/dist/lib/long-task-runner-freeze.js +23 -8
  392. package/dist/lib/long-task-runtime-types.d.ts +34 -40
  393. package/dist/lib/long-task-semantic-assurance-policy.js +2 -11
  394. package/dist/lib/long-task-semantic-contract-types.d.ts +2 -1
  395. package/dist/lib/long-task-semantic-drift-migration.js +48 -2
  396. package/dist/lib/long-task-semantic-fact-binding-types.d.ts +20 -0
  397. package/dist/lib/long-task-semantic-fact-closure.d.ts +5 -1
  398. package/dist/lib/long-task-semantic-fact-closure.js +33 -5
  399. package/dist/lib/long-task-semantic-fact-contract-closure.js +176 -1
  400. package/dist/lib/long-task-semantic-fact-contract-proofs.js +18 -1
  401. package/dist/lib/long-task-semantic-fact-input-closure.d.ts +16 -2
  402. package/dist/lib/long-task-semantic-fact-input-closure.js +138 -15
  403. package/dist/lib/long-task-semantic-fact-provenance-closure.js +1 -1
  404. package/dist/lib/long-task-semantic-fact-shape.d.ts +2 -1
  405. package/dist/lib/long-task-semantic-fact-shape.js +35 -1
  406. package/dist/lib/long-task-semantic-proof-adequacy.d.ts +2 -0
  407. package/dist/lib/long-task-semantic-proof-adequacy.js +19 -0
  408. package/dist/lib/long-task-semantic-proof-profile.d.ts +5 -0
  409. package/dist/lib/long-task-semantic-proof-profile.js +187 -0
  410. package/dist/lib/long-task-shape-primitives.d.ts +1 -1
  411. package/dist/lib/long-task-shape-primitives.js +5 -0
  412. package/dist/lib/long-task-source-anchors.d.ts +10 -0
  413. package/dist/lib/long-task-source-anchors.js +102 -0
  414. package/dist/lib/long-task-source-authority-types.d.ts +46 -0
  415. package/dist/lib/long-task-source-claim-validation.js +36 -0
  416. package/dist/lib/long-task-source-conservation-facts.d.ts +8 -0
  417. package/dist/lib/long-task-source-conservation-facts.js +57 -0
  418. package/dist/lib/long-task-source-conservation-types.d.ts +34 -0
  419. package/dist/lib/long-task-source-conservation-types.js +1 -0
  420. package/dist/lib/long-task-source-conservation.d.ts +7 -0
  421. package/dist/lib/long-task-source-conservation.js +110 -0
  422. package/dist/lib/long-task-source-fragments.d.ts +6 -0
  423. package/dist/lib/long-task-source-fragments.js +219 -0
  424. package/dist/lib/long-task-source-projection-resolution.d.ts +5 -0
  425. package/dist/lib/long-task-source-projection-resolution.js +57 -0
  426. package/dist/lib/long-task-source-projection-validation.d.ts +17 -0
  427. package/dist/lib/long-task-source-projection-validation.js +154 -0
  428. package/dist/lib/long-task-source-shape.js +14 -6
  429. package/dist/lib/long-task-source-supersession.d.ts +5 -0
  430. package/dist/lib/long-task-source-supersession.js +138 -0
  431. package/dist/lib/long-task-stage-policy.d.ts +7 -2
  432. package/dist/lib/long-task-stage-policy.js +67 -23
  433. package/dist/lib/long-task-state.d.ts +18 -4
  434. package/dist/lib/long-task-state.js +319 -33
  435. package/dist/lib/long-task-static-observation-freeze.js +4 -3
  436. package/dist/lib/long-task-status-projection.d.ts +3 -1
  437. package/dist/lib/long-task-status-projection.js +44 -13
  438. package/dist/lib/long-task-status-v2.d.ts +10 -6
  439. package/dist/lib/long-task-status-v2.js +70 -58
  440. package/dist/lib/long-task-target-policy.d.ts +8 -3
  441. package/dist/lib/long-task-target-policy.js +40 -9
  442. package/dist/lib/long-task-terminal-finalization.d.ts +12 -0
  443. package/dist/lib/long-task-terminal-finalization.js +190 -0
  444. package/dist/lib/long-task-ui-design-policy.js +15 -4
  445. package/dist/lib/long-task-verifier-counterfactuals.d.ts +11 -0
  446. package/dist/lib/long-task-verifier-counterfactuals.js +96 -0
  447. package/dist/lib/long-task-verifier-execution.d.ts +9 -0
  448. package/dist/lib/long-task-verifier-execution.js +67 -0
  449. package/dist/lib/long-task-verifier-identity.js +16 -5
  450. package/dist/lib/long-task-verifier-v2.js +52 -65
  451. package/dist/lib/long-task-windows-job-supervisor-helper.d.ts +1 -0
  452. package/dist/lib/long-task-windows-job-supervisor-helper.js +104 -0
  453. package/dist/lib/long-task-windows-job-supervisor-protocol.d.ts +28 -0
  454. package/dist/lib/long-task-windows-job-supervisor-protocol.js +124 -0
  455. package/dist/lib/long-task-windows-job-supervisor-result.d.ts +11 -0
  456. package/dist/lib/long-task-windows-job-supervisor-result.js +152 -0
  457. package/dist/lib/long-task-windows-job-supervisor.d.ts +2 -0
  458. package/dist/lib/long-task-windows-job-supervisor.js +126 -0
  459. package/dist/lib/long-task-workspace-scope.d.ts +1 -0
  460. package/dist/lib/long-task-workspace-scope.js +4 -1
  461. package/dist/lib/long-task-workspace.d.ts +1 -0
  462. package/dist/lib/long-task-workspace.js +10 -0
  463. package/dist/lib/migrations.js +43 -2
  464. package/dist/lib/repository-path-safety.d.ts +1 -0
  465. package/dist/lib/repository-path-safety.js +3 -3
  466. package/dist/lib/semantic-fact-input-shape.d.ts +7 -2
  467. package/dist/lib/semantic-fact-input-shape.js +25 -1
  468. package/dist/lib/semantic-fact-inventory-types.d.ts +8 -2
  469. package/dist/lib/semantic-fact-policy-census.d.ts +1 -1
  470. package/dist/lib/semantic-fact-policy-census.js +5 -2
  471. package/dist/lib/semantic-fact-policy.d.ts +1 -1
  472. package/dist/lib/semantic-fact-policy.js +2 -2
  473. package/dist/lib/semantic-fact-proof-shape.d.ts +1 -1
  474. package/dist/lib/semantic-fact-property-shape.d.ts +1 -1
  475. package/dist/lib/validators.d.ts +3 -0
  476. package/dist/lib/validators.js +45 -157
  477. package/dist/public-api-core.d.ts +12 -0
  478. package/dist/public-api-core.js +12 -0
  479. package/dist/public-api-long-task.d.ts +10 -0
  480. package/dist/public-api-long-task.js +10 -0
  481. package/dist/public-types.d.ts +5 -1
  482. package/dist/schemas/design-authority-delta-assessment-v1.schema.json +191 -0
  483. package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +166 -2
  484. package/dist/schemas/long-task-external-confirmation-record-v1.schema.json +155 -0
  485. package/dist/schemas/long-task-external-confirmation-record-v2.schema.json +209 -0
  486. package/migrations/README.md +99 -0
  487. package/package.json +7 -5
  488. package/source-mappings.yaml +18 -0
@@ -3,9 +3,11 @@
3
3
 
4
4
  from pathlib import Path, PureWindowsPath
5
5
  import json
6
+ import os
6
7
  import re
7
8
  import subprocess
8
9
  import sys
10
+ import unicodedata
9
11
 
10
12
  try:
11
13
  import tomllib
@@ -16,6 +18,54 @@ except ImportError: # Python 3.10 compatibility; Node is already required by ty
16
18
  ROOT = Path.cwd().resolve()
17
19
  CONTEXT_ROOT = ROOT / "project_context"
18
20
 
21
+ # The portable validator is a UTF-8 command-line surface on every supported
22
+ # platform. Windows pipe encodings otherwise depend on the active locale and
23
+ # can corrupt the canonical NFC paths that TypeScript and Python are required
24
+ # to report identically.
25
+ if hasattr(sys.stdout, "reconfigure"):
26
+ sys.stdout.reconfigure(encoding="utf-8", errors="strict")
27
+ if hasattr(sys.stderr, "reconfigure"):
28
+ sys.stderr.reconfigure(encoding="utf-8", errors="strict")
29
+
30
+
31
+ def load_context_rules():
32
+ rules_path = Path(__file__).resolve().with_name("context_rules.json")
33
+ try:
34
+ value = json.loads(rules_path.read_text(encoding="utf-8"))
35
+ except (OSError, UnicodeError, json.JSONDecodeError) as error:
36
+ raise RuntimeError(f"unable to load portable Context rules from {rules_path.name}: {error}") from error
37
+ required_arrays = (
38
+ "roles",
39
+ "read_policies",
40
+ "legacy_read_policies",
41
+ "top_level_fields",
42
+ "area_fields",
43
+ "context_fields",
44
+ )
45
+ for field in required_arrays:
46
+ entries = value.get(field)
47
+ if (
48
+ not isinstance(entries, list)
49
+ or any(not isinstance(entry, str) or not entry.strip() for entry in entries)
50
+ or len(entries) != len(set(entries))
51
+ ):
52
+ raise RuntimeError(f"portable Context rules field {field} must contain unique non-empty strings")
53
+ aliases = value.get("role_aliases")
54
+ if not isinstance(aliases, dict) or any(
55
+ not isinstance(key, str)
56
+ or not key.strip()
57
+ or not isinstance(target, str)
58
+ or target not in value["roles"]
59
+ for key, target in aliases.items()
60
+ ):
61
+ raise RuntimeError("portable Context rules role_aliases are invalid")
62
+ if any(policy not in value["read_policies"] for policy in value["legacy_read_policies"]):
63
+ raise RuntimeError("portable Context legacy read policies must be a subset of read_policies")
64
+ return value
65
+
66
+
67
+ CONTEXT_RULES = load_context_rules()
68
+
19
69
  GLOBAL_CHECKS = [
20
70
  ("project goal", ["project goal", "项目目标", "目标"]),
21
71
  ("boundaries", ["non-goals", "boundaries", "非目标", "边界"]),
@@ -35,28 +85,13 @@ ARCHITECTURE_CHECKS = [
35
85
  ("verification implications", ["verification implications", "验证影响", "验证入口"]),
36
86
  ]
37
87
 
38
- VALID_ROLES = {
39
- "global",
40
- "architecture",
41
- "area",
42
- "domain",
43
- "subdomain",
44
- "foundation",
45
- "archive",
46
- "contract",
47
- "verification",
48
- "deployment",
49
- "implementation-index",
50
- "decision-rationale",
51
- }
52
- ROLE_ALIASES = {
53
- "implementation_index": "implementation-index",
54
- "decision_rationale": "decision-rationale",
55
- }
56
- READ_POLICIES = {"default", "always", "optional", "on-demand", "never-default"}
57
- TOP_LEVEL_FIELDS = {"areas", "context"}
58
- AREA_FIELDS = {"id", "root", "context", "kind", "default", "forbidden_runtime_dependencies"}
59
- CONTEXT_FIELDS = {"path", "role", "read_when", "read_policy", "triggers", "default_children"}
88
+ VALID_ROLES = set(CONTEXT_RULES["roles"])
89
+ ROLE_ALIASES = CONTEXT_RULES["role_aliases"]
90
+ READ_POLICIES = set(CONTEXT_RULES["read_policies"])
91
+ LEGACY_READ_POLICIES = set(CONTEXT_RULES["legacy_read_policies"])
92
+ TOP_LEVEL_FIELDS = set(CONTEXT_RULES["top_level_fields"])
93
+ AREA_FIELDS = set(CONTEXT_RULES["area_fields"])
94
+ CONTEXT_FIELDS = set(CONTEXT_RULES["context_fields"])
60
95
  CONFIG_CANDIDATES = [
61
96
  ".agent/config.yaml",
62
97
  ".codex/config.yaml",
@@ -89,10 +124,18 @@ def normalize_role(value):
89
124
  return role if role in VALID_ROLES else None
90
125
 
91
126
 
92
- def normalize_context_path(value):
127
+ def normalize_context_path_spelling(value):
93
128
  return value.replace("\\", "/").removeprefix("./")
94
129
 
95
130
 
131
+ def normalize_context_path(value):
132
+ return unicodedata.normalize("NFC", normalize_context_path_spelling(value))
133
+
134
+
135
+ def portable_context_path_case_key(value):
136
+ return normalize_context_path(value).lower()
137
+
138
+
96
139
  def parse_front_matter(text):
97
140
  lines = text.splitlines()
98
141
  if not lines or lines[0].strip() != "---":
@@ -149,13 +192,45 @@ def parse_toml(content):
149
192
  return tomllib.loads(content)
150
193
  except tomllib.TOMLDecodeError as error:
151
194
  raise ValueError(str(error)) from error
152
- script = "import('smol-toml').then(({parse})=>{let s='';process.stdin.setEncoding('utf8');process.stdin.on('data',c=>s+=c);process.stdin.on('end',()=>process.stdout.write(JSON.stringify(parse(s))))}).catch(e=>{console.error(e.message);process.exit(1)})"
195
+ script = """
196
+ import('node:module').then(async ({ createRequire }) => {
197
+ const { pathToFileURL } = await import('node:url');
198
+ const { resolve } = await import('node:path');
199
+ const roots = JSON.parse(process.env.TY_CONTEXT_NODE_SEARCH_ROOTS || '[]');
200
+ let modulePath;
201
+ for (const root of roots) {
202
+ try {
203
+ modulePath = createRequire(resolve(root, 'package.json')).resolve('smol-toml');
204
+ break;
205
+ } catch {}
206
+ }
207
+ if (!modulePath) throw new Error('unable to resolve smol-toml from the project or portable-tool ancestors');
208
+ const { parse } = await import(pathToFileURL(modulePath).href);
209
+ let source = '';
210
+ process.stdin.setEncoding('utf8');
211
+ process.stdin.on('data', chunk => source += chunk);
212
+ process.stdin.on('end', () => process.stdout.write(JSON.stringify(parse(source))));
213
+ }).catch(error => {
214
+ console.error(error.message);
215
+ process.exit(1);
216
+ });
217
+ """
218
+ search_roots = []
219
+ for candidate in (ROOT, *Path(__file__).resolve().parents):
220
+ value = str(candidate)
221
+ if value not in search_roots:
222
+ search_roots.append(value)
223
+ environment = dict(os.environ)
224
+ environment["TY_CONTEXT_NODE_SEARCH_ROOTS"] = json.dumps(search_roots)
153
225
  result = subprocess.run(
154
226
  ["node", "--input-type=module", "--eval", script],
155
227
  input=content,
156
228
  text=True,
229
+ encoding="utf-8",
230
+ errors="strict",
157
231
  capture_output=True,
158
232
  cwd=ROOT,
233
+ env=environment,
159
234
  check=False,
160
235
  )
161
236
  if result.returncode != 0:
@@ -186,8 +261,6 @@ def string_array(entry, key, errors):
186
261
  if not isinstance(value, list) or any(not isinstance(item, str) or not item.strip() for item in value):
187
262
  errors.append(f"project_context/context.toml line {entry['line']} {key} must be an array of non-empty strings")
188
263
  return []
189
- if len(value) != len(set(value)):
190
- errors.append(f"project_context/context.toml line {entry['line']} {key} must not contain duplicates")
191
264
  return value
192
265
 
193
266
 
@@ -199,12 +272,18 @@ def is_relative_to(target, root):
199
272
  return False
200
273
 
201
274
 
202
- def safe_manifest_path(raw, allowed_root, label, expected, errors):
203
- normalized = raw.replace("\\", "/")
275
+ def safe_manifest_path(raw, allowed_root, label, expected, errors, physical_files=None):
276
+ normalized = normalize_context_path_spelling(raw)
204
277
  if Path(raw).is_absolute() or PureWindowsPath(raw).is_absolute() or ".." in normalized.split("/"):
205
278
  errors.append(f"project_context/context.toml {label} path must be relative and must not contain '..': {raw}")
206
279
  return None
207
- target = ROOT.joinpath(*normalized.split("/"))
280
+ target = (
281
+ physical_files.get(normalize_context_path(raw))
282
+ if expected == "context file" and physical_files is not None
283
+ else None
284
+ )
285
+ if target is None:
286
+ target = ROOT.joinpath(*normalized.split("/"))
208
287
  if not target.exists():
209
288
  errors.append(f"project_context/context.toml references missing {expected}: {normalized}")
210
289
  return None
@@ -222,7 +301,96 @@ def safe_manifest_path(raw, allowed_root, label, expected, errors):
222
301
  return resolved_target
223
302
 
224
303
 
225
- def validate_manifest(errors):
304
+ def validate_area_entry(area, area_ids, registered, roles, policies, errors, physical_files):
305
+ area_id = required_string(area, "id", errors)
306
+ area_root = required_string(area, "root", errors)
307
+ context_path = required_string(area, "context", errors)
308
+ optional_string(area, "kind", errors)
309
+ if "default" in area and not isinstance(area["default"], bool):
310
+ errors.append(f"project_context/context.toml line {area['line']} default must be a boolean")
311
+ string_array(area, "forbidden_runtime_dependencies", errors)
312
+ if area_id:
313
+ canonical_area_id = unicodedata.normalize("NFC", area_id)
314
+ previous_area_id = area_ids.get(canonical_area_id)
315
+ if previous_area_id is not None:
316
+ if previous_area_id == area_id:
317
+ errors.append(f"project_context/context.toml has duplicate area id: {area_id}")
318
+ else:
319
+ aliases = sorted((previous_area_id, area_id), key=lambda value: value.encode("utf-8"))
320
+ errors.append(
321
+ "project_context/context.toml area ids "
322
+ f"{', '.join(aliases)} normalize to the same NFC id {canonical_area_id}"
323
+ )
324
+ else:
325
+ area_ids[canonical_area_id] = area_id
326
+ label = f"area {area_id or area['line']}"
327
+ if area_root:
328
+ safe_manifest_path(area_root, ROOT, f"{label} root", "area root", errors)
329
+ if context_path:
330
+ register_context_path(
331
+ context_path,
332
+ "area",
333
+ None,
334
+ label,
335
+ registered,
336
+ roles,
337
+ policies,
338
+ errors,
339
+ physical_files,
340
+ )
341
+
342
+
343
+ def validate_context_entry(entry, registered, roles, policies, errors, warnings, physical_files):
344
+ context_path = required_string(entry, "path", errors)
345
+ raw_role = required_string(entry, "role", errors)
346
+ optional_string(entry, "read_when", errors)
347
+ read_policy = optional_string(entry, "read_policy", errors)
348
+ string_array(entry, "triggers", errors)
349
+ string_array(entry, "default_children", errors)
350
+ role = normalize_role(raw_role) if raw_role else None
351
+ if raw_role and role is None:
352
+ errors.append(f"project_context/context.toml line {entry['line']} has unsupported context role: {raw_role}")
353
+ if read_policy and read_policy not in READ_POLICIES:
354
+ errors.append(f"project_context/context.toml line {entry['line']} has unsupported read_policy: {read_policy}")
355
+ if read_policy in LEGACY_READ_POLICIES:
356
+ warnings.append(
357
+ f"project_context/context.toml line {entry['line']} uses legacy read_policy {read_policy}; "
358
+ "Schema v4 preserves its current selection behavior and migration must be explicit"
359
+ )
360
+ if context_path and role:
361
+ register_context_path(
362
+ context_path,
363
+ role,
364
+ read_policy,
365
+ f"context {context_path}",
366
+ registered,
367
+ roles,
368
+ policies,
369
+ errors,
370
+ physical_files,
371
+ )
372
+
373
+
374
+ def validate_default_children(contexts, registered, errors, warnings):
375
+ contexts_by_path = {
376
+ normalize_context_path(entry["path"]): entry
377
+ for entry in contexts
378
+ if isinstance(entry.get("path"), str) and entry["path"].strip()
379
+ }
380
+ for entry in contexts:
381
+ for child in entry.get("default_children", []):
382
+ normalized = normalize_context_path(child)
383
+ if normalized not in registered["paths"]:
384
+ errors.append(f"project_context/context.toml line {entry['line']} default_children references unregistered Context path: {child}")
385
+ elif contexts_by_path.get(normalized, {}).get("read_policy") == "never-default":
386
+ warnings.append(
387
+ f"project_context/context.toml line {entry['line']} default_children selects {normalized} even though its current "
388
+ "read_policy is never-default; Schema v4 preserves this behavior and a future migration must remove the edge or "
389
+ "change the policy explicitly"
390
+ )
391
+
392
+
393
+ def validate_manifest(errors, warnings, physical_files):
226
394
  manifest_path = CONTEXT_ROOT / "context.toml"
227
395
  roles = {}
228
396
  policies = {}
@@ -238,59 +406,64 @@ def validate_manifest(errors):
238
406
  defaults = [entry for entry in areas if entry.get("default") is True]
239
407
  if areas and len(defaults) != 1:
240
408
  errors.append(f"project_context/context.toml must mark exactly one [[areas]] entry with default = true; found {len(defaults)}")
241
- area_ids = set()
242
- registered_paths = set()
409
+ area_ids = {}
410
+ registered = {"paths": set(), "spellings": {}, "cases": {}}
243
411
 
244
412
  for area in areas:
245
- area_id = required_string(area, "id", errors)
246
- area_root = required_string(area, "root", errors)
247
- context_path = required_string(area, "context", errors)
248
- optional_string(area, "kind", errors)
249
- if "default" in area and not isinstance(area["default"], bool):
250
- errors.append(f"project_context/context.toml line {area['line']} default must be a boolean")
251
- string_array(area, "forbidden_runtime_dependencies", errors)
252
- if area_id:
253
- if area_id in area_ids:
254
- errors.append(f"project_context/context.toml has duplicate area id: {area_id}")
255
- area_ids.add(area_id)
256
- if area_root:
257
- safe_manifest_path(area_root, ROOT, f"area {area_id or area['line']} root", "area root", errors)
258
- if context_path:
259
- register_context_path(context_path, "area", None, f"area {area_id or area['line']}", registered_paths, roles, policies, errors)
260
-
261
- for entry in contexts:
262
- context_path = required_string(entry, "path", errors)
263
- raw_role = required_string(entry, "role", errors)
264
- optional_string(entry, "read_when", errors)
265
- read_policy = optional_string(entry, "read_policy", errors)
266
- string_array(entry, "triggers", errors)
267
- string_array(entry, "default_children", errors)
268
- role = normalize_role(raw_role) if raw_role else None
269
- if raw_role and role is None:
270
- errors.append(f"project_context/context.toml line {entry['line']} has unsupported context role: {raw_role}")
271
- if read_policy and read_policy not in READ_POLICIES:
272
- errors.append(f"project_context/context.toml line {entry['line']} has unsupported read_policy: {read_policy}")
273
- if context_path and role:
274
- register_context_path(context_path, role, read_policy, f"context {context_path}", registered_paths, roles, policies, errors)
275
-
413
+ validate_area_entry(area, area_ids, registered, roles, policies, errors, physical_files)
276
414
  for entry in contexts:
277
- for child in entry.get("default_children", []):
278
- normalized = normalize_context_path(child)
279
- if normalized not in registered_paths:
280
- errors.append(f"project_context/context.toml line {entry['line']} default_children references unregistered Context path: {child}")
415
+ validate_context_entry(entry, registered, roles, policies, errors, warnings, physical_files)
416
+ validate_default_children(contexts, registered, errors, warnings)
281
417
  return roles, policies
282
418
 
283
419
 
284
- def register_context_path(raw, role, read_policy, label, registered, roles, policies, errors):
420
+ def register_context_path(
421
+ raw,
422
+ role,
423
+ read_policy,
424
+ label,
425
+ registered,
426
+ roles,
427
+ policies,
428
+ errors,
429
+ physical_files,
430
+ ):
285
431
  normalized = normalize_context_path(raw)
286
- if normalized in registered:
287
- errors.append(f"project_context/context.toml has duplicate Context path: {normalized}")
288
- return
289
- registered.add(normalized)
432
+ raw_spelling = normalize_context_path_spelling(raw)
433
+ previous = registered["spellings"].get(normalized)
434
+ if previous is not None:
435
+ if previous == raw_spelling:
436
+ errors.append(f"project_context/context.toml has duplicate Context path: {normalized}")
437
+ else:
438
+ aliases = sorted((previous, raw_spelling), key=lambda value: value.encode("utf-8"))
439
+ errors.append(
440
+ "project_context/context.toml Context paths "
441
+ f"{', '.join(aliases)} normalize to the same NFC repository path {normalized}"
442
+ )
443
+ else:
444
+ registered["spellings"][normalized] = raw_spelling
445
+ case_key = portable_context_path_case_key(normalized)
446
+ previous_case = registered["cases"].get(case_key)
447
+ if previous_case is not None and previous_case != normalized:
448
+ aliases = sorted((previous_case, normalized), key=lambda value: value.encode("utf-8"))
449
+ errors.append(
450
+ "project_context/context.toml Context paths "
451
+ f"{', '.join(aliases)} collide on a case-insensitive filesystem"
452
+ )
453
+ else:
454
+ registered["cases"][case_key] = normalized
455
+ registered["paths"].add(normalized)
290
456
  if not normalized.startswith("project_context/") or not normalized.endswith(".md"):
291
457
  errors.append(f"project_context/context.toml {label} must reference a markdown file under project_context/: {raw}")
292
458
  return
293
- if safe_manifest_path(raw, CONTEXT_ROOT, label, "context file", errors) is None:
459
+ if safe_manifest_path(
460
+ raw,
461
+ CONTEXT_ROOT,
462
+ label,
463
+ "context file",
464
+ errors,
465
+ physical_files,
466
+ ) is None:
294
467
  return
295
468
  roles[normalized] = role
296
469
  if read_policy:
@@ -382,6 +555,55 @@ def validate_context_file(rel, text, role, errors):
382
555
  validate_role_recoverability(rel, text, role, errors)
383
556
 
384
557
 
558
+ def discover_context_markdown(errors):
559
+ paths = (
560
+ [
561
+ candidate
562
+ for candidate in CONTEXT_ROOT.rglob("*")
563
+ if candidate.is_file() and candidate.suffix.lower() == ".md"
564
+ ]
565
+ if CONTEXT_ROOT.exists()
566
+ else []
567
+ )
568
+ rows = []
569
+ for context_path in paths:
570
+ physical = context_path.relative_to(ROOT).as_posix()
571
+ canonical = normalize_context_path(physical)
572
+ rows.append((canonical, physical, context_path))
573
+ rows.sort(key=lambda row: (row[0].encode("utf-8"), row[1].encode("utf-8")))
574
+
575
+ grouped = {}
576
+ for canonical, physical, context_path in rows:
577
+ grouped.setdefault(canonical, []).append((physical, context_path))
578
+
579
+ public_rows = []
580
+ physical_files = {}
581
+ case_groups = {}
582
+ for canonical in sorted(grouped, key=lambda value: value.encode("utf-8")):
583
+ candidates = sorted(
584
+ grouped[canonical],
585
+ key=lambda row: row[0].encode("utf-8"),
586
+ )
587
+ spellings = [physical for physical, _path in candidates]
588
+ if len(spellings) > 1:
589
+ errors.append(
590
+ f"Context files {', '.join(spellings)} normalize to the same NFC repository path {canonical}"
591
+ )
592
+ physical, context_path = candidates[0]
593
+ public_rows.append((canonical, physical, context_path))
594
+ physical_files[canonical] = context_path
595
+ case_key = portable_context_path_case_key(canonical)
596
+ case_groups.setdefault(case_key, []).append(canonical)
597
+
598
+ for canonical_paths in case_groups.values():
599
+ aliases = sorted(set(canonical_paths), key=lambda value: value.encode("utf-8"))
600
+ if len(aliases) > 1:
601
+ errors.append(
602
+ f"Context files {', '.join(aliases)} collide on a case-insensitive filesystem"
603
+ )
604
+ return public_rows, physical_files
605
+
606
+
385
607
  def main():
386
608
  errors = []
387
609
  warnings = []
@@ -400,11 +622,14 @@ def main():
400
622
  validate_checks("project_context/architecture.md", text, ARCHITECTURE_CHECKS, errors)
401
623
  validate_context_file("project_context/architecture.md", text, "architecture", errors)
402
624
 
403
- manifest_roles, manifest_policies = validate_manifest(errors)
625
+ context_rows, physical_files = discover_context_markdown(errors)
626
+ manifest_roles, manifest_policies = validate_manifest(
627
+ errors,
628
+ warnings,
629
+ physical_files,
630
+ )
404
631
  checked = 0
405
- context_files = sorted(CONTEXT_ROOT.rglob("*.md")) if CONTEXT_ROOT.exists() else []
406
- for path in context_files:
407
- rel = path.relative_to(ROOT).as_posix()
632
+ for rel, _physical, path in context_rows:
408
633
  if rel in {"project_context/global.md", "project_context/architecture.md"}:
409
634
  continue
410
635
  text = path.read_text(encoding="utf-8")
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { commands } from "./commands/index.js";
3
+ import { cliExitCode } from "./lib/cli-exit.js";
3
4
  const [command = "help", ...args] = process.argv.slice(2);
4
5
  async function main() {
5
6
  const handler = commands[command];
@@ -10,5 +11,5 @@ async function main() {
10
11
  main().catch((error) => {
11
12
  const message = error instanceof Error ? error.message : String(error);
12
13
  console.error(`ty-context: ${message}`);
13
- process.exitCode = 1;
14
+ process.exitCode = cliExitCode(error) ?? 1;
14
15
  });
@@ -0,0 +1 @@
1
+ export declare function contextCreate(args: string[]): Promise<void>;
@@ -0,0 +1,90 @@
1
+ import { CLI_EXIT_CODES, CliCommandError } from "../lib/cli-exit.js";
2
+ import { createContextScaffold } from "../lib/context-create/context-create.js";
3
+ export async function contextCreate(args) {
4
+ const options = parseCreateArgs(args);
5
+ if (options.help) {
6
+ console.log(contextCreateHelp());
7
+ return;
8
+ }
9
+ if (!options.path || !options.role)
10
+ throw new CliCommandError(CLI_EXIT_CODES.arguments, "context create requires --path and --role");
11
+ let result;
12
+ try {
13
+ result = await createContextScaffold({
14
+ project_root: process.cwd(),
15
+ context_path: options.path,
16
+ role: options.role,
17
+ });
18
+ }
19
+ catch (error) {
20
+ if (error instanceof CliCommandError)
21
+ throw error;
22
+ throw new CliCommandError(CLI_EXIT_CODES.internal, `context create failed internally: ${message(error)}`, { cause: error });
23
+ }
24
+ if (options.format === "json")
25
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
26
+ else
27
+ process.stdout.write(renderContextCreateText(result));
28
+ }
29
+ function parseCreateArgs(args) {
30
+ const options = { format: "text", help: false };
31
+ for (let index = 0; index < args.length; index += 1) {
32
+ const argument = args[index];
33
+ if (argument === "--help" || argument === "-h")
34
+ options.help = true;
35
+ else if (argument === "--json")
36
+ options.format = "json";
37
+ else if (argument === "--path")
38
+ index = readValue(args, index, argument, (value) => {
39
+ options.path = singleValue(options.path, value, argument);
40
+ });
41
+ else if (argument === "--role")
42
+ index = readValue(args, index, argument, (value) => {
43
+ options.role = singleValue(options.role, value, argument);
44
+ });
45
+ else if (argument === "--format")
46
+ index = readValue(args, index, argument, (value) => {
47
+ if (value !== "text" && value !== "json")
48
+ throw new CliCommandError(CLI_EXIT_CODES.arguments, "context create --format must be text or json");
49
+ options.format = value;
50
+ });
51
+ else
52
+ throw new CliCommandError(CLI_EXIT_CODES.arguments, `unknown context create argument: ${argument}`);
53
+ }
54
+ return options;
55
+ }
56
+ function readValue(args, index, flag, apply) {
57
+ const value = args[index + 1];
58
+ if (value === undefined || value.startsWith("--") || value.length === 0)
59
+ throw new CliCommandError(CLI_EXIT_CODES.arguments, `context create ${flag} requires a value`);
60
+ apply(value);
61
+ return index + 1;
62
+ }
63
+ function singleValue(current, value, flag) {
64
+ if (current !== undefined)
65
+ throw new CliCommandError(CLI_EXIT_CODES.arguments, `context create accepts ${flag} exactly once`);
66
+ return value;
67
+ }
68
+ function renderContextCreateText(result) {
69
+ return [
70
+ `Created unregistered Context scaffold: ${result.path}`,
71
+ `Role: ${result.role}`,
72
+ `Bytes: ${result.bytes}`,
73
+ "Manifest modified: no",
74
+ `Default footprint: unchanged (${result.default_footprint.before.path_count} paths, ${result.default_footprint.before.bytes} bytes)`,
75
+ "Next:",
76
+ ...result.next_steps.map((step) => `- ${step}`),
77
+ "",
78
+ ].join("\n");
79
+ }
80
+ function contextCreateHelp() {
81
+ return `ty-context context create --path <project_context/file.md> --role <role>
82
+ [--format text|json]
83
+
84
+ Creates one Role-specific TODO-only scaffold as an unregistered Context file.
85
+ It refuses collisions and unsafe paths, never edits context.toml and never
86
+ provides a create-and-register or force-overwrite option.`;
87
+ }
88
+ function message(error) {
89
+ return error instanceof Error ? error.message : String(error);
90
+ }
@@ -0,0 +1 @@
1
+ export declare function contextInspect(args: string[]): Promise<void>;