@agent-native/core 0.16.3 → 0.17.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.
@@ -0,0 +1,3 @@
1
+ declare const _default: any;
2
+ export default _default;
3
+ //# sourceMappingURL=toggle-demo-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-demo-mode.d.ts","sourceRoot":"","sources":["../../../src/demo/actions/toggle-demo-mode.ts"],"names":[],"mappings":";AAIA,wBAiBG"}
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ import { defineAction } from "../../action.js";
3
+ import { writeAppState } from "../../application-state/script-helpers.js";
4
+ export default defineAction({
5
+ description: "Turn demo mode on or off. When demo mode is on, the app replaces real names, email addresses, and numbers with realistic fake data everywhere — in the UI and in what you (the agent) see — while keeping IDs, dates, and structure intact so everything still works. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.",
6
+ schema: z.object({
7
+ enabled: z
8
+ .boolean()
9
+ .describe("true to turn demo mode on, false to turn it off."),
10
+ }),
11
+ run: async ({ enabled }) => {
12
+ await writeAppState("demo-mode", { enabled });
13
+ return {
14
+ enabled,
15
+ message: enabled
16
+ ? "Demo mode is ON — real names, emails, and numbers are now replaced with deterministic fake data everywhere (UI and agent). IDs and structure are preserved so everything keeps working."
17
+ : "Demo mode is OFF — real data is shown again.",
18
+ };
19
+ },
20
+ });
21
+ //# sourceMappingURL=toggle-demo-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toggle-demo-mode.js","sourceRoot":"","sources":["../../../src/demo/actions/toggle-demo-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAE1E,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,gcAAgc;IAClc,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,QAAQ,CAAC,kDAAkD,CAAC;KAChE,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACzB,MAAM,aAAa,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9C,OAAO;YACL,OAAO;YACP,OAAO,EAAE,OAAO;gBACd,CAAC,CAAC,yLAAyL;gBAC3L,CAAC,CAAC,8CAA8C;SACnD,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { defineAction } from \"../../action.js\";\nimport { writeAppState } from \"../../application-state/script-helpers.js\";\n\nexport default defineAction({\n description:\n \"Turn demo mode on or off. When demo mode is on, the app replaces real names, email addresses, and numbers with realistic fake data everywhere — in the UI and in what you (the agent) see — while keeping IDs, dates, and structure intact so everything still works. Use when the user asks to 'hide my data', 'turn on demo mode', 'anonymize this for a screen share / recording', or similar. This is the same toggle as the Demo mode switch in settings.\",\n schema: z.object({\n enabled: z\n .boolean()\n .describe(\"true to turn demo mode on, false to turn it off.\"),\n }),\n run: async ({ enabled }) => {\n await writeAppState(\"demo-mode\", { enabled });\n return {\n enabled,\n message: enabled\n ? \"Demo mode is ON — real names, emails, and numbers are now replaced with deterministic fake data everywhere (UI and agent). IDs and structure are preserved so everything keeps working.\"\n : \"Demo mode is OFF — real data is shown again.\",\n };\n },\n});\n"]}
@@ -0,0 +1,9 @@
1
+ /** Deployment-wide force (hosted demo site). Zero cost — no I/O. */
2
+ export declare function isDemoModeForced(): boolean;
3
+ /**
4
+ * Whether demo-mode redaction should run for the current request/user.
5
+ * Cheap by design — safe to call before every action result; the expensive
6
+ * walk only happens when this is true.
7
+ */
8
+ export declare function isDemoModeEnabled(): Promise<boolean>;
9
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/demo/config.ts"],"names":[],"mappings":"AAwBA,oEAAoE;AACpE,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAsB1D"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Demo mode gate.
3
+ *
4
+ * Demo mode replaces real names, email addresses, and numbers in every action
5
+ * result with deterministic fake data — for both the UI and what the agent
6
+ * sees — while preserving IDs, dates, URLs, and structure so the app keeps
7
+ * working. The redaction WALK (see ./redact.ts) is expensive on large
8
+ * payloads, so callers MUST gate it behind this function and only walk when it
9
+ * returns true.
10
+ *
11
+ * This gate itself is intentionally cheap:
12
+ * - An env-forced deployment (a hosted demo site) short-circuits with zero
13
+ * I/O — `DEMO_MODE=true`.
14
+ * - The per-user runtime toggle lives in `application_state` under the
15
+ * `demo-mode` key (`{ enabled: boolean }`), written by the settings UI and
16
+ * the `toggle-demo-mode` agent action. It's read behind a short in-process
17
+ * TTL cache keyed by user, so a tight agent tool-call loop doesn't hit the
18
+ * DB on every result.
19
+ */
20
+ import { readAppState } from "../application-state/script-helpers.js";
21
+ const TTL_MS = 3_000;
22
+ const cache = new Map();
23
+ /** Deployment-wide force (hosted demo site). Zero cost — no I/O. */
24
+ export function isDemoModeForced() {
25
+ return process.env.DEMO_MODE === "true";
26
+ }
27
+ /**
28
+ * Whether demo-mode redaction should run for the current request/user.
29
+ * Cheap by design — safe to call before every action result; the expensive
30
+ * walk only happens when this is true.
31
+ */
32
+ export async function isDemoModeEnabled() {
33
+ if (isDemoModeForced())
34
+ return true;
35
+ try {
36
+ let sessionKey = "_";
37
+ try {
38
+ const { getRequestUserEmail } = await import("../server/request-context.js");
39
+ sessionKey = getRequestUserEmail() ?? process.env.AGENT_USER_EMAIL ?? "_";
40
+ }
41
+ catch {
42
+ // request-context unavailable (CLI / non-server) — use default key
43
+ }
44
+ const now = Date.now();
45
+ const hit = cache.get(sessionKey);
46
+ if (hit && now - hit.at < TTL_MS)
47
+ return hit.value;
48
+ const state = await readAppState("demo-mode");
49
+ const enabled = state?.enabled === true;
50
+ cache.set(sessionKey, { value: enabled, at: now });
51
+ return enabled;
52
+ }
53
+ catch {
54
+ // No request context / DB unavailable — fail closed (no redaction).
55
+ return false;
56
+ }
57
+ }
58
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/demo/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAEtE,MAAM,MAAM,GAAG,KAAK,CAAC;AACrB,MAAM,KAAK,GAAG,IAAI,GAAG,EAA0C,CAAC;AAEhE,oEAAoE;AACpE,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,MAAM,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,gBAAgB,EAAE;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,IAAI,UAAU,GAAG,GAAG,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,EAAE,mBAAmB,EAAE,GAC3B,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAC;YAC/C,UAAU,GAAG,mBAAmB,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;QACrE,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClC,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM;YAAE,OAAO,GAAG,CAAC,KAAK,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;QACxC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACnD,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["/**\n * Demo mode gate.\n *\n * Demo mode replaces real names, email addresses, and numbers in every action\n * result with deterministic fake data — for both the UI and what the agent\n * sees — while preserving IDs, dates, URLs, and structure so the app keeps\n * working. The redaction WALK (see ./redact.ts) is expensive on large\n * payloads, so callers MUST gate it behind this function and only walk when it\n * returns true.\n *\n * This gate itself is intentionally cheap:\n * - An env-forced deployment (a hosted demo site) short-circuits with zero\n * I/O — `DEMO_MODE=true`.\n * - The per-user runtime toggle lives in `application_state` under the\n * `demo-mode` key (`{ enabled: boolean }`), written by the settings UI and\n * the `toggle-demo-mode` agent action. It's read behind a short in-process\n * TTL cache keyed by user, so a tight agent tool-call loop doesn't hit the\n * DB on every result.\n */\nimport { readAppState } from \"../application-state/script-helpers.js\";\n\nconst TTL_MS = 3_000;\nconst cache = new Map<string, { value: boolean; at: number }>();\n\n/** Deployment-wide force (hosted demo site). Zero cost — no I/O. */\nexport function isDemoModeForced(): boolean {\n return process.env.DEMO_MODE === \"true\";\n}\n\n/**\n * Whether demo-mode redaction should run for the current request/user.\n * Cheap by design — safe to call before every action result; the expensive\n * walk only happens when this is true.\n */\nexport async function isDemoModeEnabled(): Promise<boolean> {\n if (isDemoModeForced()) return true;\n try {\n let sessionKey = \"_\";\n try {\n const { getRequestUserEmail } =\n await import(\"../server/request-context.js\");\n sessionKey = getRequestUserEmail() ?? process.env.AGENT_USER_EMAIL ?? \"_\";\n } catch {\n // request-context unavailable (CLI / non-server) — use default key\n }\n const now = Date.now();\n const hit = cache.get(sessionKey);\n if (hit && now - hit.at < TTL_MS) return hit.value;\n const state = await readAppState(\"demo-mode\");\n const enabled = state?.enabled === true;\n cache.set(sessionKey, { value: enabled, at: now });\n return enabled;\n } catch {\n // No request context / DB unavailable — fail closed (no redaction).\n return false;\n }\n}\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Pure, dependency-free, deterministic demo-mode redactor.
3
+ *
4
+ * Replaces sensitive values (names, emails, free numbers) with stable fake
5
+ * substitutes so a demo looks coherent — the same input always maps to the
6
+ * same fake. Crucially, it NEVER rewrites identifiers, structural tokens, or
7
+ * timestamps: under-redaction is safe, corrupting an ID is not. The string
8
+ * redactor uses a protect-first strategy (mask IDs with opaque placeholders
9
+ * before any transform runs, restore them byte-identical afterwards), and the
10
+ * structure-aware walker additionally protects leaf values by key name.
11
+ */
12
+ export interface RedactOptions {
13
+ salt?: string;
14
+ }
15
+ export declare function redactDemoString(text: string, opts?: RedactOptions): string;
16
+ export declare function redactDemoData<T>(value: T, opts?: RedactOptions): T;
17
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/demo/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAoYD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,CAU3E;AAuID,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,CAAC,CAGnE"}
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/demo/redact.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, dependency-free, deterministic demo-mode redactor.\n *\n * Replaces sensitive values (names, emails, free numbers) with stable fake\n * substitutes so a demo looks coherent — the same input always maps to the\n * same fake. Crucially, it NEVER rewrites identifiers, structural tokens, or\n * timestamps: under-redaction is safe, corrupting an ID is not. The string\n * redactor uses a protect-first strategy (mask IDs with opaque placeholders\n * before any transform runs, restore them byte-identical afterwards), and the\n * structure-aware walker additionally protects leaf values by key name.\n */\n\nexport interface RedactOptions {\n salt?: string;\n}\n\n/* ------------------------------------------------------------------ *\n * Seeded hash + PRNG (xmur3 seed → mulberry32 stream)\n * ------------------------------------------------------------------ */\n\nfunction xmur3(str: string): () => number {\n let h = 1779033703 ^ str.length;\n for (let i = 0; i < str.length; i++) {\n h = Math.imul(h ^ str.charCodeAt(i), 3432918353);\n h = (h << 13) | (h >>> 19);\n }\n return function () {\n h = Math.imul(h ^ (h >>> 16), 2246822507);\n h = Math.imul(h ^ (h >>> 13), 3266489909);\n h ^= h >>> 16;\n return h >>> 0;\n };\n}\n\nfunction mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return function () {\n a = (a + 0x6d2b79f5) >>> 0;\n let t = a;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/** Deterministic PRNG seeded by `value + salt`. */\nfunction seededRng(value: string, salt: string): () => number {\n const seedFn = xmur3(`${value}\u0000${salt}`);\n return mulberry32(seedFn());\n}\n\nfunction pick<T>(rng: () => number, pool: readonly T[]): T {\n return pool[Math.floor(rng() * pool.length) % pool.length];\n}\n\n/* ------------------------------------------------------------------ *\n * Curated name pools\n * ------------------------------------------------------------------ */\n\nconst FIRST_NAMES: readonly string[] = [\n \"Jane\",\n \"John\",\n \"Alex\",\n \"Maria\",\n \"Sam\",\n \"Olivia\",\n \"Liam\",\n \"Emma\",\n \"Noah\",\n \"Ava\",\n \"Lucas\",\n \"Mia\",\n \"Ethan\",\n \"Sofia\",\n \"Mason\",\n \"Isla\",\n \"Leo\",\n \"Aria\",\n \"Henry\",\n \"Zoe\",\n \"Owen\",\n \"Nora\",\n \"Caleb\",\n \"Lily\",\n \"Ryan\",\n \"Ruby\",\n \"Adam\",\n \"Chloe\",\n \"Eli\",\n \"Hazel\",\n \"Max\",\n \"Iris\",\n \"Ben\",\n \"Clara\",\n \"Theo\",\n \"Maya\",\n \"Felix\",\n \"Elena\",\n \"Jonah\",\n \"Greta\",\n];\n\nconst LAST_NAMES: readonly string[] = [\n \"Doe\",\n \"Smith\",\n \"Johnson\",\n \"Lee\",\n \"Brown\",\n \"Garcia\",\n \"Miller\",\n \"Davis\",\n \"Wilson\",\n \"Moore\",\n \"Taylor\",\n \"Anderson\",\n \"Thomas\",\n \"Jackson\",\n \"White\",\n \"Harris\",\n \"Martin\",\n \"Clark\",\n \"Lewis\",\n \"Walker\",\n \"Hall\",\n \"Young\",\n \"King\",\n \"Wright\",\n \"Hill\",\n \"Green\",\n \"Adams\",\n \"Baker\",\n \"Nelson\",\n \"Carter\",\n \"Mitchell\",\n \"Perez\",\n \"Roberts\",\n \"Turner\",\n \"Phillips\",\n \"Campbell\",\n \"Parker\",\n \"Evans\",\n \"Edwards\",\n \"Collins\",\n];\n\n/* ------------------------------------------------------------------ *\n * Fake value generators (deterministic in value + salt)\n * ------------------------------------------------------------------ */\n\nfunction fakeName(original: string, salt: string): string {\n const rng = seededRng(`name:${original}`, salt);\n const first = pick(rng, FIRST_NAMES);\n const last = pick(rng, LAST_NAMES);\n return `${first} ${last}`;\n}\n\nfunction fakeEmail(original: string, salt: string): string {\n // Derive the email from the same fake-name space so an address and the\n // person's name stay coherent within the demo.\n const rng = seededRng(`name:${original.toLowerCase()}`, salt);\n const first = pick(rng, FIRST_NAMES);\n const last = pick(rng, LAST_NAMES);\n return `${first.toLowerCase()}.${last.toLowerCase()}@example.com`;\n}\n\n/**\n * Replace every digit in `numericBody` with a freshly-generated digit while\n * preserving non-digit characters (grouping commas, decimal points) exactly.\n * The first digit is forced non-zero so the digit count is observable.\n */\nfunction fakeNumberBody(\n numericBody: string,\n original: string,\n salt: string,\n): string {\n const rng = seededRng(`num:${original}`, salt);\n let out = \"\";\n let seenDigit = false;\n for (const ch of numericBody) {\n if (ch >= \"0\" && ch <= \"9\") {\n let d: number;\n if (!seenDigit) {\n // Leading digit: 1-9 so length is preserved.\n d = 1 + Math.floor(rng() * 9);\n seenDigit = true;\n } else {\n d = Math.floor(rng() * 10);\n }\n out += String(d);\n } else {\n out += ch;\n }\n }\n return out;\n}\n\n/* ------------------------------------------------------------------ *\n * Protect-first tokenizer (ID-safety core)\n * ------------------------------------------------------------------ */\n\n/**\n * Patterns whose matches must be protected from ANY transform. Order matters:\n * the most structural / specific shapes come first so they win the scan.\n */\nconst PROTECT_PATTERNS: RegExp[] = [\n // URLs / URIs with a scheme.\n /\\b[a-zA-Z][a-zA-Z0-9+.-]*:\\/\\/[^\\s]+/g,\n /\\b(?:mailto|data|tel|urn):[^\\s]+/gi,\n // UUID.\n /\\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\\b/g,\n // JWT — three base64url segments separated by dots.\n /\\b[A-Za-z0-9_-]{4,}\\.[A-Za-z0-9_-]{4,}\\.[A-Za-z0-9_-]{4,}\\b/g,\n // ISO datetime / date.\n /\\b\\d{4}-\\d{2}-\\d{2}(?:[T ]\\d{2}:\\d{2}(?::\\d{2})?(?:\\.\\d+)?Z?)?\\b/g,\n // Bare clock time.\n /\\b\\d{1,2}:\\d{2}(?::\\d{2})?\\b/g,\n // Path-like tokens containing a slash (but not bare prose with slashes —\n // require no spaces and at least one slash with adjacent non-space).\n /(?:\\S*\\/\\S+)+/g,\n // nanoid / hex / base64-ish blobs: an unbroken [A-Za-z0-9_-] run that is\n // either long-with-a-digit, mixes letters AND digits at length >= 10, or\n // contains a `_`/`-` inside the run (real names/numbers never look so).\n /[A-Za-z0-9_-]+/g,\n];\n\nconst PLACEHOLDER_PREFIX = \"\u0001P\";\nconst PLACEHOLDER_SUFFIX = \"\u0001\";\n\nfunction makePlaceholder(index: number): string {\n return `${PLACEHOLDER_PREFIX}${index}${PLACEHOLDER_SUFFIX}`;\n}\n\n/** True if a `[A-Za-z0-9_-]+` run is identifier-shaped (must be protected). */\nfunction looksLikeIdentifierToken(tok: string): boolean {\n if (tok.length < 3) return false;\n const hasLetter = /[A-Za-z]/.test(tok);\n const hasDigit = /[0-9]/.test(tok);\n const hasSep = /[_-]/.test(tok);\n\n // A pure number (optionally with separators handled elsewhere) is NOT an\n // identifier here — the number rule handles those.\n if (!hasLetter && !hasSep) return false;\n\n // Long hex/base64-ish blob with a digit.\n if (tok.length >= 16 && hasDigit) return true;\n // nanoid-ish: length >= 10 mixing letters AND digits.\n if (tok.length >= 10 && hasLetter && hasDigit) return true;\n // Any token that has a `_`/`-` joined inside an unbroken run AND also\n // contains a digit or is long — e.g. `order-2024-abc`, `api_key_v2`.\n if (hasSep && (hasDigit || tok.length >= 10)) return true;\n // Mixed letters+digits adjacency (e.g. `abc123`, `v2`, `step3`) — protect so\n // the number rule never bites an embedded number.\n if (hasLetter && hasDigit) return true;\n\n return false;\n}\n\ninterface Protection {\n text: string;\n restore: Map<string, string>;\n}\n\n/**\n * Walk `text`, replace every protected substring with an opaque placeholder,\n * and return the masked text plus a restore map. Non-overlapping, left-to-right\n * earliest-match-wins so a transform literally cannot see a protected value.\n */\nfunction protect(text: string): Protection {\n const restore = new Map<string, string>();\n let counter = 0;\n\n // Collect all candidate matches across patterns, then resolve overlaps by\n // earliest start (and longest on tie).\n interface Span {\n start: number;\n end: number;\n value: string;\n }\n const spans: Span[] = [];\n\n for (let p = 0; p < PROTECT_PATTERNS.length; p++) {\n const re = new RegExp(\n PROTECT_PATTERNS[p].source,\n PROTECT_PATTERNS[p].flags,\n );\n let m: RegExpExecArray | null;\n while ((m = re.exec(text)) !== null) {\n const value = m[0];\n if (value.length === 0) {\n re.lastIndex++;\n continue;\n }\n const isTokenPattern = p === PROTECT_PATTERNS.length - 1;\n if (isTokenPattern && !looksLikeIdentifierToken(value)) {\n continue;\n }\n spans.push({ start: m.index, end: m.index + value.length, value });\n }\n }\n\n if (spans.length === 0) return { text, restore };\n\n spans.sort((a, b) =>\n a.start !== b.start ? a.start - b.start : b.end - a.end,\n );\n\n let out = \"\";\n let cursor = 0;\n for (const span of spans) {\n if (span.start < cursor) continue; // overlapped by an earlier protection\n out += text.slice(cursor, span.start);\n const ph = makePlaceholder(counter++);\n restore.set(ph, span.value);\n out += ph;\n cursor = span.end;\n }\n out += text.slice(cursor);\n\n return { text: out, restore };\n}\n\nfunction unprotect(text: string, restore: Map<string, string>): string {\n if (restore.size === 0) return text;\n let out = text;\n for (const [ph, original] of restore) {\n out = out.split(ph).join(original);\n }\n return out;\n}\n\n/* ------------------------------------------------------------------ *\n * Transforms (run only on protected text)\n * ------------------------------------------------------------------ */\n\nconst EMAIL_RE = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g;\n\n// 2+ capitalized words (each starts uppercase, allows internal lowercase /\n// apostrophes / hyphens). Single-letter middle initials allowed: `Sarah J Connor`.\nconst FULL_NAME_RE = /\\b[A-Z][a-zA-Z'’-]*(?:\\s+[A-Z](?:[a-zA-Z'’-]*)?){1,3}\\b/g;\n\n// A standalone numeric token: optional currency + sign, digits with optional\n// comma grouping and a single optional decimal part. Bounded so it is NOT\n// adjacent to a letter (placeholders already removed letter-mixed tokens, but\n// this keeps the rule self-contained and safe on raw structured values too).\nconst NUMBER_RE =\n /(^|[^A-Za-z0-9_])([$€£]?)([+-]?)(\\d[\\d,]*(?:\\.\\d+)?)(?![A-Za-z0-9_])/g;\n\nfunction transformEmails(text: string, salt: string): string {\n return text.replace(EMAIL_RE, (match) => fakeEmail(match, salt));\n}\n\nfunction transformNames(text: string, salt: string): string {\n return text.replace(FULL_NAME_RE, (match) => {\n // Keep trailing/leading whitespace handling implicit; `match` is the run.\n return fakeName(match, salt);\n });\n}\n\nfunction isProbablyYear(digits: string): boolean {\n if (digits.length !== 4) return false;\n const n = Number(digits);\n return n >= 1900 && n <= 2099;\n}\n\nfunction transformNumbers(text: string, salt: string): string {\n return text.replace(\n NUMBER_RE,\n (_full, pre: string, currency: string, sign: string, body: string) => {\n const hasGrouping = body.includes(\",\");\n const hasDecimal = body.includes(\".\");\n const digitsOnly = body.replace(/[^0-9]/g, \"\");\n\n // Skip bare years like 2026.\n if (\n !currency &&\n !sign &&\n !hasGrouping &&\n !hasDecimal &&\n isProbablyYear(digitsOnly)\n ) {\n return `${pre}${currency}${sign}${body}`;\n }\n\n // Skip standalone integers < 1000 with no currency and no grouping\n // (rewriting \"3 unread\" / \"page 2\" looks broken and isn't sensitive).\n if (!currency && !hasGrouping && !hasDecimal) {\n const n = Number(digitsOnly);\n if (Number.isFinite(n) && n < 1000) {\n return `${pre}${currency}${sign}${body}`;\n }\n }\n\n const fakeBody = fakeNumberBody(body, `${currency}${sign}${body}`, salt);\n return `${pre}${currency}${sign}${fakeBody}`;\n },\n );\n}\n\n/* ------------------------------------------------------------------ *\n * Public: string redactor\n * ------------------------------------------------------------------ */\n\nexport function redactDemoString(text: string, opts?: RedactOptions): string {\n if (typeof text !== \"string\" || text.length === 0) return text;\n const salt = opts?.salt ?? \"\";\n\n const { text: masked, restore } = protect(text);\n let out = masked;\n out = transformEmails(out, salt);\n out = transformNames(out, salt);\n out = transformNumbers(out, salt);\n return unprotect(out, restore);\n}\n\n/* ------------------------------------------------------------------ *\n * Public: structure-aware redactor\n * ------------------------------------------------------------------ */\n\n// Keys whose leaf values must NEVER be transformed (still recurse into nested\n// objects/arrays under them).\nconst PROTECTED_KEY_RE =\n /^id$|(^|_)id$|Id$|Ids$|uuid|guid|slug|token|secret|password|passwd|apikey|api_key|hash|sha\\d*|etag|cursor|nonce|sessionid|messageid|threadid|nodeid|(^|_)key$|keyid|(^|_)ref$|url$|uri$|href$|src$|path$|filename$|mimetype|mime|createdat|updatedat|deletedat|expiresat|timestamp|.+at$|.+_at$/i;\n\n// Keys whose (short) leaf string should be treated as a full name even when it\n// is a single token.\nconst NAME_KEY_RE =\n /name|from$|to$|sender|recipient|author|fullName|displayName|firstName|lastName|contact/i;\n\nconst MAX_DEPTH = 64;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n if (Array.isArray(value)) return false;\n if (value instanceof Date) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction redactNameLeaf(value: string, salt: string): string {\n if (value.length === 0 || value.length > 40) {\n // Too long to be a bare name — fall back to prose redaction.\n return redactDemoStringWithSalt(value, salt);\n }\n // If it already contains an email, redact that path instead.\n if (EMAIL_RE.test(value)) {\n EMAIL_RE.lastIndex = 0;\n return redactDemoStringWithSalt(value, salt);\n }\n EMAIL_RE.lastIndex = 0;\n\n const { text: masked, restore } = protect(value);\n // If protection consumed the whole value, it was identifier-shaped — leave.\n if (masked.trim().length === 0 || restore.size > 0) {\n // Be conservative: if any part looked like an ID, prefer prose redaction\n // (which preserves the protected bits) over forcing a name.\n return redactDemoStringWithSalt(value, salt);\n }\n return fakeName(value, salt);\n}\n\nfunction redactDemoStringWithSalt(text: string, salt: string): string {\n return redactDemoString(text, { salt });\n}\n\nfunction redactNumberLeaf(value: number, salt: string): number {\n if (!Number.isFinite(value)) return value;\n const repr = String(value);\n // Re-use the string number transform but only if the representation is a\n // clean numeric token we can round-trip back to a JS number.\n const redacted = transformNumbers(repr, salt);\n if (redacted === repr) return value;\n const n = Number(redacted);\n if (!Number.isFinite(n)) return value;\n return n;\n}\n\nfunction walk(\n value: unknown,\n salt: string,\n depth: number,\n seen: WeakSet<object>,\n underNameKey: boolean,\n): unknown {\n if (depth > MAX_DEPTH) return value;\n\n if (value === null || value === undefined) return value;\n\n const t = typeof value;\n\n if (t === \"string\") {\n const str = value as string;\n if (underNameKey) return redactNameLeaf(str, salt);\n return redactDemoStringWithSalt(str, salt);\n }\n\n if (t === \"number\") {\n return redactNumberLeaf(value as number, salt);\n }\n\n if (t === \"boolean\" || t === \"bigint\" || t === \"function\" || t === \"symbol\") {\n return value;\n }\n\n if (value instanceof Date) return value;\n\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const out = value.map((item) =>\n walk(item, salt, depth + 1, seen, underNameKey),\n );\n seen.delete(value);\n return out;\n }\n\n if (isPlainObject(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n const keyIsProtected = PROTECTED_KEY_RE.test(key);\n if (keyIsProtected) {\n if (\n entry !== null &&\n typeof entry === \"object\" &&\n !(entry instanceof Date)\n ) {\n // Still recurse into nested structures, but the protected key does\n // not propagate name/transform semantics.\n out[key] = walk(entry, salt, depth + 1, seen, false);\n } else {\n // Leaf under a protected key: pass through completely untouched.\n out[key] = entry;\n }\n continue;\n }\n const keyIsName = NAME_KEY_RE.test(key);\n out[key] = walk(entry, salt, depth + 1, seen, keyIsName);\n }\n seen.delete(value);\n return out;\n }\n\n // Unknown object kind (Map, Set, class instance, etc.) — leave untouched.\n return value;\n}\n\nexport function redactDemoData<T>(value: T, opts?: RedactOptions): T {\n const salt = opts?.salt ?? \"\";\n return walk(value, salt, 0, new WeakSet<object>(), false) as T;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"action-discovery.d.ts","sourceRoot":"","sources":["../../src/server/action-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAqChE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACnC,IAAI,CAKN;AAyND;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAqC7B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAgGtC;AAED,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED,oDAAoD;AACpD,eAAO,MAAM,mBAAmB,4BAAsB,CAAC"}
1
+ {"version":3,"file":"action-discovery.d.ts","sourceRoot":"","sources":["../../src/server/action-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAqChE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACnC,IAAI,CAKN;AAyND;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAqC7B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAgGtC;AAED,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAwCf;AAED,oDAAoD;AACpD,eAAO,MAAM,mBAAmB,4BAAsB,CAAC"}
@@ -424,6 +424,7 @@ export async function mergeCoreSharingActions(registry) {
424
424
  "change-appearance",
425
425
  () => import("../appearance/actions/change-appearance.js"),
426
426
  ],
427
+ ["toggle-demo-mode", () => import("../demo/actions/toggle-demo-mode.js")],
427
428
  ];
428
429
  for (const [name, loader] of entries) {
429
430
  if (registry[name])
@@ -1 +1 @@
1
- {"version":3,"file":"action-discovery.js","sourceRoot":"","sources":["../../src/server/action-discovery.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Auto-discover actions from a template's actions/ directory.\n *\n * Scans for .ts/.js files and builds an action registry suitable for\n * `createAgentChatPlugin({ actions })`.\n *\n * Supports two action conventions:\n *\n * 1. **Full interface** — exports `tool: ActionTool` and `run(args): Promise<string>`.\n * These are used directly.\n *\n * 2. **CLI-style** — exports only `default async function(args: string[])`.\n * These are wrapped: args are converted from `Record<string, string>` to\n * `[\"--key\", \"value\", ...]`, console output is captured, and a tool\n * definition is synthesized from the action name.\n *\n * 3. **defineAction** — exports `default` from `defineAction()`. Has `tool` and `run`.\n *\n * Usage in agent-chat plugins:\n * ```ts\n * import { autoDiscoverActions } from \"@agent-native/core/server\";\n *\n * export default createAgentChatPlugin({\n * actions: () => autoDiscoverActions(import.meta.url),\n * });\n * ```\n */\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport type { ActionTool } from \"../agent/types.js\";\nimport nodePath from \"node:path\";\nimport { captureCliOutput } from \"./cli-capture.js\";\n\n// Lazy fs — loaded via dynamic import() on first use.\n// Avoids require() which bundlers convert to createRequire() that crashes on CF Workers.\nlet _fs: typeof import(\"fs\") | undefined;\nasync function getFs(): Promise<typeof import(\"fs\")> {\n if (!_fs) {\n _fs = await import(\"node:fs\");\n }\n return _fs;\n}\nimport { fileURLToPath } from \"node:url\";\n\n/** Files to skip during auto-discovery (no extension). */\nconst SKIP_FILES = new Set([\n \"helpers\",\n \"run\",\n \"db-connect\",\n \"db-status\",\n \"registry\",\n]);\n\n/**\n * Global registry of actions contributed by published packages\n * (e.g. `@agent-native/dispatch`). Populated by `registerPackageActions()`\n * which the package calls from import side effects, then merged into\n * `autoDiscoverActions` after the template's local `actions/` directory.\n *\n * Ordering: template `actions/` files always win on name collision so\n * consumers can override a packaged action by dropping a same-named file\n * in their own `actions/` dir.\n */\nconst packageActionRegistry: Record<string, ActionEntry> = {};\n\n/**\n * Register a map of actions contributed by a published package.\n *\n * Called from a package's server entrypoint via import side effects:\n * ```ts\n * // packages/dispatch/src/server/index.ts\n * import { registerPackageActions } from \"@agent-native/core/server\";\n * import { actions } from \"../actions/index.js\";\n * registerPackageActions(actions);\n * ```\n *\n * Idempotent — re-registering the same name from the same import is a no-op\n * so HMR / repeated dynamic imports don't double-warn.\n */\nexport function registerPackageActions(\n actions: Record<string, ActionEntry>,\n): void {\n for (const [name, entry] of Object.entries(actions)) {\n if (packageActionRegistry[name]) continue;\n packageActionRegistry[name] = entry;\n }\n}\n\n/** Internal — used by `autoDiscoverActions`. Returns a shallow copy. */\nfunction getPackageActions(): Record<string, ActionEntry> {\n return { ...packageActionRegistry };\n}\n\n/**\n * Split a string into shell-like tokens, handling double and single quotes.\n * `--title \"My Page\" --content \"\"` → `[\"--title\", \"My Page\", \"--content\", \"\"]`\n */\nfunction splitShellArgs(input: string): string[] {\n const tokens: string[] = [];\n let current = \"\";\n let inDouble = false;\n let inSingle = false;\n let wasQuoted = false;\n\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '\"' && !inSingle) {\n inDouble = !inDouble;\n wasQuoted = true;\n continue;\n }\n if (ch === \"'\" && !inDouble) {\n inSingle = !inSingle;\n wasQuoted = true;\n continue;\n }\n if ((ch === \" \" || ch === \"\\t\") && !inDouble && !inSingle) {\n if (current.length > 0 || wasQuoted) {\n tokens.push(current);\n }\n current = \"\";\n wasQuoted = false;\n continue;\n }\n current += ch;\n }\n if (current.length > 0 || wasQuoted) {\n tokens.push(current);\n }\n return tokens;\n}\n\n/**\n * Wrap a CLI-style action (that writes to console.log) as an ActionEntry\n * by capturing stdout/stderr and intercepting process.exit. Uses the\n * shared AsyncLocalStorage-backed capture so concurrent invocations do\n * not corrupt the global `console.log` / `process.stdout.write` /\n * `process.exit` pointers (see `cli-capture.ts`).\n */\nfunction wrapDefaultExport(\n name: string,\n defaultFn: (args: string[]) => Promise<void>,\n): ActionEntry {\n const tool: ActionTool = {\n description: `Run the \"${name}\" action. Pass arguments as key-value pairs.`,\n parameters: {\n type: \"object\",\n properties: {\n args: {\n type: \"string\",\n description:\n \"Space-separated CLI arguments (e.g. '--id abc --title Hello')\",\n },\n },\n },\n };\n\n return {\n tool,\n run: async (args: Record<string, string>): Promise<string> => {\n const cliArgs: string[] = [];\n // If only an \"args\" key was provided, split it into CLI tokens\n if (args.args && Object.keys(args).length === 1) {\n cliArgs.push(...splitShellArgs(args.args));\n } else {\n for (const [k, v] of Object.entries(args)) {\n cliArgs.push(`--${k}`, v);\n }\n }\n return captureCliOutput(() => defaultFn(cliArgs));\n },\n };\n}\n\nfunction preserveActionFlags(entry: Record<string, any>): Partial<ActionEntry> {\n const out: Partial<ActionEntry> = {};\n if (typeof entry.readOnly === \"boolean\") out.readOnly = entry.readOnly;\n if (typeof entry.parallelSafe === \"boolean\") {\n out.parallelSafe = entry.parallelSafe;\n }\n if (typeof entry.toolCallable === \"boolean\") {\n out.toolCallable = entry.toolCallable;\n }\n if (\n entry.publicAgent &&\n typeof entry.publicAgent === \"object\" &&\n !Array.isArray(entry.publicAgent)\n ) {\n out.publicAgent = entry.publicAgent;\n }\n return out;\n}\n\n/**\n * Resolve the actions directory from the caller's context.\n *\n * @param from - Either an `import.meta.url` (file:// URL from a plugin file),\n * an absolute directory path, or \"auto\" to use `process.cwd() + \"/actions\"`.\n * When an import.meta.url is provided, the actions directory is resolved as\n * `../../actions/` relative to the caller (typically `server/plugins/agent-chat.ts`).\n * If the resolved directory doesn't exist, falls back to `../../scripts/` for\n * backwards compatibility, then to `process.cwd() + \"/actions\"`.\n */\nasync function resolveActionsDir(from: string): Promise<string> {\n const fs = await getFs();\n const exists = (p: string) => {\n try {\n return fs.existsSync(p);\n } catch {\n return false;\n }\n };\n // On edge runtimes (e.g. Cloudflare Workers), import.meta.url may be\n // undefined after bundling. Fall back to cwd-based discovery.\n if (!from) {\n const cwdActions = nodePath.join(process.cwd(), \"actions\");\n if (exists(cwdActions)) return cwdActions;\n return nodePath.join(process.cwd(), \"scripts\");\n }\n if (from.startsWith(\"file://\") || from.startsWith(\"file:///\")) {\n const callerPath = fileURLToPath(from);\n const callerDir = nodePath.dirname(callerPath);\n const actionsResolved = nodePath.resolve(callerDir, \"../../actions\");\n if (exists(actionsResolved)) return actionsResolved;\n const scriptsResolved = nodePath.resolve(callerDir, \"../../scripts\");\n if (exists(scriptsResolved)) return scriptsResolved;\n const cwdActions = nodePath.join(process.cwd(), \"actions\");\n if (exists(cwdActions)) return cwdActions;\n return nodePath.join(process.cwd(), \"scripts\");\n }\n if (from === \"auto\") {\n const cwdActions = nodePath.join(process.cwd(), \"actions\");\n if (exists(cwdActions)) return cwdActions;\n return nodePath.join(process.cwd(), \"scripts\");\n }\n return nodePath.resolve(from);\n}\n\n/**\n * Load actions from a single directory into the given registry. Shared by\n * both the template-actions discovery path and the workspace-core actions\n * layer. When `skipExisting` is true, an entry with the same name that's\n * already in the registry is left untouched (template-wins on collision).\n */\nasync function loadActionsIntoRegistry(\n actionsDir: string,\n registry: Record<string, ActionEntry>,\n skipExisting: boolean,\n): Promise<void> {\n let files: string[];\n try {\n const fs = await getFs();\n if (!fs.existsSync(actionsDir)) return;\n files = fs.readdirSync(actionsDir);\n } catch {\n return;\n }\n\n const actionFiles = files.filter((f) => {\n if (!f.endsWith(\".ts\") && !f.endsWith(\".js\")) return false;\n const name = f.replace(/\\.(ts|js)$/, \"\");\n if (name.startsWith(\"_\")) return false;\n if (SKIP_FILES.has(name)) return false;\n return true;\n });\n\n for (const file of actionFiles) {\n const name = file.replace(/\\.(ts|js)$/, \"\");\n if (skipExisting && registry[name]) continue;\n\n const filePath = nodePath.join(actionsDir, file);\n try {\n const mod = await import(/* @vite-ignore */ filePath);\n\n if (mod.tool && typeof mod.run === \"function\") {\n registry[name] = {\n tool: mod.tool,\n run: mod.run,\n ...(mod.http !== undefined ? { http: mod.http } : {}),\n ...preserveActionFlags(mod),\n };\n } else if (\n mod.default &&\n typeof mod.default === \"object\" &&\n mod.default.tool &&\n typeof mod.default.run === \"function\"\n ) {\n registry[name] = {\n tool: mod.default.tool,\n run: mod.default.run,\n ...(mod.default.http !== undefined ? { http: mod.default.http } : {}),\n ...preserveActionFlags(mod.default),\n };\n } else if (typeof mod.default === \"function\") {\n registry[name] = wrapDefaultExport(name, mod.default);\n }\n } catch {\n // CLI-style scripts (top-level execution) throw on import.\n // Expected — they're available via `pnpm action <name>` / shell instead.\n }\n }\n}\n\n/**\n * Normalize a pre-bundled static action registry (name → raw module) into\n * the `Record<string, ActionEntry>` shape the agent-chat plugin expects.\n *\n * Used by `autoDiscoverActions` when `.generated/actions-registry.ts` is\n * present so that Nitro-bundled serverless functions (Netlify, Vercel,\n * AWS-Lambda) can serve `/_agent-native/actions/*` routes without relying\n * on a filesystem scan that doesn't work in bundled output.\n */\nexport function loadActionsFromStaticRegistry(\n modules: Record<string, unknown>,\n): Record<string, ActionEntry> {\n const registry: Record<string, ActionEntry> = {};\n for (const [name, raw] of Object.entries(modules)) {\n const mod = raw as Record<string, any> | null | undefined;\n if (!mod) continue;\n\n if (mod.tool && typeof mod.run === \"function\") {\n registry[name] = {\n tool: mod.tool,\n run: mod.run,\n ...(mod.http !== undefined ? { http: mod.http } : {}),\n ...preserveActionFlags(mod),\n };\n continue;\n }\n\n const def = mod.default;\n if (\n def &&\n typeof def === \"object\" &&\n def.tool &&\n typeof def.run === \"function\"\n ) {\n registry[name] = {\n tool: def.tool,\n run: def.run,\n ...(def.http !== undefined ? { http: def.http } : {}),\n ...preserveActionFlags(def),\n };\n continue;\n }\n\n if (typeof def === \"function\") {\n registry[name] = wrapDefaultExport(name, def);\n }\n }\n return registry;\n}\n\n/**\n * Auto-discover actions from a directory.\n *\n * Merges in any actions from the enterprise workspace core (if present in\n * the ancestor chain). Template actions take precedence over workspace-core\n * actions on name collision, so an app can override an enterprise-wide\n * action by dropping a same-named file under its own `actions/`.\n *\n * Note: this helper uses a filesystem scan, which works in dev and in\n * non-bundled Node deployments. In bundled serverless functions (Nitro's\n * netlify / vercel / aws-lambda presets) the `actions/` directory is not\n * on disk at runtime; templates should pass the static registry generated\n * by the Vite plugin to `createAgentChatPlugin({ actions })` instead, so\n * the bundler sees static imports and pulls every action into the bundle.\n *\n * @param from - The caller's `import.meta.url` or an absolute path to the\n * actions directory.\n * @returns A record mapping action names to ActionEntry objects, suitable for\n * passing to `createAgentChatPlugin({ actions })`.\n */\nexport async function autoDiscoverActions(\n from: string,\n): Promise<Record<string, ActionEntry>> {\n const actionsDir = await resolveActionsDir(from);\n const registry: Record<string, ActionEntry> = {};\n\n // 1. Template actions first — these are the authoritative layer for the\n // current app and must override any workspace-core entry with the same\n // name.\n try {\n await loadActionsIntoRegistry(actionsDir, registry, false);\n } catch (err: any) {\n console.warn(\n `[autoDiscoverActions] Could not read actions directory: ${actionsDir} — ${err?.message}`,\n );\n }\n\n // 1b. Fallback: if filesystem discovery found no template actions (common\n // in bundled serverless environments like Netlify/Vercel where the\n // actions/ directory doesn't exist on disk), try importing the\n // generated static registry at .generated/actions-registry.\n //\n // This prevents the silent-empty-tools footgun where the agent has no\n // template actions and falls back to generic tools like web-request.\n // Prefer `loadActionsFromStaticRegistry` over `autoDiscoverActions` for\n // production reliability — this fallback is a safety net, not the\n // primary path.\n if (Object.keys(registry).length === 0 && from) {\n try {\n let registryPath: string;\n if (from.startsWith(\"file://\") || from.startsWith(\"file:///\")) {\n const callerDir = nodePath.dirname(fileURLToPath(from));\n registryPath = nodePath.resolve(\n callerDir,\n \"../../.generated/actions-registry.js\",\n );\n } else {\n registryPath = nodePath.resolve(\n from,\n \"../.generated/actions-registry.js\",\n );\n }\n const mod = await import(/* @vite-ignore */ registryPath);\n const staticEntries = loadActionsFromStaticRegistry(mod.default || mod);\n Object.assign(registry, staticEntries);\n if (Object.keys(staticEntries).length > 0) {\n console.log(\n `[autoDiscoverActions] Filesystem scan found 0 actions — loaded ${Object.keys(staticEntries).length} from .generated/actions-registry.ts instead. ` +\n `Consider switching to loadActionsFromStaticRegistry(actionsRegistry) for production reliability.`,\n );\n }\n } catch {\n // No generated registry available — registry stays empty.\n }\n }\n\n // If still empty after all fallbacks, warn loudly.\n if (Object.keys(registry).length === 0) {\n console.warn(\n `[autoDiscoverActions] WARNING: No template actions found! ` +\n `The agent will have no template-specific tools. ` +\n `If in production, switch from autoDiscoverActions to loadActionsFromStaticRegistry. ` +\n `See: https://docs.agent-native.com/actions#static-registry`,\n );\n }\n\n // 1c. Package-registered actions — contributed by published packages\n // (e.g. @agent-native/dispatch) via `registerPackageActions()` from\n // import side effects. Merged with skip-existing so the template's\n // own actions/ files always win on name collision.\n for (const [name, entry] of Object.entries(getPackageActions())) {\n if (registry[name]) continue;\n registry[name] = entry;\n }\n\n // 2. Workspace-core actions — merged in with skipExisting so they can't\n // overwrite template entries.\n try {\n const { getWorkspaceCoreExports } =\n await import(\"../deploy/workspace-core.js\");\n const ws = await getWorkspaceCoreExports(process.cwd());\n if (ws && ws.actionsDir) {\n await loadActionsIntoRegistry(ws.actionsDir, registry, true);\n }\n } catch {\n // workspace-core discovery unavailable (e.g. edge runtime) — skip.\n }\n\n // 3. Framework-level sharing + file-upload actions — always available to any\n // template. Merged with skipExisting so templates can override by\n // providing a same-named file.\n try {\n await mergeCoreSharingActions(registry);\n } catch {\n // Ignore — templates without sharing still work.\n }\n\n return registry;\n}\n\nexport async function mergeCoreSharingActions(\n registry: Record<string, ActionEntry>,\n): Promise<void> {\n const entries: Array<[string, () => Promise<any>]> = [\n [\"share-resource\", () => import(\"../sharing/actions/share-resource.js\")],\n [\n \"unshare-resource\",\n () => import(\"../sharing/actions/unshare-resource.js\"),\n ],\n [\n \"list-resource-shares\",\n () => import(\"../sharing/actions/list-resource-shares.js\"),\n ],\n [\n \"set-resource-visibility\",\n () => import(\"../sharing/actions/set-resource-visibility.js\"),\n ],\n [\"upload-image\", () => import(\"../file-upload/actions/upload-image.js\")],\n [\n \"change-appearance\",\n () => import(\"../appearance/actions/change-appearance.js\"),\n ],\n ];\n for (const [name, loader] of entries) {\n if (registry[name]) continue;\n try {\n const mod = await loader();\n const def = mod.default;\n if (def && def.tool && typeof def.run === \"function\") {\n registry[name] = {\n tool: def.tool,\n run: def.run,\n ...(def.http !== undefined ? { http: def.http } : {}),\n ...(def.readOnly === true ? { readOnly: true } : {}),\n ...(def.parallelSafe === true ? { parallelSafe: true } : {}),\n };\n }\n } catch {\n // Skip any sharing action that fails to import.\n }\n }\n}\n\n/** @deprecated Use `autoDiscoverActions` instead */\nexport const autoDiscoverScripts = autoDiscoverActions;\n"]}
1
+ {"version":3,"file":"action-discovery.js","sourceRoot":"","sources":["../../src/server/action-discovery.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Auto-discover actions from a template's actions/ directory.\n *\n * Scans for .ts/.js files and builds an action registry suitable for\n * `createAgentChatPlugin({ actions })`.\n *\n * Supports two action conventions:\n *\n * 1. **Full interface** — exports `tool: ActionTool` and `run(args): Promise<string>`.\n * These are used directly.\n *\n * 2. **CLI-style** — exports only `default async function(args: string[])`.\n * These are wrapped: args are converted from `Record<string, string>` to\n * `[\"--key\", \"value\", ...]`, console output is captured, and a tool\n * definition is synthesized from the action name.\n *\n * 3. **defineAction** — exports `default` from `defineAction()`. Has `tool` and `run`.\n *\n * Usage in agent-chat plugins:\n * ```ts\n * import { autoDiscoverActions } from \"@agent-native/core/server\";\n *\n * export default createAgentChatPlugin({\n * actions: () => autoDiscoverActions(import.meta.url),\n * });\n * ```\n */\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport type { ActionTool } from \"../agent/types.js\";\nimport nodePath from \"node:path\";\nimport { captureCliOutput } from \"./cli-capture.js\";\n\n// Lazy fs — loaded via dynamic import() on first use.\n// Avoids require() which bundlers convert to createRequire() that crashes on CF Workers.\nlet _fs: typeof import(\"fs\") | undefined;\nasync function getFs(): Promise<typeof import(\"fs\")> {\n if (!_fs) {\n _fs = await import(\"node:fs\");\n }\n return _fs;\n}\nimport { fileURLToPath } from \"node:url\";\n\n/** Files to skip during auto-discovery (no extension). */\nconst SKIP_FILES = new Set([\n \"helpers\",\n \"run\",\n \"db-connect\",\n \"db-status\",\n \"registry\",\n]);\n\n/**\n * Global registry of actions contributed by published packages\n * (e.g. `@agent-native/dispatch`). Populated by `registerPackageActions()`\n * which the package calls from import side effects, then merged into\n * `autoDiscoverActions` after the template's local `actions/` directory.\n *\n * Ordering: template `actions/` files always win on name collision so\n * consumers can override a packaged action by dropping a same-named file\n * in their own `actions/` dir.\n */\nconst packageActionRegistry: Record<string, ActionEntry> = {};\n\n/**\n * Register a map of actions contributed by a published package.\n *\n * Called from a package's server entrypoint via import side effects:\n * ```ts\n * // packages/dispatch/src/server/index.ts\n * import { registerPackageActions } from \"@agent-native/core/server\";\n * import { actions } from \"../actions/index.js\";\n * registerPackageActions(actions);\n * ```\n *\n * Idempotent — re-registering the same name from the same import is a no-op\n * so HMR / repeated dynamic imports don't double-warn.\n */\nexport function registerPackageActions(\n actions: Record<string, ActionEntry>,\n): void {\n for (const [name, entry] of Object.entries(actions)) {\n if (packageActionRegistry[name]) continue;\n packageActionRegistry[name] = entry;\n }\n}\n\n/** Internal — used by `autoDiscoverActions`. Returns a shallow copy. */\nfunction getPackageActions(): Record<string, ActionEntry> {\n return { ...packageActionRegistry };\n}\n\n/**\n * Split a string into shell-like tokens, handling double and single quotes.\n * `--title \"My Page\" --content \"\"` → `[\"--title\", \"My Page\", \"--content\", \"\"]`\n */\nfunction splitShellArgs(input: string): string[] {\n const tokens: string[] = [];\n let current = \"\";\n let inDouble = false;\n let inSingle = false;\n let wasQuoted = false;\n\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '\"' && !inSingle) {\n inDouble = !inDouble;\n wasQuoted = true;\n continue;\n }\n if (ch === \"'\" && !inDouble) {\n inSingle = !inSingle;\n wasQuoted = true;\n continue;\n }\n if ((ch === \" \" || ch === \"\\t\") && !inDouble && !inSingle) {\n if (current.length > 0 || wasQuoted) {\n tokens.push(current);\n }\n current = \"\";\n wasQuoted = false;\n continue;\n }\n current += ch;\n }\n if (current.length > 0 || wasQuoted) {\n tokens.push(current);\n }\n return tokens;\n}\n\n/**\n * Wrap a CLI-style action (that writes to console.log) as an ActionEntry\n * by capturing stdout/stderr and intercepting process.exit. Uses the\n * shared AsyncLocalStorage-backed capture so concurrent invocations do\n * not corrupt the global `console.log` / `process.stdout.write` /\n * `process.exit` pointers (see `cli-capture.ts`).\n */\nfunction wrapDefaultExport(\n name: string,\n defaultFn: (args: string[]) => Promise<void>,\n): ActionEntry {\n const tool: ActionTool = {\n description: `Run the \"${name}\" action. Pass arguments as key-value pairs.`,\n parameters: {\n type: \"object\",\n properties: {\n args: {\n type: \"string\",\n description:\n \"Space-separated CLI arguments (e.g. '--id abc --title Hello')\",\n },\n },\n },\n };\n\n return {\n tool,\n run: async (args: Record<string, string>): Promise<string> => {\n const cliArgs: string[] = [];\n // If only an \"args\" key was provided, split it into CLI tokens\n if (args.args && Object.keys(args).length === 1) {\n cliArgs.push(...splitShellArgs(args.args));\n } else {\n for (const [k, v] of Object.entries(args)) {\n cliArgs.push(`--${k}`, v);\n }\n }\n return captureCliOutput(() => defaultFn(cliArgs));\n },\n };\n}\n\nfunction preserveActionFlags(entry: Record<string, any>): Partial<ActionEntry> {\n const out: Partial<ActionEntry> = {};\n if (typeof entry.readOnly === \"boolean\") out.readOnly = entry.readOnly;\n if (typeof entry.parallelSafe === \"boolean\") {\n out.parallelSafe = entry.parallelSafe;\n }\n if (typeof entry.toolCallable === \"boolean\") {\n out.toolCallable = entry.toolCallable;\n }\n if (\n entry.publicAgent &&\n typeof entry.publicAgent === \"object\" &&\n !Array.isArray(entry.publicAgent)\n ) {\n out.publicAgent = entry.publicAgent;\n }\n return out;\n}\n\n/**\n * Resolve the actions directory from the caller's context.\n *\n * @param from - Either an `import.meta.url` (file:// URL from a plugin file),\n * an absolute directory path, or \"auto\" to use `process.cwd() + \"/actions\"`.\n * When an import.meta.url is provided, the actions directory is resolved as\n * `../../actions/` relative to the caller (typically `server/plugins/agent-chat.ts`).\n * If the resolved directory doesn't exist, falls back to `../../scripts/` for\n * backwards compatibility, then to `process.cwd() + \"/actions\"`.\n */\nasync function resolveActionsDir(from: string): Promise<string> {\n const fs = await getFs();\n const exists = (p: string) => {\n try {\n return fs.existsSync(p);\n } catch {\n return false;\n }\n };\n // On edge runtimes (e.g. Cloudflare Workers), import.meta.url may be\n // undefined after bundling. Fall back to cwd-based discovery.\n if (!from) {\n const cwdActions = nodePath.join(process.cwd(), \"actions\");\n if (exists(cwdActions)) return cwdActions;\n return nodePath.join(process.cwd(), \"scripts\");\n }\n if (from.startsWith(\"file://\") || from.startsWith(\"file:///\")) {\n const callerPath = fileURLToPath(from);\n const callerDir = nodePath.dirname(callerPath);\n const actionsResolved = nodePath.resolve(callerDir, \"../../actions\");\n if (exists(actionsResolved)) return actionsResolved;\n const scriptsResolved = nodePath.resolve(callerDir, \"../../scripts\");\n if (exists(scriptsResolved)) return scriptsResolved;\n const cwdActions = nodePath.join(process.cwd(), \"actions\");\n if (exists(cwdActions)) return cwdActions;\n return nodePath.join(process.cwd(), \"scripts\");\n }\n if (from === \"auto\") {\n const cwdActions = nodePath.join(process.cwd(), \"actions\");\n if (exists(cwdActions)) return cwdActions;\n return nodePath.join(process.cwd(), \"scripts\");\n }\n return nodePath.resolve(from);\n}\n\n/**\n * Load actions from a single directory into the given registry. Shared by\n * both the template-actions discovery path and the workspace-core actions\n * layer. When `skipExisting` is true, an entry with the same name that's\n * already in the registry is left untouched (template-wins on collision).\n */\nasync function loadActionsIntoRegistry(\n actionsDir: string,\n registry: Record<string, ActionEntry>,\n skipExisting: boolean,\n): Promise<void> {\n let files: string[];\n try {\n const fs = await getFs();\n if (!fs.existsSync(actionsDir)) return;\n files = fs.readdirSync(actionsDir);\n } catch {\n return;\n }\n\n const actionFiles = files.filter((f) => {\n if (!f.endsWith(\".ts\") && !f.endsWith(\".js\")) return false;\n const name = f.replace(/\\.(ts|js)$/, \"\");\n if (name.startsWith(\"_\")) return false;\n if (SKIP_FILES.has(name)) return false;\n return true;\n });\n\n for (const file of actionFiles) {\n const name = file.replace(/\\.(ts|js)$/, \"\");\n if (skipExisting && registry[name]) continue;\n\n const filePath = nodePath.join(actionsDir, file);\n try {\n const mod = await import(/* @vite-ignore */ filePath);\n\n if (mod.tool && typeof mod.run === \"function\") {\n registry[name] = {\n tool: mod.tool,\n run: mod.run,\n ...(mod.http !== undefined ? { http: mod.http } : {}),\n ...preserveActionFlags(mod),\n };\n } else if (\n mod.default &&\n typeof mod.default === \"object\" &&\n mod.default.tool &&\n typeof mod.default.run === \"function\"\n ) {\n registry[name] = {\n tool: mod.default.tool,\n run: mod.default.run,\n ...(mod.default.http !== undefined ? { http: mod.default.http } : {}),\n ...preserveActionFlags(mod.default),\n };\n } else if (typeof mod.default === \"function\") {\n registry[name] = wrapDefaultExport(name, mod.default);\n }\n } catch {\n // CLI-style scripts (top-level execution) throw on import.\n // Expected — they're available via `pnpm action <name>` / shell instead.\n }\n }\n}\n\n/**\n * Normalize a pre-bundled static action registry (name → raw module) into\n * the `Record<string, ActionEntry>` shape the agent-chat plugin expects.\n *\n * Used by `autoDiscoverActions` when `.generated/actions-registry.ts` is\n * present so that Nitro-bundled serverless functions (Netlify, Vercel,\n * AWS-Lambda) can serve `/_agent-native/actions/*` routes without relying\n * on a filesystem scan that doesn't work in bundled output.\n */\nexport function loadActionsFromStaticRegistry(\n modules: Record<string, unknown>,\n): Record<string, ActionEntry> {\n const registry: Record<string, ActionEntry> = {};\n for (const [name, raw] of Object.entries(modules)) {\n const mod = raw as Record<string, any> | null | undefined;\n if (!mod) continue;\n\n if (mod.tool && typeof mod.run === \"function\") {\n registry[name] = {\n tool: mod.tool,\n run: mod.run,\n ...(mod.http !== undefined ? { http: mod.http } : {}),\n ...preserveActionFlags(mod),\n };\n continue;\n }\n\n const def = mod.default;\n if (\n def &&\n typeof def === \"object\" &&\n def.tool &&\n typeof def.run === \"function\"\n ) {\n registry[name] = {\n tool: def.tool,\n run: def.run,\n ...(def.http !== undefined ? { http: def.http } : {}),\n ...preserveActionFlags(def),\n };\n continue;\n }\n\n if (typeof def === \"function\") {\n registry[name] = wrapDefaultExport(name, def);\n }\n }\n return registry;\n}\n\n/**\n * Auto-discover actions from a directory.\n *\n * Merges in any actions from the enterprise workspace core (if present in\n * the ancestor chain). Template actions take precedence over workspace-core\n * actions on name collision, so an app can override an enterprise-wide\n * action by dropping a same-named file under its own `actions/`.\n *\n * Note: this helper uses a filesystem scan, which works in dev and in\n * non-bundled Node deployments. In bundled serverless functions (Nitro's\n * netlify / vercel / aws-lambda presets) the `actions/` directory is not\n * on disk at runtime; templates should pass the static registry generated\n * by the Vite plugin to `createAgentChatPlugin({ actions })` instead, so\n * the bundler sees static imports and pulls every action into the bundle.\n *\n * @param from - The caller's `import.meta.url` or an absolute path to the\n * actions directory.\n * @returns A record mapping action names to ActionEntry objects, suitable for\n * passing to `createAgentChatPlugin({ actions })`.\n */\nexport async function autoDiscoverActions(\n from: string,\n): Promise<Record<string, ActionEntry>> {\n const actionsDir = await resolveActionsDir(from);\n const registry: Record<string, ActionEntry> = {};\n\n // 1. Template actions first — these are the authoritative layer for the\n // current app and must override any workspace-core entry with the same\n // name.\n try {\n await loadActionsIntoRegistry(actionsDir, registry, false);\n } catch (err: any) {\n console.warn(\n `[autoDiscoverActions] Could not read actions directory: ${actionsDir} — ${err?.message}`,\n );\n }\n\n // 1b. Fallback: if filesystem discovery found no template actions (common\n // in bundled serverless environments like Netlify/Vercel where the\n // actions/ directory doesn't exist on disk), try importing the\n // generated static registry at .generated/actions-registry.\n //\n // This prevents the silent-empty-tools footgun where the agent has no\n // template actions and falls back to generic tools like web-request.\n // Prefer `loadActionsFromStaticRegistry` over `autoDiscoverActions` for\n // production reliability — this fallback is a safety net, not the\n // primary path.\n if (Object.keys(registry).length === 0 && from) {\n try {\n let registryPath: string;\n if (from.startsWith(\"file://\") || from.startsWith(\"file:///\")) {\n const callerDir = nodePath.dirname(fileURLToPath(from));\n registryPath = nodePath.resolve(\n callerDir,\n \"../../.generated/actions-registry.js\",\n );\n } else {\n registryPath = nodePath.resolve(\n from,\n \"../.generated/actions-registry.js\",\n );\n }\n const mod = await import(/* @vite-ignore */ registryPath);\n const staticEntries = loadActionsFromStaticRegistry(mod.default || mod);\n Object.assign(registry, staticEntries);\n if (Object.keys(staticEntries).length > 0) {\n console.log(\n `[autoDiscoverActions] Filesystem scan found 0 actions — loaded ${Object.keys(staticEntries).length} from .generated/actions-registry.ts instead. ` +\n `Consider switching to loadActionsFromStaticRegistry(actionsRegistry) for production reliability.`,\n );\n }\n } catch {\n // No generated registry available — registry stays empty.\n }\n }\n\n // If still empty after all fallbacks, warn loudly.\n if (Object.keys(registry).length === 0) {\n console.warn(\n `[autoDiscoverActions] WARNING: No template actions found! ` +\n `The agent will have no template-specific tools. ` +\n `If in production, switch from autoDiscoverActions to loadActionsFromStaticRegistry. ` +\n `See: https://docs.agent-native.com/actions#static-registry`,\n );\n }\n\n // 1c. Package-registered actions — contributed by published packages\n // (e.g. @agent-native/dispatch) via `registerPackageActions()` from\n // import side effects. Merged with skip-existing so the template's\n // own actions/ files always win on name collision.\n for (const [name, entry] of Object.entries(getPackageActions())) {\n if (registry[name]) continue;\n registry[name] = entry;\n }\n\n // 2. Workspace-core actions — merged in with skipExisting so they can't\n // overwrite template entries.\n try {\n const { getWorkspaceCoreExports } =\n await import(\"../deploy/workspace-core.js\");\n const ws = await getWorkspaceCoreExports(process.cwd());\n if (ws && ws.actionsDir) {\n await loadActionsIntoRegistry(ws.actionsDir, registry, true);\n }\n } catch {\n // workspace-core discovery unavailable (e.g. edge runtime) — skip.\n }\n\n // 3. Framework-level sharing + file-upload actions — always available to any\n // template. Merged with skipExisting so templates can override by\n // providing a same-named file.\n try {\n await mergeCoreSharingActions(registry);\n } catch {\n // Ignore — templates without sharing still work.\n }\n\n return registry;\n}\n\nexport async function mergeCoreSharingActions(\n registry: Record<string, ActionEntry>,\n): Promise<void> {\n const entries: Array<[string, () => Promise<any>]> = [\n [\"share-resource\", () => import(\"../sharing/actions/share-resource.js\")],\n [\n \"unshare-resource\",\n () => import(\"../sharing/actions/unshare-resource.js\"),\n ],\n [\n \"list-resource-shares\",\n () => import(\"../sharing/actions/list-resource-shares.js\"),\n ],\n [\n \"set-resource-visibility\",\n () => import(\"../sharing/actions/set-resource-visibility.js\"),\n ],\n [\"upload-image\", () => import(\"../file-upload/actions/upload-image.js\")],\n [\n \"change-appearance\",\n () => import(\"../appearance/actions/change-appearance.js\"),\n ],\n [\"toggle-demo-mode\", () => import(\"../demo/actions/toggle-demo-mode.js\")],\n ];\n for (const [name, loader] of entries) {\n if (registry[name]) continue;\n try {\n const mod = await loader();\n const def = mod.default;\n if (def && def.tool && typeof def.run === \"function\") {\n registry[name] = {\n tool: def.tool,\n run: def.run,\n ...(def.http !== undefined ? { http: def.http } : {}),\n ...(def.readOnly === true ? { readOnly: true } : {}),\n ...(def.parallelSafe === true ? { parallelSafe: true } : {}),\n };\n }\n } catch {\n // Skip any sharing action that fails to import.\n }\n }\n}\n\n/** @deprecated Use `autoDiscoverActions` instead */\nexport const autoDiscoverScripts = autoDiscoverActions;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"action-routes.d.ts","sourceRoot":"","sources":["../../src/server/action-routes.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAiEhE,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,CACrB,KAAK,EAAE,GAAG,KACP,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtD,0DAA0D;IAC1D,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACvE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,GAAG,EACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,OAAO,CAAC,EAAE,wBAAwB,QAkKnC"}
1
+ {"version":3,"file":"action-routes.d.ts","sourceRoot":"","sources":["../../src/server/action-routes.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAmEhE,MAAM,WAAW,wBAAwB;IACvC,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7D,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,CACrB,KAAK,EAAE,GAAG,KACP,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACtD,0DAA0D;IAC1D,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACvE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,GAAG,EACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,OAAO,CAAC,EAAE,wBAAwB,QA2KnC"}
@@ -9,6 +9,8 @@ import { defineEventHandler, setResponseStatus, setResponseHeader, getMethod, ge
9
9
  import { readBody } from "../server/h3-helpers.js";
10
10
  import { runWithRequestContext } from "./request-context.js";
11
11
  import { recordChange } from "./poll.js";
12
+ import { isDemoModeEnabled } from "../demo/config.js";
13
+ import { redactDemoData, redactDemoString } from "../demo/redact.js";
12
14
  import { getAllowedCorsOrigin as resolveAllowedCorsOrigin, readCorsAllowedOrigins, } from "./cors-origins.js";
13
15
  const ROUTE_PREFIX = "/_agent-native/actions";
14
16
  /**
@@ -170,16 +172,24 @@ export function mountActionRoutes(nitroApp, actions, options) {
170
172
  // ignore
171
173
  }
172
174
  }
175
+ // Demo mode: replace real names/emails/numbers with
176
+ // deterministic fake data before the result leaves the server.
177
+ // Gated so the (expensive) structure-aware walk only runs when
178
+ // demo mode is actually on. Walking the parsed object — not the
179
+ // JSON string — is what keeps IDs/dates/URLs safe.
180
+ const demo = await isDemoModeEnabled();
173
181
  // If the action returned a string, try to parse as JSON for a clean response
174
182
  if (typeof result === "string") {
183
+ let parsed;
175
184
  try {
176
- return JSON.parse(result);
185
+ parsed = JSON.parse(result);
177
186
  }
178
187
  catch {
179
- return result;
188
+ return demo ? redactDemoString(result) : result;
180
189
  }
190
+ return demo ? redactDemoData(parsed) : parsed;
181
191
  }
182
- return result;
192
+ return demo ? redactDemoData(result) : result;
183
193
  }
184
194
  catch (err) {
185
195
  const msg = err?.message ?? String(err);
@@ -1 +1 @@
1
- {"version":3,"file":"action-routes.js","sourceRoot":"","sources":["../../src/server/action-routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Auto-mount actions as HTTP endpoints under /_agent-native/actions/:name.\n *\n * Actions are exposed as POST by default. Use `http: { method: \"GET\" }` in\n * defineAction to expose as GET. Use `http: false` to mark as agent-only.\n */\nimport { getH3App } from \"./framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseStatus,\n setResponseHeader,\n getMethod,\n getQuery,\n getHeader,\n} from \"h3\";\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { recordChange } from \"./poll.js\";\nimport {\n getAllowedCorsOrigin as resolveAllowedCorsOrigin,\n readCorsAllowedOrigins,\n} from \"./cors-origins.js\";\n\nconst ROUTE_PREFIX = \"/_agent-native/actions\";\n\n/**\n * Read the caller's IANA timezone from the `x-user-timezone` header. The core\n * client sends this on every action request so server-side \"today\" fallbacks\n * can honor the user's local day.\n */\nfunction readTimezoneHeader(event: any): string | undefined {\n try {\n const raw = getHeader(event, \"x-user-timezone\");\n if (!raw || typeof raw !== \"string\") return undefined;\n const trimmed = raw.trim();\n return trimmed.length > 0 && trimmed.length < 64 ? trimmed : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction getAllowedCorsOrigin(origin: string | undefined): string | null {\n return resolveAllowedCorsOrigin(origin, {\n allowedOrigins: readCorsAllowedOrigins(),\n allowLocalhostWhenNoAllowlist: true,\n });\n}\n\nfunction handleOptionsRequest(event: any): string {\n const origin = getHeader(event, \"origin\");\n const allowedOrigin = getAllowedCorsOrigin(\n typeof origin === \"string\" ? origin : undefined,\n );\n\n if (origin && !allowedOrigin) {\n setResponseStatus(event, 403);\n return \"\";\n }\n\n if (allowedOrigin) {\n setResponseHeader(event, \"Access-Control-Allow-Origin\", allowedOrigin);\n setResponseHeader(event, \"Vary\", \"Origin\");\n setResponseHeader(event, \"Access-Control-Allow-Credentials\", \"true\");\n setResponseHeader(\n event,\n \"Access-Control-Allow-Methods\",\n \"GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS\",\n );\n setResponseHeader(\n event,\n \"Access-Control-Allow-Headers\",\n \"Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id\",\n );\n }\n\n setResponseStatus(event, 204);\n return \"\";\n}\n\nexport interface MountActionRoutesOptions {\n /** Resolve owner email from the H3 event (for data scoping). */\n getOwnerFromEvent?: (event: any) => string | Promise<string>;\n /** Resolve display name from the H3 event, when available. */\n getUserNameFromEvent?: (\n event: any,\n ) => string | undefined | Promise<string | undefined>;\n /** Resolve org ID from the H3 event (for org scoping). */\n resolveOrgId?: (event: any) => string | null | Promise<string | null>;\n}\n\n/**\n * Mount discovered actions as HTTP endpoints.\n *\n * Only actions from `autoDiscoverActions` (template actions) are mounted.\n * Built-in actions (resource-*, chat-*, shell, etc.) are NOT passed here.\n */\nexport function mountActionRoutes(\n nitroApp: any,\n actions: Record<string, ActionEntry>,\n options?: MountActionRoutesOptions,\n) {\n const mounted: string[] = [];\n\n for (const [name, entry] of Object.entries(actions)) {\n // Skip agent-only actions\n if (entry.http === false) continue;\n\n const method = entry.http?.method ?? \"POST\";\n const path = entry.http?.path ?? name;\n const routePath = `${ROUTE_PREFIX}/${path}`;\n\n getH3App(nitroApp).use(\n routePath,\n defineEventHandler(async (event) => {\n const reqMethod = getMethod(event);\n const effectiveMethod =\n reqMethod === \"HEAD\" && method === \"GET\" ? \"GET\" : reqMethod;\n\n if (reqMethod === \"OPTIONS\") {\n return handleOptionsRequest(event);\n }\n\n setResponseHeader(event, \"Cache-Control\", \"no-store\");\n\n // Allow the declared method\n if (effectiveMethod !== method) {\n setResponseStatus(event, 405);\n return { error: `Method not allowed. Use ${method}.` };\n }\n\n // (audit H5) Per-action `toolCallable` opt-out for the tools-iframe\n // bridge. The bridge tags every outbound action call with\n // X-Agent-Native-Tool-Bridge: 1. When that header is present and the\n // action declares `toolCallable: false`, we 403 — used by the\n // framework's share-resource / unshare-resource /\n // set-resource-visibility for defense-in-depth on auth-adjacent\n // operations. Undefined defaults to allow: tools are intra-org and\n // typically authored by trusted teammates, so the default is to\n // trust the org-level access controls.\n // The header is set by the parent (the React host), not by the\n // iframe's user-authored content; sanitizeToolRequestOptions strips\n // iframe attempts to spoof it.\n const fromToolBridge =\n getHeader(event, \"x-agent-native-tool-bridge\") === \"1\";\n if (fromToolBridge && entry.toolCallable === false) {\n setResponseStatus(event, 403);\n return {\n error: `Action '${name}' is not callable from tools.`,\n };\n }\n\n // Resolve auth context for per-request scoping\n const userEmail = options?.getOwnerFromEvent\n ? await options.getOwnerFromEvent(event)\n : undefined;\n const userName = options?.getUserNameFromEvent\n ? await options.getUserNameFromEvent(event)\n : undefined;\n const orgId = options?.resolveOrgId\n ? ((await options.resolveOrgId(event)) ?? undefined)\n : undefined;\n const timezone = readTimezoneHeader(event);\n\n return runWithRequestContext(\n { userEmail, userName, orgId, timezone },\n async () => {\n // Parse params based on method. On web-standard runtimes (Netlify\n // Functions, CF Workers), event.req IS the web Request — use .json()\n // directly. H3's readBody fails on those runtimes because it expects\n // a Node.js stream on event.node.req.\n let params: Record<string, any>;\n try {\n if (method === \"GET\") {\n // H3 v2: prefer web Request URL, fallback to getQuery\n const webReq = (event as any).req;\n if (webReq?.url) {\n const url = new URL(webReq.url);\n params = Object.fromEntries(url.searchParams);\n } else {\n params = getQuery(event) as Record<string, any>;\n }\n } else {\n const webReq = (event as any).req;\n if (webReq && typeof webReq.json === \"function\") {\n // H3 v2: event.req is the web Request — use .json() directly\n params = (await webReq.json().catch(() => null)) ?? {};\n } else {\n // Fallback: H3's readBody (Node.js dev)\n params = (await readBody(event)) ?? {};\n }\n }\n } catch {\n params = {};\n }\n\n // Run the action\n try {\n const result = await entry.run(params);\n\n // Auto-refresh the UI after a successful mutating action. GET\n // actions and actions explicitly flagged readOnly are skipped.\n // Other tabs' useDbSync will see source:\"action\" and invalidate\n // their action queries. The calling tab already refetches via\n // useActionMutation's onSuccess, so this is mainly cross-tab\n // sync (and parity with the agent's tool-call path).\n // Explicit entry.readOnly (true OR false) wins over the method\n // heuristic. defineAction already auto-infers GET → readOnly=true,\n // so for actions registered through that path entry.readOnly is\n // always set and the fallback just guards legacy wrap paths.\n const isReadOnly =\n typeof entry.readOnly === \"boolean\"\n ? entry.readOnly\n : method === \"GET\";\n if (!isReadOnly) {\n try {\n recordChange({\n source: \"action\",\n type: \"change\",\n key: name,\n owner: userEmail,\n });\n } catch {\n // ignore\n }\n }\n\n // If the action returned a string, try to parse as JSON for a clean response\n if (typeof result === \"string\") {\n try {\n return JSON.parse(result);\n } catch {\n return result;\n }\n }\n\n return result;\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n // Return 400 for validation errors, 500 for everything else\n setResponseStatus(\n event,\n msg.startsWith(\"Invalid action parameters\")\n ? 400\n : typeof err?.statusCode === \"number\"\n ? err.statusCode\n : 500,\n );\n return { error: msg };\n }\n },\n ); // end runWithRequestContext\n }),\n );\n\n mounted.push(`${method} ${routePath}`);\n }\n\n if (mounted.length > 0 && process.env.DEBUG)\n console.log(\n `[action-routes] Mounted ${mounted.length} action route(s): ${mounted.join(\", \")}`,\n );\n}\n"]}
1
+ {"version":3,"file":"action-routes.js","sourceRoot":"","sources":["../../src/server/action-routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Auto-mount actions as HTTP endpoints under /_agent-native/actions/:name.\n *\n * Actions are exposed as POST by default. Use `http: { method: \"GET\" }` in\n * defineAction to expose as GET. Use `http: false` to mark as agent-only.\n */\nimport { getH3App } from \"./framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseStatus,\n setResponseHeader,\n getMethod,\n getQuery,\n getHeader,\n} from \"h3\";\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { runWithRequestContext } from \"./request-context.js\";\nimport { recordChange } from \"./poll.js\";\nimport { isDemoModeEnabled } from \"../demo/config.js\";\nimport { redactDemoData, redactDemoString } from \"../demo/redact.js\";\nimport {\n getAllowedCorsOrigin as resolveAllowedCorsOrigin,\n readCorsAllowedOrigins,\n} from \"./cors-origins.js\";\n\nconst ROUTE_PREFIX = \"/_agent-native/actions\";\n\n/**\n * Read the caller's IANA timezone from the `x-user-timezone` header. The core\n * client sends this on every action request so server-side \"today\" fallbacks\n * can honor the user's local day.\n */\nfunction readTimezoneHeader(event: any): string | undefined {\n try {\n const raw = getHeader(event, \"x-user-timezone\");\n if (!raw || typeof raw !== \"string\") return undefined;\n const trimmed = raw.trim();\n return trimmed.length > 0 && trimmed.length < 64 ? trimmed : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction getAllowedCorsOrigin(origin: string | undefined): string | null {\n return resolveAllowedCorsOrigin(origin, {\n allowedOrigins: readCorsAllowedOrigins(),\n allowLocalhostWhenNoAllowlist: true,\n });\n}\n\nfunction handleOptionsRequest(event: any): string {\n const origin = getHeader(event, \"origin\");\n const allowedOrigin = getAllowedCorsOrigin(\n typeof origin === \"string\" ? origin : undefined,\n );\n\n if (origin && !allowedOrigin) {\n setResponseStatus(event, 403);\n return \"\";\n }\n\n if (allowedOrigin) {\n setResponseHeader(event, \"Access-Control-Allow-Origin\", allowedOrigin);\n setResponseHeader(event, \"Vary\", \"Origin\");\n setResponseHeader(event, \"Access-Control-Allow-Credentials\", \"true\");\n setResponseHeader(\n event,\n \"Access-Control-Allow-Methods\",\n \"GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS\",\n );\n setResponseHeader(\n event,\n \"Access-Control-Allow-Headers\",\n \"Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id\",\n );\n }\n\n setResponseStatus(event, 204);\n return \"\";\n}\n\nexport interface MountActionRoutesOptions {\n /** Resolve owner email from the H3 event (for data scoping). */\n getOwnerFromEvent?: (event: any) => string | Promise<string>;\n /** Resolve display name from the H3 event, when available. */\n getUserNameFromEvent?: (\n event: any,\n ) => string | undefined | Promise<string | undefined>;\n /** Resolve org ID from the H3 event (for org scoping). */\n resolveOrgId?: (event: any) => string | null | Promise<string | null>;\n}\n\n/**\n * Mount discovered actions as HTTP endpoints.\n *\n * Only actions from `autoDiscoverActions` (template actions) are mounted.\n * Built-in actions (resource-*, chat-*, shell, etc.) are NOT passed here.\n */\nexport function mountActionRoutes(\n nitroApp: any,\n actions: Record<string, ActionEntry>,\n options?: MountActionRoutesOptions,\n) {\n const mounted: string[] = [];\n\n for (const [name, entry] of Object.entries(actions)) {\n // Skip agent-only actions\n if (entry.http === false) continue;\n\n const method = entry.http?.method ?? \"POST\";\n const path = entry.http?.path ?? name;\n const routePath = `${ROUTE_PREFIX}/${path}`;\n\n getH3App(nitroApp).use(\n routePath,\n defineEventHandler(async (event) => {\n const reqMethod = getMethod(event);\n const effectiveMethod =\n reqMethod === \"HEAD\" && method === \"GET\" ? \"GET\" : reqMethod;\n\n if (reqMethod === \"OPTIONS\") {\n return handleOptionsRequest(event);\n }\n\n setResponseHeader(event, \"Cache-Control\", \"no-store\");\n\n // Allow the declared method\n if (effectiveMethod !== method) {\n setResponseStatus(event, 405);\n return { error: `Method not allowed. Use ${method}.` };\n }\n\n // (audit H5) Per-action `toolCallable` opt-out for the tools-iframe\n // bridge. The bridge tags every outbound action call with\n // X-Agent-Native-Tool-Bridge: 1. When that header is present and the\n // action declares `toolCallable: false`, we 403 — used by the\n // framework's share-resource / unshare-resource /\n // set-resource-visibility for defense-in-depth on auth-adjacent\n // operations. Undefined defaults to allow: tools are intra-org and\n // typically authored by trusted teammates, so the default is to\n // trust the org-level access controls.\n // The header is set by the parent (the React host), not by the\n // iframe's user-authored content; sanitizeToolRequestOptions strips\n // iframe attempts to spoof it.\n const fromToolBridge =\n getHeader(event, \"x-agent-native-tool-bridge\") === \"1\";\n if (fromToolBridge && entry.toolCallable === false) {\n setResponseStatus(event, 403);\n return {\n error: `Action '${name}' is not callable from tools.`,\n };\n }\n\n // Resolve auth context for per-request scoping\n const userEmail = options?.getOwnerFromEvent\n ? await options.getOwnerFromEvent(event)\n : undefined;\n const userName = options?.getUserNameFromEvent\n ? await options.getUserNameFromEvent(event)\n : undefined;\n const orgId = options?.resolveOrgId\n ? ((await options.resolveOrgId(event)) ?? undefined)\n : undefined;\n const timezone = readTimezoneHeader(event);\n\n return runWithRequestContext(\n { userEmail, userName, orgId, timezone },\n async () => {\n // Parse params based on method. On web-standard runtimes (Netlify\n // Functions, CF Workers), event.req IS the web Request — use .json()\n // directly. H3's readBody fails on those runtimes because it expects\n // a Node.js stream on event.node.req.\n let params: Record<string, any>;\n try {\n if (method === \"GET\") {\n // H3 v2: prefer web Request URL, fallback to getQuery\n const webReq = (event as any).req;\n if (webReq?.url) {\n const url = new URL(webReq.url);\n params = Object.fromEntries(url.searchParams);\n } else {\n params = getQuery(event) as Record<string, any>;\n }\n } else {\n const webReq = (event as any).req;\n if (webReq && typeof webReq.json === \"function\") {\n // H3 v2: event.req is the web Request — use .json() directly\n params = (await webReq.json().catch(() => null)) ?? {};\n } else {\n // Fallback: H3's readBody (Node.js dev)\n params = (await readBody(event)) ?? {};\n }\n }\n } catch {\n params = {};\n }\n\n // Run the action\n try {\n const result = await entry.run(params);\n\n // Auto-refresh the UI after a successful mutating action. GET\n // actions and actions explicitly flagged readOnly are skipped.\n // Other tabs' useDbSync will see source:\"action\" and invalidate\n // their action queries. The calling tab already refetches via\n // useActionMutation's onSuccess, so this is mainly cross-tab\n // sync (and parity with the agent's tool-call path).\n // Explicit entry.readOnly (true OR false) wins over the method\n // heuristic. defineAction already auto-infers GET → readOnly=true,\n // so for actions registered through that path entry.readOnly is\n // always set and the fallback just guards legacy wrap paths.\n const isReadOnly =\n typeof entry.readOnly === \"boolean\"\n ? entry.readOnly\n : method === \"GET\";\n if (!isReadOnly) {\n try {\n recordChange({\n source: \"action\",\n type: \"change\",\n key: name,\n owner: userEmail,\n });\n } catch {\n // ignore\n }\n }\n\n // Demo mode: replace real names/emails/numbers with\n // deterministic fake data before the result leaves the server.\n // Gated so the (expensive) structure-aware walk only runs when\n // demo mode is actually on. Walking the parsed object — not the\n // JSON string — is what keeps IDs/dates/URLs safe.\n const demo = await isDemoModeEnabled();\n\n // If the action returned a string, try to parse as JSON for a clean response\n if (typeof result === \"string\") {\n let parsed: any;\n try {\n parsed = JSON.parse(result);\n } catch {\n return demo ? redactDemoString(result) : result;\n }\n return demo ? redactDemoData(parsed) : parsed;\n }\n\n return demo ? redactDemoData(result) : result;\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n // Return 400 for validation errors, 500 for everything else\n setResponseStatus(\n event,\n msg.startsWith(\"Invalid action parameters\")\n ? 400\n : typeof err?.statusCode === \"number\"\n ? err.statusCode\n : 500,\n );\n return { error: msg };\n }\n },\n ); // end runWithRequestContext\n }),\n );\n\n mounted.push(`${method} ${routePath}`);\n }\n\n if (mounted.length > 0 && process.env.DEBUG)\n console.log(\n `[action-routes] Mounted ${mounted.length} action route(s): ${mounted.join(\", \")}`,\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "description": "Framework for agent-native application development — where AI agents and UI share state via files",
6
6
  "license": "MIT",