create-nola-lang 0.1.13 → 0.1.15

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 (54) hide show
  1. package/README.md +8 -3
  2. package/dist/add.d.ts +3 -0
  3. package/dist/add.js +2 -1
  4. package/dist/checkout.js +1 -0
  5. package/dist/{chunk-LUSVIOAN.js → chunk-UTVGG44K.js} +124 -95
  6. package/dist/examples.d.ts +4 -2
  7. package/dist/examples.js +4 -2
  8. package/dist/flow.d.ts +20 -3
  9. package/dist/flow.js +49 -17
  10. package/dist/github.d.ts +1 -1
  11. package/dist/github.js +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/launch.d.ts +2 -2
  14. package/dist/launch.js +1 -1
  15. package/dist/main.js +1 -1
  16. package/dist/node-version.d.ts +3 -2
  17. package/dist/node-version.js +4 -3
  18. package/dist/package-manager.d.ts +5 -0
  19. package/dist/package-manager.js +7 -0
  20. package/dist/providers.d.ts +1 -1
  21. package/dist/providers.js +1 -1
  22. package/dist/registry.d.ts +21 -12
  23. package/dist/registry.js +27 -5
  24. package/dist/scaffold.d.ts +36 -16
  25. package/dist/scaffold.js +96 -116
  26. package/package.json +1 -1
  27. package/skills/nola/SKILL.md +72 -17
  28. package/skills/nola/references/config.md +35 -6
  29. package/skills/nola/references/patterns.md +129 -31
  30. package/skills/nola/references/pitfalls.md +318 -56
  31. package/skills/nola/references/syntax.md +345 -121
  32. package/templates/empty/package.json +5 -5
  33. package/templates/empty/src/main.tsi +8 -0
  34. package/templates/empty/src/main.ts +0 -5
  35. package/templates/feature-extraction/README.md +0 -20
  36. package/templates/feature-extraction/nola.config.ts +0 -14
  37. package/templates/feature-extraction/nola.replay.jsonl +0 -2
  38. package/templates/feature-extraction/package.json +0 -22
  39. package/templates/feature-extraction/src/main.tsi +0 -22
  40. package/templates/feature-extraction/tsconfig.json +0 -12
  41. package/templates/function-calling/README.md +0 -21
  42. package/templates/function-calling/nola.config.ts +0 -14
  43. package/templates/function-calling/nola.replay.jsonl +0 -1
  44. package/templates/function-calling/package.json +0 -22
  45. package/templates/function-calling/src/main.tsi +0 -12
  46. package/templates/function-calling/src/tickets.ts +0 -17
  47. package/templates/function-calling/tsconfig.json +0 -12
  48. package/templates/typescript-interop/README.md +0 -15
  49. package/templates/typescript-interop/nola.config.ts +0 -14
  50. package/templates/typescript-interop/nola.replay.jsonl +0 -1
  51. package/templates/typescript-interop/package.json +0 -22
  52. package/templates/typescript-interop/src/main.ts +0 -8
  53. package/templates/typescript-interop/src/person.tsi +0 -11
  54. package/templates/typescript-interop/tsconfig.json +0 -12
@@ -15,14 +15,14 @@ a parenthesized expression will not parse.
15
15
  ```tsi
16
16
  export infer function summarize(.text: string, useFast: boolean) {
17
17
  // WRONG
18
- const a = ask with "fast" `a rough summary`<string>;
19
- const b = ask with provider.fast `a rough summary`<string>;
18
+ const a = ask with "fast" `a rough summary`: string;
19
+ const b = ask with provider.fast `a rough summary`: string;
20
20
 
21
21
  // RIGHT — name it in nola.config.ts, then use that name
22
- const c = ask with fast `a rough summary`<string>;
22
+ const c = ask with fast `a rough summary`: string;
23
23
 
24
24
  // RIGHT — dynamic choice
25
- const d = ask (..`a rough summary`<string>).withModel(useFast ? "fast" : "careful");
25
+ const d = ask (..`a rough summary`: string).withModel(useFast ? "fast" : "careful");
26
26
 
27
27
  return { a, b, c, d };
28
28
  }
@@ -53,28 +53,27 @@ function summarize(.text: string) {
53
53
 
54
54
  // RIGHT
55
55
  export infer function summarize(.text: string) {
56
- return ask `a one-sentence summary`<string>;
56
+ return ask `a one-sentence summary`: string;
57
57
  }
58
58
  ```
59
59
 
60
60
  If the function is genuinely plain TypeScript, drop the `.`; the parameter is
61
61
  an ordinary argument.
62
62
 
63
- ## NOLA2013 — marker and body instruction together
63
+ ## NOLA1019 — the marker slot is reserved
64
64
 
65
- > this infer function already has an instruction marker — write the instruction in one place.
65
+ > the marker after an infer function's name is reserved for a future Nola version — write the instruction as a context statement in the body: `…`.
66
66
 
67
67
  ```tsi
68
- // WRONG — two spellings of the same instruction
68
+ // WRONG — the instruction in the reserved slot
69
69
  export infer function f`be terse`(.t: string) {
70
- `be terse`
71
- return ask `the kind`<string>;
70
+ return ask `the kind`: string;
72
71
  }
73
72
 
74
- // RIGHT — one or the other
73
+ // RIGHT — a context statement in the body
75
74
  export infer function f(.t: string) {
76
75
  `be terse`
77
- return ask `the kind`<string>;
76
+ return ask `the kind`: string;
78
77
  }
79
78
  ```
80
79
 
@@ -89,16 +88,16 @@ infer function — nor in a class field initializer or `static` block.
89
88
 
90
89
  ```tsi
91
90
  // WRONG
92
- const g = async () => ask `the kind`<string>; // plain closure
91
+ const g = async () => ask `the kind`: string; // plain closure
93
92
 
94
93
  export infer function f(.t: string) {
95
- const h = () => ask `the kind`<string>; // nested closure
94
+ const h = () => ask `the kind`: string; // nested closure
96
95
  return h();
97
96
  }
98
97
 
99
98
  // RIGHT — ask directly in the body, or at the top level of the module
100
99
  export infer function f(.t: string) {
101
- return ask `the kind`<string>;
100
+ return ask `the kind`: string;
102
101
  }
103
102
  export const kind = ask f("…");
104
103
  ```
@@ -107,32 +106,165 @@ Constructing an extractor outside a body is fine — only resolving it is
107
106
  restricted:
108
107
 
109
108
  ```tsi
110
- export const nameIntent = ..`the user's full name`<string>; // legal, inert
109
+ export const nameIntent = ..`the user's full name`: string; // legal, inert
111
110
  ```
112
111
 
113
- ## NOLA2014 — a typed template outside `ask` needs the dots
112
+ ## NOLA2014 — a typed template outside `ask` and a call's slots needs the dots
114
113
 
115
- > a typed template literal is an extractor only directly after `ask`; write ..`…`<T> here.
114
+ > a typed template literal is an extractor only directly after `ask` or in a call's argument list; write ..`…`<T> here.
116
115
 
117
- The `..` is implied only directly after `ask`. Anywhere else a bare template
118
- is an ordinary string, so an extractor there needs its sigil:
116
+ The `..` is implied directly after `ask` and in a call's slots (an argument,
117
+ or a value nested in plain object/array literals there). Anywhere else a bare
118
+ template is an ordinary string, so an extractor there needs its sigil. The
119
+ code is raised for the angle-bracket spelling; a colon-typed template in such
120
+ a place (`` const stored = `the user's full name`: string ``) is a plain
121
+ syntax error instead:
119
122
 
120
123
  ```tsi
121
124
  declare function createTicket(title: string): Promise<string>;
122
125
 
123
126
  infer function file(.request: string) {
124
- const wrong = ask createTicket(`a short title`<string>); // NOLA2014
125
- const right = ask createTicket(..`a short title`<string>);
127
+ const wrong = `a short title`<string>; // NOLA2014 — stored: dots required
128
+ const right = ask createTicket(`a short title`: string); // a slot: the dots are implied
126
129
  return right;
127
130
  }
128
- export const stored = ..`the user's full name`<string>; // stored: dots required
131
+ export const stored = ..`the user's full name`: string; // stored: dots required
132
+ ```
133
+
134
+ ## NOLA1018 — a colon type with nothing on its line
135
+
136
+ > expected a type after the extractor's `:` on the same line — write `…`: T.
137
+
138
+ The colon spelling `` ask `the ticket id`: string `` takes the colon glued,
139
+ spaced or on the next line (`` `p` : string `` and `` `p`\n : string `` are the
140
+ same ask — a line break alone never ends an ask) and needs the type on the
141
+ colon's line. Two more traps come with it, both from the type having no
142
+ closing delimiter:
143
+
144
+ ```tsi
145
+ interface User { name: string }
146
+
147
+ infer function f(.doc: string) {
148
+ const a = ask `the user`: User.withRetry(2); // the TYPE `User.withRetry`, called with 2 — TS error
149
+ const b = ask `the user`<User>.withRetry(2); // RIGHT
150
+ const c = ask `the tags`: string[].withRetry(2); // RIGHT — a delimited type ends the type
151
+ return { b, c };
152
+ }
153
+ ```
154
+
155
+ A bare type name followed by `.` continues as a qualified type name, and `<`
156
+ after a type name opens type arguments (`` `n`: User < 5 `` is not a
157
+ comparison). Chain intent methods after a parenthesized extractor
158
+ (`` ask (..`the user`: User).withRetry(2) ``), after a delimited type
159
+ (`string[]`, `Array<User>`, `{…}`, `(User)`), or after `<T>`.
160
+
161
+ ## NOLA1020 — a value in a context statement must be simple
162
+
163
+ > a value in a context statement is a name, a call or a bracketed expression,
164
+ > followed by text or the end of the statement — wrap anything else in
165
+ > parentheses, or assign it to a local first (`await`, `ask` and `this` cannot
166
+ > be values).
167
+
168
+ The same code, with ask-site wording, covers an ask sequence: `this`,
169
+ `await`, `ask`, `function` or `class` where a value would start after a
170
+ text, a value ending in a backtick (`` ask `p` new Foo `more` ``), and text
171
+ after the type (`` ask `p`: T `more` `` — the type ends the sequence; move
172
+ the text before `: T`).
173
+
174
+ ```tsi
175
+ export infer function total(.items: string[], a: number, b: number) {
176
+ // WRONG — an operator after a value
177
+ `total` a + b `items`;
178
+ // RIGHT
179
+ `total` (a + b) `items`;
180
+ return ask `a summary`: string;
181
+ }
182
+ ```
183
+
184
+ `this` is the same kind of mistake: an item is a hoisted function of its own,
185
+ so its `this` is not the infer function's. A bare `this` after text is
186
+ NOLA1020; in parentheses or in a `${}` hole it is TS2683 in `nola check` and
187
+ the editor (and `undefined` at run time). Assign it to a local first:
188
+
189
+ ```tsi
190
+ export infer function greet(this: { user: string }) {
191
+ // WRONG — NOLA1020 (bare `this`); `(this.user)` and `${this.user}` are TS2683
192
+ `Greet` this.user `warmly.`;
193
+ // RIGHT — a local, then its name
194
+ const user = this.user;
195
+ `Greet` user `warmly.`;
196
+ return ask `a one-line greeting`: string;
197
+ }
198
+ ```
199
+
200
+ Also:
201
+
202
+ - A value never ends with a backtick: `` `x` foo<string> `more` `` and
203
+ `` `x` new Foo `more` `` are NOLA1020 too (the text would be read as a
204
+ tagged template) — write `(foo<string>)`, `(new Foo)` or `new Foo()`.
205
+ - `typeof`, `void`, `await`, `ask`, `this`, `..`, `function` and `class`
206
+ right after text are NOLA1020. Parenthesize `typeof`, `void`, functions and
207
+ classes. `await`, `ask` and `this` cannot be values even in parentheses (an
208
+ item is read at each ask, outside the async body, in a function of its own:
209
+ `(await x)` is TS1308, `(this.x)` is TS2683, `(ask …)` is NOLA2010) —
210
+ compute the value into a `const` first and write its name.
211
+ - A NAME at the start of a line begins a new statement (JavaScript's own
212
+ rule), so `` `analyze` `` on one line and `foo(x)` on the next are a context
213
+ statement and a call. Keep values on the text's line, or start the line with
214
+ `(` or `[`.
215
+ - The mirror image: a CODE line that starts with `[` or `(` right after a
216
+ context statement continues it and becomes its value — no error, but
217
+ whatever the code returns (`undefined` for a `forEach`) lands in the
218
+ prompt, and the code runs at every ask. End the context statement with
219
+ `;`.
220
+
221
+ ## An operator after the text is not a context statement
222
+
223
+ No diagnostic: `` `Page ` + oncall `` is ordinary JavaScript — a string
224
+ concatenation whose result is dropped — so the model never sees it.
225
+
226
+ ```tsi
227
+ export infer function page(.ticket: string, oncall: string) {
228
+ // WRONG — plain concatenation, nothing reaches the model
229
+ `Page ` + oncall + ` when the ticket is an outage.`;
230
+ // RIGHT — juxtapose the parts, or use a hole
231
+ `Page` oncall `when the ticket is an outage.`;
232
+ `Page ${oncall} when the ticket is an outage.`;
233
+ return ask `the severity`: string;
234
+ }
235
+ ```
236
+
237
+ ## NOLA2017 — a context statement outside a scope body
238
+
239
+ > a context statement is only legal in a scope body — directly in an infer
240
+ > function or at module level.
241
+
242
+ > a context statement cannot be the unbraced body of an `if`, a loop or a
243
+ > label — wrap it in braces.
244
+
245
+ ```tsi
246
+ export infer function go(.items: string[], urgent: boolean) {
247
+ // WRONG — inside a callback, no ask can carry it
248
+ items.forEach((it) => {
249
+ `note` it;
250
+ });
251
+ // WRONG — an unbraced body
252
+ if (urgent) `Answer quickly.`;
253
+ // RIGHT — directly in the body, before the asks that should see it
254
+ `items:` items;
255
+ return ask `a summary`: string;
256
+ }
129
257
  ```
130
258
 
259
+ A class `static` block and a namespace body are outside a scope body too.
260
+ Inside braces (`if (urgent) { … }`) a context statement is legal and applies
261
+ to the asks inside them.
262
+
131
263
  ## NOLA2002 — a type the compiler cannot turn into a schema
132
264
 
133
265
  > unsupported type for intent schema: …
134
266
 
135
- An extractor's `<T>` must RESOLVE to a JSON-shaped value — the TypeScript
267
+ An extractor's type must RESOLVE to a JSON-shaped value — the TypeScript
136
268
  checker decides, so unions (`Refund | Chargeback`, `string | null`),
137
269
  `Partial<T>` / `Pick` / `Omit`, `interface … extends`, intersections,
138
270
  `Record<string, T>`, tuples, generics applied with arguments and types from
@@ -143,16 +275,16 @@ functions and a generic declaration used without arguments (`Box<T>` — write
143
275
  ```tsi
144
276
  export infer function tally(.doc: string) {
145
277
  // WRONG
146
- const wrong = ask `counts per label`<Map<string, number>>;
278
+ const wrong = ask `counts per label`: Map<string, number>;
147
279
 
148
280
  // RIGHT — a JSON-shaped type; convert afterwards in plain TS
149
- const counts = ask `counts per label`<{ label: string; count: number }[]>;
281
+ const counts = ask `counts per label`: { label: string; count: number }[];
150
282
  const asMap = new Map(counts.map((c) => [c.label, c.count]));
151
283
  return asMap;
152
284
  }
153
285
  ```
154
286
 
155
- Always give an extractor a concrete `<T>` in an expression position. An
287
+ Always give an extractor a concrete type in an expression position. An
156
288
  extractor is a value-producing expression; it is not a statement, a type, or a
157
289
  declaration.
158
290
 
@@ -169,18 +301,18 @@ values are serialized into the prompt.
169
301
  ```tsi
170
302
  // WRONG
171
303
  export infer function topLabel(.index: Map<string, number>) {
172
- return ask `the label with the highest count`<string>;
304
+ return ask `the label with the highest count`: string;
173
305
  }
174
306
 
175
307
  // RIGHT — pass a JSON-shaped view as the contextual parameter
176
308
  export infer function topLabel(.index: { label: string; count: number }[]) {
177
- return ask `the label with the highest count`<string>;
309
+ return ask `the label with the highest count`: string;
178
310
  }
179
311
 
180
312
  // RIGHT — keep the exotic value, but as a PLAIN parameter (the LLM never
181
313
  // sees its value, so nothing needs deriving)
182
314
  export infer function topLabel(.summary: string, index: Map<string, number>) {
183
- const label = ask `the label with the highest count`<string>;
315
+ const label = ask `the label with the highest count`: string;
184
316
  return { label, count: index.get(label) ?? 0 };
185
317
  }
186
318
  ```
@@ -199,9 +331,9 @@ export default defineConfig({
199
331
  Keep that value a literal — the editor reads it statically and never executes
200
332
  your config.
201
333
 
202
- ## NOLA2004 — a call-intent slot with no `<T>`
334
+ ## NOLA2004 — a call-intent slot with no type
203
335
 
204
- > an extractor used as a call-intent argument must have an explicit `<T>`.
336
+ > an extractor used as a call-intent argument must have an explicit type — write ..`…`: T here.
205
337
 
206
338
  ```tsi
207
339
  declare function createTicket(title: string, priority: number): Promise<string>;
@@ -210,12 +342,111 @@ export infer function fileTicket(.request: string) {
210
342
  // WRONG — the slot has no type
211
343
  const wrong = ask createTicket(..`a short ticket title`, 2);
212
344
 
213
- // RIGHT
214
- const id = ask createTicket(..`a short ticket title`<string>, 2);
345
+ // RIGHT (the slot's `..` is implied; `..`a short ticket title`: string` works too)
346
+ const id = ask createTicket(`a short ticket title`: string, 2);
215
347
  return id;
216
348
  }
217
349
  ```
218
350
 
351
+ A bare template with no type, `` createTicket(`a short ticket title`, 2) ``,
352
+ is not a slot at all: it is a plain string argument and the call stays an
353
+ ordinary call — no error, and no model request.
354
+
355
+ ## NOLA1021 / NOLA1022 — a tool list holds functions
356
+
357
+ > a tool list holds functions — a name, a member, an expression that is one function, or a group (a module or an object of functions, an array of them), bare or spread; a literal cannot be one, and the list is not empty.
358
+
359
+ The brackets after an ask's template are a TOOL LIST (tool use). An entry is
360
+ a value: a name or dotted chain (one function, or a group — a module, an
361
+ object of functions, an array of them), a spread of a group, or an
362
+ expression that is one function. A literal (a string, a number, an arrow,
363
+ an object or array literal) or an empty list is NOLA1021, and a call written
364
+ in the list — describing the arguments in place — is reserved (NOLA1022):
365
+
366
+ ```tsi
367
+ // not-checked — WRONG
368
+ const a = ask `find the files` [searchFiles, "readFile"]: string[]; // NOLA1021
369
+ const b = ask `get the user` [getUser(`the id`: string)]: User; // NOLA1022 — reserved
370
+ ```
371
+
372
+ ```tsi
373
+ // RIGHT
374
+ const a = ask `find the files` [searchFiles, fs.readFile]: string[];
375
+ const g = ask `find the files` [fileTools, ...moreTools]: string[]; // a group by name, a group flattened
376
+ const b = ask `get the user` [getUser]: User; // the arguments come from getUser's signature
377
+ ```
378
+
379
+ ## NOLA1023 — a typed ask in a ternary's consequent
380
+
381
+ > a typed extractor directly in a ternary's consequent — parenthesize it: `cond ? (ask `p`: T) : y`.
382
+
383
+ Two colons with different meanings would sit side by side, so the typed ask
384
+ goes in parentheses (an untyped ask, a call intent and the `<T>` form need
385
+ none; the alternate position is free):
386
+
387
+ ```tsi
388
+ // not-checked — WRONG
389
+ const t = cond ? ask `the title`: string : "untitled";
390
+ ```
391
+
392
+ ```tsi
393
+ // RIGHT
394
+ const t = cond ? (ask `the title`: string) : "untitled";
395
+ ```
396
+
397
+ ## NOLA2018 — a tool list entry the compiler cannot use
398
+
399
+ An entry that is neither one function nor a group (a value, a type-only
400
+ import, a class, a union of function types — `const f = cond ? a : b` —
401
+ `any`), a function under a spread, a group reached through an expression
402
+ (`[groups[0]]` — name it or spread it), a method reached through a call
403
+ (`api.client().search` — name the object first), a group with nothing
404
+ callable, or
405
+ two tools that would share one name on the wire (`a.b` beside `a_b`; the
406
+ same function twice; a spread's `search` beside another). Name a function
407
+ or a group, keep the names distinct, offer colliding groups bare so their
408
+ names carry the prefix. A parameter the walk cannot derive — a rest
409
+ parameter, a `Map`, a generic parameter — is NOLA2002 at the entry; a group
410
+ member the walk cannot use fails the group, naming the member.
411
+
412
+ ## NOLA2019 — a reserved shape of the ask sequence
413
+
414
+ Tools beside a call: `` ask `use` [searchFiles] `then` createUser(`id`: string) ``
415
+ is the kind where the loop runs and the call's slots are the answer —
416
+ designed, not built. Offer the function as a tool, or make the call its own
417
+ ask after the tool-use ask. Also a `..` sequence inside a call's slot
418
+ (`` fn(..`t` user: string) ``): a slot's instruction is one text.
419
+
420
+ ## NOLA2020 — an ask sequence that cannot mean one thing
421
+
422
+ Two calls with typed slots (an ask makes one call — split the asks); a
423
+ `: T` beside a call (the call's result is the type — drop it); text after
424
+ a bare call (`` ask f(`x`: string) `more` `` — put the words first:
425
+ `` ask `more` f(`x`: string) ``); a call with typed slots inside a data
426
+ value (`` ask `use` (createUser(`id`: string)) `go`: T `` — write it bare
427
+ between texts, it is the action, not data).
428
+
429
+ ## NOLA3019 – NOLA3022 — tool use at run time
430
+
431
+ - NOLA3019: the resolved model cannot request tool calls (a hand-written
432
+ `LanguageModel`, a mock without `{ tools: true }`, `typesafe()`, a vendor
433
+ model with `toolUse: false`). Route the
434
+ ask to `openai` / `anthropic` / `google` / `"nola"`, or brand the mock.
435
+ Refused before the network.
436
+ - NOLA3020: the model kept calling tools past the cap (`.withMaxTurns(n)`,
437
+ else `ask.maxTurns`, 10). Raise the cap, give it tools that answer in fewer
438
+ calls, or sharpen the task. Definitive; the transcript rides the error.
439
+ - NOLA3021: a tool threw. Fix the tool, or return the failure as a value
440
+ when the model should recover from it. Invalid arguments never reach the
441
+ function — they go back to the model as that call's result.
442
+ - NOLA3022: the list could not be built when the ask ran — a value that is
443
+ not what its type promised (a group member that is not a function, a
444
+ tuple of another length), a function with no name (an anonymous arrow in
445
+ an array), or two tools with one wire name. Before the network.
446
+
447
+ `.withRetry(n)` on a tool-use ask re-runs the WHOLE loop, tools included:
448
+ only with tools that are safe to repeat.
449
+
219
450
  ## NOLA3010 — bare `await` on a raw extract or call intent
220
451
 
221
452
  > extract/call intents carry no construction scope — only `ask` supplies their
@@ -285,7 +516,7 @@ import { Person } from "./models.js"; // WRONG — kept at run time; mod
285
516
 
286
517
  `__nola` and any identifier starting with `__nola` are reserved in `.tsi`.
287
518
  `__nola.ask(...)`, `__nola.intents.ExtractIntent(...)`, `__nola.types.string()`
288
- and `__nola_file_ctx()` are what the compiler EMITS — they are not an API you
519
+ and `__nola_module_ctx()` are what the compiler EMITS — they are not an API you
289
520
  call, and writing them by hand is an error.
290
521
 
291
522
  ```tsi
@@ -297,36 +528,58 @@ export infer function read(.doc: string) {
297
528
  );
298
529
 
299
530
  // RIGHT
300
- const v = ask `the value`<string>;
531
+ const v = ask `the value`: string;
301
532
  return v;
302
533
  }
303
534
  ```
304
535
 
305
- ## NOLA2009 — `${.member}` outside a Nola instruction
306
-
307
- `${.x}` is prompt-scope access and only means something inside an
308
- infer-function marker, an extractor's backticks, or a call-intent hint. In a
309
- plain template literal it is an error — use a lexical value there.
536
+ ## NOLA2010 — a Nola construct inside a context statement or a hole
537
+
538
+ > Nola constructs are not allowed inside a context statement or an instruction
539
+ > literal's hole; a hinted call intent used as a value must be parenthesized.
540
+
541
+ A context statement is read at each ask, outside the async body, and call
542
+ hints are re-emitted from source, so `ask` and `..` cannot appear in a context
543
+ statement's parenthesized value, bracketed value or `${}` hole, nor in a call
544
+ hint's hole (written bare right after the text, they are NOLA1020). A call
545
+ intent is a legal value, but a HINTED one, `` fn`hint`(…) ``, must be
546
+ parenthesized or written in a `${}` hole (an empty marker too): bare, the
547
+ backtick after `fn` is read as the next text part and the arguments as a
548
+ value of their own, so it is no call intent — a `` ..`x`: T `` in the
549
+ arguments is left as a bare extractor, and that is this error (a `` `x`: T ``
550
+ there is a syntax error at its colon, since a parenthesized group has no
551
+ slots); plain arguments may raise no error at all and render the wrong text.
552
+ A sigil-less call intent (`` fn(`x`: T) ``) needs no parentheses. Otherwise
553
+ compute the value first and interpolate the result, or move the ask into the
554
+ function body.
310
555
 
311
- ## NOLA2010 — a Nola construct inside a marker / call-hint hole
312
-
313
- Marker and call-hint literals are re-emitted from source, so `..`, call
314
- intents and `ask` cannot appear in their holes. Compute the value first and
315
- interpolate the result, or move the ask into the function body.
556
+ ```tsi
557
+ declare function escalate(team: string): void;
558
+
559
+ export infer function route(.ticket: string) {
560
+ // WRONG — the hint's backtick starts the next text part: NOLA2010 at the extractor
561
+ `If the ticket is an outage,` escalate`page the on-call engineer`(..`the team to page`: string);
562
+ // RIGHT — parenthesized (or written in a `${}` hole)
563
+ `If the ticket is an outage,` (escalate`page the on-call engineer`(`the team to page`: string));
564
+ // RIGHT — no hint, no parentheses
565
+ `If the ticket is an outage,` escalate(`the team to page`: string);
566
+ return ask `the label for the ticket`: string;
567
+ }
568
+ ```
316
569
 
317
- ## NOLA3014 — a prompt template rendered nothing (or threw)
570
+ ## NOLA3015 — the Node loader under Bun or Deno
318
571
 
319
- A `${.member}` template must produce text. An empty result usually means the
320
- template only read members that were undefined; a throw is a bug in the
321
- template's own JS. Fixed at the template — there is no retry.
572
+ `nola run` and `node --import nola-lang/register` ARE Node's module-hooks API;
573
+ Bun and Deno do not run them. On Bun, run `.tsi` from source through
574
+ `@nola-lang/bun` instead: `preload = ["@nola-lang/bun/preload"]` in
575
+ `bunfig.toml`, then `bun src/main.tsi` (see config.md, "Running on Bun").
576
+ Deno cannot load `.tsi` at all — run on Node. Any package manager is fine
577
+ (`bun install`, `bun run start`: the `nola` bin is a Node script).
322
578
 
323
- ## NOLA3015 — running `.tsi` under Bun or Deno
579
+ ## NOLA3023 — Bun older than 1.3
324
580
 
325
- The loader is Node's module-hooks API; Bun and Deno do not run it. Any package
326
- manager is fine (`bun install`, `bun run start`, `pnpm start`, `yarn start` —
327
- the `nola` bin is a Node script), but `bun --bun`, `bun src/main.ts` and
328
- `deno run` cannot load `.tsi`. Run on Node: `nola run` or
329
- `node --import nola-lang/register src/main.ts`.
581
+ `@nola-lang/bun` needs `process.getBuiltinModule` (Bun ≥ 1.3). Run
582
+ `bun upgrade`.
330
583
 
331
584
  ## Other things that will not parse
332
585
 
@@ -336,3 +589,12 @@ the `nola` bin is a Node script), but `bun --bun`, `bun src/main.ts` and
336
589
  - `infer` on a method, arrow function or function expression — top-level
337
590
  function declarations only.
338
591
  - `fn(..)` — the bare derive-all call form is reserved (NOLA1004).
592
+ - `` cond ? ask `p` : y `` — a colon on the extractor's line is its type,
593
+ spaced or glued, so the ask reads `y` as its type and the ternary loses its
594
+ alternate: NOLA1023. A typed ask standing bare as a consequent is the same
595
+ code — parenthesize it: `` cond ? (ask `p`: T) : y ``, on one line or
596
+ three: the formatted `` cond\n ? ask `p`\n : y `` reads `y` as the type
597
+ too, since a line break alone never ends an ask.
598
+ - `` fn(`x` [tools]: T) `` — a tool list is never a call slot; a bracket
599
+ there keeps its JavaScript meaning. The list goes on the ask site or the
600
+ stored `..` form only.