@agent-native/core 0.75.4 → 0.75.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +40 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/durable-background.ts +62 -28
  5. package/corpus/core/src/agent/production-agent.ts +16 -12
  6. package/corpus/core/src/cli/skills.ts +22 -4
  7. package/corpus/core/src/deploy/build.ts +47 -113
  8. package/corpus/core/src/deploy/workspace-deploy.ts +62 -30
  9. package/corpus/core/src/server/self-dispatch.ts +29 -2
  10. package/corpus/templates/clips/changelog/2026-06-24-chrome-extension-setup-now-shows-a-clear-all-done-confirmati.md +6 -0
  11. package/corpus/templates/clips/chrome-extension/src/permission.html +60 -0
  12. package/corpus/templates/clips/chrome-extension/src/permission.ts +28 -15
  13. package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +22 -4
  14. package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +22 -4
  15. package/dist/agent/durable-background.d.ts +32 -28
  16. package/dist/agent/durable-background.d.ts.map +1 -1
  17. package/dist/agent/durable-background.js +59 -28
  18. package/dist/agent/durable-background.js.map +1 -1
  19. package/dist/agent/production-agent.d.ts.map +1 -1
  20. package/dist/agent/production-agent.js +16 -12
  21. package/dist/agent/production-agent.js.map +1 -1
  22. package/dist/cli/skills.d.ts +1 -1
  23. package/dist/cli/skills.d.ts.map +1 -1
  24. package/dist/cli/skills.js +22 -4
  25. package/dist/cli/skills.js.map +1 -1
  26. package/dist/deploy/build.d.ts +32 -36
  27. package/dist/deploy/build.d.ts.map +1 -1
  28. package/dist/deploy/build.js +47 -104
  29. package/dist/deploy/build.js.map +1 -1
  30. package/dist/deploy/workspace-deploy.js +62 -30
  31. package/dist/deploy/workspace-deploy.js.map +1 -1
  32. package/dist/server/self-dispatch.d.ts +0 -10
  33. package/dist/server/self-dispatch.d.ts.map +1 -1
  34. package/dist/server/self-dispatch.js +27 -2
  35. package/dist/server/self-dispatch.js.map +1 -1
  36. package/package.json +1 -1
@@ -63,61 +63,57 @@ export declare function isDurableBackgroundDeployEnabled(): boolean;
63
63
  * 15-min async function instead of the synchronous `/*` catch-all.
64
64
  * Additive + flag-gated (see `isDurableBackgroundDeployEnabled`).
65
65
  *
66
- * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT (verified from a local Nitro build):
66
+ * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT (verified from a local Nitro build)
67
+ * AND THE NETLIFY DOCS DEFAULT-URL RULE:
67
68
  * - Nitro's `netlify` preset emits exactly ONE function source at
68
69
  * `.netlify/functions-internal/server/`. `server.mjs` re-exports `main.mjs`
69
70
  * and declares `export const config = { path: "/*", excludedPath:
70
- * ["/.netlify/*"], preferStatic: true, ... }`. Nitro writes NO `netlify.toml`
71
- * and NO `[[redirects]]`; the `/*` catch-all is an IN-CODE Functions-API-v2
72
- * `config.path`.
71
+ * ["/.netlify/*"], preferStatic: true, ... }`. The `/*` catch-all is an
72
+ * IN-CODE Functions-API-v2 `config.path` and it ALREADY EXCLUDES
73
+ * `/.netlify/*`.
73
74
  * - The generated `.netlify/netlify.toml` sets
74
75
  * `functionsDirectory = ".netlify/functions-internal"`. Netlify scans EXACTLY
75
76
  * that dir; functions placed anywhere else (e.g. `.netlify/functions/`, which
76
77
  * is the BUILD OUTPUT dir where `@netlify/build` later writes the zipped
77
78
  * functions + `manifest.json`) are NEVER deployed.
78
- * - On Netlify CI, `@netlify/build` reads each scanned function's
79
- * `export const config`, zips it, and materializes
80
- * `.netlify/functions/manifest.json` with `routes` derived from each
81
- * `config.path`. So per-file `export const config` (including `background` and
82
- * `path`) IS honored — the `server` manifest entry's `routes: [{ pattern:
83
- * "/*" }]` came straight from `server.mjs`'s `config.path`.
79
+ * - Every scanned function is reachable at its DEFAULT url
80
+ * `/.netlify/functions/<name>` BY DEFAULT. A custom `config.path` REMOVES
81
+ * that default url; declaring NO custom `config.path` KEEPS it.
84
82
  *
85
83
  * THEREFORE we:
86
84
  * 1. Emit the background function INTO the scanned dir
87
85
  * (`.netlify/functions-internal/server-agent-background/`), sharing the same
88
86
  * built `main.mjs` bundle, so Netlify discovers it and honors its config.
89
- * 2. Give its `export const config` BOTH `background: true` (→ async invoke,
90
- * immediate 202, 15-min budget) AND `path: AGENT_CHAT_PROCESS_RUN_PATH` (so
91
- * it claims that exact path at function-matching time, which Netlify
92
- * evaluates BEFORE redirects — step 10 vs 11 in the request chain).
93
- * 3. PATCH the Nitro `server` function's own `server.mjs` so its catch-all
94
- * `config.path: "/*"` EXCLUDES `AGENT_CHAT_PROCESS_RUN_PATH` (append it to
95
- * `excludedPath`). Netlify does NOT define a winner when two serverless
96
- * functions both match a path; rather than rely on that undocumented order,
97
- * we make the match UNAMBIGUOUS — only the background function matches
98
- * `_process-run`, and `server` matches everything else exactly as before.
87
+ * 2. Give its `export const config` `background: true` (→ async invoke,
88
+ * immediate 202, 15-min budget) and NO custom `config.path`. With no custom
89
+ * path the function keeps its DEFAULT url
90
+ * `/.netlify/functions/server-agent-background`, and because the Nitro
91
+ * `server` function's `/*` catch-all already excludes `/.netlify/*`, that
92
+ * default-url namespace is NEVER shadowed by the synchronous function — no
93
+ * catch-all patch is needed.
94
+ * 3. The entry NORMALIZES/rewrites the incoming request pathname to
95
+ * `AGENT_CHAT_PROCESS_RUN_PATH` before delegating to `./main.mjs`. The
96
+ * function is reached at its default url
97
+ * (`/.netlify/functions/server-agent-background`), so the Nitro router needs
98
+ * the path rewritten to the framework `_process-run` route, preserving the
99
+ * method, ALL headers (the HMAC `Authorization: Bearer` MUST survive), and
100
+ * the body.
99
101
  * 4. Set `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true` at cold start
100
102
  * (read back by `isInBackgroundFunctionRuntime()` so the worker takes the
101
103
  * ~13-min soft-timeout). A `globalThis` flag — NOT `process.env` — keeps the
102
104
  * no-env-mutation guard satisfied and carries no cross-request state.
103
105
  *
104
- * With a real `config.path` the function is reachable at that path directly, so
105
- * the foreground POSTs to `AGENT_CHAT_PROCESS_RUN_PATH`
106
- * (`resolveAgentChatProcessRunDispatchPath`) and the request entry no longer
107
- * needs to rewrite the path — it already arrives at the framework route. We keep
108
- * a defensive normalize-to-PROCESS_RUN_PATH in the entry anyway (cheap, and it
109
- * makes the function correct even if reached via its default function url).
106
+ * The foreground dispatches to this DEFAULT url on hosted Netlify
107
+ * (`resolveAgentChatProcessRunDispatchPath` `AGENT_BACKGROUND_FUNCTION_URL_PATH`).
110
108
  *
111
- * WHY THIS BEATS ALL THREE PRIOR FAILURES:
112
- * - Attempts 1 & 2 emitted into `functions-internal` (correct dir) with a
113
- * `config.path` but did NOT exclude that path from the `server` `/*`
114
- * catch-all. Two functions matched `_process-run`; the order is undocumented
115
- * and the catch-all `server` (priority 0, synchronous) won SYNC 401, not a
116
- * 202. We now exclude the path from `server`, so only the async function
117
- * matches.
118
- * - Attempt 3 emitted a standalone function into `.netlify/functions/` — the
119
- * OUTPUT dir, which Netlify does not scan — so it never entered the manifest
120
- * → 404. We now emit into the SCANNED `functions-internal` dir.
109
+ * WHY THIS IS THE DOC-CORRECT FIX: a prior attempt gave the function a custom
110
+ * `config.path` (= the framework route) plus a catch-all `excludedPath` patch.
111
+ * The custom `config.path` was NOT honored as a route in prod — a probe of
112
+ * `POST /_agent-native/agent-chat/_process-run` returned 404. The doc-correct
113
+ * approach (confirmed against the Netlify docs) is to use the DEFAULT function
114
+ * url with no custom path: the function stays reachable at
115
+ * `/.netlify/functions/<name>` and is never shadowed because `/.netlify/*` is
116
+ * already excluded from the `server` catch-all.
121
117
  *
122
118
  * Safety net regardless of Netlify routing nuance: if the dispatch fast-fails
123
119
  * (e.g. the function was not emitted), the foreground handler degrades to an
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AA+B7B,eAAO,MAAM,6BAA6B,UAiBzC,CAAC;AAuBF,wBAAgB,wCAAwC,CACtD,WAAW,EAAE,MAAM,EAAE,GACpB,MAAM,CAaR;AAgBD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAgBvE,wBAAgB,yCAAyC,CACvD,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,SAAK,GACf,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EAAE,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,kBAAkB,GAAE,MAAM,EAAO,EACjC,OAAO,GAAE,gBAAgB,EAAO,EAChC,aAAa,GAAE,oBAAoB,GAAG,IAAW,EACjD,mBAAmB,GAAE,MAAM,EAAO,EAClC,gBAAgB,SAAmC,GAClD,MAAM,CAskBR;AAyXD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAkHD,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,iBAAiB,cAAoB,QAoCtC;AAuBD,KAAK,0BAA0B,GAAG,OAAO,GAAG,KAAK,CAAC;AAQlD,wBAAgB,qCAAqC,CACnD,YAAY,GAAE,MAAM,CAAC,QAA2B,EAChD,QAAQ,GAAE,MAAM,CAAC,YAA2B,EAC5C,UAAU,GAAE,0BAA0B,GAAG,IAAgD,GACxF,OAAO,CAOT;AAqED,wBAAgB,gCAAgC,CAC9C,gBAAgB,EAAE,MAAM,EAAE,GACzB,MAAM,GAAG,IAAI,CA8Bf;AAED,wBAAgB,0BAA0B,CACxC,gBAAgB,EAAE,MAAM,EAAE,GACzB,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCpD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gCAAgC,IAAI,OAAO,CAK1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,wBAAgB,2CAA2C,CACzD,UAAU,EAAE,MAAM,GACjB,IAAI,CA8FN;AA2QD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AA+B7B,eAAO,MAAM,6BAA6B,UAiBzC,CAAC;AAuBF,wBAAgB,wCAAwC,CACtD,WAAW,EAAE,MAAM,EAAE,GACpB,MAAM,CAaR;AAgBD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAgBvE,wBAAgB,yCAAyC,CACvD,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,SAAK,GACf,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EAAE,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,kBAAkB,GAAE,MAAM,EAAO,EACjC,OAAO,GAAE,gBAAgB,EAAO,EAChC,aAAa,GAAE,oBAAoB,GAAG,IAAW,EACjD,mBAAmB,GAAE,MAAM,EAAO,EAClC,gBAAgB,SAAmC,GAClD,MAAM,CAskBR;AAyXD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAkHD,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,iBAAiB,cAAoB,QAoCtC;AAuBD,KAAK,0BAA0B,GAAG,OAAO,GAAG,KAAK,CAAC;AAQlD,wBAAgB,qCAAqC,CACnD,YAAY,GAAE,MAAM,CAAC,QAA2B,EAChD,QAAQ,GAAE,MAAM,CAAC,YAA2B,EAC5C,UAAU,GAAE,0BAA0B,GAAG,IAAgD,GACxF,OAAO,CAOT;AAqED,wBAAgB,gCAAgC,CAC9C,gBAAgB,EAAE,MAAM,EAAE,GACzB,MAAM,GAAG,IAAI,CA8Bf;AAED,wBAAgB,0BAA0B,CACxC,gBAAgB,EAAE,MAAM,EAAE,GACzB,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAqCpD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gCAAgC,IAAI,OAAO,CAK1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,wBAAgB,2CAA2C,CACzD,UAAU,EAAE,MAAM,GACjB,IAAI,CAyFN;AAkND;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -1257,61 +1257,57 @@ export function isDurableBackgroundDeployEnabled() {
1257
1257
  * 15-min async function instead of the synchronous `/*` catch-all.
1258
1258
  * Additive + flag-gated (see `isDurableBackgroundDeployEnabled`).
1259
1259
  *
1260
- * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT (verified from a local Nitro build):
1260
+ * GROUNDED IN THE REAL NETLIFY BUILD OUTPUT (verified from a local Nitro build)
1261
+ * AND THE NETLIFY DOCS DEFAULT-URL RULE:
1261
1262
  * - Nitro's `netlify` preset emits exactly ONE function source at
1262
1263
  * `.netlify/functions-internal/server/`. `server.mjs` re-exports `main.mjs`
1263
1264
  * and declares `export const config = { path: "/*", excludedPath:
1264
- * ["/.netlify/*"], preferStatic: true, ... }`. Nitro writes NO `netlify.toml`
1265
- * and NO `[[redirects]]`; the `/*` catch-all is an IN-CODE Functions-API-v2
1266
- * `config.path`.
1265
+ * ["/.netlify/*"], preferStatic: true, ... }`. The `/*` catch-all is an
1266
+ * IN-CODE Functions-API-v2 `config.path` and it ALREADY EXCLUDES
1267
+ * `/.netlify/*`.
1267
1268
  * - The generated `.netlify/netlify.toml` sets
1268
1269
  * `functionsDirectory = ".netlify/functions-internal"`. Netlify scans EXACTLY
1269
1270
  * that dir; functions placed anywhere else (e.g. `.netlify/functions/`, which
1270
1271
  * is the BUILD OUTPUT dir where `@netlify/build` later writes the zipped
1271
1272
  * functions + `manifest.json`) are NEVER deployed.
1272
- * - On Netlify CI, `@netlify/build` reads each scanned function's
1273
- * `export const config`, zips it, and materializes
1274
- * `.netlify/functions/manifest.json` with `routes` derived from each
1275
- * `config.path`. So per-file `export const config` (including `background` and
1276
- * `path`) IS honored — the `server` manifest entry's `routes: [{ pattern:
1277
- * "/*" }]` came straight from `server.mjs`'s `config.path`.
1273
+ * - Every scanned function is reachable at its DEFAULT url
1274
+ * `/.netlify/functions/<name>` BY DEFAULT. A custom `config.path` REMOVES
1275
+ * that default url; declaring NO custom `config.path` KEEPS it.
1278
1276
  *
1279
1277
  * THEREFORE we:
1280
1278
  * 1. Emit the background function INTO the scanned dir
1281
1279
  * (`.netlify/functions-internal/server-agent-background/`), sharing the same
1282
1280
  * built `main.mjs` bundle, so Netlify discovers it and honors its config.
1283
- * 2. Give its `export const config` BOTH `background: true` (→ async invoke,
1284
- * immediate 202, 15-min budget) AND `path: AGENT_CHAT_PROCESS_RUN_PATH` (so
1285
- * it claims that exact path at function-matching time, which Netlify
1286
- * evaluates BEFORE redirects — step 10 vs 11 in the request chain).
1287
- * 3. PATCH the Nitro `server` function's own `server.mjs` so its catch-all
1288
- * `config.path: "/*"` EXCLUDES `AGENT_CHAT_PROCESS_RUN_PATH` (append it to
1289
- * `excludedPath`). Netlify does NOT define a winner when two serverless
1290
- * functions both match a path; rather than rely on that undocumented order,
1291
- * we make the match UNAMBIGUOUS — only the background function matches
1292
- * `_process-run`, and `server` matches everything else exactly as before.
1281
+ * 2. Give its `export const config` `background: true` (→ async invoke,
1282
+ * immediate 202, 15-min budget) and NO custom `config.path`. With no custom
1283
+ * path the function keeps its DEFAULT url
1284
+ * `/.netlify/functions/server-agent-background`, and because the Nitro
1285
+ * `server` function's `/*` catch-all already excludes `/.netlify/*`, that
1286
+ * default-url namespace is NEVER shadowed by the synchronous function — no
1287
+ * catch-all patch is needed.
1288
+ * 3. The entry NORMALIZES/rewrites the incoming request pathname to
1289
+ * `AGENT_CHAT_PROCESS_RUN_PATH` before delegating to `./main.mjs`. The
1290
+ * function is reached at its default url
1291
+ * (`/.netlify/functions/server-agent-background`), so the Nitro router needs
1292
+ * the path rewritten to the framework `_process-run` route, preserving the
1293
+ * method, ALL headers (the HMAC `Authorization: Bearer` MUST survive), and
1294
+ * the body.
1293
1295
  * 4. Set `globalThis.__AGENT_NATIVE_BACKGROUND_RUNTIME__ = true` at cold start
1294
1296
  * (read back by `isInBackgroundFunctionRuntime()` so the worker takes the
1295
1297
  * ~13-min soft-timeout). A `globalThis` flag — NOT `process.env` — keeps the
1296
1298
  * no-env-mutation guard satisfied and carries no cross-request state.
1297
1299
  *
1298
- * With a real `config.path` the function is reachable at that path directly, so
1299
- * the foreground POSTs to `AGENT_CHAT_PROCESS_RUN_PATH`
1300
- * (`resolveAgentChatProcessRunDispatchPath`) and the request entry no longer
1301
- * needs to rewrite the path — it already arrives at the framework route. We keep
1302
- * a defensive normalize-to-PROCESS_RUN_PATH in the entry anyway (cheap, and it
1303
- * makes the function correct even if reached via its default function url).
1300
+ * The foreground dispatches to this DEFAULT url on hosted Netlify
1301
+ * (`resolveAgentChatProcessRunDispatchPath` `AGENT_BACKGROUND_FUNCTION_URL_PATH`).
1304
1302
  *
1305
- * WHY THIS BEATS ALL THREE PRIOR FAILURES:
1306
- * - Attempts 1 & 2 emitted into `functions-internal` (correct dir) with a
1307
- * `config.path` but did NOT exclude that path from the `server` `/*`
1308
- * catch-all. Two functions matched `_process-run`; the order is undocumented
1309
- * and the catch-all `server` (priority 0, synchronous) won SYNC 401, not a
1310
- * 202. We now exclude the path from `server`, so only the async function
1311
- * matches.
1312
- * - Attempt 3 emitted a standalone function into `.netlify/functions/` — the
1313
- * OUTPUT dir, which Netlify does not scan — so it never entered the manifest
1314
- * → 404. We now emit into the SCANNED `functions-internal` dir.
1303
+ * WHY THIS IS THE DOC-CORRECT FIX: a prior attempt gave the function a custom
1304
+ * `config.path` (= the framework route) plus a catch-all `excludedPath` patch.
1305
+ * The custom `config.path` was NOT honored as a route in prod — a probe of
1306
+ * `POST /_agent-native/agent-chat/_process-run` returned 404. The doc-correct
1307
+ * approach (confirmed against the Netlify docs) is to use the DEFAULT function
1308
+ * url with no custom path: the function stays reachable at
1309
+ * `/.netlify/functions/<name>` and is never shadowed because `/.netlify/*` is
1310
+ * already excluded from the `server` catch-all.
1315
1311
  *
1316
1312
  * Safety net regardless of Netlify routing nuance: if the dispatch fast-fails
1317
1313
  * (e.g. the function was not emitted), the foreground handler degrades to an
@@ -1338,10 +1334,6 @@ export function emitSingleTemplateNetlifyBackgroundFunction(projectCwd) {
1338
1334
  // Drop the original Nitro `/*` entry so our entry is the entrypoint and the
1339
1335
  // copied bundle does NOT re-register the catch-all `config.path`.
1340
1336
  fs.rmSync(path.join(dest, "server.mjs"), { force: true });
1341
- // Make the `server` `/*` catch-all NOT match the process-run path, so only the
1342
- // async background function matches it (function-vs-function path order is
1343
- // undocumented on Netlify — don't rely on it).
1344
- excludeProcessRunPathFromServerCatchAll(serverDir);
1345
1337
  const processRunPath = JSON.stringify(AGENT_CHAT_PROCESS_RUN_PATH);
1346
1338
  const entry = `// Mark this isolate as the durable background runtime BEFORE the handler
1347
1339
  // bundle is imported, so isInBackgroundFunctionRuntime() reliably returns true
@@ -1359,11 +1351,10 @@ let cachedHandler;
1359
1351
 
1360
1352
  // Netlify v2 invokes this as (request, context). The Nitro netlify handler is a
1361
1353
  // Web-standard \`async (Request) => Response\` (see nitro/presets/netlify/runtime).
1362
- // Because this function declares \`config.path = PROCESS_RUN_PATH\`, Netlify routes
1363
- // that exact path here and the request already arrives as PROCESS_RUN_PATH — no
1364
- // rewrite is needed. We still NORMALIZE the pathname to PROCESS_RUN_PATH so the
1365
- // function stays correct even if it is ever reached via its default function url
1366
- // (/.netlify/functions/${backgroundName}). Method, ALL headers (the HMAC
1354
+ // This function declares NO custom \`config.path\`, so it is reached at its
1355
+ // DEFAULT url (/.netlify/functions/${backgroundName}). The Nitro router only
1356
+ // knows the framework route, so we REWRITE the incoming pathname to
1357
+ // PROCESS_RUN_PATH before delegating. Method, ALL headers (the HMAC
1367
1358
  // Authorization: Bearer MUST survive — the plugin verifies it) and the body are
1368
1359
  // preserved by cloning the incoming Request with only its URL pathname set.
1369
1360
  export default async function handler(request) {
@@ -1387,13 +1378,12 @@ export const config = {
1387
1378
  generator: "agent-native build",
1388
1379
  // background: true makes Netlify invoke this ASYNCHRONOUSLY (immediate HTTP
1389
1380
  // 202 ack) with the 15-minute budget (Netlify docs:
1390
- // build/functions/background-functions + build/functions/api). path claims the
1391
- // process-run route directly; Netlify evaluates serverless functions BEFORE
1392
- // redirects (request-chain step 10 vs 11), and we exclude this path from the
1393
- // \`server\` /* catch-all so only THIS function matches it no ambiguous
1394
- // function-vs-function order.
1381
+ // build/functions/background-functions + build/functions/api). We declare NO
1382
+ // custom path, so the function keeps its DEFAULT url
1383
+ // /.netlify/functions/${backgroundName}; the Nitro \`server\` /* catch-all
1384
+ // already excludes /.netlify/* so that default url is never shadowed by the
1385
+ // synchronous function. The foreground dispatches to that default url.
1395
1386
  background: true,
1396
- path: PROCESS_RUN_PATH,
1397
1387
  nodeBundler: "none",
1398
1388
  includedFiles: ["**"],
1399
1389
  preferStatic: false,
@@ -1401,59 +1391,12 @@ export const config = {
1401
1391
  `;
1402
1392
  fs.writeFileSync(path.join(dest, `${backgroundName}.mjs`), entry);
1403
1393
  console.log(`[build] Emitted durable-background function "${backgroundName}" into the ` +
1404
- `scanned dir .netlify/functions-internal with config { background:true, ` +
1405
- `path:"${AGENT_CHAT_PROCESS_RUN_PATH}" } and excluded that path from the ` +
1406
- `server /* catch-all. REQUIRES real-deploy verification of Netlify async ` +
1407
- `(202) invocation see docs/design/durable-agent-runs.md.`);
1408
- }
1409
- /**
1410
- * Append `AGENT_CHAT_PROCESS_RUN_PATH` to the Nitro `server` function's
1411
- * `config.excludedPath` so its `/*` catch-all does NOT match the process-run
1412
- * path. That guarantees the async background function (which declares
1413
- * `config.path = AGENT_CHAT_PROCESS_RUN_PATH`) is the ONLY function that matches
1414
- * that path — Netlify does not define a winner when two serverless functions
1415
- * both match, so we make the match unambiguous instead of relying on order.
1416
- *
1417
- * The Nitro-generated `server/server.mjs` is small and deterministic:
1418
- * export { default } from "./main.mjs";
1419
- * export const config = { ... excludedPath: ["/.netlify/*"], ... };
1420
- * We parse the `excludedPath: [...]` array literal and add our path if absent.
1421
- * If the shape ever changes and we can't find/parse it, we log and leave the
1422
- * file untouched (the inline-40s fallback still keeps chat working).
1423
- */
1424
- function excludeProcessRunPathFromServerCatchAll(serverDir) {
1425
- const serverEntry = path.join(serverDir, "server.mjs");
1426
- if (!fs.existsSync(serverEntry)) {
1427
- console.warn("[build] Durable-background: server/server.mjs not found; cannot exclude " +
1428
- `${AGENT_CHAT_PROCESS_RUN_PATH} from the /* catch-all.`);
1429
- return;
1430
- }
1431
- const original = fs.readFileSync(serverEntry, "utf8");
1432
- if (original.includes(AGENT_CHAT_PROCESS_RUN_PATH)) {
1433
- // Already excluded (idempotent — emit may run on a re-used output tree).
1434
- return;
1435
- }
1436
- const excludedPathRe = /excludedPath:\s*\[([^\]]*)\]/;
1437
- const match = original.match(excludedPathRe);
1438
- const quotedPath = JSON.stringify(AGENT_CHAT_PROCESS_RUN_PATH);
1439
- if (match) {
1440
- const existing = match[1].trim();
1441
- const next = existing
1442
- ? `excludedPath: [${existing.replace(/,\s*$/, "")}, ${quotedPath}]`
1443
- : `excludedPath: [${quotedPath}]`;
1444
- fs.writeFileSync(serverEntry, original.replace(excludedPathRe, next));
1445
- return;
1446
- }
1447
- // No existing `excludedPath` — inject one into the config object. Match the
1448
- // `path: "/*"` line and add `excludedPath` right after it.
1449
- const pathLineRe = /(path:\s*("\/\*"|'\/\*'),?)/;
1450
- if (pathLineRe.test(original)) {
1451
- fs.writeFileSync(serverEntry, original.replace(pathLineRe, `$1\n excludedPath: [${quotedPath}],`));
1452
- return;
1453
- }
1454
- console.warn("[build] Durable-background: could not locate excludedPath/path in " +
1455
- "server/server.mjs; leaving the /* catch-all unchanged (the background " +
1456
- "function may be shadowed — the inline-40s fallback still applies).");
1394
+ `scanned dir .netlify/functions-internal with config { background:true } ` +
1395
+ `and NO custom path reachable at its default url ` +
1396
+ `/.netlify/functions/${backgroundName} (never shadowed; the server /* ` +
1397
+ `catch-all already excludes /.netlify/*). REQUIRES real-deploy ` +
1398
+ `verification of Netlify async (202) invocation — see ` +
1399
+ `docs/design/durable-agent-runs.md.`);
1457
1400
  }
1458
1401
  function copyInstalledLibsqlNativePackages(serverDir) {
1459
1402
  if (!serverDir || !fs.existsSync(serverDir))