@nifrajs/cli 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/assure-hydration.d.ts.map +1 -1
- package/dist/assure-hydration.js +6 -1
- package/dist/assure-hydration.js.map +1 -1
- package/dist/assure.d.ts.map +1 -1
- package/dist/assure.js +3 -2
- package/dist/assure.js.map +1 -1
- package/dist/check-diagnostics.d.ts +165 -0
- package/dist/check-diagnostics.d.ts.map +1 -0
- package/dist/check-diagnostics.js +1009 -0
- package/dist/check-diagnostics.js.map +1 -0
- package/dist/check-scan.d.ts +245 -0
- package/dist/check-scan.d.ts.map +1 -0
- package/dist/check-scan.js +1599 -0
- package/dist/check-scan.js.map +1 -0
- package/dist/check.d.ts +4 -324
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +8 -2366
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +247 -10
- package/dist/cli.js.map +1 -1
- package/dist/command-catalog.d.ts +21 -1
- package/dist/command-catalog.d.ts.map +1 -1
- package/dist/command-catalog.js +122 -0
- package/dist/command-catalog.js.map +1 -1
- package/dist/env-file.js +5 -5
- package/dist/env-file.js.map +1 -1
- package/dist/frontend-guidance.d.ts +57 -0
- package/dist/frontend-guidance.d.ts.map +1 -0
- package/dist/frontend-guidance.js +195 -0
- package/dist/frontend-guidance.js.map +1 -0
- package/dist/levels-tool.d.ts.map +1 -1
- package/dist/levels-tool.js +6 -0
- package/dist/levels-tool.js.map +1 -1
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +4 -1
- package/dist/load.js.map +1 -1
- package/dist/mcp-context.d.ts +48 -0
- package/dist/mcp-context.d.ts.map +1 -0
- package/dist/mcp-context.js +215 -0
- package/dist/mcp-context.js.map +1 -0
- package/dist/mcp-docs-tools.d.ts.map +1 -1
- package/dist/mcp-docs-tools.js +31 -0
- package/dist/mcp-docs-tools.js.map +1 -1
- package/dist/mcp-exec.d.ts +74 -0
- package/dist/mcp-exec.d.ts.map +1 -0
- package/dist/mcp-exec.js +844 -0
- package/dist/mcp-exec.js.map +1 -0
- package/dist/mcp-http.js +1 -1
- package/dist/mcp-io.d.ts +26 -0
- package/dist/mcp-io.d.ts.map +1 -0
- package/dist/mcp-io.js +100 -0
- package/dist/mcp-io.js.map +1 -0
- package/dist/mcp-reflect.d.ts +16 -0
- package/dist/mcp-reflect.d.ts.map +1 -0
- package/dist/mcp-reflect.js +101 -0
- package/dist/mcp-reflect.js.map +1 -0
- package/dist/mcp-root.d.ts +7 -0
- package/dist/mcp-root.d.ts.map +1 -1
- package/dist/mcp-root.js +51 -3
- package/dist/mcp-root.js.map +1 -1
- package/dist/mcp.d.ts +10 -92
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +13 -1232
- package/dist/mcp.js.map +1 -1
- package/dist/openapi-tool.d.ts +5 -10
- package/dist/openapi-tool.d.ts.map +1 -1
- package/dist/openapi-tool.js +21 -2
- package/dist/openapi-tool.js.map +1 -1
- package/dist/openapi-types.d.ts +21 -0
- package/dist/openapi-types.d.ts.map +1 -0
- package/dist/openapi-types.js +214 -0
- package/dist/openapi-types.js.map +1 -0
- package/dist/port.d.ts.map +1 -1
- package/dist/port.js +2 -1
- package/dist/port.js.map +1 -1
- package/dist/project-facts.d.ts +2 -1
- package/dist/project-facts.d.ts.map +1 -1
- package/dist/project-facts.js.map +1 -1
- package/dist/release-verification.d.ts +4 -1
- package/dist/release-verification.d.ts.map +1 -1
- package/dist/release-verification.js +6 -138
- package/dist/release-verification.js.map +1 -1
- package/dist/rules/codes.d.ts +4 -0
- package/dist/rules/codes.d.ts.map +1 -1
- package/dist/rules/codes.js +4 -0
- package/dist/rules/codes.js.map +1 -1
- package/dist/rules/islands.d.ts +4 -0
- package/dist/rules/islands.d.ts.map +1 -0
- package/dist/rules/islands.js +155 -0
- package/dist/rules/islands.js.map +1 -0
- package/dist/rules/nano.d.ts +6 -0
- package/dist/rules/nano.d.ts.map +1 -0
- package/dist/rules/nano.js +264 -0
- package/dist/rules/nano.js.map +1 -0
- package/dist/rules/security.d.ts.map +1 -1
- package/dist/rules/security.js +38 -4
- package/dist/rules/security.js.map +1 -1
- package/dist/scaffold.d.ts +12 -6
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +149 -10
- package/dist/scaffold.js.map +1 -1
- package/dist/search-terms.d.ts.map +1 -1
- package/dist/search-terms.js +5 -3
- package/dist/search-terms.js.map +1 -1
- package/dist/stylex-migrate.d.ts +38 -0
- package/dist/stylex-migrate.d.ts.map +1 -0
- package/dist/stylex-migrate.js +1052 -0
- package/dist/stylex-migrate.js.map +1 -0
- package/dist/sync-manifest.d.ts.map +1 -1
- package/dist/sync-manifest.js +2 -1
- package/dist/sync-manifest.js.map +1 -1
- package/dist/verification-plan.d.ts +24 -0
- package/dist/verification-plan.d.ts.map +1 -0
- package/dist/verification-plan.js +116 -0
- package/dist/verification-plan.js.map +1 -0
- package/dist/work-graph.d.ts.map +1 -1
- package/dist/work-graph.js +6 -3
- package/dist/work-graph.js.map +1 -1
- package/docs/examples.json +36 -0
- package/docs/llms-full.txt +1226 -14
- package/docs/types.json +4185 -87
- package/package.json +9 -9
- package/src/assure-hydration.ts +6 -1
- package/src/assure.ts +4 -2
- package/src/check-diagnostics.ts +1219 -0
- package/src/check-scan.ts +1825 -0
- package/src/check.ts +47 -2752
- package/src/cli.ts +252 -10
- package/src/command-catalog.ts +155 -0
- package/src/env-file.ts +5 -5
- package/src/frontend-guidance.ts +259 -0
- package/src/levels-tool.ts +6 -0
- package/src/load.ts +4 -1
- package/src/mcp-context.ts +266 -0
- package/src/mcp-docs-tools.ts +37 -0
- package/src/mcp-exec.ts +1040 -0
- package/src/mcp-http.ts +1 -1
- package/src/mcp-io.ts +118 -0
- package/src/mcp-reflect.ts +140 -0
- package/src/mcp-root.ts +62 -4
- package/src/mcp.ts +61 -1511
- package/src/openapi-tool.ts +32 -2
- package/src/openapi-types.ts +261 -0
- package/src/port.ts +2 -1
- package/src/project-facts.ts +2 -4
- package/src/release-verification.ts +22 -164
- package/src/rules/codes.ts +4 -0
- package/src/rules/islands.ts +171 -0
- package/src/rules/nano.ts +295 -0
- package/src/rules/security.ts +40 -4
- package/src/scaffold.ts +169 -9
- package/src/search-terms.ts +7 -3
- package/src/stylex-migrate.ts +1139 -0
- package/src/sync-manifest.ts +2 -1
- package/src/verification-plan.ts +242 -0
- package/src/work-graph.ts +6 -3
package/docs/llms-full.txt
CHANGED
|
@@ -1225,6 +1225,374 @@ if (document.documentElement.hasAttribute("data-nifra-hydrated")) start()
|
|
|
1225
1225
|
else document.addEventListener("nifra:hydrated", start, { once: true })
|
|
1226
1226
|
```
|
|
1227
1227
|
|
|
1228
|
+
## Nifra - Islands: the AI-safe interactivity lane
|
|
1229
|
+
|
|
1230
|
+
> Add interactivity to a zero-runtime vanilla page with islands - imperative DOM enhancers, no framework runtime, no hydration. Explicit code an AI (or a human) gets right first try: mount, coordinate over a typed bus, always return cleanup.
|
|
1231
|
+
|
|
1232
|
+
A `@nifrajs/web-vanilla` page ships zero framework runtime. When one corner needs
|
|
1233
|
+
to be interactive, you don't turn on hydration - you mount an **island**: a
|
|
1234
|
+
small, plain-DOM enhancer over a server-rendered element. Explicit imperative code with no
|
|
1235
|
+
hidden reactivity - the shape an AI agent (or a human) gets right on the first try.
|
|
1236
|
+
|
|
1237
|
+
### Why islands, not hydration
|
|
1238
|
+
|
|
1239
|
+
Vanilla routes set `export const hydrate = false` - there is no client framework
|
|
1240
|
+
to hydrate with, and that is the point. The five framework adapters give you a reactive
|
|
1241
|
+
runtime and pay for it in client JS and in the subtle failure modes (stale closures,
|
|
1242
|
+
hydration mismatch, what-re-runs-when) that trip up generated code. Islands take the other
|
|
1243
|
+
trade: no runtime, no reactivity to get wrong. You wire the DOM by hand and hand back a
|
|
1244
|
+
teardown. Reach for a framework adapter when you genuinely need a stateful app UI; reach for
|
|
1245
|
+
islands for widgets on an otherwise-static page.
|
|
1246
|
+
|
|
1247
|
+
### Mount an island
|
|
1248
|
+
|
|
1249
|
+
Render a `<nifra-island>` marker in your page (props are inline JSON), then
|
|
1250
|
+
bundle one entry that calls `mountIslands`. Load it via the route's
|
|
1251
|
+
`islandScripts`.
|
|
1252
|
+
|
|
1253
|
+
```ts
|
|
1254
|
+
// doc-check: skip - server-rendered island marker (HTML, not a checkable module).
|
|
1255
|
+
// In your @nifrajs/web-vanilla page, render the host element with inline JSON props:
|
|
1256
|
+
html`<nifra-island data-id="counter" data-props=${JSON.stringify({ start: 0 })}>
|
|
1257
|
+
<output>0</output>
|
|
1258
|
+
<button type="button">+1</button>
|
|
1259
|
+
</nifra-island>`
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
```ts
|
|
1263
|
+
// doc-check: skip - browser DOM enhancer, typechecked in @nifrajs/web under its DOM lib.
|
|
1264
|
+
import { defineIsland, mountIslands } from "@nifrajs/web/islands"
|
|
1265
|
+
|
|
1266
|
+
// defineIsland pins the data-props type; the body is plain imperative DOM. ALWAYS return the
|
|
1267
|
+
// teardown for anything you wire - mountIslands calls it on soft-nav (NF-C020 warns if you forget).
|
|
1268
|
+
const counter = defineIsland<{ start: number }>((el, props) => {
|
|
1269
|
+
let n = props.start
|
|
1270
|
+
const out = el.querySelector("output")!
|
|
1271
|
+
const onClick = () => { out.textContent = String(++n) }
|
|
1272
|
+
el.querySelector("button")?.addEventListener("click", onClick)
|
|
1273
|
+
return () => el.querySelector("button")?.removeEventListener("click", onClick)
|
|
1274
|
+
})
|
|
1275
|
+
|
|
1276
|
+
// One bundle entry, loaded via the route's `islandScripts`.
|
|
1277
|
+
mountIslands({ counter })
|
|
1278
|
+
```
|
|
1279
|
+
|
|
1280
|
+
`defineIsland<Props>` is a zero-cost identity helper - its only job is to
|
|
1281
|
+
type `props` and `el` so the body needs no cast. Keep the body
|
|
1282
|
+
imperative: read the DOM, add listeners, **return the cleanup**. The returned
|
|
1283
|
+
function runs on soft-nav teardown; forget it and every navigation leaks the listener -
|
|
1284
|
+
`nifra check` flags exactly that as `NF-C020`.
|
|
1285
|
+
|
|
1286
|
+
### Coordinate islands with a typed bus
|
|
1287
|
+
|
|
1288
|
+
Islands are isolated by design - each enhances one element and shares no state. When two must
|
|
1289
|
+
talk (an “add to cart” button and a cart badge), use a
|
|
1290
|
+
`createIslandBus`: one typed channel, created once and closed over by each
|
|
1291
|
+
enhancer. No implicit global, so concurrent renders and tests never cross-talk.
|
|
1292
|
+
|
|
1293
|
+
```ts
|
|
1294
|
+
import { createIslandBus } from "@nifrajs/web/islands"
|
|
1295
|
+
|
|
1296
|
+
// One typed channel, created once and closed over by every enhancer that needs it.
|
|
1297
|
+
type CartEvents = { "cart:add": { sku: string }; "cart:count": number }
|
|
1298
|
+
const bus = createIslandBus<CartEvents>()
|
|
1299
|
+
|
|
1300
|
+
const off = bus.on("cart:count", (n) => console.log("cart now has", n, "items"))
|
|
1301
|
+
bus.emit("cart:add", { sku: "ABC-1" })
|
|
1302
|
+
off() // unsubscribe - also usable directly as an island's cleanup
|
|
1303
|
+
```
|
|
1304
|
+
|
|
1305
|
+
The bus is synchronous, in-memory, and carries no history - a subscriber sees only events
|
|
1306
|
+
emitted after it subscribes. A throwing handler is isolated from the others. Because
|
|
1307
|
+
`on()` returns its own unsubscribe, an enhancer whose only job is to listen can
|
|
1308
|
+
return it directly as its cleanup:
|
|
1309
|
+
|
|
1310
|
+
```ts
|
|
1311
|
+
// doc-check: skip - browser DOM enhancer, typechecked in @nifrajs/web under its DOM lib.
|
|
1312
|
+
import { createIslandBus, defineIsland, mountIslands } from "@nifrajs/web/islands"
|
|
1313
|
+
|
|
1314
|
+
type CartEvents = { "cart:add": { sku: string }; "cart:count": number }
|
|
1315
|
+
const bus = createIslandBus<CartEvents>()
|
|
1316
|
+
|
|
1317
|
+
// Two islands that never import each other - they meet only on the bus.
|
|
1318
|
+
const addButton = defineIsland<{ sku: string }>((el, props) => {
|
|
1319
|
+
const onClick = () => bus.emit("cart:add", { sku: props.sku })
|
|
1320
|
+
el.addEventListener("click", onClick)
|
|
1321
|
+
return () => el.removeEventListener("click", onClick)
|
|
1322
|
+
})
|
|
1323
|
+
|
|
1324
|
+
let count = 0
|
|
1325
|
+
const badge = defineIsland((el) => {
|
|
1326
|
+
const unsubscribe = bus.on("cart:add", () => {
|
|
1327
|
+
count += 1
|
|
1328
|
+
el.textContent = String(count)
|
|
1329
|
+
bus.emit("cart:count", count)
|
|
1330
|
+
})
|
|
1331
|
+
return unsubscribe // the on() unsubscribe IS the cleanup
|
|
1332
|
+
})
|
|
1333
|
+
|
|
1334
|
+
mountIslands({ addButton, badge })
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
### Pattern: filter drives results
|
|
1338
|
+
|
|
1339
|
+
The same shape scales to any “one island changes, another reacts” case. Each
|
|
1340
|
+
island owns only its own DOM; they meet on the channel, never in a shared store.
|
|
1341
|
+
|
|
1342
|
+
```ts
|
|
1343
|
+
// doc-check: skip - browser DOM enhancer, typechecked in @nifrajs/web under its DOM lib.
|
|
1344
|
+
import { createIslandBus, defineIsland, mountIslands } from "@nifrajs/web/islands"
|
|
1345
|
+
|
|
1346
|
+
// filter -> results, one directional channel. The results island owns its own DOM; the filter
|
|
1347
|
+
// island owns none of it. No shared store, no reactive tree - a message and two enhancers.
|
|
1348
|
+
const bus = createIslandBus<{ "filter:set": string }>()
|
|
1349
|
+
|
|
1350
|
+
const filter = defineIsland((el) => {
|
|
1351
|
+
const input = el.querySelector("input")!
|
|
1352
|
+
const onInput = () => bus.emit("filter:set", input.value.toLowerCase())
|
|
1353
|
+
input.addEventListener("input", onInput)
|
|
1354
|
+
return () => input.removeEventListener("input", onInput)
|
|
1355
|
+
})
|
|
1356
|
+
|
|
1357
|
+
const results = defineIsland((el) =>
|
|
1358
|
+
bus.on("filter:set", (q) => {
|
|
1359
|
+
for (const row of el.querySelectorAll<HTMLElement>("[data-name]")) {
|
|
1360
|
+
const name = row.dataset.name ?? ""
|
|
1361
|
+
row.hidden = q !== "" && !name.toLowerCase().includes(q)
|
|
1362
|
+
}
|
|
1363
|
+
}),
|
|
1364
|
+
)
|
|
1365
|
+
|
|
1366
|
+
mountIslands({ filter, results })
|
|
1367
|
+
```
|
|
1368
|
+
|
|
1369
|
+
### Load strategies
|
|
1370
|
+
|
|
1371
|
+
A marker's `data-strategy` defers its enhancer: `load` (default),
|
|
1372
|
+
`idle`, `visible` (mount when it scrolls into view), or a
|
|
1373
|
+
`media` query. An island with no matching enhancer, or an invalid strategy, stays
|
|
1374
|
+
inert server-rendered HTML - forward-compatible, never a runtime error.
|
|
1375
|
+
|
|
1376
|
+
## Nifra - nano: explicit reactivity for small apps
|
|
1377
|
+
|
|
1378
|
+
> nano is the AI-safe small-app lane: signal + computed(fn, [deps]) + keyed bindList, no VDOM, no auto-tracking. Every reactive edge is a visible call, so its three mistakes are static lints (NF-C021/C022/C023) with a fix recipe - the same closed loop that makes the backend AI-safe, now on the frontend.
|
|
1379
|
+
|
|
1380
|
+
`@nifrajs/web/nano` is the middle lane between a static
|
|
1381
|
+
[island](/docs/islands) and a full framework adapter. It gives you a signal, a
|
|
1382
|
+
derived `computed`, and a keyed list - enough to build a small app with local
|
|
1383
|
+
state a human edits - and nothing else. No virtual DOM, no template compiler, no
|
|
1384
|
+
auto-tracking. Every reactive edge is a call you write, which is exactly what lets a tool
|
|
1385
|
+
catch the mistakes before runtime.
|
|
1386
|
+
|
|
1387
|
+
### Why a fourth lane
|
|
1388
|
+
|
|
1389
|
+
A framework fails generated code not because it is unfamiliar but because its reactivity is
|
|
1390
|
+
_implicit_: an effect silently tracks what it read, a stale closure captures the wrong
|
|
1391
|
+
value, a render mismatches hydration - all silent, all runtime. Preact fixes the
|
|
1392
|
+
**size** of that model (3 KB) but copies its footguns faithfully. nano
|
|
1393
|
+
fixes the **failure model** for the small-app band: dependencies are an explicit
|
|
1394
|
+
array, list keys are a required argument, cleanups are a returned value. Each of those is a
|
|
1395
|
+
thing a static check can see. Reach for nano when a page needs local state and a keyed list;
|
|
1396
|
+
reach for a [framework adapter](/docs/frameworks) the moment you need client
|
|
1397
|
+
routing, nested view state, or suspense.
|
|
1398
|
+
|
|
1399
|
+
### Signals and computed
|
|
1400
|
+
|
|
1401
|
+
A `signal` holds a value; `.get()` reads it and `.set(...)`
|
|
1402
|
+
replaces it (deduped with `Object.is`). A `computed` derives a value and
|
|
1403
|
+
declares its sources as an explicit deps array - it recomputes when a listed source changes,
|
|
1404
|
+
never by magic. Both are synchronous and framework-free.
|
|
1405
|
+
|
|
1406
|
+
```ts
|
|
1407
|
+
import { signal, computed } from "@nifrajs/web/nano"
|
|
1408
|
+
|
|
1409
|
+
// State is a signal: reads are .get(), writes are .set(...). Every edge is a call you can see.
|
|
1410
|
+
const count = signal(0)
|
|
1411
|
+
|
|
1412
|
+
// Derived state declares its dependencies EXPLICITLY - the array is the whole contract. It
|
|
1413
|
+
// recomputes when (and only when) a listed source changes. Object.is-deduped, like signal.
|
|
1414
|
+
const doubled = computed(() => count.get() * 2, [count])
|
|
1415
|
+
|
|
1416
|
+
const off = doubled.subscribe((v) => console.log("doubled is now", v))
|
|
1417
|
+
count.set(5) // logs: doubled is now 10
|
|
1418
|
+
off() // unsubscribe
|
|
1419
|
+
```
|
|
1420
|
+
|
|
1421
|
+
The deps array is the whole contract, and its one failure mode is catchable: a
|
|
1422
|
+
`computed` whose body reads a signal the array omits will never recompute when that
|
|
1423
|
+
signal changes. `nifra check` flags exactly that as `NF-C023` - the
|
|
1424
|
+
check reads which signals the body calls `.get()` on and compares them to the
|
|
1425
|
+
array. A framework's auto-tracked effect gives a tool nothing to compare, which is why
|
|
1426
|
+
the equivalent lint elsewhere is a best-effort warning, not a gate.
|
|
1427
|
+
|
|
1428
|
+
### Bind a signal to the DOM
|
|
1429
|
+
|
|
1430
|
+
`bind` is the one-value edge: it applies your function immediately and on every
|
|
1431
|
+
change, and returns a disposer. **Collect the disposer.** A bare
|
|
1432
|
+
`bind(...)` whose return value is discarded leaks its subscription on soft-nav -
|
|
1433
|
+
`nifra check` flags it as `NF-C021`.
|
|
1434
|
+
|
|
1435
|
+
```ts
|
|
1436
|
+
// doc-check: skip - browser DOM enhancer, typechecked in @nifrajs/web under its DOM lib.
|
|
1437
|
+
import { signal, bind } from "@nifrajs/web/nano"
|
|
1438
|
+
|
|
1439
|
+
const label = signal("hello")
|
|
1440
|
+
|
|
1441
|
+
// bind applies immediately AND on every change; it returns the disposer. COLLECT it - a bare
|
|
1442
|
+
// bind(...) that drops its return leaks the subscription on soft-nav (nifra check flags NF-C021).
|
|
1443
|
+
const off = bind(document.querySelector("h1")!, label, (el, v) => { el.textContent = v })
|
|
1444
|
+
label.set("world") // the <h1> updates synchronously
|
|
1445
|
+
// ...on teardown: off()
|
|
1446
|
+
```
|
|
1447
|
+
|
|
1448
|
+
### Keyed lists with bindList
|
|
1449
|
+
|
|
1450
|
+
`bindList` keeps a container's children in sync with an array by key - a keyed
|
|
1451
|
+
reconcile like a framework's list diff, but you spell the key out. Add, remove, and
|
|
1452
|
+
reorder reuse the matching node (preserving focus and scroll) instead of rebuilding the list.
|
|
1453
|
+
Key by a **stable id** on the item; keying by the array index reuses the wrong
|
|
1454
|
+
node on reorder, and `nifra check` flags it as `NF-C022`.
|
|
1455
|
+
|
|
1456
|
+
```ts
|
|
1457
|
+
// doc-check: skip - browser DOM enhancer, typechecked in @nifrajs/web under its DOM lib.
|
|
1458
|
+
import { signal, bindList } from "@nifrajs/web/nano"
|
|
1459
|
+
|
|
1460
|
+
interface Todo { id: string; text: string; done: boolean }
|
|
1461
|
+
const todos = signal<Todo[]>([])
|
|
1462
|
+
|
|
1463
|
+
// bindList keeps a container's children in sync with an array by KEY - a keyed reconcile, like a
|
|
1464
|
+
// framework's list diff, but explicit. Add/remove/reorder reuse the right node instead of rebuilding.
|
|
1465
|
+
const off = bindList(todos, document.querySelector("ul")!, {
|
|
1466
|
+
key: (t) => t.id, // a STABLE id on the item. Keying by the array index is NF-C022 - reorder breaks.
|
|
1467
|
+
create: (t) => { const li = document.createElement("li"); li.dataset.id = t.id; return li },
|
|
1468
|
+
update: (li, t) => { li.textContent = t.text; li.classList.toggle("done", t.done) },
|
|
1469
|
+
})
|
|
1470
|
+
|
|
1471
|
+
todos.set([...todos.get(), { id: crypto.randomUUID(), text: "buy milk", done: false }])
|
|
1472
|
+
// ...on teardown: off()
|
|
1473
|
+
```
|
|
1474
|
+
|
|
1475
|
+
### Async state with resource
|
|
1476
|
+
|
|
1477
|
+
`resource(fetcher, [deps])` is nano's answer to “suspense” - an
|
|
1478
|
+
async cell whose value is an explicit `{ status, value, error }` union.
|
|
1479
|
+
It runs the fetcher immediately and again whenever a declared dep changes, and it handles the
|
|
1480
|
+
two things people get wrong by hand: the fetcher receives an `AbortSignal`, and a
|
|
1481
|
+
superseded request is aborted with its late result dropped, so the newest fetch always wins -
|
|
1482
|
+
no stale-response flicker. There is no thrown promise and no magic boundary; it is a value you
|
|
1483
|
+
read or bind like any other.
|
|
1484
|
+
|
|
1485
|
+
```ts
|
|
1486
|
+
import { signal, resource } from "@nifrajs/web/nano"
|
|
1487
|
+
|
|
1488
|
+
const userId = signal(1)
|
|
1489
|
+
|
|
1490
|
+
// resource(fetcher, [deps]) is an async cell: it fetches immediately and again whenever a declared
|
|
1491
|
+
// dep changes. The fetcher gets an AbortSignal; a superseded fetch is aborted and its late result
|
|
1492
|
+
// dropped, so the newest request always wins - no stale-response flicker to hand-guard.
|
|
1493
|
+
const user = resource(async (sig) => {
|
|
1494
|
+
const res = await fetch(`/api/users/${userId.get()}`, { signal: sig })
|
|
1495
|
+
return (await res.json()) as { name: string }
|
|
1496
|
+
}, [userId])
|
|
1497
|
+
|
|
1498
|
+
// The value is an explicit union - status is "pending" | "error" | "ready", never a secret undefined.
|
|
1499
|
+
const off = user.subscribe((s) => {
|
|
1500
|
+
if (s.status === "ready") console.log("got", s.value.name)
|
|
1501
|
+
})
|
|
1502
|
+
userId.set(2) // refetches; the deps array is what NF-C023 checks against the fetcher's .get() reads
|
|
1503
|
+
// ...on teardown: off()
|
|
1504
|
+
```
|
|
1505
|
+
|
|
1506
|
+
The deps array is checked exactly like `computed`: a `resource` whose
|
|
1507
|
+
fetcher reads a signal the array omits won't refetch when it changes, and
|
|
1508
|
+
`nifra check` flags it as `NF-C023`. Bind it to the DOM with
|
|
1509
|
+
`bindResource`, which dispatches on `status` - one handler per state,
|
|
1510
|
+
`ready` required, so a still-loading value can never render as a stray
|
|
1511
|
+
`undefined`.
|
|
1512
|
+
|
|
1513
|
+
```ts
|
|
1514
|
+
// doc-check: skip - browser DOM enhancer, typechecked in @nifrajs/web under its DOM lib.
|
|
1515
|
+
import { signal, resource, bindResource } from "@nifrajs/web/nano"
|
|
1516
|
+
|
|
1517
|
+
const userId = signal(1)
|
|
1518
|
+
const user = resource(async (sig) => {
|
|
1519
|
+
const res = await fetch(`/api/users/${userId.get()}`, { signal: sig })
|
|
1520
|
+
return (await res.json()) as { name: string }
|
|
1521
|
+
}, [userId])
|
|
1522
|
+
|
|
1523
|
+
// bindResource dispatches on status - one handler per state, ready required. Like bind it returns a
|
|
1524
|
+
// disposer (a bare bindResource(...) that drops it is NF-C021).
|
|
1525
|
+
const off = bindResource(document.querySelector("[data-user]")!, user, {
|
|
1526
|
+
pending: (el) => { el.textContent = "Loading…" },
|
|
1527
|
+
ready: (el, u) => { el.textContent = u.name },
|
|
1528
|
+
error: (el) => { el.textContent = "Could not load user" },
|
|
1529
|
+
})
|
|
1530
|
+
// ...on teardown: off()
|
|
1531
|
+
```
|
|
1532
|
+
|
|
1533
|
+
### nano inside an island
|
|
1534
|
+
|
|
1535
|
+
nano owns state and DOM edges; an [island](/docs/islands) owns mount and teardown.
|
|
1536
|
+
Put the signals in the enhancer, collect every disposer, and return one cleanup that calls
|
|
1537
|
+
them all. Scaffold this shape with
|
|
1538
|
+
`nifra_scaffold { path, variant: "stateful" }` on a vanilla
|
|
1539
|
+
project - it emits the golden pattern below.
|
|
1540
|
+
|
|
1541
|
+
```ts
|
|
1542
|
+
// doc-check: skip - browser DOM enhancer, typechecked in @nifrajs/web under its DOM lib.
|
|
1543
|
+
import { defineIsland, mountIslands } from "@nifrajs/web/islands"
|
|
1544
|
+
import { signal, computed, bind, bindList } from "@nifrajs/web/nano"
|
|
1545
|
+
|
|
1546
|
+
interface Todo { id: string; text: string; done: boolean }
|
|
1547
|
+
|
|
1548
|
+
// nano lives INSIDE an island - the island owns mount/teardown, nano owns the state and the DOM edges.
|
|
1549
|
+
const todos = defineIsland<{ items: Todo[] }>((el, props) => {
|
|
1550
|
+
const items = signal<Todo[]>(props.items)
|
|
1551
|
+
const remaining = computed(() => items.get().filter((t) => !t.done).length, [items])
|
|
1552
|
+
|
|
1553
|
+
// Collect every disposer; the island's cleanup calls them all (this is what NF-C021 protects).
|
|
1554
|
+
const cleanups: Array<() => void> = []
|
|
1555
|
+
cleanups.push(bind(el.querySelector("[data-count]")!, remaining, (n, v) => {
|
|
1556
|
+
n.textContent = String(v) + " left"
|
|
1557
|
+
}))
|
|
1558
|
+
cleanups.push(bindList(items, el.querySelector("[data-list]")!, {
|
|
1559
|
+
key: (t) => t.id,
|
|
1560
|
+
create: (t) => { const li = document.createElement("li"); li.dataset.id = t.id; return li },
|
|
1561
|
+
update: (li, t) => { li.textContent = t.text; li.classList.toggle("done", t.done) },
|
|
1562
|
+
}))
|
|
1563
|
+
|
|
1564
|
+
const add = (text: string) =>
|
|
1565
|
+
items.set([...items.get(), { id: crypto.randomUUID(), text, done: false }])
|
|
1566
|
+
void add
|
|
1567
|
+
|
|
1568
|
+
return () => { for (const off of cleanups) off() }
|
|
1569
|
+
})
|
|
1570
|
+
|
|
1571
|
+
mountIslands({ todos })
|
|
1572
|
+
```
|
|
1573
|
+
|
|
1574
|
+
### The three checks
|
|
1575
|
+
|
|
1576
|
+
nano's explicitness is the whole point: because each reactive edge is a visible call, its
|
|
1577
|
+
three mistakes are static lints with a fix recipe - the same closed loop (`scaffold`
|
|
1578
|
+
→ `check` → `fix` → `verify`) that makes the
|
|
1579
|
+
backend AI-safe, now on the frontend.
|
|
1580
|
+
|
|
1581
|
+
-
|
|
1582
|
+
`NF-C021` - a `bind`/`bindList` whose disposer is
|
|
1583
|
+
discarded. Collect it; call it on teardown.
|
|
1584
|
+
|
|
1585
|
+
-
|
|
1586
|
+
`NF-C022` - a `bindList` keyed by the array index. Key by a stable id.
|
|
1587
|
+
|
|
1588
|
+
-
|
|
1589
|
+
`NF-C023` - a `computed` that reads a signal its deps omit. Add it to
|
|
1590
|
+
the deps array.
|
|
1591
|
+
|
|
1592
|
+
All three _warn_ - a false positive must never fail a build - and each carries a fix
|
|
1593
|
+
recipe an agent can apply. Where nano stops (client routing, nested views, suspense), stop
|
|
1594
|
+
adding nano and reach for `@nifrajs/web-preact` or another framework adapter.
|
|
1595
|
+
|
|
1228
1596
|
## Nifra - Streaming
|
|
1229
1597
|
|
|
1230
1598
|
> Streaming SSR, Suspense, and defer() in Nifra - on every runtime including the edge.
|
|
@@ -2967,6 +3335,7 @@ const image = createImageHandler({
|
|
|
2967
3335
|
root: "./public", // local sources resolve under here (traversal+symlink guarded)
|
|
2968
3336
|
allowedOrigins: ["https://cdn.example"], // remote sources: allowlist only (omit ⇒ none)
|
|
2969
3337
|
// maxWidth, maxSourceBytes, maxSourcePixels, concurrency, cacheMaxAge - all tunable
|
|
3338
|
+
// immutable: true, // only for content-versioned source URLs
|
|
2970
3339
|
})
|
|
2971
3340
|
|
|
2972
3341
|
// mount it in your router:
|
|
@@ -2989,9 +3358,10 @@ probe), and a concurrency semaphore bounding the CPU-heavy codec work.
|
|
|
2989
3358
|
|
|
2990
3359
|
-
|
|
2991
3360
|
**Correct + cacheable.** Never upscales past the intrinsic width; negotiates WebP via
|
|
2992
|
-
`Accept` (with `Vary: Accept`);
|
|
2993
|
-
`
|
|
2994
|
-
|
|
3361
|
+
`Accept` (with `Vary: Accept`); and hashes the emitted bytes for a strong
|
|
3362
|
+
`ETag`, so a changed source at the same URL cannot receive a false `304`.
|
|
3363
|
+
The mutable-safe default is a one-hour `max-age`; opt into `immutable` only
|
|
3364
|
+
when every source URL is content-versioned.
|
|
2995
3365
|
|
|
2996
3366
|
The handler reads the filesystem, so its _local-source_ path targets **Node/Bun servers**
|
|
2997
3367
|
- but the codec itself is a pluggable `ImageBackend`, so it runs anywhere (see below).
|
|
@@ -3819,6 +4189,48 @@ export const vitePlugins = [react()] // dev HMR (Fast Refresh)
|
|
|
3819
4189
|
// define = { __VUE_OPTIONS_API__: "true", ... } // Vue feature flags
|
|
3820
4190
|
```
|
|
3821
4191
|
|
|
4192
|
+
### Tailwind to StyleX
|
|
4193
|
+
|
|
4194
|
+
Nifra includes a conservative codemod for moving static Tailwind classes to StyleX. It is a dry
|
|
4195
|
+
run by default, so inspect the proposed edits first:
|
|
4196
|
+
|
|
4197
|
+
Supported static `className` attributes become `stylex.props(...)` calls
|
|
4198
|
+
backed by a local `stylex.create(...)` table. Responsive breakpoints and
|
|
4199
|
+
element-local pseudo-classes such as `hover:` are supported. Dynamic class
|
|
4200
|
+
expressions, arbitrary values, parent-dependent variants, and unknown utilities stay unchanged
|
|
4201
|
+
and are reported with file/line evidence. A non-zero exit status means manual migration issues
|
|
4202
|
+
remain.
|
|
4203
|
+
|
|
4204
|
+
StyleX compilation is native to Nifra's Bun pipeline. Install the runtime and compiler peers,
|
|
4205
|
+
then register both the browser and SSR transforms:
|
|
4206
|
+
|
|
4207
|
+
```ts
|
|
4208
|
+
# Install the runtime and the optional compiler peers.
|
|
4209
|
+
bun add @stylexjs/stylex
|
|
4210
|
+
bun add -d @babel/core @stylexjs/babel-plugin @babel/plugin-syntax-flow \
|
|
4211
|
+
@babel/plugin-syntax-jsx @babel/plugin-syntax-typescript
|
|
4212
|
+
```
|
|
4213
|
+
|
|
4214
|
+
```ts
|
|
4215
|
+
// nifra.config.ts - Bun's client and SSR build transforms.
|
|
4216
|
+
import { stylexBunPlugin } from "@nifrajs/web/plugins/stylex"
|
|
4217
|
+
|
|
4218
|
+
export const clientPlugins = [stylexBunPlugin("dom")]
|
|
4219
|
+
export const serverPlugins = [stylexBunPlugin("ssr")]
|
|
4220
|
+
```
|
|
4221
|
+
|
|
4222
|
+
If the project intentionally uses Vite, add the Vite adapter alongside its existing Vite
|
|
4223
|
+
transforms. Nifra will use Vite when `vitePlugins` are the app's only transforms:
|
|
4224
|
+
|
|
4225
|
+
```ts
|
|
4226
|
+
// doc-check: skip - requires the third-party Vite React plugin
|
|
4227
|
+
// If the app intentionally uses Vite, keep StyleX in vitePlugins.
|
|
4228
|
+
import react from "@vitejs/plugin-react"
|
|
4229
|
+
import { stylexVite } from "@nifrajs/web/plugins/stylex"
|
|
4230
|
+
|
|
4231
|
+
export const vitePlugins = [react(), stylexVite()]
|
|
4232
|
+
```
|
|
4233
|
+
|
|
3822
4234
|
### Scope
|
|
3823
4235
|
|
|
3824
4236
|
`nifra build` defaults to a self-hosted Bun server. Use `--target node`,
|
|
@@ -3828,7 +4240,7 @@ the command printed by the build.
|
|
|
3828
4240
|
|
|
3829
4241
|
## Nifra - Coding agents
|
|
3830
4242
|
|
|
3831
|
-
>
|
|
4243
|
+
> Nifra's agent layer: live MCP tools for coding agents, bounded typed turns, resumable evidence, a coding-agent host, browser views, A2A and AG-UI bridges, and token-only telemetry.
|
|
3832
4244
|
|
|
3833
4245
|
Nifra ships an MCP server. It is not a documentation lookup bolted onto a framework: an agent
|
|
3834
4246
|
can read the project, learn the real API, run actual requests against the backend it just
|
|
@@ -3993,8 +4405,8 @@ nifra levels --min 1
|
|
|
3993
4405
|
|
|
3994
4406
|
### Building agent features, not just serving them
|
|
3995
4407
|
|
|
3996
|
-
The tools above let an agent work on your app.
|
|
3997
|
-
the app you are building is itself an AI feature.
|
|
4408
|
+
The tools above let an agent work on your app. Nifra also provides provider-neutral building
|
|
4409
|
+
blocks for the opposite case, where the app you are building is itself an AI feature.
|
|
3998
4410
|
|
|
3999
4411
|
**
|
|
4000
4412
|
`@nifrajs/prompt`
|
|
@@ -4036,6 +4448,99 @@ serves a SQLite database as its own MCP server, fail-closed: allowlisted schema
|
|
|
4036
4448
|
default, and read-only queries only when you opt in, with plan verification. Handing a model a
|
|
4037
4449
|
database connection is not the same as handing it a query tool, and this is the second one.
|
|
4038
4450
|
|
|
4451
|
+
### Run a coding agent
|
|
4452
|
+
|
|
4453
|
+
`@nifrajs/agent-protocol` is the small versioned session and event contract.
|
|
4454
|
+
`@nifrajs/coding-agent` provides the standalone `nifra-agent` host with
|
|
4455
|
+
bounded sessions, checkpoints, workflows, extensions, verification, and authenticated local
|
|
4456
|
+
RPC. `@nifrajs/pi` is an optional Pi backend; other backends implement the same
|
|
4457
|
+
protocol port.
|
|
4458
|
+
|
|
4459
|
+
```ts
|
|
4460
|
+
bun add @nifrajs/coding-agent @nifrajs/pi
|
|
4461
|
+
|
|
4462
|
+
# Interactive, one-shot, JSON, and local RPC modes are available.
|
|
4463
|
+
bunx nifra-agent --backend pi
|
|
4464
|
+
bunx nifra-agent --backend pi --message "run the checks and explain failures"
|
|
4465
|
+
```
|
|
4466
|
+
|
|
4467
|
+
The public host keeps live queues and captured evidence bounded, filters verification process
|
|
4468
|
+
environments, and treats extensions as an explicit opt-in. The local process adapter and
|
|
4469
|
+
extension worker are crash-containment helpers, not hostile-code sandboxes.
|
|
4470
|
+
|
|
4471
|
+
### Expose the same agent to other clients
|
|
4472
|
+
|
|
4473
|
+
`@nifrajs/a2a` mounts an A2A 1.0 card and JSON-RPC/SSE binding.
|
|
4474
|
+
`@nifrajs/ag-ui` mounts the AG-UI event stream. Both drive the same bounded runner,
|
|
4475
|
+
compose step evidence with telemetry, and support typed human-in-the-loop continuation. Model
|
|
4476
|
+
ports, state stores, capabilities, and approval transports are injected per request.
|
|
4477
|
+
|
|
4478
|
+
```ts
|
|
4479
|
+
import { server } from "@nifrajs/core"
|
|
4480
|
+
import { mountA2A } from "@nifrajs/a2a"
|
|
4481
|
+
import { mountAgUI } from "@nifrajs/ag-ui"
|
|
4482
|
+
import type { AgentPorts } from "@nifrajs/agent"
|
|
4483
|
+
import { agent } from "./agent"
|
|
4484
|
+
|
|
4485
|
+
declare const myModelPort: AgentPorts["model"]
|
|
4486
|
+
declare const myStateStore: NonNullable<AgentPorts["state"]>
|
|
4487
|
+
|
|
4488
|
+
const app = server()
|
|
4489
|
+
const ports = () => ({
|
|
4490
|
+
model: myModelPort,
|
|
4491
|
+
capabilities: ["search.read"],
|
|
4492
|
+
state: myStateStore, // scope this to the request subject
|
|
4493
|
+
})
|
|
4494
|
+
|
|
4495
|
+
mountA2A(app, {
|
|
4496
|
+
agent,
|
|
4497
|
+
card: { url: "https://api.example.com/a2a", version: "1.0.0" },
|
|
4498
|
+
ports,
|
|
4499
|
+
})
|
|
4500
|
+
mountAgUI(app, { agent, ports })
|
|
4501
|
+
|
|
4502
|
+
// A2A: GET the card, POST JSON-RPC, optional SSE streaming.
|
|
4503
|
+
// AG-UI: POST RunAgentInput, receive the event stream over SSE.
|
|
4504
|
+
```
|
|
4505
|
+
|
|
4506
|
+
These mounts deliberately do not authenticate callers: put the route behind your application's
|
|
4507
|
+
auth and authorization middleware, and scope every injected port to the request subject.
|
|
4508
|
+
|
|
4509
|
+
### Browser views and the Workbench
|
|
4510
|
+
|
|
4511
|
+
`@nifrajs/agent-app` is a backend-free browser SDK for negotiated commands, ordered
|
|
4512
|
+
and resumable event streams, approvals, handoffs, and Run Studio projections. Its public views
|
|
4513
|
+
contain structure - statuses, counters, coordinates, and error codes - rather than prompts,
|
|
4514
|
+
tool payloads, model output, or filesystem paths. The optional Workbench uses that same surface:
|
|
4515
|
+
run `bun run --filter '@nifrajs/workbench' dev -- --cwd /path/to/project` for the
|
|
4516
|
+
local browser client.
|
|
4517
|
+
|
|
4518
|
+
```ts
|
|
4519
|
+
import { AgentAppClient, HttpAgentTransport } from "@nifrajs/agent-app"
|
|
4520
|
+
|
|
4521
|
+
declare function currentToken(): string
|
|
4522
|
+
declare function render(view: unknown): void
|
|
4523
|
+
|
|
4524
|
+
const client = new AgentAppClient(new HttpAgentTransport({
|
|
4525
|
+
endpoint: "http://127.0.0.1:8787",
|
|
4526
|
+
authorize: () => currentToken(), // minted per request; never stored by the transport
|
|
4527
|
+
}))
|
|
4528
|
+
|
|
4529
|
+
const session = await client.createSession()
|
|
4530
|
+
for await (const view of client.send("summarize the diff")) {
|
|
4531
|
+
render(view) // content-free status, counts, coordinates, and error codes
|
|
4532
|
+
}
|
|
4533
|
+
```
|
|
4534
|
+
|
|
4535
|
+
### Evidence, streaming, and telemetry
|
|
4536
|
+
|
|
4537
|
+
`@nifrajs/agent` runs bounded typed turns with tool contracts, budgets, approvals,
|
|
4538
|
+
resumable token-only evidence, model deltas, and a transient shared-state channel. Add an
|
|
4539
|
+
`evidenceLog` to the HTTP seams for SSE replay after a dropped connection; replay
|
|
4540
|
+
resumes evidence and never re-executes the turn. `@nifrajs/agent-telemetry` converts
|
|
4541
|
+
the same constrained evidence into fail-open OpenTelemetry run and step spans. Providers,
|
|
4542
|
+
credentials, durable storage, retention, and tenant policy remain application-owned ports.
|
|
4543
|
+
|
|
4039
4544
|
### Projects without a web config
|
|
4040
4545
|
|
|
4041
4546
|
A backend-only project - the shape `create-nifra`'s default template produces - has
|
|
@@ -7674,6 +8179,222 @@ level that regressed comes back with the reason it broke.
|
|
|
7674
8179
|
|
|
7675
8180
|
# Package reference (READMEs)
|
|
7676
8181
|
|
|
8182
|
+
## @nifrajs/a2a
|
|
8183
|
+
|
|
8184
|
+
Mount a nifra agent as an [Agent2Agent (A2A)](https://a2a-protocol.org) protocol server. The agent card is served on GET, the A2A 1.0 JSON-RPC binding on POST: `SendMessage` runs one bounded agent turn, `SendStreamingMessage` streams step evidence over SSE, `GetTask` projects the stored turn state.
|
|
8185
|
+
|
|
8186
|
+
A protocol bridge over [`@nifrajs/agent`](../agent) - the request body reuses core's single bounded, prototype-guarded trust boundary, and the model, durable state store, and approval transport are injected per request through the same `ports` factory `mountAgent` uses. Dependency-free beyond the two nifra peers.
|
|
8187
|
+
|
|
8188
|
+
## Install
|
|
8189
|
+
|
|
8190
|
+
```bash
|
|
8191
|
+
bun add @nifrajs/a2a @nifrajs/agent
|
|
8192
|
+
```
|
|
8193
|
+
|
|
8194
|
+
## Mount
|
|
8195
|
+
|
|
8196
|
+
```ts
|
|
8197
|
+
import { server } from "@nifrajs/core"
|
|
8198
|
+
import { mountA2A } from "@nifrajs/a2a"
|
|
8199
|
+
import { agent } from "./agent" // an AgentDefinition
|
|
8200
|
+
|
|
8201
|
+
const app = server()
|
|
8202
|
+
mountA2A(app, {
|
|
8203
|
+
agent,
|
|
8204
|
+
card: { url: "https://api.example.com/a2a", version: "1.0.0" },
|
|
8205
|
+
ports: (c) => ({
|
|
8206
|
+
model: myModelPort, // scope to the request subject
|
|
8207
|
+
capabilities: ["search.read"],
|
|
8208
|
+
state: myStateStore, // required for GetTask and resume
|
|
8209
|
+
}),
|
|
8210
|
+
})
|
|
8211
|
+
// GET /.well-known/agent-card.json - the agent card
|
|
8212
|
+
// POST /a2a - SendMessage | SendStreamingMessage | GetTask
|
|
8213
|
+
```
|
|
8214
|
+
|
|
8215
|
+
## Task mapping
|
|
8216
|
+
|
|
8217
|
+
One A2A task is one agent turn: `taskId` is the runner's `turnId`.
|
|
8218
|
+
|
|
8219
|
+
| Run result | Task state |
|
|
8220
|
+
| --- | --- |
|
|
8221
|
+
| completed with output | `TASK_STATE_COMPLETED` + an `output` artifact |
|
|
8222
|
+
| completed with a typed error | `TASK_STATE_FAILED` (error in `metadata`) |
|
|
8223
|
+
| suspended (approval, budget, model, max turns) | `TASK_STATE_INPUT_REQUIRED` |
|
|
8224
|
+
| suspended (cancelled) | `TASK_STATE_CANCELED` |
|
|
8225
|
+
|
|
8226
|
+
Agent input is `message.metadata.input` when present, otherwise the first `text` part. Structured output returns as a `text` part carrying JSON.
|
|
8227
|
+
|
|
8228
|
+
## Human-in-the-loop resume
|
|
8229
|
+
|
|
8230
|
+
A suspended task's status message carries the pending continuation in `metadata`. Send it back to continue the same task - the runtime keeps state token-only, so a suspended tool's input must be replayed in `continuation.input`:
|
|
8231
|
+
|
|
8232
|
+
```jsonc
|
|
8233
|
+
{
|
|
8234
|
+
"jsonrpc": "2.0", "id": 2, "method": "SendMessage",
|
|
8235
|
+
"params": {
|
|
8236
|
+
"message": {
|
|
8237
|
+
"messageId": "m2", "role": "ROLE_USER", "parts": [],
|
|
8238
|
+
"taskId": "<task id from the suspension>",
|
|
8239
|
+
"metadata": {
|
|
8240
|
+
"input": { "prompt": "go" },
|
|
8241
|
+
"resume": {
|
|
8242
|
+
"continuation": { "kind": "approval", "tool": "search.read", "effectId": "…", "input": { "q": "…" } },
|
|
8243
|
+
"approval": { "granted": true }
|
|
8244
|
+
}
|
|
8245
|
+
}
|
|
8246
|
+
}
|
|
8247
|
+
}
|
|
8248
|
+
}
|
|
8249
|
+
```
|
|
8250
|
+
|
|
8251
|
+
Cross-request registries (cancellation, subscription fan-out, push notifications) are deliberately out of scope for the stateless seam; those spec methods answer `UnsupportedOperationError` (-32004).
|
|
8252
|
+
|
|
8253
|
+
The seam performs no authentication or authorization - wrap it with your app's route guards and scope every port in `ports(c)` to the caller.
|
|
8254
|
+
|
|
8255
|
+
## Docs
|
|
8256
|
+
|
|
8257
|
+
Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework - one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
|
|
8258
|
+
|
|
8259
|
+
For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
|
|
8260
|
+
[`../../llms-full.txt`](../../llms-full.txt).
|
|
8261
|
+
|
|
8262
|
+
## @nifrajs/ag-ui
|
|
8263
|
+
|
|
8264
|
+
Mount a nifra agent as an [AG-UI](https://docs.ag-ui.com) (Agent-User Interaction protocol) endpoint: one POST accepting `RunAgentInput`, a stream of AG-UI events out over SSE - run lifecycle, step and tool-call events projected from the runner's step evidence, text message events for the output, and a typed continuation for human-in-the-loop resume.
|
|
8265
|
+
|
|
8266
|
+
A protocol bridge over [`@nifrajs/agent`](../agent) - the request body reuses core's single bounded, prototype-guarded trust boundary, and the model, durable state store, and approval transport are injected per request through the same `ports` factory `mountAgent` uses. Dependency-free beyond the two nifra peers.
|
|
8267
|
+
|
|
8268
|
+
## Install
|
|
8269
|
+
|
|
8270
|
+
```bash
|
|
8271
|
+
bun add @nifrajs/ag-ui @nifrajs/agent
|
|
8272
|
+
```
|
|
8273
|
+
|
|
8274
|
+
## Mount
|
|
8275
|
+
|
|
8276
|
+
```ts
|
|
8277
|
+
import { server } from "@nifrajs/core"
|
|
8278
|
+
import { mountAgUI } from "@nifrajs/ag-ui"
|
|
8279
|
+
import { agent } from "./agent" // an AgentDefinition
|
|
8280
|
+
|
|
8281
|
+
const app = server()
|
|
8282
|
+
mountAgUI(app, {
|
|
8283
|
+
agent,
|
|
8284
|
+
ports: (c) => ({
|
|
8285
|
+
model: myModelPort, // scope to the request subject
|
|
8286
|
+
capabilities: ["search.read"],
|
|
8287
|
+
state: myStateStore, // required for resume
|
|
8288
|
+
}),
|
|
8289
|
+
})
|
|
8290
|
+
// POST /agui - RunAgentInput in, AG-UI events out (SSE)
|
|
8291
|
+
```
|
|
8292
|
+
|
|
8293
|
+
## Event mapping
|
|
8294
|
+
|
|
8295
|
+
| Runner | AG-UI events |
|
|
8296
|
+
| --- | --- |
|
|
8297
|
+
| run starts | `RUN_STARTED`, then `CUSTOM { name: "nifra.turn" }` announcing the turn id |
|
|
8298
|
+
| tool evidence | `TOOL_CALL_START` / `TOOL_CALL_END`, then `TOOL_CALL_RESULT` whose `content` is the token-only outcome `{ "outcome": "committed" \| "failed" \| "denied", "code"? }` |
|
|
8299
|
+
| model, approval, budget, state evidence | `STEP_STARTED` / `STEP_FINISHED` |
|
|
8300
|
+
| model text deltas | live `TEXT_MESSAGE_START` / `_CONTENT` (see streaming below) |
|
|
8301
|
+
| model reasoning deltas | `REASONING_START` / `REASONING_MESSAGE_START` / `_CONTENT` / `_END` / `REASONING_END` |
|
|
8302
|
+
| model tool-args deltas | provisional `TOOL_CALL_START` + `TOOL_CALL_ARGS`, closed by the call's tool evidence |
|
|
8303
|
+
| shared state | `STATE_SNAPSHOT` on the seed and `STATE_DELTA` (RFC 6902 ops) per patch (see below) |
|
|
8304
|
+
| model usage deltas | summed per `(provider, model)` into the `usage: TokenUsage[]` array on `RUN_FINISHED` |
|
|
8305
|
+
| completed output | `TEXT_MESSAGE_START` / `_CONTENT` / `_END` (unless text was streamed), an optional `MESSAGES_SNAPSHOT` (see below), then `RUN_FINISHED` with `result` and `outcome: { "type": "success" }` |
|
|
8306
|
+
| completed with a typed error | `RUN_ERROR` |
|
|
8307
|
+
| suspended | `CUSTOM { name: "nifra.pending" }` with the continuation, then `RUN_FINISHED` with `outcome: { "type": "interrupt", "interrupts": [...] }` |
|
|
8308
|
+
|
|
8309
|
+
Evidence-derived events carry the evidence `timestamp`. The runtime is token-only by design - `TOOL_CALL_RESULT` reports the outcome and error code, never the tool's payload.
|
|
8310
|
+
|
|
8311
|
+
Agent input is `forwardedProps.input` when present, otherwise the content of the last `role: "user"` message.
|
|
8312
|
+
|
|
8313
|
+
## Token streaming
|
|
8314
|
+
|
|
8315
|
+
A model port that calls the request's optional `onDelta` callback (see `@nifrajs/agent`'s `AgentModelDelta`) streams live:
|
|
8316
|
+
|
|
8317
|
+
- `{ kind: "text", text }` opens a `TEXT_MESSAGE` and streams each chunk as `TEXT_MESSAGE_CONTENT`. When any text was streamed, the terminal text block is suppressed - the streamed text IS the assistant message, so a streaming port must stream all user-visible text. A non-streaming port keeps the single terminal block; nothing changes for it.
|
|
8318
|
+
- `{ kind: "reasoning", text }` streams a `REASONING_*` message.
|
|
8319
|
+
- `{ kind: "tool-args", name?, argsText }` opens a provisional `TOOL_CALL_START` (id `<turnId>:call:<n>`) and streams `TOOL_CALL_ARGS`. The tool evidence that follows closes the same call - `TOOL_CALL_END` plus the token-only `TOOL_CALL_RESULT` - instead of opening a second one.
|
|
8320
|
+
- `{ kind: "usage", provider?, model?, inputTokens?, ... }` never becomes a frame. The counts are summed per `(provider, model)` across the run's model decisions and stamped as the spec `usage: TokenUsage[]` array on the terminal `RUN_FINISHED` (success and interrupt alike); non-finite figures are ignored.
|
|
8321
|
+
|
|
8322
|
+
Each stream closes when a different delta kind starts, when tool evidence lands, or at the end of the run. Deltas are transient observer data: a `Last-Event-ID` replay carries evidence frames and the stored, unsuppressed terminal events only - the stored `RUN_FINISHED` keeps its `usage`.
|
|
8323
|
+
|
|
8324
|
+
## Shared state
|
|
8325
|
+
|
|
8326
|
+
The `ports` factory receives `(c, run)`; `run.sharedState` is the run's `AgentSharedState` channel and `run.turnId` the resolved turn id. `body.state` seeds the document and is announced with an upfront `STATE_SNAPSHOT`; every `patch` from a port or tool executor streams as `STATE_DELTA` carrying the RFC 6902 ops. A first patch on an unseeded document announces itself as a `STATE_SNAPSHOT` instead of a delta against a base the client never saw. The channel is per-run and transient - nothing in it is persisted.
|
|
8327
|
+
|
|
8328
|
+
```ts
|
|
8329
|
+
mountAgUI(app, {
|
|
8330
|
+
agent,
|
|
8331
|
+
ports: (c, run) => ({
|
|
8332
|
+
model: myStreamingModelPort(run.sharedState), // patch progress as the run advances
|
|
8333
|
+
capabilities: ["search.read"],
|
|
8334
|
+
}),
|
|
8335
|
+
})
|
|
8336
|
+
```
|
|
8337
|
+
|
|
8338
|
+
With `emitMessagesSnapshot: true`, a successful run also emits `MESSAGES_SNAPSHOT` - the request's `messages` echoed back with the assistant output message appended - before `RUN_FINISHED`. It is off by default: the snapshot echoes client message payloads, and terminal events persist to the evidence log when one is configured.
|
|
8339
|
+
|
|
8340
|
+
## Human-in-the-loop resume
|
|
8341
|
+
|
|
8342
|
+
A suspended run finishes with `outcome: { "type": "interrupt", "interrupts": [interrupt] }` where the interrupt is:
|
|
8343
|
+
|
|
8344
|
+
```jsonc
|
|
8345
|
+
{
|
|
8346
|
+
"id": "<turnId>",
|
|
8347
|
+
"reason": "approval", // approval | budget | model | cancelled | max_turns
|
|
8348
|
+
"toolCallId": "<effectId>", // present for tool suspensions
|
|
8349
|
+
"responseSchema": { /* JSON Schema for the resume payload */ },
|
|
8350
|
+
"metadata": { "turnId": "…", "continuation": { "kind": "approval", "tool": "…", "effectId": "…" } }
|
|
8351
|
+
}
|
|
8352
|
+
```
|
|
8353
|
+
|
|
8354
|
+
Resume with the AG-UI `resume` array. The runtime keeps state token-only - it holds no interrupt registry - so the payload must echo `metadata.continuation`, with the suspended tool's input replayed in `continuation.input`:
|
|
8355
|
+
|
|
8356
|
+
```jsonc
|
|
8357
|
+
{
|
|
8358
|
+
"threadId": "thread-1", "runId": "run-2", "messages": [],
|
|
8359
|
+
"forwardedProps": { "input": { "prompt": "go" } },
|
|
8360
|
+
"resume": [{
|
|
8361
|
+
"interruptId": "<interrupt id>",
|
|
8362
|
+
"status": "resolved", // "cancelled" without an approval resumes as a denial
|
|
8363
|
+
"payload": {
|
|
8364
|
+
"continuation": { "kind": "approval", "tool": "search.read", "effectId": "…", "input": { "q": "…" } },
|
|
8365
|
+
"approval": { "granted": true }
|
|
8366
|
+
}
|
|
8367
|
+
}]
|
|
8368
|
+
}
|
|
8369
|
+
```
|
|
8370
|
+
|
|
8371
|
+
The pre-interrupt form - the same `{ continuation, approval? }` object in `forwardedProps.resume` plus `forwardedProps.turnId` - keeps working. A resume that fails validation is ignored and the POST starts a fresh run.
|
|
8372
|
+
|
|
8373
|
+
## Resumable streams
|
|
8374
|
+
|
|
8375
|
+
Pass an `evidenceLog` to make a dropped SSE connection resumable. Evidence-derived frames then
|
|
8376
|
+
carry SSE `id: <seq>`; a client reconnects by re-POSTing the same body with a `Last-Event-ID`
|
|
8377
|
+
header and receives the missed events, rejoining a still-running turn live or replaying the stored
|
|
8378
|
+
terminal events - the run is never re-executed.
|
|
8379
|
+
|
|
8380
|
+
```ts
|
|
8381
|
+
import { createMemoryAgentEvidenceLog } from "@nifrajs/agent/events"
|
|
8382
|
+
|
|
8383
|
+
mountAgUI(app, { agent, ports, evidenceLog: createMemoryAgentEvidenceLog() })
|
|
8384
|
+
```
|
|
8385
|
+
|
|
8386
|
+
The in-memory log is the single-process dev/test reference; a durable, multi-process log is an
|
|
8387
|
+
adapter implementing the same `AgentEvidenceLog` interface.
|
|
8388
|
+
|
|
8389
|
+
The seam performs no authentication or authorization - wrap it with your app's route guards and scope every port in `ports(c)` to the caller.
|
|
8390
|
+
|
|
8391
|
+
## Docs
|
|
8392
|
+
|
|
8393
|
+
Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework - one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
|
|
8394
|
+
|
|
8395
|
+
For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
|
|
8396
|
+
[`../../llms-full.txt`](../../llms-full.txt).
|
|
8397
|
+
|
|
7677
8398
|
## @nifrajs/agent
|
|
7678
8399
|
|
|
7679
8400
|
Provider-neutral, typed, resumable agent turns over Nifra tool contracts.
|
|
@@ -7694,6 +8415,42 @@ const result = await runAgent(definition, { value: input }, ports, {
|
|
|
7694
8415
|
The public in-memory adapters are for local development and tests. Durable state, provider
|
|
7695
8416
|
credentials, and operated policy remain adapter concerns.
|
|
7696
8417
|
|
|
8418
|
+
Gateway and deployment contracts are deliberately provider-neutral. Retry, fallback, budget,
|
|
8419
|
+
deadline, workspace, and hostile-code isolation claims are admitted only from a host-approved
|
|
8420
|
+
capability report. The local and replay reference profiles are not hostile-code sandboxes, and no
|
|
8421
|
+
public package loads provider credentials or promises durable execution.
|
|
8422
|
+
|
|
8423
|
+
Several telemetry consumers can observe the same run: `combineAgentTelemetry(a, b, ...)` fans step
|
|
8424
|
+
evidence out to every port in order, so an SSE evidence stream and an exporter (for example
|
|
8425
|
+
`@nifrajs/agent-telemetry`'s `traceAgentRun`) compose instead of displacing each other. The HTTP
|
|
8426
|
+
seams (`mountAgent`, `@nifrajs/a2a`, `@nifrajs/ag-ui`) compose their streaming evidence with any
|
|
8427
|
+
telemetry port supplied through `ports`.
|
|
8428
|
+
|
|
8429
|
+
A model port can stream: when the caller wires an `AgentDeltaSink` into `ports.deltas`, every model
|
|
8430
|
+
request carries an optional `onDelta` callback the port may call per chunk - user-visible text,
|
|
8431
|
+
reasoning text, the raw argument text of the tool call being formed, or a `usage` delta reporting
|
|
8432
|
+
the decision's settled token counts (optionally attributed to a provider and model, for observers
|
|
8433
|
+
to sum across the run). Deltas are transient
|
|
8434
|
+
observer data for live UIs (`@nifrajs/ag-ui` projects them onto `TEXT_MESSAGE_*`, `REASONING_*`,
|
|
8435
|
+
and `TOOL_CALL_ARGS` frames): they are never validated, persisted, or replayed, and a failing sink
|
|
8436
|
+
never fails the model step. `combineAgentDeltaSinks(a, b, ...)` fans deltas out the way
|
|
8437
|
+
`combineAgentTelemetry` fans evidence.
|
|
8438
|
+
|
|
8439
|
+
`createAgentSharedState(initial)` is the run's shared UI state channel: a JSON document any port or
|
|
8440
|
+
tool executor patches with RFC 6902 operations (`add`, `replace`, `remove`), with subscribers
|
|
8441
|
+
observing every applied batch. Patches apply atomically - an invalid op rejects the whole batch -
|
|
8442
|
+
and prototype-grafting pointer segments are refused. The document is per-run observer data, not
|
|
8443
|
+
turn state: nothing in it is persisted by the runtime. `@nifrajs/ag-ui` projects the channel onto
|
|
8444
|
+
AG-UI `STATE_SNAPSHOT`/`STATE_DELTA` events.
|
|
8445
|
+
|
|
8446
|
+
SSE streams are resumable: give `mountAgent` (or `@nifrajs/ag-ui`'s `mountAgUI`) an `evidenceLog`
|
|
8447
|
+
and `step` frames carry `id: <seq>`. A client that loses the connection re-POSTs the same `turnId`
|
|
8448
|
+
with a `Last-Event-ID` header and receives the missed evidence, rejoining a still-running turn live
|
|
8449
|
+
or replaying the stored terminal frame - the run is never re-executed.
|
|
8450
|
+
`createMemoryAgentEvidenceLog` (from `@nifrajs/agent/events`) is the single-process dev/test
|
|
8451
|
+
reference; a durable, multi-process log is an adapter implementing the same `AgentEvidenceLog`
|
|
8452
|
+
interface.
|
|
8453
|
+
|
|
7697
8454
|
Execution policies can be required by a tool contract. `createLocalProcessAdapter` applies cwd and
|
|
7698
8455
|
environment filtering, timeouts, and cancellation to child processes. The local adapter is NOT a
|
|
7699
8456
|
security boundary. Without OS-level sandboxing it contains crashes and accidents, not hostile code.
|
|
@@ -7701,6 +8458,111 @@ security boundary. Without OS-level sandboxing it contains crashes and accidents
|
|
|
7701
8458
|
For the compact agent contract, see [`LLM.md`](./LLM.md). The full machine-readable corpus is
|
|
7702
8459
|
[`../../llms-full.txt`](../../llms-full.txt).
|
|
7703
8460
|
|
|
8461
|
+
## @nifrajs/agent-app
|
|
8462
|
+
|
|
8463
|
+
A presentation-safe browser SDK for Nifra agent hosts.
|
|
8464
|
+
|
|
8465
|
+
This package depends on **only** `@nifrajs/agent-protocol`. It pulls in no backend, model provider,
|
|
8466
|
+
storage, or UI framework, so it can be bundled into browser-facing code without dragging a private
|
|
8467
|
+
engine or payload content across the boundary. Everything it surfaces upward is a content-free view
|
|
8468
|
+
model: identifiers, lifecycle statuses, counters, and opaque references. A prompt becomes a character
|
|
8469
|
+
count; a tool result becomes an `ok` flag and an error *code*; a compaction becomes before/after token
|
|
8470
|
+
counts.
|
|
8471
|
+
|
|
8472
|
+
## What it does
|
|
8473
|
+
|
|
8474
|
+
- **Feature negotiation.** On session creation the client intersects the features it can drive with the
|
|
8475
|
+
capabilities the host advertises, and gates the matching operations behind `requireFeature`.
|
|
8476
|
+
- **Caller auth.** An optional `authorize` hook mints a bearer token per request. The token is placed
|
|
8477
|
+
on the outgoing `Authorization` header and never stored on the transport, copied into a result, or
|
|
8478
|
+
written to a log.
|
|
8479
|
+
- **Ordered, deduplicated streaming.** A turn arrives as an ordered stream of `AgentEventView`s.
|
|
8480
|
+
Out-of-order and redelivered frames are reordered and de-duplicated by sequence; a bounded buffer
|
|
8481
|
+
skips an unfilled gap rather than stalling.
|
|
8482
|
+
- **Cursor resume.** A persisted log can be replayed from a cursor. A cursor whose next record was
|
|
8483
|
+
evicted from the retained window asks the caller to resync.
|
|
8484
|
+
- **Approvals and handoffs.** Pending approvals list as identifiers; decisions and handoff outcomes go
|
|
8485
|
+
back through negotiated commands.
|
|
8486
|
+
- **Run Studio views.** Run graphs, retry/recovery timelines, eval comparisons, and fault-injection
|
|
8487
|
+
rows consume only protocol evidence and bounded replay references.
|
|
8488
|
+
- **Escape hatch.** `command()` reaches host-specific surfaces outside the negotiated contract and
|
|
8489
|
+
still returns a bounded `CommandOutcome` - it never throws the credential.
|
|
8490
|
+
|
|
8491
|
+
## Usage
|
|
8492
|
+
|
|
8493
|
+
```ts
|
|
8494
|
+
import { AgentAppClient, HttpAgentTransport } from "@nifrajs/agent-app"
|
|
8495
|
+
|
|
8496
|
+
const transport = new HttpAgentTransport({
|
|
8497
|
+
endpoint: "http://127.0.0.1:8787",
|
|
8498
|
+
authorize: () => currentToken(), // per-request; never stored
|
|
8499
|
+
})
|
|
8500
|
+
const client = new AgentAppClient(transport)
|
|
8501
|
+
|
|
8502
|
+
const session = await client.createSession()
|
|
8503
|
+
if (client.supports("resume")) {
|
|
8504
|
+
const replay = await client.resume({ cursor: lastCursor })
|
|
8505
|
+
// replay.entries: { seq, at, type }[] - no payloads
|
|
8506
|
+
}
|
|
8507
|
+
|
|
8508
|
+
for await (const view of client.send("summarize the diff")) {
|
|
8509
|
+
// view is content-free: e.g. { kind: "assistant.delta", seq, chars }
|
|
8510
|
+
}
|
|
8511
|
+
```
|
|
8512
|
+
|
|
8513
|
+
## Boundary
|
|
8514
|
+
|
|
8515
|
+
The transport receives the host's full event stream in order to derive counts, but the client's public
|
|
8516
|
+
output is projected to content-free view models. That projection is the seam: an application built on
|
|
8517
|
+
this SDK can render progress and resolve interactions, and cannot reconstruct a prompt, tool payload,
|
|
8518
|
+
model completion, diagnostic report, or filesystem path. The `scripts/check-agent-boundary.ts` gate
|
|
8519
|
+
enforces that this package imports nothing but `@nifrajs/agent-protocol`.
|
|
8520
|
+
|
|
8521
|
+
The SDK is transport-neutral and opt-in: it does not retain payloads, provide identity or tenancy,
|
|
8522
|
+
claim a remote security boundary, or imply durable delivery. Production hosts own authorization,
|
|
8523
|
+
retention, and adapter policy.
|
|
8524
|
+
|
|
8525
|
+
## License
|
|
8526
|
+
|
|
8527
|
+
MIT
|
|
8528
|
+
|
|
8529
|
+
For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
|
|
8530
|
+
[`../../llms-full.txt`](../../llms-full.txt).
|
|
8531
|
+
|
|
8532
|
+
## @nifrajs/agent-protocol
|
|
8533
|
+
|
|
8534
|
+
Small, backend-neutral contracts for local coding-agent sessions.
|
|
8535
|
+
|
|
8536
|
+
The package contains versioned session snapshots, streamed assistant/tool/approval
|
|
8537
|
+
events, bounded live event streams, and backend interfaces. It has no runtime
|
|
8538
|
+
dependencies and does not import Nifra framework packages, model SDKs, or UI code.
|
|
8539
|
+
|
|
8540
|
+
```ts
|
|
8541
|
+
import { createAgentEventStream } from "@nifrajs/agent-protocol"
|
|
8542
|
+
|
|
8543
|
+
const events = createAgentEventStream(256)
|
|
8544
|
+
events.push(/* a versioned AgentEvent */)
|
|
8545
|
+
```
|
|
8546
|
+
|
|
8547
|
+
Use `@nifrajs/pi` for the Pi backend or implement `AgentBackend` for another
|
|
8548
|
+
runtime. The protocol is intentionally small so CLI, desktop, mobile, and CI
|
|
8549
|
+
clients can share it without pulling in the Nifra application framework.
|
|
8550
|
+
|
|
8551
|
+
## Version 1 compatibility
|
|
8552
|
+
|
|
8553
|
+
Version 1 is additive. Hosts advertise capabilities and clients use only the negotiated intersection;
|
|
8554
|
+
an unsupported command is a stable `feature_unsupported` result. Optional fields are ignored by older
|
|
8555
|
+
peers, while a cursor gap returns `resync_required` instead of silently skipping evidence. A future
|
|
8556
|
+
major requires a recorded semantic incompatibility, dual decoders, cross-version fixtures, and an
|
|
8557
|
+
approved migration plan.
|
|
8558
|
+
|
|
8559
|
+
Run evidence and lifecycle values are structural only: identifiers, statuses, counters, timestamps,
|
|
8560
|
+
digests, and opaque references. Prompts, model output, tool arguments, and filesystem paths do not
|
|
8561
|
+
belong in these public contracts.
|
|
8562
|
+
|
|
8563
|
+
For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
|
|
8564
|
+
[`../../llms-full.txt`](../../llms-full.txt).
|
|
8565
|
+
|
|
7704
8566
|
## @nifrajs/agent-telemetry
|
|
7705
8567
|
|
|
7706
8568
|
Child-span telemetry for AI tool calls made through Nifra tool and MCP endpoints.
|
|
@@ -7719,6 +8581,35 @@ Requests under `/_nifra/tool/*` and requests to `/mcp` receive tool-name, input-
|
|
|
7719
8581
|
duration, and status observations. When `@nifrajs/otel` owns the request observation, tool spans are
|
|
7720
8582
|
attached as children; otherwise the plugin creates a standalone observation. Other routes pass through.
|
|
7721
8583
|
|
|
8584
|
+
## Tracing agent runs
|
|
8585
|
+
|
|
8586
|
+
`traceAgentRun` turns a `@nifrajs/agent` run's step evidence into an OpenTelemetry trace: one
|
|
8587
|
+
`nifra.agent.run` span per run, one child span per evidence item, with tool names, effect ids, error
|
|
8588
|
+
codes, and effect-ledger heads carried as span attributes. Only the runner's constrained evidence
|
|
8589
|
+
fields are exported - prompts, tool inputs, and outputs cannot enter a trace.
|
|
8590
|
+
|
|
8591
|
+
Orchestration correlation is opt-in and cardinality-bounded. Allowed attributes are run, plan, node,
|
|
8592
|
+
attempt, evidence, replay, and trace coordinates plus bounded status/error codes. Content-bearing or
|
|
8593
|
+
unbounded attributes are rejected; the exporter is not a payload retention sink.
|
|
8594
|
+
|
|
8595
|
+
```ts
|
|
8596
|
+
import { traceAgentRun } from "@nifrajs/agent-telemetry"
|
|
8597
|
+
import { combineAgentTelemetry, runAgent } from "@nifrajs/agent"
|
|
8598
|
+
|
|
8599
|
+
const trace = traceAgentRun({ agent: agent.name, turnId, exporter })
|
|
8600
|
+
const result = await runAgent(agent, input, {
|
|
8601
|
+
...ports,
|
|
8602
|
+
telemetry: combineAgentTelemetry(ports.telemetry, trace.telemetry),
|
|
8603
|
+
})
|
|
8604
|
+
trace.end(result)
|
|
8605
|
+
```
|
|
8606
|
+
|
|
8607
|
+
Model evidence arrives as a started/terminal pair and becomes one timed `nifra.agent.model` span;
|
|
8608
|
+
tool, approval, budget, and state evidence are terminal-only and become instant children. Pass
|
|
8609
|
+
`parent` (for example the enclosing request observation's `context`) to nest runs under the HTTP
|
|
8610
|
+
span, or `traceparent` to continue an inbound W3C trace; `trace.context` is the run span's identity,
|
|
8611
|
+
forwardable with `traceHeaders`. Telemetry is fail-open: a throwing exporter never fails the turn.
|
|
8612
|
+
|
|
7722
8613
|
## For AI agents
|
|
7723
8614
|
|
|
7724
8615
|
Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
|
|
@@ -7949,8 +8840,9 @@ await cache.invalidateTag(`user:${id}`)
|
|
|
7949
8840
|
|
|
7950
8841
|
## Stores
|
|
7951
8842
|
|
|
7952
|
-
The default `MemoryCache` is in-process with
|
|
7953
|
-
|
|
8843
|
+
The default `MemoryCache` is in-process with incremental expiry, a tag index, and a 10,000-entry LRU
|
|
8844
|
+
cap. Tune it with `new MemoryCache({ maxEntries: 2_000 })`; `maxEntries: 0` is the explicit unbounded
|
|
8845
|
+
opt-in. For a cache shared across instances, implement `CacheStore`
|
|
7954
8846
|
(`get` / `set` / `delete` / `invalidateTag` / `clear`) over CF KV, Redis, etc.:
|
|
7955
8847
|
|
|
7956
8848
|
```ts
|
|
@@ -7987,6 +8879,7 @@ nifra start [--port <n>] [--out <dir>] Run the generated Bun server at <out>
|
|
|
7987
8879
|
nifra context Print this project's API + page routes + conventions.
|
|
7988
8880
|
nifra mcp MCP server (stdio) exposing this project to a coding agent.
|
|
7989
8881
|
nifra check [--json] Gate: typecheck + lints; --json includes fixes/suggestions.
|
|
8882
|
+
nifra migrate --from tailwind --to stylex Dry-run safe static Tailwind → StyleX migration; --write applies it.
|
|
7990
8883
|
nifra assure [--config <file>] [--json] Gate reflected routes against enforcement evidence.
|
|
7991
8884
|
nifra capabilities check [--json] Gate effect provenance + the reviewed capability lockfile.
|
|
7992
8885
|
nifra manifest emit [--sign <key-ref>] Emit the hash-verified route trust artifact after assurance.
|
|
@@ -8049,6 +8942,15 @@ For hand-rolled own-API `fetch()` calls, `nifra check` stays conservative: simpl
|
|
|
8049
8942
|
that match a statically visible Nifra route get an exact typed-client rewrite diff; dynamic URLs, custom
|
|
8050
8943
|
headers, bodies, query strings, or ambiguous routes fall back to manual steps.
|
|
8051
8944
|
|
|
8945
|
+
## `nifra migrate --from tailwind --to stylex`
|
|
8946
|
+
|
|
8947
|
+
This command is a dry run by default. It rewrites static `className` attributes whose utilities have a
|
|
8948
|
+
direct StyleX equivalent into `stylex.props(...)` plus a local `stylex.create(...)` table. Use
|
|
8949
|
+
`--write` to apply the safe changes, and `--dir` to scan a project subdirectory. Responsive breakpoints
|
|
8950
|
+
and element-local pseudo-classes are supported; dynamic expressions, arbitrary values, parent-dependent
|
|
8951
|
+
variants, and unknown utilities are left untouched and reported with file and line evidence. A non-zero
|
|
8952
|
+
exit status means manual migration issues remain.
|
|
8953
|
+
|
|
8052
8954
|
When a library such as Better Auth intentionally owns a mounted prefix outside the Nifra contract,
|
|
8053
8955
|
declare that prefix in `nifra.check.json` so its relative calls do not keep CI red:
|
|
8054
8956
|
|
|
@@ -8175,6 +9077,76 @@ one cheap read instead of the whole corpus. For the wider framework: the repo's
|
|
|
8175
9077
|
[`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run `nifra check` as the
|
|
8176
9078
|
done-gate, or `nifra mcp` to give the agent live project tools.
|
|
8177
9079
|
|
|
9080
|
+
## @nifrajs/coding-agent
|
|
9081
|
+
|
|
9082
|
+
Standalone, extensible Nifra coding-agent host and CLI.
|
|
9083
|
+
|
|
9084
|
+
The package provides `nifra-agent` in interactive, one-shot, JSON, and local
|
|
9085
|
+
loopback RPC modes. It adds sessions, checkpoints, bounded compaction,
|
|
9086
|
+
transactional TypeScript extensions, self-healing repair stages, workflows,
|
|
9087
|
+
bounded subagents, and Nifra verification descriptors without changing Nifra's
|
|
9088
|
+
framework runtime.
|
|
9089
|
+
|
|
9090
|
+
Extensions can register bounded workflows that are listed and run through the
|
|
9091
|
+
authenticated RPC surface. Capability manifests, project workspace policies,
|
|
9092
|
+
optional isolated-worktree leases, and a pre-activation syntax gate keep those
|
|
9093
|
+
customizations explicit and replaceable.
|
|
9094
|
+
|
|
9095
|
+
```sh
|
|
9096
|
+
bunx nifra-agent --backend pi
|
|
9097
|
+
bunx nifra-agent --backend pi --message "run the checks and explain failures"
|
|
9098
|
+
bunx nifra-agent --backend pi --verify-after-turn check --max-repair-attempts 2
|
|
9099
|
+
bunx nifra-agent --backend replay --replay ./session-events.jsonl --json
|
|
9100
|
+
```
|
|
9101
|
+
|
|
9102
|
+
When --verify-after-turn is enabled, a failed gate becomes a bounded repair turn: the host sends
|
|
9103
|
+
the failure diagnostics back to the agent, runs the gate again, and stops on success or after the
|
|
9104
|
+
configured attempt cap. Use --max-repair-attempts 0 for observe-only verification.
|
|
9105
|
+
|
|
9106
|
+
For embedding, use `CodingAgentHost` or `CodingAgentRpcServer`. The host keeps
|
|
9107
|
+
live event queues bounded, filters verification subprocess environments, and
|
|
9108
|
+
requires explicit local RPC authorization. Install this package only when an
|
|
9109
|
+
application wants the agent product.
|
|
9110
|
+
|
|
9111
|
+
RPC failures return actionable bounded error messages by default. For a trusted
|
|
9112
|
+
loopback debugger, set `exposeErrorStacks: true` (or pass
|
|
9113
|
+
`--expose-error-stacks` to `nifra-agent --rpc`) to include bounded exception
|
|
9114
|
+
stacks. This option is rejected for remote binding.
|
|
9115
|
+
|
|
9116
|
+
`IsolatedExtensionWorker` is an opt-in process-backed crash-containment seam for
|
|
9117
|
+
extensions. It is not a hostile-code sandbox; use OS-level isolation before
|
|
9118
|
+
loading code you do not trust.
|
|
9119
|
+
|
|
9120
|
+
`NifraBackend` is a small provider port for a future native backend. It accepts
|
|
9121
|
+
an injected model implementation and bounded tools without importing a provider
|
|
9122
|
+
SDK. `ReplayBackend` and `readReplayEvents` provide deterministic protocol
|
|
9123
|
+
replays for CI and Workbench regression tests.
|
|
9124
|
+
|
|
9125
|
+
## At-least-once run dispatch
|
|
9126
|
+
|
|
9127
|
+
`@nifrajs/coding-agent/orchestration` also exports an evidence-only run dispatch port and an adapter
|
|
9128
|
+
over `@nifrajs/jobs`. Dispatch is at-least-once: a lease may be delivered again after worker loss or
|
|
9129
|
+
lease expiry. Every logical node attempt receives a stable idempotency key derived from the plan,
|
|
9130
|
+
run, node, and attempt boundary. Effects must provide a matching proof before recovery can settle a
|
|
9131
|
+
completed boundary; an unproven post-effect failure is dead-lettered rather than guessed safe.
|
|
9132
|
+
|
|
9133
|
+
`createMemoryRunDispatchStore()` is disposable single-process test infrastructure. It makes no
|
|
9134
|
+
durability, hosted-worker, retention, tenant-authorization, or exactly-once guarantee. Durable
|
|
9135
|
+
operated adapters implement the exported `RunDispatchStore` and `DurableDispatchAdapter` ports in
|
|
9136
|
+
their own data layer, including authorization, row policy, retention, reconciliation, and worker
|
|
9137
|
+
health. The public package does not store prompts, model output, tool arguments, or job payloads in
|
|
9138
|
+
its dispatch evidence.
|
|
9139
|
+
|
|
9140
|
+
Legacy `FileSessionStore` files remain supported for explicit local compatibility. Use
|
|
9141
|
+
`nifra-agent --migrate-session <id> --migrate-from <legacy-dir> --migrate-to <evidence-dir>` to
|
|
9142
|
+
create a separately validated, evidence-only target. The source is left untouched and the command
|
|
9143
|
+
does not switch an active configuration pointer; see
|
|
9144
|
+
[`docs/agent-platform/protocol-and-session-migration.md`](../../docs/agent-platform/protocol-and-session-migration.md)
|
|
9145
|
+
for rollback and protocol compatibility details.
|
|
9146
|
+
|
|
9147
|
+
For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
|
|
9148
|
+
[`../../llms-full.txt`](../../llms-full.txt).
|
|
9149
|
+
|
|
8178
9150
|
## @nifrajs/content
|
|
8179
9151
|
|
|
8180
9152
|
Typed, schema-validated content collections for nifra - Markdown + frontmatter, framework-agnostic.
|
|
@@ -8267,6 +9239,27 @@ import { defineChannel, memoryChannelHub } from "@nifrajs/core/channel"
|
|
|
8267
9239
|
- **Inline or contract-first.** Write routes inline (types inferred from the
|
|
8268
9240
|
builder), or `defineContract(...)` + `implement(...)` for a decoupled, versionable
|
|
8269
9241
|
surface - handlers lift over unchanged.
|
|
9242
|
+
|
|
9243
|
+
### Scaling route tables
|
|
9244
|
+
|
|
9245
|
+
Fluent chains are the best fit for a small route surface. TypeScript's type-instantiation budget
|
|
9246
|
+
usually becomes the limiting factor around 95-100 chained routes because every call both infers its
|
|
9247
|
+
handler context and re-threads the growing typed registry. The runtime router is not the limit, and
|
|
9248
|
+
the routes remain fully typed when you compose them as short domain groups:
|
|
9249
|
+
|
|
9250
|
+
```ts
|
|
9251
|
+
const listings = server()
|
|
9252
|
+
.get("/listings", () => ({ ok: true }))
|
|
9253
|
+
.get("/listings/:id", (c) => ({ id: c.params.id }))
|
|
9254
|
+
const agents = server().get("/agents/:id", (c) => ({ id: c.params.id }))
|
|
9255
|
+
|
|
9256
|
+
const app = server().get("/health", () => ({ ok: true })).merge(listings).merge(agents)
|
|
9257
|
+
```
|
|
9258
|
+
|
|
9259
|
+
Each group's routes keep the middleware and assurance captured when that group was defined. For a
|
|
9260
|
+
contract-owned surface, `defineContract(...)` + `implement(...)` is the other escape hatch: the
|
|
9261
|
+
registry is declared as one object type, so it does not grow one fluent-instantiation level per
|
|
9262
|
+
route. Split groups before the compiler reports `TS2589`, rather than weakening the route types.
|
|
8270
9263
|
- **Validation at the boundary.** Per-route `body`/`query` is any
|
|
8271
9264
|
[Standard Schema](https://standardschema.dev) (zod/valibot/arktype, or `@nifrajs/schema`'s
|
|
8272
9265
|
`t`); invalid input is rejected with a structured `422` before the handler runs.
|
|
@@ -8677,6 +9670,126 @@ one cheap read instead of the whole corpus. For the wider framework: the repo's
|
|
|
8677
9670
|
[`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run `nifra check` as the
|
|
8678
9671
|
done-gate, or `nifra mcp` to give the agent live project tools.
|
|
8679
9672
|
|
|
9673
|
+
## @nifrajs/graphql
|
|
9674
|
+
|
|
9675
|
+
Mount a GraphQL endpoint on a nifra app. A spec-compliant [GraphQL-over-HTTP](https://graphql.github.io/graphql-over-http/draft/) handler, `graphql-transport-ws` subscriptions over nifra's native WebSocket lane, and your typed nifra context piped straight into resolvers.
|
|
9676
|
+
|
|
9677
|
+
It executes with the `graphql` package's own `parse`/`validate`/`execute`/`subscribe` - no HTTP framework is re-bundled, the request body reuses core's single bounded, prototype-guarded trust boundary, and the query text is never logged.
|
|
9678
|
+
|
|
9679
|
+
## Install
|
|
9680
|
+
|
|
9681
|
+
```bash
|
|
9682
|
+
bun add @nifrajs/graphql graphql
|
|
9683
|
+
# subscriptions also need:
|
|
9684
|
+
bun add graphql-ws
|
|
9685
|
+
```
|
|
9686
|
+
|
|
9687
|
+
`graphql` is a required peer; `graphql-ws` is optional (only for subscriptions).
|
|
9688
|
+
|
|
9689
|
+
## Queries and mutations
|
|
9690
|
+
|
|
9691
|
+
```ts
|
|
9692
|
+
import { server } from "@nifrajs/core"
|
|
9693
|
+
import { mountGraphql } from "@nifrajs/graphql"
|
|
9694
|
+
import { buildSchema } from "graphql"
|
|
9695
|
+
|
|
9696
|
+
const schema = buildSchema(`
|
|
9697
|
+
type Query { hello: String }
|
|
9698
|
+
type Mutation { echo(msg: String!): String }
|
|
9699
|
+
`)
|
|
9700
|
+
|
|
9701
|
+
const rootValue = {
|
|
9702
|
+
hello: () => "world",
|
|
9703
|
+
echo: ({ msg }: { msg: string }) => msg,
|
|
9704
|
+
}
|
|
9705
|
+
|
|
9706
|
+
const app = server()
|
|
9707
|
+
mountGraphql(app, { schema, rootValue })
|
|
9708
|
+
// POST /graphql - queries + mutations
|
|
9709
|
+
// GET /graphql - queries only (idempotent, cacheable)
|
|
9710
|
+
```
|
|
9711
|
+
|
|
9712
|
+
Prefer the handler directly? Mount it yourself:
|
|
9713
|
+
|
|
9714
|
+
```ts
|
|
9715
|
+
import { respondGraphql } from "@nifrajs/graphql"
|
|
9716
|
+
|
|
9717
|
+
app.post("/graphql", (c) => respondGraphql(c.req, { schema, rootValue }))
|
|
9718
|
+
```
|
|
9719
|
+
|
|
9720
|
+
## Context injection
|
|
9721
|
+
|
|
9722
|
+
The one thing a plain third-party mount cannot do: derive the resolver `contextValue` from what your nifra handler already resolved (auth subject, env, params).
|
|
9723
|
+
|
|
9724
|
+
```ts
|
|
9725
|
+
mountGraphql(app, {
|
|
9726
|
+
schema,
|
|
9727
|
+
context: ({ request, nifra }) => ({
|
|
9728
|
+
user: nifra?.env, // nifra route context, when mounted via mountGraphql
|
|
9729
|
+
ip: request.headers.get("x-forwarded-for"),
|
|
9730
|
+
}),
|
|
9731
|
+
})
|
|
9732
|
+
```
|
|
9733
|
+
|
|
9734
|
+
Resolvers read it as their third argument.
|
|
9735
|
+
|
|
9736
|
+
## Subscriptions
|
|
9737
|
+
|
|
9738
|
+
Subscriptions run over the same route via `graphql-transport-ws`. Bring a subscription source - the bundled in-memory `createPubSub` is the reference implementation; swap in a durable bus (Redis, a Durable Object, NATS) that exposes the same `{ publish, subscribe }` shape for multi-instance deploys.
|
|
9739
|
+
|
|
9740
|
+
```ts
|
|
9741
|
+
import { server } from "@nifrajs/core"
|
|
9742
|
+
import { websocket } from "@nifrajs/core/ws"
|
|
9743
|
+
import { mountGraphql, createPubSub } from "@nifrajs/graphql"
|
|
9744
|
+
|
|
9745
|
+
const pubsub = createPubSub<number>()
|
|
9746
|
+
|
|
9747
|
+
const app = server().use(websocket())
|
|
9748
|
+
mountGraphql(app, {
|
|
9749
|
+
schema,
|
|
9750
|
+
context: () => ({ pubsub }),
|
|
9751
|
+
subscriptions: true,
|
|
9752
|
+
})
|
|
9753
|
+
|
|
9754
|
+
// A resolver:
|
|
9755
|
+
// count: { subscribe: (_, __, ctx) => ctx.pubsub.subscribe("count"), resolve: (n) => n }
|
|
9756
|
+
// Push an event from anywhere:
|
|
9757
|
+
pubsub.publish("count", 1)
|
|
9758
|
+
```
|
|
9759
|
+
|
|
9760
|
+
The route must negotiate the `graphql-transport-ws` subprotocol at the WebSocket layer for a browser `graphql-ws` client to connect.
|
|
9761
|
+
|
|
9762
|
+
## Options
|
|
9763
|
+
|
|
9764
|
+
| Option | Default | Purpose |
|
|
9765
|
+
| --- | --- | --- |
|
|
9766
|
+
| `schema` | - | Executable `GraphQLSchema` (required). |
|
|
9767
|
+
| `context` | `{}` | Build the resolver `contextValue` per operation. |
|
|
9768
|
+
| `rootValue` | - | Root value passed to the executor. |
|
|
9769
|
+
| `maxBodyBytes` | `1_000_000` | Request body cap; larger bodies answer 413. |
|
|
9770
|
+
| `protoPoisoning` | `"reject"` | Prototype-pollution policy for the JSON body. |
|
|
9771
|
+
| `allowedOrigins` | reflect `*` | CORS origin allowlist. |
|
|
9772
|
+
| `authorize` | - | Per-request guard; return `false` for 401. |
|
|
9773
|
+
| `enableGet` | `true` | Serve `GET /graphql` (queries only). |
|
|
9774
|
+
| `subscriptions` | `false` | `true` (reuse schema/context) or explicit WS options. |
|
|
9775
|
+
| `legacyJsonResponse` | `false` | Old always-200 `application/json` shape. |
|
|
9776
|
+
|
|
9777
|
+
## Responses
|
|
9778
|
+
|
|
9779
|
+
By default responses use the `application/graphql-response+json` media type with spec status codes: `200` for an executed result (including field errors in `errors`), `400` for a parse or validation failure, `401` for a rejected `authorize`, `405` for a mutation attempted over GET. Set `legacyJsonResponse: true` for the older always-`200` `application/json` behavior some clients expect.
|
|
9780
|
+
|
|
9781
|
+
## License
|
|
9782
|
+
|
|
9783
|
+
MIT
|
|
9784
|
+
|
|
9785
|
+
## For AI agents
|
|
9786
|
+
|
|
9787
|
+
Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
|
|
9788
|
+
one cheap read instead of the whole corpus. For the wider framework: the repo's
|
|
9789
|
+
[`AGENTS.md`](../../AGENTS.md) is the copy-paste quick reference, and
|
|
9790
|
+
[`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run `nifra check` as the
|
|
9791
|
+
done-gate, or `nifra mcp` to give the agent live project tools.
|
|
9792
|
+
|
|
8680
9793
|
## @nifrajs/i18n
|
|
8681
9794
|
|
|
8682
9795
|
Framework-agnostic i18n for nifra - locale negotiation + a tiny ICU message formatter on the platform Intl. Dependency-free.
|
|
@@ -8917,6 +10030,12 @@ const q = createQueue({ store: new RedisJobStore(redis) })
|
|
|
8917
10030
|
Leasing is at-least-once: a leased job is hidden for `leaseMs`; a worker that dies mid-job releases it
|
|
8918
10031
|
back automatically. Make handlers **idempotent**.
|
|
8919
10032
|
|
|
10033
|
+
The queue remains agent-agnostic. `@nifrajs/coding-agent` can place content-free run-dispatch
|
|
10034
|
+
identities in a dedicated `JobStore`, but this package does not import or define agent concepts. A
|
|
10035
|
+
`MemoryJobStore` is disposable single-process storage; production durability, authorization,
|
|
10036
|
+
retention, reconciliation, and worker coordination belong to the caller's operated adapter. No
|
|
10037
|
+
exactly-once delivery guarantee is implied by a lease.
|
|
10038
|
+
|
|
8920
10039
|
## Cloudflare Workers
|
|
8921
10040
|
|
|
8922
10041
|
Workers has no long-lived process, so don't call `start()`. Back the queue with a durable store and a
|
|
@@ -8976,6 +10095,10 @@ Mount `mcp.fetch` at `POST /mcp`. The package also exposes the JSON-RPC protocol
|
|
|
8976
10095
|
layers directly, plus `defineMcpWidget` and the React adapter for tool results that render UI in MCP
|
|
8977
10096
|
hosts.
|
|
8978
10097
|
|
|
10098
|
+
Clients that include `text/event-stream` in `Accept` receive progress notifications as they happen,
|
|
10099
|
+
followed by the final JSON-RPC response in the same stream. An SSE `GET /mcp` opens a cancellable
|
|
10100
|
+
server-message connection; a plain `GET /mcp` remains a health page.
|
|
10101
|
+
|
|
8979
10102
|
## For AI agents
|
|
8980
10103
|
|
|
8981
10104
|
Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
|
|
@@ -9357,6 +10480,43 @@ one cheap read instead of the whole corpus. For the wider framework: the repo's
|
|
|
9357
10480
|
[`llms-full.txt`](../../llms-full.txt) is the full machine-readable corpus. Run `nifra check` as the
|
|
9358
10481
|
done-gate, or `nifra mcp` to give the agent live project tools.
|
|
9359
10482
|
|
|
10483
|
+
## @nifrajs/pi
|
|
10484
|
+
|
|
10485
|
+
Lightweight Pi JSONL/RPC adapter for the Nifra agent protocol.
|
|
10486
|
+
|
|
10487
|
+
It starts Pi in headless RPC mode, maps Pi lifecycle, assistant, tool,
|
|
10488
|
+
compaction, extension, and error events into `@nifrajs/agent-protocol`, and
|
|
10489
|
+
supports cancellation, reload, session identity, and bounded event buffering.
|
|
10490
|
+
|
|
10491
|
+
Reload defaults to a process restart with the same Pi session ID. This is the
|
|
10492
|
+
reliable reload primitive in Pi's documented RPC protocol: the transcript stays
|
|
10493
|
+
in Pi's session store while the new process loads changed extensions. The tiny
|
|
10494
|
+
public-API bridge is still loaded for interactive Pi use. Set
|
|
10495
|
+
`reloadCommand: "prompt"` only for an RPC implementation that dispatches slash
|
|
10496
|
+
commands, or `reloadCommand: "rpc"` for one that provides a top-level reload
|
|
10497
|
+
command. Set `enableReloadBridge: false` when supplying a custom bridge.
|
|
10498
|
+
|
|
10499
|
+
Set `enableNifraTools: true` to load the separately packaged Pi extension with
|
|
10500
|
+
`nifra_context`, `nifra_check`, `nifra_assure`, and `nifra_test` tools. The
|
|
10501
|
+
default is off so embedding Pi stays minimal.
|
|
10502
|
+
|
|
10503
|
+
```ts
|
|
10504
|
+
import { PiBackend } from "@nifrajs/pi"
|
|
10505
|
+
|
|
10506
|
+
const backend = new PiBackend()
|
|
10507
|
+
const session = await backend.createSession({ cwd: process.cwd() })
|
|
10508
|
+
for await (const event of backend.send({ sessionId: session.id, message: "inspect this project" })) {
|
|
10509
|
+
console.log(event.type)
|
|
10510
|
+
}
|
|
10511
|
+
```
|
|
10512
|
+
|
|
10513
|
+
Pi stays an optional dependency of the agent product. Nothing in this package is
|
|
10514
|
+
reachable from `@nifrajs/core`, `@nifrajs/client`, `@nifrajs/web`, or
|
|
10515
|
+
`@nifrajs/schema`.
|
|
10516
|
+
|
|
10517
|
+
For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
|
|
10518
|
+
[`../../llms-full.txt`](../../llms-full.txt).
|
|
10519
|
+
|
|
9360
10520
|
## @nifrajs/prompt
|
|
9361
10521
|
|
|
9362
10522
|
Provider-neutral, type-safe prompts with Standard Schema input and validated structured output.
|
|
@@ -9410,7 +10570,7 @@ const upstream = createProxy({ upstream: "http://127.0.0.1:8081" })
|
|
|
9410
10570
|
const app = server().mountFetch("/api", upstream, { stripPrefix: true })
|
|
9411
10571
|
```
|
|
9412
10572
|
|
|
9413
|
-
The upstream is a **bare origin** fixed at construction - the forwarded URL is built by mutating a clone of that origin, never by resolving request-derived strings, so no request input can change which host is dialed. Hop-by-hop and `Connection`-nominated headers are stripped in both directions
|
|
10573
|
+
The upstream is a **bare origin** fixed at construction - the forwarded URL is built by mutating a clone of that origin, never by resolving request-derived strings, so no request input can change which host is dialed. Hop-by-hop and `Connection`-nominated headers are stripped in both directions. Caller IP/protocol metadata is dropped unless `forwardClientIp: true`; the inbound Host is never trusted, and `X-Forwarded-Host` is emitted only from a fixed `forwardedHost`. Upstream redirects are never followed, and TLS verification has no off switch. Unreachable upstreams answer a flat `502`; the deadline (`timeoutMs`, default 30s) answers `504`.
|
|
9414
10574
|
|
|
9415
10575
|
## Docs
|
|
9416
10576
|
|
|
@@ -9572,6 +10732,11 @@ pi install npm:@nifrajs/skills
|
|
|
9572
10732
|
/plugin install nifra@nifra
|
|
9573
10733
|
```
|
|
9574
10734
|
|
|
10735
|
+
The plugin registers the Nifra MCP server as well as the skills, so a fresh install has the live tools
|
|
10736
|
+
the skills tell it to prefer. Its launch spec is deliberately unpinned - a plugin is installed once and
|
|
10737
|
+
opened against many projects, so the CLI resolves per project and the server reports version skew
|
|
10738
|
+
itself rather than freezing one version across all of them.
|
|
10739
|
+
|
|
9575
10740
|
**Anything that reads a skills directory** (Cursor, `.agents/skills`, a project `.pi/skills`)
|
|
9576
10741
|
|
|
9577
10742
|
```sh
|
|
@@ -9588,6 +10753,9 @@ against the version installed in the project being edited:
|
|
|
9588
10753
|
bunx @nifrajs/cli init-agents # register the MCP server in an existing app
|
|
9589
10754
|
```
|
|
9590
10755
|
|
|
10756
|
+
The Claude Code plugin brings its own copy of that server, so `init-agents` is for the other surfaces -
|
|
10757
|
+
and for committing a version-pinned `.mcp.json` that every contributor on the project shares.
|
|
10758
|
+
|
|
9591
10759
|
Not in a Nifra project? The docs tools are hosted at `https://mcp.nifra.dev`.
|
|
9592
10760
|
|
|
9593
10761
|
That split is the anti-drift design: a skill that restated the API would rot on the next release,
|
|
@@ -9867,6 +11035,14 @@ that every call carries and captures cookies via a shared jar.
|
|
|
9867
11035
|
|
|
9868
11036
|
For a **stateless** request (no cookies), use `testClient` from `@nifrajs/client` directly.
|
|
9869
11037
|
|
|
11038
|
+
### Agent evaluation and failure matrix
|
|
11039
|
+
|
|
11040
|
+
`runAgentEvalComposition` composes trajectory replay, fault profiles, contract invariants,
|
|
11041
|
+
idempotency proofs, and adapter certification. Reports expose explicit invariant and rubric cases,
|
|
11042
|
+
stable regression IDs, schedule tokens, and digests; they do not retain prompts, tool payloads,
|
|
11043
|
+
model output, labels, or a single opaque quality score. The failure matrix covers model, tool,
|
|
11044
|
+
approval, cancellation, lease, cursor, registry, and deployment boundaries.
|
|
11045
|
+
|
|
9870
11046
|
## For AI agents
|
|
9871
11047
|
|
|
9872
11048
|
Start with [`LLM.md`](./LLM.md) - this package's contract card (the exports you call + its footguns),
|
|
@@ -10077,6 +11253,14 @@ Zero-framework render adapter for @nifrajs/web - auto-escaping tagged-template H
|
|
|
10077
11253
|
|
|
10078
11254
|
Part of the **[nifra](https://nifra.dev)** full-stack TypeScript framework - one core, five UI libraries, every runtime. Scaffold a new app with `bun create nifra`.
|
|
10079
11255
|
|
|
11256
|
+
## The AI-safe lane
|
|
11257
|
+
|
|
11258
|
+
Vanilla is the render adapter an agent gets right on the first try. It ships no framework runtime, so there is no hydration, no reactivity, and none of the failure modes (stale closures, hydration mismatch, what-re-runs-when) that trip up generated code. You get true SSR plus every server feature - loaders, actions, ISR/SSG, streaming, head management - unchanged from `@nifrajs/web`; those live in the core, not the view layer.
|
|
11259
|
+
|
|
11260
|
+
Interactivity is added with **islands**, not hydration: small imperative DOM enhancers over server-rendered elements. `defineIsland` types the props, `createIslandBus` coordinates islands over a typed channel, and every enhancer returns its cleanup - the one rule `nifra check` enforces (`NF-C020`). See the [islands cookbook](https://nifra.dev/docs/islands) for the counter, cart-badge, and filter patterns, or run `nifra scaffold` on a vanilla route for the golden stub.
|
|
11261
|
+
|
|
11262
|
+
Need a stateful app UI with reactive components? That is what the five framework adapters are for - reach for `@nifrajs/web-preact` or `@nifrajs/web-solid` when you want a small reactive runtime.
|
|
11263
|
+
|
|
10080
11264
|
## Install
|
|
10081
11265
|
|
|
10082
11266
|
```sh
|
|
@@ -10237,13 +11421,29 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
10237
11421
|
|
|
10238
11422
|
# Complete export index (generated from each package's src/index.ts)
|
|
10239
11423
|
|
|
11424
|
+
## @nifrajs/a2a
|
|
11425
|
+
|
|
11426
|
+
`A2A_ERROR_CODES`, `A2A_PROTOCOL_VERSION`, `A2AAgentCard`, `A2AAgentSkill`, `A2ACardInfo`, `A2AMountableApp`, `A2ARouteContext`, `A2ATaskState`, `AGENT_CARD_WELL_KNOWN_PATH`, `agentCard`, `mountA2A`, `MountA2AOptions`
|
|
11427
|
+
|
|
11428
|
+
## @nifrajs/ag-ui
|
|
11429
|
+
|
|
11430
|
+
`AgUIMountableApp`, `AgUIRouteContext`, `AgUIRunContext`, `AgUIRunUsage`, `mountAgUI`, `MountAgUIOptions`
|
|
11431
|
+
|
|
10240
11432
|
## @nifrajs/agent
|
|
10241
11433
|
|
|
10242
|
-
`AgentApprovalPort`, `AgentApprovalResult`, `AgentDefinition`, `AgentModelPort`, `AgentModelRequest`, `AgentModelResponse`, `AgentPendingContinuation`, `AgentPendingKind`, `AgentPorts`, `AgentRunResult`, `AgentStateStore`, `AgentStatus`, `AgentStepEvidence`, `AgentTelemetryPort`, `AgentToolContract`, `AgentToolDescriptor`, `AgentToolResult`, `AgentTranscript`, `AgentTurnBaseResult`, `AgentTurnError`, `AgentTurnInput`, `AgentTurnResult`, `AgentTurnState`, `createAgentState`, `createLocalProcessAdapter`, `ExecutionPolicy`, `ExecutionPolicyAdapter`, `LOCAL_PROCESS_LIMITATION`, `LocalProcessAdapter`, `LocalProcessAdapterOptions`, `LocalProcessPolicyError`, `LocalProcessRequest`, `LocalProcessResult`, `MemoryAgentStateStore`, `replayAgent`, `resumeAgent`, `runAgent`, `RunAgentOptions`, `turn`
|
|
11434
|
+
`AgentApprovalPort`, `AgentApprovalResult`, `AgentDefinition`, `AgentDeltaSink`, `AgentDeployment`, `AgentDeploymentAdapter`, `AgentDeploymentPlan`, `AgentModelDelta`, `AgentModelPort`, `AgentModelRequest`, `AgentModelResponse`, `AgentPendingContinuation`, `AgentPendingKind`, `AgentPorts`, `AgentRunResult`, `AgentSharedState`, `AgentStatePatchOp`, `AgentStateStore`, `AgentStatus`, `AgentStepEvidence`, `AgentTelemetryPort`, `AgentToolContract`, `AgentToolDescriptor`, `AgentToolResult`, `AgentTranscript`, `AgentTurnBaseResult`, `AgentTurnError`, `AgentTurnInput`, `AgentTurnResult`, `AgentTurnState`, `ApprovalClass`, `assertDeploymentAuthorityMonotonic`, `CAPABILITY_DESCRIPTOR_VERSION`, `CapabilityDescriptor`, `CapabilityKind`, `combineAgentDeltaSinks`, `combineAgentTelemetry`, `composeDescriptor`, `composeRegistrySnapshot`, `createAgentSharedState`, `createAgentState`, `createDeploymentAuthority`, `createLocalProcessAdapter`, `createStructuredOutputParser`, `DeploymentActivationOptions`, `DeploymentAuthority`, `DeploymentCancellation`, `DeploymentCancelRequest`, `DeploymentCancelResult`, `DeploymentCapabilities`, `DeploymentCapabilityReport`, `DeploymentDisposeRequest`, `DeploymentDisposeResult`, `DeploymentError`, `DeploymentErrorCode`, `DeploymentEvidence`, `DeploymentFilesystem`, `DeploymentInspection`, `DeploymentInspectRequest`, `DeploymentNetwork`, `DeploymentPrepareRequest`, `DeploymentPrepareResult`, `DeploymentProcess`, `DeploymentRuntime`, `DeploymentSecrets`, `DeploymentStartRequest`, `DeploymentStartResult`, `DeploymentState`, `descriptorFromTool`, `DescriptorInput`, `ExecutionPolicy`, `ExecutionPolicyAdapter`, `FakeModelGateway`, `FakeModelGatewayOptions`, `HostileCodeIsolation`, `IdempotencyClass`, `isModelGatewayErrorCode`, `IsolationClass`, `LOCAL_PROCESS_LIMITATION`, `LocalProcessAdapter`, `LocalProcessAdapterOptions`, `LocalProcessPolicyError`, `LocalProcessRequest`, `LocalProcessResult`, `MemoryAgentStateStore`, `MODEL_GATEWAY_ERROR_CODES`, `ModelGateway`, `ModelGatewayAttemptRequest`, `ModelGatewayBudget`, `ModelGatewayEnvelope`, `ModelGatewayError`, `ModelGatewayErrorCode`, `ModelGatewayEvidence`, `ModelGatewayExecutionResult`, `ModelGatewayFailure`, `ModelGatewayFailureError`, `ModelGatewayRawResult`, `ModelGatewayRequest`, `ModelGatewayResult`, `ModelGatewaySuccess`, `ModelGatewayTerminalFailure`, `ModelGatewayUsage`, `ModelRoute`, `ModelRoutePolicy`, `ModelRouteRef`, `parseCapabilityDescriptor`, `parseDeploymentCapabilityReport`, `parseDeploymentPlan`, `parseModelGatewayError`, `parseModelGatewayResult`, `REGISTRY_SNAPSHOT_VERSION`, `RegistryError`, `RegistryErrorCode`, `RegistrySnapshot`, `replayAgent`, `ReplayModelGateway`, `ReplayModelGatewayOptions`, `resumeAgent`, `RetryClass`, `runAgent`, `RunAgentOptions`, `runModelGateway`, `structuredOutputParser`, `StructuredOutputParser`, `ToolDescriptorOptions`, `turn`
|
|
11435
|
+
|
|
11436
|
+
## @nifrajs/agent-app
|
|
11437
|
+
|
|
11438
|
+
`AGENT_APP_FEATURES`, `AgentAppClient`, `AgentAppClientOptions`, `AgentAppError`, `AgentEventView`, `AgentTransport`, `AgentTransportError`, `AgentTransportRequest`, `ApprovalRequiredView`, `ApprovalResolvedView`, `AssistantChunkView`, `AuthProvider`, `boundaryCommands`, `BoundaryDecisionResult`, `boundaryIsStale`, `BoundaryItemView`, `BoundaryStateView`, `CommandOutcome`, `CreateSessionInput`, `EvalComparisonView`, `EvidenceTimelineView`, `ExtensionReloadedView`, `FaultInjectionView`, `HandoffView`, `HttpAgentTransport`, `HttpAgentTransportOptions`, `MemoryCompactedView`, `OrderedEventBuffer`, `parseEventStream`, `PendingApprovalView`, `RegistryCapabilityView`, `RepairRequiredView`, `ReplayEntryView`, `ReplayResult`, `ResolveHandoffInput`, `ResumeInput`, `RunStudioNodeState`, `RunStudioNodeView`, `RunStudioView`, `RunView`, `SessionFailedView`, `SessionLifecycleView`, `SessionStoppedView`, `SessionView`, `toEvalComparisonView`, `toEventView`, `toEvidenceTimelineView`, `toFaultInjectionViews`, `toHandoffView`, `ToolCompletedView`, `ToolDeltaView`, `ToolStartedView`, `toRegistryCapabilityView`, `toRunStudioView`, `toRunView`, `toSessionView`, `TurnStartedView`, `VerificationCompletedView`, `virtualizeEvidenceRows`
|
|
11439
|
+
|
|
11440
|
+
## @nifrajs/agent-protocol
|
|
11441
|
+
|
|
11442
|
+
`AGENT_PROTOCOL_VERSION`, `AgentApprovalRequiredEvent`, `AgentApprovalResolvedEvent`, `AgentAssistantDeltaEvent`, `AgentAssistantMessageEvent`, `AgentBackend`, `AgentBackendInfo`, `agentError`, `AgentError`, `AgentEvent`, `AgentEventPayload`, `AgentEventSink`, `AgentEventStream`, `AgentEventType`, `AgentExtensionReloadedEvent`, `AgentMemoryCompactedEvent`, `AgentRepairRequiredEvent`, `AgentRepairTask`, `AgentSessionCheckpoint`, `AgentSessionCompletedEvent`, `AgentSessionEventBase`, `AgentSessionFailedEvent`, `AgentSessionSnapshot`, `AgentSessionStartedEvent`, `AgentSessionStatus`, `AgentSessionStoppedEvent`, `AgentSessionUpdatedEvent`, `AgentToolCompletedEvent`, `AgentToolDeltaEvent`, `AgentToolStartedEvent`, `AgentTurnStartedEvent`, `AgentVerificationCompletedEvent`, `createAgentEventStream`, `CreateSessionInput`, `ForkSessionInput`, `ForkSessionResult`, `isAgentEvent`, `ReloadResult`, `SendMessageInput`
|
|
10243
11443
|
|
|
10244
11444
|
## @nifrajs/agent-telemetry
|
|
10245
11445
|
|
|
10246
|
-
`agentTelemetry`, `AgentTelemetryOptions`, `consoleAgentExporter`
|
|
11446
|
+
`AgentRunEvidence`, `AgentRunOutcome`, `AgentRunTrace`, `agentTelemetry`, `AgentTelemetryOptions`, `consoleAgentExporter`, `orchestrationTelemetry`, `OrchestrationTelemetry`, `OrchestrationTelemetryEvent`, `OrchestrationTelemetryKind`, `OrchestrationTelemetryOptions`, `traceAgentRun`, `TraceAgentRunOptions`
|
|
10247
11447
|
|
|
10248
11448
|
## @nifrajs/auth
|
|
10249
11449
|
|
|
@@ -10265,13 +11465,17 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
10265
11465
|
|
|
10266
11466
|
`ActionArgs`, `ActionData`, `ApiError`, `ApiProxy`, `client`, `ClientOptions`, `ClientRetryOptions`, `FetchFn`, `inProcessClient`, `InProcessClient`, `InProcessClientOptions`, `Jsonify`, `LoaderArgs`, `LoaderData`, `RegistryOf`, `RESERVED_EXACT_KEYS`, `RESERVED_KEY_READOUT`, `RESERVED_VERB_KEYS`, `reservedKeyFor`, `ResponseContractViolation`, `Result`, `SubscribeOptions`, `Subscription`, `testClient`, `Treaty`, `TreatyFromRegistry`, `WsCallOptions`, `WsHandle`
|
|
10267
11467
|
|
|
11468
|
+
## @nifrajs/coding-agent
|
|
11469
|
+
|
|
11470
|
+
`AGENT_CAPABILITY_MANIFEST_VERSION`, `AGENT_PRESETS`, `AgentCapability`, `AgentCapabilityManifest`, `AgentPlan`, `AgentPreset`, `AgentPresetName`, `ApprovalDecision`, `ApprovalManager`, `ApprovalManagerOptions`, `ApprovalMatchRejection`, `ApprovalMatchResult`, `ApprovalRequest`, `approvalRequestFromEvent`, `approvalResolvedEvent`, `BoundedSubagentRunner`, `BoundedText`, `CapabilityDescriptor`, `CiDeploymentAdapter`, `CodingAgentExtension`, `CodingAgentHost`, `CodingAgentHostOptions`, `CodingAgentRpcServer`, `CodingAgentRpcServerHandle`, `CodingAgentRpcServerOptions`, `CompactionReport`, `ContextRecord`, `ContextWindow`, `ContextWindowOptions`, `createCapabilityManifest`, `createCiDeploymentAdapter`, `createLocalProcessDeploymentAdapter`, `createNativeGatewayModelPort`, `createNifraTools`, `createPresetSpec`, `createReplayDeploymentAdapter`, `createVerificationRepairTask`, `deniedCapabilities`, `DEPLOYMENT_REFERENCE_PROFILES`, `discoverExtensions`, `ExtensionCommand`, `ExtensionContext`, `extensionDescriptor`, `ExtensionDescriptorOptions`, `extensionDescriptors`, `ExtensionDescriptorSource`, `ExtensionEventHandler`, `ExtensionHost`, `ExtensionHostOptions`, `ExtensionProvider`, `ExtensionReloadResult`, `ExtensionSubagent`, `ExtensionTool`, `FileSessionStore`, `FileSessionStoreOptions`, `getAgentPreset`, `HandoffCoordinator`, `HandoffCoordinatorOptions`, `HandoffDecision`, `HandoffError`, `HandoffRejection`, `HandoffView`, `HealingEvent`, `HealingOptions`, `HealingResult`, `IsolatedExtensionSnapshot`, `IsolatedExtensionTool`, `IsolatedExtensionWorker`, `IsolatedExtensionWorkerOptions`, `LocalProcessDeploymentAdapter`, `migrateLegacySession`, `MigrateLegacySessionOptions`, `NativeApprovalPort`, `NativeGatewayModelPortOptions`, `NativeMessage`, `NativeModelChunk`, `NativeModelPort`, `NativeModelRequest`, `NativeModelResponse`, `NativeTool`, `NIFRA_AGENT_INSTRUCTIONS`, `NifraAgentTool`, `NifraBackend`, `NifraBackendOptions`, `NifraContextOptions`, `NifraContextResult`, `OpenHandoffInput`, `parseCapabilityManifest`, `parseSessionEvidenceRecord`, `PiBackend`, `PiBackendOptions`, `PlanEvent`, `PlanPhase`, `PlanResult`, `PlanRunner`, `PlanRunnerOptions`, `ProjectDiffOptions`, `ProjectDiffResult`, `readBoundedText`, `readProjectDiff`, `readReplayEvents`, `RepairProposal`, `ReplayBackend`, `ReplayBackendOptions`, `ReplayDeploymentAdapter`, `runNifraContext`, `runNifraVerification`, `SelfHealingController`, `SESSION_EVIDENCE_VERSION`, `SessionEvidenceRecord`, `SessionLogEntry`, `SessionMigrationError`, `SessionMigrationReport`, `SessionStore`, `stableSessionEventCode`, `SubagentExecutor`, `SubagentResult`, `SubagentRunnerOptions`, `SubagentSpec`, `UiExtensionHost`, `UiExtensionHostOptions`, `UiExtensionManifest`, `UiExtensionSlot`, `UiReloadResult`, `UiStatusWidget`, `UiThemeDescriptor`, `validateExtensionModule`, `VerificationOptions`, `VerificationRepairTask`, `VerificationResult`, `WorkflowContext`, `WorkflowEvent`, `WorkflowResult`, `WorkflowRunner`, `WorkflowRunnerOptions`, `WorkflowStep`
|
|
11471
|
+
|
|
10268
11472
|
## @nifrajs/content
|
|
10269
11473
|
|
|
10270
11474
|
`bakeCollection`, `BakedCollection`, `BakedCollectionIndex`, `BakedCollectionJoin`, `BakedIndexBucket`, `ContentFieldKey`, `Entry`, `fromBaked`, `fromBakedIndex`, `fromBakedJoin`, `indexCollection`, `IndexedCollection`, `IndexedJoin`, `IndexOptions`, `IndexPage`, `IndexQueryOptions`, `IndexRange`, `IndexRanges`, `IndexSort`, `IndexWhere`, `InferSchema`, `JoinCardinality`, `joinCollections`, `JoinedRow`, `parseEntry`, `ParseEntryOptions`, `parseFrontmatter`, `SharedKey`, `StandardSchemaV1`, `StaticCollection`
|
|
10271
11475
|
|
|
10272
11476
|
## @nifrajs/core
|
|
10273
11477
|
|
|
10274
|
-
`Version`, `VERSION`
|
|
11478
|
+
`AdmissionController`, `AdmissionDecision`, `AnyServer`, `commonSecretPatterns`, `Context`, `ContextPlugin`, `cookieNamePrefix`, `CookieOptions`, `CookieSecret`, `defineContextPlugin`, `defineIdentityPlugin`, `definePlugin`, `DefinePluginResult`, `defineRouterPlugin`, `DurableObjectNamespaceLike`, `ExecutionContext`, `FetchApp`, `FRAMEWORK_NAME`, `FrameworkError`, `FrameworkName`, `Handler`, `IdentityPlugin`, `InferInput`, `InferOutput`, `isSameOriginPath`, `isSameOriginRequest`, `jsonLogger`, `LambdaEvent`, `LambdaHandler`, `LambdaResponse`, `LambdaV1Event`, `LambdaV2Event`, `LogFields`, `Logger`, `McpPromptDescriptor`, `McpResourceDescriptor`, `Method`, `METHODS`, `Middleware`, `NetlifyEvent`, `NetlifyHandler`, `NifraFeatureVersion`, `NifraPlugin`, `NifraWebSocket`, `NodeRequestContext`, `NodeRequestHook`, `NodeResponseContext`, `NodeResponseHook`, `NodeServeOutcome`, `OnRequestResult`, `Params`, `parseCookies`, `pathnameOf`, `PlainRender`, `Platform`, `PlatformResponse`, `PluginTypeCollapsed`, `Prettify`, `PromptArgument`, `PromptMessage`, `redactLogFields`, `RedactOptions`, `Registry`, `ResponseBodyHook`, `ResponseBodyReplacement`, `ResponseControls`, `ResponseFinalization`, `ResponseHeadersHook`, `ResponseHeadersView`, `ResponseMapFor`, `ResponseResult`, `RouteConfigError`, `RouteConfigErrorCode`, `RouteDescriptor`, `RouteInfo`, `RouteInfoFor`, `Router`, `RouterMatch`, `RouteSchema`, `RunningServer`, `ScheduledController`, `ScheduledHandler`, `serializeCookie`, `server`, `Server`, `ServerOptions`, `signValue`, `silentLogger`, `SSEContext`, `SSEInit`, `SSEMessage`, `SSEStream`, `StandardIssue`, `StandardResult`, `StandardSchemaV1`, `StandardTypes`, `StandardWebSocket`, `status`, `StatusResponse`, `toFetchHandler`, `toLambdaHandler`, `toNetlifyHandler`, `ToolAnnotations`, `toVercelHandler`, `TypedSSEStream`, `unsignValue`, `UrlParts`, `urlPartsOf`, `ValidationOutcome`, `VercelHandler`, `Version`, `VERSION`, `WebSocketContext`, `WebSocketData`, `WebSocketHandler`, `WebSocketUpgradeOutcome`
|
|
10275
11479
|
|
|
10276
11480
|
## @nifrajs/cron
|
|
10277
11481
|
|
|
@@ -10297,6 +11501,10 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
10297
11501
|
|
|
10298
11502
|
`createEventRegistry`, `defineEventContract`, `EventContract`, `EventContractError`, `EventEnvelope`, `EventParseResult`, `EventRegistry`, `RegistryParseResult`
|
|
10299
11503
|
|
|
11504
|
+
## @nifrajs/graphql
|
|
11505
|
+
|
|
11506
|
+
`buildContext`, `createPubSub`, `GraphqlContextBuilder`, `GraphqlContextInput`, `GraphqlHttpOptions`, `GraphqlPubSub`, `graphqlWebSocket`, `GraphqlWsOptions`, `mountGraphql`, `MountGraphqlOptions`, `NifraContextLike`, `respondGraphql`
|
|
11507
|
+
|
|
10300
11508
|
## @nifrajs/i18n
|
|
10301
11509
|
|
|
10302
11510
|
`createFormatter`, `Formatter`, `Locale`, `LocaleParts`, `LocaleSource`, `Messages`, `negotiateLocale`, `NegotiateOptions`, `ResolvedLocale`, `resolveLocale`
|
|
@@ -10341,6 +11549,10 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
10341
11549
|
|
|
10342
11550
|
`ActiveObservation`, `AttributeValue`, `causalitySpanLink`, `combineObservationAdapters`, `consoleSpanExporter`, `createObservationLifecycle`, `effectTracing`, `EffectTracingOptions`, `EffectTracingPlugin`, `EndObservation`, `formatTraceparent`, `generateSpanId`, `generateTraceId`, `NifraSpan`, `ObservationAdapter`, `ObservationClock`, `ObservationContext`, `ObservationLifecycle`, `ObservationLifecycleOptions`, `ObservationLink`, `ObservationParent`, `otlpExporter`, `OtlpExporter`, `OtlpExporterOptions`, `ParsedTraceparent`, `parseTraceparent`, `SpanStatus`, `StartObservation`, `TraceContext`, `traceHeaders`, `tracing`, `TracingOptions`
|
|
10343
11551
|
|
|
11552
|
+
## @nifrajs/pi
|
|
11553
|
+
|
|
11554
|
+
`PiBackend`, `PiBackendOptions`
|
|
11555
|
+
|
|
10344
11556
|
## @nifrajs/prompt
|
|
10345
11557
|
|
|
10346
11558
|
`prompt`, `Prompt`, `PromptInputError`, `PromptMessage`, `PromptOutputError`, `PromptRequest`, `PromptResponseFormat`, `RunOptions`
|
|
@@ -10363,7 +11575,7 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
10363
11575
|
|
|
10364
11576
|
## @nifrajs/testing
|
|
10365
11577
|
|
|
10366
|
-
`AdapterCertificationError`, `AdapterCertificationProfile`, `AdapterCertificationReport`, `AdversarialContractError`, `AdversarialContractOptions`, `AdversarialContractReport`, `AdversarialContractResult`, `AppLike`, `assertAdapterCertification`, `assertAdversarialContract`, `assertIncidentReplays`, `assertTrajectoryInvariants`, `cacheStoreCertificationProfile`, `CapturedRequest`, `CapturedRequestInput`, `captureIncident`, `CaptureIncidentOptions`, `CertifiableCacheEntry`, `CertifiableCacheStore`, `CertifiableDomainEvent`, `CertifiableEventDeliveryAdapter`, `CertifiableEventRecord`, `CertifiableJobStore`, `CertifiableRuntimeAdapter`, `CertifiableRuntimeServer`, `CertifiableStorageAdapter`, `CertificationCapabilityEvidence`, `CertificationCheck`, `CertificationCheckEvidence`, `certifyAdapter`, `checkTrajectoryInvariants`, `ContractCaseContext`, `ContractCaseKind`, `ContractCoverageGap`, `ContractCoverageGapCode`, `ContractReplay`, `ContractRuntime`, `ContractTarget`, `ContractTestApp`, `ContractWitness`, `cookieJar`, `CookieJar`, `createFailureLab`, `createTrajectoryTranscript`, `CreateTrajectoryTranscriptOptions`, `defineCertificationProfile`, `defineFaultProfile`, `EffectLedger`, `eventDeliveryCertificationProfile`, `FailureDirective`, `FailureEvidence`, `FailureInjectedError`, `FailureKind`, `FailureLab`, `FailureLabOptions`, `FailureReplay`, `FailureScenario`, `FailureScenarioReport`, `FaultProfile`, `FaultProfileFault`, `FaultProfileFaultKind`, `FaultProfileReport`, `FaultProfileScenario`, `FaultProfileScenarioReport`, `generateRegressionTest`, `GenerateRegressionTestOptions`, `httpToolAdapter`, `IdempotencyDivergence`, `IdempotencyProof`, `IncidentCapsule`, `IncidentReplayError`, `IncidentReplayResult`, `inProcessToolAdapter`, `jobStoreCertificationProfile`, `mcpToolAdapter`, `proveIdempotency`, `recordTrajectory`, `redactForEmission`, `referenceFaultProfile`, `replayIncident`, `ReplayIncidentOptions`, `replayTrajectory`, `ReplayTrajectoryOptions`, `runAdversarialContract`, `runFailureScenario`, `runFaultProfile`, `RunFaultProfileOptions`, `runtimeAdapterCertificationProfile`, `runTrajectory`, `shapeOf`, `storageAdapterCertificationProfile`, `testSession`, `TestSession`, `TestSessionOptions`, `testToolAdapter`, `TrajectoryInvariantId`, `TrajectoryInvariantOptions`, `TrajectoryInvariantResult`, `trajectoryRegressionId`, `TrajectoryReplayResult`, `TrajectoryRun`, `TrajectoryTranscript`, `verifyAdapterCertification`
|
|
11578
|
+
`AdapterCertificationError`, `AdapterCertificationProfile`, `AdapterCertificationReport`, `AdversarialContractError`, `AdversarialContractOptions`, `AdversarialContractReport`, `AdversarialContractResult`, `AgentEvalCase`, `AgentEvalComponentEvidence`, `AgentEvalCompositionOptions`, `AgentEvalCompositionReport`, `AgentEvalRegressionError`, `AgentEvalReport`, `AgentEvalSuite`, `AgentEvalSuiteSpec`, `AgentFailureMatrixCase`, `AgentFailureMatrixError`, `AgentFailureMatrixKind`, `AgentFailureMatrixReport`, `AppLike`, `assertAdapterCertification`, `assertAdversarialContract`, `assertAgentEval`, `assertAgentEvalBaseline`, `assertAgentFailureMatrix`, `assertIncidentReplays`, `assertTrajectoryInvariants`, `BaselineComparison`, `BaselineOptions`, `cacheStoreCertificationProfile`, `CapturedRequest`, `CapturedRequestInput`, `captureIncident`, `CaptureIncidentOptions`, `CaseComparison`, `CaseResult`, `CertifiableCacheEntry`, `CertifiableCacheStore`, `CertifiableDeploymentAdapter`, `CertifiableDescriptorAdapter`, `CertifiableDomainEvent`, `CertifiableEventDeliveryAdapter`, `CertifiableEventRecord`, `CertifiableJobStore`, `CertifiableModelGateway`, `CertifiableRuntimeAdapter`, `CertifiableRuntimeServer`, `CertifiableStorageAdapter`, `CertificationCapabilityEvidence`, `CertificationCheck`, `CertificationCheckEvidence`, `certifyAdapter`, `checkTrajectoryInvariants`, `compareAgentEvalBaseline`, `ComparisonCode`, `ContractCaseContext`, `ContractCaseKind`, `ContractCoverageGap`, `ContractCoverageGapCode`, `ContractLabHandler`, `ContractLabRuntimeAdapter`, `ContractLabServer`, `ContractLabWitness`, `contractLabWitnesses`, `ContractReplay`, `ContractRuntime`, `ContractTarget`, `ContractTestApp`, `ContractWitness`, `cookieJar`, `CookieJar`, `createFailureLab`, `createReferenceContractLabHandler`, `createTrajectoryTranscript`, `CreateTrajectoryTranscriptOptions`, `defineAgentEvalSuite`, `defineCertificationProfile`, `defineFaultProfile`, `deploymentAdapterCertificationProfile`, `deploymentCertificationProfile`, `EffectLedger`, `eventDeliveryCertificationProfile`, `FailureDirective`, `FailureEvidence`, `FailureInjectedError`, `FailureKind`, `FailureLab`, `FailureLabOptions`, `FailureReplay`, `FailureScenario`, `FailureScenarioReport`, `FaultProfile`, `FaultProfileFault`, `FaultProfileFaultKind`, `FaultProfileReport`, `FaultProfileScenario`, `FaultProfileScenarioReport`, `gatewayCertificationProfile`, `generateRegressionTest`, `GenerateRegressionTestOptions`, `httpToolAdapter`, `IdempotencyDivergence`, `IdempotencyProof`, `IncidentCapsule`, `IncidentReplayError`, `IncidentReplayResult`, `inProcessToolAdapter`, `jobStoreCertificationProfile`, `mcpToolAdapter`, `modelGatewayCertificationProfile`, `parseRubricVerdict`, `proveIdempotency`, `recordTrajectory`, `redactForEmission`, `referenceFaultProfile`, `registryCertificationProfile`, `replayIncident`, `ReplayIncidentOptions`, `replayTrajectory`, `ReplayTrajectoryOptions`, `RubricShape`, `RubricSpec`, `RubricVerdict`, `runAdversarialContract`, `runAgentEvalComposition`, `runAgentFailureMatrix`, `runContractLab`, `runContractLabOverHttp`, `runContractLabThroughAdapter`, `runFailureScenario`, `runFaultProfile`, `RunFaultProfileOptions`, `runtimeAdapterCertificationProfile`, `runTrajectory`, `ScoreTolerance`, `shapeOf`, `storageAdapterCertificationProfile`, `testSession`, `TestSession`, `TestSessionOptions`, `testToolAdapter`, `TrajectoryInvariantId`, `TrajectoryInvariantOptions`, `TrajectoryInvariantResult`, `trajectoryRegressionId`, `TrajectoryReplayResult`, `TrajectoryRun`, `TrajectoryTranscript`, `verifyAdapterCertification`
|
|
10367
11579
|
|
|
10368
11580
|
## @nifrajs/ts-plugin
|
|
10369
11581
|
|
|
@@ -10375,7 +11587,7 @@ done-gate, or `nifra mcp` to give the agent live project tools.
|
|
|
10375
11587
|
|
|
10376
11588
|
## @nifrajs/web
|
|
10377
11589
|
|
|
10378
|
-
`Action`, `ACTION_GLOBAL`, `
|
|
11590
|
+
`Action`, `ACTION_GLOBAL`, `assertRenderAdapterConformance`, `assertStaticBoundaryImports`, `Blocker`, `BlockerController`, `BlockerFunction`, `BlockerLocation`, `BlockerState`, `Boundary`, `BOUNDARY_GLOBAL`, `BoundaryDescriptor`, `boundaryDescriptors`, `BoundaryError`, `BoundaryMode`, `boundaryModeKey`, `BoundaryRegistration`, `BoundaryRequestCtx`, `BoundaryState`, `BoundaryStates`, `BoundaryStatus`, `BrowserNavigate`, `buildManifest`, `CachedResponse`, `CacheStore`, `canonical`, `ClientAction`, `ClientActionArgs`, `ClientActionResult`, `ClientLoader`, `ClientLoaderArgs`, `ClientRequestBody`, `ClientRouteHooks`, `ClientRouter`, `ClientRouterOptions`, `createClientRouter`, `createMatcher`, `createMutation`, `createQueryClient`, `createWebApp`, `CreateWebAppOptions`, `DATA_GLOBAL`, `DATA_HEADER`, `DEFAULT_DEV_PORT`, `defer`, `Deferred`, `DehydratedState`, `disableDraft`, `DRAFT_COOKIE`, `DraftCookieControls`, `DynamicBoundary`, `DynamicBoundaryBatch`, `enableDraft`, `EnableDraftOptions`, `enumerateStaticRoutes`, `Fetcher`, `FetcherState`, `FetchRouteData`, `filePathToPattern`, `filePathToPatterns`, `FontDisplay`, `fontFace`, `FontFace`, `fontPreload`, `FontPreloadInput`, `FontSource`, `generateClientEntry`, `GenerateClientEntryOptions`, `generateRouteSearchTypes`, `GenerateRouteSearchTypesOptions`, `generateServerManifest`, `GenerateServerManifestOptions`, `getBrowserNavigate`, `GetStaticPaths`, `gone`, `hashQueryKey`, `IDLE_BLOCKER`, `InertScriptType`, `InfiniteData`, `InfiniteQueryHandle`, `InfiniteQueryOptions`, `InterceptBoundary`, `isDraftEnabled`, `ISR_REVALIDATE_HEADER`, `ISR_REVALIDATE_TAGS_HEADER`, `ISR_STATUS_HEADER`, `ISRApp`, `ISROptions`, `ISRPlatform`, `jsonLd`, `KVCacheStore`, `KVCacheStoreOptions`, `KVNamespaceLike`, `LAYOUT_DATA_GLOBAL`, `LayoutEntry`, `LinkDescriptor`, `Loader`, `LoaderContext`, `Manifest`, `MemoryCacheStore`, `MemoryCacheStoreOptions`, `MemoryStaticBoundaryCache`, `mergeHeads`, `Meta`, `MetaArgs`, `MetaDescriptor`, `MetaInput`, `MountRouterOptions`, `MutationCallbacks`, `MutationHandle`, `MutationState`, `MutationStatus`, `NAV_FROM_HEADER`, `NavigateFunction`, `NavigateOptions`, `NavigateSearchOf`, `NavigateTargetInput`, `notFound`, `openGraph`, `OpenGraphInput`, `PendingBoundary`, `PRE_HYDRATION_GUARD`, `previewEndpoint`, `PreviewEndpointOptions`, `PublicDirCache`, `QueryClient`, `QueryClientOptions`, `QueryHandle`, `QueryOptions`, `QueryState`, `QueryStatus`, `redirect`, `REDIRECT_HEADER`, `RedirectOptions`, `registerBlocker`, `RenderAdapter`, `RenderAdapterConformanceError`, `RenderAdapterConformanceFixture`, `RenderAssemblyCache`, `RenderedPage`, `renderPage`, `RenderPageInput`, `RenderPageOptions`, `renderPageResult`, `RenderProps`, `resolveDynamicBoundaries`, `resolveMeta`, `resolveNavigate`, `resolvePublicPath`, `resolveStaticBoundaries`, `RETAIN_HEADER`, `revalidate`, `REVALIDATE_HEADER`, `revalidateEndpoint`, `RevalidateEndpointOptions`, `RevalidateResult`, `ROOT_ATTRIBUTE`, `ROUTE_GLOBAL`, `RouteEntry`, `RouteMatch`, `RouteModule`, `RoutePattern`, `RouterState`, `RouteSearch`, `ScriptDescriptor`, `searchOf`, `SearchOf`, `searchOfChain`, `serializeData`, `serializeSearch`, `servePublicDir`, `ServePublicDirOptions`, `SERVER_FN_MODULE`, `SERVER_ONLY_MODULE`, `ServerOnly`, `setBlockerController`, `setBrowserNavigate`, `setSsrModuleLoader`, `ssrModuleLoader`, `SsrModuleLoader`, `startDynamicBoundaries`, `StaticBoundary`, `StaticBoundaryCache`, `StaticBoundaryImportEdge`, `StaticBoundaryRoot`, `StaticCtx`, `StaticPath`, `StaticPaths`, `StaticRoutes`, `STATUS_HEADER`, `statusPage`, `StatusPageOptions`, `Submission`, `SubmitOptions`, `unsafeInlineScript`, `UnsafeScriptDescriptor`, `withISR`
|
|
10379
11591
|
|
|
10380
11592
|
## @nifrajs/web-preact
|
|
10381
11593
|
|