@greenpandastudios/aug-cli 0.19.0 → 0.20.1

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 (459) hide show
  1. package/README.md +9 -6
  2. package/THIRD_PARTY_NOTICES.md +4 -0
  3. package/bin/aug.mjs +12 -2
  4. package/docs/about.md +27 -0
  5. package/docs/api/crypto.md +103 -69
  6. package/docs/api/io.md +35 -33
  7. package/docs/api/json.md +3 -3
  8. package/docs/api/memory.md +23 -19
  9. package/docs/api/time.md +10 -9
  10. package/docs/api/web.md +33 -38
  11. package/docs/compatibility.md +3 -3
  12. package/docs/contributing-benchmarks.md +38 -0
  13. package/docs/dev-containers.md +95 -0
  14. package/docs/diagnostics.md +15 -5
  15. package/docs/docker.md +174 -12
  16. package/docs/editor.md +35 -0
  17. package/docs/example-projects.json +206 -24
  18. package/docs/examples/approved-design/counters.md +34 -126
  19. package/docs/examples/approved-design/dependencies/august/0.20.1/io/contracts.md +178 -0
  20. package/docs/examples/approved-design/domain/app.md +13 -77
  21. package/docs/examples/approved-design/domain/export.md +5 -19
  22. package/docs/examples/approved-design/domain/models.md +4 -23
  23. package/docs/examples/approved-design/domain/numbers.md +24 -114
  24. package/docs/examples/approved-design/index.md +16 -7
  25. package/docs/examples/approved-design/main.md +19 -96
  26. package/docs/examples/benchmark/index.md +6 -5
  27. package/docs/examples/benchmark/main.md +7 -35
  28. package/docs/examples/cli-args/index.md +6 -5
  29. package/docs/examples/cli-args/main.md +6 -31
  30. package/docs/examples/collections/index.md +6 -5
  31. package/docs/examples/collections/main.md +7 -35
  32. package/docs/examples/collections-benchmark/index.md +6 -5
  33. package/docs/examples/collections-benchmark/main.md +7 -35
  34. package/docs/examples/cpu-benchmark/index.md +6 -5
  35. package/docs/examples/cpu-benchmark/main.md +5 -24
  36. package/docs/examples/developer-workflow/calculator.md +39 -186
  37. package/docs/examples/developer-workflow/dependencies/august/0.20.1/io/contracts.md +178 -0
  38. package/docs/examples/developer-workflow/index.md +16 -7
  39. package/docs/examples/developer-workflow/logging/console.md +10 -56
  40. package/docs/examples/developer-workflow/logging/export.md +4 -14
  41. package/docs/examples/developer-workflow/logging/logger.md +7 -43
  42. package/docs/examples/developer-workflow/main.md +17 -69
  43. package/docs/examples/drop/index.md +6 -5
  44. package/docs/examples/drop/main.md +7 -27
  45. package/docs/examples/drop/resource.md +7 -30
  46. package/docs/examples/errors/errors.md +7 -27
  47. package/docs/examples/errors/index.md +6 -5
  48. package/docs/examples/errors/main.md +7 -28
  49. package/docs/examples/ffi/index.md +6 -5
  50. package/docs/examples/ffi/main.md +6 -20
  51. package/docs/examples/ffi/native.md +8 -34
  52. package/docs/examples/generic-di/dependencies/august/0.20.1/io/contracts.md +178 -0
  53. package/docs/examples/generic-di/index.md +6 -5
  54. package/docs/examples/generic-di/main.md +9 -39
  55. package/docs/examples/generic-di/types.md +23 -92
  56. package/docs/examples/generics/index.md +6 -5
  57. package/docs/examples/generics/main.md +10 -47
  58. package/docs/examples/generics/types.md +25 -100
  59. package/docs/examples/hello/app/export.md +4 -12
  60. package/docs/examples/hello/app/greeter.md +13 -91
  61. package/docs/examples/hello/dependencies/august/0.20.1/io/contracts.md +178 -0
  62. package/docs/examples/hello/index.md +17 -6
  63. package/docs/examples/hello/logging/console.md +10 -54
  64. package/docs/examples/hello/logging/export.md +4 -14
  65. package/docs/examples/hello/logging/logger.md +7 -45
  66. package/docs/examples/hello/main.md +9 -39
  67. package/docs/examples/http-benchmark/index.md +6 -5
  68. package/docs/examples/http-benchmark/main.md +6 -20
  69. package/docs/examples/http-benchmark/routes.md +9 -31
  70. package/docs/examples/index.md +46 -29
  71. package/docs/examples/interceptors/app.md +20 -139
  72. package/docs/examples/interceptors/dependencies/august/0.20.1/io/contracts.md +178 -0
  73. package/docs/examples/interceptors/index.md +6 -5
  74. package/docs/examples/interceptors/interceptors.md +24 -148
  75. package/docs/examples/interceptors/logging.md +13 -76
  76. package/docs/examples/interceptors/main.md +10 -65
  77. package/docs/examples/json-benchmark/data.md +4 -20
  78. package/docs/examples/json-benchmark/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
  79. package/docs/examples/json-benchmark/index.md +7 -5
  80. package/docs/examples/json-benchmark/main-yaml.md +20 -0
  81. package/docs/examples/json-benchmark/main.md +10 -49
  82. package/docs/examples/new-syntax/console.md +10 -52
  83. package/docs/examples/new-syntax/dependencies/august/0.20.1/io/contracts.md +178 -0
  84. package/docs/examples/new-syntax/greeter.md +13 -71
  85. package/docs/examples/new-syntax/index.md +6 -5
  86. package/docs/examples/new-syntax/logger.md +7 -43
  87. package/docs/examples/new-syntax/main.md +10 -53
  88. package/docs/examples/new-syntax/math.md +6 -24
  89. package/docs/examples/oidc-login/client/contracts.md +10 -61
  90. package/docs/examples/oidc-login/client/endpoints.md +32 -154
  91. package/docs/examples/oidc-login/client/export.md +5 -23
  92. package/docs/examples/oidc-login/client/login.md +234 -344
  93. package/docs/examples/oidc-login/client/logout.md +38 -143
  94. package/docs/examples/oidc-login/client/protocol.md +183 -304
  95. package/docs/examples/oidc-login/client/session.md +41 -149
  96. package/docs/examples/oidc-login/client/views.md +13 -58
  97. package/docs/examples/oidc-login/common/export.md +6 -26
  98. package/docs/examples/oidc-login/common/headers.md +42 -72
  99. package/docs/examples/oidc-login/common/keys.md +40 -164
  100. package/docs/examples/oidc-login/common/settings.md +24 -40
  101. package/docs/examples/oidc-login/common/views.md +7 -28
  102. package/docs/examples/oidc-login/dependencies/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.md +205 -0
  103. package/docs/examples/oidc-login/dependencies/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +67 -0
  104. package/docs/examples/oidc-login/dependencies/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +267 -0
  105. package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.md +415 -0
  106. package/docs/examples/oidc-login/dependencies/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.md +271 -0
  107. package/docs/examples/oidc-login/dependencies/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.md +89 -0
  108. package/docs/examples/oidc-login/index.md +8 -7
  109. package/docs/examples/oidc-login/main-yaml.md +7 -0
  110. package/docs/examples/oidc-login/main.md +26 -153
  111. package/docs/examples/oidc-login/provider/authorization.md +232 -275
  112. package/docs/examples/oidc-login/provider/contracts.md +24 -146
  113. package/docs/examples/oidc-login/provider/credentials.md +24 -57
  114. package/docs/examples/oidc-login/provider/discovery.md +48 -122
  115. package/docs/examples/oidc-login/provider/export.md +11 -37
  116. package/docs/examples/oidc-login/provider/token.md +159 -237
  117. package/docs/examples/oidc-login/provider/userinfo.md +47 -102
  118. package/docs/examples/oidc-login/provider/views.md +13 -53
  119. package/docs/examples/ownership/counter.md +17 -63
  120. package/docs/examples/ownership/index.md +6 -5
  121. package/docs/examples/ownership/main.md +7 -30
  122. package/docs/examples/ownership-transfer/dependencies/august/0.20.1/io/contracts.md +178 -0
  123. package/docs/examples/ownership-transfer/index.md +6 -5
  124. package/docs/examples/ownership-transfer/main.md +10 -52
  125. package/docs/examples/ownership-transfer/resource.md +15 -67
  126. package/docs/examples/packages-app/dependencies/packages/@example/aug-math/0.1.0/arithmetic.md +12 -50
  127. package/docs/examples/packages-app/index.md +7 -6
  128. package/docs/examples/packages-app/main.md +7 -25
  129. package/docs/examples/packages-math/aug-package-json.md +1 -1
  130. package/docs/examples/packages-math/index.md +7 -6
  131. package/docs/examples/packages-math/src/arithmetic.md +12 -50
  132. package/docs/examples/packages-math/src/export.md +4 -12
  133. package/docs/examples/startup-benchmark/index.md +6 -5
  134. package/docs/examples/startup-benchmark/main.md +5 -17
  135. package/docs/examples/visibility/counter.md +19 -67
  136. package/docs/examples/visibility/index.md +6 -5
  137. package/docs/examples/visibility/main.md +7 -31
  138. package/docs/examples/weather-api/forecasts.md +168 -0
  139. package/docs/examples/weather-api/index.md +42 -0
  140. package/docs/examples/weather-api/main-yaml.md +21 -0
  141. package/docs/examples/weather-api/main.md +65 -0
  142. package/docs/examples.json +10 -0
  143. package/docs/getting-started.md +105 -2
  144. package/docs/grammar.md +6 -4
  145. package/docs/guides/change-a-module.md +64 -0
  146. package/docs/guides/index.md +27 -0
  147. package/docs/index.md +51 -29
  148. package/docs/language-conformance.md +1 -1
  149. package/docs/language-constructs.md +22 -22
  150. package/docs/language-design-audit.md +1 -1
  151. package/docs/learn/data-and-errors.md +77 -0
  152. package/docs/learn/index.md +30 -0
  153. package/docs/learn/modules-and-dependencies.md +73 -0
  154. package/docs/learn/state-and-tests.md +71 -0
  155. package/docs/learn/values-and-functions.md +62 -0
  156. package/docs/lesson-failures.json +8 -0
  157. package/docs/maintaining-docs.md +16 -4
  158. package/docs/packages.md +72 -126
  159. package/docs/performance.md +13 -41
  160. package/docs/production-readiness.md +5 -4
  161. package/docs/public/downloads/approved-design.zip +0 -0
  162. package/docs/public/downloads/benchmark.zip +0 -0
  163. package/docs/public/downloads/cli-args.zip +0 -0
  164. package/docs/public/downloads/collections-benchmark.zip +0 -0
  165. package/docs/public/downloads/collections.zip +0 -0
  166. package/docs/public/downloads/cpu-benchmark.zip +0 -0
  167. package/docs/public/downloads/developer-workflow.zip +0 -0
  168. package/docs/public/downloads/drop.zip +0 -0
  169. package/docs/public/downloads/errors.zip +0 -0
  170. package/docs/public/downloads/ffi.zip +0 -0
  171. package/docs/public/downloads/generic-di.zip +0 -0
  172. package/docs/public/downloads/generics.zip +0 -0
  173. package/docs/public/downloads/hello.zip +0 -0
  174. package/docs/public/downloads/http-benchmark.zip +0 -0
  175. package/docs/public/downloads/interceptors.zip +0 -0
  176. package/docs/public/downloads/json-benchmark.zip +0 -0
  177. package/docs/public/downloads/new-syntax.zip +0 -0
  178. package/docs/public/downloads/oidc-login.zip +0 -0
  179. package/docs/public/downloads/ownership-transfer.zip +0 -0
  180. package/docs/public/downloads/ownership.zip +0 -0
  181. package/docs/public/downloads/packages-app.zip +0 -0
  182. package/docs/public/downloads/packages-math.zip +0 -0
  183. package/docs/public/downloads/startup-benchmark.zip +0 -0
  184. package/docs/public/downloads/visibility.zip +0 -0
  185. package/docs/public/downloads/weather-api.zip +0 -0
  186. package/docs/reference.md +23 -17
  187. package/docs/releasing.md +29 -15
  188. package/docs/research/code-to-natural-language.md +108 -0
  189. package/docs/research/ecosystem-workflow.md +41 -0
  190. package/docs/research/wiki-editorial-design.md +71 -0
  191. package/docs/roadmap.md +1 -1
  192. package/docs/specifications.md +27 -11
  193. package/docs/testing.md +19 -5
  194. package/docs/tooling.md +25 -12
  195. package/docs/weather-api.md +65 -0
  196. package/docs/web.md +50 -18
  197. package/docs/writing-docs.md +49 -0
  198. package/examples/{hello/.aug-spec/august/0.19.0 → approved-design/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  199. package/examples/approved-design/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  200. package/examples/approved-design/.aug-spec/manifest.json +3 -3
  201. package/examples/approved-design/counters.aug +5 -4
  202. package/examples/approved-design/counters.aug.md +25 -132
  203. package/examples/approved-design/domain/app.aug +2 -1
  204. package/examples/approved-design/domain/app.aug.md +10 -80
  205. package/examples/approved-design/domain/export.aug +1 -0
  206. package/examples/approved-design/domain/export.aug.md +4 -20
  207. package/examples/approved-design/domain/models.aug +1 -0
  208. package/examples/approved-design/domain/models.aug.md +3 -25
  209. package/examples/approved-design/domain/numbers.aug +3 -2
  210. package/examples/approved-design/domain/numbers.aug.md +19 -116
  211. package/examples/approved-design/main.aug +1 -0
  212. package/examples/approved-design/main.aug.md +12 -95
  213. package/examples/benchmark/.aug-spec/manifest.json +1 -1
  214. package/examples/benchmark/main.aug +1 -0
  215. package/examples/benchmark/main.aug.md +6 -36
  216. package/examples/cli-args/.aug-spec/manifest.json +1 -1
  217. package/examples/cli-args/main.aug +1 -0
  218. package/examples/cli-args/main.aug.md +5 -32
  219. package/examples/collections/.aug-spec/manifest.json +1 -1
  220. package/examples/collections/main.aug +1 -0
  221. package/examples/collections/main.aug.md +6 -36
  222. package/examples/{generic-di/.aug-spec/august/0.19.0 → developer-workflow/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  223. package/examples/developer-workflow/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  224. package/examples/developer-workflow/.aug-spec/manifest.json +3 -3
  225. package/examples/developer-workflow/calculator.aug +3 -2
  226. package/examples/developer-workflow/calculator.aug.md +28 -189
  227. package/examples/developer-workflow/logging/console.aug +2 -1
  228. package/examples/developer-workflow/logging/console.aug.md +7 -57
  229. package/examples/developer-workflow/logging/export.aug +1 -0
  230. package/examples/developer-workflow/logging/export.aug.md +3 -15
  231. package/examples/developer-workflow/logging/logger.aug +1 -0
  232. package/examples/developer-workflow/logging/logger.aug.md +6 -46
  233. package/examples/developer-workflow/main.aug +1 -0
  234. package/examples/developer-workflow/main.aug.md +10 -68
  235. package/examples/drop/.aug-spec/manifest.json +1 -1
  236. package/examples/drop/main.aug +1 -0
  237. package/examples/drop/main.aug.md +6 -28
  238. package/examples/drop/resource.aug +1 -0
  239. package/examples/drop/resource.aug.md +6 -34
  240. package/examples/errors/.aug-spec/manifest.json +1 -1
  241. package/examples/errors/errors.aug +2 -1
  242. package/examples/errors/errors.aug.md +4 -27
  243. package/examples/errors/main.aug +1 -0
  244. package/examples/errors/main.aug.md +6 -29
  245. package/examples/ffi/.aug-spec/manifest.json +1 -1
  246. package/examples/ffi/main.aug +1 -0
  247. package/examples/ffi/main.aug.md +5 -21
  248. package/examples/ffi/native.aug +2 -1
  249. package/examples/ffi/native.aug.md +5 -35
  250. package/examples/{approved-design/.aug-spec/august/0.19.0 → generic-di/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  251. package/examples/generic-di/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  252. package/examples/generic-di/.aug-spec/manifest.json +3 -3
  253. package/examples/generic-di/main.aug +1 -0
  254. package/examples/generic-di/main.aug.md +8 -40
  255. package/examples/generic-di/types.aug +3 -2
  256. package/examples/generic-di/types.aug.md +18 -97
  257. package/examples/generics/.aug-spec/manifest.json +1 -1
  258. package/examples/generics/main.aug +1 -0
  259. package/examples/generics/main.aug.md +9 -48
  260. package/examples/generics/types.aug +4 -3
  261. package/examples/generics/types.aug.md +18 -104
  262. package/examples/{developer-workflow/.aug-spec/august/0.19.0 → hello/.aug-spec/august/0.20.1}/io/contracts.aug +4 -3
  263. package/examples/hello/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  264. package/examples/hello/.aug-spec/manifest.json +3 -3
  265. package/examples/hello/app/export.aug +1 -0
  266. package/examples/hello/app/export.aug.md +3 -13
  267. package/examples/hello/app/greeter.aug +2 -1
  268. package/examples/hello/app/greeter.aug.md +10 -94
  269. package/examples/hello/logging/console.aug +2 -1
  270. package/examples/hello/logging/console.aug.md +7 -55
  271. package/examples/hello/logging/export.aug +1 -0
  272. package/examples/hello/logging/export.aug.md +3 -15
  273. package/examples/hello/logging/logger.aug +1 -0
  274. package/examples/hello/logging/logger.aug.md +6 -48
  275. package/examples/hello/main.aug +1 -0
  276. package/examples/hello/main.aug.md +8 -40
  277. package/examples/interceptors/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
  278. package/examples/interceptors/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  279. package/examples/interceptors/.aug-spec/manifest.json +3 -3
  280. package/examples/interceptors/app.aug +3 -2
  281. package/examples/interceptors/app.aug.md +15 -141
  282. package/examples/interceptors/interceptors.aug +3 -2
  283. package/examples/interceptors/interceptors.aug.md +19 -152
  284. package/examples/interceptors/logging.aug +2 -1
  285. package/examples/interceptors/logging.aug.md +10 -79
  286. package/examples/interceptors/main.aug +1 -0
  287. package/examples/interceptors/main.aug.md +9 -66
  288. package/examples/new-syntax/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
  289. package/examples/new-syntax/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  290. package/examples/new-syntax/.aug-spec/manifest.json +3 -3
  291. package/examples/new-syntax/console.aug +2 -1
  292. package/examples/new-syntax/console.aug.md +7 -53
  293. package/examples/new-syntax/greeter.aug +2 -1
  294. package/examples/new-syntax/greeter.aug.md +10 -74
  295. package/examples/new-syntax/logger.aug +1 -0
  296. package/examples/new-syntax/logger.aug.md +6 -46
  297. package/examples/new-syntax/main.aug +1 -0
  298. package/examples/new-syntax/main.aug.md +9 -54
  299. package/examples/new-syntax/math.aug +2 -1
  300. package/examples/new-syntax/math.aug.md +3 -24
  301. package/examples/oidc-login/.aug-spec/manifest.json +13 -13
  302. package/examples/oidc-login/.aug-spec/packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/store.aug.md +71 -0
  303. package/examples/oidc-login/.aug-spec/packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +17 -0
  304. package/examples/oidc-login/.aug-spec/packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +125 -0
  305. package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/contracts.aug +12 -11
  306. package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/contracts.aug.md +244 -0
  307. package/examples/oidc-login/.aug-spec/{august/0.19.0/crypto → packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40}/jose.aug +6 -5
  308. package/examples/oidc-login/.aug-spec/packages/@git/url_9ef654c66d34ab8f5527/0.0.0-git.b14a0f9aa41f1ce58bd51133bcdc424033e40d40/jose.aug.md +71 -0
  309. package/examples/oidc-login/.aug-spec/packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301/contracts.aug.md +30 -0
  310. package/examples/oidc-login/aug.lock.json +100 -0
  311. package/examples/oidc-login/client/contracts.aug +1 -0
  312. package/examples/oidc-login/client/contracts.aug.md +9 -66
  313. package/examples/oidc-login/client/endpoints.aug +6 -5
  314. package/examples/oidc-login/client/endpoints.aug.md +13 -145
  315. package/examples/oidc-login/client/export.aug +1 -0
  316. package/examples/oidc-login/client/export.aug.md +4 -24
  317. package/examples/oidc-login/client/login.aug +7 -6
  318. package/examples/oidc-login/client/login.aug.md +25 -303
  319. package/examples/oidc-login/client/logout.aug +5 -4
  320. package/examples/oidc-login/client/logout.aug.md +13 -135
  321. package/examples/oidc-login/client/protocol.aug +7 -6
  322. package/examples/oidc-login/client/protocol.aug.md +36 -283
  323. package/examples/oidc-login/client/session.aug +5 -4
  324. package/examples/oidc-login/client/session.aug.md +12 -139
  325. package/examples/oidc-login/client/views.aug +3 -2
  326. package/examples/oidc-login/client/views.aug.md +8 -57
  327. package/examples/oidc-login/common/export.aug +1 -0
  328. package/examples/oidc-login/common/export.aug.md +5 -27
  329. package/examples/oidc-login/common/headers.aug +4 -3
  330. package/examples/oidc-login/common/headers.aug.md +9 -67
  331. package/examples/oidc-login/common/keys.aug +6 -5
  332. package/examples/oidc-login/common/keys.aug.md +29 -165
  333. package/examples/oidc-login/common/settings.aug +2 -1
  334. package/examples/oidc-login/common/settings.aug.md +5 -39
  335. package/examples/oidc-login/common/views.aug +2 -1
  336. package/examples/oidc-login/common/views.aug.md +4 -28
  337. package/examples/oidc-login/main.aug +6 -16
  338. package/examples/oidc-login/main.aug.md +17 -146
  339. package/examples/oidc-login/main.yaml +7 -0
  340. package/examples/oidc-login/provider/authorization.aug +7 -6
  341. package/examples/oidc-login/provider/authorization.aug.md +23 -238
  342. package/examples/oidc-login/provider/contracts.aug +1 -0
  343. package/examples/oidc-login/provider/contracts.aug.md +23 -158
  344. package/examples/oidc-login/provider/credentials.aug +3 -2
  345. package/examples/oidc-login/provider/credentials.aug.md +9 -53
  346. package/examples/oidc-login/provider/discovery.aug +4 -3
  347. package/examples/oidc-login/provider/discovery.aug.md +11 -118
  348. package/examples/oidc-login/provider/export.aug +1 -0
  349. package/examples/oidc-login/provider/export.aug.md +6 -34
  350. package/examples/oidc-login/provider/token.aug +6 -5
  351. package/examples/oidc-login/provider/token.aug.md +16 -204
  352. package/examples/oidc-login/provider/userinfo.aug +4 -3
  353. package/examples/oidc-login/provider/userinfo.aug.md +10 -92
  354. package/examples/oidc-login/provider/views.aug +3 -2
  355. package/examples/oidc-login/provider/views.aug.md +8 -52
  356. package/examples/ownership/.aug-spec/manifest.json +1 -1
  357. package/examples/ownership/counter.aug +3 -2
  358. package/examples/ownership/counter.aug.md +12 -66
  359. package/examples/ownership/main.aug +1 -0
  360. package/examples/ownership/main.aug.md +6 -31
  361. package/examples/ownership-transfer/.aug-spec/august/0.20.1/io/contracts.aug +37 -0
  362. package/examples/ownership-transfer/.aug-spec/august/0.20.1/io/contracts.aug.md +82 -0
  363. package/examples/ownership-transfer/.aug-spec/manifest.json +3 -3
  364. package/examples/ownership-transfer/main.aug +1 -0
  365. package/examples/ownership-transfer/main.aug.md +9 -53
  366. package/examples/ownership-transfer/resource.aug +2 -1
  367. package/examples/ownership-transfer/resource.aug.md +12 -71
  368. package/examples/packages/app/.aug-spec/manifest.json +1 -1
  369. package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug +2 -1
  370. package/examples/packages/app/.aug-spec/packages/@example/aug-math/0.1.0/arithmetic.aug.md +9 -51
  371. package/examples/packages/app/main.aug +1 -0
  372. package/examples/packages/app/main.aug.md +6 -26
  373. package/examples/packages/math/.aug-spec/manifest.json +1 -1
  374. package/examples/packages/math/aug-package.json +1 -1
  375. package/examples/packages/math/src/arithmetic.aug +2 -1
  376. package/examples/packages/math/src/arithmetic.aug.md +9 -51
  377. package/examples/packages/math/src/export.aug +1 -0
  378. package/examples/packages/math/src/export.aug.md +3 -13
  379. package/examples/visibility/.aug-spec/manifest.json +1 -1
  380. package/examples/visibility/counter.aug +4 -3
  381. package/examples/visibility/counter.aug.md +12 -68
  382. package/examples/visibility/main.aug +1 -0
  383. package/examples/visibility/main.aug.md +6 -32
  384. package/examples/weather-api/.aug-spec/manifest.json +8 -0
  385. package/examples/weather-api/AGENTS.md +17 -0
  386. package/examples/weather-api/README.md +19 -0
  387. package/examples/weather-api/forecasts.aug +47 -0
  388. package/examples/weather-api/forecasts.aug.md +32 -0
  389. package/examples/weather-api/main.aug +4 -0
  390. package/examples/weather-api/main.aug.md +15 -0
  391. package/examples/weather-api/main.yaml +5 -0
  392. package/examples/weather-api/weather.http +5 -0
  393. package/package.json +3 -4
  394. package/scripts/bootstrap-native.mjs +181 -106
  395. package/scripts/native-setup.mjs +98 -0
  396. package/scripts/native-toolchain.mjs +28 -0
  397. package/src/builtins.js +1 -1
  398. package/src/checker.js +259 -72
  399. package/src/cli.js +114 -20
  400. package/src/codegen.js +1 -1
  401. package/src/config.js +1 -1
  402. package/src/contracts.js +10 -0
  403. package/src/editor.js +71 -16
  404. package/src/fixes.js +90 -2
  405. package/src/formatter.js +19 -8
  406. package/src/git-packages.js +110 -0
  407. package/src/help.js +24 -23
  408. package/src/http-contracts.js +14 -0
  409. package/src/http-policies.js +5 -5
  410. package/src/libraries.js +1 -1
  411. package/src/lsp.js +14 -5
  412. package/src/native.js +19 -13
  413. package/src/navigation.js +4 -2
  414. package/src/openapi.js +5 -4
  415. package/src/package-locking.js +45 -0
  416. package/src/package-manager.js +251 -67
  417. package/src/parser.js +13 -5
  418. package/src/policies.js +3 -3
  419. package/src/project-init.js +78 -4
  420. package/src/project.js +9 -7
  421. package/src/semantic.js +46 -2
  422. package/src/snippets.js +59 -0
  423. package/src/spec-hints.js +56 -0
  424. package/src/spec-tree.js +241 -0
  425. package/src/spec.js +626 -303
  426. package/docs/examples/approved-design/dependencies/august/0.19.0/io/contracts.md +0 -395
  427. package/docs/examples/developer-workflow/dependencies/august/0.19.0/io/contracts.md +0 -395
  428. package/docs/examples/generic-di/dependencies/august/0.19.0/io/contracts.md +0 -395
  429. package/docs/examples/hello/dependencies/august/0.19.0/io/contracts.md +0 -395
  430. package/docs/examples/interceptors/dependencies/august/0.19.0/io/contracts.md +0 -395
  431. package/docs/examples/json-benchmark/dependencies/august/0.19.0/json/contracts.md +0 -103
  432. package/docs/examples/new-syntax/dependencies/august/0.19.0/io/contracts.md +0 -395
  433. package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/contracts.md +0 -925
  434. package/docs/examples/oidc-login/dependencies/august/0.19.0/crypto/jose.md +0 -434
  435. package/docs/examples/oidc-login/dependencies/august/0.19.0/json/contracts.md +0 -103
  436. package/docs/examples/oidc-login/dependencies/august/0.19.0/memory/store.md +0 -374
  437. package/docs/examples/oidc-login/dependencies/august/0.19.0/time/contracts.md +0 -150
  438. package/docs/examples/oidc-login/dependencies/august/0.19.0/web/contracts.md +0 -532
  439. package/docs/examples/ownership-transfer/dependencies/august/0.19.0/io/contracts.md +0 -395
  440. package/examples/approved-design/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  441. package/examples/developer-workflow/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  442. package/examples/generic-di/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  443. package/examples/hello/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  444. package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
  445. package/examples/interceptors/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  446. package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
  447. package/examples/new-syntax/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  448. package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/contracts.aug.md +0 -791
  449. package/examples/oidc-login/.aug-spec/august/0.19.0/crypto/jose.aug.md +0 -266
  450. package/examples/oidc-login/.aug-spec/august/0.19.0/json/contracts.aug.md +0 -55
  451. package/examples/oidc-login/.aug-spec/august/0.19.0/memory/store.aug.md +0 -250
  452. package/examples/oidc-login/.aug-spec/august/0.19.0/time/contracts.aug.md +0 -96
  453. package/examples/oidc-login/.aug-spec/august/0.19.0/web/contracts.aug.md +0 -420
  454. package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug +0 -36
  455. package/examples/ownership-transfer/.aug-spec/august/0.19.0/io/contracts.aug.md +0 -316
  456. /package/examples/oidc-login/.aug-spec/{august/0.19.0/memory → packages/@git/url_0eb7c89453c87681ed15/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/store.aug +0 -0
  457. /package/examples/oidc-login/.aug-spec/{august/0.19.0/json → packages/@git/url_2d3c37c690c0fa115be1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
  458. /package/examples/oidc-login/.aug-spec/{august/0.19.0/web → packages/@git/url_897efafd565158fc4908/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
  459. /package/examples/oidc-login/.aug-spec/{august/0.19.0/time → packages/@git/url_c092cd151499c4e1d8a1/0.0.0-git.a39fc582565d4fca40be4f75fa304d71adc69301}/contracts.aug +0 -0
package/src/openapi.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { callableResult } from "./contracts.js";
1
2
  import { createHash } from 'node:crypto';
2
3
  import { schemaType } from "./schemas.js";
3
4
  import { callableDocumentation } from "./documentation.js";
@@ -81,7 +82,7 @@ export function generateOpenApi(checked) {
81
82
  result.push({ status: fn.endpoint?.status ?? 200, type: primitive('void') });
82
83
  return;
83
84
  }
84
- const type = checked.expressionTypes.get(expr) ?? schemaType(project, fn.returns, fn.span.file);
85
+ const type = checked.expressionTypes.get(expr) ?? callableResult(checked, fn);
85
86
  if (expr.kind === 'call' && expr.callee.kind === 'name' && type.name === 'HttpResponse') {
86
87
  if (expr.callee.name !== 'HttpResponse') {
87
88
  const def = project.scopes.get(fn.span.file)?.get(expr.callee.name);
@@ -125,8 +126,8 @@ export function generateOpenApi(checked) {
125
126
  }
126
127
  result.push({ status: fn.endpoint?.status ?? 200, type });
127
128
  });
128
- if (!result.length && fn.returns.name !== 'HttpResponse')
129
- result.push({ status: fn.endpoint?.status ?? 200, type: schemaType(project, fn.returns, fn.span.file) });
129
+ if (!result.length && callableResult(checked, fn).name !== 'HttpResponse')
130
+ result.push({ status: fn.endpoint?.status ?? 200, type: callableResult(checked, fn) });
130
131
  return result;
131
132
  };
132
133
  const served = new Map();
@@ -152,7 +153,7 @@ export function generateOpenApi(checked) {
152
153
  current.schema = { oneOf: [current.schema, value] };
153
154
  };
154
155
  if (endpoint.streams) {
155
- const item = schemaType(project, fn.returns, fn.span.file), sse = item.name === 'ServerEvent';
156
+ const item = callableResult(checked, fn), sse = item.name === 'ServerEvent';
156
157
  const itemSchema = sse ? { type: 'object', required: ['data'], properties: { data: { type: 'string', contentMediaType: 'application/json', contentSchema: schema(item.args[0], fn.span) }, id: { type: 'string' }, event: { type: 'string' }, retry: { type: 'integer', minimum: 0 } } } : schema(item, fn.span);
157
158
  responses[endpoint.status] = { description: 'Streaming response', content: { [sse ? 'text/event-stream' : item.name === 'Html' ? 'text/html' : 'application/octet-stream']: { itemSchema } } };
158
159
  }
@@ -0,0 +1,45 @@
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /** Serialize writers while allowing independent projects to share immutable cached Git objects. */
4
+ export function withPackageLock(path, action) {
5
+ const deadline = Date.now() + 30000;
6
+ while (true) {
7
+ try {
8
+ mkdirSync(path);
9
+ break;
10
+ }
11
+ catch (error) {
12
+ if (!error || typeof error !== 'object' || !('code' in error) || error.code !== 'EEXIST')
13
+ throw error;
14
+ let stale = false;
15
+ try {
16
+ const pid = Number(readFileSync(join(path, 'pid'), 'utf8'));
17
+ if (!Number.isSafeInteger(pid) || pid < 1)
18
+ throw new Error('Invalid lock owner');
19
+ try {
20
+ process.kill(pid, 0);
21
+ }
22
+ catch (error) {
23
+ stale = !!error && typeof error === 'object' && 'code' in error && error.code === 'ESRCH';
24
+ }
25
+ }
26
+ catch {
27
+ stale = existsSync(path) && Date.now() - statSync(path).mtimeMs > 180000;
28
+ }
29
+ if (stale) {
30
+ rmSync(path, { recursive: true, force: true });
31
+ continue;
32
+ }
33
+ if (Date.now() >= deadline)
34
+ throw new Error('Another August package installation is still running. Let it finish, then retry. Lock: ' + path);
35
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100);
36
+ }
37
+ }
38
+ try {
39
+ writeFileSync(join(path, 'pid'), String(process.pid));
40
+ return action();
41
+ }
42
+ finally {
43
+ rmSync(path, { recursive: true, force: true });
44
+ }
45
+ }
@@ -2,9 +2,25 @@ import { createHash } from 'node:crypto';
2
2
  import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, writeFileSync } from 'node:fs';
3
3
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
4
4
  import { spawnSync } from 'node:child_process';
5
+ import { x as extractArchive } from 'tar';
5
6
  import { loadConfig } from "./config.js";
7
+ import { parse } from "./parser.js";
8
+ import { isGitSource, materializeGit, sourceAlias } from "./git-packages.js";
9
+ import { agentInstructions } from "./project-init.js";
10
+ import { withPackageLock } from "./package-locking.js";
6
11
  export const compilerVersion = () => JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
7
12
  export const packageAlias = (name) => /^[a-z][a-z0-9_]*$/.test(name) && name !== 'august';
13
+ /** Repository imports declare their dependencies beside the code that uses them. */
14
+ export function packageSpecifications(sourceRoot, declared, overrides = new Map()) {
15
+ const specifications = { ...declared };
16
+ for (const path of sourcePaths(sourceRoot)) {
17
+ const file = parse(path, overrides.get(path) ?? readFileSync(path, 'utf8')).file;
18
+ for (const item of file.items)
19
+ if (item.kind === 'import' && isGitSource(item.from[0]))
20
+ specifications[sourceAlias(item.from[0])] = item.from[0];
21
+ }
22
+ return ordered(specifications);
23
+ }
8
24
  const version = /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/;
9
25
  const npmName = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
10
26
  const json = (file) => JSON.parse(readFileSync(file, 'utf8'));
@@ -38,8 +54,11 @@ export function sourcePaths(root) {
38
54
  if (entry.name.startsWith('.') || ['node_modules', 'dist'].includes(entry.name))
39
55
  continue;
40
56
  const file = join(root, entry.name);
41
- if (entry.isSymbolicLink())
42
- throw new Error(`Package source cannot contain a symlink: ${file}`);
57
+ if (entry.isSymbolicLink()) {
58
+ if (entry.name.endsWith('.aug'))
59
+ throw new Error(`Package source cannot contain a symbolic link: ${file}`);
60
+ continue;
61
+ }
43
62
  if (entry.isDirectory())
44
63
  result.push(...sourcePaths(file));
45
64
  else if (entry.isFile() && entry.name.endsWith('.aug'))
@@ -48,7 +67,10 @@ export function sourcePaths(root) {
48
67
  return result;
49
68
  }
50
69
  export function readPackage(directory) {
51
- const manifest = json(join(directory, 'aug-package.json'));
70
+ const manifest = existsSync(join(directory, 'aug-package.json')) ? json(join(directory, 'aug-package.json')) : {
71
+ format: 1, name: 'aug-' + sourceAlias(realpathSync(directory)), version: '0.0.0', compiler: compilerVersion(),
72
+ source: existsSync(join(directory, 'export.aug')) ? '.' : 'src', dependencies: {}
73
+ };
52
74
  if (manifest.format !== 1 || !npmName.test(manifest.name ?? '') || !version.test(manifest.version ?? '') ||
53
75
  manifest.compiler !== compilerVersion())
54
76
  throw new Error(`Invalid August package or compiler mismatch in ${directory}; expected compiler ${compilerVersion()}`);
@@ -64,12 +86,14 @@ export function readPackage(directory) {
64
86
  throw new Error(`Invalid package dependency ${alias}`);
65
87
  normalizeSpecifier(spec, directory, false);
66
88
  }
67
- const published = json(join(directory, 'package.json'));
68
- if (published.name !== manifest.name || published.version !== manifest.version)
89
+ const published = existsSync(join(directory, 'package.json')) ? json(join(directory, 'package.json')) : undefined;
90
+ if (published && (published.name !== manifest.name || published.version !== manifest.version))
69
91
  throw new Error('package.json and aug-package.json names/versions must match');
70
- const declared = manifest.dependencies ?? {}, actual = published.dependencies ?? {};
71
- if (Object.keys(actual).length !== Object.keys(declared).length || Object.entries(declared).some(([alias, spec]) => actual[alias] !== spec))
72
- throw new Error('package.json dependencies must match the August dependency aliases; aug package pack synchronizes them');
92
+ const configuration = loadConfig(directory);
93
+ if (configuration.diagnostics.length)
94
+ throw new Error(`Invalid package configuration in ${directory}: ${configuration.diagnostics.map(issue => issue.message).join('; ')}`);
95
+ manifest.dependencies = { ...configuration.config.packages, ...manifest.dependencies };
96
+ const declared = manifest.dependencies ?? {};
73
97
  for (const alias of Object.keys(declared))
74
98
  assertAlias(sourceRoot, alias);
75
99
  return { manifest, sourceRoot };
@@ -81,6 +105,8 @@ function assertAlias(root, alias) {
81
105
  throw new Error(`Package alias ${alias} conflicts with a local module`);
82
106
  }
83
107
  function normalizeSpecifier(spec, root, requirePath = true) {
108
+ if (isGitSource(spec))
109
+ return spec;
84
110
  if (spec.startsWith('npm:')) {
85
111
  const match = /^npm:((?:@[^/]+\/)?[^@]+)@(.+)$/.exec(spec);
86
112
  if (!match || !npmName.test(match[1]) || !version.test(match[2]))
@@ -101,7 +127,7 @@ function normalizeSpecifier(spec, root, requirePath = true) {
101
127
  }
102
128
  function packageDigest(directory, sourceRoot) {
103
129
  const hash = createHash('sha256');
104
- for (const file of [join(directory, 'aug-package.json'), join(directory, 'package.json'), ...sourcePaths(sourceRoot)].sort()) {
130
+ for (const file of [join(directory, 'aug-package.json'), join(directory, 'package.json'), ...sourcePaths(sourceRoot)].filter(existsSync).sort()) {
105
131
  hash.update(relative(directory, file).replaceAll('\\', '/'));
106
132
  hash.update('\0');
107
133
  hash.update(readFileSync(file));
@@ -111,7 +137,7 @@ function packageDigest(directory, sourceRoot) {
111
137
  }
112
138
  /** Compilation reads only a verified installed snapshot. It never fetches dependencies. */
113
139
  export function projectPackages(root, specifications, sourceFolder = root) {
114
- const result = { roots: new Map(), scopes: new Map(), diagnostics: [] };
140
+ const result = { roots: new Map(), scopes: new Map(), diagnostics: [], specifications };
115
141
  if (!Object.keys(specifications).length)
116
142
  return result;
117
143
  try {
@@ -133,7 +159,7 @@ export function projectPackages(root, specifications, sourceFolder = root) {
133
159
  if (result.scopes.has(entry.path))
134
160
  throw new Error('Duplicate package lock path');
135
161
  manifests.set(entry.path, manifest);
136
- result.scopes.set(entry.path, { ...entry, directory, sourceRoot });
162
+ result.scopes.set(entry.path, { ...entry, directory, sourceRoot, specifications: manifest.dependencies ?? {} });
137
163
  }
138
164
  verifyIdentities(lock.packages);
139
165
  for (const scope of result.scopes.values()) {
@@ -179,76 +205,208 @@ export function projectPackages(root, specifications, sourceFolder = root) {
179
205
  }
180
206
  function npm(args, cwd) {
181
207
  const process = spawnSync('npm', args, { cwd, encoding: 'utf8', timeout: 120000 });
182
- if (process.error || process.status !== 0)
183
- throw new Error(process.error?.message ?? process.stderr ?? 'npm failed');
208
+ if (process.error)
209
+ throw new Error(`Cannot install August packages: ${'code' in process.error && process.error.code === 'ENOENT' ? 'npm is missing from PATH. Install Node.js 24 or newer, which includes npm.' : process.error.message}\nRetry aug run after fixing the package installer.`);
210
+ if (process.status !== 0)
211
+ throw new Error(`August package installation failed.\n${(process.stderr || process.stdout || `npm exited ${process.status}`).trim()}\nCheck the package versions and paths in main.yaml, your network connection, and npm registry configuration. Retry aug run; use aug install for an explicit installation.`);
184
212
  return process.stdout;
185
213
  }
186
- export function installPackages(root, frozen = false, offline = false) {
214
+ /** Running an application prepares its declared packages; checking remains read-only. */
215
+ export function prepareRunPackages(root, offline = false) {
216
+ const loaded = loadConfig(root);
217
+ if (loaded.diagnostics.length)
218
+ return; // The checker renders the configuration's source diagnostics.
219
+ const library = isLibrary(root) ? readPackage(root) : undefined;
220
+ const specifications = packageSpecifications(library?.sourceRoot ?? root, library?.manifest.dependencies ?? loaded.config.packages);
221
+ if (!Object.keys(specifications).length)
222
+ return;
223
+ const lockPath = join(root, 'aug.lock.json');
224
+ let lock;
225
+ if (existsSync(lockPath)) {
226
+ try {
227
+ lock = json(lockPath);
228
+ }
229
+ catch {
230
+ throw new Error('aug.lock.json is unreadable. Restore it from version control or run aug install to recreate it.');
231
+ }
232
+ if (lock?.format !== 1 || !Array.isArray(lock.packages) || !lock.specifications || typeof lock.specifications !== 'object')
233
+ throw new Error('aug.lock.json has an unsupported structure. Run aug install to recreate it.');
234
+ }
235
+ const matching = lock?.compiler === compilerVersion() && sameSpecifications(lock.specifications, specifications);
236
+ if (!matching) {
237
+ process.stderr.write('Installing August packages declared by imports and main.yaml…\n');
238
+ installPackages(root, false, offline);
239
+ return;
240
+ }
241
+ const snapshot = resolve(root, '.aug-packages');
242
+ const missing = lock.packages.some(entry => {
243
+ if (typeof entry.path !== 'string' || isAbsolute(entry.path) || !inside(snapshot, resolve(snapshot, entry.path)))
244
+ throw new Error('Package lock contains a path outside its snapshot. Run aug install to recreate it.');
245
+ return !existsSync(resolve(snapshot, entry.path));
246
+ });
247
+ if (missing) {
248
+ process.stderr.write('Restoring August packages from aug.lock.json…\n');
249
+ installPackages(root, true, offline);
250
+ }
251
+ // projectPackages checks contents and integrity before compilation. Changed installed sources are never silently replaced.
252
+ }
253
+ export function installPackages(root, frozen = false, offline = false, update = false) {
254
+ return withPackageLock(join(root, '.aug-install.lock'), () => installLocked(root, frozen, offline, update));
255
+ }
256
+ function installLocked(root, frozen, offline, update) {
257
+ if (frozen && update)
258
+ throw new Error('--frozen and --update cannot be used together.');
187
259
  const loaded = loadConfig(root);
188
260
  if (loaded.diagnostics.length)
189
261
  throw new Error(loaded.diagnostics.map(issue => issue.message).join('\n'));
190
- const library = existsSync(join(root, 'aug-package.json')) ? json(join(root, 'aug-package.json')) : undefined;
191
- if (library)
192
- preparePackage(root);
193
- const specifications = ordered(library?.dependencies ?? loaded.config.packages);
262
+ const library = isLibrary(root) ? readPackage(root) : undefined;
263
+ const specifications = packageSpecifications(library?.sourceRoot ?? root, library?.manifest.dependencies ?? loaded.config.packages);
194
264
  for (const alias of Object.keys(specifications))
195
- assertAlias(library ? resolve(root, library.source) : root, alias);
265
+ assertAlias(library?.sourceRoot ?? root, alias);
196
266
  const lockPath = join(root, 'aug.lock.json');
197
267
  const previous = existsSync(lockPath) ? json(lockPath) : undefined;
198
- const same = previous?.compiler === compilerVersion() && sameSpecifications(previous.specifications, specifications);
268
+ const same = !update && previous?.compiler === compilerVersion() && sameSpecifications(previous.specifications, specifications);
199
269
  if (frozen && !same)
200
270
  throw new Error('Frozen installation requires a matching aug.lock.json');
271
+ return installSourceGraph(root, specifications, frozen, offline, same ? previous : undefined);
272
+ }
273
+ const isLibrary = (root) => existsSync(join(root, 'aug-package.json')) ||
274
+ !existsSync(join(root, 'main.aug')) && (existsSync(join(root, 'export.aug')) || existsSync(join(root, 'src/export.aug')));
275
+ const selectedSource = (file) => file.endsWith('.aug') || ['aug-package.json', 'package.json', 'main.yaml', 'README.md', 'LICENSE'].includes(file);
276
+ function copySource(origin, destination) {
277
+ let bytes = 0, count = 0;
278
+ const copy = (folder) => {
279
+ for (const entry of readdirSync(folder, { withFileTypes: true })) {
280
+ if (entry.name.startsWith('.') || ['node_modules', 'dist'].includes(entry.name))
281
+ continue;
282
+ const file = join(folder, entry.name), name = relative(origin, file);
283
+ if (entry.isDirectory())
284
+ copy(file);
285
+ else if (selectedSource(name)) {
286
+ if (!entry.isFile())
287
+ throw new Error('Package source must contain regular files: ' + name);
288
+ const data = readFileSync(file);
289
+ bytes += data.length;
290
+ if (++count > 10000 || bytes > 32 * 1024 * 1024)
291
+ throw new Error('Source package exceeds 10,000 files or 32 MiB.');
292
+ mkdirSync(dirname(join(destination, name)), { recursive: true });
293
+ writeFileSync(join(destination, name), data);
294
+ }
295
+ }
296
+ };
297
+ copy(origin);
298
+ }
299
+ function unpackSource(archive, destination) {
300
+ let bytes = 0, count = 0;
301
+ const paths = new Set();
302
+ extractArchive({ file: archive, cwd: destination, strip: 1, sync: true, strict: true, filter: (path, entry) => {
303
+ if (!('type' in entry))
304
+ throw new Error('Expected an archive entry.');
305
+ const parts = path.split('/');
306
+ if (isAbsolute(path) || path.includes('\\') || parts.some(part => part === '..'))
307
+ throw new Error('Package archive contains a path outside its folder.');
308
+ const name = parts.slice(1).join('/');
309
+ if (entry.type === 'Directory')
310
+ return false;
311
+ if (!selectedSource(name))
312
+ return false;
313
+ if (entry.type !== 'File' || !name || parts[0] !== 'package' || parts.slice(1).some(part => !part || part.startsWith('.')))
314
+ throw new Error('Package archive source must be regular files inside package/.');
315
+ if (paths.has(name))
316
+ throw new Error('Package archive repeats a source file: ' + name);
317
+ paths.add(name);
318
+ bytes += entry.size;
319
+ if (++count > 10000 || bytes > 32 * 1024 * 1024)
320
+ throw new Error('Source package exceeds 10,000 files or 32 MiB.');
321
+ return true;
322
+ } });
323
+ }
324
+ /** Git libraries use the same checked source graph as registry libraries. No remote program is executed. */
325
+ function installSourceGraph(root, specifications, frozen, offline, previous) {
201
326
  const stage = realpathSync(mkdtempSync(join(root, '.aug-install-')));
327
+ const packages = new Map(), visited = new Map();
328
+ const gitSources = new Map();
329
+ const registry = {};
330
+ const locked = new Map((previous?.git ?? []).map(source => [source.request, source]));
331
+ const visit = (spec, owner) => {
332
+ const normalized = normalizeSpecifier(spec, owner);
333
+ if (visited.has(normalized))
334
+ return visited.get(normalized);
335
+ if (visited.size >= 1000)
336
+ throw new Error('Package graph exceeds 1,000 source packages.');
337
+ const identity = normalized.startsWith('file:') ? 'file:' + relative(root, normalized.slice(5)).replaceAll('\\', '/') : normalized;
338
+ const path = 'packages/' + sourceAlias(identity), directory = join(stage, path);
339
+ visited.set(normalized, path);
340
+ mkdirSync(directory, { recursive: true });
341
+ let origin = directory;
342
+ let source;
343
+ if (isGitSource(normalized)) {
344
+ source = materializeGit(normalized, directory, offline, locked.get(normalized));
345
+ gitSources.set(normalized, source);
346
+ }
347
+ else if (normalized.startsWith('file:') && lstatSync(normalized.slice(5)).isDirectory()) {
348
+ origin = normalized.slice(5);
349
+ copySource(origin, directory);
350
+ }
351
+ else {
352
+ const transport = join(stage, 'transport', sourceAlias(normalized));
353
+ mkdirSync(transport, { recursive: true });
354
+ const request = normalized.startsWith('npm:') ? normalized.slice(4) : normalized.slice(5);
355
+ const packed = JSON.parse(npm(['pack', request, '--ignore-scripts', '--json', '--pack-destination', transport,
356
+ ...(offline ? ['--offline'] : [])], transport))[0];
357
+ if (!packed?.filename || !/^sha512-[A-Za-z0-9+/=]+$/.test(packed.integrity ?? ''))
358
+ throw new Error('Package archive is missing its SHA-512 integrity.');
359
+ registry[normalized] = { integrity: packed.integrity, name: packed.name, version: packed.version };
360
+ const archive = join(transport, basename(packed.filename));
361
+ const actual = 'sha512-' + createHash('sha512').update(readFileSync(archive)).digest('base64');
362
+ if (actual !== packed.integrity)
363
+ throw new Error('Package archive integrity mismatch.');
364
+ if (frozen && JSON.stringify(previous?.npm?.[normalized]) !== JSON.stringify(registry[normalized]))
365
+ throw new Error('Frozen package archive changed. Publish a new version instead of replacing an archive.');
366
+ unpackSource(archive, directory);
367
+ }
368
+ if (!existsSync(join(directory, 'aug-package.json'))) {
369
+ const folder = existsSync(join(directory, 'export.aug')) ? '.' : 'src';
370
+ const published = existsSync(join(directory, 'package.json')) ? json(join(directory, 'package.json')) : undefined;
371
+ writeJson(join(directory, 'aug-package.json'), { format: 1,
372
+ name: published?.name ?? '@git/' + sourceAlias(source ? source.repository + '/' + source.folder : identity),
373
+ version: published?.version ?? (source ? '0.0.0-git.' + source.commit : '0.0.0'),
374
+ compiler: compilerVersion(), source: folder, dependencies: published?.dependencies ?? {} });
375
+ }
376
+ const manifest = json(join(directory, 'aug-package.json'));
377
+ // A Git folder owns its August manifest. npm metadata and lifecycle scripts have no role here.
378
+ const dependencies = packageSpecifications(resolve(directory, manifest.source), { ...loadConfig(directory).config.packages, ...manifest.dependencies });
379
+ manifest.dependencies = dependencies;
380
+ writeJson(join(directory, 'aug-package.json'), manifest);
381
+ writeJson(join(directory, 'package.json'), { name: manifest.name, version: manifest.version, private: true, dependencies });
382
+ const { sourceRoot } = readPackage(directory);
383
+ const entry = { path, name: manifest.name, version: manifest.version, source: manifest.source,
384
+ digest: packageDigest(directory, sourceRoot), dependencies: {} };
385
+ packages.set(path, entry);
386
+ for (const [alias, request] of Object.entries(dependencies)) {
387
+ entry.dependencies[alias] = visit(request, origin);
388
+ verifyReference(request, packages.get(entry.dependencies[alias]));
389
+ }
390
+ return path;
391
+ };
202
392
  try {
203
- const dependencies = Object.fromEntries(Object.entries(specifications).map(([alias, spec]) => {
204
- const normalized = normalizeSpecifier(spec, root);
205
- return [alias, normalized.startsWith('file:') ? 'file:' + relative(stage, normalized.slice(5)).replaceAll('\\', '/') : normalized];
206
- }));
207
- writeJson(join(stage, 'package.json'), { name: 'august-project-dependencies', version: '0.0.0', private: true, dependencies });
208
- if (same && previous?.npm)
209
- writeJson(join(stage, 'package-lock.json'), previous.npm);
210
- npm([frozen ? 'ci' : 'install', '--ignore-scripts', '--install-links', '--bin-links=false', '--no-audit', '--no-fund',
211
- ...(offline ? ['--offline'] : [])], stage);
212
- const packages = new Map();
213
- const visit = (directory) => {
214
- const actual = realpathSync(directory);
215
- if (!inside(stage, actual))
216
- throw new Error('Package installer did not create a self-contained snapshot');
217
- const path = relative(stage, actual).replaceAll('\\', '/');
218
- if (packages.has(path))
219
- return path;
220
- const { manifest, sourceRoot } = readPackage(actual);
221
- const entry = { path, name: manifest.name, version: manifest.version, source: manifest.source,
222
- digest: packageDigest(actual, sourceRoot), dependencies: {} };
223
- packages.set(path, entry);
224
- for (const alias of Object.keys(manifest.dependencies ?? {})) {
225
- let owner = actual;
226
- while (inside(stage, owner) && !existsSync(join(owner, 'node_modules', alias, 'aug-package.json')))
227
- owner = dirname(owner);
228
- if (!inside(stage, owner))
229
- throw new Error(`${manifest.name} is missing dependency ${alias}`);
230
- entry.dependencies[alias] = visit(join(owner, 'node_modules', alias));
231
- verifyReference(manifest.dependencies[alias], packages.get(entry.dependencies[alias]));
232
- }
233
- return path;
234
- };
235
- const roots = Object.fromEntries(Object.keys(specifications).map(alias => [alias, visit(join(stage, 'node_modules', alias))]));
236
- const lock = { format: 1, compiler: compilerVersion(), specifications, roots,
237
- packages: [...packages.values()].sort((a, b) => a.path.localeCompare(b.path)), npm: json(join(stage, 'package-lock.json')) };
238
- verifyIdentities(lock.packages);
239
- for (const [alias, path] of Object.entries(roots))
240
- verifyReference(specifications[alias], packages.get(path));
241
- if (frozen && JSON.stringify(lock.packages) !== JSON.stringify(previous.packages))
242
- throw new Error('Frozen package contents changed; update the lock explicitly with aug install');
393
+ const roots = Object.fromEntries(Object.entries(specifications).map(([alias, request]) => [alias, visit(request, root)]));
394
+ verifyIdentities(packages.values());
395
+ const lock = { format: 1, compiler: compilerVersion(), specifications, roots, npm: registry,
396
+ git: [...gitSources.values()].sort((a, b) => a.request.localeCompare(b.request)),
397
+ packages: [...packages.values()].sort((a, b) => a.path.localeCompare(b.path)) };
398
+ if (frozen && JSON.stringify(lock.packages) !== JSON.stringify(previous?.packages))
399
+ throw new Error('Frozen package contents changed; use aug install --update to choose new revisions.');
400
+ rmSync(join(stage, 'transport'), { recursive: true, force: true });
243
401
  const cache = join(root, '.aug-packages'), backup = join(root, '.aug-packages-old');
244
402
  if (existsSync(backup))
245
- throw new Error('Previous package install backup exists; inspect .aug-packages-old before installing');
403
+ throw new Error('Previous package install backup exists; inspect .aug-packages-old before installing.');
246
404
  if (existsSync(cache))
247
405
  renameSync(cache, backup);
248
406
  try {
249
407
  renameSync(stage, cache);
250
- writeJson(lockPath + '.tmp', lock);
251
- renameSync(lockPath + '.tmp', lockPath);
408
+ writeJson(join(root, 'aug.lock.json.tmp'), lock);
409
+ renameSync(join(root, 'aug.lock.json.tmp'), join(root, 'aug.lock.json'));
252
410
  }
253
411
  catch (error) {
254
412
  rmSync(cache, { recursive: true, force: true });
@@ -263,16 +421,18 @@ export function installPackages(root, frozen = false, offline = false) {
263
421
  rmSync(stage, { recursive: true, force: true });
264
422
  }
265
423
  }
266
- export function initPackage(directory, name) {
424
+ export function initPackage(directory, name, npmMetadata = false) {
267
425
  if (!npmName.test(name))
268
426
  throw new Error('Package name must be an npm name, for example @owner/aug-math');
269
427
  if (existsSync(directory) && readdirSync(directory).length)
270
428
  throw new Error('Package init requires a new or empty directory');
271
429
  mkdirSync(join(directory, 'src'), { recursive: true });
430
+ writeFileSync(join(directory, 'AGENTS.md'), agentInstructions);
272
431
  const manifest = { format: 1, name, version: '0.1.0', compiler: compilerVersion(), source: 'src', dependencies: {} };
273
432
  writeJson(join(directory, 'aug-package.json'), manifest);
274
- writeJson(join(directory, 'package.json'), { name, version: manifest.version, description: 'An August source library',
275
- files: ['src', '.aug-spec', 'aug-package.json', 'README.md', 'LICENSE'], exports: { './aug-package.json': './aug-package.json' }, dependencies: {} });
433
+ if (npmMetadata)
434
+ writeJson(join(directory, 'package.json'), { name, version: manifest.version, description: 'An August source library',
435
+ files: ['src', '.aug-spec', 'aug-package.json', 'README.md', 'LICENSE'], exports: { './aug-package.json': './aug-package.json' }, dependencies: {} });
276
436
  writeFileSync(join(directory, 'src/export.aug'), 'export add from arithmetic\n');
277
437
  writeFileSync(join(directory, 'src/arithmetic.aug'), '/** Add two integers. @param left First value. @param right Second value. @return Their sum. */\nadd(int left, int right) returns int {\n return left + right\n}\n\ntest add {\n when addition {\n it adds_two_integers {\n assert(add(left=2, right=3) == 5)\n }\n }\n}\n');
278
438
  writeFileSync(join(directory, 'README.md'), `# ${name}\n\nAugust ${compilerVersion()} source library. Public exports live in src/export.aug.\n`);
@@ -281,7 +441,7 @@ export function initPackage(directory, name) {
281
441
  /** Synchronize transport metadata; August's manifest owns dependency aliases. */
282
442
  export function preparePackage(root) {
283
443
  const manifest = json(join(root, 'aug-package.json'));
284
- const transport = json(join(root, 'package.json'));
444
+ const transport = existsSync(join(root, 'package.json')) ? json(join(root, 'package.json')) : {};
285
445
  transport.name = manifest.name;
286
446
  transport.version = manifest.version;
287
447
  transport.dependencies = manifest.dependencies ?? {};
@@ -297,3 +457,27 @@ export function packPackage(root) {
297
457
  throw new Error('npm pack returned no archive');
298
458
  return join(destination, basename(result.filename));
299
459
  }
460
+ /** Give a source package a short import name and install its verified dependency graph. */
461
+ export function addPackage(root, request, alias, offline = false) {
462
+ const loaded = loadConfig(root);
463
+ if (loaded.diagnostics.length)
464
+ throw new Error(loaded.diagnostics.map(issue => issue.message).join('\n'));
465
+ assertAlias(isLibrary(root) ? readPackage(root).sourceRoot : root, alias);
466
+ normalizeSpecifier(request, root);
467
+ const path = join(root, 'main.yaml'), existed = existsSync(path), before = existed ? readFileSync(path, 'utf8') : '';
468
+ const dependencies = { ...loaded.config.packages, [alias]: request };
469
+ const block = 'packages:\n' + Object.entries(ordered(dependencies)).map(([name, value]) => ' ' + name + ': ' + JSON.stringify(value)).join('\n') + '\n';
470
+ const expression = /^packages:[^\n]*(?:\n|$)(?:[ \t][^\n]*(?:\n|$)|\n)*/m;
471
+ const after = expression.test(before) ? before.replace(expression, block) : before.trimEnd() + (before.trim() ? '\n\n' : '') + block;
472
+ writeFileSync(path, after);
473
+ try {
474
+ return installPackages(root, false, offline);
475
+ }
476
+ catch (error) {
477
+ if (existed)
478
+ writeFileSync(path, before);
479
+ else
480
+ rmSync(path, { force: true });
481
+ throw error;
482
+ }
483
+ }
package/src/parser.js CHANGED
@@ -416,7 +416,9 @@ class Parser {
416
416
  while (!everything && this.match('and'))
417
417
  names.push(this.expect('identifier').value);
418
418
  this.expect('from');
419
- const from = [this.expect('identifier').value];
419
+ const from = [this.at('string') ? this.take().value : this.expect('identifier').value];
420
+ if (!/^(?:https:\/\/|git\+(?:https|file):\/\/)/.test(from[0]) && this.tokens[this.position - 1].kind === 'string')
421
+ throw new ParseFailure({ ...start, code: 'IMPORT', message: 'A quoted import source must be a public repository URL' });
420
422
  while (this.match('.'))
421
423
  from.push(this.expect('identifier').value);
422
424
  this.endStatement();
@@ -462,11 +464,13 @@ class Parser {
462
464
  const header = this.parseTypeParams();
463
465
  const fields = this.parseParams(true);
464
466
  const validationErrors = [];
465
- if (this.match('unless')) {
467
+ const validationDeclared = !!this.match('unless');
468
+ if (validationDeclared) {
466
469
  validationErrors.push(this.parseType());
467
470
  while (this.match('and') || this.match(','))
468
471
  validationErrors.push(this.parseType());
469
472
  }
473
+ const headerEnd = this.current().span.start;
470
474
  let constructorBody = this.match('=>') ? this.parseBlock(start) : undefined;
471
475
  let hasBody = !!constructorBody;
472
476
  if (!constructorBody && (this.at('{') || this.at(':'))) {
@@ -486,7 +490,7 @@ class Parser {
486
490
  if (!hasBody)
487
491
  this.endStatement();
488
492
  return { kind: 'class', record: true, name, ...header, fields, constructorBody,
489
- validationErrors, implements: [], methods: [], span: this.span(start) };
493
+ validationErrors, validationDeclared, headerEnd, implements: [], methods: [], span: this.span(start) };
490
494
  }
491
495
  parseClass() {
492
496
  const start = this.current().span;
@@ -502,6 +506,7 @@ class Parser {
502
506
  implemented.push(this.parseType());
503
507
  while (this.match(','))
504
508
  implemented.push(this.parseType());
509
+ const headerEnd = this.current().span.start;
505
510
  this.openBlock(start);
506
511
  const methods = [];
507
512
  const stateFields = [];
@@ -537,7 +542,7 @@ class Parser {
537
542
  }
538
543
  this.closeBrace();
539
544
  return { kind: 'class', name, typeParams, typeConstraints, typeVariance, fields, stateFields, constructorBody,
540
- implements: implemented, methods, span: this.span(start) };
545
+ implements: implemented, methods, headerEnd, span: this.span(start) };
541
546
  }
542
547
  parseInterface() {
543
548
  const keyword = this.take();
@@ -638,13 +643,16 @@ class Parser {
638
643
  } while (this.match(',') || this.match('and'));
639
644
  }
640
645
  }
646
+ const headerEnd = this.current().span.start;
641
647
  const body = this.at('{') || this.at(':') ? this.parseBlock(start) : (this.endStatement(), undefined);
642
648
  if (externC && body) {
643
649
  throw new ParseFailure({ file: start.file, line: start.line, column: start.column,
644
650
  message: 'extern C functions cannot have a body', code: 'PARSE' });
645
651
  }
646
652
  return { kind: 'function', name, typeParams, typeConstraints, typeVariance, params, returns, returnOwnership,
647
- throws, changes, uses, body, externC, valueAbi, nativePure, endpoint, annotations, span: this.span(start) };
653
+ throws, changes, uses, body, externC, valueAbi, nativePure, endpoint, annotations,
654
+ declared: { returns: clauses.has('returns') || clauses.has('streams'), errors: clauses.has('unless'),
655
+ changes: clauses.has('changes'), uses: clauses.has('uses') }, headerEnd, span: this.span(start) };
648
656
  }
649
657
  parseTypeParams() {
650
658
  if (!this.match('<'))
package/src/policies.js CHANGED
@@ -85,11 +85,11 @@ export function projectPolicies(project) {
85
85
  if (!params.some(param => (param.label ?? param.name) === label))
86
86
  report(node.span, `@param ${label} does not name a public input of ${node.name}`, 'DOC');
87
87
  for (const tag of doc.tags ?? []) {
88
- if (['return', 'returns'].includes(tag.name) && !('returns' in node && node.returns.name !== 'void'))
88
+ if (node.kind !== 'function' && ['return', 'returns'].includes(tag.name))
89
89
  report(node.span, `@${tag.name} requires a value-returning callable`, 'DOC');
90
- if (['throws', 'exception'].includes(tag.name)) {
90
+ if (node.kind !== 'function' && !(node.kind === 'class' && node.record && node.validationDeclared === false) && ['throws', 'exception'].includes(tag.name)) {
91
91
  const name = tag.value.split(/\s/)[0];
92
- const errors = 'throws' in node ? node.throws : 'validationErrors' in node ? node.validationErrors ?? [] : [];
92
+ const errors = node.kind === 'class' ? node.validationErrors ?? [] : [];
93
93
  if (!('annotations' in node && node.annotations?.length) && !errors.some(error => error.name === name))
94
94
  report(node.span, `@${tag.name} ${name} is absent from ${node.name}'s unless contract`, 'DOC');
95
95
  }