@greenpandastudios/aug-cli 0.20.1 → 0.21.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 (295) hide show
  1. package/README.md +1 -1
  2. package/docs/assets/benchmarks/execution.svg +774 -637
  3. package/docs/assets/benchmarks/http.svg +278 -249
  4. package/docs/assets/benchmarks/improvements.svg +66 -66
  5. package/docs/assets/benchmarks/kernels-mobile.svg +1 -0
  6. package/docs/assets/benchmarks/kernels.svg +1 -0
  7. package/docs/assets/benchmarks/memory.svg +153 -153
  8. package/docs/benchmark-results.json +227089 -90363
  9. package/docs/compatibility.md +6 -6
  10. package/docs/contributing-benchmarks.md +36 -6
  11. package/docs/dev-containers.md +8 -15
  12. package/docs/dgx-consumers.json +122 -0
  13. package/docs/dgx-gyms.json +784 -0
  14. package/docs/dgx-kernels.json +1170 -0
  15. package/docs/dgx-performance.json +227849 -0
  16. package/docs/dgx-spark.md +64 -0
  17. package/docs/diagnostics.md +1 -1
  18. package/docs/docker.md +16 -17
  19. package/docs/example-projects.json +32 -0
  20. package/docs/examples/approved-design/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  21. package/docs/examples/approved-design/domain/app.md +4 -4
  22. package/docs/examples/approved-design/main.md +2 -2
  23. package/docs/examples/calls-benchmark/index.md +36 -0
  24. package/docs/examples/calls-benchmark/main.md +78 -0
  25. package/docs/examples/calls-benchmark/operations.md +60 -0
  26. package/docs/examples/developer-workflow/calculator.md +5 -5
  27. package/docs/examples/developer-workflow/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  28. package/docs/examples/developer-workflow/logging/console.md +2 -2
  29. package/docs/examples/developer-workflow/logging/logger.md +2 -2
  30. package/docs/examples/developer-workflow/main.md +2 -2
  31. package/docs/examples/errors-benchmark/index.md +36 -0
  32. package/docs/examples/errors-benchmark/main.md +92 -0
  33. package/docs/examples/errors-benchmark/operations.md +65 -0
  34. package/docs/examples/float-benchmark/index.md +35 -0
  35. package/docs/examples/float-benchmark/main.md +75 -0
  36. package/docs/examples/generic-di/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  37. package/docs/examples/generic-di/main.md +2 -2
  38. package/docs/examples/generic-di/types.md +3 -3
  39. package/docs/examples/hello/app/greeter.md +3 -3
  40. package/docs/examples/hello/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  41. package/docs/examples/hello/logging/console.md +2 -2
  42. package/docs/examples/hello/logging/logger.md +2 -2
  43. package/docs/examples/hello/main.md +2 -2
  44. package/docs/examples/index.md +18 -1
  45. package/docs/examples/interceptors/app.md +5 -5
  46. package/docs/examples/interceptors/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  47. package/docs/examples/interceptors/interceptors.md +2 -2
  48. package/docs/examples/interceptors/logging.md +3 -3
  49. package/docs/examples/interceptors/main.md +2 -2
  50. package/docs/examples/list-benchmark/index.md +35 -0
  51. package/docs/examples/list-benchmark/main.md +78 -0
  52. package/docs/examples/map-churn-benchmark/index.md +35 -0
  53. package/docs/examples/map-churn-benchmark/main.md +106 -0
  54. package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/api.md +104 -0
  55. package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.md +54 -0
  56. package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi-json.md +48 -0
  57. package/docs/examples/native-blake3/hashing.md +93 -0
  58. package/docs/examples/native-blake3/index.md +38 -0
  59. package/docs/examples/native-blake3/main.md +73 -0
  60. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/api.md +406 -0
  61. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.md +51 -0
  62. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.md +63 -0
  63. package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi-json.md +161 -0
  64. package/docs/examples/native-pytorch/index.md +38 -0
  65. package/docs/examples/native-pytorch/main.md +73 -0
  66. package/docs/examples/native-pytorch/tensors.md +123 -0
  67. package/docs/examples/native-sqlite/database.md +116 -0
  68. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/api.md +284 -0
  69. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.md +51 -0
  70. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.md +75 -0
  71. package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi-json.md +119 -0
  72. package/docs/examples/native-sqlite/index.md +38 -0
  73. package/docs/examples/native-sqlite/main.md +73 -0
  74. package/docs/examples/native-zlib/compression.md +99 -0
  75. package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/api.md +153 -0
  76. package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.md +54 -0
  77. package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi-json.md +76 -0
  78. package/docs/examples/native-zlib/index.md +38 -0
  79. package/docs/examples/native-zlib/main.md +78 -0
  80. package/docs/examples/new-syntax/console.md +2 -2
  81. package/docs/examples/new-syntax/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  82. package/docs/examples/new-syntax/greeter.md +3 -3
  83. package/docs/examples/new-syntax/logger.md +2 -2
  84. package/docs/examples/new-syntax/main.md +2 -2
  85. package/docs/examples/ownership-transfer/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
  86. package/docs/examples/ownership-transfer/main.md +2 -2
  87. package/docs/examples/ownership-transfer/resource.md +2 -2
  88. package/docs/examples/packages-math/aug-package-json.md +1 -1
  89. package/docs/examples/records-benchmark/data.md +55 -0
  90. package/docs/examples/records-benchmark/index.md +36 -0
  91. package/docs/examples/records-benchmark/main.md +85 -0
  92. package/docs/examples/strings-benchmark/index.md +35 -0
  93. package/docs/examples/strings-benchmark/main.md +76 -0
  94. package/docs/examples/tasks-benchmark/index.md +36 -0
  95. package/docs/examples/tasks-benchmark/main.md +89 -0
  96. package/docs/examples/tasks-benchmark/operations.md +58 -0
  97. package/docs/getting-started.md +3 -3
  98. package/docs/grammar.md +2 -2
  99. package/docs/gym-results.json +784 -0
  100. package/docs/implementation-map.md +6 -0
  101. package/docs/index.md +1 -1
  102. package/docs/kernel-results.json +1170 -0
  103. package/docs/language-conformance.md +6 -0
  104. package/docs/language-constructs.md +9 -1
  105. package/docs/learn/index.md +1 -1
  106. package/docs/maintaining-docs.md +1 -1
  107. package/docs/native-implementation.md +276 -0
  108. package/docs/native-interop-llvm-plan.md +342 -0
  109. package/docs/native-package-examples.md +684 -0
  110. package/docs/native-packages.md +179 -0
  111. package/docs/packages.md +2 -2
  112. package/docs/performance.md +50 -29
  113. package/docs/production-readiness.md +11 -1
  114. package/docs/public/downloads/approved-design.zip +0 -0
  115. package/docs/public/downloads/calls-benchmark.zip +0 -0
  116. package/docs/public/downloads/developer-workflow.zip +0 -0
  117. package/docs/public/downloads/errors-benchmark.zip +0 -0
  118. package/docs/public/downloads/float-benchmark.zip +0 -0
  119. package/docs/public/downloads/generic-di.zip +0 -0
  120. package/docs/public/downloads/hello.zip +0 -0
  121. package/docs/public/downloads/interceptors.zip +0 -0
  122. package/docs/public/downloads/json-benchmark.zip +0 -0
  123. package/docs/public/downloads/list-benchmark.zip +0 -0
  124. package/docs/public/downloads/map-churn-benchmark.zip +0 -0
  125. package/docs/public/downloads/native-blake3.zip +0 -0
  126. package/docs/public/downloads/native-pytorch.zip +0 -0
  127. package/docs/public/downloads/native-sqlite.zip +0 -0
  128. package/docs/public/downloads/native-zlib.zip +0 -0
  129. package/docs/public/downloads/new-syntax.zip +0 -0
  130. package/docs/public/downloads/oidc-login.zip +0 -0
  131. package/docs/public/downloads/ownership-transfer.zip +0 -0
  132. package/docs/public/downloads/packages-app.zip +0 -0
  133. package/docs/public/downloads/packages-math.zip +0 -0
  134. package/docs/public/downloads/records-benchmark.zip +0 -0
  135. package/docs/public/downloads/strings-benchmark.zip +0 -0
  136. package/docs/public/downloads/tasks-benchmark.zip +0 -0
  137. package/docs/qualification-results.md +66 -0
  138. package/docs/reference.md +24 -0
  139. package/docs/releasing.md +81 -6
  140. package/docs/research/libtorch-native-qualification.md +115 -0
  141. package/docs/research/native-interop-llvm.md +197 -0
  142. package/docs/research/qualification-methods.md +15 -0
  143. package/docs/roadmap.md +1 -0
  144. package/docs/safety-gyms.md +41 -0
  145. package/docs/tooling.md +16 -15
  146. package/docs/web-library-gaps.md +1 -1
  147. package/docs/web.md +4 -0
  148. package/examples/approved-design/.aug-spec/manifest.json +3 -3
  149. package/examples/approved-design/domain/app.aug.md +4 -4
  150. package/examples/approved-design/main.aug.md +2 -2
  151. package/examples/developer-workflow/.aug-spec/manifest.json +3 -3
  152. package/examples/developer-workflow/calculator.aug.md +5 -5
  153. package/examples/developer-workflow/logging/console.aug.md +2 -2
  154. package/examples/developer-workflow/logging/logger.aug.md +2 -2
  155. package/examples/developer-workflow/main.aug.md +2 -2
  156. package/examples/generic-di/.aug-spec/manifest.json +3 -3
  157. package/examples/generic-di/main.aug.md +2 -2
  158. package/examples/generic-di/types.aug.md +3 -3
  159. package/examples/hello/.aug-spec/manifest.json +3 -3
  160. package/examples/hello/app/greeter.aug.md +3 -3
  161. package/examples/hello/logging/console.aug.md +2 -2
  162. package/examples/hello/logging/logger.aug.md +2 -2
  163. package/examples/hello/main.aug.md +2 -2
  164. package/examples/interceptors/.aug-spec/manifest.json +3 -3
  165. package/examples/interceptors/app.aug.md +5 -5
  166. package/examples/interceptors/interceptors.aug.md +2 -2
  167. package/examples/interceptors/logging.aug.md +3 -3
  168. package/examples/interceptors/main.aug.md +2 -2
  169. package/examples/native-blake3/.aug-spec/manifest.json +16 -0
  170. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.1/native.abi.json +29 -0
  171. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug +14 -0
  172. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug.md +34 -0
  173. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug +4 -0
  174. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug.md +8 -0
  175. package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi.json +29 -0
  176. package/examples/native-blake3/AGENTS.md +5 -0
  177. package/examples/native-blake3/aug.lock.json +253 -0
  178. package/examples/native-blake3/hashing.aug +11 -0
  179. package/examples/native-blake3/hashing.aug.md +25 -0
  180. package/examples/native-blake3/main.aug +8 -0
  181. package/examples/native-blake3/main.aug.md +13 -0
  182. package/examples/native-pytorch/.aug-spec/manifest.json +18 -0
  183. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.1/native.abi.json +142 -0
  184. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.3/native.abi.json +142 -0
  185. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug +101 -0
  186. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug.md +160 -0
  187. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug +3 -0
  188. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug.md +8 -0
  189. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug +6 -0
  190. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug.md +13 -0
  191. package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi.json +142 -0
  192. package/examples/native-pytorch/AGENTS.md +5 -0
  193. package/examples/native-pytorch/aug.lock.json +309 -0
  194. package/examples/native-pytorch/main.aug +8 -0
  195. package/examples/native-pytorch/main.aug.md +13 -0
  196. package/examples/native-pytorch/tensors.aug +23 -0
  197. package/examples/native-pytorch/tensors.aug.md +35 -0
  198. package/examples/native-sqlite/.aug-spec/manifest.json +18 -0
  199. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.2/native.abi.json +100 -0
  200. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug +48 -0
  201. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug.md +91 -0
  202. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug +3 -0
  203. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug.md +8 -0
  204. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug +8 -0
  205. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug.md +22 -0
  206. package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi.json +100 -0
  207. package/examples/native-sqlite/AGENTS.md +5 -0
  208. package/examples/native-sqlite/aug.lock.json +236 -0
  209. package/examples/native-sqlite/database.aug +15 -0
  210. package/examples/native-sqlite/database.aug.md +27 -0
  211. package/examples/native-sqlite/main.aug +8 -0
  212. package/examples/native-sqlite/main.aug.md +13 -0
  213. package/examples/native-zlib/.aug-spec/manifest.json +16 -0
  214. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.1/native.abi.json +57 -0
  215. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug +29 -0
  216. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug.md +54 -0
  217. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug +4 -0
  218. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug.md +8 -0
  219. package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi.json +57 -0
  220. package/examples/native-zlib/AGENTS.md +5 -0
  221. package/examples/native-zlib/aug.lock.json +236 -0
  222. package/examples/native-zlib/compression.aug +15 -0
  223. package/examples/native-zlib/compression.aug.md +27 -0
  224. package/examples/native-zlib/main.aug +10 -0
  225. package/examples/native-zlib/main.aug.md +13 -0
  226. package/examples/new-syntax/.aug-spec/manifest.json +3 -3
  227. package/examples/new-syntax/console.aug.md +2 -2
  228. package/examples/new-syntax/greeter.aug.md +3 -3
  229. package/examples/new-syntax/logger.aug.md +2 -2
  230. package/examples/new-syntax/main.aug.md +2 -2
  231. package/examples/oidc-login/aug.lock.json +6 -6
  232. package/examples/ownership-transfer/.aug-spec/manifest.json +3 -3
  233. package/examples/ownership-transfer/main.aug.md +2 -2
  234. package/examples/ownership-transfer/resource.aug.md +2 -2
  235. package/examples/packages/math/aug-package.json +1 -1
  236. package/native/compiler-packs.json +43 -0
  237. package/package.json +3 -2
  238. package/runtime/aug_http.c +48 -21
  239. package/runtime/aug_http_ir.c +30 -0
  240. package/runtime/aug_http_ir.h +18 -0
  241. package/runtime/aug_ir.c +209 -0
  242. package/runtime/aug_ir.h +89 -0
  243. package/runtime/aug_json.c +6 -1
  244. package/runtime/aug_runtime.c +82 -16
  245. package/runtime/aug_runtime.h +16 -2
  246. package/runtime/aug_tasks.c +38 -7
  247. package/runtime/aug_values.c +12 -6
  248. package/scripts/bootstrap-native.mjs +4 -1
  249. package/src/ast.js +1 -1
  250. package/src/checker.js +110 -28
  251. package/src/cli.js +92 -14
  252. package/src/codegen.js +31 -6
  253. package/src/compiler-packs.js +66 -0
  254. package/src/config.js +2 -2
  255. package/src/editor.js +15 -6
  256. package/src/formatter.js +4 -2
  257. package/src/git-http.js +137 -0
  258. package/src/git-packages.js +9 -1
  259. package/src/help.js +10 -2
  260. package/src/ir-types.js +5 -0
  261. package/src/ir-verify.js +277 -0
  262. package/src/ir.js +962 -0
  263. package/src/llvm-debug.js +101 -0
  264. package/src/llvm-native.js +152 -0
  265. package/src/llvm-platform.js +20 -0
  266. package/src/llvm.js +781 -0
  267. package/src/native-artifacts.js +207 -0
  268. package/src/native-bindings.js +189 -0
  269. package/src/native-contracts.js +295 -0
  270. package/src/native-declarations.js +68 -0
  271. package/src/native-facts.js +63 -0
  272. package/src/package-locking.js +43 -0
  273. package/src/package-manager.js +23 -8
  274. package/src/parser.js +20 -2
  275. package/src/project.js +2 -2
  276. package/src/runtime-abi.js +23 -0
  277. package/src/runtime-adapters.js +18 -0
  278. package/src/schemas.js +24 -17
  279. package/src/semantic.js +8 -3
  280. package/src/snippets.js +1 -0
  281. package/src/spec.js +49 -8
  282. /package/examples/approved-design/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  283. /package/examples/approved-design/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  284. /package/examples/developer-workflow/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  285. /package/examples/developer-workflow/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  286. /package/examples/generic-di/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  287. /package/examples/generic-di/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  288. /package/examples/hello/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  289. /package/examples/hello/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  290. /package/examples/interceptors/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  291. /package/examples/interceptors/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  292. /package/examples/new-syntax/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  293. /package/examples/new-syntax/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
  294. /package/examples/ownership-transfer/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
  295. /package/examples/ownership-transfer/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
package/src/codegen.js CHANGED
@@ -206,7 +206,8 @@ class CGenerator {
206
206
  ` AugValue value = roots[${cls.fields.length}];`,
207
207
  ` value.as.object->field_names = ${this.name(def)}_field_names;`,
208
208
  ...(cls.kind === 'class' && initializationOf(cls).length ? [` ${this.initializerName(def)}(value, NULL, 0);`] : []),
209
- ...(cls.kind === 'class' && cls.record ? [' aug_freeze(value);'] : []),
209
+ ` if (aug_has_error) { aug_drop_partial(value); value = aug_scalar_null(); }`,
210
+ ...(cls.kind === 'class' && cls.record ? [' if (!aug_has_error) aug_freeze(value);'] : []),
210
211
  ` aug_frame_leave(&frame);`,
211
212
  ` return value;`,
212
213
  `}`,
@@ -377,18 +378,25 @@ class BodyEmitter {
377
378
  locals = new Map();
378
379
  owned = new Set();
379
380
  classFields = new Map();
381
+ ownedClassFields = new Set();
380
382
  scalarSlots = new Set();
381
383
  slots = 1;
382
384
  labelCounter = 0;
383
385
  errorTarget = 'aug_cleanup';
384
386
  returnTarget = 'aug_cleanup';
385
387
  continuation;
388
+ constructionNext = false;
389
+ constructorResults = new Set();
386
390
  constructor(generator, file, def, owner) {
387
391
  this.generator = generator;
388
392
  this.file = file;
389
393
  this.def = def;
390
394
  if (owner)
391
- fieldsOf(owner).forEach((field, index) => this.classFields.set(field.name, index));
395
+ fieldsOf(owner).forEach((field, index) => {
396
+ this.classFields.set(field.name, index);
397
+ if (field.ownership === 'own')
398
+ this.ownedClassFields.add(field.name);
399
+ });
392
400
  }
393
401
  addParameter(name, index, owned = false) {
394
402
  const slot = this.newSlot();
@@ -398,6 +406,7 @@ class BodyEmitter {
398
406
  this.owned.add(slot);
399
407
  }
400
408
  initializeInterceptor(layer, params, name, method) {
409
+ this.constructionNext = layer.constructorResultFresh === true;
401
410
  const receiver = method ? this.newSlot() : undefined;
402
411
  if (receiver !== undefined)
403
412
  this.line(`${this.slot(receiver)} = self;`);
@@ -448,6 +457,8 @@ class BodyEmitter {
448
457
  const slot = this.newSlot();
449
458
  this.line(`${this.slot(slot)} = ${next.target}(${next.receiver === undefined ? '' :
450
459
  `${this.slot(next.receiver)}, `}${array}, ${args.length});`);
460
+ if (this.constructionNext)
461
+ this.constructorResults.add(slot);
451
462
  this.line(`if (aug_has_error) goto ${this.errorTarget};`);
452
463
  return slot;
453
464
  }
@@ -478,7 +489,8 @@ class BodyEmitter {
478
489
  if (expr.kind === 'handle' && expr.call.kind === 'call') {
479
490
  const plan = this.generator.actionPlan(expr), endpoint = plan.endpoint.node.endpoint;
480
491
  const metadata = { method: endpoint.method, path: endpoint.path, parameters: plan.parameters.map(({ param, type, form }) => ({ name: param.source?.name ?? param.name, source: param.source?.kind, form, schema: this.generator.actionSchema(type) })) };
481
- const args = plan.parameters.map(parameter => parameter.form || parameter.source === undefined ? undefined : this.emitExpr(expr.call.args[parameter.source]));
492
+ const values = expr.call.args.map(argument => argument.kind === 'formInput' ? undefined : this.emitExpr(argument));
493
+ const args = plan.parameters.map(parameter => parameter.form || parameter.source === undefined ? undefined : values[parameter.source]);
482
494
  const array = this.label('action_values'), slot = this.newSlot();
483
495
  this.line(`AugValue ${array}[] = {${args.map(arg => arg === undefined ? 'aug_null()' : this.slot(arg)).join(', ') || 'aug_scalar_null()'}};`);
484
496
  this.line(`${this.slot(slot)} = aug_http_action(${cString(JSON.stringify(metadata))}, ${array}, ${args.length});`);
@@ -513,7 +525,9 @@ class BodyEmitter {
513
525
  thunk.line(`${thunk.slot(0)} = ${thunk.slot(result)};`);
514
526
  const name = this.generator.taskThunk(thunk, args.length), array = this.label('task_args'), slot = this.newSlot();
515
527
  this.line(`AugValue ${array}[] = {${args.map(arg => this.slot(arg)).join(', ') || 'aug_scalar_null()'}};`);
516
- this.line(`${this.slot(slot)} = aug_task_start(${name}, ${receiver === undefined ? 'aug_scalar_null()' : this.slot(receiver)}, ${array}, ${args.length});`);
528
+ const captures = this.label('task_owned');
529
+ this.line(`const unsigned char ${captures}[] = {${args.map((_, i) => this.generator.callPlan(call)?.ownerships?.[i] === 'own' ? '1' : '0').join(', ') || '0'}};`);
530
+ this.line(`${this.slot(slot)} = aug_task_start_owned(${name}, ${receiver === undefined ? 'aug_scalar_null()' : this.slot(receiver)}, ${array}, ${args.length}, ${captures});`);
517
531
  this.clearMovedArgs(call, (this.generator.callPlan(call)?.ownerships ?? []).map(ownership => ({ ownership: ownership ?? 'managed' })));
518
532
  this.line(`if (aug_has_error) goto ${this.errorTarget};`);
519
533
  return slot;
@@ -946,6 +960,8 @@ class BodyEmitter {
946
960
  this.line(`aug_set_field(${this.slot(object)}, ${this.memberIndex(stmt.target.object, stmt.target.name)}, ${this.slot(value)});`);
947
961
  }
948
962
  let targetOwns = stmt.ownership === 'own';
963
+ if (stmt.target.kind === 'name' && !this.locals.has(stmt.target.name))
964
+ targetOwns ||= this.ownedClassFields.has(stmt.target.name);
949
965
  if (stmt.target.kind === 'member') {
950
966
  const memberName = stmt.target.name;
951
967
  const node = this.generator.expressionType(stmt.target.object)?.def?.node;
@@ -1058,6 +1074,7 @@ class BodyEmitter {
1058
1074
  }
1059
1075
  emitTryAlways(stmt) {
1060
1076
  const outerError = this.errorTarget, outerReturn = this.returnTarget;
1077
+ const ownedBefore = new Set(this.owned);
1061
1078
  const caught = this.label('aug_final_catch'), failed = this.label('aug_final_error'), returned = this.label('aug_final_return');
1062
1079
  const cleanup = this.label('aug_always'), done = this.label('aug_always_done'), after = this.label('aug_always_after');
1063
1080
  const reason = this.label('aug_exit_reason'), depth = this.label('aug_final_depth'), cancellation = this.label('aug_final_cancel');
@@ -1070,8 +1087,11 @@ class BodyEmitter {
1070
1087
  this.emitScoped(stmt.body);
1071
1088
  this.line(`goto ${cleanup};`);
1072
1089
  this.line(`${caught}:;`);
1073
- this.line(`aug_scope_restore(${depth}); if (aug_cancelled) goto ${failed};`);
1074
1090
  this.line(`aug_lock_restore(${locks});`);
1091
+ this.line(`aug_scope_restore(${depth}); if (aug_cancelled) goto ${failed};`);
1092
+ for (const slot of this.owned)
1093
+ if (!ownedBefore.has(slot))
1094
+ this.line(`aug_drop(${this.slot(slot)}); ${this.slot(slot)} = aug_scalar_null();`);
1075
1095
  this.errorTarget = failed;
1076
1096
  for (const clause of stmt.catches) {
1077
1097
  this.line(`if (aug_error_is(${cString(clause.type.name)})) {`);
@@ -1087,8 +1107,12 @@ class BodyEmitter {
1087
1107
  this.line(`${returned}: ${reason} = 1; goto ${cleanup};`);
1088
1108
  this.line(`${failed}: ${reason} = 2;`);
1089
1109
  this.line(`${cleanup}:;`);
1090
- this.line(`aug_scope_restore(${depth}); ${this.slot(pending)} = aug_has_error ? aug_take_error() : aug_scalar_null();`);
1091
1110
  this.line(`aug_lock_restore(${locks});`);
1111
+ this.line(`aug_scope_restore(${depth});`);
1112
+ for (const slot of this.owned)
1113
+ if (!ownedBefore.has(slot))
1114
+ this.line(`aug_drop(${this.slot(slot)}); ${this.slot(slot)} = aug_scalar_null();`);
1115
+ this.line(`${this.slot(pending)} = aug_has_error ? aug_take_error() : aug_scalar_null();`);
1092
1116
  this.line(`${cancellation} = aug_cancelled; aug_cancelled = false;`);
1093
1117
  this.errorTarget = done;
1094
1118
  this.returnTarget = done;
@@ -1149,6 +1173,7 @@ class BodyEmitter {
1149
1173
  ` aug_lock_restore(aug_lock_base);`,
1150
1174
  ` aug_scope_join_to(aug_scope_base);`,
1151
1175
  ownedCleanup,
1176
+ ...[...this.constructorResults].map(slot => ` aug_constructor_result_cleanup(${this.slot(slot)}, ${this.slot(0)});`),
1152
1177
  ` aug_scope_restore(aug_scope_base);`,
1153
1178
  ` AugValue result = ${this.slot(0)};`,
1154
1179
  ` aug_frame_leave(&frame);`,
@@ -0,0 +1,66 @@
1
+ import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { compilerVersion } from "./package-manager.js";
6
+ import { ensureVerifiedArchive } from "./native-artifacts.js";
7
+ import { nativeHostTarget } from "./native-contracts.js";
8
+ import { withPackageLockAsync } from "./package-locking.js";
9
+ import { readRuntimePack } from "./llvm-native.js";
10
+ import { llvmPlatform } from "./llvm-platform.js";
11
+ /** The CLI owns installation. Packages cannot choose or execute a compiler driver. */
12
+ export async function prepareLLVMCompiler(offline = false, project) {
13
+ const compilerRoot = resolve(fileURLToPath(new URL('..', import.meta.url)));
14
+ const platform = llvmPlatform();
15
+ if (process.env.AUG_LLVM_HOME) {
16
+ const tools = resolve(process.env.AUG_LLVM_HOME), runtime = resolve(process.env.AUG_RUNTIME_PACK ?? join(compilerRoot, '.aug-native/llvm/runtime'));
17
+ const version = spawnSync(join(tools, 'bin/llc'), ['--version'], { encoding: 'utf8' });
18
+ if (version.status !== 0 || !version.stdout.includes('LLVM version 23.1.2'))
19
+ throw new Error('LLVM_TOOLS: Contributor override requires LLVM 23.1.2');
20
+ readRuntimePack(runtime);
21
+ if (project?.frozen)
22
+ throw new Error('LLVM_LOCK: A frozen build requires the pinned compiler pack. Remove contributor toolchain overrides.');
23
+ return { tools, runtime, developmentOverride: true };
24
+ }
25
+ const file = join(compilerRoot, 'native/compiler-packs.json');
26
+ if (!existsSync(file))
27
+ throw new Error('LLVM_TOOLS: This compiler has no published LLVM tool manifest. Install the matching LLVM preview release.');
28
+ const manifest = JSON.parse(readFileSync(file, 'utf8'));
29
+ if (manifest.format !== 1 || manifest.compiler !== compilerVersion() || manifest.llvm !== '23.1.2' || !Array.isArray(manifest.packs))
30
+ throw new Error('LLVM_TOOLS: Invalid compiler-owned LLVM manifest');
31
+ const host = process.platform + '-' + process.arch, target = nativeHostTarget(), pack = manifest.packs.find(p => p.host === host && p.target === target.triple);
32
+ if (!pack)
33
+ throw new Error('NATIVE_TARGET: No compiler pack is published for ' + platform.host + '. Available compiler packs: ' + manifest.packs.map(p => p.host).join(', '));
34
+ if (pack.minimumOS !== platform.minimumOS || pack.minimumLibc !== platform.minimumLibc)
35
+ throw new Error('LLVM_TOOLS: Compiler manifest has a different platform baseline');
36
+ const prepare = async () => {
37
+ const lockFile = project ? join(project.root, 'aug.lock.json') : undefined, initial = lockFile && existsSync(lockFile) ? readFileSync(lockFile, 'utf8') : undefined;
38
+ const lock = initial ? JSON.parse(initial) : { format: 1, compiler: compilerVersion(), specifications: {}, roots: {}, packages: [], npm: {} };
39
+ if (lock.compiler !== compilerVersion())
40
+ throw new Error('LLVM_LOCK: Project lock belongs to another compiler. Run aug install.');
41
+ const previous = lock.native?.compilers?.[host];
42
+ if (project?.frozen && (!previous || previous.artifactSha256 !== pack.archive.sha256))
43
+ throw new Error('LLVM_LOCK: Frozen build has no matching compiler artifact for ' + host + '. Run aug build --backend llvm online once on this host.');
44
+ const directory = await ensureVerifiedArchive(pack.archive, { offline, executables: platform.tools.map(tool => 'bin/' + tool) });
45
+ const identity = JSON.parse(readFileSync(join(directory, 'compiler-pack.json'), 'utf8'));
46
+ if (identity.format !== 1 || identity.compiler !== manifest.compiler || identity.llvm !== manifest.llvm || identity.host !== host || identity.target !== target.triple)
47
+ throw new Error('LLVM_TOOLS: Verified archive has a different compiler/host/target identity');
48
+ const runtime = readRuntimePack(join(directory, 'runtime'));
49
+ if (identity.runtime !== runtime.sourceSha256)
50
+ throw new Error('LLVM_TOOLS: Compiler pack runtime identity differs from its runtime manifest');
51
+ const selection = { version: manifest.compiler, llvm: manifest.llvm, host, target: target.triple, artifactSha256: pack.archive.sha256, runtimeSha256: runtime.sourceSha256 };
52
+ if (project?.frozen && JSON.stringify(previous) !== JSON.stringify(selection))
53
+ throw new Error('LLVM_LOCK: Frozen compiler/runtime identity changed for ' + host);
54
+ if (lockFile && !project?.frozen) {
55
+ lock.native ??= { format: 1, targets: {} };
56
+ lock.native.compilers ??= {};
57
+ lock.native.compilers[host] = selection;
58
+ if ((existsSync(lockFile) ? readFileSync(lockFile, 'utf8') : undefined) !== initial)
59
+ throw new Error('LLVM_LOCK: Source lock changed during compiler installation; retry');
60
+ writeFileSync(lockFile + '.llvm.tmp', JSON.stringify(lock, null, 2) + '\n');
61
+ renameSync(lockFile + '.llvm.tmp', lockFile);
62
+ }
63
+ return { tools: directory, runtime: join(directory, 'runtime'), archiveSha256: pack.archive.sha256, developmentOverride: false };
64
+ };
65
+ return project ? withPackageLockAsync(join(project.root, '.aug-install.lock'), prepare) : prepare();
66
+ }
package/src/config.js CHANGED
@@ -101,7 +101,7 @@ export function loadConfig(root) {
101
101
  }
102
102
  continue;
103
103
  }
104
- if (!entry || !(entry[1] in config || entry[1] === 'output')) {
104
+ if (!entry || !(entry[1] in config || ['output', 'backend'].includes(entry[1]))) {
105
105
  report(index + 1, `Unsupported configuration line ${JSON.stringify(raw)}`);
106
106
  continue;
107
107
  }
@@ -131,7 +131,7 @@ export function loadConfig(root) {
131
131
  config[key] = Number(value);
132
132
  }
133
133
  else {
134
- const choices = { optimization: ['debug', 'release'], assignment: ['equals', 'to'],
134
+ const choices = { backend: ['c', 'llvm'], optimization: ['debug', 'release'], assignment: ['equals', 'to'],
135
135
  block_style: ['braces', 'indent'], indentation: ['spaces', 'tabs'] };
136
136
  if (!value || choices[key] && !choices[key].includes(value))
137
137
  report(index + 1, `${key} needs ${choices[key]?.join(' or ') ?? 'a value'}`);
package/src/editor.js CHANGED
@@ -15,6 +15,8 @@ import { builtinTypes } from "./builtins.js";
15
15
  import { libraryChild, libraryRelative } from "./libraries.js";
16
16
  import { importSource, isGitSource, sourceAlias } from "./git-packages.js";
17
17
  import { snippetBody, snippetCatalog } from "./snippets.js";
18
+ import { nativeFact, nativeDependencies, nativeDescription } from "./native-facts.js";
19
+ import { pathToFileURL } from 'node:url';
18
20
  const builtins = [
19
21
  ...builtinFunctions.map(operation => {
20
22
  const parameters = operation.parameters.map(param => `${param.label}=${param.type}`);
@@ -132,9 +134,10 @@ function methodItem(checked, method, kind, owner) {
132
134
  const contract = checked.effectContracts.get(method);
133
135
  const effects = contract ? `${contract.inferred ? 'Inferred capabilities; effective' : 'Effective'} contract: changes ${contract.changes.join(', ') || 'nothing'}; capabilities ` +
134
136
  `${[...contract.uses.values()].map(effect => `${effect.source}.${effect.operation}`).join(', ') || 'none'}.` : '';
137
+ const native = nativeDependencies(checked, method).map(fact => nativeDescription(fact, '[`native.abi.json`](' + pathToFileURL(checked.native.providerDescriptors.get(fact.provider)).href + ')')).join('\n\n');
135
138
  return { label: method.name, kind, detail: label, signature: signature(method, true, errors, checked),
136
139
  documentation: [doc?.markdown, isPrivateName(method.name) ? 'Private to its declaring type.' : '',
137
- injectionHelp, effects, interceptorDescription(checked, method), 'Call arguments require labels; their order does not matter.']
140
+ injectionHelp, effects, native, interceptorDescription(checked, method), 'Call arguments require labels; their order does not matter.']
138
141
  .filter(Boolean).join('\n\n'),
139
142
  parameters: method.params.filter(param => !param.injected)
140
143
  .map(param => `${param.label ?? param.name}=${typeName(param.type)}`),
@@ -143,6 +146,11 @@ function methodItem(checked, method, kind, owner) {
143
146
  }
144
147
  function definitionItem(checked, def) {
145
148
  const node = def.node;
149
+ if (node.kind === 'resource') {
150
+ const native = nativeFact(checked, node);
151
+ return { label: def.name, kind: 'type', detail: 'extern C resource ' + def.name,
152
+ documentation: native ? nativeDescription(native, '[`native.abi.json`](' + pathToFileURL(checked.native.providerDescriptors.get(native.provider)).href + ')') : 'Opaque native resource. Its package must declare a release identity.' };
153
+ }
146
154
  if (node.kind === 'function')
147
155
  return methodItem(checked, node, 'function');
148
156
  if (node.kind === 'interface')
@@ -175,10 +183,11 @@ function definitionItem(checked, def) {
175
183
  const explicit = node.fields.filter(field => !field.injected);
176
184
  const callSignature = `${def.name}${node.typeParams.length ? `<${node.typeParams.join(', ')}>` : ''}` +
177
185
  `(${explicit.map(field => `${field.label ?? field.name}=${typeName(field.type)}`).join(', ')})`;
178
- const errors = [...new Set((checked.interceptorPlans.get(node) ?? []).flatMap(layer => layer.errors.map(tyName)))];
186
+ const errors = [...new Set([...(checked.constructorContracts.get(node)?.errors.map(tyName) ?? node.validationErrors?.map(typeName) ?? []),
187
+ ...(checked.interceptorPlans.get(node) ?? []).flatMap(layer => layer.errors.map(tyName))])];
179
188
  return { label: def.name, kind: 'class', detail: `${node.record ? 'record ' : ''}${label}` +
180
- (node.implements.length ? ` implements ${node.implements.map(typeName).join(' and ')}` : '') +
181
- (errors.length ? ` unless ${errors.join(', ')}` : ''),
189
+ (errors.length ? ` unless ${errors.join(' and ')}` : '') +
190
+ (node.implements.length ? ` implements ${node.implements.map(typeName).join(', ')}` : ''),
182
191
  signature: callSignature + (errors.length ? ` unless ${errors.join(', ')}` : ''), parameters: explicit.map(field => `${field.label ?? field.name}=${typeName(field.type)}`),
183
192
  documentation: [doc?.markdown,
184
193
  node.fields.some(field => field.injected) ? `Injected from bindings: ${node.fields.filter(field => field.injected).map(parameterText).join(', ')}.` : '',
@@ -189,7 +198,7 @@ function definitionItem(checked, def) {
189
198
  function typeFromRef(checked, file, ref) {
190
199
  const def = checked.project.scopes.get(file)?.get(ref.name);
191
200
  return { id: def?.id ?? `builtin:${ref.name}`, name: ref.name,
192
- kind: def?.node.kind === 'class' || def?.node.kind === 'interface' || def?.node.kind === 'interceptor' ? def.node.kind : 'builtin',
201
+ kind: def?.node.kind === 'class' || def?.node.kind === 'interface' || def?.node.kind === 'interceptor' || def?.node.kind === 'resource' ? def.node.kind : 'builtin',
193
202
  args: ref.args.map(arg => typeFromRef(checked, file, arg)), nullable: ref.nullable, def };
194
203
  }
195
204
  function collectLocals(checked, file, offset) {
@@ -826,7 +835,7 @@ export function semanticTokens(checked, fileName) {
826
835
  else {
827
836
  const def = scope?.get(token.value);
828
837
  if (def)
829
- type = def.node.kind === 'interceptor' ? 'decorator' : def.node.kind === 'composition' ? 'function' : def.node.kind;
838
+ type = def.node.kind === 'resource' ? 'type' : def.node.kind === 'interceptor' ? 'decorator' : def.node.kind === 'composition' ? 'function' : def.node.kind;
830
839
  }
831
840
  if (type)
832
841
  result.push({ line: token.span.line - 1, start: token.span.column - 1,
package/src/formatter.js CHANGED
@@ -254,20 +254,22 @@ class Printer {
254
254
  (item.lifetime ? ' ' + item.lifetime : '') + (item.sharedMutation ? ' mutable' : ''));
255
255
  else if (item.kind === 'composition')
256
256
  this.block('composition ' + item.name, () => item.bindings.forEach(binding => this.item(binding)), item.span);
257
+ else if (item.kind === 'resource')
258
+ this.line('extern C resource ' + item.name);
257
259
  else if (item.kind === 'function')
258
260
  this.method(item);
259
261
  else if (item.kind === 'class') {
260
262
  this.annotations(item.annotations);
261
263
  const header = `${item.record ? 'record ' : ''}${item.name}${this.generics(item)}(${item.fields.map(field => this.param(field, true)).join(', ')})`;
264
+ const errors = item.validationErrors?.length ? ` unless ${item.validationErrors.map(typeName).join(' and ')}` : '';
262
265
  if (item.record) {
263
- const errors = item.validationErrors?.length ? ` unless ${item.validationErrors.map(typeName).join(' and ')}` : '';
264
266
  if (item.constructorBody)
265
267
  this.block(header + errors, () => this.initializer(item), item.span);
266
268
  else
267
269
  this.line(header + errors);
268
270
  }
269
271
  else {
270
- this.block(header + ' implements ' + item.implements.map(typeName).join(', '), () => {
272
+ this.block(header + errors + ' implements ' + item.implements.map(typeName).join(', '), () => {
271
273
  for (const field of item.stateFields ?? []) {
272
274
  this.before(field.span.start);
273
275
  this.line(`${field.mutable ? 'mutable ' : ''}${typeName(field.type)} ${field.name} = ${this.expression(field.initializer)}`);
@@ -0,0 +1,137 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { gitReference, sourceAlias } from "./git-packages.js";
7
+ import { withPackageLockAsync } from "./package-locking.js";
8
+ const selected = (name) => !name.split('/').some(part => part.startsWith('.')) && (name.endsWith('.aug') || ['aug-package.json', 'package.json', 'main.yaml', 'README.md', 'LICENSE', 'native.abi.json', 'THIRD_PARTY_NOTICES.md'].includes(name));
9
+ async function bytes(url, maximum) {
10
+ const address = new URL(url);
11
+ if (address.protocol !== 'https:' || !['api.github.com', 'raw.githubusercontent.com'].includes(address.hostname) || address.username || address.password)
12
+ throw new Error('Invalid source transport URL');
13
+ const headers = { Accept: 'application/vnd.github+json', 'User-Agent': 'August-source-packages' };
14
+ // Only the API receives an explicitly supplied token. Raw downloads and
15
+ // redirects cannot carry it, and it never enters package metadata or logs.
16
+ if (address.hostname === 'api.github.com' && process.env.AUG_GITHUB_TOKEN)
17
+ headers.Authorization = 'Bearer ' + process.env.AUG_GITHUB_TOKEN;
18
+ const response = await fetch(address, { redirect: 'error', signal: AbortSignal.timeout(60000), headers });
19
+ if (!response.ok || !response.body)
20
+ throw new Error(`Cannot read public GitHub source (${response.status}). Check the repository/revision. For API rate limits, retry later or supply AUG_GITHUB_TOKEN for authenticated public reads.`);
21
+ if (Number(response.headers.get('content-length') ?? 0) > maximum)
22
+ throw new Error('GitHub source response exceeds its size limit');
23
+ const chunks = [];
24
+ let length = 0;
25
+ for await (const chunk of response.body) {
26
+ length += chunk.length;
27
+ if (length > maximum)
28
+ throw new Error('GitHub source response exceeds its size limit');
29
+ chunks.push(Buffer.from(chunk));
30
+ }
31
+ return Buffer.concat(chunks);
32
+ }
33
+ /** Public GitHub snapshots use HTTPS objects, so consumers do not need Git or an SDK. */
34
+ export async function materializeGitHub(request, destination, offline, locked) {
35
+ const reference = gitReference(request), url = new URL(reference.repository), parts = url.pathname.split('/').filter(Boolean), owner = parts[0], repo = parts[1]?.replace(/\.git$/, '');
36
+ if (url.hostname !== 'github.com' || parts.length !== 2 || !owner || !repo)
37
+ throw new Error('GitHub transport requires an owner/repository URL');
38
+ if (locked && (locked.repository !== reference.repository || locked.folder !== reference.folder || locked.revision !== reference.revision || !/^[0-9a-f]{40}$/.test(locked.commit)))
39
+ throw new Error('Invalid locked GitHub source identity');
40
+ const cache = resolve(process.env.AUG_PACKAGE_CACHE ?? join(homedir(), '.cache/augscript/packages'));
41
+ const base = join(cache, 'https-' + sourceAlias(reference.repository) + '-' + sourceAlias(reference.folder));
42
+ mkdirSync(base, { recursive: true });
43
+ return withPackageLockAsync(base + '.lock', async () => {
44
+ let commit = locked?.commit;
45
+ const revisionCache = join(base, 'revision-' + sourceAlias(reference.revision) + '.json');
46
+ if (!commit && offline && existsSync(revisionCache))
47
+ commit = JSON.parse(readFileSync(revisionCache, 'utf8')).commit;
48
+ if (!commit) {
49
+ if (offline)
50
+ throw new Error('GitHub revision is not cached. Run aug install online once: ' + request);
51
+ const value = JSON.parse((await bytes(`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits/${encodeURIComponent(reference.revision)}`, 4 * 1024 * 1024)).toString());
52
+ commit = value.sha;
53
+ if (!/^[0-9a-f]{40}$/.test(commit))
54
+ throw new Error('GitHub did not resolve an exact commit');
55
+ }
56
+ if (!/^[0-9a-f]{40}$/.test(commit))
57
+ throw new Error('Invalid cached GitHub revision');
58
+ const snapshot = join(base, commit), metadata = join(base, commit + '.json');
59
+ if (!existsSync(snapshot) || !existsSync(metadata)) {
60
+ if (offline)
61
+ throw new Error('Locked GitHub source is not cached: ' + commit);
62
+ // An interrupted installation may leave either half of the cache entry.
63
+ // The exclusive writer discards that incomplete entry before retrying.
64
+ rmSync(snapshot, { recursive: true, force: true });
65
+ rmSync(metadata, { force: true });
66
+ const tree = JSON.parse((await bytes(`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/git/trees/${commit}?recursive=1`, 16 * 1024 * 1024)).toString());
67
+ if (tree.truncated || !Array.isArray(tree.tree))
68
+ throw new Error('GitHub source tree coverage is incomplete; installation stopped');
69
+ const prefix = reference.folder ? reference.folder + '/' : '';
70
+ const entries = tree.tree.filter((e) => e.type === 'blob' && typeof e.path === 'string' && e.path.startsWith(prefix) && selected(e.path.slice(prefix.length)));
71
+ if (!entries.length || entries.length > 10000)
72
+ throw new Error('GitHub package has no source files or exceeds its file limit');
73
+ const stage = mkdtempSync(join(base, '.snapshot-'));
74
+ let total = 0;
75
+ const digests = {};
76
+ try {
77
+ // Bounded concurrency avoids one network round trip per source file.
78
+ for (let i = 0; i < entries.length; i += 8) {
79
+ const batch = await Promise.allSettled(entries.slice(i, i + 8).map(async (entry) => {
80
+ const name = entry.path.slice(prefix.length);
81
+ if (!['100644', '100755'].includes(entry.mode) || name.includes('\\') || name.split('/').some((p) => !p || p === '.' || p === '..' || p.startsWith('.')) || !/^[0-9a-f]{40}$/.test(entry.sha))
82
+ throw new Error('GitHub package source must be regular files inside its folder: ' + name);
83
+ const content = await bytes(`https://raw.githubusercontent.com/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/${commit}/${entry.path.split('/').map(encodeURIComponent).join('/')}`, 32 * 1024 * 1024);
84
+ total += content.length;
85
+ if (total > 32 * 1024 * 1024)
86
+ throw new Error('GitHub source package exceeds 32 MiB');
87
+ const actual = createHash('sha1').update('blob ' + content.length + '\0').update(content).digest('hex');
88
+ if (actual !== entry.sha)
89
+ throw new Error('GitHub source blob identity differs from the resolved tree');
90
+ digests[name] = createHash('sha256').update(content).digest('hex');
91
+ mkdirSync(dirname(join(stage, name)), { recursive: true });
92
+ writeFileSync(join(stage, name), content);
93
+ }));
94
+ const rejected = batch.find(r => r.status === 'rejected');
95
+ if (rejected?.status === 'rejected')
96
+ throw rejected.reason;
97
+ }
98
+ renameSync(stage, snapshot);
99
+ writeFileSync(metadata, JSON.stringify({ format: 1, commit, files: digests }));
100
+ }
101
+ finally {
102
+ rmSync(stage, { recursive: true, force: true });
103
+ }
104
+ }
105
+ const facts = JSON.parse(readFileSync(metadata, 'utf8'));
106
+ if (facts.format !== 1 || facts.commit !== commit || !facts.files)
107
+ throw new Error('Invalid cached GitHub source metadata');
108
+ const list = (folder, prefix = '') => readdirSync(folder, { withFileTypes: true }).flatMap(entry => {
109
+ if (entry.isSymbolicLink())
110
+ throw new Error('Cached GitHub source cannot contain symbolic links');
111
+ const path = prefix + entry.name;
112
+ return entry.isDirectory() ? list(join(folder, entry.name), path + '/') : entry.isFile() ? [path] : (() => { throw new Error('Cached GitHub source requires regular files'); })();
113
+ });
114
+ if (lstatSync(snapshot).isSymbolicLink() || JSON.stringify(list(snapshot).sort()) !== JSON.stringify(Object.keys(facts.files).sort()))
115
+ throw new Error('Cached GitHub source file set differs from the resolved snapshot');
116
+ for (const [name, digest] of Object.entries(facts.files)) {
117
+ if (name.includes('\\') || name.split('/').some(p => !p || p === '.' || p === '..' || p.startsWith('.')))
118
+ throw new Error('Cached source path escapes its snapshot');
119
+ if (createHash('sha256').update(readFileSync(join(snapshot, name))).digest('hex') !== digest)
120
+ throw new Error('Cached GitHub source changed: ' + name);
121
+ }
122
+ cpSync(snapshot, destination, { recursive: true });
123
+ writeFileSync(revisionCache, JSON.stringify({ commit }));
124
+ return { ...reference, commit: commit };
125
+ });
126
+ }
127
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url) && process.argv[2] === '--materialize') {
128
+ try {
129
+ const input = JSON.parse(process.argv[3]);
130
+ const result = await materializeGitHub(input.request, input.destination, input.offline, input.locked);
131
+ process.stdout.write(JSON.stringify(result));
132
+ }
133
+ catch (error) {
134
+ process.stderr.write((error instanceof Error ? error.message : String(error)) + '\n');
135
+ process.exitCode = 1;
136
+ }
137
+ }
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { dirname, join, resolve } from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
+ import { fileURLToPath } from 'node:url';
6
7
  import { withPackageLock } from "./package-locking.js";
7
8
  export const isGitSource = (value) => /^(?:https:\/\/|git\+(?:https|file):\/\/)/.test(value);
8
9
  export const sourceAlias = (value) => 'url_' + createHash('sha256').update(value).digest('hex').slice(0, 20);
@@ -65,6 +66,13 @@ export function materializeGit(request, destination, offline, locked) {
65
66
  if (locked && (locked.repository !== reference.repository || locked.folder !== reference.folder || locked.revision !== reference.revision ||
66
67
  !/^[a-f0-9]{40,64}$/.test(locked.commit)))
67
68
  throw new Error('Git package lock has an invalid repository, folder, or commit.');
69
+ if (new URL(reference.repository).hostname === 'github.com' && !process.env.AUG_GIT) {
70
+ const transport = new URL(import.meta.url.endsWith('.ts') ? './git-http.ts' : './git-http.js', import.meta.url);
71
+ const result = spawnSync(process.execPath, [fileURLToPath(transport), '--materialize', JSON.stringify({ request, destination, offline, locked })], { encoding: 'utf8', timeout: 180000, maxBuffer: 4 * 1024 * 1024 });
72
+ if (result.status !== 0)
73
+ throw new Error(result.stderr.trim() || result.error?.message || 'GitHub source installation failed');
74
+ return JSON.parse(result.stdout);
75
+ }
68
76
  const cache = resolve(process.env.AUG_PACKAGE_CACHE ?? join(homedir(), '.cache', 'augscript', 'packages'));
69
77
  const repository = join(cache, sourceAlias(reference.repository));
70
78
  mkdirSync(cache, { recursive: true });
@@ -91,7 +99,7 @@ export function materializeGit(request, destination, offline, locked) {
91
99
  if (!match || !match[3].startsWith(prefix))
92
100
  continue;
93
101
  const file = match[3].slice(prefix.length);
94
- if (!file.endsWith('.aug') && !['aug-package.json', 'package.json', 'main.yaml', 'README.md', 'LICENSE'].includes(file))
102
+ if (!file.endsWith('.aug') && !['aug-package.json', 'package.json', 'main.yaml', 'README.md', 'LICENSE', 'native.abi.json', 'THIRD_PARTY_NOTICES.md'].includes(file))
95
103
  continue;
96
104
  if (!['100644', '100755'].includes(match[1]) || file.includes('\\') || file.split('/').some(part => !part || part === '..' || part.startsWith('.')))
97
105
  throw new Error(`Git package source must be regular files inside its folder: ${file}`);
package/src/help.js CHANGED
@@ -4,6 +4,7 @@ const type = (detail, documentation) => ({ detail, documentation, category: 'typ
4
4
  const fn = (detail, documentation) => ({ detail, documentation, category: 'function' });
5
5
  const operator = (detail, documentation) => ({ detail, documentation, category: 'operator' });
6
6
  export const languageHelp = {
7
+ resource: keyword('extern C resource Tensor', 'Declare an opaque native object with a descriptor-checked release operation. Store acquired objects in own bindings; their scope releases them exactly once. Resource declarations belong to native packages, outside main.aug.'),
7
8
  RequireLogin: { category: 'tag', detail: '[RequireLogin(authentication=auth)]', documentation: 'Verify credentials before typed body decoding. Map auth to an explicit resolve Authentication parameter and infer its authenticate operation. null produces 401; the adapter validates the credential. HTTP policies precede custom parameter interceptors.' },
8
9
  RequirePermission: { category: 'tag', detail: '[RequirePermission(authentication=auth, authorization=permissions, permission="users.read")]', documentation: 'Authenticate the request and authorize one literal permission before decoding. Both dependencies are explicit resolve parameters; declare their authenticate and authorize effects. Missing credentials produce 401 and a denied permission produces 403.' },
9
10
  LogRequest: { category: 'tag', detail: '[LogRequest(logger=logger)]', documentation: 'Map a resolve RequestLogger parameter and infer its complete operation. Observe the final status and monotonic duration after output finishes, or status 499 on disconnect. Layers complete in reverse written order.' },
@@ -46,7 +47,7 @@ export const languageHelp = {
46
47
  HttpRequest: type('HttpRequest', 'A request supplied through from request. Its method, path, headers and bounded body are explicit. form<T>() allows protocol-specific form errors.'),
47
48
  HttpResponse: type('HttpResponse<T>', 'A typed HTTP body with explicit status and headers. HttpResponse(body=value, status=201, headers=headers) constructs a response. Status literals range from 200 to 599; a dynamic status requires handling or declaring HttpError.'),
48
49
  record: keyword('record Point(int x, int y)', 'Declare deeply immutable data with labeled construction and structural equality/hashing. Records contain primitives, tuples and other records. An initialize block validates inputs; validation infers rejected inputs; an explicit unless ErrorType limits permitted failures.'),
49
- initialize: keyword('initialize: ...', 'Run constructor work once after header inputs and local fields are initialized, before returning the class or record. Put this block inside the declaration, before class methods. Construction stays pure. Records can validate inputs and raise checked errors, but cannot replace immutable fields.'),
50
+ initialize: keyword('initialize: ...', 'Run constructor work once after header inputs and local fields are initialized, before returning the class or record. Put this block inside the declaration, before class methods. Construction stays pure. Classes declare checked constructor failures with unless before implements; failed construction releases transferred owned fields. Records can infer validation failures but cannot replace immutable fields.'),
50
51
  fixture: keyword('fixture example() returns Data: ...', 'Declare reusable test data through an ordinary checked function. Other files must import the fixture explicitly. Its dependencies and capabilities follow the same header contract rules as other functions.'),
51
52
  for: keyword('for item in items: ...', 'Traverse a List, Set, homogeneous Tuple, or Map. Map entries are tuples, so for (key, value) in map unpacks them. Iteration snapshots the collection in insertion order and gives elements read-only access.'),
52
53
  match: keyword('match value: when ...', 'Choose a checked case. Cover true and false for bool, null and some for nullable values, or add else. Concrete class cases narrow the named value. Duplicate and unreachable cases are rejected.'),
@@ -169,6 +170,13 @@ for (const operation of builtinFunctions)
169
170
  languageHelp[operation.name] = fn(`${operation.name}(${operation.parameters.map(param => `${param.label}=${param.type}`).join(', ')}) returns ${operation.returns}` +
170
171
  (operation.errors?.length ? ` unless ${operation.errors.join(' and ')}` : ''), operation.documentation);
171
172
  export const diagnosticHelp = {
173
+ NATIVE_HEADER: 'The native maintainer header does not match its reviewed ownership descriptor. Check fixed-width types, pointer constness, outputs, release signatures and the error record layout. aug bind header uses an explicitly selected Clang only; package consumers do not need Clang. Header checks do not prove allocator pairing, retention or thread promises.',
174
+ NATIVE_ABI: 'Keep the August declarations and native.abi.json in the same package. Parameter labels, types, resource ownership, checked errors and effects must match. Different packages cannot supply the same physical native symbol.',
175
+ NATIVE_INTEGRITY: 'The source or native archive differs from its pinned digest. Reinstall the exact package version or ask its maintainer to publish a new version. Installation never runs package build scripts.',
176
+ NATIVE_TARGET: 'This native package has no compatible prebuilt artifact for your OS, architecture, libc version or C++ runtime. LLVM builds target macOS 14+ ARM64 and Debian/Ubuntu GNU/Linux x86-64 or ARM64 with glibc 2.36+. Linux artifacts must declare their glibc floor. Musl and cross compilation are unsupported. Use one of the listed targets; missing artifacts do not trigger a source build.',
177
+ NATIVE_LOCK: 'Run aug install to record the verified source and native target. Commit aug.lock.json. Frozen builds reject changed selections; offline builds require an already verified cache.',
178
+ BACKEND_UNSUPPORTED: 'LLVM cannot compile this construct or legacy link setting. Use package-declared native bindings and link inputs. An explicit --backend c can compile migration fixtures without native ABI packages and requires a C toolchain. No automatic backend fallback occurs.',
179
+ IR_INVALID: 'The compiler produced execution IR that failed structural or ABI verification before LLVM emission. Report this source location and the compiler version. Source typing and ownership checks still run before lowering.',
172
180
  SYNTAX: 'Use word boolean operators, initialize blocks, optional Type, implement with, and resolve Key to name. The editor migration fix or aug migrate --write upgrades rejected legacy spellings while preserving grouping.',
173
181
  NATIVE: 'The C compiler reported an error at this August location. Check the external C declaration and main.yaml libraries/library_paths. Native commands prepare required pinned libraries automatically. Missing system tools include installation help. If valid August code fails without an external C boundary, report the compiler output and generated .aug-build/program.c.',
174
182
  CONFIG: 'main.yaml uses the documented scalar settings and list settings. Duplicate keys, unsupported values, and unknown lint rules are errors during check.',
@@ -191,7 +199,7 @@ export const diagnosticHelp = {
191
199
  TEST: 'Place the suite beside its declaration. Class tests initialize their named subject; test endpoint NAME client supplies an HTTP pipeline client. Put when bindings and setup before it cases and assert a bool in every case. Run aug test --group NAME to select a group.',
192
200
  HTTP: 'Declare endpoint inputs with from path/query/header/body/cookie/form/request and dependencies with resolve. Select endpoints in main with serve. HTTP policies use literal options and explicit capability mappings; put them before custom parameter interceptors.',
193
201
  JSON: 'Expose concrete immutable data records and collections. Decode<T>() requires a concrete JSON data type; freeze existing mutable collection aliases before storing them in a record.',
194
- CONCURRENCY: 'Use scope for child-task lifetimes, start a labeled call, and wait for its result before mutating or moving any object the child captured. This includes writes inside an existing borrow block. A start inside a loop can create several children; use a scope inside the loop to join each iteration. Use Shared<T> and a short lock block for shared mutation; release the lock before I/O, waits, or starting tasks.',
202
+ CONCURRENCY: 'Use scope for child-task lifetimes, start a labeled call, and wait for its result before mutating or moving any object the child captured. This includes writes inside an existing borrow block. A task may consume owned inputs, but cannot return an owned value; release resources inside it and return immutable data. A start inside a loop can create several children; use a scope inside the loop to join each iteration. Use Shared<T> and a short lock block for shared mutation; release the lock before I/O, waits, or starting tasks.',
195
203
  INTERCEPTOR: 'Declare an interceptor with one around body. Map its selected inputs to target labels, preserve the target result and ownership, and supply constructor dependencies through resolve.',
196
204
  NEXT: 'Use next only inside around, with optional labeled overrides. Each execution path may call it at most once; loops and catch paths can repeat a call.',
197
205
  LEX: 'Check quotes, comment terminators, and supported characters.',
@@ -0,0 +1,5 @@
1
+ /** These cells can never retain a managed pointer after checked execution. */
2
+ export function isIRScalar(type) {
3
+ return !type.nullable && !type.optional && !type.args.length &&
4
+ ['int', 'c_int', 'float', 'bool'].includes(type.name) && type.id === 'builtin:' + type.name;
5
+ }