tjs-lang 0.7.7 → 0.7.8

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 (59) hide show
  1. package/CLAUDE.md +90 -33
  2. package/bin/docs.js +4 -1
  3. package/demo/docs.json +45 -11
  4. package/demo/src/examples.test.ts +1 -0
  5. package/demo/src/imports.test.ts +16 -4
  6. package/demo/src/imports.ts +60 -15
  7. package/demo/src/playground-shared.ts +9 -8
  8. package/demo/src/tfs-worker.js +205 -147
  9. package/demo/src/tjs-playground.ts +34 -10
  10. package/demo/src/ts-playground.ts +24 -8
  11. package/dist/index.js +118 -101
  12. package/dist/index.js.map +4 -4
  13. package/dist/src/lang/bool-coercion.d.ts +50 -0
  14. package/dist/src/lang/docs.d.ts +31 -6
  15. package/dist/src/lang/linter.d.ts +8 -0
  16. package/dist/src/lang/parser-transforms.d.ts +18 -0
  17. package/dist/src/lang/parser-types.d.ts +2 -0
  18. package/dist/src/lang/parser.d.ts +3 -0
  19. package/dist/src/lang/runtime.d.ts +34 -0
  20. package/dist/src/lang/types.d.ts +9 -1
  21. package/dist/src/rbac/index.d.ts +1 -1
  22. package/dist/src/vm/runtime.d.ts +1 -1
  23. package/dist/tjs-eval.js +38 -36
  24. package/dist/tjs-eval.js.map +4 -4
  25. package/dist/tjs-from-ts.js +20 -20
  26. package/dist/tjs-from-ts.js.map +3 -3
  27. package/dist/tjs-lang.js +85 -83
  28. package/dist/tjs-lang.js.map +4 -4
  29. package/dist/tjs-vm.js +47 -45
  30. package/dist/tjs-vm.js.map +4 -4
  31. package/llms.txt +79 -0
  32. package/package.json +3 -2
  33. package/src/cli/commands/convert.test.ts +16 -21
  34. package/src/lang/bool-coercion.test.ts +203 -0
  35. package/src/lang/bool-coercion.ts +314 -0
  36. package/src/lang/codegen.test.ts +137 -0
  37. package/src/lang/docs.test.ts +328 -1
  38. package/src/lang/docs.ts +424 -24
  39. package/src/lang/emitters/ast.ts +11 -12
  40. package/src/lang/emitters/dts.test.ts +41 -0
  41. package/src/lang/emitters/dts.ts +9 -0
  42. package/src/lang/emitters/js-tests.ts +9 -4
  43. package/src/lang/emitters/js.ts +182 -2
  44. package/src/lang/inference.ts +54 -0
  45. package/src/lang/linter.test.ts +104 -1
  46. package/src/lang/linter.ts +124 -1
  47. package/src/lang/parser-params.ts +31 -0
  48. package/src/lang/parser-transforms.ts +304 -0
  49. package/src/lang/parser-types.ts +2 -0
  50. package/src/lang/parser.test.ts +73 -1
  51. package/src/lang/parser.ts +34 -1
  52. package/src/lang/runtime.ts +98 -0
  53. package/src/lang/types.ts +6 -0
  54. package/src/rbac/index.ts +2 -2
  55. package/src/rbac/rules.tjs.d.ts +9 -0
  56. package/src/vm/atoms/batteries.ts +2 -2
  57. package/src/vm/runtime.ts +10 -3
  58. package/dist/src/rbac/rules.d.ts +0 -184
  59. package/src/rbac/rules.js +0 -338
package/demo/docs.json CHANGED
@@ -131,6 +131,18 @@
131
131
  "language": "tjs",
132
132
  "description": "Multiple function declarations with the same name, automatically dispatched by argument types"
133
133
  },
134
+ {
135
+ "title": "JS Footgun Fixes",
136
+ "filename": "js-footgun-fixes.md",
137
+ "path": "guides/examples/tjs/js-footgun-fixes.md",
138
+ "section": "tjs",
139
+ "type": "example",
140
+ "group": "basics",
141
+ "order": 16,
142
+ "code": "/*#\n## What this demonstrates\n\nEach test below names a JavaScript footgun that native TJS quietly\nfixes. The test body is the proof: in raw JS the assertion would\nfail, in TJS it passes. The \"Test Cases\" section under this paragraph\nshows them in plain language.\n*/\n\ntest 'Boolean(new Boolean(false)) is false' {\n expect(Boolean(new Boolean(false))).toBe(false)\n}\n\ntest '!new Boolean(false) is true' {\n expect(!new Boolean(false)).toBe(true)\n}\n\ntest 'new Boolean(false) is falsy in if/while/for/?:' {\n expect((new Boolean(false)) ? 'truthy' : 'falsy').toBe('falsy')\n}\n\ntest 'new Boolean(false) || x returns x (LHS unwraps to falsy)' {\n expect((new Boolean(false)) || 'fallback').toBe('fallback')\n}\n\ntest \"'5' == 5 is false (no silent coercion across types)\" {\n expect('5' == 5).toBe(false)\n}\n\ntest \"'' == false is false (no silent coercion)\" {\n expect('' == false).toBe(false)\n}\n\ntest '0 == \"\" is false (no silent coercion)' {\n expect(0 == '').toBe(false)\n}\n\ntest 'NaN == NaN is true (NaN equals itself)' {\n expect(NaN == NaN).toBe(true)\n}\n\ntest 'null == undefined is true (preserved — useful pattern)' {\n expect(null == undefined).toBe(true)\n}\n\ntest 'new String(\"hi\") == \"hi\" is true (boxed primitives unwrap)' {\n expect(new String('hi') == 'hi').toBe(true)\n}\n\ntest 'typeof null is \"null\", not \"object\"' {\n expect(typeof null).toBe('null')\n}\n\ntest 'Is({a:1}, {a:1}) is true (deep structural equality)' {\n expect(Is({ a: 1 }, { a: 1 })).toBe(true)\n}\n\ntest 'Is([1,2,3], [1,2,3]) is true (arrays compare element-wise)' {\n expect(Is([1, 2, 3], [1, 2, 3])).toBe(true)\n}\n\ntest 'Is(new Set([1,2]), new Set([2,1])) is true (Sets are order-independent)' {\n expect(Is(new Set([1, 2]), new Set([2, 1]))).toBe(true)\n}",
143
+ "language": "tjs",
144
+ "description": "JavaScript has a small set of legendary, well-documented gotchas that no one defends but the spec will never change. Native TJS fixes them at the language level — always-on under `TjsStandard`, the default for `.tjs` files. Each test below names the footgun TJS quietly fixes."
145
+ },
134
146
  {
135
147
  "title": "Polymorphic Constructors",
136
148
  "filename": "polymorphic-constructors.md",
@@ -201,6 +213,16 @@
201
213
  "navTitle": "Documentation",
202
214
  "text": "<!--{\"section\": \"tjs\", \"group\": \"docs\", \"order\": 0, \"navTitle\": \"Documentation\"}-->\n\n# TJS: Typed JavaScript\n\n_Types as Examples. Zero Build. Runtime Metadata._\n\n---\n\n## What is TJS?\n\nTJS is a typed superset of JavaScript where **types are concrete values**, not abstract annotations.\n\n```typescript\n// TypeScript: abstract type annotation\nfunction greet(name: string): string\n\n// TJS: concrete example value\nfunction greet(name: 'World'): '' {\n return `Hello, ${name}!`\n}\n```\n\nThe example `'World'` tells TJS that `name` is a string. The example `''` tells TJS the return type is a string. Types are inferred from the examples you provide.\n\nTJS transpiles to JavaScript with embedded `__tjs` metadata, enabling runtime type checking, autocomplete from live objects, and documentation generation.\n\n---\n\n## TJS is JavaScript\n\nTJS is **purely additive**. It adds type annotations, runtime validation, and metadata on top of standard JavaScript. It does not replace, intercept, or modify any existing JavaScript semantics.\n\n**Everything you know about JavaScript still works:**\n\n- **Proxies** — fully supported. TJS never intercepts property access. `__tjs` metadata is a plain property assignment on the function object; it doesn't interfere with Proxy traps. The `[tjsEquals]` symbol protocol is specifically designed for Proxy-friendly custom equality.\n- **WeakMap, WeakSet, Map, Set** — all unchanged. TJS doesn't wrap or validate collection internals.\n- **Closures, Promises, async/await** — work identically to JS.\n- **Prototype chains** — preserved. `wrapClass()` uses a Proxy only on the class constructor (to allow calling without `new`), not on instances.\n- **Module semantics** — TJS preserves ES module `import`/`export` exactly. Lazy getters, circular dependencies, and re-exports work the same as in JS.\n- **`this` binding** — unchanged. Arrow functions, `.bind()`, `.call()`, `.apply()` all work normally.\n- **Regular expressions, JSON, Math, Date** — all standard built-ins are available and unmodified (though `Date` is banned by default in native TJS via `TjsDate` in favor of safer alternatives like `Timestamp`/`LegalDate`; use `TjsCompat` to restore it).\n\n**What TJS adds (and when): **\n\n| Addition | When | Overhead |\n| ---------------------- | ----------------------------------------------- | ----------------------------- |\n| Parameter validation | Function entry (unless `!` unsafe) | ~1.15-1.3x on that function |\n| Return type validation | Function exit (only with `safety all`) | ~1.15-1.3x on that function |\n| `__tjs` metadata | Transpile time | Zero runtime cost |\n| `wrapClass` Proxy | Class declaration (on by default in native TJS) | One-time, on constructor only |\n| Structural equality | `==`/`!=` (on by default in native TJS) | Per-comparison |\n\nIf TJS doesn't understand something in your code, it passes it through unchanged. There is no \"TJS runtime\" that interposes between your code and the JS engine — just the inline checks you can see in the transpiled output.\n\n---\n\n## The Compiler\n\nTJS compiles in the browser. No webpack, no node_modules, no build server.\n\n```typescript\nimport { tjs } from 'tjs-lang'\n\nconst code = tjs`\n function add(a: 0, b: 0): 0 {\n return a + b\n }\n`\n\n// Returns transpiled JavaScript with __tjs metadata\n```\n\nYou can also use the CLI:\n\n```bash\nbun src/cli/tjs.ts check file.tjs # Parse and type check\nbun src/cli/tjs.ts run file.tjs # Transpile and execute\nbun src/cli/tjs.ts emit file.tjs # Output transpiled JS\nbun src/cli/tjs.ts types file.tjs # Output type metadata\n```\n\n---\n\n## Syntax\n\n### Parameter Types (Colon Syntax)\n\n> **Not TypeScript.** TJS colon syntax looks like TypeScript but has different\n> semantics. The value after `:` is a **concrete example**, not a type name.\n> Write `name: 'Alice'` (example value), not `name: string` (type name).\n> TJS infers the type from the example: `'Alice'` → string, `0` → integer,\n> `true` → boolean.\n\nRequired parameters use colon syntax with an example value:\n\n```typescript\nfunction greet(name: 'Alice') {} // name is required, type: string\nfunction calculate(value: 0) {} // value is required, type: integer\nfunction measure(rate: 0.0) {} // rate is required, type: number (float)\nfunction count(n: +0) {} // n is required, type: non-negative integer\nfunction toggle(flag: true) {} // flag is required, type: boolean\n```\n\n### Numeric Types\n\nTJS distinguishes three numeric types using valid JavaScript syntax:\n\n```typescript\nfunction process(\n rate: 3.14, // number (float) -- has a decimal point\n count: 42, // integer -- whole number, no decimal\n index: +0 // non-negative integer -- prefixed with +\n) {}\n```\n\n| You Write | Type Inferred | Runtime Validation |\n| --------- | ---------------------- | ------------------------------- |\n| `3.14` | `number` (float) | `typeof x === 'number'` |\n| `0.0` | `number` (float) | `typeof x === 'number'` |\n| `42` | `integer` | `Number.isInteger(x)` |\n| `0` | `integer` | `Number.isInteger(x)` |\n| `+20` | `non-negative integer` | `Number.isInteger(x) && x >= 0` |\n| `+0` | `non-negative integer` | `Number.isInteger(x) && x >= 0` |\n| `-5` | `integer` | `Number.isInteger(x)` |\n| `-3.5` | `number` (float) | `typeof x === 'number'` |\n\nAll of these are valid JavaScript expressions. TJS reads the syntax more\ncarefully to give you finer-grained type checking than JS or TypeScript\nprovide natively.\n\n### Optional Parameters (Default Values)\n\nOptional parameters use `=` with a default value:\n\n```typescript\nfunction greet(name = 'World') {} // name is optional, defaults to 'World'\nfunction calculate(value = 0) {} // value is optional, defaults to 0 (integer)\n```\n\n### TypeScript-Style Optional (`?:`)\n\nTJS supports `?:` for compatibility, but consider it a migration aid rather than idiomatic TJS:\n\n```typescript\nfunction greet(name?: '') {} // same as name = ''\n```\n\n**Why `?:` is an antipattern.** In TypeScript, `?:` creates a three-state parameter\n(`value | undefined | missing`) that forces every function body to handle the absent case:\n\n```typescript\n// TypeScript — every caller and callee must reason about undefined\nfunction greet(name?: string) {\n const safeName = name ?? 'World' // defensive check required\n return `Hello, ${safeName}!`\n}\n```\n\nTJS offers two better alternatives:\n\n**1. Safe defaults** — the parameter always has a value, no branching needed:\n\n```typescript\nfunction greet(name = 'World') {\n return `Hello, ${name}!` // name is always a string\n}\n```\n\n**2. Polymorphic functions** — separate signatures for separate behavior:\n\n```typescript\nfunction greet() {\n return 'Hello, World!'\n}\nfunction greet(name: '') {\n return `Hello, ${name}!`\n}\n```\n\nBoth approaches eliminate the `undefined` state entirely. The function body\nnever needs a null check because the type system guarantees a valid value\nat every call site. This is simpler to write, simpler to read, and produces\ntighter runtime validation.\n\n### Object Parameters\n\nObject shapes are defined by example:\n\n```typescript\nfunction createUser(user: { name: ''; age: 0 }) {}\n// user must be an object with string name and number age\n```\n\n### Nullable Types\n\nUse `|` for union with null:\n\n```typescript\nfunction find(id: 0 | null) {} // number or null\n```\n\n### Rest Parameters\n\nRest params use `:` with an array example. The annotation is stripped from\nthe JS output (JS doesn't allow defaults on rest params) but captured in\n`__tjs` metadata:\n\n```typescript\nfunction sum(...nums: [1, 2, 3]): 6 {\n return nums.reduce((a = 0, b: 0) => a + b, 0)\n}\n\nfunction mean(...values: [1.0, 2.0, 3.0, 2.0]): 2.0 {\n return values.length\n ? values.reduce((sum = 0.0, x: 1.0) => sum + x) / values.length\n : 0.0\n}\n```\n\nSignature tests work with rest params — the example array elements are\nspread as individual arguments. `mean(1.0, 2.0, 3.0, 2.0)` is called\nand the result is checked against the `: 2.0` expected return using\nexact value comparison (deepEqual).\n\nThe array example tells TJS the element type. `[0]` means \"array of\nintegers\", `[1.0, 2.0]` means \"array of numbers (floats)\".\n\n**Heterogeneous arrays** infer a union item type:\n\n```typescript\nfunction log(...args: ['info', 42, true]) {}\n// args type: array<string | integer | boolean>\n```\n\n### Return Types (Colon Syntax)\n\nReturn types use `:`:\n\n```typescript\nfunction add(a: 0, b: 0): 0 {\n return a + b\n}\n\nfunction getUser(id: 0): { name: ''; age: 0 } {\n return { name: 'Alice', age: 30 }\n}\n```\n\n### Array Types\n\nArrays use bracket syntax with an example element:\n\n```typescript\nfunction sum(numbers: [0]): 0 {\n // array of numbers\n return numbers.reduce((a, b) => a + b, 0)\n}\n\nfunction names(users: [{ name: '' }]) {\n // array of objects\n return users.map((u) => u.name)\n}\n```\n\n---\n\n## Safety Markers\n\n### Unsafe Functions\n\nSkip validation for hot paths:\n\n```typescript\nfunction fastAdd(! a: 0, b: 0) { return a + b }\n```\n\nThe `!` marker after the function name skips input validation.\n\n### Safe Functions\n\nExplicit validation (for emphasis):\n\n```typescript\nfunction safeAdd(? a: 0, b: 0) { return a + b }\n```\n\n### Unsafe Blocks\n\nSkip validation for a block of code:\n\n```typescript\nunsafe {\n fastPath(data)\n anotherHotFunction(moreData)\n}\n```\n\n### Module Safety Directive\n\nSet the default validation level for an entire file:\n\n```typescript\nsafety none // No validation (metadata only)\nsafety inputs // Validate function inputs (default)\nsafety all // Validate everything (debug mode)\n```\n\n---\n\n## Type System\n\n### Type()\n\nDefine named types with predicates:\n\n```typescript\n// Simple type from example\nType Name 'Alice'\n\n// Type with description\nType User {\n description: 'a user object'\n example: { name: '', age: 0 }\n}\n\n// Type with predicate\nType PositiveNumber {\n description: 'a positive number'\n example: 1\n predicate(x) { return x > 0 }\n}\n```\n\nTypes can be used in function signatures:\n\n```typescript\nfunction greet(name: Name): '' {\n return `Hello, ${name}!`\n}\n```\n\n### Generic()\n\nRuntime-checkable generics:\n\n```typescript\nGeneric Box<T> {\n description: 'a boxed value'\n predicate(x, T) {\n return typeof x === 'object' && x !== null && 'value' in x && T(x.value)\n }\n}\n\n// With default type parameter\nGeneric Container<T, U = ''> {\n description: 'container with label'\n predicate(obj, T, U) {\n return T(obj.item) && U(obj.label)\n }\n}\n```\n\n#### Declaration Blocks (for TypeScript Consumers)\n\nGenerics can include an optional `declaration` block that specifies the\nTypeScript interface to emit in `.d.ts` output. This is metadata for TS\nconsumers — it has no effect on runtime behavior.\n\n```typescript\nGeneric BoxedProxy<T> {\n description: 'typed reactive proxy'\n predicate(x, T) {\n return typeof x === 'object' && 'value' in x && T(x.value)\n }\n declaration {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n touch(): void\n }\n}\n```\n\nWhen emitting `.d.ts` via `tjs emit --dts`, this produces:\n\n```typescript\nexport interface BoxedProxy<T> {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n touch(): void\n}\n```\n\nThe declaration content is raw TypeScript syntax — it's emitted verbatim\ninto the `.d.ts` file. This lets TJS libraries provide proper TypeScript\ninterfaces while keeping the TJS source as the single source of truth.\n\nWithout a `declaration` block, Generics emit an `any`-based factory stub\nthat provides basic IDE hints without false type errors.\n\n### Union()\n\nDiscriminated unions:\n\n```typescript\nconst Shape = Union('kind', {\n circle: { radius: 0 },\n rectangle: { width: 0, height: 0 },\n})\n\nfunction area(shape: Shape): 0 {\n if (shape.kind === 'circle') {\n return Math.PI * shape.radius ** 2\n }\n return shape.width * shape.height\n}\n```\n\n### Enum()\n\nString or numeric enums:\n\n```typescript\nconst Status = Enum(['pending', 'active', 'completed'])\nconst Priority = Enum({ low: 1, medium: 2, high: 3 })\n\nfunction setStatus(status: Status) {}\n```\n\n---\n\n## Structural Equality: Is / IsNot\n\nJavaScript's `==` is broken (type coercion). TJS provides structural equality:\n\n```typescript\n// Structural comparison - no coercion\n[1, 2] Is [1, 2] // true\n5 Is \"5\" // false (different types)\n{ a: 1 } Is { a: 1 } // true\n\n// Arrays compared element-by-element\n[1, [2, 3]] Is [1, [2, 3]] // true\n\n// Negation\n5 IsNot \"5\" // true\n```\n\n### Custom Equality\n\nObjects can define custom equality in two ways:\n\n**1. `[tjsEquals]` symbol protocol** (preferred for Proxies and advanced use):\n\n```typescript\nimport { tjsEquals } from 'tjs-lang/lang'\n\n// A proxy that delegates equality to its target\nconst target = { x: 1, y: 2 }\nconst proxy = new Proxy({\n [tjsEquals](other) { return target Is other }\n}, {})\n\nproxy == { x: 1, y: 2 } // true — delegates to target\n```\n\n**2. `.Equals` method** (simple, works on any object or class):\n\n```typescript\nclass Point {\n constructor(x: 0, y: 0) { this.x = x; this.y = y }\n Equals(other) { return this.x === other.x && this.y === other.y }\n}\n\nPoint(1, 2) Is Point(1, 2) // true (uses .Equals)\n```\n\n**Priority:** `[tjsEquals]` symbol > `.Equals` method > structural comparison.\n\nThe symbol is `Symbol.for('tjs.equals')`, so it works across realms. Access it\nvia `import { tjsEquals } from 'tjs-lang/lang'` or `__tjs.tjsEquals` at runtime.\n\n---\n\n## Classes\n\n### Callable Without `new`\n\nIn native TJS, classes are automatically wrapped so they can be called\nwithout `new` (the `TjsClass` mode is on by default). For TS-originated\ncode, add the `TjsClass` directive to enable this:\n\n```typescript\nclass User {\n constructor(name: '') {\n this.name = name\n }\n}\n\n// Both work identically:\nconst u1 = User('Alice') // TJS way - clean\nconst u2 = new User('Alice') // Also works (linter warns)\n```\n\nThe wrapping uses a Proxy on the constructor that intercepts bare calls\nand forwards them to `Reflect.construct`. This means `User('Alice')`\nand `new User('Alice')` always produce the same result — an instance.\n\n**What gets wrapped:** Only `class` declarations in your `.tjs` file.\nSpecifically:\n\n- `class Foo { }` in native TJS (or with `TjsClass` directive) → wrapped\n- Built-in globals (`Boolean`, `Number`, `String`, `Array`) → **never touched**\n- Old-style constructor functions (`function Foo() { }` with `Foo.prototype`) → **never touched**\n\n**Why not built-ins:** JavaScript's built-in constructors have dual\nbehavior — `Boolean(0)` returns the primitive `false` (type coercion),\nwhile `new Boolean(0)` returns a `Boolean` object wrapping `false`\n(which is truthy!). If TJS wrapped `Boolean`, then `Boolean(0)` would\nsilently become `new Boolean(0)` — a truthy object instead of `false`.\nThe same applies to `Number()`, `String()`, and `Array()`.\n\n**Why not old-style constructors:** If you're using `function` +\n`prototype` to build a class manually, you may intentionally want\n`Foo(x)` to behave differently from `new Foo(x)` — the same dual\nbehavior pattern as the built-ins. TJS respects this by only wrapping\nthe `class` keyword, where calling without `new` has no existing\nmeaning in JavaScript (it throws `TypeError`).\n\n### Private Fields\n\nUse `#` for private fields:\n\n```typescript\nclass Counter {\n #count = 0\n\n increment() {\n this.#count++\n }\n get value() {\n return this.#count\n }\n}\n```\n\nWhen converting from TypeScript, `private foo` becomes `#foo`.\n\n### Getters and Setters\n\nAsymmetric types are captured:\n\n```typescript\nclass Timestamp {\n #value\n\n constructor(initial: '' | 0 | null) {\n this.#value = initial === null ? new Date() : new Date(initial)\n }\n\n set value(v: '' | 0 | null) {\n this.#value = v === null ? new Date() : new Date(v)\n }\n\n get value() {\n return this.#value\n }\n}\n\nconst ts = Timestamp('2024-01-15')\nts.value = 0 // SET accepts: string | number | null\nts.value // GET returns: Date\n```\n\n---\n\n## Polymorphic Functions\n\nMultiple function declarations with the same name are automatically merged into a dispatcher that routes by argument count and type:\n\n```typescript\nfunction describe(value: 0) {\n return 'number: ' + value\n}\nfunction describe(value: '') {\n return 'string: ' + value\n}\nfunction describe(value: { name: '' }) {\n return 'object: ' + value.name\n}\n\ndescribe(42) // 'number: 42'\ndescribe('hello') // 'string: hello'\ndescribe({ name: 'world' }) // 'object: world'\ndescribe(true) // MonadicError: no matching overload\n```\n\n### Dispatch Order\n\n1. **Arity** first (number of arguments)\n2. **Type specificity** within same arity: `integer` > `number` > `any`; objects before primitives\n3. **Declaration order** as tiebreaker\n\n### Polymorphic Constructors\n\nClasses can have multiple constructor signatures (enabled by default in native TJS via `TjsClass`). The first becomes the real JS constructor; additional variants become factory functions:\n\n```typescript\nclass Point {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n constructor(coords: { x: 0.0; y: 0.0 }) {\n this.x = coords.x\n this.y = coords.y\n }\n}\n\nPoint(3, 4) // variant 1: two numbers\nPoint({ x: 10, y: 20 }) // variant 2: object\n```\n\nAll variants produce correct `instanceof` results.\n\n### Compile-Time Validation\n\nTJS catches these errors at transpile time:\n\n- **Ambiguous signatures**: Two variants with identical types at every position\n- **Rest parameters**: `...args` not supported in polymorphic functions\n- **Mixed async/sync**: All variants must agree\n\n---\n\n## Local Class Extensions\n\nAdd methods to built-in types without polluting prototypes:\n\n```typescript\nextend String {\n capitalize() {\n return this[0].toUpperCase() + this.slice(1)\n }\n words() {\n return this.split(/\\s+/)\n }\n}\n\n'hello world'.capitalize() // 'Hello world'\n'foo bar baz'.words() // ['foo', 'bar', 'baz']\n```\n\n### How It Works\n\nFor known-type receivers (literals, typed variables), calls are rewritten at transpile time to `.call()` — zero runtime overhead:\n\n```javascript\n// TJS source:\n'hello'.capitalize()\n\n// Generated JS:\n__ext_String.capitalize.call('hello')\n```\n\nFor unknown types, a runtime registry (`registerExtension` / `resolveExtension`) provides fallback dispatch.\n\n### Supported Types\n\nExtensions work on any type: `String`, `Number`, `Array`, `Boolean`, custom classes, and DOM classes like `HTMLElement`. Multiple `extend` blocks for the same type merge left-to-right (later declarations can override earlier methods).\n\n### Rules\n\n- Arrow functions are **not allowed** in extend blocks (they don't bind `this`)\n- Extensions are **file-local** — they don't leak across modules\n- Prototypes are **never modified** — `String.prototype.capitalize` remains `undefined`\n\n---\n\n## Runtime Features\n\n### `__tjs` Metadata\n\nEvery TJS function carries its type information:\n\n```typescript\nfunction createUser(input: { name: ''; age: 0 }): { id: 0 } {\n return { id: 123 }\n}\n\nconsole.log(createUser.__tjs)\n// {\n// params: {\n// input: { type: { kind: 'object', shape: { name: 'string', age: 'number' } } }\n// },\n// returns: { kind: 'object', shape: { id: 'number' } }\n// }\n```\n\nThis enables:\n\n- Autocomplete from live objects\n- Runtime type validation\n- Automatic documentation generation\n- JSON Schema generation (see below)\n\n### JSON Schema\n\nTJS types and function signatures can be exported as standard JSON Schema. Instead of writing schemas and inferring types (Zod), you write typed functions and get schemas out.\n\n#### From Types\n\n```typescript\nType User {\n example: { name: '', age: 0, email: '' }\n}\n\nUser.toJSONSchema()\n// {\n// type: 'object',\n// properties: {\n// name: { type: 'string' },\n// age: { type: 'integer' },\n// email: { type: 'string' }\n// },\n// required: ['name', 'age', 'email'],\n// additionalProperties: false\n// }\n\nUser.check({ name: 'Alice', age: 30, email: 'a@b.com' }) // true\nUser.strip({ name: 'Alice', age: 30, secret: 'pw' })\n// { name: 'Alice', age: 30 } — extra fields removed\n```\n\n#### From Function Signatures\n\n```typescript\nimport { functionMetaToJSONSchema } from 'tjs-lang/lang'\n\nfunction createUser(name: '', age: 0): { id: 0; name: '' } {\n return { id: 1, name }\n}\n\nconst { input, output } = functionMetaToJSONSchema(createUser.__tjs)\n// input: { type: 'object', properties: { name: { type: 'string' }, age: { type: 'integer' } }, required: ['name', 'age'] }\n// output: { type: 'object', properties: { id: { type: 'integer' }, name: { type: 'string' } }, ... }\n```\n\nWhen the shared runtime is installed (`installRuntime()`), `.schema()` is also available directly on the metadata:\n\n```typescript\ncreateUser.__tjs.schema() // same { input, output } result\n```\n\n#### Unions and Enums\n\n```typescript\nconst Direction = Union('direction', ['up', 'down', 'left', 'right'])\nDirection.toJSONSchema() // { enum: ['up', 'down', 'left', 'right'] }\n\nconst Status = Enum('status', { Active: 1, Inactive: 0 })\nStatus.toJSONSchema() // { enum: [1, 0] }\n```\n\nThis gives you OpenAPI-ready API contracts from your function signatures — no extra schema definitions needed.\n\n### Monadic Errors\n\nType validation failures return `MonadicError` instances (extends `Error`),\nnot thrown exceptions:\n\n```typescript\nimport { isMonadicError } from 'tjs-lang/lang'\n\nconst result = createUser({ name: 123 }) // wrong type\n// MonadicError: Expected string for 'createUser.name', got number\n\nif (isMonadicError(result)) {\n console.log(result.message) // \"Expected string for 'createUser.name', got number\"\n console.log(result.path) // \"createUser.name\"\n console.log(result.expected) // \"string\"\n console.log(result.actual) // \"number\"\n}\n```\n\nNo try/catch gambling. The host survives invalid inputs.\n\nFor general-purpose error values (not type errors), use the `error()` helper\nwhich returns plain `{ $error: true, message }` objects checkable with `isError()`.\n\n### Error History\n\nSince monadic errors don't throw, they can silently vanish if nobody checks the return value. TJS tracks recent type errors in a ring buffer so you can catch these:\n\n```typescript\n// Errors are tracked automatically (on by default, zero cost on happy path)\ngreet(42) // returns MonadicError, caller ignores it\nprocessOrder('bad') // same\n\n// Check what failed recently\nconst recent = __tjs.errors() // → recent MonadicErrors (newest last, max 64)\nfor (const err of recent) {\n console.log(err.message, err.path)\n}\n\n// Testing workflow: clear → run → check for surprises\n__tjs.clearErrors()\nrunMyCode()\nexpect(__tjs.errors()).toEqual([]) // no unexpected type errors\n\n// Total count survives ring buffer wrapping\n__tjs.getErrorCount() // → total since last clear\n```\n\n### Runtime Configuration\n\n```typescript\nimport { configure } from 'tjs-lang/lang'\n\n// Log type errors to console when they occur\nconfigure({ logTypeErrors: true })\n\n// Throw type errors instead of returning them (for debugging)\nconfigure({ throwTypeErrors: true })\n\n// Enable call stack tracking (off by default — ~2x overhead)\n// Useful for server-side logging and agent debugging without devtools\nconfigure({ callStacks: true })\n\n// Disable error history tracking (on by default, zero cost on happy path)\nconfigure({ trackErrors: false })\n```\n\nBoth `logTypeErrors` and `throwTypeErrors` work on the shared runtime and isolated `createRuntime()` instances.\n\n### Inline Tests\n\nTests live next to code:\n\n```typescript\nfunction double(x: 0): 0 { return x * 2 }\n\ntest('doubles numbers') {\n expect(double(5)).toBe(10)\n expect(double(-3)).toBe(-6)\n}\n```\n\nTests are extracted at compile time and can be:\n\n- Run during transpilation\n- Stripped in production builds\n- Used for documentation generation\n\n### WASM Blocks\n\nDrop into WebAssembly for compute-heavy code:\n\n```typescript\nfunction vectorDot(a: [0], b: [0]): 0 {\n let sum = 0\n wasm {\n for (let i = 0; i < a.length; i++) {\n sum = sum + a[i] * b[i]\n }\n }\n return sum\n}\n```\n\nVariables are captured automatically. Falls back to JS if WASM unavailable.\n\n#### SIMD Intrinsics (f32x4)\n\nFor compute-heavy workloads, use f32x4 SIMD intrinsics to process 4 float32 values per instruction:\n\n```typescript\nconst scale = wasm (arr: Float32Array, len: 0, factor: 0.0): 0 {\n let s = f32x4_splat(factor)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n let v = f32x4_load(arr, off)\n f32x4_store(arr, off, f32x4_mul(v, s))\n }\n} fallback {\n for (let i = 0; i < len; i++) arr[i] *= factor\n}\n```\n\nAvailable intrinsics:\n\n| Intrinsic | Description |\n| ----------------------------------- | ------------------------------------ |\n| `f32x4_load(ptr, byteOffset)` | Load 4 floats from memory into v128 |\n| `f32x4_store(ptr, byteOffset, vec)` | Store v128 as 4 floats to memory |\n| `f32x4_splat(scalar)` | Fill all 4 lanes with a scalar value |\n| `f32x4_extract_lane(vec, N)` | Extract float from lane 0-3 |\n| `f32x4_replace_lane(vec, N, val)` | Replace one lane, return new v128 |\n| `f32x4_add(a, b)` | Lane-wise addition |\n| `f32x4_sub(a, b)` | Lane-wise subtraction |\n| `f32x4_mul(a, b)` | Lane-wise multiplication |\n| `f32x4_div(a, b)` | Lane-wise division |\n| `f32x4_neg(v)` | Negate all lanes |\n| `f32x4_sqrt(v)` | Square root of all lanes |\n\nThis mirrors C/C++ SIMD intrinsics (`_mm_add_ps`, etc.) — explicit, predictable, no auto-vectorization magic.\n\n#### Zero-Copy Arrays: `wasmBuffer()`\n\nBy default, typed arrays passed to WASM blocks are copied into WASM memory before the call and copied back out after. For large arrays called frequently, this overhead can negate WASM's speed advantage.\n\n`wasmBuffer(Constructor, length)` allocates typed arrays directly in WASM linear memory. These arrays work like normal typed arrays from JavaScript, but when passed to a `wasm {}` block, they're zero-copy — the data is already there.\n\n```typescript\n// Allocate particle positions in WASM memory\nconst starX = wasmBuffer(Float32Array, 50000)\nconst starY = wasmBuffer(Float32Array, 50000)\n\n// Use from JS like normal arrays\nfor (let i = 0; i < 50000; i++) {\n starX[i] = (Math.random() - 0.5) * 2000\n starY[i] = (Math.random() - 0.5) * 2000\n}\n\n// Zero-copy SIMD processing\nfunction moveParticles(! xs: Float32Array, ys: Float32Array, len: 0, dx: 0.0, dy: 0.0) {\n wasm {\n let vdx = f32x4_splat(dx)\n let vdy = f32x4_splat(dy)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n f32x4_store(xs, off, f32x4_add(f32x4_load(xs, off), vdx))\n f32x4_store(ys, off, f32x4_add(f32x4_load(ys, off), vdy))\n }\n } fallback {\n for (let i = 0; i < len; i++) { xs[i] += dx; ys[i] += dy }\n }\n}\n\n// After WASM runs, JS sees the mutations immediately\nmoveParticles(starX, starY, 50000, 1.0, 0.5)\nconsole.log(starX[0]) // updated in place, no copy\n```\n\nKey points:\n\n- Supported constructors: `Float32Array`, `Float64Array`, `Int32Array`, `Uint8Array`\n- Uses a bump allocator — allocations persist for program lifetime\n- All WASM blocks in a file share one 64MB memory\n- Regular typed arrays still work (copy in/out as before)\n- Use `!` (unsafe) on hot-path functions to skip runtime type checks\n\n---\n\n## Module System\n\nTJS preserves standard ES module semantics exactly. `import` and `export` statements pass through to the output unchanged — TJS does not have its own module resolver.\n\n### Importing .tjs Files\n\nIn **Bun** (with the TJS plugin from `bunfig.toml`):\n\n```typescript\n// .tjs files are transpiled automatically on import\nimport { processOrder } from './orders.tjs'\nimport { validateUser } from './users.ts' // TS files also work\n```\n\nIn the **browser playground**, local modules are resolved from the playground's module store. Relative imports are looked up by name:\n\n```typescript\nimport { formatDate } from './date-utils' // resolves from saved modules\n```\n\nIn **production builds** (`tjs emit`), TJS transpiles `.tjs` → `.js`. Your bundler (esbuild, Rollup, etc.) handles resolution of the output `.js` files normally.\n\n### Importing JS/TS Libraries\n\nTJS files can import any JavaScript or TypeScript library. The imported code runs without TJS validation — it's just normal JS. Add a TJS wrapper at the boundary if you want type safety:\n\n```typescript\nimport { rawGeocode } from 'legacy-geo-pkg'\n\n// Wrap at the boundary — rawGeocode is unchecked, geocode validates its output\nfunction geocode(addr: ''): { lat: 0.0; lon: 0.0 } {\n return rawGeocode(addr)\n}\n```\n\n### CDN Imports\n\nURL imports work with any ESM CDN:\n\n```typescript\nimport lodash from 'https://esm.sh/lodash@4.17.21'\n```\n\n### Circular Dependencies\n\nTJS doesn't interfere with JS module loading. Circular imports work the same way as in standard ES modules — use lazy getters or late binding if you need to break cycles, exactly as you would in plain JS.\n\n### TypeScript Declaration Files (.d.ts)\n\nTJS can generate `.d.ts` files so TypeScript consumers can use TJS-authored libraries with autocomplete and tooltips:\n\n```bash\nbun src/cli/tjs.ts emit --dts src/lib.tjs -o dist/lib.js\n# Generates dist/lib.js + dist/lib.d.ts\n```\n\nFrom code:\n\n```typescript\nimport { tjs, generateDTS } from 'tjs-lang'\n\nconst result = tjs(source)\nconst dts = generateDTS(result, source)\n```\n\nFunctions get full type declarations. Classes, generics, and predicate-based types get `any`-based stubs that provide IDE hints (parameter names, object shapes) without generating false lint errors for types that TJS validates at runtime.\n\n---\n\n## TypeScript Compatibility\n\n### TS → TJS Converter\n\nConvert existing TypeScript:\n\n```bash\nbun src/cli/tjs.ts convert file.ts\n```\n\n```typescript\n// TypeScript\nfunction greet(name: string, age?: number): string { ... }\n\n// Converts to TJS\nfunction greet(name: '', age = 0): '' { ... }\n```\n\n### What Gets Converted\n\n| TypeScript | TJS |\n| -------------------------- | ----------------------- |\n| `name: string` | `name: ''` |\n| `age: number` | `age: 0.0` |\n| `flag: boolean` | `flag: false` |\n| `items: string[]` | `items: ['']` |\n| `age?: number` | `age: 0.0 \\| undefined` |\n| `private foo` | `#foo` |\n| `interface User` | `Type User` |\n| `type Status = 'a' \\| 'b'` | `Union(['a', 'b'])` |\n| `enum Color` | `Enum(...)` |\n\n> **Optional params:** TypeScript `x?: boolean` becomes TJS `x: false | undefined`.\n> This preserves the three-state semantics (`true` / `false` / `undefined`)\n> using a union type. The param is required but explicitly accepts `undefined`.\n\n---\n\n## Performance\n\n| Mode | Overhead | Use Case |\n| --------------- | -------------- | ---------------------------- |\n| `safety none` | **1.0x** | Metadata only, no validation |\n| `safety inputs` | **~1.15-1.3x** | Production |\n| `(!) unsafe` | **1.0x** | Hot paths |\n| `wasm {}` | **<1.0x** | Compute-heavy code |\n\n### Why ~1.15x, Not 25x\n\nMost validators interpret schemas at runtime (~25x overhead). TJS generates inline checks at transpile time:\n\n```typescript\n// Generated (JIT-friendly)\nif (\n typeof input !== 'object' ||\n input === null ||\n typeof input.name !== 'string' ||\n typeof input.age !== 'number'\n) {\n return { $error: true, message: 'Invalid input', path: 'fn.input' }\n}\n```\n\nNo schema interpretation. No object iteration. The JIT inlines these completely.\n\n---\n\n## Bare Assignments\n\nUppercase identifiers automatically get `const`:\n\n```typescript\nFoo = Type('test', 'example') // becomes: const Foo = Type(...)\nMyConfig = { debug: true } // becomes: const MyConfig = { ... }\n```\n\n---\n\n## Limitations\n\n### What TJS Doesn't Do\n\n- **No gradual typing** — types are all-or-nothing per function\n- **No complex type inference** — you provide examples, not constraints\n- **No type-level computation** — no conditional types, mapped types, etc.\n\n### What TJS Intentionally Avoids\n\n- Build steps beyond transpilation\n- External type checkers\n- Complex tooling configuration\n- Separation of types from runtime\n\n---\n\n## Troubleshooting\n\n### Common Transpilation Errors\n\n**\"Unexpected token\"** — Usually means TJS-specific syntax (`:` params, `:` returns, `Type`, `Generic`) wasn't recognized. Check:\n\n- Is the file being parsed as TJS (not plain JS)?\n- Are `Type`/`Generic`/`Union` declarations at the top level (not inside functions)?\n- Is the `: returnType` before the function body `{`?\n\n**\"Type is not defined\" / \"Generic is not defined\"** — These become `const Name = Type(...)` / `const Name = Generic(...)` after preprocessing. If you see this at runtime, the TJS runtime (`createRuntime()`) wasn't installed, or the file wasn't transpiled through TJS.\n\n**Signature test failures** — TJS runs your function with its example values at transpile time. If the function fails with its own examples, transpilation reports an error. Fix the function or choose better examples:\n\n```typescript\n// BAD: example 0 causes division by zero\nfunction inverse(x: 0): 0.0 {\n return 1 / x\n}\n\n// GOOD: example 1 works\nfunction inverse(x: 1): 0.0 {\n return 1 / x\n}\n```\n\n**Monadic errors instead of exceptions** — TJS validation returns `MonadicError` objects (with `$error: true`), it doesn't throw. Check with `isMonadicError(result)`, not `try/catch`:\n\n```typescript\nimport { isMonadicError } from 'tjs-lang'\n\nconst result = myFunction(badInput)\nif (isMonadicError(result)) {\n console.log(result.message) // \"type mismatch: expected string, got number\"\n}\n```\n\n### Debugging Type Checks\n\nEvery transpiled function has `.__tjs` metadata you can inspect:\n\n```typescript\nconsole.log(myFunction.__tjs)\n// { params: { name: { type: { kind: 'string' }, required: true } },\n// returns: { kind: 'string' } }\n```\n\nThe transpiled JS is readable — look at the generated code to see exactly what checks run:\n\n```bash\nbun src/cli/tjs.ts emit myfile.tjs # see the generated JS\n```\n\n### When to Use `!` (Unsafe)\n\nMark functions unsafe when:\n\n- The data source is already validated (e.g., internal helper called only from a validated wrapper)\n- You're in a hot loop and profiling shows the checks matter\n- You're calling a function millions of times with known-good data\n\nDon't use `!` at system boundaries (API handlers, user input, external data).\n\n---\n\n## Learn More\n\n- [AJS Documentation](DOCS-AJS.md) — The agent runtime\n- [Builder's Manifesto](MANIFESTO-BUILDER.md) — Why TJS is fun\n- [Enterprise Guide](MANIFESTO-ENTERPRISE.md) — Why TJS is safe\n- [Technical Context](CONTEXT.md) — Architecture deep dive\n"
203
215
  },
216
+ {
217
+ "title": "Playground Imports",
218
+ "filename": "playground-imports.md",
219
+ "path": "guides/playground-imports.md",
220
+ "section": "tjs",
221
+ "type": "docs",
222
+ "group": "docs",
223
+ "order": 50,
224
+ "text": "<!--{\"section\":\"tjs\",\"type\":\"docs\",\"group\":\"docs\",\"order\":50}-->\n\n# Playground Imports\n\nThe playground (https://tjs-platform.web.app) and the local dev server\nboth let you `import` external packages without a bundler or\n`node_modules`. There's no setup — just write the import. This page\ndocuments how it works and the CDN-hint syntax for power users.\n\n## Quick reference\n\n```javascript\n// Plain bare import — JSDelivr `/+esm` by default (works for ESM-native\n// and CJS packages alike; deps bundled inline)\nimport { tosi, elements } from 'tosijs'\nimport { debounce } from 'lodash-es'\nimport { marked } from 'marked'\n\n// Versioned: pin a specific release (or range)\nimport { tosi } from 'tosijs@1.6.1'\nimport { tosi } from 'tosijs@^1.6'\n\n// Subpath into a package\nimport { createRoot } from 'react-dom/client'\nimport { getAuth } from 'firebase/auth'\n\n// Full URL — passes through unchanged. Useful for arbitrary hosts:\n// your GitHub repo, a CodePen-style snippet, anything that serves ESM.\nimport { thing } from 'https://example.com/my-module.js'\nimport { x } from 'https://raw.githubusercontent.com/user/repo/main/file.js'\n\n// CDN hints (escape hatch when default routing picks the wrong CDN)\nimport { useState } from 'esmsh/react@18'\nimport { tosi } from 'jsdelivr/tosijs'\nimport { preact } from 'unpkg/preact'\nimport { whatever } from 'github/user/repo@v1.2/dist/index.js'\n```\n\n## How it works\n\n1. **Source rewrite at transpile time** (`demo/src/imports.ts`): bare\n specifiers like `'tosijs'` get rewritten to `'/tfs/tosijs'`. Relative\n paths (`'./foo'`), absolute paths (`'/foo'`), and full URLs\n (`'https://...'`) are left alone.\n2. **Service worker intercept** (`demo/src/tfs-worker.js`): the playground\n iframe is loaded from a same-origin `/iframe/<sessionId>` URL, so the\n TFS service worker controls all its fetches. When the iframe imports\n from `/tfs/<spec>`, the SW resolves it to a CDN URL, fetches the\n module, optionally rewrites the response body, and serves it back.\n3. **Browser ESM loader** does the rest — follows imports, dedupes by\n URL, evaluates modules.\n\n## Default CDN routing\n\nBy default, `/tfs/<spec>` resolves to JSDelivr's `/+esm` endpoint:\n\n```\nimport 'tosijs'\n → /tfs/tosijs\n → https://cdn.jsdelivr.net/npm/tosijs@latest/+esm\n```\n\nJSDelivr's `/+esm` returns a self-contained Rollup-bundled ESM module.\nIt works cleanly for ESM-native packages (tosijs, lodash-es) AND CJS\npackages (most things), inlines `process` polyfills, and bundles\ndependencies inline.\n\nThe bundle-inline behavior breaks one specific case: packages with peer\ndependencies that need to be the SAME instance across modules. React is\nthe canonical example — react-dom and your code both need to use the\nsame React, or hooks crash (`Cannot read properties of null (reading\n'useState')`). For these, the SW has a small allowlist that routes\nthrough esm.sh instead, which dedupes by URL.\n\nCurrent allowlist: `react`, `react-dom`. Easy to extend in the SW source.\n\n## CDN hints\n\nWhen you want to override the default routing, prefix the spec with a\nCDN name. The first path segment is treated as the hint:\n\n| Hint | Resolves to | Use when |\n| ----------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------- |\n| `jsdelivr/<spec>` | `https://cdn.jsdelivr.net/npm/<spec>/+esm` | Force JSDelivr (e.g. for a peer-dep package not on the allowlist) |\n| `esmsh/<spec>` | `https://esm.sh/<spec>` | Force esm.sh (e.g. for a different React-like package needing peer-dep dedup) |\n| `unpkg/<spec>` | `https://unpkg.com/<spec>?module` | UNPKG, returns ESM via `?module` |\n| `github/<user>/<repo>[@ref]/<path>` | `https://esm.sh/gh/<user>/<repo>[@ref]/<path>` | Load directly from a GitHub repo (esm.sh handles fetching + transformation) |\n\nThe hint name occupies what would normally be the package name slot, so\nnamed imports work normally:\n\n```javascript\nimport { tosi, elements } from 'jsdelivr/tosijs@1.6.1'\nimport { useState } from 'esmsh/react'\n```\n\nWhy `esmsh` and not `esm`: `esm` is a popular npm package (the legacy\nESM loader for Node), and we don't want to clash with `import 'esm'`.\n`jsdelivr`, `unpkg`, and `github` aren't taken as bare top-level npm\npackages.\n\n## Full URLs\n\nAnything starting with `http://` or `https://` passes through the\nrewriter unchanged. Use this for one-off cases:\n\n```javascript\n// Your own deployed module\nimport { thing } from 'https://my.com/module.js'\n\n// A GitHub raw URL (only works if the file is already valid ESM —\n// raw GitHub doesn't transform CJS or resolve bare specifiers; for\n// that use the `github/` hint, which routes through esm.sh)\nimport { x } from 'https://raw.githubusercontent.com/me/repo/main/dist/index.mjs'\n\n// Any other CDN\nimport { y } from 'https://cdn.example.com/foo@1.0.0/+esm'\n```\n\n## What lives where\n\n- **`demo/src/imports.ts`** — `rewriteImports()` (rewrites at transpile\n time) and `registerIframeContent()` (postMessage handshake)\n- **`demo/src/tfs-worker.js`** — the service worker: serves the iframe\n HTML at `/iframe/<id>`, proxies `/tfs/<spec>` to the appropriate CDN,\n rewrites response bodies for esm.sh dedup\n- **`demo/src/tjs-playground.ts`** / **`demo/src/ts-playground.ts`** —\n generate `iframeDoc`, register it with the SW, set `iframe.src`\n\n## Future: virtual modules\n\nThe SW architecture is set up to also serve user-saved modules at\n`/vmod/<path>` (or similar). This will let you \"save\" a snippet to a\nvirtual endpoint and `import` from it elsewhere — the b8rjs pattern.\nTracked in `TODO.md` under playground IDE features.\n\n## Cache and debugging\n\n- **Status**: GET `/tfs/__status` (in a new tab) — returns JSON with the\n SW version, the CDN routing config, the cached URLs, and the active\n iframe sessions\n- **Clear**: GET `/tfs/__clear` — drops the cached responses\n\nThe SW caches CDN responses in a named `Cache` (`tfs-v4-mixed-cdn`).\nBumping `SW_VERSION` in `tfs-worker.js` automatically clears old caches\non activate.\n"
225
+ },
204
226
  {
205
227
  "title": "Starfield",
206
228
  "filename": "wasm-starfield.md",
@@ -441,6 +463,18 @@
441
463
  "language": "tjs",
442
464
  "description": "Unbundled todo app - runs directly in browser, no build step."
443
465
  },
466
+ {
467
+ "title": "CDN Hints (overriding the default)",
468
+ "filename": "cdn-hints.md",
469
+ "path": "guides/examples/tjs/cdn-hints.md",
470
+ "section": "tjs",
471
+ "type": "example",
472
+ "group": "unbundled",
473
+ "order": 5,
474
+ "code": "TjsCompat\n/**\n * # Per-import CDN hints\n *\n * The first path segment of the import spec selects the CDN:\n *\n * jsdelivr/<spec> → JSDelivr `/+esm` (the default)\n * esmsh/<spec> → esm.sh (peer-dep dedup, e.g. React)\n * unpkg/<spec> → UNPKG with ?module\n * github/<user>/<repo>/<path> → esm.sh's /gh/ route\n *\n * No hint = default routing (JSDelivr, with esm.sh allowlist for React).\n *\n * For full URLs (your own host, raw.githubusercontent.com, etc.) just\n * write the URL — it's left untouched.\n */\n\n// Default routing: JSDelivr\nimport { tosi, elements } from 'tosijs'\n\n// Force a specific CDN\nimport { html, render } from 'unpkg/lit'\nimport _ from 'jsdelivr/lodash-es'\n\n// Pin a version\nimport { format } from 'jsdelivr/date-fns@3.0.0'\n\n// Load straight from a GitHub repo (esm.sh handles fetching/transform)\n// Format: github/<user>/<repo>[@ref]/<path>\n// (Comment out — the example repo is illustrative)\n// import { thing } from 'github/preactjs/preact@10.22.0/dist/preact.module.js'\n\n// Or, for the truly DIY case, paste the full URL\n// import { x } from 'https://my.com/dist/index.js'\n\nconst { div, h1, button } = elements\n\nconst state = tosi({\n count: 0,\n inc() { state.count++ },\n})\n\ndocument.body.append(\n div(\n h1({ bindText: () => `Count: ${state.count}` }),\n button({ onClick: state.inc }, '+1')\n )\n)\n\n// date-fns (loaded via JSDelivr hint) used directly\nconsole.log('Today:', format(new Date(), 'yyyy-MM-dd'))",
475
+ "language": "tjs",
476
+ "description": "By default the playground resolves bare imports through JSDelivr's `/+esm` bundles. When you need a specific CDN — to test an unreleased build, work around a transform issue, or load a module straight from GitHub — prefix the spec with a CDN hint."
477
+ },
444
478
  {
445
479
  "title": "LLM with Tool",
446
480
  "filename": "llm-with-tool.md",
@@ -1219,7 +1253,7 @@
1219
1253
  "title": "CLAUDE.md",
1220
1254
  "filename": "CLAUDE.md",
1221
1255
  "path": "CLAUDE.md",
1222
- "text": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\n**tjs-lang** (npm: `tjs-lang`) is a typed JavaScript platform — a language, runtime, and toolchain that transpiles TypeScript and TJS to JavaScript with runtime type validation, inline WASM, monadic errors, and safe eval. It also includes AJS, a gas-metered VM for executing untrusted agent code in any JavaScript environment.\n\n**Three pillars:**\n\n- **TJS** — TypeScript-like syntax where types are examples that survive to runtime as contracts, documentation, and tests. Transpiles TS → TJS → JS in a single fast pass.\n- **AJS** — Agent language that compiles to JSON AST for safe, sandboxed execution with fuel limits and injected capabilities. Code travels to data.\n- **Toolchain** — Compresses transpilation, linting, testing, and documentation generation into one pass. Includes inline WASM with SIMD, polymorphic dispatch, local class extensions, and a browser-based playground.\n\n> **TJS syntax is NOT TypeScript.** Full reference: [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md). The single most common LLM mistake is treating `function foo(x: 'default')` as a TypeScript string-literal type. It is _not_ — the colon value is an **example**, and `'default'` widens to `string`. See the syntax doc before writing or modifying TJS source.\n\n## Common Commands\n\n```bash\n# Development\nbun run format # ESLint fix + Prettier\nbun run test:fast # Core tests (skips LLM & benchmarks)\nbun run make # Full build (clean, format, grammars, tsc, esbuild)\nbun run dev # Development server with file watcher\nbun run start # Build demo + start dev server\nbun run latest # Clean reinstall (rm node_modules + bun install)\n\n# Testing (framework: bun:test — describe/it/expect)\nbun test # Full test suite\nbun test src/path/to/file.test.ts # Single test file\nbun test --test-name-pattern \"pattern\" # Run tests matching pattern\nSKIP_LLM_TESTS=1 bun test # Skip LLM integration tests\nbun test --coverage # With coverage report\n\n# Efficient test debugging - capture once, query multiple times\nbun test 2>&1 | tee /tmp/test-results.txt | tail -20 # Run and save\ngrep -E \"^\\(fail\\)\" /tmp/test-results.txt # List failures\ngrep -A10 \"test name\" /tmp/test-results.txt # See specific error\n\n# CLI tools\nbun src/cli/tjs.ts check <file> # Parse and type check TJS file\nbun src/cli/tjs.ts run <file> # Transpile and execute\nbun src/cli/tjs.ts types <file> # Output type metadata as JSON\nbun src/cli/tjs.ts emit <file> # Output transpiled JavaScript\nbun src/cli/tjs.ts convert <file> # Convert TypeScript to TJS (--emit-tjs) or JS\nbun src/cli/tjs.ts test <file> # Run inline tests in a TJS file\n\n# Type checking & other\nbun run typecheck # tsc --noEmit (type check without emitting)\nbun run test:llm # LM Studio integration tests\nbun run bench # Vector search benchmarks\nbun run docs # Generate documentation\n\n# Build standalone CLI binaries\nbun run build:cli # Compiles tjs + tjsx to dist/\n\n# Compatibility testing (transpile popular TS libraries with fromTS)\nbun scripts/compat-zod.ts # Zod validation library\nbun scripts/compat-effect.ts # Effect (HKTs, intersections)\nbun scripts/compat-radash.ts # Radash utilities\nbun scripts/compat-superstruct.ts # Superstruct validation\nbun scripts/compat-ts-pattern.ts # ts-pattern matching\nbun scripts/compat-kysely.ts # Kysely SQL builder\n\n# Deployment (Firebase)\nbun run deploy # Build demo + deploy functions + hosting\nbun run deploy:hosting # Hosting only (serves from .demo/)\nbun run functions:deploy # Cloud functions only\nbun run functions:serve # Local functions emulator\n```\n\n## Architecture\n\n### Two-Layer Design\n\n1. **Builder Layer** (`src/builder.ts`): Fluent API that constructs AST nodes. Contains no execution logic.\n2. **Runtime Layer** (`src/vm/runtime.ts`): Executes AST nodes. Contains all atom implementations (~3024 lines, security-critical).\n\n### Key Source Files\n\n- `src/index.ts` - Main entry, re-exports everything\n- `src/vm/runtime.ts` - All atom implementations, expression evaluation, fuel charging (~3024 lines, security-critical)\n- `src/vm/vm.ts` - AgentVM class (~247 lines)\n- `src/vm/atoms/batteries.ts` - Battery atoms (vector search, LLM, store operations)\n- `src/builder.ts` - TypedBuilder fluent API (~757 lines / ~19KB)\n- `src/lang/parser.ts` - TJS parser with colon shorthand, unsafe markers, return type extraction\n- `src/lang/parser-transforms.ts` - Type, Generic, and FunctionPredicate block/function form transforms\n- `src/lang/emitters/ast.ts` - Emits Agent99 AST from parsed source\n- `src/lang/emitters/js.ts` - Emits JavaScript with `__tjs` metadata\n- `src/lang/emitters/from-ts.ts` - TypeScript to TJS/JS transpiler with class metadata extraction\n- `src/lang/emitters/dts.ts` - .d.ts declaration file generator from TJS transpilation results\n- `src/lang/inference.ts` - Type inference from example values\n- `src/lang/json-schema.ts` - JSON Schema generation from TypeDescriptors and example values\n- `src/lang/linter.ts` - Static analysis (unused vars, unreachable code, no-explicit-new)\n- `src/lang/runtime.ts` - TJS runtime (monadic errors, type checking, wrapClass)\n- `src/lang/wasm.ts` - WASM compiler (opcodes, disassembler, bytecode generation)\n- `src/types/` - Type system definitions (Type.ts, Generic.ts)\n- `src/transpiler/` - AJS transpiler (source → AST)\n- `src/batteries/` - LM Studio integration (lazy init, model audit, vector search)\n- `src/store/` - Store implementations for persistence\n- `src/rbac/` - Role-based access control\n- `src/use-cases/` - Integration tests and real-world examples (28 test files)\n- `src/cli/tjs.ts` - CLI tool for check/run/types/emit/convert/test commands\n- `src/cli/tjsx.ts` - JSX/component runner\n- `src/cli/playground.ts` - Local playground server\n- `src/cli/create-app.ts` - Project scaffolding tool\n\n### Core APIs\n\n```typescript\n// Language\najs`...` // Parse AJS to AST\ntjs`...` // Parse TypeScript variant with type metadata\ntranspile(source, options) // Full transpilation with signature extraction\ncreateAgent(source, vm) // Creates callable agent\n\n// VM\nconst vm = new AgentVM(customAtoms)\nawait vm.run(ast, args, { fuel, capabilities, timeoutMs, trace })\n\n// Builder\nAgent.take(schema).varSet(...).httpFetch(...).return(schema)\nvm.Agent // Builder with custom atoms included\n\n// JSON Schema\nType('user', { name: '', age: 0 }).toJSONSchema() // → JSON Schema object\nType('user', { name: '', age: 0 }).strip(value) // → strip extra fields\nfunctionMetaToJSONSchema(fn.__tjs) // → { input, output } schemas\n\n// Error History (on by default, zero cost on happy path)\n__tjs.errors() // → recent MonadicErrors (ring buffer, max 64)\n__tjs.clearErrors() // → returns and clears\n__tjs.getErrorCount() // → total since last clear\n```\n\n### Package Entry Points\n\n```typescript\nimport { Agent, AgentVM, ajs, tjs } from 'tjs-lang' // Main entry\nimport { Eval, SafeFunction } from 'tjs-lang/eval' // Safe eval utilities\nimport { tjs, transpile } from 'tjs-lang/lang' // Language tools only\nimport { fromTS } from 'tjs-lang/lang/from-ts' // TypeScript transpilation\n```\n\n### Transpiler Chain (TS → TJS → JS)\n\nTJS supports transpiling TypeScript to JavaScript with runtime type validation. The pipeline has two distinct, independently testable steps:\n\n**Step 1: TypeScript → TJS** (`fromTS`)\n\n```typescript\nimport { fromTS } from 'tjs-lang/lang/from-ts'\n\nconst tsSource = `\nfunction greet(name: string): string {\n return \\`Hello, \\${name}!\\`\n}\n`\n\nconst result = fromTS(tsSource, { emitTJS: true })\n// result.code contains TJS:\n// function greet(name: ''): '' {\n// return \\`Hello, \\${name}!\\`\n// }\n```\n\n**Step 2: TJS → JavaScript** (`tjs`)\n\n```typescript\nimport { tjs } from 'tjs-lang/lang'\n\nconst tjsSource = `\nfunction greet(name: ''): '' {\n return \\`Hello, \\${name}!\\`\n}\n`\n\nconst jsResult = tjs(tjsSource)\n// jsResult.code contains JavaScript with __tjs metadata for runtime validation\n```\n\n**Full Chain Example:**\n\n```typescript\nimport { fromTS } from 'tjs-lang/lang/from-ts'\nimport { tjs } from 'tjs-lang/lang'\n\n// TypeScript source with type annotations\nconst tsSource = `\nfunction add(a: number, b: number): number {\n return a + b\n}\n`\n\n// Step 1: TS → TJS\nconst tjsResult = fromTS(tsSource, { emitTJS: true })\n\n// Step 2: TJS → JS (with runtime validation)\nconst jsCode = tjs(tjsResult.code)\n\n// Execute the result\nconst fn = new Function('__tjs', jsCode + '; return add')(__tjs_runtime)\nfn(1, 2) // Returns 3\nfn('a', 'b') // Returns { error: 'type mismatch', ... }\n```\n\n**Design Notes:**\n\n- The two steps are intentionally separate for tree-shaking (TS support is optional)\n- `fromTS` lives in a separate entry point (`tosijs/lang/from-ts`)\n- Import only what you need to keep bundle size minimal\n- Each step is independently testable (see `src/lang/codegen.test.ts`)\n- Constrained generics (`<T extends { id: number }>`) use the constraint as the example value instead of `any`\n- Generic defaults (`<T = string>`) use the default as the example value\n- Unconstrained generics (`<T>`) degrade to `any` — there's no information to use\n\n### Security Model\n\n- **Capability-based**: VM has zero IO by default; inject `fetch`, `store`, `llm` via capabilities\n- **Fuel metering**: Every atom has a cost; execution stops when fuel exhausted\n- **Timeout enforcement**: Default `fuel × 10ms`; explicit `timeoutMs` overrides\n- **Monadic errors**: Errors wrapped in `AgentError` (VM) / `MonadicError` (TJS), not thrown (prevents exception exploits). Use `isMonadicError()` to check — `isError()` is deprecated\n- **Expression sandboxing**: ExprNode AST evaluation, blocked prototype access\n\n### Expression Evaluation\n\nExpressions use AST nodes (`$expr`), not strings:\n\n```typescript\n{ $expr: 'binary', op: '+', left: {...}, right: {...} }\n{ $expr: 'ident', name: 'varName' }\n{ $expr: 'member', object: {...}, property: 'foo' }\n```\n\nEach node costs 0.01 fuel. Forbidden: function calls, `new`, `this`, `__proto__`, `constructor`.\n\n## AJS Expression Gotchas\n\nAJS expressions behave differently from JavaScript in several important ways:\n\n- **Null member access is safe by default**: `null.foo.bar` returns `undefined` silently (uses `?.` semantics internally). This differs from JavaScript which would throw `TypeError`.\n- **No computed member access with variables**: `items[i]` fails at transpile time with \"Computed member access with variables not yet supported\". Literal indices work (`items[0]`, `obj[\"key\"]`). Workaround: use `.map`/`.reduce` atoms instead.\n- **Unknown atom errors**: When an atom doesn't exist, the error is `\"Unknown Atom: <name>\"` with no listing of available atoms.\n- **TJS parameter syntax is NOT TypeScript**: `function foo(x: 'default')` means \"required param, example value 'default'\" — not a TypeScript string literal type. LLMs consistently generate `function foo(x: string)` which is wrong. The colon value is an _example_, not a _type annotation_.\n\n## Testing Strategy\n\n- Unit tests alongside source files (`*.test.ts`)\n- Integration tests in `src/use-cases/` (RAG, orchestration, malicious actors)\n- Security tests in `src/use-cases/malicious-actor.test.ts`\n- Language tests split across 14 files in `src/lang/` (lang.test.ts, features.test.ts, codegen.test.ts, parser.test.ts, from-ts.test.ts, wasm.test.ts, etc.)\n\nCoverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ overall.\n\n**Bug fix rule:** Always create a reproduction test case before fixing a bug.\n\n## Key Patterns\n\n### Adding a New Atom\n\n1. Define with `defineAtom(opCode, inputSchema, outputSchema, implementation, { cost, timeoutMs, docs })`\n2. Add to `src/vm/atoms/` and export from `src/vm/atoms/index.ts`\n3. Add tests\n4. Run `bun run test:fast`\n\n**Atom implementation notes:**\n\n- `cost` can be static number or dynamic: `(input, ctx) => number`\n- `timeoutMs` defaults to 1000ms; use `0` for no timeout (e.g., `seq`)\n- Atoms are always async; fuel deduction is automatic in the `exec` wrapper\n\n### Debugging Agents\n\nEnable tracing: `vm.run(ast, args, { trace: true })` returns `TraceEvent[]` with execution path, fuel consumption, and state changes.\n\n### Custom Atoms Must\n\n- Be non-blocking (no synchronous CPU-heavy work)\n- Respect `ctx.signal` for cancellation\n- Access IO only via `ctx.capabilities`\n\n### Value Resolution\n\nThe `resolveValue()` function handles multiple input patterns:\n\n- `{ $kind: 'arg', path: 'varName' }` → lookup in `ctx.args`\n- `{ $expr: ... }` → evaluate ExprNode via `evaluateExpr()`\n- String with dots `'obj.foo.bar'` → traverse state with forbidden property checks\n- Bare strings → lookup in state, else return literal\n\n### Monadic Error Flow\n\nWhen `ctx.error` is set, subsequent atoms in a `seq` skip execution. Errors are wrapped in `AgentError`, not thrown. This prevents exception-based exploits.\n\n### TJS Syntax Reference\n\nFull syntax documentation is in [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md). Key concepts:\n\n- **Colon shorthand**: `function foo(x: 'hello')` — colon value is an _example_, not a type. This is the most common LLM mistake.\n- **Numeric narrowing**: `3.14` = float, `42` = integer, `+0` = non-negative integer\n- **Return types**: `function add(a: 0, b: 0): 0 { ... }` (colon syntax, same as TypeScript)\n- **Safety markers**: `!` = unsafe (skip validation), `?` = safe (explicit validation)\n- **Mode defaults**: Native TJS has all modes ON by default (`TjsEquals`, `TjsClass`, `TjsDate`, `TjsNoeval`, `TjsNoVar`, `TjsStandard`). TS-originated code (`fromTS`) and AJS/VM code get modes OFF. `TjsCompat` directive explicitly disables all modes. `TjsStrict` enables all modes (useful for TS-originated code opting in).\n- **Bang access**: `x!.foo` — returns MonadicError if `x` is null/undefined, otherwise bare `x.foo`. Chains propagate: `x!.foo!.bar`.\n- **Type/Generic/FunctionPredicate**: Three declaration forms for runtime type predicates\n- **`const!`**: Compile-time immutability, zero runtime cost\n- **Equality**: `==`/`!=` = structural equality by default in native TJS (via `Is`/`IsNot`), `===`/`!==` = identity\n- **Polymorphic functions**: Multiple same-name declarations merge into arity/type dispatcher\n- **`extend` blocks**: Local class extensions without prototype pollution\n- **WASM blocks**: Inline WebAssembly compiled at transpile time, with SIMD intrinsics and `wasmBuffer()` zero-copy arrays\n- **`@tjs` annotations**: `/* @tjs ... */` comments in TS files enrich TJS output\n\n#### Runtime Configuration\n\n```typescript\nimport { configure } from 'tjs-lang/lang'\n\nconfigure({ logTypeErrors: true }) // Log type errors to console\nconfigure({ throwTypeErrors: true }) // Throw instead of return (debugging)\nconfigure({ callStacks: true }) // Track call stacks in errors (~2x overhead)\nconfigure({ trackErrors: false }) // Disable error history (on by default)\n```\n\n#### Error History\n\nType errors are tracked in a ring buffer (on by default, zero cost on happy path):\n\n```typescript\n__tjs.errors() // → recent MonadicErrors (newest last, max 64)\n__tjs.clearErrors() // → returns and clears the buffer\n__tjs.getErrorCount() // → total since last clear (survives buffer wrap)\n```\n\nUse for debugging (find silent failures), testing (`clearErrors()` → run → check), and monitoring.\n\n#### Standalone JS Output\n\nEmitted `.js` files work without any runtime setup. Each file includes an inline\nminimal runtime as fallback — only the functions actually used are included (~500\nbytes for a basic validated function). If `globalThis.__tjs` exists (shared runtime),\nit's used instead.\n\n## Dependencies\n\nRuntime (shipped): `acorn` (JS parser, ~30KB), `tosijs-schema` (validation, ~5KB). Both have zero transitive dependencies.\n\n## Forbidden Properties (Security)\n\nThe following property names are blocked in expression evaluation to prevent prototype pollution:\n\n- `__proto__`, `constructor`, `prototype`\n\nThese are hardcoded in `runtime.ts` and checked during member access in `evaluateExpr()`.\n\n## Batteries System\n\nThe batteries (`src/batteries/`) provide zero-config local AI development:\n\n- **Lazy initialization**: First import audits LM Studio models (cached 24 hours)\n- **HTTPS detection**: Blocks local LLM calls from HTTPS contexts (security)\n- **Capabilities interface**: `fetch`, `store` (KV + vector), `llmBattery` (predict/embed)\n\nRegister battery atoms: `new AgentVM(batteryAtoms)` then pass `{ capabilities: batteries }` to `run()`.\n\n### Capability Key Naming\n\nThe base `Capabilities` interface (`runtime.ts`) uses `llm` with `{ predict, embed? }`, but the battery atoms access capabilities via different keys:\n\n| Capability key | Used by | Contains |\n| -------------- | -------------------------------------------------------- | -------------------------------------------- |\n| `llmBattery` | `llmPredictBattery`, `llmVision` | Full `LLMCapability` (`predict` + `embed`) |\n| `vector` | `storeVectorize` | Just `{ embed }` (extracted from llmBattery) |\n| `store` | `storeSearch`, `storeCreateCollection`, `storeVectorAdd` | KV + vector store ops |\n\nBoth `llmBattery` and `vector` can be `undefined`/`null` if LM Studio isn't available or HTTPS is detected.\n\n### Battery Atom Return Types\n\n- **`llmPredictBattery`**: Returns OpenAI message format `{ role?, content?, tool_calls? }` — NOT a plain string\n- **`storeVectorize`**: Returns `number[]` (embedding vector)\n- **`storeSearch`**: Returns `any[]` (matched documents)\n\n## Development Configuration\n\n### Bun Plugin\n\n`bunfig.toml` preloads `src/bun-plugin/tjs-plugin.ts` which enables importing `.tjs` files directly in bun (transpiled on-the-fly). It also aliases `tjs-lang` to `./src/index.ts` for local development, so `import { tjs } from 'tjs-lang'` resolves to the source tree without needing `npm link` or a published package.\n\n### Code Style\n\n- **Prettier**: Single quotes, no semicolons, 2-space indentation, 80 char width, es5 trailing commas\n- Prefix unused variables with `_` (enforced by ESLint: `argsIgnorePattern: '^_'`)\n- `any` types are allowed (`@typescript-eslint/no-explicit-any: 0`)\n- Module type is ESM (`\"type\": \"module\"` in package.json)\n- Build output goes to `dist/` (declaration files only via `tsconfig.build.json`, bundles via `scripts/build.ts`)\n- Run `bun run format` before committing (ESLint fix + Prettier)\n\n### Firebase Deployment\n\nThe playground is hosted on Firebase (`tjs-platform.web.app`). Demo build output goes to `.demo/` (gitignored) which is the Firebase hosting root. Cloud Functions live in `functions/` with their own build process (`functions/src/*.tjs` → transpile → bundle). Firebase config: `firebase.json`, `.firebaserc`, `firestore.rules`.\n\nThe `docs/` directory contains real documentation (markdown), not build artifacts. See `docs/README.md` for the documentation index.\n\n### Additional Directories\n\n- `tjs-src/` — TJS runtime written in TJS itself (self-hosting)\n- `guides/` — Usage patterns, benchmarks, examples (`patterns.md`, `benchmarks.md`, `tjs-examples.md`)\n- `examples/` — Standalone TJS example files (`hello.tjs`, `datetime.tjs`, `generic-demo.tjs`)\n- `editors/` — Syntax highlighting for Monaco, CodeMirror, Ace, VSCode\n\n### Additional Documentation\n\n- `DOCS-TJS.md` — TJS language guide\n- `DOCS-AJS.md` — AJS runtime guide\n- `TJS-FOR-JS.md` — TJS guide for JavaScript developers (syntax differences, gotchas)\n- `TJS-FOR-TS.md` — TJS guide for TypeScript developers (migration, interop)\n- `CONTEXT.md` — Architecture deep dive\n- `AGENTS.md` — Agent workflow instructions (session-completion checklist, push-before-done rule)\n- `TODO.md` — Open work, organized by area; move items to the **Completed** section when done\n- `PLAN.md` — Roadmap\n\n### Tracking Work\n\nWork is tracked in plain markdown — no external issue tracker. Open items live in `TODO.md` (organized by area). When you start a task, find or add the relevant entry; when you finish, check the box and (for substantial work) move it to the Completed section with a short note.\n\n### Landing the Plane (Session Completion Checklist)\n\nWhen ending a work session that touched code, complete **all** steps below in order. Canonical version lives in `AGENTS.md`.\n\n1. **Update `TODO.md`** — check off completed items, add follow-ups for anything left undone, note blockers.\n2. **Run quality gates** — if code changed: `bun run format`, `bun run typecheck`, `bun run test:fast` (or `bun test` for full suite).\n3. **Commit** — focused commits with clear messages. Don't bundle unrelated changes.\n4. **Push to remote** — mandatory:\n ```bash\n git pull --rebase\n git push\n git status # MUST show \"up to date with 'origin/...'\"\n ```\n5. **Clean up** — clear stale stashes, prune merged remote branches if appropriate.\n6. **Verify** — working tree clean AND branch up to date with origin.\n7. **Hand off** — leave a brief summary so the next session can pick up cold.\n\n**Hard rules:**\n\n- Work is NOT complete until `git push` succeeds.\n- Never stop before pushing — leaving work stranded locally is leaving it lost.\n- Never say \"ready to push when you are\" — push it yourself.\n- If push fails, resolve the cause (rebase conflicts, hook failures, auth) and retry until it succeeds.\n- Never `--no-verify` to bypass hooks. Fix the underlying issue.\n\n### Known Gotcha: `tjs()` Returns an Object, Not a String\n\n`tjs(source)` returns `{ code, types, metadata, testResults, ... }`. Use `.code` to get the transpiled JavaScript string. This is a common mistake.\n\n### Running Emitted TJS Code\n\nEmitted JS works standalone — no setup required. Each file includes an inline\nruntime fallback. If you want the shared runtime (e.g. for `isMonadicError` to\nwork across files), install it first:\n\n```typescript\nimport { installRuntime, createRuntime } from '../lang/runtime'\ninstallRuntime() // or: globalThis.__tjs = createRuntime()\n\nconst fn = new Function(result.code + '\\nreturn fnName')()\nfn('valid') // works\nfn(42) // returns MonadicError (not thrown)\n```\n"
1256
+ "text": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## Project Overview\n\n**tjs-lang** (npm: `tjs-lang`) is a typed JavaScript platform — a language, runtime, and toolchain that transpiles TypeScript and TJS to JavaScript with runtime type validation, inline WASM, monadic errors, and safe eval. It also includes AJS, a gas-metered VM for executing untrusted agent code in any JavaScript environment.\n\n**Three pillars:**\n\n- **TJS** — TypeScript-like syntax where types are examples that survive to runtime as contracts, documentation, and tests. Transpiles TS → TJS → JS in a single fast pass.\n- **AJS** — Agent language that compiles to JSON AST for safe, sandboxed execution with fuel limits and injected capabilities. Code travels to data.\n- **Toolchain** — Compresses transpilation, linting, testing, and documentation generation into one pass. Includes inline WASM with SIMD, polymorphic dispatch, local class extensions, and a browser-based playground.\n\n> **TJS syntax is NOT TypeScript.** Full reference: [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md). The single most common LLM mistake is treating `function foo(x: 'default')` as a TypeScript string-literal type. It is _not_ — the colon value is an **example**, and `'default'` widens to `string`. See the syntax doc before writing or modifying TJS source.\n\n## Common Commands\n\n```bash\n# Development\nbun run format # ESLint fix + Prettier\nbun run test:fast # Core tests (skips LLM & benchmarks)\nbun run make # Full build (clean, format, grammars, tsc, esbuild)\nbun run dev # Development server with file watcher\nbun run start # Build demo + start dev server\nbun run latest # Clean reinstall (rm node_modules + bun install)\n\n# Testing (framework: bun:test — describe/it/expect)\nbun test # Full test suite\nbun test src/path/to/file.test.ts # Single test file\nbun test --test-name-pattern \"pattern\" # Run tests matching pattern\nSKIP_LLM_TESTS=1 bun test # Skip LLM integration tests\nbun test --coverage # With coverage report\n\n# Efficient test debugging - capture once, query multiple times\nbun test 2>&1 | tee /tmp/test-results.txt | tail -20 # Run and save\ngrep -E \"^\\(fail\\)\" /tmp/test-results.txt # List failures\ngrep -A10 \"test name\" /tmp/test-results.txt # See specific error\n\n# CLI tools\nbun src/cli/tjs.ts check <file> # Parse and type check TJS file\nbun src/cli/tjs.ts run <file> # Transpile and execute\nbun src/cli/tjs.ts types <file> # Output type metadata as JSON\nbun src/cli/tjs.ts emit <file> # Output transpiled JavaScript\nbun src/cli/tjs.ts convert <file> # Convert TypeScript to TJS (--emit-tjs) or JS\nbun src/cli/tjs.ts test <file> # Run inline tests in a TJS file\n\n# Type checking & other\nbun run typecheck # tsc --noEmit (type check without emitting)\nbun run test:llm # LM Studio integration tests\nbun run bench # Vector search benchmarks\nbun run docs # Generate documentation\n\n# Build standalone CLI binaries\nbun run build:cli # Compiles tjs + tjsx to dist/\n\n# Compatibility testing — see scripts/compat-*.ts (zod, effect, radash, superstruct, ts-pattern, kysely)\n\n# Deployment (Firebase)\nbun run deploy # Build demo + deploy functions + hosting\nbun run deploy:hosting # Hosting only (serves from .demo/)\nbun run functions:deploy # Cloud functions only\nbun run functions:serve # Local functions emulator\n```\n\n## Architecture\n\n### Two-Layer Design\n\n1. **Builder Layer** (`src/builder.ts`): Fluent API that constructs AST nodes. Contains no execution logic.\n2. **Runtime Layer** (`src/vm/runtime.ts`): Executes AST nodes. Contains all atom implementations (~3024 lines, security-critical).\n\n### Key Source Files\n\n- `src/index.ts` - Main entry, re-exports everything\n- `src/vm/runtime.ts` - All atom implementations, expression evaluation, fuel charging (~3024 lines, security-critical)\n- `src/vm/vm.ts` - AgentVM class (~247 lines)\n- `src/vm/atoms/batteries.ts` - Battery atoms (vector search, LLM, store operations)\n- `src/builder.ts` - TypedBuilder fluent API (~757 lines / ~19KB)\n- `src/lang/parser.ts` - TJS parser with colon shorthand, unsafe markers, return type extraction\n- `src/lang/parser-transforms.ts` - Type, Generic, and FunctionPredicate block/function form transforms\n- `src/lang/emitters/ast.ts` - Emits Agent99 AST from parsed source\n- `src/lang/emitters/js.ts` - Emits JavaScript with `__tjs` metadata\n- `src/lang/emitters/from-ts.ts` - TypeScript to TJS/JS transpiler with class metadata extraction\n- `src/lang/emitters/dts.ts` - .d.ts declaration file generator from TJS transpilation results\n- `src/lang/inference.ts` - Type inference from example values\n- `src/lang/json-schema.ts` - JSON Schema generation from TypeDescriptors and example values\n- `src/lang/linter.ts` - Static analysis (unused vars, unreachable code, no-explicit-new)\n- `src/lang/runtime.ts` - TJS runtime (monadic errors, type checking, wrapClass)\n- `src/lang/wasm.ts` - WASM compiler (opcodes, disassembler, bytecode generation)\n- `src/types/` - Type system definitions (Type.ts, Generic.ts)\n- `src/transpiler/` - AJS transpiler (source → AST)\n- `src/batteries/` - LM Studio integration (lazy init, model audit, vector search)\n- `src/store/` - Store implementations for persistence\n- `src/rbac/` - Role-based access control\n- `src/use-cases/` - Integration tests and real-world examples (30 test files)\n- `src/cli/tjs.ts` - CLI tool for check/run/types/emit/convert/test commands\n- `src/cli/tjsx.ts` - JSX/component runner\n- `src/cli/playground.ts` - Local playground server\n- `src/cli/create-app.ts` - Project scaffolding tool\n\n### Core APIs\n\n```typescript\n// Language\najs`...` // Parse AJS to AST\ntjs`...` // Parse TypeScript variant with type metadata\ntranspile(source, options) // Full transpilation with signature extraction\ncreateAgent(source, vm) // Creates callable agent\n\n// VM\nconst vm = new AgentVM(customAtoms)\nawait vm.run(ast, args, { fuel, capabilities, timeoutMs, trace })\n\n// Builder\nAgent.take(schema).varSet(...).httpFetch(...).return(schema)\nvm.Agent // Builder with custom atoms included\n\n// JSON Schema\nType('user', { name: '', age: 0 }).toJSONSchema() // → JSON Schema object\nType('user', { name: '', age: 0 }).strip(value) // → strip extra fields\nfunctionMetaToJSONSchema(fn.__tjs) // → { input, output } schemas\n\n// Error History (on by default, zero cost on happy path)\n__tjs.errors() // → recent MonadicErrors (ring buffer, max 64)\n__tjs.clearErrors() // → returns and clears\n__tjs.getErrorCount() // → total since last clear\n```\n\n### Package Entry Points\n\n```typescript\nimport { Agent, AgentVM, ajs, tjs } from 'tjs-lang' // Main entry\nimport { Eval, SafeFunction } from 'tjs-lang/eval' // Safe eval utilities\nimport { tjs, transpile } from 'tjs-lang/lang' // Language tools only\nimport { fromTS } from 'tjs-lang/lang/from-ts' // TypeScript transpilation\nimport { AgentVM } from 'tjs-lang/vm' // VM only (smaller bundle)\nimport { batteryAtoms } from 'tjs-lang/batteries' // LM Studio batteries\n// Editor integrations: 'tjs-lang/editors/monaco', '/codemirror', '/ace'\n```\n\n### Transpiler Chain (TS → TJS → JS)\n\nTJS supports transpiling TypeScript to JavaScript with runtime type validation. The pipeline has two distinct, independently testable steps:\n\n**Step 1: TypeScript → TJS** (`fromTS`)\n\n```typescript\nimport { fromTS } from 'tjs-lang/lang/from-ts'\n\nconst tsSource = `\nfunction greet(name: string): string {\n return \\`Hello, \\${name}!\\`\n}\n`\n\nconst result = fromTS(tsSource, { emitTJS: true })\n// result.code contains TJS:\n// function greet(name: ''): '' {\n// return \\`Hello, \\${name}!\\`\n// }\n```\n\n**Step 2: TJS → JavaScript** (`tjs`)\n\n```typescript\nimport { tjs } from 'tjs-lang/lang'\n\nconst tjsSource = `\nfunction greet(name: ''): '' {\n return \\`Hello, \\${name}!\\`\n}\n`\n\nconst jsResult = tjs(tjsSource)\n// jsResult.code contains JavaScript with __tjs metadata for runtime validation\n```\n\n**Full Chain Example:**\n\n```typescript\nimport { fromTS } from 'tjs-lang/lang/from-ts'\nimport { tjs } from 'tjs-lang/lang'\n\n// TypeScript source with type annotations\nconst tsSource = `\nfunction add(a: number, b: number): number {\n return a + b\n}\n`\n\n// Step 1: TS → TJS\nconst tjsResult = fromTS(tsSource, { emitTJS: true })\n\n// Step 2: TJS → JS (with runtime validation)\nconst jsCode = tjs(tjsResult.code)\n\n// Execute the result\nconst fn = new Function('__tjs', jsCode + '; return add')(__tjs_runtime)\nfn(1, 2) // Returns 3\nfn('a', 'b') // Returns { error: 'type mismatch', ... }\n```\n\n**Design Notes:**\n\n- The two steps are intentionally separate for tree-shaking (TS support is optional)\n- `fromTS` lives in a separate entry point (`tosijs/lang/from-ts`)\n- Import only what you need to keep bundle size minimal\n- Each step is independently testable (see `src/lang/codegen.test.ts`)\n- Constrained generics (`<T extends { id: number }>`) use the constraint as the example value instead of `any`\n- Generic defaults (`<T = string>`) use the default as the example value\n- Unconstrained generics (`<T>`) degrade to `any` — there's no information to use\n\n### Security Model\n\n- **Capability-based**: VM has zero IO by default; inject `fetch`, `store`, `llm` via capabilities\n- **Fuel metering**: Every atom has a cost; execution stops when fuel exhausted\n- **Timeout enforcement**: Default `fuel × 10ms`; explicit `timeoutMs` overrides\n- **Monadic errors**: Errors wrapped in `AgentError` (VM) / `MonadicError` (TJS), not thrown (prevents exception exploits). Use `isMonadicError()` to check — `isError()` is deprecated\n- **Expression sandboxing**: ExprNode AST evaluation, blocked prototype access\n\n### Expression Evaluation\n\nExpressions use AST nodes (`$expr`), not strings:\n\n```typescript\n{ $expr: 'binary', op: '+', left: {...}, right: {...} }\n{ $expr: 'ident', name: 'varName' }\n{ $expr: 'member', object: {...}, property: 'foo' }\n```\n\nEach node costs 0.01 fuel. Forbidden: function calls, `new`, `this`, `__proto__`, `constructor`.\n\n## AJS Expression Gotchas\n\nAJS expressions behave differently from JavaScript in several important ways:\n\n- **Null member access is safe by default**: `null.foo.bar` returns `undefined` silently (uses `?.` semantics internally). This differs from JavaScript which would throw `TypeError`.\n- **No computed member access with variables**: `items[i]` fails at transpile time with \"Computed member access with variables not yet supported\". Literal indices work (`items[0]`, `obj[\"key\"]`). Workaround: use `.map`/`.reduce` atoms instead.\n- **Unknown atom errors**: When an atom doesn't exist, the error is `\"Unknown Atom: <name>\"` with no listing of available atoms.\n- **TJS parameter syntax is NOT TypeScript**: `function foo(x: 'default')` means \"required param, example value 'default'\" — not a TypeScript string literal type. LLMs consistently generate `function foo(x: string)` which is wrong. The colon value is an _example_, not a _type annotation_.\n\n## Testing Strategy\n\n- Unit tests alongside source files (`*.test.ts`)\n- Integration tests in `src/use-cases/` (RAG, orchestration, malicious actors)\n- Security tests in `src/use-cases/malicious-actor.test.ts`\n- Language tests split across 17 files in `src/lang/` (lang.test.ts, features.test.ts, codegen.test.ts, parser.test.ts, from-ts.test.ts, wasm.test.ts, etc.)\n\nCoverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ overall.\n\n**Bug fix rule:** Always create a reproduction test case before fixing a bug.\n\n## Key Patterns\n\n### Adding a New Atom\n\n1. Define with `defineAtom(opCode, inputSchema, outputSchema, implementation, { cost, timeoutMs, docs })`\n2. Add to `src/vm/atoms/` and export from `src/vm/atoms/index.ts`\n3. Add tests\n4. Run `bun run test:fast`\n\n**Atom implementation notes:**\n\n- `cost` can be static number or dynamic: `(input, ctx) => number`\n- `timeoutMs` defaults to 1000ms; use `0` for no timeout (e.g., `seq`)\n- Atoms are always async; fuel deduction is automatic in the `exec` wrapper\n\n### Debugging Agents\n\nEnable tracing: `vm.run(ast, args, { trace: true })` returns `TraceEvent[]` with execution path, fuel consumption, and state changes.\n\n### Custom Atoms Must\n\n- Be non-blocking (no synchronous CPU-heavy work)\n- Respect `ctx.signal` for cancellation\n- Access IO only via `ctx.capabilities`\n\n### Value Resolution\n\nThe `resolveValue()` function handles multiple input patterns:\n\n- `{ $kind: 'arg', path: 'varName' }` → lookup in `ctx.args`\n- `{ $expr: ... }` → evaluate ExprNode via `evaluateExpr()`\n- String with dots `'obj.foo.bar'` → traverse state with forbidden property checks\n- Bare strings → lookup in state, else return literal\n\n### Monadic Error Flow\n\nWhen `ctx.error` is set, subsequent atoms in a `seq` skip execution. Errors are wrapped in `AgentError`, not thrown. This prevents exception-based exploits.\n\n### TJS Syntax Reference\n\nFull syntax documentation is in [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md). Key concepts:\n\n- **Colon shorthand**: `function foo(x: 'hello')` — colon value is an _example_, not a type. This is the most common LLM mistake.\n- **Numeric narrowing**: `3.14` = float, `42` = integer, `+0` = non-negative integer\n- **Return types**: `function add(a: 0, b: 0): 0 { ... }` (colon syntax, same as TypeScript)\n- **Safety markers**: `!` = unsafe (skip validation), `?` = safe (explicit validation)\n- **Mode defaults**: Native TJS has all modes ON by default (`TjsEquals`, `TjsClass`, `TjsDate`, `TjsNoeval`, `TjsNoVar`, `TjsStandard`). TS-originated code (`fromTS`) and AJS/VM code get modes OFF. `TjsCompat` directive explicitly disables all modes. `TjsStrict` enables all modes (useful for TS-originated code opting in).\n- **Bang access**: `x!.foo` — returns MonadicError if `x` is null/undefined, otherwise bare `x.foo`. Chains propagate: `x!.foo!.bar`.\n- **Type/Generic/FunctionPredicate**: Three declaration forms for runtime type predicates\n- **`const!`**: Compile-time immutability, zero runtime cost\n- **Equality**: `==`/`!=` = structural equality by default in native TJS (via `Is`/`IsNot`), `===`/`!==` = identity\n- **Polymorphic functions**: Multiple same-name declarations merge into arity/type dispatcher\n- **`extend` blocks**: Local class extensions without prototype pollution\n- **WASM blocks**: Inline WebAssembly compiled at transpile time, with SIMD intrinsics and `wasmBuffer()` zero-copy arrays\n- **`@tjs` annotations**: `/* @tjs ... */` comments in TS files enrich TJS output\n\n#### Runtime Configuration\n\n```typescript\nimport { configure } from 'tjs-lang/lang'\n\nconfigure({ logTypeErrors: true }) // Log type errors to console\nconfigure({ throwTypeErrors: true }) // Throw instead of return (debugging)\nconfigure({ callStacks: true }) // Track call stacks in errors (~2x overhead)\nconfigure({ trackErrors: false }) // Disable error history (on by default)\n```\n\n#### Error History\n\nType errors are tracked in a ring buffer (on by default, zero cost on happy path):\n\n```typescript\n__tjs.errors() // → recent MonadicErrors (newest last, max 64)\n__tjs.clearErrors() // → returns and clears the buffer\n__tjs.getErrorCount() // → total since last clear (survives buffer wrap)\n```\n\nUse for debugging (find silent failures), testing (`clearErrors()` → run → check), and monitoring.\n\n#### Standalone JS Output\n\nEmitted `.js` files work without any runtime setup. Each file includes an inline\nminimal runtime as fallback — only the functions actually used are included (~500\nbytes for a basic validated function). If `globalThis.__tjs` exists (shared runtime),\nit's used instead.\n\n## Dependencies\n\nRuntime (shipped): `acorn` (JS parser, ~30KB), `tosijs-schema` (validation, ~5KB). Both have zero transitive dependencies.\n\n## Forbidden Properties (Security)\n\nThe following property names are blocked in expression evaluation to prevent prototype pollution:\n\n- `__proto__`, `constructor`, `prototype`\n\nThese are hardcoded in `runtime.ts` and checked during member access in `evaluateExpr()`.\n\n## Batteries System\n\nThe batteries (`src/batteries/`) provide zero-config local AI development:\n\n- **Lazy initialization**: First import audits LM Studio models (cached 24 hours)\n- **HTTPS detection**: Blocks local LLM calls from HTTPS contexts (security)\n- **Capabilities interface**: `fetch`, `store` (KV + vector), `llmBattery` (predict/embed)\n\nRegister battery atoms: `new AgentVM(batteryAtoms)` then pass `{ capabilities: batteries }` to `run()`.\n\n### Capability Key Naming\n\nThe base `Capabilities` interface (`runtime.ts`) uses `llm` with `{ predict, embed? }`, but the battery atoms access capabilities via different keys:\n\n| Capability key | Used by | Contains |\n| -------------- | -------------------------------------------------------- | -------------------------------------------- |\n| `llmBattery` | `llmPredictBattery`, `llmVision` | Full `LLMCapability` (`predict` + `embed`) |\n| `vector` | `storeVectorize` | Just `{ embed }` (extracted from llmBattery) |\n| `store` | `storeSearch`, `storeCreateCollection`, `storeVectorAdd` | KV + vector store ops |\n\nBoth `llmBattery` and `vector` can be `undefined`/`null` if LM Studio isn't available or HTTPS is detected.\n\n### Battery Atom Return Types\n\n- **`llmPredictBattery`**: Returns OpenAI message format `{ role?, content?, tool_calls? }` — NOT a plain string\n- **`storeVectorize`**: Returns `number[]` (embedding vector)\n- **`storeSearch`**: Returns `any[]` (matched documents)\n\n## Development Configuration\n\n### Bun Plugin\n\n`bunfig.toml` preloads `src/bun-plugin/tjs-plugin.ts` which enables importing `.tjs` files directly in bun (transpiled on-the-fly). It also aliases `tjs-lang` to `./src/index.ts` for local development, so `import { tjs } from 'tjs-lang'` resolves to the source tree without needing `npm link` or a published package.\n\n### Code Style\n\n- **Prettier**: Single quotes, no semicolons, 2-space indentation, 80 char width, es5 trailing commas\n- Prefix unused variables with `_` (enforced by ESLint: `argsIgnorePattern: '^_'`)\n- `any` types are allowed (`@typescript-eslint/no-explicit-any: 0`)\n- Module type is ESM (`\"type\": \"module\"` in package.json)\n- Build output goes to `dist/` (declaration files only via `tsconfig.build.json`, bundles via `scripts/build.ts`)\n- Run `bun run format` before committing (ESLint fix + Prettier)\n\n### Firebase Deployment\n\nThe playground is hosted on Firebase (`tjs-platform.web.app`). Demo build output goes to `.demo/` (gitignored) which is the Firebase hosting root. Cloud Functions live in `functions/` with their own build process (`functions/src/*.tjs` → transpile → bundle). Firebase config: `firebase.json`, `.firebaserc`, `firestore.rules`.\n\nThe `docs/` directory contains real documentation (markdown), not build artifacts. See `docs/README.md` for the documentation index.\n\n### Playground Examples\n\nThe playground (https://tjs-platform.web.app) shows interactive TJS and AJS examples in a navigable sidebar. Examples live as markdown files with embedded code blocks, NOT as raw `.tjs` files.\n\n**Where they live:**\n\n- TJS playground examples: `guides/examples/tjs/<slug>.md`\n- AJS playground examples: `guides/examples/ajs/<slug>.md` (assumed parallel structure)\n\n**File format:**\n\n<!-- prettier-ignore -->\n```markdown\n<!--{\"section\":\"tjs\",\"type\":\"example\",\"group\":\"basics\",\"order\":16}-->\n\n# Example Title\n\nShort intro paragraph (plain markdown).\n\n​```tjs\n/*#\n## Optional H2 — markdown rendered above the code in the playground\nExplain the concept here. Use markdown freely.\n*/\n\n// Then the actual TJS code\nfunction demo() { ... }\n\ntest 'a description' {\n expect(...).toBe(...)\n}\n​```\n```\n\nFrontmatter fields: `section` (`tjs`/`ajs`), `type: \"example\"`, `group` (`basics`/`advanced`/etc.), `order` (numeric, controls sidebar position). The H1 becomes the example title in the nav.\n\n**Registration:**\n\nExamples are auto-discovered by `bin/docs.js` (run via `bun run docs`), which walks the markdown tree, parses frontmatter, extracts the `tjs`/`ajs` code block, and writes the result to `demo/docs.json`. The demo loads `docs.json` at runtime — no other registration step.\n\n**After adding/editing an example:** run `bun run docs` and commit the regenerated `demo/docs.json` alongside the `.md` file. (The docs builder also runs as part of `bun run build:demo` and `bun run deploy`.)\n\n**Testing playground examples:**\n\nThe CLI (`bun src/cli/tjs.ts run`) does NOT inject the test-block `expect` harness — that's a playground-only thing. So running an extracted code block via the CLI prints \"expect is not defined\" for any `test { expect(...) }` blocks even though they pass in the playground. To verify an example:\n\n1. **Console-log behavior** (works via CLI): extract the `tjs` code block and run it.\n\n ````bash\n awk '/^```tjs$/{flag=1; next} /^```$/{flag=0} flag' \\\n guides/examples/tjs/<slug>.md > /tmp/example.tjs\n bun src/cli/tjs.ts run /tmp/example.tjs\n ````\n\n Verify the printed output matches the expected behavior shown in the example's comments.\n\n2. **Test blocks**: spin up the dev server (`bun run start`) and load the example in the playground UI to confirm tests pass under the real `expect` harness.\n\n3. **Frontmatter / registration**: after `bun run docs`, grep `demo/docs.json` for the slug to confirm it was picked up with the right `section`/`group`/`order`.\n\n### Additional Directories\n\n- `tjs-src/` — TJS runtime written in TJS itself (self-hosting)\n- `guides/` — Usage patterns, benchmarks, examples (`patterns.md`, `benchmarks.md`, `tjs-examples.md`)\n- `examples/` — Standalone TJS example files (`hello.tjs`, `datetime.tjs`, `generic-demo.tjs`)\n- `editors/` — Syntax highlighting for Monaco, CodeMirror, Ace, VSCode\n\n### Additional Documentation\n\n- `llms.txt` — agent-facing navigation index (ships in npm bundle); points to docs and source entry points\n- `guides/footguns.md` — JS footguns TJS fixes (boxed-primitive truthiness, `==` coercion, `typeof null`, uninitialized `let`, etc.). Demo: `examples/js-footguns-fixed.tjs`.\n- `guides/playground-imports.md` — how the playground/dev-server resolves bare imports: TFS service worker, default JSDelivr `/+esm` routing, esm.sh allowlist for peer-dep packages (React), CDN hints (`jsdelivr/`, `esmsh/`, `unpkg/`, `github/`), and full-URL passthrough.\n- `README.md` — Project intro, install, quick start\n- `DOCS-TJS.md` — TJS language guide\n- `DOCS-AJS.md` — AJS runtime guide\n- `TJS-FOR-JS.md` — TJS guide for JavaScript developers (syntax differences, gotchas)\n- `TJS-FOR-TS.md` — TJS guide for TypeScript developers (migration, interop)\n- `CONTEXT.md` — Architecture deep dive\n- `AGENTS.md` — Agent workflow instructions (session-completion checklist, push-before-done rule)\n- `TODO.md` — Open work, organized by area; move items to the **Completed** section when done\n- `PLAN.md` — Roadmap\n- `MANIFESTO-BUILDER.md` / `MANIFESTO-ENTERPRISE.md` — Positioning docs (audience-targeted pitches)\n- `benchmarks.md` — Top-level benchmark results (separate from `guides/benchmarks.md`)\n\n### Keeping This File and `llms.txt` Current\n\nUpdate both files when you change something an agent needs to discover:\n\n- **New top-level markdown doc** → add to \"Additional Documentation\" here AND to the appropriate section of `llms.txt`.\n- **New package entry point** (subpath export in `package.json`) → add to \"Package Entry Points\" here AND to \"Package entry points\" in `llms.txt`.\n- **New CLI command or `bun run` script** → add to \"Common Commands\".\n- **Renamed or moved key source file** → update \"Key Source Files\" here AND \"Source map\" in `llms.txt`.\n- **New language mode / safety directive** → add to the TJS Syntax Reference section.\n- **New playground example** → add to `guides/examples/{tjs,ajs}/<slug>.md`, then `bun run docs` to regenerate `demo/docs.json`. See \"Playground Examples\" above.\n\nSkip stale-prone precision (exact line counts, file sizes) for new entries — they drift silently. The existing `~3024` etc. are kept current opportunistically, not on every commit.\n\n### Tracking Work\n\nWork is tracked in plain markdown — no external issue tracker. Open items live in `TODO.md` (organized by area). When you start a task, find or add the relevant entry; when you finish, check the box and (for substantial work) move it to the Completed section with a short note.\n\n### Landing the Plane (Session Completion Checklist)\n\nSee `AGENTS.md` for the canonical session-completion checklist. Hard rule: work is not complete until `git push` succeeds — never stop before pushing, never `--no-verify` to bypass hooks.\n\n### Common Gotchas\n\n- **`tjs(source)` returns an object, not a string.** It returns `{ code, types, metadata, testResults, ... }` — use `.code` for the transpiled JS string.\n- **Prettier mangles bare-expression code blocks in markdown.** Code blocks tagged ` ```js` get reformatted; bare expressions like `'5' == 5` and `[1] == 1` on consecutive lines collapse into one expression with ASI guards. Use `<!-- prettier-ignore -->` directly above the code fence to preserve hand-formatted JS examples (or tag the block as `text`/`tjs`/`ts` instead — Prettier ignores those).\n- **`tjs-lang` package alias only works inside the project** (set in `bunfig.toml`). Test scripts written in `/tmp` won't resolve `import { tjs } from 'tjs-lang/lang'` to the local source — they'll resolve to whatever's in `node_modules`. For ad-hoc experiments outside the repo, use absolute paths: `import { tjs } from '/Users/.../tjs-lang/src/lang/index'`.\n\n### Running Emitted TJS Code\n\nEmitted JS works standalone — no setup required. Each file includes an inline\nruntime fallback. If you want the shared runtime (e.g. for `isMonadicError` to\nwork across files), install it first:\n\n```typescript\nimport { installRuntime, createRuntime } from '../lang/runtime'\ninstallRuntime() // or: globalThis.__tjs = createRuntime()\n\nconst fn = new Function(result.code + '\\nreturn fnName')()\nfn('valid') // works\nfn(42) // returns MonadicError (not thrown)\n```\n"
1223
1257
  },
1224
1258
  {
1225
1259
  "title": "Context: Working with tosijs-schema",
@@ -1270,13 +1304,13 @@
1270
1304
  "text": "## Description\n\nPlease provide a detailed description of the changes and the intent behind them :)\n\n## Checklist\n\n- [ ] Changes are covered by tests if behavior has been changed or added\n- [ ] Tests have 100% coverage\n- [ ] If code changes were made, the version in `package.json` has been bumped (matching semver)\n- [ ] If code changes were made, the `yarn build` command has been run and to update the `cdn` directory\n- [ ] If code changes were made, the documentation (in the `/docs` directory) has been updated\n\n## Resolves\n\nIf the PR resolves an open issue tag it here. For example, `Resolves #34`\n"
1271
1305
  },
1272
1306
  {
1273
- "text": "... *\\/ comments render as markdown\n * - Functions render with signature and detailed type info\n *\n * @param source - TJS or TypeScript source code\n * @param types - Type metadata from transpiler (result.types)\n * @returns Formatted markdown documentation\n *\n * @example\n * ```typescript\n * const result = tjs(source)\n * const docs = generateDocsMarkdown(source, result.types)\n * ```",
1307
+ "text": "...\n\n---\n\n... *\\/ comments render as markdown\n * - Functions render with signature and detailed type info\n *\n * @param source - TJS or TypeScript source code\n * @param types - Type metadata from transpiler (result.types)\n * @returns Formatted markdown documentation\n *\n * @example\n * ```typescript\n * const result = tjs(source)\n * const docs = generateDocsMarkdown(source, result.types)\n * ```",
1274
1308
  "title": "docs (inline docs)",
1275
1309
  "filename": "docs.ts",
1276
1310
  "path": "src/lang/docs.ts"
1277
1311
  },
1278
1312
  {
1279
- "text": "# Module Header\n\nThis is the intro.\n\n---\n\nMore docs here.\n\n---\n\n# First Section\n\n---\n\n# Second Section\n\n---\n\n# Heading\n\n- List item 1\n- List item 2\n\n\\`code example\\`\n\n---\n\n## Parameter Syntax\n| Syntax | Meaning |\n|--------|---------|\n| \\`x: 0\\` | Required number |\n| \\`x = 0\\` | Optional, defaults to 0 |\n\n---\n\nIndented content.\n More indented.\n\n---\n\n# Hello World\n\nThis is documentation.\n\n---\n\nIntro\n\n---\n\nMiddle\n\n---\n\n# Math Utilities\n\nA collection of math functions.\n\n---\n\n## Notes\n\nThese functions are pure.\n\n---\n\nHello World\n\n---\n\nIntro\n\n---\n\nSection 1\n\n---\n\nSection 2\n\n---\n\nConclusion\n\n---\n\nTypeScript Example\n\n---\n\nModule header\n\n---\n\nComment inside first - should be ignored\n\n---\n\nBetween first and second\n\n---\n\nComment inside second - should be ignored\n\n---\n\nAfter all functions",
1313
+ "text": "# Module Header\n\nThis is the intro.\n\n---\n\nMore docs here.\n\n---\n\n# First Section\n\n---\n\n# Second Section\n\n---\n\n# Heading\n\n- List item 1\n- List item 2\n\n\\`code example\\`\n\n---\n\n## Parameter Syntax\n| Syntax | Meaning |\n|--------|---------|\n| \\`x: 0\\` | Required number |\n| \\`x = 0\\` | Optional, defaults to 0 |\n\n---\n\nIndented content.\n More indented.\n\n---\n\n# Hello World\n\nThis is documentation.\n\n---\n\nIntro\n\n---\n\nMiddle\n\n---\n\n# Math Utilities\n\nA collection of math functions.\n\n---\n\n## Notes\n\nThese functions are pure.\n\n---\n\nHello World\n\n---\n\nIntro\n\n---\n\nSection 1\n\n---\n\nSection 2\n\n---\n\nConclusion\n\n---\n\nTypeScript Example\n\n---\n\nModule header\n\n---\n\nComment inside first - should be ignored\n\n---\n\nBetween first and second\n\n---\n\nComment inside second - should be ignored\n\n---\n\nAfter all functions\n\n---\n\n\n\n---\n\n## Example\nDon't write this:\n\n class FakeClass { constructor(x) {} }\n\n---\n\n\n\n---\n\nDon't write this:\n\n function fakeFn() {}\n\n---\n\n# Module\nSome intro.",
1280
1314
  "title": "docs.test (inline docs)",
1281
1315
  "filename": "docs.test.ts",
1282
1316
  "path": "src/lang/docs.test.ts"
@@ -1419,6 +1453,12 @@
1419
1453
  "filename": "js.ts",
1420
1454
  "path": "src/lang/emitters/js.ts"
1421
1455
  },
1456
+ {
1457
+ "title": "JS Footguns That TJS Quietly Fixes",
1458
+ "filename": "footguns.md",
1459
+ "path": "guides/footguns.md",
1460
+ "text": "# JS Footguns That TJS Quietly Fixes\n\nJavaScript has a small set of legendary, well-documented gotchas that no one\ndefends but that the spec will never change. Native TJS fixes them at the\nlanguage level so you don't have to remember which version of an idiom to\nuse in which context.\n\nA runnable demo lives at [`examples/js-footguns-fixed.tjs`](../examples/js-footguns-fixed.tjs):\n\n```bash\nbun src/cli/tjs.ts run examples/js-footguns-fixed.tjs\n```\n\nAll the fixes below are **always-on under `TjsStandard`** (the default for\nnative TJS files). They are **off** under `TjsCompat`, in `fromTS`-emitted\ncode, and in AJS/VM targets — so existing JS/TS semantics are preserved\nwhen you opt out.\n\n---\n\n## 1. `Boolean(new Boolean(false))` is `true` (and friends)\n\nA boxed primitive is an `Object`, and the spec's `ToBoolean` operation\ndeclares any `Object` truthy. The result:\n\n```js\nBoolean(new Boolean(false)) // true — wrong!\nif (new Boolean(false)) { ... } // enters branch — wrong!\n!new Boolean(false) // false — wrong!\nnew Boolean(false) || 'x' // Boolean { false } — wrong!\nnew Boolean(false) ? 'y' : 'n' // 'y' — wrong!\n```\n\n`Symbol.toPrimitive` doesn't fire for boolean coercion, so there is no\nhook to fix this in plain JS. **TJS rewrites every truthiness context**\n(including `if`, `while`, `for`, `do`, `!`, `&&`, `||`, ternary, and\ntop-level `Boolean(x)` calls) to call `__tjs.toBool(x)`, which unwraps\nboxed primitives before applying `ToBoolean`:\n\n```tjs\nBoolean(new Boolean(false)) // false ✓\nif (new Boolean(false)) ... // does not enter ✓\n!new Boolean(false) // true ✓\nnew Boolean(false) || 'x' // 'x' ✓\n```\n\nThe `&&` / `||` rewrites preserve JS's value-returning semantics: `a && b`\nstill returns `a` when `a` is falsy (after unwrapping) and `b` otherwise.\nSide effects fire exactly as they would in raw JS — `inc() && inc()` calls\n`inc` twice. No double-evaluation.\n\n`??` (nullish coalescing) is intentionally **not** rewritten. Its semantics\nare about `null`/`undefined` specifically, not truthiness, so boxed\nprimitives behave correctly already (`new Boolean(false) ?? 'fallback'`\nreturns the wrapper, which is what you'd want).\n\n`===` / `!==` (identity) are also not touched — that's a different\nfootgun, handled by the `Is` operator (see below).\n\n> **Why fix instead of ban?** Boxed primitives have legitimate uses\n> (passing primitives by reference, attaching properties for tagging).\n> Banning them with a parse error would be paternalistic. TJS lets you\n> use them — and makes them work the way the name implies.\n\n## 2. `==` is a coercion lottery; `NaN !== NaN`\n\nRaw JS `==` coerces wildly across types:\n\n<!-- prettier-ignore -->\n```js\n'5' == 5 // true\n'' == false // true\n0 == '' // true\n[1] == 1 // true\n```\n\n…and `NaN` is famously unequal to itself, which makes \"is this a real\nnumber?\" checks awkward.\n\nNative TJS rewrites `==` and `!=` to **honest equality** (the `Eq` /\n`NotEq` runtime functions):\n\n```tjs\n'5' == 5 // false ✓ (different types, no coercion)\nNaN == NaN // true ✓\nnull == undefined // true (preserved — this one is actually useful)\n```\n\nBoxed primitives are unwrapped before comparison: `new Boolean(false) == false`\nis `true`.\n\nFor **deep structural equality** of objects, arrays, Maps, and Sets, use\nthe explicit `Is` / `IsNot` operators:\n\n```tjs\nIs({a: 1}, {a: 1}) // true ✓\nIs([1, 2], [1, 2]) // true ✓\n{a: 1} Is {a: 1} // true ✓ (infix form)\n```\n\nIdentity comparison stays available as `===` / `!==` when you really\nmean \"same reference.\"\n\n## 3. `typeof null === 'object'`\n\nThe original JS bug, preserved forever for backward compatibility.\nUnder TjsEquals, `typeof` is rewritten to a runtime helper that returns\n`'null'` for `null`:\n\n```tjs\ntypeof null // 'null' ✓\ntypeof undefined // 'undefined'\ntypeof 42 // 'number'\n```\n\n## 4. `let x` (uninitialized) silently leaves a hole\n\nRaw JS: `let x` declares a variable bound to `undefined`. There's no\nindication whether you forgot to initialize it, intend to assign it\nlater, or intend it to actually be undefined.\n\nNative TJS warns under the `safe-assign-let-needs-type` linter rule:\n\n```tjs\nlet x // ⚠ let needs initializer or type annotation\nlet y = undefined // ⚠ same\nlet z = null // ⚠ same\nlet result: '' // ✓ type annotation, no init\nlet count = 0 // ✓ inferable from init\n```\n\nOnce a `let` is \"typed\" (annotated or inferable), assigning literal\n`undefined` / `null` / `void 0` to it is also flagged:\n\n```tjs\nlet name = 'world'\nname = undefined // ⚠ Cannot assign undefined to typed let 'name'\n```\n\nSeverity is warning by default, error under `TjsStrict`.\n\n## 5. Classes that require `new`\n\nCalling a class without `new` is a `TypeError` in strict mode and silently\nleaks to the global object in sloppy mode. TJS wraps user classes (under\n`TjsClass`, on by default) so they're callable both ways:\n\n```tjs\nclass Point {\n constructor(x: 0, y: 0) { this.x = x; this.y = y }\n}\n\nPoint(1, 2) // ✓ works\nnew Point(1, 2) // ⚠ flagged by no-explicit-new linter rule (also works)\n```\n\n## 6. `var` hoisting and the temporal dead zone\n\n`TjsNoVar` (on by default) makes `var` declarations a parse error. Use\n`let` and `const` exclusively, get block scoping, and avoid the entire\nclass of \"wait, that's hoisted?\" bugs.\n\n---\n\n## Opting out\n\nIf you have a specific file where you need raw JS semantics:\n\n```tjs\nTjsCompat\n// All TJS modes off; behaves like plain JS.\n```\n\nFor ts-originated code (`fromTS`), all modes default off. Add `TjsStrict`\nif you want to opt back in.\n\nFor specific mode toggles, see [DOCS-TJS.md](../DOCS-TJS.md) and the\nmode list in [CLAUDE-TJS-SYNTAX.md](../CLAUDE-TJS-SYNTAX.md).\n"
1461
+ },
1422
1462
  {
1423
1463
  "text": "# In-Memory Store\n\nSimple in-memory store for testing and development.\nData is lost when the process exits.\n\nUseful for:\n- Unit tests\n- Quick prototyping\n- Node.js/Bun environments without IndexedDB",
1424
1464
  "title": "memory (inline docs)",
@@ -1473,12 +1513,6 @@
1473
1513
  "path": ".compat-tests/zod/rfcs/index.md",
1474
1514
  "text": "# RFCs\n"
1475
1515
  },
1476
- {
1477
- "text": "# RBAC Security Rules (Pure Logic)\n\nPure security rule evaluation logic, independent of storage backend.\nThis module contains no I/O - it only evaluates rules against contexts.\n\n## Rule Context\n- `_uid` - authenticated user ID (null if public)\n- `_roles` - array of user roles\n- `_method` - 'read' | 'write' | 'delete'\n- `_collection` - collection name\n- `_docId` - document ID\n- `doc` - existing document data (for read/write/delete)\n- `newData` - incoming data (for write only)\n\n## Rule Response\n- Return `true` to allow\n- Return `false` to deny\n- Return `{ allow: true/false, reason: string }` for detailed response\n\n---\n\n## Access Rule Shortcuts\n\nEvaluates simple access rule strings without AJS overhead.\nReturns { allowed: boolean, reason?: string } or null if not a shortcut.\n\nShortcuts:\n- 'none' - deny all\n- 'all' - allow all\n- 'authenticated' - must be logged in\n- 'admin' - must have admin role\n- 'author' - must have author role\n- 'owner:fieldName' - doc[fieldName] === _uid\n- 'role:roleName' - _roles.includes(roleName)\n\n---\n\n## Select Access Rule\n\nDetermines which access rule to use based on the operation method.\nSupports granular rules (read/create/update/delete) with fallbacks.\n\n---\n\n## Validate Schema\n\nSimple schema validation for write operations.\nChecks required fields and basic types.\n\n---\n\n## Evaluate Rule Result\n\nInterprets the result of a rule evaluation (boolean, object, etc.)\ninto a standardized { allowed, reason } format.\n\n---\n\n## Check Role Hierarchy\n\nEvaluates if a user has sufficient role level.\nRole hierarchy: admin > author > user > guest\n\n---\n\n## Build Rule Context\n\nCreates the evaluation context for a security rule.",
1478
- "title": "rules (inline docs)",
1479
- "filename": "rules.js",
1480
- "path": "src/rbac/rules.js"
1481
- },
1482
1516
  {
1483
1517
  "text": "## seq (Sequence)\n\nThe root atom for all agent programs. Executes steps in order.\n\n- Stops on `return` (when `ctx.output` is set)\n- Stops on error (monadic error flow)\n- Cost: 0.1\n\n```javascript\n// AsyncJS compiles to seq at the top level\nconst x = 1\nconst y = 2\nreturn { sum: x + y }\n```\n\n---\n\n## if (Conditional)\n\nConditional branching based on expression evaluation.\n\n```javascript\nif (count > 0) {\n console.log(\"Has items\")\n} else {\n console.log(\"Empty\")\n}\n```\n\n---\n\n## while (Loop)\n\nRepeats body while condition is truthy. Consumes fuel each iteration.\n\n```javascript\nlet i = 0\nwhile (i < 10) {\n console.log(i)\n i = i + 1\n}\n```\n\n**Note:** No `break`/`continue`. Use condition variables instead.\n\n---\n\n## return\n\nEnds execution and returns values from state. The schema defines which\nstate variables to include in the output.\n\n```javascript\nconst result = compute()\nreturn { result } // Returns { result: <computed value> }\n```\n\n---\n\n## try/catch\n\nError handling with monadic error flow. When an error occurs, subsequent\nsteps are skipped until caught.\n\n```javascript\ntry {\n const data = fetch(url)\n processData(data)\n} catch (err) {\n console.warn(\"Failed: \" + err)\n return { error: err }\n}\n```\n\nThe catch block receives:\n- `err` (or custom name): error message\n- `errorOp`: the atom that failed\n\n---\n\n## for...of / map\n\nTransforms each item in an array. The `result` variable in each iteration\nbecomes the new item value.\n\n```javascript\nconst doubled = items.map(x => x * 2)\n\n// Or with for...of:\nconst results = []\nfor (const item of items) {\n results.push(process(item))\n}\n```\n\n---\n\n## filter\n\nKeeps items that match a condition.\n\n```javascript\nconst adults = users.filter(u => u.age >= 18)\n```\n\n---\n\n## reduce\n\nAccumulates a single value from an array.\n\n```javascript\nconst sum = numbers.reduce((acc, n) => acc + n, 0)\n```\n\n---\n\n## find\n\nReturns first item matching condition, or null.\n\n```javascript\nconst admin = users.find(u => u.role === \"admin\")\n```\n\n---\n\n## fetch\n\nHTTP requests. Requires `fetch` capability or uses global fetch with SSRF protection.\n\n```javascript\nconst data = fetch(\"https://api.example.com/data\")\nconst posted = fetch(\"https://api.example.com/items\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: { name: \"New Item\" }\n})\n```\n\nResponse types: `\"json\"` (default for JSON content-type), `\"text\"`, `\"dataUrl\"` (for images)\n\nSecurity:\n- Requires `ctx.context.allowedFetchDomains` allowlist OR restricts to localhost\n- Automatically adds `X-Agent-Depth` header to prevent recursive agent loops\n- Custom fetch capability can override all restrictions\n\n---\n\n## storeGet / storeSet\n\nPersistent key-value storage. Requires `store` capability.\n\n```javascript\n// Save data\nstoreSet(\"user:123\", { name: \"Alice\", prefs: {} })\n\n// Retrieve later\nconst user = storeGet(\"user:123\")\n```\n\n**Warning:** Default in-memory store is not suitable for production.\n\n---\n\n## llmPredict\n\nCall language model. Requires `llm` capability with `predict` method.\n\n```javascript\nconst response = llmPredict(\"Summarize this: \" + text)\n\n// With options\nconst structured = llmPredict(prompt, {\n model: \"gpt-4\",\n temperature: 0.7,\n responseFormat: { type: \"json_object\" }\n})\n```\n\n---\n\n## transpileCode (Code to AST)\n\nTranspiles AsyncJS code to an AST without executing it.\nUseful for generating agents to send to other services via fetch.\n\n```javascript\n// Generate an agent and send it to a worker\nlet code = llmPredict({ prompt: 'Write an AsyncJS data processor' })\nlet ast = transpileCode({ code })\nlet result = httpFetch({\n url: 'https://worker.example.com/run',\n method: 'POST',\n body: JSON.stringify({ ast, args: { data: myData } })\n})\n```\n\nSecurity: Only available when the `code.transpile` capability is provided.\n\n---\n\n## runCode (Dynamic Code Execution)\n\nTranspiles and executes AsyncJS code at runtime. The generated code\nruns in the same context, sharing fuel budget, capabilities, and trace.\n\nThis enables agents to write and execute code to solve problems.\n\n```javascript\n// Agent writes code to solve a problem\nlet code = llmPredict({ prompt: 'Write AsyncJS to calculate fibonacci(10)' })\nlet result = runCode({ code, args: {} })\nreturn { answer: result }\n```\n\nThe code must be a valid AsyncJS function. The function's return value\nbecomes the result of runCode.\n\nSecurity: Only available when the `code.transpile` capability is provided.\nThe transpiled code runs with the same permissions as the parent.\nRecursion depth is limited to prevent stack overflow.\n\n---\n\n## memoize\n\nIn-memory caching within a single execution. Same key returns cached result.\n\n```javascript\n// Expensive computation cached by key\nconst result = memoize(\"expensive-\" + id, () => {\n return heavyComputation(data)\n})\n```\n\n---\n\n## cache\n\nPersistent caching across executions using store capability.\n\n```javascript\n// Cache API result for 1 hour (3600000 ms)\nconst weather = cache(\"weather-\" + city, 3600000, () => {\n return fetch(\"https://api.weather.com/\" + city)\n})\n```\n\n---\n\n## console.log / console.warn / console.error\n\nLogging utilities that integrate with trace and error flow.\n\n```javascript\nconsole.log(\"Debug info: \" + value) // Adds to trace\nconsole.warn(\"Potential issue\") // Adds to trace + warnings summary\nconsole.error(\"Fatal: \" + msg) // Triggers monadic error flow\n```\n\n- `log`: trace only (no side effects)\n- `warn`: trace + appears in `result.warnings`\n- `error`: stops execution, sets `result.error`",
1484
1518
  "title": "runtime (inline docs)",
@@ -1531,7 +1565,7 @@
1531
1565
  "title": "TJS Syntax Reference",
1532
1566
  "filename": "CLAUDE-TJS-SYNTAX.md",
1533
1567
  "path": "CLAUDE-TJS-SYNTAX.md",
1534
- "text": "# TJS Syntax Reference\n\nThis file is the detailed TJS syntax reference, extracted from CLAUDE.md for readability.\nSee CLAUDE.md for commands, architecture, and development patterns.\n\n## Classes (Callable Without `new`)\n\nTJS classes are wrapped to be callable without the `new` keyword:\n\n```typescript\nclass Point {\n constructor(public x: number, public y: number) {}\n}\n\n// Both work identically:\nconst p1 = Point(10, 20) // TJS way - clean\nconst p2 = new Point(10, 20) // Still works, but linter warns\n\n// The linter flags explicit `new` usage:\n// Warning: Unnecessary 'new' keyword. In TJS, classes are callable without 'new'\n```\n\nThe `wrapClass()` function in the runtime uses a Proxy to intercept calls and auto-construct. In native TJS, `TjsClass` is on by default, so all `class` declarations are wrapped. TS-originated code requires an explicit `TjsClass` directive. Built-in constructors (`Boolean`, `Number`, `String`, etc.) and old-style `function` + `prototype` constructors are never touched because they may have intentional dual behavior (e.g., `Boolean(0)` returns `false` but `new Boolean(0)` returns a truthy wrapper object).\n\n## Function Parameters\n\n```typescript\n// Required param with example value (colon shorthand)\nfunction greet(name: 'Alice') { } // name is required, type inferred as string\n\n// Numeric type narrowing (all valid JS syntax)\nfunction calc(rate: 3.14) { } // number (float) -- has decimal point\nfunction calc(count: 42) { } // integer -- whole number\nfunction calc(index: +0) { } // non-negative integer -- + prefix\n\n// Optional param with default\nfunction greet(name = 'Alice') { } // name is optional, defaults to 'Alice'\n\n// Object parameter with shape\nfunction createUser(user: { name: '', age: 0 }) { }\n\n// Nullable type\nfunction find(id: 0 | null) { } // integer or null\n\n// Optional TS-style\nfunction greet(name?: '') { } // same as name = ''\n\n// Rest parameters — array example is the type (annotation stripped in JS output)\nfunction sum(...nums: [0]) { } // nums: array of integers\nfunction log(...args: ['', 0, true]) { } // args: array<string | integer | boolean>\n```\n\n## Return Types\n\n```typescript\n// Return type annotation (colon syntax)\nfunction add(a: 0, b: 0): 0 { return a + b }\n\n// Object return type\nfunction getUser(id: 0): { name: '', age: 0 } { ... }\n```\n\n## Safety Markers\n\n```typescript\n// Unsafe function (skips runtime validation)\nfunction fastAdd(! a: 0, b: 0) { return a + b }\n\n// Safe function (explicit validation)\nfunction safeAdd(? a: 0, b: 0) { return a + b }\n\n// Unsafe block\nunsafe {\n // All calls in here skip validation\n fastPath(data)\n}\n```\n\n## Bang Access (`!.`)\n\nAsserted non-null member access. Returns a MonadicError if the target is null or undefined, and propagates existing MonadicErrors through chains.\n\n```typescript\nx!.foo // MonadicError if x is null/undefined, otherwise bare x.foo\nx!.foo!.bar // propagates — if x!.foo is a MonadicError, x!.foo!.bar returns it\nobj!.a!.b!.c // safe deep access, first null/error short-circuits the chain\n```\n\nUnlike optional chaining (`?.`), which silently returns `undefined`, bang access produces a trackable MonadicError on null/undefined. On other errors (e.g., accessing a property that throws), it throws as usual.\n\n## Type Declarations\n\n```typescript\n// Simple type from example\nType Name 'Alice'\n\n// Type with description and example\nType User {\n description: 'a user object'\n example: { name: '', age: 0 }\n}\n\n// Type with predicate (auto-generates type guard from example)\nType EvenNumber {\n description: 'an even number'\n example: 2\n predicate(x) { return x % 2 === 0 }\n}\n```\n\n## Generic Declarations\n\n```typescript\n// Simple generic\nGeneric Box<T> {\n description: 'a boxed value'\n predicate(x, T) {\n return typeof x === 'object' && x !== null && 'value' in x && T(x.value)\n }\n}\n\n// Generic with default type parameter\nGeneric Container<T, U = ''> {\n description: 'container with label'\n predicate(obj, T, U) {\n return T(obj.item) && U(obj.label)\n }\n}\n\n// Generic with declaration block (for .d.ts emission)\n// The declaration block contains TypeScript syntax emitted verbatim into .d.ts\n// It is stripped from runtime JS output\nGeneric BoxedProxy<T> {\n predicate(x, T) { return typeof x === 'object' && T(x.value) }\n declaration {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n }\n}\n```\n\n## FunctionPredicate Declarations\n\nFirst-class function types, completing the Type/Generic/FunctionPredicate triad:\n\n```typescript\n// Block form — declare a function type shape\nFunctionPredicate Callback {\n params: { x: 0, y: 0 }\n returns: ''\n}\n\n// Function form — extract signature from existing function\nFunctionPredicate Handler(existingFn, 'description')\n\n// Return contracts:\n// : returns (standard)\n// :! assertReturns (throws on mismatch)\n// :? checkedReturns (wraps in MonadicError)\n```\n\nRuntime creates a `RuntimeType` that checks `typeof === 'function'`. The spec includes params, returns, and returnContract. In `fromTS`, TS function type aliases (`type Cb = (x: number) => void`) emit FunctionPredicate declarations automatically.\n\n## Bare Assignments\n\n```typescript\n// Uppercase identifiers auto-get const\nFoo = Type('test', 'example') // becomes: const Foo = Type(...)\nMyConfig = { debug: true } // becomes: const MyConfig = { ... }\n```\n\n## Module Safety Directive\n\n```typescript\n// At top of file - sets default validation level\nsafety none // No validation (metadata only)\nsafety inputs // Validate function inputs (default)\nsafety all // Validate everything (debug mode)\n```\n\n## TJS Mode Directives\n\nNative TJS (`.tjs` files) has all modes ON by default: `TjsEquals`, `TjsClass`, `TjsDate`, `TjsNoeval`, `TjsNoVar`, `TjsStandard`. The default safety level is `inputs`.\n\nTS-originated code (from `fromTS`, detected by the `/* tjs <- */` annotation) and AJS/VM code get all modes OFF with safety `none`, matching plain JavaScript semantics.\n\n```typescript\n// Individual modes (on by default in native TJS, off by default in TS-originated/AJS)\nTjsEquals // == and != use honest equality (Eq/NotEq) — no coercion, unwraps boxed primitives\nTjsClass // Classes callable without new, explicit new is banned\nTjsDate // Date is banned, use Timestamp/LegalDate instead\nTjsNoeval // eval() and new Function() are banned\nTjsNoVar // var declarations are syntax errors — use const or let\nTjsStandard // Newlines as statement terminators (prevents ASI footguns)\nTjsSafeEval // Include Eval/SafeFunction in runtime for dynamic code (always opt-in, adds an import)\n\n// Meta-directives\nTjsStrict // Enables ALL modes (useful for TS-originated code opting in to TJS semantics)\nTjsCompat // Disables ALL modes (for gradual migration or JS interop in native TJS files)\n```\n\n`TjsSafeEval` is always opt-in regardless of file origin because it adds a runtime import.\n\nIndividual directives still work for selective enable/disable. Multiple directives can be combined. Place them at the top of the file before any code.\n\n## Compile-Time Immutability (`const!`)\n\n`const!` declares bindings whose properties cannot be mutated. Enforced at transpile time with zero runtime cost — emits as plain `const`.\n\n```typescript\nconst! config = { debug: false, port: 8080 }\nconsole.log(config.port) // OK — reads are fine\nconfig.debug = true // ERROR at transpile time\n\nconst! items = [1, 2, 3]\nitems.map(x => x * 2) // OK — non-mutating methods\nitems.push(4) // ERROR — mutating method\n```\n\nCatches: property assignment, compound assignment (`+=`), increment/decrement, `delete`, and mutating array methods (`push`, `pop`, `splice`, `shift`, `unshift`, `sort`, `reverse`, `fill`).\n\nWhen runtimes support records/tuples, `const!` can emit those instead.\n\n## Equality Operators\n\nWith `TjsEquals` (or `TjsStrict`), TJS fixes JavaScript's confusing `==` coercion without the performance cost of deep structural comparison.\n\n| Operator | Meaning | Example |\n| ----------- | -------------------------------------------- | ---------------------------------- |\n| `==` | Honest equality (no coercion, unwraps boxed) | `new String('x') == 'x'` is `true` |\n| `!=` | Honest inequality | `0 != ''` is `true` (no coercion) |\n| `===` | Identity (same reference) | `obj === obj` is `true` |\n| `!==` | Not same reference | `{a:1} !== {a:1}` is `true` |\n| `a Is b` | Deep structural equality (explicit) | `{a:1} Is {a:1}` is `true` |\n| `a IsNot b` | Deep structural inequality (explicit) | `[1,2] IsNot [2,1]` is `true` |\n\n```typescript\n// == is honest: no coercion, unwraps boxed primitives\n'foo' == 'foo' // true\nnew String('foo') == 'foo' // true (unwraps)\nnew Boolean(false) == false // true (unwraps)\nnull == undefined // true (nullish equality preserved)\n0 == '' // false (no coercion!)\nfalse == [] // false (no coercion!)\n\n// == is fast: objects/arrays use reference equality (O(1))\n{a:1} == {a:1} // false (different refs)\n[1,2] == [1,2] // false (different refs)\n\n// Is/IsNot for explicit deep structural comparison (O(n))\n{a:1} Is {a:1} // true\n[1,2,3] Is [1,2,3] // true\nnew Set([1,2]) Is new Set([2,1]) // true (Sets are order-independent)\n```\n\n**Implementation Notes:**\n\n- **AJS (VM)**: The VM's expression evaluator (`src/vm/runtime.ts`) uses `isStructurallyEqual()` for `==`/`!=`\n- **TJS (browser/Node)**: Source transformation converts `==` to `Eq()` and `!=` to `NotEq()` calls\n- **`===` and `!==`**: Always preserved as identity checks, never transformed\n- `Eq()`/`NotEq()` — fast honest equality (unwraps boxed primitives, nullish equality, reference for objects)\n- `Is()`/`IsNot()` — deep structural comparison (arrays, objects, Sets, Maps, Dates, RegExps)\n\n**Custom Equality Protocol:**\n\n- `[tjsEquals]` symbol (`Symbol.for('tjs.equals')`) — highest priority, ideal for Proxies\n- `.Equals` method — backward-compatible, works on any object/class\n- Priority: symbol → `.Equals` → structural comparison\n- `tjsEquals` is exported from `src/lang/runtime.ts` and available as `__tjs.tjsEquals`\n\n## Honest typeof\n\nWith `TjsEquals`, `typeof null` returns `'null'` instead of `'object'` (JS's oldest bug). All other typeof results are unchanged. Transforms `typeof expr` to `TypeOf(expr)`.\n\n## `@tjs` Annotations in TypeScript Source\n\nTypeScript files can include `/* @tjs ... */` comments that `fromTS` uses to enrich\nthe TJS output. The TS compiler ignores them as regular comments.\n\n```typescript\n/* @tjs TjsClass TjsEquals */ // Enable TJS modes in TS-originated code\n/* @tjs-skip */ // Skip this declaration entirely\n/* @tjs example: { name: 'Alice' } */ // Custom example value for Type\n/* @tjs predicate(x) { return x > 0 } */ // Custom runtime predicate\n/* @tjs declaration { value: T } */ // Declaration block for Generic .d.ts\n```\n\nMode directives (`TjsClass`, `TjsEquals`, etc.) are emitted at the top of the `.tjs`\noutput. These are mainly useful for TS-originated code (where modes are off by\ndefault) to opt in to TJS features like `private → #` conversion (`TjsClass`).\n\n## Polymorphic Functions\n\nMultiple function declarations with the same name are merged into a dispatcher:\n\n```typescript\nfunction area(radius: 3.14) {\n return Math.PI * radius * radius\n}\nfunction area(w: 0.0, h: 0.0) {\n return w * h\n}\n\narea(5) // dispatches to variant 1 (one number)\narea(3, 4) // dispatches to variant 2 (two numbers)\n```\n\nDispatch order: arity first, then type specificity, then declaration order. Ambiguous signatures (same types at same arity) are caught at transpile time.\n\n## Polymorphic Constructors\n\nClasses can have multiple constructor signatures (`TjsClass` is on by default in native TJS):\n\n```typescript\nclass Point {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n constructor(coords: { x: 0.0; y: 0.0 }) {\n this.x = coords.x\n this.y = coords.y\n }\n}\n\nPoint(3, 4) // variant 1\nPoint({ x: 10, y: 20 }) // variant 2 (both produce correct instanceof)\n```\n\nThe first constructor becomes the real JS constructor; additional variants become factory functions using `Object.create`.\n\n## Local Class Extensions\n\nAdd methods to built-in types without prototype pollution:\n\n```typescript\nextend String {\n capitalize() { return this[0].toUpperCase() + this.slice(1) }\n}\n\nextend Array {\n last() { return this[this.length - 1] }\n}\n\n'hello'.capitalize() // 'Hello' — rewritten to __ext_String.capitalize.call('hello')\n[1, 2, 3].last() // 3\n```\n\n- Methods are rewritten to `.call()` at transpile time for known-type receivers (zero overhead)\n- Runtime fallback via `registerExtension()`/`resolveExtension()` for unknown types\n- Arrow functions rejected (need `this` binding)\n- Multiple `extend` blocks for same type merge left-to-right\n- File-local only — no cross-module leaking\n\n## WASM Blocks\n\nTJS supports inline WebAssembly for performance-critical code. WASM blocks are compiled at transpile time and embedded as base64 in the output.\n\n### Syntax\n\n```typescript\nconst add = wasm (a: i32, b: i32): i32 {\n local.get $a\n local.get $b\n i32.add\n}\n```\n\n### Features\n\n- **Transpile-time compilation**: WASM bytecode is generated during transpilation, not at runtime\n- **WAT comments**: Human-readable WebAssembly Text format is included as comments above the base64\n- **Type-safe**: Parameters and return types are validated\n- **Self-contained**: Compiled WASM is embedded in output JS, no separate .wasm files needed\n\n### Output Example\n\nThe transpiler generates code like:\n\n```javascript\n/*\n * WASM Block: add\n * WAT (WebAssembly Text):\n * (func $add (param $a i32) (param $b i32) (result i32)\n * local.get 0\n * local.get 1\n * i32.add\n * )\n */\nconst add = await (async () => {\n const bytes = Uint8Array.from(atob('AGFzbQEAAAA...'), (c) => c.charCodeAt(0))\n const { instance } = await WebAssembly.instantiate(bytes)\n return instance.exports.fn\n})()\n```\n\n### SIMD Intrinsics (f32x4)\n\nWASM blocks support explicit SIMD via `f32x4_*` intrinsics:\n\n```typescript\nconst scale = wasm (arr: Float32Array, len: 0, factor: 0.0): 0 {\n let s = f32x4_splat(factor)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n let v = f32x4_load(arr, off)\n f32x4_store(arr, off, f32x4_mul(v, s))\n }\n} fallback {\n for (let i = 0; i < len; i++) arr[i] *= factor\n}\n```\n\nAvailable: `f32x4_load`, `f32x4_store`, `f32x4_splat`, `f32x4_extract_lane`, `f32x4_replace_lane`, `f32x4_add`, `f32x4_sub`, `f32x4_mul`, `f32x4_div`, `f32x4_neg`, `f32x4_sqrt`.\n\n### Zero-Copy Arrays: `wasmBuffer()`\n\n`wasmBuffer(Constructor, length)` allocates typed arrays directly in WASM linear memory. When passed to a `wasm {}` block, these arrays are zero-copy — no marshalling overhead.\n\n```typescript\n// Allocate in WASM memory (zero-copy when passed to wasm blocks)\nconst xs = wasmBuffer(Float32Array, 50000)\n\n// Works like a normal Float32Array from JS\nxs[0] = 3.14\nfor (let i = 0; i < xs.length; i++) xs[i] = Math.random()\n\n// Zero-copy in WASM blocks — data is already in WASM memory\nfunction process(! xs: Float32Array, len: 0, delta: 0.0) {\n wasm {\n let vd = f32x4_splat(delta)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n f32x4_store(xs, off, f32x4_add(f32x4_load(xs, off), vd))\n }\n } fallback {\n for (let i = 0; i < len; i++) xs[i] += delta\n }\n}\n\n// After WASM runs, JS sees mutations immediately (same memory)\n```\n\n- Regular `Float32Array` args are copied in before and out after each WASM call\n- `wasmBuffer` arrays skip both copies (detected via `buffer === wasmMemory.buffer`)\n- Uses a bump allocator — allocations persist for program lifetime (no deallocation)\n- All WASM blocks in a file share one `WebAssembly.Memory` (64MB / 1024 pages)\n- Supports `Float32Array`, `Float64Array`, `Int32Array`, `Uint8Array`\n\n### Current Limitations\n\n- No imports/exports beyond the function itself\n- `wasmBuffer` allocations are permanent (bump allocator, no free)\n"
1568
+ "text": "# TJS Syntax Reference\n\nThis file is the detailed TJS syntax reference, extracted from CLAUDE.md for readability.\nSee CLAUDE.md for commands, architecture, and development patterns.\n\n## Classes (Callable Without `new`)\n\nTJS classes are wrapped to be callable without the `new` keyword:\n\n```typescript\nclass Point {\n constructor(public x: number, public y: number) {}\n}\n\n// Both work identically:\nconst p1 = Point(10, 20) // TJS way - clean\nconst p2 = new Point(10, 20) // Still works, but linter warns\n\n// The linter flags explicit `new` usage:\n// Warning: Unnecessary 'new' keyword. In TJS, classes are callable without 'new'\n```\n\nThe `wrapClass()` function in the runtime uses a Proxy to intercept calls and auto-construct. In native TJS, `TjsClass` is on by default, so all `class` declarations are wrapped. TS-originated code requires an explicit `TjsClass` directive. Built-in constructors (`Boolean`, `Number`, `String`, etc.) and old-style `function` + `prototype` constructors are never touched because they may have intentional dual behavior (e.g., `Boolean(0)` returns `false` but `new Boolean(0)` returns a truthy wrapper object).\n\n## Function Parameters\n\n```typescript\n// Required param with example value (colon shorthand)\nfunction greet(name: 'Alice') { } // name is required, type inferred as string\n\n// Numeric type narrowing (all valid JS syntax)\nfunction calc(rate: 3.14) { } // number (float) -- has decimal point\nfunction calc(count: 42) { } // integer -- whole number\nfunction calc(index: +0) { } // non-negative integer -- + prefix\n\n// Optional param with default\nfunction greet(name = 'Alice') { } // name is optional, defaults to 'Alice'\n\n// Object parameter with shape\nfunction createUser(user: { name: '', age: 0 }) { }\n\n// Nullable type\nfunction find(id: 0 | null) { } // integer or null\n\n// Optional TS-style\nfunction greet(name?: '') { } // same as name = ''\n\n// Rest parameters — array example is the type (annotation stripped in JS output)\nfunction sum(...nums: [0]) { } // nums: array of integers\nfunction log(...args: ['', 0, true]) { } // args: array<string | integer | boolean>\n```\n\n## Return Types\n\n```typescript\n// Return type annotation (colon syntax)\nfunction add(a: 0, b: 0): 0 { return a + b }\n\n// Object return type\nfunction getUser(id: 0): { name: '', age: 0 } { ... }\n```\n\n## Safety Markers\n\n```typescript\n// Unsafe function (skips runtime validation)\nfunction fastAdd(! a: 0, b: 0) { return a + b }\n\n// Safe function (explicit validation)\nfunction safeAdd(? a: 0, b: 0) { return a + b }\n\n// Unsafe block\nunsafe {\n // All calls in here skip validation\n fastPath(data)\n}\n```\n\n## Bang Access (`!.`)\n\nAsserted non-null member access. Returns a MonadicError if the target is null or undefined, and propagates existing MonadicErrors through chains.\n\n```typescript\nx!.foo // MonadicError if x is null/undefined, otherwise bare x.foo\nx!.foo!.bar // propagates — if x!.foo is a MonadicError, x!.foo!.bar returns it\nobj!.a!.b!.c // safe deep access, first null/error short-circuits the chain\n```\n\nUnlike optional chaining (`?.`), which silently returns `undefined`, bang access produces a trackable MonadicError on null/undefined. On other errors (e.g., accessing a property that throws), it throws as usual.\n\n## Type Declarations\n\n```typescript\n// Simple type from example\nType Name 'Alice'\n\n// Type with description and example\nType User {\n description: 'a user object'\n example: { name: '', age: 0 }\n}\n\n// Type with predicate (auto-generates type guard from example)\nType EvenNumber {\n description: 'an even number'\n example: 2\n predicate(x) { return x % 2 === 0 }\n}\n```\n\n## Generic Declarations\n\n```typescript\n// Simple generic\nGeneric Box<T> {\n description: 'a boxed value'\n predicate(x, T) {\n return typeof x === 'object' && x !== null && 'value' in x && T(x.value)\n }\n}\n\n// Generic with default type parameter\nGeneric Container<T, U = ''> {\n description: 'container with label'\n predicate(obj, T, U) {\n return T(obj.item) && U(obj.label)\n }\n}\n\n// Generic with declaration block (for .d.ts emission)\n// The declaration block contains TypeScript syntax emitted verbatim into .d.ts\n// It is stripped from runtime JS output\nGeneric BoxedProxy<T> {\n predicate(x, T) { return typeof x === 'object' && T(x.value) }\n declaration {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n }\n}\n```\n\n## FunctionPredicate Declarations\n\nFirst-class function types, completing the Type/Generic/FunctionPredicate triad:\n\n```typescript\n// Block form — declare a function type shape\nFunctionPredicate Callback {\n params: { x: 0, y: 0 }\n returns: ''\n}\n\n// Function form — extract signature from existing function\nFunctionPredicate Handler(existingFn, 'description')\n\n// Return contracts:\n// : returns (standard)\n// :! assertReturns (throws on mismatch)\n// :? checkedReturns (wraps in MonadicError)\n```\n\nRuntime creates a `RuntimeType` that checks `typeof === 'function'`. The spec includes params, returns, and returnContract. In `fromTS`, TS function type aliases (`type Cb = (x: number) => void`) emit FunctionPredicate declarations automatically.\n\n## Bare Assignments\n\n```typescript\n// Uppercase identifiers auto-get const\nFoo = Type('test', 'example') // becomes: const Foo = Type(...)\nMyConfig = { debug: true } // becomes: const MyConfig = { ... }\n```\n\n## Module Safety Directive\n\n```typescript\n// At top of file - sets default validation level\nsafety none // No validation (metadata only)\nsafety inputs // Validate function inputs (default)\nsafety all // Validate everything (debug mode)\n```\n\n## TJS Mode Directives\n\nNative TJS (`.tjs` files) has all modes ON by default: `TjsEquals`, `TjsClass`, `TjsDate`, `TjsNoeval`, `TjsNoVar`, `TjsStandard`. The default safety level is `inputs`.\n\nTS-originated code (from `fromTS`, detected by the `/* tjs <- */` annotation) and AJS/VM code get all modes OFF with safety `none`, matching plain JavaScript semantics.\n\n```typescript\n// Individual modes (on by default in native TJS, off by default in TS-originated/AJS)\nTjsEquals // == and != use honest equality (Eq/NotEq) — no coercion, unwraps boxed primitives\nTjsClass // Classes callable without new, explicit new is banned\nTjsDate // Date is banned, use Timestamp/LegalDate instead\nTjsNoeval // eval() and new Function() are banned\nTjsNoVar // var declarations are syntax errors — use const or let\nTjsStandard // Newlines as statement terminators (prevents ASI footguns)\nTjsSafeEval // Include Eval/SafeFunction in runtime for dynamic code (always opt-in, adds an import)\n\n// Meta-directives\nTjsStrict // Enables ALL modes (useful for TS-originated code opting in to TJS semantics)\nTjsCompat // Disables ALL modes (for gradual migration or JS interop in native TJS files)\n```\n\n`TjsSafeEval` is always opt-in regardless of file origin because it adds a runtime import.\n\nIndividual directives still work for selective enable/disable. Multiple directives can be combined. Place them at the top of the file before any code.\n\n## Compile-Time Immutability (`const!`)\n\n`const!` declares bindings whose properties cannot be mutated. Enforced at transpile time with zero runtime cost — emits as plain `const`.\n\n```typescript\nconst! config = { debug: false, port: 8080 }\nconsole.log(config.port) // OK — reads are fine\nconfig.debug = true // ERROR at transpile time\n\nconst! items = [1, 2, 3]\nitems.map(x => x * 2) // OK — non-mutating methods\nitems.push(4) // ERROR — mutating method\n```\n\nCatches: property assignment, compound assignment (`+=`), increment/decrement, `delete`, and mutating array methods (`push`, `pop`, `splice`, `shift`, `unshift`, `sort`, `reverse`, `fill`).\n\nWhen runtimes support records/tuples, `const!` can emit those instead.\n\n## Equality Operators\n\nWith `TjsEquals` (or `TjsStrict`), TJS fixes JavaScript's confusing `==` coercion without the performance cost of deep structural comparison.\n\n| Operator | Meaning | Example |\n| ----------- | -------------------------------------------- | ---------------------------------- |\n| `==` | Honest equality (no coercion, unwraps boxed) | `new String('x') == 'x'` is `true` |\n| `!=` | Honest inequality | `0 != ''` is `true` (no coercion) |\n| `===` | Identity (same reference) | `obj === obj` is `true` |\n| `!==` | Not same reference | `{a:1} !== {a:1}` is `true` |\n| `a Is b` | Deep structural equality (explicit) | `{a:1} Is {a:1}` is `true` |\n| `a IsNot b` | Deep structural inequality (explicit) | `[1,2] IsNot [2,1]` is `true` |\n\n```typescript\n// == is honest: no coercion, unwraps boxed primitives\n'foo' == 'foo' // true\nnew String('foo') == 'foo' // true (unwraps)\nnew Boolean(false) == false // true (unwraps)\nnull == undefined // true (nullish equality preserved)\n0 == '' // false (no coercion!)\nfalse == [] // false (no coercion!)\n\n// == is fast: objects/arrays use reference equality (O(1))\n{a:1} == {a:1} // false (different refs)\n[1,2] == [1,2] // false (different refs)\n\n// Is/IsNot for explicit deep structural comparison (O(n))\n{a:1} Is {a:1} // true\n[1,2,3] Is [1,2,3] // true\nnew Set([1,2]) Is new Set([2,1]) // true (Sets are order-independent)\n```\n\n**Implementation Notes:**\n\n- **AJS (VM)**: The VM's expression evaluator (`src/vm/runtime.ts`) uses `isStructurallyEqual()` for `==`/`!=`\n- **TJS (browser/Node)**: Source transformation converts `==` to `Eq()` and `!=` to `NotEq()` calls\n- **`===` and `!==`**: Always preserved as identity checks, never transformed\n- `Eq()`/`NotEq()` — fast honest equality (unwraps boxed primitives, nullish equality, reference for objects)\n- `Is()`/`IsNot()` — deep structural comparison (arrays, objects, Sets, Maps, Dates, RegExps)\n\n**Custom Equality Protocol:**\n\n- `[tjsEquals]` symbol (`Symbol.for('tjs.equals')`) — highest priority, ideal for Proxies\n- `.Equals` method — backward-compatible, works on any object/class\n- Priority: symbol → `.Equals` → structural comparison\n- `tjsEquals` is exported from `src/lang/runtime.ts` and available as `__tjs.tjsEquals`\n\n## Honest typeof\n\nWith `TjsEquals`, `typeof null` returns `'null'` instead of `'object'` (JS's oldest bug). All other typeof results are unchanged. Transforms `typeof expr` to `TypeOf(expr)`.\n\n## Honest Boolean Coercion (TjsStandard)\n\nRaw JS: `Boolean(new Boolean(false)) === true` (a boxed primitive is an Object → truthy). Same trap for `if`, `!`, `&&`, `||`, `?:`, `while`, `for`, `do/while`. The spec's `ToBoolean` operation has no override hook (`Symbol.toPrimitive` doesn't fire for boolean coercion).\n\nNative TJS rewrites every truthiness context to `__tjs.toBool(x)`, which unwraps boxed primitives before coercing. Always-on under `TjsStandard`.\n\n```typescript\nBoolean(new Boolean(false)) // false ✓\nif (new Boolean(false)) ... // does not enter ✓\n!new Boolean(false) // true ✓\nnew Boolean(false) || 'x' // 'x' ✓\nnew Boolean(false) ? 'a' : 'b' // 'b' ✓\n```\n\n`&&` / `||` rewrites preserve JS's value-returning semantics (`a && b` returns `a` when falsy, else `b`). `??` is intentionally not touched (it checks null/undefined, not truthiness). `===` / `!==` are not touched (use `Is` for structural).\n\nSee [`guides/footguns.md`](guides/footguns.md) for the broader list of JS footguns TJS fixes, with a runnable example at [`examples/js-footguns-fixed.tjs`](examples/js-footguns-fixed.tjs).\n\n## `@tjs` Annotations in TypeScript Source\n\nTypeScript files can include `/* @tjs ... */` comments that `fromTS` uses to enrich\nthe TJS output. The TS compiler ignores them as regular comments.\n\n```typescript\n/* @tjs TjsClass TjsEquals */ // Enable TJS modes in TS-originated code\n/* @tjs-skip */ // Skip this declaration entirely\n/* @tjs example: { name: 'Alice' } */ // Custom example value for Type\n/* @tjs predicate(x) { return x > 0 } */ // Custom runtime predicate\n/* @tjs declaration { value: T } */ // Declaration block for Generic .d.ts\n```\n\nMode directives (`TjsClass`, `TjsEquals`, etc.) are emitted at the top of the `.tjs`\noutput. These are mainly useful for TS-originated code (where modes are off by\ndefault) to opt in to TJS features like `private → #` conversion (`TjsClass`).\n\n## Polymorphic Functions\n\nMultiple function declarations with the same name are merged into a dispatcher:\n\n```typescript\nfunction area(radius: 3.14) {\n return Math.PI * radius * radius\n}\nfunction area(w: 0.0, h: 0.0) {\n return w * h\n}\n\narea(5) // dispatches to variant 1 (one number)\narea(3, 4) // dispatches to variant 2 (two numbers)\n```\n\nDispatch order: arity first, then type specificity, then declaration order. Ambiguous signatures (same types at same arity) are caught at transpile time.\n\n## Polymorphic Constructors\n\nClasses can have multiple constructor signatures (`TjsClass` is on by default in native TJS):\n\n```typescript\nclass Point {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n constructor(coords: { x: 0.0; y: 0.0 }) {\n this.x = coords.x\n this.y = coords.y\n }\n}\n\nPoint(3, 4) // variant 1\nPoint({ x: 10, y: 20 }) // variant 2 (both produce correct instanceof)\n```\n\nThe first constructor becomes the real JS constructor; additional variants become factory functions using `Object.create`.\n\n## Local Class Extensions\n\nAdd methods to built-in types without prototype pollution:\n\n```typescript\nextend String {\n capitalize() { return this[0].toUpperCase() + this.slice(1) }\n}\n\nextend Array {\n last() { return this[this.length - 1] }\n}\n\n'hello'.capitalize() // 'Hello' — rewritten to __ext_String.capitalize.call('hello')\n[1, 2, 3].last() // 3\n```\n\n- Methods are rewritten to `.call()` at transpile time for known-type receivers (zero overhead)\n- Runtime fallback via `registerExtension()`/`resolveExtension()` for unknown types\n- Arrow functions rejected (need `this` binding)\n- Multiple `extend` blocks for same type merge left-to-right\n- File-local only — no cross-module leaking\n\n## WASM Blocks\n\nTJS supports inline WebAssembly for performance-critical code. WASM blocks are compiled at transpile time and embedded as base64 in the output.\n\n### Syntax\n\n```typescript\nconst add = wasm (a: i32, b: i32): i32 {\n local.get $a\n local.get $b\n i32.add\n}\n```\n\n### Features\n\n- **Transpile-time compilation**: WASM bytecode is generated during transpilation, not at runtime\n- **WAT comments**: Human-readable WebAssembly Text format is included as comments above the base64\n- **Type-safe**: Parameters and return types are validated\n- **Self-contained**: Compiled WASM is embedded in output JS, no separate .wasm files needed\n\n### Output Example\n\nThe transpiler generates code like:\n\n```javascript\n/*\n * WASM Block: add\n * WAT (WebAssembly Text):\n * (func $add (param $a i32) (param $b i32) (result i32)\n * local.get 0\n * local.get 1\n * i32.add\n * )\n */\nconst add = await (async () => {\n const bytes = Uint8Array.from(atob('AGFzbQEAAAA...'), (c) => c.charCodeAt(0))\n const { instance } = await WebAssembly.instantiate(bytes)\n return instance.exports.fn\n})()\n```\n\n### SIMD Intrinsics (f32x4)\n\nWASM blocks support explicit SIMD via `f32x4_*` intrinsics:\n\n```typescript\nconst scale = wasm (arr: Float32Array, len: 0, factor: 0.0): 0 {\n let s = f32x4_splat(factor)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n let v = f32x4_load(arr, off)\n f32x4_store(arr, off, f32x4_mul(v, s))\n }\n} fallback {\n for (let i = 0; i < len; i++) arr[i] *= factor\n}\n```\n\nAvailable: `f32x4_load`, `f32x4_store`, `f32x4_splat`, `f32x4_extract_lane`, `f32x4_replace_lane`, `f32x4_add`, `f32x4_sub`, `f32x4_mul`, `f32x4_div`, `f32x4_neg`, `f32x4_sqrt`.\n\n### Zero-Copy Arrays: `wasmBuffer()`\n\n`wasmBuffer(Constructor, length)` allocates typed arrays directly in WASM linear memory. When passed to a `wasm {}` block, these arrays are zero-copy — no marshalling overhead.\n\n```typescript\n// Allocate in WASM memory (zero-copy when passed to wasm blocks)\nconst xs = wasmBuffer(Float32Array, 50000)\n\n// Works like a normal Float32Array from JS\nxs[0] = 3.14\nfor (let i = 0; i < xs.length; i++) xs[i] = Math.random()\n\n// Zero-copy in WASM blocks — data is already in WASM memory\nfunction process(! xs: Float32Array, len: 0, delta: 0.0) {\n wasm {\n let vd = f32x4_splat(delta)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n f32x4_store(xs, off, f32x4_add(f32x4_load(xs, off), vd))\n }\n } fallback {\n for (let i = 0; i < len; i++) xs[i] += delta\n }\n}\n\n// After WASM runs, JS sees mutations immediately (same memory)\n```\n\n- Regular `Float32Array` args are copied in before and out after each WASM call\n- `wasmBuffer` arrays skip both copies (detected via `buffer === wasmMemory.buffer`)\n- Uses a bump allocator — allocations persist for program lifetime (no deallocation)\n- All WASM blocks in a file share one `WebAssembly.Memory` (64MB / 1024 pages)\n- Supports `Float32Array`, `Float64Array`, `Int32Array`, `Uint8Array`\n\n### Current Limitations\n\n- No imports/exports beyond the function itself\n- `wasmBuffer` allocations are permanent (bump allocator, no free)\n"
1535
1569
  },
1536
1570
  {
1537
1571
  "title": "tjs-lang Guides",
@@ -1543,7 +1577,7 @@
1543
1577
  "title": "TJS-Lang TODO",
1544
1578
  "filename": "TODO.md",
1545
1579
  "path": "TODO.md",
1546
- "text": "# TJS-Lang TODO\n\n## Playground - Error Navigation\n\n- [ ] Test errors: click should navigate to source location\n- [ ] Console errors: click should navigate to source location\n- [ ] Error in imported module: click through to source\n\n## Playground - Module Management\n\n- [ ] Import one example from another in playground\n- [ ] Save/Load TS examples (consistency with TJS examples)\n- [ ] File name should be linked to example name\n- [ ] New example button in playground\n- [ ] UI for managing stored modules (browse/delete IndexedDB)\n- [ ] Auto-discover and build local dependencies in module resolution\n\n## Language Features\n\n- [ ] Portable Type predicates - expression-only AJS subset (no loops, no async, serializable)\n- [ ] Sync AJS / AJS-to-JS compilation - for type-checked AJS that passes static analysis, transpile to native JS with fuel injection points. Enables both type safety guarantees AND native performance for RBAC rules, predicates, etc.\n- [ ] Self-contained transpiler output (no runtime dependency)\n - Currently transpiled code references `globalThis.__tjs` for pushStack/popStack, typeError, Is/IsNot\n - Requires runtime to be installed or a stub (see playground's manual \\_\\_tjs stub)\n - Goal: TJS produces completely independent code, only needing semantic dependencies\n - Options: inline minimal runtime (~1KB), `{ standalone: true }` option, or tree-shake\n - See: src/lang/emitters/js.ts TODO comment for details\n- [x] WASM compilation at transpile time (not runtime)\n - [x] Compile wasm {} blocks during transpilation\n - [x] Embed base64-encoded WASM bytes in output\n - [x] Include WAT disassembly as comment for debugging/learning\n - [x] Self-contained async instantiation (no separate compileWasmBlocksForIframe)\n- [x] Expand WASM support beyond POC\n - [x] For loops with numeric bounds\n - [x] Conditionals (if/else)\n - [x] Local variables within block\n - [x] Typed array access (Float32Array, Float64Array, Int32Array, Uint8Array)\n - [x] Memory operations\n - [x] Continue/break statements\n - [x] Logical expressions (&& / ||)\n - [x] Math functions (sqrt, abs, floor, ceil, min, max, sin, cos, log, exp, pow)\n- [x] WASM SIMD support (v128/f32x4)\n - 12 f32x4 intrinsics: load, store, splat, extract_lane, replace_lane, add, sub, mul, div, neg, sqrt\n - Explicit intrinsic approach (users call f32x4\\_\\* in wasm blocks)\n - Disassembler handles 0xfd prefix with LEB128 sub-opcodes\n - 16-byte aligned memory for v128 loads/stores\n - Demos: starfield SIMD rotation, vector search cosine similarity\n- [ ] WASM SIMD vector search (batteries)\n - Replace JS vectorSearch battery with WASM SIMD implementation\n - SIMD cosine similarity demonstrated in vector search demo\n - TODO: integrate as a battery atom with auto-detect + fallback\n\n## Editor\n\n- [ ] Embedded AJS syntax highlighting\n\n## Documentation / Examples\n\n- [ ] Create an endpoint example\n- [ ] Fold docs and tests into one panel, with passing tests collapsed by default (ts -> tjs inserts test; tjs -> js turns test blocks into documentation along with outcomes).\n- [ ] Dim/hide the preview tab if nothing ever changed it\n- [ ] Single source of truth for version number. I note the badge displayed in console is not matching the version. No hardwired versions -- version number is pulled from package.json and written to version.ts somewhere and that is the single source of truth.\n\n## Infrastructure\n\n- [ ] Make playground components reusable for others\n- [ ] Web worker for transpiles (freezer - not needed yet)\n- [x] Retarget Firebase as host platform (vs GitHub Pages)\n- [ ] Universal LLM endpoint with real LLMs (OpenAI, Anthropic, etc.)\n- [ ] ESM-as-a-service: versioned library endpoints\n- [ ] User accounts (Google sign-in) for API key storage\n- [ ] AJS-based Firestore and Storage security rules\n- [ ] npx tjs-playground - run playground locally with LM Studio\n- [ ] Virtual subdomains for user apps (yourapp.tjs.land)\n - [ ] Wildcard DNS to Firebase\n - [ ] Subdomain routing in Cloud Function\n - [ ] Deploy button in playground\n - [ ] Public/private visibility toggle\n- [ ] Rate limiting / abuse prevention for LLM endpoint\n- [ ] Usage tracking / billing foundation (for future paid tiers)\n\n---\n\n## Completed (this session)\n\n### Project Rename\n\n- [x] Rename from tosijs-agent to tjs-lang\n- [x] Update all references in package.json, docs, scripts\n\n### Timestamp & LegalDate Utilities\n\n- [x] Timestamp - pure functions, 1-based months, no Date warts (53 tests)\n - now, from, parse, tryParse\n - addDays/Hours/Minutes/Seconds/Weeks/Months/Years\n - diff, diffSeconds/Minutes/Hours/Days\n - year/month/day/hour/minute/second/millisecond/dayOfWeek\n - toLocal, format, formatDate, formatTime, toDate\n - isBefore/isAfter/isEqual/min/max\n - startOf/endOf Day/Month/Year\n- [x] LegalDate - pure functions, YYYY-MM-DD strings (55 tests)\n - today, todayIn, from, parse, tryParse\n - addDays/Weeks/Months/Years\n - diff, diffMonths, diffYears\n - year/month/day/dayOfWeek/weekOfYear/dayOfYear/quarter\n - isLeapYear, daysInMonth, daysInYear\n - toTimestamp, toUnix, fromUnix\n - format, formatLong, formatShort\n - isBefore/isAfter/isEqual/min/max/isBetween\n - startOf/endOf Month/Quarter/Year/Week\n- [x] Portable predicate helpers: isValidUrl, isValidTimestamp, isValidLegalDate\n\n### TJS Mode System (native TJS has all modes ON by default; TS-originated code defaults to OFF)\n\n- [x] Invert mode system - native TJS enables all modes; TS-originated/AJS code defaults to JS semantics\n- [x] TjsEquals directive - structural == and != (null == undefined)\n- [x] TjsClass directive - classes callable without new\n- [x] TjsDate directive - bans Date constructor/methods\n- [x] TjsNoeval directive - bans eval() and new Function()\n- [x] TjsStrict directive - enables all of the above\n- [x] TjsSafeEval directive - includes Eval/SafeFunction for dynamic code execution\n- [x] Updated Is() for nullish equality (null == undefined)\n- [x] Added Is/IsNot tests (structural equality, nullish handling)\n- [x] TjsStandard directive - newlines as statement terminators (prevents ASI footguns)\n- [x] WASM POC - wasm {} blocks with parsing, fallback mechanism, basic numeric compilation\n- [x] Eval/SafeFunction - proper VM-backed implementation with fuel metering and capabilities\n\n### Bundle Size Optimization\n\n- [x] Separated Eval/SafeFunction into standalone module (eval.ts)\n- [x] Created core.ts - AJS transpiler without TypeScript dependency\n- [x] Fixed tjs-transpiler bundle: 4.14MB → 88.9KB (27KB gzipped)\n- [x] Runtime is now ~5KB gzipped (just Is/IsNot, wrap, Type, etc.)\n- [x] Eval adds ~27KB gzipped (VM + AJS transpiler, no TypeScript)\n- [x] TypeScript only bundled in playground (5.8MB) for real-time TS transpilation\n"
1580
+ "text": "# TJS-Lang TODO\n\n## Playground - Error Navigation\n\n- [ ] Test errors: click should navigate to source location\n- [ ] Console errors: click should navigate to source location\n- [ ] Error in imported module: click through to source\n\n## Playground - Module Management\n\n- [ ] Import one example from another in playground\n- [ ] Save/Load TS examples (consistency with TJS examples)\n- [ ] File name should be linked to example name\n- [ ] New example button in playground\n- [ ] UI for managing stored modules (browse/delete IndexedDB)\n- [ ] Auto-discover and build local dependencies in module resolution\n\n## Language Features\n\n- [x] Honest boolean coercion (TjsStandard) — `Boolean(new Boolean(false))` and friends now return false. Source rewriter wraps every truthiness context (`if`/`while`/`for`/`do`/`!`/`&&`/`||`/`?:`, `Boolean(x)` calls) with `__tjs.toBool` which unwraps boxed primitives. Always-on under `TjsStandard`. Demo: `examples/js-footguns-fixed.tjs`. Doc: `guides/footguns.md`.\n- [ ] Intra-function type safety — bring TJS to parity with TS / good linters\n - [ ] **Tier 1 (lint):** `TjsTypedLet` mode — warn/error on `let` without type annotation. Follows the `TjsNoVar` precedent (`src/lang/parser.ts:214`). Severity gated by mode (info under `TjsStandard`, error under `TjsStrict`). ~30 lines in `src/lang/linter.ts`.\n - [ ] **Tier 2 (compile-time inference):** infer `TypeDescriptor` from initializer (already have `src/lang/inference.ts`), store per-decl in scope, walk subsequent `AssignmentExpression` nodes, warn on type-incompatible reassignment. ~200–300 lines, linter-only, no codegen changes.\n - [ ] **Tier 3 (runtime checks, long-term):** rewrite `let x = e` / `x = e` in the JS emitter to `__tjs.checkType(...)` so out-of-band assignments return MonadicError. Open design questions: closed-over `let`s, uninitialized `let x`, perf cost of per-assignment call. Defer until we see how Tier 1+2 land.\n- [ ] Audit monadic-error propagation when an error is nested inside a parameter (esp. arrays)\n - Rule: a MonadicError reaching a checked boundary should surface as ONE error, not as data containing an error (e.g. `[5, <error>, 7]`).\n - Caveat: if the function never inspects the param, no error needs to fire — propagation is on-check, not eager.\n - Partial coverage today: input-validation in emitted JS scans top-level array params for an embedded MonadicError and re-propagates it (commit `3db372d`). Other paths likely miss this — return values, deeper nesting (object fields, arrays-of-arrays), function-typed params whose callbacks return arrays containing errors, etc.\n - Investigate: where does a MonadicError survive past a boundary as data? Audit `checkType` in `src/lang/runtime.ts`, the emitted-JS validation prefix in `src/lang/emitters/js.ts`, and `checkFnShape` interaction with array returns.\n- [ ] Portable Type predicates - expression-only AJS subset (no loops, no async, serializable)\n- [ ] Sync AJS / AJS-to-JS compilation - for type-checked AJS that passes static analysis, transpile to native JS with fuel injection points. Enables both type safety guarantees AND native performance for RBAC rules, predicates, etc.\n- [ ] Self-contained transpiler output (no runtime dependency)\n - Currently transpiled code references `globalThis.__tjs` for pushStack/popStack, typeError, Is/IsNot\n - Requires runtime to be installed or a stub (see playground's manual \\_\\_tjs stub)\n - Goal: TJS produces completely independent code, only needing semantic dependencies\n - Options: inline minimal runtime (~1KB), `{ standalone: true }` option, or tree-shake\n - See: src/lang/emitters/js.ts TODO comment for details\n- [x] WASM compilation at transpile time (not runtime)\n - [x] Compile wasm {} blocks during transpilation\n - [x] Embed base64-encoded WASM bytes in output\n - [x] Include WAT disassembly as comment for debugging/learning\n - [x] Self-contained async instantiation (no separate compileWasmBlocksForIframe)\n- [x] Expand WASM support beyond POC\n - [x] For loops with numeric bounds\n - [x] Conditionals (if/else)\n - [x] Local variables within block\n - [x] Typed array access (Float32Array, Float64Array, Int32Array, Uint8Array)\n - [x] Memory operations\n - [x] Continue/break statements\n - [x] Logical expressions (&& / ||)\n - [x] Math functions (sqrt, abs, floor, ceil, min, max, sin, cos, log, exp, pow)\n- [x] WASM SIMD support (v128/f32x4)\n - 12 f32x4 intrinsics: load, store, splat, extract_lane, replace_lane, add, sub, mul, div, neg, sqrt\n - Explicit intrinsic approach (users call f32x4\\_\\* in wasm blocks)\n - Disassembler handles 0xfd prefix with LEB128 sub-opcodes\n - 16-byte aligned memory for v128 loads/stores\n - Demos: starfield SIMD rotation, vector search cosine similarity\n- [ ] WASM SIMD vector search (batteries)\n - Replace JS vectorSearch battery with WASM SIMD implementation\n - SIMD cosine similarity demonstrated in vector search demo\n - TODO: integrate as a battery atom with auto-detect + fallback\n\n## Editor\n\n- [ ] Embedded AJS syntax highlighting\n\n## Documentation / Examples\n\n- [ ] Create an endpoint example\n- [ ] Fold docs and tests into one panel, with passing tests collapsed by default (ts -> tjs inserts test; tjs -> js turns test blocks into documentation along with outcomes).\n- [ ] Dim/hide the preview tab if nothing ever changed it\n- [ ] Single source of truth for version number. I note the badge displayed in console is not matching the version. No hardwired versions -- version number is pulled from package.json and written to version.ts somewhere and that is the single source of truth.\n\n## Infrastructure\n\n- [ ] Make playground components reusable for others\n- [ ] Web worker for transpiles (freezer - not needed yet)\n- [x] Retarget Firebase as host platform (vs GitHub Pages)\n- [ ] Universal LLM endpoint with real LLMs (OpenAI, Anthropic, etc.)\n- [ ] ESM-as-a-service: versioned library endpoints\n- [ ] User accounts (Google sign-in) for API key storage\n- [ ] AJS-based Firestore and Storage security rules\n- [ ] npx tjs-playground - run playground locally with LM Studio\n- [ ] Virtual subdomains for user apps (yourapp.tjs.land)\n - [ ] Wildcard DNS to Firebase\n - [ ] Subdomain routing in Cloud Function\n - [ ] Deploy button in playground\n - [ ] Public/private visibility toggle\n- [ ] Rate limiting / abuse prevention for LLM endpoint\n- [ ] Usage tracking / billing foundation (for future paid tiers)\n\n---\n\n## Completed (this session)\n\n### Project Rename\n\n- [x] Rename from tosijs-agent to tjs-lang\n- [x] Update all references in package.json, docs, scripts\n\n### Timestamp & LegalDate Utilities\n\n- [x] Timestamp - pure functions, 1-based months, no Date warts (53 tests)\n - now, from, parse, tryParse\n - addDays/Hours/Minutes/Seconds/Weeks/Months/Years\n - diff, diffSeconds/Minutes/Hours/Days\n - year/month/day/hour/minute/second/millisecond/dayOfWeek\n - toLocal, format, formatDate, formatTime, toDate\n - isBefore/isAfter/isEqual/min/max\n - startOf/endOf Day/Month/Year\n- [x] LegalDate - pure functions, YYYY-MM-DD strings (55 tests)\n - today, todayIn, from, parse, tryParse\n - addDays/Weeks/Months/Years\n - diff, diffMonths, diffYears\n - year/month/day/dayOfWeek/weekOfYear/dayOfYear/quarter\n - isLeapYear, daysInMonth, daysInYear\n - toTimestamp, toUnix, fromUnix\n - format, formatLong, formatShort\n - isBefore/isAfter/isEqual/min/max/isBetween\n - startOf/endOf Month/Quarter/Year/Week\n- [x] Portable predicate helpers: isValidUrl, isValidTimestamp, isValidLegalDate\n\n### TJS Mode System (native TJS has all modes ON by default; TS-originated code defaults to OFF)\n\n- [x] Invert mode system - native TJS enables all modes; TS-originated/AJS code defaults to JS semantics\n- [x] TjsEquals directive - structural == and != (null == undefined)\n- [x] TjsClass directive - classes callable without new\n- [x] TjsDate directive - bans Date constructor/methods\n- [x] TjsNoeval directive - bans eval() and new Function()\n- [x] TjsStrict directive - enables all of the above\n- [x] TjsSafeEval directive - includes Eval/SafeFunction for dynamic code execution\n- [x] Updated Is() for nullish equality (null == undefined)\n- [x] Added Is/IsNot tests (structural equality, nullish handling)\n- [x] TjsStandard directive - newlines as statement terminators (prevents ASI footguns)\n- [x] WASM POC - wasm {} blocks with parsing, fallback mechanism, basic numeric compilation\n- [x] Eval/SafeFunction - proper VM-backed implementation with fuel metering and capabilities\n\n### Bundle Size Optimization\n\n- [x] Separated Eval/SafeFunction into standalone module (eval.ts)\n- [x] Created core.ts - AJS transpiler without TypeScript dependency\n- [x] Fixed tjs-transpiler bundle: 4.14MB → 88.9KB (27KB gzipped)\n- [x] Runtime is now ~5KB gzipped (just Is/IsNot, wrap, Type, etc.)\n- [x] Eval adds ~27KB gzipped (VM + AJS transpiler, no TypeScript)\n- [x] TypeScript only bundled in playground (5.8MB) for real-time TS transpilation\n"
1547
1581
  },
1548
1582
  {
1549
1583
  "title": "TJS: Typed JavaScript",
@@ -37,6 +37,7 @@ describe('TJS Playground Examples with tests', () => {
37
37
  'React Todo (Comparison)', // comparison example, not runnable
38
38
  'tosijs Todo App', // requires tosijs runtime
39
39
  'Full-Stack Demo: Client App', // requires saved module
40
+ 'CDN Hints (overriding the default)', // imports tosijs and date-fns
40
41
  ])
41
42
 
42
43
  for (const example of tjsExamples) {
@@ -34,13 +34,13 @@ describe('extractImports', () => {
34
34
  })
35
35
 
36
36
  describe('rewriteImports', () => {
37
- it('should rewrite bare specifiers to /tfs/', () => {
37
+ it('should rewrite bare specifiers to /tfs/ URLs', () => {
38
38
  expect(rewriteImports(`import { foo } from 'tosijs'`)).toBe(
39
39
  `import { foo } from '/tfs/tosijs'`
40
40
  )
41
41
  })
42
42
 
43
- it('should handle versioned specifiers', () => {
43
+ it('should preserve versioned specifiers', () => {
44
44
  expect(rewriteImports(`import { x } from 'tosijs@1.3.11'`)).toBe(
45
45
  `import { x } from '/tfs/tosijs@1.3.11'`
46
46
  )
@@ -52,12 +52,24 @@ describe('rewriteImports', () => {
52
52
  ).toBe(`import { debounce } from '/tfs/lodash-es/debounce'`)
53
53
  })
54
54
 
55
+ it('should handle react-dom/client', () => {
56
+ expect(
57
+ rewriteImports(`import { createRoot } from 'react-dom/client'`)
58
+ ).toBe(`import { createRoot } from '/tfs/react-dom/client'`)
59
+ })
60
+
55
61
  it('should handle scoped packages', () => {
56
62
  expect(rewriteImports(`import { x } from '@scope/pkg'`)).toBe(
57
63
  `import { x } from '/tfs/@scope/pkg'`
58
64
  )
59
65
  })
60
66
 
67
+ it('should handle scoped packages with version and subpath', () => {
68
+ expect(rewriteImports(`import { x } from '@scope/pkg@1.0.0/sub'`)).toBe(
69
+ `import { x } from '/tfs/@scope/pkg@1.0.0/sub'`
70
+ )
71
+ })
72
+
61
73
  it('should not rewrite relative imports', () => {
62
74
  expect(rewriteImports(`import { x } from './local'`)).toBe(
63
75
  `import { x } from './local'`
@@ -79,8 +91,8 @@ describe('rewriteImports', () => {
79
91
  it('should handle multiple imports', () => {
80
92
  const source = `import { a } from 'pkg-a'\nimport { b } from 'pkg-b'`
81
93
  const result = rewriteImports(source)
82
- expect(result).toContain("from '/tfs/pkg-a'")
83
- expect(result).toContain("from '/tfs/pkg-b'")
94
+ expect(result).toContain(`from '/tfs/pkg-a'`)
95
+ expect(result).toContain(`from '/tfs/pkg-b'`)
84
96
  })
85
97
 
86
98
  it('should handle re-exports', () => {